@assistant-ui/tap 0.5.14 → 0.6.1

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 (181) hide show
  1. package/README.md +9 -8
  2. package/dist/core/ResourceFiber.d.ts.map +1 -1
  3. package/dist/core/ResourceFiber.js +3 -2
  4. package/dist/core/ResourceFiber.js.map +1 -1
  5. package/dist/core/context.d.ts +13 -6
  6. package/dist/core/context.d.ts.map +1 -1
  7. package/dist/core/context.js +19 -6
  8. package/dist/core/context.js.map +1 -1
  9. package/dist/core/createResourceRoot.d.ts +2 -1
  10. package/dist/core/createResourceRoot.d.ts.map +1 -1
  11. package/dist/core/createResourceRoot.js +2 -2
  12. package/dist/core/createResourceRoot.js.map +1 -1
  13. package/dist/core/helpers/execution-context.d.ts +2 -1
  14. package/dist/core/helpers/execution-context.d.ts.map +1 -1
  15. package/dist/core/helpers/execution-context.js +4 -1
  16. package/dist/core/helpers/execution-context.js.map +1 -1
  17. package/dist/core/react-dispatcher.d.ts +12 -0
  18. package/dist/core/react-dispatcher.d.ts.map +1 -0
  19. package/dist/core/react-dispatcher.js +63 -0
  20. package/dist/core/react-dispatcher.js.map +1 -0
  21. package/dist/core/scheduler.js +1 -1
  22. package/dist/core/scheduler.js.map +1 -1
  23. package/dist/core/types.d.ts +3 -3
  24. package/dist/hooks/index.d.ts +13 -0
  25. package/dist/hooks/index.js +13 -0
  26. package/dist/hooks/use.d.ts +9 -0
  27. package/dist/hooks/use.d.ts.map +1 -0
  28. package/dist/hooks/use.js +14 -0
  29. package/dist/hooks/use.js.map +1 -0
  30. package/dist/hooks/useCallback.d.ts +5 -0
  31. package/dist/hooks/useCallback.d.ts.map +1 -0
  32. package/dist/hooks/useCallback.js +9 -0
  33. package/dist/hooks/useCallback.js.map +1 -0
  34. package/dist/hooks/useEffect.d.ts +10 -0
  35. package/dist/hooks/useEffect.d.ts.map +1 -0
  36. package/dist/hooks/{tap-effect.js → useEffect.js} +7 -7
  37. package/dist/hooks/useEffect.js.map +1 -0
  38. package/dist/hooks/{tap-effect-event.d.ts → useEffectEvent.d.ts} +5 -5
  39. package/dist/hooks/useEffectEvent.d.ts.map +1 -0
  40. package/dist/hooks/{tap-effect-event.js → useEffectEvent.js} +12 -12
  41. package/dist/hooks/useEffectEvent.js.map +1 -0
  42. package/dist/hooks/useMemo.d.ts +5 -0
  43. package/dist/hooks/useMemo.d.ts.map +1 -0
  44. package/dist/hooks/{tap-memo.js → useMemo.js} +6 -6
  45. package/dist/hooks/useMemo.js.map +1 -0
  46. package/dist/hooks/useMemoCache.d.ts +10 -0
  47. package/dist/hooks/useMemoCache.d.ts.map +1 -0
  48. package/dist/hooks/useMemoCache.js +21 -0
  49. package/dist/hooks/useMemoCache.js.map +1 -0
  50. package/dist/hooks/useReducer.d.ts +21 -0
  51. package/dist/hooks/useReducer.d.ts.map +1 -0
  52. package/dist/hooks/{tap-reducer.js → useReducer.js} +10 -10
  53. package/dist/hooks/useReducer.js.map +1 -0
  54. package/dist/hooks/useRef.d.ts +11 -0
  55. package/dist/hooks/useRef.d.ts.map +1 -0
  56. package/dist/hooks/useRef.js +10 -0
  57. package/dist/hooks/useRef.js.map +1 -0
  58. package/dist/{react/use-resource.d.ts → hooks/useResource.d.ts} +3 -2
  59. package/dist/hooks/useResource.d.ts.map +1 -0
  60. package/dist/hooks/{tap-resource.js → useResource.js} +12 -12
  61. package/dist/hooks/useResource.js.map +1 -0
  62. package/dist/hooks/useResourceRoot.d.ts +20 -0
  63. package/dist/hooks/useResourceRoot.d.ts.map +1 -0
  64. package/dist/{tapResourceRoot.js → hooks/useResourceRoot.js} +30 -26
  65. package/dist/hooks/useResourceRoot.js.map +1 -0
  66. package/dist/hooks/{tap-resources.d.ts → useResources.d.ts} +4 -4
  67. package/dist/hooks/useResources.d.ts.map +1 -0
  68. package/dist/hooks/{tap-resources.js → useResources.js} +28 -23
  69. package/dist/hooks/useResources.js.map +1 -0
  70. package/dist/hooks/useState.d.ts +9 -0
  71. package/dist/hooks/useState.d.ts.map +1 -0
  72. package/dist/hooks/useState.js +11 -0
  73. package/dist/hooks/useState.js.map +1 -0
  74. package/dist/hooks/utils/useCell.d.ts +10 -0
  75. package/dist/hooks/utils/useCell.d.ts.map +1 -0
  76. package/dist/hooks/utils/{tapHook.js → useCell.js} +4 -4
  77. package/dist/hooks/utils/{tapHook.js.map → useCell.js.map} +1 -1
  78. package/dist/index.d.ts +3 -13
  79. package/dist/index.js +3 -13
  80. package/dist/react/hooks.d.ts +25 -0
  81. package/dist/react/hooks.d.ts.map +1 -0
  82. package/dist/react/hooks.js +69 -0
  83. package/dist/react/hooks.js.map +1 -0
  84. package/dist/react-shim/index.d.ts +17 -0
  85. package/dist/react-shim/index.d.ts.map +1 -0
  86. package/dist/react-shim/index.js +28 -0
  87. package/dist/react-shim/index.js.map +1 -0
  88. package/package.json +13 -16
  89. package/react-shim/package.json +4 -0
  90. package/src/__tests__/basic/resourceHandle.test.ts +7 -3
  91. package/src/__tests__/basic/tapEffect.basic.test.ts +19 -19
  92. package/src/__tests__/basic/tapReducer.basic.test.ts +14 -14
  93. package/src/__tests__/basic/tapResources.basic.test.ts +19 -14
  94. package/src/__tests__/basic/tapState.basic.test.ts +20 -20
  95. package/src/__tests__/errors/errors.effect-errors.test.ts +21 -21
  96. package/src/__tests__/errors/errors.render-errors.test.ts +18 -18
  97. package/src/__tests__/lifecycle/lifecycle.dependencies.test.ts +25 -25
  98. package/src/__tests__/lifecycle/lifecycle.mount-unmount.test.ts +17 -18
  99. package/src/__tests__/react/concurrent-mode.test.tsx +7 -7
  100. package/src/__tests__/react/react-shim.test.tsx +65 -0
  101. package/src/__tests__/react/useResource.test.tsx +172 -0
  102. package/src/__tests__/react-dispatcher.test.ts +74 -0
  103. package/src/__tests__/rules/rules.hook-count.test.ts +30 -29
  104. package/src/__tests__/rules/rules.hook-order.test.ts +27 -27
  105. package/src/__tests__/strictmode/react-strictmode-behavior.test.tsx +1 -1
  106. package/src/__tests__/strictmode/strictmode.test.ts +42 -42
  107. package/src/__tests__/strictmode/tap-strictmode-rerender-sources.test.ts +55 -55
  108. package/src/__tests__/test-utils.ts +2 -2
  109. package/src/core/ResourceFiber.ts +4 -1
  110. package/src/core/context.ts +31 -9
  111. package/src/core/createResourceRoot.ts +4 -4
  112. package/src/core/helpers/execution-context.ts +4 -0
  113. package/src/core/react-dispatcher.ts +78 -0
  114. package/src/core/scheduler.ts +1 -1
  115. package/src/core/types.ts +3 -3
  116. package/src/hooks/index.ts +12 -0
  117. package/src/hooks/use.ts +13 -0
  118. package/src/hooks/useCallback.ts +9 -0
  119. package/src/hooks/{tap-effect.ts → useEffect.ts} +9 -9
  120. package/src/hooks/{tap-effect-event.ts → useEffectEvent.ts} +9 -9
  121. package/src/hooks/{tap-memo.ts → useMemo.ts} +3 -3
  122. package/src/hooks/useMemoCache.ts +25 -0
  123. package/src/hooks/{tap-reducer.ts → useReducer.ts} +23 -11
  124. package/src/hooks/useRef.ts +16 -0
  125. package/src/hooks/{tap-resource.ts → useResource.ts} +13 -12
  126. package/src/{tapResourceRoot.ts → hooks/useResourceRoot.ts} +26 -27
  127. package/src/hooks/{tap-resources.ts → useResources.ts} +21 -22
  128. package/src/hooks/useState.ts +29 -0
  129. package/src/hooks/utils/{tapHook.ts → useCell.ts} +1 -1
  130. package/src/index.ts +4 -24
  131. package/src/react/hooks.ts +112 -0
  132. package/src/react-shim/index.ts +75 -0
  133. package/dist/hooks/tap-callback.d.ts +0 -5
  134. package/dist/hooks/tap-callback.d.ts.map +0 -1
  135. package/dist/hooks/tap-callback.js +0 -9
  136. package/dist/hooks/tap-callback.js.map +0 -1
  137. package/dist/hooks/tap-const.d.ts +0 -5
  138. package/dist/hooks/tap-const.d.ts.map +0 -1
  139. package/dist/hooks/tap-const.js +0 -10
  140. package/dist/hooks/tap-const.js.map +0 -1
  141. package/dist/hooks/tap-effect-event.d.ts.map +0 -1
  142. package/dist/hooks/tap-effect-event.js.map +0 -1
  143. package/dist/hooks/tap-effect.d.ts +0 -10
  144. package/dist/hooks/tap-effect.d.ts.map +0 -1
  145. package/dist/hooks/tap-effect.js.map +0 -1
  146. package/dist/hooks/tap-memo.d.ts +0 -5
  147. package/dist/hooks/tap-memo.d.ts.map +0 -1
  148. package/dist/hooks/tap-memo.js.map +0 -1
  149. package/dist/hooks/tap-reducer.d.ts +0 -9
  150. package/dist/hooks/tap-reducer.d.ts.map +0 -1
  151. package/dist/hooks/tap-reducer.js.map +0 -1
  152. package/dist/hooks/tap-ref.d.ts +0 -11
  153. package/dist/hooks/tap-ref.d.ts.map +0 -1
  154. package/dist/hooks/tap-ref.js +0 -10
  155. package/dist/hooks/tap-ref.js.map +0 -1
  156. package/dist/hooks/tap-resource.d.ts +0 -8
  157. package/dist/hooks/tap-resource.d.ts.map +0 -1
  158. package/dist/hooks/tap-resource.js.map +0 -1
  159. package/dist/hooks/tap-resources.d.ts.map +0 -1
  160. package/dist/hooks/tap-resources.js.map +0 -1
  161. package/dist/hooks/tap-state.d.ts +0 -9
  162. package/dist/hooks/tap-state.d.ts.map +0 -1
  163. package/dist/hooks/tap-state.js +0 -11
  164. package/dist/hooks/tap-state.js.map +0 -1
  165. package/dist/hooks/utils/tapHook.d.ts +0 -10
  166. package/dist/hooks/utils/tapHook.d.ts.map +0 -1
  167. package/dist/react/index.d.ts +0 -2
  168. package/dist/react/index.js +0 -2
  169. package/dist/react/use-resource.d.ts.map +0 -1
  170. package/dist/react/use-resource.js +0 -46
  171. package/dist/react/use-resource.js.map +0 -1
  172. package/dist/tapResourceRoot.d.ts +0 -20
  173. package/dist/tapResourceRoot.d.ts.map +0 -1
  174. package/dist/tapResourceRoot.js.map +0 -1
  175. package/react/package.json +0 -5
  176. package/src/hooks/tap-callback.ts +0 -9
  177. package/src/hooks/tap-const.ts +0 -6
  178. package/src/hooks/tap-ref.ts +0 -16
  179. package/src/hooks/tap-state.ts +0 -29
  180. package/src/react/index.ts +0 -1
  181. package/src/react/use-resource.ts +0 -61
