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

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
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,26 +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
- 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
- ];
7
+ var useAsyncEffect = (cb, deps) => {
12
8
  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);
9
+ const controller = new AbortController();
10
+ let cleanup;
11
+ const t = setTimeout(async () => {
12
+ if (!controller.signal.aborted) {
13
+ cleanup = await cb(controller);
14
+ }
15
+ });
19
16
  return () => {
20
- mounted = false;
21
- effectDestructor?.(value);
17
+ clearTimeout(t);
18
+ controller.abort();
19
+ cleanup?.();
22
20
  };
23
- }, effectDeps);
21
+ }, deps ?? []);
24
22
  };
25
23
 
26
24
  // src/useAsyncState.ts
@@ -47,55 +45,107 @@ var useAsyncState = (cb, deps = []) => {
47
45
  };
48
46
 
49
47
  // 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);
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);
56
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;
57
76
  }, [
58
- controlledValue,
59
- ...deps
77
+ value
60
78
  ]);
61
- useEffect3(() => {
62
- 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);
63
87
  }, [
64
- value,
65
- 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
66
99
  ]);
67
100
  return [
68
101
  value,
69
102
  setValue
70
103
  ];
71
104
  };
105
+ function isFunction(value) {
106
+ return typeof value === "function";
107
+ }
72
108
 
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
- });
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 = {};
82
120
  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]
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)
86
134
  });
87
135
  }
88
- console.groupEnd();
89
136
  lastDeps.current = deps;
90
- }, deps);
137
+ }, [
138
+ ...deps,
139
+ active
140
+ ]);
91
141
  };
92
142
 
93
143
  // src/useDefaultValue.ts
94
- import { useEffect as useEffect5, useState as useState3, useMemo } from "react";
144
+ import { useEffect as useEffect6, useMemo, useState as useState4 } from "react";
95
145
  var useDefaultValue = (reactiveValue, getDefaultValue) => {
96
146
  const stableDefaultValue = useMemo(getDefaultValue, []);
97
- const [value, setValue] = useState3(reactiveValue ?? stableDefaultValue);
98
- useEffect5(() => {
147
+ const [value, setValue] = useState4(reactiveValue ?? stableDefaultValue);
148
+ useEffect6(() => {
99
149
  setValue(reactiveValue ?? stableDefaultValue);
100
150
  }, [
101
151
  reactiveValue,
@@ -114,18 +164,6 @@ var useDefaults = (value, defaults) => {
114
164
  ]);
115
165
  };
116
166
 
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
167
  // src/useFileDownload.ts
130
168
  import { useMemo as useMemo3 } from "react";
131
169
  var useFileDownload = () => {
@@ -140,38 +178,59 @@ var useFileDownload = () => {
140
178
  };
141
179
 
142
180
  // src/useForwardedRef.ts
143
- import { useRef as useRef3, useEffect as useEffect7 } from "react";
144
- var useForwardedRef = (ref) => {
145
- 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);
146
184
  useEffect7(() => {
147
- if (!ref) {
148
- return;
149
- }
150
- if (typeof ref === "function") {
151
- ref(innerRef.current);
152
- } else {
153
- 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));
154
204
  }
155
- });
156
- 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
+ ]);
157
214
  };
158
215
 
159
216
  // src/useId.ts
160
217
  import alea from "alea";
161
- import { useMemo as useMemo4 } from "react";
218
+ import { useMemo as useMemo5 } from "react";
162
219
  var Alea = alea;
163
220
  var prng = new Alea("@dxos/react-hooks");
164
221
  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
- ]);
222
+ var useId = (namespace, propsId, opts) => {
223
+ return useMemo5(() => makeId(namespace, propsId, opts), [
224
+ propsId
225
+ ]);
226
+ };
168
227
  var makeId = (namespace, propsId, opts) => propsId ?? `${namespace}-${randomString(opts?.n ?? 4)}`;
169
228
 
170
229
  // src/useIsFocused.ts
