@dashadmin/dash-utils 1.3.73 → 1.3.74-srcfree.1

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.
Files changed (66) hide show
  1. package/dist/components/LazyAppLoader.d.ts +17 -0
  2. package/dist/components/MinimalLayout.d.ts +6 -0
  3. package/dist/components/RouterComponent.d.ts +22 -0
  4. package/dist/components/index.d.ts +2 -0
  5. package/dist/contexts/IPCMessageBrokerContext.d.ts +42 -0
  6. package/dist/hooks/useCapacitorAppStateRefresh.d.ts +2 -0
  7. package/dist/hooks/useCapacitorKeyboard.d.ts +19 -0
  8. package/dist/hooks/useDeviceStorageSync.d.ts +4 -0
  9. package/dist/hooks/useDraggable.d.ts +24 -0
  10. package/dist/hooks/useMenuStateInit.d.ts +10 -0
  11. package/dist/hooks/useMobileDetection.d.ts +20 -0
  12. package/dist/hooks/useNotifications.d.ts +51 -0
  13. package/dist/hooks/useQuickSearch.d.ts +6 -0
  14. package/dist/hooks/useWindowSize.d.ts +6 -0
  15. package/dist/index.d.ts +30 -0
  16. package/dist/utils/authProviderUtils.d.ts +37 -0
  17. package/dist/utils/dashBootstrapApp.d.ts +9 -0
  18. package/dist/utils/dashDtorage.d.ts +8 -0
  19. package/dist/utils/dashIPCService.d.ts +93 -0
  20. package/dist/utils/dataProviderUtils.d.ts +44 -0
  21. package/dist/utils/electronStoreSync.d.ts +3 -0
  22. package/dist/utils/envUtils.d.ts +1 -0
  23. package/dist/utils/environmentBodyClasses.d.ts +11 -0
  24. package/dist/utils/isDev.d.ts +5 -0
  25. package/dist/utils/notificationPermission.d.ts +5 -0
  26. package/dist/utils/platformDetection.d.ts +13 -0
  27. package/dist/utils/priceFormatter.d.ts +2 -0
  28. package/dist/utils/resourceLoader.d.ts +8 -0
  29. package/dist/utils/speechService.d.ts +7 -0
  30. package/dist/utils/storedTheme.d.ts +11 -0
  31. package/dist/utils/updateDomCssVariables.d.ts +6 -0
  32. package/dist/utils/validation.d.ts +12 -0
  33. package/package.json +13 -10
  34. package/src/components/LazyAppLoader.tsx +0 -143
  35. package/src/components/MinimalLayout.tsx +0 -22
  36. package/src/components/RouterComponent.tsx +0 -169
  37. package/src/components/index.ts +0 -16
  38. package/src/contexts/IPCMessageBrokerContext.tsx +0 -303
  39. package/src/hooks/useCapacitorAppStateRefresh.ts +0 -34
  40. package/src/hooks/useCapacitorKeyboard.ts +0 -213
  41. package/src/hooks/useDeviceStorageSync.ts +0 -70
  42. package/src/hooks/useDraggable.ts +0 -133
  43. package/src/hooks/useMenuStateInit.ts +0 -85
  44. package/src/hooks/useMobileDetection.ts +0 -165
  45. package/src/hooks/useNotifications.ts +0 -220
  46. package/src/hooks/useQuickSearch.ts +0 -42
  47. package/src/hooks/useWindowSize.tsx +0 -36
  48. package/src/index.ts +0 -202
  49. package/src/utils/authProviderUtils.ts +0 -170
  50. package/src/utils/dashBootstrapApp.ts +0 -104
  51. package/src/utils/dashDtorage.tsx +0 -51
  52. package/src/utils/dashDtorage.tsx.old +0 -78
  53. package/src/utils/dashIPCService.ts +0 -204
  54. package/src/utils/dataProviderUtils.ts +0 -221
  55. package/src/utils/electronStoreSync.ts +0 -34
  56. package/src/utils/envUtils.tsx +0 -27
  57. package/src/utils/environmentBodyClasses.ts +0 -72
  58. package/src/utils/isDev.ts +0 -65
  59. package/src/utils/notificationPermission.ts +0 -57
  60. package/src/utils/platformDetection.ts +0 -98
  61. package/src/utils/priceFormatter.ts +0 -36
  62. package/src/utils/resourceLoader.ts +0 -107
  63. package/src/utils/speechService.ts +0 -112
  64. package/src/utils/storedTheme.ts +0 -60
  65. package/src/utils/updateDomCssVariables.tsx +0 -181
  66. package/src/utils/validation.ts +0 -147
