224 lines
5.5 KiB
TypeScript
224 lines
5.5 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-actionsheet.demo.js';
|
||
|
|
|
||
|
|
export interface IActionSheetOption {
|
||
|
|
id: string;
|
||
|
|
icon?: string;
|
||
|
|
iconColor?: string;
|
||
|
|
iconBackground?: string;
|
||
|
|
title: string;
|
||
|
|
subtitle?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
declare global {
|
||
|
|
interface HTMLElementTagNameMap {
|
||
|
|
'dees-mobile-actionsheet': DeesMobileActionsheet;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@customElement('dees-mobile-actionsheet')
|
||
|
|
export class DeesMobileActionsheet extends DeesElement {
|
||
|
|
public static demo = demoFunc;
|
||
|
|
|
||
|
|
@property({ type: String })
|
||
|
|
accessor title: string = '';
|
||
|
|
|
||
|
|
@property({ type: Array })
|
||
|
|
accessor options: IActionSheetOption[] = [];
|
||
|
|
|
||
|
|
@property({ type: String })
|
||
|
|
accessor cancelText: string = 'Cancel';
|
||
|
|
|
||
|
|
public static styles = [
|
||
|
|
cssManager.defaultStyles,
|
||
|
|
mobileComponentStyles,
|
||
|
|
css`
|
||
|
|
:host {
|
||
|
|
position: fixed;
|
||
|
|
inset: 0;
|
||
|
|
z-index: var(--dees-z-modal, 500);
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
justify-content: flex-end;
|
||
|
|
}
|
||
|
|
|
||
|
|
.backdrop {
|
||
|
|
position: absolute;
|
||
|
|
inset: 0;
|
||
|
|
background: rgba(0, 0, 0, 0);
|
||
|
|
animation: fadeInBackdrop 0.2s ease-out forwards;
|
||
|
|
}
|
||
|
|
|
||
|
|
@keyframes fadeInBackdrop {
|
||
|
|
to {
|
||
|
|
background: rgba(0, 0, 0, 0.5);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.sheet {
|
||
|
|
position: relative;
|
||
|
|
background: var(--dees-card);
|
||
|
|
border-radius: var(--dees-radius-lg) var(--dees-radius-lg) 0 0;
|
||
|
|
padding: var(--dees-space-md);
|
||
|
|
padding-bottom: calc(var(--dees-space-md) + env(safe-area-inset-bottom, 0px));
|
||
|
|
transform: translateY(100%);
|
||
|
|
animation: slideUp 0.3s ease-out forwards;
|
||
|
|
}
|
||
|
|
|
||
|
|
@keyframes slideUp {
|
||
|
|
to {
|
||
|
|
transform: translateY(0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.sheet-title {
|
||
|
|
text-align: center;
|
||
|
|
font-size: 0.875rem;
|
||
|
|
color: var(--dees-muted-foreground);
|
||
|
|
margin-bottom: var(--dees-space-md);
|
||
|
|
padding-bottom: var(--dees-space-sm);
|
||
|
|
border-bottom: 1px solid var(--dees-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
.options {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: var(--dees-space-xs);
|
||
|
|
}
|
||
|
|
|
||
|
|
.option {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: var(--dees-space-md);
|
||
|
|
padding: var(--dees-space-md);
|
||
|
|
border: none;
|
||
|
|
background: var(--dees-background);
|
||
|
|
border-radius: var(--dees-radius-md);
|
||
|
|
cursor: pointer;
|
||
|
|
color: var(--dees-foreground);
|
||
|
|
font-size: 1rem;
|
||
|
|
font-weight: 500;
|
||
|
|
text-align: left;
|
||
|
|
transition: background var(--dees-transition-fast);
|
||
|
|
}
|
||
|
|
|
||
|
|
.option:hover {
|
||
|
|
background: var(--dees-muted);
|
||
|
|
}
|
||
|
|
|
||
|
|
.option:active {
|
||
|
|
background: var(--dees-accent);
|
||
|
|
}
|
||
|
|
|
||
|
|
.option-icon {
|
||
|
|
width: 44px;
|
||
|
|
height: 44px;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
border-radius: var(--dees-radius-full);
|
||
|
|
flex-shrink: 0;
|
||
|
|
background: var(--dees-accent);
|
||
|
|
color: var(--dees-primary);
|
||
|
|
}
|
||
|
|
|
||
|
|
.option-text {
|
||
|
|
flex: 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
.option-title {
|
||
|
|
font-weight: 500;
|
||
|
|
}
|
||
|
|
|
||
|
|
.option-subtitle {
|
||
|
|
font-size: 0.75rem;
|
||
|
|
color: var(--dees-muted-foreground);
|
||
|
|
font-weight: normal;
|
||
|
|
margin-top: 2px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.cancel {
|
||
|
|
margin-top: var(--dees-space-sm);
|
||
|
|
padding: var(--dees-space-md);
|
||
|
|
border: none;
|
||
|
|
background: var(--dees-background);
|
||
|
|
border-radius: var(--dees-radius-md);
|
||
|
|
cursor: pointer;
|
||
|
|
color: var(--dees-danger);
|
||
|
|
font-size: 1rem;
|
||
|
|
font-weight: 500;
|
||
|
|
width: 100%;
|
||
|
|
transition: background var(--dees-transition-fast);
|
||
|
|
}
|
||
|
|
|
||
|
|
.cancel:hover {
|
||
|
|
background: rgba(220, 38, 38, 0.1);
|
||
|
|
}
|
||
|
|
`,
|
||
|
|
];
|
||
|
|
|
||
|
|
private handleSelect(option: IActionSheetOption) {
|
||
|
|
this.dispatchEvent(new CustomEvent('select', {
|
||
|
|
detail: option,
|
||
|
|
bubbles: true,
|
||
|
|
composed: true,
|
||
|
|
}));
|
||
|
|
}
|
||
|
|
|
||
|
|
private handleClose() {
|
||
|
|
this.dispatchEvent(new CustomEvent('close', {
|
||
|
|
bubbles: true,
|
||
|
|
composed: true,
|
||
|
|
}));
|
||
|
|
}
|
||
|
|
|
||
|
|
public render(): TemplateResult {
|
||
|
|
return html`
|
||
|
|
<div class="backdrop" @click=${this.handleClose}></div>
|
||
|
|
<div class="sheet">
|
||
|
|
${this.title ? html`<div class="sheet-title">${this.title}</div>` : ''}
|
||
|
|
|
||
|
|
<div class="options">
|
||
|
|
${this.options.map(option => html`
|
||
|
|
<button class="option" @click=${() => this.handleSelect(option)}>
|
||
|
|
${option.icon ? html`
|
||
|
|
<div
|
||
|
|
class="option-icon"
|
||
|
|
style=${option.iconBackground ? `background: ${option.iconBackground}` : ''}
|
||
|
|
>
|
||
|
|
<dees-mobile-icon
|
||
|
|
icon=${option.icon}
|
||
|
|
size="24"
|
||
|
|
color=${option.iconColor || 'currentColor'}
|
||
|
|
></dees-mobile-icon>
|
||
|
|
</div>
|
||
|
|
` : ''}
|
||
|
|
<div class="option-text">
|
||
|
|
<div class="option-title">${option.title}</div>
|
||
|
|
${option.subtitle ? html`
|
||
|
|
<div class="option-subtitle">${option.subtitle}</div>
|
||
|
|
` : ''}
|
||
|
|
</div>
|
||
|
|
</button>
|
||
|
|
`)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<button class="cancel" @click=${this.handleClose}>
|
||
|
|
${this.cancelText}
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
`;
|
||
|
|
}
|
||
|
|
}
|