@idealyst/components 1.0.99 → 1.1.0
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 +4 -4
- package/src/Accordion/Accordion.native.tsx +15 -0
- package/src/Accordion/Accordion.styles.tsx +17 -0
- package/src/Accordion/Accordion.web.tsx +15 -0
- package/src/Accordion/types.ts +2 -1
- package/src/Button/Button.native.tsx +55 -2
- package/src/Button/Button.styles.tsx +22 -0
- package/src/Button/Button.web.tsx +6 -2
- package/src/Button/types.ts +15 -0
- package/src/Card/Card.native.tsx +18 -5
- package/src/Card/Card.styles.tsx +123 -131
- package/src/Card/Card.web.tsx +17 -4
- package/src/Card/types.ts +3 -8
- package/src/Checkbox/Checkbox.native.tsx +7 -0
- package/src/Checkbox/Checkbox.styles.tsx +11 -0
- package/src/Checkbox/Checkbox.web.tsx +7 -0
- package/src/Checkbox/types.ts +2 -1
- package/src/Input/Input.native.tsx +7 -0
- package/src/Input/Input.styles.tsx +9 -0
- package/src/Input/Input.web.tsx +7 -0
- package/src/Input/types.ts +2 -1
- package/src/List/List.native.tsx +15 -0
- package/src/List/List.styles.tsx +17 -0
- package/src/List/List.web.tsx +15 -0
- package/src/List/types.ts +2 -1
- package/src/Pressable/Pressable.native.tsx +13 -1
- package/src/Pressable/Pressable.styles.tsx +24 -0
- package/src/Pressable/Pressable.web.tsx +24 -6
- package/src/Pressable/types.ts +3 -2
- package/src/RadioButton/RadioButton.native.tsx +7 -0
- package/src/RadioButton/RadioButton.styles.tsx +9 -0
- package/src/RadioButton/RadioButton.web.tsx +7 -0
- package/src/RadioButton/types.ts +2 -1
- package/src/Screen/Screen.native.tsx +25 -12
- package/src/Screen/Screen.styles.tsx +28 -16
- package/src/Screen/Screen.web.tsx +16 -3
- package/src/Screen/types.ts +4 -8
- package/src/Select/Select.native.tsx +7 -0
- package/src/Select/Select.styles.tsx +11 -0
- package/src/Select/Select.web.tsx +7 -0
- package/src/Select/types.ts +2 -1
- package/src/Slider/Slider.native.tsx +7 -0
- package/src/Slider/Slider.styles.tsx +11 -0
- package/src/Slider/Slider.web.tsx +7 -0
- package/src/Slider/types.ts +2 -1
- package/src/Switch/Switch.native.tsx +7 -0
- package/src/Switch/Switch.styles.tsx +11 -0
- package/src/Switch/Switch.web.tsx +7 -0
- package/src/Switch/types.ts +2 -1
- package/src/TabBar/TabBar.native.tsx +19 -1
- package/src/TabBar/TabBar.styles.tsx +17 -0
- package/src/TabBar/TabBar.web.tsx +20 -1
- package/src/TabBar/types.ts +2 -1
- package/src/Table/Table.native.tsx +15 -0
- package/src/Table/Table.styles.tsx +27 -0
- package/src/Table/Table.web.tsx +15 -0
- package/src/Table/types.ts +2 -1
- package/src/Text/Text.native.tsx +14 -3
- package/src/Text/Text.styles.tsx +36 -12
- package/src/Text/Text.web.tsx +15 -4
- package/src/Text/types.ts +15 -4
- package/src/TextArea/TextArea.native.tsx +7 -0
- package/src/TextArea/TextArea.styles.tsx +11 -0
- package/src/TextArea/TextArea.web.tsx +7 -0
- package/src/TextArea/types.ts +2 -1
- package/src/View/View.native.tsx +35 -12
- package/src/View/View.styles.tsx +78 -75
- package/src/View/View.web.tsx +18 -9
- package/src/View/types.ts +8 -23
- package/src/examples/AccordionExamples.tsx +32 -32
- package/src/examples/AlertExamples.tsx +42 -42
- package/src/examples/AvatarExamples.tsx +18 -18
- package/src/examples/BadgeExamples.tsx +30 -30
- package/src/examples/BreadcrumbExamples.tsx +64 -64
- package/src/examples/ButtonExamples.tsx +128 -16
- package/src/examples/CardExamples.tsx +28 -28
- package/src/examples/CheckboxExamples.tsx +25 -25
- package/src/examples/ChipExamples.tsx +17 -17
- package/src/examples/DialogExamples.tsx +17 -17
- package/src/examples/DividerExamples.tsx +21 -21
- package/src/examples/IconExamples.tsx +113 -113
- package/src/examples/ImageExamples.tsx +34 -34
- package/src/examples/InputExamples.tsx +20 -20
- package/src/examples/LinkExamples.tsx +23 -23
- package/src/examples/ListExamples.tsx +42 -42
- package/src/examples/MenuExamples.tsx +15 -15
- package/src/examples/PopoverExamples.tsx +23 -23
- package/src/examples/ProgressExamples.tsx +41 -41
- package/src/examples/RadioButtonExamples.tsx +21 -21
- package/src/examples/SVGImageExamples.tsx +25 -25
- package/src/examples/ScreenExamples.tsx +41 -41
- package/src/examples/SelectExamples.tsx +59 -59
- package/src/examples/SkeletonExamples.tsx +30 -30
- package/src/examples/SliderExamples.tsx +54 -54
- package/src/examples/SwitchExamples.tsx +20 -20
- package/src/examples/TabBarExamples.tsx +26 -26
- package/src/examples/TableExamples.tsx +36 -36
- package/src/examples/TextAreaExamples.tsx +25 -25
- package/src/examples/TextExamples.tsx +61 -66
- package/src/examples/ThemeExtensionExamples.tsx +12 -12
- package/src/examples/TooltipExamples.tsx +21 -21
- package/src/examples/VideoExamples.tsx +28 -28
- package/src/examples/ViewExamples.tsx +59 -59
- package/src/index.ts +4 -0
- package/src/utils/buildViewStyleVariants.ts +148 -0
- package/src/utils/viewStyleProps.ts +63 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@idealyst/components",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Shared component library for React and React Native",
|
|
5
5
|
"documentation": "https://github.com/IdealystIO/idealyst-framework/tree/main/packages/components#readme",
|
|
6
6
|
"readme": "README.md",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"publish:npm": "npm publish"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
|
-
"@idealyst/theme": "^1.0
|
|
44
|
+
"@idealyst/theme": "^1.1.0",
|
|
45
45
|
"@mdi/js": ">=7.0.0",
|
|
46
46
|
"@mdi/react": ">=1.0.0",
|
|
47
47
|
"@react-native-vector-icons/common": ">=12.0.0",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
}
|
|
92
92
|
},
|
|
93
93
|
"devDependencies": {
|
|
94
|
-
"@idealyst/theme": "^1.0
|
|
94
|
+
"@idealyst/theme": "^1.1.0",
|
|
95
95
|
"@mdi/react": "^1.6.1",
|
|
96
96
|
"@types/react": "^19.1.0",
|
|
97
97
|
"react": "^19.1.0",
|
|
@@ -117,4 +117,4 @@
|
|
|
117
117
|
"components",
|
|
118
118
|
"cross-platform"
|
|
119
119
|
]
|
|
120
|
-
}
|
|
120
|
+
}
|
|
@@ -132,6 +132,14 @@ const Accordion = forwardRef<View, AccordionProps>(({
|
|
|
132
132
|
defaultExpanded = [],
|
|
133
133
|
type = 'standard',
|
|
134
134
|
size = 'md',
|
|
135
|
+
// Spacing variants from ContainerStyleProps
|
|
136
|
+
gap,
|
|
137
|
+
padding,
|
|
138
|
+
paddingVertical,
|
|
139
|
+
paddingHorizontal,
|
|
140
|
+
margin,
|
|
141
|
+
marginVertical,
|
|
142
|
+
marginHorizontal,
|
|
135
143
|
style,
|
|
136
144
|
testID,
|
|
137
145
|
}, ref) => {
|
|
@@ -141,6 +149,13 @@ const Accordion = forwardRef<View, AccordionProps>(({
|
|
|
141
149
|
accordionStyles.useVariants({
|
|
142
150
|
type,
|
|
143
151
|
size,
|
|
152
|
+
gap,
|
|
153
|
+
padding,
|
|
154
|
+
paddingVertical,
|
|
155
|
+
paddingHorizontal,
|
|
156
|
+
margin,
|
|
157
|
+
marginVertical,
|
|
158
|
+
marginHorizontal,
|
|
144
159
|
});
|
|
145
160
|
|
|
146
161
|
const toggleItem = (itemId: string, disabled?: boolean) => {
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native-unistyles';
|
|
2
2
|
import { Theme, StylesheetStyles, CompoundVariants, Size} from '@idealyst/theme';
|
|
3
3
|
import { buildSizeVariants } from '../utils/buildSizeVariants';
|
|
4
|
+
import {
|
|
5
|
+
buildGapVariants,
|
|
6
|
+
buildPaddingVariants,
|
|
7
|
+
buildPaddingVerticalVariants,
|
|
8
|
+
buildPaddingHorizontalVariants,
|
|
9
|
+
buildMarginVariants,
|
|
10
|
+
buildMarginVerticalVariants,
|
|
11
|
+
buildMarginHorizontalVariants,
|
|
12
|
+
} from '../utils/buildViewStyleVariants';
|
|
4
13
|
import { AccordionType } from './types';
|
|
5
14
|
|
|
6
15
|
type AccordionSize = Size;
|
|
@@ -127,6 +136,14 @@ export const accordionStyles = StyleSheet.create((theme: Theme) => {
|
|
|
127
136
|
expanded: { true: {}, false: {} },
|
|
128
137
|
disabled: { true: {}, false: {} },
|
|
129
138
|
isLast: { true: {}, false: {} },
|
|
139
|
+
// Spacing variants from ContainerStyleProps
|
|
140
|
+
gap: buildGapVariants(theme),
|
|
141
|
+
padding: buildPaddingVariants(theme),
|
|
142
|
+
paddingVertical: buildPaddingVerticalVariants(theme),
|
|
143
|
+
paddingHorizontal: buildPaddingHorizontalVariants(theme),
|
|
144
|
+
margin: buildMarginVariants(theme),
|
|
145
|
+
marginVertical: buildMarginVerticalVariants(theme),
|
|
146
|
+
marginHorizontal: buildMarginHorizontalVariants(theme),
|
|
130
147
|
},
|
|
131
148
|
},
|
|
132
149
|
item: {
|
|
@@ -98,6 +98,14 @@ const Accordion: React.FC<AccordionProps> = ({
|
|
|
98
98
|
defaultExpanded = [],
|
|
99
99
|
type = 'standard',
|
|
100
100
|
size = 'md',
|
|
101
|
+
// Spacing variants from ContainerStyleProps
|
|
102
|
+
gap,
|
|
103
|
+
padding,
|
|
104
|
+
paddingVertical,
|
|
105
|
+
paddingHorizontal,
|
|
106
|
+
margin,
|
|
107
|
+
marginVertical,
|
|
108
|
+
marginHorizontal,
|
|
101
109
|
style,
|
|
102
110
|
testID,
|
|
103
111
|
}) => {
|
|
@@ -107,6 +115,13 @@ const Accordion: React.FC<AccordionProps> = ({
|
|
|
107
115
|
accordionStyles.useVariants({
|
|
108
116
|
type,
|
|
109
117
|
size,
|
|
118
|
+
gap,
|
|
119
|
+
padding,
|
|
120
|
+
paddingVertical,
|
|
121
|
+
paddingHorizontal,
|
|
122
|
+
margin,
|
|
123
|
+
marginVertical,
|
|
124
|
+
marginHorizontal,
|
|
110
125
|
});
|
|
111
126
|
|
|
112
127
|
const containerProps = getWebProps([accordionStyles.container, style as any]);
|
package/src/Accordion/types.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Size } from '@idealyst/theme';
|
|
2
2
|
import type { StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
import { ContainerStyleProps } from '../utils/viewStyleProps';
|
|
3
4
|
|
|
4
5
|
// Component-specific type aliases for future extensibility
|
|
5
6
|
export type AccordionType = 'standard' | 'separated' | 'bordered';
|
|
@@ -12,7 +13,7 @@ export interface AccordionItem {
|
|
|
12
13
|
disabled?: boolean;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
export interface AccordionProps {
|
|
16
|
+
export interface AccordionProps extends ContainerStyleProps {
|
|
16
17
|
items: AccordionItem[];
|
|
17
18
|
allowMultiple?: boolean;
|
|
18
19
|
defaultExpanded?: string[];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { ComponentRef, forwardRef, isValidElement } from 'react';
|
|
2
|
-
import { Text, TouchableOpacity, View } from 'react-native';
|
|
2
|
+
import { StyleSheet as RNStyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
|
3
3
|
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
|
4
|
+
import Svg, { Defs, LinearGradient, Stop, Rect } from 'react-native-svg';
|
|
4
5
|
import { buttonStyles } from './Button.styles';
|
|
5
6
|
import { ButtonProps } from './types';
|
|
6
7
|
|
|
@@ -13,17 +14,39 @@ const Button = forwardRef<ComponentRef<typeof TouchableOpacity>, ButtonProps>((p
|
|
|
13
14
|
type = 'contained',
|
|
14
15
|
intent = 'primary',
|
|
15
16
|
size = 'md',
|
|
17
|
+
gradient,
|
|
16
18
|
leftIcon,
|
|
17
19
|
rightIcon,
|
|
18
20
|
style,
|
|
19
21
|
testID,
|
|
20
22
|
} = props;
|
|
21
23
|
|
|
24
|
+
// Apply variants
|
|
25
|
+
buttonStyles.useVariants({
|
|
26
|
+
type,
|
|
27
|
+
intent,
|
|
28
|
+
size,
|
|
29
|
+
disabled,
|
|
30
|
+
gradient,
|
|
31
|
+
});
|
|
32
|
+
|
|
22
33
|
// Compute dynamic styles
|
|
23
34
|
const buttonStyle = buttonStyles.button;
|
|
24
35
|
const textStyle = buttonStyles.text;
|
|
25
36
|
const iconStyle = buttonStyles.icon;
|
|
26
37
|
|
|
38
|
+
// Gradient is only applicable to contained buttons
|
|
39
|
+
const showGradient = gradient && type === 'contained';
|
|
40
|
+
|
|
41
|
+
// Get gradient overlay colors (transparent to semi-transparent black/white)
|
|
42
|
+
const getGradientColors = (): [string, string] => {
|
|
43
|
+
switch (gradient) {
|
|
44
|
+
case 'darken': return ['transparent', 'rgba(0, 0, 0, 0.15)'];
|
|
45
|
+
case 'lighten': return ['transparent', 'rgba(255, 255, 255, 0.2)'];
|
|
46
|
+
default: return ['transparent', 'transparent'];
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
27
50
|
// Map button size to icon size
|
|
28
51
|
const iconSizeMap = {
|
|
29
52
|
xs: 12,
|
|
@@ -59,6 +82,31 @@ const Button = forwardRef<ComponentRef<typeof TouchableOpacity>, ButtonProps>((p
|
|
|
59
82
|
// Determine if we need to wrap content in icon container
|
|
60
83
|
const hasIcons = leftIcon || rightIcon;
|
|
61
84
|
|
|
85
|
+
// Render gradient background layer
|
|
86
|
+
const renderGradientLayer = () => {
|
|
87
|
+
if (!showGradient) return null;
|
|
88
|
+
|
|
89
|
+
const [startColor, endColor] = getGradientColors();
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<Svg style={RNStyleSheet.absoluteFill}>
|
|
93
|
+
<Defs>
|
|
94
|
+
<LinearGradient id="buttonGradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
95
|
+
<Stop offset="0%" stopColor={startColor} />
|
|
96
|
+
<Stop offset="100%" stopColor={endColor} />
|
|
97
|
+
</LinearGradient>
|
|
98
|
+
</Defs>
|
|
99
|
+
<Rect
|
|
100
|
+
width="100%"
|
|
101
|
+
height="100%"
|
|
102
|
+
fill="url(#buttonGradient)"
|
|
103
|
+
rx={8}
|
|
104
|
+
ry={8}
|
|
105
|
+
/>
|
|
106
|
+
</Svg>
|
|
107
|
+
);
|
|
108
|
+
};
|
|
109
|
+
|
|
62
110
|
return (
|
|
63
111
|
<TouchableOpacity
|
|
64
112
|
ref={ref}
|
|
@@ -66,8 +114,13 @@ const Button = forwardRef<ComponentRef<typeof TouchableOpacity>, ButtonProps>((p
|
|
|
66
114
|
disabled={disabled}
|
|
67
115
|
testID={testID}
|
|
68
116
|
activeOpacity={0.7}
|
|
69
|
-
style={[
|
|
117
|
+
style={[
|
|
118
|
+
buttonStyle,
|
|
119
|
+
showGradient && { overflow: 'hidden' },
|
|
120
|
+
style,
|
|
121
|
+
]}
|
|
70
122
|
>
|
|
123
|
+
{renderGradientLayer()}
|
|
71
124
|
{hasIcons ? (
|
|
72
125
|
<View style={buttonStyles.iconContainer}>
|
|
73
126
|
{leftIcon && renderIcon(leftIcon)}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native-unistyles';
|
|
2
2
|
import { Theme, Intent, Size, CompoundVariants} from '@idealyst/theme';
|
|
3
3
|
import { buildSizeVariants } from '../utils/buildSizeVariants';
|
|
4
|
+
import { ButtonGradient } from './types';
|
|
4
5
|
|
|
5
6
|
type ButtonSize = Size;
|
|
6
7
|
type ButtonIntent = Intent;
|
|
@@ -11,6 +12,7 @@ export type ButtonVariants = {
|
|
|
11
12
|
intent: ButtonIntent;
|
|
12
13
|
type: ButtonType;
|
|
13
14
|
disabled: boolean;
|
|
15
|
+
gradient?: ButtonGradient;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
/**
|
|
@@ -86,6 +88,25 @@ function createButtonCompoundVariants(theme: Theme): CompoundVariants<keyof Butt
|
|
|
86
88
|
return compoundVariants;
|
|
87
89
|
}
|
|
88
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%)',
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
'lighten': {
|
|
103
|
+
_web: {
|
|
104
|
+
backgroundImage: 'linear-gradient(135deg, transparent 0%, rgba(255, 255, 255, 0.2) 100%)',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
} as const;
|
|
108
|
+
}
|
|
109
|
+
|
|
89
110
|
/**
|
|
90
111
|
* Create icon compound variants for intent+type combinations
|
|
91
112
|
*/
|
|
@@ -214,6 +235,7 @@ export const buttonStyles = StyleSheet.create((theme: Theme) => {
|
|
|
214
235
|
},
|
|
215
236
|
} },
|
|
216
237
|
} as const,
|
|
238
|
+
gradient: createGradientVariants(),
|
|
217
239
|
} as const,
|
|
218
240
|
compoundVariants: createButtonCompoundVariants(theme),
|
|
219
241
|
} as const,
|
|
@@ -21,6 +21,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props: InternalButton
|
|
|
21
21
|
type = 'contained',
|
|
22
22
|
intent = 'primary',
|
|
23
23
|
size = 'md',
|
|
24
|
+
gradient,
|
|
24
25
|
leftIcon,
|
|
25
26
|
rightIcon,
|
|
26
27
|
leftIconPath,
|
|
@@ -33,10 +34,13 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props: InternalButton
|
|
|
33
34
|
type,
|
|
34
35
|
intent,
|
|
35
36
|
size,
|
|
36
|
-
disabled
|
|
37
|
+
disabled,
|
|
38
|
+
gradient,
|
|
37
39
|
});
|
|
38
40
|
|
|
39
|
-
const handleClick = () => {
|
|
41
|
+
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
|
42
|
+
e.preventDefault();
|
|
43
|
+
e.stopPropagation();
|
|
40
44
|
if (!disabled && onPress) {
|
|
41
45
|
onPress();
|
|
42
46
|
}
|
package/src/Button/types.ts
CHANGED
|
@@ -8,6 +8,14 @@ export type ButtonType = 'contained' | 'outlined' | 'text';
|
|
|
8
8
|
export type ButtonIntentVariant = Intent;
|
|
9
9
|
export type ButtonSizeVariant = Size;
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Gradient overlay options for buttons.
|
|
13
|
+
* Applies a transparent gradient over the intent background color.
|
|
14
|
+
* - 'darken': Transparent to semi-transparent black (darkens one corner)
|
|
15
|
+
* - 'lighten': Transparent to semi-transparent white (lightens one corner)
|
|
16
|
+
*/
|
|
17
|
+
export type ButtonGradient = 'darken' | 'lighten';
|
|
18
|
+
|
|
11
19
|
export interface ButtonProps {
|
|
12
20
|
/**
|
|
13
21
|
* The text or content to display inside the button
|
|
@@ -44,6 +52,13 @@ export interface ButtonProps {
|
|
|
44
52
|
*/
|
|
45
53
|
size?: ButtonSizeVariant;
|
|
46
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Apply a gradient background enhancement.
|
|
57
|
+
* Only applies to 'contained' button type.
|
|
58
|
+
* Options: 'color-to-dark', 'color-to-light', 'light-to-color', 'dark-to-color'
|
|
59
|
+
*/
|
|
60
|
+
gradient?: ButtonGradient;
|
|
61
|
+
|
|
47
62
|
/**
|
|
48
63
|
* Icon to display on the left side. Can be an icon name or custom component (ReactNode)
|
|
49
64
|
*/
|
package/src/Card/Card.native.tsx
CHANGED
|
@@ -5,13 +5,20 @@ import { cardStyles } from './Card.styles';
|
|
|
5
5
|
|
|
6
6
|
const Card = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pressable>, CardProps>(({
|
|
7
7
|
children,
|
|
8
|
-
type = '
|
|
9
|
-
padding = 'md',
|
|
8
|
+
type = 'elevated',
|
|
10
9
|
radius = 'md',
|
|
11
10
|
intent = 'neutral',
|
|
12
11
|
clickable = false,
|
|
13
12
|
onPress,
|
|
14
13
|
disabled = false,
|
|
14
|
+
// Spacing variants from ContainerStyleProps
|
|
15
|
+
gap,
|
|
16
|
+
padding,
|
|
17
|
+
paddingVertical,
|
|
18
|
+
paddingHorizontal,
|
|
19
|
+
margin,
|
|
20
|
+
marginVertical,
|
|
21
|
+
marginHorizontal,
|
|
15
22
|
style,
|
|
16
23
|
testID,
|
|
17
24
|
accessibilityLabel,
|
|
@@ -21,11 +28,17 @@ const Card = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pressabl
|
|
|
21
28
|
clickable,
|
|
22
29
|
radius,
|
|
23
30
|
type,
|
|
24
|
-
padding,
|
|
25
31
|
intent,
|
|
26
32
|
disabled,
|
|
33
|
+
gap,
|
|
34
|
+
padding,
|
|
35
|
+
paddingVertical,
|
|
36
|
+
paddingHorizontal,
|
|
37
|
+
margin,
|
|
38
|
+
marginVertical,
|
|
39
|
+
marginHorizontal,
|
|
27
40
|
});
|
|
28
|
-
|
|
41
|
+
|
|
29
42
|
// Use appropriate component based on clickable state
|
|
30
43
|
const Component = clickable ? Pressable : View;
|
|
31
44
|
|
|
@@ -52,4 +65,4 @@ const Card = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pressabl
|
|
|
52
65
|
|
|
53
66
|
Card.displayName = 'Card';
|
|
54
67
|
|
|
55
|
-
export default Card;
|
|
68
|
+
export default Card;
|
package/src/Card/Card.styles.tsx
CHANGED
|
@@ -1,107 +1,94 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native-unistyles';
|
|
2
2
|
import { Theme, Intent, CompoundVariants } 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';
|
|
3
13
|
|
|
4
|
-
type CardType = '
|
|
5
|
-
type
|
|
6
|
-
type CardRadius = 'none' | 'sm' | 'md' | 'lg';
|
|
14
|
+
type CardType = 'outlined' | 'elevated' | 'filled';
|
|
15
|
+
type CardRadius = 'none' | 'sm' | 'md' | 'lg' | 'xs' | 'xl';
|
|
7
16
|
type CardIntent = Intent | 'info' | 'neutral';
|
|
8
17
|
|
|
9
18
|
export type CardVariants = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
type: CardType;
|
|
20
|
+
radius: CardRadius;
|
|
21
|
+
intent: CardIntent;
|
|
22
|
+
clickable: boolean;
|
|
23
|
+
disabled: boolean;
|
|
24
|
+
// Spacing variants from ContainerStyleProps
|
|
25
|
+
gap: ViewStyleSize;
|
|
26
|
+
padding: ViewStyleSize;
|
|
27
|
+
paddingVertical: ViewStyleSize;
|
|
28
|
+
paddingHorizontal: ViewStyleSize;
|
|
29
|
+
margin: ViewStyleSize;
|
|
30
|
+
marginVertical: ViewStyleSize;
|
|
31
|
+
marginHorizontal: ViewStyleSize;
|
|
32
|
+
};
|
|
17
33
|
|
|
18
34
|
/**
|
|
19
35
|
* Create type variants (structure only, colors handled by compound variants)
|
|
20
36
|
*/
|
|
21
37
|
function createTypeVariants(theme: Theme) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
filled: {
|
|
39
|
-
backgroundColor: theme.colors.surface.secondary,
|
|
40
|
-
borderWidth: 0,
|
|
41
|
-
},
|
|
42
|
-
} as const;
|
|
38
|
+
return {
|
|
39
|
+
outlined: {
|
|
40
|
+
backgroundColor: 'transparent',
|
|
41
|
+
borderWidth: 1,
|
|
42
|
+
borderStyle: 'solid' as const,
|
|
43
|
+
},
|
|
44
|
+
elevated: {
|
|
45
|
+
backgroundColor: theme.colors.surface.primary,
|
|
46
|
+
borderWidth: 0,
|
|
47
|
+
...theme.shadows.md,
|
|
48
|
+
},
|
|
49
|
+
filled: {
|
|
50
|
+
backgroundColor: theme.colors.surface.secondary,
|
|
51
|
+
borderWidth: 0,
|
|
52
|
+
},
|
|
53
|
+
} as const;
|
|
43
54
|
}
|
|
44
55
|
|
|
45
56
|
/**
|
|
46
57
|
* Create compound variants for type + intent combinations
|
|
47
58
|
*/
|
|
48
59
|
function createCardCompoundVariants(theme: Theme) {
|
|
49
|
-
|
|
60
|
+
const compoundVariants: CompoundVariants<keyof CardVariants> = [];
|
|
50
61
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
62
|
+
// Add intent-based border colors for outlined type
|
|
63
|
+
for (const intent in theme.intents) {
|
|
64
|
+
const intentValue = theme.intents[intent as Intent];
|
|
54
65
|
|
|
55
|
-
// Default + intent
|
|
56
|
-
compoundVariants.push({
|
|
57
|
-
intent,
|
|
58
|
-
type: 'default',
|
|
59
|
-
styles: {
|
|
60
|
-
borderColor: intentValue.primary,
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
// Outlined + intent
|
|
65
|
-
compoundVariants.push({
|
|
66
|
-
intent,
|
|
67
|
-
type: 'outlined',
|
|
68
|
-
styles: {
|
|
69
|
-
borderColor: intentValue.primary,
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Add special intents (info, neutral)
|
|
75
66
|
compoundVariants.push({
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
});
|
|
82
|
-
compoundVariants.push({
|
|
83
|
-
intent: 'info',
|
|
84
|
-
type: 'outlined',
|
|
85
|
-
styles: {
|
|
86
|
-
borderColor: theme.colors.border.secondary,
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
compoundVariants.push({
|
|
90
|
-
intent: 'neutral',
|
|
91
|
-
type: 'default',
|
|
92
|
-
styles: {
|
|
93
|
-
borderColor: theme.colors.border.secondary,
|
|
94
|
-
},
|
|
95
|
-
});
|
|
96
|
-
compoundVariants.push({
|
|
97
|
-
intent: 'neutral',
|
|
98
|
-
type: 'outlined',
|
|
99
|
-
styles: {
|
|
100
|
-
borderColor: theme.colors.border.secondary,
|
|
101
|
-
},
|
|
67
|
+
intent,
|
|
68
|
+
type: 'outlined',
|
|
69
|
+
styles: {
|
|
70
|
+
borderColor: intentValue.primary,
|
|
71
|
+
},
|
|
102
72
|
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Add special intents (info, neutral) for outlined type
|
|
76
|
+
compoundVariants.push({
|
|
77
|
+
intent: 'info',
|
|
78
|
+
type: 'outlined',
|
|
79
|
+
styles: {
|
|
80
|
+
borderColor: theme.colors.border.secondary,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
compoundVariants.push({
|
|
84
|
+
intent: 'neutral',
|
|
85
|
+
type: 'outlined',
|
|
86
|
+
styles: {
|
|
87
|
+
borderColor: theme.colors.border.secondary,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
103
90
|
|
|
104
|
-
|
|
91
|
+
return compoundVariants;
|
|
105
92
|
}
|
|
106
93
|
|
|
107
94
|
// Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
|
|
@@ -109,58 +96,63 @@ function createCardCompoundVariants(theme: Theme) {
|
|
|
109
96
|
export const cardStyles = StyleSheet.create((theme: Theme) => {
|
|
110
97
|
return {
|
|
111
98
|
card: {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
transform: 'translateY(-2px)',
|
|
136
|
-
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.06)',
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
false: {
|
|
141
|
-
_web: {
|
|
142
|
-
cursor: 'default',
|
|
143
|
-
},
|
|
144
|
-
},
|
|
99
|
+
backgroundColor: theme.colors.surface.primary,
|
|
100
|
+
position: 'relative',
|
|
101
|
+
overflow: 'hidden',
|
|
102
|
+
variants: {
|
|
103
|
+
type: createTypeVariants(theme),
|
|
104
|
+
radius: {
|
|
105
|
+
none: { borderRadius: 0 },
|
|
106
|
+
xs: { borderRadius: 2 },
|
|
107
|
+
sm: { borderRadius: 4 },
|
|
108
|
+
md: { borderRadius: 8 },
|
|
109
|
+
lg: { borderRadius: 12 },
|
|
110
|
+
xl: { borderRadius: 16 },
|
|
111
|
+
},
|
|
112
|
+
clickable: {
|
|
113
|
+
true: {
|
|
114
|
+
_web: {
|
|
115
|
+
cursor: 'pointer',
|
|
116
|
+
transition: 'all 0.2s ease',
|
|
117
|
+
_hover: {
|
|
118
|
+
transform: 'translateY(-2px)',
|
|
119
|
+
boxShadow:
|
|
120
|
+
'0 4px 12px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.06)',
|
|
121
|
+
},
|
|
145
122
|
},
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
cursor: 'not-allowed',
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
false: {
|
|
154
|
-
opacity: 1,
|
|
155
|
-
},
|
|
123
|
+
},
|
|
124
|
+
false: {
|
|
125
|
+
_web: {
|
|
126
|
+
cursor: 'default',
|
|
156
127
|
},
|
|
128
|
+
},
|
|
157
129
|
},
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
130
|
+
disabled: {
|
|
131
|
+
true: {
|
|
132
|
+
opacity: 0.6,
|
|
133
|
+
_web: {
|
|
134
|
+
cursor: 'not-allowed',
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
false: {
|
|
138
|
+
opacity: 1,
|
|
139
|
+
},
|
|
163
140
|
},
|
|
141
|
+
// Spacing variants from ContainerStyleProps
|
|
142
|
+
gap: buildGapVariants(theme),
|
|
143
|
+
padding: buildPaddingVariants(theme),
|
|
144
|
+
paddingVertical: buildPaddingVerticalVariants(theme),
|
|
145
|
+
paddingHorizontal: buildPaddingHorizontalVariants(theme),
|
|
146
|
+
margin: buildMarginVariants(theme),
|
|
147
|
+
marginVertical: buildMarginVerticalVariants(theme),
|
|
148
|
+
marginHorizontal: buildMarginHorizontalVariants(theme),
|
|
149
|
+
},
|
|
150
|
+
compoundVariants: createCardCompoundVariants(theme),
|
|
151
|
+
_web: {
|
|
152
|
+
display: 'flex',
|
|
153
|
+
flexDirection: 'column',
|
|
154
|
+
boxSizing: 'border-box',
|
|
155
|
+
},
|
|
164
156
|
} as const,
|
|
165
157
|
};
|
|
166
|
-
});
|
|
158
|
+
});
|