@dxos/react-hooks 0.8.4-main.fd6878d → 0.8.4-staging.ac66bdf99f

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