@assistant-ui/tap 0.6.1 → 0.7.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.
- package/README.md +9 -6
- package/dist/core/ResourceFiber.d.ts +5 -5
- package/dist/core/ResourceFiber.d.ts.map +1 -1
- package/dist/core/ResourceFiber.js +26 -18
- package/dist/core/ResourceFiber.js.map +1 -1
- package/dist/core/createTapRoot.d.ts +9 -0
- package/dist/core/createTapRoot.d.ts.map +1 -0
- package/dist/core/createTapRoot.js +27 -0
- package/dist/core/createTapRoot.js.map +1 -0
- package/dist/core/helpers/commit.d.ts +1 -1
- package/dist/core/helpers/commit.d.ts.map +1 -1
- package/dist/core/helpers/commit.js +6 -1
- package/dist/core/helpers/commit.js.map +1 -1
- package/dist/core/helpers/execution-context.d.ts +4 -5
- package/dist/core/helpers/execution-context.d.ts.map +1 -1
- package/dist/core/helpers/execution-context.js +1 -7
- package/dist/core/helpers/execution-context.js.map +1 -1
- package/dist/core/helpers/root.d.ts +3 -2
- package/dist/core/helpers/root.d.ts.map +1 -1
- package/dist/core/helpers/root.js +19 -15
- package/dist/core/helpers/root.js.map +1 -1
- package/dist/core/react-dispatcher.d.ts.map +1 -1
- package/dist/core/react-dispatcher.js +14 -14
- package/dist/core/react-dispatcher.js.map +1 -1
- package/dist/core/resource.d.ts +2 -4
- package/dist/core/resource.d.ts.map +1 -1
- package/dist/core/resource.js +5 -10
- package/dist/core/resource.js.map +1 -1
- package/dist/core/scheduler.d.ts +2 -2
- package/dist/core/scheduler.d.ts.map +1 -1
- package/dist/core/scheduler.js +2 -2
- package/dist/core/scheduler.js.map +1 -1
- package/dist/core/types.d.ts +27 -25
- package/dist/core/types.d.ts.map +1 -1
- package/dist/hooks/useResource.d.ts +2 -2
- package/dist/hooks/useResource.d.ts.map +1 -1
- package/dist/hooks/useResource.js +14 -20
- package/dist/hooks/useResource.js.map +1 -1
- package/dist/hooks/useResources.d.ts +1 -1
- package/dist/hooks/useResources.d.ts.map +1 -1
- package/dist/hooks/useResources.js +18 -27
- package/dist/hooks/useResources.js.map +1 -1
- package/dist/hooks/useTapHost.d.ts +21 -0
- package/dist/hooks/useTapHost.d.ts.map +1 -0
- package/dist/hooks/useTapHost.js +30 -0
- package/dist/hooks/useTapHost.js.map +1 -0
- package/dist/hooks/useTapRoot.d.ts +18 -0
- package/dist/hooks/useTapRoot.d.ts.map +1 -0
- package/dist/hooks/useTapRoot.js +77 -0
- package/dist/hooks/useTapRoot.js.map +1 -0
- package/dist/hooks/utils/depsShallowEqual.d.ts.map +1 -1
- package/dist/hooks/utils/depsShallowEqual.js +5 -2
- package/dist/hooks/utils/depsShallowEqual.js.map +1 -1
- package/dist/hooks/utils/useCell.d.ts +2 -2
- package/dist/hooks/utils/useCell.d.ts.map +1 -1
- package/dist/hooks/utils/useCell.js.map +1 -1
- package/dist/hooks/utils/useDevStrictMode.d.ts +5 -0
- package/dist/hooks/utils/useDevStrictMode.d.ts.map +1 -0
- package/dist/hooks/utils/useDevStrictMode.js +25 -0
- package/dist/hooks/utils/useDevStrictMode.js.map +1 -0
- package/dist/hooks/utils/useRenderMemo.d.ts +5 -0
- package/dist/hooks/utils/useRenderMemo.d.ts.map +1 -0
- package/dist/hooks/utils/useRenderMemo.js +25 -0
- package/dist/hooks/utils/useRenderMemo.js.map +1 -0
- package/dist/hooks/utils/useResourceFiberHostUtils.d.ts +10 -0
- package/dist/hooks/utils/useResourceFiberHostUtils.d.ts.map +1 -0
- package/dist/hooks/utils/useResourceFiberHostUtils.js +46 -0
- package/dist/hooks/utils/useResourceFiberHostUtils.js.map +1 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.js +7 -4
- package/dist/{hooks → react-hooks}/index.d.ts +6 -6
- package/dist/{hooks → react-hooks}/index.js +5 -5
- package/dist/{hooks → react-hooks}/use.d.ts +1 -1
- package/dist/{hooks → react-hooks}/use.d.ts.map +1 -1
- package/dist/{hooks → react-hooks}/use.js +1 -1
- package/dist/react-hooks/use.js.map +1 -0
- package/dist/{hooks → react-hooks}/useCallback.d.ts +1 -1
- package/dist/react-hooks/useCallback.d.ts.map +1 -0
- package/dist/{hooks → react-hooks}/useCallback.js +1 -1
- package/dist/react-hooks/useCallback.js.map +1 -0
- package/dist/{hooks → react-hooks}/useEffect.d.ts +1 -1
- package/dist/react-hooks/useEffect.d.ts.map +1 -0
- package/dist/react-hooks/useEffect.js +35 -0
- package/dist/react-hooks/useEffect.js.map +1 -0
- package/dist/{hooks → react-hooks}/useEffectEvent.d.ts +1 -1
- package/dist/react-hooks/useEffectEvent.d.ts.map +1 -0
- package/dist/{hooks → react-hooks}/useEffectEvent.js +2 -2
- package/dist/react-hooks/useEffectEvent.js.map +1 -0
- package/dist/{hooks → react-hooks}/useMemo.d.ts +1 -1
- package/dist/react-hooks/useMemo.d.ts.map +1 -0
- package/dist/{hooks → react-hooks}/useMemo.js +3 -3
- package/dist/react-hooks/useMemo.js.map +1 -0
- package/dist/{hooks → react-hooks}/useMemoCache.d.ts +1 -1
- package/dist/react-hooks/useMemoCache.d.ts.map +1 -0
- package/dist/{hooks → react-hooks}/useMemoCache.js +1 -1
- package/dist/react-hooks/useMemoCache.js.map +1 -0
- package/dist/react-hooks/useReducer.d.ts +9 -0
- package/dist/react-hooks/useReducer.d.ts.map +1 -0
- package/dist/react-hooks/useReducer.js +120 -0
- package/dist/react-hooks/useReducer.js.map +1 -0
- package/dist/{hooks → react-hooks}/useRef.d.ts +1 -1
- package/dist/react-hooks/useRef.d.ts.map +1 -0
- package/dist/{hooks → react-hooks}/useRef.js +1 -1
- package/dist/react-hooks/useRef.js.map +1 -0
- package/dist/{hooks → react-hooks}/useState.d.ts +1 -1
- package/dist/react-hooks/useState.d.ts.map +1 -0
- package/dist/{hooks → react-hooks}/useState.js +3 -3
- package/dist/react-hooks/useState.js.map +1 -0
- package/dist/react-shim/index.js +11 -11
- package/dist/react-shim/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/basic/resourceHandle.test.ts +32 -22
- package/src/__tests__/basic/tapEffect.basic.test.ts +8 -8
- package/src/__tests__/basic/tapReducer.basic.test.ts +16 -14
- package/src/__tests__/basic/tapResources.basic.test.ts +19 -16
- package/src/__tests__/basic/tapState.basic.test.ts +11 -11
- package/src/__tests__/bench/hosts.bench.tsx +124 -0
- package/src/__tests__/bench/tree.bench.tsx +166 -0
- package/src/__tests__/errors/errors.effect-errors.test.ts +12 -13
- package/src/__tests__/errors/errors.render-errors.test.ts +65 -22
- package/src/__tests__/lifecycle/lifecycle.dependencies.test.ts +19 -19
- package/src/__tests__/lifecycle/lifecycle.mount-unmount.test.ts +14 -14
- package/src/__tests__/parity/describeParity.tsx +217 -0
- package/src/__tests__/parity/parity.adversarial.test.tsx +375 -0
- package/src/__tests__/parity/parity.basics.test.tsx +281 -0
- package/src/__tests__/parity/parity.divergences.test.tsx +208 -0
- package/src/__tests__/parity/parity.smoke.test.tsx +43 -0
- package/src/__tests__/react/concurrent-mode.test.tsx +10 -6
- package/src/__tests__/react/concurrent-pending-updates.test.tsx +351 -0
- package/src/__tests__/react/concurrent-render-phase.test.tsx +350 -0
- package/src/__tests__/react/react-shim.test.tsx +1 -1
- package/src/__tests__/react/useResource.test.tsx +41 -26
- package/src/__tests__/react/useTapHost.test.tsx +233 -0
- package/src/__tests__/react-dispatcher.test.ts +4 -4
- package/src/__tests__/rules/rules.hook-count.test.ts +21 -21
- package/src/__tests__/rules/rules.hook-order.test.ts +17 -17
- package/src/__tests__/strictmode/strictmode-parity.test.tsx +420 -0
- package/src/__tests__/strictmode/strictmode.test.ts +39 -209
- package/src/__tests__/test-utils.ts +33 -23
- package/src/core/ResourceFiber.ts +43 -35
- package/src/core/createTapRoot.ts +45 -0
- package/src/core/helpers/commit.ts +12 -2
- package/src/core/helpers/execution-context.ts +4 -13
- package/src/core/helpers/root.ts +24 -12
- package/src/core/react-dispatcher.ts +10 -9
- package/src/core/resource.ts +5 -20
- package/src/core/scheduler.ts +1 -1
- package/src/core/types.ts +27 -21
- package/src/hooks/useResource.ts +18 -27
- package/src/hooks/useResources.ts +18 -42
- package/src/hooks/useTapHost.ts +60 -0
- package/src/hooks/useTapRoot.ts +135 -0
- package/src/hooks/utils/depsShallowEqual.ts +12 -2
- package/src/hooks/utils/useCell.ts +2 -2
- package/src/hooks/utils/useDevStrictMode.ts +34 -0
- package/src/hooks/utils/useRenderMemo.ts +27 -0
- package/src/hooks/utils/useResourceFiberHostUtils.ts +61 -0
- package/src/index.ts +6 -3
- package/src/{hooks → react-hooks}/index.ts +4 -4
- package/src/react-hooks/useEffect.ts +58 -0
- package/src/{hooks → react-hooks}/useMemo.ts +1 -1
- package/src/react-hooks/useReducer.ts +254 -0
- package/src/{hooks → react-hooks}/useState.ts +2 -2
- package/src/react-shim/index.ts +1 -1
- package/dist/core/createResourceRoot.d.ts +0 -11
- package/dist/core/createResourceRoot.d.ts.map +0 -1
- package/dist/core/createResourceRoot.js +0 -31
- package/dist/core/createResourceRoot.js.map +0 -1
- package/dist/core/helpers/callResourceFn.d.ts +0 -1
- package/dist/core/helpers/callResourceFn.js +0 -19
- package/dist/core/helpers/callResourceFn.js.map +0 -1
- package/dist/hooks/use.js.map +0 -1
- package/dist/hooks/useCallback.d.ts.map +0 -1
- package/dist/hooks/useCallback.js.map +0 -1
- package/dist/hooks/useEffect.d.ts.map +0 -1
- package/dist/hooks/useEffect.js +0 -40
- package/dist/hooks/useEffect.js.map +0 -1
- package/dist/hooks/useEffectEvent.d.ts.map +0 -1
- package/dist/hooks/useEffectEvent.js.map +0 -1
- package/dist/hooks/useMemo.d.ts.map +0 -1
- package/dist/hooks/useMemo.js.map +0 -1
- package/dist/hooks/useMemoCache.d.ts.map +0 -1
- package/dist/hooks/useMemoCache.js.map +0 -1
- package/dist/hooks/useReducer.d.ts +0 -21
- package/dist/hooks/useReducer.d.ts.map +0 -1
- package/dist/hooks/useReducer.js +0 -81
- package/dist/hooks/useReducer.js.map +0 -1
- package/dist/hooks/useRef.d.ts.map +0 -1
- package/dist/hooks/useRef.js.map +0 -1
- package/dist/hooks/useResourceRoot.d.ts +0 -20
- package/dist/hooks/useResourceRoot.d.ts.map +0 -1
- package/dist/hooks/useResourceRoot.js +0 -77
- package/dist/hooks/useResourceRoot.js.map +0 -1
- package/dist/hooks/useState.d.ts.map +0 -1
- package/dist/hooks/useState.js.map +0 -1
- package/dist/react/hooks.d.ts +0 -25
- package/dist/react/hooks.d.ts.map +0 -1
- package/dist/react/hooks.js +0 -69
- package/dist/react/hooks.js.map +0 -1
- package/src/__tests__/strictmode/react-strictmode-behavior.test.tsx +0 -920
- package/src/__tests__/strictmode/react-strictmode-rerender-sources.test.tsx +0 -488
- package/src/__tests__/strictmode/tap-strictmode-rerender-sources.test.ts +0 -687
- package/src/core/createResourceRoot.ts +0 -53
- package/src/core/helpers/callResourceFn.ts +0 -21
- package/src/hooks/useEffect.ts +0 -72
- package/src/hooks/useReducer.ts +0 -160
- package/src/hooks/useResourceRoot.ts +0 -130
- package/src/react/hooks.ts +0 -112
- /package/src/{hooks → react-hooks}/use.ts +0 -0
- /package/src/{hooks → react-hooks}/useCallback.ts +0 -0
- /package/src/{hooks → react-hooks}/useEffectEvent.ts +0 -0
- /package/src/{hooks → react-hooks}/useMemoCache.ts +0 -0
- /package/src/{hooks → react-hooks}/useRef.ts +0 -0
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import type { ResourceElement } from "./types";
|
|
2
|
-
import {
|
|
3
|
-
createResourceFiber,
|
|
4
|
-
unmountResourceFiber,
|
|
5
|
-
renderResourceFiber,
|
|
6
|
-
commitResourceFiber,
|
|
7
|
-
} from "./ResourceFiber";
|
|
8
|
-
import { useResourceRoot } from "../hooks/useResourceRoot";
|
|
9
|
-
import { resource } from "./resource";
|
|
10
|
-
import { isDevelopment } from "./helpers/env";
|
|
11
|
-
import { flushResourcesSync, UpdateScheduler } from "./scheduler";
|
|
12
|
-
import { createResourceFiberRoot } from "./helpers/root";
|
|
13
|
-
|
|
14
|
-
const SubscribableResource = resource(useResourceRoot);
|
|
15
|
-
|
|
16
|
-
export const createResourceRoot = () => {
|
|
17
|
-
const fiber = createResourceFiber<
|
|
18
|
-
useResourceRoot.SubscribableResource<any>,
|
|
19
|
-
ResourceElement<any>
|
|
20
|
-
>(
|
|
21
|
-
SubscribableResource,
|
|
22
|
-
createResourceFiberRoot((callback) => {
|
|
23
|
-
new UpdateScheduler(() => {
|
|
24
|
-
if (callback()) {
|
|
25
|
-
throw new Error(
|
|
26
|
-
"Unexpected rerender of createResourceRoot outer fiber",
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
return false;
|
|
30
|
-
}).markDirty();
|
|
31
|
-
}),
|
|
32
|
-
undefined,
|
|
33
|
-
isDevelopment ? "root" : null,
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
return {
|
|
37
|
-
render: <R, P>(element: ResourceElement<R, P>) => {
|
|
38
|
-
// In strict mode, render twice to detect side effects
|
|
39
|
-
if (isDevelopment && fiber.devStrictMode === "root") {
|
|
40
|
-
void renderResourceFiber(fiber, element);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const render = renderResourceFiber(fiber, element);
|
|
44
|
-
|
|
45
|
-
flushResourcesSync(() => commitResourceFiber(fiber, render));
|
|
46
|
-
|
|
47
|
-
return render.output as useResourceRoot.SubscribableResource<R>;
|
|
48
|
-
},
|
|
49
|
-
unmount: () => {
|
|
50
|
-
unmountResourceFiber(fiber);
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { Resource } from "../types";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Renders a resource with the given props.
|
|
5
|
-
* @internal This is for internal use only.
|
|
6
|
-
*/
|
|
7
|
-
export function callResourceFn<R, P>(resource: Resource<R, P>, props: P): R {
|
|
8
|
-
const fn = (resource as unknown as { [fnSymbol]?: (props: P) => R })[
|
|
9
|
-
fnSymbol
|
|
10
|
-
];
|
|
11
|
-
if (!fn) {
|
|
12
|
-
throw new Error("ResourceElement.type is not a valid Resource");
|
|
13
|
-
}
|
|
14
|
-
return fn(props);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Symbol used to store the ResourceFn in the Resource constructor.
|
|
19
|
-
* @internal This is for internal use only.
|
|
20
|
-
*/
|
|
21
|
-
export const fnSymbol = Symbol("fnSymbol");
|
package/src/hooks/useEffect.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import type { Cell } from "../core/types";
|
|
2
|
-
import { depsShallowEqual } from "./utils/depsShallowEqual";
|
|
3
|
-
import { useCell, registerRenderMountTask } from "./utils/useCell";
|
|
4
|
-
|
|
5
|
-
const newEffect = (): Cell & { type: "effect" } => ({
|
|
6
|
-
type: "effect",
|
|
7
|
-
cleanup: undefined,
|
|
8
|
-
deps: null, // null means the effect has never been run
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
export namespace useEffect {
|
|
12
|
-
export type Destructor = () => void;
|
|
13
|
-
export type EffectCallback = () => Destructor | undefined;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function useEffect(effect: useEffect.EffectCallback): void;
|
|
17
|
-
export function useEffect(
|
|
18
|
-
effect: useEffect.EffectCallback,
|
|
19
|
-
deps: readonly unknown[],
|
|
20
|
-
): void;
|
|
21
|
-
export function useEffect(
|
|
22
|
-
effect: useEffect.EffectCallback,
|
|
23
|
-
deps?: readonly unknown[],
|
|
24
|
-
): void {
|
|
25
|
-
const cell = useCell("effect", newEffect);
|
|
26
|
-
|
|
27
|
-
if (deps && cell.deps && depsShallowEqual(cell.deps, deps)) return;
|
|
28
|
-
if (cell.deps !== null && !!deps !== !!cell.deps)
|
|
29
|
-
throw new Error(
|
|
30
|
-
"useEffect called with and without dependencies across re-renders",
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
registerRenderMountTask(() => {
|
|
34
|
-
const errors: unknown[] = [];
|
|
35
|
-
|
|
36
|
-
try {
|
|
37
|
-
cell.cleanup?.();
|
|
38
|
-
} catch (error) {
|
|
39
|
-
errors.push(error);
|
|
40
|
-
} finally {
|
|
41
|
-
cell.cleanup = undefined;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
const cleanup = effect();
|
|
46
|
-
|
|
47
|
-
if (cleanup !== undefined && typeof cleanup !== "function") {
|
|
48
|
-
throw new Error(
|
|
49
|
-
"An effect function must either return a cleanup function or nothing. " +
|
|
50
|
-
`Received: ${typeof cleanup}`,
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
cell.cleanup = cleanup;
|
|
55
|
-
} catch (error) {
|
|
56
|
-
errors.push(error);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
cell.deps = deps;
|
|
60
|
-
|
|
61
|
-
if (errors.length > 0) {
|
|
62
|
-
if (errors.length === 1) {
|
|
63
|
-
throw errors[0];
|
|
64
|
-
} else {
|
|
65
|
-
for (const error of errors) {
|
|
66
|
-
console.error(error);
|
|
67
|
-
}
|
|
68
|
-
throw new AggregateError(errors, "Errors during commit");
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
}
|
package/src/hooks/useReducer.ts
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import { isDevelopment } from "../core/helpers/env";
|
|
2
|
-
import { getCurrentResourceFiber } from "../core/helpers/execution-context";
|
|
3
|
-
import type { ReducerQueueEntry, ResourceFiber } from "../core/types";
|
|
4
|
-
import { markCellDirty } from "../core/helpers/root";
|
|
5
|
-
import { useCell } from "./utils/useCell";
|
|
6
|
-
|
|
7
|
-
type Dispatch<A> = (action: A) => void;
|
|
8
|
-
|
|
9
|
-
const dispatchOnFiber = (
|
|
10
|
-
fiber: ResourceFiber<any, any>,
|
|
11
|
-
callback: () => (() => void) | null,
|
|
12
|
-
): void => {
|
|
13
|
-
if (fiber.renderContext) {
|
|
14
|
-
throw new Error("Resource updated during render");
|
|
15
|
-
}
|
|
16
|
-
if (fiber.isNeverMounted) {
|
|
17
|
-
throw new Error("Resource updated before mount");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
fiber.root.dispatchUpdate(() => {
|
|
21
|
-
const result = callback();
|
|
22
|
-
if (result) {
|
|
23
|
-
result();
|
|
24
|
-
fiber.root.changelog.push(result);
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
return false;
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
function useReducerImpl<S, A, I, R extends S>(
|
|
32
|
-
reducer: (state: S, action: A) => S,
|
|
33
|
-
getDerivedState: ((state: S) => R) | undefined,
|
|
34
|
-
initialArg: S | I,
|
|
35
|
-
initFn: ((arg: I) => S) | undefined,
|
|
36
|
-
): [R, Dispatch<A>] {
|
|
37
|
-
const cell = useCell("reducer", () => {
|
|
38
|
-
const fiber = getCurrentResourceFiber();
|
|
39
|
-
|
|
40
|
-
// First render: compute initial state
|
|
41
|
-
const initialState = initFn ? initFn(initialArg as I) : initialArg;
|
|
42
|
-
|
|
43
|
-
if (isDevelopment && fiber.devStrictMode && initFn) {
|
|
44
|
-
void initFn(initialArg as I);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
type: "reducer",
|
|
49
|
-
queue: new Set(),
|
|
50
|
-
dirty: false,
|
|
51
|
-
workInProgress: initialState,
|
|
52
|
-
current: initialState,
|
|
53
|
-
reducer,
|
|
54
|
-
dispatch: (action: A) => {
|
|
55
|
-
const entry: ReducerQueueEntry = {
|
|
56
|
-
action,
|
|
57
|
-
hasEagerState: false,
|
|
58
|
-
eagerState: undefined,
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
dispatchOnFiber(fiber, () => {
|
|
62
|
-
if (fiber.root.dirtyCells.length === 0 && !entry.hasEagerState) {
|
|
63
|
-
entry.eagerState = reducer(cell.workInProgress, action);
|
|
64
|
-
entry.hasEagerState = true;
|
|
65
|
-
|
|
66
|
-
if (Object.is(cell.current, entry.eagerState)) return null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return () => {
|
|
70
|
-
markCellDirty(fiber, cell);
|
|
71
|
-
cell.queue.add(entry);
|
|
72
|
-
};
|
|
73
|
-
});
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
const fiber = getCurrentResourceFiber();
|
|
79
|
-
const sameReducer = reducer === cell.reducer;
|
|
80
|
-
cell.reducer = reducer;
|
|
81
|
-
|
|
82
|
-
for (const item of cell.queue) {
|
|
83
|
-
if (!item.hasEagerState || !sameReducer) {
|
|
84
|
-
item.eagerState = reducer(cell.workInProgress, item.action);
|
|
85
|
-
item.hasEagerState = true;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (isDevelopment && fiber.devStrictMode) {
|
|
89
|
-
void reducer(cell.workInProgress, item.action);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
cell.workInProgress = item.eagerState;
|
|
93
|
-
}
|
|
94
|
-
cell.queue.clear();
|
|
95
|
-
|
|
96
|
-
if (getDerivedState) {
|
|
97
|
-
const derived = getDerivedState(cell.workInProgress);
|
|
98
|
-
|
|
99
|
-
if (!Object.is(derived, cell.workInProgress)) {
|
|
100
|
-
markCellDirty(fiber, cell);
|
|
101
|
-
cell.workInProgress = derived;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return [cell.workInProgress, cell.dispatch];
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export function useReducer<S, A>(
|
|
109
|
-
reducer: (state: S, action: A) => S,
|
|
110
|
-
initialState: S,
|
|
111
|
-
): [S, Dispatch<A>];
|
|
112
|
-
export function useReducer<S, A, I>(
|
|
113
|
-
reducer: (state: S, action: A) => S,
|
|
114
|
-
initialArg: I,
|
|
115
|
-
init: (arg: I) => S,
|
|
116
|
-
): [S, Dispatch<A>];
|
|
117
|
-
export function useReducer<S, A, I>(
|
|
118
|
-
reducer: (state: S, action: A) => S,
|
|
119
|
-
initialArg: S | I,
|
|
120
|
-
init?: (arg: I) => S,
|
|
121
|
-
): [S, Dispatch<A>] {
|
|
122
|
-
return useReducerImpl(
|
|
123
|
-
reducer,
|
|
124
|
-
undefined,
|
|
125
|
-
initialArg as S,
|
|
126
|
-
init as ((arg: S) => S) | undefined,
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* @deprecated experimental — a `getDerivedStateFromProps` replacement for
|
|
132
|
-
* resources: adjust state in response to props without setting during render.
|
|
133
|
-
* Tap-only for now (call it inside a resource render, not a React component) and
|
|
134
|
-
* may change before stabilizing.
|
|
135
|
-
*/
|
|
136
|
-
export function useReducerWithDerivedState<S, A, R extends S>(
|
|
137
|
-
reducer: (state: S, action: A) => S,
|
|
138
|
-
getDerivedState: (state: S) => R,
|
|
139
|
-
initialState: S,
|
|
140
|
-
): [R, Dispatch<A>];
|
|
141
|
-
/**
|
|
142
|
-
* @deprecated experimental — a `getDerivedStateFromProps` replacement for
|
|
143
|
-
* resources: adjust state in response to props without setting during render.
|
|
144
|
-
* Tap-only for now (call it inside a resource render, not a React component) and
|
|
145
|
-
* may change before stabilizing.
|
|
146
|
-
*/
|
|
147
|
-
export function useReducerWithDerivedState<S, A, I, R extends S>(
|
|
148
|
-
reducer: (state: S, action: A) => S,
|
|
149
|
-
getDerivedState: (state: S) => R,
|
|
150
|
-
initialArg: I,
|
|
151
|
-
init: (arg: I) => S,
|
|
152
|
-
): [R, Dispatch<A>];
|
|
153
|
-
export function useReducerWithDerivedState<S, A, I, R extends S>(
|
|
154
|
-
reducer: (state: S, action: A) => S,
|
|
155
|
-
getDerivedState: (state: S) => R,
|
|
156
|
-
initialArg: I,
|
|
157
|
-
init?: (arg: I) => S,
|
|
158
|
-
): [R, Dispatch<A>] {
|
|
159
|
-
return useReducerImpl(reducer, getDerivedState, initialArg, init);
|
|
160
|
-
}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
commitResourceFiber,
|
|
3
|
-
createResourceFiber,
|
|
4
|
-
renderResourceFiber,
|
|
5
|
-
unmountResourceFiber,
|
|
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";
|
|
14
|
-
import {
|
|
15
|
-
commitRoot,
|
|
16
|
-
createResourceFiberRoot,
|
|
17
|
-
setRootVersion,
|
|
18
|
-
} from "../core/helpers/root";
|
|
19
|
-
|
|
20
|
-
export namespace useResourceRoot {
|
|
21
|
-
export type Unsubscribe = () => void;
|
|
22
|
-
|
|
23
|
-
export interface SubscribableResource<TState> {
|
|
24
|
-
/**
|
|
25
|
-
* Get the current state of the store.
|
|
26
|
-
*/
|
|
27
|
-
getValue(): TState;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Subscribe to the store.
|
|
31
|
-
*/
|
|
32
|
-
subscribe(listener: () => void): Unsubscribe;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// The root is never reset, because rollbacks are not supported in useResourceRoot.
|
|
37
|
-
|
|
38
|
-
export const useResourceRoot = <TState>(
|
|
39
|
-
element: ResourceElement<TState>,
|
|
40
|
-
): useResourceRoot.SubscribableResource<TState> => {
|
|
41
|
-
const scheduler = useMemo(
|
|
42
|
-
() => new UpdateScheduler(() => handleUpdate(null)),
|
|
43
|
-
[],
|
|
44
|
-
);
|
|
45
|
-
const queue = useMemo(() => [] as (() => void)[], []);
|
|
46
|
-
|
|
47
|
-
const fiber = useMemo(() => {
|
|
48
|
-
void element.key;
|
|
49
|
-
|
|
50
|
-
return createResourceFiber(
|
|
51
|
-
element.type,
|
|
52
|
-
createResourceFiberRoot((callback) => {
|
|
53
|
-
if (!scheduler.isDirty && !callback()) return;
|
|
54
|
-
queue.push(callback);
|
|
55
|
-
scheduler.markDirty();
|
|
56
|
-
}),
|
|
57
|
-
);
|
|
58
|
-
}, [element.type, element.key, queue, scheduler]);
|
|
59
|
-
|
|
60
|
-
setRootVersion(fiber.root, fiber.root.committedVersion);
|
|
61
|
-
const render = renderResourceFiber(fiber, element.props);
|
|
62
|
-
|
|
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) => {
|
|
68
|
-
if (render === null) {
|
|
69
|
-
setRootVersion(fiber.root, 2);
|
|
70
|
-
setRootVersion(fiber.root, 1);
|
|
71
|
-
|
|
72
|
-
queue.forEach((callback) => {
|
|
73
|
-
if (isDevelopment && fiber.devStrictMode) {
|
|
74
|
-
callback();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
callback();
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
if (isDevelopment && fiber.devStrictMode) {
|
|
81
|
-
void renderResourceFiber(fiber, committedPropsRef.current);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
render = renderResourceFiber(fiber, committedPropsRef.current);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (scheduler.isDirty)
|
|
88
|
-
throw new Error("Scheduler is dirty, this should never happen");
|
|
89
|
-
|
|
90
|
-
commitRoot(fiber.root);
|
|
91
|
-
queue.length = 0;
|
|
92
|
-
|
|
93
|
-
if (isMountedRef.current) {
|
|
94
|
-
commitResourceFiber(fiber, render);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (scheduler.isDirty || valueRef.current === render.output) return;
|
|
98
|
-
valueRef.current = render.output;
|
|
99
|
-
subscribers.forEach((callback) => callback());
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
useEffect(() => {
|
|
103
|
-
isMountedRef.current = true;
|
|
104
|
-
return () => {
|
|
105
|
-
isMountedRef.current = false;
|
|
106
|
-
unmountResourceFiber(fiber);
|
|
107
|
-
};
|
|
108
|
-
}, [fiber]);
|
|
109
|
-
|
|
110
|
-
useEffect(() => {
|
|
111
|
-
committedPropsRef.current = render.props;
|
|
112
|
-
commitRoot(fiber.root);
|
|
113
|
-
commitResourceFiber(fiber, render);
|
|
114
|
-
|
|
115
|
-
if (scheduler.isDirty || valueRef.current === render.output) return;
|
|
116
|
-
valueRef.current = render.output;
|
|
117
|
-
subscribers.forEach((callback) => callback());
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
return useMemo(
|
|
121
|
-
() => ({
|
|
122
|
-
getValue: () => valueRef.current,
|
|
123
|
-
subscribe: (listener: () => void) => {
|
|
124
|
-
subscribers.add(listener);
|
|
125
|
-
return () => subscribers.delete(listener);
|
|
126
|
-
},
|
|
127
|
-
}),
|
|
128
|
-
[subscribers],
|
|
129
|
-
);
|
|
130
|
-
};
|
package/src/react/hooks.ts
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
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
|
-
);
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|