@chenzy-design/core 0.1.0
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/LICENSE +21 -0
- package/dist/back-top.d.ts +16 -0
- package/dist/back-top.d.ts.map +1 -0
- package/dist/back-top.js +29 -0
- package/dist/back-top.js.map +1 -0
- package/dist/back-top.test.d.ts +2 -0
- package/dist/back-top.test.d.ts.map +1 -0
- package/dist/back-top.test.js +44 -0
- package/dist/back-top.test.js.map +1 -0
- package/dist/banner.d.ts +19 -0
- package/dist/banner.d.ts.map +1 -0
- package/dist/banner.js +20 -0
- package/dist/banner.js.map +1 -0
- package/dist/banner.test.d.ts +2 -0
- package/dist/banner.test.d.ts.map +1 -0
- package/dist/banner.test.js +29 -0
- package/dist/banner.test.js.map +1 -0
- package/dist/breakpoints.d.ts +30 -0
- package/dist/breakpoints.d.ts.map +1 -0
- package/dist/breakpoints.js +45 -0
- package/dist/breakpoints.js.map +1 -0
- package/dist/breakpoints.test.d.ts +2 -0
- package/dist/breakpoints.test.d.ts.map +1 -0
- package/dist/breakpoints.test.js +46 -0
- package/dist/breakpoints.test.js.map +1 -0
- package/dist/calendar.d.ts +63 -0
- package/dist/calendar.d.ts.map +1 -0
- package/dist/calendar.js +94 -0
- package/dist/calendar.js.map +1 -0
- package/dist/calendar.test.d.ts +2 -0
- package/dist/calendar.test.d.ts.map +1 -0
- package/dist/calendar.test.js +88 -0
- package/dist/calendar.test.js.map +1 -0
- package/dist/cascader.d.ts +64 -0
- package/dist/cascader.d.ts.map +1 -0
- package/dist/cascader.js +79 -0
- package/dist/cascader.js.map +1 -0
- package/dist/cascader.test.d.ts +2 -0
- package/dist/cascader.test.d.ts.map +1 -0
- package/dist/cascader.test.js +107 -0
- package/dist/cascader.test.js.map +1 -0
- package/dist/color.d.ts +70 -0
- package/dist/color.d.ts.map +1 -0
- package/dist/color.js +217 -0
- package/dist/color.js.map +1 -0
- package/dist/color.test.d.ts +2 -0
- package/dist/color.test.d.ts.map +1 -0
- package/dist/color.test.js +161 -0
- package/dist/color.test.js.map +1 -0
- package/dist/config-provider.d.ts +57 -0
- package/dist/config-provider.d.ts.map +1 -0
- package/dist/config-provider.js +49 -0
- package/dist/config-provider.js.map +1 -0
- package/dist/config-provider.test.d.ts +2 -0
- package/dist/config-provider.test.d.ts.map +1 -0
- package/dist/config-provider.test.js +76 -0
- package/dist/config-provider.test.js.map +1 -0
- package/dist/copyable.d.ts +43 -0
- package/dist/copyable.d.ts.map +1 -0
- package/dist/copyable.js +102 -0
- package/dist/copyable.js.map +1 -0
- package/dist/copyable.test.d.ts +2 -0
- package/dist/copyable.test.d.ts.map +1 -0
- package/dist/copyable.test.js +97 -0
- package/dist/copyable.test.js.map +1 -0
- package/dist/date.d.ts +86 -0
- package/dist/date.d.ts.map +1 -0
- package/dist/date.js +226 -0
- package/dist/date.js.map +1 -0
- package/dist/date.test.d.ts +2 -0
- package/dist/date.test.d.ts.map +1 -0
- package/dist/date.test.js +171 -0
- package/dist/date.test.js.map +1 -0
- package/dist/dismiss.d.ts +28 -0
- package/dist/dismiss.d.ts.map +1 -0
- package/dist/dismiss.js +42 -0
- package/dist/dismiss.js.map +1 -0
- package/dist/editable.d.ts +59 -0
- package/dist/editable.d.ts.map +1 -0
- package/dist/editable.js +85 -0
- package/dist/editable.js.map +1 -0
- package/dist/editable.test.d.ts +2 -0
- package/dist/editable.test.d.ts.map +1 -0
- package/dist/editable.test.js +111 -0
- package/dist/editable.test.js.map +1 -0
- package/dist/ellipsis.d.ts +76 -0
- package/dist/ellipsis.d.ts.map +1 -0
- package/dist/ellipsis.js +99 -0
- package/dist/ellipsis.js.map +1 -0
- package/dist/ellipsis.test.d.ts +2 -0
- package/dist/ellipsis.test.d.ts.map +1 -0
- package/dist/ellipsis.test.js +94 -0
- package/dist/ellipsis.test.js.map +1 -0
- package/dist/floating.d.ts +78 -0
- package/dist/floating.d.ts.map +1 -0
- package/dist/floating.js +169 -0
- package/dist/floating.js.map +1 -0
- package/dist/floating.test.d.ts +2 -0
- package/dist/floating.test.d.ts.map +1 -0
- package/dist/floating.test.js +169 -0
- package/dist/floating.test.js.map +1 -0
- package/dist/focus-trap.d.ts +24 -0
- package/dist/focus-trap.d.ts.map +1 -0
- package/dist/focus-trap.js +64 -0
- package/dist/focus-trap.js.map +1 -0
- package/dist/form.d.ts +131 -0
- package/dist/form.d.ts.map +1 -0
- package/dist/form.js +257 -0
- package/dist/form.js.map +1 -0
- package/dist/form.test.d.ts +2 -0
- package/dist/form.test.d.ts.map +1 -0
- package/dist/form.test.js +323 -0
- package/dist/form.test.js.map +1 -0
- package/dist/highlight.d.ts +57 -0
- package/dist/highlight.d.ts.map +1 -0
- package/dist/highlight.js +124 -0
- package/dist/highlight.js.map +1 -0
- package/dist/highlight.test.d.ts +2 -0
- package/dist/highlight.test.d.ts.map +1 -0
- package/dist/highlight.test.js +155 -0
- package/dist/highlight.test.js.map +1 -0
- package/dist/id.d.ts +4 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +14 -0
- package/dist/id.js.map +1 -0
- package/dist/id.test.d.ts +2 -0
- package/dist/id.test.d.ts.map +1 -0
- package/dist/id.test.js +13 -0
- package/dist/id.test.js.map +1 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/inert-background.d.ts +27 -0
- package/dist/inert-background.d.ts.map +1 -0
- package/dist/inert-background.js +92 -0
- package/dist/inert-background.js.map +1 -0
- package/dist/inert-background.test.d.ts +2 -0
- package/dist/inert-background.test.d.ts.map +1 -0
- package/dist/inert-background.test.js +62 -0
- package/dist/inert-background.test.js.map +1 -0
- package/dist/input-number.d.ts +34 -0
- package/dist/input-number.d.ts.map +1 -0
- package/dist/input-number.js +69 -0
- package/dist/input-number.js.map +1 -0
- package/dist/input-number.test.d.ts +2 -0
- package/dist/input-number.test.d.ts.map +1 -0
- package/dist/input-number.test.js +74 -0
- package/dist/input-number.test.js.map +1 -0
- package/dist/list-selection.d.ts +38 -0
- package/dist/list-selection.d.ts.map +1 -0
- package/dist/list-selection.js +61 -0
- package/dist/list-selection.js.map +1 -0
- package/dist/list-selection.test.d.ts +2 -0
- package/dist/list-selection.test.d.ts.map +1 -0
- package/dist/list-selection.test.js +61 -0
- package/dist/list-selection.test.js.map +1 -0
- package/dist/live-announcer.d.ts +38 -0
- package/dist/live-announcer.d.ts.map +1 -0
- package/dist/live-announcer.js +89 -0
- package/dist/live-announcer.js.map +1 -0
- package/dist/live-announcer.test.d.ts +2 -0
- package/dist/live-announcer.test.d.ts.map +1 -0
- package/dist/live-announcer.test.js +70 -0
- package/dist/live-announcer.test.js.map +1 -0
- package/dist/lottie-icon.d.ts +88 -0
- package/dist/lottie-icon.d.ts.map +1 -0
- package/dist/lottie-icon.js +84 -0
- package/dist/lottie-icon.js.map +1 -0
- package/dist/lottie-icon.test.d.ts +2 -0
- package/dist/lottie-icon.test.d.ts.map +1 -0
- package/dist/lottie-icon.test.js +88 -0
- package/dist/lottie-icon.test.js.map +1 -0
- package/dist/notification.d.ts +61 -0
- package/dist/notification.d.ts.map +1 -0
- package/dist/notification.js +133 -0
- package/dist/notification.js.map +1 -0
- package/dist/notification.test.d.ts +2 -0
- package/dist/notification.test.d.ts.map +1 -0
- package/dist/notification.test.js +103 -0
- package/dist/notification.test.js.map +1 -0
- package/dist/overflow-list.d.ts +102 -0
- package/dist/overflow-list.d.ts.map +1 -0
- package/dist/overflow-list.js +159 -0
- package/dist/overflow-list.js.map +1 -0
- package/dist/overflow-list.test.d.ts +2 -0
- package/dist/overflow-list.test.d.ts.map +1 -0
- package/dist/overflow-list.test.js +223 -0
- package/dist/overflow-list.test.js.map +1 -0
- package/dist/pagination.d.ts +51 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +127 -0
- package/dist/pagination.js.map +1 -0
- package/dist/pagination.test.d.ts +2 -0
- package/dist/pagination.test.d.ts.map +1 -0
- package/dist/pagination.test.js +147 -0
- package/dist/pagination.test.js.map +1 -0
- package/dist/progress.d.ts +64 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +92 -0
- package/dist/progress.js.map +1 -0
- package/dist/progress.test.d.ts +2 -0
- package/dist/progress.test.d.ts.map +1 -0
- package/dist/progress.test.js +79 -0
- package/dist/progress.test.js.map +1 -0
- package/dist/resize-observer.d.ts +133 -0
- package/dist/resize-observer.d.ts.map +1 -0
- package/dist/resize-observer.js +358 -0
- package/dist/resize-observer.js.map +1 -0
- package/dist/resize-observer.test.d.ts +2 -0
- package/dist/resize-observer.test.d.ts.map +1 -0
- package/dist/resize-observer.test.js +377 -0
- package/dist/resize-observer.test.js.map +1 -0
- package/dist/roving.d.ts +26 -0
- package/dist/roving.d.ts.map +1 -0
- package/dist/roving.js +61 -0
- package/dist/roving.js.map +1 -0
- package/dist/roving.test.d.ts +2 -0
- package/dist/roving.test.d.ts.map +1 -0
- package/dist/roving.test.js +48 -0
- package/dist/roving.test.js.map +1 -0
- package/dist/scroll-list.d.ts +81 -0
- package/dist/scroll-list.d.ts.map +1 -0
- package/dist/scroll-list.js +175 -0
- package/dist/scroll-list.js.map +1 -0
- package/dist/scroll-list.test.d.ts +2 -0
- package/dist/scroll-list.test.d.ts.map +1 -0
- package/dist/scroll-list.test.js +135 -0
- package/dist/scroll-list.test.js.map +1 -0
- package/dist/scroll-lock.d.ts +11 -0
- package/dist/scroll-lock.d.ts.map +1 -0
- package/dist/scroll-lock.js +45 -0
- package/dist/scroll-lock.js.map +1 -0
- package/dist/scroll-lock.test.d.ts +2 -0
- package/dist/scroll-lock.test.d.ts.map +1 -0
- package/dist/scroll-lock.test.js +55 -0
- package/dist/scroll-lock.test.js.map +1 -0
- package/dist/sider.d.ts +26 -0
- package/dist/sider.d.ts.map +1 -0
- package/dist/sider.js +55 -0
- package/dist/sider.js.map +1 -0
- package/dist/sider.test.d.ts +2 -0
- package/dist/sider.test.d.ts.map +1 -0
- package/dist/sider.test.js +29 -0
- package/dist/sider.test.js.map +1 -0
- package/dist/spin.d.ts +25 -0
- package/dist/spin.d.ts.map +1 -0
- package/dist/spin.js +96 -0
- package/dist/spin.js.map +1 -0
- package/dist/spin.test.d.ts +2 -0
- package/dist/spin.test.d.ts.map +1 -0
- package/dist/spin.test.js +80 -0
- package/dist/spin.test.js.map +1 -0
- package/dist/table.d.ts +101 -0
- package/dist/table.d.ts.map +1 -0
- package/dist/table.js +244 -0
- package/dist/table.js.map +1 -0
- package/dist/table.test.d.ts +2 -0
- package/dist/table.test.d.ts.map +1 -0
- package/dist/table.test.js +184 -0
- package/dist/table.test.js.map +1 -0
- package/dist/textarea.d.ts +48 -0
- package/dist/textarea.d.ts.map +1 -0
- package/dist/textarea.js +76 -0
- package/dist/textarea.js.map +1 -0
- package/dist/textarea.test.d.ts +2 -0
- package/dist/textarea.test.d.ts.map +1 -0
- package/dist/textarea.test.js +77 -0
- package/dist/textarea.test.js.map +1 -0
- package/dist/time.d.ts +93 -0
- package/dist/time.d.ts.map +1 -0
- package/dist/time.js +181 -0
- package/dist/time.js.map +1 -0
- package/dist/time.test.d.ts +2 -0
- package/dist/time.test.d.ts.map +1 -0
- package/dist/time.test.js +159 -0
- package/dist/time.test.js.map +1 -0
- package/dist/toast.d.ts +60 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +135 -0
- package/dist/toast.js.map +1 -0
- package/dist/toast.test.d.ts +2 -0
- package/dist/toast.test.d.ts.map +1 -0
- package/dist/toast.test.js +127 -0
- package/dist/toast.test.js.map +1 -0
- package/dist/tree.d.ts +129 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +351 -0
- package/dist/tree.js.map +1 -0
- package/dist/tree.test.d.ts +2 -0
- package/dist/tree.test.d.ts.map +1 -0
- package/dist/tree.test.js +291 -0
- package/dist/tree.test.js.map +1 -0
- package/dist/upload.d.ts +62 -0
- package/dist/upload.d.ts.map +1 -0
- package/dist/upload.js +85 -0
- package/dist/upload.js.map +1 -0
- package/dist/upload.test.d.ts +2 -0
- package/dist/upload.test.d.ts.map +1 -0
- package/dist/upload.test.js +169 -0
- package/dist/upload.test.js.map +1 -0
- package/dist/virtual-list.d.ts +83 -0
- package/dist/virtual-list.d.ts.map +1 -0
- package/dist/virtual-list.js +143 -0
- package/dist/virtual-list.js.map +1 -0
- package/dist/virtual-list.test.d.ts +2 -0
- package/dist/virtual-list.test.d.ts.map +1 -0
- package/dist/virtual-list.test.js +148 -0
- package/dist/virtual-list.test.js.map +1 -0
- package/package.json +22 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useInertBackground — hide page content behind a modal overlay from assistive
|
|
3
|
+
* tech and pointer/keyboard interaction while the overlay is open.
|
|
4
|
+
*
|
|
5
|
+
* Pass the overlay's portal root (the element appended to body/getContainer).
|
|
6
|
+
* Every *sibling* of that root (the rest of the page, plus any overlay opened
|
|
7
|
+
* earlier) is marked `inert` + `aria-hidden="true"`; on release the originals
|
|
8
|
+
* are restored. See specs/components/feedback/Modal.spec.md §6 ("背景内容对 SR
|
|
9
|
+
* aria-hidden/inert").
|
|
10
|
+
*
|
|
11
|
+
* Stacked overlays: a module-level stack tracks every active overlay root. Only
|
|
12
|
+
* the *topmost* (most recently activated) overlay drives the inert set — its
|
|
13
|
+
* siblings (including lower overlays) get hidden, while the topmost overlay
|
|
14
|
+
* itself stays interactive. When it releases, the previous overlay re-applies.
|
|
15
|
+
* This keeps nested Modal/Drawer/SideSheet correct without inerting the layer
|
|
16
|
+
* the user is currently working in.
|
|
17
|
+
*
|
|
18
|
+
* No framework deps; client-only (guards document). Returned function releases.
|
|
19
|
+
*/
|
|
20
|
+
const INERT_MARK = 'data-cd-inert-bg';
|
|
21
|
+
// Active overlay roots, in activation order. Last = topmost.
|
|
22
|
+
const stack = [];
|
|
23
|
+
// Elements we marked, with the attribute values to restore on release.
|
|
24
|
+
// We toggle the `inert` *attribute* (not the IDL property) so it reflects
|
|
25
|
+
// consistently across browsers and SSR-ish DOM impls.
|
|
26
|
+
let hidden = [];
|
|
27
|
+
function clearHidden() {
|
|
28
|
+
for (const { el, prevInert, prevAriaHidden } of hidden) {
|
|
29
|
+
if (prevInert)
|
|
30
|
+
el.setAttribute('inert', '');
|
|
31
|
+
else
|
|
32
|
+
el.removeAttribute('inert');
|
|
33
|
+
if (prevAriaHidden === null)
|
|
34
|
+
el.removeAttribute('aria-hidden');
|
|
35
|
+
else
|
|
36
|
+
el.setAttribute('aria-hidden', prevAriaHidden);
|
|
37
|
+
}
|
|
38
|
+
hidden = [];
|
|
39
|
+
}
|
|
40
|
+
function apply() {
|
|
41
|
+
// Restore whatever the previous topmost overlay hid, then re-hide for the new
|
|
42
|
+
// topmost. Simpler and correct than diffing when the active root changes.
|
|
43
|
+
clearHidden();
|
|
44
|
+
const top = stack[stack.length - 1];
|
|
45
|
+
if (!top || !top.parentNode)
|
|
46
|
+
return;
|
|
47
|
+
const parent = top.parentNode;
|
|
48
|
+
for (const node of Array.from(parent.childNodes)) {
|
|
49
|
+
if (!(node instanceof HTMLElement))
|
|
50
|
+
continue;
|
|
51
|
+
if (node === top)
|
|
52
|
+
continue;
|
|
53
|
+
// Never inert another active overlay root that sits above us — but since we
|
|
54
|
+
// always hide for the *topmost*, every other root here is below `top`, so
|
|
55
|
+
// hiding them is what we want.
|
|
56
|
+
hidden.push({
|
|
57
|
+
el: node,
|
|
58
|
+
prevInert: node.hasAttribute('inert'),
|
|
59
|
+
prevAriaHidden: node.getAttribute('aria-hidden'),
|
|
60
|
+
});
|
|
61
|
+
node.setAttribute('inert', '');
|
|
62
|
+
node.setAttribute('aria-hidden', 'true');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Mark `root`'s siblings inert/aria-hidden. `root` should be the overlay's
|
|
67
|
+
* portal root element. Returns a release function (idempotent).
|
|
68
|
+
*/
|
|
69
|
+
export function useInertBackground(root) {
|
|
70
|
+
if (typeof document === 'undefined' || !root)
|
|
71
|
+
return () => { };
|
|
72
|
+
root.setAttribute(INERT_MARK, '');
|
|
73
|
+
stack.push(root);
|
|
74
|
+
apply();
|
|
75
|
+
let released = false;
|
|
76
|
+
return () => {
|
|
77
|
+
if (released)
|
|
78
|
+
return;
|
|
79
|
+
released = true;
|
|
80
|
+
const i = stack.indexOf(root);
|
|
81
|
+
if (i !== -1)
|
|
82
|
+
stack.splice(i, 1);
|
|
83
|
+
root.removeAttribute(INERT_MARK);
|
|
84
|
+
apply();
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/** test-only reset of internal state */
|
|
88
|
+
export function __resetInertBackground() {
|
|
89
|
+
clearHidden();
|
|
90
|
+
stack.length = 0;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=inert-background.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inert-background.js","sourceRoot":"","sources":["../src/inert-background.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,UAAU,GAAG,kBAAkB,CAAC;AAEtC,6DAA6D;AAC7D,MAAM,KAAK,GAAkB,EAAE,CAAC;AAChC,uEAAuE;AACvE,0EAA0E;AAC1E,sDAAsD;AACtD,IAAI,MAAM,GAIL,EAAE,CAAC;AAER,SAAS,WAAW;IAClB,KAAK,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,IAAI,MAAM,EAAE,CAAC;QACvD,IAAI,SAAS;YAAE,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;;YACvC,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,cAAc,KAAK,IAAI;YAAE,EAAE,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC;;YAC1D,EAAE,CAAC,YAAY,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;IACtD,CAAC;IACD,MAAM,GAAG,EAAE,CAAC;AACd,CAAC;AAED,SAAS,KAAK;IACZ,8EAA8E;IAC9E,0EAA0E;IAC1E,WAAW,EAAE,CAAC;IACd,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACpC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU;QAAE,OAAO;IACpC,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QACjD,IAAI,CAAC,CAAC,IAAI,YAAY,WAAW,CAAC;YAAE,SAAS;QAC7C,IAAI,IAAI,KAAK,GAAG;YAAE,SAAS;QAC3B,4EAA4E;QAC5E,0EAA0E;QAC1E,+BAA+B;QAC/B,MAAM,CAAC,IAAI,CAAC;YACV,EAAE,EAAE,IAAI;YACR,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;YACrC,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC;SACjD,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC/B,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAiB;IAClD,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,CAAC,IAAI;QAAE,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;IAE9D,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAClC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,KAAK,EAAE,CAAC;IAER,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,OAAO,GAAG,EAAE;QACV,IAAI,QAAQ;YAAE,OAAO;QACrB,QAAQ,GAAG,IAAI,CAAC;QAChB,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK,CAAC,CAAC;YAAE,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACjC,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;QACjC,KAAK,EAAE,CAAC;IACV,CAAC,CAAC;AACJ,CAAC;AAED,wCAAwC;AACxC,MAAM,UAAU,sBAAsB;IACpC,WAAW,EAAE,CAAC;IACd,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inert-background.test.d.ts","sourceRoot":"","sources":["../src/inert-background.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
3
|
+
import { useInertBackground, __resetInertBackground, } from './inert-background.js';
|
|
4
|
+
let page;
|
|
5
|
+
let overlayA;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
document.body.innerHTML = '';
|
|
8
|
+
page = document.createElement('div');
|
|
9
|
+
page.id = 'page';
|
|
10
|
+
overlayA = document.createElement('div');
|
|
11
|
+
overlayA.id = 'overlay-a';
|
|
12
|
+
document.body.append(page, overlayA);
|
|
13
|
+
});
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
__resetInertBackground();
|
|
16
|
+
document.body.innerHTML = '';
|
|
17
|
+
});
|
|
18
|
+
describe('useInertBackground', () => {
|
|
19
|
+
it('hides siblings of the overlay root and restores on release', () => {
|
|
20
|
+
const release = useInertBackground(overlayA);
|
|
21
|
+
expect(page.getAttribute('aria-hidden')).toBe('true');
|
|
22
|
+
expect(page.hasAttribute('inert')).toBe(true);
|
|
23
|
+
// the overlay root itself stays interactive
|
|
24
|
+
expect(overlayA.getAttribute('aria-hidden')).toBeNull();
|
|
25
|
+
expect(overlayA.hasAttribute('inert')).toBe(false);
|
|
26
|
+
release();
|
|
27
|
+
expect(page.getAttribute('aria-hidden')).toBeNull();
|
|
28
|
+
expect(page.hasAttribute('inert')).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
it('release is idempotent', () => {
|
|
31
|
+
const release = useInertBackground(overlayA);
|
|
32
|
+
release();
|
|
33
|
+
release();
|
|
34
|
+
expect(page.getAttribute('aria-hidden')).toBeNull();
|
|
35
|
+
});
|
|
36
|
+
it('restores a pre-existing aria-hidden value', () => {
|
|
37
|
+
page.setAttribute('aria-hidden', 'false');
|
|
38
|
+
const release = useInertBackground(overlayA);
|
|
39
|
+
expect(page.getAttribute('aria-hidden')).toBe('true');
|
|
40
|
+
release();
|
|
41
|
+
expect(page.getAttribute('aria-hidden')).toBe('false');
|
|
42
|
+
});
|
|
43
|
+
it('stacked overlays: topmost hides lower overlay, keeps itself interactive', () => {
|
|
44
|
+
const overlayB = document.createElement('div');
|
|
45
|
+
overlayB.id = 'overlay-b';
|
|
46
|
+
document.body.appendChild(overlayB);
|
|
47
|
+
const releaseA = useInertBackground(overlayA);
|
|
48
|
+
expect(page.hasAttribute('inert')).toBe(true);
|
|
49
|
+
// B opens on top → page AND overlayA become inert; B stays interactive.
|
|
50
|
+
const releaseB = useInertBackground(overlayB);
|
|
51
|
+
expect(page.hasAttribute('inert')).toBe(true);
|
|
52
|
+
expect(overlayA.hasAttribute('inert')).toBe(true);
|
|
53
|
+
expect(overlayB.hasAttribute('inert')).toBe(false);
|
|
54
|
+
// B closes → A is topmost again: page inert, A interactive.
|
|
55
|
+
releaseB();
|
|
56
|
+
expect(page.hasAttribute('inert')).toBe(true);
|
|
57
|
+
expect(overlayA.hasAttribute('inert')).toBe(false);
|
|
58
|
+
releaseA();
|
|
59
|
+
expect(page.hasAttribute('inert')).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=inert-background.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inert-background.test.js","sourceRoot":"","sources":["../src/inert-background.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createInputNumber helpers — framework-agnostic numeric primitives for InputNumber.
|
|
3
|
+
* Pure functions only (clamp/boundaryMode, precision round, float-safe step,
|
|
4
|
+
* locale-aware default formatting). The svelte layer owns DOM, listeners and
|
|
5
|
+
* the editing-text state machine; it delegates the math here so it stays testable.
|
|
6
|
+
* See specs/components/input/InputNumber.spec.md §3.
|
|
7
|
+
*/
|
|
8
|
+
/** Boundary handling: 'clamp' pins to [min,max]; 'strict' rejects out-of-range. */
|
|
9
|
+
export type BoundaryMode = 'clamp' | 'strict';
|
|
10
|
+
/**
|
|
11
|
+
* clampWithMode — apply min/max according to boundaryMode.
|
|
12
|
+
* - 'clamp': returns the value pinned into [min,max].
|
|
13
|
+
* - 'strict': returns null when `n` lies outside [min,max] (caller rolls back).
|
|
14
|
+
*/
|
|
15
|
+
export declare function clampWithMode(n: number, min: number, max: number, mode?: BoundaryMode): number | null;
|
|
16
|
+
/** Which boundary (if any) `n` touches/exceeds given [min,max]. */
|
|
17
|
+
export declare function boundaryHitOf(n: number, min: number, max: number): 'min' | 'max' | null;
|
|
18
|
+
/** round `n` to `precision` decimal places (undefined → unchanged). */
|
|
19
|
+
export declare function roundToPrecision(n: number, precision?: number): number;
|
|
20
|
+
/** count of decimal places in a number's default string form. */
|
|
21
|
+
export declare function decimalsOf(n: number): number;
|
|
22
|
+
/**
|
|
23
|
+
* addStep — float-safe addition using integer scaling, avoiding 0.1+0.2 drift.
|
|
24
|
+
*/
|
|
25
|
+
export declare function addStep(base: number, delta: number): number;
|
|
26
|
+
/**
|
|
27
|
+
* formatWithLocale — default display string for a value using Intl.NumberFormat,
|
|
28
|
+
* cached per (locale, options). Used only when a `locale` is supplied and no
|
|
29
|
+
* custom formatter is given; otherwise the svelte layer keeps `String(n)`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function formatWithLocale(n: number, locale: string, options?: Intl.NumberFormatOptions): string;
|
|
32
|
+
/** reset the Intl format cache (test determinism). */
|
|
33
|
+
export declare function __resetNumberFormatCache(): void;
|
|
34
|
+
//# sourceMappingURL=input-number.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-number.d.ts","sourceRoot":"","sources":["../src/input-number.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,mFAAmF;AACnF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE9C;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,CAAC,EAAE,MAAM,EACT,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,YAAsB,GAC3B,MAAM,GAAG,IAAI,CAMf;AAED,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,CAIvF;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAItE;AAED,iEAAiE;AACjE,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAI5C;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAI3D;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,CAAC,EAAE,MAAM,EACT,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,GACjC,MAAM,CAQR;AAED,sDAAsD;AACtD,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createInputNumber helpers — framework-agnostic numeric primitives for InputNumber.
|
|
3
|
+
* Pure functions only (clamp/boundaryMode, precision round, float-safe step,
|
|
4
|
+
* locale-aware default formatting). The svelte layer owns DOM, listeners and
|
|
5
|
+
* the editing-text state machine; it delegates the math here so it stays testable.
|
|
6
|
+
* See specs/components/input/InputNumber.spec.md §3.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* clampWithMode — apply min/max according to boundaryMode.
|
|
10
|
+
* - 'clamp': returns the value pinned into [min,max].
|
|
11
|
+
* - 'strict': returns null when `n` lies outside [min,max] (caller rolls back).
|
|
12
|
+
*/
|
|
13
|
+
export function clampWithMode(n, min, max, mode = 'clamp') {
|
|
14
|
+
if (mode === 'strict') {
|
|
15
|
+
if (n < min || n > max)
|
|
16
|
+
return null;
|
|
17
|
+
return n;
|
|
18
|
+
}
|
|
19
|
+
return Math.min(max, Math.max(min, n));
|
|
20
|
+
}
|
|
21
|
+
/** Which boundary (if any) `n` touches/exceeds given [min,max]. */
|
|
22
|
+
export function boundaryHitOf(n, min, max) {
|
|
23
|
+
if (n <= min && Number.isFinite(min))
|
|
24
|
+
return 'min';
|
|
25
|
+
if (n >= max && Number.isFinite(max))
|
|
26
|
+
return 'max';
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
/** round `n` to `precision` decimal places (undefined → unchanged). */
|
|
30
|
+
export function roundToPrecision(n, precision) {
|
|
31
|
+
if (precision === undefined)
|
|
32
|
+
return n;
|
|
33
|
+
const factor = 10 ** precision;
|
|
34
|
+
return Math.round(n * factor) / factor;
|
|
35
|
+
}
|
|
36
|
+
/** count of decimal places in a number's default string form. */
|
|
37
|
+
export function decimalsOf(n) {
|
|
38
|
+
const s = String(n);
|
|
39
|
+
const dot = s.indexOf('.');
|
|
40
|
+
return dot === -1 ? 0 : s.length - dot - 1;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* addStep — float-safe addition using integer scaling, avoiding 0.1+0.2 drift.
|
|
44
|
+
*/
|
|
45
|
+
export function addStep(base, delta) {
|
|
46
|
+
const decimals = Math.max(decimalsOf(base), decimalsOf(delta));
|
|
47
|
+
const factor = 10 ** decimals;
|
|
48
|
+
return (Math.round(base * factor) + Math.round(delta * factor)) / factor;
|
|
49
|
+
}
|
|
50
|
+
const numberFormatCache = new Map();
|
|
51
|
+
/**
|
|
52
|
+
* formatWithLocale — default display string for a value using Intl.NumberFormat,
|
|
53
|
+
* cached per (locale, options). Used only when a `locale` is supplied and no
|
|
54
|
+
* custom formatter is given; otherwise the svelte layer keeps `String(n)`.
|
|
55
|
+
*/
|
|
56
|
+
export function formatWithLocale(n, locale, options) {
|
|
57
|
+
const key = `${locale}|${JSON.stringify(options ?? {})}`;
|
|
58
|
+
let fmt = numberFormatCache.get(key);
|
|
59
|
+
if (!fmt) {
|
|
60
|
+
fmt = new Intl.NumberFormat(locale, options);
|
|
61
|
+
numberFormatCache.set(key, fmt);
|
|
62
|
+
}
|
|
63
|
+
return fmt.format(n);
|
|
64
|
+
}
|
|
65
|
+
/** reset the Intl format cache (test determinism). */
|
|
66
|
+
export function __resetNumberFormatCache() {
|
|
67
|
+
numberFormatCache.clear();
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=input-number.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-number.js","sourceRoot":"","sources":["../src/input-number.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,CAAS,EACT,GAAW,EACX,GAAW,EACX,OAAqB,OAAO;IAE5B,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,GAAG;YAAE,OAAO,IAAI,CAAC;QACpC,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,aAAa,CAAC,CAAS,EAAE,GAAW,EAAE,GAAW;IAC/D,IAAI,CAAC,IAAI,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACnD,IAAI,CAAC,IAAI,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACnD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,gBAAgB,CAAC,CAAS,EAAE,SAAkB;IAC5D,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,EAAE,IAAI,SAAS,CAAC;IAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC;AACzC,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACpB,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,KAAa;IACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,EAAE,IAAI,QAAQ,CAAC;IAC9B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC;AAC3E,CAAC;AAED,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAA6B,CAAC;AAE/D;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC9B,CAAS,EACT,MAAc,EACd,OAAkC;IAElC,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;IACzD,IAAI,GAAG,GAAG,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,GAAG,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC7C,iBAAiB,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACvB,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,wBAAwB;IACtC,iBAAiB,CAAC,KAAK,EAAE,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-number.test.d.ts","sourceRoot":"","sources":["../src/input-number.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { clampWithMode, boundaryHitOf, roundToPrecision, decimalsOfNumber, addNumberStep, formatWithLocale, __resetNumberFormatCache, } from './index.js';
|
|
3
|
+
describe('clampWithMode', () => {
|
|
4
|
+
it('clamp mode pins into range', () => {
|
|
5
|
+
expect(clampWithMode(15, 0, 10, 'clamp')).toBe(10);
|
|
6
|
+
expect(clampWithMode(-5, 0, 10, 'clamp')).toBe(0);
|
|
7
|
+
expect(clampWithMode(5, 0, 10, 'clamp')).toBe(5);
|
|
8
|
+
});
|
|
9
|
+
it('clamp is the default mode', () => {
|
|
10
|
+
expect(clampWithMode(99, 0, 10)).toBe(10);
|
|
11
|
+
});
|
|
12
|
+
it('strict mode returns null when out of range', () => {
|
|
13
|
+
expect(clampWithMode(15, 0, 10, 'strict')).toBeNull();
|
|
14
|
+
expect(clampWithMode(-1, 0, 10, 'strict')).toBeNull();
|
|
15
|
+
});
|
|
16
|
+
it('strict mode keeps in-range value', () => {
|
|
17
|
+
expect(clampWithMode(5, 0, 10, 'strict')).toBe(5);
|
|
18
|
+
expect(clampWithMode(0, 0, 10, 'strict')).toBe(0);
|
|
19
|
+
expect(clampWithMode(10, 0, 10, 'strict')).toBe(10);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('boundaryHitOf', () => {
|
|
23
|
+
it('detects min/max touches', () => {
|
|
24
|
+
expect(boundaryHitOf(0, 0, 10)).toBe('min');
|
|
25
|
+
expect(boundaryHitOf(10, 0, 10)).toBe('max');
|
|
26
|
+
expect(boundaryHitOf(5, 0, 10)).toBeNull();
|
|
27
|
+
});
|
|
28
|
+
it('ignores infinite bounds', () => {
|
|
29
|
+
expect(boundaryHitOf(-1e9, -Infinity, Infinity)).toBeNull();
|
|
30
|
+
expect(boundaryHitOf(1e9, -Infinity, Infinity)).toBeNull();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe('roundToPrecision', () => {
|
|
34
|
+
it('rounds to given decimals', () => {
|
|
35
|
+
expect(roundToPrecision(1.2345, 2)).toBe(1.23);
|
|
36
|
+
expect(roundToPrecision(1.235, 2)).toBe(1.24);
|
|
37
|
+
});
|
|
38
|
+
it('passes through when precision undefined', () => {
|
|
39
|
+
expect(roundToPrecision(1.2345)).toBe(1.2345);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('decimalsOfNumber', () => {
|
|
43
|
+
it('counts decimals', () => {
|
|
44
|
+
expect(decimalsOfNumber(1)).toBe(0);
|
|
45
|
+
expect(decimalsOfNumber(1.5)).toBe(1);
|
|
46
|
+
expect(decimalsOfNumber(0.001)).toBe(3);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe('addNumberStep', () => {
|
|
50
|
+
it('avoids float drift', () => {
|
|
51
|
+
expect(addNumberStep(0.1, 0.2)).toBe(0.3);
|
|
52
|
+
expect(addNumberStep(0.3, -0.1)).toBe(0.2);
|
|
53
|
+
});
|
|
54
|
+
it('handles integers', () => {
|
|
55
|
+
expect(addNumberStep(5, 1)).toBe(6);
|
|
56
|
+
expect(addNumberStep(5, -10)).toBe(-5);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe('formatWithLocale', () => {
|
|
60
|
+
beforeEach(() => __resetNumberFormatCache());
|
|
61
|
+
it('formats with grouping per locale', () => {
|
|
62
|
+
expect(formatWithLocale(1234567, 'en-US')).toBe('1,234,567');
|
|
63
|
+
});
|
|
64
|
+
it('honors options', () => {
|
|
65
|
+
expect(formatWithLocale(0.5, 'en-US', { style: 'percent' })).toBe('50%');
|
|
66
|
+
});
|
|
67
|
+
it('caches instances per (locale, options)', () => {
|
|
68
|
+
const a = formatWithLocale(1, 'en-US');
|
|
69
|
+
const b = formatWithLocale(2, 'en-US');
|
|
70
|
+
expect(a).toBe('1');
|
|
71
|
+
expect(b).toBe('2');
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=input-number.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-number.test.js","sourceRoot":"","sources":["../src/input-number.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List selection state — framework-agnostic, pure functions.
|
|
3
|
+
* Toggling / range-selecting row keys for a selectable List. No DOM, no
|
|
4
|
+
* framework deps, no mutable module state — the render layer owns the controlled
|
|
5
|
+
* `selectedKeys` and only feeds the next set to `onSelectionChange`.
|
|
6
|
+
* See specs/components/show/List.spec.md.
|
|
7
|
+
*/
|
|
8
|
+
export type ListKey = string | number;
|
|
9
|
+
export type SelectionMode = 'single' | 'multiple';
|
|
10
|
+
/**
|
|
11
|
+
* Compute the next selected-key set after clicking row `key`.
|
|
12
|
+
*
|
|
13
|
+
* - `single`: clicking an unselected row selects only it; clicking the already
|
|
14
|
+
* selected row clears the selection (toggle).
|
|
15
|
+
* - `multiple`: clicking toggles `key`'s membership, preserving the rest.
|
|
16
|
+
*
|
|
17
|
+
* Pure: returns a brand new Set; never mutates `current`.
|
|
18
|
+
*
|
|
19
|
+
* @param current the current selected-key set (controlled value)
|
|
20
|
+
* @param key the row key being toggled
|
|
21
|
+
* @param mode 'single' | 'multiple'
|
|
22
|
+
*/
|
|
23
|
+
export declare function toggleSelection(current: ReadonlySet<ListKey>, key: ListKey, mode: SelectionMode): Set<ListKey>;
|
|
24
|
+
/**
|
|
25
|
+
* Compute the next selected-key set for a shift range-select between the anchor
|
|
26
|
+
* row and the just-clicked row (multiple mode only). All keys in the inclusive
|
|
27
|
+
* index range [min(anchor, target), max(anchor, target)] are added to the
|
|
28
|
+
* current selection.
|
|
29
|
+
*
|
|
30
|
+
* Pure: returns a brand new Set; never mutates `current`.
|
|
31
|
+
*
|
|
32
|
+
* @param current the current selected-key set
|
|
33
|
+
* @param orderedKeys the full ordered list of row keys (index = row position)
|
|
34
|
+
* @param anchorIndex the index of the last single-clicked (anchor) row
|
|
35
|
+
* @param targetIndex the index of the shift-clicked row
|
|
36
|
+
*/
|
|
37
|
+
export declare function rangeSelection(current: ReadonlySet<ListKey>, orderedKeys: readonly ListKey[], anchorIndex: number, targetIndex: number): Set<ListKey>;
|
|
38
|
+
//# sourceMappingURL=list-selection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-selection.d.ts","sourceRoot":"","sources":["../src/list-selection.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAEtC,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,UAAU,CAAC;AAElD;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,EAC7B,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,aAAa,GAClB,GAAG,CAAC,OAAO,CAAC,CAUd;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,EAC7B,WAAW,EAAE,SAAS,OAAO,EAAE,EAC/B,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,GAAG,CAAC,OAAO,CAAC,CAUd"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List selection state — framework-agnostic, pure functions.
|
|
3
|
+
* Toggling / range-selecting row keys for a selectable List. No DOM, no
|
|
4
|
+
* framework deps, no mutable module state — the render layer owns the controlled
|
|
5
|
+
* `selectedKeys` and only feeds the next set to `onSelectionChange`.
|
|
6
|
+
* See specs/components/show/List.spec.md.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Compute the next selected-key set after clicking row `key`.
|
|
10
|
+
*
|
|
11
|
+
* - `single`: clicking an unselected row selects only it; clicking the already
|
|
12
|
+
* selected row clears the selection (toggle).
|
|
13
|
+
* - `multiple`: clicking toggles `key`'s membership, preserving the rest.
|
|
14
|
+
*
|
|
15
|
+
* Pure: returns a brand new Set; never mutates `current`.
|
|
16
|
+
*
|
|
17
|
+
* @param current the current selected-key set (controlled value)
|
|
18
|
+
* @param key the row key being toggled
|
|
19
|
+
* @param mode 'single' | 'multiple'
|
|
20
|
+
*/
|
|
21
|
+
export function toggleSelection(current, key, mode) {
|
|
22
|
+
if (mode === 'single') {
|
|
23
|
+
// Toggle: re-clicking the sole selected row clears it.
|
|
24
|
+
if (current.has(key) && current.size === 1)
|
|
25
|
+
return new Set();
|
|
26
|
+
return new Set([key]);
|
|
27
|
+
}
|
|
28
|
+
const next = new Set(current);
|
|
29
|
+
if (next.has(key))
|
|
30
|
+
next.delete(key);
|
|
31
|
+
else
|
|
32
|
+
next.add(key);
|
|
33
|
+
return next;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Compute the next selected-key set for a shift range-select between the anchor
|
|
37
|
+
* row and the just-clicked row (multiple mode only). All keys in the inclusive
|
|
38
|
+
* index range [min(anchor, target), max(anchor, target)] are added to the
|
|
39
|
+
* current selection.
|
|
40
|
+
*
|
|
41
|
+
* Pure: returns a brand new Set; never mutates `current`.
|
|
42
|
+
*
|
|
43
|
+
* @param current the current selected-key set
|
|
44
|
+
* @param orderedKeys the full ordered list of row keys (index = row position)
|
|
45
|
+
* @param anchorIndex the index of the last single-clicked (anchor) row
|
|
46
|
+
* @param targetIndex the index of the shift-clicked row
|
|
47
|
+
*/
|
|
48
|
+
export function rangeSelection(current, orderedKeys, anchorIndex, targetIndex) {
|
|
49
|
+
const next = new Set(current);
|
|
50
|
+
if (anchorIndex < 0 || targetIndex < 0)
|
|
51
|
+
return next;
|
|
52
|
+
const lo = Math.max(0, Math.min(anchorIndex, targetIndex));
|
|
53
|
+
const hi = Math.min(orderedKeys.length - 1, Math.max(anchorIndex, targetIndex));
|
|
54
|
+
for (let i = lo; i <= hi; i += 1) {
|
|
55
|
+
const k = orderedKeys[i];
|
|
56
|
+
if (k !== undefined)
|
|
57
|
+
next.add(k);
|
|
58
|
+
}
|
|
59
|
+
return next;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=list-selection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-selection.js","sourceRoot":"","sources":["../src/list-selection.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAC7B,OAA6B,EAC7B,GAAY,EACZ,IAAmB;IAEnB,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,uDAAuD;QACvD,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,GAAG,EAAE,CAAC;QAC7D,OAAO,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAC9B,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;;QAC/B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAC5B,OAA6B,EAC7B,WAA+B,EAC/B,WAAmB,EACnB,WAAmB;IAEnB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAC9B,IAAI,WAAW,GAAG,CAAC,IAAI,WAAW,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACpD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;IAC3D,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;IAChF,KAAK,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,CAAC,KAAK,SAAS;YAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-selection.test.d.ts","sourceRoot":"","sources":["../src/list-selection.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { toggleSelection, rangeSelection } from './list-selection.js';
|
|
3
|
+
describe('toggleSelection (single)', () => {
|
|
4
|
+
it('selects only the clicked row', () => {
|
|
5
|
+
const next = toggleSelection(new Set([1]), 2, 'single');
|
|
6
|
+
expect([...next]).toEqual([2]);
|
|
7
|
+
});
|
|
8
|
+
it('clears when re-clicking the sole selected row', () => {
|
|
9
|
+
const next = toggleSelection(new Set([2]), 2, 'single');
|
|
10
|
+
expect(next.size).toBe(0);
|
|
11
|
+
});
|
|
12
|
+
it('replaces a different existing selection', () => {
|
|
13
|
+
const next = toggleSelection(new Set([5, 6]), 6, 'single');
|
|
14
|
+
expect([...next]).toEqual([6]);
|
|
15
|
+
});
|
|
16
|
+
it('does not mutate the input set', () => {
|
|
17
|
+
const cur = new Set([1]);
|
|
18
|
+
toggleSelection(cur, 2, 'single');
|
|
19
|
+
expect([...cur]).toEqual([1]);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('toggleSelection (multiple)', () => {
|
|
23
|
+
it('adds an unselected key', () => {
|
|
24
|
+
const next = toggleSelection(new Set([1]), 2, 'multiple');
|
|
25
|
+
expect([...next].sort()).toEqual([1, 2]);
|
|
26
|
+
});
|
|
27
|
+
it('removes a selected key', () => {
|
|
28
|
+
const next = toggleSelection(new Set([1, 2]), 2, 'multiple');
|
|
29
|
+
expect([...next]).toEqual([1]);
|
|
30
|
+
});
|
|
31
|
+
it('does not mutate the input set', () => {
|
|
32
|
+
const cur = new Set([1, 2]);
|
|
33
|
+
toggleSelection(cur, 3, 'multiple');
|
|
34
|
+
expect([...cur].sort()).toEqual([1, 2]);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
describe('rangeSelection', () => {
|
|
38
|
+
const keys = ['a', 'b', 'c', 'd', 'e'];
|
|
39
|
+
it('adds inclusive range between anchor and target', () => {
|
|
40
|
+
const next = rangeSelection(new Set(['a']), keys, 1, 3);
|
|
41
|
+
expect([...next].sort()).toEqual(['a', 'b', 'c', 'd']);
|
|
42
|
+
});
|
|
43
|
+
it('works regardless of click direction', () => {
|
|
44
|
+
const next = rangeSelection(new Set(), keys, 3, 1);
|
|
45
|
+
expect([...next].sort()).toEqual(['b', 'c', 'd']);
|
|
46
|
+
});
|
|
47
|
+
it('clamps out-of-bounds target index', () => {
|
|
48
|
+
const next = rangeSelection(new Set(), keys, 0, 99);
|
|
49
|
+
expect([...next].sort()).toEqual(['a', 'b', 'c', 'd', 'e']);
|
|
50
|
+
});
|
|
51
|
+
it('returns current copy when anchor missing', () => {
|
|
52
|
+
const next = rangeSelection(new Set(['a']), keys, -1, 3);
|
|
53
|
+
expect([...next]).toEqual(['a']);
|
|
54
|
+
});
|
|
55
|
+
it('does not mutate the input set', () => {
|
|
56
|
+
const cur = new Set(['a']);
|
|
57
|
+
rangeSelection(cur, keys, 1, 3);
|
|
58
|
+
expect([...cur]).toEqual(['a']);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
//# sourceMappingURL=list-selection.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-selection.test.js","sourceRoot":"","sources":["../src/list-selection.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useLiveAnnouncer — 全库通用的单例 ARIA live region 播报原语。
|
|
3
|
+
*
|
|
4
|
+
* 动态状态变化(排序/筛选/翻页/越界/选择…)需要让屏幕阅读器播报,但若每个
|
|
5
|
+
* 组件各自渲染 `aria-live` 容器,会出现重复/竞争且难以统一。本原语在 body 上
|
|
6
|
+
* 命令式挂载两个全局唯一的 region(polite + assertive),所有组件复用同一对节点。
|
|
7
|
+
*
|
|
8
|
+
* - 红线 #3:region DOM 命令式创建/挂载 + 命令式写入 + cleanup;模块级单例复用,
|
|
9
|
+
* 不依赖任何框架 effect。客户端 only(守 `document`,SSR 下静默 no-op)。
|
|
10
|
+
* - region 视觉隐藏(sr-only:absolute + 1px + clip),不可用 display:none /
|
|
11
|
+
* visibility:hidden(会被辅助技术忽略)。
|
|
12
|
+
* - 级别策略(WAI-ARIA APG):polite 排队播报(默认,状态结果类);assertive
|
|
13
|
+
* 立即打断(错误/紧急)。
|
|
14
|
+
* - 同一文案连续两次也能被重播:先清空再写入,触发新一次 AT 播报。
|
|
15
|
+
*
|
|
16
|
+
* 文案由调用方在组件层经 `@chenzy-design/locale` 本地化后传入(本原语不含文案)。
|
|
17
|
+
*
|
|
18
|
+
* 参考 packages/svelte/src/toast/live-region.ts(Toast 自带的 region 范式),
|
|
19
|
+
* 但本原语放在 core,供全库组件复用。Toast/Notification 仍用各自既有 region。
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const announcer = useLiveAnnouncer();
|
|
23
|
+
* announcer.announce('已按名称升序排序'); // polite
|
|
24
|
+
* announcer.announce('表单提交失败', 'assertive'); // 立即打断
|
|
25
|
+
*/
|
|
26
|
+
export type Politeness = 'polite' | 'assertive';
|
|
27
|
+
export interface LiveAnnouncer {
|
|
28
|
+
/** 把文案写入对应级别的单例 region 供屏幕阅读器播报。默认 polite。 */
|
|
29
|
+
announce(message: string, politeness?: Politeness): void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 获取全局单例播报器。多次调用返回等价 API(共享同一对 region 节点),
|
|
33
|
+
* 首次写入时才惰性挂载 region(SSR 下不挂载)。
|
|
34
|
+
*/
|
|
35
|
+
export declare function useLiveAnnouncer(): LiveAnnouncer;
|
|
36
|
+
/** 测试 only:移除单例 region 并复位模块状态。 */
|
|
37
|
+
export declare function __resetLiveAnnouncer(): void;
|
|
38
|
+
//# sourceMappingURL=live-announcer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-announcer.d.ts","sourceRoot":"","sources":["../src/live-announcer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEhD,MAAM,WAAW,aAAa;IAC5B,8CAA8C;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;CAC1D;AAwDD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED,mCAAmC;AACnC,wBAAgB,oBAAoB,IAAI,IAAI,CAM3C"}
|