Move contexts over to useXContext model

Fixes #4
This commit is contained in:
Ryan Gossiaux
2021-12-15 10:13:01 -08:00
parent f1edb17609
commit dbfb2c227e
12 changed files with 85 additions and 31 deletions

View File

@@ -34,6 +34,22 @@
unregisterOption(id: string): void; unregisterOption(id: string): void;
select(value: unknown): void; select(value: unknown): void;
}; };
const LISTBOX_CONTEXT_NAME = "ListboxContext";
export function useListboxContext(
component: string
): Writable<StateDefinition | undefined> {
let context: Writable<StateDefinition | undefined> | undefined =
getContext(LISTBOX_CONTEXT_NAME);
if (context === undefined) {
throw new Error(
`<${component} /> is missing a parent <Listbox /> component.`
);
}
return context;
}
</script> </script>
<script lang="ts"> <script lang="ts">
@@ -41,7 +57,7 @@
Focus, Focus,
calculateActiveIndex, calculateActiveIndex,
} from "$lib/utils/calculate-active-index"; } from "$lib/utils/calculate-active-index";
import { createEventDispatcher, setContext } from "svelte"; import { createEventDispatcher, getContext, setContext } from "svelte";
import { writable, Writable } from "svelte/store"; import { writable, Writable } from "svelte/store";
import { match } from "$lib/utils/match"; import { match } from "$lib/utils/match";
import { State, useOpenClosedProvider } from "$lib/internal/open-closed"; import { State, useOpenClosedProvider } from "$lib/internal/open-closed";
@@ -63,7 +79,7 @@
let activeOptionIndex = null; let activeOptionIndex = null;
let api: Writable<StateDefinition | undefined> = writable(); let api: Writable<StateDefinition | undefined> = writable();
setContext("api", api); setContext(LISTBOX_CONTEXT_NAME, api);
let openClosedState = writable(State.Closed); let openClosedState = writable(State.Closed);
useOpenClosedProvider(openClosedState); useOpenClosedProvider(openClosedState);

View File

@@ -1,10 +1,11 @@
<script lang="ts"> <script lang="ts">
import { getContext, tick } from "svelte"; import { getContext, tick } from "svelte";
import { ListboxStates, StateDefinition } from "./Listbox.svelte"; import { ListboxStates, useListboxContext } from "./Listbox.svelte";
import { useId } from "$lib/hooks/use-id"; import { useId } from "$lib/hooks/use-id";
import { Keys } from "$lib/utils/keyboard"; import { Keys } from "$lib/utils/keyboard";
import { Focus } from "$lib/utils/calculate-active-index"; import { Focus } from "$lib/utils/calculate-active-index";
let api: SvelteStore<StateDefinition> = getContext("api");
let api = useListboxContext("ListboxButton");
let id = `headlessui-listbox-button-${useId()}`; let id = `headlessui-listbox-button-${useId()}`;
let buttonStore: SvelteStore<HTMLButtonElement> = getContext("buttonStore"); let buttonStore: SvelteStore<HTMLButtonElement> = getContext("buttonStore");

View File

@@ -1,8 +1,8 @@
<script lang="ts"> <script lang="ts">
import { getContext } from "svelte"; import { getContext } from "svelte";
import { ListboxStates, StateDefinition } from "./Listbox.svelte"; import { ListboxStates, useListboxContext } from "./Listbox.svelte";
import { useId } from "$lib/hooks/use-id"; import { useId } from "$lib/hooks/use-id";
let api: SvelteStore<StateDefinition> = getContext("api"); let api = useListboxContext("ListboxLabel");
let id = `headlessui-listbox-label-${useId()}`; let id = `headlessui-listbox-label-${useId()}`;
let labelStore: SvelteStore<HTMLLabelElement> = getContext("labelStore"); let labelStore: SvelteStore<HTMLLabelElement> = getContext("labelStore");

View File

@@ -1,11 +1,11 @@
<script lang="ts"> <script lang="ts">
import { getContext, onDestroy, onMount, tick } from "svelte"; import { onDestroy, onMount, tick } from "svelte";
import { ListboxStates, StateDefinition } from "./Listbox.svelte"; import { ListboxStates, useListboxContext } from "./Listbox.svelte";
import { useId } from "$lib/hooks/use-id"; import { useId } from "$lib/hooks/use-id";
import { Focus } from "$lib/utils/calculate-active-index"; import { Focus } from "$lib/utils/calculate-active-index";
export let value: any; export let value: any;
export let disabled = false; export let disabled = false;
let api: SvelteStore<StateDefinition> = getContext("api"); let api = useListboxContext("ListboxOption");
let id = `headlessui-listbox-option-${useId()}`; let id = `headlessui-listbox-option-${useId()}`;
$: active = $: active =

View File

