@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
@@ -4,6 +4,7 @@
4
4
  import { render } from 'preact';
5
5
 
6
6
  import { LifecycleConstant, NativeUpdateDataType } from '../lifecycleConstant.js';
7
+ import type { FirstScreenData } from '../lifecycleConstant.js';
7
8
  import {
8
9
  PerformanceTimingFlags,
9
10
  PerformanceTimingKeys,
@@ -18,17 +19,18 @@ import { delayedEvents, delayedPublishEvent } from '../lifecycle/event/delayEven
18
19
  import { delayLifecycleEvent, delayedLifecycleEvents } from '../lifecycle/event/delayLifecycleEvents.js';
19
20
  import { commitPatchUpdate, genCommitTaskId, globalCommitTaskMap } from '../lifecycle/patch/commit.js';
20
21
  import type { PatchList } from '../lifecycle/patch/commit.js';
22
+ import { removeCtxNotFoundEventListener } from '../lifecycle/patch/error.js';
23
+ import { runDelayedUiOps } from '../lifecycle/ref/delay.js';
21
24
  import { reloadBackground } from '../lifecycle/reload.js';
22
25
  import { CHILDREN } from '../renderToOpcodes/constants.js';
23
26
  import { __root } from '../root.js';
24
- import { globalRefsToSet, updateBackgroundRefs } from '../snapshot/ref.js';
25
27
  import { backgroundSnapshotInstanceManager } from '../snapshot.js';
28
+ import type { SerializedSnapshotInstance } from '../snapshot.js';
26
29
  import { destroyWorklet } from '../worklet/destroy.js';
27
30
 
28
31
  export { runWithForce };
29
32
 
30
33
  function injectTt(): void {
31
- // @ts-ignore
32
34
  const tt = lynxCoreInject.tt;
33
35
  tt.OnLifecycleEvent = onLifecycleEvent;
34
36
  tt.publishEvent = delayedPublishEvent;
@@ -36,6 +38,7 @@ function injectTt(): void {
36
38
  tt.callDestroyLifetimeFun = () => {
37
39
  destroyWorklet();
38
40
  destroyBackground();
41
+ removeCtxNotFoundEventListener();
39
42
  };
40
43
  tt.updateGlobalProps = updateGlobalProps;
41
44
  tt.updateCardData = updateCardData;
@@ -45,7 +48,7 @@ function injectTt(): void {
45
48
  };
46
49
  }
47
50
 
48
- function onLifecycleEvent([type, data]: [string, any]) {
51
+ function onLifecycleEvent([type, data]: [LifecycleConstant, unknown]) {
49
52
  const hasRootRendered = CHILDREN in __root;
50
53
  // never called `render(<App/>, __root)`
51
54
  // happens if user call `root.render()` async
@@ -69,16 +72,16 @@ function onLifecycleEvent([type, data]: [string, any]) {
69
72
  }
70
73
  }
71
74
 
72
- function onLifecycleEventImpl(type: string, data: any): void {
75
+ function onLifecycleEventImpl(type: LifecycleConstant, data: unknown): void {
73
76
  switch (type) {
74
77
  case LifecycleConstant.firstScreen: {
75
- const { root: lepusSide, refPatch, jsReadyEventIdSwap } = data;
78
+ const { root: lepusSide, jsReadyEventIdSwap } = data as FirstScreenData;
76
79
  if (__PROFILE__) {
77
80
  console.profile('hydrate');
78
81
  }
79
82
  beginPipeline(true, PipelineOrigins.reactLynxHydrate, PerformanceTimingFlags.reactLynxHydrate);
80
83
  markTiming(PerformanceTimingKeys.hydrateParseSnapshotStart);
81
- const before = JSON.parse(lepusSide);
84
+ const before = JSON.parse(lepusSide) as SerializedSnapshotInstance;
82
85
  markTiming(PerformanceTimingKeys.hydrateParseSnapshotEnd);
83
86
  markTiming(PerformanceTimingKeys.diffVdomStart);
84
87
  const snapshotPatch = hydrate(
@@ -95,8 +98,9 @@ function onLifecycleEventImpl(type: string, data: any): void {
95
98
  if (delayedEvents) {
96
99
  delayedEvents.forEach((args) => {
97
100
  const [handlerName, data] = args;
101
+ // eslint-disable-next-line prefer-const
98
102
  let [idStr, ...rest] = handlerName.split(':');
99
- while (jsReadyEventIdSwap[idStr!]) idStr = jsReadyEventIdSwap[idStr!];
103
+ while (jsReadyEventIdSwap[idStr!]) idStr = jsReadyEventIdSwap[idStr!]?.toString();
100
104
  try {
101
105
  publishEvent([idStr, ...rest].join(':'), data);
102
106
  } catch (e) {
@@ -109,16 +113,6 @@ function onLifecycleEventImpl(type: string, data: any): void {
109
113
  lynxCoreInject.tt.publishEvent = publishEvent;
110
114
  lynxCoreInject.tt.publicComponentEvent = publicComponentEvent;
111
115
 
112
- if (__PROFILE__) {
113
- console.profile('patchRef');
114
- }
115
- if (refPatch) {
116
- globalRefsToSet.set(0, JSON.parse(refPatch));
117
- updateBackgroundRefs(0);
118
- }
119
- if (__PROFILE__) {
120
- console.profileEnd();
121
- }
122
116
  // console.debug("********** After hydration:");
123
117
  // printSnapshotInstance(__root as BackgroundSnapshotInstance);
124
118
  if (__PROFILE__) {
@@ -131,7 +125,6 @@ function onLifecycleEventImpl(type: string, data: any): void {
131
125
  const obj = commitPatchUpdate(patchList, { isHydration: true });
132
126
 
133
127
  lynx.getNativeApp().callLepusMethod(LifecycleConstant.patchUpdate, obj, () => {
134
- updateBackgroundRefs(commitTaskId);
135
128
  globalCommitTaskMap.forEach((commitTask, id) => {
136
129
  if (id > commitTaskId) {
137
130
  return;
@@ -140,23 +133,14 @@ function onLifecycleEventImpl(type: string, data: any): void {
140
133
  globalCommitTaskMap.delete(id);
141
134
  });
142
135
  });
136
+ runDelayedUiOps();
143
137
  break;
144
138
  }
145
139
  case LifecycleConstant.globalEventFromLepus: {
146
- const [eventName, params] = data;
140
+ const [eventName, params] = data as [string, Record<string, any>];
147
141
  lynx.getJSModule('GlobalEventEmitter').trigger(eventName, params);
148
142
  break;
149
143
  }
150
- case LifecycleConstant.ref: {
151
- const { refPatch, commitTaskId } = data;
152
- if (commitTaskId) {
153
- globalRefsToSet.set(commitTaskId, JSON.parse(refPatch));
154
- } else {
155
- globalRefsToSet.set(0, JSON.parse(refPatch));
156
- updateBackgroundRefs(0);
157
- }
158
- break;
159
- }
160
144
  }
161
145
  }
162
146
 
@@ -175,14 +159,13 @@ function flushDelayedLifecycleEvents(): void {
175
159
  }
176
160
 
177
161
  function publishEvent(handlerName: string, data: unknown) {
178
- // TODO: delay js events until js ready
179
162
  lynxCoreInject.tt.callBeforePublishEvent?.(data);
180
163
  const eventHandler = backgroundSnapshotInstanceManager.getValueBySign(
181
164
  handlerName,
182
165
  );
183
166
  if (eventHandler) {
184
167
  try {
185
- (eventHandler as Function)(data);
168
+ (eventHandler as (...args: unknown[]) => void)(data);
186
169
  } catch (e) {
187
170
  lynx.reportError(e as Error);
188
171
  }
@@ -204,10 +187,11 @@ function updateGlobalProps(newData: Record<string, any>): void {
204
187
  // can be batched with updateFromRoot
205
188
  // This is already done because updateFromRoot will consume all dirty flags marked by
206
189
  // the setState, and setState's flush will be a noop. No extra diffs will be needed.
207
- Promise.resolve().then(() => {
190
+ void Promise.resolve().then(() => {
191
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
208
192
  runWithForce(() => render(__root.__jsx, __root as any));
209
193
  });
210
- lynxCoreInject.tt.GlobalEventEmitter.emit('onGlobalPropsChanged');
194
+ lynxCoreInject.tt.GlobalEventEmitter.emit('onGlobalPropsChanged', undefined);
211
195
  }
212
196
 
213
197
  function updateCardData(newData: Record<string, any>, options?: Record<string, any>): void {
@@ -219,16 +203,14 @@ function updateCardData(newData: Record<string, any>, options?: Record<string, a
219
203
  ),
220
204
  );
221
205
  }
222
- const { type = NativeUpdateDataType.UPDATE } = options || {};
206
+ const { type = NativeUpdateDataType.UPDATE } = options ?? {};
223
207
  if (type == NativeUpdateDataType.RESET) {
224
- // @ts-ignore
225
208
  lynx.__initData = {};
226
209
  }
227
210
 
228
211
  // COW when modify `lynx.__initData` to make sure Provider & Consumer works
229
- // @ts-ignore
230
212
  lynx.__initData = Object.assign({}, lynx.__initData, restNewData);
231
- lynxCoreInject.tt.GlobalEventEmitter.emit('onDataChanged');
213
+ lynxCoreInject.tt.GlobalEventEmitter.emit('onDataChanged', undefined);
232
214
  }
233
215
 
234
216
  export { injectTt, flushDelayedLifecycleEvents };
@@ -86,6 +86,7 @@ export const root: Root = {
86
86
  __root.__jsx = jsx;
87
87
  } else {
88
88
  __root.__jsx = jsx;
89
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
89
90
  render(jsx, __root as any);
90
91
  if (__FIRST_SCREEN_SYNC_TIMING__ === 'immediately') {
91
92
  // This is for cases where `root.render()` is called asynchronously,
@@ -107,7 +108,7 @@ const _InitData = /* @__PURE__ */ factory<InitData>(
107
108
  useState,
108
109
  createElement,
109
110
  useLynxGlobalEventListener,
110
- } as any,
111
+ },
111
112
  '__initData',
112
113
  'onDataChanged',
113
114
  );
@@ -137,6 +138,7 @@ const _InitData = /* @__PURE__ */ factory<InitData>(
137
138
  *
138
139
  * @public
139
140
  */
141
+ // @ts-expect-error make preact and react types work
140
142
  export const InitDataProvider: FC<{ children?: ReactNode | undefined }> = /* @__PURE__ */ _InitData.Provider();
141
143
  /**
142
144
  * The {@link https://react.dev/reference/react/createContext#consumer | Consumer} Component that provide `initData`.
@@ -144,6 +146,7 @@ export const InitDataProvider: FC<{ children?: ReactNode | undefined }> = /* @__
144
146
  * @group Components
145
147
  * @public
146
148
  */
149
+ // @ts-expect-error make preact and react types work
147
150
  export const InitDataConsumer: Consumer<InitData> = /* @__PURE__ */ _InitData.Consumer();
148
151
  /**
149
152
  * A React Hooks for you to get `initData`.
@@ -235,7 +238,7 @@ export interface DataProcessorDefinition {
235
238
  *
236
239
  * @public
237
240
  */
238
- dataProcessors?: Record<string, Function>;
241
+ dataProcessors?: Record<string, ((rawInitData: InitDataRaw) => InitData)>;
239
242
  }
240
243
 
241
244
  /**
@@ -7,14 +7,15 @@ import './hooks/react.js';
7
7
 
8
8
  import { initProfileHook } from './debug/profile.js';
9
9
  import { document, setupBackgroundDocument } from './document.js';
10
- import { initDelayUnmount } from './lifecycle/delayUnmount.js';
11
- import { replaceCommitHook, replaceRequestAnimationFrame } from './lifecycle/patch/commit.js';
10
+ import { replaceCommitHook } from './lifecycle/patch/commit.js';
11
+ import { addCtxNotFoundEventListener } from './lifecycle/patch/error.js';
12
12
  import { injectUpdateMainThread } from './lifecycle/patch/updateMainThread.js';
13
13
  import { injectCalledByNative } from './lynx/calledByNative.js';
14
- import { setupLynxTestingEnv } from './lynx/env.js';
14
+ import { setupLynxEnv } from './lynx/env.js';
15
15
  import { injectLepusMethods } from './lynx/injectLepusMethods.js';
16
16
  import { initTimingAPI } from './lynx/performance.js';
17
17
  import { injectTt } from './lynx/tt.js';
18
+
18
19
  export { runWithForce } from './lynx/runWithForce.js';
19
20
 
20
21
  // @ts-expect-error Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature
@@ -41,17 +42,17 @@ if (__PROFILE__) {
41
42
 
42
43
  if (__BACKGROUND__) {
43
44
  // Trick Preact and TypeScript to accept our custom document adapter.
45
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
44
46
  options.document = document as any;
45
47
  setupBackgroundDocument();
46
48
  injectTt();
49
+ addCtxNotFoundEventListener();
47
50
 
48
51
  if (process.env['NODE_ENV'] === 'test') {}
49
52
  else {
50
53
  replaceCommitHook();
51
- replaceRequestAnimationFrame();
52
54
  initTimingAPI();
53
- initDelayUnmount();
54
55
  }
55
56
  }
56
57
 
57
- setupLynxTestingEnv();
58
+ setupLynxEnv();
@@ -1,6 +1,7 @@
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 { hydrate } from './hydrate.js';
4
5
  import { componentAtIndexFactory, enqueueComponentFactory, gRecycleMap, gSignMap } from './list.js';
5
6
  import { CHILDREN } from './renderToOpcodes/constants.js';
6
7
  import { SnapshotInstance } from './snapshot.js';
@@ -52,7 +53,7 @@ export function ssrHydrateByOpcodes(
52
53
  const signMap = gSignMap[listElementUniqueID] = new Map();
53
54
  gRecycleMap[listElementUniqueID] = new Map();
54
55
  const enqueueFunc = enqueueComponentFactory();
55
- const [componentAtIndex, componentAtIndexes] = componentAtIndexFactory(top.childNodes);
56
+ const [componentAtIndex, componentAtIndexes] = componentAtIndexFactory(top.childNodes, hydrate);
56
57
  for (const child of top.childNodes) {
57
58
  if (child.__element_root) {
58
59
  const childElementUniqueID = __GetElementUniqueID(child.__element_root);
@@ -0,0 +1,18 @@
1
+ // Copyright 2025 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 { ListUpdateInfo } from './listUpdateInfo.js';
6
+
7
+ export const __pendingListUpdates = {
8
+ values: {} as Record<number, ListUpdateInfo>,
9
+ clear(): void {
10
+ this.values = {};
11
+ },
12
+ flush(): void {
13
+ Object.values(this.values).forEach(update => {
14
+ update.flush();
15
+ });
16
+ this.clear();
17
+ },
18
+ };
@@ -97,9 +97,9 @@ export const __OpText = 3;
97
97
  * @param {Record<string, unknown>} context
98
98
  */
99
99
  function renderClassComponent(vnode, context) {
100
- let type = /** @type {import("preact").ComponentClass<typeof vnode.props>} */ (vnode.type);
100
+ const type = /** @type {import("preact").ComponentClass<typeof vnode.props>} */ (vnode.type);
101
101
 
102
- let c = new type(vnode.props, context);
102
+ const c = new type(vnode.props, context);
103
103
 
104
104
  vnode[COMPONENT] = c;
105
105
  c[VNODE] = vnode;
@@ -162,7 +162,7 @@ function _renderToString(
162
162
  if (isArray(vnode)) {
163
163
  parent[CHILDREN] = vnode;
164
164
  for (let i = 0; i < vnode.length; i++) {
165
- let child = vnode[i];
165
+ const child = vnode[i];
166
166
  if (child == null || typeof child === 'boolean') continue;
167
167
 
168
168
  _renderToString(child, context, isSvgMode, selectValue, parent, opcodes);
@@ -190,7 +190,7 @@ function _renderToString(
190
190
  } else {
191
191
  contextType = type.contextType;
192
192
  if (contextType != null) {
193
- let provider = context[contextType.__c];
193
+ const provider = context[contextType.__c];
194
194
  cctx = provider ? provider.props.value : contextType.__;
195
195
  }
196
196
 
@@ -236,7 +236,7 @@ function _renderToString(
236
236
 
237
237
  // When a component returns a Fragment node we flatten it in core, so we
238
238
  // need to mirror that logic here too
239
- let isTopLevelFragment = rendered != null && rendered.type === Fragment
239
+ const isTopLevelFragment = rendered != null && rendered.type === Fragment
240
240
  && rendered.key == null;
241
241
  rendered = isTopLevelFragment ? rendered.props.children : rendered;
242
242
 
@@ -254,8 +254,8 @@ function _renderToString(
254
254
 
255
255
  opcodes.push(__OpBegin, vnode);
256
256
 
257
- for (let name in props) {
258
- let v = props[name];
257
+ for (const name in props) {
258
+ const v = props[name];
259
259
 
260
260
  switch (name) {
261
261
  case 'children':
@@ -0,0 +1,16 @@
1
+ // Copyright 2025 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
+ * Types of dynamic parts that can be updated in a snapshot
7
+ * These are determined at compile time through static analysis
8
+ */
9
+ export const enum DynamicPartType {
10
+ Attr = 0, // Regular attribute updates
11
+ Spread, // Spread operator in JSX
12
+ Slot, // Slot for component children
13
+ Children, // Regular children updates
14
+ ListChildren, // List/array children updates
15
+ MultiChildren, // Multiple children updates (compat layer)
16
+ }
@@ -1,3 +1,6 @@
1
+ // Copyright 2025 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.
1
4
  import { processGesture } from '../gesture/processGesture.js';
2
5
  import type { GestureKind } from '../gesture/types.js';
3
6
  import { isMainThreadHydrationFinished } from '../lifecycle/patch/isMainThreadHydrationFinished.js';
@@ -0,0 +1,36 @@
1
+ // Copyright 2025 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 { hydrate } from '../hydrate.js';
6
+ import { componentAtIndexFactory, enqueueComponentFactory, gRecycleMap, gSignMap } from '../list.js';
7
+ import type { SnapshotInstance } from '../snapshot.js';
8
+
9
+ export function snapshotCreateList(
10
+ pageId: number,
11
+ _ctx: SnapshotInstance,
12
+ _expIndex: number,
13
+ ): FiberElement {
14
+ const signMap = new Map<number, SnapshotInstance>();
15
+ const recycleMap = new Map<string, Map<number, SnapshotInstance>>();
16
+ const [componentAtIndex, componentAtIndexes] = componentAtIndexFactory([], hydrate);
17
+ const list = __CreateList(
18
+ pageId,
19
+ componentAtIndex,
20
+ enqueueComponentFactory(),
21
+ {},
22
+ componentAtIndexes,
23
+ );
24
+ const listID = __GetElementUniqueID(list);
25
+ gSignMap[listID] = signMap;
26
+ gRecycleMap[listID] = recycleMap;
27
+ return list;
28
+ }
29
+
30
+ export function snapshotDestroyList(si: SnapshotInstance): void {
31
+ const [, elementIndex] = si.__snapshot_def.slot[0]!;
32
+ const list = si.__elements![elementIndex]!;
33
+ const listID = __GetElementUniqueID(list);
34
+ delete gSignMap[listID];
35
+ delete gRecycleMap[listID];
36
+ }
@@ -1,4 +1,8 @@
1
- import { __pendingListUpdates, ListUpdateInfoRecording } from '../list.js';
1
+ // Copyright 2025 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
+ import { ListUpdateInfoRecording } from '../listUpdateInfo.js';
5
+ import { __pendingListUpdates } from '../pendingListUpdates.js';
2
6
  import { SnapshotInstance } from '../snapshot.js';
3
7
 
4
8
  const platformInfoVirtualAttributes: Set<string> = /* @__PURE__ */ new Set<string>(['reuse-identifier']);
@@ -13,16 +17,26 @@ const platformInfoAttributes: Set<string> = /* @__PURE__ */ new Set<string>([
13
17
  'estimated-main-axis-size-px',
14
18
  ]);
15
19
 
20
+ export interface PlatformInfo {
21
+ 'reuse-identifier'?: string;
22
+ 'full-span'?: boolean;
23
+ 'item-key'?: string;
24
+ 'sticky-top'?: boolean;
25
+ 'sticky-bottom'?: boolean;
26
+ 'estimated-height'?: number;
27
+ 'estimated-height-px'?: number;
28
+ 'estimated-main-axis-size-px'?: number;
29
+ }
30
+
16
31
  function updateListItemPlatformInfo(
17
32
  ctx: SnapshotInstance,
18
33
  index: number,
19
34
  oldValue: any,
20
35
  elementIndex: number,
21
36
  ): void {
22
- const newValue = ctx.__listItemPlatformInfo = ctx.__values![index];
37
+ const newValue = ctx.__listItemPlatformInfo = ctx.__values![index] as PlatformInfo;
23
38
 
24
- // @ts-ignore
25
- const list = ctx.__parent;
39
+ const list = ctx.parentNode;
26
40
  if (list?.__snapshot_def.isListHolder) {
27
41
  (__pendingListUpdates.values[list.__id] ??= new ListUpdateInfoRecording(list)).onSetAttribute(
28
42
  ctx,
@@ -35,7 +49,7 @@ function updateListItemPlatformInfo(
35
49
  // No adding / removing keys.
36
50
  if (ctx.__elements) {
37
51
  const e = ctx.__elements[elementIndex]!;
38
- const value = ctx.__values![index];
52
+ const value = ctx.__values![index] as Record<string, unknown>;
39
53
  for (const k in value) {
40
54
  if (platformInfoVirtualAttributes.has(k)) {
41
55
  continue;
@@ -3,21 +3,19 @@
3
3
  // LICENSE file in the root directory of this source tree.
4
4
  import type { Element, Worklet, WorkletRefImpl } from '@lynx-js/react/worklet-runtime/bindings';
5
5
 
6
- import { nextCommitTaskId } from '../lifecycle/patch/commit.js';
7
- import { SnapshotInstance, backgroundSnapshotInstanceManager } from '../snapshot.js';
6
+ import type { SnapshotInstance } from '../snapshot.js';
8
7
  import { workletUnRef } from './workletRef.js';
8
+ import { RefProxy } from '../lifecycle/ref/delay.js';
9
9
 
10
- let globalRefPatch: Record<string, number | null> = {};
11
- const globalRefsToRemove: Map</* commitId */ number, Map</* sign */ string, /* ref */ any>> = /* @__PURE__ */ new Map();
12
- const globalRefsToSet: Map</* commitId */ number, Record<string, number>> = /* @__PURE__ */ new Map();
13
- let nextRefId = 1;
10
+ const refsToClear: Ref[] = [];
11
+ const refsToApply: (Ref | [snapshotInstanceId: number, expIndex: number])[] = [];
14
12
 
15
- function unref(snapshot: SnapshotInstance, recursive: boolean): void {
16
- snapshot.__ref_set?.forEach(v => {
17
- globalRefPatch[v] = null;
18
- });
19
- snapshot.__ref_set?.clear();
13
+ type Ref = (((ref: RefProxy) => () => void) | { current: RefProxy | null }) & {
14
+ _unmount?: () => void;
15
+ __ref?: { value: number };
16
+ };
20
17
 
18
+ function unref(snapshot: SnapshotInstance, recursive: boolean): void {
21
19
  snapshot.__worklet_ref_set?.forEach(v => {
22
20
  if (v) {
23
21
  workletUnRef(v as Worklet | WorkletRefImpl<Element>);
@@ -32,91 +30,65 @@ function unref(snapshot: SnapshotInstance, recursive: boolean): void {
32
30
  }
33
31
  }
34
32
 
35
- function applyRef(ref: any, value: any) {
36
- // TODO: ref: exceptions thrown in user functions should be able to be caught by an Error Boundary
37
- if (typeof ref == 'function') {
38
- const hasRefUnmount = typeof ref._unmount == 'function';
39
- if (hasRefUnmount) {
40
- // @ts-ignore TS doesn't like moving narrowing checks into variables
41
- ref._unmount();
42
- }
33
+ // This function is modified from preact source code.
34
+ function applyRef(ref: Ref, value: null | [snapshotInstanceId: number, expIndex: number]): void {
35
+ const newRef = value && new RefProxy(value);
43
36
 
44
- if (!hasRefUnmount || value != null) {
45
- // Store the cleanup function on the function
46
- // instance object itself to avoid shape
47
- // transitioning vnode
48
- ref._unmount = ref(value);
49
- }
50
- } else ref.current = value;
51
- }
37
+ try {
38
+ if (typeof ref == 'function') {
39
+ const hasRefUnmount = typeof ref._unmount == 'function';
40
+ if (hasRefUnmount) {
41
+ ref._unmount!();
42
+ }
52
43
 
53
- function updateBackgroundRefs(commitId: number): void {
54
- const oldRefMap = globalRefsToRemove.get(commitId);
55
- if (oldRefMap) {
56
- globalRefsToRemove.delete(commitId);
57
- for (const ref of oldRefMap.values()) {
58
- applyRef(ref, null);
59
- }
60
- }
61
- const newRefMap = globalRefsToSet.get(commitId);
62
- if (newRefMap) {
63
- globalRefsToSet.delete(commitId);
64
- for (const sign in newRefMap) {
65
- const ref = backgroundSnapshotInstanceManager.getValueBySign(sign);
66
- if (ref) {
67
- // TODO: ref: support __REF_FIRE_IMMEDIATELY__
68
- const v = newRefMap[sign] && lynx.createSelectorQuery().selectUniqueID(newRefMap[sign]);
69
- applyRef(ref, v);
44
+ if (!hasRefUnmount || newRef != null) {
45
+ // Store the cleanup function on the function
46
+ // instance object itself to avoid shape
47
+ // transitioning vnode
48
+ ref._unmount = ref(newRef!);
70
49
  }
71
- }
50
+ } else ref.current = newRef;
51
+ /* v8 ignore start */
52
+ } catch (e) {
53
+ lynx.reportError(e as Error);
72
54
  }
55
+ /* v8 ignore stop */
73
56
  }
74
57
 
75
58
  function updateRef(
76
59
  snapshot: SnapshotInstance,
77
60
  expIndex: number,
78
- oldValue: any,
61
+ oldValue: string | null,
79
62
  elementIndex: number,
80
- spreadKey: string,
81
63
  ): void {
82
- const value = snapshot.__values![expIndex];
64
+ const value: unknown = snapshot.__values![expIndex];
83
65
  let ref;
84
- if (!value) {
85
- ref = undefined;
86
- } else if (typeof value === 'string') {
66
+ if (typeof value === 'string') {
87
67
  ref = value;
88
68
  } else {
89
- ref = `${snapshot.__id}:${expIndex}:${spreadKey}`;
69
+ ref = `react-ref-${snapshot.__id}-${expIndex}`;
90
70
  }
91
71
 
92
72
  snapshot.__values![expIndex] = ref;
93
- if (snapshot.__elements && ref) {
94
- __SetAttribute(snapshot.__elements[elementIndex]!, 'has-react-ref', true);
95
- const uid = __GetElementUniqueID(snapshot.__elements[elementIndex]!);
96
- globalRefPatch[ref] = uid;
97
- snapshot.__ref_set ??= new Set();
98
- snapshot.__ref_set.add(ref);
99
- }
100
- if (oldValue !== ref) {
101
- snapshot.__ref_set?.delete(oldValue);
73
+ if (snapshot.__elements && oldValue !== ref) {
74
+ if (oldValue) {
75
+ __SetAttribute(snapshot.__elements[elementIndex]!, oldValue, undefined);
76
+ }
77
+ if (ref) {
78
+ __SetAttribute(snapshot.__elements[elementIndex]!, ref, 1);
79
+ }
102
80
  }
103
81
  }
104
82
 
105
- function takeGlobalRefPatchMap(): Record<string, number | null> {
106
- const patch = globalRefPatch;
107
- globalRefPatch = {};
108
- return patch;
109
- }
110
-
111
- function transformRef(ref: unknown): Function | (object & Record<'current', unknown>) | null | undefined {
83
+ function transformRef(ref: unknown): Ref | null | undefined {
112
84
  if (ref === undefined || ref === null) {
113
85
  return ref;
114
86
  }
115
87
  if (typeof ref === 'function' || (typeof ref === 'object' && 'current' in ref)) {
116
88
  if ('__ref' in ref) {
117
- return ref;
89
+ return ref as Ref;
118
90
  }
119
- return Object.defineProperty(ref, '__ref', { value: nextRefId++ });
91
+ return Object.defineProperty(ref, '__ref', { value: 1 }) as Ref;
120
92
  }
121
93
  throw new Error(
122
94
  `Elements' "ref" property should be a function, or an object created `
@@ -124,25 +96,44 @@ function transformRef(ref: unknown): Function | (object & Record<'current', unkn
124
96
  );
125
97
  }
126
98
 
127
- function markRefToRemove(sign: string, ref: unknown): void {
128
- if (!ref) {
99
+ function applyQueuedRefs(): void {
100
+ try {
101
+ for (const ref of refsToClear) {
102
+ applyRef(ref, null);
103
+ }
104
+ for (let i = 0; i < refsToApply.length; i += 2) {
105
+ const ref = refsToApply[i] as Ref;
106
+ const value = refsToApply[i + 1] as [snapshotInstanceId: number, expIndex: number] | null;
107
+ applyRef(ref, value);
108
+ }
109
+ } finally {
110
+ clearQueuedRefs();
111
+ }
112
+ }
113
+
114
+ function queueRefAttrUpdate(
115
+ oldRef: Ref | null | undefined,
116
+ newRef: Ref | null | undefined,
117
+ snapshotInstanceId: number,
118
+ expIndex: number,
119
+ ): void {
120
+ if (oldRef === newRef) {
129
121
  return;
130
122
  }
131
- let oldRefs = globalRefsToRemove.get(nextCommitTaskId);
132
- if (!oldRefs) {
133
- oldRefs = new Map();
134
- globalRefsToRemove.set(nextCommitTaskId, oldRefs);
123
+ if (oldRef) {
124
+ refsToClear.push(oldRef);
125
+ }
126
+ if (newRef) {
127
+ refsToApply.push(newRef, [snapshotInstanceId, expIndex]);
135
128
  }
136
- oldRefs.set(sign, ref);
137
129
  }
138
130
 
139
- export {
140
- globalRefsToRemove,
141
- globalRefsToSet,
142
- markRefToRemove,
143
- takeGlobalRefPatchMap,
144
- transformRef,
145
- unref,
146
- updateBackgroundRefs,
147
- updateRef,
148
- };
131
+ function clearQueuedRefs(): void {
132
+ refsToClear.length = 0;
133
+ refsToApply.length = 0;
134
+ }
135
+
136
+ /**
137
+ * @internal
138
+ */
139
+ export { queueRefAttrUpdate, updateRef, unref, transformRef, applyRef, applyQueuedRefs, clearQueuedRefs, type Ref };