@onekeyfe/react-native-native-list 6.7.0-alpha.424 → 6.7.0-alpha.428
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/NativeListIdentityRenderer.kt +82 -3
- package/android/src/main/java/com/onekey/nativelist/NativeListPrimitives.kt +6 -3
- package/android/src/main/java/com/onekey/nativelist/NativeListTitleSegmentLayout.kt +38 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListTitleSegmentsView.kt +105 -0
- package/android/src/test/java/com/margelo/nitro/nativelist/NativeListTitleSegmentLayoutTest.kt +65 -0
- package/docs/ROW_TEMPLATES.md +8 -1
- package/docs/SPEC.md +87 -1
- package/ios/NativeListIdentityRenderer.swift +86 -6
- package/ios/NativeListTitleSegmentLayout.swift +32 -0
- package/ios/NativeListTitleSegmentsLabel.swift +80 -0
- package/lib/module/models.js +2 -0
- package/lib/module/validation.js +70 -4
- package/lib/module/web/NativeListWebEngine.js +1 -1
- package/lib/module/web/templates/IdentityRowRenderer.js +99 -0
- package/lib/typescript/src/models.d.ts +21 -1
- package/package.json +3 -3
- package/src/models.ts +23 -0
- package/src/validation.ts +120 -1
- package/src/web/NativeListWebEngine.ts +1 -1
- package/src/web/templates/IdentityRowRenderer.ts +146 -0
package/src/validation.ts
CHANGED
|
@@ -1344,6 +1344,108 @@ function assertButtonGroup(
|
|
|
1344
1344
|
});
|
|
1345
1345
|
}
|
|
1346
1346
|
|
|
1347
|
+
const MAX_TITLE_SEGMENTS = 4;
|
|
1348
|
+
const HEX_COLOR_PATTERN = /^#[0-9a-f]{6}([0-9a-f]{2})?$/i;
|
|
1349
|
+
|
|
1350
|
+
function assertTitleSegments(value: unknown, path: string): void {
|
|
1351
|
+
if (
|
|
1352
|
+
!Array.isArray(value) ||
|
|
1353
|
+
value.length === 0 ||
|
|
1354
|
+
value.length > MAX_TITLE_SEGMENTS
|
|
1355
|
+
)
|
|
1356
|
+
fail(path, `must hold 1...${MAX_TITLE_SEGMENTS} segments`);
|
|
1357
|
+
let shrinking = 0;
|
|
1358
|
+
value.forEach((item: unknown, index) => {
|
|
1359
|
+
const segmentPath = `${path}[${index}]`;
|
|
1360
|
+
const segment = protocolObject(item, segmentPath);
|
|
1361
|
+
assertUnknownKeys(
|
|
1362
|
+
segment,
|
|
1363
|
+
['text', 'tone', 'fontWeight', 'shrink', 'maxWidthRatio'],
|
|
1364
|
+
segmentPath,
|
|
1365
|
+
'title segment key'
|
|
1366
|
+
);
|
|
1367
|
+
const { text, tone, fontWeight, shrink, maxWidthRatio } = segment;
|
|
1368
|
+
if (typeof text !== 'string' || !text.trim())
|
|
1369
|
+
fail(`${segmentPath}.text`, 'must be non-blank');
|
|
1370
|
+
assertText(text, `${segmentPath}.text`);
|
|
1371
|
+
if (tone !== undefined && tone !== 'primary' && tone !== 'secondary')
|
|
1372
|
+
fail(`${segmentPath}.tone`, 'must be primary or secondary');
|
|
1373
|
+
if (
|
|
1374
|
+
fontWeight !== undefined &&
|
|
1375
|
+
fontWeight !== 'regular' &&
|
|
1376
|
+
fontWeight !== 'medium'
|
|
1377
|
+
)
|
|
1378
|
+
fail(`${segmentPath}.fontWeight`, 'must be regular or medium');
|
|
1379
|
+
if (shrink !== undefined && typeof shrink !== 'boolean')
|
|
1380
|
+
fail(`${segmentPath}.shrink`, 'must be a boolean');
|
|
1381
|
+
if (shrink) shrinking += 1;
|
|
1382
|
+
if (
|
|
1383
|
+
maxWidthRatio !== undefined &&
|
|
1384
|
+
(typeof maxWidthRatio !== 'number' ||
|
|
1385
|
+
!Number.isFinite(maxWidthRatio) ||
|
|
1386
|
+
maxWidthRatio <= 0 ||
|
|
1387
|
+
maxWidthRatio > 1)
|
|
1388
|
+
)
|
|
1389
|
+
fail(`${segmentPath}.maxWidthRatio`, 'must be finite within (0, 1]');
|
|
1390
|
+
});
|
|
1391
|
+
if (shrinking > 1) fail(path, 'allows at most one shrinking segment');
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
function assertTitleLeadingIcon(value: unknown, path: string): void {
|
|
1395
|
+
const icon = protocolObject(value, path);
|
|
1396
|
+
assertUnknownKeys(
|
|
1397
|
+
icon,
|
|
1398
|
+
['name', 'tintColor', 'accessibilityLabel'],
|
|
1399
|
+
path,
|
|
1400
|
+
'title leading icon key'
|
|
1401
|
+
);
|
|
1402
|
+
const { name, tintColor, accessibilityLabel } = icon;
|
|
1403
|
+
if (typeof name !== 'string' || !name.trim())
|
|
1404
|
+
fail(`${path}.name`, 'must be non-blank');
|
|
1405
|
+
if (
|
|
1406
|
+
tintColor !== undefined &&
|
|
1407
|
+
(typeof tintColor !== 'string' || !HEX_COLOR_PATTERN.test(tintColor))
|
|
1408
|
+
)
|
|
1409
|
+
fail(`${path}.tintColor`, 'must be #RRGGBB or #RRGGBBAA');
|
|
1410
|
+
if (
|
|
1411
|
+
accessibilityLabel !== undefined &&
|
|
1412
|
+
typeof accessibilityLabel !== 'string'
|
|
1413
|
+
)
|
|
1414
|
+
fail(`${path}.accessibilityLabel`, 'must be a string');
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
function assertIdentityTitleRuns(
|
|
1418
|
+
row: Pick<
|
|
1419
|
+
IdentityRow,
|
|
1420
|
+
'titleSegments' | 'titleLeadingIcon' | 'titleMatch' | 'presentation'
|
|
1421
|
+
>,
|
|
1422
|
+
path: string
|
|
1423
|
+
): void {
|
|
1424
|
+
if (row.titleSegments !== undefined) {
|
|
1425
|
+
assertTitleSegments(row.titleSegments, `${path}.titleSegments`);
|
|
1426
|
+
// titleMatch ranges index `title`, which the runs replace on screen.
|
|
1427
|
+
if (row.titleMatch?.length)
|
|
1428
|
+
fail(`${path}.titleMatch`, 'cannot be combined with titleSegments');
|
|
1429
|
+
if (row.presentation === 'walletSidebar')
|
|
1430
|
+
fail(`${path}.titleSegments`, 'is not supported with walletSidebar');
|
|
1431
|
+
}
|
|
1432
|
+
if (row.titleLeadingIcon !== undefined) {
|
|
1433
|
+
assertTitleLeadingIcon(row.titleLeadingIcon, `${path}.titleLeadingIcon`);
|
|
1434
|
+
if (row.presentation === 'walletSidebar')
|
|
1435
|
+
fail(`${path}.titleLeadingIcon`, 'is not supported with walletSidebar');
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
/** Production keeps decorative title runs only when they pass the rules. */
|
|
1440
|
+
function passesTitleRunRules(check: () => void): boolean {
|
|
1441
|
+
try {
|
|
1442
|
+
check();
|
|
1443
|
+
return true;
|
|
1444
|
+
} catch {
|
|
1445
|
+
return false;
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1347
1449
|
function assertIdentityExtras(
|
|
1348
1450
|
row: Pick<
|
|
1349
1451
|
IdentityRow,
|
|
@@ -1834,6 +1936,7 @@ function assertRow(
|
|
|
1834
1936
|
);
|
|
1835
1937
|
});
|
|
1836
1938
|
assertIdentityExtras(row, path);
|
|
1939
|
+
assertIdentityTitleRuns(row, path);
|
|
1837
1940
|
assertText(row.subtitle, `${path}.subtitle`);
|
|
1838
1941
|
// OneKey patch: selector text segments truncate independently.
|
|
1839
1942
|
row.subtitleSegments?.forEach((segment, segmentIndex) => {
|
|
@@ -2416,6 +2519,8 @@ const ROW_FIELDS: Readonly<Record<string, readonly string[]>> = {
|
|
|
2416
2519
|
'titleIcon',
|
|
2417
2520
|
'secondaryTitleIcon',
|
|
2418
2521
|
'titleImage',
|
|
2522
|
+
'titleSegments',
|
|
2523
|
+
'titleLeadingIcon',
|
|
2419
2524
|
'subtitle',
|
|
2420
2525
|
'tertiary',
|
|
2421
2526
|
'tertiaryTone',
|
|
@@ -2593,6 +2698,8 @@ const PATCH_FIELDS: Readonly<Record<string, readonly string[]>> = {
|
|
|
2593
2698
|
'titleIcon',
|
|
2594
2699
|
'secondaryTitleIcon',
|
|
2595
2700
|
'titleImage',
|
|
2701
|
+
'titleSegments',
|
|
2702
|
+
'titleLeadingIcon',
|
|
2596
2703
|
'subtitle',
|
|
2597
2704
|
'tertiary',
|
|
2598
2705
|
'tertiaryTone',
|
|
@@ -2724,6 +2831,7 @@ function protocolKey(value: unknown, path: string): void {
|
|
|
2724
2831
|
const PROTOCOL_ARRAY_FIELDS = new Set([
|
|
2725
2832
|
'columns',
|
|
2726
2833
|
'titleSuffixes',
|
|
2834
|
+
'titleSegments',
|
|
2727
2835
|
'cells',
|
|
2728
2836
|
'points',
|
|
2729
2837
|
'images',
|
|
@@ -2965,7 +3073,10 @@ function assertRowProtocol(row: RowModel, path: string): void {
|
|
|
2965
3073
|
if (row.height !== undefined && row.height < 0)
|
|
2966
3074
|
fail(`${path}.height`, 'must be non-negative');
|
|
2967
3075
|
if (row.type === 'identity') {
|
|
2968
|
-
if (isDevelopment())
|
|
3076
|
+
if (isDevelopment()) {
|
|
3077
|
+
assertIdentityExtras(row, path);
|
|
3078
|
+
assertIdentityTitleRuns(row, path);
|
|
3079
|
+
}
|
|
2969
3080
|
if (row.titleSuffixes !== undefined && !Array.isArray(row.titleSuffixes))
|
|
2970
3081
|
fail(`${path}.titleSuffixes`, 'must be an array');
|
|
2971
3082
|
row.titleSuffixes?.forEach((suffix, index) => {
|
|
@@ -3560,6 +3671,14 @@ const NESTED_DECORATION_FIELDS: Readonly<Record<string, readonly string[]>> = {
|
|
|
3560
3671
|
|
|
3561
3672
|
function sanitizeDecoration(value: unknown, field: string): unknown {
|
|
3562
3673
|
if (value === undefined || value === null) return undefined;
|
|
3674
|
+
if (field === 'titleSegments')
|
|
3675
|
+
return passesTitleRunRules(() => assertTitleSegments(value, field))
|
|
3676
|
+
? value
|
|
3677
|
+
: undefined;
|
|
3678
|
+
if (field === 'titleLeadingIcon')
|
|
3679
|
+
return passesTitleRunRules(() => assertTitleLeadingIcon(value, field))
|
|
3680
|
+
? value
|
|
3681
|
+
: undefined;
|
|
3563
3682
|
if (
|
|
3564
3683
|
!Array.isArray(value) &&
|
|
3565
3684
|
[
|
|
@@ -845,7 +845,7 @@ export const WEB_LIST_CSS = `
|
|
|
845
845
|
.ok-native-list-trailing-button{appearance:none;box-sizing:border-box;flex:0 0 auto;padding:4px 10px;border:1px solid transparent;border-radius:9999px;background:var(--nl-button-bg,var(--nl-strong));color:var(--nl-button-text,var(--nl-primary));font:500 14px/20px var(--nl-font-medium);white-space:nowrap;cursor:pointer}.ok-native-list-trailing-button:hover:not(:disabled){background:var(--nl-button-hover,var(--nl-strong))}.ok-native-list-trailing-button:active:not(:disabled){background:var(--nl-button-pressed,var(--nl-pressed))}.ok-native-list-trailing-button:focus-visible{outline:2px solid var(--nl-button-focus,var(--nl-accent))}.ok-native-list-trailing-button:disabled{opacity:.4;cursor:default}
|
|
846
846
|
.ok-native-list-icon-button.ok-native-list-tertiary-icon{box-sizing:border-box;flex:0 0 38px;width:38px;height:38px;margin:-7px;padding:6px;border:1px solid transparent;border-radius:9999px;color:var(--nl-icon-subdued);background:transparent}.ok-native-list-icon-button.ok-native-list-tertiary-icon:hover:not(:disabled){background:var(--nl-hover)}.ok-native-list-icon-button.ok-native-list-tertiary-icon:active:not(:disabled){background:var(--nl-pressed)}.ok-native-list-icon-button.ok-native-list-tertiary-icon:disabled{opacity:.4;cursor:default}
|
|
847
847
|
.ok-native-list-icon-button.ok-native-list-tertiary-icon:focus-visible:not(:disabled){outline:2px solid var(--nl-accent)}
|
|
848
|
-
.ok-native-list-identity-title-icon{flex:0 0 20px;width:20px;height:20px;display:inline-flex;align-items:center;justify-content:center;color:var(--nl-icon);font-size:20px}.ok-native-list-identity-title-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
848
|
+
.ok-native-list-identity-title-icon{flex:0 0 20px;width:20px;height:20px;display:inline-flex;align-items:center;justify-content:center;color:var(--nl-icon);font-size:20px}.ok-native-list-identity-title-leading-icon{flex:0 0 16px;width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center;color:var(--nl-icon-subdued);font-size:16px}.ok-native-list-identity-title-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
849
849
|
.ok-native-list-account-row .ok-native-list-visual,.ok-native-list-account-action-row .ok-native-list-visual{width:32px;height:32px;flex-basis:32px}.ok-native-list-account-row .ok-native-list-visual>img,.ok-native-list-account-row .ok-native-list-visual-main,.ok-native-list-account-action-row .ok-native-list-visual>img,.ok-native-list-account-action-row .ok-native-list-visual-main{width:32px;height:32px}.ok-native-list-account-row .ok-native-list-visual>.ok-native-list-visual-corner{width:20px;height:20px;padding:2px}.ok-native-list-account-action-row .ok-native-list-visual{border-radius:8px!important}.ok-native-list-wallet-row .ok-native-list-title{color:var(--nl-secondary);font-size:12px;line-height:16px;font-weight:400;font-family:var(--nl-font-regular)}.ok-native-list-item[data-native-list-selected="true"]>.ok-native-list-wallet-row .ok-native-list-title{color:var(--nl-primary)}.ok-native-list-account-row .ok-native-list-title{font-size:16px;line-height:20px;font-weight:400;font-family:var(--nl-font-regular)}.ok-native-list-account-row .ok-native-list-secondary{font-size:14px;line-height:20px;font-weight:400;font-family:var(--nl-font-regular)}
|
|
850
850
|
.ok-native-list-flex{display:flex;flex:1;min-width:0;flex-direction:column;justify-content:center}.ok-native-list-title{font-size:15px;line-height:20px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:var(--nl-font-semibold)}.ok-native-list-secondary{font-size:13px;line-height:18px;color:var(--nl-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ok-native-list-tertiary{color:var(--nl-secondary)}.ok-native-list-info{color:var(--nl-info)}
|
|
851
851
|
.ok-native-list-identity-row .ok-native-list-title,.ok-native-list-identity-row .ok-native-list-amounts>span:first-child{font-size:16px;line-height:20px}.ok-native-list-identity-row .ok-native-list-secondary{font-size:14px;line-height:20px}
|
|
@@ -30,6 +30,79 @@ function toneColor(
|
|
|
30
30
|
if (tone === 'secondary') return 'var(--nl-secondary)';
|
|
31
31
|
return fallback === 'secondary' ? 'var(--nl-secondary)' : 'var(--nl-primary)';
|
|
32
32
|
}
|
|
33
|
+
// Hidden from sight, still read: the runs themselves are hidden from
|
|
34
|
+
// assistive technology in favor of `title`.
|
|
35
|
+
const VISUALLY_HIDDEN: Partial<CSSStyleDeclaration> = {
|
|
36
|
+
position: 'absolute',
|
|
37
|
+
width: '1px',
|
|
38
|
+
height: '1px',
|
|
39
|
+
overflow: 'hidden',
|
|
40
|
+
clip: 'rect(0 0 0 0)',
|
|
41
|
+
whiteSpace: 'nowrap',
|
|
42
|
+
};
|
|
43
|
+
function appendTitleRuns(
|
|
44
|
+
document: Document,
|
|
45
|
+
target: HTMLElement,
|
|
46
|
+
row: IdentityRow
|
|
47
|
+
): void {
|
|
48
|
+
const runs = createElement(
|
|
49
|
+
document,
|
|
50
|
+
'span',
|
|
51
|
+
'ok-native-list-identity-title-runs'
|
|
52
|
+
);
|
|
53
|
+
runs.setAttribute('aria-hidden', 'true');
|
|
54
|
+
Object.assign(runs.style, {
|
|
55
|
+
display: 'flex',
|
|
56
|
+
flex: '1 1 auto',
|
|
57
|
+
minWidth: '0',
|
|
58
|
+
maxWidth: '100%',
|
|
59
|
+
overflow: 'hidden',
|
|
60
|
+
});
|
|
61
|
+
row.titleSegments?.forEach((segment) => {
|
|
62
|
+
const run = createElement(
|
|
63
|
+
document,
|
|
64
|
+
'span',
|
|
65
|
+
'ok-native-list-identity-title-run',
|
|
66
|
+
segment.text
|
|
67
|
+
);
|
|
68
|
+
// Only the shrinking run gives up width; a cap is a share of the line.
|
|
69
|
+
Object.assign(run.style, {
|
|
70
|
+
flex: segment.shrink ? '0 1 auto' : '0 0 auto',
|
|
71
|
+
minWidth: segment.shrink ? '0' : '',
|
|
72
|
+
maxWidth:
|
|
73
|
+
segment.maxWidthRatio === undefined
|
|
74
|
+
? ''
|
|
75
|
+
: `${segment.maxWidthRatio * 100}%`,
|
|
76
|
+
overflow: 'hidden',
|
|
77
|
+
textOverflow: 'ellipsis',
|
|
78
|
+
whiteSpace: 'pre',
|
|
79
|
+
});
|
|
80
|
+
if (segment.tone)
|
|
81
|
+
run.style.color =
|
|
82
|
+
segment.tone === 'secondary'
|
|
83
|
+
? 'var(--nl-secondary)'
|
|
84
|
+
: 'var(--nl-primary)';
|
|
85
|
+
if (segment.fontWeight === 'medium') {
|
|
86
|
+
run.style.fontWeight = '500';
|
|
87
|
+
run.style.fontFamily = 'var(--nl-font-medium)';
|
|
88
|
+
} else if (segment.fontWeight === 'regular') {
|
|
89
|
+
run.style.fontWeight = '400';
|
|
90
|
+
run.style.fontFamily = 'var(--nl-font-regular)';
|
|
91
|
+
}
|
|
92
|
+
setData(run, 'tone', segment.tone);
|
|
93
|
+
runs.appendChild(run);
|
|
94
|
+
});
|
|
95
|
+
const spoken = createElement(
|
|
96
|
+
document,
|
|
97
|
+
'span',
|
|
98
|
+
'ok-native-list-identity-title-spoken',
|
|
99
|
+
row.title
|
|
100
|
+
);
|
|
101
|
+
Object.assign(spoken.style, VISUALLY_HIDDEN);
|
|
102
|
+
target.replaceChildren(runs, spoken);
|
|
103
|
+
target.style.display = 'flex';
|
|
104
|
+
target.style.minWidth = '0';
|
|
105
|
+
}
|
|
33
106
|
function appendAccessories(
|
|
34
107
|
parent: HTMLElement,
|
|
35
108
|
document: Document,
|
|
@@ -195,6 +268,18 @@ function createIdentityRow(
|
|
|
195
268
|
fragment.appendChild(document.createTextNode(row.title.slice(offset)));
|
|
196
269
|
textTarget.prepend(fragment);
|
|
197
270
|
}
|
|
271
|
+
// The runs replace the plain title, except where `title` itself is
|
|
272
|
+
// highlighted or shown in the wallet sidebar.
|
|
273
|
+
const hasTitleRuns =
|
|
274
|
+
!!row.titleSegments?.length &&
|
|
275
|
+
presentation !== 'walletSidebar' &&
|
|
276
|
+
!row.titleMatch?.length;
|
|
277
|
+
if (hasTitleRuns) {
|
|
278
|
+
const textTarget =
|
|
279
|
+
titleElement.querySelector<HTMLElement>('[data-nl-slot="title"]') ??
|
|
280
|
+
titleElement;
|
|
281
|
+
appendTitleRuns(document, textTarget, row);
|
|
282
|
+
}
|
|
198
283
|
if (row.subtitleSegments?.length) {
|
|
199
284
|
column.querySelector('.ok-native-list-secondary')?.remove();
|
|
200
285
|
const segments = createElement(
|
|
@@ -238,6 +323,14 @@ function createIdentityRow(
|
|
|
238
323
|
while (titleElement.firstChild && titleElement.firstChild !== badgeLine)
|
|
239
324
|
titleText.appendChild(titleElement.firstChild);
|
|
240
325
|
titleElement.prepend(titleText);
|
|
326
|
+
// The title slot tag moves with the text. `applyTextLayout` writes the
|
|
327
|
+
// single-line clamp (`display: block`, nowrap, ellipsis) onto the slot
|
|
328
|
+
// element; left on this container it would undo the flex row below and
|
|
329
|
+
// leave the inline-flex glyph baseline-aligned above the title (OK-66402).
|
|
330
|
+
if (titleElement.hasAttribute('data-nl-slot')) {
|
|
331
|
+
titleElement.removeAttribute('data-nl-slot');
|
|
332
|
+
tagSlot(titleText, 'title');
|
|
333
|
+
}
|
|
241
334
|
const icons = [row.titleIcon, row.secondaryTitleIcon]
|
|
242
335
|
.filter((icon): icon is NonNullable<typeof icon> => icon !== undefined)
|
|
243
336
|
.map((descriptor) => {
|
|
@@ -383,6 +476,58 @@ function createIdentityRow(
|
|
|
383
476
|
badges.style.minWidth = '0';
|
|
384
477
|
}
|
|
385
478
|
}
|
|
479
|
+
if (hasTitleRuns) {
|
|
480
|
+
// The runs fill what the title line leaves, so a ratio is a share of
|
|
481
|
+
// that width and title accessories sit at the line's end.
|
|
482
|
+
const runs = titleElement.querySelector<HTMLElement>(
|
|
483
|
+
'.ok-native-list-identity-title-runs'
|
|
484
|
+
);
|
|
485
|
+
for (
|
|
486
|
+
let node = runs?.parentElement;
|
|
487
|
+
node && node !== titleElement;
|
|
488
|
+
node = node.parentElement
|
|
489
|
+
) {
|
|
490
|
+
node.style.display = 'flex';
|
|
491
|
+
node.style.flex = '1 1 auto';
|
|
492
|
+
node.style.minWidth = '0';
|
|
493
|
+
}
|
|
494
|
+
titleElement.style.display = 'flex';
|
|
495
|
+
titleElement.style.alignItems = 'center';
|
|
496
|
+
}
|
|
497
|
+
if (row.titleLeadingIcon && presentation !== 'walletSidebar') {
|
|
498
|
+
const descriptor = row.titleLeadingIcon;
|
|
499
|
+
if (titleElement.hasAttribute('data-nl-slot')) {
|
|
500
|
+
// Keep the glyph out of the title slot that text styles apply to.
|
|
501
|
+
const titleText = tagSlot(
|
|
502
|
+
createElement(document, 'span', 'ok-native-list-identity-title-text'),
|
|
503
|
+
'title'
|
|
504
|
+
);
|
|
505
|
+
while (titleElement.firstChild)
|
|
506
|
+
titleText.appendChild(titleElement.firstChild);
|
|
507
|
+
if (hasTitleRuns) {
|
|
508
|
+
titleText.style.display = 'flex';
|
|
509
|
+
titleText.style.minWidth = '0';
|
|
510
|
+
}
|
|
511
|
+
titleElement.removeAttribute('data-nl-slot');
|
|
512
|
+
titleElement.appendChild(titleText);
|
|
513
|
+
}
|
|
514
|
+
const icon = primitives.iconAction(
|
|
515
|
+
descriptor.name,
|
|
516
|
+
undefined,
|
|
517
|
+
undefined,
|
|
518
|
+
descriptor.tintColor
|
|
519
|
+
);
|
|
520
|
+
icon.className = 'ok-native-list-identity-title-leading-icon';
|
|
521
|
+
if (descriptor.accessibilityLabel)
|
|
522
|
+
icon.setAttribute('aria-label', descriptor.accessibilityLabel);
|
|
523
|
+
else icon.setAttribute('aria-hidden', 'true');
|
|
524
|
+
titleElement.style.display = 'flex';
|
|
525
|
+
titleElement.style.alignItems = 'center';
|
|
526
|
+
// 6px to the title, whatever gap the title line already has.
|
|
527
|
+
const lineGap = Number.parseFloat(titleElement.style.gap || '0') || 0;
|
|
528
|
+
icon.style.marginInlineEnd = `${Math.max(0, 6 - lineGap)}px`;
|
|
529
|
+
titleElement.prepend(icon);
|
|
530
|
+
}
|
|
386
531
|
if (presentation === 'walletSidebar' && row.badges?.length) {
|
|
387
532
|
const badges = createElement(
|
|
388
533
|
document,
|
|
@@ -395,6 +540,7 @@ function createIdentityRow(
|
|
|
395
540
|
column.appendChild(badges);
|
|
396
541
|
}
|
|
397
542
|
for (const key of ['title', 'subtitle'] as const) {
|
|
543
|
+
if (key === 'title' && hasTitleRuns) continue;
|
|
398
544
|
const lines = row.style?.[key]?.lines ?? row[`${key}Lines`];
|
|
399
545
|
if (lines !== undefined)
|
|
400
546
|
column
|