@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
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,120 @@ 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', 'contentTrailingGap', 'subtitleTrailingPadding']) {
|
|
88
|
+
assertBoundedStyleNumber(style[field], `${path}.${field}`, 0, 64);
|
|
89
|
+
}
|
|
90
|
+
// OneKey patch: validate the opt-in Market badge layout.
|
|
91
|
+
if (style.titleBadgeLayout !== undefined && style.titleBadgeLayout !== 'inline') {
|
|
92
|
+
fail(`${path}.titleBadgeLayout`, 'must be inline when provided');
|
|
93
|
+
}
|
|
94
|
+
assertBoundedStyleNumber(style.lineGap, `${path}.lineGap`, 0, 16);
|
|
95
|
+
assertBoundedStyleNumber(style.changeWidth, `${path}.changeWidth`, 1, 160);
|
|
96
|
+
assertBoundedStyleNumber(style.changeHeight, `${path}.changeHeight`, 1, 160);
|
|
97
|
+
assertBoundedStyleNumber(style.changeCornerRadius, `${path}.changeCornerRadius`, 0, 80);
|
|
98
|
+
if (style.image) {
|
|
99
|
+
assertBoundedStyleNumber(style.image.width, `${path}.image.width`, 1, 160);
|
|
100
|
+
assertBoundedStyleNumber(style.image.height, `${path}.image.height`, 1, 160);
|
|
101
|
+
assertBoundedStyleNumber(style.image.cornerRadius, `${path}.image.cornerRadius`, 0, 80);
|
|
102
|
+
assertVisualShape(style.image.shape, `${path}.image.shape`);
|
|
103
|
+
if (style.image.contentFit !== undefined && !['cover', 'contain', 'fill', 'center'].includes(style.image.contentFit)) {
|
|
104
|
+
fail(`${path}.image.contentFit`, 'must be cover, contain, fill, or center');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
assertMarketTextStyle(style.title, `${path}.title`);
|
|
108
|
+
assertMarketTextStyle(style.subtitle, `${path}.subtitle`);
|
|
109
|
+
assertMarketTextStyle(style.price, `${path}.price`);
|
|
110
|
+
assertMarketTextStyle(style.change, `${path}.change`);
|
|
111
|
+
}
|
|
112
|
+
function assertMarketRow(row, path) {
|
|
113
|
+
if (!['token', 'stock', 'perp'].includes(row.variant)) {
|
|
114
|
+
fail(`${path}.variant`, 'must be token, stock, or perp');
|
|
115
|
+
}
|
|
116
|
+
assertText(row.title, `${path}.title`);
|
|
117
|
+
assertText(row.subtitle, `${path}.subtitle`);
|
|
118
|
+
// OneKey patch: validate the independently laid out Market name.
|
|
119
|
+
if (row.subtitlePrefix) {
|
|
120
|
+
assertText(row.subtitlePrefix.text, `${path}.subtitlePrefix.text`);
|
|
121
|
+
assertBoundedStyleNumber(row.subtitlePrefix.gap, `${path}.subtitlePrefix.gap`, 0, 64);
|
|
122
|
+
assertBoundedStyleNumber(row.subtitlePrefix.maxWidth, `${path}.subtitlePrefix.maxWidth`, 1, 320);
|
|
123
|
+
assertMarketTextStyle(row.subtitlePrefix.style, `${path}.subtitlePrefix.style`);
|
|
124
|
+
}
|
|
125
|
+
assertText(row.price, `${path}.price`);
|
|
126
|
+
assertText(row.change.text, `${path}.change.text`);
|
|
127
|
+
assertLeadingVisual(row.leading, `${path}.leading`);
|
|
128
|
+
const assertSegments = (segments, segmentPath) => {
|
|
129
|
+
segments?.forEach((segment, index) => {
|
|
130
|
+
assertText(segment.text, `${segmentPath}[${index}].text`);
|
|
131
|
+
if (segment.style !== undefined && segment.style !== 'subscript') {
|
|
132
|
+
fail(`${segmentPath}[${index}].style`, 'must be subscript when provided');
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
assertSegments(row.subtitleSegments, `${path}.subtitleSegments`);
|
|
137
|
+
assertSegments(row.priceSegments, `${path}.priceSegments`);
|
|
138
|
+
assertSegments(row.change.textSegments, `${path}.change.textSegments`);
|
|
139
|
+
if (!['positive', 'negative', 'neutral'].includes(row.change.tone)) {
|
|
140
|
+
fail(`${path}.change.tone`, 'must be positive, negative, or neutral');
|
|
141
|
+
}
|
|
142
|
+
if ((row.badges?.length ?? 0) > MAX_MARKET_BADGES) {
|
|
143
|
+
fail(`${path}.badges`, `supports at most ${MAX_MARKET_BADGES} badges`);
|
|
144
|
+
}
|
|
145
|
+
const badgeKeys = new Set();
|
|
146
|
+
row.badges?.forEach((badge, index) => {
|
|
147
|
+
const badgePath = `${path}.badges[${index}]`;
|
|
148
|
+
assertKey(badge.key, `${badgePath}.key`);
|
|
149
|
+
if (badgeKeys.has(badge.key)) {
|
|
150
|
+
fail(`${path}.badges`, `duplicate badge key "${badge.key}"`);
|
|
151
|
+
}
|
|
152
|
+
badgeKeys.add(badge.key);
|
|
153
|
+
assertText(badge.text, `${badgePath}.text`);
|
|
154
|
+
// OneKey patch: share typography bounds with Market text styles.
|
|
155
|
+
assertMarketTextStyle(badge.style, `${badgePath}.style`);
|
|
156
|
+
assertBoundedStyleNumber(badge.style?.height, `${badgePath}.style.height`, 1, 64);
|
|
157
|
+
assertBoundedStyleNumber(badge.style?.horizontalPadding, `${badgePath}.style.horizontalPadding`, 0, 32);
|
|
158
|
+
if (badge.iconName !== undefined && badge.iconName !== 'verified') {
|
|
159
|
+
fail(`${badgePath}.iconName`, 'must be verified when provided');
|
|
160
|
+
}
|
|
161
|
+
if (badge.iconName !== undefined && badge.icon !== undefined) {
|
|
162
|
+
fail(`${badgePath}.icon`, 'cannot be combined with iconName');
|
|
163
|
+
}
|
|
164
|
+
assertImage(badge.icon, `${badgePath}.icon`);
|
|
165
|
+
if (badge.tone !== undefined && !['neutral', 'info', 'success', 'warning', 'danger'].includes(badge.tone)) {
|
|
166
|
+
fail(`${badgePath}.tone`, 'must be neutral, info, success, warning, or danger');
|
|
167
|
+
}
|
|
168
|
+
if (!badge.text && !badge.icon && !badge.iconName) {
|
|
169
|
+
fail(badgePath, 'requires text, icon, or iconName');
|
|
170
|
+
}
|
|
171
|
+
if (badge.actionKey !== undefined) {
|
|
172
|
+
assertKey(badge.actionKey, `${badgePath}.actionKey`);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
for (const [key, value] of [['pressActionKey', row.pressActionKey], ['pressInActionKey', row.pressInActionKey], ['longPressActionKey', row.longPressActionKey], ['diagnostics.imageBindActionKey', row.diagnostics?.imageBindActionKey]]) {
|
|
176
|
+
if (value !== undefined) assertKey(value, `${path}.${key}`);
|
|
177
|
+
}
|
|
178
|
+
assertMarketStyle(row.style, `${path}.style`);
|
|
179
|
+
}
|
|
65
180
|
function assertSectionHeaderVariant(variant, path) {
|
|
66
181
|
if (variant !== undefined && !['summary', 'gallery', 'history'].includes(variant)) {
|
|
67
182
|
fail(path, 'must be summary, gallery, or history when provided');
|
|
@@ -150,7 +265,7 @@ function assertLeadingVisual(visual, path) {
|
|
|
150
265
|
}
|
|
151
266
|
}
|
|
152
267
|
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] : [];
|
|
268
|
+
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
269
|
visuals.forEach((visual, index) => {
|
|
155
270
|
assertLeadingVisual(visual, `${path}.visual[${index}]`);
|
|
156
271
|
});
|
|
@@ -262,6 +377,9 @@ function assertRow(row, index, path = `rows[${index}]`) {
|
|
|
262
377
|
fail(`${path}.badges`, `supports at most ${MAX_BADGES} badges`);
|
|
263
378
|
}
|
|
264
379
|
break;
|
|
380
|
+
case 'market':
|
|
381
|
+
assertMarketRow(row, path);
|
|
382
|
+
break;
|
|
265
383
|
case 'mediaTile':
|
|
266
384
|
assertImage(row.image, `${path}.image`);
|
|
267
385
|
if (row.imageState !== undefined && !['empty', 'error'].includes(row.imageState)) {
|
|
@@ -327,12 +445,19 @@ function assertRow(row, index, path = `rows[${index}]`) {
|
|
|
327
445
|
assertTrailingAccessories(row.trailing, `${path}.trailing`);
|
|
328
446
|
break;
|
|
329
447
|
case 'system':
|
|
448
|
+
const presentation = 'presentation' in row ? row.presentation : undefined;
|
|
449
|
+
if (presentation !== undefined && presentation !== 'market') {
|
|
450
|
+
fail(`${path}.presentation`, 'must be market when provided');
|
|
451
|
+
}
|
|
330
452
|
if (
|
|
331
453
|
// OneKey patch: deprecated-wallet warnings retain the original scrolling semantics.
|
|
332
454
|
!['loading', 'retry', 'noMatch', 'end', 'spacer', 'warning'].includes(row.variant)) {
|
|
333
455
|
fail(`${path}.variant`, 'must be loading, retry, noMatch, end, spacer, or warning');
|
|
334
456
|
}
|
|
335
457
|
if (row.variant === 'warning') assertText(row.title, `${path}.title`);
|
|
458
|
+
if (row.variant === 'loading' && row.loadingStyle !== undefined && row.loadingStyle !== 'skeleton' && row.loadingStyle !== 'spinner') {
|
|
459
|
+
fail(`${path}.loadingStyle`, 'must be skeleton or spinner when provided');
|
|
460
|
+
}
|
|
336
461
|
if (row.variant !== 'spacer') {
|
|
337
462
|
assertText(row.message, `${path}.message`);
|
|
338
463
|
}
|
|
@@ -341,6 +466,7 @@ function assertRow(row, index, path = `rows[${index}]`) {
|
|
|
341
466
|
}
|
|
342
467
|
if (row.variant === 'retry') {
|
|
343
468
|
assertKey(row.actionKey, `${path}.actionKey`);
|
|
469
|
+
assertText(row.actionText, `${path}.actionText`);
|
|
344
470
|
}
|
|
345
471
|
break;
|
|
346
472
|
}
|
|
@@ -503,6 +629,24 @@ function assertPatchChanges(patch, index) {
|
|
|
503
629
|
fail(`${path}.badges`, `supports at most ${MAX_BADGES} badges`);
|
|
504
630
|
}
|
|
505
631
|
break;
|
|
632
|
+
case 'market':
|
|
633
|
+
assertMarketRow({
|
|
634
|
+
type: 'market',
|
|
635
|
+
key: patch.key,
|
|
636
|
+
variant: 'token',
|
|
637
|
+
leading: {
|
|
638
|
+
kind: 'icon',
|
|
639
|
+
name: 'placeholder'
|
|
640
|
+
},
|
|
641
|
+
title: '',
|
|
642
|
+
price: '',
|
|
643
|
+
change: {
|
|
644
|
+
text: '',
|
|
645
|
+
tone: 'neutral'
|
|
646
|
+
},
|
|
647
|
+
...patch.changes
|
|
648
|
+
}, path);
|
|
649
|
+
break;
|
|
506
650
|
case 'mediaTile':
|
|
507
651
|
assertImage(patch.changes.image, `${path}.image`);
|
|
508
652
|
if (patch.changes.imageState !== undefined && !['empty', 'error'].includes(patch.changes.imageState)) {
|