@one_deploy/sdk 1.0.3 → 1.0.5

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.
Files changed (53) hide show
  1. package/dist/{engine-CrlhH0nw.d.mts → engine-BeVuHpVx.d.mts} +163 -0
  2. package/dist/{engine-5ndtBaCr.d.ts → engine-DSc1Em4V.d.ts} +163 -0
  3. package/dist/hooks/index.d.mts +132 -3
  4. package/dist/hooks/index.d.ts +132 -3
  5. package/dist/hooks/index.js +351 -0
  6. package/dist/hooks/index.js.map +1 -1
  7. package/dist/hooks/index.mjs +345 -2
  8. package/dist/hooks/index.mjs.map +1 -1
  9. package/dist/index.d.mts +3 -3
  10. package/dist/index.d.ts +3 -3
  11. package/dist/index.js +352 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +345 -2
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/providers/index.d.mts +1 -1
  16. package/dist/providers/index.d.ts +1 -1
  17. package/dist/providers/index.js +98 -0
  18. package/dist/providers/index.js.map +1 -1
  19. package/dist/providers/index.mjs +98 -0
  20. package/dist/providers/index.mjs.map +1 -1
  21. package/dist/react-native.d.mts +140 -3
  22. package/dist/react-native.d.ts +140 -3
  23. package/dist/react-native.js +642 -0
  24. package/dist/react-native.js.map +1 -1
  25. package/dist/react-native.mjs +636 -1
  26. package/dist/react-native.mjs.map +1 -1
  27. package/dist/services/index.d.mts +99 -79
  28. package/dist/services/index.d.ts +99 -79
  29. package/dist/services/index.js +254 -0
  30. package/dist/services/index.js.map +1 -1
  31. package/dist/services/index.mjs +252 -1
  32. package/dist/services/index.mjs.map +1 -1
  33. package/dist/supabase-BT0c7q9e.d.mts +82 -0
  34. package/dist/supabase-BT0c7q9e.d.ts +82 -0
  35. package/package.json +5 -1
  36. package/src/components/OneSwapWidget.tsx +1 -1
  37. package/src/components/ai/OneChainSelector.tsx +183 -0
  38. package/src/components/ai/OneCycleSelector.tsx +187 -0
  39. package/src/components/ai/OnePairSelector.tsx +181 -0
  40. package/src/components/ai/OneTierSelector.tsx +187 -0
  41. package/src/components/ai/index.ts +17 -0
  42. package/src/components/index.ts +3 -0
  43. package/src/hooks/index.ts +20 -0
  44. package/src/hooks/useAITrading.ts +444 -0
  45. package/src/index.ts +20 -0
  46. package/src/react-native.ts +23 -0
  47. package/src/services/engine.ts +184 -0
  48. package/src/services/index.ts +16 -0
  49. package/src/services/usage.ts +249 -0
  50. package/.turbo/turbo-build.log +0 -0
  51. package/.turbo/turbo-type-check.log +0 -0
  52. package/tsconfig.json +0 -22
  53. package/tsup.config.ts +0 -25
