initial
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import { html } from '@design.estate/dees-element';
|
||||
import { injectCssVariables } from '../../00variables.js';
|
||||
|
||||
export const demoFunc = () => {
|
||||
injectCssVariables();
|
||||
return html`
|
||||
<style>
|
||||
.demo-section {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.demo-section h3 {
|
||||
margin: 0 0 1rem 0;
|
||||
font-size: 0.875rem;
|
||||
color: var(--dees-muted-foreground);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
.modal-content {
|
||||
padding: 1rem 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>Modal (click button to open)</h3>
|
||||
<dees-mobile-button
|
||||
@click=${(e: Event) => {
|
||||
const modal = (e.target as HTMLElement).parentElement?.querySelector('dees-mobile-modal');
|
||||
if (modal) (modal as any).open = true;
|
||||
}}
|
||||
>Open Modal</dees-mobile-button>
|
||||
|
||||
<dees-mobile-modal
|
||||
title="Confirm Action"
|
||||
@close=${(e: Event) => {
|
||||
(e.target as any).open = false;
|
||||
}}
|
||||
>
|
||||
<div class="modal-content">
|
||||
<p>Are you sure you want to proceed with this action?</p>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<dees-mobile-button variant="ghost">Cancel</dees-mobile-button>
|
||||
<dees-mobile-button variant="primary">Confirm</dees-mobile-button>
|
||||
</div>
|
||||
</dees-mobile-modal>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>Modal without Close Button</h3>
|
||||
<dees-mobile-button
|
||||
variant="outline"
|
||||
@click=${(e: Event) => {
|
||||
const modal = (e.target as HTMLElement).parentElement?.querySelector('dees-mobile-modal');
|
||||
if (modal) (modal as any).open = true;
|
||||
}}
|
||||
>Open Required Modal</dees-mobile-button>
|
||||
|
||||
<dees-mobile-modal
|
||||
title="Terms & Conditions"
|
||||
.showCloseButton=${false}
|
||||
@close=${(e: Event) => {
|
||||
(e.target as any).open = false;
|
||||
}}
|
||||
>
|
||||
<div class="modal-content">
|
||||
<p>You must accept the terms to continue.</p>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<dees-mobile-button variant="primary">I Accept</dees-mobile-button>
|
||||
</div>
|
||||
</dees-mobile-modal>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
@@ -0,0 +1,202 @@
|
||||
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>
|
||||
`;
|
||||
}
|
||||
}
|
||||
1
ts_web/elements/00group-ui/dees-mobile-modal/index.ts
Normal file
1
ts_web/elements/00group-ui/dees-mobile-modal/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './dees-mobile-modal.js';
|
||||
Reference in New Issue
Block a user