@pzerelles/headlessui-svelte 2.1.2-next.22 → 2.1.2-next.24

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 (132) hide show
  1. package/dist/button/Button.svelte +84 -54
  2. package/dist/button/Button.svelte.d.ts +7 -4
  3. package/dist/checkbox/Checkbox.svelte +173 -120
  4. package/dist/checkbox/Checkbox.svelte.d.ts +7 -4
  5. package/dist/close-button/CloseButton.svelte +12 -6
  6. package/dist/close-button/CloseButton.svelte.d.ts +13 -10
  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 +7 -5
  10. package/dist/description/Description.svelte +39 -24
  11. package/dist/description/Description.svelte.d.ts +8 -5
  12. package/dist/description/context.svelte.js +13 -15
  13. package/dist/dialog/Dialog.svelte +358 -38
  14. package/dist/dialog/Dialog.svelte.d.ts +10 -7
  15. package/dist/dialog/DialogBackdrop.svelte +30 -13
  16. package/dist/dialog/DialogBackdrop.svelte.d.ts +7 -4
  17. package/dist/dialog/DialogPanel.svelte +49 -26
  18. package/dist/dialog/DialogPanel.svelte.d.ts +7 -4
  19. package/dist/dialog/DialogTitle.svelte +38 -23
  20. package/dist/dialog/DialogTitle.svelte.d.ts +7 -4
  21. package/dist/field/Field.svelte +50 -34
  22. package/dist/field/Field.svelte.d.ts +7 -4
  23. package/dist/fieldset/Fieldset.svelte +50 -29
  24. package/dist/fieldset/Fieldset.svelte.d.ts +7 -4
  25. package/dist/focus-trap/FocusTrap.svelte +419 -283
  26. package/dist/focus-trap/FocusTrap.svelte.d.ts +7 -4
  27. package/dist/hooks/use-disabled.d.ts +4 -1
  28. package/dist/hooks/use-disabled.js +10 -5
  29. package/dist/input/Input.svelte +84 -53
  30. package/dist/input/Input.svelte.d.ts +7 -4
  31. package/dist/internal/FloatingProvider.svelte +14 -9
  32. package/dist/internal/FocusSentinel.svelte +16 -8
  33. package/dist/internal/ForcePortalRoot.svelte +7 -3
  34. package/dist/internal/FormFields.svelte +47 -34
  35. package/dist/internal/FormFieldsProvider.svelte +9 -5
  36. package/dist/internal/FormResolver.svelte +20 -15
  37. package/dist/internal/Hidden.svelte +50 -29
  38. package/dist/internal/Hidden.svelte.d.ts +7 -4
  39. package/dist/internal/MainTreeProvider.svelte +89 -36
  40. package/dist/internal/Portal.svelte +18 -14
  41. package/dist/internal/floating-provider.svelte.js +1 -1
  42. package/dist/internal/floating.svelte.d.ts +5 -5
  43. package/dist/internal/floating.svelte.js +17 -17
  44. package/dist/label/Label.svelte +93 -58
  45. package/dist/label/Label.svelte.d.ts +7 -4
  46. package/dist/legend/Legend.svelte +12 -3
  47. package/dist/listbox/Listbox.svelte +525 -387
  48. package/dist/listbox/Listbox.svelte.d.ts +7 -5
  49. package/dist/listbox/ListboxButton.svelte +173 -127
  50. package/dist/listbox/ListboxButton.svelte.d.ts +7 -5
  51. package/dist/listbox/ListboxOption.svelte +170 -129
  52. package/dist/listbox/ListboxOption.svelte.d.ts +7 -5
  53. package/dist/listbox/ListboxOptions.svelte +400 -304
  54. package/dist/listbox/ListboxOptions.svelte.d.ts +7 -5
  55. package/dist/listbox/ListboxSelectedOption.svelte +38 -15
  56. package/dist/listbox/ListboxSelectedOption.svelte.d.ts +7 -4
  57. package/dist/listbox/index.d.ts +4 -4
  58. package/dist/listbox/index.js +1 -1
  59. package/dist/menu/Menu.svelte +78 -57
  60. package/dist/menu/Menu.svelte.d.ts +7 -5
  61. package/dist/menu/MenuButton.svelte +157 -117
  62. package/dist/menu/MenuButton.svelte.d.ts +7 -5
  63. package/dist/menu/MenuHeading.svelte +32 -14
  64. package/dist/menu/MenuHeading.svelte.d.ts +7 -5
  65. package/dist/menu/MenuItem.svelte +142 -107
  66. package/dist/menu/MenuItem.svelte.d.ts +8 -8
  67. package/dist/menu/MenuItems.svelte +301 -229
  68. package/dist/menu/MenuItems.svelte.d.ts +7 -5
  69. package/dist/menu/MenuSection.svelte +24 -9
  70. package/dist/menu/MenuSection.svelte.d.ts +7 -5
  71. package/dist/menu/MenuSeparator.svelte +17 -4
  72. package/dist/menu/MenuSeparator.svelte.d.ts +7 -6
  73. package/dist/menu/context.svelte.d.ts +1 -29
  74. package/dist/menu/context.svelte.js +29 -27
  75. package/dist/menu/index.d.ts +7 -7
  76. package/dist/popover/Popover.svelte +216 -150
  77. package/dist/popover/Popover.svelte.d.ts +7 -4
  78. package/dist/popover/PopoverBackdrop.svelte +67 -41
  79. package/dist/popover/PopoverBackdrop.svelte.d.ts +7 -4
  80. package/dist/popover/PopoverButton.svelte +292 -212
  81. package/dist/popover/PopoverButton.svelte.d.ts +7 -4
  82. package/dist/popover/PopoverGroup.svelte +62 -35
  83. package/dist/popover/PopoverGroup.svelte.d.ts +7 -4
  84. package/dist/popover/PopoverPanel.svelte +311 -229
  85. package/dist/popover/PopoverPanel.svelte.d.ts +7 -4
  86. package/dist/portal/InternalPortal.svelte +141 -85
  87. package/dist/portal/InternalPortal.svelte.d.ts +7 -4
  88. package/dist/portal/Portal.svelte +5 -2
  89. package/dist/portal/PortalGroup.svelte +30 -9
  90. package/dist/portal/PortalGroup.svelte.d.ts +7 -4
  91. package/dist/select/Select.svelte +98 -68
  92. package/dist/select/Select.svelte.d.ts +7 -4
  93. package/dist/switch/Switch.svelte +179 -132
  94. package/dist/switch/Switch.svelte.d.ts +7 -4
  95. package/dist/switch/SwitchGroup.svelte +44 -31
  96. package/dist/switch/SwitchGroup.svelte.d.ts +7 -4
  97. package/dist/tabs/Tab.svelte +194 -143
  98. package/dist/tabs/Tab.svelte.d.ts +7 -4
  99. package/dist/tabs/TabGroup.svelte +81 -214
  100. package/dist/tabs/TabGroup.svelte.d.ts +7 -24
  101. package/dist/tabs/TabList.svelte +31 -11
  102. package/dist/tabs/TabList.svelte.d.ts +7 -4
  103. package/dist/tabs/TabPanel.svelte +67 -43
  104. package/dist/tabs/TabPanel.svelte.d.ts +7 -4
  105. package/dist/tabs/TabPanels.svelte +18 -7
  106. package/dist/tabs/TabPanels.svelte.d.ts +7 -4
  107. package/dist/tabs/context.svelte.d.ts +31 -0
  108. package/dist/tabs/context.svelte.js +134 -0
  109. package/dist/textarea/Textarea.svelte +84 -53
  110. package/dist/textarea/Textarea.svelte.d.ts +7 -4
  111. package/dist/transition/InternalTransitionChild.svelte +259 -170
  112. package/dist/transition/InternalTransitionChild.svelte.d.ts +7 -4
  113. package/dist/transition/Transition.svelte +96 -66
  114. package/dist/transition/Transition.svelte.d.ts +7 -4
  115. package/dist/transition/TransitionChild.svelte +31 -11
  116. package/dist/transition/TransitionChild.svelte.d.ts +7 -4
  117. package/dist/utils/ElementOrComponent.svelte +43 -23
  118. package/dist/utils/ElementOrComponent.svelte.d.ts +10 -4
  119. package/dist/utils/Generic.svelte +36 -22
  120. package/dist/utils/Generic.svelte.d.ts +7 -4
  121. package/dist/utils/StableCollection.svelte +54 -36
  122. package/dist/utils/floating-ui/svelte/components/FloatingNode.svelte +27 -12
  123. package/dist/utils/floating-ui/svelte/components/FloatingTree.svelte +88 -44
  124. package/dist/utils/floating-ui/svelte/hooks/useFloating.svelte.js +7 -7
  125. package/dist/utils/floating-ui/svelte/hooks/useFloatingRootContext.svelte.js +1 -1
  126. package/dist/utils/floating-ui/svelte/types.d.ts +4 -4
  127. package/dist/utils/floating-ui/svelte-dom/types.d.ts +2 -2
  128. package/dist/utils/floating-ui/svelte-dom/useFloating.svelte.js +6 -6
  129. package/dist/utils/types.d.ts +11 -4
  130. package/package.json +2 -2
  131. package/dist/dialog/InternalDialog.svelte +0 -233
  132. package/dist/dialog/InternalDialog.svelte.d.ts +0 -42
