@onekeyfe/react-native-native-list 3.0.105 → 3.0.106
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/NativeListAdapter.kt +16 -3
- package/android/src/main/java/com/onekey/nativelist/NativeListModels.kt +6 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRowView.kt +671 -52
- package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +282 -54
- package/ios/HybridNativeList.swift +8 -2
- package/ios/NativeListCell.swift +630 -31
- package/ios/NativeListDesignAssets.swift +24 -1
- package/ios/RNCNativeListView.swift +216 -42
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_account_error_custom.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_account_error_custom.imageset/icon.svg +14 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_all_networks_solid.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_all_networks_solid.imageset/icon.svg +12 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_apple_brand.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_apple_brand.imageset/icon.svg +6 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_bot_illus.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_bot_illus.imageset/icon.svg +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_crossed_small_solid.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_crossed_small_solid.imageset/icon.svg +3 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_globus_outline.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_globus_outline.imageset/icon.svg +7 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_google_illus.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_google_illus.imageset/icon.svg +18 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_lock_solid.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_selector_lock_solid.imageset/icon.svg +7 -0
- package/lib/module/NativeList.js +102 -8
- package/lib/module/NativeList.web.js +20 -2
- package/lib/module/avatarPrefetch.js +174 -0
- package/lib/module/validation.js +45 -2
- package/lib/module/web/NativeListAvatarWorker.js +542 -0
- package/lib/module/web/NativeListWebAvatarCache.js +267 -0
- package/lib/module/web/NativeListWebEngine.js +958 -47
- package/lib/typescript/src/NativeList.web.d.ts +2 -2
- package/lib/typescript/src/avatarPrefetch.d.ts +28 -0
- package/lib/typescript/src/models.d.ts +72 -4
- package/lib/typescript/src/web/NativeListWebAvatarCache.d.ts +6 -0
- package/lib/typescript/src/web/NativeListWebEngine.d.ts +10 -1
- package/package.json +2 -2
- package/src/NativeList.tsx +149 -13
- package/src/NativeList.web.tsx +30 -3
- package/src/avatarPrefetch.ts +236 -0
- package/src/models.ts +98 -7
- package/src/validation.ts +131 -2
- package/src/web/NativeListAvatarWorker.js +567 -0
- package/src/web/NativeListWebAvatarCache.ts +314 -0
- package/src/web/NativeListWebEngine.ts +1409 -60
|
@@ -37,8 +37,18 @@ import {
|
|
|
37
37
|
type NormalizedPositionScroll,
|
|
38
38
|
} from '../scrolling';
|
|
39
39
|
import { applyRowPatches, validateSnapshot } from '../validation';
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
import { avatarPrefetchWindow } from '../avatarPrefetch';
|
|
41
|
+
import {
|
|
42
|
+
acquireNativeListAvatar,
|
|
43
|
+
canonicalNativeListAvatarUri,
|
|
44
|
+
type AvatarLease,
|
|
45
|
+
} from './NativeListWebAvatarCache';
|
|
46
|
+
|
|
47
|
+
const SECTION_INDEX_CONTENT_INSET = 16;
|
|
48
|
+
const SECTION_INDEX_RAIL_WIDTH = 32;
|
|
49
|
+
const SECTION_INDEX_EDGE_PADDING = 8;
|
|
50
|
+
const SECTION_INDEX_MIN_LABEL_SPACING = 14;
|
|
51
|
+
const SECTION_INDEX_MIN_HEIGHT = 120;
|
|
42
52
|
const DEFAULT_VIEWPORT_WIDTH = 320;
|
|
43
53
|
const DEFAULT_VIEWPORT_HEIGHT = 640;
|
|
44
54
|
const OVERSCAN_VIEWPORTS = 1;
|
|
@@ -354,11 +364,40 @@ export function estimateWebRowHeight(
|
|
|
354
364
|
snapshot: NativeListSnapshot,
|
|
355
365
|
availableWidth: number
|
|
356
366
|
): number {
|
|
357
|
-
|
|
367
|
+
// OneKey patch: explicit selector height takes precedence over presets.
|
|
368
|
+
// if (row.type === 'system' && row.variant === 'spacer') return row.height;
|
|
369
|
+
if (row.height !== undefined) return row.height;
|
|
370
|
+
if (row.type === 'system' && row.variant === 'warning') {
|
|
371
|
+
const width = Math.max(1, availableWidth - 24);
|
|
372
|
+
const lines = (text: string) =>
|
|
373
|
+
Math.max(
|
|
374
|
+
1,
|
|
375
|
+
Math.ceil(
|
|
376
|
+
Array.from(text).reduce(
|
|
377
|
+
(length, char) => length + (char.charCodeAt(0) > 255 ? 14 : 7),
|
|
378
|
+
0
|
|
379
|
+
) / width
|
|
380
|
+
)
|
|
381
|
+
);
|
|
382
|
+
return 32 + 20 * (lines(row.title) + lines(row.message));
|
|
383
|
+
}
|
|
358
384
|
if (row.type === 'walletGroup')
|
|
359
|
-
|
|
385
|
+
// OneKey patch: wallet badges participate in the outer group height.
|
|
386
|
+
// return (row.children.length + 1) * 68 + row.children.length * 12;
|
|
387
|
+
return (
|
|
388
|
+
[row.parent, ...row.children].reduce(
|
|
389
|
+
(height, member) =>
|
|
390
|
+
height + estimateWebRowHeight(member, snapshot, availableWidth),
|
|
391
|
+
0
|
|
392
|
+
) +
|
|
393
|
+
row.children.length * 12 +
|
|
394
|
+
(row.parent.height !== undefined ? 2 : 0)
|
|
395
|
+
);
|
|
396
|
+
// OneKey patch: reserve the source badge line below wallet names.
|
|
397
|
+
// if (row.type === 'identity' && row.presentation === 'walletSidebar')
|
|
398
|
+
// return 68;
|
|
360
399
|
if (row.type === 'identity' && row.presentation === 'walletSidebar')
|
|
361
|
-
return 68;
|
|
400
|
+
return 68 + (row.badges?.length ? 24 : 0);
|
|
362
401
|
if (row.type === 'identity' && row.presentation === 'networkSelector')
|
|
363
402
|
return 47;
|
|
364
403
|
if (row.type === 'identity' && row.presentation === 'accountSelector')
|
|
@@ -471,9 +510,13 @@ export function computeWebListLayout(
|
|
|
471
510
|
const horizontal = snapshot.layout.orientation === 'horizontal';
|
|
472
511
|
const spacing = snapshot.layout.itemSpacing ?? 0;
|
|
473
512
|
const padding = paddingValues(snapshot);
|
|
474
|
-
const indexGutter = sectionIndexEnabled(snapshot) ? SECTION_INDEX_GUTTER : 0;
|
|
475
513
|
const width = Math.max(1, viewportWidth || DEFAULT_VIEWPORT_WIDTH);
|
|
476
514
|
const height = Math.max(1, viewportHeight || DEFAULT_VIEWPORT_HEIGHT);
|
|
515
|
+
// OneKey patch: the index overlays the content and only keeps a small accessory-safe inset.
|
|
516
|
+
const indexGutter =
|
|
517
|
+
sectionIndexEnabled(snapshot) && height >= SECTION_INDEX_MIN_HEIGHT
|
|
518
|
+
? SECTION_INDEX_CONTENT_INSET
|
|
519
|
+
: 0;
|
|
477
520
|
const availableWidth = Math.max(
|
|
478
521
|
1,
|
|
479
522
|
width - padding.horizontal * 2 - indexGutter
|
|
@@ -699,7 +742,9 @@ export function webRowRenderSignature(row: RowModel): string {
|
|
|
699
742
|
return JSON.stringify(rowWithoutSelectionState(row));
|
|
700
743
|
}
|
|
701
744
|
|
|
745
|
+
// OneKey patch: selector names must shrink before the sidebar clips their contents.
|
|
702
746
|
export const WEB_LIST_CSS = `
|
|
747
|
+
[data-native-list-selector="walletSidebar"] .ok-native-list-title{max-width:100%;min-width:0}
|
|
703
748
|
.ok-native-list-root{--nl-bg:#f7f7f7;--nl-row:#fff;--nl-selected:#eaf2ff;--nl-pressed:#e8e8e8;--nl-subdued:#f9f9f9;--nl-strong:#0000000f;--nl-primary:#111;--nl-secondary:#6b7280;--nl-disabled:#8d8d8d;--nl-icon:#111;--nl-icon-subdued:#8d8d8d;--nl-separator:#e5e7eb;--nl-accent:#2f6bff;--nl-positive:#15803d;--nl-negative:#dc2626;--nl-critical:#feecec;--nl-inverse:#202020;--nl-inverse-text:#fcfcfc;--nl-info:#0d74ce;position:absolute;inset:0;display:flex;min-width:0;min-height:0;overflow:hidden;background:var(--nl-bg);color:var(--nl-primary);font-family:Roobert,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;font-synthesis:none}
|
|
704
749
|
.ok-native-list-viewport-frame{position:relative;flex:1;min-width:0;min-height:0;overflow:hidden}
|
|
705
750
|
.ok-native-list-viewport{position:absolute;inset:0;overflow:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;scrollbar-gutter:stable}
|
|
@@ -710,6 +755,7 @@ export const WEB_LIST_CSS = `
|
|
|
710
755
|
.ok-native-list-item[data-native-list-selected="true"]>.ok-native-list-row{background:var(--nl-selected)}
|
|
711
756
|
.ok-native-list-item[data-native-list-disabled="true"]>.ok-native-list-row{opacity:.5;cursor:default}
|
|
712
757
|
.ok-native-list-item:not([data-native-list-disabled="true"]):hover>.ok-native-list-row{background:var(--nl-pressed)}
|
|
758
|
+
.ok-native-list-item:not([data-native-list-disabled="true"]):active>.ok-native-list-row{background:var(--nl-pressed)}
|
|
713
759
|
.ok-native-list-item:not([data-native-list-disabled="true"]):not([data-native-list-selected="true"]):hover>.ok-native-list-wallet-row{background:var(--nl-strong)}
|
|
714
760
|
.ok-native-list-item:not([data-native-list-disabled="true"]):not([data-native-list-selected="true"]):active>.ok-native-list-wallet-row{background:var(--nl-pressed)}
|
|
715
761
|
.ok-native-list-item[data-native-list-selected="true"]:hover>.ok-native-list-wallet-row{background:var(--nl-selected)}
|
|
@@ -752,9 +798,29 @@ export const WEB_LIST_CSS = `
|
|
|
752
798
|
.ok-native-list-media{display:block;padding:0 5px;background:transparent;border-radius:16px}.ok-native-list-media-image{display:block;width:100%;aspect-ratio:1;border-radius:10px;background:var(--nl-strong);object-fit:cover}.ok-native-list-media-image[data-state="empty"]{background:transparent}.ok-native-list-media-image[data-state="error"]{display:flex;align-items:center;justify-content:center;color:var(--nl-icon-subdued);font-size:24px}.ok-native-list-media-meta{padding-top:7px}.ok-native-list-media-subtitle-row{display:flex;align-items:center;gap:6px}.ok-native-list-media-subtitle{flex:1;min-width:0;font-size:12px;color:var(--nl-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ok-native-list-media-network{width:14px;height:14px;border-radius:50%}.ok-native-list-media-title{font-size:16px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ok-native-list-media-close{position:absolute;right:9px;top:4px;border:0;background:color-mix(in srgb,var(--nl-inverse) 72%,transparent);color:var(--nl-inverse-text);width:24px;height:24px;border-radius:50%;font:18px/20px inherit;cursor:pointer}
|
|
753
799
|
.ok-native-list-metric{display:flex;flex-direction:column;align-items:flex-start;padding:12px;border-radius:12px;gap:5px;background:var(--nl-row)}.ok-native-list-metric-value{font-size:22px;line-height:28px;font-weight:700}.ok-native-list-composite{display:flex;flex-direction:column;align-items:stretch;padding:14px;border-radius:12px;gap:12px;background:var(--nl-subdued)}.ok-native-list-composite-heading{font-size:14px;letter-spacing:1px;color:var(--nl-secondary)}.ok-native-list-composite-row{display:flex;gap:12px}.ok-native-list-composite-cell{flex:1;min-width:0}.ok-native-list-composite-cell[data-shaded="true"]{padding:10px;border-radius:10px;background:color-mix(in srgb,var(--nl-primary) 5%,transparent)}.ok-native-list-composite-value{font-size:18px;font-weight:600}.ok-native-list-divider{height:1px;background:var(--nl-separator)}.ok-native-list-progress{height:4px;border-radius:2px;overflow:hidden;background:var(--nl-negative)}.ok-native-list-progress>span{display:block;height:100%;border-radius:2px;background:var(--nl-positive)}
|
|
754
800
|
.ok-native-list-data{padding:6px 12px}.ok-native-list-index{flex:0 0 28px;color:var(--nl-secondary);font-size:13px}.ok-native-list-favorite{flex:0 0 24px;color:var(--nl-icon-subdued);font-size:22px}.ok-native-list-favorite[data-active="true"]{color:var(--nl-accent)}.ok-native-list-data-cell{display:flex;flex-direction:column;min-width:0}.ok-native-list-data-cell[data-align="center"]{align-items:center}.ok-native-list-data-cell[data-align="end"]{align-items:flex-end}.ok-native-list-data-primary{display:flex;align-items:center;gap:5px;max-width:100%;font-size:16px;font-weight:500;white-space:nowrap}.ok-native-list-unread{width:7px;height:7px;flex:0 0 7px;border-radius:50%;background:var(--nl-accent)}.ok-native-list-thumbnail{width:64px;height:64px;border-radius:10px;object-fit:cover}
|
|
755
|
-
.ok-native-list-footer{flex:0 0 auto;min-height:0}.ok-native-list-sticky{position:absolute;z-index:4;left:0;right:0;top:0;pointer-events:auto;box-shadow:0 1px 0 var(--nl-separator)}.ok-native-list-index-rail{position:absolute;z-index:6;top:0;right:0;bottom:0;width
|
|
801
|
+
.ok-native-list-footer{flex:0 0 auto;min-height:0}.ok-native-list-sticky{position:absolute;z-index:4;left:0;right:0;top:0;pointer-events:auto;box-shadow:0 1px 0 var(--nl-separator)}.ok-native-list-index-rail{position:absolute;z-index:6;top:0;right:0;bottom:0;width:${SECTION_INDEX_RAIL_WIDTH}px;touch-action:none;cursor:pointer}.ok-native-list-index-rail[hidden]{display:none}.ok-native-list-index-button{appearance:none;position:absolute;left:6px;display:flex;width:20px;height:16px;align-items:center;justify-content:center;padding:0;transform:translateY(-50%);border:0;border-radius:8px;background:transparent;color:var(--nl-secondary);font:600 10px/1 inherit;cursor:pointer}.ok-native-list-index-button[data-active="true"]{background:var(--nl-accent);color:var(--nl-inverse-text)}.ok-native-list-index-button:focus-visible{outline:2px solid var(--nl-accent);outline-offset:1px}.ok-native-list-index-preview{position:absolute;z-index:8;right:40px;top:50%;display:flex;width:48px;height:48px;align-items:center;justify-content:center;transform:translateY(-50%) scale(.92);border-radius:14px;background:var(--nl-inverse);color:var(--nl-inverse-text);font-size:22px;font-weight:600;opacity:0;pointer-events:none;transition:opacity .15s ease,transform .15s ease}.ok-native-list-index-preview[data-visible="true"]{opacity:1;transform:translateY(-50%) scale(1)}
|
|
756
802
|
.ok-native-list-refresh{position:absolute;z-index:7;left:50%;top:8px;display:flex;align-items:center;gap:6px;padding:6px 10px;border-radius:999px;background:var(--nl-inverse);color:var(--nl-inverse-text);font-size:12px;opacity:0;transform:translate(-50%,-16px);transition:opacity .15s ease,transform .15s ease;pointer-events:none}.ok-native-list-refresh[data-visible="true"]{opacity:1;transform:translate(-50%,0)}
|
|
803
|
+
.ok-native-list-warning{height:auto;display:flex;flex-direction:column;align-items:stretch;gap:4px;padding:14px 12px;border-top:1px solid;border-bottom:1px solid;box-sizing:border-box;cursor:default}.ok-native-list-warning-title,.ok-native-list-warning-message{font-size:14px;line-height:20px;white-space:normal;overflow-wrap:anywhere}.ok-native-list-warning-title{font-weight:500;color:var(--nl-primary)}.ok-native-list-warning-message{font-weight:400;color:var(--nl-secondary)}
|
|
804
|
+
.ok-native-list-subtitle-segments{display:flex;align-items:center;min-width:0;max-width:100%;height:20px}.ok-native-list-subtitle-segments>.ok-native-list-secondary{flex:0 1 auto;min-width:0}.ok-native-list-subtitle-dot{flex:0 0 4px;width:4px;height:4px;margin:0 6px;border-radius:50%;background:var(--nl-disabled)}.ok-native-list-wallet-row>.ok-native-list-flex{flex:0 1 auto;width:100%;align-items:center}.ok-native-list-wallet-badges{display:flex;gap:4px;justify-content:center;margin-top:4px;height:20px;max-width:100%}.ok-native-list-wallet-badges>.ok-native-list-badge{background:var(--nl-strong);color:var(--nl-secondary);font-size:12px;line-height:16px;height:20px;box-sizing:border-box;padding:2px 4px}.ok-native-list-visual-overlay{position:absolute;display:flex;align-items:center;justify-content:center;box-sizing:border-box;border-radius:50%;overflow:hidden;line-height:1;font-size:10px}.ok-native-list-visual-overlay img,.ok-native-list-visual-overlay svg{width:100%;height:100%;object-fit:contain}
|
|
757
805
|
@media (prefers-reduced-motion:reduce){.ok-native-list-index-preview,.ok-native-list-refresh{transition:none}.ok-native-list-spinner{animation:none}}
|
|
806
|
+
/* OneKey patch: selector controls follow their original semantic colors and geometry. */
|
|
807
|
+
.ok-native-list-checkbox[data-selector="networkSelector"]{padding:0;border-radius:4px;border-color:var(--nl-checkbox-border,var(--nl-separator));background:var(--nl-checkbox-icon,var(--nl-inverse-text))}
|
|
808
|
+
.ok-native-list-checkbox[data-selector="networkSelector"]::after{display:none}
|
|
809
|
+
.ok-native-list-checkbox[data-selector="networkSelector"]>svg{display:none;width:16px;height:16px;color:var(--nl-checkbox-icon,var(--nl-inverse-text));flex-shrink:0}
|
|
810
|
+
.ok-native-list-checkbox[data-selector="networkSelector"][data-state="checked"],.ok-native-list-checkbox[data-selector="networkSelector"][data-state="indeterminate"]{border-color:transparent;background:var(--nl-checkbox-background,var(--nl-primary))}
|
|
811
|
+
.ok-native-list-checkbox[data-selector="networkSelector"][data-state="checked"]>svg[data-state="checked"],.ok-native-list-checkbox[data-selector="networkSelector"][data-state="indeterminate"]>svg[data-state="indeterminate"]{display:block}
|
|
812
|
+
/* OneKey patch: source WalletListItem uses four-point padding on every side. */
|
|
813
|
+
.ok-native-list-wallet-row[data-native-list-selector="walletSidebar"]{border-radius:12px;padding:4px}
|
|
814
|
+
/* OneKey patch: selected group members use the same primary title color as standalone wallets. */
|
|
815
|
+
.ok-native-list-wallet-member[data-native-list-selected="true"]>.ok-native-list-wallet-row[data-native-list-selector="walletSidebar"] .ok-native-list-title{color:var(--nl-primary)}
|
|
816
|
+
.ok-native-list-wallet-row[data-native-list-selector="walletSidebar"] .ok-native-list-wallet-badges{height:18px}
|
|
817
|
+
.ok-native-list-wallet-row[data-native-list-selector="walletSidebar"] .ok-native-list-wallet-badges>.ok-native-list-badge{font-size:11px;line-height:14px;font-weight:400;height:18px;padding:2px 6px;border-radius:4px;background:var(--nl-subdued);color:var(--nl-secondary)}
|
|
818
|
+
.ok-native-list-wallet-row[data-native-list-selector="walletSidebar"] .ok-native-list-wallet-badges>.ok-native-list-badge[data-tone="warning"]{background:var(--nl-caution-background);color:var(--nl-caution)}
|
|
819
|
+
.ok-native-list-account-row[data-native-list-selector="accountSelector"] .ok-native-list-accessories>.ok-native-list-icon-button{box-sizing:border-box;flex:0 0 38px;width:38px;height:38px;margin:-7px;padding:7px}
|
|
820
|
+
/* OneKey patch: AccountSelectorAccountListItem fixes the borderless Plus slot at top18/right20. */
|
|
821
|
+
.ok-native-list-account-row[data-native-list-selector="accountSelector"]>.ok-native-list-accessories[data-native-list-account-control="createAddress"]{position:absolute;top:18px;right:12px}
|
|
822
|
+
.ok-native-list-account-row[data-native-list-selector="accountSelector"] .ok-native-list-accessories>[data-native-list-account-control="createAddress"]{flex-basis:36px;width:36px;height:36px;padding:6px;border-radius:8px}
|
|
823
|
+
.ok-native-list-account-action-row{padding-left:12px;padding-right:12px}.ok-native-list-account-action-row .ok-native-list-action-title{font-size:16px;line-height:24px;font-weight:400}.ok-native-list-account-action-row .ok-native-list-action-title[data-tone="primary"]{color:var(--nl-primary)}
|
|
758
824
|
`;
|
|
759
825
|
|
|
760
826
|
function createElement(
|
|
@@ -788,16 +854,132 @@ function safeImageUri(uri: string): string | undefined {
|
|
|
788
854
|
return undefined;
|
|
789
855
|
}
|
|
790
856
|
|
|
857
|
+
// OneKey patch: retries belong to an image binding and must not outlive recycled rows.
|
|
858
|
+
const webImageRetryCleanup = new WeakMap<HTMLImageElement, () => void>();
|
|
859
|
+
const webAvatarCleanup = new WeakMap<HTMLImageElement, () => void>();
|
|
860
|
+
const webAvatarSources = new WeakMap<
|
|
861
|
+
HTMLImageElement,
|
|
862
|
+
{ uri: string; source: ImageSource }
|
|
863
|
+
>();
|
|
864
|
+
function disposeWebImageRetries(element: HTMLElement): boolean {
|
|
865
|
+
let disposed = false;
|
|
866
|
+
const images = element.matches('img')
|
|
867
|
+
? [element as HTMLImageElement]
|
|
868
|
+
: element.querySelectorAll('img');
|
|
869
|
+
images.forEach((image) => {
|
|
870
|
+
const avatarCleanup = webAvatarCleanup.get(image);
|
|
871
|
+
const cleanup = webImageRetryCleanup.get(image);
|
|
872
|
+
if (!cleanup && !avatarCleanup) return;
|
|
873
|
+
avatarCleanup?.();
|
|
874
|
+
webAvatarCleanup.delete(image);
|
|
875
|
+
webAvatarSources.delete(image);
|
|
876
|
+
cleanup?.();
|
|
877
|
+
webImageRetryCleanup.delete(image);
|
|
878
|
+
disposed = true;
|
|
879
|
+
});
|
|
880
|
+
return disposed;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
function configureWebImageRetry(
|
|
884
|
+
image: HTMLImageElement,
|
|
885
|
+
source: ImageSource,
|
|
886
|
+
initialUri: string
|
|
887
|
+
) {
|
|
888
|
+
const fallbackUri = source.fallbackUri
|
|
889
|
+
? safeImageUri(source.fallbackUri)
|
|
890
|
+
: undefined;
|
|
891
|
+
const retryLimit = Number.isFinite(source.retryTimes)
|
|
892
|
+
? Math.max(0, Math.floor(source.retryTimes ?? 0))
|
|
893
|
+
: 0;
|
|
894
|
+
if (!fallbackUri && retryLimit === 0) return;
|
|
895
|
+
const view = image.ownerDocument.defaultView;
|
|
896
|
+
let currentUri = initialUri;
|
|
897
|
+
let usedFallback = false;
|
|
898
|
+
let retryCount = 0;
|
|
899
|
+
let retryTimer: number | undefined;
|
|
900
|
+
let disposed = false;
|
|
901
|
+
const clearRetry = () => {
|
|
902
|
+
if (retryTimer !== undefined) view?.clearTimeout(retryTimer);
|
|
903
|
+
retryTimer = undefined;
|
|
904
|
+
};
|
|
905
|
+
const handleError = (event: Event) => {
|
|
906
|
+
if (disposed || !image.isConnected || retryTimer !== undefined) {
|
|
907
|
+
event.stopImmediatePropagation();
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
if (fallbackUri && !usedFallback && fallbackUri !== currentUri) {
|
|
911
|
+
event.stopImmediatePropagation();
|
|
912
|
+
usedFallback = true;
|
|
913
|
+
currentUri = fallbackUri;
|
|
914
|
+
image.src = currentUri;
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
if (retryCount >= retryLimit || !view) return;
|
|
918
|
+
event.stopImmediatePropagation();
|
|
919
|
+
retryCount += 1;
|
|
920
|
+
retryTimer = view.setTimeout(() => {
|
|
921
|
+
retryTimer = undefined;
|
|
922
|
+
if (disposed || !image.isConnected) return;
|
|
923
|
+
image.removeAttribute('src');
|
|
924
|
+
image.src = currentUri;
|
|
925
|
+
}, Math.floor(Math.random() * 3) * 1000);
|
|
926
|
+
};
|
|
927
|
+
image.addEventListener('error', handleError);
|
|
928
|
+
image.addEventListener('load', clearRetry);
|
|
929
|
+
webImageRetryCleanup.set(image, () => {
|
|
930
|
+
disposed = true;
|
|
931
|
+
clearRetry();
|
|
932
|
+
image.removeEventListener('error', handleError);
|
|
933
|
+
image.removeEventListener('load', clearRetry);
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
function configureWebAvatar(
|
|
938
|
+
image: HTMLImageElement,
|
|
939
|
+
source: ImageSource,
|
|
940
|
+
uri: string
|
|
941
|
+
) {
|
|
942
|
+
const dispose = acquireNativeListAvatar(
|
|
943
|
+
image.ownerDocument,
|
|
944
|
+
uri,
|
|
945
|
+
(resolvedUri) => {
|
|
946
|
+
configureWebImageRetry(image, source, resolvedUri);
|
|
947
|
+
image.src = resolvedUri;
|
|
948
|
+
},
|
|
949
|
+
() => {
|
|
950
|
+
const fallbackUri = source.fallbackUri
|
|
951
|
+
? safeImageUri(source.fallbackUri)
|
|
952
|
+
: undefined;
|
|
953
|
+
if (fallbackUri) {
|
|
954
|
+
configureWebImageRetry(image, source, fallbackUri);
|
|
955
|
+
image.src = fallbackUri;
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
const ImageEvent = image.ownerDocument.defaultView?.Event;
|
|
959
|
+
if (ImageEvent) image.dispatchEvent(new ImageEvent('error'));
|
|
960
|
+
}
|
|
961
|
+
);
|
|
962
|
+
webAvatarSources.set(image, { uri, source });
|
|
963
|
+
webAvatarCleanup.set(image, dispose);
|
|
964
|
+
}
|
|
965
|
+
|
|
791
966
|
function createImage(
|
|
792
967
|
context: RenderContext,
|
|
793
968
|
source: ImageSource,
|
|
794
969
|
className?: string
|
|
795
970
|
): HTMLImageElement | undefined {
|
|
796
|
-
const
|
|
971
|
+
const avatarUri = canonicalNativeListAvatarUri(source.uri);
|
|
972
|
+
const uri = avatarUri ?? safeImageUri(source.uri);
|
|
797
973
|
if (!uri) return undefined;
|
|
798
974
|
const image = context.document.createElement('img');
|
|
799
975
|
if (className) image.className = className;
|
|
800
|
-
|
|
976
|
+
// OneKey patch: consume recoverable errors before the visual's final fallback listener.
|
|
977
|
+
if (avatarUri) {
|
|
978
|
+
configureWebAvatar(image, source, avatarUri);
|
|
979
|
+
} else {
|
|
980
|
+
configureWebImageRetry(image, source, uri);
|
|
981
|
+
image.src = uri;
|
|
982
|
+
}
|
|
801
983
|
image.alt = '';
|
|
802
984
|
image.draggable = false;
|
|
803
985
|
image.loading = 'lazy';
|
|
@@ -807,6 +989,324 @@ function createImage(
|
|
|
807
989
|
return image;
|
|
808
990
|
}
|
|
809
991
|
|
|
992
|
+
// OneKey patch: React Native Web paints selector images as centered CSS backgrounds.
|
|
993
|
+
// The image keeps its loading/error lifecycle; only its replaced-element pixels are hidden.
|
|
994
|
+
function paintSelectorImageBackground(
|
|
995
|
+
image: HTMLImageElement,
|
|
996
|
+
frame: HTMLElement,
|
|
997
|
+
inset = 0
|
|
998
|
+
) {
|
|
999
|
+
const paint = createElement(
|
|
1000
|
+
image.ownerDocument,
|
|
1001
|
+
'span',
|
|
1002
|
+
'ok-native-list-selector-image-background'
|
|
1003
|
+
);
|
|
1004
|
+
paint.style.cssText =
|
|
1005
|
+
'position:absolute;pointer-events:none;border-radius:inherit;background-position:center;background-repeat:no-repeat';
|
|
1006
|
+
paint.style.inset = String(inset) + 'px';
|
|
1007
|
+
paint.style.backgroundSize =
|
|
1008
|
+
image.style.objectFit === 'fill'
|
|
1009
|
+
? '100% 100%'
|
|
1010
|
+
: image.style.objectFit === 'center'
|
|
1011
|
+
? 'auto'
|
|
1012
|
+
: image.style.objectFit;
|
|
1013
|
+
image.style.opacity = '0';
|
|
1014
|
+
const update = () => {
|
|
1015
|
+
paint.style.backgroundImage =
|
|
1016
|
+
'url(' + JSON.stringify(image.currentSrc || image.src) + ')';
|
|
1017
|
+
};
|
|
1018
|
+
image.addEventListener('load', update);
|
|
1019
|
+
image.addEventListener('error', () => {
|
|
1020
|
+
paint.style.backgroundImage = 'none';
|
|
1021
|
+
});
|
|
1022
|
+
frame.insertBefore(paint, image);
|
|
1023
|
+
if (image.complete && image.naturalWidth > 0) update();
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
// OneKey patch: use source SVG paths for selector actions and wallet provider marks.
|
|
1027
|
+
const selectorIcons: Readonly<
|
|
1028
|
+
Record<
|
|
1029
|
+
string,
|
|
1030
|
+
Readonly<{
|
|
1031
|
+
viewBox: string;
|
|
1032
|
+
paths: readonly Readonly<{
|
|
1033
|
+
d: string;
|
|
1034
|
+
fill: string;
|
|
1035
|
+
fillRule: string;
|
|
1036
|
+
opacity: number;
|
|
1037
|
+
}>[];
|
|
1038
|
+
}>
|
|
1039
|
+
>
|
|
1040
|
+
> = {
|
|
1041
|
+
GlobusOutline: {
|
|
1042
|
+
viewBox: '0 0 24 24',
|
|
1043
|
+
paths: [
|
|
1044
|
+
{
|
|
1045
|
+
d: 'M12 2c5.185 0 9.448 3.947 9.95 9H22v2h-.05c-.502 5.053-4.765 9-9.95 9s-9.448-3.947-9.95-9H2v-2h.05C2.552 5.947 6.815 2 12 2M9.523 13c.09 1.982.438 3.726.934 5.002.29.746.612 1.282.917 1.614.304.331.517.384.626.384s.322-.053.626-.384c.305-.332.627-.868.917-1.614.496-1.276.845-3.02.934-5.002zm-5.459 0a8 8 0 0 0 4.8 6.36 10 10 0 0 1-.271-.633C7.994 17.187 7.61 15.189 7.52 13zm12.416 0c-.09 2.189-.474 4.187-1.073 5.727a10 10 0 0 1-.271.633 8 8 0 0 0 4.8-6.36zM8.863 4.639A8 8 0 0 0 4.064 11h3.457c.09-2.189.473-4.187 1.072-5.727q.127-.327.27-.634M12 4c-.109 0-.322.053-.626.384-.305.332-.627.868-.917 1.614-.496 1.276-.844 3.02-.934 5.002h4.954c-.09-1.982-.438-3.726-.934-5.002-.29-.746-.612-1.282-.917-1.614C12.322 4.053 12.109 4 12 4m3.136.639q.144.307.271.634c.599 1.54.982 3.538 1.073 5.727h3.456a8 8 0 0 0-4.8-6.361',
|
|
1046
|
+
fill: 'currentColor',
|
|
1047
|
+
fillRule: 'evenodd',
|
|
1048
|
+
opacity: 1.0,
|
|
1049
|
+
},
|
|
1050
|
+
],
|
|
1051
|
+
},
|
|
1052
|
+
LockSolid: {
|
|
1053
|
+
viewBox: '0 0 24 24',
|
|
1054
|
+
paths: [
|
|
1055
|
+
{
|
|
1056
|
+
d: 'M12 2a5 5 0 0 1 5 5v2h3v13H4V9h3V7a5 5 0 0 1 5-5m-1 11v5h2v-5zm1-9a3 3 0 0 0-3 3v2h6V7a3 3 0 0 0-3-3',
|
|
1057
|
+
fill: 'currentColor',
|
|
1058
|
+
fillRule: 'evenodd',
|
|
1059
|
+
opacity: 1.0,
|
|
1060
|
+
},
|
|
1061
|
+
],
|
|
1062
|
+
},
|
|
1063
|
+
GoogleIllus: {
|
|
1064
|
+
viewBox: '0 0 24 24',
|
|
1065
|
+
paths: [
|
|
1066
|
+
{
|
|
1067
|
+
d: 'M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09',
|
|
1068
|
+
fill: '#4285F4',
|
|
1069
|
+
fillRule: 'nonzero',
|
|
1070
|
+
opacity: 1.0,
|
|
1071
|
+
},
|
|
1072
|
+
{
|
|
1073
|
+
d: 'M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23',
|
|
1074
|
+
fill: '#34A853',
|
|
1075
|
+
fillRule: 'nonzero',
|
|
1076
|
+
opacity: 1.0,
|
|
1077
|
+
},
|
|
1078
|
+
{
|
|
1079
|
+
d: 'M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22z',
|
|
1080
|
+
fill: '#FBBC05',
|
|
1081
|
+
fillRule: 'nonzero',
|
|
1082
|
+
opacity: 1.0,
|
|
1083
|
+
},
|
|
1084
|
+
{
|
|
1085
|
+
d: 'M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53',
|
|
1086
|
+
fill: '#EA4335',
|
|
1087
|
+
fillRule: 'nonzero',
|
|
1088
|
+
opacity: 1.0,
|
|
1089
|
+
},
|
|
1090
|
+
],
|
|
1091
|
+
},
|
|
1092
|
+
AppleBrand: {
|
|
1093
|
+
viewBox: '0 0 16 20',
|
|
1094
|
+
paths: [
|
|
1095
|
+
{
|
|
1096
|
+
d: 'M11.67.834c.117 1.074-.315 2.153-.955 2.928-.64.773-1.692 1.378-2.718 1.298-.14-1.054.38-2.151.971-2.836C9.63 1.45 10.746.872 11.67.834M14.994 7.093c-.176.108-1.992 1.224-1.972 3.482.025 2.769 2.428 3.693 2.46 3.705l-.004.015a10.1 10.1 0 0 1-1.264 2.593c-.764 1.116-1.556 2.229-2.806 2.254-.598.011-1-.162-1.416-.343-.437-.19-.891-.386-1.609-.386-.751 0-1.226.203-1.683.398-.397.169-.78.333-1.32.354-1.208.047-2.124-1.207-2.895-2.32C.909 14.57-.294 10.414 1.322 7.612c.803-1.395 2.237-2.275 3.794-2.298.671-.014 1.32.244 1.89.47.434.172.821.326 1.135.326.282 0 .659-.149 1.099-.323.692-.273 1.539-.607 2.41-.518.599.026 2.276.24 3.354 1.818z',
|
|
1097
|
+
fill: 'currentColor',
|
|
1098
|
+
fillRule: 'nonzero',
|
|
1099
|
+
opacity: 1.0,
|
|
1100
|
+
},
|
|
1101
|
+
],
|
|
1102
|
+
},
|
|
1103
|
+
BotIllus: {
|
|
1104
|
+
viewBox: '0 0 24 24',
|
|
1105
|
+
paths: [
|
|
1106
|
+
{
|
|
1107
|
+
d: 'M11 2a1 1 0 1 1 2 0v1.8l1.6 1.6a1 1 0 1 1-1.4 1.4L12 5.6l-1.2 1.2a1 1 0 0 1-1.4-1.4L11 3.8z',
|
|
1108
|
+
fill: '#8897A5',
|
|
1109
|
+
fillRule: 'nonzero',
|
|
1110
|
+
opacity: 1.0,
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
d: 'M8.0 6.0h8.0a5.0 5.0 0 0 1 5.0 5.0v4.0a5.0 5.0 0 0 1 -5.0 5.0h-8.0a5.0 5.0 0 0 1 -5.0 -5.0v-4.0a5.0 5.0 0 0 1 5.0 -5.0z',
|
|
1114
|
+
fill: '#3FA9F5',
|
|
1115
|
+
fillRule: 'nonzero',
|
|
1116
|
+
opacity: 1.0,
|
|
1117
|
+
},
|
|
1118
|
+
{
|
|
1119
|
+
d: 'M3.0 10.0h0.0a1.5 1.5 0 0 1 1.5 1.5v3.0a1.5 1.5 0 0 1 -1.5 1.5h0.0a1.5 1.5 0 0 1 -1.5 -1.5v-3.0a1.5 1.5 0 0 1 1.5 -1.5z',
|
|
1120
|
+
fill: '#8897A5',
|
|
1121
|
+
fillRule: 'nonzero',
|
|
1122
|
+
opacity: 1.0,
|
|
1123
|
+
},
|
|
1124
|
+
{
|
|
1125
|
+
d: 'M21.0 10.0h0.0a1.5 1.5 0 0 1 1.5 1.5v3.0a1.5 1.5 0 0 1 -1.5 1.5h0.0a1.5 1.5 0 0 1 -1.5 -1.5v-3.0a1.5 1.5 0 0 1 1.5 -1.5z',
|
|
1126
|
+
fill: '#8897A5',
|
|
1127
|
+
fillRule: 'nonzero',
|
|
1128
|
+
opacity: 1.0,
|
|
1129
|
+
},
|
|
1130
|
+
{
|
|
1131
|
+
d: 'M7.5 12.0a1.5 1.5 0 1 0 3.0 0a1.5 1.5 0 1 0 -3.0 0',
|
|
1132
|
+
fill: '#10243E',
|
|
1133
|
+
fillRule: 'nonzero',
|
|
1134
|
+
opacity: 1.0,
|
|
1135
|
+
},
|
|
1136
|
+
{
|
|
1137
|
+
d: 'M13.5 12.0a1.5 1.5 0 1 0 3.0 0a1.5 1.5 0 1 0 -3.0 0',
|
|
1138
|
+
fill: '#10243E',
|
|
1139
|
+
fillRule: 'nonzero',
|
|
1140
|
+
opacity: 1.0,
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
d: 'M8.5 15.4c.9.8 2.08 1.2 3.5 1.2s2.6-.4 3.5-1.2c.24-.2.6-.18.8.06.2.23.17.6-.06.8-1.14.98-2.58 1.46-4.24 1.46s-3.1-.48-4.24-1.46a.58.58 0 0 1-.06-.8c.2-.24.56-.26.8-.06',
|
|
1144
|
+
fill: '#10243E',
|
|
1145
|
+
fillRule: 'nonzero',
|
|
1146
|
+
opacity: 1.0,
|
|
1147
|
+
},
|
|
1148
|
+
],
|
|
1149
|
+
},
|
|
1150
|
+
AllNetworksSolid: {
|
|
1151
|
+
viewBox: '0 0 24 24',
|
|
1152
|
+
paths: [
|
|
1153
|
+
{
|
|
1154
|
+
d: 'M15.333 13.998a1.335 1.335 0 1 1 0 2.67 1.335 1.335 0 0 1 0-2.67',
|
|
1155
|
+
fill: 'currentColor',
|
|
1156
|
+
fillRule: 'nonzero',
|
|
1157
|
+
opacity: 1.0,
|
|
1158
|
+
},
|
|
1159
|
+
{
|
|
1160
|
+
d: 'M12 0c6.627 0 12 5.373 12 12s-5.373 12-12 12S0 18.627 0 12 5.373 0 12 0M8 12.668A2 2 0 0 0 6 14.666V16c0 1.103.895 1.997 1.998 1.998h1.334A2 2 0 0 0 11.33 16v-1.334a2 2 0 0 0-1.998-1.998zm7.333 0a2.665 2.665 0 1 0 0 5.33 2.665 2.665 0 0 0 0-5.33M7.999 6.001A2 2 0 0 0 6.001 8v1.334c0 1.103.895 1.998 1.998 1.998h1.334a2 2 0 0 0 1.998-1.998V7.999a2 2 0 0 0-1.998-1.998zm6.667 0A2 2 0 0 0 12.668 8v1.334c0 1.103.895 1.998 1.998 1.998H16a2 2 0 0 0 1.998-1.998V7.999A2 2 0 0 0 16 6.001z',
|
|
1161
|
+
fill: 'currentColor',
|
|
1162
|
+
fillRule: 'evenodd',
|
|
1163
|
+
opacity: 1.0,
|
|
1164
|
+
},
|
|
1165
|
+
],
|
|
1166
|
+
},
|
|
1167
|
+
CrossedSmallSolid: {
|
|
1168
|
+
viewBox: '0 0 24 24',
|
|
1169
|
+
paths: [
|
|
1170
|
+
{
|
|
1171
|
+
d: 'M17.87 8.25 14.12 12l3.75 3.75-2.12 2.121-3.75-3.75-3.75 3.75-2.121-2.121L9.879 12l-3.75-3.75 2.12-2.121L12 9.879l3.75-3.75 2.122 2.121Z',
|
|
1172
|
+
fill: 'currentColor',
|
|
1173
|
+
fillRule: 'nonzero',
|
|
1174
|
+
opacity: 1.0,
|
|
1175
|
+
},
|
|
1176
|
+
],
|
|
1177
|
+
},
|
|
1178
|
+
AccountErrorCustom: {
|
|
1179
|
+
viewBox: '0 0 18 18',
|
|
1180
|
+
paths: [
|
|
1181
|
+
{
|
|
1182
|
+
d: 'M12.5 12.75a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5',
|
|
1183
|
+
fill: '#000',
|
|
1184
|
+
fillRule: 'nonzero',
|
|
1185
|
+
opacity: 0.447,
|
|
1186
|
+
},
|
|
1187
|
+
{
|
|
1188
|
+
d: 'M0 3.5A3.5 3.5 0 0 1 3.5 0h8.088A2.41 2.41 0 0 1 14 2.412V5h1a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3H4a4 4 0 0 1-4-4zm2 3.163V14a2 2 0 0 0 2 2h11a1 1 0 0 0 1-1V8a1 1 0 0 0-1-1H3.5c-.537 0-1.045-.12-1.5-.337M2 3.5A1.5 1.5 0 0 0 3.5 5H12V2.412A.41.41 0 0 0 11.588 2H3.5A1.5 1.5 0 0 0 2 3.5',
|
|
1189
|
+
fill: '#000',
|
|
1190
|
+
fillRule: 'evenodd',
|
|
1191
|
+
opacity: 0.447,
|
|
1192
|
+
},
|
|
1193
|
+
],
|
|
1194
|
+
},
|
|
1195
|
+
PlusSmallOutline: {
|
|
1196
|
+
viewBox: '0 0 24 24',
|
|
1197
|
+
paths: [
|
|
1198
|
+
{
|
|
1199
|
+
d: 'M13 11h5v2h-5v5h-2v-5H6v-2h5V6h2z',
|
|
1200
|
+
fill: 'currentColor',
|
|
1201
|
+
fillRule: 'nonzero',
|
|
1202
|
+
opacity: 1.0,
|
|
1203
|
+
},
|
|
1204
|
+
],
|
|
1205
|
+
},
|
|
1206
|
+
DotHorOutline: {
|
|
1207
|
+
viewBox: '0 0 24 24',
|
|
1208
|
+
paths: [
|
|
1209
|
+
{
|
|
1210
|
+
d: 'M6 14H2v-4h4zm8 0h-4v-4h4zm8 0h-4v-4h4z',
|
|
1211
|
+
fill: 'currentColor',
|
|
1212
|
+
fillRule: 'nonzero',
|
|
1213
|
+
opacity: 1.0,
|
|
1214
|
+
},
|
|
1215
|
+
],
|
|
1216
|
+
},
|
|
1217
|
+
ChevronRightSmallOutline: {
|
|
1218
|
+
viewBox: '0 0 24 24',
|
|
1219
|
+
paths: [
|
|
1220
|
+
{
|
|
1221
|
+
d: 'M15.414 12 10 17.414 8.586 16l4-4-4-4L10 6.586z',
|
|
1222
|
+
fill: 'currentColor',
|
|
1223
|
+
fillRule: 'nonzero',
|
|
1224
|
+
opacity: 1.0,
|
|
1225
|
+
},
|
|
1226
|
+
],
|
|
1227
|
+
},
|
|
1228
|
+
DragOutline: {
|
|
1229
|
+
viewBox: '0 0 24 24',
|
|
1230
|
+
paths: [
|
|
1231
|
+
{
|
|
1232
|
+
d: 'M11 21H7v-4h4zm6 0h-4v-4h4zm-6-7H7v-4h4zm6 0h-4v-4h4zm-6-7H7V3h4zm6 0h-4V3h4z',
|
|
1233
|
+
fill: 'currentColor',
|
|
1234
|
+
fillRule: 'nonzero',
|
|
1235
|
+
opacity: 1.0,
|
|
1236
|
+
},
|
|
1237
|
+
],
|
|
1238
|
+
},
|
|
1239
|
+
PencilOutline: {
|
|
1240
|
+
viewBox: '0 0 24 24',
|
|
1241
|
+
paths: [
|
|
1242
|
+
{
|
|
1243
|
+
d: 'M22.414 7.5 7.914 22H2v-5.914l14.5-14.5zM4 16.914V20h3.086l9.5-9.5L13.5 7.414zM14.914 6 18 9.086 19.586 7.5 16.5 4.414z',
|
|
1244
|
+
fill: 'currentColor',
|
|
1245
|
+
fillRule: 'evenodd',
|
|
1246
|
+
opacity: 1.0,
|
|
1247
|
+
},
|
|
1248
|
+
],
|
|
1249
|
+
},
|
|
1250
|
+
CheckboxCheckedCustom: {
|
|
1251
|
+
viewBox: '0 0 16 16',
|
|
1252
|
+
paths: [
|
|
1253
|
+
{
|
|
1254
|
+
d: 'M12.204 5.043a1 1 0 0 1 0 1.414l-4.5 4.5a1 1 0 0 1-1.414 0l-2-2a1 1 0 1 1 1.414-1.414l1.293 1.293 3.793-3.793a1 1 0 0 1 1.414 0',
|
|
1255
|
+
fill: 'currentColor',
|
|
1256
|
+
fillRule: 'evenodd',
|
|
1257
|
+
opacity: 1.0,
|
|
1258
|
+
},
|
|
1259
|
+
],
|
|
1260
|
+
},
|
|
1261
|
+
CheckboxIndeterminateCustom: {
|
|
1262
|
+
viewBox: '0 0 16 16',
|
|
1263
|
+
paths: [
|
|
1264
|
+
{
|
|
1265
|
+
d: 'M4 8a1 1 0 0 1 1-1h6a1 1 0 0 1 0 2H5a1 1 0 0 1-1-1',
|
|
1266
|
+
fill: 'currentColor',
|
|
1267
|
+
fillRule: 'evenodd',
|
|
1268
|
+
opacity: 1.0,
|
|
1269
|
+
},
|
|
1270
|
+
],
|
|
1271
|
+
},
|
|
1272
|
+
Circle: {
|
|
1273
|
+
viewBox: '0 0 24 24',
|
|
1274
|
+
paths: [
|
|
1275
|
+
{
|
|
1276
|
+
d: 'M0 12a12 12 0 1 0 24 0a12 12 0 1 0 -24 0',
|
|
1277
|
+
fill: 'currentColor',
|
|
1278
|
+
fillRule: 'nonzero',
|
|
1279
|
+
opacity: 1,
|
|
1280
|
+
},
|
|
1281
|
+
],
|
|
1282
|
+
},
|
|
1283
|
+
};
|
|
1284
|
+
function applySelectorIcon(element: HTMLElement, name: string) {
|
|
1285
|
+
const icon = selectorIcons[name];
|
|
1286
|
+
if (!icon) return;
|
|
1287
|
+
element.textContent = '';
|
|
1288
|
+
const svg = element.ownerDocument.createElementNS(
|
|
1289
|
+
'http://www.w3.org/2000/svg',
|
|
1290
|
+
'svg'
|
|
1291
|
+
);
|
|
1292
|
+
svg.setAttribute('viewBox', icon.viewBox);
|
|
1293
|
+
svg.setAttribute('width', '24');
|
|
1294
|
+
svg.setAttribute('height', '24');
|
|
1295
|
+
svg.setAttribute('aria-hidden', 'true');
|
|
1296
|
+
icon.paths.forEach((path) => {
|
|
1297
|
+
const child = element.ownerDocument.createElementNS(
|
|
1298
|
+
'http://www.w3.org/2000/svg',
|
|
1299
|
+
'path'
|
|
1300
|
+
);
|
|
1301
|
+
child.setAttribute('d', path.d);
|
|
1302
|
+
child.setAttribute('fill', path.fill);
|
|
1303
|
+
child.setAttribute('fill-rule', path.fillRule);
|
|
1304
|
+
child.setAttribute('fill-opacity', String(path.opacity));
|
|
1305
|
+
svg.appendChild(child);
|
|
1306
|
+
});
|
|
1307
|
+
element.appendChild(svg);
|
|
1308
|
+
}
|
|
1309
|
+
|
|
810
1310
|
function iconGlyph(name: string): string {
|
|
811
1311
|
const normalized = name.toLocaleLowerCase();
|
|
812
1312
|
if (normalized.includes('chevron')) {
|
|
@@ -841,7 +1341,8 @@ function visualFromRow(row: RowModel): LeadingVisual | undefined {
|
|
|
841
1341
|
|
|
842
1342
|
function createVisual(
|
|
843
1343
|
context: RenderContext,
|
|
844
|
-
visual: LeadingVisual | undefined
|
|
1344
|
+
visual: LeadingVisual | undefined,
|
|
1345
|
+
selectorPresentation?: string
|
|
845
1346
|
): HTMLElement | undefined {
|
|
846
1347
|
if (!visual) return undefined;
|
|
847
1348
|
if (visual.kind === 'stackedImages') {
|
|
@@ -873,6 +1374,7 @@ function createVisual(
|
|
|
873
1374
|
'ok-native-list-visual-fallback',
|
|
874
1375
|
iconGlyph(visual.name)
|
|
875
1376
|
);
|
|
1377
|
+
applySelectorIcon(fallback, visual.name);
|
|
876
1378
|
if (visual.tintColor) fallback.style.color = visual.tintColor;
|
|
877
1379
|
frame.appendChild(fallback);
|
|
878
1380
|
return frame;
|
|
@@ -885,6 +1387,7 @@ function createVisual(
|
|
|
885
1387
|
if (image) {
|
|
886
1388
|
image.className = 'ok-native-list-visual-main';
|
|
887
1389
|
frame.appendChild(image);
|
|
1390
|
+
if (selectorPresentation) paintSelectorImageBackground(image, frame);
|
|
888
1391
|
} else {
|
|
889
1392
|
frame.appendChild(
|
|
890
1393
|
createElement(
|
|
@@ -913,8 +1416,98 @@ function createVisual(
|
|
|
913
1416
|
corner.style.color = visual.cornerIcon.tintColor;
|
|
914
1417
|
if (visual.cornerIcon.backgroundColor)
|
|
915
1418
|
corner.style.background = visual.cornerIcon.backgroundColor;
|
|
1419
|
+
applySelectorIcon(corner, visual.cornerIcon.name);
|
|
916
1420
|
frame.appendChild(corner);
|
|
917
1421
|
}
|
|
1422
|
+
// OneKey patch: image failure uses the same source-derived fallback as v1.
|
|
1423
|
+
if ('fallbackIcon' in visual && visual.fallbackIcon) {
|
|
1424
|
+
const icon = visual.fallbackIcon;
|
|
1425
|
+
const showFallback = () => {
|
|
1426
|
+
if (image) {
|
|
1427
|
+
disposeWebImageRetries(image);
|
|
1428
|
+
image.remove();
|
|
1429
|
+
}
|
|
1430
|
+
frame
|
|
1431
|
+
.querySelector(
|
|
1432
|
+
'.ok-native-list-visual-fallback:not(.ok-native-list-visual-corner)'
|
|
1433
|
+
)
|
|
1434
|
+
?.remove();
|
|
1435
|
+
const fallback = createElement(
|
|
1436
|
+
context.document,
|
|
1437
|
+
'span',
|
|
1438
|
+
'ok-native-list-visual-fallback'
|
|
1439
|
+
);
|
|
1440
|
+
applySelectorIcon(fallback, icon.name);
|
|
1441
|
+
if (icon.tintColor) fallback.style.color = icon.tintColor;
|
|
1442
|
+
frame.prepend(fallback);
|
|
1443
|
+
};
|
|
1444
|
+
if (image) image.addEventListener('error', showFallback, { once: true });
|
|
1445
|
+
else showFallback();
|
|
1446
|
+
}
|
|
1447
|
+
if ('borderStyle' in visual && visual.borderStyle === 'dashed') {
|
|
1448
|
+
frame.style.border =
|
|
1449
|
+
'2px dashed ' + (visual.borderColor ?? 'var(--nl-disabled)');
|
|
1450
|
+
frame.style.boxSizing = 'border-box';
|
|
1451
|
+
}
|
|
1452
|
+
if ('overlays' in visual)
|
|
1453
|
+
visual.overlays?.forEach((overlay) => {
|
|
1454
|
+
const corner = createElement(
|
|
1455
|
+
context.document,
|
|
1456
|
+
'span',
|
|
1457
|
+
'ok-native-list-visual-overlay',
|
|
1458
|
+
overlay.text
|
|
1459
|
+
);
|
|
1460
|
+
const size = overlay.size ?? 20;
|
|
1461
|
+
const isWalletText =
|
|
1462
|
+
selectorPresentation === 'walletSidebar' &&
|
|
1463
|
+
!!overlay.text &&
|
|
1464
|
+
!overlay.image &&
|
|
1465
|
+
!overlay.name;
|
|
1466
|
+
corner.style.width =
|
|
1467
|
+
isWalletText && overlay.width === undefined
|
|
1468
|
+
? 'auto'
|
|
1469
|
+
: String(overlay.width ?? size) + 'px';
|
|
1470
|
+
corner.style.height =
|
|
1471
|
+
String(overlay.height ?? (isWalletText ? 16 : size)) + 'px';
|
|
1472
|
+
corner.style.padding = isWalletText
|
|
1473
|
+
? '0 2px'
|
|
1474
|
+
: String(overlay.padding ?? 0) + 'px';
|
|
1475
|
+
if (isWalletText) {
|
|
1476
|
+
corner.style.fontSize = '12px';
|
|
1477
|
+
corner.style.lineHeight = '16px';
|
|
1478
|
+
corner.style.fontWeight = '400';
|
|
1479
|
+
}
|
|
1480
|
+
if (
|
|
1481
|
+
isWalletText ||
|
|
1482
|
+
overlay.width !== undefined ||
|
|
1483
|
+
overlay.height !== undefined
|
|
1484
|
+
)
|
|
1485
|
+
corner.style.borderRadius = '9999px';
|
|
1486
|
+
const offsetX = String(-(overlay.offsetX ?? overlay.offset ?? 2)) + 'px';
|
|
1487
|
+
const offsetY = String(-(overlay.offsetY ?? overlay.offset ?? 2)) + 'px';
|
|
1488
|
+
corner.style.background = overlay.backgroundColor ?? 'transparent';
|
|
1489
|
+
corner.style.color = overlay.tintColor ?? 'var(--nl-secondary)';
|
|
1490
|
+
if (overlay.position === 'topLeft') {
|
|
1491
|
+
corner.style.left = offsetX;
|
|
1492
|
+
corner.style.top = offsetY;
|
|
1493
|
+
} else {
|
|
1494
|
+
corner.style.right = offsetX;
|
|
1495
|
+
corner.style.bottom = offsetY;
|
|
1496
|
+
}
|
|
1497
|
+
if (overlay.image) {
|
|
1498
|
+
const overlayImage = createImage(context, overlay.image);
|
|
1499
|
+
if (overlayImage) {
|
|
1500
|
+
corner.appendChild(overlayImage);
|
|
1501
|
+
if (selectorPresentation)
|
|
1502
|
+
paintSelectorImageBackground(
|
|
1503
|
+
overlayImage,
|
|
1504
|
+
corner,
|
|
1505
|
+
overlay.padding ?? 0
|
|
1506
|
+
);
|
|
1507
|
+
}
|
|
1508
|
+
} else if (overlay.name) applySelectorIcon(corner, overlay.name);
|
|
1509
|
+
frame.appendChild(corner);
|
|
1510
|
+
});
|
|
918
1511
|
return frame;
|
|
919
1512
|
}
|
|
920
1513
|
|
|
@@ -1022,6 +1615,22 @@ function createCheckbox(
|
|
|
1022
1615
|
setData(element, 'checkboxFallback', accessory.state);
|
|
1023
1616
|
setData(element, 'nativeListAction', accessory.actionKey ?? 'selection');
|
|
1024
1617
|
setData(element, 'selectionScope', accessory.target?.scope ?? 'row');
|
|
1618
|
+
const row = context.snapshot.rows[context.itemIndex];
|
|
1619
|
+
if (row && 'presentation' in row && row.presentation === 'networkSelector') {
|
|
1620
|
+
setData(element, 'selector', 'networkSelector');
|
|
1621
|
+
for (const [state, name] of [
|
|
1622
|
+
['checked', 'CheckboxCheckedCustom'],
|
|
1623
|
+
['indeterminate', 'CheckboxIndeterminateCustom'],
|
|
1624
|
+
]) {
|
|
1625
|
+
const holder = createElement(context.document, 'span');
|
|
1626
|
+
applySelectorIcon(holder, name);
|
|
1627
|
+
const svg = holder.firstElementChild;
|
|
1628
|
+
if (svg) {
|
|
1629
|
+
svg.setAttribute('data-state', state);
|
|
1630
|
+
element.appendChild(svg);
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1025
1634
|
if (accessory.target?.scope === 'section')
|
|
1026
1635
|
setData(element, 'selectionKey', accessory.target.sectionKey);
|
|
1027
1636
|
else if (accessory.target?.scope === 'row')
|
|
@@ -1046,6 +1655,7 @@ function createIconAction(
|
|
|
1046
1655
|
element.setAttribute('type', 'button');
|
|
1047
1656
|
element.toggleAttribute('disabled', Boolean(disabled));
|
|
1048
1657
|
}
|
|
1658
|
+
applySelectorIcon(element, name);
|
|
1049
1659
|
if (actionKey) setData(element, 'nativeListAction', actionKey);
|
|
1050
1660
|
if (tintColor) element.style.color = tintColor;
|
|
1051
1661
|
return element;
|
|
@@ -1060,6 +1670,36 @@ function markActionAnchorSource(
|
|
|
1060
1670
|
if (slot !== undefined) setData(element, 'nativeListAnchorSlot', slot);
|
|
1061
1671
|
}
|
|
1062
1672
|
|
|
1673
|
+
// OneKey patch: the compact zero-count digits share the amount baseline.
|
|
1674
|
+
function applyValueSegments(
|
|
1675
|
+
element: HTMLElement,
|
|
1676
|
+
segments:
|
|
1677
|
+
| readonly Readonly<{ text: string; style?: 'subscript' }>[]
|
|
1678
|
+
| undefined,
|
|
1679
|
+
fontSize = 16,
|
|
1680
|
+
lineHeight = 24,
|
|
1681
|
+
weight = 500
|
|
1682
|
+
) {
|
|
1683
|
+
if (!segments?.length) return;
|
|
1684
|
+
element.textContent = '';
|
|
1685
|
+
element.style.fontSize = String(fontSize) + 'px';
|
|
1686
|
+
element.style.lineHeight = String(lineHeight) + 'px';
|
|
1687
|
+
element.style.fontWeight = String(weight);
|
|
1688
|
+
segments.forEach((segment) => {
|
|
1689
|
+
const span = createElement(
|
|
1690
|
+
element.ownerDocument,
|
|
1691
|
+
'span',
|
|
1692
|
+
undefined,
|
|
1693
|
+
segment.text
|
|
1694
|
+
);
|
|
1695
|
+
if (segment.style === 'subscript') {
|
|
1696
|
+
span.style.fontSize = String(Math.ceil(fontSize * 0.6)) + 'px';
|
|
1697
|
+
span.style.lineHeight = String(fontSize) + 'px';
|
|
1698
|
+
}
|
|
1699
|
+
element.appendChild(span);
|
|
1700
|
+
});
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1063
1703
|
function createAccessory(
|
|
1064
1704
|
context: RenderContext,
|
|
1065
1705
|
rowKey: string,
|
|
@@ -1080,6 +1720,25 @@ function createAccessory(
|
|
|
1080
1720
|
accessory.tintColor
|
|
1081
1721
|
);
|
|
1082
1722
|
markActionAnchorSource(element, 'trailingAccessory', slot);
|
|
1723
|
+
setData(element, 'testid', accessory.testID);
|
|
1724
|
+
if (accessory.hoverActionKey)
|
|
1725
|
+
setData(element, 'nativeListHoverAction', accessory.hoverActionKey);
|
|
1726
|
+
if (accessory.accessibilityLabel)
|
|
1727
|
+
element.setAttribute('aria-label', accessory.accessibilityLabel);
|
|
1728
|
+
const row = context.snapshot.rows[context.itemIndex];
|
|
1729
|
+
if (
|
|
1730
|
+
row &&
|
|
1731
|
+
'presentation' in row &&
|
|
1732
|
+
row.presentation === 'accountSelector'
|
|
1733
|
+
) {
|
|
1734
|
+
setData(element, 'nativeListAnchorInset', 7);
|
|
1735
|
+
// OneKey patch: the create-address button omits IconButton's one-point border.
|
|
1736
|
+
if (row.height !== undefined && accessory.name === 'PlusSmallOutline') {
|
|
1737
|
+
setData(element, 'nativeListAccountControl', 'createAddress');
|
|
1738
|
+
if (!accessory.tintColor)
|
|
1739
|
+
element.style.color = 'var(--nl-icon-subdued)';
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1083
1742
|
return element;
|
|
1084
1743
|
}
|
|
1085
1744
|
if (accessory.kind === 'spinner') {
|
|
@@ -1099,6 +1758,7 @@ function createAccessory(
|
|
|
1099
1758
|
switch (accessory.kind) {
|
|
1100
1759
|
case 'value':
|
|
1101
1760
|
element.textContent = accessory.text;
|
|
1761
|
+
applyValueSegments(element, accessory.textSegments);
|
|
1102
1762
|
if (accessory.secondary)
|
|
1103
1763
|
element.classList.add('ok-native-list-accessory-secondary');
|
|
1104
1764
|
break;
|
|
@@ -1157,6 +1817,30 @@ function appendAccessories(
|
|
|
1157
1817
|
'span',
|
|
1158
1818
|
'ok-native-list-accessories'
|
|
1159
1819
|
);
|
|
1820
|
+
const row = context.snapshot.rows[context.itemIndex];
|
|
1821
|
+
if (
|
|
1822
|
+
row &&
|
|
1823
|
+
row.height !== undefined &&
|
|
1824
|
+
'presentation' in row &&
|
|
1825
|
+
row.presentation === 'networkSelector'
|
|
1826
|
+
) {
|
|
1827
|
+
container.style.gap = accessories.some(
|
|
1828
|
+
(accessory) => accessory.kind === 'checkbox'
|
|
1829
|
+
)
|
|
1830
|
+
? '12px'
|
|
1831
|
+
: '20px';
|
|
1832
|
+
}
|
|
1833
|
+
if (
|
|
1834
|
+
row &&
|
|
1835
|
+
row.height !== undefined &&
|
|
1836
|
+
'presentation' in row &&
|
|
1837
|
+
row.presentation === 'accountSelector' &&
|
|
1838
|
+
accessories.length === 1 &&
|
|
1839
|
+
accessories[0]?.kind === 'icon' &&
|
|
1840
|
+
accessories[0].name === 'PlusSmallOutline'
|
|
1841
|
+
) {
|
|
1842
|
+
setData(container, 'nativeListAccountControl', 'createAddress');
|
|
1843
|
+
}
|
|
1160
1844
|
accessories.forEach((accessory, slot) =>
|
|
1161
1845
|
container.appendChild(createAccessory(context, rowKey, accessory, slot))
|
|
1162
1846
|
);
|
|
@@ -1234,7 +1918,88 @@ function createSectionHeader(
|
|
|
1234
1918
|
markActionAnchorSource(titleIcon, 'leadingAction');
|
|
1235
1919
|
body.appendChild(titleIcon);
|
|
1236
1920
|
}
|
|
1237
|
-
|
|
1921
|
+
// OneKey patch: section title help has its own measurable action target.
|
|
1922
|
+
// body.appendChild(createTextColumn(context, row.title, row.subtitle));
|
|
1923
|
+
const column = createTextColumn(context, row.title, row.subtitle);
|
|
1924
|
+
const title = column.firstElementChild as HTMLElement;
|
|
1925
|
+
title.classList.add('ok-native-list-section-title');
|
|
1926
|
+
if (row.titleActionKey) {
|
|
1927
|
+
setData(title, 'nativeListAction', row.titleActionKey);
|
|
1928
|
+
markActionAnchorSource(title, 'leadingAction');
|
|
1929
|
+
title.setAttribute('role', 'button');
|
|
1930
|
+
title.tabIndex = 0;
|
|
1931
|
+
title.style.alignSelf = 'flex-start';
|
|
1932
|
+
title.style.maxWidth = '100%';
|
|
1933
|
+
// OneKey patch: explicit network headers reserve a separate 3-point underline area.
|
|
1934
|
+
if (row.presentation !== 'networkSelector' || row.height === undefined) {
|
|
1935
|
+
title.style.textDecoration = 'underline dotted';
|
|
1936
|
+
title.style.textUnderlineOffset = '6px';
|
|
1937
|
+
}
|
|
1938
|
+
if (row.titleActionOnHover) setData(title, 'nativeListHoverAction', true);
|
|
1939
|
+
}
|
|
1940
|
+
if (row.presentation === 'networkSelector' && row.height !== undefined) {
|
|
1941
|
+
body.style.padding =
|
|
1942
|
+
row.variant === 'summary' ? '24px 12px 20px' : '0 12px';
|
|
1943
|
+
body.style.backgroundColor = 'var(--nl-bg)';
|
|
1944
|
+
body.style.gap = row.checkbox ? '12px' : '8px';
|
|
1945
|
+
title.style.fontSize = row.variant === 'summary' ? '16px' : '14px';
|
|
1946
|
+
title.style.lineHeight = row.variant === 'summary' ? '24px' : '20px';
|
|
1947
|
+
title.style.fontWeight =
|
|
1948
|
+
row.variant === 'summary' || (row.titleActionKey && !row.checkbox)
|
|
1949
|
+
? '500'
|
|
1950
|
+
: '600';
|
|
1951
|
+
if (row.titleActionKey) {
|
|
1952
|
+
const text = createElement(
|
|
1953
|
+
context.document,
|
|
1954
|
+
'span',
|
|
1955
|
+
'ok-native-list-section-title-text',
|
|
1956
|
+
row.title
|
|
1957
|
+
);
|
|
1958
|
+
text.style.overflow = 'hidden';
|
|
1959
|
+
text.style.textOverflow = 'ellipsis';
|
|
1960
|
+
text.style.maxWidth = '100%';
|
|
1961
|
+
const dotted = context.document.createElementNS(
|
|
1962
|
+
'http://www.w3.org/2000/svg',
|
|
1963
|
+
'svg'
|
|
1964
|
+
);
|
|
1965
|
+
dotted.setAttribute('height', '2');
|
|
1966
|
+
dotted.style.cssText =
|
|
1967
|
+
'display:block;position:absolute;left:0;bottom:0;width:100%;height:2px;color:var(--nl-secondary)';
|
|
1968
|
+
const line = context.document.createElementNS(
|
|
1969
|
+
'http://www.w3.org/2000/svg',
|
|
1970
|
+
'line'
|
|
1971
|
+
);
|
|
1972
|
+
for (const [key, value] of Object.entries({
|
|
1973
|
+
x1: '1',
|
|
1974
|
+
y1: '1',
|
|
1975
|
+
x2: '100%',
|
|
1976
|
+
y2: '1',
|
|
1977
|
+
stroke: 'currentColor',
|
|
1978
|
+
'stroke-width': '1.5',
|
|
1979
|
+
'stroke-dasharray': '0,4',
|
|
1980
|
+
'stroke-linecap': 'round',
|
|
1981
|
+
}))
|
|
1982
|
+
line.setAttribute(key, value);
|
|
1983
|
+
// OneKey patch: keep both round caps inside the original full-width viewport.
|
|
1984
|
+
const lineViewport = context.document.createElementNS(
|
|
1985
|
+
'http://www.w3.org/2000/svg',
|
|
1986
|
+
'svg'
|
|
1987
|
+
);
|
|
1988
|
+
lineViewport.setAttribute('width', 'calc(100% - 1px)');
|
|
1989
|
+
lineViewport.setAttribute('height', '2');
|
|
1990
|
+
lineViewport.setAttribute('overflow', 'visible');
|
|
1991
|
+
lineViewport.appendChild(line);
|
|
1992
|
+
dotted.appendChild(lineViewport);
|
|
1993
|
+
// OneKey patch: SVG intrinsic width must not expand the title action beyond its text.
|
|
1994
|
+
title.style.display = 'block';
|
|
1995
|
+
title.style.position = 'relative';
|
|
1996
|
+
title.style.width = 'fit-content';
|
|
1997
|
+
title.style.paddingBottom = '3px';
|
|
1998
|
+
text.style.display = 'block';
|
|
1999
|
+
title.replaceChildren(text, dotted);
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
body.appendChild(column);
|
|
1238
2003
|
if (row.value) {
|
|
1239
2004
|
const value = createElement(
|
|
1240
2005
|
context.document,
|
|
@@ -1244,6 +2009,19 @@ function createSectionHeader(
|
|
|
1244
2009
|
: 'ok-native-list-value ok-native-list-section-value',
|
|
1245
2010
|
row.value
|
|
1246
2011
|
);
|
|
2012
|
+
applyValueSegments(value, row.valueSegments);
|
|
2013
|
+
if (row.presentation === 'networkSelector' && row.height !== undefined) {
|
|
2014
|
+
value.style.fontFamily = 'inherit';
|
|
2015
|
+
value.style.fontSize = '16px';
|
|
2016
|
+
value.style.lineHeight = '24px';
|
|
2017
|
+
value.style.fontWeight = '500';
|
|
2018
|
+
if (row.valueActionKey) {
|
|
2019
|
+
value.style.color = 'var(--nl-secondary)';
|
|
2020
|
+
value.style.padding = '0';
|
|
2021
|
+
value.style.flexShrink = '0';
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
if (row.valueActionTestID) setData(value, 'testid', row.valueActionTestID);
|
|
1247
2025
|
if (row.valueActionKey) {
|
|
1248
2026
|
value.setAttribute('type', 'button');
|
|
1249
2027
|
setData(value, 'nativeListAction', row.valueActionKey);
|
|
@@ -1292,6 +2070,8 @@ function createActionRow(
|
|
|
1292
2070
|
row.title
|
|
1293
2071
|
);
|
|
1294
2072
|
setData(title, 'tone', row.tone);
|
|
2073
|
+
if (row.presentation === 'accountSelector' && row.icon)
|
|
2074
|
+
title.style.fontWeight = '500';
|
|
1295
2075
|
body.appendChild(title);
|
|
1296
2076
|
if (row.checkbox)
|
|
1297
2077
|
body.appendChild(createCheckbox(context, row.key, row.checkbox));
|
|
@@ -1309,6 +2089,27 @@ function createSystemRow(
|
|
|
1309
2089
|
'ok-native-list-row ok-native-list-system'
|
|
1310
2090
|
);
|
|
1311
2091
|
setData(body, 'variant', row.variant);
|
|
2092
|
+
if (row.variant === 'warning') {
|
|
2093
|
+
body.classList.add('ok-native-list-warning');
|
|
2094
|
+
body.style.borderColor = row.borderColor ?? 'var(--nl-separator)';
|
|
2095
|
+
body.appendChild(
|
|
2096
|
+
createElement(
|
|
2097
|
+
context.document,
|
|
2098
|
+
'span',
|
|
2099
|
+
'ok-native-list-warning-title',
|
|
2100
|
+
row.title
|
|
2101
|
+
)
|
|
2102
|
+
);
|
|
2103
|
+
body.appendChild(
|
|
2104
|
+
createElement(
|
|
2105
|
+
context.document,
|
|
2106
|
+
'span',
|
|
2107
|
+
'ok-native-list-warning-message',
|
|
2108
|
+
row.message
|
|
2109
|
+
)
|
|
2110
|
+
);
|
|
2111
|
+
return body;
|
|
2112
|
+
}
|
|
1312
2113
|
if (row.variant === 'loading')
|
|
1313
2114
|
body.appendChild(
|
|
1314
2115
|
createElement(context.document, 'span', 'ok-native-list-spinner')
|
|
@@ -1703,6 +2504,15 @@ function createIdentityActivityOrMessageRow(
|
|
|
1703
2504
|
.filter(Boolean)
|
|
1704
2505
|
.join(' ')
|
|
1705
2506
|
);
|
|
2507
|
+
setData(
|
|
2508
|
+
body,
|
|
2509
|
+
'nativeListSelector',
|
|
2510
|
+
row.height !== undefined ? presentation : undefined
|
|
2511
|
+
);
|
|
2512
|
+
if (row.type === 'identity' && row.titleActionKey && row.titleActionOnHover) {
|
|
2513
|
+
setData(body, 'nativeListHoverAction', row.titleActionKey);
|
|
2514
|
+
markActionAnchorSource(body, 'leadingAction');
|
|
2515
|
+
}
|
|
1706
2516
|
if (row.type === 'identity' && row.leadingAction) {
|
|
1707
2517
|
const action = createIconAction(
|
|
1708
2518
|
context,
|
|
@@ -1714,7 +2524,44 @@ function createIdentityActivityOrMessageRow(
|
|
|
1714
2524
|
markActionAnchorSource(action, 'leadingAction');
|
|
1715
2525
|
body.appendChild(action);
|
|
1716
2526
|
}
|
|
1717
|
-
const visual = createVisual(
|
|
2527
|
+
const visual = createVisual(
|
|
2528
|
+
context,
|
|
2529
|
+
visualFromRow(row),
|
|
2530
|
+
row.height !== undefined ? presentation : undefined
|
|
2531
|
+
);
|
|
2532
|
+
if (
|
|
2533
|
+
visual &&
|
|
2534
|
+
row.type === 'identity' &&
|
|
2535
|
+
row.height !== undefined &&
|
|
2536
|
+
row.presentation === 'walletSidebar' &&
|
|
2537
|
+
'fallbackIcon' in row.leading &&
|
|
2538
|
+
row.leading.fallbackIcon?.name === 'LockSolid'
|
|
2539
|
+
) {
|
|
2540
|
+
// OneKey patch: hidden-wallet locks use WalletAvatar's full 40-point icon.
|
|
2541
|
+
const icon = visual.querySelector<SVGElement>(
|
|
2542
|
+
'.ok-native-list-visual-fallback svg'
|
|
2543
|
+
);
|
|
2544
|
+
if (icon) {
|
|
2545
|
+
icon.style.width = '40px';
|
|
2546
|
+
icon.style.height = '40px';
|
|
2547
|
+
}
|
|
2548
|
+
const fallback = visual.querySelector<HTMLElement>(
|
|
2549
|
+
'.ok-native-list-visual-fallback'
|
|
2550
|
+
);
|
|
2551
|
+
if (fallback) {
|
|
2552
|
+
fallback.style.borderRadius = '0';
|
|
2553
|
+
fallback.style.overflow = 'visible';
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
if (
|
|
2557
|
+
visual &&
|
|
2558
|
+
row.type === 'identity' &&
|
|
2559
|
+
row.height !== undefined &&
|
|
2560
|
+
row.presentation === 'walletSidebar' &&
|
|
2561
|
+
'borderStyle' in row.leading &&
|
|
2562
|
+
row.leading.borderStyle === 'dashed'
|
|
2563
|
+
)
|
|
2564
|
+
visual.style.borderWidth = '1px';
|
|
1718
2565
|
if (visual) body.appendChild(visual);
|
|
1719
2566
|
if (row.type === 'activity' && row.secondaryLeading) {
|
|
1720
2567
|
const secondVisual = createVisual(context, row.secondaryLeading);
|
|
@@ -1737,8 +2584,82 @@ function createIdentityActivityOrMessageRow(
|
|
|
1737
2584
|
subtitle,
|
|
1738
2585
|
row.type === 'identity' ? row.tertiary : undefined,
|
|
1739
2586
|
row.type === 'identity' ? row.tertiaryTone : undefined,
|
|
1740
|
-
row.type === 'identity'
|
|
2587
|
+
row.type === 'identity' && presentation !== 'walletSidebar'
|
|
2588
|
+
? row.badges
|
|
2589
|
+
: undefined
|
|
1741
2590
|
);
|
|
2591
|
+
// OneKey patch: match existing search, subtitle fragments, and sidebar badges.
|
|
2592
|
+
if (row.type === 'identity') {
|
|
2593
|
+
const titleElement = column.firstElementChild as HTMLElement;
|
|
2594
|
+
if (row.titleMatch?.length) {
|
|
2595
|
+
const firstText = titleElement.firstChild;
|
|
2596
|
+
if (firstText) firstText.remove();
|
|
2597
|
+
const fragment = context.document.createDocumentFragment();
|
|
2598
|
+
let offset = 0;
|
|
2599
|
+
row.titleMatch.forEach(({ start, end }) => {
|
|
2600
|
+
fragment.appendChild(
|
|
2601
|
+
context.document.createTextNode(row.title.slice(offset, start))
|
|
2602
|
+
);
|
|
2603
|
+
const match = createElement(
|
|
2604
|
+
context.document,
|
|
2605
|
+
'span',
|
|
2606
|
+
'ok-native-list-info',
|
|
2607
|
+
row.title.slice(start, end)
|
|
2608
|
+
);
|
|
2609
|
+
fragment.appendChild(match);
|
|
2610
|
+
offset = end;
|
|
2611
|
+
});
|
|
2612
|
+
fragment.appendChild(
|
|
2613
|
+
context.document.createTextNode(row.title.slice(offset))
|
|
2614
|
+
);
|
|
2615
|
+
titleElement.prepend(fragment);
|
|
2616
|
+
}
|
|
2617
|
+
if (row.subtitleSegments?.length) {
|
|
2618
|
+
column.querySelector('.ok-native-list-secondary')?.remove();
|
|
2619
|
+
const segments = createElement(
|
|
2620
|
+
context.document,
|
|
2621
|
+
'span',
|
|
2622
|
+
'ok-native-list-subtitle-segments'
|
|
2623
|
+
);
|
|
2624
|
+
row.subtitleSegments.forEach((segment) => {
|
|
2625
|
+
if (segment.separatorBefore)
|
|
2626
|
+
segments.appendChild(
|
|
2627
|
+
createElement(
|
|
2628
|
+
context.document,
|
|
2629
|
+
'span',
|
|
2630
|
+
'ok-native-list-subtitle-dot'
|
|
2631
|
+
)
|
|
2632
|
+
);
|
|
2633
|
+
const text = createElement(
|
|
2634
|
+
context.document,
|
|
2635
|
+
'span',
|
|
2636
|
+
'ok-native-list-secondary',
|
|
2637
|
+
segment.text
|
|
2638
|
+
);
|
|
2639
|
+
applyValueSegments(text, segment.textSegments, 14, 20, 400);
|
|
2640
|
+
setData(text, 'tone', segment.tone);
|
|
2641
|
+
text.style.color =
|
|
2642
|
+
segment.tone === 'disabled'
|
|
2643
|
+
? 'var(--nl-disabled)'
|
|
2644
|
+
: segment.tone === 'caution'
|
|
2645
|
+
? 'var(--nl-caution)'
|
|
2646
|
+
: toneColor(segment.tone, 'secondary');
|
|
2647
|
+
segments.appendChild(text);
|
|
2648
|
+
});
|
|
2649
|
+
column.insertBefore(segments, titleElement.nextSibling);
|
|
2650
|
+
}
|
|
2651
|
+
if (presentation === 'walletSidebar' && row.badges?.length) {
|
|
2652
|
+
const badges = createElement(
|
|
2653
|
+
context.document,
|
|
2654
|
+
'span',
|
|
2655
|
+
'ok-native-list-wallet-badges'
|
|
2656
|
+
);
|
|
2657
|
+
row.badges.forEach((badge) =>
|
|
2658
|
+
badges.appendChild(createBadge(context, badge))
|
|
2659
|
+
);
|
|
2660
|
+
column.appendChild(badges);
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
1742
2663
|
if (row.type === 'activity' && row.status)
|
|
1743
2664
|
column.appendChild(
|
|
1744
2665
|
createElement(
|
|
@@ -1814,6 +2735,21 @@ function createIdentityActivityOrMessageRow(
|
|
|
1814
2735
|
return body;
|
|
1815
2736
|
}
|
|
1816
2737
|
|
|
2738
|
+
// OneKey patch: SizableText enables tabular digits without replacing its font family.
|
|
2739
|
+
function applySelectorTabularNumbers(body: HTMLElement, row: RowModel) {
|
|
2740
|
+
if (
|
|
2741
|
+
!('presentation' in row) ||
|
|
2742
|
+
!['accountSelector', 'networkSelector', 'walletSidebar'].includes(
|
|
2743
|
+
row.presentation ?? ''
|
|
2744
|
+
)
|
|
2745
|
+
)
|
|
2746
|
+
return;
|
|
2747
|
+
body.style.fontVariantNumeric = 'tabular-nums';
|
|
2748
|
+
body.querySelectorAll<HTMLElement>('span,button').forEach((text) => {
|
|
2749
|
+
text.style.fontVariantNumeric = 'tabular-nums';
|
|
2750
|
+
});
|
|
2751
|
+
}
|
|
2752
|
+
|
|
1817
2753
|
function createWalletGroupRow(
|
|
1818
2754
|
context: RenderContext,
|
|
1819
2755
|
row: Extract<RowModel, { type: 'walletGroup' }>
|
|
@@ -1830,11 +2766,19 @@ function createWalletGroupRow(
|
|
|
1830
2766
|
'ok-native-list-wallet-member'
|
|
1831
2767
|
);
|
|
1832
2768
|
setData(memberElement, 'nativeListGroupMemberKey', member.key);
|
|
2769
|
+
setData(memberElement, 'testid', member.testID);
|
|
1833
2770
|
setData(memberElement, 'nativeListGroupParent', memberIndex === 0);
|
|
1834
2771
|
setData(memberElement, 'nativeListSelected', member.selected);
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
);
|
|
2772
|
+
// OneKey patch: grouped members have the same selector typography as standalone wallets.
|
|
2773
|
+
// memberElement.appendChild(createIdentityActivityOrMessageRow(context, member));
|
|
2774
|
+
const memberBody = createIdentityActivityOrMessageRow(context, member);
|
|
2775
|
+
applySelectorTabularNumbers(memberBody, member);
|
|
2776
|
+
memberElement.appendChild(memberBody);
|
|
2777
|
+
// OneKey patch: group children use their own measured badge height.
|
|
2778
|
+
memberElement.style.flexBasis =
|
|
2779
|
+
String(member.height ?? 68 + (member.badges?.length ? 24 : 0)) + 'px';
|
|
2780
|
+
memberElement.style.height = memberElement.style.flexBasis;
|
|
2781
|
+
memberElement.style.opacity = String(member.opacity ?? 1);
|
|
1838
2782
|
body.appendChild(memberElement);
|
|
1839
2783
|
});
|
|
1840
2784
|
return body;
|
|
@@ -1894,9 +2838,18 @@ export class NativeListWebEngine {
|
|
|
1894
2838
|
private resizeObserver: ResizeObserver | undefined;
|
|
1895
2839
|
private pendingScroll: PendingScroll | undefined;
|
|
1896
2840
|
private lastVisibleSignature: string | undefined;
|
|
2841
|
+
// OneKey patch: URI leases outlive DOM overscan only inside this bounded window.
|
|
2842
|
+
private readonly avatarLeases = new Map<string, AvatarLease>();
|
|
2843
|
+
private avatarOffset = 0;
|
|
2844
|
+
private avatarDirection = 1;
|
|
1897
2845
|
private reachedGeneration: number | undefined;
|
|
1898
2846
|
private stickyKey: string | undefined;
|
|
1899
2847
|
private previewTimer: number | undefined;
|
|
2848
|
+
private sectionIndexEntries: readonly Readonly<{
|
|
2849
|
+
key: string;
|
|
2850
|
+
title: string;
|
|
2851
|
+
position: number;
|
|
2852
|
+
}>[] = [];
|
|
1900
2853
|
private pointerReorder: PointerReorderState | undefined;
|
|
1901
2854
|
private keyboardReorder: KeyboardReorderState | undefined;
|
|
1902
2855
|
private reorderMoveFrame: number | undefined;
|
|
@@ -1919,6 +2872,8 @@ export class NativeListWebEngine {
|
|
|
1919
2872
|
private lastViewportWidth = -1;
|
|
1920
2873
|
private lastViewportHeight = -1;
|
|
1921
2874
|
private destroyed = false;
|
|
2875
|
+
// OneKey patch: warning banners are measured after normal browser text wrapping.
|
|
2876
|
+
private measuredWarningHeights = new Map<string, number>();
|
|
1922
2877
|
|
|
1923
2878
|
constructor(
|
|
1924
2879
|
host: HTMLElement,
|
|
@@ -2004,6 +2959,9 @@ export class NativeListWebEngine {
|
|
|
2004
2959
|
passive: true,
|
|
2005
2960
|
});
|
|
2006
2961
|
this.root.addEventListener('click', this.handleClick);
|
|
2962
|
+
// OneKey patch: preserve web tooltip hover for section titles.
|
|
2963
|
+
this.root.addEventListener('pointerover', this.handleTitlePointerOver);
|
|
2964
|
+
this.root.addEventListener('pointerout', this.handleTitlePointerOut);
|
|
2007
2965
|
this.root.addEventListener('keydown', this.handleKeyDown);
|
|
2008
2966
|
this.viewport.addEventListener(
|
|
2009
2967
|
'pointerdown',
|
|
@@ -2160,7 +3118,10 @@ export class NativeListWebEngine {
|
|
|
2160
3118
|
const index = resolveLocationIndex(this.snapshot.rows, params);
|
|
2161
3119
|
if (index === undefined) {
|
|
2162
3120
|
const sectionCount = this.snapshot.rows.filter(
|
|
2163
|
-
(row) =>
|
|
3121
|
+
(row) =>
|
|
3122
|
+
row.type === 'sectionHeader' &&
|
|
3123
|
+
row.sticky !== false &&
|
|
3124
|
+
row.variant !== 'summary'
|
|
2164
3125
|
).length;
|
|
2165
3126
|
this.emitScrollFailure(
|
|
2166
3127
|
params.itemIndex,
|
|
@@ -2219,6 +3180,8 @@ export class NativeListWebEngine {
|
|
|
2219
3180
|
);
|
|
2220
3181
|
this.viewport.removeEventListener('scroll', this.handleScroll);
|
|
2221
3182
|
this.root.removeEventListener('click', this.handleClick);
|
|
3183
|
+
this.root.removeEventListener('pointerover', this.handleTitlePointerOver);
|
|
3184
|
+
this.root.removeEventListener('pointerout', this.handleTitlePointerOut);
|
|
2222
3185
|
this.root.removeEventListener('keydown', this.handleKeyDown);
|
|
2223
3186
|
this.cancelPointerReorder(true);
|
|
2224
3187
|
this.viewport.removeEventListener(
|
|
@@ -2251,25 +3214,29 @@ export class NativeListWebEngine {
|
|
|
2251
3214
|
this.viewport.removeEventListener('pointerup', this.handlePullEnd);
|
|
2252
3215
|
this.viewport.removeEventListener('pointercancel', this.handlePullEnd);
|
|
2253
3216
|
const host = this.root.parentElement;
|
|
3217
|
+
disposeWebImageRetries(this.root);
|
|
3218
|
+
this.pool.forEach(disposeWebImageRetries);
|
|
2254
3219
|
this.root.remove();
|
|
2255
3220
|
this.hideReorderPreview();
|
|
2256
3221
|
this.reorderPreview.remove();
|
|
2257
3222
|
if (host) host.style.position = this.previousHostPosition;
|
|
2258
3223
|
this.mounted.clear();
|
|
2259
3224
|
this.pool.length = 0;
|
|
3225
|
+
this.avatarLeases.forEach((release) => release());
|
|
3226
|
+
this.avatarLeases.clear();
|
|
2260
3227
|
}
|
|
2261
3228
|
|
|
2262
3229
|
private setSnapshot(
|
|
2263
3230
|
snapshot: NativeListSnapshot,
|
|
2264
3231
|
selectedKeys?: ReadonlySet<string>
|
|
2265
3232
|
) {
|
|
3233
|
+
this.measuredWarningHeights.clear();
|
|
2266
3234
|
this.snapshot = snapshot;
|
|
2267
3235
|
this.rows = effectiveRows(snapshot);
|
|
2268
3236
|
this.selectedKeys =
|
|
2269
3237
|
selectedKeys ?? selectionStateFromSnapshot(snapshot).selectedKeys;
|
|
2270
3238
|
if (this.reachedGeneration !== snapshot.generation)
|
|
2271
3239
|
this.reachedGeneration = undefined;
|
|
2272
|
-
this.renderSectionIndex();
|
|
2273
3240
|
this.applyTheme();
|
|
2274
3241
|
this.recomputeLayout();
|
|
2275
3242
|
this.renderFooter();
|
|
@@ -2288,6 +3255,11 @@ export class NativeListWebEngine {
|
|
|
2288
3255
|
'--nl-primary': theme.primaryText,
|
|
2289
3256
|
'--nl-secondary': theme.secondaryText,
|
|
2290
3257
|
'--nl-disabled': theme.disabledText,
|
|
3258
|
+
'--nl-caution': theme.caution ?? '#AB6400',
|
|
3259
|
+
'--nl-caution-background': theme.cautionBackground,
|
|
3260
|
+
'--nl-checkbox-background': theme.checkboxBackground,
|
|
3261
|
+
'--nl-checkbox-border': theme.checkboxBorder,
|
|
3262
|
+
'--nl-checkbox-icon': theme.checkboxIcon,
|
|
2291
3263
|
'--nl-icon': theme.icon,
|
|
2292
3264
|
'--nl-icon-subdued': theme.iconSubdued,
|
|
2293
3265
|
'--nl-separator': theme.separator,
|
|
@@ -2316,18 +3288,31 @@ export class NativeListWebEngine {
|
|
|
2316
3288
|
viewportHeight !== this.lastViewportHeight)
|
|
2317
3289
|
) {
|
|
2318
3290
|
this.invalidateActionAnchor('layout');
|
|
3291
|
+
this.measuredWarningHeights.clear();
|
|
2319
3292
|
}
|
|
2320
3293
|
this.lastViewportWidth = viewportWidth;
|
|
2321
3294
|
this.lastViewportHeight = viewportHeight;
|
|
2322
3295
|
const previousHorizontal = this.layout.horizontal;
|
|
3296
|
+
const measuredSnapshot: NativeListSnapshot = {
|
|
3297
|
+
...this.snapshot,
|
|
3298
|
+
rows: this.snapshot.rows.map((row) =>
|
|
3299
|
+
row.type === 'system' &&
|
|
3300
|
+
row.variant === 'warning' &&
|
|
3301
|
+
row.height === undefined &&
|
|
3302
|
+
this.measuredWarningHeights.has(row.key)
|
|
3303
|
+
? { ...row, height: this.measuredWarningHeights.get(row.key) }
|
|
3304
|
+
: row
|
|
3305
|
+
),
|
|
3306
|
+
};
|
|
2323
3307
|
this.layout = computeWebListLayout(
|
|
2324
|
-
|
|
3308
|
+
measuredSnapshot,
|
|
2325
3309
|
viewportWidth,
|
|
2326
3310
|
viewportHeight,
|
|
2327
3311
|
this.reorderCompactKey
|
|
2328
3312
|
);
|
|
2329
3313
|
this.content.style.width = String(this.layout.contentWidth) + 'px';
|
|
2330
3314
|
this.content.style.height = String(this.layout.contentHeight) + 'px';
|
|
3315
|
+
this.renderSectionIndex(viewportHeight || DEFAULT_VIEWPORT_HEIGHT);
|
|
2331
3316
|
if (previousHorizontal !== this.layout.horizontal) {
|
|
2332
3317
|
this.viewport.scrollLeft = 0;
|
|
2333
3318
|
this.viewport.scrollTop = 0;
|
|
@@ -2336,7 +3321,62 @@ export class NativeListWebEngine {
|
|
|
2336
3321
|
this.performPendingScroll();
|
|
2337
3322
|
};
|
|
2338
3323
|
|
|
3324
|
+
private updateAvatarWindow() {
|
|
3325
|
+
const offset = this.currentOffset();
|
|
3326
|
+
if (offset !== this.avatarOffset)
|
|
3327
|
+
this.avatarDirection = Math.sign(offset - this.avatarOffset);
|
|
3328
|
+
this.avatarOffset = offset;
|
|
3329
|
+
const visible = visibleWebLayoutItems(
|
|
3330
|
+
this.layout,
|
|
3331
|
+
offset,
|
|
3332
|
+
this.viewportLength(),
|
|
3333
|
+
0
|
|
3334
|
+
);
|
|
3335
|
+
const first = visible[0]?.index ?? -1;
|
|
3336
|
+
const last = visible[visible.length - 1]?.index ?? -1;
|
|
3337
|
+
const candidates = avatarPrefetchWindow(
|
|
3338
|
+
this.rows,
|
|
3339
|
+
first,
|
|
3340
|
+
last,
|
|
3341
|
+
this.avatarDirection
|
|
3342
|
+
);
|
|
3343
|
+
const desired = new Set(
|
|
3344
|
+
candidates
|
|
3345
|
+
.map(({ source }) => canonicalNativeListAvatarUri(source.uri))
|
|
3346
|
+
.filter((uri) => uri !== undefined)
|
|
3347
|
+
);
|
|
3348
|
+
this.avatarLeases.forEach((release, uri) => {
|
|
3349
|
+
if (!desired.has(uri)) {
|
|
3350
|
+
release();
|
|
3351
|
+
this.avatarLeases.delete(uri);
|
|
3352
|
+
}
|
|
3353
|
+
});
|
|
3354
|
+
candidates.forEach(({ source, priority }) => {
|
|
3355
|
+
const uri = canonicalNativeListAvatarUri(source.uri);
|
|
3356
|
+
if (!uri) return;
|
|
3357
|
+
const existing = this.avatarLeases.get(uri);
|
|
3358
|
+
if (existing) existing.setPriority(priority);
|
|
3359
|
+
else {
|
|
3360
|
+
let lease: AvatarLease | undefined;
|
|
3361
|
+
lease = acquireNativeListAvatar(
|
|
3362
|
+
this.document,
|
|
3363
|
+
uri,
|
|
3364
|
+
() => {},
|
|
3365
|
+
() => {
|
|
3366
|
+
if (this.avatarLeases.get(uri) === lease) {
|
|
3367
|
+
lease?.();
|
|
3368
|
+
this.avatarLeases.delete(uri);
|
|
3369
|
+
}
|
|
3370
|
+
},
|
|
3371
|
+
priority
|
|
3372
|
+
);
|
|
3373
|
+
this.avatarLeases.set(uri, lease);
|
|
3374
|
+
}
|
|
3375
|
+
});
|
|
3376
|
+
}
|
|
3377
|
+
|
|
2339
3378
|
private renderWindow() {
|
|
3379
|
+
this.updateAvatarWindow();
|
|
2340
3380
|
const viewportLength = this.viewportLength();
|
|
2341
3381
|
const visible = webLayoutItemsForMount(
|
|
2342
3382
|
this.layout,
|
|
@@ -2350,6 +3390,8 @@ export class NativeListWebEngine {
|
|
|
2350
3390
|
if (!desired.has(index)) {
|
|
2351
3391
|
this.invalidateActionAnchorForElement(element);
|
|
2352
3392
|
this.mounted.delete(index);
|
|
3393
|
+
if (disposeWebImageRetries(element))
|
|
3394
|
+
element.removeAttribute('data-render-signature');
|
|
2353
3395
|
element.remove();
|
|
2354
3396
|
this.pool.push(element);
|
|
2355
3397
|
}
|
|
@@ -2377,6 +3419,27 @@ export class NativeListWebEngine {
|
|
|
2377
3419
|
element.dataset.renderSignature = signature;
|
|
2378
3420
|
}
|
|
2379
3421
|
});
|
|
3422
|
+
let measuredWarningChanged = false;
|
|
3423
|
+
this.mounted.forEach((element, index) => {
|
|
3424
|
+
const row = this.rows[index];
|
|
3425
|
+
if (
|
|
3426
|
+
row?.type !== 'system' ||
|
|
3427
|
+
row.variant !== 'warning' ||
|
|
3428
|
+
row.height !== undefined
|
|
3429
|
+
)
|
|
3430
|
+
return;
|
|
3431
|
+
const height =
|
|
3432
|
+
element.querySelector<HTMLElement>('.ok-native-list-warning')
|
|
3433
|
+
?.offsetHeight ?? 0;
|
|
3434
|
+
if (height > 0 && height !== this.measuredWarningHeights.get(row.key)) {
|
|
3435
|
+
this.measuredWarningHeights.set(row.key, height);
|
|
3436
|
+
measuredWarningChanged = true;
|
|
3437
|
+
}
|
|
3438
|
+
});
|
|
3439
|
+
if (measuredWarningChanged) {
|
|
3440
|
+
this.recomputeLayout();
|
|
3441
|
+
return;
|
|
3442
|
+
}
|
|
2380
3443
|
this.updateVisibleSelection();
|
|
2381
3444
|
this.updateVisibleState();
|
|
2382
3445
|
}
|
|
@@ -2395,6 +3458,7 @@ export class NativeListWebEngine {
|
|
|
2395
3458
|
overlay = false
|
|
2396
3459
|
) {
|
|
2397
3460
|
this.invalidateActionAnchorForElement(element);
|
|
3461
|
+
disposeWebImageRetries(element);
|
|
2398
3462
|
const bindingEpoch = String(++this.bindingEpochCounter);
|
|
2399
3463
|
element.className = overlay
|
|
2400
3464
|
? 'ok-native-list-item ok-native-list-sticky'
|
|
@@ -2403,6 +3467,9 @@ export class NativeListWebEngine {
|
|
|
2403
3467
|
setData(element, 'nativeListBindingEpoch', bindingEpoch);
|
|
2404
3468
|
setData(element, 'nativeListRowIndex', index);
|
|
2405
3469
|
setData(element, 'nativeListDisabled', Boolean(row.disabled));
|
|
3470
|
+
setData(element, 'testid', row.testID);
|
|
3471
|
+
// OneKey patch: deprecation dims a row without disabling its actions.
|
|
3472
|
+
element.style.opacity = String(row.opacity ?? 1);
|
|
2406
3473
|
setData(element, 'nativeListReorderable', this.isReorderable(row));
|
|
2407
3474
|
setData(
|
|
2408
3475
|
element,
|
|
@@ -2435,12 +3502,90 @@ export class NativeListWebEngine {
|
|
|
2435
3502
|
selectedKeys: this.selectedKeys,
|
|
2436
3503
|
itemIndex: index,
|
|
2437
3504
|
};
|
|
2438
|
-
|
|
3505
|
+
const body = createRowBody(context, row);
|
|
3506
|
+
applySelectorTabularNumbers(body, row);
|
|
3507
|
+
// OneKey patch: explicit selector fields preserve original page geometry.
|
|
3508
|
+
element.style.contain = row.backgroundFullWidth ? 'layout style' : '';
|
|
3509
|
+
if (row.backgroundColor) body.style.backgroundColor = row.backgroundColor;
|
|
3510
|
+
if (row.backgroundFullWidth && row.backgroundColor) {
|
|
3511
|
+
const bleed = paddingValues(this.snapshot).horizontal;
|
|
3512
|
+
body.style.position = 'relative';
|
|
3513
|
+
body.style.overflow = 'visible';
|
|
3514
|
+
body.style.boxShadow =
|
|
3515
|
+
String(-bleed) +
|
|
3516
|
+
'px 0 ' +
|
|
3517
|
+
row.backgroundColor +
|
|
3518
|
+
',' +
|
|
3519
|
+
String(bleed) +
|
|
3520
|
+
'px 0 ' +
|
|
3521
|
+
row.backgroundColor;
|
|
3522
|
+
}
|
|
3523
|
+
if (row.type === 'identity' && row.height !== undefined) {
|
|
3524
|
+
const title = body.querySelector<HTMLElement>('.ok-native-list-title');
|
|
3525
|
+
if (row.presentation === 'accountSelector') {
|
|
3526
|
+
body.style.gap = '12px';
|
|
3527
|
+
body.style.borderRadius = '12px';
|
|
3528
|
+
if ('shape' in row.leading && row.leading.shape === 'rounded') {
|
|
3529
|
+
const visual = body.querySelector<HTMLElement>(
|
|
3530
|
+
'.ok-native-list-visual'
|
|
3531
|
+
);
|
|
3532
|
+
if (visual) visual.style.borderRadius = '8px';
|
|
3533
|
+
}
|
|
3534
|
+
if (title) title.style.lineHeight = '24px';
|
|
3535
|
+
}
|
|
3536
|
+
if (row.presentation === 'networkSelector') {
|
|
3537
|
+
body.style.borderRadius = '12px';
|
|
3538
|
+
const visual = body.querySelector<HTMLElement>(
|
|
3539
|
+
'.ok-native-list-visual'
|
|
3540
|
+
);
|
|
3541
|
+
if (visual) {
|
|
3542
|
+
visual.style.width = '32px';
|
|
3543
|
+
visual.style.height = '32px';
|
|
3544
|
+
visual.style.flexBasis = '32px';
|
|
3545
|
+
}
|
|
3546
|
+
if (
|
|
3547
|
+
row.leading.kind === 'network' &&
|
|
3548
|
+
!row.leading.image &&
|
|
3549
|
+
!row.leading.fallbackIcon &&
|
|
3550
|
+
row.leading.fallbackText
|
|
3551
|
+
) {
|
|
3552
|
+
const fallback = visual?.querySelector<HTMLElement>(
|
|
3553
|
+
'.ok-native-list-visual-fallback'
|
|
3554
|
+
);
|
|
3555
|
+
if (fallback) {
|
|
3556
|
+
fallback.style.fontSize = '19px';
|
|
3557
|
+
fallback.style.lineHeight = '27px';
|
|
3558
|
+
fallback.style.fontWeight = '600';
|
|
3559
|
+
fallback.style.color = 'var(--nl-inverse-text)';
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3562
|
+
visual
|
|
3563
|
+
?.querySelectorAll<HTMLElement>('.ok-native-list-visual-main')
|
|
3564
|
+
.forEach((image) => {
|
|
3565
|
+
image.style.width = '32px';
|
|
3566
|
+
image.style.height = '32px';
|
|
3567
|
+
});
|
|
3568
|
+
if (title) {
|
|
3569
|
+
title.style.fontSize = '16px';
|
|
3570
|
+
title.style.lineHeight = '24px';
|
|
3571
|
+
title.style.fontWeight = '500';
|
|
3572
|
+
}
|
|
3573
|
+
body
|
|
3574
|
+
.querySelectorAll<HTMLElement>('.ok-native-list-accessory')
|
|
3575
|
+
.forEach((value) => {
|
|
3576
|
+
value.style.fontSize = '16px';
|
|
3577
|
+
value.style.lineHeight = '24px';
|
|
3578
|
+
value.style.fontWeight = '500';
|
|
3579
|
+
});
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
element.replaceChildren(body);
|
|
2439
3583
|
}
|
|
2440
3584
|
|
|
2441
3585
|
private renderFooter() {
|
|
2442
3586
|
const row = this.snapshot.fixedFooter;
|
|
2443
3587
|
this.invalidateActionAnchorForElement(this.footer);
|
|
3588
|
+
disposeWebImageRetries(this.footer);
|
|
2444
3589
|
this.footer.replaceChildren();
|
|
2445
3590
|
if (!row) return;
|
|
2446
3591
|
const element = createElement(this.document, 'div', 'ok-native-list-item');
|
|
@@ -2459,25 +3604,79 @@ export class NativeListWebEngine {
|
|
|
2459
3604
|
this.footer.appendChild(element);
|
|
2460
3605
|
}
|
|
2461
3606
|
|
|
2462
|
-
private
|
|
3607
|
+
private sectionIndexVisibleEntryIndices(
|
|
3608
|
+
viewportHeight: number
|
|
3609
|
+
): readonly number[] {
|
|
3610
|
+
const entryCount = this.sectionIndexEntries.length;
|
|
3611
|
+
if (entryCount <= 1) return entryCount ? [0] : [];
|
|
3612
|
+
const availableHeight = Math.max(
|
|
3613
|
+
0,
|
|
3614
|
+
viewportHeight - SECTION_INDEX_EDGE_PADDING * 2
|
|
3615
|
+
);
|
|
3616
|
+
const maxVisible = Math.max(
|
|
3617
|
+
2,
|
|
3618
|
+
Math.floor(availableHeight / SECTION_INDEX_MIN_LABEL_SPACING) + 1
|
|
3619
|
+
);
|
|
3620
|
+
if (entryCount <= maxVisible) {
|
|
3621
|
+
return Array.from({ length: entryCount }, (_, index) => index);
|
|
3622
|
+
}
|
|
3623
|
+
const result = new Set<number>();
|
|
3624
|
+
for (let slot = 0; slot < maxVisible; slot += 1) {
|
|
3625
|
+
result.add(Math.round((slot * (entryCount - 1)) / (maxVisible - 1)));
|
|
3626
|
+
}
|
|
3627
|
+
return [...result].sort((left, right) => left - right);
|
|
3628
|
+
}
|
|
3629
|
+
|
|
3630
|
+
private renderSectionIndex(viewportHeight: number) {
|
|
2463
3631
|
this.indexRail.replaceChildren();
|
|
2464
3632
|
if (!sectionIndexEnabled(this.snapshot)) {
|
|
3633
|
+
this.sectionIndexEntries = [];
|
|
2465
3634
|
this.indexRail.hidden = true;
|
|
2466
3635
|
return;
|
|
2467
3636
|
}
|
|
3637
|
+
this.sectionIndexEntries = this.snapshot.rows.flatMap((row, position) =>
|
|
3638
|
+
row.type === 'sectionHeader' && row.indexTitle
|
|
3639
|
+
? [{ key: row.key, title: row.indexTitle, position }]
|
|
3640
|
+
: []
|
|
3641
|
+
);
|
|
3642
|
+
if (
|
|
3643
|
+
this.sectionIndexEntries.length === 0 ||
|
|
3644
|
+
viewportHeight < SECTION_INDEX_MIN_HEIGHT
|
|
3645
|
+
) {
|
|
3646
|
+
this.indexRail.hidden = true;
|
|
3647
|
+
return;
|
|
3648
|
+
}
|
|
3649
|
+
const visibleEntryIndices =
|
|
3650
|
+
this.sectionIndexVisibleEntryIndices(viewportHeight);
|
|
3651
|
+
setData(
|
|
3652
|
+
this.indexRail,
|
|
3653
|
+
'compact',
|
|
3654
|
+
visibleEntryIndices.length < this.sectionIndexEntries.length
|
|
3655
|
+
);
|
|
2468
3656
|
const fragment = this.document.createDocumentFragment();
|
|
2469
|
-
|
|
2470
|
-
|
|
3657
|
+
visibleEntryIndices.forEach((entryIndex) => {
|
|
3658
|
+
const entry = this.sectionIndexEntries[entryIndex];
|
|
3659
|
+
if (!entry) return;
|
|
2471
3660
|
const button = createElement(
|
|
2472
3661
|
this.document,
|
|
2473
3662
|
'button',
|
|
2474
3663
|
'ok-native-list-index-button',
|
|
2475
|
-
|
|
3664
|
+
entry.title
|
|
2476
3665
|
);
|
|
2477
3666
|
button.setAttribute('type', 'button');
|
|
2478
|
-
button.setAttribute('aria-label', 'Jump to ' +
|
|
2479
|
-
setData(button, '
|
|
2480
|
-
setData(button, '
|
|
3667
|
+
button.setAttribute('aria-label', 'Jump to ' + entry.title);
|
|
3668
|
+
setData(button, 'sectionEntryIndex', entryIndex);
|
|
3669
|
+
setData(button, 'sectionPosition', entry.position);
|
|
3670
|
+
setData(button, 'sectionKey', entry.key);
|
|
3671
|
+
const progress =
|
|
3672
|
+
this.sectionIndexEntries.length === 1
|
|
3673
|
+
? 0.5
|
|
3674
|
+
: entryIndex / (this.sectionIndexEntries.length - 1);
|
|
3675
|
+
button.style.top =
|
|
3676
|
+
String(
|
|
3677
|
+
SECTION_INDEX_EDGE_PADDING +
|
|
3678
|
+
progress * (viewportHeight - SECTION_INDEX_EDGE_PADDING * 2)
|
|
3679
|
+
) + 'px';
|
|
2481
3680
|
fragment.appendChild(button);
|
|
2482
3681
|
});
|
|
2483
3682
|
this.indexRail.appendChild(fragment);
|
|
@@ -2487,7 +3686,9 @@ export class NativeListWebEngine {
|
|
|
2487
3686
|
private updateVisibleSelection() {
|
|
2488
3687
|
const update = (element: HTMLElement, row: RowModel | undefined) => {
|
|
2489
3688
|
if (!row) return;
|
|
2490
|
-
|
|
3689
|
+
// OneKey patch: selector adapters mark active rows independently of checkbox selection.
|
|
3690
|
+
// const selected = this.selectedKeys.has(row.key);
|
|
3691
|
+
const selected = row.selected === true || this.selectedKeys.has(row.key);
|
|
2491
3692
|
setData(element, 'nativeListSelected', selected);
|
|
2492
3693
|
element.setAttribute('aria-selected', String(selected));
|
|
2493
3694
|
element
|
|
@@ -2548,7 +3749,9 @@ export class NativeListWebEngine {
|
|
|
2548
3749
|
}
|
|
2549
3750
|
this.checkEndReached(last?.index ?? -1);
|
|
2550
3751
|
this.updateStickyHeader(first?.index ?? -1);
|
|
2551
|
-
|
|
3752
|
+
// OneKey patch: index highlighting follows header positions at scroll boundaries.
|
|
3753
|
+
// this.updateSectionIndex(first?.index ?? -1);
|
|
3754
|
+
this.updateSectionIndex();
|
|
2552
3755
|
}
|
|
2553
3756
|
|
|
2554
3757
|
private updateStickyHeader(firstVisibleIndex: number) {
|
|
@@ -2564,7 +3767,11 @@ export class NativeListWebEngine {
|
|
|
2564
3767
|
let index = -1;
|
|
2565
3768
|
for (let cursor = firstVisibleIndex; cursor >= 0; cursor -= 1) {
|
|
2566
3769
|
const row = this.rows[cursor];
|
|
2567
|
-
if (
|
|
3770
|
+
if (
|
|
3771
|
+
row?.type === 'sectionHeader' &&
|
|
3772
|
+
row.sticky !== false &&
|
|
3773
|
+
row.variant !== 'summary'
|
|
3774
|
+
) {
|
|
2568
3775
|
index = cursor;
|
|
2569
3776
|
break;
|
|
2570
3777
|
}
|
|
@@ -2595,6 +3802,7 @@ export class NativeListWebEngine {
|
|
|
2595
3802
|
const candidate = this.rows[cursor];
|
|
2596
3803
|
if (
|
|
2597
3804
|
candidate?.type === 'sectionHeader' &&
|
|
3805
|
+
candidate.sticky !== false &&
|
|
2598
3806
|
candidate.variant !== 'summary'
|
|
2599
3807
|
) {
|
|
2600
3808
|
nextIndex = cursor;
|
|
@@ -2610,12 +3818,17 @@ export class NativeListWebEngine {
|
|
|
2610
3818
|
this.updateVisibleSelection();
|
|
2611
3819
|
}
|
|
2612
3820
|
|
|
2613
|
-
private updateSectionIndex(firstVisibleIndex: number) {
|
|
3821
|
+
// private updateSectionIndex(firstVisibleIndex: number) {
|
|
3822
|
+
private updateSectionIndex() {
|
|
2614
3823
|
let activeKey: string | undefined;
|
|
2615
3824
|
this.snapshot.rows.forEach((row, index) => {
|
|
2616
3825
|
if (
|
|
2617
|
-
|
|
3826
|
+
// OneKey patch: a spacer ending exactly at the viewport is not the active section.
|
|
3827
|
+
// index <= firstVisibleIndex &&
|
|
3828
|
+
itemStart(this.layout.items[index], this.layout.horizontal) <=
|
|
3829
|
+
this.currentOffset() &&
|
|
2618
3830
|
row.type === 'sectionHeader' &&
|
|
3831
|
+
row.sticky !== false &&
|
|
2619
3832
|
row.indexTitle
|
|
2620
3833
|
)
|
|
2621
3834
|
activeKey = row.key;
|
|
@@ -2793,7 +4006,14 @@ export class NativeListWebEngine {
|
|
|
2793
4006
|
if (!source || !bindingEpoch || !rowElement.contains(actionElement))
|
|
2794
4007
|
return undefined;
|
|
2795
4008
|
this.invalidateActionAnchor('rebind');
|
|
2796
|
-
const
|
|
4009
|
+
const actualRect = actionElement.getBoundingClientRect();
|
|
4010
|
+
const inset = Number(actionElement.dataset.nativeListAnchorInset ?? 0);
|
|
4011
|
+
const rect = {
|
|
4012
|
+
left: actualRect.left + inset,
|
|
4013
|
+
top: actualRect.top + inset,
|
|
4014
|
+
width: actualRect.width - inset * 2,
|
|
4015
|
+
height: actualRect.height - inset * 2,
|
|
4016
|
+
};
|
|
2797
4017
|
const token = [
|
|
2798
4018
|
this.actionAnchorInstanceId,
|
|
2799
4019
|
this.snapshot.generation,
|
|
@@ -2866,7 +4086,9 @@ export class NativeListWebEngine {
|
|
|
2866
4086
|
rowElement?: HTMLElement,
|
|
2867
4087
|
sourceElement = rowElement
|
|
2868
4088
|
) {
|
|
2869
|
-
|
|
4089
|
+
// OneKey patch: missing-address rows keep their create-address accessory interactive.
|
|
4090
|
+
// if (row.disabled) return;
|
|
4091
|
+
if (row.disabled || row.pressDisabled) return;
|
|
2870
4092
|
if (
|
|
2871
4093
|
this.snapshot.selection?.rowPressToggles &&
|
|
2872
4094
|
this.snapshot.selection.mode !== 'none' &&
|
|
@@ -2894,6 +4116,56 @@ export class NativeListWebEngine {
|
|
|
2894
4116
|
}
|
|
2895
4117
|
}
|
|
2896
4118
|
|
|
4119
|
+
// OneKey patch: hover opens the same anchored help action as native taps.
|
|
4120
|
+
private handleTitlePointerOver = (event: PointerEvent) => {
|
|
4121
|
+
const target = event.target;
|
|
4122
|
+
if (!(target instanceof Element)) return;
|
|
4123
|
+
const action = target.closest<HTMLElement>(
|
|
4124
|
+
'[data-native-list-hover-action]'
|
|
4125
|
+
);
|
|
4126
|
+
if (
|
|
4127
|
+
!action ||
|
|
4128
|
+
(event.relatedTarget instanceof Node &&
|
|
4129
|
+
action.contains(event.relatedTarget))
|
|
4130
|
+
)
|
|
4131
|
+
return;
|
|
4132
|
+
const rowElement = action.closest<HTMLElement>(
|
|
4133
|
+
'[data-native-list-row-key]'
|
|
4134
|
+
);
|
|
4135
|
+
const row = this.rowAtElement(rowElement);
|
|
4136
|
+
const memberKey = action.closest<HTMLElement>(
|
|
4137
|
+
'[data-native-list-group-member-key]'
|
|
4138
|
+
)?.dataset.nativeListGroupMemberKey;
|
|
4139
|
+
const sourceRow =
|
|
4140
|
+
row?.type === 'walletGroup'
|
|
4141
|
+
? [row.parent, ...row.children].find(
|
|
4142
|
+
(member) => member.key === memberKey
|
|
4143
|
+
) ?? row
|
|
4144
|
+
: row;
|
|
4145
|
+
const actionKey =
|
|
4146
|
+
action.dataset.nativeListHoverAction === 'true'
|
|
4147
|
+
? action.dataset.nativeListAction
|
|
4148
|
+
: action.dataset.nativeListHoverAction;
|
|
4149
|
+
if (sourceRow && !sourceRow.disabled && actionKey)
|
|
4150
|
+
this.emitRowAction(sourceRow, actionKey, action, rowElement ?? undefined);
|
|
4151
|
+
};
|
|
4152
|
+
|
|
4153
|
+
private handleTitlePointerOut = (event: PointerEvent) => {
|
|
4154
|
+
const target = event.target;
|
|
4155
|
+
if (!(target instanceof Element)) return;
|
|
4156
|
+
const action = target.closest<HTMLElement>(
|
|
4157
|
+
'[data-native-list-hover-action]'
|
|
4158
|
+
);
|
|
4159
|
+
if (
|
|
4160
|
+
!action ||
|
|
4161
|
+
(event.relatedTarget instanceof Node &&
|
|
4162
|
+
action.contains(event.relatedTarget))
|
|
4163
|
+
)
|
|
4164
|
+
return;
|
|
4165
|
+
if (this.actionAnchor?.actionElement === action)
|
|
4166
|
+
this.invalidateActionAnchor('pointerLeave');
|
|
4167
|
+
};
|
|
4168
|
+
|
|
2897
4169
|
private handleClick = (event: Event) => {
|
|
2898
4170
|
if (Date.now() < this.suppressClickUntil) {
|
|
2899
4171
|
event.preventDefault();
|
|
@@ -2944,6 +4216,16 @@ export class NativeListWebEngine {
|
|
|
2944
4216
|
};
|
|
2945
4217
|
|
|
2946
4218
|
private handleKeyDown = (event: KeyboardEvent) => {
|
|
4219
|
+
// OneKey patch: non-button title help supports keyboard activation.
|
|
4220
|
+
if (
|
|
4221
|
+
(event.key === 'Enter' || event.key === ' ') &&
|
|
4222
|
+
event.target instanceof HTMLElement &&
|
|
4223
|
+
event.target.matches('[role="button"][data-native-list-action]')
|
|
4224
|
+
) {
|
|
4225
|
+
event.preventDefault();
|
|
4226
|
+
event.target.click();
|
|
4227
|
+
return;
|
|
4228
|
+
}
|
|
2947
4229
|
if (event.key === 'Escape') {
|
|
2948
4230
|
if (this.pointerReorder?.active) {
|
|
2949
4231
|
event.preventDefault();
|
|
@@ -3073,7 +4355,10 @@ export class NativeListWebEngine {
|
|
|
3073
4355
|
this.frameHandle = this.requestFrame(() => {
|
|
3074
4356
|
this.frameHandle = undefined;
|
|
3075
4357
|
if (this.virtualizationEnabled) this.renderWindow();
|
|
3076
|
-
else
|
|
4358
|
+
else {
|
|
4359
|
+
this.updateAvatarWindow();
|
|
4360
|
+
this.updateVisibleState();
|
|
4361
|
+
}
|
|
3077
4362
|
});
|
|
3078
4363
|
}
|
|
3079
4364
|
|
|
@@ -3090,13 +4375,27 @@ export class NativeListWebEngine {
|
|
|
3090
4375
|
else view?.clearTimeout(handle);
|
|
3091
4376
|
}
|
|
3092
4377
|
|
|
3093
|
-
private selectIndexPosition(
|
|
4378
|
+
private selectIndexPosition(
|
|
4379
|
+
position: number,
|
|
4380
|
+
title: string,
|
|
4381
|
+
previewClientY?: number
|
|
4382
|
+
) {
|
|
3094
4383
|
this.scrollToIndex(position, {
|
|
3095
4384
|
animated: false,
|
|
3096
4385
|
alignment: 'start',
|
|
3097
4386
|
viewPosition: 0,
|
|
3098
4387
|
viewOffset: 0,
|
|
3099
4388
|
});
|
|
4389
|
+
const frame = this.viewportFrame.getBoundingClientRect();
|
|
4390
|
+
if (previewClientY !== undefined && frame.height > 0) {
|
|
4391
|
+
const previewY = Math.min(
|
|
4392
|
+
frame.height - 24,
|
|
4393
|
+
Math.max(24, previewClientY - frame.top)
|
|
4394
|
+
);
|
|
4395
|
+
this.indexPreview.style.top = String(previewY) + 'px';
|
|
4396
|
+
} else {
|
|
4397
|
+
this.indexPreview.style.top = '50%';
|
|
4398
|
+
}
|
|
3100
4399
|
this.indexPreview.textContent = title;
|
|
3101
4400
|
setData(this.indexPreview, 'visible', true);
|
|
3102
4401
|
if (this.previewTimer !== undefined)
|
|
@@ -3106,37 +4405,69 @@ export class NativeListWebEngine {
|
|
|
3106
4405
|
}, 180);
|
|
3107
4406
|
}
|
|
3108
4407
|
|
|
3109
|
-
private
|
|
3110
|
-
|
|
3111
|
-
|
|
4408
|
+
private sectionIndexEntryAtEvent(event: PointerEvent):
|
|
4409
|
+
| Readonly<{
|
|
4410
|
+
entry: NativeListWebEngine['sectionIndexEntries'][number];
|
|
4411
|
+
previewClientY: number;
|
|
4412
|
+
}>
|
|
4413
|
+
| undefined {
|
|
4414
|
+
const rail = this.indexRail.getBoundingClientRect();
|
|
4415
|
+
if (this.sectionIndexEntries.length === 0 || rail.height <= 0) {
|
|
4416
|
+
return undefined;
|
|
4417
|
+
}
|
|
4418
|
+
const availableHeight = Math.max(
|
|
4419
|
+
1,
|
|
4420
|
+
rail.height - SECTION_INDEX_EDGE_PADDING * 2
|
|
3112
4421
|
);
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
4422
|
+
const progress = Math.min(
|
|
4423
|
+
1,
|
|
4424
|
+
Math.max(
|
|
4425
|
+
0,
|
|
4426
|
+
(event.clientY - rail.top - SECTION_INDEX_EDGE_PADDING) /
|
|
4427
|
+
availableHeight
|
|
4428
|
+
)
|
|
3118
4429
|
);
|
|
4430
|
+
const entryIndex = Math.round(
|
|
4431
|
+
progress * (this.sectionIndexEntries.length - 1)
|
|
4432
|
+
);
|
|
4433
|
+
const entry = this.sectionIndexEntries[entryIndex];
|
|
4434
|
+
return entry ? { entry, previewClientY: event.clientY } : undefined;
|
|
3119
4435
|
}
|
|
3120
4436
|
|
|
3121
4437
|
private handleIndexPointer = (event: PointerEvent) => {
|
|
3122
4438
|
if (event.type === 'pointermove' && event.buttons === 0) return;
|
|
3123
|
-
const
|
|
3124
|
-
if (!
|
|
4439
|
+
const selection = this.sectionIndexEntryAtEvent(event);
|
|
4440
|
+
if (!selection) return;
|
|
3125
4441
|
event.preventDefault();
|
|
4442
|
+
if (event.type === 'pointerdown') {
|
|
4443
|
+
this.indexRail.setPointerCapture?.(event.pointerId);
|
|
4444
|
+
}
|
|
3126
4445
|
this.selectIndexPosition(
|
|
3127
|
-
|
|
3128
|
-
|
|
4446
|
+
selection.entry.position,
|
|
4447
|
+
selection.entry.title,
|
|
4448
|
+
selection.previewClientY
|
|
3129
4449
|
);
|
|
3130
4450
|
};
|
|
3131
4451
|
|
|
3132
4452
|
private handleIndexClick = (event: Event) => {
|
|
4453
|
+
if (
|
|
4454
|
+
'detail' in event &&
|
|
4455
|
+
typeof event.detail === 'number' &&
|
|
4456
|
+
event.detail > 0
|
|
4457
|
+
)
|
|
4458
|
+
return;
|
|
3133
4459
|
const target = event.target;
|
|
3134
4460
|
if (!(target instanceof Element)) return;
|
|
3135
|
-
const button = target.closest<HTMLElement>('[data-section-
|
|
4461
|
+
const button = target.closest<HTMLElement>('[data-section-entry-index]');
|
|
3136
4462
|
if (!button) return;
|
|
4463
|
+
const entry =
|
|
4464
|
+
this.sectionIndexEntries[Number(button.dataset.sectionEntryIndex)];
|
|
4465
|
+
if (!entry) return;
|
|
4466
|
+
const rect = button.getBoundingClientRect();
|
|
3137
4467
|
this.selectIndexPosition(
|
|
3138
|
-
|
|
3139
|
-
|
|
4468
|
+
entry.position,
|
|
4469
|
+
entry.title,
|
|
4470
|
+
rect.top + rect.height / 2
|
|
3140
4471
|
);
|
|
3141
4472
|
};
|
|
3142
4473
|
|
|
@@ -3203,12 +4534,13 @@ export class NativeListWebEngine {
|
|
|
3203
4534
|
const index = Number(rowElement?.dataset.nativeListRowIndex);
|
|
3204
4535
|
const row = this.rows[index];
|
|
3205
4536
|
if (!row || !this.isReorderable(row)) return;
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
4537
|
+
// OneKey patch: a child drag reorders its parent wallet group as one item.
|
|
4538
|
+
// if (
|
|
4539
|
+
// row.type === 'walletGroup' &&
|
|
4540
|
+
// target.closest<HTMLElement>('[data-native-list-group-parent]')?.dataset
|
|
4541
|
+
// .nativeListGroupParent !== 'true'
|
|
4542
|
+
// )
|
|
4543
|
+
// return;
|
|
3212
4544
|
|
|
3213
4545
|
const view = this.document.defaultView;
|
|
3214
4546
|
const state: PointerReorderState = {
|
|
@@ -3225,9 +4557,8 @@ export class NativeListWebEngine {
|
|
|
3225
4557
|
active: false,
|
|
3226
4558
|
};
|
|
3227
4559
|
this.pointerReorder = state;
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
} else {
|
|
4560
|
+
// OneKey patch: normal wallet taps retain their target until a drag is activated.
|
|
4561
|
+
if (state.pointerType !== 'mouse') {
|
|
3231
4562
|
state.longPressTimer = view?.setTimeout(
|
|
3232
4563
|
() => this.activatePointerReorder(state),
|
|
3233
4564
|
REORDER_TOUCH_LONG_PRESS_MS
|
|
@@ -3363,6 +4694,23 @@ export class NativeListWebEngine {
|
|
|
3363
4694
|
Math.max(0, state.startY - rect.top)
|
|
3364
4695
|
);
|
|
3365
4696
|
this.reorderPreview.replaceChildren(previewRow.cloneNode(true));
|
|
4697
|
+
// Cloned previews need their own lease when a source row is recycled during dragging.
|
|
4698
|
+
const originals = previewRow.querySelectorAll('img');
|
|
4699
|
+
this.reorderPreview.querySelectorAll('img').forEach((image, index) => {
|
|
4700
|
+
const original = originals.item(index);
|
|
4701
|
+
const avatar = original ? webAvatarSources.get(original) : undefined;
|
|
4702
|
+
if (!avatar) return;
|
|
4703
|
+
const paint = image.previousElementSibling;
|
|
4704
|
+
if (
|
|
4705
|
+
paint?.classList.contains('ok-native-list-selector-image-background')
|
|
4706
|
+
) {
|
|
4707
|
+
image.addEventListener('load', () => {
|
|
4708
|
+
(paint as HTMLElement).style.backgroundImage =
|
|
4709
|
+
'url(' + JSON.stringify(image.currentSrc || image.src) + ')';
|
|
4710
|
+
});
|
|
4711
|
+
}
|
|
4712
|
+
configureWebAvatar(image, avatar.source, avatar.uri);
|
|
4713
|
+
});
|
|
3366
4714
|
const sourceRow = state.workingRows[state.currentIndex];
|
|
3367
4715
|
const badgeText = sourceRow
|
|
3368
4716
|
? webWalletGroupReorderBadge(sourceRow)
|
|
@@ -3430,6 +4778,7 @@ export class NativeListWebEngine {
|
|
|
3430
4778
|
|
|
3431
4779
|
private clearReorderPreviewVisual() {
|
|
3432
4780
|
this.reorderPreview.hidden = true;
|
|
4781
|
+
disposeWebImageRetries(this.reorderPreview);
|
|
3433
4782
|
this.reorderPreview.replaceChildren();
|
|
3434
4783
|
this.reorderPreview.style.removeProperty('transform');
|
|
3435
4784
|
this.reorderPreview.style.removeProperty('transition');
|