Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 20 additions & 14 deletions src/components/ToggleButton/ToggleButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import color from 'color';

import { ToggleButtonGroupContext } from './ToggleButtonGroup';
import type { ToggleButtonContextType } from './ToggleButtonGroup';
import { getToggleButtonColor } from './utils';
import { useInternalTheme } from '../../core/theming';
import { black, white } from '../../styles/themes/v2/colors';
Expand All @@ -20,7 +21,7 @@ import { forwardRef } from '../../utils/forwardRef';
import type { IconSource } from '../Icon';
import IconButton from '../IconButton/IconButton';

export type Props = {
export type Props<Value = string> = {
/**
* Icon to display for the `ToggleButton`.
*/
Expand Down Expand Up @@ -48,11 +49,11 @@ export type Props = {
/**
* Function to execute on press.
*/
onPress?: (value?: GestureResponderEvent | string) => void;
onPress?: (value?: GestureResponderEvent | Value) => void;
/**
* Value of button.
*/
value?: string;
value?: Value;
/**
* Status of button.
*/
Expand All @@ -69,6 +70,12 @@ export type Props = {
testID?: string;
};

// React.forwardRef doesn't preserve generic type parameters, causing type inference issues
// Define a generic function type to maintain proper TypeScript typing for <Value>
type ToggleButtonComponent = <Value = string>(
props: Props<Value> & { ref?: React.Ref<View> }
) => React.ReactElement;

/**
* Toggle buttons can be used to group related options. To emphasize groups of related toggle buttons,
* a group should share a common container.
Expand Down Expand Up @@ -99,8 +106,9 @@ export type Props = {
*
* ```
*/
const ToggleButton = forwardRef<View, Props>(
(

const ToggleButton = forwardRef(
<Value = string,>(
{
icon,
size,
Expand All @@ -113,18 +121,16 @@ const ToggleButton = forwardRef<View, Props>(
onPress,
rippleColor,
...rest
}: Props,
ref
}: Props<Value>,
ref: React.ForwardedRef<View>
) => {
const theme = useInternalTheme(themeOverrides);
const borderRadius = theme.roundness;

return (
<ToggleButtonGroupContext.Consumer>
{(
context: { value: string | null; onValueChange: Function } | null
) => {
const checked: boolean | null =
{(context: ToggleButtonContextType<Value> | null) => {
const checked: boolean =
(context && context.value === value) || status === 'checked';

const backgroundColor = getToggleButtonColor({ theme, checked });
Expand All @@ -139,13 +145,13 @@ const ToggleButton = forwardRef<View, Props>(
<IconButton
borderless={false}
icon={icon}
onPress={(e?: GestureResponderEvent | string) => {
onPress={(e?: GestureResponderEvent) => {
if (onPress) {
onPress(e);
}

if (context) {
context.onValueChange(!checked ? value : null);
context.onValueChange(!checked ? value ?? null : null);
}
}}
size={size}
Expand All @@ -171,7 +177,7 @@ const ToggleButton = forwardRef<View, Props>(
</ToggleButtonGroupContext.Consumer>
);
}
);
) as ToggleButtonComponent;

const styles = StyleSheet.create({
content: {
Expand Down
4 changes: 2 additions & 2 deletions src/components/ToggleButton/ToggleButtonGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export type Props<Value = string> = {
children: React.ReactNode;
};

type ToggleButtonContextType<Value> = {
export type ToggleButtonContextType<Value> = {
value: Value | null;
onValueChange: (item: Value) => void;
onValueChange: (item: Value | null) => void;
};

export const ToggleButtonGroupContext =
Expand Down
13 changes: 9 additions & 4 deletions src/components/ToggleButton/ToggleButtonRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import { StyleSheet, View, StyleProp, ViewStyle } from 'react-native';
import ToggleButton from './ToggleButton';
import ToggleButtonGroup from './ToggleButtonGroup';

export type Props = {
export type Props<Value = string> = {
/**
* Function to execute on selection change.
*/
onValueChange: (value: string) => void;
onValueChange: (value: Value) => void;
/**
* Value of the currently selected toggle button.
*/
value: string;
value: Value;
/**
* React elements containing toggle buttons.
*/
Expand Down Expand Up @@ -43,7 +43,12 @@ export type Props = {
*
*```
*/
const ToggleButtonRow = ({ value, onValueChange, children, style }: Props) => {
const ToggleButtonRow = <Value = string,>({
value,
onValueChange,
children,
style,
}: Props<Value>) => {
const count = React.Children.count(children);

return (
Expand Down