initial
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
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;
|
||||
}
|
||||
.demo-note {
|
||||
font-size: 0.875rem;
|
||||
color: var(--dees-muted-foreground);
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>Action Sheet</h3>
|
||||
<dees-mobile-button
|
||||
@click=${(e: Event) => {
|
||||
const container = (e.target as HTMLElement).parentElement;
|
||||
const existing = container?.querySelector('dees-mobile-actionsheet');
|
||||
if (existing) existing.remove();
|
||||
|
||||
const sheet = document.createElement('dees-mobile-actionsheet');
|
||||
(sheet as any).title = 'Add Photo';
|
||||
(sheet as any).options = [
|
||||
{
|
||||
id: 'camera',
|
||||
icon: 'camera',
|
||||
iconColor: 'var(--dees-primary)',
|
||||
iconBackground: 'rgba(59, 130, 246, 0.1)',
|
||||
title: 'Take Photo',
|
||||
subtitle: 'Use camera to capture a new photo'
|
||||
},
|
||||
{
|
||||
id: 'gallery',
|
||||
icon: 'image',
|
||||
iconColor: '#16a34a',
|
||||
iconBackground: '#dcfce7',
|
||||
title: 'Choose from Gallery',
|
||||
subtitle: 'Select an existing photo'
|
||||
}
|
||||
];
|
||||
sheet.addEventListener('close', () => sheet.remove());
|
||||
sheet.addEventListener('select', (ev: any) => {
|
||||
console.log('Selected:', ev.detail);
|
||||
sheet.remove();
|
||||
});
|
||||
document.body.appendChild(sheet);
|
||||
}}
|
||||
>Show Photo Options</dees-mobile-button>
|
||||
<p class="demo-note">Opens an iOS-style action sheet from the bottom of the screen.</p>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>Share Options</h3>
|
||||
<dees-mobile-button
|
||||
variant="outline"
|
||||
@click=${(e: Event) => {
|
||||
const sheet = document.createElement('dees-mobile-actionsheet');
|
||||
(sheet as any).title = 'Share';
|
||||
(sheet as any).options = [
|
||||
{
|
||||
id: 'copy',
|
||||
icon: 'copy',
|
||||
title: 'Copy Link'
|
||||
},
|
||||
{
|
||||
id: 'email',
|
||||
icon: 'mail',
|
||||
title: 'Send via Email'
|
||||
},
|
||||
{
|
||||
id: 'message',
|
||||
icon: 'message-circle',
|
||||
title: 'Send Message'
|
||||
}
|
||||
];
|
||||
sheet.addEventListener('close', () => sheet.remove());
|
||||
sheet.addEventListener('select', (ev: any) => {
|
||||
console.log('Share via:', ev.detail);
|
||||
sheet.remove();
|
||||
});
|
||||
document.body.appendChild(sheet);
|
||||
}}
|
||||
>Share Options</dees-mobile-button>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
@@ -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>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './dees-mobile-actionsheet.js';
|
||||
Reference in New Issue
Block a user