@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.
Files changed (202) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/components/lib/Page.js.map +1 -1
  3. package/components/src/Page.ts +1 -1
  4. package/package.json +1 -1
  5. package/refresh/.turbo/turbo-build.log +1 -1
  6. package/runtime/lib/backgroundSnapshot.d.ts +2 -1
  7. package/runtime/lib/backgroundSnapshot.js +66 -42
  8. package/runtime/lib/backgroundSnapshot.js.map +1 -1
  9. package/runtime/lib/compat/initData.d.ts +7 -5
  10. package/runtime/lib/compat/initData.js +1 -2
  11. package/runtime/lib/compat/initData.js.map +1 -1
  12. package/runtime/lib/compat/lynxComponent.js +10 -12
  13. package/runtime/lib/compat/lynxComponent.js.map +1 -1
  14. package/runtime/lib/debug/profile.js +1 -0
  15. package/runtime/lib/debug/profile.js.map +1 -1
  16. package/runtime/lib/gesture/processGestureBagkround.d.ts +1 -1
  17. package/runtime/lib/gesture/processGestureBagkround.js +4 -1
  18. package/runtime/lib/gesture/processGestureBagkround.js.map +1 -1
  19. package/runtime/lib/gesture/types.js.map +1 -1
  20. package/runtime/lib/hooks/react.js +3 -3
  21. package/runtime/lib/hooks/react.js.map +1 -1
  22. package/runtime/lib/hooks/useLynxGlobalEventListener.d.ts +1 -1
  23. package/runtime/lib/hydrate.d.ts +1 -1
  24. package/runtime/lib/hydrate.js +5 -4
  25. package/runtime/lib/hydrate.js.map +1 -1
  26. package/runtime/lib/internal.d.ts +3 -2
  27. package/runtime/lib/internal.js +3 -2
  28. package/runtime/lib/internal.js.map +1 -1
  29. package/runtime/lib/legacy-react-runtime/index.js +1 -1
  30. package/runtime/lib/legacy-react-runtime/index.js.map +1 -1
  31. package/runtime/lib/lifecycle/destroy.js +1 -0
  32. package/runtime/lib/lifecycle/destroy.js.map +1 -1
  33. package/runtime/lib/lifecycle/event/delayEvents.js +3 -0
  34. package/runtime/lib/lifecycle/event/delayEvents.js.map +1 -1
  35. package/runtime/lib/lifecycle/event/delayLifecycleEvents.d.ts +3 -2
  36. package/runtime/lib/lifecycle/event/delayLifecycleEvents.js +1 -12
  37. package/runtime/lib/lifecycle/event/delayLifecycleEvents.js.map +1 -1
  38. package/runtime/lib/lifecycle/event/jsReady.d.ts +1 -1
  39. package/runtime/lib/lifecycle/event/jsReady.js +3 -2
  40. package/runtime/lib/lifecycle/event/jsReady.js.map +1 -1
  41. package/runtime/lib/lifecycle/patch/commit.d.ts +0 -2
  42. package/runtime/lib/lifecycle/patch/commit.js +8 -36
  43. package/runtime/lib/lifecycle/patch/commit.js.map +1 -1
  44. package/runtime/lib/lifecycle/patch/error.d.ts +8 -0
  45. package/runtime/lib/lifecycle/patch/error.js +47 -0
  46. package/runtime/lib/lifecycle/patch/error.js.map +1 -0
  47. package/runtime/lib/lifecycle/patch/isMainThreadHydrationFinished.js +3 -0
  48. package/runtime/lib/lifecycle/patch/isMainThreadHydrationFinished.js.map +1 -1
  49. package/runtime/lib/lifecycle/patch/snapshotPatch.d.ts +2 -2
  50. package/runtime/lib/lifecycle/patch/snapshotPatch.js.map +1 -1
  51. package/runtime/lib/lifecycle/patch/snapshotPatchApply.js +10 -10
  52. package/runtime/lib/lifecycle/patch/snapshotPatchApply.js.map +1 -1
  53. package/runtime/lib/lifecycle/patch/updateMainThread.d.ts +0 -1
  54. package/runtime/lib/lifecycle/patch/updateMainThread.js +7 -14
  55. package/runtime/lib/lifecycle/patch/updateMainThread.js.map +1 -1
  56. package/runtime/lib/lifecycle/ref/delay.d.ts +31 -0
  57. package/runtime/lib/lifecycle/ref/delay.js +80 -0
  58. package/runtime/lib/lifecycle/ref/delay.js.map +1 -0
  59. package/runtime/lib/lifecycle/reload.d.ts +1 -1
  60. package/runtime/lib/lifecycle/reload.js +8 -5
  61. package/runtime/lib/lifecycle/reload.js.map +1 -1
  62. package/runtime/lib/lifecycle/render.js +3 -2
  63. package/runtime/lib/lifecycle/render.js.map +1 -1
  64. package/runtime/lib/lifecycleConstant.d.ts +10 -7
  65. package/runtime/lib/lifecycleConstant.js +8 -8
  66. package/runtime/lib/lifecycleConstant.js.map +1 -1
  67. package/runtime/lib/list.d.ts +1 -45
  68. package/runtime/lib/list.js +31 -206
  69. package/runtime/lib/list.js.map +1 -1
  70. package/runtime/lib/listUpdateInfo.d.ts +38 -0
  71. package/runtime/lib/listUpdateInfo.js +152 -0
  72. package/runtime/lib/listUpdateInfo.js.map +1 -0
  73. package/runtime/lib/lynx/calledByNative.js +9 -6
  74. package/runtime/lib/lynx/calledByNative.js.map +1 -1
  75. package/runtime/lib/lynx/component.js +7 -0
  76. package/runtime/lib/lynx/component.js.map +1 -1
  77. package/runtime/lib/lynx/dynamic-js.d.ts +5 -1
  78. package/runtime/lib/lynx/dynamic-js.js +1 -0
  79. package/runtime/lib/lynx/dynamic-js.js.map +1 -1
  80. package/runtime/lib/lynx/env.d.ts +1 -1
  81. package/runtime/lib/lynx/env.js +13 -13
  82. package/runtime/lib/lynx/env.js.map +1 -1
  83. package/runtime/lib/lynx/lazy-bundle.js +7 -5
  84. package/runtime/lib/lynx/lazy-bundle.js.map +1 -1
  85. package/runtime/lib/lynx/performance.js +1 -1
  86. package/runtime/lib/lynx/performance.js.map +1 -1
  87. package/runtime/lib/lynx/runWithForce.js +3 -0
  88. package/runtime/lib/lynx/runWithForce.js.map +1 -1
  89. package/runtime/lib/lynx/tt.js +12 -33
  90. package/runtime/lib/lynx/tt.js.map +1 -1
  91. package/runtime/lib/lynx-api.d.ts +1 -1
  92. package/runtime/lib/lynx-api.js +3 -0
  93. package/runtime/lib/lynx-api.js.map +1 -1
  94. package/runtime/lib/lynx.js +6 -6
  95. package/runtime/lib/lynx.js.map +1 -1
  96. package/runtime/lib/opcodes.js +2 -1
  97. package/runtime/lib/opcodes.js.map +1 -1
  98. package/runtime/lib/pendingListUpdates.d.ts +6 -0
  99. package/runtime/lib/pendingListUpdates.js +16 -0
  100. package/runtime/lib/pendingListUpdates.js.map +1 -0
  101. package/runtime/lib/renderToOpcodes/index.js +7 -7
  102. package/runtime/lib/renderToOpcodes/index.js.map +1 -1
  103. package/runtime/lib/snapshot/dynamicPartType.d.ts +12 -0
  104. package/runtime/lib/snapshot/dynamicPartType.js +17 -0
  105. package/runtime/lib/snapshot/dynamicPartType.js.map +1 -0
  106. package/runtime/lib/snapshot/gesture.js +3 -0
  107. package/runtime/lib/snapshot/gesture.js.map +1 -1
  108. package/runtime/lib/snapshot/list.d.ts +3 -0
  109. package/runtime/lib/snapshot/list.js +23 -0
  110. package/runtime/lib/snapshot/list.js.map +1 -0
  111. package/runtime/lib/snapshot/platformInfo.d.ts +10 -0
  112. package/runtime/lib/snapshot/platformInfo.js +6 -3
  113. package/runtime/lib/snapshot/platformInfo.js.map +1 -1
  114. package/runtime/lib/snapshot/ref.d.ts +17 -9
  115. package/runtime/lib/snapshot/ref.js +64 -73
  116. package/runtime/lib/snapshot/ref.js.map +1 -1
  117. package/runtime/lib/snapshot/spread.d.ts +2 -2
  118. package/runtime/lib/snapshot/spread.js +12 -12
  119. package/runtime/lib/snapshot/spread.js.map +1 -1
  120. package/runtime/lib/snapshot/workletEvent.js +1 -1
  121. package/runtime/lib/snapshot/workletEvent.js.map +1 -1
  122. package/runtime/lib/snapshot/workletRef.d.ts +3 -3
  123. package/runtime/lib/snapshot/workletRef.js +27 -8
  124. package/runtime/lib/snapshot/workletRef.js.map +1 -1
  125. package/runtime/lib/snapshot.d.ts +9 -18
  126. package/runtime/lib/snapshot.js +46 -40
  127. package/runtime/lib/snapshot.js.map +1 -1
  128. package/runtime/lib/snapshotInstanceHydrationMap.d.ts +9 -0
  129. package/runtime/lib/snapshotInstanceHydrationMap.js +16 -0
  130. package/runtime/lib/snapshotInstanceHydrationMap.js.map +1 -0
  131. package/runtime/lib/utils.js +1 -1
  132. package/runtime/lib/utils.js.map +1 -1
  133. package/runtime/lib/worklet/workletRef.js +1 -2
  134. package/runtime/lib/worklet/workletRef.js.map +1 -1
  135. package/runtime/src/backgroundSnapshot.ts +75 -52
  136. package/runtime/src/compat/initData.ts +10 -9
  137. package/runtime/src/compat/lynxComponent.ts +12 -13
  138. package/runtime/src/debug/profile.ts +1 -0
  139. package/runtime/src/gesture/processGestureBagkround.ts +5 -1
  140. package/runtime/src/gesture/types.ts +3 -0
  141. package/runtime/src/hooks/react.ts +3 -3
  142. package/runtime/src/hooks/useLynxGlobalEventListener.ts +1 -1
  143. package/runtime/src/hydrate.ts +6 -4
  144. package/runtime/src/internal.ts +3 -2
  145. package/runtime/src/legacy-react-runtime/index.ts +1 -1
  146. package/runtime/src/lifecycle/destroy.ts +1 -0
  147. package/runtime/src/lifecycle/event/delayEvents.ts +3 -0
  148. package/runtime/src/lifecycle/event/delayLifecycleEvents.ts +7 -13
  149. package/runtime/src/lifecycle/event/jsReady.ts +4 -3
  150. package/runtime/src/lifecycle/patch/commit.ts +10 -41
  151. package/runtime/src/lifecycle/patch/error.ts +61 -0
  152. package/runtime/src/lifecycle/patch/isMainThreadHydrationFinished.ts +3 -0
  153. package/runtime/src/lifecycle/patch/snapshotPatch.ts +2 -2
  154. package/runtime/src/lifecycle/patch/snapshotPatchApply.ts +28 -28
  155. package/runtime/src/lifecycle/patch/updateMainThread.ts +7 -16
  156. package/runtime/src/lifecycle/ref/delay.ts +99 -0
  157. package/runtime/src/lifecycle/reload.ts +10 -7
  158. package/runtime/src/lifecycle/render.ts +3 -2
  159. package/runtime/src/lifecycleConstant.ts +11 -7
  160. package/runtime/src/list.ts +33 -269
  161. package/runtime/src/listUpdateInfo.ts +221 -0
  162. package/runtime/src/lynx/calledByNative.ts +15 -10
  163. package/runtime/src/lynx/component.ts +9 -0
  164. package/runtime/src/lynx/dynamic-js.ts +5 -1
  165. package/runtime/src/lynx/env.ts +17 -17
  166. package/runtime/src/lynx/lazy-bundle.ts +22 -14
  167. package/runtime/src/lynx/performance.ts +1 -1
  168. package/runtime/src/lynx/runWithForce.ts +9 -5
  169. package/runtime/src/lynx/tt.ts +19 -37
  170. package/runtime/src/lynx-api.ts +5 -2
  171. package/runtime/src/lynx.ts +7 -6
  172. package/runtime/src/opcodes.ts +2 -1
  173. package/runtime/src/pendingListUpdates.ts +18 -0
  174. package/runtime/src/renderToOpcodes/index.ts +7 -7
  175. package/runtime/src/snapshot/dynamicPartType.ts +16 -0
  176. package/runtime/src/snapshot/gesture.ts +3 -0
  177. package/runtime/src/snapshot/list.ts +36 -0
  178. package/runtime/src/snapshot/platformInfo.ts +19 -5
  179. package/runtime/src/snapshot/ref.ts +78 -87
  180. package/runtime/src/snapshot/spread.ts +47 -22
  181. package/runtime/src/snapshot/workletEvent.ts +1 -1
  182. package/runtime/src/snapshot/workletRef.ts +36 -10
  183. package/runtime/src/snapshot.ts +62 -51
  184. package/runtime/src/snapshotInstanceHydrationMap.ts +17 -0
  185. package/runtime/src/utils.ts +3 -3
  186. package/runtime/src/worklet/workletRef.ts +1 -2
  187. package/testing-library/dist/env/vitest.js +8 -6
  188. package/testing-library/dist/pure.js +4 -3
  189. package/testing-library/dist/vitest.config.js +7 -7
  190. package/transform/cjs/main.cjs +4 -0
  191. package/transform/dist/wasm.cjs +1 -1
  192. package/worklet-runtime/dist/dev.js +1 -4
  193. package/worklet-runtime/dist/main.js +0 -3
  194. package/worklet-runtime/lib/bindings/observers.d.ts +14 -1
  195. package/worklet-runtime/lib/bindings/observers.js +7 -7
  196. package/worklet-runtime/lib/bindings/observers.js.map +1 -1
  197. package/worklet-runtime/lib/hydrate.js +0 -5
  198. package/worklet-runtime/lib/hydrate.js.map +1 -1
  199. package/runtime/lib/lifecycle/delayUnmount.d.ts +0 -8
  200. package/runtime/lib/lifecycle/delayUnmount.js +0 -65
  201. package/runtime/lib/lifecycle/delayUnmount.js.map +0 -1
  202. package/runtime/src/lifecycle/delayUnmount.ts +0 -77
