react-hook-toolkit 3.0.2 → 3.0.3

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.
@@ -1,70 +1,25 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- var __generator = (this && this.__generator) || function (thisArg, body) {
11
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
12
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
- function verb(n) { return function (v) { return step([n, v]); }; }
14
- function step(op) {
15
- if (f) throw new TypeError("Generator is already executing.");
16
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
- if (y = 0, t) op = [op[0] & 2, t.value];
19
- switch (op[0]) {
20
- case 0: case 1: t = op; break;
21
- case 4: _.label++; return { value: op[1], done: false };
22
- case 5: _.label++; y = op[1]; op = [0]; continue;
23
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
- default:
25
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
- if (t[2]) _.ops.pop();
30
- _.trys.pop(); continue;
31
- }
32
- op = body.call(thisArg, _);
33
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
- }
36
- };
37
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
38
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
39
- if (ar || !(i in from)) {
40
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
41
- ar[i] = from[i];
42
- }
43
- }
44
- return to.concat(ar || Array.prototype.slice.call(from));
45
- };
46
1
  import { useCallback, useEffect, useMemo, useState } from "react";
47
2
  import { flattenArrayByKey, navigateTo } from "../utils";
48
- export var useBrowser = function () {
3
+ export const useBrowser = () => {
49
4
  var _a, _b;
50
- var _c = useState(new URL(window.location.href)), currentUrl = _c[0], setCurrentUrl = _c[1];
51
- var _d = useState({
5
+ const [currentUrl, setCurrentUrl] = useState(new URL(window.location.href));
6
+ const [historyState, setHistoryState] = useState({
52
7
  canGoBack: ((_a = window.history.state) === null || _a === void 0 ? void 0 : _a.idx) > 0,
53
8
  canGoForward: ((_b = window.history.state) === null || _b === void 0 ? void 0 : _b.idx) < window.history.length - 1,
54
9
  historyLength: window.history.length,
55
- }), historyState = _d[0], setHistoryState = _d[1];
56
- var _e = useState(navigator.onLine), isOnline = _e[0], setIsOnline = _e[1];
57
- var _f = useState(false), isFullscreen = _f[0], setIsFullscreen = _f[1];
58
- var _g = useState({
10
+ });
11
+ const [isOnline, setIsOnline] = useState(navigator.onLine);
12
+ const [isFullscreen, setIsFullscreen] = useState(false);
13
+ const [viewportSize, setViewportSize] = useState({
59
14
  width: window.innerWidth,
60
15
  height: window.innerHeight,
61
- }), viewportSize = _g[0], setViewportSize = _g[1];
62
- var _h = useState({
16
+ });
17
+ const [screenSize, setScreenSize] = useState({
63
18
  width: window.screen.width,
64
19
  height: window.screen.height,
65
- }), screenSize = _h[0], setScreenSize = _h[1];
20
+ });
66
21
  // Update URL and history state when changes occur
67
- var updateState = useCallback(function () {
22
+ const updateState = useCallback(() => {
68
23
  var _a, _b;
69
24
  setCurrentUrl(new URL(window.location.href));
70
25
  setHistoryState({
@@ -74,11 +29,11 @@ export var useBrowser = function () {
74
29
  });
75
30
  }, []);
76
31
  // Event listeners setup
77
- useEffect(function () {
78
- var handlePopState = function () { return updateState(); };
79
- var handleOnline = function () { return setIsOnline(true); };
80
- var handleOffline = function () { return setIsOnline(false); };
81
- var handleResize = function () {
32
+ useEffect(() => {
33
+ const handlePopState = () => updateState();
34
+ const handleOnline = () => setIsOnline(true);
35
+ const handleOffline = () => setIsOnline(false);
36
+ const handleResize = () => {
82
37
  setViewportSize({
83
38
  width: window.innerWidth,
84
39
  height: window.innerHeight,
@@ -88,7 +43,7 @@ export var useBrowser = function () {
88
43
  height: window.screen.height,
89
44
  });
90
45
  };
91
- var handleFullscreenChange = function () {
46
+ const handleFullscreenChange = () => {
92
47
  setIsFullscreen(!!document.fullscreenElement);
93
48
  };
94
49
  window.addEventListener('popstate', handlePopState);
@@ -96,7 +51,7 @@ export var useBrowser = function () {
96
51
  window.addEventListener('offline', handleOffline);
97
52
  window.addEventListener('resize', handleResize);
98
53
  document.addEventListener('fullscreenchange', handleFullscreenChange);
99
- return function () {
54
+ return () => {
100
55
  window.removeEventListener('popstate', handlePopState);
101
56
  window.removeEventListener('online', handleOnline);
102
57
  window.removeEventListener('offline', handleOffline);
@@ -104,7 +59,7 @@ export var useBrowser = function () {
104
59
  document.removeEventListener('fullscreenchange', handleFullscreenChange);
105
60
  };
106
61
  }, [updateState]);
107
- var goBack = useCallback(function () {
62
+ const goBack = useCallback(() => {
108
63
  try {
109
64
  if (historyState.canGoBack) {
110
65
  window.history.back();
@@ -118,7 +73,7 @@ export var useBrowser = function () {
118
73
  window.location.href = '/';
119
74
  }
120
75
  }, [historyState.canGoBack]);
121
- var goForward = useCallback(function () {
76
+ const goForward = useCallback(() => {
122
77
  try {
123
78
  if (historyState.canGoForward) {
124
79
  window.history.forward();
@@ -131,9 +86,7 @@ export var useBrowser = function () {
131
86
  console.error('Error going forward:', error);
132
87
  }
133
88
  }, [historyState.canGoForward]);
134
- var reload = useCallback(function (hardReload, scrollToTop) {
135
- if (hardReload === void 0) { hardReload = false; }
136
- if (scrollToTop === void 0) { scrollToTop = false; }
89
+ const reload = useCallback((hardReload = false, scrollToTop = false) => {
137
90
  try {
138
91
  if (scrollToTop) {
139
92
  window.scrollTo(0, 0);
@@ -149,10 +102,9 @@ export var useBrowser = function () {
149
102
  console.error('Error reloading page:', error);
150
103
  }
151
104
  }, []);
152
- var navigateTo = useCallback(function (url, replace) {
153
- if (replace === void 0) { replace = false; }
105
+ const navigateTo = useCallback((url, replace = false) => {
154
106
  try {
155
- var urlObj = typeof url === 'string' ? new URL(url, window.location.origin) : url;
107
+ const urlObj = typeof url === 'string' ? new URL(url, window.location.origin) : url;
156
108
  if (replace) {
157
109
  window.location.replace(urlObj.href);
158
110
  }
@@ -161,79 +113,50 @@ export var useBrowser = function () {
161
113
  }
162
114
  }
163
115
  catch (error) {
164
- console.error("Error navigating to ".concat(url, ":"), error);
116
+ console.error(`Error navigating to ${url}:`, error);
165
117
  }
166
118
  }, []);
167
- var clearBrowserData = useCallback(function () {
168
- var args_1 = [];
169
- for (var _i = 0; _i < arguments.length; _i++) {
170
- args_1[_i] = arguments[_i];
119
+ const clearBrowserData = useCallback(async (settings = {}) => {
120
+ const { clearCache = false, clearCookies = false, clearLocalStorage = false, clearSessionStorage = false, } = settings;
121
+ try {
122
+ if (clearLocalStorage) {
123
+ localStorage.clear();
124
+ }
125
+ if (clearSessionStorage) {
126
+ sessionStorage.clear();
127
+ }
128
+ if (clearCookies) {
129
+ document.cookie.split(';').forEach((cookie) => {
130
+ const [name] = cookie.split('=');
131
+ document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
132
+ });
133
+ }
134
+ if (clearCache && 'caches' in window) {
135
+ const cacheKeys = await caches.keys();
136
+ await Promise.all(cacheKeys.map((key) => caches.delete(key)));
137
+ }
138
+ }
139
+ catch (error) {
140
+ console.error('Error clearing browser data:', error);
141
+ throw error;
171
142
  }
172
- return __awaiter(void 0, __spreadArray([], args_1, true), void 0, function (settings) {
173
- var _a, clearCache, _b, clearCookies, _c, clearLocalStorage, _d, clearSessionStorage, cacheKeys, error_1;
174
- if (settings === void 0) { settings = {}; }
175
- return __generator(this, function (_e) {
176
- switch (_e.label) {
177
- case 0:
178
- _a = settings.clearCache, clearCache = _a === void 0 ? false : _a, _b = settings.clearCookies, clearCookies = _b === void 0 ? false : _b, _c = settings.clearLocalStorage, clearLocalStorage = _c === void 0 ? false : _c, _d = settings.clearSessionStorage, clearSessionStorage = _d === void 0 ? false : _d;
179
- _e.label = 1;
180
- case 1:
181
- _e.trys.push([1, 5, , 6]);
182
- if (clearLocalStorage) {
183
- localStorage.clear();
184
- }
185
- if (clearSessionStorage) {
186
- sessionStorage.clear();
187
- }
188
- if (clearCookies) {
189
- document.cookie.split(';').forEach(function (cookie) {
190
- var name = cookie.split('=')[0];
191
- document.cookie = "".concat(name, "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/");
192
- });
193
- }
194
- if (!(clearCache && 'caches' in window)) return [3 /*break*/, 4];
195
- return [4 /*yield*/, caches.keys()];
196
- case 2:
197
- cacheKeys = _e.sent();
198
- return [4 /*yield*/, Promise.all(cacheKeys.map(function (key) { return caches.delete(key); }))];
199
- case 3:
200
- _e.sent();
201
- _e.label = 4;
202
- case 4: return [3 /*break*/, 6];
203
- case 5:
204
- error_1 = _e.sent();
205
- console.error('Error clearing browser data:', error_1);
206
- throw error_1;
207
- case 6: return [2 /*return*/];
208
- }
209
- });
210
- });
211
143
  }, []);
212
- var copyCurrentUrl = useCallback(function () { return __awaiter(void 0, void 0, void 0, function () {
213
- var error_2, textArea;
214
- return __generator(this, function (_a) {
215
- switch (_a.label) {
216
- case 0:
217
- _a.trys.push([0, 2, , 3]);
218
- return [4 /*yield*/, navigator.clipboard.writeText(window.location.href)];
219
- case 1:
220
- _a.sent();
221
- return [3 /*break*/, 3];
222
- case 2:
223
- error_2 = _a.sent();
224
- console.error('Error copying URL to clipboard:', error_2);
225
- textArea = document.createElement('textarea');
226
- textArea.value = window.location.href;
227
- document.body.appendChild(textArea);
228
- textArea.select();
229
- document.execCommand('copy');
230
- document.body.removeChild(textArea);
231
- return [3 /*break*/, 3];
232
- case 3: return [2 /*return*/];
233
- }
234
- });
235
- }); }, []);
236
- var openNewTab = useCallback(function (url) {
144
+ const copyCurrentUrl = useCallback(async () => {
145
+ try {
146
+ await navigator.clipboard.writeText(window.location.href);
147
+ }
148
+ catch (error) {
149
+ console.error('Error copying URL to clipboard:', error);
150
+ // Fallback for browsers that don't support clipboard API
151
+ const textArea = document.createElement('textarea');
152
+ textArea.value = window.location.href;
153
+ document.body.appendChild(textArea);
154
+ textArea.select();
155
+ document.execCommand('copy');
156
+ document.body.removeChild(textArea);
157
+ }
158
+ }, []);
159
+ const openNewTab = useCallback((url) => {
237
160
  try {
238
161
  window.open(url || window.location.href, '_blank', 'noopener,noreferrer');
239
162
  }
@@ -241,104 +164,65 @@ export var useBrowser = function () {
241
164
  console.error('Error opening new tab:', error);
242
165
  }
243
166
  }, []);
244
- var getFaviconUrl = useCallback(function (size) {
245
- if (size === void 0) { size = 32; }
246
- var url = new URL(window.location.origin);
167
+ const getFaviconUrl = useCallback((size = 32) => {
168
+ const url = new URL(window.location.origin);
247
169
  url.pathname = '/favicon.ico';
248
170
  url.searchParams.set('size', size.toString());
249
171
  return url.href;
250
172
  }, []);
251
- var getPageTitle = useCallback(function () {
173
+ const getPageTitle = useCallback(() => {
252
174
  return document.title;
253
175
  }, []);
254
- var setPageTitle = useCallback(function (title) {
176
+ const setPageTitle = useCallback((title) => {
255
177
  document.title = title;
256
178
  }, []);
257
- var enableFullscreen = useCallback(function () { return __awaiter(void 0, void 0, void 0, function () {
258
- var error_3;
259
- return __generator(this, function (_a) {
260
- switch (_a.label) {
261
- case 0:
262
- _a.trys.push([0, 7, , 8]);
263
- if (!document.documentElement.requestFullscreen) return [3 /*break*/, 2];
264
- return [4 /*yield*/, document.documentElement.requestFullscreen()];
265
- case 1:
266
- _a.sent();
267
- return [3 /*break*/, 6];
268
- case 2:
269
- if (!document.documentElement.webkitRequestFullscreen) return [3 /*break*/, 4];
270
- return [4 /*yield*/, document.documentElement.webkitRequestFullscreen()];
271
- case 3:
272
- _a.sent();
273
- return [3 /*break*/, 6];
274
- case 4:
275
- if (!document.documentElement.msRequestFullscreen) return [3 /*break*/, 6];
276
- return [4 /*yield*/, document.documentElement.msRequestFullscreen()];
277
- case 5:
278
- _a.sent();
279
- _a.label = 6;
280
- case 6: return [3 /*break*/, 8];
281
- case 7:
282
- error_3 = _a.sent();
283
- console.error('Error enabling fullscreen:', error_3);
284
- throw error_3;
285
- case 8: return [2 /*return*/];
179
+ const enableFullscreen = useCallback(async () => {
180
+ try {
181
+ if (document.documentElement.requestFullscreen) {
182
+ await document.documentElement.requestFullscreen();
286
183
  }
287
- });
288
- }); }, []);
289
- var disableFullscreen = useCallback(function () { return __awaiter(void 0, void 0, void 0, function () {
290
- var error_4;
291
- return __generator(this, function (_a) {
292
- switch (_a.label) {
293
- case 0:
294
- _a.trys.push([0, 7, , 8]);
295
- if (!document.exitFullscreen) return [3 /*break*/, 2];
296
- return [4 /*yield*/, document.exitFullscreen()];
297
- case 1:
298
- _a.sent();
299
- return [3 /*break*/, 6];
300
- case 2:
301
- if (!document.webkitExitFullscreen) return [3 /*break*/, 4];
302
- return [4 /*yield*/, document.webkitExitFullscreen()];
303
- case 3:
304
- _a.sent();
305
- return [3 /*break*/, 6];
306
- case 4:
307
- if (!document.msExitFullscreen) return [3 /*break*/, 6];
308
- return [4 /*yield*/, document.msExitFullscreen()];
309
- case 5:
310
- _a.sent();
311
- _a.label = 6;
312
- case 6: return [3 /*break*/, 8];
313
- case 7:
314
- error_4 = _a.sent();
315
- console.error('Error disabling fullscreen:', error_4);
316
- throw error_4;
317
- case 8: return [2 /*return*/];
184
+ else if (document.documentElement.webkitRequestFullscreen) {
185
+ await document.documentElement.webkitRequestFullscreen();
318
186
  }
319
- });
320
- }); }, []);
321
- var printPage = useCallback(function () {
187
+ else if (document.documentElement.msRequestFullscreen) {
188
+ await document.documentElement.msRequestFullscreen();
189
+ }
190
+ }
191
+ catch (error) {
192
+ console.error('Error enabling fullscreen:', error);
193
+ throw error;
194
+ }
195
+ }, []);
196
+ const disableFullscreen = useCallback(async () => {
197
+ try {
198
+ if (document.exitFullscreen) {
199
+ await document.exitFullscreen();
200
+ }
201
+ else if (document.webkitExitFullscreen) {
202
+ await document.webkitExitFullscreen();
203
+ }
204
+ else if (document.msExitFullscreen) {
205
+ await document.msExitFullscreen();
206
+ }
207
+ }
208
+ catch (error) {
209
+ console.error('Error disabling fullscreen:', error);
210
+ throw error;
211
+ }
212
+ }, []);
213
+ const printPage = useCallback(() => {
322
214
  window.print();
323
215
  }, []);
324
- var getUserAgent = useCallback(function () {
216
+ const getUserAgent = useCallback(() => {
325
217
  return navigator.userAgent;
326
218
  }, []);
327
- var shareContent = useCallback(function (data) { return __awaiter(void 0, void 0, void 0, function () {
328
- return __generator(this, function (_a) {
329
- switch (_a.label) {
330
- case 0:
331
- if (!navigator.share) {
332
- throw new Error('Web Share API not supported');
333
- }
334
- return [4 /*yield*/, navigator.share(data)];
335
- case 1:
336
- _a.sent();
337
- return [2 /*return*/];
338
- }
339
- });
340
- }); }, []);
341
- var closeCurrentTab = useCallback(function () {
219
+ const shareContent = useCallback(async (data) => {
220
+ if (!navigator.share) {
221
+ throw new Error('Web Share API not supported');
222
+ }
223
+ await navigator.share(data);
224
+ }, []);
225
+ const closeCurrentTab = useCallback(() => {
342
226
  try {
343
227
  // Note: This will only work if the tab was opened by JavaScript
344
228
  // Browsers typically prevent closing windows/tabs not opened by script
@@ -351,70 +235,69 @@ export var useBrowser = function () {
351
235
  }
352
236
  }, []);
353
237
  return {
354
- currentUrl: currentUrl,
238
+ currentUrl,
355
239
  currentPath: currentUrl.pathname,
356
240
  currentHash: currentUrl.hash,
357
241
  currentSearchParams: currentUrl.searchParams,
358
- goBack: goBack,
359
- goForward: goForward,
360
- reload: reload,
361
- navigateTo: navigateTo,
362
- clearBrowserData: clearBrowserData,
363
- historyState: historyState,
364
- isOnline: isOnline,
365
- copyCurrentUrl: copyCurrentUrl,
366
- openNewTab: openNewTab,
367
- getFaviconUrl: getFaviconUrl,
368
- getPageTitle: getPageTitle,
369
- setPageTitle: setPageTitle,
242
+ goBack,
243
+ goForward,
244
+ reload,
245
+ navigateTo,
246
+ clearBrowserData,
247
+ historyState,
248
+ isOnline,
249
+ copyCurrentUrl,
250
+ openNewTab,
251
+ getFaviconUrl,
252
+ getPageTitle,
253
+ setPageTitle,
370
254
  isSecureContext: window.isSecureContext,
371
- viewportSize: viewportSize,
372
- screenSize: screenSize,
373
- enableFullscreen: enableFullscreen,
374
- disableFullscreen: disableFullscreen,
375
- isFullscreen: isFullscreen,
376
- printPage: printPage,
377
- getUserAgent: getUserAgent,
378
- shareContent: shareContent,
255
+ viewportSize,
256
+ screenSize,
257
+ enableFullscreen,
258
+ disableFullscreen,
259
+ isFullscreen,
260
+ printPage,
261
+ getUserAgent,
262
+ shareContent,
379
263
  isShareSupported: 'share' in navigator,
380
- closeCurrentTab: closeCurrentTab,
264
+ closeCurrentTab,
381
265
  };
382
266
  };
383
- export function useRouter(initialPath) {
384
- if (initialPath === void 0) { initialPath = window.location.pathname + window.location.search; }
385
- var _a = useState(initialPath), path = _a[0], setPath = _a[1];
386
- var _b = useMemo(function () {
387
- var _a = path.split('?'), basePath = _a[0], queryString = _a[1];
267
+ export function useRouter(initialPath = window.location.pathname + window.location.search) {
268
+ const [path, setPath] = useState(initialPath);
269
+ const { pathname, searchParams } = useMemo(() => {
270
+ const [basePath, queryString] = path.split('?');
388
271
  return {
389
272
  pathname: basePath,
390
273
  searchParams: new URLSearchParams(queryString || ''),
391
274
  };
392
- }, [path]), pathname = _b.pathname, searchParams = _b.searchParams;
393
- var navigate = useCallback(function (newPath) {
394
- var newPathStr = String(newPath);
275
+ }, [path]);
276
+ const navigate = useCallback((newPath) => {
277
+ const newPathStr = String(newPath);
395
278
  setPath(newPathStr);
396
279
  window.history.pushState({}, '', newPathStr);
397
280
  }, []);
398
- useEffect(function () {
399
- var handlePopState = function () {
281
+ useEffect(() => {
282
+ const handlePopState = () => {
400
283
  setPath(window.location.pathname + window.location.search);
401
284
  };
402
285
  window.addEventListener('popstate', handlePopState);
403
- return function () { return window.removeEventListener('popstate', handlePopState); };
286
+ return () => window.removeEventListener('popstate', handlePopState);
404
287
  }, []);
405
288
  return {
406
- pathname: pathname,
407
- searchParams: searchParams,
408
- navigate: navigate,
289
+ pathname,
290
+ searchParams,
291
+ navigate,
409
292
  };
410
293
  }
411
294
  export function useNavigationState() {
412
- var _a = useState({
295
+ const [location, setLocation] = useState({
413
296
  pathname: window.location.pathname,
414
297
  search: window.location.search,
415
298
  state: window.history.state,
416
- }), location = _a[0], setLocation = _a[1];
417
- var navigate = useCallback(function (newPath, options) {
299
+ });
300
+ const navigate = useCallback((newPath, options) => {
418
301
  window.history.pushState((options === null || options === void 0 ? void 0 : options.state) || {}, "", newPath);
419
302
  setLocation({
420
303
  pathname: window.location.pathname,
@@ -423,8 +306,8 @@ export function useNavigationState() {
423
306
  });
424
307
  window.dispatchEvent(new PopStateEvent("popstate"));
425
308
  }, []);
426
- useEffect(function () {
427
- var handlePopState = function () {
309
+ useEffect(() => {
310
+ const handlePopState = () => {
428
311
  setLocation({
429
312
  pathname: window.location.pathname,
430
313
  search: window.location.search,
@@ -432,31 +315,30 @@ export function useNavigationState() {
432
315
  });
433
316
  };
434
317
  window.addEventListener("popstate", handlePopState);
435
- return function () { return window.removeEventListener("popstate", handlePopState); };
318
+ return () => window.removeEventListener("popstate", handlePopState);
436
319
  }, []);
437
- var searchParams = useMemo(function () { return new URLSearchParams(location.search); }, [location.search]);
320
+ const searchParams = useMemo(() => new URLSearchParams(location.search), [location.search]);
438
321
  return {
439
322
  pathname: location.pathname,
440
323
  search: location.search,
441
- searchParams: searchParams,
324
+ searchParams,
442
325
  state: location.state,
443
- navigate: navigate,
326
+ navigate,
444
327
  };
445
328
  }
446
- export function useMenuNavigation(menuData, key) {
447
- if (key === void 0) { key = 'children'; }
448
- var _a = useState([]), menuList = _a[0], setMenuList = _a[1];
449
- useEffect(function () {
329
+ export function useMenuNavigation(menuData, key = 'children') {
330
+ const [menuList, setMenuList] = useState([]);
331
+ useEffect(() => {
450
332
  if (menuData.length > 0) {
451
- var data = flattenArrayByKey(menuData, key);
333
+ const data = flattenArrayByKey(menuData, key);
452
334
  setMenuList(data);
453
335
  }
454
- return function () { return setMenuList([]); };
336
+ return () => setMenuList([]);
455
337
  }, [menuData, key]);
456
- var handleSelect = function (path) {
338
+ const handleSelect = (path) => {
457
339
  if (path) {
458
340
  navigateTo(path);
459
341
  }
460
342
  };
461
- return { menuList: menuList, handleSelect: handleSelect };
343
+ return { menuList, handleSelect };
462
344
  }
@@ -0,0 +1,63 @@
1
+ export type VoiceStatus = 'idle' | 'listening' | 'processing' | 'confirming' | 'error' | 'unsupported';
2
+ export interface VoiceCommand {
3
+ keywords: string[];
4
+ label: string;
5
+ path?: string;
6
+ requiresConfirmation?: boolean;
7
+ action?: () => void;
8
+ }
9
+ export interface HistoryEntry {
10
+ text: string;
11
+ matched: boolean;
12
+ label?: string;
13
+ time: string;
14
+ }
15
+ export type NavigateFn = (path: string) => void;
16
+ export interface UseVoiceOptions {
17
+ commands?: VoiceCommand[];
18
+ language?: string;
19
+ continuous?: boolean;
20
+ interimResults?: boolean;
21
+ autoNavigate?: boolean;
22
+ historySize?: number;
23
+ minConfidence?: number;
24
+ idleTimeoutMs?: number;
25
+ wakeWord?: string;
26
+ shortcut?: string;
27
+ navigate?: NavigateFn;
28
+ onMatch?: (command: VoiceCommand, text: string) => void;
29
+ onNoMatch?: (text: string, closest: VoiceCommand | null) => void;
30
+ onError?: (error: string) => void;
31
+ onStart?: () => void;
32
+ onEnd?: () => void;
33
+ onToast?: (type: 'success' | 'error' | 'warn', message: string) => void;
34
+ }
35
+ export interface UseVoiceResult {
36
+ status: VoiceStatus;
37
+ transcript: string;
38
+ audioLevel: number;
39
+ history: HistoryEntry[];
40
+ lastMatch: VoiceCommand | null;
41
+ pendingConfirm: VoiceCommand | null;
42
+ isSupported: boolean;
43
+ isContinuousSupported: boolean;
44
+ isListening: boolean;
45
+ isProcessing: boolean;
46
+ start: () => Promise<void>;
47
+ stop: () => void;
48
+ toggle: () => Promise<void>;
49
+ reset: () => void;
50
+ executeCommand: (text: string) => void;
51
+ }
52
+ /**
53
+ * Word-boundary match — avoids "home" firing on "homework".
54
+ * Splits both transcript and keyword on whitespace and checks for an
55
+ * exact word (or multi-word phrase) match.
56
+ */
57
+ export declare function matchVoiceCommand(transcript: string, commands: VoiceCommand[]): VoiceCommand | null;
58
+ /**
59
+ * Returns the command whose keywords share the most words with the transcript.
60
+ * Used for "did you mean?" hints on no-match.
61
+ */
62
+ export declare function closestVoiceCommand(transcript: string, commands: VoiceCommand[]): VoiceCommand | null;
63
+ export declare function useVoice(options?: UseVoiceOptions): UseVoiceResult;