@onekeyfe/react-native-native-list 6.7.0-alpha.378 → 6.7.0-alpha.382
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.
- package/android/src/main/java/com/onekey/nativelist/HybridNativeList.kt +14 -1
- package/android/src/main/java/com/onekey/nativelist/NativeListAccessoryStack.kt +240 -11
- package/android/src/main/java/com/onekey/nativelist/NativeListActivityDetailsView.kt +7 -4
- package/android/src/main/java/com/onekey/nativelist/NativeListActivityRenderer.kt +6 -3
- package/android/src/main/java/com/onekey/nativelist/NativeListButtonGroupRenderer.kt +102 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListContainerSlotAdapter.kt +12 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListDataRowRenderer.kt +87 -7
- package/android/src/main/java/com/onekey/nativelist/NativeListIdentityRenderer.kt +177 -1
- package/android/src/main/java/com/onekey/nativelist/NativeListLeadingVisual.kt +43 -14
- package/android/src/main/java/com/onekey/nativelist/NativeListMessageRenderer.kt +25 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListModels.kt +33 -2
- package/android/src/main/java/com/onekey/nativelist/NativeListPrimitives.kt +22 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRendererRegistry.kt +2 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRendererRowView.kt +2 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListResolvedText.kt +3 -2
- package/android/src/main/java/com/onekey/nativelist/NativeListSectionHeaderRenderer.kt +69 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListTextView.kt +55 -1
- package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +1912 -107
- package/android/src/test/java/com/margelo/nitro/nativelist/NativeListPressPolicyTest.kt +1 -0
- package/docs/ROW_TEMPLATES.md +60 -9
- package/docs/SPEC.md +450 -5
- package/docs/STYLE_SPEC.md +6 -0
- package/ios/HybridNativeList.swift +21 -2
- package/ios/NativeListAccessoryStack.swift +227 -39
- package/ios/NativeListActivityDetailsView.swift +18 -8
- package/ios/NativeListActivityRenderer.swift +8 -2
- package/ios/NativeListButtonGroupRenderer.swift +89 -0
- package/ios/NativeListDataRowRenderer.swift +155 -27
- package/ios/NativeListDesignAssets.swift +3 -0
- package/ios/NativeListIdentityRenderer.swift +166 -30
- package/ios/NativeListLeadingVisual.swift +49 -14
- package/ios/NativeListMessageRenderer.swift +34 -1
- package/ios/NativeListModels.swift +42 -2
- package/ios/NativeListRendererRegistry.swift +1 -0
- package/ios/NativeListResolvedText.swift +2 -1
- package/ios/NativeListRowHost.swift +14 -0
- package/ios/NativeListSectionHeaderRenderer.swift +88 -0
- package/ios/RNCNativeListView.swift +1013 -55
- package/ios/Resources/NativeListIcons.xcassets/onekey_crypto_coin_outline.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_crypto_coin_outline.imageset/icon.svg +4 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_gas_solid.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_gas_solid.imageset/icon.svg +3 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_refresh_ccw_outline.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_refresh_ccw_outline.imageset/icon.svg +3 -0
- package/ios/tests/NativeListActivityPresentationTests.swift +56 -0
- package/ios/tests/NativeListLifecycleTests.swift +2720 -3
- package/lib/module/NativeList.js +175 -28
- package/lib/module/NativeList.web.js +129 -30
- package/lib/module/index.js +1 -1
- package/lib/module/models.js +1 -0
- package/lib/module/selection.js +1 -1
- package/lib/module/validation.js +421 -8
- package/lib/module/web/NativeListWebEngine.js +507 -19
- package/lib/module/web/templates/ActivityRowRenderer.js +8 -7
- package/lib/module/web/templates/ButtonGroupRowRenderer.js +47 -0
- package/lib/module/web/templates/DataRowRenderer.js +40 -5
- package/lib/module/web/templates/IdentityRowRenderer.js +90 -4
- package/lib/module/web/templates/MessageRowRenderer.js +18 -2
- package/lib/module/web/templates/RowContainerStyle.js +1 -0
- package/lib/module/web/templates/RowRendererRegistry.js +3 -0
- package/lib/module/web/templates/SectionHeaderRowRenderer.js +36 -2
- package/lib/nitrogen/generated/android/c++/JHybridNativeListSpec.cpp +26 -0
- package/lib/nitrogen/generated/android/c++/JHybridNativeListSpec.hpp +4 -0
- package/lib/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.cpp +10 -0
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/HybridNativeListSpec.kt +20 -0
- package/lib/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.hpp +14 -0
- package/lib/nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm +12 -0
- package/lib/nitrogen/generated/ios/swift/HybridNativeListSpec.swift +2 -0
- package/lib/nitrogen/generated/ios/swift/HybridNativeListSpec_cxx.swift +43 -0
- package/lib/nitrogen/generated/shared/c++/HybridNativeListSpec.cpp +4 -0
- package/lib/nitrogen/generated/shared/c++/HybridNativeListSpec.hpp +4 -0
- package/lib/nitrogen/generated/shared/c++/views/HybridNativeListComponent.cpp +4 -0
- package/lib/nitrogen/generated/shared/c++/views/HybridNativeListComponent.hpp +6 -0
- package/lib/nitrogen/generated/shared/json/NativeListConfig.json +2 -0
- package/lib/typescript/src/NativeList.d.ts +1 -1
- package/lib/typescript/src/NativeList.nitro.d.ts +2 -0
- package/lib/typescript/src/NativeList.types.d.ts +18 -0
- package/lib/typescript/src/index.d.ts +2 -2
- package/lib/typescript/src/models.d.ts +105 -9
- package/lib/typescript/src/validation.d.ts +12 -0
- package/lib/typescript/src/web/NativeListWebEngine.d.ts +32 -0
- package/lib/typescript/src/web/templates/ButtonGroupRowRenderer.d.ts +14 -0
- package/lib/typescript/src/web/templates/IdentityRowRenderer.d.ts +1 -1
- package/lib/typescript/src/web/templates/MessageRowRenderer.d.ts +9 -3
- package/nitrogen/generated/android/c++/JHybridNativeListSpec.cpp +26 -0
- package/nitrogen/generated/android/c++/JHybridNativeListSpec.hpp +4 -0
- package/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.cpp +10 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/HybridNativeListSpec.kt +20 -0
- package/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.hpp +14 -0
- package/nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm +12 -0
- package/nitrogen/generated/ios/swift/HybridNativeListSpec.swift +2 -0
- package/nitrogen/generated/ios/swift/HybridNativeListSpec_cxx.swift +43 -0
- package/nitrogen/generated/shared/c++/HybridNativeListSpec.cpp +4 -0
- package/nitrogen/generated/shared/c++/HybridNativeListSpec.hpp +4 -0
- package/nitrogen/generated/shared/c++/views/HybridNativeListComponent.cpp +4 -0
- package/nitrogen/generated/shared/c++/views/HybridNativeListComponent.hpp +6 -0
- package/nitrogen/generated/shared/json/NativeListConfig.json +2 -0
- package/package.json +3 -3
- package/react-native-native-list.podspec +1 -0
- package/src/NativeList.nitro.ts +2 -0
- package/src/NativeList.tsx +313 -44
- package/src/NativeList.types.ts +22 -0
- package/src/NativeList.web.tsx +204 -48
- package/src/index.ts +2 -0
- package/src/models.ts +117 -3
- package/src/selection.ts +1 -0
- package/src/validation.ts +852 -6
- package/src/web/NativeListWebEngine.ts +803 -20
- package/src/web/templates/ActivityRowRenderer.ts +14 -6
- package/src/web/templates/ButtonGroupRowRenderer.ts +58 -0
- package/src/web/templates/DataRowRenderer.ts +93 -20
- package/src/web/templates/IdentityRowRenderer.ts +150 -5
- package/src/web/templates/MessageRowRenderer.ts +23 -7
- package/src/web/templates/RowContainerStyle.ts +2 -0
- package/src/web/templates/RowRendererRegistry.ts +11 -1
- package/src/web/templates/SectionHeaderRowRenderer.ts +47 -4
|
@@ -47,6 +47,7 @@ function bindLegacy(
|
|
|
47
47
|
}
|
|
48
48
|
const visualKey = JSON.stringify([
|
|
49
49
|
row.key,
|
|
50
|
+
row.hideLeading,
|
|
50
51
|
row.leading,
|
|
51
52
|
row.secondaryLeading,
|
|
52
53
|
]);
|
|
@@ -55,7 +56,7 @@ function bindLegacy(
|
|
|
55
56
|
primitives.dispose(node);
|
|
56
57
|
node.remove();
|
|
57
58
|
});
|
|
58
|
-
v.visuals = [row.leading, row.secondaryLeading]
|
|
59
|
+
v.visuals = (row.hideLeading ? [] : [row.leading, row.secondaryLeading])
|
|
59
60
|
.map((source) => primitives.visual(source))
|
|
60
61
|
.filter((node): node is HTMLElement => !!node);
|
|
61
62
|
v.visuals.forEach((node) => body.insertBefore(node, v.column));
|
|
@@ -389,11 +390,12 @@ function bindHistory(
|
|
|
389
390
|
Object.assign(v.identity.style, {
|
|
390
391
|
display: 'flex',
|
|
391
392
|
alignItems: 'center',
|
|
392
|
-
gap: '12px',
|
|
393
|
+
gap: row.hideLeading ? '0' : '12px',
|
|
393
394
|
minWidth: '0',
|
|
394
395
|
flex: '1 1 0',
|
|
395
396
|
});
|
|
396
397
|
Object.assign(v.visual.style, {
|
|
398
|
+
display: row.hideLeading ? 'none' : '',
|
|
397
399
|
position: 'relative',
|
|
398
400
|
width: '40px',
|
|
399
401
|
height: '40px',
|
|
@@ -401,6 +403,7 @@ function bindHistory(
|
|
|
401
403
|
});
|
|
402
404
|
const visualKey = JSON.stringify([
|
|
403
405
|
row.key,
|
|
406
|
+
row.hideLeading,
|
|
404
407
|
row.leading,
|
|
405
408
|
row.secondaryLeading,
|
|
406
409
|
]);
|
|
@@ -410,7 +413,9 @@ function bindHistory(
|
|
|
410
413
|
);
|
|
411
414
|
v.visual.replaceChildren();
|
|
412
415
|
v.visuals = [];
|
|
413
|
-
const sources =
|
|
416
|
+
const sources = row.hideLeading
|
|
417
|
+
? []
|
|
418
|
+
: [row.leading, row.secondaryLeading].filter(Boolean);
|
|
414
419
|
sources.forEach((source) => {
|
|
415
420
|
const visual = primitives.visual(source);
|
|
416
421
|
if (!visual) return;
|
|
@@ -439,7 +444,9 @@ function bindHistory(
|
|
|
439
444
|
});
|
|
440
445
|
v.visualKey = visualKey;
|
|
441
446
|
}
|
|
442
|
-
const sources =
|
|
447
|
+
const sources = row.hideLeading
|
|
448
|
+
? []
|
|
449
|
+
: [row.leading, row.secondaryLeading].filter(Boolean);
|
|
443
450
|
v.visuals.forEach((retained, index) => {
|
|
444
451
|
const { node: visual, style, background, loaded } = retained;
|
|
445
452
|
const source = sources[index];
|
|
@@ -773,8 +780,9 @@ function bindHistory(
|
|
|
773
780
|
20,
|
|
774
781
|
400
|
|
775
782
|
);
|
|
776
|
-
v.actions.style.cssText =
|
|
777
|
-
|
|
783
|
+
v.actions.style.cssText = `display:flex;gap:12px;padding-left:${
|
|
784
|
+
row.hideLeading ? 0 : 52
|
|
785
|
+
}px;padding-bottom:4px;`;
|
|
778
786
|
v.actions.style.display = footer ? 'flex' : 'none';
|
|
779
787
|
const actionKeys = new Set<string>();
|
|
780
788
|
for (const [index, action] of (row.footerActions ?? []).entries()) {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ButtonGroupRow } from '../../models';
|
|
2
|
+
import { markActionAnchorSource } from './RowElements';
|
|
3
|
+
import type { RowPrimitives } from './RowVisual';
|
|
4
|
+
|
|
5
|
+
function bind(body: HTMLElement, row: ButtonGroupRow) {
|
|
6
|
+
body.replaceChildren();
|
|
7
|
+
body.className = 'ok-native-list-row ok-native-list-button-group';
|
|
8
|
+
body.removeAttribute('data-nl-container-background');
|
|
9
|
+
body.removeAttribute('data-nl-container-border');
|
|
10
|
+
row.buttons.forEach((descriptor, index) => {
|
|
11
|
+
const button = body.ownerDocument.createElement('button');
|
|
12
|
+
button.type = 'button';
|
|
13
|
+
button.className = 'ok-native-list-block-button';
|
|
14
|
+
button.dataset.nativeListAction = descriptor.actionKey;
|
|
15
|
+
button.dataset.nlButtonKey = descriptor.key;
|
|
16
|
+
button.dataset.nlSlot = `button-${index}`;
|
|
17
|
+
if (descriptor.testID) button.dataset.testid = descriptor.testID;
|
|
18
|
+
button.setAttribute(
|
|
19
|
+
'aria-label',
|
|
20
|
+
descriptor.accessibilityLabel ?? descriptor.label
|
|
21
|
+
);
|
|
22
|
+
button.disabled = Boolean(
|
|
23
|
+
row.disabled || descriptor.disabled || descriptor.loading
|
|
24
|
+
);
|
|
25
|
+
button.setAttribute('aria-busy', descriptor.loading ? 'true' : 'false');
|
|
26
|
+
markActionAnchorSource(button, 'buttonGroup', index);
|
|
27
|
+
const label = body.ownerDocument.createElement('span');
|
|
28
|
+
label.textContent = descriptor.label;
|
|
29
|
+
if (descriptor.loading) {
|
|
30
|
+
const spinner = body.ownerDocument.createElement('span');
|
|
31
|
+
spinner.className = 'ok-native-list-spinner';
|
|
32
|
+
spinner.setAttribute('role', 'progressbar');
|
|
33
|
+
button.appendChild(spinner);
|
|
34
|
+
}
|
|
35
|
+
button.appendChild(label);
|
|
36
|
+
body.appendChild(button);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function create(
|
|
41
|
+
document: Document,
|
|
42
|
+
row: ButtonGroupRow,
|
|
43
|
+
_primitives: RowPrimitives
|
|
44
|
+
) {
|
|
45
|
+
const body = document.createElement('div');
|
|
46
|
+
body.dataset.nlRenderer = 'buttonGroup';
|
|
47
|
+
bind(body, row);
|
|
48
|
+
return body;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const buttonGroupRowRenderer = {
|
|
52
|
+
key: 'buttonGroup' as const,
|
|
53
|
+
create,
|
|
54
|
+
bind,
|
|
55
|
+
recycle: (body: HTMLElement) => body.replaceChildren(),
|
|
56
|
+
measure: (_row: ButtonGroupRow, _width: number) => 64,
|
|
57
|
+
measureRendered: (body: HTMLElement) => body.scrollHeight,
|
|
58
|
+
};
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import type { DataRow, TextTone } from '../../models';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
createElement,
|
|
4
|
+
markActionAnchorSource,
|
|
5
|
+
setData,
|
|
6
|
+
tagSlot,
|
|
7
|
+
} from './RowElements';
|
|
8
|
+
import { applyValueSegments, fontWeight } from './RowText';
|
|
3
9
|
import { RowVisualStyle, type RowPrimitives } from './RowVisual';
|
|
4
10
|
type ColumnViews = {
|
|
5
11
|
body: HTMLElement;
|
|
6
12
|
primaryLine: HTMLElement;
|
|
7
13
|
primary: HTMLElement;
|
|
14
|
+
titleIcons: HTMLElement;
|
|
8
15
|
badges: HTMLElement;
|
|
9
16
|
secondaryLine: HTMLElement;
|
|
10
17
|
secondary: HTMLElement[];
|
|
@@ -13,6 +20,7 @@ type Views = {
|
|
|
13
20
|
favorite: HTMLElement;
|
|
14
21
|
index: HTMLElement;
|
|
15
22
|
controls: HTMLElement;
|
|
23
|
+
trailing: HTMLElement;
|
|
16
24
|
columns: ColumnViews[];
|
|
17
25
|
visual?: HTMLElement;
|
|
18
26
|
visualStyle?: RowVisualStyle;
|
|
@@ -43,6 +51,11 @@ function bind(body: HTMLElement, row: DataRow, primitives: RowPrimitives) {
|
|
|
43
51
|
if (row.checkbox)
|
|
44
52
|
v.controls.appendChild(primitives.accessory(row.key, row.checkbox, 0));
|
|
45
53
|
v.controls.style.display = 'contents';
|
|
54
|
+
v.trailing.replaceChildren();
|
|
55
|
+
row.trailing?.forEach((accessory, index) =>
|
|
56
|
+
v.trailing.appendChild(primitives.accessory(row.key, accessory, index))
|
|
57
|
+
);
|
|
58
|
+
v.trailing.hidden = !row.trailing?.length;
|
|
46
59
|
v.index.style.cssText = '';
|
|
47
60
|
v.index.hidden = row.index === undefined;
|
|
48
61
|
v.index.textContent = String(row.index ?? '');
|
|
@@ -88,7 +101,41 @@ function bind(body: HTMLElement, row: DataRow, primitives: RowPrimitives) {
|
|
|
88
101
|
cell.primaryLine.style.gap = `${style.titleBadgeGap}px`;
|
|
89
102
|
cell.primary.style.cssText = '';
|
|
90
103
|
cell.primary.textContent = column.text;
|
|
104
|
+
applyValueSegments(
|
|
105
|
+
cell.primary,
|
|
106
|
+
column.textSegments,
|
|
107
|
+
style?.columns?.fontSize ?? 14,
|
|
108
|
+
style?.columns?.lineHeight ?? 20,
|
|
109
|
+
fontWeight(style?.columns?.fontWeight, 500)
|
|
110
|
+
);
|
|
91
111
|
if (style?.columns) primitives.textStyle(cell.primary, style.columns);
|
|
112
|
+
cell.titleIcons.replaceChildren();
|
|
113
|
+
if (column.titleIcon || column.secondaryTitleIcon) {
|
|
114
|
+
cell.primary.style.minWidth = '0';
|
|
115
|
+
cell.primary.style.overflow = 'hidden';
|
|
116
|
+
cell.primary.style.textOverflow = 'ellipsis';
|
|
117
|
+
cell.primary.style.whiteSpace = 'nowrap';
|
|
118
|
+
[column.titleIcon, column.secondaryTitleIcon]
|
|
119
|
+
.filter((icon): icon is NonNullable<typeof icon> => icon !== undefined)
|
|
120
|
+
.forEach((descriptor) => {
|
|
121
|
+
const icon = primitives.iconAction(
|
|
122
|
+
descriptor.name,
|
|
123
|
+
undefined,
|
|
124
|
+
undefined,
|
|
125
|
+
descriptor.tintColor
|
|
126
|
+
);
|
|
127
|
+
icon.className = 'ok-native-list-identity-title-icon';
|
|
128
|
+
if (descriptor.hoverActionKey) {
|
|
129
|
+
setData(icon, 'nativeListHoverAction', descriptor.hoverActionKey);
|
|
130
|
+
setData(icon, 'nativeListIconHelp', true);
|
|
131
|
+
markActionAnchorSource(icon, 'leadingAction');
|
|
132
|
+
}
|
|
133
|
+
if (descriptor.accessibilityLabel)
|
|
134
|
+
icon.setAttribute('aria-label', descriptor.accessibilityLabel);
|
|
135
|
+
else icon.setAttribute('aria-hidden', 'true');
|
|
136
|
+
cell.titleIcons.appendChild(icon);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
92
139
|
cell.badges.replaceChildren();
|
|
93
140
|
cell.badges.style.display = 'contents';
|
|
94
141
|
if (column.key === 'asset')
|
|
@@ -107,25 +154,34 @@ function bind(body: HTMLElement, row: DataRow, primitives: RowPrimitives) {
|
|
|
107
154
|
});
|
|
108
155
|
// Legacy Web layout: secondary leading text sits inline before the primary
|
|
109
156
|
// text; secondary text is a direct line below it, toned by secondaryTone.
|
|
110
|
-
|
|
111
|
-
? '
|
|
112
|
-
:
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
157
|
+
const secondaryText = column.secondaryTextSegments?.length
|
|
158
|
+
? column.secondaryTextSegments.map((segment) => segment.text).join('')
|
|
159
|
+
: column.secondaryText;
|
|
160
|
+
cell.secondaryLine.style.display = secondaryText ? 'contents' : 'none';
|
|
161
|
+
[column.secondaryLeadingText, secondaryText].forEach((text, slot) => {
|
|
162
|
+
const label = cell.secondary[slot]!;
|
|
163
|
+
label.hidden = !text;
|
|
164
|
+
if (!text) label.remove();
|
|
165
|
+
else if (slot === 0) cell.primaryLine.insertBefore(label, cell.primary);
|
|
166
|
+
else cell.secondaryLine.appendChild(label);
|
|
167
|
+
label.style.cssText = '';
|
|
168
|
+
label.textContent = text ?? '';
|
|
169
|
+
if (slot === 1) {
|
|
170
|
+
applyValueSegments(
|
|
171
|
+
label,
|
|
172
|
+
column.secondaryTextSegments,
|
|
173
|
+
style?.columnSecondary?.fontSize ?? 12,
|
|
174
|
+
style?.columnSecondary?.lineHeight ?? 16,
|
|
175
|
+
fontWeight(style?.columnSecondary?.fontWeight, 400)
|
|
176
|
+
);
|
|
126
177
|
}
|
|
127
|
-
|
|
178
|
+
if (slot === 1)
|
|
179
|
+
label.style.color = tone(column.secondaryTone, 'secondary');
|
|
180
|
+
if (style?.columnSecondary)
|
|
181
|
+
primitives.textStyle(label, style.columnSecondary);
|
|
182
|
+
});
|
|
128
183
|
});
|
|
184
|
+
body.appendChild(v.trailing);
|
|
129
185
|
}
|
|
130
186
|
function create(document: Document, row: DataRow, primitives: RowPrimitives) {
|
|
131
187
|
const body = createElement(
|
|
@@ -140,6 +196,11 @@ function create(document: Document, row: DataRow, primitives: RowPrimitives) {
|
|
|
140
196
|
);
|
|
141
197
|
const favorite = createElement(document, 'span', 'ok-native-list-favorite');
|
|
142
198
|
const controls = createElement(document, 'span');
|
|
199
|
+
const trailing = createElement(
|
|
200
|
+
document,
|
|
201
|
+
'span',
|
|
202
|
+
'ok-native-list-accessories'
|
|
203
|
+
);
|
|
143
204
|
body.append(controls, index, favorite);
|
|
144
205
|
const columns = Array.from({ length: 4 }, () => {
|
|
145
206
|
const cell = createElement(document, 'span', 'ok-native-list-data-cell');
|
|
@@ -149,8 +210,10 @@ function create(document: Document, row: DataRow, primitives: RowPrimitives) {
|
|
|
149
210
|
'ok-native-list-data-primary'
|
|
150
211
|
);
|
|
151
212
|
const primary = tagSlot(createElement(document, 'span'), 'columns');
|
|
213
|
+
const titleIcons = createElement(document, 'span');
|
|
214
|
+
titleIcons.style.display = 'contents';
|
|
152
215
|
const badges = createElement(document, 'span');
|
|
153
|
-
primaryLine.append(primary, badges);
|
|
216
|
+
primaryLine.append(primary, titleIcons, badges);
|
|
154
217
|
const secondaryLine = createElement(
|
|
155
218
|
document,
|
|
156
219
|
'span',
|
|
@@ -169,15 +232,18 @@ function create(document: Document, row: DataRow, primitives: RowPrimitives) {
|
|
|
169
232
|
body: cell,
|
|
170
233
|
primaryLine,
|
|
171
234
|
primary,
|
|
235
|
+
titleIcons,
|
|
172
236
|
badges,
|
|
173
237
|
secondaryLine,
|
|
174
238
|
secondary,
|
|
175
239
|
};
|
|
176
240
|
});
|
|
241
|
+
body.appendChild(trailing);
|
|
177
242
|
views.set(body, {
|
|
178
243
|
favorite,
|
|
179
244
|
index,
|
|
180
245
|
controls,
|
|
246
|
+
trailing,
|
|
181
247
|
columns,
|
|
182
248
|
visualKey: '',
|
|
183
249
|
primitives,
|
|
@@ -196,6 +262,7 @@ function recycle(body: HTMLElement) {
|
|
|
196
262
|
v.visualStyle = undefined;
|
|
197
263
|
v.visualKey = '';
|
|
198
264
|
v.controls.replaceChildren();
|
|
265
|
+
v.trailing.replaceChildren();
|
|
199
266
|
}
|
|
200
267
|
export const dataRowRenderer = {
|
|
201
268
|
key: 'dataRow' as const,
|
|
@@ -204,7 +271,13 @@ export const dataRowRenderer = {
|
|
|
204
271
|
recycle,
|
|
205
272
|
// Legacy presets: table rows without secondary text are 8 units shorter.
|
|
206
273
|
measure: (row: DataRow, _width: number, layout?: string) => {
|
|
207
|
-
const secondary = row.columns.some((column) =>
|
|
274
|
+
const secondary = row.columns.some((column) =>
|
|
275
|
+
column.secondaryTextSegments?.length
|
|
276
|
+
? column.secondaryTextSegments.some(
|
|
277
|
+
(segment) => segment.text.length > 0
|
|
278
|
+
)
|
|
279
|
+
: !!column.secondaryText
|
|
280
|
+
);
|
|
208
281
|
return (secondary ? 60 : 56) + (layout === 'table' && !secondary ? -8 : 0);
|
|
209
282
|
},
|
|
210
283
|
measureRendered: (_body: HTMLElement, _row: DataRow): number | undefined =>
|
|
@@ -226,6 +226,117 @@ function createIdentityRow(
|
|
|
226
226
|
});
|
|
227
227
|
column.insertBefore(segments, titleElement.nextSibling);
|
|
228
228
|
}
|
|
229
|
+
if (row.titleIcon || row.secondaryTitleIcon) {
|
|
230
|
+
const badgeLine = titleElement.querySelector<HTMLElement>(
|
|
231
|
+
':scope > .ok-native-list-badges'
|
|
232
|
+
);
|
|
233
|
+
const titleText = createElement(
|
|
234
|
+
document,
|
|
235
|
+
'span',
|
|
236
|
+
'ok-native-list-identity-title-text'
|
|
237
|
+
);
|
|
238
|
+
while (titleElement.firstChild && titleElement.firstChild !== badgeLine)
|
|
239
|
+
titleText.appendChild(titleElement.firstChild);
|
|
240
|
+
titleElement.prepend(titleText);
|
|
241
|
+
const icons = [row.titleIcon, row.secondaryTitleIcon]
|
|
242
|
+
.filter((icon): icon is NonNullable<typeof icon> => icon !== undefined)
|
|
243
|
+
.map((descriptor) => {
|
|
244
|
+
const icon = primitives.iconAction(
|
|
245
|
+
descriptor.name,
|
|
246
|
+
undefined,
|
|
247
|
+
undefined,
|
|
248
|
+
descriptor.tintColor
|
|
249
|
+
);
|
|
250
|
+
icon.className = 'ok-native-list-identity-title-icon';
|
|
251
|
+
if (descriptor.hoverActionKey) {
|
|
252
|
+
setData(icon, 'nativeListHoverAction', descriptor.hoverActionKey);
|
|
253
|
+
setData(icon, 'nativeListIconHelp', true);
|
|
254
|
+
markActionAnchorSource(icon, 'leadingAction');
|
|
255
|
+
}
|
|
256
|
+
if (descriptor.accessibilityLabel)
|
|
257
|
+
icon.setAttribute('aria-label', descriptor.accessibilityLabel);
|
|
258
|
+
else icon.setAttribute('aria-hidden', 'true');
|
|
259
|
+
return icon;
|
|
260
|
+
});
|
|
261
|
+
titleText.after(...icons);
|
|
262
|
+
titleElement.style.display = 'flex';
|
|
263
|
+
titleElement.style.alignItems = 'center';
|
|
264
|
+
titleElement.style.gap = '4px';
|
|
265
|
+
}
|
|
266
|
+
if (row.titleSuffixes?.length) {
|
|
267
|
+
const badges = titleElement.querySelector(
|
|
268
|
+
':scope > .ok-native-list-badges'
|
|
269
|
+
);
|
|
270
|
+
let titleText = titleElement.querySelector<HTMLElement>(
|
|
271
|
+
':scope > .ok-native-list-identity-title-text, :scope > [data-nl-slot="title"]'
|
|
272
|
+
);
|
|
273
|
+
if (!titleText) {
|
|
274
|
+
titleText = tagSlot(
|
|
275
|
+
createElement(document, 'span', 'ok-native-list-identity-title-text'),
|
|
276
|
+
'title'
|
|
277
|
+
);
|
|
278
|
+
while (titleElement.firstChild && titleElement.firstChild !== badges)
|
|
279
|
+
titleText.appendChild(titleElement.firstChild);
|
|
280
|
+
titleElement.prepend(titleText);
|
|
281
|
+
titleElement.removeAttribute('data-nl-slot');
|
|
282
|
+
} else if (titleElement.hasAttribute('data-nl-slot')) {
|
|
283
|
+
titleElement.removeAttribute('data-nl-slot');
|
|
284
|
+
tagSlot(titleText, 'title');
|
|
285
|
+
}
|
|
286
|
+
titleElement.style.display = 'flex';
|
|
287
|
+
titleElement.style.alignItems = 'center';
|
|
288
|
+
titleText.style.flex = '0 1 auto';
|
|
289
|
+
titleText.style.minWidth = 'min(80px, 100%)';
|
|
290
|
+
titleText.style.overflow = 'hidden';
|
|
291
|
+
titleText.style.textOverflow = 'ellipsis';
|
|
292
|
+
titleText.style.whiteSpace = 'nowrap';
|
|
293
|
+
row.titleSuffixes.forEach((suffix) => {
|
|
294
|
+
const label = createElement(
|
|
295
|
+
document,
|
|
296
|
+
'span',
|
|
297
|
+
'ok-native-list-identity-title-suffix',
|
|
298
|
+
suffix.text
|
|
299
|
+
);
|
|
300
|
+
label.style.flex = '0 1 auto';
|
|
301
|
+
label.style.minWidth = '0';
|
|
302
|
+
label.style.marginInlineStart =
|
|
303
|
+
row.titleIcon || row.secondaryTitleIcon ? '4px' : '8px';
|
|
304
|
+
label.style.maxWidth =
|
|
305
|
+
suffix.maxWidth === undefined ? '' : `${suffix.maxWidth}px`;
|
|
306
|
+
label.style.overflow = 'hidden';
|
|
307
|
+
label.style.textOverflow = 'ellipsis';
|
|
308
|
+
label.style.whiteSpace = 'nowrap';
|
|
309
|
+
label.style.fontSize = '12px';
|
|
310
|
+
label.style.lineHeight = '16px';
|
|
311
|
+
label.style.fontWeight = '400';
|
|
312
|
+
label.style.fontFamily = 'var(--nl-font-regular)';
|
|
313
|
+
label.style.color =
|
|
314
|
+
suffix.tone === 'disabled'
|
|
315
|
+
? 'var(--nl-disabled)'
|
|
316
|
+
: 'var(--nl-secondary)';
|
|
317
|
+
titleElement.insertBefore(label, badges);
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
if (row.badges?.length && !row.titleIcon && !row.secondaryTitleIcon) {
|
|
321
|
+
const titleText = titleElement.querySelector<HTMLElement>(
|
|
322
|
+
':scope > [data-nl-slot="title"]'
|
|
323
|
+
);
|
|
324
|
+
const badges = titleElement.querySelector<HTMLElement>(
|
|
325
|
+
':scope > .ok-native-list-badges'
|
|
326
|
+
);
|
|
327
|
+
titleElement.style.display = 'flex';
|
|
328
|
+
titleElement.style.alignItems = 'center';
|
|
329
|
+
if (titleText) {
|
|
330
|
+
titleText.style.flex = '0 1 auto';
|
|
331
|
+
titleText.style.minWidth = row.titleSuffixes?.length
|
|
332
|
+
? 'min(80px, 100%)'
|
|
333
|
+
: '0';
|
|
334
|
+
}
|
|
335
|
+
if (badges) {
|
|
336
|
+
badges.style.flex = '0 1 auto';
|
|
337
|
+
badges.style.minWidth = '0';
|
|
338
|
+
}
|
|
339
|
+
}
|
|
229
340
|
if (presentation === 'walletSidebar' && row.badges?.length) {
|
|
230
341
|
const badges = createElement(
|
|
231
342
|
document,
|
|
@@ -242,7 +353,13 @@ function createIdentityRow(
|
|
|
242
353
|
if (lines !== undefined)
|
|
243
354
|
column
|
|
244
355
|
.querySelectorAll<HTMLElement>(`[data-nl-slot="${key}"]`)
|
|
245
|
-
.forEach((text) =>
|
|
356
|
+
.forEach((text) =>
|
|
357
|
+
applyTextLayout(
|
|
358
|
+
text,
|
|
359
|
+
lines === 0 ? {} : { lines },
|
|
360
|
+
lines === 0 ? 0 : undefined
|
|
361
|
+
)
|
|
362
|
+
);
|
|
246
363
|
}
|
|
247
364
|
}
|
|
248
365
|
body.appendChild(column);
|
|
@@ -272,6 +389,29 @@ function applyIdentityStyle(body: HTMLElement, row: IdentityRow) {
|
|
|
272
389
|
const leading = body.querySelector<HTMLElement>(
|
|
273
390
|
':scope > .ok-native-list-visual, :scope > .ok-native-list-stacked'
|
|
274
391
|
);
|
|
392
|
+
if (row.style?.leadingContentMaxWidthRatio !== undefined && !vertical) {
|
|
393
|
+
const column = body.querySelector<HTMLElement>(
|
|
394
|
+
':scope > .ok-native-list-flex'
|
|
395
|
+
);
|
|
396
|
+
const trailing = body.querySelector<HTMLElement>(
|
|
397
|
+
':scope > .ok-native-list-accessories'
|
|
398
|
+
);
|
|
399
|
+
const visualWidth = leading
|
|
400
|
+
? row.style.image?.width ??
|
|
401
|
+
(row.presentation === 'accountSelector' ||
|
|
402
|
+
row.presentation === 'networkSelector'
|
|
403
|
+
? 32
|
|
404
|
+
: 40)
|
|
405
|
+
: 0;
|
|
406
|
+
const gap = leading ? row.style.leadingGap ?? 12 : 0;
|
|
407
|
+
if (column) {
|
|
408
|
+
column.style.flex = '0 1 auto';
|
|
409
|
+
column.style.maxWidth = `calc(${
|
|
410
|
+
row.style.leadingContentMaxWidthRatio * 100
|
|
411
|
+
}% - ${visualWidth + gap}px)`;
|
|
412
|
+
}
|
|
413
|
+
if (trailing) trailing.style.marginInlineStart = 'auto';
|
|
414
|
+
}
|
|
275
415
|
const defaultGap =
|
|
276
416
|
body.style.gap ||
|
|
277
417
|
(row.type === 'identity' && row.presentation === 'walletSidebar'
|
|
@@ -343,7 +483,7 @@ function applyIdentityStyle(body: HTMLElement, row: IdentityRow) {
|
|
|
343
483
|
const images = leading.matches('img')
|
|
344
484
|
? [leading]
|
|
345
485
|
: leading.querySelectorAll<HTMLElement>(
|
|
346
|
-
':scope > img, :scope > .ok-native-list-visual-fallback'
|
|
486
|
+
':scope > img:not(.ok-native-list-visual-corner), :scope > .ok-native-list-visual-fallback:not(.ok-native-list-visual-corner)'
|
|
347
487
|
);
|
|
348
488
|
images.forEach((bitmap) => {
|
|
349
489
|
if (bitmap !== leading) {
|
|
@@ -522,7 +662,12 @@ export const identityRowRenderer = {
|
|
|
522
662
|
? 60
|
|
523
663
|
: 56,
|
|
524
664
|
measureRendered: (
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
): number | undefined =>
|
|
665
|
+
body: HTMLElement,
|
|
666
|
+
row: IdentityRow
|
|
667
|
+
): number | undefined => {
|
|
668
|
+
if (row.contentHeight !== 'auto' || hasExplicitRowHeight(row))
|
|
669
|
+
return undefined;
|
|
670
|
+
const height = body.getBoundingClientRect().height;
|
|
671
|
+
return height > 0 ? height : undefined;
|
|
672
|
+
},
|
|
528
673
|
};
|
|
@@ -4,10 +4,8 @@ import type { MessageRow, NativeListTextStyle } from '../../models';
|
|
|
4
4
|
|
|
5
5
|
type Text = Readonly<{
|
|
6
6
|
value: string;
|
|
7
|
-
style: Required<
|
|
8
|
-
|
|
9
|
-
> &
|
|
10
|
-
NativeListTextStyle;
|
|
7
|
+
style: Required<Pick<NativeListTextStyle, 'fontSize' | 'lineHeight'>> &
|
|
8
|
+
Omit<NativeListTextStyle, 'lines'> & { lines: 0 | 1 | 2 | 3 };
|
|
11
9
|
}>;
|
|
12
10
|
export function resolveMessageRow(row: MessageRow) {
|
|
13
11
|
const text = (
|
|
@@ -15,7 +13,7 @@ export function resolveMessageRow(row: MessageRow) {
|
|
|
15
13
|
style: NativeListTextStyle | undefined,
|
|
16
14
|
fontSize: number,
|
|
17
15
|
lineHeight: number,
|
|
18
|
-
lines: 1 | 2 | 3,
|
|
16
|
+
lines: 0 | 1 | 2 | 3,
|
|
19
17
|
color: string,
|
|
20
18
|
fontWeight: NativeListTextStyle['fontWeight'] = 'regular'
|
|
21
19
|
): Text => ({
|
|
@@ -117,6 +115,9 @@ export function bindMessageRow(
|
|
|
117
115
|
body.style.cssText = '';
|
|
118
116
|
body.removeAttribute('data-nl-container-background');
|
|
119
117
|
body.removeAttribute('data-nl-container-border');
|
|
118
|
+
if (row.presentation === 'inlineWarning')
|
|
119
|
+
body.setAttribute('data-nl-inline-warning', 'true');
|
|
120
|
+
else body.removeAttribute('data-nl-inline-warning');
|
|
120
121
|
body.style.padding = `${resolved.verticalPadding}px ${resolved.horizontalPadding}px`;
|
|
121
122
|
body.style.height = resolved.automaticHeight ? 'auto' : '100%';
|
|
122
123
|
views.column.style.cssText = '';
|
|
@@ -128,7 +129,19 @@ export function bindMessageRow(
|
|
|
128
129
|
] as const) {
|
|
129
130
|
view.style.cssText = '';
|
|
130
131
|
view.textContent = text.value;
|
|
131
|
-
|
|
132
|
+
const { lines, ...textStyle } = text.style;
|
|
133
|
+
primitives.textStyle(
|
|
134
|
+
view,
|
|
135
|
+
lines === 0 ? textStyle : { ...textStyle, lines }
|
|
136
|
+
);
|
|
137
|
+
if (lines === 0) {
|
|
138
|
+
view.style.whiteSpace = 'pre-wrap';
|
|
139
|
+
view.style.overflow = 'visible';
|
|
140
|
+
view.style.textOverflow = 'clip';
|
|
141
|
+
view.style.maxHeight = 'none';
|
|
142
|
+
view.style.removeProperty('-webkit-line-clamp');
|
|
143
|
+
view.style.removeProperty('-webkit-box-orient');
|
|
144
|
+
}
|
|
132
145
|
}
|
|
133
146
|
views.unread.style.cssText = '';
|
|
134
147
|
if (row.body) {
|
|
@@ -258,7 +271,10 @@ export function measureMessageRow(
|
|
|
258
271
|
),
|
|
259
272
|
0
|
|
260
273
|
);
|
|
261
|
-
return
|
|
274
|
+
return (
|
|
275
|
+
(text.style.lines === 0 ? lines : Math.min(text.style.lines, lines)) *
|
|
276
|
+
text.style.lineHeight
|
|
277
|
+
);
|
|
262
278
|
};
|
|
263
279
|
const timeWidth = Math.min(
|
|
264
280
|
availableWidth / 3,
|
|
@@ -88,6 +88,8 @@ export function applyRowContainerStyle(body: HTMLElement, row: RowModel): void {
|
|
|
88
88
|
}
|
|
89
89
|
if (container.cornerRadius !== undefined)
|
|
90
90
|
set(body, 'border-radius', `${container.cornerRadius}px`);
|
|
91
|
+
if (row.type === 'message' && row.presentation === 'inlineWarning')
|
|
92
|
+
set(body, 'border-radius', '0px');
|
|
91
93
|
if (container.borderWidth !== undefined) {
|
|
92
94
|
// Paint above member backgrounds without changing the content box or hit targets.
|
|
93
95
|
body.setAttribute('data-nl-container-border', 'true');
|
|
@@ -16,8 +16,15 @@ import type { SystemRow } from '../../models';
|
|
|
16
16
|
import { systemRowRenderer } from './SystemRowRenderer';
|
|
17
17
|
import type { ActionRow } from '../../models';
|
|
18
18
|
import { actionRowRenderer } from './ActionRowRenderer';
|
|
19
|
+
import { buttonGroupRowRenderer } from './ButtonGroupRowRenderer';
|
|
19
20
|
import { mediaTileRowRenderer } from './MediaTileRowRenderer';
|
|
20
|
-
import type {
|
|
21
|
+
import type {
|
|
22
|
+
ButtonGroupRow,
|
|
23
|
+
MessageRow,
|
|
24
|
+
RailRow,
|
|
25
|
+
MediaTileRow,
|
|
26
|
+
RowModel,
|
|
27
|
+
} from '../../models';
|
|
21
28
|
import { messageRowRenderer } from './MessageRowRenderer';
|
|
22
29
|
import type { RowPrimitives } from './RowVisual';
|
|
23
30
|
import { railRowRenderer } from './RailRowRenderer';
|
|
@@ -71,6 +78,8 @@ const factories = {
|
|
|
71
78
|
registration(activityRowRenderer, row as ActivityRow),
|
|
72
79
|
system: (row: RowModel) => registration(systemRowRenderer, row as SystemRow),
|
|
73
80
|
action: (row: RowModel) => registration(actionRowRenderer, row as ActionRow),
|
|
81
|
+
buttonGroup: (row: RowModel) =>
|
|
82
|
+
registration(buttonGroupRowRenderer, row as ButtonGroupRow),
|
|
74
83
|
message: (row: RowModel) =>
|
|
75
84
|
registration(messageRowRenderer, row as MessageRow),
|
|
76
85
|
rail: (row: RowModel) => registration(railRowRenderer, row as RailRow),
|
|
@@ -91,6 +100,7 @@ const renderers = {
|
|
|
91
100
|
activity: activityRowRenderer,
|
|
92
101
|
system: systemRowRenderer,
|
|
93
102
|
action: actionRowRenderer,
|
|
103
|
+
buttonGroup: buttonGroupRowRenderer,
|
|
94
104
|
message: messageRowRenderer,
|
|
95
105
|
rail: railRowRenderer,
|
|
96
106
|
mediaTile: mediaTileRowRenderer,
|