@pzerelles/headlessui-svelte 2.0.0-next.1 → 2.1.1-next.1

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 (182) hide show
  1. package/dist/button/Button.svelte +65 -0
  2. package/dist/button/Button.svelte.d.ts +39 -0
  3. package/dist/button/index.d.ts +1 -0
  4. package/dist/button/index.js +1 -0
  5. package/dist/checkbox/Checkbox.svelte +60 -46
  6. package/dist/checkbox/Checkbox.svelte.d.ts +1 -1
  7. package/dist/close-button/CloseButton.svelte +10 -0
  8. package/dist/close-button/CloseButton.svelte.d.ts +25 -0
  9. package/dist/close-button/index.d.ts +1 -0
  10. package/dist/close-button/index.js +1 -0
  11. package/dist/combobox/Combobox.svelte +6 -0
  12. package/dist/combobox/Combobox.svelte.d.ts +50 -0
  13. package/dist/description/Description.svelte +50 -32
  14. package/dist/description/Description.svelte.d.ts +14 -5
  15. package/dist/field/Field.svelte +9 -9
  16. package/dist/fieldset/Fieldset.svelte +9 -9
  17. package/dist/hooks/document-overflow/adjust-scrollbar-padding.d.ts +2 -0
  18. package/dist/hooks/document-overflow/adjust-scrollbar-padding.js +18 -0
  19. package/dist/hooks/document-overflow/handle-ios-locking.d.ts +6 -0
  20. package/dist/hooks/document-overflow/handle-ios-locking.js +134 -0
  21. package/dist/hooks/document-overflow/overflow-store.d.ts +19 -0
  22. package/dist/hooks/document-overflow/overflow-store.js +76 -0
  23. package/dist/hooks/document-overflow/prevent-scroll.d.ts +2 -0
  24. package/dist/hooks/document-overflow/prevent-scroll.js +7 -0
  25. package/dist/hooks/document-overflow/use-document-overflow.svelte.d.ts +7 -0
  26. package/dist/hooks/document-overflow/use-document-overflow.svelte.js +27 -0
  27. package/dist/hooks/use-active-press.svelte.d.ts +14 -0
  28. package/dist/{actions/activePress.svelte.js → hooks/use-active-press.svelte.js} +33 -39
  29. package/dist/hooks/use-by-comparator.d.ts +2 -0
  30. package/dist/hooks/use-by-comparator.js +15 -0
  31. package/dist/hooks/use-controllable.svelte.d.ts +6 -0
  32. package/dist/hooks/use-controllable.svelte.js +34 -0
  33. package/dist/hooks/use-did-element-move.svelte.d.ts +6 -0
  34. package/dist/hooks/use-did-element-move.svelte.js +27 -0
  35. package/dist/hooks/use-disabled.d.ts +3 -0
  36. package/dist/hooks/use-disabled.js +9 -0
  37. package/dist/hooks/use-element-size.svelte.d.ts +7 -0
  38. package/dist/hooks/use-element-size.svelte.js +36 -0
  39. package/dist/hooks/use-flags.svelte.d.ts +8 -0
  40. package/dist/hooks/use-flags.svelte.js +18 -0
  41. package/dist/hooks/use-focus-ring.svelte.d.ts +10 -0
  42. package/dist/hooks/use-focus-ring.svelte.js +24 -0
  43. package/dist/hooks/use-hover.svelte.d.ts +26 -0
  44. package/dist/hooks/use-hover.svelte.js +124 -0
  45. package/dist/hooks/use-id.d.ts +1 -0
  46. package/dist/hooks/use-id.js +1 -0
  47. package/dist/hooks/use-inert-others.svelte.d.ts +32 -0
  48. package/dist/hooks/use-inert-others.svelte.js +114 -0
  49. package/dist/hooks/use-is-top-layer.svelte.d.ts +29 -0
  50. package/dist/hooks/use-is-top-layer.svelte.js +82 -0
  51. package/dist/hooks/use-on-disappear.svelte.d.ts +12 -0
  52. package/dist/hooks/use-on-disappear.svelte.js +38 -0
  53. package/dist/hooks/use-outside-click.svelte.d.ts +10 -0
  54. package/dist/hooks/use-outside-click.svelte.js +150 -0
  55. package/dist/hooks/use-reducer.d.ts +4 -0
  56. package/dist/hooks/use-reducer.js +11 -0
  57. package/dist/hooks/use-resolve-button-type.svelte.d.ts +10 -0
  58. package/dist/hooks/use-resolve-button-type.svelte.js +19 -0
  59. package/dist/hooks/use-scroll-lock.svelte.d.ts +5 -0
  60. package/dist/hooks/use-scroll-lock.svelte.js +24 -0
  61. package/dist/hooks/use-sync-refs.d.ts +7 -0
  62. package/dist/hooks/use-sync-refs.js +22 -0
  63. package/dist/hooks/use-text-value.svelte.d.ts +3 -0
  64. package/dist/hooks/use-text-value.svelte.js +20 -0
  65. package/dist/hooks/use-tracked-pointer.d.ts +4 -0
  66. package/dist/hooks/use-tracked-pointer.js +26 -0
  67. package/dist/hooks/use-transition.svelte.d.ts +20 -0
  68. package/dist/hooks/use-transition.svelte.js +252 -0
  69. package/dist/index.d.ts +4 -0
  70. package/dist/index.js +4 -0
  71. package/dist/internal/FocusSentinel.svelte +45 -0
  72. package/dist/internal/FocusSentinel.svelte.d.ts +17 -0
  73. package/dist/internal/FormFields.svelte +2 -4
  74. package/dist/internal/FormFields.svelte.d.ts +5 -6
  75. package/dist/internal/FormResolver.svelte +11 -16
  76. package/dist/internal/FormResolver.svelte.d.ts +2 -3
  77. package/dist/internal/Hidden.svelte +8 -8
  78. package/dist/internal/Hidden.svelte.d.ts +28 -19
  79. package/dist/internal/HoistFormFields.svelte.d.ts +1 -1
  80. package/dist/internal/Portal.svelte.d.ts +1 -1
  81. package/dist/internal/floating.svelte.d.ts +57 -0
  82. package/dist/internal/floating.svelte.js +477 -0
  83. package/dist/internal/frozen.svelte.d.ts +6 -0
  84. package/dist/internal/frozen.svelte.js +18 -0
  85. package/dist/internal/id.d.ts +8 -0
  86. package/dist/internal/id.js +11 -0
  87. package/dist/internal/open-closed.d.ts +14 -0
  88. package/dist/internal/open-closed.js +17 -0
  89. package/dist/internal/portal-force-root.svelte.d.ts +6 -0
  90. package/dist/internal/portal-force-root.svelte.js +11 -0
  91. package/dist/label/Label.svelte +53 -32
  92. package/dist/label/Label.svelte.d.ts +14 -5
  93. package/dist/legend/Legend.svelte.d.ts +1 -2
  94. package/dist/listbox/Listbox.svelte +451 -0
  95. package/dist/listbox/Listbox.svelte.d.ts +107 -0
  96. package/dist/listbox/ListboxButton.svelte +141 -0
  97. package/dist/listbox/ListboxButton.svelte.d.ts +41 -0
  98. package/dist/listbox/ListboxOption.svelte +138 -0
  99. package/dist/listbox/ListboxOption.svelte.d.ts +39 -0
  100. package/dist/listbox/ListboxOptions.svelte +267 -0
  101. package/dist/listbox/ListboxOptions.svelte.d.ts +39 -0
  102. package/dist/listbox/ListboxSelectedOption.svelte +25 -0
  103. package/dist/listbox/ListboxSelectedOption.svelte.d.ts +30 -0
  104. package/dist/listbox/index.d.ts +5 -0
  105. package/dist/listbox/index.js +5 -0
  106. package/dist/portal/InternalPortal.svelte +108 -0
  107. package/dist/portal/InternalPortal.svelte.d.ts +34 -0
  108. package/dist/portal/Portal.svelte +11 -0
  109. package/dist/portal/Portal.svelte.d.ts +23 -0
  110. package/dist/portal/PortalGroup.svelte +15 -0
  111. package/dist/portal/PortalGroup.svelte.d.ts +31 -0
  112. package/dist/switch/Switch.svelte +149 -0
  113. package/dist/switch/Switch.svelte.d.ts +44 -0
  114. package/dist/switch/SwitchGroup.svelte +38 -0
  115. package/dist/switch/SwitchGroup.svelte.d.ts +27 -0
  116. package/dist/switch/index.d.ts +2 -0
  117. package/dist/switch/index.js +2 -0
  118. package/dist/tabs/Button.svelte +65 -0
  119. package/dist/tabs/Button.svelte.d.ts +39 -0
  120. package/dist/tabs/Tab.svelte +161 -0
  121. package/dist/tabs/Tab.svelte.d.ts +36 -0
  122. package/dist/tabs/TabGroup.svelte +244 -0
  123. package/dist/tabs/TabGroup.svelte.d.ts +54 -0
  124. package/dist/tabs/TabList.svelte +18 -0
  125. package/dist/tabs/TabList.svelte.d.ts +28 -0
  126. package/dist/tabs/TabPanel.svelte +63 -0
  127. package/dist/tabs/TabPanel.svelte.d.ts +34 -0
  128. package/dist/tabs/TabPanels.svelte +13 -0
  129. package/dist/tabs/TabPanels.svelte.d.ts +27 -0
  130. package/dist/tabs/index.d.ts +5 -0
  131. package/dist/tabs/index.js +5 -0
  132. package/dist/test-utils/accessability-assertions.d.ts +271 -0
  133. package/dist/test-utils/accessability-assertions.js +1572 -0
  134. package/dist/test-utils/fake-pointer.d.ts +24 -0
  135. package/dist/test-utils/fake-pointer.js +48 -0
  136. package/dist/test-utils/interactions.d.ts +61 -0
  137. package/dist/test-utils/interactions.js +453 -0
  138. package/dist/test-utils/suppress-console-logs.d.ts +7 -0
  139. package/dist/test-utils/suppress-console-logs.js +17 -0
  140. package/dist/utils/StableCollection.svelte +43 -0
  141. package/dist/utils/StableCollection.svelte.d.ts +19 -0
  142. package/dist/utils/calculate-active-index.d.ts +25 -0
  143. package/dist/utils/calculate-active-index.js +74 -0
  144. package/dist/utils/close.d.ts +2 -0
  145. package/dist/utils/close.js +3 -0
  146. package/dist/utils/default-map.d.ts +5 -0
  147. package/dist/utils/default-map.js +15 -0
  148. package/dist/utils/disposables.d.ts +14 -12
  149. package/dist/utils/disposables.js +13 -10
  150. package/dist/utils/dom.d.ts +0 -2
  151. package/dist/utils/dom.js +2 -4
  152. package/dist/utils/env.d.ts +17 -0
  153. package/dist/utils/env.js +39 -0
  154. package/dist/utils/focus-management.d.ts +44 -0
  155. package/dist/utils/focus-management.js +242 -0
  156. package/dist/utils/focusVisible.svelte.d.ts +3 -3
  157. package/dist/utils/focusVisible.svelte.js +52 -41
  158. package/dist/utils/get-text-value.d.ts +1 -0
  159. package/dist/utils/get-text-value.js +71 -0
  160. package/dist/utils/id.d.ts +1 -1
  161. package/dist/utils/match.d.ts +1 -0
  162. package/dist/utils/match.js +13 -0
  163. package/dist/utils/once.d.ts +1 -0
  164. package/dist/utils/once.js +9 -0
  165. package/dist/utils/owner.d.ts +1 -0
  166. package/dist/utils/owner.js +8 -0
  167. package/dist/utils/platform.d.ts +2 -0
  168. package/dist/utils/platform.js +17 -0
  169. package/dist/utils/ref.svelte.d.ts +4 -0
  170. package/dist/utils/ref.svelte.js +4 -0
  171. package/dist/utils/render.d.ts +31 -0
  172. package/dist/utils/render.js +56 -0
  173. package/dist/utils/store.d.ts +11 -0
  174. package/dist/utils/store.js +20 -0
  175. package/dist/utils/types.d.ts +27 -0
  176. package/dist/utils/types.js +6 -0
  177. package/package.json +28 -21
  178. package/dist/actions/activePress.svelte.d.ts +0 -8
  179. package/dist/actions/focusRing.svelte.d.ts +0 -9
  180. package/dist/actions/focusRing.svelte.js +0 -34
  181. package/dist/utils/disabled.d.ts +0 -3
  182. package/dist/utils/disabled.js +0 -2
