@flamingo-stack/openframe-frontend-core 0.0.263 → 0.0.264
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/{chunk-C3FAOQAH.cjs → chunk-3LWUHLPK.cjs} +28 -28
- package/dist/{chunk-C3FAOQAH.cjs.map → chunk-3LWUHLPK.cjs.map} +1 -1
- package/dist/{chunk-U7UDESAU.js → chunk-6ZEKKAAL.js} +2 -2
- package/dist/{chunk-YC357BPF.js → chunk-JOUI6TQY.js} +3 -3
- package/dist/{chunk-2XUWR7AH.cjs → chunk-P67D545X.cjs} +11 -11
- package/dist/{chunk-2XUWR7AH.cjs.map → chunk-P67D545X.cjs.map} +1 -1
- package/dist/{chunk-3DC6MHW6.cjs → chunk-QLWBBCI5.cjs} +491 -391
- package/dist/chunk-QLWBBCI5.cjs.map +1 -0
- package/dist/{chunk-36HLBLDK.cjs → chunk-SIYHXLFH.cjs} +462 -454
- package/dist/chunk-SIYHXLFH.cjs.map +1 -0
- package/dist/{chunk-ALEKX56R.js → chunk-SSUUMPAQ.js} +2 -2
- package/dist/{chunk-6AIXHYBZ.js → chunk-VYTU7JZR.js} +64 -56
- package/dist/chunk-VYTU7JZR.js.map +1 -0
- package/dist/{chunk-6GBA6YJN.js → chunk-ZMFT5XOB.js} +576 -476
- package/dist/chunk-ZMFT5XOB.js.map +1 -0
- package/dist/{chunk-XKA7UFED.cjs → chunk-ZOOTBYZO.cjs} +30 -30
- package/dist/{chunk-XKA7UFED.cjs.map → chunk-ZOOTBYZO.cjs.map} +1 -1
- package/dist/components/chat/index.cjs +3 -3
- package/dist/components/chat/index.js +2 -2
- package/dist/components/contact/index.cjs +4 -4
- package/dist/components/contact/index.js +3 -3
- package/dist/components/features/index.cjs +3 -3
- package/dist/components/features/index.js +2 -2
- package/dist/components/features/notifications/notification-drawer.d.ts.map +1 -1
- package/dist/components/features/notifications/notifications-context.d.ts +9 -1
- package/dist/components/features/notifications/notifications-context.d.ts.map +1 -1
- package/dist/components/index.cjs +50 -50
- package/dist/components/index.js +4 -4
- package/dist/components/navigation/index.cjs +3 -3
- package/dist/components/navigation/index.js +2 -2
- package/dist/components/navigation/sliding-sidebar.d.ts.map +1 -1
- package/dist/components/related-content/index.cjs +4 -4
- package/dist/components/related-content/index.js +3 -3
- package/dist/components/tickets/index.cjs +58 -58
- package/dist/components/tickets/index.js +4 -4
- package/dist/components/ui/drawer.d.ts +5 -0
- package/dist/components/ui/drawer.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +3 -3
- package/dist/components/ui/index.js +2 -2
- package/dist/hooks/index.cjs +6 -2
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.js +5 -1
- package/dist/hooks/ui/index.d.ts +6 -4
- package/dist/hooks/ui/index.d.ts.map +1 -1
- package/dist/hooks/ui/use-header-height.d.ts +8 -0
- package/dist/hooks/ui/use-header-height.d.ts.map +1 -0
- package/dist/hooks/ui/use-horizontal-scrollbar.d.ts.map +1 -1
- package/dist/hooks/ui/use-notification-permission.d.ts +14 -0
- package/dist/hooks/ui/use-notification-permission.d.ts.map +1 -0
- package/dist/index.cjs +7 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +6 -2
- package/package.json +1 -1
- package/src/components/features/notifications/notification-drawer.tsx +51 -2
- package/src/components/features/notifications/notifications-context.tsx +26 -0
- package/src/components/navigation/sliding-sidebar.tsx +3 -82
- package/src/components/ui/drawer.tsx +17 -6
- package/src/hooks/ui/index.ts +6 -4
- package/src/hooks/ui/use-header-height.ts +55 -0
- package/src/hooks/ui/use-horizontal-scrollbar.ts +19 -2
- package/src/hooks/ui/use-notification-permission.ts +64 -0
- package/dist/chunk-36HLBLDK.cjs.map +0 -1
- package/dist/chunk-3DC6MHW6.cjs.map +0 -1
- package/dist/chunk-6AIXHYBZ.js.map +0 -1
- package/dist/chunk-6GBA6YJN.js.map +0 -1
- /package/dist/{chunk-U7UDESAU.js.map → chunk-6ZEKKAAL.js.map} +0 -0
- /package/dist/{chunk-YC357BPF.js.map → chunk-JOUI6TQY.js.map} +0 -0
- /package/dist/{chunk-ALEKX56R.js.map → chunk-SSUUMPAQ.js.map} +0 -0
|
@@ -33,373 +33,65 @@ import {
|
|
|
33
33
|
XmarkIcon
|
|
34
34
|
} from "./chunk-4WZOFD46.js";
|
|
35
35
|
|
|
36
|
-
// src/hooks/ui/use-
|
|
37
|
-
import { useEffect,
|
|
38
|
-
function
|
|
39
|
-
const [
|
|
40
|
-
try {
|
|
41
|
-
if (typeof window !== "undefined") {
|
|
42
|
-
const item = window.localStorage.getItem(key);
|
|
43
|
-
return item ? JSON.parse(item) : initialValue;
|
|
44
|
-
}
|
|
45
|
-
} catch (error) {
|
|
46
|
-
console.error(`Error reading localStorage key "${key}":`, error);
|
|
47
|
-
}
|
|
48
|
-
return initialValue;
|
|
49
|
-
});
|
|
50
|
-
const isInitialized = useRef(true);
|
|
51
|
-
const isFromStorageEvent = useRef(false);
|
|
36
|
+
// src/hooks/ui/use-header-height.ts
|
|
37
|
+
import { useEffect, useState } from "react";
|
|
38
|
+
function useHeaderHeight(defaultHeight = 64) {
|
|
39
|
+
const [height, setHeight] = useState(defaultHeight);
|
|
52
40
|
useEffect(() => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
console.log(`\u{1F504} Updated localStorage key "${key}" from storage event`);
|
|
61
|
-
} catch (error) {
|
|
62
|
-
console.error(`Error parsing storage event for key "${key}":`, error);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
41
|
+
const measure = () => {
|
|
42
|
+
let total = 0;
|
|
43
|
+
const header2 = document.querySelector("header");
|
|
44
|
+
if (header2) total += header2.offsetHeight;
|
|
45
|
+
const bar2 = document.querySelector("[data-announcement-bar]");
|
|
46
|
+
if (bar2 instanceof HTMLElement) total += bar2.offsetHeight;
|
|
47
|
+
setHeight(total > 0 ? total : defaultHeight);
|
|
65
48
|
};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
} catch (error) {
|
|
80
|
-
console.error(`Error parsing custom storage event for key "${key}":`, error);
|
|
49
|
+
measure();
|
|
50
|
+
const resizeObserver = new ResizeObserver(measure);
|
|
51
|
+
const header = document.querySelector("header");
|
|
52
|
+
if (header) resizeObserver.observe(header);
|
|
53
|
+
const bar = document.querySelector("[data-announcement-bar]");
|
|
54
|
+
if (bar) resizeObserver.observe(bar);
|
|
55
|
+
const mutationObserver = new MutationObserver((mutations) => {
|
|
56
|
+
for (const mutation of mutations) {
|
|
57
|
+
if (mutation.type === "childList" || mutation.type === "attributes") {
|
|
58
|
+
measure();
|
|
59
|
+
const newBar = document.querySelector("[data-announcement-bar]");
|
|
60
|
+
if (newBar) resizeObserver.observe(newBar);
|
|
81
61
|
}
|
|
82
62
|
}
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
};
|
|
90
|
-
}, [key]);
|
|
91
|
-
useEffect(() => {
|
|
92
|
-
if (!isInitialized.current) return;
|
|
93
|
-
if (isFromStorageEvent.current) {
|
|
94
|
-
isFromStorageEvent.current = false;
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
try {
|
|
98
|
-
if (typeof window !== "undefined") {
|
|
99
|
-
window.localStorage.setItem(key, JSON.stringify(storedValue));
|
|
100
|
-
}
|
|
101
|
-
} catch (error) {
|
|
102
|
-
console.error(`Error writing to localStorage key "${key}":`, error);
|
|
103
|
-
}
|
|
104
|
-
}, [key, storedValue]);
|
|
105
|
-
const setValue = (value) => {
|
|
106
|
-
try {
|
|
107
|
-
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
108
|
-
setStoredValue(valueToStore);
|
|
109
|
-
} catch (error) {
|
|
110
|
-
console.error(`Error setting value for localStorage key "${key}":`, error);
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
return [storedValue, setValue];
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// src/hooks/ui/use-media-query.ts
|
|
117
|
-
import { useLayoutEffect, useState as useState2 } from "react";
|
|
118
|
-
function useMediaQuery(query) {
|
|
119
|
-
const [matches, setMatches] = useState2(void 0);
|
|
120
|
-
useLayoutEffect(() => {
|
|
121
|
-
const matchMedia = window.matchMedia(query);
|
|
122
|
-
const handleChange = () => {
|
|
123
|
-
setMatches(matchMedia.matches);
|
|
124
|
-
};
|
|
125
|
-
handleChange();
|
|
126
|
-
matchMedia.addEventListener("change", handleChange);
|
|
127
|
-
return () => {
|
|
128
|
-
matchMedia.removeEventListener("change", handleChange);
|
|
129
|
-
};
|
|
130
|
-
}, [query]);
|
|
131
|
-
return matches;
|
|
132
|
-
}
|
|
133
|
-
var breakpoints = {
|
|
134
|
-
md: "(min-width: 800px)",
|
|
135
|
-
// Tablet: 50rem
|
|
136
|
-
lg: "(min-width: 1280px)"
|
|
137
|
-
// Desktop: 80rem
|
|
138
|
-
};
|
|
139
|
-
function useSmUp() {
|
|
140
|
-
return useMdUp();
|
|
141
|
-
}
|
|
142
|
-
function useMdUp() {
|
|
143
|
-
const matches = useMediaQuery(breakpoints.md);
|
|
144
|
-
return matches === void 0 ? void 0 : matches;
|
|
145
|
-
}
|
|
146
|
-
function useLgUp() {
|
|
147
|
-
const matches = useMediaQuery(breakpoints.lg);
|
|
148
|
-
return matches === void 0 ? void 0 : matches;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// src/hooks/ui/use-memoized-callback.ts
|
|
152
|
-
import { useCallback, useRef as useRef2 } from "react";
|
|
153
|
-
function useMemoizedCallback(callback, dependencies) {
|
|
154
|
-
const callbackRef = useRef2(callback);
|
|
155
|
-
const dependenciesRef = useRef2(dependencies);
|
|
156
|
-
callbackRef.current = callback;
|
|
157
|
-
const depsChanged = dependencies.some((dep, i) => !Object.is(dep, dependenciesRef.current[i]));
|
|
158
|
-
if (depsChanged) {
|
|
159
|
-
dependenciesRef.current = dependencies;
|
|
160
|
-
}
|
|
161
|
-
return useCallback(((...args) => callbackRef.current(...args)), [depsChanged]);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// src/hooks/ui/use-onboarding-state.ts
|
|
165
|
-
import { useState as useState3, useEffect as useEffect2, useCallback as useCallback2 } from "react";
|
|
166
|
-
|
|
167
|
-
// src/utils/onboarding-storage.ts
|
|
168
|
-
var DEFAULT_STATE = {
|
|
169
|
-
completedSteps: [],
|
|
170
|
-
skippedSteps: [],
|
|
171
|
-
dismissed: false,
|
|
172
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
173
|
-
};
|
|
174
|
-
function saveOnboardingState(key, state) {
|
|
175
|
-
if (typeof window === "undefined") return;
|
|
176
|
-
try {
|
|
177
|
-
localStorage.setItem(key, JSON.stringify(state));
|
|
178
|
-
console.log("\u{1F4BE} Saved onboarding state:", state);
|
|
179
|
-
if (typeof window !== "undefined") {
|
|
180
|
-
window.dispatchEvent(
|
|
181
|
-
new CustomEvent("localStorageUpdate", {
|
|
182
|
-
detail: { key, newValue: JSON.stringify(state) }
|
|
183
|
-
})
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
} catch (err) {
|
|
187
|
-
console.warn("[onboarding-storage] Failed saving to localStorage:", err);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
function loadOnboardingState(key) {
|
|
191
|
-
if (typeof window === "undefined") return DEFAULT_STATE;
|
|
192
|
-
try {
|
|
193
|
-
const raw = localStorage.getItem(key);
|
|
194
|
-
if (!raw) return DEFAULT_STATE;
|
|
195
|
-
const parsed = JSON.parse(raw);
|
|
196
|
-
return parsed;
|
|
197
|
-
} catch (err) {
|
|
198
|
-
console.warn("[onboarding-storage] Failed parsing localStorage data:", err);
|
|
199
|
-
return DEFAULT_STATE;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
function markMultipleComplete(key, stepIds) {
|
|
203
|
-
const state = loadOnboardingState(key);
|
|
204
|
-
const newState = {
|
|
205
|
-
...state,
|
|
206
|
-
completedSteps: [.../* @__PURE__ */ new Set([...state.completedSteps, ...stepIds])],
|
|
207
|
-
skippedSteps: state.skippedSteps.filter((id) => !stepIds.includes(id)),
|
|
208
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
209
|
-
};
|
|
210
|
-
saveOnboardingState(key, newState);
|
|
211
|
-
return newState;
|
|
212
|
-
}
|
|
213
|
-
function markStepComplete(key, stepId) {
|
|
214
|
-
return markMultipleComplete(key, [stepId]);
|
|
215
|
-
}
|
|
216
|
-
function markStepSkipped(key, stepId) {
|
|
217
|
-
const state = loadOnboardingState(key);
|
|
218
|
-
const newState = {
|
|
219
|
-
...state,
|
|
220
|
-
skippedSteps: [.../* @__PURE__ */ new Set([...state.skippedSteps, stepId])],
|
|
221
|
-
completedSteps: state.completedSteps.filter((id) => id !== stepId),
|
|
222
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
223
|
-
};
|
|
224
|
-
saveOnboardingState(key, newState);
|
|
225
|
-
return newState;
|
|
226
|
-
}
|
|
227
|
-
function dismissOnboarding(key) {
|
|
228
|
-
const state = loadOnboardingState(key);
|
|
229
|
-
const newState = {
|
|
230
|
-
...state,
|
|
231
|
-
dismissed: true,
|
|
232
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
233
|
-
};
|
|
234
|
-
saveOnboardingState(key, newState);
|
|
235
|
-
return newState;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// src/hooks/ui/use-onboarding-state.ts
|
|
239
|
-
function useOnboardingState(storageKey = "openframe-onboarding-state") {
|
|
240
|
-
const [state, setState] = useState3(() => loadOnboardingState(storageKey));
|
|
241
|
-
const [, forceUpdate] = useState3(0);
|
|
242
|
-
useEffect2(() => {
|
|
243
|
-
const handleStorageUpdate = (e) => {
|
|
244
|
-
if (e.detail.key === storageKey) {
|
|
245
|
-
const newState = loadOnboardingState(storageKey);
|
|
246
|
-
setState(newState);
|
|
247
|
-
forceUpdate((prev) => prev + 1);
|
|
248
|
-
console.log("\u{1F504} State updated from storage event:", newState);
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
window.addEventListener("localStorageUpdate", handleStorageUpdate);
|
|
63
|
+
});
|
|
64
|
+
mutationObserver.observe(document.body, {
|
|
65
|
+
childList: true,
|
|
66
|
+
subtree: true,
|
|
67
|
+
attributes: true,
|
|
68
|
+
attributeFilter: ["data-announcement-bar"]
|
|
69
|
+
});
|
|
252
70
|
return () => {
|
|
253
|
-
|
|
71
|
+
resizeObserver.disconnect();
|
|
72
|
+
mutationObserver.disconnect();
|
|
254
73
|
};
|
|
255
|
-
}, [
|
|
256
|
-
|
|
257
|
-
console.log(`\u{1F3AF} markComplete called for: "${stepId}"`);
|
|
258
|
-
const newState = markStepComplete(storageKey, stepId);
|
|
259
|
-
setState(newState);
|
|
260
|
-
forceUpdate((prev) => prev + 1);
|
|
261
|
-
}, [storageKey]);
|
|
262
|
-
const markSkipped = useCallback2((stepId) => {
|
|
263
|
-
console.log(`\u23ED\uFE0F markSkipped called for: "${stepId}"`);
|
|
264
|
-
const newState = markStepSkipped(storageKey, stepId);
|
|
265
|
-
setState(newState);
|
|
266
|
-
forceUpdate((prev) => prev + 1);
|
|
267
|
-
}, [storageKey]);
|
|
268
|
-
const dismissOnboarding2 = useCallback2(() => {
|
|
269
|
-
console.log(`\u{1F6AB} dismissOnboarding called`);
|
|
270
|
-
const newState = dismissOnboarding(storageKey);
|
|
271
|
-
setState(newState);
|
|
272
|
-
forceUpdate((prev) => prev + 1);
|
|
273
|
-
}, [storageKey]);
|
|
274
|
-
const markMultipleComplete2 = useCallback2((stepIds) => {
|
|
275
|
-
console.log(`\u{1F3AF} markMultipleComplete called for:`, stepIds);
|
|
276
|
-
const newState = markMultipleComplete(storageKey, stepIds);
|
|
277
|
-
setState(newState);
|
|
278
|
-
forceUpdate((prev) => prev + 1);
|
|
279
|
-
console.log(`\u{1F4DD} State after batch:`, newState);
|
|
280
|
-
}, [storageKey]);
|
|
281
|
-
const isStepComplete = useCallback2((stepId) => {
|
|
282
|
-
return state.completedSteps.includes(stepId);
|
|
283
|
-
}, [state.completedSteps]);
|
|
284
|
-
const isStepSkipped = useCallback2((stepId) => {
|
|
285
|
-
return state.skippedSteps.includes(stepId);
|
|
286
|
-
}, [state.skippedSteps]);
|
|
287
|
-
const allStepsComplete = useCallback2((steps) => {
|
|
288
|
-
return steps.every((step) => isStepComplete(step.id) || isStepSkipped(step.id));
|
|
289
|
-
}, [isStepComplete, isStepSkipped]);
|
|
290
|
-
return {
|
|
291
|
-
state,
|
|
292
|
-
markComplete,
|
|
293
|
-
markSkipped,
|
|
294
|
-
dismissOnboarding: dismissOnboarding2,
|
|
295
|
-
isStepComplete,
|
|
296
|
-
isStepSkipped,
|
|
297
|
-
allStepsComplete,
|
|
298
|
-
markMultipleComplete: markMultipleComplete2
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// src/hooks/ui/use-table-pagination.ts
|
|
303
|
-
import { useMemo } from "react";
|
|
304
|
-
function useTablePagination(config) {
|
|
305
|
-
return useMemo(() => {
|
|
306
|
-
if (!config) return void 0;
|
|
307
|
-
if (config.type === "client") {
|
|
308
|
-
if (config.totalPages <= 1) return void 0;
|
|
309
|
-
return {
|
|
310
|
-
hasNextPage: config.currentPage < config.totalPages,
|
|
311
|
-
hasPreviousPage: config.currentPage > 1,
|
|
312
|
-
isFirstPage: config.currentPage === 1,
|
|
313
|
-
startCursor: (config.currentPage - 1).toString(),
|
|
314
|
-
endCursor: config.currentPage.toString(),
|
|
315
|
-
currentCount: config.itemCount,
|
|
316
|
-
itemName: config.itemName || "items",
|
|
317
|
-
onNext: () => config.onNext(),
|
|
318
|
-
onPrevious: () => config.onPrevious(),
|
|
319
|
-
showInfo: config.showInfo ?? true
|
|
320
|
-
};
|
|
321
|
-
} else {
|
|
322
|
-
return {
|
|
323
|
-
hasNextPage: config.hasNextPage,
|
|
324
|
-
hasPreviousPage: config.hasLoadedBeyondFirst,
|
|
325
|
-
isFirstPage: !config.hasLoadedBeyondFirst,
|
|
326
|
-
startCursor: config.startCursor,
|
|
327
|
-
endCursor: config.endCursor,
|
|
328
|
-
currentCount: config.itemCount,
|
|
329
|
-
itemName: config.itemName || "items",
|
|
330
|
-
onNext: config.onNext,
|
|
331
|
-
onPrevious: config.onReset,
|
|
332
|
-
// Previous button goes back to first page
|
|
333
|
-
showInfo: config.showInfo ?? true
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
}, [config]);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// src/hooks/ui/use-throttle.ts
|
|
340
|
-
import { useState as useState4, useEffect as useEffect3, useRef as useRef3 } from "react";
|
|
341
|
-
function useThrottle(value, limit = 200) {
|
|
342
|
-
const [throttledValue, setThrottledValue] = useState4(value);
|
|
343
|
-
const lastUpdated = useRef3(Date.now());
|
|
344
|
-
useEffect3(() => {
|
|
345
|
-
const now = Date.now();
|
|
346
|
-
const elapsed = now - lastUpdated.current;
|
|
347
|
-
if (elapsed >= limit) {
|
|
348
|
-
setThrottledValue(value);
|
|
349
|
-
lastUpdated.current = now;
|
|
350
|
-
} else {
|
|
351
|
-
const timerId = setTimeout(() => {
|
|
352
|
-
setThrottledValue(value);
|
|
353
|
-
lastUpdated.current = Date.now();
|
|
354
|
-
}, limit - elapsed);
|
|
355
|
-
return () => {
|
|
356
|
-
clearTimeout(timerId);
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
}, [value, limit]);
|
|
360
|
-
return throttledValue;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// src/hooks/ui/use-window-size.ts
|
|
364
|
-
import { useLayoutEffect as useLayoutEffect2, useState as useState5 } from "react";
|
|
365
|
-
function useWindowSize() {
|
|
366
|
-
const [windowSize, setWindowSize] = useState5({
|
|
367
|
-
width: 0,
|
|
368
|
-
height: 0
|
|
369
|
-
});
|
|
370
|
-
const [isClient, setIsClient] = useState5(false);
|
|
371
|
-
useLayoutEffect2(() => {
|
|
372
|
-
setIsClient(true);
|
|
373
|
-
if (!isClient) return;
|
|
374
|
-
const handleResize = () => {
|
|
375
|
-
setWindowSize({
|
|
376
|
-
width: window.innerWidth,
|
|
377
|
-
height: window.innerHeight
|
|
378
|
-
});
|
|
379
|
-
};
|
|
380
|
-
handleResize();
|
|
381
|
-
window.addEventListener("resize", handleResize);
|
|
382
|
-
return () => window.removeEventListener("resize", handleResize);
|
|
383
|
-
}, [isClient]);
|
|
384
|
-
return windowSize;
|
|
74
|
+
}, [defaultHeight]);
|
|
75
|
+
return height;
|
|
385
76
|
}
|
|
386
77
|
|
|
387
78
|
// src/hooks/ui/use-horizontal-scrollbar.ts
|
|
388
|
-
import { useRef
|
|
79
|
+
import { useRef, useState as useState2, useCallback } from "react";
|
|
389
80
|
function useHorizontalScrollbar() {
|
|
390
|
-
const scrollElRef =
|
|
391
|
-
const trackRef =
|
|
392
|
-
const thumbRef =
|
|
393
|
-
const roRef =
|
|
394
|
-
const
|
|
395
|
-
const [
|
|
396
|
-
const [
|
|
397
|
-
const
|
|
398
|
-
const
|
|
399
|
-
const
|
|
400
|
-
const
|
|
401
|
-
const
|
|
402
|
-
const
|
|
81
|
+
const scrollElRef = useRef(null);
|
|
82
|
+
const trackRef = useRef(null);
|
|
83
|
+
const thumbRef = useRef(null);
|
|
84
|
+
const roRef = useRef(null);
|
|
85
|
+
const moRef = useRef(null);
|
|
86
|
+
const [thumbRatio, setThumbRatio] = useState2(0);
|
|
87
|
+
const [canScrollLeft, setCanScrollLeft] = useState2(false);
|
|
88
|
+
const [canScrollRight, setCanScrollRight] = useState2(false);
|
|
89
|
+
const prevCanScrollLeftRef = useRef(false);
|
|
90
|
+
const prevCanScrollRightRef = useRef(false);
|
|
91
|
+
const isDraggingRef = useRef(false);
|
|
92
|
+
const dragStartRef = useRef({ mouseX: 0, scrollLeft: 0 });
|
|
93
|
+
const rafIdRef = useRef(0);
|
|
94
|
+
const syncThumbToDOM = useCallback(() => {
|
|
403
95
|
const el = scrollElRef.current;
|
|
404
96
|
const thumb = thumbRef.current;
|
|
405
97
|
if (!el || !thumb) return;
|
|
@@ -412,7 +104,7 @@ function useHorizontalScrollbar() {
|
|
|
412
104
|
const fraction = Math.min(Math.max(el.scrollLeft, 0), maxScroll) / maxScroll;
|
|
413
105
|
thumb.style.left = `${fraction * (1 - ratio) * 100}%`;
|
|
414
106
|
}, []);
|
|
415
|
-
const syncEdgeFades =
|
|
107
|
+
const syncEdgeFades = useCallback(() => {
|
|
416
108
|
const el = scrollElRef.current;
|
|
417
109
|
if (!el) return;
|
|
418
110
|
const maxScroll = el.scrollWidth - el.clientWidth;
|
|
@@ -440,7 +132,7 @@ function useHorizontalScrollbar() {
|
|
|
440
132
|
setCanScrollRight(right);
|
|
441
133
|
}
|
|
442
134
|
}, []);
|
|
443
|
-
const measure =
|
|
135
|
+
const measure = useCallback(() => {
|
|
444
136
|
const el = scrollElRef.current;
|
|
445
137
|
if (!el) return;
|
|
446
138
|
const ratio = el.clientWidth / el.scrollWidth;
|
|
@@ -448,11 +140,15 @@ function useHorizontalScrollbar() {
|
|
|
448
140
|
syncThumbToDOM();
|
|
449
141
|
syncEdgeFades();
|
|
450
142
|
}, [syncThumbToDOM, syncEdgeFades]);
|
|
451
|
-
const scrollRef =
|
|
143
|
+
const scrollRef = useCallback((node) => {
|
|
452
144
|
if (roRef.current) {
|
|
453
145
|
roRef.current.disconnect();
|
|
454
146
|
roRef.current = null;
|
|
455
147
|
}
|
|
148
|
+
if (moRef.current) {
|
|
149
|
+
moRef.current.disconnect();
|
|
150
|
+
moRef.current = null;
|
|
151
|
+
}
|
|
456
152
|
if (rafIdRef.current) {
|
|
457
153
|
cancelAnimationFrame(rafIdRef.current);
|
|
458
154
|
rafIdRef.current = 0;
|
|
@@ -461,8 +157,19 @@ function useHorizontalScrollbar() {
|
|
|
461
157
|
if (node) {
|
|
462
158
|
const ratio = node.clientWidth / node.scrollWidth;
|
|
463
159
|
setThumbRatio(ratio >= 1 ? 0 : ratio);
|
|
464
|
-
|
|
465
|
-
roRef.current
|
|
160
|
+
const ro = new ResizeObserver(measure);
|
|
161
|
+
roRef.current = ro;
|
|
162
|
+
const observeAll = () => {
|
|
163
|
+
ro.disconnect();
|
|
164
|
+
ro.observe(node);
|
|
165
|
+
for (const child of Array.from(node.children)) ro.observe(child);
|
|
166
|
+
};
|
|
167
|
+
observeAll();
|
|
168
|
+
moRef.current = new MutationObserver(() => {
|
|
169
|
+
observeAll();
|
|
170
|
+
measure();
|
|
171
|
+
});
|
|
172
|
+
moRef.current.observe(node, { childList: true });
|
|
466
173
|
requestAnimationFrame(() => {
|
|
467
174
|
syncThumbToDOM();
|
|
468
175
|
syncEdgeFades();
|
|
@@ -475,7 +182,7 @@ function useHorizontalScrollbar() {
|
|
|
475
182
|
setCanScrollRight(false);
|
|
476
183
|
}
|
|
477
184
|
}, [measure, syncThumbToDOM, syncEdgeFades]);
|
|
478
|
-
const onScroll =
|
|
185
|
+
const onScroll = useCallback(() => {
|
|
479
186
|
if (isDraggingRef.current) return;
|
|
480
187
|
if (rafIdRef.current) cancelAnimationFrame(rafIdRef.current);
|
|
481
188
|
rafIdRef.current = requestAnimationFrame(() => {
|
|
@@ -483,7 +190,7 @@ function useHorizontalScrollbar() {
|
|
|
483
190
|
syncEdgeFades();
|
|
484
191
|
});
|
|
485
192
|
}, [syncThumbToDOM, syncEdgeFades]);
|
|
486
|
-
const onTrackClick =
|
|
193
|
+
const onTrackClick = useCallback((e) => {
|
|
487
194
|
if (e.target.closest("[data-scrollbar-thumb]")) return;
|
|
488
195
|
const track = trackRef.current;
|
|
489
196
|
const el = scrollElRef.current;
|
|
@@ -501,13 +208,13 @@ function useHorizontalScrollbar() {
|
|
|
501
208
|
const targetScrollLeft = targetFraction * (el.scrollWidth - el.clientWidth);
|
|
502
209
|
el.scrollTo({ left: targetScrollLeft, behavior: "smooth" });
|
|
503
210
|
}, []);
|
|
504
|
-
const onTrackWheel =
|
|
211
|
+
const onTrackWheel = useCallback((e) => {
|
|
505
212
|
const el = scrollElRef.current;
|
|
506
213
|
if (!el) return;
|
|
507
214
|
e.preventDefault();
|
|
508
215
|
el.scrollLeft += e.deltaX || e.deltaY;
|
|
509
216
|
}, []);
|
|
510
|
-
const onThumbPointerDown =
|
|
217
|
+
const onThumbPointerDown = useCallback((e) => {
|
|
511
218
|
e.preventDefault();
|
|
512
219
|
e.stopPropagation();
|
|
513
220
|
const el = scrollElRef.current;
|
|
@@ -518,7 +225,7 @@ function useHorizontalScrollbar() {
|
|
|
518
225
|
target.setPointerCapture(e.pointerId);
|
|
519
226
|
target.style.cursor = "grabbing";
|
|
520
227
|
}, []);
|
|
521
|
-
const onThumbPointerMove =
|
|
228
|
+
const onThumbPointerMove = useCallback((e) => {
|
|
522
229
|
if (!isDraggingRef.current) return;
|
|
523
230
|
const el = scrollElRef.current;
|
|
524
231
|
const track = trackRef.current;
|
|
@@ -538,7 +245,7 @@ function useHorizontalScrollbar() {
|
|
|
538
245
|
syncThumbToDOM();
|
|
539
246
|
syncEdgeFades();
|
|
540
247
|
}, [syncThumbToDOM, syncEdgeFades]);
|
|
541
|
-
const onThumbPointerUp =
|
|
248
|
+
const onThumbPointerUp = useCallback((e) => {
|
|
542
249
|
isDraggingRef.current = false;
|
|
543
250
|
const target = e.currentTarget;
|
|
544
251
|
target.releasePointerCapture(e.pointerId);
|
|
@@ -561,7 +268,7 @@ function useHorizontalScrollbar() {
|
|
|
561
268
|
}
|
|
562
269
|
|
|
563
270
|
// src/hooks/ui/use-image-edge-color.ts
|
|
564
|
-
import { useState as
|
|
271
|
+
import { useState as useState3, useEffect as useEffect2 } from "react";
|
|
565
272
|
function extractEdgeColor(img) {
|
|
566
273
|
const canvas = document.createElement("canvas");
|
|
567
274
|
const ctx = canvas.getContext("2d");
|
|
@@ -603,51 +310,357 @@ function extractEdgeColor(img) {
|
|
|
603
310
|
}
|
|
604
311
|
}
|
|
605
312
|
}
|
|
606
|
-
if (buckets.size === 0) return "#000000";
|
|
607
|
-
let bestBucket = null;
|
|
608
|
-
for (const bucket of buckets.values()) {
|
|
609
|
-
if (!bestBucket || bucket.count > bestBucket.count) {
|
|
610
|
-
bestBucket = bucket;
|
|
611
|
-
}
|
|
313
|
+
if (buckets.size === 0) return "#000000";
|
|
314
|
+
let bestBucket = null;
|
|
315
|
+
for (const bucket of buckets.values()) {
|
|
316
|
+
if (!bestBucket || bucket.count > bestBucket.count) {
|
|
317
|
+
bestBucket = bucket;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (!bestBucket || bestBucket.count === 0) return "#000000";
|
|
321
|
+
const r = Math.round(bestBucket.r / bestBucket.count);
|
|
322
|
+
const g = Math.round(bestBucket.g / bestBucket.count);
|
|
323
|
+
const b = Math.round(bestBucket.b / bestBucket.count);
|
|
324
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
325
|
+
}
|
|
326
|
+
function useImageEdgeColor(imageUrl, fallback = "#000000") {
|
|
327
|
+
const [color, setColor] = useState3(fallback);
|
|
328
|
+
useEffect2(() => {
|
|
329
|
+
if (!imageUrl) {
|
|
330
|
+
setColor(fallback);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
let cancelled = false;
|
|
334
|
+
const img = new Image();
|
|
335
|
+
img.crossOrigin = "anonymous";
|
|
336
|
+
img.onload = () => {
|
|
337
|
+
if (cancelled) return;
|
|
338
|
+
try {
|
|
339
|
+
setColor(extractEdgeColor(img));
|
|
340
|
+
} catch {
|
|
341
|
+
setColor(fallback);
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
img.onerror = () => {
|
|
345
|
+
if (cancelled) return;
|
|
346
|
+
setColor(fallback);
|
|
347
|
+
};
|
|
348
|
+
img.src = imageUrl;
|
|
349
|
+
return () => {
|
|
350
|
+
cancelled = true;
|
|
351
|
+
};
|
|
352
|
+
}, [imageUrl, fallback]);
|
|
353
|
+
return color;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// src/hooks/ui/use-local-storage.ts
|
|
357
|
+
import { useEffect as useEffect3, useRef as useRef2, useState as useState4 } from "react";
|
|
358
|
+
function useLocalStorage(key, initialValue) {
|
|
359
|
+
const [storedValue, setStoredValue] = useState4(() => {
|
|
360
|
+
try {
|
|
361
|
+
if (typeof window !== "undefined") {
|
|
362
|
+
const item = window.localStorage.getItem(key);
|
|
363
|
+
return item ? JSON.parse(item) : initialValue;
|
|
364
|
+
}
|
|
365
|
+
} catch (error) {
|
|
366
|
+
console.error(`Error reading localStorage key "${key}":`, error);
|
|
367
|
+
}
|
|
368
|
+
return initialValue;
|
|
369
|
+
});
|
|
370
|
+
const isInitialized = useRef2(true);
|
|
371
|
+
const isFromStorageEvent = useRef2(false);
|
|
372
|
+
useEffect3(() => {
|
|
373
|
+
if (!isInitialized.current) return;
|
|
374
|
+
const handleStorageChange = (e) => {
|
|
375
|
+
if (e.key === key && e.newValue !== null) {
|
|
376
|
+
try {
|
|
377
|
+
const newValue = JSON.parse(e.newValue);
|
|
378
|
+
isFromStorageEvent.current = true;
|
|
379
|
+
setStoredValue(newValue);
|
|
380
|
+
console.log(`\u{1F504} Updated localStorage key "${key}" from storage event`);
|
|
381
|
+
} catch (error) {
|
|
382
|
+
console.error(`Error parsing storage event for key "${key}":`, error);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
const handleCustomStorageUpdate = (e) => {
|
|
387
|
+
if (e.detail.key === key) {
|
|
388
|
+
try {
|
|
389
|
+
if (e.detail.newValue === null || e.detail.newValue === void 0) {
|
|
390
|
+
isFromStorageEvent.current = true;
|
|
391
|
+
setStoredValue(initialValue);
|
|
392
|
+
console.log(`\u{1F504} Cleared localStorage key "${key}" from custom storage event`);
|
|
393
|
+
} else {
|
|
394
|
+
const newValue = JSON.parse(e.detail.newValue);
|
|
395
|
+
isFromStorageEvent.current = true;
|
|
396
|
+
setStoredValue(newValue);
|
|
397
|
+
console.log(`\u{1F504} Updated localStorage key "${key}" from custom storage event`);
|
|
398
|
+
}
|
|
399
|
+
} catch (error) {
|
|
400
|
+
console.error(`Error parsing custom storage event for key "${key}":`, error);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
window.addEventListener("storage", handleStorageChange);
|
|
405
|
+
window.addEventListener("localStorageUpdate", handleCustomStorageUpdate);
|
|
406
|
+
return () => {
|
|
407
|
+
window.removeEventListener("storage", handleStorageChange);
|
|
408
|
+
window.removeEventListener("localStorageUpdate", handleCustomStorageUpdate);
|
|
409
|
+
};
|
|
410
|
+
}, [key]);
|
|
411
|
+
useEffect3(() => {
|
|
412
|
+
if (!isInitialized.current) return;
|
|
413
|
+
if (isFromStorageEvent.current) {
|
|
414
|
+
isFromStorageEvent.current = false;
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
try {
|
|
418
|
+
if (typeof window !== "undefined") {
|
|
419
|
+
window.localStorage.setItem(key, JSON.stringify(storedValue));
|
|
420
|
+
}
|
|
421
|
+
} catch (error) {
|
|
422
|
+
console.error(`Error writing to localStorage key "${key}":`, error);
|
|
423
|
+
}
|
|
424
|
+
}, [key, storedValue]);
|
|
425
|
+
const setValue = (value) => {
|
|
426
|
+
try {
|
|
427
|
+
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
428
|
+
setStoredValue(valueToStore);
|
|
429
|
+
} catch (error) {
|
|
430
|
+
console.error(`Error setting value for localStorage key "${key}":`, error);
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
return [storedValue, setValue];
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// src/hooks/ui/use-media-query.ts
|
|
437
|
+
import { useLayoutEffect, useState as useState5 } from "react";
|
|
438
|
+
function useMediaQuery(query) {
|
|
439
|
+
const [matches, setMatches] = useState5(void 0);
|
|
440
|
+
useLayoutEffect(() => {
|
|
441
|
+
const matchMedia = window.matchMedia(query);
|
|
442
|
+
const handleChange = () => {
|
|
443
|
+
setMatches(matchMedia.matches);
|
|
444
|
+
};
|
|
445
|
+
handleChange();
|
|
446
|
+
matchMedia.addEventListener("change", handleChange);
|
|
447
|
+
return () => {
|
|
448
|
+
matchMedia.removeEventListener("change", handleChange);
|
|
449
|
+
};
|
|
450
|
+
}, [query]);
|
|
451
|
+
return matches;
|
|
452
|
+
}
|
|
453
|
+
var breakpoints = {
|
|
454
|
+
md: "(min-width: 800px)",
|
|
455
|
+
// Tablet: 50rem
|
|
456
|
+
lg: "(min-width: 1280px)"
|
|
457
|
+
// Desktop: 80rem
|
|
458
|
+
};
|
|
459
|
+
function useSmUp() {
|
|
460
|
+
return useMdUp();
|
|
461
|
+
}
|
|
462
|
+
function useMdUp() {
|
|
463
|
+
const matches = useMediaQuery(breakpoints.md);
|
|
464
|
+
return matches === void 0 ? void 0 : matches;
|
|
465
|
+
}
|
|
466
|
+
function useLgUp() {
|
|
467
|
+
const matches = useMediaQuery(breakpoints.lg);
|
|
468
|
+
return matches === void 0 ? void 0 : matches;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// src/hooks/ui/use-memoized-callback.ts
|
|
472
|
+
import { useCallback as useCallback2, useRef as useRef3 } from "react";
|
|
473
|
+
function useMemoizedCallback(callback, dependencies) {
|
|
474
|
+
const callbackRef = useRef3(callback);
|
|
475
|
+
const dependenciesRef = useRef3(dependencies);
|
|
476
|
+
callbackRef.current = callback;
|
|
477
|
+
const depsChanged = dependencies.some((dep, i) => !Object.is(dep, dependenciesRef.current[i]));
|
|
478
|
+
if (depsChanged) {
|
|
479
|
+
dependenciesRef.current = dependencies;
|
|
480
|
+
}
|
|
481
|
+
return useCallback2(((...args) => callbackRef.current(...args)), [depsChanged]);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// src/hooks/ui/use-notification-permission.ts
|
|
485
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useState as useState6 } from "react";
|
|
486
|
+
function useNotificationPermission() {
|
|
487
|
+
const [supported, setSupported] = useState6(false);
|
|
488
|
+
const [permission, setPermission] = useState6("default");
|
|
489
|
+
useEffect4(() => {
|
|
490
|
+
if (typeof window === "undefined" || !("Notification" in window)) return;
|
|
491
|
+
setSupported(true);
|
|
492
|
+
const sync = () => setPermission(Notification.permission);
|
|
493
|
+
sync();
|
|
494
|
+
let cancelled = false;
|
|
495
|
+
let status;
|
|
496
|
+
navigator.permissions?.query({ name: "notifications" }).then((s) => {
|
|
497
|
+
if (cancelled) return;
|
|
498
|
+
status = s;
|
|
499
|
+
s.addEventListener("change", sync);
|
|
500
|
+
}).catch(() => void 0);
|
|
501
|
+
document.addEventListener("visibilitychange", sync);
|
|
502
|
+
window.addEventListener("focus", sync);
|
|
503
|
+
return () => {
|
|
504
|
+
cancelled = true;
|
|
505
|
+
status?.removeEventListener("change", sync);
|
|
506
|
+
document.removeEventListener("visibilitychange", sync);
|
|
507
|
+
window.removeEventListener("focus", sync);
|
|
508
|
+
};
|
|
509
|
+
}, []);
|
|
510
|
+
const request = useCallback3(async () => {
|
|
511
|
+
if (typeof window === "undefined" || !("Notification" in window)) {
|
|
512
|
+
return "denied";
|
|
513
|
+
}
|
|
514
|
+
const result = await new Promise((resolve) => {
|
|
515
|
+
const maybePromise = Notification.requestPermission(resolve);
|
|
516
|
+
if (maybePromise && typeof maybePromise.then === "function") void maybePromise.then(resolve);
|
|
517
|
+
});
|
|
518
|
+
setPermission(Notification.permission);
|
|
519
|
+
return result;
|
|
520
|
+
}, []);
|
|
521
|
+
return { supported, permission, request };
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// src/hooks/ui/use-onboarding-state.ts
|
|
525
|
+
import { useState as useState7, useEffect as useEffect5, useCallback as useCallback4 } from "react";
|
|
526
|
+
|
|
527
|
+
// src/utils/onboarding-storage.ts
|
|
528
|
+
var DEFAULT_STATE = {
|
|
529
|
+
completedSteps: [],
|
|
530
|
+
skippedSteps: [],
|
|
531
|
+
dismissed: false,
|
|
532
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
533
|
+
};
|
|
534
|
+
function saveOnboardingState(key, state) {
|
|
535
|
+
if (typeof window === "undefined") return;
|
|
536
|
+
try {
|
|
537
|
+
localStorage.setItem(key, JSON.stringify(state));
|
|
538
|
+
console.log("\u{1F4BE} Saved onboarding state:", state);
|
|
539
|
+
if (typeof window !== "undefined") {
|
|
540
|
+
window.dispatchEvent(
|
|
541
|
+
new CustomEvent("localStorageUpdate", {
|
|
542
|
+
detail: { key, newValue: JSON.stringify(state) }
|
|
543
|
+
})
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
} catch (err) {
|
|
547
|
+
console.warn("[onboarding-storage] Failed saving to localStorage:", err);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
function loadOnboardingState(key) {
|
|
551
|
+
if (typeof window === "undefined") return DEFAULT_STATE;
|
|
552
|
+
try {
|
|
553
|
+
const raw = localStorage.getItem(key);
|
|
554
|
+
if (!raw) return DEFAULT_STATE;
|
|
555
|
+
const parsed = JSON.parse(raw);
|
|
556
|
+
return parsed;
|
|
557
|
+
} catch (err) {
|
|
558
|
+
console.warn("[onboarding-storage] Failed parsing localStorage data:", err);
|
|
559
|
+
return DEFAULT_STATE;
|
|
612
560
|
}
|
|
613
|
-
if (!bestBucket || bestBucket.count === 0) return "#000000";
|
|
614
|
-
const r = Math.round(bestBucket.r / bestBucket.count);
|
|
615
|
-
const g = Math.round(bestBucket.g / bestBucket.count);
|
|
616
|
-
const b = Math.round(bestBucket.b / bestBucket.count);
|
|
617
|
-
return `rgb(${r}, ${g}, ${b})`;
|
|
618
561
|
}
|
|
619
|
-
function
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
562
|
+
function markMultipleComplete(key, stepIds) {
|
|
563
|
+
const state = loadOnboardingState(key);
|
|
564
|
+
const newState = {
|
|
565
|
+
...state,
|
|
566
|
+
completedSteps: [.../* @__PURE__ */ new Set([...state.completedSteps, ...stepIds])],
|
|
567
|
+
skippedSteps: state.skippedSteps.filter((id) => !stepIds.includes(id)),
|
|
568
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
569
|
+
};
|
|
570
|
+
saveOnboardingState(key, newState);
|
|
571
|
+
return newState;
|
|
572
|
+
}
|
|
573
|
+
function markStepComplete(key, stepId) {
|
|
574
|
+
return markMultipleComplete(key, [stepId]);
|
|
575
|
+
}
|
|
576
|
+
function markStepSkipped(key, stepId) {
|
|
577
|
+
const state = loadOnboardingState(key);
|
|
578
|
+
const newState = {
|
|
579
|
+
...state,
|
|
580
|
+
skippedSteps: [.../* @__PURE__ */ new Set([...state.skippedSteps, stepId])],
|
|
581
|
+
completedSteps: state.completedSteps.filter((id) => id !== stepId),
|
|
582
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
583
|
+
};
|
|
584
|
+
saveOnboardingState(key, newState);
|
|
585
|
+
return newState;
|
|
586
|
+
}
|
|
587
|
+
function dismissOnboarding(key) {
|
|
588
|
+
const state = loadOnboardingState(key);
|
|
589
|
+
const newState = {
|
|
590
|
+
...state,
|
|
591
|
+
dismissed: true,
|
|
592
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
593
|
+
};
|
|
594
|
+
saveOnboardingState(key, newState);
|
|
595
|
+
return newState;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// src/hooks/ui/use-onboarding-state.ts
|
|
599
|
+
function useOnboardingState(storageKey = "openframe-onboarding-state") {
|
|
600
|
+
const [state, setState] = useState7(() => loadOnboardingState(storageKey));
|
|
601
|
+
const [, forceUpdate] = useState7(0);
|
|
602
|
+
useEffect5(() => {
|
|
603
|
+
const handleStorageUpdate = (e) => {
|
|
604
|
+
if (e.detail.key === storageKey) {
|
|
605
|
+
const newState = loadOnboardingState(storageKey);
|
|
606
|
+
setState(newState);
|
|
607
|
+
forceUpdate((prev) => prev + 1);
|
|
608
|
+
console.log("\u{1F504} State updated from storage event:", newState);
|
|
635
609
|
}
|
|
636
610
|
};
|
|
637
|
-
|
|
638
|
-
if (cancelled) return;
|
|
639
|
-
setColor(fallback);
|
|
640
|
-
};
|
|
641
|
-
img.src = imageUrl;
|
|
611
|
+
window.addEventListener("localStorageUpdate", handleStorageUpdate);
|
|
642
612
|
return () => {
|
|
643
|
-
|
|
613
|
+
window.removeEventListener("localStorageUpdate", handleStorageUpdate);
|
|
644
614
|
};
|
|
645
|
-
}, [
|
|
646
|
-
|
|
615
|
+
}, [storageKey]);
|
|
616
|
+
const markComplete = useCallback4((stepId) => {
|
|
617
|
+
console.log(`\u{1F3AF} markComplete called for: "${stepId}"`);
|
|
618
|
+
const newState = markStepComplete(storageKey, stepId);
|
|
619
|
+
setState(newState);
|
|
620
|
+
forceUpdate((prev) => prev + 1);
|
|
621
|
+
}, [storageKey]);
|
|
622
|
+
const markSkipped = useCallback4((stepId) => {
|
|
623
|
+
console.log(`\u23ED\uFE0F markSkipped called for: "${stepId}"`);
|
|
624
|
+
const newState = markStepSkipped(storageKey, stepId);
|
|
625
|
+
setState(newState);
|
|
626
|
+
forceUpdate((prev) => prev + 1);
|
|
627
|
+
}, [storageKey]);
|
|
628
|
+
const dismissOnboarding2 = useCallback4(() => {
|
|
629
|
+
console.log(`\u{1F6AB} dismissOnboarding called`);
|
|
630
|
+
const newState = dismissOnboarding(storageKey);
|
|
631
|
+
setState(newState);
|
|
632
|
+
forceUpdate((prev) => prev + 1);
|
|
633
|
+
}, [storageKey]);
|
|
634
|
+
const markMultipleComplete2 = useCallback4((stepIds) => {
|
|
635
|
+
console.log(`\u{1F3AF} markMultipleComplete called for:`, stepIds);
|
|
636
|
+
const newState = markMultipleComplete(storageKey, stepIds);
|
|
637
|
+
setState(newState);
|
|
638
|
+
forceUpdate((prev) => prev + 1);
|
|
639
|
+
console.log(`\u{1F4DD} State after batch:`, newState);
|
|
640
|
+
}, [storageKey]);
|
|
641
|
+
const isStepComplete = useCallback4((stepId) => {
|
|
642
|
+
return state.completedSteps.includes(stepId);
|
|
643
|
+
}, [state.completedSteps]);
|
|
644
|
+
const isStepSkipped = useCallback4((stepId) => {
|
|
645
|
+
return state.skippedSteps.includes(stepId);
|
|
646
|
+
}, [state.skippedSteps]);
|
|
647
|
+
const allStepsComplete = useCallback4((steps) => {
|
|
648
|
+
return steps.every((step) => isStepComplete(step.id) || isStepSkipped(step.id));
|
|
649
|
+
}, [isStepComplete, isStepSkipped]);
|
|
650
|
+
return {
|
|
651
|
+
state,
|
|
652
|
+
markComplete,
|
|
653
|
+
markSkipped,
|
|
654
|
+
dismissOnboarding: dismissOnboarding2,
|
|
655
|
+
isStepComplete,
|
|
656
|
+
isStepSkipped,
|
|
657
|
+
allStepsComplete,
|
|
658
|
+
markMultipleComplete: markMultipleComplete2
|
|
659
|
+
};
|
|
647
660
|
}
|
|
648
661
|
|
|
649
662
|
// src/hooks/ui/use-search.ts
|
|
650
|
-
import { useState as useState8, useEffect as
|
|
663
|
+
import { useState as useState8, useEffect as useEffect6, useCallback as useCallback5 } from "react";
|
|
651
664
|
function useSearch(config) {
|
|
652
665
|
const { searchFn, mapResult, debounceMs = 300, minQueryLength = 2 } = config;
|
|
653
666
|
const [query, setQuery] = useState8("");
|
|
@@ -655,11 +668,11 @@ function useSearch(config) {
|
|
|
655
668
|
const [isLoading, setIsLoading] = useState8(false);
|
|
656
669
|
const [error, setError] = useState8(null);
|
|
657
670
|
const debouncedQuery = useDebounce(query, debounceMs);
|
|
658
|
-
const clearResults =
|
|
671
|
+
const clearResults = useCallback5(() => {
|
|
659
672
|
setResults([]);
|
|
660
673
|
setError(null);
|
|
661
674
|
}, []);
|
|
662
|
-
|
|
675
|
+
useEffect6(() => {
|
|
663
676
|
if (!debouncedQuery || debouncedQuery.length < minQueryLength) {
|
|
664
677
|
setResults([]);
|
|
665
678
|
setIsLoading(false);
|
|
@@ -694,8 +707,93 @@ function useSearch(config) {
|
|
|
694
707
|
return { query, setQuery, results, isLoading, error, clearResults };
|
|
695
708
|
}
|
|
696
709
|
|
|
710
|
+
// src/hooks/ui/use-table-pagination.ts
|
|
711
|
+
import { useMemo } from "react";
|
|
712
|
+
function useTablePagination(config) {
|
|
713
|
+
return useMemo(() => {
|
|
714
|
+
if (!config) return void 0;
|
|
715
|
+
if (config.type === "client") {
|
|
716
|
+
if (config.totalPages <= 1) return void 0;
|
|
717
|
+
return {
|
|
718
|
+
hasNextPage: config.currentPage < config.totalPages,
|
|
719
|
+
hasPreviousPage: config.currentPage > 1,
|
|
720
|
+
isFirstPage: config.currentPage === 1,
|
|
721
|
+
startCursor: (config.currentPage - 1).toString(),
|
|
722
|
+
endCursor: config.currentPage.toString(),
|
|
723
|
+
currentCount: config.itemCount,
|
|
724
|
+
itemName: config.itemName || "items",
|
|
725
|
+
onNext: () => config.onNext(),
|
|
726
|
+
onPrevious: () => config.onPrevious(),
|
|
727
|
+
showInfo: config.showInfo ?? true
|
|
728
|
+
};
|
|
729
|
+
} else {
|
|
730
|
+
return {
|
|
731
|
+
hasNextPage: config.hasNextPage,
|
|
732
|
+
hasPreviousPage: config.hasLoadedBeyondFirst,
|
|
733
|
+
isFirstPage: !config.hasLoadedBeyondFirst,
|
|
734
|
+
startCursor: config.startCursor,
|
|
735
|
+
endCursor: config.endCursor,
|
|
736
|
+
currentCount: config.itemCount,
|
|
737
|
+
itemName: config.itemName || "items",
|
|
738
|
+
onNext: config.onNext,
|
|
739
|
+
onPrevious: config.onReset,
|
|
740
|
+
// Previous button goes back to first page
|
|
741
|
+
showInfo: config.showInfo ?? true
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
}, [config]);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// src/hooks/ui/use-throttle.ts
|
|
748
|
+
import { useState as useState9, useEffect as useEffect7, useRef as useRef4 } from "react";
|
|
749
|
+
function useThrottle(value, limit = 200) {
|
|
750
|
+
const [throttledValue, setThrottledValue] = useState9(value);
|
|
751
|
+
const lastUpdated = useRef4(Date.now());
|
|
752
|
+
useEffect7(() => {
|
|
753
|
+
const now = Date.now();
|
|
754
|
+
const elapsed = now - lastUpdated.current;
|
|
755
|
+
if (elapsed >= limit) {
|
|
756
|
+
setThrottledValue(value);
|
|
757
|
+
lastUpdated.current = now;
|
|
758
|
+
} else {
|
|
759
|
+
const timerId = setTimeout(() => {
|
|
760
|
+
setThrottledValue(value);
|
|
761
|
+
lastUpdated.current = Date.now();
|
|
762
|
+
}, limit - elapsed);
|
|
763
|
+
return () => {
|
|
764
|
+
clearTimeout(timerId);
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
}, [value, limit]);
|
|
768
|
+
return throttledValue;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// src/hooks/ui/use-window-size.ts
|
|
772
|
+
import { useLayoutEffect as useLayoutEffect2, useState as useState10 } from "react";
|
|
773
|
+
function useWindowSize() {
|
|
774
|
+
const [windowSize, setWindowSize] = useState10({
|
|
775
|
+
width: 0,
|
|
776
|
+
height: 0
|
|
777
|
+
});
|
|
778
|
+
const [isClient, setIsClient] = useState10(false);
|
|
779
|
+
useLayoutEffect2(() => {
|
|
780
|
+
setIsClient(true);
|
|
781
|
+
if (!isClient) return;
|
|
782
|
+
const handleResize = () => {
|
|
783
|
+
setWindowSize({
|
|
784
|
+
width: window.innerWidth,
|
|
785
|
+
height: window.innerHeight
|
|
786
|
+
});
|
|
787
|
+
};
|
|
788
|
+
handleResize();
|
|
789
|
+
window.addEventListener("resize", handleResize);
|
|
790
|
+
return () => window.removeEventListener("resize", handleResize);
|
|
791
|
+
}, [isClient]);
|
|
792
|
+
return windowSize;
|
|
793
|
+
}
|
|
794
|
+
|
|
697
795
|
// src/hooks/platform/use-platform-config.ts
|
|
698
|
-
import { useState as
|
|
796
|
+
import { useState as useState11, useEffect as useEffect8 } from "react";
|
|
699
797
|
|
|
700
798
|
// src/utils/platform-config.tsx
|
|
701
799
|
import { Globe } from "lucide-react";
|
|
@@ -873,10 +971,10 @@ function getPlatformIconComponent(platformName, className = "h-6 w-6") {
|
|
|
873
971
|
var platformCache = null;
|
|
874
972
|
var fetchPromise = null;
|
|
875
973
|
function usePlatformConfig() {
|
|
876
|
-
const [platforms, setPlatforms] =
|
|
877
|
-
const [isLoading, setIsLoading] =
|
|
878
|
-
const [error, setError] =
|
|
879
|
-
|
|
974
|
+
const [platforms, setPlatforms] = useState11(platformCache || []);
|
|
975
|
+
const [isLoading, setIsLoading] = useState11(!platformCache);
|
|
976
|
+
const [error, setError] = useState11(null);
|
|
977
|
+
useEffect8(() => {
|
|
880
978
|
if (platformCache) {
|
|
881
979
|
setPlatforms(platformCache);
|
|
882
980
|
setIsLoading(false);
|
|
@@ -1325,16 +1423,16 @@ var useToast = () => ({
|
|
|
1325
1423
|
});
|
|
1326
1424
|
|
|
1327
1425
|
// src/hooks/use-contact-submission.ts
|
|
1328
|
-
import { useState as
|
|
1426
|
+
import { useState as useState13, useCallback as useCallback6, useEffect as useEffect9 } from "react";
|
|
1329
1427
|
init_next_navigation();
|
|
1330
1428
|
function useContactSubmission(options = {}) {
|
|
1331
1429
|
const { userId, successRedirectUrl, successToastMessage, onSuccess } = options;
|
|
1332
1430
|
const { toast: toast2 } = useToast();
|
|
1333
1431
|
const router = useRouter();
|
|
1334
1432
|
const { contactUrl } = useRequiredEndpointsRuntime();
|
|
1335
|
-
const [isSubmitting, setIsSubmitting] =
|
|
1336
|
-
const [isSuccess, setIsSuccess] =
|
|
1337
|
-
const submit =
|
|
1433
|
+
const [isSubmitting, setIsSubmitting] = useState13(false);
|
|
1434
|
+
const [isSuccess, setIsSuccess] = useState13(false);
|
|
1435
|
+
const submit = useCallback6(async (formData) => {
|
|
1338
1436
|
if (isSubmitting) return;
|
|
1339
1437
|
setIsSubmitting(true);
|
|
1340
1438
|
try {
|
|
@@ -1369,7 +1467,7 @@ function useContactSubmission(options = {}) {
|
|
|
1369
1467
|
setIsSubmitting(false);
|
|
1370
1468
|
}
|
|
1371
1469
|
}, [isSubmitting, toast2, userId, successToastMessage, contactUrl]);
|
|
1372
|
-
|
|
1470
|
+
useEffect9(() => {
|
|
1373
1471
|
if (isSuccess && successRedirectUrl) {
|
|
1374
1472
|
console.log("\u{1F680} Contact submission successful, redirecting to:", successRedirectUrl);
|
|
1375
1473
|
const timer = setTimeout(() => {
|
|
@@ -1383,7 +1481,7 @@ function useContactSubmission(options = {}) {
|
|
|
1383
1481
|
return () => clearTimeout(timer);
|
|
1384
1482
|
}
|
|
1385
1483
|
}, [isSuccess, successRedirectUrl, router]);
|
|
1386
|
-
|
|
1484
|
+
useEffect9(() => {
|
|
1387
1485
|
if (isSuccess && onSuccess) {
|
|
1388
1486
|
onSuccess();
|
|
1389
1487
|
}
|
|
@@ -1392,19 +1490,19 @@ function useContactSubmission(options = {}) {
|
|
|
1392
1490
|
}
|
|
1393
1491
|
|
|
1394
1492
|
// src/hooks/use-quick-action-hint.ts
|
|
1395
|
-
import { useEffect as
|
|
1493
|
+
import { useEffect as useEffect10, useState as useState14, useRef as useRef5, useCallback as useCallback7 } from "react";
|
|
1396
1494
|
function useQuickActionHint({
|
|
1397
1495
|
actionCount,
|
|
1398
1496
|
cycleDuration = 5e3,
|
|
1399
1497
|
enabled = true
|
|
1400
1498
|
}) {
|
|
1401
|
-
const [activeHintIndex, setActiveHintIndex] =
|
|
1499
|
+
const [activeHintIndex, setActiveHintIndex] = useState14(-1);
|
|
1402
1500
|
const containerRef = useRef5(null);
|
|
1403
1501
|
const timeoutRef = useRef5(null);
|
|
1404
1502
|
const cycleCountRef = useRef5(0);
|
|
1405
1503
|
const currentIndexRef = useRef5(0);
|
|
1406
1504
|
const sequenceRef = useRef5([]);
|
|
1407
|
-
const shuffleIndices =
|
|
1505
|
+
const shuffleIndices = useCallback7((length) => {
|
|
1408
1506
|
const indices = Array.from({ length }, (_, i) => i);
|
|
1409
1507
|
for (let i = indices.length - 1; i > 0; i--) {
|
|
1410
1508
|
const j = Math.floor(Math.random() * (i + 1));
|
|
@@ -1412,7 +1510,7 @@ function useQuickActionHint({
|
|
|
1412
1510
|
}
|
|
1413
1511
|
return indices;
|
|
1414
1512
|
}, []);
|
|
1415
|
-
const stopHint =
|
|
1513
|
+
const stopHint = useCallback7(() => {
|
|
1416
1514
|
if (timeoutRef.current) {
|
|
1417
1515
|
clearTimeout(timeoutRef.current);
|
|
1418
1516
|
timeoutRef.current = null;
|
|
@@ -1422,7 +1520,7 @@ function useQuickActionHint({
|
|
|
1422
1520
|
currentIndexRef.current = 0;
|
|
1423
1521
|
sequenceRef.current = [];
|
|
1424
1522
|
}, []);
|
|
1425
|
-
const advanceHint =
|
|
1523
|
+
const advanceHint = useCallback7(() => {
|
|
1426
1524
|
if (currentIndexRef.current === 0) {
|
|
1427
1525
|
sequenceRef.current = shuffleIndices(actionCount);
|
|
1428
1526
|
}
|
|
@@ -1435,7 +1533,7 @@ function useQuickActionHint({
|
|
|
1435
1533
|
}
|
|
1436
1534
|
timeoutRef.current = setTimeout(advanceHint, cycleDuration);
|
|
1437
1535
|
}, [actionCount, cycleDuration, shuffleIndices]);
|
|
1438
|
-
|
|
1536
|
+
useEffect10(() => {
|
|
1439
1537
|
if (!enabled || actionCount === 0) {
|
|
1440
1538
|
return;
|
|
1441
1539
|
}
|
|
@@ -1461,7 +1559,7 @@ function useQuickActionHint({
|
|
|
1461
1559
|
}
|
|
1462
1560
|
|
|
1463
1561
|
// src/hooks/use-copy-to-clipboard.ts
|
|
1464
|
-
import { useCallback as
|
|
1562
|
+
import { useCallback as useCallback8, useState as useState15 } from "react";
|
|
1465
1563
|
function useCopyToClipboard({
|
|
1466
1564
|
successTitle = "Copied",
|
|
1467
1565
|
successDescription = "Copied to clipboard",
|
|
@@ -1470,8 +1568,8 @@ function useCopyToClipboard({
|
|
|
1470
1568
|
resetDelay = 2e3
|
|
1471
1569
|
} = {}) {
|
|
1472
1570
|
const { toast: toast2 } = useToast();
|
|
1473
|
-
const [copied, setCopied] =
|
|
1474
|
-
const copy =
|
|
1571
|
+
const [copied, setCopied] = useState15(false);
|
|
1572
|
+
const copy = useCallback8(
|
|
1475
1573
|
async (text) => {
|
|
1476
1574
|
try {
|
|
1477
1575
|
await navigator.clipboard.writeText(text);
|
|
@@ -1488,7 +1586,7 @@ function useCopyToClipboard({
|
|
|
1488
1586
|
}
|
|
1489
1587
|
|
|
1490
1588
|
// src/hooks/use-batch-images.ts
|
|
1491
|
-
import { useEffect as
|
|
1589
|
+
import { useEffect as useEffect11, useMemo as useMemo2, useState as useState16, useRef as useRef6 } from "react";
|
|
1492
1590
|
var globalBatchImageConfig = {};
|
|
1493
1591
|
function configureBatchImageFetch(config) {
|
|
1494
1592
|
globalBatchImageConfig = { ...globalBatchImageConfig, ...config };
|
|
@@ -1561,14 +1659,14 @@ async function batchFetchAuthenticatedImages(imageUrls, config) {
|
|
|
1561
1659
|
return results;
|
|
1562
1660
|
}
|
|
1563
1661
|
function useBatchImages(imageUrls, config) {
|
|
1564
|
-
const [fetchedImages, setFetchedImages] =
|
|
1565
|
-
const [loading, setLoading] =
|
|
1662
|
+
const [fetchedImages, setFetchedImages] = useState16({});
|
|
1663
|
+
const [loading, setLoading] = useState16(false);
|
|
1566
1664
|
const uniqueUrls = useMemo2(
|
|
1567
1665
|
() => Array.from(new Set(imageUrls.filter((url) => Boolean(url)))),
|
|
1568
1666
|
[imageUrls]
|
|
1569
1667
|
);
|
|
1570
1668
|
const requestedUrls = useRef6(/* @__PURE__ */ new Set());
|
|
1571
|
-
|
|
1669
|
+
useEffect11(() => {
|
|
1572
1670
|
if (uniqueUrls.length === 0) {
|
|
1573
1671
|
setFetchedImages({});
|
|
1574
1672
|
return;
|
|
@@ -1598,7 +1696,7 @@ function useBatchImages(imageUrls, config) {
|
|
|
1598
1696
|
}
|
|
1599
1697
|
|
|
1600
1698
|
// src/hooks/use-authenticated-image.ts
|
|
1601
|
-
import { useEffect as
|
|
1699
|
+
import { useEffect as useEffect12, useState as useState17, useRef as useRef7 } from "react";
|
|
1602
1700
|
var globalImageConfig = {};
|
|
1603
1701
|
var imageCache = /* @__PURE__ */ new Map();
|
|
1604
1702
|
var pendingRequests = /* @__PURE__ */ new Map();
|
|
@@ -1627,11 +1725,11 @@ function getImageConfig() {
|
|
|
1627
1725
|
};
|
|
1628
1726
|
}
|
|
1629
1727
|
function useAuthenticatedImage(imageUrl, refreshKey, config) {
|
|
1630
|
-
const [fetchedImageUrl, setFetchedImageUrl] =
|
|
1631
|
-
const [isLoading, setIsLoading] =
|
|
1632
|
-
const [error, setError] =
|
|
1728
|
+
const [fetchedImageUrl, setFetchedImageUrl] = useState17();
|
|
1729
|
+
const [isLoading, setIsLoading] = useState17(false);
|
|
1730
|
+
const [error, setError] = useState17(null);
|
|
1633
1731
|
const currentCacheKeyRef = useRef7(null);
|
|
1634
|
-
|
|
1732
|
+
useEffect12(() => {
|
|
1635
1733
|
if (!imageUrl) {
|
|
1636
1734
|
setFetchedImageUrl(void 0);
|
|
1637
1735
|
setIsLoading(false);
|
|
@@ -1742,7 +1840,7 @@ function useAuthenticatedImage(imageUrl, refreshKey, config) {
|
|
|
1742
1840
|
});
|
|
1743
1841
|
pendingRequests.set(cacheKey, fetchPromise2);
|
|
1744
1842
|
}, [imageUrl, refreshKey, config]);
|
|
1745
|
-
|
|
1843
|
+
useEffect12(() => {
|
|
1746
1844
|
return () => {
|
|
1747
1845
|
if (currentCacheKeyRef.current) {
|
|
1748
1846
|
const entry = imageCache.get(currentCacheKeyRef.current);
|
|
@@ -1757,7 +1855,7 @@ function useAuthenticatedImage(imageUrl, refreshKey, config) {
|
|
|
1757
1855
|
|
|
1758
1856
|
// src/hooks/state/use-query-params.ts
|
|
1759
1857
|
init_next_navigation();
|
|
1760
|
-
import { useEffect as
|
|
1858
|
+
import { useEffect as useEffect13, useState as useState18, useMemo as useMemo3, useCallback as useCallback9 } from "react";
|
|
1761
1859
|
|
|
1762
1860
|
// src/hooks/state/graphql-parser.ts
|
|
1763
1861
|
import {
|
|
@@ -2219,14 +2317,14 @@ var introspector = new GraphQLIntrospector();
|
|
|
2219
2317
|
function useQueryParams(query, options = {}) {
|
|
2220
2318
|
const router = useRouter();
|
|
2221
2319
|
const searchParams = useSearchParams();
|
|
2222
|
-
const [isLoading, setIsLoading] =
|
|
2223
|
-
const [isReady, setIsReady] =
|
|
2224
|
-
const [error, setError] =
|
|
2225
|
-
const [schema, setSchema] =
|
|
2320
|
+
const [isLoading, setIsLoading] = useState18(true);
|
|
2321
|
+
const [isReady, setIsReady] = useState18(false);
|
|
2322
|
+
const [error, setError] = useState18(null);
|
|
2323
|
+
const [schema, setSchema] = useState18({});
|
|
2226
2324
|
const defaultValues = options.defaultValues || {};
|
|
2227
2325
|
const skipIntrospection = options.skipIntrospection || false;
|
|
2228
2326
|
const debug = options.debug || false;
|
|
2229
|
-
|
|
2327
|
+
useEffect13(() => {
|
|
2230
2328
|
async function initialize() {
|
|
2231
2329
|
try {
|
|
2232
2330
|
if (debug) console.log("[useQueryParams] Initializing...");
|
|
@@ -2296,14 +2394,14 @@ function useQueryParams(query, options = {}) {
|
|
|
2296
2394
|
});
|
|
2297
2395
|
return result;
|
|
2298
2396
|
}, [searchParams]);
|
|
2299
|
-
const updateUrl =
|
|
2397
|
+
const updateUrl = useCallback9((newParams) => {
|
|
2300
2398
|
const url = newParams.toString() ? `?${newParams.toString()}` : window.location.pathname;
|
|
2301
2399
|
if (debug) {
|
|
2302
2400
|
console.log("[useQueryParams] Updating URL:", url);
|
|
2303
2401
|
}
|
|
2304
2402
|
router.replace(url, { scroll: false });
|
|
2305
2403
|
}, [router, debug]);
|
|
2306
|
-
const setParam =
|
|
2404
|
+
const setParam = useCallback9((key, value) => {
|
|
2307
2405
|
if (!isReady) {
|
|
2308
2406
|
console.warn("[useQueryParams] Schema not ready, cannot set param");
|
|
2309
2407
|
return;
|
|
@@ -2317,7 +2415,7 @@ function useQueryParams(query, options = {}) {
|
|
|
2317
2415
|
console.error("[useQueryParams] Failed to set param:", err);
|
|
2318
2416
|
}
|
|
2319
2417
|
}, [variables, schema, isReady, updateUrl]);
|
|
2320
|
-
const setParams =
|
|
2418
|
+
const setParams = useCallback9((updates) => {
|
|
2321
2419
|
if (!isReady) {
|
|
2322
2420
|
console.warn("[useQueryParams] Schema not ready, cannot set params");
|
|
2323
2421
|
return;
|
|
@@ -2331,7 +2429,7 @@ function useQueryParams(query, options = {}) {
|
|
|
2331
2429
|
console.error("[useQueryParams] Failed to set params:", err);
|
|
2332
2430
|
}
|
|
2333
2431
|
}, [variables, schema, isReady, updateUrl]);
|
|
2334
|
-
const clearParamsHandler =
|
|
2432
|
+
const clearParamsHandler = useCallback9((keys) => {
|
|
2335
2433
|
if (!isReady) {
|
|
2336
2434
|
console.warn("[useQueryParams] Schema not ready, cannot clear params");
|
|
2337
2435
|
return;
|
|
@@ -2345,7 +2443,7 @@ function useQueryParams(query, options = {}) {
|
|
|
2345
2443
|
console.error("[useQueryParams] Failed to clear params:", err);
|
|
2346
2444
|
}
|
|
2347
2445
|
}, [variables, schema, isReady, updateUrl]);
|
|
2348
|
-
const resetParams =
|
|
2446
|
+
const resetParams = useCallback9(() => {
|
|
2349
2447
|
if (debug) {
|
|
2350
2448
|
console.log("[useQueryParams] Resetting params");
|
|
2351
2449
|
}
|
|
@@ -2378,7 +2476,7 @@ function applyParamMapping(schema, mapping) {
|
|
|
2378
2476
|
|
|
2379
2477
|
// src/hooks/state/use-api-params.ts
|
|
2380
2478
|
init_next_navigation();
|
|
2381
|
-
import { useCallback as
|
|
2479
|
+
import { useCallback as useCallback10, useMemo as useMemo4, useRef as useRef8 } from "react";
|
|
2382
2480
|
function useContentStable(value, key) {
|
|
2383
2481
|
const ref = useRef8(void 0);
|
|
2384
2482
|
if (ref.current && ref.current.key === key) return ref.current.value;
|
|
@@ -2437,7 +2535,7 @@ function useApiParams(schema, options = {}) {
|
|
|
2437
2535
|
prevParamsRef.current = result;
|
|
2438
2536
|
return result;
|
|
2439
2537
|
}, [searchString, schemaKey, debug]);
|
|
2440
|
-
const addParamToSearchParams =
|
|
2538
|
+
const addParamToSearchParams = useCallback10((searchParams, key, value) => {
|
|
2441
2539
|
if (value === void 0 || value === "" || value === null) {
|
|
2442
2540
|
return;
|
|
2443
2541
|
}
|
|
@@ -2465,7 +2563,7 @@ function useApiParams(schema, options = {}) {
|
|
|
2465
2563
|
}
|
|
2466
2564
|
return newParams;
|
|
2467
2565
|
}, [params, schemaKey, flattenedSchema, addParamToSearchParams]);
|
|
2468
|
-
const updateUrl =
|
|
2566
|
+
const updateUrl = useCallback10((newParams, keysToRemove = []) => {
|
|
2469
2567
|
const finalParams = new URLSearchParams(searchString);
|
|
2470
2568
|
keysToRemove.forEach((key) => {
|
|
2471
2569
|
if (key in stableSchema) {
|
|
@@ -2501,7 +2599,7 @@ function useApiParams(schema, options = {}) {
|
|
|
2501
2599
|
}
|
|
2502
2600
|
return false;
|
|
2503
2601
|
};
|
|
2504
|
-
const setParam =
|
|
2602
|
+
const setParam = useCallback10((key, value) => {
|
|
2505
2603
|
const config = stableSchema[key];
|
|
2506
2604
|
if (!config) {
|
|
2507
2605
|
console.warn(`[useApiParams] Unknown parameter: ${key}`);
|
|
@@ -2515,7 +2613,7 @@ function useApiParams(schema, options = {}) {
|
|
|
2515
2613
|
updateUrl(newParams);
|
|
2516
2614
|
}
|
|
2517
2615
|
}, [schemaKey, updateUrl, addParamToSearchParams]);
|
|
2518
|
-
const setParams =
|
|
2616
|
+
const setParams = useCallback10((updates) => {
|
|
2519
2617
|
const newParams = new URLSearchParams();
|
|
2520
2618
|
const keysToRemove = [];
|
|
2521
2619
|
for (const [key, value] of Object.entries(updates)) {
|
|
@@ -2532,11 +2630,11 @@ function useApiParams(schema, options = {}) {
|
|
|
2532
2630
|
}
|
|
2533
2631
|
updateUrl(newParams, keysToRemove);
|
|
2534
2632
|
}, [schemaKey, updateUrl, addParamToSearchParams]);
|
|
2535
|
-
const clearParams2 =
|
|
2633
|
+
const clearParams2 = useCallback10((keys) => {
|
|
2536
2634
|
const newParams = new URLSearchParams();
|
|
2537
2635
|
updateUrl(newParams, keys);
|
|
2538
2636
|
}, [updateUrl]);
|
|
2539
|
-
const resetParams =
|
|
2637
|
+
const resetParams = useCallback10(() => {
|
|
2540
2638
|
if (debug) {
|
|
2541
2639
|
console.log("[useApiParams] Resetting params");
|
|
2542
2640
|
}
|
|
@@ -2573,7 +2671,7 @@ function createSearchParams(params) {
|
|
|
2573
2671
|
}
|
|
2574
2672
|
|
|
2575
2673
|
// src/hooks/state/use-cursor-pagination-state.ts
|
|
2576
|
-
import { useCallback as
|
|
2674
|
+
import { useCallback as useCallback11, useEffect as useEffect14, useRef as useRef9, useState as useState19 } from "react";
|
|
2577
2675
|
var urlSchema = {
|
|
2578
2676
|
search: { type: "string", default: "" },
|
|
2579
2677
|
cursor: { type: "string", default: "" }
|
|
@@ -2584,13 +2682,13 @@ function useCursorPaginationState(options) {
|
|
|
2584
2682
|
onSearchChange
|
|
2585
2683
|
} = options;
|
|
2586
2684
|
const { params, setParam, setParams } = useApiParams(urlSchema);
|
|
2587
|
-
const [searchInput, setSearchInput] =
|
|
2588
|
-
const [hasLoadedBeyondFirst, setHasLoadedBeyondFirst] =
|
|
2589
|
-
const [initialLoadCount, setInitialLoadCount] =
|
|
2685
|
+
const [searchInput, setSearchInput] = useState19(params.search || "");
|
|
2686
|
+
const [hasLoadedBeyondFirst, setHasLoadedBeyondFirst] = useState19(false);
|
|
2687
|
+
const [initialLoadCount, setInitialLoadCount] = useState19(0);
|
|
2590
2688
|
const lastSearchRef = useRef9(null);
|
|
2591
2689
|
const isSyncingFromUrl = useRef9(false);
|
|
2592
2690
|
const isInitialLoadInProgress = useRef9(true);
|
|
2593
|
-
|
|
2691
|
+
useEffect14(() => {
|
|
2594
2692
|
if (isInitialLoadInProgress.current) return;
|
|
2595
2693
|
const urlSearch = params.search || "";
|
|
2596
2694
|
if (urlSearch !== searchInput) {
|
|
@@ -2601,7 +2699,7 @@ function useCursorPaginationState(options) {
|
|
|
2601
2699
|
}, 0);
|
|
2602
2700
|
}
|
|
2603
2701
|
}, [params.search, initialLoadCount]);
|
|
2604
|
-
|
|
2702
|
+
useEffect14(() => {
|
|
2605
2703
|
if (isInitialLoadInProgress.current) return;
|
|
2606
2704
|
if (isSyncingFromUrl.current) return;
|
|
2607
2705
|
if (searchInput !== params.search) {
|
|
@@ -2612,7 +2710,7 @@ function useCursorPaginationState(options) {
|
|
|
2612
2710
|
});
|
|
2613
2711
|
}
|
|
2614
2712
|
}, [searchInput, params.search, setParams, initialLoadCount]);
|
|
2615
|
-
|
|
2713
|
+
useEffect14(() => {
|
|
2616
2714
|
if (initialLoadCount === 0) {
|
|
2617
2715
|
const cursor = params.cursor || null;
|
|
2618
2716
|
const search = params.search || "";
|
|
@@ -2626,7 +2724,7 @@ function useCursorPaginationState(options) {
|
|
|
2626
2724
|
});
|
|
2627
2725
|
}
|
|
2628
2726
|
}, []);
|
|
2629
|
-
|
|
2727
|
+
useEffect14(() => {
|
|
2630
2728
|
if (isInitialLoadInProgress.current) return;
|
|
2631
2729
|
if (initialLoadCount === 0) return;
|
|
2632
2730
|
const currentSearch = params.search || "";
|
|
@@ -2636,7 +2734,7 @@ function useCursorPaginationState(options) {
|
|
|
2636
2734
|
onSearchChange(currentSearch);
|
|
2637
2735
|
}
|
|
2638
2736
|
}, [params.search, onSearchChange, initialLoadCount]);
|
|
2639
|
-
const handleNextPage =
|
|
2737
|
+
const handleNextPage = useCallback11(
|
|
2640
2738
|
async (endCursor, fetchFn) => {
|
|
2641
2739
|
setParam("cursor", endCursor);
|
|
2642
2740
|
await fetchFn();
|
|
@@ -2644,7 +2742,7 @@ function useCursorPaginationState(options) {
|
|
|
2644
2742
|
},
|
|
2645
2743
|
[setParam]
|
|
2646
2744
|
);
|
|
2647
|
-
const handleResetToFirstPage =
|
|
2745
|
+
const handleResetToFirstPage = useCallback11(
|
|
2648
2746
|
async (fetchFn) => {
|
|
2649
2747
|
setParam("cursor", "");
|
|
2650
2748
|
await fetchFn();
|
|
@@ -2666,16 +2764,16 @@ function useCursorPaginationState(options) {
|
|
|
2666
2764
|
}
|
|
2667
2765
|
|
|
2668
2766
|
// src/hooks/nats/use-nats-client.ts
|
|
2669
|
-
import { useEffect as
|
|
2767
|
+
import { useEffect as useEffect15, useMemo as useMemo5, useState as useState20 } from "react";
|
|
2670
2768
|
function useNatsClient(clientOptions, options = {}) {
|
|
2671
2769
|
const { autoConnect = true } = options;
|
|
2672
2770
|
const client = useMemo5(() => {
|
|
2673
2771
|
if (!clientOptions) return null;
|
|
2674
2772
|
return createNatsClient(clientOptions);
|
|
2675
2773
|
}, [clientOptions]);
|
|
2676
|
-
const [status, setStatus] =
|
|
2677
|
-
const [lastError, setLastError] =
|
|
2678
|
-
|
|
2774
|
+
const [status, setStatus] = useState20("disconnected");
|
|
2775
|
+
const [lastError, setLastError] = useState20(null);
|
|
2776
|
+
useEffect15(() => {
|
|
2679
2777
|
if (!client) {
|
|
2680
2778
|
setStatus("disconnected");
|
|
2681
2779
|
setLastError(null);
|
|
@@ -2808,7 +2906,7 @@ function useAccessCodeIntegration() {
|
|
|
2808
2906
|
}
|
|
2809
2907
|
|
|
2810
2908
|
// src/hooks/use-humanity-signals.ts
|
|
2811
|
-
import { useCallback as
|
|
2909
|
+
import { useCallback as useCallback12, useRef as useRef10 } from "react";
|
|
2812
2910
|
|
|
2813
2911
|
// src/utils/humanity-signals.ts
|
|
2814
2912
|
var HONEYPOT_FIELD = "contact_url_confirm";
|
|
@@ -2834,14 +2932,14 @@ var splitCsvEnv = (s) => s?.split(",").map((t) => t.trim()).filter(Boolean) ?? [
|
|
|
2834
2932
|
function useHumanitySignals() {
|
|
2835
2933
|
const ref = useRef10(null);
|
|
2836
2934
|
const mountedAt = useRef10(typeof performance !== "undefined" ? performance.now() : 0);
|
|
2837
|
-
const getSignals =
|
|
2935
|
+
const getSignals = useCallback12(
|
|
2838
2936
|
() => ({
|
|
2839
2937
|
[HONEYPOT_FIELD]: ref.current?.value ?? "",
|
|
2840
2938
|
[ELAPSED_MS_FIELD]: typeof performance !== "undefined" ? Math.round(performance.now() - mountedAt.current) : 0
|
|
2841
2939
|
}),
|
|
2842
2940
|
[]
|
|
2843
2941
|
);
|
|
2844
|
-
const resetSignals =
|
|
2942
|
+
const resetSignals = useCallback12(() => {
|
|
2845
2943
|
if (ref.current) ref.current.value = "";
|
|
2846
2944
|
if (typeof performance !== "undefined") mountedAt.current = performance.now();
|
|
2847
2945
|
}, []);
|
|
@@ -2849,6 +2947,9 @@ function useHumanitySignals() {
|
|
|
2849
2947
|
}
|
|
2850
2948
|
|
|
2851
2949
|
export {
|
|
2950
|
+
useHeaderHeight,
|
|
2951
|
+
useHorizontalScrollbar,
|
|
2952
|
+
useImageEdgeColor,
|
|
2852
2953
|
useLocalStorage,
|
|
2853
2954
|
useMediaQuery,
|
|
2854
2955
|
breakpoints,
|
|
@@ -2856,13 +2957,12 @@ export {
|
|
|
2856
2957
|
useMdUp,
|
|
2857
2958
|
useLgUp,
|
|
2858
2959
|
useMemoizedCallback,
|
|
2960
|
+
useNotificationPermission,
|
|
2859
2961
|
useOnboardingState,
|
|
2962
|
+
useSearch,
|
|
2860
2963
|
useTablePagination,
|
|
2861
2964
|
useThrottle,
|
|
2862
2965
|
useWindowSize,
|
|
2863
|
-
useHorizontalScrollbar,
|
|
2864
|
-
useImageEdgeColor,
|
|
2865
|
-
useSearch,
|
|
2866
2966
|
platformIcons,
|
|
2867
2967
|
platformColors,
|
|
2868
2968
|
platformDisplayNames,
|
|
@@ -2939,4 +3039,4 @@ export {
|
|
|
2939
3039
|
splitCsvEnv,
|
|
2940
3040
|
useHumanitySignals
|
|
2941
3041
|
};
|
|
2942
|
-
//# sourceMappingURL=chunk-
|
|
3042
|
+
//# sourceMappingURL=chunk-ZMFT5XOB.js.map
|