@dxos/react-hooks 0.8.4-main.84f28bd → 0.8.4-main.937b3ca

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.
Files changed (57) hide show
  1. package/dist/lib/browser/index.mjs +189 -134
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +189 -134
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/index.d.ts +3 -3
  8. package/dist/types/src/index.d.ts.map +1 -1
  9. package/dist/types/src/useAsyncEffect.d.ts +5 -29
  10. package/dist/types/src/useAsyncEffect.d.ts.map +1 -1
  11. package/dist/types/src/useControlledState.d.ts +2 -1
  12. package/dist/types/src/useControlledState.d.ts.map +1 -1
  13. package/dist/types/src/useDebugDeps.d.ts +6 -0
  14. package/dist/types/src/useDebugDeps.d.ts.map +1 -0
  15. package/dist/types/src/useDynamicRef.d.ts +6 -1
  16. package/dist/types/src/useDynamicRef.d.ts.map +1 -1
  17. package/dist/types/src/useForwardedRef.d.ts +23 -3
  18. package/dist/types/src/useForwardedRef.d.ts.map +1 -1
  19. package/dist/types/src/useId.d.ts.map +1 -1
  20. package/dist/types/src/useIsFocused.d.ts +1 -1
  21. package/dist/types/src/useIsFocused.d.ts.map +1 -1
  22. package/dist/types/src/useMediaQuery.d.ts +1 -1
  23. package/dist/types/src/useMediaQuery.d.ts.map +1 -1
  24. package/dist/types/src/useMulticastObservable.test.d.ts.map +1 -1
  25. package/dist/types/src/useTimeout.d.ts +2 -1
  26. package/dist/types/src/useTimeout.d.ts.map +1 -1
  27. package/dist/types/src/useTransitions.d.ts +2 -1
  28. package/dist/types/src/useTransitions.d.ts.map +1 -1
  29. package/dist/types/src/useViewportResize.d.ts +3 -0
  30. package/dist/types/src/useViewportResize.d.ts.map +1 -0
  31. package/dist/types/tsconfig.tsbuildinfo +1 -1
  32. package/package.json +17 -11
  33. package/src/index.ts +4 -3
  34. package/src/useAsyncEffect.ts +19 -49
  35. package/src/useControlledState.ts +22 -11
  36. package/src/useDebugDeps.ts +35 -0
  37. package/src/useDefaultValue.ts +1 -1
  38. package/src/useDynamicRef.ts +26 -5
  39. package/src/useForwardedRef.ts +48 -13
  40. package/src/useId.ts +3 -2
  41. package/src/useIsFocused.ts +2 -2
  42. package/src/useMediaQuery.ts +8 -9
  43. package/src/{useMulticastObservable.test.tsx → useMulticastObservable.test.ts} +1 -3
  44. package/src/useTimeout.ts +28 -3
  45. package/src/useTransitions.ts +4 -2
  46. package/src/{useResize.ts → useViewportResize.ts} +1 -1
  47. package/dist/types/src/useAsyncEffect.test.d.ts +0 -2
  48. package/dist/types/src/useAsyncEffect.test.d.ts.map +0 -1
  49. package/dist/types/src/useDebugReactDeps.d.ts +0 -6
  50. package/dist/types/src/useDebugReactDeps.d.ts.map +0 -1
  51. package/dist/types/src/useResize.d.ts +0 -3
  52. package/dist/types/src/useResize.d.ts.map +0 -1
  53. package/dist/types/src/useTrackProps.d.ts +0 -5
  54. package/dist/types/src/useTrackProps.d.ts.map +0 -1
  55. package/src/useAsyncEffect.test.tsx +0 -51
  56. package/src/useDebugReactDeps.ts +0 -27
  57. package/src/useTrackProps.ts +0 -40
@@ -1,26 +1,20 @@
1
1
  // src/useAsyncEffect.ts
2
2
  import { useEffect } from "react";
