sse-hooks 1.3.0 → 2.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/index.cjs DELETED
@@ -1,3108 +0,0 @@
1
- 'use strict';
2
-
3
- const React = require('react');
4
- const debounce = require('lodash.debounce');
5
- require('react-dom');
6
-
7
- function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
8
-
9
- const React__default = /*#__PURE__*/_interopDefaultCompat(React);
10
- const debounce__default = /*#__PURE__*/_interopDefaultCompat(debounce);
11
-
12
- const extend = Object.assign;
13
- const isArray = Array.isArray;
14
- const isMap = (val) => val instanceof Map;
15
- const isFunction = (val) => typeof val === "function";
16
- const isSymbol = (val) => typeof val === "symbol";
17
- const isObject = (val) => val !== null && typeof val === "object";
18
- const isIntegerKey = (key) => typeof key === "string" && key !== "NaN" && key[0] !== "-" && "" + parseInt(key, 10) === key;
19
- const __DEV__ = process.env.NODE_ENV !== "production";
20
-
21
- let activeSub;
22
- let shouldTrack = true;
23
- function getActiveSub() {
24
- return activeSub;
25
- }
26
- function setActiveSub(sub) {
27
- activeSub = sub;
28
- }
29
- function startBatch() {
30
- }
31
- function endBatch() {
32
- }
33
- function batch(sub, isComputed = false) {
34
- }
35
-
36
- var EffectFlags = /* @__PURE__ */ ((EffectFlags2) => {
37
- EffectFlags2[EffectFlags2["ACTIVE"] = 1] = "ACTIVE";
38
- EffectFlags2[EffectFlags2["RUNNING"] = 2] = "RUNNING";
39
- EffectFlags2[EffectFlags2["TRACKING"] = 4] = "TRACKING";
40
- EffectFlags2[EffectFlags2["NOTIFIED"] = 8] = "NOTIFIED";
41
- EffectFlags2[EffectFlags2["DIRTY"] = 16] = "DIRTY";
42
- EffectFlags2[EffectFlags2["ALLOW_RECURSE"] = 32] = "ALLOW_RECURSE";
43
- EffectFlags2[EffectFlags2["PAUSED"] = 64] = "PAUSED";
44
- return EffectFlags2;
45
- })(EffectFlags || {});
46
- var TrackOpTypes = /* @__PURE__ */ ((TrackOpTypes2) => {
47
- TrackOpTypes2["GET"] = "get";
48
- TrackOpTypes2["HAS"] = "has";
49
- TrackOpTypes2["ITERATE"] = "iterate";
50
- return TrackOpTypes2;
51
- })(TrackOpTypes || {});
52
- var TriggerOpTypes = /* @__PURE__ */ ((TriggerOpTypes2) => {
53
- TriggerOpTypes2["SET"] = "set";
54
- TriggerOpTypes2["ADD"] = "add";
55
- TriggerOpTypes2["DELETE"] = "delete";
56
- TriggerOpTypes2["CLEAR"] = "clear";
57
- return TriggerOpTypes2;
58
- })(TriggerOpTypes || {});
59
- const ReactiveFlags = {
60
- IS_REF: "__v_isRef",
61
- IS_READONLY: "__v_isReadonly",
62
- SKIP: "__v_skip"
63
- };
64
-
65
- exports.globalVersion = 0;
66
- class Link {
67
- constructor(sub, dep) {
68
- this.sub = sub;
69
- this.dep = dep;
70
- this.version = dep.version;
71
- }
72
- version;
73
- nextDep;
74
- prevDep;
75
- nextSub;
76
- prevSub;
77
- prevActiveLink;
78
- }
79
- class Dep {
80
- constructor(computed) {
81
- this.computed = computed;
82
- if (__DEV__) {
83
- this.subsHead = void 0;
84
- }
85
- }
86
- version = 0;
87
- activeLink = void 0;
88
- subs = void 0;
89
- subsHead;
90
- map = void 0;
91
- key = void 0;
92
- sc = 0;
93
- track(debugInfo) {
94
- const activeSub = getActiveSub();
95
- if (!activeSub || !shouldTrack || activeSub === this.computed) {
96
- return;
97
- }
98
- let link = this.activeLink;
99
- if (link === void 0 || link.sub !== activeSub) {
100
- link = this.activeLink = new Link(activeSub, this);
101
- if (!activeSub.deps) {
102
- activeSub.deps = activeSub.depsTail = link;
103
- } else {
104
- link.prevDep = activeSub.depsTail;
105
- activeSub.depsTail.nextDep = link;
106
- activeSub.depsTail = link;
107
- }
108
- addSub(link);
109
- } else if (link.version === -1) {
110
- link.version = this.version;
111
- if (link.nextDep) {
112
- const next = link.nextDep;
113
- next.prevDep = link.prevDep;
114
- if (link.prevDep) link.prevDep.nextDep = next;
115
- link.prevDep = activeSub.depsTail;
116
- link.nextDep = void 0;
117
- activeSub.depsTail.nextDep = link;
118
- activeSub.depsTail = link;
119
- if (activeSub.deps === link) activeSub.deps = next;
120
- }
121
- }
122
- if (__DEV__ && activeSub.onTrack) {
123
- activeSub.onTrack(extend({ effect: activeSub }, debugInfo));
124
- }
125
- return link;
126
- }
127
- trigger(debugInfo) {
128
- this.version++;
129
- exports.globalVersion++;
130
- this.notify(debugInfo);
131
- }
132
- notify(debugInfo) {
133
- try {
134
- for (let link = this.subs; link; link = link.prevSub) {
135
- if (link.sub.notify()) {
136
- link.sub.dep.notify();
137
- }
138
- }
139
- } finally {
140
- }
141
- }
142
- }
143
- function addSub(link) {
144
- link.dep.sc++;
145
- if (link.sub.flags & EffectFlags.TRACKING) {
146
- const computed = link.dep.computed;
147
- if (computed && !link.dep.subs) {
148
- computed.flags |= EffectFlags.TRACKING | EffectFlags.DIRTY;
149
- for (let l = computed.deps; l; l = l.nextDep) {
150
- addSub(l);
151
- }
152
- }
153
- const currentTail = link.dep.subs;
154
- if (currentTail !== link) {
155
- link.prevSub = currentTail;
156
- if (currentTail) currentTail.nextSub = link;
157
- }
158
- link.dep.subs = link;
159
- }
160
- }
161
- const targetMap = /* @__PURE__ */ new WeakMap();
162
- function track(target, type, key) {
163
- const activeSub = getActiveSub();
164
- if (activeSub) {
165
- let depsMap = targetMap.get(target);
166
- if (!depsMap) {
167
- targetMap.set(target, depsMap = /* @__PURE__ */ new Map());
168
- }
169
- let dep = depsMap.get(key);
170
- if (!dep) {
171
- depsMap.set(key, dep = new Dep());
172
- dep.map = depsMap;
173
- dep.key = key;
174
- }
175
- dep.track({ target, type, key });
176
- }
177
- }
178
-
179
- function refreshComputed(computed2) {
180
- if (computed2.flags & EffectFlags.DIRTY) {
181
- const prevSub = getActiveSub();
182
- setActiveSub(computed2);
183
- try {
184
- for (let link = computed2.deps; link; link = link.nextDep) {
185
- link.version = -1;
186
- link.prevActiveLink = link.prevDep;
187
- }
188
- const value = computed2.fn(computed2._value);
189
- computed2._value = value;
190
- computed2.flags &= ~EffectFlags.DIRTY;
191
- } finally {
192
- setActiveSub(prevSub);
193
- }
194
- }
195
- }
196
- class ComputedRefImpl {
197
- constructor(fn, setter, isSSR) {
198
- this.fn = fn;
199
- this.setter = setter;
200
- this.isSSR = isSSR;
201
- }
202
- _value = void 0;
203
- dep = new Dep(this);
204
- __v_isRef = true;
205
- deps = void 0;
206
- depsTail = void 0;
207
- flags = EffectFlags.DIRTY;
208
- globalVersion = exports.globalVersion - 1;
209
- isSSR;
210
- effect = this;
211
- onTrack;
212
- onTrigger;
213
- notify() {
214
- this.flags |= EffectFlags.DIRTY;
215
- return true;
216
- }
217
- get value() {
218
- const link = __DEV__ ? this.dep.track({ target: this, type: TrackOpTypes.GET, key: "value" }) : this.dep.track();
219
- refreshComputed(this);
220
- if (link) link.version = this.dep.version;
221
- return this._value;
222
- }
223
- set value(newValue) {
224
- if (this.setter) {
225
- this.setter(newValue);
226
- } else {
227
- console.warn("Write operation failed: computed value is readonly");
228
- }
229
- }
230
- }
231
- function computed(getterOrOptions, debugOptions, isSSR = false) {
232
- let getter;
233
- let setter;
234
- if (isFunction(getterOrOptions)) {
235
- getter = getterOrOptions;
236
- } else {
237
- getter = getterOrOptions.get;
238
- setter = getterOrOptions.set;
239
- }
240
- const cRef = new ComputedRefImpl(getter, setter, isSSR);
241
- return cRef;
242
- }
243
-
244
- class ReactSubscriber {
245
- constructor(triggerUpdate) {
246
- this.triggerUpdate = triggerUpdate;
247
- }
248
- deps;
249
- depsTail;
250
- flags = EffectFlags.TRACKING;
251
- notify() {
252
- this.triggerUpdate();
253
- }
254
- }
255
- function useReactive(refObj) {
256
- const [, setTick] = React.useState(0);
257
- const forceUpdate = () => setTick((t) => t + 1);
258
- const subscriberRef = React.useRef(null);
259
- if (!subscriberRef.current) {
260
- subscriberRef.current = new ReactSubscriber(forceUpdate);
261
- }
262
- const sub = subscriberRef.current;
263
- const prevSub = getActiveSub();
264
- setActiveSub(sub);
265
- const value = refObj.value;
266
- setActiveSub(prevSub);
267
- React.useEffect(() => {
268
- return () => {
269
- };
270
- }, []);
271
- return value;
272
- }
273
- function useComputed(getter, deps = []) {
274
- const cRef = React.useMemo(() => computed(getter), deps);
275
- return useReactive(cRef);
276
- }
277
-
278
- class RefImpl {
279
- _value;
280
- dep;
281
- __v_isRef = true;
282
- constructor(value) {
283
- this._value = value;
284
- this.dep = new Dep();
285
- }
286
- get value() {
287
- this.dep.track({ target: this, type: TrackOpTypes.GET, key: "value" });
288
- return this._value;
289
- }
290
- set value(newVal) {
291
- if (newVal !== this._value) {
292
- this._value = newVal;
293
- this.dep.trigger({
294
- target: this,
295
- type: TriggerOpTypes.SET,
296
- key: "value",
297
- newValue: newVal
298
- });
299
- }
300
- }
301
- }
302
- function ref(value) {
303
- return new RefImpl(value);
304
- }
305
-
306
- function withDefaults(props, defaults) {
307
- const merged = React.useMemo(() => {
308
- const result = { ...props };
309
- for (const key in defaults) {
310
- if (!(key in result) || result[key] === void 0) {
311
- const def = defaults[key];
312
- if (typeof def === "function") {
313
- result[key] = def(result);
314
- } else {
315
- result[key] = def;
316
- }
317
- }
318
- }
319
- return result;
320
- }, [props, defaults]);
321
- return merged;
322
- }
323
-
324
- const useAudioRecorder = (options = {}) => {
325
- const { audioBitsPerSecond, mimeType, timeslice, enableAnalysis, fftSize } = withDefaults(options, {
326
- audioBitsPerSecond: 128e3,
327
- mimeType: "audio/webm",
328
- enableAnalysis: false,
329
- fftSize: 2048
330
- });
331
- const [isRecording, setIsRecording] = React.useState(false);
332
- const [isPaused, setIsPaused] = React.useState(false);
333
- const [stream, setStream] = React.useState(null);
334
- const [mediaRecorder, setMediaRecorder] = React.useState(
335
- null
336
- );
337
- const [audioBlob, setAudioBlob] = React.useState(null);
338
- const [audioUrl, setAudioUrl] = React.useState(null);
339
- const [duration, setDuration] = React.useState(0);
340
- const [error, setError] = React.useState(null);
341
- const [analysisData, setAnalysisData] = React.useState(
342
- null
343
- );
344
- const chunksRef = React.useRef([]);
345
- const startTimeRef = React.useRef(0);
346
- const pausedTimeRef = React.useRef(0);
347
- const intervalRef = React.useRef(null);
348
- const audioContextRef = React.useRef(null);
349
- const analyserRef = React.useRef(null);
350
- const sourceRef = React.useRef(null);
351
- const animationFrameRef = React.useRef(null);
352
- const isSupported = typeof navigator !== "undefined" && !!navigator.mediaDevices && !!navigator.mediaDevices.getUserMedia && !!window.MediaRecorder;
353
- const updateDuration = React.useCallback(() => {
354
- if (startTimeRef.current) {
355
- const elapsed = Date.now() - startTimeRef.current - pausedTimeRef.current;
356
- setDuration(Math.floor(elapsed / 1e3));
357
- }
358
- }, []);
359
- const analyzeAudio = React.useCallback(() => {
360
- if (!analyserRef.current || !enableAnalysis) return;
361
- const frequencyData = new Uint8Array(analyserRef.current.frequencyBinCount);
362
- const timeData = new Uint8Array(analyserRef.current.fftSize);
363
- analyserRef.current.getByteFrequencyData(frequencyData);
364
- analyserRef.current.getByteTimeDomainData(timeData);
365
- let sum = 0;
366
- for (let i = 0; i < timeData.length; i++) {
367
- const sample = ((timeData[i] ?? 0) - 128) / 128;
368
- sum += sample * sample;
369
- }
370
- const volume = Math.sqrt(sum / timeData.length);
371
- setAnalysisData({
372
- frequencyData: frequencyData.slice(),
373
- timeData: timeData.slice(),
374
- volume
375
- });
376
- if (isRecording && !isPaused) {
377
- animationFrameRef.current = requestAnimationFrame(analyzeAudio);
378
- }
379
- }, [isRecording, isPaused, enableAnalysis]);
380
- const setupAudioAnalysis = React.useCallback(
381
- (mediaStream) => {
382
- if (!enableAnalysis) return;
383
- try {
384
- audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
385
- analyserRef.current = audioContextRef.current.createAnalyser();
386
- sourceRef.current = audioContextRef.current.createMediaStreamSource(mediaStream);
387
- analyserRef.current.fftSize = fftSize;
388
- analyserRef.current.smoothingTimeConstant = 0.8;
389
- sourceRef.current.connect(analyserRef.current);
390
- analyzeAudio();
391
- } catch (err) {
392
- console.warn("Failed to setup audio analysis:", err);
393
- }
394
- },
395
- [enableAnalysis, fftSize, analyzeAudio]
396
- );
397
- const startRecording = React.useCallback(async () => {
398
- if (!isSupported) {
399
- setError("Audio recording is not supported in this browser");
400
- return;
401
- }
402
- try {
403
- setError(null);
404
- const mediaStream = await navigator.mediaDevices.getUserMedia({
405
- audio: {
406
- echoCancellation: true,
407
- noiseSuppression: true,
408
- autoGainControl: true
409
- }
410
- });
411
- setStream(mediaStream);
412
- setupAudioAnalysis(mediaStream);
413
- const recorder = new MediaRecorder(mediaStream, {
414
- audioBitsPerSecond,
415
- mimeType: MediaRecorder.isTypeSupported(mimeType) ? mimeType : "audio/webm"
416
- });
417
- chunksRef.current = [];
418
- recorder.ondataavailable = (event) => {
419
- if (event.data.size > 0) {
420
- chunksRef.current.push(event.data);
421
- }
422
- };
423
- recorder.onstop = () => {
424
- const blob = new Blob(chunksRef.current, { type: recorder.mimeType });
425
- setAudioBlob(blob);
426
- setAudioUrl(URL.createObjectURL(blob));
427
- setIsRecording(false);
428
- setIsPaused(false);
429
- if (intervalRef.current) {
430
- clearInterval(intervalRef.current);
431
- intervalRef.current = null;
432
- }
433
- if (animationFrameRef.current) {
434
- cancelAnimationFrame(animationFrameRef.current);
435
- animationFrameRef.current = null;
436
- }
437
- };
438
- recorder.onpause = () => {
439
- setIsPaused(true);
440
- pausedTimeRef.current += Date.now() - startTimeRef.current;
441
- if (animationFrameRef.current) {
442
- cancelAnimationFrame(animationFrameRef.current);
443
- animationFrameRef.current = null;
444
- }
445
- };
446
- recorder.onresume = () => {
447
- setIsPaused(false);
448
- startTimeRef.current = Date.now();
449
- if (enableAnalysis) {
450
- analyzeAudio();
451
- }
452
- };
453
- recorder.onerror = (event) => {
454
- setError(`Recording error: ${event.error?.message || "Unknown error"}`);
455
- setIsRecording(false);
456
- setIsPaused(false);
457
- };
458
- setMediaRecorder(recorder);
459
- recorder.start(timeslice);
460
- setIsRecording(true);
461
- startTimeRef.current = Date.now();
462
- pausedTimeRef.current = 0;
463
- setDuration(0);
464
- intervalRef.current = setInterval(updateDuration, 1e3);
465
- } catch (err) {
466
- const errorMessage = err instanceof Error ? err.message : "Failed to start recording";
467
- setError(errorMessage);
468
- }
469
- }, [
470
- isSupported,
471
- audioBitsPerSecond,
472
- mimeType,
473
- timeslice,
474
- setupAudioAnalysis,
475
- updateDuration,
476
- enableAnalysis,
477
- analyzeAudio
478
- ]);
479
- const stopRecording = React.useCallback(() => {
480
- if (mediaRecorder && mediaRecorder.state !== "inactive") {
481
- mediaRecorder.stop();
482
- }
483
- if (stream) {
484
- stream.getTracks().forEach((track) => track.stop());
485
- setStream(null);
486
- }
487
- if (audioContextRef.current) {
488
- audioContextRef.current.close();
489
- audioContextRef.current = null;
490
- }
491
- }, [mediaRecorder, stream]);
492
- const pauseRecording = React.useCallback(() => {
493
- if (mediaRecorder && mediaRecorder.state === "recording") {
494
- mediaRecorder.pause();
495
- }
496
- }, [mediaRecorder]);
497
- const resumeRecording = React.useCallback(() => {
498
- if (mediaRecorder && mediaRecorder.state === "paused") {
499
- mediaRecorder.resume();
500
- }
501
- }, [mediaRecorder]);
502
- const clearRecording = React.useCallback(() => {
503
- if (audioUrl) {
504
- URL.revokeObjectURL(audioUrl);
505
- }
506
- setAudioBlob(null);
507
- setAudioUrl(null);
508
- setDuration(0);
509
- setAnalysisData(null);
510
- setError(null);
511
- }, [audioUrl]);
512
- const downloadRecording = React.useCallback(
513
- (filename = "recording.webm") => {
514
- if (!audioUrl) return;
515
- const link = document.createElement("a");
516
- link.href = audioUrl;
517
- link.download = filename;
518
- document.body.appendChild(link);
519
- link.click();
520
- document.body.removeChild(link);
521
- },
522
- [audioUrl]
523
- );
524
- React.useEffect(() => {
525
- return () => {
526
- if (intervalRef.current) {
527
- clearInterval(intervalRef.current);
528
- }
529
- if (animationFrameRef.current) {
530
- cancelAnimationFrame(animationFrameRef.current);
531
- }
532
- if (stream) {
533
- stream.getTracks().forEach((track) => track.stop());
534
- }
535
- if (audioContextRef.current) {
536
- audioContextRef.current.close();
537
- }
538
- if (audioUrl) {
539
- URL.revokeObjectURL(audioUrl);
540
- }
541
- };
542
- }, [stream, audioUrl]);
543
- return {
544
- isSupported,
545
- isRecording,
546
- isPaused,
547
- stream,
548
- mediaRecorder,
549
- audioBlob,
550
- audioUrl,
551
- duration,
552
- error,
553
- analysisData,
554
- startRecording,
555
- stopRecording,
556
- pauseRecording,
557
- resumeRecording,
558
- clearRecording,
559
- downloadRecording
560
- };
561
- };
562
-
563
- function on(obj, ...args) {
564
- if (obj && obj.addEventListener) {
565
- obj.addEventListener(
566
- ...args
567
- );
568
- }
569
- }
570
- function off(obj, ...args) {
571
- if (obj && obj.removeEventListener) {
572
- obj.removeEventListener(
573
- ...args
574
- );
575
- }
576
- }
577
- const isNavigator = typeof navigator !== "undefined";
578
-
579
- const { valueOf, toString } = Object.prototype;
580
- const isEqual = (a, b) => {
581
- const visited = /* @__PURE__ */ new WeakMap();
582
- const inner = (a2, b2) => {
583
- if (a2 === b2) {
584
- return true;
585
- }
586
- if (typeof a2 !== "object" || typeof b2 !== "object" || !a2 || !b2) {
587
- return a2 !== a2 && b2 !== b2;
588
- }
589
- if (Object.getPrototypeOf(a2) !== Object.getPrototypeOf(b2)) {
590
- return false;
591
- }
592
- const { constructor } = a2;
593
- if (constructor === Date) {
594
- return a2.getTime() === b2.getTime();
595
- }
596
- if (constructor === RegExp) {
597
- return a2.source === b2.source && a2.flags === b2.flags;
598
- }
599
- if (constructor === Set) {
600
- if (a2.size !== b2.size) {
601
- return false;
602
- }
603
- for (const value of a2) {
604
- if (!b2.has(value)) {
605
- return false;
606
- }
607
- }
608
- return true;
609
- }
610
- if (constructor === ArrayBuffer) {
611
- a2 = new DataView(a2);
612
- b2 = new DataView(b2);
613
- }
614
- if (constructor === DataView || ArrayBuffer.isView(a2)) {
615
- if (constructor !== DataView) {
616
- a2 = new DataView(a2.buffer);
617
- b2 = new DataView(b2.buffer);
618
- }
619
- if (a2.byteLength !== b2.byteLength) return false;
620
- for (let i = a2.byteLength; i-- !== 0; ) {
621
- if (a2.getUint8(i) !== b2.getUint8(i)) {
622
- return false;
623
- }
624
- }
625
- return true;
626
- }
627
- if (visited.has(a2) && visited.get(a2) === b2) {
628
- return true;
629
- }
630
- visited.set(a2, b2);
631
- if (constructor === Array) {
632
- if (a2.length !== b2.length) {
633
- return false;
634
- }
635
- for (let i = a2.length; i-- !== 0; ) {
636
- if (!inner(a2[i], b2[i])) {
637
- return false;
638
- }
639
- }
640
- return true;
641
- }
642
- if (constructor === Map) {
643
- if (a2.size !== b2.size) {
644
- return false;
645
- }
646
- for (const entry of a2) {
647
- if (!b2.has(entry[0]) || !inner(entry[1], b2.get(entry[0]))) {
648
- return false;
649
- }
650
- }
651
- return true;
652
- }
653
- if (a2.valueOf !== valueOf && typeof a2.valueOf === "function" && typeof b2.valueOf === "function") {
654
- return a2.valueOf() === b2.valueOf();
655
- }
656
- if (a2.toString !== toString && typeof a2.toString === "function" && typeof b2.toString === "function") {
657
- return a2.toString() === b2.toString();
658
- }
659
- const aKeys = Object.keys(a2);
660
- let key;
661
- for (let l = aKeys.length; l-- !== 0; ) {
662
- key = aKeys[l];
663
- if (!Object.hasOwn(b2, key) || !inner(a2[key], b2[key])) {
664
- return false;
665
- }
666
- }
667
- return Object.keys(b2).length === aKeys.length;
668
- };
669
- return inner(a, b);
670
- };
671
-
672
- const nav = isNavigator ? navigator : void 0;
673
- const isBatteryApiSupported = nav && typeof nav.getBattery === "function";
674
- function useBatteryMock() {
675
- return { isSupported: false };
676
- }
677
- function useBattery() {
678
- const [state, setState] = React.useState({
679
- isSupported: true,
680
- fetched: false
681
- });
682
- React.useEffect(() => {
683
- let isMounted = true;
684
- let battery = null;
685
- const handleChange = () => {
686
- if (!isMounted || !battery) {
687
- return;
688
- }
689
- const newState = {
690
- isSupported: true,
691
- fetched: true,
692
- level: battery.level,
693
- charging: battery.charging,
694
- dischargingTime: battery.dischargingTime,
695
- chargingTime: battery.chargingTime
696
- };
697
- !isEqual(state, newState) && setState(newState);
698
- };
699
- nav.getBattery().then((bat) => {
700
- if (!isMounted) {
701
- return;
702
- }
703
- battery = bat;
704
- on(battery, "chargingchange", handleChange);
705
- on(battery, "chargingtimechange", handleChange);
706
- on(battery, "dischargingtimechange", handleChange);
707
- on(battery, "levelchange", handleChange);
708
- handleChange();
709
- });
710
- return () => {
711
- isMounted = false;
712
- if (battery) {
713
- off(battery, "chargingchange", handleChange);
714
- off(battery, "chargingtimechange", handleChange);
715
- off(battery, "dischargingtimechange", handleChange);
716
- off(battery, "levelchange", handleChange);
717
- }
718
- };
719
- }, []);
720
- return state;
721
- }
722
- const useBatteryHook = isBatteryApiSupported ? useBattery : useBatteryMock;
723
-
724
- function useBoolean(defaultValue = false) {
725
- if (typeof defaultValue !== "boolean") {
726
- throw new Error("defaultValue must be `true` or `false`");
727
- }
728
- const [value, setValue] = React.useState(defaultValue);
729
- const setTrue = React.useCallback(() => {
730
- setValue(true);
731
- }, []);
732
- const setFalse = React.useCallback(() => {
733
- setValue(false);
734
- }, []);
735
- const toggle = React.useCallback(() => {
736
- setValue((x) => !x);
737
- }, []);
738
- return { value, setValue, setTrue, setFalse, toggle };
739
- }
740
-
741
- const breakpointsTailwind = {
742
- sm: 640,
743
- md: 768,
744
- lg: 1024,
745
- xl: 1280,
746
- "2xl": 1536
747
- };
748
- const breakpointsBootstrapV5 = {
749
- sm: 576,
750
- md: 768,
751
- lg: 992,
752
- xl: 1200,
753
- xxl: 1400
754
- };
755
- const breakpointsVuetify = {
756
- xs: 600,
757
- sm: 960,
758
- md: 1264,
759
- lg: 1904
760
- };
761
- const breakpointsAntDesign = {
762
- xs: 480,
763
- sm: 576,
764
- md: 768,
765
- lg: 992,
766
- xl: 1200,
767
- xxl: 1600
768
- };
769
- const breakpointsSematic = {
770
- mobileS: 320,
771
- mobileM: 375,
772
- mobileL: 425,
773
- tablet: 768,
774
- laptop: 1024,
775
- laptopL: 1440,
776
- desktop4K: 2560
777
- };
778
-
779
- const useIsomorphicLayoutEffect = typeof window !== "undefined" ? React.useLayoutEffect : React.useEffect;
780
-
781
- const IS_SERVER$7 = typeof window === "undefined";
782
- function useMediaQuery(query, {
783
- defaultValue = false,
784
- initializeWithValue = true
785
- } = {}) {
786
- const getMatches = (query2) => {
787
- if (IS_SERVER$7) {
788
- return defaultValue;
789
- }
790
- return window.matchMedia(query2).matches;
791
- };
792
- const [matches, setMatches] = React.useState(() => {
793
- if (initializeWithValue) {
794
- return getMatches(query);
795
- }
796
- return defaultValue;
797
- });
798
- function handleChange() {
799
- setMatches(getMatches(query));
800
- }
801
- useIsomorphicLayoutEffect(() => {
802
- const matchMedia = window.matchMedia(query);
803
- handleChange();
804
- if (matchMedia.addListener) {
805
- matchMedia.addListener(handleChange);
806
- } else {
807
- matchMedia.addEventListener("change", handleChange);
808
- }
809
- return () => {
810
- if (matchMedia.removeListener) {
811
- matchMedia.removeListener(handleChange);
812
- } else {
813
- matchMedia.removeEventListener("change", handleChange);
814
- }
815
- };
816
- }, [query]);
817
- return matches;
818
- }
819
-
820
- function match(query) {
821
- if (typeof window === "undefined") return false;
822
- return window.matchMedia(query).matches;
823
- }
824
- function useBreakpoint(breakpoints) {
825
- return {
826
- /**
827
- * Hook that returns a boolean if screen width is greater than given breakpoint.
828
- *
829
- * @param k {string} breakpoint
830
- * @returns boolean
831
- *
832
- * @see https://react-hooks-library.vercel.app/core/BreakPointHooks
833
- **/
834
- useGreater: (k) => {
835
- return useMediaQuery(`(min-width: ${breakpoints[k]}px)`);
836
- },
837
- /**
838
- * Hook that returns a boolean if screen width is smaller than given breakpoint.
839
- *
840
- * @param k {string} breakpoint
841
- * @param k {string} breakpoint
842
- *
843
- * @returns boolean
844
- *
845
- * @see https://react-hooks-library.vercel.app/core/BreakPointHooks
846
- **/
847
- useSmaller: (k) => {
848
- return useMediaQuery(`(max-width: ${breakpoints[k]}px)`);
849
- },
850
- /**
851
- * Hook that returns a boolean if screen width is between two given breakpoint.
852
- *
853
- * @param a {string} breakpoint
854
- * @param b {string} breakpoint
855
- *
856
- * @returns boolean
857
- *
858
- * @see https://react-hooks-library.vercel.app/core/BreakPointHooks
859
- **/
860
- useBetween: (a, b) => {
861
- return useMediaQuery(
862
- `(min-width: ${breakpoints[a]}px) and (max-width: ${breakpoints[b]}px)`
863
- );
864
- },
865
- /**
866
- * Utility function that returns a boolean if screen width is greater than given breakpoint.
867
- *
868
- * @param k {string} breakpoint
869
- *
870
- * @see https://react-hooks-library.vercel.app/core/BreakPointHooks
871
- **/
872
- isGreater(k) {
873
- return match(`(min-width: ${breakpoints[k]}px)`);
874
- },
875
- /**
876
- * Utility function that returns a boolean if screen width is smaller than given breakpoint.
877
- *
878
- * @param k {string} breakpoint
879
- *
880
- * @see https://react-hooks-library.vercel.app/core/BreakPointHooks
881
- **/
882
- isSmaller(k) {
883
- return match(`(max-width: ${breakpoints[k]}px)`);
884
- },
885
- /**
886
- * Utility function that returns a boolean if screen width is between two given breakpoint.
887
- *
888
- * @param k {string} breakpoint
889
- *
890
- * @see https://react-hooks-library.vercel.app/core/BreakPointHooks
891
- **/
892
- isInBetween(a, b) {
893
- return match(
894
- `(min-width: ${breakpoints[a]}px) and (max-width: ${breakpoints[b]}px)`
895
- );
896
- }
897
- };
898
- }
899
-
900
- function useEventListener(eventName, handler, element, options) {
901
- const savedHandler = React.useRef(handler);
902
- useIsomorphicLayoutEffect(() => {
903
- savedHandler.current = handler;
904
- }, [handler]);
905
- React.useEffect(() => {
906
- const targetElement = element?.current ?? window;
907
- if (!(targetElement && targetElement.addEventListener)) return;
908
- const listener = (event) => {
909
- savedHandler.current(event);
910
- };
911
- targetElement.addEventListener(eventName, listener, options);
912
- return () => {
913
- targetElement.removeEventListener(eventName, listener, options);
914
- };
915
- }, [eventName, element, options]);
916
- }
917
-
918
- function useClickAnyWhere(handler) {
919
- useEventListener("click", (event) => {
920
- handler(event);
921
- });
922
- }
923
-
924
- function useForkRef(...refs) {
925
- const cleanupRef = React__default.useRef(void 0);
926
- const refEffect = React__default.useCallback((instance) => {
927
- const cleanups = refs.map((ref) => {
928
- if (ref == null) {
929
- return null;
930
- }
931
- if (typeof ref === "function") {
932
- const refCallback = ref;
933
- const refCleanup = refCallback(instance);
934
- return typeof refCleanup === "function" ? refCleanup : () => {
935
- refCallback(null);
936
- };
937
- }
938
- ref.current = instance;
939
- return () => {
940
- ref.current = null;
941
- };
942
- });
943
- return () => {
944
- cleanups.forEach((refCleanup) => refCleanup?.());
945
- };
946
- }, refs);
947
- return React__default.useMemo(() => {
948
- if (refs.every((ref) => ref == null)) {
949
- return null;
950
- }
951
- return (value) => {
952
- if (cleanupRef.current) {
953
- cleanupRef.current();
954
- cleanupRef.current = void 0;
955
- }
956
- if (value != null) {
957
- cleanupRef.current = refEffect(value);
958
- }
959
- };
960
- }, refs);
961
- }
962
-
963
- function ownerDocument(node) {
964
- return node && node.ownerDocument || document;
965
- }
966
-
967
- function useEventCallback(fn) {
968
- const ref = React.useRef(() => {
969
- throw new Error("Cannot call an event handler while rendering.");
970
- });
971
- useIsomorphicLayoutEffect(() => {
972
- ref.current = fn;
973
- }, [fn]);
974
- return React.useCallback((...args) => ref.current?.(...args), [ref]);
975
- }
976
-
977
- function mapEventPropToEvent(eventProp) {
978
- return eventProp.substring(2).toLowerCase();
979
- }
980
- function clickedRootScrollbar(event, doc) {
981
- return doc.documentElement.clientWidth < event.clientX || doc.documentElement.clientHeight < event.clientY;
982
- }
983
- function useClickAway(onClickAway, options = {}) {
984
- const {
985
- disableReactTree = false,
986
- mouseEvent = "onClick",
987
- touchEvent = "onTouchEnd",
988
- ref: externalRef
989
- } = options;
990
- const internalRef = React__default.useRef(null);
991
- const handleRef = useForkRef(externalRef, internalRef);
992
- const movedRef = React__default.useRef(false);
993
- const activatedRef = React__default.useRef(false);
994
- const syntheticEventRef = React__default.useRef(false);
995
- React__default.useEffect(() => {
996
- const timer = setTimeout(() => {
997
- activatedRef.current = true;
998
- }, 0);
999
- return () => {
1000
- activatedRef.current = false;
1001
- clearTimeout(timer);
1002
- };
1003
- }, []);
1004
- const handleClickAway = useEventCallback((event) => {
1005
- const insideReactTree = syntheticEventRef.current;
1006
- syntheticEventRef.current = false;
1007
- const doc = ownerDocument(internalRef.current);
1008
- if (!activatedRef.current || !internalRef.current || "clientX" in event && clickedRootScrollbar(event, doc)) {
1009
- return;
1010
- }
1011
- if (movedRef.current) {
1012
- movedRef.current = false;
1013
- return;
1014
- }
1015
- let insideDOM;
1016
- if (event.composedPath) {
1017
- insideDOM = event.composedPath().includes(internalRef.current);
1018
- } else {
1019
- insideDOM = !doc.documentElement.contains(
1020
- // @ts-expect-error returns `false` as intended when not dispatched from a Node
1021
- event.target
1022
- ) || internalRef.current.contains(
1023
- // @ts-expect-error returns `false` as intended when not dispatched from a Node
1024
- event.target
1025
- );
1026
- }
1027
- if (!insideDOM && (disableReactTree || !insideReactTree)) {
1028
- onClickAway(event);
1029
- }
1030
- });
1031
- const createHandleSynthetic = (event) => {
1032
- syntheticEventRef.current = true;
1033
- };
1034
- React__default.useEffect(() => {
1035
- if (touchEvent !== false) {
1036
- const mappedTouchEvent = mapEventPropToEvent(touchEvent);
1037
- const doc = ownerDocument(internalRef.current);
1038
- const handleTouchMove = () => {
1039
- movedRef.current = true;
1040
- };
1041
- doc.addEventListener(mappedTouchEvent, handleClickAway);
1042
- doc.addEventListener("touchmove", handleTouchMove);
1043
- return () => {
1044
- doc.removeEventListener(mappedTouchEvent, handleClickAway);
1045
- doc.removeEventListener("touchmove", handleTouchMove);
1046
- };
1047
- }
1048
- return void 0;
1049
- }, [handleClickAway, touchEvent]);
1050
- React__default.useEffect(() => {
1051
- if (mouseEvent !== false) {
1052
- const mappedMouseEvent = mapEventPropToEvent(mouseEvent);
1053
- const doc = ownerDocument(internalRef.current);
1054
- doc.addEventListener(mappedMouseEvent, handleClickAway);
1055
- return () => {
1056
- doc.removeEventListener(mappedMouseEvent, handleClickAway);
1057
- };
1058
- }
1059
- return void 0;
1060
- }, [handleClickAway, mouseEvent]);
1061
- const listenerProps = {};
1062
- if (mouseEvent !== false) {
1063
- listenerProps[mouseEvent] = createHandleSynthetic;
1064
- }
1065
- if (touchEvent !== false) {
1066
- listenerProps[touchEvent] = createHandleSynthetic;
1067
- }
1068
- return {
1069
- ref: handleRef,
1070
- listenerProps
1071
- };
1072
- }
1073
-
1074
- const DEFAULT_CONSTRAINTS = {
1075
- video: true,
1076
- audio: true
1077
- };
1078
- const useUserMedia = (initialConstraints = DEFAULT_CONSTRAINTS) => {
1079
- const [stream, setStream] = React.useState(null);
1080
- const [error, setError] = React.useState(null);
1081
- const [isLoading, setIsLoading] = React.useState(false);
1082
- const streamRef = React.useRef(null);
1083
- const isSupported = typeof navigator !== "undefined" && "mediaDevices" in navigator && "getUserMedia" in navigator.mediaDevices;
1084
- const stopCapture = React.useCallback(() => {
1085
- if (streamRef.current) {
1086
- streamRef.current.getTracks().forEach((track) => {
1087
- track.stop();
1088
- });
1089
- streamRef.current = null;
1090
- setStream(null);
1091
- }
1092
- setError(null);
1093
- }, []);
1094
- const startCapture = React.useCallback(
1095
- async (constraints = initialConstraints) => {
1096
- if (!isSupported) {
1097
- setError("getUserMedia is not supported in this browser");
1098
- return;
1099
- }
1100
- stopCapture();
1101
- setIsLoading(true);
1102
- setError(null);
1103
- try {
1104
- const mediaStream = await navigator.mediaDevices.getUserMedia(constraints);
1105
- streamRef.current = mediaStream;
1106
- setStream(mediaStream);
1107
- } catch (err) {
1108
- let errorMessage = "Failed to access media devices";
1109
- if (err instanceof Error) {
1110
- switch (err.name) {
1111
- case "NotAllowedError":
1112
- errorMessage = "Permission denied. Please allow camera/microphone access.";
1113
- break;
1114
- case "NotFoundError":
1115
- errorMessage = "No camera or microphone found.";
1116
- break;
1117
- case "NotReadableError":
1118
- errorMessage = "Camera or microphone is already in use.";
1119
- break;
1120
- case "OverconstrainedError":
1121
- errorMessage = "Camera or microphone constraints cannot be satisfied.";
1122
- break;
1123
- case "SecurityError":
1124
- errorMessage = "Security error. Make sure you're using HTTPS.";
1125
- break;
1126
- case "AbortError":
1127
- errorMessage = "Media access was aborted.";
1128
- break;
1129
- default:
1130
- errorMessage = err.message || errorMessage;
1131
- }
1132
- }
1133
- setError(errorMessage);
1134
- } finally {
1135
- setIsLoading(false);
1136
- }
1137
- },
1138
- [isSupported, initialConstraints, stopCapture]
1139
- );
1140
- React.useEffect(() => {
1141
- return () => {
1142
- stopCapture();
1143
- };
1144
- }, [stopCapture]);
1145
- return {
1146
- stream,
1147
- error,
1148
- isLoading,
1149
- isSupported,
1150
- startCapture,
1151
- stopCapture
1152
- };
1153
- };
1154
-
1155
- const DEFAULT_OPTIONS = {
1156
- video: true,
1157
- audio: false
1158
- };
1159
- function useScreenShare(initialOptions = DEFAULT_OPTIONS) {
1160
- const [stream, setStream] = React.useState(null);
1161
- const [error, setError] = React.useState(null);
1162
- const [isLoading, setIsLoading] = React.useState(false);
1163
- const streamRef = React.useRef(null);
1164
- const isSupported = typeof navigator !== "undefined" && "mediaDevices" in navigator && "getDisplayMedia" in navigator.mediaDevices;
1165
- const stopCapture = React.useCallback(() => {
1166
- if (streamRef.current) {
1167
- streamRef.current.getTracks().forEach((track) => {
1168
- track.stop();
1169
- });
1170
- streamRef.current = null;
1171
- setStream(null);
1172
- }
1173
- setError(null);
1174
- }, []);
1175
- const startCapture = React.useCallback(
1176
- async (options = initialOptions) => {
1177
- if (!isSupported) {
1178
- setError("getDisplayMedia is not supported in this browser");
1179
- return;
1180
- }
1181
- stopCapture();
1182
- setIsLoading(true);
1183
- setError(null);
1184
- try {
1185
- const mediaStream = await navigator.mediaDevices.getDisplayMedia(options);
1186
- const videoTrack = mediaStream.getVideoTracks()[0];
1187
- if (videoTrack) {
1188
- videoTrack.onended = () => {
1189
- stopCapture();
1190
- };
1191
- }
1192
- streamRef.current = mediaStream;
1193
- setStream(mediaStream);
1194
- } catch (err) {
1195
- let errorMessage = "Failed to start screen sharing";
1196
- if (err instanceof Error) {
1197
- switch (err.name) {
1198
- case "NotAllowedError":
1199
- errorMessage = "Permission denied or user cancelled the selection.";
1200
- break;
1201
- case "NotFoundError":
1202
- errorMessage = "No screen video source found.";
1203
- break;
1204
- case "NotReadableError":
1205
- errorMessage = "Could not capture the screen (OS or hardware error).";
1206
- break;
1207
- case "OverconstrainedError":
1208
- errorMessage = "The specified constraints cannot be satisfied.";
1209
- break;
1210
- case "AbortError":
1211
- errorMessage = "Screen sharing selection was aborted.";
1212
- break;
1213
- default:
1214
- errorMessage = err.message || errorMessage;
1215
- }
1216
- }
1217
- setError(errorMessage);
1218
- } finally {
1219
- setIsLoading(false);
1220
- }
1221
- },
1222
- [isSupported, initialOptions, stopCapture]
1223
- );
1224
- React.useEffect(() => {
1225
- return () => {
1226
- stopCapture();
1227
- };
1228
- }, [stopCapture]);
1229
- return {
1230
- stream,
1231
- error,
1232
- isLoading,
1233
- isSupported,
1234
- startCapture,
1235
- stopCapture
1236
- };
1237
- }
1238
-
1239
- const useNetworkInformation = () => {
1240
- const [networkInfo, setNetworkInfo] = React.useState(
1241
- null
1242
- );
1243
- const [isOnline, setIsOnline] = React.useState(
1244
- typeof navigator !== "undefined" ? navigator.onLine : true
1245
- );
1246
- const isSupported = typeof navigator !== "undefined" && "connection" in navigator && navigator.connection !== void 0;
1247
- const updateNetworkInfo = React.useCallback(() => {
1248
- if (!isSupported || !navigator.connection) return;
1249
- const connection = navigator.connection;
1250
- setNetworkInfo({
1251
- downlink: connection.downlink,
1252
- downlinkMax: connection.downlinkMax,
1253
- effectiveType: connection.effectiveType,
1254
- rtt: connection.rtt,
1255
- saveData: connection.saveData,
1256
- type: connection.type
1257
- });
1258
- }, [isSupported]);
1259
- const handleOnlineStatusChange = React.useCallback(() => {
1260
- setIsOnline(navigator.onLine);
1261
- }, []);
1262
- const handleConnectionChange = React.useCallback(() => {
1263
- updateNetworkInfo();
1264
- }, [updateNetworkInfo]);
1265
- React.useEffect(() => {
1266
- if (typeof window === "undefined") return;
1267
- updateNetworkInfo();
1268
- window.addEventListener("online", handleOnlineStatusChange);
1269
- window.addEventListener("offline", handleOnlineStatusChange);
1270
- if (isSupported) {
1271
- const connection = navigator.connection;
1272
- connection.addEventListener("change", handleConnectionChange);
1273
- }
1274
- return () => {
1275
- window.removeEventListener("online", handleOnlineStatusChange);
1276
- window.removeEventListener("offline", handleOnlineStatusChange);
1277
- if (isSupported) {
1278
- const connection = navigator.connection;
1279
- connection.removeEventListener("change", handleConnectionChange);
1280
- }
1281
- };
1282
- }, [
1283
- isSupported,
1284
- updateNetworkInfo,
1285
- handleOnlineStatusChange,
1286
- handleConnectionChange
1287
- ]);
1288
- return {
1289
- networkInfo,
1290
- isOnline,
1291
- isSupported,
1292
- refresh: updateNetworkInfo
1293
- };
1294
- };
1295
-
1296
- const QUALITY_PRESETS = {
1297
- low: {
1298
- width: { ideal: 320 },
1299
- height: { ideal: 240 },
1300
- frameRate: { max: 15 }
1301
- },
1302
- medium: {
1303
- width: { ideal: 640 },
1304
- height: { ideal: 480 },
1305
- frameRate: { max: 24 }
1306
- },
1307
- high: {
1308
- width: { ideal: 1280 },
1309
- height: { ideal: 720 },
1310
- frameRate: { max: 30 }
1311
- }
1312
- };
1313
- const useMediaQuality = (stream) => {
1314
- const [quality, setQuality] = React.useState("high");
1315
- const [isChanging, setIsChanging] = React.useState(false);
1316
- const applyQuality = React.useCallback(
1317
- async (level) => {
1318
- if (!stream) return;
1319
- const videoTrack = stream.getVideoTracks()[0];
1320
- if (!videoTrack) return;
1321
- if (level === quality && !isChanging) return;
1322
- setIsChanging(true);
1323
- try {
1324
- await videoTrack.applyConstraints(QUALITY_PRESETS[level]);
1325
- setQuality(level);
1326
- console.log(`Video quality switched to: ${level}`);
1327
- } catch (err) {
1328
- console.warn("Camera hardware could not satisfy constraints:", err);
1329
- } finally {
1330
- setIsChanging(false);
1331
- }
1332
- },
1333
- [stream, quality, isChanging]
1334
- );
1335
- return { quality, isChanging, setQuality: applyQuality };
1336
- };
1337
-
1338
- const useConferenceSystem = (options = {}) => {
1339
- const camera = useUserMedia();
1340
- const screen = useScreenShare();
1341
- const network = useNetworkInformation();
1342
- const {
1343
- quality,
1344
- setQuality: applyQuality,
1345
- isChanging: isQualityChanging
1346
- } = useMediaQuality(camera.stream);
1347
- const [isAutoQuality, setIsAutoQuality] = React.useState(
1348
- options.defaultAutoQuality ?? true
1349
- );
1350
- React.useEffect(() => {
1351
- if (!isAutoQuality || !camera.stream || !network.networkInfo) return;
1352
- const { downlink, effectiveType, saveData } = network.networkInfo;
1353
- let targetQuality = "high";
1354
- if (saveData) {
1355
- targetQuality = "low";
1356
- } else if (effectiveType === "2g" || effectiveType === "slow-2g") {
1357
- targetQuality = "low";
1358
- } else if (downlink && downlink < 1.5) {
1359
- targetQuality = "low";
1360
- } else if (downlink && downlink < 5) {
1361
- targetQuality = "medium";
1362
- } else {
1363
- targetQuality = "high";
1364
- }
1365
- if (quality !== targetQuality) {
1366
- applyQuality(targetQuality);
1367
- }
1368
- }, [
1369
- network.networkInfo,
1370
- isAutoQuality,
1371
- camera.stream,
1372
- quality,
1373
- applyQuality
1374
- ]);
1375
- return {
1376
- camera: {
1377
- stream: camera.stream,
1378
- start: camera.startCapture,
1379
- stop: camera.stopCapture,
1380
- isActive: !!camera.stream,
1381
- error: camera.error,
1382
- isLoading: camera.isLoading
1383
- },
1384
- screen: {
1385
- stream: screen.stream,
1386
- start: screen.startCapture,
1387
- stop: screen.stopCapture,
1388
- isActive: !!screen.stream,
1389
- error: screen.error
1390
- },
1391
- quality: {
1392
- current: quality,
1393
- isChanging: isQualityChanging,
1394
- set: applyQuality,
1395
- // Manual Override
1396
- isAuto: isAutoQuality,
1397
- toggleAuto: () => setIsAutoQuality((prev) => !prev)
1398
- },
1399
- network: {
1400
- isOnline: network.isOnline,
1401
- speed: network.networkInfo?.downlink || 0,
1402
- // Mbps
1403
- type: network.networkInfo?.effectiveType || "unknown"
1404
- }
1405
- };
1406
- };
1407
-
1408
- const IS_SERVER$6 = typeof document === "undefined";
1409
- function parseCookies() {
1410
- if (IS_SERVER$6) return {};
1411
- return document.cookie.split("; ").reduce(
1412
- (acc, part) => {
1413
- const [k, ...v] = part.split("=");
1414
- if (k && v) {
1415
- acc[decodeURIComponent(k.trim())] = decodeURIComponent(v.join("="));
1416
- }
1417
- return acc;
1418
- },
1419
- {}
1420
- );
1421
- }
1422
- function buildCookie(key, value, options) {
1423
- let cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
1424
- if (options.path) cookie += `; path=${options.path}`;
1425
- if (options.domain) cookie += `; domain=${options.domain}`;
1426
- if (options.expires) cookie += `; expires=${options.expires.toUTCString()}`;
1427
- if (options.maxAge) cookie += `; max-age=${options.maxAge}`;
1428
- if (options.secure) cookie += `; secure`;
1429
- if (options.sameSite) cookie += `; samesite=${options.sameSite}`;
1430
- return cookie;
1431
- }
1432
- function useCookie(key, initialValue, options = {}) {
1433
- const { initializeWithValue = true, prefix = "" } = options;
1434
- const cookieKey = prefix + key;
1435
- const serializer = React.useCallback(
1436
- (value) => {
1437
- if (options.serializer) return options.serializer(value);
1438
- return JSON.stringify(value);
1439
- },
1440
- [options]
1441
- );
1442
- const deserializer = React.useCallback(
1443
- (value) => {
1444
- if (options.deserializer) return options.deserializer(value);
1445
- if (value === "undefined") return void 0;
1446
- const fallback = initialValue instanceof Function ? initialValue() : initialValue;
1447
- try {
1448
- return JSON.parse(value);
1449
- } catch {
1450
- return fallback;
1451
- }
1452
- },
1453
- [options, initialValue]
1454
- );
1455
- const readValue = React.useCallback(() => {
1456
- const fallback = initialValue instanceof Function ? initialValue() : initialValue;
1457
- if (IS_SERVER$6) return fallback;
1458
- const cookies = parseCookies();
1459
- if (!(cookieKey in cookies)) return fallback;
1460
- return deserializer(cookies[cookieKey]);
1461
- }, [cookieKey, deserializer, initialValue]);
1462
- const [storedValue, setStoredValue] = React.useState(() => {
1463
- if (initializeWithValue) return readValue();
1464
- return initialValue instanceof Function ? initialValue() : initialValue;
1465
- });
1466
- const setValue = useEventCallback((value) => {
1467
- if (IS_SERVER$6) return;
1468
- try {
1469
- const newValue = value instanceof Function ? value(readValue()) : value;
1470
- const serialized = serializer(newValue);
1471
- document.cookie = buildCookie(cookieKey, serialized, {
1472
- path: "/",
1473
- ...options
1474
- });
1475
- setStoredValue(newValue);
1476
- window.dispatchEvent(
1477
- new CustomEvent("cookie-change", { detail: { key: cookieKey } })
1478
- );
1479
- } catch (error) {
1480
- console.warn(`Error setting cookie "${cookieKey}":`, error);
1481
- }
1482
- });
1483
- const removeValue = useEventCallback(() => {
1484
- if (IS_SERVER$6) return;
1485
- const fallback = initialValue instanceof Function ? initialValue() : initialValue;
1486
- document.cookie = buildCookie(cookieKey, "", {
1487
- path: "/",
1488
- ...options,
1489
- expires: /* @__PURE__ */ new Date(0)
1490
- });
1491
- setStoredValue(fallback);
1492
- window.dispatchEvent(
1493
- new CustomEvent("cookie-change", { detail: { key: cookieKey } })
1494
- );
1495
- });
1496
- React.useEffect(() => {
1497
- setStoredValue(readValue());
1498
- }, [cookieKey]);
1499
- const handleChange = React.useCallback(
1500
- (event) => {
1501
- if ("detail" in event && event.detail?.key !== cookieKey) return;
1502
- if ("key" in event && event.key !== cookieKey) return;
1503
- setStoredValue(readValue());
1504
- },
1505
- [cookieKey, readValue]
1506
- );
1507
- useEventListener("cookie-change", handleChange);
1508
- useEventListener("visibilitychange", () => {
1509
- if (document.visibilityState === "visible") {
1510
- setStoredValue(readValue());
1511
- }
1512
- });
1513
- return [storedValue, setValue, removeValue];
1514
- }
1515
-
1516
- function useCopyToClipboard() {
1517
- const [copiedText, setCopiedText] = React.useState(null);
1518
- const copy = React.useCallback(async (text) => {
1519
- if (!navigator?.clipboard) {
1520
- console.warn("Clipboard not supported");
1521
- return false;
1522
- }
1523
- try {
1524
- await navigator.clipboard.writeText(text);
1525
- setCopiedText(text);
1526
- return true;
1527
- } catch (error) {
1528
- console.warn("Copy failed", error);
1529
- setCopiedText(null);
1530
- return false;
1531
- }
1532
- }, []);
1533
- return [copiedText, copy];
1534
- }
1535
-
1536
- function useCounter(initialValue) {
1537
- const [count, setCount] = React.useState(initialValue ?? 0);
1538
- const increment = React.useCallback(() => {
1539
- setCount((x) => x + 1);
1540
- }, []);
1541
- const decrement = React.useCallback(() => {
1542
- setCount((x) => x - 1);
1543
- }, []);
1544
- const reset = React.useCallback(() => {
1545
- setCount(initialValue ?? 0);
1546
- }, [initialValue]);
1547
- return {
1548
- count,
1549
- increment,
1550
- decrement,
1551
- reset,
1552
- setCount
1553
- };
1554
- }
1555
-
1556
- function useInterval(callback, delay) {
1557
- const savedCallback = React.useRef(callback);
1558
- useIsomorphicLayoutEffect(() => {
1559
- savedCallback.current = callback;
1560
- }, [callback]);
1561
- React.useEffect(() => {
1562
- if (delay === null) {
1563
- return;
1564
- }
1565
- const id = setInterval(() => {
1566
- savedCallback.current();
1567
- }, delay);
1568
- return () => {
1569
- clearInterval(id);
1570
- };
1571
- }, [delay]);
1572
- }
1573
-
1574
- function useCountdown({
1575
- countStart,
1576
- countStop = 0,
1577
- intervalMs = 1e3,
1578
- isIncrement = false
1579
- }) {
1580
- const {
1581
- count,
1582
- increment,
1583
- decrement,
1584
- reset: resetCounter
1585
- } = useCounter(countStart);
1586
- const {
1587
- value: isCountdownRunning,
1588
- setTrue: startCountdown,
1589
- setFalse: stopCountdown
1590
- } = useBoolean(false);
1591
- const resetCountdown = React.useCallback(() => {
1592
- stopCountdown();
1593
- resetCounter();
1594
- }, [stopCountdown, resetCounter]);
1595
- const countdownCallback = React.useCallback(() => {
1596
- if (count === countStop) {
1597
- stopCountdown();
1598
- return;
1599
- }
1600
- if (isIncrement) {
1601
- increment();
1602
- } else {
1603
- decrement();
1604
- }
1605
- }, [count, countStop, decrement, increment, isIncrement, stopCountdown]);
1606
- useInterval(countdownCallback, isCountdownRunning ? intervalMs : null);
1607
- return [count, { startCountdown, stopCountdown, resetCountdown }];
1608
- }
1609
-
1610
- const IS_SERVER$5 = typeof window === "undefined";
1611
- function useLocalStorage(key, initialValue, options = {}) {
1612
- const { initializeWithValue = true } = options;
1613
- const serializer = React.useCallback(
1614
- (value) => {
1615
- if (options.serializer) {
1616
- return options.serializer(value);
1617
- }
1618
- return JSON.stringify(value);
1619
- },
1620
- [options]
1621
- );
1622
- const deserializer = React.useCallback(
1623
- (value) => {
1624
- if (options.deserializer) {
1625
- return options.deserializer(value);
1626
- }
1627
- if (value === "undefined") {
1628
- return void 0;
1629
- }
1630
- const defaultValue = initialValue instanceof Function ? initialValue() : initialValue;
1631
- let parsed;
1632
- try {
1633
- parsed = JSON.parse(value);
1634
- } catch (error) {
1635
- console.error("Error parsing JSON:", error);
1636
- return defaultValue;
1637
- }
1638
- return parsed;
1639
- },
1640
- [options, initialValue]
1641
- );
1642
- const readValue = React.useCallback(() => {
1643
- const initialValueToUse = initialValue instanceof Function ? initialValue() : initialValue;
1644
- if (IS_SERVER$5) {
1645
- return initialValueToUse;
1646
- }
1647
- try {
1648
- const raw = window.localStorage.getItem(key);
1649
- return raw ? deserializer(raw) : initialValueToUse;
1650
- } catch (error) {
1651
- console.warn(`Error reading localStorage key \u201C${key}\u201D:`, error);
1652
- return initialValueToUse;
1653
- }
1654
- }, [initialValue, key, deserializer]);
1655
- const [storedValue, setStoredValue] = React.useState(() => {
1656
- if (initializeWithValue) {
1657
- return readValue();
1658
- }
1659
- return initialValue instanceof Function ? initialValue() : initialValue;
1660
- });
1661
- const setValue = useEventCallback((value) => {
1662
- if (IS_SERVER$5) {
1663
- console.warn(
1664
- `Tried setting localStorage key \u201C${key}\u201D even though environment is not a client`
1665
- );
1666
- }
1667
- try {
1668
- const newValue = value instanceof Function ? value(readValue()) : value;
1669
- window.localStorage.setItem(key, serializer(newValue));
1670
- setStoredValue(newValue);
1671
- window.dispatchEvent(new StorageEvent("local-storage", { key }));
1672
- } catch (error) {
1673
- console.warn(`Error setting localStorage key \u201C${key}\u201D:`, error);
1674
- }
1675
- });
1676
- const removeValue = useEventCallback(() => {
1677
- if (IS_SERVER$5) {
1678
- console.warn(
1679
- `Tried removing localStorage key \u201C${key}\u201D even though environment is not a client`
1680
- );
1681
- }
1682
- const defaultValue = initialValue instanceof Function ? initialValue() : initialValue;
1683
- window.localStorage.removeItem(key);
1684
- setStoredValue(defaultValue);
1685
- window.dispatchEvent(new StorageEvent("local-storage", { key }));
1686
- });
1687
- React.useEffect(() => {
1688
- setStoredValue(readValue());
1689
- }, [key]);
1690
- const handleStorageChange = React.useCallback(
1691
- (event) => {
1692
- if (event.key && event.key !== key) {
1693
- return;
1694
- }
1695
- setStoredValue(readValue());
1696
- },
1697
- [key, readValue]
1698
- );
1699
- useEventListener("storage", handleStorageChange);
1700
- useEventListener("local-storage", handleStorageChange);
1701
- return [storedValue, setValue, removeValue];
1702
- }
1703
-
1704
- const COLOR_SCHEME_QUERY$1 = "(prefers-color-scheme: dark)";
1705
- const LOCAL_STORAGE_KEY$1 = "sse-hooks-dark-mode";
1706
- function useDarkMode(options = {}) {
1707
- const {
1708
- defaultValue,
1709
- localStorageKey = LOCAL_STORAGE_KEY$1,
1710
- initializeWithValue = true
1711
- } = options;
1712
- const isDarkOS = useMediaQuery(COLOR_SCHEME_QUERY$1, {
1713
- initializeWithValue,
1714
- defaultValue
1715
- });
1716
- const [isDarkMode, setDarkMode] = useLocalStorage(
1717
- localStorageKey,
1718
- defaultValue ?? isDarkOS ?? false,
1719
- { initializeWithValue }
1720
- );
1721
- useIsomorphicLayoutEffect(() => {
1722
- if (isDarkOS !== isDarkMode) {
1723
- setDarkMode(isDarkOS);
1724
- }
1725
- }, [isDarkOS]);
1726
- return {
1727
- isDarkMode,
1728
- toggle: () => {
1729
- setDarkMode((prev) => !prev);
1730
- },
1731
- enable: () => {
1732
- setDarkMode(true);
1733
- },
1734
- disable: () => {
1735
- setDarkMode(false);
1736
- },
1737
- set: (value) => {
1738
- setDarkMode(value);
1739
- }
1740
- };
1741
- }
1742
-
1743
- function useUnmount(func) {
1744
- const funcRef = React.useRef(func);
1745
- funcRef.current = func;
1746
- React.useEffect(
1747
- () => () => {
1748
- funcRef.current();
1749
- },
1750
- []
1751
- );
1752
- }
1753
-
1754
- function useDebounceCallback(func, delay = 500, options) {
1755
- const debouncedFunc = React.useRef();
1756
- useUnmount(() => {
1757
- if (debouncedFunc.current) {
1758
- debouncedFunc.current.cancel();
1759
- }
1760
- });
1761
- const debounced = React.useMemo(() => {
1762
- const debouncedFuncInstance = debounce__default(func, delay, options);
1763
- const wrappedFunc = (...args) => {
1764
- return debouncedFuncInstance(...args);
1765
- };
1766
- wrappedFunc.cancel = () => {
1767
- debouncedFuncInstance.cancel();
1768
- };
1769
- wrappedFunc.isPending = () => {
1770
- return !!debouncedFunc.current;
1771
- };
1772
- wrappedFunc.flush = () => {
1773
- return debouncedFuncInstance.flush();
1774
- };
1775
- return wrappedFunc;
1776
- }, [func, delay, options]);
1777
- React.useEffect(() => {
1778
- debouncedFunc.current = debounce__default(func, delay, options);
1779
- }, [func, delay, options]);
1780
- return debounced;
1781
- }
1782
-
1783
- function useDebounceValue(initialValue, delay, options) {
1784
- const eq = options?.equalityFn ?? ((left, right) => left === right);
1785
- const unwrappedInitialValue = initialValue instanceof Function ? initialValue() : initialValue;
1786
- const [debouncedValue, setDebouncedValue] = React.useState(
1787
- unwrappedInitialValue
1788
- );
1789
- const previousValueRef = React.useRef(unwrappedInitialValue);
1790
- const updateDebouncedValue = useDebounceCallback(
1791
- setDebouncedValue,
1792
- delay,
1793
- options
1794
- );
1795
- if (!eq(previousValueRef.current, unwrappedInitialValue)) {
1796
- updateDebouncedValue(unwrappedInitialValue);
1797
- previousValueRef.current = unwrappedInitialValue;
1798
- }
1799
- return [debouncedValue, updateDebouncedValue];
1800
- }
1801
-
1802
- function useDocumentTitle(title, options = {}) {
1803
- const { preserveTitleOnUnmount = true } = options;
1804
- const defaultTitle = React.useRef(null);
1805
- useIsomorphicLayoutEffect(() => {
1806
- defaultTitle.current = window.document.title;
1807
- }, []);
1808
- useIsomorphicLayoutEffect(() => {
1809
- window.document.title = title;
1810
- }, [title]);
1811
- useUnmount(() => {
1812
- if (!preserveTitleOnUnmount && defaultTitle.current) {
1813
- window.document.title = defaultTitle.current;
1814
- }
1815
- });
1816
- }
1817
-
1818
- function useFetch(url, options = {}) {
1819
- const [state, setState] = React.useState({
1820
- data: null,
1821
- loading: false,
1822
- error: null
1823
- });
1824
- const abortControllerRef = React.useRef(null);
1825
- const optionsRef = React.useRef(options);
1826
- React.useEffect(() => {
1827
- optionsRef.current = options;
1828
- }, [options]);
1829
- const execute = React.useCallback(
1830
- async (executeUrl, executeOptions) => {
1831
- const targetUrl = executeUrl || url;
1832
- if (!targetUrl) {
1833
- const error = new Error("No URL provided");
1834
- setState((prev) => ({ ...prev, error, loading: false }));
1835
- optionsRef.current.onError?.(error);
1836
- throw error;
1837
- }
1838
- if (abortControllerRef.current) {
1839
- abortControllerRef.current.abort();
1840
- }
1841
- abortControllerRef.current = new AbortController();
1842
- setState((prev) => ({ ...prev, loading: true, error: null }));
1843
- try {
1844
- const { immediate, onSuccess, onError, ...fetchOptions } = optionsRef.current;
1845
- const response = await fetch(targetUrl, {
1846
- ...fetchOptions,
1847
- ...executeOptions,
1848
- signal: abortControllerRef.current.signal
1849
- });
1850
- if (!response.ok) {
1851
- throw new Error(`HTTP error! status: ${response.status}`);
1852
- }
1853
- let data;
1854
- const contentType = response.headers.get("content-type");
1855
- if (contentType && contentType.includes("application/json")) {
1856
- data = await response.json();
1857
- } else {
1858
- data = await response.text();
1859
- }
1860
- setState({ data, loading: false, error: null });
1861
- onSuccess?.(data);
1862
- return data;
1863
- } catch (error) {
1864
- const fetchError = error;
1865
- if (fetchError.name !== "AbortError") {
1866
- setState((prev) => ({ ...prev, loading: false, error: fetchError }));
1867
- optionsRef.current.onError?.(fetchError);
1868
- }
1869
- throw fetchError;
1870
- }
1871
- },
1872
- [url]
1873
- );
1874
- const abort = React.useCallback(() => {
1875
- if (abortControllerRef.current) {
1876
- abortControllerRef.current.abort();
1877
- abortControllerRef.current = null;
1878
- }
1879
- }, []);
1880
- const reset = React.useCallback(() => {
1881
- abort();
1882
- setState({ data: null, loading: false, error: null });
1883
- }, [abort]);
1884
- React.useEffect(() => {
1885
- if (options.immediate && url) {
1886
- execute();
1887
- }
1888
- }, [url, options.immediate, execute]);
1889
- React.useEffect(() => {
1890
- return () => {
1891
- abort();
1892
- };
1893
- }, [abort]);
1894
- return {
1895
- ...state,
1896
- execute,
1897
- abort,
1898
- reset
1899
- };
1900
- }
1901
- function useGet(url, options = {}) {
1902
- return useFetch(url, { ...options, method: "GET" });
1903
- }
1904
- function usePost(url, options = {}) {
1905
- return useFetch(url, { ...options, method: "POST" });
1906
- }
1907
- function usePut(url, options = {}) {
1908
- return useFetch(url, { ...options, method: "PUT" });
1909
- }
1910
- function useDelete(url, options = {}) {
1911
- return useFetch(url, { ...options, method: "DELETE" });
1912
- }
1913
-
1914
- function useHover(elementRef) {
1915
- const [value, setValue] = React.useState(false);
1916
- const handleMouseEnter = () => {
1917
- setValue(true);
1918
- };
1919
- const handleMouseLeave = () => {
1920
- setValue(false);
1921
- };
1922
- useEventListener("mouseenter", handleMouseEnter, elementRef);
1923
- useEventListener("mouseleave", handleMouseLeave, elementRef);
1924
- return value;
1925
- }
1926
-
1927
- function useIndexedDB(databaseName, storeName, options = {}) {
1928
- const [data, setData] = React.useState(null);
1929
- const [error, setError] = React.useState(null);
1930
- const [loading, setLoading] = React.useState(false);
1931
- const [db, setDb] = React.useState(null);
1932
- const { version = 1, onUpgradeNeeded } = options;
1933
- React.useEffect(() => {
1934
- if (typeof window === "undefined") return;
1935
- const initDB = async () => {
1936
- try {
1937
- setLoading(true);
1938
- setError(null);
1939
- const request = indexedDB.open(databaseName, version);
1940
- request.onerror = () => {
1941
- setError(`Failed to open database: ${request.error?.message}`);
1942
- setLoading(false);
1943
- };
1944
- request.onsuccess = () => {
1945
- setDb(request.result);
1946
- setLoading(false);
1947
- };
1948
- request.onupgradeneeded = (event) => {
1949
- const database = request.result;
1950
- const oldVersion = event.oldVersion;
1951
- const newVersion = event.newVersion || version;
1952
- if (!database.objectStoreNames.contains(storeName)) {
1953
- database.createObjectStore(storeName);
1954
- }
1955
- if (onUpgradeNeeded) {
1956
- onUpgradeNeeded(database, oldVersion, newVersion);
1957
- }
1958
- };
1959
- } catch (err) {
1960
- setError(`IndexedDB initialization error: ${err}`);
1961
- setLoading(false);
1962
- }
1963
- };
1964
- initDB();
1965
- return () => {
1966
- if (db) {
1967
- db.close();
1968
- }
1969
- };
1970
- }, [databaseName, storeName, version, onUpgradeNeeded]);
1971
- const setItem = React.useCallback(
1972
- async (key, value) => {
1973
- if (!db) {
1974
- throw new Error("Database not initialized");
1975
- }
1976
- return new Promise((resolve, reject) => {
1977
- const transaction = db.transaction([storeName], "readwrite");
1978
- const store = transaction.objectStore(storeName);
1979
- const request = store.put(value, key);
1980
- request.onsuccess = () => {
1981
- setData(value);
1982
- resolve();
1983
- };
1984
- request.onerror = () => {
1985
- const errorMsg = `Failed to set item: ${request.error?.message}`;
1986
- setError(errorMsg);
1987
- reject(new Error(errorMsg));
1988
- };
1989
- });
1990
- },
1991
- [db, storeName]
1992
- );
1993
- const getItem = React.useCallback(
1994
- async (key) => {
1995
- if (!db) {
1996
- throw new Error("Database not initialized");
1997
- }
1998
- return new Promise((resolve, reject) => {
1999
- const transaction = db.transaction([storeName], "readonly");
2000
- const store = transaction.objectStore(storeName);
2001
- const request = store.get(key);
2002
- request.onsuccess = () => {
2003
- const result = request.result || null;
2004
- setData(result);
2005
- resolve(result);
2006
- };
2007
- request.onerror = () => {
2008
- const errorMsg = `Failed to get item: ${request.error?.message}`;
2009
- setError(errorMsg);
2010
- reject(new Error(errorMsg));
2011
- };
2012
- });
2013
- },
2014
- [db, storeName]
2015
- );
2016
- const removeItem = React.useCallback(
2017
- async (key) => {
2018
- if (!db) {
2019
- throw new Error("Database not initialized");
2020
- }
2021
- return new Promise((resolve, reject) => {
2022
- const transaction = db.transaction([storeName], "readwrite");
2023
- const store = transaction.objectStore(storeName);
2024
- const request = store.delete(key);
2025
- request.onsuccess = () => {
2026
- setData(null);
2027
- resolve();
2028
- };
2029
- request.onerror = () => {
2030
- const errorMsg = `Failed to remove item: ${request.error?.message}`;
2031
- setError(errorMsg);
2032
- reject(new Error(errorMsg));
2033
- };
2034
- });
2035
- },
2036
- [db, storeName]
2037
- );
2038
- const clear = React.useCallback(async () => {
2039
- if (!db) {
2040
- throw new Error("Database not initialized");
2041
- }
2042
- return new Promise((resolve, reject) => {
2043
- const transaction = db.transaction([storeName], "readwrite");
2044
- const store = transaction.objectStore(storeName);
2045
- const request = store.clear();
2046
- request.onsuccess = () => {
2047
- setData(null);
2048
- resolve();
2049
- };
2050
- request.onerror = () => {
2051
- const errorMsg = `Failed to clear store: ${request.error?.message}`;
2052
- setError(errorMsg);
2053
- reject(new Error(errorMsg));
2054
- };
2055
- });
2056
- }, [db, storeName]);
2057
- const getAllKeys = React.useCallback(async () => {
2058
- if (!db) {
2059
- throw new Error("Database not initialized");
2060
- }
2061
- return new Promise((resolve, reject) => {
2062
- const transaction = db.transaction([storeName], "readonly");
2063
- const store = transaction.objectStore(storeName);
2064
- const request = store.getAllKeys();
2065
- request.onsuccess = () => {
2066
- resolve(request.result);
2067
- };
2068
- request.onerror = () => {
2069
- const errorMsg = `Failed to get keys: ${request.error?.message}`;
2070
- setError(errorMsg);
2071
- reject(new Error(errorMsg));
2072
- };
2073
- });
2074
- }, [db, storeName]);
2075
- return {
2076
- data,
2077
- error,
2078
- loading,
2079
- setItem,
2080
- getItem,
2081
- removeItem,
2082
- clear,
2083
- getAllKeys
2084
- };
2085
- }
2086
-
2087
- function useIntersectionObserver({
2088
- threshold = 0,
2089
- root = null,
2090
- rootMargin = "0%",
2091
- freezeOnceVisible = false,
2092
- initialIsIntersecting = false,
2093
- onChange
2094
- } = {}) {
2095
- const [ref, setRef] = React.useState(null);
2096
- const [state, setState] = React.useState(() => ({
2097
- isIntersecting: initialIsIntersecting,
2098
- entry: void 0
2099
- }));
2100
- const callbackRef = React.useRef();
2101
- callbackRef.current = onChange;
2102
- const frozen = state.entry?.isIntersecting && freezeOnceVisible;
2103
- React.useEffect(() => {
2104
- if (!ref) return;
2105
- if (!("IntersectionObserver" in window)) return;
2106
- if (frozen) return;
2107
- const observer = new IntersectionObserver(
2108
- (entries) => {
2109
- const thresholds = Array.isArray(observer.thresholds) ? observer.thresholds : [observer.thresholds];
2110
- entries.forEach((entry) => {
2111
- const isIntersecting = entry.isIntersecting && thresholds.some(
2112
- (threshold2) => entry.intersectionRatio >= threshold2
2113
- );
2114
- setState({ isIntersecting, entry });
2115
- if (callbackRef.current) {
2116
- callbackRef.current(isIntersecting, entry);
2117
- }
2118
- });
2119
- },
2120
- { threshold, root, rootMargin }
2121
- );
2122
- observer.observe(ref);
2123
- return () => {
2124
- observer.disconnect();
2125
- };
2126
- }, [
2127
- ref,
2128
- // eslint-disable-next-line react-hooks/exhaustive-deps
2129
- JSON.stringify(threshold),
2130
- root,
2131
- rootMargin,
2132
- frozen,
2133
- freezeOnceVisible
2134
- ]);
2135
- const prevRef = React.useRef(null);
2136
- React.useEffect(() => {
2137
- if (!ref && state.entry?.target && !freezeOnceVisible && !frozen && prevRef.current !== state.entry.target) {
2138
- prevRef.current = state.entry.target;
2139
- setState({ isIntersecting: initialIsIntersecting, entry: void 0 });
2140
- }
2141
- }, [ref, state.entry, freezeOnceVisible, frozen, initialIsIntersecting]);
2142
- const result = [
2143
- setRef,
2144
- !!state.isIntersecting,
2145
- state.entry
2146
- ];
2147
- result.ref = result[0];
2148
- result.isIntersecting = result[1];
2149
- result.entry = result[2];
2150
- return result;
2151
- }
2152
-
2153
- function useIsClient() {
2154
- const [isClient, setClient] = React.useState(false);
2155
- React.useEffect(() => {
2156
- setClient(true);
2157
- }, []);
2158
- return isClient;
2159
- }
2160
-
2161
- function useIsMounted() {
2162
- const isMounted = React.useRef(false);
2163
- React.useEffect(() => {
2164
- isMounted.current = true;
2165
- return () => {
2166
- isMounted.current = false;
2167
- };
2168
- }, []);
2169
- return React.useCallback(() => isMounted.current, []);
2170
- }
2171
-
2172
- const kbdKeysMap = {
2173
- meta: "",
2174
- ctrl: "",
2175
- alt: "",
2176
- win: "\u229E",
2177
- command: "\u2318",
2178
- shift: "\u21E7",
2179
- control: "\u2303",
2180
- option: "\u2325",
2181
- enter: "\u21B5",
2182
- delete: "\u2326",
2183
- backspace: "\u232B",
2184
- escape: "Esc",
2185
- tab: "\u21E5",
2186
- capslock: "\u21EA",
2187
- arrowup: "\u2191",
2188
- arrowright: "\u2192",
2189
- arrowdown: "\u2193",
2190
- arrowleft: "\u2190",
2191
- pageup: "\u21DE",
2192
- pagedown: "\u21DF",
2193
- home: "\u2196",
2194
- end: "\u2198"
2195
- };
2196
- const useKbd = () => {
2197
- const [isMac, setIsMac] = React.useState(false);
2198
- React.useEffect(() => {
2199
- const isClient = typeof window !== "undefined" && typeof navigator !== "undefined";
2200
- if (isClient) {
2201
- const isMacUserAgent = /Macintosh/.test(navigator.userAgent);
2202
- setIsMac(isMacUserAgent);
2203
- }
2204
- }, []);
2205
- const kbdKeysSpecificMap = {
2206
- meta: isMac ? kbdKeysMap.command : "Ctrl",
2207
- ctrl: isMac ? kbdKeysMap.control : "Ctrl",
2208
- alt: isMac ? kbdKeysMap.option : "Alt"
2209
- };
2210
- const getKbdKey = React.useCallback(
2211
- (value) => {
2212
- if (!value) {
2213
- return void 0;
2214
- }
2215
- if (["meta", "alt", "ctrl"].includes(value)) {
2216
- return kbdKeysSpecificMap[value];
2217
- }
2218
- return kbdKeysMap[value] || value;
2219
- },
2220
- [isMac]
2221
- );
2222
- return {
2223
- isMac,
2224
- getKbdKey
2225
- };
2226
- };
2227
-
2228
- function useMap(initialState = /* @__PURE__ */ new Map()) {
2229
- const [map, setMap] = React.useState(new Map(initialState));
2230
- const actions = {
2231
- set: React.useCallback((key, value) => {
2232
- setMap((prev) => {
2233
- const copy = new Map(prev);
2234
- copy.set(key, value);
2235
- return copy;
2236
- });
2237
- }, []),
2238
- setAll: React.useCallback((entries) => {
2239
- setMap(() => new Map(entries));
2240
- }, []),
2241
- remove: React.useCallback((key) => {
2242
- setMap((prev) => {
2243
- const copy = new Map(prev);
2244
- copy.delete(key);
2245
- return copy;
2246
- });
2247
- }, []),
2248
- reset: React.useCallback(() => {
2249
- setMap(() => /* @__PURE__ */ new Map());
2250
- }, [])
2251
- };
2252
- return [map, actions];
2253
- }
2254
-
2255
- const useMediaSession = (options) => {
2256
- const actionHandlersRef = React.useRef(/* @__PURE__ */ new Set());
2257
- const isSupported = typeof navigator !== "undefined" && "mediaSession" in navigator;
2258
- const setMetadata = React.useCallback(
2259
- (metadata) => {
2260
- if (!isSupported) return;
2261
- try {
2262
- navigator.mediaSession.metadata = new MediaMetadata(metadata);
2263
- } catch (error) {
2264
- console.warn("Failed to set media metadata:", error);
2265
- }
2266
- },
2267
- [isSupported]
2268
- );
2269
- const setPlaybackState = React.useCallback(
2270
- (state) => {
2271
- if (!isSupported) return;
2272
- try {
2273
- navigator.mediaSession.playbackState = state;
2274
- } catch (error) {
2275
- console.warn("Failed to set playback state:", error);
2276
- }
2277
- },
2278
- [isSupported]
2279
- );
2280
- const setActionHandler = React.useCallback(
2281
- (action, handler) => {
2282
- if (!isSupported) return;
2283
- try {
2284
- navigator.mediaSession.setActionHandler(action, handler);
2285
- if (handler) {
2286
- actionHandlersRef.current.add(action);
2287
- } else {
2288
- actionHandlersRef.current.delete(action);
2289
- }
2290
- } catch (error) {
2291
- console.warn(`Failed to set action handler for ${action}:`, error);
2292
- }
2293
- },
2294
- [isSupported]
2295
- );
2296
- const clearActionHandlers = React.useCallback(() => {
2297
- if (!isSupported) return;
2298
- actionHandlersRef.current.forEach((action) => {
2299
- try {
2300
- navigator.mediaSession.setActionHandler(action, null);
2301
- } catch (error) {
2302
- console.warn(`Failed to clear action handler for ${action}:`, error);
2303
- }
2304
- });
2305
- actionHandlersRef.current.clear();
2306
- }, [isSupported]);
2307
- React.useEffect(() => {
2308
- if (options?.metadata) {
2309
- setMetadata(options.metadata);
2310
- }
2311
- }, [setMetadata, options?.metadata]);
2312
- React.useEffect(() => {
2313
- if (options?.playbackState) {
2314
- setPlaybackState(options.playbackState);
2315
- }
2316
- }, [setPlaybackState, options?.playbackState]);
2317
- React.useEffect(() => {
2318
- if (options?.actionHandlers) {
2319
- Object.entries(options.actionHandlers).forEach(([action, handler]) => {
2320
- if (handler) {
2321
- setActionHandler(action, handler);
2322
- }
2323
- });
2324
- }
2325
- return () => {
2326
- clearActionHandlers();
2327
- };
2328
- }, [setActionHandler, clearActionHandlers, options?.actionHandlers]);
2329
- return {
2330
- isSupported,
2331
- setMetadata,
2332
- setPlaybackState,
2333
- setActionHandler,
2334
- clearActionHandlers
2335
- };
2336
- };
2337
-
2338
- var Device = /* @__PURE__ */ ((Device2) => {
2339
- Device2["Browser"] = "browser";
2340
- Device2["Server"] = "server";
2341
- Device2["Native"] = "native";
2342
- return Device2;
2343
- })(Device || {});
2344
-
2345
- const { Browser, Server, Native } = Device;
2346
- const canUseDOM = !!(typeof window !== "undefined" && window.document && window.document.createElement);
2347
- const canUseNative = typeof navigator != "undefined" && navigator.product == "ReactNative";
2348
- const device = canUseNative ? Native : canUseDOM ? Browser : Server;
2349
- const SSRObject = {
2350
- isBrowser: device === Browser,
2351
- isServer: device === Server,
2352
- isNative: device === Native,
2353
- device,
2354
- canUseWorkers: typeof Worker !== "undefined",
2355
- canUseEventListeners: device === Browser && !!window.addEventListener,
2356
- canUseViewport: device === Browser && !!window.screen
2357
- };
2358
- const assign = (...args) => args.reduce((acc, obj) => ({ ...acc, ...obj }), {});
2359
- const values = (obj) => Object.keys(obj).map((key) => obj[key]);
2360
- const toArrayObject = () => assign((values(SSRObject), SSRObject));
2361
- let useSSRObject = toArrayObject();
2362
- const weAreServer = () => {
2363
- SSRObject.isServer = true;
2364
- useSSRObject = toArrayObject();
2365
- };
2366
- const useSSR = () => useSSRObject;
2367
-
2368
- const errorMessage1 = "You must either add a `ref` to the element you are interacting with or pass an `event` to openPortal(e) or togglePortal(e) when the `programmaticallyOpen` option is not set to `true`.";
2369
-
2370
- const IS_SERVER$4 = typeof window === "undefined";
2371
- function useReadLocalStorage(key, options = {}) {
2372
- let { initializeWithValue = true } = options;
2373
- if (IS_SERVER$4) {
2374
- initializeWithValue = false;
2375
- }
2376
- const deserializer = React.useCallback(
2377
- (value) => {
2378
- if (options.deserializer) {
2379
- return options.deserializer(value);
2380
- }
2381
- if (value === "undefined") {
2382
- return void 0;
2383
- }
2384
- let parsed;
2385
- try {
2386
- parsed = JSON.parse(value);
2387
- } catch (error) {
2388
- console.error("Error parsing JSON:", error);
2389
- return null;
2390
- }
2391
- return parsed;
2392
- },
2393
- [options]
2394
- );
2395
- const readValue = React.useCallback(() => {
2396
- if (IS_SERVER$4) {
2397
- return null;
2398
- }
2399
- try {
2400
- const raw = window.localStorage.getItem(key);
2401
- return raw ? deserializer(raw) : null;
2402
- } catch (error) {
2403
- console.warn(`Error reading localStorage key \u201C${key}\u201D:`, error);
2404
- return null;
2405
- }
2406
- }, [key, deserializer]);
2407
- const [storedValue, setStoredValue] = React.useState(() => {
2408
- if (initializeWithValue) {
2409
- return readValue();
2410
- }
2411
- return void 0;
2412
- });
2413
- React.useEffect(() => {
2414
- setStoredValue(readValue());
2415
- }, [key]);
2416
- const handleStorageChange = React.useCallback(
2417
- (event) => {
2418
- if (event.key && event.key !== key) {
2419
- return;
2420
- }
2421
- setStoredValue(readValue());
2422
- },
2423
- [key, readValue]
2424
- );
2425
- useEventListener("storage", handleStorageChange);
2426
- useEventListener("local-storage", handleStorageChange);
2427
- return storedValue;
2428
- }
2429
-
2430
- const initialSize = {
2431
- width: void 0,
2432
- height: void 0
2433
- };
2434
- function useResizeObserver(options) {
2435
- const { ref, box = "content-box" } = options;
2436
- const [{ width, height }, setSize] = React.useState(initialSize);
2437
- const isMounted = useIsMounted();
2438
- const previousSize = React.useRef({ ...initialSize });
2439
- const onResize = React.useRef(void 0);
2440
- onResize.current = options.onResize;
2441
- React.useEffect(() => {
2442
- if (!ref.current) return;
2443
- if (typeof window === "undefined" || !("ResizeObserver" in window)) return;
2444
- const observer = new ResizeObserver(([entry]) => {
2445
- const boxProp = box === "border-box" ? "borderBoxSize" : box === "device-pixel-content-box" ? "devicePixelContentBoxSize" : "contentBoxSize";
2446
- const newWidth = extractSize(entry, boxProp, "inlineSize");
2447
- const newHeight = extractSize(entry, boxProp, "blockSize");
2448
- const hasChanged = previousSize.current.width !== newWidth || previousSize.current.height !== newHeight;
2449
- if (hasChanged) {
2450
- const newSize = { width: newWidth, height: newHeight };
2451
- previousSize.current.width = newWidth;
2452
- previousSize.current.height = newHeight;
2453
- if (onResize.current) {
2454
- onResize.current(newSize);
2455
- } else {
2456
- if (isMounted()) {
2457
- setSize(newSize);
2458
- }
2459
- }
2460
- }
2461
- });
2462
- observer.observe(ref.current, { box });
2463
- return () => {
2464
- observer.disconnect();
2465
- };
2466
- }, [box, ref, isMounted]);
2467
- return { width, height };
2468
- }
2469
- function extractSize(entry, box, sizeType) {
2470
- if (!entry[box]) {
2471
- if (box === "contentBoxSize") {
2472
- return entry.contentRect[sizeType === "inlineSize" ? "width" : "height"];
2473
- }
2474
- return void 0;
2475
- }
2476
- return Array.isArray(entry[box]) ? entry[box][0][sizeType] : (
2477
- // @ts-ignore Support Firefox's non-standard behavior
2478
- entry[box][sizeType]
2479
- );
2480
- }
2481
-
2482
- function useRoleGuard(requiredRoles, options = {}) {
2483
- const {
2484
- user: providedUser,
2485
- redirectTo = "/unauthorized",
2486
- onUnauthorized,
2487
- sessionKey = "user"
2488
- } = options;
2489
- const [user, setUser] = React.useState(providedUser || null);
2490
- const [isLoading, setIsLoading] = React.useState(!providedUser);
2491
- React.useEffect(() => {
2492
- if (!providedUser && typeof window !== "undefined") {
2493
- try {
2494
- const sessionUser = sessionStorage.getItem(sessionKey);
2495
- if (sessionUser) {
2496
- const parsedUser = JSON.parse(sessionUser);
2497
- setUser(parsedUser);
2498
- }
2499
- } catch (error) {
2500
- console.error("Error parsing user from session:", error);
2501
- } finally {
2502
- setIsLoading(false);
2503
- }
2504
- }
2505
- }, [providedUser, sessionKey]);
2506
- const hasAnyRole = React.useCallback(
2507
- (roles) => {
2508
- if (!user || !user.roles) return false;
2509
- return roles.some((role) => user.roles.includes(role));
2510
- },
2511
- [user]
2512
- );
2513
- const hasAllRoles = React.useCallback(
2514
- (roles) => {
2515
- if (!user || !user.roles) return false;
2516
- return roles.every((role) => user.roles.includes(role));
2517
- },
2518
- [user]
2519
- );
2520
- const checkAccess = React.useCallback(
2521
- (roles) => {
2522
- return hasAnyRole(roles);
2523
- },
2524
- [hasAnyRole]
2525
- );
2526
- const hasAccess = checkAccess(requiredRoles);
2527
- const redirect = React.useCallback(() => {
2528
- if (typeof window !== "undefined" && redirectTo) {
2529
- window.location.href = redirectTo;
2530
- }
2531
- }, [redirectTo]);
2532
- React.useEffect(() => {
2533
- if (!isLoading && !hasAccess) {
2534
- if (onUnauthorized) {
2535
- onUnauthorized();
2536
- } else if (redirectTo && typeof window !== "undefined") {
2537
- redirect();
2538
- }
2539
- }
2540
- }, [hasAccess, isLoading, onUnauthorized, redirect, redirectTo]);
2541
- return {
2542
- hasAccess,
2543
- hasAnyRole,
2544
- hasAllRoles,
2545
- isLoading,
2546
- user,
2547
- checkAccess,
2548
- redirect
2549
- };
2550
- }
2551
-
2552
- const IS_SERVER$3 = typeof window === "undefined";
2553
- function useScreen(options = {}) {
2554
- let { initializeWithValue = true } = options;
2555
- if (IS_SERVER$3) {
2556
- initializeWithValue = false;
2557
- }
2558
- const readScreen = () => {
2559
- if (IS_SERVER$3) {
2560
- return void 0;
2561
- }
2562
- return window.screen;
2563
- };
2564
- const [screen, setScreen] = React.useState(() => {
2565
- if (initializeWithValue) {
2566
- return readScreen();
2567
- }
2568
- return void 0;
2569
- });
2570
- const debouncedSetScreen = useDebounceCallback(
2571
- setScreen,
2572
- options.debounceDelay
2573
- );
2574
- function handleSize() {
2575
- const newScreen = readScreen();
2576
- const setSize = options.debounceDelay ? debouncedSetScreen : setScreen;
2577
- if (newScreen) {
2578
- const {
2579
- width,
2580
- height,
2581
- availHeight,
2582
- availWidth,
2583
- colorDepth,
2584
- orientation,
2585
- pixelDepth
2586
- } = newScreen;
2587
- setSize({
2588
- width,
2589
- height,
2590
- availHeight,
2591
- availWidth,
2592
- colorDepth,
2593
- orientation,
2594
- pixelDepth
2595
- });
2596
- }
2597
- }
2598
- useEventListener("resize", handleSize);
2599
- useIsomorphicLayoutEffect(() => {
2600
- handleSize();
2601
- }, []);
2602
- return screen;
2603
- }
2604
-
2605
- const cachedScriptStatuses = /* @__PURE__ */ new Map();
2606
- function getScriptNode(src) {
2607
- const node = document.querySelector(
2608
- `script[src="${src}"]`
2609
- );
2610
- const status = node?.getAttribute("data-status");
2611
- return {
2612
- node,
2613
- status
2614
- };
2615
- }
2616
- function useScript(src, options) {
2617
- const [status, setStatus] = React.useState(() => {
2618
- if (!src || options?.shouldPreventLoad) {
2619
- return "idle";
2620
- }
2621
- if (typeof window === "undefined") {
2622
- return "loading";
2623
- }
2624
- return cachedScriptStatuses.get(src) ?? "loading";
2625
- });
2626
- React.useEffect(() => {
2627
- if (!src || options?.shouldPreventLoad) {
2628
- return;
2629
- }
2630
- const cachedScriptStatus = cachedScriptStatuses.get(src);
2631
- if (cachedScriptStatus === "ready" || cachedScriptStatus === "error") {
2632
- setStatus(cachedScriptStatus);
2633
- return;
2634
- }
2635
- const script = getScriptNode(src);
2636
- let scriptNode = script.node;
2637
- if (!scriptNode) {
2638
- scriptNode = document.createElement("script");
2639
- scriptNode.src = src;
2640
- scriptNode.async = true;
2641
- if (options?.id) {
2642
- scriptNode.id = options.id;
2643
- }
2644
- scriptNode.setAttribute("data-status", "loading");
2645
- document.body.appendChild(scriptNode);
2646
- const setAttributeFromEvent = (event) => {
2647
- const scriptStatus = event.type === "load" ? "ready" : "error";
2648
- scriptNode?.setAttribute("data-status", scriptStatus);
2649
- };
2650
- scriptNode.addEventListener("load", setAttributeFromEvent);
2651
- scriptNode.addEventListener("error", setAttributeFromEvent);
2652
- } else {
2653
- setStatus(script.status ?? cachedScriptStatus ?? "loading");
2654
- }
2655
- const setStateFromEvent = (event) => {
2656
- const newStatus = event.type === "load" ? "ready" : "error";
2657
- setStatus(newStatus);
2658
- cachedScriptStatuses.set(src, newStatus);
2659
- };
2660
- scriptNode.addEventListener("load", setStateFromEvent);
2661
- scriptNode.addEventListener("error", setStateFromEvent);
2662
- return () => {
2663
- if (scriptNode) {
2664
- scriptNode.removeEventListener("load", setStateFromEvent);
2665
- scriptNode.removeEventListener("error", setStateFromEvent);
2666
- }
2667
- if (scriptNode && options?.removeOnUnmount) {
2668
- scriptNode.remove();
2669
- cachedScriptStatuses.delete(src);
2670
- }
2671
- };
2672
- }, [src, options?.shouldPreventLoad, options?.removeOnUnmount, options?.id]);
2673
- return status;
2674
- }
2675
-
2676
- const IS_SERVER$2 = typeof window === "undefined";
2677
- function useScrollLock(options = {}) {
2678
- const { autoLock = true, lockTarget, widthReflow = true } = options;
2679
- const [isLocked, setIsLocked] = React.useState(false);
2680
- const target = React.useRef(null);
2681
- const originalStyle = React.useRef(null);
2682
- const lock = () => {
2683
- if (target.current) {
2684
- const { overflow, paddingRight } = target.current.style;
2685
- originalStyle.current = { overflow, paddingRight };
2686
- if (widthReflow) {
2687
- const offsetWidth = target.current === document.body ? window.innerWidth : target.current.offsetWidth;
2688
- const currentPaddingRight = parseInt(window.getComputedStyle(target.current).paddingRight, 10) || 0;
2689
- const scrollbarWidth = offsetWidth - target.current.scrollWidth;
2690
- target.current.style.paddingRight = `${scrollbarWidth + currentPaddingRight}px`;
2691
- }
2692
- target.current.style.overflow = "hidden";
2693
- setIsLocked(true);
2694
- }
2695
- };
2696
- const unlock = () => {
2697
- if (target.current && originalStyle.current) {
2698
- target.current.style.overflow = originalStyle.current.overflow;
2699
- if (widthReflow) {
2700
- target.current.style.paddingRight = originalStyle.current.paddingRight;
2701
- }
2702
- }
2703
- setIsLocked(false);
2704
- };
2705
- useIsomorphicLayoutEffect(() => {
2706
- if (IS_SERVER$2) return;
2707
- if (lockTarget) {
2708
- target.current = typeof lockTarget === "string" ? document.querySelector(lockTarget) : lockTarget;
2709
- }
2710
- if (!target.current) {
2711
- target.current = document.body;
2712
- }
2713
- if (autoLock) {
2714
- lock();
2715
- }
2716
- return () => {
2717
- unlock();
2718
- };
2719
- }, [autoLock, lockTarget, widthReflow]);
2720
- return { isLocked, lock, unlock };
2721
- }
2722
-
2723
- const IS_SERVER$1 = typeof window === "undefined";
2724
- function useSessionStorage(key, initialValue, options = {}) {
2725
- const { initializeWithValue = true } = options;
2726
- const serializer = React.useCallback(
2727
- (value) => {
2728
- if (options.serializer) {
2729
- return options.serializer(value);
2730
- }
2731
- return JSON.stringify(value);
2732
- },
2733
- [options]
2734
- );
2735
- const deserializer = React.useCallback(
2736
- (value) => {
2737
- if (options.deserializer) {
2738
- return options.deserializer(value);
2739
- }
2740
- if (value === "undefined") {
2741
- return void 0;
2742
- }
2743
- const defaultValue = initialValue instanceof Function ? initialValue() : initialValue;
2744
- let parsed;
2745
- try {
2746
- parsed = JSON.parse(value);
2747
- } catch (error) {
2748
- console.error("Error parsing JSON:", error);
2749
- return defaultValue;
2750
- }
2751
- return parsed;
2752
- },
2753
- [options, initialValue]
2754
- );
2755
- const readValue = React.useCallback(() => {
2756
- const initialValueToUse = initialValue instanceof Function ? initialValue() : initialValue;
2757
- if (IS_SERVER$1) {
2758
- return initialValueToUse;
2759
- }
2760
- try {
2761
- const raw = window.sessionStorage.getItem(key);
2762
- return raw ? deserializer(raw) : initialValueToUse;
2763
- } catch (error) {
2764
- console.warn(`Error reading sessionStorage key \u201C${key}\u201D:`, error);
2765
- return initialValueToUse;
2766
- }
2767
- }, [initialValue, key, deserializer]);
2768
- const [storedValue, setStoredValue] = React.useState(() => {
2769
- if (initializeWithValue) {
2770
- return readValue();
2771
- }
2772
- return initialValue instanceof Function ? initialValue() : initialValue;
2773
- });
2774
- const setValue = useEventCallback((value) => {
2775
- if (IS_SERVER$1) {
2776
- console.warn(
2777
- `Tried setting sessionStorage key \u201C${key}\u201D even though environment is not a client`
2778
- );
2779
- }
2780
- try {
2781
- const newValue = value instanceof Function ? value(readValue()) : value;
2782
- window.sessionStorage.setItem(key, serializer(newValue));
2783
- setStoredValue(newValue);
2784
- window.dispatchEvent(new StorageEvent("session-storage", { key }));
2785
- } catch (error) {
2786
- console.warn(`Error setting sessionStorage key \u201C${key}\u201D:`, error);
2787
- }
2788
- });
2789
- const removeValue = useEventCallback(() => {
2790
- if (IS_SERVER$1) {
2791
- console.warn(
2792
- `Tried removing sessionStorage key \u201C${key}\u201D even though environment is not a client`
2793
- );
2794
- }
2795
- const defaultValue = initialValue instanceof Function ? initialValue() : initialValue;
2796
- window.sessionStorage.removeItem(key);
2797
- setStoredValue(defaultValue);
2798
- window.dispatchEvent(new StorageEvent("session-storage", { key }));
2799
- });
2800
- React.useEffect(() => {
2801
- setStoredValue(readValue());
2802
- }, [key]);
2803
- const handleStorageChange = React.useCallback(
2804
- (event) => {
2805
- if (event.key && event.key !== key) {
2806
- return;
2807
- }
2808
- setStoredValue(readValue());
2809
- },
2810
- [key, readValue]
2811
- );
2812
- useEventListener("storage", handleStorageChange);
2813
- useEventListener("session-storage", handleStorageChange);
2814
- return [storedValue, setValue, removeValue];
2815
- }
2816
-
2817
- function useStep(maxStep) {
2818
- const [currentStep, setCurrentStep] = React.useState(1);
2819
- const canGoToNextStep = currentStep + 1 <= maxStep;
2820
- const canGoToPrevStep = currentStep - 1 > 0;
2821
- const setStep = React.useCallback(
2822
- (step) => {
2823
- const newStep = step instanceof Function ? step(currentStep) : step;
2824
- if (newStep >= 1 && newStep <= maxStep) {
2825
- setCurrentStep(newStep);
2826
- return;
2827
- }
2828
- throw new Error("Step not valid");
2829
- },
2830
- [maxStep, currentStep]
2831
- );
2832
- const goToNextStep = React.useCallback(() => {
2833
- if (canGoToNextStep) {
2834
- setCurrentStep((step) => step + 1);
2835
- }
2836
- }, [canGoToNextStep]);
2837
- const goToPrevStep = React.useCallback(() => {
2838
- if (canGoToPrevStep) {
2839
- setCurrentStep((step) => step - 1);
2840
- }
2841
- }, [canGoToPrevStep]);
2842
- const reset = React.useCallback(() => {
2843
- setCurrentStep(1);
2844
- }, []);
2845
- return [
2846
- currentStep,
2847
- {
2848
- goToNextStep,
2849
- goToPrevStep,
2850
- canGoToNextStep,
2851
- canGoToPrevStep,
2852
- setStep,
2853
- reset
2854
- }
2855
- ];
2856
- }
2857
-
2858
- function useSymbol() {
2859
- const [symbols, setSymbols] = React.useState([]);
2860
- const symbolsRef = React.useRef(/* @__PURE__ */ new Set());
2861
- const createSymbol = React.useCallback((description) => {
2862
- const newSymbol = Symbol(description);
2863
- setSymbols((prev) => [...prev, newSymbol]);
2864
- symbolsRef.current.add(newSymbol);
2865
- return newSymbol;
2866
- }, []);
2867
- const getGlobalSymbol = React.useCallback((key) => {
2868
- return Symbol.for(key);
2869
- }, []);
2870
- const getSymbolKey = React.useCallback((symbol) => {
2871
- return Symbol.keyFor(symbol);
2872
- }, []);
2873
- const isSymbol = React.useCallback((value) => {
2874
- return typeof value === "symbol";
2875
- }, []);
2876
- const getDescription = React.useCallback((symbol) => {
2877
- return symbol.description;
2878
- }, []);
2879
- const addSymbol = React.useCallback((symbol) => {
2880
- if (!symbolsRef.current.has(symbol)) {
2881
- setSymbols((prev) => [...prev, symbol]);
2882
- symbolsRef.current.add(symbol);
2883
- }
2884
- }, []);
2885
- const removeSymbol = React.useCallback((symbol) => {
2886
- if (symbolsRef.current.has(symbol)) {
2887
- setSymbols((prev) => prev.filter((s) => s !== symbol));
2888
- symbolsRef.current.delete(symbol);
2889
- }
2890
- }, []);
2891
- const clearSymbols = React.useCallback(() => {
2892
- setSymbols([]);
2893
- symbolsRef.current.clear();
2894
- }, []);
2895
- const wellKnownSymbols = React.useMemo(
2896
- () => ({
2897
- iterator: Symbol.iterator,
2898
- asyncIterator: Symbol.asyncIterator,
2899
- hasInstance: Symbol.hasInstance,
2900
- isConcatSpreadable: Symbol.isConcatSpreadable,
2901
- species: Symbol.species,
2902
- toPrimitive: Symbol.toPrimitive,
2903
- toStringTag: Symbol.toStringTag,
2904
- unscopables: Symbol.unscopables,
2905
- match: Symbol.match,
2906
- matchAll: Symbol.matchAll,
2907
- replace: Symbol.replace,
2908
- search: Symbol.search,
2909
- split: Symbol.split
2910
- }),
2911
- []
2912
- );
2913
- return {
2914
- createSymbol,
2915
- getGlobalSymbol,
2916
- getSymbolKey,
2917
- isSymbol,
2918
- getDescription,
2919
- wellKnownSymbols,
2920
- symbols,
2921
- addSymbol,
2922
- removeSymbol,
2923
- clearSymbols
2924
- };
2925
- }
2926
-
2927
- const COLOR_SCHEME_QUERY = "(prefers-color-scheme: dark)";
2928
- const LOCAL_STORAGE_KEY = "sse-hooks-ternary-dark-mode";
2929
- function useTernaryDarkMode({
2930
- defaultValue = "system",
2931
- localStorageKey = LOCAL_STORAGE_KEY,
2932
- initializeWithValue = true
2933
- } = {}) {
2934
- const isDarkOS = useMediaQuery(COLOR_SCHEME_QUERY, { initializeWithValue });
2935
- const [mode, setMode] = useLocalStorage(localStorageKey, defaultValue, {
2936
- initializeWithValue
2937
- });
2938
- const isDarkMode = mode === "dark" || mode === "system" && isDarkOS;
2939
- const toggleTernaryDarkMode = () => {
2940
- const modes = ["light", "system", "dark"];
2941
- setMode((prevMode) => {
2942
- const nextIndex = (modes.indexOf(prevMode) + 1) % modes.length;
2943
- return modes[nextIndex];
2944
- });
2945
- };
2946
- return {
2947
- isDarkMode,
2948
- ternaryDarkMode: mode,
2949
- setTernaryDarkMode: setMode,
2950
- toggleTernaryDarkMode
2951
- };
2952
- }
2953
-
2954
- function useTimeout(callback, delay) {
2955
- const savedCallback = React.useRef(callback);
2956
- useIsomorphicLayoutEffect(() => {
2957
- savedCallback.current = callback;
2958
- }, [callback]);
2959
- React.useEffect(() => {
2960
- if (!delay && delay !== 0) {
2961
- return;
2962
- }
2963
- const id = setTimeout(() => {
2964
- savedCallback.current();
2965
- }, delay);
2966
- return () => {
2967
- clearTimeout(id);
2968
- };
2969
- }, [delay]);
2970
- }
2971
-
2972
- function useToggle(defaultValue) {
2973
- const [value, setValue] = React.useState(!!defaultValue);
2974
- const toggle = React.useCallback(() => {
2975
- setValue((x) => !x);
2976
- }, []);
2977
- return [value, toggle, setValue];
2978
- }
2979
-
2980
- const IS_SERVER = typeof window === "undefined";
2981
- function useWindowSize(options = {}) {
2982
- let { initializeWithValue = true } = options;
2983
- if (IS_SERVER) {
2984
- initializeWithValue = false;
2985
- }
2986
- const [windowSize, setWindowSize] = React.useState(() => {
2987
- if (initializeWithValue) {
2988
- return {
2989
- width: window.innerWidth,
2990
- height: window.innerHeight
2991
- };
2992
- }
2993
- return {
2994
- width: void 0,
2995
- height: void 0
2996
- };
2997
- });
2998
- const debouncedSetWindowSize = useDebounceCallback(
2999
- setWindowSize,
3000
- options.debounceDelay
3001
- );
3002
- function handleSize() {
3003
- const setSize = options.debounceDelay ? debouncedSetWindowSize : setWindowSize;
3004
- setSize({
3005
- width: window.innerWidth,
3006
- height: window.innerHeight
3007
- });
3008
- }
3009
- useEventListener("resize", handleSize);
3010
- useIsomorphicLayoutEffect(() => {
3011
- handleSize();
3012
- }, []);
3013
- return windowSize;
3014
- }
3015
-
3016
- exports.ComputedRefImpl = ComputedRefImpl;
3017
- exports.Dep = Dep;
3018
- exports.Device = Device;
3019
- exports.EffectFlags = EffectFlags;
3020
- exports.Link = Link;
3021
- exports.ReactiveFlags = ReactiveFlags;
3022
- exports.RefImpl = RefImpl;
3023
- exports.TrackOpTypes = TrackOpTypes;
3024
- exports.TriggerOpTypes = TriggerOpTypes;
3025
- exports.__DEV__ = __DEV__;
3026
- exports.batch = batch;
3027
- exports.breakpointsAntDesign = breakpointsAntDesign;
3028
- exports.breakpointsBootstrapV5 = breakpointsBootstrapV5;
3029
- exports.breakpointsSematic = breakpointsSematic;
3030
- exports.breakpointsTailwind = breakpointsTailwind;
3031
- exports.breakpointsVuetify = breakpointsVuetify;
3032
- exports.computed = computed;
3033
- exports.endBatch = endBatch;
3034
- exports.errorMessage1 = errorMessage1;
3035
- exports.extend = extend;
3036
- exports.getActiveSub = getActiveSub;
3037
- exports.isArray = isArray;
3038
- exports.isFunction = isFunction;
3039
- exports.isIntegerKey = isIntegerKey;
3040
- exports.isMap = isMap;
3041
- exports.isObject = isObject;
3042
- exports.isSymbol = isSymbol;
3043
- exports.kbdKeysMap = kbdKeysMap;
3044
- exports.ref = ref;
3045
- exports.refreshComputed = refreshComputed;
3046
- exports.setActiveSub = setActiveSub;
3047
- exports.shouldTrack = shouldTrack;
3048
- exports.startBatch = startBatch;
3049
- exports.targetMap = targetMap;
3050
- exports.track = track;
3051
- exports.useAudioRecorder = useAudioRecorder;
3052
- exports.useBattery = useBatteryHook;
3053
- exports.useBoolean = useBoolean;
3054
- exports.useBreakpoint = useBreakpoint;
3055
- exports.useClickAnyWhere = useClickAnyWhere;
3056
- exports.useClickAway = useClickAway;
3057
- exports.useComputed = useComputed;
3058
- exports.useConferenceSystem = useConferenceSystem;
3059
- exports.useCookie = useCookie;
3060
- exports.useCopyToClipboard = useCopyToClipboard;
3061
- exports.useCountdown = useCountdown;
3062
- exports.useCounter = useCounter;
3063
- exports.useDarkMode = useDarkMode;
3064
- exports.useDebounceCallback = useDebounceCallback;
3065
- exports.useDebounceValue = useDebounceValue;
3066
- exports.useDelete = useDelete;
3067
- exports.useDocumentTitle = useDocumentTitle;
3068
- exports.useEventCallback = useEventCallback;
3069
- exports.useEventListener = useEventListener;
3070
- exports.useFetch = useFetch;
3071
- exports.useForkRef = useForkRef;
3072
- exports.useGet = useGet;
3073
- exports.useHover = useHover;
3074
- exports.useIndexedDB = useIndexedDB;
3075
- exports.useIntersectionObserver = useIntersectionObserver;
3076
- exports.useInterval = useInterval;
3077
- exports.useIsClient = useIsClient;
3078
- exports.useIsMounted = useIsMounted;
3079
- exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect;
3080
- exports.useKbd = useKbd;
3081
- exports.useLocalStorage = useLocalStorage;
3082
- exports.useMap = useMap;
3083
- exports.useMediaQuality = useMediaQuality;
3084
- exports.useMediaQuery = useMediaQuery;
3085
- exports.useMediaSession = useMediaSession;
3086
- exports.useNetworkInformation = useNetworkInformation;
3087
- exports.usePost = usePost;
3088
- exports.usePut = usePut;
3089
- exports.useReactive = useReactive;
3090
- exports.useReadLocalStorage = useReadLocalStorage;
3091
- exports.useResizeObserver = useResizeObserver;
3092
- exports.useRoleGuard = useRoleGuard;
3093
- exports.useSSR = useSSR;
3094
- exports.useScreen = useScreen;
3095
- exports.useScreenShare = useScreenShare;
3096
- exports.useScript = useScript;
3097
- exports.useScrollLock = useScrollLock;
3098
- exports.useSessionStorage = useSessionStorage;
3099
- exports.useStep = useStep;
3100
- exports.useSymbol = useSymbol;
3101
- exports.useTernaryDarkMode = useTernaryDarkMode;
3102
- exports.useTimeout = useTimeout;
3103
- exports.useToggle = useToggle;
3104
- exports.useUnmount = useUnmount;
3105
- exports.useUserMedia = useUserMedia;
3106
- exports.useWindowSize = useWindowSize;
3107
- exports.weAreServer = weAreServer;
3108
- exports.withDefaults = withDefaults;