@t007/utils 0.0.33 → 0.0.35
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/{arrowNavigation-DK8mqVOk.d.cts → arrowNavigation-B9bEdoqR.d.ts} +5 -2
- package/dist/{arrowNavigation-VenvPI4H.d.ts → arrowNavigation-zEJbo8Er.d.cts} +5 -2
- package/dist/{chunk-QJ72EQCJ.js → chunk-NX2LWYD6.js} +22 -17
- package/dist/chunk-ZALPHCSJ.js +317 -0
- package/dist/components/react.d.cts +1 -1
- package/dist/components/react.d.ts +1 -1
- package/dist/hooks/react.cjs +67 -53
- package/dist/hooks/react.d.cts +9 -6
- package/dist/hooks/react.d.ts +9 -6
- package/dist/hooks/react.js +34 -24
- package/dist/hooks/vanilla.cjs +58 -41
- package/dist/hooks/vanilla.d.cts +10 -10
- package/dist/hooks/vanilla.d.ts +10 -10
- package/dist/hooks/vanilla.js +25 -14
- package/dist/index.cjs +143 -22
- package/dist/index.d.cts +143 -16
- package/dist/index.d.ts +143 -16
- package/dist/index.js +23 -3
- package/dist/ripple-D1kGErTn.d.cts +55 -0
- package/dist/ripple-D1kGErTn.d.ts +55 -0
- package/dist/scrollAssist-BNvPnsJq.d.cts +97 -0
- package/dist/scrollAssist-BNvPnsJq.d.ts +97 -0
- package/dist/{useHighlight-DMpDCILK.d.cts → useHighlight-DYc_GF0R.d.cts} +2 -2
- package/dist/{useHighlight-DMpDCILK.d.ts → useHighlight-DYc_GF0R.d.ts} +2 -2
- package/package.json +4 -3
- package/dist/chunk-4O76EZJ4.js +0 -206
- package/dist/ripple-C5MfEErC.d.cts +0 -73
- package/dist/ripple-C5MfEErC.d.ts +0 -73
- package/dist/scrollAssist-y9wFmYgt.d.cts +0 -72
- package/dist/scrollAssist-y9wFmYgt.d.ts +0 -72
package/dist/hooks/react.cjs
CHANGED
|
@@ -38,12 +38,13 @@ var import_utils = require("sia-reactor/utils");
|
|
|
38
38
|
// src/ts/core/dom.ts
|
|
39
39
|
var import_utils2 = require("sia-reactor/utils");
|
|
40
40
|
var import_utils3 = require("sia-reactor/utils");
|
|
41
|
-
var
|
|
41
|
+
var import_sia_reactor = require("sia-reactor");
|
|
42
|
+
var INTERACTIVE_SELECTOR = ":is(button,[href],input:not([type='hidden']),select,textarea,details>summary,[contenteditable],iframe,audio[controls],video[controls],[tabindex]):not([disabled],[tabindex='-1'],[data-focus-guard],[inert],[inert] *)";
|
|
42
43
|
var isInteractive = (target) => target instanceof HTMLElement && target.matches(INTERACTIVE_SELECTOR);
|
|
43
44
|
|
|
44
45
|
// src/ts/hooks/react/useScrollAssist.ts
|
|
45
|
-
var
|
|
46
|
-
function useScrollAssist(ref, { enabled = true, pxPerSecond = 80, assistClassName = "t007-scroll-assist", vertical = true, horizontal = true } =
|
|
46
|
+
var import_sia_reactor2 = require("sia-reactor");
|
|
47
|
+
function useScrollAssist(ref, { enabled = true, pxPerSecond = 80, assistClassName = "t007-scroll-assist", vertical = true, horizontal = true } = import_sia_reactor2.NIL) {
|
|
47
48
|
const scrollId = (0, import_react.useRef)(null), last = (0, import_react.useRef)(performance.now()), assists = (0, import_react.useRef)({}), assistWidth = (0, import_react.useRef)(20), assistHeight = (0, import_react.useRef)(20);
|
|
48
49
|
const update = (0, import_react.useCallback)(() => {
|
|
49
50
|
const el = ref.current;
|
|
@@ -124,31 +125,30 @@ function useScrollAssist(ref, { enabled = true, pxPerSecond = 80, assistClassNam
|
|
|
124
125
|
var import_react2 = require("react");
|
|
125
126
|
|
|
126
127
|
// src/ts/hooks/vanilla/outsideClick.ts
|
|
127
|
-
var
|
|
128
|
-
function initOutsideClick(el, { enabled = false, onOutside =
|
|
129
|
-
const
|
|
128
|
+
var import_sia_reactor3 = require("sia-reactor");
|
|
129
|
+
function initOutsideClick(el, { enabled = false, onOutside = import_sia_reactor3.NOOP, outOnClick = true, outOnEscape = true, outOnFocusOut = false, allowBounds = false, allowInputs = false, root = window, scoped = true, capture = true } = import_sia_reactor3.NIL) {
|
|
130
|
+
const stack = t007._outsiders_stack ??= [], existing = (t007._outsiders ??= /* @__PURE__ */ new WeakMap()).get(el);
|
|
130
131
|
if (!enabled || existing) return existing ? existing : void 0;
|
|
131
132
|
scoped = scoped && root instanceof HTMLElement, root = scoped ? root : root === document ? document : window;
|
|
132
|
-
const
|
|
133
|
+
const onScopedOut = (e, t, p = e.touches?.[0] || e, rect = allowBounds ? el.getBoundingClientRect() : null) => {
|
|
133
134
|
if (stack.at(-1) !== el || (allowBounds ? p.clientX >= rect.left && p.clientX <= rect.right && p.clientY >= rect.top && p.clientY <= rect.bottom : el.contains(t))) return false;
|
|
134
135
|
return (!scoped ? true : root.contains(t)) && onOutside(e);
|
|
135
136
|
}, handleClick = ((e) => outOnClick && !(allowInputs && isInteractive(e.target)) && onScopedOut(e, e.target)), handleEscape = ((e) => outOnEscape && e.key === "Escape" && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey && stack.at(-1) === el && onOutside(e)), handleFocusOut = (e) => outOnFocusOut && !el.contains(e.relatedTarget) && onScopedOut(e, e.relatedTarget);
|
|
136
137
|
root.addEventListener("mousedown", handleClick, capture), root.addEventListener("touchstart", handleClick, { passive: true, capture });
|
|
137
138
|
root.addEventListener("keydown", handleEscape, capture);
|
|
138
139
|
el.addEventListener("focusout", handleFocusOut, capture);
|
|
139
|
-
if (!stack.includes(el)) stack.push(el), stacks.set(root, stack);
|
|
140
140
|
const destroy = () => {
|
|
141
141
|
root.removeEventListener("mousedown", handleClick, capture), root.removeEventListener("touchstart", handleClick, capture);
|
|
142
142
|
root.removeEventListener("keydown", handleEscape, capture);
|
|
143
143
|
el.removeEventListener("focusout", handleFocusOut, capture);
|
|
144
144
|
t007._outsiders.delete(el), stack.splice(stack.indexOf(el), 1);
|
|
145
145
|
};
|
|
146
|
-
return t007._outsiders.set(el, destroy), destroy;
|
|
146
|
+
return !stack.includes(el) && stack.push(el), t007._outsiders.set(el, destroy), destroy;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
// src/ts/hooks/react/useOutsideClick.ts
|
|
150
|
-
var
|
|
151
|
-
function useOutsideClick(ref, config =
|
|
150
|
+
var import_sia_reactor4 = require("sia-reactor");
|
|
151
|
+
function useOutsideClick(ref, config = import_sia_reactor4.NIL) {
|
|
152
152
|
(0, import_react2.useEffect)(() => ref.current ? initOutsideClick(ref.current, config) : void 0, [ref, config.enabled, config.onOutside, config.outOnEscape, config.outOnClick, config.outOnFocusOut, config.allowBounds, config.allowInputs, config.root, config.scoped, config.capture]);
|
|
153
153
|
}
|
|
154
154
|
|
|
@@ -200,7 +200,7 @@ var getGrid = (all, x = true, y = true, vY = true) => {
|
|
|
200
200
|
};
|
|
201
201
|
|
|
202
202
|
// src/ts/hooks/react/useArrowNavigation/consts.ts
|
|
203
|
-
var
|
|
203
|
+
var import_sia_reactor5 = require("sia-reactor");
|
|
204
204
|
var H_NAV_KEYS = ["ArrowRight", "ArrowLeft", "Home", "End"];
|
|
205
205
|
var V_NAV_KEYS = ["ArrowUp", "ArrowDown", "PageDown", "PageUp"];
|
|
206
206
|
var NAV_KEYS = [...H_NAV_KEYS, ...V_NAV_KEYS];
|
|
@@ -218,16 +218,16 @@ var DEFAULT_CONFIG = {
|
|
|
218
218
|
rtl: null,
|
|
219
219
|
grid: {},
|
|
220
220
|
activeClass: "focus-outlined",
|
|
221
|
-
inputSelector: "input,textarea,[contenteditable
|
|
221
|
+
inputSelector: "input,textarea,[contenteditable]",
|
|
222
222
|
focusOptions: { preventScroll: false },
|
|
223
223
|
scrollIntoView: { block: "nearest", inline: "nearest" },
|
|
224
|
-
onSelect:
|
|
225
|
-
onFocusOut:
|
|
224
|
+
onSelect: import_sia_reactor5.NOOP,
|
|
225
|
+
onFocusOut: import_sia_reactor5.NOOP
|
|
226
226
|
};
|
|
227
227
|
|
|
228
228
|
// src/ts/hooks/react/useArrowNavigation/index.ts
|
|
229
229
|
function useArrowNavigation(containerRef, config = {}) {
|
|
230
|
-
const { enabled: isEnabled, selector, focusOnHover, loop, virtual, typeahead, rovingTab, resetMs, activeClass, inputSelector, defaultTabbableIndex, baseTabIndex, grid, rtl: isRtl, focusOptions, scrollIntoView, onSelect, onFocusOut } = { ...DEFAULT_CONFIG, ...config }, [gridX, setGridX] = (0, import_react3.useState)(grid.x || 1), [gridY, setGridY] = (0, import_react3.useState)(grid.y || 1), [vGridY, setVGridY] = (0, import_react3.useState)(grid.vY || 1), [activeIndex, setActiveIndex] = (0, import_react3.useState)(-1), buffer = (0, import_react3.useRef)(""), timeout = (0, import_react3.useRef)(null), itemsRef = (0, import_react3.useRef)([]), enabled = isEnabled ?? virtual, roving = rovingTab ?? !virtual, rtl = (0, import_react3.useMemo)(() => isRtl ?? ("undefined" === typeof document ? false : getComputedStyle(containerRef.current || document.body).direction === "rtl"), [containerRef, isRtl]), mutationObserverRef = (0, import_react3.useRef)(null), shouldSnub = (0, import_react3.useCallback)(() => !enabled || !containerRef.current, [enabled, containerRef]), isItemDisabled = (0, import_react3.useCallback)((el) => !el
|
|
230
|
+
const { enabled: isEnabled, selector, focusOnHover, loop, virtual, typeahead, rovingTab, resetMs, activeClass, inputSelector, defaultTabbableIndex, baseTabIndex, grid, rtl: isRtl, focusOptions, scrollIntoView, onSelect, onFocusOut } = { ...DEFAULT_CONFIG, ...config }, [gridX, setGridX] = (0, import_react3.useState)(grid.x || 1), [gridY, setGridY] = (0, import_react3.useState)(grid.y || 1), [vGridY, setVGridY] = (0, import_react3.useState)(grid.vY || 1), [activeIndex, setActiveIndex] = (0, import_react3.useState)(-1), buffer = (0, import_react3.useRef)(""), timeout = (0, import_react3.useRef)(null), itemsRef = (0, import_react3.useRef)([]), enabled = isEnabled ?? virtual, roving = rovingTab ?? !virtual, rtl = (0, import_react3.useMemo)(() => isRtl ?? ("undefined" === typeof document ? false : getComputedStyle(containerRef.current || document.body).direction === "rtl"), [containerRef, isRtl]), mutationObserverRef = (0, import_react3.useRef)(null), shouldSnub = (0, import_react3.useCallback)(() => !enabled || !containerRef.current, [enabled, containerRef]), isItemDisabled = (0, import_react3.useCallback)((el) => !el || el.matches('[disabled],[aria-disabled="true"],[inert],:disabled'), []), getItems = (0, import_react3.useCallback)(() => itemsRef.current = Array.from(containerRef.current?.querySelectorAll(selector) || []), [containerRef, selector]);
|
|
231
231
|
const getAbleIndex = (0, import_react3.useCallback)(
|
|
232
232
|
(targetIndex, e = { key: "ArrowRight", ctrlKey: false }) => {
|
|
233
233
|
if (shouldSnub()) return;
|
|
@@ -301,8 +301,9 @@ function useArrowNavigation(containerRef, config = {}) {
|
|
|
301
301
|
},
|
|
302
302
|
[shouldSnub, virtual, activeIndex, gridX, gridY, vGridY, loop, rtl, goToIndex, typeahead, typeAhead]
|
|
303
303
|
);
|
|
304
|
-
const latest = (0, import_react3.useRef)({ getItems, updateDOM, activeIndex
|
|
305
|
-
|
|
304
|
+
const latest = (0, import_react3.useRef)({ getItems, updateDOM, activeIndex, calcGrid: () => {
|
|
305
|
+
} });
|
|
306
|
+
(0, import_react3.useEffect)(() => void (latest.current = { ...latest.current, getItems, updateDOM, activeIndex }), [getItems, updateDOM, activeIndex]);
|
|
306
307
|
(0, import_react3.useEffect)(() => void getItems(), [getItems, enabled]);
|
|
307
308
|
(0, import_react3.useEffect)(() => void (!enabled && setActiveIndex(-1)), [enabled]);
|
|
308
309
|
(0, import_react3.useEffect)(() => updateDOM(), [activeIndex, updateDOM]);
|
|
@@ -331,8 +332,7 @@ function useArrowNavigation(containerRef, config = {}) {
|
|
|
331
332
|
const all = itemsRef.current;
|
|
332
333
|
const handleHover = (e) => {
|
|
333
334
|
if (!focusOnHover) return;
|
|
334
|
-
const el = e.currentTarget;
|
|
335
|
-
const i = itemsRef.current?.indexOf(el);
|
|
335
|
+
const el = e.currentTarget, i = itemsRef.current?.indexOf(el);
|
|
336
336
|
if (i !== -1) goToIndex(i);
|
|
337
337
|
};
|
|
338
338
|
for (const el of all) el.addEventListener("mouseenter", handleHover);
|
|
@@ -340,23 +340,23 @@ function useArrowNavigation(containerRef, config = {}) {
|
|
|
340
340
|
for (const el of all) el.removeEventListener("mouseenter", handleHover);
|
|
341
341
|
};
|
|
342
342
|
}, [enabled, focusOnHover, goToIndex]);
|
|
343
|
+
const sync = (0, import_react3.useCallback)(() => {
|
|
344
|
+
const { getItems: getItems2, updateDOM: updateDOM2, activeIndex: activeIndex2 } = latest.current;
|
|
345
|
+
const oldEl = itemsRef.current[activeIndex2];
|
|
346
|
+
getItems2();
|
|
347
|
+
const newEl = itemsRef.current[activeIndex2];
|
|
348
|
+
updateDOM2();
|
|
349
|
+
if (oldEl && newEl && oldEl === newEl) return;
|
|
350
|
+
setActiveIndex(-1);
|
|
351
|
+
}, []);
|
|
343
352
|
(0, import_react3.useEffect)(() => {
|
|
344
353
|
if (shouldSnub()) return;
|
|
345
|
-
const observer = mutationObserverRef.current = new MutationObserver(
|
|
346
|
-
const { getItems: getItems2, updateDOM: updateDOM2, activeIndex: activeIndex2 } = latest.current;
|
|
347
|
-
const oldEl = itemsRef.current[activeIndex2];
|
|
348
|
-
getItems2();
|
|
349
|
-
const newEl = itemsRef.current[activeIndex2];
|
|
350
|
-
updateDOM2();
|
|
351
|
-
if (oldEl && newEl && oldEl === newEl) return;
|
|
352
|
-
setActiveIndex(-1);
|
|
353
|
-
});
|
|
354
|
+
const observer = mutationObserverRef.current = new MutationObserver(sync);
|
|
354
355
|
observer.observe(containerRef.current, { childList: true, subtree: true });
|
|
355
356
|
return () => observer.disconnect();
|
|
356
|
-
}, [shouldSnub, containerRef]);
|
|
357
|
+
}, [shouldSnub, containerRef, sync]);
|
|
357
358
|
(0, import_react3.useEffect)(() => {
|
|
358
359
|
if (shouldSnub()) return;
|
|
359
|
-
const all = itemsRef.current;
|
|
360
360
|
const setGrid = (g) => {
|
|
361
361
|
if (g.x) setGridX(g.x);
|
|
362
362
|
if (g.y) setGridY(g.y);
|
|
@@ -364,26 +364,32 @@ function useArrowNavigation(containerRef, config = {}) {
|
|
|
364
364
|
};
|
|
365
365
|
setGrid(grid);
|
|
366
366
|
if (grid.x && grid.y && grid.vY) return;
|
|
367
|
-
|
|
368
|
-
calcGrid();
|
|
367
|
+
let ancestor = null;
|
|
369
368
|
const resizeObserver = new ResizeObserver(() => calcGrid());
|
|
370
|
-
|
|
369
|
+
const calcGrid = () => {
|
|
370
|
+
setGrid(getGrid(itemsRef.current, !grid.x, !grid.y, !grid.vY));
|
|
371
|
+
const next = itemsRef.current.length > 1 ? getCommonAncestor(itemsRef.current[0], itemsRef.current[1]) : containerRef.current;
|
|
372
|
+
if (next && next !== ancestor) ancestor && resizeObserver.unobserve(ancestor), ancestor = next, resizeObserver.observe(ancestor);
|
|
373
|
+
};
|
|
374
|
+
latest.current.calcGrid = calcGrid;
|
|
375
|
+
calcGrid();
|
|
371
376
|
return () => resizeObserver.disconnect();
|
|
372
377
|
}, [shouldSnub, containerRef, grid]);
|
|
373
378
|
(0, import_react3.useEffect)(() => void (timeout.current && clearTimeout(timeout.current)), []);
|
|
374
|
-
return { gridX, gridY, vGridY, activeIndex, activeItem: (0, import_react3.useCallback)(() => itemsRef.current[activeIndex] ?? null, [activeIndex]), items: (0, import_react3.useCallback)(() => itemsRef.current, []), getAbleIndex, typeAhead, goToIndex, simulateKey };
|
|
379
|
+
return { gridX, gridY, vGridY, activeIndex, activeItem: (0, import_react3.useCallback)(() => itemsRef.current[activeIndex] ?? null, [activeIndex]), items: (0, import_react3.useCallback)(() => itemsRef.current, []), getAbleIndex, typeAhead, goToIndex, simulateKey, sync };
|
|
375
380
|
}
|
|
376
381
|
|
|
377
382
|
// src/ts/hooks/react/useFocusTrap.ts
|
|
378
383
|
var import_react4 = require("react");
|
|
379
384
|
|
|
380
385
|
// src/ts/hooks/vanilla/focusTrap.ts
|
|
381
|
-
var
|
|
382
|
-
function initFocusTrap(el, { enabled = false, initialSelector = "[data-autofocus]", ringClassName = "focus-outline", root = window, scoped = true, capture = true } =
|
|
383
|
-
const
|
|
386
|
+
var import_sia_reactor6 = require("sia-reactor");
|
|
387
|
+
function initFocusTrap(el, { enabled = false, initialSelector = "[data-autofocus]", ringClassName = "focus-outline", root = window, scoped = true, capture = true } = import_sia_reactor6.NIL) {
|
|
388
|
+
const stack = t007._ftrappers_stack ??= [], existing = (t007._ftrappers ??= /* @__PURE__ */ new WeakMap()).get(el);
|
|
384
389
|
if (!enabled || existing) return existing ? existing : void 0;
|
|
385
390
|
scoped = scoped && root instanceof HTMLElement, root = scoped ? root : root === document ? document : window;
|
|
386
|
-
|
|
391
|
+
let recovering = false;
|
|
392
|
+
const focused = document.querySelector(":focus"), initial = el.querySelector(initialSelector), first = (0, import_utils2.createEl)("span", { tabIndex: 0 }, { focusGuard: "start" }, { position: "absolute", width: "0", height: "0", pointerEvents: "none" }), last = (0, import_utils2.createEl)("span", { tabIndex: 0 }, { focusGuard: "end" }, { position: "absolute", width: "0", height: "0", pointerEvents: "none" }), getFocusable = (c = el) => [...c.querySelectorAll(INTERACTIVE_SELECTOR)], resetFocus = (i = 0, els = getFocusable()) => !recovering && (recovering = true, els?.length ? els.at(i).focus() : (!el.hasAttribute("tabindex") && (el.tabIndex = -1), el.focus()), recovering = false), edgeFocus = (pre = false, rt = root) => {
|
|
387
393
|
if (!scoped) return resetFocus(pre ? -1 : 0);
|
|
388
394
|
if (rt.hasAttribute("tabindex")) return rt.focus();
|
|
389
395
|
const items = getFocusable();
|
|
@@ -393,28 +399,33 @@ function initFocusTrap(el, { enabled = false, initialSelector = "[data-autofocus
|
|
|
393
399
|
while (p !== ceil && (!all.length || (pre ? rt.contains(all[0]) : rt.contains(all.at(-1))))) all = getFocusable(p = p.parentElement || ceil);
|
|
394
400
|
for (let target, len = all.length, i = all.indexOf(items[pre ? 0 : items.length - 1]) + (pre ? -1 : 1); pre ? i >= 0 : i < len; pre ? i-- : i++) if (!rt.contains(target = all[i])) return target.focus();
|
|
395
401
|
(pre ? first : last).blur();
|
|
396
|
-
}, handleFocusIn = () => {
|
|
402
|
+
}, handleFocusIn = (e) => {
|
|
397
403
|
if (document.querySelector("dialog:modal") && !el.matches("dialog:modal")) return;
|
|
398
|
-
stack.at(-1) === el && (0, import_utils3.getActiveEl)(el.ownerDocument) !== root && !el.contains((0, import_utils3.getActiveEl)(el.ownerDocument)) && resetFocus();
|
|
404
|
+
stack.at(-1) === el && (0, import_utils3.getActiveEl)(el.ownerDocument) !== root && !el.contains((0, import_utils3.getActiveEl)(el.ownerDocument)) && !e.composedPath().includes(el) && resetFocus();
|
|
399
405
|
}, handleInitialBlur = () => initial.classList.remove(ringClassName);
|
|
400
406
|
first.addEventListener("focus", (e) => el.contains(e.relatedTarget) ? edgeFocus(true) : resetFocus(), capture), el.prepend(first);
|
|
401
407
|
last.addEventListener("focus", (e) => el.contains(e.relatedTarget) ? edgeFocus() : resetFocus(-1), capture), el.append(last);
|
|
402
408
|
root.addEventListener("focusin", handleFocusIn, capture);
|
|
403
409
|
if (initial || !el.contains(focused)) !initial ? setTimeout(resetFocus) : setTimeout(() => (initial.classList.add(ringClassName), initial.focus(), initial.addEventListener("blur", handleInitialBlur, capture)));
|
|
404
|
-
if (!stack.includes(el)) stack.push(el), stacks.set(root, stack);
|
|
405
410
|
const destroy = () => {
|
|
406
411
|
focused?.isConnected && focused.focus(), first.remove(), last.remove();
|
|
407
412
|
root.removeEventListener("focusin", handleFocusIn, capture);
|
|
408
413
|
initial?.removeEventListener("blur", handleInitialBlur, capture);
|
|
409
414
|
t007._ftrappers.delete(el), stack.splice(stack.indexOf(el), 1);
|
|
410
415
|
};
|
|
411
|
-
|
|
416
|
+
const handle = { destroy, sync: () => (el.prepend(first), el.append(last)) };
|
|
417
|
+
return !stack.includes(el) && stack.push(el), t007._ftrappers.set(el, handle), handle;
|
|
412
418
|
}
|
|
413
419
|
|
|
414
420
|
// src/ts/hooks/react/useFocusTrap.ts
|
|
415
|
-
var
|
|
416
|
-
function useFocusTrap(ref, config =
|
|
417
|
-
(0, import_react4.
|
|
421
|
+
var import_sia_reactor7 = require("sia-reactor");
|
|
422
|
+
function useFocusTrap(ref, config = import_sia_reactor7.NIL) {
|
|
423
|
+
const handle = (0, import_react4.useRef)(void 0);
|
|
424
|
+
(0, import_react4.useEffect)(() => {
|
|
425
|
+
if (!ref.current) return;
|
|
426
|
+
return handle.current = initFocusTrap(ref.current, config), () => handle.current?.destroy();
|
|
427
|
+
}, [ref, config.enabled, config.initialSelector, config.ringClassName, config.root, config.scoped, config.capture]);
|
|
428
|
+
return { sync: () => handle.current?.sync() };
|
|
418
429
|
}
|
|
419
430
|
|
|
420
431
|
// src/ts/hooks/react/useHighlight.ts
|
|
@@ -434,8 +445,8 @@ function useHighlight(text, query, ignoreCase = true, options) {
|
|
|
434
445
|
var import_react6 = require("react");
|
|
435
446
|
|
|
436
447
|
// src/ts/hooks/vanilla/ripple.ts
|
|
437
|
-
var
|
|
438
|
-
function rippleHandler(e, { target, forceCenter = false, wrapperClassName = "t007-ripple-wrapper", className = "t007-ripple", holdClassName = "t007-ripple-hold", fadeClassName = "t007-ripple-fade" } =
|
|
448
|
+
var import_sia_reactor8 = require("sia-reactor");
|
|
449
|
+
function rippleHandler(e, { target, forceCenter = false, wrapperClassName = "t007-ripple-wrapper", className = "t007-ripple", holdClassName = "t007-ripple-hold", fadeClassName = "t007-ripple-fade", maxDuration = 1e3 } = import_sia_reactor8.NIL) {
|
|
439
450
|
const el = target || e.currentTarget;
|
|
440
451
|
if (!el || e.target !== e.currentTarget && isInteractive(e.target) || el.hasAttribute("disabled") || e.pointerType === "mouse" && e.button !== 0) return;
|
|
441
452
|
e.stopPropagation?.();
|
|
@@ -443,19 +454,22 @@ function rippleHandler(e, { target, forceCenter = false, wrapperClassName = "t00
|
|
|
443
454
|
let canRelease = false;
|
|
444
455
|
ripple.addEventListener("animationend", () => canRelease = true, { once: true });
|
|
445
456
|
el.append(wrapper.appendChild(ripple).parentElement);
|
|
446
|
-
|
|
447
|
-
|
|
457
|
+
let released = false;
|
|
458
|
+
const release = (force) => {
|
|
459
|
+
if (released) return;
|
|
460
|
+
if (!canRelease && force !== true) return ripple.addEventListener("animationend", release, { once: true }), void setTimeout(release, maxDuration, true);
|
|
461
|
+
released = true;
|
|
448
462
|
ripple.classList.replace(holdClassName, fadeClassName);
|
|
449
|
-
ripple.addEventListener("animationend", () => setTimeout(() => wrapper.remove()));
|
|
463
|
+
ripple.addEventListener("animationend", () => setTimeout(() => wrapper.remove())), setTimeout(() => wrapper.remove(), maxDuration);
|
|
450
464
|
for (const evt of ["pointerup", "pointercancel"]) (el.ownerDocument?.defaultView || window).removeEventListener(evt, release);
|
|
451
465
|
};
|
|
452
466
|
for (const evt of ["pointerup", "pointercancel"]) (el.ownerDocument?.defaultView || window).addEventListener(evt, release);
|
|
453
467
|
}
|
|
454
468
|
|
|
455
469
|
// src/ts/hooks/react/useRipple.ts
|
|
456
|
-
var
|
|
470
|
+
var import_sia_reactor9 = require("sia-reactor");
|
|
457
471
|
function useRipple() {
|
|
458
|
-
return (0, import_react6.useCallback)((e, config =
|
|
472
|
+
return (0, import_react6.useCallback)((e, config = import_sia_reactor9.NIL) => rippleHandler(e.nativeEvent, config), []);
|
|
459
473
|
}
|
|
460
474
|
// Annotate the CommonJS export names for ESM import in node:
|
|
461
475
|
0 && (module.exports = {
|
package/dist/hooks/react.d.cts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { RefObject } from 'react';
|
|
2
|
-
import { a as ScrollAssistConfig, C as Config, K as KeyEvent } from '../scrollAssist-
|
|
3
|
-
import { O as OutsideClickConfig,
|
|
4
|
-
export { H as HighlightOptions, u as useHighlight } from '../useHighlight-
|
|
2
|
+
import { a as ScrollAssistConfig, C as Config, K as KeyEvent, b as FocusTrapConfig } from '../scrollAssist-BNvPnsJq.cjs';
|
|
3
|
+
import { O as OutsideClickConfig, R as RippleConfig } from '../ripple-D1kGErTn.cjs';
|
|
4
|
+
export { H as HighlightOptions, u as useHighlight } from '../useHighlight-DYc_GF0R.cjs';
|
|
5
5
|
|
|
6
6
|
/** Configuration options for the `useScrollAssist` hook. */
|
|
7
7
|
interface UseScrollAssistConfig extends ScrollAssistConfig {
|
|
8
|
-
/** Enables or disables the scroll assist.
|
|
8
|
+
/** Enables or disables the scroll assist. @default `true`. */
|
|
9
9
|
enabled?: boolean;
|
|
10
10
|
}
|
|
11
11
|
/** React hook to add edge-scrolling assist to an element. It creates invisible "hot zones" at the edges of the element that, when hovered or dragged into, will scroll the element in that direction.
|
|
@@ -33,10 +33,13 @@ declare function useArrowNavigation(containerRef: React.RefObject<HTMLElement>,
|
|
|
33
33
|
typeAhead: (key: string) => void;
|
|
34
34
|
goToIndex: (targetIndex: number, e?: KeyEvent) => void;
|
|
35
35
|
simulateKey: (e: KeyEvent) => void;
|
|
36
|
+
sync: () => void;
|
|
36
37
|
};
|
|
37
38
|
|
|
38
|
-
/** React hook
|
|
39
|
-
declare function useFocusTrap(ref: RefObject<HTMLElement>, config?: FocusTrapConfig):
|
|
39
|
+
/** React hook to keep focus trapped inside an element until disabled. */
|
|
40
|
+
declare function useFocusTrap(ref: RefObject<HTMLElement>, config?: FocusTrapConfig): {
|
|
41
|
+
sync: () => void | undefined;
|
|
42
|
+
};
|
|
40
43
|
|
|
41
44
|
/** React hook to render and control a material-style ripple animation on an element.
|
|
42
45
|
* @returns Stable pointer handler for clickable UI surfaces.
|
package/dist/hooks/react.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { RefObject } from 'react';
|
|
2
|
-
import { a as ScrollAssistConfig, C as Config, K as KeyEvent } from '../scrollAssist-
|
|
3
|
-
import { O as OutsideClickConfig,
|
|
4
|
-
export { H as HighlightOptions, u as useHighlight } from '../useHighlight-
|
|
2
|
+
import { a as ScrollAssistConfig, C as Config, K as KeyEvent, b as FocusTrapConfig } from '../scrollAssist-BNvPnsJq.js';
|
|
3
|
+
import { O as OutsideClickConfig, R as RippleConfig } from '../ripple-D1kGErTn.js';
|
|
4
|
+
export { H as HighlightOptions, u as useHighlight } from '../useHighlight-DYc_GF0R.js';
|
|
5
5
|
|
|
6
6
|
/** Configuration options for the `useScrollAssist` hook. */
|
|
7
7
|
interface UseScrollAssistConfig extends ScrollAssistConfig {
|
|
8
|
-
/** Enables or disables the scroll assist.
|
|
8
|
+
/** Enables or disables the scroll assist. @default `true`. */
|
|
9
9
|
enabled?: boolean;
|
|
10
10
|
}
|
|
11
11
|
/** React hook to add edge-scrolling assist to an element. It creates invisible "hot zones" at the edges of the element that, when hovered or dragged into, will scroll the element in that direction.
|
|
@@ -33,10 +33,13 @@ declare function useArrowNavigation(containerRef: React.RefObject<HTMLElement>,
|
|
|
33
33
|
typeAhead: (key: string) => void;
|
|
34
34
|
goToIndex: (targetIndex: number, e?: KeyEvent) => void;
|
|
35
35
|
simulateKey: (e: KeyEvent) => void;
|
|
36
|
+
sync: () => void;
|
|
36
37
|
};
|
|
37
38
|
|
|
38
|
-
/** React hook
|
|
39
|
-
declare function useFocusTrap(ref: RefObject<HTMLElement>, config?: FocusTrapConfig):
|
|
39
|
+
/** React hook to keep focus trapped inside an element until disabled. */
|
|
40
|
+
declare function useFocusTrap(ref: RefObject<HTMLElement>, config?: FocusTrapConfig): {
|
|
41
|
+
sync: () => void | undefined;
|
|
42
|
+
};
|
|
40
43
|
|
|
41
44
|
/** React hook to render and control a material-style ripple animation on an element.
|
|
42
45
|
* @returns Stable pointer handler for clickable UI surfaces.
|
package/dist/hooks/react.js
CHANGED
|
@@ -11,11 +11,11 @@ import {
|
|
|
11
11
|
initFocusTrap,
|
|
12
12
|
initOutsideClick,
|
|
13
13
|
rippleHandler
|
|
14
|
-
} from "../chunk-
|
|
14
|
+
} from "../chunk-NX2LWYD6.js";
|
|
15
15
|
import {
|
|
16
16
|
INTERACTIVE_SELECTOR,
|
|
17
17
|
getActiveEl
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-ZALPHCSJ.js";
|
|
19
19
|
|
|
20
20
|
// src/ts/hooks/react/useScrollAssist.ts
|
|
21
21
|
import { useEffect, useRef, useCallback } from "react";
|
|
@@ -107,7 +107,7 @@ function useOutsideClick(ref, config = NIL2) {
|
|
|
107
107
|
// src/ts/hooks/react/useArrowNavigation/index.ts
|
|
108
108
|
import { useEffect as useEffect3, useState, useCallback as useCallback2, useRef as useRef2, useMemo } from "react";
|
|
109
109
|
function useArrowNavigation(containerRef, config = {}) {
|
|
110
|
-
const { enabled: isEnabled, selector, focusOnHover, loop, virtual, typeahead, rovingTab, resetMs, activeClass, inputSelector, defaultTabbableIndex, baseTabIndex, grid, rtl: isRtl, focusOptions, scrollIntoView, onSelect, onFocusOut } = { ...DEFAULT_CONFIG, ...config }, [gridX, setGridX] = useState(grid.x || 1), [gridY, setGridY] = useState(grid.y || 1), [vGridY, setVGridY] = useState(grid.vY || 1), [activeIndex, setActiveIndex] = useState(-1), buffer = useRef2(""), timeout = useRef2(null), itemsRef = useRef2([]), enabled = isEnabled ?? virtual, roving = rovingTab ?? !virtual, rtl = useMemo(() => isRtl ?? ("undefined" === typeof document ? false : getComputedStyle(containerRef.current || document.body).direction === "rtl"), [containerRef, isRtl]), mutationObserverRef = useRef2(null), shouldSnub = useCallback2(() => !enabled || !containerRef.current, [enabled, containerRef]), isItemDisabled = useCallback2((el) => !el
|
|
110
|
+
const { enabled: isEnabled, selector, focusOnHover, loop, virtual, typeahead, rovingTab, resetMs, activeClass, inputSelector, defaultTabbableIndex, baseTabIndex, grid, rtl: isRtl, focusOptions, scrollIntoView, onSelect, onFocusOut } = { ...DEFAULT_CONFIG, ...config }, [gridX, setGridX] = useState(grid.x || 1), [gridY, setGridY] = useState(grid.y || 1), [vGridY, setVGridY] = useState(grid.vY || 1), [activeIndex, setActiveIndex] = useState(-1), buffer = useRef2(""), timeout = useRef2(null), itemsRef = useRef2([]), enabled = isEnabled ?? virtual, roving = rovingTab ?? !virtual, rtl = useMemo(() => isRtl ?? ("undefined" === typeof document ? false : getComputedStyle(containerRef.current || document.body).direction === "rtl"), [containerRef, isRtl]), mutationObserverRef = useRef2(null), shouldSnub = useCallback2(() => !enabled || !containerRef.current, [enabled, containerRef]), isItemDisabled = useCallback2((el) => !el || el.matches('[disabled],[aria-disabled="true"],[inert],:disabled'), []), getItems = useCallback2(() => itemsRef.current = Array.from(containerRef.current?.querySelectorAll(selector) || []), [containerRef, selector]);
|
|
111
111
|
const getAbleIndex = useCallback2(
|
|
112
112
|
(targetIndex, e = { key: "ArrowRight", ctrlKey: false }) => {
|
|
113
113
|
if (shouldSnub()) return;
|
|
@@ -181,8 +181,9 @@ function useArrowNavigation(containerRef, config = {}) {
|
|
|
181
181
|
},
|
|
182
182
|
[shouldSnub, virtual, activeIndex, gridX, gridY, vGridY, loop, rtl, goToIndex, typeahead, typeAhead]
|
|
183
183
|
);
|
|
184
|
-
const latest = useRef2({ getItems, updateDOM, activeIndex
|
|
185
|
-
|
|
184
|
+
const latest = useRef2({ getItems, updateDOM, activeIndex, calcGrid: () => {
|
|
185
|
+
} });
|
|
186
|
+
useEffect3(() => void (latest.current = { ...latest.current, getItems, updateDOM, activeIndex }), [getItems, updateDOM, activeIndex]);
|
|
186
187
|
useEffect3(() => void getItems(), [getItems, enabled]);
|
|
187
188
|
useEffect3(() => void (!enabled && setActiveIndex(-1)), [enabled]);
|
|
188
189
|
useEffect3(() => updateDOM(), [activeIndex, updateDOM]);
|
|
@@ -211,8 +212,7 @@ function useArrowNavigation(containerRef, config = {}) {
|
|
|
211
212
|
const all = itemsRef.current;
|
|
212
213
|
const handleHover = (e) => {
|
|
213
214
|
if (!focusOnHover) return;
|
|
214
|
-
const el = e.currentTarget;
|
|
215
|
-
const i = itemsRef.current?.indexOf(el);
|
|
215
|
+
const el = e.currentTarget, i = itemsRef.current?.indexOf(el);
|
|
216
216
|
if (i !== -1) goToIndex(i);
|
|
217
217
|
};
|
|
218
218
|
for (const el of all) el.addEventListener("mouseenter", handleHover);
|
|
@@ -220,23 +220,23 @@ function useArrowNavigation(containerRef, config = {}) {
|
|
|
220
220
|
for (const el of all) el.removeEventListener("mouseenter", handleHover);
|
|
221
221
|
};
|
|
222
222
|
}, [enabled, focusOnHover, goToIndex]);
|
|
223
|
+
const sync = useCallback2(() => {
|
|
224
|
+
const { getItems: getItems2, updateDOM: updateDOM2, activeIndex: activeIndex2 } = latest.current;
|
|
225
|
+
const oldEl = itemsRef.current[activeIndex2];
|
|
226
|
+
getItems2();
|
|
227
|
+
const newEl = itemsRef.current[activeIndex2];
|
|
228
|
+
updateDOM2();
|
|
229
|
+
if (oldEl && newEl && oldEl === newEl) return;
|
|
230
|
+
setActiveIndex(-1);
|
|
231
|
+
}, []);
|
|
223
232
|
useEffect3(() => {
|
|
224
233
|
if (shouldSnub()) return;
|
|
225
|
-
const observer = mutationObserverRef.current = new MutationObserver(
|
|
226
|
-
const { getItems: getItems2, updateDOM: updateDOM2, activeIndex: activeIndex2 } = latest.current;
|
|
227
|
-
const oldEl = itemsRef.current[activeIndex2];
|
|
228
|
-
getItems2();
|
|
229
|
-
const newEl = itemsRef.current[activeIndex2];
|
|
230
|
-
updateDOM2();
|
|
231
|
-
if (oldEl && newEl && oldEl === newEl) return;
|
|
232
|
-
setActiveIndex(-1);
|
|
233
|
-
});
|
|
234
|
+
const observer = mutationObserverRef.current = new MutationObserver(sync);
|
|
234
235
|
observer.observe(containerRef.current, { childList: true, subtree: true });
|
|
235
236
|
return () => observer.disconnect();
|
|
236
|
-
}, [shouldSnub, containerRef]);
|
|
237
|
+
}, [shouldSnub, containerRef, sync]);
|
|
237
238
|
useEffect3(() => {
|
|
238
239
|
if (shouldSnub()) return;
|
|
239
|
-
const all = itemsRef.current;
|
|
240
240
|
const setGrid = (g) => {
|
|
241
241
|
if (g.x) setGridX(g.x);
|
|
242
242
|
if (g.y) setGridY(g.y);
|
|
@@ -244,21 +244,31 @@ function useArrowNavigation(containerRef, config = {}) {
|
|
|
244
244
|
};
|
|
245
245
|
setGrid(grid);
|
|
246
246
|
if (grid.x && grid.y && grid.vY) return;
|
|
247
|
-
|
|
248
|
-
calcGrid();
|
|
247
|
+
let ancestor = null;
|
|
249
248
|
const resizeObserver = new ResizeObserver(() => calcGrid());
|
|
250
|
-
|
|
249
|
+
const calcGrid = () => {
|
|
250
|
+
setGrid(getGrid(itemsRef.current, !grid.x, !grid.y, !grid.vY));
|
|
251
|
+
const next = itemsRef.current.length > 1 ? getCommonAncestor(itemsRef.current[0], itemsRef.current[1]) : containerRef.current;
|
|
252
|
+
if (next && next !== ancestor) ancestor && resizeObserver.unobserve(ancestor), ancestor = next, resizeObserver.observe(ancestor);
|
|
253
|
+
};
|
|
254
|
+
latest.current.calcGrid = calcGrid;
|
|
255
|
+
calcGrid();
|
|
251
256
|
return () => resizeObserver.disconnect();
|
|
252
257
|
}, [shouldSnub, containerRef, grid]);
|
|
253
258
|
useEffect3(() => void (timeout.current && clearTimeout(timeout.current)), []);
|
|
254
|
-
return { gridX, gridY, vGridY, activeIndex, activeItem: useCallback2(() => itemsRef.current[activeIndex] ?? null, [activeIndex]), items: useCallback2(() => itemsRef.current, []), getAbleIndex, typeAhead, goToIndex, simulateKey };
|
|
259
|
+
return { gridX, gridY, vGridY, activeIndex, activeItem: useCallback2(() => itemsRef.current[activeIndex] ?? null, [activeIndex]), items: useCallback2(() => itemsRef.current, []), getAbleIndex, typeAhead, goToIndex, simulateKey, sync };
|
|
255
260
|
}
|
|
256
261
|
|
|
257
262
|
// src/ts/hooks/react/useFocusTrap.ts
|
|
258
|
-
import { useEffect as useEffect4 } from "react";
|
|
263
|
+
import { useEffect as useEffect4, useRef as useRef3 } from "react";
|
|
259
264
|
import { NIL as NIL3 } from "sia-reactor";
|
|
260
265
|
function useFocusTrap(ref, config = NIL3) {
|
|
261
|
-
|
|
266
|
+
const handle = useRef3(void 0);
|
|
267
|
+
useEffect4(() => {
|
|
268
|
+
if (!ref.current) return;
|
|
269
|
+
return handle.current = initFocusTrap(ref.current, config), () => handle.current?.destroy();
|
|
270
|
+
}, [ref, config.enabled, config.initialSelector, config.ringClassName, config.root, config.scoped, config.capture]);
|
|
271
|
+
return { sync: () => handle.current?.sync() };
|
|
262
272
|
}
|
|
263
273
|
|
|
264
274
|
// src/ts/hooks/react/useRipple.ts
|