svelte-ag 0.0.2-dev.72
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/README.md +6 -0
- package/dist/app.css +209 -0
- package/dist/app.d.ts +13 -0
- package/dist/app.html +12 -0
- package/dist/icons.css +6 -0
- package/dist/lib/bits/internal/arrays.d.ts +95 -0
- package/dist/lib/bits/internal/arrays.js +250 -0
- package/dist/lib/bits/internal/arrays.test.d.ts +1 -0
- package/dist/lib/bits/internal/arrays.test.js +366 -0
- package/dist/lib/bits/internal/attrs.d.ts +22 -0
- package/dist/lib/bits/internal/attrs.js +69 -0
- package/dist/lib/bits/internal/box-auto-reset.svelte.d.ts +8 -0
- package/dist/lib/bits/internal/box-auto-reset.svelte.js +31 -0
- package/dist/lib/bits/internal/box.svelte.d.ts +21 -0
- package/dist/lib/bits/internal/box.svelte.js +26 -0
- package/dist/lib/bits/internal/clamp.d.ts +4 -0
- package/dist/lib/bits/internal/clamp.js +6 -0
- package/dist/lib/bits/internal/clamp.test.d.ts +1 -0
- package/dist/lib/bits/internal/clamp.test.js +31 -0
- package/dist/lib/bits/internal/create-event-hook.svelte.d.ts +18 -0
- package/dist/lib/bits/internal/create-event-hook.svelte.js +29 -0
- package/dist/lib/bits/internal/create-shared-hook.svelte.d.ts +2 -0
- package/dist/lib/bits/internal/create-shared-hook.svelte.js +27 -0
- package/dist/lib/bits/internal/date-time/announcer.d.ts +7 -0
- package/dist/lib/bits/internal/date-time/announcer.js +82 -0
- package/dist/lib/bits/internal/date-time/calendar-helpers.svelte.d.ts +201 -0
- package/dist/lib/bits/internal/date-time/calendar-helpers.svelte.js +510 -0
- package/dist/lib/bits/internal/date-time/field/helpers.d.ts +76 -0
- package/dist/lib/bits/internal/date-time/field/helpers.js +378 -0
- package/dist/lib/bits/internal/date-time/field/parts.d.ts +6 -0
- package/dist/lib/bits/internal/date-time/field/parts.js +9 -0
- package/dist/lib/bits/internal/date-time/field/segments.d.ts +51 -0
- package/dist/lib/bits/internal/date-time/field/segments.js +128 -0
- package/dist/lib/bits/internal/date-time/field/types.d.ts +25 -0
- package/dist/lib/bits/internal/date-time/field/types.js +1 -0
- package/dist/lib/bits/internal/date-time/formatter.d.ts +24 -0
- package/dist/lib/bits/internal/date-time/formatter.js +97 -0
- package/dist/lib/bits/internal/date-time/placeholders.d.ts +8 -0
- package/dist/lib/bits/internal/date-time/placeholders.js +129 -0
- package/dist/lib/bits/internal/date-time/utils.d.ts +69 -0
- package/dist/lib/bits/internal/date-time/utils.js +212 -0
- package/dist/lib/bits/internal/debounce.d.ts +4 -0
- package/dist/lib/bits/internal/debounce.js +19 -0
- package/dist/lib/bits/internal/debounce.test.d.ts +1 -0
- package/dist/lib/bits/internal/debounce.test.js +50 -0
- package/dist/lib/bits/internal/dom.d.ts +10 -0
- package/dist/lib/bits/internal/dom.js +38 -0
- package/dist/lib/bits/internal/elements.d.ts +2 -0
- package/dist/lib/bits/internal/elements.js +6 -0
- package/dist/lib/bits/internal/events.d.ts +21 -0
- package/dist/lib/bits/internal/events.js +49 -0
- package/dist/lib/bits/internal/floating-svelte/floating-utils.svelte.d.ts +7 -0
- package/dist/lib/bits/internal/floating-svelte/floating-utils.svelte.js +24 -0
- package/dist/lib/bits/internal/floating-svelte/types.d.ts +85 -0
- package/dist/lib/bits/internal/floating-svelte/types.js +1 -0
- package/dist/lib/bits/internal/floating-svelte/use-floating.svelte.d.ts +2 -0
- package/dist/lib/bits/internal/floating-svelte/use-floating.svelte.js +112 -0
- package/dist/lib/bits/internal/focus.d.ts +46 -0
- package/dist/lib/bits/internal/focus.js +109 -0
- package/dist/lib/bits/internal/get-directional-keys.d.ts +21 -0
- package/dist/lib/bits/internal/get-directional-keys.js +37 -0
- package/dist/lib/bits/internal/get-directional-keys.test.d.ts +1 -0
- package/dist/lib/bits/internal/get-directional-keys.test.js +46 -0
- package/dist/lib/bits/internal/is.d.ts +25 -0
- package/dist/lib/bits/internal/is.js +62 -0
- package/dist/lib/bits/internal/is.test.d.ts +1 -0
- package/dist/lib/bits/internal/is.test.js +34 -0
- package/dist/lib/bits/internal/kbd-constants.d.ts +40 -0
- package/dist/lib/bits/internal/kbd-constants.js +40 -0
- package/dist/lib/bits/internal/kbd.d.ts +1 -0
- package/dist/lib/bits/internal/kbd.js +1 -0
- package/dist/lib/bits/internal/locale.d.ts +6 -0
- package/dist/lib/bits/internal/locale.js +9 -0
- package/dist/lib/bits/internal/math.d.ts +5 -0
- package/dist/lib/bits/internal/math.js +43 -0
- package/dist/lib/bits/internal/math.test.d.ts +1 -0
- package/dist/lib/bits/internal/math.test.js +71 -0
- package/dist/lib/bits/internal/noop.d.ts +4 -0
- package/dist/lib/bits/internal/noop.js +4 -0
- package/dist/lib/bits/internal/should-trap-focus.d.ts +6 -0
- package/dist/lib/bits/internal/should-trap-focus.js +6 -0
- package/dist/lib/bits/internal/sleep.d.ts +1 -0
- package/dist/lib/bits/internal/sleep.js +3 -0
- package/dist/lib/bits/internal/tabbable.d.ts +10 -0
- package/dist/lib/bits/internal/tabbable.js +66 -0
- package/dist/lib/bits/internal/types.d.ts +92 -0
- package/dist/lib/bits/internal/types.js +1 -0
- package/dist/lib/bits/internal/use-after-animations.svelte.d.ts +5 -0
- package/dist/lib/bits/internal/use-after-animations.svelte.js +27 -0
- package/dist/lib/bits/internal/use-arrow-navigation.d.ts +62 -0
- package/dist/lib/bits/internal/use-arrow-navigation.js +76 -0
- package/dist/lib/bits/internal/use-body-scroll-lock.svelte.d.ts +6 -0
- package/dist/lib/bits/internal/use-body-scroll-lock.svelte.js +106 -0
- package/dist/lib/bits/internal/use-data-typeahead.svelte.d.ts +14 -0
- package/dist/lib/bits/internal/use-data-typeahead.svelte.js +31 -0
- package/dist/lib/bits/internal/use-dom-typeahead.svelte.d.ts +11 -0
- package/dist/lib/bits/internal/use-dom-typeahead.svelte.js +30 -0
- package/dist/lib/bits/internal/use-form-control.svelte.d.ts +4 -0
- package/dist/lib/bits/internal/use-form-control.svelte.js +16 -0
- package/dist/lib/bits/internal/use-grace-area.svelte.d.ts +12 -0
- package/dist/lib/bits/internal/use-grace-area.svelte.js +197 -0
- package/dist/lib/bits/internal/use-id.d.ts +4 -0
- package/dist/lib/bits/internal/use-id.js +8 -0
- package/dist/lib/bits/internal/use-resize-observer.svelte.d.ts +2 -0
- package/dist/lib/bits/internal/use-resize-observer.svelte.js +17 -0
- package/dist/lib/bits/internal/use-roving-focus.svelte.d.ts +38 -0
- package/dist/lib/bits/internal/use-roving-focus.svelte.js +91 -0
- package/dist/lib/bits/internal/use-size.svelte.d.ts +7 -0
- package/dist/lib/bits/internal/use-size.svelte.js +54 -0
- package/dist/lib/bits/internal/use-state-machine.svelte.d.ts +24 -0
- package/dist/lib/bits/internal/use-state-machine.svelte.js +28 -0
- package/dist/lib/bits/internal/use-timeout-fn.svelte.d.ts +25 -0
- package/dist/lib/bits/internal/use-timeout-fn.svelte.js +39 -0
- package/dist/lib/components/Typeahead.svelte.d.ts +47 -0
- package/dist/lib/components/Typeahead.svelte.js +150 -0
- package/dist/lib/components/animated/animated.svelte +244 -0
- package/dist/lib/components/animated/animated.svelte.d.ts +61 -0
- package/dist/lib/components/animated/index.d.ts +2 -0
- package/dist/lib/components/animated/index.js +2 -0
- package/dist/lib/components/combo/combo.svelte +186 -0
- package/dist/lib/components/combo/combo.svelte.d.ts +21 -0
- package/dist/lib/components/combo/index.d.ts +2 -0
- package/dist/lib/components/combo/index.js +2 -0
- package/dist/lib/components/dnd/Droppable.svelte +25 -0
- package/dist/lib/components/dnd/Droppable.svelte.d.ts +10 -0
- package/dist/lib/components/dnd/context.svelte.d.ts +22 -0
- package/dist/lib/components/dnd/context.svelte.js +25 -0
- package/dist/lib/components/dnd/dnd-context.svelte +45 -0
- package/dist/lib/components/dnd/dnd-context.svelte.d.ts +30 -0
- package/dist/lib/components/dnd/dnd-drag-overlay.svelte +44 -0
- package/dist/lib/components/dnd/dnd-drag-overlay.svelte.d.ts +27 -0
- package/dist/lib/components/dnd/dnd-drag-placeholder.svelte +24 -0
- package/dist/lib/components/dnd/dnd-drag-placeholder.svelte.d.ts +9 -0
- package/dist/lib/components/dnd/dnd-draghandle.svelte +30 -0
- package/dist/lib/components/dnd/dnd-draghandle.svelte.d.ts +6 -0
- package/dist/lib/components/dnd/dnd-overlay.svelte +0 -0
- package/dist/lib/components/dnd/dnd-overlay.svelte.d.ts +26 -0
- package/dist/lib/components/dnd/dnd-sortable-context.svelte +18 -0
- package/dist/lib/components/dnd/dnd-sortable-context.svelte.d.ts +8 -0
- package/dist/lib/components/dnd/dnd-sortable-item.svelte +68 -0
- package/dist/lib/components/dnd/dnd-sortable-item.svelte.d.ts +23 -0
- package/dist/lib/components/dnd/example.svelte +109 -0
- package/dist/lib/components/dnd/example.svelte.d.ts +3 -0
- package/dist/lib/components/dnd/exports.d.ts +9 -0
- package/dist/lib/components/dnd/exports.js +9 -0
- package/dist/lib/components/dnd/index.d.ts +1 -0
- package/dist/lib/components/dnd/index.js +1 -0
- package/dist/lib/components/dnd/sortable.svelte.d.ts +13 -0
- package/dist/lib/components/dnd/sortable.svelte.js +70 -0
- package/dist/lib/components/dnd/utils.svelte.d.ts +20 -0
- package/dist/lib/components/dnd/utils.svelte.js +20 -0
- package/dist/lib/components/search/combinations/searchPopover.svelte +68 -0
- package/dist/lib/components/search/combinations/searchPopover.svelte.d.ts +22 -0
- package/dist/lib/components/search/components/search-empty.svelte +28 -0
- package/dist/lib/components/search/components/search-empty.svelte.d.ts +4 -0
- package/dist/lib/components/search/components/search-input.svelte +53 -0
- package/dist/lib/components/search/components/search-input.svelte.d.ts +4 -0
- package/dist/lib/components/search/components/search-list.svelte +46 -0
- package/dist/lib/components/search/components/search-list.svelte.d.ts +4 -0
- package/dist/lib/components/search/components/search-pagnation.svelte +68 -0
- package/dist/lib/components/search/components/search-pagnation.svelte.d.ts +8 -0
- package/dist/lib/components/search/components/search.svelte +47 -0
- package/dist/lib/components/search/components/search.svelte.d.ts +4 -0
- package/dist/lib/components/search/exports.d.ts +6 -0
- package/dist/lib/components/search/exports.js +5 -0
- package/dist/lib/components/search/index.d.ts +2 -0
- package/dist/lib/components/search/index.js +2 -0
- package/dist/lib/components/search/search.svelte.d.ts +102 -0
- package/dist/lib/components/search/search.svelte.js +202 -0
- package/dist/lib/components/search/types.d.ts +28 -0
- package/dist/lib/components/search/types.js +1 -0
- package/dist/lib/components/utilities/arrow/arrow.svelte +23 -0
- package/dist/lib/components/utilities/arrow/arrow.svelte.d.ts +3 -0
- package/dist/lib/components/utilities/arrow/index.d.ts +2 -0
- package/dist/lib/components/utilities/arrow/index.js +1 -0
- package/dist/lib/components/utilities/arrow/types.d.ts +17 -0
- package/dist/lib/components/utilities/arrow/types.js +1 -0
- package/dist/lib/components/utilities/floating-layer/components/floating-layer-anchor.svelte +15 -0
- package/dist/lib/components/utilities/floating-layer/components/floating-layer-anchor.svelte.d.ts +4 -0
- package/dist/lib/components/utilities/floating-layer/components/floating-layer-arrow.svelte +20 -0
- package/dist/lib/components/utilities/floating-layer/components/floating-layer-arrow.svelte.d.ts +3 -0
- package/dist/lib/components/utilities/floating-layer/components/floating-layer-content-static.svelte +19 -0
- package/dist/lib/components/utilities/floating-layer/components/floating-layer-content-static.svelte.d.ts +13 -0
- package/dist/lib/components/utilities/floating-layer/components/floating-layer-content.svelte +61 -0
- package/dist/lib/components/utilities/floating-layer/components/floating-layer-content.svelte.d.ts +4 -0
- package/dist/lib/components/utilities/floating-layer/components/floating-layer.svelte +10 -0
- package/dist/lib/components/utilities/floating-layer/components/floating-layer.svelte.d.ts +7 -0
- package/dist/lib/components/utilities/floating-layer/components/index.d.ts +6 -0
- package/dist/lib/components/utilities/floating-layer/components/index.js +5 -0
- package/dist/lib/components/utilities/floating-layer/index.d.ts +1 -0
- package/dist/lib/components/utilities/floating-layer/index.js +1 -0
- package/dist/lib/components/utilities/floating-layer/types.d.ts +115 -0
- package/dist/lib/components/utilities/floating-layer/types.js +1 -0
- package/dist/lib/components/utilities/floating-layer/use-floating-layer.svelte.d.ts +118 -0
- package/dist/lib/components/utilities/floating-layer/use-floating-layer.svelte.js +311 -0
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.js +1 -0
- package/dist/lib/utils/asyncDerived.svelte.d.ts +12 -0
- package/dist/lib/utils/asyncDerived.svelte.js +26 -0
- package/dist/lib/utils/bits.d.ts +39 -0
- package/dist/lib/utils/bits.js +69 -0
- package/dist/lib/utils/index.d.ts +3 -0
- package/dist/lib/utils/index.js +3 -0
- package/dist/lib/utils/utils.d.ts +21 -0
- package/dist/lib/utils/utils.js +72 -0
- package/dist/routes/+layout.svelte +0 -0
- package/dist/routes/+layout.svelte.d.ts +26 -0
- package/package.json +79 -0
- package/src/app.css +209 -0
- package/src/app.d.ts +13 -0
- package/src/app.html +12 -0
- package/src/icons.css +6 -0
- package/src/lib/bits/internal/arrays.test.ts +460 -0
- package/src/lib/bits/internal/arrays.ts +301 -0
- package/src/lib/bits/internal/attrs.ts +97 -0
- package/src/lib/bits/internal/box-auto-reset.svelte.ts +40 -0
- package/src/lib/bits/internal/box.svelte.ts +60 -0
- package/src/lib/bits/internal/clamp.test.ts +37 -0
- package/src/lib/bits/internal/clamp.ts +6 -0
- package/src/lib/bits/internal/create-event-hook.svelte.ts +64 -0
- package/src/lib/bits/internal/create-shared-hook.svelte.ts +33 -0
- package/src/lib/bits/internal/date-time/announcer.ts +88 -0
- package/src/lib/bits/internal/date-time/calendar-helpers.svelte.ts +815 -0
- package/src/lib/bits/internal/date-time/field/helpers.ts +441 -0
- package/src/lib/bits/internal/date-time/field/parts.ts +9 -0
- package/src/lib/bits/internal/date-time/field/segments.ts +126 -0
- package/src/lib/bits/internal/date-time/field/types.ts +35 -0
- package/src/lib/bits/internal/date-time/formatter.ts +116 -0
- package/src/lib/bits/internal/date-time/placeholders.ts +143 -0
- package/src/lib/bits/internal/date-time/utils.ts +261 -0
- package/src/lib/bits/internal/debounce.test.ts +67 -0
- package/src/lib/bits/internal/debounce.ts +22 -0
- package/src/lib/bits/internal/dom.ts +47 -0
- package/src/lib/bits/internal/elements.ts +7 -0
- package/src/lib/bits/internal/events.ts +89 -0
- package/src/lib/bits/internal/floating-svelte/floating-utils.svelte.ts +28 -0
- package/src/lib/bits/internal/floating-svelte/types.ts +108 -0
- package/src/lib/bits/internal/floating-svelte/use-floating.svelte.ts +133 -0
- package/src/lib/bits/internal/focus.ts +111 -0
- package/src/lib/bits/internal/get-directional-keys.test.ts +51 -0
- package/src/lib/bits/internal/get-directional-keys.ts +43 -0
- package/src/lib/bits/internal/is.test.ts +40 -0
- package/src/lib/bits/internal/is.ts +78 -0
- package/src/lib/bits/internal/kbd-constants.ts +40 -0
- package/src/lib/bits/internal/kbd.ts +1 -0
- package/src/lib/bits/internal/locale.ts +13 -0
- package/src/lib/bits/internal/math.test.ts +88 -0
- package/src/lib/bits/internal/math.ts +50 -0
- package/src/lib/bits/internal/noop.ts +4 -0
- package/src/lib/bits/internal/should-trap-focus.ts +16 -0
- package/src/lib/bits/internal/sleep.ts +3 -0
- package/src/lib/bits/internal/tabbable.ts +76 -0
- package/src/lib/bits/internal/types.ts +91 -0
- package/src/lib/bits/internal/use-after-animations.svelte.ts +30 -0
- package/src/lib/bits/internal/use-arrow-navigation.ts +168 -0
- package/src/lib/bits/internal/use-body-scroll-lock.svelte.ts +138 -0
- package/src/lib/bits/internal/use-data-typeahead.svelte.ts +44 -0
- package/src/lib/bits/internal/use-dom-typeahead.svelte.ts +44 -0
- package/src/lib/bits/internal/use-form-control.svelte.ts +17 -0
- package/src/lib/bits/internal/use-grace-area.svelte.ts +229 -0
- package/src/lib/bits/internal/use-id.ts +9 -0
- package/src/lib/bits/internal/use-resize-observer.svelte.ts +19 -0
- package/src/lib/bits/internal/use-roving-focus.svelte.ts +141 -0
- package/src/lib/bits/internal/use-size.svelte.ts +60 -0
- package/src/lib/bits/internal/use-state-machine.svelte.ts +46 -0
- package/src/lib/bits/internal/use-timeout-fn.svelte.ts +80 -0
- package/src/lib/components/Typeahead.svelte.ts +200 -0
- package/src/lib/components/animated/animated.svelte +244 -0
- package/src/lib/components/animated/index.ts +3 -0
- package/src/lib/components/combo/combo.svelte +186 -0
- package/src/lib/components/combo/index.ts +3 -0
- package/src/lib/components/dnd/Droppable.svelte +25 -0
- package/src/lib/components/dnd/context.svelte.ts +30 -0
- package/src/lib/components/dnd/dnd-context.svelte +45 -0
- package/src/lib/components/dnd/dnd-drag-overlay.svelte +44 -0
- package/src/lib/components/dnd/dnd-drag-placeholder.svelte +24 -0
- package/src/lib/components/dnd/dnd-draghandle.svelte +30 -0
- package/src/lib/components/dnd/dnd-overlay.svelte +0 -0
- package/src/lib/components/dnd/dnd-sortable-context.svelte +18 -0
- package/src/lib/components/dnd/dnd-sortable-item.svelte +68 -0
- package/src/lib/components/dnd/example.svelte +109 -0
- package/src/lib/components/dnd/exports.ts +12 -0
- package/src/lib/components/dnd/index.ts +1 -0
- package/src/lib/components/dnd/sortable.svelte.ts +82 -0
- package/src/lib/components/dnd/utils.svelte.ts +29 -0
- package/src/lib/components/search/combinations/searchPopover.svelte +68 -0
- package/src/lib/components/search/components/search-empty.svelte +28 -0
- package/src/lib/components/search/components/search-input.svelte +53 -0
- package/src/lib/components/search/components/search-list.svelte +46 -0
- package/src/lib/components/search/components/search-pagnation.svelte +68 -0
- package/src/lib/components/search/components/search.svelte +47 -0
- package/src/lib/components/search/exports.ts +13 -0
- package/src/lib/components/search/index.ts +2 -0
- package/src/lib/components/search/search.svelte.ts +286 -0
- package/src/lib/components/search/types.ts +48 -0
- package/src/lib/components/utilities/arrow/arrow.svelte +23 -0
- package/src/lib/components/utilities/arrow/index.ts +2 -0
- package/src/lib/components/utilities/arrow/types.ts +20 -0
- package/src/lib/components/utilities/floating-layer/components/floating-layer-anchor.svelte +15 -0
- package/src/lib/components/utilities/floating-layer/components/floating-layer-arrow.svelte +20 -0
- package/src/lib/components/utilities/floating-layer/components/floating-layer-content-static.svelte +19 -0
- package/src/lib/components/utilities/floating-layer/components/floating-layer-content.svelte +61 -0
- package/src/lib/components/utilities/floating-layer/components/floating-layer.svelte +10 -0
- package/src/lib/components/utilities/floating-layer/components/index.ts +11 -0
- package/src/lib/components/utilities/floating-layer/index.ts +1 -0
- package/src/lib/components/utilities/floating-layer/types.ts +133 -0
- package/src/lib/components/utilities/floating-layer/use-floating-layer.svelte.ts +406 -0
- package/src/lib/index.ts +1 -0
- package/src/lib/utils/asyncDerived.svelte.ts +38 -0
- package/src/lib/utils/bits.ts +93 -0
- package/src/lib/utils/index.ts +3 -0
- package/src/lib/utils/utils.ts +97 -0
- package/src/routes/+layout.svelte +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const ALT = "Alt";
|
|
2
|
+
export const ARROW_DOWN = "ArrowDown";
|
|
3
|
+
export const ARROW_LEFT = "ArrowLeft";
|
|
4
|
+
export const ARROW_RIGHT = "ArrowRight";
|
|
5
|
+
export const ARROW_UP = "ArrowUp";
|
|
6
|
+
export const BACKSPACE = "Backspace";
|
|
7
|
+
export const CAPS_LOCK = "CapsLock";
|
|
8
|
+
export const CONTROL = "Control";
|
|
9
|
+
export const DELETE = "Delete";
|
|
10
|
+
export const END = "End";
|
|
11
|
+
export const ENTER = "Enter";
|
|
12
|
+
export const ESCAPE = "Escape";
|
|
13
|
+
export const F1 = "F1";
|
|
14
|
+
export const F10 = "F10";
|
|
15
|
+
export const F11 = "F11";
|
|
16
|
+
export const F12 = "F12";
|
|
17
|
+
export const F2 = "F2";
|
|
18
|
+
export const F3 = "F3";
|
|
19
|
+
export const F4 = "F4";
|
|
20
|
+
export const F5 = "F5";
|
|
21
|
+
export const F6 = "F6";
|
|
22
|
+
export const F7 = "F7";
|
|
23
|
+
export const F8 = "F8";
|
|
24
|
+
export const F9 = "F9";
|
|
25
|
+
export const HOME = "Home";
|
|
26
|
+
export const META = "Meta";
|
|
27
|
+
export const PAGE_DOWN = "PageDown";
|
|
28
|
+
export const PAGE_UP = "PageUp";
|
|
29
|
+
export const SHIFT = "Shift";
|
|
30
|
+
export const SPACE = " ";
|
|
31
|
+
export const TAB = "Tab";
|
|
32
|
+
export const CTRL = "Control";
|
|
33
|
+
export const ASTERISK = "*";
|
|
34
|
+
export const a = "a";
|
|
35
|
+
export const P = "P";
|
|
36
|
+
export const A = "A";
|
|
37
|
+
export const p = "p";
|
|
38
|
+
export const n = "n";
|
|
39
|
+
export const j = "j";
|
|
40
|
+
export const k = "k";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * as kbd from "./kbd-constants.js";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// https://github.com/melt-ui/melt-ui
|
|
2
|
+
import type { Direction } from "$lib/shared/index.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Detects the text direction in the element.
|
|
6
|
+
* @returns {Direction} The text direction ('ltr' for left-to-right or 'rtl' for right-to-left).
|
|
7
|
+
*/
|
|
8
|
+
export function getElemDirection(elem: HTMLElement): Direction {
|
|
9
|
+
const style = window.getComputedStyle(elem);
|
|
10
|
+
const direction = style.getPropertyValue("direction");
|
|
11
|
+
|
|
12
|
+
return direction as Direction;
|
|
13
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { linearScale, snapValueToStep } from "./math.js";
|
|
3
|
+
|
|
4
|
+
describe("snapValueToStep", () => {
|
|
5
|
+
it("should snap value to nearest step", () => {
|
|
6
|
+
expect(snapValueToStep(3.7, 0, 10, 1)).toBe(4);
|
|
7
|
+
expect(snapValueToStep(3.2, 0, 10, 1)).toBe(3);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("should handle decimal steps", () => {
|
|
11
|
+
expect(snapValueToStep(3.7, 0, 10, 0.5)).toBe(3.5);
|
|
12
|
+
expect(snapValueToStep(3.8, 0, 10, 0.5)).toBe(4);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("should respect min value", () => {
|
|
16
|
+
expect(snapValueToStep(1.2, 2, 10, 1)).toBe(2);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should respect max value", () => {
|
|
20
|
+
expect(snapValueToStep(9.8, 0, 9, 1)).toBe(9);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should handle NaN min value", () => {
|
|
24
|
+
expect(snapValueToStep(3.7, Number.NaN, 10, 1)).toBe(4);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should handle NaN max value", () => {
|
|
28
|
+
expect(snapValueToStep(3.7, 0, Number.NaN, 1)).toBe(4);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should handle both NaN min and max values", () => {
|
|
32
|
+
expect(snapValueToStep(3.7, Number.NaN, Number.NaN, 1)).toBe(4);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("should handle values outside the range", () => {
|
|
36
|
+
expect(snapValueToStep(12, 0, 10, 1)).toBe(10);
|
|
37
|
+
expect(snapValueToStep(-2, 0, 10, 1)).toBe(0);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("should handle large steps", () => {
|
|
41
|
+
expect(snapValueToStep(17, 0, 100, 20)).toBe(20);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("should maintain precision for decimal steps", () => {
|
|
45
|
+
expect(snapValueToStep(3.14159, 0, 10, 0.01)).toBe(3.14);
|
|
46
|
+
expect(snapValueToStep(3.14159, 0, 10, 0.001)).toBe(3.142);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe("linearScale", () => {
|
|
51
|
+
it("correctly scales the value", () => {
|
|
52
|
+
expect(linearScale([0, 1], [0, 100])(0.5)).toBe(50);
|
|
53
|
+
expect(linearScale([0, 1], [10, 90])(0.5)).toBe(50);
|
|
54
|
+
expect(linearScale([0, 1], [0, 100])(0.33)).toBe(33);
|
|
55
|
+
expect(linearScale([0, 1], [0, 100])(0)).toBe(0);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("is minimum when below minimum", () => {
|
|
59
|
+
expect(linearScale([0, 1], [0, 100])(2)).toBe(100);
|
|
60
|
+
expect(linearScale([0, 1], [0, 100])(-5)).toBe(0);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("correctly handles negative scales", () => {
|
|
64
|
+
expect(linearScale([-1, 1], [0, 100])(0)).toBe(50);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("handles reversed ranges", () => {
|
|
68
|
+
expect(linearScale([0, 1], [100, 0])(0.5)).toBe(50);
|
|
69
|
+
expect(linearScale([0, 1], [100, 0])(0)).toBe(100);
|
|
70
|
+
expect(linearScale([0, 1], [100, 0])(2)).toBe(0); // clamped
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("works with non-zero based domains", () => {
|
|
74
|
+
expect(linearScale([10, 20], [0, 100])(15)).toBe(50);
|
|
75
|
+
expect(linearScale([100, 200], [0, 1])(150)).toBe(0.5);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("handles unclamped values when clamp is false", () => {
|
|
79
|
+
const scale = linearScale([0, 1], [0, 100], false);
|
|
80
|
+
expect(scale(2)).toBe(200);
|
|
81
|
+
expect(scale(-1)).toBe(-100);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("maintains precision with small numbers", () => {
|
|
85
|
+
expect(linearScale([0, 0.1], [0, 1])(0.05)).toBeCloseTo(0.5, 6);
|
|
86
|
+
expect(linearScale([0, 1e-6], [0, 1])(5e-7)).toBeCloseTo(0.5, 6);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* From https://github.com/melt-ui/melt-ui/blob/main/packages/svelte/src/lib/internal/math.ts
|
|
3
|
+
*/
|
|
4
|
+
export function snapValueToStep(value: number, min: number, max: number, step: number): number {
|
|
5
|
+
const remainder = (value - (Number.isNaN(min) ? 0 : min)) % step;
|
|
6
|
+
let snappedValue =
|
|
7
|
+
Math.abs(remainder) * 2 >= step
|
|
8
|
+
? value + Math.sign(remainder) * (step - Math.abs(remainder))
|
|
9
|
+
: value - remainder;
|
|
10
|
+
|
|
11
|
+
if (!Number.isNaN(min)) {
|
|
12
|
+
if (snappedValue < min) {
|
|
13
|
+
snappedValue = min;
|
|
14
|
+
} else if (!Number.isNaN(max) && snappedValue > max) {
|
|
15
|
+
snappedValue = min + Math.floor((max - min) / step) * step;
|
|
16
|
+
}
|
|
17
|
+
} else if (!Number.isNaN(max) && snappedValue > max) {
|
|
18
|
+
snappedValue = Math.floor(max / step) * step;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const string = step.toString();
|
|
22
|
+
const index = string.indexOf(".");
|
|
23
|
+
const precision = index >= 0 ? string.length - index : 0;
|
|
24
|
+
|
|
25
|
+
if (precision > 0) {
|
|
26
|
+
const pow = 10 ** precision;
|
|
27
|
+
snappedValue = Math.round(snappedValue * pow) / pow;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return snappedValue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function linearScale(
|
|
34
|
+
domain: [number, number],
|
|
35
|
+
range: [number, number],
|
|
36
|
+
clamp: boolean = true
|
|
37
|
+
): (x: number) => number {
|
|
38
|
+
const [d0, d1] = domain;
|
|
39
|
+
const [r0, r1] = range;
|
|
40
|
+
|
|
41
|
+
const slope = (r1 - r0) / (d1 - d0);
|
|
42
|
+
|
|
43
|
+
return (x: number) => {
|
|
44
|
+
const result = r0 + slope * (x - d0);
|
|
45
|
+
if (!clamp) return result;
|
|
46
|
+
if (result > Math.max(r0, r1)) return Math.max(r0, r1);
|
|
47
|
+
if (result < Math.min(r0, r1)) return Math.min(r0, r1);
|
|
48
|
+
return result;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function shouldTrapFocus({
|
|
2
|
+
forceMount,
|
|
3
|
+
present,
|
|
4
|
+
trapFocus,
|
|
5
|
+
open,
|
|
6
|
+
}: {
|
|
7
|
+
forceMount: boolean;
|
|
8
|
+
present: boolean;
|
|
9
|
+
trapFocus: boolean;
|
|
10
|
+
open: boolean;
|
|
11
|
+
}): boolean {
|
|
12
|
+
if (forceMount) {
|
|
13
|
+
return open && trapFocus;
|
|
14
|
+
}
|
|
15
|
+
return present && trapFocus && open;
|
|
16
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { focusable, isFocusable, isTabbable, tabbable } from "tabbable";
|
|
2
|
+
import { activeElement, getDocument } from "./dom.js";
|
|
3
|
+
|
|
4
|
+
function getTabbableOptions() {
|
|
5
|
+
return {
|
|
6
|
+
getShadowRoot: true,
|
|
7
|
+
displayCheck:
|
|
8
|
+
// JSDOM does not support the `tabbable` library. To solve this we can
|
|
9
|
+
// check if `ResizeObserver` is a real function (not polyfilled), which
|
|
10
|
+
// determines if the current environment is JSDOM-like.
|
|
11
|
+
typeof ResizeObserver === "function" &&
|
|
12
|
+
ResizeObserver.toString().includes("[native code]")
|
|
13
|
+
? "full"
|
|
14
|
+
: "none",
|
|
15
|
+
} as const;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getTabbableIn(container: HTMLElement, direction: "next" | "prev") {
|
|
19
|
+
const allTabbable = tabbable(container, getTabbableOptions());
|
|
20
|
+
|
|
21
|
+
if (direction === "prev") {
|
|
22
|
+
allTabbable.reverse();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const activeEl = activeElement(getDocument(container)) as HTMLElement;
|
|
26
|
+
|
|
27
|
+
const activeIndex = allTabbable.indexOf(activeEl);
|
|
28
|
+
const nextTabbableElements = allTabbable.slice(activeIndex + 1);
|
|
29
|
+
return nextTabbableElements[0];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Gets all tabbable elements in the body and finds the next/previous tabbable element
|
|
34
|
+
* from the `currentNode` based on the `direction` provided.
|
|
35
|
+
* @param currentNode - the node we want to get the next/previous tabbable from
|
|
36
|
+
*/
|
|
37
|
+
export function getTabbableFrom(currentNode: HTMLElement, direction: "next" | "prev") {
|
|
38
|
+
if (!isTabbable(currentNode, getTabbableOptions())) {
|
|
39
|
+
return getTabbableFromFocusable(currentNode, direction);
|
|
40
|
+
}
|
|
41
|
+
const allTabbable = tabbable(getDocument(currentNode).body, getTabbableOptions());
|
|
42
|
+
if (direction === "prev") allTabbable.reverse();
|
|
43
|
+
const activeIndex = allTabbable.indexOf(currentNode);
|
|
44
|
+
if (activeIndex === -1) return document.body;
|
|
45
|
+
const nextTabbableElements = allTabbable.slice(activeIndex + 1);
|
|
46
|
+
return nextTabbableElements[0];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getTabbableFromFocusable(currentNode: HTMLElement, direction: "next" | "prev") {
|
|
50
|
+
if (!isFocusable(currentNode, getTabbableOptions())) return document.body;
|
|
51
|
+
|
|
52
|
+
// find all focusable nodes, since some elements may be focusable but not tabbable
|
|
53
|
+
// such as context menu triggers
|
|
54
|
+
const allFocusable = focusable(getDocument(currentNode).body, getTabbableOptions());
|
|
55
|
+
|
|
56
|
+
// find index of current node among focusable siblings
|
|
57
|
+
if (direction === "prev") allFocusable.reverse();
|
|
58
|
+
const activeIndex = allFocusable.indexOf(currentNode);
|
|
59
|
+
if (activeIndex === -1) return document.body;
|
|
60
|
+
|
|
61
|
+
const nextFocusableElements = allFocusable.slice(activeIndex + 1);
|
|
62
|
+
|
|
63
|
+
// find the next focusable node that is also tabbable
|
|
64
|
+
return (
|
|
65
|
+
nextFocusableElements.find((node) => isTabbable(node, getTabbableOptions())) ??
|
|
66
|
+
document.body
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function getNextTabbable() {
|
|
71
|
+
return getTabbableIn(document.body, "next");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function getPreviousTabbable() {
|
|
75
|
+
return getTabbableIn(document.body, "prev");
|
|
76
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
|
|
4
|
+
import type { Box, ReadableBoxedValues, WritableBoxedValues } from "./box.svelte.js";
|
|
5
|
+
import type { StyleProperties } from "$lib/shared/index.js";
|
|
6
|
+
|
|
7
|
+
export type OnChangeFn<T> = (value: T) => void;
|
|
8
|
+
|
|
9
|
+
export type ElementRef = Box<HTMLElement | null>;
|
|
10
|
+
|
|
11
|
+
export type WithChild<
|
|
12
|
+
/**
|
|
13
|
+
* The props that the component accepts.
|
|
14
|
+
*/
|
|
15
|
+
Props extends Record<PropertyKey, unknown> = {},
|
|
16
|
+
/**
|
|
17
|
+
* The props that are passed to the `child` and `children` snippets. The `ElementProps` are
|
|
18
|
+
* merged with these props for the `child` snippet.
|
|
19
|
+
*/
|
|
20
|
+
SnippetProps extends Record<PropertyKey, unknown> = { _default: never },
|
|
21
|
+
/**
|
|
22
|
+
* The underlying DOM element being rendered. You can bind to this prop to
|
|
23
|
+
* programmatically interact with the element.
|
|
24
|
+
*/
|
|
25
|
+
Ref = HTMLElement,
|
|
26
|
+
> = Omit<Props, "child" | "children"> & {
|
|
27
|
+
child?: SnippetProps extends { _default: never }
|
|
28
|
+
? Snippet<[{ props: Record<string, unknown> }]>
|
|
29
|
+
: Snippet<[SnippetProps & { props: Record<string, unknown> }]>;
|
|
30
|
+
children?: SnippetProps extends { _default: never } ? Snippet : Snippet<[SnippetProps]>;
|
|
31
|
+
style?: StyleProperties | string | null | undefined;
|
|
32
|
+
ref?: Ref | null | undefined;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type WithChildNoChildrenSnippetProps<
|
|
36
|
+
/**
|
|
37
|
+
* The props that the component accepts.
|
|
38
|
+
*/
|
|
39
|
+
Props extends Record<PropertyKey, unknown> = {},
|
|
40
|
+
/**
|
|
41
|
+
* The props that are passed to the `child` and `children` snippets. The `ElementProps` are
|
|
42
|
+
* merged with these props for the `child` snippet.
|
|
43
|
+
*/
|
|
44
|
+
SnippetProps extends Record<PropertyKey, unknown> = { _default: never },
|
|
45
|
+
/**
|
|
46
|
+
* The underlying DOM element being rendered. You can bind to this prop to
|
|
47
|
+
* programmatically interact with the element.
|
|
48
|
+
*/
|
|
49
|
+
Ref = HTMLElement,
|
|
50
|
+
> = Omit<Props, "child" | "children"> & {
|
|
51
|
+
child?: SnippetProps extends { _default: never }
|
|
52
|
+
? Snippet<[{ props: Record<string, unknown> }]>
|
|
53
|
+
: Snippet<[SnippetProps & { props: Record<string, unknown> }]>;
|
|
54
|
+
children?: Snippet;
|
|
55
|
+
style?: StyleProperties | string | null | undefined;
|
|
56
|
+
ref?: Ref | null | undefined;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type WithChildren<Props = {}> = Props & {
|
|
60
|
+
children?: Snippet | undefined;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Constructs a new type by omitting properties from type
|
|
65
|
+
* 'T' that exist in type 'U'.
|
|
66
|
+
*
|
|
67
|
+
* @template T - The base object type from which properties will be omitted.
|
|
68
|
+
* @template U - The object type whose properties will be omitted from 'T'.
|
|
69
|
+
* @example
|
|
70
|
+
* type Result = Without<{ a: number; b: string; }, { b: string; }>;
|
|
71
|
+
* // Result type will be { a: number; }
|
|
72
|
+
*/
|
|
73
|
+
export type Without<T extends object, U extends object> = Omit<T, keyof U>;
|
|
74
|
+
|
|
75
|
+
export type Arrayable<T> = T[] | T;
|
|
76
|
+
|
|
77
|
+
export type Fn = () => void;
|
|
78
|
+
export type AnyFn = (...args: any[]) => any;
|
|
79
|
+
|
|
80
|
+
export type WithRefProps<T = {}> = T &
|
|
81
|
+
ReadableBoxedValues<{ id: string }> &
|
|
82
|
+
WritableBoxedValues<{ ref: HTMLElement | null }>;
|
|
83
|
+
|
|
84
|
+
export type BitsEvent<T extends Event = Event, U extends HTMLElement = HTMLElement> = T & {
|
|
85
|
+
currentTarget: U;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export type BitsPointerEvent<T extends HTMLElement = HTMLElement> = BitsEvent<PointerEvent, T>;
|
|
89
|
+
export type BitsKeyboardEvent<T extends HTMLElement = HTMLElement> = BitsEvent<KeyboardEvent, T>;
|
|
90
|
+
export type BitsMouseEvent<T extends HTMLElement = HTMLElement> = BitsEvent<MouseEvent, T>;
|
|
91
|
+
export type BitsFocusEvent<T extends HTMLElement = HTMLElement> = BitsEvent<FocusEvent, T>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { flushSync } from "svelte";
|
|
2
|
+
import type { Getter } from "svelte-toolbelt";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Calls a function the next frame after all animations have finished.
|
|
6
|
+
*/
|
|
7
|
+
export function useAfterAnimations(getNode: Getter<HTMLElement | null>) {
|
|
8
|
+
let frame = -1;
|
|
9
|
+
|
|
10
|
+
function cancelFrame() {
|
|
11
|
+
cancelAnimationFrame(frame);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
$effect(() => cancelFrame);
|
|
15
|
+
|
|
16
|
+
return (fn: () => void) => {
|
|
17
|
+
cancelFrame();
|
|
18
|
+
const node = getNode();
|
|
19
|
+
if (!node) return;
|
|
20
|
+
if (typeof node.getAnimations !== "function" || globalThis.bitsAnimationsDisabled) {
|
|
21
|
+
fn();
|
|
22
|
+
} else {
|
|
23
|
+
frame = requestAnimationFrame(() => {
|
|
24
|
+
Promise.allSettled(node.getAnimations().map((anim) => anim.finished)).then(() => {
|
|
25
|
+
flushSync(fn);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import type { Direction } from "$lib/shared/index.js";
|
|
2
|
+
|
|
3
|
+
type ArrowKeyOptions = "horizontal" | "vertical" | "both";
|
|
4
|
+
|
|
5
|
+
interface ArrowNavigationOptions {
|
|
6
|
+
/**
|
|
7
|
+
* The arrow key options to allow navigation
|
|
8
|
+
*
|
|
9
|
+
* @defaultValue "both"
|
|
10
|
+
*/
|
|
11
|
+
arrowKeyOptions?: ArrowKeyOptions;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The attribute name to find the collection items in the parent element.
|
|
15
|
+
*/
|
|
16
|
+
attributeName: string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The parent element where contains all the collection items, this will collect every item to be used when nav
|
|
20
|
+
* It will be ignored if attributeName is provided
|
|
21
|
+
*
|
|
22
|
+
* @defaultValue []
|
|
23
|
+
*/
|
|
24
|
+
itemsArray?: HTMLElement[];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Allow loop navigation. If false, it will stop at the first and last element
|
|
28
|
+
*
|
|
29
|
+
* @defaultValue true
|
|
30
|
+
*/
|
|
31
|
+
loop?: boolean;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The orientation of the collection
|
|
35
|
+
*
|
|
36
|
+
* @defaultValue "ltr"
|
|
37
|
+
*/
|
|
38
|
+
dir?: Direction;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Prevent the scroll when navigating. This happens when the direction of the
|
|
42
|
+
* key matches the scroll direction of any ancestor scrollable elements.
|
|
43
|
+
*
|
|
44
|
+
* @defaultValue true
|
|
45
|
+
*/
|
|
46
|
+
preventScroll?: boolean;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* By default all currentElement would trigger navigation. If `true`, currentElement nodeName in the ignore list will return null
|
|
50
|
+
*
|
|
51
|
+
* @defaultValue false
|
|
52
|
+
*/
|
|
53
|
+
enableIgnoredElement?: boolean;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Focus the element after navigation
|
|
57
|
+
*
|
|
58
|
+
* @defaultValue false
|
|
59
|
+
*/
|
|
60
|
+
focus?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const ignoredElement = ["INPUT", "TEXTAREA"];
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
*
|
|
67
|
+
* @param e Keyboard event
|
|
68
|
+
* @param currentElement Event initiator element or any element that wants to handle the navigation
|
|
69
|
+
* @param parentElement Parent element where contains all the collection items, this will collect every item to be used when nav
|
|
70
|
+
* @param options further options
|
|
71
|
+
* @returns the navigated html element or null if none
|
|
72
|
+
*/
|
|
73
|
+
export function useArrowNavigation(
|
|
74
|
+
e: KeyboardEvent,
|
|
75
|
+
currentElement: HTMLElement,
|
|
76
|
+
parentElement: HTMLElement | undefined,
|
|
77
|
+
options: ArrowNavigationOptions
|
|
78
|
+
): HTMLElement | null {
|
|
79
|
+
if (
|
|
80
|
+
!currentElement ||
|
|
81
|
+
(options.enableIgnoredElement && ignoredElement.includes(currentElement.nodeName))
|
|
82
|
+
) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const {
|
|
87
|
+
arrowKeyOptions = "both",
|
|
88
|
+
attributeName,
|
|
89
|
+
itemsArray = [],
|
|
90
|
+
loop = true,
|
|
91
|
+
dir = "ltr",
|
|
92
|
+
preventScroll = true,
|
|
93
|
+
focus = false,
|
|
94
|
+
} = options;
|
|
95
|
+
|
|
96
|
+
const [right, left, up, down, home, end] = [
|
|
97
|
+
e.key === "ArrowRight",
|
|
98
|
+
e.key === "ArrowLeft",
|
|
99
|
+
e.key === "ArrowUp",
|
|
100
|
+
e.key === "ArrowDown",
|
|
101
|
+
e.key === "Home",
|
|
102
|
+
e.key === "End",
|
|
103
|
+
];
|
|
104
|
+
const goingVertical = up || down;
|
|
105
|
+
const goingHorizontal = right || left;
|
|
106
|
+
if (
|
|
107
|
+
!home &&
|
|
108
|
+
!end &&
|
|
109
|
+
((!goingVertical && !goingHorizontal) ||
|
|
110
|
+
(arrowKeyOptions === "vertical" && goingHorizontal) ||
|
|
111
|
+
(arrowKeyOptions === "horizontal" && goingVertical))
|
|
112
|
+
)
|
|
113
|
+
return null;
|
|
114
|
+
|
|
115
|
+
const allCollectionItems: HTMLElement[] = parentElement
|
|
116
|
+
? Array.from(parentElement.querySelectorAll(attributeName))
|
|
117
|
+
: itemsArray;
|
|
118
|
+
|
|
119
|
+
if (!allCollectionItems.length) return null;
|
|
120
|
+
|
|
121
|
+
if (preventScroll) e.preventDefault();
|
|
122
|
+
|
|
123
|
+
let item: HTMLElement | null = null;
|
|
124
|
+
|
|
125
|
+
if (goingHorizontal || goingVertical) {
|
|
126
|
+
const goForward = goingVertical ? down : dir === "ltr" ? right : left;
|
|
127
|
+
item = findNextFocusableElement(allCollectionItems, currentElement, {
|
|
128
|
+
goForward,
|
|
129
|
+
loop,
|
|
130
|
+
});
|
|
131
|
+
} else if (home) {
|
|
132
|
+
item = allCollectionItems.at(0) || null;
|
|
133
|
+
} else if (end) {
|
|
134
|
+
item = allCollectionItems.at(-1) || null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (focus) item?.focus();
|
|
138
|
+
|
|
139
|
+
return item;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Recursive function to find the next focusable element to avoid disabled elements
|
|
144
|
+
*/
|
|
145
|
+
function findNextFocusableElement(
|
|
146
|
+
elements: HTMLElement[],
|
|
147
|
+
currentElement: HTMLElement,
|
|
148
|
+
{ goForward, loop }: { goForward: boolean; loop?: boolean },
|
|
149
|
+
iterations = elements.length
|
|
150
|
+
): HTMLElement | null {
|
|
151
|
+
if (--iterations === 0) return null;
|
|
152
|
+
|
|
153
|
+
const index = elements.indexOf(currentElement);
|
|
154
|
+
const newIndex = goForward ? index + 1 : index - 1;
|
|
155
|
+
|
|
156
|
+
if (!loop && (newIndex < 0 || newIndex >= elements.length)) return null;
|
|
157
|
+
|
|
158
|
+
const adjustedNewIndex = (newIndex + elements.length) % elements.length;
|
|
159
|
+
const candidate = elements[adjustedNewIndex];
|
|
160
|
+
if (!candidate) return null;
|
|
161
|
+
|
|
162
|
+
const isDisabled =
|
|
163
|
+
candidate.hasAttribute("disabled") && candidate.getAttribute("disabled") !== "false";
|
|
164
|
+
if (isDisabled) {
|
|
165
|
+
return findNextFocusableElement(elements, candidate, { goForward, loop }, iterations);
|
|
166
|
+
}
|
|
167
|
+
return candidate;
|
|
168
|
+
}
|