@@ -0,0 +1,82 @@
1
+ import * as _supabase_supabase_js from '@supabase/supabase-js';
2
+ import { SupabaseClient } from '@supabase/supabase-js';
3
+
4
+ declare function createSupabaseClient(url?: string, anonKey?: string): SupabaseClient;
5
+ declare function getSupabaseClient(): SupabaseClient;
6
+ declare class SupabaseService {
7
+ private client;
8
+ constructor(client?: SupabaseClient);
9
+ signInWithEmail(email: string): Promise<{
10
+ data: {
11
+ user: null;
12
+ session: null;
13
+ messageId?: string | null;
14
+ } | {
15
+ user: null;
16
+ session: null;
17
+ messageId?: null | undefined;
18
+ };
19
+ error: _supabase_supabase_js.AuthError | null;
20
+ }>;
21
+ verifyOtp(email: string, token: string): Promise<{
22
+ data: {
23
+ user: _supabase_supabase_js.AuthUser | null;
24
+ session: _supabase_supabase_js.AuthSession | null;
25
+ } | {
26
+ user: null;
27
+ session: null;
28
+ };
29
+ error: _supabase_supabase_js.AuthError | null;
30
+ }>;
31
+ signOut(): Promise<{
32
+ error: _supabase_supabase_js.AuthError | null;
33
+ }>;
34
+ getSession(): Promise<{
35
+ session: _supabase_supabase_js.AuthSession | null;
36
+ error: _supabase_supabase_js.AuthError | null;
37
+ }>;
38
+ getUser(): Promise<{
39
+ user: _supabase_supabase_js.AuthUser | null;
40
+ error: _supabase_supabase_js.AuthError | null;
41
+ }>;
42
+ getUserProfile(userId: string): Promise<{
43
+ data: any;
44
+ error: _supabase_supabase_js.PostgrestError | null;
45
+ }>;
46
+ updateUserProfile(userId: string, updates: Record<string, any>): Promise<{
47
+ data: any;
48
+ error: _supabase_supabase_js.PostgrestError | null;
49
+ }>;
50
+ getTransactions(userId: string, limit?: number): Promise<{
51
+ data: any[] | null;
52
+ error: _supabase_supabase_js.PostgrestError | null;
53
+ }>;
54
+ createTransaction(transaction: Record<string, any>): Promise<{
55
+ data: any;
56
+ error: _supabase_supabase_js.PostgrestError | null;
57
+ }>;
58
+ getStrategies(status?: string): Promise<{
59
+ data: any[] | null;
60
+ error: _supabase_supabase_js.PostgrestError | null;
61
+ }>;
62
+ getStrategyById(strategyId: string): Promise<{
63
+ data: any;
64
+ error: _supabase_supabase_js.PostgrestError | null;
65
+ }>;
66
+ getUserOrders(userId: string): Promise<{
67
+ data: any[] | null;
68
+ error: _supabase_supabase_js.PostgrestError | null;
69
+ }>;
70
+ createOrder(order: Record<string, any>): Promise<{
71
+ data: any;
72
+ error: _supabase_supabase_js.PostgrestError | null;
73
+ }>;
74
+ getUserCards(userId: string): Promise<{
75
+ data: any[] | null;
76
+ error: _supabase_supabase_js.PostgrestError | null;
77
+ }>;
78
+ subscribeToTransactions(userId: string, callback: (payload: any) => void): _supabase_supabase_js.RealtimeChannel;
79
+ unsubscribe(channel: ReturnType<typeof this$1.client.channel>): Promise<"error" | "ok" | "timed out">;
80
+ }
81
+
82
+ export { SupabaseService as S, createSupabaseClient as c, getSupabaseClient as g };
@@ -0,0 +1,82 @@
1
+ import * as _supabase_supabase_js from '@supabase/supabase-js';
2
+ import { SupabaseClient } from '@supabase/supabase-js';
3
+
4
+ declare function createSupabaseClient(url?: string, anonKey?: string): SupabaseClient;
5
+ declare function getSupabaseClient(): SupabaseClient;
6
+ declare class SupabaseService {
7
+ private client;
8
+ constructor(client?: SupabaseClient);
9
+ signInWithEmail(email: string): Promise<{
10
+ data: {
11
+ user: null;
12
+ session: null;
13
+ messageId?: string | null;
14
+ } | {
15
+ user: null;
16
+ session: null;
17
+ messageId?: null | undefined;
18
+ };
19
+ error: _supabase_supabase_js.AuthError | null;
20
+ }>;
21
+ verifyOtp(email: string, token: string): Promise<{
22
+ data: {
23
+ user: _supabase_supabase_js.AuthUser | null;
24
+ session: _supabase_supabase_js.AuthSession | null;
25
+ } | {
26
+ user: null;
27
+ session: null;
28
+ };
29
+ error: _supabase_supabase_js.AuthError | null;
30
+ }>;
31
+ signOut(): Promise<{
32
+ error: _supabase_supabase_js.AuthError | null;
33
+ }>;
34
+ getSession(): Promise<{
35
+ session: _supabase_supabase_js.AuthSession | null;
36
+ error: _supabase_supabase_js.AuthError | null;
37
+ }>;
38
+ getUser(): Promise<{
39
+ user: _supabase_supabase_js.AuthUser | null;
40
+ error: _supabase_supabase_js.AuthError | null;
41
+ }>;
42
+ getUserProfile(userId: string): Promise<{
43
+ data: any;
44
+ error: _supabase_supabase_js.PostgrestError | null;
45
+ }>;
46
+ updateUserProfile(userId: string, updates: Record<string, any>): Promise<{
47
+ data: any;
48
+ error: _supabase_supabase_js.PostgrestError | null;
49
+ }>;
50
+ getTransactions(userId: string, limit?: number): Promise<{
51
+ data: any[] | null;
52
+ error: _supabase_supabase_js.PostgrestError | null;
53
+ }>;
54
+ createTransaction(transaction: Record<string, any>): Promise<{
55
+ data: any;
56
+ error: _supabase_supabase_js.PostgrestError | null;
57
+ }>;
58
+ getStrategies(status?: string): Promise<{
59
+ data: any[] | null;
60
+ error: _supabase_supabase_js.PostgrestError | null;
61
+ }>;
62
+ getStrategyById(strategyId: string): Promise<{
63
+ data: any;
64
+ error: _supabase_supabase_js.PostgrestError | null;
65
+ }>;
66
+ getUserOrders(userId: string): Promise<{
67
+ data: any[] | null;
68
+ error: _supabase_supabase_js.PostgrestError | null;
69
+ }>;
70
+ createOrder(order: Record<string, any>): Promise<{
71
+ data: any;
72
+ error: _supabase_supabase_js.PostgrestError | null;
73
+ }>;
74
+ getUserCards(userId: string): Promise<{
75
+ data: any[] | null;
76
+ error: _supabase_supabase_js.PostgrestError | null;
77
+ }>;
78
+ subscribeToTransactions(userId: string, callback: (payload: any) => void): _supabase_supabase_js.RealtimeChannel;
79
+ unsubscribe(channel: ReturnType<typeof this$1.client.channel>): Promise<"error" | "ok" | "timed out">;
80
+ }
81
+
82
+ export { SupabaseService as S, createSupabaseClient as c, getSupabaseClient as g };
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "@one_deploy/sdk",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "ONE Ecosystem SDK - Shared services, types, utilities, and React providers",
5
+ "files": [
6
+ "dist",
7
+ "src"
8
+ ],
5
9
  "main": "./dist/index.js",