@@ -1,12 +1,13 @@
<script lang="ts"> <script lang="ts">
import { getContext, tick } from "svelte"; import { getContext, tick } from "svelte";
import { ListboxStates, StateDefinition } from "./Listbox.svelte"; import { ListboxStates, useListboxContext } from "./Listbox.svelte";
import { useId } from "$lib/hooks/use-id"; import { useId } from "$lib/hooks/use-id";
import { match } from "$lib/utils/match"; import { match } from "$lib/utils/match";
import { Keys } from "$lib/utils/keyboard"; import { Keys } from "$lib/utils/keyboard";
import { Focus } from "$lib/utils/calculate-active-index"; import { Focus } from "$lib/utils/calculate-active-index";
import { State, useOpenClosed } from "$lib/internal/open-closed"; import { State, useOpenClosed } from "$lib/internal/open-closed";
let api: SvelteStore<StateDefinition> = getContext("api");
let api = useListboxContext("ListboxOptions");
let id = `headlessui-listbox-options-${useId()}`; let id = `headlessui-listbox-options-${useId()}`;
let optionsStore: SvelteStore<HTMLUListElement> = getContext("optionsStore"); let optionsStore: SvelteStore<HTMLUListElement> = getContext("optionsStore");

View File

@@ -24,6 +24,21 @@
panelId: string; panelId: string;
close(): void; close(): void;
} }
const POPOVER_CONTEXT_NAME = "PopoverContext";
export function usePopoverContext(
component: string
): Writable<StateDefinition | undefined> {
let context = getContext(POPOVER_CONTEXT_NAME) as
| Writable<StateDefinition | undefined>
| undefined;
if (context === undefined) {
throw new Error(
`<${component} /> is missing a parent <Popover /> component.`
);
}
return context;
}
</script> </script>
<script lang="ts"> <script lang="ts">
@@ -43,7 +58,7 @@
let popoverState: PopoverStates = PopoverStates.Closed; let popoverState: PopoverStates = PopoverStates.Closed;
let api: Writable<StateDefinition | undefined> = writable(); let api: Writable<StateDefinition | undefined> = writable();
setContext("PopoverApi", api); setContext(POPOVER_CONTEXT_NAME, api);
let openClosedState: Writable<State> | undefined = writable(); let openClosedState: Writable<State> | undefined = writable();
setContext("OpenClosed", openClosedState); setContext("OpenClosed", openClosedState);

View File