@@ -0,0 +1,24 @@
1
+ import { useDocumentOverflowLockedEffect } from "./document-overflow/use-document-overflow.svelte.js";
2
+ import { useIsTopLayer } from "./use-is-top-layer.svelte.js";
3
+ export function useScrollLock(options) {
4
+ const { enabled, ownerDocument, resolveAllowedContainers = () => [document.body] } = $derived(options);
5
+ const isTopLayer = useIsTopLayer({
6
+ get enabled() {
7
+ return enabled;
8
+ },
9
+ scope: "scroll-lock",
10
+ });
11
+ useDocumentOverflowLockedEffect({
12
+ get shouldBeLocked() {
13
+ return isTopLayer.value;
14
+ },
15
+ get doc() {
16
+ return ownerDocument;
17
+ },
18
+ get meta() {
19
+ return (meta) => ({
20
+ containers: [...(meta.containers ?? []), resolveAllowedContainers()],
21
+ });
22
+ },
23
+ });
24
+ }
@@ -0,0 +1,7 @@
1
+ import { type MutableRefObject } from "../utils/ref.svelte.js";
2
+ declare const Optional: unique symbol;
3
+ export declare function optionalRef<T>(cb: (ref: T) => void, isOptional?: boolean): ((ref: T) => void) & {
4
+ [Optional]: boolean;
5
+ };
6
+ export declare function useSyncRefs<TType>(...refs: (MutableRefObject<TType | null> | ((instance: TType) => void) | null)[]): ((value: TType) => void) | undefined;
7
+ export {};
@@ -0,0 +1,22 @@
1
+ import { useRef } from "../utils/ref.svelte.js";
2
+ const Optional = Symbol();
3
+ export function optionalRef(cb, isOptional = true) {
4
+ return Object.assign(cb, { [Optional]: isOptional });
5
+ }
6
+ export function useSyncRefs(...refs) {
7
+ let syncRefs = (value) => {
8
+ for (let ref of refs) {
9
+ if (ref == null)
10
+ continue;
11
+ if (typeof ref === "function")
12
+ ref(value);
13
+ else
14
+ ref.current = value;
15
+ }
16
+ };
17
+ return refs.every((ref) => ref == null ||
18
+ // @ts-expect-error
19
+ ref?.[Optional])
20
+ ? undefined
21
+ : syncRefs;
22
+ }
@@ -0,0 +1,3 @@
1
+ export declare function useTextValue(options: {
2
+ element: HTMLElement | null;
3
+ }): () => string;
@@ -0,0 +1,20 @@
1
+ import { getTextValue } from "../utils/get-text-value.js";
2
+ export function useTextValue(options) {
3
+ const { element } = $derived(options);
4
+ let cacheKey = $state("");
5
+ let cacheValue = $state("");
6
+ return () => {
7
+ if (!element)
8
+ return "";
9
+ // Check for a cached version
10
+ let currentKey = element.innerText;
11
+ if (cacheKey === currentKey) {
12
+ return cacheValue;
13
+ }
14
+ // Calculate the value
15
+ let value = getTextValue(element).trim().toLowerCase();
16
+ cacheKey = currentKey;
17
+ cacheValue = value;
18
+ return value;
19
+ };
20
+ }
@@ -0,0 +1,4 @@
1
+ export declare function useTrackedPointer(): {
2
+ wasMoved(evt: PointerEvent): boolean;
3
+ update(evt: PointerEvent): void;
4
+ };
@@ -0,0 +1,26 @@
1
+ import { BROWSER } from "esm-env";
2
+ function eventToPosition(evt) {
3
+ return [evt.screenX, evt.screenY];
4
+ }
5
+ export function useTrackedPointer() {
6
+ let lastPos = [-1, -1];
7
+ return {
8
+ wasMoved(evt) {
9
+ // FIXME: Remove this once we use browser testing in all the relevant places.
10
+ // NOTE: This is replaced with a compile-time define during the build process
11
+ // This hack exists to work around a few failing tests caused by our inability to "move" the virtual pointer in JSDOM pointer events.
12
+ if (!BROWSER && process.env.TEST_BYPASS_TRACKED_POINTER) {
13
+ return true;
14
+ }
15
+ let newPos = eventToPosition(evt);
16
+ if (lastPos[0] === newPos[0] && lastPos[1] === newPos[1]) {
17
+ return false;
18
+ }
19
+ lastPos = newPos;
20
+ return true;
21
+ },
22
+ update(evt) {
23
+ lastPos = eventToPosition(evt);
24
+ },
25
+ };
26
+ }
@@ -0,0 +1,20 @@
1
+ type TransitionData = {
2
+ closed?: boolean;
3
+ enter?: boolean;
4
+ leave?: boolean;
5
+ transition?: boolean;
6
+ };
7
+ export declare function transitionDataAttributes(data: TransitionData): Record<string, string>;
8
+ export declare function useTransition(options: {
9
+ enabled: boolean;
10
+ element: HTMLElement | null | undefined;
11
+ show: boolean;
12
+ events?: {
13
+ start?(show: boolean): void;
14
+ end?(show: boolean): void;
15
+ };
16
+ }): {
17
+ readonly visible: boolean;
18
+ readonly data: TransitionData;
19
+ };
20
+ export {};
@@ -0,0 +1,252 @@
1
+ import { disposables, useDisposables } from "../utils/disposables.js";
2
+ import { once } from "../utils/once.js";
3
+ import { untrack } from "svelte";
4
+ import { useFlags } from "./use-flags.svelte.js";
5
+ /**
6
+ * ```
7
+ * ┌──────┐ │ ┌──────────────┐
8
+ * │Closed│ │ │Closed │
9
+ * └──────┘ │ └──────────────┘
10
+ * ┌──────┐┌──────┐┌──────┐│┌──────┐┌──────┐┌──────┐
11
+ * │Frame ││Frame ││Frame │││Frame ││Frame ││Frame │
12
+ * └──────┘└──────┘└──────┘│└──────┘└──────┘└──────┘
13
+ * ┌──────────────────────┐│┌──────────────────────┐
14
+ * │Enter │││Leave │
15
+ * └──────────────────────┘│└──────────────────────┘
16
+ * ┌──────────────────────┐│┌──────────────────────┐
17
+ * │Transition │││Transition │
18
+ * ├──────────────────────┘│└──────────────────────┘
19
+ * │
20
+ * └─ Applied when `Enter` or `Leave` is applied.
21
+ * ```
22
+ */
23
+ var TransitionState;
24
+ (function (TransitionState) {
25
+ TransitionState[TransitionState["None"] = 0] = "None";
26
+ TransitionState[TransitionState["Closed"] = 1] = "Closed";
27
+ TransitionState[TransitionState["Enter"] = 2] = "Enter";
28
+ TransitionState[TransitionState["Leave"] = 4] = "Leave";
29
+ })(TransitionState || (TransitionState = {}));
30
+ export function transitionDataAttributes(data) {
31
+ let attributes = {};
32
+ for (let key in data) {
33
+ if (data[key] === true) {
34
+ attributes[`data-${key}`] = "";
35
+ }
36
+ }
37
+ return attributes;
38
+ }
39
+ export function useTransition(options) {
40
+ const { enabled, element, show, events } = $derived(options);
41
+ let visible = $state(show);
42
+ let flags = $state(enabled && visible ? TransitionState.Enter | TransitionState.Closed : TransitionState.None);
43
+ let inFlight = $state(false);
44
+ let cancelled = $state(false);
45
+ const d = useDisposables();
46
+ function retry(enabled, show, node, d) {
47
+ if (!enabled)
48
+ return;
49
+ if (show) {
50
+ visible = true;
51
+ }
52
+ if (!node) {
53
+ // Retry if the DOM node isn't available yet
54
+ if (show) {
55
+ flags |= TransitionState.Enter | TransitionState.Closed;
56
+ return d.nextFrame(() => retry(enabled, show, node, d));
57
+ }
58
+ return;
59
+ }
60
+ events?.start?.(show);
61
+ return transition(node, {
62
+ inFlight,
63
+ prepare() {
64
+ if (cancelled) {
65
+ // Cancelled a cancellation, we're back to the original state.
66
+ cancelled = false;
67
+ }
68
+ else {
69
+ // If we were already in-flight, then we want to cancel the current
70
+ // transition.
71
+ cancelled = inFlight;
72
+ }
73
+ inFlight = true;
74
+ if (cancelled)
75
+ return;
76
+ if (show) {
77
+ flags = TransitionState.Enter | TransitionState.Closed;
78
+ }
79
+ else {
80
+ flags = TransitionState.Leave | (flags & TransitionState.Closed);
81
+ }
82
+ },
83
+ run() {
84
+ if (cancelled) {
85
+ // If we cancelled a transition, then the `show` state is going to
86
+ // be inverted already, but that doesn't mean we have to go to that
87
+ // new state.
88
+ //
89
+ // What we actually want is to revert to the "idle" state (the
90
+ // stable state where an `Enter` transitions to, and a `Leave`
91
+ // transitions from.)
92
+ //
93
+ // Because of this, it might look like we are swapping the flags in
94
+ // the following branches, but that's not the case.
95
+ if (!show) {
96
+ flags = TransitionState.Leave | TransitionState.Closed;
97
+ }
98
+ else {
99
+ flags = TransitionState.Enter | TransitionState.Closed;
100
+ }
101
+ }
102
+ else {
103
+ if (show) {
104
+ flags = flags & ~TransitionState.Closed;
105
+ }
106
+ else {
107
+ flags |= TransitionState.Closed;
108
+ }
109
+ }
110
+ },
111
+ done() {
112
+ if (cancelled) {
113
+ if (typeof node.getAnimations === "function" && node.getAnimations().length > 0) {
114
+ return;
115
+ }
116
+ }
117
+ inFlight = false;
118
+ flags = 0;
119
+ if (!show) {
120
+ visible = false;
121
+ }
122
+ events?.end?.(show);
123
+ },
124
+ });
125
+ }
126
+ $effect(() => {
127
+ ;
128
+ [enabled, show, element, d];
129
+ return untrack(() => retry(enabled, show, element, d));
130
+ });
131
+ const data = $derived({
132
+ closed: enabled ? !!(flags & TransitionState.Closed) : undefined,
133
+ enter: enabled ? !!(flags & TransitionState.Enter) : undefined,
134
+ leave: enabled ? !!(flags & TransitionState.Leave) : undefined,
135
+ transition: enabled ? !!(flags & (TransitionState.Enter | TransitionState.Leave)) : undefined,
136
+ });
137
+ return {
138
+ get visible() {
139
+ return enabled ? visible : show;
140
+ },
141
+ get data() {
142
+ return data;
143
+ },
144
+ };
145
+ }
146
+ function transition(node, { prepare, run, done, inFlight, }) {
147
+ const d = disposables();
148
+ // Prepare the transitions by ensuring that all the "before" classes are
149
+ // applied and flushed to the DOM.
150
+ prepareTransition(node, {
151
+ prepare,
152
+ inFlight,
153
+ });
154
+ // This is a workaround for a bug in all major browsers.
155
+ //
156
+ // 1. When an element is just mounted
157
+ // 2. And you apply a transition to it (e.g.: via a class)
158
+ // 3. And you're using `getComputedStyle` and read any returned value
159
+ // 4. Then the `transition` immediately jumps to the end state
160
+ //
161
+ // This means that no transition happens at all. To fix this, we delay the
162
+ // actual transition by one frame.
163
+ d.nextFrame(() => {
164
+ // Wait for the transition, once the transition is complete we can cleanup.
165
+ // This is registered first to prevent race conditions, otherwise it could
166
+ // happen that the transition is already done before we start waiting for
167
+ // the actual event.
168
+ d.add(waitForTransition(node, done));
169
+ // Initiate the transition by applying the new classes.
170
+ run();
171
+ });
172
+ return d.dispose;
173
+ }
174
+ function waitForTransition(node, _done) {
175
+ let done = once(_done);
176
+ let d = disposables();
177
+ if (!node)
178
+ return d.dispose;
179
+ // Safari returns a comma separated list of values, so let's sort them and take the highest value.
180
+ let { transitionDuration, transitionDelay } = getComputedStyle(node);
181
+ let [durationMs, delayMs] = [transitionDuration, transitionDelay].map((value) => {
182
+ let [resolvedValue = 0] = value
183
+ .split(",")
184
+ // Remove falsy we can't work with
185
+ .filter(Boolean)
186
+ // Values are returned as `0.3s` or `75ms`
187
+ .map((v) => (v.includes("ms") ? parseFloat(v) : parseFloat(v) * 1000))
188
+ .sort((a, z) => z - a);
189
+ return resolvedValue;
190
+ });
191
+ let totalDuration = durationMs + delayMs;
192
+ if (totalDuration !== 0) {
193
+ if (process.env.NODE_ENV === "test") {
194
+ let dispose = d.setTimeout(() => {
195
+ done();
196
+ dispose();
197
+ }, totalDuration);
198
+ }
199
+ else {
200
+ let disposeGroup = d.group((d) => {
201
+ // Mark the transition as done when the timeout is reached. This is a fallback in case the
202
+ // transitionrun event is not fired.
203
+ let cancelTimeout = d.setTimeout(() => {
204
+ done();
205
+ d.dispose();
206
+ }, totalDuration);
207
+ // The moment the transitionrun event fires, we should cleanup the timeout fallback, because
208
+ // then we know that we can use the native transition events because something is
209
+ // transitioning.
210
+ d.addEventListener(node, "transitionrun", (event) => {
211
+ if (event.target !== event.currentTarget)
212
+ return;
213
+ cancelTimeout();
214
+ d.addEventListener(node, "transitioncancel", (event) => {
215
+ if (event.target !== event.currentTarget)
216
+ return;
217
+ done();
218
+ disposeGroup();
219
+ });
220
+ });
221
+ });
222
+ d.addEventListener(node, "transitionend", (event) => {
223
+ if (event.target !== event.currentTarget)
224
+ return;
225
+ done();
226
+ d.dispose();
227
+ });
228
+ }
229
+ }
230
+ else {
231
+ // No transition is happening, so we should cleanup already. Otherwise we have to wait until we
232
+ // get disposed.
233
+ done();
234
+ }
235
+ return d.dispose;
236
+ }
237
+ function prepareTransition(node, { inFlight, prepare }) {
238
+ // If we are already transitioning, then we don't need to force cancel the
239
+ // current transition (by triggering a reflow).
240
+ if (inFlight) {
241
+ prepare();
242
+ return;
243
+ }
244
+ let previous = node.style.transition;
245
+ // Force cancel current transition
246
+ node.style.transition = "none";
247
+ prepare();
248
+ // Trigger a reflow, flushing the CSS changes
249
+ node.offsetHeight;
250
+ // Reset the transition to what it was before
251
+ node.style.transition = previous;
252
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,10 @@
1
+ export * from "./button/index.js";
1
2
  export * from "./checkbox/index.js";
2
3
  export * from "./description/index.js";
3
4
  export * from "./field/index.js";
4
5
  export * from "./fieldset/index.js";
5
6
  export * from "./label/index.js";
6
7
  export * from "./legend/index.js";
8
+ export * from "./listbox/index.js";
9
+ export * from "./switch/index.js";
10
+ export * from "./tabs/index.js";
package/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
+ export * from "./button/index.js";
1
2
  export * from "./checkbox/index.js";
2
3
  export * from "./description/index.js";
3
4
  export * from "./field/index.js";
4
5
  export * from "./fieldset/index.js";
5
6
  export * from "./label/index.js";
6
7
  export * from "./legend/index.js";
8
+ export * from "./listbox/index.js";
9
+ export * from "./switch/index.js";
10
+ export * from "./tabs/index.js";
@@ -0,0 +1,45 @@
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
+ });
9
+ </script>
10
+
11
+ {#if enabled}
12
+ <Hidden
13
+ as="button"
14
+ type="button"
15
+ features={HiddenFeatures.Focusable}
16
+ onfocus={(event: FocusEvent) => {
17
+ event.preventDefault()
18
+ let frame: ReturnType<typeof requestAnimationFrame>
19
+
20
+ let tries = 50
21
+ function forwardFocus() {
22
+ // Prevent infinite loops
23
+ if (tries-- <= 0) {
24
+ if (frame) cancelAnimationFrame(frame)
25
+ return
26
+ }
27
+
28
+ // Try to move focus to the correct element. This depends on the implementation
29
+ // of `onFocus` of course since it would be different for each place we use it in.
30
+ if (onfocus?.()) {
31
+ cancelAnimationFrame(frame)
32
+ if (!mounted) return
33
+
34
+ enabled = false
35
+ return
36
+ }
37
+
38
+ // Retry
39
+ frame = requestAnimationFrame(forwardFocus)
40
+ }
41
+
42
+ frame = requestAnimationFrame(forwardFocus)
43
+ }}
44
+ />
45
+ {/if}
@@ -0,0 +1,17 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: Props & {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports;
9
+ z_$$bindings?: Bindings;
10
+ }
11
+ declare const FocusSentinel: $$__sveltets_2_IsomorphicComponent<{
12
+ onfocus: () => boolean;
13
+ }, {
14
+ [evt: string]: CustomEvent<any>;
15
+ }, {}, {}, "">;
16
+ type FocusSentinel = InstanceType<typeof FocusSentinel>;
17
+ export default FocusSentinel;
@@ -14,10 +14,8 @@ let {
14
14
  let form = $state(null);
15
15
  const d = disposables();
16
16
  $effect(() => {
17
- if (!onReset)
18
- return;
19
- if (!form)
20
- return;
17
+ if (!onReset) return;
18
+ if (!form) return;
21
19
  return d.addEventListener(form, "reset", onReset);
22
20
  });
23
21
  </script>
@@ -1,4 +1,3 @@
1
- /// <reference types="svelte" />
2
1
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
2
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
3
  $$bindings?: Bindings;
@@ -11,12 +10,12 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
11
10
  }
12
11
  declare const FormFields: $$__sveltets_2_IsomorphicComponent<{
13
12
  data: Record<string, any>;
14
- overrides?: Record<string, any> | undefined;
15
- form?: string | undefined;
16
- disabled?: boolean | undefined;
17
- onReset?: ((e: Event) => void) | undefined;
13
+ overrides?: Record<string, any>;
14
+ form?: string;
15
+ disabled?: boolean;
16
+ onReset?: (e: Event) => void;
18
17
  }, {
19
18
  [evt: string]: CustomEvent<any>;
20
- }, {}, Record<string, any>, "">;
19
+ }, {}, {}, "">;
21
20
  type FormFields = InstanceType<typeof FormFields>;
