@geekmidas/ui 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/index.cjs +5 -0
- package/dist/hooks/index.d.cts +2 -0
- package/dist/hooks/index.d.mts +2 -0
- package/dist/hooks/index.mjs +3 -0
- package/dist/hooks-DBc-Cw9X.mjs +206 -0
- package/dist/hooks-DBc-Cw9X.mjs.map +1 -0
- package/dist/hooks-DuxmSO-h.cjs +252 -0
- package/dist/hooks-DuxmSO-h.cjs.map +1 -0
- package/dist/index-DmtSyJ1q.d.mts +113 -0
- package/dist/index-DmtSyJ1q.d.mts.map +1 -0
- package/dist/index-QNnnyGjB.d.cts +113 -0
- package/dist/index-QNnnyGjB.d.cts.map +1 -0
- package/dist/index.cjs +2566 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +727 -1
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +727 -1
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2428 -0
- package/dist/index.mjs.map +1 -0
- package/dist/styles/theme.cjs +6 -0
- package/dist/styles/theme.d.cts +2 -0
- package/dist/styles/theme.d.mts +2 -0
- package/dist/styles/theme.mjs +3 -0
- package/dist/theme-B5mGkTlU.d.cts +103 -0
- package/dist/theme-B5mGkTlU.d.cts.map +1 -0
- package/dist/theme-BRGSS8qx.cjs +135 -0
- package/dist/theme-BRGSS8qx.cjs.map +1 -0
- package/dist/theme-DAiFBbyM.mjs +111 -0
- package/dist/theme-DAiFBbyM.mjs.map +1 -0
- package/dist/theme-vpDwDfcR.d.mts +103 -0
- package/dist/theme-vpDwDfcR.d.mts.map +1 -0
- package/package.json +96 -5
- package/src/styles/globals.css +175 -0
- package/src/styles/theme.ts +138 -0
- package/scripts/embed-ui.ts +0 -97
- package/src/index.ts +0 -1
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/hooks/use-debounce.ts
|
|
4
|
+
/**
|
|
5
|
+
* Debounces a value by delaying updates until after a specified delay.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* const [search, setSearch] = useState('');
|
|
10
|
+
* const debouncedSearch = useDebounce(search, 300);
|
|
11
|
+
*
|
|
12
|
+
* useEffect(() => {
|
|
13
|
+
* // Only fires 300ms after user stops typing
|
|
14
|
+
* fetchResults(debouncedSearch);
|
|
15
|
+
* }, [debouncedSearch]);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
function useDebounce(value, delay) {
|
|
19
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const timer = setTimeout(() => {
|
|
22
|
+
setDebouncedValue(value);
|
|
23
|
+
}, delay);
|
|
24
|
+
return () => {
|
|
25
|
+
clearTimeout(timer);
|
|
26
|
+
};
|
|
27
|
+
}, [value, delay]);
|
|
28
|
+
return debouncedValue;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/hooks/use-local-storage.ts
|
|
33
|
+
/**
|
|
34
|
+
* Syncs state with localStorage, with SSR support.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```tsx
|
|
38
|
+
* const [theme, setTheme] = useLocalStorage('theme', 'dark');
|
|
39
|
+
*
|
|
40
|
+
* // Value persists across page reloads
|
|
41
|
+
* setTheme('light');
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
function useLocalStorage(key, initialValue) {
|
|
45
|
+
const readValue = useCallback(() => {
|
|
46
|
+
if (typeof window === "undefined") return initialValue;
|
|
47
|
+
try {
|
|
48
|
+
const item = window.localStorage.getItem(key);
|
|
49
|
+
return item ? JSON.parse(item) : initialValue;
|
|
50
|
+
} catch (_error) {
|
|
51
|
+
return initialValue;
|
|
52
|
+
}
|
|
53
|
+
}, [initialValue, key]);
|
|
54
|
+
const [storedValue, setStoredValue] = useState(readValue);
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
setStoredValue(readValue());
|
|
57
|
+
}, [readValue]);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
const handleStorageChange = (event) => {
|
|
60
|
+
if (event.key === key && event.newValue !== null) try {
|
|
61
|
+
setStoredValue(JSON.parse(event.newValue));
|
|
62
|
+
} catch {
|
|
63
|
+
setStoredValue(event.newValue);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
window.addEventListener("storage", handleStorageChange);
|
|
67
|
+
return () => window.removeEventListener("storage", handleStorageChange);
|
|
68
|
+
}, [key]);
|
|
69
|
+
const setValue = useCallback((value) => {
|
|
70
|
+
try {
|
|
71
|
+
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
72
|
+
setStoredValue(valueToStore);
|
|
73
|
+
if (typeof window !== "undefined") {
|
|
74
|
+
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
75
|
+
window.dispatchEvent(new StorageEvent("storage", {
|
|
76
|
+
key,
|
|
77
|
+
newValue: JSON.stringify(valueToStore)
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
} catch (_error) {}
|
|
81
|
+
}, [key, storedValue]);
|
|
82
|
+
const removeValue = useCallback(() => {
|
|
83
|
+
try {
|
|
84
|
+
if (typeof window !== "undefined") {
|
|
85
|
+
window.localStorage.removeItem(key);
|
|
86
|
+
setStoredValue(initialValue);
|
|
87
|
+
}
|
|
88
|
+
} catch (_error) {}
|
|
89
|
+
}, [key, initialValue]);
|
|
90
|
+
return [
|
|
91
|
+
storedValue,
|
|
92
|
+
setValue,
|
|
93
|
+
removeValue
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/hooks/use-websocket.ts
|
|
99
|
+
/**
|
|
100
|
+
* Hook for managing WebSocket connections with auto-reconnect.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```tsx
|
|
104
|
+
* const { status, lastMessage, send } = useWebSocket<LogEntry>(
|
|
105
|
+
* 'ws://localhost:3000/ws',
|
|
106
|
+
* {
|
|
107
|
+
* onMessage: (event) => console.log('Received:', event.data),
|
|
108
|
+
* }
|
|
109
|
+
* );
|
|
110
|
+
*
|
|
111
|
+
* // Send a message
|
|
112
|
+
* send({ type: 'subscribe', channel: 'logs' });
|
|
113
|
+
*
|
|
114
|
+
* // Check connection status
|
|
115
|
+
* if (status === 'connected') {
|
|
116
|
+
* // ...
|
|
117
|
+
* }
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
function useWebSocket(url, options = {}) {
|
|
121
|
+
const { reconnect = true, reconnectDelay = 3e3, maxReconnectAttempts = 5, onOpen, onClose, onError, onMessage } = options;
|
|
122
|
+
const [status, setStatus] = useState("disconnected");
|
|
123
|
+
const [lastMessage, setLastMessage] = useState(null);
|
|
124
|
+
const wsRef = useRef(null);
|
|
125
|
+
const reconnectAttemptsRef = useRef(0);
|
|
126
|
+
const reconnectTimeoutRef = useRef(null);
|
|
127
|
+
const connect = useCallback(() => {
|
|
128
|
+
if (!url || wsRef.current?.readyState === WebSocket.OPEN) return;
|
|
129
|
+
if (wsRef.current) wsRef.current.close();
|
|
130
|
+
setStatus("connecting");
|
|
131
|
+
const ws = new WebSocket(url);
|
|
132
|
+
ws.onopen = (event) => {
|
|
133
|
+
setStatus("connected");
|
|
134
|
+
reconnectAttemptsRef.current = 0;
|
|
135
|
+
onOpen?.(event);
|
|
136
|
+
};
|
|
137
|
+
ws.onclose = (event) => {
|
|
138
|
+
setStatus("disconnected");
|
|
139
|
+
onClose?.(event);
|
|
140
|
+
if (reconnect && !event.wasClean && reconnectAttemptsRef.current < maxReconnectAttempts) {
|
|
141
|
+
reconnectAttemptsRef.current += 1;
|
|
142
|
+
reconnectTimeoutRef.current = setTimeout(() => {
|
|
143
|
+
connect();
|
|
144
|
+
}, reconnectDelay);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
ws.onerror = (event) => {
|
|
148
|
+
onError?.(event);
|
|
149
|
+
};
|
|
150
|
+
ws.onmessage = (event) => {
|
|
151
|
+
try {
|
|
152
|
+
const data = JSON.parse(event.data);
|
|
153
|
+
setLastMessage(data);
|
|
154
|
+
} catch {
|
|
155
|
+
setLastMessage(event.data);
|
|
156
|
+
}
|
|
157
|
+
onMessage?.(event);
|
|
158
|
+
};
|
|
159
|
+
wsRef.current = ws;
|
|
160
|
+
}, [
|
|
161
|
+
url,
|
|
162
|
+
reconnect,
|
|
163
|
+
reconnectDelay,
|
|
164
|
+
maxReconnectAttempts,
|
|
165
|
+
onOpen,
|
|
166
|
+
onClose,
|
|
167
|
+
onError,
|
|
168
|
+
onMessage
|
|
169
|
+
]);
|
|
170
|
+
const disconnect = useCallback(() => {
|
|
171
|
+
if (reconnectTimeoutRef.current) {
|
|
172
|
+
clearTimeout(reconnectTimeoutRef.current);
|
|
173
|
+
reconnectTimeoutRef.current = null;
|
|
174
|
+
}
|
|
175
|
+
if (wsRef.current) {
|
|
176
|
+
wsRef.current.close(1e3, "Manual disconnect");
|
|
177
|
+
wsRef.current = null;
|
|
178
|
+
}
|
|
179
|
+
reconnectAttemptsRef.current = maxReconnectAttempts;
|
|
180
|
+
setStatus("disconnected");
|
|
181
|
+
}, [maxReconnectAttempts]);
|
|
182
|
+
const send = useCallback((data) => {
|
|
183
|
+
if (wsRef.current?.readyState === WebSocket.OPEN) {
|
|
184
|
+
const message = typeof data === "string" ? data : JSON.stringify(data);
|
|
185
|
+
wsRef.current.send(message);
|
|
186
|
+
}
|
|
187
|
+
}, []);
|
|
188
|
+
useEffect(() => {
|
|
189
|
+
if (url) connect();
|
|
190
|
+
return () => {
|
|
191
|
+
if (reconnectTimeoutRef.current) clearTimeout(reconnectTimeoutRef.current);
|
|
192
|
+
if (wsRef.current) wsRef.current.close(1e3, "Component unmount");
|
|
193
|
+
};
|
|
194
|
+
}, [url, connect]);
|
|
195
|
+
return {
|
|
196
|
+
status,
|
|
197
|
+
lastMessage,
|
|
198
|
+
send,
|
|
199
|
+
connect,
|
|
200
|
+
disconnect
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
//#endregion
|
|
205
|
+
export { useDebounce, useLocalStorage, useWebSocket };
|
|
206
|
+
//# sourceMappingURL=hooks-DBc-Cw9X.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks-DBc-Cw9X.mjs","names":["value: T","delay: number","key: string","initialValue: T","event: StorageEvent","value: T | ((prev: T) => T)","url: string | null","options: UseWebSocketOptions","data: string | object"],"sources":["../src/hooks/use-debounce.ts","../src/hooks/use-local-storage.ts","../src/hooks/use-websocket.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\n/**\n * Debounces a value by delaying updates until after a specified delay.\n *\n * @example\n * ```tsx\n * const [search, setSearch] = useState('');\n * const debouncedSearch = useDebounce(search, 300);\n *\n * useEffect(() => {\n * // Only fires 300ms after user stops typing\n * fetchResults(debouncedSearch);\n * }, [debouncedSearch]);\n * ```\n */\nexport function useDebounce<T>(value: T, delay: number): T {\n\tconst [debouncedValue, setDebouncedValue] = useState<T>(value);\n\n\tuseEffect(() => {\n\t\tconst timer = setTimeout(() => {\n\t\t\tsetDebouncedValue(value);\n\t\t}, delay);\n\n\t\treturn () => {\n\t\t\tclearTimeout(timer);\n\t\t};\n\t}, [value, delay]);\n\n\treturn debouncedValue;\n}\n\nexport default useDebounce;\n","import { useCallback, useEffect, useState } from 'react';\n\n/**\n * Syncs state with localStorage, with SSR support.\n *\n * @example\n * ```tsx\n * const [theme, setTheme] = useLocalStorage('theme', 'dark');\n *\n * // Value persists across page reloads\n * setTheme('light');\n * ```\n */\nexport function useLocalStorage<T>(\n\tkey: string,\n\tinitialValue: T,\n): [T, (value: T | ((prev: T) => T)) => void, () => void] {\n\t// Get initial value from localStorage or use provided initial value\n\tconst readValue = useCallback((): T => {\n\t\tif (typeof window === 'undefined') {\n\t\t\treturn initialValue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst item = window.localStorage.getItem(key);\n\t\t\treturn item ? (JSON.parse(item) as T) : initialValue;\n\t\t} catch (_error) {\n\t\t\treturn initialValue;\n\t\t}\n\t}, [initialValue, key]);\n\n\tconst [storedValue, setStoredValue] = useState<T>(readValue);\n\n\t// Update state when key changes\n\tuseEffect(() => {\n\t\tsetStoredValue(readValue());\n\t}, [readValue]);\n\n\t// Listen for storage changes from other tabs/windows\n\tuseEffect(() => {\n\t\tconst handleStorageChange = (event: StorageEvent) => {\n\t\t\tif (event.key === key && event.newValue !== null) {\n\t\t\t\ttry {\n\t\t\t\t\tsetStoredValue(JSON.parse(event.newValue) as T);\n\t\t\t\t} catch {\n\t\t\t\t\tsetStoredValue(event.newValue as unknown as T);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\twindow.addEventListener('storage', handleStorageChange);\n\t\treturn () => window.removeEventListener('storage', handleStorageChange);\n\t}, [key]);\n\n\t// Setter that also updates localStorage\n\tconst setValue = useCallback(\n\t\t(value: T | ((prev: T) => T)) => {\n\t\t\ttry {\n\t\t\t\t// Allow value to be a function for functional updates\n\t\t\t\tconst valueToStore =\n\t\t\t\t\tvalue instanceof Function ? value(storedValue) : value;\n\n\t\t\t\tsetStoredValue(valueToStore);\n\n\t\t\t\tif (typeof window !== 'undefined') {\n\t\t\t\t\twindow.localStorage.setItem(key, JSON.stringify(valueToStore));\n\n\t\t\t\t\t// Dispatch event for other components using the same key\n\t\t\t\t\twindow.dispatchEvent(\n\t\t\t\t\t\tnew StorageEvent('storage', {\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t\tnewValue: JSON.stringify(valueToStore),\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch (_error) {}\n\t\t},\n\t\t[key, storedValue],\n\t);\n\n\t// Remove value from localStorage\n\tconst removeValue = useCallback(() => {\n\t\ttry {\n\t\t\tif (typeof window !== 'undefined') {\n\t\t\t\twindow.localStorage.removeItem(key);\n\t\t\t\tsetStoredValue(initialValue);\n\t\t\t}\n\t\t} catch (_error) {}\n\t}, [key, initialValue]);\n\n\treturn [storedValue, setValue, removeValue];\n}\n\nexport default useLocalStorage;\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport type WebSocketStatus = 'connecting' | 'connected' | 'disconnected';\n\nexport interface UseWebSocketOptions {\n\t/**\n\t * Automatically reconnect on disconnect.\n\t * @default true\n\t */\n\treconnect?: boolean;\n\t/**\n\t * Reconnection delay in milliseconds.\n\t * @default 3000\n\t */\n\treconnectDelay?: number;\n\t/**\n\t * Maximum reconnection attempts.\n\t * @default 5\n\t */\n\tmaxReconnectAttempts?: number;\n\t/**\n\t * Callback when connection opens.\n\t */\n\tonOpen?: (event: Event) => void;\n\t/**\n\t * Callback when connection closes.\n\t */\n\tonClose?: (event: CloseEvent) => void;\n\t/**\n\t * Callback when an error occurs.\n\t */\n\tonError?: (event: Event) => void;\n\t/**\n\t * Callback when a message is received.\n\t */\n\tonMessage?: (event: MessageEvent) => void;\n}\n\nexport interface UseWebSocketReturn<T = unknown> {\n\t/**\n\t * Current connection status.\n\t */\n\tstatus: WebSocketStatus;\n\t/**\n\t * Last received message (parsed as JSON if possible).\n\t */\n\tlastMessage: T | null;\n\t/**\n\t * Send a message through the WebSocket.\n\t */\n\tsend: (data: string | object) => void;\n\t/**\n\t * Manually connect to the WebSocket.\n\t */\n\tconnect: () => void;\n\t/**\n\t * Manually disconnect from the WebSocket.\n\t */\n\tdisconnect: () => void;\n}\n\n/**\n * Hook for managing WebSocket connections with auto-reconnect.\n *\n * @example\n * ```tsx\n * const { status, lastMessage, send } = useWebSocket<LogEntry>(\n * 'ws://localhost:3000/ws',\n * {\n * onMessage: (event) => console.log('Received:', event.data),\n * }\n * );\n *\n * // Send a message\n * send({ type: 'subscribe', channel: 'logs' });\n *\n * // Check connection status\n * if (status === 'connected') {\n * // ...\n * }\n * ```\n */\nexport function useWebSocket<T = unknown>(\n\turl: string | null,\n\toptions: UseWebSocketOptions = {},\n): UseWebSocketReturn<T> {\n\tconst {\n\t\treconnect = true,\n\t\treconnectDelay = 3000,\n\t\tmaxReconnectAttempts = 5,\n\t\tonOpen,\n\t\tonClose,\n\t\tonError,\n\t\tonMessage,\n\t} = options;\n\n\tconst [status, setStatus] = useState<WebSocketStatus>('disconnected');\n\tconst [lastMessage, setLastMessage] = useState<T | null>(null);\n\n\tconst wsRef = useRef<WebSocket | null>(null);\n\tconst reconnectAttemptsRef = useRef(0);\n\tconst reconnectTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(\n\t\tnull,\n\t);\n\n\tconst connect = useCallback(() => {\n\t\tif (!url || wsRef.current?.readyState === WebSocket.OPEN) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Clean up existing connection\n\t\tif (wsRef.current) {\n\t\t\twsRef.current.close();\n\t\t}\n\n\t\tsetStatus('connecting');\n\n\t\tconst ws = new WebSocket(url);\n\n\t\tws.onopen = (event) => {\n\t\t\tsetStatus('connected');\n\t\t\treconnectAttemptsRef.current = 0;\n\t\t\tonOpen?.(event);\n\t\t};\n\n\t\tws.onclose = (event) => {\n\t\t\tsetStatus('disconnected');\n\t\t\tonClose?.(event);\n\n\t\t\t// Attempt reconnection if enabled\n\t\t\tif (\n\t\t\t\treconnect &&\n\t\t\t\t!event.wasClean &&\n\t\t\t\treconnectAttemptsRef.current < maxReconnectAttempts\n\t\t\t) {\n\t\t\t\treconnectAttemptsRef.current += 1;\n\t\t\t\treconnectTimeoutRef.current = setTimeout(() => {\n\t\t\t\t\tconnect();\n\t\t\t\t}, reconnectDelay);\n\t\t\t}\n\t\t};\n\n\t\tws.onerror = (event) => {\n\t\t\tonError?.(event);\n\t\t};\n\n\t\tws.onmessage = (event) => {\n\t\t\ttry {\n\t\t\t\tconst data = JSON.parse(event.data) as T;\n\t\t\t\tsetLastMessage(data);\n\t\t\t} catch {\n\t\t\t\tsetLastMessage(event.data as unknown as T);\n\t\t\t}\n\t\t\tonMessage?.(event);\n\t\t};\n\n\t\twsRef.current = ws;\n\t}, [\n\t\turl,\n\t\treconnect,\n\t\treconnectDelay,\n\t\tmaxReconnectAttempts,\n\t\tonOpen,\n\t\tonClose,\n\t\tonError,\n\t\tonMessage,\n\t]);\n\n\tconst disconnect = useCallback(() => {\n\t\tif (reconnectTimeoutRef.current) {\n\t\t\tclearTimeout(reconnectTimeoutRef.current);\n\t\t\treconnectTimeoutRef.current = null;\n\t\t}\n\n\t\tif (wsRef.current) {\n\t\t\twsRef.current.close(1000, 'Manual disconnect');\n\t\t\twsRef.current = null;\n\t\t}\n\n\t\treconnectAttemptsRef.current = maxReconnectAttempts; // Prevent auto-reconnect\n\t\tsetStatus('disconnected');\n\t}, [maxReconnectAttempts]);\n\n\tconst send = useCallback((data: string | object) => {\n\t\tif (wsRef.current?.readyState === WebSocket.OPEN) {\n\t\t\tconst message = typeof data === 'string' ? data : JSON.stringify(data);\n\t\t\twsRef.current.send(message);\n\t\t} else {\n\t\t}\n\t}, []);\n\n\t// Connect on mount if URL is provided\n\tuseEffect(() => {\n\t\tif (url) {\n\t\t\tconnect();\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (reconnectTimeoutRef.current) {\n\t\t\t\tclearTimeout(reconnectTimeoutRef.current);\n\t\t\t}\n\t\t\tif (wsRef.current) {\n\t\t\t\twsRef.current.close(1000, 'Component unmount');\n\t\t\t}\n\t\t};\n\t}, [url, connect]);\n\n\treturn {\n\t\tstatus,\n\t\tlastMessage,\n\t\tsend,\n\t\tconnect,\n\t\tdisconnect,\n\t};\n}\n\nexport default useWebSocket;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
const react = __toESM(require("react"));
|
|
25
|
+
|
|
26
|
+
//#region src/hooks/use-debounce.ts
|
|
27
|
+
/**
|
|
28
|
+
* Debounces a value by delaying updates until after a specified delay.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* const [search, setSearch] = useState('');
|
|
33
|
+
* const debouncedSearch = useDebounce(search, 300);
|
|
34
|
+
*
|
|
35
|
+
* useEffect(() => {
|
|
36
|
+
* // Only fires 300ms after user stops typing
|
|
37
|
+
* fetchResults(debouncedSearch);
|
|
38
|
+
* }, [debouncedSearch]);
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
function useDebounce(value, delay) {
|
|
42
|
+
const [debouncedValue, setDebouncedValue] = (0, react.useState)(value);
|
|
43
|
+
(0, react.useEffect)(() => {
|
|
44
|
+
const timer = setTimeout(() => {
|
|
45
|
+
setDebouncedValue(value);
|
|
46
|
+
}, delay);
|
|
47
|
+
return () => {
|
|
48
|
+
clearTimeout(timer);
|
|
49
|
+
};
|
|
50
|
+
}, [value, delay]);
|
|
51
|
+
return debouncedValue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/hooks/use-local-storage.ts
|
|
56
|
+
/**
|
|
57
|
+
* Syncs state with localStorage, with SSR support.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```tsx
|
|
61
|
+
* const [theme, setTheme] = useLocalStorage('theme', 'dark');
|
|
62
|
+
*
|
|
63
|
+
* // Value persists across page reloads
|
|
64
|
+
* setTheme('light');
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
function useLocalStorage(key, initialValue) {
|
|
68
|
+
const readValue = (0, react.useCallback)(() => {
|
|
69
|
+
if (typeof window === "undefined") return initialValue;
|
|
70
|
+
try {
|
|
71
|
+
const item = window.localStorage.getItem(key);
|
|
72
|
+
return item ? JSON.parse(item) : initialValue;
|
|
73
|
+
} catch (_error) {
|
|
74
|
+
return initialValue;
|
|
75
|
+
}
|
|
76
|
+
}, [initialValue, key]);
|
|
77
|
+
const [storedValue, setStoredValue] = (0, react.useState)(readValue);
|
|
78
|
+
(0, react.useEffect)(() => {
|
|
79
|
+
setStoredValue(readValue());
|
|
80
|
+
}, [readValue]);
|
|
81
|
+
(0, react.useEffect)(() => {
|
|
82
|
+
const handleStorageChange = (event) => {
|
|
83
|
+
if (event.key === key && event.newValue !== null) try {
|
|
84
|
+
setStoredValue(JSON.parse(event.newValue));
|
|
85
|
+
} catch {
|
|
86
|
+
setStoredValue(event.newValue);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
window.addEventListener("storage", handleStorageChange);
|
|
90
|
+
return () => window.removeEventListener("storage", handleStorageChange);
|
|
91
|
+
}, [key]);
|
|
92
|
+
const setValue = (0, react.useCallback)((value) => {
|
|
93
|
+
try {
|
|
94
|
+
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
95
|
+
setStoredValue(valueToStore);
|
|
96
|
+
if (typeof window !== "undefined") {
|
|
97
|
+
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
98
|
+
window.dispatchEvent(new StorageEvent("storage", {
|
|
99
|
+
key,
|
|
100
|
+
newValue: JSON.stringify(valueToStore)
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
} catch (_error) {}
|
|
104
|
+
}, [key, storedValue]);
|
|
105
|
+
const removeValue = (0, react.useCallback)(() => {
|
|
106
|
+
try {
|
|
107
|
+
if (typeof window !== "undefined") {
|
|
108
|
+
window.localStorage.removeItem(key);
|
|
109
|
+
setStoredValue(initialValue);
|
|
110
|
+
}
|
|
111
|
+
} catch (_error) {}
|
|
112
|
+
}, [key, initialValue]);
|
|
113
|
+
return [
|
|
114
|
+
storedValue,
|
|
115
|
+
setValue,
|
|
116
|
+
removeValue
|
|
117
|
+
];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/hooks/use-websocket.ts
|
|
122
|
+
/**
|
|
123
|
+
* Hook for managing WebSocket connections with auto-reconnect.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```tsx
|
|
127
|
+
* const { status, lastMessage, send } = useWebSocket<LogEntry>(
|
|
128
|
+
* 'ws://localhost:3000/ws',
|
|
129
|
+
* {
|
|
130
|
+
* onMessage: (event) => console.log('Received:', event.data),
|
|
131
|
+
* }
|
|
132
|
+
* );
|
|
133
|
+
*
|
|
134
|
+
* // Send a message
|
|
135
|
+
* send({ type: 'subscribe', channel: 'logs' });
|
|
136
|
+
*
|
|
137
|
+
* // Check connection status
|
|
138
|
+
* if (status === 'connected') {
|
|
139
|
+
* // ...
|
|
140
|
+
* }
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
function useWebSocket(url, options = {}) {
|
|
144
|
+
const { reconnect = true, reconnectDelay = 3e3, maxReconnectAttempts = 5, onOpen, onClose, onError, onMessage } = options;
|
|
145
|
+
const [status, setStatus] = (0, react.useState)("disconnected");
|
|
146
|
+
const [lastMessage, setLastMessage] = (0, react.useState)(null);
|
|
147
|
+
const wsRef = (0, react.useRef)(null);
|
|
148
|
+
const reconnectAttemptsRef = (0, react.useRef)(0);
|
|
149
|
+
const reconnectTimeoutRef = (0, react.useRef)(null);
|
|
150
|
+
const connect = (0, react.useCallback)(() => {
|
|
151
|
+
if (!url || wsRef.current?.readyState === WebSocket.OPEN) return;
|
|
152
|
+
if (wsRef.current) wsRef.current.close();
|
|
153
|
+
setStatus("connecting");
|
|
154
|
+
const ws = new WebSocket(url);
|
|
155
|
+
ws.onopen = (event) => {
|
|
156
|
+
setStatus("connected");
|
|
157
|
+
reconnectAttemptsRef.current = 0;
|
|
158
|
+
onOpen?.(event);
|
|
159
|
+
};
|
|
160
|
+
ws.onclose = (event) => {
|
|
161
|
+
setStatus("disconnected");
|
|
162
|
+
onClose?.(event);
|
|
163
|
+
if (reconnect && !event.wasClean && reconnectAttemptsRef.current < maxReconnectAttempts) {
|
|
164
|
+
reconnectAttemptsRef.current += 1;
|
|
165
|
+
reconnectTimeoutRef.current = setTimeout(() => {
|
|
166
|
+
connect();
|
|
167
|
+
}, reconnectDelay);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
ws.onerror = (event) => {
|
|
171
|
+
onError?.(event);
|
|
172
|
+
};
|
|
173
|
+
ws.onmessage = (event) => {
|
|
174
|
+
try {
|
|
175
|
+
const data = JSON.parse(event.data);
|
|
176
|
+
setLastMessage(data);
|
|
177
|
+
} catch {
|
|
178
|
+
setLastMessage(event.data);
|
|
179
|
+
}
|
|
180
|
+
onMessage?.(event);
|
|
181
|
+
};
|
|
182
|
+
wsRef.current = ws;
|
|
183
|
+
}, [
|
|
184
|
+
url,
|
|
185
|
+
reconnect,
|
|
186
|
+
reconnectDelay,
|
|
187
|
+
maxReconnectAttempts,
|
|
188
|
+
onOpen,
|
|
189
|
+
onClose,
|
|
190
|
+
onError,
|
|
191
|
+
onMessage
|
|
192
|
+
]);
|
|
193
|
+
const disconnect = (0, react.useCallback)(() => {
|
|
194
|
+
if (reconnectTimeoutRef.current) {
|
|
195
|
+
clearTimeout(reconnectTimeoutRef.current);
|
|
196
|
+
reconnectTimeoutRef.current = null;
|
|
197
|
+
}
|
|
198
|
+
if (wsRef.current) {
|
|
199
|
+
wsRef.current.close(1e3, "Manual disconnect");
|
|
200
|
+
wsRef.current = null;
|
|
201
|
+
}
|
|
202
|
+
reconnectAttemptsRef.current = maxReconnectAttempts;
|
|
203
|
+
setStatus("disconnected");
|
|
204
|
+
}, [maxReconnectAttempts]);
|
|
205
|
+
const send = (0, react.useCallback)((data) => {
|
|
206
|
+
if (wsRef.current?.readyState === WebSocket.OPEN) {
|
|
207
|
+
const message = typeof data === "string" ? data : JSON.stringify(data);
|
|
208
|
+
wsRef.current.send(message);
|
|
209
|
+
}
|
|
210
|
+
}, []);
|
|
211
|
+
(0, react.useEffect)(() => {
|
|
212
|
+
if (url) connect();
|
|
213
|
+
return () => {
|
|
214
|
+
if (reconnectTimeoutRef.current) clearTimeout(reconnectTimeoutRef.current);
|
|
215
|
+
if (wsRef.current) wsRef.current.close(1e3, "Component unmount");
|
|
216
|
+
};
|
|
217
|
+
}, [url, connect]);
|
|
218
|
+
return {
|
|
219
|
+
status,
|
|
220
|
+
lastMessage,
|
|
221
|
+
send,
|
|
222
|
+
connect,
|
|
223
|
+
disconnect
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
//#endregion
|
|
228
|
+
Object.defineProperty(exports, '__toESM', {
|
|
229
|
+
enumerable: true,
|
|
230
|
+
get: function () {
|
|
231
|
+
return __toESM;
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
Object.defineProperty(exports, 'useDebounce', {
|
|
235
|
+
enumerable: true,
|
|
236
|
+
get: function () {
|
|
237
|
+
return useDebounce;
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
Object.defineProperty(exports, 'useLocalStorage', {
|
|
241
|
+
enumerable: true,
|
|
242
|
+
get: function () {
|
|
243
|
+
return useLocalStorage;
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
Object.defineProperty(exports, 'useWebSocket', {
|
|
247
|
+
enumerable: true,
|
|
248
|
+
get: function () {
|
|
249
|
+
return useWebSocket;
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
//# sourceMappingURL=hooks-DuxmSO-h.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks-DuxmSO-h.cjs","names":["value: T","delay: number","key: string","initialValue: T","event: StorageEvent","value: T | ((prev: T) => T)","url: string | null","options: UseWebSocketOptions","data: string | object"],"sources":["../src/hooks/use-debounce.ts","../src/hooks/use-local-storage.ts","../src/hooks/use-websocket.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\n/**\n * Debounces a value by delaying updates until after a specified delay.\n *\n * @example\n * ```tsx\n * const [search, setSearch] = useState('');\n * const debouncedSearch = useDebounce(search, 300);\n *\n * useEffect(() => {\n * // Only fires 300ms after user stops typing\n * fetchResults(debouncedSearch);\n * }, [debouncedSearch]);\n * ```\n */\nexport function useDebounce<T>(value: T, delay: number): T {\n\tconst [debouncedValue, setDebouncedValue] = useState<T>(value);\n\n\tuseEffect(() => {\n\t\tconst timer = setTimeout(() => {\n\t\t\tsetDebouncedValue(value);\n\t\t}, delay);\n\n\t\treturn () => {\n\t\t\tclearTimeout(timer);\n\t\t};\n\t}, [value, delay]);\n\n\treturn debouncedValue;\n}\n\nexport default useDebounce;\n","import { useCallback, useEffect, useState } from 'react';\n\n/**\n * Syncs state with localStorage, with SSR support.\n *\n * @example\n * ```tsx\n * const [theme, setTheme] = useLocalStorage('theme', 'dark');\n *\n * // Value persists across page reloads\n * setTheme('light');\n * ```\n */\nexport function useLocalStorage<T>(\n\tkey: string,\n\tinitialValue: T,\n): [T, (value: T | ((prev: T) => T)) => void, () => void] {\n\t// Get initial value from localStorage or use provided initial value\n\tconst readValue = useCallback((): T => {\n\t\tif (typeof window === 'undefined') {\n\t\t\treturn initialValue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst item = window.localStorage.getItem(key);\n\t\t\treturn item ? (JSON.parse(item) as T) : initialValue;\n\t\t} catch (_error) {\n\t\t\treturn initialValue;\n\t\t}\n\t}, [initialValue, key]);\n\n\tconst [storedValue, setStoredValue] = useState<T>(readValue);\n\n\t// Update state when key changes\n\tuseEffect(() => {\n\t\tsetStoredValue(readValue());\n\t}, [readValue]);\n\n\t// Listen for storage changes from other tabs/windows\n\tuseEffect(() => {\n\t\tconst handleStorageChange = (event: StorageEvent) => {\n\t\t\tif (event.key === key && event.newValue !== null) {\n\t\t\t\ttry {\n\t\t\t\t\tsetStoredValue(JSON.parse(event.newValue) as T);\n\t\t\t\t} catch {\n\t\t\t\t\tsetStoredValue(event.newValue as unknown as T);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\twindow.addEventListener('storage', handleStorageChange);\n\t\treturn () => window.removeEventListener('storage', handleStorageChange);\n\t}, [key]);\n\n\t// Setter that also updates localStorage\n\tconst setValue = useCallback(\n\t\t(value: T | ((prev: T) => T)) => {\n\t\t\ttry {\n\t\t\t\t// Allow value to be a function for functional updates\n\t\t\t\tconst valueToStore =\n\t\t\t\t\tvalue instanceof Function ? value(storedValue) : value;\n\n\t\t\t\tsetStoredValue(valueToStore);\n\n\t\t\t\tif (typeof window !== 'undefined') {\n\t\t\t\t\twindow.localStorage.setItem(key, JSON.stringify(valueToStore));\n\n\t\t\t\t\t// Dispatch event for other components using the same key\n\t\t\t\t\twindow.dispatchEvent(\n\t\t\t\t\t\tnew StorageEvent('storage', {\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t\tnewValue: JSON.stringify(valueToStore),\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch (_error) {}\n\t\t},\n\t\t[key, storedValue],\n\t);\n\n\t// Remove value from localStorage\n\tconst removeValue = useCallback(() => {\n\t\ttry {\n\t\t\tif (typeof window !== 'undefined') {\n\t\t\t\twindow.localStorage.removeItem(key);\n\t\t\t\tsetStoredValue(initialValue);\n\t\t\t}\n\t\t} catch (_error) {}\n\t}, [key, initialValue]);\n\n\treturn [storedValue, setValue, removeValue];\n}\n\nexport default useLocalStorage;\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport type WebSocketStatus = 'connecting' | 'connected' | 'disconnected';\n\nexport interface UseWebSocketOptions {\n\t/**\n\t * Automatically reconnect on disconnect.\n\t * @default true\n\t */\n\treconnect?: boolean;\n\t/**\n\t * Reconnection delay in milliseconds.\n\t * @default 3000\n\t */\n\treconnectDelay?: number;\n\t/**\n\t * Maximum reconnection attempts.\n\t * @default 5\n\t */\n\tmaxReconnectAttempts?: number;\n\t/**\n\t * Callback when connection opens.\n\t */\n\tonOpen?: (event: Event) => void;\n\t/**\n\t * Callback when connection closes.\n\t */\n\tonClose?: (event: CloseEvent) => void;\n\t/**\n\t * Callback when an error occurs.\n\t */\n\tonError?: (event: Event) => void;\n\t/**\n\t * Callback when a message is received.\n\t */\n\tonMessage?: (event: MessageEvent) => void;\n}\n\nexport interface UseWebSocketReturn<T = unknown> {\n\t/**\n\t * Current connection status.\n\t */\n\tstatus: WebSocketStatus;\n\t/**\n\t * Last received message (parsed as JSON if possible).\n\t */\n\tlastMessage: T | null;\n\t/**\n\t * Send a message through the WebSocket.\n\t */\n\tsend: (data: string | object) => void;\n\t/**\n\t * Manually connect to the WebSocket.\n\t */\n\tconnect: () => void;\n\t/**\n\t * Manually disconnect from the WebSocket.\n\t */\n\tdisconnect: () => void;\n}\n\n/**\n * Hook for managing WebSocket connections with auto-reconnect.\n *\n * @example\n * ```tsx\n * const { status, lastMessage, send } = useWebSocket<LogEntry>(\n * 'ws://localhost:3000/ws',\n * {\n * onMessage: (event) => console.log('Received:', event.data),\n * }\n * );\n *\n * // Send a message\n * send({ type: 'subscribe', channel: 'logs' });\n *\n * // Check connection status\n * if (status === 'connected') {\n * // ...\n * }\n * ```\n */\nexport function useWebSocket<T = unknown>(\n\turl: string | null,\n\toptions: UseWebSocketOptions = {},\n): UseWebSocketReturn<T> {\n\tconst {\n\t\treconnect = true,\n\t\treconnectDelay = 3000,\n\t\tmaxReconnectAttempts = 5,\n\t\tonOpen,\n\t\tonClose,\n\t\tonError,\n\t\tonMessage,\n\t} = options;\n\n\tconst [status, setStatus] = useState<WebSocketStatus>('disconnected');\n\tconst [lastMessage, setLastMessage] = useState<T | null>(null);\n\n\tconst wsRef = useRef<WebSocket | null>(null);\n\tconst reconnectAttemptsRef = useRef(0);\n\tconst reconnectTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(\n\t\tnull,\n\t);\n\n\tconst connect = useCallback(() => {\n\t\tif (!url || wsRef.current?.readyState === WebSocket.OPEN) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Clean up existing connection\n\t\tif (wsRef.current) {\n\t\t\twsRef.current.close();\n\t\t}\n\n\t\tsetStatus('connecting');\n\n\t\tconst ws = new WebSocket(url);\n\n\t\tws.onopen = (event) => {\n\t\t\tsetStatus('connected');\n\t\t\treconnectAttemptsRef.current = 0;\n\t\t\tonOpen?.(event);\n\t\t};\n\n\t\tws.onclose = (event) => {\n\t\t\tsetStatus('disconnected');\n\t\t\tonClose?.(event);\n\n\t\t\t// Attempt reconnection if enabled\n\t\t\tif (\n\t\t\t\treconnect &&\n\t\t\t\t!event.wasClean &&\n\t\t\t\treconnectAttemptsRef.current < maxReconnectAttempts\n\t\t\t) {\n\t\t\t\treconnectAttemptsRef.current += 1;\n\t\t\t\treconnectTimeoutRef.current = setTimeout(() => {\n\t\t\t\t\tconnect();\n\t\t\t\t}, reconnectDelay);\n\t\t\t}\n\t\t};\n\n\t\tws.onerror = (event) => {\n\t\t\tonError?.(event);\n\t\t};\n\n\t\tws.onmessage = (event) => {\n\t\t\ttry {\n\t\t\t\tconst data = JSON.parse(event.data) as T;\n\t\t\t\tsetLastMessage(data);\n\t\t\t} catch {\n\t\t\t\tsetLastMessage(event.data as unknown as T);\n\t\t\t}\n\t\t\tonMessage?.(event);\n\t\t};\n\n\t\twsRef.current = ws;\n\t}, [\n\t\turl,\n\t\treconnect,\n\t\treconnectDelay,\n\t\tmaxReconnectAttempts,\n\t\tonOpen,\n\t\tonClose,\n\t\tonError,\n\t\tonMessage,\n\t]);\n\n\tconst disconnect = useCallback(() => {\n\t\tif (reconnectTimeoutRef.current) {\n\t\t\tclearTimeout(reconnectTimeoutRef.current);\n\t\t\treconnectTimeoutRef.current = null;\n\t\t}\n\n\t\tif (wsRef.current) {\n\t\t\twsRef.current.close(1000, 'Manual disconnect');\n\t\t\twsRef.current = null;\n\t\t}\n\n\t\treconnectAttemptsRef.current = maxReconnectAttempts; // Prevent auto-reconnect\n\t\tsetStatus('disconnected');\n\t}, [maxReconnectAttempts]);\n\n\tconst send = useCallback((data: string | object) => {\n\t\tif (wsRef.current?.readyState === WebSocket.OPEN) {\n\t\t\tconst message = typeof data === 'string' ? data : JSON.stringify(data);\n\t\t\twsRef.current.send(message);\n\t\t} else {\n\t\t}\n\t}, []);\n\n\t// Connect on mount if URL is provided\n\tuseEffect(() => {\n\t\tif (url) {\n\t\t\tconnect();\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (reconnectTimeoutRef.current) {\n\t\t\t\tclearTimeout(reconnectTimeoutRef.current);\n\t\t\t}\n\t\t\tif (wsRef.current) {\n\t\t\t\twsRef.current.close(1000, 'Component unmount');\n\t\t\t}\n\t\t};\n\t}, [url, connect]);\n\n\treturn {\n\t\tstatus,\n\t\tlastMessage,\n\t\tsend,\n\t\tconnect,\n\t\tdisconnect,\n\t};\n}\n\nexport default useWebSocket;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
//#region src/hooks/use-debounce.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Debounces a value by delaying updates until after a specified delay.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```tsx
|
|
7
|
+
* const [search, setSearch] = useState('');
|
|
8
|
+
* const debouncedSearch = useDebounce(search, 300);
|
|
9
|
+
*
|
|
10
|
+
* useEffect(() => {
|
|
11
|
+
* // Only fires 300ms after user stops typing
|
|
12
|
+
* fetchResults(debouncedSearch);
|
|
13
|
+
* }, [debouncedSearch]);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
declare function useDebounce<T>(value: T, delay: number): T;
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/hooks/use-local-storage.d.ts
|
|
19
|
+
/**
|
|
20
|
+
* Syncs state with localStorage, with SSR support.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* const [theme, setTheme] = useLocalStorage('theme', 'dark');
|
|
25
|
+
*
|
|
26
|
+
* // Value persists across page reloads
|
|
27
|
+
* setTheme('light');
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
declare function useLocalStorage<T>(key: string, initialValue: T): [T, (value: T | ((prev: T) => T)) => void, () => void];
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/hooks/use-websocket.d.ts
|
|
33
|
+
type WebSocketStatus = 'connecting' | 'connected' | 'disconnected';
|
|
34
|
+
interface UseWebSocketOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Automatically reconnect on disconnect.
|
|
37
|
+
* @default true
|
|
38
|
+
*/
|
|
39
|
+
reconnect?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Reconnection delay in milliseconds.
|
|
42
|
+
* @default 3000
|
|
43
|
+
*/
|
|
44
|
+
reconnectDelay?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Maximum reconnection attempts.
|
|
47
|
+
* @default 5
|
|
48
|
+
*/
|
|
49
|
+
maxReconnectAttempts?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Callback when connection opens.
|
|
52
|
+
*/
|
|
53
|
+
onOpen?: (event: Event) => void;
|
|
54
|
+
/**
|
|
55
|
+
* Callback when connection closes.
|
|
56
|
+
*/
|
|
57
|
+
onClose?: (event: CloseEvent) => void;
|
|
58
|
+
/**
|
|
59
|
+
* Callback when an error occurs.
|
|
60
|
+
*/
|
|
61
|
+
onError?: (event: Event) => void;
|
|
62
|
+
/**
|
|
63
|
+
* Callback when a message is received.
|
|
64
|
+
*/
|
|
65
|
+
onMessage?: (event: MessageEvent) => void;
|
|
66
|
+
}
|
|
67
|
+
interface UseWebSocketReturn<T = unknown> {
|
|
68
|
+
/**
|
|
69
|
+
* Current connection status.
|
|
70
|
+
*/
|
|
71
|
+
status: WebSocketStatus;
|
|
72
|
+
/**
|
|
73
|
+
* Last received message (parsed as JSON if possible).
|
|
74
|
+
*/
|
|
75
|
+
lastMessage: T | null;
|
|
76
|
+
/**
|
|
77
|
+
* Send a message through the WebSocket.
|
|
78
|
+
*/
|
|
79
|
+
send: (data: string | object) => void;
|
|
80
|
+
/**
|
|
81
|
+
* Manually connect to the WebSocket.
|
|
82
|
+
*/
|
|
83
|
+
connect: () => void;
|
|
84
|
+
/**
|
|
85
|
+
* Manually disconnect from the WebSocket.
|
|
86
|
+
*/
|
|
87
|
+
disconnect: () => void;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Hook for managing WebSocket connections with auto-reconnect.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```tsx
|
|
94
|
+
* const { status, lastMessage, send } = useWebSocket<LogEntry>(
|
|
95
|
+
* 'ws://localhost:3000/ws',
|
|
96
|
+
* {
|
|
97
|
+
* onMessage: (event) => console.log('Received:', event.data),
|
|
98
|
+
* }
|
|
99
|
+
* );
|
|
100
|
+
*
|
|
101
|
+
* // Send a message
|
|
102
|
+
* send({ type: 'subscribe', channel: 'logs' });
|
|
103
|
+
*
|
|
104
|
+
* // Check connection status
|
|
105
|
+
* if (status === 'connected') {
|
|
106
|
+
* // ...
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
declare function useWebSocket<T = unknown>(url: string | null, options?: UseWebSocketOptions): UseWebSocketReturn<T>;
|
|
111
|
+
//#endregion
|
|
112
|
+
export { UseWebSocketOptions, UseWebSocketReturn, WebSocketStatus, useDebounce, useLocalStorage, useWebSocket };
|
|
113
|
+
//# sourceMappingURL=index-DmtSyJ1q.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-DmtSyJ1q.d.mts","names":[],"sources":["../src/hooks/use-debounce.ts","../src/hooks/use-local-storage.ts","../src/hooks/use-websocket.ts"],"sourcesContent":[],"mappings":";;AAgBA;;;;AAA0D;;;;ACH1D;;;;;AAG2B,iBDAX,WCAW,CAAA,CAAA,CAAA,CAAA,KAAA,EDAW,CCAX,EAAA,KAAA,EAAA,MAAA,CAAA,EDA8B,CCA9B;;;;ADA3B;;;;AAA0D;;;;ACH1D;;AAEe,iBAFC,eAED,CAAA,CAAA,CAAA,CAAA,GAAA,EAAA,MAAA,EAAA,YAAA,EAAA,CAAA,CAAA,EAAA,CACX,CADW,EAAA,CAAA,KAAA,EACA,CADA,GAAA,CAAA,CAAA,IAAA,EACY,CADZ,EAAA,GACkB,CADlB,CAAA,EAAA,GAAA,IAAA,EAAA,GAAA,GAAA,IAAA,CAAA;;;KCbH,eAAA;AFcI,UEZC,mBAAA,CFYU;EAAA;;;AAA+B;;;;ACH1D;;EAA+B,cAEhB,CAAA,EAAA,MAAA;EAAC;;;;EACkB,oBAAA,CAAA,EAAA,MAAA;;;;ECdtB,MAAA,CAAA,EAAA,CAAA,KAAA,EAqBM,KArBS,EAAA,GAAA,IAAA;EAEV;;;EAmBM,OAIJ,CAAA,EAAA,CAAA,KAAA,EAAA,UAAA,EAAA,GAAA,IAAA;EAAU;;AAQI;EAGhB,OAAA,CAAA,EAAA,CAAA,KAAA,EAPE,KAOgB,EAAA,GAAA,IAAA;EAAA;;;EAQpB,SAAA,CAAA,EAAA,CAAA,KAAA,EAXM,YAWN,EAAA,GAAA,IAAA;AAoCf;AAA4B,UA5CX,kBA4CW,CAAA,IAAA,OAAA,CAAA,CAAA;EAAA;;;EAGP,MAAA,EA3CZ,eA2CY;;;;eAvCP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoCE,wDAEN,sBACP,mBAAmB"}
|