@lynx-js/react 0.110.0 → 0.111.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 +50 -0
- package/components/lib/DeferredListItem.d.ts +7 -0
- package/components/lib/DeferredListItem.jsx +40 -0
- package/components/lib/DeferredListItem.jsx.map +1 -0
- package/components/lib/Page.js.map +1 -1
- package/components/lib/index.d.ts +1 -0
- package/components/lib/index.js +1 -0
- package/components/lib/index.js.map +1 -1
- package/components/src/DeferredListItem.tsx +56 -0
- package/components/src/Page.ts +1 -1
- package/components/src/index.ts +1 -0
- package/package.json +1 -1
- package/refresh/.turbo/turbo-build.log +1 -1
- package/runtime/lazy/react-lepus.js +1 -0
- package/runtime/lazy/react.js +1 -0
- package/runtime/lepus/index.d.ts +1 -1
- package/runtime/lepus/index.js +44 -0
- package/runtime/lib/backgroundSnapshot.d.ts +2 -1
- package/runtime/lib/backgroundSnapshot.js +64 -41
- package/runtime/lib/backgroundSnapshot.js.map +1 -1
- package/runtime/lib/compat/initData.d.ts +7 -5
- package/runtime/lib/compat/initData.js +11 -2
- package/runtime/lib/compat/initData.js.map +1 -1
- package/runtime/lib/compat/lynxComponent.js +10 -12
- package/runtime/lib/compat/lynxComponent.js.map +1 -1
- package/runtime/lib/debug/profile.js +1 -0
- package/runtime/lib/debug/profile.js.map +1 -1
- package/runtime/lib/gesture/processGestureBagkround.d.ts +1 -1
- package/runtime/lib/gesture/processGestureBagkround.js +4 -1
- package/runtime/lib/gesture/processGestureBagkround.js.map +1 -1
- package/runtime/lib/gesture/types.js.map +1 -1
- package/runtime/lib/hooks/useLynxGlobalEventListener.d.ts +1 -1
- package/runtime/lib/hydrate.d.ts +1 -1
- package/runtime/lib/hydrate.js +5 -4
- package/runtime/lib/hydrate.js.map +1 -1
- package/runtime/lib/index.d.ts +2 -2
- package/runtime/lib/index.js +2 -2
- package/runtime/lib/index.js.map +1 -1
- package/runtime/lib/internal.d.ts +3 -2
- package/runtime/lib/internal.js +3 -2
- package/runtime/lib/internal.js.map +1 -1
- package/runtime/lib/legacy-react-runtime/index.js +1 -1
- package/runtime/lib/legacy-react-runtime/index.js.map +1 -1
- package/runtime/lib/lifecycle/patch/commit.js +5 -5
- package/runtime/lib/lifecycle/patch/commit.js.map +1 -1
- package/runtime/lib/lifecycle/patch/snapshotPatch.d.ts +9 -9
- package/runtime/lib/lifecycle/patch/snapshotPatch.js +9 -10
- package/runtime/lib/lifecycle/patch/snapshotPatch.js.map +1 -1
- package/runtime/lib/lifecycle/patch/snapshotPatchApply.js.map +1 -1
- package/runtime/lib/lifecycle/patch/updateMainThread.js +11 -12
- package/runtime/lib/lifecycle/patch/updateMainThread.js.map +1 -1
- package/runtime/lib/lifecycle/reload.js +1 -1
- package/runtime/lib/lifecycle/reload.js.map +1 -1
- package/runtime/lib/lifecycleConstant.d.ts +2 -1
- package/runtime/lib/lifecycleConstant.js +1 -0
- package/runtime/lib/lifecycleConstant.js.map +1 -1
- package/runtime/lib/list.d.ts +2 -46
- package/runtime/lib/list.js +124 -211
- package/runtime/lib/list.js.map +1 -1
- package/runtime/lib/listUpdateInfo.d.ts +38 -0
- package/runtime/lib/listUpdateInfo.js +152 -0
- package/runtime/lib/listUpdateInfo.js.map +1 -0
- package/runtime/lib/lynx/calledByNative.js +8 -11
- package/runtime/lib/lynx/calledByNative.js.map +1 -1
- package/runtime/lib/lynx/component.js +11 -14
- package/runtime/lib/lynx/component.js.map +1 -1
- package/runtime/lib/lynx/env.js +1 -2
- package/runtime/lib/lynx/env.js.map +1 -1
- package/runtime/lib/lynx/lazy-bundle.js +48 -21
- package/runtime/lib/lynx/lazy-bundle.js.map +1 -1
- package/runtime/lib/lynx/performance.d.ts +3 -19
- package/runtime/lib/lynx/performance.js +25 -26
- package/runtime/lib/lynx/performance.js.map +1 -1
- package/runtime/lib/lynx/tt.js +10 -5
- package/runtime/lib/lynx/tt.js.map +1 -1
- package/runtime/lib/lynx-api.d.ts +78 -1
- package/runtime/lib/lynx-api.js +3 -0
- package/runtime/lib/lynx-api.js.map +1 -1
- package/runtime/lib/lynx.js +1 -0
- package/runtime/lib/lynx.js.map +1 -1
- package/runtime/lib/opcodes.js +2 -1
- package/runtime/lib/opcodes.js.map +1 -1
- package/runtime/lib/pendingListUpdates.d.ts +6 -0
- package/runtime/lib/pendingListUpdates.js +16 -0
- package/runtime/lib/pendingListUpdates.js.map +1 -0
- package/runtime/lib/renderToOpcodes/index.js +7 -7
- package/runtime/lib/renderToOpcodes/index.js.map +1 -1
- package/runtime/lib/snapshot/dynamicPartType.d.ts +12 -0
- package/runtime/lib/snapshot/dynamicPartType.js +17 -0
- package/runtime/lib/snapshot/dynamicPartType.js.map +1 -0
- package/runtime/lib/snapshot/gesture.js +3 -0
- package/runtime/lib/snapshot/gesture.js.map +1 -1
- package/runtime/lib/snapshot/list.d.ts +3 -0
- package/runtime/lib/snapshot/list.js +23 -0
- package/runtime/lib/snapshot/list.js.map +1 -0
- package/runtime/lib/snapshot/platformInfo.d.ts +10 -0
- package/runtime/lib/snapshot/platformInfo.js +6 -3
- package/runtime/lib/snapshot/platformInfo.js.map +1 -1
- package/runtime/lib/snapshot/ref.d.ts +3 -0
- package/runtime/lib/snapshot/ref.js.map +1 -1
- package/runtime/lib/snapshot/spread.d.ts +2 -2
- package/runtime/lib/snapshot/spread.js +4 -5
- package/runtime/lib/snapshot/spread.js.map +1 -1
- package/runtime/lib/snapshot/workletEvent.js +1 -1
- package/runtime/lib/snapshot/workletEvent.js.map +1 -1
- package/runtime/lib/snapshot/workletRef.d.ts +1 -1
- package/runtime/lib/snapshot/workletRef.js.map +1 -1
- package/runtime/lib/snapshot.d.ts +7 -14
- package/runtime/lib/snapshot.js +36 -31
- package/runtime/lib/snapshot.js.map +1 -1
- package/runtime/lib/snapshotInstanceHydrationMap.js.map +1 -1
- package/runtime/lib/utils.d.ts +1 -0
- package/runtime/lib/utils.js +7 -1
- package/runtime/lib/utils.js.map +1 -1
- package/runtime/src/backgroundSnapshot.ts +78 -63
- package/runtime/src/compat/initData.ts +20 -9
- package/runtime/src/compat/lynxComponent.ts +12 -13
- package/runtime/src/debug/profile.ts +1 -0
- package/runtime/src/gesture/processGestureBagkround.ts +5 -1
- package/runtime/src/gesture/types.ts +3 -0
- package/runtime/src/hooks/useLynxGlobalEventListener.ts +1 -1
- package/runtime/src/hydrate.ts +6 -4
- package/runtime/src/index.ts +2 -0
- package/runtime/src/internal.ts +3 -2
- package/runtime/src/legacy-react-runtime/index.ts +1 -1
- package/runtime/src/lifecycle/patch/commit.ts +5 -11
- package/runtime/src/lifecycle/patch/snapshotPatch.ts +9 -9
- package/runtime/src/lifecycle/patch/snapshotPatchApply.ts +1 -1
- package/runtime/src/lifecycle/patch/updateMainThread.ts +11 -12
- package/runtime/src/lifecycle/reload.ts +1 -1
- package/runtime/src/lifecycleConstant.ts +1 -0
- package/runtime/src/list.ts +143 -278
- package/runtime/src/listUpdateInfo.ts +221 -0
- package/runtime/src/lynx/calledByNative.ts +8 -10
- package/runtime/src/lynx/component.ts +17 -29
- package/runtime/src/lynx/env.ts +1 -2
- package/runtime/src/lynx/lazy-bundle.ts +55 -20
- package/runtime/src/lynx/performance.ts +26 -27
- package/runtime/src/lynx/tt.ts +10 -11
- package/runtime/src/lynx-api.ts +81 -2
- package/runtime/src/lynx.ts +1 -0
- package/runtime/src/opcodes.ts +2 -1
- package/runtime/src/pendingListUpdates.ts +18 -0
- package/runtime/src/renderToOpcodes/index.ts +7 -7
- package/runtime/src/snapshot/dynamicPartType.ts +16 -0
- package/runtime/src/snapshot/gesture.ts +3 -0
- package/runtime/src/snapshot/list.ts +36 -0
- package/runtime/src/snapshot/platformInfo.ts +19 -5
- package/runtime/src/snapshot/ref.ts +1 -0
- package/runtime/src/snapshot/spread.ts +42 -17
- package/runtime/src/snapshot/workletEvent.ts +1 -1
- package/runtime/src/snapshot/workletRef.ts +1 -1
- package/runtime/src/snapshot.ts +41 -34
- package/runtime/src/snapshotInstanceHydrationMap.ts +1 -1
- package/runtime/src/utils.ts +12 -3
- package/testing-library/dist/env/vitest.js +3 -3
- package/testing-library/dist/index.d.ts +4 -1
- package/testing-library/dist/pure.js +1 -1
- package/testing-library/dist/vitest.config.js +45 -8
- package/testing-library/types/entry.d.ts +3 -2
- package/transform/cjs/main.cjs +4 -0
- package/transform/dist/wasm.cjs +1 -1
- package/types/react.d.ts +21 -1
- package/types/react.docs.d.ts +1 -1
package/runtime/src/list.ts
CHANGED
|
@@ -1,240 +1,15 @@
|
|
|
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
|
-
import {
|
|
4
|
+
import { LifecycleConstant } from './lifecycleConstant.js';
|
|
5
5
|
import { applyRefQueue } from './snapshot/workletRef.js';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
export interface ListUpdateInfo {
|
|
9
|
-
flush(): void;
|
|
10
|
-
onInsertBefore(
|
|
11
|
-
newNode: SnapshotInstance,
|
|
12
|
-
existingNode?: SnapshotInstance,
|
|
13
|
-
): void;
|
|
14
|
-
onRemoveChild(child: SnapshotInstance): void;
|
|
15
|
-
onSetAttribute(child: SnapshotInstance, attr: any, oldAttr: any): void;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface InsertAction {
|
|
19
|
-
position: number;
|
|
20
|
-
type: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface UpdateAction {
|
|
24
|
-
from: number;
|
|
25
|
-
to: number;
|
|
26
|
-
type: string;
|
|
27
|
-
flush: boolean;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface ListOperations {
|
|
31
|
-
insertAction: InsertAction[];
|
|
32
|
-
removeAction: number[];
|
|
33
|
-
updateAction: UpdateAction[];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// class ListUpdateInfoDiffing implements ListUpdateInfo {
|
|
37
|
-
// private oldChildNodes: SnapshotInstance[];
|
|
38
|
-
// constructor(private list: SnapshotInstance) {
|
|
39
|
-
// this.oldChildNodes = list.childNodes;
|
|
40
|
-
// }
|
|
41
|
-
// flush(): void {
|
|
42
|
-
// Object.defineProperty(SnapshotInstance.prototype, "key", {
|
|
43
|
-
// get: function () {
|
|
44
|
-
// return this.values[0]["item-key"];
|
|
45
|
-
// },
|
|
46
|
-
// });
|
|
47
|
-
|
|
48
|
-
// }
|
|
49
|
-
// onInsertBefore(newNode: SnapshotInstance, existingNode?: SnapshotInstance | undefined): void {}
|
|
50
|
-
// onRemoveChild(child: SnapshotInstance): void {}
|
|
51
|
-
// onSetAttribute(child: SnapshotInstance, attr: any): void {
|
|
52
|
-
// throw new Error("Method not implemented.");
|
|
53
|
-
// }
|
|
54
|
-
// }
|
|
55
|
-
|
|
56
|
-
export class ListUpdateInfoRecording implements ListUpdateInfo {
|
|
57
|
-
constructor(private list: SnapshotInstance) {
|
|
58
|
-
this.oldChildNodes = list.childNodes;
|
|
59
|
-
// this.oldChildNodesSet = new Set(this.oldChildNodes);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// private __commitAndReset() {
|
|
63
|
-
// (this.__pendingAttributes ??= []).push(this.__toAttribute());
|
|
64
|
-
// this.oldChildNodes = this.list.childNodes;
|
|
65
|
-
// this.oldChildNodesSet = new Set(this.oldChildNodes);
|
|
66
|
-
// this.removeChild1.clear();
|
|
67
|
-
// this.removeChild2.clear();
|
|
68
|
-
// this.insertBefore.clear();
|
|
69
|
-
// this.appendChild.length = 0;
|
|
70
|
-
// this.platformInfoUpdate.clear();
|
|
71
|
-
// }
|
|
72
|
-
|
|
73
|
-
flush(): void {
|
|
74
|
-
const elementIndex = this.list.__snapshot_def.slot[0]![1];
|
|
75
|
-
const listElement = this.list.__elements![elementIndex]!;
|
|
76
|
-
// this.__pendingAttributes?.forEach(pendingAttribute => {
|
|
77
|
-
// __SetAttribute(listElement, "update-list-info", pendingAttribute);
|
|
78
|
-
// __FlushElementTree(listElement);
|
|
79
|
-
// });
|
|
80
|
-
__SetAttribute(listElement, 'update-list-info', this.__toAttribute());
|
|
81
|
-
const [componentAtIndex, componentAtIndexes] = componentAtIndexFactory(this.list.childNodes);
|
|
82
|
-
__UpdateListCallbacks(
|
|
83
|
-
listElement,
|
|
84
|
-
componentAtIndex,
|
|
85
|
-
enqueueComponentFactory(),
|
|
86
|
-
componentAtIndexes,
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
private oldChildNodes: SnapshotInstance[];
|
|
91
|
-
// private oldChildNodesSet: Set<SnapshotInstance>;
|
|
92
|
-
private removeChild = new Set<SnapshotInstance>();
|
|
93
|
-
private insertBefore = new Map<SnapshotInstance, SnapshotInstance[]>(); // insert V before K
|
|
94
|
-
private appendChild = [] as SnapshotInstance[];
|
|
95
|
-
private platformInfoUpdate = new Map<SnapshotInstance, any>();
|
|
96
|
-
|
|
97
|
-
onInsertBefore(newNode: SnapshotInstance, existingNode?: SnapshotInstance): void {
|
|
98
|
-
// @ts-ignore
|
|
99
|
-
if (newNode.__parent) {
|
|
100
|
-
// if (!this.oldChildNodesSet.has(newNode)) {
|
|
101
|
-
// this.__commitAndReset();
|
|
102
|
-
// }
|
|
103
|
-
this.removeChild.add(newNode);
|
|
104
|
-
}
|
|
105
|
-
if (existingNode) {
|
|
106
|
-
// if (!this.oldChildNodesSet.has(existingNode)) {
|
|
107
|
-
// this.__commitAndReset();
|
|
108
|
-
// }
|
|
109
|
-
const newChildren = this.insertBefore.get(existingNode) ?? [];
|
|
110
|
-
newChildren.push(newNode);
|
|
111
|
-
this.insertBefore.set(existingNode, newChildren);
|
|
112
|
-
} else {
|
|
113
|
-
this.appendChild.push(newNode);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
onRemoveChild(child: SnapshotInstance): void {
|
|
118
|
-
// if (!this.oldChildNodesSet.has(child)) {
|
|
119
|
-
// this.__commitAndReset();
|
|
120
|
-
// }
|
|
121
|
-
this.removeChild.add(child);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
onSetAttribute(child: SnapshotInstance, attr: any, _oldAttr: any): void {
|
|
125
|
-
this.platformInfoUpdate.set(child, attr);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
private __toAttribute(): ListOperations {
|
|
129
|
-
const { removeChild, insertBefore, appendChild, platformInfoUpdate } = this;
|
|
130
|
-
|
|
131
|
-
const removals: number[] = [];
|
|
132
|
-
const insertions: InsertAction[] = [];
|
|
133
|
-
const updates: UpdateAction[] = [];
|
|
134
|
-
|
|
135
|
-
let j = 0;
|
|
136
|
-
for (let i = 0; i < this.oldChildNodes.length; i++, j++) {
|
|
137
|
-
const child = this.oldChildNodes[i]!;
|
|
138
|
-
if (platformInfoUpdate.has(child)) {
|
|
139
|
-
updates.push({
|
|
140
|
-
...platformInfoUpdate.get(child),
|
|
141
|
-
from: +j,
|
|
142
|
-
to: +j,
|
|
143
|
-
// no flush
|
|
144
|
-
flush: false,
|
|
145
|
-
type: child.type,
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
if (insertBefore.has(child)) {
|
|
149
|
-
const children = insertBefore.get(child)!;
|
|
150
|
-
children.forEach(c => {
|
|
151
|
-
insertions.push({
|
|
152
|
-
position: j,
|
|
153
|
-
type: c.type,
|
|
154
|
-
...c.__listItemPlatformInfo,
|
|
155
|
-
});
|
|
156
|
-
j++;
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
if (removeChild.has(child)) {
|
|
160
|
-
removals.push(i);
|
|
161
|
-
removeChild.delete(child);
|
|
162
|
-
j--;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
for (let i = 0; i < appendChild.length; i++) {
|
|
166
|
-
const child = appendChild[i]!;
|
|
167
|
-
insertions.push({
|
|
168
|
-
position: j + i,
|
|
169
|
-
type: child.type,
|
|
170
|
-
...child.__listItemPlatformInfo,
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
insertions.sort((a, b) => a.position - b.position);
|
|
175
|
-
removals.sort((a, b) => a - b);
|
|
176
|
-
|
|
177
|
-
if (
|
|
178
|
-
SystemInfo.lynxSdkVersion === '2.14'
|
|
179
|
-
|| SystemInfo.lynxSdkVersion === '2.15'
|
|
180
|
-
|| SystemInfo.lynxSdkVersion === '2.16'
|
|
181
|
-
|| SystemInfo.lynxSdkVersion === '2.17'
|
|
182
|
-
|| SystemInfo.lynxSdkVersion === '2.18'
|
|
183
|
-
) {
|
|
184
|
-
const elementIndex = this.list.__snapshot_def.slot[0]![1];
|
|
185
|
-
const listElement = this.list.__elements![elementIndex]!;
|
|
186
|
-
|
|
187
|
-
// `__GetAttributeByName` is available since Lynx 2.14
|
|
188
|
-
if (__GetAttributeByName(listElement, 'custom-list-name') === 'list-container') {
|
|
189
|
-
// `updateAction` must be full (not incremental) when Lynx version <= 2.18 and
|
|
190
|
-
// when `custom-list-name` is `list-container` (available when Lynx version >= 2.14) is true,
|
|
191
|
-
updates.length = 0;
|
|
192
|
-
this.list.childNodes.forEach((child, index) => {
|
|
193
|
-
updates.push({
|
|
194
|
-
...child.__listItemPlatformInfo,
|
|
195
|
-
from: index,
|
|
196
|
-
to: index,
|
|
197
|
-
// no flush
|
|
198
|
-
flush: false,
|
|
199
|
-
type: child.type,
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
return {
|
|
206
|
-
insertAction: insertions,
|
|
207
|
-
removeAction: removals,
|
|
208
|
-
updateAction: updates,
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
toJSON(): [ListOperations] {
|
|
213
|
-
// if (this.__pendingAttributes) {
|
|
214
|
-
// return [...this.__pendingAttributes, this.__toAttribute()];
|
|
215
|
-
// } else {
|
|
216
|
-
// return [this.__toAttribute()];
|
|
217
|
-
// }
|
|
218
|
-
|
|
219
|
-
return [this.__toAttribute()] as const;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
export const __pendingListUpdates = {
|
|
224
|
-
values: {} as Record<number, ListUpdateInfo>,
|
|
225
|
-
clear(): void {
|
|
226
|
-
this.values = {};
|
|
227
|
-
},
|
|
228
|
-
flush(): void {
|
|
229
|
-
Object.values(this.values).forEach(update => {
|
|
230
|
-
update.flush();
|
|
231
|
-
});
|
|
232
|
-
this.clear();
|
|
233
|
-
},
|
|
234
|
-
};
|
|
6
|
+
import type { SnapshotInstance } from './snapshot.js';
|
|
7
|
+
import { maybePromise } from './utils.js';
|
|
235
8
|
|
|
236
9
|
export const gSignMap: Record<number, Map<number, SnapshotInstance>> = {};
|
|
237
10
|
export const gRecycleMap: Record<number, Map<string, Map<number, SnapshotInstance>>> = {};
|
|
11
|
+
const gParentWeakMap: WeakMap<SnapshotInstance, unknown> = new WeakMap();
|
|
12
|
+
const resolvedPromise = /* @__PURE__ */ Promise.resolve();
|
|
238
13
|
|
|
239
14
|
export function clearListGlobal(): void {
|
|
240
15
|
for (const key in gSignMap) {
|
|
@@ -247,11 +22,29 @@ export function clearListGlobal(): void {
|
|
|
247
22
|
|
|
248
23
|
export function componentAtIndexFactory(
|
|
249
24
|
ctx: SnapshotInstance[],
|
|
25
|
+
hydrateFunction: (before: SnapshotInstance, after: SnapshotInstance) => void,
|
|
250
26
|
): [ComponentAtIndexCallback, ComponentAtIndexesCallback] {
|
|
251
|
-
|
|
27
|
+
// A hack workaround to ensure childCtx has no direct reference through `__parent` to list,
|
|
28
|
+
// to avoid memory leak.
|
|
29
|
+
// TODO(hzy): make `__parent` a WeakRef or `#__parent` in the future.
|
|
30
|
+
ctx.forEach((childCtx) => {
|
|
31
|
+
if (gParentWeakMap.has(childCtx)) {
|
|
32
|
+
// do it only once
|
|
33
|
+
} else {
|
|
34
|
+
gParentWeakMap.set(childCtx, childCtx.parentNode!);
|
|
35
|
+
Object.defineProperty(childCtx, '__parent', {
|
|
36
|
+
get: () => gParentWeakMap.get(childCtx)!,
|
|
37
|
+
set: (value: unknown) => {
|
|
38
|
+
gParentWeakMap.set(childCtx, value);
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const componentAtChildCtx = (
|
|
252
45
|
list: FiberElement,
|
|
253
46
|
listID: number,
|
|
254
|
-
|
|
47
|
+
childCtx: SnapshotInstance,
|
|
255
48
|
operationID: number,
|
|
256
49
|
enableReuseNotification: boolean,
|
|
257
50
|
enableBatchRender: boolean = false,
|
|
@@ -263,12 +56,54 @@ export function componentAtIndexFactory(
|
|
|
263
56
|
throw new Error('componentAtIndex called on removed list');
|
|
264
57
|
}
|
|
265
58
|
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
59
|
+
const platformInfo = childCtx.__listItemPlatformInfo ?? {};
|
|
60
|
+
|
|
61
|
+
// The lifecycle of this `__extraProps.isReady`:
|
|
62
|
+
// 0 -> Promise<number> -> 1
|
|
63
|
+
// 0: The initial state, the list-item is not ready yet, we will send a event to background
|
|
64
|
+
// when `componentAtIndex` is called on it
|
|
65
|
+
// Promise<number>: A promise that will be resolved when the list-item is ready
|
|
66
|
+
// 1: The list-item is ready, we can use it to render the list
|
|
67
|
+
if (childCtx.__extraProps?.['isReady'] === 0) {
|
|
68
|
+
if (
|
|
69
|
+
typeof __GetAttributeByName === 'function'
|
|
70
|
+
&& __GetAttributeByName(list, 'custom-list-name') === 'list-container'
|
|
71
|
+
) {
|
|
72
|
+
// we are in supported env
|
|
73
|
+
// do not throw
|
|
74
|
+
} else {
|
|
75
|
+
throw new Error(
|
|
76
|
+
'Unsupported: `<list-item/>` with `defer={true}` must be used with `<list custom-list-name="list-container"/>`',
|
|
77
|
+
);
|
|
78
|
+
}
|
|
270
79
|
|
|
271
|
-
|
|
80
|
+
__OnLifecycleEvent([LifecycleConstant.publishEvent, {
|
|
81
|
+
handlerName: `${childCtx.__id}:__extraProps:onComponentAtIndex`,
|
|
82
|
+
data: {},
|
|
83
|
+
}]);
|
|
84
|
+
|
|
85
|
+
let p: Promise<number>;
|
|
86
|
+
return (p = new Promise<number>((resolve) => {
|
|
87
|
+
Object.defineProperty(childCtx.__extraProps, 'isReady', {
|
|
88
|
+
set(isReady) {
|
|
89
|
+
if (isReady === 1) {
|
|
90
|
+
delete childCtx.__extraProps!['isReady'];
|
|
91
|
+
childCtx.__extraProps!['isReady'] = 1;
|
|
92
|
+
|
|
93
|
+
void resolvedPromise.then(() => {
|
|
94
|
+
// the cellIndex may be changed already, but the `childCtx` is the same
|
|
95
|
+
resolve(componentAtChildCtx(list, listID, childCtx, operationID, enableReuseNotification));
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
get() {
|
|
100
|
+
return p;
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}));
|
|
104
|
+
} else if (maybePromise<number>(childCtx.__extraProps?.['isReady'])) {
|
|
105
|
+
throw new Error('componentAtIndex was called on a pending deferred list item');
|
|
106
|
+
}
|
|
272
107
|
|
|
273
108
|
const uniqID = childCtx.type + (platformInfo['reuse-identifier'] ?? '');
|
|
274
109
|
const recycleSignMap = recycleMap.get(uniqID);
|
|
@@ -308,10 +143,15 @@ export function componentAtIndexFactory(
|
|
|
308
143
|
const [first] = recycleSignMap;
|
|
309
144
|
const [sign, oldCtx] = first!;
|
|
310
145
|
recycleSignMap.delete(sign);
|
|
311
|
-
|
|
146
|
+
hydrateFunction(oldCtx, childCtx);
|
|
312
147
|
oldCtx.unRenderElements();
|
|
313
148
|
if (!oldCtx.__id) {
|
|
314
149
|
oldCtx.tearDown();
|
|
150
|
+
} else if (oldCtx.__extraProps?.['isReady'] === 1) {
|
|
151
|
+
__OnLifecycleEvent([LifecycleConstant.publishEvent, {
|
|
152
|
+
handlerName: `${oldCtx.__id}:__extraProps:onRecycleComponent`,
|
|
153
|
+
data: {},
|
|
154
|
+
}]);
|
|
315
155
|
}
|
|
316
156
|
const root = childCtx.__element_root!;
|
|
317
157
|
applyRefQueue();
|
|
@@ -325,7 +165,7 @@ export function componentAtIndexFactory(
|
|
|
325
165
|
if (enableReuseNotification) {
|
|
326
166
|
flushOptions.listReuseNotification = {
|
|
327
167
|
listElement: list,
|
|
328
|
-
itemKey: platformInfo['item-key']
|
|
168
|
+
itemKey: platformInfo['item-key']!,
|
|
329
169
|
};
|
|
330
170
|
}
|
|
331
171
|
__FlushElementTree(root, flushOptions);
|
|
@@ -336,7 +176,7 @@ export function componentAtIndexFactory(
|
|
|
336
176
|
if (enableReuseNotification) {
|
|
337
177
|
flushOptions.listReuseNotification = {
|
|
338
178
|
listElement: list,
|
|
339
|
-
itemKey: platformInfo['item-key']
|
|
179
|
+
itemKey: platformInfo['item-key']!,
|
|
340
180
|
};
|
|
341
181
|
}
|
|
342
182
|
__FlushElementTree(root, flushOptions);
|
|
@@ -366,29 +206,83 @@ export function componentAtIndexFactory(
|
|
|
366
206
|
return sign;
|
|
367
207
|
};
|
|
368
208
|
|
|
369
|
-
|
|
209
|
+
function componentAtIndex(
|
|
210
|
+
list: FiberElement,
|
|
211
|
+
listID: number,
|
|
212
|
+
cellIndex: number,
|
|
213
|
+
operationID: number,
|
|
214
|
+
enableReuseNotification: boolean,
|
|
215
|
+
) {
|
|
216
|
+
const childCtx = ctx[cellIndex];
|
|
217
|
+
if (!childCtx) {
|
|
218
|
+
throw new Error('childCtx not found');
|
|
219
|
+
}
|
|
220
|
+
const r = componentAtChildCtx(list, listID, childCtx, operationID, enableReuseNotification);
|
|
221
|
+
|
|
222
|
+
/* v8 ignore start */
|
|
223
|
+
if (process.env['NODE_ENV'] === 'test') {
|
|
224
|
+
return r;
|
|
225
|
+
} else {
|
|
226
|
+
return typeof r === 'number' ? r : undefined;
|
|
227
|
+
}
|
|
228
|
+
/* v8 ignore end */
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function componentAtIndexes(
|
|
370
232
|
list: FiberElement,
|
|
371
233
|
listID: number,
|
|
372
234
|
cellIndexes: number[],
|
|
373
235
|
operationIDs: number[],
|
|
374
236
|
enableReuseNotification: boolean,
|
|
375
237
|
asyncFlush: boolean,
|
|
376
|
-
)
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
238
|
+
) {
|
|
239
|
+
let hasUnready = false;
|
|
240
|
+
const p: Array<Promise<number> | number> = [];
|
|
241
|
+
|
|
242
|
+
cellIndexes.forEach((cellIndex, index) => {
|
|
243
|
+
const operationID = operationIDs[index]!;
|
|
244
|
+
const childCtx = ctx[cellIndex];
|
|
245
|
+
if (!childCtx) {
|
|
246
|
+
throw new Error('childCtx not found');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const u = componentAtChildCtx(list, listID, childCtx, operationID, enableReuseNotification, true, asyncFlush);
|
|
250
|
+
if (typeof u === 'number') {
|
|
251
|
+
// ready
|
|
252
|
+
} else {
|
|
253
|
+
hasUnready = true;
|
|
254
|
+
}
|
|
255
|
+
p.push(u);
|
|
380
256
|
});
|
|
257
|
+
|
|
258
|
+
// We need __FlushElementTree twice:
|
|
259
|
+
// 1. The first time is sync, we flush the items that are ready, with unready items' uiSign as -1.
|
|
260
|
+
// 2. The second time is async, with all the uiSigns.
|
|
261
|
+
// NOTE: The `operationIDs` passed to __FlushElementTree must be the one passed in,
|
|
262
|
+
// not the one generated by any code here, to workaround a bug of Lynx Engine.
|
|
263
|
+
// So we CANNOT split the `operationIDs` into two parts: one for ready items, one for unready items.
|
|
264
|
+
if (hasUnready) {
|
|
265
|
+
void Promise.all(p).then((uiSigns) => {
|
|
266
|
+
__FlushElementTree(list, {
|
|
267
|
+
triggerLayout: true,
|
|
268
|
+
operationIDs,
|
|
269
|
+
elementIDs: uiSigns,
|
|
270
|
+
listID,
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
}
|
|
381
274
|
__FlushElementTree(list, {
|
|
382
275
|
triggerLayout: true,
|
|
383
|
-
operationIDs
|
|
384
|
-
elementIDs:
|
|
276
|
+
operationIDs,
|
|
277
|
+
elementIDs: cellIndexes.map((_, index) => typeof p[index] === 'number' ? p[index] : -1),
|
|
385
278
|
listID,
|
|
386
279
|
});
|
|
387
|
-
}
|
|
280
|
+
}
|
|
388
281
|
return [componentAtIndex, componentAtIndexes] as const;
|
|
389
282
|
}
|
|
390
283
|
|
|
391
284
|
export function enqueueComponentFactory(): EnqueueComponentCallback {
|
|
285
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
392
286
|
const enqueueComponent = (_: FiberElement, listID: number, sign: number) => {
|
|
393
287
|
const signMap = gSignMap[listID];
|
|
394
288
|
const recycleMap = gRecycleMap[listID];
|
|
@@ -401,7 +295,7 @@ export function enqueueComponentFactory(): EnqueueComponentCallback {
|
|
|
401
295
|
return;
|
|
402
296
|
}
|
|
403
297
|
|
|
404
|
-
const platformInfo = childCtx.__listItemPlatformInfo
|
|
298
|
+
const platformInfo = childCtx.__listItemPlatformInfo ?? {};
|
|
405
299
|
|
|
406
300
|
const uniqID = childCtx.type + (platformInfo['reuse-identifier'] ?? '');
|
|
407
301
|
if (!recycleMap.has(uniqID)) {
|
|
@@ -411,32 +305,3 @@ export function enqueueComponentFactory(): EnqueueComponentCallback {
|
|
|
411
305
|
};
|
|
412
306
|
return enqueueComponent;
|
|
413
307
|
}
|
|
414
|
-
|
|
415
|
-
export function snapshotCreateList(
|
|
416
|
-
pageId: number,
|
|
417
|
-
_ctx: SnapshotInstance,
|
|
418
|
-
_expIndex: number,
|
|
419
|
-
): FiberElement {
|
|
420
|
-
const signMap = new Map<number, SnapshotInstance>();
|
|
421
|
-
const recycleMap = new Map<string, Map<number, SnapshotInstance>>();
|
|
422
|
-
const [componentAtIndex, componentAtIndexes] = componentAtIndexFactory([]);
|
|
423
|
-
const list = __CreateList(
|
|
424
|
-
pageId,
|
|
425
|
-
componentAtIndex,
|
|
426
|
-
enqueueComponentFactory(),
|
|
427
|
-
{},
|
|
428
|
-
componentAtIndexes,
|
|
429
|
-
);
|
|
430
|
-
const listID = __GetElementUniqueID(list);
|
|
431
|
-
gSignMap[listID] = signMap;
|
|
432
|
-
gRecycleMap[listID] = recycleMap;
|
|
433
|
-
return list;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
export function snapshotDestroyList(si: SnapshotInstance): void {
|
|
437
|
-
const [, elementIndex] = si.__snapshot_def.slot[0]!;
|
|
438
|
-
const list = si.__elements![elementIndex]!;
|
|
439
|
-
const listID = __GetElementUniqueID(list);
|
|
440
|
-
delete gSignMap[listID];
|
|
441
|
-
delete gRecycleMap[listID];
|
|
442
|
-
}
|