@pzerelles/headlessui-svelte 2.0.0-next.1 → 2.1.2-next.2
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.
- package/dist/button/Button.svelte +61 -0
- package/dist/button/Button.svelte.d.ts +47 -0
- package/dist/button/index.d.ts +1 -0
- package/dist/button/index.js +1 -0
- package/dist/checkbox/Checkbox.svelte +93 -61
- package/dist/checkbox/Checkbox.svelte.d.ts +45 -29
- package/dist/close-button/CloseButton.svelte +11 -0
- package/dist/close-button/CloseButton.svelte.d.ts +48 -0
- package/dist/close-button/index.d.ts +1 -0
- package/dist/close-button/index.js +1 -0
- package/dist/combobox/Combobox.svelte +6 -0
- package/dist/combobox/Combobox.svelte.d.ts +50 -0
- package/dist/data-interactive/DataInteractive.svelte +41 -0
- package/dist/data-interactive/DataInteractive.svelte.d.ts +39 -0
- package/dist/data-interactive/index.d.ts +1 -0
- package/dist/data-interactive/index.js +1 -0
- package/dist/description/Description.svelte +16 -41
- package/dist/description/Description.svelte.d.ts +15 -23
- package/dist/description/context.svelte.d.ts +17 -0
- package/dist/description/context.svelte.js +51 -0
- package/dist/dialog/Dialog.svelte +51 -0
- package/dist/dialog/Dialog.svelte.d.ts +60 -0
- package/dist/dialog/DialogBackdrop.svelte +39 -0
- package/dist/dialog/DialogBackdrop.svelte.d.ts +38 -0
- package/dist/dialog/DialogPanel.svelte +46 -0
- package/dist/dialog/DialogPanel.svelte.d.ts +40 -0
- package/dist/dialog/DialogTitle.svelte +29 -0
- package/dist/dialog/DialogTitle.svelte.d.ts +34 -0
- package/dist/dialog/InternalDialog.svelte +233 -0
- package/dist/dialog/InternalDialog.svelte.d.ts +42 -0
- package/dist/dialog/context.svelte.d.ts +15 -0
- package/dist/dialog/context.svelte.js +16 -0
- package/dist/dialog/index.d.ts +4 -0
- package/dist/dialog/index.js +4 -0
- package/dist/field/Field.svelte +14 -16
- package/dist/field/Field.svelte.d.ts +21 -17
- package/dist/fieldset/Fieldset.svelte +19 -17
- package/dist/fieldset/Fieldset.svelte.d.ts +21 -17
- package/dist/focus-trap/FocusTrap.svelte +332 -0
- package/dist/focus-trap/FocusTrap.svelte.d.ts +58 -0
- package/dist/hooks/document-overflow/adjust-scrollbar-padding.d.ts +2 -0
- package/dist/hooks/document-overflow/adjust-scrollbar-padding.js +18 -0
- package/dist/hooks/document-overflow/handle-ios-locking.d.ts +6 -0
- package/dist/hooks/document-overflow/handle-ios-locking.js +134 -0
- package/dist/hooks/document-overflow/overflow-store.d.ts +19 -0
- package/dist/hooks/document-overflow/overflow-store.js +76 -0
- package/dist/hooks/document-overflow/prevent-scroll.d.ts +2 -0
- package/dist/hooks/document-overflow/prevent-scroll.js +7 -0
- package/dist/hooks/document-overflow/use-document-overflow.svelte.d.ts +7 -0
- package/dist/hooks/document-overflow/use-document-overflow.svelte.js +27 -0
- package/dist/hooks/use-active-press.svelte.d.ts +14 -0
- package/dist/{actions/activePress.svelte.js → hooks/use-active-press.svelte.js} +33 -39
- package/dist/hooks/use-by-comparator.d.ts +2 -0
- package/dist/hooks/use-by-comparator.js +15 -0
- package/dist/hooks/use-controllable.svelte.d.ts +6 -0
- package/dist/hooks/use-controllable.svelte.js +34 -0
- package/dist/hooks/use-did-element-move.svelte.d.ts +6 -0
- package/dist/hooks/use-did-element-move.svelte.js +27 -0
- package/dist/hooks/use-disabled.d.ts +3 -0
- package/dist/hooks/use-disabled.js +9 -0
- package/dist/hooks/use-element-size.svelte.d.ts +7 -0
- package/dist/hooks/use-element-size.svelte.js +36 -0
- package/dist/hooks/use-escape.svelte.d.ts +5 -0
- package/dist/hooks/use-escape.svelte.js +26 -0
- package/dist/hooks/use-event-listener.svelte.d.ts +6 -0
- package/dist/hooks/use-event-listener.svelte.js +12 -0
- package/dist/hooks/use-flags.svelte.d.ts +8 -0
- package/dist/hooks/use-flags.svelte.js +18 -0
- package/dist/hooks/use-focus-ring.svelte.d.ts +10 -0
- package/dist/hooks/use-focus-ring.svelte.js +24 -0
- package/dist/hooks/use-hover.svelte.d.ts +26 -0
- package/dist/hooks/use-hover.svelte.js +124 -0
- package/dist/hooks/use-id.d.ts +1 -0
- package/dist/hooks/use-id.js +1 -0
- package/dist/hooks/use-inert-others.svelte.d.ts +32 -0
- package/dist/hooks/use-inert-others.svelte.js +114 -0
- package/dist/hooks/use-is-mounted.svelte.d.ts +3 -0
- package/dist/hooks/use-is-mounted.svelte.js +14 -0
- package/dist/hooks/use-is-top-layer.svelte.d.ts +29 -0
- package/dist/hooks/use-is-top-layer.svelte.js +82 -0
- package/dist/hooks/use-is-touch-device.svelte.d.ts +3 -0
- package/dist/hooks/use-is-touch-device.svelte.js +20 -0
- package/dist/hooks/use-on-disappear.svelte.d.ts +12 -0
- package/dist/hooks/use-on-disappear.svelte.js +38 -0
- package/dist/hooks/use-outside-click.svelte.d.ts +10 -0
- package/dist/hooks/use-outside-click.svelte.js +150 -0
- package/dist/hooks/use-reducer.d.ts +4 -0
- package/dist/hooks/use-reducer.js +11 -0
- package/dist/hooks/use-resolve-button-type.svelte.d.ts +10 -0
- package/dist/hooks/use-resolve-button-type.svelte.js +19 -0
- package/dist/hooks/use-root-containers.svelte.d.ts +9 -0
- package/dist/hooks/use-root-containers.svelte.js +50 -0
- package/dist/hooks/use-scroll-lock.svelte.d.ts +5 -0
- package/dist/hooks/use-scroll-lock.svelte.js +24 -0
- package/dist/hooks/use-sync-refs.d.ts +7 -0
- package/dist/hooks/use-sync-refs.js +22 -0
- package/dist/hooks/use-tab-direction.svelte.d.ts +7 -0
- package/dist/hooks/use-tab-direction.svelte.js +25 -0
- package/dist/hooks/use-text-value.svelte.d.ts +3 -0
- package/dist/hooks/use-text-value.svelte.js +20 -0
- package/dist/hooks/use-tracked-pointer.d.ts +4 -0
- package/dist/hooks/use-tracked-pointer.js +26 -0
- package/dist/hooks/use-transition.svelte.d.ts +20 -0
- package/dist/hooks/use-transition.svelte.js +253 -0
- package/dist/hooks/use-tree-walker.svelte.d.ts +8 -0
- package/dist/hooks/use-tree-walker.svelte.js +19 -0
- package/dist/hooks/use-watch.svelte.d.ts +4 -0
- package/dist/hooks/use-watch.svelte.js +16 -0
- package/dist/hooks/use-window-event.svelte.d.ts +6 -0
- package/dist/hooks/use-window-event.svelte.js +12 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +13 -0
- package/dist/input/Input.svelte +59 -0
- package/dist/input/Input.svelte.d.ts +52 -0
- package/dist/input/index.d.ts +1 -0
- package/dist/input/index.js +1 -0
- package/dist/internal/FocusSentinel.svelte +45 -0
- package/dist/internal/FocusSentinel.svelte.d.ts +20 -0
- package/dist/internal/ForcePortalRoot.svelte +6 -0
- package/dist/internal/ForcePortalRoot.svelte.d.ts +22 -0
- package/dist/internal/FormFields.svelte +2 -4
- package/dist/internal/FormFields.svelte.d.ts +9 -7
- package/dist/internal/FormResolver.svelte +11 -16
- package/dist/internal/FormResolver.svelte.d.ts +6 -4
- package/dist/internal/Hidden.svelte +5 -9
- package/dist/internal/Hidden.svelte.d.ts +35 -19
- package/dist/internal/HoistFormFields.svelte.d.ts +5 -2
- package/dist/internal/MainTreeProvider.svelte +45 -0
- package/dist/internal/MainTreeProvider.svelte.d.ts +31 -0
- package/dist/internal/Portal.svelte.d.ts +5 -2
- package/dist/internal/close-provider.d.ts +7 -0
- package/dist/internal/close-provider.js +7 -0
- package/dist/internal/floating.svelte.d.ts +62 -0
- package/dist/internal/floating.svelte.js +488 -0
- package/dist/internal/frozen.svelte.d.ts +6 -0
- package/dist/internal/frozen.svelte.js +18 -0
- package/dist/internal/id.d.ts +8 -0
- package/dist/internal/id.js +11 -0
- package/dist/internal/open-closed.d.ts +14 -0
- package/dist/internal/open-closed.js +17 -0
- package/dist/internal/portal-force-root.svelte.d.ts +6 -0
- package/dist/internal/portal-force-root.svelte.js +11 -0
- package/dist/label/Label.svelte +17 -45
- package/dist/label/Label.svelte.d.ts +19 -23
- package/dist/label/context.svelte.d.ts +17 -0
- package/dist/label/context.svelte.js +56 -0
- package/dist/legend/Legend.svelte +4 -3
- package/dist/legend/Legend.svelte.d.ts +33 -16
- package/dist/listbox/Listbox.svelte +448 -0
- package/dist/listbox/Listbox.svelte.d.ts +126 -0
- package/dist/listbox/ListboxButton.svelte +139 -0
- package/dist/listbox/ListboxButton.svelte.d.ts +52 -0
- package/dist/listbox/ListboxOption.svelte +136 -0
- package/dist/listbox/ListboxOption.svelte.d.ts +50 -0
- package/dist/listbox/ListboxOptions.svelte +269 -0
- package/dist/listbox/ListboxOptions.svelte.d.ts +55 -0
- package/dist/listbox/ListboxSelectedOption.svelte +35 -0
- package/dist/listbox/ListboxSelectedOption.svelte.d.ts +40 -0
- package/dist/listbox/index.d.ts +5 -0
- package/dist/listbox/index.js +5 -0
- package/dist/menu/Menu.svelte +235 -0
- package/dist/menu/Menu.svelte.d.ts +42 -0
- package/dist/menu/MenuButton.svelte +127 -0
- package/dist/menu/MenuButton.svelte.d.ts +52 -0
- package/dist/menu/MenuHeading.svelte +19 -0
- package/dist/menu/MenuHeading.svelte.d.ts +39 -0
- package/dist/menu/MenuItem.svelte +114 -0
- package/dist/menu/MenuItem.svelte.d.ts +49 -0
- package/dist/menu/MenuItems.svelte +244 -0
- package/dist/menu/MenuItems.svelte.d.ts +55 -0
- package/dist/menu/MenuSection.svelte +14 -0
- package/dist/menu/MenuSection.svelte.d.ts +35 -0
- package/dist/menu/MenuSeparator.svelte +9 -0
- package/dist/menu/MenuSeparator.svelte.d.ts +35 -0
- package/dist/menu/context.svelte.d.ts +47 -0
- package/dist/menu/context.svelte.js +21 -0
- package/dist/menu/index.d.ts +7 -0
- package/dist/menu/index.js +7 -0
- package/dist/portal/InternalPortal.svelte +97 -0
- package/dist/portal/InternalPortal.svelte.d.ts +43 -0
- package/dist/portal/Portal.svelte +7 -0
- package/dist/portal/Portal.svelte.d.ts +23 -0
- package/dist/portal/PortalGroup.svelte +14 -0
- package/dist/portal/PortalGroup.svelte.d.ts +40 -0
- package/dist/switch/Switch.svelte +143 -0
- package/dist/switch/Switch.svelte.d.ts +61 -0
- package/dist/switch/SwitchGroup.svelte +37 -0
- package/dist/switch/SwitchGroup.svelte.d.ts +34 -0
- package/dist/switch/index.d.ts +2 -0
- package/dist/switch/index.js +2 -0
- package/dist/tabs/Tab.svelte +156 -0
- package/dist/tabs/Tab.svelte.d.ts +48 -0
- package/dist/tabs/TabGroup.svelte +241 -0
- package/dist/tabs/TabGroup.svelte.d.ts +67 -0
- package/dist/tabs/TabList.svelte +16 -0
- package/dist/tabs/TabList.svelte.d.ts +35 -0
- package/dist/tabs/TabPanel.svelte +61 -0
- package/dist/tabs/TabPanel.svelte.d.ts +47 -0
- package/dist/tabs/TabPanels.svelte +12 -0
- package/dist/tabs/TabPanels.svelte.d.ts +34 -0
- package/dist/tabs/index.d.ts +5 -0
- package/dist/tabs/index.js +5 -0
- package/dist/test-utils/accessability-assertions.d.ts +271 -0
- package/dist/test-utils/accessability-assertions.js +1572 -0
- package/dist/test-utils/fake-pointer.d.ts +24 -0
- package/dist/test-utils/fake-pointer.js +48 -0
- package/dist/test-utils/interactions.d.ts +61 -0
- package/dist/test-utils/interactions.js +453 -0
- package/dist/test-utils/suppress-console-logs.d.ts +7 -0
- package/dist/test-utils/suppress-console-logs.js +17 -0
- package/dist/transition/InternalTransitionChild.svelte +178 -0
- package/dist/transition/InternalTransitionChild.svelte.d.ts +55 -0
- package/dist/transition/Transition.svelte +89 -0
- package/dist/transition/Transition.svelte.d.ts +42 -0
- package/dist/transition/TransitionChild.svelte +16 -0
- package/dist/transition/TransitionChild.svelte.d.ts +44 -0
- package/dist/transition/context.svelte.d.ts +64 -0
- package/dist/transition/context.svelte.js +120 -0
- package/dist/transition/index.d.ts +2 -0
- package/dist/transition/index.js +2 -0
- package/dist/utils/ElementOrComponent.svelte +26 -0
- package/dist/utils/ElementOrComponent.svelte.d.ts +56 -0
- package/dist/utils/Generic.svelte +44 -0
- package/dist/utils/Generic.svelte.d.ts +35 -0
- package/dist/utils/StableCollection.svelte +43 -0
- package/dist/utils/StableCollection.svelte.d.ts +22 -0
- package/dist/utils/active-element-history.d.ts +1 -0
- package/dist/utils/active-element-history.js +35 -0
- package/dist/utils/alternative-types.d.ts +21 -0
- package/dist/utils/alternative-types.js +1 -0
- package/dist/utils/calculate-active-index.d.ts +25 -0
- package/dist/utils/calculate-active-index.js +74 -0
- package/dist/utils/class-names.d.ts +1 -0
- package/dist/utils/class-names.js +10 -0
- package/dist/utils/default-map.d.ts +5 -0
- package/dist/utils/default-map.js +15 -0
- package/dist/utils/disposables.d.ts +14 -12
- package/dist/utils/disposables.js +13 -10
- package/dist/utils/dom.d.ts +0 -2
- package/dist/utils/dom.js +2 -4
- package/dist/utils/env.d.ts +17 -0
- package/dist/utils/env.js +39 -0
- package/dist/utils/focus-management.d.ts +45 -0
- package/dist/utils/focus-management.js +242 -0
- package/dist/utils/focusVisible.svelte.d.ts +3 -3
- package/dist/utils/focusVisible.svelte.js +52 -41
- package/dist/utils/get-text-value.d.ts +1 -0
- package/dist/utils/get-text-value.js +71 -0
- package/dist/utils/id.d.ts +1 -1
- package/dist/utils/match.d.ts +1 -0
- package/dist/utils/match.js +13 -0
- package/dist/utils/on-document-ready.d.ts +1 -0
- package/dist/utils/on-document-ready.js +12 -0
- package/dist/utils/once.d.ts +1 -0
- package/dist/utils/once.js +9 -0
- package/dist/utils/owner.d.ts +1 -0
- package/dist/utils/owner.js +8 -0
- package/dist/utils/platform.d.ts +2 -0
- package/dist/utils/platform.js +17 -0
- package/dist/utils/ref.svelte.d.ts +4 -0
- package/dist/utils/ref.svelte.js +4 -0
- package/dist/utils/render.d.ts +34 -0
- package/dist/utils/render.js +119 -0
- package/dist/utils/state.d.ts +7 -1
- package/dist/utils/state.js +10 -6
- package/dist/utils/store.d.ts +11 -0
- package/dist/utils/store.js +20 -0
- package/dist/utils/types.d.ts +24 -0
- package/dist/utils/types.js +1 -0
- package/package.json +33 -25
- package/dist/actions/activePress.svelte.d.ts +0 -8
- package/dist/actions/focusRing.svelte.d.ts +0 -9
- package/dist/actions/focusRing.svelte.js +0 -34
- package/dist/utils/disabled.d.ts +0 -3
- package/dist/utils/disabled.js +0 -2
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useWindowEvent } from "./use-window-event.svelte.js";
|
|
2
|
+
export var Direction;
|
|
3
|
+
(function (Direction) {
|
|
4
|
+
Direction[Direction["Forwards"] = 0] = "Forwards";
|
|
5
|
+
Direction[Direction["Backwards"] = 1] = "Backwards";
|
|
6
|
+
})(Direction || (Direction = {}));
|
|
7
|
+
export function useTabDirection() {
|
|
8
|
+
let direction = $state(Direction.Forwards);
|
|
9
|
+
let enabled = true;
|
|
10
|
+
useWindowEvent({
|
|
11
|
+
enabled,
|
|
12
|
+
type: "keydown",
|
|
13
|
+
listener: (event) => {
|
|
14
|
+
if (event.key === "Tab") {
|
|
15
|
+
direction = event.shiftKey ? Direction.Backwards : Direction.Forwards;
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
options: true,
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
get current() {
|
|
22
|
+
return direction;
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -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,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,253 @@
|
|
|
1
|
+
import { disposables, useDisposables } from "../utils/disposables.js";
|
|
2
|
+
import { once } from "../utils/once.js";
|
|
3
|
+
import { untrack } from "svelte";
|
|
4
|
+
/**
|
|
5
|
+
* ```
|
|
6
|
+
* ┌──────┐ │ ┌──────────────┐
|
|
7
|
+
* │Closed│ │ │Closed │
|
|
8
|
+
* └──────┘ │ └──────────────┘
|
|
9
|
+
* ┌──────┐┌──────┐┌──────┐│┌──────┐┌──────┐┌──────┐
|
|
10
|
+
* │Frame ││Frame ││Frame │││Frame ││Frame ││Frame │
|
|
11
|
+
* └──────┘└──────┘└──────┘│└──────┘└──────┘└──────┘
|
|
12
|
+
* ┌──────────────────────┐│┌──────────────────────┐
|
|
13
|
+
* │Enter │││Leave │
|
|
14
|
+
* └──────────────────────┘│└──────────────────────┘
|
|
15
|
+
* ┌──────────────────────┐│┌──────────────────────┐
|
|
16
|
+
* │Transition │││Transition │
|
|
17
|
+
* ├──────────────────────┘│└──────────────────────┘
|
|
18
|
+
* │
|
|
19
|
+
* └─ Applied when `Enter` or `Leave` is applied.
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
var TransitionState;
|
|
23
|
+
(function (TransitionState) {
|
|
24
|
+
TransitionState[TransitionState["None"] = 0] = "None";
|
|
25
|
+
TransitionState[TransitionState["Closed"] = 1] = "Closed";
|
|
26
|
+
TransitionState[TransitionState["Enter"] = 2] = "Enter";
|
|
27
|
+
TransitionState[TransitionState["Leave"] = 4] = "Leave";
|
|
28
|
+
})(TransitionState || (TransitionState = {}));
|
|
29
|
+
export function transitionDataAttributes(data) {
|
|
30
|
+
const attributes = {};
|
|
31
|
+
for (const key in data) {
|
|
32
|
+
if (data[key] === true) {
|
|
33
|
+
attributes[`data-${key}`] = "";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return attributes;
|
|
37
|
+
}
|
|
38
|
+
export function useTransition(options) {
|
|
39
|
+
const { enabled, element, show, events } = $derived(options);
|
|
40
|
+
let visible = $state(show);
|
|
41
|
+
let flags = $state(enabled && visible ? TransitionState.Enter | TransitionState.Closed : TransitionState.None);
|
|
42
|
+
let inFlight = $state(false);
|
|
43
|
+
let cancelled = $state(false);
|
|
44
|
+
const d = useDisposables();
|
|
45
|
+
function retry(enabled, show, node, d) {
|
|
46
|
+
if (!enabled)
|
|
47
|
+
return;
|
|
48
|
+
if (show) {
|
|
49
|
+
visible = true;
|
|
50
|
+
}
|
|
51
|
+
if (!node) {
|
|
52
|
+
// Retry if the DOM node isn't available yet
|
|
53
|
+
if (show) {
|
|
54
|
+
flags |= TransitionState.Enter | TransitionState.Closed;
|
|
55
|
+
return d.nextFrame(() => retry(enabled, show, node, d));
|
|
56
|
+
}
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
events?.start?.(show);
|
|
60
|
+
return transition(node, {
|
|
61
|
+
inFlight,
|
|
62
|
+
prepare() {
|
|
63
|
+
if (cancelled) {
|
|
64
|
+
// Cancelled a cancellation, we're back to the original state.
|
|
65
|
+
cancelled = false;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// If we were already in-flight, then we want to cancel the current
|
|
69
|
+
// transition.
|
|
70
|
+
cancelled = inFlight;
|
|
71
|
+
}
|
|
72
|
+
inFlight = true;
|
|
73
|
+
if (cancelled)
|
|
74
|
+
return;
|
|
75
|
+
if (show) {
|
|
76
|
+
flags = TransitionState.Enter | TransitionState.Closed;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
flags = TransitionState.Leave | (flags & TransitionState.Closed);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
run() {
|
|
83
|
+
if (cancelled) {
|
|
84
|
+
// If we cancelled a transition, then the `show` state is going to
|
|
85
|
+
// be inverted already, but that doesn't mean we have to go to that
|
|
86
|
+
// new state.
|
|
87
|
+
//
|
|
88
|
+
// What we actually want is to revert to the "idle" state (the
|
|
89
|
+
// stable state where an `Enter` transitions to, and a `Leave`
|
|
90
|
+
// transitions from.)
|
|
91
|
+
//
|
|
92
|
+
// Because of this, it might look like we are swapping the flags in
|
|
93
|
+
// the following branches, but that's not the case.
|
|
94
|
+
if (!show) {
|
|
95
|
+
flags = TransitionState.Leave | TransitionState.Closed;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
flags = TransitionState.Enter | TransitionState.Closed;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
if (show) {
|
|
103
|
+
flags = flags & ~TransitionState.Closed;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
flags |= TransitionState.Closed;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
done() {
|
|
111
|
+
if (cancelled) {
|
|
112
|
+
if (typeof node.getAnimations === "function" && node.getAnimations().length > 0) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
inFlight = false;
|
|
117
|
+
flags = 0;
|
|
118
|
+
if (!show) {
|
|
119
|
+
visible = false;
|
|
120
|
+
}
|
|
121
|
+
events?.end?.(show);
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
$effect(() => {
|
|
126
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
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
|
+
const done = once(_done);
|
|
176
|
+
const 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
|
+
const { transitionDuration, transitionDelay } = getComputedStyle(node);
|
|
181
|
+
const [durationMs, delayMs] = [transitionDuration, transitionDelay].map((value) => {
|
|
182
|
+
const [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
|
+
const totalDuration = durationMs + delayMs;
|
|
192
|
+
if (totalDuration !== 0) {
|
|
193
|
+
if (process.env.NODE_ENV === "test") {
|
|
194
|
+
const dispose = d.setTimeout(() => {
|
|
195
|
+
done();
|
|
196
|
+
dispose();
|
|
197
|
+
}, totalDuration);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
const 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
|
+
const 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
|
+
const 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
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
250
|
+
node.offsetHeight;
|
|
251
|
+
// Reset the transition to what it was before
|
|
252
|
+
node.style.transition = previous;
|
|
253
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type AcceptNode = (node: HTMLElement) => typeof NodeFilter.FILTER_ACCEPT | typeof NodeFilter.FILTER_SKIP | typeof NodeFilter.FILTER_REJECT;
|
|
2
|
+
export declare function useTreeWalker(options: {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
container: HTMLElement | null;
|
|
5
|
+
accept: AcceptNode;
|
|
6
|
+
walk(node: HTMLElement): void;
|
|
7
|
+
}): void;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { getOwnerDocument } from "../utils/owner.js";
|
|
2
|
+
export function useTreeWalker(options) {
|
|
3
|
+
const { enabled, container, accept, walk } = $derived(options);
|
|
4
|
+
$effect(() => {
|
|
5
|
+
if (!container)
|
|
6
|
+
return;
|
|
7
|
+
if (!enabled)
|
|
8
|
+
return;
|
|
9
|
+
const ownerDocument = getOwnerDocument(container);
|
|
10
|
+
if (!ownerDocument)
|
|
11
|
+
return;
|
|
12
|
+
const acceptNode = Object.assign((node) => accept(node), { acceptNode: accept });
|
|
13
|
+
const walker = ownerDocument.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, acceptNode,
|
|
14
|
+
// @ts-expect-error This `false` is a simple small fix for older browsers
|
|
15
|
+
false);
|
|
16
|
+
while (walker.nextNode())
|
|
17
|
+
walk(walker.currentNode);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { untrack } from "svelte";
|
|
2
|
+
export function useWatch(options) {
|
|
3
|
+
const { action, dependencies } = $derived(options);
|
|
4
|
+
let track = [];
|
|
5
|
+
$effect(() => {
|
|
6
|
+
let oldValues = untrack(() => [...track]);
|
|
7
|
+
for (let [idx, value] of dependencies.entries()) {
|
|
8
|
+
if (untrack(() => track[idx]) !== value) {
|
|
9
|
+
// At least 1 item changed
|
|
10
|
+
let returnValue = action(dependencies, oldValues);
|
|
11
|
+
track = dependencies;
|
|
12
|
+
return returnValue;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function useWindowEvent(params) {
|
|
2
|
+
let { enabled, type, listener, options } = $derived(params);
|
|
3
|
+
$effect(() => {
|
|
4
|
+
if (!enabled)
|
|
5
|
+
return;
|
|
6
|
+
function handler(event) {
|
|
7
|
+
listener(event);
|
|
8
|
+
}
|
|
9
|
+
window.addEventListener(type, handler, options);
|
|
10
|
+
return () => window.removeEventListener(type, handler, options);
|
|
11
|
+
});
|
|
12
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
+
export * from "./button/index.js";
|
|
1
2
|
export * from "./checkbox/index.js";
|
|
3
|
+
export * from "./close-button/index.js";
|
|
4
|
+
export * from "./data-interactive/index.js";
|
|
2
5
|
export * from "./description/index.js";
|
|
6
|
+
export * from "./dialog/index.js";
|
|
3
7
|
export * from "./field/index.js";
|
|
4
8
|
export * from "./fieldset/index.js";
|
|
9
|
+
export * from "./input/index.js";
|
|
5
10
|
export * from "./label/index.js";
|
|
6
11
|
export * from "./legend/index.js";
|
|
12
|
+
export * from "./listbox/index.js";
|
|
13
|
+
export * from "./menu/index.js";
|
|
14
|
+
export * from "./switch/index.js";
|
|
15
|
+
export * from "./tabs/index.js";
|
|
16
|
+
export * from "./transition/index.js";
|
|
17
|
+
export * from "./hooks/use-id.js";
|
|
18
|
+
export * from "./utils/types.js";
|
|
19
|
+
export { mergeProps } from "./utils/render.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
+
export * from "./button/index.js";
|
|
1
2
|
export * from "./checkbox/index.js";
|
|
3
|
+
export * from "./close-button/index.js";
|
|
4
|
+
export * from "./data-interactive/index.js";
|
|
2
5
|
export * from "./description/index.js";
|
|
6
|
+
export * from "./dialog/index.js";
|
|
3
7
|
export * from "./field/index.js";
|
|
4
8
|
export * from "./fieldset/index.js";
|
|
9
|
+
export * from "./input/index.js";
|
|
5
10
|
export * from "./label/index.js";
|
|
6
11
|
export * from "./legend/index.js";
|
|
12
|
+
export * from "./listbox/index.js";
|
|
13
|
+
export * from "./menu/index.js";
|
|
14
|
+
export * from "./switch/index.js";
|
|
15
|
+
export * from "./tabs/index.js";
|
|
16
|
+
export * from "./transition/index.js";
|
|
17
|
+
export * from "./hooks/use-id.js";
|
|
18
|
+
export * from "./utils/types.js";
|
|
19
|
+
export { mergeProps } from "./utils/render.js";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script lang="ts" module>const DEFAULT_INPUT_TAG = "input";
|
|
2
|
+
</script>
|
|
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 "../internal/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?.value || `headlessui-input-${internalId}`,
|
|
20
|
+
disabled: theirDisabled = false,
|
|
21
|
+
autofocus = false,
|
|
22
|
+
invalid = false,
|
|
23
|
+
...theirProps
|
|
24
|
+
} = $props();
|
|
25
|
+
const disabled = $derived(providedDisabled?.value ?? 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(
|
|
44
|
+
{
|
|
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
|
|
54
|
+
)
|
|
55
|
+
);
|
|
56
|
+
const slot = $derived({ disabled, invalid, hover, focus, autofocus });
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<ElementOrComponent {ourProps} {theirProps} {slot} defaultTag={DEFAULT_INPUT_TAG} name="Input" bind:ref bind:value />
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ElementType, Props } from "../utils/types.js";
|
|
2
|
+
declare const DEFAULT_INPUT_TAG: "input";
|
|
3
|
+
type InputRenderPropArg = {
|
|
4
|
+
disabled: boolean;
|
|
5
|
+
hover: boolean;
|
|
6
|
+
focus: boolean;
|
|
7
|
+
autofocus: boolean;
|
|
8
|
+
invalid: boolean;
|
|
9
|
+
};
|
|
10
|
+
type InputPropsWeControl = "aria-labelledby" | "aria-describedby";
|
|
11
|
+
export type InputProps<TTag extends ElementType = typeof DEFAULT_INPUT_TAG, TValue = string> = Props<TTag, InputRenderPropArg, InputPropsWeControl, {
|
|
12
|
+
id?: string;
|
|
13
|
+
value?: TValue;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
invalid?: boolean;
|
|
16
|
+
autofocus?: boolean;
|
|
17
|
+
}>;
|
|
18
|
+
declare class __sveltets_Render<TTag extends ElementType = typeof DEFAULT_INPUT_TAG, TValue = string> {
|
|
19
|
+
props(): {
|
|
20
|
+
as?: TTag | undefined;
|
|
21
|
+
value?: TValue | undefined;
|
|
22
|
+
} & (Exclude<keyof import("../utils/types.js").PropsOf<TTag>, ("as" | "children" | "refName" | "class") | "invalid" | "disabled" | "autofocus" | "value" | "id" | InputPropsWeControl> extends infer T extends keyof import("../utils/types.js").PropsOf<TTag> ? { [P in T]: import("../utils/types.js").PropsOf<TTag>[P]; } : never) & {
|
|
23
|
+
children?: import("../utils/types.js").Children<InputRenderPropArg> | undefined;
|
|
24
|
+
ref?: HTMLElement;
|
|
25
|
+
} & (true extends (import("../utils/types.js").PropsOf<TTag> extends infer T_1 ? T_1 extends import("../utils/types.js").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) ? {
|
|
26
|
+
class?: import("../utils/types.js").PropsOf<TTag>["class"] | ((bag: InputRenderPropArg) => string) | undefined;
|
|
27
|
+
} : {}) & {
|
|
28
|
+
id?: string;
|
|
29
|
+
value?: TValue | undefined;
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
invalid?: boolean;
|
|
32
|
+
autofocus?: boolean;
|
|
33
|
+
};
|
|
34
|
+
events(): {} & {
|
|
35
|
+
[evt: string]: CustomEvent<any>;
|
|
36
|
+
};
|
|
37
|
+
slots(): {};
|
|
38
|
+
bindings(): "ref" | "value";
|
|
39
|
+
exports(): {};
|
|
40
|
+
}
|
|
41
|
+
interface $$IsomorphicComponent {
|
|
42
|
+
new <TTag extends ElementType = typeof DEFAULT_INPUT_TAG, TValue = string>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TTag, TValue>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TTag, TValue>['props']>, ReturnType<__sveltets_Render<TTag, TValue>['events']>, ReturnType<__sveltets_Render<TTag, TValue>['slots']>> & {
|
|
43
|
+
$$bindings?: ReturnType<__sveltets_Render<TTag, TValue>['bindings']>;
|
|
44
|
+
} & ReturnType<__sveltets_Render<TTag, TValue>['exports']>;
|
|
45
|
+
<TTag extends ElementType = typeof DEFAULT_INPUT_TAG, TValue = string>(internal: unknown, props: ReturnType<__sveltets_Render<TTag, TValue>['props']> & {
|
|
46
|
+
$$events?: ReturnType<__sveltets_Render<TTag, TValue>['events']>;
|
|
47
|
+
}): ReturnType<__sveltets_Render<TTag, TValue>['exports']>;
|
|
48
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any, any>['bindings']>;
|
|
49
|
+
}
|
|
50
|
+
declare const Input: $$IsomorphicComponent;
|
|
51
|
+
type Input<TTag extends ElementType = typeof DEFAULT_INPUT_TAG, TValue = string> = InstanceType<typeof Input<TTag, TValue>>;
|
|
52
|
+
export default Input;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Input, type InputProps } from "./Input.svelte";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Input } from "./Input.svelte";
|
|
@@ -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,20 @@
|
|
|
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
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const FocusSentinel: $$__sveltets_2_IsomorphicComponent<{
|
|
15
|
+
onfocus: () => boolean;
|
|
16
|
+
}, {
|
|
17
|
+
[evt: string]: CustomEvent<any>;
|
|
18
|
+
}, {}, {}, "">;
|
|
19
|
+
type FocusSentinel = InstanceType<typeof FocusSentinel>;
|
|
20
|
+
export default FocusSentinel;
|