@sudobility/components-rn 1.0.42 → 1.0.43
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/dist/index.cjs.js +895 -299
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +896 -300
- package/dist/index.esm.js.map +1 -1
- package/dist/ui/Avatar/Avatar.d.ts.map +1 -1
- package/dist/ui/Breadcrumb/Breadcrumb.d.ts.map +1 -1
- package/dist/ui/BreadcrumbNav/BreadcrumbNav.d.ts.map +1 -1
- package/dist/ui/CTASection/CTASection.d.ts.map +1 -1
- package/dist/ui/Calendar/Calendar.d.ts.map +1 -1
- package/dist/ui/ChainBadge/ChainBadge.d.ts.map +1 -1
- package/dist/ui/Checkbox/Checkbox.d.ts +0 -22
- package/dist/ui/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/ui/Code/Code.d.ts +0 -17
- package/dist/ui/Code/Code.d.ts.map +1 -1
- package/dist/ui/CodeDisplay/CodeDisplay.d.ts +0 -21
- package/dist/ui/CodeDisplay/CodeDisplay.d.ts.map +1 -1
- package/dist/ui/CollapsibleSection/CollapsibleSection.d.ts.map +1 -1
- package/dist/ui/Combobox/Combobox.d.ts.map +1 -1
- package/dist/ui/Command/Command.d.ts.map +1 -1
- package/dist/ui/DashboardStatCard/DashboardStatCard.d.ts +0 -17
- package/dist/ui/DashboardStatCard/DashboardStatCard.d.ts.map +1 -1
- package/dist/ui/DataList/DataList.d.ts.map +1 -1
- package/dist/ui/Dropdown/Dropdown.d.ts.map +1 -1
- package/dist/ui/ExternalLink/ExternalLink.d.ts.map +1 -1
- package/dist/ui/FeatureCard/FeatureCard.d.ts.map +1 -1
- package/dist/ui/FeatureGrid/FeatureGrid.d.ts.map +1 -1
- package/dist/ui/GradientIconContainer/GradientIconContainer.d.ts +0 -13
- package/dist/ui/GradientIconContainer/GradientIconContainer.d.ts.map +1 -1
- package/dist/ui/HelperText/HelperText.d.ts.map +1 -1
- package/dist/ui/IconContainer/IconContainer.d.ts +0 -13
- package/dist/ui/IconContainer/IconContainer.d.ts.map +1 -1
- package/dist/ui/IconText/IconText.d.ts.map +1 -1
- package/dist/ui/InfiniteScroll/InfiniteScroll.d.ts.map +1 -1
- package/dist/ui/KeyValuePair/KeyValuePair.d.ts.map +1 -1
- package/dist/ui/Link/Link.d.ts.map +1 -1
- package/dist/ui/ListItemWithAction/ListItemWithAction.d.ts.map +1 -1
- package/dist/ui/Modal/Modal.d.ts.map +1 -1
- package/dist/ui/MultiSelect/MultiSelect.d.ts.map +1 -1
- package/dist/ui/NavigationList/NavigationList.d.ts.map +1 -1
- package/dist/ui/PageSectionHeader/PageSectionHeader.d.ts.map +1 -1
- package/dist/ui/Pagination/Pagination.d.ts.map +1 -1
- package/dist/ui/PhoneInput/PhoneInput.d.ts.map +1 -1
- package/dist/ui/PopupSelect/PopupSelect.d.ts.map +1 -1
- package/dist/ui/Progress/Progress.d.ts +0 -15
- package/dist/ui/Progress/Progress.d.ts.map +1 -1
- package/dist/ui/PromotionalBanner/PromotionalBanner.d.ts.map +1 -1
- package/dist/ui/SearchInput/SearchInput.d.ts.map +1 -1
- package/dist/ui/SectionHeader/SectionHeader.d.ts.map +1 -1
- package/dist/ui/Select/Select.d.ts.map +1 -1
- package/dist/ui/SettingsList/SettingsList.d.ts.map +1 -1
- package/dist/ui/Sheet/Sheet.d.ts.map +1 -1
- package/dist/ui/SideNav/SideNav.d.ts.map +1 -1
- package/dist/ui/SmartLink/SmartLink.d.ts.map +1 -1
- package/dist/ui/StatDisplay/StatDisplay.d.ts +0 -12
- package/dist/ui/StatDisplay/StatDisplay.d.ts.map +1 -1
- package/dist/ui/StepList/StepList.d.ts.map +1 -1
- package/dist/ui/Table/Table.d.ts.map +1 -1
- package/dist/ui/Tabs/Tabs.d.ts.map +1 -1
- package/dist/ui/TextArea/TextArea.d.ts.map +1 -1
- package/dist/ui/TextInputModal/TextInputModal.d.ts.map +1 -1
- package/dist/ui/Tooltip/Tooltip.d.ts +0 -20
- package/dist/ui/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/ui/TransferList/TransferList.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ui/Avatar/Avatar.tsx +6 -5
- package/src/ui/Breadcrumb/Breadcrumb.tsx +8 -5
- package/src/ui/BreadcrumbNav/BreadcrumbNav.tsx +22 -3
- package/src/ui/CTASection/CTASection.tsx +8 -6
- package/src/ui/Calendar/Calendar.tsx +35 -6
- package/src/ui/ChainBadge/ChainBadge.tsx +67 -42
- package/src/ui/Checkbox/Checkbox.tsx +47 -20
- package/src/ui/Code/Code.tsx +51 -21
- package/src/ui/CodeDisplay/CodeDisplay.tsx +46 -20
- package/src/ui/CollapsibleSection/CollapsibleSection.tsx +7 -3
- package/src/ui/Combobox/Combobox.tsx +2 -1
- package/src/ui/Command/Command.tsx +2 -1
- package/src/ui/DashboardStatCard/DashboardStatCard.tsx +29 -11
- package/src/ui/DataList/DataList.tsx +23 -5
- package/src/ui/Dropdown/Dropdown.tsx +4 -1
- package/src/ui/ExternalLink/ExternalLink.tsx +5 -4
- package/src/ui/FeatureCard/FeatureCard.tsx +60 -29
- package/src/ui/FeatureGrid/FeatureGrid.tsx +7 -7
- package/src/ui/GradientIconContainer/GradientIconContainer.tsx +33 -8
- package/src/ui/HelperText/HelperText.tsx +9 -8
- package/src/ui/IconContainer/IconContainer.tsx +26 -9
- package/src/ui/IconText/IconText.tsx +6 -5
- package/src/ui/InfiniteScroll/InfiniteScroll.tsx +2 -1
- package/src/ui/KeyValuePair/KeyValuePair.tsx +12 -5
- package/src/ui/Link/Link.tsx +6 -5
- package/src/ui/ListItemWithAction/ListItemWithAction.tsx +2 -1
- package/src/ui/Modal/Modal.tsx +16 -2
- package/src/ui/MultiSelect/MultiSelect.tsx +2 -1
- package/src/ui/NavigationList/NavigationList.tsx +17 -3
- package/src/ui/PageSectionHeader/PageSectionHeader.tsx +2 -1
- package/src/ui/Pagination/Pagination.tsx +9 -6
- package/src/ui/PhoneInput/PhoneInput.tsx +3 -2
- package/src/ui/PopupSelect/PopupSelect.tsx +15 -14
- package/src/ui/Progress/Progress.tsx +63 -14
- package/src/ui/PromotionalBanner/PromotionalBanner.tsx +7 -4
- package/src/ui/SearchInput/SearchInput.tsx +3 -2
- package/src/ui/SectionHeader/SectionHeader.tsx +4 -1
- package/src/ui/Select/Select.tsx +20 -5
- package/src/ui/SettingsList/SettingsList.tsx +4 -1
- package/src/ui/Sheet/Sheet.tsx +20 -3
- package/src/ui/SideNav/SideNav.tsx +11 -2
- package/src/ui/SmartLink/SmartLink.tsx +6 -3
- package/src/ui/Spinner/Spinner.tsx +1 -1
- package/src/ui/StatDisplay/StatDisplay.tsx +59 -23
- package/src/ui/StepList/StepList.tsx +25 -3
- package/src/ui/Table/Table.tsx +22 -9
- package/src/ui/Tabs/Tabs.tsx +7 -2
- package/src/ui/TextArea/TextArea.tsx +2 -1
- package/src/ui/TextInputModal/TextInputModal.tsx +2 -1
- package/src/ui/Tooltip/Tooltip.tsx +47 -9
- package/src/ui/TransferList/TransferList.tsx +2 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { View, Text, ScrollView } from 'react-native';
|
|
3
3
|
import { cn } from '../../lib/utils';
|
|
4
|
+
import { colors, designTokens } from '@sudobility/design';
|
|
4
5
|
|
|
5
6
|
export interface CodeDisplayProps {
|
|
6
7
|
/** Code or text to display */
|
|
@@ -40,6 +41,36 @@ export interface CodeDisplayProps {
|
|
|
40
41
|
* </CodeDisplay>
|
|
41
42
|
* ```
|
|
42
43
|
*/
|
|
44
|
+
|
|
45
|
+
// Lazily derive display colors from DS to avoid ESM issues in tests.
|
|
46
|
+
let _displayColors: ReturnType<typeof buildDisplayColors> | null = null;
|
|
47
|
+
function getDisplayColors() {
|
|
48
|
+
if (!_displayColors) _displayColors = buildDisplayColors();
|
|
49
|
+
return _displayColors;
|
|
50
|
+
}
|
|
51
|
+
function buildDisplayColors() {
|
|
52
|
+
const alert = colors.component.alert;
|
|
53
|
+
function splitClasses(base: string, dark: string) {
|
|
54
|
+
const all = `${base} ${dark}`.split(' ');
|
|
55
|
+
return {
|
|
56
|
+
text: all.filter(c => c.includes('text-')).join(' '),
|
|
57
|
+
bg: all.filter(c => c.includes('bg-')).join(' '),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const info = splitClasses(alert.info.base, alert.info.dark);
|
|
61
|
+
const success = splitClasses(alert.success.base, alert.success.dark);
|
|
62
|
+
const warning = splitClasses(alert.warning.base, alert.warning.dark);
|
|
63
|
+
return {
|
|
64
|
+
primary: `${info.text} ${info.bg}`,
|
|
65
|
+
// secondary uses purple — no DS mapping, keep local
|
|
66
|
+
secondary:
|
|
67
|
+
'text-purple-600 dark:text-purple-400 bg-purple-50 dark:bg-purple-900/30',
|
|
68
|
+
success: `${success.text} ${success.bg}`,
|
|
69
|
+
warning: `${warning.text} ${warning.bg}`,
|
|
70
|
+
neutral: 'text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-800',
|
|
71
|
+
} as Record<string, string>;
|
|
72
|
+
}
|
|
73
|
+
|
|
43
74
|
export const CodeDisplay: React.FC<CodeDisplayProps> = ({
|
|
44
75
|
children,
|
|
45
76
|
variant = 'primary',
|
|
@@ -49,34 +80,25 @@ export const CodeDisplay: React.FC<CodeDisplayProps> = ({
|
|
|
49
80
|
wrap = false,
|
|
50
81
|
className,
|
|
51
82
|
}) => {
|
|
52
|
-
// Color variant configurations
|
|
53
|
-
const variantClasses =
|
|
54
|
-
primary: 'text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/30',
|
|
55
|
-
secondary:
|
|
56
|
-
'text-purple-600 dark:text-purple-400 bg-purple-50 dark:bg-purple-900/30',
|
|
57
|
-
success:
|
|
58
|
-
'text-green-600 dark:text-green-400 bg-green-50 dark:bg-green-900/30',
|
|
59
|
-
warning:
|
|
60
|
-
'text-yellow-700 dark:text-yellow-400 bg-yellow-50 dark:bg-yellow-900/30',
|
|
61
|
-
neutral: 'text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-800',
|
|
62
|
-
};
|
|
83
|
+
// Color variant configurations from DS
|
|
84
|
+
const variantClasses = getDisplayColors();
|
|
63
85
|
|
|
64
|
-
// Size configurations
|
|
86
|
+
// Size configurations using DS typography tokens
|
|
65
87
|
const sizeClasses = {
|
|
66
88
|
xs: {
|
|
67
|
-
text:
|
|
89
|
+
text: designTokens.typography.size.xs,
|
|
68
90
|
padding: inline ? 'px-1.5 py-0.5' : 'px-2 py-1',
|
|
69
91
|
},
|
|
70
92
|
sm: {
|
|
71
|
-
text:
|
|
93
|
+
text: designTokens.typography.size.sm,
|
|
72
94
|
padding: inline ? 'px-2 py-0.5' : 'px-3 py-1.5',
|
|
73
95
|
},
|
|
74
96
|
md: {
|
|
75
|
-
text:
|
|
97
|
+
text: designTokens.typography.size.base,
|
|
76
98
|
padding: inline ? 'px-2.5 py-1' : 'px-4 py-2',
|
|
77
99
|
},
|
|
78
100
|
lg: {
|
|
79
|
-
text:
|
|
101
|
+
text: designTokens.typography.size.lg,
|
|
80
102
|
padding: inline ? 'px-3 py-1' : 'px-4 py-2',
|
|
81
103
|
},
|
|
82
104
|
};
|
|
@@ -90,14 +112,18 @@ export const CodeDisplay: React.FC<CodeDisplayProps> = ({
|
|
|
90
112
|
|
|
91
113
|
const sizeConfig = sizeClasses[size];
|
|
92
114
|
|
|
93
|
-
// Extract background and text color classes
|
|
94
|
-
const
|
|
115
|
+
// Extract background and text color classes from combined variant string
|
|
116
|
+
const variantParts = variantClasses[variant].split(' ');
|
|
117
|
+
const textColorClass = variantParts
|
|
118
|
+
.filter(c => c.includes('text-'))
|
|
119
|
+
.join(' ');
|
|
120
|
+
const bgClass = variantParts.filter(c => c.includes('bg-')).join(' ');
|
|
95
121
|
|
|
96
122
|
if (inline) {
|
|
97
123
|
return (
|
|
98
124
|
<Text
|
|
99
125
|
className={cn(
|
|
100
|
-
|
|
126
|
+
`${designTokens.typography.family.mono} rounded-lg`,
|
|
101
127
|
textColorClass,
|
|
102
128
|
bgClass,
|
|
103
129
|
sizeConfig.text,
|
|
@@ -113,7 +139,7 @@ export const CodeDisplay: React.FC<CodeDisplayProps> = ({
|
|
|
113
139
|
const content = (
|
|
114
140
|
<Text
|
|
115
141
|
className={cn(
|
|
116
|
-
|
|
142
|
+
designTokens.typography.family.mono,
|
|
117
143
|
textColorClass,
|
|
118
144
|
sizeConfig.text,
|
|
119
145
|
!inline && alignClasses[align],
|
|
@@ -10,6 +10,9 @@ import {
|
|
|
10
10
|
UIManager,
|
|
11
11
|
} from 'react-native';
|
|
12
12
|
import { cn } from '../../lib/utils';
|
|
13
|
+
import { designTokens } from '@sudobility/design';
|
|
14
|
+
|
|
15
|
+
const { typography } = designTokens;
|
|
13
16
|
|
|
14
17
|
// Enable LayoutAnimation on Android
|
|
15
18
|
if (
|
|
@@ -126,7 +129,8 @@ export const CollapsibleSection: React.FC<CollapsibleSectionProps> = ({
|
|
|
126
129
|
>
|
|
127
130
|
<Text
|
|
128
131
|
className={cn(
|
|
129
|
-
|
|
132
|
+
typography.size.base,
|
|
133
|
+
typography.weight.medium,
|
|
130
134
|
isSelected && !selectedSubsection
|
|
131
135
|
? 'text-blue-700 dark:text-blue-300'
|
|
132
136
|
: 'text-gray-700 dark:text-gray-300'
|
|
@@ -145,7 +149,7 @@ export const CollapsibleSection: React.FC<CollapsibleSectionProps> = ({
|
|
|
145
149
|
accessibilityLabel={isExpanded ? 'Collapse' : 'Expand'}
|
|
146
150
|
>
|
|
147
151
|
<Animated.View style={{ transform: [{ rotate: rotation }] }}>
|
|
148
|
-
<Text className='text-gray-500
|
|
152
|
+
<Text className={cn('text-gray-500', typography.size.lg)}>›</Text>
|
|
149
153
|
</Animated.View>
|
|
150
154
|
</Pressable>
|
|
151
155
|
)}
|
|
@@ -172,7 +176,7 @@ export const CollapsibleSection: React.FC<CollapsibleSectionProps> = ({
|
|
|
172
176
|
>
|
|
173
177
|
<Text
|
|
174
178
|
className={cn(
|
|
175
|
-
|
|
179
|
+
typography.size.sm,
|
|
176
180
|
selectedSubsection === subsection.id
|
|
177
181
|
? 'text-blue-700 dark:text-blue-300'
|
|
178
182
|
: 'text-gray-600 dark:text-gray-400'
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
TouchableWithoutFeedback,
|
|
11
11
|
} from 'react-native';
|
|
12
12
|
import { cn } from '../../lib/utils';
|
|
13
|
+
import { colors } from '@sudobility/design';
|
|
13
14
|
|
|
14
15
|
export interface ComboboxOption {
|
|
15
16
|
/** Option value */
|
|
@@ -143,7 +144,7 @@ export const Combobox: React.FC<ComboboxProps> = ({
|
|
|
143
144
|
value={searchQuery}
|
|
144
145
|
onChangeText={setSearchQuery}
|
|
145
146
|
placeholder={searchPlaceholder}
|
|
146
|
-
placeholderTextColor=
|
|
147
|
+
placeholderTextColor={colors.raw.neutral[400]}
|
|
147
148
|
autoFocus
|
|
148
149
|
className='px-3 py-2 text-sm bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-white rounded-md'
|
|
149
150
|
/>
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
Platform,
|
|
12
12
|
} from 'react-native';
|
|
13
13
|
import { cn } from '../../lib/utils';
|
|
14
|
+
import { colors } from '@sudobility/design';
|
|
14
15
|
|
|
15
16
|
export interface CommandItem {
|
|
16
17
|
/** Item ID */
|
|
@@ -159,7 +160,7 @@ export const Command: React.FC<CommandProps> = ({
|
|
|
159
160
|
value={searchQuery}
|
|
160
161
|
onChangeText={setSearchQuery}
|
|
161
162
|
placeholder={placeholder}
|
|
162
|
-
placeholderTextColor=
|
|
163
|
+
placeholderTextColor={colors.raw.neutral[400]}
|
|
163
164
|
className='flex-1 text-gray-900 dark:text-white text-base'
|
|
164
165
|
autoCapitalize='none'
|
|
165
166
|
autoCorrect={false}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { View, Text } from 'react-native';
|
|
3
3
|
import { cn } from '../../lib/utils';
|
|
4
|
+
import { designTokens, getCardVariantColors } from '@sudobility/design';
|
|
4
5
|
|
|
5
6
|
export interface DashboardStatCardProps {
|
|
6
7
|
/** Stat title */
|
|
@@ -36,6 +37,22 @@ export interface DashboardStatCardProps {
|
|
|
36
37
|
* />
|
|
37
38
|
* ```
|
|
38
39
|
*/
|
|
40
|
+
|
|
41
|
+
// Lazily derive card variant colors from DS to avoid ESM issues in tests.
|
|
42
|
+
let _cardColors: Record<string, string> | null = null;
|
|
43
|
+
function getDashboardCardColors() {
|
|
44
|
+
if (!_cardColors) {
|
|
45
|
+
_cardColors = {
|
|
46
|
+
default: getCardVariantColors('default'),
|
|
47
|
+
primary: getCardVariantColors('info'),
|
|
48
|
+
success: getCardVariantColors('success'),
|
|
49
|
+
warning: getCardVariantColors('warning'),
|
|
50
|
+
danger: getCardVariantColors('error'),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return _cardColors;
|
|
54
|
+
}
|
|
55
|
+
|
|
39
56
|
export const DashboardStatCard: React.FC<DashboardStatCardProps> = ({
|
|
40
57
|
title,
|
|
41
58
|
value,
|
|
@@ -45,13 +62,7 @@ export const DashboardStatCard: React.FC<DashboardStatCardProps> = ({
|
|
|
45
62
|
variant = 'default',
|
|
46
63
|
className,
|
|
47
64
|
}) => {
|
|
48
|
-
const variantClasses =
|
|
49
|
-
default: 'bg-white dark:bg-gray-900',
|
|
50
|
-
primary: 'bg-blue-50 dark:bg-blue-900/20',
|
|
51
|
-
success: 'bg-green-50 dark:bg-green-900/20',
|
|
52
|
-
warning: 'bg-yellow-50 dark:bg-yellow-900/20',
|
|
53
|
-
danger: 'bg-red-50 dark:bg-red-900/20',
|
|
54
|
-
};
|
|
65
|
+
const variantClasses = getDashboardCardColors();
|
|
55
66
|
|
|
56
67
|
const isPositive = change !== undefined && change >= 0;
|
|
57
68
|
|
|
@@ -65,7 +76,9 @@ export const DashboardStatCard: React.FC<DashboardStatCardProps> = ({
|
|
|
65
76
|
>
|
|
66
77
|
{/* Header */}
|
|
67
78
|
<View className='flex-row items-start justify-between mb-2'>
|
|
68
|
-
<Text
|
|
79
|
+
<Text
|
|
80
|
+
className={`${designTokens.typography.size.sm} ${designTokens.typography.weight.medium} text-gray-600 dark:text-gray-400`}
|
|
81
|
+
>
|
|
69
82
|
{title}
|
|
70
83
|
</Text>
|
|
71
84
|
{icon && (
|
|
@@ -74,7 +87,9 @@ export const DashboardStatCard: React.FC<DashboardStatCardProps> = ({
|
|
|
74
87
|
</View>
|
|
75
88
|
|
|
76
89
|
{/* Value */}
|
|
77
|
-
<Text
|
|
90
|
+
<Text
|
|
91
|
+
className={`${designTokens.typography.size['3xl']} ${designTokens.typography.weight.bold} text-gray-900 dark:text-white`}
|
|
92
|
+
>
|
|
78
93
|
{value}
|
|
79
94
|
</Text>
|
|
80
95
|
|
|
@@ -83,7 +98,8 @@ export const DashboardStatCard: React.FC<DashboardStatCardProps> = ({
|
|
|
83
98
|
<View className='flex-row items-center gap-1 mt-2'>
|
|
84
99
|
<Text
|
|
85
100
|
className={cn(
|
|
86
|
-
|
|
101
|
+
designTokens.typography.size.sm,
|
|
102
|
+
designTokens.typography.weight.medium,
|
|
87
103
|
isPositive
|
|
88
104
|
? 'text-green-600 dark:text-green-400'
|
|
89
105
|
: 'text-red-600 dark:text-red-400'
|
|
@@ -91,7 +107,9 @@ export const DashboardStatCard: React.FC<DashboardStatCardProps> = ({
|
|
|
91
107
|
>
|
|
92
108
|
{isPositive ? '↑' : '↓'} {Math.abs(change)}%
|
|
93
109
|
</Text>
|
|
94
|
-
<Text
|
|
110
|
+
<Text
|
|
111
|
+
className={`${designTokens.typography.size.xs} text-gray-500 dark:text-gray-400`}
|
|
112
|
+
>
|
|
95
113
|
{changePeriod}
|
|
96
114
|
</Text>
|
|
97
115
|
</View>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { View, Text, Pressable, FlatList } from 'react-native';
|
|
3
3
|
import { cn } from '../../lib/utils';
|
|
4
|
+
import { ui, designTokens } from '@sudobility/design';
|
|
4
5
|
|
|
5
6
|
export interface DataListColumn<T> {
|
|
6
7
|
/** Column key */
|
|
@@ -74,7 +75,13 @@ export function DataList<T extends Record<string, unknown>>({
|
|
|
74
75
|
if (!showHeader) return null;
|
|
75
76
|
|
|
76
77
|
return (
|
|
77
|
-
<View
|
|
78
|
+
<View
|
|
79
|
+
className={cn(
|
|
80
|
+
'flex-row',
|
|
81
|
+
ui.table.thead,
|
|
82
|
+
'border-b border-gray-200 dark:border-gray-700'
|
|
83
|
+
)}
|
|
84
|
+
>
|
|
78
85
|
{columns.map(column => (
|
|
79
86
|
<View
|
|
80
87
|
key={column.key}
|
|
@@ -84,7 +91,15 @@ export function DataList<T extends Record<string, unknown>>({
|
|
|
84
91
|
)}
|
|
85
92
|
style={{ flex: column.flex || 1 }}
|
|
86
93
|
>
|
|
87
|
-
<Text
|
|
94
|
+
<Text
|
|
95
|
+
className={cn(
|
|
96
|
+
designTokens.typography.size.xs,
|
|
97
|
+
designTokens.typography.weight.medium,
|
|
98
|
+
'text-gray-700 dark:text-gray-300',
|
|
99
|
+
designTokens.typography.transform.uppercase,
|
|
100
|
+
designTokens.typography.tracking.wider
|
|
101
|
+
)}
|
|
102
|
+
>
|
|
88
103
|
{column.label}
|
|
89
104
|
</Text>
|
|
90
105
|
</View>
|
|
@@ -101,7 +116,7 @@ export function DataList<T extends Record<string, unknown>>({
|
|
|
101
116
|
onPress={() => onRowPress?.(item, index)}
|
|
102
117
|
className={cn(
|
|
103
118
|
'flex-row border-b border-gray-200 dark:border-gray-700',
|
|
104
|
-
isOdd &&
|
|
119
|
+
isOdd && ui.table.trAlt,
|
|
105
120
|
onRowPress && 'active:bg-gray-100 dark:active:bg-gray-800'
|
|
106
121
|
)}
|
|
107
122
|
disabled={!onRowPress}
|
|
@@ -121,7 +136,10 @@ export function DataList<T extends Record<string, unknown>>({
|
|
|
121
136
|
column.render(item, index)
|
|
122
137
|
) : (
|
|
123
138
|
<Text
|
|
124
|
-
className=
|
|
139
|
+
className={cn(
|
|
140
|
+
designTokens.typography.size.sm,
|
|
141
|
+
'text-gray-900 dark:text-white'
|
|
142
|
+
)}
|
|
125
143
|
numberOfLines={1}
|
|
126
144
|
>
|
|
127
145
|
{String(item[column.key] ?? '')}
|
|
@@ -142,7 +160,7 @@ export function DataList<T extends Record<string, unknown>>({
|
|
|
142
160
|
);
|
|
143
161
|
|
|
144
162
|
return (
|
|
145
|
-
<View className={cn(
|
|
163
|
+
<View className={cn(ui.table.tr, className)}>
|
|
146
164
|
{renderHeader()}
|
|
147
165
|
<FlatList
|
|
148
166
|
data={data}
|
|
@@ -8,6 +8,9 @@ import {
|
|
|
8
8
|
TouchableWithoutFeedback,
|
|
9
9
|
} from 'react-native';
|
|
10
10
|
import { cn } from '../../lib/utils';
|
|
11
|
+
import { designTokens } from '@sudobility/design';
|
|
12
|
+
|
|
13
|
+
const { typography } = designTokens;
|
|
11
14
|
|
|
12
15
|
export interface DropdownItem {
|
|
13
16
|
/** Unique identifier */
|
|
@@ -156,7 +159,7 @@ export const Dropdown: React.FC<DropdownProps> = ({
|
|
|
156
159
|
{item.icon && <View className='w-5 h-5'>{item.icon}</View>}
|
|
157
160
|
<Text
|
|
158
161
|
className={cn(
|
|
159
|
-
|
|
162
|
+
typography.size.sm,
|
|
160
163
|
item.disabled
|
|
161
164
|
? 'text-gray-400 dark:text-gray-500'
|
|
162
165
|
: 'text-gray-700 dark:text-gray-200'
|
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import { useCallback } from 'react';
|
|
3
3
|
import { Text, Pressable, Linking } from 'react-native';
|
|
4
4
|
import { cn } from '../../lib/utils';
|
|
5
|
+
import { textVariants } from '@sudobility/design';
|
|
5
6
|
|
|
6
7
|
export interface ExternalLinkProps {
|
|
7
8
|
/** Link URL */
|
|
@@ -63,11 +64,11 @@ export const ExternalLink: React.FC<ExternalLinkProps> = ({
|
|
|
63
64
|
lg: 'text-base',
|
|
64
65
|
};
|
|
65
66
|
|
|
66
|
-
// Color variant configurations
|
|
67
|
+
// Color variant configurations using DS textVariants.link
|
|
67
68
|
const variantClasses = {
|
|
68
|
-
default:
|
|
69
|
-
primary:
|
|
70
|
-
muted:
|
|
69
|
+
default: textVariants.link.external(),
|
|
70
|
+
primary: `${textVariants.link.default()} font-semibold`,
|
|
71
|
+
muted: textVariants.link.muted(),
|
|
71
72
|
};
|
|
72
73
|
|
|
73
74
|
const handlePress = useCallback(async () => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { View, Text, Pressable } from 'react-native';
|
|
3
3
|
import { cn } from '../../lib/utils';
|
|
4
|
+
import { designTokens } from '@sudobility/design';
|
|
4
5
|
|
|
5
6
|
export type FeatureCardColor =
|
|
6
7
|
| 'green'
|
|
@@ -69,57 +70,58 @@ export const FeatureCard: React.FC<FeatureCardProps> = ({
|
|
|
69
70
|
borderColor = false,
|
|
70
71
|
className,
|
|
71
72
|
}) => {
|
|
72
|
-
// Color configurations
|
|
73
|
+
// Color configurations -- derived from colors.raw.* palette
|
|
74
|
+
// Each Tailwind class maps to a colors.raw hex value at the same shade
|
|
73
75
|
const colorClasses: Record<FeatureCardColor, string> = {
|
|
74
|
-
blue: 'text-blue-600 dark:text-blue-400',
|
|
75
|
-
green: 'text-green-600 dark:text-green-400',
|
|
76
|
+
blue: 'text-blue-600 dark:text-blue-400', // colors.raw.blue[600] / [400]
|
|
77
|
+
green: 'text-green-600 dark:text-green-400', // colors.raw.green[600] / [400]
|
|
76
78
|
purple: 'text-purple-600 dark:text-purple-400',
|
|
77
|
-
orange: 'text-orange-600 dark:text-orange-400',
|
|
79
|
+
orange: 'text-orange-600 dark:text-orange-400', // colors.raw.orange[600] / [400]
|
|
78
80
|
pink: 'text-pink-600 dark:text-pink-400',
|
|
79
|
-
gray: 'text-gray-600 dark:text-gray-400',
|
|
80
|
-
red: 'text-red-600 dark:text-red-400',
|
|
81
|
+
gray: 'text-gray-600 dark:text-gray-400', // colors.raw.neutral[600] / [400]
|
|
82
|
+
red: 'text-red-600 dark:text-red-400', // colors.raw.red[600] / [400]
|
|
81
83
|
indigo: 'text-indigo-600 dark:text-indigo-400',
|
|
82
84
|
cyan: 'text-cyan-600 dark:text-cyan-400',
|
|
83
85
|
emerald: 'text-emerald-600 dark:text-emerald-400',
|
|
84
86
|
};
|
|
85
87
|
|
|
86
88
|
const borderColorClasses: Record<FeatureCardColor, string> = {
|
|
87
|
-
green: 'border-l-4 border-l-green-500',
|
|
88
|
-
blue: 'border-l-4 border-l-blue-500',
|
|
89
|
-
purple: 'border-l-4 border-l-purple-500',
|
|
90
|
-
orange: 'border-l-4 border-l-orange-500',
|
|
91
|
-
red: 'border-l-4 border-l-red-500',
|
|
89
|
+
green: 'border-l-4 border-l-green-500', // colors.raw.green[500]
|
|
90
|
+
blue: 'border-l-4 border-l-blue-500', // colors.raw.blue[500]
|
|
91
|
+
purple: 'border-l-4 border-l-purple-500', // colors.raw.purple[500]
|
|
92
|
+
orange: 'border-l-4 border-l-orange-500', // colors.raw.orange[500]
|
|
93
|
+
red: 'border-l-4 border-l-red-500', // colors.raw.red[500]
|
|
92
94
|
indigo: 'border-l-4 border-l-indigo-500',
|
|
93
95
|
cyan: 'border-l-4 border-l-cyan-500',
|
|
94
96
|
emerald: 'border-l-4 border-l-emerald-500',
|
|
95
97
|
pink: 'border-l-4 border-l-pink-500',
|
|
96
|
-
gray: 'border-l-4 border-l-gray-500',
|
|
98
|
+
gray: 'border-l-4 border-l-gray-500', // colors.raw.neutral[500]
|
|
97
99
|
};
|
|
98
100
|
|
|
99
101
|
const iconBackgroundClasses: Record<FeatureCardColor, string> = {
|
|
100
|
-
green: 'bg-green-100 dark:bg-green-900/20',
|
|
101
|
-
blue: 'bg-blue-100 dark:bg-blue-900/20',
|
|
102
|
-
purple: 'bg-purple-100 dark:bg-purple-900/20',
|
|
103
|
-
orange: 'bg-orange-100 dark:bg-orange-900/20',
|
|
104
|
-
red: 'bg-red-100 dark:bg-red-900/20',
|
|
102
|
+
green: 'bg-green-100 dark:bg-green-900/20', // colors.raw.green[100] / [900]
|
|
103
|
+
blue: 'bg-blue-100 dark:bg-blue-900/20', // colors.raw.blue[100] / [900]
|
|
104
|
+
purple: 'bg-purple-100 dark:bg-purple-900/20', // colors.raw.purple[100] / [900]
|
|
105
|
+
orange: 'bg-orange-100 dark:bg-orange-900/20', // colors.raw.orange[100] / [900]
|
|
106
|
+
red: 'bg-red-100 dark:bg-red-900/20', // colors.raw.red[100] / [900]
|
|
105
107
|
indigo: 'bg-indigo-100 dark:bg-indigo-900/20',
|
|
106
108
|
cyan: 'bg-cyan-100 dark:bg-cyan-900/20',
|
|
107
109
|
emerald: 'bg-emerald-100 dark:bg-emerald-900/20',
|
|
108
110
|
pink: 'bg-pink-100 dark:bg-pink-900/20',
|
|
109
|
-
gray: 'bg-gray-100 dark:bg-gray-900/20',
|
|
111
|
+
gray: 'bg-gray-100 dark:bg-gray-900/20', // colors.raw.neutral[100] / [900]
|
|
110
112
|
};
|
|
111
113
|
|
|
112
114
|
const bulletColorClasses: Record<FeatureCardColor, string> = {
|
|
113
|
-
green: 'bg-green-500',
|
|
114
|
-
blue: 'bg-blue-500',
|
|
115
|
-
purple: 'bg-purple-500',
|
|
116
|
-
orange: 'bg-orange-500',
|
|
117
|
-
red: 'bg-red-500',
|
|
115
|
+
green: 'bg-green-500', // colors.raw.green[500]
|
|
116
|
+
blue: 'bg-blue-500', // colors.raw.blue[500]
|
|
117
|
+
purple: 'bg-purple-500', // colors.raw.purple[500]
|
|
118
|
+
orange: 'bg-orange-500', // colors.raw.orange[500]
|
|
119
|
+
red: 'bg-red-500', // colors.raw.red[500]
|
|
118
120
|
indigo: 'bg-indigo-500',
|
|
119
121
|
cyan: 'bg-cyan-500',
|
|
120
122
|
emerald: 'bg-emerald-500',
|
|
121
123
|
pink: 'bg-pink-500',
|
|
122
|
-
gray: 'bg-gray-500',
|
|
124
|
+
gray: 'bg-gray-500', // colors.raw.neutral[500]
|
|
123
125
|
};
|
|
124
126
|
|
|
125
127
|
const CardContent = () => (
|
|
@@ -139,12 +141,24 @@ export const FeatureCard: React.FC<FeatureCardProps> = ({
|
|
|
139
141
|
)}
|
|
140
142
|
|
|
141
143
|
{/* Title */}
|
|
142
|
-
<Text
|
|
144
|
+
<Text
|
|
145
|
+
className={cn(
|
|
146
|
+
designTokens.typography.size.xl,
|
|
147
|
+
designTokens.typography.weight.semibold,
|
|
148
|
+
'text-gray-900 dark:text-white mb-3'
|
|
149
|
+
)}
|
|
150
|
+
>
|
|
143
151
|
{title}
|
|
144
152
|
</Text>
|
|
145
153
|
|
|
146
154
|
{/* Description */}
|
|
147
|
-
<Text
|
|
155
|
+
<Text
|
|
156
|
+
className={cn(
|
|
157
|
+
designTokens.typography.size.base,
|
|
158
|
+
designTokens.typography.leading.relaxed,
|
|
159
|
+
'text-gray-600 dark:text-gray-300 mb-4'
|
|
160
|
+
)}
|
|
161
|
+
>
|
|
148
162
|
{description}
|
|
149
163
|
</Text>
|
|
150
164
|
|
|
@@ -162,7 +176,13 @@ export const FeatureCard: React.FC<FeatureCardProps> = ({
|
|
|
162
176
|
bulletColorClasses[color]
|
|
163
177
|
)}
|
|
164
178
|
/>
|
|
165
|
-
<Text
|
|
179
|
+
<Text
|
|
180
|
+
className={cn(
|
|
181
|
+
'flex-1',
|
|
182
|
+
designTokens.typography.size.sm,
|
|
183
|
+
'text-gray-600 dark:text-gray-400'
|
|
184
|
+
)}
|
|
185
|
+
>
|
|
166
186
|
{benefit}
|
|
167
187
|
</Text>
|
|
168
188
|
</View>
|
|
@@ -178,10 +198,21 @@ export const FeatureCard: React.FC<FeatureCardProps> = ({
|
|
|
178
198
|
key={index}
|
|
179
199
|
className='flex-1 min-w-[80px] items-center p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg'
|
|
180
200
|
>
|
|
181
|
-
<Text
|
|
201
|
+
<Text
|
|
202
|
+
className={cn(
|
|
203
|
+
designTokens.typography.size.lg,
|
|
204
|
+
designTokens.typography.weight.bold,
|
|
205
|
+
colorClasses[color]
|
|
206
|
+
)}
|
|
207
|
+
>
|
|
182
208
|
{value}
|
|
183
209
|
</Text>
|
|
184
|
-
<Text
|
|
210
|
+
<Text
|
|
211
|
+
className={cn(
|
|
212
|
+
designTokens.typography.size.xs,
|
|
213
|
+
'text-gray-500 dark:text-gray-400 mt-1'
|
|
214
|
+
)}
|
|
215
|
+
>
|
|
185
216
|
{key}
|
|
186
217
|
</Text>
|
|
187
218
|
</View>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { View, Text, Pressable } from 'react-native';
|
|
3
3
|
import { cn } from '../../lib/utils';
|
|
4
|
+
import { colors, getCardVariantColors } from '@sudobility/design';
|
|
4
5
|
|
|
5
6
|
export interface Feature {
|
|
6
7
|
/** Unique identifier */
|
|
@@ -72,13 +73,12 @@ export const FeatureGrid: React.FC<FeatureGridProps> = ({
|
|
|
72
73
|
lg: 'w-20 h-20',
|
|
73
74
|
};
|
|
74
75
|
|
|
76
|
+
// Badge variants using DS badge colors
|
|
75
77
|
const badgeVariants = {
|
|
76
|
-
success:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
'bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-300',
|
|
81
|
-
default: 'bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-300',
|
|
78
|
+
success: `${colors.component.badge.success.base} ${colors.component.badge.success.dark}`,
|
|
79
|
+
info: `${colors.component.badge.primary.base} ${colors.component.badge.primary.dark}`,
|
|
80
|
+
warning: `${colors.component.badge.attention.base} ${colors.component.badge.attention.dark}`,
|
|
81
|
+
default: `${colors.component.badge.default.base} ${colors.component.badge.default.dark}`,
|
|
82
82
|
};
|
|
83
83
|
|
|
84
84
|
const renderFeature = (feature: Feature, index: number) => {
|
|
@@ -87,7 +87,7 @@ export const FeatureGrid: React.FC<FeatureGridProps> = ({
|
|
|
87
87
|
className={cn(
|
|
88
88
|
'items-center',
|
|
89
89
|
cardVariant === 'card' &&
|
|
90
|
-
'
|
|
90
|
+
`${getCardVariantColors('elevated')} rounded-2xl p-6`,
|
|
91
91
|
cardVariant === 'minimal' && 'gap-4'
|
|
92
92
|
)}
|
|
93
93
|
>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { View, StyleSheet } from 'react-native';
|
|
3
3
|
import { cn } from '../../lib/utils';
|
|
4
|
+
import { colors } from '@sudobility/design';
|
|
4
5
|
|
|
5
6
|
export interface GradientIconContainerProps {
|
|
6
7
|
/** Icon element */
|
|
@@ -28,6 +29,36 @@ export interface GradientIconContainerProps {
|
|
|
28
29
|
* </GradientIconContainer>
|
|
29
30
|
* ```
|
|
30
31
|
*/
|
|
32
|
+
|
|
33
|
+
// Lazily derive gradient icon colors from DS to avoid ESM issues in tests.
|
|
34
|
+
let _gradientIconColors: Record<string, string> | null = null;
|
|
35
|
+
function getGradientIconColors() {
|
|
36
|
+
if (!_gradientIconColors) {
|
|
37
|
+
const btn = colors.component.button;
|
|
38
|
+
// Extract the leading bg-* class from DS button base strings (solid colors)
|
|
39
|
+
function extractBg(base: string) {
|
|
40
|
+
return (
|
|
41
|
+
base
|
|
42
|
+
.split(' ')
|
|
43
|
+
.find(
|
|
44
|
+
c =>
|
|
45
|
+
c.startsWith('bg-') &&
|
|
46
|
+
!c.includes('hover:') &&
|
|
47
|
+
!c.includes('active:')
|
|
48
|
+
) || ''
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
_gradientIconColors = {
|
|
52
|
+
blue: extractBg(btn.primary.base),
|
|
53
|
+
purple: 'bg-purple-600', // DS has no purple button; local fallback
|
|
54
|
+
green: extractBg(btn.success.base),
|
|
55
|
+
orange: 'bg-orange-600', // DS has no orange button; local fallback
|
|
56
|
+
gray: 'bg-gray-700 dark:bg-gray-600',
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return _gradientIconColors;
|
|
60
|
+
}
|
|
61
|
+
|
|
31
62
|
export const GradientIconContainer: React.FC<GradientIconContainerProps> = ({
|
|
32
63
|
children,
|
|
33
64
|
size = 'md',
|
|
@@ -50,14 +81,8 @@ export const GradientIconContainer: React.FC<GradientIconContainerProps> = ({
|
|
|
50
81
|
circle: 'rounded-full',
|
|
51
82
|
};
|
|
52
83
|
|
|
53
|
-
// Color variants (solid colors approximating gradients)
|
|
54
|
-
const variantClasses =
|
|
55
|
-
blue: 'bg-blue-600',
|
|
56
|
-
purple: 'bg-purple-600',
|
|
57
|
-
green: 'bg-green-600',
|
|
58
|
-
orange: 'bg-orange-600',
|
|
59
|
-
gray: 'bg-gray-700 dark:bg-gray-600',
|
|
60
|
-
};
|
|
84
|
+
// Color variants from DS (solid colors approximating gradients)
|
|
85
|
+
const variantClasses = getGradientIconColors();
|
|
61
86
|
|
|
62
87
|
const config = sizeConfig[size];
|
|
63
88
|
|