@omerdlw/base-framework 1.0.6 → 2.0.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/dist/atoms/index.js +1 -103
- package/dist/atoms/index.js.map +1 -1
- package/dist/chunk-3BUP64Q6.js +105 -0
- package/dist/chunk-3BUP64Q6.js.map +1 -0
- package/dist/chunk-3MSK4XGK.js +9888 -0
- package/dist/chunk-3MSK4XGK.js.map +1 -0
- package/dist/chunk-4GMQKD6F.js +353 -0
- package/dist/chunk-4GMQKD6F.js.map +1 -0
- package/dist/chunk-65ZB4QTQ.js +888 -0
- package/dist/chunk-65ZB4QTQ.js.map +1 -0
- package/dist/chunk-6SG7V77J.js +577 -0
- package/dist/chunk-6SG7V77J.js.map +1 -0
- package/dist/chunk-7HQMXTNP.js +419 -0
- package/dist/chunk-7HQMXTNP.js.map +1 -0
- package/dist/chunk-7TAVYJ3A.js +371 -0
- package/dist/chunk-7TAVYJ3A.js.map +1 -0
- package/dist/chunk-AQ4BNXA2.js +349 -0
- package/dist/chunk-AQ4BNXA2.js.map +1 -0
- package/dist/chunk-CGHZSSFR.js +2166 -0
- package/dist/chunk-CGHZSSFR.js.map +1 -0
- package/dist/chunk-DGCQWQLZ.js +61 -0
- package/dist/chunk-DGCQWQLZ.js.map +1 -0
- package/dist/chunk-FIMPHODX.js +67 -0
- package/dist/chunk-FIMPHODX.js.map +1 -0
- package/dist/chunk-GF7TUX5I.js +1889 -0
- package/dist/chunk-GF7TUX5I.js.map +1 -0
- package/dist/chunk-JELG4JLT.js +454 -0
- package/dist/chunk-JELG4JLT.js.map +1 -0
- package/dist/chunk-K676GL7Z.js +51 -0
- package/dist/chunk-K676GL7Z.js.map +1 -0
- package/dist/chunk-KKQT46TP.js +26 -0
- package/dist/chunk-KKQT46TP.js.map +1 -0
- package/dist/chunk-QI3ALLIB.js +38 -0
- package/dist/chunk-QI3ALLIB.js.map +1 -0
- package/dist/chunk-QXR55VVS.js +1139 -0
- package/dist/chunk-QXR55VVS.js.map +1 -0
- package/dist/chunk-R2YGFJDJ.js +408 -0
- package/dist/chunk-R2YGFJDJ.js.map +1 -0
- package/dist/chunk-RFZQWLC5.js +27 -0
- package/dist/chunk-RFZQWLC5.js.map +1 -0
- package/dist/chunk-SYAVGTOX.js +521 -0
- package/dist/chunk-SYAVGTOX.js.map +1 -0
- package/dist/chunk-TV3WEF5G.js +784 -0
- package/dist/chunk-TV3WEF5G.js.map +1 -0
- package/dist/chunk-XASQT4CQ.js +280 -0
- package/dist/chunk-XASQT4CQ.js.map +1 -0
- package/dist/error/index.js +5 -682
- package/dist/error/index.js.map +1 -1
- package/dist/error/reporter.d.ts.map +1 -1
- package/dist/error/theme.d.ts +1 -1
- package/dist/error/theme.d.ts.map +1 -1
- package/dist/events.js +1 -7
- package/dist/events.js.map +1 -1
- package/dist/hooks/index.js +1 -358
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/use-global-event.d.ts +1 -1
- package/dist/index.js +18 -20029
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.js +2 -2035
- package/dist/kernel/index.js.map +1 -1
- package/dist/kernel/types.d.ts +1 -1
- package/dist/modules/ambient/analyze.d.ts +46 -0
- package/dist/modules/ambient/analyze.d.ts.map +1 -0
- package/dist/modules/ambient/constants.d.ts +1 -5
- package/dist/modules/ambient/constants.d.ts.map +1 -1
- package/dist/modules/ambient/context.d.ts.map +1 -1
- package/dist/modules/ambient/dom.d.ts +11 -12
- package/dist/modules/ambient/dom.d.ts.map +1 -1
- package/dist/modules/ambient/extractor.d.ts +10 -10
- package/dist/modules/ambient/extractor.d.ts.map +1 -1
- package/dist/modules/ambient/hooks.d.ts +1 -1
- package/dist/modules/ambient/hooks.d.ts.map +1 -1
- package/dist/modules/ambient/index.d.ts +6 -4
- package/dist/modules/ambient/index.d.ts.map +1 -1
- package/dist/modules/ambient/index.js +7 -762
- package/dist/modules/ambient/index.js.map +1 -1
- package/dist/modules/ambient/module.d.ts +1 -1
- package/dist/modules/ambient/module.d.ts.map +1 -1
- package/dist/modules/ambient/oklab.d.ts +36 -0
- package/dist/modules/ambient/oklab.d.ts.map +1 -0
- package/dist/modules/ambient/pipeline.d.ts +28 -0
- package/dist/modules/ambient/pipeline.d.ts.map +1 -0
- package/dist/modules/ambient/quantize.d.ts +22 -0
- package/dist/modules/ambient/quantize.d.ts.map +1 -0
- package/dist/modules/ambient/server/address.d.ts +8 -0
- package/dist/modules/ambient/server/address.d.ts.map +1 -0
- package/dist/modules/ambient/server/index.d.ts +53 -0
- package/dist/modules/ambient/server/index.d.ts.map +1 -0
- package/dist/modules/ambient/server/index.js +221 -0
- package/dist/modules/ambient/server/index.js.map +1 -0
- package/dist/modules/ambient/settings.d.ts +19 -0
- package/dist/modules/ambient/settings.d.ts.map +1 -0
- package/dist/modules/ambient/types.d.ts +105 -9
- package/dist/modules/ambient/types.d.ts.map +1 -1
- package/dist/modules/ambient/worker/index.d.ts +15 -0
- package/dist/modules/ambient/worker/index.d.ts.map +1 -0
- package/dist/modules/ambient/worker/index.js +114 -0
- package/dist/modules/ambient/worker/index.js.map +1 -0
- package/dist/modules/background/constants.d.ts +2 -2
- package/dist/modules/background/constants.d.ts.map +1 -1
- package/dist/modules/background/hooks.d.ts +1 -1
- package/dist/modules/background/index.js +6 -3078
- package/dist/modules/background/index.js.map +1 -1
- package/dist/modules/background/motion.d.ts +9 -7
- package/dist/modules/background/motion.d.ts.map +1 -1
- package/dist/modules/background/overlay.d.ts +3 -8
- package/dist/modules/background/overlay.d.ts.map +1 -1
- package/dist/modules/background/types.d.ts +16 -2
- package/dist/modules/background/types.d.ts.map +1 -1
- package/dist/modules/context-menu/constants.d.ts +2 -2
- package/dist/modules/context-menu/constants.d.ts.map +1 -1
- package/dist/modules/context-menu/hooks.d.ts +1 -1
- package/dist/modules/context-menu/index.js +10 -1896
- package/dist/modules/context-menu/index.js.map +1 -1
- package/dist/modules/context-menu/motion.d.ts +1 -8
- package/dist/modules/context-menu/motion.d.ts.map +1 -1
- package/dist/modules/context-menu/overlay.d.ts.map +1 -1
- package/dist/modules/context-menu/types.d.ts +16 -2
- package/dist/modules/context-menu/types.d.ts.map +1 -1
- package/dist/modules/controls/constants.d.ts +1 -1
- package/dist/modules/controls/constants.d.ts.map +1 -1
- package/dist/modules/controls/entries.d.ts +1 -1
- package/dist/modules/controls/hooks.d.ts +1 -1
- package/dist/modules/controls/index.js +4 -1110
- package/dist/modules/controls/index.js.map +1 -1
- package/dist/modules/controls/overlay.d.ts +1 -1
- package/dist/modules/controls/types.d.ts +2 -2
- package/dist/modules/dock/cards.d.ts +708 -24
- package/dist/modules/dock/cards.d.ts.map +1 -1
- package/dist/modules/dock/constants.d.ts +2 -2
- package/dist/modules/dock/constants.d.ts.map +1 -1
- package/dist/modules/dock/helpers.d.ts +2 -2
- package/dist/modules/dock/hooks.d.ts +2 -2
- package/dist/modules/dock/index.d.ts +1 -1
- package/dist/modules/dock/index.d.ts.map +1 -1
- package/dist/modules/dock/index.js +9 -12132
- package/dist/modules/dock/index.js.map +1 -1
- package/dist/modules/dock/module.d.ts +1 -1
- package/dist/modules/dock/motion.d.ts +41 -915
- package/dist/modules/dock/motion.d.ts.map +1 -1
- package/dist/modules/dock/overlay.d.ts.map +1 -1
- package/dist/modules/dock/runtime/dock.d.ts +1 -23
- package/dist/modules/dock/runtime/dock.d.ts.map +1 -1
- package/dist/modules/dock/styles.d.ts +4 -4
- package/dist/modules/dock/surface/hooks.d.ts +5 -20
- package/dist/modules/dock/surface/hooks.d.ts.map +1 -1
- package/dist/modules/dock/surface/machine.d.ts +4 -3
- package/dist/modules/dock/surface/machine.d.ts.map +1 -1
- package/dist/modules/dock/surface/stack.d.ts.map +1 -1
- package/dist/modules/dock/types.d.ts +158 -3
- package/dist/modules/dock/types.d.ts.map +1 -1
- package/dist/modules/index.js +16 -17883
- package/dist/modules/index.js.map +1 -1
- package/dist/modules/loading/constants.d.ts +1 -1
- package/dist/modules/loading/constants.d.ts.map +1 -1
- package/dist/modules/loading/context.d.ts +1 -1
- package/dist/modules/loading/hooks.d.ts +1 -1
- package/dist/modules/loading/index.js +5 -1153
- package/dist/modules/loading/index.js.map +1 -1
- package/dist/modules/loading/types.d.ts +2 -2
- package/dist/modules/media/context.d.ts +1 -1
- package/dist/modules/media/index.js +3 -570
- package/dist/modules/media/index.js.map +1 -1
- package/dist/modules/media/types.d.ts +2 -2
- package/dist/modules/modal/constants.d.ts +2 -2
- package/dist/modules/modal/constants.d.ts.map +1 -1
- package/dist/modules/modal/context.d.ts +1 -1
- package/dist/modules/modal/hooks.d.ts +3 -3
- package/dist/modules/modal/index.js +8 -2355
- package/dist/modules/modal/index.js.map +1 -1
- package/dist/modules/modal/motion.d.ts +3 -8
- package/dist/modules/modal/motion.d.ts.map +1 -1
- package/dist/modules/modal/overlay.d.ts.map +1 -1
- package/dist/modules/modal/types.d.ts +21 -0
- package/dist/modules/modal/types.d.ts.map +1 -1
- package/dist/modules/notification/constants.d.ts +2 -2
- package/dist/modules/notification/constants.d.ts.map +1 -1
- package/dist/modules/notification/context.d.ts +1 -1
- package/dist/modules/notification/hooks.d.ts +1 -1
- package/dist/modules/notification/index.js +4 -828
- package/dist/modules/notification/index.js.map +1 -1
- package/dist/modules/notification/motion.d.ts +1 -7
- package/dist/modules/notification/motion.d.ts.map +1 -1
- package/dist/modules/notification/overlay.d.ts.map +1 -1
- package/dist/modules/notification/types.d.ts +9 -1
- package/dist/modules/notification/types.d.ts.map +1 -1
- package/dist/overlay-TZ6L52A5.js +9 -0
- package/dist/overlay-TZ6L52A5.js.map +1 -0
- package/dist/provider.d.ts +1 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +6 -1968
- package/dist/provider.js.map +1 -1
- package/dist/result.js +2 -63
- package/dist/result.js.map +1 -1
- package/dist/theme.d.ts +45 -8
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +3 -41
- package/dist/theme.js.map +1 -1
- package/dist/tokens/index.d.ts +1 -0
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +126 -155
- package/dist/tokens/index.js.map +1 -1
- package/dist/tokens/motion-config.d.ts +44 -0
- package/dist/tokens/motion-config.d.ts.map +1 -0
- package/dist/tokens/motion.d.ts +23 -174
- package/dist/tokens/motion.d.ts.map +1 -1
- package/dist/utils/index.js +4 -82
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/report.d.ts.map +1 -1
- package/docs/README.md +1 -0
- package/docs/architecture-and-rules.md +4 -3
- package/docs/core-engine.md +7 -10
- package/docs/getting-started.md +4 -2
- package/docs/modules/ambient.md +194 -80
- package/docs/modules/background.md +3 -3
- package/docs/modules/context-menu.md +2 -2
- package/docs/modules/dock.md +8 -5
- package/docs/modules/modal.md +2 -2
- package/docs/modules/notification.md +2 -2
- package/docs/theming.md +81 -9
- package/package.json +22 -5
- package/templates/AGENTS.md +1 -1
- package/templates/motion/background.ts +17 -0
- package/templates/motion/context-menu.ts +63 -0
- package/templates/motion/dock.ts +327 -0
- package/templates/motion/modal.ts +79 -0
- package/templates/motion/notification.ts +27 -0
- package/templates/motion/tokens.ts +47 -0
- package/templates/tsconfig.json +7 -0
- package/dist/modules/ambient/color.d.ts +0 -21
- package/dist/modules/ambient/color.d.ts.map +0 -1
|
@@ -0,0 +1,784 @@
|
|
|
1
|
+
import { useLayoutEffect, useEffect, use, useRef, useCallback, useSyncExternalStore, useState } from 'react';
|
|
2
|
+
import { clsx } from 'clsx';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
|
+
|
|
5
|
+
function useRequiredContext(context, hookName, providerName) {
|
|
6
|
+
const value = use(context);
|
|
7
|
+
if (value === null) {
|
|
8
|
+
throw new Error(`${hookName} must be used within ${providerName}`);
|
|
9
|
+
}
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
function useStore(store, selector = (state) => state, isEqual = Object.is) {
|
|
13
|
+
const cacheRef = useRef({
|
|
14
|
+
isEqual: null,
|
|
15
|
+
selected: void 0,
|
|
16
|
+
selector: null,
|
|
17
|
+
snapshot: null
|
|
18
|
+
});
|
|
19
|
+
const getSelectedSnapshot = useCallback(() => {
|
|
20
|
+
const snapshot = store.getSnapshot();
|
|
21
|
+
const cache = cacheRef.current;
|
|
22
|
+
if (cache.snapshot === snapshot && cache.selector === selector && cache.isEqual === isEqual) {
|
|
23
|
+
return cache.selected;
|
|
24
|
+
}
|
|
25
|
+
const selected = selector(snapshot);
|
|
26
|
+
if (cache.snapshot !== null && cache.isEqual === isEqual && isEqual(cache.selected, selected)) {
|
|
27
|
+
cache.snapshot = snapshot;
|
|
28
|
+
cache.selector = selector;
|
|
29
|
+
return cache.selected;
|
|
30
|
+
}
|
|
31
|
+
cacheRef.current = {
|
|
32
|
+
isEqual,
|
|
33
|
+
selected,
|
|
34
|
+
selector,
|
|
35
|
+
snapshot
|
|
36
|
+
};
|
|
37
|
+
return selected;
|
|
38
|
+
}, [isEqual, selector, store]);
|
|
39
|
+
return useSyncExternalStore(
|
|
40
|
+
store.subscribe,
|
|
41
|
+
getSelectedSnapshot,
|
|
42
|
+
getSelectedSnapshot
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
function useClickOutside(ref, callback) {
|
|
46
|
+
const handlePointer = useCallback(
|
|
47
|
+
(event) => {
|
|
48
|
+
if (ref?.current && !ref.current.contains(event.target)) {
|
|
49
|
+
callback?.(event);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
[callback, ref]
|
|
53
|
+
);
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
document.addEventListener("pointerdown", handlePointer);
|
|
56
|
+
return () => document.removeEventListener("pointerdown", handlePointer);
|
|
57
|
+
}, [handlePointer]);
|
|
58
|
+
}
|
|
59
|
+
function cn(...inputs) {
|
|
60
|
+
return twMerge(clsx(inputs));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/utils/string.ts
|
|
64
|
+
function trimToNull(value) {
|
|
65
|
+
if (value === null || value === void 0) return null;
|
|
66
|
+
const trimmed = String(value).trim();
|
|
67
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
68
|
+
}
|
|
69
|
+
function stripTrailingSlash(url) {
|
|
70
|
+
if (typeof url !== "string") return "";
|
|
71
|
+
return url.replace(/\/+$/, "");
|
|
72
|
+
}
|
|
73
|
+
function normalizePath(path) {
|
|
74
|
+
const trimmed = trimToNull(path);
|
|
75
|
+
if (!trimmed) return "";
|
|
76
|
+
if (trimmed === "/") return "/";
|
|
77
|
+
return stripTrailingSlash(trimmed);
|
|
78
|
+
}
|
|
79
|
+
function isImageIconSource(icon) {
|
|
80
|
+
return typeof icon === "string" && (icon.startsWith("http://") || icon.startsWith("https://") || icon.startsWith("/") || icon.startsWith("data:image/"));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/utils/dom.ts
|
|
84
|
+
var isBrowser = typeof window !== "undefined";
|
|
85
|
+
var globalScrollLockCount = 0;
|
|
86
|
+
var globalScrollLockStyles = null;
|
|
87
|
+
function acquireGlobalScrollLock() {
|
|
88
|
+
if (typeof document === "undefined") return () => {
|
|
89
|
+
};
|
|
90
|
+
if (globalScrollLockCount === 0) {
|
|
91
|
+
globalScrollLockStyles = {
|
|
92
|
+
bodyOverflow: document.body.style.overflow,
|
|
93
|
+
bodyOverscrollBehavior: document.body.style.overscrollBehavior,
|
|
94
|
+
htmlOverflow: document.documentElement.style.overflow,
|
|
95
|
+
htmlOverscrollBehavior: document.documentElement.style.overscrollBehavior
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
globalScrollLockCount += 1;
|
|
99
|
+
document.body.style.overflow = "hidden";
|
|
100
|
+
document.body.style.overscrollBehavior = "none";
|
|
101
|
+
document.documentElement.style.overflow = "hidden";
|
|
102
|
+
document.documentElement.style.overscrollBehavior = "none";
|
|
103
|
+
let released = false;
|
|
104
|
+
return () => {
|
|
105
|
+
if (released) return;
|
|
106
|
+
released = true;
|
|
107
|
+
globalScrollLockCount = Math.max(0, globalScrollLockCount - 1);
|
|
108
|
+
if (globalScrollLockCount > 0 || !globalScrollLockStyles) return;
|
|
109
|
+
document.body.style.overflow = globalScrollLockStyles.bodyOverflow;
|
|
110
|
+
document.body.style.overscrollBehavior = globalScrollLockStyles.bodyOverscrollBehavior;
|
|
111
|
+
document.documentElement.style.overflow = globalScrollLockStyles.htmlOverflow;
|
|
112
|
+
document.documentElement.style.overscrollBehavior = globalScrollLockStyles.htmlOverscrollBehavior;
|
|
113
|
+
globalScrollLockStyles = null;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function getSiteUrl() {
|
|
117
|
+
return stripTrailingSlash(
|
|
118
|
+
process.env.NEXT_PUBLIC_SITE_URL || "http://localhost:3000"
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
function getCurrentPath() {
|
|
122
|
+
if (!isBrowser) return "/";
|
|
123
|
+
return `${window.location.pathname}${window.location.search}`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// src/utils/number.ts
|
|
127
|
+
function clamp(value, min, max) {
|
|
128
|
+
const num = Number(value);
|
|
129
|
+
const finite = Number.isFinite(num) ? num : min;
|
|
130
|
+
return Math.min(Math.max(finite, min), max);
|
|
131
|
+
}
|
|
132
|
+
function toFiniteNumber(value, fallback = 0) {
|
|
133
|
+
const parsed = Number(value);
|
|
134
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/utils/object.ts
|
|
138
|
+
function isObject(value) {
|
|
139
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
140
|
+
}
|
|
141
|
+
function isPlainObject(value) {
|
|
142
|
+
if (!isObject(value)) return false;
|
|
143
|
+
const proto = Object.getPrototypeOf(value);
|
|
144
|
+
return proto === Object.prototype || proto === null;
|
|
145
|
+
}
|
|
146
|
+
function shallowEqual(a, b) {
|
|
147
|
+
if (Object.is(a, b)) return true;
|
|
148
|
+
if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
const keysA = Object.keys(a);
|
|
152
|
+
const keysB = Object.keys(b);
|
|
153
|
+
if (keysA.length !== keysB.length) return false;
|
|
154
|
+
for (const key of keysA) {
|
|
155
|
+
if (!Object.prototype.hasOwnProperty.call(b, key) || !Object.is(
|
|
156
|
+
a[key],
|
|
157
|
+
b[key]
|
|
158
|
+
)) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
function toArray(value) {
|
|
165
|
+
if (value === null || value === void 0) return [];
|
|
166
|
+
return Array.isArray(value) ? value : [value];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/utils/timing.ts
|
|
170
|
+
function debounce(func, wait = 300) {
|
|
171
|
+
let timeoutId = null;
|
|
172
|
+
function debounced(...args) {
|
|
173
|
+
if (timeoutId !== null) clearTimeout(timeoutId);
|
|
174
|
+
timeoutId = setTimeout(() => {
|
|
175
|
+
timeoutId = null;
|
|
176
|
+
func(...args);
|
|
177
|
+
}, wait);
|
|
178
|
+
}
|
|
179
|
+
debounced.cancel = () => {
|
|
180
|
+
if (timeoutId !== null) {
|
|
181
|
+
clearTimeout(timeoutId);
|
|
182
|
+
timeoutId = null;
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
return debounced;
|
|
186
|
+
}
|
|
187
|
+
function throttle(func, limit = 300) {
|
|
188
|
+
let lastRan = 0;
|
|
189
|
+
let timerId = null;
|
|
190
|
+
const throttled = function(...args) {
|
|
191
|
+
const now = Date.now();
|
|
192
|
+
if (now - lastRan >= limit) {
|
|
193
|
+
lastRan = now;
|
|
194
|
+
func(...args);
|
|
195
|
+
} else if (timerId === null) {
|
|
196
|
+
timerId = setTimeout(
|
|
197
|
+
() => {
|
|
198
|
+
lastRan = Date.now();
|
|
199
|
+
timerId = null;
|
|
200
|
+
func(...args);
|
|
201
|
+
},
|
|
202
|
+
limit - (now - lastRan)
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
throttled.cancel = () => {
|
|
207
|
+
if (timerId === null) return;
|
|
208
|
+
clearTimeout(timerId);
|
|
209
|
+
timerId = null;
|
|
210
|
+
};
|
|
211
|
+
return throttled;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// src/utils/report.ts
|
|
215
|
+
var GLOBAL_SINK_KEY = /* @__PURE__ */ Symbol.for("__base_framework_report_sink__");
|
|
216
|
+
var _global = globalThis;
|
|
217
|
+
function report(scope, error, level = "error") {
|
|
218
|
+
const sink = _global[GLOBAL_SINK_KEY];
|
|
219
|
+
if (sink) {
|
|
220
|
+
try {
|
|
221
|
+
sink(scope, error, level);
|
|
222
|
+
return;
|
|
223
|
+
} catch {
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (process.env.NODE_ENV === "production" && typeof window !== "undefined") {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
console[level](`[${scope}]`, error);
|
|
230
|
+
}
|
|
231
|
+
function setReportSink(next) {
|
|
232
|
+
_global[GLOBAL_SINK_KEY] = next;
|
|
233
|
+
return () => {
|
|
234
|
+
if (_global[GLOBAL_SINK_KEY] === next) _global[GLOBAL_SINK_KEY] = null;
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// src/utils/user-message.ts
|
|
239
|
+
var USER_MESSAGES = Object.freeze({
|
|
240
|
+
generic: "Something went wrong. Please try again",
|
|
241
|
+
network: "You appear to be offline. Check your connection and try again",
|
|
242
|
+
timeout: "That took too long. Please try again",
|
|
243
|
+
unauthorized: "Your session has expired. Please sign in again",
|
|
244
|
+
forbidden: "You don't have permission to do that",
|
|
245
|
+
notFound: "We couldn't find what you were looking for",
|
|
246
|
+
rateLimited: "Too many attempts. Please wait a moment and try again",
|
|
247
|
+
server: "We're having trouble on our end. Please try again in a moment"
|
|
248
|
+
});
|
|
249
|
+
var UserError = class extends Error {
|
|
250
|
+
status;
|
|
251
|
+
constructor(message, status) {
|
|
252
|
+
super(message);
|
|
253
|
+
this.name = "UserError";
|
|
254
|
+
this.status = status;
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
var NETWORK_FAILURE = /failed to fetch|network|load failed|fetch failed/i;
|
|
258
|
+
function readField(source, field, type) {
|
|
259
|
+
const value = source?.[field];
|
|
260
|
+
return typeof value === type ? value : void 0;
|
|
261
|
+
}
|
|
262
|
+
function readPayloadMessage(error) {
|
|
263
|
+
const payload = error?.payload;
|
|
264
|
+
const message = readField(payload, "error", "string")?.trim();
|
|
265
|
+
return message || void 0;
|
|
266
|
+
}
|
|
267
|
+
function toUserMessage(error, { codes, fallback = USER_MESSAGES.generic } = {}) {
|
|
268
|
+
if (typeof error === "string") return error.trim() || fallback;
|
|
269
|
+
if (!error || typeof error !== "object") return fallback;
|
|
270
|
+
if (error instanceof UserError) {
|
|
271
|
+
if (error.status === 401) return USER_MESSAGES.unauthorized;
|
|
272
|
+
return error.message || fallback;
|
|
273
|
+
}
|
|
274
|
+
if (error.name === "AbortError") return fallback;
|
|
275
|
+
const code = readField(error, "code", "string");
|
|
276
|
+
if (code && codes?.[code]) return codes[code];
|
|
277
|
+
const status = readField(error, "status", "number");
|
|
278
|
+
if (status === 401) return USER_MESSAGES.unauthorized;
|
|
279
|
+
if (status === 429) return USER_MESSAGES.rateLimited;
|
|
280
|
+
if (status === 408 || status === 504) return USER_MESSAGES.timeout;
|
|
281
|
+
if (status !== void 0 && status >= 500) return USER_MESSAGES.server;
|
|
282
|
+
if (status !== void 0 && status >= 400) {
|
|
283
|
+
const authored = readPayloadMessage(error);
|
|
284
|
+
if (authored) return authored;
|
|
285
|
+
if (status === 403) return USER_MESSAGES.forbidden;
|
|
286
|
+
if (status === 404) return USER_MESSAGES.notFound;
|
|
287
|
+
return fallback;
|
|
288
|
+
}
|
|
289
|
+
const isOffline = typeof navigator !== "undefined" && navigator.onLine === false;
|
|
290
|
+
if (isOffline || NETWORK_FAILURE.test(error.message ?? "") && (error instanceof TypeError || /fetch/i.test(error.name))) {
|
|
291
|
+
return USER_MESSAGES.network;
|
|
292
|
+
}
|
|
293
|
+
return fallback;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// src/utils/store.ts
|
|
297
|
+
function freezeStoreSnapshot(state) {
|
|
298
|
+
if (process.env.NODE_ENV === "production" || !state || typeof state !== "object") {
|
|
299
|
+
return state;
|
|
300
|
+
}
|
|
301
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
302
|
+
const freeze = (value) => {
|
|
303
|
+
if (seen.has(value) || Object.isFrozen(value)) return;
|
|
304
|
+
seen.add(value);
|
|
305
|
+
const prototype = Object.getPrototypeOf(value);
|
|
306
|
+
if (Array.isArray(value) || prototype === Object.prototype || prototype === null) {
|
|
307
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
308
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
309
|
+
if (descriptor && "value" in descriptor && descriptor.value !== null) {
|
|
310
|
+
if (typeof descriptor.value === "object") freeze(descriptor.value);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
Object.freeze(value);
|
|
315
|
+
};
|
|
316
|
+
freeze(state);
|
|
317
|
+
return state;
|
|
318
|
+
}
|
|
319
|
+
function createStore(initialState, { freezeSnapshots = true } = {}) {
|
|
320
|
+
const listeners2 = /* @__PURE__ */ new Set();
|
|
321
|
+
const prepare = freezeSnapshots ? freezeStoreSnapshot : (state) => state;
|
|
322
|
+
let snapshot = prepare(initialState);
|
|
323
|
+
const publish = (nextStateOrUpdater) => {
|
|
324
|
+
const nextState = typeof nextStateOrUpdater === "function" ? nextStateOrUpdater(snapshot) : nextStateOrUpdater;
|
|
325
|
+
if (Object.is(snapshot, nextState)) return false;
|
|
326
|
+
snapshot = prepare(nextState);
|
|
327
|
+
for (const listener of listeners2) {
|
|
328
|
+
try {
|
|
329
|
+
listener();
|
|
330
|
+
} catch (error) {
|
|
331
|
+
report("CoreStore subscriber", error, "warn");
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return true;
|
|
335
|
+
};
|
|
336
|
+
const setState = (updater) => {
|
|
337
|
+
if (typeof updater === "function") {
|
|
338
|
+
return publish(updater);
|
|
339
|
+
}
|
|
340
|
+
if (snapshot && typeof snapshot === "object" && updater && typeof updater === "object") {
|
|
341
|
+
return publish({ ...snapshot, ...updater });
|
|
342
|
+
}
|
|
343
|
+
return publish(updater);
|
|
344
|
+
};
|
|
345
|
+
return Object.freeze({
|
|
346
|
+
getSnapshot() {
|
|
347
|
+
return snapshot;
|
|
348
|
+
},
|
|
349
|
+
publish,
|
|
350
|
+
setState,
|
|
351
|
+
subscribe(listener) {
|
|
352
|
+
if (typeof listener !== "function") return () => {
|
|
353
|
+
};
|
|
354
|
+
listeners2.add(listener);
|
|
355
|
+
return () => listeners2.delete(listener);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// src/utils/scheduler.ts
|
|
361
|
+
var DEFAULT_SCHEDULER_FRAME_MS = 16;
|
|
362
|
+
var EMPTY_SCHEDULER_TASKS = Object.freeze(
|
|
363
|
+
[]
|
|
364
|
+
);
|
|
365
|
+
function getDefaultSchedulerNow() {
|
|
366
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
367
|
+
}
|
|
368
|
+
function createScheduler({
|
|
369
|
+
cancelFrame = typeof window !== "undefined" && typeof window.cancelAnimationFrame === "function" ? (id) => window.cancelAnimationFrame(id) : (id) => clearTimeout(id),
|
|
370
|
+
clearTimer = (id) => clearTimeout(id),
|
|
371
|
+
defaultLabel = "scheduled-task",
|
|
372
|
+
now = getDefaultSchedulerNow,
|
|
373
|
+
requestFrame = typeof window !== "undefined" && typeof window.requestAnimationFrame === "function" ? (cb) => window.requestAnimationFrame(cb) : (cb) => setTimeout(cb, DEFAULT_SCHEDULER_FRAME_MS),
|
|
374
|
+
scheduleTimer = (cb, delayMs) => setTimeout(cb, delayMs)
|
|
375
|
+
} = {}) {
|
|
376
|
+
const listeners2 = /* @__PURE__ */ new Set();
|
|
377
|
+
const tasks = /* @__PURE__ */ new Map();
|
|
378
|
+
let nextTaskId = 0;
|
|
379
|
+
let snapshot = {
|
|
380
|
+
pendingCount: 0,
|
|
381
|
+
tasks: EMPTY_SCHEDULER_TASKS
|
|
382
|
+
};
|
|
383
|
+
const publish = () => {
|
|
384
|
+
const currentTasks = [];
|
|
385
|
+
for (const task of tasks.values()) {
|
|
386
|
+
currentTasks.push({
|
|
387
|
+
createdAt: task.createdAt,
|
|
388
|
+
dueAt: task.dueAt,
|
|
389
|
+
id: task.id,
|
|
390
|
+
kind: task.kind,
|
|
391
|
+
label: task.label
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
snapshot = {
|
|
395
|
+
pendingCount: tasks.size,
|
|
396
|
+
tasks: currentTasks
|
|
397
|
+
};
|
|
398
|
+
for (const listener of listeners2) {
|
|
399
|
+
try {
|
|
400
|
+
listener();
|
|
401
|
+
} catch (error) {
|
|
402
|
+
report("Scheduler subscriber", error, "warn");
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
const scheduleInternal = (kind, callback, delayMs, options = {}) => {
|
|
407
|
+
if (typeof callback !== "function") return null;
|
|
408
|
+
const safeDelay = Math.max(0, Number(delayMs) || 0);
|
|
409
|
+
const taskId = ++nextTaskId;
|
|
410
|
+
const createdAt = now();
|
|
411
|
+
const invoke = (timestamp = now()) => {
|
|
412
|
+
if (!tasks.has(taskId)) return;
|
|
413
|
+
tasks.delete(taskId);
|
|
414
|
+
publish();
|
|
415
|
+
callback(timestamp);
|
|
416
|
+
};
|
|
417
|
+
const nativeId = kind === "frame" ? requestFrame(invoke) : scheduleTimer(invoke, safeDelay);
|
|
418
|
+
tasks.set(taskId, {
|
|
419
|
+
cancel: kind === "frame" ? cancelFrame : clearTimer,
|
|
420
|
+
createdAt,
|
|
421
|
+
dueAt: createdAt + (kind === "frame" ? DEFAULT_SCHEDULER_FRAME_MS : safeDelay),
|
|
422
|
+
id: taskId,
|
|
423
|
+
kind,
|
|
424
|
+
label: typeof options.label === "string" && options.label ? options.label : defaultLabel,
|
|
425
|
+
nativeId
|
|
426
|
+
});
|
|
427
|
+
publish();
|
|
428
|
+
return taskId;
|
|
429
|
+
};
|
|
430
|
+
const cancel = (taskId) => {
|
|
431
|
+
const task = tasks.get(taskId);
|
|
432
|
+
if (!task) return false;
|
|
433
|
+
tasks.delete(taskId);
|
|
434
|
+
try {
|
|
435
|
+
task.cancel(task.nativeId);
|
|
436
|
+
} catch (error) {
|
|
437
|
+
report("Scheduler cancellation", error, "warn");
|
|
438
|
+
}
|
|
439
|
+
publish();
|
|
440
|
+
return true;
|
|
441
|
+
};
|
|
442
|
+
return Object.freeze({
|
|
443
|
+
cancel,
|
|
444
|
+
cancelAll() {
|
|
445
|
+
if (tasks.size === 0) return [];
|
|
446
|
+
const taskIds = [];
|
|
447
|
+
for (const [taskId, task] of tasks) {
|
|
448
|
+
taskIds.push(taskId);
|
|
449
|
+
try {
|
|
450
|
+
task.cancel(task.nativeId);
|
|
451
|
+
} catch (error) {
|
|
452
|
+
report("Scheduler cancellation", error, "warn");
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
tasks.clear();
|
|
456
|
+
publish();
|
|
457
|
+
return taskIds;
|
|
458
|
+
},
|
|
459
|
+
getSnapshot() {
|
|
460
|
+
return snapshot;
|
|
461
|
+
},
|
|
462
|
+
now,
|
|
463
|
+
schedule(callback, delayMs = 0, options = {}) {
|
|
464
|
+
return scheduleInternal("timer", callback, delayMs, options);
|
|
465
|
+
},
|
|
466
|
+
scheduleFrame(callback, options = {}) {
|
|
467
|
+
return scheduleInternal(
|
|
468
|
+
"frame",
|
|
469
|
+
callback,
|
|
470
|
+
DEFAULT_SCHEDULER_FRAME_MS,
|
|
471
|
+
options
|
|
472
|
+
);
|
|
473
|
+
},
|
|
474
|
+
subscribe(listener) {
|
|
475
|
+
if (typeof listener !== "function") return () => {
|
|
476
|
+
};
|
|
477
|
+
listeners2.add(listener);
|
|
478
|
+
return () => listeners2.delete(listener);
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/hooks/use-isomorphic-layout-effect.ts
|
|
484
|
+
var useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : useEffect;
|
|
485
|
+
|
|
486
|
+
// src/events.ts
|
|
487
|
+
var EVENT_TYPES = Object.freeze({
|
|
488
|
+
API_UNAUTHORIZED: "API_UNAUTHORIZED",
|
|
489
|
+
STATE_CHANGE: "STATE_CHANGE",
|
|
490
|
+
API_ERROR: "API_ERROR",
|
|
491
|
+
APP_ERROR: "APP_ERROR"
|
|
492
|
+
});
|
|
493
|
+
var EventEmitter = class {
|
|
494
|
+
events = /* @__PURE__ */ new Map();
|
|
495
|
+
debounceTimers = /* @__PURE__ */ new Map();
|
|
496
|
+
subscribe(event, callback) {
|
|
497
|
+
if (typeof event !== "string" || !event || typeof callback !== "function") {
|
|
498
|
+
return () => {
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
const listeners2 = this.events.get(event) || /* @__PURE__ */ new Set();
|
|
502
|
+
listeners2.add(callback);
|
|
503
|
+
this.events.set(event, listeners2);
|
|
504
|
+
return () => {
|
|
505
|
+
listeners2.delete(callback);
|
|
506
|
+
if (listeners2.size === 0) this.events.delete(event);
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
emit(event, payload) {
|
|
510
|
+
const listeners2 = this.events.get(event);
|
|
511
|
+
if (!listeners2 || listeners2.size === 0) return;
|
|
512
|
+
const snapshot = Array.from(listeners2);
|
|
513
|
+
for (const callback of snapshot) {
|
|
514
|
+
try {
|
|
515
|
+
callback(payload);
|
|
516
|
+
} catch (error) {
|
|
517
|
+
report(`Event listener (${String(event)})`, error);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
emitDebounced(event, payload, waitMs = 100) {
|
|
522
|
+
const existing = this.debounceTimers.get(event);
|
|
523
|
+
if (existing) clearTimeout(existing);
|
|
524
|
+
const timer = setTimeout(() => {
|
|
525
|
+
this.debounceTimers.delete(event);
|
|
526
|
+
this.emit(event, payload);
|
|
527
|
+
}, waitMs);
|
|
528
|
+
this.debounceTimers.set(event, timer);
|
|
529
|
+
}
|
|
530
|
+
cancelDebounced(event) {
|
|
531
|
+
if (event) {
|
|
532
|
+
const timer = this.debounceTimers.get(event);
|
|
533
|
+
if (timer) {
|
|
534
|
+
clearTimeout(timer);
|
|
535
|
+
this.debounceTimers.delete(event);
|
|
536
|
+
}
|
|
537
|
+
} else {
|
|
538
|
+
for (const timer of this.debounceTimers.values()) {
|
|
539
|
+
clearTimeout(timer);
|
|
540
|
+
}
|
|
541
|
+
this.debounceTimers.clear();
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
unsubscribeAll(event) {
|
|
545
|
+
this.cancelDebounced(event);
|
|
546
|
+
if (event) this.events.delete(event);
|
|
547
|
+
else this.events.clear();
|
|
548
|
+
}
|
|
549
|
+
hasListeners(event) {
|
|
550
|
+
return Boolean(this.events.get(event)?.size);
|
|
551
|
+
}
|
|
552
|
+
getListenerCount(event) {
|
|
553
|
+
return this.events.get(event)?.size || 0;
|
|
554
|
+
}
|
|
555
|
+
getAllEvents() {
|
|
556
|
+
return [...this.events.keys()];
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
var GLOBAL_EVENTS_KEY = /* @__PURE__ */ Symbol.for("__base_framework_global_events__");
|
|
560
|
+
var _global2 = globalThis;
|
|
561
|
+
var globalEvents = _global2[GLOBAL_EVENTS_KEY] ?? (_global2[GLOBAL_EVENTS_KEY] = new EventEmitter());
|
|
562
|
+
|
|
563
|
+
// src/hooks/use-global-event.ts
|
|
564
|
+
function useGlobalEvent(event, callback, options) {
|
|
565
|
+
const callbackRef = useRef(callback);
|
|
566
|
+
const debounceTimerRef = useRef(null);
|
|
567
|
+
const lastThrottleTimeRef = useRef(0);
|
|
568
|
+
const throttleTimerRef = useRef(null);
|
|
569
|
+
useIsomorphicLayoutEffect(() => {
|
|
570
|
+
callbackRef.current = callback;
|
|
571
|
+
});
|
|
572
|
+
const debounceMs = options?.debounceMs;
|
|
573
|
+
const throttleMs = options?.throttleMs;
|
|
574
|
+
useEffect(() => {
|
|
575
|
+
if (!event) return;
|
|
576
|
+
const events = Array.isArray(event) ? event.filter(Boolean) : [event];
|
|
577
|
+
if (events.length === 0) return;
|
|
578
|
+
const handler = (payload) => {
|
|
579
|
+
if (debounceMs != null && debounceMs > 0) {
|
|
580
|
+
if (debounceTimerRef.current !== null) {
|
|
581
|
+
clearTimeout(debounceTimerRef.current);
|
|
582
|
+
}
|
|
583
|
+
debounceTimerRef.current = setTimeout(() => {
|
|
584
|
+
debounceTimerRef.current = null;
|
|
585
|
+
callbackRef.current?.(payload);
|
|
586
|
+
}, debounceMs);
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
if (throttleMs != null && throttleMs > 0) {
|
|
590
|
+
const now = Date.now();
|
|
591
|
+
const remaining = throttleMs - (now - lastThrottleTimeRef.current);
|
|
592
|
+
if (remaining <= 0) {
|
|
593
|
+
if (throttleTimerRef.current !== null) {
|
|
594
|
+
clearTimeout(throttleTimerRef.current);
|
|
595
|
+
throttleTimerRef.current = null;
|
|
596
|
+
}
|
|
597
|
+
lastThrottleTimeRef.current = now;
|
|
598
|
+
callbackRef.current?.(payload);
|
|
599
|
+
} else if (throttleTimerRef.current === null) {
|
|
600
|
+
throttleTimerRef.current = setTimeout(() => {
|
|
601
|
+
lastThrottleTimeRef.current = Date.now();
|
|
602
|
+
throttleTimerRef.current = null;
|
|
603
|
+
callbackRef.current?.(payload);
|
|
604
|
+
}, remaining);
|
|
605
|
+
}
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
callbackRef.current?.(payload);
|
|
609
|
+
};
|
|
610
|
+
const unsubs = events.map((ev) => globalEvents.subscribe(ev, handler));
|
|
611
|
+
return () => {
|
|
612
|
+
unsubs.forEach((unsub) => unsub());
|
|
613
|
+
if (debounceTimerRef.current !== null) {
|
|
614
|
+
clearTimeout(debounceTimerRef.current);
|
|
615
|
+
debounceTimerRef.current = null;
|
|
616
|
+
}
|
|
617
|
+
if (throttleTimerRef.current !== null) {
|
|
618
|
+
clearTimeout(throttleTimerRef.current);
|
|
619
|
+
throttleTimerRef.current = null;
|
|
620
|
+
}
|
|
621
|
+
};
|
|
622
|
+
}, [event, debounceMs, throttleMs]);
|
|
623
|
+
}
|
|
624
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
625
|
+
var activeFullscreenStateIds = /* @__PURE__ */ new Set();
|
|
626
|
+
var ACTIVE_FULLSCREEN_ROOT_SELECTOR = '[data-fullscreen-state-root="true"][data-affect-global-state="true"]';
|
|
627
|
+
var domObserver = null;
|
|
628
|
+
var lastSnapshot = false;
|
|
629
|
+
function getDomSnapshot() {
|
|
630
|
+
if (typeof document === "undefined") {
|
|
631
|
+
return activeFullscreenStateIds.size > 0;
|
|
632
|
+
}
|
|
633
|
+
return document.querySelector(ACTIVE_FULLSCREEN_ROOT_SELECTOR) !== null;
|
|
634
|
+
}
|
|
635
|
+
function emitChange() {
|
|
636
|
+
listeners.forEach((listener) => listener());
|
|
637
|
+
}
|
|
638
|
+
function emitIfSnapshotChanged() {
|
|
639
|
+
const nextSnapshot = getDomSnapshot();
|
|
640
|
+
if (nextSnapshot === lastSnapshot) {
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
lastSnapshot = nextSnapshot;
|
|
644
|
+
emitChange();
|
|
645
|
+
}
|
|
646
|
+
function ensureDomObserver() {
|
|
647
|
+
if (typeof document === "undefined" || domObserver || listeners.size === 0) {
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
domObserver = new MutationObserver(() => {
|
|
651
|
+
emitIfSnapshotChanged();
|
|
652
|
+
});
|
|
653
|
+
domObserver.observe(document.documentElement, {
|
|
654
|
+
attributes: true,
|
|
655
|
+
childList: true,
|
|
656
|
+
subtree: true,
|
|
657
|
+
attributeFilter: [
|
|
658
|
+
"data-fullscreen-state",
|
|
659
|
+
"data-fullscreen-state-root",
|
|
660
|
+
"data-affect-global-state"
|
|
661
|
+
]
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
function releaseDomObserver() {
|
|
665
|
+
if (listeners.size > 0 || !domObserver) {
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
domObserver.disconnect();
|
|
669
|
+
domObserver = null;
|
|
670
|
+
}
|
|
671
|
+
function subscribe(listener) {
|
|
672
|
+
listeners.add(listener);
|
|
673
|
+
ensureDomObserver();
|
|
674
|
+
emitIfSnapshotChanged();
|
|
675
|
+
return () => {
|
|
676
|
+
listeners.delete(listener);
|
|
677
|
+
releaseDomObserver();
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
function getSnapshot() {
|
|
681
|
+
return getDomSnapshot();
|
|
682
|
+
}
|
|
683
|
+
function useIsFullscreenStateActive() {
|
|
684
|
+
return useSyncExternalStore(subscribe, getSnapshot, () => false);
|
|
685
|
+
}
|
|
686
|
+
function useControllableState({
|
|
687
|
+
defaultValue,
|
|
688
|
+
onChange,
|
|
689
|
+
value
|
|
690
|
+
}) {
|
|
691
|
+
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
692
|
+
const isControlled = value !== void 0;
|
|
693
|
+
const currentValue = isControlled ? value : uncontrolledValue;
|
|
694
|
+
const valueRef = useRef(currentValue);
|
|
695
|
+
const onChangeRef = useRef(onChange);
|
|
696
|
+
useIsomorphicLayoutEffect(() => {
|
|
697
|
+
valueRef.current = currentValue;
|
|
698
|
+
onChangeRef.current = onChange;
|
|
699
|
+
});
|
|
700
|
+
const setValue = useCallback(
|
|
701
|
+
(next) => {
|
|
702
|
+
const resolvedNext = typeof next === "function" ? next(valueRef.current) : next;
|
|
703
|
+
if (!Object.is(valueRef.current, resolvedNext)) {
|
|
704
|
+
if (!isControlled) {
|
|
705
|
+
setUncontrolledValue(resolvedNext);
|
|
706
|
+
}
|
|
707
|
+
onChangeRef.current?.(resolvedNext);
|
|
708
|
+
}
|
|
709
|
+
},
|
|
710
|
+
[isControlled]
|
|
711
|
+
);
|
|
712
|
+
return [currentValue, setValue];
|
|
713
|
+
}
|
|
714
|
+
function isEditableElement(target) {
|
|
715
|
+
if (!target || typeof target.tagName !== "string") {
|
|
716
|
+
return false;
|
|
717
|
+
}
|
|
718
|
+
const element = target;
|
|
719
|
+
const tagName = element.tagName.toLowerCase();
|
|
720
|
+
if (tagName === "input" || tagName === "textarea" || tagName === "select") {
|
|
721
|
+
return true;
|
|
722
|
+
}
|
|
723
|
+
return Boolean(element.isContentEditable);
|
|
724
|
+
}
|
|
725
|
+
function matchesKeyCombo(event, combo) {
|
|
726
|
+
const parts = combo.toLowerCase().split("+").map((p) => p.trim()).filter(Boolean);
|
|
727
|
+
if (parts.length === 0) return false;
|
|
728
|
+
const keyPart = parts[parts.length - 1];
|
|
729
|
+
const modifiers = new Set(parts.slice(0, -1));
|
|
730
|
+
const wantsMod = modifiers.has("mod") || modifiers.has("cmd") || modifiers.has("meta");
|
|
731
|
+
const wantsCtrl = modifiers.has("ctrl") || modifiers.has("control");
|
|
732
|
+
const wantsAlt = modifiers.has("alt") || modifiers.has("option");
|
|
733
|
+
const wantsShift = modifiers.has("shift");
|
|
734
|
+
const isModPressed = event.metaKey || event.ctrlKey;
|
|
735
|
+
if (wantsMod && !isModPressed) return false;
|
|
736
|
+
if (!wantsMod && !wantsCtrl && (event.metaKey || event.ctrlKey)) return false;
|
|
737
|
+
if (wantsCtrl && !event.ctrlKey) return false;
|
|
738
|
+
if (wantsAlt !== event.altKey) return false;
|
|
739
|
+
if (wantsShift !== event.shiftKey) return false;
|
|
740
|
+
const pressedKey = event.key.toLowerCase();
|
|
741
|
+
if (keyPart === "esc" || keyPart === "escape") {
|
|
742
|
+
return pressedKey === "escape" || pressedKey === "esc";
|
|
743
|
+
}
|
|
744
|
+
if (keyPart === "space") {
|
|
745
|
+
return pressedKey === " " || pressedKey === "spacebar";
|
|
746
|
+
}
|
|
747
|
+
return pressedKey === keyPart;
|
|
748
|
+
}
|
|
749
|
+
function useHotkey(combo, callback, options) {
|
|
750
|
+
const callbackRef = useRef(callback);
|
|
751
|
+
useIsomorphicLayoutEffect(() => {
|
|
752
|
+
callbackRef.current = callback;
|
|
753
|
+
});
|
|
754
|
+
const enabled = options?.enabled ?? true;
|
|
755
|
+
const enableOnFormTags = options?.enableOnFormTags ?? false;
|
|
756
|
+
const preventDefault = options?.preventDefault ?? true;
|
|
757
|
+
const stopPropagation = options?.stopPropagation ?? false;
|
|
758
|
+
useEffect(() => {
|
|
759
|
+
if (!isBrowser || !enabled || !combo) return;
|
|
760
|
+
const combos = (Array.isArray(combo) ? combo : [combo]).filter(Boolean);
|
|
761
|
+
if (combos.length === 0) return;
|
|
762
|
+
const handleKeyDown = (event) => {
|
|
763
|
+
if (!enableOnFormTags && isEditableElement(event.target)) return;
|
|
764
|
+
const matched = combos.some((c) => matchesKeyCombo(event, c));
|
|
765
|
+
if (!matched) return;
|
|
766
|
+
if (preventDefault) event.preventDefault();
|
|
767
|
+
if (stopPropagation) event.stopPropagation();
|
|
768
|
+
callbackRef.current?.(event);
|
|
769
|
+
};
|
|
770
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
771
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
772
|
+
}, [combo, enabled, enableOnFormTags, preventDefault, stopPropagation]);
|
|
773
|
+
}
|
|
774
|
+
function useEscapeKey(callback, enabled = true) {
|
|
775
|
+
useHotkey("escape", callback, {
|
|
776
|
+
enabled,
|
|
777
|
+
enableOnFormTags: true,
|
|
778
|
+
preventDefault: false
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
export { EVENT_TYPES, EventEmitter, USER_MESSAGES, UserError, acquireGlobalScrollLock, clamp, cn, createScheduler, createStore, debounce, getCurrentPath, getSiteUrl, globalEvents, isBrowser, isImageIconSource, isObject, isPlainObject, normalizePath, report, setReportSink, shallowEqual, stripTrailingSlash, throttle, toArray, toFiniteNumber, toUserMessage, trimToNull, useClickOutside, useControllableState, useEscapeKey, useGlobalEvent, useHotkey, useIsFullscreenStateActive, useIsomorphicLayoutEffect, useRequiredContext, useStore };
|
|
783
|
+
//# sourceMappingURL=chunk-TV3WEF5G.js.map
|
|
784
|
+
//# sourceMappingURL=chunk-TV3WEF5G.js.map
|