@onekeyfe/react-native-native-list 3.0.157-alpha.249 → 3.0.157-alpha.251

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 (130) hide show
  1. package/README.md +21 -5
  2. package/android/src/main/java/com/onekey/nativelist/NativeListAccessoryStack.kt +711 -0
  3. package/android/src/main/java/com/onekey/nativelist/NativeListActionRenderer.kt +169 -0
  4. package/android/src/main/java/com/onekey/nativelist/NativeListActivityRenderer.kt +243 -0
  5. package/android/src/main/java/com/onekey/nativelist/NativeListAdapter.kt +20 -6
  6. package/android/src/main/java/com/onekey/nativelist/NativeListDataRowRenderer.kt +487 -0
  7. package/android/src/main/java/com/onekey/nativelist/NativeListIdentityRenderer.kt +820 -0
  8. package/android/src/main/java/com/onekey/nativelist/NativeListImageSlot.kt +147 -0
  9. package/android/src/main/java/com/onekey/nativelist/NativeListLeadingVisual.kt +453 -0
  10. package/android/src/main/java/com/onekey/nativelist/NativeListMarketRenderer.kt +997 -0
  11. package/android/src/main/java/com/onekey/nativelist/NativeListMediaTileRenderer.kt +234 -0
  12. package/android/src/main/java/com/onekey/nativelist/NativeListMessageRenderer.kt +232 -0
  13. package/android/src/main/java/com/onekey/nativelist/NativeListMetricCardRenderer.kt +551 -0
  14. package/android/src/main/java/com/onekey/nativelist/NativeListModels.kt +24 -0
  15. package/android/src/main/java/com/onekey/nativelist/NativeListPrimitives.kt +475 -0
  16. package/android/src/main/java/com/onekey/nativelist/NativeListRailRenderer.kt +143 -0
  17. package/android/src/main/java/com/onekey/nativelist/NativeListRendererRegistry.kt +42 -0
  18. package/android/src/main/java/com/onekey/nativelist/NativeListRendererRowView.kt +415 -0
  19. package/android/src/main/java/com/onekey/nativelist/NativeListResolvedText.kt +163 -0
  20. package/android/src/main/java/com/onekey/nativelist/NativeListRowHost.kt +70 -0
  21. package/android/src/main/java/com/onekey/nativelist/NativeListSectionHeaderRenderer.kt +748 -0
  22. package/android/src/main/java/com/onekey/nativelist/NativeListSystemRenderer.kt +464 -0
  23. package/android/src/main/java/com/onekey/nativelist/NativeListTextView.kt +25 -0
  24. package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +174 -104
  25. package/android/src/main/java/com/onekey/nativelist/NativeListWalletGroupRenderer.kt +407 -0
  26. package/android/src/test/java/com/margelo/nitro/nativelist/NativeListSelectorBackgroundColorTest.kt +34 -0
  27. package/docs/DESIGN.md +518 -9
  28. package/docs/MIGRATION_BASELINE.md +117 -0
  29. package/docs/ROW_TEMPLATES.md +359 -0
  30. package/docs/SPEC.md +358 -0
  31. package/docs/STYLE_SPEC.md +978 -0
  32. package/docs/images/list-capabilities.svg +39 -0
  33. package/docs/images/row-action.svg +17 -0
  34. package/docs/images/row-activity.svg +24 -0
  35. package/docs/images/row-data.svg +24 -0
  36. package/docs/images/row-identity.svg +25 -0
  37. package/docs/images/row-market.svg +23 -0
  38. package/docs/images/row-media-tile.svg +26 -0
  39. package/docs/images/row-message.svg +20 -0
  40. package/docs/images/row-metric-card.svg +33 -0
  41. package/docs/images/row-rail.svg +18 -0
  42. package/docs/images/row-section-header.svg +19 -0
  43. package/docs/images/row-style-regions.svg +30 -0
  44. package/docs/images/row-system.svg +30 -0
  45. package/docs/images/row-wallet-group.svg +26 -0
  46. package/ios/NativeListAccessoryStack.swift +680 -0
  47. package/ios/NativeListActionRenderer.swift +108 -0
  48. package/ios/NativeListActivityRenderer.swift +179 -0
  49. package/ios/NativeListDataRowRenderer.swift +444 -0
  50. package/ios/NativeListIdentityRenderer.swift +685 -0
  51. package/ios/NativeListImageSlot.swift +140 -0
  52. package/ios/NativeListLeadingVisual.swift +372 -0
  53. package/ios/NativeListMarketRenderer.swift +698 -0
  54. package/ios/NativeListMediaTileRenderer.swift +184 -0
  55. package/ios/NativeListMessageRenderer.swift +168 -0
  56. package/ios/NativeListMetricCardRenderer.swift +420 -0
  57. package/ios/NativeListModels.swift +32 -0
  58. package/ios/NativeListRailRenderer.swift +152 -0
  59. package/ios/NativeListRendererCell.swift +311 -0
  60. package/ios/NativeListRendererRegistry.swift +50 -0
  61. package/ios/NativeListResolvedText.swift +122 -0
  62. package/ios/NativeListRowHost.swift +63 -0
  63. package/ios/NativeListSectionHeaderRenderer.swift +708 -0
  64. package/ios/NativeListSystemRenderer.swift +568 -0
  65. package/ios/NativeListTextLabel.swift +42 -0
  66. package/ios/NativeListTextStyles.swift +236 -0
  67. package/ios/NativeListWalletGroupRenderer.swift +255 -0
  68. package/ios/RNCNativeListView.swift +111 -180
  69. package/lib/module/models.js +54 -0
  70. package/lib/module/validation.js +324 -26
  71. package/lib/module/web/NativeListWebEngine.js +148 -936
  72. package/lib/module/web/templates/ActionRowRenderer.js +97 -0
  73. package/lib/module/web/templates/ActivityRowRenderer.js +95 -0
  74. package/lib/module/web/templates/DataRowRenderer.js +145 -0
  75. package/lib/module/web/templates/IdentityRowRenderer.js +289 -0
  76. package/lib/module/web/templates/MarketRowRenderer.js +310 -0
  77. package/lib/module/web/templates/MediaTileRowRenderer.js +132 -0
  78. package/lib/module/web/templates/MessageRowRenderer.js +165 -0
  79. package/lib/module/web/templates/MetricCardRowRenderer.js +172 -0
  80. package/lib/module/web/templates/RailRowRenderer.js +98 -0
  81. package/lib/module/web/templates/RowContainerStyle.js +100 -0
  82. package/lib/module/web/templates/RowElements.js +93 -0
  83. package/lib/module/web/templates/RowRendererRegistry.js +70 -0
  84. package/lib/module/web/templates/RowText.js +121 -0
  85. package/lib/module/web/templates/RowVisual.js +43 -0
  86. package/lib/module/web/templates/SectionHeaderRowRenderer.js +146 -0
  87. package/lib/module/web/templates/SystemRowRenderer.js +161 -0
  88. package/lib/module/web/templates/WalletGroupRowRenderer.js +96 -0
  89. package/lib/typescript/src/models.d.ts +166 -13
  90. package/lib/typescript/src/web/NativeListWebEngine.d.ts +18 -16
  91. package/lib/typescript/src/web/templates/ActionRowRenderer.d.ts +15 -0
  92. package/lib/typescript/src/web/templates/ActivityRowRenderer.d.ts +15 -0
  93. package/lib/typescript/src/web/templates/DataRowRenderer.d.ts +15 -0
  94. package/lib/typescript/src/web/templates/IdentityRowRenderer.d.ts +16 -0
  95. package/lib/typescript/src/web/templates/MarketRowRenderer.d.ts +30 -0
  96. package/lib/typescript/src/web/templates/MediaTileRowRenderer.d.ts +15 -0
  97. package/lib/typescript/src/web/templates/MessageRowRenderer.d.ts +44 -0
  98. package/lib/typescript/src/web/templates/MetricCardRowRenderer.d.ts +15 -0
  99. package/lib/typescript/src/web/templates/RailRowRenderer.d.ts +28 -0
  100. package/lib/typescript/src/web/templates/RowContainerStyle.d.ts +9 -0
  101. package/lib/typescript/src/web/templates/RowElements.d.ts +38 -0
  102. package/lib/typescript/src/web/templates/RowRendererRegistry.d.ts +83 -0
  103. package/lib/typescript/src/web/templates/RowText.d.ts +9 -0
  104. package/lib/typescript/src/web/templates/RowVisual.d.ts +20 -0
  105. package/lib/typescript/src/web/templates/SectionHeaderRowRenderer.d.ts +15 -0
  106. package/lib/typescript/src/web/templates/SystemRowRenderer.d.ts +16 -0
  107. package/lib/typescript/src/web/templates/WalletGroupRowRenderer.d.ts +20 -0
  108. package/package.json +3 -3
  109. package/src/models.ts +281 -19
  110. package/src/validation.ts +501 -46
  111. package/src/web/NativeListWebEngine.ts +361 -1932
  112. package/src/web/templates/ActionRowRenderer.ts +123 -0
  113. package/src/web/templates/ActivityRowRenderer.ts +159 -0
  114. package/src/web/templates/DataRowRenderer.ts +212 -0
  115. package/src/web/templates/IdentityRowRenderer.ts +527 -0
  116. package/src/web/templates/MarketRowRenderer.ts +467 -0
  117. package/src/web/templates/MediaTileRowRenderer.ts +182 -0
  118. package/src/web/templates/MessageRowRenderer.ts +306 -0
  119. package/src/web/templates/MetricCardRowRenderer.ts +337 -0
  120. package/src/web/templates/RailRowRenderer.ts +136 -0
  121. package/src/web/templates/RowContainerStyle.ts +131 -0
  122. package/src/web/templates/RowElements.ts +160 -0
  123. package/src/web/templates/RowRendererRegistry.ts +111 -0
  124. package/src/web/templates/RowText.ts +181 -0
  125. package/src/web/templates/RowVisual.ts +115 -0
  126. package/src/web/templates/SectionHeaderRowRenderer.ts +243 -0
  127. package/src/web/templates/SystemRowRenderer.ts +282 -0
  128. package/src/web/templates/WalletGroupRowRenderer.ts +131 -0
  129. package/android/src/main/java/com/onekey/nativelist/NativeListRowView.kt +0 -4538
  130. package/ios/NativeListCell.swift +0 -4300
