@dxos/react-hooks 0.8.4-main.b97322e → 0.8.4-main.bcb3aa67d6

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