@t007/utils 0.0.25 → 0.0.27

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.
@@ -0,0 +1,233 @@
1
+ import {
2
+ DEFAULT_CONFIG,
3
+ H_NAV_KEYS,
4
+ NAV_KEYS,
5
+ getCommonAncestor,
6
+ getGrid,
7
+ getTargetIndex,
8
+ initFocusTrap,
9
+ initOutsideClick,
10
+ removeFocusTrap,
11
+ removeOutsideClick,
12
+ rippleHandler
13
+ } from "../chunk-NLR4ANGT.js";
14
+ import {
15
+ INTERACTIVE_SELECTOR,
16
+ createEl,
17
+ getActiveEl
18
+ } from "../chunk-N5KX6IW4.js";
19
+
20
+ // src/hooks/vanilla/scrollAssist.ts
21
+ import { NIL } from "sia-reactor";
22
+ function initScrollAssist(el, { pxPerSecond = 80, assistClassName = "t007-scroll-assist", vertical = true, horizontal = true } = NIL) {
23
+ const parent = el?.parentElement, existing = (t007._scrollers ??= /* @__PURE__ */ new WeakMap()).get(el);
24
+ if (!parent || existing) return existing ? existing : void 0;
25
+ t007._scrollers_r_observer ??= new ResizeObserver((entries) => {
26
+ for (const { target } of entries) t007._scrollers.get(target)?.update();
27
+ });
28
+ t007._scrollers_m_observer ??= new MutationObserver((entries) => {
29
+ const els = /* @__PURE__ */ new Set();
30
+ for (const entry of entries) {
31
+ let node = entry.target instanceof Element ? entry.target : null;
32
+ while (node && !t007._scrollers.has(node)) node = node.parentElement;
33
+ if (node) els.add(node);
34
+ }
35
+ for (const el2 of els) t007._scrollers.get(el2)?.update();
36
+ });
37
+ const assist = {};
38
+ let scrollId = null, last = performance.now(), assistWidth = 20, assistHeight = 20;
39
+ const update = () => {
40
+ const hasInteractive = !!parent.querySelector(INTERACTIVE_SELECTOR);
41
+ if (horizontal) {
42
+ const w = assist.left?.offsetWidth || assistWidth, check = hasInteractive ? el.clientWidth < w * 2 : false;
43
+ assist.left.style.display = check ? "none" : el.scrollLeft > 0 ? "block" : "none";
44
+ assist.right.style.display = check ? "none" : el.scrollLeft + el.clientWidth < el.scrollWidth - 1 ? "block" : "none";
45
+ assistWidth = w;
46
+ }
47
+ if (vertical) {
48
+ const h = assist.up?.offsetHeight || assistHeight, check = hasInteractive ? el.clientHeight < h * 2 : false;
49
+ assist.up.style.display = check ? "none" : el.scrollTop > 0 ? "block" : "none";
50
+ assist.down.style.display = check ? "none" : el.scrollTop + el.clientHeight < el.scrollHeight - 1 ? "block" : "none";
51
+ assistHeight = h;
52
+ }
53
+ };
54
+ const scroll = (dir) => {
55
+ const frame = () => {
56
+ const now = performance.now(), dt = now - last;
57
+ last = now;
58
+ const d = pxPerSecond * dt / 1e3;
59
+ if (dir === "left") el.scrollLeft = Math.max(0, el.scrollLeft - d);
60
+ if (dir === "right") el.scrollLeft = Math.min(el.scrollWidth - el.clientWidth, el.scrollLeft + d);
61
+ if (dir === "up") el.scrollTop = Math.max(0, el.scrollTop - d);
62
+ if (dir === "down") el.scrollTop = Math.min(el.scrollHeight - el.clientHeight, el.scrollTop + d);
63
+ scrollId = requestAnimationFrame(frame);
64
+ };
65
+ last = performance.now();
66
+ frame();
67
+ };
68
+ const stop = () => (cancelAnimationFrame(scrollId ?? 0), scrollId = null);
69
+ const addAssist = (dir) => {
70
+ const div = createEl("div", { className: assistClassName }, { scrollDirection: dir }, { display: "none" });
71
+ if (!div) return;
72
+ for (const evt of ["pointerenter", "dragenter"]) div.addEventListener(evt, () => scroll(dir));
73
+ for (const evt of ["pointerleave", "pointerup", "pointercancel", "dragleave", "dragend"]) div.addEventListener(evt, stop);
74
+ dir === "left" || dir === "up" ? parent.insertBefore(div, el) : parent.append(div);
75
+ assist[dir] = div;
76
+ };
77
+ if (horizontal) for (const dir of ["left", "right"]) addAssist(dir);
78
+ if (vertical) for (const dir of ["up", "down"]) addAssist(dir);
79
+ const handle = {
80
+ update,
81
+ destroy() {
82
+ stop(), el.removeEventListener("scroll", update);
83
+ t007._scrollers_r_observer.unobserve(el), t007._scrollers.delete(el);
84
+ for (const a of Object.values(assist)) a.remove();
85
+ }
86
+ };
87
+ update(), el.addEventListener("scroll", update);
88
+ t007._scrollers_r_observer.observe(el), t007._scrollers_m_observer.observe(el, { childList: true, subtree: true, characterData: true });
89
+ return t007._scrollers.set(el, handle), handle;
90
+ }
91
+ var removeScrollAssist = (el) => t007._scrollers.get(el)?.destroy();
92
+
93
+ // src/hooks/vanilla/scrollerator.ts
94
+ import { NIL as NIL2 } from "sia-reactor";
95
+ function initVScrollerator({ baseSpeed = 3, maxSpeed = 10, stepDelay = 2e3, baseRate = 16, lineHeight = 80, margin = 80, car = window } = NIL2) {
96
+ let linesPerSec = baseSpeed, accelId = null, lastTime = null;
97
+ const drive = (clientY, brake = false, offsetY = 0) => {
98
+ if (car !== window) clientY -= offsetY;
99
+ const now = performance.now(), speed = linesPerSec * lineHeight * ((lastTime ? now - lastTime : baseRate) / 1e3);
100
+ if (!brake && (clientY < margin || clientY > (car.innerHeight ?? car.offsetHeight) - margin)) {
101
+ accelId === null ? accelId = setTimeout(() => linesPerSec += 1, stepDelay) : linesPerSec > baseSpeed && (linesPerSec = Math.min(linesPerSec + 1, maxSpeed));
102
+ car.scrollBy?.(0, clientY < margin ? -speed : speed);
103
+ } else reset();
104
+ return lastTime = !brake ? now : null, speed;
105
+ };
106
+ const reset = () => (accelId && clearTimeout(accelId), accelId = null, linesPerSec = baseSpeed, lastTime = null);
107
+ return { drive, reset };
108
+ }
109
+
110
+ // src/hooks/vanilla/arrowNavigation.ts
111
+ function initArrowNavigation(container, config = {}) {
112
+ const existing = (t007._arrownavs ??= /* @__PURE__ */ new WeakMap()).get(container);
113
+ if (!config.enabled || existing) return existing ? existing : void 0;
114
+ const { enabled: isEnabled, selector, focusOnHover, loop, virtual, typeahead, resetMs, activeClass, inputSelector, defaultTabbableIndex, baseTabIndex, grid, rtl: isRtl, focusOptions, scrollIntoView, onSelect, onFocusOut, rovingTab } = { ...DEFAULT_CONFIG, ...config };
115
+ let gridX = grid.x || 1, gridY = grid.y || 1, vGridY = grid.vY || 1, activeIndex = -1, buffer = "", timeout = null, items = [];
116
+ const enabled = isEnabled ?? virtual, roving = rovingTab ?? !virtual, rtl = isRtl ?? getComputedStyle(container).direction === "rtl", shouldSnub = () => !enabled || !container, isItemDisabled = (el) => !el || el.hasAttribute("disabled") || el.hasAttribute("aria-disabled"), getItems = () => items = Array.from(container.querySelectorAll(selector));
117
+ const getAbleIndex = (targetIndex, e = { key: "ArrowRight", ctrlKey: false }) => {
118
+ if (shouldSnub() || !items.length) return null;
119
+ let index = targetIndex;
120
+ let attempts = 0;
121
+ while (attempts < items.length) {
122
+ if (!isItemDisabled(items[index])) return index;
123
+ index = getTargetIndex({ key: e.key, currIndex: index, gridX, gridY, vGridY, length: items.length, loop, ctrlKey: e.ctrlKey, rtl });
124
+ attempts++;
125
+ }
126
+ return null;
127
+ };
128
+ const goToIndex = (targetIndex, e = { key: "ArrowRight" }) => {
129
+ if (shouldSnub()) return;
130
+ const idx = getAbleIndex(targetIndex, e);
131
+ if (idx === null) return;
132
+ resetActiveIndex(idx);
133
+ onSelect?.(items[idx], e), updateDOM();
134
+ if (virtual) {
135
+ items[idx]?.scrollIntoView(scrollIntoView);
136
+ container.setAttribute("aria-activedescendant", items[idx].id || "");
137
+ } else items[idx]?.focus(focusOptions);
138
+ };
139
+ const updateDOM = () => {
140
+ if (shouldSnub() || !virtual && !roving || !items.length) return;
141
+ const hasDefaultTabbable = defaultTabbableIndex !== null && defaultTabbableIndex !== void 0, tabbableIndex = hasDefaultTabbable && !isItemDisabled(items[defaultTabbableIndex]) ? defaultTabbableIndex : getAbleIndex(0);
142
+ for (let i = 0, len = items.length; i < len; i++) {
143
+ const el = items[i], isActive = i === activeIndex;
144
+ if (roving) el.setAttribute("tabindex", i === activeIndex || activeIndex === -1 && i === tabbableIndex ? baseTabIndex : "-1");
145
+ else if (virtual && activeIndex > 0) el.setAttribute("tabindex", i > activeIndex ? baseTabIndex : "-1");
146
+ else el.setAttribute("tabindex", baseTabIndex);
147
+ if (virtual) el.setAttribute("aria-selected", String(isActive)), el.classList.toggle(activeClass, isActive);
148
+ }
149
+ };
150
+ const resetActiveIndex = (index = -1) => (activeIndex = index, updateDOM());
151
+ const typeAhead = (key) => {
152
+ if (shouldSnub() || !typeahead) return;
153
+ buffer += key.toLowerCase();
154
+ if (timeout) clearTimeout(timeout);
155
+ timeout = setTimeout(() => buffer = "", resetMs);
156
+ const start = activeIndex >= 0 ? activeIndex + 1 : 0;
157
+ for (let i = 0; i < items.length; i++) {
158
+ const idx = (start + i) % items.length, label = (items[idx].getAttribute("data-label") || items[idx].innerText || "").trim().toLowerCase();
159
+ if (label.startsWith(buffer)) return goToIndex(idx);
160
+ }
161
+ };
162
+ const simulateKey = (e) => {
163
+ const t = e.target;
164
+ if (shouldSnub() || getActiveEl(t?.ownerDocument)?.matches("option")) return;
165
+ const { key } = e;
166
+ if (!items.length) return;
167
+ if (virtual && (key === " " || key === "Enter")) return items[activeIndex]?.click();
168
+ if (t?.matches(DEFAULT_CONFIG.inputSelector) && !virtual) return;
169
+ if (typeahead && key.length === 1 && /^[a-z0-9]$/i.test(key)) return typeAhead(key);
170
+ if (!NAV_KEYS.includes(key)) return;
171
+ if (!(e.currentTarget?.matches(DEFAULT_CONFIG.inputSelector) && gridX <= 1 && H_NAV_KEYS.includes(key))) e.preventDefault?.(), e.stopPropagation?.();
172
+ const currIndex = virtual ? activeIndex : items.indexOf(getActiveEl(t?.ownerDocument)), targetIndex = getTargetIndex({ currIndex, gridX, gridY, vGridY, length: items.length, loop, rtl, key, ctrlKey: e.ctrlKey });
173
+ goToIndex(targetIndex, e);
174
+ };
175
+ getItems(), updateDOM();
176
+ const interactiveEls = !virtual ? [container] : [container.querySelector(inputSelector)];
177
+ for (const el of interactiveEls) el?.addEventListener("keydown", simulateKey);
178
+ const handleFocusOut = (e) => {
179
+ if (!container.contains(e.relatedTarget)) return resetActiveIndex(), updateDOM(), onFocusOut?.(e);
180
+ const among = items.includes(e.relatedTarget);
181
+ if (!among && (defaultTabbableIndex ?? -1) >= 0) return resetActiveIndex(), updateDOM();
182
+ if (virtual) resetActiveIndex(), updateDOM();
183
+ };
184
+ container.addEventListener("focusout", handleFocusOut);
185
+ const handleHover = (e) => {
186
+ if (!enabled || !focusOnHover) return;
187
+ const el = e.currentTarget, idx = items.indexOf(el);
188
+ if (idx !== -1) goToIndex(idx);
189
+ };
190
+ for (const el of items) el.addEventListener("mouseenter", handleHover);
191
+ const mutationObserver = new MutationObserver(() => {
192
+ const oldEl = items[activeIndex];
193
+ getItems();
194
+ const newEl = items[activeIndex];
195
+ updateDOM();
196
+ if (oldEl && newEl && oldEl === newEl) return;
197
+ resetActiveIndex();
198
+ updateDOM();
199
+ });
200
+ mutationObserver.observe(container, { childList: true, subtree: true });
201
+ const setGrid = (g) => {
202
+ if (g.x !== void 0) gridX = g.x;
203
+ if (g.y !== void 0) gridY = g.y;
204
+ if (g.vY !== void 0) vGridY = g.vY;
205
+ };
206
+ const calcGrid = () => setGrid(getGrid(items, !grid.x, !grid.y, !grid.vY));
207
+ setGrid(grid), calcGrid();
208
+ const ancestor = items.length > 1 ? getCommonAncestor(items[0], items[1]) : container;
209
+ const resizeObserver = new ResizeObserver(calcGrid);
210
+ if (ancestor) resizeObserver.observe(ancestor);
211
+ const destroy = () => {
212
+ for (const el of interactiveEls) el?.removeEventListener("keydown", simulateKey);
213
+ container.removeEventListener("focusout", handleFocusOut);
214
+ for (const el of items) el.removeEventListener("mouseenter", handleHover);
215
+ mutationObserver.disconnect(), resizeObserver.disconnect();
216
+ if (timeout) clearTimeout(timeout);
217
+ };
218
+ const handle = { gridX: () => gridX, gridY: () => gridY, vGridY: () => vGridY, items: () => items, activeIndex: () => activeIndex, activeItem: () => items[activeIndex] ?? null, getAbleIndex, typeAhead, goToIndex, simulateKey, destroy };
219
+ return t007._arrownavs.set(container, handle), handle;
220
+ }
221
+ var removeArrowNavigation = (container) => t007._arrownavs?.get(container)?.destroy();
222
+ export {
223
+ initArrowNavigation,
224
+ initFocusTrap,
225
+ initOutsideClick,
226
+ initScrollAssist,
227
+ initVScrollerator,
228
+ removeArrowNavigation,
229
+ removeFocusTrap,
230
+ removeOutsideClick,
231
+ removeScrollAssist,
232
+ rippleHandler
233
+ };
package/dist/index.cjs CHANGED
@@ -20,53 +20,63 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ INTERACTIVE_SELECTOR: () => INTERACTIVE_SELECTOR,
24
+ NIL: () => import_sia_reactor.NIL,
25
+ NOOP: () => import_sia_reactor.NOOP,
23
26
  VIRTUAL_RESOURCE: () => VIRTUAL_RESOURCE,
