@onekeyfe/react-native-native-list 6.7.0-alpha.430 → 6.7.0-alpha.435

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.
@@ -702,66 +702,6 @@ function assertButtonGroup(row, path) {
702
702
  }
703
703
  });
704
704
  }
705
- const MAX_TITLE_SEGMENTS = 4;
706
- const HEX_COLOR_PATTERN = /^#[0-9a-f]{6}([0-9a-f]{2})?$/i;
707
- function assertTitleSegments(value, path) {
708
- if (!Array.isArray(value) || value.length === 0 || value.length > MAX_TITLE_SEGMENTS) fail(path, `must hold 1...${MAX_TITLE_SEGMENTS} segments`);
709
- let shrinking = 0;
710
- value.forEach((item, index) => {
711
- const segmentPath = `${path}[${index}]`;
712
- const segment = protocolObject(item, segmentPath);
713
- assertUnknownKeys(segment, ['text', 'tone', 'fontWeight', 'shrink', 'maxWidthRatio'], segmentPath, 'title segment key');
714
- const {
715
- text,
716
- tone,
717
- fontWeight,
718
- shrink,
719
- maxWidthRatio
720
- } = segment;
721
- if (typeof text !== 'string' || !text.trim()) fail(`${segmentPath}.text`, 'must be non-blank');
722
- assertText(text, `${segmentPath}.text`);
723
- if (tone !== undefined && tone !== 'primary' && tone !== 'secondary') fail(`${segmentPath}.tone`, 'must be primary or secondary');
724
- if (fontWeight !== undefined && fontWeight !== 'regular' && fontWeight !== 'medium') fail(`${segmentPath}.fontWeight`, 'must be regular or medium');
725
- if (shrink !== undefined && typeof shrink !== 'boolean') fail(`${segmentPath}.shrink`, 'must be a boolean');
726
- if (shrink) shrinking += 1;
727
- if (maxWidthRatio !== undefined && (typeof maxWidthRatio !== 'number' || !Number.isFinite(maxWidthRatio) || maxWidthRatio <= 0 || maxWidthRatio > 1)) fail(`${segmentPath}.maxWidthRatio`, 'must be finite within (0, 1]');
728
- });
729
- if (shrinking > 1) fail(path, 'allows at most one shrinking segment');
730
- }
731
- function assertTitleLeadingIcon(value, path) {
732
- const icon = protocolObject(value, path);
733
- assertUnknownKeys(icon, ['name', 'tintColor', 'accessibilityLabel'], path, 'title leading icon key');
734
- const {
735
- name,
736
- tintColor,
737
- accessibilityLabel
738
- } = icon;
739
- if (typeof name !== 'string' || !name.trim()) fail(`${path}.name`, 'must be non-blank');
740
- if (tintColor !== undefined && (typeof tintColor !== 'string' || !HEX_COLOR_PATTERN.test(tintColor))) fail(`${path}.tintColor`, 'must be #RRGGBB or #RRGGBBAA');
741
- if (accessibilityLabel !== undefined && typeof accessibilityLabel !== 'string') fail(`${path}.accessibilityLabel`, 'must be a string');
742
- }
743
- function assertIdentityTitleRuns(row, path) {
744
- if (row.titleSegments !== undefined) {
745
- assertTitleSegments(row.titleSegments, `${path}.titleSegments`);
746
- // titleMatch ranges index `title`, which the runs replace on screen.
747
- if (row.titleMatch?.length) fail(`${path}.titleMatch`, 'cannot be combined with titleSegments');
748
- if (row.presentation === 'walletSidebar') fail(`${path}.titleSegments`, 'is not supported with walletSidebar');
749
- }
750
- if (row.titleLeadingIcon !== undefined) {
751
- assertTitleLeadingIcon(row.titleLeadingIcon, `${path}.titleLeadingIcon`);
752
- if (row.presentation === 'walletSidebar') fail(`${path}.titleLeadingIcon`, 'is not supported with walletSidebar');
753
- }
754
- }
755
-
756
- /** Production keeps decorative title runs only when they pass the rules. */
757
- function passesTitleRunRules(check) {
758
- try {
759
- check();
760
- return true;
761
- } catch {
762
- return false;
763
- }
764
- }
765
705
  function assertIdentityExtras(row, path) {
766
706
  for (const field of ['titleIcon', 'secondaryTitleIcon']) {
767
707
  const titleIcon = row[field];
@@ -993,7 +933,6 @@ function assertRow(row, index, path = `rows[${index}]`) {
993
933
  if (suffix.maxWidth !== undefined && (!Number.isFinite(suffix.maxWidth) || suffix.maxWidth < 0 || suffix.maxWidth > 4096)) fail(`${path}.titleSuffixes[${index}].maxWidth`, 'must be finite within 0...4096');
994
934
  });
995
935
  assertIdentityExtras(row, path);
996
- assertIdentityTitleRuns(row, path);
997
936
  assertText(row.subtitle, `${path}.subtitle`);
998
937
  // OneKey patch: selector text segments truncate independently.
999
938
  row.subtitleSegments?.forEach((segment, segmentIndex) => {
@@ -1287,7 +1226,7 @@ function assertSnapshotContract(snapshot) {
1287
1226
  }
1288
1227
  const COMMON_ROW_FIELDS = ['height', 'heightRounding', 'testID', 'opacity', 'backgroundColor', 'backgroundFullWidth', 'pressDisabled', 'key', 'revision', 'sectionKey', 'groupId', 'groupPosition', 'size', 'density', 'disabled', 'selected', 'accessibilityLabel', 'separator', 'type', 'style'];
1289
1228
  const ROW_FIELDS = {
1290
- identity: [...COMMON_ROW_FIELDS, 'contentHeight', 'longPressActionKey', 'titleMatch', 'titleActionKey', 'titleActionOnHover', 'subtitleSegments', 'presentation', 'leading', 'leadingAction', 'title', 'titleSuffixes', 'titleIcon', 'secondaryTitleIcon', 'titleImage', 'titleSegments', 'titleLeadingIcon', 'subtitle', 'tertiary', 'tertiaryTone', 'titleLines', 'subtitleLines', 'badges', 'trailing', 'draggable'],
1229
+ identity: [...COMMON_ROW_FIELDS, 'contentHeight', 'longPressActionKey', 'titleMatch', 'titleActionKey', 'titleActionOnHover', 'subtitleSegments', 'presentation', 'leading', 'leadingAction', 'title', 'titleSuffixes', 'titleIcon', 'secondaryTitleIcon', 'titleImage', 'subtitle', 'tertiary', 'tertiaryTone', 'titleLines', 'subtitleLines', 'badges', 'trailing', 'draggable'],
1291
1230
  walletGroup: [...COMMON_ROW_FIELDS, 'parent', 'children', 'draggable'],
1292
1231
  rail: [...COMMON_ROW_FIELDS, 'visual', 'title', 'status', 'badge', 'draggable'],
1293
1232
  activity: [...COMMON_ROW_FIELDS, 'leading', 'hideLeading', 'secondaryLeading', 'title', 'description', 'status', 'primaryAmount', 'secondaryAmount', 'amounts', 'badges', 'presentation', 'fee', 'descriptionActionKey', 'footerActions'],
@@ -1303,7 +1242,7 @@ const ROW_FIELDS = {
1303
1242
  };
1304
1243
  const COMMON_PATCH_FIELDS = ['height', 'heightRounding', 'opacity', 'pressDisabled', 'revision', 'disabled', 'selected', 'accessibilityLabel', 'separator', 'style'];
1305
1244
  const PATCH_FIELDS = {
1306
- identity: [...COMMON_PATCH_FIELDS, 'contentHeight', 'longPressActionKey', 'titleMatch', 'titleActionKey', 'titleActionOnHover', 'subtitleSegments', 'leading', 'leadingAction', 'title', 'titleSuffixes', 'titleIcon', 'secondaryTitleIcon', 'titleImage', 'titleSegments', 'titleLeadingIcon', 'subtitle', 'tertiary', 'tertiaryTone', 'subtitleLines', 'badges', 'trailing'],
1245
+ identity: [...COMMON_PATCH_FIELDS, 'contentHeight', 'longPressActionKey', 'titleMatch', 'titleActionKey', 'titleActionOnHover', 'subtitleSegments', 'leading', 'leadingAction', 'title', 'titleSuffixes', 'titleIcon', 'secondaryTitleIcon', 'titleImage', 'subtitle', 'tertiary', 'tertiaryTone', 'subtitleLines', 'badges', 'trailing'],
1307
1246
  rail: [...COMMON_PATCH_FIELDS, 'title', 'visual', 'status', 'badge'],
1308
1247
  activity: [...COMMON_PATCH_FIELDS, 'presentation', 'leading', 'title', 'badges', 'status', 'hideLeading', 'secondaryLeading', 'description', 'primaryAmount', 'secondaryAmount', 'amounts', 'fee', 'descriptionActionKey', 'footerActions'],
1309
1248
  message: [...COMMON_PATCH_FIELDS, 'presentation', 'title', 'unread', 'body', 'bodyLines', 'time', 'thumbnail'],
@@ -1323,7 +1262,7 @@ function protocolObject(value, path) {
1323
1262
  function protocolKey(value, path) {
1324
1263
  if (typeof value !== 'string' || value.trim().length === 0) fail(path, 'must be a non-blank string');
1325
1264
  }
1326
- const PROTOCOL_ARRAY_FIELDS = new Set(['columns', 'titleSuffixes', 'titleSegments', 'cells', 'points', 'images', 'overlays', 'badges', 'trailing', 'footerActions', 'buttons', 'amounts', 'metrics', 'children', 'subtitleSegments', 'titleMatch', 'selectedKeys', 'segments', 'hoverSecondary', 'hoverImages', 'secondaryBadges', 'fallbackUris', 'probeOrder', 'priceSegments', 'textSegments', 'secondaryTextSegments', 'primaryTextSegments']);
1265
+ const PROTOCOL_ARRAY_FIELDS = new Set(['columns', 'titleSuffixes', 'cells', 'points', 'images', 'overlays', 'badges', 'trailing', 'footerActions', 'buttons', 'amounts', 'metrics', 'children', 'subtitleSegments', 'titleMatch', 'selectedKeys', 'segments', 'hoverSecondary', 'hoverImages', 'secondaryBadges', 'fallbackUris', 'probeOrder', 'priceSegments', 'textSegments', 'secondaryTextSegments', 'primaryTextSegments']);
1327
1266
  const PROTOCOL_NUMBER_FIELDS = new Set(['leadingContentMaxWidthRatio', 'height', 'width', 'fontSize', 'lineHeight', 'opacity', 'offsetY', 'offsetX', 'cornerRadius', 'borderWidth', 'horizontalPadding', 'verticalPadding', 'leadingGap', 'lineGap', 'titleBadgeGap', 'trailingGap', 'start', 'end', 'padding', 'offset', 'overscan', 'minWidth', 'flex', 'paddingStart', 'paddingEnd', 'changeWidth', 'changeHeight', 'changeCornerRadius', 'contentTrailingGap', 'subtitleTrailingPadding', 'partGap', 'contentPadding', 'contentPaddingHorizontal', 'contentPaddingTop', 'contentPaddingBottom', 'itemSpacing', 'gridColumns']);
1328
1267
 
1329
1268
  /** Validate only shapes that renderers dereference, not display budgets. */
@@ -1394,10 +1333,7 @@ function assertRowProtocol(row, path) {
1394
1333
  }
1395
1334
  if (row.height !== undefined && row.height < 0) fail(`${path}.height`, 'must be non-negative');
1396
1335
  if (row.type === 'identity') {
1397
- if (isDevelopment()) {
1398
- assertIdentityExtras(row, path);
1399
- assertIdentityTitleRuns(row, path);
1400
- }
1336
+ if (isDevelopment()) assertIdentityExtras(row, path);
1401
1337
  if (row.titleSuffixes !== undefined && !Array.isArray(row.titleSuffixes)) fail(`${path}.titleSuffixes`, 'must be an array');
1402
1338
  row.titleSuffixes?.forEach((suffix, index) => {
1403
1339
  protocolObject(suffix, `${path}.titleSuffixes[${index}]`);
@@ -1647,8 +1583,6 @@ const NESTED_DECORATION_FIELDS = {
1647
1583
  };
1648
1584
  function sanitizeDecoration(value, field) {
1649
1585
  if (value === undefined || value === null) return undefined;
1650
- if (field === 'titleSegments') return passesTitleRunRules(() => assertTitleSegments(value, field)) ? value : undefined;
1651
- if (field === 'titleLeadingIcon') return passesTitleRunRules(() => assertTitleLeadingIcon(value, field)) ? value : undefined;
1652
1586
  if (!Array.isArray(value) && ['image', 'networkImage', 'thumbnail', 'source', 'images', 'hoverImages'].includes(field)) return sanitizeImage(value);
1653
1587
  if (['titleImage', 'titleIcon', 'secondaryTitleIcon', 'fallbackIcon', 'cornerIcon', 'media'].includes(field) && !isRecord(value)) return undefined;
1654
1588
  if (field === 'style' && typeof value !== 'string' && !isRecord(value)) return undefined;
@@ -467,7 +467,7 @@ export const WEB_LIST_CSS = `
467
467
  .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}
468
468
  .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}
469
469
  .ok-native-list-icon-button.ok-native-list-tertiary-icon:focus-visible:not(:disabled){outline:2px solid var(--nl-accent)}
470
- .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}
470
+ .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}
471
471
  .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)}
472
472
  .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)}
473
473
  .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}
@@ -11,54 +11,6 @@ function toneColor(tone, fallback) {
11
11
  if (tone === 'secondary') return 'var(--nl-secondary)';
12
12
  return fallback === 'secondary' ? 'var(--nl-secondary)' : 'var(--nl-primary)';
13
13
  }
14
- // Hidden from sight, still read: the runs themselves are hidden from
15
- // assistive technology in favor of `title`.
16
- const VISUALLY_HIDDEN = {
17
- position: 'absolute',
18
- width: '1px',
19
- height: '1px',
20
- overflow: 'hidden',
21
- clip: 'rect(0 0 0 0)',
22
- whiteSpace: 'nowrap'
23
- };
24
- function appendTitleRuns(document, target, row) {
25
- const runs = createElement(document, 'span', 'ok-native-list-identity-title-runs');
26
- runs.setAttribute('aria-hidden', 'true');
27
- Object.assign(runs.style, {
28
- display: 'flex',
29
- flex: '1 1 auto',
30
- minWidth: '0',
31
- maxWidth: '100%',
32
- overflow: 'hidden'
33
- });
34
- row.titleSegments?.forEach(segment => {
35
- const run = createElement(document, 'span', 'ok-native-list-identity-title-run', segment.text);
36
- // Only the shrinking run gives up width; a cap is a share of the line.
37
- Object.assign(run.style, {
38
- flex: segment.shrink ? '0 1 auto' : '0 0 auto',
39
- minWidth: segment.shrink ? '0' : '',
40
- maxWidth: segment.maxWidthRatio === undefined ? '' : `${segment.maxWidthRatio * 100}%`,
41
- overflow: 'hidden',
42
- textOverflow: 'ellipsis',
43
- whiteSpace: 'pre'
44
- });
45
- if (segment.tone) run.style.color = segment.tone === 'secondary' ? 'var(--nl-secondary)' : 'var(--nl-primary)';
46
- if (segment.fontWeight === 'medium') {
47
- run.style.fontWeight = '500';
48
- run.style.fontFamily = 'var(--nl-font-medium)';
49
- } else if (segment.fontWeight === 'regular') {
50
- run.style.fontWeight = '400';
51
- run.style.fontFamily = 'var(--nl-font-regular)';
52
- }
53
- setData(run, 'tone', segment.tone);
54
- runs.appendChild(run);
55
- });
56
- const spoken = createElement(document, 'span', 'ok-native-list-identity-title-spoken', row.title);
57
- Object.assign(spoken.style, VISUALLY_HIDDEN);
58
- target.replaceChildren(runs, spoken);
59
- target.style.display = 'flex';
60
- target.style.minWidth = '0';
61
- }
62
14
  function appendAccessories(parent, document, primitives, row, accessories) {
63
15
  if (!accessories?.length) return;
64
16
  const container = createElement(document, 'span', 'ok-native-list-accessories');
@@ -134,13 +86,6 @@ function createIdentityRow(document, primitives, row) {
134
86
  fragment.appendChild(document.createTextNode(row.title.slice(offset)));
135
87
  textTarget.prepend(fragment);
136
88
  }
137
- // The runs replace the plain title, except where `title` itself is
138
- // highlighted or shown in the wallet sidebar.
139
- const hasTitleRuns = !!row.titleSegments?.length && presentation !== 'walletSidebar' && !row.titleMatch?.length;
140
- if (hasTitleRuns) {
141
- const textTarget = titleElement.querySelector('[data-nl-slot="title"]') ?? titleElement;
142
- appendTitleRuns(document, textTarget, row);
143
- }
144
89
  if (row.subtitleSegments?.length) {
145
90
  column.querySelector('.ok-native-list-secondary')?.remove();
146
91
  const segments = createElement(document, 'span', 'ok-native-list-subtitle-segments');
@@ -266,48 +211,12 @@ function createIdentityRow(document, primitives, row) {
266
211
  badges.style.minWidth = '0';
267
212
  }
268
213
  }
269
- if (hasTitleRuns) {
270
- // The runs fill what the title line leaves, so a ratio is a share of
271
- // that width and title accessories sit at the line's end.
272
- const runs = titleElement.querySelector('.ok-native-list-identity-title-runs');
273
- for (let node = runs?.parentElement; node && node !== titleElement; node = node.parentElement) {
274
- node.style.display = 'flex';
275
- node.style.flex = '1 1 auto';
276
- node.style.minWidth = '0';
277
- }
278
- titleElement.style.display = 'flex';
279
- titleElement.style.alignItems = 'center';
280
- }
281
- if (row.titleLeadingIcon && presentation !== 'walletSidebar') {
282
- const descriptor = row.titleLeadingIcon;
283
- if (titleElement.hasAttribute('data-nl-slot')) {
284
- // Keep the glyph out of the title slot that text styles apply to.
285
- const titleText = tagSlot(createElement(document, 'span', 'ok-native-list-identity-title-text'), 'title');
286
- while (titleElement.firstChild) titleText.appendChild(titleElement.firstChild);
287
- if (hasTitleRuns) {
288
- titleText.style.display = 'flex';
289
- titleText.style.minWidth = '0';
290
- }
291
- titleElement.removeAttribute('data-nl-slot');
292
- titleElement.appendChild(titleText);
293
- }
294
- const icon = primitives.iconAction(descriptor.name, undefined, undefined, descriptor.tintColor);
295
- icon.className = 'ok-native-list-identity-title-leading-icon';
296
- if (descriptor.accessibilityLabel) icon.setAttribute('aria-label', descriptor.accessibilityLabel);else icon.setAttribute('aria-hidden', 'true');
297
- titleElement.style.display = 'flex';
298
- titleElement.style.alignItems = 'center';
299
- // 6px to the title, whatever gap the title line already has.
300
- const lineGap = Number.parseFloat(titleElement.style.gap || '0') || 0;
301
- icon.style.marginInlineEnd = `${Math.max(0, 6 - lineGap)}px`;
302
- titleElement.prepend(icon);
303
- }
304
214
  if (presentation === 'walletSidebar' && row.badges?.length) {
305
215
  const badges = createElement(document, 'span', 'ok-native-list-wallet-badges');
306
216
  row.badges.forEach(badge => badges.appendChild(createBadge(document, badge)));
307
217
  column.appendChild(badges);
308
218
  }
309
219
  for (const key of ['title', 'subtitle']) {
310
- if (key === 'title' && hasTitleRuns) continue;
311
220
  const lines = row.style?.[key]?.lines ?? row[`${key}Lines`];
312
221
  if (lines !== undefined) column.querySelectorAll(`[data-nl-slot="${key}"]`).forEach(text => applyTextLayout(text, lines === 0 ? {} : {
313
222
  lines
@@ -1,6 +1,6 @@
1
1
  import type { ScrollEdgeEffect } from './ScrollEdgeEffect';
2
2
  import type { ReactNode, RefObject } from 'react';
3
- import type { View, ViewProps } from 'react-native';
3
+ import type { ViewInstance, ViewProps } from 'react-native';
4
4
  import type { ActionAnchorInvalidatedEvent, EndReachedEvent, NativeListSnapshot, ReorderEvent, RowActionEvent, RowModel, RowPatch, SelectionDeltaEvent, VisibleRangeChangedEvent } from './models';
5
5
  export type ActionAnchorState = Readonly<{
6
6
  token: string;
@@ -114,7 +114,7 @@ export type NativeListProps = Omit<ViewProps, 'children'> & Readonly<{
114
114
  /** Web only: visible sticky chrome above the parent's list viewport. */
115
115
  webStickyInset?: number;
116
116
  /** Web only. Hosts the section index inside this container. */
117
- webSectionIndexContainerRef?: RefObject<View | null>;
117
+ webSectionIndexContainerRef?: RefObject<ViewInstance | null>;
118
118
  /** Defaults to `none`. `interactive` behaves as `none` on Android. */
119
119
  keyboardDismissMode?: NativeListKeyboardDismissMode;
120
120
  /**
@@ -394,18 +394,6 @@ export type RowBase = Readonly<{
394
394
  accessibilityLabel?: string;
395
395
  separator?: boolean;
396
396
  }>;
397
- /** One run of an identity title line; see docs/SPEC.md. */
398
- export type IdentityTitleSegment = Readonly<{
399
- text: string;
400
- /** Omitted: the title color. */
401
- tone?: 'primary' | 'secondary';
402
- /** Omitted: the title weight. */
403
- fontWeight?: 'regular' | 'medium';
404
- /** The one run that gives up width when the line is too narrow. */
405
- shrink?: boolean;
406
- /** Caps the run at this fraction of the title line, within (0, 1]. */
407
- maxWidthRatio?: number;
408
- }>;
409
397
  export type IdentityRow = RowBase & Readonly<{
410
398
  type: 'identity';
411
399
  /** Opt in to content-based height; explicit row/container height still wins. */
@@ -440,14 +428,6 @@ export type IdentityRow = RowBase & Readonly<{
440
428
  }>;
441
429
  /** Web-only additional help icon after titleIcon. */
442
430
  secondaryTitleIcon?: IdentityRow['titleIcon'];
443
- /** Runs drawn in place of `title`, which stays the spoken label. */
444
- titleSegments?: readonly IdentityTitleSegment[];
445
- /** 16-point glyph before the title; decorative unless labelled. */
446
- titleLeadingIcon?: Readonly<{
447
- name: string;
448
- tintColor?: string;
449
- accessibilityLabel?: string;
450
- }>;
451
431
  /** Circular image after title icons; image dimensions must be square, 1...40. */
452
432
  titleImage?: Readonly<{
453
433
  image: ImageSource;
@@ -900,7 +880,7 @@ export type PatchClearableChanges<Row, Keys extends keyof Row> = Readonly<{
900
880
  export type RowPatch = Readonly<{
901
881
  type: 'identity';
902
882
  key: string;
903
- changes: PatchClearableChanges<IdentityRow, CommonPatchFields | 'title' | 'titleSuffixes' | 'titleIcon' | 'secondaryTitleIcon' | 'titleImage' | 'titleSegments' | 'titleLeadingIcon' | 'subtitle' | 'subtitleLines' | 'contentHeight' | 'longPressActionKey' | 'tertiary' | 'tertiaryTone' | 'badges' | 'trailing' | 'leading' | 'leadingAction' | 'titleMatch' | 'titleActionKey' | 'titleActionOnHover' | 'subtitleSegments'>;
883
+ changes: PatchClearableChanges<IdentityRow, CommonPatchFields | 'title' | 'titleSuffixes' | 'titleIcon' | 'secondaryTitleIcon' | 'titleImage' | 'subtitle' | 'subtitleLines' | 'contentHeight' | 'longPressActionKey' | 'tertiary' | 'tertiaryTone' | 'badges' | 'trailing' | 'leading' | 'leadingAction' | 'titleMatch' | 'titleActionKey' | 'titleActionOnHover' | 'subtitleSegments'>;
904
884
  }> | Readonly<{
905
885
  type: 'rail';
906
886
  key: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-native-list",
3
- "version": "6.7.0-alpha.430",
3
+ "version": "6.7.0-alpha.435",
4
4
  "description": "Template-driven native RecyclerView and UICollectionView for React Native",
5
5
  "source": "./src/index.ts",
6
6
  "main": "./lib/module/index.js",
@@ -70,10 +70,10 @@
70
70
  "@eslint/compat": "^1.3.2",
71
71
  "@eslint/eslintrc": "^3.3.1",
72
72
  "@eslint/js": "^9.35.0",
73
- "@react-native/babel-preset": "0.86.2",
74
- "@react-native/eslint-config": "0.86.2",
73
+ "@react-native/babel-preset": "0.88.0",
74
+ "@react-native/eslint-config": "0.88.0",
75
75
  "@types/jest": "^29.5.14",
76
- "@types/react": "^19.2.0",
76
+ "@types/react": "^19.3.0",
77
77
  "del-cli": "^6.0.0",
78
78
  "eslint": "^9.35.0",
79
79
  "eslint-config-prettier": "^10.1.8",
@@ -82,15 +82,15 @@
82
82
  "jsdom": "26.1.0",
83
83
  "nitrogen": "0.37.0",
84
84
  "prettier": "^2.8.8",
85
- "react": "19.2.3",
86
- "react-native": "patch:react-native@npm%3A0.86.2#~/.yarn/patches/react-native-npm-0.86.2-c9d546616f.patch",
85
+ "react": "19.3.0",
86
+ "react-native": "patch:react-native@npm%3A0.88.0#~/.yarn/patches/react-native-npm-0.88.0-60c6201dd2.patch",
87
87
  "react-native-builder-bob": "^0.40.13",
88
88
  "react-native-nitro-modules": "0.37.0",
89
89
  "typescript": "^5.9.2"
90
90
  },
91
91
  "peerDependencies": {
92
- "@onekeyfe/react-native-image": "6.7.0-alpha.430",
93
- "@onekeyfe/react-native-native-logger": "6.7.0-alpha.430",
92
+ "@onekeyfe/react-native-image": "6.7.0-alpha.435",
93
+ "@onekeyfe/react-native-native-logger": "6.7.0-alpha.435",
94
94
  "react": "*",
95
95
  "react-native": "*",
96
96
  "react-native-nitro-modules": "0.37.0"
@@ -121,7 +121,7 @@
121
121
  ]
122
122
  },
123
123
  "jest": {
124
- "preset": "react-native",
124
+ "preset": "@react-native/jest-preset",
125
125
  "modulePathIgnorePatterns": [
126
126
  "<rootDir>/lib/"
127
127
  ],
@@ -1,6 +1,6 @@
1
1
  import type { ScrollEdgeEffect } from './ScrollEdgeEffect';
2
2
  import type { ReactNode, RefObject } from 'react';
3
- import type { View, ViewProps } from 'react-native';
3
+ import type { ViewInstance, ViewProps } from 'react-native';
4
4
  import type {
5
5
  ActionAnchorInvalidatedEvent,
6
6
  EndReachedEvent,
@@ -161,7 +161,7 @@ export type NativeListProps = Omit<ViewProps, 'children'> &
161
161
  /** Web only: visible sticky chrome above the parent's list viewport. */
162
162
  webStickyInset?: number;
163
163
  /** Web only. Hosts the section index inside this container. */
164
- webSectionIndexContainerRef?: RefObject<View | null>;
164
+ webSectionIndexContainerRef?: RefObject<ViewInstance | null>;
165
165
  /** Defaults to `none`. `interactive` behaves as `none` on Android. */
166
166
  keyboardDismissMode?: NativeListKeyboardDismissMode;
167
167
  /**
package/src/models.ts CHANGED
@@ -513,19 +513,6 @@ export type RowBase = Readonly<{
513
513
  separator?: boolean;
514
514
  }>;
515
515
 
516
- /** One run of an identity title line; see docs/SPEC.md. */
517
- export type IdentityTitleSegment = Readonly<{
518
- text: string;
519
- /** Omitted: the title color. */
520
- tone?: 'primary' | 'secondary';
521
- /** Omitted: the title weight. */
522
- fontWeight?: 'regular' | 'medium';
523
- /** The one run that gives up width when the line is too narrow. */
524
- shrink?: boolean;
525
- /** Caps the run at this fraction of the title line, within (0, 1]. */
526
- maxWidthRatio?: number;
527
- }>;
528
-
529
516
  export type IdentityRow = RowBase &
530
517
  Readonly<{
531
518
  type: 'identity';
@@ -557,14 +544,6 @@ export type IdentityRow = RowBase &
557
544
  }>;
558
545
  /** Web-only additional help icon after titleIcon. */
559
546
  secondaryTitleIcon?: IdentityRow['titleIcon'];
560
- /** Runs drawn in place of `title`, which stays the spoken label. */
561
- titleSegments?: readonly IdentityTitleSegment[];
562
- /** 16-point glyph before the title; decorative unless labelled. */
563
- titleLeadingIcon?: Readonly<{
564
- name: string;
565
- tintColor?: string;
566
- accessibilityLabel?: string;
567
- }>;
568
547
  /** Circular image after title icons; image dimensions must be square, 1...40. */
569
548
  titleImage?: Readonly<{
570
549
  image: ImageSource;
@@ -1114,8 +1093,6 @@ export type RowPatch =
1114
1093
  | 'titleIcon'
1115
1094
  | 'secondaryTitleIcon'
1116
1095
  | 'titleImage'
1117
- | 'titleSegments'
1118
- | 'titleLeadingIcon'
1119
1096
  | 'subtitle'
1120
1097
  | 'subtitleLines'
1121
1098
  | 'contentHeight'
package/src/validation.ts CHANGED
@@ -1344,108 +1344,6 @@ 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
-
1449
1347
  function assertIdentityExtras(
1450
1348
  row: Pick<
1451
1349
  IdentityRow,
@@ -1936,7 +1834,6 @@ function assertRow(
1936
1834
  );
1937
1835
  });
1938
1836
  assertIdentityExtras(row, path);
1939
- assertIdentityTitleRuns(row, path);
1940
1837
  assertText(row.subtitle, `${path}.subtitle`);
1941
1838
  // OneKey patch: selector text segments truncate independently.
1942
1839
  row.subtitleSegments?.forEach((segment, segmentIndex) => {
@@ -2519,8 +2416,6 @@ const ROW_FIELDS: Readonly<Record<string, readonly string[]>> = {
2519
2416
  'titleIcon',
2520
2417
  'secondaryTitleIcon',
2521
2418
  'titleImage',
2522
- 'titleSegments',
2523
- 'titleLeadingIcon',
2524
2419
  'subtitle',
2525
2420
  'tertiary',
2526
2421
  'tertiaryTone',
@@ -2698,8 +2593,6 @@ const PATCH_FIELDS: Readonly<Record<string, readonly string[]>> = {
2698
2593
  'titleIcon',
2699
2594
  'secondaryTitleIcon',
2700
2595
  'titleImage',
2701
- 'titleSegments',
2702
- 'titleLeadingIcon',
2703
2596
  'subtitle',
2704
2597
  'tertiary',
2705
2598
  'tertiaryTone',
@@ -2831,7 +2724,6 @@ function protocolKey(value: unknown, path: string): void {
2831
2724
  const PROTOCOL_ARRAY_FIELDS = new Set([
2832
2725
  'columns',
2833
2726
  'titleSuffixes',
2834
- 'titleSegments',
2835
2727
  'cells',
2836
2728
  'points',
2837
2729
  'images',
@@ -3073,10 +2965,7 @@ function assertRowProtocol(row: RowModel, path: string): void {
3073
2965
  if (row.height !== undefined && row.height < 0)
3074
2966
  fail(`${path}.height`, 'must be non-negative');
3075
2967
  if (row.type === 'identity') {
3076
- if (isDevelopment()) {
3077
- assertIdentityExtras(row, path);
3078
- assertIdentityTitleRuns(row, path);
3079
- }
2968
+ if (isDevelopment()) assertIdentityExtras(row, path);
3080
2969
  if (row.titleSuffixes !== undefined && !Array.isArray(row.titleSuffixes))
3081
2970
  fail(`${path}.titleSuffixes`, 'must be an array');
3082
2971
  row.titleSuffixes?.forEach((suffix, index) => {
@@ -3671,14 +3560,6 @@ const NESTED_DECORATION_FIELDS: Readonly<Record<string, readonly string[]>> = {
3671
3560
 
3672
3561
  function sanitizeDecoration(value: unknown, field: string): unknown {
3673
3562
  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;
3682
3563
  if (
3683
3564
  !Array.isArray(value) &&
3684
3565
  [
@@ -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-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}
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}
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}