@lynx-js/react 0.109.1 → 0.110.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.
- package/CHANGELOG.md +39 -0
- package/package.json +2 -2
- package/refresh/.turbo/turbo-build.log +1 -1
- package/refresh/package.json +1 -1
- package/runtime/lib/backgroundSnapshot.d.ts +2 -1
- package/runtime/lib/backgroundSnapshot.js +65 -42
- package/runtime/lib/backgroundSnapshot.js.map +1 -1
- package/runtime/lib/hooks/react.js +3 -3
- package/runtime/lib/hooks/react.js.map +1 -1
- package/runtime/lib/lifecycle/destroy.js +1 -0
- package/runtime/lib/lifecycle/destroy.js.map +1 -1
- package/runtime/lib/lifecycle/event/delayEvents.js +3 -0
- package/runtime/lib/lifecycle/event/delayEvents.js.map +1 -1
- package/runtime/lib/lifecycle/event/delayLifecycleEvents.d.ts +3 -2
- package/runtime/lib/lifecycle/event/delayLifecycleEvents.js +1 -12
- package/runtime/lib/lifecycle/event/delayLifecycleEvents.js.map +1 -1
- package/runtime/lib/lifecycle/event/jsReady.d.ts +1 -1
- package/runtime/lib/lifecycle/event/jsReady.js +3 -2
- package/runtime/lib/lifecycle/event/jsReady.js.map +1 -1
- package/runtime/lib/lifecycle/patch/commit.d.ts +0 -2
- package/runtime/lib/lifecycle/patch/commit.js +8 -36
- package/runtime/lib/lifecycle/patch/commit.js.map +1 -1
- package/runtime/lib/lifecycle/patch/error.d.ts +8 -0
- package/runtime/lib/lifecycle/patch/error.js +47 -0
- package/runtime/lib/lifecycle/patch/error.js.map +1 -0
- package/runtime/lib/lifecycle/patch/isMainThreadHydrationFinished.js +3 -0
- package/runtime/lib/lifecycle/patch/isMainThreadHydrationFinished.js.map +1 -1
- package/runtime/lib/lifecycle/patch/snapshotPatch.d.ts +2 -2
- package/runtime/lib/lifecycle/patch/snapshotPatch.js.map +1 -1
- package/runtime/lib/lifecycle/patch/snapshotPatchApply.js +18 -11
- package/runtime/lib/lifecycle/patch/snapshotPatchApply.js.map +1 -1
- package/runtime/lib/lifecycle/patch/updateMainThread.d.ts +0 -1
- package/runtime/lib/lifecycle/patch/updateMainThread.js +6 -13
- package/runtime/lib/lifecycle/patch/updateMainThread.js.map +1 -1
- package/runtime/lib/lifecycle/ref/delay.d.ts +31 -0
- package/runtime/lib/lifecycle/ref/delay.js +80 -0
- package/runtime/lib/lifecycle/ref/delay.js.map +1 -0
- package/runtime/lib/lifecycle/reload.d.ts +1 -1
- package/runtime/lib/lifecycle/reload.js +7 -4
- package/runtime/lib/lifecycle/reload.js.map +1 -1
- package/runtime/lib/lifecycle/render.js +3 -2
- package/runtime/lib/lifecycle/render.js.map +1 -1
- package/runtime/lib/lifecycleConstant.d.ts +10 -7
- package/runtime/lib/lifecycleConstant.js +8 -8
- package/runtime/lib/lifecycleConstant.js.map +1 -1
- package/runtime/lib/list.d.ts +1 -1
- package/runtime/lib/list.js +9 -7
- package/runtime/lib/list.js.map +1 -1
- package/runtime/lib/lynx/calledByNative.js +8 -5
- package/runtime/lib/lynx/calledByNative.js.map +1 -1
- package/runtime/lib/lynx/component.js +7 -0
- package/runtime/lib/lynx/component.js.map +1 -1
- package/runtime/lib/lynx/dynamic-js.d.ts +5 -1
- package/runtime/lib/lynx/dynamic-js.js +1 -0
- package/runtime/lib/lynx/dynamic-js.js.map +1 -1
- package/runtime/lib/lynx/env.d.ts +1 -1
- package/runtime/lib/lynx/env.js +13 -13
- package/runtime/lib/lynx/env.js.map +1 -1
- package/runtime/lib/lynx/lazy-bundle.js +7 -5
- package/runtime/lib/lynx/lazy-bundle.js.map +1 -1
- package/runtime/lib/lynx/performance.js +1 -1
- package/runtime/lib/lynx/performance.js.map +1 -1
- package/runtime/lib/lynx/runWithForce.js +3 -0
- package/runtime/lib/lynx/runWithForce.js.map +1 -1
- package/runtime/lib/lynx/tt.js +12 -33
- package/runtime/lib/lynx/tt.js.map +1 -1
- package/runtime/lib/lynx-api.d.ts +1 -1
- package/runtime/lib/lynx.js +5 -6
- package/runtime/lib/lynx.js.map +1 -1
- package/runtime/lib/snapshot/ref.d.ts +14 -9
- package/runtime/lib/snapshot/ref.js +64 -73
- package/runtime/lib/snapshot/ref.js.map +1 -1
- package/runtime/lib/snapshot/spread.js +9 -8
- package/runtime/lib/snapshot/spread.js.map +1 -1
- package/runtime/lib/snapshot/workletRef.d.ts +3 -3
- package/runtime/lib/snapshot/workletRef.js +27 -8
- package/runtime/lib/snapshot/workletRef.js.map +1 -1
- package/runtime/lib/snapshot.d.ts +4 -4
- package/runtime/lib/snapshot.js +28 -13
- package/runtime/lib/snapshot.js.map +1 -1
- package/runtime/lib/snapshotInstanceHydrationMap.d.ts +9 -0
- package/runtime/lib/snapshotInstanceHydrationMap.js +16 -0
- package/runtime/lib/snapshotInstanceHydrationMap.js.map +1 -0
- package/runtime/lib/worklet/workletRef.js +1 -2
- package/runtime/lib/worklet/workletRef.js.map +1 -1
- package/runtime/src/backgroundSnapshot.ts +74 -47
- package/runtime/src/hooks/react.ts +3 -3
- package/runtime/src/lifecycle/destroy.ts +1 -0
- package/runtime/src/lifecycle/event/delayEvents.ts +3 -0
- package/runtime/src/lifecycle/event/delayLifecycleEvents.ts +7 -13
- package/runtime/src/lifecycle/event/jsReady.ts +4 -3
- package/runtime/src/lifecycle/patch/commit.ts +10 -41
- package/runtime/src/lifecycle/patch/error.ts +61 -0
- package/runtime/src/lifecycle/patch/isMainThreadHydrationFinished.ts +3 -0
- package/runtime/src/lifecycle/patch/snapshotPatch.ts +2 -2
- package/runtime/src/lifecycle/patch/snapshotPatchApply.ts +35 -28
- package/runtime/src/lifecycle/patch/updateMainThread.ts +7 -16
- package/runtime/src/lifecycle/ref/delay.ts +99 -0
- package/runtime/src/lifecycle/reload.ts +9 -6
- package/runtime/src/lifecycle/render.ts +3 -2
- package/runtime/src/lifecycleConstant.ts +11 -7
- package/runtime/src/list.ts +9 -7
- package/runtime/src/lynx/calledByNative.ts +14 -9
- package/runtime/src/lynx/component.ts +9 -0
- package/runtime/src/lynx/dynamic-js.ts +5 -1
- package/runtime/src/lynx/env.ts +17 -17
- package/runtime/src/lynx/lazy-bundle.ts +22 -14
- package/runtime/src/lynx/performance.ts +1 -1
- package/runtime/src/lynx/runWithForce.ts +9 -5
- package/runtime/src/lynx/tt.ts +19 -37
- package/runtime/src/lynx-api.ts +1 -1
- package/runtime/src/lynx.ts +6 -6
- package/runtime/src/snapshot/ref.ts +77 -87
- package/runtime/src/snapshot/spread.ts +8 -8
- package/runtime/src/snapshot/workletRef.ts +35 -9
- package/runtime/src/snapshot.ts +39 -20
- package/runtime/src/snapshotInstanceHydrationMap.ts +17 -0
- package/runtime/src/worklet/workletRef.ts +1 -2
- package/testing-library/dist/env/vitest.js +10 -8
- package/testing-library/dist/index.js +3 -3
- package/testing-library/dist/pure.js +93 -92
- package/testing-library/dist/vitest-global-setup.js +41 -41
- package/testing-library/dist/vitest.config.js +17 -14
- package/transform/dist/wasm.cjs +1 -1
- package/worklet-runtime/dist/dev.js +1 -4
- package/worklet-runtime/dist/main.js +0 -4
- package/worklet-runtime/lib/bindings/bindings.d.ts +1 -1
- package/worklet-runtime/lib/bindings/bindings.js +1 -26
- package/worklet-runtime/lib/bindings/bindings.js.map +1 -1
- package/worklet-runtime/lib/bindings/index.d.ts +2 -1
- package/worklet-runtime/lib/bindings/index.js +2 -1
- package/worklet-runtime/lib/bindings/index.js.map +1 -1
- package/worklet-runtime/lib/bindings/observers.d.ts +14 -0
- package/worklet-runtime/lib/bindings/observers.js +31 -0
- package/worklet-runtime/lib/bindings/observers.js.map +1 -0
- package/worklet-runtime/lib/hydrate.js +0 -5
- package/worklet-runtime/lib/hydrate.js.map +1 -1
- package/runtime/lib/lifecycle/delayUnmount.d.ts +0 -8
- package/runtime/lib/lifecycle/delayUnmount.js +0 -65
- package/runtime/lib/lifecycle/delayUnmount.js.map +0 -1
- package/runtime/src/lifecycle/delayUnmount.ts +0 -77
- package/worklet-runtime/dist/dev.js.map +0 -8
- package/worklet-runtime/dist/main.js.map +0 -8
|
@@ -3,21 +3,18 @@
|
|
|
3
3
|
// LICENSE file in the root directory of this source tree.
|
|
4
4
|
import type { Element, Worklet, WorkletRefImpl } from '@lynx-js/react/worklet-runtime/bindings';
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import { SnapshotInstance, backgroundSnapshotInstanceManager } from '../snapshot.js';
|
|
6
|
+
import type { SnapshotInstance } from '../snapshot.js';
|
|
8
7
|
import { workletUnRef } from './workletRef.js';
|
|
8
|
+
import { RefProxy } from '../lifecycle/ref/delay.js';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
const globalRefsToSet: Map</* commitId */ number, Record<string, number>> = /* @__PURE__ */ new Map();
|
|
13
|
-
let nextRefId = 1;
|
|
10
|
+
const refsToClear: Ref[] = [];
|
|
11
|
+
const refsToApply: (Ref | [snapshotInstanceId: number, expIndex: number])[] = [];
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
});
|
|
19
|
-
snapshot.__ref_set?.clear();
|
|
13
|
+
type Ref = (((ref: RefProxy) => () => void) | { current: RefProxy | null }) & {
|
|
14
|
+
_unmount?: () => void;
|
|
15
|
+
};
|
|
20
16
|
|
|
17
|
+
function unref(snapshot: SnapshotInstance, recursive: boolean): void {
|
|
21
18
|
snapshot.__worklet_ref_set?.forEach(v => {
|
|
22
19
|
if (v) {
|
|
23
20
|
workletUnRef(v as Worklet | WorkletRefImpl<Element>);
|
|
@@ -32,91 +29,65 @@ function unref(snapshot: SnapshotInstance, recursive: boolean): void {
|
|
|
32
29
|
}
|
|
33
30
|
}
|
|
34
31
|
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const hasRefUnmount = typeof ref._unmount == 'function';
|
|
39
|
-
if (hasRefUnmount) {
|
|
40
|
-
// @ts-ignore TS doesn't like moving narrowing checks into variables
|
|
41
|
-
ref._unmount();
|
|
42
|
-
}
|
|
32
|
+
// This function is modified from preact source code.
|
|
33
|
+
function applyRef(ref: Ref, value: null | [snapshotInstanceId: number, expIndex: number]): void {
|
|
34
|
+
const newRef = value && new RefProxy(value);
|
|
43
35
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
} else ref.current = value;
|
|
51
|
-
}
|
|
36
|
+
try {
|
|
37
|
+
if (typeof ref == 'function') {
|
|
38
|
+
const hasRefUnmount = typeof ref._unmount == 'function';
|
|
39
|
+
if (hasRefUnmount) {
|
|
40
|
+
ref._unmount!();
|
|
41
|
+
}
|
|
52
42
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
applyRef(ref, null);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
const newRefMap = globalRefsToSet.get(commitId);
|
|
62
|
-
if (newRefMap) {
|
|
63
|
-
globalRefsToSet.delete(commitId);
|
|
64
|
-
for (const sign in newRefMap) {
|
|
65
|
-
const ref = backgroundSnapshotInstanceManager.getValueBySign(sign);
|
|
66
|
-
if (ref) {
|
|
67
|
-
// TODO: ref: support __REF_FIRE_IMMEDIATELY__
|
|
68
|
-
const v = newRefMap[sign] && lynx.createSelectorQuery().selectUniqueID(newRefMap[sign]);
|
|
69
|
-
applyRef(ref, v);
|
|
43
|
+
if (!hasRefUnmount || newRef != null) {
|
|
44
|
+
// Store the cleanup function on the function
|
|
45
|
+
// instance object itself to avoid shape
|
|
46
|
+
// transitioning vnode
|
|
47
|
+
ref._unmount = ref(newRef!);
|
|
70
48
|
}
|
|
71
|
-
}
|
|
49
|
+
} else ref.current = newRef;
|
|
50
|
+
/* v8 ignore start */
|
|
51
|
+
} catch (e) {
|
|
52
|
+
lynx.reportError(e as Error);
|
|
72
53
|
}
|
|
54
|
+
/* v8 ignore stop */
|
|
73
55
|
}
|
|
74
56
|
|
|
75
57
|
function updateRef(
|
|
76
58
|
snapshot: SnapshotInstance,
|
|
77
59
|
expIndex: number,
|
|
78
|
-
oldValue:
|
|
60
|
+
oldValue: string | null,
|
|
79
61
|
elementIndex: number,
|
|
80
|
-
spreadKey: string,
|
|
81
62
|
): void {
|
|
82
|
-
const value = snapshot.__values![expIndex];
|
|
63
|
+
const value: unknown = snapshot.__values![expIndex];
|
|
83
64
|
let ref;
|
|
84
|
-
if (
|
|
85
|
-
ref = undefined;
|
|
86
|
-
} else if (typeof value === 'string') {
|
|
65
|
+
if (typeof value === 'string') {
|
|
87
66
|
ref = value;
|
|
88
67
|
} else {
|
|
89
|
-
ref =
|
|
68
|
+
ref = `react-ref-${snapshot.__id}-${expIndex}`;
|
|
90
69
|
}
|
|
91
70
|
|
|
92
71
|
snapshot.__values![expIndex] = ref;
|
|
93
|
-
if (snapshot.__elements && ref) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (oldValue !== ref) {
|
|
101
|
-
snapshot.__ref_set?.delete(oldValue);
|
|
72
|
+
if (snapshot.__elements && oldValue !== ref) {
|
|
73
|
+
if (oldValue) {
|
|
74
|
+
__SetAttribute(snapshot.__elements[elementIndex]!, oldValue, undefined);
|
|
75
|
+
}
|
|
76
|
+
if (ref) {
|
|
77
|
+
__SetAttribute(snapshot.__elements[elementIndex]!, ref, 1);
|
|
78
|
+
}
|
|
102
79
|
}
|
|
103
80
|
}
|
|
104
81
|
|
|
105
|
-
function
|
|
106
|
-
const patch = globalRefPatch;
|
|
107
|
-
globalRefPatch = {};
|
|
108
|
-
return patch;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function transformRef(ref: unknown): Function | (object & Record<'current', unknown>) | null | undefined {
|
|
82
|
+
function transformRef(ref: unknown): Ref | null | undefined {
|
|
112
83
|
if (ref === undefined || ref === null) {
|
|
113
84
|
return ref;
|
|
114
85
|
}
|
|
115
86
|
if (typeof ref === 'function' || (typeof ref === 'object' && 'current' in ref)) {
|
|
116
87
|
if ('__ref' in ref) {
|
|
117
|
-
return ref;
|
|
88
|
+
return ref as Ref;
|
|
118
89
|
}
|
|
119
|
-
return Object.defineProperty(ref, '__ref', { value:
|
|
90
|
+
return Object.defineProperty(ref, '__ref', { value: 1 }) as Ref;
|
|
120
91
|
}
|
|
121
92
|
throw new Error(
|
|
122
93
|
`Elements' "ref" property should be a function, or an object created `
|
|
@@ -124,25 +95,44 @@ function transformRef(ref: unknown): Function | (object & Record<'current', unkn
|
|
|
124
95
|
);
|
|
125
96
|
}
|
|
126
97
|
|
|
127
|
-
function
|
|
128
|
-
|
|
98
|
+
function applyQueuedRefs(): void {
|
|
99
|
+
try {
|
|
100
|
+
for (const ref of refsToClear) {
|
|
101
|
+
applyRef(ref, null);
|
|
102
|
+
}
|
|
103
|
+
for (let i = 0; i < refsToApply.length; i += 2) {
|
|
104
|
+
const ref = refsToApply[i] as Ref;
|
|
105
|
+
const value = refsToApply[i + 1] as [snapshotInstanceId: number, expIndex: number] | null;
|
|
106
|
+
applyRef(ref, value);
|
|
107
|
+
}
|
|
108
|
+
} finally {
|
|
109
|
+
clearQueuedRefs();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function queueRefAttrUpdate(
|
|
114
|
+
oldRef: Ref | null | undefined,
|
|
115
|
+
newRef: Ref | null | undefined,
|
|
116
|
+
snapshotInstanceId: number,
|
|
117
|
+
expIndex: number,
|
|
118
|
+
): void {
|
|
119
|
+
if (oldRef === newRef) {
|
|
129
120
|
return;
|
|
130
121
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
122
|
+
if (oldRef) {
|
|
123
|
+
refsToClear.push(oldRef);
|
|
124
|
+
}
|
|
125
|
+
if (newRef) {
|
|
126
|
+
refsToApply.push(newRef, [snapshotInstanceId, expIndex]);
|
|
135
127
|
}
|
|
136
|
-
oldRefs.set(sign, ref);
|
|
137
128
|
}
|
|
138
129
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
};
|
|
130
|
+
function clearQueuedRefs(): void {
|
|
131
|
+
refsToClear.length = 0;
|
|
132
|
+
refsToApply.length = 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @internal
|
|
137
|
+
*/
|
|
138
|
+
export { queueRefAttrUpdate, updateRef, unref, transformRef, applyRef, applyQueuedRefs, clearQueuedRefs, type Ref };
|
|
@@ -93,7 +93,6 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
|
|
|
93
93
|
} else if (key.startsWith('data-')) {
|
|
94
94
|
// collected below
|
|
95
95
|
} else if (key === 'ref') {
|
|
96
|
-
snapshot.__ref_set ??= new Set();
|
|
97
96
|
const fakeSnapshot = {
|
|
98
97
|
__values: {
|
|
99
98
|
get [index]() {
|
|
@@ -106,9 +105,8 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
|
|
|
106
105
|
},
|
|
107
106
|
__id: snapshot.__id,
|
|
108
107
|
__elements: snapshot.__elements,
|
|
109
|
-
__ref_set: snapshot.__ref_set,
|
|
110
108
|
} as SnapshotInstance;
|
|
111
|
-
updateRef(fakeSnapshot, index, oldValue[key], elementIndex
|
|
109
|
+
updateRef(fakeSnapshot, index, oldValue[key], elementIndex);
|
|
112
110
|
} else if (key.endsWith(':ref')) {
|
|
113
111
|
snapshot.__worklet_ref_set ??= new Set();
|
|
114
112
|
const fakeSnapshot = {
|
|
@@ -189,7 +187,6 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
|
|
|
189
187
|
} else if (key.startsWith('data-')) {
|
|
190
188
|
// collected below
|
|
191
189
|
} else if (key === 'ref') {
|
|
192
|
-
snapshot.__ref_set ??= new Set();
|
|
193
190
|
const fakeSnapshot = {
|
|
194
191
|
__values: {
|
|
195
192
|
get [index]() {
|
|
@@ -202,9 +199,8 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
|
|
|
202
199
|
},
|
|
203
200
|
__id: snapshot.__id,
|
|
204
201
|
__elements: snapshot.__elements,
|
|
205
|
-
__ref_set: snapshot.__ref_set,
|
|
206
202
|
} as SnapshotInstance;
|
|
207
|
-
updateRef(fakeSnapshot, index, oldValue[key], elementIndex
|
|
203
|
+
updateRef(fakeSnapshot, index, oldValue[key], elementIndex);
|
|
208
204
|
} else if (key.endsWith(':ref')) {
|
|
209
205
|
snapshot.__worklet_ref_set ??= new Set();
|
|
210
206
|
const fakeSnapshot = {
|
|
@@ -284,8 +280,12 @@ function transformSpread(
|
|
|
284
280
|
value ??= '';
|
|
285
281
|
result['className'] = value;
|
|
286
282
|
} else if (key === 'ref') {
|
|
287
|
-
|
|
288
|
-
|
|
283
|
+
if (__LEPUS__) {
|
|
284
|
+
result[key] = value ? 1 : undefined;
|
|
285
|
+
} else {
|
|
286
|
+
// @ts-ignore
|
|
287
|
+
result[key] = transformRef(value)?.__ref;
|
|
288
|
+
}
|
|
289
289
|
} else if (typeof value === 'function') {
|
|
290
290
|
result[key] = `${snapshot.__id}:${index}:${key}`;
|
|
291
291
|
} else {
|
|
@@ -1,12 +1,34 @@
|
|
|
1
1
|
// Copyright 2024 The Lynx Authors. All rights reserved.
|
|
2
2
|
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
3
|
// LICENSE file in the root directory of this source tree.
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
import { onWorkletCtxUpdate, runWorkletCtx, updateWorkletRef as update } from '@lynx-js/react/worklet-runtime/bindings';
|
|
5
6
|
import type { Element, Worklet, WorkletRefImpl } from '@lynx-js/react/worklet-runtime/bindings';
|
|
6
7
|
|
|
8
|
+
import { isMainThreadHydrationFinished } from '../lifecycle/patch/isMainThreadHydrationFinished.js';
|
|
7
9
|
import type { SnapshotInstance } from '../snapshot.js';
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
let mtRefQueue: (WorkletRefImpl<Element> | Worklet | Element)[] = [];
|
|
12
|
+
|
|
13
|
+
export function applyRefQueue(): void {
|
|
14
|
+
const queue = mtRefQueue;
|
|
15
|
+
mtRefQueue = [];
|
|
16
|
+
for (let i = 0; i < queue.length; i += 2) {
|
|
17
|
+
const worklet = queue[i] as Worklet | WorkletRefImpl<Element>;
|
|
18
|
+
const element = queue[i + 1] as Element;
|
|
19
|
+
if ('_wvid' in worklet) {
|
|
20
|
+
update(worklet as WorkletRefImpl<Element>, element);
|
|
21
|
+
} else if ('_wkltId' in worklet) {
|
|
22
|
+
worklet._unmount = runWorkletCtx(worklet, [{ elementRefptr: element }]) as () => void;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function addToRefQueue(worklet: Worklet | WorkletRefImpl<Element>, element: Element): void {
|
|
28
|
+
mtRefQueue.push(worklet, element);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function workletUnRef(value: Worklet | WorkletRefImpl<Element>): void {
|
|
10
32
|
if ('_wvid' in value) {
|
|
11
33
|
update(value as WorkletRefImpl<Element>, null);
|
|
12
34
|
} else if ('_wkltId' in value) {
|
|
@@ -18,7 +40,7 @@ function workletUnRef(value: Worklet | WorkletRefImpl<Element>): void {
|
|
|
18
40
|
}
|
|
19
41
|
}
|
|
20
42
|
|
|
21
|
-
function updateWorkletRef(
|
|
43
|
+
export function updateWorkletRef(
|
|
22
44
|
snapshot: SnapshotInstance,
|
|
23
45
|
expIndex: number,
|
|
24
46
|
oldValue: WorkletRefImpl<Element> | Worklet | undefined,
|
|
@@ -38,11 +60,17 @@ function updateWorkletRef(
|
|
|
38
60
|
if (value === null || value === undefined) {
|
|
39
61
|
// do nothing
|
|
40
62
|
} else if (value._wvid) {
|
|
41
|
-
|
|
63
|
+
const element = snapshot.__elements[elementIndex]! as Element;
|
|
64
|
+
addToRefQueue(value as Worklet, element);
|
|
42
65
|
} else if ((value as Worklet)._wkltId) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
66
|
+
const element = snapshot.__elements[elementIndex]! as Element;
|
|
67
|
+
onWorkletCtxUpdate(
|
|
68
|
+
value as Worklet,
|
|
69
|
+
oldValue as Worklet | undefined,
|
|
70
|
+
!isMainThreadHydrationFinished,
|
|
71
|
+
element,
|
|
72
|
+
);
|
|
73
|
+
addToRefQueue(value as Worklet, element);
|
|
46
74
|
/* v8 ignore next 3 */
|
|
47
75
|
} else if (value._type === '__LEPUS__' || (value as Worklet)._lepusWorkletHash) {
|
|
48
76
|
// for pre-0.99 compatibility
|
|
@@ -58,5 +86,3 @@ function updateWorkletRef(
|
|
|
58
86
|
// Add an arbitrary attribute to avoid this element being layout-only
|
|
59
87
|
__SetAttribute(snapshot.__elements[elementIndex]!, 'has-react-ref', true);
|
|
60
88
|
}
|
|
61
|
-
|
|
62
|
-
export { updateWorkletRef, workletUnRef };
|
package/runtime/src/snapshot.ts
CHANGED
|
@@ -39,7 +39,7 @@ export const enum DynamicPartType {
|
|
|
39
39
|
* A snapshot definition that contains all the information needed to create and update elements
|
|
40
40
|
* This is generated at compile time through static analysis of the JSX
|
|
41
41
|
*/
|
|
42
|
-
interface Snapshot {
|
|
42
|
+
export interface Snapshot {
|
|
43
43
|
create: null | ((ctx: SnapshotInstance) => FiberElement[]);
|
|
44
44
|
update: null | ((ctx: SnapshotInstance, index: number, oldValue: any) => void)[];
|
|
45
45
|
slot: [DynamicPartType, number][];
|
|
@@ -47,6 +47,7 @@ interface Snapshot {
|
|
|
47
47
|
isListHolder?: boolean;
|
|
48
48
|
cssId?: number | undefined;
|
|
49
49
|
entryName?: string | undefined;
|
|
50
|
+
refAndSpreadIndexes?: number[] | null;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
export let __page: FiberElement;
|
|
@@ -166,7 +167,7 @@ export const backgroundSnapshotInstanceManager: {
|
|
|
166
167
|
if (!res || (res.length != 2 && res.length != 3)) {
|
|
167
168
|
throw new Error('Invalid ctx format: ' + str);
|
|
168
169
|
}
|
|
169
|
-
|
|
170
|
+
const id = Number(res[0]);
|
|
170
171
|
const expIndex = Number(res[1]);
|
|
171
172
|
const ctx = this.values.get(id);
|
|
172
173
|
if (!ctx) {
|
|
@@ -190,8 +191,9 @@ export function createSnapshot(
|
|
|
190
191
|
create: Snapshot['create'] | null,
|
|
191
192
|
update: Snapshot['update'] | null,
|
|
192
193
|
slot: Snapshot['slot'],
|
|
193
|
-
cssId
|
|
194
|
-
entryName
|
|
194
|
+
cssId: number | undefined,
|
|
195
|
+
entryName: string | undefined,
|
|
196
|
+
refAndSpreadIndexes: number[] | null,
|
|
195
197
|
): string {
|
|
196
198
|
if (
|
|
197
199
|
__DEV__ && __JS__
|
|
@@ -221,7 +223,7 @@ export function createSnapshot(
|
|
|
221
223
|
|
|
222
224
|
uniqID = entryUniqID(uniqID, entryName);
|
|
223
225
|
|
|
224
|
-
const s: Snapshot = { create, update, slot, cssId, entryName };
|
|
226
|
+
const s: Snapshot = { create, update, slot, cssId, entryName, refAndSpreadIndexes };
|
|
225
227
|
snapshotManager.values.set(uniqID, s);
|
|
226
228
|
if (slot && slot[0] && slot[0][0] === DynamicPartType.ListChildren) {
|
|
227
229
|
s.isListHolder = true;
|
|
@@ -268,12 +270,15 @@ export class SnapshotInstance {
|
|
|
268
270
|
__element_root?: FiberElement | undefined;
|
|
269
271
|
__values?: any[] | undefined;
|
|
270
272
|
__current_slot_index = 0;
|
|
271
|
-
__ref_set?: Set<string>;
|
|
272
273
|
__worklet_ref_set?: Set<WorkletRefImpl<any> | Worklet>;
|
|
273
274
|
__listItemPlatformInfo?: any;
|
|
274
275
|
|
|
275
276
|
constructor(public type: string, id?: number) {
|
|
276
277
|
this.__snapshot_def = snapshotManager.values.get(type)!;
|
|
278
|
+
// Suspense uses 'div'
|
|
279
|
+
if (!this.__snapshot_def && type !== 'div') {
|
|
280
|
+
throw new Error('Snapshot not found: ' + type);
|
|
281
|
+
}
|
|
277
282
|
|
|
278
283
|
id ||= snapshotInstanceManager.nextId -= 1;
|
|
279
284
|
this.__id = id;
|
|
@@ -291,15 +296,15 @@ export class SnapshotInstance {
|
|
|
291
296
|
// CSS Scope is removed(We only need to call `__SetCSSId` when there is `entryName`)
|
|
292
297
|
// Or an old bundle(`__SetCSSId` is called in `create`), we skip calling `__SetCSSId`
|
|
293
298
|
if (entryName !== DEFAULT_ENTRY_NAME && entryName !== undefined) {
|
|
294
|
-
__SetCSSId(this.__elements
|
|
299
|
+
__SetCSSId(this.__elements, DEFAULT_CSS_ID, entryName);
|
|
295
300
|
}
|
|
296
301
|
} else {
|
|
297
302
|
// cssId !== undefined
|
|
298
303
|
if (entryName !== DEFAULT_ENTRY_NAME && entryName !== undefined) {
|
|
299
304
|
// For lazy bundle, we need add `entryName` to the third params
|
|
300
|
-
__SetCSSId(this.__elements
|
|
305
|
+
__SetCSSId(this.__elements, cssId, entryName);
|
|
301
306
|
} else {
|
|
302
|
-
__SetCSSId(this.__elements
|
|
307
|
+
__SetCSSId(this.__elements, cssId);
|
|
303
308
|
}
|
|
304
309
|
}
|
|
305
310
|
|
|
@@ -388,6 +393,14 @@ export class SnapshotInstance {
|
|
|
388
393
|
return a;
|
|
389
394
|
}
|
|
390
395
|
|
|
396
|
+
tearDown(): void {
|
|
397
|
+
traverseSnapshotInstance(this, v => {
|
|
398
|
+
v.__parent = null;
|
|
399
|
+
v.__previousSibling = null;
|
|
400
|
+
v.__nextSibling = null;
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
|
|
391
404
|
// onCreate?: () => void;
|
|
392
405
|
// onAttach?: () => void;
|
|
393
406
|
// onDetach?: () => void;
|
|
@@ -539,26 +552,22 @@ export class SnapshotInstance {
|
|
|
539
552
|
}
|
|
540
553
|
|
|
541
554
|
removeChild(child: SnapshotInstance): void {
|
|
542
|
-
const r = () => {
|
|
543
|
-
this.__removeChild(child);
|
|
544
|
-
traverseSnapshotInstance(child, v => {
|
|
545
|
-
v.__parent = null;
|
|
546
|
-
snapshotInstanceManager.values.delete(v.__id);
|
|
547
|
-
});
|
|
548
|
-
};
|
|
549
|
-
|
|
550
555
|
const __snapshot_def = this.__snapshot_def;
|
|
551
556
|
if (__snapshot_def.isListHolder) {
|
|
552
557
|
(__pendingListUpdates.values[this.__id] ??= new ListUpdateInfoRecording(
|
|
553
558
|
this,
|
|
554
559
|
)).onRemoveChild(child);
|
|
555
|
-
|
|
560
|
+
|
|
561
|
+
this.__removeChild(child);
|
|
562
|
+
traverseSnapshotInstance(child, v => {
|
|
563
|
+
snapshotInstanceManager.values.delete(v.__id);
|
|
564
|
+
});
|
|
565
|
+
// mark this child as deleted
|
|
566
|
+
child.__id = 0;
|
|
556
567
|
return;
|
|
557
568
|
}
|
|
558
569
|
|
|
559
|
-
// TODO: ref: can this be done on the background thread?
|
|
560
570
|
unref(child, true);
|
|
561
|
-
r();
|
|
562
571
|
if (this.__elements) {
|
|
563
572
|
const [, elementIndex] = __snapshot_def.slot[0]!;
|
|
564
573
|
__RemoveElement(this.__elements[elementIndex]!, child.__element_root!);
|
|
@@ -567,6 +576,16 @@ export class SnapshotInstance {
|
|
|
567
576
|
if (child.__snapshot_def.isListHolder) {
|
|
568
577
|
snapshotDestroyList(child);
|
|
569
578
|
}
|
|
579
|
+
|
|
580
|
+
this.__removeChild(child);
|
|
581
|
+
traverseSnapshotInstance(child, v => {
|
|
582
|
+
v.__parent = null;
|
|
583
|
+
v.__previousSibling = null;
|
|
584
|
+
v.__nextSibling = null;
|
|
585
|
+
delete v.__elements;
|
|
586
|
+
delete v.__element_root;
|
|
587
|
+
snapshotInstanceManager.values.delete(v.__id);
|
|
588
|
+
});
|
|
570
589
|
}
|
|
571
590
|
|
|
572
591
|
setAttribute(key: string | number, value: any): void {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Copyright 2024 The Lynx Authors. All rights reserved.
|
|
2
|
+
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
|
+
// LICENSE file in the root directory of this source tree.
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A map to store hydration states between snapshot instances.
|
|
7
|
+
* K->V: main thread snapshotInstance IDs -> background snapshotInstance IDs.
|
|
8
|
+
*
|
|
9
|
+
* The map is used by the ref system to translate between snapshot instance IDs when
|
|
10
|
+
* operations need to cross the thread boundary during the commit phase.
|
|
11
|
+
*/
|
|
12
|
+
const hydrationMap: Map<number, number> = new Map();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
export { hydrationMap };
|
|
@@ -54,10 +54,9 @@ abstract class WorkletRef<T> {
|
|
|
54
54
|
throw new Error('MainThreadRef: value of a MainThreadRef cannot be accessed in the background thread.');
|
|
55
55
|
}
|
|
56
56
|
if (__LEPUS__ && __DEV__) {
|
|
57
|
-
/* v8 ignore next */
|
|
57
|
+
/* v8 ignore next 3 */
|
|
58
58
|
throw new Error('MainThreadRef: value of a MainThreadRef cannot be accessed outside of main thread script.');
|
|
59
59
|
}
|
|
60
|
-
/* v8 ignore next */
|
|
61
60
|
return undefined as T;
|
|
62
61
|
}
|
|
63
62
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { builtinEnvironments } from "vitest/environments";
|
|
2
|
+
import external_events_default from "events";
|
|
3
3
|
function util_define(object, properties) {
|
|
4
4
|
for (const name of Object.getOwnPropertyNames(properties)){
|
|
5
5
|
const propDesc = Object.getOwnPropertyDescriptor(properties, name);
|
|
@@ -149,7 +149,7 @@ const initElementTree = ()=>{
|
|
|
149
149
|
e.id = id;
|
|
150
150
|
}
|
|
151
151
|
__SetInlineStyles(e, styles) {
|
|
152
|
-
if ('string' == typeof styles) e.style
|
|
152
|
+
if ('string' == typeof styles) e.setAttributeNS(null, 'style', styles);
|
|
153
153
|
else Object.assign(e.style, styles);
|
|
154
154
|
}
|
|
155
155
|
__AddDataset(e, key, value) {
|
|
@@ -321,7 +321,7 @@ function createPolyfills() {
|
|
|
321
321
|
]);
|
|
322
322
|
}
|
|
323
323
|
};
|
|
324
|
-
const ee = new
|
|
324
|
+
const ee = new external_events_default();
|
|
325
325
|
ee.dispatchEvent = ({ type, data })=>{
|
|
326
326
|
const isMainThread = __MAIN_THREAD__;
|
|
327
327
|
lynxTestingEnv.switchToBackgroundThread();
|
|
@@ -357,7 +357,7 @@ function createPolyfills() {
|
|
|
357
357
|
function injectMainThreadGlobals(target, polyfills) {
|
|
358
358
|
var _globalThis_onInjectMainThreadGlobals, _globalThis;
|
|
359
359
|
__injectElementApi(target);
|
|
360
|
-
const { performance, JsContext, __LoadLepusChunk } = polyfills || {};
|
|
360
|
+
const { performance, CoreContext, JsContext, __LoadLepusChunk } = polyfills || {};
|
|
361
361
|
if (void 0 === target) target = globalThis;
|
|
362
362
|
target.__DEV__ = true;
|
|
363
363
|
target.__PROFILE__ = true;
|
|
@@ -372,6 +372,7 @@ function injectMainThreadGlobals(target, polyfills) {
|
|
|
372
372
|
target.globDynamicComponentEntry = '__Card__';
|
|
373
373
|
target.lynx = {
|
|
374
374
|
performance,
|
|
375
|
+
getCoreContext: ()=>CoreContext,
|
|
375
376
|
getJSContext: ()=>JsContext,
|
|
376
377
|
reportError: (e)=>{
|
|
377
378
|
throw e;
|
|
@@ -410,7 +411,7 @@ class NodesRef {
|
|
|
410
411
|
}
|
|
411
412
|
function injectBackgroundThreadGlobals(target, polyfills) {
|
|
412
413
|
var _globalThis_onInjectBackgroundThreadGlobals, _globalThis;
|
|
413
|
-
const { app, performance, CoreContext, __LoadLepusChunk } = polyfills || {};
|
|
414
|
+
const { app, performance, CoreContext, JsContext, __LoadLepusChunk } = polyfills || {};
|
|
414
415
|
if (void 0 === target) target = globalThis;
|
|
415
416
|
target.__DEV__ = true;
|
|
416
417
|
target.__PROFILE__ = true;
|
|
@@ -427,7 +428,7 @@ function injectBackgroundThreadGlobals(target, polyfills) {
|
|
|
427
428
|
updateData: {}
|
|
428
429
|
}
|
|
429
430
|
};
|
|
430
|
-
const globalEventEmitter = new
|
|
431
|
+
const globalEventEmitter = new external_events_default();
|
|
431
432
|
globalEventEmitter.trigger = globalEventEmitter.emit;
|
|
432
433
|
globalEventEmitter.toggle = globalEventEmitter.emit;
|
|
433
434
|
target.lynx = {
|
|
@@ -442,6 +443,7 @@ function injectBackgroundThreadGlobals(target, polyfills) {
|
|
|
442
443
|
}
|
|
443
444
|
}),
|
|
444
445
|
getCoreContext: ()=>CoreContext,
|
|
446
|
+
getJSContext: ()=>JsContext,
|
|
445
447
|
getJSModule: (moduleName)=>{
|
|
446
448
|
if ('GlobalEventEmitter' === moduleName) return globalEventEmitter;
|
|
447
449
|
throw new Error(`getJSModule(${moduleName}) not implemented`);
|
|
@@ -531,7 +533,7 @@ const env = {
|
|
|
531
533
|
transformMode: 'web',
|
|
532
534
|
async setup (global1) {
|
|
533
535
|
const fakeGlobal = {};
|
|
534
|
-
await
|
|
536
|
+
await builtinEnvironments.jsdom.setup(fakeGlobal, {});
|
|
535
537
|
global1.jsdom = fakeGlobal.jsdom;
|
|
536
538
|
const lynxTestingEnv1 = new LynxTestingEnv();
|
|
537
539
|
global1.lynxTestingEnv = lynxTestingEnv1;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { cleanup } from "./pure.js";
|
|
2
2
|
export * from "./pure.js";
|
|
3
3
|
if ('undefined' == typeof process || 'true' !== process.env.PTL_SKIP_AUTO_CLEANUP) {
|
|
4
4
|
if ('function' == typeof afterEach) afterEach(()=>{
|
|
5
|
-
|
|
5
|
+
cleanup();
|
|
6
6
|
lynxTestingEnv.reset();
|
|
7
7
|
});
|
|
8
8
|
else if ('function' == typeof teardown) teardown(()=>{
|
|
9
|
-
|
|
9
|
+
cleanup();
|
|
10
10
|
lynxTestingEnv.reset();
|
|
11
11
|
});
|
|
12
12
|
}
|