@idealyst/components 1.1.8 → 1.2.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 +3 -3
- package/plugin/web.js +280 -532
- package/src/Accordion/Accordion.web.tsx +1 -3
- package/src/Alert/Alert.web.tsx +3 -4
- package/src/Badge/Badge.web.tsx +8 -15
- package/src/Breadcrumb/Breadcrumb.web.tsx +4 -8
- package/src/Button/Button.native.tsx +14 -21
- package/src/Button/Button.styles.tsx +15 -0
- package/src/Button/Button.web.tsx +9 -19
- package/src/Checkbox/Checkbox.web.tsx +1 -2
- package/src/Chip/Chip.web.tsx +3 -5
- package/src/Dialog/Dialog.web.tsx +3 -3
- package/src/Dialog/types.ts +1 -1
- package/src/Icon/Icon.web.tsx +22 -17
- package/src/Icon/IconRegistry.native.ts +41 -0
- package/src/Icon/IconRegistry.ts +107 -0
- package/src/Icon/IconSvg/IconSvg.web.tsx +26 -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/Input/Input.styles.tsx +56 -83
- package/src/Input/Input.web.tsx +5 -8
- package/src/List/ListItem.native.tsx +6 -7
- package/src/List/ListItem.web.tsx +3 -3
- package/src/Menu/MenuItem.web.tsx +3 -5
- package/src/Screen/Screen.native.tsx +1 -1
- package/src/Screen/Screen.styles.tsx +3 -6
- package/src/Screen/Screen.web.tsx +1 -1
- package/src/Select/Select.styles.tsx +31 -48
- package/src/Select/Select.web.tsx +45 -33
- package/src/Slider/Slider.web.tsx +2 -4
- package/src/Switch/Switch.native.tsx +2 -2
- package/src/Switch/Switch.web.tsx +2 -3
- package/src/Table/Table.native.tsx +168 -65
- package/src/Table/Table.styles.tsx +26 -33
- package/src/Table/Table.web.tsx +169 -70
- package/src/Text/Text.web.tsx +1 -0
- package/src/TextArea/TextArea.native.tsx +21 -8
- package/src/TextArea/TextArea.styles.tsx +15 -27
- package/src/TextArea/TextArea.web.tsx +17 -6
- package/src/View/View.native.tsx +33 -3
- package/src/View/View.web.tsx +4 -21
- package/src/View/types.ts +31 -3
- package/src/examples/ButtonExamples.tsx +20 -0
- package/src/index.ts +1 -1
|
@@ -1,38 +1,59 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import MdiIcon from '@mdi/react';
|
|
3
|
+
import { IconRegistry } from '../IconRegistry';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
|
-
* Internal component for rendering SVG icons
|
|
6
|
+
* Internal component for rendering SVG icons from the icon registry.
|
|
6
7
|
* This is used internally by components like Button, Badge, etc. to render icons
|
|
7
8
|
* without going through the full Icon component.
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
+
* Icons are looked up from the registry by name. The registry is populated
|
|
11
|
+
* at build time by the Babel plugin.
|
|
10
12
|
*/
|
|
11
13
|
interface IconSvgProps {
|
|
12
|
-
|
|
14
|
+
/** Icon name in canonical format (e.g., "home", "account-circle") */
|
|
15
|
+
name: string;
|
|
13
16
|
size?: string | number;
|
|
14
17
|
color?: string;
|
|
15
18
|
style?: React.CSSProperties;
|
|
19
|
+
className?: string;
|
|
16
20
|
'aria-label'?: string;
|
|
17
21
|
'data-testid'?: string;
|
|
18
22
|
}
|
|
19
23
|
|
|
20
24
|
export const IconSvg: React.FC<IconSvgProps> = ({
|
|
21
|
-
|
|
25
|
+
name,
|
|
22
26
|
size = '1em',
|
|
23
27
|
color = 'currentColor',
|
|
24
28
|
style,
|
|
29
|
+
className,
|
|
25
30
|
'aria-label': ariaLabel,
|
|
26
31
|
'data-testid': testID,
|
|
27
32
|
...rest
|
|
28
33
|
}) => {
|
|
34
|
+
// Look up path from registry
|
|
35
|
+
const path = IconRegistry.get(name);
|
|
36
|
+
|
|
37
|
+
// Warn in development if icon is not registered
|
|
38
|
+
if (!path && process.env.NODE_ENV !== 'production') {
|
|
39
|
+
console.warn(
|
|
40
|
+
`[IconSvg] Icon "${name}" is not registered. ` +
|
|
41
|
+
`Add it to the 'icons' array in your babel config.`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!path) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
29
49
|
return (
|
|
30
50
|
<MdiIcon
|
|
31
51
|
style={style}
|
|
52
|
+
className={className}
|
|
32
53
|
path={path}
|
|
33
54
|
size={size}
|
|
34
55
|
color={color}
|
|
35
|
-
aria-label={ariaLabel}
|
|
56
|
+
aria-label={ariaLabel || name}
|
|
36
57
|
data-testid={testID}
|
|
37
58
|
{...rest}
|
|
38
59
|
/>
|
|
@@ -1,62 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Runtime utility for resolving MDI icon names to their SVG paths.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import * as mdiIcons from '@mdi/js';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Formats an icon name from kebab-case to the MDI export name format.
|
|
11
|
-
* Examples:
|
|
12
|
-
* "home" -> "mdiHome"
|
|
13
|
-
* "account-circle" -> "mdiAccountCircle"
|
|
14
|
-
* "star-outline" -> "mdiStarOutline"
|
|
3
|
+
*
|
|
4
|
+
* Icons are looked up from the IconRegistry, which is populated at build time
|
|
5
|
+
* by the Babel plugin. This replaces the previous approach of importing all
|
|
6
|
+
* 7,447 icons from @mdi/js.
|
|
15
7
|
*/
|
|
16
|
-
function formatIconName(name: string): string {
|
|
17
|
-
if (!name || typeof name !== 'string') {
|
|
18
|
-
return 'mdiHelpCircle';
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Remove mdi: prefix if present
|
|
22
|
-
const cleanName = name.startsWith('mdi:') ? name.substring(4) : name;
|
|
23
8
|
|
|
24
|
-
|
|
25
|
-
if (!/^[a-zA-Z0-9-_]+$/.test(cleanName)) {
|
|
26
|
-
console.warn(
|
|
27
|
-
`[icon-resolver] Invalid icon name "${name}" (contains special characters), using "help-circle" as fallback`
|
|
28
|
-
);
|
|
29
|
-
return 'mdiHelpCircle';
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Convert kebab-case to PascalCase
|
|
33
|
-
const pascalCase = cleanName
|
|
34
|
-
.split('-')
|
|
35
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
36
|
-
.join('');
|
|
37
|
-
|
|
38
|
-
return `mdi${pascalCase}`;
|
|
39
|
-
}
|
|
9
|
+
import { IconRegistry } from './IconRegistry';
|
|
40
10
|
|
|
41
11
|
/**
|
|
42
|
-
* Resolves an icon name to its SVG path data.
|
|
43
|
-
* Returns undefined if the icon is not
|
|
12
|
+
* Resolves an icon name to its SVG path data from the registry.
|
|
13
|
+
* Returns undefined if the icon is not registered.
|
|
44
14
|
*
|
|
45
15
|
* @param iconName - The icon name in kebab-case (e.g., "home", "account-circle")
|
|
46
16
|
* @returns The SVG path string or undefined if not found
|
|
47
17
|
*/
|
|
48
18
|
export function resolveIconPath(iconName: string): string | undefined {
|
|
49
|
-
const
|
|
50
|
-
const iconPath = (mdiIcons as any)[mdiIconName];
|
|
19
|
+
const path = IconRegistry.get(iconName);
|
|
51
20
|
|
|
52
|
-
if (!
|
|
21
|
+
if (!path && process.env.NODE_ENV !== 'production') {
|
|
53
22
|
console.warn(
|
|
54
|
-
`[icon-resolver] Icon "${iconName}"
|
|
23
|
+
`[icon-resolver] Icon "${iconName}" is not registered. ` +
|
|
24
|
+
`Add it to the 'icons' array in your babel config.`
|
|
55
25
|
);
|
|
56
|
-
return (mdiIcons as any).mdiHelpCircle;
|
|
57
26
|
}
|
|
58
27
|
|
|
59
|
-
return
|
|
28
|
+
return path;
|
|
60
29
|
}
|
|
61
30
|
|
|
62
31
|
/**
|
package/src/Icon/index.native.ts
CHANGED
package/src/Icon/index.ts
CHANGED
package/src/Icon/index.web.ts
CHANGED
|
@@ -28,95 +28,68 @@ export type InputDynamicProps = {
|
|
|
28
28
|
* Input styles with type/state handling.
|
|
29
29
|
*/
|
|
30
30
|
export const inputStyles = defineStyle('Input', (theme: Theme) => ({
|
|
31
|
-
container: ({ type = 'outlined', focused = false, hasError = false, disabled = false }: InputDynamicProps) => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
borderColor = errorColor;
|
|
51
|
-
borderWidth = 1;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Focus state (error still takes precedence for color)
|
|
55
|
-
if (focused && !hasError) {
|
|
56
|
-
borderColor = focusColor;
|
|
57
|
-
borderWidth = 1;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Disabled state
|
|
61
|
-
if (disabled) {
|
|
62
|
-
backgroundColor = theme.colors.surface.secondary;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Web-specific border and shadow
|
|
66
|
-
let webBorder = `1px solid ${borderColor}`;
|
|
67
|
-
let webBoxShadow = 'none';
|
|
68
|
-
|
|
69
|
-
if (type === 'filled' || type === 'bare') {
|
|
70
|
-
webBorder = 'none';
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (hasError) {
|
|
74
|
-
webBorder = `1px solid ${errorColor}`;
|
|
75
|
-
if (focused) {
|
|
76
|
-
webBoxShadow = `0 0 0 2px ${errorColor}20`;
|
|
77
|
-
}
|
|
78
|
-
} else if (focused) {
|
|
79
|
-
webBorder = `1px solid ${focusColor}`;
|
|
80
|
-
webBoxShadow = `0 0 0 2px ${focusColor}20`;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return {
|
|
84
|
-
display: 'flex' as const,
|
|
85
|
-
flexDirection: 'row' as const,
|
|
86
|
-
alignItems: 'center' as const,
|
|
87
|
-
width: '100%',
|
|
88
|
-
minWidth: 0,
|
|
89
|
-
borderRadius: 8,
|
|
90
|
-
backgroundColor,
|
|
91
|
-
borderWidth,
|
|
92
|
-
borderColor,
|
|
93
|
-
borderStyle: 'solid' as const,
|
|
94
|
-
opacity: disabled ? 0.6 : 1,
|
|
95
|
-
variants: {
|
|
96
|
-
// $iterator expands for each input size
|
|
97
|
-
size: {
|
|
98
|
-
height: theme.sizes.$input.height,
|
|
99
|
-
paddingHorizontal: theme.sizes.$input.paddingHorizontal,
|
|
31
|
+
container: ({ type = 'outlined', focused = false, hasError = false, disabled = false }: InputDynamicProps) => ({
|
|
32
|
+
display: 'flex' as const,
|
|
33
|
+
flexDirection: 'row' as const,
|
|
34
|
+
alignItems: 'center' as const,
|
|
35
|
+
width: '100%',
|
|
36
|
+
minWidth: 0,
|
|
37
|
+
borderRadius: theme.radii.md,
|
|
38
|
+
borderWidth: 1,
|
|
39
|
+
borderStyle: 'solid' as const,
|
|
40
|
+
borderColor: theme.colors.border.primary,
|
|
41
|
+
variants: {
|
|
42
|
+
type: {
|
|
43
|
+
outlined: {
|
|
44
|
+
backgroundColor: theme.colors.surface.primary,
|
|
45
|
+
borderColor: theme.colors.border.primary,
|
|
46
|
+
},
|
|
47
|
+
filled: {
|
|
48
|
+
backgroundColor: theme.colors.surface.secondary,
|
|
49
|
+
borderColor: 'transparent',
|
|
100
50
|
},
|
|
101
|
-
|
|
102
|
-
|
|
51
|
+
bare: {
|
|
52
|
+
backgroundColor: 'transparent',
|
|
53
|
+
borderWidth: 0,
|
|
54
|
+
borderColor: 'transparent',
|
|
103
55
|
},
|
|
104
|
-
|
|
105
|
-
|
|
56
|
+
},
|
|
57
|
+
focused: {
|
|
58
|
+
true: {
|
|
59
|
+
borderColor: theme.intents.primary.primary,
|
|
106
60
|
},
|
|
107
|
-
|
|
108
|
-
|
|
61
|
+
false: {
|
|
62
|
+
|
|
109
63
|
},
|
|
110
64
|
},
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
65
|
+
disabled: {
|
|
66
|
+
true: { opacity: 0.8, _web: { cursor: 'not-allowed' } },
|
|
67
|
+
false: { opacity: 1 }
|
|
68
|
+
},
|
|
69
|
+
hasError: {
|
|
70
|
+
true: { borderColor: theme.intents.error.primary },
|
|
71
|
+
false: { borderColor: theme.colors.border.primary },
|
|
72
|
+
},
|
|
73
|
+
// $iterator expands for each input size
|
|
74
|
+
size: {
|
|
75
|
+
height: theme.sizes.$input.height,
|
|
76
|
+
paddingHorizontal: theme.sizes.$input.paddingHorizontal,
|
|
117
77
|
},
|
|
118
|
-
|
|
119
|
-
|
|
78
|
+
margin: {
|
|
79
|
+
margin: theme.sizes.$view.padding,
|
|
80
|
+
},
|
|
81
|
+
marginVertical: {
|
|
82
|
+
marginVertical: theme.sizes.$view.padding,
|
|
83
|
+
},
|
|
84
|
+
marginHorizontal: {
|
|
85
|
+
marginHorizontal: theme.sizes.$view.padding,
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
_web: {
|
|
89
|
+
boxSizing: 'border-box',
|
|
90
|
+
transition: 'border-color 0.2s ease, box-shadow 0.2s ease',
|
|
91
|
+
}
|
|
92
|
+
}),
|
|
120
93
|
|
|
121
94
|
input: (_props: InputDynamicProps) => ({
|
|
122
95
|
flex: 1,
|
package/src/Input/Input.web.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { isValidElement, useState, useMemo, useRef } from 'react';
|
|
2
2
|
import { getWebProps } from 'react-native-unistyles/web';
|
|
3
3
|
import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
|
|
4
|
-
import { isIconName
|
|
4
|
+
import { isIconName } from '../Icon/icon-resolver';
|
|
5
5
|
import useMergeRefs from '../hooks/useMergeRefs';
|
|
6
6
|
import { inputStyles } from './Input.styles';
|
|
7
7
|
import { InputProps } from './types';
|
|
@@ -184,10 +184,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({
|
|
|
184
184
|
if (!leftIcon) return null;
|
|
185
185
|
|
|
186
186
|
if (isIconName(leftIcon)) {
|
|
187
|
-
const iconPath = resolveIconPath(leftIcon);
|
|
188
187
|
return (
|
|
189
188
|
<IconSvg
|
|
190
|
-
|
|
189
|
+
name={leftIcon}
|
|
191
190
|
{...leftIconProps}
|
|
192
191
|
aria-label={leftIcon}
|
|
193
192
|
/>
|
|
@@ -204,10 +203,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({
|
|
|
204
203
|
if (!rightIcon) return null;
|
|
205
204
|
|
|
206
205
|
if (isIconName(rightIcon)) {
|
|
207
|
-
const iconPath = resolveIconPath(rightIcon);
|
|
208
206
|
return (
|
|
209
207
|
<IconSvg
|
|
210
|
-
|
|
208
|
+
name={rightIcon}
|
|
211
209
|
{...rightIconProps}
|
|
212
210
|
aria-label={rightIcon}
|
|
213
211
|
/>
|
|
@@ -222,10 +220,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({
|
|
|
222
220
|
// Helper to render password toggle icon
|
|
223
221
|
const renderPasswordToggleIcon = () => {
|
|
224
222
|
const iconName = isPasswordVisible ? 'eye-off' : 'eye';
|
|
225
|
-
const iconPath = resolveIconPath(iconName);
|
|
226
223
|
return (
|
|
227
224
|
<IconSvg
|
|
228
|
-
|
|
225
|
+
name={iconName}
|
|
229
226
|
{...passwordToggleIconProps}
|
|
230
227
|
aria-label={iconName}
|
|
231
228
|
/>
|
|
@@ -290,4 +287,4 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({
|
|
|
290
287
|
|
|
291
288
|
Input.displayName = 'Input';
|
|
292
289
|
|
|
293
|
-
export default Input;
|
|
290
|
+
export default Input;
|
|
@@ -66,18 +66,17 @@ const ListItem = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pres
|
|
|
66
66
|
const trailingStyle = (listStyles.trailing as any)({});
|
|
67
67
|
const trailingIconStyle = (listStyles.trailingIcon as any)({});
|
|
68
68
|
const labelContainerStyle = (listStyles.labelContainer as any)({});
|
|
69
|
-
const itemContentStyle = (listStyles.itemContent as any)({});
|
|
70
69
|
|
|
71
70
|
// Resolve icon color - check intents first, then color palette
|
|
72
|
-
const resolvedIconColor = (() => {
|
|
73
|
-
if (!iconColor) return
|
|
71
|
+
const resolvedIconColor = useMemo(() => {
|
|
72
|
+
if (!iconColor) return trailingIconStyle.color || leadingStyle.color;
|
|
74
73
|
// Check if it's an intent name
|
|
75
74
|
if (iconColor in theme.intents) {
|
|
76
75
|
return theme.intents[iconColor as Intent]?.primary;
|
|
77
76
|
}
|
|
78
77
|
// Otherwise try color palette
|
|
79
78
|
return getColorFromString(theme, iconColor as Color);
|
|
80
|
-
})
|
|
79
|
+
}, [iconColor, theme, trailingIconStyle.color, leadingStyle.color]);
|
|
81
80
|
|
|
82
81
|
// Helper to render leading/trailing icons
|
|
83
82
|
const renderElement = (element: typeof leading | typeof trailing, styleKey: 'leading' | 'trailingIcon') => {
|
|
@@ -85,12 +84,12 @@ const ListItem = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pres
|
|
|
85
84
|
|
|
86
85
|
// If it's a string, treat it as an icon name
|
|
87
86
|
if (typeof element === 'string') {
|
|
88
|
-
const
|
|
87
|
+
const iconSize = styleKey === 'leading' ? leadingStyle.width : trailingIconStyle.width;
|
|
89
88
|
return (
|
|
90
89
|
<MaterialCommunityIcons
|
|
91
90
|
name={element}
|
|
92
|
-
size={
|
|
93
|
-
color={resolvedIconColor
|
|
91
|
+
size={iconSize}
|
|
92
|
+
color={resolvedIconColor}
|
|
94
93
|
/>
|
|
95
94
|
);
|
|
96
95
|
} else if (isValidElement(element)) {
|
|
@@ -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> = ({
|
|
@@ -77,10 +77,10 @@ const ListItem: React.FC<ListItemProps> = ({
|
|
|
77
77
|
if (!element) return null;
|
|
78
78
|
|
|
79
79
|
if (isIconName(element)) {
|
|
80
|
-
|
|
80
|
+
// Use IconSvg with name - registry lookup happens inside
|
|
81
81
|
return (
|
|
82
82
|
<IconSvg
|
|
83
|
-
|
|
83
|
+
name={element}
|
|
84
84
|
color={resolvedIconColor || 'currentColor'}
|
|
85
85
|
aria-label={element}
|
|
86
86
|
/>
|
|
@@ -3,7 +3,7 @@ import { getWebProps } from 'react-native-unistyles/web';
|
|
|
3
3
|
import { menuItemStyles } from './MenuItem.styles';
|
|
4
4
|
import type { MenuItem as MenuItemType, MenuSizeVariant } from './types';
|
|
5
5
|
import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
|
|
6
|
-
import {
|
|
6
|
+
import { isIconName } from '../Icon/icon-resolver';
|
|
7
7
|
import useMergeRefs from '../hooks/useMergeRefs';
|
|
8
8
|
|
|
9
9
|
interface MenuItemProps {
|
|
@@ -33,12 +33,10 @@ const MenuItem = forwardRef<HTMLButtonElement, MenuItemProps>(({ item, onPress,
|
|
|
33
33
|
if (!item.icon) return null;
|
|
34
34
|
|
|
35
35
|
if (isIconName(item.icon)) {
|
|
36
|
-
//
|
|
37
|
-
const iconPath = resolveIconPath(item.icon);
|
|
38
|
-
// IconSvg uses size="1em" by default, sized by container's fontSize from styles
|
|
36
|
+
// Use IconSvg with name - registry lookup happens inside
|
|
39
37
|
return (
|
|
40
38
|
<IconSvg
|
|
41
|
-
|
|
39
|
+
name={item.icon}
|
|
42
40
|
color="currentColor"
|
|
43
41
|
aria-label={item.icon}
|
|
44
42
|
/>
|
|
@@ -12,7 +12,7 @@ void StyleSheet;
|
|
|
12
12
|
// Wrap theme for $iterator support
|
|
13
13
|
type Theme = ThemeStyleWrapper<BaseTheme>;
|
|
14
14
|
|
|
15
|
-
type ScreenBackground = 'primary' | 'secondary' | 'tertiary' | 'inverse' | 'inverse-secondary' | 'inverse-tertiary' | 'transparent';
|
|
15
|
+
type ScreenBackground = 'screen' | 'primary' | 'secondary' | 'tertiary' | 'inverse' | 'inverse-secondary' | 'inverse-tertiary' | 'transparent';
|
|
16
16
|
|
|
17
17
|
export type ScreenDynamicProps = {
|
|
18
18
|
background?: ScreenBackground;
|
|
@@ -34,10 +34,9 @@ export type ScreenDynamicProps = {
|
|
|
34
34
|
export const screenStyles = defineStyle('Screen', (theme: Theme) => ({
|
|
35
35
|
screen: (_props: ScreenDynamicProps) => ({
|
|
36
36
|
flex: 1,
|
|
37
|
-
// Theme marker for Unistyles reactivity
|
|
38
|
-
backgroundColor: theme.colors.surface.primary,
|
|
39
37
|
variants: {
|
|
40
38
|
background: {
|
|
39
|
+
screen: { backgroundColor: theme.colors.surface.screen },
|
|
41
40
|
primary: { backgroundColor: theme.colors.surface.primary },
|
|
42
41
|
secondary: { backgroundColor: theme.colors.surface.secondary },
|
|
43
42
|
tertiary: { backgroundColor: theme.colors.surface.tertiary },
|
|
@@ -74,7 +73,6 @@ export const screenStyles = defineStyle('Screen', (theme: Theme) => ({
|
|
|
74
73
|
},
|
|
75
74
|
},
|
|
76
75
|
_web: {
|
|
77
|
-
overflow: 'auto',
|
|
78
76
|
display: 'flex',
|
|
79
77
|
flexDirection: 'column',
|
|
80
78
|
minHeight: '100%',
|
|
@@ -83,10 +81,9 @@ export const screenStyles = defineStyle('Screen', (theme: Theme) => ({
|
|
|
83
81
|
}),
|
|
84
82
|
|
|
85
83
|
screenContent: (_props: ScreenDynamicProps) => ({
|
|
86
|
-
// Theme marker for Unistyles reactivity
|
|
87
|
-
backgroundColor: theme.colors.surface.primary,
|
|
88
84
|
variants: {
|
|
89
85
|
background: {
|
|
86
|
+
screen: { backgroundColor: theme.colors.surface.screen },
|
|
90
87
|
primary: { backgroundColor: theme.colors.surface.primary },
|
|
91
88
|
secondary: { backgroundColor: theme.colors.surface.secondary },
|
|
92
89
|
tertiary: { backgroundColor: theme.colors.surface.tertiary },
|
|
@@ -52,56 +52,39 @@ export const selectStyles = defineStyle('Select', (theme: Theme) => ({
|
|
|
52
52
|
marginBottom: 4,
|
|
53
53
|
}),
|
|
54
54
|
|
|
55
|
-
trigger: ({ type = 'outlined', intent = 'neutral', disabled = false, error = false, focused = false }: SelectDynamicProps) => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
borderColor = errorColor;
|
|
69
|
-
} else if (focused) {
|
|
70
|
-
borderColor = primaryIntent.primary;
|
|
71
|
-
} else if (intent !== 'neutral') {
|
|
72
|
-
borderColor = intentValue.primary;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
position: 'relative' as const,
|
|
77
|
-
flexDirection: 'row' as const,
|
|
78
|
-
alignItems: 'center' as const,
|
|
79
|
-
justifyContent: 'space-between' as const,
|
|
80
|
-
borderRadius: 8,
|
|
81
|
-
borderWidth: 1,
|
|
82
|
-
borderStyle: 'solid' as const,
|
|
83
|
-
backgroundColor,
|
|
84
|
-
borderColor,
|
|
85
|
-
opacity: disabled ? 0.6 : 1,
|
|
86
|
-
variants: {
|
|
87
|
-
size: {
|
|
88
|
-
paddingHorizontal: theme.sizes.$select.paddingHorizontal,
|
|
89
|
-
minHeight: theme.sizes.$select.minHeight,
|
|
55
|
+
trigger: ({ type = 'outlined', intent = 'neutral', disabled = false, error = false, focused = false }: SelectDynamicProps) => ({
|
|
56
|
+
position: 'relative' as const,
|
|
57
|
+
flexDirection: 'row' as const,
|
|
58
|
+
alignItems: 'center' as const,
|
|
59
|
+
justifyContent: 'space-between' as const,
|
|
60
|
+
borderWidth: 1,
|
|
61
|
+
borderStyle: 'solid' as const,
|
|
62
|
+
opacity: disabled ? 0.6 : 1,
|
|
63
|
+
variants: {
|
|
64
|
+
type: {
|
|
65
|
+
filled: {
|
|
66
|
+
backgroundColor: theme.colors.surface.secondary,
|
|
67
|
+
borderColor: 'transparent',
|
|
90
68
|
},
|
|
69
|
+
outlined: {
|
|
70
|
+
backgroundColor: theme.colors.surface.primary,
|
|
71
|
+
borderWidth: 1,
|
|
72
|
+
borderColor: theme.colors.border.primary,
|
|
73
|
+
}
|
|
91
74
|
},
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
},
|
|
103
|
-
}
|
|
104
|
-
},
|
|
75
|
+
size: theme.sizes.$select,
|
|
76
|
+
},
|
|
77
|
+
_web: {
|
|
78
|
+
display: 'flex',
|
|
79
|
+
boxSizing: 'border-box',
|
|
80
|
+
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
81
|
+
border: `1px solid`,
|
|
82
|
+
transition: 'border-color 0.2s ease, box-shadow 0.2s ease',
|
|
83
|
+
_hover: disabled ? {} : { opacity: 0.9 },
|
|
84
|
+
_active: disabled ? {} : { opacity: 0.8 },
|
|
85
|
+
_focus: { outline: 'none' },
|
|
86
|
+
},
|
|
87
|
+
}),
|
|
105
88
|
|
|
106
89
|
triggerContent: (_props: SelectDynamicProps) => ({
|
|
107
90
|
flex: 1,
|