@lynx-js/react 0.110.0 → 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 (112) hide show
  1. package/CHANGELOG.md +6 -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.js +2 -1
  7. package/runtime/lib/backgroundSnapshot.js.map +1 -1
  8. package/runtime/lib/compat/initData.d.ts +7 -5
  9. package/runtime/lib/compat/initData.js +1 -2
  10. package/runtime/lib/compat/initData.js.map +1 -1
  11. package/runtime/lib/compat/lynxComponent.js +10 -12
  12. package/runtime/lib/compat/lynxComponent.js.map +1 -1
  13. package/runtime/lib/debug/profile.js +1 -0
  14. package/runtime/lib/debug/profile.js.map +1 -1
  15. package/runtime/lib/gesture/processGestureBagkround.d.ts +1 -1
  16. package/runtime/lib/gesture/processGestureBagkround.js +4 -1
  17. package/runtime/lib/gesture/processGestureBagkround.js.map +1 -1
  18. package/runtime/lib/gesture/types.js.map +1 -1
  19. package/runtime/lib/hooks/useLynxGlobalEventListener.d.ts +1 -1
  20. package/runtime/lib/hydrate.d.ts +1 -1
  21. package/runtime/lib/hydrate.js +5 -4
  22. package/runtime/lib/hydrate.js.map +1 -1
  23. package/runtime/lib/internal.d.ts +3 -2
  24. package/runtime/lib/internal.js +3 -2
  25. package/runtime/lib/internal.js.map +1 -1
  26. package/runtime/lib/legacy-react-runtime/index.js +1 -1
  27. package/runtime/lib/legacy-react-runtime/index.js.map +1 -1
  28. package/runtime/lib/lifecycle/patch/snapshotPatchApply.js.map +1 -1
  29. package/runtime/lib/lifecycle/patch/updateMainThread.js +4 -4
  30. package/runtime/lib/lifecycle/patch/updateMainThread.js.map +1 -1
  31. package/runtime/lib/lifecycle/reload.js +1 -1
  32. package/runtime/lib/lifecycle/reload.js.map +1 -1
  33. package/runtime/lib/list.d.ts +2 -46
  34. package/runtime/lib/list.js +23 -200
  35. package/runtime/lib/list.js.map +1 -1
  36. package/runtime/lib/listUpdateInfo.d.ts +38 -0
  37. package/runtime/lib/listUpdateInfo.js +152 -0
  38. package/runtime/lib/listUpdateInfo.js.map +1 -0
  39. package/runtime/lib/lynx/calledByNative.js +2 -2
  40. package/runtime/lib/lynx/calledByNative.js.map +1 -1
  41. package/runtime/lib/lynx-api.js +3 -0
  42. package/runtime/lib/lynx-api.js.map +1 -1
  43. package/runtime/lib/lynx.js +1 -0
  44. package/runtime/lib/lynx.js.map +1 -1
  45. package/runtime/lib/opcodes.js +2 -1
  46. package/runtime/lib/opcodes.js.map +1 -1
  47. package/runtime/lib/pendingListUpdates.d.ts +6 -0
  48. package/runtime/lib/pendingListUpdates.js +16 -0
  49. package/runtime/lib/pendingListUpdates.js.map +1 -0
  50. package/runtime/lib/renderToOpcodes/index.js +7 -7
  51. package/runtime/lib/renderToOpcodes/index.js.map +1 -1
  52. package/runtime/lib/snapshot/dynamicPartType.d.ts +12 -0
  53. package/runtime/lib/snapshot/dynamicPartType.js +17 -0
  54. package/runtime/lib/snapshot/dynamicPartType.js.map +1 -0
  55. package/runtime/lib/snapshot/gesture.js +3 -0
  56. package/runtime/lib/snapshot/gesture.js.map +1 -1
  57. package/runtime/lib/snapshot/list.d.ts +3 -0
  58. package/runtime/lib/snapshot/list.js +23 -0
  59. package/runtime/lib/snapshot/list.js.map +1 -0
  60. package/runtime/lib/snapshot/platformInfo.d.ts +10 -0
  61. package/runtime/lib/snapshot/platformInfo.js +6 -3
  62. package/runtime/lib/snapshot/platformInfo.js.map +1 -1
  63. package/runtime/lib/snapshot/ref.d.ts +3 -0
  64. package/runtime/lib/snapshot/ref.js.map +1 -1
  65. package/runtime/lib/snapshot/spread.d.ts +2 -2
  66. package/runtime/lib/snapshot/spread.js +4 -5
  67. package/runtime/lib/snapshot/spread.js.map +1 -1
  68. package/runtime/lib/snapshot/workletEvent.js +1 -1
  69. package/runtime/lib/snapshot/workletEvent.js.map +1 -1
  70. package/runtime/lib/snapshot/workletRef.d.ts +1 -1
  71. package/runtime/lib/snapshot/workletRef.js.map +1 -1
  72. package/runtime/lib/snapshot.d.ts +5 -14
  73. package/runtime/lib/snapshot.js +18 -27
  74. package/runtime/lib/snapshot.js.map +1 -1
  75. package/runtime/lib/snapshotInstanceHydrationMap.js.map +1 -1
  76. package/runtime/lib/utils.js +1 -1
  77. package/runtime/lib/utils.js.map +1 -1
  78. package/runtime/src/backgroundSnapshot.ts +4 -8
  79. package/runtime/src/compat/initData.ts +10 -9
  80. package/runtime/src/compat/lynxComponent.ts +12 -13
  81. package/runtime/src/debug/profile.ts +1 -0
  82. package/runtime/src/gesture/processGestureBagkround.ts +5 -1
  83. package/runtime/src/gesture/types.ts +3 -0
  84. package/runtime/src/hooks/useLynxGlobalEventListener.ts +1 -1
  85. package/runtime/src/hydrate.ts +6 -4
  86. package/runtime/src/internal.ts +3 -2
  87. package/runtime/src/legacy-react-runtime/index.ts +1 -1
  88. package/runtime/src/lifecycle/patch/snapshotPatchApply.ts +1 -1
  89. package/runtime/src/lifecycle/patch/updateMainThread.ts +5 -5
  90. package/runtime/src/lifecycle/reload.ts +1 -1
  91. package/runtime/src/list.ts +26 -264
  92. package/runtime/src/listUpdateInfo.ts +221 -0
  93. package/runtime/src/lynx/calledByNative.ts +2 -2
  94. package/runtime/src/lynx-api.ts +4 -1
  95. package/runtime/src/lynx.ts +1 -0
  96. package/runtime/src/opcodes.ts +2 -1
  97. package/runtime/src/pendingListUpdates.ts +18 -0
  98. package/runtime/src/renderToOpcodes/index.ts +7 -7
  99. package/runtime/src/snapshot/dynamicPartType.ts +16 -0
  100. package/runtime/src/snapshot/gesture.ts +3 -0
  101. package/runtime/src/snapshot/list.ts +36 -0
  102. package/runtime/src/snapshot/platformInfo.ts +19 -5
  103. package/runtime/src/snapshot/ref.ts +1 -0
  104. package/runtime/src/snapshot/spread.ts +42 -17
  105. package/runtime/src/snapshot/workletEvent.ts +1 -1
  106. package/runtime/src/snapshot/workletRef.ts +1 -1
  107. package/runtime/src/snapshot.ts +23 -31
  108. package/runtime/src/snapshotInstanceHydrationMap.ts +1 -1
  109. package/runtime/src/utils.ts +3 -3
  110. package/testing-library/dist/env/vitest.js +3 -3
  111. package/testing-library/dist/vitest.config.js +7 -7
  112. package/transform/cjs/main.cjs +4 -0
