@idealyst/components 1.2.29 → 1.2.31
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/README.md +3 -3
- package/package.json +4 -4
- package/plugin/__tests__/web.test.ts +2 -2
- package/plugin/web.js +2 -0
- package/src/Accordion/Accordion.native.tsx +3 -2
- package/src/ActivityIndicator/ActivityIndicator.native.tsx +4 -2
- package/src/ActivityIndicator/ActivityIndicator.styles.tsx +22 -27
- package/src/ActivityIndicator/ActivityIndicator.web.tsx +17 -29
- package/src/Alert/Alert.native.tsx +20 -10
- package/src/Alert/Alert.styles.tsx +173 -86
- package/src/Alert/Alert.web.tsx +34 -30
- package/src/Alert/types.ts +53 -3
- package/src/Avatar/Avatar.native.tsx +3 -2
- package/src/Avatar/Avatar.web.tsx +2 -1
- package/src/Avatar/types.ts +1 -1
- package/src/Badge/Badge.native.tsx +18 -6
- package/src/Badge/Badge.styles.tsx +22 -5
- package/src/Badge/Badge.web.tsx +12 -4
- package/src/Badge/types.ts +14 -2
- package/src/Breadcrumb/Breadcrumb.native.tsx +3 -2
- package/src/Button/Button.native.tsx +16 -6
- package/src/Button/Button.styles.tsx +2 -2
- package/src/Button/Button.web.tsx +19 -15
- package/src/Button/types.ts +6 -10
- package/src/Card/Card.native.tsx +27 -3
- package/src/Card/Card.web.tsx +30 -4
- package/src/Card/types.ts +15 -0
- package/src/Checkbox/Checkbox.native.tsx +5 -4
- package/src/Checkbox/Checkbox.styles.tsx +62 -52
- package/src/Checkbox/Checkbox.web.tsx +4 -3
- package/src/Checkbox/types.ts +1 -1
- package/src/Chip/Chip.native.tsx +30 -7
- package/src/Chip/Chip.web.tsx +28 -5
- package/src/Chip/types.ts +15 -0
- package/src/Dialog/Dialog.native.tsx +6 -6
- package/src/Dialog/Dialog.web.tsx +5 -5
- package/src/Dialog/types.ts +2 -2
- package/src/Divider/Divider.native.tsx +20 -17
- package/src/Divider/Divider.styles.tsx +51 -29
- package/src/Divider/Divider.web.tsx +5 -4
- package/src/Divider/types.ts +3 -3
- package/src/Icon/Icon.native.tsx +3 -2
- package/src/Icon/Icon.web.tsx +2 -1
- package/src/Icon/IconSvg/IconSvg.native.tsx +3 -2
- package/src/IconButton/IconButton.native.tsx +219 -0
- package/src/IconButton/IconButton.styles.tsx +127 -0
- package/src/IconButton/IconButton.web.tsx +198 -0
- package/src/IconButton/index.native.ts +5 -0
- package/src/IconButton/index.ts +5 -0
- package/src/IconButton/index.web.ts +5 -0
- package/src/IconButton/types.ts +84 -0
- package/src/Image/Image.native.tsx +3 -2
- package/src/Input/Input.native.tsx +42 -290
- package/src/Input/Input.styles.tsx +1 -1
- package/src/Input/Input.web.tsx +37 -288
- package/src/Input/index.native.ts +9 -2
- package/src/Input/index.ts +8 -1
- package/src/Input/index.web.ts +8 -1
- package/src/Input/types.ts +1 -1
- package/src/List/List.native.tsx +3 -2
- package/src/List/ListItem.native.tsx +3 -2
- package/src/List/ListSection.native.tsx +3 -2
- package/src/Menu/Menu.native.tsx +2 -1
- package/src/Menu/Menu.styles.tsx +79 -29
- package/src/Menu/Menu.web.tsx +2 -1
- package/src/Menu/MenuItem.native.tsx +4 -3
- package/src/Menu/MenuItem.styles.tsx +81 -32
- package/src/Menu/MenuItem.web.tsx +2 -1
- package/src/Menu/docs.ts +1 -1
- package/src/Popover/Popover.native.tsx +2 -1
- package/src/Popover/Popover.web.tsx +2 -1
- package/src/Popover/types.ts +15 -4
- package/src/Pressable/Pressable.native.tsx +3 -2
- package/src/Pressable/Pressable.web.tsx +3 -5
- package/src/Progress/Progress.native.tsx +5 -4
- package/src/Progress/Progress.web.tsx +3 -3
- package/src/Progress/types.ts +3 -3
- package/src/RadioButton/RadioButton.native.tsx +4 -3
- package/src/RadioButton/RadioButton.styles.tsx +53 -33
- package/src/RadioButton/RadioGroup.native.tsx +3 -2
- package/src/SVGImage/SVGImage.native.tsx +5 -4
- package/src/SVGImage/SVGImage.styles.tsx +44 -10
- package/src/SVGImage/SVGImage.web.tsx +2 -1
- package/src/Screen/Screen.native.tsx +2 -1
- package/src/Screen/Screen.web.tsx +2 -1
- package/src/Select/Select.native.tsx +6 -5
- package/src/Select/Select.styles.tsx +1 -1
- package/src/Select/Select.web.tsx +4 -3
- package/src/Select/types.ts +1 -1
- package/src/Skeleton/Skeleton.native.tsx +2 -1
- package/src/Skeleton/Skeleton.web.tsx +1 -1
- package/src/Slider/Slider.native.tsx +9 -8
- package/src/Slider/Slider.web.tsx +10 -9
- package/src/Slider/types.ts +9 -2
- package/src/Switch/Switch.native.tsx +7 -6
- package/src/Switch/Switch.styles.tsx +52 -17
- package/src/Switch/Switch.web.tsx +15 -16
- package/src/Switch/types.ts +44 -4
- package/src/TabBar/TabBar.native.tsx +3 -2
- package/src/Text/Text.native.tsx +3 -2
- package/src/Text/Text.web.tsx +2 -1
- package/src/TextArea/TextArea.native.tsx +3 -2
- package/src/TextArea/TextArea.styles.tsx +2 -2
- package/src/TextArea/TextArea.web.tsx +2 -1
- package/src/TextInput/TextInput.native.tsx +300 -0
- package/src/TextInput/TextInput.styles.tsx +207 -0
- package/src/TextInput/TextInput.web.tsx +301 -0
- package/src/TextInput/index.native.ts +3 -0
- package/src/TextInput/index.ts +5 -0
- package/src/TextInput/index.web.ts +5 -0
- package/src/TextInput/types.ts +163 -0
- package/src/Tooltip/Tooltip.native.tsx +3 -2
- package/src/Video/Video.native.tsx +4 -3
- package/src/View/View.native.tsx +2 -1
- package/src/View/View.styles.tsx +1 -0
- package/src/View/View.web.tsx +9 -2
- package/src/examples/ActivityIndicatorExamples.tsx +177 -0
- package/src/examples/AlertExamples.tsx +5 -5
- package/src/examples/ButtonExamples.tsx +12 -12
- package/src/examples/CardExamples.tsx +1 -1
- package/src/examples/CheckboxExamples.tsx +2 -2
- package/src/examples/ChipExamples.tsx +6 -6
- package/src/examples/DialogExamples.tsx +1 -1
- package/src/examples/DividerExamples.tsx +1 -1
- package/src/examples/InputExamples.tsx +1 -1
- package/src/examples/LinkExamples.tsx +1 -1
- package/src/examples/ListExamples.tsx +1 -1
- package/src/examples/MenuExamples.tsx +2 -2
- package/src/examples/ProgressExamples.tsx +1 -1
- package/src/examples/RadioButtonExamples.tsx +5 -5
- package/src/examples/SVGImageExamples.tsx +1 -1
- package/src/examples/SelectExamples.tsx +1 -1
- package/src/examples/SliderExamples.tsx +5 -5
- package/src/examples/SwitchExamples.tsx +26 -26
- package/src/examples/TableExamples.tsx +1 -1
- package/src/examples/TooltipExamples.tsx +2 -2
- package/src/examples/index.ts +1 -0
- package/src/extensions/index.ts +1 -0
- package/src/extensions/types.ts +22 -3
- package/src/index.native.ts +4 -0
- package/src/index.ts +27 -2
- package/src/utils/index.ts +12 -0
- package/src/utils/refTypes.ts +50 -0
|
@@ -2,11 +2,12 @@ import { forwardRef } from 'react';
|
|
|
2
2
|
import { View, Text } from 'react-native';
|
|
3
3
|
import { DividerProps } from './types';
|
|
4
4
|
import { dividerStyles } from './Divider.styles';
|
|
5
|
+
import type { IdealystElement } from '../utils/refTypes';
|
|
5
6
|
|
|
6
|
-
const Divider = forwardRef<
|
|
7
|
+
const Divider = forwardRef<IdealystElement, DividerProps>(({
|
|
7
8
|
orientation = 'horizontal',
|
|
8
9
|
type = 'solid',
|
|
9
|
-
|
|
10
|
+
size = 'sm',
|
|
10
11
|
intent = 'neutral',
|
|
11
12
|
length = 'full',
|
|
12
13
|
spacing = 'md',
|
|
@@ -26,7 +27,7 @@ const Divider = forwardRef<View, DividerProps>(({
|
|
|
26
27
|
// Get dynamic divider style
|
|
27
28
|
const dividerStyle = (dividerStyles.divider as any)({
|
|
28
29
|
orientation,
|
|
29
|
-
|
|
30
|
+
size,
|
|
30
31
|
type,
|
|
31
32
|
intent,
|
|
32
33
|
spacing,
|
|
@@ -35,15 +36,17 @@ const Divider = forwardRef<View, DividerProps>(({
|
|
|
35
36
|
// Get dynamic line style
|
|
36
37
|
const lineStyle = (dividerStyles.line as any)({
|
|
37
38
|
orientation,
|
|
38
|
-
|
|
39
|
+
size,
|
|
39
40
|
});
|
|
40
41
|
|
|
41
|
-
// Get
|
|
42
|
-
const
|
|
43
|
-
switch (
|
|
44
|
-
case '
|
|
42
|
+
// Get size value for dashed/dotted border handling on native
|
|
43
|
+
const getSizeValue = () => {
|
|
44
|
+
switch (size) {
|
|
45
|
+
case 'xs': return 1;
|
|
46
|
+
case 'sm': return 1;
|
|
45
47
|
case 'md': return 2;
|
|
46
|
-
case '
|
|
48
|
+
case 'lg': return 3;
|
|
49
|
+
case 'xl': return 4;
|
|
47
50
|
default: return 1;
|
|
48
51
|
}
|
|
49
52
|
};
|
|
@@ -51,19 +54,19 @@ const Divider = forwardRef<View, DividerProps>(({
|
|
|
51
54
|
// For dashed/dotted variants on native, we need to use border instead of background
|
|
52
55
|
const getNativeDashedStyle = () => {
|
|
53
56
|
if (type === 'dashed' || type === 'dotted') {
|
|
54
|
-
const
|
|
57
|
+
const actualSize = getSizeValue();
|
|
55
58
|
|
|
56
59
|
return {
|
|
57
60
|
backgroundColor: 'transparent',
|
|
58
61
|
borderStyle: type,
|
|
59
62
|
borderColor: dividerStyle.backgroundColor,
|
|
60
63
|
...(orientation === 'horizontal' ? {
|
|
61
|
-
borderTopWidth:
|
|
64
|
+
borderTopWidth: actualSize,
|
|
62
65
|
borderBottomWidth: 0,
|
|
63
66
|
borderLeftWidth: 0,
|
|
64
67
|
borderRightWidth: 0,
|
|
65
68
|
} : {
|
|
66
|
-
borderLeftWidth:
|
|
69
|
+
borderLeftWidth: actualSize,
|
|
67
70
|
borderTopWidth: 0,
|
|
68
71
|
borderBottomWidth: 0,
|
|
69
72
|
borderRightWidth: 0,
|
|
@@ -77,7 +80,7 @@ const Divider = forwardRef<View, DividerProps>(({
|
|
|
77
80
|
if (!children) {
|
|
78
81
|
return (
|
|
79
82
|
<View
|
|
80
|
-
ref={ref}
|
|
83
|
+
ref={ref as any}
|
|
81
84
|
nativeID={id}
|
|
82
85
|
style={[dividerStyle, getNativeDashedStyle(), style]}
|
|
83
86
|
testID={testID}
|
|
@@ -89,7 +92,7 @@ const Divider = forwardRef<View, DividerProps>(({
|
|
|
89
92
|
// For lines with content, create line segments
|
|
90
93
|
const renderLineSegment = () => {
|
|
91
94
|
if (type === 'dashed' || type === 'dotted') {
|
|
92
|
-
const
|
|
95
|
+
const actualSize = getSizeValue();
|
|
93
96
|
|
|
94
97
|
return (
|
|
95
98
|
<View
|
|
@@ -100,12 +103,12 @@ const Divider = forwardRef<View, DividerProps>(({
|
|
|
100
103
|
borderStyle: type,
|
|
101
104
|
borderColor: lineStyle.backgroundColor,
|
|
102
105
|
...(orientation === 'horizontal' ? {
|
|
103
|
-
borderTopWidth:
|
|
106
|
+
borderTopWidth: actualSize,
|
|
104
107
|
borderBottomWidth: 0,
|
|
105
108
|
borderLeftWidth: 0,
|
|
106
109
|
borderRightWidth: 0,
|
|
107
110
|
} : {
|
|
108
|
-
borderLeftWidth:
|
|
111
|
+
borderLeftWidth: actualSize,
|
|
109
112
|
borderTopWidth: 0,
|
|
110
113
|
borderBottomWidth: 0,
|
|
111
114
|
borderRightWidth: 0,
|
|
@@ -121,7 +124,7 @@ const Divider = forwardRef<View, DividerProps>(({
|
|
|
121
124
|
|
|
122
125
|
return (
|
|
123
126
|
<View
|
|
124
|
-
ref={ref}
|
|
127
|
+
ref={ref as any}
|
|
125
128
|
nativeID={id}
|
|
126
129
|
style={dividerStyles.container}
|
|
127
130
|
testID={testID}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { StyleSheet } from 'react-native-unistyles';
|
|
5
5
|
import { defineStyle, ThemeStyleWrapper } from '@idealyst/theme';
|
|
6
|
-
import type { Theme as BaseTheme, Intent } from '@idealyst/theme';
|
|
6
|
+
import type { Theme as BaseTheme, Intent, Size } from '@idealyst/theme';
|
|
7
7
|
|
|
8
8
|
// Required: Unistyles must see StyleSheet usage in original source to process this file
|
|
9
9
|
void StyleSheet;
|
|
@@ -12,14 +12,14 @@ void StyleSheet;
|
|
|
12
12
|
type Theme = ThemeStyleWrapper<BaseTheme>;
|
|
13
13
|
|
|
14
14
|
type DividerOrientation = 'horizontal' | 'vertical';
|
|
15
|
-
type
|
|
15
|
+
type DividerSize = Size;
|
|
16
16
|
type DividerType = 'solid' | 'dashed' | 'dotted';
|
|
17
17
|
type DividerIntent = Intent | 'secondary' | 'neutral' | 'info';
|
|
18
18
|
type DividerSpacing = 'none' | 'sm' | 'md' | 'lg';
|
|
19
19
|
|
|
20
20
|
export type DividerDynamicProps = {
|
|
21
21
|
orientation?: DividerOrientation;
|
|
22
|
-
|
|
22
|
+
size?: DividerSize;
|
|
23
23
|
type?: DividerType;
|
|
24
24
|
intent?: DividerIntent;
|
|
25
25
|
spacing?: DividerSpacing;
|
|
@@ -27,14 +27,20 @@ export type DividerDynamicProps = {
|
|
|
27
27
|
|
|
28
28
|
export type LineDynamicProps = {
|
|
29
29
|
orientation?: DividerOrientation;
|
|
30
|
-
|
|
30
|
+
size?: DividerSize;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Maps Size to thickness value in pixels.
|
|
35
|
+
* xs=1, sm=1, md=2, lg=3, xl=4
|
|
36
|
+
*/
|
|
37
|
+
function getSizeValue(size: DividerSize): number {
|
|
38
|
+
switch (size) {
|
|
39
|
+
case 'xs': return 1;
|
|
40
|
+
case 'sm': return 1;
|
|
36
41
|
case 'md': return 2;
|
|
37
|
-
case '
|
|
42
|
+
case 'lg': return 3;
|
|
43
|
+
case 'xl': return 4;
|
|
38
44
|
default: return 1;
|
|
39
45
|
}
|
|
40
46
|
}
|
|
@@ -50,17 +56,17 @@ function getSpacingValue(spacing: DividerSpacing): number {
|
|
|
50
56
|
}
|
|
51
57
|
|
|
52
58
|
/**
|
|
53
|
-
* Divider styles with dynamic functions for orientation/
|
|
59
|
+
* Divider styles with dynamic functions for orientation/size/intent combinations.
|
|
54
60
|
*/
|
|
55
61
|
export const dividerStyles = defineStyle('Divider', (theme: Theme) => ({
|
|
56
62
|
divider: ({
|
|
57
63
|
orientation = 'horizontal',
|
|
58
|
-
|
|
64
|
+
size = 'sm',
|
|
59
65
|
type = 'solid',
|
|
60
66
|
intent = 'neutral',
|
|
61
67
|
spacing = 'md'
|
|
62
68
|
}: DividerDynamicProps) => {
|
|
63
|
-
const
|
|
69
|
+
const sizeValue = getSizeValue(size);
|
|
64
70
|
const spacingValue = getSpacingValue(spacing);
|
|
65
71
|
const isHorizontal = orientation === 'horizontal';
|
|
66
72
|
const isDashedOrDotted = type === 'dashed' || type === 'dotted';
|
|
@@ -72,11 +78,11 @@ export const dividerStyles = defineStyle('Divider', (theme: Theme) => ({
|
|
|
72
78
|
? theme.colors.border.secondary
|
|
73
79
|
: intent === 'info'
|
|
74
80
|
? theme.intents.primary.primary
|
|
75
|
-
: theme.intents[intent as Intent].primary;
|
|
81
|
+
: (theme.intents[intent as Intent]?.primary ?? theme.colors.border.primary);
|
|
76
82
|
|
|
77
83
|
const dimensionStyles = isHorizontal
|
|
78
|
-
? { width: '100%', height:
|
|
79
|
-
: { width:
|
|
84
|
+
? { width: '100%', height: sizeValue, flexDirection: 'row' as const }
|
|
85
|
+
: { width: sizeValue, height: '100%', flexDirection: 'column' as const };
|
|
80
86
|
|
|
81
87
|
const spacingStyles = isHorizontal
|
|
82
88
|
? { marginVertical: spacingValue }
|
|
@@ -86,8 +92,8 @@ export const dividerStyles = defineStyle('Divider', (theme: Theme) => ({
|
|
|
86
92
|
border: 'none',
|
|
87
93
|
backgroundColor: 'transparent',
|
|
88
94
|
...(isHorizontal
|
|
89
|
-
? { borderTop: `${
|
|
90
|
-
: { borderLeft: `${
|
|
95
|
+
? { borderTop: `${sizeValue}px ${type} ${color}` }
|
|
96
|
+
: { borderLeft: `${sizeValue}px ${type} ${color}` }
|
|
91
97
|
),
|
|
92
98
|
} : {};
|
|
93
99
|
|
|
@@ -137,17 +143,33 @@ export const dividerStyles = defineStyle('Divider', (theme: Theme) => ({
|
|
|
137
143
|
},
|
|
138
144
|
}),
|
|
139
145
|
|
|
140
|
-
line: (
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
: {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
146
|
+
line: (_props: LineDynamicProps) => ({
|
|
147
|
+
backgroundColor: theme.colors.border.secondary,
|
|
148
|
+
flex: 1,
|
|
149
|
+
variants: {
|
|
150
|
+
orientation: {
|
|
151
|
+
horizontal: {},
|
|
152
|
+
vertical: {},
|
|
153
|
+
},
|
|
154
|
+
size: {
|
|
155
|
+
xs: {},
|
|
156
|
+
sm: {},
|
|
157
|
+
md: {},
|
|
158
|
+
lg: {},
|
|
159
|
+
xl: {},
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
compoundVariants: [
|
|
163
|
+
{ orientation: 'horizontal', size: 'xs', styles: { height: 1 } },
|
|
164
|
+
{ orientation: 'horizontal', size: 'sm', styles: { height: 1 } },
|
|
165
|
+
{ orientation: 'horizontal', size: 'md', styles: { height: 2 } },
|
|
166
|
+
{ orientation: 'horizontal', size: 'lg', styles: { height: 3 } },
|
|
167
|
+
{ orientation: 'horizontal', size: 'xl', styles: { height: 4 } },
|
|
168
|
+
{ orientation: 'vertical', size: 'xs', styles: { width: 1 } },
|
|
169
|
+
{ orientation: 'vertical', size: 'sm', styles: { width: 1 } },
|
|
170
|
+
{ orientation: 'vertical', size: 'md', styles: { width: 2 } },
|
|
171
|
+
{ orientation: 'vertical', size: 'lg', styles: { width: 3 } },
|
|
172
|
+
{ orientation: 'vertical', size: 'xl', styles: { width: 4 } },
|
|
173
|
+
],
|
|
174
|
+
}),
|
|
153
175
|
}));
|
|
@@ -3,15 +3,16 @@ import { getWebProps } from 'react-native-unistyles/web';
|
|
|
3
3
|
import { DividerProps } from './types';
|
|
4
4
|
import { dividerStyles } from './Divider.styles';
|
|
5
5
|
import useMergeRefs from '../hooks/useMergeRefs';
|
|
6
|
+
import type { IdealystElement } from '../utils/refTypes';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Visual separator for dividing content sections horizontally or vertically.
|
|
9
10
|
* Supports solid, dashed, and dotted styles with optional text content.
|
|
10
11
|
*/
|
|
11
|
-
const Divider = forwardRef<
|
|
12
|
+
const Divider = forwardRef<IdealystElement, DividerProps>(({
|
|
12
13
|
orientation = 'horizontal',
|
|
13
14
|
type = 'solid',
|
|
14
|
-
|
|
15
|
+
size = 'sm',
|
|
15
16
|
intent = 'neutral',
|
|
16
17
|
length = 'full',
|
|
17
18
|
spacing = 'md',
|
|
@@ -31,7 +32,7 @@ const Divider = forwardRef<HTMLDivElement, DividerProps>(({
|
|
|
31
32
|
// Get dynamic divider style
|
|
32
33
|
const dividerStyle = (dividerStyles.divider as any)({
|
|
33
34
|
orientation,
|
|
34
|
-
|
|
35
|
+
size,
|
|
35
36
|
type,
|
|
36
37
|
intent,
|
|
37
38
|
spacing,
|
|
@@ -40,7 +41,7 @@ const Divider = forwardRef<HTMLDivElement, DividerProps>(({
|
|
|
40
41
|
// Get dynamic line style
|
|
41
42
|
const lineStyle = (dividerStyles.line as any)({
|
|
42
43
|
orientation,
|
|
43
|
-
|
|
44
|
+
size,
|
|
44
45
|
});
|
|
45
46
|
|
|
46
47
|
// Generate web props
|
package/src/Divider/types.ts
CHANGED
|
@@ -5,9 +5,9 @@ import { BaseProps } from '../utils/viewStyleProps';
|
|
|
5
5
|
|
|
6
6
|
// Component-specific type aliases for future extensibility
|
|
7
7
|
export type DividerIntentVariant = Intent;
|
|
8
|
+
export type DividerSizeVariant = Size;
|
|
8
9
|
export type DividerOrientationVariant = 'horizontal' | 'vertical';
|
|
9
10
|
export type DividerType = 'solid' | 'dashed' | 'dotted';
|
|
10
|
-
export type DividerThicknessVariant = 'thin' | 'md' | 'thick';
|
|
11
11
|
export type DividerLengthVariant = 'full' | 'auto' | number;
|
|
12
12
|
export type DividerSpacingVariant = 'none' | Size;
|
|
13
13
|
|
|
@@ -27,9 +27,9 @@ export interface DividerProps extends BaseProps {
|
|
|
27
27
|
type?: DividerType;
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* The thickness of the divider
|
|
30
|
+
* The size (thickness) of the divider
|
|
31
31
|
*/
|
|
32
|
-
|
|
32
|
+
size?: DividerSizeVariant;
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* The color intent of the divider
|
package/src/Icon/Icon.native.tsx
CHANGED
|
@@ -2,8 +2,9 @@ import { forwardRef, useMemo } from 'react';
|
|
|
2
2
|
import MaterialDesignIcons from '@react-native-vector-icons/material-design-icons';
|
|
3
3
|
import { IconProps } from './types';
|
|
4
4
|
import { iconStyles } from './Icon.styles';
|
|
5
|
+
import type { IdealystElement } from '../utils/refTypes';
|
|
5
6
|
|
|
6
|
-
const Icon = forwardRef<
|
|
7
|
+
const Icon = forwardRef<IdealystElement, IconProps>(({
|
|
7
8
|
name,
|
|
8
9
|
size = 'md',
|
|
9
10
|
color,
|
|
@@ -26,7 +27,7 @@ const Icon = forwardRef<any, IconProps>(({
|
|
|
26
27
|
|
|
27
28
|
return (
|
|
28
29
|
<MaterialDesignIcons
|
|
29
|
-
ref={ref}
|
|
30
|
+
ref={ref as any}
|
|
30
31
|
nativeID={id}
|
|
31
32
|
size={iconSize}
|
|
32
33
|
name={name}
|
package/src/Icon/Icon.web.tsx
CHANGED
|
@@ -7,12 +7,13 @@ import { useUnistyles } from 'react-native-unistyles';
|
|
|
7
7
|
import useMergeRefs from '../hooks/useMergeRefs';
|
|
8
8
|
import { getColorFromString, Intent, Color, Text } from '@idealyst/theme';
|
|
9
9
|
import { IconRegistry } from './IconRegistry';
|
|
10
|
+
import type { IdealystElement } from '../utils/refTypes';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Vector icon display from the Material Design Icons library.
|
|
13
14
|
* Supports intent-based coloring and theme-aware sizing.
|
|
14
15
|
*/
|
|
15
|
-
const Icon = forwardRef<
|
|
16
|
+
const Icon = forwardRef<IdealystElement, IconProps>((props, ref) => {
|
|
16
17
|
const {
|
|
17
18
|
name,
|
|
18
19
|
size = 'md',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { View } from 'react-native';
|
|
3
3
|
import Svg, { Path } from 'react-native-svg';
|
|
4
|
+
import type { IdealystElement } from '../../utils/refTypes';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Internal component for rendering SVG icons directly from MDI paths.
|
|
@@ -18,7 +19,7 @@ interface IconSvgProps {
|
|
|
18
19
|
'data-testid'?: string;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
export const IconSvg = React.forwardRef<
|
|
22
|
+
export const IconSvg = React.forwardRef<IdealystElement, IconSvgProps>(({
|
|
22
23
|
path,
|
|
23
24
|
size = 24,
|
|
24
25
|
color = 'currentColor',
|
|
@@ -29,7 +30,7 @@ export const IconSvg = React.forwardRef<View, IconSvgProps>(({
|
|
|
29
30
|
const sizeNum = typeof size === 'string' ? parseFloat(size) : size;
|
|
30
31
|
|
|
31
32
|
return (
|
|
32
|
-
<View ref={ref} style={[{ width: sizeNum, height: sizeNum }, style]} testID={testID}>
|
|
33
|
+
<View ref={ref as any} style={[{ width: sizeNum, height: sizeNum }, style]} testID={testID}>
|
|
33
34
|
<Svg viewBox="0 0 24 24" width={sizeNum} height={sizeNum}>
|
|
34
35
|
<Path d={path} fill={color} />
|
|
35
36
|
</Svg>
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { forwardRef, useMemo } from 'react';
|
|
2
|
+
import { ActivityIndicator, StyleSheet as RNStyleSheet, TouchableOpacity, View } from 'react-native';
|
|
3
|
+
import MaterialDesignIcons from '@react-native-vector-icons/material-design-icons';
|
|
4
|
+
import Svg, { Defs, LinearGradient, Stop, Rect } from 'react-native-svg';
|
|
5
|
+
import { iconButtonStyles } from './IconButton.styles';
|
|
6
|
+
import { IconButtonProps } from './types';
|
|
7
|
+
import { getNativeInteractiveAccessibilityProps } from '../utils/accessibility';
|
|
8
|
+
import type { IdealystElement } from '../utils/refTypes';
|
|
9
|
+
|
|
10
|
+
const IconButton = forwardRef<IdealystElement, IconButtonProps>((props, ref) => {
|
|
11
|
+
const {
|
|
12
|
+
icon,
|
|
13
|
+
onPress,
|
|
14
|
+
onClick,
|
|
15
|
+
disabled = false,
|
|
16
|
+
loading = false,
|
|
17
|
+
type = 'contained',
|
|
18
|
+
intent = 'primary',
|
|
19
|
+
size = 'md',
|
|
20
|
+
gradient,
|
|
21
|
+
style,
|
|
22
|
+
testID,
|
|
23
|
+
id,
|
|
24
|
+
// Accessibility props
|
|
25
|
+
accessibilityLabel,
|
|
26
|
+
accessibilityHint,
|
|
27
|
+
accessibilityDisabled,
|
|
28
|
+
accessibilityHidden,
|
|
29
|
+
accessibilityRole,
|
|
30
|
+
accessibilityLabelledBy,
|
|
31
|
+
accessibilityDescribedBy,
|
|
32
|
+
accessibilityControls,
|
|
33
|
+
accessibilityExpanded,
|
|
34
|
+
accessibilityPressed,
|
|
35
|
+
} = props;
|
|
36
|
+
|
|
37
|
+
// Button is effectively disabled when loading
|
|
38
|
+
const isDisabled = disabled || loading;
|
|
39
|
+
|
|
40
|
+
// Determine the handler to use - onPress takes precedence
|
|
41
|
+
const pressHandler = onPress ?? onClick;
|
|
42
|
+
|
|
43
|
+
// Warn about deprecated onClick usage in development
|
|
44
|
+
if (__DEV__ && onClick && !onPress) {
|
|
45
|
+
console.warn(
|
|
46
|
+
'IconButton: onClick prop is deprecated. Use onPress instead for cross-platform compatibility.'
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Apply variants for size, disabled, gradient
|
|
51
|
+
iconButtonStyles.useVariants({
|
|
52
|
+
size,
|
|
53
|
+
disabled: isDisabled,
|
|
54
|
+
gradient,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Compute dynamic styles with all props for full flexibility
|
|
58
|
+
const dynamicProps = { intent, type, size, disabled: isDisabled, gradient };
|
|
59
|
+
const buttonStyle = (iconButtonStyles.button as any)(dynamicProps);
|
|
60
|
+
const iconStyle = (iconButtonStyles.icon as any)(dynamicProps);
|
|
61
|
+
const spinnerStyle = (iconButtonStyles.spinner as any)(dynamicProps);
|
|
62
|
+
|
|
63
|
+
// Gradient is only applicable to contained buttons
|
|
64
|
+
const showGradient = gradient && type === 'contained';
|
|
65
|
+
|
|
66
|
+
// Map button size to icon size
|
|
67
|
+
const iconSizeMap: Record<string, number> = {
|
|
68
|
+
xs: 12,
|
|
69
|
+
sm: 14,
|
|
70
|
+
md: 16,
|
|
71
|
+
lg: 18,
|
|
72
|
+
xl: 20,
|
|
73
|
+
};
|
|
74
|
+
const iconSize = iconSizeMap[size] ?? 16;
|
|
75
|
+
|
|
76
|
+
// Generate native accessibility props
|
|
77
|
+
const nativeA11yProps = useMemo(() => {
|
|
78
|
+
const computedLabel = accessibilityLabel ?? (typeof icon === 'string' ? icon : undefined);
|
|
79
|
+
|
|
80
|
+
return getNativeInteractiveAccessibilityProps({
|
|
81
|
+
accessibilityLabel: computedLabel,
|
|
82
|
+
accessibilityHint,
|
|
83
|
+
accessibilityDisabled: accessibilityDisabled ?? isDisabled,
|
|
84
|
+
accessibilityHidden,
|
|
85
|
+
accessibilityRole: accessibilityRole ?? 'button',
|
|
86
|
+
accessibilityLabelledBy,
|
|
87
|
+
accessibilityDescribedBy,
|
|
88
|
+
accessibilityControls,
|
|
89
|
+
accessibilityExpanded,
|
|
90
|
+
accessibilityPressed,
|
|
91
|
+
});
|
|
92
|
+
}, [
|
|
93
|
+
accessibilityLabel,
|
|
94
|
+
icon,
|
|
95
|
+
accessibilityHint,
|
|
96
|
+
accessibilityDisabled,
|
|
97
|
+
isDisabled,
|
|
98
|
+
accessibilityHidden,
|
|
99
|
+
accessibilityRole,
|
|
100
|
+
accessibilityLabelledBy,
|
|
101
|
+
accessibilityDescribedBy,
|
|
102
|
+
accessibilityControls,
|
|
103
|
+
accessibilityExpanded,
|
|
104
|
+
accessibilityPressed,
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
// Render gradient background layer
|
|
108
|
+
const renderGradientLayer = () => {
|
|
109
|
+
if (!showGradient) return null;
|
|
110
|
+
|
|
111
|
+
const [startColor, endColor] = useMemo(() => {
|
|
112
|
+
switch (gradient) {
|
|
113
|
+
case 'darken': return [{
|
|
114
|
+
stopColor: 'black',
|
|
115
|
+
stopOpacity: 0,
|
|
116
|
+
}, {
|
|
117
|
+
stopColor: 'black',
|
|
118
|
+
stopOpacity: 0.15,
|
|
119
|
+
}];
|
|
120
|
+
case 'lighten': return [{
|
|
121
|
+
stopColor: 'white',
|
|
122
|
+
stopOpacity: 0,
|
|
123
|
+
}, {
|
|
124
|
+
stopColor: 'white',
|
|
125
|
+
stopOpacity: 0.2,
|
|
126
|
+
}];
|
|
127
|
+
default: return [{
|
|
128
|
+
stopColor: 'black',
|
|
129
|
+
stopOpacity: 0,
|
|
130
|
+
}, {
|
|
131
|
+
stopColor: 'black',
|
|
132
|
+
stopOpacity: 0,
|
|
133
|
+
}];
|
|
134
|
+
}
|
|
135
|
+
}, [gradient]);
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<Svg style={RNStyleSheet.absoluteFill}>
|
|
139
|
+
<Defs>
|
|
140
|
+
<LinearGradient id="iconButtonGradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
141
|
+
<Stop offset="0%" {...startColor} />
|
|
142
|
+
<Stop offset="100%" {...endColor} />
|
|
143
|
+
</LinearGradient>
|
|
144
|
+
</Defs>
|
|
145
|
+
<Rect
|
|
146
|
+
width="100%"
|
|
147
|
+
height="100%"
|
|
148
|
+
fill="url(#iconButtonGradient)"
|
|
149
|
+
rx={9999}
|
|
150
|
+
ry={9999}
|
|
151
|
+
/>
|
|
152
|
+
</Svg>
|
|
153
|
+
);
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// TouchableOpacity types don't include nativeID but it's a valid RN prop
|
|
157
|
+
const touchableProps = {
|
|
158
|
+
ref,
|
|
159
|
+
onPress: pressHandler,
|
|
160
|
+
disabled: isDisabled,
|
|
161
|
+
testID,
|
|
162
|
+
nativeID: id,
|
|
163
|
+
activeOpacity: 0.7,
|
|
164
|
+
style: [
|
|
165
|
+
buttonStyle,
|
|
166
|
+
showGradient && { overflow: 'hidden' },
|
|
167
|
+
style,
|
|
168
|
+
],
|
|
169
|
+
accessibilityState: loading ? { busy: true } : undefined,
|
|
170
|
+
...nativeA11yProps,
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// Get spinner color from the spinner style (matches icon color)
|
|
174
|
+
const spinnerColor = spinnerStyle?.color || (type === 'contained' ? '#fff' : undefined);
|
|
175
|
+
|
|
176
|
+
// Content opacity - hide when loading but keep for sizing
|
|
177
|
+
const contentOpacity = loading ? 0 : 1;
|
|
178
|
+
|
|
179
|
+
// Render icon
|
|
180
|
+
const renderIcon = () => {
|
|
181
|
+
if (typeof icon === 'string') {
|
|
182
|
+
return (
|
|
183
|
+
<MaterialDesignIcons
|
|
184
|
+
name={icon}
|
|
185
|
+
size={iconSize}
|
|
186
|
+
style={[iconStyle, { opacity: contentOpacity }]}
|
|
187
|
+
/>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
// Custom ReactNode icon
|
|
191
|
+
return (
|
|
192
|
+
<View style={{ opacity: contentOpacity }}>
|
|
193
|
+
{icon}
|
|
194
|
+
</View>
|
|
195
|
+
);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
return (
|
|
199
|
+
<TouchableOpacity {...touchableProps as any}>
|
|
200
|
+
{renderGradientLayer()}
|
|
201
|
+
{/* Centered spinner overlay */}
|
|
202
|
+
{loading && (
|
|
203
|
+
<View style={RNStyleSheet.absoluteFill}>
|
|
204
|
+
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
|
205
|
+
<ActivityIndicator
|
|
206
|
+
size="small"
|
|
207
|
+
color={spinnerColor}
|
|
208
|
+
/>
|
|
209
|
+
</View>
|
|
210
|
+
</View>
|
|
211
|
+
)}
|
|
212
|
+
{renderIcon()}
|
|
213
|
+
</TouchableOpacity>
|
|
214
|
+
);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
IconButton.displayName = 'IconButton';
|
|
218
|
+
|
|
219
|
+
export default IconButton;
|