@onekeyfe/react-native-native-list 3.0.114 → 3.0.115
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 +17 -1
- package/android/src/main/java/com/onekey/nativelist/NativeListRowView.kt +543 -26
- package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +404 -90
- package/ios/NativeListCell.swift +506 -20
- package/ios/NativeListDesignAssets.swift +8 -0
- package/ios/RNCNativeListView.swift +271 -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 +129 -1
- package/lib/module/web/NativeListWebEngine.js +461 -51
- package/lib/typescript/src/models.d.ts +82 -2
- package/lib/typescript/src/web/NativeListWebEngine.d.ts +37 -3
- package/package.json +4 -2
- package/src/models.ts +121 -3
- package/src/validation.ts +206 -0
- package/src/web/NativeListWebEngine.ts +766 -91
package/lib/module/validation.js
CHANGED
|
@@ -10,6 +10,7 @@ const MAX_IMAGE_HEADERS = 32;
|
|
|
10
10
|
const MAX_HEADER_LENGTH = 4096;
|
|
11
11
|
const MAX_SPACER_HEIGHT = 512;
|
|
12
12
|
const MAX_SECTION_INDEX_TITLE_LENGTH = 8;
|
|
13
|
+
const MAX_MARKET_BADGES = 3;
|
|
13
14
|
function fail(path, message) {
|
|
14
15
|
throw new Error(`NativeList ${path}: ${message}`);
|
|
15
16
|
}
|
|
@@ -62,6 +63,105 @@ function assertTextTone(tone, path) {
|
|
|
62
63
|
fail(path, 'must be primary, secondary, positive, or negative');
|
|
63
64
|
}
|
|
64
65
|
}
|
|
66
|
+
function assertBoundedStyleNumber(value, path, min, max) {
|
|
67
|
+
if (value !== undefined && (!Number.isFinite(value) || value < min || value > max)) {
|
|
68
|
+
fail(path, `must be within ${min}...${max}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function assertMarketTextStyle(style, path) {
|
|
72
|
+
if (!style) return;
|
|
73
|
+
assertBoundedStyleNumber(style.fontSize, `${path}.fontSize`, 8, 48);
|
|
74
|
+
assertBoundedStyleNumber(style.lineHeight, `${path}.lineHeight`, 8, 64);
|
|
75
|
+
if (style.fontWeight !== undefined && !['regular', 'medium', 'semibold', 'bold'].includes(style.fontWeight)) {
|
|
76
|
+
fail(`${path}.fontWeight`, 'must be regular, medium, semibold, or bold');
|
|
77
|
+
}
|
|
78
|
+
if (style.alignment !== undefined && !['start', 'center', 'end'].includes(style.alignment)) {
|
|
79
|
+
fail(`${path}.alignment`, 'must be start, center, or end');
|
|
80
|
+
}
|
|
81
|
+
if (style.lines !== undefined && ![1, 2].includes(style.lines)) {
|
|
82
|
+
fail(`${path}.lines`, 'must be 1 or 2');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function assertMarketStyle(style, path) {
|
|
86
|
+
if (!style) return;
|
|
87
|
+
for (const field of ['horizontalPadding', 'verticalPadding', 'leadingGap', 'titleBadgeGap', 'trailingGap']) {
|
|
88
|
+
assertBoundedStyleNumber(style[field], `${path}.${field}`, 0, 64);
|
|
89
|
+
}
|
|
90
|
+
assertBoundedStyleNumber(style.lineGap, `${path}.lineGap`, 0, 16);
|
|
91
|
+
assertBoundedStyleNumber(style.changeWidth, `${path}.changeWidth`, 1, 160);
|
|
92
|
+
assertBoundedStyleNumber(style.changeHeight, `${path}.changeHeight`, 1, 160);
|
|
93
|
+
assertBoundedStyleNumber(style.changeCornerRadius, `${path}.changeCornerRadius`, 0, 80);
|
|
94
|
+
if (style.image) {
|
|
95
|
+
assertBoundedStyleNumber(style.image.width, `${path}.image.width`, 1, 160);
|
|
96
|
+
assertBoundedStyleNumber(style.image.height, `${path}.image.height`, 1, 160);
|
|
97
|
+
assertBoundedStyleNumber(style.image.cornerRadius, `${path}.image.cornerRadius`, 0, 80);
|
|
98
|
+
assertVisualShape(style.image.shape, `${path}.image.shape`);
|
|
99
|
+
if (style.image.contentFit !== undefined && !['cover', 'contain', 'fill', 'center'].includes(style.image.contentFit)) {
|
|
100
|
+
fail(`${path}.image.contentFit`, 'must be cover, contain, fill, or center');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
assertMarketTextStyle(style.title, `${path}.title`);
|
|
104
|
+
assertMarketTextStyle(style.subtitle, `${path}.subtitle`);
|
|
105
|
+
assertMarketTextStyle(style.price, `${path}.price`);
|
|
106
|
+
assertMarketTextStyle(style.change, `${path}.change`);
|
|
107
|
+
}
|
|
108
|
+
function assertMarketRow(row, path) {
|
|
109
|
+
if (!['token', 'stock', 'perp'].includes(row.variant)) {
|
|
110
|
+
fail(`${path}.variant`, 'must be token, stock, or perp');
|
|
111
|
+
}
|
|
112
|
+
assertText(row.title, `${path}.title`);
|
|
113
|
+
assertText(row.subtitle, `${path}.subtitle`);
|
|
114
|
+
assertText(row.price, `${path}.price`);
|
|
115
|
+
assertText(row.change.text, `${path}.change.text`);
|
|
116
|
+
assertLeadingVisual(row.leading, `${path}.leading`);
|
|
117
|
+
const assertSegments = (segments, segmentPath) => {
|
|
118
|
+
segments?.forEach((segment, index) => {
|
|
119
|
+
assertText(segment.text, `${segmentPath}[${index}].text`);
|
|
120
|
+
if (segment.style !== undefined && segment.style !== 'subscript') {
|
|
121
|
+
fail(`${segmentPath}[${index}].style`, 'must be subscript when provided');
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
assertSegments(row.subtitleSegments, `${path}.subtitleSegments`);
|
|
126
|
+
assertSegments(row.priceSegments, `${path}.priceSegments`);
|
|
127
|
+
assertSegments(row.change.textSegments, `${path}.change.textSegments`);
|
|
128
|
+
if (!['positive', 'negative', 'neutral'].includes(row.change.tone)) {
|
|
129
|
+
fail(`${path}.change.tone`, 'must be positive, negative, or neutral');
|
|
130
|
+
}
|
|
131
|
+
if ((row.badges?.length ?? 0) > MAX_MARKET_BADGES) {
|
|
132
|
+
fail(`${path}.badges`, `supports at most ${MAX_MARKET_BADGES} badges`);
|
|
133
|
+
}
|
|
134
|
+
const badgeKeys = new Set();
|
|
135
|
+
row.badges?.forEach((badge, index) => {
|
|
136
|
+
const badgePath = `${path}.badges[${index}]`;
|
|
137
|
+
assertKey(badge.key, `${badgePath}.key`);
|
|
138
|
+
if (badgeKeys.has(badge.key)) {
|
|
139
|
+
fail(`${path}.badges`, `duplicate badge key "${badge.key}"`);
|
|
140
|
+
}
|
|
141
|
+
badgeKeys.add(badge.key);
|
|
142
|
+
assertText(badge.text, `${badgePath}.text`);
|
|
143
|
+
if (badge.iconName !== undefined && badge.iconName !== 'verified') {
|
|
144
|
+
fail(`${badgePath}.iconName`, 'must be verified when provided');
|
|
145
|
+
}
|
|
146
|
+
if (badge.iconName !== undefined && badge.icon !== undefined) {
|
|
147
|
+
fail(`${badgePath}.icon`, 'cannot be combined with iconName');
|
|
148
|
+
}
|
|
149
|
+
assertImage(badge.icon, `${badgePath}.icon`);
|
|
150
|
+
if (badge.tone !== undefined && !['neutral', 'info', 'success', 'warning', 'danger'].includes(badge.tone)) {
|
|
151
|
+
fail(`${badgePath}.tone`, 'must be neutral, info, success, warning, or danger');
|
|
152
|
+
}
|
|
153
|
+
if (!badge.text && !badge.icon && !badge.iconName) {
|
|
154
|
+
fail(badgePath, 'requires text, icon, or iconName');
|
|
155
|
+
}
|
|
156
|
+
if (badge.actionKey !== undefined) {
|
|
157
|
+
assertKey(badge.actionKey, `${badgePath}.actionKey`);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
for (const [key, value] of [['pressActionKey', row.pressActionKey], ['pressInActionKey', row.pressInActionKey], ['longPressActionKey', row.longPressActionKey], ['diagnostics.imageBindActionKey', row.diagnostics?.imageBindActionKey]]) {
|
|
161
|
+
if (value !== undefined) assertKey(value, `${path}.${key}`);
|
|
162
|
+
}
|
|
163
|
+
assertMarketStyle(row.style, `${path}.style`);
|
|
164
|
+
}
|
|
65
165
|
function assertSectionHeaderVariant(variant, path) {
|
|
66
166
|
if (variant !== undefined && !['summary', 'gallery', 'history'].includes(variant)) {
|
|
67
167
|
fail(path, 'must be summary, gallery, or history when provided');
|
|
@@ -150,7 +250,7 @@ function assertLeadingVisual(visual, path) {
|
|
|
150
250
|
}
|
|
151
251
|
}
|
|
152
252
|
function assertVisual(row, path) {
|
|
153
|
-
const visuals = row.type === 'identity' ? [row.leading] : row.type === 'rail' ? [row.visual] : row.type === 'activity' ? [row.leading, row.secondaryLeading] : row.type === 'message' ? [row.leading] : row.type === 'dataRow' ? [row.leading] : row.type === 'metricCard' ? [row.visual] : [];
|
|
253
|
+
const visuals = row.type === 'identity' ? [row.leading] : row.type === 'rail' ? [row.visual] : row.type === 'activity' ? [row.leading, row.secondaryLeading] : row.type === 'message' ? [row.leading] : row.type === 'dataRow' ? [row.leading] : row.type === 'market' ? [row.leading] : row.type === 'metricCard' ? [row.visual] : [];
|
|
154
254
|
visuals.forEach((visual, index) => {
|
|
155
255
|
assertLeadingVisual(visual, `${path}.visual[${index}]`);
|
|
156
256
|
});
|
|
@@ -262,6 +362,9 @@ function assertRow(row, index, path = `rows[${index}]`) {
|
|
|
262
362
|
fail(`${path}.badges`, `supports at most ${MAX_BADGES} badges`);
|
|
263
363
|
}
|
|
264
364
|
break;
|
|
365
|
+
case 'market':
|
|
366
|
+
assertMarketRow(row, path);
|
|
367
|
+
break;
|
|
265
368
|
case 'mediaTile':
|
|
266
369
|
assertImage(row.image, `${path}.image`);
|
|
267
370
|
if (row.imageState !== undefined && !['empty', 'error'].includes(row.imageState)) {
|
|
@@ -327,12 +430,19 @@ function assertRow(row, index, path = `rows[${index}]`) {
|
|
|
327
430
|
assertTrailingAccessories(row.trailing, `${path}.trailing`);
|
|
328
431
|
break;
|
|
329
432
|
case 'system':
|
|
433
|
+
const presentation = 'presentation' in row ? row.presentation : undefined;
|
|
434
|
+
if (presentation !== undefined && presentation !== 'market') {
|
|
435
|
+
fail(`${path}.presentation`, 'must be market when provided');
|
|
436
|
+
}
|
|
330
437
|
if (
|
|
331
438
|
// OneKey patch: deprecated-wallet warnings retain the original scrolling semantics.
|
|
332
439
|
!['loading', 'retry', 'noMatch', 'end', 'spacer', 'warning'].includes(row.variant)) {
|
|
333
440
|
fail(`${path}.variant`, 'must be loading, retry, noMatch, end, spacer, or warning');
|
|
334
441
|
}
|
|
335
442
|
if (row.variant === 'warning') assertText(row.title, `${path}.title`);
|
|
443
|
+
if (row.variant === 'loading' && row.loadingStyle !== undefined && row.loadingStyle !== 'skeleton' && row.loadingStyle !== 'spinner') {
|
|
444
|
+
fail(`${path}.loadingStyle`, 'must be skeleton or spinner when provided');
|
|
445
|
+
}
|
|
336
446
|
if (row.variant !== 'spacer') {
|
|
337
447
|
assertText(row.message, `${path}.message`);
|
|
338
448
|
}
|
|
@@ -503,6 +613,24 @@ function assertPatchChanges(patch, index) {
|
|
|
503
613
|
fail(`${path}.badges`, `supports at most ${MAX_BADGES} badges`);
|
|
504
614
|
}
|
|
505
615
|
break;
|
|
616
|
+
case 'market':
|
|
617
|
+
assertMarketRow({
|
|
618
|
+
type: 'market',
|
|
619
|
+
key: patch.key,
|
|
620
|
+
variant: 'token',
|
|
621
|
+
leading: {
|
|
622
|
+
kind: 'icon',
|
|
623
|
+
name: 'placeholder'
|
|
624
|
+
},
|
|
625
|
+
title: '',
|
|
626
|
+
price: '',
|
|
627
|
+
change: {
|
|
628
|
+
text: '',
|
|
629
|
+
tone: 'neutral'
|
|
630
|
+
},
|
|
631
|
+
...patch.changes
|
|
632
|
+
}, path);
|
|
633
|
+
break;
|
|
506
634
|
case 'mediaTile':
|
|
507
635
|
assertImage(patch.changes.image, `${path}.image`);
|
|
508
636
|
if (patch.changes.imageState !== undefined && !['empty', 'error'].includes(patch.changes.imageState)) {
|