dialog: add autofreeze to sync loading state

Enabled by default, autofreeze freezes the dialog whenever loading state
is enabled.
This commit is contained in:
Elijah Duffy
2026-03-15 15:58:44 -07:00
parent ebdca97527
commit 622481a1ca

View File

@@ -141,8 +141,10 @@
onopenchange?: ({ open, dialog }: { open: boolean; dialog: DialogAPI }) => void; onopenchange?: ({ open, dialog }: { open: boolean; dialog: DialogAPI }) => void;
/** If default controls are used, controls loading state of submit button */ /** If default controls are used, controls loading state of submit button */
loading?: boolean; loading?: boolean;
/** If default controls are used, freezes all interactions */ /** If default controls are used, freezes all interactions preventing user input */
frozen?: boolean; frozen?: boolean;
/** If enabled, automatically freezes dialog when loading (default: true) */
autoFreeze?: boolean;
/** If default controls are used, disables submit button */ /** If default controls are used, disables submit button */
disabled?: boolean; disabled?: boolean;
} }
@@ -162,6 +164,7 @@
onopenchange, onopenchange,
loading = $bindable(false), loading = $bindable(false),
frozen = $bindable(false), frozen = $bindable(false),
autoFreeze = true,
disabled = $bindable(false) disabled = $bindable(false)
}: Props = $props(); }: Props = $props();
@@ -180,6 +183,8 @@
let stackIndex = $state(-1); let stackIndex = $state(-1);
const zIndex = $derived(1000 + stackIndex * 100); const zIndex = $derived(1000 + stackIndex * 100);
const reallyFrozen = $derived(autoFreeze ? frozen || loading : frozen);
/** handles open change */ /** handles open change */
const handleOpenChange = (localOpen: boolean) => { const handleOpenChange = (localOpen: boolean) => {
if (localOpen) { if (localOpen) {
@@ -244,7 +249,7 @@
/** Returns the current state of the dialog */ /** Returns the current state of the dialog */
export const getState = (): DialogState => { export const getState = (): DialogState => {
return { return {
frozen, frozen: reallyFrozen,
loading, loading,
disabled, disabled,
api: dialogAPI api: dialogAPI
@@ -271,11 +276,11 @@
transition:fade={{ duration: 150 }} transition:fade={{ duration: 150 }}
onclick={(e) => { onclick={(e) => {
const target = e.target as HTMLElement; const target = e.target as HTMLElement;
if (open && !frozen && !dialogContainer?.contains(target) && target !== dialogContainer) if (open && !reallyFrozen && !dialogContainer?.contains(target) && target !== dialogContainer)
open = false; open = false;
}} }}
onkeydown={(e) => { onkeydown={(e) => {
if (e.key === 'Escape' && !frozen) { if (e.key === 'Escape' && !reallyFrozen) {
if (stackIndex === dialogStack.length - 1) { if (stackIndex === dialogStack.length - 1) {
// only close if this dialog is the topmost dialog // only close if this dialog is the topmost dialog
open = false; open = false;
@@ -374,7 +379,7 @@
state.api.close(); state.api.close();
} }
}} }}
disabled={state.frozen} disabled={state.frozen || state.disabled}
> >
{opts?.label || 'Cancel'} {opts?.label || 'Cancel'}
</Button> </Button>