Skip to content

Instantly share code, notes, and snippets.

@Totati
Last active April 5, 2023 12:54
Show Gist options
  • Save Totati/8399dd48cf7a7a78bb5326e35392f26b to your computer and use it in GitHub Desktop.
Save Totati/8399dd48cf7a7a78bb5326e35392f26b to your computer and use it in GitHub Desktop.
import { nothing } from 'lit';
import { AsyncDirective, directive, ElementPart, PartInfo, ElementPartInfo, PartType } from 'lit/async-directive.js';
/**
* @emits accept - when the user accept the dialog
* @emits decline - when the user declines the dialog
*/
class ConfirmDialogDirective extends AsyncDirective {
private element?: Element;
private config?: ConfirmDialogOptions;
private dialog?: Promise<void>;
constructor(partInfo: PartInfo) {
super(partInfo);
if (partInfo.type !== PartType.ELEMENT) {
throw new Error('confirmDialog can only be used in element bindings');
}
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
render(config?: ConfirmDialogOptions) {
return nothing;
}
update(part: ElementPart, [config]: Parameters<this['render']>) {
if (!this.element) {
this.element = part.element;
this.element.addEventListener('click', this.onClick);
}
this.config = config;
return nothing;
}
disconnected() {
this.element?.removeEventListener('click', this.onClick);
}
reconnected() {
this.element?.addEventListener('click', this.onClick);
}
private onClick = () => {
if(this.dialog) { return; }
this.dialog = dialogService.request(this.config)
.then(result => {
this.dialog = undefined;
this.element?.dispatchEvent(new CustomEvent(result ? 'accept' : 'decline'));
});
};
}
export const confirmDialog = directive(ConfirmDialogDirective);
/**
* The type of the class that powers this directive. Necessary for naming the
* directive's return type.
*/
export type { ConfirmDialogDirective };
export interface ConfirmDialogOptions {
body?: string;
}
// It is currently irrelevant from an implementation point of view
var dialogService = {
request: function (config?: ConfirmDialogOptions) {
return new Promise((resolve) => setTimeout(() => resolve(confirm(config?.body ?? "Are you sure?")), 200));
}
} as const;
<!DOCTYPE html>
<head>
<script type="module" src="./simple-greeting.js"></script>
</head>
<body>
<simple-greeting name="World"></simple-greeting>
</body>
{
"dependencies": {
"lit": "^2.0.0",
"@lit/reactive-element": "^1.0.0",
"lit-element": "^3.0.0",
"lit-html": "^2.0.0"
}
}
import {html, css, LitElement} from 'lit';
import {customElement, property} from 'lit/decorators.js';
import {confirmDialog} from './confirm-dialog.js';
@customElement('simple-greeting')
export class SimpleGreeting extends LitElement {
render() {
return html`<button
@accept="${this.onAccept}"
@decline="${this.onDecline}"
${confirmDialog({body: "Are you sure? (Customised)"})}>Click to confirm</button>`;
}
onAccept() {
alert('accepted');
}
onDecline() {
alert('declined');
}
}
{
"files": {
"simple-greeting.ts": {
"position": 0
},
"index.html": {
"position": 1
},
"package.json": {
"position": 2,
"hidden": true
},
"confirm-dialog.ts": {
"position": 3
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment