@pzerelles/headlessui-svelte 2.0.0-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 (64) hide show
  1. package/README.md +58 -0
  2. package/dist/actions/activePress.svelte.d.ts +8 -0
  3. package/dist/actions/activePress.svelte.js +84 -0
  4. package/dist/actions/focusRing.svelte.d.ts +9 -0
  5. package/dist/actions/focusRing.svelte.js +34 -0
  6. package/dist/checkbox/Checkbox.svelte +114 -0
  7. package/dist/checkbox/Checkbox.svelte.d.ts +48 -0
  8. package/dist/checkbox/index.d.ts +1 -0
  9. package/dist/checkbox/index.js +1 -0
  10. package/dist/description/Description.svelte +53 -0
  11. package/dist/description/Description.svelte.d.ts +39 -0
  12. package/dist/description/index.d.ts +1 -0
  13. package/dist/description/index.js +1 -0
  14. package/dist/field/Field.svelte +33 -0
  15. package/dist/field/Field.svelte.d.ts +33 -0
  16. package/dist/field/index.d.ts +1 -0
  17. package/dist/field/index.js +1 -0
  18. package/dist/fieldset/Fieldset.svelte +32 -0
  19. package/dist/fieldset/Fieldset.svelte.d.ts +33 -0
  20. package/dist/fieldset/index.d.ts +1 -0
  21. package/dist/fieldset/index.js +1 -0
  22. package/dist/index.d.ts +6 -0
  23. package/dist/index.js +6 -0
  24. package/dist/internal/FormFields.svelte +44 -0
  25. package/dist/internal/FormFields.svelte.d.ts +22 -0
  26. package/dist/internal/FormResolver.svelte +25 -0
  27. package/dist/internal/FormResolver.svelte.d.ts +19 -0
  28. package/dist/internal/Hidden.svelte +36 -0
  29. package/dist/internal/Hidden.svelte.d.ts +26 -0
  30. package/dist/internal/HoistFormFields.svelte +11 -0
  31. package/dist/internal/HoistFormFields.svelte.d.ts +18 -0
  32. package/dist/internal/Portal.svelte +17 -0
  33. package/dist/internal/Portal.svelte.d.ts +19 -0
  34. package/dist/label/Label.svelte +99 -0
  35. package/dist/label/Label.svelte.d.ts +41 -0
  36. package/dist/label/index.d.ts +1 -0
  37. package/dist/label/index.js +1 -0
  38. package/dist/legend/Legend.svelte +7 -0
  39. package/dist/legend/Legend.svelte.d.ts +18 -0
  40. package/dist/legend/index.d.ts +1 -0
  41. package/dist/legend/index.js +1 -0
  42. package/dist/utils/disabled.d.ts +3 -0
  43. package/dist/utils/disabled.js +2 -0
  44. package/dist/utils/disposables.d.ts +24 -0
  45. package/dist/utils/disposables.js +78 -0
  46. package/dist/utils/dom.d.ts +3 -0
  47. package/dist/utils/dom.js +10 -0
  48. package/dist/utils/focusVisible.svelte.d.ts +50 -0
  49. package/dist/utils/focusVisible.svelte.js +278 -0
  50. package/dist/utils/form.d.ts +4 -0
  51. package/dist/utils/form.js +57 -0
  52. package/dist/utils/id.d.ts +4 -0
  53. package/dist/utils/id.js +6 -0
  54. package/dist/utils/isVirtualEvent.d.ts +2 -0
  55. package/dist/utils/isVirtualEvent.js +48 -0
  56. package/dist/utils/microTask.d.ts +1 -0
  57. package/dist/utils/microTask.js +13 -0
  58. package/dist/utils/object.d.ts +1 -0
  59. package/dist/utils/object.js +8 -0
  60. package/dist/utils/platform.d.ts +4 -0
  61. package/dist/utils/platform.js +29 -0
  62. package/dist/utils/state.d.ts +1 -0
  63. package/dist/utils/state.js +20 -0
  64. package/package.json +69 -0
@@ -0,0 +1,278 @@
1
+ /*
2
+ * Copyright 2020 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+ // Portions of the code in this file are based on code from react.
13
+ // Original licensing for the following can be found in the
14
+ // NOTICE file in the root directory of this source tree.
15
+ // See https://github.com/facebook/react/tree/cc7c1aece46a6b69b41958d731e0fd27c94bfc6c/packages/react-interactions
16
+ import { getOwnerDocument, getOwnerWindow } from "./dom.js";
17
+ import { isVirtualClick } from "./isVirtualEvent.js";
18
+ import { isMac } from "./platform.js";
19
+ let currentModality = null;
20
+ let changeHandlers = new Set();
21
+ export let hasSetupGlobalListeners = new Map(); // We use a map here to support setting event listeners across multiple document objects.
22
+ let hasEventBeforeFocus = false;
23
+ let hasBlurredWindowRecently = false;
24
+ // Only Tab or Esc keys will make focus visible on text input elements
25
+ const FOCUS_VISIBLE_INPUT_KEYS = {
26
+ Tab: true,
27
+ Escape: true,
28
+ };
29
+ function triggerChangeHandlers(modality, e) {
30
+ for (let handler of changeHandlers) {
31
+ handler(modality, e);
32
+ }
33
+ }
34
+ /**
35
+ * Helper function to determine if a KeyboardEvent is unmodified and could make keyboard focus styles visible.
36
+ */
37
+ function isValidKey(e) {
38
+ // Control and Shift keys trigger when navigating back to the tab with keyboard.
39
+ return !(e.metaKey ||
40
+ (!isMac() && e.altKey) ||
41
+ e.ctrlKey ||
42
+ e.key === "Control" ||
43
+ e.key === "Shift" ||
44
+ e.key === "Meta");
45
+ }
46
+ function handleKeyboardEvent(e) {
47
+ hasEventBeforeFocus = true;
48
+ if (isValidKey(e)) {
49
+ currentModality = "keyboard";
50
+ triggerChangeHandlers("keyboard", e);
51
+ }
52
+ }
53
+ function handlePointerEvent(e) {
54
+ currentModality = "pointer";
55
+ if (e.type === "mousedown" || e.type === "pointerdown") {
56
+ hasEventBeforeFocus = true;
57
+ triggerChangeHandlers("pointer", e);
58
+ }
59
+ }
60
+ function handleClickEvent(e) {
61
+ if (isVirtualClick(e)) {
62
+ hasEventBeforeFocus = true;
63
+ currentModality = "virtual";
64
+ }
65
+ }
66
+ function handleFocusEvent(e) {
67
+ // Firefox fires two extra focus events when the user first clicks into an iframe:
68
+ // first on the window, then on the document. We ignore these events so they don't
69
+ // cause keyboard focus rings to appear.
70
+ if (e.target === window || e.target === document) {
71
+ return;
72
+ }
73
+ // If a focus event occurs without a preceding keyboard or pointer event, switch to virtual modality.
74
+ // This occurs, for example, when navigating a form with the next/previous buttons on iOS.
75
+ if (!hasEventBeforeFocus && !hasBlurredWindowRecently) {
76
+ currentModality = "virtual";
77
+ triggerChangeHandlers("virtual", e);
78
+ }
79
+ hasEventBeforeFocus = false;
80
+ hasBlurredWindowRecently = false;
81
+ }
82
+ function handleWindowBlur() {
83
+ // When the window is blurred, reset state. This is necessary when tabbing out of the window,
84
+ // for example, since a subsequent focus event won't be fired.
85
+ hasEventBeforeFocus = false;
86
+ hasBlurredWindowRecently = true;
87
+ }
88
+ /**
89
+ * Setup global event listeners to control when keyboard focus style should be visible.
90
+ */
91
+ function setupGlobalFocusEvents(element) {
92
+ if (typeof window === "undefined" || hasSetupGlobalListeners.get(getOwnerWindow(element))) {
93
+ return;
94
+ }
95
+ const windowObject = getOwnerWindow(element);
96
+ const documentObject = getOwnerDocument(element);
97
+ // Programmatic focus() calls shouldn't affect the current input modality.
98
+ // However, we need to detect other cases when a focus event occurs without
99
+ // a preceding user event (e.g. screen reader focus). Overriding the focus
100
+ // method on HTMLElement.prototype is a bit hacky, but works.
101
+ let focus = windowObject.HTMLElement.prototype.focus;
102
+ windowObject.HTMLElement.prototype.focus = function () {
103
+ hasEventBeforeFocus = true;
104
+ focus.apply(this, arguments);
105
+ };
106
+ documentObject.addEventListener("keydown", handleKeyboardEvent, true);
107
+ documentObject.addEventListener("keyup", handleKeyboardEvent, true);
108
+ documentObject.addEventListener("click", handleClickEvent, true);
109
+ // Register focus events on the window so they are sure to happen
110
+ // before React's event listeners (registered on the document).
111
+ windowObject.addEventListener("focus", handleFocusEvent, true);
112
+ windowObject.addEventListener("blur", handleWindowBlur, false);
113
+ if (typeof PointerEvent !== "undefined") {
114
+ documentObject.addEventListener("pointerdown", handlePointerEvent, true);
115
+ documentObject.addEventListener("pointermove", handlePointerEvent, true);
116
+ documentObject.addEventListener("pointerup", handlePointerEvent, true);
117
+ }
118
+ else {
119
+ documentObject.addEventListener("mousedown", handlePointerEvent, true);
120
+ documentObject.addEventListener("mousemove", handlePointerEvent, true);
121
+ documentObject.addEventListener("mouseup", handlePointerEvent, true);
122
+ }
123
+ // Add unmount handler
124
+ windowObject.addEventListener("beforeunload", () => {
125
+ tearDownWindowFocusTracking(element);
126
+ }, { once: true });
127
+ hasSetupGlobalListeners.set(windowObject, { focus });
128
+ }
129
+ const tearDownWindowFocusTracking = (element, loadListener) => {
130
+ const windowObject = getOwnerWindow(element);
131
+ const documentObject = getOwnerDocument(element);
132
+ if (loadListener) {
133
+ documentObject.removeEventListener("DOMContentLoaded", loadListener);
134
+ }
135
+ if (!hasSetupGlobalListeners.has(windowObject)) {
136
+ return;
137
+ }
138
+ windowObject.HTMLElement.prototype.focus = hasSetupGlobalListeners.get(windowObject).focus;
139
+ documentObject.removeEventListener("keydown", handleKeyboardEvent, true);
140
+ documentObject.removeEventListener("keyup", handleKeyboardEvent, true);
141
+ documentObject.removeEventListener("click", handleClickEvent, true);
142
+ windowObject.removeEventListener("focus", handleFocusEvent, true);
143
+ windowObject.removeEventListener("blur", handleWindowBlur, false);
144
+ if (typeof PointerEvent !== "undefined") {
145
+ documentObject.removeEventListener("pointerdown", handlePointerEvent, true);
146
+ documentObject.removeEventListener("pointermove", handlePointerEvent, true);
147
+ documentObject.removeEventListener("pointerup", handlePointerEvent, true);
148
+ }
149
+ else {
150
+ documentObject.removeEventListener("mousedown", handlePointerEvent, true);
151
+ documentObject.removeEventListener("mousemove", handlePointerEvent, true);
152
+ documentObject.removeEventListener("mouseup", handlePointerEvent, true);
153
+ }
154
+ hasSetupGlobalListeners.delete(windowObject);
155
+ };
156
+ /**
157
+ * EXPERIMENTAL
158
+ * Adds a window (i.e. iframe) to the list of windows that are being tracked for focus visible.
159
+ *
160
+ * Sometimes apps render portions of their tree into an iframe. In this case, we cannot accurately track if the focus
161
+ * is visible because we cannot see interactions inside the iframe. If you have this in your application's architecture,
162
+ * then this function will attach event listeners inside the iframe. You should call `addWindowFocusTracking` with an
163
+ * element from inside the window you wish to add. We'll retrieve the relevant elements based on that.
164
+ * Note, you do not need to call this for the default window, as we call it for you.
165
+ *
166
+ * When you are ready to stop listening, but you do not wish to unmount the iframe, you may call the cleanup function
167
+ * returned by `addWindowFocusTracking`. Otherwise, when you unmount the iframe, all listeners and state will be cleaned
168
+ * up automatically for you.
169
+ *
170
+ * @param element @default document.body - The element provided will be used to get the window to add.
171
+ * @returns A function to remove the event listeners and cleanup the state.
172
+ */
173
+ export function addWindowFocusTracking(element) {
174
+ const documentObject = getOwnerDocument(element);
175
+ let loadListener;
176
+ if (documentObject.readyState !== "loading") {
177
+ setupGlobalFocusEvents(element);
178
+ }
179
+ else {
180
+ loadListener = () => {
181
+ setupGlobalFocusEvents(element);
182
+ };
183
+ documentObject.addEventListener("DOMContentLoaded", loadListener);
184
+ }
185
+ return () => tearDownWindowFocusTracking(element, loadListener);
186
+ }
187
+ // Server-side rendering does not have the document object defined
188
+ // eslint-disable-next-line no-restricted-globals
189
+ if (typeof document !== "undefined") {
190
+ addWindowFocusTracking();
191
+ }
192
+ /**
193
+ * If true, keyboard focus is visible.
194
+ */
195
+ export function isFocusVisible() {
196
+ return currentModality !== "pointer";
197
+ }
198
+ export function getInteractionModality() {
199
+ return currentModality;
200
+ }
201
+ export function setInteractionModality(modality) {
202
+ currentModality = modality;
203
+ triggerChangeHandlers(modality, null);
204
+ }
205
+ /**
206
+ * Keeps state of the current modality.
207
+ */
208
+ /*export function useInteractionModality(): Modality | null {
209
+ setupGlobalFocusEvents()
210
+
211
+ let [modality, setModality] = useState(currentModality)
212
+ useEffect(() => {
213
+ let handler = () => {
214
+ setModality(currentModality)
215
+ }
216
+
217
+ changeHandlers.add(handler)
218
+ return () => {
219
+ changeHandlers.delete(handler)
220
+ }
221
+ }, [])
222
+
223
+ return useIsSSR() ? null : modality
224
+ }*/
225
+ const nonTextInputTypes = new Set(["checkbox", "radio", "range", "color", "file", "image", "button", "submit", "reset"]);
226
+ /**
227
+ * If this is attached to text input component, return if the event is a focus event (Tab/Escape keys pressed) so that
228
+ * focus visible style can be properly set.
229
+ */
230
+ function isKeyboardFocusEvent(isTextInput, modality, e) {
231
+ const IHTMLInputElement = typeof window !== "undefined" ? getOwnerWindow(e?.target).HTMLInputElement : HTMLInputElement;
232
+ const IHTMLTextAreaElement = typeof window !== "undefined" ? getOwnerWindow(e?.target).HTMLTextAreaElement : HTMLTextAreaElement;
233
+ const IHTMLElement = typeof window !== "undefined" ? getOwnerWindow(e?.target).HTMLElement : HTMLElement;
234
+ const IKeyboardEvent = typeof window !== "undefined" ? getOwnerWindow(e?.target).KeyboardEvent : KeyboardEvent;
235
+ isTextInput =
236
+ isTextInput ||
237
+ (e?.target instanceof IHTMLInputElement && !nonTextInputTypes.has(e.target.type)) ||
238
+ e?.target instanceof IHTMLTextAreaElement ||
239
+ (e?.target instanceof IHTMLElement && e.target.isContentEditable);
240
+ return !(isTextInput &&
241
+ modality === "keyboard" &&
242
+ e instanceof IKeyboardEvent &&
243
+ !FOCUS_VISIBLE_INPUT_KEYS[e.key]);
244
+ }
245
+ /**
246
+ * Manages focus visible state for the page, and subscribes individual components for updates.
247
+ */
248
+ /*export function useFocusVisible(props: FocusVisibleProps = {}): FocusVisibleResult {
249
+ let { isTextInput, autoFocus } = props
250
+ let [isFocusVisibleState, setFocusVisible] = useState(autoFocus || isFocusVisible())
251
+ useFocusVisibleListener(
252
+ (isFocusVisible) => {
253
+ setFocusVisible(isFocusVisible)
254
+ },
255
+ [isTextInput],
256
+ { isTextInput }
257
+ )
258
+
259
+ return { isFocusVisible: isFocusVisibleState }
260
+ }*/
261
+ /**
262
+ * Listens for trigger change and reports if focus is visible (i.e., modality is not pointer).
263
+ */
264
+ export function useFocusVisibleListener(fn, opts) {
265
+ setupGlobalFocusEvents();
266
+ $effect(() => {
267
+ const handler = (modality, e) => {
268
+ if (!isKeyboardFocusEvent(!!opts?.isTextInput, modality, e)) {
269
+ return;
270
+ }
271
+ fn(isFocusVisible());
272
+ };
273
+ changeHandlers.add(handler);
274
+ return () => {
275
+ changeHandlers.delete(handler);
276
+ };
277
+ });
278
+ }
@@ -0,0 +1,4 @@
1
+ type Entries = [string, string][];
2
+ export declare function objectToFormEntries(source?: Record<string, any>, parentKey?: string | null, entries?: Entries): Entries;
3
+ export declare function attemptSubmit(elementInForm: HTMLElement): void;
4
+ export {};
@@ -0,0 +1,57 @@
1
+ export function objectToFormEntries(source = {}, parentKey = null, entries = []) {
2
+ for (let [key, value] of Object.entries(source)) {
3
+ append(entries, composeKey(parentKey, key), value);
4
+ }
5
+ return entries;
6
+ }
7
+ function composeKey(parent, key) {
8
+ return parent ? parent + "[" + key + "]" : key;
9
+ }
10
+ function append(entries, key, value) {
11
+ if (Array.isArray(value)) {
12
+ for (let [subkey, subvalue] of value.entries()) {
13
+ append(entries, composeKey(key, subkey.toString()), subvalue);
14
+ }
15
+ }
16
+ else if (value instanceof Date) {
17
+ entries.push([key, value.toISOString()]);
18
+ }
19
+ else if (typeof value === "boolean") {
20
+ entries.push([key, value ? "1" : "0"]);
21
+ }
22
+ else if (typeof value === "string") {
23
+ entries.push([key, value]);
24
+ }
25
+ else if (typeof value === "number") {
26
+ entries.push([key, `${value}`]);
27
+ }
28
+ else if (value === null || value === undefined) {
29
+ entries.push([key, ""]);
30
+ }
31
+ else {
32
+ objectToFormEntries(value, key, entries);
33
+ }
34
+ }
35
+ export function attemptSubmit(elementInForm) {
36
+ let form = elementInForm?.form ?? elementInForm.closest("form");
37
+ if (!form)
38
+ return;
39
+ for (let element of form.elements) {
40
+ if (element === elementInForm)
41
+ continue;
42
+ if ((element.tagName === "INPUT" && element.type === "submit") ||
43
+ (element.tagName === "BUTTON" && element.type === "submit") ||
44
+ (element.nodeName === "INPUT" && element.type === "image")) {
45
+ // If you press `enter` in a normal input[type='text'] field, then the form will submit by
46
+ // searching for the a submit element and "click" it. We could also use the
47
+ // `form.requestSubmit()` function, but this has a downside where an `event.preventDefault()`
48
+ // inside a `click` listener on the submit button won't stop the form from submitting.
49
+ element.click();
50
+ return;
51
+ }
52
+ }
53
+ // If we get here, then there is no submit button in the form. We can use the
54
+ // `form.requestSubmit()` function to submit the form instead. We cannot use `form.submit()`
55
+ // because then the `submit` event won't be fired and `onSubmit` listeners won't be fired.
56
+ form.requestSubmit?.();
57
+ }
@@ -0,0 +1,4 @@
1
+ export declare const alphaid: (size?: number | undefined) => string;
2
+ export declare const htmlid: (size?: number) => string;
3
+ export declare const getIdContext: () => string | undefined;
4
+ export declare const createIdContext: (id: string) => string | undefined;
@@ -0,0 +1,6 @@
1
+ import { nanoid, customAlphabet } from "nanoid";
2
+ import { getContext, setContext } from "svelte";
3
+ export const alphaid = customAlphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
4
+ export const htmlid = (size = 10) => alphaid(1) + nanoid(size - 1);
5
+ export const getIdContext = () => getContext("Id");
6
+ export const createIdContext = (id) => setContext("Id", id);
@@ -0,0 +1,2 @@
1
+ export declare function isVirtualClick(event: MouseEvent | PointerEvent): boolean;
2
+ export declare function isVirtualPointerEvent(event: PointerEvent): boolean;
@@ -0,0 +1,48 @@
1
+ /*
2
+ * Copyright 2022 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+ import { isAndroid } from "./platform.js";
13
+ // Original licensing for the following method can be found in the
14
+ // NOTICE file in the root directory of this source tree.
15
+ // See https://github.com/facebook/react/blob/3c713d513195a53788b3f8bb4b70279d68b15bcc/packages/react-interactions/events/src/dom/shared/index.js#L74-L87
16
+ // Keyboards, Assistive Technologies, and element.click() all produce a "virtual"
17
+ // click event. This is a method of inferring such clicks. Every browser except
18
+ // IE 11 only sets a zero value of "detail" for click events that are "virtual".
19
+ // However, IE 11 uses a zero value for all click events. For IE 11 we rely on
20
+ // the quirk that it produces click events that are of type PointerEvent, and
21
+ // where only the "virtual" click lacks a pointerType field.
22
+ export function isVirtualClick(event) {
23
+ // JAWS/NVDA with Firefox.
24
+ if (event.mozInputSource === 0 && event.isTrusted) {
25
+ return true;
26
+ }
27
+ // Android TalkBack's detail value varies depending on the event listener providing the event so we have specific logic here instead
28
+ // If pointerType is defined, event is from a click listener. For events from mousedown listener, detail === 0 is a sufficient check
29
+ // to detect TalkBack virtual clicks.
30
+ if (isAndroid() && event.pointerType) {
31
+ return event.type === "click" && event.buttons === 1;
32
+ }
33
+ return event.detail === 0 && !event.pointerType;
34
+ }
35
+ export function isVirtualPointerEvent(event) {
36
+ // If the pointer size is zero, then we assume it's from a screen reader.
37
+ // Android TalkBack double tap will sometimes return a event with width and height of 1
38
+ // and pointerType === 'mouse' so we need to check for a specific combination of event attributes.
39
+ // Cannot use "event.pressure === 0" as the sole check due to Safari pointer events always returning pressure === 0
40
+ // instead of .5, see https://bugs.webkit.org/show_bug.cgi?id=206216. event.pointerType === 'mouse' is to distingush
41
+ // Talkback double tap from Windows Firefox touch screen press
42
+ return ((!isAndroid() && event.width === 0 && event.height === 0) ||
43
+ (event.width === 1 &&
44
+ event.height === 1 &&
45
+ event.pressure === 0 &&
46
+ event.detail === 0 &&
47
+ event.pointerType === "mouse"));
48
+ }
@@ -0,0 +1 @@
1
+ export declare function microTask(cb: () => void): void;
@@ -0,0 +1,13 @@
1
+ // Polyfill
2
+ export function microTask(cb) {
3
+ if (typeof queueMicrotask === "function") {
4
+ queueMicrotask(cb);
5
+ }
6
+ else {
7
+ Promise.resolve()
8
+ .then(cb)
9
+ .catch((e) => setTimeout(() => {
10
+ throw e;
11
+ }));
12
+ }
13
+ }
@@ -0,0 +1 @@
1
+ export declare function compact<T extends Record<any, any>>(object: T): {} & T;
@@ -0,0 +1,8 @@
1
+ export function compact(object) {
2
+ let clone = Object.assign({}, object);
3
+ for (let key in clone) {
4
+ if (clone[key] === undefined)
5
+ delete clone[key];
6
+ }
7
+ return clone;
8
+ }
@@ -0,0 +1,4 @@
1
+ export declare function testUserAgent(re: RegExp): any;
2
+ export declare function testPlatform(re: RegExp): boolean;
3
+ export declare const isMac: () => boolean;
4
+ export declare const isAndroid: () => boolean;
@@ -0,0 +1,29 @@
1
+ export function testUserAgent(re) {
2
+ if (typeof window === "undefined" || window.navigator == null) {
3
+ return false;
4
+ }
5
+ return (window.navigator["userAgentData"]?.brands.some((brand) => re.test(brand.brand)) || re.test(window.navigator.userAgent));
6
+ }
7
+ export function testPlatform(re) {
8
+ return typeof window !== "undefined" && window.navigator != null
9
+ ? re.test(window.navigator["userAgentData"]?.platform || window.navigator.platform)
10
+ : false;
11
+ }
12
+ function cached(fn) {
13
+ if (process.env.NODE_ENV === "test") {
14
+ return fn;
15
+ }
16
+ let res = null;
17
+ return () => {
18
+ if (res == null) {
19
+ res = fn();
20
+ }
21
+ return res;
22
+ };
23
+ }
24
+ export const isMac = cached(function () {
25
+ return testPlatform(/^Mac/i);
26
+ });
27
+ export const isAndroid = cached(function () {
28
+ return testUserAgent(/Android/i);
29
+ });
@@ -0,0 +1 @@
1
+ export declare const stateFromSlot: <TSlot extends Record<string, any>>(slot?: TSlot) => Record<string, string>;
@@ -0,0 +1,20 @@
1
+ export const stateFromSlot = (slot = {}) => {
2
+ let dataAttributes = {};
3
+ let exposeState = false;
4
+ let states = [];
5
+ for (let [k, v] of Object.entries(slot)) {
6
+ if (typeof v === "boolean") {
7
+ exposeState = true;
8
+ }
9
+ if (v === true) {
10
+ states.push(k.replace(/([A-Z])/g, (m) => `-${m.toLowerCase()}`));
11
+ }
12
+ }
13
+ if (exposeState) {
14
+ dataAttributes["data-headlessui-state"] = states.join(" ");
15
+ for (let s of states) {
16
+ dataAttributes[`data-${s}`] = "";
17
+ }
18
+ }
19
+ return dataAttributes;
20
+ };
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@pzerelles/headlessui-svelte",
3
+ "version": "2.0.0-next.1",
4
+ "exports": {
5
+ ".": {
6
+ "types": "./dist/index.d.ts",
7
+ "svelte": "./dist/index.js"
8
+ }
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "!dist/**/*.test.*",
13
+ "!dist/**/*.spec.*"
14
+ ],
15
+ "peerDependencies": {
16
+ "svelte": "^5.0.0-next.1"
17
+ },
18
+ "devDependencies": {
19
+ "@changesets/cli": "^2.27.5",
20
+ "@changesets/types": "^6.0.0",
21
+ "@playwright/test": "^1.44.1",
22
+ "@sveltejs/adapter-auto": "^3.2.1",
23
+ "@sveltejs/kit": "^2.5.10",
24
+ "@sveltejs/package": "^2.3.1",
25
+ "@sveltejs/vite-plugin-svelte": "^3.1.1",
26
+ "@types/eslint": "^8.56.10",
27
+ "@types/node": "^20.14.2",
28
+ "autoprefixer": "^10.4.19",
29
+ "eslint": "^9.4.0",
30
+ "eslint-config-prettier": "^9.1.0",
31
+ "eslint-plugin-svelte": "^2.39.0",
32
+ "globals": "^15.3.0",
33
+ "outdent": "^0.8.0",
34
+ "postcss": "^8.4.38",
35
+ "prettier": "^3.3.1",
36
+ "prettier-plugin-svelte": "^3.2.3",
37
+ "prettier-plugin-tailwindcss": "^0.5.14",
38
+ "publint": "^0.1.16",
39
+ "svelte": "5.0.0-next.150",
40
+ "svelte-check": "^3.8.0",
41
+ "tailwindcss": "^3.4.4",
42
+ "tslib": "^2.6.3",
43
+ "typescript": "^5.4.5",
44
+ "typescript-eslint": "8.0.0-alpha.28",
45
+ "vite": "^5.2.12",
46
+ "vitest": "^1.6.0"
47
+ },
48
+ "dependencies": {
49
+ "nanoid": "^5.0.7",
50
+ "svelte-interactions": "^0.2.0"
51
+ },
52
+ "svelte": "./dist/index.js",
53
+ "types": "./dist/index.d.ts",
54
+ "type": "module",
55
+ "scripts": {
56
+ "dev": "vite dev",
57
+ "build": "vite build && npm run package",
58
+ "preview": "vite preview",
59
+ "package": "svelte-kit sync && svelte-package && publint",
60
+ "test": "npm run test:integration && npm run test:unit",
61
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
62
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
63
+ "lint": "prettier --check . && eslint .",
64
+ "format": "prettier --write .",
65
+ "test:integration": "playwright test",
66
+ "test:unit": "vitest",
67
+ "release": "pnpm package && changeset publish"
68
+ }
69
+ }