@idealyst/components 1.1.6 → 1.1.8
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 +8 -3
- package/src/Accordion/Accordion.native.tsx +22 -14
- package/src/Accordion/Accordion.styles.old.tsx +298 -0
- package/src/Accordion/Accordion.styles.tsx +139 -248
- package/src/Accordion/Accordion.web.tsx +12 -7
- package/src/ActivityIndicator/ActivityIndicator.native.tsx +3 -2
- package/src/ActivityIndicator/ActivityIndicator.styles.old.tsx +94 -0
- package/src/ActivityIndicator/ActivityIndicator.styles.tsx +43 -62
- package/src/ActivityIndicator/ActivityIndicator.web.tsx +2 -2
- package/src/Alert/Alert.native.tsx +26 -15
- package/src/Alert/Alert.styles.old.tsx +209 -0
- package/src/Alert/Alert.styles.tsx +108 -281
- package/src/Alert/Alert.web.tsx +6 -10
- package/src/Avatar/Avatar.native.tsx +5 -2
- package/src/Avatar/Avatar.styles.old.tsx +99 -0
- package/src/Avatar/Avatar.styles.tsx +47 -62
- package/src/Avatar/Avatar.web.tsx +2 -2
- package/src/Badge/Badge.native.tsx +2 -2
- package/src/Badge/Badge.styles.old.tsx +157 -0
- package/src/Badge/Badge.styles.tsx +69 -108
- package/src/Badge/Badge.web.tsx +6 -6
- package/src/Breadcrumb/Breadcrumb.native.tsx +12 -5
- package/src/Breadcrumb/Breadcrumb.styles.old.tsx +231 -0
- package/src/Breadcrumb/Breadcrumb.styles.tsx +93 -209
- package/src/Breadcrumb/Breadcrumb.web.tsx +39 -27
- package/src/Button/Button.native.tsx +39 -14
- package/src/Button/Button.styles.tsx +99 -253
- package/src/Button/Button.web.tsx +10 -8
- package/src/Card/Card.native.tsx +8 -4
- package/src/Card/Card.styles.old.tsx +160 -0
- package/src/Card/Card.styles.tsx +107 -142
- package/src/Card/Card.web.tsx +6 -4
- package/src/Checkbox/Checkbox.native.tsx +14 -6
- package/src/Checkbox/Checkbox.styles.old.tsx +271 -0
- package/src/Checkbox/Checkbox.styles.tsx +109 -197
- package/src/Checkbox/Checkbox.web.tsx +7 -7
- package/src/Chip/Chip.native.tsx +5 -5
- package/src/Chip/Chip.styles.old.tsx +184 -0
- package/src/Chip/Chip.styles.tsx +34 -22
- package/src/Chip/Chip.web.tsx +5 -5
- package/src/Dialog/Dialog.native.tsx +16 -7
- package/src/Dialog/Dialog.styles.old.tsx +202 -0
- package/src/Dialog/Dialog.styles.tsx +108 -132
- package/src/Dialog/Dialog.web.tsx +4 -4
- package/src/Divider/Divider.native.tsx +29 -42
- package/src/Divider/Divider.styles.old.tsx +172 -0
- package/src/Divider/Divider.styles.tsx +116 -242
- package/src/Divider/Divider.web.tsx +17 -14
- package/src/Icon/Icon.native.tsx +12 -4
- package/src/Icon/Icon.styles.old.tsx +81 -0
- package/src/Icon/Icon.styles.tsx +52 -60
- package/src/Icon/Icon.web.tsx +43 -7
- package/src/Icon/IconSvg/IconSvg.web.tsx +2 -0
- package/src/Image/Image.styles.old.tsx +69 -0
- package/src/Image/Image.styles.tsx +45 -43
- package/src/Input/Input.native.tsx +140 -56
- package/src/Input/Input.styles.old.tsx +289 -0
- package/src/Input/Input.styles.tsx +177 -228
- package/src/Input/Input.web.tsx +5 -8
- package/src/Link/Link.native.tsx +4 -1
- package/src/List/List.native.tsx +5 -2
- package/src/List/List.styles.old.tsx +242 -0
- package/src/List/List.styles.tsx +178 -240
- package/src/List/ListItem.native.tsx +16 -8
- package/src/List/ListItem.web.tsx +26 -15
- package/src/Menu/Menu.native.tsx +1 -1
- package/src/Menu/Menu.styles.old.tsx +197 -0
- package/src/Menu/Menu.styles.tsx +90 -156
- package/src/Menu/Menu.web.tsx +2 -2
- package/src/Menu/MenuItem.native.tsx +9 -5
- package/src/Menu/MenuItem.styles.old.tsx +114 -0
- package/src/Menu/MenuItem.styles.tsx +71 -104
- package/src/Menu/MenuItem.web.tsx +23 -5
- package/src/Popover/Popover.native.tsx +10 -4
- package/src/Popover/Popover.styles.old.tsx +135 -0
- package/src/Popover/Popover.styles.tsx +46 -96
- package/src/Popover/Popover.web.tsx +1 -1
- package/src/Pressable/Pressable.native.tsx +3 -1
- package/src/Pressable/Pressable.styles.old.tsx +27 -0
- package/src/Pressable/Pressable.styles.tsx +35 -20
- package/src/Pressable/Pressable.web.tsx +1 -1
- package/src/Progress/Progress.native.tsx +15 -6
- package/src/Progress/Progress.styles.old.tsx +200 -0
- package/src/Progress/Progress.styles.tsx +69 -118
- package/src/Progress/Progress.web.tsx +10 -9
- package/src/RadioButton/RadioButton.native.tsx +10 -4
- package/src/RadioButton/RadioButton.styles.old.tsx +175 -0
- package/src/RadioButton/RadioButton.styles.tsx +81 -145
- package/src/RadioButton/RadioButton.web.tsx +4 -4
- package/src/SVGImage/SVGImage.styles.old.tsx +86 -0
- package/src/SVGImage/SVGImage.styles.tsx +35 -66
- package/src/Screen/Screen.native.tsx +30 -27
- package/src/Screen/Screen.styles.old.tsx +87 -0
- package/src/Screen/Screen.styles.tsx +120 -71
- package/src/Screen/Screen.web.tsx +2 -2
- package/src/Select/Select.native.tsx +44 -29
- package/src/Select/Select.styles.old.tsx +353 -0
- package/src/Select/Select.styles.tsx +244 -293
- package/src/Select/Select.web.tsx +5 -5
- package/src/Skeleton/Skeleton.styles.old.tsx +67 -0
- package/src/Skeleton/Skeleton.styles.tsx +31 -43
- package/src/Slider/Slider.native.tsx +9 -5
- package/src/Slider/Slider.styles.old.tsx +259 -0
- package/src/Slider/Slider.styles.tsx +157 -227
- package/src/Slider/Slider.web.tsx +5 -5
- package/src/Switch/Switch.native.tsx +11 -5
- package/src/Switch/Switch.styles.old.tsx +203 -0
- package/src/Switch/Switch.styles.tsx +103 -149
- package/src/Switch/Switch.web.tsx +8 -8
- package/src/TabBar/TabBar.native.tsx +24 -31
- package/src/TabBar/TabBar.styles.old.tsx +343 -0
- package/src/TabBar/TabBar.styles.tsx +204 -494
- package/src/TabBar/TabBar.web.tsx +21 -33
- package/src/Table/Table.native.tsx +18 -9
- package/src/Table/Table.styles.old.tsx +311 -0
- package/src/Table/Table.styles.tsx +151 -278
- package/src/Table/Table.web.tsx +1 -1
- package/src/Text/Text.native.tsx +1 -4
- 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 -78
- package/src/Text/Text.web.tsx +2 -2
- package/src/Text/index.ts +1 -0
- package/src/TextArea/TextArea.styles.old.tsx +213 -0
- package/src/TextArea/TextArea.styles.tsx +101 -157
- package/src/Tooltip/Tooltip.native.tsx +2 -2
- package/src/Tooltip/Tooltip.styles.old.tsx +82 -0
- package/src/Tooltip/Tooltip.styles.tsx +38 -53
- package/src/Tooltip/Tooltip.web.tsx +2 -2
- package/src/Video/Video.styles.old.tsx +51 -0
- package/src/Video/Video.styles.tsx +32 -28
- package/src/View/View.native.tsx +12 -12
- package/src/View/View.styles.old.tsx +125 -0
- package/src/View/View.styles.tsx +84 -103
- package/src/View/View.web.tsx +14 -2
- package/src/examples/CardExamples.tsx +0 -6
- package/src/extensions/applyExtension.ts +210 -0
- package/src/extensions/extendComponent.ts +438 -0
- package/src/extensions/index.ts +102 -0
- package/src/extensions/types.ts +497 -0
- package/src/globals.ts +16 -0
- package/src/index.native.ts +4 -0
- package/src/index.ts +28 -0
- package/src/utils/deepMerge.ts +54 -2
|
@@ -1,279 +1,125 @@
|
|
|
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>;
|
|
17
|
+
|
|
6
18
|
type ButtonSize = Size;
|
|
7
|
-
type ButtonIntent = Intent;
|
|
8
19
|
type ButtonType = 'contained' | 'outlined' | 'text';
|
|
9
20
|
|
|
10
21
|
export type ButtonVariants = {
|
|
11
22
|
size: ButtonSize;
|
|
12
|
-
intent:
|
|
23
|
+
intent: Intent;
|
|
13
24
|
type: ButtonType;
|
|
14
25
|
disabled: boolean;
|
|
15
26
|
gradient?: ButtonGradient;
|
|
16
27
|
}
|
|
17
28
|
|
|
18
29
|
/**
|
|
19
|
-
*
|
|
30
|
+
* All dynamic props passed to button style functions.
|
|
20
31
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
32
|
+
export type ButtonDynamicProps = {
|
|
33
|
+
intent?: Intent;
|
|
34
|
+
type?: ButtonType;
|
|
35
|
+
size?: Size;
|
|
36
|
+
disabled?: boolean;
|
|
37
|
+
gradient?: ButtonGradient;
|
|
38
|
+
};
|
|
28
39
|
|
|
29
40
|
/**
|
|
30
|
-
*
|
|
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.
|
|
31
45
|
*/
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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',
|
|
45
68
|
},
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
function createButtonCompoundVariants(theme: Theme): CompoundVariants<keyof ButtonVariants> {
|
|
53
|
-
const compoundVariants: CompoundVariants<keyof ButtonVariants> = [];
|
|
54
|
-
|
|
55
|
-
for (const intent in theme.intents) {
|
|
56
|
-
const intentValue = theme.intents[intent];
|
|
57
|
-
|
|
58
|
-
// Contained + intent
|
|
59
|
-
compoundVariants.push({
|
|
60
|
-
intent,
|
|
61
|
-
type: 'contained',
|
|
62
|
-
styles: {
|
|
63
|
-
backgroundColor: intentValue.primary,
|
|
64
|
-
color: intentValue.contrast,
|
|
69
|
+
variants: {
|
|
70
|
+
// $iterator expands for each button size
|
|
71
|
+
size: {
|
|
72
|
+
paddingVertical: theme.sizes.$button.paddingVertical,
|
|
73
|
+
paddingHorizontal: theme.sizes.$button.paddingHorizontal,
|
|
74
|
+
minHeight: theme.sizes.$button.minHeight,
|
|
65
75
|
},
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
compoundVariants.push({
|
|
70
|
-
intent,
|
|
71
|
-
type: 'outlined',
|
|
72
|
-
styles: {
|
|
73
|
-
color: intentValue.primary,
|
|
74
|
-
borderColor: intentValue.primary,
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// Text + intent
|
|
79
|
-
compoundVariants.push({
|
|
80
|
-
intent,
|
|
81
|
-
type: 'text',
|
|
82
|
-
styles: {
|
|
83
|
-
color: intentValue.primary,
|
|
84
|
-
},
|
|
85
|
-
});
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
return compoundVariants;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Create gradient variant styles for web
|
|
93
|
-
* Applies a transparent overlay gradient over the intent background color
|
|
94
|
-
*/
|
|
95
|
-
function createGradientVariants() {
|
|
96
|
-
return {
|
|
97
|
-
'darken': {
|
|
98
|
-
_web: {
|
|
99
|
-
backgroundImage: 'linear-gradient(135deg, transparent 0%, rgba(0, 0, 0, 0.15) 100%)',
|
|
76
|
+
disabled: {
|
|
77
|
+
true: { opacity: 0.6 },
|
|
78
|
+
false: { opacity: 1, _web: { cursor: 'pointer', _hover: { opacity: 0.90 }, _active: { opacity: 0.75 } } },
|
|
100
79
|
},
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
backgroundImage: 'linear-gradient(135deg, transparent 0%, rgba(255, 255, 255, 0.2) 100%)',
|
|
80
|
+
gradient: {
|
|
81
|
+
darken: { _web: { backgroundImage: 'linear-gradient(135deg, transparent 0%, rgba(0, 0, 0, 0.15) 100%)' } },
|
|
82
|
+
lighten: { _web: { backgroundImage: 'linear-gradient(135deg, transparent 0%, rgba(255, 255, 255, 0.2) 100%)' } },
|
|
105
83
|
},
|
|
106
84
|
},
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
// Contained + intent
|
|
120
|
-
compoundVariants.push({
|
|
121
|
-
intent,
|
|
122
|
-
type: 'contained',
|
|
123
|
-
styles: { color: intentValue.contrast },
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// Outlined + intent
|
|
127
|
-
compoundVariants.push({
|
|
128
|
-
intent,
|
|
129
|
-
type: 'outlined',
|
|
130
|
-
styles: { color: intentValue.primary },
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// Text + intent
|
|
134
|
-
compoundVariants.push({
|
|
135
|
-
intent,
|
|
136
|
-
type: 'text',
|
|
137
|
-
styles: { color: intentValue.primary },
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return compoundVariants;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Create icon color variants dynamically based on theme, intent, and type
|
|
146
|
-
*/
|
|
147
|
-
function createIconColorVariants(theme: Theme, intent: Intent) {
|
|
148
|
-
const intentValue = theme.intents[intent];
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
contained: {
|
|
152
|
-
color: intentValue.contrast,
|
|
153
|
-
},
|
|
154
|
-
outlined: {
|
|
155
|
-
color: intentValue.primary,
|
|
156
|
-
},
|
|
157
|
-
text: {
|
|
158
|
-
color: intentValue.primary,
|
|
159
|
-
},
|
|
160
|
-
} as const;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Generate button icon styles
|
|
165
|
-
*/
|
|
166
|
-
const createButtonIconStyles = (theme: Theme) => {
|
|
167
|
-
return ({ intent }: Partial<ButtonVariants>) => {
|
|
168
|
-
return {
|
|
169
|
-
display: 'flex',
|
|
170
|
-
alignItems: 'center',
|
|
171
|
-
justifyContent: 'center',
|
|
172
|
-
variants: {
|
|
173
|
-
size: buildSizeVariants(theme, 'button', size => ({
|
|
174
|
-
width: size.iconSize,
|
|
175
|
-
height: size.iconSize,
|
|
176
|
-
})),
|
|
177
|
-
type: createIconColorVariants(theme, intent),
|
|
178
|
-
},
|
|
179
|
-
} as const;
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Generate button text styles
|
|
185
|
-
*/
|
|
186
|
-
const createButtonTextStyles = (theme: Theme) => {
|
|
187
|
-
return ({ intent }: Partial<ButtonVariants>) => {
|
|
188
|
-
return {
|
|
189
|
-
fontWeight: '600',
|
|
190
|
-
textAlign: 'center',
|
|
191
|
-
variants: {
|
|
192
|
-
size: buildSizeVariants(theme, 'button', size => ({
|
|
193
|
-
fontSize: size.fontSize,
|
|
194
|
-
})),
|
|
195
|
-
type: createIconColorVariants(theme, intent), // Text uses same colors as icons
|
|
196
|
-
disabled: {
|
|
197
|
-
true: { opacity: 0.6 },
|
|
198
|
-
false: { opacity: 1 },
|
|
199
|
-
},
|
|
85
|
+
}),
|
|
86
|
+
text: ({ intent = 'primary', type = 'contained' }: ButtonDynamicProps) => ({
|
|
87
|
+
fontWeight: '600',
|
|
88
|
+
textAlign: 'center',
|
|
89
|
+
// Inline: contained uses contrast, others use primary
|
|
90
|
+
color: type === 'contained'
|
|
91
|
+
? theme.intents[intent].contrast
|
|
92
|
+
: theme.intents[intent].primary,
|
|
93
|
+
variants: {
|
|
94
|
+
size: {
|
|
95
|
+
fontSize: theme.sizes.$button.fontSize,
|
|
96
|
+
lineHeight: theme.sizes.$button.fontSize,
|
|
200
97
|
},
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
|
|
206
|
-
// transform on native cannot resolve function calls to extract variant structures.
|
|
207
|
-
export const buttonStyles = StyleSheet.create((theme: Theme) => {
|
|
208
|
-
return {
|
|
209
|
-
button: {
|
|
210
|
-
boxSizing: 'border-box',
|
|
211
|
-
alignItems: 'center',
|
|
212
|
-
justifyContent: 'center',
|
|
213
|
-
borderRadius: 8,
|
|
214
|
-
fontWeight: '600',
|
|
215
|
-
textAlign: 'center',
|
|
216
|
-
_web: {
|
|
217
|
-
display: 'flex',
|
|
218
|
-
transition: 'all 0.1s ease',
|
|
98
|
+
disabled: {
|
|
99
|
+
true: { opacity: 0.6 },
|
|
100
|
+
false: { opacity: 1 },
|
|
219
101
|
},
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
},
|
|
234
|
-
_active: {
|
|
235
|
-
opacity: 0.75,
|
|
236
|
-
},
|
|
237
|
-
} },
|
|
238
|
-
} as const,
|
|
239
|
-
gradient: createGradientVariants(),
|
|
240
|
-
} as const,
|
|
241
|
-
compoundVariants: createButtonCompoundVariants(theme),
|
|
242
|
-
} as const,
|
|
243
|
-
icon: {
|
|
244
|
-
display: 'flex',
|
|
245
|
-
alignItems: 'center',
|
|
246
|
-
justifyContent: 'center',
|
|
247
|
-
variants: {
|
|
248
|
-
size: buildSizeVariants(theme, 'button', size => ({
|
|
249
|
-
width: size.iconSize,
|
|
250
|
-
height: size.iconSize,
|
|
251
|
-
})),
|
|
252
|
-
intent: createIntentVariants(theme),
|
|
253
|
-
} as const,
|
|
254
|
-
compoundVariants: createIconCompoundVariants(theme),
|
|
255
|
-
} as const,
|
|
256
|
-
iconContainer: {
|
|
257
|
-
display: 'flex',
|
|
258
|
-
flexDirection: 'row',
|
|
259
|
-
alignItems: 'center',
|
|
260
|
-
justifyContent: 'center',
|
|
261
|
-
gap: 4,
|
|
262
|
-
} as const,
|
|
263
|
-
text: {
|
|
264
|
-
fontWeight: '600',
|
|
265
|
-
textAlign: 'center',
|
|
266
|
-
variants: {
|
|
267
|
-
size: buildSizeVariants(theme, 'button', size => ({
|
|
268
|
-
fontSize: size.fontSize,
|
|
269
|
-
})),
|
|
270
|
-
intent: createIntentVariants(theme),
|
|
271
|
-
disabled: {
|
|
272
|
-
true: { opacity: 0.6 },
|
|
273
|
-
false: { opacity: 1 },
|
|
274
|
-
},
|
|
102
|
+
},
|
|
103
|
+
}),
|
|
104
|
+
icon: ({ intent = 'primary', type = 'contained' }: ButtonDynamicProps) => ({
|
|
105
|
+
display: 'flex',
|
|
106
|
+
alignItems: 'center',
|
|
107
|
+
justifyContent: 'center',
|
|
108
|
+
color: type === 'contained'
|
|
109
|
+
? theme.intents[intent].contrast
|
|
110
|
+
: theme.intents[intent].primary,
|
|
111
|
+
variants: {
|
|
112
|
+
size: {
|
|
113
|
+
width: theme.sizes.$button.iconSize,
|
|
114
|
+
height: theme.sizes.$button.iconSize,
|
|
275
115
|
},
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
116
|
+
},
|
|
117
|
+
}),
|
|
118
|
+
iconContainer: (_props: ButtonDynamicProps) => ({
|
|
119
|
+
display: 'flex' as const,
|
|
120
|
+
flexDirection: 'row' as const,
|
|
121
|
+
alignItems: 'center' as const,
|
|
122
|
+
justifyContent: 'center' as const,
|
|
123
|
+
gap: 4,
|
|
124
|
+
}),
|
|
125
|
+
}));
|
|
@@ -45,9 +45,8 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props: InternalButton
|
|
|
45
45
|
accessibilityHasPopup,
|
|
46
46
|
} = props;
|
|
47
47
|
|
|
48
|
+
// Apply variants for size, disabled, gradient
|
|
48
49
|
buttonStyles.useVariants({
|
|
49
|
-
type,
|
|
50
|
-
intent,
|
|
51
50
|
size,
|
|
52
51
|
disabled,
|
|
53
52
|
gradient,
|
|
@@ -55,8 +54,10 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props: InternalButton
|
|
|
55
54
|
|
|
56
55
|
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
|
57
56
|
e.preventDefault();
|
|
58
|
-
|
|
57
|
+
// Only stop propagation if we have an onPress handler
|
|
58
|
+
// Otherwise, let clicks bubble up to parent handlers (e.g., Menu triggers)
|
|
59
59
|
if (!disabled && onPress) {
|
|
60
|
+
e.stopPropagation();
|
|
60
61
|
onPress();
|
|
61
62
|
}
|
|
62
63
|
};
|
|
@@ -105,10 +106,11 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props: InternalButton
|
|
|
105
106
|
accessibilityHasPopup,
|
|
106
107
|
]);
|
|
107
108
|
|
|
108
|
-
// Compute dynamic styles
|
|
109
|
+
// Compute dynamic styles with all props for full flexibility
|
|
110
|
+
const dynamicProps = { intent, type, size, disabled, gradient };
|
|
109
111
|
const buttonStyleArray = [
|
|
110
|
-
buttonStyles.button,
|
|
111
|
-
buttonStyles.text,
|
|
112
|
+
(buttonStyles.button as any)(dynamicProps),
|
|
113
|
+
(buttonStyles.text as any)(dynamicProps),
|
|
112
114
|
style as any,
|
|
113
115
|
];
|
|
114
116
|
|
|
@@ -116,10 +118,10 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props: InternalButton
|
|
|
116
118
|
const webProps = getWebProps(buttonStyleArray);
|
|
117
119
|
|
|
118
120
|
// Icon container styles
|
|
119
|
-
const iconContainerProps = getWebProps([buttonStyles.iconContainer]);
|
|
121
|
+
const iconContainerProps = getWebProps([(buttonStyles.iconContainer as any)(dynamicProps)]);
|
|
120
122
|
|
|
121
123
|
// Icon styles with dynamic function
|
|
122
|
-
const iconStyleArray = [buttonStyles.icon];
|
|
124
|
+
const iconStyleArray = [(buttonStyles.icon as any)(dynamicProps)];
|
|
123
125
|
const iconProps = getWebProps(iconStyleArray);
|
|
124
126
|
|
|
125
127
|
// Helper to render icon
|
package/src/Card/Card.native.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { forwardRef, ComponentRef, useMemo } from 'react';
|
|
2
2
|
import { View, Pressable } from 'react-native';
|
|
3
|
+
import { useUnistyles } from 'react-native-unistyles';
|
|
3
4
|
import { CardProps } from './types';
|
|
4
5
|
import { cardStyles } from './Card.styles';
|
|
5
6
|
import { getNativeInteractiveAccessibilityProps } from '../utils/accessibility';
|
|
@@ -42,12 +43,12 @@ const Card = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pressabl
|
|
|
42
43
|
accessibilityPressed,
|
|
43
44
|
});
|
|
44
45
|
}, [accessibilityLabel, accessibilityHint, accessibilityDisabled, disabled, accessibilityHidden, accessibilityRole, clickable, accessibilityPressed]);
|
|
46
|
+
|
|
45
47
|
// Apply variants
|
|
46
48
|
cardStyles.useVariants({
|
|
47
|
-
clickable,
|
|
48
|
-
radius,
|
|
49
49
|
type,
|
|
50
|
-
|
|
50
|
+
radius,
|
|
51
|
+
clickable,
|
|
51
52
|
disabled,
|
|
52
53
|
gap,
|
|
53
54
|
padding,
|
|
@@ -58,13 +59,16 @@ const Card = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pressabl
|
|
|
58
59
|
marginHorizontal,
|
|
59
60
|
});
|
|
60
61
|
|
|
62
|
+
// Get card style
|
|
63
|
+
const cardStyle = (cardStyles.card as any)({});
|
|
64
|
+
|
|
61
65
|
// Use appropriate component based on clickable state
|
|
62
66
|
const Component = clickable ? Pressable : View;
|
|
63
67
|
|
|
64
68
|
const componentProps = {
|
|
65
69
|
ref,
|
|
66
70
|
nativeID: id,
|
|
67
|
-
style: [
|
|
71
|
+
style: [cardStyle, style],
|
|
68
72
|
testID,
|
|
69
73
|
...nativeA11yProps,
|
|
70
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
|
+
});
|