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