@@ -0,0 +1,221 @@
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 } from './list.js';
7
+ import type { SnapshotInstance } from './snapshot.js';
8
+
9
+ export interface ListUpdateInfo {
10
+ flush(): void;
11
+ onInsertBefore(
12
+ newNode: SnapshotInstance,
13
+ existingNode?: SnapshotInstance,
14
+ ): void;
15
+ onRemoveChild(child: SnapshotInstance): void;
16
+ onSetAttribute(child: SnapshotInstance, attr: any, oldAttr: any): void;
17
+ }
18
+
19
+ // class ListUpdateInfoDiffing implements ListUpdateInfo {
20
+ // private oldChildNodes: SnapshotInstance[];
21
+ // constructor(private list: SnapshotInstance) {
22
+ // this.oldChildNodes = list.childNodes;
23
+ // }
24
+ // flush(): void {
25
+ // Object.defineProperty(SnapshotInstance.prototype, "key", {
26
+ // get: function () {
27
+ // return this.values[0]["item-key"];
28
+ // },
29
+ // });
30
+
31
+ // }
32
+ // onInsertBefore(newNode: SnapshotInstance, existingNode?: SnapshotInstance | undefined): void {}
33
+ // onRemoveChild(child: SnapshotInstance): void {}
34
+ // onSetAttribute(child: SnapshotInstance, attr: any): void {
35
+ // throw new Error("Method not implemented.");
36
+ // }
37
+ // }
38
+
39
+ interface InsertAction {
40
+ position: number;
41
+ type: string;
42
+ }
43
+
44
+ interface UpdateAction {
45
+ from: number;
46
+ to: number;
47
+ type: string;
48
+ flush: boolean;
49
+ }
50
+
51
+ interface ListOperations {
52
+ insertAction: InsertAction[];
53
+ removeAction: number[];
54
+ updateAction: UpdateAction[];
55
+ }
56
+
57
+ export class ListUpdateInfoRecording implements ListUpdateInfo {
58
+ constructor(private list: SnapshotInstance) {
59
+ this.oldChildNodes = list.childNodes;
60
+ // this.oldChildNodesSet = new Set(this.oldChildNodes);
61
+ }
62
+
63
+ // private __commitAndReset() {
64
+ // (this.__pendingAttributes ??= []).push(this.__toAttribute());
65
+ // this.oldChildNodes = this.list.childNodes;
66
+ // this.oldChildNodesSet = new Set(this.oldChildNodes);
67
+ // this.removeChild1.clear();
68
+ // this.removeChild2.clear();
69
+ // this.insertBefore.clear();
70
+ // this.appendChild.length = 0;
71
+ // this.platformInfoUpdate.clear();
72
+ // }
73
+
74
+ flush(): void {
75
+ const elementIndex = this.list.__snapshot_def.slot[0]![1];
76
+ const listElement = this.list.__elements![elementIndex]!;
77
+ // this.__pendingAttributes?.forEach(pendingAttribute => {
78
+ // __SetAttribute(listElement, "update-list-info", pendingAttribute);
79
+ // __FlushElementTree(listElement);
80
+ // });
81
+ __SetAttribute(listElement, 'update-list-info', this.__toAttribute());
82
+ const [componentAtIndex, componentAtIndexes] = componentAtIndexFactory(this.list.childNodes, hydrate);
83
+ __UpdateListCallbacks(
84
+ listElement,
85
+ componentAtIndex,
86
+ enqueueComponentFactory(),
87
+ componentAtIndexes,
88
+ );
89
+ }
90
+
91
+ private oldChildNodes: SnapshotInstance[];
92
+ // private oldChildNodesSet: Set<SnapshotInstance>;
93
+ private removeChild = new Set<SnapshotInstance>();
94
+ private insertBefore = new Map<SnapshotInstance, SnapshotInstance[]>(); // insert V before K
95
+ private appendChild = [] as SnapshotInstance[];
96
+ private platformInfoUpdate = new Map<SnapshotInstance, any>();
97
+
98
+ onInsertBefore(newNode: SnapshotInstance, existingNode?: SnapshotInstance): void {
99
+ if (newNode.parentNode) {
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
+ } as UpdateAction);
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
+ } as InsertAction);
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
+ } as InsertAction);
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
+ } as UpdateAction);
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
+ }
@@ -6,13 +6,13 @@ import { isJSReady, jsReady, jsReadyEventIdSwap, resetJSReady } from '../lifecyc
6
6
  import { reloadMainThread } from '../lifecycle/reload.js';