22
21
  export default FormFields;
@@ -1,25 +1,20 @@
1
- <script lang="ts">import Hidden, { HiddenFeatures } from "./Hidden.svelte";
1
+ <script lang="ts">import { onMount } from "svelte";
2
+ import Hidden, { HiddenFeatures } from "./Hidden.svelte";
2
3
  let { setForm, formId } = $props();
3
4
  $effect(() => {
4
5
  if (formId) {
5
- let resolvedForm = document.getElementById(formId);
6
- if (resolvedForm)
7
- setForm(resolvedForm);
6
+ const resolvedForm = document.getElementById(formId);
7
+ if (resolvedForm) setForm(resolvedForm);
8
8
  }
9
9
  });
10
+ let element = $state();
11
+ onMount(() => {
12
+ if (!element) return;
13
+ const resolvedForm = element.closest("form");
14
+ if (resolvedForm) setForm(resolvedForm);
15
+ });
10
16
  </script>
11
17
 
12
18
  {#if !formId}
13
- <Hidden
14
- features={HiddenFeatures.Hidden}
15
- as="input"
16
- type="hidden"
17
- hidden
18
- readonly
19
- ref={(el) => {
20
- if (!el) return
21
- let resolvedForm = el.closest("form")
22
- if (resolvedForm) setForm(resolvedForm)
23
- }}
24
- />
19
+ <Hidden features={HiddenFeatures.Hidden} as="input" type="hidden" hidden readonly bind:ref={element} />
25
20
  {/if}
@@ -1,4 +1,3 @@
1
- /// <reference types="svelte" />
2
1
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
2
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
3
  $$bindings?: Bindings;
@@ -11,9 +10,9 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
11
10
  }