@@ -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>
@@ -10,7 +10,7 @@ export const useFloatingProvider = (options = { enabled: true }) => {
10
10
  const setInnerOffset = (offset) => (innerOffset = typeof offset === "function" ? offset(innerOffset) : offset);
11
11
  const overflowRef = $state({ current: null });
12
12
  let floatingEl = $state(null);
13
- const setFloatingElement = (element) => (floatingEl = element);
13
+ const setFloatingElement = (element) => (floatingEl = element ?? null);
14
14
  useFixScrollingPixel({
15
15
  get element() {
16
16
  return floatingEl;
@@ -37,9 +37,9 @@ export type InternalFloatingPanelProps = Partial<{
37
37
  };
38
38
  }>;
39
39
  export type FloatingContext = {
40
- styles?: UseFloatingReturn<any>["floatingStyles"];
41
- setReference: UseFloatingReturn<any>["refs"]["setReference"];
42
- setFloating: UseFloatingReturn<any>["refs"]["setFloating"];
40
+ styles?: UseFloatingReturn["floatingStyles"];
41
+ setReference: UseFloatingReturn["refs"]["setReference"];
42
+ setFloating: UseFloatingReturn["refs"]["setFloating"];
43
43
  getReferenceProps: ReturnType<typeof useInteractions>["getReferenceProps"];
44
44
  getFloatingProps: ReturnType<typeof useInteractions>["getFloatingProps"];
45
45
  slot: Partial<{
@@ -55,7 +55,7 @@ export declare function useResolvedAnchor<T extends AnchorProps | AnchorPropsWit
55
55
  anchor: Exclude<T, boolean | string> | null;
56
56
  };
57
57
  export declare function useFloatingReference(): {
58
- readonly setReference: ((node: import("../utils/floating-ui/svelte-dom/types.js").ReferenceType | null) => void) & ((node: any) => void);
58
+ readonly setReference: ((node: import("../utils/floating-ui/svelte-dom/types.js").ReferenceType | null | undefined) => void) & ((node: import("../utils/floating-ui/svelte/types.js").ReferenceType | null | undefined) => void);
59
59
  };
60
60
  export declare function useFloatingReferenceProps(): {
61
61
  readonly getReferenceProps: (userProps?: import("svelte/elements.js").HTMLAttributes<Element>) => Record<string, unknown>;
@@ -66,7 +66,7 @@ export declare function useFloatingPanelProps(): (userProps?: import("svelte/ele
66
66
  export declare function useFloatingPanel(options?: {
67
67
  placement: (AnchorPropsWithSelection & InternalFloatingPanelProps) | null;
68
68
  }): {
69
- readonly setFloating: ((node: HTMLElement | null) => void) & ((node: HTMLElement | null) => void);
69
+ readonly setFloating: ((node: HTMLElement | null | undefined) => void) & ((node: HTMLElement | null | undefined) => void);
70
70
  readonly styles: string | undefined;
71
71
  };
72
72
  export declare function useFixScrollingPixel(options: {
@@ -76,17 +76,17 @@ export function useFloatingPanel(options = { placement: null }) {
76
76
  };
77
77
  }
78
78
  export function useFixScrollingPixel(options) {
79
- const { element } = $derived(options);
80
79
  $effect(() => {
80
+ const element = options.element;
81
81
  if (!element)
82
82
  return;
83
83
  untrack(() => {
84
- let observer = new MutationObserver(() => {
85
- let maxHeight = window.getComputedStyle(element).maxHeight;
86
- let maxHeightFloat = parseFloat(maxHeight);
84
+ const observer = new MutationObserver(() => {
85
+ const maxHeight = window.getComputedStyle(element).maxHeight;
86
+ const maxHeightFloat = parseFloat(maxHeight);
87
87
  if (isNaN(maxHeightFloat))
88
88
  return;
89
- let maxHeightInt = parseInt(maxHeight);
89
+ const maxHeightInt = parseInt(maxHeight);
90
90
  if (isNaN(maxHeightInt))
91
91
  return;
92
92
  if (maxHeightFloat !== maxHeightInt) {
@@ -149,7 +149,7 @@ export function useResolvedConfig(options) {
149
149
  }
150
150
  function useResolvePxValue(options) {
151
151
  const { input, element, defaultValue } = $derived(options);
152
- let d = useDisposables();
152
+ const d = useDisposables();
153
153
  const computeValue = (value, element) => {
154
154
  // Nullish
155
155
  if (value == null)
@@ -165,7 +165,7 @@ function useResolvePxValue(options) {
165
165
  return [
166
166
  result,
167
167
  (setValue) => {
168
- let variables = resolveVariables(value);
168
+ const variables = resolveVariables(value);
169
169
  // TODO: Improve this part and make it work
170
170
  //
171
171
  // Observe variables themselves. Currently the browser doesn't support this, but the
@@ -197,7 +197,7 @@ function useResolvePxValue(options) {
197
197
  // }
198
198
  // Works as a fallback, but not very performant because we are polling the value.
199
199
  {
200
- let history = variables.map((variable) => window.getComputedStyle(element).getPropertyValue(variable));
200
+ const history = variables.map((variable) => window.getComputedStyle(element).getPropertyValue(variable));
201
201
  d.requestAnimationFrame(function check() {
202
202
  d.nextFrame(check);
203
203
  // Fast path, detect if the value of the CSS Variable has changed before completely
@@ -206,8 +206,8 @@ function useResolvePxValue(options) {
206
206
  //
207
207
  // This is a lot of work, so we want to avoid it if possible.
208
208
  let changed = false;
209
- for (let [idx, variable] of variables.entries()) {
210
- let value = window.getComputedStyle(element).getPropertyValue(variable);
209
+ for (const [idx, variable] of variables.entries()) {
210
+ const value = window.getComputedStyle(element).getPropertyValue(variable);
211
211
  if (history[idx] !== value) {
212
212
  history[idx] = value;
213
213
  changed = true;
@@ -217,7 +217,7 @@ function useResolvePxValue(options) {
217
217
  // Nothing changed, no need to perform the expensive computation.
218
218
  if (!changed)
219
219
  return;
220
- let newResult = resolveCSSVariablePxValue(value, element);
220
+ const newResult = resolveCSSVariablePxValue(value, element);
221
221
  if (result !== newResult) {
222
222
  setValue(newResult);
223
223
  result = newResult;
@@ -250,14 +250,14 @@ function useResolvePxValue(options) {
250
250
  };
251
251
  }
252
252
  function resolveVariables(value) {
253
- let matches = /var\((.*)\)/.exec(value);
253
+ const matches = /var\((.*)\)/.exec(value);
254
254
  if (matches) {
255
- let idx = matches[1].indexOf(",");
255
+ const idx = matches[1].indexOf(",");
256
256
  if (idx === -1) {
257
257
  return [matches[1]];
258
258
  }
259
- let variable = matches[1].slice(0, idx).trim();
260
- let fallback = matches[1].slice(idx + 1).trim();
259
+ const variable = matches[1].slice(0, idx).trim();
260
+ const fallback = matches[1].slice(idx + 1).trim();
261
261
  if (fallback) {
262
262
  return [variable, ...resolveVariables(fallback)];
263
263
  }
@@ -291,7 +291,7 @@ function resolveCSSVariablePxValue(input, element) {
291
291
  // ```
292
292
  //
293
293
  // Then this will result to resolved value of `2rem`, instead of `1rem`
294
- let tmpEl = document.createElement("div");
294
+ const tmpEl = document.createElement("div");
295
295
  element.appendChild(tmpEl);
296
296
  // Set the value to `0px` otherwise if an invalid value is provided later the browser will read
297
297
  // out the default value.
@@ -301,7 +301,7 @@ function resolveCSSVariablePxValue(input, element) {
301
301
  // Set the new value, if this is invalid the previous value will be used.
302
302
  tmpEl.style.setProperty("margin-top", input, "important");
303
303
  // Reading the `margin-top` will already be in pixels (e.g.: 123px).
304
- let pxValue = parseFloat(window.getComputedStyle(tmpEl).marginTop) || 0;
304
+ const pxValue = parseFloat(window.getComputedStyle(tmpEl).marginTop) || 0;
305
305
  element.removeChild(tmpEl);
306
306
  return pxValue;
307
307
  }
@@ -1,66 +1,101 @@
1
- <script lang="ts" module>let DEFAULT_LABEL_TAG = "label";
2
- </script>
1
+ <script lang="ts" module>
2
+ import type { ElementType, Props, PropsOf } from "../utils/types.js"
3
+
4
+ let DEFAULT_LABEL_TAG = "label" as const
3
5
 
4
- <script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_LABEL_TAG">import { onMount } from "svelte";
5
- import { useProvidedId, htmlid } from "../utils/id.js";
6
- import { useDisabled } from "../hooks/use-disabled.js";
7
- import { stateFromSlot } from "../utils/state.js";
8
- import ElementOrComponent from "../utils/ElementOrComponent.svelte";
9
- import { useLabelContext } from "./context.svelte.js";
10
- const internalId = htmlid();
11
- const context = useLabelContext();
12
- const providedHtmlFor = useProvidedId();
13
- const providedDisabled = useDisabled();
14
- let {
15
- ref = $bindable(),
16
- id = `headlessui-label-${internalId}`,
17
- htmlFor = providedHtmlFor,
18
- passive = false,
19
- ...theirOriginalProps
20
- } = $props();
21
- onMount(() => {
22
- context.register(id);
23
- });
24
- let handleClick = (e) => {
25
- let current = e.currentTarget;
26
- if (current instanceof HTMLLabelElement) {
27
- e.preventDefault();
6
+ export type LabelProps<TTag extends ElementType = typeof DEFAULT_LABEL_TAG> = Props<TTag> & {
7
+ passive?: boolean
8
+ htmlFor?: string
28
9
  }
29
- console.log("click", providedHtmlFor);
30
- if (current instanceof HTMLLabelElement) {
31
- let target = document.getElementById(current.getAttribute("for") ?? "");
32
- if (target) {
33
- let actuallyDisabled = target.getAttribute("disabled");
34
- if (actuallyDisabled === "true" || actuallyDisabled === "") {
35
- return;
36
- }
37
- let ariaDisabled = target.getAttribute("aria-disabled");
38
- if (ariaDisabled === "true" || ariaDisabled === "") {
39
- return;
40
- }
41
- if (target instanceof HTMLInputElement && (target.type === "radio" || target.type === "checkbox") || target.role === "radio" || target.role === "checkbox" || target.role === "switch") {
42
- target.click();
10
+ </script>
11
+
12
+ <script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_LABEL_TAG">
13
+ import { onMount } from "svelte"
14
+ import { useProvidedId, htmlid } from "../utils/id.js"
15
+ import { useDisabled } from "../hooks/use-disabled.js"
16
+ import { stateFromSlot } from "../utils/state.js"
17
+ import ElementOrComponent from "../utils/ElementOrComponent.svelte"
18
+ import { useLabelContext } from "./context.svelte.js"
19
+
20
+ const internalId = htmlid()
21
+ const context = useLabelContext()
22
+ const providedHtmlFor = useProvidedId()
23
+ const providedDisabled = useDisabled()
24
+
25
+ let {
26
+ ref = $bindable(),
27
+ id = `headlessui-label-${internalId}` as PropsOf<TTag>["id"],
28
+ htmlFor = providedHtmlFor,
29
+ passive = false,
30
+ ...theirOriginalProps
31
+ }: { as?: TTag } & LabelProps<TTag> = $props()
32
+
33
+ onMount(() => {
34
+ context.register(id)
35
+ })
36
+
37
+ let handleClick = (e: MouseEvent) => {
38
+ let current = e.currentTarget
39
+
40
+ // Labels connected to 'real' controls will already click the element. But we don't know that
41
+ // ahead of time. This will prevent the default click, such that only a single click happens
42
+ // instead of two. Otherwise this results in a visual no-op.
43
+ if (current instanceof HTMLLabelElement) {
44
+ e.preventDefault()
45
+ }
46
+
47
+ console.log("click", providedHtmlFor)
48
+
49
+ if (current instanceof HTMLLabelElement) {
50
+ let target = document.getElementById(current.getAttribute("for") ?? "")
51
+ if (target) {
52
+ // Bail if the target element is disabled
53
+ let actuallyDisabled = target.getAttribute("disabled")
54
+ if (actuallyDisabled === "true" || actuallyDisabled === "") {
55
+ return
56
+ }
57
+
58
+ let ariaDisabled = target.getAttribute("aria-disabled")
59
+ if (ariaDisabled === "true" || ariaDisabled === "") {
60
+ return
61
+ }
62
+
63
+ // Ensure we click the element this label is bound to. This is necessary for elements that
64
+ // immediately require state changes, e.g.: Radio & Checkbox inputs need to be checked (or
65
+ // unchecked).
66
+ if (
67
+ (target instanceof HTMLInputElement && (target.type === "radio" || target.type === "checkbox")) ||
68
+ target.role === "radio" ||
69
+ target.role === "checkbox" ||
70
+ target.role === "switch"
71
+ ) {
72
+ target.click()
73
+ }
74
+
75
+ // Move focus to the element, this allows you to start using keyboard shortcuts since the
76
+ // bound element is now focused.
77
+ target.focus({ preventScroll: true })
43
78
  }
44
- target.focus({ preventScroll: true });
45
79
  }
46
80
  }
47
- };
48
- const disabled = $derived(providedDisabled.value ?? false);
49
- const slot = $derived({ disabled });
50
- const ourProps = $derived({
51
- id,
52
- for: passive ? void 0 : htmlFor,
53
- onclick: passive ? void 0 : handleClick,
54
- ...stateFromSlot(slot)
55
- });
56
- const theirProps = $derived.by(() => {
57
- if (passive) {
58
- const { onclick: _, ...props } = theirOriginalProps;
59
- return props;
60
- } else {
61
- return theirOriginalProps;
62
- }
63
- });
81
+
82
+ const disabled = $derived(providedDisabled.current ?? false)
83
+ const slot = $derived({ disabled })
84
+ const ourProps = $derived({
85
+ id,
86
+ for: passive ? undefined : htmlFor,
87
+ onclick: passive ? undefined : handleClick,
88
+ ...stateFromSlot(slot),
89
+ })
90
+
91
+ const theirProps = $derived.by(() => {
92
+ if (passive) {
93
+ const { onclick: _, ...props } = theirOriginalProps
94
+ return props
95
+ } else {
96
+ return theirOriginalProps
97
+ }
98
+ })
64
99
  </script>
65
100
 
66
101
  <ElementOrComponent
@@ -7,11 +7,14 @@ export type LabelProps<TTag extends ElementType = typeof DEFAULT_LABEL_TAG> = Pr
7
7
  declare class __sveltets_Render<TTag extends ElementType = typeof DEFAULT_LABEL_TAG> {
8
8
  props(): {
9
9
  as?: TTag | undefined;
10
- } & (Exclude<keyof PropsOf<TTag>, "as" | "children" | "refName" | "class"> extends infer T extends keyof PropsOf<TTag> ? { [P in T]: PropsOf<TTag>[P]; } : never) & {
11
- children?: import("svelte").Snippet<[{}, Record<string, any>]> | undefined;
10
+ } & (Exclude<keyof PropsOf<TTag>, "as" | "children" | "class"> extends infer T extends keyof PropsOf<TTag> ? { [P in T]: PropsOf<TTag>[P]; } : never) & {
11
+ children?: import("svelte").Snippet<[{
12
+ slot: {};
13
+ props: Record<string, any>;
14
+ }]> | undefined;
12
15
  ref?: HTMLElement;
13
- } & (true extends (PropsOf<TTag> extends infer T_1 ? T_1 extends PropsOf<TTag> ? T_1 extends never ? never : "class" extends infer T_2 ? T_2 extends "class" ? T_2 extends keyof T_1 ? true : never : never : never : never : never) ? {
14
- class?: PropsOf<TTag>["class"] | ((bag: {}) => string) | undefined;
16
+ } & (true extends (import("svelte/elements.js").SvelteHTMLElements[TTag] extends infer T_1 ? T_1 extends import("svelte/elements.js").SvelteHTMLElements[TTag] ? T_1 extends never ? never : "class" extends infer T_2 ? T_2 extends "class" ? T_2 extends keyof T_1 ? true : never : never : never : never : never) ? {
17
+ class?: string | ((bag: {}) => string) | null | undefined;
15
18
  } : {}) & {
16
19
  passive?: boolean;
17
20
  htmlFor?: string;
@@ -1,8 +1,17 @@
1
- <script lang="ts" module>import { Label } from "../index.js";
2
- const DEFAULT_LEGEND_TAG = "div";
1
+ <script lang="ts" module>
2
+ import { Label } from "../index.js"
3
+ import type { Props } from "../utils/types.js"
4
+
5
+ const DEFAULT_LEGEND_TAG = "div" as const
6
+
7
+ type LegendRenderPropArg = {}
8
+ type LegendPropsWeControl = never
9
+
10
+ export type LegendProps = Props<typeof DEFAULT_LEGEND_TAG, LegendRenderPropArg, LegendPropsWeControl, {}>
3
11
  </script>
4
12
 
5
- <script lang="ts">let { ...props } = $props();
13
+ <script lang="ts">
14
+ let { ...props }: LegendProps = $props()
6
15
  </script>
7
16
 
8
17
  <Label as="div" {...props} />