@@ -3,22 +3,21 @@ import {
3
3
  createResourceFiber,
4
4
  renderResourceFiber,
5
5
  unmountResourceFiber,
6
- } from "./core/ResourceFiber";
7
- import { UpdateScheduler } from "./core/scheduler";
8
- import { tapConst } from "./hooks/tap-const";
9
- import { tapMemo } from "./hooks/tap-memo";
10
- import { tapEffect } from "./hooks/tap-effect";
11
- import { tapEffectEvent } from "./hooks/tap-effect-event";
12
- import { tapRef } from "./hooks/tap-ref";
13
- import type { RenderResult, ResourceElement } from "./core/types";
14
- import { isDevelopment } from "./core/helpers/env";
6
+ } from "../core/ResourceFiber";
7
+ import { UpdateScheduler } from "../core/scheduler";
8
+ import { useMemo } from "./useMemo";
9
+ import { useEffect } from "./useEffect";
10
+ import { useEffectEvent } from "./useEffectEvent";
11
+ import { useRef } from "./useRef";
12
+ import type { RenderResult, ResourceElement } from "../core/types";
13
+ import { isDevelopment } from "../core/helpers/env";
15
14
  import {
16
15
  commitRoot,
17
16
  createResourceFiberRoot,
18
17
  setRootVersion,
19
- } from "./core/helpers/root";
18
+ } from "../core/helpers/root";
20
19
 
