Files
dees-catalog-mobile/ts_web/elements/00group-ui/dees-mobile-modal/dees-mobile-modal.ts
2025-12-22 10:53:15 +00:00

203 lines
4.7 KiB
TypeScript

import {
DeesElement,
css,
cssManager,
customElement,
html,
property,
type TemplateResult,
} from '@design.estate/dees-element';
import { mobileComponentStyles } from '../../00componentstyles.js';
import '../dees-mobile-icon/dees-mobile-icon.js';
import { demoFunc } from './dees-mobile-modal.demo.js';
declare global {
interface HTMLElementTagNameMap {
'dees-mobile-modal': DeesMobileModal;
}
}
@customElement('dees-mobile-modal')
export class DeesMobileModal extends DeesElement {
public static demo = demoFunc;
@property({ type: Boolean })
accessor open: boolean = false;
@property({ type: String })
accessor title: string = '';
@property({ type: Boolean })
accessor showCloseButton: boolean = true;
public static styles = [
cssManager.defaultStyles,
mobileComponentStyles,
css`
.modal-backdrop {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: var(--dees-z-modal, 500);
padding: 1rem;
animation: fadeIn 200ms ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.modal {
background: ${cssManager.bdTheme('#ffffff', '#18181b')};
border-radius: 0.75rem;
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
/* Mobile-first defaults */
max-width: 100%;
width: 100%;
max-height: 90vh;
display: flex;
flex-direction: column;
animation: slideUp 200ms ease-out;
}
/* Desktop enhancements */
@media (min-width: 641px) {
.modal {
max-width: 500px;
}
}
@keyframes slideUp {
from {
transform: translateY(20px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.modal-header {
display: flex;
align-items: center;
justify-content: space-between;
/* Mobile-first defaults */
padding: 1rem;
border-bottom: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')};
}
/* Desktop enhancements */
@media (min-width: 641px) {
.modal-header {
padding: 1.5rem;
}
}
.modal-title {
font-size: 1.125rem;
font-weight: 600;
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
margin: 0;
}
.close-button {
display: flex;
align-items: center;
justify-content: center;
width: 2rem;
height: 2rem;
border: none;
background: transparent;
border-radius: 0.25rem;
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
cursor: pointer;
transition: all 150ms ease;
}
.close-button:hover {
background: ${cssManager.bdTheme('#f4f4f5', '#27272a')};
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
}
.modal-content {
overflow-y: auto;
-webkit-overflow-scrolling: touch;
padding: 1rem;
}
@media (min-width: 641px) {
.modal-content {
padding: 1.5rem;
}
}
.modal-footer {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 0.5rem;
padding: 1rem;
border-top: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')};
}
@media (min-width: 641px) {
.modal-footer {
padding: 1.5rem;
}
}
.modal-footer:empty {
display: none;
}
`,
];
private handleBackdropClick(e: MouseEvent) {
if (e.target === e.currentTarget) {
this.handleClose();
}
}
private handleClose() {
this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }));
}
public render(): TemplateResult {
if (!this.open) return html``;
return html`
<div class="modal-backdrop" @click=${this.handleBackdropClick}>
<div class="modal">
<div class="modal-header">
<h2 class="modal-title">${this.title}</h2>
${this.showCloseButton ? html`
<button class="close-button" @click=${this.handleClose} aria-label="Close">
<dees-mobile-icon icon="x" size="20"></dees-mobile-icon>
</button>
` : ''}
</div>
<div class="modal-content">
<slot></slot>
</div>
<div class="modal-footer">
<slot name="footer"></slot>
</div>
</div>
</div>
`;
}
}