@lynx-js/react 0.109.2 → 0.110.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/CHANGELOG.md +33 -0
- package/components/lib/Page.js.map +1 -1
- package/components/src/Page.ts +1 -1
- package/package.json +1 -1
- package/refresh/.turbo/turbo-build.log +1 -1
- package/runtime/lib/backgroundSnapshot.d.ts +2 -1
- package/runtime/lib/backgroundSnapshot.js +66 -42
- package/runtime/lib/backgroundSnapshot.js.map +1 -1
- package/runtime/lib/compat/initData.d.ts +7 -5
- package/runtime/lib/compat/initData.js +1 -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/react.js +3 -3
- package/runtime/lib/hooks/react.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/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/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 +10 -10
- 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 +7 -14
- 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 +8 -5
- 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 -45
- package/runtime/lib/list.js +31 -206
- 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 +9 -6
- 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-api.js +3 -0
- package/runtime/lib/lynx-api.js.map +1 -1
- package/runtime/lib/lynx.js +6 -6
- 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 +17 -9
- package/runtime/lib/snapshot/ref.js +64 -73
- package/runtime/lib/snapshot/ref.js.map +1 -1
- package/runtime/lib/snapshot/spread.d.ts +2 -2
- package/runtime/lib/snapshot/spread.js +12 -12
- 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 +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 +9 -18
- package/runtime/lib/snapshot.js +46 -40
- 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/utils.js +1 -1
- package/runtime/lib/utils.js.map +1 -1
- package/runtime/lib/worklet/workletRef.js +1 -2
- package/runtime/lib/worklet/workletRef.js.map +1 -1
- package/runtime/src/backgroundSnapshot.ts +75 -52
- package/runtime/src/compat/initData.ts +10 -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/react.ts +3 -3
- package/runtime/src/hooks/useLynxGlobalEventListener.ts +1 -1
- package/runtime/src/hydrate.ts +6 -4
- package/runtime/src/internal.ts +3 -2
- package/runtime/src/legacy-react-runtime/index.ts +1 -1
- 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 +28 -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 +10 -7
- package/runtime/src/lifecycle/render.ts +3 -2
- package/runtime/src/lifecycleConstant.ts +11 -7
- package/runtime/src/list.ts +33 -269
- package/runtime/src/listUpdateInfo.ts +221 -0
- package/runtime/src/lynx/calledByNative.ts +15 -10
- 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 +5 -2
- package/runtime/src/lynx.ts +7 -6
- 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 +78 -87
- package/runtime/src/snapshot/spread.ts +47 -22
- package/runtime/src/snapshot/workletEvent.ts +1 -1
- package/runtime/src/snapshot/workletRef.ts +36 -10
- package/runtime/src/snapshot.ts +62 -51
- package/runtime/src/snapshotInstanceHydrationMap.ts +17 -0
- package/runtime/src/utils.ts +3 -3
- package/runtime/src/worklet/workletRef.ts +1 -2
- package/testing-library/dist/env/vitest.js +8 -6
- package/testing-library/dist/pure.js +4 -3
- package/testing-library/dist/vitest.config.js +7 -7
- package/transform/cjs/main.cjs +4 -0
- package/transform/dist/wasm.cjs +1 -1
- package/worklet-runtime/dist/dev.js +1 -4
- package/worklet-runtime/dist/main.js +0 -3
- package/worklet-runtime/lib/bindings/observers.d.ts +14 -1
- package/worklet-runtime/lib/bindings/observers.js +7 -7
- package/worklet-runtime/lib/bindings/observers.js.map +1 -1
- 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
|
@@ -0,0 +1,99 @@
|
|
|
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
|
+
import type { NodesRef, SelectorQuery } from '@lynx-js/types';
|
|
6
|
+
|
|
7
|
+
import { hydrationMap } from '../../snapshotInstanceHydrationMap.js';
|
|
8
|
+
|
|
9
|
+
type RefTask = (nodesRef: NodesRef) => SelectorQuery;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A flag to indicate whether UI operations should be delayed.
|
|
13
|
+
* When set to true, UI operations will be queued in the `delayedUiOps` array
|
|
14
|
+
* and executed later when `runDelayedUiOps` is called.
|
|
15
|
+
* This is used before hydration to ensure UI operations are batched
|
|
16
|
+
* and executed at the appropriate time.
|
|
17
|
+
*/
|
|
18
|
+
const shouldDelayUiOps = { value: true };
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* An array of functions that will be executed later when `runDelayedUiOps` is called.
|
|
22
|
+
* These functions contain UI operations that need to be delayed.
|
|
23
|
+
*/
|
|
24
|
+
const delayedUiOps: (() => void)[] = [];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Runs a task either immediately or delays it based on the `shouldDelayUiOps` flag.
|
|
28
|
+
* @param task - The function to execute.
|
|
29
|
+
*/
|
|
30
|
+
function runOrDelay(task: () => void): void {
|
|
31
|
+
if (shouldDelayUiOps.value) {
|
|
32
|
+
delayedUiOps.push(task);
|
|
33
|
+
} else {
|
|
34
|
+
task();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Executes all delayed UI operations.
|
|
40
|
+
*/
|
|
41
|
+
function runDelayedUiOps(): void {
|
|
42
|
+
for (const task of delayedUiOps) {
|
|
43
|
+
task();
|
|
44
|
+
}
|
|
45
|
+
shouldDelayUiOps.value = false;
|
|
46
|
+
delayedUiOps.length = 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A proxy class designed for managing and executing reference-based tasks.
|
|
51
|
+
* It delays the execution of tasks until hydration is complete.
|
|
52
|
+
*/
|
|
53
|
+
class RefProxy {
|
|
54
|
+
private readonly refAttr: [snapshotInstanceId: number, expIndex: number];
|
|
55
|
+
private task: RefTask | undefined;
|
|
56
|
+
|
|
57
|
+
constructor(refAttr: [snapshotInstanceId: number, expIndex: number]) {
|
|
58
|
+
this.refAttr = refAttr;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private setTask<K extends keyof NodesRef>(
|
|
62
|
+
method: K,
|
|
63
|
+
args: Parameters<NodesRef[K]>,
|
|
64
|
+
): this {
|
|
65
|
+
this.task = (nodesRef) => {
|
|
66
|
+
return (nodesRef[method] as unknown as (...args: any[]) => SelectorQuery)(...args);
|
|
67
|
+
};
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
invoke(...args: Parameters<NodesRef['invoke']>): RefProxy {
|
|
72
|
+
return new RefProxy(this.refAttr).setTask('invoke', args);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
path(...args: Parameters<NodesRef['path']>): RefProxy {
|
|
76
|
+
return new RefProxy(this.refAttr).setTask('path', args);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fields(...args: Parameters<NodesRef['fields']>): RefProxy {
|
|
80
|
+
return new RefProxy(this.refAttr).setTask('fields', args);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
setNativeProps(...args: Parameters<NodesRef['setNativeProps']>): RefProxy {
|
|
84
|
+
return new RefProxy(this.refAttr).setTask('setNativeProps', args);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
exec(): void {
|
|
88
|
+
runOrDelay(() => {
|
|
89
|
+
const realRefId = hydrationMap.get(this.refAttr[0]) ?? this.refAttr[0];
|
|
90
|
+
const refSelector = `[react-ref-${realRefId}-${this.refAttr[1]}]`;
|
|
91
|
+
this.task!(lynx.createSelectorQuery().select(refSelector)).exec();
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
99
|
+
export { RefProxy, runDelayedUiOps, shouldDelayUiOps };
|
|
@@ -11,27 +11,28 @@ import { render } from 'preact';
|
|
|
11
11
|
|
|
12
12
|
import { hydrate } from '../hydrate.js';
|
|
13
13
|
import { LifecycleConstant } from '../lifecycleConstant.js';
|
|
14
|
-
import { __pendingListUpdates } from '../
|
|
14
|
+
import { __pendingListUpdates } from '../pendingListUpdates.js';
|
|
15
15
|
import { __root, setRoot } from '../root.js';
|
|
16
|
+
import { destroyBackground } from './destroy.js';
|
|
17
|
+
import { applyRefQueue } from '../snapshot/workletRef.js';
|
|
16
18
|
import { SnapshotInstance, __page, snapshotInstanceManager } from '../snapshot.js';
|
|
17
|
-
import { takeGlobalRefPatchMap } from '../snapshot/ref.js';
|
|
18
19
|
import { isEmptyObject } from '../utils.js';
|
|
19
20
|
import { destroyWorklet } from '../worklet/destroy.js';
|
|
20
|
-
import { destroyBackground } from './destroy.js';
|
|
21
21
|
import { clearJSReadyEventIdSwap, isJSReady } from './event/jsReady.js';
|
|
22
22
|
import { increaseReloadVersion } from './pass.js';
|
|
23
|
+
import { setMainThreadHydrationFinished } from './patch/isMainThreadHydrationFinished.js';
|
|
23
24
|
import { deinitGlobalSnapshotPatch } from './patch/snapshotPatch.js';
|
|
25
|
+
import { shouldDelayUiOps } from './ref/delay.js';
|
|
24
26
|
import { renderMainThread } from './render.js';
|
|
25
|
-
import { setMainThreadHydrationFinished } from './patch/isMainThreadHydrationFinished.js';
|
|
26
27
|
|
|
27
|
-
function reloadMainThread(data:
|
|
28
|
+
function reloadMainThread(data: unknown, options: UpdatePageOption): void {
|
|
28
29
|
if (__PROFILE__) {
|
|
29
30
|
console.profile('reloadTemplate');
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
increaseReloadVersion();
|
|
33
34
|
|
|
34
|
-
if (typeof data == 'object' && !isEmptyObject(data)) {
|
|
35
|
+
if (typeof data == 'object' && !isEmptyObject(data as Record<string, unknown>)) {
|
|
35
36
|
Object.assign(lynx.__initData, data);
|
|
36
37
|
}
|
|
37
38
|
|
|
@@ -51,13 +52,13 @@ function reloadMainThread(data: any, options: UpdatePageOption): void {
|
|
|
51
52
|
|
|
52
53
|
// always call this before `__FlushElementTree`
|
|
53
54
|
__pendingListUpdates.flush();
|
|
55
|
+
applyRefQueue();
|
|
54
56
|
|
|
55
57
|
if (isJSReady) {
|
|
56
58
|
__OnLifecycleEvent([
|
|
57
59
|
LifecycleConstant.firstScreen, /* FIRST_SCREEN */
|
|
58
60
|
{
|
|
59
61
|
root: JSON.stringify(__root),
|
|
60
|
-
refPatch: JSON.stringify(takeGlobalRefPatchMap()),
|
|
61
62
|
},
|
|
62
63
|
]);
|
|
63
64
|
}
|
|
@@ -84,6 +85,8 @@ function reloadBackground(updateData: Record<string, any>): void {
|
|
|
84
85
|
// COW when modify `lynx.__initData` to make sure Provider & Consumer works
|
|
85
86
|
lynx.__initData = Object.assign({}, lynx.__initData, updateData);
|
|
86
87
|
|
|
88
|
+
shouldDelayUiOps.value = true;
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
87
90
|
render(__root.__jsx, __root as any);
|
|
88
91
|
|
|
89
92
|
if (__PROFILE__) {
|
|
@@ -18,6 +18,7 @@ function renderMainThread(): void {
|
|
|
18
18
|
process.env['NODE_ENV'] === 'test' && typeof __TESTING_FORCE_RENDER_TO_OPCODE__ !== 'undefined'
|
|
19
19
|
&& !__TESTING_FORCE_RENDER_TO_OPCODE__
|
|
20
20
|
) {
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
21
22
|
render(__root.__jsx, __root as any);
|
|
22
23
|
} else {
|
|
23
24
|
let opcodes;
|
|
@@ -25,8 +26,7 @@ function renderMainThread(): void {
|
|
|
25
26
|
if (__PROFILE__) {
|
|
26
27
|
console.profile('renderToString');
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
-
opcodes = renderToString(__root.__jsx);
|
|
29
|
+
opcodes = renderToString(__root.__jsx, undefined);
|
|
30
30
|
} catch (e) {
|
|
31
31
|
lynx.reportError(e as Error);
|
|
32
32
|
opcodes = [];
|
|
@@ -39,6 +39,7 @@ function renderMainThread(): void {
|
|
|
39
39
|
if (__PROFILE__) {
|
|
40
40
|
console.profile('renderOpcodesInto');
|
|
41
41
|
}
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
42
43
|
renderOpcodesInto(opcodes, __root as any);
|
|
43
44
|
if (__ENABLE_SSR__) {
|
|
44
45
|
__root.__opcodes = opcodes;
|
|
@@ -1,13 +1,17 @@
|
|
|
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
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
export const enum LifecycleConstant {
|
|
5
|
+
firstScreen = 'rLynxFirstScreen',
|
|
6
|
+
updateFromRoot = 'updateFromRoot',
|
|
7
|
+
globalEventFromLepus = 'globalEventFromLepus',
|
|
8
|
+
jsReady = 'rLynxJSReady',
|
|
9
|
+
patchUpdate = 'rLynxChange',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface FirstScreenData {
|
|
13
|
+
root: string;
|
|
14
|
+
jsReadyEventIdSwap: Record<string | number, number>;
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
export const enum NativeUpdateDataType {
|
package/runtime/src/list.ts
CHANGED
|
@@ -1,240 +1,12 @@
|
|
|
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 {
|
|
5
|
-
import { commitMainThreadPatchUpdate } from './lifecycle/patch/updateMainThread.js';
|
|
4
|
+
import { applyRefQueue } from './snapshot/workletRef.js';
|
|
6
5
|
import type { SnapshotInstance } from './snapshot.js';
|
|
7
6
|
|
|
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
|
-
};
|
|
235
|
-
|
|
236
7
|
export const gSignMap: Record<number, Map<number, SnapshotInstance>> = {};
|
|
237
8
|
export const gRecycleMap: Record<number, Map<string, Map<number, SnapshotInstance>>> = {};
|
|
9
|
+
const gParentWeakMap: WeakMap<SnapshotInstance, unknown> = new WeakMap();
|
|
238
10
|
|
|
239
11
|
export function clearListGlobal(): void {
|
|
240
12
|
for (const key in gSignMap) {
|
|
@@ -247,7 +19,25 @@ export function clearListGlobal(): void {
|
|
|
247
19
|
|
|
248
20
|
export function componentAtIndexFactory(
|
|
249
21
|
ctx: SnapshotInstance[],
|
|
22
|
+
hydrateFunction: (before: SnapshotInstance, after: SnapshotInstance) => void,
|
|
250
23
|
): [ComponentAtIndexCallback, ComponentAtIndexesCallback] {
|
|
24
|
+
// A hack workaround to ensure childCtx has no direct reference through `__parent` to list,
|
|
25
|
+
// to avoid memory leak.
|
|
26
|
+
// TODO(hzy): make `__parent` a WeakRef or `#__parent` in the future.
|
|
27
|
+
ctx.forEach((childCtx) => {
|
|
28
|
+
if (gParentWeakMap.has(childCtx)) {
|
|
29
|
+
// do it only once
|
|
30
|
+
} else {
|
|
31
|
+
gParentWeakMap.set(childCtx, childCtx.parentNode!);
|
|
32
|
+
Object.defineProperty(childCtx, '__parent', {
|
|
33
|
+
get: () => gParentWeakMap.get(childCtx)!,
|
|
34
|
+
set: (value: unknown) => {
|
|
35
|
+
gParentWeakMap.set(childCtx, value);
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
251
41
|
const componentAtIndex = (
|
|
252
42
|
list: FiberElement,
|
|
253
43
|
listID: number,
|
|
@@ -268,7 +58,7 @@ export function componentAtIndexFactory(
|
|
|
268
58
|
throw new Error('childCtx not found');
|
|
269
59
|
}
|
|
270
60
|
|
|
271
|
-
const platformInfo = childCtx.__listItemPlatformInfo
|
|
61
|
+
const platformInfo = childCtx.__listItemPlatformInfo ?? {};
|
|
272
62
|
|
|
273
63
|
const uniqID = childCtx.type + (platformInfo['reuse-identifier'] ?? '');
|
|
274
64
|
const recycleSignMap = recycleMap.get(uniqID);
|
|
@@ -294,10 +84,9 @@ export function componentAtIndexFactory(
|
|
|
294
84
|
__FlushElementTree(root, { triggerLayout: true, operationID, elementID: sign, listID });
|
|
295
85
|
} else if (enableBatchRender && asyncFlush) {
|
|
296
86
|
__FlushElementTree(root, { asyncFlush: true });
|
|
297
|
-
} else {
|
|
298
|
-
// enableBatchRender == true && asyncFlush == false
|
|
299
|
-
// in this case, no need to invoke __FlushElementTree because in the end of componentAtIndexes(), the list will invoke __FlushElementTree.
|
|
300
87
|
}
|
|
88
|
+
// enableBatchRender == true && asyncFlush == false
|
|
89
|
+
// in this case, no need to invoke __FlushElementTree because in the end of componentAtIndexes(), the list will invoke __FlushElementTree.
|
|
301
90
|
return sign;
|
|
302
91
|
} else {
|
|
303
92
|
const newCtx = childCtx.takeElements();
|
|
@@ -309,9 +98,13 @@ export function componentAtIndexFactory(
|
|
|
309
98
|
const [first] = recycleSignMap;
|
|
310
99
|
const [sign, oldCtx] = first!;
|
|
311
100
|
recycleSignMap.delete(sign);
|
|
312
|
-
|
|
101
|
+
hydrateFunction(oldCtx, childCtx);
|
|
313
102
|
oldCtx.unRenderElements();
|
|
103
|
+
if (!oldCtx.__id) {
|
|
104
|
+
oldCtx.tearDown();
|
|
105
|
+
}
|
|
314
106
|
const root = childCtx.__element_root!;
|
|
107
|
+
applyRefQueue();
|
|
315
108
|
if (!enableBatchRender) {
|
|
316
109
|
const flushOptions: FlushOptions = {
|
|
317
110
|
triggerLayout: true,
|
|
@@ -322,7 +115,7 @@ export function componentAtIndexFactory(
|
|
|
322
115
|
if (enableReuseNotification) {
|
|
323
116
|
flushOptions.listReuseNotification = {
|
|
324
117
|
listElement: list,
|
|
325
|
-
itemKey: platformInfo['item-key']
|
|
118
|
+
itemKey: platformInfo['item-key']!,
|
|
326
119
|
};
|
|
327
120
|
}
|
|
328
121
|
__FlushElementTree(root, flushOptions);
|
|
@@ -333,13 +126,12 @@ export function componentAtIndexFactory(
|
|
|
333
126
|
if (enableReuseNotification) {
|
|
334
127
|
flushOptions.listReuseNotification = {
|
|
335
128
|
listElement: list,
|
|
336
|
-
itemKey: platformInfo['item-key']
|
|
129
|
+
itemKey: platformInfo['item-key']!,
|
|
337
130
|
};
|
|
338
131
|
}
|
|
339
132
|
__FlushElementTree(root, flushOptions);
|
|
340
133
|
}
|
|
341
134
|
signMap.set(sign, childCtx);
|
|
342
|
-
commitMainThreadPatchUpdate(undefined);
|
|
343
135
|
return sign;
|
|
344
136
|
}
|
|
345
137
|
|
|
@@ -347,6 +139,7 @@ export function componentAtIndexFactory(
|
|
|
347
139
|
const root = childCtx.__element_root!;
|
|
348
140
|
__AppendElement(list, root);
|
|
349
141
|
const sign = __GetElementUniqueID(root);
|
|
142
|
+
applyRefQueue();
|
|
350
143
|
if (!enableBatchRender) {
|
|
351
144
|
__FlushElementTree(root, {
|
|
352
145
|
triggerLayout: true,
|
|
@@ -360,7 +153,6 @@ export function componentAtIndexFactory(
|
|
|
360
153
|
});
|
|
361
154
|
}
|
|
362
155
|
signMap.set(sign, childCtx);
|
|
363
|
-
commitMainThreadPatchUpdate(undefined);
|
|
364
156
|
return sign;
|
|
365
157
|
};
|
|
366
158
|
|
|
@@ -387,6 +179,7 @@ export function componentAtIndexFactory(
|
|
|
387
179
|
}
|
|
388
180
|
|
|
389
181
|
export function enqueueComponentFactory(): EnqueueComponentCallback {
|
|
182
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
390
183
|
const enqueueComponent = (_: FiberElement, listID: number, sign: number) => {
|
|
391
184
|
const signMap = gSignMap[listID];
|
|
392
185
|
const recycleMap = gRecycleMap[listID];
|
|
@@ -399,7 +192,7 @@ export function enqueueComponentFactory(): EnqueueComponentCallback {
|
|
|
399
192
|
return;
|
|
400
193
|
}
|
|
401
194
|
|
|
402
|
-
const platformInfo = childCtx.__listItemPlatformInfo
|
|
195
|
+
const platformInfo = childCtx.__listItemPlatformInfo ?? {};
|
|
403
196
|
|
|
404
197
|
const uniqID = childCtx.type + (platformInfo['reuse-identifier'] ?? '');
|
|
405
198
|
if (!recycleMap.has(uniqID)) {
|
|
@@ -409,32 +202,3 @@ export function enqueueComponentFactory(): EnqueueComponentCallback {
|
|
|
409
202
|
};
|
|
410
203
|
return enqueueComponent;
|
|
411
204
|
}
|
|
412
|
-
|
|
413
|
-
export function snapshotCreateList(
|
|
414
|
-
pageId: number,
|
|
415
|
-
_ctx: SnapshotInstance,
|
|
416
|
-
_expIndex: number,
|
|
417
|
-
): FiberElement {
|
|
418
|
-
const signMap = new Map<number, SnapshotInstance>();
|
|
419
|
-
const recycleMap = new Map<string, Map<number, SnapshotInstance>>();
|
|
420
|
-
const [componentAtIndex, componentAtIndexes] = componentAtIndexFactory([]);
|
|
421
|
-
const list = __CreateList(
|
|
422
|
-
pageId,
|
|
423
|
-
componentAtIndex,
|
|
424
|
-
enqueueComponentFactory(),
|
|
425
|
-
{},
|
|
426
|
-
componentAtIndexes,
|
|
427
|
-
);
|
|
428
|
-
const listID = __GetElementUniqueID(list);
|
|
429
|
-
gSignMap[listID] = signMap;
|
|
430
|
-
gRecycleMap[listID] = recycleMap;
|
|
431
|
-
return list;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
export function snapshotDestroyList(si: SnapshotInstance): void {
|
|
435
|
-
const [, elementIndex] = si.__snapshot_def.slot[0]!;
|
|
436
|
-
const list = si.__elements![elementIndex]!;
|
|
437
|
-
const listID = __GetElementUniqueID(list);
|
|
438
|
-
delete gSignMap[listID];
|
|
439
|
-
delete gRecycleMap[listID];
|
|
440
|
-
}
|