funda-ui 4.7.171 → 4.7.181
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/LiveSearch/index.d.ts +1 -0
- package/LiveSearch/index.js +7 -5
- package/MultipleCheckboxes/index.d.ts +24 -0
- package/MultipleCheckboxes/index.js +105 -14
- package/README.md +1 -1
- package/Select/index.d.ts +1 -0
- package/Select/index.js +8 -6
- package/Tree/index.css +5 -0
- package/Tree/index.d.ts +15 -3
- package/Tree/index.js +449 -208
- package/Utils/useHistoryTracker.d.ts +155 -15
- package/Utils/useHistoryTracker.js +262 -88
- package/lib/cjs/LiveSearch/index.d.ts +1 -0
- package/lib/cjs/LiveSearch/index.js +7 -5
- package/lib/cjs/MultipleCheckboxes/index.d.ts +24 -0
- package/lib/cjs/MultipleCheckboxes/index.js +105 -14
- package/lib/cjs/Select/index.d.ts +1 -0
- package/lib/cjs/Select/index.js +8 -6
- package/lib/cjs/Tree/index.d.ts +15 -3
- package/lib/cjs/Tree/index.js +449 -208
- package/lib/cjs/Utils/useHistoryTracker.d.ts +155 -15
- package/lib/cjs/Utils/useHistoryTracker.js +262 -88
- package/lib/css/Tree/index.css +5 -0
- package/lib/esm/LiveSearch/index.tsx +14 -6
- package/lib/esm/MultipleCheckboxes/index.tsx +350 -215
- package/lib/esm/Select/index.tsx +23 -7
- package/lib/esm/Tree/TreeList.tsx +114 -130
- package/lib/esm/Tree/index.scss +10 -12
- package/lib/esm/Tree/index.tsx +253 -68
- package/lib/esm/Tree/init-height.tsx +14 -1
- package/lib/esm/Utils/hooks/useHistoryTracker.tsx +266 -115
- package/package.json +1 -1
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* History Tracker
|
|
3
|
+
* @since 20250515
|
|
3
4
|
*
|
|
4
5
|
* @usage:
|
|
5
6
|
|
|
6
7
|
const App = () => {
|
|
7
8
|
const {
|
|
8
|
-
|
|
9
|
-
forwardHistory,
|
|
10
|
-
currentUrl,
|
|
11
|
-
firstUrl,
|
|
9
|
+
getReady,
|
|
12
10
|
clearHistory,
|
|
13
|
-
goBack
|
|
11
|
+
goBack,
|
|
12
|
+
getFirstUrl,
|
|
13
|
+
getCurrentUrl,
|
|
14
|
+
getForwardHistory,
|
|
15
|
+
getHistory,
|
|
14
16
|
} = useHistoryTracker({
|
|
15
17
|
onChange: ({
|
|
16
18
|
isReady,
|
|
@@ -41,32 +43,50 @@ const App = () => {
|
|
|
41
43
|
}
|
|
42
44
|
});
|
|
43
45
|
|
|
46
|
+
// useEffect(() => {
|
|
47
|
+
// console.log(getReady(), getFirstUrl(), getCurrentUrl(), getForwardHistory(), getHistory());
|
|
48
|
+
// }, [getReady, getFirstUrl, getCurrentUrl]);
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
// useEffect(() => {
|
|
52
|
+
// setTimeout(async () => {
|
|
53
|
+
// console.log('--> clean history within 2m');
|
|
54
|
+
// await clearHistory();
|
|
55
|
+
// }, 2000);
|
|
56
|
+
// }, []);
|
|
57
|
+
|
|
58
|
+
|
|
44
59
|
return (
|
|
45
60
|
<div>
|
|
46
61
|
|
|
62
|
+
<div>
|
|
63
|
+
<h3>isReady:</h3>
|
|
64
|
+
<p>{String(getReady())}</p>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
47
67
|
<div>
|
|
48
68
|
<h3>First URL:</h3>
|
|
49
|
-
<p>{
|
|
69
|
+
<p>{getFirstUrl()}</p>
|
|
50
70
|
</div>
|
|
51
71
|
|
|
52
72
|
<div>
|
|
53
73
|
<h3>Current URL:</h3>
|
|
54
|
-
<p>{
|
|
74
|
+
<p>{getCurrentUrl()}</p>
|
|
55
75
|
</div>
|
|
56
76
|
|
|
57
77
|
<div>
|
|
58
|
-
<h3>History ({
|
|
78
|
+
<h3>History ({getHistory().length}):</h3>
|
|
59
79
|
<ul>
|
|
60
|
-
{
|
|
80
|
+
{getHistory().map((url, index) => (
|
|
61
81
|
<li key={index}>{url}</li>
|
|
62
82
|
))}
|
|
63
83
|
</ul>
|
|
64
84
|
</div>
|
|
65
85
|
|
|
66
86
|
<div>
|
|
67
|
-
<h3>Forward History ({
|
|
87
|
+
<h3>Forward History ({getForwardHistory().length}):</h3>
|
|
68
88
|
<ul>
|
|
69
|
-
{
|
|
89
|
+
{getForwardHistory().map((url, index) => (
|
|
70
90
|
<li key={index}>{url}</li>
|
|
71
91
|
))}
|
|
72
92
|
</ul>
|
|
@@ -116,89 +136,91 @@ const App = () => {
|
|
|
116
136
|
};
|
|
117
137
|
|
|
118
138
|
*/
|
|
139
|
+
|
|
119
140
|
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
120
141
|
|
|
121
|
-
export
|
|
142
|
+
export interface HistoryTrackerChange {
|
|
122
143
|
isReady: boolean;
|
|
123
144
|
history: string[];
|
|
124
|
-
forwardHistory: string[]
|
|
145
|
+
forwardHistory: string[];
|
|
125
146
|
currentUrl: string;
|
|
126
147
|
firstUrl: string;
|
|
127
148
|
canGoBack: boolean;
|
|
128
149
|
canGoForward: boolean;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface UseHistoryTrackerProps {
|
|
153
|
+
onChange?: (data: HistoryTrackerChange) => void;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface UseHistoryTrackerReturn {
|
|
157
|
+
getReady: () => boolean;
|
|
158
|
+
getHistory: () => string[];
|
|
159
|
+
getForwardHistory: () => string[];
|
|
160
|
+
getCurrentUrl: () => string;
|
|
161
|
+
getFirstUrl: () => string;
|
|
162
|
+
clearHistory: () => Promise<HistoryTrackerChange>;
|
|
163
|
+
goToHistory: (index: number) => void;
|
|
164
|
+
goBack: () => Promise<HistoryTrackerChange>;
|
|
165
|
+
goForward: () => Promise<HistoryTrackerChange>;
|
|
166
|
+
canGoBack: () => boolean;
|
|
167
|
+
canGoForward: () => boolean;
|
|
168
|
+
addHistoryToFirst: (url: string) => Promise<HistoryTrackerChange>;
|
|
169
|
+
}
|
|
135
170
|
|
|
136
171
|
// Create a secure version of useLayoutEffect that is downgraded to useEffect when SSR
|
|
137
172
|
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
|
138
173
|
|
|
139
|
-
const useHistoryTracker = (props
|
|
174
|
+
const useHistoryTracker = (props?: UseHistoryTrackerProps): UseHistoryTrackerReturn => {
|
|
140
175
|
const {
|
|
141
176
|
onChange
|
|
142
|
-
} = props;
|
|
177
|
+
} = props || {};
|
|
143
178
|
|
|
144
179
|
const [isReady, setIsReady] = useState<boolean>(false);
|
|
145
180
|
const historyRef = useRef<string[]>([]);
|
|
146
181
|
const forwardHistoryRef = useRef<string[]>([]);
|
|
147
182
|
const firstUrlRef = useRef<string>('');
|
|
148
183
|
const [currentUrl, setCurrentUrl] = useState<string>('');
|
|
149
|
-
|
|
150
|
-
const
|
|
184
|
+
|
|
185
|
+
const canGoBack = useCallback((): boolean => {
|
|
186
|
+
return historyRef.current.length > 1;
|
|
187
|
+
}, []);
|
|
188
|
+
|
|
189
|
+
const canGoForward = useCallback((): boolean => {
|
|
190
|
+
return forwardHistoryRef.current.length > 0;
|
|
191
|
+
}, []);
|
|
192
|
+
|
|
193
|
+
const initialize = useCallback((ready: boolean = false): void => {
|
|
151
194
|
if (typeof window === 'undefined') return;
|
|
152
195
|
|
|
153
|
-
const currentLocation = window.location.href
|
|
154
|
-
|
|
196
|
+
const currentLocation = window.location.href;
|
|
197
|
+
|
|
155
198
|
// If the history is empty, set the first record
|
|
156
199
|
if (historyRef.current.length === 0) {
|
|
157
200
|
firstUrlRef.current = currentLocation;
|
|
158
201
|
historyRef.current = [currentLocation];
|
|
159
202
|
setCurrentUrl(currentLocation);
|
|
160
203
|
|
|
161
|
-
onChange
|
|
162
|
-
isReady:
|
|
204
|
+
onChange && onChange({
|
|
205
|
+
isReady: ready,
|
|
163
206
|
history: [currentLocation],
|
|
164
207
|
forwardHistory: [],
|
|
165
208
|
currentUrl: currentLocation,
|
|
166
209
|
firstUrl: currentLocation,
|
|
167
210
|
canGoBack: false,
|
|
168
|
-
canGoForward: false
|
|
211
|
+
canGoForward: false,
|
|
169
212
|
});
|
|
170
213
|
|
|
171
214
|
}
|
|
172
215
|
|
|
173
216
|
setIsReady(true);
|
|
174
|
-
}, []);
|
|
217
|
+
}, [onChange]);
|
|
175
218
|
|
|
176
219
|
useIsomorphicLayoutEffect(() => {
|
|
177
220
|
initialize();
|
|
178
221
|
}, [initialize]);
|
|
179
222
|
|
|
180
|
-
|
|
181
|
-
const clearHistory = useCallback(() => {
|
|
182
|
-
if (typeof window === 'undefined') return;
|
|
183
|
-
|
|
184
|
-
historyRef.current = [];
|
|
185
|
-
forwardHistoryRef.current = [];
|
|
186
|
-
firstUrlRef.current = '';
|
|
187
|
-
setCurrentUrl('');
|
|
188
|
-
|
|
189
|
-
onChange?.({
|
|
190
|
-
isReady: true,
|
|
191
|
-
history: [],
|
|
192
|
-
forwardHistory: [],
|
|
193
|
-
currentUrl: '',
|
|
194
|
-
firstUrl: '',
|
|
195
|
-
canGoBack: false,
|
|
196
|
-
canGoForward: false
|
|
197
|
-
|
|
198
|
-
});
|
|
199
|
-
}, [onChange]); // only "onChange"
|
|
200
|
-
|
|
201
|
-
const goToHistory = useCallback((index: number) => {
|
|
223
|
+
const goToHistory = useCallback((index: number): void => {
|
|
202
224
|
if (typeof window === 'undefined') return;
|
|
203
225
|
if (index < 0 || index >= historyRef.current.length) return;
|
|
204
226
|
|
|
@@ -208,20 +230,21 @@ const useHistoryTracker = (props: UseHistoryTrackerProps) => {
|
|
|
208
230
|
}
|
|
209
231
|
}, []);
|
|
210
232
|
|
|
211
|
-
const goBack = useCallback(() => {
|
|
233
|
+
const goBack = useCallback((): Promise<HistoryTrackerChange> => {
|
|
212
234
|
if (typeof window === 'undefined') return Promise.reject('Window is undefined');
|
|
213
|
-
if (historyRef.current.length <= 1) return Promise.reject('
|
|
235
|
+
if (historyRef.current.length <= 1) return Promise.reject('History does not meet the criteria (total records are less than 2), cannot go back');
|
|
214
236
|
|
|
215
237
|
return new Promise((resolve) => {
|
|
216
238
|
// Moves the current URL into the forward history
|
|
217
|
-
const removedUrl = historyRef.current.pop()
|
|
218
|
-
|
|
219
|
-
|
|
239
|
+
const removedUrl = historyRef.current.pop();
|
|
240
|
+
if (removedUrl) {
|
|
241
|
+
forwardHistoryRef.current.push(removedUrl);
|
|
242
|
+
}
|
|
220
243
|
const newCurrentUrl = historyRef.current[historyRef.current.length - 1];
|
|
221
244
|
setCurrentUrl(newCurrentUrl);
|
|
222
245
|
|
|
223
246
|
// Create initial data object
|
|
224
|
-
const data = {
|
|
247
|
+
const data: HistoryTrackerChange = {
|
|
225
248
|
isReady: true,
|
|
226
249
|
history: [...historyRef.current],
|
|
227
250
|
forwardHistory: [...forwardHistoryRef.current],
|
|
@@ -232,7 +255,7 @@ const useHistoryTracker = (props: UseHistoryTrackerProps) => {
|
|
|
232
255
|
};
|
|
233
256
|
|
|
234
257
|
// Notify about the history change
|
|
235
|
-
onChange
|
|
258
|
+
onChange && onChange(data);
|
|
236
259
|
|
|
237
260
|
// Create one-time listener for popstate
|
|
238
261
|
const handlePopState = () => {
|
|
@@ -240,7 +263,7 @@ const useHistoryTracker = (props: UseHistoryTrackerProps) => {
|
|
|
240
263
|
window.removeEventListener('popstate', handlePopState);
|
|
241
264
|
|
|
242
265
|
// Get the final data after URL has changed
|
|
243
|
-
const finalData = {
|
|
266
|
+
const finalData: HistoryTrackerChange = {
|
|
244
267
|
isReady: true,
|
|
245
268
|
history: [...historyRef.current],
|
|
246
269
|
forwardHistory: [...forwardHistoryRef.current],
|
|
@@ -259,30 +282,32 @@ const useHistoryTracker = (props: UseHistoryTrackerProps) => {
|
|
|
259
282
|
// Trigger the navigation
|
|
260
283
|
window.history.go(-1);
|
|
261
284
|
});
|
|
262
|
-
}, [onChange]);
|
|
285
|
+
}, [onChange, canGoBack, canGoForward]);
|
|
263
286
|
|
|
264
|
-
const goForward = useCallback(() => {
|
|
287
|
+
const goForward = useCallback((): Promise<HistoryTrackerChange> => {
|
|
265
288
|
if (typeof window === 'undefined') return Promise.reject('Window is undefined');
|
|
266
|
-
if (forwardHistoryRef.current.length === 0) return Promise.reject('
|
|
289
|
+
if (forwardHistoryRef.current.length === 0) return Promise.reject('Forward history does not meet the criteria (total 0 records), cannot go forward');
|
|
267
290
|
|
|
268
291
|
return new Promise((resolve) => {
|
|
269
292
|
// Take the URL from the forward history and add it to the main history
|
|
270
|
-
const nextUrl = forwardHistoryRef.current.pop()
|
|
271
|
-
|
|
272
|
-
|
|
293
|
+
const nextUrl = forwardHistoryRef.current.pop();
|
|
294
|
+
if (nextUrl) {
|
|
295
|
+
historyRef.current.push(nextUrl);
|
|
296
|
+
setCurrentUrl(nextUrl);
|
|
297
|
+
}
|
|
273
298
|
|
|
274
299
|
// Create initial data object
|
|
275
|
-
const data = {
|
|
300
|
+
const data: HistoryTrackerChange = {
|
|
276
301
|
isReady: true,
|
|
277
302
|
history: [...historyRef.current],
|
|
278
303
|
forwardHistory: [...forwardHistoryRef.current],
|
|
279
|
-
currentUrl: nextUrl,
|
|
304
|
+
currentUrl: nextUrl || '',
|
|
280
305
|
firstUrl: firstUrlRef.current,
|
|
281
306
|
canGoBack: canGoBack(),
|
|
282
307
|
canGoForward: canGoForward()
|
|
283
308
|
};
|
|
284
309
|
|
|
285
|
-
onChange
|
|
310
|
+
onChange && onChange(data);
|
|
286
311
|
|
|
287
312
|
// Create one-time listener for popstate
|
|
288
313
|
const handlePopState = () => {
|
|
@@ -290,7 +315,7 @@ const useHistoryTracker = (props: UseHistoryTrackerProps) => {
|
|
|
290
315
|
window.removeEventListener('popstate', handlePopState);
|
|
291
316
|
|
|
292
317
|
// Get the final data after URL has changed
|
|
293
|
-
const finalData = {
|
|
318
|
+
const finalData: HistoryTrackerChange = {
|
|
294
319
|
isReady: true,
|
|
295
320
|
history: [...historyRef.current],
|
|
296
321
|
forwardHistory: [...forwardHistoryRef.current],
|
|
@@ -309,47 +334,144 @@ const useHistoryTracker = (props: UseHistoryTrackerProps) => {
|
|
|
309
334
|
// Trigger the navigation
|
|
310
335
|
window.history.go(1);
|
|
311
336
|
});
|
|
312
|
-
}, [onChange]);
|
|
337
|
+
}, [onChange, canGoBack, canGoForward]);
|
|
313
338
|
|
|
314
|
-
const
|
|
315
|
-
return historyRef.current.length > 1;
|
|
316
|
-
}, []);
|
|
317
|
-
|
|
318
|
-
const canGoForward = useCallback(() => {
|
|
319
|
-
return forwardHistoryRef.current.length > 0;
|
|
320
|
-
}, []);
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
const handleUrlChange = useCallback(() => {
|
|
339
|
+
const handleUrlChange = useCallback((): void => {
|
|
324
340
|
if (typeof window === 'undefined') return;
|
|
325
341
|
|
|
326
342
|
const newUrl = window.location.href;
|
|
327
|
-
|
|
328
|
-
// If the history is empty, set
|
|
343
|
+
|
|
344
|
+
// If the history is empty, set the first record
|
|
329
345
|
if (historyRef.current.length === 0) {
|
|
330
346
|
firstUrlRef.current = newUrl;
|
|
331
347
|
}
|
|
332
348
|
|
|
333
|
-
//
|
|
334
|
-
|
|
349
|
+
// Check whether it is back
|
|
350
|
+
const isBackOperation = historyRef.current.length > 1 &&
|
|
351
|
+
historyRef.current[historyRef.current.length - 2] === newUrl;
|
|
352
|
+
|
|
353
|
+
// Check whether it is forward
|
|
354
|
+
const isForwardOperation = forwardHistoryRef.current.length > 0 &&
|
|
355
|
+
forwardHistoryRef.current[forwardHistoryRef.current.length - 1] === newUrl;
|
|
356
|
+
|
|
357
|
+
if (isBackOperation) {
|
|
358
|
+
// If it is a rollback, remove the last URL and add it to forwardHistory
|
|
359
|
+
const removedUrl = historyRef.current.pop();
|
|
360
|
+
if (removedUrl) {
|
|
361
|
+
forwardHistoryRef.current.push(removedUrl);
|
|
362
|
+
}
|
|
363
|
+
} else if (isForwardOperation) {
|
|
364
|
+
// If it is a forward operation, take out the URL from forwardHistory and add it to history
|
|
365
|
+
const nextUrl = forwardHistoryRef.current.pop();
|
|
366
|
+
if (nextUrl) {
|
|
367
|
+
historyRef.current.push(nextUrl);
|
|
368
|
+
}
|
|
369
|
+
} else if (historyRef.current[historyRef.current.length - 1] !== newUrl) {
|
|
370
|
+
// If it's a new navigation, add to history and clear forwardHistory
|
|
335
371
|
historyRef.current.push(newUrl);
|
|
336
|
-
|
|
337
|
-
// Clear the advance history, as new navigation invalidates the advance history
|
|
338
372
|
forwardHistoryRef.current = [];
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
setCurrentUrl(newUrl);
|
|
376
|
+
|
|
377
|
+
onChange && onChange({
|
|
378
|
+
isReady: true,
|
|
379
|
+
history: [...historyRef.current],
|
|
380
|
+
forwardHistory: [...forwardHistoryRef.current],
|
|
381
|
+
currentUrl: newUrl,
|
|
382
|
+
firstUrl: firstUrlRef.current || newUrl,
|
|
383
|
+
canGoBack: canGoBack(),
|
|
384
|
+
canGoForward: canGoForward()
|
|
385
|
+
});
|
|
386
|
+
}, [onChange, canGoBack, canGoForward]);
|
|
387
|
+
|
|
388
|
+
// Create a wrapper for history methods
|
|
389
|
+
const createHistoryWrapper = useCallback(<T extends (...args: any[]) => any>(originalMethod: T): T => {
|
|
390
|
+
return function(this: History, ...args: Parameters<T>): ReturnType<T> {
|
|
391
|
+
const result = originalMethod.apply(this, args);
|
|
392
|
+
handleUrlChange();
|
|
393
|
+
return result;
|
|
394
|
+
} as T;
|
|
395
|
+
}, [handleUrlChange]);
|
|
396
|
+
|
|
397
|
+
const getFirstUrl = useCallback((): string => {
|
|
398
|
+
return firstUrlRef.current;
|
|
399
|
+
}, []);
|
|
400
|
+
|
|
401
|
+
const getCurrentUrl = useCallback((): string => {
|
|
402
|
+
return currentUrl;
|
|
403
|
+
}, [currentUrl]);
|
|
404
|
+
|
|
405
|
+
const getForwardHistory = useCallback((): string[] => {
|
|
406
|
+
return forwardHistoryRef.current;
|
|
407
|
+
}, []);
|
|
408
|
+
|
|
409
|
+
const getHistory = useCallback((): string[] => {
|
|
410
|
+
return historyRef.current;
|
|
411
|
+
}, []);
|
|
412
|
+
|
|
413
|
+
const getReady = useCallback((): boolean => {
|
|
414
|
+
return isReady;
|
|
415
|
+
}, [isReady]);
|
|
416
|
+
|
|
417
|
+
const addHistoryToFirst = useCallback(async (url: string): Promise<HistoryTrackerChange> => {
|
|
418
|
+
if (typeof window === 'undefined') return Promise.reject('Window is undefined');
|
|
419
|
+
if (!url) return Promise.reject('URL does not exist');
|
|
420
|
+
|
|
421
|
+
return new Promise((resolve) => {
|
|
422
|
+
if (historyRef.current.length === 0) {
|
|
423
|
+
firstUrlRef.current = url;
|
|
424
|
+
historyRef.current = [url];
|
|
425
|
+
setCurrentUrl(url);
|
|
426
|
+
} else {
|
|
427
|
+
// Insert at the front
|
|
428
|
+
historyRef.current = [url, ...historyRef.current];
|
|
429
|
+
firstUrlRef.current = url;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const result: HistoryTrackerChange = {
|
|
342
433
|
isReady: true,
|
|
343
434
|
history: [...historyRef.current],
|
|
344
435
|
forwardHistory: [...forwardHistoryRef.current],
|
|
345
|
-
currentUrl:
|
|
346
|
-
firstUrl: firstUrlRef.current
|
|
436
|
+
currentUrl: currentUrl || url,
|
|
437
|
+
firstUrl: firstUrlRef.current,
|
|
347
438
|
canGoBack: canGoBack(),
|
|
348
439
|
canGoForward: canGoForward()
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
onChange && onChange(result);
|
|
443
|
+
resolve(result);
|
|
444
|
+
});
|
|
445
|
+
}, [onChange, currentUrl, canGoBack, canGoForward]);
|
|
446
|
+
|
|
447
|
+
const clearHistory = useCallback(async (): Promise<HistoryTrackerChange> => {
|
|
448
|
+
if (typeof window === 'undefined') return Promise.reject('Window is undefined');
|
|
449
|
+
|
|
450
|
+
return new Promise((resolve) => {
|
|
451
|
+
historyRef.current = [];
|
|
452
|
+
forwardHistoryRef.current = [];
|
|
453
|
+
firstUrlRef.current = '';
|
|
454
|
+
setCurrentUrl('');
|
|
352
455
|
|
|
456
|
+
const result: HistoryTrackerChange = {
|
|
457
|
+
isReady: true,
|
|
458
|
+
history: [],
|
|
459
|
+
forwardHistory: [],
|
|
460
|
+
currentUrl: '',
|
|
461
|
+
firstUrl: '',
|
|
462
|
+
canGoBack: false,
|
|
463
|
+
canGoForward: false
|
|
464
|
+
};
|
|
465
|
+
onChange && onChange(result);
|
|
466
|
+
|
|
467
|
+
// After clearHistory(), immediately take the current url as the first history
|
|
468
|
+
// !!!Fixed: "There is still only 1 record of goBack(), and there is no cumulative forward record"
|
|
469
|
+
setTimeout(() => {
|
|
470
|
+
initialize(true);
|
|
471
|
+
resolve(result);
|
|
472
|
+
}, 0);
|
|
473
|
+
});
|
|
474
|
+
}, [onChange, initialize]);
|
|
353
475
|
|
|
354
476
|
useEffect(() => {
|
|
355
477
|
if (typeof window === 'undefined') return;
|
|
@@ -360,43 +482,72 @@ const useHistoryTracker = (props: UseHistoryTrackerProps) => {
|
|
|
360
482
|
// Listen for hashchange events
|
|
361
483
|
window.addEventListener('hashchange', handleUrlChange);
|
|
362
484
|
|
|
363
|
-
//
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
485
|
+
// !!!Fixed: "Reinitialize the history, but this will not cause the URL to change either"
|
|
486
|
+
|
|
487
|
+
// Store original methods (Just save the reference, don't modify the global)
|
|
488
|
+
const originalPushState = window.history.pushState.bind(window.history);
|
|
489
|
+
const originalReplaceState = window.history.replaceState.bind(window.history);
|
|
490
|
+
const originalGo = window.history.go.bind(window.history);
|
|
491
|
+
|
|
492
|
+
// Create wrapped versions of history methods
|
|
493
|
+
const wrappedPushState = createHistoryWrapper(originalPushState);
|
|
494
|
+
const wrappedReplaceState = createHistoryWrapper(originalReplaceState);
|
|
495
|
+
const wrappedGo = createHistoryWrapper(originalGo);
|
|
496
|
+
|
|
497
|
+
// Create a proxy for history object
|
|
498
|
+
const historyProxy = new Proxy(window.history, {
|
|
499
|
+
get: function(target: History, prop: string | symbol) {
|
|
500
|
+
if (prop === 'pushState') {
|
|
501
|
+
return wrappedPushState;
|
|
368
502
|
}
|
|
369
|
-
|
|
503
|
+
if (prop === 'replaceState') {
|
|
504
|
+
return wrappedReplaceState;
|
|
505
|
+
}
|
|
506
|
+
if (prop === 'go') {
|
|
507
|
+
return wrappedGo;
|
|
508
|
+
}
|
|
509
|
+
return target[prop as keyof History];
|
|
510
|
+
}
|
|
370
511
|
});
|
|
371
512
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
attributeFilter: ['href'] // only monitor changes in the href attribute
|
|
513
|
+
// Replace window.history with our proxy
|
|
514
|
+
Object.defineProperty(window, 'history', {
|
|
515
|
+
value: historyProxy,
|
|
516
|
+
writable: true,
|
|
517
|
+
configurable: true
|
|
378
518
|
});
|
|
379
519
|
|
|
380
520
|
return () => {
|
|
381
521
|
window.removeEventListener('popstate', handleUrlChange);
|
|
382
522
|
window.removeEventListener('hashchange', handleUrlChange);
|
|
383
|
-
|
|
523
|
+
|
|
524
|
+
// Restore original history methods
|
|
525
|
+
Object.defineProperty(window, 'history', {
|
|
526
|
+
value: {
|
|
527
|
+
...window.history,
|
|
528
|
+
pushState: originalPushState,
|
|
529
|
+
replaceState: originalReplaceState,
|
|
530
|
+
go: originalGo
|
|
531
|
+
},
|
|
532
|
+
writable: true,
|
|
533
|
+
configurable: true
|
|
534
|
+
});
|
|
384
535
|
};
|
|
385
|
-
}, [handleUrlChange]);
|
|
386
|
-
|
|
536
|
+
}, [handleUrlChange, createHistoryWrapper]);
|
|
387
537
|
|
|
388
538
|
return {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
539
|
+
getReady,
|
|
540
|
+
getHistory,
|
|
541
|
+
getForwardHistory,
|
|
542
|
+
getCurrentUrl,
|
|
543
|
+
getFirstUrl,
|
|
394
544
|
clearHistory,
|
|
395
545
|
goToHistory,
|
|
396
546
|
goBack,
|
|
397
547
|
goForward,
|
|
398
548
|
canGoBack,
|
|
399
|
-
canGoForward
|
|
549
|
+
canGoForward,
|
|
550
|
+
addHistoryToFirst
|
|
400
551
|
};
|
|
401
552
|
};
|
|
402
553
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"author": "UIUX Lab",
|
|
3
3
|
"email": "uiuxlab@gmail.com",
|
|
4
4
|
"name": "funda-ui",
|
|
5
|
-
"version": "4.7.
|
|
5
|
+
"version": "4.7.181",
|
|
6
6
|
"description": "React components using pure Bootstrap 5+ which does not contain any external style and script libraries.",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|