@pzerelles/headlessui-svelte 2.1.2-next.30 → 2.1.2-next.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/dist/button/Button.svelte +84 -54
  2. package/dist/button/Button.svelte.d.ts +2 -3
  3. package/dist/checkbox/Checkbox.svelte +173 -120
  4. package/dist/checkbox/Checkbox.svelte.d.ts +2 -3
  5. package/dist/close-button/CloseButton.svelte +12 -6
  6. package/dist/close-button/CloseButton.svelte.d.ts +7 -8
  7. package/dist/combobox/Combobox.svelte +50 -3
  8. package/dist/data-interactive/DataInteractive.svelte +55 -29
  9. package/dist/data-interactive/DataInteractive.svelte.d.ts +2 -3
  10. package/dist/description/Description.svelte +31 -21
  11. package/dist/description/Description.svelte.d.ts +1 -2
  12. package/dist/dialog/Dialog.svelte +320 -228
  13. package/dist/dialog/Dialog.svelte.d.ts +2 -3
  14. package/dist/dialog/DialogBackdrop.svelte +30 -13
  15. package/dist/dialog/DialogBackdrop.svelte.d.ts +2 -3
  16. package/dist/dialog/DialogPanel.svelte +49 -26
  17. package/dist/dialog/DialogPanel.svelte.d.ts +2 -3
  18. package/dist/dialog/DialogTitle.svelte +38 -23
  19. package/dist/dialog/DialogTitle.svelte.d.ts +2 -3
  20. package/dist/field/Field.svelte +47 -25
  21. package/dist/field/Field.svelte.d.ts +1 -2
  22. package/dist/fieldset/Fieldset.svelte +50 -29
  23. package/dist/fieldset/Fieldset.svelte.d.ts +1 -2
  24. package/dist/focus-trap/FocusTrap.svelte +419 -283
  25. package/dist/focus-trap/FocusTrap.svelte.d.ts +1 -2
  26. package/dist/input/Input.svelte +84 -53
  27. package/dist/input/Input.svelte.d.ts +2 -3
  28. package/dist/internal/FloatingProvider.svelte +14 -9
  29. package/dist/internal/FocusSentinel.svelte +16 -8
  30. package/dist/internal/ForcePortalRoot.svelte +7 -3
  31. package/dist/internal/FormFields.svelte +47 -34
  32. package/dist/internal/FormFieldsProvider.svelte +9 -5
  33. package/dist/internal/FormResolver.svelte +20 -15
  34. package/dist/internal/Hidden.svelte +50 -29
  35. package/dist/internal/Hidden.svelte.d.ts +1 -2
  36. package/dist/internal/MainTreeProvider.svelte +89 -36
  37. package/dist/internal/Portal.svelte +18 -14
  38. package/dist/internal/floating.svelte.d.ts +2 -3
  39. package/dist/internal/floating.svelte.js +0 -1
  40. package/dist/label/Label.svelte +93 -58
  41. package/dist/label/Label.svelte.d.ts +1 -2
  42. package/dist/legend/Legend.svelte +12 -3
  43. package/dist/listbox/Listbox.svelte +525 -387
  44. package/dist/listbox/Listbox.svelte.d.ts +2 -3
  45. package/dist/listbox/ListboxButton.svelte +173 -127
  46. package/dist/listbox/ListboxButton.svelte.d.ts +2 -3
  47. package/dist/listbox/ListboxOption.svelte +170 -129
  48. package/dist/listbox/ListboxOption.svelte.d.ts +2 -3
  49. package/dist/listbox/ListboxOptions.svelte +400 -304
  50. package/dist/listbox/ListboxOptions.svelte.d.ts +2 -3
  51. package/dist/listbox/ListboxSelectedOption.svelte +38 -15
  52. package/dist/listbox/ListboxSelectedOption.svelte.d.ts +1 -2
  53. package/dist/menu/Menu.svelte +77 -51
  54. package/dist/menu/Menu.svelte.d.ts +2 -4
  55. package/dist/menu/MenuButton.svelte +157 -117
  56. package/dist/menu/MenuButton.svelte.d.ts +2 -3
  57. package/dist/menu/MenuHeading.svelte +32 -14
  58. package/dist/menu/MenuHeading.svelte.d.ts +1 -2
  59. package/dist/menu/MenuItem.svelte +142 -107
  60. package/dist/menu/MenuItem.svelte.d.ts +2 -3
  61. package/dist/menu/MenuItems.svelte +301 -229
  62. package/dist/menu/MenuItems.svelte.d.ts +2 -3
  63. package/dist/menu/MenuSection.svelte +24 -9
  64. package/dist/menu/MenuSection.svelte.d.ts +1 -2
  65. package/dist/menu/MenuSeparator.svelte +17 -4
  66. package/dist/menu/MenuSeparator.svelte.d.ts +1 -2
  67. package/dist/popover/Popover.svelte +216 -150
  68. package/dist/popover/Popover.svelte.d.ts +2 -3
  69. package/dist/popover/PopoverBackdrop.svelte +67 -41
  70. package/dist/popover/PopoverBackdrop.svelte.d.ts +2 -3
  71. package/dist/popover/PopoverButton.svelte +292 -212
  72. package/dist/popover/PopoverButton.svelte.d.ts +2 -3
  73. package/dist/popover/PopoverGroup.svelte +62 -35
  74. package/dist/popover/PopoverGroup.svelte.d.ts +1 -2
  75. package/dist/popover/PopoverPanel.svelte +311 -229
  76. package/dist/popover/PopoverPanel.svelte.d.ts +2 -3
  77. package/dist/portal/InternalPortal.svelte +141 -85
  78. package/dist/portal/InternalPortal.svelte.d.ts +1 -2
  79. package/dist/portal/Portal.svelte +5 -2
  80. package/dist/portal/PortalGroup.svelte +30 -9
  81. package/dist/portal/PortalGroup.svelte.d.ts +1 -2
  82. package/dist/select/Select.svelte +98 -68
  83. package/dist/select/Select.svelte.d.ts +2 -3
  84. package/dist/switch/Switch.svelte +179 -132
  85. package/dist/switch/Switch.svelte.d.ts +2 -3
  86. package/dist/switch/SwitchGroup.svelte +44 -31
  87. package/dist/switch/SwitchGroup.svelte.d.ts +1 -2
  88. package/dist/tabs/Tab.svelte +194 -142
  89. package/dist/tabs/Tab.svelte.d.ts +2 -3
  90. package/dist/tabs/TabGroup.svelte +86 -56
  91. package/dist/tabs/TabGroup.svelte.d.ts +2 -3
  92. package/dist/tabs/TabList.svelte +31 -11
  93. package/dist/tabs/TabList.svelte.d.ts +2 -3
  94. package/dist/tabs/TabPanel.svelte +67 -42
  95. package/dist/tabs/TabPanel.svelte.d.ts +2 -3
  96. package/dist/tabs/TabPanels.svelte +18 -7
  97. package/dist/tabs/TabPanels.svelte.d.ts +2 -3
  98. package/dist/textarea/Textarea.svelte +84 -53
  99. package/dist/textarea/Textarea.svelte.d.ts +2 -3
  100. package/dist/transition/InternalTransitionChild.svelte +259 -170
  101. package/dist/transition/InternalTransitionChild.svelte.d.ts +2 -3
  102. package/dist/transition/Transition.svelte +96 -66
  103. package/dist/transition/Transition.svelte.d.ts +2 -3
  104. package/dist/transition/TransitionChild.svelte +31 -11
  105. package/dist/transition/TransitionChild.svelte.d.ts +2 -3
  106. package/dist/utils/DisabledProvider.svelte +7 -3
  107. package/dist/utils/ElementOrComponent.svelte +46 -23
  108. package/dist/utils/ElementOrComponent.svelte.d.ts +8 -10
  109. package/dist/utils/Generic.svelte +30 -19
  110. package/dist/utils/Generic.svelte.d.ts +6 -7
  111. package/dist/utils/StableCollection.svelte +54 -36
  112. package/dist/utils/floating-ui/svelte/components/FloatingNode.svelte +27 -12
  113. package/dist/utils/floating-ui/svelte/components/FloatingTree.svelte +88 -44
  114. package/dist/utils/types.d.ts +4 -5
  115. package/package.json +1 -1
