@gabvdl/ui 0.0.14 → 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/README.md +6 -3
- package/dist/components/button/button.test.d.ts +2 -0
- package/dist/components/button/button.test.d.ts.map +1 -0
- package/dist/components/element-picker/use-element-picker.d.ts +3 -0
- package/dist/components/element-picker/use-element-picker.d.ts.map +1 -1
- package/dist/components/element-picker/use-element-picker.js +90 -89
- package/dist/components/element-picker/use-element-picker.js.map +1 -1
- package/dist/components/fuzzy-list/fuzzy-list.test.d.ts +2 -0
- package/dist/components/fuzzy-list/fuzzy-list.test.d.ts.map +1 -0
- package/dist/components/input/input.d.ts +1 -0
- package/dist/components/input/input.d.ts.map +1 -1
- package/dist/components/input/input.js.map +1 -1
- package/dist/components/modal/modal.test.d.ts +2 -0
- package/dist/components/modal/modal.test.d.ts.map +1 -0
- package/dist/components/progressive-timeline/index.d.ts +1 -1
- package/dist/components/progressive-timeline/index.d.ts.map +1 -1
- package/dist/components/progressive-timeline/progressive-timeline.d.ts +11 -6
- package/dist/components/progressive-timeline/progressive-timeline.d.ts.map +1 -1
- package/dist/components/progressive-timeline/progressive-timeline.js.map +1 -1
- package/dist/components/theme/theme.d.ts.map +1 -1
- package/dist/components/theme/theme.js +24 -20
- package/dist/components/theme/theme.js.map +1 -1
- package/dist/components/theme/theme.test.d.ts +2 -0
- package/dist/components/theme/theme.test.d.ts.map +1 -0
- package/dist/components/toast/toast.test.d.ts +2 -0
- package/dist/components/toast/toast.test.d.ts.map +1 -0
- package/dist/components/virtual-list/virtual-list.test.d.ts +2 -0
- package/dist/components/virtual-list/virtual-list.test.d.ts.map +1 -0
- package/dist/hooks/use-local-storage.test.d.ts +2 -0
- package/dist/hooks/use-local-storage.test.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/format.test.d.ts +2 -0
- package/dist/lib/format.test.d.ts.map +1 -0
- package/dist/lib/highlight.test.d.ts +2 -0
- package/dist/lib/highlight.test.d.ts.map +1 -0
- package/dist/test/setup.d.ts +1 -0
- package/dist/test/setup.d.ts.map +1 -0
- package/package.json +11 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gabriel Vidal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# @gabvdl/ui
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
> `0.0
|
|
5
|
-
>
|
|
3
|
+
> **Beta.** `0.1.0` is the first coherent, tested, documented cut — the API is
|
|
4
|
+
> stabilizing. From `0.1.0` on, a breaking change bumps the **minor**, and a
|
|
5
|
+
> renamed prop keeps its old name as a deprecated alias for at least one minor.
|
|
6
|
+
> Pin `~0.1.0` if you want stability without missing fixes. `1.0.0` will be the
|
|
7
|
+
> first stable cut. See [`CHANGELOG.md`](../../CHANGELOG.md) for what shipped
|
|
8
|
+
> when.
|
|
6
9
|
|
|
7
10
|
Gabriel Vidal's personal design system — tree-shakeable React components built on
|
|
8
11
|
shadcn primitives, reused across the homelab. Flagship: a full-screen image
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.test.d.ts","sourceRoot":"","sources":["../../../src/components/button/button.test.tsx"],"names":[],"mappings":""}
|
|
@@ -7,6 +7,9 @@ export interface UseElementPickerOptions {
|
|
|
7
7
|
/** Controlled selection. */
|
|
8
8
|
value?: PickedElement[];
|
|
9
9
|
defaultValue?: PickedElement[];
|
|
10
|
+
/** Called with the full selection whenever it changes. */
|
|
11
|
+
onValueChange?: (picked: PickedElement[]) => void;
|
|
12
|
+
/** @deprecated Use `onValueChange`. */
|
|
10
13
|
onChange?: (picked: PickedElement[]) => void;
|
|
11
14
|
onPick?: (picked: PickedElement) => void;
|
|
12
15
|
/** Controlled picking mode. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-element-picker.d.ts","sourceRoot":"","sources":["../../../src/components/element-picker/use-element-picker.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAc7C,MAAM,WAAW,uBAAuB;IACtC,kEAAkE;IAClE,IAAI,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,sDAAsD;IACtD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,4BAA4B;IAC5B,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,aAAa,EAAE,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;IAC7C,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,+BAA+B;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC;IACtC,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,oEAAoE;IACpE,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,sDAAsD;IACtD,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,IAAI,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,IAAI,CAAC;IAChC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC;IACvC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAOD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B,GAAG,sBAAsB,
|
|
1
|
+
{"version":3,"file":"use-element-picker.d.ts","sourceRoot":"","sources":["../../../src/components/element-picker/use-element-picker.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAc7C,MAAM,WAAW,uBAAuB;IACtC,kEAAkE;IAClE,IAAI,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,sDAAsD;IACtD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,4BAA4B;IAC5B,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,aAAa,EAAE,CAAC;IAC/B,0DAA0D;IAC1D,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;IAClD,uCAAuC;IACvC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;IAC7C,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,+BAA+B;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC;IACtC,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,oEAAoE;IACpE,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,sDAAsD;IACtD,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,IAAI,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,IAAI,CAAC;IAChC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC;IACvC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAOD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B,GAAG,sBAAsB,CAqW9F"}
|
|
@@ -1,38 +1,39 @@
|
|
|
1
1
|
import * as i from "react";
|
|
2
|
-
import { parseElement as
|
|
3
|
-
const
|
|
4
|
-
let
|
|
5
|
-
const
|
|
6
|
-
let w =
|
|
7
|
-
return w || (w = `el-${++
|
|
8
|
-
},
|
|
9
|
-
function
|
|
2
|
+
import { parseElement as ue } from "./parse.js";
|
|
3
|
+
const F = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
let de = 0;
|
|
5
|
+
const fe = (D) => {
|
|
6
|
+
let w = F.get(D);
|
|
7
|
+
return w || (w = `el-${++de}`, F.set(D, w)), w;
|
|
8
|
+
}, G = "data-element-picker-ignore", pe = 700;
|
|
9
|
+
function ve(D = {}) {
|
|
10
10
|
const {
|
|
11
11
|
root: w,
|
|
12
12
|
multiple: R = !0,
|
|
13
13
|
value: A,
|
|
14
|
-
defaultValue:
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
defaultValue: N = [],
|
|
15
|
+
onValueChange: W,
|
|
16
|
+
onChange: j,
|
|
17
|
+
onPick: X,
|
|
17
18
|
active: x,
|
|
18
19
|
onActiveChange: S,
|
|
19
|
-
filter:
|
|
20
|
-
ignoreSelector:
|
|
21
|
-
styleProps:
|
|
22
|
-
holdDelay:
|
|
23
|
-
moveTolerance:
|
|
24
|
-
max:
|
|
25
|
-
} = D,
|
|
26
|
-
|
|
20
|
+
filter: Y,
|
|
21
|
+
ignoreSelector: H = `[${G}]`,
|
|
22
|
+
styleProps: V,
|
|
23
|
+
holdDelay: I = 350,
|
|
24
|
+
moveTolerance: O = 12,
|
|
25
|
+
max: U
|
|
26
|
+
} = D, _ = W ?? j, [z, B] = i.useState(!1), L = x ?? z, [J, Q] = i.useState(N), C = A ?? J, [Z, ee] = i.useState(null), [te, M] = i.useState(!1), [m, ne] = i.useState(null), K = i.useRef(null), E = i.useCallback((n) => {
|
|
27
|
+
K.current = n, ee((o) => o === n ? o : n);
|
|
27
28
|
}, []), l = i.useRef({
|
|
28
|
-
picked:
|
|
29
|
+
picked: C,
|
|
29
30
|
multiple: R,
|
|
30
|
-
max:
|
|
31
|
-
filter:
|
|
32
|
-
ignoreSelector:
|
|
33
|
-
styleProps:
|
|
34
|
-
|
|
35
|
-
onPick:
|
|
31
|
+
max: U,
|
|
32
|
+
filter: Y,
|
|
33
|
+
ignoreSelector: H,
|
|
34
|
+
styleProps: V,
|
|
35
|
+
onValueChange: _,
|
|
36
|
+
onPick: X,
|
|
36
37
|
root: m,
|
|
37
38
|
controlled: A !== void 0,
|
|
38
39
|
stop: () => {
|
|
@@ -40,18 +41,18 @@ function pe(D = {}) {
|
|
|
40
41
|
});
|
|
41
42
|
l.current = {
|
|
42
43
|
...l.current,
|
|
43
|
-
picked:
|
|
44
|
+
picked: C,
|
|
44
45
|
multiple: R,
|
|
45
|
-
max:
|
|
46
|
-
filter:
|
|
47
|
-
ignoreSelector:
|
|
48
|
-
styleProps:
|
|
49
|
-
|
|
50
|
-
onPick:
|
|
46
|
+
max: U,
|
|
47
|
+
filter: Y,
|
|
48
|
+
ignoreSelector: H,
|
|
49
|
+
styleProps: V,
|
|
50
|
+
onValueChange: _,
|
|
51
|
+
onPick: X,
|
|
51
52
|
root: m,
|
|
52
53
|
controlled: A !== void 0
|
|
53
54
|
};
|
|
54
|
-
const
|
|
55
|
+
const oe = i.useRef({
|
|
55
56
|
timer: void 0,
|
|
56
57
|
from: null,
|
|
57
58
|
on: !1,
|
|
@@ -67,102 +68,102 @@ function pe(D = {}) {
|
|
|
67
68
|
pickedAt: 0
|
|
68
69
|
});
|
|
69
70
|
i.useEffect(() => {
|
|
70
|
-
|
|
71
|
+
ne(w ?? (typeof document > "u" ? null : document.body));
|
|
71
72
|
}, [w]);
|
|
72
73
|
const g = i.useCallback(
|
|
73
74
|
(n) => {
|
|
74
|
-
x === void 0 &&
|
|
75
|
+
x === void 0 && B(n), S == null || S(n);
|
|
75
76
|
},
|
|
76
77
|
[x, S]
|
|
77
|
-
),
|
|
78
|
-
l.current.stop =
|
|
78
|
+
), re = i.useCallback(() => g(!0), [g]), $ = i.useCallback(() => g(!1), [g]), ie = i.useCallback(() => g(!L), [L, g]);
|
|
79
|
+
l.current.stop = $;
|
|
79
80
|
const k = i.useCallback((n) => {
|
|
80
81
|
var o, t;
|
|
81
|
-
l.current.controlled ||
|
|
82
|
-
}, []),
|
|
82
|
+
l.current.controlled || Q(n), (t = (o = l.current).onValueChange) == null || t.call(o, n);
|
|
83
|
+
}, []), P = i.useCallback(
|
|
83
84
|
(n) => {
|
|
84
|
-
var
|
|
85
|
-
const { picked: o, multiple: t, max:
|
|
86
|
-
if (o.some((
|
|
87
|
-
k(o.filter((
|
|
85
|
+
var b, d;
|
|
86
|
+
const { picked: o, multiple: t, max: a, styleProps: p, root: u } = l.current, c = fe(n);
|
|
87
|
+
if (o.some((y) => y.id === c)) {
|
|
88
|
+
k(o.filter((y) => y.id !== c));
|
|
88
89
|
return;
|
|
89
90
|
}
|
|
90
|
-
const
|
|
91
|
+
const h = {
|
|
91
92
|
id: c,
|
|
92
93
|
element: n,
|
|
93
|
-
info:
|
|
94
|
+
info: ue(n, { root: u ?? void 0, styleProps: p })
|
|
94
95
|
};
|
|
95
|
-
let v = t ? [...o,
|
|
96
|
-
|
|
96
|
+
let v = t ? [...o, h] : [h];
|
|
97
|
+
a && v.length > a && (v = v.slice(v.length - a)), k(v), (d = (b = l.current).onPick) == null || d.call(b, h);
|
|
97
98
|
},
|
|
98
99
|
[k]
|
|
99
|
-
),
|
|
100
|
+
), se = i.useCallback(
|
|
100
101
|
(n) => k(l.current.picked.filter((o) => o.id !== n)),
|
|
101
102
|
[k]
|
|
102
|
-
),
|
|
103
|
-
const { root: t, filter:
|
|
103
|
+
), ce = i.useCallback(() => k([]), [k]), le = i.useCallback((n) => C.some((o) => o.element === n), [C]), T = i.useCallback((n, o) => {
|
|
104
|
+
const { root: t, filter: a, ignoreSelector: p } = l.current;
|
|
104
105
|
if (!t) return null;
|
|
105
|
-
const
|
|
106
|
-
if (!(
|
|
107
|
-
if (!
|
|
108
|
-
for (let c =
|
|
109
|
-
if (
|
|
106
|
+
const u = t.ownerDocument.elementFromPoint(n, o);
|
|
107
|
+
if (!(u instanceof HTMLElement) || p && u.closest(p) || !t.contains(u) || u === t) return null;
|
|
108
|
+
if (!a) return u;
|
|
109
|
+
for (let c = u; c && c !== t; c = c.parentElement)
|
|
110
|
+
if (a(c)) return c;
|
|
110
111
|
return null;
|
|
111
112
|
}, []);
|
|
112
113
|
return i.useEffect(() => {
|
|
113
114
|
if (!L || !m) return;
|
|
114
|
-
const n = m.ownerDocument, o = n.documentElement, t =
|
|
115
|
+
const n = m.ownerDocument, o = n.documentElement, t = oe.current;
|
|
115
116
|
t.timer = void 0, t.from = null, t.on = !1;
|
|
116
|
-
const
|
|
117
|
+
const a = (e) => {
|
|
117
118
|
const { ignoreSelector: r } = l.current;
|
|
118
119
|
return !!(r && e instanceof Element && e.closest(r));
|
|
119
|
-
}, p = (e, r) => E(T(e, r)),
|
|
120
|
+
}, p = (e, r) => E(T(e, r)), u = (e) => {
|
|
120
121
|
if (e.pointerType === "touch") {
|
|
121
|
-
t.on ? p(e.clientX, e.clientY) : t.from && Math.hypot(e.clientX - t.from.x, e.clientY - t.from.y) >
|
|
122
|
+
t.on ? p(e.clientX, e.clientY) : t.from && Math.hypot(e.clientX - t.from.x, e.clientY - t.from.y) > O && (clearTimeout(t.timer), t.from = null);
|
|
122
123
|
return;
|
|
123
124
|
}
|
|
124
125
|
p(e.clientX, e.clientY);
|
|
125
126
|
}, c = () => {
|
|
126
127
|
clearTimeout(t.timer), t.from = null, t.on && (t.on = !1, M(!1));
|
|
127
|
-
},
|
|
128
|
-
if (!
|
|
128
|
+
}, h = (e) => {
|
|
129
|
+
if (!a(e.target)) {
|
|
129
130
|
if (e.pointerType === "touch") {
|
|
130
131
|
t.from = { x: e.clientX, y: e.clientY }, t.timer = setTimeout(() => {
|
|
131
132
|
var r;
|
|
132
133
|
t.on = !0, t.from = null, M(!0), (r = navigator.vibrate) == null || r.call(navigator, 12), p(e.clientX, e.clientY);
|
|
133
|
-
},
|
|
134
|
+
}, I);
|
|
134
135
|
return;
|
|
135
136
|
}
|
|
136
137
|
e.preventDefault(), e.stopPropagation();
|
|
137
138
|
}
|
|
138
139
|
}, v = (e) => {
|
|
139
|
-
if (!
|
|
140
|
+
if (!a(e.target)) {
|
|
140
141
|
if (e.pointerType === "touch") {
|
|
141
142
|
const r = t.on;
|
|
142
143
|
c();
|
|
143
144
|
const f = T(e.clientX, e.clientY);
|
|
144
|
-
f && (
|
|
145
|
+
f && (P(f), t.pickedAt = performance.now()), (r || f) && E(null), e.preventDefault(), e.stopPropagation();
|
|
145
146
|
return;
|
|
146
147
|
}
|
|
147
148
|
e.preventDefault(), e.stopPropagation();
|
|
148
149
|
}
|
|
149
|
-
},
|
|
150
|
-
if (
|
|
150
|
+
}, b = (e) => {
|
|
151
|
+
if (a(e.target) || (e.preventDefault(), e.stopPropagation(), e.detail === 0) || performance.now() - t.pickedAt < pe) return;
|
|
151
152
|
const r = T(e.clientX, e.clientY);
|
|
152
|
-
r &&
|
|
153
|
+
r && P(r);
|
|
153
154
|
}, d = (e) => {
|
|
154
|
-
|
|
155
|
-
},
|
|
155
|
+
a(e.target) || (e.preventDefault(), e.stopPropagation());
|
|
156
|
+
}, y = (e) => {
|
|
156
157
|
if (!t.on) return;
|
|
157
158
|
e.preventDefault();
|
|
158
159
|
const r = e.touches[0];
|
|
159
160
|
r && p(r.clientX, r.clientY);
|
|
160
|
-
},
|
|
161
|
+
}, q = (e) => {
|
|
161
162
|
if (e.key === "Escape") {
|
|
162
163
|
e.preventDefault(), l.current.stop();
|
|
163
164
|
return;
|
|
164
165
|
}
|
|
165
|
-
const r =
|
|
166
|
+
const r = K.current;
|
|
166
167
|
if (r)
|
|
167
168
|
if (e.key === "ArrowUp") {
|
|
168
169
|
e.preventDefault();
|
|
@@ -172,30 +173,30 @@ function pe(D = {}) {
|
|
|
172
173
|
e.preventDefault();
|
|
173
174
|
const f = r.firstElementChild;
|
|
174
175
|
f instanceof HTMLElement && E(f);
|
|
175
|
-
} else (e.key === "Enter" || e.key === " ") && (e.preventDefault(),
|
|
176
|
+
} else (e.key === "Enter" || e.key === " ") && (e.preventDefault(), P(r));
|
|
176
177
|
}, s = { capture: !0 };
|
|
177
|
-
window.addEventListener("pointermove",
|
|
178
|
-
const
|
|
178
|
+
window.addEventListener("pointermove", u, s), window.addEventListener("pointerdown", h, s), window.addEventListener("pointerup", v, s), window.addEventListener("pointercancel", c, s), window.addEventListener("click", b, s), window.addEventListener("mousedown", d, s), window.addEventListener("mouseup", d, s), window.addEventListener("dblclick", d, s), window.addEventListener("contextmenu", d, s), window.addEventListener("keydown", q, s), n.addEventListener("touchmove", y, { passive: !1, capture: !0 });
|
|
179
|
+
const ae = o.style.cssText;
|
|
179
180
|
return o.style.cursor = "crosshair", o.style.userSelect = "none", o.style.webkitUserSelect = "none", o.style.webkitTouchCallout = "none", () => {
|
|
180
|
-
clearTimeout(t.timer), window.removeEventListener("pointermove",
|
|
181
|
+
clearTimeout(t.timer), window.removeEventListener("pointermove", u, s), window.removeEventListener("pointerdown", h, s), window.removeEventListener("pointerup", v, s), window.removeEventListener("pointercancel", c, s), window.removeEventListener("click", b, s), window.removeEventListener("mousedown", d, s), window.removeEventListener("mouseup", d, s), window.removeEventListener("dblclick", d, s), window.removeEventListener("contextmenu", d, s), window.removeEventListener("keydown", q, s), n.removeEventListener("touchmove", y, { capture: !0 }), o.style.cssText = ae, E(null), M(!1);
|
|
181
182
|
};
|
|
182
|
-
}, [L, m,
|
|
183
|
+
}, [L, m, I, O, P, T, E]), {
|
|
183
184
|
active: L,
|
|
184
|
-
start:
|
|
185
|
-
stop:
|
|
186
|
-
toggle:
|
|
187
|
-
hovered:
|
|
188
|
-
holding:
|
|
189
|
-
picked:
|
|
190
|
-
pick:
|
|
191
|
-
remove:
|
|
192
|
-
clear:
|
|
193
|
-
isPicked:
|
|
185
|
+
start: re,
|
|
186
|
+
stop: $,
|
|
187
|
+
toggle: ie,
|
|
188
|
+
hovered: Z,
|
|
189
|
+
holding: te,
|
|
190
|
+
picked: C,
|
|
191
|
+
pick: P,
|
|
192
|
+
remove: se,
|
|
193
|
+
clear: ce,
|
|
194
|
+
isPicked: le,
|
|
194
195
|
root: m,
|
|
195
|
-
ignoreProps: { [
|
|
196
|
+
ignoreProps: { [G]: "" }
|
|
196
197
|
};
|
|
197
198
|
}
|
|
198
199
|
export {
|
|
199
|
-
|
|
200
|
+
ve as useElementPicker
|
|
200
201
|
};
|
|
201
202
|
//# sourceMappingURL=use-element-picker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-element-picker.js","sources":["../../../src/components/element-picker/use-element-picker.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { parseElement } from './parse';\nimport type { PickedElement } from './types';\n\n/** Stable ids, so re-picking the same node doesn't churn React keys. */\nconst IDS = new WeakMap<HTMLElement, string>();\nlet seq = 0;\nconst idOf = (el: HTMLElement) => {\n let id = IDS.get(el);\n if (!id) {\n id = `el-${++seq}`;\n IDS.set(el, id);\n }\n return id;\n};\n\nexport interface UseElementPickerOptions {\n /** The subtree you can pick from. Defaults to `document.body`. */\n root?: HTMLElement | null;\n /** Keep picking after the first hit. Default true. */\n multiple?: boolean;\n /** Controlled selection. */\n value?: PickedElement[];\n defaultValue?: PickedElement[];\n onChange?: (picked: PickedElement[]) => void;\n onPick?: (picked: PickedElement) => void;\n /** Controlled picking mode. */\n active?: boolean;\n onActiveChange?: (active: boolean) => void;\n /**\n * Which elements may be picked. When an element fails, the picker walks up to\n * the nearest ancestor that passes — so `(el) => el.matches('.card')` turns it\n * into a card picker, however deep the pointer actually lands.\n */\n filter?: (el: HTMLElement) => boolean;\n /** Subtrees the picker won't look at — your own toolbar, typically. */\n ignoreSelector?: string;\n /** Override which computed properties get captured. */\n styleProps?: string[];\n /** Touch: how long to hold before hover mode engages, in ms. Default 350. */\n holdDelay?: number;\n /** Touch: movement (px) that reads as a scroll and cancels the hold. Default 12. */\n moveTolerance?: number;\n /** Cap the selection. Picking past it drops the oldest. */\n max?: number;\n}\n\nexport interface UseElementPickerResult {\n active: boolean;\n start: () => void;\n stop: () => void;\n toggle: () => void;\n /** What the pointer is over right now — the live preview target. */\n hovered: HTMLElement | null;\n /** True while a touch hold has engaged hover mode. */\n holding: boolean;\n picked: PickedElement[];\n pick: (el: HTMLElement) => void;\n remove: (id: string) => void;\n clear: () => void;\n isPicked: (el: HTMLElement) => boolean;\n root: HTMLElement | null;\n /** Put this on any UI of your own that must stay clickable while picking. */\n ignoreProps: Record<string, string>;\n}\n\nconst IGNORE_ATTR = 'data-element-picker-ignore';\n\n/** How long after a touch pick a click is still assumed to be its replay. */\nconst COMPAT_CLICK_MS = 700;\n\n/**\n * The machinery behind {@link ElementPicker}: hover tracking, click-to-select,\n * and the press-and-hold gesture that turns a touchscreen — which has no hover\n * — into one. Use it directly when you want the behaviour without the overlay.\n */\nexport function useElementPicker(options: UseElementPickerOptions = {}): UseElementPickerResult {\n const {\n root: rootProp,\n multiple = true,\n value,\n defaultValue = [],\n onChange,\n onPick,\n active: activeProp,\n onActiveChange,\n filter,\n ignoreSelector = `[${IGNORE_ATTR}]`,\n styleProps,\n holdDelay = 350,\n moveTolerance = 12,\n max,\n } = options;\n\n const [activeState, setActiveState] = React.useState(false);\n const active = activeProp ?? activeState;\n\n const [pickedState, setPickedState] = React.useState<PickedElement[]>(defaultValue);\n const picked = value ?? pickedState;\n\n const [hovered, setHoveredState] = React.useState<HTMLElement | null>(null);\n const [holding, setHolding] = React.useState(false);\n const [root, setRoot] = React.useState<HTMLElement | null>(null);\n\n // Mirrored into a ref so the listeners below can read the hover without being\n // torn down and rebound on every pointer move.\n const hoveredRef = React.useRef<HTMLElement | null>(null);\n const setHovered = React.useCallback((el: HTMLElement | null) => {\n hoveredRef.current = el;\n setHoveredState((prev) => (prev === el ? prev : el));\n }, []);\n\n // Latest props, read from listeners that are only bound once per activation.\n // `controlled` lives here too so `commit` — and therefore `pick`, and\n // therefore the listener effect — stays referentially stable across a pick.\n const latest = React.useRef({\n picked,\n multiple,\n max,\n filter,\n ignoreSelector,\n styleProps,\n onChange,\n onPick,\n root,\n controlled: value !== undefined,\n stop: () => {},\n });\n latest.current = {\n ...latest.current,\n picked,\n multiple,\n max,\n filter,\n ignoreSelector,\n styleProps,\n onChange,\n onPick,\n root,\n controlled: value !== undefined,\n };\n\n /**\n * Gesture state, held across effect re-binds. It cannot live inside the\n * effect: a pick changes `picked`, which can re-run the effect *between* a\n * touch's pointerup and the compatibility click it triggers — and a fresh\n * object there would lose the very stamp that click has to be checked against.\n */\n const gesture = React.useRef({\n timer: undefined as ReturnType<typeof setTimeout> | undefined,\n from: null as { x: number; y: number } | null,\n on: false,\n /**\n * When a touch ends in a pick, the browser replays it as a compatibility\n * mouse sequence — pointerdown, mousedown, mouseup, *click* — on the same\n * spot. That click would pick the element a second time, and a second pick\n * is a deselect, so the tap would appear to do nothing at all. We stamp the\n * pick and ignore any click landing in its wake. A stamp rather than a flag\n * because the replay isn't guaranteed to arrive: a flag left standing would\n * go on to eat somebody's real click.\n */\n pickedAt: 0,\n });\n\n React.useEffect(() => {\n setRoot(rootProp ?? (typeof document === 'undefined' ? null : document.body));\n }, [rootProp]);\n\n const setActive = React.useCallback(\n (next: boolean) => {\n if (activeProp === undefined) setActiveState(next);\n onActiveChange?.(next);\n },\n [activeProp, onActiveChange],\n );\n\n const start = React.useCallback(() => setActive(true), [setActive]);\n const stop = React.useCallback(() => setActive(false), [setActive]);\n const toggle = React.useCallback(() => setActive(!active), [active, setActive]);\n latest.current.stop = stop;\n\n const commit = React.useCallback((next: PickedElement[]) => {\n if (!latest.current.controlled) setPickedState(next);\n latest.current.onChange?.(next);\n }, []);\n\n const pick = React.useCallback(\n (el: HTMLElement) => {\n const { picked: current, multiple: many, max: cap, styleProps: props, root: base } = latest.current;\n const id = idOf(el);\n\n // A second click on a selected element unselects it — the only way back\n // out of a mis-pick without leaving the flow.\n if (current.some((p) => p.id === id)) {\n commit(current.filter((p) => p.id !== id));\n return;\n }\n\n const entry: PickedElement = {\n id,\n element: el,\n info: parseElement(el, { root: base ?? undefined, styleProps: props }),\n };\n let next = many ? [...current, entry] : [entry];\n if (cap && next.length > cap) next = next.slice(next.length - cap);\n\n commit(next);\n latest.current.onPick?.(entry);\n },\n [commit],\n );\n\n const remove = React.useCallback(\n (id: string) => commit(latest.current.picked.filter((p) => p.id !== id)),\n [commit],\n );\n const clear = React.useCallback(() => commit([]), [commit]);\n const isPicked = React.useCallback((el: HTMLElement) => picked.some((p) => p.element === el), [picked]);\n\n /** The pickable element under a viewport point, or null. */\n const resolve = React.useCallback((x: number, y: number): HTMLElement | null => {\n const { root: base, filter: pass, ignoreSelector: ignore } = latest.current;\n if (!base) return null;\n\n // The overlay is pointer-events:none, so elementFromPoint looks straight\n // through it at the page underneath.\n const hit = base.ownerDocument.elementFromPoint(x, y);\n if (!(hit instanceof HTMLElement)) return null;\n if (ignore && hit.closest(ignore)) return null;\n if (!base.contains(hit) || hit === base) return null;\n\n if (!pass) return hit;\n // Walk up to the nearest ancestor that passes, but never past the root —\n // the root is the frame, not something you can pick.\n for (let el: HTMLElement | null = hit; el && el !== base; el = el.parentElement) {\n if (pass(el)) return el;\n }\n return null;\n }, []);\n\n // Picking mode: swallow the page's own pointer handling, track the hover, and\n // take a click as a pick.\n React.useEffect(() => {\n if (!active || !root) return;\n\n const doc = root.ownerDocument;\n const html = doc.documentElement;\n const held = gesture.current;\n held.timer = undefined;\n held.from = null;\n held.on = false;\n\n const inIgnored = (target: EventTarget | null) => {\n const { ignoreSelector: ignore } = latest.current;\n return !!(ignore && target instanceof Element && target.closest(ignore));\n };\n\n const hoverAt = (x: number, y: number) => setHovered(resolve(x, y));\n\n const onPointerMove = (e: PointerEvent) => {\n if (e.pointerType === 'touch') {\n if (held.on) {\n hoverAt(e.clientX, e.clientY);\n } else if (held.from && Math.hypot(e.clientX - held.from.x, e.clientY - held.from.y) > moveTolerance) {\n clearTimeout(held.timer); // they're scrolling, not holding\n held.from = null;\n }\n return;\n }\n hoverAt(e.clientX, e.clientY);\n };\n\n const endHold = () => {\n clearTimeout(held.timer);\n held.from = null;\n if (held.on) {\n held.on = false;\n setHolding(false);\n }\n };\n\n const onPointerDown = (e: PointerEvent) => {\n if (inIgnored(e.target)) return;\n\n if (e.pointerType === 'touch') {\n held.from = { x: e.clientX, y: e.clientY };\n held.timer = setTimeout(() => {\n held.on = true;\n held.from = null;\n setHolding(true);\n // A tick of haptics, so the hold registers without looking at the screen.\n navigator.vibrate?.(12);\n hoverAt(e.clientX, e.clientY);\n }, holdDelay);\n return;\n }\n\n // Mouse: keep the press off the page (no text selection, no drag start).\n e.preventDefault();\n e.stopPropagation();\n };\n\n const onPointerUp = (e: PointerEvent) => {\n if (inIgnored(e.target)) return;\n\n if (e.pointerType === 'touch') {\n const wasHolding = held.on;\n endHold();\n // Either way the finger lifts on the element it was previewing: a hold\n // and drag commits what's under it, a plain tap commits what it hit.\n const target = resolve(e.clientX, e.clientY);\n if (target) {\n pick(target);\n held.pickedAt = performance.now();\n }\n if (wasHolding || target) setHovered(null);\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n e.preventDefault();\n e.stopPropagation();\n };\n\n const onClick = (e: MouseEvent) => {\n if (inIgnored(e.target)) return;\n // Never let the page act on a pick — no navigation, no form submit.\n e.preventDefault();\n e.stopPropagation();\n if (e.detail === 0) return; // synthetic (keyboard) click, not a real one\n\n // The compatibility click replaying the touch we already picked from.\n if (performance.now() - held.pickedAt < COMPAT_CLICK_MS) return;\n\n const target = resolve(e.clientX, e.clientY);\n if (target) pick(target);\n };\n\n const swallow = (e: Event) => {\n if (inIgnored(e.target)) return;\n e.preventDefault();\n e.stopPropagation();\n };\n\n // Non-passive: this is what stops the page scrolling under a held finger.\n const onTouchMove = (e: TouchEvent) => {\n if (!held.on) return;\n e.preventDefault();\n const touch = e.touches[0];\n if (touch) hoverAt(touch.clientX, touch.clientY);\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n latest.current.stop();\n return;\n }\n const current = hoveredRef.current;\n if (!current) return;\n\n // Walk the tree without moving the mouse — the devtools reflex.\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n const parent = current.parentElement;\n if (parent && parent !== root.parentElement && root.contains(parent)) setHovered(parent);\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n const child = current.firstElementChild;\n if (child instanceof HTMLElement) setHovered(child);\n } else if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n pick(current);\n }\n };\n\n const opts = { capture: true } as const;\n window.addEventListener('pointermove', onPointerMove, opts);\n window.addEventListener('pointerdown', onPointerDown, opts);\n window.addEventListener('pointerup', onPointerUp, opts);\n window.addEventListener('pointercancel', endHold, opts);\n window.addEventListener('click', onClick, opts);\n window.addEventListener('mousedown', swallow, opts);\n window.addEventListener('mouseup', swallow, opts);\n window.addEventListener('dblclick', swallow, opts);\n window.addEventListener('contextmenu', swallow, opts);\n window.addEventListener('keydown', onKeyDown, opts);\n doc.addEventListener('touchmove', onTouchMove, { passive: false, capture: true });\n\n const prior = html.style.cssText;\n html.style.cursor = 'crosshair';\n html.style.userSelect = 'none';\n html.style.webkitUserSelect = 'none';\n (html.style as CSSStyleDeclaration & { webkitTouchCallout?: string }).webkitTouchCallout = 'none';\n\n return () => {\n clearTimeout(held.timer);\n window.removeEventListener('pointermove', onPointerMove, opts);\n window.removeEventListener('pointerdown', onPointerDown, opts);\n window.removeEventListener('pointerup', onPointerUp, opts);\n window.removeEventListener('pointercancel', endHold, opts);\n window.removeEventListener('click', onClick, opts);\n window.removeEventListener('mousedown', swallow, opts);\n window.removeEventListener('mouseup', swallow, opts);\n window.removeEventListener('dblclick', swallow, opts);\n window.removeEventListener('contextmenu', swallow, opts);\n window.removeEventListener('keydown', onKeyDown, opts);\n doc.removeEventListener('touchmove', onTouchMove, { capture: true });\n html.style.cssText = prior;\n setHovered(null);\n setHolding(false);\n };\n }, [active, root, holdDelay, moveTolerance, pick, resolve, setHovered]);\n\n return {\n active,\n start,\n stop,\n toggle,\n hovered,\n holding,\n picked,\n pick,\n remove,\n clear,\n isPicked,\n root,\n ignoreProps: { [IGNORE_ATTR]: '' },\n };\n}\n"],"names":["IDS","seq","idOf","el","id","IGNORE_ATTR","COMPAT_CLICK_MS","useElementPicker","options","rootProp","multiple","value","defaultValue","onChange","onPick","activeProp","onActiveChange","filter","ignoreSelector","styleProps","holdDelay","moveTolerance","max","activeState","setActiveState","React","active","pickedState","setPickedState","picked","hovered","setHoveredState","holding","setHolding","root","setRoot","hoveredRef","setHovered","prev","latest","gesture","setActive","next","start","stop","toggle","commit","_b","_a","pick","current","many","cap","props","base","p","entry","parseElement","remove","clear","isPicked","resolve","x","y","pass","ignore","hit","doc","html","held","inIgnored","target","hoverAt","onPointerMove","endHold","onPointerDown","onPointerUp","wasHolding","onClick","swallow","onTouchMove","touch","onKeyDown","parent","child","opts","prior"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-element-picker.js","sources":["../../../src/components/element-picker/use-element-picker.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { parseElement } from './parse';\nimport type { PickedElement } from './types';\n\n/** Stable ids, so re-picking the same node doesn't churn React keys. */\nconst IDS = new WeakMap<HTMLElement, string>();\nlet seq = 0;\nconst idOf = (el: HTMLElement) => {\n let id = IDS.get(el);\n if (!id) {\n id = `el-${++seq}`;\n IDS.set(el, id);\n }\n return id;\n};\n\nexport interface UseElementPickerOptions {\n /** The subtree you can pick from. Defaults to `document.body`. */\n root?: HTMLElement | null;\n /** Keep picking after the first hit. Default true. */\n multiple?: boolean;\n /** Controlled selection. */\n value?: PickedElement[];\n defaultValue?: PickedElement[];\n /** Called with the full selection whenever it changes. */\n onValueChange?: (picked: PickedElement[]) => void;\n /** @deprecated Use `onValueChange`. */\n onChange?: (picked: PickedElement[]) => void;\n onPick?: (picked: PickedElement) => void;\n /** Controlled picking mode. */\n active?: boolean;\n onActiveChange?: (active: boolean) => void;\n /**\n * Which elements may be picked. When an element fails, the picker walks up to\n * the nearest ancestor that passes — so `(el) => el.matches('.card')` turns it\n * into a card picker, however deep the pointer actually lands.\n */\n filter?: (el: HTMLElement) => boolean;\n /** Subtrees the picker won't look at — your own toolbar, typically. */\n ignoreSelector?: string;\n /** Override which computed properties get captured. */\n styleProps?: string[];\n /** Touch: how long to hold before hover mode engages, in ms. Default 350. */\n holdDelay?: number;\n /** Touch: movement (px) that reads as a scroll and cancels the hold. Default 12. */\n moveTolerance?: number;\n /** Cap the selection. Picking past it drops the oldest. */\n max?: number;\n}\n\nexport interface UseElementPickerResult {\n active: boolean;\n start: () => void;\n stop: () => void;\n toggle: () => void;\n /** What the pointer is over right now — the live preview target. */\n hovered: HTMLElement | null;\n /** True while a touch hold has engaged hover mode. */\n holding: boolean;\n picked: PickedElement[];\n pick: (el: HTMLElement) => void;\n remove: (id: string) => void;\n clear: () => void;\n isPicked: (el: HTMLElement) => boolean;\n root: HTMLElement | null;\n /** Put this on any UI of your own that must stay clickable while picking. */\n ignoreProps: Record<string, string>;\n}\n\nconst IGNORE_ATTR = 'data-element-picker-ignore';\n\n/** How long after a touch pick a click is still assumed to be its replay. */\nconst COMPAT_CLICK_MS = 700;\n\n/**\n * The machinery behind {@link ElementPicker}: hover tracking, click-to-select,\n * and the press-and-hold gesture that turns a touchscreen — which has no hover\n * — into one. Use it directly when you want the behaviour without the overlay.\n */\nexport function useElementPicker(options: UseElementPickerOptions = {}): UseElementPickerResult {\n const {\n root: rootProp,\n multiple = true,\n value,\n defaultValue = [],\n onValueChange,\n onChange,\n onPick,\n active: activeProp,\n onActiveChange,\n filter,\n ignoreSelector = `[${IGNORE_ATTR}]`,\n styleProps,\n holdDelay = 350,\n moveTolerance = 12,\n max,\n } = options;\n\n // The deprecated `onChange` alias still fires; `onValueChange` wins when both are given.\n const handleValueChange = onValueChange ?? onChange;\n\n const [activeState, setActiveState] = React.useState(false);\n const active = activeProp ?? activeState;\n\n const [pickedState, setPickedState] = React.useState<PickedElement[]>(defaultValue);\n const picked = value ?? pickedState;\n\n const [hovered, setHoveredState] = React.useState<HTMLElement | null>(null);\n const [holding, setHolding] = React.useState(false);\n const [root, setRoot] = React.useState<HTMLElement | null>(null);\n\n // Mirrored into a ref so the listeners below can read the hover without being\n // torn down and rebound on every pointer move.\n const hoveredRef = React.useRef<HTMLElement | null>(null);\n const setHovered = React.useCallback((el: HTMLElement | null) => {\n hoveredRef.current = el;\n setHoveredState((prev) => (prev === el ? prev : el));\n }, []);\n\n // Latest props, read from listeners that are only bound once per activation.\n // `controlled` lives here too so `commit` — and therefore `pick`, and\n // therefore the listener effect — stays referentially stable across a pick.\n const latest = React.useRef({\n picked,\n multiple,\n max,\n filter,\n ignoreSelector,\n styleProps,\n onValueChange: handleValueChange,\n onPick,\n root,\n controlled: value !== undefined,\n stop: () => {},\n });\n latest.current = {\n ...latest.current,\n picked,\n multiple,\n max,\n filter,\n ignoreSelector,\n styleProps,\n onValueChange: handleValueChange,\n onPick,\n root,\n controlled: value !== undefined,\n };\n\n /**\n * Gesture state, held across effect re-binds. It cannot live inside the\n * effect: a pick changes `picked`, which can re-run the effect *between* a\n * touch's pointerup and the compatibility click it triggers — and a fresh\n * object there would lose the very stamp that click has to be checked against.\n */\n const gesture = React.useRef({\n timer: undefined as ReturnType<typeof setTimeout> | undefined,\n from: null as { x: number; y: number } | null,\n on: false,\n /**\n * When a touch ends in a pick, the browser replays it as a compatibility\n * mouse sequence — pointerdown, mousedown, mouseup, *click* — on the same\n * spot. That click would pick the element a second time, and a second pick\n * is a deselect, so the tap would appear to do nothing at all. We stamp the\n * pick and ignore any click landing in its wake. A stamp rather than a flag\n * because the replay isn't guaranteed to arrive: a flag left standing would\n * go on to eat somebody's real click.\n */\n pickedAt: 0,\n });\n\n React.useEffect(() => {\n setRoot(rootProp ?? (typeof document === 'undefined' ? null : document.body));\n }, [rootProp]);\n\n const setActive = React.useCallback(\n (next: boolean) => {\n if (activeProp === undefined) setActiveState(next);\n onActiveChange?.(next);\n },\n [activeProp, onActiveChange],\n );\n\n const start = React.useCallback(() => setActive(true), [setActive]);\n const stop = React.useCallback(() => setActive(false), [setActive]);\n const toggle = React.useCallback(() => setActive(!active), [active, setActive]);\n latest.current.stop = stop;\n\n const commit = React.useCallback((next: PickedElement[]) => {\n if (!latest.current.controlled) setPickedState(next);\n latest.current.onValueChange?.(next);\n }, []);\n\n const pick = React.useCallback(\n (el: HTMLElement) => {\n const { picked: current, multiple: many, max: cap, styleProps: props, root: base } = latest.current;\n const id = idOf(el);\n\n // A second click on a selected element unselects it — the only way back\n // out of a mis-pick without leaving the flow.\n if (current.some((p) => p.id === id)) {\n commit(current.filter((p) => p.id !== id));\n return;\n }\n\n const entry: PickedElement = {\n id,\n element: el,\n info: parseElement(el, { root: base ?? undefined, styleProps: props }),\n };\n let next = many ? [...current, entry] : [entry];\n if (cap && next.length > cap) next = next.slice(next.length - cap);\n\n commit(next);\n latest.current.onPick?.(entry);\n },\n [commit],\n );\n\n const remove = React.useCallback(\n (id: string) => commit(latest.current.picked.filter((p) => p.id !== id)),\n [commit],\n );\n const clear = React.useCallback(() => commit([]), [commit]);\n const isPicked = React.useCallback((el: HTMLElement) => picked.some((p) => p.element === el), [picked]);\n\n /** The pickable element under a viewport point, or null. */\n const resolve = React.useCallback((x: number, y: number): HTMLElement | null => {\n const { root: base, filter: pass, ignoreSelector: ignore } = latest.current;\n if (!base) return null;\n\n // The overlay is pointer-events:none, so elementFromPoint looks straight\n // through it at the page underneath.\n const hit = base.ownerDocument.elementFromPoint(x, y);\n if (!(hit instanceof HTMLElement)) return null;\n if (ignore && hit.closest(ignore)) return null;\n if (!base.contains(hit) || hit === base) return null;\n\n if (!pass) return hit;\n // Walk up to the nearest ancestor that passes, but never past the root —\n // the root is the frame, not something you can pick.\n for (let el: HTMLElement | null = hit; el && el !== base; el = el.parentElement) {\n if (pass(el)) return el;\n }\n return null;\n }, []);\n\n // Picking mode: swallow the page's own pointer handling, track the hover, and\n // take a click as a pick.\n React.useEffect(() => {\n if (!active || !root) return;\n\n const doc = root.ownerDocument;\n const html = doc.documentElement;\n const held = gesture.current;\n held.timer = undefined;\n held.from = null;\n held.on = false;\n\n const inIgnored = (target: EventTarget | null) => {\n const { ignoreSelector: ignore } = latest.current;\n return !!(ignore && target instanceof Element && target.closest(ignore));\n };\n\n const hoverAt = (x: number, y: number) => setHovered(resolve(x, y));\n\n const onPointerMove = (e: PointerEvent) => {\n if (e.pointerType === 'touch') {\n if (held.on) {\n hoverAt(e.clientX, e.clientY);\n } else if (held.from && Math.hypot(e.clientX - held.from.x, e.clientY - held.from.y) > moveTolerance) {\n clearTimeout(held.timer); // they're scrolling, not holding\n held.from = null;\n }\n return;\n }\n hoverAt(e.clientX, e.clientY);\n };\n\n const endHold = () => {\n clearTimeout(held.timer);\n held.from = null;\n if (held.on) {\n held.on = false;\n setHolding(false);\n }\n };\n\n const onPointerDown = (e: PointerEvent) => {\n if (inIgnored(e.target)) return;\n\n if (e.pointerType === 'touch') {\n held.from = { x: e.clientX, y: e.clientY };\n held.timer = setTimeout(() => {\n held.on = true;\n held.from = null;\n setHolding(true);\n // A tick of haptics, so the hold registers without looking at the screen.\n navigator.vibrate?.(12);\n hoverAt(e.clientX, e.clientY);\n }, holdDelay);\n return;\n }\n\n // Mouse: keep the press off the page (no text selection, no drag start).\n e.preventDefault();\n e.stopPropagation();\n };\n\n const onPointerUp = (e: PointerEvent) => {\n if (inIgnored(e.target)) return;\n\n if (e.pointerType === 'touch') {\n const wasHolding = held.on;\n endHold();\n // Either way the finger lifts on the element it was previewing: a hold\n // and drag commits what's under it, a plain tap commits what it hit.\n const target = resolve(e.clientX, e.clientY);\n if (target) {\n pick(target);\n held.pickedAt = performance.now();\n }\n if (wasHolding || target) setHovered(null);\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n e.preventDefault();\n e.stopPropagation();\n };\n\n const onClick = (e: MouseEvent) => {\n if (inIgnored(e.target)) return;\n // Never let the page act on a pick — no navigation, no form submit.\n e.preventDefault();\n e.stopPropagation();\n if (e.detail === 0) return; // synthetic (keyboard) click, not a real one\n\n // The compatibility click replaying the touch we already picked from.\n if (performance.now() - held.pickedAt < COMPAT_CLICK_MS) return;\n\n const target = resolve(e.clientX, e.clientY);\n if (target) pick(target);\n };\n\n const swallow = (e: Event) => {\n if (inIgnored(e.target)) return;\n e.preventDefault();\n e.stopPropagation();\n };\n\n // Non-passive: this is what stops the page scrolling under a held finger.\n const onTouchMove = (e: TouchEvent) => {\n if (!held.on) return;\n e.preventDefault();\n const touch = e.touches[0];\n if (touch) hoverAt(touch.clientX, touch.clientY);\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n latest.current.stop();\n return;\n }\n const current = hoveredRef.current;\n if (!current) return;\n\n // Walk the tree without moving the mouse — the devtools reflex.\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n const parent = current.parentElement;\n if (parent && parent !== root.parentElement && root.contains(parent)) setHovered(parent);\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n const child = current.firstElementChild;\n if (child instanceof HTMLElement) setHovered(child);\n } else if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n pick(current);\n }\n };\n\n const opts = { capture: true } as const;\n window.addEventListener('pointermove', onPointerMove, opts);\n window.addEventListener('pointerdown', onPointerDown, opts);\n window.addEventListener('pointerup', onPointerUp, opts);\n window.addEventListener('pointercancel', endHold, opts);\n window.addEventListener('click', onClick, opts);\n window.addEventListener('mousedown', swallow, opts);\n window.addEventListener('mouseup', swallow, opts);\n window.addEventListener('dblclick', swallow, opts);\n window.addEventListener('contextmenu', swallow, opts);\n window.addEventListener('keydown', onKeyDown, opts);\n doc.addEventListener('touchmove', onTouchMove, { passive: false, capture: true });\n\n const prior = html.style.cssText;\n html.style.cursor = 'crosshair';\n html.style.userSelect = 'none';\n html.style.webkitUserSelect = 'none';\n (html.style as CSSStyleDeclaration & { webkitTouchCallout?: string }).webkitTouchCallout = 'none';\n\n return () => {\n clearTimeout(held.timer);\n window.removeEventListener('pointermove', onPointerMove, opts);\n window.removeEventListener('pointerdown', onPointerDown, opts);\n window.removeEventListener('pointerup', onPointerUp, opts);\n window.removeEventListener('pointercancel', endHold, opts);\n window.removeEventListener('click', onClick, opts);\n window.removeEventListener('mousedown', swallow, opts);\n window.removeEventListener('mouseup', swallow, opts);\n window.removeEventListener('dblclick', swallow, opts);\n window.removeEventListener('contextmenu', swallow, opts);\n window.removeEventListener('keydown', onKeyDown, opts);\n doc.removeEventListener('touchmove', onTouchMove, { capture: true });\n html.style.cssText = prior;\n setHovered(null);\n setHolding(false);\n };\n }, [active, root, holdDelay, moveTolerance, pick, resolve, setHovered]);\n\n return {\n active,\n start,\n stop,\n toggle,\n hovered,\n holding,\n picked,\n pick,\n remove,\n clear,\n isPicked,\n root,\n ignoreProps: { [IGNORE_ATTR]: '' },\n };\n}\n"],"names":["IDS","seq","idOf","el","id","IGNORE_ATTR","COMPAT_CLICK_MS","useElementPicker","options","rootProp","multiple","value","defaultValue","onValueChange","onChange","onPick","activeProp","onActiveChange","filter","ignoreSelector","styleProps","holdDelay","moveTolerance","max","handleValueChange","activeState","setActiveState","React","active","pickedState","setPickedState","picked","hovered","setHoveredState","holding","setHolding","root","setRoot","hoveredRef","setHovered","prev","latest","gesture","setActive","next","start","stop","toggle","commit","_b","_a","pick","current","many","cap","props","base","p","entry","parseElement","remove","clear","isPicked","resolve","x","y","pass","ignore","hit","doc","html","held","inIgnored","target","hoverAt","onPointerMove","endHold","onPointerDown","onPointerUp","wasHolding","onClick","swallow","onTouchMove","touch","onKeyDown","parent","child","opts","prior"],"mappings":";;AAMA,MAAMA,wBAAU,QAAA;AAChB,IAAIC,KAAM;AACV,MAAMC,KAAO,CAACC,MAAoB;AAChC,MAAIC,IAAKJ,EAAI,IAAIG,CAAE;AACnB,SAAKC,MACHA,IAAK,MAAM,EAAEH,EAAG,IAChBD,EAAI,IAAIG,GAAIC,CAAE,IAETA;AACT,GAuDMC,IAAc,8BAGdC,KAAkB;AAOjB,SAASC,GAAiBC,IAAmC,IAA4B;AAC9F,QAAM;AAAA,IACJ,MAAMC;AAAA,IACN,UAAAC,IAAW;AAAA,IACX,OAAAC;AAAA,IACA,cAAAC,IAAe,CAAA;AAAA,IACf,eAAAC;AAAA,IACA,UAAAC;AAAA,IACA,QAAAC;AAAA,IACA,QAAQC;AAAA,IACR,gBAAAC;AAAA,IACA,QAAAC;AAAA,IACA,gBAAAC,IAAiB,IAAId,CAAW;AAAA,IAChC,YAAAe;AAAA,IACA,WAAAC,IAAY;AAAA,IACZ,eAAAC,IAAgB;AAAA,IAChB,KAAAC;AAAA,EAAA,IACEf,GAGEgB,IAAoBX,KAAiBC,GAErC,CAACW,GAAaC,CAAc,IAAIC,EAAM,SAAS,EAAK,GACpDC,IAASZ,KAAcS,GAEvB,CAACI,GAAaC,CAAc,IAAIH,EAAM,SAA0Bf,CAAY,GAC5EmB,IAASpB,KAASkB,GAElB,CAACG,GAASC,EAAe,IAAIN,EAAM,SAA6B,IAAI,GACpE,CAACO,IAASC,CAAU,IAAIR,EAAM,SAAS,EAAK,GAC5C,CAACS,GAAMC,EAAO,IAAIV,EAAM,SAA6B,IAAI,GAIzDW,IAAaX,EAAM,OAA2B,IAAI,GAClDY,IAAaZ,EAAM,YAAY,CAACxB,MAA2B;AAC/D,IAAAmC,EAAW,UAAUnC,GACrB8B,GAAgB,CAACO,MAAUA,MAASrC,IAAKqC,IAAOrC,CAAG;AAAA,EACrD,GAAG,CAAA,CAAE,GAKCsC,IAASd,EAAM,OAAO;AAAA,IAC1B,QAAAI;AAAA,IACA,UAAArB;AAAA,IACA,KAAAa;AAAA,IACA,QAAAL;AAAA,IACA,gBAAAC;AAAA,IACA,YAAAC;AAAA,IACA,eAAeI;AAAA,IACf,QAAAT;AAAA,IACA,MAAAqB;AAAA,IACA,YAAYzB,MAAU;AAAA,IACtB,MAAM,MAAM;AAAA,IAAC;AAAA,EAAA,CACd;AACD,EAAA8B,EAAO,UAAU;AAAA,IACf,GAAGA,EAAO;AAAA,IACV,QAAAV;AAAA,IACA,UAAArB;AAAA,IACA,KAAAa;AAAA,IACA,QAAAL;AAAA,IACA,gBAAAC;AAAA,IACA,YAAAC;AAAA,IACA,eAAeI;AAAA,IACf,QAAAT;AAAA,IACA,MAAAqB;AAAA,IACA,YAAYzB,MAAU;AAAA,EAAA;AASxB,QAAM+B,KAAUf,EAAM,OAAO;AAAA,IAC3B,OAAO;AAAA,IACP,MAAM;AAAA,IACN,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAUJ,UAAU;AAAA,EAAA,CACX;AAED,EAAAA,EAAM,UAAU,MAAM;AACpB,IAAAU,GAAQ5B,MAAa,OAAO,WAAa,MAAc,OAAO,SAAS,KAAK;AAAA,EAC9E,GAAG,CAACA,CAAQ,CAAC;AAEb,QAAMkC,IAAYhB,EAAM;AAAA,IACtB,CAACiB,MAAkB;AACjB,MAAI5B,MAAe,UAAWU,EAAekB,CAAI,GACjD3B,KAAA,QAAAA,EAAiB2B;AAAA,IACnB;AAAA,IACA,CAAC5B,GAAYC,CAAc;AAAA,EAAA,GAGvB4B,KAAQlB,EAAM,YAAY,MAAMgB,EAAU,EAAI,GAAG,CAACA,CAAS,CAAC,GAC5DG,IAAOnB,EAAM,YAAY,MAAMgB,EAAU,EAAK,GAAG,CAACA,CAAS,CAAC,GAC5DI,KAASpB,EAAM,YAAY,MAAMgB,EAAU,CAACf,CAAM,GAAG,CAACA,GAAQe,CAAS,CAAC;AAC9E,EAAAF,EAAO,QAAQ,OAAOK;AAEtB,QAAME,IAASrB,EAAM,YAAY,CAACiB,MAA0B;;AAC1D,IAAKH,EAAO,QAAQ,gBAA2BG,CAAI,IACnDK,KAAAC,IAAAT,EAAO,SAAQ,kBAAf,QAAAQ,EAAA,KAAAC,GAA+BN;AAAA,EACjC,GAAG,CAAA,CAAE,GAECO,IAAOxB,EAAM;AAAA,IACjB,CAACxB,MAAoB;;AACnB,YAAM,EAAE,QAAQiD,GAAS,UAAUC,GAAM,KAAKC,GAAK,YAAYC,GAAO,MAAMC,EAAA,IAASf,EAAO,SACtFrC,IAAKF,GAAKC,CAAE;AAIlB,UAAIiD,EAAQ,KAAK,CAACK,MAAMA,EAAE,OAAOrD,CAAE,GAAG;AACpC,QAAA4C,EAAOI,EAAQ,OAAO,CAACK,MAAMA,EAAE,OAAOrD,CAAE,CAAC;AACzC;AAAA,MACF;AAEA,YAAMsD,IAAuB;AAAA,QAC3B,IAAAtD;AAAA,QACA,SAASD;AAAA,QACT,MAAMwD,GAAaxD,GAAI,EAAE,MAAMqD,KAAQ,QAAW,YAAYD,EAAA,CAAO;AAAA,MAAA;AAEvE,UAAIX,IAAOS,IAAO,CAAC,GAAGD,GAASM,CAAK,IAAI,CAACA,CAAK;AAC9C,MAAIJ,KAAOV,EAAK,SAASU,UAAYV,EAAK,MAAMA,EAAK,SAASU,CAAG,IAEjEN,EAAOJ,CAAI,IACXK,KAAAC,IAAAT,EAAO,SAAQ,WAAf,QAAAQ,EAAA,KAAAC,GAAwBQ;AAAA,IAC1B;AAAA,IACA,CAACV,CAAM;AAAA,EAAA,GAGHY,KAASjC,EAAM;AAAA,IACnB,CAACvB,MAAe4C,EAAOP,EAAO,QAAQ,OAAO,OAAO,CAACgB,MAAMA,EAAE,OAAOrD,CAAE,CAAC;AAAA,IACvE,CAAC4C,CAAM;AAAA,EAAA,GAEHa,KAAQlC,EAAM,YAAY,MAAMqB,EAAO,EAAE,GAAG,CAACA,CAAM,CAAC,GACpDc,KAAWnC,EAAM,YAAY,CAACxB,MAAoB4B,EAAO,KAAK,CAAC0B,MAAMA,EAAE,YAAYtD,CAAE,GAAG,CAAC4B,CAAM,CAAC,GAGhGgC,IAAUpC,EAAM,YAAY,CAACqC,GAAWC,MAAkC;AAC9E,UAAM,EAAE,MAAMT,GAAM,QAAQU,GAAM,gBAAgBC,MAAW1B,EAAO;AACpE,QAAI,CAACe,EAAM,QAAO;AAIlB,UAAMY,IAAMZ,EAAK,cAAc,iBAAiBQ,GAAGC,CAAC;AAGpD,QAFI,EAAEG,aAAe,gBACjBD,KAAUC,EAAI,QAAQD,CAAM,KAC5B,CAACX,EAAK,SAASY,CAAG,KAAKA,MAAQZ,EAAM,QAAO;AAEhD,QAAI,CAACU,EAAM,QAAOE;AAGlB,aAASjE,IAAyBiE,GAAKjE,KAAMA,MAAOqD,GAAMrD,IAAKA,EAAG;AAChE,UAAI+D,EAAK/D,CAAE,EAAG,QAAOA;AAEvB,WAAO;AAAA,EACT,GAAG,CAAA,CAAE;AAIL,SAAAwB,EAAM,UAAU,MAAM;AACpB,QAAI,CAACC,KAAU,CAACQ,EAAM;AAEtB,UAAMiC,IAAMjC,EAAK,eACXkC,IAAOD,EAAI,iBACXE,IAAO7B,GAAQ;AACrB,IAAA6B,EAAK,QAAQ,QACbA,EAAK,OAAO,MACZA,EAAK,KAAK;AAEV,UAAMC,IAAY,CAACC,MAA+B;AAChD,YAAM,EAAE,gBAAgBN,EAAA,IAAW1B,EAAO;AAC1C,aAAO,CAAC,EAAE0B,KAAUM,aAAkB,WAAWA,EAAO,QAAQN,CAAM;AAAA,IACxE,GAEMO,IAAU,CAACV,GAAWC,MAAc1B,EAAWwB,EAAQC,GAAGC,CAAC,CAAC,GAE5DU,IAAgB,CAAC,MAAoB;AACzC,UAAI,EAAE,gBAAgB,SAAS;AAC7B,QAAIJ,EAAK,KACPG,EAAQ,EAAE,SAAS,EAAE,OAAO,IACnBH,EAAK,QAAQ,KAAK,MAAM,EAAE,UAAUA,EAAK,KAAK,GAAG,EAAE,UAAUA,EAAK,KAAK,CAAC,IAAIjD,MACrF,aAAaiD,EAAK,KAAK,GACvBA,EAAK,OAAO;AAEd;AAAA,MACF;AACA,MAAAG,EAAQ,EAAE,SAAS,EAAE,OAAO;AAAA,IAC9B,GAEME,IAAU,MAAM;AACpB,mBAAaL,EAAK,KAAK,GACvBA,EAAK,OAAO,MACRA,EAAK,OACPA,EAAK,KAAK,IACVpC,EAAW,EAAK;AAAA,IAEpB,GAEM0C,IAAgB,CAAC,MAAoB;AACzC,UAAI,CAAAL,EAAU,EAAE,MAAM,GAEtB;AAAA,YAAI,EAAE,gBAAgB,SAAS;AAC7B,UAAAD,EAAK,OAAO,EAAE,GAAG,EAAE,SAAS,GAAG,EAAE,QAAA,GACjCA,EAAK,QAAQ,WAAW,MAAM;;AAC5B,YAAAA,EAAK,KAAK,IACVA,EAAK,OAAO,MACZpC,EAAW,EAAI,IAEfe,IAAA,UAAU,YAAV,QAAAA,EAAA,gBAAoB,KACpBwB,EAAQ,EAAE,SAAS,EAAE,OAAO;AAAA,UAC9B,GAAGrD,CAAS;AACZ;AAAA,QACF;AAGA,UAAE,eAAA,GACF,EAAE,gBAAA;AAAA;AAAA,IACJ,GAEMyD,IAAc,CAAC,MAAoB;AACvC,UAAI,CAAAN,EAAU,EAAE,MAAM,GAEtB;AAAA,YAAI,EAAE,gBAAgB,SAAS;AAC7B,gBAAMO,IAAaR,EAAK;AACxB,UAAAK,EAAA;AAGA,gBAAMH,IAASV,EAAQ,EAAE,SAAS,EAAE,OAAO;AAC3C,UAAIU,MACFtB,EAAKsB,CAAM,GACXF,EAAK,WAAW,YAAY,IAAA,KAE1BQ,KAAcN,MAAQlC,EAAW,IAAI,GACzC,EAAE,eAAA,GACF,EAAE,gBAAA;AACF;AAAA,QACF;AACA,UAAE,eAAA,GACF,EAAE,gBAAA;AAAA;AAAA,IACJ,GAEMyC,IAAU,CAAC,MAAkB;AAQjC,UAPIR,EAAU,EAAE,MAAM,MAEtB,EAAE,eAAA,GACF,EAAE,gBAAA,GACE,EAAE,WAAW,MAGb,YAAY,IAAA,IAAQD,EAAK,WAAWjE,GAAiB;AAEzD,YAAMmE,IAASV,EAAQ,EAAE,SAAS,EAAE,OAAO;AAC3C,MAAIU,OAAaA,CAAM;AAAA,IACzB,GAEMQ,IAAU,CAAC,MAAa;AAC5B,MAAIT,EAAU,EAAE,MAAM,MACtB,EAAE,eAAA,GACF,EAAE,gBAAA;AAAA,IACJ,GAGMU,IAAc,CAAC,MAAkB;AACrC,UAAI,CAACX,EAAK,GAAI;AACd,QAAE,eAAA;AACF,YAAMY,IAAQ,EAAE,QAAQ,CAAC;AACzB,MAAIA,KAAOT,EAAQS,EAAM,SAASA,EAAM,OAAO;AAAA,IACjD,GAEMC,IAAY,CAAC,MAAqB;AACtC,UAAI,EAAE,QAAQ,UAAU;AACtB,UAAE,eAAA,GACF3C,EAAO,QAAQ,KAAA;AACf;AAAA,MACF;AACA,YAAMW,IAAUd,EAAW;AAC3B,UAAKc;AAGL,YAAI,EAAE,QAAQ,WAAW;AACvB,YAAE,eAAA;AACF,gBAAMiC,IAASjC,EAAQ;AACvB,UAAIiC,KAAUA,MAAWjD,EAAK,iBAAiBA,EAAK,SAASiD,CAAM,KAAG9C,EAAW8C,CAAM;AAAA,QACzF,WAAW,EAAE,QAAQ,aAAa;AAChC,YAAE,eAAA;AACF,gBAAMC,IAAQlC,EAAQ;AACtB,UAAIkC,aAAiB,eAAa/C,EAAW+C,CAAK;AAAA,QACpD,QAAW,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACxC,EAAE,eAAA,GACFnC,EAAKC,CAAO;AAAA,IAEhB,GAEMmC,IAAO,EAAE,SAAS,GAAA;AACxB,WAAO,iBAAiB,eAAeZ,GAAeY,CAAI,GAC1D,OAAO,iBAAiB,eAAeV,GAAeU,CAAI,GAC1D,OAAO,iBAAiB,aAAaT,GAAaS,CAAI,GACtD,OAAO,iBAAiB,iBAAiBX,GAASW,CAAI,GACtD,OAAO,iBAAiB,SAASP,GAASO,CAAI,GAC9C,OAAO,iBAAiB,aAAaN,GAASM,CAAI,GAClD,OAAO,iBAAiB,WAAWN,GAASM,CAAI,GAChD,OAAO,iBAAiB,YAAYN,GAASM,CAAI,GACjD,OAAO,iBAAiB,eAAeN,GAASM,CAAI,GACpD,OAAO,iBAAiB,WAAWH,GAAWG,CAAI,GAClDlB,EAAI,iBAAiB,aAAaa,GAAa,EAAE,SAAS,IAAO,SAAS,IAAM;AAEhF,UAAMM,KAAQlB,EAAK,MAAM;AACzB,WAAAA,EAAK,MAAM,SAAS,aACpBA,EAAK,MAAM,aAAa,QACxBA,EAAK,MAAM,mBAAmB,QAC7BA,EAAK,MAAgE,qBAAqB,QAEpF,MAAM;AACX,mBAAaC,EAAK,KAAK,GACvB,OAAO,oBAAoB,eAAeI,GAAeY,CAAI,GAC7D,OAAO,oBAAoB,eAAeV,GAAeU,CAAI,GAC7D,OAAO,oBAAoB,aAAaT,GAAaS,CAAI,GACzD,OAAO,oBAAoB,iBAAiBX,GAASW,CAAI,GACzD,OAAO,oBAAoB,SAASP,GAASO,CAAI,GACjD,OAAO,oBAAoB,aAAaN,GAASM,CAAI,GACrD,OAAO,oBAAoB,WAAWN,GAASM,CAAI,GACnD,OAAO,oBAAoB,YAAYN,GAASM,CAAI,GACpD,OAAO,oBAAoB,eAAeN,GAASM,CAAI,GACvD,OAAO,oBAAoB,WAAWH,GAAWG,CAAI,GACrDlB,EAAI,oBAAoB,aAAaa,GAAa,EAAE,SAAS,IAAM,GACnEZ,EAAK,MAAM,UAAUkB,IACrBjD,EAAW,IAAI,GACfJ,EAAW,EAAK;AAAA,IAClB;AAAA,EACF,GAAG,CAACP,GAAQQ,GAAMf,GAAWC,GAAe6B,GAAMY,GAASxB,CAAU,CAAC,GAE/D;AAAA,IACL,QAAAX;AAAA,IACA,OAAAiB;AAAA,IACA,MAAAC;AAAA,IACA,QAAAC;AAAA,IACA,SAAAf;AAAA,IACA,SAAAE;AAAA,IACA,QAAAH;AAAA,IACA,MAAAoB;AAAA,IACA,QAAAS;AAAA,IACA,OAAAC;AAAA,IACA,UAAAC;AAAA,IACA,MAAA1B;AAAA,IACA,aAAa,EAAE,CAAC/B,CAAW,GAAG,GAAA;AAAA,EAAG;AAErC;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fuzzy-list.test.d.ts","sourceRoot":"","sources":["../../../src/components/fuzzy-list/fuzzy-list.test.tsx"],"names":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../src/components/input/input.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,WAAW,UAAW,SAAQ,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC;IAC/D;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACrC;AAYD,2EAA2E;AAC3E,wBAAgB,KAAK,CAAC,EACpB,SAAS,EACT,IAAI,EACJ,QAAQ,EACR,aAAuB,EACvB,QAAQ,EACR,YAAY,EACZ,GAAG,KAAK,EACT,EAAE,UAAU,qBAwCZ"}
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../src/components/input/input.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,6EAA6E;AAC7E,MAAM,WAAW,UAAW,SAAQ,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC;IAC/D;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACrC;AAYD,2EAA2E;AAC3E,wBAAgB,KAAK,CAAC,EACpB,SAAS,EACT,IAAI,EACJ,QAAQ,EACR,aAAuB,EACvB,QAAQ,EACR,YAAY,EACZ,GAAG,KAAK,EACT,EAAE,UAAU,qBAwCZ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.js","sources":["../../../src/components/input/input.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../../lib/utils';\n\nexport interface InputProps extends React.ComponentProps<'input'> {\n /**\n * Persist the input's value under this key so it survives a page reload.\n * The value is restored on mount and written on every change. Works with\n * uncontrolled inputs (restores via `defaultValue`); a controlled `value`\n * is still mirrored to storage on change. Omit to disable caching.\n */\n cacheKey?: string;\n /** Where to cache when `cacheKey` is set. Default: `\"local\"`. */\n cacheLocation?: 'local' | 'session';\n}\n\n/** Resolve the requested Web Storage, tolerating SSR and blocked cookies. */\nfunction getStore(location: 'local' | 'session'): Storage | null {\n if (typeof window === 'undefined') return null;\n try {\n return location === 'session' ? window.sessionStorage : window.localStorage;\n } catch {\n return null;\n }\n}\n\n/** A minimal Tailwind text input, styled from the shared design tokens. */\nexport function Input({\n className,\n type,\n cacheKey,\n cacheLocation = 'local',\n onChange,\n defaultValue,\n ...props\n}: InputProps) {\n const store = cacheKey ? getStore(cacheLocation) : null;\n\n // Read the cached value once, synchronously, so the first render already\n // shows it (avoids a flash of empty input on reload).\n const [cached] = React.useState<string | null>(() => {\n if (!store || !cacheKey) return null;\n try {\n return store.getItem(cacheKey);\n } catch {\n return null;\n }\n });\n\n const handleChange = React.useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n if (store && cacheKey) {\n try {\n store.setItem(cacheKey, e.target.value);\n } catch {\n /* storage full or unavailable — degrade to a plain input */\n }\n }\n onChange?.(e);\n },\n [store, cacheKey, onChange],\n );\n\n return (\n <input\n type={type}\n defaultValue={cacheKey ? (cached ?? defaultValue) : defaultValue}\n onChange={cacheKey ? handleChange : onChange}\n className={cn(\n 'h-9 w-full min-w-0 rounded-lg border border-input bg-transparent px-3 py-1 text-base transition-colors outline-none placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 md:text-sm',\n className,\n )}\n {...props}\n />\n );\n}\n"],"names":["getStore","location","Input","className","type","cacheKey","cacheLocation","onChange","defaultValue","props","store","cached","React","handleChange","e","jsx","cn"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"input.js","sources":["../../../src/components/input/input.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../../lib/utils';\n\n/** Everything a native `<input>` takes, plus optional reload persistence. */\nexport interface InputProps extends React.ComponentProps<'input'> {\n /**\n * Persist the input's value under this key so it survives a page reload.\n * The value is restored on mount and written on every change. Works with\n * uncontrolled inputs (restores via `defaultValue`); a controlled `value`\n * is still mirrored to storage on change. Omit to disable caching.\n */\n cacheKey?: string;\n /** Where to cache when `cacheKey` is set. Default: `\"local\"`. */\n cacheLocation?: 'local' | 'session';\n}\n\n/** Resolve the requested Web Storage, tolerating SSR and blocked cookies. */\nfunction getStore(location: 'local' | 'session'): Storage | null {\n if (typeof window === 'undefined') return null;\n try {\n return location === 'session' ? window.sessionStorage : window.localStorage;\n } catch {\n return null;\n }\n}\n\n/** A minimal Tailwind text input, styled from the shared design tokens. */\nexport function Input({\n className,\n type,\n cacheKey,\n cacheLocation = 'local',\n onChange,\n defaultValue,\n ...props\n}: InputProps) {\n const store = cacheKey ? getStore(cacheLocation) : null;\n\n // Read the cached value once, synchronously, so the first render already\n // shows it (avoids a flash of empty input on reload).\n const [cached] = React.useState<string | null>(() => {\n if (!store || !cacheKey) return null;\n try {\n return store.getItem(cacheKey);\n } catch {\n return null;\n }\n });\n\n const handleChange = React.useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n if (store && cacheKey) {\n try {\n store.setItem(cacheKey, e.target.value);\n } catch {\n /* storage full or unavailable — degrade to a plain input */\n }\n }\n onChange?.(e);\n },\n [store, cacheKey, onChange],\n );\n\n return (\n <input\n type={type}\n defaultValue={cacheKey ? (cached ?? defaultValue) : defaultValue}\n onChange={cacheKey ? handleChange : onChange}\n className={cn(\n 'h-9 w-full min-w-0 rounded-lg border border-input bg-transparent px-3 py-1 text-base transition-colors outline-none placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 md:text-sm',\n className,\n )}\n {...props}\n />\n );\n}\n"],"names":["getStore","location","Input","className","type","cacheKey","cacheLocation","onChange","defaultValue","props","store","cached","React","handleChange","e","jsx","cn"],"mappings":";;;AAkBA,SAASA,EAASC,GAA+C;AAC/D,MAAI,OAAO,SAAW,IAAa,QAAO;AAC1C,MAAI;AACF,WAAOA,MAAa,YAAY,OAAO,iBAAiB,OAAO;AAAA,EACjE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAASC,EAAM;AAAA,EACpB,WAAAC;AAAA,EACA,MAAAC;AAAA,EACA,UAAAC;AAAA,EACA,eAAAC,IAAgB;AAAA,EAChB,UAAAC;AAAA,EACA,cAAAC;AAAA,EACA,GAAGC;AACL,GAAe;AACb,QAAMC,IAAQL,IAAWL,EAASM,CAAa,IAAI,MAI7C,CAACK,CAAM,IAAIC,EAAM,SAAwB,MAAM;AACnD,QAAI,CAACF,KAAS,CAACL,EAAU,QAAO;AAChC,QAAI;AACF,aAAOK,EAAM,QAAQL,CAAQ;AAAA,IAC/B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,CAAC,GAEKQ,IAAeD,EAAM;AAAA,IACzB,CAACE,MAA2C;AAC1C,UAAIJ,KAASL;AACX,YAAI;AACF,UAAAK,EAAM,QAAQL,GAAUS,EAAE,OAAO,KAAK;AAAA,QACxC,QAAQ;AAAA,QAER;AAEF,MAAAP,KAAA,QAAAA,EAAWO;AAAA,IACb;AAAA,IACA,CAACJ,GAAOL,GAAUE,CAAQ;AAAA,EAAA;AAG5B,SACE,gBAAAQ;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAAX;AAAA,MACA,cAAcC,IAAYM,KAAUH,IAAgBA;AAAA,MACpD,UAAUH,IAAWQ,IAAeN;AAAA,MACpC,WAAWS;AAAA,QACT;AAAA,QACAb;AAAA,MAAA;AAAA,MAED,GAAGM;AAAA,IAAA;AAAA,EAAA;AAGV;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modal.test.d.ts","sourceRoot":"","sources":["../../../src/components/modal/modal.test.tsx"],"names":[],"mappings":""}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { useProgressiveSlot, ProgressiveTimelineSlot } from './progressive-timeline';
|
|
2
|
-
export type { ProgressiveSlotValue } from './progressive-timeline';
|
|
2
|
+
export type { ProgressiveSlotValue, ProgressiveTimelineSlotProps } from './progressive-timeline';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/progressive-timeline/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACrF,YAAY,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/progressive-timeline/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACrF,YAAY,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -31,16 +31,21 @@ export interface ProgressiveSlotValue {
|
|
|
31
31
|
* components keep working standalone.
|
|
32
32
|
*/
|
|
33
33
|
export declare function useProgressiveSlot(): ProgressiveSlotValue;
|
|
34
|
+
export interface ProgressiveTimelineSlotProps {
|
|
35
|
+
/** True while this slot is the head of the timeline — its turn to animate. */
|
|
36
|
+
active: boolean;
|
|
37
|
+
/** How long (ms) to hold the slot when no child reports an animation duration. */
|
|
38
|
+
fallbackMs: number;
|
|
39
|
+
/** Called once when the slot's turn ends, to advance the timeline. */
|
|
40
|
+
onComplete: () => void;
|
|
41
|
+
/** The subtree that reads this slot via {@link useProgressiveSlot}. */
|
|
42
|
+
children: ReactNode;
|
|
43
|
+
}
|
|
34
44
|
/**
|
|
35
45
|
* One slot on a {@link ProgressiveList}'s timeline. Provides the slot context to
|
|
36
46
|
* its subtree and, while `active`, decides when to hand off to the next slot:
|
|
37
47
|
* after the longest duration its children reported, or — if nothing reported —
|
|
38
48
|
* after `fallbackMs`; whichever child calls its `done` early wins.
|
|
39
49
|
*/
|
|
40
|
-
export declare function ProgressiveTimelineSlot({ active, fallbackMs, onComplete, children, }:
|
|
41
|
-
active: boolean;
|
|
42
|
-
fallbackMs: number;
|
|
43
|
-
onComplete: () => void;
|
|
44
|
-
children: ReactNode;
|
|
45
|
-
}): import("react").JSX.Element;
|
|
50
|
+
export declare function ProgressiveTimelineSlot({ active, fallbackMs, onComplete, children, }: ProgressiveTimelineSlotProps): import("react").JSX.Element;
|
|
46
51
|
//# sourceMappingURL=progressive-timeline.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"progressive-timeline.d.ts","sourceRoot":"","sources":["../../../src/components/progressive-timeline/progressive-timeline.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAQ9F,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB;;;;;;;;OAQG;IACH,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,IAAI,CAAC;IAC3C,oFAAoF;IACpF,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAUD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,IAAI,oBAAoB,CAEzD;AAED
|
|
1
|
+
{"version":3,"file":"progressive-timeline.d.ts","sourceRoot":"","sources":["../../../src/components/progressive-timeline/progressive-timeline.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAQ9F,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB;;;;;;;;OAQG;IACH,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,IAAI,CAAC;IAC3C,oFAAoF;IACpF,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAUD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,IAAI,oBAAoB,CAEzD;AAED,MAAM,WAAW,4BAA4B;IAC3C,8EAA8E;IAC9E,MAAM,EAAE,OAAO,CAAC;IAChB,kFAAkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,uEAAuE;IACvE,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,MAAM,EACN,UAAU,EACV,UAAU,EACV,QAAQ,GACT,EAAE,4BAA4B,+BAmE9B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"progressive-timeline.js","sources":["../../../src/components/progressive-timeline/progressive-timeline.tsx"],"sourcesContent":["import { createContext, useContext, useEffect, useMemo, useRef, type ReactNode } from 'react';\n\nfunction now(): number {\n return typeof performance !== 'undefined' && typeof performance.now === 'function'\n ? performance.now()\n : Date.now();\n}\n\nexport interface ProgressiveSlotValue {\n /**\n * True when this slot is the current head of the timeline — the moment its\n * children are meant to animate. Outside a {@link ProgressiveList} this is\n * always `true`, so a progressive element just animates on its own.\n */\n active: boolean;\n /**\n * A participating child announces that — once active — it will animate for\n * `durationMs`. The timeline waits (at least) that long before revealing the\n * next slot: this is how a list element's appearance is delayed by the inner\n * animation of the one before it. Calling it again raises the wait to the\n * longest reported duration (e.g. as streamed text grows). Returns a `done`\n * callback that advances the timeline immediately — call it the instant the\n * child actually finishes, if you want to hand off early.\n */\n report: (durationMs: number) => () => void;\n /** Advance the timeline for this slot right now (e.g. instant / static content). */\n finish: () => void;\n}\n\nconst NOOP_SLOT: ProgressiveSlotValue = {\n active: true,\n report: () => () => {},\n finish: () => {},\n};\n\nconst ProgressiveSlotContext = createContext<ProgressiveSlotValue>(NOOP_SLOT);\n\n/**\n * Read the enclosing {@link ProgressiveList} timeline slot. Any component can\n * consume this to participate in the sequence:\n * - hold its animation until it's this slot's turn (`active`);\n * - tell the timeline how long it will animate (`report`) — so the *next* list\n * element is delayed until this one's inner animation completes — or that it's\n * done (`finish` / the `done` returned by `report`).\n *\n * Outside a ProgressiveList it returns an always-active no-op, so progressive\n * components keep working standalone.\n */\nexport function useProgressiveSlot(): ProgressiveSlotValue {\n return useContext(ProgressiveSlotContext);\n}\n\n/**\n * One slot on a {@link ProgressiveList}'s timeline. Provides the slot context to\n * its subtree and, while `active`, decides when to hand off to the next slot:\n * after the longest duration its children reported, or — if nothing reported —\n * after `fallbackMs`; whichever child calls its `done` early wins.\n */\nexport function ProgressiveTimelineSlot({\n active,\n fallbackMs,\n onComplete,\n children,\n}:
|
|
1
|
+
{"version":3,"file":"progressive-timeline.js","sources":["../../../src/components/progressive-timeline/progressive-timeline.tsx"],"sourcesContent":["import { createContext, useContext, useEffect, useMemo, useRef, type ReactNode } from 'react';\n\nfunction now(): number {\n return typeof performance !== 'undefined' && typeof performance.now === 'function'\n ? performance.now()\n : Date.now();\n}\n\nexport interface ProgressiveSlotValue {\n /**\n * True when this slot is the current head of the timeline — the moment its\n * children are meant to animate. Outside a {@link ProgressiveList} this is\n * always `true`, so a progressive element just animates on its own.\n */\n active: boolean;\n /**\n * A participating child announces that — once active — it will animate for\n * `durationMs`. The timeline waits (at least) that long before revealing the\n * next slot: this is how a list element's appearance is delayed by the inner\n * animation of the one before it. Calling it again raises the wait to the\n * longest reported duration (e.g. as streamed text grows). Returns a `done`\n * callback that advances the timeline immediately — call it the instant the\n * child actually finishes, if you want to hand off early.\n */\n report: (durationMs: number) => () => void;\n /** Advance the timeline for this slot right now (e.g. instant / static content). */\n finish: () => void;\n}\n\nconst NOOP_SLOT: ProgressiveSlotValue = {\n active: true,\n report: () => () => {},\n finish: () => {},\n};\n\nconst ProgressiveSlotContext = createContext<ProgressiveSlotValue>(NOOP_SLOT);\n\n/**\n * Read the enclosing {@link ProgressiveList} timeline slot. Any component can\n * consume this to participate in the sequence:\n * - hold its animation until it's this slot's turn (`active`);\n * - tell the timeline how long it will animate (`report`) — so the *next* list\n * element is delayed until this one's inner animation completes — or that it's\n * done (`finish` / the `done` returned by `report`).\n *\n * Outside a ProgressiveList it returns an always-active no-op, so progressive\n * components keep working standalone.\n */\nexport function useProgressiveSlot(): ProgressiveSlotValue {\n return useContext(ProgressiveSlotContext);\n}\n\nexport interface ProgressiveTimelineSlotProps {\n /** True while this slot is the head of the timeline — its turn to animate. */\n active: boolean;\n /** How long (ms) to hold the slot when no child reports an animation duration. */\n fallbackMs: number;\n /** Called once when the slot's turn ends, to advance the timeline. */\n onComplete: () => void;\n /** The subtree that reads this slot via {@link useProgressiveSlot}. */\n children: ReactNode;\n}\n\n/**\n * One slot on a {@link ProgressiveList}'s timeline. Provides the slot context to\n * its subtree and, while `active`, decides when to hand off to the next slot:\n * after the longest duration its children reported, or — if nothing reported —\n * after `fallbackMs`; whichever child calls its `done` early wins.\n */\nexport function ProgressiveTimelineSlot({\n active,\n fallbackMs,\n onComplete,\n children,\n}: ProgressiveTimelineSlotProps) {\n const st = useRef({ activatedAt: 0, anyReport: false, maxDuration: 0, completed: false, timer: 0 });\n\n // A slot is mounted exactly when it becomes the head, so its first render is\n // the activation instant. Stamp it during render so a child's report() — which\n // runs in a child effect, before this component's own effects — sees a valid\n // clock to measure elapsed time against.\n if (active && st.current.activatedAt === 0) st.current.activatedAt = now();\n\n // Latest props read by the (stable) api closures without rebuilding them.\n const activeRef = useRef(active);\n activeRef.current = active;\n const fallbackRef = useRef(fallbackMs);\n fallbackRef.current = fallbackMs;\n const onCompleteRef = useRef(onComplete);\n onCompleteRef.current = onComplete;\n\n const api = useMemo(() => {\n const complete = () => {\n const s = st.current;\n if (s.completed) return;\n s.completed = true;\n if (s.timer) {\n clearTimeout(s.timer);\n s.timer = 0;\n }\n onCompleteRef.current();\n };\n const schedule = () => {\n const s = st.current;\n if (s.completed || !activeRef.current) return;\n if (s.timer) clearTimeout(s.timer);\n const target = s.anyReport ? s.maxDuration : fallbackRef.current;\n const elapsed = now() - s.activatedAt;\n s.timer = window.setTimeout(complete, Math.max(0, target - elapsed));\n };\n const report = (durationMs: number) => {\n const s = st.current;\n s.anyReport = true;\n s.maxDuration = Math.max(s.maxDuration, durationMs);\n schedule();\n return complete;\n };\n return { complete, schedule, report };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const value = useMemo<ProgressiveSlotValue>(\n () => ({ active, report: api.report, finish: api.complete }),\n [active, api],\n );\n\n useEffect(() => {\n if (!active) return;\n const s = st.current;\n if (s.completed) return;\n if (s.activatedAt === 0) s.activatedAt = now();\n api.schedule(); // fallback / duration timer (reschedules over any earlier child report)\n return () => {\n if (s.timer) {\n clearTimeout(s.timer);\n s.timer = 0;\n }\n };\n }, [active, api]);\n\n return <ProgressiveSlotContext.Provider value={value}>{children}</ProgressiveSlotContext.Provider>;\n}\n"],"names":["now","NOOP_SLOT","ProgressiveSlotContext","createContext","useProgressiveSlot","useContext","ProgressiveTimelineSlot","active","fallbackMs","onComplete","children","st","useRef","activeRef","fallbackRef","onCompleteRef","api","useMemo","complete","s","schedule","target","elapsed","durationMs","value","useEffect","jsx"],"mappings":";;AAEA,SAASA,IAAc;AACrB,SAAO,OAAO,cAAgB,OAAe,OAAO,YAAY,OAAQ,aACpE,YAAY,QACZ,KAAK,IAAA;AACX;AAuBA,MAAMC,IAAkC;AAAA,EACtC,QAAQ;AAAA,EACR,QAAQ,MAAM,MAAM;AAAA,EAAC;AAAA,EACrB,QAAQ,MAAM;AAAA,EAAC;AACjB,GAEMC,IAAyBC,EAAoCF,CAAS;AAarE,SAASG,IAA2C;AACzD,SAAOC,EAAWH,CAAsB;AAC1C;AAmBO,SAASI,EAAwB;AAAA,EACtC,QAAAC;AAAA,EACA,YAAAC;AAAA,EACA,YAAAC;AAAA,EACA,UAAAC;AACF,GAAiC;AAC/B,QAAMC,IAAKC,EAAO,EAAE,aAAa,GAAG,WAAW,IAAO,aAAa,GAAG,WAAW,IAAO,OAAO,GAAG;AAMlG,EAAIL,KAAUI,EAAG,QAAQ,gBAAgB,MAAGA,EAAG,QAAQ,cAAcX,EAAA;AAGrE,QAAMa,IAAYD,EAAOL,CAAM;AAC/B,EAAAM,EAAU,UAAUN;AACpB,QAAMO,IAAcF,EAAOJ,CAAU;AACrC,EAAAM,EAAY,UAAUN;AACtB,QAAMO,IAAgBH,EAAOH,CAAU;AACvC,EAAAM,EAAc,UAAUN;AAExB,QAAMO,IAAMC,EAAQ,MAAM;AACxB,UAAMC,IAAW,MAAM;AACrB,YAAMC,IAAIR,EAAG;AACb,MAAIQ,EAAE,cACNA,EAAE,YAAY,IACVA,EAAE,UACJ,aAAaA,EAAE,KAAK,GACpBA,EAAE,QAAQ,IAEZJ,EAAc,QAAA;AAAA,IAChB,GACMK,IAAW,MAAM;AACrB,YAAMD,IAAIR,EAAG;AACb,UAAIQ,EAAE,aAAa,CAACN,EAAU,QAAS;AACvC,MAAIM,EAAE,SAAO,aAAaA,EAAE,KAAK;AACjC,YAAME,IAASF,EAAE,YAAYA,EAAE,cAAcL,EAAY,SACnDQ,IAAUtB,MAAQmB,EAAE;AAC1B,MAAAA,EAAE,QAAQ,OAAO,WAAWD,GAAU,KAAK,IAAI,GAAGG,IAASC,CAAO,CAAC;AAAA,IACrE;AAQA,WAAO,EAAE,UAAAJ,GAAU,UAAAE,GAAU,QAPd,CAACG,MAAuB;AACrC,YAAMJ,IAAIR,EAAG;AACb,aAAAQ,EAAE,YAAY,IACdA,EAAE,cAAc,KAAK,IAAIA,EAAE,aAAaI,CAAU,GAClDH,EAAA,GACOF;AAAA,IACT,EAC6B;AAAA,EAE/B,GAAG,CAAA,CAAE,GAECM,IAAQP;AAAA,IACZ,OAAO,EAAE,QAAAV,GAAQ,QAAQS,EAAI,QAAQ,QAAQA,EAAI;IACjD,CAACT,GAAQS,CAAG;AAAA,EAAA;AAGd,SAAAS,EAAU,MAAM;AACd,QAAI,CAAClB,EAAQ;AACb,UAAMY,IAAIR,EAAG;AACb,QAAI,CAAAQ,EAAE;AACN,aAAIA,EAAE,gBAAgB,MAAGA,EAAE,cAAcnB,EAAA,IACzCgB,EAAI,SAAA,GACG,MAAM;AACX,QAAIG,EAAE,UACJ,aAAaA,EAAE,KAAK,GACpBA,EAAE,QAAQ;AAAA,MAEd;AAAA,EACF,GAAG,CAACZ,GAAQS,CAAG,CAAC,GAET,gBAAAU,EAACxB,EAAuB,UAAvB,EAAgC,OAAAsB,GAAe,UAAAd,EAAA,CAAS;AAClE;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../src/components/theme/theme.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAuDpD,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,QASvC;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,SAE1B;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,IAAI,OAAO,GAAG,MAAM,CAG/C;AAQD,MAAM,WAAW,cAAc;IAC7B,2CAA2C;IAC3C,KAAK,EAAE,SAAS,CAAC;IACjB,sDAAsD;IACtD,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IACpC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../src/components/theme/theme.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAuDpD,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,QASvC;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,SAE1B;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,IAAI,OAAO,GAAG,MAAM,CAG/C;AAQD,MAAM,WAAW,cAAc;IAC7B,2CAA2C;IAC3C,KAAK,EAAE,SAAS,CAAC;IACjB,sDAAsD;IACtD,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IACpC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAUD,gDAAgD;AAChD,wBAAgB,QAAQ,IAAI,cAAc,CAQzC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,UAAU,EAAE,GAAgB,EAC5B,YAAuB,GACxB,EAAE;IACD,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,SAAS,CAAC;CAC1B,qBAQA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as f, Fragment as h } from "react/jsx-runtime";
|
|
2
2
|
import * as g from "react";
|
|
3
3
|
let s = "ui-theme", o = "system", n = null;
|
|
4
|
-
const
|
|
5
|
-
function
|
|
4
|
+
const i = /* @__PURE__ */ new Set();
|
|
5
|
+
function c() {
|
|
6
6
|
return typeof window < "u" && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
7
7
|
}
|
|
8
8
|
function a() {
|
|
@@ -13,7 +13,7 @@ function a() {
|
|
|
13
13
|
}
|
|
14
14
|
function d() {
|
|
15
15
|
if (typeof document > "u" || !n) return;
|
|
16
|
-
const e = n === "dark" || n === "system" &&
|
|
16
|
+
const e = n === "dark" || n === "system" && c(), t = document.documentElement;
|
|
17
17
|
t.classList.toggle("dark", e), t.style.colorScheme = e ? "dark" : "light";
|
|
18
18
|
const r = document.querySelector('meta[name="theme-color"]');
|
|
19
19
|
if (r) {
|
|
@@ -24,7 +24,7 @@ function d() {
|
|
|
24
24
|
let u = !1;
|
|
25
25
|
function y() {
|
|
26
26
|
u || typeof window > "u" || (u = !0, window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
|
|
27
|
-
n === "system" && (d(),
|
|
27
|
+
n === "system" && (d(), i.forEach((e) => e()));
|
|
28
28
|
}));
|
|
29
29
|
}
|
|
30
30
|
function l(e) {
|
|
@@ -33,38 +33,42 @@ function l(e) {
|
|
|
33
33
|
window.localStorage.setItem(s, e);
|
|
34
34
|
} catch {
|
|
35
35
|
}
|
|
36
|
-
d(),
|
|
37
|
-
}
|
|
38
|
-
function w() {
|
|
39
|
-
l(k() === "dark" ? "light" : "dark");
|
|
36
|
+
d(), i.forEach((t) => t());
|
|
40
37
|
}
|
|
41
38
|
function k() {
|
|
39
|
+
l(w() === "dark" ? "light" : "dark");
|
|
40
|
+
}
|
|
41
|
+
function w() {
|
|
42
42
|
const e = a();
|
|
43
|
-
return e === "system" ?
|
|
43
|
+
return e === "system" ? c() ? "dark" : "light" : e;
|
|
44
44
|
}
|
|
45
45
|
function p(e) {
|
|
46
|
-
return a(),
|
|
46
|
+
return a(), i.add(e), () => i.delete(e);
|
|
47
47
|
}
|
|
48
48
|
function S() {
|
|
49
|
+
const e = a();
|
|
50
|
+
return `${e}:${e === "system" ? c() ? "dark" : "light" : e}`;
|
|
51
|
+
}
|
|
52
|
+
function b() {
|
|
49
53
|
const e = g.useSyncExternalStore(
|
|
50
54
|
p,
|
|
51
|
-
|
|
52
|
-
() => o
|
|
53
|
-
), t = e
|
|
54
|
-
return { theme:
|
|
55
|
+
S,
|
|
56
|
+
() => `${o}:${o === "dark" ? "dark" : "light"}`
|
|
57
|
+
), [t, r] = e.split(":");
|
|
58
|
+
return { theme: t, resolved: r, isDark: r === "dark", setTheme: l, toggle: k };
|
|
55
59
|
}
|
|
56
|
-
function
|
|
60
|
+
function v({
|
|
57
61
|
children: e,
|
|
58
62
|
storageKey: t = "ui-theme",
|
|
59
63
|
defaultTheme: r = "system"
|
|
60
64
|
}) {
|
|
61
|
-
return (t !== s || r !== o) && (s = t, o = r, n = null),
|
|
65
|
+
return (t !== s || r !== o) && (s = t, o = r, n = null), b(), /* @__PURE__ */ f(h, { children: e });
|
|
62
66
|
}
|
|
63
67
|
export {
|
|
64
|
-
|
|
65
|
-
|
|
68
|
+
v as ThemeProvider,
|
|
69
|
+
w as resolveTheme,
|
|
66
70
|
l as setTheme,
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
k as toggleTheme,
|
|
72
|
+
b as useTheme
|
|
69
73
|
};
|
|
70
74
|
//# sourceMappingURL=theme.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.js","sources":["../../../src/components/theme/theme.tsx"],"sourcesContent":["import * as React from 'react';\n\nexport type ThemeMode = 'light' | 'dark' | 'system';\n\n/*\n * A module-level store rather than a context, because the theme is one global\n * fact: `useTheme()` works anywhere with no provider, and `<ThemeProvider>` is\n * only needed to change the storage key or the default. Every subscriber shares\n * one `matchMedia` listener via `useSyncExternalStore`.\n */\n\nlet storageKey = 'ui-theme';\nlet fallback: ThemeMode = 'system';\nlet mode: ThemeMode | null = null;\nconst listeners = new Set<() => void>();\n\nfunction systemDark(): boolean {\n return typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches;\n}\n\nfunction init(): ThemeMode {\n if (mode) return mode;\n if (typeof window === 'undefined') return fallback;\n const stored = window.localStorage.getItem(storageKey) as ThemeMode | null;\n mode = stored === 'light' || stored === 'dark' || stored === 'system' ? stored : fallback;\n apply();\n watchSystem();\n return mode;\n}\n\nfunction apply() {\n if (typeof document === 'undefined' || !mode) return;\n const dark = mode === 'dark' || (mode === 'system' && systemDark());\n const root = document.documentElement;\n root.classList.toggle('dark', dark);\n root.style.colorScheme = dark ? 'dark' : 'light';\n // Keep the mobile browser chrome in step with the page, or a dark page keeps\n // a white notch bar.\n const meta = document.querySelector<HTMLMetaElement>('meta[name=\"theme-color\"]');\n if (meta) {\n const bg = getComputedStyle(root).getPropertyValue('--background').trim();\n if (bg) meta.content = bg;\n }\n}\n\nlet watching = false;\nfunction watchSystem() {\n if (watching || typeof window === 'undefined') return;\n watching = true;\n window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {\n if (mode === 'system') {\n apply();\n listeners.forEach((l) => l());\n }\n });\n}\n\n/** Set the theme from anywhere — a settings page, a keyboard shortcut, a test. */\nexport function setTheme(next: ThemeMode) {\n mode = next;\n try {\n window.localStorage.setItem(storageKey, next);\n } catch {\n /* private mode — the theme still applies for this session */\n }\n apply();\n listeners.forEach((l) => l());\n}\n\n/** Light ⇄ dark. From `system`, flips to the opposite of what is showing. */\nexport function toggleTheme() {\n setTheme(resolveTheme() === 'dark' ? 'light' : 'dark');\n}\n\n/** What is actually on screen right now (`system` resolved against the OS). */\nexport function resolveTheme(): 'light' | 'dark' {\n const m = init();\n return m === 'system' ? (systemDark() ? 'dark' : 'light') : m;\n}\n\nfunction subscribe(l: () => void) {\n init();\n listeners.add(l);\n return () => listeners.delete(l);\n}\n\nexport interface UseThemeResult {\n /** The chosen mode, including `system`. */\n theme: ThemeMode;\n /** The mode in effect — `system` already resolved. */\n resolved: 'light' | 'dark';\n isDark: boolean;\n setTheme: (mode: ThemeMode) => void;\n toggle: () => void;\n}\n\n/** The dark-mode hook. No provider required. */\nexport function useTheme(): UseThemeResult {\n const
|
|
1
|
+
{"version":3,"file":"theme.js","sources":["../../../src/components/theme/theme.tsx"],"sourcesContent":["import * as React from 'react';\n\nexport type ThemeMode = 'light' | 'dark' | 'system';\n\n/*\n * A module-level store rather than a context, because the theme is one global\n * fact: `useTheme()` works anywhere with no provider, and `<ThemeProvider>` is\n * only needed to change the storage key or the default. Every subscriber shares\n * one `matchMedia` listener via `useSyncExternalStore`.\n */\n\nlet storageKey = 'ui-theme';\nlet fallback: ThemeMode = 'system';\nlet mode: ThemeMode | null = null;\nconst listeners = new Set<() => void>();\n\nfunction systemDark(): boolean {\n return typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches;\n}\n\nfunction init(): ThemeMode {\n if (mode) return mode;\n if (typeof window === 'undefined') return fallback;\n const stored = window.localStorage.getItem(storageKey) as ThemeMode | null;\n mode = stored === 'light' || stored === 'dark' || stored === 'system' ? stored : fallback;\n apply();\n watchSystem();\n return mode;\n}\n\nfunction apply() {\n if (typeof document === 'undefined' || !mode) return;\n const dark = mode === 'dark' || (mode === 'system' && systemDark());\n const root = document.documentElement;\n root.classList.toggle('dark', dark);\n root.style.colorScheme = dark ? 'dark' : 'light';\n // Keep the mobile browser chrome in step with the page, or a dark page keeps\n // a white notch bar.\n const meta = document.querySelector<HTMLMetaElement>('meta[name=\"theme-color\"]');\n if (meta) {\n const bg = getComputedStyle(root).getPropertyValue('--background').trim();\n if (bg) meta.content = bg;\n }\n}\n\nlet watching = false;\nfunction watchSystem() {\n if (watching || typeof window === 'undefined') return;\n watching = true;\n window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {\n if (mode === 'system') {\n apply();\n listeners.forEach((l) => l());\n }\n });\n}\n\n/** Set the theme from anywhere — a settings page, a keyboard shortcut, a test. */\nexport function setTheme(next: ThemeMode) {\n mode = next;\n try {\n window.localStorage.setItem(storageKey, next);\n } catch {\n /* private mode — the theme still applies for this session */\n }\n apply();\n listeners.forEach((l) => l());\n}\n\n/** Light ⇄ dark. From `system`, flips to the opposite of what is showing. */\nexport function toggleTheme() {\n setTheme(resolveTheme() === 'dark' ? 'light' : 'dark');\n}\n\n/** What is actually on screen right now (`system` resolved against the OS). */\nexport function resolveTheme(): 'light' | 'dark' {\n const m = init();\n return m === 'system' ? (systemDark() ? 'dark' : 'light') : m;\n}\n\nfunction subscribe(l: () => void) {\n init();\n listeners.add(l);\n return () => listeners.delete(l);\n}\n\nexport interface UseThemeResult {\n /** The chosen mode, including `system`. */\n theme: ThemeMode;\n /** The mode in effect — `system` already resolved. */\n resolved: 'light' | 'dark';\n isDark: boolean;\n setTheme: (mode: ThemeMode) => void;\n toggle: () => void;\n}\n\n// The snapshot carries the resolved value too — with the bare mode, a live OS\n// flip under `system` never changes the snapshot and React bails out of\n// re-rendering, leaving `resolved`/`isDark` stale while the DOM class moves on.\nfunction snapshot(): string {\n const m = init();\n return `${m}:${m === 'system' ? (systemDark() ? 'dark' : 'light') : m}`;\n}\n\n/** The dark-mode hook. No provider required. */\nexport function useTheme(): UseThemeResult {\n const snap = React.useSyncExternalStore(\n subscribe,\n snapshot,\n () => `${fallback}:${fallback === 'dark' ? 'dark' : 'light'}`,\n );\n const [theme, resolved] = snap.split(':') as [ThemeMode, 'light' | 'dark'];\n return { theme, resolved, isDark: resolved === 'dark', setTheme, toggle: toggleTheme };\n}\n\n/**\n * Optional — only to override the defaults (`localStorage['ui-theme']`,\n * defaulting to the OS preference). Configure before the first paint.\n */\nexport function ThemeProvider({\n children,\n storageKey: key = 'ui-theme',\n defaultTheme = 'system',\n}: {\n children?: React.ReactNode;\n storageKey?: string;\n defaultTheme?: ThemeMode;\n}) {\n if (key !== storageKey || defaultTheme !== fallback) {\n storageKey = key;\n fallback = defaultTheme;\n mode = null; // re-read under the new key\n }\n useTheme(); // mount the subscription so the class lands before paint\n return <>{children}</>;\n}\n"],"names":["storageKey","fallback","mode","listeners","systemDark","init","stored","apply","watchSystem","dark","root","meta","bg","watching","l","setTheme","next","toggleTheme","resolveTheme","m","subscribe","snapshot","useTheme","snap","React","theme","resolved","ThemeProvider","children","key","defaultTheme"],"mappings":";;AAWA,IAAIA,IAAa,YACbC,IAAsB,UACtBC,IAAyB;AAC7B,MAAMC,wBAAgB,IAAA;AAEtB,SAASC,IAAsB;AAC7B,SAAO,OAAO,SAAW,OAAe,OAAO,WAAW,8BAA8B,EAAE;AAC5F;AAEA,SAASC,IAAkB;AACzB,MAAIH,EAAM,QAAOA;AACjB,MAAI,OAAO,SAAW,IAAa,QAAOD;AAC1C,QAAMK,IAAS,OAAO,aAAa,QAAQN,CAAU;AACrD,SAAAE,IAAOI,MAAW,WAAWA,MAAW,UAAUA,MAAW,WAAWA,IAASL,GACjFM,EAAA,GACAC,EAAA,GACON;AACT;AAEA,SAASK,IAAQ;AACf,MAAI,OAAO,WAAa,OAAe,CAACL,EAAM;AAC9C,QAAMO,IAAOP,MAAS,UAAWA,MAAS,YAAYE,EAAA,GAChDM,IAAO,SAAS;AACtB,EAAAA,EAAK,UAAU,OAAO,QAAQD,CAAI,GAClCC,EAAK,MAAM,cAAcD,IAAO,SAAS;AAGzC,QAAME,IAAO,SAAS,cAA+B,0BAA0B;AAC/E,MAAIA,GAAM;AACR,UAAMC,IAAK,iBAAiBF,CAAI,EAAE,iBAAiB,cAAc,EAAE,KAAA;AACnE,IAAIE,QAAS,UAAUA;AAAA,EACzB;AACF;AAEA,IAAIC,IAAW;AACf,SAASL,IAAc;AACrB,EAAIK,KAAY,OAAO,SAAW,QAClCA,IAAW,IACX,OAAO,WAAW,8BAA8B,EAAE,iBAAiB,UAAU,MAAM;AACjF,IAAIX,MAAS,aACXK,EAAA,GACAJ,EAAU,QAAQ,CAACW,MAAMA,EAAA,CAAG;AAAA,EAEhC,CAAC;AACH;AAGO,SAASC,EAASC,GAAiB;AACxC,EAAAd,IAAOc;AACP,MAAI;AACF,WAAO,aAAa,QAAQhB,GAAYgB,CAAI;AAAA,EAC9C,QAAQ;AAAA,EAER;AACA,EAAAT,EAAA,GACAJ,EAAU,QAAQ,CAACW,MAAMA,EAAA,CAAG;AAC9B;AAGO,SAASG,IAAc;AAC5B,EAAAF,EAASG,EAAA,MAAmB,SAAS,UAAU,MAAM;AACvD;AAGO,SAASA,IAAiC;AAC/C,QAAMC,IAAId,EAAA;AACV,SAAOc,MAAM,WAAYf,EAAA,IAAe,SAAS,UAAWe;AAC9D;AAEA,SAASC,EAAUN,GAAe;AAChC,SAAAT,EAAA,GACAF,EAAU,IAAIW,CAAC,GACR,MAAMX,EAAU,OAAOW,CAAC;AACjC;AAeA,SAASO,IAAmB;AAC1B,QAAMF,IAAId,EAAA;AACV,SAAO,GAAGc,CAAC,IAAIA,MAAM,WAAYf,EAAA,IAAe,SAAS,UAAWe,CAAC;AACvE;AAGO,SAASG,IAA2B;AACzC,QAAMC,IAAOC,EAAM;AAAA,IACjBJ;AAAA,IACAC;AAAA,IACA,MAAM,GAAGpB,CAAQ,IAAIA,MAAa,SAAS,SAAS,OAAO;AAAA,EAAA,GAEvD,CAACwB,GAAOC,CAAQ,IAAIH,EAAK,MAAM,GAAG;AACxC,SAAO,EAAE,OAAAE,GAAO,UAAAC,GAAU,QAAQA,MAAa,QAAQ,UAAAX,GAAU,QAAQE,EAAA;AAC3E;AAMO,SAASU,EAAc;AAAA,EAC5B,UAAAC;AAAA,EACA,YAAYC,IAAM;AAAA,EAClB,cAAAC,IAAe;AACjB,GAIG;AACD,UAAID,MAAQ7B,KAAc8B,MAAiB7B,OACzCD,IAAa6B,GACb5B,IAAW6B,GACX5B,IAAO,OAEToB,EAAA,0BACU,UAAAM,GAAS;AACrB;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.test.d.ts","sourceRoot":"","sources":["../../../src/components/theme/theme.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toast.test.d.ts","sourceRoot":"","sources":["../../../src/components/toast/toast.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual-list.test.d.ts","sourceRoot":"","sources":["../../../src/components/virtual-list/virtual-list.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-local-storage.test.d.ts","sourceRoot":"","sources":["../../src/hooks/use-local-storage.test.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
CHANGED
|
@@ -55,7 +55,7 @@ export type { ProgressiveListProps, ProgressiveListItemMeta } from './components
|
|
|
55
55
|
export { ProgressiveTable } from './components/progressive-table';
|
|
56
56
|
export type { ProgressiveTableProps, ProgressiveTableCellContext } from './components/progressive-table';
|
|
57
57
|
export { useProgressiveSlot, ProgressiveTimelineSlot } from './components/progressive-timeline';
|
|
58
|
-
export type { ProgressiveSlotValue } from './components/progressive-timeline';
|
|
58
|
+
export type { ProgressiveSlotValue, ProgressiveTimelineSlotProps } from './components/progressive-timeline';
|
|
59
59
|
export { ProgressiveBash } from './components/progressive-bash';
|
|
60
60
|
export type { ProgressiveBashProps, ProgressiveBashHandle, BashEntry, PlaybackTuning } from './components/progressive-bash';
|
|
61
61
|
export { computeGapMs as computeBashGapMs, DEFAULT_TUNING as DEFAULT_BASH_TUNING, tokenizeCommand, splitOutput, classifyLine, splitBySubparts, } from './components/progressive-bash';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.test.d.ts","sourceRoot":"","sources":["../../src/lib/format.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highlight.test.d.ts","sourceRoot":"","sources":["../../src/lib/highlight.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/test/setup.ts"],"names":[],"mappings":"AAAA,OAAO,kCAAkC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gabvdl/ui",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Gabriel Vidal's personal design system — tree-shakeable React components built on shadcn primitives. Flagship: a full-screen image viewer with zoom, pan and swipe.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
],
|
|
27
27
|
"files": [
|
|
28
28
|
"dist",
|
|
29
|
-
"README.md"
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
30
31
|
],
|
|
31
32
|
"publishConfig": {
|
|
32
33
|
"access": "public"
|
|
@@ -50,7 +51,8 @@
|
|
|
50
51
|
"scripts": {
|
|
51
52
|
"build": "vite build && node scripts/copy-css.mjs",
|
|
52
53
|
"dev": "vite build --watch",
|
|
53
|
-
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
54
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
55
|
+
"test": "vitest run"
|
|
54
56
|
},
|
|
55
57
|
"peerDependencies": {
|
|
56
58
|
"react": ">=18",
|
|
@@ -65,13 +67,18 @@
|
|
|
65
67
|
"tailwind-merge": "^3.6.0"
|
|
66
68
|
},
|
|
67
69
|
"devDependencies": {
|
|
70
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
71
|
+
"@testing-library/react": "^16.3.2",
|
|
72
|
+
"@testing-library/user-event": "^14.6.1",
|
|
68
73
|
"@types/react": "^19.1.2",
|
|
69
74
|
"@types/react-dom": "^19.1.2",
|
|
70
75
|
"@vitejs/plugin-react": "^4.4.1",
|
|
76
|
+
"jsdom": "^29.1.1",
|
|
71
77
|
"react": "^19.1.0",
|
|
72
78
|
"react-dom": "^19.1.0",
|
|
73
79
|
"typescript": "~5.8.3",
|
|
74
80
|
"vite": "^6.3.1",
|
|
75
|
-
"vite-plugin-dts": "^4.5.0"
|
|
81
|
+
"vite-plugin-dts": "^4.5.0",
|
|
82
|
+
"vitest": "^4.1.10"
|
|
76
83
|
}
|
|
77
84
|
}
|