@simpreact/simpreact 0.0.8 → 0.0.9
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/compat/core.js +101 -15
- package/compat/hooks.js +15 -0
- package/compat/index.d.ts +10 -1
- package/compat/renderRuntime.js +47 -12
- package/component/index.js +96 -94
- package/context/index.js +27 -17
- package/core/createElement.js +14 -17
- package/core/flags.js +31 -0
- package/core/hostOperations.js +5 -13
- package/core/index.d.ts +38 -8
- package/core/index.js +3 -2
- package/core/internal.d.ts +136 -16
- package/core/internal.js +8 -16
- package/core/lifecycleEventBus.js +35 -16
- package/core/memo.js +4 -1
- package/core/mounting.js +70 -150
- package/core/mountingChildren.js +11 -29
- package/core/patching.js +122 -181
- package/core/patchingChildren.js +74 -145
- package/core/portal.js +1 -1
- package/core/processStack.js +115 -45
- package/core/ref.js +1 -0
- package/core/rerender.js +20 -22
- package/core/runtime.js +10 -2
- package/core/unmounting.js +41 -49
- package/core/unmountingChildren.js +9 -12
- package/core/utils.js +38 -16
- package/dom/attach-element-to-dom.js +16 -8
- package/dom/events.js +11 -15
- package/dom/index.d.ts +2 -0
- package/dom/props/attrMaps.js +90 -0
- package/dom/props/controlled/select.js +8 -10
- package/dom/props/props.js +13 -14
- package/hooks/index.d.ts +3 -0
- package/hooks/index.js +107 -84
- package/package.json +10 -5
- package/compat/context.d.ts +0 -7
- package/compat/core.d.ts +0 -48
- package/compat/dom.d.ts +0 -10
- package/compat/hooks.d.ts +0 -26
- package/compat/jsx-runtime.d.ts +0 -10
- package/compat/renderRuntime.d.ts +0 -6
- package/core/createElement.d.ts +0 -39
- package/core/fragment.d.ts +0 -5
- package/core/hostAdapter.d.ts +0 -23
- package/core/hostOperations.d.ts +0 -5
- package/core/lifecycleEventBus.d.ts +0 -39
- package/core/memo.d.ts +0 -8
- package/core/mounting.d.ts +0 -7
- package/core/mountingChildren.d.ts +0 -4
- package/core/patching.d.ts +0 -8
- package/core/patchingChildren.d.ts +0 -6
- package/core/portal.d.ts +0 -2
- package/core/processStack.d.ts +0 -106
- package/core/ref.d.ts +0 -18
- package/core/rerender.d.ts +0 -4
- package/core/runtime.d.ts +0 -17
- package/core/unmounting.d.ts +0 -7
- package/core/unmountingChildren.d.ts +0 -4
- package/core/utils.d.ts +0 -11
- package/dom/attach-element-to-dom.d.ts +0 -5
- package/dom/domAdapter.d.ts +0 -3
- package/dom/events.d.ts +0 -27
- package/dom/namespace.d.ts +0 -2
- package/dom/props/controlled/index.d.ts +0 -7
- package/dom/props/controlled/input.d.ts +0 -7
- package/dom/props/controlled/select.d.ts +0 -6
- package/dom/props/controlled/textarea.d.ts +0 -6
- package/dom/props/dangerInnerHTML.d.ts +0 -7
- package/dom/props/index.d.ts +0 -1
- package/dom/props/props.d.ts +0 -5
- package/dom/props/style.d.ts +0 -1
- package/dom/render.d.ts +0 -8
- package/shared/lang.d.ts +0 -3
- package/shared/utils.d.ts +0 -5
package/compat/core.js
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
import { createElement as _createElement, createPortal as _createPortal, Fragment as _Fragment, memo as _memo, } from '../core/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { isFragment, isPortal, withSyncRerender } from '../core/internal.js';
|
|
3
3
|
import { useCatch, useState } from './hooks.js';
|
|
4
|
+
import { renderRuntime } from './renderRuntime.js';
|
|
5
|
+
// Threads refs through FC elements without polluting string-keyed props.
|
|
6
|
+
// Symbol keys are invisible to `for…in` and Object.keys, so they never
|
|
7
|
+
// accidentally end up on HOST elements via `{...props}` spread.
|
|
8
|
+
export const REF_SYMBOL = Symbol('simpreact.compat.ref');
|
|
9
|
+
// Wraps core createElement to strip `ref` from FC props (matching React's
|
|
10
|
+
// model where ref is not part of the props the component receives).
|
|
11
|
+
export function createElement(type, props, ...args) {
|
|
12
|
+
if (typeof type === 'function' && props != null && 'ref' in props) {
|
|
13
|
+
const { ref, ...restProps } = props;
|
|
14
|
+
if (ref != null) {
|
|
15
|
+
restProps[REF_SYMBOL] = ref;
|
|
16
|
+
}
|
|
17
|
+
return _createElement(type, restProps, ...args);
|
|
18
|
+
}
|
|
19
|
+
return _createElement(type, props, ...args);
|
|
20
|
+
}
|
|
4
21
|
export const Children = {
|
|
5
22
|
map(children, fn) {
|
|
6
23
|
return Children.toArray(children).map(fn);
|
|
@@ -40,47 +57,112 @@ export function cloneElement(element, props, ...children) {
|
|
|
40
57
|
if (!isValidElement(element)) {
|
|
41
58
|
throw new Error(`cloneElement: expected a SimpElement, got ${element}`);
|
|
42
59
|
}
|
|
43
|
-
if ((element
|
|
60
|
+
if (isPortal(element)) {
|
|
44
61
|
throw new Error('cloneElement: the argument must be a SimpElement, but you passed a portal instead.');
|
|
45
62
|
}
|
|
46
|
-
|
|
63
|
+
const mergedProps = Object.assign({}, element.props, props);
|
|
64
|
+
const resolvedChildren = arguments.length > 2 ? children : mergedProps.children !== undefined ? mergedProps.children : element.children;
|
|
65
|
+
return createElement(isFragment(element) ? Fragment : element.type, mergedProps, resolvedChildren);
|
|
47
66
|
}
|
|
48
67
|
export function isValidElement(element) {
|
|
49
68
|
return typeof element === 'object' && element !== null && 'flag' in element;
|
|
50
69
|
}
|
|
51
70
|
export function Suspense(props) {
|
|
52
|
-
const [
|
|
71
|
+
const [pendingCount, setPendingCount] = useState(0);
|
|
53
72
|
useCatch(error => {
|
|
54
73
|
if (!(error instanceof Promise)) {
|
|
55
74
|
throw error;
|
|
56
75
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
setIsSuspended(true);
|
|
61
|
-
error.then(() => setIsSuspended(false));
|
|
76
|
+
setPendingCount(c => c + 1);
|
|
77
|
+
error.then(() => setPendingCount(c => c - 1));
|
|
62
78
|
});
|
|
63
|
-
return
|
|
79
|
+
return pendingCount > 0 ? props.fallback : props.children;
|
|
64
80
|
}
|
|
65
81
|
export function StrictMode(props) {
|
|
66
82
|
return props.children;
|
|
67
83
|
}
|
|
84
|
+
// Reads the ref from the Symbol slot so that string-keyed `ref` never
|
|
85
|
+
// appears in the props the inner component receives.
|
|
68
86
|
export function forwardRef(Component) {
|
|
69
87
|
return function Forwarded(props) {
|
|
70
|
-
|
|
88
|
+
const ref = props?.[REF_SYMBOL] ?? null;
|
|
89
|
+
if (props != null && REF_SYMBOL in props) {
|
|
90
|
+
const { [REF_SYMBOL]: _, ...restProps } = props;
|
|
91
|
+
return Component(restProps, ref);
|
|
92
|
+
}
|
|
93
|
+
return Component(props, ref);
|
|
71
94
|
};
|
|
72
95
|
}
|
|
96
|
+
export const version = '18.3.1';
|
|
73
97
|
export const Fragment = _Fragment;
|
|
74
|
-
export const createElement = _createElement;
|
|
75
98
|
export const createPortal = _createPortal;
|
|
76
99
|
export const memo = _memo;
|
|
77
|
-
|
|
100
|
+
// Minimal React / ReactDOM internals shim for react-dom/test-utils.
|
|
101
|
+
export const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {
|
|
102
|
+
ReactCurrentOwner: { current: null },
|
|
103
|
+
ReactCurrentDispatcher: { current: null },
|
|
104
|
+
ReactCurrentBatchConfig: { transition: null },
|
|
105
|
+
// react-dom/test-utils: var EventInternals = SecretInternals.Events; EventInternals[0..4]
|
|
106
|
+
Events: [
|
|
107
|
+
/* getInstanceFromNode */ _node => null,
|
|
108
|
+
/* getNodeFromInstance */ _inst => null,
|
|
109
|
+
/* getFiberCurrentPropsFromNode */ _node => null,
|
|
110
|
+
/* enqueueStateRestore */ () => { },
|
|
111
|
+
/* restoreStateIfNeeded */ () => { },
|
|
112
|
+
],
|
|
113
|
+
};
|
|
114
|
+
// react-dom/test-utils uses React.unstable_act / React.act for flushing updates.
|
|
115
|
+
export async function unstable_act(callback) {
|
|
116
|
+
const result = callback();
|
|
117
|
+
if (result && typeof result.then === 'function')
|
|
118
|
+
await result;
|
|
119
|
+
await Promise.resolve();
|
|
120
|
+
}
|
|
121
|
+
export { unstable_act as act };
|
|
122
|
+
export function flushSync(callback) {
|
|
123
|
+
let result;
|
|
124
|
+
withSyncRerender(renderRuntime, () => {
|
|
125
|
+
result = callback();
|
|
126
|
+
});
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
export function lazy(factory) {
|
|
130
|
+
let state = null;
|
|
131
|
+
return function LazyComponent(props) {
|
|
132
|
+
if (state === null) {
|
|
133
|
+
const promise = factory().then(mod => {
|
|
134
|
+
state = { status: 'resolved', component: mod.default };
|
|
135
|
+
}, reason => {
|
|
136
|
+
state = { status: 'rejected', reason };
|
|
137
|
+
});
|
|
138
|
+
state = { status: 'pending', promise };
|
|
139
|
+
}
|
|
140
|
+
if (state.status === 'pending') {
|
|
141
|
+
throw state.promise;
|
|
142
|
+
}
|
|
143
|
+
if (state.status === 'rejected') {
|
|
144
|
+
throw state.reason;
|
|
145
|
+
}
|
|
146
|
+
return createElement(state.component, props);
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
// Minimal base class for React-style class components.
|
|
150
|
+
// setState and forceUpdate are no-ops here; the compat renderer overrides
|
|
151
|
+
// them on each instance with real implementations backed by the render queue.
|
|
78
152
|
export class Component {
|
|
79
|
-
constructor() {
|
|
80
|
-
|
|
153
|
+
constructor(props) {
|
|
154
|
+
this.props = props;
|
|
155
|
+
this.state = {};
|
|
156
|
+
}
|
|
157
|
+
setState(_updater, _callback) { }
|
|
158
|
+
forceUpdate(_callback) { }
|
|
159
|
+
render() {
|
|
160
|
+
throw new Error('Component.render() must be implemented by the subclass.');
|
|
81
161
|
}
|
|
82
162
|
}
|
|
163
|
+
Component.prototype.isReactComponent = true;
|
|
83
164
|
export default {
|
|
165
|
+
version,
|
|
84
166
|
Children,
|
|
85
167
|
cloneElement,
|
|
86
168
|
isValidElement,
|
|
@@ -92,5 +174,9 @@ export default {
|
|
|
92
174
|
createPortal,
|
|
93
175
|
memo,
|
|
94
176
|
flushSync,
|
|
177
|
+
lazy,
|
|
95
178
|
Component,
|
|
179
|
+
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
|
|
180
|
+
unstable_act,
|
|
181
|
+
act: unstable_act,
|
|
96
182
|
};
|
package/compat/hooks.js
CHANGED
|
@@ -65,15 +65,30 @@ export function useMemo(factory, deps) {
|
|
|
65
65
|
export function useCallback(cb, deps) {
|
|
66
66
|
return useMemo(() => cb, deps);
|
|
67
67
|
}
|
|
68
|
+
export function useImperativeHandle(ref, init, deps) {
|
|
69
|
+
useLayoutEffect(() => {
|
|
70
|
+
if (typeof ref === 'function') {
|
|
71
|
+
ref(init());
|
|
72
|
+
}
|
|
73
|
+
else if (ref != null) {
|
|
74
|
+
ref.current = init();
|
|
75
|
+
}
|
|
76
|
+
}, deps);
|
|
77
|
+
}
|
|
78
|
+
export function useDebugValue(_value, _format) { }
|
|
68
79
|
export default {
|
|
69
80
|
useSyncExternalStore,
|
|
70
81
|
useReducer,
|
|
71
82
|
useId,
|
|
72
83
|
useMemo,
|
|
73
84
|
useCallback,
|
|
85
|
+
useImperativeHandle,
|
|
86
|
+
useDebugValue,
|
|
74
87
|
useState,
|
|
75
88
|
useEffect,
|
|
76
89
|
useLayoutEffect,
|
|
77
90
|
useInsertionEffect,
|
|
78
91
|
useRef,
|
|
92
|
+
useRerender,
|
|
93
|
+
useCatch,
|
|
79
94
|
};
|
package/compat/index.d.ts
CHANGED
|
@@ -50,6 +50,12 @@ export declare function useReducer<R extends (state: any, action: any) => any, I
|
|
|
50
50
|
export declare function useId(prefix?: string): string;
|
|
51
51
|
export declare function useMemo<T>(factory: () => T, deps: DependencyList): T;
|
|
52
52
|
export declare function useCallback<T>(cb: T, deps: DependencyList): T;
|
|
53
|
+
export declare function useImperativeHandle<T>(
|
|
54
|
+
ref: { current: T | null } | ((value: T | null) => void) | null | undefined,
|
|
55
|
+
init: () => T,
|
|
56
|
+
deps?: DependencyList
|
|
57
|
+
): void;
|
|
58
|
+
export declare function useDebugValue(value: unknown, format?: (value: unknown) => unknown): void;
|
|
53
59
|
export declare function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
|
|
54
60
|
export declare function useState<S>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];
|
|
55
61
|
export declare function useEffect(effect: Effect, deps?: DependencyList): void;
|
|
@@ -58,7 +64,7 @@ export declare function useInsertionEffect(effect: Effect, deps?: DependencyList
|
|
|
58
64
|
export declare function useRef<T>(initialValue: T): RefObject<T>;
|
|
59
65
|
export declare function useRef<T>(initialValue: T | null): RefObject<T | null>;
|
|
60
66
|
export declare function useRef<T = undefined>(initialValue?: T): RefObject<T | undefined>;
|
|
61
|
-
export declare function useCatch(
|
|
67
|
+
export declare function useCatch(handler: (error: unknown) => void): void;
|
|
62
68
|
|
|
63
69
|
export declare function hydrate(): void;
|
|
64
70
|
export declare function render(element: SimpElement, parentReference: Nullable<HTMLElement>): void;
|
|
@@ -94,6 +100,9 @@ export declare function createPortal(children: SimpNode, container: any): SimpEl
|
|
|
94
100
|
|
|
95
101
|
export declare function memo(Component: FC, compare: (objA: any, objB: any) => boolean): FC;
|
|
96
102
|
export declare function flushSync(value: any): any;
|
|
103
|
+
export declare function lazy<T extends FC<any>>(factory: () => Promise<{ default: T }>): FC<any>;
|
|
104
|
+
|
|
105
|
+
export declare const version: string;
|
|
97
106
|
|
|
98
107
|
export declare class Component {}
|
|
99
108
|
|
package/compat/renderRuntime.js
CHANGED
|
@@ -1,17 +1,52 @@
|
|
|
1
1
|
import { domAdapter } from '../dom/index.js';
|
|
2
|
+
import { createUseEffect, createUseRef, createUseRerender } from '../hooks/index.js';
|
|
3
|
+
import { createRenderRuntime } from '../core/internal.js';
|
|
2
4
|
import { emptyObject } from '../shared/index.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
// Lazily assigned after renderRuntime is created to avoid a circular reference
|
|
6
|
+
// at module-evaluation time. All are set before any render can fire.
|
|
7
|
+
let useRef;
|
|
8
|
+
let useRerender;
|
|
9
|
+
let useLayoutEffect;
|
|
10
|
+
export const renderRuntime = createRenderRuntime(domAdapter, function renderer(component, element) {
|
|
11
|
+
const props = element.props || emptyObject;
|
|
12
|
+
const proto = component.prototype;
|
|
13
|
+
if (proto?.isReactComponent || proto?.render) {
|
|
14
|
+
// Persist the instance across re-renders so state is not reset on every
|
|
15
|
+
// render cycle. Hook calls run in the current FC render context.
|
|
16
|
+
const instRef = useRef(null);
|
|
17
|
+
const rerender = useRerender();
|
|
18
|
+
if (instRef.current === null) {
|
|
19
|
+
instRef.current = new component(props);
|
|
20
|
+
if (instRef.current.state == null) {
|
|
21
|
+
instRef.current.state = {};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const inst = instRef.current;
|
|
25
|
+
inst.props = props;
|
|
26
|
+
// Override the no-op stubs from Component base with real implementations.
|
|
27
|
+
inst.setState = function (updater, callback) {
|
|
28
|
+
const prevState = inst.state;
|
|
29
|
+
const patch = typeof updater === 'function' ? updater(prevState, inst.props) : updater;
|
|
30
|
+
inst.state = Object.assign({}, prevState, patch);
|
|
31
|
+
rerender();
|
|
32
|
+
callback?.();
|
|
33
|
+
};
|
|
34
|
+
inst.forceUpdate = function (callback) {
|
|
35
|
+
rerender();
|
|
36
|
+
callback?.();
|
|
37
|
+
};
|
|
38
|
+
useLayoutEffect(() => {
|
|
39
|
+
if (typeof inst.componentDidMount === 'function') {
|
|
40
|
+
inst.componentDidMount();
|
|
41
|
+
}
|
|
42
|
+
}, []);
|
|
43
|
+
return inst.render();
|
|
44
|
+
}
|
|
45
|
+
return component(props);
|
|
46
|
+
});
|
|
47
|
+
useRef = createUseRef(renderRuntime);
|
|
48
|
+
useRerender = createUseRerender(renderRuntime);
|
|
49
|
+
useLayoutEffect = createUseEffect(renderRuntime);
|
|
13
50
|
export default {
|
|
14
51
|
renderRuntime,
|
|
15
52
|
};
|
|
16
|
-
// TODO
|
|
17
|
-
window.__SIMP_RUNTIME__ = renderRuntime;
|
package/component/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isFC, registerLifecyclePlugin, rerender, } from '../core/internal.js';
|
|
2
2
|
import { emptyObject, shallowEqual, } from '../shared/index.js';
|
|
3
|
-
const
|
|
4
|
-
function getComponentSpecificStore(
|
|
5
|
-
let hooksSpecificStore =
|
|
3
|
+
const componentSpecificStoreByElement = new WeakMap();
|
|
4
|
+
function getComponentSpecificStore(element, renderRuntime) {
|
|
5
|
+
let hooksSpecificStore = componentSpecificStoreByElement.get(element);
|
|
6
6
|
if (!hooksSpecificStore) {
|
|
7
7
|
function _rerender() {
|
|
8
|
-
rerender(
|
|
8
|
+
rerender(element, renderRuntime);
|
|
9
9
|
}
|
|
10
10
|
hooksSpecificStore = {
|
|
11
11
|
context: {
|
|
@@ -17,121 +17,123 @@ function getComponentSpecificStore(store, renderRuntime) {
|
|
|
17
17
|
pendingEffectStates: null,
|
|
18
18
|
effectStates: null,
|
|
19
19
|
};
|
|
20
|
-
|
|
20
|
+
componentSpecificStoreByElement.set(element, hooksSpecificStore);
|
|
21
21
|
}
|
|
22
22
|
return hooksSpecificStore;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (event.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
let element = event.element;
|
|
30
|
-
let curError = event.error;
|
|
31
|
-
let catchers;
|
|
32
|
-
while (element) {
|
|
33
|
-
if (!isComponentElement(element)) {
|
|
34
|
-
element = element.parent;
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
const store = getComponentSpecificStore(element.store, event.renderRuntime);
|
|
38
|
-
catchers = store.context.catchers;
|
|
39
|
-
if (!catchers) {
|
|
40
|
-
element = element.parent;
|
|
41
|
-
continue;
|
|
24
|
+
registerLifecyclePlugin(bus => {
|
|
25
|
+
bus.subscribe(event => {
|
|
26
|
+
if (event.type === 'errored') {
|
|
27
|
+
if (event.handled) {
|
|
28
|
+
return;
|
|
42
29
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
30
|
+
let element = event.element;
|
|
31
|
+
let curError = event.error;
|
|
32
|
+
let catchers;
|
|
33
|
+
while (element) {
|
|
34
|
+
if (!isComponentElement(element)) {
|
|
35
|
+
element = element.parent;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const store = getComponentSpecificStore(element, event.renderRuntime);
|
|
39
|
+
catchers = store.context.catchers;
|
|
40
|
+
if (!catchers) {
|
|
41
|
+
element = element.parent;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
for (let i = 0; i < catchers.length; i++) {
|
|
46
|
+
catchers[i](curError);
|
|
47
|
+
}
|
|
48
|
+
event.handled = true;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
element = element.parent;
|
|
53
|
+
curError = error;
|
|
46
54
|
}
|
|
47
|
-
event.handled = true;
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
element = element.parent;
|
|
52
|
-
curError = error;
|
|
53
55
|
}
|
|
56
|
+
return;
|
|
54
57
|
}
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
if (!isComponentElement(event.element)) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
const store = getComponentSpecificStore(event.element.store, event.renderRuntime);
|
|
61
|
-
switch (event.type) {
|
|
62
|
-
case 'beforeRender': {
|
|
63
|
-
store.context.effects = [];
|
|
64
|
-
store.context.catchers = [];
|
|
65
|
-
store.pendingEffectStates = null;
|
|
58
|
+
if (!isComponentElement(event.element)) {
|
|
66
59
|
return;
|
|
67
60
|
}
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
const store = getComponentSpecificStore(event.element, event.renderRuntime);
|
|
62
|
+
switch (event.type) {
|
|
63
|
+
case 'beforeRender': {
|
|
64
|
+
store.context.effects = [];
|
|
65
|
+
store.context.catchers = [];
|
|
66
|
+
store.pendingEffectStates = null;
|
|
70
67
|
return;
|
|
71
68
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (!state) {
|
|
76
|
-
state = store.effectStates[i] = {
|
|
77
|
-
effect: renderEffectState.effect,
|
|
78
|
-
deps: null,
|
|
79
|
-
cleanup: null,
|
|
80
|
-
};
|
|
69
|
+
case 'afterRender': {
|
|
70
|
+
if (!store.context.effects) {
|
|
71
|
+
return;
|
|
81
72
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
state
|
|
85
|
-
|
|
73
|
+
for (let i = 0; i < store.context.effects.length; i++) {
|
|
74
|
+
const renderEffectState = store.context.effects[i];
|
|
75
|
+
let state = (store.effectStates ||= [])[i];
|
|
76
|
+
if (!state) {
|
|
77
|
+
state = store.effectStates[i] = {
|
|
78
|
+
effect: renderEffectState.effect,
|
|
79
|
+
deps: null,
|
|
80
|
+
cleanup: null,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
if (!shallowEqual(renderEffectState.deps, state.deps)) {
|
|
84
|
+
state.effect = renderEffectState.effect;
|
|
85
|
+
state.deps = renderEffectState.deps || null;
|
|
86
|
+
(store.pendingEffectStates ||= []).push(state);
|
|
87
|
+
}
|
|
86
88
|
}
|
|
87
|
-
}
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
case 'mounted': {
|
|
91
|
-
if (!store.pendingEffectStates) {
|
|
92
89
|
return;
|
|
93
90
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
91
|
+
case 'mounted': {
|
|
92
|
+
if (!store.pendingEffectStates) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const effects = store.pendingEffectStates;
|
|
96
|
+
store.pendingEffectStates = null;
|
|
97
|
+
for (const state of effects) {
|
|
98
|
+
if (typeof state.cleanup === 'function') {
|
|
99
|
+
state.cleanup();
|
|
100
|
+
}
|
|
101
|
+
state.cleanup = state.effect() || null;
|
|
99
102
|
}
|
|
100
|
-
state.cleanup = state.effect() || null;
|
|
101
|
-
}
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
case 'updated': {
|
|
105
|
-
if (!store.pendingEffectStates) {
|
|
106
103
|
return;
|
|
107
104
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
105
|
+
case 'updated': {
|
|
106
|
+
if (!store.pendingEffectStates) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const effects = store.pendingEffectStates;
|
|
110
|
+
store.pendingEffectStates = null;
|
|
111
|
+
for (const state of effects) {
|
|
112
|
+
if (typeof state.cleanup === 'function') {
|
|
113
|
+
state.cleanup();
|
|
114
|
+
}
|
|
115
|
+
state.cleanup = state.effect() || null;
|
|
113
116
|
}
|
|
114
|
-
state.cleanup = state.effect() || null;
|
|
115
|
-
}
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
case 'unmounted': {
|
|
119
|
-
if (!store.effectStates) {
|
|
120
117
|
return;
|
|
121
118
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
119
|
+
case 'unmounted': {
|
|
120
|
+
if (!store.effectStates) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const effects = store.effectStates;
|
|
124
|
+
store.effectStates = null;
|
|
125
|
+
for (const state of effects) {
|
|
126
|
+
if (state && 'cleanup' in state && typeof state.cleanup === 'function') {
|
|
127
|
+
state.cleanup();
|
|
128
|
+
}
|
|
127
129
|
}
|
|
128
130
|
}
|
|
129
131
|
}
|
|
130
|
-
}
|
|
132
|
+
});
|
|
131
133
|
});
|
|
132
134
|
export function componentRenderer(component, element, renderRuntime) {
|
|
133
135
|
if (isComponentElement(element)) {
|
|
134
|
-
const store = getComponentSpecificStore(element
|
|
136
|
+
const store = getComponentSpecificStore(element, renderRuntime);
|
|
135
137
|
return component(element.props || emptyObject, store.context);
|
|
136
138
|
}
|
|
137
139
|
else {
|
|
@@ -160,5 +162,5 @@ export function createState(onChange) {
|
|
|
160
162
|
});
|
|
161
163
|
}
|
|
162
164
|
export function isComponentElement(element) {
|
|
163
|
-
return element
|
|
165
|
+
return isFC(element) && element.type._isComponent;
|
|
164
166
|
}
|
package/context/index.js
CHANGED
|
@@ -1,27 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { registerLifecyclePlugin, rerender, } from '../core/internal.js';
|
|
2
|
+
const currentFCByRuntime = new WeakMap();
|
|
3
|
+
registerLifecyclePlugin(bus => {
|
|
4
|
+
bus.subscribe(event => {
|
|
5
|
+
if (event.type === 'beforeRender') {
|
|
6
|
+
currentFCByRuntime.set(event.renderRuntime, event.element);
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
else if (event.type === 'afterRender' || event.type === 'errored') {
|
|
9
|
+
currentFCByRuntime.set(event.renderRuntime, null);
|
|
10
|
+
}
|
|
11
|
+
if (event.type === 'unmounted' && event.element.context) {
|
|
12
|
+
const contextMap = event.element.context;
|
|
13
|
+
for (const entry of contextMap.values()) {
|
|
14
|
+
entry.subs.delete(event.element);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
});
|
|
9
18
|
});
|
|
10
19
|
export function createCreateContext(renderRuntime) {
|
|
11
20
|
return defaultValue => {
|
|
21
|
+
const providerElements = new WeakSet();
|
|
12
22
|
const context = {
|
|
13
23
|
defaultValue,
|
|
14
24
|
Provider(props) {
|
|
15
|
-
const currentElement = renderRuntime
|
|
16
|
-
const
|
|
25
|
+
const currentElement = currentFCByRuntime.get(renderRuntime);
|
|
26
|
+
const isFirstRender = !providerElements.has(currentElement);
|
|
17
27
|
let contextMap = currentElement.context;
|
|
18
28
|
if (!contextMap) {
|
|
19
29
|
currentElement.context = contextMap = new Map();
|
|
30
|
+
providerElements.add(currentElement);
|
|
20
31
|
}
|
|
21
|
-
else if (
|
|
32
|
+
else if (isFirstRender) {
|
|
22
33
|
currentElement.context = contextMap = new Map(currentElement.context);
|
|
34
|
+
providerElements.add(currentElement);
|
|
23
35
|
}
|
|
24
|
-
if (
|
|
36
|
+
if (isFirstRender) {
|
|
25
37
|
contextMap.set(context, { value: props.value, subs: new Set() });
|
|
26
38
|
return props.children;
|
|
27
39
|
}
|
|
@@ -40,14 +52,13 @@ export function createCreateContext(renderRuntime) {
|
|
|
40
52
|
return props.children;
|
|
41
53
|
},
|
|
42
54
|
Consumer(props) {
|
|
43
|
-
const currentElement = renderRuntime
|
|
55
|
+
const currentElement = currentFCByRuntime.get(renderRuntime);
|
|
44
56
|
const contextMap = currentElement.context;
|
|
45
|
-
const store = currentElement.store;
|
|
46
57
|
const entry = contextMap?.get(context);
|
|
47
58
|
if (!entry) {
|
|
48
59
|
return props.children(defaultValue);
|
|
49
60
|
}
|
|
50
|
-
entry.subs.add(
|
|
61
|
+
entry.subs.add(currentElement);
|
|
51
62
|
return props.children(entry.value);
|
|
52
63
|
},
|
|
53
64
|
};
|
|
@@ -56,14 +67,13 @@ export function createCreateContext(renderRuntime) {
|
|
|
56
67
|
}
|
|
57
68
|
export function createUseContext(renderRuntime) {
|
|
58
69
|
return context => {
|
|
59
|
-
const currentElement = renderRuntime
|
|
70
|
+
const currentElement = currentFCByRuntime.get(renderRuntime);
|
|
60
71
|
const contextMap = currentElement.context;
|
|
61
|
-
const store = currentElement.store;
|
|
62
72
|
const entry = contextMap?.get(context);
|
|
63
73
|
if (!entry) {
|
|
64
74
|
return context.defaultValue;
|
|
65
75
|
}
|
|
66
|
-
entry.subs.add(
|
|
76
|
+
entry.subs.add(currentElement);
|
|
67
77
|
return entry.value;
|
|
68
78
|
};
|
|
69
79
|
}
|