@idealyst/components 1.1.7 → 1.1.9
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 +3 -3
- package/plugin/web.js +280 -532
- package/src/Accordion/Accordion.native.tsx +8 -6
- package/src/Accordion/Accordion.styles.old.tsx +298 -0
- package/src/Accordion/Accordion.styles.tsx +102 -236
- package/src/Accordion/Accordion.web.tsx +1 -3
- package/src/ActivityIndicator/ActivityIndicator.styles.old.tsx +94 -0
- package/src/ActivityIndicator/ActivityIndicator.styles.tsx +44 -74
- package/src/Alert/Alert.native.tsx +16 -6
- package/src/Alert/Alert.styles.old.tsx +209 -0
- package/src/Alert/Alert.styles.tsx +67 -149
- package/src/Alert/Alert.web.tsx +3 -4
- package/src/Avatar/Avatar.styles.old.tsx +99 -0
- package/src/Avatar/Avatar.styles.tsx +35 -80
- package/src/Badge/Badge.styles.old.tsx +157 -0
- package/src/Badge/Badge.styles.tsx +61 -121
- package/src/Badge/Badge.web.tsx +8 -15
- package/src/Breadcrumb/Breadcrumb.styles.old.tsx +231 -0
- package/src/Breadcrumb/Breadcrumb.styles.tsx +83 -200
- package/src/Breadcrumb/Breadcrumb.web.tsx +31 -30
- package/src/Button/Button.native.tsx +14 -21
- package/src/Button/Button.styles.tsx +103 -140
- package/src/Button/Button.web.tsx +9 -19
- package/src/Card/Card.native.tsx +7 -11
- package/src/Card/Card.styles.old.tsx +160 -0
- package/src/Card/Card.styles.tsx +105 -142
- package/src/Card/Card.web.tsx +5 -4
- package/src/Checkbox/Checkbox.native.tsx +9 -5
- package/src/Checkbox/Checkbox.styles.old.tsx +271 -0
- package/src/Checkbox/Checkbox.styles.tsx +104 -216
- package/src/Checkbox/Checkbox.web.tsx +7 -8
- package/src/Chip/Chip.styles.old.tsx +184 -0
- package/src/Chip/Chip.styles.tsx +34 -72
- package/src/Chip/Chip.web.tsx +3 -5
- package/src/Dialog/Dialog.native.tsx +7 -4
- package/src/Dialog/Dialog.styles.old.tsx +202 -0
- package/src/Dialog/Dialog.styles.tsx +69 -133
- package/src/Dialog/Dialog.web.tsx +3 -3
- package/src/Dialog/types.ts +1 -1
- package/src/Divider/Divider.styles.old.tsx +172 -0
- package/src/Divider/Divider.styles.tsx +62 -84
- package/src/Icon/Icon.native.tsx +8 -8
- package/src/Icon/Icon.styles.old.tsx +81 -0
- package/src/Icon/Icon.styles.tsx +52 -66
- package/src/Icon/Icon.web.tsx +62 -21
- package/src/Icon/IconRegistry.native.ts +41 -0
- package/src/Icon/IconRegistry.ts +107 -0
- package/src/Icon/IconSvg/IconSvg.web.tsx +28 -5
- package/src/Icon/icon-resolver.ts +12 -43
- package/src/Icon/index.native.ts +2 -1
- package/src/Icon/index.ts +1 -0
- package/src/Icon/index.web.ts +1 -0
- package/src/Image/Image.styles.old.tsx +69 -0
- package/src/Image/Image.styles.tsx +46 -60
- package/src/Input/Input.native.tsx +138 -53
- package/src/Input/Input.styles.old.tsx +289 -0
- package/src/Input/Input.styles.tsx +134 -232
- package/src/Input/Input.web.tsx +5 -8
- package/src/List/List.native.tsx +5 -2
- package/src/List/List.styles.old.tsx +242 -0
- package/src/List/List.styles.tsx +179 -215
- package/src/List/ListItem.native.tsx +16 -11
- package/src/List/ListItem.web.tsx +26 -16
- package/src/Menu/Menu.styles.old.tsx +197 -0
- package/src/Menu/Menu.styles.tsx +68 -150
- package/src/Menu/MenuItem.native.tsx +5 -3
- package/src/Menu/MenuItem.styles.old.tsx +114 -0
- package/src/Menu/MenuItem.styles.tsx +57 -89
- package/src/Menu/MenuItem.web.tsx +10 -7
- package/src/Popover/Popover.native.tsx +10 -4
- package/src/Popover/Popover.styles.old.tsx +135 -0
- package/src/Popover/Popover.styles.tsx +51 -112
- package/src/Pressable/Pressable.styles.old.tsx +27 -0
- package/src/Pressable/Pressable.styles.tsx +35 -27
- package/src/Progress/Progress.styles.old.tsx +200 -0
- package/src/Progress/Progress.styles.tsx +75 -164
- package/src/RadioButton/RadioButton.native.tsx +4 -3
- package/src/RadioButton/RadioButton.styles.old.tsx +175 -0
- package/src/RadioButton/RadioButton.styles.tsx +83 -154
- package/src/RadioButton/RadioButton.web.tsx +2 -2
- package/src/SVGImage/SVGImage.styles.old.tsx +86 -0
- package/src/SVGImage/SVGImage.styles.tsx +35 -78
- package/src/Screen/Screen.native.tsx +19 -26
- package/src/Screen/Screen.styles.old.tsx +87 -0
- package/src/Screen/Screen.styles.tsx +103 -68
- package/src/Screen/Screen.web.tsx +2 -2
- package/src/Select/Select.native.tsx +42 -33
- package/src/Select/Select.styles.old.tsx +353 -0
- package/src/Select/Select.styles.tsx +214 -300
- package/src/Select/Select.web.tsx +45 -33
- package/src/Skeleton/Skeleton.styles.old.tsx +67 -0
- package/src/Skeleton/Skeleton.styles.tsx +29 -53
- package/src/Slider/Slider.styles.old.tsx +259 -0
- package/src/Slider/Slider.styles.tsx +153 -234
- package/src/Slider/Slider.web.tsx +2 -4
- package/src/Switch/Switch.native.tsx +9 -7
- package/src/Switch/Switch.styles.old.tsx +203 -0
- package/src/Switch/Switch.styles.tsx +101 -174
- package/src/Switch/Switch.web.tsx +7 -8
- package/src/TabBar/TabBar.native.tsx +3 -2
- package/src/TabBar/TabBar.styles.old.tsx +343 -0
- package/src/TabBar/TabBar.styles.tsx +145 -279
- package/src/Table/Table.native.tsx +180 -68
- package/src/Table/Table.styles.old.tsx +311 -0
- package/src/Table/Table.styles.tsx +140 -281
- package/src/Table/Table.web.tsx +169 -70
- package/src/Text/Text.native.tsx +1 -3
- package/src/Text/Text.style.demo.tsx +16 -0
- package/src/Text/Text.styles.old.tsx +219 -0
- package/src/Text/Text.styles.tsx +94 -84
- package/src/Text/Text.web.tsx +3 -2
- package/src/Text/index.ts +1 -0
- package/src/TextArea/TextArea.native.tsx +21 -8
- package/src/TextArea/TextArea.styles.old.tsx +213 -0
- package/src/TextArea/TextArea.styles.tsx +87 -187
- package/src/TextArea/TextArea.web.tsx +17 -6
- package/src/Tooltip/Tooltip.styles.old.tsx +82 -0
- package/src/Tooltip/Tooltip.styles.tsx +32 -56
- package/src/Video/Video.styles.old.tsx +51 -0
- package/src/Video/Video.styles.tsx +32 -44
- package/src/View/View.native.tsx +41 -13
- package/src/View/View.styles.old.tsx +125 -0
- package/src/View/View.styles.tsx +76 -106
- package/src/View/View.web.tsx +5 -21
- package/src/View/types.ts +31 -3
- package/src/examples/ButtonExamples.tsx +20 -0
- package/src/examples/CardExamples.tsx +0 -6
- package/src/extensions/extendComponent.ts +61 -0
- package/src/index.ts +1 -1
|
@@ -5,6 +5,7 @@ import Svg, { Defs, LinearGradient, Stop, Rect } from 'react-native-svg';
|
|
|
5
5
|
import { buttonStyles } from './Button.styles';
|
|
6
6
|
import { ButtonProps } from './types';
|
|
7
7
|
import { getNativeInteractiveAccessibilityProps } from '../utils/accessibility';
|
|
8
|
+
import { useUnistyles } from 'react-native-unistyles';
|
|
8
9
|
|
|
9
10
|
const Button = forwardRef<ComponentRef<typeof TouchableOpacity>, ButtonProps>((props, ref) => {
|
|
10
11
|
const {
|
|
@@ -71,24 +72,6 @@ const Button = forwardRef<ComponentRef<typeof TouchableOpacity>, ButtonProps>((p
|
|
|
71
72
|
} as const;
|
|
72
73
|
const iconSize = iconSizeMap[size];
|
|
73
74
|
|
|
74
|
-
// Helper to render icon - uses the icon styles from buttonStyles
|
|
75
|
-
const renderIcon = (icon: string | React.ReactNode) => {
|
|
76
|
-
if (typeof icon === 'string') {
|
|
77
|
-
// Render MaterialCommunityIcons with explicit size prop
|
|
78
|
-
// The icon styles provide the correct color based on dynamic styles
|
|
79
|
-
return (
|
|
80
|
-
<MaterialCommunityIcons
|
|
81
|
-
name={icon}
|
|
82
|
-
size={iconSize}
|
|
83
|
-
style={iconStyle}
|
|
84
|
-
/>
|
|
85
|
-
);
|
|
86
|
-
} else if (isValidElement(icon)) {
|
|
87
|
-
// Render custom component as-is
|
|
88
|
-
return icon;
|
|
89
|
-
}
|
|
90
|
-
return null;
|
|
91
|
-
};
|
|
92
75
|
|
|
93
76
|
// Use children if available, otherwise use title
|
|
94
77
|
const buttonContent = children || title;
|
|
@@ -199,12 +182,22 @@ const Button = forwardRef<ComponentRef<typeof TouchableOpacity>, ButtonProps>((p
|
|
|
199
182
|
<TouchableOpacity {...touchableProps as any}>
|
|
200
183
|
{renderGradientLayer()}
|
|
201
184
|
{hasIcons ? (
|
|
202
|
-
<View
|
|
203
|
-
{leftIcon &&
|
|
185
|
+
<View style={iconContainerStyle}>
|
|
186
|
+
{leftIcon &&
|
|
187
|
+
<MaterialCommunityIcons
|
|
188
|
+
name={leftIcon}
|
|
189
|
+
size={iconSize}
|
|
190
|
+
style={iconStyle}
|
|
191
|
+
/>}
|
|
204
192
|
<Text style={textStyle}>
|
|
205
193
|
{buttonContent}
|
|
206
194
|
</Text>
|
|
207
|
-
{rightIcon &&
|
|
195
|
+
{rightIcon &&
|
|
196
|
+
<MaterialCommunityIcons
|
|
197
|
+
name={rightIcon}
|
|
198
|
+
size={iconSize}
|
|
199
|
+
style={iconStyle}
|
|
200
|
+
/>}
|
|
208
201
|
</View>
|
|
209
202
|
) : (
|
|
210
203
|
<Text style={textStyle}>
|
|
@@ -1,8 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Button styles using defineStyle with $iterator expansion.
|
|
3
|
+
*
|
|
4
|
+
* Dynamic style functions are used for intent/type combinations since
|
|
5
|
+
* the color depends on both values (compound logic).
|
|
6
|
+
*/
|
|
1
7
|
import { StyleSheet } from 'react-native-unistyles';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
8
|
+
import { defineStyle, ThemeStyleWrapper } from '@idealyst/theme';
|
|
9
|
+
import type { Theme as BaseTheme, Intent, Size } from '@idealyst/theme';
|
|
4
10
|
import { ButtonGradient } from './types';
|
|
5
|
-
|
|
11
|
+
|
|
12
|
+
// Required: Unistyles must see StyleSheet usage in original source to process this file
|
|
13
|
+
void StyleSheet;
|
|
14
|
+
|
|
15
|
+
// Wrap theme for $iterator support
|
|
16
|
+
type Theme = ThemeStyleWrapper<BaseTheme>;
|
|
6
17
|
|
|
7
18
|
type ButtonSize = Size;
|
|
8
19
|
type ButtonType = 'contained' | 'outlined' | 'text';
|
|
@@ -17,8 +28,6 @@ export type ButtonVariants = {
|
|
|
17
28
|
|
|
18
29
|
/**
|
|
19
30
|
* All dynamic props passed to button style functions.
|
|
20
|
-
* Every style function receives all props for maximum flexibility
|
|
21
|
-
* when using extensions or replacements.
|
|
22
31
|
*/
|
|
23
32
|
export type ButtonDynamicProps = {
|
|
24
33
|
intent?: Intent;
|
|
@@ -29,149 +38,103 @@ export type ButtonDynamicProps = {
|
|
|
29
38
|
};
|
|
30
39
|
|
|
31
40
|
/**
|
|
32
|
-
*
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return theme.intents[intent].primary;
|
|
37
|
-
}
|
|
38
|
-
if (type === 'outlined') {
|
|
39
|
-
return theme.colors.surface.primary;
|
|
40
|
-
}
|
|
41
|
-
return 'transparent';
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Get button border color based on intent and type
|
|
41
|
+
* Button styles with $iterator expansion for size variants.
|
|
42
|
+
*
|
|
43
|
+
* Intent/type combinations use dynamic functions with inlined theme accesses
|
|
44
|
+
* so Unistyles can trace all possible theme paths.
|
|
46
45
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
fontWeight: '600',
|
|
77
|
-
textAlign: 'center',
|
|
78
|
-
backgroundColor: getButtonBackgroundColor(theme, intent, type),
|
|
79
|
-
borderColor: getButtonBorderColor(theme, intent, type),
|
|
80
|
-
borderWidth: type === 'outlined' ? 1 : 0,
|
|
81
|
-
borderStyle: type === 'outlined' ? 'solid' as const : undefined,
|
|
82
|
-
_web: {
|
|
83
|
-
display: 'flex',
|
|
84
|
-
transition: 'all 0.1s ease',
|
|
85
|
-
},
|
|
86
|
-
variants: {
|
|
87
|
-
size: buildSizeVariants(theme, 'button', size => ({
|
|
88
|
-
paddingVertical: size.paddingVertical,
|
|
89
|
-
paddingHorizontal: size.paddingHorizontal,
|
|
90
|
-
minHeight: size.minHeight,
|
|
91
|
-
})),
|
|
92
|
-
disabled: {
|
|
93
|
-
true: { opacity: 0.6 },
|
|
94
|
-
false: { opacity: 1, _web: { cursor: 'pointer', _hover: { opacity: 0.90 }, _active: { opacity: 0.75 } } },
|
|
46
|
+
export const buttonStyles = defineStyle('Button', (theme: Theme) => ({
|
|
47
|
+
button: ({ intent = 'primary', type = 'contained' }: ButtonDynamicProps) => ({
|
|
48
|
+
boxSizing: 'border-box',
|
|
49
|
+
alignItems: 'center',
|
|
50
|
+
justifyContent: 'center',
|
|
51
|
+
borderRadius: 8,
|
|
52
|
+
fontWeight: '600',
|
|
53
|
+
textAlign: 'center',
|
|
54
|
+
// Inline theme accesses so Unistyles can trace them
|
|
55
|
+
backgroundColor: type === 'contained'
|
|
56
|
+
? theme.intents[intent].primary
|
|
57
|
+
: type === 'outlined'
|
|
58
|
+
? theme.colors.surface.primary
|
|
59
|
+
: 'transparent',
|
|
60
|
+
borderColor: type === 'outlined'
|
|
61
|
+
? theme.intents[intent].primary
|
|
62
|
+
: 'transparent',
|
|
63
|
+
borderWidth: type === 'outlined' ? 1 : 0,
|
|
64
|
+
borderStyle: type === 'outlined' ? 'solid' as const : undefined,
|
|
65
|
+
_web: {
|
|
66
|
+
display: 'flex',
|
|
67
|
+
transition: 'all 0.1s ease',
|
|
68
|
+
},
|
|
69
|
+
variants: {
|
|
70
|
+
// $iterator expands for each button size
|
|
71
|
+
type: {
|
|
72
|
+
contained: {
|
|
73
|
+
backgroundColor: theme.intents[intent].primary,
|
|
74
|
+
borderColor: 'transparent',
|
|
95
75
|
},
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
76
|
+
outlined: {
|
|
77
|
+
backgroundColor: 'transparent',
|
|
78
|
+
borderColor: theme.intents[intent].primary,
|
|
99
79
|
},
|
|
80
|
+
text: {
|
|
81
|
+
backgroundColor: 'transparent',
|
|
82
|
+
borderColor: 'transparent',
|
|
83
|
+
borderWidth: 0,
|
|
84
|
+
}
|
|
100
85
|
},
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Create dynamic text styles
|
|
107
|
-
* Receives all ButtonDynamicProps for flexibility in extensions/replacements
|
|
108
|
-
*/
|
|
109
|
-
function createTextStyles(theme: Theme) {
|
|
110
|
-
return (props: ButtonDynamicProps) => {
|
|
111
|
-
const { intent = 'primary', type = 'contained' } = props;
|
|
112
|
-
return {
|
|
113
|
-
fontWeight: '600',
|
|
114
|
-
textAlign: 'center',
|
|
115
|
-
color: getTextColor(theme, intent, type),
|
|
116
|
-
variants: {
|
|
117
|
-
size: buildSizeVariants(theme, 'button', size => ({
|
|
118
|
-
fontSize: size.fontSize,
|
|
119
|
-
lineHeight: size.fontSize,
|
|
120
|
-
})),
|
|
121
|
-
disabled: {
|
|
122
|
-
true: { opacity: 0.6 },
|
|
123
|
-
false: { opacity: 1 },
|
|
124
|
-
},
|
|
86
|
+
size: {
|
|
87
|
+
paddingVertical: theme.sizes.$button.paddingVertical,
|
|
88
|
+
paddingHorizontal: theme.sizes.$button.paddingHorizontal,
|
|
89
|
+
minHeight: theme.sizes.$button.minHeight,
|
|
125
90
|
},
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Create dynamic icon styles
|
|
132
|
-
* Receives all ButtonDynamicProps for flexibility in extensions/replacements
|
|
133
|
-
*/
|
|
134
|
-
function createIconStyles(theme: Theme) {
|
|
135
|
-
return (props: ButtonDynamicProps) => {
|
|
136
|
-
const { intent = 'primary', type = 'contained' } = props;
|
|
137
|
-
return {
|
|
138
|
-
display: 'flex',
|
|
139
|
-
alignItems: 'center',
|
|
140
|
-
justifyContent: 'center',
|
|
141
|
-
color: getTextColor(theme, intent, type),
|
|
142
|
-
variants: {
|
|
143
|
-
size: buildSizeVariants(theme, 'button', size => ({
|
|
144
|
-
width: size.iconSize,
|
|
145
|
-
height: size.iconSize,
|
|
146
|
-
})),
|
|
91
|
+
disabled: {
|
|
92
|
+
true: { opacity: 0.6 },
|
|
93
|
+
false: { opacity: 1, _web: { cursor: 'pointer', _hover: { opacity: 0.90 }, _active: { opacity: 0.75 } } },
|
|
147
94
|
},
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
95
|
+
gradient: {
|
|
96
|
+
darken: { _web: { backgroundImage: 'linear-gradient(135deg, transparent 0%, rgba(0, 0, 0, 0.15) 100%)' } },
|
|
97
|
+
lighten: { _web: { backgroundImage: 'linear-gradient(135deg, transparent 0%, rgba(255, 255, 255, 0.2) 100%)' } },
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
}),
|
|
101
|
+
text: ({ intent = 'primary', type = 'contained' }: ButtonDynamicProps) => ({
|
|
102
|
+
fontWeight: '600',
|
|
103
|
+
textAlign: 'center',
|
|
104
|
+
// Inline: contained uses contrast, others use primary
|
|
105
|
+
color: type === 'contained'
|
|
106
|
+
? theme.intents[intent].contrast
|
|
107
|
+
: theme.intents[intent].primary,
|
|
108
|
+
variants: {
|
|
109
|
+
size: {
|
|
110
|
+
fontSize: theme.sizes.$button.fontSize,
|
|
111
|
+
lineHeight: theme.sizes.$button.fontSize,
|
|
112
|
+
},
|
|
113
|
+
disabled: {
|
|
114
|
+
true: { opacity: 0.6 },
|
|
115
|
+
false: { opacity: 1 },
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
}),
|
|
119
|
+
icon: ({ intent = 'primary', type = 'contained' }: ButtonDynamicProps) => ({
|
|
120
|
+
display: 'flex',
|
|
121
|
+
alignItems: 'center',
|
|
122
|
+
justifyContent: 'center',
|
|
123
|
+
color: type === 'contained'
|
|
124
|
+
? theme.intents[intent].contrast
|
|
125
|
+
: theme.intents[intent].primary,
|
|
126
|
+
variants: {
|
|
127
|
+
size: {
|
|
128
|
+
width: theme.sizes.$button.iconSize,
|
|
129
|
+
height: theme.sizes.$button.iconSize,
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
}),
|
|
133
|
+
iconContainer: (_props: ButtonDynamicProps) => ({
|
|
160
134
|
display: 'flex' as const,
|
|
161
135
|
flexDirection: 'row' as const,
|
|
162
136
|
alignItems: 'center' as const,
|
|
163
137
|
justifyContent: 'center' as const,
|
|
164
138
|
gap: 4,
|
|
165
|
-
})
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Styles use dynamic functions for intent/type to support theme extensions
|
|
169
|
-
// applyExtensions handles both replacements and extensions automatically
|
|
170
|
-
export const buttonStyles = StyleSheet.create((theme: Theme) => {
|
|
171
|
-
return applyExtensions('Button', theme, {
|
|
172
|
-
button: createButtonStyles(theme),
|
|
173
|
-
text: createTextStyles(theme),
|
|
174
|
-
icon: createIconStyles(theme),
|
|
175
|
-
iconContainer: createIconContainerStyles(),
|
|
176
|
-
});
|
|
177
|
-
});
|
|
139
|
+
}),
|
|
140
|
+
}));
|
|
@@ -6,14 +6,7 @@ import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
|
|
|
6
6
|
import useMergeRefs from '../hooks/useMergeRefs';
|
|
7
7
|
import { getWebInteractiveAriaProps, generateAccessibilityId } from '../utils/accessibility';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
interface InternalButtonProps extends ButtonProps {
|
|
11
|
-
leftIconPath?: string;
|
|
12
|
-
rightIconPath?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const Button = forwardRef<HTMLButtonElement, ButtonProps>((props: InternalButtonProps, ref) => {
|
|
16
|
-
|
|
9
|
+
const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
|
|
17
10
|
const {
|
|
18
11
|
title,
|
|
19
12
|
children,
|
|
@@ -25,8 +18,6 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props: InternalButton
|
|
|
25
18
|
gradient,
|
|
26
19
|
leftIcon,
|
|
27
20
|
rightIcon,
|
|
28
|
-
leftIconPath,
|
|
29
|
-
rightIconPath,
|
|
30
21
|
style,
|
|
31
22
|
testID,
|
|
32
23
|
id,
|
|
@@ -124,14 +115,13 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props: InternalButton
|
|
|
124
115
|
const iconStyleArray = [(buttonStyles.icon as any)(dynamicProps)];
|
|
125
116
|
const iconProps = getWebProps(iconStyleArray);
|
|
126
117
|
|
|
127
|
-
// Helper to render icon
|
|
128
|
-
const renderIcon = (icon: string | React.ReactNode
|
|
129
|
-
if (typeof icon === 'string'
|
|
130
|
-
// Render IconSvg
|
|
131
|
-
// Don't pass size - let the style control the dimensions
|
|
118
|
+
// Helper to render icon - now uses icon name directly
|
|
119
|
+
const renderIcon = (icon: string | React.ReactNode) => {
|
|
120
|
+
if (typeof icon === 'string') {
|
|
121
|
+
// Render IconSvg with the icon name - registry lookup happens inside
|
|
132
122
|
return (
|
|
133
123
|
<IconSvg
|
|
134
|
-
|
|
124
|
+
name={icon}
|
|
135
125
|
{...iconProps}
|
|
136
126
|
aria-label={icon}
|
|
137
127
|
/>
|
|
@@ -164,9 +154,9 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props: InternalButton
|
|
|
164
154
|
>
|
|
165
155
|
{hasIcons ? (
|
|
166
156
|
<div {...iconContainerProps}>
|
|
167
|
-
{leftIcon && renderIcon(leftIcon
|
|
157
|
+
{leftIcon && renderIcon(leftIcon)}
|
|
168
158
|
{buttonContent}
|
|
169
|
-
{rightIcon && renderIcon(rightIcon
|
|
159
|
+
{rightIcon && renderIcon(rightIcon)}
|
|
170
160
|
</div>
|
|
171
161
|
) : (
|
|
172
162
|
buttonContent
|
|
@@ -177,4 +167,4 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props: InternalButton
|
|
|
177
167
|
|
|
178
168
|
Button.displayName = 'Button';
|
|
179
169
|
|
|
180
|
-
export default Button;
|
|
170
|
+
export default Button;
|
package/src/Card/Card.native.tsx
CHANGED
|
@@ -2,7 +2,7 @@ import React, { forwardRef, ComponentRef, useMemo } from 'react';
|
|
|
2
2
|
import { View, Pressable } from 'react-native';
|
|
3
3
|
import { useUnistyles } from 'react-native-unistyles';
|
|
4
4
|
import { CardProps } from './types';
|
|
5
|
-
import { cardStyles
|
|
5
|
+
import { cardStyles } from './Card.styles';
|
|
6
6
|
import { getNativeInteractiveAccessibilityProps } from '../utils/accessibility';
|
|
7
7
|
|
|
8
8
|
const Card = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pressable>, CardProps>(({
|
|
@@ -44,11 +44,10 @@ const Card = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pressabl
|
|
|
44
44
|
});
|
|
45
45
|
}, [accessibilityLabel, accessibilityHint, accessibilityDisabled, disabled, accessibilityHidden, accessibilityRole, clickable, accessibilityPressed]);
|
|
46
46
|
|
|
47
|
-
//
|
|
48
|
-
const { theme } = useUnistyles();
|
|
49
|
-
|
|
50
|
-
// Apply variants (for spacing only - radius is applied directly below)
|
|
47
|
+
// Apply variants
|
|
51
48
|
cardStyles.useVariants({
|
|
49
|
+
type,
|
|
50
|
+
radius,
|
|
52
51
|
clickable,
|
|
53
52
|
disabled,
|
|
54
53
|
gap,
|
|
@@ -60,11 +59,8 @@ const Card = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pressabl
|
|
|
60
59
|
marginHorizontal,
|
|
61
60
|
});
|
|
62
61
|
|
|
63
|
-
// Get
|
|
64
|
-
const cardStyle = (cardStyles.card as any)({
|
|
65
|
-
|
|
66
|
-
// Get border radius from theme - variants don't work with dynamic styles on iOS
|
|
67
|
-
const borderRadius = getCardBorderRadius(theme, radius);
|
|
62
|
+
// Get card style
|
|
63
|
+
const cardStyle = (cardStyles.card as any)({});
|
|
68
64
|
|
|
69
65
|
// Use appropriate component based on clickable state
|
|
70
66
|
const Component = clickable ? Pressable : View;
|
|
@@ -72,7 +68,7 @@ const Card = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pressabl
|
|
|
72
68
|
const componentProps = {
|
|
73
69
|
ref,
|
|
74
70
|
nativeID: id,
|
|
75
|
-
style: [cardStyle,
|
|
71
|
+
style: [cardStyle, style],
|
|
76
72
|
testID,
|
|
77
73
|
...nativeA11yProps,
|
|
78
74
|
...(clickable && {
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
2
|
+
import { Theme, Intent, Radius } from '@idealyst/theme';
|
|
3
|
+
import {
|
|
4
|
+
buildGapVariants,
|
|
5
|
+
buildPaddingVariants,
|
|
6
|
+
buildPaddingVerticalVariants,
|
|
7
|
+
buildPaddingHorizontalVariants,
|
|
8
|
+
buildMarginVariants,
|
|
9
|
+
buildMarginVerticalVariants,
|
|
10
|
+
buildMarginHorizontalVariants,
|
|
11
|
+
} from '../utils/buildViewStyleVariants';
|
|
12
|
+
import { ViewStyleSize } from '../utils/viewStyleProps';
|
|
13
|
+
import { applyExtensions } from '../extensions/applyExtension';
|
|
14
|
+
|
|
15
|
+
type CardType = 'outlined' | 'elevated' | 'filled';
|
|
16
|
+
type CardRadius = Radius;
|
|
17
|
+
type CardIntent = Intent | 'info' | 'neutral';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get border radius value from theme
|
|
21
|
+
*/
|
|
22
|
+
export function getCardBorderRadius(theme: Theme, radius: CardRadius): number {
|
|
23
|
+
return theme.radii[radius];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type CardVariants = {
|
|
27
|
+
type: CardType;
|
|
28
|
+
radius: CardRadius;
|
|
29
|
+
intent: CardIntent;
|
|
30
|
+
clickable: boolean;
|
|
31
|
+
disabled: boolean;
|
|
32
|
+
// Spacing variants from ContainerStyleProps
|
|
33
|
+
gap: ViewStyleSize;
|
|
34
|
+
padding: ViewStyleSize;
|
|
35
|
+
paddingVertical: ViewStyleSize;
|
|
36
|
+
paddingHorizontal: ViewStyleSize;
|
|
37
|
+
margin: ViewStyleSize;
|
|
38
|
+
marginVertical: ViewStyleSize;
|
|
39
|
+
marginHorizontal: ViewStyleSize;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type CardDynamicProps = {
|
|
43
|
+
intent?: CardIntent;
|
|
44
|
+
type?: CardType;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get the border color based on intent (only used for outlined type)
|
|
49
|
+
*/
|
|
50
|
+
function getBorderColor(theme: Theme, intent: CardIntent): string {
|
|
51
|
+
if (intent === 'info' || intent === 'neutral') {
|
|
52
|
+
return theme.colors.border.secondary;
|
|
53
|
+
}
|
|
54
|
+
if (intent in theme.intents) {
|
|
55
|
+
return theme.intents[intent as Intent].primary;
|
|
56
|
+
}
|
|
57
|
+
return theme.colors.border.secondary;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get type-specific styles
|
|
62
|
+
*/
|
|
63
|
+
function getTypeStyles(theme: Theme, type: CardType, intent: CardIntent) {
|
|
64
|
+
switch (type) {
|
|
65
|
+
case 'outlined':
|
|
66
|
+
return {
|
|
67
|
+
backgroundColor: 'transparent',
|
|
68
|
+
borderWidth: 1,
|
|
69
|
+
borderStyle: 'solid' as const,
|
|
70
|
+
borderColor: getBorderColor(theme, intent),
|
|
71
|
+
};
|
|
72
|
+
case 'elevated':
|
|
73
|
+
return {
|
|
74
|
+
backgroundColor: theme.colors.surface.primary,
|
|
75
|
+
borderWidth: 0,
|
|
76
|
+
...theme.shadows.md,
|
|
77
|
+
};
|
|
78
|
+
case 'filled':
|
|
79
|
+
return {
|
|
80
|
+
backgroundColor: theme.colors.surface.secondary,
|
|
81
|
+
borderWidth: 0,
|
|
82
|
+
};
|
|
83
|
+
default:
|
|
84
|
+
return {};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Create dynamic card styles
|
|
90
|
+
*/
|
|
91
|
+
function createCardStyles(theme: Theme) {
|
|
92
|
+
return ({ intent = 'neutral', type = 'elevated' }: CardDynamicProps) => {
|
|
93
|
+
const typeStyles = getTypeStyles(theme, type, intent);
|
|
94
|
+
return {
|
|
95
|
+
...typeStyles,
|
|
96
|
+
position: 'relative',
|
|
97
|
+
overflow: 'hidden',
|
|
98
|
+
variants: {
|
|
99
|
+
radius: {
|
|
100
|
+
none: { borderRadius: 0 },
|
|
101
|
+
xs: { borderRadius: 2 },
|
|
102
|
+
sm: { borderRadius: 4 },
|
|
103
|
+
md: { borderRadius: 8 },
|
|
104
|
+
lg: { borderRadius: 12 },
|
|
105
|
+
xl: { borderRadius: 16 },
|
|
106
|
+
},
|
|
107
|
+
clickable: {
|
|
108
|
+
true: {
|
|
109
|
+
_web: {
|
|
110
|
+
cursor: 'pointer',
|
|
111
|
+
transition: 'all 0.2s ease',
|
|
112
|
+
_hover: {
|
|
113
|
+
transform: 'translateY(-2px)',
|
|
114
|
+
boxShadow:
|
|
115
|
+
'0 4px 12px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.06)',
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
false: {
|
|
120
|
+
_web: {
|
|
121
|
+
cursor: 'default',
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
disabled: {
|
|
126
|
+
true: {
|
|
127
|
+
opacity: 0.6,
|
|
128
|
+
_web: {
|
|
129
|
+
cursor: 'not-allowed',
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
false: {
|
|
133
|
+
opacity: 1,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
// Spacing variants from ContainerStyleProps
|
|
137
|
+
gap: buildGapVariants(theme),
|
|
138
|
+
padding: buildPaddingVariants(theme),
|
|
139
|
+
paddingVertical: buildPaddingVerticalVariants(theme),
|
|
140
|
+
paddingHorizontal: buildPaddingHorizontalVariants(theme),
|
|
141
|
+
margin: buildMarginVariants(theme),
|
|
142
|
+
marginVertical: buildMarginVerticalVariants(theme),
|
|
143
|
+
marginHorizontal: buildMarginHorizontalVariants(theme),
|
|
144
|
+
},
|
|
145
|
+
_web: {
|
|
146
|
+
display: 'flex',
|
|
147
|
+
flexDirection: 'column',
|
|
148
|
+
boxSizing: 'border-box',
|
|
149
|
+
},
|
|
150
|
+
} as const;
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
|
|
155
|
+
// transform on native cannot resolve function calls to extract variant structures.
|
|
156
|
+
export const cardStyles = StyleSheet.create((theme: Theme) => {
|
|
157
|
+
return applyExtensions('Card', theme, {
|
|
158
|
+
card: createCardStyles(theme),
|
|
159
|
+
});
|
|
160
|
+
});
|