12
11
  declare const FormResolver: $$__sveltets_2_IsomorphicComponent<{
13
12
  setForm: (form: HTMLFormElement) => void;
14
- formId?: string | undefined;
13
+ formId?: string;
15
14
  }, {
16
15
  [evt: string]: CustomEvent<any>;
17
- }, {}, Record<string, any>, "">;
16
+ }, {}, {}, "">;
18
17
  type FormResolver = InstanceType<typeof FormResolver>;
19
18
  export default FormResolver;
@@ -4,15 +4,15 @@
4
4
  HiddenFeatures2[HiddenFeatures2["Hidden"] = 4] = "Hidden";
5
5
  return HiddenFeatures2;
6
6
  })(HiddenFeatures || {});
7
+ const DEFAULT_VISUALLY_HIDDEN_TAG = "div";
7
8
  </script>
8
9
 
9
- <script lang="ts">import { onMount } from "svelte";
10
- const DEFAULT_VISUALLY_HIDDEN_TAG = "div";
11
- let { as = "div", features = HiddenFeatures.None, ref: applyRef, ...theirProps } = $props();
12
- let ref = $state();
13
- onMount(() => {
14
- applyRef?.(ref);
15
- });
10
+ <script lang="ts" generics="TTag extends keyof SvelteHTMLElements">let {
11
+ as = DEFAULT_VISUALLY_HIDDEN_TAG,
12
+ ref = $bindable(),
13
+ features = HiddenFeatures.None,
14
+ ...theirProps
15
+ } = $props();
16
16
  let ourProps = {
17
17
  "aria-hidden": (features & HiddenFeatures.Focusable) === HiddenFeatures.Focusable ? true : theirProps["aria-hidden"] ?? void 0,
18
18
  hidden: (features & HiddenFeatures.Hidden) === HiddenFeatures.Hidden ? true : void 0,
@@ -33,4 +33,4 @@ let ourProps = {
33
33
  };
34
34
  </script>
35
35
 
36
- <svelte:element this={as} {...theirProps} {...ourProps} bind:this={ref} />
36
+ <svelte:element this={as} bind:this={ref} {...ourProps} {...theirProps} />
@@ -1,26 +1,35 @@
1
- /// <reference types="svelte" />
1
+ import type { HTMLElementType, Props } from "../utils/types.js";
2
+ import type { SvelteHTMLElements } from "svelte/elements";
2
3
  export declare enum HiddenFeatures {
3
4
  None = 1,
4
5
  Focusable = 2,
5
6
  Hidden = 4
6
7
  }
7
- import type { HTMLInputAttributes } from "svelte/elements";
8
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
9
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
10
- $$bindings?: Bindings;
11
- } & Exports;
12
- (internal: unknown, props: Props & {
13
- $$events?: Events;
14
- $$slots?: Slots;
15
- }): Exports;
16
- z_$$bindings?: Bindings;
8
+ declare const DEFAULT_VISUALLY_HIDDEN_TAG: "div";
9
+ type HiddenRenderPropArg = {};
10
+ type HiddenPropsWeControl = never;
11
+ export type HiddenProps<TTag extends keyof SvelteHTMLElements = typeof DEFAULT_VISUALLY_HIDDEN_TAG> = Props<TTag, HiddenRenderPropArg, HiddenPropsWeControl, {
12
+ features?: HiddenFeatures;
13
+ ref?: HTMLElementType<TTag> | null;
14
+ }>;
15
+ declare class __sveltets_Render<TTag extends keyof SvelteHTMLElements> {
16
+ props(): HiddenProps<TTag>;
17
+ events(): {} & {
18
+ [evt: string]: CustomEvent<any>;
19
+ };
20
+ slots(): {};
21
+ bindings(): "ref";
22
+ exports(): {};
17
23
  }
