@onekeyfe/react-native-native-list 3.0.157-alpha.249 → 3.0.157-alpha.251
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 +21 -5
- package/android/src/main/java/com/onekey/nativelist/NativeListAccessoryStack.kt +711 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListActionRenderer.kt +169 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListActivityRenderer.kt +243 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListAdapter.kt +20 -6
- package/android/src/main/java/com/onekey/nativelist/NativeListDataRowRenderer.kt +487 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListIdentityRenderer.kt +820 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListImageSlot.kt +147 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListLeadingVisual.kt +453 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListMarketRenderer.kt +997 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListMediaTileRenderer.kt +234 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListMessageRenderer.kt +232 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListMetricCardRenderer.kt +551 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListModels.kt +24 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListPrimitives.kt +475 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRailRenderer.kt +143 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRendererRegistry.kt +42 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRendererRowView.kt +415 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListResolvedText.kt +163 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRowHost.kt +70 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListSectionHeaderRenderer.kt +748 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListSystemRenderer.kt +464 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListTextView.kt +25 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +174 -104
- package/android/src/main/java/com/onekey/nativelist/NativeListWalletGroupRenderer.kt +407 -0
- package/android/src/test/java/com/margelo/nitro/nativelist/NativeListSelectorBackgroundColorTest.kt +34 -0
- package/docs/DESIGN.md +518 -9
- package/docs/MIGRATION_BASELINE.md +117 -0
- package/docs/ROW_TEMPLATES.md +359 -0
- package/docs/SPEC.md +358 -0
- package/docs/STYLE_SPEC.md +978 -0
- package/docs/images/list-capabilities.svg +39 -0
- package/docs/images/row-action.svg +17 -0
- package/docs/images/row-activity.svg +24 -0
- package/docs/images/row-data.svg +24 -0
- package/docs/images/row-identity.svg +25 -0
- package/docs/images/row-market.svg +23 -0
- package/docs/images/row-media-tile.svg +26 -0
- package/docs/images/row-message.svg +20 -0
- package/docs/images/row-metric-card.svg +33 -0
- package/docs/images/row-rail.svg +18 -0
- package/docs/images/row-section-header.svg +19 -0
- package/docs/images/row-style-regions.svg +30 -0
- package/docs/images/row-system.svg +30 -0
- package/docs/images/row-wallet-group.svg +26 -0
- package/ios/NativeListAccessoryStack.swift +680 -0
- package/ios/NativeListActionRenderer.swift +108 -0
- package/ios/NativeListActivityRenderer.swift +179 -0
- package/ios/NativeListDataRowRenderer.swift +444 -0
- package/ios/NativeListIdentityRenderer.swift +685 -0
- package/ios/NativeListImageSlot.swift +140 -0
- package/ios/NativeListLeadingVisual.swift +372 -0
- package/ios/NativeListMarketRenderer.swift +698 -0
- package/ios/NativeListMediaTileRenderer.swift +184 -0
- package/ios/NativeListMessageRenderer.swift +168 -0
- package/ios/NativeListMetricCardRenderer.swift +420 -0
- package/ios/NativeListModels.swift +32 -0
- package/ios/NativeListRailRenderer.swift +152 -0
- package/ios/NativeListRendererCell.swift +311 -0
- package/ios/NativeListRendererRegistry.swift +50 -0
- package/ios/NativeListResolvedText.swift +122 -0
- package/ios/NativeListRowHost.swift +63 -0
- package/ios/NativeListSectionHeaderRenderer.swift +708 -0
- package/ios/NativeListSystemRenderer.swift +568 -0
- package/ios/NativeListTextLabel.swift +42 -0
- package/ios/NativeListTextStyles.swift +236 -0
- package/ios/NativeListWalletGroupRenderer.swift +255 -0
- package/ios/RNCNativeListView.swift +111 -180
- package/lib/module/models.js +54 -0
- package/lib/module/validation.js +324 -26
- package/lib/module/web/NativeListWebEngine.js +148 -936
- package/lib/module/web/templates/ActionRowRenderer.js +97 -0
- package/lib/module/web/templates/ActivityRowRenderer.js +95 -0
- package/lib/module/web/templates/DataRowRenderer.js +145 -0
- package/lib/module/web/templates/IdentityRowRenderer.js +289 -0
- package/lib/module/web/templates/MarketRowRenderer.js +310 -0
- package/lib/module/web/templates/MediaTileRowRenderer.js +132 -0
- package/lib/module/web/templates/MessageRowRenderer.js +165 -0
- package/lib/module/web/templates/MetricCardRowRenderer.js +172 -0
- package/lib/module/web/templates/RailRowRenderer.js +98 -0
- package/lib/module/web/templates/RowContainerStyle.js +100 -0
- package/lib/module/web/templates/RowElements.js +93 -0
- package/lib/module/web/templates/RowRendererRegistry.js +70 -0
- package/lib/module/web/templates/RowText.js +121 -0
- package/lib/module/web/templates/RowVisual.js +43 -0
- package/lib/module/web/templates/SectionHeaderRowRenderer.js +146 -0
- package/lib/module/web/templates/SystemRowRenderer.js +161 -0
- package/lib/module/web/templates/WalletGroupRowRenderer.js +96 -0
- package/lib/typescript/src/models.d.ts +166 -13
- package/lib/typescript/src/web/NativeListWebEngine.d.ts +18 -16
- package/lib/typescript/src/web/templates/ActionRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/ActivityRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/DataRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/IdentityRowRenderer.d.ts +16 -0
- package/lib/typescript/src/web/templates/MarketRowRenderer.d.ts +30 -0
- package/lib/typescript/src/web/templates/MediaTileRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/MessageRowRenderer.d.ts +44 -0
- package/lib/typescript/src/web/templates/MetricCardRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/RailRowRenderer.d.ts +28 -0
- package/lib/typescript/src/web/templates/RowContainerStyle.d.ts +9 -0
- package/lib/typescript/src/web/templates/RowElements.d.ts +38 -0
- package/lib/typescript/src/web/templates/RowRendererRegistry.d.ts +83 -0
- package/lib/typescript/src/web/templates/RowText.d.ts +9 -0
- package/lib/typescript/src/web/templates/RowVisual.d.ts +20 -0
- package/lib/typescript/src/web/templates/SectionHeaderRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/SystemRowRenderer.d.ts +16 -0
- package/lib/typescript/src/web/templates/WalletGroupRowRenderer.d.ts +20 -0
- package/package.json +3 -3
- package/src/models.ts +281 -19
- package/src/validation.ts +501 -46
- package/src/web/NativeListWebEngine.ts +361 -1932
- package/src/web/templates/ActionRowRenderer.ts +123 -0
- package/src/web/templates/ActivityRowRenderer.ts +159 -0
- package/src/web/templates/DataRowRenderer.ts +212 -0
- package/src/web/templates/IdentityRowRenderer.ts +527 -0
- package/src/web/templates/MarketRowRenderer.ts +467 -0
- package/src/web/templates/MediaTileRowRenderer.ts +182 -0
- package/src/web/templates/MessageRowRenderer.ts +306 -0
- package/src/web/templates/MetricCardRowRenderer.ts +337 -0
- package/src/web/templates/RailRowRenderer.ts +136 -0
- package/src/web/templates/RowContainerStyle.ts +131 -0
- package/src/web/templates/RowElements.ts +160 -0
- package/src/web/templates/RowRendererRegistry.ts +111 -0
- package/src/web/templates/RowText.ts +181 -0
- package/src/web/templates/RowVisual.ts +115 -0
- package/src/web/templates/SectionHeaderRowRenderer.ts +243 -0
- package/src/web/templates/SystemRowRenderer.ts +282 -0
- package/src/web/templates/WalletGroupRowRenderer.ts +131 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRowView.kt +0 -4538
- package/ios/NativeListCell.swift +0 -4300
|
@@ -7,7 +7,7 @@ final class NativeListView: UIView {
|
|
|
7
7
|
private final class ActionAnchorRecord {
|
|
8
8
|
let token: String
|
|
9
9
|
weak var sourceView: UIView?
|
|
10
|
-
weak var ownerCell:
|
|
10
|
+
weak var ownerCell: NativeListRowHost?
|
|
11
11
|
let bindingEpoch: Int
|
|
12
12
|
var open = false
|
|
13
13
|
var invalidatedReason: String?
|
|
@@ -62,7 +62,8 @@ final class NativeListView: UIView {
|
|
|
62
62
|
private let flowLayout = NativeListFlowLayout()
|
|
63
63
|
private lazy var collectionView = NativeListCollectionView(frame: .zero, collectionViewLayout: flowLayout)
|
|
64
64
|
private let footerContainer = UIView()
|
|
65
|
-
private
|
|
65
|
+
private var footerCell: NativeListRowHost = NativeListRendererRegistry.create(.action)
|
|
66
|
+
private var footerRendererKey = NativeListRendererKey.action
|
|
66
67
|
private let sectionIndexView = NativeListSectionIndexView()
|
|
67
68
|
private let sectionIndexPreview = NativeListSectionIndexPreviewView()
|
|
68
69
|
private var sectionIndexLayoutConstraints: [NSLayoutConstraint] = []
|
|
@@ -102,13 +103,13 @@ final class NativeListView: UIView {
|
|
|
102
103
|
private var keyboardDismissMode: NativeListKeyboardDismissMode = .none
|
|
103
104
|
private var keyboardShouldPersistTaps: NativeListKeyboardShouldPersistTaps = .never
|
|
104
105
|
private var interactiveReorderSource: (key: String, index: Int)?
|
|
105
|
-
private weak var interactiveReorderCell:
|
|
106
|
+
private weak var interactiveReorderCell: NativeListRowHost?
|
|
106
107
|
private var interactiveReorderCompactKey: String?
|
|
107
108
|
private var interactiveReorderUsesAtomicTargeting = false
|
|
108
109
|
private var interactiveReorderTargetIndex: Int?
|
|
109
110
|
private var interactiveReorderTargetKey: String?
|
|
110
111
|
private var interactiveReorderLockedCrossAxisPosition: CGFloat?
|
|
111
|
-
private var interactiveReorderTransformedCells: [
|
|
112
|
+
private var interactiveReorderTransformedCells: [NativeListRowHost] = []
|
|
112
113
|
private var deferredReorderReconfigureKeys = Set<String>()
|
|
113
114
|
private let interactiveReorderPlaceholder = UIView()
|
|
114
115
|
private var interactiveReorderAnimator: UIViewPropertyAnimator?
|
|
@@ -129,7 +130,7 @@ final class NativeListView: UIView {
|
|
|
129
130
|
|
|
130
131
|
override init(frame: CGRect) {
|
|
131
132
|
super.init(frame: frame)
|
|
132
|
-
|
|
133
|
+
NativeListRendererRegistry.register(in: collectionView)
|
|
133
134
|
collectionView.backgroundColor = .clear
|
|
134
135
|
collectionView.delegate = self
|
|
135
136
|
collectionView.dragDelegate = self
|
|
@@ -228,9 +229,9 @@ final class NativeListView: UIView {
|
|
|
228
229
|
guard let self,
|
|
229
230
|
let item = self.itemsByKey[key],
|
|
230
231
|
let cell = collectionView.dequeueReusableCell(
|
|
231
|
-
withReuseIdentifier:
|
|
232
|
+
withReuseIdentifier: NativeListRendererRegistry.reuseIdentifier(for: item.rendererKey),
|
|
232
233
|
for: indexPath
|
|
233
|
-
) as?
|
|
234
|
+
) as? NativeListRowHost else { return nil }
|
|
234
235
|
cell.onAction = { [weak self] item, action, target, origin in
|
|
235
236
|
self?.handleAction(item: item, actionKey: action, target: target, origin: origin)
|
|
236
237
|
}
|
|
@@ -329,10 +330,38 @@ final class NativeListView: UIView {
|
|
|
329
330
|
lastLayoutSize = bounds.size
|
|
330
331
|
if lastLayoutDirection != direction, let config {
|
|
331
332
|
configureLayout(config)
|
|
333
|
+
rebindRowsForLayoutDirection(config)
|
|
332
334
|
}
|
|
333
335
|
performPendingScrollIfNeeded()
|
|
334
336
|
}
|
|
335
337
|
|
|
338
|
+
// A layout-direction change may arrive without a layout pass (semantic attribute or trait).
|
|
339
|
+
override var semanticContentAttribute: UISemanticContentAttribute {
|
|
340
|
+
didSet { if semanticContentAttribute != oldValue { setNeedsLayout() } }
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
|
344
|
+
super.traitCollectionDidChange(previousTraitCollection)
|
|
345
|
+
if previousTraitCollection?.layoutDirection != traitCollection.layoutDirection {
|
|
346
|
+
setNeedsLayout()
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/// Renderers resolve start/end alignment at bind time, and the layout direction is one of a
|
|
351
|
+
/// cell's bound inputs; rebinding visible rows and the footer re-resolves it. A cell whose
|
|
352
|
+
/// bound direction already matches only refreshes selection and appearance. Offscreen rows
|
|
353
|
+
/// rebind when they are next dequeued.
|
|
354
|
+
private func rebindRowsForLayoutDirection(_ config: NativeListConfig) {
|
|
355
|
+
for case let cell as NativeListRowHost in collectionView.visibleCells {
|
|
356
|
+
guard let indexPath = collectionView.indexPath(for: cell),
|
|
357
|
+
let item = item(at: indexPath) else { continue }
|
|
358
|
+
bind(cell: cell, item: item, itemIndex: indexPath.item)
|
|
359
|
+
}
|
|
360
|
+
if let footer = config.fixedFooter, !footerCell.isHidden {
|
|
361
|
+
bind(cell: footerCell, item: footer, itemIndex: nil)
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
336
365
|
func applySnapshotJson(_ json: String) {
|
|
337
366
|
guard let next = try? NativeListConfig.parse(json: json) else { return }
|
|
338
367
|
invalidateActionAnchor(reason: "snapshot")
|
|
@@ -352,7 +381,10 @@ final class NativeListView: UIView {
|
|
|
352
381
|
cancelInteractiveReorderForStructuralUpdate()
|
|
353
382
|
}
|
|
354
383
|
let oldItems = itemsByKey
|
|
384
|
+
// Chrome lives outside the row payload, so a changed list style must rebind
|
|
385
|
+
// rows whose own content is unchanged.
|
|
355
386
|
let themeChanged = !dictionariesEqual(config?.theme, next.theme)
|
|
387
|
+
|| !dictionariesEqual(config?.listStyle, next.listStyle)
|
|
356
388
|
if config?.generation != next.generation { endReachedGeneration = nil }
|
|
357
389
|
config = next
|
|
358
390
|
itemsByKey = Dictionary(uniqueKeysWithValues: next.items.map { ($0.key, $0) })
|
|
@@ -371,7 +403,13 @@ final class NativeListView: UIView {
|
|
|
371
403
|
})
|
|
372
404
|
changedKeys.formUnion(deferredReorderReconfigureKeys)
|
|
373
405
|
deferredReorderReconfigureKeys.removeAll()
|
|
374
|
-
|
|
406
|
+
let retainedKeys = Set(dataSource.snapshot().itemIdentifiers).intersection(keys)
|
|
407
|
+
let changedRetainedKeys = changedKeys.filter { retainedKeys.contains($0) }
|
|
408
|
+
// Reconfigure must keep its existing reuse identifier. A same-key renderer
|
|
409
|
+
// change needs reload so UIKit dequeues from the new structural pool.
|
|
410
|
+
let replacedKeys = changedRetainedKeys.filter { oldItems[$0]?.rendererKey != itemsByKey[$0]?.rendererKey }
|
|
411
|
+
snapshot.reloadItems(Array(replacedKeys))
|
|
412
|
+
snapshot.reconfigureItems(Array(changedRetainedKeys.subtracting(replacedKeys)))
|
|
375
413
|
dataSource.apply(snapshot, animatingDifferences: false) { [weak self] in
|
|
376
414
|
guard let self else { return }
|
|
377
415
|
self.collectionView.layoutIfNeeded()
|
|
@@ -444,7 +482,7 @@ final class NativeListView: UIView {
|
|
|
444
482
|
for indexPath in collectionView.indexPathsForVisibleItems {
|
|
445
483
|
guard let item = item(at: indexPath),
|
|
446
484
|
marketQuoteKeys.contains(item.key),
|
|
447
|
-
let cell = collectionView.cellForItem(at: indexPath) as?
|
|
485
|
+
let cell = collectionView.cellForItem(at: indexPath) as? NativeListRowHost else { continue }
|
|
448
486
|
cell.updateMarketQuote(item, theme: current.theme)
|
|
449
487
|
}
|
|
450
488
|
if changedKeys.isEmpty {
|
|
@@ -685,7 +723,7 @@ final class NativeListView: UIView {
|
|
|
685
723
|
let indexPath = collectionView.indexPathForItem(at: point),
|
|
686
724
|
let item = item(at: indexPath),
|
|
687
725
|
item.isReorderable,
|
|
688
|
-
let cell = collectionView.cellForItem(at: indexPath) as?
|
|
726
|
+
let cell = collectionView.cellForItem(at: indexPath) as? NativeListRowHost,
|
|
689
727
|
cell.canStartWalletGroupReorder(at: gesture.location(in: cell)) else {
|
|
690
728
|
interactiveReorderSource = nil
|
|
691
729
|
interactiveReorderCell = nil
|
|
@@ -981,9 +1019,9 @@ final class NativeListView: UIView {
|
|
|
981
1019
|
animator.startAnimation()
|
|
982
1020
|
}
|
|
983
1021
|
|
|
984
|
-
private func walletGroupCell(for key: String) ->
|
|
1022
|
+
private func walletGroupCell(for key: String) -> NativeListRowHost? {
|
|
985
1023
|
guard let index = dataSource.snapshot().indexOfItem(key) else { return nil }
|
|
986
|
-
return collectionView.cellForItem(at: IndexPath(item: index, section: 0)) as?
|
|
1024
|
+
return collectionView.cellForItem(at: IndexPath(item: index, section: 0)) as? NativeListRowHost
|
|
987
1025
|
}
|
|
988
1026
|
|
|
989
1027
|
// OneKey patch: flow layout sizes an interactive move in UIKit's in-flight order,
|
|
@@ -1017,7 +1055,7 @@ final class NativeListView: UIView {
|
|
|
1017
1055
|
let distance = CGFloat(68) + flowLayout.minimumLineSpacing
|
|
1018
1056
|
let updates = { [weak self] in
|
|
1019
1057
|
guard let self else { return }
|
|
1020
|
-
for case let cell as
|
|
1058
|
+
for case let cell as NativeListRowHost in self.collectionView.visibleCells {
|
|
1021
1059
|
guard let indexPath = self.collectionView.indexPath(for: cell),
|
|
1022
1060
|
indexPath.item != source.index else { continue }
|
|
1023
1061
|
let offset: CGFloat
|
|
@@ -1286,8 +1324,14 @@ final class NativeListView: UIView {
|
|
|
1286
1324
|
|
|
1287
1325
|
private func syncSectionIndexToVisibleRows() {
|
|
1288
1326
|
guard !sectionIndexScrubbing, !sectionIndexEntries.isEmpty else { return }
|
|
1289
|
-
let
|
|
1290
|
-
|
|
1327
|
+
let offset = collectionView.contentOffset.y + collectionView.adjustedContentInset.top
|
|
1328
|
+
// Legacy semantics: a header at the first position is active even while overscrolled;
|
|
1329
|
+
// no entry is active while rows above the first header are still visible.
|
|
1330
|
+
let index = sectionIndexEntries.lastIndex {
|
|
1331
|
+
if $0.position == 0 { return true }
|
|
1332
|
+
guard let attributes = flowLayout.layoutAttributesForItem(at: IndexPath(item: $0.position, section: 0)) else { return false }
|
|
1333
|
+
return attributes.frame.minY <= offset + 1
|
|
1334
|
+
}
|
|
1291
1335
|
sectionIndexView.setActiveIndex(index)
|
|
1292
1336
|
}
|
|
1293
1337
|
|
|
@@ -1311,13 +1355,27 @@ final class NativeListView: UIView {
|
|
|
1311
1355
|
footerCell.isHidden = true
|
|
1312
1356
|
return
|
|
1313
1357
|
}
|
|
1358
|
+
if footer.rendererKey != footerRendererKey {
|
|
1359
|
+
let previous = footerCell
|
|
1360
|
+
previous.prepareForReuse()
|
|
1361
|
+
footerCell = NativeListRendererRegistry.create(footer.rendererKey)
|
|
1362
|
+
footerCell.onAction = previous.onAction
|
|
1363
|
+
footerCell.onBindingInvalidated = previous.onBindingInvalidated
|
|
1364
|
+
for recognizer in previous.gestureRecognizers ?? [] { footerCell.addGestureRecognizer(recognizer) }
|
|
1365
|
+
previous.removeFromSuperview()
|
|
1366
|
+
footerContainer.addSubview(footerCell)
|
|
1367
|
+
footerCell.frame = footerContainer.bounds
|
|
1368
|
+
footerCell.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
1369
|
+
footerRendererKey = footer.rendererKey
|
|
1370
|
+
}
|
|
1314
1371
|
footerCell.isHidden = false
|
|
1315
1372
|
footerHeightConstraint.constant = rowHeight(footer)
|
|
1316
1373
|
bind(cell: footerCell, item: footer, itemIndex: nil)
|
|
1317
1374
|
}
|
|
1318
1375
|
|
|
1319
|
-
private func bind(cell:
|
|
1376
|
+
private func bind(cell: NativeListRowHost, item: NativeListItem, itemIndex: Int? = nil) {
|
|
1320
1377
|
guard let config else { return }
|
|
1378
|
+
cell.listStyle = config.listStyle
|
|
1321
1379
|
cell.bind(
|
|
1322
1380
|
item: item,
|
|
1323
1381
|
theme: config.theme,
|
|
@@ -1360,7 +1418,7 @@ final class NativeListView: UIView {
|
|
|
1360
1418
|
item.isRowPressEnabled else { return }
|
|
1361
1419
|
let actionKey = item.data.string("longPressActionKey")
|
|
1362
1420
|
guard !actionKey.isEmpty else { return }
|
|
1363
|
-
let origin = (collectionView.cellForItem(at: indexPath) as?
|
|
1421
|
+
let origin = (collectionView.cellForItem(at: indexPath) as? NativeListRowHost)?.rowActionOrigin()
|
|
1364
1422
|
origin?.windowPoint = gesture.location(in: window)
|
|
1365
1423
|
handleAction(item: item, actionKey: actionKey, target: nil, origin: origin)
|
|
1366
1424
|
}
|
|
@@ -1442,7 +1500,7 @@ final class NativeListView: UIView {
|
|
|
1442
1500
|
}
|
|
1443
1501
|
for indexPath in collectionView.indexPathsForVisibleItems {
|
|
1444
1502
|
guard let item = item(at: indexPath),
|
|
1445
|
-
let cell = collectionView.cellForItem(at: indexPath) as?
|
|
1503
|
+
let cell = collectionView.cellForItem(at: indexPath) as? NativeListRowHost else { continue }
|
|
1446
1504
|
if changedSummaryKeys.contains(item.key) {
|
|
1447
1505
|
bind(cell: cell, item: item, itemIndex: indexPath.item)
|
|
1448
1506
|
continue
|
|
@@ -1470,6 +1528,7 @@ final class NativeListView: UIView {
|
|
|
1470
1528
|
current.layout == next.layout,
|
|
1471
1529
|
current.orientation == next.orientation,
|
|
1472
1530
|
current.gridColumns == next.gridColumns,
|
|
1531
|
+
dictionariesEqual(current.listStyle, next.listStyle),
|
|
1473
1532
|
current.stickyHeaders == next.stickyHeaders,
|
|
1474
1533
|
current.contentPadding == next.contentPadding,
|
|
1475
1534
|
current.contentPaddingHorizontal == next.contentPaddingHorizontal,
|
|
@@ -1517,6 +1576,7 @@ final class NativeListView: UIView {
|
|
|
1517
1576
|
guard current.layout == next.layout,
|
|
1518
1577
|
current.orientation == next.orientation,
|
|
1519
1578
|
current.gridColumns == next.gridColumns,
|
|
1579
|
+
dictionariesEqual(current.listStyle, next.listStyle),
|
|
1520
1580
|
current.stickyHeaders == next.stickyHeaders,
|
|
1521
1581
|
current.contentPadding == next.contentPadding,
|
|
1522
1582
|
current.contentPaddingHorizontal == next.contentPaddingHorizontal,
|
|
@@ -1670,149 +1730,29 @@ final class NativeListView: UIView {
|
|
|
1670
1730
|
|
|
1671
1731
|
private func rowHeight(
|
|
1672
1732
|
_ item: NativeListItem,
|
|
1673
|
-
usingCompactReorderHeight: Bool = true
|
|
1733
|
+
usingCompactReorderHeight: Bool = true,
|
|
1734
|
+
allocatedWidth: CGFloat? = nil
|
|
1674
1735
|
) -> CGFloat {
|
|
1675
1736
|
// OneKey patch: honor selector baseline geometry; keep compact drag sizing.
|
|
1676
|
-
if item.type
|
|
1677
|
-
if
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
let textWidth = max(1, collectionView.bounds.width - (config?.contentPaddingHorizontal ?? 0) * 2 - 24)
|
|
1683
|
-
func textHeight(_ key: String, weight: NativeListFontWeight) -> CGFloat {
|
|
1684
|
-
let paragraph = NSMutableParagraphStyle()
|
|
1685
|
-
paragraph.minimumLineHeight = 20
|
|
1686
|
-
paragraph.maximumLineHeight = 20
|
|
1687
|
-
return ceil((item.data.string(key) as NSString).boundingRect(with: CGSize(width: textWidth, height: .greatestFiniteMagnitude), options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [.font: nativeListFont(ofSize: 14, weight: weight), .paragraphStyle: paragraph], context: nil).height / 20) * 20
|
|
1688
|
-
}
|
|
1689
|
-
return 32 + textHeight("title", weight: .medium) + textHeight("message", weight: .regular)
|
|
1690
|
-
}
|
|
1691
|
-
if item.type == "walletGroup" {
|
|
1692
|
-
if usingCompactReorderHeight, item.key == interactiveReorderCompactKey { return 68 }
|
|
1693
|
-
let childCount = item.data.dictionaries("children").count
|
|
1694
|
-
// OneKey patch: wallet badges contribute their own member heights.
|
|
1695
|
-
// return CGFloat((childCount + 1) * 68 + childCount * 12)
|
|
1696
|
-
let members = [item.data.dictionary("parent")].compactMap { $0 } + item.data.dictionaries("children")
|
|
1697
|
-
return members.reduce(CGFloat(childCount * 12 + (members.first?["height"] != nil ? 2 : 0))) { total, data in
|
|
1698
|
-
total + CGFloat(data.double("height", default: data.dictionaries("badges").isEmpty ? 68 : 92))
|
|
1699
|
-
}
|
|
1737
|
+
if item.type == "walletGroup", usingCompactReorderHeight, item.key == interactiveReorderCompactKey { return 68 }
|
|
1738
|
+
if let height = item.styledHeight { return height }
|
|
1739
|
+
// Legacy WalletGroup ignored `row.height` (its height comes from its members);
|
|
1740
|
+
// `style.container.height` above still wins.
|
|
1741
|
+
if item.type != "walletGroup", item.data["height"] != nil {
|
|
1742
|
+
return CGFloat(item.data.double("height"))
|
|
1700
1743
|
}
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
if
|
|
1707
|
-
return
|
|
1708
|
-
}
|
|
1709
|
-
let base: CGFloat
|
|
1710
|
-
switch item.type {
|
|
1711
|
-
case "rail": base = 40
|
|
1712
|
-
case "activity": base = item.data.dictionaries("footerActions").isEmpty ? 60 : 100
|
|
1713
|
-
case "message": base = messageHeight(item)
|
|
1714
|
-
case "mediaTile": base = 244
|
|
1715
|
-
case "metricCard":
|
|
1716
|
-
base = item.data.string("variant") == "activity"
|
|
1717
|
-
? 160 + 1 / UIScreen.main.scale
|
|
1718
|
-
: item.data.string("variant") == "performance" ? 178 : 132
|
|
1719
|
-
case "sectionHeader":
|
|
1720
|
-
let variant = item.data.string("variant")
|
|
1721
|
-
let isNetworkSelector = item.data.string("presentation") == "networkSelector"
|
|
1722
|
-
let isHistory = variant == "history" ||
|
|
1723
|
-
item.key.hasPrefix("history-") ||
|
|
1724
|
-
(item.sectionKey?.hasPrefix("history-") ?? false)
|
|
1725
|
-
base = config?.layout == "table"
|
|
1726
|
-
? 28
|
|
1727
|
-
: isNetworkSelector
|
|
1728
|
-
? 47
|
|
1729
|
-
: isHistory
|
|
1730
|
-
? 16
|
|
1731
|
-
: variant == "summary"
|
|
1732
|
-
? 68
|
|
1733
|
-
: variant == "gallery"
|
|
1734
|
-
? 32
|
|
1735
|
-
: item.data.dictionary("checkbox") != nil
|
|
1736
|
-
? 56
|
|
1737
|
-
: config?.layout == "linear" ? 30 : 36
|
|
1738
|
-
case "system":
|
|
1739
|
-
if item.data.string("variant") == "loading" && item.data.string("loadingStyle") == "skeleton" {
|
|
1740
|
-
base = 56
|
|
1741
|
-
} else if item.data.string("variant") == "loading" && item.data.string("loadingStyle") == "spinner" {
|
|
1742
|
-
base = 52
|
|
1743
|
-
} else if item.data.string("presentation") == "market" {
|
|
1744
|
-
base = item.data.string("variant") == "loading" ? 68 : 44
|
|
1745
|
-
} else {
|
|
1746
|
-
switch item.data.string("variant") {
|
|
1747
|
-
case "noMatch", "end": base = 36
|
|
1748
|
-
case "retry": base = 44
|
|
1749
|
-
default: base = 56
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
case "action":
|
|
1753
|
-
base = item.data.string("presentation") == "accountSelector"
|
|
1754
|
-
? 48
|
|
1755
|
-
: item.data.dictionary("icon") == nil ? 44 : 60
|
|
1756
|
-
case "dataRow":
|
|
1757
|
-
base = item.data.dictionaries("columns").contains {
|
|
1758
|
-
!$0.string("secondaryText").isEmpty
|
|
1759
|
-
} ? 60 : 56
|
|
1760
|
-
case "market":
|
|
1761
|
-
let style = item.data.dictionary("style")
|
|
1762
|
-
let imageHeight = CGFloat(style?.dictionary("image")?.double(
|
|
1763
|
-
"height",
|
|
1764
|
-
default: item.data.string("variant") == "stock" ? 40 : 32
|
|
1765
|
-
) ?? (item.data.string("variant") == "stock" ? 40 : 32))
|
|
1766
|
-
let verticalPadding = CGFloat(style?.double("verticalPadding", default: 12) ?? 12)
|
|
1767
|
-
base = max(item.data.string("variant") == "stock" ? 72 : 68, imageHeight + verticalPadding * 2)
|
|
1768
|
-
default:
|
|
1769
|
-
if item.type == "identity", !item.data.string("tertiary").isEmpty {
|
|
1770
|
-
base = 72
|
|
1771
|
-
} else if item.type == "identity", !item.data.string("subtitle").isEmpty {
|
|
1772
|
-
base = 60
|
|
1773
|
-
} else {
|
|
1774
|
-
base = 56
|
|
1775
|
-
}
|
|
1744
|
+
let availableWidth = max(0, collectionView.bounds.width - flowLayout.sectionInset.left - flowLayout.sectionInset.right)
|
|
1745
|
+
let columnWidth = config?.layout == "grid"
|
|
1746
|
+
? floor((availableWidth - CGFloat((config?.gridColumns ?? 2) - 1) * (config?.itemSpacing ?? 0)) / CGFloat(config?.gridColumns ?? 2))
|
|
1747
|
+
: availableWidth
|
|
1748
|
+
let rowWidth = allocatedWidth ?? (config?.orientation == "horizontal" ? 280 : columnWidth)
|
|
1749
|
+
if let height = NativeListRendererRegistry.measure(item, width: rowWidth, theme: config?.theme, layout: config?.layout ?? "linear") {
|
|
1750
|
+
return max(0, height + (NativeListRendererRegistry.appliesSizePreset(item) ? (item.data.string("size") == "small" ? -8 : item.data.string("size") == "large" ? 12 : 0) : 0))
|
|
1776
1751
|
}
|
|
1777
|
-
|
|
1778
|
-
["summary", "gallery"].contains(item.data.string("variant"))
|
|
1779
|
-
let modifier: CGFloat = hasFixedHeaderHeight
|
|
1780
|
-
? 0
|
|
1781
|
-
: item.data.string("size", default: "medium") == "small"
|
|
1782
|
-
? -8
|
|
1783
|
-
: item.data.string("size") == "large" ? 12 : 0
|
|
1784
|
-
let sectionSpacing: CGFloat = 0
|
|
1785
|
-
let tableAdjustment: CGFloat = config?.layout == "table" &&
|
|
1786
|
-
item.type == "dataRow" &&
|
|
1787
|
-
!item.data.dictionaries("columns").contains(where: { !$0.string("secondaryText").isEmpty })
|
|
1788
|
-
? -8
|
|
1789
|
-
: 0
|
|
1790
|
-
return max(0, base + modifier + sectionSpacing + tableAdjustment)
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
private func messageHeight(_ item: NativeListItem) -> CGFloat {
|
|
1794
|
-
let maximumBodyLines = min(3, max(1, item.data.int("bodyLines", default: 3)))
|
|
1795
|
-
let horizontalInsets = (config?.contentPaddingHorizontal ?? 0) * 2 + 40
|
|
1796
|
-
let leadingWidth: CGFloat = item.data.dictionary("leading") == nil ? 0 : 40
|
|
1797
|
-
let thumbnailWidth: CGFloat = item.data.dictionary("thumbnail") == nil ? 0 : 76
|
|
1798
|
-
let textWidth = max(1, collectionView.bounds.width - horizontalInsets - leadingWidth - thumbnailWidth)
|
|
1799
|
-
let bodyBounds = (item.data.string("body") as NSString).boundingRect(
|
|
1800
|
-
with: CGSize(width: textWidth, height: .greatestFiniteMagnitude),
|
|
1801
|
-
options: [.usesLineFragmentOrigin, .usesFontLeading],
|
|
1802
|
-
attributes: [.font: nativeListFont(ofSize: 14)],
|
|
1803
|
-
context: nil
|
|
1804
|
-
)
|
|
1805
|
-
let titleBounds = (item.data.string("title") as NSString).boundingRect(
|
|
1806
|
-
with: CGSize(width: textWidth, height: .greatestFiniteMagnitude),
|
|
1807
|
-
options: [.usesLineFragmentOrigin, .usesFontLeading],
|
|
1808
|
-
attributes: [.font: nativeListFont(ofSize: 14, weight: .semibold)],
|
|
1809
|
-
context: nil
|
|
1810
|
-
)
|
|
1811
|
-
let bodyLines = min(maximumBodyLines, max(1, Int(ceil(bodyBounds.height / 20))))
|
|
1812
|
-
let titleLines = min(2, max(1, Int(ceil(titleBounds.height / 20))))
|
|
1813
|
-
return 32 + CGFloat(titleLines * 20 + bodyLines * 20) + 22
|
|
1752
|
+
return 56
|
|
1814
1753
|
}
|
|
1815
1754
|
|
|
1755
|
+
|
|
1816
1756
|
private func emit(_ block: ((String) -> Void)?, _ value: [String: Any]) {
|
|
1817
1757
|
guard JSONSerialization.isValidJSONObject(value),
|
|
1818
1758
|
let data = try? JSONSerialization.data(withJSONObject: value),
|
|
@@ -1894,7 +1834,7 @@ final class NativeListView: UIView {
|
|
|
1894
1834
|
reorderLongPress.delegate = nil
|
|
1895
1835
|
marketLongPress.delegate = nil
|
|
1896
1836
|
|
|
1897
|
-
for case let cell as
|
|
1837
|
+
for case let cell as NativeListRowHost in collectionView.visibleCells {
|
|
1898
1838
|
cell.onAction = nil
|
|
1899
1839
|
cell.onBindingInvalidated = nil
|
|
1900
1840
|
cell.prepareForReuse()
|
|
@@ -1961,7 +1901,7 @@ final class NativeListView: UIView {
|
|
|
1961
1901
|
&& (sourceView === ownerCell.contentView || sourceView.isDescendant(of: ownerCell.contentView))
|
|
1962
1902
|
}
|
|
1963
1903
|
|
|
1964
|
-
private func handleBindingInvalidated(cell:
|
|
1904
|
+
private func handleBindingInvalidated(cell: NativeListRowHost, epoch: Int) {
|
|
1965
1905
|
guard let anchor = actionAnchor,
|
|
1966
1906
|
anchor.ownerCell === cell,
|
|
1967
1907
|
anchor.bindingEpoch == epoch else { return }
|
|
@@ -2158,7 +2098,8 @@ extension NativeListView: UICollectionViewDelegateFlowLayout {
|
|
|
2158
2098
|
if config.orientation == "horizontal" {
|
|
2159
2099
|
let width: CGFloat = item.type == "rail" ? railWidth(item) : item.type == "mediaTile" ? 200 : 280
|
|
2160
2100
|
let availableHeight = max(0, collectionView.bounds.height - insets.top - insets.bottom)
|
|
2161
|
-
let height = item.type == "
|
|
2101
|
+
let height = item.type == "walletGroup" && item.key == interactiveReorderCompactKey ? 68
|
|
2102
|
+
: item.styledHeight ?? (item.data["height"] != nil ? rowHeight(item) : item.type == "rail" ? min(rowHeight(item), availableHeight) : availableHeight)
|
|
2162
2103
|
return CGSize(width: width, height: height)
|
|
2163
2104
|
}
|
|
2164
2105
|
let available = max(0, collectionView.bounds.width - insets.left - insets.right)
|
|
@@ -2166,34 +2107,20 @@ extension NativeListView: UICollectionViewDelegateFlowLayout {
|
|
|
2166
2107
|
if config.layout == "grid", !structural {
|
|
2167
2108
|
let spacing = CGFloat(config.gridColumns - 1) * config.itemSpacing
|
|
2168
2109
|
let width = floor((available - spacing) / CGFloat(config.gridColumns))
|
|
2169
|
-
let height = item.type == "mediaTile" ? width + 48 : rowHeight(item)
|
|
2110
|
+
let height = item.styledHeight ?? (item.type == "mediaTile" && item.data["height"] == nil ? width + 48 : rowHeight(item, allocatedWidth: width))
|
|
2170
2111
|
return CGSize(width: width, height: height)
|
|
2171
2112
|
}
|
|
2172
|
-
return CGSize(width: available, height: rowHeight(item))
|
|
2113
|
+
return CGSize(width: available, height: rowHeight(item, allocatedWidth: available))
|
|
2173
2114
|
}
|
|
2174
2115
|
|
|
2175
2116
|
private func railWidth(_ item: NativeListItem) -> CGFloat {
|
|
2176
|
-
|
|
2177
|
-
withAttributes: [.font: nativeListFont(ofSize: 12, weight: .medium)]
|
|
2178
|
-
).width
|
|
2179
|
-
let badge = item.data.dictionary("badge")?.string("text") ?? ""
|
|
2180
|
-
let badgeWidth = (badge as NSString).size(
|
|
2181
|
-
withAttributes: [.font: nativeListTabularFont(ofSize: 12, weight: .medium)]
|
|
2182
|
-
).width
|
|
2183
|
-
let status = item.data.string("status")
|
|
2184
|
-
let statusWidth = status.isEmpty || status == "none" ? 0 : (status as NSString).size(
|
|
2185
|
-
withAttributes: [.font: nativeListTabularFont(ofSize: 12)]
|
|
2186
|
-
).width
|
|
2187
|
-
let visibleTextCount = 1 + (badgeWidth > 0 ? 1 : 0) + (statusWidth > 0 ? 1 : 0)
|
|
2188
|
-
let width = 4 + 20 + 6 + titleWidth + badgeWidth + statusWidth
|
|
2189
|
-
+ CGFloat(max(0, visibleTextCount - 1)) * 6 + 4
|
|
2190
|
-
return min(288, max(72, ceil(width + 8)))
|
|
2117
|
+
NativeListRailRenderer.Resolved(item, theme: config?.theme).horizontalWidth
|
|
2191
2118
|
}
|
|
2192
2119
|
|
|
2193
2120
|
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
|
2194
2121
|
guard let item = config?.items[safe: indexPath.item] else { return }
|
|
2195
2122
|
if item.type == "walletGroup" { return }
|
|
2196
|
-
let origin = (collectionView.cellForItem(at: indexPath) as?
|
|
2123
|
+
let origin = (collectionView.cellForItem(at: indexPath) as? NativeListRowHost)?.rowActionOrigin()
|
|
2197
2124
|
handleRowPress(item, origin: origin)
|
|
2198
2125
|
}
|
|
2199
2126
|
|
|
@@ -2206,7 +2133,7 @@ extension NativeListView: UICollectionViewDelegateFlowLayout {
|
|
|
2206
2133
|
guard let item = config?.items[safe: indexPath.item], item.type == "market" else { return }
|
|
2207
2134
|
let actionKey = item.data.string("pressInActionKey")
|
|
2208
2135
|
guard !actionKey.isEmpty else { return }
|
|
2209
|
-
let origin = (collectionView.cellForItem(at: indexPath) as?
|
|
2136
|
+
let origin = (collectionView.cellForItem(at: indexPath) as? NativeListRowHost)?.rowActionOrigin()
|
|
2210
2137
|
handleAction(item: item, actionKey: actionKey, target: nil, origin: origin)
|
|
2211
2138
|
}
|
|
2212
2139
|
|
|
@@ -2365,11 +2292,15 @@ final class NativeListFlowLayout: UICollectionViewFlowLayout {
|
|
|
2365
2292
|
!stickyItemIndexes.isEmpty,
|
|
2366
2293
|
let collectionView else { return super.layoutAttributesForElements(in: rect) }
|
|
2367
2294
|
let base = super.layoutAttributesForElements(in: rect)?.compactMap { $0.copy() as? UICollectionViewLayoutAttributes } ?? []
|
|
2368
|
-
let
|
|
2369
|
-
|
|
2295
|
+
let pinY = collectionView.contentOffset.y + collectionView.adjustedContentInset.top
|
|
2296
|
+
// Visible cells can still describe the old viewport during an imperative
|
|
2297
|
+
// scroll. Resolve the pinned header from unmodified layout positions.
|
|
2298
|
+
guard let stickyIndex = stickyItemIndexes.filter({
|
|
2299
|
+
guard let attributes = super.layoutAttributesForItem(at: IndexPath(item: $0, section: 0)) else { return false }
|
|
2300
|
+
return attributes.frame.minY <= pinY
|
|
2301
|
+
}).max(),
|
|
2370
2302
|
let original = super.layoutAttributesForItem(at: IndexPath(item: stickyIndex, section: 0)),
|
|
2371
2303
|
let sticky = original.copy() as? UICollectionViewLayoutAttributes else { return base }
|
|
2372
|
-
let pinY = collectionView.contentOffset.y + collectionView.adjustedContentInset.top
|
|
2373
2304
|
let nextHeaderY = stickyItemIndexes
|
|
2374
2305
|
.filter { $0 > stickyIndex }
|
|
2375
2306
|
.min()
|
package/lib/module/models.js
CHANGED
|
@@ -1,2 +1,56 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Named typography steps, shared with the application's design scale. Resolved
|
|
5
|
+
* to fontSize/lineHeight/fontWeight in JavaScript before the snapshot is
|
|
6
|
+
* serialized, so no native renderer needs to know the vocabulary.
|
|
7
|
+
* See docs/STYLE_SPEC.md §3.2.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Retained alias: Market shipped this name before the style surface was shared. */
|
|
11
|
+
|
|
12
|
+
/** Local box vocabulary. Each template exposes only parameters for its own slots. */
|
|
13
|
+
|
|
14
|
+
/** Template-owned slots determine which local box parameters exist, on every platform. */
|
|
15
|
+
export const ROW_BOX_STYLE_KEYS_BY_TYPE = {
|
|
16
|
+
identity: ['horizontalPadding', 'verticalPadding', 'leadingGap', 'lineGap', 'titleBadgeGap', 'trailingGap', 'image'],
|
|
17
|
+
walletGroup: ['horizontalPadding', 'verticalPadding'],
|
|
18
|
+
rail: ['horizontalPadding', 'verticalPadding', 'leadingGap', 'titleBadgeGap', 'trailingGap', 'image'],
|
|
19
|
+
activity: ['horizontalPadding', 'verticalPadding', 'leadingGap', 'lineGap', 'trailingGap', 'image'],
|
|
20
|
+
message: ['horizontalPadding', 'verticalPadding', 'leadingGap', 'lineGap', 'image'],
|
|
21
|
+
dataRow: ['horizontalPadding', 'verticalPadding', 'leadingGap', 'lineGap', 'titleBadgeGap', 'image'],
|
|
22
|
+
market: ['horizontalPadding', 'verticalPadding', 'leadingGap', 'lineGap', 'titleBadgeGap', 'trailingGap', 'image'],
|
|
23
|
+
mediaTile: ['horizontalPadding', 'verticalPadding', 'leadingGap', 'lineGap', 'image'],
|
|
24
|
+
metricCard: ['horizontalPadding', 'verticalPadding', 'leadingGap', 'lineGap', 'image'],
|
|
25
|
+
sectionHeader: ['horizontalPadding', 'verticalPadding', 'lineGap', 'trailingGap'],
|
|
26
|
+
action: ['horizontalPadding', 'verticalPadding', 'leadingGap', 'trailingGap', 'image'],
|
|
27
|
+
system: ['horizontalPadding', 'verticalPadding', 'lineGap']
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A style key names the model field it modifies, never the view that carries
|
|
32
|
+
* it. Each template renderer owns its views and maps the key to whichever view
|
|
33
|
+
* renders that field (for example metricCard `value` is its large number), so
|
|
34
|
+
* the same key name keeps one meaning across platforms. See docs/STYLE_SPEC.md §4.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
// OneKey patch: keep selector decoration and text data serializable.
|
|
38
|
+
|
|
39
|
+
// OneKey patch: preserve compact very-small-balance digit runs.
|
|
40
|
+
|
|
41
|
+
/** Native Market quote row. All values are already localized/formatted strings. */
|
|
42
|
+
|
|
43
|
+
/** Compact KPI card for dashboards and grids. */
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* List chrome that every platform can honour. Pull to refresh, the section index
|
|
47
|
+
* rail and the reorder preview are deliberately absent: the first two are system
|
|
48
|
+
* controls or three independent constant sets, and the third is drawn with
|
|
49
|
+
* platform-specific primitives. See docs/STYLE_SPEC.md §5.
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
// OneKey patch: include selector-only mutable presentation fields.
|
|
53
|
+
// type CommonPatchFields = 'revision' | 'disabled' | 'selected' | 'separator';
|
|
54
|
+
// OneKey patch: balance patches also refresh the existing row's spoken content.
|
|
55
|
+
// type CommonPatchFields = 'revision' | 'disabled' | 'selected' | 'separator' | 'height' | 'heightRounding' | 'opacity' | 'pressDisabled';
|
|
2
56
|
//# sourceMappingURL=models.js.map
|