Skip to content

Commit 3966bd7

Browse files
feat(buttons): implemented icon buttons
1 parent da820a0 commit 3966bd7

File tree

11 files changed

+184
-4
lines changed

11 files changed

+184
-4
lines changed

src/buttons/common-buttons/outlined-button/OutlinedButton.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const OutlinedButton: React.FC<CommonButtonProps> = ({titleStyle, style,
1212
() =>
1313
StyleSheet.create(
1414
props.disabled
15-
? {title: {opacity: 0.38, color: surface.text}, container: {opacity: 0.12, borderColor: surface.text}}
15+
? {title: {opacity: 0.38, color: surface.text}, container: {borderColor: surface.text}}
1616
: {title: {color: primary.background}, container: {borderColor: outline}}
1717
),
1818
[props.disabled]
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from 'react';
2+
import {TouchableOpacity, type TouchableOpacityProps} from 'react-native';
3+
4+
import {type IconProps} from '../../../types/icon-props.type';
5+
import {getIconButtonFrameStyles, styles} from './base-icon-button.styles';
6+
7+
export interface BaseIconButtonProps extends TouchableOpacityProps {
8+
Icon: React.FC<IconProps>;
9+
10+
size?: number;
11+
iconProps?: IconProps;
12+
}
13+
14+
const DEFAULT_SIZE = 40;
15+
const ICON_SIZE_COEFF = 0.6;
16+
17+
export const BaseIconButton: React.FC<BaseIconButtonProps> = ({Icon, size = DEFAULT_SIZE, iconProps, style, ...props}) => (
18+
<TouchableOpacity style={[styles.container, getIconButtonFrameStyles(size), style]} hitSlop={8} {...props}>
19+
<Icon size={size * ICON_SIZE_COEFF} {...iconProps} />
20+
</TouchableOpacity>
21+
);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {StyleSheet} from 'react-native';
2+
3+
export const styles = StyleSheet.create({
4+
container: {
5+
alignItems: 'center',
6+
justifyContent: 'center',
7+
},
8+
});
9+
10+
export const getIconButtonFrameStyles = (size: number) =>
11+
StyleSheet.create({
12+
container: {
13+
width: size,
14+
height: size,
15+
borderRadius: size * 0.5,
16+
},
17+
}).container;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react';
2+
3+
import {useTheme} from '../../../theme/useTheme.hook';
4+
import {type IconButtonProps} from '../icon-button.types';
5+
import {type ColorValue} from '../../../theme/theme.types';
6+
import {convertToRGBA} from '../../../utils/convert-to-rgba';
7+
import {BaseIconButton} from '../base-icon-button/BaseIconButton.component';
8+
9+
export const FilledIconButton: React.FC<IconButtonProps> = ({selected, Icon, selectedIcon, style, ...props}) => {
10+
const {primary, surface, surfaceContainer} = useTheme();
11+
12+
const disabledIconColor = convertToRGBA(surface.text as ColorValue, 0.38);
13+
const disabledContainerColor = convertToRGBA(surface.text as ColorValue, 0.12);
14+
15+
const [activeContainerColor, activeIconColor, IconComponent] = selected
16+
? [primary.background, primary.text, selectedIcon ?? Icon]
17+
: [surfaceContainer.backgroundHighest, primary.background, Icon];
18+
const [appliedContainerColor, appliedIconColor] = props.disabled
19+
? [disabledContainerColor, disabledIconColor]
20+
: [activeContainerColor, activeIconColor];
21+
22+
return (
23+
<BaseIconButton style={[{backgroundColor: appliedContainerColor}, style]} Icon={IconComponent} iconProps={{color: appliedIconColor}} {...props} />
24+
);
25+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import type {IconProps} from '../../icons/icon-props';
2+
import type {BaseIconButtonProps} from './base-icon-button/BaseIconButton.component';
3+
4+
export interface IconButtonProps extends BaseIconButtonProps {
5+
selected?: boolean;
6+
selectedIcon?: React.FC<IconProps>;
7+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from 'react';
2+
3+
import {useTheme} from '../../../theme/useTheme.hook';
4+
import {type ColorValue} from 'src/theme/theme.types';
5+
import {type IconButtonProps} from '../icon-button.types';
6+
import {convertToRGBA} from '../../../utils/convert-to-rgba';
7+
import {BaseIconButton} from '../base-icon-button/BaseIconButton.component';
8+
9+
export const OutlinedIconButton: React.FC<IconButtonProps> = ({selected, Icon, selectedIcon, style, ...props}) => {
10+
const {surface, outline} = useTheme();
11+
12+
const disabledIconColor = convertToRGBA(surface.text as ColorValue, 0.38);
13+
const disabledContainerColor = convertToRGBA(surface.text as ColorValue, 0.12);
14+
const appliedDisabledContainerColor = selected ? convertToRGBA(surface.text as ColorValue, 0.12) : 'transparent';
15+
16+
const [activeContainerColor, activeIconColor, activeBorderColor, IconComponent] = selected
17+
? [surface.backgroundInverse, surface.textInverse, surface.backgroundInverse, selectedIcon ?? Icon]
18+
: ['transparent', surface.textVariant, outline, Icon];
19+
const [appliedContainerColor, appliedIconColor, appliedBorderColor] = props.disabled
20+
? [appliedDisabledContainerColor, disabledIconColor, disabledContainerColor]
21+
: [activeContainerColor, activeIconColor, activeBorderColor];
22+
23+
return (
24+
<BaseIconButton
25+
style={[{backgroundColor: appliedContainerColor, borderColor: appliedBorderColor, borderWidth: Number(!selected)}, style]}
26+
Icon={IconComponent}
27+
iconProps={{color: appliedIconColor}}
28+
{...props}
29+
/>
30+
);
31+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React from 'react';
2+
3+
import {useTheme} from '../../../theme/useTheme.hook';
4+
import {type IconButtonProps} from '../icon-button.types';
5+
import {type ColorValue} from '../../../theme/theme.types';
6+
import {convertToRGBA} from '../../../utils/convert-to-rgba';
7+
import {BaseIconButton} from '../base-icon-button/BaseIconButton.component';
8+
9+
export const StandartIconButton: React.FC<IconButtonProps> = ({selected, Icon, selectedIcon, ...props}) => {
10+
const {primary, surface} = useTheme();
11+
12+
const disabledIconColor = convertToRGBA(surface.text as ColorValue, 0.38);
13+
14+
const [iconColor, IconComponent] = selected ? [primary.background, selectedIcon ?? Icon] : [surface.textVariant, Icon];
15+
16+
return <BaseIconButton Icon={IconComponent} iconProps={{color: props.disabled ? disabledIconColor : iconColor}} {...props} />;
17+
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react';
2+
3+
import {useTheme} from '../../../theme/useTheme.hook';
4+
import {type IconButtonProps} from '../icon-button.types';
5+
import {type ColorValue} from '../../../theme/theme.types';
6+
import {convertToRGBA} from '../../../utils/convert-to-rgba';
7+
import {BaseIconButton} from '../base-icon-button/BaseIconButton.component';
8+
9+
export const TonalIconButton: React.FC<IconButtonProps> = ({selected, Icon, selectedIcon, style, ...props}) => {
10+
const {surfaceContainer, surface, secondaryContainer} = useTheme();
11+
12+
const disabledIconColor = convertToRGBA(surface.text as ColorValue, 0.38);
13+
const disabledContainerColor = convertToRGBA(surface.text as ColorValue, 0.12);
14+
15+
const [activeContainerColor, activeIconColor, IconComponent] = selected
16+
? [secondaryContainer.background, secondaryContainer.text, selectedIcon ?? Icon]
17+
: [surfaceContainer.backgroundHighest, surface.textVariant, Icon];
18+
const [appliedContainerColor, appliedIconColor] = props.disabled
19+
? [disabledContainerColor, disabledIconColor]
20+
: [activeContainerColor, activeIconColor];
21+
22+
return (
23+
<BaseIconButton style={[{backgroundColor: appliedContainerColor}, style]} Icon={IconComponent} iconProps={{color: appliedIconColor}} {...props} />
24+
);
25+
};

src/theme/theme.types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import type {ColorValue as RNColorValue} from 'react-native';
22

3-
type ColorHex = `#${string}`;
4-
type ColorRgn = `rgb(${number}, ${number}, ${number})`;
5-
type ColorRgba = `rgba(${number}, ${number}, ${number}, ${number})`;
3+
export type ColorHex = `#${string}`;
4+
export type ColorRgn = `rgb(${number}, ${number}, ${number})`;
5+
export type ColorRgba = `rgba(${number}, ${number}, ${number}, ${number})`;
66

77
export type ColorValue = ColorHex | ColorRgn | ColorRgba;
88

src/types/icon-props.type.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import {type ColorValue} from 'react-native';
2+
3+
export interface IconProps extends BaseIconProps {
4+
[key: string]: any;
5+
}
6+
7+
export interface BaseIconProps {
8+
size?: number;
9+
color?: ColorValue;
10+
}

0 commit comments

Comments
 (0)