@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
|
@@ -8,7 +8,7 @@ import { acquireNativeListAvatar, canonicalNativeListAvatarUri } from "./NativeL
|
|
|
8
8
|
const SECTION_INDEX_CONTENT_INSET = 16;
|
|
9
9
|
const SECTION_INDEX_RAIL_WIDTH = 32;
|
|
10
10
|
const SECTION_INDEX_EDGE_PADDING = 8;
|
|
11
|
-
const
|
|
11
|
+
const SECTION_INDEX_LABEL_SPACING = 16;
|
|
12
12
|
const SECTION_INDEX_MIN_HEIGHT = 120;
|
|
13
13
|
const DEFAULT_VIEWPORT_WIDTH = 320;
|
|
14
14
|
const DEFAULT_VIEWPORT_HEIGHT = 640;
|
|
@@ -20,6 +20,9 @@ export const WEB_REORDER_ANIMATION = {
|
|
|
20
20
|
dropTimingFunction: 'ease'
|
|
21
21
|
};
|
|
22
22
|
const REORDER_TOUCH_LONG_PRESS_MS = 120;
|
|
23
|
+
const MARKET_LONG_PRESS_MS = 800;
|
|
24
|
+
const MARKET_MOVE_CANCEL_PX = 10;
|
|
25
|
+
export const WEB_MARKET_VERIFIED_PATH = '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';
|
|
23
26
|
const REORDER_MOUSE_MOVE_THRESHOLD_PX = 5;
|
|
24
27
|
const REORDER_EDGE_RATIO = 0.25;
|
|
25
28
|
const REORDER_MAX_SPEED_ZONE_RATIO = 0.05;
|
|
@@ -50,6 +53,25 @@ const defaultTheme = {
|
|
|
50
53
|
inverseText: '#FCFCFC',
|
|
51
54
|
info: '#0D74CE'
|
|
52
55
|
};
|
|
56
|
+
/** Resolves every reusable Market geometry field, including legacy defaults. */
|
|
57
|
+
export function resolveWebMarketLayoutStyle(row) {
|
|
58
|
+
const style = row.style;
|
|
59
|
+
const imageWidth = style?.image?.width ?? (row.variant === 'stock' ? 40 : 32);
|
|
60
|
+
const imageHeight = style?.image?.height ?? (row.variant === 'stock' ? 40 : 32);
|
|
61
|
+
return {
|
|
62
|
+
horizontalPadding: style?.horizontalPadding ?? (row.variant === 'perp' ? 16 : 20),
|
|
63
|
+
verticalPadding: style?.verticalPadding ?? 12,
|
|
64
|
+
leadingGap: style?.leadingGap ?? (row.variant === 'perp' ? 8 : 14),
|
|
65
|
+
titleBadgeGap: style?.titleBadgeGap ?? 4,
|
|
66
|
+
trailingGap: style?.trailingGap ?? 8,
|
|
67
|
+
imageWidth,
|
|
68
|
+
imageHeight,
|
|
69
|
+
imageCornerRadius: style?.image?.cornerRadius ?? (style?.image?.shape === 'square' ? 0 : style?.image?.shape === 'rounded' ? 8 : Math.min(imageWidth, imageHeight) / 2),
|
|
70
|
+
changeWidth: style?.changeWidth ?? 80,
|
|
71
|
+
changeHeight: style?.changeHeight ?? 32,
|
|
72
|
+
changeCornerRadius: style?.changeCornerRadius ?? 8
|
|
73
|
+
};
|
|
74
|
+
}
|
|
53
75
|
export function webActionAnchorPayload(token, rect, source, generation, layoutDirection, slot) {
|
|
54
76
|
return {
|
|
55
77
|
token,
|
|
@@ -195,7 +217,7 @@ export function estimateWebRowHeight(row, snapshot, availableWidth) {
|
|
|
195
217
|
break;
|
|
196
218
|
}
|
|
197
219
|
case 'system':
|
|
198
|
-
base = row.variant === 'noMatch' || row.variant === 'end' ? 36 : row.variant === 'retry' ? 44 : 56;
|
|
220
|
+
base = row.variant === 'loading' && row.loadingStyle === 'skeleton' ? 56 : row.variant === 'loading' && row.loadingStyle === 'spinner' ? 52 : 'presentation' in row && row.presentation === 'market' ? row.variant === 'loading' ? 68 : 44 : row.variant === 'noMatch' || row.variant === 'end' ? 36 : row.variant === 'retry' ? 44 : 56;
|
|
199
221
|
break;
|
|
200
222
|
case 'action':
|
|
201
223
|
base = row.presentation === 'accountSelector' ? 48 : row.icon ? 60 : 44;
|
|
@@ -203,6 +225,12 @@ export function estimateWebRowHeight(row, snapshot, availableWidth) {
|
|
|
203
225
|
case 'dataRow':
|
|
204
226
|
base = row.columns.some(column => column.secondaryText) ? 60 : 56;
|
|
205
227
|
break;
|
|
228
|
+
case 'market':
|
|
229
|
+
{
|
|
230
|
+
const marketStyle = resolveWebMarketLayoutStyle(row);
|
|
231
|
+
base = Math.max(row.variant === 'stock' ? 72 : 68, marketStyle.imageHeight + marketStyle.verticalPadding * 2);
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
206
234
|
case 'identity':
|
|
207
235
|
base = row.tertiary ? 72 : row.subtitle ? 60 : 56;
|
|
208
236
|
break;
|
|
@@ -366,6 +394,17 @@ export function visibleWebLayoutItems(layout, offset, viewportLength, overscan =
|
|
|
366
394
|
}
|
|
367
395
|
return visible;
|
|
368
396
|
}
|
|
397
|
+
export function resolveWebCollapsiblePagerScrollMetrics(rawOffset, rawViewportLength, headerInset, stickyInset) {
|
|
398
|
+
const header = Math.max(0, headerInset);
|
|
399
|
+
const sticky = Math.max(0, stickyInset);
|
|
400
|
+
return {
|
|
401
|
+
offset: Math.max(0, rawOffset - header),
|
|
402
|
+
viewportLength: Math.max(0, rawViewportLength - sticky)
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
export function resolveWebCollapsiblePagerRawOffset(logicalOffset, headerInset) {
|
|
406
|
+
return Math.max(0, logicalOffset) + Math.max(0, headerInset);
|
|
407
|
+
}
|
|
369
408
|
export function webLayoutItemsForMount(layout, offset, viewportLength, virtualizationEnabled, overscan = 0) {
|
|
370
409
|
return virtualizationEnabled ? visibleWebLayoutItems(layout, offset, viewportLength, overscan) : layout.items;
|
|
371
410
|
}
|
|
@@ -391,6 +430,15 @@ function rowWithoutSelectionState(row) {
|
|
|
391
430
|
export function webRowRenderSignature(row) {
|
|
392
431
|
return JSON.stringify(rowWithoutSelectionState(row));
|
|
393
432
|
}
|
|
433
|
+
const MARKET_QUOTE_PATCH_FIELDS = new Set(['revision', 'price', 'priceSegments', 'change', 'accessibilityLabel']);
|
|
434
|
+
export function isWebMarketQuotePatch(patch) {
|
|
435
|
+
return patch.type === 'market' && Object.keys(patch.changes).every(key => MARKET_QUOTE_PATCH_FIELDS.has(key));
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/** Number of Market image-binding passes caused by one Web patch transaction. */
|
|
439
|
+
export function webMarketImageBindDeltaForPatches(patches) {
|
|
440
|
+
return patches.length > 0 && patches.every(isWebMarketQuotePatch) ? 0 : 1;
|
|
441
|
+
}
|
|
394
442
|
|
|
395
443
|
// OneKey patch: selector names must shrink before the sidebar clips their contents.
|
|
396
444
|
export const WEB_LIST_CSS = `
|
|
@@ -448,11 +496,19 @@ export const WEB_LIST_CSS = `
|
|
|
448
496
|
.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}
|
|
449
497
|
.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)}
|
|
450
498
|
.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}
|
|
499
|
+
.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)}
|
|
500
|
+
.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}
|
|
451
501
|
.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)}
|
|
452
502
|
.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)}
|
|
453
503
|
.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)}
|
|
454
504
|
.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}
|
|
455
|
-
|
|
505
|
+
.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}
|
|
506
|
+
@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)}}
|
|
507
|
+
.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}
|
|
508
|
+
.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)}
|
|
509
|
+
.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)}
|
|
510
|
+
.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}
|
|
511
|
+
@media (prefers-reduced-motion:reduce){.ok-native-list-refresh{transition:none}.ok-native-list-spinner{animation:none}}
|
|
456
512
|
/* OneKey patch: selector controls follow their original semantic colors and geometry. */
|
|
457
513
|
.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))}
|
|
458
514
|
.ok-native-list-checkbox[data-selector="networkSelector"]::after{display:none}
|
|
@@ -812,6 +868,15 @@ const selectorIcons = {
|
|
|
812
868
|
fillRule: 'nonzero',
|
|
813
869
|
opacity: 1
|
|
814
870
|
}]
|
|
871
|
+
},
|
|
872
|
+
BadgeVerifiedSolid: {
|
|
873
|
+
viewBox: '0 0 24 24',
|
|
874
|
+
paths: [{
|
|
875
|
+
d: WEB_MARKET_VERIFIED_PATH,
|
|
876
|
+
fill: 'currentColor',
|
|
877
|
+
fillRule: 'evenodd',
|
|
878
|
+
opacity: 1
|
|
879
|
+
}]
|
|
815
880
|
}
|
|
816
881
|
};
|
|
817
882
|
function applySelectorIcon(element, name) {
|
|
@@ -859,6 +924,7 @@ function visualFromRow(row) {
|
|
|
859
924
|
if (row.type === 'activity') return row.leading;
|
|
860
925
|
if (row.type === 'message') return row.leading;
|
|
861
926
|
if (row.type === 'dataRow') return row.leading;
|
|
927
|
+
if (row.type === 'market') return row.leading;
|
|
862
928
|
if (row.type === 'metricCard') return row.visual;
|
|
863
929
|
return undefined;
|
|
864
930
|
}
|
|
@@ -1266,6 +1332,69 @@ function createActionRow(context, row) {
|
|
|
1266
1332
|
function createSystemRow(context, row) {
|
|
1267
1333
|
const body = createElement(context.document, 'div', 'ok-native-list-row ok-native-list-system');
|
|
1268
1334
|
setData(body, 'variant', row.variant);
|
|
1335
|
+
if ('presentation' in row) setData(body, 'nativeListPresentation', row.presentation);
|
|
1336
|
+
if (row.variant === 'loading' && row.loadingStyle === 'skeleton') {
|
|
1337
|
+
body.classList.add('ok-native-list-market-skeleton');
|
|
1338
|
+
const background = resolvedTheme(context.snapshot).background;
|
|
1339
|
+
const rgb = Number.parseInt(background.slice(1, 7), 16);
|
|
1340
|
+
const dark = (rgb >> 16 & 255) * 0.299 + (rgb >> 8 & 255) * 0.587 + (rgb & 255) * 0.114 < 128;
|
|
1341
|
+
body.style.setProperty('--nl-skeleton-base', dark ? '#111111' : '#fafafa');
|
|
1342
|
+
body.style.setProperty('--nl-skeleton-highlight', dark ? '#333333' : '#cdcdcd');
|
|
1343
|
+
const left = createElement(context.document, 'div', 'ok-native-list-skeleton-left');
|
|
1344
|
+
const mark = (width, height, circle = false) => {
|
|
1345
|
+
const element = createElement(context.document, 'span', 'ok-native-list-skeleton-mark');
|
|
1346
|
+
element.style.width = `${width}px`;
|
|
1347
|
+
element.style.height = `${height}px`;
|
|
1348
|
+
if (circle) element.style.borderRadius = '50%';
|
|
1349
|
+
return element;
|
|
1350
|
+
};
|
|
1351
|
+
left.appendChild(mark(32, 32, true));
|
|
1352
|
+
const text = createElement(context.document, 'div', 'ok-native-list-skeleton-text');
|
|
1353
|
+
text.appendChild(mark(80, 16));
|
|
1354
|
+
text.appendChild(mark(60, 12));
|
|
1355
|
+
left.appendChild(text);
|
|
1356
|
+
body.appendChild(left);
|
|
1357
|
+
const right = createElement(context.document, 'div', 'ok-native-list-skeleton-right');
|
|
1358
|
+
right.appendChild(mark(80, 18));
|
|
1359
|
+
right.appendChild(mark(80, 18));
|
|
1360
|
+
body.appendChild(right);
|
|
1361
|
+
return body;
|
|
1362
|
+
}
|
|
1363
|
+
if (row.variant === 'loading' && row.loadingStyle === 'spinner') {
|
|
1364
|
+
body.style.justifyContent = 'center';
|
|
1365
|
+
body.style.padding = '16px';
|
|
1366
|
+
const spinner = createElement(context.document, 'span', 'ok-native-list-market-spinner');
|
|
1367
|
+
spinner.setAttribute('role', 'progressbar');
|
|
1368
|
+
// Same 20px SVG and 750ms rotation as react-native-web ActivityIndicator.
|
|
1369
|
+
spinner.innerHTML = '<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>';
|
|
1370
|
+
body.appendChild(spinner);
|
|
1371
|
+
return body;
|
|
1372
|
+
}
|
|
1373
|
+
if ('presentation' in row && row.presentation === 'market') {
|
|
1374
|
+
if (row.variant === 'noMatch') {
|
|
1375
|
+
body.style.justifyContent = 'center';
|
|
1376
|
+
body.style.padding = '32px';
|
|
1377
|
+
const message = createElement(context.document, 'span', '', row.message);
|
|
1378
|
+
message.style.fontSize = '16px';
|
|
1379
|
+
message.style.lineHeight = '24px';
|
|
1380
|
+
body.appendChild(message);
|
|
1381
|
+
return body;
|
|
1382
|
+
}
|
|
1383
|
+
if (row.variant === 'end') {
|
|
1384
|
+
body.style.justifyContent = 'center';
|
|
1385
|
+
body.style.padding = '16px';
|
|
1386
|
+
body.style.gap = '8px';
|
|
1387
|
+
for (const width of [80, 4, 80]) {
|
|
1388
|
+
const mark = createElement(context.document, 'span', '');
|
|
1389
|
+
mark.style.width = String(width) + 'px';
|
|
1390
|
+
mark.style.height = width === 4 ? '4px' : '1px';
|
|
1391
|
+
mark.style.borderRadius = width === 4 ? '2px' : '0';
|
|
1392
|
+
mark.style.background = 'var(--nl-separator)';
|
|
1393
|
+
body.appendChild(mark);
|
|
1394
|
+
}
|
|
1395
|
+
return body;
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1269
1398
|
if (row.variant === 'warning') {
|
|
1270
1399
|
body.classList.add('ok-native-list-warning');
|
|
1271
1400
|
body.style.borderColor = row.borderColor ?? 'var(--nl-separator)';
|
|
@@ -1555,6 +1684,163 @@ function createWalletGroupRow(context, row) {
|
|
|
1555
1684
|
});
|
|
1556
1685
|
return body;
|
|
1557
1686
|
}
|
|
1687
|
+
function marketFontWeight(value, fallback) {
|
|
1688
|
+
if (value === 'bold') return 700;
|
|
1689
|
+
if (value === 'semibold') return 600;
|
|
1690
|
+
if (value === 'medium') return 500;
|
|
1691
|
+
if (value === 'regular') return 400;
|
|
1692
|
+
return fallback;
|
|
1693
|
+
}
|
|
1694
|
+
function applyMarketTextStyle(element, style, defaults) {
|
|
1695
|
+
element.style.fontSize = String(style?.fontSize ?? defaults.fontSize) + 'px';
|
|
1696
|
+
element.style.lineHeight = String(style?.lineHeight ?? defaults.lineHeight) + 'px';
|
|
1697
|
+
element.style.fontWeight = String(marketFontWeight(style?.fontWeight, defaults.weight));
|
|
1698
|
+
element.style.color = style?.color ?? '';
|
|
1699
|
+
element.style.textAlign = style?.alignment ?? defaults.alignment;
|
|
1700
|
+
element.style.whiteSpace = style?.lines === 2 ? 'normal' : 'nowrap';
|
|
1701
|
+
element.style.display = '';
|
|
1702
|
+
element.style.removeProperty('-webkit-line-clamp');
|
|
1703
|
+
element.style.removeProperty('-webkit-box-orient');
|
|
1704
|
+
if (style?.lines === 2) {
|
|
1705
|
+
element.style.display = '-webkit-box';
|
|
1706
|
+
element.style.setProperty('-webkit-line-clamp', '2');
|
|
1707
|
+
element.style.setProperty('-webkit-box-orient', 'vertical');
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
function setMarketQuoteContent(element, row) {
|
|
1711
|
+
const style = row.style;
|
|
1712
|
+
const layoutStyle = resolveWebMarketLayoutStyle(row);
|
|
1713
|
+
const price = element.querySelector('.ok-native-list-market-price');
|
|
1714
|
+
if (price) {
|
|
1715
|
+
price.textContent = row.price;
|
|
1716
|
+
applyMarketTextStyle(price, style?.price, {
|
|
1717
|
+
fontSize: 16,
|
|
1718
|
+
lineHeight: 24,
|
|
1719
|
+
weight: 500,
|
|
1720
|
+
alignment: 'end'
|
|
1721
|
+
});
|
|
1722
|
+
applyValueSegments(price, row.priceSegments, style?.price?.fontSize ?? 16, style?.price?.lineHeight ?? 24, marketFontWeight(style?.price?.fontWeight, 500));
|
|
1723
|
+
}
|
|
1724
|
+
const change = element.querySelector('.ok-native-list-market-change');
|
|
1725
|
+
if (change) {
|
|
1726
|
+
change.textContent = row.change.text;
|
|
1727
|
+
setData(change, 'tone', row.change.tone);
|
|
1728
|
+
applyMarketTextStyle(change, style?.change, {
|
|
1729
|
+
fontSize: 14,
|
|
1730
|
+
lineHeight: 20,
|
|
1731
|
+
weight: 500,
|
|
1732
|
+
alignment: 'center'
|
|
1733
|
+
});
|
|
1734
|
+
applyValueSegments(change, row.change.textSegments, style?.change?.fontSize ?? 14, style?.change?.lineHeight ?? 20, marketFontWeight(style?.change?.fontWeight, 500));
|
|
1735
|
+
change.style.width = String(layoutStyle.changeWidth) + 'px';
|
|
1736
|
+
change.style.height = String(layoutStyle.changeHeight) + 'px';
|
|
1737
|
+
change.style.borderRadius = String(layoutStyle.changeCornerRadius) + 'px';
|
|
1738
|
+
change.style.color = row.change.textColor ?? style?.change?.color ?? '';
|
|
1739
|
+
change.style.background = row.change.backgroundColor ?? '';
|
|
1740
|
+
}
|
|
1741
|
+
element.setAttribute('aria-label', row.accessibilityLabel ?? [row.title, row.subtitle, row.price, row.change.text].filter(Boolean).join(', '));
|
|
1742
|
+
}
|
|
1743
|
+
function createMarketRow(context, row) {
|
|
1744
|
+
const body = createElement(context.document, 'div', 'ok-native-list-row ok-native-list-market');
|
|
1745
|
+
setData(body, 'variant', row.variant);
|
|
1746
|
+
const style = row.style;
|
|
1747
|
+
const layoutStyle = resolveWebMarketLayoutStyle(row);
|
|
1748
|
+
body.style.padding = String(layoutStyle.verticalPadding) + 'px ' + String(layoutStyle.horizontalPadding) + 'px';
|
|
1749
|
+
body.style.gap = '0px';
|
|
1750
|
+
const visual = createVisual(context, row.leading);
|
|
1751
|
+
if (visual) {
|
|
1752
|
+
const width = layoutStyle.imageWidth;
|
|
1753
|
+
const height = layoutStyle.imageHeight;
|
|
1754
|
+
visual.style.width = String(width) + 'px';
|
|
1755
|
+
visual.style.height = String(height) + 'px';
|
|
1756
|
+
visual.style.flexBasis = String(width) + 'px';
|
|
1757
|
+
visual.style.borderRadius = String(layoutStyle.imageCornerRadius) + 'px';
|
|
1758
|
+
const borderColor = 'borderColor' in row.leading ? row.leading.borderColor : undefined;
|
|
1759
|
+
if (borderColor) {
|
|
1760
|
+
visual.style.border = '1px solid ' + borderColor;
|
|
1761
|
+
visual.style.boxSizing = 'border-box';
|
|
1762
|
+
}
|
|
1763
|
+
visual.querySelectorAll('img').forEach(image => {
|
|
1764
|
+
if (!image.classList.contains('ok-native-list-visual-corner')) {
|
|
1765
|
+
image.style.width = '100%';
|
|
1766
|
+
image.style.height = '100%';
|
|
1767
|
+
if (borderColor) {
|
|
1768
|
+
image.style.borderRadius = '0';
|
|
1769
|
+
image.style.clipPath = 'inset(-1px round ' + String(layoutStyle.imageCornerRadius) + 'px)';
|
|
1770
|
+
}
|
|
1771
|
+
image.style.objectFit = style?.image?.contentFit ?? image.style.objectFit;
|
|
1772
|
+
} else {
|
|
1773
|
+
image.style.width = '20px';
|
|
1774
|
+
image.style.height = '20px';
|
|
1775
|
+
if (borderColor) {
|
|
1776
|
+
image.style.right = '-5px';
|
|
1777
|
+
image.style.bottom = '-5px';
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
});
|
|
1781
|
+
visual.style.marginRight = String(layoutStyle.leadingGap) + 'px';
|
|
1782
|
+
body.appendChild(visual);
|
|
1783
|
+
}
|
|
1784
|
+
const main = createElement(context.document, 'span', 'ok-native-list-market-main');
|
|
1785
|
+
main.style.gap = String(style?.lineGap ?? 0) + 'px';
|
|
1786
|
+
const titleLine = createElement(context.document, 'span', 'ok-native-list-market-title-line');
|
|
1787
|
+
titleLine.style.gap = String(layoutStyle.titleBadgeGap) + 'px';
|
|
1788
|
+
const title = createElement(context.document, 'span', 'ok-native-list-market-title', row.title);
|
|
1789
|
+
applyMarketTextStyle(title, style?.title, {
|
|
1790
|
+
fontSize: 16,
|
|
1791
|
+
lineHeight: 24,
|
|
1792
|
+
weight: 500,
|
|
1793
|
+
alignment: 'start'
|
|
1794
|
+
});
|
|
1795
|
+
titleLine.appendChild(title);
|
|
1796
|
+
row.badges?.forEach((badge, slot) => {
|
|
1797
|
+
const element = createElement(context.document, badge.actionKey ? 'button' : 'span', 'ok-native-list-market-badge', badge.text);
|
|
1798
|
+
if (badge.actionKey) {
|
|
1799
|
+
element.setAttribute('type', 'button');
|
|
1800
|
+
setData(element, 'nativeListAction', badge.actionKey);
|
|
1801
|
+
markActionAnchorSource(element, 'marketBadge', slot);
|
|
1802
|
+
}
|
|
1803
|
+
setData(element, 'tone', badge.tone);
|
|
1804
|
+
element.style.color = badge.textColor ?? (badge.tone === 'success' ? 'var(--nl-positive)' : badge.tone === 'danger' ? 'var(--nl-negative)' : badge.tone === 'info' ? 'var(--nl-info)' : badge.tone === 'warning' ? 'var(--nl-primary)' : '');
|
|
1805
|
+
element.style.background = badge.backgroundColor ?? ((badge.icon || badge.iconName) && !badge.text ? 'transparent' : '');
|
|
1806
|
+
if ((badge.icon || badge.iconName) && !badge.text) {
|
|
1807
|
+
element.style.padding = '0';
|
|
1808
|
+
}
|
|
1809
|
+
if (badge.accessibilityLabel) element.setAttribute('aria-label', badge.accessibilityLabel);
|
|
1810
|
+
if (badge.icon) {
|
|
1811
|
+
const icon = createImage(context, badge.icon);
|
|
1812
|
+
if (icon) {
|
|
1813
|
+
icon.style.borderRadius = '50%';
|
|
1814
|
+
element.prepend(icon);
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
if (badge.iconName === 'verified') {
|
|
1818
|
+
const icon = createElement(context.document, 'span', 'ok-native-list-market-badge-icon');
|
|
1819
|
+
applySelectorIcon(icon, 'BadgeVerifiedSolid');
|
|
1820
|
+
element.prepend(icon);
|
|
1821
|
+
}
|
|
1822
|
+
titleLine.appendChild(element);
|
|
1823
|
+
});
|
|
1824
|
+
main.appendChild(titleLine);
|
|
1825
|
+
if (row.subtitle || row.subtitleSegments?.length) {
|
|
1826
|
+
const subtitle = createElement(context.document, 'span', 'ok-native-list-market-subtitle', row.subtitle);
|
|
1827
|
+
applyMarketTextStyle(subtitle, style?.subtitle, {
|
|
1828
|
+
fontSize: 14,
|
|
1829
|
+
lineHeight: 20,
|
|
1830
|
+
weight: 400,
|
|
1831
|
+
alignment: 'start'
|
|
1832
|
+
});
|
|
1833
|
+
applyValueSegments(subtitle, row.subtitleSegments, style?.subtitle?.fontSize ?? 14, style?.subtitle?.lineHeight ?? 20, marketFontWeight(style?.subtitle?.fontWeight, 400));
|
|
1834
|
+
main.appendChild(subtitle);
|
|
1835
|
+
}
|
|
1836
|
+
body.appendChild(main);
|
|
1837
|
+
const trailing = createElement(context.document, 'span', 'ok-native-list-market-trailing');
|
|
1838
|
+
trailing.style.gap = String(layoutStyle.trailingGap) + 'px';
|
|
1839
|
+
trailing.append(createElement(context.document, 'span', 'ok-native-list-market-price'), createElement(context.document, 'span', 'ok-native-list-market-change'));
|
|
1840
|
+
body.appendChild(trailing);
|
|
1841
|
+
setMarketQuoteContent(body, row);
|
|
1842
|
+
return body;
|
|
1843
|
+
}
|
|
1558
1844
|
function createRowBody(context, row) {
|
|
1559
1845
|
switch (row.type) {
|
|
1560
1846
|
case 'walletGroup':
|
|
@@ -1573,6 +1859,8 @@ function createRowBody(context, row) {
|
|
|
1573
1859
|
return createMetricRow(context, row);
|
|
1574
1860
|
case 'dataRow':
|
|
1575
1861
|
return createDataRow(context, row);
|
|
1862
|
+
case 'market':
|
|
1863
|
+
return createMarketRow(context, row);
|
|
1576
1864
|
case 'identity':
|
|
1577
1865
|
case 'activity':
|
|
1578
1866
|
case 'message':
|
|
@@ -1600,6 +1888,7 @@ export class NativeListWebEngine {
|
|
|
1600
1888
|
actionAnchorInstanceId = String(++webNativeListInstanceCounter);
|
|
1601
1889
|
actionAnchorCounter = 0;
|
|
1602
1890
|
bindingEpochCounter = 0;
|
|
1891
|
+
marketLongPressFired = false;
|
|
1603
1892
|
lastViewportWidth = -1;
|
|
1604
1893
|
lastViewportHeight = -1;
|
|
1605
1894
|
destroyed = false;
|
|
@@ -1627,8 +1916,6 @@ export class NativeListWebEngine {
|
|
|
1627
1916
|
this.indexRail.setAttribute('role', 'navigation');
|
|
1628
1917
|
this.indexRail.setAttribute('aria-label', 'Section index');
|
|
1629
1918
|
this.indexRail.hidden = true;
|
|
1630
|
-
this.indexPreview = createElement(this.document, 'div', 'ok-native-list-index-preview');
|
|
1631
|
-
this.indexPreview.setAttribute('aria-live', 'polite');
|
|
1632
1919
|
this.refreshIndicator = createElement(this.document, 'div', 'ok-native-list-refresh', 'Refreshing');
|
|
1633
1920
|
this.refreshIndicator.setAttribute('role', 'status');
|
|
1634
1921
|
this.reorderPreview = createElement(this.document, 'div', 'ok-native-list-reorder-preview');
|
|
@@ -1636,13 +1923,18 @@ export class NativeListWebEngine {
|
|
|
1636
1923
|
this.reorderPreview.setAttribute('aria-hidden', 'true');
|
|
1637
1924
|
this.document.body.appendChild(this.reorderPreview);
|
|
1638
1925
|
this.viewport.append(this.content);
|
|
1639
|
-
this.viewportFrame.append(this.viewport, this.sticky, this.indexRail, this.
|
|
1926
|
+
this.viewportFrame.append(this.viewport, this.sticky, this.indexRail, this.refreshIndicator);
|
|
1640
1927
|
this.root.append(style, this.viewportFrame, this.footer);
|
|
1641
1928
|
host.appendChild(this.root);
|
|
1642
1929
|
this.viewport.addEventListener('scroll', this.handleScroll, {
|
|
1643
1930
|
passive: true
|
|
1644
1931
|
});
|
|
1932
|
+
this.viewport.addEventListener('ok-collapsible-pager-insets-changed', this.handleCollapsiblePagerInsetsChanged);
|
|
1645
1933
|
this.root.addEventListener('click', this.handleClick);
|
|
1934
|
+
this.root.addEventListener('pointerdown', this.handleMarketPointerDown);
|
|
1935
|
+
this.root.addEventListener('pointermove', this.handleMarketPointerMove);
|
|
1936
|
+
this.root.addEventListener('pointerup', this.handleMarketPointerEnd);
|
|
1937
|
+
this.root.addEventListener('pointercancel', this.handleMarketPointerEnd);
|
|
1646
1938
|
// OneKey patch: preserve web tooltip hover for section titles.
|
|
1647
1939
|
this.root.addEventListener('pointerover', this.handleTitlePointerOver);
|
|
1648
1940
|
this.root.addEventListener('pointerout', this.handleTitlePointerOut);
|
|
@@ -1664,6 +1956,8 @@ export class NativeListWebEngine {
|
|
|
1664
1956
|
this.viewport.addEventListener('touchcancel', this.handleReorderTouchCancel);
|
|
1665
1957
|
this.indexRail.addEventListener('pointerdown', this.handleIndexPointer);
|
|
1666
1958
|
this.indexRail.addEventListener('pointermove', this.handleIndexPointer);
|
|
1959
|
+
this.indexRail.addEventListener('pointerup', this.handleIndexPointerEnd);
|
|
1960
|
+
this.indexRail.addEventListener('pointercancel', this.handleIndexPointerEnd);
|
|
1667
1961
|
this.indexRail.addEventListener('click', this.handleIndexClick);
|
|
1668
1962
|
this.viewport.addEventListener('pointerdown', this.handlePullStart, {
|
|
1669
1963
|
passive: true
|
|
@@ -1698,12 +1992,31 @@ export class NativeListWebEngine {
|
|
|
1698
1992
|
applyPatches(patches) {
|
|
1699
1993
|
if (patches.length === 0) return;
|
|
1700
1994
|
const next = applyRowPatches(this.snapshot, patches);
|
|
1701
|
-
this.invalidateActionAnchor('snapshot');
|
|
1702
1995
|
const selection = new Set(this.selectedKeys);
|
|
1703
1996
|
patches.forEach(patch => {
|
|
1704
1997
|
const selected = 'selected' in patch.changes ? patch.changes.selected : undefined;
|
|
1705
1998
|
if (selected === true) selection.add(patch.key);else if (selected === false) selection.delete(patch.key);
|
|
1706
1999
|
});
|
|
2000
|
+
if (webMarketImageBindDeltaForPatches(patches) === 0) {
|
|
2001
|
+
this.snapshot = next;
|
|
2002
|
+
this.rows = effectiveRows(next);
|
|
2003
|
+
this.selectedKeys = selection;
|
|
2004
|
+
patches.forEach(patch => {
|
|
2005
|
+
const index = this.rows.findIndex(row => row.key === patch.key);
|
|
2006
|
+
const row = this.rows[index];
|
|
2007
|
+
const element = this.mounted.get(index);
|
|
2008
|
+
if (row?.type === 'market' && element) {
|
|
2009
|
+
setMarketQuoteContent(element, row);
|
|
2010
|
+
element.dataset.renderSignature = webRowRenderSignature(row);
|
|
2011
|
+
}
|
|
2012
|
+
if (row?.type === 'market' && this.sticky.dataset.nativeListRowKey === row.key) {
|
|
2013
|
+
setMarketQuoteContent(this.sticky, row);
|
|
2014
|
+
this.sticky.dataset.renderSignature = webRowRenderSignature(row);
|
|
2015
|
+
}
|
|
2016
|
+
});
|
|
2017
|
+
return;
|
|
2018
|
+
}
|
|
2019
|
+
this.invalidateActionAnchor('snapshot');
|
|
1707
2020
|
this.setSnapshot(next, selection);
|
|
1708
2021
|
}
|
|
1709
2022
|
reconcileSelection(keys) {
|
|
@@ -1821,12 +2134,17 @@ export class NativeListWebEngine {
|
|
|
1821
2134
|
this.invalidateActionAnchor('destroy');
|
|
1822
2135
|
this.destroyed = true;
|
|
1823
2136
|
if (this.frameHandle !== undefined) this.cancelFrame(this.frameHandle);
|
|
1824
|
-
if (this.previewTimer !== undefined) this.document.defaultView?.clearTimeout(this.previewTimer);
|
|
1825
2137
|
if (this.reorderMovementTimer !== undefined) this.document.defaultView?.clearTimeout(this.reorderMovementTimer);
|
|
1826
2138
|
this.resizeObserver?.disconnect();
|
|
1827
2139
|
this.document.defaultView?.removeEventListener('resize', this.handleWindowResize);
|
|
1828
2140
|
this.viewport.removeEventListener('scroll', this.handleScroll);
|
|
2141
|
+
this.viewport.removeEventListener('ok-collapsible-pager-insets-changed', this.handleCollapsiblePagerInsetsChanged);
|
|
1829
2142
|
this.root.removeEventListener('click', this.handleClick);
|
|
2143
|
+
this.cancelMarketPointer();
|
|
2144
|
+
this.root.removeEventListener('pointerdown', this.handleMarketPointerDown);
|
|
2145
|
+
this.root.removeEventListener('pointermove', this.handleMarketPointerMove);
|
|
2146
|
+
this.root.removeEventListener('pointerup', this.handleMarketPointerEnd);
|
|
2147
|
+
this.root.removeEventListener('pointercancel', this.handleMarketPointerEnd);
|
|
1830
2148
|
this.root.removeEventListener('pointerover', this.handleTitlePointerOver);
|
|
1831
2149
|
this.root.removeEventListener('pointerout', this.handleTitlePointerOut);
|
|
1832
2150
|
this.root.removeEventListener('keydown', this.handleKeyDown);
|
|
@@ -1840,6 +2158,8 @@ export class NativeListWebEngine {
|
|
|
1840
2158
|
this.viewport.removeEventListener('touchcancel', this.handleReorderTouchCancel);
|
|
1841
2159
|
this.indexRail.removeEventListener('pointerdown', this.handleIndexPointer);
|
|
1842
2160
|
this.indexRail.removeEventListener('pointermove', this.handleIndexPointer);
|
|
2161
|
+
this.indexRail.removeEventListener('pointerup', this.handleIndexPointerEnd);
|
|
2162
|
+
this.indexRail.removeEventListener('pointercancel', this.handleIndexPointerEnd);
|
|
1843
2163
|
this.indexRail.removeEventListener('click', this.handleIndexClick);
|
|
1844
2164
|
this.viewport.removeEventListener('pointerdown', this.handlePullStart);
|
|
1845
2165
|
this.viewport.removeEventListener('pointermove', this.handlePullMove);
|
|
@@ -1858,6 +2178,7 @@ export class NativeListWebEngine {
|
|
|
1858
2178
|
this.avatarLeases.clear();
|
|
1859
2179
|
}
|
|
1860
2180
|
setSnapshot(snapshot, selectedKeys) {
|
|
2181
|
+
this.cancelMarketPointer();
|
|
1861
2182
|
this.measuredWarningHeights.clear();
|
|
1862
2183
|
this.snapshot = snapshot;
|
|
1863
2184
|
this.rows = effectiveRows(snapshot);
|
|
@@ -1905,7 +2226,17 @@ export class NativeListWebEngine {
|
|
|
1905
2226
|
recomputeLayout = () => {
|
|
1906
2227
|
if (this.destroyed) return;
|
|
1907
2228
|
const viewportWidth = this.viewport.clientWidth;
|
|
1908
|
-
const viewportHeight = this.viewport.clientHeight;
|
|
2229
|
+
const viewportHeight = this.snapshot.layout.orientation === 'horizontal' ? this.viewport.clientHeight : this.verticalScrollMetrics().viewportLength;
|
|
2230
|
+
if (this.snapshot.layout.orientation !== 'horizontal') {
|
|
2231
|
+
const stickyInset = this.collapsiblePagerInsets().sticky;
|
|
2232
|
+
this.sticky.style.top = String(stickyInset) + 'px';
|
|
2233
|
+
this.indexRail.style.top = String(stickyInset) + 'px';
|
|
2234
|
+
this.refreshIndicator.style.top = String(stickyInset + 8) + 'px';
|
|
2235
|
+
} else {
|
|
2236
|
+
this.sticky.style.top = '0px';
|
|
2237
|
+
this.indexRail.style.top = '0px';
|
|
2238
|
+
this.refreshIndicator.style.top = '8px';
|
|
2239
|
+
}
|
|
1909
2240
|
if (this.lastViewportWidth >= 0 && (viewportWidth !== this.lastViewportWidth || viewportHeight !== this.lastViewportHeight)) {
|
|
1910
2241
|
this.invalidateActionAnchor('layout');
|
|
1911
2242
|
this.measuredWarningHeights.clear();
|
|
@@ -1923,7 +2254,7 @@ export class NativeListWebEngine {
|
|
|
1923
2254
|
this.layout = computeWebListLayout(measuredSnapshot, viewportWidth, viewportHeight, this.reorderCompactKey);
|
|
1924
2255
|
this.content.style.width = String(this.layout.contentWidth) + 'px';
|
|
1925
2256
|
this.content.style.height = String(this.layout.contentHeight) + 'px';
|
|
1926
|
-
this.renderSectionIndex(
|
|
2257
|
+
this.renderSectionIndex(this.viewport.clientHeight <= 0 ? DEFAULT_VIEWPORT_HEIGHT : Math.max(1, viewportHeight));
|
|
1927
2258
|
if (previousHorizontal !== this.layout.horizontal) {
|
|
1928
2259
|
this.viewport.scrollLeft = 0;
|
|
1929
2260
|
this.viewport.scrollTop = 0;
|
|
@@ -2107,6 +2438,13 @@ export class NativeListWebEngine {
|
|
|
2107
2438
|
}
|
|
2108
2439
|
}
|
|
2109
2440
|
element.replaceChildren(body);
|
|
2441
|
+
if (row.type === 'market' && row.diagnostics?.imageBindActionKey && body.querySelector('img')) {
|
|
2442
|
+
this.callbacks.onRowAction?.({
|
|
2443
|
+
rowKey: row.key,
|
|
2444
|
+
actionKey: row.diagnostics.imageBindActionKey,
|
|
2445
|
+
sectionKey: row.sectionKey
|
|
2446
|
+
});
|
|
2447
|
+
}
|
|
2110
2448
|
}
|
|
2111
2449
|
renderFooter() {
|
|
2112
2450
|
const row = this.snapshot.fixedFooter;
|
|
@@ -2125,19 +2463,30 @@ export class NativeListWebEngine {
|
|
|
2125
2463
|
sectionIndexVisibleEntryIndices(viewportHeight) {
|
|
2126
2464
|
const entryCount = this.sectionIndexEntries.length;
|
|
2127
2465
|
if (entryCount <= 1) return entryCount ? [0] : [];
|
|
2128
|
-
const
|
|
2129
|
-
|
|
2466
|
+
const {
|
|
2467
|
+
trackHeight
|
|
2468
|
+
} = this.sectionIndexMetrics(viewportHeight);
|
|
2469
|
+
const maxVisible = Math.max(1, Math.floor(trackHeight / SECTION_INDEX_LABEL_SPACING));
|
|
2130
2470
|
if (entryCount <= maxVisible) {
|
|
2131
2471
|
return Array.from({
|
|
2132
2472
|
length: entryCount
|
|
2133
2473
|
}, (_, index) => index);
|
|
2134
2474
|
}
|
|
2475
|
+
if (maxVisible === 1) return [0];
|
|
2135
2476
|
const result = new Set();
|
|
2136
2477
|
for (let slot = 0; slot < maxVisible; slot += 1) {
|
|
2137
2478
|
result.add(Math.round(slot * (entryCount - 1) / (maxVisible - 1)));
|
|
2138
2479
|
}
|
|
2139
2480
|
return [...result].sort((left, right) => left - right);
|
|
2140
2481
|
}
|
|
2482
|
+
sectionIndexMetrics(viewportHeight) {
|
|
2483
|
+
const availableHeight = Math.max(0, viewportHeight - SECTION_INDEX_EDGE_PADDING * 2);
|
|
2484
|
+
const trackHeight = Math.min(availableHeight, SECTION_INDEX_LABEL_SPACING * this.sectionIndexEntries.length);
|
|
2485
|
+
return {
|
|
2486
|
+
originY: (viewportHeight - trackHeight) / 2,
|
|
2487
|
+
trackHeight
|
|
2488
|
+
};
|
|
2489
|
+
}
|
|
2141
2490
|
renderSectionIndex(viewportHeight) {
|
|
2142
2491
|
this.indexRail.replaceChildren();
|
|
2143
2492
|
if (!sectionIndexEnabled(this.snapshot)) {
|
|
@@ -2156,8 +2505,11 @@ export class NativeListWebEngine {
|
|
|
2156
2505
|
}
|
|
2157
2506
|
const visibleEntryIndices = this.sectionIndexVisibleEntryIndices(viewportHeight);
|
|
2158
2507
|
setData(this.indexRail, 'compact', visibleEntryIndices.length < this.sectionIndexEntries.length);
|
|
2508
|
+
const metrics = this.sectionIndexMetrics(viewportHeight);
|
|
2509
|
+
const visibleTrackHeight = Math.min(metrics.trackHeight, SECTION_INDEX_LABEL_SPACING * visibleEntryIndices.length);
|
|
2510
|
+
const visibleOriginY = metrics.originY + (metrics.trackHeight - visibleTrackHeight) / 2;
|
|
2159
2511
|
const fragment = this.document.createDocumentFragment();
|
|
2160
|
-
visibleEntryIndices.forEach(entryIndex => {
|
|
2512
|
+
visibleEntryIndices.forEach((entryIndex, visibleIndex) => {
|
|
2161
2513
|
const entry = this.sectionIndexEntries[entryIndex];
|
|
2162
2514
|
if (!entry) return;
|
|
2163
2515
|
const button = createElement(this.document, 'button', 'ok-native-list-index-button', entry.title);
|
|
@@ -2166,8 +2518,7 @@ export class NativeListWebEngine {
|
|
|
2166
2518
|
setData(button, 'sectionEntryIndex', entryIndex);
|
|
2167
2519
|
setData(button, 'sectionPosition', entry.position);
|
|
2168
2520
|
setData(button, 'sectionKey', entry.key);
|
|
2169
|
-
|
|
2170
|
-
button.style.top = String(SECTION_INDEX_EDGE_PADDING + progress * (viewportHeight - SECTION_INDEX_EDGE_PADDING * 2)) + 'px';
|
|
2521
|
+
button.style.top = String(visibleOriginY + visibleTrackHeight * (visibleIndex + 0.5) / visibleEntryIndices.length) + 'px';
|
|
2171
2522
|
fragment.appendChild(button);
|
|
2172
2523
|
});
|
|
2173
2524
|
this.indexRail.appendChild(fragment);
|
|
@@ -2262,7 +2613,7 @@ export class NativeListWebEngine {
|
|
|
2262
2613
|
}
|
|
2263
2614
|
}
|
|
2264
2615
|
const next = this.layout.items[nextIndex];
|
|
2265
|
-
const translate = next ? Math.min(0, next.y - this.
|
|
2616
|
+
const translate = next ? Math.min(0, next.y - this.currentOffset() - item.height) : 0;
|
|
2266
2617
|
this.sticky.style.transform = 'translate3d(0,' + String(translate) + 'px,0)';
|
|
2267
2618
|
this.updateVisibleSelection();
|
|
2268
2619
|
}
|
|
@@ -2297,23 +2648,45 @@ export class NativeListWebEngine {
|
|
|
2297
2648
|
return viewportLength > 0 && this.layout.items.length > 0;
|
|
2298
2649
|
}
|
|
2299
2650
|
viewportLength() {
|
|
2300
|
-
|
|
2651
|
+
if (this.layout.horizontal) {
|
|
2652
|
+
return this.viewport.clientWidth || DEFAULT_VIEWPORT_WIDTH;
|
|
2653
|
+
}
|
|
2654
|
+
if (this.viewport.clientHeight <= 0) return DEFAULT_VIEWPORT_HEIGHT;
|
|
2655
|
+
return Math.max(1, this.verticalScrollMetrics().viewportLength);
|
|
2301
2656
|
}
|
|
2302
2657
|
contentLength() {
|
|
2303
2658
|
return this.layout.horizontal ? this.layout.contentWidth : this.layout.contentHeight;
|
|
2304
2659
|
}
|
|
2305
2660
|
currentOffset() {
|
|
2306
|
-
return this.layout.horizontal ? this.viewport.scrollLeft : this.
|
|
2661
|
+
return this.layout.horizontal ? this.viewport.scrollLeft : this.verticalScrollMetrics().offset;
|
|
2307
2662
|
}
|
|
2663
|
+
collapsiblePagerInsets() {
|
|
2664
|
+
const readInset = name => {
|
|
2665
|
+
const parsed = Number.parseFloat(this.viewport.style.getPropertyValue(name));
|
|
2666
|
+
return Number.isFinite(parsed) ? Math.max(0, parsed) : 0;
|
|
2667
|
+
};
|
|
2668
|
+
return {
|
|
2669
|
+
header: readInset('--ok-collapsible-pager-header-inset'),
|
|
2670
|
+
sticky: readInset('--ok-collapsible-pager-sticky-inset')
|
|
2671
|
+
};
|
|
2672
|
+
}
|
|
2673
|
+
verticalScrollMetrics() {
|
|
2674
|
+
const insets = this.collapsiblePagerInsets();
|
|
2675
|
+
return resolveWebCollapsiblePagerScrollMetrics(this.viewport.scrollTop, this.viewport.clientHeight, insets.header, insets.sticky);
|
|
2676
|
+
}
|
|
2677
|
+
handleCollapsiblePagerInsetsChanged = () => {
|
|
2678
|
+
this.recomputeLayout();
|
|
2679
|
+
};
|
|
2308
2680
|
scrollToAbsoluteOffset(offset, animated) {
|
|
2309
2681
|
const resolved = Math.min(Math.max(0, offset), Math.max(0, this.contentLength() - this.viewportLength()));
|
|
2682
|
+
const rawOffset = this.layout.horizontal ? resolved : resolveWebCollapsiblePagerRawOffset(resolved, this.collapsiblePagerInsets().header);
|
|
2310
2683
|
this.viewport.scrollTo(this.layout.horizontal ? {
|
|
2311
|
-
left:
|
|
2684
|
+
left: rawOffset,
|
|
2312
2685
|
top: 0,
|
|
2313
2686
|
behavior: animated ? 'smooth' : 'auto'
|
|
2314
2687
|
} : {
|
|
2315
2688
|
left: 0,
|
|
2316
|
-
top:
|
|
2689
|
+
top: rawOffset,
|
|
2317
2690
|
behavior: animated ? 'smooth' : 'auto'
|
|
2318
2691
|
});
|
|
2319
2692
|
this.scheduleFrame();
|
|
@@ -2421,7 +2794,7 @@ export class NativeListWebEngine {
|
|
|
2421
2794
|
}, row);
|
|
2422
2795
|
return;
|
|
2423
2796
|
}
|
|
2424
|
-
const actionKey = row.type === 'action' ? row.actionKey : row.type === 'system' && row.variant === 'retry' ? row.actionKey : 'press';
|
|
2797
|
+
const actionKey = row.type === 'action' ? row.actionKey : row.type === 'system' && row.variant === 'retry' ? row.actionKey : row.type === 'market' && row.pressActionKey ? row.pressActionKey : 'press';
|
|
2425
2798
|
if (rowElement && sourceElement) {
|
|
2426
2799
|
const anchor = this.createActionAnchor(sourceElement, rowElement, 'row');
|
|
2427
2800
|
this.callbacks.onRowAction?.({
|
|
@@ -2434,6 +2807,47 @@ export class NativeListWebEngine {
|
|
|
2434
2807
|
this.emitRowAction(row, actionKey);
|
|
2435
2808
|
}
|
|
2436
2809
|
}
|
|
2810
|
+
cancelMarketPointer() {
|
|
2811
|
+
const state = this.marketPointer;
|
|
2812
|
+
if (!state) return;
|
|
2813
|
+
this.document.defaultView?.clearTimeout(state.timer);
|
|
2814
|
+
this.marketPointer = undefined;
|
|
2815
|
+
}
|
|
2816
|
+
handleMarketPointerDown = event => {
|
|
2817
|
+
if (event.button !== 0 || !(event.target instanceof Element)) return;
|
|
2818
|
+
this.marketLongPressFired = false;
|
|
2819
|
+
if (event.target.closest('[data-native-list-action]')) return;
|
|
2820
|
+
const rowElement = event.target.closest('[data-native-list-row-key]');
|
|
2821
|
+
const row = this.rowAtElement(rowElement);
|
|
2822
|
+
if (row?.type !== 'market' || row.disabled) return;
|
|
2823
|
+
this.cancelMarketPointer();
|
|
2824
|
+
if (row.pressInActionKey) this.emitRowAction(row, row.pressInActionKey, rowElement ?? undefined, rowElement ?? undefined);
|
|
2825
|
+
if (!row.longPressActionKey || !rowElement) return;
|
|
2826
|
+
markActionAnchorSource(rowElement, 'row');
|
|
2827
|
+
const timer = this.document.defaultView?.setTimeout(() => {
|
|
2828
|
+
const current = this.marketPointer;
|
|
2829
|
+
if (!current || current.pointerId !== event.pointerId) return;
|
|
2830
|
+
this.marketPointer = undefined;
|
|
2831
|
+
this.marketLongPressFired = true;
|
|
2832
|
+
this.emitRowAction(row, row.longPressActionKey, rowElement, rowElement);
|
|
2833
|
+
}, MARKET_LONG_PRESS_MS);
|
|
2834
|
+
if (timer === undefined) return;
|
|
2835
|
+
this.marketPointer = {
|
|
2836
|
+
pointerId: event.pointerId,
|
|
2837
|
+
rowKey: row.key,
|
|
2838
|
+
startX: event.clientX,
|
|
2839
|
+
startY: event.clientY,
|
|
2840
|
+
timer
|
|
2841
|
+
};
|
|
2842
|
+
};
|
|
2843
|
+
handleMarketPointerMove = event => {
|
|
2844
|
+
const state = this.marketPointer;
|
|
2845
|
+
if (!state || state.pointerId !== event.pointerId) return;
|
|
2846
|
+
if (Math.abs(event.clientX - state.startX) > MARKET_MOVE_CANCEL_PX || Math.abs(event.clientY - state.startY) > MARKET_MOVE_CANCEL_PX) this.cancelMarketPointer();
|
|
2847
|
+
};
|
|
2848
|
+
handleMarketPointerEnd = event => {
|
|
2849
|
+
if (this.marketPointer?.pointerId === event.pointerId) this.cancelMarketPointer();
|
|
2850
|
+
};
|
|
2437
2851
|
|
|
2438
2852
|
// OneKey patch: hover opens the same anchored help action as native taps.
|
|
2439
2853
|
handleTitlePointerOver = event => {
|
|
@@ -2456,7 +2870,8 @@ export class NativeListWebEngine {
|
|
|
2456
2870
|
if (this.actionAnchor?.actionElement === action) this.invalidateActionAnchor('pointerLeave');
|
|
2457
2871
|
};
|
|
2458
2872
|
handleClick = event => {
|
|
2459
|
-
if (Date.now() < this.suppressClickUntil) {
|
|
2873
|
+
if (this.marketLongPressFired || Date.now() < this.suppressClickUntil) {
|
|
2874
|
+
this.marketLongPressFired = false;
|
|
2460
2875
|
event.preventDefault();
|
|
2461
2876
|
event.stopPropagation();
|
|
2462
2877
|
return;
|
|
@@ -2581,6 +2996,7 @@ export class NativeListWebEngine {
|
|
|
2581
2996
|
});
|
|
2582
2997
|
}
|
|
2583
2998
|
handleScroll = () => {
|
|
2999
|
+
this.cancelMarketPointer();
|
|
2584
3000
|
this.invalidateActionAnchor('scroll');
|
|
2585
3001
|
this.scheduleFrame();
|
|
2586
3002
|
};
|
|
@@ -2607,50 +3023,42 @@ export class NativeListWebEngine {
|
|
|
2607
3023
|
const view = this.document.defaultView;
|
|
2608
3024
|
if (view?.cancelAnimationFrame) view.cancelAnimationFrame(handle);else view?.clearTimeout(handle);
|
|
2609
3025
|
}
|
|
2610
|
-
selectIndexPosition(position
|
|
3026
|
+
selectIndexPosition(position) {
|
|
3027
|
+
const activeKey = this.sectionIndexEntries.find(entry => entry.position === position)?.key;
|
|
3028
|
+
this.indexRail.querySelectorAll('[data-section-key]').forEach(button => setData(button, 'active', button.dataset.sectionKey === activeKey));
|
|
2611
3029
|
this.scrollToIndex(position, {
|
|
2612
3030
|
animated: false,
|
|
2613
3031
|
alignment: 'start',
|
|
2614
3032
|
viewPosition: 0,
|
|
2615
3033
|
viewOffset: 0
|
|
2616
3034
|
});
|
|
2617
|
-
const frame = this.viewportFrame.getBoundingClientRect();
|
|
2618
|
-
if (previewClientY !== undefined && frame.height > 0) {
|
|
2619
|
-
const previewY = Math.min(frame.height - 24, Math.max(24, previewClientY - frame.top));
|
|
2620
|
-
this.indexPreview.style.top = String(previewY) + 'px';
|
|
2621
|
-
} else {
|
|
2622
|
-
this.indexPreview.style.top = '50%';
|
|
2623
|
-
}
|
|
2624
|
-
this.indexPreview.textContent = title;
|
|
2625
|
-
setData(this.indexPreview, 'visible', true);
|
|
2626
|
-
if (this.previewTimer !== undefined) this.document.defaultView?.clearTimeout(this.previewTimer);
|
|
2627
|
-
this.previewTimer = this.document.defaultView?.setTimeout(() => {
|
|
2628
|
-
setData(this.indexPreview, 'visible', false);
|
|
2629
|
-
}, 180);
|
|
2630
3035
|
}
|
|
2631
3036
|
sectionIndexEntryAtEvent(event) {
|
|
2632
3037
|
const rail = this.indexRail.getBoundingClientRect();
|
|
2633
3038
|
if (this.sectionIndexEntries.length === 0 || rail.height <= 0) {
|
|
2634
3039
|
return undefined;
|
|
2635
3040
|
}
|
|
2636
|
-
const
|
|
2637
|
-
|
|
2638
|
-
const
|
|
2639
|
-
const
|
|
2640
|
-
return
|
|
2641
|
-
entry,
|
|
2642
|
-
previewClientY: event.clientY
|
|
2643
|
-
} : undefined;
|
|
3041
|
+
const metrics = this.sectionIndexMetrics(rail.height);
|
|
3042
|
+
if (metrics.trackHeight <= 0) return undefined;
|
|
3043
|
+
const progress = Math.min(1, Math.max(0, (event.clientY - rail.top - metrics.originY) / metrics.trackHeight));
|
|
3044
|
+
const entryIndex = Math.min(this.sectionIndexEntries.length - 1, Math.floor(progress * this.sectionIndexEntries.length));
|
|
3045
|
+
return this.sectionIndexEntries[entryIndex];
|
|
2644
3046
|
}
|
|
2645
3047
|
handleIndexPointer = event => {
|
|
2646
3048
|
if (event.type === 'pointermove' && event.buttons === 0) return;
|
|
2647
|
-
const
|
|
2648
|
-
if (!
|
|
3049
|
+
const entry = this.sectionIndexEntryAtEvent(event);
|
|
3050
|
+
if (!entry) return;
|
|
2649
3051
|
event.preventDefault();
|
|
2650
3052
|
if (event.type === 'pointerdown') {
|
|
2651
3053
|
this.indexRail.setPointerCapture?.(event.pointerId);
|
|
2652
3054
|
}
|
|
2653
|
-
this.selectIndexPosition(
|
|
3055
|
+
this.selectIndexPosition(entry.position);
|
|
3056
|
+
};
|
|
3057
|
+
handleIndexPointerEnd = event => {
|
|
3058
|
+
if (event.type === 'pointerup') {
|
|
3059
|
+
const entry = this.sectionIndexEntryAtEvent(event);
|
|
3060
|
+
if (entry) this.selectIndexPosition(entry.position);
|
|
3061
|
+
}
|
|
2654
3062
|
};
|
|
2655
3063
|
handleIndexClick = event => {
|
|
2656
3064
|
if ('detail' in event && typeof event.detail === 'number' && event.detail > 0) return;
|
|
@@ -2660,8 +3068,7 @@ export class NativeListWebEngine {
|
|
|
2660
3068
|
if (!button) return;
|
|
2661
3069
|
const entry = this.sectionIndexEntries[Number(button.dataset.sectionEntryIndex)];
|
|
2662
3070
|
if (!entry) return;
|
|
2663
|
-
|
|
2664
|
-
this.selectIndexPosition(entry.position, entry.title, rect.top + rect.height / 2);
|
|
3071
|
+
this.selectIndexPosition(entry.position);
|
|
2665
3072
|
};
|
|
2666
3073
|
handlePullStart = event => {
|
|
2667
3074
|
if (this.pointerReorder?.pointerId === event.pointerId || !this.snapshot.capabilities?.pullToRefresh || this.viewport.scrollTop > 0 || event.pointerType !== 'touch' && event.pointerType !== 'pen') return;
|
|
@@ -2816,7 +3223,9 @@ export class NativeListWebEngine {
|
|
|
2816
3223
|
setCurrentOffset(offset) {
|
|
2817
3224
|
const maximum = Math.max(0, this.contentLength() - this.viewportLength());
|
|
2818
3225
|
const next = Math.max(0, Math.min(maximum, offset));
|
|
2819
|
-
if (this.layout.horizontal) this.viewport.scrollLeft = next;else
|
|
3226
|
+
if (this.layout.horizontal) this.viewport.scrollLeft = next;else {
|
|
3227
|
+
this.viewport.scrollTop = resolveWebCollapsiblePagerRawOffset(next, this.collapsiblePagerInsets().header);
|
|
3228
|
+
}
|
|
2820
3229
|
this.scheduleFrame();
|
|
2821
3230
|
}
|
|
2822
3231
|
showReorderPreview(state) {
|
|
@@ -2867,8 +3276,9 @@ export class NativeListWebEngine {
|
|
|
2867
3276
|
}
|
|
2868
3277
|
this.reorderSettlingKey = state.sourceKey;
|
|
2869
3278
|
const viewportRect = this.viewport.getBoundingClientRect();
|
|
3279
|
+
const insets = this.collapsiblePagerInsets();
|
|
2870
3280
|
const left = viewportRect.left + destinationLayout.x - this.viewport.scrollLeft;
|
|
2871
|
-
const top = viewportRect.top + destinationLayout.y - this.viewport.scrollTop;
|
|
3281
|
+
const top = viewportRect.top + destinationLayout.y + insets.header + insets.sticky - this.viewport.scrollTop;
|
|
2872
3282
|
this.reorderPreview.getBoundingClientRect();
|
|
2873
3283
|
this.reorderPreview.style.transition = 'transform ' + String(REORDER_DROP_TRANSITION_MS) + 'ms ' + WEB_REORDER_ANIMATION.dropTimingFunction + ', box-shadow ' + String(REORDER_DROP_TRANSITION_MS) + 'ms ' + WEB_REORDER_ANIMATION.dropTimingFunction;
|
|
2874
3284
|
this.reorderPreview.style.boxShadow = 'none';
|