24
27
  assignEl: () => import_utils.assignEl,
25
- bindAllMethods: () => import_utils6.bindAllMethods,
28
+ bindAllMethods: () => import_utils7.bindAllMethods,
26
29
  bindCleanupToSignal: () => bindCleanupToSignal,
27
30
  breath: () => breath,
28
- clamp: () => import_utils3.clamp,
29
- cleanKeyCombo: () => import_utils5.cleanKeyCombo,
31
+ clamp: () => import_utils4.clamp,
32
+ cleanKeyCombo: () => import_utils6.cleanKeyCombo,
30
33
  createEl: () => import_utils.createEl,
31
34
  deepBreath: () => deepBreath,
32
- formatKeyForDisplay: () => import_utils5.formatKeyForDisplay,
33
- formatKeyShortcutsForDisplay: () => import_utils5.formatKeyShortcutsForDisplay,
34
- getTermsForKey: () => import_utils5.getTermsForKey,
35
- guardAllMethods: () => import_utils6.guardAllMethods,
36
- guardMethod: () => import_utils6.guardMethod,
35
+ formatKeyForDisplay: () => import_utils6.formatKeyForDisplay,
36
+ formatKeyShortcutsForDisplay: () => import_utils6.formatKeyShortcutsForDisplay,
37
+ formatSize: () => formatSize,
38
+ getActiveEl: () => import_utils2.getActiveEl,
39
+ getTermsForKey: () => import_utils6.getTermsForKey,
40
+ guardAllMethods: () => import_utils7.guardAllMethods,
41
+ guardMethod: () => import_utils7.guardMethod,
37
42
  inBoolArrOpt: () => inBoolArrOpt,
