react-hook-toolkit 3.0.2 → 3.0.4
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/chunk1213/chunk158261.js +22 -22
- package/dist/chunk1415/chunk143.js +21 -25
- package/dist/chunk1516/chunk0021.d.ts +23 -3
- package/dist/chunk1516/chunk0021.js +386 -352
- package/dist/chunk1516/chunk0022.js +159 -277
- package/dist/chunk1516/chunk3312.d.ts +63 -0
- package/dist/chunk1516/chunk3312.js +462 -0
- package/dist/chunk1516/chunk726433.js +172 -206
- package/dist/chunk1516/chunk940514.js +284 -415
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/utils.js +42 -68
- package/package.json +1 -1
|
@@ -1,70 +1,14 @@
|
|
|
1
|
-
var __assign = (this && this.__assign) || function () {
|
|
2
|
-
__assign = Object.assign || function(t) {
|
|
3
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
-
s = arguments[i];
|
|
5
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
-
t[p] = s[p];
|
|
7
|
-
}
|
|
8
|
-
return t;
|
|
9
|
-
};
|
|
10
|
-
return __assign.apply(this, arguments);
|
|
11
|
-
};
|
|
12
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
13
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
14
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
15
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
16
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
17
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
18
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
22
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
23
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
24
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
25
|
-
function step(op) {
|
|
26
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
27
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
28
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
29
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
30
|
-
switch (op[0]) {
|
|
31
|
-
case 0: case 1: t = op; break;
|
|
32
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
33
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
34
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
35
|
-
default:
|
|
36
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
37
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
38
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
39
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
40
|
-
if (t[2]) _.ops.pop();
|
|
41
|
-
_.trys.pop(); continue;
|
|
42
|
-
}
|
|
43
|
-
op = body.call(thisArg, _);
|
|
44
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
45
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
49
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
50
|
-
if (ar || !(i in from)) {
|
|
51
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
52
|
-
ar[i] = from[i];
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
56
|
-
};
|
|
57
1
|
import { useState, useEffect, useCallback, useRef, useContext, createContext, useMemo } from 'react';
|
|
58
2
|
import { isReady } from './chunk940514';
|
|
59
3
|
export function useGeoLocation() {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
useEffect(
|
|
63
|
-
|
|
4
|
+
const [position, setPosition] = useState(null);
|
|
5
|
+
const [error, setError] = useState(null);
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
const success = (pos) => {
|
|
64
8
|
setPosition(pos);
|
|
65
9
|
};
|
|
66
|
-
|
|
67
|
-
setError(new Error(
|
|
10
|
+
const failure = (err) => {
|
|
11
|
+
setError(new Error(`Geolocation error: ${err.message}`));
|
|
68
12
|
};
|
|
69
13
|
if (navigator.geolocation) {
|
|
70
14
|
navigator.geolocation.getCurrentPosition(success, failure);
|
|
@@ -73,117 +17,235 @@ export function useGeoLocation() {
|
|
|
73
17
|
setError(new Error('Geolocation not supported'));
|
|
74
18
|
}
|
|
75
19
|
}, []);
|
|
76
|
-
return { position
|
|
20
|
+
return { position, error };
|
|
77
21
|
}
|
|
78
22
|
export function useTimer(initialTime) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
useEffect(
|
|
23
|
+
const [time, setTime] = useState(initialTime);
|
|
24
|
+
const [error, setError] = useState(null);
|
|
25
|
+
useEffect(() => {
|
|
82
26
|
try {
|
|
83
|
-
|
|
84
|
-
setTime(
|
|
27
|
+
const intervalId = setInterval(() => {
|
|
28
|
+
setTime((prevTime) => prevTime - 1);
|
|
85
29
|
}, 1000);
|
|
86
|
-
return
|
|
30
|
+
return () => clearInterval(intervalId);
|
|
87
31
|
}
|
|
88
32
|
catch (err) {
|
|
89
33
|
setError(err instanceof Error ? err : new Error('Failed to start timer'));
|
|
90
34
|
}
|
|
91
35
|
}, []);
|
|
92
|
-
return { time
|
|
36
|
+
return { time, error };
|
|
93
37
|
}
|
|
94
38
|
export function useIsMounted() {
|
|
95
|
-
|
|
96
|
-
useEffect(
|
|
39
|
+
const [isMounted, setIsMounted] = useState(false);
|
|
40
|
+
useEffect(() => {
|
|
97
41
|
setIsMounted(true);
|
|
98
|
-
return
|
|
42
|
+
return () => setIsMounted(false);
|
|
99
43
|
}, []);
|
|
100
44
|
return isMounted;
|
|
101
45
|
}
|
|
102
46
|
export function useCss(css) {
|
|
103
|
-
|
|
104
|
-
useEffect(
|
|
47
|
+
const [error, setError] = useState(null);
|
|
48
|
+
useEffect(() => {
|
|
105
49
|
try {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
document.head.appendChild(
|
|
109
|
-
return
|
|
110
|
-
document.head.removeChild(
|
|
50
|
+
const style = document.createElement('style');
|
|
51
|
+
style.textContent = css;
|
|
52
|
+
document.head.appendChild(style);
|
|
53
|
+
return () => {
|
|
54
|
+
document.head.removeChild(style);
|
|
111
55
|
};
|
|
112
56
|
}
|
|
113
57
|
catch (err) {
|
|
114
58
|
setError(err instanceof Error ? err : new Error('Failed to apply CSS'));
|
|
115
59
|
}
|
|
116
60
|
}, [css]);
|
|
117
|
-
return { error
|
|
61
|
+
return { error };
|
|
118
62
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
63
|
+
const IS_SUPPORTED = typeof window !== 'undefined' && 'speechSynthesis' in window;
|
|
64
|
+
export function useSpeak() {
|
|
65
|
+
const [status, setStatus] = useState('idle');
|
|
66
|
+
const [error, setError] = useState(null);
|
|
67
|
+
const isMounted = useRef(true);
|
|
68
|
+
const utteranceRef = useRef(null);
|
|
69
|
+
const callbacksRef = useRef({});
|
|
70
|
+
// ── Derived state (no extra useState) ──────────────────────
|
|
71
|
+
const isPlaying = status === 'playing';
|
|
72
|
+
const isPaused = status === 'paused';
|
|
73
|
+
// ── Mount / Unmount ────────────────────────────────────────
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
isMounted.current = true;
|
|
76
|
+
return () => {
|
|
77
|
+
var _a;
|
|
78
|
+
isMounted.current = false;
|
|
79
|
+
(_a = window.speechSynthesis) === null || _a === void 0 ? void 0 : _a.cancel();
|
|
80
|
+
utteranceRef.current = null;
|
|
81
|
+
};
|
|
82
|
+
}, []);
|
|
83
|
+
// ── Stable status setter ───────────────────────────────────
|
|
84
|
+
const safeSetStatus = useCallback((next) => {
|
|
85
|
+
if (isMounted.current)
|
|
86
|
+
setStatus(next);
|
|
87
|
+
}, []);
|
|
88
|
+
const safeSetError = useCallback((err) => {
|
|
89
|
+
if (isMounted.current)
|
|
90
|
+
setError(err);
|
|
91
|
+
}, []);
|
|
92
|
+
// ── Controls ───────────────────────────────────────────────
|
|
93
|
+
const stop = useCallback(() => {
|
|
94
|
+
var _a;
|
|
95
|
+
(_a = window.speechSynthesis) === null || _a === void 0 ? void 0 : _a.cancel();
|
|
96
|
+
safeSetStatus('idle');
|
|
97
|
+
}, [safeSetStatus]);
|
|
98
|
+
const pause = useCallback(() => {
|
|
99
|
+
var _a;
|
|
100
|
+
if (!isPlaying)
|
|
101
|
+
return;
|
|
102
|
+
(_a = window.speechSynthesis) === null || _a === void 0 ? void 0 : _a.pause();
|
|
103
|
+
safeSetStatus('paused');
|
|
104
|
+
}, [isPlaying, safeSetStatus]);
|
|
105
|
+
const resume = useCallback(() => {
|
|
106
|
+
var _a;
|
|
107
|
+
if (!isPaused)
|
|
108
|
+
return;
|
|
109
|
+
(_a = window.speechSynthesis) === null || _a === void 0 ? void 0 : _a.resume();
|
|
110
|
+
safeSetStatus('playing');
|
|
111
|
+
}, [isPaused, safeSetStatus]);
|
|
112
|
+
// ── Core speak ─────────────────────────────────────────────
|
|
113
|
+
const speak = useCallback((text, options = {}) => {
|
|
114
|
+
var _a, _b, _c, _d, _e;
|
|
115
|
+
// Guards
|
|
116
|
+
if (!IS_SUPPORTED) {
|
|
117
|
+
const err = new Error('SpeechSynthesis is not supported in this browser');
|
|
118
|
+
safeSetError(err);
|
|
119
|
+
(_a = options.onError) === null || _a === void 0 ? void 0 : _a.call(options, err);
|
|
120
|
+
return;
|
|
125
121
|
}
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
const trimmed = text === null || text === void 0 ? void 0 : text.trim();
|
|
123
|
+
if (!trimmed) {
|
|
124
|
+
const err = new Error('Text cannot be empty');
|
|
125
|
+
safeSetError(err);
|
|
126
|
+
(_b = options.onError) === null || _b === void 0 ? void 0 : _b.call(options, err);
|
|
127
|
+
return;
|
|
128
128
|
}
|
|
129
|
+
// Store latest callbacks in ref — avoids stale closure in handlers
|
|
130
|
+
callbacksRef.current = {
|
|
131
|
+
onStart: options.onStart,
|
|
132
|
+
onEnd: options.onEnd,
|
|
133
|
+
onPause: options.onPause,
|
|
134
|
+
onError: options.onError,
|
|
135
|
+
};
|
|
136
|
+
// Cancel any ongoing speech
|
|
137
|
+
window.speechSynthesis.cancel();
|
|
138
|
+
setError(null);
|
|
139
|
+
// Build utterance
|
|
140
|
+
const utterance = new SpeechSynthesisUtterance(trimmed);
|
|
141
|
+
utterance.rate = (_c = options.rate) !== null && _c !== void 0 ? _c : 1;
|
|
142
|
+
utterance.pitch = (_d = options.pitch) !== null && _d !== void 0 ? _d : 1;
|
|
143
|
+
utterance.volume = (_e = options.volume) !== null && _e !== void 0 ? _e : 1;
|
|
144
|
+
if (options.lang)
|
|
145
|
+
utterance.lang = options.lang;
|
|
146
|
+
if (options.voice)
|
|
147
|
+
utterance.voice = options.voice;
|
|
148
|
+
// ── Event handlers (read callbacks from ref — always fresh) ──
|
|
149
|
+
utterance.onstart = () => {
|
|
150
|
+
var _a, _b;
|
|
151
|
+
safeSetStatus('playing');
|
|
152
|
+
(_b = (_a = callbacksRef.current).onStart) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
153
|
+
};
|
|
154
|
+
utterance.onpause = () => {
|
|
155
|
+
var _a, _b;
|
|
156
|
+
safeSetStatus('paused');
|
|
157
|
+
(_b = (_a = callbacksRef.current).onPause) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
158
|
+
};
|
|
159
|
+
utterance.onresume = () => {
|
|
160
|
+
safeSetStatus('playing');
|
|
161
|
+
};
|
|
162
|
+
utterance.onend = () => {
|
|
163
|
+
var _a, _b;
|
|
164
|
+
safeSetStatus('ended');
|
|
165
|
+
(_b = (_a = callbacksRef.current).onEnd) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
166
|
+
utteranceRef.current = null;
|
|
167
|
+
};
|
|
168
|
+
utterance.onerror = (e) => {
|
|
169
|
+
var _a, _b;
|
|
170
|
+
// 'interrupted' fires on manual stop() — not a real error
|
|
171
|
+
if (e.error === 'interrupted' || e.error === 'canceled')
|
|
172
|
+
return;
|
|
173
|
+
const err = new Error(`Speech error: ${e.error}`);
|
|
174
|
+
safeSetStatus('error');
|
|
175
|
+
safeSetError(err);
|
|
176
|
+
(_b = (_a = callbacksRef.current).onError) === null || _b === void 0 ? void 0 : _b.call(_a, err);
|
|
177
|
+
utteranceRef.current = null;
|
|
178
|
+
};
|
|
179
|
+
utteranceRef.current = utterance;
|
|
180
|
+
window.speechSynthesis.speak(utterance);
|
|
181
|
+
}, [safeSetStatus, safeSetError]); // minimal deps — text passed at call time
|
|
182
|
+
return {
|
|
183
|
+
speak,
|
|
184
|
+
stop,
|
|
185
|
+
pause,
|
|
186
|
+
resume,
|
|
187
|
+
isPlaying,
|
|
188
|
+
isPaused,
|
|
189
|
+
status,
|
|
190
|
+
isSupported: IS_SUPPORTED,
|
|
191
|
+
error,
|
|
129
192
|
};
|
|
130
|
-
return { speak: speak, error: error };
|
|
131
193
|
}
|
|
132
194
|
export function useCountUp(target, duration) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
useEffect(
|
|
195
|
+
const [count, setCount] = useState(0);
|
|
196
|
+
const [error, setError] = useState(null);
|
|
197
|
+
useEffect(() => {
|
|
136
198
|
try {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
199
|
+
let startTime = Date.now();
|
|
200
|
+
const intervalId = setInterval(() => {
|
|
201
|
+
const elapsed = Date.now() - startTime;
|
|
140
202
|
setCount(Math.min(target, (elapsed / duration) * target));
|
|
141
203
|
if (count >= target)
|
|
142
|
-
clearInterval(
|
|
204
|
+
clearInterval(intervalId);
|
|
143
205
|
}, 1000);
|
|
144
|
-
return
|
|
206
|
+
return () => clearInterval(intervalId);
|
|
145
207
|
}
|
|
146
208
|
catch (err) {
|
|
147
209
|
setError(err instanceof Error ? err : new Error('Failed to count up'));
|
|
148
210
|
}
|
|
149
211
|
}, [target, duration]);
|
|
150
|
-
return { count
|
|
212
|
+
return { count, error };
|
|
151
213
|
}
|
|
152
214
|
export function useCountDown(start) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
useEffect(
|
|
215
|
+
const [count, setCount] = useState(start);
|
|
216
|
+
const [error, setError] = useState(null);
|
|
217
|
+
useEffect(() => {
|
|
156
218
|
try {
|
|
157
219
|
if (count <= 0)
|
|
158
220
|
return;
|
|
159
|
-
|
|
160
|
-
setCount(
|
|
221
|
+
const intervalId = setInterval(() => {
|
|
222
|
+
setCount((prevCount) => Math.max(0, prevCount - 1));
|
|
161
223
|
}, 1000);
|
|
162
|
-
return
|
|
224
|
+
return () => clearInterval(intervalId);
|
|
163
225
|
}
|
|
164
226
|
catch (err) {
|
|
165
227
|
setError(err instanceof Error ? err : new Error('Failed to start countdown'));
|
|
166
228
|
}
|
|
167
229
|
}, [count]);
|
|
168
|
-
return { count
|
|
230
|
+
return { count, error };
|
|
169
231
|
}
|
|
170
|
-
export
|
|
171
|
-
|
|
232
|
+
export const useBattery = () => {
|
|
233
|
+
const [batteryState, setBatteryState] = useState({
|
|
172
234
|
supported: true,
|
|
173
235
|
loading: true,
|
|
174
236
|
level: null,
|
|
175
237
|
charging: null,
|
|
176
238
|
chargingTime: null,
|
|
177
239
|
dischargingTime: null,
|
|
178
|
-
})
|
|
179
|
-
useEffect(
|
|
240
|
+
});
|
|
241
|
+
useEffect(() => {
|
|
180
242
|
if (!isReady()) {
|
|
181
|
-
setBatteryState(
|
|
243
|
+
setBatteryState((prevState) => (Object.assign(Object.assign({}, prevState), { supported: false, loading: false })));
|
|
182
244
|
return;
|
|
183
245
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
246
|
+
const _navigator = navigator;
|
|
247
|
+
let battery = null;
|
|
248
|
+
const handleBatteryChange = () => {
|
|
187
249
|
if (battery) {
|
|
188
250
|
setBatteryState({
|
|
189
251
|
supported: true,
|
|
@@ -195,7 +257,7 @@ export var useBattery = function () {
|
|
|
195
257
|
});
|
|
196
258
|
}
|
|
197
259
|
};
|
|
198
|
-
_navigator.getBattery().then(
|
|
260
|
+
_navigator.getBattery().then((_battery) => {
|
|
199
261
|
battery = _battery;
|
|
200
262
|
handleBatteryChange();
|
|
201
263
|
_battery.addEventListener('levelchange', handleBatteryChange);
|
|
@@ -203,7 +265,7 @@ export var useBattery = function () {
|
|
|
203
265
|
_battery.addEventListener('chargingtimechange', handleBatteryChange);
|
|
204
266
|
_battery.addEventListener('dischargingtimechange', handleBatteryChange);
|
|
205
267
|
});
|
|
206
|
-
return
|
|
268
|
+
return () => {
|
|
207
269
|
if (battery) {
|
|
208
270
|
battery.removeEventListener('levelchange', handleBatteryChange);
|
|
209
271
|
battery.removeEventListener('chargingchange', handleBatteryChange);
|
|
@@ -214,76 +276,76 @@ export var useBattery = function () {
|
|
|
214
276
|
}, []);
|
|
215
277
|
return batteryState;
|
|
216
278
|
};
|
|
217
|
-
export
|
|
218
|
-
|
|
219
|
-
useEffect(
|
|
279
|
+
export const useEventListener = (eventName, handler, elementRef, options) => {
|
|
280
|
+
const savedHandler = useRef();
|
|
281
|
+
useEffect(() => {
|
|
220
282
|
savedHandler.current = handler;
|
|
221
283
|
}, [handler]);
|
|
222
|
-
useEffect(
|
|
223
|
-
|
|
284
|
+
useEffect(() => {
|
|
285
|
+
const element = (elementRef && elementRef.current) || window;
|
|
224
286
|
if (!isReady() || !element)
|
|
225
287
|
return;
|
|
226
|
-
|
|
288
|
+
const eventListener = (event) => {
|
|
227
289
|
if (savedHandler.current) {
|
|
228
290
|
savedHandler.current(event);
|
|
229
291
|
}
|
|
230
292
|
};
|
|
231
293
|
element.addEventListener(eventName, eventListener, options);
|
|
232
|
-
return
|
|
294
|
+
return () => {
|
|
233
295
|
element.removeEventListener(eventName, eventListener, options);
|
|
234
296
|
};
|
|
235
297
|
}, [eventName, elementRef, options]);
|
|
236
298
|
};
|
|
237
|
-
export
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
299
|
+
export const useHistory = () => {
|
|
300
|
+
const [history, setHistory] = useState(window.history);
|
|
301
|
+
const [state, setState] = useState(null);
|
|
302
|
+
const push = useCallback((path, state) => {
|
|
241
303
|
if (isReady()) {
|
|
242
304
|
window.history.pushState(state, "", path);
|
|
243
305
|
setState(state || null);
|
|
244
306
|
}
|
|
245
307
|
}, []);
|
|
246
|
-
|
|
308
|
+
const replace = useCallback((path, state) => {
|
|
247
309
|
if (isReady()) {
|
|
248
310
|
window.history.replaceState(state, "", path);
|
|
249
311
|
setState(state || null);
|
|
250
312
|
}
|
|
251
313
|
}, []);
|
|
252
|
-
|
|
314
|
+
const goBack = useCallback(() => {
|
|
253
315
|
if (isReady()) {
|
|
254
316
|
window.history.back();
|
|
255
317
|
}
|
|
256
318
|
}, []);
|
|
257
|
-
|
|
319
|
+
const goForward = useCallback(() => {
|
|
258
320
|
if (isReady()) {
|
|
259
321
|
window.history.forward();
|
|
260
322
|
}
|
|
261
323
|
}, []);
|
|
262
|
-
useEffect(
|
|
263
|
-
|
|
324
|
+
useEffect(() => {
|
|
325
|
+
const handlePopState = (event) => {
|
|
264
326
|
setState(event.state || null);
|
|
265
327
|
};
|
|
266
328
|
if (isReady()) {
|
|
267
329
|
window.addEventListener("popstate", handlePopState);
|
|
268
|
-
return
|
|
330
|
+
return () => {
|
|
269
331
|
window.removeEventListener("popstate", handlePopState);
|
|
270
332
|
};
|
|
271
333
|
}
|
|
272
334
|
}, []);
|
|
273
335
|
return {
|
|
274
|
-
history
|
|
275
|
-
state
|
|
276
|
-
push
|
|
277
|
-
replace
|
|
278
|
-
goBack
|
|
279
|
-
goForward
|
|
336
|
+
history,
|
|
337
|
+
state,
|
|
338
|
+
push,
|
|
339
|
+
replace,
|
|
340
|
+
goBack,
|
|
341
|
+
goForward,
|
|
280
342
|
};
|
|
281
343
|
};
|
|
282
|
-
export
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
useEffect(
|
|
344
|
+
export const usePreferredLanguage = () => {
|
|
345
|
+
const [language, setLanguage] = useState(isReady() ? navigator.language : "");
|
|
346
|
+
const [languages, setLanguages] = useState(isReady() ? Array.from(navigator.languages) : []);
|
|
347
|
+
const [isSupported, setIsSupported] = useState(isReady() && !!navigator.language);
|
|
348
|
+
useEffect(() => {
|
|
287
349
|
if (isReady()) {
|
|
288
350
|
if (navigator.language) {
|
|
289
351
|
setLanguage(navigator.language);
|
|
@@ -302,57 +364,57 @@ export var usePreferredLanguage = function () {
|
|
|
302
364
|
}
|
|
303
365
|
}, []);
|
|
304
366
|
return {
|
|
305
|
-
language
|
|
306
|
-
languages
|
|
307
|
-
isSupported
|
|
367
|
+
language,
|
|
368
|
+
languages,
|
|
369
|
+
isSupported,
|
|
308
370
|
};
|
|
309
371
|
};
|
|
310
|
-
export
|
|
311
|
-
|
|
372
|
+
export const useSessionStorage = (key, initialValue) => {
|
|
373
|
+
const [storedValue, setStoredValue] = useState(() => {
|
|
312
374
|
if (!isReady()) {
|
|
313
375
|
return initialValue;
|
|
314
376
|
}
|
|
315
377
|
try {
|
|
316
|
-
|
|
378
|
+
const item = window.sessionStorage.getItem(key);
|
|
317
379
|
return item ? JSON.parse(item) : initialValue;
|
|
318
380
|
}
|
|
319
381
|
catch (error) {
|
|
320
|
-
console.warn(
|
|
382
|
+
console.warn(`Error reading sessionStorage key "${key}":`, error);
|
|
321
383
|
return initialValue;
|
|
322
384
|
}
|
|
323
|
-
})
|
|
324
|
-
|
|
385
|
+
});
|
|
386
|
+
const setValue = (value) => {
|
|
325
387
|
try {
|
|
326
|
-
|
|
388
|
+
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
327
389
|
setStoredValue(valueToStore);
|
|
328
390
|
if (isReady()) {
|
|
329
391
|
window.sessionStorage.setItem(key, JSON.stringify(valueToStore));
|
|
330
392
|
}
|
|
331
393
|
}
|
|
332
394
|
catch (error) {
|
|
333
|
-
console.warn(
|
|
395
|
+
console.warn(`Error setting sessionStorage key "${key}":`, error);
|
|
334
396
|
}
|
|
335
397
|
};
|
|
336
398
|
return [storedValue, setValue];
|
|
337
399
|
};
|
|
338
|
-
export
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
useEffect(
|
|
400
|
+
export const useSound = (url) => {
|
|
401
|
+
const [audio, setAudio] = useState(null);
|
|
402
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
403
|
+
const [error, setError] = useState(null);
|
|
404
|
+
useEffect(() => {
|
|
343
405
|
if (!isReady() || !window.Audio) {
|
|
344
406
|
setError(new Error("Sound is not supported in this environment."));
|
|
345
407
|
return;
|
|
346
408
|
}
|
|
347
|
-
|
|
409
|
+
const audioElement = new Audio(url);
|
|
348
410
|
setAudio(audioElement);
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
411
|
+
const handlePlay = () => setIsPlaying(true);
|
|
412
|
+
const handlePause = () => setIsPlaying(false);
|
|
413
|
+
const handleError = (e) => setError(e);
|
|
352
414
|
audioElement.addEventListener("play", handlePlay);
|
|
353
415
|
audioElement.addEventListener("pause", handlePause);
|
|
354
416
|
audioElement.addEventListener("error", handleError);
|
|
355
|
-
return
|
|
417
|
+
return () => {
|
|
356
418
|
audioElement.removeEventListener("play", handlePlay);
|
|
357
419
|
audioElement.removeEventListener("pause", handlePause);
|
|
358
420
|
audioElement.removeEventListener("error", handleError);
|
|
@@ -360,78 +422,78 @@ export var useSound = function (url) {
|
|
|
360
422
|
audioElement.currentTime = 0;
|
|
361
423
|
};
|
|
362
424
|
}, [url]);
|
|
363
|
-
|
|
425
|
+
const play = useCallback(() => {
|
|
364
426
|
if (audio) {
|
|
365
|
-
audio.play().catch(
|
|
427
|
+
audio.play().catch((e) => setError(e));
|
|
366
428
|
}
|
|
367
429
|
}, [audio]);
|
|
368
|
-
|
|
430
|
+
const pause = useCallback(() => {
|
|
369
431
|
if (audio) {
|
|
370
432
|
audio.pause();
|
|
371
433
|
}
|
|
372
434
|
}, [audio]);
|
|
373
|
-
|
|
435
|
+
const stop = useCallback(() => {
|
|
374
436
|
if (audio) {
|
|
375
437
|
audio.pause();
|
|
376
438
|
audio.currentTime = 0;
|
|
377
439
|
}
|
|
378
440
|
}, [audio]);
|
|
379
|
-
|
|
441
|
+
const setVolume = useCallback((volume) => {
|
|
380
442
|
if (audio) {
|
|
381
443
|
audio.volume = volume;
|
|
382
444
|
}
|
|
383
445
|
}, [audio]);
|
|
384
446
|
return {
|
|
385
|
-
play
|
|
386
|
-
pause
|
|
387
|
-
stop
|
|
388
|
-
setVolume
|
|
389
|
-
isPlaying
|
|
390
|
-
error
|
|
447
|
+
play,
|
|
448
|
+
pause,
|
|
449
|
+
stop,
|
|
450
|
+
setVolume,
|
|
451
|
+
isPlaying,
|
|
452
|
+
error,
|
|
391
453
|
};
|
|
392
454
|
};
|
|
393
|
-
export
|
|
394
|
-
|
|
455
|
+
export const useTouch = (elementRef) => {
|
|
456
|
+
const [touchStart, setTouchStart] = useState({
|
|
395
457
|
x: null,
|
|
396
458
|
y: null,
|
|
397
|
-
})
|
|
398
|
-
|
|
459
|
+
});
|
|
460
|
+
const [touchMove, setTouchMove] = useState({
|
|
399
461
|
x: null,
|
|
400
462
|
y: null,
|
|
401
|
-
})
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
463
|
+
});
|
|
464
|
+
const [touchEnd, setTouchEnd] = useState({ x: null, y: null });
|
|
465
|
+
const handleTouchStart = useCallback((event) => {
|
|
466
|
+
const touch = event.touches[0];
|
|
405
467
|
setTouchStart({ x: touch.clientX, y: touch.clientY });
|
|
406
468
|
}, []);
|
|
407
|
-
|
|
408
|
-
|
|
469
|
+
const handleTouchMove = useCallback((event) => {
|
|
470
|
+
const touch = event.touches[0];
|
|
409
471
|
setTouchMove({ x: touch.clientX, y: touch.clientY });
|
|
410
472
|
}, []);
|
|
411
|
-
|
|
473
|
+
const handleTouchEnd = useCallback(() => {
|
|
412
474
|
setTouchEnd(touchMove);
|
|
413
475
|
setTouchMove({ x: null, y: null });
|
|
414
476
|
setTouchStart({ x: null, y: null });
|
|
415
477
|
}, [touchMove]);
|
|
416
|
-
useEffect(
|
|
478
|
+
useEffect(() => {
|
|
417
479
|
if (!isReady() || !elementRef.current) {
|
|
418
480
|
return;
|
|
419
481
|
}
|
|
420
|
-
|
|
482
|
+
const element = elementRef.current;
|
|
421
483
|
element.addEventListener("touchstart", handleTouchStart);
|
|
422
484
|
element.addEventListener("touchmove", handleTouchMove);
|
|
423
485
|
element.addEventListener("touchend", handleTouchEnd);
|
|
424
|
-
return
|
|
486
|
+
return () => {
|
|
425
487
|
element.removeEventListener("touchstart", handleTouchStart);
|
|
426
488
|
element.removeEventListener("touchmove", handleTouchMove);
|
|
427
489
|
element.removeEventListener("touchend", handleTouchEnd);
|
|
428
490
|
};
|
|
429
491
|
}, [elementRef, handleTouchStart, handleTouchMove, handleTouchEnd]);
|
|
430
|
-
return { touchStart
|
|
492
|
+
return { touchStart, touchMove, touchEnd };
|
|
431
493
|
};
|
|
432
|
-
export
|
|
433
|
-
|
|
434
|
-
useEffect(
|
|
494
|
+
export const useUpdateEffect = (effect, deps) => {
|
|
495
|
+
const isFirstMount = useRef(true);
|
|
496
|
+
useEffect(() => {
|
|
435
497
|
if (!isReady()) {
|
|
436
498
|
return;
|
|
437
499
|
}
|
|
@@ -442,258 +504,230 @@ export var useUpdateEffect = function (effect, deps) {
|
|
|
442
504
|
return effect();
|
|
443
505
|
}, deps);
|
|
444
506
|
};
|
|
445
|
-
export
|
|
446
|
-
|
|
507
|
+
export const usePersistedForm = (key, initialValue) => {
|
|
508
|
+
const [state, setState] = useState(() => {
|
|
447
509
|
try {
|
|
448
|
-
|
|
510
|
+
const stored = localStorage.getItem(key);
|
|
449
511
|
return stored ? JSON.parse(stored) : initialValue;
|
|
450
512
|
}
|
|
451
513
|
catch (_a) {
|
|
452
514
|
return initialValue;
|
|
453
515
|
}
|
|
454
|
-
})
|
|
455
|
-
useEffect(
|
|
516
|
+
});
|
|
517
|
+
useEffect(() => {
|
|
456
518
|
localStorage.setItem(key, JSON.stringify(state));
|
|
457
519
|
}, [key, state]);
|
|
458
520
|
return [state, setState];
|
|
459
521
|
};
|
|
460
|
-
export
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
522
|
+
export const useCrossFieldValidation = (validate) => {
|
|
523
|
+
const [errors, setErrors] = useState({});
|
|
524
|
+
const validateFields = (values) => {
|
|
525
|
+
const newErrors = validate(values);
|
|
464
526
|
setErrors(newErrors);
|
|
465
|
-
return Object.values(newErrors).every(
|
|
527
|
+
return Object.values(newErrors).every((e) => !e);
|
|
466
528
|
};
|
|
467
|
-
return { errors
|
|
529
|
+
return { errors, validateFields };
|
|
468
530
|
};
|
|
469
|
-
export
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
};
|
|
476
|
-
return { fields: fields, append: append, remove: remove, update: update };
|
|
531
|
+
export const useFieldArray = (initialValue) => {
|
|
532
|
+
const [fields, setFields] = useState(initialValue);
|
|
533
|
+
const append = (item) => setFields([...fields, item]);
|
|
534
|
+
const remove = (index) => setFields(fields.filter((_, i) => i !== index));
|
|
535
|
+
const update = (index, item) => setFields(fields.map((f, i) => (i === index ? item : f)));
|
|
536
|
+
return { fields, append, remove, update };
|
|
477
537
|
};
|
|
478
|
-
export
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
setSubmitError(err_1 instanceof Error ? err_1.message : 'Submission failed');
|
|
496
|
-
return [3 /*break*/, 4];
|
|
497
|
-
case 3:
|
|
498
|
-
setIsSubmitting(false);
|
|
499
|
-
return [7 /*endfinally*/];
|
|
500
|
-
case 4: return [2 /*return*/];
|
|
501
|
-
}
|
|
502
|
-
});
|
|
503
|
-
}); };
|
|
504
|
-
return { handleSubmit: handleSubmit, isSubmitting: isSubmitting, submitError: submitError };
|
|
538
|
+
export const useFormSubmit = (handler) => {
|
|
539
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
540
|
+
const [submitError, setSubmitError] = useState(null);
|
|
541
|
+
const handleSubmit = async (data) => {
|
|
542
|
+
try {
|
|
543
|
+
setIsSubmitting(true);
|
|
544
|
+
setSubmitError(null);
|
|
545
|
+
await handler(data);
|
|
546
|
+
}
|
|
547
|
+
catch (err) {
|
|
548
|
+
setSubmitError(err instanceof Error ? err.message : 'Submission failed');
|
|
549
|
+
}
|
|
550
|
+
finally {
|
|
551
|
+
setIsSubmitting(false);
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
return { handleSubmit, isSubmitting, submitError };
|
|
505
555
|
};
|
|
506
|
-
export
|
|
507
|
-
|
|
556
|
+
export const useSmartForm = (initialValues, storageKey) => {
|
|
557
|
+
const [values, setValues] = useState(() => {
|
|
508
558
|
if (!storageKey)
|
|
509
559
|
return initialValues;
|
|
510
560
|
try {
|
|
511
|
-
|
|
561
|
+
const saved = localStorage.getItem(storageKey);
|
|
512
562
|
return saved ? JSON.parse(saved) : initialValues;
|
|
513
563
|
}
|
|
514
564
|
catch (_a) {
|
|
515
565
|
return initialValues;
|
|
516
566
|
}
|
|
517
|
-
})
|
|
518
|
-
|
|
519
|
-
useEffect(
|
|
567
|
+
});
|
|
568
|
+
const [dirty, setDirty] = useState(false);
|
|
569
|
+
useEffect(() => {
|
|
520
570
|
if (storageKey && dirty) {
|
|
521
|
-
|
|
571
|
+
const timer = setTimeout(() => {
|
|
522
572
|
localStorage.setItem(storageKey, JSON.stringify(values));
|
|
523
573
|
}, 500);
|
|
524
|
-
return
|
|
574
|
+
return () => clearTimeout(timer);
|
|
525
575
|
}
|
|
526
576
|
}, [values, storageKey, dirty]);
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
setValues(
|
|
530
|
-
var _a;
|
|
531
|
-
return (__assign(__assign({}, prev), (_a = {}, _a[name] = type === 'checkbox' ? checked : value, _a)));
|
|
532
|
-
});
|
|
577
|
+
const handleChange = (e) => {
|
|
578
|
+
const { name, value, type, checked } = e.target;
|
|
579
|
+
setValues(prev => (Object.assign(Object.assign({}, prev), { [name]: type === 'checkbox' ? checked : value })));
|
|
533
580
|
setDirty(true);
|
|
534
581
|
};
|
|
535
|
-
return { values
|
|
582
|
+
return { values, handleChange, setValues, dirty };
|
|
536
583
|
};
|
|
537
|
-
export
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
setStates(
|
|
584
|
+
export const useUndo = (initialState) => {
|
|
585
|
+
const [states, setStates] = useState([initialState]);
|
|
586
|
+
const [index, setIndex] = useState(0);
|
|
587
|
+
const present = states[index];
|
|
588
|
+
const canUndo = index > 0;
|
|
589
|
+
const canRedo = index < states.length - 1;
|
|
590
|
+
const updateState = (newState) => {
|
|
591
|
+
const newStates = states.slice(0, index + 1);
|
|
592
|
+
setStates([...newStates, newState]);
|
|
546
593
|
setIndex(newStates.length);
|
|
547
594
|
};
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
return { state: present, setState: updateState, undo
|
|
595
|
+
const undo = () => canUndo && setIndex(i => i - 1);
|
|
596
|
+
const redo = () => canRedo && setIndex(i => i + 1);
|
|
597
|
+
return { state: present, setState: updateState, undo, redo, canUndo, canRedo };
|
|
551
598
|
};
|
|
552
|
-
export
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
599
|
+
export const useFormWizard = (steps, initialValues) => {
|
|
600
|
+
const [currentStep, setCurrentStep] = useState(0);
|
|
601
|
+
const [values, setValues] = useState(initialValues);
|
|
602
|
+
const [errors, setErrors] = useState({});
|
|
603
|
+
const next = () => {
|
|
557
604
|
var _a, _b;
|
|
558
|
-
|
|
605
|
+
const validation = ((_b = (_a = steps[currentStep]).validate) === null || _b === void 0 ? void 0 : _b.call(_a, values)) || {};
|
|
559
606
|
if (Object.keys(validation).length > 0) {
|
|
560
607
|
setErrors(validation);
|
|
561
608
|
return;
|
|
562
609
|
}
|
|
563
610
|
setErrors({});
|
|
564
|
-
setCurrentStep(
|
|
611
|
+
setCurrentStep(prev => Math.min(prev + 1, steps.length - 1));
|
|
565
612
|
};
|
|
566
|
-
|
|
567
|
-
setCurrentStep(
|
|
613
|
+
const prev = () => {
|
|
614
|
+
setCurrentStep(prev => Math.max(prev - 1, 0));
|
|
568
615
|
};
|
|
569
616
|
return {
|
|
570
|
-
currentStep
|
|
617
|
+
currentStep,
|
|
571
618
|
CurrentStep: steps[currentStep].component,
|
|
572
|
-
values
|
|
573
|
-
setValues
|
|
574
|
-
next
|
|
575
|
-
prev
|
|
576
|
-
errors
|
|
619
|
+
values,
|
|
620
|
+
setValues,
|
|
621
|
+
next,
|
|
622
|
+
prev,
|
|
623
|
+
errors,
|
|
577
624
|
isFirstStep: currentStep === 0,
|
|
578
625
|
isLastStep: currentStep === steps.length - 1,
|
|
579
626
|
};
|
|
580
627
|
};
|
|
581
|
-
export
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
628
|
+
export const createOptimizedContext = () => {
|
|
629
|
+
const Context = createContext(undefined);
|
|
630
|
+
const useOptimizedContext = (selector) => {
|
|
631
|
+
const value = useContext(Context);
|
|
585
632
|
if (value === undefined)
|
|
586
633
|
throw new Error('Missing provider');
|
|
587
|
-
return useMemo(
|
|
634
|
+
return useMemo(() => selector(value), [value, selector]);
|
|
588
635
|
};
|
|
589
636
|
return [Context.Provider, useOptimizedContext];
|
|
590
637
|
};
|
|
591
|
-
export
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
638
|
+
export const useWebSocket = (url, onMessage) => {
|
|
639
|
+
const [data, setData] = useState(null);
|
|
640
|
+
const [isConnected, setIsConnected] = useState(false);
|
|
641
|
+
const [socket, setSocket] = useState(null);
|
|
642
|
+
const send = useCallback((message) => {
|
|
596
643
|
if ((socket === null || socket === void 0 ? void 0 : socket.readyState) === WebSocket.OPEN) {
|
|
597
644
|
socket.send(JSON.stringify(message));
|
|
598
645
|
}
|
|
599
646
|
}, [socket]);
|
|
600
|
-
useEffect(
|
|
601
|
-
|
|
647
|
+
useEffect(() => {
|
|
648
|
+
const ws = new WebSocket(url);
|
|
602
649
|
setSocket(ws);
|
|
603
|
-
ws.onopen =
|
|
604
|
-
ws.onclose =
|
|
605
|
-
ws.onmessage =
|
|
606
|
-
|
|
650
|
+
ws.onopen = () => setIsConnected(true);
|
|
651
|
+
ws.onclose = () => setIsConnected(false);
|
|
652
|
+
ws.onmessage = (event) => {
|
|
653
|
+
const newData = JSON.parse(event.data);
|
|
607
654
|
setData(newData);
|
|
608
655
|
onMessage === null || onMessage === void 0 ? void 0 : onMessage(newData);
|
|
609
656
|
};
|
|
610
|
-
return
|
|
657
|
+
return () => ws.close();
|
|
611
658
|
}, [url, onMessage]);
|
|
612
|
-
return { data
|
|
659
|
+
return { data, send, isConnected };
|
|
613
660
|
};
|
|
614
|
-
export
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
661
|
+
export const useDragReorder = (initialItems) => {
|
|
662
|
+
const [items, setItems] = useState(initialItems);
|
|
663
|
+
const dragItem = useRef(null);
|
|
664
|
+
const dragOverItem = useRef(null);
|
|
665
|
+
const handleDragStart = (index) => {
|
|
619
666
|
dragItem.current = index;
|
|
620
667
|
};
|
|
621
|
-
|
|
668
|
+
const handleDragEnter = (index) => {
|
|
622
669
|
dragOverItem.current = index;
|
|
623
670
|
};
|
|
624
|
-
|
|
671
|
+
const handleDrop = () => {
|
|
625
672
|
if (dragItem.current === null || dragOverItem.current === null)
|
|
626
673
|
return;
|
|
627
|
-
|
|
628
|
-
|
|
674
|
+
const newItems = [...items];
|
|
675
|
+
const draggedItem = newItems[dragItem.current];
|
|
629
676
|
newItems.splice(dragItem.current, 1);
|
|
630
677
|
newItems.splice(dragOverItem.current, 0, draggedItem);
|
|
631
678
|
setItems(newItems);
|
|
632
679
|
dragItem.current = null;
|
|
633
680
|
dragOverItem.current = null;
|
|
634
681
|
};
|
|
635
|
-
return { items
|
|
682
|
+
return { items, handleDragStart, handleDragEnter, handleDrop };
|
|
636
683
|
};
|
|
637
|
-
export
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
var lastElementRef = useCallback(function (node) {
|
|
684
|
+
export const useInfiniteScroll = (fetchData, initialData = []) => {
|
|
685
|
+
const [data, setData] = useState(initialData);
|
|
686
|
+
const [page, setPage] = useState(1);
|
|
687
|
+
const [loading, setLoading] = useState(false);
|
|
688
|
+
const [hasMore, setHasMore] = useState(true);
|
|
689
|
+
const observer = useRef();
|
|
690
|
+
const lastElementRef = useCallback((node) => {
|
|
645
691
|
if (loading)
|
|
646
692
|
return;
|
|
647
693
|
if (observer.current)
|
|
648
694
|
observer.current.disconnect();
|
|
649
|
-
observer.current = new IntersectionObserver(
|
|
695
|
+
observer.current = new IntersectionObserver(entries => {
|
|
650
696
|
if (entries[0].isIntersecting && hasMore) {
|
|
651
|
-
setPage(
|
|
697
|
+
setPage(prev => prev + 1);
|
|
652
698
|
}
|
|
653
699
|
});
|
|
654
700
|
if (node)
|
|
655
701
|
observer.current.observe(node);
|
|
656
702
|
}, [loading, hasMore]);
|
|
657
|
-
useEffect(
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
newData_1 = _a.sent();
|
|
670
|
-
setData(function (prev) { return __spreadArray(__spreadArray([], prev, true), newData_1, true); });
|
|
671
|
-
setHasMore(newData_1.length > 0);
|
|
672
|
-
return [3 /*break*/, 4];
|
|
673
|
-
case 3:
|
|
674
|
-
setLoading(false);
|
|
675
|
-
return [7 /*endfinally*/];
|
|
676
|
-
case 4: return [2 /*return*/];
|
|
677
|
-
}
|
|
678
|
-
});
|
|
679
|
-
}); };
|
|
703
|
+
useEffect(() => {
|
|
704
|
+
const loadData = async () => {
|
|
705
|
+
setLoading(true);
|
|
706
|
+
try {
|
|
707
|
+
const newData = await fetchData(page);
|
|
708
|
+
setData(prev => [...prev, ...newData]);
|
|
709
|
+
setHasMore(newData.length > 0);
|
|
710
|
+
}
|
|
711
|
+
finally {
|
|
712
|
+
setLoading(false);
|
|
713
|
+
}
|
|
714
|
+
};
|
|
680
715
|
loadData();
|
|
681
716
|
}, [page, fetchData]);
|
|
682
|
-
return { data
|
|
717
|
+
return { data, loading, hasMore, lastElementRef };
|
|
683
718
|
};
|
|
684
|
-
export
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
useEffect(function () {
|
|
719
|
+
export const useEventListeners = (eventType, handler, element = window, options) => {
|
|
720
|
+
const savedHandler = useRef(handler);
|
|
721
|
+
useEffect(() => {
|
|
688
722
|
savedHandler.current = handler;
|
|
689
723
|
}, [handler]);
|
|
690
|
-
useEffect(
|
|
691
|
-
|
|
724
|
+
useEffect(() => {
|
|
725
|
+
const isSupported = element && element.addEventListener;
|
|
692
726
|
if (!isSupported)
|
|
693
727
|
return;
|
|
694
|
-
|
|
728
|
+
const listener = (event) => savedHandler.current(event);
|
|
695
729
|
element.addEventListener(eventType, listener, options);
|
|
696
|
-
return
|
|
730
|
+
return () => {
|
|
697
731
|
element.removeEventListener(eventType, listener, options);
|
|
698
732
|
};
|
|
699
733
|
}, [eventType, element, options]);
|