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

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,181 @@
1
+ import type { NativeListTextStyle } from '../../models';
2
+ import { createElement } from './RowElements';
3
+ export function applyValueSegments(
4
+ element: HTMLElement,
5
+ segments:
6
+ | readonly Readonly<{ text: string; style?: 'subscript' }>[]
7
+ | undefined,
8
+ fontSize = 16,
9
+ lineHeight = 24,
10
+ weight = 500
11
+ ) {
12
+ if (!segments?.length) return;
13
+ element.textContent = '';
14
+ element.style.fontSize = String(fontSize) + 'px';
15
+ element.style.lineHeight = String(lineHeight) + 'px';
16
+ element.style.fontWeight = String(weight);
17
+ segments.forEach((segment) => {
18
+ const span = createElement(
19
+ element.ownerDocument,
20
+ 'span',
21
+ undefined,
22
+ segment.text
23
+ );
24
+ if (segment.style === 'subscript') {
25
+ span.dataset.nlSegment = 'subscript';
26
+ applySubscriptMetrics(span, fontSize);
27
+ }
28
+ element.appendChild(span);
29
+ });
30
+ }
31
+ // Legacy subscript metrics: 60% of the field size on a field-size line box.
32
+ function applySubscriptMetrics(span: HTMLElement, fontSize: number) {
33
+ span.style.fontSize = String(Math.ceil(fontSize * 0.6)) + 'px';
34
+ span.style.lineHeight = String(fontSize) + 'px';
35
+ }
36
+ export function applyTextLayout(
37
+ element: HTMLElement,
38
+ style: NativeListTextStyle,
39
+ defaultLines?: number
40
+ ): void {
41
+ if (
42
+ style.lines === undefined &&
43
+ style.truncate === undefined &&
44
+ style.verticalAlignment === undefined &&
45
+ style.offsetY === undefined &&
46
+ defaultLines === undefined
47
+ )
48
+ return;
49
+ let content = element.querySelector<HTMLElement>(
50
+ ':scope > .ok-native-list-text-content'
51
+ );
52
+ // Line clamps are only ever written inline by templates (no stylesheet rule
53
+ // sets them), so no computed-style read is needed; this also keeps the result
54
+ // identical for attached and detached rows.
55
+ const inheritedClamp = Number(
56
+ element.style.getPropertyValue('-webkit-line-clamp')
57
+ );
58
+ const lines = style.lines ?? defaultLines ?? (inheritedClamp || 1);
59
+ if (
60
+ !content &&
61
+ (style.verticalAlignment !== undefined ||
62
+ style.offsetY !== undefined ||
63
+ element.classList.contains('ok-native-list-market-change'))
64
+ ) {
65
+ content = element.ownerDocument.createElement('span');
66
+ content.className = 'ok-native-list-text-content';
67
+ content.append(...Array.from(element.childNodes));
68
+ element.appendChild(content);
69
+ element.style.display = 'flex';
70
+ element.style.flexDirection = 'column';
71
+ element.style.removeProperty('-webkit-line-clamp');
72
+ element.style.removeProperty('-webkit-box-orient');
73
+ content.style.minWidth = '0';
74
+ content.style.flex = '0 1 auto';
75
+ content.style.width = '100%';
76
+ }
77
+ const text = content ?? element;
78
+ if (style.verticalAlignment !== undefined) {
79
+ element.style.justifyContent = {
80
+ top: 'flex-start',
81
+ center: 'center',
82
+ bottom: 'flex-end',
83
+ }[style.verticalAlignment];
84
+ }
85
+ if (style.offsetY !== undefined)
86
+ text.style.transform = `translateY(${style.offsetY}px)`;
87
+ if (
88
+ style.lines === undefined &&
89
+ style.truncate === undefined &&
90
+ defaultLines === undefined &&
91
+ !inheritedClamp
92
+ ) {
93
+ if (content) {
94
+ // Inherit the slot's resolved wrapping/truncation from CSS or inline style.
95
+ content.style.whiteSpace = 'inherit';
96
+ content.style.textOverflow = 'inherit';
97
+ content.style.overflow = 'hidden';
98
+ }
99
+ return;
100
+ }
101
+ if (lines === 1) {
102
+ const walker = element.ownerDocument.createTreeWalker(
103
+ text,
104
+ 4 /* SHOW_TEXT */
105
+ );
106
+ let previousCarriageReturn = false;
107
+ while (walker.nextNode()) {
108
+ const value = walker.currentNode.nodeValue ?? '';
109
+ if (!value) continue;
110
+ // A CRLF pair may straddle two styled runs.
111
+ const textValue =
112
+ previousCarriageReturn && value.startsWith('\n')
113
+ ? value.slice(1)
114
+ : value;
115
+ walker.currentNode.nodeValue = textValue.replace(/\r\n|[\r\n]/g, ' ');
116
+ previousCarriageReturn = value.endsWith('\r');
117
+ }
118
+ }
119
+ text.style.whiteSpace = lines === 1 ? 'nowrap' : 'pre-wrap';
120
+ text.style.overflow = 'hidden';
121
+ text.style.textOverflow = style.truncate === 'clip' ? 'clip' : 'ellipsis';
122
+ text.style.removeProperty('-webkit-line-clamp');
123
+ text.style.removeProperty('-webkit-box-orient');
124
+ text.style.maxHeight = '';
125
+ if (lines > 1 && style.truncate !== 'clip') {
126
+ text.style.display = '-webkit-box';
127
+ text.style.setProperty('-webkit-line-clamp', String(lines));
128
+ text.style.setProperty('-webkit-box-orient', 'vertical');
129
+ } else {
130
+ text.style.display = 'block';
131
+ if (lines > 1) {
132
+ // Rows are styled before mounting, when computed typography is unavailable.
133
+ // Resolve omitted line height in CSS after the template rules take effect.
134
+ text.style.maxHeight =
135
+ style.lineHeight !== undefined
136
+ ? `${lines * style.lineHeight}px`
137
+ : `${lines}lh`;
138
+ }
139
+ }
140
+ }
141
+ export function applyTextStyleToSlot(
142
+ element: HTMLElement,
143
+ style: NativeListTextStyle,
144
+ defaultLines?: number
145
+ ): void {
146
+ if (style.fontSize !== undefined)
147
+ element.style.fontSize = String(style.fontSize) + 'px';
148
+ if (style.lineHeight !== undefined)
149
+ element.style.lineHeight = String(style.lineHeight) + 'px';
150
+ if (style.fontWeight !== undefined)
151
+ element.style.fontWeight = String(fontWeight(style.fontWeight, 400));
152
+ if (style.color !== undefined) element.style.color = style.color;
153
+ // Explicit overrides also apply to rich text runs, but never to sibling badges.
154
+ // Subscript segments keep their legacy size relative to the field size.
155
+ element.querySelectorAll<HTMLElement>('span').forEach((run) => {
156
+ const subscript = run.dataset.nlSegment === 'subscript';
157
+ if (style.color !== undefined) run.style.color = style.color;
158
+ if (style.fontSize !== undefined) {
159
+ if (subscript) applySubscriptMetrics(run, style.fontSize);
160
+ else run.style.fontSize = String(style.fontSize) + 'px';
161
+ }
162
+ if (style.fontWeight !== undefined)
163
+ run.style.fontWeight = String(fontWeight(style.fontWeight, 400));
164
+ if (style.lineHeight !== undefined && !subscript)
165
+ run.style.lineHeight = String(style.lineHeight) + 'px';
166
+ if (style.lines !== undefined || style.truncate !== undefined)
167
+ run.style.whiteSpace = 'inherit';
168
+ });
169
+ if (style.alignment !== undefined) element.style.textAlign = style.alignment;
170
+ applyTextLayout(element, style, defaultLines);
171
+ }
172
+ export function fontWeight(
173
+ value: NativeListTextStyle['fontWeight'] | undefined,
174
+ fallback: number
175
+ ): number {
176
+ if (value === 'bold') return 700;
177
+ if (value === 'semibold') return 600;
178
+ if (value === 'medium') return 500;
179
+ if (value === 'regular') return 400;
180
+ return fallback;
181
+ }
@@ -0,0 +1,115 @@
1
+ import type {
2
+ TrailingAccessory,
3
+ ImageSource,
4
+ LeadingVisual,
5
+ NativeListTextStyle,
6
+ NativeListImageStyle,
7
+ } from '../../models';
8
+
9
+ export type RowPrimitives = Readonly<{
10
+ background: string;
11
+ icon: (element: HTMLElement, name: string) => void;
12
+ iconAction: (
13
+ name: string,
14
+ actionKey: string | undefined,
15
+ disabled?: boolean,
16
+ tintColor?: string
17
+ ) => HTMLElement;
18
+ accessory: (
19
+ rowKey: string,
20
+ descriptor: TrailingAccessory,
21
+ slot: number
22
+ ) => HTMLElement;
23
+ visual: (
24
+ source: LeadingVisual | undefined,
25
+ presentation?: string
26
+ ) => HTMLElement | undefined;
27
+ thumbnail: (source: ImageSource) => HTMLElement | undefined;
28
+ textStyle: (
29
+ element: HTMLElement,
30
+ style: NativeListTextStyle,
31
+ defaultLines?: number
32
+ ) => void;
33
+ dispose: (element: HTMLElement) => void;
34
+ }>;
35
+
36
+ const properties = [
37
+ 'width',
38
+ 'height',
39
+ 'flex-basis',
40
+ 'border-radius',
41
+ 'overflow',
42
+ 'object-fit',
43
+ 'margin-inline-end',
44
+ 'margin-bottom',
45
+ 'align-self',
46
+ 'border',
47
+ 'box-sizing',
48
+ 'clip-path',
49
+ 'flex',
50
+ ];
51
+
52
+ /** Restores factory geometry without touching async loading visibility. */
53
+ export class RowVisualStyle {
54
+ private readonly defaults = new Map<HTMLElement, Map<string, string>>();
55
+ constructor(private readonly view: HTMLElement) {
56
+ [view, ...view.querySelectorAll<HTMLElement>('*')].forEach((element) => {
57
+ this.defaults.set(
58
+ element,
59
+ new Map(
60
+ properties.map((key) => [key, element.style.getPropertyValue(key)])
61
+ )
62
+ );
63
+ });
64
+ }
65
+ restore() {
66
+ this.defaults.forEach((style, element) =>
67
+ style.forEach((value, key) => {
68
+ element.style.removeProperty(key);
69
+ if (value) element.style.setProperty(key, value);
70
+ })
71
+ );
72
+ }
73
+ apply(
74
+ image: NativeListImageStyle | undefined,
75
+ width: number,
76
+ height: number,
77
+ margin: number
78
+ ) {
79
+ this.restore();
80
+ const leading = this.view;
81
+ leading.style.width = `${width}px`;
82
+ leading.style.height = `${height}px`;
83
+ leading.style.flexBasis = `${width}px`;
84
+ leading.style.marginInlineEnd = `${margin}px`;
85
+ const radius =
86
+ image?.cornerRadius !== undefined
87
+ ? `${image.cornerRadius}px`
88
+ : image?.shape === 'circle'
89
+ ? '50%'
90
+ : image?.shape === 'square'
91
+ ? '0px'
92
+ : image?.shape === 'rounded'
93
+ ? '10px'
94
+ : undefined;
95
+ if (radius !== undefined) {
96
+ leading.style.setProperty('border-radius', radius, 'important');
97
+ leading.style.overflow = leading.matches('img') ? 'hidden' : 'visible';
98
+ }
99
+ const images = leading.matches('img')
100
+ ? [leading]
101
+ : leading.querySelectorAll<HTMLElement>(
102
+ ':scope > img:not(.ok-native-list-visual-corner), :scope > .ok-native-list-visual-fallback:not(.ok-native-list-visual-corner)'
103
+ );
104
+ images.forEach((bitmap) => {
105
+ if (bitmap !== leading) {
106
+ if (image?.width !== undefined) bitmap.style.width = '100%';
107
+ if (image?.height !== undefined) bitmap.style.height = '100%';
108
+ }
109
+ if (radius !== undefined) bitmap.style.borderRadius = radius;
110
+ if (image?.contentFit)
111
+ bitmap.style.objectFit =
112
+ image.contentFit === 'center' ? 'none' : image.contentFit;
113
+ });
114
+ }
115
+ }
@@ -0,0 +1,243 @@
1
+ import { applyTabularNumbers, hasExplicitRowHeight } from './RowElements';
2
+ import type { SectionHeaderRow } from '../../models';
3
+ import {
4
+ createElement,
5
+ setData,
6
+ tagSlot,
7
+ markActionAnchorSource,
8
+ createTextColumn,
9
+ } from './RowElements';
10
+ import { applyValueSegments } from './RowText';
11
+ import type { RowPrimitives } from './RowVisual';
12
+ function createSectionHeader(
13
+ document: Document,
14
+ primitives: RowPrimitives,
15
+ row: SectionHeaderRow
16
+ ): HTMLElement {
17
+ const body = createElement(
18
+ document,
19
+ 'div',
20
+ 'ok-native-list-row ok-native-list-section'
21
+ );
22
+ setData(body, 'variant', row.variant);
23
+ if (row.titleIcon) {
24
+ const titleIcon = primitives.iconAction(
25
+ row.titleIcon.name,
26
+ row.titleIcon.actionKey,
27
+ row.titleIcon.disabled,
28
+ row.titleIcon.tintColor
29
+ );
30
+ markActionAnchorSource(titleIcon, 'leadingAction');
31
+ body.appendChild(titleIcon);
32
+ }
33
+ // OneKey patch: section title help has its own measurable action target.
34
+ // body.appendChild(createTextColumn(document, row.title, row.subtitle));
35
+ const column = createTextColumn(document, row.title, row.subtitle);
36
+ const title = column.firstElementChild as HTMLElement;
37
+ title.classList.add('ok-native-list-section-title');
38
+ if (row.titleActionKey) {
39
+ setData(title, 'nativeListAction', row.titleActionKey);
40
+ markActionAnchorSource(title, 'leadingAction');
41
+ title.setAttribute('role', 'button');
42
+ title.tabIndex = 0;
43
+ title.style.alignSelf = 'flex-start';
44
+ title.style.maxWidth = '100%';
45
+ // OneKey patch: explicit network headers reserve a separate 3-point underline area.
46
+ if (row.presentation !== 'networkSelector' || !hasExplicitRowHeight(row)) {
47
+ title.style.textDecoration = 'underline dotted';
48
+ title.style.textUnderlineOffset = '6px';
49
+ }
50
+ if (row.titleActionOnHover) setData(title, 'nativeListHoverAction', true);
51
+ }
52
+ if (row.presentation === 'networkSelector' && hasExplicitRowHeight(row)) {
53
+ body.style.padding =
54
+ row.variant === 'summary' ? '24px 12px 20px' : '0 12px';
55
+ body.style.backgroundColor = 'var(--nl-bg)';
56
+ body.style.gap = row.checkbox ? '12px' : '8px';
57
+ title.style.fontSize = row.variant === 'summary' ? '16px' : '14px';
58
+ title.style.lineHeight = row.variant === 'summary' ? '24px' : '20px';
59
+ title.style.fontWeight =
60
+ row.variant === 'summary' || (row.titleActionKey && !row.checkbox)
61
+ ? '500'
62
+ : '600';
63
+ if (row.titleActionKey) {
64
+ const text = createElement(
65
+ document,
66
+ 'span',
67
+ 'ok-native-list-section-title-text',
68
+ row.title
69
+ );
70
+ text.style.overflow = 'hidden';
71
+ text.style.textOverflow = 'ellipsis';
72
+ text.style.maxWidth = '100%';
73
+ const dotted = document.createElementNS(
74
+ 'http://www.w3.org/2000/svg',
75
+ 'svg'
76
+ );
77
+ dotted.setAttribute('height', '2');
78
+ dotted.style.cssText =
79
+ 'display:block;position:absolute;left:0;bottom:0;width:100%;height:2px;color:var(--nl-secondary)';
80
+ const line = document.createElementNS(
81
+ 'http://www.w3.org/2000/svg',
82
+ 'line'
83
+ );
84
+ for (const [key, value] of Object.entries({
85
+ x1: '1',
86
+ y1: '1',
87
+ x2: '100%',
88
+ y2: '1',
89
+ stroke: 'currentColor',
90
+ 'stroke-width': '1.5',
91
+ 'stroke-dasharray': '0,4',
92
+ 'stroke-linecap': 'round',
93
+ }))
94
+ line.setAttribute(key, value);
95
+ // OneKey patch: keep both round caps inside the original full-width viewport.
96
+ const lineViewport = document.createElementNS(
97
+ 'http://www.w3.org/2000/svg',
98
+ 'svg'
99
+ );
100
+ lineViewport.setAttribute('width', 'calc(100% - 1px)');
101
+ lineViewport.setAttribute('height', '2');
102
+ lineViewport.setAttribute('overflow', 'visible');
103
+ lineViewport.appendChild(line);
104
+ dotted.appendChild(lineViewport);
105
+ // OneKey patch: SVG intrinsic width must not expand the title action beyond its text.
106
+ title.style.display = 'block';
107
+ title.style.position = 'relative';
108
+ title.style.width = 'fit-content';
109
+ title.style.paddingBottom = '3px';
110
+ text.style.display = 'block';
111
+ title.replaceChildren(text, dotted);
112
+ }
113
+ }
114
+ body.appendChild(column);
115
+ if (row.value) {
116
+ const value = tagSlot(
117
+ createElement(
118
+ document,
119
+ row.valueActionKey ? 'button' : 'span',
120
+ row.valueActionKey
121
+ ? 'ok-native-list-action-button ok-native-list-section-value'
122
+ : 'ok-native-list-value ok-native-list-section-value',
123
+ row.value
124
+ ),
125
+ 'value'
126
+ );
127
+ applyValueSegments(value, row.valueSegments);
128
+ if (row.presentation === 'networkSelector' && hasExplicitRowHeight(row)) {
129
+ value.style.fontFamily = 'inherit';
130
+ value.style.fontSize = '16px';
131
+ value.style.lineHeight = '24px';
132
+ value.style.fontWeight = '500';
133
+ if (row.valueActionKey) {
134
+ value.style.color = 'var(--nl-secondary)';
135
+ value.style.padding = '0';
136
+ value.style.flexShrink = '0';
137
+ }
138
+ }
139
+ if (row.valueActionTestID) setData(value, 'testid', row.valueActionTestID);
140
+ if (row.valueActionKey) {
141
+ value.setAttribute('type', 'button');
142
+ setData(value, 'nativeListAction', row.valueActionKey);
143
+ markActionAnchorSource(value, 'trailingAccessory', 0);
144
+ }
145
+ body.appendChild(value);
146
+ }
147
+ if (row.valueIcon) {
148
+ const valueIcon = primitives.iconAction(
149
+ row.valueIcon.name,
150
+ row.valueIcon.actionKey,
151
+ row.valueIcon.disabled,
152
+ row.valueIcon.tintColor
153
+ );
154
+ markActionAnchorSource(valueIcon, 'trailingAccessory', 1);
155
+ body.appendChild(valueIcon);
156
+ }
157
+ if (row.checkbox)
158
+ body.appendChild(primitives.accessory(row.key, row.checkbox, 0));
159
+ return body;
160
+ }
161
+ function bind(
162
+ body: HTMLElement,
163
+ row: SectionHeaderRow,
164
+ primitives: RowPrimitives
165
+ ) {
166
+ const next = createSectionHeader(body.ownerDocument, primitives, row);
167
+ body.replaceChildren(...Array.from(next.childNodes));
168
+ body.className = next.className;
169
+ body.style.cssText = next.style.cssText;
170
+ if (row.presentation === 'networkSelector') applyTabularNumbers(body);
171
+ body.dataset.variant = row.variant ?? '';
172
+ body.removeAttribute('data-nl-container-background');
173
+ body.removeAttribute('data-nl-container-border');
174
+ const style = row.style;
175
+ if (!style) return;
176
+ if (style.horizontalPadding !== undefined)
177
+ body.style.paddingInline = style.horizontalPadding + 'px';
178
+ if (style.verticalPadding !== undefined)
179
+ body.style.paddingBlock = style.verticalPadding + 'px';
180
+ if (style.lineGap !== undefined)
181
+ body
182
+ .querySelectorAll<HTMLElement>(':scope > .ok-native-list-flex')
183
+ .forEach((column) => {
184
+ column.style.rowGap = style.lineGap + 'px';
185
+ });
186
+ if (style.trailingGap !== undefined) {
187
+ const children = Array.from(body.children) as HTMLElement[];
188
+ const column = children.findIndex((child) =>
189
+ child.classList.contains('ok-native-list-flex')
190
+ );
191
+ children.slice(column + 2).forEach((child) => {
192
+ child.style.marginInlineStart =
193
+ 'calc(' +
194
+ style.trailingGap +
195
+ 'px - ' +
196
+ (body.style.gap || '12px') +
197
+ ')';
198
+ });
199
+ }
200
+ for (const slot of ['title', 'subtitle', 'value'] as const)
201
+ if (style[slot])
202
+ body
203
+ .querySelectorAll<HTMLElement>('[data-nl-slot="' + slot + '"]')
204
+ .forEach((node) => primitives.textStyle(node, style[slot]!));
205
+ }
206
+ function create(
207
+ document: Document,
208
+ row: SectionHeaderRow,
209
+ primitives: RowPrimitives
210
+ ) {
211
+ const body = document.createElement('div');
212
+ body.dataset.nlRenderer = 'sectionHeader';
213
+ bind(body, row, primitives);
214
+ return body;
215
+ }
216
+ export const sectionHeaderRowRenderer = {
217
+ key: 'sectionHeader' as const,
218
+ create,
219
+ bind,
220
+ recycle: (body: HTMLElement) => body.replaceChildren(),
221
+ appliesSizePreset: (row: SectionHeaderRow) =>
222
+ !['summary', 'gallery'].includes(row.variant ?? ''),
223
+ measure: (row: SectionHeaderRow, _width: number, layout = 'linear') =>
224
+ layout === 'table'
225
+ ? 28
226
+ : row.presentation === 'networkSelector'
227
+ ? 47
228
+ : row.variant === 'history'
229
+ ? 16
230
+ : row.variant === 'summary'
231
+ ? 68
232
+ : row.variant === 'gallery'
233
+ ? 32
234
+ : row.checkbox
235
+ ? 56
236
+ : layout === 'linear'
237
+ ? 30
238
+ : 36,
239
+ measureRendered: (
240
+ _body: HTMLElement,
241
+ _row: SectionHeaderRow
242
+ ): number | undefined => undefined,
243
+ };