38
- initScrollAssist: () => initScrollAssist,
39
- initVScrollerator: () => initVScrollerator,
40
43
  isArr: () => isArr,
41
44
  isBool: () => isBool,
42
45
  isDef: () => isDef,
43
46
  isFunc: () => isFunc,
47
+ isInteractive: () => isInteractive,
44
48
  isIter: () => isIter,
45
49
  isNum: () => isNum,
46
- isObj: () => import_utils2.isObj,
50
+ isObj: () => import_utils3.isObj,
47
51
  isPOJO: () => isPOJO,
48
52
  isSameURL: () => isSameURL,
49
53
  isStr: () => isStr,
50
54
  isSym: () => isSym,
51
- keyEventAllowed: () => import_utils5.keyEventAllowed,
55
+ keyEventAllowed: () => import_utils6.keyEventAllowed,
52
56
  limited: () => limited,
53
57
  loadResource: () => loadResource,
54
- matchKeys: () => import_utils5.matchKeys,
58
+ matchKeys: () => import_utils6.matchKeys,
55
59
  mockAsync: () => mockAsync,
56
- onAllMethods: () => import_utils6.onAllMethods,
57
- parseForARIAKS: () => import_utils5.parseForARIAKS,
58
- parseKeyCombo: () => import_utils5.parseKeyCombo,
59
- removeScrollAssist: () => removeScrollAssist,
60
- requestAnimationFrame: () => import_utils4.requestAnimationFrame,
61
- setInterval: () => import_utils4.setInterval,
62
- setTimeout: () => import_utils4.setTimeout,
63
- stringifyKeyEvent: () => import_utils5.stringifyKeyEvent,
60
+ onAllMethods: () => import_utils7.onAllMethods,
61
+ parseCSSSize: () => parseCSSSize,
62
+ parseCSSTime: () => parseCSSTime,
63
+ parseForARIAKS: () => import_utils6.parseForARIAKS,
64
+ parseKeyCombo: () => import_utils6.parseKeyCombo,
65
+ pxToRem: () => pxToRem,
66
+ remToPx: () => remToPx,
67
+ requestAnimationFrame: () => import_utils5.requestAnimationFrame,
68
+ setInterval: () => import_utils5.setInterval,
69
+ setTimeout: () => import_utils5.setTimeout,
70
+ stringifyKeyEvent: () => import_utils6.stringifyKeyEvent,
64
71
  uid: () => uid
