@dxos/react-async 2.28.2

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 (61) hide show
  1. package/README.md +29 -0
  2. package/dist/src/index.d.ts +8 -0
  3. package/dist/src/index.d.ts.map +1 -0
  4. package/dist/src/index.js +23 -0
  5. package/dist/src/index.js.map +1 -0
  6. package/dist/src/useAsyncEffect.d.ts +28 -0
  7. package/dist/src/useAsyncEffect.d.ts.map +1 -0
  8. package/dist/src/useAsyncEffect.js +53 -0
  9. package/dist/src/useAsyncEffect.js.map +1 -0
  10. package/dist/src/useAsyncEffect.test.d.ts +2 -0
  11. package/dist/src/useAsyncEffect.test.d.ts.map +1 -0
  12. package/dist/src/useAsyncEffect.test.js +70 -0
  13. package/dist/src/useAsyncEffect.test.js.map +1 -0
  14. package/dist/src/useControlledState.d.ts +17 -0
  15. package/dist/src/useControlledState.d.ts.map +1 -0
  16. package/dist/src/useControlledState.js +37 -0
  17. package/dist/src/useControlledState.js.map +1 -0
  18. package/dist/src/useDynamicRef.d.ts +17 -0
  19. package/dist/src/useDynamicRef.d.ts.map +1 -0
  20. package/dist/src/useDynamicRef.js +33 -0
  21. package/dist/src/useDynamicRef.js.map +1 -0
  22. package/dist/src/useMounted.d.ts +25 -0
  23. package/dist/src/useMounted.d.ts.map +1 -0
  24. package/dist/src/useMounted.js +42 -0
  25. package/dist/src/useMounted.js.map +1 -0
  26. package/dist/src/useStateUpdater.d.ts +20 -0
  27. package/dist/src/useStateUpdater.d.ts.map +1 -0
  28. package/dist/src/useStateUpdater.js +43 -0
  29. package/dist/src/useStateUpdater.js.map +1 -0
  30. package/dist/src/useStateUpdater.test.d.ts +2 -0
  31. package/dist/src/useStateUpdater.test.d.ts.map +1 -0
  32. package/dist/src/useStateUpdater.test.js +69 -0
  33. package/dist/src/useStateUpdater.test.js.map +1 -0
  34. package/dist/src/useStateWithRef.d.ts +17 -0
  35. package/dist/src/useStateWithRef.d.ts.map +1 -0
  36. package/dist/src/useStateWithRef.js +31 -0
  37. package/dist/src/useStateWithRef.js.map +1 -0
  38. package/dist/src/useTimestamp.d.ts +12 -0
  39. package/dist/src/useTimestamp.d.ts.map +1 -0
  40. package/dist/src/useTimestamp.js +28 -0
  41. package/dist/src/useTimestamp.js.map +1 -0
  42. package/dist/stories/stale-callback.stories.d.ts +6 -0
  43. package/dist/stories/stale-callback.stories.d.ts.map +1 -0
  44. package/dist/stories/stale-callback.stories.js +59 -0
  45. package/dist/stories/stale-callback.stories.js.map +1 -0
  46. package/dist/stories/unmounted.stories.d.ts +6 -0
  47. package/dist/stories/unmounted.stories.d.ts.map +1 -0
  48. package/dist/stories/unmounted.stories.js +60 -0
  49. package/dist/stories/unmounted.stories.js.map +1 -0
  50. package/dist/tsconfig.tsbuildinfo +1 -0
  51. package/package.json +52 -0
  52. package/src/index.ts +11 -0
  53. package/src/useAsyncEffect.test.tsx +57 -0
  54. package/src/useAsyncEffect.ts +61 -0
  55. package/src/useControlledState.ts +39 -0
  56. package/src/useDynamicRef.ts +34 -0
  57. package/src/useMounted.ts +40 -0
  58. package/src/useStateUpdater.test.tsx +58 -0
  59. package/src/useStateUpdater.ts +40 -0
  60. package/src/useStateWithRef.ts +31 -0
  61. package/src/useTimestamp.ts +27 -0
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ ## React Async
2
+
3
+ ### Configuration
4
+
5
+ Add the following to `package.json`.
6
+
7
+ ```json
8
+ "toolchain": {
9
+ "forceCloseTests": true,
10
+ "jsdom": true,
11
+ "testingFramework": "mocha"
12
+ }
13
+ ```
14
+
15
+ The `react-dom/test-utils` requires the `raf` (React animation frame) polyfill to run headless.
16
+
17
+ ```ts
18
+ import 'raf/polyfill';
19
+ import { act } from 'react-dom/test-utils';
20
+ ```
21
+
22
+
23
+ ### Next
24
+
25
+ Evaluate the following:
26
+
27
+ - https://www.npmjs.com/package/react-async-hook (popular)
28
+ - https://www.npmjs.com/package/use-enhanced-state
29
+ - https://www.npmjs.com/package/react-hooks-lib
@@ -0,0 +1,8 @@
1
+ export * from './useAsyncEffect';
2
+ export * from './useControlledState';
3
+ export * from './useDynamicRef';
4
+ export * from './useMounted';
5
+ export * from './useStateUpdater';
6
+ export * from './useStateWithRef';
7
+ export * from './useTimestamp';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2022 DXOS.org
4
+ //
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
8
+ }) : (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ o[k2] = m[k];
11
+ }));
12
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
13
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
14
+ };
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ __exportStar(require("./useAsyncEffect"), exports);
17
+ __exportStar(require("./useControlledState"), exports);
18
+ __exportStar(require("./useDynamicRef"), exports);
19
+ __exportStar(require("./useMounted"), exports);
20
+ __exportStar(require("./useStateUpdater"), exports);
21
+ __exportStar(require("./useStateWithRef"), exports);
22
+ __exportStar(require("./useTimestamp"), exports);
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;;;;;;;;;;AAEF,mDAAiC;AACjC,uDAAqC;AACrC,kDAAgC;AAChC,+CAA6B;AAC7B,oDAAkC;AAClC,oDAAkC;AAClC,iDAA+B"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Process async event with optional non-async destructor.
3
+ * Inspired by: https://github.com/rauldeheer/use-async-effect/blob/master/index.js
4
+ *
5
+ * ```tsx
6
+ * useAsyncEffect(async () => {
7
+ * await test();
8
+ * }, []);
9
+ * ```
10
+ *
11
+ * The callback may check of the component is still mounted before doing state updates.
12
+ *
13
+ * ```tsx
14
+ * const [value, setValue] = useState<string>();
15
+ * useAsyncEffect<string>(async (isMounted) => {
16
+ * const value = await test();
17
+ * if (!isMounted()) {
18
+ * setValue(value);
19
+ * }
20
+ * }, () => console.log('Unmounted'), []);
21
+ * ```
22
+ *
23
+ * @param callback Receives a getter function that determines if the componet is still mounted.
24
+ * @param destructor Receives the value retuned from the callback.
25
+ * @param deps
26
+ */
27
+ export declare const useAsyncEffect: <T>(callback: (isMounted: () => boolean) => Promise<T>, destructor?: any[] | ((value?: T | undefined) => void) | undefined, deps?: any[] | undefined) => void;
28
+ //# sourceMappingURL=useAsyncEffect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAsyncEffect.d.ts","sourceRoot":"","sources":["../../src/useAsyncEffect.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,eAAO,MAAM,cAAc,4BACH,MAAM,OAAO,kEACN,IAAI,gDAwBlC,CAAC"}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2022 DXOS.org
4
+ //
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.useAsyncEffect = void 0;
7
+ const react_1 = require("react");
8
+ /**
9
+ * Process async event with optional non-async destructor.
10
+ * Inspired by: https://github.com/rauldeheer/use-async-effect/blob/master/index.js
11
+ *
12
+ * ```tsx
13
+ * useAsyncEffect(async () => {
14
+ * await test();
15
+ * }, []);
16
+ * ```
17
+ *
18
+ * The callback may check of the component is still mounted before doing state updates.
19
+ *
20
+ * ```tsx
21
+ * const [value, setValue] = useState<string>();
22
+ * useAsyncEffect<string>(async (isMounted) => {
23
+ * const value = await test();
24
+ * if (!isMounted()) {
25
+ * setValue(value);
26
+ * }
27
+ * }, () => console.log('Unmounted'), []);
28
+ * ```
29
+ *
30
+ * @param callback Receives a getter function that determines if the componet is still mounted.
31
+ * @param destructor Receives the value retuned from the callback.
32
+ * @param deps
33
+ */
34
+ // TODO(burdon): Creade useAsyncMemo?
35
+ // TODO(burdon): Replace setImmediate everywhere (approx 30 places).
36
+ const useAsyncEffect = (callback, destructor, deps) => {
37
+ const [effectDestructor, effectDeps] = typeof destructor === 'function' ? [destructor, deps] : [undefined, destructor];
38
+ (0, react_1.useEffect)(() => {
39
+ let mounted = true;
40
+ let value;
41
+ const asyncResult = callback(() => mounted);
42
+ // TODO(burdon): Catch exception.
43
+ void Promise.resolve(asyncResult).then(result => {
44
+ value = result;
45
+ });
46
+ return () => {
47
+ mounted = false;
48
+ effectDestructor === null || effectDestructor === void 0 ? void 0 : effectDestructor(value);
49
+ };
50
+ }, effectDeps);
51
+ };
52
+ exports.useAsyncEffect = useAsyncEffect;
53
+ //# sourceMappingURL=useAsyncEffect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAsyncEffect.js","sourceRoot":"","sources":["../../src/useAsyncEffect.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;AAEF,iCAAkC;AAElC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qCAAqC;AACrC,oEAAoE;AAC7D,MAAM,cAAc,GAAG,CAC5B,QAAkD,EAClD,UAA0C,EAC1C,IAAY,EACZ,EAAE;IACF,MAAM,CACJ,gBAAgB,EAChB,UAAU,CACX,GAAG,OAAO,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAEpF,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,IAAI,OAAO,GAAG,IAAI,CAAC;QAEnB,IAAI,KAAQ,CAAC;QACb,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC;QAE5C,iCAAiC;QACjC,KAAK,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YAC9C,KAAK,GAAG,MAAM,CAAC;QACjB,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,OAAO,GAAG,KAAK,CAAC;YAChB,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAG,KAAK,CAAC,CAAC;QAC5B,CAAC,CAAC;IACJ,CAAC,EAAE,UAAU,CAAC,CAAC;AACjB,CAAC,CAAC;AA1BW,QAAA,cAAc,kBA0BzB"}
@@ -0,0 +1,2 @@
1
+ import 'raf/polyfill';
2
+ //# sourceMappingURL=useAsyncEffect.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAsyncEffect.test.d.ts","sourceRoot":"","sources":["../../src/useAsyncEffect.test.tsx"],"names":[],"mappings":"AAKA,OAAO,cAAc,CAAC"}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2022 DXOS.org
4
+ //
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
8
+ }) : (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ o[k2] = m[k];
11
+ }));
12
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
13
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
14
+ }) : function(o, v) {
15
+ o["default"] = v;
16
+ });
17
+ var __importStar = (this && this.__importStar) || function (mod) {
18
+ if (mod && mod.__esModule) return mod;
19
+ var result = {};
20
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
21
+ __setModuleDefault(result, mod);
22
+ return result;
23
+ };
24
+ var __importDefault = (this && this.__importDefault) || function (mod) {
25
+ return (mod && mod.__esModule) ? mod : { "default": mod };
26
+ };
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ const expect_1 = __importDefault(require("expect"));
29
+ require("raf/polyfill");
30
+ const react_1 = __importStar(require("react"));
31
+ const react_dom_1 = __importDefault(require("react-dom"));
32
+ const test_utils_1 = require("react-dom/test-utils");
33
+ const wait_for_expect_1 = __importDefault(require("wait-for-expect"));
34
+ const useAsyncEffect_1 = require("./useAsyncEffect");
35
+ const doAsync = async (value) => {
36
+ return await new Promise((resolve) => {
37
+ resolve(value);
38
+ });
39
+ };
40
+ const Test = () => {
41
+ const [value, setValue] = (0, react_1.useState)();
42
+ (0, useAsyncEffect_1.useAsyncEffect)(async (isMounted) => {
43
+ const value = await doAsync('DXOS');
44
+ if (isMounted()) {
45
+ setValue(value);
46
+ }
47
+ }, []);
48
+ return (react_1.default.createElement("h1", null, value));
49
+ };
50
+ let rootContainer;
51
+ beforeEach(() => {
52
+ rootContainer = document.createElement('div');
53
+ document.body.appendChild(rootContainer);
54
+ });
55
+ afterEach(() => {
56
+ document.body.removeChild(rootContainer);
57
+ rootContainer = null;
58
+ });
59
+ describe('useAsyncEffect', () => {
60
+ it('gets async value.', async () => {
61
+ (0, test_utils_1.act)(() => {
62
+ react_dom_1.default.render(react_1.default.createElement(Test, null), rootContainer);
63
+ });
64
+ const h1 = rootContainer.querySelector('h1');
65
+ await (0, wait_for_expect_1.default)(() => {
66
+ (0, expect_1.default)(h1.textContent).toEqual('DXOS');
67
+ });
68
+ });
69
+ });
70
+ //# sourceMappingURL=useAsyncEffect.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAsyncEffect.test.js","sourceRoot":"","sources":["../../src/useAsyncEffect.test.tsx"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;;;;;;;;;;;;;;;;;;;;;;AAEF,oDAA4B;AAC5B,wBAAsB;AACtB,+CAAwC;AACxC,0DAAiC;AACjC,qDAA2C;AAC3C,sEAA4C;AAE5C,qDAAkD;AAElD,MAAM,OAAO,GAAG,KAAK,EAAQ,KAAQ,EAAE,EAAE;IACvC,OAAO,MAAM,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,EAAE;QACtC,OAAO,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,IAAI,GAAG,GAAG,EAAE;IAChB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,IAAA,gBAAQ,GAAU,CAAC;IAC7C,IAAA,+BAAc,EAAC,KAAK,EAAE,SAAS,EAAE,EAAE;QACjC,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;QACpC,IAAI,SAAS,EAAE,EAAE;YACf,QAAQ,CAAC,KAAK,CAAC,CAAC;SACjB;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,0CAAK,KAAK,CAAM,CACjB,CAAC;AACJ,CAAC,CAAC;AAEF,IAAI,aAAkB,CAAC;AAEvB,UAAU,CAAC,GAAG,EAAE;IACd,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC9C,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,GAAG,EAAE;IACb,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;IACzC,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACjC,IAAA,gBAAG,EAAC,GAAG,EAAE;YACP,mBAAQ,CAAC,MAAM,CAAC,8BAAC,IAAI,OAAG,EAAE,aAAa,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,MAAM,EAAE,GAAG,aAAa,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,IAAA,yBAAa,EAAC,GAAG,EAAE;YACvB,IAAA,gBAAM,EAAC,EAAE,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+ /**
3
+ * Hook that manages state and that can be updated by caller.
4
+ * The optional callback is triggered only if the state is updated internally.
5
+ *
6
+ * ```tsx
7
+ * const Component = ({ value: controlledValue, onChange }: { value: string, onChange: (value:string) => void }) => {
8
+ * const [value, setValue] = useControlledState(controlledValue, onChange);
9
+ * const handleUpdate = (value: string) => setValue(value);
10
+ * }
11
+ *
12
+ * @param controlledValue
13
+ * @param onChange
14
+ * @param deps other deps that may change the state
15
+ */
16
+ export declare const useControlledState: <T>(controlledValue: T, onChange?: ((value: T) => void) | undefined, deps?: any[] | undefined) => [T, Dispatch<SetStateAction<T>>];
17
+ //# sourceMappingURL=useControlledState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useControlledState.d.ts","sourceRoot":"","sources":["../../src/useControlledState.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAuB,MAAM,OAAO,CAAC;AAEtE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,oDAEJ,IAAI,4EAgB9B,CAAC"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2022 DXOS.org
4
+ //
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.useControlledState = void 0;
7
+ const react_1 = require("react");
8
+ /**
9
+ * Hook that manages state and that can be updated by caller.
10
+ * The optional callback is triggered only if the state is updated internally.
11
+ *
12
+ * ```tsx
13
+ * const Component = ({ value: controlledValue, onChange }: { value: string, onChange: (value:string) => void }) => {
14
+ * const [value, setValue] = useControlledState(controlledValue, onChange);
15
+ * const handleUpdate = (value: string) => setValue(value);
16
+ * }
17
+ *
18
+ * @param controlledValue
19
+ * @param onChange
20
+ * @param deps other deps that may change the state
21
+ */
22
+ const useControlledState = (controlledValue, onChange, deps) => {
23
+ const [value, setValue] = (0, react_1.useState)(controlledValue);
24
+ (0, react_1.useEffect)(() => {
25
+ setValue(controlledValue);
26
+ }, [controlledValue, ...(deps !== null && deps !== void 0 ? deps : [])]);
27
+ return [
28
+ value,
29
+ (callback) => {
30
+ const newValue = (typeof callback === 'function') ? callback(value) : callback;
31
+ setValue(newValue);
32
+ onChange === null || onChange === void 0 ? void 0 : onChange(newValue);
33
+ }
34
+ ];
35
+ };
36
+ exports.useControlledState = useControlledState;
37
+ //# sourceMappingURL=useControlledState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useControlledState.js","sourceRoot":"","sources":["../../src/useControlledState.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;AAEF,iCAAsE;AAEtE;;;;;;;;;;;;;GAaG;AACI,MAAM,kBAAkB,GAAG,CAChC,eAAkB,EAClB,QAA6B,EAC7B,IAAY,EACsB,EAAE;IACpC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,IAAA,gBAAQ,EAAI,eAAe,CAAC,CAAC;IACvD,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,QAAQ,CAAC,eAAe,CAAC,CAAC;IAC5B,CAAC,EAAE,CAAC,eAAe,EAAE,GAAG,CAAC,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAEvC,OAAO;QACL,KAAK;QACL,CAAC,QAAkC,EAAE,EAAE;YACrC,MAAM,QAAQ,GAAG,CAAC,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,CAAE,QAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC7F,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACnB,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAG,QAAQ,CAAC,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAlBW,QAAA,kBAAkB,sBAkB7B"}
@@ -0,0 +1,17 @@
1
+ import { RefObject } from 'react';
2
+ /**
3
+ * Extension of useRef that contains computed values based on dependencies.
4
+ * E.g., to use in callbacks where the state value is stale.
5
+ *
6
+ * ```tsx
7
+ * const valueRef = useDynamicRef<() => value>([value]);
8
+ * const handleAction = () => {
9
+ * console.log(valueRef.current);
10
+ * }
11
+ * ```
12
+ *
13
+ * @param initialValue
14
+ * @param deps
15
+ */
16
+ export declare const useDynamicRef: <V>(initialValue: () => V, deps: any[]) => RefObject<V>;
17
+ //# sourceMappingURL=useDynamicRef.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDynamicRef.d.ts","sourceRoot":"","sources":["../../src/useDynamicRef.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAA+B,MAAM,OAAO,CAAC;AAE/D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,aAAa,mCAElB,GAAG,EAAE,iBAWZ,CAAC"}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2022 DXOS.org
4
+ //
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.useDynamicRef = void 0;
7
+ const react_1 = require("react");
8
+ /**
9
+ * Extension of useRef that contains computed values based on dependencies.
10
+ * E.g., to use in callbacks where the state value is stale.
11
+ *
12
+ * ```tsx
13
+ * const valueRef = useDynamicRef<() => value>([value]);
14
+ * const handleAction = () => {
15
+ * console.log(valueRef.current);
16
+ * }
17
+ * ```
18
+ *
19
+ * @param initialValue
20
+ * @param deps
21
+ */
22
+ const useDynamicRef = (initialValue, deps) => {
23
+ const [, setValue] = (0, react_1.useState)(initialValue);
24
+ const ref = (0, react_1.useRef)(initialValue());
25
+ (0, react_1.useEffect)(() => {
26
+ ref.current = initialValue();
27
+ // Must update state to trigger render cycle.
28
+ setValue(ref.current);
29
+ }, deps);
30
+ return ref;
31
+ };
32
+ exports.useDynamicRef = useDynamicRef;
33
+ //# sourceMappingURL=useDynamicRef.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDynamicRef.js","sourceRoot":"","sources":["../../src/useDynamicRef.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;AAEF,iCAA+D;AAE/D;;;;;;;;;;;;;GAaG;AACI,MAAM,aAAa,GAAG,CAC3B,YAAqB,EACrB,IAAW,EACG,EAAE;IAChB,MAAM,CAAC,EAAE,QAAQ,CAAC,GAAG,IAAA,gBAAQ,EAAI,YAAY,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAG,IAAA,cAAM,EAAI,YAAY,EAAE,CAAC,CAAC;IACtC,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,GAAG,CAAC,OAAO,GAAG,YAAY,EAAE,CAAC;QAC7B,6CAA6C;QAC7C,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC,EAAE,IAAI,CAAC,CAAC;IAET,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAbW,QAAA,aAAa,iBAaxB"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Provides a function to test if the component is still mounted.
3
+ * Avoids the following error:
4
+ * "Warning: Can't perform a React state update on an unmounted component."
5
+ *
6
+ * ```tsx
7
+ * const Test = () => {
8
+ * const isMounted = useMounted();
9
+ * const [value, setValue] = useState('');
10
+ * useEffect(() => {
11
+ * setTimeout(() => {
12
+ * if (isMounted()) {
13
+ * setValue(value);
14
+ * }
15
+ * }, 1000);
16
+ * }, []);
17
+ *
18
+ * return (
19
+ * <div>{value}</div>
20
+ * );
21
+ * }
22
+ * ```
23
+ */
24
+ export declare const useMounted: () => () => boolean;
25
+ //# sourceMappingURL=useMounted.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMounted.d.ts","sourceRoot":"","sources":["../../src/useMounted.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,UAAU,qBAUtB,CAAC"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2022 DXOS.org
4
+ //
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.useMounted = void 0;
7
+ const react_1 = require("react");
8
+ /**
9
+ * Provides a function to test if the component is still mounted.
10
+ * Avoids the following error:
11
+ * "Warning: Can't perform a React state update on an unmounted component."
12
+ *
13
+ * ```tsx
14
+ * const Test = () => {
15
+ * const isMounted = useMounted();
16
+ * const [value, setValue] = useState('');
17
+ * useEffect(() => {
18
+ * setTimeout(() => {
19
+ * if (isMounted()) {
20
+ * setValue(value);
21
+ * }
22
+ * }, 1000);
23
+ * }, []);
24
+ *
25
+ * return (
26
+ * <div>{value}</div>
27
+ * );
28
+ * }
29
+ * ```
30
+ */
31
+ const useMounted = () => {
32
+ const mounted = (0, react_1.useRef)(false);
33
+ (0, react_1.useEffect)(() => {
34
+ mounted.current = true;
35
+ return () => {
36
+ mounted.current = false;
37
+ };
38
+ }, []);
39
+ return () => mounted.current;
40
+ };
41
+ exports.useMounted = useMounted;
42
+ //# sourceMappingURL=useMounted.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMounted.js","sourceRoot":"","sources":["../../src/useMounted.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;AAEF,iCAA0C;AAE1C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACI,MAAM,UAAU,GAAG,GAAG,EAAE;IAC7B,MAAM,OAAO,GAAG,IAAA,cAAM,EAAC,KAAK,CAAC,CAAC;IAC9B,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;QACvB,OAAO,GAAG,EAAE;YACV,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC;QAC1B,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;AAC/B,CAAC,CAAC;AAVW,QAAA,UAAU,cAUrB"}
@@ -0,0 +1,20 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+ /**
3
+ * Partially updates state without copying complex (expensive) objects.
4
+ * https://github.com/kolodny/immutability-helper
5
+ *
6
+ * ```tsx
7
+ * const [value,, updateValue] = useStateMutator({ items: [], ... });
8
+ * useEffect(() => {
9
+ * updateValue({
10
+ * items: {
11
+ * $push: [1, 2, 3] // Only update the items property.
12
+ * }
13
+ * })
14
+ * }, []);
15
+ * ```
16
+ *
17
+ * @param initialValue
18
+ */
19
+ export declare const useStateUpdater: <T>(initialValue: T) => [T, Dispatch<SetStateAction<T>>, (spec: any) => T];
20
+ //# sourceMappingURL=useStateUpdater.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStateUpdater.d.ts","sourceRoot":"","sources":["../../src/useStateUpdater.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAY,MAAM,OAAO,CAAC;AAE3D;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,eAAe,kEAEe,GAAG,OAa7C,CAAC"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2022 DXOS.org
4
+ //
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.useStateUpdater = void 0;
10
+ const immutability_helper_1 = __importDefault(require("immutability-helper"));
11
+ const react_1 = require("react");
12
+ /**
13
+ * Partially updates state without copying complex (expensive) objects.
14
+ * https://github.com/kolodny/immutability-helper
15
+ *
16
+ * ```tsx
17
+ * const [value,, updateValue] = useStateMutator({ items: [], ... });
18
+ * useEffect(() => {
19
+ * updateValue({
20
+ * items: {
21
+ * $push: [1, 2, 3] // Only update the items property.
22
+ * }
23
+ * })
24
+ * }, []);
25
+ * ```
26
+ *
27
+ * @param initialValue
28
+ */
29
+ const useStateUpdater = (initialValue) => {
30
+ const [value, setValue] = (0, react_1.useState)(initialValue);
31
+ const handleUpdate = (spec) => {
32
+ const newValue = (0, immutability_helper_1.default)(value, spec);
33
+ setValue(newValue);
34
+ return newValue;
35
+ };
36
+ return [
37
+ value,
38
+ setValue,
39
+ handleUpdate
40
+ ];
41
+ };
42
+ exports.useStateUpdater = useStateUpdater;
43
+ //# sourceMappingURL=useStateUpdater.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStateUpdater.js","sourceRoot":"","sources":["../../src/useStateUpdater.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;;;;AAEF,8EAAyC;AACzC,iCAA2D;AAE3D;;;;;;;;;;;;;;;;GAgBG;AACI,MAAM,eAAe,GAAG,CAC7B,YAAe,EACqC,EAAE;IACtD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,IAAA,gBAAQ,EAAI,YAAY,CAAC,CAAC;IACpD,MAAM,YAAY,GAAG,CAAC,IAAS,EAAE,EAAE;QACjC,MAAM,QAAQ,GAAG,IAAA,6BAAM,EAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACrC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACnB,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO;QACL,KAAK;QACL,QAAQ;QACR,YAAY;KACb,CAAC;AACJ,CAAC,CAAC;AAfW,QAAA,eAAe,mBAe1B"}
@@ -0,0 +1,2 @@
1
+ import 'raf/polyfill';
2
+ //# sourceMappingURL=useStateUpdater.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStateUpdater.test.d.ts","sourceRoot":"","sources":["../../src/useStateUpdater.test.tsx"],"names":[],"mappings":"AAKA,OAAO,cAAc,CAAC"}
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2022 DXOS.org
4
+ //
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
8
+ }) : (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ o[k2] = m[k];
11
+ }));
12
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
13
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
14
+ }) : function(o, v) {
15
+ o["default"] = v;
16
+ });
17
+ var __importStar = (this && this.__importStar) || function (mod) {
18
+ if (mod && mod.__esModule) return mod;
19
+ var result = {};
20
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
21
+ __setModuleDefault(result, mod);
22
+ return result;
23
+ };
24
+ var __importDefault = (this && this.__importDefault) || function (mod) {
25
+ return (mod && mod.__esModule) ? mod : { "default": mod };
26
+ };
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ const expect_1 = __importDefault(require("expect"));
29
+ require("raf/polyfill");
30
+ const react_1 = __importStar(require("react"));
31
+ const react_dom_1 = __importDefault(require("react-dom"));
32
+ const test_utils_1 = require("react-dom/test-utils");
33
+ const wait_for_expect_1 = __importDefault(require("wait-for-expect"));
34
+ const useStateUpdater_1 = require("./useStateUpdater");
35
+ // Don't copy this.
36
+ const complex = {};
37
+ const Test = () => {
38
+ const [value, , updateValue] = (0, useStateUpdater_1.useStateUpdater)({ complex, items: [] });
39
+ (0, react_1.useEffect)(() => {
40
+ updateValue({
41
+ items: {
42
+ $push: [1, 2, 3]
43
+ }
44
+ });
45
+ }, []);
46
+ return (react_1.default.createElement("pre", null, JSON.stringify(value)));
47
+ };
48
+ let rootContainer;
49
+ beforeEach(() => {
50
+ rootContainer = document.createElement('div');
51
+ document.body.appendChild(rootContainer);
52
+ });
53
+ afterEach(() => {
54
+ document.body.removeChild(rootContainer);
55
+ rootContainer = null;
56
+ });
57
+ describe('useStateMutator', () => {
58
+ it('udpates the value.', async () => {
59
+ (0, test_utils_1.act)(() => {
60
+ react_dom_1.default.render(react_1.default.createElement(Test, null), rootContainer);
61
+ });
62
+ const pre = rootContainer.querySelector('pre');
63
+ await (0, wait_for_expect_1.default)(() => {
64
+ const data = JSON.parse(pre.textContent);
65
+ (0, expect_1.default)(data).toEqual({ complex, items: [1, 2, 3] });
66
+ });
67
+ });
68
+ });
69
+ //# sourceMappingURL=useStateUpdater.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStateUpdater.test.js","sourceRoot":"","sources":["../../src/useStateUpdater.test.tsx"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;;;;;;;;;;;;;;;;;;;;;;AAEF,oDAA4B;AAC5B,wBAAsB;AACtB,+CAAyC;AACzC,0DAAiC;AACjC,qDAA2C;AAC3C,sEAA4C;AAE5C,uDAAoD;AAEpD,mBAAmB;AACnB,MAAM,OAAO,GAAG,EAEf,CAAC;AAEF,MAAM,IAAI,GAAG,GAAG,EAAE;IAChB,MAAM,CAAC,KAAK,EAAC,EAAE,WAAW,CAAC,GAAG,IAAA,iCAAe,EAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;IACtE,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,WAAW,CAAC;YACV,KAAK,EAAE;gBACL,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;aACjB;SACF,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,2CAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAO,CACnC,CAAC;AACJ,CAAC,CAAC;AAEF,IAAI,aAAkB,CAAC;AAEvB,UAAU,CAAC,GAAG,EAAE;IACd,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC9C,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,GAAG,EAAE;IACb,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;IACzC,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,oBAAoB,EAAE,KAAK,IAAI,EAAE;QAClC,IAAA,gBAAG,EAAC,GAAG,EAAE;YACP,mBAAQ,CAAC,MAAM,CAAC,8BAAC,IAAI,OAAG,EAAE,aAAa,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,aAAa,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,IAAA,yBAAa,EAAC,GAAG,EAAE;YACvB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACzC,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { Dispatch, RefObject, SetStateAction } from 'react';
2
+ /**
3
+ * Extension of useState to return an up-to-date reference.
4
+ * E.g., to use in callbacks where the state value is stale.
5
+ * https://css-tricks.com/dealing-with-stale-props-and-states-in-reacts-functional-components
6
+ *
7
+ * ```tsx
8
+ * const [value, setValue, valueRef] = useStateWithRef<string>();
9
+ * const handleAction = () => {
10
+ * console.log(valueRef.current);
11
+ * }
12
+ * ```
13
+ *
14
+ * @param initialValue
15
+ */
16
+ export declare const useStateWithRef: <V>(initialValue?: V | (() => V) | undefined) => [V | undefined, Dispatch<SetStateAction<V | undefined>>, RefObject<V | undefined>];
17
+ //# sourceMappingURL=useStateWithRef.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStateWithRef.d.ts","sourceRoot":"","sources":["../../src/useStateWithRef.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAA+B,MAAM,OAAO,CAAC;AAEzF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,eAAe,qIAU3B,CAAC"}