@onekeyfe/react-native-native-list 3.0.114 → 3.0.116
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/README.md +57 -3
- package/android/build.gradle +1 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListAdapter.kt +47 -1
- package/android/src/main/java/com/onekey/nativelist/NativeListRowView.kt +795 -30
- package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +445 -91
- package/ios/NativeListCell.swift +655 -20
- package/ios/NativeListDesignAssets.swift +8 -0
- package/ios/RNCNativeListView.swift +275 -42
- package/ios/Resources/NativeListIcons.xcassets/onekey_badge_verified_solid.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_badge_verified_solid.imageset/icon.svg +1 -0
- package/lib/module/validation.js +145 -1
- package/lib/module/web/NativeListWebEngine.js +461 -51
- package/lib/typescript/src/models.d.ts +108 -2
- package/lib/typescript/src/web/NativeListWebEngine.d.ts +37 -3
- package/package.json +4 -2
- package/src/models.ts +144 -3
- package/src/validation.ts +250 -0
- package/src/web/NativeListWebEngine.ts +766 -91
|
@@ -3,6 +3,8 @@ import type {
|
|
|
3
3
|
CheckboxState,
|
|
4
4
|
ImageSource,
|
|
5
5
|
LeadingVisual,
|
|
6
|
+
MarketRow,
|
|
7
|
+
MarketTextStyle,
|
|
6
8
|
NativeListSnapshot,
|
|
7
9
|
NativeListActionAnchor,
|
|
8
10
|
NativeListActionSource,
|
|
@@ -47,7 +49,7 @@ import {
|
|
|
47
49
|
const SECTION_INDEX_CONTENT_INSET = 16;
|
|
48
50
|
const SECTION_INDEX_RAIL_WIDTH = 32;
|
|
49
51
|
const SECTION_INDEX_EDGE_PADDING = 8;
|
|
50
|
-
const
|
|
52
|
+
const SECTION_INDEX_LABEL_SPACING = 16;
|
|
51
53
|
const SECTION_INDEX_MIN_HEIGHT = 120;
|
|
52
54
|
const DEFAULT_VIEWPORT_WIDTH = 320;
|
|
53
55
|
const DEFAULT_VIEWPORT_HEIGHT = 640;
|
|
@@ -60,6 +62,10 @@ export const WEB_REORDER_ANIMATION = {
|
|
|
60
62
|
} as const;
|
|
61
63
|
|
|
62
64
|
const REORDER_TOUCH_LONG_PRESS_MS = 120;
|
|
65
|
+
const MARKET_LONG_PRESS_MS = 800;
|
|
66
|
+
const MARKET_MOVE_CANCEL_PX = 10;
|
|
67
|
+
export const WEB_MARKET_VERIFIED_PATH =
|
|
68
|
+
'M9.483 11.458v3.5h-1v-3.5z M10.467 2.698a2.03 2.03 0 0 1 3.065 0l1.358 1.564a.03.03 0 0 0 .028.01l2.046-.325a2.03 2.03 0 0 1 2.347 1.971l.037 2.07q0 .016.014.026l1.776 1.066a2.03 2.03 0 0 1 .532 3.019l-1.304 1.609a.03.03 0 0 0-.005.03l.675 1.956a2.03 2.03 0 0 1-1.533 2.656l-2.033.394a.03.03 0 0 0-.023.019l-.741 1.933a2.03 2.03 0 0 1-2.88 1.05l-1.811-1.006a.03.03 0 0 0-.03 0l-1.811 1.005a2.03 2.03 0 0 1-2.88-1.049l-.742-1.933a.03.03 0 0 0-.023-.019l-2.033-.394a2.03 2.03 0 0 1-1.532-2.656l.675-1.957a.03.03 0 0 0-.005-.029l-1.304-1.61a2.03 2.03 0 0 1 .532-3.018l1.776-1.066a.03.03 0 0 0 .014-.026l.035-2.07a2.03 2.03 0 0 1 2.349-1.97l2.045.324a.03.03 0 0 0 .028-.01zm1.516 3.76a.5.5 0 0 0-.447.276l-1.861 3.724H8.483a1 1 0 0 0-1 1v3.5a1 1 0 0 0 1 1h6.692a2 2 0 0 0 1.981-1.73l.341-2.5a2 2 0 0 0-1.982-2.27h-1.939l.197-1.269a1.5 1.5 0 0 0-1.481-1.731z';
|
|
63
69
|
const REORDER_MOUSE_MOVE_THRESHOLD_PX = 5;
|
|
64
70
|
const REORDER_EDGE_RATIO = 0.25;
|
|
65
71
|
const REORDER_MAX_SPEED_ZONE_RATIO = 0.05;
|
|
@@ -108,6 +114,50 @@ export type WebListLayout = Readonly<{
|
|
|
108
114
|
horizontal: boolean;
|
|
109
115
|
}>;
|
|
110
116
|
|
|
117
|
+
export type WebMarketLayoutStyle = Readonly<{
|
|
118
|
+
horizontalPadding: number;
|
|
119
|
+
verticalPadding: number;
|
|
120
|
+
leadingGap: number;
|
|
121
|
+
titleBadgeGap: number;
|
|
122
|
+
trailingGap: number;
|
|
123
|
+
imageWidth: number;
|
|
124
|
+
imageHeight: number;
|
|
125
|
+
imageCornerRadius: number;
|
|
126
|
+
changeWidth: number;
|
|
127
|
+
changeHeight: number;
|
|
128
|
+
changeCornerRadius: number;
|
|
129
|
+
}>;
|
|
130
|
+
|
|
131
|
+
/** Resolves every reusable Market geometry field, including legacy defaults. */
|
|
132
|
+
export function resolveWebMarketLayoutStyle(
|
|
133
|
+
row: MarketRow
|
|
134
|
+
): WebMarketLayoutStyle {
|
|
135
|
+
const style = row.style;
|
|
136
|
+
const imageWidth = style?.image?.width ?? (row.variant === 'stock' ? 40 : 32);
|
|
137
|
+
const imageHeight =
|
|
138
|
+
style?.image?.height ?? (row.variant === 'stock' ? 40 : 32);
|
|
139
|
+
return {
|
|
140
|
+
horizontalPadding:
|
|
141
|
+
style?.horizontalPadding ?? (row.variant === 'perp' ? 16 : 20),
|
|
142
|
+
verticalPadding: style?.verticalPadding ?? 12,
|
|
143
|
+
leadingGap: style?.leadingGap ?? (row.variant === 'perp' ? 8 : 14),
|
|
144
|
+
titleBadgeGap: style?.titleBadgeGap ?? 4,
|
|
145
|
+
trailingGap: style?.trailingGap ?? 8,
|
|
146
|
+
imageWidth,
|
|
147
|
+
imageHeight,
|
|
148
|
+
imageCornerRadius:
|
|
149
|
+
style?.image?.cornerRadius ??
|
|
150
|
+
(style?.image?.shape === 'square'
|
|
151
|
+
? 0
|
|
152
|
+
: style?.image?.shape === 'rounded'
|
|
153
|
+
? 8
|
|
154
|
+
: Math.min(imageWidth, imageHeight) / 2),
|
|
155
|
+
changeWidth: style?.changeWidth ?? 80,
|
|
156
|
+
changeHeight: style?.changeHeight ?? 32,
|
|
157
|
+
changeCornerRadius: style?.changeCornerRadius ?? 8,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
111
161
|
export type NativeListWebCallbacks = Readonly<{
|
|
112
162
|
onRowAction?: (event: RowActionEvent) => void;
|
|
113
163
|
onActionAnchorInvalidated?: (event: ActionAnchorInvalidatedEvent) => void;
|
|
@@ -450,7 +500,15 @@ export function estimateWebRowHeight(
|
|
|
450
500
|
}
|
|
451
501
|
case 'system':
|
|
452
502
|
base =
|
|
453
|
-
row.variant === '
|
|
503
|
+
row.variant === 'loading' && row.loadingStyle === 'skeleton'
|
|
504
|
+
? 56
|
|
505
|
+
: row.variant === 'loading' && row.loadingStyle === 'spinner'
|
|
506
|
+
? 52
|
|
507
|
+
: 'presentation' in row && row.presentation === 'market'
|
|
508
|
+
? row.variant === 'loading'
|
|
509
|
+
? 68
|
|
510
|
+
: 44
|
|
511
|
+
: row.variant === 'noMatch' || row.variant === 'end'
|
|
454
512
|
? 36
|
|
455
513
|
: row.variant === 'retry'
|
|
456
514
|
? 44
|
|
@@ -462,6 +520,14 @@ export function estimateWebRowHeight(
|
|
|
462
520
|
case 'dataRow':
|
|
463
521
|
base = row.columns.some((column) => column.secondaryText) ? 60 : 56;
|
|
464
522
|
break;
|
|
523
|
+
case 'market': {
|
|
524
|
+
const marketStyle = resolveWebMarketLayoutStyle(row);
|
|
525
|
+
base = Math.max(
|
|
526
|
+
row.variant === 'stock' ? 72 : 68,
|
|
527
|
+
marketStyle.imageHeight + marketStyle.verticalPadding * 2
|
|
528
|
+
);
|
|
529
|
+
break;
|
|
530
|
+
}
|
|
465
531
|
case 'identity':
|
|
466
532
|
base = row.tertiary ? 72 : row.subtitle ? 60 : 56;
|
|
467
533
|
break;
|
|
@@ -706,6 +772,32 @@ export function visibleWebLayoutItems(
|
|
|
706
772
|
return visible;
|
|
707
773
|
}
|
|
708
774
|
|
|
775
|
+
export type WebCollapsiblePagerScrollMetrics = Readonly<{
|
|
776
|
+
offset: number;
|
|
777
|
+
viewportLength: number;
|
|
778
|
+
}>;
|
|
779
|
+
|
|
780
|
+
export function resolveWebCollapsiblePagerScrollMetrics(
|
|
781
|
+
rawOffset: number,
|
|
782
|
+
rawViewportLength: number,
|
|
783
|
+
headerInset: number,
|
|
784
|
+
stickyInset: number
|
|
785
|
+
): WebCollapsiblePagerScrollMetrics {
|
|
786
|
+
const header = Math.max(0, headerInset);
|
|
787
|
+
const sticky = Math.max(0, stickyInset);
|
|
788
|
+
return {
|
|
789
|
+
offset: Math.max(0, rawOffset - header),
|
|
790
|
+
viewportLength: Math.max(0, rawViewportLength - sticky),
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
export function resolveWebCollapsiblePagerRawOffset(
|
|
795
|
+
logicalOffset: number,
|
|
796
|
+
headerInset: number
|
|
797
|
+
): number {
|
|
798
|
+
return Math.max(0, logicalOffset) + Math.max(0, headerInset);
|
|
799
|
+
}
|
|
800
|
+
|
|
709
801
|
export function webLayoutItemsForMount(
|
|
710
802
|
layout: WebListLayout,
|
|
711
803
|
offset: number,
|
|
@@ -742,6 +834,30 @@ export function webRowRenderSignature(row: RowModel): string {
|
|
|
742
834
|
return JSON.stringify(rowWithoutSelectionState(row));
|
|
743
835
|
}
|
|
744
836
|
|
|
837
|
+
const MARKET_QUOTE_PATCH_FIELDS = new Set([
|
|
838
|
+
'revision',
|
|
839
|
+
'price',
|
|
840
|
+
'priceSegments',
|
|
841
|
+
'change',
|
|
842
|
+
'accessibilityLabel',
|
|
843
|
+
]);
|
|
844
|
+
|
|
845
|
+
export function isWebMarketQuotePatch(patch: RowPatch): boolean {
|
|
846
|
+
return (
|
|
847
|
+
patch.type === 'market' &&
|
|
848
|
+
Object.keys(patch.changes).every((key) =>
|
|
849
|
+
MARKET_QUOTE_PATCH_FIELDS.has(key)
|
|
850
|
+
)
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
/** Number of Market image-binding passes caused by one Web patch transaction. */
|
|
855
|
+
export function webMarketImageBindDeltaForPatches(
|
|
856
|
+
patches: readonly RowPatch[]
|
|
857
|
+
): 0 | 1 {
|
|
858
|
+
return patches.length > 0 && patches.every(isWebMarketQuotePatch) ? 0 : 1;
|
|
859
|
+
}
|
|
860
|
+
|
|
745
861
|
// OneKey patch: selector names must shrink before the sidebar clips their contents.
|
|
746
862
|
export const WEB_LIST_CSS = `
|
|
747
863
|
[data-native-list-selector="walletSidebar"] .ok-native-list-title{max-width:100%;min-width:0}
|
|
@@ -798,11 +914,19 @@ export const WEB_LIST_CSS = `
|
|
|
798
914
|
.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}
|
|
799
915
|
.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)}
|
|
800
916
|
.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}
|
|
917
|
+
.ok-native-list-market{padding:12px 20px;gap:14px}.ok-native-list-market>.ok-native-list-visual{width:32px;height:32px;flex-basis:32px}.ok-native-list-market[data-variant="stock"]>.ok-native-list-visual{width:40px;height:40px;flex-basis:40px}.ok-native-list-market>.ok-native-list-visual>.ok-native-list-visual-main{width:100%;height:100%}.ok-native-list-market-main{display:flex;flex:1;min-width:0;flex-direction:column;justify-content:center}.ok-native-list-market-title-line{display:flex;align-items:center;min-width:0;gap:4px}.ok-native-list-market-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--nl-primary);font-size:16px;line-height:24px;font-weight:500}.ok-native-list-market-subtitle{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--nl-secondary);font-size:14px;line-height:20px;font-weight:400}.ok-native-list-market-badge{display:inline-flex;flex:0 0 auto;align-items:center;justify-content:center;box-sizing:border-box;max-width:72px;height:18px;padding:0 5px;border:0;border-radius:4px;background:var(--nl-strong);color:var(--nl-secondary);font:500 11px/18px inherit;overflow:hidden;white-space:nowrap}.ok-native-list-market-badge img{width:14px;height:14px;object-fit:contain}.ok-native-list-market-trailing{display:flex;flex:0 0 auto;align-items:center;gap:8px}.ok-native-list-market-price{max-width:112px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:right;color:var(--nl-primary);font-size:16px;line-height:24px;font-weight:500;font-variant-numeric:tabular-nums}.ok-native-list-market-change{display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:80px;height:32px;border-radius:8px;color:#fff;background:#8d8d8d;font-size:14px;line-height:20px;font-weight:500;font-variant-numeric:tabular-nums;white-space:nowrap}.ok-native-list-market-change[data-tone="positive"]{background:var(--nl-positive)}.ok-native-list-market-change[data-tone="negative"]{background:var(--nl-negative)}
|
|
918
|
+
.ok-native-list-market-badge>svg,.ok-native-list-market-badge>.ok-native-list-market-badge-icon>svg{display:block;width:16px;height:16px;flex:0 0 16px}.ok-native-list-system[data-native-list-presentation="market"]{box-sizing:border-box;padding:12px 20px}.ok-native-list-system[data-native-list-presentation="market"]>.ok-native-list-spinner{width:32px;height:32px}
|
|
801
919
|
.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)}
|
|
802
920
|
.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
921
|
.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
922
|
.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}
|
|
805
|
-
|
|
923
|
+
.ok-native-list-row.ok-native-list-market-skeleton{padding:12px 20px;gap:0}.ok-native-list-skeleton-left{display:flex;align-items:center;gap:12px;flex:1}.ok-native-list-skeleton-text{display:flex;flex-direction:column;gap:4px}.ok-native-list-skeleton-right{display:flex;align-items:center;gap:8px}.ok-native-list-skeleton-mark{display:block;flex-shrink:0;border-radius:8px;animation:ok-native-list-skeleton 1.5s linear infinite alternate}@keyframes ok-native-list-skeleton{from{background-color:var(--nl-skeleton-base)}to{background-color:var(--nl-skeleton-highlight)}}.ok-native-list-market-spinner{display:block;width:20px;height:20px;flex-shrink:0;color:var(--nl-icon);animation:ok-native-list-spin .75s linear infinite}
|
|
924
|
+
@media (prefers-reduced-motion:reduce){.ok-native-list-index-preview,.ok-native-list-refresh{transition:none}.ok-native-list-spinner,.ok-native-list-market-spinner{animation:none}.ok-native-list-skeleton-mark{animation:none;background:var(--nl-skeleton-base)}}
|
|
925
|
+
.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-viewport-frame:has(>.ok-native-list-index-rail:not([hidden]))>.ok-native-list-viewport{scrollbar-width:none}.ok-native-list-viewport-frame:has(>.ok-native-list-index-rail:not([hidden]))>.ok-native-list-viewport::-webkit-scrollbar{display:none}.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:15px;display:flex;width:14px;height:14px;align-items:center;justify-content:center;padding:0;transform:translateY(-50%);border:0;border-radius:7px;background:transparent;color:var(--nl-disabled);font-family:inherit;font-size:10px;font-weight:400;line-height:1;cursor:pointer}.ok-native-list-index-button[data-active="true"]{background:var(--nl-positive);color:var(--nl-inverse-text);font-weight:500}.ok-native-list-index-button:focus-visible{outline:2px solid var(--nl-positive);outline-offset:1px}
|
|
926
|
+
.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)}
|
|
927
|
+
.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)}
|
|
928
|
+
.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}
|
|
929
|
+
@media (prefers-reduced-motion:reduce){.ok-native-list-refresh{transition:none}.ok-native-list-spinner{animation:none}}
|
|
806
930
|
/* OneKey patch: selector controls follow their original semantic colors and geometry. */
|
|
807
931
|
.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
932
|
.ok-native-list-checkbox[data-selector="networkSelector"]::after{display:none}
|
|
@@ -1280,6 +1404,17 @@ const selectorIcons: Readonly<
|
|
|
1280
1404
|
},
|
|
1281
1405
|
],
|
|
1282
1406
|
},
|
|
1407
|
+
BadgeVerifiedSolid: {
|
|
1408
|
+
viewBox: '0 0 24 24',
|
|
1409
|
+
paths: [
|
|
1410
|
+
{
|
|
1411
|
+
d: WEB_MARKET_VERIFIED_PATH,
|
|
1412
|
+
fill: 'currentColor',
|
|
1413
|
+
fillRule: 'evenodd',
|
|
1414
|
+
opacity: 1,
|
|
1415
|
+
},
|
|
1416
|
+
],
|
|
1417
|
+
},
|
|
1283
1418
|
};
|
|
1284
1419
|
function applySelectorIcon(element: HTMLElement, name: string) {
|
|
1285
1420
|
const icon = selectorIcons[name];
|
|
@@ -1335,6 +1470,7 @@ function visualFromRow(row: RowModel): LeadingVisual | undefined {
|
|
|
1335
1470
|
if (row.type === 'activity') return row.leading;
|
|
1336
1471
|
if (row.type === 'message') return row.leading;
|
|
1337
1472
|
if (row.type === 'dataRow') return row.leading;
|
|
1473
|
+
if (row.type === 'market') return row.leading;
|
|
1338
1474
|
if (row.type === 'metricCard') return row.visual;
|
|
1339
1475
|
return undefined;
|
|
1340
1476
|
}
|
|
@@ -2089,6 +2225,98 @@ function createSystemRow(
|
|
|
2089
2225
|
'ok-native-list-row ok-native-list-system'
|
|
2090
2226
|
);
|
|
2091
2227
|
setData(body, 'variant', row.variant);
|
|
2228
|
+
if ('presentation' in row)
|
|
2229
|
+
setData(body, 'nativeListPresentation', row.presentation);
|
|
2230
|
+
if (row.variant === 'loading' && row.loadingStyle === 'skeleton') {
|
|
2231
|
+
body.classList.add('ok-native-list-market-skeleton');
|
|
2232
|
+
const background = resolvedTheme(context.snapshot).background;
|
|
2233
|
+
const rgb = Number.parseInt(background.slice(1, 7), 16);
|
|
2234
|
+
const dark =
|
|
2235
|
+
((rgb >> 16) & 255) * 0.299 +
|
|
2236
|
+
((rgb >> 8) & 255) * 0.587 +
|
|
2237
|
+
(rgb & 255) * 0.114 <
|
|
2238
|
+
128;
|
|
2239
|
+
body.style.setProperty('--nl-skeleton-base', dark ? '#111111' : '#fafafa');
|
|
2240
|
+
body.style.setProperty(
|
|
2241
|
+
'--nl-skeleton-highlight',
|
|
2242
|
+
dark ? '#333333' : '#cdcdcd'
|
|
2243
|
+
);
|
|
2244
|
+
const left = createElement(
|
|
2245
|
+
context.document,
|
|
2246
|
+
'div',
|
|
2247
|
+
'ok-native-list-skeleton-left'
|
|
2248
|
+
);
|
|
2249
|
+
const mark = (width: number, height: number, circle = false) => {
|
|
2250
|
+
const element = createElement(
|
|
2251
|
+
context.document,
|
|
2252
|
+
'span',
|
|
2253
|
+
'ok-native-list-skeleton-mark'
|
|
2254
|
+
);
|
|
2255
|
+
element.style.width = `${width}px`;
|
|
2256
|
+
element.style.height = `${height}px`;
|
|
2257
|
+
if (circle) element.style.borderRadius = '50%';
|
|
2258
|
+
return element;
|
|
2259
|
+
};
|
|
2260
|
+
left.appendChild(mark(32, 32, true));
|
|
2261
|
+
const text = createElement(
|
|
2262
|
+
context.document,
|
|
2263
|
+
'div',
|
|
2264
|
+
'ok-native-list-skeleton-text'
|
|
2265
|
+
);
|
|
2266
|
+
text.appendChild(mark(80, 16));
|
|
2267
|
+
text.appendChild(mark(60, 12));
|
|
2268
|
+
left.appendChild(text);
|
|
2269
|
+
body.appendChild(left);
|
|
2270
|
+
const right = createElement(
|
|
2271
|
+
context.document,
|
|
2272
|
+
'div',
|
|
2273
|
+
'ok-native-list-skeleton-right'
|
|
2274
|
+
);
|
|
2275
|
+
right.appendChild(mark(80, 18));
|
|
2276
|
+
right.appendChild(mark(80, 18));
|
|
2277
|
+
body.appendChild(right);
|
|
2278
|
+
return body;
|
|
2279
|
+
}
|
|
2280
|
+
if (row.variant === 'loading' && row.loadingStyle === 'spinner') {
|
|
2281
|
+
body.style.justifyContent = 'center';
|
|
2282
|
+
body.style.padding = '16px';
|
|
2283
|
+
const spinner = createElement(
|
|
2284
|
+
context.document,
|
|
2285
|
+
'span',
|
|
2286
|
+
'ok-native-list-market-spinner'
|
|
2287
|
+
);
|
|
2288
|
+
spinner.setAttribute('role', 'progressbar');
|
|
2289
|
+
// Same 20px SVG and 750ms rotation as react-native-web ActivityIndicator.
|
|
2290
|
+
spinner.innerHTML =
|
|
2291
|
+
'<svg viewBox="0 0 32 32" width="20" height="20"><circle cx="16" cy="16" r="14" fill="none" stroke="currentColor" stroke-width="4" opacity="0.2"/><circle cx="16" cy="16" r="14" fill="none" stroke="currentColor" stroke-width="4" stroke-dasharray="80" stroke-dashoffset="60"/></svg>';
|
|
2292
|
+
body.appendChild(spinner);
|
|
2293
|
+
return body;
|
|
2294
|
+
}
|
|
2295
|
+
if ('presentation' in row && row.presentation === 'market') {
|
|
2296
|
+
if (row.variant === 'noMatch') {
|
|
2297
|
+
body.style.justifyContent = 'center';
|
|
2298
|
+
body.style.padding = '32px';
|
|
2299
|
+
const message = createElement(context.document, 'span', '', row.message);
|
|
2300
|
+
message.style.fontSize = '16px';
|
|
2301
|
+
message.style.lineHeight = '24px';
|
|
2302
|
+
body.appendChild(message);
|
|
2303
|
+
return body;
|
|
2304
|
+
}
|
|
2305
|
+
if (row.variant === 'end') {
|
|
2306
|
+
body.style.justifyContent = 'center';
|
|
2307
|
+
body.style.padding = '16px';
|
|
2308
|
+
body.style.gap = '8px';
|
|
2309
|
+
for (const width of [80, 4, 80]) {
|
|
2310
|
+
const mark = createElement(context.document, 'span', '');
|
|
2311
|
+
mark.style.width = String(width) + 'px';
|
|
2312
|
+
mark.style.height = width === 4 ? '4px' : '1px';
|
|
2313
|
+
mark.style.borderRadius = width === 4 ? '2px' : '0';
|
|
2314
|
+
mark.style.background = 'var(--nl-separator)';
|
|
2315
|
+
body.appendChild(mark);
|
|
2316
|
+
}
|
|
2317
|
+
return body;
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2092
2320
|
if (row.variant === 'warning') {
|
|
2093
2321
|
body.classList.add('ok-native-list-warning');
|
|
2094
2322
|
body.style.borderColor = row.borderColor ?? 'var(--nl-separator)';
|
|
@@ -2784,6 +3012,268 @@ function createWalletGroupRow(
|
|
|
2784
3012
|
return body;
|
|
2785
3013
|
}
|
|
2786
3014
|
|
|
3015
|
+
function marketFontWeight(
|
|
3016
|
+
value: MarketTextStyle['fontWeight'] | undefined,
|
|
3017
|
+
fallback: number
|
|
3018
|
+
): number {
|
|
3019
|
+
if (value === 'bold') return 700;
|
|
3020
|
+
if (value === 'semibold') return 600;
|
|
3021
|
+
if (value === 'medium') return 500;
|
|
3022
|
+
if (value === 'regular') return 400;
|
|
3023
|
+
return fallback;
|
|
3024
|
+
}
|
|
3025
|
+
|
|
3026
|
+
function applyMarketTextStyle(
|
|
3027
|
+
element: HTMLElement,
|
|
3028
|
+
style: MarketTextStyle | undefined,
|
|
3029
|
+
defaults: Readonly<{
|
|
3030
|
+
fontSize: number;
|
|
3031
|
+
lineHeight: number;
|
|
3032
|
+
weight: number;
|
|
3033
|
+
alignment: 'start' | 'center' | 'end';
|
|
3034
|
+
}>
|
|
3035
|
+
) {
|
|
3036
|
+
element.style.fontSize = String(style?.fontSize ?? defaults.fontSize) + 'px';
|
|
3037
|
+
element.style.lineHeight =
|
|
3038
|
+
String(style?.lineHeight ?? defaults.lineHeight) + 'px';
|
|
3039
|
+
element.style.fontWeight = String(
|
|
3040
|
+
marketFontWeight(style?.fontWeight, defaults.weight)
|
|
3041
|
+
);
|
|
3042
|
+
element.style.color = style?.color ?? '';
|
|
3043
|
+
element.style.textAlign = style?.alignment ?? defaults.alignment;
|
|
3044
|
+
element.style.whiteSpace = style?.lines === 2 ? 'normal' : 'nowrap';
|
|
3045
|
+
element.style.display = '';
|
|
3046
|
+
element.style.removeProperty('-webkit-line-clamp');
|
|
3047
|
+
element.style.removeProperty('-webkit-box-orient');
|
|
3048
|
+
if (style?.lines === 2) {
|
|
3049
|
+
element.style.display = '-webkit-box';
|
|
3050
|
+
element.style.setProperty('-webkit-line-clamp', '2');
|
|
3051
|
+
element.style.setProperty('-webkit-box-orient', 'vertical');
|
|
3052
|
+
}
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
function setMarketQuoteContent(element: HTMLElement, row: MarketRow) {
|
|
3056
|
+
const style = row.style;
|
|
3057
|
+
const layoutStyle = resolveWebMarketLayoutStyle(row);
|
|
3058
|
+
const price = element.querySelector<HTMLElement>(
|
|
3059
|
+
'.ok-native-list-market-price'
|
|
3060
|
+
);
|
|
3061
|
+
if (price) {
|
|
3062
|
+
price.textContent = row.price;
|
|
3063
|
+
applyMarketTextStyle(price, style?.price, {
|
|
3064
|
+
fontSize: 16,
|
|
3065
|
+
lineHeight: 24,
|
|
3066
|
+
weight: 500,
|
|
3067
|
+
alignment: 'end',
|
|
3068
|
+
});
|
|
3069
|
+
applyValueSegments(
|
|
3070
|
+
price,
|
|
3071
|
+
row.priceSegments,
|
|
3072
|
+
style?.price?.fontSize ?? 16,
|
|
3073
|
+
style?.price?.lineHeight ?? 24,
|
|
3074
|
+
marketFontWeight(style?.price?.fontWeight, 500)
|
|
3075
|
+
);
|
|
3076
|
+
}
|
|
3077
|
+
const change = element.querySelector<HTMLElement>(
|
|
3078
|
+
'.ok-native-list-market-change'
|
|
3079
|
+
);
|
|
3080
|
+
if (change) {
|
|
3081
|
+
change.textContent = row.change.text;
|
|
3082
|
+
setData(change, 'tone', row.change.tone);
|
|
3083
|
+
applyMarketTextStyle(change, style?.change, {
|
|
3084
|
+
fontSize: 14,
|
|
3085
|
+
lineHeight: 20,
|
|
3086
|
+
weight: 500,
|
|
3087
|
+
alignment: 'center',
|
|
3088
|
+
});
|
|
3089
|
+
applyValueSegments(
|
|
3090
|
+
change,
|
|
3091
|
+
row.change.textSegments,
|
|
3092
|
+
style?.change?.fontSize ?? 14,
|
|
3093
|
+
style?.change?.lineHeight ?? 20,
|
|
3094
|
+
marketFontWeight(style?.change?.fontWeight, 500)
|
|
3095
|
+
);
|
|
3096
|
+
change.style.width = String(layoutStyle.changeWidth) + 'px';
|
|
3097
|
+
change.style.height = String(layoutStyle.changeHeight) + 'px';
|
|
3098
|
+
change.style.borderRadius = String(layoutStyle.changeCornerRadius) + 'px';
|
|
3099
|
+
change.style.color = row.change.textColor ?? style?.change?.color ?? '';
|
|
3100
|
+
change.style.background = row.change.backgroundColor ?? '';
|
|
3101
|
+
}
|
|
3102
|
+
element.setAttribute(
|
|
3103
|
+
'aria-label',
|
|
3104
|
+
row.accessibilityLabel ??
|
|
3105
|
+
[row.title, row.subtitle, row.price, row.change.text]
|
|
3106
|
+
.filter(Boolean)
|
|
3107
|
+
.join(', ')
|
|
3108
|
+
);
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
function createMarketRow(context: RenderContext, row: MarketRow): HTMLElement {
|
|
3112
|
+
const body = createElement(
|
|
3113
|
+
context.document,
|
|
3114
|
+
'div',
|
|
3115
|
+
'ok-native-list-row ok-native-list-market'
|
|
3116
|
+
);
|
|
3117
|
+
setData(body, 'variant', row.variant);
|
|
3118
|
+
const style = row.style;
|
|
3119
|
+
const layoutStyle = resolveWebMarketLayoutStyle(row);
|
|
3120
|
+
body.style.padding =
|
|
3121
|
+
String(layoutStyle.verticalPadding) +
|
|
3122
|
+
'px ' +
|
|
3123
|
+
String(layoutStyle.horizontalPadding) +
|
|
3124
|
+
'px';
|
|
3125
|
+
body.style.gap = '0px';
|
|
3126
|
+
const visual = createVisual(context, row.leading);
|
|
3127
|
+
if (visual) {
|
|
3128
|
+
const width = layoutStyle.imageWidth;
|
|
3129
|
+
const height = layoutStyle.imageHeight;
|
|
3130
|
+
visual.style.width = String(width) + 'px';
|
|
3131
|
+
visual.style.height = String(height) + 'px';
|
|
3132
|
+
visual.style.flexBasis = String(width) + 'px';
|
|
3133
|
+
visual.style.borderRadius = String(layoutStyle.imageCornerRadius) + 'px';
|
|
3134
|
+
const borderColor =
|
|
3135
|
+
'borderColor' in row.leading ? row.leading.borderColor : undefined;
|
|
3136
|
+
if (borderColor) {
|
|
3137
|
+
visual.style.border = '1px solid ' + borderColor;
|
|
3138
|
+
visual.style.boxSizing = 'border-box';
|
|
3139
|
+
}
|
|
3140
|
+
visual.querySelectorAll<HTMLElement>('img').forEach((image) => {
|
|
3141
|
+
if (!image.classList.contains('ok-native-list-visual-corner')) {
|
|
3142
|
+
image.style.width = '100%';
|
|
3143
|
+
image.style.height = '100%';
|
|
3144
|
+
if (borderColor) {
|
|
3145
|
+
image.style.borderRadius = '0';
|
|
3146
|
+
image.style.clipPath =
|
|
3147
|
+
'inset(-1px round ' + String(layoutStyle.imageCornerRadius) + 'px)';
|
|
3148
|
+
}
|
|
3149
|
+
image.style.objectFit =
|
|
3150
|
+
style?.image?.contentFit ?? image.style.objectFit;
|
|
3151
|
+
} else {
|
|
3152
|
+
image.style.width = '20px';
|
|
3153
|
+
image.style.height = '20px';
|
|
3154
|
+
if (borderColor) {
|
|
3155
|
+
image.style.right = '-5px';
|
|
3156
|
+
image.style.bottom = '-5px';
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
});
|
|
3160
|
+
visual.style.marginRight = String(layoutStyle.leadingGap) + 'px';
|
|
3161
|
+
body.appendChild(visual);
|
|
3162
|
+
}
|
|
3163
|
+
const main = createElement(
|
|
3164
|
+
context.document,
|
|
3165
|
+
'span',
|
|
3166
|
+
'ok-native-list-market-main'
|
|
3167
|
+
);
|
|
3168
|
+
main.style.gap = String(style?.lineGap ?? 0) + 'px';
|
|
3169
|
+
const titleLine = createElement(
|
|
3170
|
+
context.document,
|
|
3171
|
+
'span',
|
|
3172
|
+
'ok-native-list-market-title-line'
|
|
3173
|
+
);
|
|
3174
|
+
titleLine.style.gap = String(layoutStyle.titleBadgeGap) + 'px';
|
|
3175
|
+
const title = createElement(
|
|
3176
|
+
context.document,
|
|
3177
|
+
'span',
|
|
3178
|
+
'ok-native-list-market-title',
|
|
3179
|
+
row.title
|
|
3180
|
+
);
|
|
3181
|
+
applyMarketTextStyle(title, style?.title, {
|
|
3182
|
+
fontSize: 16,
|
|
3183
|
+
lineHeight: 24,
|
|
3184
|
+
weight: 500,
|
|
3185
|
+
alignment: 'start',
|
|
3186
|
+
});
|
|
3187
|
+
titleLine.appendChild(title);
|
|
3188
|
+
row.badges?.forEach((badge, slot) => {
|
|
3189
|
+
const element = createElement(
|
|
3190
|
+
context.document,
|
|
3191
|
+
badge.actionKey ? 'button' : 'span',
|
|
3192
|
+
'ok-native-list-market-badge',
|
|
3193
|
+
badge.text
|
|
3194
|
+
);
|
|
3195
|
+
if (badge.actionKey) {
|
|
3196
|
+
element.setAttribute('type', 'button');
|
|
3197
|
+
setData(element, 'nativeListAction', badge.actionKey);
|
|
3198
|
+
markActionAnchorSource(element, 'marketBadge', slot);
|
|
3199
|
+
}
|
|
3200
|
+
setData(element, 'tone', badge.tone);
|
|
3201
|
+
element.style.color =
|
|
3202
|
+
badge.textColor ??
|
|
3203
|
+
(badge.tone === 'success'
|
|
3204
|
+
? 'var(--nl-positive)'
|
|
3205
|
+
: badge.tone === 'danger'
|
|
3206
|
+
? 'var(--nl-negative)'
|
|
3207
|
+
: badge.tone === 'info'
|
|
3208
|
+
? 'var(--nl-info)'
|
|
3209
|
+
: badge.tone === 'warning'
|
|
3210
|
+
? 'var(--nl-primary)'
|
|
3211
|
+
: '');
|
|
3212
|
+
element.style.background =
|
|
3213
|
+
badge.backgroundColor ??
|
|
3214
|
+
((badge.icon || badge.iconName) && !badge.text ? 'transparent' : '');
|
|
3215
|
+
if ((badge.icon || badge.iconName) && !badge.text) {
|
|
3216
|
+
element.style.padding = '0';
|
|
3217
|
+
}
|
|
3218
|
+
if (badge.accessibilityLabel)
|
|
3219
|
+
element.setAttribute('aria-label', badge.accessibilityLabel);
|
|
3220
|
+
if (badge.icon) {
|
|
3221
|
+
const icon = createImage(context, badge.icon);
|
|
3222
|
+
if (icon) {
|
|
3223
|
+
icon.style.borderRadius = '50%';
|
|
3224
|
+
element.prepend(icon);
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
if (badge.iconName === 'verified') {
|
|
3228
|
+
const icon = createElement(
|
|
3229
|
+
context.document,
|
|
3230
|
+
'span',
|
|
3231
|
+
'ok-native-list-market-badge-icon'
|
|
3232
|
+
);
|
|
3233
|
+
applySelectorIcon(icon, 'BadgeVerifiedSolid');
|
|
3234
|
+
element.prepend(icon);
|
|
3235
|
+
}
|
|
3236
|
+
titleLine.appendChild(element);
|
|
3237
|
+
});
|
|
3238
|
+
main.appendChild(titleLine);
|
|
3239
|
+
if (row.subtitle || row.subtitleSegments?.length) {
|
|
3240
|
+
const subtitle = createElement(
|
|
3241
|
+
context.document,
|
|
3242
|
+
'span',
|
|
3243
|
+
'ok-native-list-market-subtitle',
|
|
3244
|
+
row.subtitle
|
|
3245
|
+
);
|
|
3246
|
+
applyMarketTextStyle(subtitle, style?.subtitle, {
|
|
3247
|
+
fontSize: 14,
|
|
3248
|
+
lineHeight: 20,
|
|
3249
|
+
weight: 400,
|
|
3250
|
+
alignment: 'start',
|
|
3251
|
+
});
|
|
3252
|
+
applyValueSegments(
|
|
3253
|
+
subtitle,
|
|
3254
|
+
row.subtitleSegments,
|
|
3255
|
+
style?.subtitle?.fontSize ?? 14,
|
|
3256
|
+
style?.subtitle?.lineHeight ?? 20,
|
|
3257
|
+
marketFontWeight(style?.subtitle?.fontWeight, 400)
|
|
3258
|
+
);
|
|
3259
|
+
main.appendChild(subtitle);
|
|
3260
|
+
}
|
|
3261
|
+
body.appendChild(main);
|
|
3262
|
+
const trailing = createElement(
|
|
3263
|
+
context.document,
|
|
3264
|
+
'span',
|
|
3265
|
+
'ok-native-list-market-trailing'
|
|
3266
|
+
);
|
|
3267
|
+
trailing.style.gap = String(layoutStyle.trailingGap) + 'px';
|
|
3268
|
+
trailing.append(
|
|
3269
|
+
createElement(context.document, 'span', 'ok-native-list-market-price'),
|
|
3270
|
+
createElement(context.document, 'span', 'ok-native-list-market-change')
|
|
3271
|
+
);
|
|
3272
|
+
body.appendChild(trailing);
|
|
3273
|
+
setMarketQuoteContent(body, row);
|
|
3274
|
+
return body;
|
|
3275
|
+
}
|
|
3276
|
+
|
|
2787
3277
|
function createRowBody(context: RenderContext, row: RowModel): HTMLElement {
|
|
2788
3278
|
switch (row.type) {
|
|
2789
3279
|
case 'walletGroup':
|
|
@@ -2802,6 +3292,8 @@ function createRowBody(context: RenderContext, row: RowModel): HTMLElement {
|
|
|
2802
3292
|
return createMetricRow(context, row);
|
|
2803
3293
|
case 'dataRow':
|
|
2804
3294
|
return createDataRow(context, row);
|
|
3295
|
+
case 'market':
|
|
3296
|
+
return createMarketRow(context, row);
|
|
2805
3297
|
case 'identity':
|
|
2806
3298
|
case 'activity':
|
|
2807
3299
|
case 'message':
|
|
@@ -2818,7 +3310,6 @@ export class NativeListWebEngine {
|
|
|
2818
3310
|
private readonly footer: HTMLElement;
|
|
2819
3311
|
private readonly sticky: HTMLElement;
|
|
2820
3312
|
private readonly indexRail: HTMLElement;
|
|
2821
|
-
private readonly indexPreview: HTMLElement;
|
|
2822
3313
|
private readonly refreshIndicator: HTMLElement;
|
|
2823
3314
|
private readonly reorderPreview: HTMLElement;
|
|
2824
3315
|
private readonly previousHostPosition: string;
|
|
@@ -2844,7 +3335,6 @@ export class NativeListWebEngine {
|
|
|
2844
3335
|
private avatarDirection = 1;
|
|
2845
3336
|
private reachedGeneration: number | undefined;
|
|
2846
3337
|
private stickyKey: string | undefined;
|
|
2847
|
-
private previewTimer: number | undefined;
|
|
2848
3338
|
private sectionIndexEntries: readonly Readonly<{
|
|
2849
3339
|
key: string;
|
|
2850
3340
|
title: string;
|
|
@@ -2869,6 +3359,16 @@ export class NativeListWebEngine {
|
|
|
2869
3359
|
);
|
|
2870
3360
|
private actionAnchorCounter = 0;
|
|
2871
3361
|
private bindingEpochCounter = 0;
|
|
3362
|
+
private marketPointer:
|
|
3363
|
+
| Readonly<{
|
|
3364
|
+
pointerId: number;
|
|
3365
|
+
rowKey: string;
|
|
3366
|
+
startX: number;
|
|
3367
|
+
startY: number;
|
|
3368
|
+
timer: number;
|
|
3369
|
+
}>
|
|
3370
|
+
| undefined;
|
|
3371
|
+
private marketLongPressFired = false;
|
|
2872
3372
|
private lastViewportWidth = -1;
|
|
2873
3373
|
private lastViewportHeight = -1;
|
|
2874
3374
|
private destroyed = false;
|
|
@@ -2923,12 +3423,6 @@ export class NativeListWebEngine {
|
|
|
2923
3423
|
this.indexRail.setAttribute('role', 'navigation');
|
|
2924
3424
|
this.indexRail.setAttribute('aria-label', 'Section index');
|
|
2925
3425
|
this.indexRail.hidden = true;
|
|
2926
|
-
this.indexPreview = createElement(
|
|
2927
|
-
this.document,
|
|
2928
|
-
'div',
|
|
2929
|
-
'ok-native-list-index-preview'
|
|
2930
|
-
);
|
|
2931
|
-
this.indexPreview.setAttribute('aria-live', 'polite');
|
|
2932
3426
|
this.refreshIndicator = createElement(
|
|
2933
3427
|
this.document,
|
|
2934
3428
|
'div',
|
|
@@ -2949,7 +3443,6 @@ export class NativeListWebEngine {
|
|
|
2949
3443
|
this.viewport,
|
|
2950
3444
|
this.sticky,
|
|
2951
3445
|
this.indexRail,
|
|
2952
|
-
this.indexPreview,
|
|
2953
3446
|
this.refreshIndicator
|
|
2954
3447
|
);
|
|
2955
3448
|
this.root.append(style, this.viewportFrame, this.footer);
|
|
@@ -2958,7 +3451,15 @@ export class NativeListWebEngine {
|
|
|
2958
3451
|
this.viewport.addEventListener('scroll', this.handleScroll, {
|
|
2959
3452
|
passive: true,
|
|
2960
3453
|
});
|
|
3454
|
+
this.viewport.addEventListener(
|
|
3455
|
+
'ok-collapsible-pager-insets-changed',
|
|
3456
|
+
this.handleCollapsiblePagerInsetsChanged
|
|
3457
|
+
);
|
|
2961
3458
|
this.root.addEventListener('click', this.handleClick);
|
|
3459
|
+
this.root.addEventListener('pointerdown', this.handleMarketPointerDown);
|
|
3460
|
+
this.root.addEventListener('pointermove', this.handleMarketPointerMove);
|
|
3461
|
+
this.root.addEventListener('pointerup', this.handleMarketPointerEnd);
|
|
3462
|
+
this.root.addEventListener('pointercancel', this.handleMarketPointerEnd);
|
|
2962
3463
|
// OneKey patch: preserve web tooltip hover for section titles.
|
|
2963
3464
|
this.root.addEventListener('pointerover', this.handleTitlePointerOver);
|
|
2964
3465
|
this.root.addEventListener('pointerout', this.handleTitlePointerOut);
|
|
@@ -2990,6 +3491,11 @@ export class NativeListWebEngine {
|
|
|
2990
3491
|
);
|
|
2991
3492
|
this.indexRail.addEventListener('pointerdown', this.handleIndexPointer);
|
|
2992
3493
|
this.indexRail.addEventListener('pointermove', this.handleIndexPointer);
|
|
3494
|
+
this.indexRail.addEventListener('pointerup', this.handleIndexPointerEnd);
|
|
3495
|
+
this.indexRail.addEventListener(
|
|
3496
|
+
'pointercancel',
|
|
3497
|
+
this.handleIndexPointerEnd
|
|
3498
|
+
);
|
|
2993
3499
|
this.indexRail.addEventListener('click', this.handleIndexClick);
|
|
2994
3500
|
this.viewport.addEventListener('pointerdown', this.handlePullStart, {
|
|
2995
3501
|
passive: true,
|
|
@@ -3034,7 +3540,6 @@ export class NativeListWebEngine {
|
|
|
3034
3540
|
applyPatches(patches: readonly RowPatch[]) {
|
|
3035
3541
|
if (patches.length === 0) return;
|
|
3036
3542
|
const next = applyRowPatches(this.snapshot, patches);
|
|
3037
|
-
this.invalidateActionAnchor('snapshot');
|
|
3038
3543
|
const selection = new Set(this.selectedKeys);
|
|
3039
3544
|
patches.forEach((patch) => {
|
|
3040
3545
|
const selected =
|
|
@@ -3042,6 +3547,29 @@ export class NativeListWebEngine {
|
|
|
3042
3547
|
if (selected === true) selection.add(patch.key);
|
|
3043
3548
|
else if (selected === false) selection.delete(patch.key);
|
|
3044
3549
|
});
|
|
3550
|
+
if (webMarketImageBindDeltaForPatches(patches) === 0) {
|
|
3551
|
+
this.snapshot = next;
|
|
3552
|
+
this.rows = effectiveRows(next);
|
|
3553
|
+
this.selectedKeys = selection;
|
|
3554
|
+
patches.forEach((patch) => {
|
|
3555
|
+
const index = this.rows.findIndex((row) => row.key === patch.key);
|
|
3556
|
+
const row = this.rows[index];
|
|
3557
|
+
const element = this.mounted.get(index);
|
|
3558
|
+
if (row?.type === 'market' && element) {
|
|
3559
|
+
setMarketQuoteContent(element, row);
|
|
3560
|
+
element.dataset.renderSignature = webRowRenderSignature(row);
|
|
3561
|
+
}
|
|
3562
|
+
if (
|
|
3563
|
+
row?.type === 'market' &&
|
|
3564
|
+
this.sticky.dataset.nativeListRowKey === row.key
|
|
3565
|
+
) {
|
|
3566
|
+
setMarketQuoteContent(this.sticky, row);
|
|
3567
|
+
this.sticky.dataset.renderSignature = webRowRenderSignature(row);
|
|
3568
|
+
}
|
|
3569
|
+
});
|
|
3570
|
+
return;
|
|
3571
|
+
}
|
|
3572
|
+
this.invalidateActionAnchor('snapshot');
|
|
3045
3573
|
this.setSnapshot(next, selection);
|
|
3046
3574
|
}
|
|
3047
3575
|
|
|
@@ -3169,8 +3697,6 @@ export class NativeListWebEngine {
|
|
|
3169
3697
|
this.invalidateActionAnchor('destroy');
|
|
3170
3698
|
this.destroyed = true;
|
|
3171
3699
|
if (this.frameHandle !== undefined) this.cancelFrame(this.frameHandle);
|
|
3172
|
-
if (this.previewTimer !== undefined)
|
|
3173
|
-
this.document.defaultView?.clearTimeout(this.previewTimer);
|
|
3174
3700
|
if (this.reorderMovementTimer !== undefined)
|
|
3175
3701
|
this.document.defaultView?.clearTimeout(this.reorderMovementTimer);
|
|
3176
3702
|
this.resizeObserver?.disconnect();
|
|
@@ -3179,7 +3705,16 @@ export class NativeListWebEngine {
|
|
|
3179
3705
|
this.handleWindowResize
|
|
3180
3706
|
);
|
|
3181
3707
|
this.viewport.removeEventListener('scroll', this.handleScroll);
|
|
3708
|
+
this.viewport.removeEventListener(
|
|
3709
|
+
'ok-collapsible-pager-insets-changed',
|
|
3710
|
+
this.handleCollapsiblePagerInsetsChanged
|
|
3711
|
+
);
|
|
3182
3712
|
this.root.removeEventListener('click', this.handleClick);
|
|
3713
|
+
this.cancelMarketPointer();
|
|
3714
|
+
this.root.removeEventListener('pointerdown', this.handleMarketPointerDown);
|
|
3715
|
+
this.root.removeEventListener('pointermove', this.handleMarketPointerMove);
|
|
3716
|
+
this.root.removeEventListener('pointerup', this.handleMarketPointerEnd);
|
|
3717
|
+
this.root.removeEventListener('pointercancel', this.handleMarketPointerEnd);
|
|
3183
3718
|
this.root.removeEventListener('pointerover', this.handleTitlePointerOver);
|
|
3184
3719
|
this.root.removeEventListener('pointerout', this.handleTitlePointerOut);
|
|
3185
3720
|
this.root.removeEventListener('keydown', this.handleKeyDown);
|
|
@@ -3208,6 +3743,11 @@ export class NativeListWebEngine {
|
|
|
3208
3743
|
);
|
|
3209
3744
|
this.indexRail.removeEventListener('pointerdown', this.handleIndexPointer);
|
|
3210
3745
|
this.indexRail.removeEventListener('pointermove', this.handleIndexPointer);
|
|
3746
|
+
this.indexRail.removeEventListener('pointerup', this.handleIndexPointerEnd);
|
|
3747
|
+
this.indexRail.removeEventListener(
|
|
3748
|
+
'pointercancel',
|
|
3749
|
+
this.handleIndexPointerEnd
|
|
3750
|
+
);
|
|
3211
3751
|
this.indexRail.removeEventListener('click', this.handleIndexClick);
|
|
3212
3752
|
this.viewport.removeEventListener('pointerdown', this.handlePullStart);
|
|
3213
3753
|
this.viewport.removeEventListener('pointermove', this.handlePullMove);
|
|
@@ -3230,6 +3770,7 @@ export class NativeListWebEngine {
|
|
|
3230
3770
|
snapshot: NativeListSnapshot,
|
|
3231
3771
|
selectedKeys?: ReadonlySet<string>
|
|
3232
3772
|
) {
|
|
3773
|
+
this.cancelMarketPointer();
|
|
3233
3774
|
this.measuredWarningHeights.clear();
|
|
3234
3775
|
this.snapshot = snapshot;
|
|
3235
3776
|
this.rows = effectiveRows(snapshot);
|
|
@@ -3281,7 +3822,20 @@ export class NativeListWebEngine {
|
|
|
3281
3822
|
private recomputeLayout = () => {
|
|
3282
3823
|
if (this.destroyed) return;
|
|
3283
3824
|
const viewportWidth = this.viewport.clientWidth;
|
|
3284
|
-
const viewportHeight =
|
|
3825
|
+
const viewportHeight =
|
|
3826
|
+
this.snapshot.layout.orientation === 'horizontal'
|
|
3827
|
+
? this.viewport.clientHeight
|
|
3828
|
+
: this.verticalScrollMetrics().viewportLength;
|
|
3829
|
+
if (this.snapshot.layout.orientation !== 'horizontal') {
|
|
3830
|
+
const stickyInset = this.collapsiblePagerInsets().sticky;
|
|
3831
|
+
this.sticky.style.top = String(stickyInset) + 'px';
|
|
3832
|
+
this.indexRail.style.top = String(stickyInset) + 'px';
|
|
3833
|
+
this.refreshIndicator.style.top = String(stickyInset + 8) + 'px';
|
|
3834
|
+
} else {
|
|
3835
|
+
this.sticky.style.top = '0px';
|
|
3836
|
+
this.indexRail.style.top = '0px';
|
|
3837
|
+
this.refreshIndicator.style.top = '8px';
|
|
3838
|
+
}
|
|
3285
3839
|
if (
|
|
3286
3840
|
this.lastViewportWidth >= 0 &&
|
|
3287
3841
|
(viewportWidth !== this.lastViewportWidth ||
|
|
@@ -3312,7 +3866,11 @@ export class NativeListWebEngine {
|
|
|
3312
3866
|
);
|
|
3313
3867
|
this.content.style.width = String(this.layout.contentWidth) + 'px';
|
|
3314
3868
|
this.content.style.height = String(this.layout.contentHeight) + 'px';
|
|
3315
|
-
this.renderSectionIndex(
|
|
3869
|
+
this.renderSectionIndex(
|
|
3870
|
+
this.viewport.clientHeight <= 0
|
|
3871
|
+
? DEFAULT_VIEWPORT_HEIGHT
|
|
3872
|
+
: Math.max(1, viewportHeight)
|
|
3873
|
+
);
|
|
3316
3874
|
if (previousHorizontal !== this.layout.horizontal) {
|
|
3317
3875
|
this.viewport.scrollLeft = 0;
|
|
3318
3876
|
this.viewport.scrollTop = 0;
|
|
@@ -3580,6 +4138,17 @@ export class NativeListWebEngine {
|
|
|
3580
4138
|
}
|
|
3581
4139
|
}
|
|
3582
4140
|
element.replaceChildren(body);
|
|
4141
|
+
if (
|
|
4142
|
+
row.type === 'market' &&
|
|
4143
|
+
row.diagnostics?.imageBindActionKey &&
|
|
4144
|
+
body.querySelector('img')
|
|
4145
|
+
) {
|
|
4146
|
+
this.callbacks.onRowAction?.({
|
|
4147
|
+
rowKey: row.key,
|
|
4148
|
+
actionKey: row.diagnostics.imageBindActionKey,
|
|
4149
|
+
sectionKey: row.sectionKey,
|
|
4150
|
+
});
|
|
4151
|
+
}
|
|
3583
4152
|
}
|
|
3584
4153
|
|
|
3585
4154
|
private renderFooter() {
|
|
@@ -3609,17 +4178,15 @@ export class NativeListWebEngine {
|
|
|
3609
4178
|
): readonly number[] {
|
|
3610
4179
|
const entryCount = this.sectionIndexEntries.length;
|
|
3611
4180
|
if (entryCount <= 1) return entryCount ? [0] : [];
|
|
3612
|
-
const
|
|
3613
|
-
0,
|
|
3614
|
-
viewportHeight - SECTION_INDEX_EDGE_PADDING * 2
|
|
3615
|
-
);
|
|
4181
|
+
const { trackHeight } = this.sectionIndexMetrics(viewportHeight);
|
|
3616
4182
|
const maxVisible = Math.max(
|
|
3617
|
-
|
|
3618
|
-
Math.floor(
|
|
4183
|
+
1,
|
|
4184
|
+
Math.floor(trackHeight / SECTION_INDEX_LABEL_SPACING)
|
|
3619
4185
|
);
|
|
3620
4186
|
if (entryCount <= maxVisible) {
|
|
3621
4187
|
return Array.from({ length: entryCount }, (_, index) => index);
|
|
3622
4188
|
}
|
|
4189
|
+
if (maxVisible === 1) return [0];
|
|
3623
4190
|
const result = new Set<number>();
|
|
3624
4191
|
for (let slot = 0; slot < maxVisible; slot += 1) {
|
|
3625
4192
|
result.add(Math.round((slot * (entryCount - 1)) / (maxVisible - 1)));
|
|
@@ -3627,6 +4194,21 @@ export class NativeListWebEngine {
|
|
|
3627
4194
|
return [...result].sort((left, right) => left - right);
|
|
3628
4195
|
}
|
|
3629
4196
|
|
|
4197
|
+
private sectionIndexMetrics(viewportHeight: number) {
|
|
4198
|
+
const availableHeight = Math.max(
|
|
4199
|
+
0,
|
|
4200
|
+
viewportHeight - SECTION_INDEX_EDGE_PADDING * 2
|
|
4201
|
+
);
|
|
4202
|
+
const trackHeight = Math.min(
|
|
4203
|
+
availableHeight,
|
|
4204
|
+
SECTION_INDEX_LABEL_SPACING * this.sectionIndexEntries.length
|
|
4205
|
+
);
|
|
4206
|
+
return {
|
|
4207
|
+
originY: (viewportHeight - trackHeight) / 2,
|
|
4208
|
+
trackHeight,
|
|
4209
|
+
};
|
|
4210
|
+
}
|
|
4211
|
+
|
|
3630
4212
|
private renderSectionIndex(viewportHeight: number) {
|
|
3631
4213
|
this.indexRail.replaceChildren();
|
|
3632
4214
|
if (!sectionIndexEnabled(this.snapshot)) {
|
|
@@ -3653,8 +4235,15 @@ export class NativeListWebEngine {
|
|
|
3653
4235
|
'compact',
|
|
3654
4236
|
visibleEntryIndices.length < this.sectionIndexEntries.length
|
|
3655
4237
|
);
|
|
4238
|
+
const metrics = this.sectionIndexMetrics(viewportHeight);
|
|
4239
|
+
const visibleTrackHeight = Math.min(
|
|
4240
|
+
metrics.trackHeight,
|
|
4241
|
+
SECTION_INDEX_LABEL_SPACING * visibleEntryIndices.length
|
|
4242
|
+
);
|
|
4243
|
+
const visibleOriginY =
|
|
4244
|
+
metrics.originY + (metrics.trackHeight - visibleTrackHeight) / 2;
|
|
3656
4245
|
const fragment = this.document.createDocumentFragment();
|
|
3657
|
-
visibleEntryIndices.forEach((entryIndex) => {
|
|
4246
|
+
visibleEntryIndices.forEach((entryIndex, visibleIndex) => {
|
|
3658
4247
|
const entry = this.sectionIndexEntries[entryIndex];
|
|
3659
4248
|
if (!entry) return;
|
|
3660
4249
|
const button = createElement(
|
|
@@ -3668,14 +4257,11 @@ export class NativeListWebEngine {
|
|
|
3668
4257
|
setData(button, 'sectionEntryIndex', entryIndex);
|
|
3669
4258
|
setData(button, 'sectionPosition', entry.position);
|
|
3670
4259
|
setData(button, 'sectionKey', entry.key);
|
|
3671
|
-
const progress =
|
|
3672
|
-
this.sectionIndexEntries.length === 1
|
|
3673
|
-
? 0.5
|
|
3674
|
-
: entryIndex / (this.sectionIndexEntries.length - 1);
|
|
3675
4260
|
button.style.top =
|
|
3676
4261
|
String(
|
|
3677
|
-
|
|
3678
|
-
|
|
4262
|
+
visibleOriginY +
|
|
4263
|
+
(visibleTrackHeight * (visibleIndex + 0.5)) /
|
|
4264
|
+
visibleEntryIndices.length
|
|
3679
4265
|
) + 'px';
|
|
3680
4266
|
fragment.appendChild(button);
|
|
3681
4267
|
});
|
|
@@ -3811,7 +4397,7 @@ export class NativeListWebEngine {
|
|
|
3811
4397
|
}
|
|
3812
4398
|
const next = this.layout.items[nextIndex];
|
|
3813
4399
|
const translate = next
|
|
3814
|
-
? Math.min(0, next.y - this.
|
|
4400
|
+
? Math.min(0, next.y - this.currentOffset() - item.height)
|
|
3815
4401
|
: 0;
|
|
3816
4402
|
this.sticky.style.transform =
|
|
3817
4403
|
'translate3d(0,' + String(translate) + 'px,0)';
|
|
@@ -3887,9 +4473,11 @@ export class NativeListWebEngine {
|
|
|
3887
4473
|
}
|
|
3888
4474
|
|
|
3889
4475
|
private viewportLength(): number {
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
4476
|
+
if (this.layout.horizontal) {
|
|
4477
|
+
return this.viewport.clientWidth || DEFAULT_VIEWPORT_WIDTH;
|
|
4478
|
+
}
|
|
4479
|
+
if (this.viewport.clientHeight <= 0) return DEFAULT_VIEWPORT_HEIGHT;
|
|
4480
|
+
return Math.max(1, this.verticalScrollMetrics().viewportLength);
|
|
3893
4481
|
}
|
|
3894
4482
|
|
|
3895
4483
|
private contentLength(): number {
|
|
@@ -3901,18 +4489,54 @@ export class NativeListWebEngine {
|
|
|
3901
4489
|
private currentOffset(): number {
|
|
3902
4490
|
return this.layout.horizontal
|
|
3903
4491
|
? this.viewport.scrollLeft
|
|
3904
|
-
: this.
|
|
4492
|
+
: this.verticalScrollMetrics().offset;
|
|
4493
|
+
}
|
|
4494
|
+
|
|
4495
|
+
private collapsiblePagerInsets(): Readonly<{
|
|
4496
|
+
header: number;
|
|
4497
|
+
sticky: number;
|
|
4498
|
+
}> {
|
|
4499
|
+
const readInset = (name: string) => {
|
|
4500
|
+
const parsed = Number.parseFloat(
|
|
4501
|
+
this.viewport.style.getPropertyValue(name)
|
|
4502
|
+
);
|
|
4503
|
+
return Number.isFinite(parsed) ? Math.max(0, parsed) : 0;
|
|
4504
|
+
};
|
|
4505
|
+
return {
|
|
4506
|
+
header: readInset('--ok-collapsible-pager-header-inset'),
|
|
4507
|
+
sticky: readInset('--ok-collapsible-pager-sticky-inset'),
|
|
4508
|
+
};
|
|
4509
|
+
}
|
|
4510
|
+
|
|
4511
|
+
private verticalScrollMetrics(): WebCollapsiblePagerScrollMetrics {
|
|
4512
|
+
const insets = this.collapsiblePagerInsets();
|
|
4513
|
+
return resolveWebCollapsiblePagerScrollMetrics(
|
|
4514
|
+
this.viewport.scrollTop,
|
|
4515
|
+
this.viewport.clientHeight,
|
|
4516
|
+
insets.header,
|
|
4517
|
+
insets.sticky
|
|
4518
|
+
);
|
|
3905
4519
|
}
|
|
3906
4520
|
|
|
4521
|
+
private handleCollapsiblePagerInsetsChanged = () => {
|
|
4522
|
+
this.recomputeLayout();
|
|
4523
|
+
};
|
|
4524
|
+
|
|
3907
4525
|
private scrollToAbsoluteOffset(offset: number, animated: boolean) {
|
|
3908
4526
|
const resolved = Math.min(
|
|
3909
4527
|
Math.max(0, offset),
|
|
3910
4528
|
Math.max(0, this.contentLength() - this.viewportLength())
|
|
3911
4529
|
);
|
|
4530
|
+
const rawOffset = this.layout.horizontal
|
|
4531
|
+
? resolved
|
|
4532
|
+
: resolveWebCollapsiblePagerRawOffset(
|
|
4533
|
+
resolved,
|
|
4534
|
+
this.collapsiblePagerInsets().header
|
|
4535
|
+
);
|
|
3912
4536
|
this.viewport.scrollTo(
|
|
3913
4537
|
this.layout.horizontal
|
|
3914
|
-
? { left:
|
|
3915
|
-
: { left: 0, top:
|
|
4538
|
+
? { left: rawOffset, top: 0, behavior: animated ? 'smooth' : 'auto' }
|
|
4539
|
+
: { left: 0, top: rawOffset, behavior: animated ? 'smooth' : 'auto' }
|
|
3916
4540
|
);
|
|
3917
4541
|
this.scheduleFrame();
|
|
3918
4542
|
}
|
|
@@ -4102,6 +4726,8 @@ export class NativeListWebEngine {
|
|
|
4102
4726
|
? row.actionKey
|
|
4103
4727
|
: row.type === 'system' && row.variant === 'retry'
|
|
4104
4728
|
? row.actionKey
|
|
4729
|
+
: row.type === 'market' && row.pressActionKey
|
|
4730
|
+
? row.pressActionKey
|
|
4105
4731
|
: 'press';
|
|
4106
4732
|
if (rowElement && sourceElement) {
|
|
4107
4733
|
const anchor = this.createActionAnchor(sourceElement, rowElement, 'row');
|
|
@@ -4116,6 +4742,64 @@ export class NativeListWebEngine {
|
|
|
4116
4742
|
}
|
|
4117
4743
|
}
|
|
4118
4744
|
|
|
4745
|
+
private cancelMarketPointer() {
|
|
4746
|
+
const state = this.marketPointer;
|
|
4747
|
+
if (!state) return;
|
|
4748
|
+
this.document.defaultView?.clearTimeout(state.timer);
|
|
4749
|
+
this.marketPointer = undefined;
|
|
4750
|
+
}
|
|
4751
|
+
|
|
4752
|
+
private handleMarketPointerDown = (event: PointerEvent) => {
|
|
4753
|
+
if (event.button !== 0 || !(event.target instanceof Element)) return;
|
|
4754
|
+
this.marketLongPressFired = false;
|
|
4755
|
+
if (event.target.closest('[data-native-list-action]')) return;
|
|
4756
|
+
const rowElement = event.target.closest<HTMLElement>(
|
|
4757
|
+
'[data-native-list-row-key]'
|
|
4758
|
+
);
|
|
4759
|
+
const row = this.rowAtElement(rowElement);
|
|
4760
|
+
if (row?.type !== 'market' || row.disabled) return;
|
|
4761
|
+
this.cancelMarketPointer();
|
|
4762
|
+
if (row.pressInActionKey)
|
|
4763
|
+
this.emitRowAction(
|
|
4764
|
+
row,
|
|
4765
|
+
row.pressInActionKey,
|
|
4766
|
+
rowElement ?? undefined,
|
|
4767
|
+
rowElement ?? undefined
|
|
4768
|
+
);
|
|
4769
|
+
if (!row.longPressActionKey || !rowElement) return;
|
|
4770
|
+
markActionAnchorSource(rowElement, 'row');
|
|
4771
|
+
const timer = this.document.defaultView?.setTimeout(() => {
|
|
4772
|
+
const current = this.marketPointer;
|
|
4773
|
+
if (!current || current.pointerId !== event.pointerId) return;
|
|
4774
|
+
this.marketPointer = undefined;
|
|
4775
|
+
this.marketLongPressFired = true;
|
|
4776
|
+
this.emitRowAction(row, row.longPressActionKey!, rowElement, rowElement);
|
|
4777
|
+
}, MARKET_LONG_PRESS_MS);
|
|
4778
|
+
if (timer === undefined) return;
|
|
4779
|
+
this.marketPointer = {
|
|
4780
|
+
pointerId: event.pointerId,
|
|
4781
|
+
rowKey: row.key,
|
|
4782
|
+
startX: event.clientX,
|
|
4783
|
+
startY: event.clientY,
|
|
4784
|
+
timer,
|
|
4785
|
+
};
|
|
4786
|
+
};
|
|
4787
|
+
|
|
4788
|
+
private handleMarketPointerMove = (event: PointerEvent) => {
|
|
4789
|
+
const state = this.marketPointer;
|
|
4790
|
+
if (!state || state.pointerId !== event.pointerId) return;
|
|
4791
|
+
if (
|
|
4792
|
+
Math.abs(event.clientX - state.startX) > MARKET_MOVE_CANCEL_PX ||
|
|
4793
|
+
Math.abs(event.clientY - state.startY) > MARKET_MOVE_CANCEL_PX
|
|
4794
|
+
)
|
|
4795
|
+
this.cancelMarketPointer();
|
|
4796
|
+
};
|
|
4797
|
+
|
|
4798
|
+
private handleMarketPointerEnd = (event: PointerEvent) => {
|
|
4799
|
+
if (this.marketPointer?.pointerId === event.pointerId)
|
|
4800
|
+
this.cancelMarketPointer();
|
|
4801
|
+
};
|
|
4802
|
+
|
|
4119
4803
|
// OneKey patch: hover opens the same anchored help action as native taps.
|
|
4120
4804
|
private handleTitlePointerOver = (event: PointerEvent) => {
|
|
4121
4805
|
const target = event.target;
|
|
@@ -4167,7 +4851,8 @@ export class NativeListWebEngine {
|
|
|
4167
4851
|
};
|
|
4168
4852
|
|
|
4169
4853
|
private handleClick = (event: Event) => {
|
|
4170
|
-
if (Date.now() < this.suppressClickUntil) {
|
|
4854
|
+
if (this.marketLongPressFired || Date.now() < this.suppressClickUntil) {
|
|
4855
|
+
this.marketLongPressFired = false;
|
|
4171
4856
|
event.preventDefault();
|
|
4172
4857
|
event.stopPropagation();
|
|
4173
4858
|
return;
|
|
@@ -4340,6 +5025,7 @@ export class NativeListWebEngine {
|
|
|
4340
5025
|
}
|
|
4341
5026
|
|
|
4342
5027
|
private handleScroll = () => {
|
|
5028
|
+
this.cancelMarketPointer();
|
|
4343
5029
|
this.invalidateActionAnchor('scroll');
|
|
4344
5030
|
this.scheduleFrame();
|
|
4345
5031
|
};
|
|
@@ -4375,78 +5061,62 @@ export class NativeListWebEngine {
|
|
|
4375
5061
|
else view?.clearTimeout(handle);
|
|
4376
5062
|
}
|
|
4377
5063
|
|
|
4378
|
-
private selectIndexPosition(
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
5064
|
+
private selectIndexPosition(position: number) {
|
|
5065
|
+
const activeKey = this.sectionIndexEntries.find(
|
|
5066
|
+
(entry) => entry.position === position
|
|
5067
|
+
)?.key;
|
|
5068
|
+
this.indexRail
|
|
5069
|
+
.querySelectorAll<HTMLElement>('[data-section-key]')
|
|
5070
|
+
.forEach((button) =>
|
|
5071
|
+
setData(button, 'active', button.dataset.sectionKey === activeKey)
|
|
5072
|
+
);
|
|
4383
5073
|
this.scrollToIndex(position, {
|
|
4384
5074
|
animated: false,
|
|
4385
5075
|
alignment: 'start',
|
|
4386
5076
|
viewPosition: 0,
|
|
4387
5077
|
viewOffset: 0,
|
|
4388
5078
|
});
|
|
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
|
-
}
|
|
4399
|
-
this.indexPreview.textContent = title;
|
|
4400
|
-
setData(this.indexPreview, 'visible', true);
|
|
4401
|
-
if (this.previewTimer !== undefined)
|
|
4402
|
-
this.document.defaultView?.clearTimeout(this.previewTimer);
|
|
4403
|
-
this.previewTimer = this.document.defaultView?.setTimeout(() => {
|
|
4404
|
-
setData(this.indexPreview, 'visible', false);
|
|
4405
|
-
}, 180);
|
|
4406
5079
|
}
|
|
4407
5080
|
|
|
4408
|
-
private sectionIndexEntryAtEvent(
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
previewClientY: number;
|
|
4412
|
-
}>
|
|
4413
|
-
| undefined {
|
|
5081
|
+
private sectionIndexEntryAtEvent(
|
|
5082
|
+
event: PointerEvent
|
|
5083
|
+
): NativeListWebEngine['sectionIndexEntries'][number] | undefined {
|
|
4414
5084
|
const rail = this.indexRail.getBoundingClientRect();
|
|
4415
5085
|
if (this.sectionIndexEntries.length === 0 || rail.height <= 0) {
|
|
4416
5086
|
return undefined;
|
|
4417
5087
|
}
|
|
4418
|
-
const
|
|
4419
|
-
|
|
4420
|
-
rail.height - SECTION_INDEX_EDGE_PADDING * 2
|
|
4421
|
-
);
|
|
5088
|
+
const metrics = this.sectionIndexMetrics(rail.height);
|
|
5089
|
+
if (metrics.trackHeight <= 0) return undefined;
|
|
4422
5090
|
const progress = Math.min(
|
|
4423
5091
|
1,
|
|
4424
5092
|
Math.max(
|
|
4425
5093
|
0,
|
|
4426
|
-
(event.clientY - rail.top -
|
|
4427
|
-
availableHeight
|
|
5094
|
+
(event.clientY - rail.top - metrics.originY) / metrics.trackHeight
|
|
4428
5095
|
)
|
|
4429
5096
|
);
|
|
4430
|
-
const entryIndex = Math.
|
|
4431
|
-
|
|
5097
|
+
const entryIndex = Math.min(
|
|
5098
|
+
this.sectionIndexEntries.length - 1,
|
|
5099
|
+
Math.floor(progress * this.sectionIndexEntries.length)
|
|
4432
5100
|
);
|
|
4433
|
-
|
|
4434
|
-
return entry ? { entry, previewClientY: event.clientY } : undefined;
|
|
5101
|
+
return this.sectionIndexEntries[entryIndex];
|
|
4435
5102
|
}
|
|
4436
5103
|
|
|
4437
5104
|
private handleIndexPointer = (event: PointerEvent) => {
|
|
4438
5105
|
if (event.type === 'pointermove' && event.buttons === 0) return;
|
|
4439
|
-
const
|
|
4440
|
-
if (!
|
|
5106
|
+
const entry = this.sectionIndexEntryAtEvent(event);
|
|
5107
|
+
if (!entry) return;
|
|
4441
5108
|
event.preventDefault();
|
|
4442
5109
|
if (event.type === 'pointerdown') {
|
|
4443
5110
|
this.indexRail.setPointerCapture?.(event.pointerId);
|
|
4444
5111
|
}
|
|
4445
|
-
this.selectIndexPosition(
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
)
|
|
5112
|
+
this.selectIndexPosition(entry.position);
|
|
5113
|
+
};
|
|
5114
|
+
|
|
5115
|
+
private handleIndexPointerEnd = (event: PointerEvent) => {
|
|
5116
|
+
if (event.type === 'pointerup') {
|
|
5117
|
+
const entry = this.sectionIndexEntryAtEvent(event);
|
|
5118
|
+
if (entry) this.selectIndexPosition(entry.position);
|
|
5119
|
+
}
|
|
4450
5120
|
};
|
|
4451
5121
|
|
|
4452
5122
|
private handleIndexClick = (event: Event) => {
|
|
@@ -4463,12 +5133,7 @@ export class NativeListWebEngine {
|
|
|
4463
5133
|
const entry =
|
|
4464
5134
|
this.sectionIndexEntries[Number(button.dataset.sectionEntryIndex)];
|
|
4465
5135
|
if (!entry) return;
|
|
4466
|
-
|
|
4467
|
-
this.selectIndexPosition(
|
|
4468
|
-
entry.position,
|
|
4469
|
-
entry.title,
|
|
4470
|
-
rect.top + rect.height / 2
|
|
4471
|
-
);
|
|
5136
|
+
this.selectIndexPosition(entry.position);
|
|
4472
5137
|
};
|
|
4473
5138
|
|
|
4474
5139
|
private handlePullStart = (event: PointerEvent) => {
|
|
@@ -4671,7 +5336,12 @@ export class NativeListWebEngine {
|
|
|
4671
5336
|
const maximum = Math.max(0, this.contentLength() - this.viewportLength());
|
|
4672
5337
|
const next = Math.max(0, Math.min(maximum, offset));
|
|
4673
5338
|
if (this.layout.horizontal) this.viewport.scrollLeft = next;
|
|
4674
|
-
else
|
|
5339
|
+
else {
|
|
5340
|
+
this.viewport.scrollTop = resolveWebCollapsiblePagerRawOffset(
|
|
5341
|
+
next,
|
|
5342
|
+
this.collapsiblePagerInsets().header
|
|
5343
|
+
);
|
|
5344
|
+
}
|
|
4675
5345
|
this.scheduleFrame();
|
|
4676
5346
|
}
|
|
4677
5347
|
|
|
@@ -4753,10 +5423,15 @@ export class NativeListWebEngine {
|
|
|
4753
5423
|
}
|
|
4754
5424
|
this.reorderSettlingKey = state.sourceKey;
|
|
4755
5425
|
const viewportRect = this.viewport.getBoundingClientRect();
|
|
5426
|
+
const insets = this.collapsiblePagerInsets();
|
|
4756
5427
|
const left =
|
|
4757
5428
|
viewportRect.left + destinationLayout.x - this.viewport.scrollLeft;
|
|
4758
5429
|
const top =
|
|
4759
|
-
viewportRect.top +
|
|
5430
|
+
viewportRect.top +
|
|
5431
|
+
destinationLayout.y +
|
|
5432
|
+
insets.header +
|
|
5433
|
+
insets.sticky -
|
|
5434
|
+
this.viewport.scrollTop;
|
|
4760
5435
|
this.reorderPreview.getBoundingClientRect();
|
|
4761
5436
|
this.reorderPreview.style.transition =
|
|
4762
5437
|
'transform ' +
|