65
72
  });
66
73
  module.exports = __toCommonJS(index_exports);
67
74
 
68
75
  // src/core/dom.ts
69
76
  var import_utils = require("sia-reactor/utils");
77
+ var import_utils2 = require("sia-reactor/utils");
78
+ var INTERACTIVE_SELECTOR = ":is(button,[href],input:not([type='hidden']),select,textarea,details>summary,[contenteditable='true'],iframe,audio[controls],video[controls],[tabindex]):not([disabled],[tabindex='-1'],[data-focus-guard],[inert],[inert] *)";
79
+ var isInteractive = (target) => target instanceof HTMLElement && target.matches(INTERACTIVE_SELECTOR);
70
80
  var VIRTUAL_RESOURCE = /* @__PURE__ */ Symbol.for("T007_VIRTUAL_RESOURCE");
71
81
  function loadResource(req, type = "style", { module: module2, media, crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, attempts = 3, retryKey = false } = {}, w = window) {
72
82
  w.t007 ??= {}, w.t007._resourceCache ??= {};
@@ -96,8 +106,11 @@ function loadResource(req, type = "style", { module: module2, media, crossOrigin
96
106
  return w.t007._resourceCache[src];
97
107
  }
98
108
 
109
+ // src/index.ts
110
+ var import_sia_reactor = require("sia-reactor");
111
+
99
112
  // src/core/obj.ts
100
- var import_utils2 = require("sia-reactor/utils");
113
+ var import_utils3 = require("sia-reactor/utils");
101
114
  function isDef(val) {
102
115
  return "undefined" !== typeof val;
103
116
  }
@@ -117,7 +130,7 @@ function isArr(obj) {
117
130
  return Array.isArray(obj);
118
131
  }
119
132
  function isPOJO(obj, crossRealms = false, typecheck = true) {
120
- return (typecheck ? (0, import_utils2.isObj)(obj, false) : true) && (crossRealms ? Object.prototype.toString.call(obj) === "[object Object]" : obj.constructor === Object);
133
+ return (typecheck ? (0, import_utils3.isObj)(obj, false) : true) && (crossRealms ? Object.prototype.toString.call(obj) === "[object Object]" : obj.constructor === Object);
121
134
  }
122
135
  function isIter(obj) {
123
136
  return obj != null && "function" === typeof obj[Symbol.iterator];
@@ -130,12 +143,24 @@ function inBoolArrOpt(opt, str) {
130
143
  }
131
144
 
132
145
  // src/core/num.ts
133
- var import_utils3 = require("sia-reactor/utils");
146
+ var import_utils4 = require("sia-reactor/utils");
134
147
 
135
148
  // src/core/str.ts
136
149
  function uid(prefix = "") {
137
150
  return prefix + Date.now().toString(36) + "_" + performance.now().toString(36).replace(".", "") + "_" + Math.random().toString(36).slice(2);
138
151
  }
152
+ function remToPx(rem, el = document.documentElement) {
153
+ return rem * parseFloat(getComputedStyle(el).fontSize);
154
+ }
155
+ function pxToRem(px, el = document.documentElement) {
156
+ return px / parseFloat(getComputedStyle(el).fontSize);
157
+ }
158
+ function parseCSSTime(time) {
159
+ return time?.endsWith?.("ms") ? parseFloat(time) : parseFloat(time) * 1e3;
160
+ }
161
+ function parseCSSSize(size, el) {
162
+ return size?.endsWith?.("px") ? parseFloat(size) : remToPx(parseFloat(size), el);
163
+ }
139
164
  function isSameURL(src1, src2) {
140
165
  if (!isStr(src1) || !isStr(src2) || !src1 || !src2) return false;
141
166
  try {
@@ -147,7 +172,7 @@ function isSameURL(src1, src2) {
147
172
  }
148
173
 
149
174
  // src/core/fn.ts
150
- var import_utils4 = require("sia-reactor/utils");
175
+ var import_utils5 = require("sia-reactor/utils");
151
176
  function limited(FN_KEY, fn, opts = {}) {
152
177
  let count = 0, { key, maxTimes: max = 1 } = isStr(opts) ? { key: opts } : opts;
153
178
  const getReg = () => JSON.parse(localStorage.getItem(FN_KEY) || "{}"), setReg = (r) => localStorage.setItem(FN_KEY, JSON.stringify(r));
@@ -171,103 +196,21 @@ function bindCleanupToSignal(cleanup, signal) {
171
196
  }
172
197
 
173
198
  // src/core/keys.ts
174
- var import_utils5 = require("sia-reactor/utils");
175
-
176
- // src/mixins/methd.ts
177
199
  var import_utils6 = require("sia-reactor/utils");
178
200
 
179
- // src/quirks/scroll.ts
180
- function initVScrollerator({ baseSpeed = 3, maxSpeed = 10, stepDelay = 2e3, baseRate = 16, lineHeight = 80, margin = 80, car = window } = {}) {
181
- let linesPerSec = baseSpeed, accelId = null, lastTime = null;
182
- const drive = (clientY, brake = false, offsetY = 0) => {
183
- if (car !== window) clientY -= offsetY;
184
- const now = performance.now(), speed = linesPerSec * lineHeight * ((lastTime ? now - lastTime : baseRate) / 1e3);
185
- if (!brake && (clientY < margin || clientY > (car.innerHeight ?? car.offsetHeight) - margin)) {
186
- accelId === null ? accelId = setTimeout(() => linesPerSec += 1, stepDelay) : linesPerSec > baseSpeed && (linesPerSec = Math.min(linesPerSec + 1, maxSpeed));
187
- car.scrollBy?.(0, clientY < margin ? -speed : speed);
188
- } else reset();
189
- return lastTime = !brake ? now : null, speed;
190
- };
191
- const reset = () => (accelId && clearTimeout(accelId), accelId = null, linesPerSec = baseSpeed, lastTime = null);
192
- return { drive, reset };
193
- }
194
- function initScrollAssist(el, { pxPerSecond = 80, assistClassName = "t007-scroll-assist", vertical = true, horizontal = true } = {}) {
195
- t007._scrollers ??= /* @__PURE__ */ new WeakMap();
196
- t007._scroller_r_observer ??= new ResizeObserver((entries) => entries.forEach(({ target }) => t007._scrollers.get(target)?.update()));
197
- t007._scroller_m_observer ??= new MutationObserver((entries) => {
198
- const els = /* @__PURE__ */ new Set();
199
- for (const entry of entries) {
200
- let node = entry.target instanceof Element ? entry.target : null;
201
- while (node && !t007._scrollers.has(node)) node = node.parentElement;
202
- if (node) els.add(node);
203
- }
204
- for (const el2 of els) t007._scrollers.get(el2)?.update();
205
- });
206
- const parent = el?.parentElement;
207
- if (!parent || t007._scrollers.has(el)) return;
208
- const assist = {};
209
- let scrollId = null, last = performance.now(), assistWidth = 20, assistHeight = 20;
210
- const update = () => {
211
- const hasInteractive = !!parent.querySelector('button, a[href], input, select, textarea, [contenteditable="true"], [tabindex]:not([tabindex="-1"])');
212
- if (horizontal) {
213
- const w = assist.left?.offsetWidth || assistWidth, check = hasInteractive ? el.clientWidth < w * 2 : false;
214
- assist.left.style.display = check ? "none" : el.scrollLeft > 0 ? "block" : "none";
215
- assist.right.style.display = check ? "none" : el.scrollLeft + el.clientWidth < el.scrollWidth - 1 ? "block" : "none";
216
- assistWidth = w;
217
- }
218
- if (vertical) {
219
- const h = assist.up?.offsetHeight || assistHeight, check = hasInteractive ? el.clientHeight < h * 2 : false;
220
- assist.up.style.display = check ? "none" : el.scrollTop > 0 ? "block" : "none";
221
- assist.down.style.display = check ? "none" : el.scrollTop + el.clientHeight < el.scrollHeight - 1 ? "block" : "none";
222
- assistHeight = h;
223
- }
224
- };
225
- const scroll = (dir) => {
226
- const frame = () => {
227
- const now = performance.now(), dt = now - last;
228
- last = now;
229
- const d = pxPerSecond * dt / 1e3;
230
- if (dir === "left") el.scrollLeft = Math.max(0, el.scrollLeft - d);
231
- if (dir === "right") el.scrollLeft = Math.min(el.scrollWidth - el.clientWidth, el.scrollLeft + d);
232
- if (dir === "up") el.scrollTop = Math.max(0, el.scrollTop - d);
233
- if (dir === "down") el.scrollTop = Math.min(el.scrollHeight - el.clientHeight, el.scrollTop + d);
234
- scrollId = requestAnimationFrame(frame);
235
- };
236
- last = performance.now();
237
- frame();
238
- };
239
- const stop = () => (cancelAnimationFrame(scrollId ?? 0), scrollId = null);
240
- const addAssist = (dir) => {
241
- const div = (0, import_utils.createEl)("div", { className: assistClassName }, { scrollDirection: dir }, { display: "none" });
242
- if (!div) return;
243
- ["pointerenter", "dragenter"].forEach((evt) => div.addEventListener(evt, () => scroll(dir)));
244
- ["pointerleave", "pointerup", "pointercancel", "dragleave", "dragend"].forEach((evt) => div.addEventListener(evt, stop));
245
- dir === "left" || dir === "up" ? parent.insertBefore(div, el) : parent.append(div);
246
- assist[dir] = div;
247
- };
248
- if (horizontal) ["left", "right"].forEach(addAssist);
249
- if (vertical) ["up", "down"].forEach(addAssist);
250
- el.addEventListener("scroll", update);
251
- t007._scroller_r_observer.observe(el);
252
- t007._scroller_m_observer.observe(el, { childList: true, subtree: true, characterData: true });
253
- t007._scrollers.set(el, {
254
- update,
255
- destroy() {
256
- stop();
257
- el.removeEventListener("scroll", update);
258
- t007._scroller_r_observer.unobserve(el);
259
- t007._scrollers.delete(el);
260
- Object.values(assist).forEach((a) => a.remove());
261
- }
262
- });
263
- return update(), t007._scrollers.get(el);
201
+ // src/core/file.ts
202
+ function formatSize(bytes, decimals = 3, base = 1e3) {
203
+ if (bytes < base) return `${bytes} byte${bytes == 1 ? "" : "s"}`;
204
+ const units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"], exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(base)), units.length - 1);
205
+ return `${(bytes / Math.pow(base, exponent)).toFixed(decimals).replace(/\.0+$/, "")} ${units[exponent]}`;
264
206
  }
265
- var removeScrollAssist = (el) => t007._scrollers.get(el)?.destroy();
207
+
208
+ // src/mixins/methd.ts
209
+ var import_utils7 = require("sia-reactor/utils");
266
210
 
267
211
  // src/index.ts
268
212
  if ("undefined" !== typeof window) {
269
- window.t007 ??= {};
270
- t007.VIRTUAL_RESOURCE = VIRTUAL_RESOURCE;
213
+ (window.t007 ??= {}).VIRTUAL_RESOURCE = VIRTUAL_RESOURCE;
271
214
  window.T007_TOAST_JS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/toast@latest`;
272
215
  window.T007_INPUT_JS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/input@latest`;
273
216
  window.T007_DIALOG_JS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/dialog@latest`;
@@ -277,6 +220,9 @@ if ("undefined" !== typeof window) {
277
220
  }
278
221
  // Annotate the CommonJS export names for ESM import in node:
279
222
  0 && (module.exports = {
223
+ INTERACTIVE_SELECTOR,
224
+ NIL,
225
+ NOOP,
280
226
  VIRTUAL_RESOURCE,
281
227
  assignEl,
282
228
  bindAllMethods,
@@ -288,16 +234,17 @@ if ("undefined" !== typeof window) {
288
234
  deepBreath,
289
235
  formatKeyForDisplay,
290
236
  formatKeyShortcutsForDisplay,
237
+ formatSize,
238
+ getActiveEl,
291
239
  getTermsForKey,
292
240
  guardAllMethods,
293
241
  guardMethod,
294
242
  inBoolArrOpt,
295
- initScrollAssist,
296
- initVScrollerator,
297
243
  isArr,
298
244
  isBool,
299
245
  isDef,
300
246
  isFunc,
247
+ isInteractive,
301
248
  isIter,
302
249
  isNum,
303
250
  isObj,
@@ -311,9 +258,12 @@ if ("undefined" !== typeof window) {
311
258
  matchKeys,
312
259
  mockAsync,
313
260
  onAllMethods,
261
+ parseCSSSize,
262
+ parseCSSTime,
314
263
  parseForARIAKS,
315
264
  parseKeyCombo,
316
- removeScrollAssist,
265
+ pxToRem,
266
+ remToPx,
317
267
  requestAnimationFrame,
318
268
  setInterval,
319
269
  setTimeout,