@@ -7,19 +7,17 @@
} from "$lib/utils/focus-management"; } from "$lib/utils/focus-management";
import { getContext } from "svelte"; import { getContext } from "svelte";
import { writable, Writable } from "svelte/store"; import { writable, Writable } from "svelte/store";
import { PopoverStates, StateDefinition } from "./Popover.svelte"; import { PopoverStates, usePopoverContext } from "./Popover.svelte";
import type { PopoverGroupContext } from "./PopoverGroup.svelte"; import { usePopoverGroupContext } from "./PopoverGroup.svelte";
import type { PopoverPanelContext } from "./PopoverPanel.svelte"; import { usePopoverPanelContext } from "./PopoverPanel.svelte";
let buttonStore: Writable<HTMLButtonElement> = getContext("PopoverButtonRef"); let buttonStore: Writable<HTMLButtonElement> = getContext("PopoverButtonRef");
export let disabled: Boolean = false; export let disabled: Boolean = false;
let api: Writable<StateDefinition> | undefined = getContext("PopoverApi"); let api = usePopoverContext("PopoverButton");
const groupContext: PopoverGroupContext | undefined = let groupContext = usePopoverGroupContext();
getContext("PopoverGroup"); let closeOthers = groupContext?.closeOthers;
const closeOthers = groupContext?.closeOthers;
let panelContext: PopoverPanelContext | undefined = let panelContext = usePopoverPanelContext();
getContext("PopoverPanel");
let isWithinPanel = let isWithinPanel =
panelContext === null ? false : panelContext === $api.panelId; panelContext === null ? false : panelContext === $api.panelId;
if (isWithinPanel) { if (isWithinPanel) {

View File

@@ -5,11 +5,16 @@
isFocusWithinPopoverGroup(): boolean; isFocusWithinPopoverGroup(): boolean;
closeOthers(buttonId: string): void; closeOthers(buttonId: string): void;
} }
const POPOVER_GROUP_CONTEXT_NAME = "PopoverGroupContext";
export function usePopoverGroupContext(): PopoverGroupContext | undefined {
return getContext(POPOVER_GROUP_CONTEXT_NAME);
}
</script> </script>
<script lang="ts"> <script lang="ts">
import type { PopoverRegisterBag } from "./Popover.svelte"; import type { PopoverRegisterBag } from "./Popover.svelte";
import { setContext } from "svelte"; import { getContext, setContext } from "svelte";
let groupRef: HTMLDivElement | undefined; let groupRef: HTMLDivElement | undefined;
let popovers: PopoverRegisterBag[] = []; let popovers: PopoverRegisterBag[] = [];
@@ -44,7 +49,7 @@
} }
} }
setContext("PopoverGroup", { setContext(POPOVER_GROUP_CONTEXT_NAME, {
unregisterPopover, unregisterPopover,
registerPopover, registerPopover,
isFocusWithinPopoverGroup, isFocusWithinPopoverGroup,

View File

@@ -2,9 +2,9 @@
import { State } from "$lib/internal/open-closed"; import { State } from "$lib/internal/open-closed";
import { getContext } from "svelte"; import { getContext } from "svelte";
import type { Writable } from "svelte/store"; import type { Writable } from "svelte/store";
import { PopoverStates, StateDefinition } from "./Popover.svelte"; import { PopoverStates, usePopoverContext } from "./Popover.svelte";
let api: Writable<StateDefinition> | undefined = getContext("PopoverApi"); let api = usePopoverContext("PopoverOverlay");
let openClosedState: Writable<State> | undefined = getContext("OpenClosed"); let openClosedState: Writable<State> | undefined = getContext("OpenClosed");

View File

@@ -1,5 +1,12 @@
<script lang="ts" context="module"> <script lang="ts" context="module">
export type PopoverPanelContext = string | null; export type PopoverPanelContext = string | null;
const POPOVER_PANEL_CONTEXT_NAME = "PopoverPanelContext";
export function usePopoverPanelContext():
| StateDefinition["panelId"]
| undefined {
return getContext(POPOVER_PANEL_CONTEXT_NAME);
}
</script> </script>
<script lang="ts"> <script lang="ts">
@@ -13,12 +20,16 @@
} from "$lib/utils/focus-management"; } from "$lib/utils/focus-management";
import { getContext, setContext, onMount } from "svelte"; import { getContext, setContext, onMount } from "svelte";
import type { Writable } from "svelte/store"; import type { Writable } from "svelte/store";
import { PopoverStates, StateDefinition } from "./Popover.svelte"; import {
PopoverStates,
StateDefinition,
usePopoverContext,
} from "./Popover.svelte";
let panelStore: SvelteStore<HTMLDivElement> = getContext("PopoverPanelRef"); let panelStore: SvelteStore<HTMLDivElement> = getContext("PopoverPanelRef");
export let focus = false; export let focus = false;
let api: Writable<StateDefinition> | undefined = getContext("PopoverApi"); let api = usePopoverContext("PopoverPanel");
setContext("PopoverPanelContext", $api.panelId); setContext(POPOVER_PANEL_CONTEXT_NAME, $api.panelId);
let openClosedState: Writable<State> | undefined = getContext("OpenClosed"); let openClosedState: Writable<State> | undefined = getContext("OpenClosed");

View File

@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import type { StateDefinition } from "./SwitchGroup.svelte"; import { useSwitchContext } from "./SwitchGroup.svelte";
import type { LabelContext } from "$lib/components/label/LabelProvider.svelte"; import type { LabelContext } from "$lib/components/label/LabelProvider.svelte";
import type { DescriptionContext } from "$lib/components/description/DescriptionProvider.svelte"; import type { DescriptionContext } from "$lib/components/description/DescriptionProvider.svelte";
import { useId } from "$lib/hooks/use-id"; import { useId } from "$lib/hooks/use-id";
@@ -9,7 +9,7 @@
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
export let checked = false; export let checked = false;
let api: Writable<StateDefinition> | undefined = getContext("SwitchApi"); let api = useSwitchContext();
let labelContext: Writable<LabelContext> | undefined = getContext( let labelContext: Writable<LabelContext> | undefined = getContext(
"headlessui-label-context" "headlessui-label-context"
); );

View File

@@ -2,12 +2,19 @@
export interface StateDefinition { export interface StateDefinition {
switchStore: Writable<HTMLButtonElement | null>; switchStore: Writable<HTMLButtonElement | null>;
} }
const SWITCH_CONTEXT_NAME = "SwitchContext";
export function useSwitchContext():
| Writable<StateDefinition | undefined>
| undefined {
return getContext(SWITCH_CONTEXT_NAME);
}
</script> </script>
<script lang="ts"> <script lang="ts">
import DescriptionProvider from "./DescriptionProvider.svelte"; import DescriptionProvider from "./DescriptionProvider.svelte";
import LabelProvider from "./LabelProvider.svelte"; import LabelProvider from "./LabelProvider.svelte";
import { setContext } from "svelte"; import { getContext, setContext } from "svelte";
import { Writable, writable } from "svelte/store"; import { Writable, writable } from "svelte/store";
let switchStore: Writable<HTMLButtonElement | null> = writable(null); let switchStore: Writable<HTMLButtonElement | null> = writable(null);