@one_deploy/sdk 1.0.6 → 1.0.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@one_deploy/sdk",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "ONE Ecosystem SDK - Shared services, types, utilities, and React providers",
5
5
  "files": [
6
6
  "dist",
@@ -1,10 +1,10 @@
1
1
  /**
2
- * OneChainSelector - Multi-chain selection component for AI trading
3
- * Part of ONE Ecosystem SDK - can be used by any ecosystem partner
2
+ * OneChainSelector - Multi-chain selection component with dropdown style
3
+ * Part of ONE Ecosystem SDK - Responsive design for desktop and mobile
4
4
  */
5
5
 
6
- import React from 'react';
7
- import { View, Text, StyleSheet, TouchableOpacity, ViewStyle, TextStyle } from 'react-native';
6
+ import React, { useState } from 'react';
7
+ import { View, Text, StyleSheet, TouchableOpacity, ViewStyle, TextStyle, Modal, ScrollView, Pressable, Dimensions, Platform } from 'react-native';
8
8
 
9
9
  // Chain configuration with branding
10
10
  export const CHAIN_CONFIG: Record<string, { name: string; icon: string; color: string }> = {
@@ -37,12 +37,19 @@ export interface OneChainSelectorProps {
37
37
  subtitle?: string;
38
38
  /** Minimum required selections (for multi-select) */
39
39
  minSelections?: number;
40
+ /** Placeholder text */
41
+ placeholder?: string;
40
42
  /** Custom styles */
41
43
  style?: ViewStyle;
42
44
  /** Custom title style */
43
45
  titleStyle?: TextStyle;
44
46
  }
45
47
 
48
+ const isDesktop = () => {
49
+ const { width } = Dimensions.get('window');
50
+ return Platform.OS === 'web' && width >= 768;
51
+ };
52
+
46
53
  export const OneChainSelector: React.FC<OneChainSelectorProps> = ({
47
54
  supportedChains,
48
55
  selectedChains,
@@ -52,69 +59,179 @@ export const OneChainSelector: React.FC<OneChainSelectorProps> = ({
52
59
  title,
53
60
  subtitle,
54
61
  minSelections = 1,
62
+ placeholder = 'Select chains...',
55
63
  style,
56
64
  titleStyle,
57
65
  }) => {
66
+ const [isOpen, setIsOpen] = useState(false);
67
+ const desktop = isDesktop();
68
+
58
69
  const handleSelect = (chain: string) => {
59
70
  if (multiSelect) {
60
- // In multi-select, prevent deselecting if at minimum
61
71
  if (selectedChains.includes(chain) && selectedChains.length <= minSelections) {
62
72
  return;
63
73
  }
64
74
  onSelectChain(chain);
65
75
  } else {
66
- // Single select - always allow selection
67
76
  if (!selectedChains.includes(chain)) {
68
77
  onSelectChain(chain);
69
78
  }
79
+ setIsOpen(false);
70
80
  }
71
81
  };
72
82
 
83
+ // Desktop: Inline grid display
84
+ if (desktop) {
85
+ return (
86
+ <View style={[styles.container, style]}>
87
+ {title && <Text style={[styles.title, titleStyle]}>{title}</Text>}
88
+ {subtitle && <Text style={styles.subtitle}>{subtitle}</Text>}
89
+
90
+ <View style={styles.desktopGrid}>
91
+ {supportedChains.map((chain) => {
92
+ const chainInfo = CHAIN_CONFIG[chain] || { name: chain, icon: '●', color: '#888' };
93
+ const isSelected = selectedChains.includes(chain);
94
+
95
+ return (
96
+ <TouchableOpacity
97
+ key={chain}
98
+ style={[
99
+ styles.desktopChip,
100
+ isSelected && styles.desktopChipSelected,
101
+ isSelected && { borderColor: accentColor, backgroundColor: accentColor + '12' }
102
+ ]}
103
+ onPress={() => handleSelect(chain)}
104
+ activeOpacity={0.7}
105
+ >
106
+ <View style={[styles.desktopIconBg, { backgroundColor: chainInfo.color + '20' }]}>
107
+ <Text style={[styles.desktopIcon, { color: chainInfo.color }]}>{chainInfo.icon}</Text>
108
+ </View>
109
+ <Text style={[
110
+ styles.desktopChipText,
111
+ isSelected && { color: accentColor, fontWeight: '600' }
112
+ ]}>
113
+ {chainInfo.name}
114
+ </Text>
115
+ {isSelected && (
116
+ <View style={[styles.desktopCheckbox, { backgroundColor: accentColor }]}>
117
+ <Text style={styles.desktopCheckIcon}>✓</Text>
118
+ </View>
119
+ )}
120
+ </TouchableOpacity>
121
+ );
122
+ })}
123
+ </View>
124
+
125
+ {multiSelect && selectedChains.length > 0 && (
126
+ <Text style={[styles.selectedCount, { color: accentColor }]}>
127
+ {selectedChains.length} chain{selectedChains.length > 1 ? 's' : ''} selected
128
+ </Text>
129
+ )}
130
+ </View>
131
+ );
132
+ }
133
+
134
+ // Mobile: Dropdown modal
73
135
  return (
74
136
  <View style={[styles.container, style]}>
75
137
  {title && <Text style={[styles.title, titleStyle]}>{title}</Text>}
76
138
  {subtitle && <Text style={styles.subtitle}>{subtitle}</Text>}
77
139
 
78
- <View style={styles.chainsContainer}>
79
- {supportedChains.map((chain) => {
80
- const chainInfo = CHAIN_CONFIG[chain] || { name: chain, icon: '●', color: '#888' };
81
- const isSelected = selectedChains.includes(chain);
82
-
83
- return (
84
- <TouchableOpacity
85
- key={chain}
86
- style={[
87
- styles.chainChip,
88
- isSelected && styles.chainChipSelected,
89
- isSelected && { borderColor: accentColor, backgroundColor: accentColor + '15' }
90
- ]}
91
- onPress={() => handleSelect(chain)}
92
- activeOpacity={0.7}
93
- >
94
- <View style={[styles.chainIconBg, { backgroundColor: chainInfo.color + '20' }]}>
95
- <Text style={[styles.chainIcon, { color: chainInfo.color }]}>{chainInfo.icon}</Text>
140
+ <TouchableOpacity
141
+ style={[styles.dropdownTrigger, { borderColor: isOpen ? accentColor : '#e5e5e5' }]}
142
+ onPress={() => setIsOpen(true)}
143
+ activeOpacity={0.7}
144
+ >
145
+ <View style={styles.selectedPreview}>
146
+ {selectedChains.slice(0, 3).map((chain) => {
147
+ const chainInfo = CHAIN_CONFIG[chain] || { name: chain, icon: '●', color: '#888' };
148
+ return (
149
+ <View key={chain} style={[styles.previewChip, { backgroundColor: chainInfo.color + '20' }]}>
150
+ <Text style={[styles.previewIcon, { color: chainInfo.color }]}>{chainInfo.icon}</Text>
96
151
  </View>
97
- <Text style={[
98
- styles.chainText,
99
- isSelected && { color: accentColor, fontWeight: '600' }
100
- ]}>
101
- {chainInfo.name}
102
- </Text>
103
- {isSelected && (
104
- <Text style={[styles.checkmark, { color: accentColor }]}>✓</Text>
105
- )}
106
- </TouchableOpacity>
107
- );
108
- })}
109
- </View>
152
+ );
153
+ })}
154
+ {selectedChains.length > 3 && (
155
+ <View style={styles.previewMore}>
156
+ <Text style={styles.previewMoreText}>+{selectedChains.length - 3}</Text>
157
+ </View>
158
+ )}
159
+ {selectedChains.length === 0 && (
160
+ <Text style={styles.placeholderText}>{placeholder}</Text>
161
+ )}
162
+ </View>
163
+ <Text style={styles.dropdownArrow}>{isOpen ? '▲' : '▼'}</Text>
164
+ </TouchableOpacity>
110
165
 
111
166
  {multiSelect && selectedChains.length > 0 && (
112
- <View style={styles.selectedInfo}>
113
- <Text style={styles.selectedText}>
114
- {selectedChains.length} chain{selectedChains.length > 1 ? 's' : ''} selected
115
- </Text>
116
- </View>
167
+ <Text style={[styles.selectedCount, { color: accentColor }]}>
168
+ {selectedChains.length} chain{selectedChains.length > 1 ? 's' : ''} selected
169
+ </Text>
117
170
  )}
171
+
172
+ <Modal
173
+ visible={isOpen}
174
+ transparent
175
+ animationType="fade"
176
+ onRequestClose={() => setIsOpen(false)}
177
+ >
178
+ <Pressable style={styles.modalOverlay} onPress={() => setIsOpen(false)}>
179
+ <View style={styles.modalContent}>
180
+ <View style={styles.modalHeader}>
181
+ <Text style={styles.modalTitle}>{title || 'Select Chains'}</Text>
182
+ <TouchableOpacity onPress={() => setIsOpen(false)}>
183
+ <Text style={styles.modalClose}>✕</Text>
184
+ </TouchableOpacity>
185
+ </View>
186
+
187
+ <ScrollView style={styles.optionsList} showsVerticalScrollIndicator={false}>
188
+ {supportedChains.map((chain) => {
189
+ const chainInfo = CHAIN_CONFIG[chain] || { name: chain, icon: '●', color: '#888' };
190
+ const isSelected = selectedChains.includes(chain);
191
+
192
+ return (
193
+ <TouchableOpacity
194
+ key={chain}
195
+ style={[
196
+ styles.optionItem,
197
+ isSelected && styles.optionItemSelected,
198
+ isSelected && { backgroundColor: accentColor + '10', borderColor: accentColor }
199
+ ]}
200
+ onPress={() => handleSelect(chain)}
201
+ activeOpacity={0.7}
202
+ >
203
+ <View style={[styles.optionIconBg, { backgroundColor: chainInfo.color + '20' }]}>
204
+ <Text style={[styles.optionIcon, { color: chainInfo.color }]}>{chainInfo.icon}</Text>
205
+ </View>
206
+ <Text style={[
207
+ styles.optionText,
208
+ isSelected && { color: accentColor, fontWeight: '600' }
209
+ ]}>
210
+ {chainInfo.name}
211
+ </Text>
212
+ {isSelected ? (
213
+ <View style={[styles.checkbox, { backgroundColor: accentColor }]}>
214
+ <Text style={styles.checkboxIcon}>✓</Text>
215
+ </View>
216
+ ) : (
217
+ <View style={styles.checkboxEmpty} />
218
+ )}
219
+ </TouchableOpacity>
220
+ );
221
+ })}
222
+ </ScrollView>
223
+
224
+ {multiSelect && (
225
+ <TouchableOpacity
226
+ style={[styles.doneButton, { backgroundColor: accentColor }]}
227
+ onPress={() => setIsOpen(false)}
228
+ >
229
+ <Text style={styles.doneButtonText}>Done ({selectedChains.length})</Text>
230
+ </TouchableOpacity>
231
+ )}
232
+ </View>
233
+ </Pressable>
234
+ </Modal>
118
235
  </View>
119
236
  );
120
237
  };
@@ -134,50 +251,206 @@ const styles = StyleSheet.create({
134
251
  color: '#666',
135
252
  marginBottom: 12,
136
253
  },
137
- chainsContainer: {
254
+ // Desktop styles
255
+ desktopGrid: {
138
256
  flexDirection: 'row',
139
257
  flexWrap: 'wrap',
140
- gap: 8,
258
+ gap: 10,
141
259
  },
142
- chainChip: {
260
+ desktopChip: {
143
261
  flexDirection: 'row',
144
262
  alignItems: 'center',
145
- paddingHorizontal: 12,
146
- paddingVertical: 8,
263
+ paddingHorizontal: 14,
264
+ paddingVertical: 10,
147
265
  backgroundColor: '#fff',
148
- borderRadius: 12,
266
+ borderRadius: 10,
149
267
  borderWidth: 2,
150
- borderColor: '#e5e5e5',
151
- gap: 8,
268
+ borderColor: '#e8e8e8',
269
+ gap: 10,
270
+ cursor: 'pointer' as any,
152
271
  },
153
- chainChipSelected: {
272
+ desktopChipSelected: {
154
273
  borderWidth: 2,
155
274
  },
156
- chainIconBg: {
157
- width: 28,
158
- height: 28,
159
- borderRadius: 14,
275
+ desktopIconBg: {
276
+ width: 32,
277
+ height: 32,
278
+ borderRadius: 16,
160
279
  alignItems: 'center',
161
280
  justifyContent: 'center',
162
281
  },
163
- chainIcon: {
282
+ desktopIcon: {
164
283
  fontSize: 14,
165
284
  fontWeight: '700',
166
285
  },
167
- chainText: {
286
+ desktopChipText: {
168
287
  fontSize: 14,
169
- color: '#666',
288
+ color: '#444',
170
289
  },
171
- checkmark: {
172
- fontSize: 16,
290
+ desktopCheckbox: {
291
+ width: 20,
292
+ height: 20,
293
+ borderRadius: 10,
294
+ alignItems: 'center',
295
+ justifyContent: 'center',
296
+ marginLeft: 4,
297
+ },
298
+ desktopCheckIcon: {
299
+ fontSize: 12,
300
+ color: '#fff',
173
301
  fontWeight: '700',
174
302
  },
175
- selectedInfo: {
176
- marginTop: 8,
303
+ // Mobile dropdown styles
304
+ dropdownTrigger: {
305
+ flexDirection: 'row',
306
+ alignItems: 'center',
307
+ justifyContent: 'space-between',
308
+ paddingHorizontal: 14,
309
+ paddingVertical: 12,
310
+ backgroundColor: '#fff',
311
+ borderRadius: 12,
312
+ borderWidth: 2,
313
+ borderColor: '#e5e5e5',
314
+ minHeight: 52,
315
+ },
316
+ selectedPreview: {
317
+ flex: 1,
318
+ flexDirection: 'row',
319
+ alignItems: 'center',
320
+ gap: 6,
321
+ },
322
+ previewChip: {
323
+ width: 32,
324
+ height: 32,
325
+ borderRadius: 16,
326
+ alignItems: 'center',
327
+ justifyContent: 'center',
328
+ },
329
+ previewIcon: {
330
+ fontSize: 14,
331
+ fontWeight: '700',
332
+ },
333
+ previewMore: {
334
+ paddingHorizontal: 8,
177
335
  paddingVertical: 4,
336
+ backgroundColor: '#f0f0f0',
337
+ borderRadius: 8,
338
+ },
339
+ previewMoreText: {
340
+ fontSize: 12,
341
+ color: '#666',
342
+ fontWeight: '600',
343
+ },
344
+ placeholderText: {
345
+ fontSize: 14,
346
+ color: '#999',
347
+ },
348
+ dropdownArrow: {
349
+ fontSize: 12,
350
+ color: '#888',
351
+ marginLeft: 8,
178
352
  },
179
- selectedText: {
353
+ selectedCount: {
180
354
  fontSize: 12,
355
+ marginTop: 6,
356
+ fontWeight: '500',
357
+ },
358
+ // Modal styles
359
+ modalOverlay: {
360
+ flex: 1,
361
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
362
+ justifyContent: 'center',
363
+ alignItems: 'center',
364
+ },
365
+ modalContent: {
366
+ width: '85%',
367
+ maxWidth: 340,
368
+ maxHeight: '70%',
369
+ backgroundColor: '#fff',
370
+ borderRadius: 16,
371
+ overflow: 'hidden',
372
+ },
373
+ modalHeader: {
374
+ flexDirection: 'row',
375
+ justifyContent: 'space-between',
376
+ alignItems: 'center',
377
+ paddingHorizontal: 16,
378
+ paddingVertical: 14,
379
+ borderBottomWidth: 1,
380
+ borderBottomColor: '#f0f0f0',
381
+ },
382
+ modalTitle: {
383
+ fontSize: 18,
384
+ fontWeight: '700',
385
+ color: '#1a1a1a',
386
+ },
387
+ modalClose: {
388
+ fontSize: 20,
181
389
  color: '#888',
390
+ padding: 4,
391
+ },
392
+ optionsList: {
393
+ padding: 8,
394
+ },
395
+ optionItem: {
396
+ flexDirection: 'row',
397
+ alignItems: 'center',
398
+ paddingHorizontal: 12,
399
+ paddingVertical: 12,
400
+ borderRadius: 10,
401
+ borderWidth: 1,
402
+ borderColor: 'transparent',
403
+ marginBottom: 6,
404
+ gap: 12,
405
+ },
406
+ optionItemSelected: {
407
+ borderWidth: 1,
408
+ },
409
+ optionIconBg: {
410
+ width: 36,
411
+ height: 36,
412
+ borderRadius: 18,
413
+ alignItems: 'center',
414
+ justifyContent: 'center',
415
+ },
416
+ optionIcon: {
417
+ fontSize: 16,
418
+ fontWeight: '700',
419
+ },
420
+ optionText: {
421
+ flex: 1,
422
+ fontSize: 15,
423
+ color: '#333',
424
+ },
425
+ checkbox: {
426
+ width: 24,
427
+ height: 24,
428
+ borderRadius: 12,
429
+ alignItems: 'center',
430
+ justifyContent: 'center',
431
+ },
432
+ checkboxIcon: {
433
+ fontSize: 14,
434
+ color: '#fff',
435
+ fontWeight: '700',
436
+ },
437
+ checkboxEmpty: {
438
+ width: 24,
439
+ height: 24,
440
+ borderRadius: 12,
441
+ borderWidth: 2,
442
+ borderColor: '#ddd',
443
+ },
444
+ doneButton: {
445
+ marginHorizontal: 16,
446
+ marginVertical: 12,
447
+ paddingVertical: 14,
448
+ borderRadius: 10,
449
+ alignItems: 'center',
450
+ },
451
+ doneButtonText: {
452
+ fontSize: 16,
453
+ fontWeight: '600',
454
+ color: '#fff',
182
455
  },
183
456
  });