Skip to content

Commit 5dd0cef

Browse files
chore(buttons): added disabled styles for segmented button
1 parent b697eee commit 5dd0cef

File tree

2 files changed

+26
-16
lines changed

2 files changed

+26
-16
lines changed

src/buttons/segmented-button/SegmentedButton.component.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import React, {useCallback, useMemo, type ReactElement} from 'react';
12
import {View, type ViewProps, type ColorValue, type StyleProp, type TextStyle} from 'react-native';
2-
import React, {useCallback, type ReactElement} from 'react';
33

44
import {styles} from './segmented-button.styles';
55
import {useTheme} from '../../theme/useTheme.hook';
66
import {type IconProps} from '../../icons/icon-props';
7+
import {convertToRGBA} from '../../utils/convert-to-rgba';
78
import {ButtonSegment as ButtonSegmentComponent} from './button-segment/ButtonSegment.component';
89

910
export interface ButtonSegment<T> {
@@ -17,6 +18,7 @@ export interface SegmentedButtonProps<T> extends ViewProps {
1718
segments: ButtonSegment<T>[];
1819
selected: T[];
1920

21+
disabled?: boolean;
2022
multiSelectionEnabled?: boolean;
2123
withCheckmark?: boolean;
2224
iconSize?: number;
@@ -30,6 +32,7 @@ export interface SegmentedButtonProps<T> extends ViewProps {
3032
export const SegmentedButton: <T extends any>(props: SegmentedButtonProps<T>) => ReactElement = ({
3133
segments,
3234
selected,
35+
disabled = false,
3336
multiSelectionEnabled = false,
3437
onSegmentPress,
3538
style,
@@ -42,13 +45,16 @@ export const SegmentedButton: <T extends any>(props: SegmentedButtonProps<T>) =>
4245
}) => {
4346
const {outline} = useTheme();
4447

48+
const borderColor = useMemo(() => (disabled ? convertToRGBA(outline as string, 0.12) : outline), [disabled]);
49+
4550
const renderButtonSegment = useCallback(
4651
(segment, index) => (
4752
<ButtonSegmentComponent
4853
key={segment.value}
49-
style={{borderLeftWidth: Number(Boolean(index))}}
54+
style={{borderLeftWidth: Number(Boolean(index)), borderLeftColor: borderColor}}
5055
selected={selected.includes(segment.value)}
5156
onSegmentPress={onSegmentPress}
57+
disabled={disabled}
5258
multiSelectionEnabled={multiSelectionEnabled}
5359
withCheckmark={withCheckmark}
5460
labelStyle={labelStyle}
@@ -58,11 +64,11 @@ export const SegmentedButton: <T extends any>(props: SegmentedButtonProps<T>) =>
5864
{...segment}
5965
/>
6066
),
61-
[selected, withCheckmark, labelStyle, iconColor, iconSize, rippleColor, multiSelectionEnabled, onSegmentPress]
67+
[selected, withCheckmark, disabled, borderColor, labelStyle, iconColor, iconSize, rippleColor, multiSelectionEnabled, onSegmentPress]
6268
);
6369

6470
return (
65-
<View style={[styles.container, {borderColor: outline}, style]} {...props}>
71+
<View style={[styles.container, {borderColor}, style]} {...props}>
6672
{segments.map(renderButtonSegment)}
6773
</View>
6874
);

src/buttons/segmented-button/button-segment/ButtonSegment.component.tsx

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {useEffect} from 'react';
1+
import React, {useEffect, useMemo} from 'react';
22
import {Pressable, type PressableProps, type StyleProp, type ViewStyle, type TextStyle, type ColorValue} from 'react-native';
33
import Animated, {
44
FadeIn,
@@ -14,12 +14,14 @@ import Animated, {
1414
import {styles} from './button-segment.styles';
1515
import {useTheme} from '../../../theme/useTheme.hook';
1616
import {type IconProps} from '../../../icons/icon-props';
17+
import {convertToRGBA} from '../../../utils/convert-to-rgba';
1718
import {useTypography} from '../../../typography/useTypography.component';
1819
import {AnimatedSelectedIcon} from './animated-selected-icon/AnimatedSelectedIcon.component';
1920

2021
interface ButtonSegmentProps<T> extends Omit<PressableProps, 'onPress'> {
2122
value: T;
2223
selected: boolean;
24+
disabled: boolean;
2325
multiSelectionEnabled: boolean;
2426

2527
label?: string;
@@ -40,6 +42,7 @@ export const ButtonSegment = React.memo(
4042
<T extends any>({
4143
value,
4244
selected,
45+
disabled,
4346
Icon,
4447
label,
4548
multiSelectionEnabled,
@@ -56,16 +59,20 @@ export const ButtonSegment = React.memo(
5659
const {surface, secondaryContainer} = useTheme();
5760

5861
const fill = useSharedValue(Number(selected));
62+
const labelDisabledColor = useMemo(() => convertToRGBA(surface.text as string, 0.38), []);
63+
64+
const defaultIconColor = selected ? secondaryContainer.text : iconColor ?? surface.text;
65+
const appliedIconColor = disabled ? labelDisabledColor : defaultIconColor;
5966

6067
useEffect(() => {
6168
fill.value = withTiming(Number(selected));
6269
}, [selected]);
6370

6471
const animatedLabelStyle = useAnimatedStyle(
6572
() => ({
66-
color: interpolateColor(fill.value, [0, 1], [surface.text as string, secondaryContainer.text as string]),
73+
color: disabled ? labelDisabledColor : interpolateColor(fill.value, [0, 1], [surface.text as string, secondaryContainer.text as string]),
6774
}),
68-
[]
75+
[disabled]
6976
);
7077

7178
const circleAnimatedStyle = useAnimatedStyle(() => {
@@ -91,25 +98,22 @@ export const ButtonSegment = React.memo(
9198
});
9299
};
93100

94-
const renderIconConditionally = () => {
95-
const defaultIconColor = selected ? secondaryContainer.text : surface.text;
96-
97-
return Icon ? (
101+
const renderIconConditionally = () =>
102+
Icon ? (
98103
<Animated.View layout={LinearTransition} entering={FadeIn} exiting={FadeOut}>
99-
<Icon size={iconSize} color={iconColor ?? defaultIconColor} />
104+
<Icon size={iconSize} color={appliedIconColor} />
100105
</Animated.View>
101106
) : null;
102-
};
103107

104108
return (
105-
<Pressable style={[styles.container, style]} {...props} onPress={handleSegmentPress}>
109+
<Pressable style={[styles.container, style]} disabled={disabled} {...props} onPress={handleSegmentPress}>
106110
<Animated.View style={[styles.ripple, {backgroundColor: rippleColor ?? secondaryContainer.background}, circleAnimatedStyle]} />
107111
{withCheckmark && selected ? (
108112
<Animated.View layout={LinearTransition} entering={FadeIn}>
109-
<AnimatedSelectedIcon width={iconSize} height={iconSize} strokeWidth={2} stroke={secondaryContainer.text} />
113+
<AnimatedSelectedIcon width={iconSize} height={iconSize} strokeWidth={2} stroke={appliedIconColor} />
110114
</Animated.View>
111115
) : null}
112-
{Icon && withCheckmark && selected ? null : renderIconConditionally()}
116+
{Icon && withCheckmark && label && selected ? null : renderIconConditionally()}
113117
{label ? (
114118
<Animated.Text layout={LinearTransition} style={[labelLarge, animatedLabelStyle, labelStyle]}>
115119
{label}

0 commit comments

Comments
 (0)