@@ -1,213 +0,0 @@
1
- import { useEffect, useState, useCallback } from 'react';
2
-
3
- export interface KeyboardState {
4
- isKeyboardOpen: boolean;
5
- keyboardHeight: number;
6
- }
7
-
8
- export interface UseCapacitorKeyboardOptions {
9
- /** Disable accessory bar for cleaner UI */
10
- disableAccessoryBar?: boolean;
11
- /** Resize mode: 'body', 'ionic', 'native', 'none' */
12
- resizeMode?: 'body' | 'ionic' | 'native' | 'none';
13
- /** Enable debug logging */
14
- debug?: boolean;
15
- }
16
-
17
- /**
18
- * Check if Capacitor Keyboard plugin is available
19
- */
20
- export const isCapacitorKeyboardAvailable = (): boolean => {
21
- const hasCapacitor = !!(window as any)?.Capacitor?.Plugins?.Keyboard;
22
- const hasCapacitorKeyboard = !!(window as any)?.CapacitorKeyboard;
23
- return hasCapacitor || hasCapacitorKeyboard;
24
- };
25
-
26
- /**
27
- * Get Capacitor Keyboard instance from window
28
- */
29
- export const getCapacitorKeyboard = () => {
30
- return (window as any)?.Capacitor?.Plugins?.Keyboard || (window as any)?.CapacitorKeyboard;
31
- };
32
-
33
- /**
34
- * Hook for Capacitor keyboard detection and management
35
- * Handles both Capacitor native keyboard and fallback viewport-based detection
36
- *
37
- * @param options - Configuration options
38
- * @returns Keyboard state and utility functions
39
- */
40
- export const useCapacitorKeyboard = (options: UseCapacitorKeyboardOptions = {}) => {
41
- const {
42
- disableAccessoryBar = true,
43
- resizeMode = 'body',
44
- debug = false
45
- } = options;
46
-
47
- const [keyboardState, setKeyboardState] = useState<KeyboardState>({
48
- isKeyboardOpen: false,
49
- keyboardHeight: 0,
50
- });
51
-
52
- const log = useCallback((message: string, data?: any) => {
53
- if (debug) {
54
- console.log(`[useCapacitorKeyboard] ${message}`, data || '');
55
- }
56
- }, [debug]);
57
-
58
- // Hide keyboard programmatically
59
- const hideKeyboard = useCallback(async () => {
60
- if (isCapacitorKeyboardAvailable()) {
61
- const Keyboard = getCapacitorKeyboard();
62
- if (Keyboard?.hide) {
63
- try {
64
- log('Hiding keyboard...');
65
- await Keyboard.hide();
66
- } catch (error) {
67
- log('Error hiding keyboard:', error);
68
- }
69
- }
70
- }
71
- }, [log]);
72
-
73
- // Show keyboard programmatically
74
- const showKeyboard = useCallback(async () => {
75
- if (isCapacitorKeyboardAvailable()) {
76
- const Keyboard = getCapacitorKeyboard();
77
- if (Keyboard?.show) {
78
- try {
79
- log('Showing keyboard...');
80
- await Keyboard.show();
81
- } catch (error) {
82
- log('Error showing keyboard:', error);
83
- }
84
- }
85
- }
86
- }, [log]);
87
-
88
- // Configure Capacitor Keyboard
89
- useEffect(() => {
90
- const configureKeyboard = async () => {
91
- if (isCapacitorKeyboardAvailable()) {
92
- const Keyboard = getCapacitorKeyboard();
93
- if (Keyboard) {
94
- try {
95
- log('Configuring Capacitor Keyboard...');
96
-
97
- if (Keyboard.setAccessoryBarVisible) {
98
- await Keyboard.setAccessoryBarVisible({ isVisible: !disableAccessoryBar });
99
- }
100
-
101
- if (Keyboard.setResizeMode) {
102
- await Keyboard.setResizeMode({ mode: resizeMode });
103
- }
104
-
105
- log('Capacitor Keyboard configured successfully');
106
- } catch (error) {
107
- log('Error configuring Capacitor Keyboard:', error);
108
- }
109
- }
110
- }
111
- };
112
-
113
- configureKeyboard();
114
- }, [disableAccessoryBar, resizeMode, log]);
115
-
116
- // Setup keyboard listeners
117
- useEffect(() => {
118
- if (isCapacitorKeyboardAvailable()) {
119
- const Keyboard = getCapacitorKeyboard();
120
-
121
- if (Keyboard) {
122
- log('Using Capacitor Keyboard API');
123
-
124
- const handleKeyboardWillShow = (info: any) => {
125
- log('Keyboard will show', { height: info.keyboardHeight });
126
- setKeyboardState({
127
- isKeyboardOpen: true,
128
- keyboardHeight: info.keyboardHeight,
129
- });
130
- };
131
-
132
- const handleKeyboardDidShow = (info: any) => {
133
- setKeyboardState({
134
- isKeyboardOpen: true,
135
- keyboardHeight: info.keyboardHeight,
136
- });
137
- };
138
-
139
- const handleKeyboardWillHide = () => {
140
- log('Keyboard will hide');
141
- setKeyboardState({
142
- isKeyboardOpen: false,
143
- keyboardHeight: 0,
144
- });
145
- };
146
-
147
- const handleKeyboardDidHide = () => {
148
- setKeyboardState({
149
- isKeyboardOpen: false,
150
- keyboardHeight: 0,
151
- });
152
- };
153
-
154
- Keyboard.addListener('keyboardWillShow', handleKeyboardWillShow);
155
- Keyboard.addListener('keyboardDidShow', handleKeyboardDidShow);
156
- Keyboard.addListener('keyboardWillHide', handleKeyboardWillHide);
157
- Keyboard.addListener('keyboardDidHide', handleKeyboardDidHide);
158
-
159
- return () => {
160
- Keyboard.removeAllListeners?.();
161
- };
162
- }
163
- }
164
-
165
- // Fallback: viewport-based detection for web
166
- log('Using fallback viewport-based keyboard detection');
167
-
168
- let previousViewportHeight = window.visualViewport?.height || window.innerHeight;
169
-
170
- const handleResize = () => {
171
- const viewportHeight = window.visualViewport?.height || window.innerHeight;
172
- const screenHeight = window.screen.height;
173
-
174
- // If viewport is significantly smaller than screen, keyboard is likely open
175
- const keyboardThreshold = screenHeight * 0.75;
176
- const keyboardOpen = viewportHeight < keyboardThreshold;
177
-
178
- if (keyboardOpen !== keyboardState.isKeyboardOpen) {
179
- const estimatedKeyboardHeight = keyboardOpen ? screenHeight - viewportHeight : 0;
180
- log(keyboardOpen ? 'Keyboard opened (fallback)' : 'Keyboard closed (fallback)', {
181
- height: estimatedKeyboardHeight
182
- });
183
- setKeyboardState({
184
- isKeyboardOpen: keyboardOpen,
185
- keyboardHeight: estimatedKeyboardHeight,
186
- });
187
- }
188
-
189
- previousViewportHeight = viewportHeight;
190
- };
191
-
192
- window.addEventListener('resize', handleResize);
193
- if (window.visualViewport) {
194
- window.visualViewport.addEventListener('resize', handleResize);
195
- }
196
-
197
- return () => {
198
- window.removeEventListener('resize', handleResize);
199
- if (window.visualViewport) {
200
- window.visualViewport.removeEventListener('resize', handleResize);
201
- }
202
- };
203
- }, [log, keyboardState.isKeyboardOpen]);
204
-
205
- return {
206
- ...keyboardState,
207
- hideKeyboard,
208
- showKeyboard,
209
- isCapacitorAvailable: isCapacitorKeyboardAvailable(),
210
- };
211
- };
212
-
213
- export default useCapacitorKeyboard;
@@ -1,70 +0,0 @@
1
- import { useEffect } from 'react';
2
-
3
- /**
4
- * Hook to sync device storage (Electron store) with localStorage
5
- * Useful for Electron apps to maintain state persistence
6
- */
7
- export const useDeviceStorageSync = () => {
8
- useEffect(() => {
9
- const syncDeviceStoreToLocalStorage = async () => {
10
- const electronStore = (window as any).electronStore;
11
- if (electronStore && electronStore.getAll) {
12
- // Sync logic can be implemented here if needed
13
- // Currently placeholder for future implementation
14
- console.log('[useDeviceStorageSync] Electron store detected');
15
- }
16
- };
17
- syncDeviceStoreToLocalStorage();
18
- }, []);
19
- };
20
-
21
- /**
22
- * Sync all data from Electron store to localStorage
23
- * Call this on app initialization
24
- */
25
- export const syncDeviceStoreToLocalStorage = async (): Promise<void> => {
26
- const electronStore = (window as any).electronStore;
27
- if (electronStore && electronStore.getAll) {
28
- try {
29
- const allData = await electronStore.getAll();
30
- if (allData && typeof allData === 'object') {
31
- for (const [key, value] of Object.entries(allData)) {
32
- window.localStorage.setItem(key, JSON.stringify(value));
33
- }
34
- console.log('[syncDeviceStoreToLocalStorage] Synced electron-store to localStorage');
35
- }
36
- } catch (err) {
37
- console.error('[syncDeviceStoreToLocalStorage] Failed to sync:', err);
38
- }
39
- }
40
- };
41
-
42
- /**
43
- * Sync all data from localStorage to Electron store
44
- * Call this after auth changes or important state updates
45
- */
46
- export const syncLocalStorageToDeviceStore = async (): Promise<void> => {
47
- const electronStore = (window as any).electronStore;
48
- if (electronStore && electronStore.set) {
49
- try {
50
- for (let i = 0; i < window.localStorage.length; i++) {
51
- const key = window.localStorage.key(i);
52
- if (key) {
53
- const value = window.localStorage.getItem(key);
54
- if (value !== null) {
55
- try {
56
- await electronStore.set(key, JSON.parse(value));
57
- } catch {
58
- await electronStore.set(key, value);
59
- }
60
- }
61
- }
62
- }
63
- console.log('[syncLocalStorageToDeviceStore] Synced localStorage to electron-store');
64
- } catch (err) {
65
- console.error('[syncLocalStorageToDeviceStore] Failed to sync:', err);
66
- }
67
- }
68
- };
69
-
70
- export default useDeviceStorageSync;
@@ -1,133 +0,0 @@
1
- import { useState, useCallback, useEffect } from 'react';
2
-
3
- export interface DraggablePosition {
4
- x: number;
5
- y: number;
6
- }
7
-
8
- export interface UseDraggableOptions {
9
- /** Initial position */
10
- initialPosition?: DraggablePosition;
11
- /** Minimum X position (default: 0) */
12
- minX?: number;
13
- /** Minimum Y position (default: 0) */
14
- minY?: number;
15
- /** Maximum X position (default: window.innerWidth - elementWidth) */
16
- maxX?: number;
17
- /** Maximum Y position (default: window.innerHeight - elementHeight) */
18
- maxY?: number;
19
- /** Element width for boundary calculation */
20
- elementWidth?: number;
21
- /** Element height for boundary calculation */
22
- elementHeight?: number;
23
- /** Callback when position changes */
24
- onPositionChange?: (position: DraggablePosition) => void;
25
- /** Callback when drag starts */
26
- onDragStart?: () => void;
27
- /** Callback when drag ends */
28
- onDragEnd?: () => void;
29
- }
30
-
31
- export interface UseDraggableReturn {
32
- position: DraggablePosition;
33
- isDragging: boolean;
34
- handleMouseDown: (e: React.MouseEvent) => void;
35
- setPosition: (position: DraggablePosition) => void;
36
- }
37
-
38
- /**
39
- * Hook for making elements draggable
40
- * Handles mouse events and position calculations
41
- */
42
- export const useDraggable = (options: UseDraggableOptions = {}): UseDraggableReturn => {
43
- const {
44
- initialPosition = { x: 0, y: 0 },
45
- minX = 0,
46
- minY = 0,
47
- maxX,
48
- maxY,
49
- elementWidth = 400,
50
- elementHeight = 200,
51
- onPositionChange,
52
- onDragStart,
53
- onDragEnd,
54
- } = options;
55
-
56
- const [position, setPosition] = useState<DraggablePosition>(initialPosition);
57
- const [isDragging, setIsDragging] = useState(false);
58
- const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
59
-
60
- // Calculate boundaries
61
- const getMaxX = useCallback(() => {
62
- if (maxX !== undefined) return maxX;
63
- return typeof window !== 'undefined' ? window.innerWidth - elementWidth : 1000;
64
- }, [maxX, elementWidth]);
65
-
66
- const getMaxY = useCallback(() => {
67
- if (maxY !== undefined) return maxY;
68
- return typeof window !== 'undefined' ? window.innerHeight - elementHeight : 800;
69
- }, [maxY, elementHeight]);
70
-
71
- // Handle mouse down - start dragging
72
- const handleMouseDown = useCallback((e: React.MouseEvent) => {
73
- // Only start drag if clicking on an element with .drag-handle class
74
- if ((e.target as HTMLElement).closest('.drag-handle')) {
75
- e.preventDefault();
76
- setIsDragging(true);
77
- setDragOffset({
78
- x: e.clientX - position.x,
79
- y: e.clientY - position.y,
80
- });
81
- onDragStart?.();
82
- }
83
- }, [position, onDragStart]);
84
-
85
- // Handle mouse move
86
- const handleMouseMove = useCallback((e: MouseEvent) => {
87
- if (isDragging) {
88
- e.preventDefault();
89
- const newX = Math.max(minX, Math.min(getMaxX(), e.clientX - dragOffset.x));
90
- const newY = Math.max(minY, Math.min(getMaxY(), e.clientY - dragOffset.y));
91
- const newPosition = { x: newX, y: newY };
92
- setPosition(newPosition);
93
- onPositionChange?.(newPosition);
94
- }
95
- }, [isDragging, dragOffset, minX, minY, getMaxX, getMaxY, onPositionChange]);
96
-
97
- // Handle mouse up - stop dragging
98
- const handleMouseUp = useCallback(() => {
99
- if (isDragging) {
100
- setIsDragging(false);
101
- onDragEnd?.();
102
- }
103
- }, [isDragging, onDragEnd]);
104
-
105
- // Add/remove event listeners
106
- useEffect(() => {
107
- if (isDragging) {
108
- document.addEventListener('mousemove', handleMouseMove);
109
- document.addEventListener('mouseup', handleMouseUp);
110
- document.body.style.userSelect = 'none';
111
-
112
- return () => {
113
- document.removeEventListener('mousemove', handleMouseMove);
114
- document.removeEventListener('mouseup', handleMouseUp);
115
- document.body.style.userSelect = '';
116
- };
117
- }
118
- }, [isDragging, handleMouseMove, handleMouseUp]);
119
-
120
- // Update position when initialPosition changes
121
- useEffect(() => {
122
- setPosition(initialPosition);
123
- }, [initialPosition.x, initialPosition.y]);
124
-
125
- return {
126
- position,
127
- isDragging,
128
- handleMouseDown,
129
- setPosition,
130
- };
131
- };
132
-
133
- export default useDraggable;
@@ -1,85 +0,0 @@
1
- /**
2
- * Menu State Initialization Hook
3
- *
4
- * Hook to initialize menu/navigation state from localStorage
5
- * and sync it with Redux store.
6
- */
7
- import { useEffect } from 'react';
8
- import { useDispatch } from 'react-redux';
9
- import { dashStorage } from '../utils/dashDtorage';
10
-
11
- /**
12
- * Options for the useMenuStateInit hook
13
- */
14
- export interface UseMenuStateInitOptions {
15
- /** Storage key for nav expanded state */
16
- navExpandedKey?: string;
17
- /** Storage key for nav size */
18
- navSizeKey?: string;
19
- /** Redux action creator for setting nav expanded */
20
- setNavExpandedAction?: (isExpanded: boolean) => any;
21
- /** Redux action creator for setting nav size */
22
- setNavSizeAction?: (size: string) => any;
23
- }
24
-
25
- /**
26
- * Default options
27
- */
28
- const defaultOptions: UseMenuStateInitOptions = {
29
- navExpandedKey: 'dashNavExpanded',
30
- navSizeKey: 'dashNavSize',
31
- };
32
-
33
- /**
34
- * Hook to initialize menu state from localStorage
35
- * Reads persisted navigation state and dispatches Redux actions
36
- */
37
- export const useMenuStateInit = (options: UseMenuStateInitOptions = {}) => {
38
- const dispatch = useDispatch();
39
- const {
40
- navExpandedKey = defaultOptions.navExpandedKey!,
41
- setNavExpandedAction
42
- } = options;
43
-
44
- useEffect(() => {
45
- if (!setNavExpandedAction) return;
46
-
47
- try {
48
- const savedNavState = dashStorage.getItem(navExpandedKey);
49
- if (savedNavState !== null) {
50
- const isExpanded = savedNavState === 'true';
51
- dispatch(setNavExpandedAction(isExpanded));
52
- }
53
- } catch (e) {
54
- console.error('Error accessing localStorage:', e);
55
- }
56
- }, [dispatch, navExpandedKey, setNavExpandedAction]);
57
- };
58
-
59
- /**
60
- * Initialize menu state without Redux (returns state)
61
- * Useful for initial state setup
62
- */
63
- export const getInitialMenuState = (navExpandedKey: string = 'dashNavExpanded') => {
64
- try {
65
- const savedNavState = dashStorage.getItem(navExpandedKey);
66
- return savedNavState !== null ? savedNavState === 'true' : true;
67
- } catch (e) {
68
- console.error('Error accessing localStorage:', e);
69
- return true;
70
- }
71
- };
72
-
73
- /**
74
- * Get initial nav size from localStorage
75
- */
76
- export const getInitialNavSize = (navSizeKey: string = 'dashNavSize') => {
77
- try {
78
- return dashStorage.getItem(navSizeKey) || 'small';
79
- } catch (e) {
80
- console.error('Error accessing localStorage:', e);
81
- return 'small';
82
- }
83
- };
84
-
85
- export default useMenuStateInit;
@@ -1,165 +0,0 @@
1
- import { useEffect, useState, useCallback } from 'react';
2
-
3
- export interface MobileDetectionState {
4
- isMobile: boolean;
5
- isAndroid: boolean;
6
- isIOS: boolean;
7
- isWebView: boolean;
8
- screenWidth: number;
9
- }
10
-
11
- export interface UseMobileDetectionOptions {
12
- /** Screen width threshold to consider as mobile (default: 700) */
13
- mobileBreakpoint?: number;
14
- /** Enable debug logging */
15
- debug?: boolean;
16
- }
17
-
18
- /**
19
- * Check if the current environment is a mobile device
20
- * Based on body classes and screen width
21
- */
22
- export const checkMobileDevice = (mobileBreakpoint: number = 700): boolean => {
23
- // Check body classes for mobile devices
24
- const bodyClasses = document.body.className;
25
- const hasMobileClass = bodyClasses.includes('webview') ||
26
- bodyClasses.includes('android') ||
27
- bodyClasses.includes('ios') ||
28
- bodyClasses.includes('mobile');
29
-
30
- // Check screen width
31
- const screenWidth = window.innerWidth;
32
- const isSmallScreen = screenWidth < mobileBreakpoint;
33
-
34
- // Consider mobile if either condition is true
35
- return hasMobileClass || isSmallScreen;
36
- };
37
-
38
- /**
39
- * Check if running in a WebView
40
- */
41
- export const isWebView = (): boolean => {
42
- const userAgent = navigator.userAgent.toLowerCase();
43
- return (/(webview|wv)/.test(userAgent) ||
44
- /android.*(wv|.net)/.test(userAgent) || /iphone|ipod|ipad.*applewebkit(?!.*safari)/i.test(userAgent));
45
- };
46
-
47
- /**
48
- * Check if running on Android
49
- */
50
- export const isAndroid = (): boolean => {
51
- return /android/i.test(navigator.userAgent.toLowerCase());
52
- };
53
-
54
- /**
55
- * Check if running on iOS
56
- */
57
- export const isIOS = (): boolean => {
58
- return /iphone|ipad|ipod/i.test(navigator.userAgent.toLowerCase());
59
- };
60
-
61
- /**
62
- * Check if running on Windows
63
- */
64
- export const isWindows = (): boolean => {
65
- try {
66
- // Check Node.js process (for Electron)
67
- const nodeProcess = (globalThis as any).process;
68
- if (nodeProcess?.platform === 'win32') return true;
69
-
70
- return navigator.userAgent.toLowerCase().includes('windows');
71
- } catch (error) {
72
- return false;
73
- }
74
- };
75
-
76
- /**
77
- * Check if running on macOS
78
- */
79
- export const isMacOS = (): boolean => {
80
- try {
81
- // Check Node.js process (for Electron)
82
- const nodeProcess = (globalThis as any).process;
83
- if (nodeProcess?.platform === 'darwin') return true;
84
-
85
- return /macintosh|mac os x/i.test(navigator.userAgent.toLowerCase());
86
- } catch (error) {
87
- return false;
88
- }
89
- };
90
-
91
- /**
92
- * Check if running on Linux
93
- */
94
- export const isLinux = (): boolean => {
95
- try {
96
- // Check Node.js process (for Electron)
97
- const nodeProcess = (globalThis as any).process;
98
- if (nodeProcess?.platform === 'linux') return true;
99
-
100
- return /linux/i.test(navigator.userAgent.toLowerCase());
101
- } catch (error) {
102
- return false;
103
- }
104
- };
105
-
106
- /**
107
- * Hook for detecting mobile devices and platform information
108
- *
109
- * @param options - Configuration options
110
- * @returns Mobile detection state
111
- */
112
- export const useMobileDetection = (options: UseMobileDetectionOptions = {}) => {
113
- const { mobileBreakpoint = 700, debug = false } = options;
114
-
115
- const [state, setState] = useState<MobileDetectionState>(() => ({
116
- isMobile: checkMobileDevice(mobileBreakpoint),
117
- isAndroid: isAndroid(),
118
- isIOS: isIOS(),
119
- isWebView: isWebView(),
120
- screenWidth: window.innerWidth,
121
- }));
122
-
123
- const log = useCallback((message: string, data?: any) => {
124
- if (debug) {
125
- console.log(`[useMobileDetection] ${message}`, data || '');
126
- }
127
- }, [debug]);
128
-
129
- useEffect(() => {
130
- const handleResize = () => {
131
- const newState: MobileDetectionState = {
132
- isMobile: checkMobileDevice(mobileBreakpoint),
133
- isAndroid: isAndroid(),
134
- isIOS: isIOS(),
135
- isWebView: isWebView(),
136
- screenWidth: window.innerWidth,
137
- };
138
-
139
- // Only update if something changed
140
- if (newState.isMobile !== state.isMobile || newState.screenWidth !== state.screenWidth) {
141
- log('Mobile detection state changed', newState);
142
- setState(newState);
143
- }
144
- };
145
-
146
- window.addEventListener('resize', handleResize);
147
-
148
- // Also listen to orientation changes
149
- window.addEventListener('orientationchange', handleResize);
150
-
151
- return () => {
152
- window.removeEventListener('resize', handleResize);
153
- window.removeEventListener('orientationchange', handleResize);
154
- };
155
- }, [mobileBreakpoint, state.isMobile, state.screenWidth, log]);
156
-
157
- // Initial detection logging
158
- useEffect(() => {
159
- log('Initial mobile detection', state);
160
- }, []);
161
-
162
- return state;
163
- };
164
-
165
- export default useMobileDetection;