@@ -9,10 +9,11 @@
9
9
  * optimized attribute updates at compile time, avoiding runtime object spreads.
10
10
  */
11
11
 
12
- import type { Worklet } from '@lynx-js/react/worklet-runtime/bindings';
12
+ import type { Element, Worklet, WorkletRefImpl } from '@lynx-js/react/worklet-runtime/bindings';
13
13
 
14
- import { BackgroundSnapshotInstance } from '../backgroundSnapshot.js';
15
- import { ListUpdateInfoRecording, __pendingListUpdates } from '../list.js';
14
+ import type { BackgroundSnapshotInstance } from '../backgroundSnapshot.js';
15
+ import { ListUpdateInfoRecording } from '../listUpdateInfo.js';
16
+ import { __pendingListUpdates } from '../pendingListUpdates.js';
16
17
  import { SnapshotInstance } from '../snapshot.js';
17
18
  import { isDirectOrDeepEqual, isEmptyObject, pick } from '../utils.js';
18
19
  import { updateEvent } from './event.js';
@@ -22,6 +23,7 @@ import { transformRef, updateRef } from './ref.js';
22
23
  import { updateWorkletEvent } from './workletEvent.js';
23
24
  import { updateWorkletRef } from './workletRef.js';
24
25
 
26
+ // eslint-disable-next-line regexp/no-unused-capturing-group
25
27
  const eventRegExp = /^(([A-Za-z-]*):)?(bind|catch|capture-bind|capture-catch|global-bind)([A-Za-z]+)$/;
