From 2d694a7277b1c0a753b49051ca23e128cb783ce9 Mon Sep 17 00:00:00 2001 From: Elijah Duffy Date: Tue, 3 Mar 2026 16:42:38 -0800 Subject: [PATCH] dialog: title & control customization with snippets, fixed callbacks --- src/lib/Dialog.svelte | 223 +++++++++++++++++++++++++++++------------- src/lib/index.ts | 9 +- 2 files changed, 165 insertions(+), 67 deletions(-) diff --git a/src/lib/Dialog.svelte b/src/lib/Dialog.svelte index 2719007..c759fbf 100644 --- a/src/lib/Dialog.svelte +++ b/src/lib/Dialog.svelte @@ -42,8 +42,11 @@ } type DialogControlButton = { + /** Label for the button */ label?: string; + /** Additional classes to apply to the button */ class?: ClassValue; + /** Callback when the button is pressed */ action?: (dialog: DialogAPI) => void; }; @@ -51,25 +54,36 @@ * Configures the default dialog controls. */ export type DialogControls = { + /** Options for the bottom cancel button */ cancel?: DialogControlButton | null; + /** Options for the bottom submit button */ ok?: DialogControlButton | null; - close?: Omit | null; + /** Inverts the order of the buttons */ + flip?: boolean; + }; + + /** + * Stores internal state of the dialog, everything necessary to render + * internal snippets. + */ + type DialogState = { + frozen: boolean; + loading: boolean; + disabled: boolean; + api: DialogAPI; }; const defaultDialogControls: DialogControls = { - cancel: { - label: 'Cancel' - }, - ok: { - label: 'OK' - }, - close: {} + cancel: { label: 'Cancel' }, + ok: { label: 'OK' } }; + + export { dialogCancelButton, dialogOkButton, dialogCloseButton }; @@ -190,7 +233,21 @@ start: 0.96 }} > -

{title}

+
+ +

+ {@render stringOrSnippet(title)} +

+ + + {#if close !== null} + {#if typeof close === 'function'} + {@render close()} + {:else} + {@render dialogCloseButton(getState(), close)} + {/if} + {/if} +
{#if error} @@ -198,68 +255,102 @@ {#if description}

- {description} + {@render stringOrSnippet(description)}

{/if} {#if children}{@render children()}{:else}Dialog is empty{/if} -
+
{#if controls && typeof controls === 'function'}{@render controls()}{:else} - {#if controls.cancel !== null} - - {/if} {#if controls.ok !== null} - + {@render dialogOkButton(getState(), controls.ok)} + {/if} + {#if controls?.flip} + {#if controls.cancel !== null} + {@render dialogCancelButton(getState(), controls.cancel)} + {/if} + {:else} + {#if controls.cancel !== null} + {@render dialogCancelButton(getState(), controls.cancel)} + {/if} + {#if controls.ok !== null} + {@render dialogOkButton(getState(), controls.ok)} + {/if} {/if} {/if}
- - - {#if typeof controls === 'function' || controls?.close !== null} - - {/if}
{/snippet} + +{#snippet dialogCancelButton(state: DialogState, opts?: DialogControls['cancel'])} + +{/snippet} + +{#snippet dialogOkButton(state: DialogState, opts?: DialogControls['ok'])} + +{/snippet} + +{#snippet dialogCloseButton(state: DialogState, opts?: Omit | null)} + +{/snippet} + +{#snippet stringOrSnippet(val: string | Snippet)} + {#if typeof val === 'string'} + {val} + {:else} + {@render val()} + {/if} +{/snippet} diff --git a/src/lib/index.ts b/src/lib/index.ts index 39c866e..9a695b3 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -6,7 +6,14 @@ export { default as CenterBox } from './CenterBox.svelte'; export { default as Checkbox, type CheckboxState } from './Checkbox.svelte'; export { default as Combobox, type ComboboxOption } from './Combobox.svelte'; export { default as DateInput } from './DateInput.svelte'; -export { default as Dialog, type DialogAPI, type DialogControls } from './Dialog.svelte'; +export { + default as Dialog, + type DialogAPI, + type DialogControls, + dialogCancelButton, + dialogCloseButton, + dialogOkButton +} from './Dialog.svelte'; export { default as DurationInput, formatDuration,