initial
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
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>
|
||||
`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user