Skip to content

Commit

Permalink
Create radio button
Browse files Browse the repository at this point in the history
  • Loading branch information
maltenzo committed Sep 22, 2022
1 parent 722675a commit 9044bee
Show file tree
Hide file tree
Showing 21 changed files with 529 additions and 9 deletions.
121 changes: 121 additions & 0 deletions docs/docs/components/radioButton.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import {RadioButton, HStack} from '@amalgama/react-native-ui-kit'
import {UIKitIcon} from '@amalgama/react-native-ui-kit/'
import CodePreview from '@site/src/components/CodePreview'
import ExampleRadioButton from '@site/src/components/ExampleRadioButton'
import {useState} from 'react'

# RadioButton

## Import

To add the `RadioButton` component to your project you can import it as follows:

```tsx
import {RadioButton} from '@amalgama/react-native-ui-kit';
```

## Examples
<CodePreview>
<ExampleRadioButton/>
</CodePreview>

## Props

### as
The icon components family to use. See [Icon - as prop documentation](./icon.md#as) for more information.
The default value is `UIKitIcon`.

```jsx
import UIKitIcon from '@amalgama/react-native-ui-kit';

<RadioButton
as={UIKitIcon}
selectedIcon="circle-filled"
unselectedIcon="circle"
onPress={() => { window && window.alert( 'Clicked!' );}}
/>
```

### selectedIcon
The name of the icon from the icon family selected to use when the button is selected. See [Icon - name prop documentation](./icon.md#name) for more information. The default value is `circle-filled`.

```jsx
import UIKitIcon from '@amalgama/react-native-ui-kit';

<RadioButton
as={UIKitIcon}
selectedIcon="circle-filled"
unselectedIcon="circle"
onPress={() => { window && window.alert( 'Clicked!' );}}
/>
```

### unselectedIcon

The name of the icon from the icon family selected to use when the button is unselected. See [Icon - name prop documentation](./icon.md#name) for more information. The default value is `circle`.

```jsx
import UIKitIcon from '@amalgama/react-native-ui-kit';

<RadioButton
as={UIKitIcon}
selectedIcon="circle-filled"
unselectedIcon="circle"
onPress={() => { window && window.alert( 'Clicked!' );}}
/>
```
### selected
If the RadioButton is selected or not.

| TYPE | REQUIRED | DEFAULT |
| ---- | -------- | ------- |
| bool | No | false |

<CodePreview>
<HStack>
<RadioButton />
<RadioButton selected />
</HStack>
</CodePreview>

### disabled
If the radioButton is disabled or not.

| TYPE | REQUIRED | DEFAULT |
| ---- | -------- | ------- |
| bool | No | false |

<CodePreview>
<HStack backgroundColor="white">
<RadioButton disabled />
<RadioButton selected disabled />
</HStack>
</CodePreview>


### onPress
Invoked when the RadioButton is pressed.

| TYPE | REQUIRED |
| -------- | -------- |
| function | No |

<CodePreview>
<RadioButton onPress={ () => { window.alert( 'The RadioButton was pressed!' ) } }/>
</CodePreview>

```jsx
<RadioButton onPress={ () => { window.alert( 'The radioButton was pressed!' ) } }/>
```

## Accessibility props
[React Native accessibility docs](https://reactnative.dev/docs/accessibility)

### accessible
Sets the component to an accessibility element. It is set by default to `true`.

### accessibilityRole
Communicates the purpose of the component. It is set by default to `"radio"`.

### accessibilityState
Describes the current state of the element. By default, indicates if the `RadioButton` is `disabled`, `selected` or `unselected`.
14 changes: 14 additions & 0 deletions docs/src/components/ExampleRadioButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { RadioButton } from '@amalgama/react-native-ui-kit';
import React, { useState } from 'react';

const ExampleRadioButton = () => {
const [ isSelected, setSelected ] = useState( false );
return (
<RadioButton
selected={ isSelected }
onPress={ () => { setSelected( prev => !prev ); } }
/>
);
};

export default ExampleRadioButton;
2 changes: 2 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ThemeProvider, VStack, extendThemeConfig } from '@amalgama/react-native
import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome';
import IoniconsIcon from 'react-native-vector-icons/Ionicons';

import RadioButtonExamples from './components/RadioButtonExamples';
import TextExamples from './components/TextExamples';
import BoxExamples from './components/BoxExamples';
import ButtonExamples from './components/ButtonExamples';
Expand Down Expand Up @@ -87,6 +88,7 @@ export default function App() {
<IconExamples />
<IconButtonExamples />
<CheckboxExamples />
<RadioButtonExamples/>
</VStack>
</ScrollView>
</SafeAreaView>
Expand Down
64 changes: 64 additions & 0 deletions example/src/components/RadioButtonExamples.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* eslint-disable no-alert */
import * as React from 'react';

import { StyleSheet, View } from 'react-native';
import {
RadioButton, VStack, Text, HStack
} from '@amalgama/react-native-ui-kit';

const styles = StyleSheet.create( {
container: {
width: '100%',
marginBottom: 20
},
separator: {
height: 1,
minWidth: '100%',
marginTop: 2,
marginBottom: 6,
backgroundColor: 'black'
},
vspace: {
height: 10,
minWidth: '100%'
}
} );

const RadioButtonExamples = () => {
const [ selected, setSelected ] = React.useState( false );
return (
<VStack style={styles.container}>
<Text variant="h1" bgColor="primary.200">RadioButton Component</Text>
<View style={styles.vspace} />
<Text variant="sh1" color="primary.800">Enabled</Text>
<View style={styles.separator} />

<HStack>
<RadioButton />
<RadioButton selected />
</HStack>

<View style={styles.vspace} />
<Text variant="sh1" color="primary.800">Disabled</Text>
<View style={styles.separator} />

<HStack>
<RadioButton disabled />
<RadioButton disabled selected />
</HStack>

<View style={styles.vspace} />
<Text variant="sh1" color="primary.800">On press</Text>
<View style={styles.separator} />

<HStack>
<RadioButton selected={selected} onPress={() => setSelected( prev => !prev )} />
</HStack>

<View style={styles.vspace} />

</VStack>
);
};

export default RadioButtonExamples;
3 changes: 3 additions & 0 deletions src/components/hooks/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default as useIsFocused } from './useIsFocused';
export { default as useIsHovered } from './useIsHovered';
export { default as useIsPressed } from './useIsPressed';
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export { default as Text } from './main/Text';
export { default as Icon } from './main/Icon';
export { default as IconButton } from './main/IconButton';
export { default as Checkbox } from './main/Checkbox';
export { default as RadioButton } from './main/RadioButton';
7 changes: 4 additions & 3 deletions src/components/main/IconButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import React from 'react';
import React, { memo, forwardRef } from 'react';
import Pressable from '../Pressable';
import Icon from '../Icon';
import { useIconButtonPropsResolver } from './hooks';
import type { IIconButtonProps } from './types';

const IconButton = ( { name, ...props }: IIconButtonProps ) => {
const IconButton = ( { name, ...props }: IIconButtonProps, ref?:any ) => {
const {
iconProps, containerProps
} = useIconButtonPropsResolver( props );

return (
<Pressable
ref={ref}
accessible
accessibilityRole='button'
accessibilityState={{ disabled: props.disabled || false }}
Expand All @@ -21,4 +22,4 @@ const IconButton = ( { name, ...props }: IIconButtonProps ) => {
);
};

export default IconButton;
export default memo( forwardRef( IconButton ) );
54 changes: 54 additions & 0 deletions src/components/main/RadioButton/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useMemo } from 'react';
import { useComponentPropsResolver } from '../../../hooks';
import type { IRadioButtonProps } from './types';
import { useIsFocused, useIsHovered, useIsPressed } from '../../hooks';
import type { IIconButtonProps } from '../IconButton/types';

interface IUseRadioButtonPropsResolverReturnType {
iconProps: IRadioButtonProps[ '__icon' ];
restProps: Omit<IIconButtonProps, '__pressed' | 'size' >;
}

const useRadioButtonPropsResolver = (
{
selectedIcon,
unselectedIcon,
...props
} : IRadioButtonProps ) : IUseRadioButtonPropsResolverReturnType => {
const { isPressed, onPressIn, onPressOut } = useIsPressed( props );
const { isHovered, onHoverIn, onHoverOut } = useIsHovered( props );
const { isFocused, onFocus, onBlur } = useIsFocused( props );

const { selected, disabled, testID } = props;
const state = useMemo( () => ( {
isDisabled: !!disabled,
isSelected: !!selected,
isPressed,
isHovered,
isFocused
} ), [ disabled, selected, isFocused, isHovered, isPressed ] );

const {
__icon: iconProps,
...restProps
} = useComponentPropsResolver( 'RadioButton', props, state ) as IIconButtonProps;
const name = ( props.selected ? selectedIcon : unselectedIcon ) as string;

const iconPropsWithTestId = { ...iconProps, testID: !!testID && `${testID}-icon` };

return {
iconProps: iconPropsWithTestId,
restProps: {
...restProps,
name,
onPressIn,
onPressOut,
onHoverIn,
onHoverOut,
onFocus,
onBlur
}
};
};

export default useRadioButtonPropsResolver;
38 changes: 38 additions & 0 deletions src/components/main/RadioButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { forwardRef, memo } from 'react';
import UIKitIcon from '../../../icons/UIKitIcon';
import IconButton from '../IconButton';
import useRadioButtonPropsResolver from './hooks';
import type { IRadioButtonProps } from './types';

const RadioButton = ( {
as = UIKitIcon,
selectedIcon = 'circle-filled',
unselectedIcon = 'circle',
selected = false,
...props
}: IRadioButtonProps, ref?: any ) => {
const { iconProps, restProps } = useRadioButtonPropsResolver( {
...props,
selectedIcon,
unselectedIcon,
selected
} );

return (
<IconButton
ref={ref}
accessible
accessibilityLabel='radio button'
accessibilityRole='radio'
accessibilityState={{
checked: selected,
disabled: !!props.disabled
}}
as={as}
__icon={iconProps}
{...restProps}
/>
);
};

export default memo( forwardRef( RadioButton ) );
11 changes: 11 additions & 0 deletions src/components/main/RadioButton/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { ComponentStyledProps } from '../../../core/components/types';
import type { IPressableProps } from '../Pressable/types';
import type { IIconProps } from '../Icon/types';

export interface IRadioButtonProps extends Omit<IPressableProps, 'children' | 'size' | 'variant' >,
ComponentStyledProps<'RadioButton'>{
selectedIcon?: string;
unselectedIcon?: string;
selected?: boolean;
size?: IIconProps['size'];
}
3 changes: 2 additions & 1 deletion src/core/components/types/common.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { StyledProps } from '../../theme/types';

export type ComponentName = 'Text' | 'Box' | 'Stack' | 'Button' | 'Pressable' | 'Icon' | 'IconButton' | 'Checkbox';
export type ComponentName = 'Text' | 'Box' | 'Stack' | 'Button' | 'Pressable' | 'Icon' | 'Checkbox'
| 'IconButton' | 'RadioButton';

export type VariantName = string;

Expand Down
5 changes: 5 additions & 0 deletions src/core/components/types/customProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ interface IconCustomProps {
interface IconButtonCustomProps {
as?: any
}
// RadioButton
interface RadioButtonCustomProps {
as?: any
}

// Stack
interface StackCustomProps {
Expand All @@ -27,6 +31,7 @@ interface StackCustomProps {
interface ComponentsCustomPropsConfig {
Icon: IconCustomProps,
IconButton: IconButtonCustomProps,
RadioButton: RadioButtonCustomProps,
Stack: StackCustomProps
}

Expand Down
5 changes: 3 additions & 2 deletions src/core/components/types/pseudoProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ interface ICheckboxPseudoProps {
// Pseudoprops config for all components
interface ComponentsPseudoPropsConfig {
Button: IButtonPseudoProps,
IconButton: IIconButtonPseudoProps
Checkbox: ICheckboxPseudoProps
Checkbox: ICheckboxPseudoProps,
IconButton: IIconButtonPseudoProps,
RadioButton: IIconButtonPseudoProps
}

// Template type to get pseudoprops for a given component
Expand Down
Loading

0 comments on commit 9044bee

Please sign in to comment.