@djangocfg/ui-nextjs 2.1.102 → 2.1.104
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/package.json +26 -30
- package/src/components/index.ts +2 -0
- package/src/components/ssr-pagination.tsx +2 -1
- package/src/hooks/index.ts +1 -6
- package/src/index.ts +2 -0
- package/src/theme/index.ts +2 -0
- package/dist/animations.cjs +0 -880
- package/dist/animations.cjs.map +0 -1
- package/dist/animations.mjs +0 -877
- package/dist/animations.mjs.map +0 -1
- package/dist/blocks.cjs +0 -1609
- package/dist/blocks.cjs.map +0 -1
- package/dist/blocks.d.mts +0 -278
- package/dist/blocks.d.ts +0 -278
- package/dist/blocks.mjs +0 -1589
- package/dist/blocks.mjs.map +0 -1
- package/dist/components.cjs +0 -1946
- package/dist/components.cjs.map +0 -1
- package/dist/components.d.mts +0 -322
- package/dist/components.d.ts +0 -322
- package/dist/components.mjs +0 -1860
- package/dist/components.mjs.map +0 -1
- package/dist/hooks.cjs +0 -530
- package/dist/hooks.cjs.map +0 -1
- package/dist/hooks.mjs +0 -506
- package/dist/hooks.mjs.map +0 -1
- package/dist/index.cjs +0 -4080
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.mts +0 -1044
- package/dist/index.d.ts +0 -1044
- package/dist/index.mjs +0 -3962
- package/dist/index.mjs.map +0 -1
- package/dist/theme.cjs +0 -189
- package/dist/theme.cjs.map +0 -1
- package/dist/theme.d.mts +0 -60
- package/dist/theme.d.ts +0 -60
- package/dist/theme.mjs +0 -184
- package/dist/theme.mjs.map +0 -1
- package/src/hooks/useCfgRouter.ts +0 -153
- package/src/hooks/useQueryParams.ts +0 -73
package/dist/hooks.cjs
DELETED
|
@@ -1,530 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var hooks = require('@djangocfg/ui-core/hooks');
|
|
4
|
-
var react = require('react');
|
|
5
|
-
var navigation = require('next/navigation');
|
|
6
|
-
var reactHotkeysHook = require('react-hotkeys-hook');
|
|
7
|
-
|
|
8
|
-
var __defProp = Object.defineProperty;
|
|
9
|
-
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
10
|
-
var useResolvedTheme = /* @__PURE__ */ __name(() => {
|
|
11
|
-
const [theme, setTheme] = react.useState("light");
|
|
12
|
-
react.useEffect(() => {
|
|
13
|
-
const checkTheme = /* @__PURE__ */ __name(() => {
|
|
14
|
-
if (document.documentElement.classList.contains("dark")) {
|
|
15
|
-
return "dark";
|
|
16
|
-
}
|
|
17
|
-
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
18
|
-
return "dark";
|
|
19
|
-
}
|
|
20
|
-
return "light";
|
|
21
|
-
}, "checkTheme");
|
|
22
|
-
setTheme(checkTheme());
|
|
23
|
-
const observer = new MutationObserver(() => {
|
|
24
|
-
setTheme(checkTheme());
|
|
25
|
-
});
|
|
26
|
-
observer.observe(document.documentElement, {
|
|
27
|
-
attributes: true,
|
|
28
|
-
attributeFilter: ["class"]
|
|
29
|
-
});
|
|
30
|
-
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
31
|
-
const handleMediaChange = /* @__PURE__ */ __name(() => {
|
|
32
|
-
setTheme(checkTheme());
|
|
33
|
-
}, "handleMediaChange");
|
|
34
|
-
mediaQuery.addEventListener("change", handleMediaChange);
|
|
35
|
-
return () => {
|
|
36
|
-
observer.disconnect();
|
|
37
|
-
mediaQuery.removeEventListener("change", handleMediaChange);
|
|
38
|
-
};
|
|
39
|
-
}, []);
|
|
40
|
-
return theme;
|
|
41
|
-
}, "useResolvedTheme");
|
|
42
|
-
function useQueryParams() {
|
|
43
|
-
const pathname = navigation.usePathname();
|
|
44
|
-
const [queryParams, setQueryParams] = react.useState(() => {
|
|
45
|
-
if (typeof window === "undefined") {
|
|
46
|
-
return new URLSearchParams();
|
|
47
|
-
}
|
|
48
|
-
return new URLSearchParams(window.location.search);
|
|
49
|
-
});
|
|
50
|
-
const lastSearchRef = react.useRef("");
|
|
51
|
-
react.useEffect(() => {
|
|
52
|
-
if (typeof window === "undefined") return;
|
|
53
|
-
const updateQueryParams = /* @__PURE__ */ __name(() => {
|
|
54
|
-
const currentSearch = window.location.search;
|
|
55
|
-
if (currentSearch !== lastSearchRef.current) {
|
|
56
|
-
lastSearchRef.current = currentSearch;
|
|
57
|
-
setQueryParams(new URLSearchParams(currentSearch));
|
|
58
|
-
}
|
|
59
|
-
}, "updateQueryParams");
|
|
60
|
-
updateQueryParams();
|
|
61
|
-
window.addEventListener("popstate", updateQueryParams);
|
|
62
|
-
const intervalId = setInterval(updateQueryParams, 100);
|
|
63
|
-
return () => {
|
|
64
|
-
window.removeEventListener("popstate", updateQueryParams);
|
|
65
|
-
clearInterval(intervalId);
|
|
66
|
-
};
|
|
67
|
-
}, [pathname]);
|
|
68
|
-
return queryParams;
|
|
69
|
-
}
|
|
70
|
-
__name(useQueryParams, "useQueryParams");
|
|
71
|
-
function getBasePath() {
|
|
72
|
-
if (typeof process === "undefined") {
|
|
73
|
-
return "";
|
|
74
|
-
}
|
|
75
|
-
return process.env.NEXT_PUBLIC_BASE_PATH || "";
|
|
76
|
-
}
|
|
77
|
-
__name(getBasePath, "getBasePath");
|
|
78
|
-
function withBasePath(path, basePath) {
|
|
79
|
-
if (!basePath) {
|
|
80
|
-
return path;
|
|
81
|
-
}
|
|
82
|
-
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
83
|
-
const normalizedBasePath = basePath.replace(/\/$/, "");
|
|
84
|
-
return `${normalizedBasePath}${normalizedPath}`;
|
|
85
|
-
}
|
|
86
|
-
__name(withBasePath, "withBasePath");
|
|
87
|
-
function useCfgRouter() {
|
|
88
|
-
const router = navigation.useRouter();
|
|
89
|
-
const basePath = react.useMemo(() => getBasePath(), []);
|
|
90
|
-
react.useMemo(() => {
|
|
91
|
-
return typeof process !== "undefined" && process.env.NEXT_PUBLIC_STATIC_BUILD === "true";
|
|
92
|
-
}, []);
|
|
93
|
-
const push = react.useCallback((href, options) => {
|
|
94
|
-
if (basePath) {
|
|
95
|
-
window.location.href = withBasePath(href, basePath);
|
|
96
|
-
} else {
|
|
97
|
-
router.push(href, options);
|
|
98
|
-
}
|
|
99
|
-
}, [router, basePath]);
|
|
100
|
-
const replace = react.useCallback((href, options) => {
|
|
101
|
-
if (basePath) {
|
|
102
|
-
window.location.replace(withBasePath(href, basePath));
|
|
103
|
-
} else {
|
|
104
|
-
router.replace(href, options);
|
|
105
|
-
}
|
|
106
|
-
}, [router, basePath]);
|
|
107
|
-
const hardPush = react.useCallback((href) => {
|
|
108
|
-
window.location.href = withBasePath(href, basePath);
|
|
109
|
-
}, [basePath]);
|
|
110
|
-
const hardReplace = react.useCallback((href) => {
|
|
111
|
-
window.location.replace(withBasePath(href, basePath));
|
|
112
|
-
}, [basePath]);
|
|
113
|
-
const prefetch = react.useCallback((href) => {
|
|
114
|
-
router.prefetch(href);
|
|
115
|
-
}, [router]);
|
|
116
|
-
const back = react.useCallback(() => {
|
|
117
|
-
router.back();
|
|
118
|
-
}, [router]);
|
|
119
|
-
const forward = react.useCallback(() => {
|
|
120
|
-
router.forward();
|
|
121
|
-
}, [router]);
|
|
122
|
-
const refresh = react.useCallback(() => {
|
|
123
|
-
router.refresh();
|
|
124
|
-
}, [router]);
|
|
125
|
-
return {
|
|
126
|
-
push,
|
|
127
|
-
replace,
|
|
128
|
-
hardPush,
|
|
129
|
-
hardReplace,
|
|
130
|
-
prefetch,
|
|
131
|
-
back,
|
|
132
|
-
forward,
|
|
133
|
-
refresh
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
__name(useCfgRouter, "useCfgRouter");
|
|
137
|
-
function useHotkey(keys, callback, options = {}) {
|
|
138
|
-
const {
|
|
139
|
-
enabled = true,
|
|
140
|
-
preventDefault = false,
|
|
141
|
-
enableOnFormTags = false,
|
|
142
|
-
enableOnContentEditable = false,
|
|
143
|
-
description: _description,
|
|
144
|
-
...restOptions
|
|
145
|
-
} = options;
|
|
146
|
-
return reactHotkeysHook.useHotkeys(
|
|
147
|
-
keys,
|
|
148
|
-
(event, handler) => {
|
|
149
|
-
if (preventDefault) {
|
|
150
|
-
event.preventDefault();
|
|
151
|
-
}
|
|
152
|
-
callback(event, handler);
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
enabled,
|
|
156
|
-
enableOnFormTags,
|
|
157
|
-
enableOnContentEditable,
|
|
158
|
-
...restOptions
|
|
159
|
-
}
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
__name(useHotkey, "useHotkey");
|
|
163
|
-
var defaultSelectors = {
|
|
164
|
-
isMobile: false,
|
|
165
|
-
isTablet: false,
|
|
166
|
-
isDesktop: false,
|
|
167
|
-
isBrowser: false,
|
|
168
|
-
isMobileOnly: false,
|
|
169
|
-
isSmartTV: false,
|
|
170
|
-
isConsole: false,
|
|
171
|
-
isWearable: false,
|
|
172
|
-
isEmbedded: false,
|
|
173
|
-
isAndroid: false,
|
|
174
|
-
isIOS: false,
|
|
175
|
-
isWindows: false,
|
|
176
|
-
isMacOs: false,
|
|
177
|
-
isWinPhone: false,
|
|
178
|
-
isChrome: false,
|
|
179
|
-
isFirefox: false,
|
|
180
|
-
isSafari: false,
|
|
181
|
-
isOpera: false,
|
|
182
|
-
isIE: false,
|
|
183
|
-
isEdge: false,
|
|
184
|
-
isEdgeChromium: false,
|
|
185
|
-
isLegacyEdge: false,
|
|
186
|
-
isChromium: false,
|
|
187
|
-
isMobileSafari: false,
|
|
188
|
-
isYandex: false,
|
|
189
|
-
isMIUI: false,
|
|
190
|
-
isSamsungBrowser: false,
|
|
191
|
-
isElectron: false,
|
|
192
|
-
osVersion: "unknown",
|
|
193
|
-
osName: "unknown",
|
|
194
|
-
fullBrowserVersion: "unknown",
|
|
195
|
-
browserVersion: "unknown",
|
|
196
|
-
browserName: "unknown",
|
|
197
|
-
mobileVendor: "unknown",
|
|
198
|
-
mobileModel: "unknown",
|
|
199
|
-
engineName: "unknown",
|
|
200
|
-
engineVersion: "unknown",
|
|
201
|
-
getUA: "",
|
|
202
|
-
deviceType: "unknown",
|
|
203
|
-
isIOS13: false,
|
|
204
|
-
isIPad13: false,
|
|
205
|
-
isIPhone13: false,
|
|
206
|
-
isIPod13: false
|
|
207
|
-
};
|
|
208
|
-
var defaultDeviceData = {
|
|
209
|
-
deviceType: "unknown",
|
|
210
|
-
osName: "unknown",
|
|
211
|
-
osVersion: "unknown",
|
|
212
|
-
browserName: "unknown",
|
|
213
|
-
browserVersion: "unknown",
|
|
214
|
-
fullBrowserVersion: "unknown",
|
|
215
|
-
mobileVendor: "unknown",
|
|
216
|
-
mobileModel: "unknown",
|
|
217
|
-
engineName: "unknown",
|
|
218
|
-
engineVersion: "unknown",
|
|
219
|
-
getUA: ""
|
|
220
|
-
};
|
|
221
|
-
var defaultOrientation = {
|
|
222
|
-
isPortrait: false,
|
|
223
|
-
isLandscape: false,
|
|
224
|
-
orientation: "portrait"
|
|
225
|
-
};
|
|
226
|
-
function useDeviceDetect(userAgent) {
|
|
227
|
-
const [deviceInfo, setDeviceInfo] = react.useState({
|
|
228
|
-
selectors: defaultSelectors,
|
|
229
|
-
deviceData: defaultDeviceData,
|
|
230
|
-
orientation: defaultOrientation
|
|
231
|
-
});
|
|
232
|
-
react.useEffect(() => {
|
|
233
|
-
if (typeof window === "undefined") return;
|
|
234
|
-
import('react-device-detect').then((deviceDetect) => {
|
|
235
|
-
const ua = userAgent || (typeof window !== "undefined" ? window.navigator.userAgent : "");
|
|
236
|
-
if (!ua) {
|
|
237
|
-
console.warn("No user agent available");
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
const parsed = deviceDetect.parseUserAgent(ua);
|
|
241
|
-
if (!parsed) {
|
|
242
|
-
console.warn("Failed to parse user agent");
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
const selectors2 = deviceDetect.getSelectorsByUserAgent(ua) || defaultSelectors;
|
|
246
|
-
const deviceData2 = {
|
|
247
|
-
deviceType: parsed.device?.type || "unknown",
|
|
248
|
-
osName: parsed.os?.name || "unknown",
|
|
249
|
-
osVersion: parsed.os?.version || "unknown",
|
|
250
|
-
browserName: parsed.browser?.name || "unknown",
|
|
251
|
-
browserVersion: parsed.browser?.version || "unknown",
|
|
252
|
-
fullBrowserVersion: parsed.browser?.version || "unknown",
|
|
253
|
-
mobileVendor: parsed.device?.vendor || "unknown",
|
|
254
|
-
mobileModel: parsed.device?.model || "unknown",
|
|
255
|
-
engineName: parsed.engine?.name || "unknown",
|
|
256
|
-
engineVersion: parsed.engine?.version || "unknown",
|
|
257
|
-
getUA: parsed.ua || ua
|
|
258
|
-
};
|
|
259
|
-
let orientation2 = defaultOrientation;
|
|
260
|
-
try {
|
|
261
|
-
if (typeof window !== "undefined") {
|
|
262
|
-
const isPortrait = window.innerHeight > window.innerWidth;
|
|
263
|
-
orientation2 = {
|
|
264
|
-
isPortrait,
|
|
265
|
-
isLandscape: !isPortrait,
|
|
266
|
-
orientation: isPortrait ? "portrait" : "landscape"
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
} catch (error) {
|
|
270
|
-
console.warn("Failed to get orientation:", error);
|
|
271
|
-
}
|
|
272
|
-
setDeviceInfo({ selectors: selectors2, deviceData: deviceData2, orientation: orientation2 });
|
|
273
|
-
}).catch((error) => {
|
|
274
|
-
console.warn("Failed to load device detection:", error);
|
|
275
|
-
});
|
|
276
|
-
}, [userAgent]);
|
|
277
|
-
react.useEffect(() => {
|
|
278
|
-
if (typeof window === "undefined") return;
|
|
279
|
-
const handleResize = /* @__PURE__ */ __name(() => {
|
|
280
|
-
const isPortrait = window.innerHeight > window.innerWidth;
|
|
281
|
-
setDeviceInfo((prev) => ({
|
|
282
|
-
...prev,
|
|
283
|
-
orientation: {
|
|
284
|
-
isPortrait,
|
|
285
|
-
isLandscape: !isPortrait,
|
|
286
|
-
orientation: isPortrait ? "portrait" : "landscape"
|
|
287
|
-
}
|
|
288
|
-
}));
|
|
289
|
-
}, "handleResize");
|
|
290
|
-
window.addEventListener("resize", handleResize);
|
|
291
|
-
window.addEventListener("orientationchange", handleResize);
|
|
292
|
-
return () => {
|
|
293
|
-
window.removeEventListener("resize", handleResize);
|
|
294
|
-
window.removeEventListener("orientationchange", handleResize);
|
|
295
|
-
};
|
|
296
|
-
}, []);
|
|
297
|
-
const { selectors, deviceData, orientation } = deviceInfo;
|
|
298
|
-
return react.useMemo(() => {
|
|
299
|
-
return {
|
|
300
|
-
// Device type selectors
|
|
301
|
-
isMobile: selectors.isMobile ?? false,
|
|
302
|
-
isTablet: selectors.isTablet ?? false,
|
|
303
|
-
isDesktop: selectors.isDesktop ?? false,
|
|
304
|
-
isBrowser: selectors.isBrowser ?? false,
|
|
305
|
-
isMobileOnly: selectors.isMobileOnly ?? false,
|
|
306
|
-
isSmartTV: selectors.isSmartTV ?? false,
|
|
307
|
-
isConsole: selectors.isConsole ?? false,
|
|
308
|
-
isWearable: selectors.isWearable ?? false,
|
|
309
|
-
isEmbedded: selectors.isEmbedded ?? false,
|
|
310
|
-
// OS selectors
|
|
311
|
-
isAndroid: selectors.isAndroid ?? false,
|
|
312
|
-
isIOS: selectors.isIOS ?? false,
|
|
313
|
-
isWindows: selectors.isWindows ?? false,
|
|
314
|
-
isMacOs: selectors.isMacOs ?? false,
|
|
315
|
-
isWinPhone: selectors.isWinPhone ?? false,
|
|
316
|
-
// Browser selectors
|
|
317
|
-
isChrome: selectors.isChrome ?? false,
|
|
318
|
-
isFirefox: selectors.isFirefox ?? false,
|
|
319
|
-
isSafari: selectors.isSafari ?? false,
|
|
320
|
-
isOpera: selectors.isOpera ?? false,
|
|
321
|
-
isIE: selectors.isIE ?? false,
|
|
322
|
-
isEdge: selectors.isEdge ?? false,
|
|
323
|
-
isEdgeChromium: selectors.isEdgeChromium ?? false,
|
|
324
|
-
isLegacyEdge: selectors.isLegacyEdge ?? false,
|
|
325
|
-
isChromium: selectors.isChromium ?? false,
|
|
326
|
-
isMobileSafari: selectors.isMobileSafari ?? false,
|
|
327
|
-
isYandex: selectors.isYandex ?? false,
|
|
328
|
-
isMIUI: selectors.isMIUI ?? false,
|
|
329
|
-
isSamsungBrowser: selectors.isSamsungBrowser ?? false,
|
|
330
|
-
isElectron: selectors.isElectron ?? false,
|
|
331
|
-
// iOS version selectors
|
|
332
|
-
isIOS13: selectors.isIOS13 ?? false,
|
|
333
|
-
isIPad13: selectors.isIPad13 ?? false,
|
|
334
|
-
isIPhone13: selectors.isIPhone13 ?? false,
|
|
335
|
-
isIPod13: selectors.isIPod13 ?? false,
|
|
336
|
-
// Device information
|
|
337
|
-
deviceType: deviceData.deviceType ?? "unknown",
|
|
338
|
-
osName: deviceData.osName ?? "unknown",
|
|
339
|
-
osVersion: deviceData.osVersion ?? "unknown",
|
|
340
|
-
browserName: deviceData.browserName ?? "unknown",
|
|
341
|
-
browserVersion: deviceData.browserVersion ?? "unknown",
|
|
342
|
-
fullBrowserVersion: deviceData.fullBrowserVersion ?? "unknown",
|
|
343
|
-
mobileVendor: deviceData.mobileVendor ?? "unknown",
|
|
344
|
-
mobileModel: deviceData.mobileModel ?? "unknown",
|
|
345
|
-
engineName: deviceData.engineName ?? "unknown",
|
|
346
|
-
engineVersion: deviceData.engineVersion ?? "unknown",
|
|
347
|
-
getUA: deviceData.getUA ?? "",
|
|
348
|
-
// Orientation
|
|
349
|
-
isPortrait: orientation.isPortrait,
|
|
350
|
-
isLandscape: orientation.isLandscape,
|
|
351
|
-
orientation: orientation.orientation,
|
|
352
|
-
// Raw data (for advanced usage)
|
|
353
|
-
selectors,
|
|
354
|
-
deviceData
|
|
355
|
-
};
|
|
356
|
-
}, [selectors, deviceData, orientation]);
|
|
357
|
-
}
|
|
358
|
-
__name(useDeviceDetect, "useDeviceDetect");
|
|
359
|
-
function useBrowserDetect() {
|
|
360
|
-
return react.useMemo(() => {
|
|
361
|
-
if (typeof window === "undefined") {
|
|
362
|
-
return {
|
|
363
|
-
isChrome: false,
|
|
364
|
-
isChromium: false,
|
|
365
|
-
isSafari: false,
|
|
366
|
-
isFirefox: false,
|
|
367
|
-
isEdge: false,
|
|
368
|
-
isOpera: false,
|
|
369
|
-
isBrave: false,
|
|
370
|
-
isArc: false,
|
|
371
|
-
isVivaldi: false,
|
|
372
|
-
isYandex: false,
|
|
373
|
-
isSamsungBrowser: false,
|
|
374
|
-
isUCBrowser: false,
|
|
375
|
-
isComet: false,
|
|
376
|
-
isOperaMini: false,
|
|
377
|
-
isIE: false,
|
|
378
|
-
isFacebookInApp: false,
|
|
379
|
-
isInstagramInApp: false,
|
|
380
|
-
isTikTokInApp: false,
|
|
381
|
-
isSnapchatInApp: false,
|
|
382
|
-
isWeChatInApp: false,
|
|
383
|
-
isThreadsInApp: false,
|
|
384
|
-
isLinkedInInApp: false,
|
|
385
|
-
isTwitterInApp: false,
|
|
386
|
-
isInAppBrowser: false,
|
|
387
|
-
isWebView: false,
|
|
388
|
-
browserName: "unknown",
|
|
389
|
-
isWebKit: false,
|
|
390
|
-
isBlink: false,
|
|
391
|
-
isGecko: false,
|
|
392
|
-
supportsPushNotifications: false,
|
|
393
|
-
isIOSBrowser: false,
|
|
394
|
-
userAgent: ""
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
const ua = window.navigator.userAgent.toLowerCase();
|
|
398
|
-
const isEdge = ua.includes("edg/") || ua.includes("edge/");
|
|
399
|
-
const isBrave = !!window.navigator.brave;
|
|
400
|
-
const isArc = ua.includes("arc/");
|
|
401
|
-
const isVivaldi = ua.includes("vivaldi");
|
|
402
|
-
const isYandex = ua.includes("yabrowser");
|
|
403
|
-
const isSamsungBrowser = ua.includes("samsungbrowser");
|
|
404
|
-
const isUCBrowser = ua.includes("ucbrowser") || ua.includes("uc browser");
|
|
405
|
-
const isComet = ua.includes("comet") || ua.includes("perplexity");
|
|
406
|
-
const isOperaMini = ua.includes("opera mini") || ua.includes("opios");
|
|
407
|
-
const isIE = ua.includes("msie") || ua.includes("trident/");
|
|
408
|
-
const isFacebookInApp = ua.includes("fban") || ua.includes("fbav") || ua.includes("fb_iab");
|
|
409
|
-
const isInstagramInApp = ua.includes("instagram");
|
|
410
|
-
const isTikTokInApp = ua.includes("tiktok") || ua.includes("bytedancewebview") || ua.includes("bytelocale");
|
|
411
|
-
const isSnapchatInApp = ua.includes("snapchat");
|
|
412
|
-
const isWeChatInApp = ua.includes("micromessenger");
|
|
413
|
-
const isThreadsInApp = ua.includes("barcelona");
|
|
414
|
-
const isLinkedInInApp = ua.includes("linkedinapp");
|
|
415
|
-
const isTwitterInApp = ua.includes("twitter");
|
|
416
|
-
const isPinterestInApp = ua.includes("pinterest");
|
|
417
|
-
const isTelegramInApp = ua.includes("telegram");
|
|
418
|
-
const isLineInApp = ua.includes("line/");
|
|
419
|
-
const isKakaoInApp = ua.includes("kakaotalk");
|
|
420
|
-
const isWebView = ua.includes("wv)") || // Android WebView marker
|
|
421
|
-
ua.includes("webview") || ua.includes("; wv") || ua.includes("iphone") && !ua.includes("safari") || // iOS WebView (no Safari)
|
|
422
|
-
ua.includes("ipad") && !ua.includes("safari");
|
|
423
|
-
const isInAppBrowser = isFacebookInApp || isInstagramInApp || isTikTokInApp || isSnapchatInApp || isWeChatInApp || isThreadsInApp || isLinkedInInApp || isTwitterInApp || isPinterestInApp || isTelegramInApp || isLineInApp || isKakaoInApp;
|
|
424
|
-
const isIOSBrowser = ua.includes("iphone") || ua.includes("ipad") || ua.includes("ipod");
|
|
425
|
-
const isOpera = (ua.includes("opr/") || ua.includes("opera")) && !isOperaMini;
|
|
426
|
-
const isChrome = ua.includes("chrome") && !isEdge && !isOpera && !isYandex && !isSamsungBrowser && !isVivaldi && !isArc && !isBrave && !isComet;
|
|
427
|
-
const isFirefox = ua.includes("firefox") && !ua.includes("seamonkey");
|
|
428
|
-
const hasSafariUA = ua.includes("safari");
|
|
429
|
-
const hasChrome = ua.includes("chrome") || ua.includes("crios");
|
|
430
|
-
const hasVersion = ua.includes("version/");
|
|
431
|
-
const isSafari = hasSafariUA && !hasChrome && hasVersion;
|
|
432
|
-
const isChromium = hasChrome || isEdge || isOpera || isYandex || isSamsungBrowser || isVivaldi || isArc || isBrave || isUCBrowser || isComet;
|
|
433
|
-
const isWebKit = !isChromium && isSafari;
|
|
434
|
-
const isBlink = isChromium;
|
|
435
|
-
const isGecko = isFirefox;
|
|
436
|
-
let browserName = "unknown";
|
|
437
|
-
if (isFacebookInApp) browserName = "Facebook In-App";
|
|
438
|
-
else if (isInstagramInApp) browserName = "Instagram In-App";
|
|
439
|
-
else if (isTikTokInApp) browserName = "TikTok In-App";
|
|
440
|
-
else if (isSnapchatInApp) browserName = "Snapchat In-App";
|
|
441
|
-
else if (isWeChatInApp) browserName = "WeChat In-App";
|
|
442
|
-
else if (isThreadsInApp) browserName = "Threads In-App";
|
|
443
|
-
else if (isLinkedInInApp) browserName = "LinkedIn In-App";
|
|
444
|
-
else if (isTwitterInApp) browserName = "Twitter In-App";
|
|
445
|
-
else if (isPinterestInApp) browserName = "Pinterest In-App";
|
|
446
|
-
else if (isTelegramInApp) browserName = "Telegram In-App";
|
|
447
|
-
else if (isLineInApp) browserName = "Line In-App";
|
|
448
|
-
else if (isKakaoInApp) browserName = "KakaoTalk In-App";
|
|
449
|
-
else if (isComet) browserName = "Comet";
|
|
450
|
-
else if (isOperaMini) browserName = "Opera Mini";
|
|
451
|
-
else if (isIE) browserName = "Internet Explorer";
|
|
452
|
-
else if (isBrave) browserName = "Brave";
|
|
453
|
-
else if (isArc) browserName = "Arc";
|
|
454
|
-
else if (isVivaldi) browserName = "Vivaldi";
|
|
455
|
-
else if (isYandex) browserName = "Yandex";
|
|
456
|
-
else if (isSamsungBrowser) browserName = "Samsung Internet";
|
|
457
|
-
else if (isUCBrowser) browserName = "UC Browser";
|
|
458
|
-
else if (isEdge) browserName = "Edge";
|
|
459
|
-
else if (isOpera) browserName = "Opera";
|
|
460
|
-
else if (isChrome) browserName = "Chrome";
|
|
461
|
-
else if (isSafari) browserName = "Safari";
|
|
462
|
-
else if (isFirefox) browserName = "Firefox";
|
|
463
|
-
else if (isWebView) browserName = "WebView";
|
|
464
|
-
const browserBlocksPush = isOperaMini || isIE || isUCBrowser || isFacebookInApp || isInstagramInApp || isTikTokInApp || isSnapchatInApp || isWeChatInApp || isThreadsInApp || isPinterestInApp || isTelegramInApp || isLineInApp || isKakaoInApp || isWebView;
|
|
465
|
-
const twitterLinkedInAndroid = (isTwitterInApp || isLinkedInInApp) && !isIOSBrowser;
|
|
466
|
-
const supportsPushNotifications = !browserBlocksPush || twitterLinkedInAndroid;
|
|
467
|
-
return {
|
|
468
|
-
isChrome,
|
|
469
|
-
isChromium,
|
|
470
|
-
isSafari,
|
|
471
|
-
isFirefox,
|
|
472
|
-
isEdge,
|
|
473
|
-
isOpera,
|
|
474
|
-
isBrave,
|
|
475
|
-
isArc,
|
|
476
|
-
isVivaldi,
|
|
477
|
-
isYandex,
|
|
478
|
-
isSamsungBrowser,
|
|
479
|
-
isUCBrowser,
|
|
480
|
-
isComet,
|
|
481
|
-
isOperaMini,
|
|
482
|
-
isIE,
|
|
483
|
-
isFacebookInApp,
|
|
484
|
-
isInstagramInApp,
|
|
485
|
-
isTikTokInApp,
|
|
486
|
-
isSnapchatInApp,
|
|
487
|
-
isWeChatInApp,
|
|
488
|
-
isThreadsInApp,
|
|
489
|
-
isLinkedInInApp,
|
|
490
|
-
isTwitterInApp,
|
|
491
|
-
isInAppBrowser,
|
|
492
|
-
isWebView,
|
|
493
|
-
browserName,
|
|
494
|
-
isWebKit,
|
|
495
|
-
isBlink,
|
|
496
|
-
isGecko,
|
|
497
|
-
supportsPushNotifications,
|
|
498
|
-
isIOSBrowser,
|
|
499
|
-
userAgent: window.navigator.userAgent
|
|
500
|
-
};
|
|
501
|
-
}, []);
|
|
502
|
-
}
|
|
503
|
-
__name(useBrowserDetect, "useBrowserDetect");
|
|
504
|
-
|
|
505
|
-
Object.defineProperty(exports, "HotkeysProvider", {
|
|
506
|
-
enumerable: true,
|
|
507
|
-
get: function () { return reactHotkeysHook.HotkeysProvider; }
|
|
508
|
-
});
|
|
509
|
-
Object.defineProperty(exports, "isHotkeyPressed", {
|
|
510
|
-
enumerable: true,
|
|
511
|
-
get: function () { return reactHotkeysHook.isHotkeyPressed; }
|
|
512
|
-
});
|
|
513
|
-
Object.defineProperty(exports, "useHotkeysContext", {
|
|
514
|
-
enumerable: true,
|
|
515
|
-
get: function () { return reactHotkeysHook.useHotkeysContext; }
|
|
516
|
-
});
|
|
517
|
-
exports.useBrowserDetect = useBrowserDetect;
|
|
518
|
-
exports.useCfgRouter = useCfgRouter;
|
|
519
|
-
exports.useDeviceDetect = useDeviceDetect;
|
|
520
|
-
exports.useHotkey = useHotkey;
|
|
521
|
-
exports.useQueryParams = useQueryParams;
|
|
522
|
-
exports.useResolvedTheme = useResolvedTheme;
|
|
523
|
-
Object.keys(hooks).forEach(function (k) {
|
|
524
|
-
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
525
|
-
enumerable: true,
|
|
526
|
-
get: function () { return hooks[k]; }
|
|
527
|
-
});
|
|
528
|
-
});
|
|
529
|
-
//# sourceMappingURL=hooks.cjs.map
|
|
530
|
-
//# sourceMappingURL=hooks.cjs.map
|
package/dist/hooks.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useResolvedTheme.ts","../src/hooks/useQueryParams.ts","../src/hooks/useCfgRouter.ts","../src/hooks/useHotkey.ts","../src/hooks/useDeviceDetect.ts","../src/hooks/useBrowserDetect.ts"],"names":["useState","useEffect","usePathname","useRef","useNextRouter","useMemo","useCallback","useHotkeys","selectors","deviceData","orientation"],"mappings":"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","file":"hooks.cjs","sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\n\nexport type ResolvedTheme = 'light' | 'dark';\n\n/**\n * Hook to detect the current resolved theme (light or dark)\n *\n * Standalone hook - doesn't require ThemeProvider.\n * Detects theme from:\n * 1. 'dark' class on html element\n * 2. System preference (prefers-color-scheme)\n *\n * For full theme control (setTheme, toggleTheme), use useThemeContext instead.\n *\n * @example\n * ```tsx\n * const theme = useResolvedTheme(); // 'light' | 'dark'\n * ```\n */\nexport const useResolvedTheme = (): ResolvedTheme => {\n const [theme, setTheme] = useState<ResolvedTheme>('light');\n\n useEffect(() => {\n const checkTheme = (): ResolvedTheme => {\n // Check if dark class is applied to html element\n if (document.documentElement.classList.contains('dark')) {\n return 'dark';\n }\n\n // Check system preference\n if (window.matchMedia('(prefers-color-scheme: dark)').matches) {\n return 'dark';\n }\n\n return 'light';\n };\n\n // Set initial theme\n setTheme(checkTheme());\n\n // Listen for class changes on html element\n const observer = new MutationObserver(() => {\n setTheme(checkTheme());\n });\n\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['class']\n });\n\n // Listen for system theme changes\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n const handleMediaChange = () => {\n setTheme(checkTheme());\n };\n\n mediaQuery.addEventListener('change', handleMediaChange);\n\n return () => {\n observer.disconnect();\n mediaQuery.removeEventListener('change', handleMediaChange);\n };\n }, []);\n\n return theme;\n};\n","/**\n * useQueryParams Hook\n * \n * Safe hook to access URL query parameters without requiring Suspense boundary.\n * Works on client-side only, returns empty URLSearchParams during SSR/prerendering.\n * \n * @example\n * ```tsx\n * const params = useQueryParams();\n * const flow = params.get('flow');\n * const hasFlow = params.has('flow');\n * const allTags = params.getAll('tags');\n * ```\n */\n\n'use client';\n\nimport { usePathname } from 'next/navigation';\nimport { useEffect, useRef, useState } from 'react';\n\n/**\n * Hook to safely access URL query parameters without useSearchParams()\n * \n * This hook reads query parameters directly from window.location.search,\n * avoiding the need for Suspense boundaries that useSearchParams() requires.\n * \n * Automatically updates when URL changes (navigation, back/forward, etc.)\n * Uses pathname from Next.js to detect route changes and polls for query param changes.\n * \n * Returns a URLSearchParams object with get(), getAll(), has(), etc.\n * \n * @returns URLSearchParams object (empty during SSR)\n */\nexport function useQueryParams(): URLSearchParams {\n const pathname = usePathname();\n const [queryParams, setQueryParams] = useState<URLSearchParams>(() => {\n if (typeof window === 'undefined') {\n return new URLSearchParams();\n }\n return new URLSearchParams(window.location.search);\n });\n const lastSearchRef = useRef<string>('');\n\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const updateQueryParams = () => {\n const currentSearch = window.location.search;\n if (currentSearch !== lastSearchRef.current) {\n lastSearchRef.current = currentSearch;\n setQueryParams(new URLSearchParams(currentSearch));\n }\n };\n\n // Update when pathname changes (Next.js navigation)\n updateQueryParams();\n\n // Listen to popstate (back/forward navigation)\n window.addEventListener('popstate', updateQueryParams);\n\n // Poll for query param changes (for router.push with same pathname)\n // This handles cases where Next.js router.push updates query params without changing pathname\n const intervalId = setInterval(updateQueryParams, 100);\n\n return () => {\n window.removeEventListener('popstate', updateQueryParams);\n clearInterval(intervalId);\n };\n }, [pathname]);\n\n return queryParams;\n}\n\n","/**\n * Universal Router Hook with BasePath Support\n *\n * Wrapper around Next.js useRouter that automatically handles basePath\n * for static builds served via iframe or subdirectory\n * \n * IMPORTANT: In Next.js 15 App Router, router.push() does NOT automatically\n * handle basePath (unlike Pages Router). This is a breaking change in App Router.\n * \n * This hook ensures basePath is always included when navigating, especially\n * important for static exports served via iframe where basePath is critical.\n * \n * @see https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration\n */\n\n'use client';\n\nimport { useRouter as useNextRouter } from 'next/navigation';\nimport { useCallback, useMemo } from 'react';\n\n/**\n * Get base path from environment variable\n */\nfunction getBasePath(): string {\n if (typeof process === 'undefined') {\n return '';\n }\n return process.env.NEXT_PUBLIC_BASE_PATH || '';\n}\n\n/**\n * Add base path to a route path\n */\nfunction withBasePath(path: string, basePath: string): string {\n if (!basePath) {\n return path;\n }\n // Ensure path starts with /\n const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n // Remove trailing slash from basePath\n const normalizedBasePath = basePath.replace(/\\/$/, '');\n return `${normalizedBasePath}${normalizedPath}`;\n}\n\n/**\n * Router with basePath support\n *\n * Automatically adds basePath to all navigation methods when basePath is configured.\n * In Next.js 15 App Router, router.push() doesn't handle basePath automatically,\n * so this hook uses window.location to ensure basePath is always included.\n *\n * @example\n * ```tsx\n * const router = useCfgRouter();\n *\n * // With basePath='/cfg/admin':\n * router.push('/dashboard'); // Client-side navigation to '/cfg/admin/dashboard'\n * router.replace('/auth'); // Client-side replace with '/cfg/admin/auth'\n * router.hardPush('/dashboard'); // Full page reload to '/cfg/admin/dashboard'\n * router.hardReplace('/auth'); // Full page replace with '/cfg/admin/auth'\n * ```\n */\nexport function useCfgRouter() {\n const router = useNextRouter();\n\n // Get basePath and check if we're in static build mode\n const basePath = useMemo(() => getBasePath(), []);\n const isStaticBuild = useMemo(() => {\n return typeof process !== 'undefined' && process.env.NEXT_PUBLIC_STATIC_BUILD === 'true';\n }, []);\n\n const push = useCallback((href: string, options?: { scroll?: boolean }) => {\n if (basePath) {\n // App Router doesn't handle basePath automatically, use window.location\n window.location.href = withBasePath(href, basePath);\n } else {\n // No basePath configured, use standard router\n router.push(href, options);\n }\n }, [router, basePath]);\n\n const replace = useCallback((href: string, options?: { scroll?: boolean }) => {\n if (basePath) {\n // App Router doesn't handle basePath automatically, use window.location\n window.location.replace(withBasePath(href, basePath));\n } else {\n // No basePath configured, use standard router\n router.replace(href, options);\n }\n }, [router, basePath]);\n\n /**\n * Hard push - always uses window.location.href for full page reload\n *\n * Use this for auth redirects where React contexts need to reinitialize.\n * Unlike push(), this ALWAYS triggers a full page reload, ensuring all\n * contexts are reinitialized with fresh state.\n *\n * @example\n * ```tsx\n * // After successful login - contexts need to reload with new auth state\n * router.hardPush('/dashboard');\n * ```\n */\n const hardPush = useCallback((href: string) => {\n window.location.href = withBasePath(href, basePath);\n }, [basePath]);\n\n /**\n * Hard replace - always uses window.location.replace for full page reload\n *\n * Same as hardPush but replaces current history entry.\n * Use for auth redirects where you don't want back button to return to login.\n *\n * @example\n * ```tsx\n * // After logout - replace so back button doesn't go to protected page\n * router.hardReplace('/auth');\n * ```\n */\n const hardReplace = useCallback((href: string) => {\n window.location.replace(withBasePath(href, basePath));\n }, [basePath]);\n\n const prefetch = useCallback((href: string) => {\n // Prefetch doesn't need basePath handling, Next.js handles it\n router.prefetch(href);\n }, [router]);\n\n const back = useCallback(() => {\n router.back();\n }, [router]);\n\n const forward = useCallback(() => {\n router.forward();\n }, [router]);\n\n const refresh = useCallback(() => {\n router.refresh();\n }, [router]);\n\n return {\n push,\n replace,\n hardPush,\n hardReplace,\n prefetch,\n back,\n forward,\n refresh,\n };\n}\n\n","'use client';\n\nimport type { RefObject } from 'react';\nimport { Options as HotkeysOptions, useHotkeys } from 'react-hotkeys-hook';\n\nimport type { HotkeyCallback, Keys } from 'react-hotkeys-hook';\n\n/**\n * Options for the useHotkey hook\n */\nexport interface UseHotkeyOptions extends Omit<HotkeysOptions, 'enabled'> {\n /** Whether the hotkey is enabled (default: true) */\n enabled?: boolean;\n /** Scope for the hotkey - useful for context-specific shortcuts */\n scope?: string;\n /** Only trigger when focus is within a specific element */\n scopes?: string[];\n /** Prevent default browser behavior */\n preventDefault?: boolean;\n /** Enable in input fields and textareas */\n enableOnFormTags?: boolean | readonly ('input' | 'textarea' | 'select')[];\n /** Enable when contentEditable element is focused */\n enableOnContentEditable?: boolean;\n /** Split key for multiple hotkey combinations (default: ',') */\n splitKey?: string;\n /** Key up/down events */\n keyup?: boolean;\n keydown?: boolean;\n /** Description for the hotkey (useful for help dialogs) */\n description?: string;\n}\n\n/**\n * Simple wrapper hook for react-hotkeys-hook\n *\n * @example\n * // Single key\n * useHotkey('escape', () => closeModal());\n *\n * @example\n * // Key combination\n * useHotkey('ctrl+s', (e) => {\n * e.preventDefault();\n * saveDocument();\n * });\n *\n * @example\n * // Multiple keys (any of them will trigger)\n * useHotkey(['ArrowLeft', '['], () => goToPrevious());\n * useHotkey(['ArrowRight', ']'], () => goToNext());\n *\n * @example\n * // With options\n * useHotkey('/', () => focusSearch(), {\n * preventDefault: true,\n * enableOnFormTags: false,\n * description: 'Focus search input'\n * });\n *\n * @example\n * // Scoped hotkeys\n * useHotkey('delete', () => deleteItem(), { scopes: ['list-view'] });\n *\n * @param keys - Hotkey or array of hotkeys (e.g., 'ctrl+s', 'ArrowLeft', ['[', 'ArrowLeft'])\n * @param callback - Function to call when hotkey is pressed\n * @param options - Configuration options\n * @returns Ref to attach to element for scoped hotkeys\n */\nexport function useHotkey<T extends HTMLElement = HTMLElement>(\n keys: Keys,\n callback: HotkeyCallback,\n options: UseHotkeyOptions = {}\n): RefObject<T | null> {\n const {\n enabled = true,\n preventDefault = false,\n enableOnFormTags = false,\n enableOnContentEditable = false,\n description: _description,\n ...restOptions\n } = options;\n\n return useHotkeys<T>(\n keys,\n (event, handler) => {\n if (preventDefault) {\n event.preventDefault();\n }\n callback(event, handler);\n },\n {\n enabled,\n enableOnFormTags,\n enableOnContentEditable,\n ...restOptions,\n }\n );\n}\n\n// Re-export useful utilities from react-hotkeys-hook\nexport { useHotkeysContext, HotkeysProvider, isHotkeyPressed } from 'react-hotkeys-hook';\n\n// Re-export types\nexport type { HotkeyCallback, Keys } from 'react-hotkeys-hook';\n","'use client';\n\nimport { useEffect, useMemo, useState } from 'react';\n\n// Safe defaults for SSR\nconst defaultSelectors = {\n isMobile: false,\n isTablet: false,\n isDesktop: false,\n isBrowser: false,\n isMobileOnly: false,\n isSmartTV: false,\n isConsole: false,\n isWearable: false,\n isEmbedded: false,\n isAndroid: false,\n isIOS: false,\n isWindows: false,\n isMacOs: false,\n isWinPhone: false,\n isChrome: false,\n isFirefox: false,\n isSafari: false,\n isOpera: false,\n isIE: false,\n isEdge: false,\n isEdgeChromium: false,\n isLegacyEdge: false,\n isChromium: false,\n isMobileSafari: false,\n isYandex: false,\n isMIUI: false,\n isSamsungBrowser: false,\n isElectron: false,\n osVersion: 'unknown',\n osName: 'unknown',\n fullBrowserVersion: 'unknown',\n browserVersion: 'unknown',\n browserName: 'unknown',\n mobileVendor: 'unknown',\n mobileModel: 'unknown',\n engineName: 'unknown',\n engineVersion: 'unknown',\n getUA: '',\n deviceType: 'unknown',\n isIOS13: false,\n isIPad13: false,\n isIPhone13: false,\n isIPod13: false,\n};\n\nconst defaultDeviceData = {\n deviceType: 'unknown',\n osName: 'unknown',\n osVersion: 'unknown',\n browserName: 'unknown',\n browserVersion: 'unknown',\n fullBrowserVersion: 'unknown',\n mobileVendor: 'unknown',\n mobileModel: 'unknown',\n engineName: 'unknown',\n engineVersion: 'unknown',\n getUA: '',\n};\n\nconst defaultOrientation = {\n isPortrait: false,\n isLandscape: false,\n orientation: 'portrait' as 'portrait' | 'landscape',\n};\n\n/**\n * Device detection hook wrapper for react-device-detect\n * \n * Provides a convenient interface to access device information including:\n * - Device type (mobile, tablet, desktop, etc.)\n * - Browser information (name, version, etc.)\n * - OS information (name, version, etc.)\n * - Orientation (portrait/landscape)\n * \n * @param userAgent - Optional user agent string (useful for SSR)\n * @returns Device detection object with all available information\n * \n * @example\n * ```tsx\n * const device = useDeviceDetect();\n * \n * if (device.isMobile) {\n * return <MobileView />;\n * }\n * \n * return <DesktopView />;\n * ```\n */\nexport function useDeviceDetect(userAgent?: string) {\n const [deviceInfo, setDeviceInfo] = useState<{\n selectors: typeof defaultSelectors;\n deviceData: typeof defaultDeviceData;\n orientation: {\n isPortrait: boolean;\n isLandscape: boolean;\n orientation: 'portrait' | 'landscape';\n };\n }>({\n selectors: defaultSelectors,\n deviceData: defaultDeviceData,\n orientation: defaultOrientation,\n });\n\n useEffect(() => {\n // Only run on client side\n if (typeof window === 'undefined') return;\n\n // Dynamic import to avoid SSR issues\n import('react-device-detect').then((deviceDetect) => {\n // Get user agent string\n const ua = userAgent || (typeof window !== 'undefined' ? window.navigator.userAgent : '');\n \n if (!ua) {\n console.warn('No user agent available');\n return;\n }\n\n // Parse user agent using library's parseUserAgent function\n const parsed = deviceDetect.parseUserAgent(ua);\n \n if (!parsed) {\n console.warn('Failed to parse user agent');\n return;\n }\n\n // Build selectors using library's buildSelectorsObject\n // We need to import buildSelectorsObject, but it's not exported\n // So we'll use getSelectorsByUserAgent which is exported\n const selectors = deviceDetect.getSelectorsByUserAgent(ua) || defaultSelectors;\n \n // Extract device data from parsed result\n const deviceData = {\n deviceType: parsed.device?.type || 'unknown',\n osName: parsed.os?.name || 'unknown',\n osVersion: parsed.os?.version || 'unknown',\n browserName: parsed.browser?.name || 'unknown',\n browserVersion: parsed.browser?.version || 'unknown',\n fullBrowserVersion: parsed.browser?.version || 'unknown',\n mobileVendor: parsed.device?.vendor || 'unknown',\n mobileModel: parsed.device?.model || 'unknown',\n engineName: parsed.engine?.name || 'unknown',\n engineVersion: parsed.engine?.version || 'unknown',\n getUA: parsed.ua || ua,\n };\n\n // Get orientation - use library's hook if available, otherwise calculate\n let orientation = defaultOrientation;\n \n try {\n // Try to use the hook, but we can't call hooks conditionally\n // So we'll calculate orientation manually\n if (typeof window !== 'undefined') {\n const isPortrait = window.innerHeight > window.innerWidth;\n orientation = {\n isPortrait,\n isLandscape: !isPortrait,\n orientation: (isPortrait ? 'portrait' : 'landscape') as 'portrait' | 'landscape',\n };\n }\n } catch (error) {\n console.warn('Failed to get orientation:', error);\n }\n \n setDeviceInfo({ selectors, deviceData, orientation });\n }).catch((error) => {\n console.warn('Failed to load device detection:', error);\n });\n }, [userAgent]);\n\n // Update orientation on window resize\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const handleResize = () => {\n const isPortrait = window.innerHeight > window.innerWidth;\n setDeviceInfo((prev) => ({\n ...prev,\n orientation: {\n isPortrait,\n isLandscape: !isPortrait,\n orientation: (isPortrait ? 'portrait' : 'landscape') as 'portrait' | 'landscape',\n },\n }));\n };\n\n window.addEventListener('resize', handleResize);\n window.addEventListener('orientationchange', handleResize);\n \n return () => {\n window.removeEventListener('resize', handleResize);\n window.removeEventListener('orientationchange', handleResize);\n };\n }, []);\n\n const { selectors, deviceData, orientation } = deviceInfo;\n\n return useMemo(() => {\n return {\n // Device type selectors\n isMobile: selectors.isMobile ?? false,\n isTablet: selectors.isTablet ?? false,\n isDesktop: selectors.isDesktop ?? false,\n isBrowser: selectors.isBrowser ?? false,\n isMobileOnly: selectors.isMobileOnly ?? false,\n isSmartTV: selectors.isSmartTV ?? false,\n isConsole: selectors.isConsole ?? false,\n isWearable: selectors.isWearable ?? false,\n isEmbedded: selectors.isEmbedded ?? false,\n\n // OS selectors\n isAndroid: selectors.isAndroid ?? false,\n isIOS: selectors.isIOS ?? false,\n isWindows: selectors.isWindows ?? false,\n isMacOs: selectors.isMacOs ?? false,\n isWinPhone: selectors.isWinPhone ?? false,\n\n // Browser selectors\n isChrome: selectors.isChrome ?? false,\n isFirefox: selectors.isFirefox ?? false,\n isSafari: selectors.isSafari ?? false,\n isOpera: selectors.isOpera ?? false,\n isIE: selectors.isIE ?? false,\n isEdge: selectors.isEdge ?? false,\n isEdgeChromium: selectors.isEdgeChromium ?? false,\n isLegacyEdge: selectors.isLegacyEdge ?? false,\n isChromium: selectors.isChromium ?? false,\n isMobileSafari: selectors.isMobileSafari ?? false,\n isYandex: selectors.isYandex ?? false,\n isMIUI: selectors.isMIUI ?? false,\n isSamsungBrowser: selectors.isSamsungBrowser ?? false,\n isElectron: selectors.isElectron ?? false,\n\n // iOS version selectors\n isIOS13: selectors.isIOS13 ?? false,\n isIPad13: selectors.isIPad13 ?? false,\n isIPhone13: selectors.isIPhone13 ?? false,\n isIPod13: selectors.isIPod13 ?? false,\n\n // Device information\n deviceType: deviceData.deviceType ?? 'unknown',\n osName: deviceData.osName ?? 'unknown',\n osVersion: deviceData.osVersion ?? 'unknown',\n browserName: deviceData.browserName ?? 'unknown',\n browserVersion: deviceData.browserVersion ?? 'unknown',\n fullBrowserVersion: deviceData.fullBrowserVersion ?? 'unknown',\n mobileVendor: deviceData.mobileVendor ?? 'unknown',\n mobileModel: deviceData.mobileModel ?? 'unknown',\n engineName: deviceData.engineName ?? 'unknown',\n engineVersion: deviceData.engineVersion ?? 'unknown',\n getUA: deviceData.getUA ?? '',\n\n // Orientation\n isPortrait: orientation.isPortrait,\n isLandscape: orientation.isLandscape,\n orientation: orientation.orientation,\n\n // Raw data (for advanced usage)\n selectors,\n deviceData,\n };\n }, [selectors, deviceData, orientation]);\n}\n\nexport type DeviceDetectResult = ReturnType<typeof useDeviceDetect>;\n","/**\n * Advanced browser detection hook\n *\n * Detects modern browsers including Chromium-based browsers that may\n * incorrectly report as Safari (Arc, Brave, Vivaldi, Comet, etc.)\n */\n\n'use client';\n\nimport { useMemo } from 'react';\n\nexport interface BrowserInfo {\n // Core browser types\n isChrome: boolean;\n isChromium: boolean; // Any Chromium-based browser\n isSafari: boolean; // Real Safari (WebKit on macOS/iOS)\n isFirefox: boolean;\n isEdge: boolean;\n isOpera: boolean;\n\n // Modern Chromium-based browsers\n isBrave: boolean;\n isArc: boolean;\n isVivaldi: boolean;\n isYandex: boolean;\n isSamsungBrowser: boolean;\n isUCBrowser: boolean;\n\n // Additional browsers\n isComet: boolean; // Perplexity's Comet browser (Chromium-based, supports push)\n isOperaMini: boolean; // Opera Mini (does NOT support push notifications)\n isIE: boolean; // Internet Explorer (does NOT support push notifications)\n\n // In-App Browsers (WebViews) - typically do NOT support push notifications\n isFacebookInApp: boolean; // Facebook's in-app browser\n isInstagramInApp: boolean; // Instagram's in-app browser\n isTikTokInApp: boolean; // TikTok's in-app browser\n isSnapchatInApp: boolean; // Snapchat's in-app browser\n isWeChatInApp: boolean; // WeChat's in-app browser\n isThreadsInApp: boolean; // Threads' in-app browser\n isLinkedInInApp: boolean; // LinkedIn's in-app browser (uses Chrome WebView - supports push on Android)\n isTwitterInApp: boolean; // Twitter/X's in-app browser (uses Chrome WebView - supports push on Android)\n isInAppBrowser: boolean; // Any in-app browser detected\n isWebView: boolean; // Generic WebView detection\n\n // Browser name\n browserName: string;\n\n // Engine\n isWebKit: boolean; // Safari's engine\n isBlink: boolean; // Chromium's engine\n isGecko: boolean; // Firefox's engine\n\n // Push notification support\n /**\n * Whether the browser supports Web Push Notifications.\n * Returns false for browsers known to NOT support push:\n * - Opera Mini (no service worker support)\n * - Internet Explorer (deprecated, no Push API)\n * - UC Browser (unreliable push support)\n * - In-App browsers (Facebook, Instagram, TikTok, Snapchat, etc.)\n * - Generic WebViews (except Twitter/LinkedIn on Android which use Chrome WebView)\n *\n * Note: Comet (Perplexity) is Chromium-based and DOES support push notifications.\n * Note: This is a browser-level check. For full push support,\n * also check 'serviceWorker' in navigator && 'PushManager' in window\n */\n supportsPushNotifications: boolean;\n\n // iOS specific\n isIOSBrowser: boolean; // Any browser on iOS (all use WebKit, limited push support)\n\n // For debugging\n userAgent: string;\n}\n\n/**\n * Detect browser with improved accuracy for Chromium-based browsers\n *\n * @example\n * ```tsx\n * const browser = useBrowserDetect();\n *\n * if (browser.isSafari && !browser.isChromium) {\n * // Real Safari\n * }\n *\n * if (browser.isChromium) {\n * // Any Chromium-based browser (Chrome, Edge, Brave, Arc, etc.)\n * }\n * ```\n */\nexport function useBrowserDetect(): BrowserInfo {\n return useMemo(() => {\n if (typeof window === 'undefined') {\n return {\n isChrome: false,\n isChromium: false,\n isSafari: false,\n isFirefox: false,\n isEdge: false,\n isOpera: false,\n isBrave: false,\n isArc: false,\n isVivaldi: false,\n isYandex: false,\n isSamsungBrowser: false,\n isUCBrowser: false,\n isComet: false,\n isOperaMini: false,\n isIE: false,\n isFacebookInApp: false,\n isInstagramInApp: false,\n isTikTokInApp: false,\n isSnapchatInApp: false,\n isWeChatInApp: false,\n isThreadsInApp: false,\n isLinkedInInApp: false,\n isTwitterInApp: false,\n isInAppBrowser: false,\n isWebView: false,\n browserName: 'unknown',\n isWebKit: false,\n isBlink: false,\n isGecko: false,\n supportsPushNotifications: false,\n isIOSBrowser: false,\n userAgent: '',\n };\n }\n\n const ua = window.navigator.userAgent.toLowerCase();\n\n // Check for specific browsers first (most specific to least specific)\n\n // Edge (Chromium-based)\n const isEdge = ua.includes('edg/') || ua.includes('edge/');\n\n // Brave (check for Brave-specific API)\n const isBrave = !!(window.navigator as any).brave;\n\n // Arc (check for Arc-specific markers in UA)\n const isArc = ua.includes('arc/');\n\n // Vivaldi\n const isVivaldi = ua.includes('vivaldi');\n\n // Yandex Browser\n const isYandex = ua.includes('yabrowser');\n\n // Samsung Internet\n const isSamsungBrowser = ua.includes('samsungbrowser');\n\n // UC Browser\n const isUCBrowser = ua.includes('ucbrowser') || ua.includes('uc browser');\n\n // Comet Browser (Perplexity's AI browser, Chromium-based)\n // May have 'comet' in UA or can be detected by specific markers\n const isComet = ua.includes('comet') || ua.includes('perplexity');\n\n // Opera Mini (does NOT support service workers or push)\n const isOperaMini = ua.includes('opera mini') || ua.includes('opios');\n\n // Internet Explorer (deprecated, no Push API support)\n const isIE = ua.includes('msie') || ua.includes('trident/');\n\n // ============================================================================\n // In-App Browsers Detection (WebViews)\n // These browsers typically do NOT support web push notifications\n // ============================================================================\n\n // Facebook In-App Browser\n // UA contains: FBAN (Facebook App Name) or FBAV (Facebook App Version)\n const isFacebookInApp = ua.includes('fban') || ua.includes('fbav') || ua.includes('fb_iab');\n\n // Instagram In-App Browser\n // UA contains: Instagram\n const isInstagramInApp = ua.includes('instagram');\n\n // TikTok In-App Browser\n // UA contains: TikTok or BytedanceWebview or ByteLocale\n const isTikTokInApp = ua.includes('tiktok') || ua.includes('bytedancewebview') || ua.includes('bytelocale');\n\n // Snapchat In-App Browser\n // UA contains: Snapchat\n const isSnapchatInApp = ua.includes('snapchat');\n\n // WeChat In-App Browser\n // UA contains: MicroMessenger\n const isWeChatInApp = ua.includes('micromessenger');\n\n // Threads In-App Browser (Meta's app)\n // UA contains: Threads or uses same markers as Instagram\n const isThreadsInApp = ua.includes('barcelona'); // Threads codename is Barcelona\n\n // LinkedIn In-App Browser\n // UA contains: LinkedIn - NOTE: Uses Chrome WebView on Android, may support push\n const isLinkedInInApp = ua.includes('linkedinapp');\n\n // Twitter/X In-App Browser\n // UA contains: Twitter - NOTE: Uses Chrome WebView on Android, may support push\n const isTwitterInApp = ua.includes('twitter');\n\n // Pinterest In-App Browser\n const isPinterestInApp = ua.includes('pinterest');\n\n // Telegram In-App Browser\n const isTelegramInApp = ua.includes('telegram');\n\n // Line In-App Browser\n const isLineInApp = ua.includes('line/');\n\n // Kakao In-App Browser (Korea)\n const isKakaoInApp = ua.includes('kakaotalk');\n\n // Generic WebView detection\n // Android WebView: contains 'wv' in UA or specific WebView markers\n // iOS WebView: WKWebView doesn't have distinct UA, but some markers exist\n const isWebView = ua.includes('wv)') || // Android WebView marker\n ua.includes('webview') ||\n ua.includes('; wv') ||\n (ua.includes('iphone') && !ua.includes('safari')) || // iOS WebView (no Safari)\n (ua.includes('ipad') && !ua.includes('safari'));\n\n // Aggregate: Any in-app browser\n const isInAppBrowser = isFacebookInApp ||\n isInstagramInApp ||\n isTikTokInApp ||\n isSnapchatInApp ||\n isWeChatInApp ||\n isThreadsInApp ||\n isLinkedInInApp ||\n isTwitterInApp ||\n isPinterestInApp ||\n isTelegramInApp ||\n isLineInApp ||\n isKakaoInApp;\n\n // iOS detection (all iOS browsers use WebKit, limited push support)\n const isIOSBrowser = ua.includes('iphone') || ua.includes('ipad') || ua.includes('ipod');\n\n // Opera (modern Chromium-based)\n const isOpera = (ua.includes('opr/') || ua.includes('opera')) && !isOperaMini;\n\n // Chrome (not Edge, not other Chromium browsers)\n const isChrome = ua.includes('chrome') &&\n !isEdge &&\n !isOpera &&\n !isYandex &&\n !isSamsungBrowser &&\n !isVivaldi &&\n !isArc &&\n !isBrave &&\n !isComet;\n\n // Firefox\n const isFirefox = ua.includes('firefox') && !ua.includes('seamonkey');\n\n // Safari (real Safari, not Chromium pretending to be Safari)\n // Safari will have 'safari' in UA but NOT 'chrome' or 'chromium'\n // Real Safari uses WebKit engine\n // Additional check: Safari has 'version/' in UA, Chromium browsers don't combine it with Safari\n const hasSafariUA = ua.includes('safari');\n const hasChrome = ua.includes('chrome') || ua.includes('crios');\n const hasVersion = ua.includes('version/'); // Real Safari includes Version/XX.X\n const isSafari = hasSafariUA && !hasChrome && hasVersion;\n\n // Chromium detection (any browser using Chromium/Blink engine)\n // If it has \"chrome\" in UA or is one of the known Chromium browsers\n const isChromium = hasChrome ||\n isEdge ||\n isOpera ||\n isYandex ||\n isSamsungBrowser ||\n isVivaldi ||\n isArc ||\n isBrave ||\n isUCBrowser ||\n isComet;\n\n // Engine detection\n const isWebKit = !isChromium && isSafari;\n const isBlink = isChromium;\n const isGecko = isFirefox;\n\n // Determine browser name\n // In-app browsers take priority in naming\n let browserName = 'unknown';\n if (isFacebookInApp) browserName = 'Facebook In-App';\n else if (isInstagramInApp) browserName = 'Instagram In-App';\n else if (isTikTokInApp) browserName = 'TikTok In-App';\n else if (isSnapchatInApp) browserName = 'Snapchat In-App';\n else if (isWeChatInApp) browserName = 'WeChat In-App';\n else if (isThreadsInApp) browserName = 'Threads In-App';\n else if (isLinkedInInApp) browserName = 'LinkedIn In-App';\n else if (isTwitterInApp) browserName = 'Twitter In-App';\n else if (isPinterestInApp) browserName = 'Pinterest In-App';\n else if (isTelegramInApp) browserName = 'Telegram In-App';\n else if (isLineInApp) browserName = 'Line In-App';\n else if (isKakaoInApp) browserName = 'KakaoTalk In-App';\n else if (isComet) browserName = 'Comet';\n else if (isOperaMini) browserName = 'Opera Mini';\n else if (isIE) browserName = 'Internet Explorer';\n else if (isBrave) browserName = 'Brave';\n else if (isArc) browserName = 'Arc';\n else if (isVivaldi) browserName = 'Vivaldi';\n else if (isYandex) browserName = 'Yandex';\n else if (isSamsungBrowser) browserName = 'Samsung Internet';\n else if (isUCBrowser) browserName = 'UC Browser';\n else if (isEdge) browserName = 'Edge';\n else if (isOpera) browserName = 'Opera';\n else if (isChrome) browserName = 'Chrome';\n else if (isSafari) browserName = 'Safari';\n else if (isFirefox) browserName = 'Firefox';\n else if (isWebView) browserName = 'WebView';\n\n // Determine push notification support\n // These browsers are known to NOT support Web Push:\n // - Opera Mini: no service worker support\n // - Internet Explorer: deprecated, no Push API\n // - UC Browser: unreliable push support on many versions\n // - Most In-App browsers (Facebook, Instagram, TikTok, etc.)\n // - Generic WebViews (except Twitter/LinkedIn on Android)\n //\n // Note: Comet (Perplexity) is Chromium-based and DOES support push notifications.\n // Note: Twitter and LinkedIn on Android use Chrome WebView and DO support push.\n // However, we err on the side of caution and disable for all in-app browsers.\n const browserBlocksPush = isOperaMini ||\n isIE ||\n isUCBrowser ||\n isFacebookInApp ||\n isInstagramInApp ||\n isTikTokInApp ||\n isSnapchatInApp ||\n isWeChatInApp ||\n isThreadsInApp ||\n isPinterestInApp ||\n isTelegramInApp ||\n isLineInApp ||\n isKakaoInApp ||\n isWebView;\n\n // Twitter and LinkedIn on Android use Chrome WebView - they actually support push\n // But only on Android, not iOS\n const twitterLinkedInAndroid = (isTwitterInApp || isLinkedInInApp) && !isIOSBrowser;\n\n const supportsPushNotifications = !browserBlocksPush || twitterLinkedInAndroid;\n\n return {\n isChrome,\n isChromium,\n isSafari,\n isFirefox,\n isEdge,\n isOpera,\n isBrave,\n isArc,\n isVivaldi,\n isYandex,\n isSamsungBrowser,\n isUCBrowser,\n isComet,\n isOperaMini,\n isIE,\n isFacebookInApp,\n isInstagramInApp,\n isTikTokInApp,\n isSnapchatInApp,\n isWeChatInApp,\n isThreadsInApp,\n isLinkedInInApp,\n isTwitterInApp,\n isInAppBrowser,\n isWebView,\n browserName,\n isWebKit,\n isBlink,\n isGecko,\n supportsPushNotifications,\n isIOSBrowser,\n userAgent: window.navigator.userAgent,\n };\n }, []);\n}\n"]}
|