3
- import { log } from "@dxos/log";
4
- var useAsyncEffect = (callback, destructor, deps) => {
5
- const [effectDestructor, effectDeps] = typeof destructor === "function" ? [
6
- destructor,
7
- deps
8
- ] : [
9
- void 0,
10
- destructor
11
- ];
3
+ var useAsyncEffect = (cb, deps) => {
12
4
  useEffect(() => {
13
- let mounted = true;
14
- let value;
15
- const asyncResult = callback(() => mounted);
16
- void Promise.resolve(asyncResult).then((result) => {
17
- value = result;
18
- }).catch(log.catch);
5
+ const controller = new AbortController();
6
+ let cleanup;
7
+ const t = setTimeout(async () => {
8
+ if (!controller.signal.aborted) {
9
+ cleanup = await cb(controller);
10
+ }
11
+ });
19
12
  return () => {
20
- mounted = false;
21
- effectDestructor?.(value);
13
+ clearTimeout(t);
14
+ controller.abort();
15
+ cleanup?.();
22
16
  };
23
- }, effectDeps);
17
+ }, deps ?? []);
24
18
  };
25
19
 
26
20
  // src/useAsyncState.ts
@@ -47,55 +41,107 @@ var useAsyncState = (cb, deps = []) => {
47
41
  };
48
42
 
49
43
  // src/useControlledState.ts
