import { LitElement, html } from "lit";
import { property } from "lit/decorators.js";
// Import from barrel file to ensure Dialog custom element is registered
import { AgnosticDialog } from "../../Dialog/core/Dialog";
// Event types
export type DrawerOpenEvent = CustomEvent;
export type DrawerCloseEvent = CustomEvent;
export type DrawerCancelEvent = CustomEvent;
// Props interface following INTERFACE_STANDARDS.md
export interface DrawerProps {
open?: boolean;
heading?: string;
description?: string;
noCloseOnEscape?: boolean;
noCloseOnBackdrop?: boolean;
showCloseButton?: boolean;
position?: 'start' | 'end' | 'top' | 'bottom';
// Event handlers
onDrawerOpen?: (event: DrawerOpenEvent) => void;
onDrawerClose?: (event: DrawerCloseEvent) => void;
onDrawerCancel?: (event: DrawerCancelEvent) => void;
}
export class AgnosticDrawer extends LitElement implements DrawerProps {
@property({ type: Boolean, reflect: true })
declare open: boolean;
@property({ type: String })
declare heading: string;
@property({ type: String })
declare description: string;
@property({ type: Boolean })
declare noCloseOnEscape: boolean;
@property({ type: Boolean })
declare noCloseOnBackdrop: boolean;
@property({ type: Boolean })
declare showCloseButton: boolean;
@property({ type: String, reflect: true, attribute: 'position' })
declare position: 'start' | 'end' | 'top' | 'bottom';
@property({ attribute: false })
declare onDrawerOpen?: (event: DrawerOpenEvent) => void;
@property({ attribute: false })
declare onDrawerClose?: (event: DrawerCloseEvent) => void;
@property({ attribute: false })
declare onDrawerCancel?: (event: DrawerCancelEvent) => void;
private _dialogElement?: AgnosticDialog;
constructor() {
super();
this.open = false;
this.heading = '';
this.description = '';
this.position = 'bottom';
this.noCloseOnEscape = false;
this.noCloseOnBackdrop = false;
this.showCloseButton = false;
}
firstUpdated(changedProperties: Map) {
super.firstUpdated(changedProperties);
this._dialogElement = this.shadowRoot?.querySelector('ag-dialog') as AgnosticDialog | undefined;
if (this._dialogElement) {
// Set up event forwarding from Dialog events to Drawer events
this._dialogElement.addEventListener('dialog-open', () => {
const openEvent = new CustomEvent('drawer-open', {
bubbles: true,
composed: true,
});
this.dispatchEvent(openEvent);
this.onDrawerOpen?.(openEvent);
});
this._dialogElement.addEventListener('dialog-close', () => {
const closeEvent = new CustomEvent('drawer-close', {
bubbles: true,
composed: true,
});
this.dispatchEvent(closeEvent);
this.onDrawerClose?.(closeEvent);
// Sync Drawer's state when Dialog closes itself
if (this.open) {
this.open = false;
}
});
this._dialogElement.addEventListener('dialog-cancel', () => {
const cancelEvent = new CustomEvent('drawer-cancel', {
bubbles: true,
composed: true,
});
this.dispatchEvent(cancelEvent);
this.onDrawerCancel?.(cancelEvent);
// Sync Drawer's state when Dialog cancels itself
if (this.open) {
this.open = false;
}
});
}
}
updated(changedProperties: Map) {
super.updated(changedProperties);
// Sync open property changes from Drawer to Dialog
if (changedProperties.has('open') && this._dialogElement) {
if (this._dialogElement.open !== this.open) {
this._dialogElement.open = this.open;
}
}
}
/*
Property Bindings
In Lit, the dot (.) prefix is used to create a property binding, which sets a JavaScript property on an element instead of an HTML attribute. This is a critical distinction because properties can hold any JavaScript data type, including objects, arrays, and booleans, while HTML attributes can only store strings.
https://lit.dev/docs/v1/lit-html/template-reference/#binding-types
https://vaadin.com/docs/latest/hilla/lit/components/create#binding-to-a-property
*/
render() {
return html`
`;
}
}