21
- export namespace tapResourceRoot {
20
+ export namespace useResourceRoot {
22
21
  export type Unsubscribe = () => void;
23
22
 
24
23
  export interface SubscribableResource<TState> {
@@ -34,18 +33,18 @@ export namespace tapResourceRoot {
34
33
  }
35
34
  }
36
35
 
37
- // currently we never reset the root, because rollbakcs are not supported in tapResourceRoot
36
+ // The root is never reset, because rollbacks are not supported in useResourceRoot.
38
37
 
39
- export const tapResourceRoot = <TState>(
38
+ export const useResourceRoot = <TState>(
40
39
  element: ResourceElement<TState>,
41
- ): tapResourceRoot.SubscribableResource<TState> => {
42
- const scheduler = tapConst(
40
+ ): useResourceRoot.SubscribableResource<TState> => {
41
+ const scheduler = useMemo(
43
42
  () => new UpdateScheduler(() => handleUpdate(null)),
44
43
  [],
45
44
  );
46
- const queue = tapConst(() => [] as (() => void)[], []);
45
+ const queue = useMemo(() => [] as (() => void)[], []);
47
46
 
48
- const fiber = tapMemo(() => {
47
+ const fiber = useMemo(() => {
49
48
  void element.key;
50
49
 
51
50
  return createResourceFiber(
@@ -56,16 +55,16 @@ export const tapResourceRoot = <TState>(
56
55
  scheduler.markDirty();
57
56
  }),
58
57
  );
59
- }, [element.type, element.key]);
58
+ }, [element.type, element.key, queue, scheduler]);
60
59
 
61
60
  setRootVersion(fiber.root, fiber.root.committedVersion);
62
61
  const render = renderResourceFiber(fiber, element.props);
63
62
 
64
- const isMountedRef = tapRef(false);
65
- const committedPropsRef = tapRef(element.props);
66
- const valueRef = tapRef<TState>(render.output);
67
- const subscribers = tapConst(() => new Set<() => void>(), []);
68
- const handleUpdate = tapEffectEvent((render: RenderResult | null) => {
63
+ const isMountedRef = useRef(false);
64
+ const committedPropsRef = useRef(element.props);
65
+ const valueRef = useRef<TState>(render.output);
66
+ const subscribers = useMemo(() => new Set<() => void>(), []);
67
+ const handleUpdate = useEffectEvent((render: RenderResult | null) => {
69
68
  if (render === null) {
70
69
  setRootVersion(fiber.root, 2);
71
70
  setRootVersion(fiber.root, 1);
@@ -100,7 +99,7 @@ export const tapResourceRoot = <TState>(
100
99
  subscribers.forEach((callback) => callback());
101
100
  });
102
101
 
103
- tapEffect(() => {
102
+ useEffect(() => {
104
103
  isMountedRef.current = true;
105
104
  return () => {
106
105
  isMountedRef.current = false;
@@ -108,7 +107,7 @@ export const tapResourceRoot = <TState>(
108
107
  };
109
108
  }, [fiber]);
110
109
 
111
- tapEffect(() => {
110
+ useEffect(() => {
112
111
  committedPropsRef.current = render.props;
113
112
  commitRoot(fiber.root);
114
113
  commitResourceFiber(fiber, render);
@@ -118,7 +117,7 @@ export const tapResourceRoot = <TState>(
118
117
  subscribers.forEach((callback) => callback());
119
118
  });
120
119
 
121
- return tapMemo(
120
+ return useMemo(
122
121
  () => ({
123
122
  getValue: () => valueRef.current,
124
123
  subscribe: (listener: () => void) => {
@@ -126,6 +125,6 @@ export const tapResourceRoot = <TState>(
126
125
  return () => subscribers.delete(listener);
127
126
  },
128
127
  }),
129
- [],
128
+ [subscribers],
130
129
  );
131
130
  };
@@ -4,17 +4,16 @@ import type {
4
4
  ResourceElement,
5
5
  ResourceFiber,
6
6
  } from "../core/types";
7
- import { tapEffect } from "./tap-effect";
8
- import { tapMemo } from "./tap-memo";
9
- import { tapCallback } from "./tap-callback";
7
+ import { useEffect } from "./useEffect";
8
+ import { useMemo } from "./useMemo";
9
+ import { useCallback } from "./useCallback";
10
10
  import {
11
11
  createResourceFiber,
12
12
  unmountResourceFiber,
13
13
  renderResourceFiber,
14
14
  commitResourceFiber,
15
15
  } from "../core/ResourceFiber";
16
- import { tapConst } from "./tap-const";
17
- import { tapRef } from "./tap-ref";
16
+ import { useRef } from "./useRef";
18
17
  import { getCurrentResourceFiber } from "../core/helpers/execution-context";
19
18
 
20
19
  type FiberState = {
@@ -25,31 +24,31 @@ type FiberState = {
25
24
  | "delete";
26
25
  };
27
26
 
28
- export function tapResources<E extends ResourceElement<any, any>>(
27
+ export function useResources<E extends ResourceElement<any, any>>(
29
28
  getElements: () => readonly E[],
30
29
  getElementsDeps?: readonly unknown[],
31
30
  ): ExtractResourceReturnType<E>[] {
32
- const versionRef = tapRef(0);
31
+ const versionRef = useRef(0);
33
32
  const version = versionRef.current;
34
33
 
35
- const parentFiber = tapConst(getCurrentResourceFiber, []);
36
- const markDirty = tapConst(
34
+ const parentFiber = useMemo(() => getCurrentResourceFiber(), []);
35
+ const markDirty = useMemo(
37
36
  () => () => {
38
37
  versionRef.current++;
39
38
  parentFiber.markDirty?.();
40
39
  },
41
- [],
40
+ [parentFiber],
42
41
  );
43
- const fibers = tapConst(() => new Map<string | number, FiberState>(), []);
42
+ const fibers = useMemo(() => new Map<string | number, FiberState>(), []);
44
43
 
45
44
  const getElementsMemo = getElementsDeps
46
- ? // oxlint-disable-next-line tap-hooks/exhaustive-deps -- deps forwarded by caller
47
- tapCallback(getElements, getElementsDeps)
45
+ ? // oxlint-disable-next-line react/exhaustive-deps,react/rules-of-hooks -- deps forwarded by caller; getElementsDeps presence is fixed per call site
46
+ useCallback(getElements, getElementsDeps)
48
47
  : getElements;
49
48
 
50
49
  // Process each element
51
50
 
52
- const res = tapMemo(() => {
51
+ const res = useMemo(() => {
53
52
  void version;
54
53
 
55
54
  const elementsArray = getElementsMemo();
@@ -64,12 +63,12 @@ export function tapResources<E extends ResourceElement<any, any>>(
64
63
  const elementKey = element.key;
65
64
  if (elementKey === undefined) {
66
65
  throw new Error(
67
- `tapResources did not provide a key for array at index ${i}`,
66
+ `useResources did not provide a key for array at index ${i}`,
68
67
  );
69
68
  }
70
69
 
71
70
  if (seenKeys.has(elementKey))
72
- throw new Error(`Duplicate key ${elementKey} in tapResources`);
71
+ throw new Error(`Duplicate key ${elementKey} in useResources`);
73
72
  seenKeys.add(elementKey);
74
73
 
75
74
  let state = fibers.get(elementKey);
@@ -112,20 +111,20 @@ export function tapResources<E extends ResourceElement<any, any>>(
112
111
  }
113
112
 
114
113
  return results;
115
- }, [getElementsMemo, version]);
114
+ }, [getElementsMemo, version, parentFiber, markDirty, fibers]);
116
115
 
117
116
  // Cleanup on unmount
118
- tapEffect(() => {
117
+ useEffect(() => {
119
118
  return () => {
120
119
  for (const key of fibers.keys()) {
121
120
  const fiber = fibers.get(key)!.fiber;
122
121
  unmountResourceFiber(fiber);
123
122
  }
124
123
  };
125
- }, []);
124
+ }, [fibers]);
126
125
 
127
- tapEffect(() => {
128
- res; // as a performance optimization, we only run if the results have changed
126
+ useEffect(() => {
127
+ void res; // as a performance optimization, we only run if the results have changed
129
128
 
130
129
  for (const [key, state] of fibers.entries()) {
131
130
  if (state.next === "delete") {
@@ -142,7 +141,7 @@ export function tapResources<E extends ResourceElement<any, any>>(
142
141
  commitResourceFiber(state.fiber, state.next);
143
142
  }
144
143
  }
145
- }, [res]);
144
+ }, [res, fibers]);
146
145
 
147
146
  return res;
148
147
  }
@@ -0,0 +1,29 @@
1
+ import { useReducer } from "./useReducer";
2
+
3
+ export namespace useState {
4
+ export type StateUpdater<S> = S | ((prev: S) => S);
5
+ }
6
+
7
+ const stateReducer = <S>(
8
+ state: S | undefined,
9
+ action: useState.StateUpdater<S>,
10
+ ): S =>
11
+ typeof action === "function"
12
+ ? (action as (prev: S | undefined) => S)(state)
13
+ : action;
14
+
15
+ const stateInit = <S>(initial: S | (() => S)): S =>
16
+ typeof initial === "function" ? (initial as () => S)() : initial;
17
+
18
+ export function useState<S = undefined>(): [
19
+ S | undefined,
20
+ (updater: useState.StateUpdater<S>) => void,
21
+ ];
22
+ export function useState<S>(
23
+ initial: S | (() => S),
24
+ ): [S, (updater: useState.StateUpdater<S>) => void];
25
+ export function useState<S>(
26
+ initial?: S | (() => S),
27
+ ): [S | undefined, (updater: useState.StateUpdater<S>) => void] {
28
+ return useReducer(stateReducer, initial, stateInit);
29
+ }
@@ -1,7 +1,7 @@
1
1
  import { getCurrentResourceFiber } from "../../core/helpers/execution-context";
2
2
  import type { Cell } from "../../core/types";
3
3
 
4
- export const tapHook = <T extends Cell["type"]>(
4
+ export const useCell = <T extends Cell["type"]>(
5
5
  type: T,
6
6
  init: () => Cell,
7
7
  ): Cell & { type: T } => {
package/src/index.ts CHANGED
@@ -1,35 +1,15 @@
1
1
  export { resource } from "./core/resource";
2
2
  export { withKey } from "./core/withKey";
3
3
 
4
- // primitive hooks
5
- export { tapState } from "./hooks/tap-state";
6
- export { tapReducer, tapReducerWithDerivedState } from "./hooks/tap-reducer";
7
- export { tapEffect } from "./hooks/tap-effect";
8
-
9
- // utility hooks
10
- export { tapRef } from "./hooks/tap-ref";
11
- export { tapConst } from "./hooks/tap-const";
12
- export { tapMemo } from "./hooks/tap-memo";
13
- export { tapCallback } from "./hooks/tap-callback";
14
- export { tapEffectEvent } from "./hooks/tap-effect-event";
15
-
16
- // resources
17
- export { tapResource } from "./hooks/tap-resource";
18
- export { tapResources } from "./hooks/tap-resources";
19
-
20
- // subscribable
21
- export { tapResourceRoot } from "./tapResourceRoot";
22
-
23
4
  // imperative
24
5
  export { createResourceRoot } from "./core/createResourceRoot";
25
6
  export { flushResourcesSync } from "./core/scheduler";
26
7
 
27
8
  // context
28
- export {
29
- createResourceContext,
30
- tap,
31
- withContextProvider,
32
- } from "./core/context";
9
+ export { createResourceContext, withContextProvider } from "./core/context";
10
+
11
+ // hooks
12
+ export { useResource, useResources, useResourceRoot } from "./react/hooks";
33
13
 
34
14
  // types
35
15
  export type {
@@ -0,0 +1,112 @@
1
+ import { useLayoutEffect, useMemo, useReducer, useRef, useState } from "react";
2
+ import type { ResourceFiberRoot, Resource } from "../core/types";
3
+ import {
4
+ createResourceFiber,
5
+ unmountResourceFiber,
6
+ renderResourceFiber,
7
+ commitResourceFiber,
8
+ } from "../core/ResourceFiber";
9
+ import { isDevelopment } from "../core/helpers/env";
10
+ import {
11
+ commitRoot,
12
+ createResourceFiberRoot,
13
+ setRootVersion,
14
+ } from "../core/helpers/root";
15
+ import { peekResourceFiber } from "../core/helpers/execution-context";
16
+ import * as hooks from "../hooks";
17
+ import { resource } from "../core/resource";
18
+
19
+ const useDevStrictMode = () => {
20
+ if (!isDevelopment) return null;
21
+
22
+ // oxlint-disable-next-line react/rules-of-hooks -- isDevelopment is a build-time constant, so this branch is stable per build
23
+ const count = useRef(0);
24
+ const isFirstRender = count.current === 0;
25
+ // oxlint-disable-next-line react/rules-of-hooks -- isDevelopment is a build-time constant, so this branch is stable per build
26
+ useState(() => count.current++);
27
+ if (count.current !== 2) return null;
28
+ return isFirstRender ? ("child" as const) : ("root" as const);
29
+ };
30
+
31
+ const HostResource = resource(function HostResource<T>(callback: () => T) {
32
+ return callback();
33
+ });
34
+
35
+ // Runs `callback` inside a resource render hosted by a React component, so the
36
+ // resource composition hooks (useResource/useResources/useResourceRoot) work from
37
+ // React. `callback` executes inside the resource fiber below, so it may only call
38
+ // resource hooks, not React's own hooks (which would have no fiber to attach to).
39
+ // This is the single React->resource bridge; the React branch of every public
40
+ // hook goes through it.
41
+ const useResourceHost = <T>(callback: () => T): T => {
42
+ const root = useMemo<ResourceFiberRoot>(() => {
43
+ return createResourceFiberRoot((cb) => dispatch(cb));
44
+ }, []);
45
+
46
+ const [version, dispatch] = useReducer((v: number, cb: () => boolean) => {
47
+ setRootVersion(root, v);
48
+ return v + (cb() ? 1 : 0);
49
+ }, 0);
50
+ setRootVersion(root, version);
51
+
52
+ const devStrictMode = useDevStrictMode();
53
+ const fiber = useMemo(() => {
54
+ return createResourceFiber(
55
+ HostResource as unknown as Resource<T, () => T>,
56
+ root,
57
+ undefined,
58
+ devStrictMode,
59
+ );
60
+ }, [root, devStrictMode]);
61
+
62
+ const result = renderResourceFiber(fiber, callback);
63
+ useLayoutEffect(() => {
64
+ return () => unmountResourceFiber(fiber);
65
+ }, [fiber]);
66
+ useLayoutEffect(() => {
67
+ commitRoot(root);
68
+ commitResourceFiber(fiber, result);
69
+ });
70
+
71
+ return result.output;
72
+ };
73
+
74
+ // Turns a resource hook into an isomorphic hook with the SAME type (overloads
75
+ // included): inside a resource render it calls the hook directly; inside a React
76
+ // component it hosts it via the `useResourceHost` bridge. peekResourceFiber() is
77
+ // stable per call site (a given call always renders in the same environment), so
78
+ // the branch order across renders is fixed even though rules-of-hooks can't prove
79
+ // it.
80
+ const makeHook = <F extends (...args: any[]) => any>(hook: F): F =>
81
+ ((...args: any[]) => {
82
+ /* oxlint-disable react/rules-of-hooks */
83
+ if (peekResourceFiber()) return hook(...args);
84
+ return useResourceHost(() => hook(...args));
85
+ /* oxlint-enable react/rules-of-hooks */
86
+ }) as F;
87
+
88
+ /**
89
+ * Hosts a resource element. Inside a resource render it hosts the element as a
90
+ * child resource; inside a React component it hosts it via the React bridge.
91
+ * `propsDeps` is a resource-render optimization and is ignored on the React side.
92
+ */
93
+ export const useResource: typeof hooks.useResource = makeHook(
94
+ hooks.useResource,
95
+ );
96
+
97
+ /**
98
+ * Hosts a keyed list of resource elements. Inside a resource render it composes
99
+ * them directly; inside a React component it hosts them via the React bridge.
100
+ */
101
+ export const useResources: typeof hooks.useResources = makeHook(
102
+ hooks.useResources,
103
+ );
104
+
105
+ /**
106
+ * Hosts a resource element as a subscribable root. Inside a resource render it
107
+ * uses the root hook directly; inside a React component it hosts that root via
108
+ * the React bridge (host it in one place; observe it via getValue/subscribe).
109
+ */
110
+ export const useResourceRoot: typeof hooks.useResourceRoot = makeHook(
111
+ hooks.useResourceRoot,
112
+ );
@@ -0,0 +1,75 @@
1
+ /* oxlint-disable react/rules-of-hooks -- this module deliberately routes hook calls between tap and React at runtime */
2
+ /* oxlint-disable react/exhaustive-deps -- dependency arrays are forwarded verbatim from the caller */
3
+ // Runtime drop-in for "react": forward everything from react, then override the
4
+ // hooks that have a tap equivalent so they route to tap inside a resource render
5
+ // and to React otherwise. Alias `react` to this module (build `output.paths` /
6
+ // vitest resolver) in code that can run inside a tap resource.
7
+ //
8
+ // This subpath ships no type declarations: the build reverts the aliased
9
+ // specifier back to `"react"` in emitted `.d.ts`, so consumer types resolve to
10
+ // React's own. The source-level TS2498 from the `export *` below is suppressed.
11
+ import React from "react";
12
+ import { peekResourceFiber } from "../core/helpers/execution-context";
13
+ import * as hooks from "../hooks";
14
+ import { useResourceContext, isResourceContext } from "../core/context";
15
+
16
+ // @ts-expect-error -- @types/react uses `export =`; this is valid at runtime.
17
+ export * from "react";
18
+ export { default } from "react";
19
+
20
+ const inTap = () => peekResourceFiber() !== null;
21
+ const ReactRuntime = React as any;
22
+
23
+ // --- hooks with a tap equivalent: override the star-exported react hooks ---
24
+
25
+ export const useState = (initialState?: any) =>
26
+ inTap() ? hooks.useState(initialState) : ReactRuntime.useState(initialState);
27
+
28
+ export const useReducer = (reducer: any, initialArg: any, init?: any) =>
29
+ inTap()
30
+ ? hooks.useReducer(reducer, initialArg, init)
31
+ : ReactRuntime.useReducer(reducer, initialArg, init);
32
+
33
+ export const useRef = (initialValue?: any) =>
34
+ inTap() ? hooks.useRef(initialValue) : ReactRuntime.useRef(initialValue);
35
+
36
+ export const useMemo = (factory: any, deps: any) =>
37
+ inTap() ? hooks.useMemo(factory, deps) : ReactRuntime.useMemo(factory, deps);
38
+
39
+ export const useCallback = (callback: any, deps: any) =>
40
+ inTap()
41
+ ? hooks.useCallback(callback, deps)
42
+ : ReactRuntime.useCallback(callback, deps);
43
+
44
+ export const useEffect = (effect: any, deps?: any) =>
45
+ inTap()
46
+ ? hooks.useEffect(effect, deps)
47
+ : ReactRuntime.useEffect(effect, deps);
48
+
49
+ // tap has a single effect primitive; layout effects collapse onto it
50
+ export const useLayoutEffect = (effect: any, deps?: any) =>
51
+ inTap()
52
+ ? hooks.useEffect(effect, deps)
53
+ : ReactRuntime.useLayoutEffect(effect, deps);
54
+
55
+ // The non-tap fallback requires a React version that provides useEffectEvent.
56
+ export const useEffectEvent = (callback: any) =>
57
+ inTap()
58
+ ? hooks.useEffectEvent(callback)
59
+ : ReactRuntime.useEffectEvent(callback);
60
+
61
+ // `use(usable)` reads tap resource context when handed a tap context (routed by
62
+ // its brand, not by ambient render state), and falls back to React's `use`
63
+ // (promises / React context) for everything else. The non-tap fallback requires
64
+ // React 19.
65
+ export const use = (usable: any) =>
66
+ isResourceContext(usable)
67
+ ? useResourceContext(usable)
68
+ : ReactRuntime.use(usable);
69
+
70
+ // `useContext(context)` reads tap resource context when handed a tap context
71
+ // (routed by its brand), and falls back to React's `useContext` otherwise.
72
+ export const useContext = (context: any) =>
73
+ isResourceContext(context)
74
+ ? useResourceContext(context)
75
+ : ReactRuntime.useContext(context);
@@ -1,5 +0,0 @@
1
- //#region src/hooks/tap-callback.d.ts
2
- declare const tapCallback: <T extends (...args: any[]) => any>(fn: T, deps: readonly unknown[]) => T;
3
- //#endregion
4
- export { tapCallback };
5
- //# sourceMappingURL=tap-callback.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tap-callback.d.ts","names":[],"sources":["../../src/hooks/tap-callback.ts"],"mappings":";cAEa,WAAA,iBAA6B,IAAA,iBACxC,EAAA,EAAI,CAAA,EACJ,IAAA,yBACC,CAGF"}
@@ -1,9 +0,0 @@
1
- import { tapMemo } from "./tap-memo.js";
2
- //#region src/hooks/tap-callback.ts
3
- const tapCallback = (fn, deps) => {
4
- return tapMemo(() => fn, deps);
5
- };
6
- //#endregion
7
- export { tapCallback };
8
-
9
- //# sourceMappingURL=tap-callback.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tap-callback.js","names":[],"sources":["../../src/hooks/tap-callback.ts"],"sourcesContent":["import { tapMemo } from \"./tap-memo\";\n\nexport const tapCallback = <T extends (...args: any[]) => any>(\n fn: T,\n deps: readonly unknown[],\n): T => {\n // oxlint-disable-next-line tap-hooks/exhaustive-deps -- user-provided dep array forwarded verbatim\n return tapMemo(() => fn, deps);\n};\n"],"mappings":";;AAEA,MAAa,eACX,IACA,SACM;CAEN,OAAO,cAAc,IAAI,IAAI;AAC/B"}
@@ -1,5 +0,0 @@
1
- //#region src/hooks/tap-const.d.ts
2
- declare function tapConst<T>(getValue: () => T, _deps: readonly never[]): T;
3
- //#endregion
4
- export { tapConst };
5
- //# sourceMappingURL=tap-const.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tap-const.d.ts","names":[],"sources":["../../src/hooks/tap-const.ts"],"mappings":";iBAEgB,QAAA,IAAY,QAAA,QAAgB,CAAA,EAAG,KAAA,qBAA0B,CAAC"}
@@ -1,10 +0,0 @@
1
- import { tapState } from "./tap-state.js";
2
- //#region src/hooks/tap-const.ts
3
- function tapConst(getValue, _deps) {
4
- const [state] = tapState(getValue);
5
- return state;
6
- }
7
- //#endregion
8
- export { tapConst };
9
-
10
- //# sourceMappingURL=tap-const.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tap-const.js","names":[],"sources":["../../src/hooks/tap-const.ts"],"sourcesContent":["import { tapState } from \"./tap-state\";\n\nexport function tapConst<T>(getValue: () => T, _deps: readonly never[]): T {\n const [state] = tapState(getValue);\n return state;\n}\n"],"mappings":";;AAEA,SAAgB,SAAY,UAAmB,OAA4B;CACzE,MAAM,CAAC,SAAS,SAAS,QAAQ;CACjC,OAAO;AACT"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tap-effect-event.d.ts","names":[],"sources":["../../src/hooks/tap-effect-event.ts"],"mappings":";;AAqBA;;;;;;;;;;AAEI;;;;iBAFY,cAAA,eAA6B,IAAA,iBAC3C,QAAA,EAAU,CAAA,GACT,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tap-effect-event.js","names":[],"sources":["../../src/hooks/tap-effect-event.ts"],"sourcesContent":["import { tapRef } from \"./tap-ref\";\nimport { tapEffect } from \"./tap-effect\";\nimport { isDevelopment } from \"../core/helpers/env\";\nimport { tapCallback } from \"./tap-callback\";\nimport { getCurrentResourceFiber } from \"../core/helpers/execution-context\";\n\n/**\n * Creates a stable function reference that always calls the most recent version of the callback.\n * Similar to React's useEffectEvent hook.\n *\n * @param callback - The callback function to wrap\n * @returns A stable function reference that always calls the latest callback\n *\n * @example\n * ```typescript\n * const handleClick = tapEffectEvent((value: string) => {\n * console.log(value);\n * });\n * // handleClick reference is stable, but always calls the latest version\n * ```\n */\nexport function tapEffectEvent<T extends (...args: any[]) => any>(\n callback: T,\n): T {\n const callbackRef = tapRef(callback);\n\n // TODO this effect needs to run before all userland effects\n tapEffect(() => {\n callbackRef.current = callback;\n });\n\n const fiber = getCurrentResourceFiber();\n return tapCallback(\n ((...args: Parameters<T>) => {\n if (isDevelopment && fiber.renderContext)\n throw new Error(\"tapEffectEvent cannot be called during render\");\n return callbackRef.current(...args);\n }) as T,\n [fiber],\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,eACd,UACG;CACH,MAAM,cAAc,OAAO,QAAQ;CAGnC,gBAAgB;EACd,YAAY,UAAU;CACxB,CAAC;CAED,MAAM,QAAQ,wBAAwB;CACtC,OAAO,cACH,GAAG,SAAwB;EAC3B,IAAI,iBAAiB,MAAM,eACzB,MAAM,IAAI,MAAM,+CAA+C;EACjE,OAAO,YAAY,QAAQ,GAAG,IAAI;CACpC,IACA,CAAC,KAAK,CACR;AACF"}
@@ -1,10 +0,0 @@
1
- //#region src/hooks/tap-effect.d.ts
2
- declare namespace tapEffect {
3
- type Destructor = () => void;
4
- type EffectCallback = () => Destructor | undefined;
5
- }
6
- declare function tapEffect(effect: tapEffect.EffectCallback): void;
7
- declare function tapEffect(effect: tapEffect.EffectCallback, deps: readonly unknown[]): void;
8
- //#endregion
9
- export { tapEffect };
10
- //# sourceMappingURL=tap-effect.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tap-effect.d.ts","names":[],"sources":["../../src/hooks/tap-effect.ts"],"mappings":";kBAUiB,SAAA;EAAA,KACH,UAAA;EAAA,KACA,cAAA,SAAuB,UAAU;AAAA;AAAA,iBAG/B,SAAA,CAAU,MAAA,EAAQ,SAAA,CAAU,cAAc;AAAA,iBAC1C,SAAA,CACd,MAAA,EAAQ,SAAA,CAAU,cAAc,EAChC,IAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tap-effect.js","names":[],"sources":["../../src/hooks/tap-effect.ts"],"sourcesContent":["import type { Cell } from \"../core/types\";\nimport { depsShallowEqual } from \"./utils/depsShallowEqual\";\nimport { tapHook, registerRenderMountTask } from \"./utils/tapHook\";\n\nconst newEffect = (): Cell & { type: \"effect\" } => ({\n type: \"effect\",\n cleanup: undefined,\n deps: null, // null means the effect has never been run\n});\n\nexport namespace tapEffect {\n export type Destructor = () => void;\n export type EffectCallback = () => Destructor | undefined;\n}\n\nexport function tapEffect(effect: tapEffect.EffectCallback): void;\nexport function tapEffect(\n effect: tapEffect.EffectCallback,\n deps: readonly unknown[],\n): void;\nexport function tapEffect(\n effect: tapEffect.EffectCallback,\n deps?: readonly unknown[],\n): void {\n const cell = tapHook(\"effect\", newEffect);\n\n if (deps && cell.deps && depsShallowEqual(cell.deps, deps)) return;\n if (cell.deps !== null && !!deps !== !!cell.deps)\n throw new Error(\n \"tapEffect called with and without dependencies across re-renders\",\n );\n\n registerRenderMountTask(() => {\n const errors: unknown[] = [];\n\n try {\n cell.cleanup?.();\n } catch (error) {\n errors.push(error);\n } finally {\n cell.cleanup = undefined;\n }\n\n try {\n const cleanup = effect();\n\n if (cleanup !== undefined && typeof cleanup !== \"function\") {\n throw new Error(\n \"An effect function must either return a cleanup function or nothing. \" +\n `Received: ${typeof cleanup}`,\n );\n }\n\n cell.cleanup = cleanup;\n } catch (error) {\n errors.push(error);\n }\n\n cell.deps = deps;\n\n if (errors.length > 0) {\n if (errors.length === 1) {\n throw errors[0];\n } else {\n for (const error of errors) {\n console.error(error);\n }\n throw new AggregateError(errors, \"Errors during commit\");\n }\n }\n });\n}\n"],"mappings":";;;AAIA,MAAM,mBAA8C;CAClD,MAAM;CACN,SAAS,KAAA;CACT,MAAM;AACR;AAYA,SAAgB,UACd,QACA,MACM;CACN,MAAM,OAAO,QAAQ,UAAU,SAAS;CAExC,IAAI,QAAQ,KAAK,QAAQ,iBAAiB,KAAK,MAAM,IAAI,GAAG;CAC5D,IAAI,KAAK,SAAS,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,MAC1C,MAAM,IAAI,MACR,kEACF;CAEF,8BAA8B;EAC5B,MAAM,SAAoB,CAAC;EAE3B,IAAI;GACF,KAAK,UAAU;EACjB,SAAS,OAAO;GACd,OAAO,KAAK,KAAK;EACnB,UAAU;GACR,KAAK,UAAU,KAAA;EACjB;EAEA,IAAI;GACF,MAAM,UAAU,OAAO;GAEvB,IAAI,YAAY,KAAA,KAAa,OAAO,YAAY,YAC9C,MAAM,IAAI,MACR,kFACe,OAAO,SACxB;GAGF,KAAK,UAAU;EACjB,SAAS,OAAO;GACd,OAAO,KAAK,KAAK;EACnB;EAEA,KAAK,OAAO;EAEZ,IAAI,OAAO,SAAS,GAClB,IAAI,OAAO,WAAW,GACpB,MAAM,OAAO;OACR;GACL,KAAK,MAAM,SAAS,QAClB,QAAQ,MAAM,KAAK;GAErB,MAAM,IAAI,eAAe,QAAQ,sBAAsB;EACzD;CAEJ,CAAC;AACH"}
@@ -1,5 +0,0 @@
1
- //#region src/hooks/tap-memo.d.ts
2
- declare const tapMemo: <T>(fn: () => T, deps: readonly unknown[]) => T;
3
- //#endregion
4
- export { tapMemo };
5
- //# sourceMappingURL=tap-memo.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tap-memo.d.ts","names":[],"sources":["../../src/hooks/tap-memo.ts"],"mappings":";cAWa,OAAA,MAAc,EAAA,QAAU,CAAA,EAAG,IAAA,yBAA2B,CAkBlE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tap-memo.js","names":[],"sources":["../../src/hooks/tap-memo.ts"],"sourcesContent":["import { isDevelopment } from \"../core/helpers/env\";\nimport { getCurrentResourceFiber } from \"../core/helpers/execution-context\";\nimport { tapReducerWithDerivedState } from \"./tap-reducer\";\nimport { depsShallowEqual } from \"./utils/depsShallowEqual\";\n\nconst memoReducer = () => {\n throw new Error(\"Memo reducer should not be called\");\n};\n\ntype MemoState<T> = { value: T; deps: readonly unknown[] };\n\nexport const tapMemo = <T>(fn: () => T, deps: readonly unknown[]): T => {\n const fiber = getCurrentResourceFiber();\n const [state] = tapReducerWithDerivedState(\n memoReducer,\n (state: MemoState<T> | null): MemoState<T> => {\n if (state && depsShallowEqual(state.deps, deps)) return state;\n\n const value = fn();\n\n if (isDevelopment && fiber.devStrictMode) {\n void fn();\n }\n\n return { value, deps };\n },\n null,\n );\n return state.value;\n};\n"],"mappings":";;;;;AAKA,MAAM,oBAAoB;CACxB,MAAM,IAAI,MAAM,mCAAmC;AACrD;AAIA,MAAa,WAAc,IAAa,SAAgC;CACtE,MAAM,QAAQ,wBAAwB;CACtC,MAAM,CAAC,SAAS,2BACd,cACC,UAA6C;EAC5C,IAAI,SAAS,iBAAiB,MAAM,MAAM,IAAI,GAAG,OAAO;EAExD,MAAM,QAAQ,GAAG;EAEjB,IAAI,iBAAiB,MAAM,eACzB,GAAQ;EAGV,OAAO;GAAE;GAAO;EAAK;CACvB,GACA,IACF;CACA,OAAO,MAAM;AACf"}
@@ -1,9 +0,0 @@
1
- //#region src/hooks/tap-reducer.d.ts
2
- type Dispatch<A> = (action: A) => void;
3
- declare function tapReducer<S, A>(reducer: (state: S, action: A) => S, initialState: S): [S, Dispatch<A>];
4
- declare function tapReducer<S, A, I>(reducer: (state: S, action: A) => S, initialArg: I, init: (arg: I) => S): [S, Dispatch<A>];
5
- declare function tapReducerWithDerivedState<S, A, R extends S>(reducer: (state: S, action: A) => S, getDerivedState: (state: S) => R, initialState: S): [R, Dispatch<A>];
6
- declare function tapReducerWithDerivedState<S, A, I, R extends S>(reducer: (state: S, action: A) => S, getDerivedState: (state: S) => R, initialArg: I, init: (arg: I) => S): [R, Dispatch<A>];
7
- //#endregion
8
- export { tapReducer, tapReducerWithDerivedState };
9
- //# sourceMappingURL=tap-reducer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tap-reducer.d.ts","names":[],"sources":["../../src/hooks/tap-reducer.ts"],"mappings":";KAMK,QAAA,OAAe,MAAA,EAAQ,CAAC;AAAA,iBAqGb,UAAA,OACd,OAAA,GAAU,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,KAAM,CAAA,EAClC,YAAA,EAAc,CAAA,IACZ,CAAA,EAAG,QAAA,CAAS,CAAA;AAAA,iBACA,UAAA,UACd,OAAA,GAAU,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,KAAM,CAAA,EAClC,UAAA,EAAY,CAAA,EACZ,IAAA,GAAO,GAAA,EAAK,CAAA,KAAM,CAAA,IAChB,CAAA,EAAG,QAAA,CAAS,CAAA;AAAA,iBAcA,0BAAA,iBAA2C,CAAA,EACzD,OAAA,GAAU,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,KAAM,CAAA,EAClC,eAAA,GAAkB,KAAA,EAAO,CAAA,KAAM,CAAA,EAC/B,YAAA,EAAc,CAAA,IACZ,CAAA,EAAG,QAAA,CAAS,CAAA;AAAA,iBACA,0BAAA,oBAA8C,CAAA,EAC5D,OAAA,GAAU,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,KAAM,CAAA,EAClC,eAAA,GAAkB,KAAA,EAAO,CAAA,KAAM,CAAA,EAC/B,UAAA,EAAY,CAAA,EACZ,IAAA,GAAO,GAAA,EAAK,CAAA,KAAM,CAAA,IAChB,CAAA,EAAG,QAAA,CAAS,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tap-reducer.js","names":[],"sources":["../../src/hooks/tap-reducer.ts"],"sourcesContent":["import { isDevelopment } from \"../core/helpers/env\";\nimport { getCurrentResourceFiber } from \"../core/helpers/execution-context\";\nimport type { ReducerQueueEntry, ResourceFiber } from \"../core/types\";\nimport { markCellDirty } from \"../core/helpers/root\";\nimport { tapHook } from \"./utils/tapHook\";\n\ntype Dispatch<A> = (action: A) => void;\n\nconst dispatchOnFiber = (\n fiber: ResourceFiber<any, any>,\n callback: () => (() => void) | null,\n): void => {\n if (fiber.renderContext) {\n throw new Error(\"Resource updated during render\");\n }\n if (fiber.isNeverMounted) {\n throw new Error(\"Resource updated before mount\");\n }\n\n fiber.root.dispatchUpdate(() => {\n const result = callback();\n if (result) {\n result();\n fiber.root.changelog.push(result);\n return true;\n }\n return false;\n });\n};\n\nfunction tapReducerImpl<S, A, I, R extends S>(\n reducer: (state: S, action: A) => S,\n getDerivedState: ((state: S) => R) | undefined,\n initialArg: S | I,\n initFn: ((arg: I) => S) | undefined,\n): [R, Dispatch<A>] {\n const cell = tapHook(\"reducer\", () => {\n const fiber = getCurrentResourceFiber();\n\n // First render: compute initial state\n const initialState = initFn ? initFn(initialArg as I) : initialArg;\n\n if (isDevelopment && fiber.devStrictMode && initFn) {\n void initFn(initialArg as I);\n }\n\n return {\n type: \"reducer\",\n queue: new Set(),\n dirty: false,\n workInProgress: initialState,\n current: initialState,\n reducer,\n dispatch: (action: A) => {\n const entry: ReducerQueueEntry = {\n action,\n hasEagerState: false,\n eagerState: undefined,\n };\n\n dispatchOnFiber(fiber, () => {\n if (fiber.root.dirtyCells.length === 0 && !entry.hasEagerState) {\n entry.eagerState = reducer(cell.workInProgress, action);\n entry.hasEagerState = true;\n\n if (Object.is(cell.current, entry.eagerState)) return null;\n }\n\n return () => {\n markCellDirty(fiber, cell);\n cell.queue.add(entry);\n };\n });\n },\n };\n });\n\n const fiber = getCurrentResourceFiber();\n const sameReducer = reducer === cell.reducer;\n cell.reducer = reducer;\n\n for (const item of cell.queue) {\n if (!item.hasEagerState || !sameReducer) {\n item.eagerState = reducer(cell.workInProgress, item.action);\n item.hasEagerState = true;\n }\n\n if (isDevelopment && fiber.devStrictMode) {\n void reducer(cell.workInProgress, item.action);\n }\n\n cell.workInProgress = item.eagerState;\n }\n cell.queue.clear();\n\n if (getDerivedState) {\n const derived = getDerivedState(cell.workInProgress);\n\n if (!Object.is(derived, cell.workInProgress)) {\n markCellDirty(fiber, cell);\n cell.workInProgress = derived;\n }\n }\n\n return [cell.workInProgress, cell.dispatch];\n}\n\nexport function tapReducer<S, A>(\n reducer: (state: S, action: A) => S,\n initialState: S,\n): [S, Dispatch<A>];\nexport function tapReducer<S, A, I>(\n reducer: (state: S, action: A) => S,\n initialArg: I,\n init: (arg: I) => S,\n): [S, Dispatch<A>];\nexport function tapReducer<S, A, I>(\n reducer: (state: S, action: A) => S,\n initialArg: S | I,\n init?: (arg: I) => S,\n): [S, Dispatch<A>] {\n return tapReducerImpl(\n reducer,\n undefined,\n initialArg as S,\n init as ((arg: S) => S) | undefined,\n );\n}\n\nexport function tapReducerWithDerivedState<S, A, R extends S>(\n reducer: (state: S, action: A) => S,\n getDerivedState: (state: S) => R,\n initialState: S,\n): [R, Dispatch<A>];\nexport function tapReducerWithDerivedState<S, A, I, R extends S>(\n reducer: (state: S, action: A) => S,\n getDerivedState: (state: S) => R,\n initialArg: I,\n init: (arg: I) => S,\n): [R, Dispatch<A>];\nexport function tapReducerWithDerivedState<S, A, I, R extends S>(\n reducer: (state: S, action: A) => S,\n getDerivedState: (state: S) => R,\n initialArg: I,\n init?: (arg: I) => S,\n): [R, Dispatch<A>] {\n return tapReducerImpl(reducer, getDerivedState, initialArg, init);\n}\n"],"mappings":";;;;;AAQA,MAAM,mBACJ,OACA,aACS;CACT,IAAI,MAAM,eACR,MAAM,IAAI,MAAM,gCAAgC;CAElD,IAAI,MAAM,gBACR,MAAM,IAAI,MAAM,+BAA+B;CAGjD,MAAM,KAAK,qBAAqB;EAC9B,MAAM,SAAS,SAAS;EACxB,IAAI,QAAQ;GACV,OAAO;GACP,MAAM,KAAK,UAAU,KAAK,MAAM;GAChC,OAAO;EACT;EACA,OAAO;CACT,CAAC;AACH;AAEA,SAAS,eACP,SACA,iBACA,YACA,QACkB;CAClB,MAAM,OAAO,QAAQ,iBAAiB;EACpC,MAAM,QAAQ,wBAAwB;EAGtC,MAAM,eAAe,SAAS,OAAO,UAAe,IAAI;EAExD,IAAI,iBAAiB,MAAM,iBAAiB,QAC1C,OAAY,UAAe;EAG7B,OAAO;GACL,MAAM;GACN,uBAAO,IAAI,IAAI;GACf,OAAO;GACP,gBAAgB;GAChB,SAAS;GACT;GACA,WAAW,WAAc;IACvB,MAAM,QAA2B;KAC/B;KACA,eAAe;KACf,YAAY,KAAA;IACd;IAEA,gBAAgB,aAAa;KAC3B,IAAI,MAAM,KAAK,WAAW,WAAW,KAAK,CAAC,MAAM,eAAe;MAC9D,MAAM,aAAa,QAAQ,KAAK,gBAAgB,MAAM;MACtD,MAAM,gBAAgB;MAEtB,IAAI,OAAO,GAAG,KAAK,SAAS,MAAM,UAAU,GAAG,OAAO;KACxD;KAEA,aAAa;MACX,cAAc,OAAO,IAAI;MACzB,KAAK,MAAM,IAAI,KAAK;KACtB;IACF,CAAC;GACH;EACF;CACF,CAAC;CAED,MAAM,QAAQ,wBAAwB;CACtC,MAAM,cAAc,YAAY,KAAK;CACrC,KAAK,UAAU;CAEf,KAAK,MAAM,QAAQ,KAAK,OAAO;EAC7B,IAAI,CAAC,KAAK,iBAAiB,CAAC,aAAa;GACvC,KAAK,aAAa,QAAQ,KAAK,gBAAgB,KAAK,MAAM;GAC1D,KAAK,gBAAgB;EACvB;EAEA,IAAI,iBAAiB,MAAM,eACzB,QAAa,KAAK,gBAAgB,KAAK,MAAM;EAG/C,KAAK,iBAAiB,KAAK;CAC7B;CACA,KAAK,MAAM,MAAM;CAEjB,IAAI,iBAAiB;EACnB,MAAM,UAAU,gBAAgB,KAAK,cAAc;EAEnD,IAAI,CAAC,OAAO,GAAG,SAAS,KAAK,cAAc,GAAG;GAC5C,cAAc,OAAO,IAAI;GACzB,KAAK,iBAAiB;EACxB;CACF;CAEA,OAAO,CAAC,KAAK,gBAAgB,KAAK,QAAQ;AAC5C;AAWA,SAAgB,WACd,SACA,YACA,MACkB;CAClB,OAAO,eACL,SACA,KAAA,GACA,YACA,IACF;AACF;AAaA,SAAgB,2BACd,SACA,iBACA,YACA,MACkB;CAClB,OAAO,eAAe,SAAS,iBAAiB,YAAY,IAAI;AAClE"}
@@ -1,11 +0,0 @@
1
- //#region src/hooks/tap-ref.d.ts
2
- declare namespace tapRef {
3
- interface RefObject<T> {
4
- current: T;
5
- }
6
- }
7
- declare function tapRef<T>(initialValue: T): tapRef.RefObject<T>;
8
- declare function tapRef<T = undefined>(): tapRef.RefObject<T | undefined>;
9
- //#endregion
10
- export { tapRef };
11
- //# sourceMappingURL=tap-ref.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tap-ref.d.ts","names":[],"sources":["../../src/hooks/tap-ref.ts"],"mappings":";kBAEiB,MAAA;EAAA,UACE,SAAA;IACf,OAAA,EAAS,CAAC;EAAA;AAAA;AAAA,iBAIE,MAAA,IAAU,YAAA,EAAc,CAAA,GAAI,MAAA,CAAO,SAAA,CAAU,CAAA;AAAA,iBAC7C,MAAA,mBAAyB,MAAA,CAAO,SAAS,CAAC,CAAA"}