50
- import { useEffect as useEffect3, useState as useState2 } from "react";
51
- var useControlledState = (controlledValue, onChange, ...deps) => {
52
- const [value, setValue] = useState2(controlledValue);
53
- useEffect3(() => {
54
- if (controlledValue !== void 0) {
55
- setValue(controlledValue);
44
+ import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef2, useState as useState3 } from "react";
45
+
46
+ // src/useDynamicRef.ts
47
+ import { useCallback, useEffect as useEffect3, useRef, useState as useState2 } from "react";
48
+ var useStateWithRef = (valueProp) => {
49
+ const [value, setValue] = useState2(valueProp);
50
+ const valueRef = useRef(valueProp);
51
+ const setter = useCallback((value2) => {
52
+ if (typeof value2 === "function") {
53
+ setValue((current) => {
54
+ valueRef.current = value2(current);
55
+ return valueRef.current;
56
+ });
57
+ } else {
58
+ valueRef.current = value2;
59
+ setValue(value2);
56
60
  }
61
+ }, []);
62
+ return [
63
+ value,
64
+ setter,
65
+ valueRef
66
+ ];
67
+ };
68
+ var useDynamicRef = (value) => {
69
+ const valueRef = useRef(value);
70
+ useEffect3(() => {
71
+ valueRef.current = value;
57
72
  }, [
58
- controlledValue,
59
- ...deps
73
+ value
60
74
  ]);
61
- useEffect3(() => {
62
- onChange?.(value);
75
+ return valueRef;
76
+ };
77
+
78
+ // src/useControlledState.ts
79
+ var useControlledState = (valueProp, onChange) => {
80
+ const [value, setControlledValue] = useState3(valueProp);
81
+ useEffect4(() => {
82
+ setControlledValue(valueProp);
63
83
  }, [
64
- value,
65
- onChange
84
+ valueProp
85
+ ]);
86
+ const onChangeRef = useRef2(onChange);
87
+ const valueRef = useDynamicRef(valueProp);
88
+ const setValue = useCallback2((nextValue) => {
89
+ const value2 = isFunction(nextValue) ? nextValue(valueRef.current) : nextValue;
90
+ setControlledValue(value2);
91
+ onChangeRef.current?.(value2);
92
+ }, [
93
+ valueRef,
94
+ onChangeRef
66
95
  ]);
67
96
  return [
68
97
  value,
69
98
  setValue
70
99
  ];
71
100
  };
101
+ function isFunction(value) {
102
+ return typeof value === "function";
103
+ }
72
104
 
73
- // src/useDebugReactDeps.ts
74
- import { useEffect as useEffect4, useRef } from "react";
75
- var useDebugReactDeps = (deps = []) => {
76
- const lastDeps = useRef([]);
77
- useEffect4(() => {
78
- console.group("deps changed", {
79
- old: lastDeps.current.length,
80
- new: deps.length
81
- });
105
+ // src/useDebugDeps.ts
106
+ import { useEffect as useEffect5, useRef as useRef3 } from "react";
107
+ import { log } from "@dxos/log";
108
+ var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-primitives/react-hooks/src/useDebugDeps.ts";
109
+ var useDebugDeps = (deps = [], label = "useDebugDeps", active = true) => {
110
+ const lastDeps = useRef3([]);
111
+ useEffect5(() => {
112
+ if (!active) {
113
+ return;
114
+ }
115
+ const diff = {};
82
116
  for (let i = 0; i < Math.max(lastDeps.current.length ?? 0, deps.length ?? 0); i++) {
83
- console.log(i, lastDeps.current[i] === deps[i] ? "SAME" : "CHANGED", {
84
- previous: lastDeps.current[i],
85
- current: deps[i]
117
+ if (lastDeps.current[i] !== deps[i] || i > lastDeps.current.length) {
118
+ diff[i] = {
119
+ previous: lastDeps.current[i],
120
+ current: deps[i]
121
+ };
122
+ }
123
+ }
124
+ if (Object.keys(diff).length > 0) {
125
+ log.warn(`Updated: ${label} [${lastDeps.current.length}/${deps.length}]`, diff, {
126
+ F: __dxlog_file,
127
+ L: 30,
128
+ S: void 0,
129
+ C: (f, a) => f(...a)
86
130
  });
87
131
  }
88
- console.groupEnd();
89
132
  lastDeps.current = deps;
90
- }, deps);
133
+ }, [
134
+ ...deps,
135
+ active
136
+ ]);
91
137
  };
92
138
 
93
139
  // src/useDefaultValue.ts
94
- import { useEffect as useEffect5, useState as useState3, useMemo } from "react";
140
+ import { useEffect as useEffect6, useMemo, useState as useState4 } from "react";
95
141
  var useDefaultValue = (reactiveValue, getDefaultValue) => {
96
142
  const stableDefaultValue = useMemo(getDefaultValue, []);
97
- const [value, setValue] = useState3(reactiveValue ?? stableDefaultValue);
98
- useEffect5(() => {
143
+ const [value, setValue] = useState4(reactiveValue ?? stableDefaultValue);
144
+ useEffect6(() => {
99
145
  setValue(reactiveValue ?? stableDefaultValue);
100
146
  }, [
101
147
  reactiveValue,
@@ -114,18 +160,6 @@ var useDefaults = (value, defaults) => {
114
160
  ]);
115
161
  };
116
162
 
117
- // src/useDynamicRef.ts
118
- import { useEffect as useEffect6, useRef as useRef2 } from "react";
119
- var useDynamicRef = (value) => {
120
- const ref = useRef2(value);
121
- useEffect6(() => {
122
- ref.current = value;
123
- }, [
124
- value
125
- ]);
126
- return ref;
127
- };
128
-
129
163
  // src/useFileDownload.ts
130
164
  import { useMemo as useMemo3 } from "react";
131
165
  var useFileDownload = () => {
@@ -140,38 +174,59 @@ var useFileDownload = () => {
140
174
  };
141
175
 
142
176
  // src/useForwardedRef.ts
143
- import { useRef as useRef3, useEffect as useEffect7 } from "react";
144
- var useForwardedRef = (ref) => {
145
- const innerRef = useRef3(null);
177
+ import { useEffect as useEffect7, useMemo as useMemo4, useRef as useRef4 } from "react";
178
+ var useForwardedRef = (forwardedRef) => {
179
+ const localRef = useRef4(null);
146
180
  useEffect7(() => {
147
- if (!ref) {
148
- return;
149
- }
150
- if (typeof ref === "function") {
151
- ref(innerRef.current);
152
- } else {
153
- ref.current = innerRef.current;
181
+ setRef(forwardedRef, localRef.current);
182
+ }, [
183
+ forwardedRef
184
+ ]);
185
+ return localRef;
186
+ };
187
+ function setRef(ref, value) {
188
+ if (typeof ref === "function") {
189
+ return ref(value);
190
+ } else if (ref) {
191
+ ref.current = value;
192
+ }
193
+ }
194
+ var mergeRefs = (refs) => {
195
+ return (value) => {
196
+ const cleanups = [];
197
+ for (const ref of refs) {
198
+ const cleanup = setRef(ref, value);
199
+ cleanups.push(typeof cleanup === "function" ? cleanup : () => setRef(ref, null));
154
200
  }
155
- });
156
- return innerRef;
201
+ return () => {
202
+ for (const cleanup of cleanups) cleanup();
203
+ };
204
+ };
205
+ };
206
+ var useMergeRefs = (refs) => {
207
+ return useMemo4(() => mergeRefs(refs), [
208
+ ...refs
209
+ ]);
157
210
  };
158
211
 
159
212
  // src/useId.ts
160
213
  import alea from "alea";
161
- import { useMemo as useMemo4 } from "react";
214
+ import { useMemo as useMemo5 } from "react";
162
215
  var Alea = alea;
163
216
  var prng = new Alea("@dxos/react-hooks");
164
217
  var randomString = (n = 4) => prng().toString(16).slice(2, n + 2);
165
- var useId = (namespace, propsId, opts) => useMemo4(() => makeId(namespace, propsId, opts), [
166
- propsId
167
- ]);
218
+ var useId = (namespace, propsId, opts) => {
219
+ return useMemo5(() => makeId(namespace, propsId, opts), [
220
+ propsId
221
+ ]);
222
+ };
168
223
  var makeId = (namespace, propsId, opts) => propsId ?? `${namespace}-${randomString(opts?.n ?? 4)}`;
169
224
 
170
225
  // src/useIsFocused.ts
171
- import { useEffect as useEffect8, useRef as useRef4, useState as useState4 } from "react";
226
+ import { useEffect as useEffect8, useRef as useRef5, useState as useState5 } from "react";
172
227
  var useIsFocused = (inputRef) => {
173
- const [isFocused, setIsFocused] = useState4(void 0);
174
- const isFocusedRef = useRef4(isFocused);
228
+ const [isFocused, setIsFocused] = useState5(void 0);
229
+ const isFocusedRef = useRef5(isFocused);
175
230
  isFocusedRef.current = isFocused;
176
231
  useEffect8(() => {
177
232
  const input = inputRef.current;
@@ -197,7 +252,7 @@ var useIsFocused = (inputRef) => {
197
252
  };
198
253
 
199
254
  // src/useMediaQuery.ts
200
- import { useEffect as useEffect9, useState as useState5 } from "react";
255
+ import { useEffect as useEffect9, useState as useState6 } from "react";
201
256
  var breakpointMediaQueries = {
202
257
  sm: "(min-width: 640px)",
203
258
  md: "(min-width: 768px)",
@@ -206,7 +261,7 @@ var breakpointMediaQueries = {
206
261
  "2xl": "(min-width: 1536px)"
207
262
  };
208
263
  var useMediaQuery = (query, options = {}) => {
209
- const { ssr = true, fallback } = options;
264
+ const { ssr = false, fallback } = options;
210
265
  const queries = (Array.isArray(query) ? query : [
211
266
  query
212
267
  ]).map((query2) => query2 in breakpointMediaQueries ? breakpointMediaQueries[query2] : query2);
@@ -214,7 +269,7 @@ var useMediaQuery = (query, options = {}) => {
214
269
  fallback
215
270
  ];
216
271
  fallbackValues = fallbackValues.filter((v) => v != null);
217
- const [value, setValue] = useState5(() => {
272
+ const [value, setValue] = useState6(() => {
218
273
  return queries.map((query2, index) => ({
219
274
  media: query2,
220
275
  matches: ssr ? !!fallbackValues[index] : document.defaultView?.matchMedia(query2).matches
@@ -262,9 +317,9 @@ var useMediaQuery = (query, options = {}) => {
262
317
  };
263
318
 
264
319
  // src/useMulticastObservable.ts
265
- import { useMemo as useMemo5, useSyncExternalStore } from "react";
320
+ import { useMemo as useMemo6, useSyncExternalStore } from "react";
266
321
  var useMulticastObservable = (observable) => {
267
- const subscribeFn = useMemo5(() => (listener) => {
322
+ const subscribeFn = useMemo6(() => (listener) => {
268
323
  const subscription = observable.subscribe(listener);
269
324
  return () => subscription.unsubscribe();
270
325
  }, [
@@ -274,19 +329,19 @@ var useMulticastObservable = (observable) => {
274
329
  };
275
330
 
276
331
  // src/useRefCallback.ts
277
- import { useState as useState6 } from "react";
332
+ import { useState as useState7 } from "react";
278
333
  var useRefCallback = () => {
279
- const [value, setValue] = useState6(null);
334
+ const [value, setValue] = useState7(null);
280
335
  return {
281
336
  refCallback: (value2) => setValue(value2),
282
337
  value
283
338
  };
284
339
  };
285
340
 
286
- // src/useResize.ts
287
- import { useLayoutEffect, useMemo as useMemo6 } from "react";
288
- var useResize = (handler, deps = [], delay = 800) => {
289
- const debouncedHandler = useMemo6(() => {
341
+ // src/useViewportResize.ts
342
+ import { useLayoutEffect, useMemo as useMemo7 } from "react";
343
+ var useViewportResize = (handler, deps = [], delay = 800) => {
344
+ const debouncedHandler = useMemo7(() => {
290
345
  let timeout;
291
346
  return (event) => {
292
347
  clearTimeout(timeout);
@@ -309,9 +364,9 @@ var useResize = (handler, deps = [], delay = 800) => {
309
364
  };
310
365
 
311
366
  // src/useTimeout.ts
312
- import { useEffect as useEffect10, useRef as useRef5 } from "react";
367
+ import { useEffect as useEffect10, useRef as useRef6 } from "react";
313
368
  var useTimeout = (callback, delay = 0, deps = []) => {
314
- const callbackRef = useRef5(callback);
369
+ const callbackRef = useRef6(callback);
315
370
  useEffect10(() => {
316
371
  callbackRef.current = callback;
317
372
  }, [
@@ -321,57 +376,48 @@ var useTimeout = (callback, delay = 0, deps = []) => {
321
376
  if (delay == null) {
322
377
  return;
323
378
  }
324
- const timeout = setTimeout(() => callbackRef.current?.(), delay);
325
- return () => clearTimeout(timeout);
379
+ const t = setTimeout(() => callbackRef.current?.(), delay);
380
+ return () => clearTimeout(t);
326
381
  }, [
327
382
  delay,
328
383
  ...deps
329
384
  ]);
330
385
  };
331
-
332
- // src/useTrackProps.ts
333
- import { useRef as useRef6, useEffect as useEffect11 } from "react";
334
- import { log as log2 } from "@dxos/log";
335
- var __dxlog_file = "/__w/dxos/dxos/packages/ui/primitives/react-hooks/src/useTrackProps.ts";
336
- var useTrackProps = (props, componentName = "Component", active = true) => {
337
- const prevProps = useRef6(props);
338
- useEffect11(() => {
339
- const changes = Object.entries(props).filter(([key]) => props[key] !== prevProps.current[key]);
340
- if (changes.length > 0) {
341
- if (active) {
342
- log2.info("props changed", {
343
- componentName,
344
- keys: changes.map(([key]) => key).join(","),
345
- props: Object.fromEntries(changes.map(([key]) => [
346
- key,
347
- {
348
- from: prevProps.current[key],
349
- to: props[key]
350
- }
351
- ]))
352
- }, {
353
- F: __dxlog_file,
354
- L: 22,
355
- S: void 0,
356
- C: (f, a) => f(...a)
357
- });
358
- }
386
+ var useInterval = (callback, delay = 0, deps = []) => {
387
+ const callbackRef = useRef6(callback);
388
+ useEffect10(() => {
389
+ callbackRef.current = callback;
390
+ }, [
391
+ callback
392
+ ]);
393
+ useEffect10(() => {
394
+ if (delay == null) {
395
+ return;
359
396
  }
360
- prevProps.current = props;
361
- });
397
+ const i = setInterval(async () => {
398
+ const result = await callbackRef.current?.();
399
+ if (result === false) {
400
+ clearInterval(i);
401
+ }
402
+ }, delay);
403
+ return () => clearInterval(i);
404
+ }, [
405
+ delay,
406
+ ...deps
407
+ ]);
362
408
  };
363
409
 
364
410
  // src/useTransitions.ts
365
- import { useRef as useRef7, useEffect as useEffect12, useState as useState7 } from "react";
366
- var isFunction = (functionToCheck) => {
411
+ import { useEffect as useEffect11, useRef as useRef7, useState as useState8 } from "react";
412
+ var isFunction2 = (functionToCheck) => {
367
413
  return functionToCheck instanceof Function;
368
414
  };
369
415
  var useDidTransition = (currentValue, fromValue, toValue) => {
370
- const [hasTransitioned, setHasTransitioned] = useState7(false);
416
+ const [hasTransitioned, setHasTransitioned] = useState8(false);
371
417
  const previousValue = useRef7(currentValue);
372
- useEffect12(() => {
373
- const toValueValid = isFunction(toValue) ? toValue(currentValue) : toValue === currentValue;
374
- const fromValueValid = isFunction(fromValue) ? fromValue(previousValue.current) : fromValue === previousValue.current;
418
+ useEffect11(() => {
419
+ const toValueValid = isFunction2(toValue) ? toValue(currentValue) : toValue === currentValue;
420
+ const fromValueValid = isFunction2(fromValue) ? fromValue(previousValue.current) : fromValue === previousValue.current;
375
421
  if (fromValueValid && toValueValid && !hasTransitioned) {
376
422
  setHasTransitioned(true);
377
423
  } else if ((!fromValueValid || !toValueValid) && hasTransitioned) {
@@ -389,13 +435,13 @@ var useDidTransition = (currentValue, fromValue, toValue) => {
389
435
  var useOnTransition = (currentValue, fromValue, toValue, callback) => {
390
436
  const dirty = useRef7(false);
391
437
  const hasTransitioned = useDidTransition(currentValue, fromValue, toValue);
392
- useEffect12(() => {
438
+ useEffect11(() => {
393
439
  dirty.current = false;
394
440
  }, [
395
441
  currentValue,
396
442
  dirty
397
443
  ]);
398
- useEffect12(() => {
444
+ useEffect11(() => {
399
445
  if (hasTransitioned && !dirty.current) {
400
446
  callback();
401
447
  dirty.current = true;
@@ -406,13 +452,18 @@ var useOnTransition = (currentValue, fromValue, toValue, callback) => {
406
452
  callback
407
453
  ]);
408
454
  };
455
+
456
+ // src/index.ts
457
+ import { useSize, useScroller } from "mini-virtual-list";
409
458
  export {
410
459
  makeId,
460
+ mergeRefs,
411
461
  randomString,
462
+ setRef,
412
463
  useAsyncEffect,
413
464
  useAsyncState,
414
465
  useControlledState,
415
- useDebugReactDeps,
466
+ useDebugDeps,
416
467
  useDefaultValue,
417
468
  useDefaults,
418
469
  useDidTransition,
@@ -420,13 +471,17 @@ export {
420
471
  useFileDownload,
421
472
  useForwardedRef,
422
473
  useId,
474
+ useInterval,
423
475
  useIsFocused,
424
476
  useMediaQuery,
477
+ useMergeRefs,
425
478
  useMulticastObservable,
426
479
  useOnTransition,
427
480
  useRefCallback,
428
- useResize,
481
+ useScroller,
482
+ useSize,
483
+ useStateWithRef,
429
484
  useTimeout,
430
- useTrackProps
485
+ useViewportResize
431
486
  };
432
487
  //# sourceMappingURL=index.mjs.map