@@ -16,8 +16,7 @@ declare class __sveltets_Render<TTag extends ElementType = typeof DEFAULT_FOCUS_
16
16
  as?: TTag | undefined;
17
17
  } & (Exclude<keyof import("../utils/types.js").PropsOf<TTag>, ("slot" | "as" | "children" | "class" | "ref") | "features" | "containers" | "initialFocus" | "initialFocusFallback"> extends infer T extends keyof import("../utils/types.js").PropsOf<TTag> ? { [P in T]: import("../utils/types.js").PropsOf<TTag>[P]; } : never) & {
18
18
  children?: import("svelte").Snippet<[{
19
- slot: FocusTrapRenderPropArg;
20
- props: Record<string, any>;
19
+ props?: Record<string, any>;
21
20
  }]> | undefined;
22
21
  class?: string | ((bag: FocusTrapRenderPropArg) => string) | null | undefined;
23
22
  ref?: HTMLElement;
@@ -1,59 +1,90 @@
1
- <script lang="ts" module>const DEFAULT_INPUT_TAG = "input";
2
- </script>
1
+ <script lang="ts" module>
2
+ import type { ElementType, Props, PropsOf } from "../utils/types.js"
3
3
 
4
- <script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_INPUT_TAG, TValue = string">import { htmlid } from "../utils/id.js";
5
- import { useDisabled } from "../hooks/use-disabled.js";
6
- import { useProvidedId } from "../utils/id.js";
7
- import { useLabelledBy } from "../label/context.svelte.js";
8
- import { useDescribedBy } from "../description/context.svelte.js";
9
- import { useHover } from "../hooks/use-hover.svelte.js";
10
- import { useFocusRing } from "../hooks/use-focus-ring.svelte.js";
11
- import { mergeProps } from "../utils/render.js";
12
- import ElementOrComponent from "../utils/ElementOrComponent.svelte";
13
- const internalId = htmlid();
14
- const providedId = useProvidedId();
15
- const providedDisabled = useDisabled();
16
- let {
17
- ref = $bindable(),
18
- value = $bindable(),
19
- id = providedId || `headlessui-input-${internalId}`,
20
- disabled: theirDisabled = false,
21
- autofocus = false,
22
- invalid = false,
23
- ...theirProps
24
- } = $props();
25
- const disabled = $derived(providedDisabled.current || theirDisabled);
26
- const labelledBy = useLabelledBy();
27
- const describedBy = useDescribedBy();
28
- const { isHovered: hover, hoverProps } = $derived(
29
- useHover({
30
- get disabled() {
31
- return disabled;
32
- }
33
- })
34
- );
35
- const { isFocusVisible: focus, focusProps } = $derived(
36
- useFocusRing({
37
- get autofocus() {
38
- return autofocus;
39
- }
40
- })
41
- );
42
- const ourProps = $derived(
43
- mergeProps(
4
+ const DEFAULT_INPUT_TAG = "input" as const
5
+
6
+ type InputRenderPropArg = {
7
+ disabled: boolean
8
+ hover: boolean
9
+ focus: boolean
10
+ autofocus: boolean
11
+ invalid: boolean
12
+ }
13
+ type InputPropsWeControl = "aria-labelledby" | "aria-describedby"
14
+
15
+ export type InputProps<TTag extends ElementType = typeof DEFAULT_INPUT_TAG, TValue = string> = Props<
16
+ TTag,
17
+ InputRenderPropArg,
18
+ InputPropsWeControl,
44
19
  {
45
- id,
46
- "aria-labelledby": labelledBy?.value,
47
- "aria-describedby": describedBy?.value,
48
- "aria-invalid": invalid ? "" : void 0,
49
- disabled: disabled || void 0,
50
- autofocus
51
- },
52
- focusProps,
53
- hoverProps
20
+ value?: TValue
21
+ disabled?: boolean
22
+ invalid?: boolean
23
+ autofocus?: boolean
24
+ }
25
+ >
26
+ </script>
27
+
28
+ <script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_INPUT_TAG, TValue = string">
29
+ import { htmlid } from "../utils/id.js"
30
+ import { useDisabled } from "../hooks/use-disabled.js"
31
+ import { useProvidedId } from "../utils/id.js"
32
+ import { useLabelledBy } from "../label/context.svelte.js"
33
+ import { useDescribedBy } from "../description/context.svelte.js"
34
+ import { useHover } from "../hooks/use-hover.svelte.js"
35
+ import { useFocusRing } from "../hooks/use-focus-ring.svelte.js"
36
+ import { mergeProps } from "../utils/render.js"
37
+ import ElementOrComponent from "../utils/ElementOrComponent.svelte"
38
+
39
+ const internalId = htmlid()
40
+ const providedId = useProvidedId()
41
+ const providedDisabled = useDisabled()
42
+
43
+ let {
44
+ ref = $bindable(),
45
+ value = $bindable(),
46
+ id = (providedId || `headlessui-input-${internalId}`) as PropsOf<TTag>["id"],
47
+ disabled: theirDisabled = false,
48
+ autofocus = false,
49
+ invalid = false,
50
+ ...theirProps
51
+ }: { as?: TTag; value?: TValue } & InputProps<TTag, TValue> = $props()
52
+ const disabled = $derived(providedDisabled.current || theirDisabled)
53
+
54
+ const labelledBy = useLabelledBy()
55
+ const describedBy = useDescribedBy()
56
+
57
+ const { isHovered: hover, hoverProps } = $derived(
58
+ useHover({
59
+ get disabled() {
60
+ return disabled
61
+ },
62
+ })
54
63
  )
55
- );
56
- const slot = $derived({ disabled, invalid, hover, focus, autofocus });
64
+ const { isFocusVisible: focus, focusProps } = $derived(
65
+ useFocusRing({
66
+ get autofocus() {
67
+ return autofocus
68
+ },
69
+ })
70
+ )
71
+
72
+ const ourProps = $derived(
73
+ mergeProps(
74
+ {
75
+ id,
76
+ "aria-labelledby": labelledBy?.value,
77
+ "aria-describedby": describedBy?.value,
78
+ "aria-invalid": invalid ? "" : undefined,
79
+ disabled: disabled || undefined,
80
+ autofocus,
81
+ },
82
+ focusProps,
83
+ hoverProps
84
+ )
85
+ )
86
+
87
+ const slot = $derived({ disabled, invalid, hover, focus, autofocus } satisfies InputRenderPropArg)
57
88
  </script>
58
89
 
59
90
  <ElementOrComponent {ourProps} {theirProps} {slot} defaultTag={DEFAULT_INPUT_TAG} name="Input" bind:ref bind:value />
@@ -19,9 +19,8 @@ declare class __sveltets_Render<TTag extends ElementType = typeof DEFAULT_INPUT_
19
19
  as?: TTag | undefined;
20
20
  value?: TValue | undefined;
21
21
  } & (Exclude<keyof PropsOf<TTag>, ("slot" | "as" | "children" | "class" | "ref") | "invalid" | "disabled" | "autofocus" | "value" | InputPropsWeControl> extends infer T extends keyof PropsOf<TTag> ? { [P in T]: PropsOf<TTag>[P]; } : never) & {
22
- children?: import("svelte").Snippet<[{
23
- slot: InputRenderPropArg;
24
- props: Record<string, any>;
22
+ children?: import("svelte").Snippet<[InputRenderPropArg & {
23
+ props?: Record<string, any>;
25
24
  }]> | undefined;
26
25
  class?: string | ((bag: InputRenderPropArg) => string) | null | undefined;
27
26
  ref?: HTMLElement;
@@ -1,12 +1,17 @@
1
- <script lang="ts" module></script>
2
-
3
- <script lang="ts">import { useFloatingProvider } from "./floating-provider.svelte.js";
4
- const { children, enabled = true } = $props();
5
- useFloatingProvider({
6
- get enabled() {
7
- return enabled;
8
- }
9
- });
1
+ <script lang="ts" module>
2
+ </script>
3
+
4
+ <script lang="ts">
5
+ import type { Snippet } from "svelte"
6
+ import { useFloatingProvider } from "./floating-provider.svelte.js"
7
+
8
+ const { children, enabled = true }: { children: Snippet; enabled?: boolean } = $props()
9
+
10
+ useFloatingProvider({
11
+ get enabled() {
12
+ return enabled
13
+ },
14
+ })
10
15
  </script>
11
16
 
12
17
  {#if children}{@render children()}{/if}
@@ -1,11 +1,19 @@
1
- <script lang="ts">import { onMount } from "svelte";
2
- import Hidden, { HiddenFeatures } from "./Hidden.svelte";
3
- let { onfocus } = $props();
4
- let enabled = $state(true);
5
- let mounted = $state(false);
6
- onMount(() => {
7
- mounted = true;
8
- });
1
+ <script lang="ts">
2
+ import { onMount } from "svelte"
3
+ import Hidden, { HiddenFeatures } from "./Hidden.svelte"
4
+
5
+ interface FocusSentinelProps {
6
+ onfocus: () => boolean
7
+ }
8
+
9
+ let { onfocus }: FocusSentinelProps = $props()
10
+
11
+ let enabled = $state(true)
12
+ let mounted = $state(false)
13
+
14
+ onMount(() => {
15
+ mounted = true
16
+ })
9
17
  </script>
10
18
 
11
19
  {#if enabled}
@@ -1,6 +1,10 @@
1
- <script lang="ts">import { createPortalRoot } from "./portal-force-root.svelte.js";
2
- let { force, children } = $props();
3
- createPortalRoot({ force });
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte"
3
+ import { createPortalRoot } from "./portal-force-root.svelte.js"
4
+
5
+ let { force, children }: { force: boolean; children: Snippet } = $props()
6
+
7
+ createPortalRoot({ force })
4
8
  </script>
5
9
 
6
10
  {#if children}{@render children()}{/if}
@@ -1,38 +1,51 @@
1
- <script lang="ts">import { disposables } from "../utils/disposables.js";
2
- import { objectToFormEntries } from "../utils/form.js";
3
- import FormResolver from "./FormResolver.svelte";
4
- import { hoistFormFields } from "./form-fields.svelte.js";
5
- import Hidden, { HiddenFeatures } from "./Hidden.svelte";
6
- import { compact } from "../utils/object.js";
7
- let {
8
- data,
9
- form: formId,
10
- disabled,
11
- onReset,
12
- overrides
13
- } = $props();
14
- let form = $state(null);
15
- const d = disposables();
16
- $effect(() => {
17
- if (!onReset) return;
18
- if (!form) return;
19
- return d.addEventListener(form, "reset", onReset);
20
- });
21
- const fields = $derived(
22
- objectToFormEntries(data).map(
23
- ([name, value]) => compact({
24
- key: name,
25
- as: "input",
26
- type: "hidden",
27
- form: formId,
28
- disabled,
29
- name,
30
- value,
31
- ...overrides
32
- })
1
+ <script lang="ts">
2
+ import { disposables } from "../utils/disposables.js"
3
+ import { objectToFormEntries } from "../utils/form.js"
4
+ import FormResolver from "./FormResolver.svelte"
5
+ import { hoistFormFields } from "./form-fields.svelte.js"
6
+ import Hidden, { HiddenFeatures } from "./Hidden.svelte"
7
+ import { compact } from "../utils/object.js"
8
+
9
+ let {
10
+ data,
11
+ form: formId,
12
+ disabled,
13
+ onReset,
14
+ overrides,
15
+ }: {
16
+ data: Record<string, any>
17
+ overrides?: Record<string, any>
18
+ form?: string
19
+ disabled?: boolean
20
+ onReset?: (e: Event) => void
21
+ } = $props()
22
+
23
+ let form = $state<HTMLFormElement | null>(null)
24
+ const d = disposables()
25
+
26
+ $effect(() => {
27
+ if (!onReset) return
28
+ if (!form) return
29
+
30
+ return d.addEventListener(form, "reset", onReset)
31
+ })
32
+
33
+ const fields = $derived(
34
+ objectToFormEntries(data).map(([name, value]) =>
35
+ compact({
36
+ key: name,
37
+ as: "input",
38
+ type: "hidden",
39
+ form: formId,
40
+ disabled,
41
+ name,
42
+ value,
43
+ ...overrides,
44
+ })
45
+ )
33
46
  )
34
- );
35
- const hoisted = hoistFormFields(formFields);
47
+
48
+ const hoisted = hoistFormFields(formFields)
36
49
  </script>
37
50
 
38
51
  {#snippet formFields()}
@@ -1,8 +1,12 @@
1
- <script lang="ts">import Hidden, { HiddenFeatures } from "./Hidden.svelte";
2
- import { createFormFieldsContext } from "./form-fields.svelte.js";
3
- const { children } = $props();
4
- const context = createFormFieldsContext();
5
- const { fields } = $derived(context);
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte"
3
+ import Hidden, { HiddenFeatures } from "./Hidden.svelte"
4
+ import { createFormFieldsContext } from "./form-fields.svelte.js"
5
+
6
+ const { children }: { children?: Snippet } = $props()
7
+
8
+ const context = createFormFieldsContext()
9
+ const { fields } = $derived(context)
6
10
  </script>
7
11
 
8
12
  {#if children}{@render children()}{/if}
@@ -1,18 +1,23 @@
1
- <script lang="ts">import { onMount } from "svelte";
2
- import Hidden, { HiddenFeatures } from "./Hidden.svelte";
3
- let { setForm, formId } = $props();
4
- $effect(() => {
5
- if (formId) {
6
- const resolvedForm = document.getElementById(formId);
7
- if (resolvedForm) setForm(resolvedForm);
8
- }
9
- });
10
- let element = $state();
11
- onMount(() => {
12
- if (!element) return;
13
- const resolvedForm = element.closest("form");
14
- if (resolvedForm) setForm(resolvedForm);
15
- });
1
+ <script lang="ts">
2
+ import { onMount } from "svelte"
3
+ import Hidden, { HiddenFeatures } from "./Hidden.svelte"
4
+
5
+ let { setForm, formId }: { setForm: (form: HTMLFormElement) => void; formId?: string } = $props()
6
+
7
+ $effect(() => {
8
+ if (formId) {
9
+ const resolvedForm = document.getElementById(formId) as HTMLFormElement
10
+ if (resolvedForm) setForm(resolvedForm)
11
+ }
12
+ })
13
+
14
+ let element = $state<HTMLElement>()
15
+
16
+ onMount(() => {
17
+ if (!element) return
18
+ const resolvedForm = element.closest("form")
19
+ if (resolvedForm) setForm(resolvedForm)
20
+ })
16
21
  </script>
17
22
 
18
23
  {#if !formId}
@@ -1,34 +1,55 @@
1
- <script lang="ts" module>import ElementOrComponent from "../utils/ElementOrComponent.svelte";
2
- import { HiddenFeatures } from "./HiddenFeatures.js";
3
- export * from "./HiddenFeatures.js";
4
- const DEFAULT_VISUALLY_HIDDEN_TAG = "span";
1
+ <script lang="ts" module>
2
+ import ElementOrComponent from "../utils/ElementOrComponent.svelte"
3
+ import type { ElementType, Props } from "../utils/types.js"
4
+ import { HiddenFeatures } from "./HiddenFeatures.js"
5
+
6
+ export * from "./HiddenFeatures.js"
7
+
8
+ const DEFAULT_VISUALLY_HIDDEN_TAG = "span" as const
9
+
10
+ type HiddenRenderPropArg = {}
11
+ type HiddenPropsWeControl = never
12
+ export type HiddenProps<TTag extends ElementType = typeof DEFAULT_VISUALLY_HIDDEN_TAG> = Props<
13
+ TTag,
14
+ HiddenRenderPropArg,
15
+ HiddenPropsWeControl,
16
+ { features?: HiddenFeatures }
17
+ >
5
18
  </script>
6
19
 
7
- <script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_VISUALLY_HIDDEN_TAG">let {
8
- ref = $bindable(),
9
- value,
10
- checked,
11
- features = HiddenFeatures.None,
12
- ...theirProps
13
- } = $props();
14
- let ourProps = {
15
- "aria-hidden": (features & HiddenFeatures.Focusable) === HiddenFeatures.Focusable ? true : theirProps["aria-hidden"] ?? void 0,
16
- hidden: (features & HiddenFeatures.Hidden) === HiddenFeatures.Hidden ? true : void 0,
17
- style: [
18
- "position: fixed",
19
- "top: 1px",
20
- "left: 1px",
21
- "width: 1px",
22
- "height: 0",
23
- "padding: 0",
24
- "margin: -1px",
25
- "overflow: hidden",
26
- "clip: rect(0, 0, 0, 0)",
27
- "whiteSpace: nowrap",
28
- "borderWidth: 0",
29
- ...(features & HiddenFeatures.Hidden) === HiddenFeatures.Hidden && !((features & HiddenFeatures.Focusable) === HiddenFeatures.Focusable) ? ["display: none"] : []
30
- ].join("; ")
31
- };
20
+ <script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_VISUALLY_HIDDEN_TAG">
21
+ let {
22
+ ref = $bindable(),
23
+ value,
24
+ checked,
25
+ features = HiddenFeatures.None,
26
+ ...theirProps
27
+ }: { as?: TTag } & HiddenProps<TTag> = $props()
28
+
29
+ let ourProps = {
30
+ "aria-hidden":
31
+ (features & HiddenFeatures.Focusable) === HiddenFeatures.Focusable
32
+ ? true
33
+ : (theirProps["aria-hidden" as keyof typeof theirProps] ?? undefined),
34
+ hidden: (features & HiddenFeatures.Hidden) === HiddenFeatures.Hidden ? true : undefined,
35
+ style: [
36
+ "position: fixed",
37
+ "top: 1px",
38
+ "left: 1px",
39
+ "width: 1px",
40
+ "height: 0",
41
+ "padding: 0",
42
+ "margin: -1px",
43
+ "overflow: hidden",
44
+ "clip: rect(0, 0, 0, 0)",
45
+ "whiteSpace: nowrap",
46
+ "borderWidth: 0",
47
+ ...((features & HiddenFeatures.Hidden) === HiddenFeatures.Hidden &&
48
+ !((features & HiddenFeatures.Focusable) === HiddenFeatures.Focusable)
49
+ ? ["display: none"]
50
+ : []),
51
+ ].join("; "),
52
+ }
32
53
  </script>
33
54
 
34
55
  <ElementOrComponent
@@ -12,8 +12,7 @@ declare class __sveltets_Render<TTag extends ElementType = typeof DEFAULT_VISUAL
12
12
  as?: TTag | undefined;
13
13
  } & (Exclude<keyof import("../utils/types.js").PropsOf<TTag>, ("slot" | "as" | "children" | "class" | "ref") | "features"> extends infer T extends keyof import("../utils/types.js").PropsOf<TTag> ? { [P in T]: import("../utils/types.js").PropsOf<TTag>[P]; } : never) & {
14
14
  children?: import("svelte").Snippet<[{
15
- slot: HiddenRenderPropArg;
16
- props: Record<string, any>;
15
+ props?: Record<string, any>;
17
16
  }]> | undefined;
18
17
  class?: string | ((bag: HiddenRenderPropArg) => string) | null | undefined;
19
18
  ref?: HTMLElement;
@@ -1,42 +1,95 @@
1
- <script lang="ts" module>import { getContext, onMount } from "svelte";
2
- export function useMainTreeNode(options = {}) {
3
- const { fallbackMainTreeNode = null } = $derived(options);
4
- return getContext("MainTreeContext") ?? {
5
- get node() {
6
- return fallbackMainTreeNode;
7
- }
8
- };
9
- }
10
- </script>
1
+ <script lang="ts" module>
2
+ import { getContext, onMount } from "svelte"
11
3
 
12
- <script lang="ts">import { setContext } from "svelte";
13
- import Hidden, { HiddenFeatures } from "./Hidden.svelte";
14
- import { getOwnerDocument } from "../utils/owner.js";
15
- let { node, children } = $props();
16
- let mainTreeNode = $state(null);
17
- const resolvedMainTreeNode = useMainTreeNode({
18
- get fallbackMainTreeNode() {
19
- return node ?? mainTreeNode;
20
- }
21
- });
22
- setContext("MainTreeContext", {
23
- get node() {
24
- return resolvedMainTreeNode.node;
4
+ type MainTreeContext = { node: HTMLElement | null }
5
+
6
+ /**
7
+ * Get the main tree node from context or fallback to the optionally provided node.
8
+ */
9
+ export function useMainTreeNode(options: { fallbackMainTreeNode?: HTMLElement | null } = {}) {
10
+ const { fallbackMainTreeNode = null } = $derived(options)
11
+
12
+ // Prefer the main tree node from context, but fallback to the provided node.
13
+ return (
14
+ getContext<MainTreeContext>("MainTreeContext") ?? {
15
+ get node() {
16
+ return fallbackMainTreeNode
17
+ },
18
+ }
19
+ )
25
20
  }
26
- });
27
- let el = $state();
28
- onMount(() => {
29
- if (!el) return;
30
- for (let container of getOwnerDocument(el)?.querySelectorAll("html > *, body > *") ?? []) {
31
- if (container === document.body) continue;
32
- if (container === document.head) continue;
33
- if (!(container instanceof HTMLElement)) continue;
34
- if (container?.contains(el)) {
35
- mainTreeNode = container;
36
- break;
21
+ </script>
22
+
23
+ <script lang="ts">
24
+ import { setContext, type Snippet } from "svelte"
25
+ import Hidden, { HiddenFeatures } from "./Hidden.svelte"
26
+ import { getOwnerDocument } from "../utils/owner.js"
27
+ /**
28
+ * A provider for the main tree node.
29
+ *
30
+ * When a component is rendered in a `Portal`, it is no longer part of the main
31
+ * tree. This provider helps to find the main tree node and pass it along to the
32
+ * components that need it.
33
+ *
34
+ * The main tree node is used for features such as outside click behavior, where
35
+ * we allow clicks in 3rd party containers, but not in the parent of the "main
36
+ * tree".
37
+ *
38
+ * In case of a `Popover`, we can use the `PopoverButton` as a marker in the
39
+ * "main tree", the `PopoverPanel` can't be used because it could be rendered in
40
+ * a `Portal` (e.g. when using the `anchor` props).
41
+ *
42
+ * However, we can't use the `PopoverButton` when it's nested inside of another
43
+ * `Popover`'s `PopoverPanel` component if the parent `PopoverPanel` is
44
+ * rendered in a `Portal`.
45
+ *
46
+ * This is where the `MainTreeProvider` comes in. It will find the "main tree"
47
+ * node and pass it on. The top-level `PopoverButton` will be used as a marker
48
+ * in the "main tree" and nested `Popover` will use this button as well.
49
+ */
50
+ let { node, children }: { children: Snippet; node?: HTMLElement | null } = $props()
51
+
52
+ let mainTreeNode = $state<HTMLElement | null>(null)
53
+
54
+ // 1. Prefer the main tree node from context
55
+ // 2. Prefer the provided node
56
+ // 3. Create a new node at this point, and find the main tree node
57
+ const resolvedMainTreeNode = useMainTreeNode({
58
+ get fallbackMainTreeNode() {
59
+ return node ?? mainTreeNode
60
+ },
61
+ })
62
+
63
+ setContext("MainTreeContext", {
64
+ get node() {
65
+ return resolvedMainTreeNode.node
66
+ },
67
+ })
68
+
69
+ /**
70
+ * If no main tree node is found at this point, then we briefly render an
71
+ * element to find the main tree node and pass it along.
72
+ */
73
+ let el = $state<HTMLElement>()
74
+ onMount(() => {
75
+ if (!el) return
76
+
77
+ // We will only render this when no `mainTreeNode` is found. This
78
+ // means that if we render this element and use it as the
79
+ // `mainTreeNode` that we will be unmounting it later.
80
+ //
81
+ // However, we can resolve the actual root container of the main
82
+ // tree node and use that instead.
83
+ for (let container of getOwnerDocument(el)?.querySelectorAll("html > *, body > *") ?? []) {
84
+ if (container === document.body) continue // Skip `<body>`
85
+ if (container === document.head) continue // Skip `<head>`
86
+ if (!(container instanceof HTMLElement)) continue // Skip non-HTMLElements
87
+ if (container?.contains(el)) {
88
+ mainTreeNode = container
89
+ break
90
+ }
37
91
  }
38
- }
39
- });
92
+ })
40
93
  </script>
41
94
 
42
95
  {#if children}{@render children()}{/if}
@@ -1,17 +1,21 @@
1
- <script lang="ts">import { onDestroy, onMount } from "svelte";
2
- let { target, children } = $props();
3
- let ref = $state();
4
- onMount(() => {
5
- target.appendChild(ref);
6
- });
7
- onDestroy(() => {
8
- const _ref = ref;
9
- setTimeout(() => {
10
- if (_ref?.parentNode) {
11
- _ref.parentNode?.removeChild(_ref);
12
- }
13
- });
14
- });
1
+ <script lang="ts">
2
+ import { onDestroy, onMount, type Snippet } from "svelte"
3
+
4
+ let { target, children }: { target: HTMLElement; children: Snippet } = $props()
5
+ let ref = $state<HTMLDivElement>()
6
+
7
+ onMount(() => {
8
+ target.appendChild(ref!)
9
+ })
10
+
11
+ onDestroy(() => {
12
+ const _ref = ref
13
+ setTimeout(() => {
14
+ if (_ref?.parentNode) {
15
+ _ref.parentNode?.removeChild(_ref)
16
+ }
17
+ })
18
+ })
15
19
  </script>
16
20
 
17
21
  <div bind:this={ref}>{@render children()}</div>