diff --git a/src/lib/components/description/DescriptionProvider.svelte b/src/lib/components/description/DescriptionProvider.svelte index 38b2b5e..9d4881d 100644 --- a/src/lib/components/description/DescriptionProvider.svelte +++ b/src/lib/components/description/DescriptionProvider.svelte @@ -18,7 +18,7 @@ import { getContext, setContext } from "svelte"; import { writable, Writable } from "svelte/store"; export let name: string; - let descriptionIds = []; + let descriptionIds: string[] = []; let contextStore: Writable = writable({ name, register, diff --git a/src/lib/components/dialog/Dialog.svelte b/src/lib/components/dialog/Dialog.svelte index 8ed7517..ba6eacb 100644 --- a/src/lib/components/dialog/Dialog.svelte +++ b/src/lib/components/dialog/Dialog.svelte @@ -15,9 +15,9 @@ export interface StateDefinition { dialogState: DialogStates; - titleId: string | null; + titleId?: string; - setTitleId(id: string | null): void; + setTitleId(id?: string): void; close(): void; } @@ -26,9 +26,9 @@ export function useDialogContext( component: string - ): Writable { + ): Writable { let context = getContext(DIALOG_CONTEXT_NAME) as - | Writable + | Writable | undefined; if (context === undefined) { throw new Error( @@ -112,14 +112,12 @@ } }); - let titleId: StateDefinition["titleId"] = null; + let titleId: StateDefinition["titleId"]; - let api: Writable = writable(); - setContext(DIALOG_CONTEXT_NAME, api); - $: api.set({ + let api: Writable = writable({ titleId, dialogState, - setTitleId(id: string | null) { + setTitleId(id?: string) { if (titleId === id) return; titleId = id; }, @@ -127,6 +125,14 @@ dispatch("close", false); }, }); + setContext(DIALOG_CONTEXT_NAME, api); + $: api.update((obj) => { + return { + ...obj, + titleId, + dialogState, + }; + }); // Handle outside click async function handleWindowMousedown(event: MouseEvent) { @@ -136,7 +142,7 @@ if (containers.size !== 1) return; if (contains(containers, target)) return; - $api.close(); + $api?.close(); await tick(); target?.focus(); } @@ -148,7 +154,7 @@ if (containers.size > 1) return; // 1 is myself, otherwise other elements in the Stack event.preventDefault(); event.stopPropagation(); - $api.close(); + $api?.close(); } let mounted = false; @@ -196,7 +202,7 @@ entry.boundingClientRect.width === 0 && entry.boundingClientRect.height === 0 ) { - $api.close(); + $api?.close(); } } }); diff --git a/src/lib/components/dialog/DialogOverlay.svelte b/src/lib/components/dialog/DialogOverlay.svelte index 74de6b3..6ef9100 100644 --- a/src/lib/components/dialog/DialogOverlay.svelte +++ b/src/lib/components/dialog/DialogOverlay.svelte @@ -7,7 +7,7 @@ if (event.target !== event.currentTarget) return; event.preventDefault(); event.stopPropagation(); - $api.close(); + $api?.close(); } $: propsWeControl = { id, @@ -16,5 +16,5 @@
- +
diff --git a/src/lib/components/disclosure/Disclosure.svelte b/src/lib/components/disclosure/Disclosure.svelte index 480e74a..24f5096 100644 --- a/src/lib/components/disclosure/Disclosure.svelte +++ b/src/lib/components/disclosure/Disclosure.svelte @@ -26,8 +26,8 @@ export function useDisclosureContext( component: string - ): Writable { - let context: Writable | undefined = getContext( + ): Writable { + let context: Writable | undefined = getContext( DISCLOSURE_CONTEXT_NAME ); @@ -55,10 +55,7 @@ let panelStore: StateDefinition["panelStore"] = writable(null); let buttonStore: StateDefinition["buttonStore"] = writable(null); - let api: Writable = writable(); - setContext(DISCLOSURE_CONTEXT_NAME, api); - - $: api.set({ + let api: Writable = writable({ buttonId, panelId, disclosureState, @@ -87,6 +84,14 @@ restoreElement?.focus(); }, }); + setContext(DISCLOSURE_CONTEXT_NAME, api); + + $: api.update((obj) => { + return { + ...obj, + disclosureState, + }; + }); let openClosedState: Writable | undefined = writable(); setContext("OpenClosed", openClosedState); diff --git a/src/lib/components/label/LabelProvider.svelte b/src/lib/components/label/LabelProvider.svelte index 6df97f6..1b91721 100644 --- a/src/lib/components/label/LabelProvider.svelte +++ b/src/lib/components/label/LabelProvider.svelte @@ -16,7 +16,7 @@ import { getContext, setContext } from "svelte"; import { writable, Writable } from "svelte/store"; export let name: string; - let labelIds = []; + let labelIds: string[] = []; let contextStore: Writable = writable({ name, register, diff --git a/src/lib/components/listbox/Listbox.svelte b/src/lib/components/listbox/Listbox.svelte index 2aebe20..b31bfc7 100644 --- a/src/lib/components/listbox/Listbox.svelte +++ b/src/lib/components/listbox/Listbox.svelte @@ -38,8 +38,8 @@ const LISTBOX_CONTEXT_NAME = "ListboxContext"; export function useListboxContext( component: string - ): Writable { - let context: Writable | undefined = + ): Writable { + let context: Writable | undefined = getContext(LISTBOX_CONTEXT_NAME); if (context === undefined) { @@ -61,6 +61,12 @@ import { writable, Writable } from "svelte/store"; import { match } from "$lib/utils/match"; import { State, useOpenClosedProvider } from "$lib/internal/open-closed"; + export let disabled = false; + export let horizontal = false; + export let value: any; + $: orientation = (horizontal ? "horizontal" : "vertical") as + | "horizontal" + | "vertical"; const dispatch = createEventDispatcher(); @@ -68,41 +74,23 @@ let labelStore = writable(null); setContext("labelStore", labelStore); $: labelRef = $labelStore; - let buttonStore = writable(null); - setContext("buttonStore", buttonStore); - $: buttonRef = $buttonStore; - let optionsStore = writable(null); - setContext("optionsStore", optionsStore); - $: optionsRef = $optionsStore; - let options = []; - let searchQuery = ""; - let activeOptionIndex = null; - let api: Writable = writable(); - setContext(LISTBOX_CONTEXT_NAME, api); + let buttonRef: Writable = writable(null); + setContext("buttonStore", buttonRef); - let openClosedState = writable(State.Closed); - useOpenClosedProvider(openClosedState); - $: openClosedState.set( - match(listboxState, { - [ListboxStates.Open]: State.Open, - [ListboxStates.Closed]: State.Closed, - }) - ); + let optionsRef: Writable = writable(null); + setContext("optionsStore", optionsRef); - export let disabled = false; - export let horizontal = false; - export let value: any; + let options: StateDefinition["options"] = []; + let searchQuery: StateDefinition["searchQuery"] = ""; + let activeOptionIndex: StateDefinition["activeOptionIndex"] = null; - $: orientation = (horizontal ? "horizontal" : "vertical") as - | "horizontal" - | "vertical"; - $: api.set({ + let api: Writable = writable({ listboxState, labelRef, value, - buttonRef, - optionsRef, + buttonRef: $buttonRef, + optionsRef: $optionsRef, options, searchQuery, activeOptionIndex, @@ -131,7 +119,7 @@ resolveItems: () => options, resolveActiveIndex: () => activeOptionIndex, resolveId: (option) => option.id, - resolveDisabled: (option) => option.disabled, + resolveDisabled: (option) => option.dataRef.disabled, } ); @@ -147,7 +135,9 @@ searchQuery += value.toLowerCase(); let match = options.findIndex( - (option) => !option.disabled && option.textValue.startsWith(searchQuery) + (option) => + !option.dataRef.disabled && + option.dataRef.textValue.startsWith(searchQuery) ); if (match === -1 || match === activeOptionIndex) return; @@ -184,18 +174,44 @@ dispatch("updateValue", { value }); }, }); + setContext(LISTBOX_CONTEXT_NAME, api); + + let openClosedState = writable(State.Closed); + useOpenClosedProvider(openClosedState); + $: openClosedState.set( + match(listboxState, { + [ListboxStates.Open]: State.Open, + [ListboxStates.Closed]: State.Closed, + }) + ); + + $: api.update((obj) => { + return { + ...obj, + listboxState, + labelRef, + value, + buttonRef: $buttonRef, + optionsRef: $optionsRef, + options, + searchQuery, + activeOptionIndex, + disabled, + orientation, + }; + }); function handleMousedown(event: MouseEvent) { let target = event.target as HTMLElement; let active = document.activeElement; if (listboxState !== ListboxStates.Open) return; - if (buttonRef?.contains(target)) return; + if ($buttonRef?.contains(target)) return; - if (!optionsRef?.contains(target)) $api.closeListbox(); + if (!$optionsRef?.contains(target)) $api.closeListbox(); if (active !== document.body && active?.contains(target)) return; // Keep focus on newly clicked/focused element if (!event.defaultPrevented) { - buttonRef?.focus({ preventScroll: true }); + $buttonRef?.focus({ preventScroll: true }); } } diff --git a/src/lib/components/switch/Switch.svelte b/src/lib/components/switch/Switch.svelte index 834e78c..9bcd4ce 100644 --- a/src/lib/components/switch/Switch.svelte +++ b/src/lib/components/switch/Switch.svelte @@ -19,7 +19,6 @@ let descriptionContext = useDescriptionContext(); let id = `headlessui-switch-${useId()}`; $: switchStore = $api?.switchStore; - let internalSwitchRef = null; function toggle() { dispatch("updateValue", !checked); @@ -63,7 +62,6 @@ {:else}