26
28
  const eventTypeMap: Record<string, string> = {
27
29
  bind: 'bindEvent',
@@ -38,12 +40,16 @@ const noFlattenAttributes = /* @__PURE__ */ new Set<string>([
38
40
  'exposure-id',
39
41
  ]);
40
42
 
41
- function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any, elementIndex: number): void {
43
+ function updateSpread(
44
+ snapshot: SnapshotInstance,
45
+ index: number,
46
+ oldValue: Record<string, unknown> | undefined | null,
47
+ elementIndex: number,
48
+ ): void {
42
49
  oldValue ??= {};
43
- let newValue: Record<string, any> = snapshot.__values![index]; // compiler guarantee this must be an object;
50
+ let newValue: Record<string, unknown> = snapshot.__values![index] as Record<string, unknown>; // compiler guarantee this must be an object;
44
51
 
45
- // @ts-ignore
46
- const list = snapshot.__parent;
52
+ const list = snapshot.parentNode;
47
53
  if (list?.__snapshot_def.isListHolder) {
48
54
  const oldPlatformInfo = pick(oldValue, platformInfoAttributes);
49
55
  const platformInfo = pick(newValue, platformInfoAttributes);
@@ -79,21 +85,20 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
79
85
  snapshot.__values![index] = newValue;
80
86
  }
81
87
 
82
- const dataset: Record<string, any> = {};
88
+ const dataset: Record<string, unknown> = {};
83
89
  let match: RegExpMatchArray | null = null;
84
90
  for (const key in newValue) {
85
91
  const v = newValue[key];
86
92
  if (v !== oldValue[key]) {
87
93
  if (key === 'className') {
88
- __SetClasses(snapshot.__elements[elementIndex]!, v);
94
+ __SetClasses(snapshot.__elements[elementIndex]!, v as string);
89
95
  } else if (key === 'style') {
90
- __SetInlineStyles(snapshot.__elements[elementIndex]!, v);
96
+ __SetInlineStyles(snapshot.__elements[elementIndex]!, v as string);
91
97
  } else if (key === 'id') {
92
- __SetID(snapshot.__elements[elementIndex]!, v);
98
+ __SetID(snapshot.__elements[elementIndex]!, v as string);
93
99
  } else if (key.startsWith('data-')) {
94
100
  // collected below
95
101
  } else if (key === 'ref') {
96
- snapshot.__ref_set ??= new Set();
97
102
  const fakeSnapshot = {
98
103
  __values: {
99
104
  get [index]() {
@@ -106,9 +111,8 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
106
111
  },
107
112
  __id: snapshot.__id,
108
113
  __elements: snapshot.__elements,
109
- __ref_set: snapshot.__ref_set,
110
114
  } as SnapshotInstance;
111
- updateRef(fakeSnapshot, index, oldValue[key], elementIndex, key);
115
+ updateRef(fakeSnapshot, index, oldValue[key] as string | null, elementIndex);
112
116
  } else if (key.endsWith(':ref')) {
113
117
  snapshot.__worklet_ref_set ??= new Set();
114
118
  const fakeSnapshot = {
@@ -121,7 +125,13 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
121
125
  __elements: snapshot.__elements,
122
126
  __worklet_ref_set: snapshot.__worklet_ref_set,
123
127
  } as SnapshotInstance;
124
- updateWorkletRef(fakeSnapshot, index, oldValue[key], elementIndex, key.slice(0, -4));
128
+ updateWorkletRef(
129
+ fakeSnapshot,
130
+ index,
131
+ oldValue[key] as WorkletRefImpl<Element> | Worklet | null | undefined,
132
+ elementIndex,
133
+ key.slice(0, -4),
134
+ );
125
135
  } else if (key.endsWith(':gesture')) {
126
136
  const workletType = key.slice(0, -8);
127
137
  const fakeSnapshot = {
@@ -189,7 +199,6 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
189
199
  } else if (key.startsWith('data-')) {
190
200
  // collected below
191
201
  } else if (key === 'ref') {
192
- snapshot.__ref_set ??= new Set();
193
202
  const fakeSnapshot = {
194
203
  __values: {
195
204
  get [index]() {
@@ -202,9 +211,8 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
202
211
  },
203
212
  __id: snapshot.__id,
204
213
  __elements: snapshot.__elements,
205
- __ref_set: snapshot.__ref_set,
206
214
  } as SnapshotInstance;
207
- updateRef(fakeSnapshot, index, oldValue[key], elementIndex, key);
215
+ updateRef(fakeSnapshot, index, oldValue[key] as string | null, elementIndex);
208
216
  } else if (key.endsWith(':ref')) {
209
217
  snapshot.__worklet_ref_set ??= new Set();
210
218
  const fakeSnapshot = {
@@ -217,7 +225,13 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
217
225
  __elements: snapshot.__elements,
218
226
  __worklet_ref_set: snapshot.__worklet_ref_set,
219
227
  } as SnapshotInstance;
220
- updateWorkletRef(fakeSnapshot, index, oldValue[key], elementIndex, key.slice(0, -4));
228
+ updateWorkletRef(
229
+ fakeSnapshot,
230
+ index,
231
+ oldValue[key] as WorkletRefImpl<Element> | Worklet | null | undefined,
232
+ elementIndex,
233
+ key.slice(0, -4),
234
+ );
221
235
  } else if (key.endsWith(':gesture')) {
222
236
  const workletType = key.slice(0, -8);
223
237
  const fakeSnapshot = {
@@ -247,7 +261,15 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
247
261
  __elements: snapshot.__elements,
248
262
  } as SnapshotInstance;
249
263
  if (workletType) {
250
- updateWorkletEvent(fakeSnapshot, index, oldValue[key], elementIndex, workletType, eventType, eventName);
264
+ updateWorkletEvent(
265
+ fakeSnapshot,
266
+ index,
267
+ oldValue[key] as Worklet,
268
+ elementIndex,
269
+ workletType,
270
+ eventType,
271
+ eventName,
272
+ );
251
273
  } else {
252
274
  updateEvent(fakeSnapshot, index, oldValue[key], elementIndex, eventType, eventName, key);
253
275
  }
@@ -284,8 +306,11 @@ function transformSpread(
284
306
  value ??= '';
285
307
  result['className'] = value;
286
308
  } else if (key === 'ref') {
287
- // @ts-ignore
288
- result[key] = transformRef(value)?.__ref;
309
+ if (__LEPUS__) {
310
+ result[key] = value ? 1 : undefined;
311
+ } else {
312
+ result[key] = transformRef(value)?.__ref;
313
+ }
289
314
  } else if (typeof value === 'function') {
290
315
  result[key] = `${snapshot.__id}:${index}:${key}`;
291
316
  } else {
@@ -4,8 +4,8 @@
4
4
  import { onWorkletCtxUpdate } from '@lynx-js/react/worklet-runtime/bindings';
5
5
  import type { Worklet } from '@lynx-js/react/worklet-runtime/bindings';
6
6
 
7
- import { SnapshotInstance } from '../snapshot.js';
8
7
  import { isMainThreadHydrationFinished } from '../lifecycle/patch/isMainThreadHydrationFinished.js';
8
+ import { SnapshotInstance } from '../snapshot.js';
9
9
 
10
10
  function updateWorkletEvent(
11
11
  snapshot: SnapshotInstance,
@@ -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
- import { runWorkletCtx, updateWorkletRef as update } from '@lynx-js/react/worklet-runtime/bindings';
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
- function workletUnRef(value: Worklet | WorkletRefImpl<Element>): void {
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,10 +40,10 @@ 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
- oldValue: WorkletRefImpl<Element> | Worklet | undefined,
46
+ oldValue: WorkletRefImpl<Element> | Worklet | null | undefined,
25
47
  elementIndex: number,
26
48
  _workletType: string,
27
49
  ): void {
@@ -38,11 +60,17 @@ function updateWorkletRef(
38
60
  if (value === null || value === undefined) {
39
61
  // do nothing
40
62
  } else if (value._wvid) {
41
- update(value as WorkletRefImpl<Element>, snapshot.__elements[elementIndex]!);
63
+ const element = snapshot.__elements[elementIndex]! as Element;
64
+ addToRefQueue(value as Worklet, element);
42
65
  } else if ((value as Worklet)._wkltId) {
43
- (value as Worklet)._unmount = runWorkletCtx(value as Worklet, [{
44
- elementRefptr: (snapshot.__elements[elementIndex]!) as any,
45
- }]) as () => void;
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 };
@@ -18,28 +18,19 @@ import type { Worklet, WorkletRefImpl } from '@lynx-js/react/worklet-runtime/bin
18
18
 
19
19
  import type { BackgroundSnapshotInstance } from './backgroundSnapshot.js';
20
20
  import { SnapshotOperation, __globalSnapshotPatch } from './lifecycle/patch/snapshotPatch.js';
21
- import { ListUpdateInfoRecording, __pendingListUpdates, snapshotDestroyList } from './list.js';
21
+ import { ListUpdateInfoRecording } from './listUpdateInfo.js';
22
+ import { __pendingListUpdates } from './pendingListUpdates.js';
23
+ import { DynamicPartType } from './snapshot/dynamicPartType.js';
24
+ import { snapshotDestroyList } from './snapshot/list.js';
25
+ import type { PlatformInfo } from './snapshot/platformInfo.js';
22
26
  import { unref } from './snapshot/ref.js';
23
27
  import { isDirectOrDeepEqual } from './utils.js';
24
28
 
25
- /**
26
- * Types of dynamic parts that can be updated in a snapshot
27
- * These are determined at compile time through static analysis
28
- */
29
- export const enum DynamicPartType {
30
- Attr = 0, // Regular attribute updates
31
- Spread, // Spread operator in JSX
32
- Slot, // Slot for component children
33
- Children, // Regular children updates
34
- ListChildren, // List/array children updates
35
- MultiChildren, // Multiple children updates (compat layer)
36
- }
37
-
38
29
  /**
39
30
  * A snapshot definition that contains all the information needed to create and update elements
40
31
  * This is generated at compile time through static analysis of the JSX
41
32
  */
42
- interface Snapshot {
33
+ export interface Snapshot {
43
34
  create: null | ((ctx: SnapshotInstance) => FiberElement[]);
44
35
  update: null | ((ctx: SnapshotInstance, index: number, oldValue: any) => void)[];
45
36
  slot: [DynamicPartType, number][];
@@ -47,6 +38,7 @@ interface Snapshot {
47
38
  isListHolder?: boolean;
48
39
  cssId?: number | undefined;
49
40
  entryName?: string | undefined;
41
+ refAndSpreadIndexes?: number[] | null;
50
42
  }
51
43
 
52
44
  export let __page: FiberElement;
@@ -166,7 +158,7 @@ export const backgroundSnapshotInstanceManager: {
166
158
  if (!res || (res.length != 2 && res.length != 3)) {
167
159
  throw new Error('Invalid ctx format: ' + str);
168
160
  }
169
- let id = Number(res[0]);
161
+ const id = Number(res[0]);
170
162
  const expIndex = Number(res[1]);
171
163
  const ctx = this.values.get(id);
172
164
  if (!ctx) {
@@ -174,7 +166,7 @@ export const backgroundSnapshotInstanceManager: {
174
166
  }
175
167
  const spreadKey = res[2];
176
168
  if (spreadKey) {
177
- return ctx.__values![expIndex][spreadKey];
169
+ return (ctx.__values![expIndex] as { [spreadKey]: unknown })[spreadKey];
178
170
  } else {
179
171
  return ctx.__values![expIndex];
180
172
  }
@@ -190,8 +182,9 @@ export function createSnapshot(
190
182
  create: Snapshot['create'] | null,
191
183
  update: Snapshot['update'] | null,
192
184
  slot: Snapshot['slot'],
193
- cssId?: number,
194
- entryName?: string,
185
+ cssId: number | undefined,
186
+ entryName: string | undefined,
187
+ refAndSpreadIndexes: number[] | null,
195
188
  ): string {
196
189
  if (
197
190
  __DEV__ && __JS__
@@ -221,7 +214,7 @@ export function createSnapshot(
221
214
 
222
215
  uniqID = entryUniqID(uniqID, entryName);
223
216
 
224
- const s: Snapshot = { create, update, slot, cssId, entryName };
217
+ const s: Snapshot = { create, update, slot, cssId, entryName, refAndSpreadIndexes };
225
218
  snapshotManager.values.set(uniqID, s);
226
219
  if (slot && slot[0] && slot[0][0] === DynamicPartType.ListChildren) {
227
220
  s.isListHolder = true;
@@ -266,16 +259,19 @@ export class SnapshotInstance {
266
259
  __snapshot_def: Snapshot;
267
260
  __elements?: FiberElement[] | undefined;
268
261
  __element_root?: FiberElement | undefined;
269
- __values?: any[] | undefined;
262
+ __values?: unknown[] | undefined;
270
263
  __current_slot_index = 0;
271
- __ref_set?: Set<string>;
272
264
  __worklet_ref_set?: Set<WorkletRefImpl<any> | Worklet>;
273
- __listItemPlatformInfo?: any;
265
+ __listItemPlatformInfo?: PlatformInfo;
274
266
 
275
267
  constructor(public type: string, id?: number) {
276
268
  this.__snapshot_def = snapshotManager.values.get(type)!;
269
+ // Suspense uses 'div'
270
+ if (!this.__snapshot_def && type !== 'div') {
271
+ throw new Error('Snapshot not found: ' + type);
272
+ }
277
273
 
278
- id ||= snapshotInstanceManager.nextId -= 1;
274
+ id ??= snapshotInstanceManager.nextId -= 1;
279
275
  this.__id = id;
280
276
  snapshotInstanceManager.values.set(id, this);
281
277
  }
@@ -291,15 +287,15 @@ export class SnapshotInstance {
291
287
  // CSS Scope is removed(We only need to call `__SetCSSId` when there is `entryName`)
292
288
  // Or an old bundle(`__SetCSSId` is called in `create`), we skip calling `__SetCSSId`
293
289
  if (entryName !== DEFAULT_ENTRY_NAME && entryName !== undefined) {
294
- __SetCSSId(this.__elements!, DEFAULT_CSS_ID, entryName);
290
+ __SetCSSId(this.__elements, DEFAULT_CSS_ID, entryName);
295
291
  }
296
292
  } else {
297
293
  // cssId !== undefined
298
294
  if (entryName !== DEFAULT_ENTRY_NAME && entryName !== undefined) {
299
295
  // For lazy bundle, we need add `entryName` to the third params
300
- __SetCSSId(this.__elements!, cssId, entryName);
296
+ __SetCSSId(this.__elements, cssId, entryName);
301
297
  } else {
302
- __SetCSSId(this.__elements!, cssId);
298
+ __SetCSSId(this.__elements, cssId);
303
299
  }
304
300
  }
305
301
 
@@ -388,6 +384,14 @@ export class SnapshotInstance {
388
384
  return a;
389
385
  }
390
386
 
387
+ tearDown(): void {
388
+ traverseSnapshotInstance(this, v => {
389
+ v.__parent = null;
390
+ v.__previousSibling = null;
391
+ v.__nextSibling = null;
392
+ });
393
+ }
394
+
391
395
  // onCreate?: () => void;
392
396
  // onAttach?: () => void;
393
397
  // onDetach?: () => void;
@@ -539,26 +543,22 @@ export class SnapshotInstance {
539
543
  }
540
544
 
541
545
  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
546
  const __snapshot_def = this.__snapshot_def;
551
547
  if (__snapshot_def.isListHolder) {
552
548
  (__pendingListUpdates.values[this.__id] ??= new ListUpdateInfoRecording(
553
549
  this,
554
550
  )).onRemoveChild(child);
555
- r();
551
+
552
+ this.__removeChild(child);
553
+ traverseSnapshotInstance(child, v => {
554
+ snapshotInstanceManager.values.delete(v.__id);
555
+ });
556
+ // mark this child as deleted
557
+ child.__id = 0;
556
558
  return;
557
559
  }
558
560
 
559
- // TODO: ref: can this be done on the background thread?
560
561
  unref(child, true);
561
- r();
562
562
  if (this.__elements) {
563
563
  const [, elementIndex] = __snapshot_def.slot[0]!;
564
564
  __RemoveElement(this.__elements[elementIndex]!, child.__element_root!);
@@ -567,26 +567,30 @@ export class SnapshotInstance {
567
567
  if (child.__snapshot_def.isListHolder) {
568
568
  snapshotDestroyList(child);
569
569
  }
570
+
571
+ this.__removeChild(child);
572
+ traverseSnapshotInstance(child, v => {
573
+ v.__parent = null;
574
+ v.__previousSibling = null;
575
+ v.__nextSibling = null;
576
+ delete v.__elements;
577
+ delete v.__element_root;
578
+ snapshotInstanceManager.values.delete(v.__id);
579
+ });
570
580
  }
571
581
 
572
582
  setAttribute(key: string | number, value: any): void {
573
- const helper = (index: number, oldValue: any, newValue: any) => {
574
- if (isDirectOrDeepEqual(oldValue, newValue)) {}
575
- else {
576
- this.__snapshot_def.update![index]!(this, index, oldValue);
577
- }
578
- };
579
-
580
583
  if (key === 'values') {
581
584
  const oldValues = this.__values;
582
- this.__values = value;
585
+ const values = value as unknown[];
586
+ this.__values = values;
583
587
  if (oldValues) {
584
- for (let index = 0; index < value.length; index++) {
585
- helper(index, oldValues[index], value[index]);
588
+ for (let index = 0; index < values.length; index++) {
589
+ this.callUpdateIfNotDirectOrDeepEqual(index, oldValues[index], values[index]);
586
590
  }
587
591
  } else {
588
- for (let index = 0; index < value.length; index++) {
589
- helper(index, undefined, value[index]);
592
+ for (let index = 0; index < values.length; index++) {
593
+ this.callUpdateIfNotDirectOrDeepEqual(index, undefined, values[index]);
590
594
  }
591
595
  }
592
596
  return;
@@ -594,7 +598,7 @@ export class SnapshotInstance {
594
598
 
595
599
  const index = typeof key === 'string' ? Number(key.slice(2)) : key;
596
600
  this.__values ??= [];
597
- helper(index, this.__values[index], this.__values[index] = value);
601
+ this.callUpdateIfNotDirectOrDeepEqual(index, this.__values[index], this.__values[index] = value);
598
602
  }
599
603
 
600
604
  toJSON(): Omit<SerializedSnapshotInstance, 'children'> & { children: SnapshotInstance[] | undefined } {
@@ -605,4 +609,11 @@ export class SnapshotInstance {
605
609
  children: this.__firstChild ? this.childNodes : undefined,
606
610
  };
607
611
  }
612
+
613
+ callUpdateIfNotDirectOrDeepEqual(index: number, oldValue: any, newValue: any): void {
614
+ if (isDirectOrDeepEqual(oldValue, newValue)) {}
615
+ else {
616
+ this.__snapshot_def.update![index]!(this, index, oldValue);
617
+ }
618
+ }
608
619
  }
@@ -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<number, number>();
13
+
14
+ /**
15
+ * @internal
16
+ */
17
+ export { hydrationMap };
@@ -14,7 +14,7 @@ export function isDirectOrDeepEqual(a: any, b: any): boolean {
14
14
  }
15
15
 
16
16
  export function isEmptyObject(obj?: object): obj is Record<string, never> {
17
- for (var _ in obj) return false;
17
+ for (const _ in obj) return false;
18
18
  return true;
19
19
  }
20
20
 
@@ -25,11 +25,11 @@ export function isSdkVersionGt(major: number, minor: number): boolean {
25
25
  }
26
26
 
27
27
  export function pick<T extends object, K extends keyof T>(obj: T, keys: Iterable<K>): Pick<T, K> {
28
- const result: any = {};
28
+ const result: Partial<Pick<T, K>> = {};
29
29
  for (const key of keys) {
30
30
  if (key in obj) {
31
31
  result[key] = obj[key];
32
32
  }
33
33
  }
34
- return result;
34
+ return result as Pick<T, K>;
35
35
  }
@@ -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
1
  import { builtinEnvironments } from "vitest/environments";
2
- import external_events_default from "events";
2
+ import events 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.cssText = styles;
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 external_events_default();
324
+ const ee = new events();
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 external_events_default();
431
+ const globalEventEmitter = new events();
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`);
@@ -14413,9 +14413,10 @@ function __webpack_require__(moduleId) {
14413
14413
  };
14414
14414
  })();
14415
14415
  var dom_esm = __webpack_require__("../../../node_modules/.pnpm/@testing-library+dom@10.4.0/node_modules/@testing-library/dom/dist/@testing-library/dom.esm.js");
14416
- let NodesRef = lynx.createSelectorQuery().selectUniqueID(-1).constructor;
14416
+ const NodesRef = lynx.createSelectorQuery().selectUniqueID(-1).constructor;
14417
14417
  function getElement(elemOrNodesRef) {
14418
14418
  if (elemOrNodesRef instanceof NodesRef) return __GetElementByUniqueId(Number(elemOrNodesRef._nodeSelectToken.identifier));
14419
+ if ('refAttr' in elemOrNodesRef) return document.querySelector(`[react-ref-${elemOrNodesRef.refAttr[0]}-${elemOrNodesRef.refAttr[1]}]`);
14419
14420
  if (elemOrNodesRef?.constructor?.name === 'HTMLUnknownElement') return elemOrNodesRef;
14420
14421
  throw new Error('Invalid element, got: ' + elemOrNodesRef.constructor?.name);
14421
14422
  }
@@ -14423,7 +14424,7 @@ const fireEvent = (elemOrNodesRef, ...args)=>{
14423
14424
  const isMainThread = __MAIN_THREAD__;
14424
14425
  lynxTestingEnv.switchToBackgroundThread();
14425
14426
  const elem = getElement(elemOrNodesRef);
14426
- let ans = (0, dom_esm.BX)(elem, ...args);
14427
+ const ans = (0, dom_esm.BX)(elem, ...args);
14427
14428
  if (isMainThread) lynxTestingEnv.switchToMainThread();
14428
14429
  return ans;
14429
14430
  };
@@ -14542,7 +14543,7 @@ Object.keys(eventMap).forEach((key)=>{
14542
14543
  const isMainThread = __MAIN_THREAD__;
14543
14544
  lynxTestingEnv.switchToBackgroundThread();
14544
14545
  const elem = getElement(elemOrNodesRef);
14545
- const eventType = init?.['eventType'] || 'bindEvent';
14546
+ const eventType = init?.eventType || 'bindEvent';
14546
14547
  init = {
14547
14548
  eventType,
14548
14549
  eventName: key,