@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
|
@@ -59,19 +59,24 @@ const ListItem = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pres
|
|
|
59
59
|
disabled,
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
// Get dynamic
|
|
62
|
+
// Get dynamic styles - call as functions to get theme-reactive styles
|
|
63
63
|
const itemStyle = (listStyles.item as any)({ type: effectiveVariant, disabled, clickable: isClickable });
|
|
64
|
+
const labelStyle = (listStyles.label as any)({ disabled, selected });
|
|
65
|
+
const leadingStyle = (listStyles.leading as any)({});
|
|
66
|
+
const trailingStyle = (listStyles.trailing as any)({});
|
|
67
|
+
const trailingIconStyle = (listStyles.trailingIcon as any)({});
|
|
68
|
+
const labelContainerStyle = (listStyles.labelContainer as any)({});
|
|
64
69
|
|
|
65
70
|
// Resolve icon color - check intents first, then color palette
|
|
66
|
-
const resolvedIconColor = (() => {
|
|
67
|
-
if (!iconColor) return
|
|
71
|
+
const resolvedIconColor = useMemo(() => {
|
|
72
|
+
if (!iconColor) return trailingIconStyle.color || leadingStyle.color;
|
|
68
73
|
// Check if it's an intent name
|
|
69
74
|
if (iconColor in theme.intents) {
|
|
70
75
|
return theme.intents[iconColor as Intent]?.primary;
|
|
71
76
|
}
|
|
72
77
|
// Otherwise try color palette
|
|
73
78
|
return getColorFromString(theme, iconColor as Color);
|
|
74
|
-
})
|
|
79
|
+
}, [iconColor, theme, trailingIconStyle.color, leadingStyle.color]);
|
|
75
80
|
|
|
76
81
|
// Helper to render leading/trailing icons
|
|
77
82
|
const renderElement = (element: typeof leading | typeof trailing, styleKey: 'leading' | 'trailingIcon') => {
|
|
@@ -79,12 +84,12 @@ const ListItem = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pres
|
|
|
79
84
|
|
|
80
85
|
// If it's a string, treat it as an icon name
|
|
81
86
|
if (typeof element === 'string') {
|
|
82
|
-
const
|
|
87
|
+
const iconSize = styleKey === 'leading' ? leadingStyle.width : trailingIconStyle.width;
|
|
83
88
|
return (
|
|
84
89
|
<MaterialCommunityIcons
|
|
85
90
|
name={element}
|
|
86
|
-
size={
|
|
87
|
-
color={resolvedIconColor
|
|
91
|
+
size={iconSize}
|
|
92
|
+
color={resolvedIconColor}
|
|
88
93
|
/>
|
|
89
94
|
);
|
|
90
95
|
} else if (isValidElement(element)) {
|
|
@@ -98,20 +103,20 @@ const ListItem = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pres
|
|
|
98
103
|
const content = (
|
|
99
104
|
<>
|
|
100
105
|
{leading && (
|
|
101
|
-
<View style={
|
|
106
|
+
<View style={leadingStyle}>
|
|
102
107
|
{renderElement(leading, 'leading')}
|
|
103
108
|
</View>
|
|
104
109
|
)}
|
|
105
110
|
|
|
106
|
-
<View style={
|
|
111
|
+
<View style={labelContainerStyle}>
|
|
107
112
|
{label && (
|
|
108
|
-
<Text style={
|
|
113
|
+
<Text style={labelStyle}>{label}</Text>
|
|
109
114
|
)}
|
|
110
115
|
{children}
|
|
111
116
|
</View>
|
|
112
117
|
|
|
113
118
|
{trailing && (
|
|
114
|
-
<View style={
|
|
119
|
+
<View style={trailingStyle}>
|
|
115
120
|
{renderElement(trailing, 'trailingIcon')}
|
|
116
121
|
</View>
|
|
117
122
|
)}
|
|
@@ -5,7 +5,7 @@ import { getColorFromString, Intent, Theme, Color } from '@idealyst/theme';
|
|
|
5
5
|
import { listStyles } from './List.styles';
|
|
6
6
|
import type { ListItemProps } from './types';
|
|
7
7
|
import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
|
|
8
|
-
import {
|
|
8
|
+
import { isIconName } from '../Icon/icon-resolver';
|
|
9
9
|
import { useListContext } from './ListContext';
|
|
10
10
|
|
|
11
11
|
const ListItem: React.FC<ListItemProps> = ({
|
|
@@ -40,13 +40,19 @@ const ListItem: React.FC<ListItemProps> = ({
|
|
|
40
40
|
disabled,
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
-
// Get dynamic
|
|
43
|
+
// Get dynamic styles - call as functions for theme reactivity
|
|
44
44
|
const itemStyle = (listStyles.item as any)({ type: effectiveVariant, disabled, clickable: isClickable });
|
|
45
|
+
const labelStyle = (listStyles.label as any)({ disabled, selected });
|
|
46
|
+
const leadingStyle = (listStyles.leading as any)({});
|
|
47
|
+
const trailingStyle = (listStyles.trailing as any)({});
|
|
48
|
+
const trailingIconStyle = (listStyles.trailingIcon as any)({});
|
|
49
|
+
const labelContainerStyle = (listStyles.labelContainer as any)({});
|
|
50
|
+
|
|
45
51
|
const itemProps = getWebProps([itemStyle, style]);
|
|
46
|
-
const labelProps = getWebProps([
|
|
47
|
-
const leadingProps = getWebProps([
|
|
48
|
-
const trailingProps = getWebProps([
|
|
49
|
-
const trailingIconProps = getWebProps([
|
|
52
|
+
const labelProps = getWebProps([labelStyle]);
|
|
53
|
+
const leadingProps = getWebProps([leadingStyle]);
|
|
54
|
+
const trailingProps = getWebProps([trailingStyle]);
|
|
55
|
+
const trailingIconProps = getWebProps([trailingStyle, trailingIconStyle]);
|
|
50
56
|
|
|
51
57
|
const handleClick = () => {
|
|
52
58
|
if (!disabled && onPress) {
|
|
@@ -66,18 +72,16 @@ const ListItem: React.FC<ListItemProps> = ({
|
|
|
66
72
|
})();
|
|
67
73
|
|
|
68
74
|
// Helper to render leading/trailing icons
|
|
69
|
-
|
|
75
|
+
// IconSvg uses size="1em" by default, sized by container's fontSize from styles
|
|
76
|
+
const renderElement = (element: typeof leading | typeof trailing, isTrailing = false) => {
|
|
70
77
|
if (!element) return null;
|
|
71
78
|
|
|
72
79
|
if (isIconName(element)) {
|
|
73
|
-
|
|
74
|
-
// Use trailingIconProps for trailing icons to apply size constraints
|
|
75
|
-
const iconPropsToUse = isTrailing ? trailingIconProps : props;
|
|
80
|
+
// Use IconSvg with name - registry lookup happens inside
|
|
76
81
|
return (
|
|
77
82
|
<IconSvg
|
|
78
|
-
|
|
79
|
-
{
|
|
80
|
-
color={resolvedIconColor}
|
|
83
|
+
name={element}
|
|
84
|
+
color={resolvedIconColor || 'currentColor'}
|
|
81
85
|
aria-label={element}
|
|
82
86
|
/>
|
|
83
87
|
);
|
|
@@ -88,11 +92,17 @@ const ListItem: React.FC<ListItemProps> = ({
|
|
|
88
92
|
return null;
|
|
89
93
|
};
|
|
90
94
|
|
|
95
|
+
const labelContainerProps = getWebProps([labelContainerStyle]);
|
|
96
|
+
|
|
91
97
|
const content = (
|
|
92
98
|
<>
|
|
93
|
-
{leading &&
|
|
99
|
+
{leading && (
|
|
100
|
+
<span {...leadingProps}>
|
|
101
|
+
{renderElement(leading)}
|
|
102
|
+
</span>
|
|
103
|
+
)}
|
|
94
104
|
|
|
95
|
-
<div {...
|
|
105
|
+
<div {...labelContainerProps}>
|
|
96
106
|
{label && (
|
|
97
107
|
<span {...labelProps}>{label}</span>
|
|
98
108
|
)}
|
|
@@ -101,7 +111,7 @@ const ListItem: React.FC<ListItemProps> = ({
|
|
|
101
111
|
|
|
102
112
|
{trailing && (
|
|
103
113
|
<div {...trailingProps}>
|
|
104
|
-
{renderElement(trailing,
|
|
114
|
+
{renderElement(trailing, true)}
|
|
105
115
|
</div>
|
|
106
116
|
)}
|
|
107
117
|
</>
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
2
|
+
import { Theme, StylesheetStyles, CompoundVariants, Intent, Size } from '@idealyst/theme';
|
|
3
|
+
import { buildSizeVariants } from '../utils/buildSizeVariants';
|
|
4
|
+
import { applyExtensions } from '../extensions/applyExtension';
|
|
5
|
+
|
|
6
|
+
type MenuSize = Size;
|
|
7
|
+
type MenuIntent = Intent;
|
|
8
|
+
|
|
9
|
+
type MenuVariants = {
|
|
10
|
+
size: MenuSize;
|
|
11
|
+
intent: MenuIntent;
|
|
12
|
+
disabled: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type ExpandedMenuStyles = StylesheetStyles<keyof MenuVariants>;
|
|
16
|
+
|
|
17
|
+
export type MenuStylesheet = {
|
|
18
|
+
overlay: ExpandedMenuStyles;
|
|
19
|
+
menu: ExpandedMenuStyles;
|
|
20
|
+
separator: ExpandedMenuStyles;
|
|
21
|
+
item: ExpandedMenuStyles;
|
|
22
|
+
icon: ExpandedMenuStyles;
|
|
23
|
+
label: ExpandedMenuStyles;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Create size variants for menu item
|
|
28
|
+
*/
|
|
29
|
+
function createItemSizeVariants(theme: Theme) {
|
|
30
|
+
return buildSizeVariants(theme, 'menu', (size) => ({
|
|
31
|
+
paddingVertical: size.paddingVertical,
|
|
32
|
+
paddingHorizontal: size.paddingHorizontal,
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get hover styles for menu item based on intent
|
|
38
|
+
*/
|
|
39
|
+
function getItemHoverStyles(theme: Theme, intent: MenuIntent) {
|
|
40
|
+
if (intent === 'neutral') {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
const intentValue = theme.intents[intent];
|
|
44
|
+
return {
|
|
45
|
+
_web: {
|
|
46
|
+
_hover: {
|
|
47
|
+
backgroundColor: intentValue.light + '20',
|
|
48
|
+
color: intentValue.primary,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
} as const;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Create compound variants for menu item
|
|
56
|
+
*/
|
|
57
|
+
function createItemCompoundVariants(theme: Theme): CompoundVariants<keyof MenuVariants> {
|
|
58
|
+
return [
|
|
59
|
+
{
|
|
60
|
+
disabled: true,
|
|
61
|
+
styles: {
|
|
62
|
+
_web: {
|
|
63
|
+
_hover: {
|
|
64
|
+
backgroundColor: 'transparent',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
] as const;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Create size variants for icon
|
|
74
|
+
*/
|
|
75
|
+
function createIconSizeVariants(theme: Theme) {
|
|
76
|
+
return buildSizeVariants(theme, 'menu', (size) => ({
|
|
77
|
+
width: size.iconSize,
|
|
78
|
+
height: size.iconSize,
|
|
79
|
+
fontSize: size.iconSize,
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Create size variants for label
|
|
85
|
+
*/
|
|
86
|
+
function createLabelSizeVariants(theme: Theme) {
|
|
87
|
+
return buildSizeVariants(theme, 'menu', (size) => ({
|
|
88
|
+
fontSize: size.labelFontSize,
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Main element style creators (for extension support)
|
|
93
|
+
function createOverlayStyles(theme: Theme) {
|
|
94
|
+
return () => ({
|
|
95
|
+
backgroundColor: 'transparent',
|
|
96
|
+
_web: {
|
|
97
|
+
position: 'fixed' as const,
|
|
98
|
+
top: 0,
|
|
99
|
+
left: 0,
|
|
100
|
+
right: 0,
|
|
101
|
+
bottom: 0,
|
|
102
|
+
zIndex: 999,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function createMenuStyles(theme: Theme) {
|
|
108
|
+
return () => ({
|
|
109
|
+
position: 'absolute' as const,
|
|
110
|
+
zIndex: 1000,
|
|
111
|
+
backgroundColor: theme.colors.surface.primary,
|
|
112
|
+
borderWidth: 1,
|
|
113
|
+
borderStyle: 'solid' as const,
|
|
114
|
+
borderColor: theme.colors.border.primary,
|
|
115
|
+
borderRadius: 8,
|
|
116
|
+
minWidth: 120,
|
|
117
|
+
maxWidth: 400,
|
|
118
|
+
padding: 4,
|
|
119
|
+
display: 'flex' as const,
|
|
120
|
+
flexDirection: 'column' as const,
|
|
121
|
+
_web: {
|
|
122
|
+
border: `1px solid ${theme.colors.border.primary}`,
|
|
123
|
+
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
|
|
124
|
+
width: 'fit-content',
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function createItemStyles(theme: Theme) {
|
|
130
|
+
return ({ intent }: Partial<MenuVariants>) => {
|
|
131
|
+
const hoverStyles = getItemHoverStyles(theme, intent ?? 'neutral');
|
|
132
|
+
return {
|
|
133
|
+
flexDirection: 'row',
|
|
134
|
+
alignItems: 'center',
|
|
135
|
+
backgroundColor: 'transparent',
|
|
136
|
+
borderRadius: 4,
|
|
137
|
+
minHeight: 44,
|
|
138
|
+
variants: {
|
|
139
|
+
size: createItemSizeVariants(theme),
|
|
140
|
+
disabled: {
|
|
141
|
+
true: {
|
|
142
|
+
opacity: 0.5,
|
|
143
|
+
_web: {
|
|
144
|
+
cursor: 'not-allowed',
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
false: {},
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
compoundVariants: createItemCompoundVariants(theme),
|
|
151
|
+
_web: {
|
|
152
|
+
cursor: 'pointer',
|
|
153
|
+
border: 'none',
|
|
154
|
+
outline: 'none',
|
|
155
|
+
transition: 'background-color 0.2s ease',
|
|
156
|
+
textAlign: 'left',
|
|
157
|
+
_hover: {
|
|
158
|
+
backgroundColor: theme.colors.surface.secondary,
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
...hoverStyles,
|
|
162
|
+
} as const;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel transform on native cannot resolve function calls to extract variant structures.
|
|
167
|
+
export const menuStyles = StyleSheet.create((theme: Theme) => {
|
|
168
|
+
// Apply extensions to main visual elements
|
|
169
|
+
|
|
170
|
+
return applyExtensions('Menu', theme, {overlay: createOverlayStyles(theme),
|
|
171
|
+
menu: createMenuStyles(theme),
|
|
172
|
+
item: createItemStyles(theme),
|
|
173
|
+
// Additional styles (merged from return)
|
|
174
|
+
// Minor utility styles (not extended)
|
|
175
|
+
separator: {
|
|
176
|
+
height: 1,
|
|
177
|
+
backgroundColor: theme.colors.border.primary,
|
|
178
|
+
marginTop: 4,
|
|
179
|
+
marginBottom: 4,
|
|
180
|
+
},
|
|
181
|
+
icon: {
|
|
182
|
+
alignItems: 'center',
|
|
183
|
+
justifyContent: 'center',
|
|
184
|
+
flexShrink: 0,
|
|
185
|
+
marginRight: 8,
|
|
186
|
+
variants: {
|
|
187
|
+
size: createIconSizeVariants(theme),
|
|
188
|
+
} as const,
|
|
189
|
+
} as const,
|
|
190
|
+
label: {
|
|
191
|
+
flex: 1,
|
|
192
|
+
color: theme.colors.text.primary,
|
|
193
|
+
variants: {
|
|
194
|
+
size: createLabelSizeVariants(theme),
|
|
195
|
+
} as const,
|
|
196
|
+
} as const});
|
|
197
|
+
});
|
package/src/Menu/Menu.styles.tsx
CHANGED
|
@@ -1,98 +1,28 @@
|
|
|
1
|
-
import { StyleSheet } from 'react-native-unistyles';
|
|
2
|
-
import { Theme, StylesheetStyles, CompoundVariants, Intent, Size } from '@idealyst/theme';
|
|
3
|
-
import { buildSizeVariants } from '../utils/buildSizeVariants';
|
|
4
|
-
import { applyExtensions } from '../extensions/applyExtension';
|
|
5
|
-
|
|
6
|
-
type MenuSize = Size;
|
|
7
|
-
type MenuIntent = Intent;
|
|
8
|
-
|
|
9
|
-
type MenuVariants = {
|
|
10
|
-
size: MenuSize;
|
|
11
|
-
intent: MenuIntent;
|
|
12
|
-
disabled: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export type ExpandedMenuStyles = StylesheetStyles<keyof MenuVariants>;
|
|
16
|
-
|
|
17
|
-
export type MenuStylesheet = {
|
|
18
|
-
overlay: ExpandedMenuStyles;
|
|
19
|
-
menu: ExpandedMenuStyles;
|
|
20
|
-
separator: ExpandedMenuStyles;
|
|
21
|
-
item: ExpandedMenuStyles;
|
|
22
|
-
icon: ExpandedMenuStyles;
|
|
23
|
-
label: ExpandedMenuStyles;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
1
|
/**
|
|
27
|
-
*
|
|
2
|
+
* Menu styles using defineStyle with dynamic props.
|
|
28
3
|
*/
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
paddingHorizontal: size.paddingHorizontal,
|
|
33
|
-
}));
|
|
34
|
-
}
|
|
4
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
5
|
+
import { defineStyle, ThemeStyleWrapper } from '@idealyst/theme';
|
|
6
|
+
import type { Theme as BaseTheme, Intent, Size } from '@idealyst/theme';
|
|
35
7
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
*/
|
|
39
|
-
function getItemHoverStyles(theme: Theme, intent: MenuIntent) {
|
|
40
|
-
if (intent === 'neutral') {
|
|
41
|
-
return {};
|
|
42
|
-
}
|
|
43
|
-
const intentValue = theme.intents[intent];
|
|
44
|
-
return {
|
|
45
|
-
_web: {
|
|
46
|
-
_hover: {
|
|
47
|
-
backgroundColor: intentValue.light + '20',
|
|
48
|
-
color: intentValue.primary,
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
} as const;
|
|
52
|
-
}
|
|
8
|
+
// Required: Unistyles must see StyleSheet usage in original source to process this file
|
|
9
|
+
void StyleSheet;
|
|
53
10
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
*/
|
|
57
|
-
function createItemCompoundVariants(theme: Theme): CompoundVariants<keyof MenuVariants> {
|
|
58
|
-
return [
|
|
59
|
-
{
|
|
60
|
-
disabled: true,
|
|
61
|
-
styles: {
|
|
62
|
-
_web: {
|
|
63
|
-
_hover: {
|
|
64
|
-
backgroundColor: 'transparent',
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
] as const;
|
|
70
|
-
}
|
|
11
|
+
// Wrap theme for $iterator support
|
|
12
|
+
type Theme = ThemeStyleWrapper<BaseTheme>;
|
|
71
13
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
width: size.iconSize,
|
|
78
|
-
height: size.iconSize,
|
|
79
|
-
fontSize: size.iconSize,
|
|
80
|
-
}));
|
|
81
|
-
}
|
|
14
|
+
export type MenuDynamicProps = {
|
|
15
|
+
size?: Size;
|
|
16
|
+
intent?: Intent;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
};
|
|
82
19
|
|
|
83
20
|
/**
|
|
84
|
-
*
|
|
21
|
+
* Menu styles with intent/disabled handling.
|
|
85
22
|
*/
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}));
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Main element style creators (for extension support)
|
|
93
|
-
function createOverlayStyles(theme: Theme) {
|
|
94
|
-
return () => ({
|
|
95
|
-
backgroundColor: 'transparent',
|
|
23
|
+
export const menuStyles = defineStyle('Menu', (theme: Theme) => ({
|
|
24
|
+
overlay: (_props: MenuDynamicProps) => ({
|
|
25
|
+
backgroundColor: 'transparent' as const,
|
|
96
26
|
_web: {
|
|
97
27
|
position: 'fixed' as const,
|
|
98
28
|
top: 0,
|
|
@@ -101,11 +31,9 @@ function createOverlayStyles(theme: Theme) {
|
|
|
101
31
|
bottom: 0,
|
|
102
32
|
zIndex: 999,
|
|
103
33
|
},
|
|
104
|
-
})
|
|
105
|
-
}
|
|
34
|
+
}),
|
|
106
35
|
|
|
107
|
-
|
|
108
|
-
return () => ({
|
|
36
|
+
menu: (_props: MenuDynamicProps) => ({
|
|
109
37
|
position: 'absolute' as const,
|
|
110
38
|
zIndex: 1000,
|
|
111
39
|
backgroundColor: theme.colors.surface.primary,
|
|
@@ -123,79 +51,69 @@ function createMenuStyles(theme: Theme) {
|
|
|
123
51
|
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
|
|
124
52
|
width: 'fit-content',
|
|
125
53
|
},
|
|
126
|
-
})
|
|
127
|
-
|
|
54
|
+
}),
|
|
55
|
+
|
|
56
|
+
item: ({ intent = 'neutral', disabled = false }: MenuDynamicProps) => {
|
|
57
|
+
const intentValue = theme.intents[intent];
|
|
58
|
+
const hoverStyles = intent !== 'neutral' ? {
|
|
59
|
+
backgroundColor: intentValue.light + '20',
|
|
60
|
+
color: intentValue.primary,
|
|
61
|
+
} : {
|
|
62
|
+
backgroundColor: theme.colors.surface.secondary,
|
|
63
|
+
};
|
|
128
64
|
|
|
129
|
-
function createItemStyles(theme: Theme) {
|
|
130
|
-
return ({ intent }: Partial<MenuVariants>) => {
|
|
131
|
-
const hoverStyles = getItemHoverStyles(theme, intent ?? 'neutral');
|
|
132
65
|
return {
|
|
133
|
-
flexDirection: 'row',
|
|
134
|
-
alignItems: 'center',
|
|
135
|
-
backgroundColor: 'transparent',
|
|
66
|
+
flexDirection: 'row' as const,
|
|
67
|
+
alignItems: 'center' as const,
|
|
68
|
+
backgroundColor: 'transparent' as const,
|
|
136
69
|
borderRadius: 4,
|
|
137
70
|
minHeight: 44,
|
|
71
|
+
opacity: disabled ? 0.5 : 1,
|
|
138
72
|
variants: {
|
|
139
|
-
size:
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
opacity: 0.5,
|
|
143
|
-
_web: {
|
|
144
|
-
cursor: 'not-allowed',
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
false: {},
|
|
73
|
+
size: {
|
|
74
|
+
paddingVertical: theme.sizes.$menu.paddingVertical,
|
|
75
|
+
paddingHorizontal: theme.sizes.$menu.paddingHorizontal,
|
|
148
76
|
},
|
|
149
77
|
},
|
|
150
|
-
compoundVariants: createItemCompoundVariants(theme),
|
|
151
78
|
_web: {
|
|
152
|
-
cursor: 'pointer',
|
|
79
|
+
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
153
80
|
border: 'none',
|
|
154
81
|
outline: 'none',
|
|
155
82
|
transition: 'background-color 0.2s ease',
|
|
156
83
|
textAlign: 'left',
|
|
157
|
-
_hover: {
|
|
158
|
-
backgroundColor: theme.colors.surface.secondary,
|
|
159
|
-
},
|
|
84
|
+
_hover: disabled ? { backgroundColor: 'transparent' } : hoverStyles,
|
|
160
85
|
},
|
|
161
|
-
...hoverStyles,
|
|
162
86
|
} as const;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
87
|
+
},
|
|
165
88
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
item: createItemStyles(theme),
|
|
173
|
-
});
|
|
89
|
+
separator: (_props: MenuDynamicProps) => ({
|
|
90
|
+
height: 1,
|
|
91
|
+
backgroundColor: theme.colors.border.primary,
|
|
92
|
+
marginTop: 4,
|
|
93
|
+
marginBottom: 4,
|
|
94
|
+
}),
|
|
174
95
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
96
|
+
icon: (_props: MenuDynamicProps) => ({
|
|
97
|
+
alignItems: 'center' as const,
|
|
98
|
+
justifyContent: 'center' as const,
|
|
99
|
+
flexShrink: 0,
|
|
100
|
+
marginRight: 8,
|
|
101
|
+
variants: {
|
|
102
|
+
size: {
|
|
103
|
+
width: theme.sizes.$menu.iconSize,
|
|
104
|
+
height: theme.sizes.$menu.iconSize,
|
|
105
|
+
fontSize: theme.sizes.$menu.iconSize,
|
|
106
|
+
},
|
|
183
107
|
},
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
variants: {
|
|
197
|
-
size: createLabelSizeVariants(theme),
|
|
198
|
-
} as const,
|
|
199
|
-
} as const,
|
|
200
|
-
};
|
|
201
|
-
});
|
|
108
|
+
}),
|
|
109
|
+
|
|
110
|
+
label: (_props: MenuDynamicProps) => ({
|
|
111
|
+
flex: 1,
|
|
112
|
+
color: theme.colors.text.primary,
|
|
113
|
+
variants: {
|
|
114
|
+
size: {
|
|
115
|
+
fontSize: theme.sizes.$menu.labelFontSize,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
}),
|
|
119
|
+
}));
|
|
@@ -19,8 +19,10 @@ const MenuItem = forwardRef<ComponentRef<typeof Pressable>, MenuItemProps>(({ it
|
|
|
19
19
|
disabled: Boolean(item.disabled),
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
//
|
|
22
|
+
// Call styles as functions to get theme-reactive styles
|
|
23
23
|
const itemStyle = (menuItemStyles.item as any)({ intent: item.intent || 'neutral' });
|
|
24
|
+
const iconStyle = (menuItemStyles.icon as any)({});
|
|
25
|
+
const labelStyle = (menuItemStyles.label as any)({});
|
|
24
26
|
|
|
25
27
|
const renderIcon = () => {
|
|
26
28
|
if (!item.icon) return null;
|
|
@@ -29,7 +31,7 @@ const MenuItem = forwardRef<ComponentRef<typeof Pressable>, MenuItemProps>(({ it
|
|
|
29
31
|
return (
|
|
30
32
|
<MaterialDesignIcons
|
|
31
33
|
name={item.icon as any}
|
|
32
|
-
style={
|
|
34
|
+
style={iconStyle}
|
|
33
35
|
/>
|
|
34
36
|
);
|
|
35
37
|
} else if (isValidElement(item.icon)) {
|
|
@@ -56,7 +58,7 @@ const MenuItem = forwardRef<ComponentRef<typeof Pressable>, MenuItemProps>(({ it
|
|
|
56
58
|
{renderIcon()}
|
|
57
59
|
</View>
|
|
58
60
|
)}
|
|
59
|
-
<Text style={
|
|
61
|
+
<Text style={labelStyle}>
|
|
60
62
|
{item.label}
|
|
61
63
|
</Text>
|
|
62
64
|
</Pressable>
|