@nocoo/basalt 2.1.2 → 2.1.8
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/ai/INTEGRATION.md +19 -1
- package/ai/USAGE.md +1 -1
- package/ai/registry.json +81 -81
- package/dist/charts/charts.d.ts +1 -1
- package/dist/charts/charts.js +3 -16
- package/dist/charts/charts.js.map +1 -1
- package/dist/charts/custom-chart.d.ts +1 -1
- package/dist/charts/custom-chart.js +3 -16
- package/dist/charts/custom-chart.js.map +1 -1
- package/dist/charts/grouped-bar.d.ts +1 -1
- package/dist/charts/grouped-bar.js +11 -48
- package/dist/charts/grouped-bar.js.map +1 -1
- package/dist/charts/heatmap-calendar.js +80 -136
- package/dist/charts/heatmap-calendar.js.map +1 -1
- package/dist/charts/slot-bar.js +2 -12
- package/dist/charts/slot-bar.js.map +1 -1
- package/dist/charts/stat-card.js +2 -7
- package/dist/charts/stat-card.js.map +1 -1
- package/dist/charts/timeseries.d.ts +1 -1
- package/dist/charts/timeseries.js +3 -16
- package/dist/charts/timeseries.js.map +1 -1
- package/dist/charts/tooltip.js +13 -51
- package/dist/charts/tooltip.js.map +1 -1
- package/dist/components/autocomplete.d.ts +1 -1
- package/dist/components/autocomplete.js +3 -16
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/banner.js +28 -28
- package/dist/components/banner.js.map +1 -1
- package/dist/components/button.js +8 -9
- package/dist/components/button.js.map +1 -1
- package/dist/components/chat-composer.js +1 -2
- package/dist/components/chat-composer.js.map +1 -1
- package/dist/components/checkbox.js +50 -82
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/code.js +1 -1
- package/dist/components/code.js.map +1 -1
- package/dist/components/combobox.d.ts +1 -1
- package/dist/components/combobox.js +3 -16
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/confirm-dialog.js +1 -1
- package/dist/components/confirm-dialog.js.map +1 -1
- package/dist/components/context-menu.d.ts +1 -67
- package/dist/components/context-menu.js.map +1 -1
- package/dist/components/data-table.js +112 -124
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.js +236 -245
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/delete-resource.js +1 -1
- package/dist/components/delete-resource.js.map +1 -1
- package/dist/components/dock.js +15 -16
- package/dist/components/dock.js.map +1 -1
- package/dist/components/field.js +20 -23
- package/dist/components/field.js.map +1 -1
- package/dist/components/layer-card.d.ts +1 -1
- package/dist/components/layer-card.js +44 -51
- package/dist/components/layer-card.js.map +1 -1
- package/dist/components/skeleton-line.d.ts +2 -2
- package/dist/components/skeleton-line.js +1 -1
- package/dist/components/skeleton-line.js.map +1 -1
- package/dist/components/switch.js +46 -78
- package/dist/components/switch.js.map +1 -1
- package/dist/components/toggle-group.js +2 -2
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle.js +1 -1
- package/dist/components/toggle.js.map +1 -1
- package/dist/components/tooltip.js +14 -13
- package/dist/components/tooltip.js.map +1 -1
- package/dist/providers/accent.js +89 -198
- package/dist/providers/accent.js.map +1 -1
- package/dist/providers/theme.js +46 -144
- package/dist/providers/theme.js.map +1 -1
- package/dist/styles/standalone.css +37 -13
- package/dist/utils/preference-store.d.ts +16 -0
- package/dist/utils/preference-store.js +106 -0
- package/dist/utils/preference-store.js.map +1 -0
- package/dist/utils/selection-indicator.js +1 -1
- package/dist/utils/selection-indicator.js.map +1 -1
- package/dist/utils/use-checkable-group.d.ts +19 -0
- package/dist/utils/use-checkable-group.js +61 -0
- package/dist/utils/use-checkable-group.js.map +1 -0
- package/package.json +2 -3
package/dist/providers/theme.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { createPreferenceStore as e } from "../utils/preference-store.js";
|
|
3
|
+
import { createContext as t, useCallback as n, useContext as r, useEffect as i, useMemo as a, useState as o, useSyncExternalStore as s } from "react";
|
|
4
|
+
import { jsx as c } from "react/jsx-runtime";
|
|
4
5
|
//#region src/providers/theme.tsx
|
|
5
|
-
var
|
|
6
|
-
function
|
|
6
|
+
var l = "theme", u = t(null);
|
|
7
|
+
function d(e) {
|
|
7
8
|
if (typeof document > "u") return;
|
|
8
9
|
let t = document.documentElement, n = !1;
|
|
9
10
|
try {
|
|
@@ -14,163 +15,64 @@ function u(e) {
|
|
|
14
15
|
let r = e === "dark" || e === "system" && n;
|
|
15
16
|
t.classList.toggle("dark", r), t.classList.toggle("light", !r), t.dataset.mode = r ? "dark" : "light";
|
|
16
17
|
}
|
|
17
|
-
function d(e) {
|
|
18
|
-
return e === "light" || e === "dark" || e === "system";
|
|
19
|
-
}
|
|
20
18
|
function f(e) {
|
|
21
|
-
|
|
22
|
-
return typeof window > "u" || !window.localStorage ? { status: "error" } : {
|
|
23
|
-
status: "success",
|
|
24
|
-
value: window.localStorage.getItem(e)
|
|
25
|
-
};
|
|
26
|
-
} catch {
|
|
27
|
-
return { status: "error" };
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function p(e, t) {
|
|
31
|
-
try {
|
|
32
|
-
return typeof window > "u" || !window.localStorage ? !1 : (window.localStorage.setItem(e, t), !0);
|
|
33
|
-
} catch {
|
|
34
|
-
return !1;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
function m(e) {
|
|
38
|
-
if (!e) return !0;
|
|
39
|
-
try {
|
|
40
|
-
if (typeof window < "u" && window.localStorage) return e === window.localStorage;
|
|
41
|
-
} catch {
|
|
42
|
-
return !1;
|
|
43
|
-
}
|
|
44
|
-
return !1;
|
|
45
|
-
}
|
|
46
|
-
var h = "basalt:theme-change";
|
|
47
|
-
function g(e, t, n) {
|
|
48
|
-
let r = e, i = t, a = n, o = i, s = !1, c = !1;
|
|
49
|
-
if (a) {
|
|
50
|
-
let e = f(r);
|
|
51
|
-
e.status === "success" && d(e.value) && (o = e.value, s = !0);
|
|
52
|
-
}
|
|
53
|
-
let l = /* @__PURE__ */ new Set(), u = () => {
|
|
54
|
-
for (let e of l) e();
|
|
55
|
-
}, g = (e) => {
|
|
56
|
-
if (!a) return;
|
|
57
|
-
let t = e;
|
|
58
|
-
if (!t.detail || t.detail.key !== r) return;
|
|
59
|
-
let { value: n, writeSucceeded: i } = t.detail;
|
|
60
|
-
c = !i, o = n, s = !0, u();
|
|
61
|
-
}, _ = (e) => {
|
|
62
|
-
if (!a) return;
|
|
63
|
-
let t = e;
|
|
64
|
-
if ("key" in t && t.key !== void 0) {
|
|
65
|
-
if (!m(t.storageArea) || t.key !== null && t.key !== r) return;
|
|
66
|
-
c = !1;
|
|
67
|
-
let e = t.newValue;
|
|
68
|
-
if (e == null || !d(e)) {
|
|
69
|
-
o = i, s = !1, u();
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
o = e, s = !0, u();
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
if (c) return;
|
|
76
|
-
let n = f(r);
|
|
77
|
-
n.status !== "error" && (d(n.value) ? (o = n.value, s = !0, u()) : (o = i, s = !1, u()));
|
|
78
|
-
}, v = null, y = () => {
|
|
79
|
-
typeof window > "u" || l.size === 1 && !v && (window.addEventListener("storage", _), window.addEventListener(h, g), v = () => {
|
|
80
|
-
window.removeEventListener("storage", _), window.removeEventListener(h, g), v = null;
|
|
81
|
-
});
|
|
82
|
-
}, b = () => {
|
|
83
|
-
l.size === 0 && v && v();
|
|
84
|
-
};
|
|
85
|
-
return {
|
|
86
|
-
getSnapshot: () => o,
|
|
87
|
-
subscribe: (e) => (l.add(e), y(), () => {
|
|
88
|
-
l.delete(e), b();
|
|
89
|
-
}),
|
|
90
|
-
setTheme: (e) => {
|
|
91
|
-
o = e, s = !0;
|
|
92
|
-
let t = !0;
|
|
93
|
-
if (a) {
|
|
94
|
-
let n = p(r, e);
|
|
95
|
-
if (c = !n, t = n, typeof window < "u") try {
|
|
96
|
-
window.dispatchEvent(new CustomEvent(h, { detail: {
|
|
97
|
-
key: r,
|
|
98
|
-
value: e,
|
|
99
|
-
writeSucceeded: t
|
|
100
|
-
} }));
|
|
101
|
-
} catch {}
|
|
102
|
-
}
|
|
103
|
-
u();
|
|
104
|
-
},
|
|
105
|
-
updateConfig: (e) => {
|
|
106
|
-
let t = r !== e.storageKey, n = a !== e.persist, l = i !== e.defaultTheme, p = a;
|
|
107
|
-
if (r = e.storageKey, i = e.defaultTheme, a = e.persist, t) {
|
|
108
|
-
if (a) {
|
|
109
|
-
let e = f(r);
|
|
110
|
-
e.status === "success" && (c = !1, d(e.value) ? (o = e.value, s = !0) : (o = i, s = !1)), u();
|
|
111
|
-
}
|
|
112
|
-
} else if (n) {
|
|
113
|
-
if (!p && a) {
|
|
114
|
-
let e = f(r);
|
|
115
|
-
e.status === "success" && (c = !1, d(e.value) && (o = e.value, s = !0, u()));
|
|
116
|
-
}
|
|
117
|
-
} else if (l && !s) {
|
|
118
|
-
if (a) {
|
|
119
|
-
let e = f(r);
|
|
120
|
-
e.status === "success" && !d(e.value) && (o = i, u());
|
|
121
|
-
} else o = i, u();
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
};
|
|
19
|
+
return e === "light" || e === "dark" || e === "system";
|
|
125
20
|
}
|
|
126
|
-
function
|
|
127
|
-
let
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
21
|
+
function p({ children: t, storageKey: r = l, defaultTheme: p = "system", persist: m = !0, theme: h, onThemeChange: g, applyToDocument: _ = !0 }) {
|
|
22
|
+
let v = h !== void 0, [y] = o(() => e({
|
|
23
|
+
storageKey: r,
|
|
24
|
+
defaultValue: p,
|
|
25
|
+
persist: m,
|
|
26
|
+
isValid: f,
|
|
27
|
+
normalize: (e) => e,
|
|
28
|
+
eventName: "basalt:theme-change"
|
|
29
|
+
}));
|
|
30
|
+
i(() => {
|
|
31
|
+
y.updateConfig({
|
|
32
|
+
storageKey: r,
|
|
33
|
+
defaultValue: p,
|
|
34
|
+
persist: m
|
|
133
35
|
});
|
|
134
36
|
}, [
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
37
|
+
y,
|
|
38
|
+
r,
|
|
39
|
+
p,
|
|
40
|
+
m
|
|
139
41
|
]);
|
|
140
|
-
let
|
|
141
|
-
|
|
142
|
-
if (!(!
|
|
143
|
-
let e = window.matchMedia("(prefers-color-scheme: dark)"), t = () =>
|
|
42
|
+
let b = n(() => p, [p]), x = s(y.subscribe, y.getSnapshot, b), S = v ? h : x;
|
|
43
|
+
i(() => {
|
|
44
|
+
if (!(!_ || typeof window > "u") && (d(S), S === "system")) try {
|
|
45
|
+
let e = window.matchMedia("(prefers-color-scheme: dark)"), t = () => d("system");
|
|
144
46
|
return e.addEventListener("change", t), () => e.removeEventListener("change", t);
|
|
145
47
|
} catch {
|
|
146
48
|
return;
|
|
147
49
|
}
|
|
148
|
-
}, [
|
|
149
|
-
let
|
|
150
|
-
if (
|
|
151
|
-
|
|
50
|
+
}, [S, _]);
|
|
51
|
+
let C = n((e) => {
|
|
52
|
+
if (v) {
|
|
53
|
+
g?.(e);
|
|
152
54
|
return;
|
|
153
55
|
}
|
|
154
|
-
|
|
56
|
+
y.setValue(e), g?.(e);
|
|
155
57
|
}, [
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
]),
|
|
160
|
-
theme:
|
|
161
|
-
setTheme:
|
|
162
|
-
}), [
|
|
163
|
-
return /* @__PURE__ */
|
|
164
|
-
value:
|
|
165
|
-
children:
|
|
58
|
+
v,
|
|
59
|
+
g,
|
|
60
|
+
y
|
|
61
|
+
]), w = a(() => ({
|
|
62
|
+
theme: S,
|
|
63
|
+
setTheme: C
|
|
64
|
+
}), [S, C]);
|
|
65
|
+
return /* @__PURE__ */ c(u.Provider, {
|
|
66
|
+
value: w,
|
|
67
|
+
children: t
|
|
166
68
|
});
|
|
167
69
|
}
|
|
168
|
-
function
|
|
169
|
-
let e =
|
|
70
|
+
function m() {
|
|
71
|
+
let e = r(u);
|
|
170
72
|
if (!e) throw Error("useTheme must be used within ThemeProvider");
|
|
171
73
|
return e;
|
|
172
74
|
}
|
|
173
75
|
//#endregion
|
|
174
|
-
export {
|
|
76
|
+
export { p as ThemeProvider, m as useTheme };
|
|
175
77
|
|
|
176
78
|
//# sourceMappingURL=theme.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.js","names":[],"sources":["../../src/providers/theme.tsx"],"sourcesContent":["import {\n\tcreateContext,\n\ttype ReactNode,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseState,\n\tuseSyncExternalStore,\n} from \"react\";\n\nexport type BasaltTheme = \"light\" | \"dark\" | \"system\";\n\nconst STORAGE_KEY = \"theme\";\n\ntype ThemeContextValue = {\n\ttheme: BasaltTheme;\n\tsetTheme: (theme: BasaltTheme) => void;\n};\n\nconst ThemeContext = createContext<ThemeContextValue | null>(null);\n\nfunction applyTheme(theme: BasaltTheme) {\n\tif (typeof document === \"undefined\") {\n\t\treturn;\n\t}\n\tconst root = document.documentElement;\n\tlet systemDark = false;\n\ttry {\n\t\tif (typeof window !== \"undefined\" && typeof window.matchMedia === \"function\") {\n\t\t\tsystemDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n\t\t}\n\t} catch {\n\t\tsystemDark = false;\n\t}\n\tconst dark = theme === \"dark\" || (theme === \"system\" && systemDark);\n\troot.classList.toggle(\"dark\", dark);\n\troot.classList.toggle(\"light\", !dark);\n\troot.dataset.mode = dark ? \"dark\" : \"light\";\n}\n\nexport interface ThemeProviderProps {\n\t/**\n\t * Application components wrapped by the theme context.\n\t */\n\tchildren: ReactNode;\n\t/**\n\t * Storage key used for theme persistence.\n\t * @default \"theme\"\n\t */\n\tstorageKey?: string;\n\t/**\n\t * Initial theme used when no stored preference exists or during SSR.\n\t * @default \"system\"\n\t */\n\tdefaultTheme?: BasaltTheme;\n\t/**\n\t * Whether to persist theme changes to localStorage.\n\t * If false, localStorage is never read or written.\n\t * @default true\n\t */\n\tpersist?: boolean;\n\t/**\n\t * Controlled theme value. When provided, the provider acts as a controlled component\n\t * and internal state is driven by this prop.\n\t */\n\ttheme?: BasaltTheme;\n\t/**\n\t * Callback fired when theme change is requested.\n\t * In controlled mode, callers are responsible for updating `theme`.\n\t */\n\tonThemeChange?: (theme: BasaltTheme) => void;\n\t/**\n\t * Whether to apply mode classes and data-mode attribute to document.documentElement.\n\t * Set to false when a host theme system manages the document root.\n\t * @default true\n\t */\n\tapplyToDocument?: boolean;\n}\n\ninterface ThemeStore {\n\tgetSnapshot: () => BasaltTheme;\n\tsubscribe: (listener: () => void) => () => void;\n\tsetTheme: (next: BasaltTheme) => void;\n\tupdateConfig: (config: {\n\t\tstorageKey: string;\n\t\tdefaultTheme: BasaltTheme;\n\t\tpersist: boolean;\n\t}) => void;\n}\n\nfunction isValidTheme(value: unknown): value is BasaltTheme {\n\treturn value === \"light\" || value === \"dark\" || value === \"system\";\n}\n\ntype StorageReadResult = { status: \"success\"; value: string | null } | { status: \"error\" };\n\nfunction safeGetStorageItem(key: string): StorageReadResult {\n\ttry {\n\t\tif (typeof window === \"undefined\" || !window.localStorage) {\n\t\t\treturn { status: \"error\" };\n\t\t}\n\t\tconst value = window.localStorage.getItem(key);\n\t\treturn { status: \"success\", value };\n\t} catch {\n\t\treturn { status: \"error\" };\n\t}\n}\n\nfunction safeSetStorageItem(key: string, value: string): boolean {\n\ttry {\n\t\tif (typeof window === \"undefined\" || !window.localStorage) {\n\t\t\treturn false;\n\t\t}\n\t\twindow.localStorage.setItem(key, value);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction isLocalStorageArea(area: Storage | null | undefined): boolean {\n\tif (!area) {\n\t\treturn true;\n\t}\n\ttry {\n\t\tif (typeof window !== \"undefined\" && window.localStorage) {\n\t\t\treturn area === window.localStorage;\n\t\t}\n\t} catch {\n\t\t// localStorage getter threw\n\t\treturn false;\n\t}\n\treturn false;\n}\n\nconst THEME_CHANGE_EVENT = \"basalt:theme-change\";\n\ninterface ThemeChangeEventDetail {\n\tkey: string;\n\tvalue: BasaltTheme;\n\twriteSucceeded: boolean;\n}\n\nfunction createThemeStore(\n\tinitialStorageKey: string,\n\tinitialDefaultTheme: BasaltTheme,\n\tinitialPersist: boolean,\n): ThemeStore {\n\tlet storageKey = initialStorageKey;\n\tlet defaultTheme = initialDefaultTheme;\n\tlet persist = initialPersist;\n\n\t// In-memory fallback / cache value\n\tlet memoryTheme: BasaltTheme = defaultTheme;\n\tlet hasExplicitSelection = false;\n\tlet lastSetFailed = false;\n\n\tif (persist) {\n\t\tconst res = safeGetStorageItem(storageKey);\n\t\tif (res.status === \"success\" && isValidTheme(res.value)) {\n\t\t\tmemoryTheme = res.value;\n\t\t\thasExplicitSelection = true;\n\t\t}\n\t}\n\n\tconst listeners = new Set<() => void>();\n\n\tconst notify = () => {\n\t\tfor (const listener of listeners) {\n\t\t\tlistener();\n\t\t}\n\t};\n\n\tconst onInternalChange = (event: Event) => {\n\t\tif (!persist) {\n\t\t\treturn;\n\t\t}\n\t\tconst customEv = event as CustomEvent<ThemeChangeEventDetail>;\n\t\tif (!customEv.detail || customEv.detail.key !== storageKey) {\n\t\t\treturn;\n\t\t}\n\t\tconst { value, writeSucceeded } = customEv.detail;\n\t\tif (writeSucceeded) {\n\t\t\tlastSetFailed = false;\n\t\t} else {\n\t\t\tlastSetFailed = true;\n\t\t}\n\t\tmemoryTheme = value;\n\t\thasExplicitSelection = true;\n\t\tnotify();\n\t};\n\n\tconst onStorage = (event: StorageEvent | Event) => {\n\t\tif (!persist) {\n\t\t\treturn;\n\t\t}\n\t\tconst storageEv = event as Partial<StorageEvent>;\n\t\tif (\"key\" in storageEv && storageEv.key !== undefined) {\n\t\t\tif (!isLocalStorageArea(storageEv.storageArea)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (storageEv.key !== null && storageEv.key !== storageKey) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlastSetFailed = false;\n\t\t\tconst rawVal = storageEv.newValue;\n\t\t\tif (rawVal === null || rawVal === undefined || !isValidTheme(rawVal)) {\n\t\t\t\t// Key removed or invalid value: revert to configured default\n\t\t\t\tmemoryTheme = defaultTheme;\n\t\t\t\thasExplicitSelection = false;\n\t\t\t\tnotify();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tmemoryTheme = rawVal;\n\t\t\thasExplicitSelection = true;\n\t\t\tnotify();\n\t\t\treturn;\n\t\t}\n\t\t// Untyped/bare storage event: e.g. dispatchEvent(new Event(\"storage\"))\n\t\t// If last set failed, ignore so stale storage cannot overwrite in-memory switch\n\t\tif (lastSetFailed) {\n\t\t\treturn;\n\t\t}\n\t\tconst res = safeGetStorageItem(storageKey);\n\t\tif (res.status === \"error\") {\n\t\t\t// Read failed: preserve current cached memory theme, do not revert to default\n\t\t\treturn;\n\t\t}\n\t\tif (isValidTheme(res.value)) {\n\t\t\tmemoryTheme = res.value;\n\t\t\thasExplicitSelection = true;\n\t\t\tnotify();\n\t\t} else {\n\t\t\t// Key removed or invalid value stored: revert to default\n\t\t\tmemoryTheme = defaultTheme;\n\t\t\thasExplicitSelection = false;\n\t\t\tnotify();\n\t\t}\n\t};\n\n\tlet cleanupStorageListener: (() => void) | null = null;\n\tconst attachStorageListener = () => {\n\t\tif (typeof window === \"undefined\") {\n\t\t\treturn;\n\t\t}\n\t\tif (listeners.size === 1 && !cleanupStorageListener) {\n\t\t\twindow.addEventListener(\"storage\", onStorage);\n\t\t\twindow.addEventListener(THEME_CHANGE_EVENT, onInternalChange);\n\t\t\tcleanupStorageListener = () => {\n\t\t\t\twindow.removeEventListener(\"storage\", onStorage);\n\t\t\t\twindow.removeEventListener(THEME_CHANGE_EVENT, onInternalChange);\n\t\t\t\tcleanupStorageListener = null;\n\t\t\t};\n\t\t}\n\t};\n\n\tconst detachStorageListener = () => {\n\t\tif (listeners.size === 0 && cleanupStorageListener) {\n\t\t\tcleanupStorageListener();\n\t\t}\n\t};\n\n\treturn {\n\t\tgetSnapshot: () => memoryTheme,\n\t\tsubscribe: (listener: () => void) => {\n\t\t\tlisteners.add(listener);\n\t\t\tattachStorageListener();\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t\tdetachStorageListener();\n\t\t\t};\n\t\t},\n\t\tsetTheme: (next: BasaltTheme) => {\n\t\t\tmemoryTheme = next;\n\t\t\thasExplicitSelection = true;\n\t\t\tlet writeSucceeded = true;\n\t\t\tif (persist) {\n\t\t\t\tconst success = safeSetStorageItem(storageKey, next);\n\t\t\t\tlastSetFailed = !success;\n\t\t\t\twriteSucceeded = success;\n\t\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\twindow.dispatchEvent(\n\t\t\t\t\t\t\tnew CustomEvent<ThemeChangeEventDetail>(THEME_CHANGE_EVENT, {\n\t\t\t\t\t\t\t\tdetail: { key: storageKey, value: next, writeSucceeded },\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tnotify();\n\t\t},\n\t\tupdateConfig: (config) => {\n\t\t\tconst keyChanged = storageKey !== config.storageKey;\n\t\t\tconst persistChanged = persist !== config.persist;\n\t\t\tconst defaultChanged = defaultTheme !== config.defaultTheme;\n\n\t\t\tconst oldPersist = persist;\n\t\t\tstorageKey = config.storageKey;\n\t\t\tdefaultTheme = config.defaultTheme;\n\t\t\tpersist = config.persist;\n\n\t\t\tif (keyChanged) {\n\t\t\t\tif (persist) {\n\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\tif (res.status === \"success\") {\n\t\t\t\t\t\tlastSetFailed = false;\n\t\t\t\t\t\tif (isValidTheme(res.value)) {\n\t\t\t\t\t\t\tmemoryTheme = res.value;\n\t\t\t\t\t\t\thasExplicitSelection = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmemoryTheme = defaultTheme;\n\t\t\t\t\t\t\thasExplicitSelection = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tnotify();\n\t\t\t\t}\n\t\t\t\t// persist=false: changing storageKey does not reset current memoryTheme\n\t\t\t} else if (persistChanged) {\n\t\t\t\tif (!oldPersist && persist) {\n\t\t\t\t\t// persist flipped false -> true: read from storage or keep current\n\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\tif (res.status === \"success\") {\n\t\t\t\t\t\tlastSetFailed = false;\n\t\t\t\t\t\tif (isValidTheme(res.value)) {\n\t\t\t\t\t\t\tmemoryTheme = res.value;\n\t\t\t\t\t\t\thasExplicitSelection = true;\n\t\t\t\t\t\t\tnotify();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// persist flipped true -> false: only disable persistence, keep current memoryTheme, no storage read/write\n\t\t\t} else if (defaultChanged) {\n\t\t\t\t// defaultTheme changed: only update if no explicit selection was made\n\t\t\t\tif (!hasExplicitSelection) {\n\t\t\t\t\tif (persist) {\n\t\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\t\tif (res.status === \"success\" && !isValidTheme(res.value)) {\n\t\t\t\t\t\t\tmemoryTheme = defaultTheme;\n\t\t\t\t\t\t\tnotify();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmemoryTheme = defaultTheme;\n\t\t\t\t\t\tnotify();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport function ThemeProvider({\n\tchildren,\n\tstorageKey = STORAGE_KEY,\n\tdefaultTheme = \"system\",\n\tpersist = true,\n\ttheme: controlledTheme,\n\tonThemeChange,\n\tapplyToDocument = true,\n}: ThemeProviderProps) {\n\tconst isControlled = controlledTheme !== undefined;\n\n\tconst [store] = useState(() => createThemeStore(storageKey, defaultTheme, persist));\n\n\tuseEffect(() => {\n\t\tstore.updateConfig({ storageKey, defaultTheme, persist });\n\t}, [store, storageKey, defaultTheme, persist]);\n\n\tconst getServerSnapshot = useCallback(() => defaultTheme, [defaultTheme]);\n\n\tconst storeTheme = useSyncExternalStore(store.subscribe, store.getSnapshot, getServerSnapshot);\n\n\tconst currentTheme = isControlled ? controlledTheme : storeTheme;\n\n\tuseEffect(() => {\n\t\tif (!applyToDocument || typeof window === \"undefined\") {\n\t\t\treturn;\n\t\t}\n\t\tapplyTheme(currentTheme);\n\t\tif (currentTheme !== \"system\") {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tconst mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n\t\t\tconst onChange = () => applyTheme(\"system\");\n\t\t\tmq.addEventListener(\"change\", onChange);\n\t\t\treturn () => mq.removeEventListener(\"change\", onChange);\n\t\t} catch {\n\t\t\t// matchMedia not supported or restricted\n\t\t\treturn;\n\t\t}\n\t}, [currentTheme, applyToDocument]);\n\n\tconst setTheme = useCallback(\n\t\t(next: BasaltTheme) => {\n\t\t\tif (isControlled) {\n\t\t\t\tonThemeChange?.(next);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstore.setTheme(next);\n\t\t\tonThemeChange?.(next);\n\t\t},\n\t\t[isControlled, onThemeChange, store],\n\t);\n\n\tconst value = useMemo(() => ({ theme: currentTheme, setTheme }), [currentTheme, setTheme]);\n\n\treturn <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;\n}\n\nexport function useTheme() {\n\tconst ctx = useContext(ThemeContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useTheme must be used within ThemeProvider\");\n\t}\n\treturn ctx;\n}\n"],"mappings":";;;;AAaA,IAAM,IAAc,SAOd,IAAe,EAAwC,IAAI;AAEjE,SAAS,EAAW,GAAoB;CACvC,IAAI,OAAO,WAAa,KACvB;CAED,IAAM,IAAO,SAAS,iBAClB,IAAa;CACjB,IAAI;EACH,AAAI,OAAO,SAAW,OAAe,OAAO,OAAO,cAAe,eACjE,IAAa,OAAO,WAAW,8BAA8B,CAAC,CAAC;CAEjE,QAAQ;EACP,IAAa;CACd;CACA,IAAM,IAAO,MAAU,UAAW,MAAU,YAAY;CAGxD,AAFA,EAAK,UAAU,OAAO,QAAQ,CAAI,GAClC,EAAK,UAAU,OAAO,SAAS,CAAC,CAAI,GACpC,EAAK,QAAQ,OAAO,IAAO,SAAS;AACrC;AAoDA,SAAS,EAAa,GAAsC;CAC3D,OAAO,MAAU,WAAW,MAAU,UAAU,MAAU;AAC3D;AAIA,SAAS,EAAmB,GAAgC;CAC3D,IAAI;EAKH,OAJI,OAAO,SAAW,OAAe,CAAC,OAAO,eACrC,EAAE,QAAQ,QAAQ,IAGnB;GAAE,QAAQ;GAAW,OADd,OAAO,aAAa,QAAQ,CACd;EAAM;CACnC,QAAQ;EACP,OAAO,EAAE,QAAQ,QAAQ;CAC1B;AACD;AAEA,SAAS,EAAmB,GAAa,GAAwB;CAChE,IAAI;EAKH,OAJI,OAAO,SAAW,OAAe,CAAC,OAAO,eACrC,MAER,OAAO,aAAa,QAAQ,GAAK,CAAK,GAC/B;CACR,QAAQ;EACP,OAAO;CACR;AACD;AAEA,SAAS,EAAmB,GAA2C;CACtE,IAAI,CAAC,GACJ,OAAO;CAER,IAAI;EACH,IAAI,OAAO,SAAW,OAAe,OAAO,cAC3C,OAAO,MAAS,OAAO;CAEzB,QAAQ;EAEP,OAAO;CACR;CACA,OAAO;AACR;AAEA,IAAM,IAAqB;AAQ3B,SAAS,EACR,GACA,GACA,GACa;CACb,IAAI,IAAa,GACb,IAAe,GACf,IAAU,GAGV,IAA2B,GAC3B,IAAuB,IACvB,IAAgB;CAEpB,IAAI,GAAS;EACZ,IAAM,IAAM,EAAmB,CAAU;EACzC,AAAI,EAAI,WAAW,aAAa,EAAa,EAAI,KAAK,MACrD,IAAc,EAAI,OAClB,IAAuB;CAEzB;CAEA,IAAM,oBAAY,IAAI,IAAgB,GAEhC,UAAe;EACpB,KAAK,IAAM,KAAY,GACtB,EAAS;CAEX,GAEM,KAAoB,MAAiB;EAC1C,IAAI,CAAC,GACJ;EAED,IAAM,IAAW;EACjB,IAAI,CAAC,EAAS,UAAU,EAAS,OAAO,QAAQ,GAC/C;EAED,IAAM,EAAE,UAAO,sBAAmB,EAAS;EAQ3C,AAPA,AAGC,IAHD,CAAI,GAKJ,IAAc,GACd,IAAuB,IACvB,EAAO;CACR,GAEM,KAAa,MAAgC;EAClD,IAAI,CAAC,GACJ;EAED,IAAM,IAAY;EAClB,IAAI,SAAS,KAAa,EAAU,QAAQ,KAAA,GAAW;GAItD,IAHI,CAAC,EAAmB,EAAU,WAAW,KAGzC,EAAU,QAAQ,QAAQ,EAAU,QAAQ,GAC/C;GAED,IAAgB;GAChB,IAAM,IAAS,EAAU;GACzB,IAAI,KAAW,QAAgC,CAAC,EAAa,CAAM,GAAG;IAIrE,AAFA,IAAc,GACd,IAAuB,IACvB,EAAO;IACP;GACD;GAGA,AAFA,IAAc,GACd,IAAuB,IACvB,EAAO;GACP;EACD;EAGA,IAAI,GACH;EAED,IAAM,IAAM,EAAmB,CAAU;EACrC,EAAI,WAAW,YAIf,EAAa,EAAI,KAAK,KACzB,IAAc,EAAI,OAClB,IAAuB,IACvB,EAAO,MAGP,IAAc,GACd,IAAuB,IACvB,EAAO;CAET,GAEI,IAA8C,MAC5C,UAA8B;EAC/B,OAAO,SAAW,OAGlB,EAAU,SAAS,KAAK,CAAC,MAC5B,OAAO,iBAAiB,WAAW,CAAS,GAC5C,OAAO,iBAAiB,GAAoB,CAAgB,GAC5D,UAA+B;GAG9B,AAFA,OAAO,oBAAoB,WAAW,CAAS,GAC/C,OAAO,oBAAoB,GAAoB,CAAgB,GAC/D,IAAyB;EAC1B;CAEF,GAEM,UAA8B;EACnC,AAAI,EAAU,SAAS,KAAK,KAC3B,EAAuB;CAEzB;CAEA,OAAO;EACN,mBAAmB;EACnB,YAAY,OACX,EAAU,IAAI,CAAQ,GACtB,EAAsB,SACT;GAEZ,AADA,EAAU,OAAO,CAAQ,GACzB,EAAsB;EACvB;EAED,WAAW,MAAsB;GAEhC,AADA,IAAc,GACd,IAAuB;GACvB,IAAI,IAAiB;GACrB,IAAI,GAAS;IACZ,IAAM,IAAU,EAAmB,GAAY,CAAI;IAGnD,IAFA,IAAgB,CAAC,GACjB,IAAiB,GACb,OAAO,SAAW,KACrB,IAAI;KACH,OAAO,cACN,IAAI,YAAoC,GAAoB,EAC3D,QAAQ;MAAE,KAAK;MAAY,OAAO;MAAM;KAAe,EACxD,CAAC,CACF;IACD,QAAQ,CAER;GAEF;GACA,EAAO;EACR;EACA,eAAe,MAAW;GACzB,IAAM,IAAa,MAAe,EAAO,YACnC,IAAiB,MAAY,EAAO,SACpC,IAAiB,MAAiB,EAAO,cAEzC,IAAa;GAKnB,IAJA,IAAa,EAAO,YACpB,IAAe,EAAO,cACtB,IAAU,EAAO,SAEb,GACC;QAAA,GAAS;KACZ,IAAM,IAAM,EAAmB,CAAU;KAWzC,AAVI,EAAI,WAAW,cAClB,IAAgB,IACZ,EAAa,EAAI,KAAK,KACzB,IAAc,EAAI,OAClB,IAAuB,OAEvB,IAAc,GACd,IAAuB,MAGzB,EAAO;IACR;UAEM,IAAI,GACN;QAAA,CAAC,KAAc,GAAS;KAE3B,IAAM,IAAM,EAAmB,CAAU;KACzC,AAAI,EAAI,WAAW,cAClB,IAAgB,IACZ,EAAa,EAAI,KAAK,MACzB,IAAc,EAAI,OAClB,IAAuB,IACvB,EAAO;IAGV;UAEM,IAAI,KAEN,CAAC,GAAsB;IAC1B,IAAI,GAAS;KACZ,IAAM,IAAM,EAAmB,CAAU;KACzC,AAAI,EAAI,WAAW,aAAa,CAAC,EAAa,EAAI,KAAK,MACtD,IAAc,GACd,EAAO;IAET,OAEC,AADA,IAAc,GACd,EAAO;GAET;EAEF;CACD;AACD;AAEA,SAAgB,EAAc,EAC7B,aACA,gBAAa,GACb,kBAAe,UACf,aAAU,IACV,OAAO,GACP,kBACA,qBAAkB,MACI;CACtB,IAAM,IAAe,MAAoB,KAAA,GAEnC,CAAC,KAAS,QAAe,EAAiB,GAAY,GAAc,CAAO,CAAC;CAElF,QAAgB;EACf,EAAM,aAAa;GAAE;GAAY;GAAc;EAAQ,CAAC;CACzD,GAAG;EAAC;EAAO;EAAY;EAAc;CAAO,CAAC;CAE7C,IAAM,IAAoB,QAAkB,GAAc,CAAC,CAAY,CAAC,GAElE,IAAa,EAAqB,EAAM,WAAW,EAAM,aAAa,CAAiB,GAEvF,IAAe,IAAe,IAAkB;CAEtD,QAAgB;EACX,OAAC,KAAmB,OAAO,SAAW,SAG1C,EAAW,CAAY,GACnB,MAAiB,WAGrB,IAAI;GACH,IAAM,IAAK,OAAO,WAAW,8BAA8B,GACrD,UAAiB,EAAW,QAAQ;GAE1C,OADA,EAAG,iBAAiB,UAAU,CAAQ,SACzB,EAAG,oBAAoB,UAAU,CAAQ;EACvD,QAAQ;GAEP;EACD;CACD,GAAG,CAAC,GAAc,CAAe,CAAC;CAElC,IAAM,IAAW,GACf,MAAsB;EACtB,IAAI,GAAc;GACjB,IAAgB,CAAI;GACpB;EACD;EAEA,AADA,EAAM,SAAS,CAAI,GACnB,IAAgB,CAAI;CACrB,GACA;EAAC;EAAc;EAAe;CAAK,CACpC,GAEM,IAAQ,SAAe;EAAE,OAAO;EAAc;CAAS,IAAI,CAAC,GAAc,CAAQ,CAAC;CAEzF,OAAO,kBAAC,EAAa,UAAd;EAA8B;EAAQ;CAAgC,CAAA;AAC9E;AAEA,SAAgB,IAAW;CAC1B,IAAM,IAAM,EAAW,CAAY;CACnC,IAAI,CAAC,GACJ,MAAU,MAAM,4CAA4C;CAE7D,OAAO;AACR"}
|
|
1
|
+
{"version":3,"file":"theme.js","names":[],"sources":["../../src/providers/theme.tsx"],"sourcesContent":["import {\n\tcreateContext,\n\ttype ReactNode,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseState,\n\tuseSyncExternalStore,\n} from \"react\";\nimport { createPreferenceStore } from \"../utils/preference-store\";\n\nexport type BasaltTheme = \"light\" | \"dark\" | \"system\";\n\nconst STORAGE_KEY = \"theme\";\n\ntype ThemeContextValue = {\n\ttheme: BasaltTheme;\n\tsetTheme: (theme: BasaltTheme) => void;\n};\n\nconst ThemeContext = createContext<ThemeContextValue | null>(null);\n\nfunction applyTheme(theme: BasaltTheme) {\n\tif (typeof document === \"undefined\") {\n\t\treturn;\n\t}\n\tconst root = document.documentElement;\n\tlet systemDark = false;\n\ttry {\n\t\tif (typeof window !== \"undefined\" && typeof window.matchMedia === \"function\") {\n\t\t\tsystemDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n\t\t}\n\t} catch {\n\t\tsystemDark = false;\n\t}\n\tconst dark = theme === \"dark\" || (theme === \"system\" && systemDark);\n\troot.classList.toggle(\"dark\", dark);\n\troot.classList.toggle(\"light\", !dark);\n\troot.dataset.mode = dark ? \"dark\" : \"light\";\n}\n\nexport interface ThemeProviderProps {\n\t/**\n\t * Application components wrapped by the theme context.\n\t */\n\tchildren: ReactNode;\n\t/**\n\t * Storage key used for theme persistence.\n\t * @default \"theme\"\n\t */\n\tstorageKey?: string;\n\t/**\n\t * Initial theme used when no stored preference exists or during SSR.\n\t * @default \"system\"\n\t */\n\tdefaultTheme?: BasaltTheme;\n\t/**\n\t * Whether to persist theme changes to localStorage.\n\t * If false, localStorage is never read or written.\n\t * @default true\n\t */\n\tpersist?: boolean;\n\t/**\n\t * Controlled theme value. When provided, the provider acts as a controlled component\n\t * and internal state is driven by this prop.\n\t */\n\ttheme?: BasaltTheme;\n\t/**\n\t * Callback fired when theme change is requested.\n\t * In controlled mode, callers are responsible for updating `theme`.\n\t */\n\tonThemeChange?: (theme: BasaltTheme) => void;\n\t/**\n\t * Whether to apply mode classes and data-mode attribute to document.documentElement.\n\t * Set to false when a host theme system manages the document root.\n\t * @default true\n\t */\n\tapplyToDocument?: boolean;\n}\n\nfunction isValidTheme(value: unknown): value is BasaltTheme {\n\treturn value === \"light\" || value === \"dark\" || value === \"system\";\n}\n\nexport function ThemeProvider({\n\tchildren,\n\tstorageKey = STORAGE_KEY,\n\tdefaultTheme = \"system\",\n\tpersist = true,\n\ttheme: controlledTheme,\n\tonThemeChange,\n\tapplyToDocument = true,\n}: ThemeProviderProps) {\n\tconst isControlled = controlledTheme !== undefined;\n\n\tconst [store] = useState(() =>\n\t\tcreatePreferenceStore({\n\t\t\tstorageKey,\n\t\t\tdefaultValue: defaultTheme,\n\t\t\tpersist,\n\t\t\tisValid: isValidTheme,\n\t\t\tnormalize: (value) => value,\n\t\t\teventName: \"basalt:theme-change\",\n\t\t}),\n\t);\n\n\tuseEffect(() => {\n\t\tstore.updateConfig({ storageKey, defaultValue: defaultTheme, persist });\n\t}, [store, storageKey, defaultTheme, persist]);\n\n\tconst getServerSnapshot = useCallback(() => defaultTheme, [defaultTheme]);\n\n\tconst storeTheme = useSyncExternalStore(store.subscribe, store.getSnapshot, getServerSnapshot);\n\n\tconst currentTheme = isControlled ? controlledTheme : storeTheme;\n\n\tuseEffect(() => {\n\t\tif (!applyToDocument || typeof window === \"undefined\") {\n\t\t\treturn;\n\t\t}\n\t\tapplyTheme(currentTheme);\n\t\tif (currentTheme !== \"system\") {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tconst mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n\t\t\tconst onChange = () => applyTheme(\"system\");\n\t\t\tmq.addEventListener(\"change\", onChange);\n\t\t\treturn () => mq.removeEventListener(\"change\", onChange);\n\t\t} catch {\n\t\t\t// matchMedia not supported or restricted\n\t\t\treturn;\n\t\t}\n\t}, [currentTheme, applyToDocument]);\n\n\tconst setTheme = useCallback(\n\t\t(next: BasaltTheme) => {\n\t\t\tif (isControlled) {\n\t\t\t\tonThemeChange?.(next);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstore.setValue(next);\n\t\t\tonThemeChange?.(next);\n\t\t},\n\t\t[isControlled, onThemeChange, store],\n\t);\n\n\tconst value = useMemo(() => ({ theme: currentTheme, setTheme }), [currentTheme, setTheme]);\n\n\treturn <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;\n}\n\nexport function useTheme() {\n\tconst ctx = useContext(ThemeContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useTheme must be used within ThemeProvider\");\n\t}\n\treturn ctx;\n}\n"],"mappings":";;;;;AAcA,IAAM,IAAc,SAOd,IAAe,EAAwC,IAAI;AAEjE,SAAS,EAAW,GAAoB;CACvC,IAAI,OAAO,WAAa,KACvB;CAED,IAAM,IAAO,SAAS,iBAClB,IAAa;CACjB,IAAI;EACH,AAAI,OAAO,SAAW,OAAe,OAAO,OAAO,cAAe,eACjE,IAAa,OAAO,WAAW,8BAA8B,CAAC,CAAC;CAEjE,QAAQ;EACP,IAAa;CACd;CACA,IAAM,IAAO,MAAU,UAAW,MAAU,YAAY;CAGxD,AAFA,EAAK,UAAU,OAAO,QAAQ,CAAI,GAClC,EAAK,UAAU,OAAO,SAAS,CAAC,CAAI,GACpC,EAAK,QAAQ,OAAO,IAAO,SAAS;AACrC;AAyCA,SAAS,EAAa,GAAsC;CAC3D,OAAO,MAAU,WAAW,MAAU,UAAU,MAAU;AAC3D;AAEA,SAAgB,EAAc,EAC7B,aACA,gBAAa,GACb,kBAAe,UACf,aAAU,IACV,OAAO,GACP,kBACA,qBAAkB,MACI;CACtB,IAAM,IAAe,MAAoB,KAAA,GAEnC,CAAC,KAAS,QACf,EAAsB;EACrB;EACA,cAAc;EACd;EACA,SAAS;EACT,YAAY,MAAU;EACtB,WAAW;CACZ,CAAC,CACF;CAEA,QAAgB;EACf,EAAM,aAAa;GAAE;GAAY,cAAc;GAAc;EAAQ,CAAC;CACvE,GAAG;EAAC;EAAO;EAAY;EAAc;CAAO,CAAC;CAE7C,IAAM,IAAoB,QAAkB,GAAc,CAAC,CAAY,CAAC,GAElE,IAAa,EAAqB,EAAM,WAAW,EAAM,aAAa,CAAiB,GAEvF,IAAe,IAAe,IAAkB;CAEtD,QAAgB;EACX,OAAC,KAAmB,OAAO,SAAW,SAG1C,EAAW,CAAY,GACnB,MAAiB,WAGrB,IAAI;GACH,IAAM,IAAK,OAAO,WAAW,8BAA8B,GACrD,UAAiB,EAAW,QAAQ;GAE1C,OADA,EAAG,iBAAiB,UAAU,CAAQ,SACzB,EAAG,oBAAoB,UAAU,CAAQ;EACvD,QAAQ;GAEP;EACD;CACD,GAAG,CAAC,GAAc,CAAe,CAAC;CAElC,IAAM,IAAW,GACf,MAAsB;EACtB,IAAI,GAAc;GACjB,IAAgB,CAAI;GACpB;EACD;EAEA,AADA,EAAM,SAAS,CAAI,GACnB,IAAgB,CAAI;CACrB,GACA;EAAC;EAAc;EAAe;CAAK,CACpC,GAEM,IAAQ,SAAe;EAAE,OAAO;EAAc;CAAS,IAAI,CAAC,GAAc,CAAQ,CAAC;CAEzF,OAAO,kBAAC,EAAa,UAAd;EAA8B;EAAQ;CAAgC,CAAA;AAC9E;AAEA,SAAgB,IAAW;CAC1B,IAAM,IAAM,EAAW,CAAY;CACnC,IAAI,CAAC,GACJ,MAAU,MAAM,4CAA4C;CAE7D,OAAO;AACR"}
|
|
@@ -1688,6 +1688,10 @@
|
|
|
1688
1688
|
.text-\[13px\] {
|
|
1689
1689
|
font-size: 13px;
|
|
1690
1690
|
}
|
|
1691
|
+
.leading-4 {
|
|
1692
|
+
--tw-leading: calc(var(--spacing) * 4);
|
|
1693
|
+
line-height: calc(var(--spacing) * 4);
|
|
1694
|
+
}
|
|
1691
1695
|
.leading-5 {
|
|
1692
1696
|
--tw-leading: calc(var(--spacing) * 5);
|
|
1693
1697
|
line-height: calc(var(--spacing) * 5);
|
|
@@ -2014,6 +2018,14 @@
|
|
|
2014
2018
|
.placeholder\:text-basalt-muted-foreground::placeholder {
|
|
2015
2019
|
color: hsl(var(--basalt-muted-foreground));
|
|
2016
2020
|
}
|
|
2021
|
+
.before\:absolute::before {
|
|
2022
|
+
content: var(--tw-content);
|
|
2023
|
+
position: absolute;
|
|
2024
|
+
}
|
|
2025
|
+
.before\:inset-0::before {
|
|
2026
|
+
content: var(--tw-content);
|
|
2027
|
+
inset: 0px;
|
|
2028
|
+
}
|
|
2017
2029
|
.first\:rounded-l-basalt-md:first-child {
|
|
2018
2030
|
border-top-left-radius: calc(var(--basalt-radius) - 2px);
|
|
2019
2031
|
border-bottom-left-radius: calc(var(--basalt-radius) - 2px);
|
|
@@ -2214,6 +2226,12 @@
|
|
|
2214
2226
|
.disabled\:opacity-100:disabled {
|
|
2215
2227
|
opacity: 100%;
|
|
2216
2228
|
}
|
|
2229
|
+
.aria-checked\:text-basalt-primary-foreground[aria-checked="true"] {
|
|
2230
|
+
color: hsl(var(--basalt-primary-foreground));
|
|
2231
|
+
}
|
|
2232
|
+
.aria-disabled\:cursor-not-allowed[aria-disabled="true"] {
|
|
2233
|
+
cursor: not-allowed;
|
|
2234
|
+
}
|
|
2217
2235
|
.aria-disabled\:opacity-50[aria-disabled="true"] {
|
|
2218
2236
|
opacity: 50%;
|
|
2219
2237
|
}
|
|
@@ -2223,6 +2241,19 @@
|
|
|
2223
2241
|
.aria-invalid\:focus-visible\:border-basalt-destructive[aria-invalid="true"]:focus-visible {
|
|
2224
2242
|
border-color: hsl(var(--basalt-destructive));
|
|
2225
2243
|
}
|
|
2244
|
+
.aria-pressed\:bg-basalt-accent[aria-pressed="true"] {
|
|
2245
|
+
background-color: hsl(var(--basalt-accent));
|
|
2246
|
+
}
|
|
2247
|
+
.aria-pressed\:bg-basalt-primary[aria-pressed="true"] {
|
|
2248
|
+
background-color: hsl(var(--basalt-primary));
|
|
2249
|
+
}
|
|
2250
|
+
.aria-pressed\:text-basalt-primary-foreground[aria-pressed="true"] {
|
|
2251
|
+
color: hsl(var(--basalt-primary-foreground));
|
|
2252
|
+
}
|
|
2253
|
+
.aria-pressed\:shadow-sm[aria-pressed="true"] {
|
|
2254
|
+
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
2255
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
2256
|
+
}
|
|
2226
2257
|
.data-disabled\:pointer-events-none[data-disabled] {
|
|
2227
2258
|
pointer-events: none;
|
|
2228
2259
|
}
|
|
@@ -2287,19 +2318,6 @@
|
|
|
2287
2318
|
.data-\[state\=indeterminate\]\:text-basalt-primary-foreground[data-state="indeterminate"] {
|
|
2288
2319
|
color: hsl(var(--basalt-primary-foreground));
|
|
2289
2320
|
}
|
|
2290
|
-
.data-\[state\=on\]\:bg-basalt-accent[data-state="on"] {
|
|
2291
|
-
background-color: hsl(var(--basalt-accent));
|
|
2292
|
-
}
|
|
2293
|
-
.data-\[state\=on\]\:bg-basalt-primary[data-state="on"] {
|
|
2294
|
-
background-color: hsl(var(--basalt-primary));
|
|
2295
|
-
}
|
|
2296
|
-
.data-\[state\=on\]\:text-basalt-primary-foreground[data-state="on"] {
|
|
2297
|
-
color: hsl(var(--basalt-primary-foreground));
|
|
2298
|
-
}
|
|
2299
|
-
.data-\[state\=on\]\:shadow-sm[data-state="on"] {
|
|
2300
|
-
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
2301
|
-
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
2302
|
-
}
|
|
2303
2321
|
.data-\[state\=open\]\:animate-basalt-collapsible-down[data-state="open"] {
|
|
2304
2322
|
animation: basalt-collapsible-down 150ms ease-out;
|
|
2305
2323
|
}
|
|
@@ -3010,6 +3028,11 @@
|
|
|
3010
3028
|
syntax: "*";
|
|
3011
3029
|
inherits: false;
|
|
3012
3030
|
}
|
|
3031
|
+
@property --tw-content {
|
|
3032
|
+
syntax: "*";
|
|
3033
|
+
initial-value: "";
|
|
3034
|
+
inherits: false;
|
|
3035
|
+
}
|
|
3013
3036
|
@layer properties {
|
|
3014
3037
|
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
|
|
3015
3038
|
*, ::before, ::after, ::backdrop {
|
|
@@ -3079,6 +3102,7 @@
|
|
|
3079
3102
|
--tw-backdrop-sepia: initial;
|
|
3080
3103
|
--tw-duration: initial;
|
|
3081
3104
|
--tw-ease: initial;
|
|
3105
|
+
--tw-content: "";
|
|
3082
3106
|
}
|
|
3083
3107
|
}
|
|
3084
3108
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type PreferenceConfig<T> = {
|
|
2
|
+
storageKey: string;
|
|
3
|
+
defaultValue: T;
|
|
4
|
+
persist: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare function createPreferenceStore<T extends string>({ storageKey, defaultValue: initialDefaultValue, persist, isValid, normalize, eventName, }: PreferenceConfig<T> & {
|
|
7
|
+
isValid: (value: unknown) => value is T;
|
|
8
|
+
normalize: (value: T) => T;
|
|
9
|
+
eventName: string;
|
|
10
|
+
}): {
|
|
11
|
+
getSnapshot: () => T;
|
|
12
|
+
subscribe: (listener: () => void) => () => void;
|
|
13
|
+
setValue: (next: T) => void;
|
|
14
|
+
updateConfig: (config: PreferenceConfig<T>) => void;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
//#region src/utils/preference-store.ts
|
|
3
|
+
function e(e) {
|
|
4
|
+
try {
|
|
5
|
+
return typeof window > "u" || !window.localStorage ? { status: "error" } : {
|
|
6
|
+
status: "success",
|
|
7
|
+
value: window.localStorage.getItem(e)
|
|
8
|
+
};
|
|
9
|
+
} catch {
|
|
10
|
+
return { status: "error" };
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function t(e, t) {
|
|
14
|
+
try {
|
|
15
|
+
return typeof window > "u" || !window.localStorage ? !1 : (window.localStorage.setItem(e, t), !0);
|
|
16
|
+
} catch {
|
|
17
|
+
return !1;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function n(e) {
|
|
21
|
+
if (!e) return !0;
|
|
22
|
+
try {
|
|
23
|
+
if (typeof window < "u" && window.localStorage) return e === window.localStorage;
|
|
24
|
+
} catch {
|
|
25
|
+
return !1;
|
|
26
|
+
}
|
|
27
|
+
return !1;
|
|
28
|
+
}
|
|
29
|
+
function r({ storageKey: r, defaultValue: i, persist: a, isValid: o, normalize: s, eventName: c }) {
|
|
30
|
+
let l = s(i), u = l, d = !1, f = !1;
|
|
31
|
+
if (a) {
|
|
32
|
+
let t = e(r);
|
|
33
|
+
t.status === "success" && o(t.value) && (u = s(t.value), d = !0);
|
|
34
|
+
}
|
|
35
|
+
let p = /* @__PURE__ */ new Set(), m = () => {
|
|
36
|
+
for (let e of p) e();
|
|
37
|
+
}, h = (e) => {
|
|
38
|
+
if (!a) return;
|
|
39
|
+
let t = e;
|
|
40
|
+
if (!t.detail || t.detail.key !== r) return;
|
|
41
|
+
let { value: n, writeSucceeded: i } = t.detail;
|
|
42
|
+
f = !i, u = n, d = !0, m();
|
|
43
|
+
}, g = (t) => {
|
|
44
|
+
if (!a) return;
|
|
45
|
+
let i = t;
|
|
46
|
+
if ("key" in i && i.key !== void 0) {
|
|
47
|
+
if (!n(i.storageArea) || i.key !== null && i.key !== r) return;
|
|
48
|
+
f = !1;
|
|
49
|
+
let e = i.newValue;
|
|
50
|
+
e == null || !o(e) ? (u = l, d = !1) : (u = s(e), d = !0), m();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (f) return;
|
|
54
|
+
let c = e(r);
|
|
55
|
+
c.status !== "error" && (o(c.value) ? (u = s(c.value), d = !0) : (u = l, d = !1), m());
|
|
56
|
+
}, _ = null, v = () => {
|
|
57
|
+
typeof window > "u" || p.size === 1 && !_ && (window.addEventListener("storage", g), window.addEventListener(c, h), _ = () => {
|
|
58
|
+
window.removeEventListener("storage", g), window.removeEventListener(c, h), _ = null;
|
|
59
|
+
});
|
|
60
|
+
}, y = () => {
|
|
61
|
+
p.size === 0 && _ && _();
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
getSnapshot: () => u,
|
|
65
|
+
subscribe: (e) => (p.add(e), v(), () => {
|
|
66
|
+
p.delete(e), y();
|
|
67
|
+
}),
|
|
68
|
+
setValue: (e) => {
|
|
69
|
+
let n = s(e);
|
|
70
|
+
if (u = n, d = !0, a) {
|
|
71
|
+
let e = t(r, n);
|
|
72
|
+
if (f = !e, typeof window < "u") try {
|
|
73
|
+
window.dispatchEvent(new CustomEvent(c, { detail: {
|
|
74
|
+
key: r,
|
|
75
|
+
value: n,
|
|
76
|
+
writeSucceeded: e
|
|
77
|
+
} }));
|
|
78
|
+
} catch {}
|
|
79
|
+
}
|
|
80
|
+
m();
|
|
81
|
+
},
|
|
82
|
+
updateConfig: (t) => {
|
|
83
|
+
let n = r !== t.storageKey, i = a !== t.persist, c = s(t.defaultValue), p = l !== c, h = a;
|
|
84
|
+
if (r = t.storageKey, l = c, a = t.persist, n) {
|
|
85
|
+
if (a) {
|
|
86
|
+
let t = e(r);
|
|
87
|
+
t.status === "success" && (f = !1, o(t.value) ? (u = s(t.value), d = !0) : (u = l, d = !1)), m();
|
|
88
|
+
}
|
|
89
|
+
} else if (i) {
|
|
90
|
+
if (!h && a) {
|
|
91
|
+
let t = e(r);
|
|
92
|
+
t.status === "success" && (f = !1, o(t.value) && (u = s(t.value), d = !0, m()));
|
|
93
|
+
}
|
|
94
|
+
} else if (p && !d) {
|
|
95
|
+
if (a) {
|
|
96
|
+
let t = e(r);
|
|
97
|
+
t.status === "success" && !o(t.value) && (u = l, m());
|
|
98
|
+
} else u = l, m();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { r as createPreferenceStore };
|
|
105
|
+
|
|
106
|
+
//# sourceMappingURL=preference-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preference-store.js","names":[],"sources":["../../src/utils/preference-store.ts"],"sourcesContent":["type PreferenceConfig<T> = {\n\tstorageKey: string;\n\tdefaultValue: T;\n\tpersist: boolean;\n};\n\ntype StorageReadResult = { status: \"success\"; value: string | null } | { status: \"error\" };\n\nfunction safeGetStorageItem(key: string): StorageReadResult {\n\ttry {\n\t\tif (typeof window === \"undefined\" || !window.localStorage) {\n\t\t\treturn { status: \"error\" };\n\t\t}\n\t\tconst value = window.localStorage.getItem(key);\n\t\treturn { status: \"success\", value };\n\t} catch {\n\t\treturn { status: \"error\" };\n\t}\n}\n\nfunction safeSetStorageItem(key: string, value: string): boolean {\n\ttry {\n\t\tif (typeof window === \"undefined\" || !window.localStorage) {\n\t\t\treturn false;\n\t\t}\n\t\twindow.localStorage.setItem(key, value);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction isLocalStorageArea(area: Storage | null | undefined): boolean {\n\tif (!area) {\n\t\treturn true;\n\t}\n\ttry {\n\t\tif (typeof window !== \"undefined\" && window.localStorage) {\n\t\t\treturn area === window.localStorage;\n\t\t}\n\t} catch {\n\t\treturn false;\n\t}\n\treturn false;\n}\n\ninterface PreferenceChangeEventDetail<T> {\n\tkey: string;\n\tvalue: T;\n\twriteSucceeded: boolean;\n}\n\nexport function createPreferenceStore<T extends string>({\n\tstorageKey,\n\tdefaultValue: initialDefaultValue,\n\tpersist,\n\tisValid,\n\tnormalize,\n\teventName,\n}: PreferenceConfig<T> & {\n\tisValid: (value: unknown) => value is T;\n\tnormalize: (value: T) => T;\n\teventName: string;\n}) {\n\tlet defaultValue = normalize(initialDefaultValue);\n\tlet memoryValue = defaultValue;\n\tlet hasExplicitSelection = false;\n\tlet lastSetFailed = false;\n\n\tif (persist) {\n\t\tconst res = safeGetStorageItem(storageKey);\n\t\tif (res.status === \"success\" && isValid(res.value)) {\n\t\t\tmemoryValue = normalize(res.value);\n\t\t\thasExplicitSelection = true;\n\t\t}\n\t}\n\n\tconst listeners = new Set<() => void>();\n\tconst notify = () => {\n\t\tfor (const listener of listeners) {\n\t\t\tlistener();\n\t\t}\n\t};\n\n\tconst onInternalChange = (event: Event) => {\n\t\tif (!persist) {\n\t\t\treturn;\n\t\t}\n\t\tconst customEv = event as CustomEvent<PreferenceChangeEventDetail<T>>;\n\t\tif (!customEv.detail || customEv.detail.key !== storageKey) {\n\t\t\treturn;\n\t\t}\n\t\tconst { value, writeSucceeded } = customEv.detail;\n\t\tlastSetFailed = !writeSucceeded;\n\t\tmemoryValue = value;\n\t\thasExplicitSelection = true;\n\t\tnotify();\n\t};\n\n\tconst onStorage = (event: StorageEvent | Event) => {\n\t\tif (!persist) {\n\t\t\treturn;\n\t\t}\n\t\tconst storageEv = event as Partial<StorageEvent>;\n\t\tif (\"key\" in storageEv && storageEv.key !== undefined) {\n\t\t\tif (!isLocalStorageArea(storageEv.storageArea)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (storageEv.key !== null && storageEv.key !== storageKey) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlastSetFailed = false;\n\t\t\tconst rawValue = storageEv.newValue;\n\t\t\tif (rawValue === null || rawValue === undefined || !isValid(rawValue)) {\n\t\t\t\tmemoryValue = defaultValue;\n\t\t\t\thasExplicitSelection = false;\n\t\t\t} else {\n\t\t\t\tmemoryValue = normalize(rawValue);\n\t\t\t\thasExplicitSelection = true;\n\t\t\t}\n\t\t\tnotify();\n\t\t\treturn;\n\t\t}\n\t\t// A bare storage event must not replace a selection whose write failed.\n\t\tif (lastSetFailed) {\n\t\t\treturn;\n\t\t}\n\t\tconst res = safeGetStorageItem(storageKey);\n\t\tif (res.status === \"error\") {\n\t\t\treturn;\n\t\t}\n\t\tif (isValid(res.value)) {\n\t\t\tmemoryValue = normalize(res.value);\n\t\t\thasExplicitSelection = true;\n\t\t} else {\n\t\t\tmemoryValue = defaultValue;\n\t\t\thasExplicitSelection = false;\n\t\t}\n\t\tnotify();\n\t};\n\n\tlet cleanupStorageListener: (() => void) | null = null;\n\tconst attachStorageListener = () => {\n\t\tif (typeof window === \"undefined\") {\n\t\t\treturn;\n\t\t}\n\t\tif (listeners.size === 1 && !cleanupStorageListener) {\n\t\t\twindow.addEventListener(\"storage\", onStorage);\n\t\t\twindow.addEventListener(eventName, onInternalChange);\n\t\t\tcleanupStorageListener = () => {\n\t\t\t\twindow.removeEventListener(\"storage\", onStorage);\n\t\t\t\twindow.removeEventListener(eventName, onInternalChange);\n\t\t\t\tcleanupStorageListener = null;\n\t\t\t};\n\t\t}\n\t};\n\n\tconst detachStorageListener = () => {\n\t\tif (listeners.size === 0 && cleanupStorageListener) {\n\t\t\tcleanupStorageListener();\n\t\t}\n\t};\n\n\treturn {\n\t\tgetSnapshot: () => memoryValue,\n\t\tsubscribe: (listener: () => void) => {\n\t\t\tlisteners.add(listener);\n\t\t\tattachStorageListener();\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t\tdetachStorageListener();\n\t\t\t};\n\t\t},\n\t\tsetValue: (next: T) => {\n\t\t\tconst value = normalize(next);\n\t\t\tmemoryValue = value;\n\t\t\thasExplicitSelection = true;\n\t\t\tif (persist) {\n\t\t\t\tconst writeSucceeded = safeSetStorageItem(storageKey, value);\n\t\t\t\tlastSetFailed = !writeSucceeded;\n\t\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\twindow.dispatchEvent(\n\t\t\t\t\t\t\tnew CustomEvent<PreferenceChangeEventDetail<T>>(eventName, {\n\t\t\t\t\t\t\t\tdetail: { key: storageKey, value, writeSucceeded },\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// The local selection still applies when dispatch is unavailable.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tnotify();\n\t\t},\n\t\tupdateConfig: (config: PreferenceConfig<T>) => {\n\t\t\tconst keyChanged = storageKey !== config.storageKey;\n\t\t\tconst persistChanged = persist !== config.persist;\n\t\t\tconst normalizedDefault = normalize(config.defaultValue);\n\t\t\tconst defaultChanged = defaultValue !== normalizedDefault;\n\n\t\t\tconst oldPersist = persist;\n\t\t\tstorageKey = config.storageKey;\n\t\t\tdefaultValue = normalizedDefault;\n\t\t\tpersist = config.persist;\n\n\t\t\tif (keyChanged) {\n\t\t\t\tif (persist) {\n\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\tif (res.status === \"success\") {\n\t\t\t\t\t\tlastSetFailed = false;\n\t\t\t\t\t\tif (isValid(res.value)) {\n\t\t\t\t\t\t\tmemoryValue = normalize(res.value);\n\t\t\t\t\t\t\thasExplicitSelection = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmemoryValue = defaultValue;\n\t\t\t\t\t\t\thasExplicitSelection = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tnotify();\n\t\t\t\t}\n\t\t\t} else if (persistChanged) {\n\t\t\t\tif (!oldPersist && persist) {\n\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\tif (res.status === \"success\") {\n\t\t\t\t\t\tlastSetFailed = false;\n\t\t\t\t\t\tif (isValid(res.value)) {\n\t\t\t\t\t\t\tmemoryValue = normalize(res.value);\n\t\t\t\t\t\t\thasExplicitSelection = true;\n\t\t\t\t\t\t\tnotify();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (defaultChanged) {\n\t\t\t\tif (!hasExplicitSelection) {\n\t\t\t\t\tif (persist) {\n\t\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\t\tif (res.status === \"success\" && !isValid(res.value)) {\n\t\t\t\t\t\t\tmemoryValue = defaultValue;\n\t\t\t\t\t\t\tnotify();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmemoryValue = defaultValue;\n\t\t\t\t\t\tnotify();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -92,7 +92,7 @@ function s({ itemSelector: s, enabled: c = !0, mapGeometry: l, ref: u }) {
|
|
|
92
92
|
subtree: !0,
|
|
93
93
|
childList: !0,
|
|
94
94
|
characterData: !0,
|
|
95
|
-
attributeFilter: ["data-state"]
|
|
95
|
+
attributeFilter: ["data-state", "aria-checked"]
|
|
96
96
|
}), () => {
|
|
97
97
|
cancelAnimationFrame(t), i.disconnect(), n.disconnect();
|
|
98
98
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection-indicator.js","names":[],"sources":["../../src/utils/selection-indicator.ts"],"sourcesContent":["import * as React from \"react\";\n\nexport const SELECTION_INDICATOR_MOTION_CLASS =\n\t\"transition-[left,width,top,height] duration-200 ease-out\";\n\nexport type SelectionGeometry = {\n\tleft: number;\n\twidth: number;\n\ttop: number;\n\theight: number;\n};\n\nexport type SelectionIndicatorState = SelectionGeometry & {\n\tvisible: boolean;\n\tanimated: boolean;\n};\n\nconst EMPTY: SelectionGeometry = { left: 0, width: 0, top: 0, height: 0 };\n\nexport function assignRef<T>(ref: React.Ref<T> | undefined, value: T | null) {\n\tif (typeof ref === \"function\") {\n\t\tref(value);\n\t} else if (ref) {\n\t\t(ref as React.MutableRefObject<T | null>).current = value;\n\t}\n}\n\nexport function measureSelectionItem(item: HTMLElement): SelectionGeometry {\n\treturn {\n\t\tleft: item.offsetLeft,\n\t\twidth: item.offsetWidth,\n\t\ttop: item.offsetTop,\n\t\theight: item.offsetHeight,\n\t};\n}\n\nfunction prefersReducedMotion() {\n\treturn (\n\t\ttypeof window !== \"undefined\" && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches\n\t);\n}\n\nfunction selectionTargets(root: HTMLElement) {\n\tconst targets: HTMLElement[] = [root];\n\tfor (const node of root.children) {\n\t\tif (node instanceof HTMLElement && node.getAttribute(\"aria-hidden\") !== \"true\") {\n\t\t\ttargets.push(node);\n\t\t}\n\t}\n\treturn targets;\n}\n\nexport function useSelectionIndicator({\n\titemSelector,\n\tenabled = true,\n\tmapGeometry,\n\tref,\n}: {\n\titemSelector: string;\n\tenabled?: boolean;\n\tmapGeometry?: (item: HTMLElement, root: HTMLElement) => SelectionGeometry;\n\tref?: React.Ref<HTMLElement | null>;\n}) {\n\tconst rootRef = React.useRef<HTMLElement | null>(null);\n\tconst composedRef = React.useMemo(() => {\n\t\treturn (node: HTMLElement | null) => {\n\t\t\trootRef.current = node;\n\t\t\tassignRef(ref, node);\n\t\t};\n\t}, [ref]);\n\tconst [state, setState] = React.useState<SelectionIndicatorState>({\n\t\t...EMPTY,\n\t\tvisible: false,\n\t\tanimated: false,\n\t});\n\tconst [reduced, setReduced] = React.useState(prefersReducedMotion);\n\n\tReact.useEffect(() => {\n\t\tconst media = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n\t\tconst onChange = () => setReduced(media.matches);\n\t\tonChange();\n\t\tmedia.addEventListener(\"change\", onChange);\n\t\treturn () => media.removeEventListener(\"change\", onChange);\n\t}, []);\n\n\tconst sync = React.useCallback(() => {\n\t\tconst root = rootRef.current;\n\t\tif (!root || !enabled) {\n\t\t\tsetState((current) => ({ ...current, ...EMPTY, visible: false, animated: false }));\n\t\t\treturn;\n\t\t}\n\t\tconst item = root.querySelector<HTMLElement>(itemSelector);\n\t\tif (!item) {\n\t\t\tsetState((current) => ({ ...current, width: 0, height: 0, visible: false, animated: false }));\n\t\t\treturn;\n\t\t}\n\t\t// Keep the optional dependency undefined. Production optimizers may inline a\n\t\t// function-valued parameter default, creating a new effect dependency every render.\n\t\tconst geometry = (mapGeometry ?? measureSelectionItem)(item, root);\n\t\tsetState((current) => ({\n\t\t\t...geometry,\n\t\t\tvisible: true,\n\t\t\tanimated: current.visible && !reduced,\n\t\t}));\n\t}, [enabled, itemSelector, mapGeometry, reduced]);\n\n\tReact.useLayoutEffect(() => {\n\t\tconst root = rootRef.current;\n\t\tif (!root || !enabled) {\n\t\t\treturn;\n\t\t}\n\t\tlet frame = 0;\n\t\tconst ro = new ResizeObserver(() => {\n\t\t\tcancelAnimationFrame(frame);\n\t\t\tframe = requestAnimationFrame(sync);\n\t\t});\n\t\tconst observe = () => {\n\t\t\tro.disconnect();\n\t\t\tfor (const node of selectionTargets(root)) {\n\t\t\t\tro.observe(node);\n\t\t\t}\n\t\t};\n\t\tobserve();\n\t\tsync();\n\t\tconst mo = new MutationObserver(() => {\n\t\t\tcancelAnimationFrame(frame);\n\t\t\tframe = requestAnimationFrame(() => {\n\t\t\t\tobserve();\n\t\t\t\tsync();\n\t\t\t});\n\t\t});\n\t\tmo.observe(root, {\n\t\t\tattributes: true,\n\t\t\tsubtree: true,\n\t\t\tchildList: true,\n\t\t\tcharacterData: true,\n\t\t\tattributeFilter: [\"data-state\"],\n\t\t});\n\t\treturn () => {\n\t\t\tcancelAnimationFrame(frame);\n\t\t\tmo.disconnect();\n\t\t\tro.disconnect();\n\t\t};\n\t}, [enabled, sync]);\n\n\treturn {\n\t\tref: composedRef,\n\t\tstate,\n\t\tmotionClassName: state.animated && !reduced ? SELECTION_INDICATOR_MOTION_CLASS : undefined,\n\t};\n}\n"],"mappings":";;;AAEA,IAAa,IACZ,4DAcK,IAA2B;CAAE,MAAM;CAAG,OAAO;CAAG,KAAK;CAAG,QAAQ;AAAE;AAExE,SAAgB,EAAa,GAA+B,GAAiB;CAC5E,AAAI,OAAO,KAAQ,aAClB,EAAI,CAAK,IACC,MACV,EAA0C,UAAU;AAEtD;AAEA,SAAgB,EAAqB,GAAsC;CAC1E,OAAO;EACN,MAAM,EAAK;EACX,OAAO,EAAK;EACZ,KAAK,EAAK;EACV,QAAQ,EAAK;CACd;AACD;AAEA,SAAS,IAAuB;CAC/B,OACC,OAAO,SAAW,OAAe,OAAO,WAAW,kCAAkC,CAAC,CAAC;AAEzF;AAEA,SAAS,EAAiB,GAAmB;CAC5C,IAAM,IAAyB,CAAC,CAAI;CACpC,KAAK,IAAM,KAAQ,EAAK,UACvB,AAAI,aAAgB,eAAe,EAAK,aAAa,aAAa,MAAM,UACvE,EAAQ,KAAK,CAAI;CAGnB,OAAO;AACR;AAEA,SAAgB,EAAsB,EACrC,iBACA,aAAU,IACV,gBACA,UAME;CACF,IAAM,IAAU,EAAM,OAA2B,IAAI,GAC/C,IAAc,EAAM,eACjB,MAA6B;EAEpC,AADA,EAAQ,UAAU,GAClB,EAAU,GAAK,CAAI;CACpB,GACE,CAAC,CAAG,CAAC,GACF,CAAC,GAAO,KAAY,EAAM,SAAkC;EACjE,GAAG;EACH,SAAS;EACT,UAAU;CACX,CAAC,GACK,CAAC,GAAS,KAAc,EAAM,SAAS,CAAoB;CAEjE,EAAM,gBAAgB;EACrB,IAAM,IAAQ,OAAO,WAAW,kCAAkC,GAC5D,UAAiB,EAAW,EAAM,OAAO;EAG/C,OAFA,EAAS,GACT,EAAM,iBAAiB,UAAU,CAAQ,SAC5B,EAAM,oBAAoB,UAAU,CAAQ;CAC1D,GAAG,CAAC,CAAC;CAEL,IAAM,IAAO,EAAM,kBAAkB;EACpC,IAAM,IAAO,EAAQ;EACrB,IAAI,CAAC,KAAQ,CAAC,GAAS;GACtB,GAAU,OAAa;IAAE,GAAG;IAAS,GAAG;IAAO,SAAS;IAAO,UAAU;GAAM,EAAE;GACjF;EACD;EACA,IAAM,IAAO,EAAK,cAA2B,CAAY;EACzD,IAAI,CAAC,GAAM;GACV,GAAU,OAAa;IAAE,GAAG;IAAS,OAAO;IAAG,QAAQ;IAAG,SAAS;IAAO,UAAU;GAAM,EAAE;GAC5F;EACD;EAGA,IAAM,KAAY,KAAe,EAAA,CAAsB,GAAM,CAAI;EACjE,GAAU,OAAa;GACtB,GAAG;GACH,SAAS;GACT,UAAU,EAAQ,WAAW,CAAC;EAC/B,EAAE;CACH,GAAG;EAAC;EAAS;EAAc;EAAa;CAAO,CAAC;CAyChD,OAvCA,EAAM,sBAAsB;EAC3B,IAAM,IAAO,EAAQ;EACrB,IAAI,CAAC,KAAQ,CAAC,GACb;EAED,IAAI,IAAQ,GACN,IAAK,IAAI,qBAAqB;GAEnC,AADA,qBAAqB,CAAK,GAC1B,IAAQ,sBAAsB,CAAI;EACnC,CAAC,GACK,UAAgB;GACrB,EAAG,WAAW;GACd,KAAK,IAAM,KAAQ,EAAiB,CAAI,GACvC,EAAG,QAAQ,CAAI;EAEjB;EAEA,AADA,EAAQ,GACR,EAAK;EACL,IAAM,IAAK,IAAI,uBAAuB;GAErC,AADA,qBAAqB,CAAK,GAC1B,IAAQ,4BAA4B;IAEnC,AADA,EAAQ,GACR,EAAK;GACN,CAAC;EACF,CAAC;EAQD,OAPA,EAAG,QAAQ,GAAM;GAChB,YAAY;GACZ,SAAS;GACT,WAAW;GACX,eAAe;GACf,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"selection-indicator.js","names":[],"sources":["../../src/utils/selection-indicator.ts"],"sourcesContent":["import * as React from \"react\";\n\nexport const SELECTION_INDICATOR_MOTION_CLASS =\n\t\"transition-[left,width,top,height] duration-200 ease-out\";\n\nexport type SelectionGeometry = {\n\tleft: number;\n\twidth: number;\n\ttop: number;\n\theight: number;\n};\n\nexport type SelectionIndicatorState = SelectionGeometry & {\n\tvisible: boolean;\n\tanimated: boolean;\n};\n\nconst EMPTY: SelectionGeometry = { left: 0, width: 0, top: 0, height: 0 };\n\nexport function assignRef<T>(ref: React.Ref<T> | undefined, value: T | null) {\n\tif (typeof ref === \"function\") {\n\t\tref(value);\n\t} else if (ref) {\n\t\t(ref as React.MutableRefObject<T | null>).current = value;\n\t}\n}\n\nexport function measureSelectionItem(item: HTMLElement): SelectionGeometry {\n\treturn {\n\t\tleft: item.offsetLeft,\n\t\twidth: item.offsetWidth,\n\t\ttop: item.offsetTop,\n\t\theight: item.offsetHeight,\n\t};\n}\n\nfunction prefersReducedMotion() {\n\treturn (\n\t\ttypeof window !== \"undefined\" && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches\n\t);\n}\n\nfunction selectionTargets(root: HTMLElement) {\n\tconst targets: HTMLElement[] = [root];\n\tfor (const node of root.children) {\n\t\tif (node instanceof HTMLElement && node.getAttribute(\"aria-hidden\") !== \"true\") {\n\t\t\ttargets.push(node);\n\t\t}\n\t}\n\treturn targets;\n}\n\nexport function useSelectionIndicator({\n\titemSelector,\n\tenabled = true,\n\tmapGeometry,\n\tref,\n}: {\n\titemSelector: string;\n\tenabled?: boolean;\n\tmapGeometry?: (item: HTMLElement, root: HTMLElement) => SelectionGeometry;\n\tref?: React.Ref<HTMLElement | null>;\n}) {\n\tconst rootRef = React.useRef<HTMLElement | null>(null);\n\tconst composedRef = React.useMemo(() => {\n\t\treturn (node: HTMLElement | null) => {\n\t\t\trootRef.current = node;\n\t\t\tassignRef(ref, node);\n\t\t};\n\t}, [ref]);\n\tconst [state, setState] = React.useState<SelectionIndicatorState>({\n\t\t...EMPTY,\n\t\tvisible: false,\n\t\tanimated: false,\n\t});\n\tconst [reduced, setReduced] = React.useState(prefersReducedMotion);\n\n\tReact.useEffect(() => {\n\t\tconst media = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n\t\tconst onChange = () => setReduced(media.matches);\n\t\tonChange();\n\t\tmedia.addEventListener(\"change\", onChange);\n\t\treturn () => media.removeEventListener(\"change\", onChange);\n\t}, []);\n\n\tconst sync = React.useCallback(() => {\n\t\tconst root = rootRef.current;\n\t\tif (!root || !enabled) {\n\t\t\tsetState((current) => ({ ...current, ...EMPTY, visible: false, animated: false }));\n\t\t\treturn;\n\t\t}\n\t\tconst item = root.querySelector<HTMLElement>(itemSelector);\n\t\tif (!item) {\n\t\t\tsetState((current) => ({ ...current, width: 0, height: 0, visible: false, animated: false }));\n\t\t\treturn;\n\t\t}\n\t\t// Keep the optional dependency undefined. Production optimizers may inline a\n\t\t// function-valued parameter default, creating a new effect dependency every render.\n\t\tconst geometry = (mapGeometry ?? measureSelectionItem)(item, root);\n\t\tsetState((current) => ({\n\t\t\t...geometry,\n\t\t\tvisible: true,\n\t\t\tanimated: current.visible && !reduced,\n\t\t}));\n\t}, [enabled, itemSelector, mapGeometry, reduced]);\n\n\tReact.useLayoutEffect(() => {\n\t\tconst root = rootRef.current;\n\t\tif (!root || !enabled) {\n\t\t\treturn;\n\t\t}\n\t\tlet frame = 0;\n\t\tconst ro = new ResizeObserver(() => {\n\t\t\tcancelAnimationFrame(frame);\n\t\t\tframe = requestAnimationFrame(sync);\n\t\t});\n\t\tconst observe = () => {\n\t\t\tro.disconnect();\n\t\t\tfor (const node of selectionTargets(root)) {\n\t\t\t\tro.observe(node);\n\t\t\t}\n\t\t};\n\t\tobserve();\n\t\tsync();\n\t\tconst mo = new MutationObserver(() => {\n\t\t\tcancelAnimationFrame(frame);\n\t\t\tframe = requestAnimationFrame(() => {\n\t\t\t\tobserve();\n\t\t\t\tsync();\n\t\t\t});\n\t\t});\n\t\tmo.observe(root, {\n\t\t\tattributes: true,\n\t\t\tsubtree: true,\n\t\t\tchildList: true,\n\t\t\tcharacterData: true,\n\t\t\tattributeFilter: [\"data-state\", \"aria-checked\"],\n\t\t});\n\t\treturn () => {\n\t\t\tcancelAnimationFrame(frame);\n\t\t\tmo.disconnect();\n\t\t\tro.disconnect();\n\t\t};\n\t}, [enabled, sync]);\n\n\treturn {\n\t\tref: composedRef,\n\t\tstate,\n\t\tmotionClassName: state.animated && !reduced ? SELECTION_INDICATOR_MOTION_CLASS : undefined,\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export declare function useCheckableGroup({ value, defaultValue, onValueChange, error, describedBy, ariaInvalid, form, ref, }: {
|
|
3
|
+
value?: string[];
|
|
4
|
+
defaultValue?: string[];
|
|
5
|
+
onValueChange?: (value: string[]) => void;
|
|
6
|
+
error?: React.ReactNode;
|
|
7
|
+
describedBy?: string;
|
|
8
|
+
ariaInvalid?: React.AriaAttributes["aria-invalid"];
|
|
9
|
+
form?: string;
|
|
10
|
+
ref: React.ForwardedRef<HTMLFieldSetElement>;
|
|
11
|
+
}): {
|
|
12
|
+
current: string[];
|
|
13
|
+
setValue: (next: string[]) => void;
|
|
14
|
+
invalid: boolean;
|
|
15
|
+
errorId: string;
|
|
16
|
+
mergedDescribedBy: string | undefined;
|
|
17
|
+
setRefs: (node: HTMLFieldSetElement | null) => (() => void) | undefined;
|
|
18
|
+
ariaInvalid: "false" | "grammar" | "spelling" | "true" | boolean | undefined;
|
|
19
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as e from "react";
|
|
3
|
+
//#region src/utils/use-checkable-group.ts
|
|
4
|
+
function t({ value: t, defaultValue: n, onValueChange: r, error: i, describedBy: a, ariaInvalid: o, form: s, ref: c }) {
|
|
5
|
+
let l = e.useId(), u = e.useRef(null), [d, f] = e.useState(n ?? []), p = t ?? d, m = !!i, h = `${l}-error`, g = [m ? h : null, a].filter(Boolean).join(" ") || void 0, _ = e.useRef(null), v = e.useCallback((e) => {
|
|
6
|
+
let n = _.current;
|
|
7
|
+
n && n.eventPhase !== Event.NONE || (t === void 0 && f(e), r?.(e));
|
|
8
|
+
}, [r, t]), y = e.useCallback((e) => {
|
|
9
|
+
if (u.current = e, c) {
|
|
10
|
+
if (typeof c == "function") {
|
|
11
|
+
let t = c(e);
|
|
12
|
+
return typeof t == "function" ? () => {
|
|
13
|
+
u.current = null, t();
|
|
14
|
+
} : () => {
|
|
15
|
+
u.current = null, c(null);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return c.current = e, () => {
|
|
19
|
+
u.current = null, c.current = null;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}, [c]), b = e.useRef({
|
|
23
|
+
defaultValue: n,
|
|
24
|
+
value: t
|
|
25
|
+
});
|
|
26
|
+
return e.useEffect(() => {
|
|
27
|
+
b.current = {
|
|
28
|
+
defaultValue: n,
|
|
29
|
+
value: t
|
|
30
|
+
};
|
|
31
|
+
}), e.useEffect(() => {
|
|
32
|
+
let e = u.current?.form;
|
|
33
|
+
if (!e || s && e.id !== s) return;
|
|
34
|
+
let t = !1, n = /* @__PURE__ */ new Set(), r = (e) => {
|
|
35
|
+
_.current = e;
|
|
36
|
+
let r = setTimeout(() => {
|
|
37
|
+
if (n.delete(r), t || e.defaultPrevented) return;
|
|
38
|
+
let i = b.current;
|
|
39
|
+
i.value === void 0 && f(i.defaultValue ?? []);
|
|
40
|
+
}, 0);
|
|
41
|
+
n.add(r);
|
|
42
|
+
};
|
|
43
|
+
return e.addEventListener("reset", r, !0), () => {
|
|
44
|
+
t = !0, _.current = null;
|
|
45
|
+
for (let e of n) clearTimeout(e);
|
|
46
|
+
n.clear(), e.removeEventListener("reset", r, !0);
|
|
47
|
+
};
|
|
48
|
+
}, [s]), {
|
|
49
|
+
current: p,
|
|
50
|
+
setValue: v,
|
|
51
|
+
invalid: m,
|
|
52
|
+
errorId: h,
|
|
53
|
+
mergedDescribedBy: g,
|
|
54
|
+
setRefs: y,
|
|
55
|
+
ariaInvalid: m ? !0 : o
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { t as useCheckableGroup };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=use-checkable-group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-checkable-group.js","names":[],"sources":["../../src/utils/use-checkable-group.ts"],"sourcesContent":["import * as React from \"react\";\n\nexport function useCheckableGroup({\n\tvalue,\n\tdefaultValue,\n\tonValueChange,\n\terror,\n\tdescribedBy,\n\tariaInvalid,\n\tform,\n\tref,\n}: {\n\tvalue?: string[];\n\tdefaultValue?: string[];\n\tonValueChange?: (value: string[]) => void;\n\terror?: React.ReactNode;\n\tdescribedBy?: string;\n\tariaInvalid?: React.AriaAttributes[\"aria-invalid\"];\n\tform?: string;\n\tref: React.ForwardedRef<HTMLFieldSetElement>;\n}) {\n\tconst generatedId = React.useId();\n\tconst nodeRef = React.useRef<HTMLFieldSetElement | null>(null);\n\tconst [uncontrolled, setUncontrolled] = React.useState(defaultValue ?? []);\n\tconst current = value ?? uncontrolled;\n\tconst invalid = Boolean(error);\n\tconst errorId = `${generatedId}-error`;\n\tconst mergedDescribedBy =\n\t\t[invalid ? errorId : null, describedBy].filter(Boolean).join(\" \") || undefined;\n\tconst resetEventRef = React.useRef<Event | null>(null);\n\tconst setValue = React.useCallback(\n\t\t(next: string[]) => {\n\t\t\tconst activeReset = resetEventRef.current;\n\t\t\tif (activeReset && activeReset.eventPhase !== Event.NONE) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (value === undefined) {\n\t\t\t\tsetUncontrolled(next);\n\t\t\t}\n\t\t\tonValueChange?.(next);\n\t\t},\n\t\t[onValueChange, value],\n\t);\n\tconst setRefs = React.useCallback(\n\t\t(node: HTMLFieldSetElement | null) => {\n\t\t\tnodeRef.current = node;\n\t\t\tif (!ref) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (typeof ref === \"function\") {\n\t\t\t\tconst cleanup = (ref as React.RefCallback<HTMLFieldSetElement>)(node);\n\t\t\t\tif (typeof cleanup === \"function\") {\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tnodeRef.current = null;\n\t\t\t\t\t\tcleanup();\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn () => {\n\t\t\t\t\tnodeRef.current = null;\n\t\t\t\t\tref(null);\n\t\t\t\t};\n\t\t\t}\n\t\t\t(ref as React.RefObject<HTMLFieldSetElement | null>).current = node;\n\t\t\treturn () => {\n\t\t\t\tnodeRef.current = null;\n\t\t\t\t(ref as React.RefObject<HTMLFieldSetElement | null>).current = null;\n\t\t\t};\n\t\t},\n\t\t[ref],\n\t);\n\tconst latestConfigRef = React.useRef({\n\t\tdefaultValue,\n\t\tvalue,\n\t});\n\tReact.useEffect(() => {\n\t\tlatestConfigRef.current = {\n\t\t\tdefaultValue,\n\t\t\tvalue,\n\t\t};\n\t});\n\n\tReact.useEffect(() => {\n\t\tconst formEl = nodeRef.current?.form;\n\t\tif (!formEl || (form && formEl.id !== form)) {\n\t\t\treturn;\n\t\t}\n\t\tlet disposed = false;\n\t\tconst timers = new Set<ReturnType<typeof setTimeout>>();\n\t\tconst onReset = (event: Event) => {\n\t\t\tresetEventRef.current = event;\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\ttimers.delete(timer);\n\t\t\t\tif (disposed || event.defaultPrevented) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst cfg = latestConfigRef.current;\n\t\t\t\tif (cfg.value === undefined) {\n\t\t\t\t\tsetUncontrolled(cfg.defaultValue ?? []);\n\t\t\t\t}\n\t\t\t}, 0);\n\t\t\ttimers.add(timer);\n\t\t};\n\t\tformEl.addEventListener(\"reset\", onReset, true);\n\t\treturn () => {\n\t\t\tdisposed = true;\n\t\t\tresetEventRef.current = null;\n\t\t\tfor (const timer of timers) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t}\n\t\t\ttimers.clear();\n\t\t\tformEl.removeEventListener(\"reset\", onReset, true);\n\t\t};\n\t}, [form]);\n\n\treturn {\n\t\tcurrent,\n\t\tsetValue,\n\t\tinvalid,\n\t\terrorId,\n\t\tmergedDescribedBy,\n\t\tsetRefs,\n\t\tariaInvalid: invalid ? true : ariaInvalid,\n\t};\n}\n"],"mappings":";;;AAEA,SAAgB,EAAkB,EACjC,UACA,iBACA,kBACA,UACA,gBACA,gBACA,SACA,UAUE;CACF,IAAM,IAAc,EAAM,MAAM,GAC1B,IAAU,EAAM,OAAmC,IAAI,GACvD,CAAC,GAAc,KAAmB,EAAM,SAAS,KAAgB,CAAC,CAAC,GACnE,IAAU,KAAS,GACnB,IAAU,EAAQ,GAClB,IAAU,GAAG,EAAY,SACzB,IACL,CAAC,IAAU,IAAU,MAAM,CAAW,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA,GAChE,IAAgB,EAAM,OAAqB,IAAI,GAC/C,IAAW,EAAM,aACrB,MAAmB;EACnB,IAAM,IAAc,EAAc;EAC9B,KAAe,EAAY,eAAe,MAAM,SAGhD,MAAU,KAAA,KACb,EAAgB,CAAI,GAErB,IAAgB,CAAI;CACrB,GACA,CAAC,GAAe,CAAK,CACtB,GACM,IAAU,EAAM,aACpB,MAAqC;EACrC,MAAQ,UAAU,GACb,GAGL;OAAI,OAAO,KAAQ,YAAY;IAC9B,IAAM,IAAW,EAA+C,CAAI;IAOpE,OANI,OAAO,KAAY,mBACT;KAEZ,AADA,EAAQ,UAAU,MAClB,EAAQ;IACT,UAEY;KAEZ,AADA,EAAQ,UAAU,MAClB,EAAI,IAAI;IACT;GACD;GAEA,OADA,EAAqD,UAAU,SAClD;IAEZ,AADA,EAAQ,UAAU,MAClB,EAAqD,UAAU;GAChE;EALA;CAMD,GACA,CAAC,CAAG,CACL,GACM,IAAkB,EAAM,OAAO;EACpC;EACA;CACD,CAAC;CAyCD,OAxCA,EAAM,gBAAgB;EACrB,EAAgB,UAAU;GACzB;GACA;EACD;CACD,CAAC,GAED,EAAM,gBAAgB;EACrB,IAAM,IAAS,EAAQ,SAAS;EAChC,IAAI,CAAC,KAAW,KAAQ,EAAO,OAAO,GACrC;EAED,IAAI,IAAW,IACT,oBAAS,IAAI,IAAmC,GAChD,KAAW,MAAiB;GACjC,EAAc,UAAU;GACxB,IAAM,IAAQ,iBAAiB;IAE9B,IADA,EAAO,OAAO,CAAK,GACf,KAAY,EAAM,kBACrB;IAED,IAAM,IAAM,EAAgB;IAC5B,AAAI,EAAI,UAAU,KAAA,KACjB,EAAgB,EAAI,gBAAgB,CAAC,CAAC;GAExC,GAAG,CAAC;GACJ,EAAO,IAAI,CAAK;EACjB;EAEA,OADA,EAAO,iBAAiB,SAAS,GAAS,EAAI,SACjC;GAEZ,AADA,IAAW,IACX,EAAc,UAAU;GACxB,KAAK,IAAM,KAAS,GACnB,aAAa,CAAK;GAGnB,AADA,EAAO,MAAM,GACb,EAAO,oBAAoB,SAAS,GAAS,EAAI;EAClD;CACD,GAAG,CAAC,CAAI,CAAC,GAEF;EACN;EACA;EACA;EACA;EACA;EACA;EACA,aAAa,IAAU,KAAO;CAC/B;AACD"}
|