Skip to content

Commit 1a4746e

Browse files
Merge branch 'buttons' into 'main'
Buttons See merge request react-native/react-native-material-components!14
2 parents 1b605fe + 3ffbd29 commit 1a4746e

36 files changed

+958
-21
lines changed

README.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,92 @@ export const AppBodyLargeText: React.FC<PropsWithChildren> = ({children}) => {
212212
![linear activity indicator gif](https://ik.imagekit.io/Computools/rn-material-components/linear-indicator-gif.gif?updatedAt=1705066319092)
213213
</details>
214214
</details>
215+
<details><summary>Buttons</summary>
216+
<br />
217+
<details><summary>Common buttons</summary>
218+
<br />
219+
220+
**Components**
221+
222+
- ```TextButton```
223+
- ```FilledButton```
224+
- ```OutlinedButton```
225+
- ```ElevatedButton```
226+
- ```TonalButton```
227+
228+
**Properties**
229+
230+
| name | description | type | default |
231+
| ------ | ------ | ------ | ----|
232+
| title | required | string | - |
233+
| StartIcon | - | React.FC<T> | - |
234+
| EndIcon | - | React.FC<T> | - |
235+
| iconProps | - | T | - |
236+
| titleStyle | - | StyleProp<TextStyle | - |
237+
238+
![common buttons](https://ik.imagekit.io/Computools/rn-material-components/common_buttons.png?updatedAt=1730123562488)
239+
</details>
240+
<details><summary>Icon buttons</summary>
241+
<br />
242+
243+
**Components**
244+
245+
- ```StandartIconButton```
246+
- ```FilledIconButton```
247+
- ```OutlinedIconButton```
248+
- ```TonalIconButton```
249+
250+
**Properties**
251+
252+
| name | description | type | default |
253+
| ------ | ------ | ------ | ----|
254+
| Icon | required | React.FC<T> | - |
255+
| size | - | number | - |
256+
| selectedIcon | - | React.FC<T> | - |
257+
| selected | - | boolean | false |
258+
| iconProps | - | T | - |
259+
260+
![icon buttons](https://ik.imagekit.io/Computools/rn-material-components/icon_buttons.png?updatedAt=1730123727799)
261+
</details>
262+
<details><summary>Floatin action button</summary>
263+
<br />
264+
265+
**Properties**
266+
267+
| name | description | type | default |
268+
| ------ | ------ | ------ | ----|
269+
| type | PRIMARY, SECONDARY, TERTIARY, SURRFACE | FloatingActionButtonType | PRIMARY |
270+
| label | - | string | - |
271+
| extended | Enables control over label visibility with animation. If set to true, the label remains constantly visible; otherwise, it appears or hides with an animation based on specific conditions | true | - |
272+
| size | SMALL, BIG | FloatingActionButtonSize | SMALL |
273+
| iconProps | - | T | - |
274+
| Icon | - | React.FC<T> | - |
275+
| labelStyle | - | StyleProp<TextStyle> | - |
276+
277+
![fab](https://ik.imagekit.io/Computools/rn-material-components/fab.gif?updatedAt=1730123868550)
278+
</details>
279+
<details><summary>Segmented button</summary>
280+
<br />
281+
282+
**Properties**
283+
284+
| name | description | type | default |
285+
| ------ | ------ | ------ | ----|
286+
| segments | required | ButtonSegment<T, U>[] | - |
287+
| selected | required | T[] | - |
288+
| onSegmentPress | required |(value: T[] | ((currValues: T[]) => T[])) => void | - |
289+
| disabled | - | boolean | false |
290+
| multiSelectionEnabled | - | boolean | false |
291+
| withCheckmark | Enables control over checkmark visibility with selected segment. | boolean | true |
292+
| iconSize | - | number | 18 |
293+
| iconColor | - | ColorValue | - |
294+
| iconColor | - | ColorValue | - |
295+
| rippleColor | - | ColorValue | - |
296+
| labelStyle | - | StyleProp<TextStyle> | - |
297+
298+
![segmented buttons](https://ik.imagekit.io/Computools/rn-material-components/segmented_button_single.gif?updatedAt=1730123815131)
299+
</details>
300+
</details>
215301
<details><summary>Cards</summary>
216302
<br />
217303
<details><summary>Filled Card</summary>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import React from 'react';
2+
import {TouchableOpacity, Text, type StyleProp, type TextStyle, type TouchableOpacityProps} from 'react-native';
3+
4+
import {styles} from './common-button.styles';
5+
import {type IconProps} from '../../../icons/icon-props';
6+
import {useTypography} from '../../../typography/useTypography.component';
7+
8+
export interface CommonButtonProps<T extends IconProps> extends TouchableOpacityProps {
9+
title: string;
10+
11+
titleStyle?: StyleProp<TextStyle>;
12+
StartIcon?: React.FC<T>;
13+
EndIcon?: React.FC<T>;
14+
iconProps?: T;
15+
}
16+
17+
const DEFAULT_ICON_SIZE = 18;
18+
19+
export const CommonButton = <T extends IconProps>({
20+
title,
21+
StartIcon,
22+
EndIcon,
23+
titleStyle,
24+
iconProps = {} as T,
25+
style,
26+
...props
27+
}: CommonButtonProps<T>) => {
28+
const {labelLarge} = useTypography();
29+
30+
const containerPaddingStart = StartIcon || EndIcon ? 16 : 24;
31+
32+
return (
33+
<TouchableOpacity style={[styles.container, {paddingStart: containerPaddingStart}, style]} hitSlop={16} {...props}>
34+
{StartIcon && <StartIcon size={DEFAULT_ICON_SIZE} {...iconProps} />}
35+
<Text style={[labelLarge, titleStyle]}>{title}</Text>
36+
{EndIcon && <EndIcon size={DEFAULT_ICON_SIZE} {...iconProps} />}
37+
</TouchableOpacity>
38+
);
39+
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {StyleSheet} from 'react-native';
2+
3+
export const styles = StyleSheet.create({
4+
container: {
5+
flexDirection: 'row',
6+
alignItems: 'center',
7+
gap: 8,
8+
9+
paddingVertical: 10,
10+
paddingEnd: 24,
11+
paddingStart: 16,
12+
borderRadius: 100,
13+
},
14+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React, {useMemo} from 'react';
2+
import {StyleSheet} from 'react-native';
3+
4+
import {styles} from './elevated-button.styles';
5+
import {useTheme} from '../../../theme/useTheme.hook';
6+
import {type IconProps} from '../../../icons/icon-props';
7+
import {convertToRGBA} from '../../../utils/convert-to-rgba';
8+
import {CommonButton, type CommonButtonProps} from '../common-button/CommonButton.component';
9+
10+
export const ElevatedButton = <T extends IconProps>({titleStyle, style, iconProps = {} as T, ...props}: CommonButtonProps<T>) => {
11+
const {primary, surface, shadow, surfaceContainer} = useTheme();
12+
13+
const colorStyles = useMemo(
14+
() =>
15+
StyleSheet.create(
16+
props.disabled
17+
? {
18+
title: {color: convertToRGBA(surface.text as string, 0.38)},
19+
container: {backgroundColor: convertToRGBA(surface.text as string, 0.12)},
20+
}
21+
: {title: {color: primary.background}, container: {backgroundColor: surfaceContainer.backgroundLow, shadowColor: shadow}}
22+
),
23+
[props.disabled]
24+
);
25+
26+
return (
27+
<CommonButton
28+
style={[colorStyles.container, styles.container, style]}
29+
titleStyle={[colorStyles.title, titleStyle]}
30+
iconProps={{color: colorStyles.title.color, ...iconProps}}
31+
{...props}
32+
/>
33+
);
34+
};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import {StyleSheet} from 'react-native';
2+
3+
export const styles = StyleSheet.create({
4+
container: {
5+
shadowOffset: {
6+
width: 0,
7+
height: 1,
8+
},
9+
shadowOpacity: 0.15,
10+
shadowRadius: 3,
11+
elevation: 3,
12+
},
13+
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React, {useMemo} from 'react';
2+
import {StyleSheet} from 'react-native';
3+
4+
import {useTheme} from '../../../theme/useTheme.hook';
5+
import {type IconProps} from '../../../icons/icon-props';
6+
import {convertToRGBA} from '../../../utils/convert-to-rgba';
7+
import {CommonButton, type CommonButtonProps} from '../common-button/CommonButton.component';
8+
9+
export const FilledButton = <T extends IconProps>({style, titleStyle, iconProps = {} as T, ...props}: CommonButtonProps<T>) => {
10+
const {primary, surface} = useTheme();
11+
12+
const colorStyles = useMemo(
13+
() =>
14+
StyleSheet.create(
15+
props.disabled
16+
? {
17+
title: {color: convertToRGBA(surface.text as string, 0.38)},
18+
container: {backgroundColor: convertToRGBA(surface.text as string, 0.12)},
19+
}
20+
: {title: {color: primary.text}, container: {backgroundColor: primary.background}}
21+
),
22+
[props.disabled]
23+
);
24+
25+
return (
26+
<CommonButton
27+
style={[colorStyles.container, style]}
28+
titleStyle={[colorStyles.title, titleStyle]}
29+
iconProps={{color: colorStyles.title.color, ...iconProps}}
30+
{...props}
31+
/>
32+
);
33+
};
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React, {useMemo} from 'react';
2+
import {StyleSheet} from 'react-native';
3+
4+
import {styles} from './outlined-button.styles';
5+
import {useTheme} from '../../../theme/useTheme.hook';
6+
import {type IconProps} from '../../../icons/icon-props';
7+
import {convertToRGBA} from '../../../utils/convert-to-rgba';
8+
import {CommonButton, type CommonButtonProps} from '../common-button/CommonButton.component';
9+
10+
export const OutlinedButton = <T extends IconProps>({titleStyle, style, iconProps = {} as T, ...props}: CommonButtonProps<T>) => {
11+
const {primary, outline, surface} = useTheme();
12+
13+
const colorStyles = useMemo(
14+
() =>
15+
StyleSheet.create(
16+
props.disabled
17+
? {title: {color: convertToRGBA(surface.text as string, 0.38)}, container: {borderColor: convertToRGBA(surface.text as string, 0.12)}}
18+
: {title: {color: primary.background}, container: {borderColor: outline}}
19+
),
20+
[props.disabled]
21+
);
22+
23+
return (
24+
<CommonButton
25+
titleStyle={[colorStyles.title, titleStyle]}
26+
style={[styles.container, colorStyles.container, style]}
27+
iconProps={{color: colorStyles.title.color, ...iconProps}}
28+
{...props}
29+
/>
30+
);
31+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import {StyleSheet} from 'react-native';
2+
3+
export const styles = StyleSheet.create({
4+
container: {
5+
borderWidth: 1,
6+
},
7+
});
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React, {useMemo} from 'react';
2+
import {StyleSheet} from 'react-native';
3+
4+
import {useTheme} from '../../../theme/useTheme.hook';
5+
import {type IconProps} from '../../../icons/icon-props';
6+
import {convertToRGBA} from '../../../utils/convert-to-rgba';
7+
import {CommonButton, type CommonButtonProps} from '../common-button/CommonButton.component';
8+
9+
export const TextButton = <T extends IconProps>({titleStyle, iconProps = {} as T, ...props}: CommonButtonProps<T>) => {
10+
const {primary, surface} = useTheme();
11+
12+
const colorStyles = useMemo(
13+
() =>
14+
StyleSheet.create({
15+
title: {color: props.disabled ? convertToRGBA(surface.text as string, 0.38) : primary.background},
16+
}),
17+
[props.disabled]
18+
);
19+
20+
return <CommonButton titleStyle={[colorStyles.title, titleStyle]} iconProps={{color: colorStyles.title.color, ...iconProps}} {...props} />;
21+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React, {useMemo} from 'react';
2+
import {StyleSheet} from 'react-native';
3+
4+
import {useTheme} from '../../../theme/useTheme.hook';
5+
import {convertToRGBA} from '../../../utils/convert-to-rgba';
6+
import {CommonButton, type CommonButtonProps} from '../common-button/CommonButton.component';
7+
import {type IconProps} from '../../../icons/icon-props';
8+
9+
export const TonalButton = <T extends IconProps>({titleStyle, style, iconProps = {} as T, ...props}: CommonButtonProps<T>) => {
10+
const {secondaryContainer, surface} = useTheme();
11+
12+
const colorStyles = useMemo(
13+
() =>
14+
StyleSheet.create(
15+
props.disabled
16+
? {
17+
title: {color: convertToRGBA(surface.text as string, 0.38)},
18+
container: {borderColor: convertToRGBA(surface.text as string, 0.12)},
19+
}
20+
: {title: {color: secondaryContainer.text}, container: {backgroundColor: secondaryContainer.background}}
21+
),
22+
[props.disabled]
23+
);
24+
25+
return (
26+
<CommonButton
27+
style={[colorStyles.container, style]}
28+
titleStyle={[colorStyles.title, titleStyle]}
29+
iconProps={{color: colorStyles.title.color, ...iconProps}}
30+
{...props}
31+
/>
32+
);
33+
};

0 commit comments

Comments
 (0)