7
7
  import { renderMainThread } from '../lifecycle/render.js';
8
8
  import { LifecycleConstant } from '../lifecycleConstant.js';
9
- import { __pendingListUpdates } from '../list.js';
10
9
  import { ssrHydrateByOpcodes } from '../opcodes.js';
10
+ import { __pendingListUpdates } from '../pendingListUpdates.js';
11
11
  import { __root, setRoot } from '../root.js';
12
+ import { applyRefQueue } from '../snapshot/workletRef.js';
12
13
  import { SnapshotInstance, __page, setupPage } from '../snapshot.js';
13
14
  import { isEmptyObject } from '../utils.js';
14
15
  import { PerformanceTimingKeys, markTiming, setPipeline } from './performance.js';
15
- import { applyRefQueue } from '../snapshot/workletRef.js';
16
16
 
17
17
  function ssrEncode() {
18
18
  const { __opcodes } = __root;
@@ -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`.
@@ -42,6 +42,7 @@ if (__PROFILE__) {
42
42
 
43
43
  if (__BACKGROUND__) {
44
44
  // Trick Preact and TypeScript to accept our custom document adapter.
45
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
45
46
  options.document = document as any;
46
47
  setupBackgroundDocument();
47
48
  injectTt();
@@ -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;
@@ -12,6 +12,7 @@ const refsToApply: (Ref | [snapshotInstanceId: number, expIndex: number])[] = []
12
12
 
13
13
  type Ref = (((ref: RefProxy) => () => void) | { current: RefProxy | null }) & {
14
14
  _unmount?: () => void;
15
+ __ref?: { value: number };
15
16
  };
16
17
 
17
18
  function unref(snapshot: SnapshotInstance, recursive: boolean): void {
@@ -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,17 +85,17 @@ 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') {
@@ -106,7 +112,7 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
106
112
  __id: snapshot.__id,
107
113
  __elements: snapshot.__elements,
108
114
  } as SnapshotInstance;
109
- updateRef(fakeSnapshot, index, oldValue[key], elementIndex);
115
+ updateRef(fakeSnapshot, index, oldValue[key] as string | null, elementIndex);
110
116
  } else if (key.endsWith(':ref')) {
111
117
  snapshot.__worklet_ref_set ??= new Set();
112
118
  const fakeSnapshot = {
@@ -119,7 +125,13 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
119
125
  __elements: snapshot.__elements,
120
126
  __worklet_ref_set: snapshot.__worklet_ref_set,
121
127
  } as SnapshotInstance;
122
- 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
+ );
123
135
  } else if (key.endsWith(':gesture')) {
124
136
  const workletType = key.slice(0, -8);
125
137
  const fakeSnapshot = {
@@ -200,7 +212,7 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
200
212
  __id: snapshot.__id,
201
213
  __elements: snapshot.__elements,
202
214
  } as SnapshotInstance;
203
- updateRef(fakeSnapshot, index, oldValue[key], elementIndex);
215
+ updateRef(fakeSnapshot, index, oldValue[key] as string | null, elementIndex);
204
216
  } else if (key.endsWith(':ref')) {
205
217
  snapshot.__worklet_ref_set ??= new Set();
206
218
  const fakeSnapshot = {
@@ -213,7 +225,13 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
213
225
  __elements: snapshot.__elements,
214
226
  __worklet_ref_set: snapshot.__worklet_ref_set,
215
227
  } as SnapshotInstance;
216
- 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
+ );
217
235
  } else if (key.endsWith(':gesture')) {
218
236
  const workletType = key.slice(0, -8);
219
237
  const fakeSnapshot = {
@@ -243,7 +261,15 @@ function updateSpread(snapshot: SnapshotInstance, index: number, oldValue: any,
243
261
  __elements: snapshot.__elements,
244
262
  } as SnapshotInstance;
245
263
  if (workletType) {
246
- 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
+ );
247
273
  } else {
248
274
  updateEvent(fakeSnapshot, index, oldValue[key], elementIndex, eventType, eventName, key);
249
275
  }
@@ -283,7 +309,6 @@ function transformSpread(
283
309
  if (__LEPUS__) {
284
310
  result[key] = value ? 1 : undefined;
285
311
  } else {
286
- // @ts-ignore
287
312
  result[key] = transformRef(value)?.__ref;
288
313
  }
289
314
  } else if (typeof value === 'function') {
@@ -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,
@@ -43,7 +43,7 @@ export function workletUnRef(value: Worklet | WorkletRefImpl<Element>): void {
43
43
  export function updateWorkletRef(
44
44
  snapshot: SnapshotInstance,
45
45
  expIndex: number,
46
- oldValue: WorkletRefImpl<Element> | Worklet | undefined,
46
+ oldValue: WorkletRefImpl<Element> | Worklet | null | undefined,
47
47
  elementIndex: number,
48
48
  _workletType: string,
49
49
  ): void {