@assistant-ui/tap 0.5.14 → 0.6.0

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 +62 -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 +19 -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 +64 -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
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![bundle size](https://img.shields.io/bundlephobia/minzip/@assistant-ui/tap)](https://bundlephobia.com/package/@assistant-ui/tap)
6
6
  [![GitHub stars](https://img.shields.io/github/stars/assistant-ui/assistant-ui)](https://github.com/assistant-ui/assistant-ui)
7
7
 
8
- Reactive primitives that bring React's hook mental model outside of components. The core has zero runtime dependencies and works in vanilla JS, on a server, or in React via the optional `/react` sub-path. Define self-contained units of state and effects (Resources) using `tapState`, `tapEffect`, `tapMemo`, and friends, and consume them via `useResource`.
8
+ React's hooks, headless. Write a **resource** the same way you write a component, with the same hooks (`useState`, `useEffect`, `useMemo`, ...) imported from `"react"` and the same rules, except a resource returns a plain value instead of JSX. It runs inside a React component, inside another resource, or standalone with no React tree at all.
9
9
 
10
10
  `tap` powers the runtime layer of assistant-ui. Most users do not install it directly; reach for `@assistant-ui/react` instead.
11
11
 
@@ -18,12 +18,13 @@ npm install @assistant-ui/tap
18
18
  ## Usage
19
19
 
20
20
  ```typescript
21
- import { resource, tapState, tapEffect, createResourceRoot } from "@assistant-ui/tap";
21
+ import { resource, createResourceRoot } from "@assistant-ui/tap";
22
+ import { useState, useEffect } from "react";
22
23
 
23
- const Counter = resource(({ incrementBy = 1 }: { incrementBy?: number }) => {
24
- const [count, setCount] = tapState(0);
24
+ const Counter = resource(function Counter({ incrementBy = 1 }: { incrementBy?: number }) {
25
+ const [count, setCount] = useState(0);
25
26
 
26
- tapEffect(() => {
27
+ useEffect(() => {
27
28
  console.log("count:", count);
28
29
  }, [count]);
29
30
 
@@ -43,10 +44,10 @@ const unsubscribe = counter.subscribe(() => {
43
44
  counter.getValue().increment();
44
45
  ```
45
46
 
46
- In React, use the `useResource` hook from the `/react` sub-path:
47
+ In React, host a resource with `useResource`:
47
48
 
48
49
  ```tsx
49
- import { useResource } from "@assistant-ui/tap/react";
50
+ import { useResource } from "@assistant-ui/tap";
50
51
 
51
52
  function CounterButton() {
52
53
  const { count, increment } = useResource(Counter({ incrementBy: 1 }));
@@ -56,7 +57,7 @@ function CounterButton() {
56
57
 
57
58
  ## Hooks
58
59
 
59
- `tapState`, `tapEffect`, `tapMemo`, `tapCallback`, `tapRef` mirror their React counterparts. Additional primitives include `tapResource` and `tapResources` for composition, plus `createResourceContext` / `tap` / `withContextProvider` for context.
60
+ Inside a resource you use React's hooks (`useState`, `useEffect`, `useMemo`, `useCallback`, `useRef`, `use`, ...) imported from `"react"`. tap adds `useResource` / `useResources` / `useResourceRoot` for composition and `createResourceContext` / `withContextProvider` for context.
60
61
 
61
62
  Full API reference at [assistant-ui.com/tap/docs](https://www.assistant-ui.com/tap/docs).
62
63
 
@@ -1 +1 @@
1
- {"version":3,"file":"ResourceFiber.d.ts","names":[],"sources":["../../src/core/ResourceFiber.ts"],"mappings":";;;iBAcgB,mBAAA,OACd,IAAA,EAAM,QAAA,CAAS,CAAA,EAAG,CAAA,GAClB,IAAA,EAAM,iBAAA,EACN,SAAA,6BACA,UAAA,6BACC,aAAA,CAAc,CAAA,EAAG,CAAA;AAAA,iBAeJ,oBAAA,OAA2B,KAAA,EAAO,aAAA,CAAc,CAAA,EAAG,CAAA;AAAA,iBAQnD,mBAAA,OACd,KAAA,EAAO,aAAA,CAAc,CAAA,EAAG,CAAA,GACxB,KAAA,EAAO,CAAA,GACN,YAAA;AAAA,iBAmBa,mBAAA,OACd,KAAA,EAAO,aAAA,CAAc,CAAA,EAAG,CAAA,GACxB,MAAA,EAAQ,YAAA"}
1
+ {"version":3,"file":"ResourceFiber.d.ts","names":[],"sources":["../../src/core/ResourceFiber.ts"],"mappings":";;;iBAegB,mBAAA,OACd,IAAA,EAAM,QAAA,CAAS,CAAA,EAAG,CAAA,GAClB,IAAA,EAAM,iBAAA,EACN,SAAA,6BACA,UAAA,6BACC,aAAA,CAAc,CAAA,EAAG,CAAA;AAAA,iBAeJ,oBAAA,OAA2B,KAAA,EAAO,aAAA,CAAc,CAAA,EAAG,CAAA;AAAA,iBAQnD,mBAAA,OACd,KAAA,EAAO,aAAA,CAAc,CAAA,EAAG,CAAA,GACxB,KAAA,EAAO,CAAA,GACN,YAAA;AAAA,iBAqBa,mBAAA,OACd,KAAA,EAAO,aAAA,CAAc,CAAA,EAAG,CAAA,GACxB,MAAA,EAAQ,YAAA"}
@@ -1,7 +1,8 @@
1
1
  import { callResourceFn } from "./helpers/callResourceFn.js";
2
+ import { cleanupAllEffects, commitAllEffects } from "./helpers/commit.js";
2
3
  import { isDevelopment } from "./helpers/env.js";
3
4
  import { getDevStrictMode, withResourceFiber } from "./helpers/execution-context.js";
4
- import { cleanupAllEffects, commitAllEffects } from "./helpers/commit.js";
5
+ import { withReactDispatcher } from "./react-dispatcher.js";
5
6
  //#region src/core/ResourceFiber.ts
6
7
  function createResourceFiber(type, root, markDirty = void 0, strictMode = getDevStrictMode(false)) {
7
8
  return {
@@ -31,7 +32,7 @@ function renderResourceFiber(fiber, props) {
31
32
  withResourceFiber(fiber, () => {
32
33
  fiber.renderContext = result;
33
34
  try {
34
- result.output = callResourceFn(fiber.type, props);
35
+ result.output = withReactDispatcher(() => callResourceFn(fiber.type, props));
35
36
  } finally {
36
37
  fiber.renderContext = void 0;
37
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ResourceFiber.js","names":[],"sources":["../../src/core/ResourceFiber.ts"],"sourcesContent":["import type {\n ResourceFiber,\n RenderResult,\n Resource,\n ResourceFiberRoot,\n} from \"./types\";\nimport { commitAllEffects, cleanupAllEffects } from \"./helpers/commit\";\nimport {\n getDevStrictMode,\n withResourceFiber,\n} from \"./helpers/execution-context\";\nimport { callResourceFn } from \"./helpers/callResourceFn\";\nimport { isDevelopment } from \"./helpers/env\";\n\nexport function createResourceFiber<R, P>(\n type: Resource<R, P>,\n root: ResourceFiberRoot,\n markDirty: (() => void) | undefined = undefined,\n strictMode: \"root\" | \"child\" | null = getDevStrictMode(false),\n): ResourceFiber<R, P> {\n return {\n type,\n root,\n markDirty,\n devStrictMode: strictMode,\n cells: [],\n currentIndex: 0,\n renderContext: undefined,\n isFirstRender: true,\n isMounted: false,\n isNeverMounted: true,\n };\n}\n\nexport function unmountResourceFiber<R, P>(fiber: ResourceFiber<R, P>): void {\n if (!fiber.isMounted)\n throw new Error(\"Tried to unmount a fiber that is already unmounted\");\n\n fiber.isMounted = false;\n cleanupAllEffects(fiber);\n}\n\nexport function renderResourceFiber<R, P>(\n fiber: ResourceFiber<R, P>,\n props: P,\n): RenderResult {\n const result = {\n effectTasks: [],\n props,\n output: undefined as R | undefined,\n };\n\n withResourceFiber(fiber, () => {\n fiber.renderContext = result;\n try {\n result.output = callResourceFn(fiber.type, props);\n } finally {\n fiber.renderContext = undefined;\n }\n });\n\n return result;\n}\n\nexport function commitResourceFiber<R, P>(\n fiber: ResourceFiber<R, P>,\n result: RenderResult,\n): void {\n fiber.isMounted = true;\n\n if (isDevelopment && fiber.isNeverMounted && fiber.devStrictMode === \"root\") {\n fiber.isNeverMounted = false;\n\n commitAllEffects(result);\n cleanupAllEffects(fiber);\n }\n\n fiber.isNeverMounted = false;\n commitAllEffects(result);\n}\n"],"mappings":";;;;;AAcA,SAAgB,oBACd,MACA,MACA,YAAsC,KAAA,GACtC,aAAsC,iBAAiB,KAAK,GACvC;CACrB,OAAO;EACL;EACA;EACA;EACA,eAAe;EACf,OAAO,CAAC;EACR,cAAc;EACd,eAAe,KAAA;EACf,eAAe;EACf,WAAW;EACX,gBAAgB;CAClB;AACF;AAEA,SAAgB,qBAA2B,OAAkC;CAC3E,IAAI,CAAC,MAAM,WACT,MAAM,IAAI,MAAM,oDAAoD;CAEtE,MAAM,YAAY;CAClB,kBAAkB,KAAK;AACzB;AAEA,SAAgB,oBACd,OACA,OACc;CACd,MAAM,SAAS;EACb,aAAa,CAAC;EACd;EACA,QAAQ,KAAA;CACV;CAEA,kBAAkB,aAAa;EAC7B,MAAM,gBAAgB;EACtB,IAAI;GACF,OAAO,SAAS,eAAe,MAAM,MAAM,KAAK;EAClD,UAAU;GACR,MAAM,gBAAgB,KAAA;EACxB;CACF,CAAC;CAED,OAAO;AACT;AAEA,SAAgB,oBACd,OACA,QACM;CACN,MAAM,YAAY;CAElB,IAAI,iBAAiB,MAAM,kBAAkB,MAAM,kBAAkB,QAAQ;EAC3E,MAAM,iBAAiB;EAEvB,iBAAiB,MAAM;EACvB,kBAAkB,KAAK;CACzB;CAEA,MAAM,iBAAiB;CACvB,iBAAiB,MAAM;AACzB"}
1
+ {"version":3,"file":"ResourceFiber.js","names":[],"sources":["../../src/core/ResourceFiber.ts"],"sourcesContent":["import type {\n ResourceFiber,\n RenderResult,\n Resource,\n ResourceFiberRoot,\n} from \"./types\";\nimport { commitAllEffects, cleanupAllEffects } from \"./helpers/commit\";\nimport {\n getDevStrictMode,\n withResourceFiber,\n} from \"./helpers/execution-context\";\nimport { callResourceFn } from \"./helpers/callResourceFn\";\nimport { withReactDispatcher } from \"./react-dispatcher\";\nimport { isDevelopment } from \"./helpers/env\";\n\nexport function createResourceFiber<R, P>(\n type: Resource<R, P>,\n root: ResourceFiberRoot,\n markDirty: (() => void) | undefined = undefined,\n strictMode: \"root\" | \"child\" | null = getDevStrictMode(false),\n): ResourceFiber<R, P> {\n return {\n type,\n root,\n markDirty,\n devStrictMode: strictMode,\n cells: [],\n currentIndex: 0,\n renderContext: undefined,\n isFirstRender: true,\n isMounted: false,\n isNeverMounted: true,\n };\n}\n\nexport function unmountResourceFiber<R, P>(fiber: ResourceFiber<R, P>): void {\n if (!fiber.isMounted)\n throw new Error(\"Tried to unmount a fiber that is already unmounted\");\n\n fiber.isMounted = false;\n cleanupAllEffects(fiber);\n}\n\nexport function renderResourceFiber<R, P>(\n fiber: ResourceFiber<R, P>,\n props: P,\n): RenderResult {\n const result = {\n effectTasks: [],\n props,\n output: undefined as R | undefined,\n };\n\n withResourceFiber(fiber, () => {\n fiber.renderContext = result;\n try {\n result.output = withReactDispatcher(() =>\n callResourceFn(fiber.type, props),\n );\n } finally {\n fiber.renderContext = undefined;\n }\n });\n\n return result;\n}\n\nexport function commitResourceFiber<R, P>(\n fiber: ResourceFiber<R, P>,\n result: RenderResult,\n): void {\n fiber.isMounted = true;\n\n if (isDevelopment && fiber.isNeverMounted && fiber.devStrictMode === \"root\") {\n fiber.isNeverMounted = false;\n\n commitAllEffects(result);\n cleanupAllEffects(fiber);\n }\n\n fiber.isNeverMounted = false;\n commitAllEffects(result);\n}\n"],"mappings":";;;;;;AAeA,SAAgB,oBACd,MACA,MACA,YAAsC,KAAA,GACtC,aAAsC,iBAAiB,KAAK,GACvC;CACrB,OAAO;EACL;EACA;EACA;EACA,eAAe;EACf,OAAO,CAAC;EACR,cAAc;EACd,eAAe,KAAA;EACf,eAAe;EACf,WAAW;EACX,gBAAgB;CAClB;AACF;AAEA,SAAgB,qBAA2B,OAAkC;CAC3E,IAAI,CAAC,MAAM,WACT,MAAM,IAAI,MAAM,oDAAoD;CAEtE,MAAM,YAAY;CAClB,kBAAkB,KAAK;AACzB;AAEA,SAAgB,oBACd,OACA,OACc;CACd,MAAM,SAAS;EACb,aAAa,CAAC;EACd;EACA,QAAQ,KAAA;CACV;CAEA,kBAAkB,aAAa;EAC7B,MAAM,gBAAgB;EACtB,IAAI;GACF,OAAO,SAAS,0BACd,eAAe,MAAM,MAAM,KAAK,CAClC;EACF,UAAU;GACR,MAAM,gBAAgB,KAAA;EACxB;CACF,CAAC;CAED,OAAO;AACT;AAEA,SAAgB,oBACd,OACA,QACM;CACN,MAAM,YAAY;CAElB,IAAI,iBAAiB,MAAM,kBAAkB,MAAM,kBAAkB,QAAQ;EAC3E,MAAM,iBAAiB;EAEvB,iBAAiB,MAAM;EACvB,kBAAkB,KAAK;CACzB;CAEA,MAAM,iBAAiB;CACvB,iBAAiB,MAAM;AACzB"}
@@ -1,11 +1,18 @@
1
+ import { Context } from "react";
2
+
1
3
  //#region src/core/context.d.ts
2
- declare const contextValue: unique symbol;
3
- type Context<T> = {
4
- [contextValue]: T;
5
- };
4
+ /**
5
+ * @deprecated experimental — the resource context API is not yet stable and may
6
+ * change or be removed in a future release.
7
+ */
6
8
  declare const createResourceContext: <T>(defaultValue: T) => Context<T>;
9
+ declare const isResourceContext: (value: unknown) => boolean;
10
+ /**
11
+ * @deprecated experimental — the resource context API is not yet stable and may
12
+ * change or be removed in a future release.
13
+ */
7
14
  declare const withContextProvider: <T, TResult>(context: Context<T>, value: T, fn: () => TResult) => TResult;
8
- declare const tap: <T>(context: Context<T>) => T;
15
+ declare const useResourceContext: <T>(context: Context<T>) => T;
9
16
  //#endregion
10
- export { createResourceContext, tap, withContextProvider };
17
+ export { createResourceContext, isResourceContext, useResourceContext, withContextProvider };
11
18
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","names":[],"sources":["../../src/core/context.ts"],"mappings":";cAAM,YAAA;AAAA,KACD,OAAA;EAAA,CACF,YAAY,GAAG,CAAA;AAAA;AAAA,cAGL,qBAAA,MAA4B,YAAA,EAAc,CAAA,KAAI,OAAA,CAAQ,CAAA;AAAA,cAMtD,mBAAA,eACX,OAAA,EAAS,OAAA,CAAQ,CAAA,GACjB,KAAA,EAAO,CAAA,EACP,EAAA,QAAU,OAAA,KAAO,OAAA;AAAA,cAWN,GAAA,MAAU,OAAA,EAAS,OAAA,CAAQ,CAAA,MAAE,CAAA"}
1
+ {"version":3,"file":"context.d.ts","names":[],"sources":["../../src/core/context.ts"],"mappings":";;;;;AAkBA;;cAAa,qBAAA,MAA4B,YAAA,EAAc,CAAA,KAAI,OAAA,CAAa,CAAA;AAAA,cAM3D,iBAAA,GAAqB,KAAc;;;;;cAQnC,mBAAA,eACX,OAAA,EAAS,OAAA,CAAa,CAAA,GACtB,KAAA,EAAO,CAAA,EACP,EAAA,QAAU,OAAA,KAAO,OAAA;AAAA,cAYN,kBAAA,MAAyB,OAAA,EAAS,OAAA,CAAa,CAAA,MAAE,CAAA"}
@@ -1,21 +1,34 @@
1
1
  //#region src/core/context.ts
2
2
  const contextValue = Symbol("tap.Context");
3
+ const asTap = (context) => context;
4
+ /**
5
+ * @deprecated experimental — the resource context API is not yet stable and may
6
+ * change or be removed in a future release.
7
+ */
3
8
  const createResourceContext = (defaultValue) => {
4
9
  return { [contextValue]: defaultValue };
5
10
  };
11
+ const isResourceContext = (value) => {
12
+ return typeof value === "object" && value !== null && contextValue in value;
13
+ };
14
+ /**
15
+ * @deprecated experimental — the resource context API is not yet stable and may
16
+ * change or be removed in a future release.
17
+ */
6
18
  const withContextProvider = (context, value, fn) => {
7
- const previousValue = context[contextValue];
8
- context[contextValue] = value;
19
+ const tapContext = asTap(context);
20
+ const previousValue = tapContext[contextValue];
21
+ tapContext[contextValue] = value;
9
22
  try {
10
23
  return fn();
11
24
  } finally {
12
- context[contextValue] = previousValue;
25
+ tapContext[contextValue] = previousValue;
13
26
  }
14
27
  };
15
- const tap = (context) => {
16
- return context[contextValue];
28
+ const useResourceContext = (context) => {
29
+ return asTap(context)[contextValue];
17
30
  };
18
31
  //#endregion
19
- export { createResourceContext, tap, withContextProvider };
32
+ export { createResourceContext, isResourceContext, useResourceContext, withContextProvider };
20
33
 
21
34
  //# sourceMappingURL=context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","names":[],"sources":["../../src/core/context.ts"],"sourcesContent":["const contextValue: unique symbol = Symbol(\"tap.Context\");\ntype Context<T> = {\n [contextValue]: T;\n};\n\nexport const createResourceContext = <T>(defaultValue: T): Context<T> => {\n return {\n [contextValue]: defaultValue,\n };\n};\n\nexport const withContextProvider = <T, TResult>(\n context: Context<T>,\n value: T,\n fn: () => TResult,\n) => {\n const previousValue = context[contextValue];\n context[contextValue] = value;\n try {\n return fn();\n } finally {\n context[contextValue] = previousValue;\n }\n};\n\nexport const tap = <T>(context: Context<T>) => {\n return context[contextValue];\n};\n"],"mappings":";AAAA,MAAM,eAA8B,OAAO,aAAa;AAKxD,MAAa,yBAA4B,iBAAgC;CACvE,OAAO,GACJ,eAAe,aAClB;AACF;AAEA,MAAa,uBACX,SACA,OACA,OACG;CACH,MAAM,gBAAgB,QAAQ;CAC9B,QAAQ,gBAAgB;CACxB,IAAI;EACF,OAAO,GAAG;CACZ,UAAU;EACR,QAAQ,gBAAgB;CAC1B;AACF;AAEA,MAAa,OAAU,YAAwB;CAC7C,OAAO,QAAQ;AACjB"}
1
+ {"version":3,"file":"context.js","names":[],"sources":["../../src/core/context.ts"],"sourcesContent":["import type { Context as ReactContext } from \"react\";\n\nconst contextValue: unique symbol = Symbol(\"tap.Context\");\ntype TapContext<T> = {\n [contextValue]: T;\n};\n\nconst asTap = <T>(context: ReactContext<T>): TapContext<T> =>\n context as unknown as TapContext<T>;\n\n// A tap resource context is typed as a React `Context<T>` purely so React's\n// `use(context)` accepts it (the type is erased, so this adds no runtime react\n// dependency). At runtime it is only a branded `{ [contextValue]: T }` and is\n// not a usable React context — `use()` routes it to `useResourceContext()` via the brand.\n/**\n * @deprecated experimental — the resource context API is not yet stable and may\n * change or be removed in a future release.\n */\nexport const createResourceContext = <T>(defaultValue: T): ReactContext<T> => {\n return {\n [contextValue]: defaultValue,\n } as unknown as ReactContext<T>;\n};\n\nexport const isResourceContext = (value: unknown): boolean => {\n return typeof value === \"object\" && value !== null && contextValue in value;\n};\n\n/**\n * @deprecated experimental — the resource context API is not yet stable and may\n * change or be removed in a future release.\n */\nexport const withContextProvider = <T, TResult>(\n context: ReactContext<T>,\n value: T,\n fn: () => TResult,\n) => {\n const tapContext = asTap(context);\n const previousValue = tapContext[contextValue];\n tapContext[contextValue] = value;\n try {\n return fn();\n } finally {\n tapContext[contextValue] = previousValue;\n }\n};\n\nexport const useResourceContext = <T>(context: ReactContext<T>) => {\n return asTap(context)[contextValue];\n};\n"],"mappings":";AAEA,MAAM,eAA8B,OAAO,aAAa;AAKxD,MAAM,SAAY,YAChB;;;;;AAUF,MAAa,yBAA4B,iBAAqC;CAC5E,OAAO,GACJ,eAAe,aAClB;AACF;AAEA,MAAa,qBAAqB,UAA4B;CAC5D,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,gBAAgB;AACxE;;;;;AAMA,MAAa,uBACX,SACA,OACA,OACG;CACH,MAAM,aAAa,MAAM,OAAO;CAChC,MAAM,gBAAgB,WAAW;CACjC,WAAW,gBAAgB;CAC3B,IAAI;EACF,OAAO,GAAG;CACZ,UAAU;EACR,WAAW,gBAAgB;CAC7B;AACF;AAEA,MAAa,sBAAyB,YAA6B;CACjE,OAAO,MAAM,OAAO,CAAC,CAAC;AACxB"}
@@ -1,8 +1,9 @@
1
1
  import { ResourceElement } from "./types.js";
2
+ import { useResourceRoot } from "../hooks/useResourceRoot.js";
2
3
 
3
4
  //#region src/core/createResourceRoot.d.ts
4
5
  declare const createResourceRoot: () => {
5
- render: <R, P>(element: ResourceElement<R, P>) => any;
6
+ render: <R, P>(element: ResourceElement<R, P>) => useResourceRoot.SubscribableResource<R>;
6
7
  unmount: () => void;
7
8
  };
8
9
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"createResourceRoot.d.ts","names":[],"sources":["../../src/core/createResourceRoot.ts"],"mappings":";;;cAea,kBAAA;iBAqBI,OAAA,EAAW,eAAA,CAAgB,CAAA,EAAG,CAAA"}
1
+ {"version":3,"file":"createResourceRoot.d.ts","names":[],"sources":["../../src/core/createResourceRoot.ts"],"mappings":";;;;cAea,kBAAA;iBAqBI,OAAA,EAAW,eAAA,CAAgB,CAAA,EAAG,CAAA,MAUjB,eAAA,CAAgB,oBAAA,CAAqB,CAAA"}
@@ -3,9 +3,9 @@ import { isDevelopment } from "./helpers/env.js";
3
3
  import { createResourceFiberRoot } from "./helpers/root.js";
4
4
  import { commitResourceFiber, createResourceFiber, renderResourceFiber, unmountResourceFiber } from "./ResourceFiber.js";
5
5
  import { UpdateScheduler, flushResourcesSync } from "./scheduler.js";
6
- import { tapResourceRoot } from "../tapResourceRoot.js";
6
+ import { useResourceRoot } from "../hooks/useResourceRoot.js";
7
7
  //#region src/core/createResourceRoot.ts
8
- const SubscribableResource = resource(tapResourceRoot);
8
+ const SubscribableResource = resource(useResourceRoot);
9
9
  const createResourceRoot = () => {
10
10
  const fiber = createResourceFiber(SubscribableResource, createResourceFiberRoot((callback) => {
11
11
  new UpdateScheduler(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"createResourceRoot.js","names":[],"sources":["../../src/core/createResourceRoot.ts"],"sourcesContent":["import type { ResourceElement } from \"./types\";\nimport {\n createResourceFiber,\n unmountResourceFiber,\n renderResourceFiber,\n commitResourceFiber,\n} from \"./ResourceFiber\";\nimport { tapResourceRoot } from \"../tapResourceRoot\";\nimport { resource } from \"./resource\";\nimport { isDevelopment } from \"./helpers/env\";\nimport { flushResourcesSync, UpdateScheduler } from \"./scheduler\";\nimport { createResourceFiberRoot } from \"./helpers/root\";\n\nconst SubscribableResource = resource(tapResourceRoot);\n\nexport const createResourceRoot = () => {\n const fiber = createResourceFiber<\n tapResourceRoot.SubscribableResource<any>,\n ResourceElement<any>\n >(\n SubscribableResource,\n createResourceFiberRoot((callback) => {\n new UpdateScheduler(() => {\n if (callback()) {\n throw new Error(\n \"Unexpected rerender of createResourceRoot outer fiber\",\n );\n }\n return false;\n }).markDirty();\n }),\n undefined,\n isDevelopment ? \"root\" : null,\n );\n\n return {\n render: <R, P>(element: ResourceElement<R, P>) => {\n // In strict mode, render twice to detect side effects\n if (isDevelopment && fiber.devStrictMode === \"root\") {\n void renderResourceFiber(fiber, element);\n }\n\n const render = renderResourceFiber(fiber, element);\n\n flushResourcesSync(() => commitResourceFiber(fiber, render));\n\n return render.output;\n },\n unmount: () => {\n unmountResourceFiber(fiber);\n },\n };\n};\n"],"mappings":";;;;;;;AAaA,MAAM,uBAAuB,SAAS,eAAe;AAErD,MAAa,2BAA2B;CACtC,MAAM,QAAQ,oBAIZ,sBACA,yBAAyB,aAAa;EACpC,IAAI,sBAAsB;GACxB,IAAI,SAAS,GACX,MAAM,IAAI,MACR,uDACF;GAEF,OAAO;EACT,CAAC,EAAE,UAAU;CACf,CAAC,GACD,KAAA,GACA,gBAAgB,SAAS,IAC3B;CAEA,OAAO;EACL,SAAe,YAAmC;GAEhD,IAAI,iBAAiB,MAAM,kBAAkB,QAC3C,oBAAyB,OAAO,OAAO;GAGzC,MAAM,SAAS,oBAAoB,OAAO,OAAO;GAEjD,yBAAyB,oBAAoB,OAAO,MAAM,CAAC;GAE3D,OAAO,OAAO;EAChB;EACA,eAAe;GACb,qBAAqB,KAAK;EAC5B;CACF;AACF"}
1
+ {"version":3,"file":"createResourceRoot.js","names":[],"sources":["../../src/core/createResourceRoot.ts"],"sourcesContent":["import type { ResourceElement } from \"./types\";\nimport {\n createResourceFiber,\n unmountResourceFiber,\n renderResourceFiber,\n commitResourceFiber,\n} from \"./ResourceFiber\";\nimport { useResourceRoot } from \"../hooks/useResourceRoot\";\nimport { resource } from \"./resource\";\nimport { isDevelopment } from \"./helpers/env\";\nimport { flushResourcesSync, UpdateScheduler } from \"./scheduler\";\nimport { createResourceFiberRoot } from \"./helpers/root\";\n\nconst SubscribableResource = resource(useResourceRoot);\n\nexport const createResourceRoot = () => {\n const fiber = createResourceFiber<\n useResourceRoot.SubscribableResource<any>,\n ResourceElement<any>\n >(\n SubscribableResource,\n createResourceFiberRoot((callback) => {\n new UpdateScheduler(() => {\n if (callback()) {\n throw new Error(\n \"Unexpected rerender of createResourceRoot outer fiber\",\n );\n }\n return false;\n }).markDirty();\n }),\n undefined,\n isDevelopment ? \"root\" : null,\n );\n\n return {\n render: <R, P>(element: ResourceElement<R, P>) => {\n // In strict mode, render twice to detect side effects\n if (isDevelopment && fiber.devStrictMode === \"root\") {\n void renderResourceFiber(fiber, element);\n }\n\n const render = renderResourceFiber(fiber, element);\n\n flushResourcesSync(() => commitResourceFiber(fiber, render));\n\n return render.output as useResourceRoot.SubscribableResource<R>;\n },\n unmount: () => {\n unmountResourceFiber(fiber);\n },\n };\n};\n"],"mappings":";;;;;;;AAaA,MAAM,uBAAuB,SAAS,eAAe;AAErD,MAAa,2BAA2B;CACtC,MAAM,QAAQ,oBAIZ,sBACA,yBAAyB,aAAa;EACpC,IAAI,sBAAsB;GACxB,IAAI,SAAS,GACX,MAAM,IAAI,MACR,uDACF;GAEF,OAAO;EACT,CAAC,CAAC,CAAC,UAAU;CACf,CAAC,GACD,KAAA,GACA,gBAAgB,SAAS,IAC3B;CAEA,OAAO;EACL,SAAe,YAAmC;GAEhD,IAAI,iBAAiB,MAAM,kBAAkB,QAC3C,oBAAyB,OAAO,OAAO;GAGzC,MAAM,SAAS,oBAAoB,OAAO,OAAO;GAEjD,yBAAyB,oBAAoB,OAAO,MAAM,CAAC;GAE3D,OAAO,OAAO;EAChB;EACA,eAAe;GACb,qBAAqB,KAAK;EAC5B;CACF;AACF"}
@@ -3,7 +3,8 @@ import { ResourceFiber } from "../types.js";
3
3
  //#region src/core/helpers/execution-context.d.ts
4
4
  declare function withResourceFiber<R, P>(fiber: ResourceFiber<R, P>, fn: () => void): void;
5
5
  declare function getCurrentResourceFiber(): ResourceFiber<unknown, unknown>;
6
+ declare function peekResourceFiber(): ResourceFiber<unknown, unknown> | null;
6
7
  declare function getDevStrictMode(enable: boolean): "root" | "child" | null;
7
8
  //#endregion
8
- export { getCurrentResourceFiber, getDevStrictMode, withResourceFiber };
9
+ export { getCurrentResourceFiber, getDevStrictMode, peekResourceFiber, withResourceFiber };
9
10
  //# sourceMappingURL=execution-context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"execution-context.d.ts","names":[],"sources":["../../../src/core/helpers/execution-context.ts"],"mappings":";;;iBAKgB,iBAAA,OACd,KAAA,EAAO,aAAA,CAAc,CAAA,EAAG,CAAA,GACxB,EAAA;AAAA,iBAsBc,uBAAA,IAA2B,aAAa;AAAA,iBAOxC,gBAAA,CAAiB,MAAe"}
1
+ {"version":3,"file":"execution-context.d.ts","names":[],"sources":["../../../src/core/helpers/execution-context.ts"],"mappings":";;;iBAKgB,iBAAA,OACd,KAAA,EAAO,aAAA,CAAc,CAAA,EAAG,CAAA,GACxB,EAAA;AAAA,iBAsBc,uBAAA,IAA2B,aAAa;AAAA,iBAOxC,iBAAA,IAAqB,aAAa;AAAA,iBAIlC,gBAAA,CAAiB,MAAe"}
@@ -17,12 +17,15 @@ function getCurrentResourceFiber() {
17
17
  if (!currentResourceFiber) throw new Error("No resource fiber available");
18
18
  return currentResourceFiber;
19
19
  }
20
+ function peekResourceFiber() {
21
+ return currentResourceFiber;
22
+ }
20
23
  function getDevStrictMode(enable) {
21
24
  if (!isDevelopment) return null;
22
25
  if (currentResourceFiber?.devStrictMode) return currentResourceFiber.isFirstRender ? "child" : "root";
23
26
  return enable ? "root" : null;
24
27
  }
25
28
  //#endregion
26
- export { getCurrentResourceFiber, getDevStrictMode, withResourceFiber };
29
+ export { getCurrentResourceFiber, getDevStrictMode, peekResourceFiber, withResourceFiber };
27
30
 
28
31
  //# sourceMappingURL=execution-context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"execution-context.js","names":[],"sources":["../../../src/core/helpers/execution-context.ts"],"sourcesContent":["import { isDevelopment } from \"./env\";\nimport type { ResourceFiber } from \"../types\";\n\nlet currentResourceFiber: ResourceFiber<any, any> | null = null;\n\nexport function withResourceFiber<R, P>(\n fiber: ResourceFiber<R, P>,\n fn: () => void,\n): void {\n fiber.currentIndex = 0;\n\n const previousContext = currentResourceFiber;\n currentResourceFiber = fiber;\n try {\n fn();\n\n fiber.isFirstRender = false;\n\n // ensure hook count matches\n if (fiber.cells.length !== fiber.currentIndex) {\n throw new Error(\n `Rendered ${fiber.currentIndex} hooks but expected ${fiber.cells.length}. ` +\n \"Hooks must be called in the exact same order in every render.\",\n );\n }\n } finally {\n currentResourceFiber = previousContext;\n }\n}\nexport function getCurrentResourceFiber(): ResourceFiber<unknown, unknown> {\n if (!currentResourceFiber) {\n throw new Error(\"No resource fiber available\");\n }\n return currentResourceFiber;\n}\n\nexport function getDevStrictMode(enable: boolean) {\n if (!isDevelopment) return null;\n if (currentResourceFiber?.devStrictMode)\n return currentResourceFiber.isFirstRender ? \"child\" : \"root\";\n\n return enable ? \"root\" : null;\n}\n"],"mappings":";;AAGA,IAAI,uBAAuD;AAE3D,SAAgB,kBACd,OACA,IACM;CACN,MAAM,eAAe;CAErB,MAAM,kBAAkB;CACxB,uBAAuB;CACvB,IAAI;EACF,GAAG;EAEH,MAAM,gBAAgB;EAGtB,IAAI,MAAM,MAAM,WAAW,MAAM,cAC/B,MAAM,IAAI,MACR,YAAY,MAAM,aAAa,sBAAsB,MAAM,MAAM,OAAO,gEAE1E;CAEJ,UAAU;EACR,uBAAuB;CACzB;AACF;AACA,SAAgB,0BAA2D;CACzE,IAAI,CAAC,sBACH,MAAM,IAAI,MAAM,6BAA6B;CAE/C,OAAO;AACT;AAEA,SAAgB,iBAAiB,QAAiB;CAChD,IAAI,CAAC,eAAe,OAAO;CAC3B,IAAI,sBAAsB,eACxB,OAAO,qBAAqB,gBAAgB,UAAU;CAExD,OAAO,SAAS,SAAS;AAC3B"}
1
+ {"version":3,"file":"execution-context.js","names":[],"sources":["../../../src/core/helpers/execution-context.ts"],"sourcesContent":["import { isDevelopment } from \"./env\";\nimport type { ResourceFiber } from \"../types\";\n\nlet currentResourceFiber: ResourceFiber<any, any> | null = null;\n\nexport function withResourceFiber<R, P>(\n fiber: ResourceFiber<R, P>,\n fn: () => void,\n): void {\n fiber.currentIndex = 0;\n\n const previousContext = currentResourceFiber;\n currentResourceFiber = fiber;\n try {\n fn();\n\n fiber.isFirstRender = false;\n\n // ensure hook count matches\n if (fiber.cells.length !== fiber.currentIndex) {\n throw new Error(\n `Rendered ${fiber.currentIndex} hooks but expected ${fiber.cells.length}. ` +\n \"Hooks must be called in the exact same order in every render.\",\n );\n }\n } finally {\n currentResourceFiber = previousContext;\n }\n}\nexport function getCurrentResourceFiber(): ResourceFiber<unknown, unknown> {\n if (!currentResourceFiber) {\n throw new Error(\"No resource fiber available\");\n }\n return currentResourceFiber;\n}\n\nexport function peekResourceFiber(): ResourceFiber<unknown, unknown> | null {\n return currentResourceFiber;\n}\n\nexport function getDevStrictMode(enable: boolean) {\n if (!isDevelopment) return null;\n if (currentResourceFiber?.devStrictMode)\n return currentResourceFiber.isFirstRender ? \"child\" : \"root\";\n\n return enable ? \"root\" : null;\n}\n"],"mappings":";;AAGA,IAAI,uBAAuD;AAE3D,SAAgB,kBACd,OACA,IACM;CACN,MAAM,eAAe;CAErB,MAAM,kBAAkB;CACxB,uBAAuB;CACvB,IAAI;EACF,GAAG;EAEH,MAAM,gBAAgB;EAGtB,IAAI,MAAM,MAAM,WAAW,MAAM,cAC/B,MAAM,IAAI,MACR,YAAY,MAAM,aAAa,sBAAsB,MAAM,MAAM,OAAO,gEAE1E;CAEJ,UAAU;EACR,uBAAuB;CACzB;AACF;AACA,SAAgB,0BAA2D;CACzE,IAAI,CAAC,sBACH,MAAM,IAAI,MAAM,6BAA6B;CAE/C,OAAO;AACT;AAEA,SAAgB,oBAA4D;CAC1E,OAAO;AACT;AAEA,SAAgB,iBAAiB,QAAiB;CAChD,IAAI,CAAC,eAAe,OAAO;CAC3B,IAAI,sBAAsB,eACxB,OAAO,qBAAqB,gBAAgB,UAAU;CAExD,OAAO,SAAS,SAAS;AAC3B"}
@@ -0,0 +1,12 @@
1
+ //#region src/core/react-dispatcher.d.ts
2
+ /**
3
+ * Runs a resource body with tap's React dispatcher installed, so real React
4
+ * hooks called inside it (`import { useState } from "react"`) route to tap, then
5
+ * restores the previous dispatcher. If React's internal dispatcher slot can't be
6
+ * found (an unsupported React version), the body runs unchanged and `react`
7
+ * hooks inside it keep throwing React's "invalid hook call".
8
+ */
9
+ declare function withReactDispatcher<T>(render: () => T): T;
10
+ //#endregion
11
+ export { withReactDispatcher };
12
+ //# sourceMappingURL=react-dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-dispatcher.d.ts","names":[],"sources":["../../src/core/react-dispatcher.ts"],"mappings":";;AAmEA;;;;;;iBAAgB,mBAAA,IAAuB,MAAA,QAAc,CAAA,GAAI,CAAC"}
@@ -0,0 +1,62 @@
1
+ import { useReducer as useReducer$1 } from "../hooks/useReducer.js";
2
+ import { useState as useState$1 } from "../hooks/useState.js";
3
+ import { useRef as useRef$1 } from "../hooks/useRef.js";
4
+ import { useMemo as useMemo$1 } from "../hooks/useMemo.js";
5
+ import { useCallback } from "../hooks/useCallback.js";
6
+ import { useEffect } from "../hooks/useEffect.js";
7
+ import { useEffectEvent } from "../hooks/useEffectEvent.js";
8
+ import { use } from "../hooks/use.js";
9
+ import { useMemoCache } from "../hooks/useMemoCache.js";
10
+ import * as React from "react";
11
+ //#region src/core/react-dispatcher.ts
12
+ const tapDispatcher = {
13
+ useState: useState$1,
14
+ useReducer: useReducer$1,
15
+ useRef: useRef$1,
16
+ useMemo: useMemo$1,
17
+ useCallback,
18
+ useEffect,
19
+ useLayoutEffect: useEffect,
20
+ useInsertionEffect: useEffect,
21
+ useEffectEvent,
22
+ useContext: use,
23
+ use,
24
+ useMemoCache
25
+ };
26
+ const internals = React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE ?? React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
27
+ const slot = internals == null ? null : "H" in internals ? {
28
+ get current() {
29
+ return internals.H;
30
+ },
31
+ set current(d) {
32
+ internals.H = d;
33
+ }
34
+ } : "ReactCurrentDispatcher" in internals ? {
35
+ get current() {
36
+ return internals.ReactCurrentDispatcher.current;
37
+ },
38
+ set current(d) {
39
+ internals.ReactCurrentDispatcher.current = d;
40
+ }
41
+ } : null;
42
+ /**
43
+ * Runs a resource body with tap's React dispatcher installed, so real React
44
+ * hooks called inside it (`import { useState } from "react"`) route to tap, then
45
+ * restores the previous dispatcher. If React's internal dispatcher slot can't be
46
+ * found (an unsupported React version), the body runs unchanged and `react`
47
+ * hooks inside it keep throwing React's "invalid hook call".
48
+ */
49
+ function withReactDispatcher(render) {
50
+ if (!slot) return render();
51
+ const previous = slot.current;
52
+ slot.current = tapDispatcher;
53
+ try {
54
+ return render();
55
+ } finally {
56
+ slot.current = previous;
57
+ }
58
+ }
59
+ //#endregion
60
+ export { withReactDispatcher };
61
+
62
+ //# sourceMappingURL=react-dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-dispatcher.js","names":[],"sources":["../../src/core/react-dispatcher.ts"],"sourcesContent":["import * as React from \"react\";\nimport { useState } from \"../hooks/useState\";\nimport { useReducer } from \"../hooks/useReducer\";\nimport { useRef } from \"../hooks/useRef\";\nimport { useMemo } from \"../hooks/useMemo\";\nimport { useCallback } from \"../hooks/useCallback\";\nimport { useEffect } from \"../hooks/useEffect\";\nimport { useEffectEvent } from \"../hooks/useEffectEvent\";\nimport { use } from \"../hooks/use\";\nimport { useMemoCache } from \"../hooks/useMemoCache\";\n\n// The dispatcher React reads while a resource renders, so hooks imported from\n// \"react\" route to tap with no build step. Hooks tap has no equivalent for are\n// intentionally absent: calling one throws, which is the intended \"unsupported\n// in a resource\" signal.\nconst tapDispatcher = {\n useState,\n useReducer,\n useRef,\n useMemo,\n useCallback,\n useEffect,\n useLayoutEffect: useEffect,\n useInsertionEffect: useEffect,\n useEffectEvent,\n useContext: use,\n use,\n useMemoCache,\n};\n\n// React's live dispatcher slot differs by version: React 19 exposes it as `H` on\n// the client internals object; React 18 as `ReactCurrentDispatcher.current`.\nconst internals =\n (React as any)\n .__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE ??\n (React as any).__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;\n\nconst slot: { current: unknown } | null =\n internals == null\n ? null\n : \"H\" in internals\n ? {\n get current() {\n return internals.H;\n },\n set current(d) {\n internals.H = d;\n },\n }\n : \"ReactCurrentDispatcher\" in internals\n ? {\n get current() {\n return internals.ReactCurrentDispatcher.current;\n },\n set current(d) {\n internals.ReactCurrentDispatcher.current = d;\n },\n }\n : null;\n\n/**\n * Runs a resource body with tap's React dispatcher installed, so real React\n * hooks called inside it (`import { useState } from \"react\"`) route to tap, then\n * restores the previous dispatcher. If React's internal dispatcher slot can't be\n * found (an unsupported React version), the body runs unchanged and `react`\n * hooks inside it keep throwing React's \"invalid hook call\".\n */\nexport function withReactDispatcher<T>(render: () => T): T {\n if (!slot) return render();\n\n const previous = slot.current;\n slot.current = tapDispatcher;\n try {\n return render();\n } finally {\n slot.current = previous;\n }\n}\n"],"mappings":";;;;;;;;;;;AAeA,MAAM,gBAAgB;CACpB,UAAA;CACA,YAAA;CACA,QAAA;CACA,SAAA;CACA;CACA;CACA,iBAAiB;CACjB,oBAAoB;CACpB;CACA,YAAY;CACZ;CACA;AACF;AAIA,MAAM,YACH,MACE,mEACF,MAAc;AAEjB,MAAM,OACJ,aAAa,OACT,OACA,OAAO,YACL;CACE,IAAI,UAAU;EACZ,OAAO,UAAU;CACnB;CACA,IAAI,QAAQ,GAAG;EACb,UAAU,IAAI;CAChB;AACF,IACA,4BAA4B,YAC1B;CACE,IAAI,UAAU;EACZ,OAAO,UAAU,uBAAuB;CAC1C;CACA,IAAI,QAAQ,GAAG;EACb,UAAU,uBAAuB,UAAU;CAC7C;AACF,IACA;;;;;;;;AASV,SAAgB,oBAAuB,QAAoB;CACzD,IAAI,CAAC,MAAM,OAAO,OAAO;CAEzB,MAAM,WAAW,KAAK;CACtB,KAAK,UAAU;CACf,IAAI;EACF,OAAO,OAAO;CAChB,UAAU;EACR,KAAK,UAAU;CACjB;AACF"}
@@ -36,7 +36,7 @@ const flushScheduled = () => {
36
36
  flushState.schedulers.delete(scheduler);
37
37
  if (!scheduler.isDirty) continue;
38
38
  flushDepth++;
39
- if (flushDepth > MAX_FLUSH_LIMIT) throw new Error("Maximum update depth exceeded. This can happen when a resource repeatedly calls setState inside tapEffect.");
39
+ if (flushDepth > MAX_FLUSH_LIMIT) throw new Error("Maximum update depth exceeded. This can happen when a resource repeatedly calls setState inside useEffect.");
40
40
  try {
41
41
  scheduler.runTask();
42
42
  } catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.js","names":[],"sources":["../../src/core/scheduler.ts"],"sourcesContent":["type Task = () => void;\n\ntype GlobalFlushState = {\n schedulers: Set<UpdateScheduler>;\n isScheduled: boolean;\n};\n\nconst MAX_FLUSH_LIMIT = 50;\nlet flushState: GlobalFlushState = {\n schedulers: new Set([]),\n isScheduled: false,\n};\n\nexport class UpdateScheduler {\n private _isDirty = false;\n\n constructor(private readonly _task: Task) {}\n\n get isDirty() {\n return this._isDirty;\n }\n\n markDirty() {\n this._isDirty = true;\n\n flushState.schedulers.add(this);\n scheduleFlush();\n }\n\n runTask() {\n this._isDirty = false;\n this._task();\n }\n}\n\nconst scheduleFlush = () => {\n if (flushState.isScheduled) return;\n flushState.isScheduled = true;\n scheduleMacrotask();\n};\n\nconst flushScheduled = () => {\n try {\n const errors = [];\n let flushDepth = 0;\n\n for (const scheduler of flushState.schedulers) {\n flushState.schedulers.delete(scheduler);\n if (!scheduler.isDirty) continue;\n\n flushDepth++;\n\n if (flushDepth > MAX_FLUSH_LIMIT) {\n throw new Error(\n `Maximum update depth exceeded. This can happen when a resource ` +\n `repeatedly calls setState inside tapEffect.`,\n );\n }\n\n try {\n scheduler.runTask();\n } catch (error) {\n errors.push(error);\n }\n }\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 occurred during flushSync\");\n }\n }\n } finally {\n flushState.schedulers.clear();\n flushState.isScheduled = false;\n }\n};\n\n// Use MessageChannel to schedule flushes as macrotasks (like React's scheduler).\n// This allows more state updates to batch into a single re-render.\nconst scheduleMacrotask = (() => {\n if (typeof MessageChannel !== \"undefined\") {\n const channel = new MessageChannel();\n channel.port1.onmessage = flushScheduled;\n return () => channel.port2.postMessage(null);\n }\n // Fallback for environments without MessageChannel\n return () => setTimeout(flushScheduled, 0);\n})();\n\nexport const flushResourcesSync = <T>(callback: () => T): T => {\n const prev = flushState;\n flushState = {\n schedulers: new Set([]),\n isScheduled: true,\n };\n\n try {\n const result = callback();\n flushScheduled();\n\n return result;\n } finally {\n flushState = prev;\n }\n};\n"],"mappings":";AAOA,MAAM,kBAAkB;AACxB,IAAI,aAA+B;CACjC,4BAAY,IAAI,IAAI,CAAC,CAAC;CACtB,aAAa;AACf;AAEA,IAAa,kBAAb,MAA6B;CAGE;CAF7B,WAAmB;CAEnB,YAAY,OAA8B;EAAb,KAAA,QAAA;CAAc;CAE3C,IAAI,UAAU;EACZ,OAAO,KAAK;CACd;CAEA,YAAY;EACV,KAAK,WAAW;EAEhB,WAAW,WAAW,IAAI,IAAI;EAC9B,cAAc;CAChB;CAEA,UAAU;EACR,KAAK,WAAW;EAChB,KAAK,MAAM;CACb;AACF;AAEA,MAAM,sBAAsB;CAC1B,IAAI,WAAW,aAAa;CAC5B,WAAW,cAAc;CACzB,kBAAkB;AACpB;AAEA,MAAM,uBAAuB;CAC3B,IAAI;EACF,MAAM,SAAS,CAAC;EAChB,IAAI,aAAa;EAEjB,KAAK,MAAM,aAAa,WAAW,YAAY;GAC7C,WAAW,WAAW,OAAO,SAAS;GACtC,IAAI,CAAC,UAAU,SAAS;GAExB;GAEA,IAAI,aAAa,iBACf,MAAM,IAAI,MACR,4GAEF;GAGF,IAAI;IACF,UAAU,QAAQ;GACpB,SAAS,OAAO;IACd,OAAO,KAAK,KAAK;GACnB;EACF;EAEA,IAAI,OAAO,SAAS,GAClB,IAAI,OAAO,WAAW,GACpB,MAAM,OAAO;OACR;GACL,KAAK,MAAM,SAAS,QAClB,QAAQ,MAAM,KAAK;GAErB,MAAM,IAAI,eAAe,QAAQ,kCAAkC;EACrE;CAEJ,UAAU;EACR,WAAW,WAAW,MAAM;EAC5B,WAAW,cAAc;CAC3B;AACF;AAIA,MAAM,2BAA2B;CAC/B,IAAI,OAAO,mBAAmB,aAAa;EACzC,MAAM,UAAU,IAAI,eAAe;EACnC,QAAQ,MAAM,YAAY;EAC1B,aAAa,QAAQ,MAAM,YAAY,IAAI;CAC7C;CAEA,aAAa,WAAW,gBAAgB,CAAC;AAC3C,GAAG;AAEH,MAAa,sBAAyB,aAAyB;CAC7D,MAAM,OAAO;CACb,aAAa;EACX,4BAAY,IAAI,IAAI,CAAC,CAAC;EACtB,aAAa;CACf;CAEA,IAAI;EACF,MAAM,SAAS,SAAS;EACxB,eAAe;EAEf,OAAO;CACT,UAAU;EACR,aAAa;CACf;AACF"}
1
+ {"version":3,"file":"scheduler.js","names":[],"sources":["../../src/core/scheduler.ts"],"sourcesContent":["type Task = () => void;\n\ntype GlobalFlushState = {\n schedulers: Set<UpdateScheduler>;\n isScheduled: boolean;\n};\n\nconst MAX_FLUSH_LIMIT = 50;\nlet flushState: GlobalFlushState = {\n schedulers: new Set([]),\n isScheduled: false,\n};\n\nexport class UpdateScheduler {\n private _isDirty = false;\n\n constructor(private readonly _task: Task) {}\n\n get isDirty() {\n return this._isDirty;\n }\n\n markDirty() {\n this._isDirty = true;\n\n flushState.schedulers.add(this);\n scheduleFlush();\n }\n\n runTask() {\n this._isDirty = false;\n this._task();\n }\n}\n\nconst scheduleFlush = () => {\n if (flushState.isScheduled) return;\n flushState.isScheduled = true;\n scheduleMacrotask();\n};\n\nconst flushScheduled = () => {\n try {\n const errors = [];\n let flushDepth = 0;\n\n for (const scheduler of flushState.schedulers) {\n flushState.schedulers.delete(scheduler);\n if (!scheduler.isDirty) continue;\n\n flushDepth++;\n\n if (flushDepth > MAX_FLUSH_LIMIT) {\n throw new Error(\n `Maximum update depth exceeded. This can happen when a resource ` +\n `repeatedly calls setState inside useEffect.`,\n );\n }\n\n try {\n scheduler.runTask();\n } catch (error) {\n errors.push(error);\n }\n }\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 occurred during flushSync\");\n }\n }\n } finally {\n flushState.schedulers.clear();\n flushState.isScheduled = false;\n }\n};\n\n// Use MessageChannel to schedule flushes as macrotasks (like React's scheduler).\n// This allows more state updates to batch into a single re-render.\nconst scheduleMacrotask = (() => {\n if (typeof MessageChannel !== \"undefined\") {\n const channel = new MessageChannel();\n channel.port1.onmessage = flushScheduled;\n return () => channel.port2.postMessage(null);\n }\n // Fallback for environments without MessageChannel\n return () => setTimeout(flushScheduled, 0);\n})();\n\nexport const flushResourcesSync = <T>(callback: () => T): T => {\n const prev = flushState;\n flushState = {\n schedulers: new Set([]),\n isScheduled: true,\n };\n\n try {\n const result = callback();\n flushScheduled();\n\n return result;\n } finally {\n flushState = prev;\n }\n};\n"],"mappings":";AAOA,MAAM,kBAAkB;AACxB,IAAI,aAA+B;CACjC,4BAAY,IAAI,IAAI,CAAC,CAAC;CACtB,aAAa;AACf;AAEA,IAAa,kBAAb,MAA6B;CAGE;CAF7B,WAAmB;CAEnB,YAAY,OAA8B;EAAb,KAAA,QAAA;CAAc;CAE3C,IAAI,UAAU;EACZ,OAAO,KAAK;CACd;CAEA,YAAY;EACV,KAAK,WAAW;EAEhB,WAAW,WAAW,IAAI,IAAI;EAC9B,cAAc;CAChB;CAEA,UAAU;EACR,KAAK,WAAW;EAChB,KAAK,MAAM;CACb;AACF;AAEA,MAAM,sBAAsB;CAC1B,IAAI,WAAW,aAAa;CAC5B,WAAW,cAAc;CACzB,kBAAkB;AACpB;AAEA,MAAM,uBAAuB;CAC3B,IAAI;EACF,MAAM,SAAS,CAAC;EAChB,IAAI,aAAa;EAEjB,KAAK,MAAM,aAAa,WAAW,YAAY;GAC7C,WAAW,WAAW,OAAO,SAAS;GACtC,IAAI,CAAC,UAAU,SAAS;GAExB;GAEA,IAAI,aAAa,iBACf,MAAM,IAAI,MACR,4GAEF;GAGF,IAAI;IACF,UAAU,QAAQ;GACpB,SAAS,OAAO;IACd,OAAO,KAAK,KAAK;GACnB;EACF;EAEA,IAAI,OAAO,SAAS,GAClB,IAAI,OAAO,WAAW,GACpB,MAAM,OAAO;OACR;GACL,KAAK,MAAM,SAAS,QAClB,QAAQ,MAAM,KAAK;GAErB,MAAM,IAAI,eAAe,QAAQ,kCAAkC;EACrE;CAEJ,UAAU;EACR,WAAW,WAAW,MAAM;EAC5B,WAAW,cAAc;CAC3B;AACF;AAIA,MAAM,2BAA2B;CAC/B,IAAI,OAAO,mBAAmB,aAAa;EACzC,MAAM,UAAU,IAAI,eAAe;EACnC,QAAQ,MAAM,YAAY;EAC1B,aAAa,QAAQ,MAAM,YAAY,IAAI;CAC7C;CAEA,aAAa,WAAW,gBAAgB,CAAC;AAC3C,EAAA,CAAG;AAEH,MAAa,sBAAyB,aAAyB;CAC7D,MAAM,OAAO;CACb,aAAa;EACX,4BAAY,IAAI,IAAI,CAAC,CAAC;EACtB,aAAa;CACf;CAEA,IAAI;EACF,MAAM,SAAS,SAAS;EACxB,eAAe;EAEf,OAAO;CACT,UAAU;EACR,aAAa;CACf;AACF"}
@@ -1,4 +1,4 @@
1
- import { tapEffect } from "../hooks/tap-effect.js";
1
+ import { useEffect } from "../hooks/useEffect.js";
2
2
 
3
3
  //#region src/core/types.d.ts
4
4
  type ResourceElement<R, P = any> = {
@@ -24,11 +24,11 @@ type Cell = {
24
24
  reducer: (state: any, action: any) => any;
25
25
  } | {
26
26
  readonly type: "effect";
27
- cleanup: tapEffect.Destructor | undefined;
27
+ cleanup: useEffect.Destructor | undefined;
28
28
  deps: readonly unknown[] | null | undefined;
29
29
  };
30
30
  interface EffectTask {
31
- readonly effect: tapEffect.EffectCallback;
31
+ readonly effect: useEffect.EffectCallback;
32
32
  readonly deps: readonly unknown[] | undefined;
33
33
  readonly cell: Cell & {
34
34
  type: "effect";
@@ -0,0 +1,13 @@
1
+ import { useEffect } from "./useEffect.js";
2
+ import { useResourceRoot } from "./useResourceRoot.js";
3
+ import { useState } from "./useState.js";
4
+ import { useReducer, useReducerWithDerivedState } from "./useReducer.js";
5
+ import { useRef } from "./useRef.js";
6
+ import { useMemo } from "./useMemo.js";
7
+ import { useCallback } from "./useCallback.js";
8
+ import { useEffectEvent } from "./useEffectEvent.js";
9
+ import { use } from "./use.js";
10
+ import { useMemoCache } from "./useMemoCache.js";
11
+ import { useResource } from "./useResource.js";
12
+ import { useResources } from "./useResources.js";
13
+ export { use, useCallback, useEffect, useEffectEvent, useMemo, useMemoCache, useReducer, useReducerWithDerivedState, useRef, useResource, useResourceRoot, useResources, useState };
@@ -0,0 +1,13 @@
1
+ import { useReducer, useReducerWithDerivedState } from "./useReducer.js";
2
+ import { useState } from "./useState.js";
3
+ import { useRef } from "./useRef.js";
4
+ import { useMemo } from "./useMemo.js";
5
+ import { useCallback } from "./useCallback.js";
6
+ import { useEffect } from "./useEffect.js";
7
+ import { useEffectEvent } from "./useEffectEvent.js";
8
+ import { use } from "./use.js";
9
+ import { useMemoCache } from "./useMemoCache.js";
10
+ import { useResourceRoot } from "./useResourceRoot.js";
11
+ import { useResource } from "./useResource.js";
12
+ import { useResources } from "./useResources.js";
13
+ export { use, useCallback, useEffect, useEffectEvent, useMemo, useMemoCache, useReducer, useReducerWithDerivedState, useRef, useResource, useResourceRoot, useResources, useState };
@@ -0,0 +1,9 @@
1
+ //#region src/hooks/use.d.ts
2
+ /**
3
+ * Reads a resource context from inside a resource render, the tap equivalent of
4
+ * React's `use(Context)`. Only resource contexts are supported.
5
+ */
6
+ declare const use: (usable: unknown) => unknown;
7
+ //#endregion
8
+ export { use };
9
+ //# sourceMappingURL=use.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use.d.ts","names":[],"sources":["../../src/hooks/use.ts"],"mappings":";;AAMA;;;cAAa,GAAA,GAAO,MAAe"}
@@ -0,0 +1,14 @@
1
+ import { isResourceContext, useResourceContext } from "../core/context.js";
2
+ //#region src/hooks/use.ts
3
+ /**
4
+ * Reads a resource context from inside a resource render, the tap equivalent of
5
+ * React's `use(Context)`. Only resource contexts are supported.
6
+ */
7
+ const use = (usable) => {
8
+ if (!isResourceContext(usable)) throw new Error("A tap resource's `use()` only accepts a resource context.");
9
+ return useResourceContext(usable);
10
+ };
11
+ //#endregion
12
+ export { use };
13
+
14
+ //# sourceMappingURL=use.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use.js","names":[],"sources":["../../src/hooks/use.ts"],"sourcesContent":["import { isResourceContext, useResourceContext } from \"../core/context\";\n\n/**\n * Reads a resource context from inside a resource render, the tap equivalent of\n * React's `use(Context)`. Only resource contexts are supported.\n */\nexport const use = (usable: unknown): unknown => {\n if (!isResourceContext(usable))\n throw new Error(\n \"A tap resource's `use()` only accepts a resource context.\",\n );\n return useResourceContext(usable as never);\n};\n"],"mappings":";;;;;;AAMA,MAAa,OAAO,WAA6B;CAC/C,IAAI,CAAC,kBAAkB,MAAM,GAC3B,MAAM,IAAI,MACR,2DACF;CACF,OAAO,mBAAmB,MAAe;AAC3C"}
@@ -0,0 +1,5 @@
1
+ //#region src/hooks/useCallback.d.ts
2
+ declare const useCallback: <T extends (...args: any[]) => any>(fn: T, deps: readonly unknown[]) => T;
3
+ //#endregion
4
+ export { useCallback };
5
+ //# sourceMappingURL=useCallback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCallback.d.ts","names":[],"sources":["../../src/hooks/useCallback.ts"],"mappings":";cAEa,WAAA,iBAA6B,IAAA,iBACxC,EAAA,EAAI,CAAA,EACJ,IAAA,yBACC,CAGF"}
@@ -0,0 +1,9 @@
1
+ import { useMemo } from "./useMemo.js";
2
+ //#region src/hooks/useCallback.ts
3
+ const useCallback = (fn, deps) => {
4
+ return useMemo(() => fn, deps);
5
+ };
6
+ //#endregion
7
+ export { useCallback };
8
+
9
+ //# sourceMappingURL=useCallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCallback.js","names":[],"sources":["../../src/hooks/useCallback.ts"],"sourcesContent":["import { useMemo } from \"./useMemo\";\n\nexport const useCallback = <T extends (...args: any[]) => any>(\n fn: T,\n deps: readonly unknown[],\n): T => {\n // oxlint-disable-next-line react/exhaustive-deps -- user-provided dep array forwarded verbatim\n return useMemo(() => fn, deps);\n};\n"],"mappings":";;AAEA,MAAa,eACX,IACA,SACM;CAEN,OAAO,cAAc,IAAI,IAAI;AAC/B"}
@@ -0,0 +1,10 @@
1
+ //#region src/hooks/useEffect.d.ts
2
+ declare namespace useEffect {
3
+ type Destructor = () => void;
4
+ type EffectCallback = () => Destructor | undefined;
5
+ }
6
+ declare function useEffect(effect: useEffect.EffectCallback): void;
7
+ declare function useEffect(effect: useEffect.EffectCallback, deps: readonly unknown[]): void;
8
+ //#endregion
9
+ export { useEffect };
10
+ //# sourceMappingURL=useEffect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEffect.d.ts","names":[],"sources":["../../src/hooks/useEffect.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,15 +1,15 @@
1
- import { registerRenderMountTask, tapHook } from "./utils/tapHook.js";
1
+ import { registerRenderMountTask, useCell } from "./utils/useCell.js";
2
2
  import { depsShallowEqual } from "./utils/depsShallowEqual.js";
3
- //#region src/hooks/tap-effect.ts
3
+ //#region src/hooks/useEffect.ts
4
4
  const newEffect = () => ({
5
5
  type: "effect",
6
6
  cleanup: void 0,
7
7
  deps: null
8
8
  });
9
- function tapEffect(effect, deps) {
10
- const cell = tapHook("effect", newEffect);
9
+ function useEffect(effect, deps) {
10
+ const cell = useCell("effect", newEffect);
11
11
  if (deps && cell.deps && depsShallowEqual(cell.deps, deps)) return;
12
- if (cell.deps !== null && !!deps !== !!cell.deps) throw new Error("tapEffect called with and without dependencies across re-renders");
12
+ if (cell.deps !== null && !!deps !== !!cell.deps) throw new Error("useEffect called with and without dependencies across re-renders");
13
13
  registerRenderMountTask(() => {
14
14
  const errors = [];
15
15
  try {
@@ -35,6 +35,6 @@ function tapEffect(effect, deps) {
35
35
  });
36
36
  }
37
37
  //#endregion
38
- export { tapEffect };
38
+ export { useEffect };
39
39
 
40
- //# sourceMappingURL=tap-effect.js.map
40
+ //# sourceMappingURL=useEffect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEffect.js","names":[],"sources":["../../src/hooks/useEffect.ts"],"sourcesContent":["import type { Cell } from \"../core/types\";\nimport { depsShallowEqual } from \"./utils/depsShallowEqual\";\nimport { useCell, registerRenderMountTask } from \"./utils/useCell\";\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 useEffect {\n export type Destructor = () => void;\n export type EffectCallback = () => Destructor | undefined;\n}\n\nexport function useEffect(effect: useEffect.EffectCallback): void;\nexport function useEffect(\n effect: useEffect.EffectCallback,\n deps: readonly unknown[],\n): void;\nexport function useEffect(\n effect: useEffect.EffectCallback,\n deps?: readonly unknown[],\n): void {\n const cell = useCell(\"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 \"useEffect 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,4 +1,4 @@
1
- //#region src/hooks/tap-effect-event.d.ts
1
+ //#region src/hooks/useEffectEvent.d.ts
2
2
  /**
3
3
  * Creates a stable function reference that always calls the most recent version of the callback.
4
4
  * Similar to React's useEffectEvent hook.
@@ -8,13 +8,13 @@
8
8
  *
9
9
  * @example
10
10
  * ```typescript
11
- * const handleClick = tapEffectEvent((value: string) => {
11
+ * const handleClick = useEffectEvent((value: string) => {
12
12
  * console.log(value);
13
13
  * });
14
14
  * // handleClick reference is stable, but always calls the latest version
15
15
  * ```
16
16
  */
17
- declare function tapEffectEvent<T extends (...args: any[]) => any>(callback: T): T;
17
+ declare function useEffectEvent<T extends (...args: any[]) => any>(callback: T): T;
18
18
  //#endregion
19
- export { tapEffectEvent };
20
- //# sourceMappingURL=tap-effect-event.d.ts.map
19
+ export { useEffectEvent };
20
+ //# sourceMappingURL=useEffectEvent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEffectEvent.d.ts","names":[],"sources":["../../src/hooks/useEffectEvent.ts"],"mappings":";;AAqBA;;;;;;;;;;AAEI;;;;iBAFY,cAAA,eAA6B,IAAA,iBAC3C,QAAA,EAAU,CAAA,GACT,CAAC"}