6
10
  "module": "./dist/index.mjs",
7
11
  "types": "./dist/index.d.ts",
@@ -102,7 +102,7 @@ const TOKENS_BY_CHAIN: Record<number, SwapToken[]> = {
102
102
  { address: '0x0000000000000000000000000000000000000000', symbol: 'ETH', name: 'Ethereum', decimals: 18, chainId: 1 },
103
103
  { address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', symbol: 'USDC', name: 'USD Coin', decimals: 6, chainId: 1 },
104
104
  { address: '0xdAC17F958D2ee523a2206206994597C13D831ec7', symbol: 'USDT', name: 'Tether', decimals: 6, chainId: 1 },
105
- { address: '0x6B175474E89094C44Da98b954EescdeCB5', symbol: 'DAI', name: 'Dai', decimals: 18, chainId: 1 },
105
+ { address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', symbol: 'DAI', name: 'Dai', decimals: 18, chainId: 1 },
106
106
  { address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', symbol: 'WETH', name: 'Wrapped Ether', decimals: 18, chainId: 1 },
107
107
  ],
108
108
  // Base
@@ -0,0 +1,183 @@
1
+ /**
2
+ * OneChainSelector - Multi-chain selection component for AI trading
3
+ * Part of ONE Ecosystem SDK - can be used by any ecosystem partner
4
+ */
5
+
6
+ import React from 'react';
7
+ import { View, Text, StyleSheet, TouchableOpacity, ViewStyle, TextStyle } from 'react-native';
8
+
9
+ // Chain configuration with branding
10
+ export const CHAIN_CONFIG: Record<string, { name: string; icon: string; color: string }> = {
11
+ ethereum: { name: 'Ethereum', icon: 'Ξ', color: '#627EEA' },
12
+ arbitrum: { name: 'Arbitrum', icon: '◆', color: '#28A0F0' },
13
+ bsc: { name: 'BSC', icon: '◆', color: '#F3BA2F' },
14
+ base: { name: 'Base', icon: '●', color: '#0052FF' },
15
+ polygon: { name: 'Polygon', icon: '⬡', color: '#8247E5' },
16
+ optimism: { name: 'Optimism', icon: '◉', color: '#FF0420' },
17
+ avalanche: { name: 'Avalanche', icon: '▲', color: '#E84142' },
18
+ linea: { name: 'Linea', icon: '═', color: '#121212' },
19
+ zksync: { name: 'zkSync', icon: '⬢', color: '#8C8DFC' },
20
+ scroll: { name: 'Scroll', icon: '◎', color: '#FFEEDA' },
21
+ };
22
+
23
+ export interface OneChainSelectorProps {
24
+ /** List of supported chain IDs */
25
+ supportedChains: string[];
26
+ /** Currently selected chains */
27
+ selectedChains: string[];
28
+ /** Callback when chain selection changes */
29
+ onSelectChain: (chain: string) => void;
30
+ /** Enable multi-select (default: true) */
31
+ multiSelect?: boolean;
32
+ /** Accent color for selected state */
33
+ accentColor?: string;
34
+ /** Section title */
35
+ title?: string;
36
+ /** Section subtitle */
37
+ subtitle?: string;
38
+ /** Minimum required selections (for multi-select) */
39
+ minSelections?: number;
40
+ /** Custom styles */
41
+ style?: ViewStyle;
42
+ /** Custom title style */
43
+ titleStyle?: TextStyle;
44
+ }
45
+
46
+ export const OneChainSelector: React.FC<OneChainSelectorProps> = ({
47
+ supportedChains,
48
+ selectedChains,
49
+ onSelectChain,
50
+ multiSelect = true,
51
+ accentColor = '#188775',
52
+ title,
53
+ subtitle,
54
+ minSelections = 1,
55
+ style,
56
+ titleStyle,
57
+ }) => {
58
+ const handleSelect = (chain: string) => {
59
+ if (multiSelect) {
60
+ // In multi-select, prevent deselecting if at minimum
61
+ if (selectedChains.includes(chain) && selectedChains.length <= minSelections) {
62
+ return;
63
+ }
64
+ onSelectChain(chain);
65
+ } else {
66
+ // Single select - always allow selection
67
+ if (!selectedChains.includes(chain)) {
68
+ onSelectChain(chain);
69
+ }
70
+ }
71
+ };
72
+
73
+ return (
74
+ <View style={[styles.container, style]}>
75
+ {title && <Text style={[styles.title, titleStyle]}>{title}</Text>}
76
+ {subtitle && <Text style={styles.subtitle}>{subtitle}</Text>}
77
+
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>
96
+ </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>
110
+
111
+ {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>
117
+ )}
118
+ </View>
119
+ );
120
+ };
121
+
122
+ const styles = StyleSheet.create({
123
+ container: {
124
+ marginBottom: 16,
125
+ },
126
+ title: {
127
+ fontSize: 16,
128
+ fontWeight: '600',
129
+ color: '#1a1a1a',
130
+ marginBottom: 4,
131
+ },
132
+ subtitle: {
133
+ fontSize: 12,
134
+ color: '#666',
135
+ marginBottom: 12,
136
+ },
137
+ chainsContainer: {
138
+ flexDirection: 'row',
139
+ flexWrap: 'wrap',
140
+ gap: 8,
141
+ },
142
+ chainChip: {
143
+ flexDirection: 'row',
144
+ alignItems: 'center',
145
+ paddingHorizontal: 12,
146
+ paddingVertical: 8,
147
+ backgroundColor: '#fff',
148
+ borderRadius: 12,
149
+ borderWidth: 2,
150
+ borderColor: '#e5e5e5',
151
+ gap: 8,
152
+ },
153
+ chainChipSelected: {
154
+ borderWidth: 2,
155
+ },
156
+ chainIconBg: {
157
+ width: 28,
158
+ height: 28,
159
+ borderRadius: 14,
160
+ alignItems: 'center',
161
+ justifyContent: 'center',
162
+ },
163
+ chainIcon: {
164
+ fontSize: 14,
165
+ fontWeight: '700',
166
+ },
167
+ chainText: {
168
+ fontSize: 14,
169
+ color: '#666',
170
+ },
171
+ checkmark: {
172
+ fontSize: 16,
173
+ fontWeight: '700',
174
+ },
175
+ selectedInfo: {
176
+ marginTop: 8,
177
+ paddingVertical: 4,
178
+ },
179
+ selectedText: {
180
+ fontSize: 12,
181
+ color: '#888',
182
+ },
183
+ });
@@ -0,0 +1,187 @@
1
+ /**
2
+ * OneCycleSelector - Investment cycle selection component for AI trading
3
+ * Part of ONE Ecosystem SDK - can be used by any ecosystem partner
4
+ */
5
+
6
+ import React from 'react';
7
+ import { View, Text, StyleSheet, TouchableOpacity, ViewStyle, TextStyle } from 'react-native';
8
+
9
+ // Default share rates by cycle (platform takes this percentage)
10
+ export const DEFAULT_SHARE_RATES: Record<number, number> = {
11
+ 7: 25,
12
+ 14: 22,
13
+ 30: 18,
14
+ 60: 15,
15
+ 90: 12,
16
+ };
17
+
18
+ export interface OneCycleSelectorProps {
19
+ /** List of supported cycle days */
20
+ supportedCycles: number[];
21
+ /** Currently selected cycle */
22
+ selectedCycle: number;
23
+ /** Callback when cycle selection changes */
24
+ onSelectCycle: (cycle: number) => void;
25
+ /** Accent color for selected state */
26
+ accentColor?: string;
27
+ /** Section title */
28
+ title?: string;
29
+ /** Section subtitle */
30
+ subtitle?: string;
31
+ /** Custom share rates by cycle (overrides defaults) */
32
+ shareRates?: Record<number, number>;
33
+ /** Days label */
34
+ daysLabel?: string;
35
+ /** Your share label */
36
+ yourShareLabel?: string;
37
+ /** Platform fee label */
38
+ platformFeeLabel?: string;
39
+ /** Custom styles */
40
+ style?: ViewStyle;
41
+ /** Custom title style */
42
+ titleStyle?: TextStyle;
43
+ }
44
+
45
+ export const OneCycleSelector: React.FC<OneCycleSelectorProps> = ({
46
+ supportedCycles,
47
+ selectedCycle,
48
+ onSelectCycle,
49
+ accentColor = '#188775',
50
+ title,
51
+ subtitle,
52
+ shareRates = DEFAULT_SHARE_RATES,
53
+ daysLabel = 'days',
54
+ yourShareLabel = 'Your share',
55
+ platformFeeLabel = 'Platform fee',
56
+ style,
57
+ titleStyle,
58
+ }) => {
59
+ return (
60
+ <View style={[styles.container, style]}>
61
+ {title && <Text style={[styles.title, titleStyle]}>{title}</Text>}
62
+ {subtitle && <Text style={styles.subtitle}>{subtitle}</Text>}
63
+
64
+ <View style={styles.cyclesContainer}>
65
+ {supportedCycles.map((cycle) => {
66
+ const isSelected = selectedCycle === cycle;
67
+ const shareRate = shareRates[cycle] || 20;
68
+ const userRate = 100 - shareRate;
69
+
70
+ return (
71
+ <TouchableOpacity
72
+ key={cycle}
73
+ style={[
74
+ styles.cycleOption,
75
+ isSelected && styles.cycleOptionSelected,
76
+ isSelected && { borderColor: accentColor, backgroundColor: accentColor + '10' }
77
+ ]}
78
+ onPress={() => onSelectCycle(cycle)}
79
+ activeOpacity={0.7}
80
+ >
81
+ <Text style={[
82
+ styles.cycleDays,
83
+ isSelected && { color: accentColor }
84
+ ]}>
85
+ {cycle}
86
+ </Text>
87
+ <Text style={styles.cycleDaysLabel}>{daysLabel}</Text>
88
+
89
+ <View style={styles.cycleEarnings}>
90
+ <Text style={[
91
+ styles.cycleEarningsValue,
92
+ isSelected && { color: accentColor }
93
+ ]}>
94
+ {userRate}%
95
+ </Text>
96
+ <Text style={styles.cycleEarningsLabel}>{yourShareLabel}</Text>
97
+ </View>
98
+
99
+ <Text style={styles.cycleFee}>
100
+ {shareRate}% {platformFeeLabel}
101
+ </Text>
102
+ </TouchableOpacity>
103
+ );
104
+ })}
105
+ </View>
106
+
107
+ <View style={styles.infoBox}>
108
+ <Text style={styles.infoText}>
109
+ Longer cycles = higher user share
110
+ </Text>
111
+ </View>
112
+ </View>
113
+ );
114
+ };
115
+
116
+ const styles = StyleSheet.create({
117
+ container: {
118
+ marginBottom: 16,
119
+ },
120
+ title: {
121
+ fontSize: 16,
122
+ fontWeight: '600',
123
+ color: '#1a1a1a',
124
+ marginBottom: 4,
125
+ },
126
+ subtitle: {
127
+ fontSize: 12,
128
+ color: '#666',
129
+ marginBottom: 12,
130
+ },
131
+ cyclesContainer: {
132
+ flexDirection: 'row',
133
+ flexWrap: 'wrap',
134
+ gap: 8,
135
+ },
136
+ cycleOption: {
137
+ flex: 1,
138
+ minWidth: '45%',
139
+ padding: 16,
140
+ borderRadius: 12,
141
+ borderWidth: 2,
142
+ borderColor: '#e5e5e5',
143
+ backgroundColor: '#fff',
144
+ alignItems: 'center',
145
+ },
146
+ cycleOptionSelected: {
147
+ borderWidth: 2,
148
+ },
149
+ cycleDays: {
150
+ fontSize: 28,
151
+ fontWeight: '700',
152
+ color: '#1a1a1a',
153
+ },
154
+ cycleDaysLabel: {
155
+ fontSize: 12,
156
+ color: '#666',
157
+ marginBottom: 8,
158
+ },
159
+ cycleEarnings: {
160
+ alignItems: 'center',
161
+ },
162
+ cycleEarningsValue: {
163
+ fontSize: 18,
164
+ fontWeight: '700',
165
+ color: '#10B981',
166
+ },
167
+ cycleEarningsLabel: {
168
+ fontSize: 11,
169
+ color: '#666',
170
+ },
171
+ cycleFee: {
172
+ fontSize: 11,
173
+ color: '#888',
174
+ marginTop: 4,
175
+ },
176
+ infoBox: {
177
+ marginTop: 12,
178
+ padding: 8,
179
+ backgroundColor: '#f5f5f5',
180
+ borderRadius: 8,
181
+ },
182
+ infoText: {
183
+ fontSize: 12,
184
+ color: '#666',
185
+ textAlign: 'center',
186
+ },
187
+ });