171
- 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";
172
231
  var useIsFocused = (inputRef) => {
173
- const [isFocused, setIsFocused] = useState4(void 0);
174
- const isFocusedRef = useRef4(isFocused);
232
+ const [isFocused, setIsFocused] = useState5(void 0);
233
+ const isFocusedRef = useRef5(isFocused);
175
234
  isFocusedRef.current = isFocused;
176
235
  useEffect8(() => {
177
236
  const input = inputRef.current;
@@ -197,7 +256,7 @@ var useIsFocused = (inputRef) => {
197
256
  };
198
257
 
199
258
  // src/useMediaQuery.ts
200
- import { useEffect as useEffect9, useState as useState5 } from "react";
259
+ import { useEffect as useEffect9, useState as useState6 } from "react";
201
260
  var breakpointMediaQueries = {
202
261
  sm: "(min-width: 640px)",
203
262
  md: "(min-width: 768px)",
@@ -206,7 +265,7 @@ var breakpointMediaQueries = {
206
265
  "2xl": "(min-width: 1536px)"
207
266
  };
208
267
  var useMediaQuery = (query, options = {}) => {
209
- const { ssr = true, fallback } = options;
268
+ const { ssr = false, fallback } = options;
210
269
  const queries = (Array.isArray(query) ? query : [
211
270
  query
212
271
  ]).map((query2) => query2 in breakpointMediaQueries ? breakpointMediaQueries[query2] : query2);
@@ -214,7 +273,7 @@ var useMediaQuery = (query, options = {}) => {
214
273
  fallback
215
274
  ];
216
275
  fallbackValues = fallbackValues.filter((v) => v != null);
217
- const [value, setValue] = useState5(() => {
276
+ const [value, setValue] = useState6(() => {
218
277
  return queries.map((query2, index) => ({
219
278
  media: query2,
220
279
  matches: ssr ? !!fallbackValues[index] : document.defaultView?.matchMedia(query2).matches
@@ -262,9 +321,9 @@ var useMediaQuery = (query, options = {}) => {
262
321
  };
263
322
 
264
323
  // src/useMulticastObservable.ts
265
- import { useMemo as useMemo5, useSyncExternalStore } from "react";
324
+ import { useMemo as useMemo6, useSyncExternalStore } from "react";
266
325
  var useMulticastObservable = (observable) => {
267
- const subscribeFn = useMemo5(() => (listener) => {
326
+ const subscribeFn = useMemo6(() => (listener) => {
268
327
  const subscription = observable.subscribe(listener);
269
328
  return () => subscription.unsubscribe();
270
329
  }, [
@@ -274,28 +333,28 @@ var useMulticastObservable = (observable) => {
274
333
  };
275
334
 
276
335
  // src/useRefCallback.ts
277
- import { useState as useState6 } from "react";
336
+ import { useState as useState7 } from "react";
278
337
  var useRefCallback = () => {
279
- const [value, setValue] = useState6(null);
338
+ const [value, setValue] = useState7(null);
280
339
  return {
281
340
  refCallback: (value2) => setValue(value2),
282
341
  value
283
342
  };
284
343
  };
285
344
 
286
- // src/useResize.ts
287
- import { useLayoutEffect, useMemo as useMemo6 } from "react";
288
- var useResize = (handler, deps = [], delay = 800) => {
289
- 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(() => {
290
349
  let timeout;
291
350
  return (event) => {
292
351
  clearTimeout(timeout);
293
352
  timeout = setTimeout(() => {
294
- handler(event);
353
+ cb(event);
295
354
  }, delay);
296
355
  };
297
356
  }, [
298
- handler,
357
+ cb,
299
358
  delay
300
359
  ]);
301
360
  return useLayoutEffect(() => {
@@ -309,9 +368,9 @@ var useResize = (handler, deps = [], delay = 800) => {
309
368
  };
310
369
 
311
370
  // src/useTimeout.ts
312
- import { useEffect as useEffect10, useRef as useRef5 } from "react";
371
+ import { useEffect as useEffect10, useRef as useRef6 } from "react";
313
372
  var useTimeout = (callback, delay = 0, deps = []) => {
314
- const callbackRef = useRef5(callback);
373
+ const callbackRef = useRef6(callback);
315
374
  useEffect10(() => {
316
375
  callbackRef.current = callback;
317
376
  }, [
@@ -321,57 +380,48 @@ var useTimeout = (callback, delay = 0, deps = []) => {
321
380
  if (delay == null) {
322
381
  return;
323
382
  }
324
- const timeout = setTimeout(() => callbackRef.current?.(), delay);
325
- return () => clearTimeout(timeout);
383
+ const t = setTimeout(() => callbackRef.current?.(), delay);
384
+ return () => clearTimeout(t);
326
385
  }, [
327
386
  delay,
328
387
  ...deps
329
388
  ]);
330
389
  };
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
- }
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;
359
400
  }
360
- prevProps.current = props;
361
- });
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
+ ]);
362
412
  };
363
413
 
364
414
  // src/useTransitions.ts
365
- import { useRef as useRef7, useEffect as useEffect12, useState as useState7 } from "react";
366
- var isFunction = (functionToCheck) => {
415
+ import { useEffect as useEffect11, useRef as useRef7, useState as useState8 } from "react";
416
+ var isFunction2 = (functionToCheck) => {
367
417
  return functionToCheck instanceof Function;
368
418
  };
369
419
  var useDidTransition = (currentValue, fromValue, toValue) => {
370
- const [hasTransitioned, setHasTransitioned] = useState7(false);
420
+ const [hasTransitioned, setHasTransitioned] = useState8(false);
371
421
  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;
422
+ useEffect11(() => {
423
+ const toValueValid = isFunction2(toValue) ? toValue(currentValue) : toValue === currentValue;
424
+ const fromValueValid = isFunction2(fromValue) ? fromValue(previousValue.current) : fromValue === previousValue.current;
375
425
  if (fromValueValid && toValueValid && !hasTransitioned) {
376
426
  setHasTransitioned(true);
377
427
  } else if ((!fromValueValid || !toValueValid) && hasTransitioned) {
@@ -389,13 +439,13 @@ var useDidTransition = (currentValue, fromValue, toValue) => {
389
439
  var useOnTransition = (currentValue, fromValue, toValue, callback) => {
390
440
  const dirty = useRef7(false);
391
441
  const hasTransitioned = useDidTransition(currentValue, fromValue, toValue);
392
- useEffect12(() => {
442
+ useEffect11(() => {
393
443
  dirty.current = false;
394
444
  }, [
395
445
  currentValue,
396
446
  dirty
397
447
  ]);
398
- useEffect12(() => {
448
+ useEffect11(() => {
399
449
  if (hasTransitioned && !dirty.current) {
400
450
  callback();
401
451
  dirty.current = true;
@@ -408,11 +458,14 @@ var useOnTransition = (currentValue, fromValue, toValue, callback) => {
408
458
  };
409
459
  export {
410
460
  makeId,
461
+ mergeRefs,
411
462
  randomString,
463
+ setRef,
412
464
  useAsyncEffect,
413
465
  useAsyncState,
466
+ useComposedRefs,
414
467
  useControlledState,
415
- useDebugReactDeps,
468
+ useDebugDeps,
416
469
  useDefaultValue,
417
470
  useDefaults,
418
471
  useDidTransition,
@@ -420,13 +473,17 @@ export {
420
473
  useFileDownload,
421
474
  useForwardedRef,
422
475
  useId,
476
+ useInterval,
423
477
  useIsFocused,
424
478
  useMediaQuery,
479
+ useMergeRefs,
425
480
  useMulticastObservable,
426
481
  useOnTransition,
427
482
  useRefCallback,
428
- useResize,
483
+ useScroller,
484
+ useSize,
485
+ useStateWithRef,
429
486
  useTimeout,
430
- useTrackProps
487
+ useViewportResize
431
488
  };
432
489
  //# sourceMappingURL=index.mjs.map