@@ -0,0 +1,282 @@
1
+ import type { NativeListTextStyle, SystemRow } from '../../models';
2
+ import type { RowPrimitives } from './RowVisual';
3
+ import {
4
+ captureInlineStyles,
5
+ createElement,
6
+ hasExplicitRowHeight,
7
+ restoreInlineStyles,
8
+ setData,
9
+ tagSlot,
10
+ } from './RowElements';
11
+ function createSystemRow(
12
+ document: Document,
13
+ primitives: RowPrimitives,
14
+ row: SystemRow
15
+ ): HTMLElement {
16
+ const body = createElement(
17
+ document,
18
+ 'div',
19
+ 'ok-native-list-row ok-native-list-system'
20
+ );
21
+ setData(body, 'variant', row.variant);
22
+ if ('presentation' in row)
23
+ setData(body, 'nativeListPresentation', row.presentation);
24
+ if (row.variant === 'loading' && row.loadingStyle === 'skeleton') {
25
+ body.classList.add('ok-native-list-market-skeleton');
26
+ const background = primitives.background;
27
+ const rgb = Number.parseInt(background.slice(1, 7), 16);
28
+ const dark =
29
+ ((rgb >> 16) & 255) * 0.299 +
30
+ ((rgb >> 8) & 255) * 0.587 +
31
+ (rgb & 255) * 0.114 <
32
+ 128;
33
+ body.style.setProperty('--nl-skeleton-base', dark ? '#111111' : '#fafafa');
34
+ body.style.setProperty(
35
+ '--nl-skeleton-highlight',
36
+ dark ? '#333333' : '#cdcdcd'
37
+ );
38
+ const left = createElement(document, 'div', 'ok-native-list-skeleton-left');
39
+ const mark = (width: number, height: number, circle = false) => {
40
+ const element = createElement(
41
+ document,
42
+ 'span',
43
+ 'ok-native-list-skeleton-mark'
44
+ );
45
+ element.style.width = `${width}px`;
46
+ element.style.height = `${height}px`;
47
+ if (circle) element.style.borderRadius = '50%';
48
+ return element;
49
+ };
50
+ left.appendChild(mark(32, 32, true));
51
+ const text = createElement(document, 'div', 'ok-native-list-skeleton-text');
52
+ text.appendChild(mark(80, 16));
53
+ text.appendChild(mark(60, 12));
54
+ left.appendChild(text);
55
+ body.appendChild(left);
56
+ const right = createElement(
57
+ document,
58
+ 'div',
59
+ 'ok-native-list-skeleton-right'
60
+ );
61
+ right.appendChild(mark(80, 18));
62
+ right.appendChild(mark(80, 18));
63
+ body.appendChild(right);
64
+ return body;
65
+ }
66
+ if (row.variant === 'loading' && row.loadingStyle === 'spinner') {
67
+ body.style.justifyContent = 'center';
68
+ body.style.padding = '16px';
69
+ const spinner = createElement(
70
+ document,
71
+ 'span',
72
+ 'ok-native-list-market-spinner'
73
+ );
74
+ spinner.setAttribute('role', 'progressbar');
75
+ // Same 20px SVG and 750ms rotation as react-native-web ActivityIndicator.
76
+ spinner.innerHTML =
77
+ '<svg viewBox="0 0 32 32" width="20" height="20"><circle cx="16" cy="16" r="14" fill="none" stroke="currentColor" stroke-width="4" opacity="0.2"/><circle cx="16" cy="16" r="14" fill="none" stroke="currentColor" stroke-width="4" stroke-dasharray="80" stroke-dashoffset="60"/></svg>';
78
+ body.appendChild(spinner);
79
+ return body;
80
+ }
81
+ if ('presentation' in row && row.presentation === 'market') {
82
+ if (row.variant === 'noMatch') {
83
+ body.style.justifyContent = 'center';
84
+ body.style.padding = '32px';
85
+ const message = tagSlot(
86
+ createElement(document, 'span', '', row.message),
87
+ 'message'
88
+ );
89
+ message.style.fontSize = '16px';
90
+ message.style.lineHeight = '24px';
91
+ body.appendChild(message);
92
+ return body;
93
+ }
94
+ if (row.variant === 'end') {
95
+ body.style.justifyContent = 'center';
96
+ body.style.padding = '16px';
97
+ body.style.gap = '8px';
98
+ for (const width of [80, 4, 80]) {
99
+ const mark = createElement(document, 'span', '');
100
+ mark.style.width = String(width) + 'px';
101
+ mark.style.height = width === 4 ? '4px' : '1px';
102
+ mark.style.borderRadius = width === 4 ? '2px' : '0';
103
+ mark.style.background = 'var(--nl-separator)';
104
+ body.appendChild(mark);
105
+ }
106
+ return body;
107
+ }
108
+ }
109
+ if (row.variant === 'warning') {
110
+ body.classList.add('ok-native-list-warning');
111
+ body.style.borderColor = row.borderColor ?? 'var(--nl-separator)';
112
+ body.appendChild(
113
+ tagSlot(
114
+ createElement(
115
+ document,
116
+ 'span',
117
+ 'ok-native-list-warning-title',
118
+ row.title
119
+ ),
120
+ 'title'
121
+ )
122
+ );
123
+ body.appendChild(
124
+ tagSlot(
125
+ createElement(
126
+ document,
127
+ 'span',
128
+ 'ok-native-list-warning-message',
129
+ row.message
130
+ ),
131
+ 'message'
132
+ )
133
+ );
134
+ return body;
135
+ }
136
+ if (row.variant === 'loading')
137
+ body.appendChild(createElement(document, 'span', 'ok-native-list-spinner'));
138
+ const message =
139
+ row.variant === 'spacer'
140
+ ? ''
141
+ : row.message ?? (row.variant === 'end' ? 'End' : '');
142
+ if (message)
143
+ body.appendChild(
144
+ tagSlot(
145
+ createElement(document, 'span', 'ok-native-list-secondary', message),
146
+ 'message'
147
+ )
148
+ );
149
+ // Legacy Web draws no retry button for any presentation: a retry row shows
150
+ // only its message and the whole row (click, Enter or Space) emits the
151
+ // retry `actionKey`. `actionText` / `style.actionText` therefore have no Web
152
+ // target; they style the native retry button only.
153
+ return body;
154
+ }
155
+
156
+ type Binding = { key: string; defaults: Map<HTMLElement, string> };
157
+ const bindings = new WeakMap<HTMLElement, Binding>();
158
+ function bind(body: HTMLElement, row: SystemRow, primitives: RowPrimitives) {
159
+ // Text styles are part of the key: applyTextLayout inserts wrappers and
160
+ // rewrites text (lines: 1), which restoring inline styles cannot undo.
161
+ const content = {
162
+ ...row,
163
+ style: { title: row.style?.title, message: row.style?.message },
164
+ };
165
+ const key = JSON.stringify([content, primitives.background]);
166
+ let binding = bindings.get(body);
167
+ if (!binding || binding.key !== key) {
168
+ const next = createSystemRow(body.ownerDocument, primitives, row);
169
+ body.replaceChildren(...Array.from(next.childNodes));
170
+ body.className = next.className;
171
+ body.style.cssText = next.style.cssText;
172
+ body.dataset.variant = row.variant;
173
+ body.dataset.nativeListPresentation =
174
+ 'presentation' in row ? row.presentation ?? '' : '';
175
+ binding = {
176
+ key,
177
+ defaults: captureInlineStyles(body),
178
+ };
179
+ bindings.set(body, binding);
180
+ }
181
+ restoreInlineStyles(binding.defaults);
182
+ body.removeAttribute('data-nl-container-background');
183
+ body.removeAttribute('data-nl-container-border');
184
+ const style = row.style;
185
+ if (style?.horizontalPadding !== undefined)
186
+ body.style.paddingInline = `${style.horizontalPadding}px`;
187
+ if (style?.verticalPadding !== undefined)
188
+ body.style.paddingBlock = `${style.verticalPadding}px`;
189
+ if (style?.lineGap !== undefined && row.variant === 'warning')
190
+ body.style.rowGap = `${style.lineGap}px`;
191
+ for (const slot of ['title', 'message'] as const) {
192
+ const text = style?.[slot];
193
+ if (!text) continue;
194
+ body
195
+ .querySelectorAll<HTMLElement>(`[data-nl-slot="${slot}"]`)
196
+ .forEach((node) =>
197
+ primitives.textStyle(
198
+ node,
199
+ text,
200
+ row.variant === 'warning' ? 0 : undefined
201
+ )
202
+ );
203
+ }
204
+ }
205
+ function create(document: Document, row: SystemRow, primitives: RowPrimitives) {
206
+ const body = document.createElement('div');
207
+ body.dataset.nlRenderer = 'system';
208
+ bind(body, row, primitives);
209
+ return body;
210
+ }
211
+ function measure(row: SystemRow, width: number) {
212
+ if (row.variant === 'warning') {
213
+ const textWidth = Math.max(
214
+ 1,
215
+ width - (row.style?.horizontalPadding ?? 12) * 2
216
+ );
217
+ const height = (text: string, style: NativeListTextStyle | undefined) => {
218
+ const size = style?.fontSize ?? 14;
219
+ const lines = text
220
+ .split(/\r\n|[\r\n]/)
221
+ .reduce(
222
+ (total, line) =>
223
+ total +
224
+ Math.max(
225
+ 1,
226
+ Math.ceil(
227
+ Array.from(line).reduce(
228
+ (length, char) =>
229
+ length + (char.charCodeAt(0) > 255 ? size : size / 2),
230
+ 0
231
+ ) / textWidth
232
+ )
233
+ ),
234
+ 0
235
+ );
236
+ return (
237
+ Math.min(style?.lines ?? Infinity, lines) * (style?.lineHeight ?? 20)
238
+ );
239
+ };
240
+ return (
241
+ (row.style?.verticalPadding ?? 14) * 2 +
242
+ (row.style?.lineGap ?? 4) +
243
+ height(row.title, row.style?.title) +
244
+ height(row.message, row.style?.message)
245
+ );
246
+ }
247
+ return row.variant === 'spacer'
248
+ ? row.height
249
+ : row.variant === 'loading' && row.loadingStyle === 'skeleton'
250
+ ? 56
251
+ : row.variant === 'loading' && row.loadingStyle === 'spinner'
252
+ ? 52
253
+ : 'presentation' in row && row.presentation === 'market'
254
+ ? row.variant === 'loading'
255
+ ? 68
256
+ : 44
257
+ : row.variant === 'noMatch' || row.variant === 'end'
258
+ ? 36
259
+ : row.variant === 'retry'
260
+ ? 44
261
+ : 56;
262
+ }
263
+ export const systemRowRenderer = {
264
+ key: 'system' as const,
265
+ appliesSizePreset: (row: SystemRow) =>
266
+ !['warning', 'spacer'].includes(row.variant),
267
+ create,
268
+ bind,
269
+ measure,
270
+ // Legacy Web lays out an automatic-height warning at its rendered border-box
271
+ // height (padding, both borders and wrapped text), not the estimate above.
272
+ measureRendered: (body: HTMLElement, row: SystemRow): number | undefined => {
273
+ if (row.variant !== 'warning' || hasExplicitRowHeight(row))
274
+ return undefined;
275
+ const height = body.offsetHeight;
276
+ return height > 0 ? height : undefined;
277
+ },
278
+ recycle: (body: HTMLElement) => {
279
+ bindings.delete(body);
280
+ body.replaceChildren();
281
+ },
282
+ };
@@ -0,0 +1,131 @@
1
+ import type { IdentityRow, WalletGroupRow } from '../../models';
2
+ import { identityRowRenderer } from './IdentityRowRenderer';
3
+ import {
4
+ applyRowContainerStyle,
5
+ resetRowContainerStyle,
6
+ } from './RowContainerStyle';
7
+ import { setData } from './RowElements';
8
+ import type { RowPrimitives } from './RowVisual';
9
+
10
+ type Member = { wrapper: HTMLElement; body: HTMLElement };
11
+ const membersByBody = new WeakMap<HTMLElement, Map<string, Member>>();
12
+ // Members are walletSidebar identities; like the legacy engine, their preset
13
+ // height (68, +24 with badges) ignores the `size` preset adjustment.
14
+ const memberHeight = (member: IdentityRow, width: number) =>
15
+ member.style?.container?.height ??
16
+ member.height ??
17
+ identityRowRenderer.measure(member, width);
18
+
19
+ function bind(
20
+ body: HTMLElement,
21
+ row: WalletGroupRow,
22
+ primitives: RowPrimitives
23
+ ) {
24
+ const members = membersByBody.get(body)!;
25
+ const nextKeys = new Set(
26
+ [row.parent, ...row.children].map((member) => member.key)
27
+ );
28
+ for (const [key, member] of members) {
29
+ if (!nextKeys.has(key)) {
30
+ identityRowRenderer.recycle(member.body);
31
+ member.wrapper.remove();
32
+ members.delete(key);
33
+ }
34
+ }
35
+ body.style.cssText = '';
36
+ for (const name of body.getAttributeNames())
37
+ if (name.startsWith('data-') && name !== 'data-nl-renderer')
38
+ body.removeAttribute(name);
39
+ // The group's legacy 1px border is its default one-unit inset (native: a
40
+ // 1-unit padding when the parent has `height`). A style padding replaces that
41
+ // inset, so the border supplies its first unit and CSS padding the rest; the
42
+ // edge-to-content distance is then exactly the style value, as on native and
43
+ // as `measure` budgets it.
44
+ if (row.style?.horizontalPadding !== undefined)
45
+ body.style.paddingInline = `${Math.max(
46
+ 0,
47
+ row.style.horizontalPadding - 1
48
+ )}px`;
49
+ if (row.style?.verticalPadding !== undefined)
50
+ body.style.paddingBlock = `${Math.max(0, row.style.verticalPadding - 1)}px`;
51
+ [row.parent, ...row.children].forEach((memberRow, index) => {
52
+ let member = members.get(memberRow.key);
53
+ if (member) {
54
+ resetRowContainerStyle(member.body);
55
+ identityRowRenderer.bind(member.body, memberRow, primitives);
56
+ } else {
57
+ const wrapper = body.ownerDocument.createElement('div');
58
+ wrapper.className = 'ok-native-list-wallet-member';
59
+ const memberBody = identityRowRenderer.create(
60
+ body.ownerDocument,
61
+ memberRow,
62
+ primitives
63
+ );
64
+ wrapper.appendChild(memberBody);
65
+ member = { wrapper, body: memberBody };
66
+ members.set(memberRow.key, member);
67
+ }
68
+ const { wrapper, body: memberBody } = member;
69
+ setData(wrapper, 'nativeListGroupMemberKey', memberRow.key);
70
+ setData(wrapper, 'testid', memberRow.testID);
71
+ setData(wrapper, 'nativeListGroupParent', index === 0);
72
+ setData(wrapper, 'nativeListSelected', memberRow.selected);
73
+ wrapper.style.cssText = '';
74
+ wrapper.style.flexBasis = `${memberHeight(memberRow, 0)}px`;
75
+ wrapper.style.height = wrapper.style.flexBasis;
76
+ wrapper.style.opacity = String(
77
+ (memberRow.style?.container?.opacity ?? memberRow.opacity ?? 1) *
78
+ (memberRow.disabled ? 0.5 : 1)
79
+ );
80
+ if (memberRow.style?.container?.cornerRadius !== undefined)
81
+ wrapper.style.borderRadius = `${memberRow.style.container.cornerRadius}px`;
82
+ if (memberRow.backgroundColor)
83
+ memberBody.style.backgroundColor = memberRow.backgroundColor;
84
+ applyRowContainerStyle(memberBody, memberRow);
85
+ body.appendChild(wrapper);
86
+ });
87
+ }
88
+ function create(
89
+ document: Document,
90
+ row: WalletGroupRow,
91
+ primitives: RowPrimitives
92
+ ) {
93
+ const body = document.createElement('div');
94
+ body.className = 'ok-native-list-wallet-group';
95
+ body.dataset.nlRenderer = 'walletGroup';
96
+ membersByBody.set(body, new Map());
97
+ bind(body, row, primitives);
98
+ return body;
99
+ }
100
+ function recycle(body: HTMLElement) {
101
+ const members = membersByBody.get(body);
102
+ members?.forEach((member) => identityRowRenderer.recycle(member.body));
103
+ members?.clear();
104
+ body.replaceChildren();
105
+ }
106
+ export const walletGroupRowRenderer = {
107
+ key: 'walletGroup' as const,
108
+ reorderPreview: (body: HTMLElement, row: WalletGroupRow) => {
109
+ const parent = membersByBody.get(body)?.get(row.parent.key);
110
+ return parent ? { element: parent.body, height: 68 } : undefined;
111
+ },
112
+ create,
113
+ bind,
114
+ recycle,
115
+ appliesSizePreset: () => false,
116
+ // Legacy group height: members, 12-unit gaps and the 1px border pair, which
117
+ // (like native's 1-unit inset) is budgeted only when the parent carries
118
+ // `height`. `style.verticalPadding` replaces that inset, as on native.
119
+ measure: (row: WalletGroupRow, width: number) =>
120
+ [row.parent, ...row.children].reduce(
121
+ (total, member) => total + memberHeight(member, width),
122
+ 0
123
+ ) +
124
+ row.children.length * 12 +
125
+ (row.style?.verticalPadding ?? (row.parent.height !== undefined ? 1 : 0)) *
126
+ 2,
127
+ measureRendered: (
128
+ _body: HTMLElement,
129
+ _row: WalletGroupRow
130
+ ): number | undefined => undefined,
131
+ };