18
- declare const Hidden: $$__sveltets_2_IsomorphicComponent<Omit<HTMLInputAttributes, "style"> & {
19
- as?: string | undefined;
20
- features?: HiddenFeatures | undefined;
21
- ref?: ((el: HTMLElement) => void) | undefined;
22
- }, {
23
- [evt: string]: CustomEvent<any>;
24
- }, {}, Record<string, any>, "">;
25
- type Hidden = InstanceType<typeof Hidden>;
24
+ interface $$IsomorphicComponent {
25
+ new <TTag extends keyof SvelteHTMLElements>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TTag>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TTag>['props']>, ReturnType<__sveltets_Render<TTag>['events']>, ReturnType<__sveltets_Render<TTag>['slots']>> & {
26
+ $$bindings?: ReturnType<__sveltets_Render<TTag>['bindings']>;
27
+ } & ReturnType<__sveltets_Render<TTag>['exports']>;
28
+ <TTag extends keyof SvelteHTMLElements>(internal: unknown, props: ReturnType<__sveltets_Render<TTag>['props']> & {
29
+ $$events?: ReturnType<__sveltets_Render<TTag>['events']>;
30
+ }): ReturnType<__sveltets_Render<TTag>['exports']>;
31
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
32
+ }
33
+ declare const Hidden: $$IsomorphicComponent;
34
+ type Hidden<TTag extends keyof SvelteHTMLElements> = InstanceType<typeof Hidden<TTag>>;
26
35
  export default Hidden;
@@ -13,6 +13,6 @@ declare const HoistFormFields: $$__sveltets_2_IsomorphicComponent<{
13
13
  children: Snippet;
14
14
  }, {
15
15
  [evt: string]: CustomEvent<any>;
16
- }, {}, Record<string, any>, "">;
16
+ }, {}, {}, "">;
17
17
  type HoistFormFields = InstanceType<typeof HoistFormFields>;
18
18
  export default HoistFormFields;