Skip to content

feat(components/radio): add component, add to example, add to doc, ad… #87

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: next
Choose a base branch
from
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
160 changes: 160 additions & 0 deletions apps/docs/pages/docs/v2/Components/Inputs/radio.en-US.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
---
searchable: true
---

import { CodeEditor } from '@components/code-editor';
import PropsTable from "@components/docs/props-table";

# Radio

Component to render a radio input.

## Import

```js
import { Radio, RadioGroup } from "@ficus-ui/native";
```

## Usage

### Simple radio

<CodeEditor code={`<Box>
<Radio value={1} />
<Radio value={2} defaultChecked />
<Radio value={3} colorScheme="green" />
<Radio value={4} isDisabled />
<Radio value={5} isLoading />
</Box>`} />

### Radio group

<CodeEditor code={`<RadioGroup colorScheme="red">
<Radio value={1} prefix={<Text flex={1}>Option 1</Text>} />
<Radio value={2} prefix={<Text flex={1}>Option 2</Text>} />
<Radio value={3} prefix={<Text flex={1}>Option 3</Text>} />
</RadioGroup>`} />

### Radio sizes

<CodeEditor code={`<Box>
<RadioGroup>
<Radio value={1} size="sm">
Option 1
</Radio>
<Radio value={2} size="lg">
Option 2
</Radio>
</RadioGroup>
<Radio value={3} size="lg" isLoading>
Loading option
</Radio>
</Box>`} />

### Custom radio

<CodeEditor code={`<RadioGroup colorScheme="red" flexDirection="row">
{['Option 1', 'Option 2', 'Option 3'].map((item) => (
<Radio value={item}>
{({ isChecked }) => (
<Badge
variant={isChecked ? 'solid' : 'subtle'}
colorScheme="pink"
fontSize="lg"
px="md"
py="md"
borderRadius="full"
mx="sm"
>
{item}
</Badge>
)}
</Radio>
))}
</RadioGroup>`} />

## Props

### Radio props

Extends every `Box` props.

### `colorScheme`
<PropsTable
description="The colorScheme property will define the checkbox color."
prop={{ type: "string", required: false, default: "blue" }}
/>

### `defaultChecked`
<PropsTable
description="Boolean to indicate if checkbox should be checked by default."
prop={{ type: "boolean", required: false, default: false }}
/>

### `isChecked`
<PropsTable
description="Boolean to indicate if checkbox is checked."
prop={{ type: "boolean", required: false, default: false }}
/>

### `isDisabled`
<PropsTable
description="Boolean to indicate if checkbox is disabled."
prop={{ type: "boolean", required: false, default: false }}
/>

### `isLoading`
<PropsTable
description="Boolean to indicate if checkbox should display a loader/spinner."
prop={{ type: "boolean", required: false, default: false }}
/>

### `onChecked`
<PropsTable
description="Function called when checked status changes on checkbox."
prop={{ type: "(newValue: boolean) => void", required: false }}
/>

### `icon`
<PropsTable
description="Custom icon component to replace default checkbox icon."
prop={{ type: "React.ReactNode", required: false }}
/>

### `iconColor`
<PropsTable
description="Custom icon color."
prop={{ type: "string", required: false }}
/>

### `size`
<PropsTable
description="Size of checkbox."
prop={{ type: "number | 'sm' | 'lg'", required: false }}
/>

### RadioGroup props

### `onChange`
<PropsTable
description="Function called when checked value changes."
prop={{ type: "(value: any) => void", required: false }}
/>

### `value`
<PropsTable
description="Value for the checkbox group."
prop={{ type: "any", required: false }}
/>

### `defaultValue`
<PropsTable
description="Default value for the checkbox group."
prop={{ type: "any", required: false }}
/>

### `colorScheme`
<PropsTable
description="The colorScheme property will define group checkboxes color."
prop={{ type: "string", required: false, default: "blue" }}
/>
110 changes: 110 additions & 0 deletions apps/examples/app/components-v2/Radio.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { SafeAreaView } from "react-native";
import { Badge, Box, Radio, RadioGroup, Text } from '@ficus-ui/native'
import ExampleSection from "@/src/ExampleSection";

const RadioComponent = () => {
return (
<SafeAreaView>
<Text mx="xl" fontSize="4xl">
Radio component
</Text>
<ExampleSection name="Simple radio">
<Box>
<Radio value={1} isChecked>Label</Radio>
<Radio value={2} defaultChecked>
Label
</Radio>
<Radio value={3} colorScheme="green">
Label
</Radio>
<Radio value={4} isDisabled>
Label
</Radio>
<Radio value={5} isLoading>
Label
</Radio>
</Box>
</ExampleSection>

<ExampleSection name="Simple radio group">
<RadioGroup colorScheme="red">
<Radio value={1} prefix={<Text flex={1}>Option 1</Text>}>
Label
</Radio>
<Radio value={2} prefix={<Text flex={1}>Option 2</Text>}>
Label
</Radio>
<Radio value={3} prefix={<Text flex={1}>Option 3</Text>}>
Label
</Radio>
</RadioGroup>
</ExampleSection>

<ExampleSection name="Radio sizes">
<RadioGroup>
<Radio value={1} size="sm">
Option 1
</Radio>
<Radio value={2} size="lg">
Option 2
</Radio>
</RadioGroup>
<Radio value={3} size="lg" isLoading>
Loading option
</Radio>
</ExampleSection>

<ExampleSection name="Custom radio">
<RadioGroup colorScheme="red" flexDirection="row">
<Radio value={1}>
{({ isChecked }) => (
<Badge
variant={isChecked ? "solid" : "subtle"}
colorScheme="pink"
fontSize="xl"
px="lg"
py="lg"
borderRadius="full"
mx="sm"
>
Option 1
</Badge>
)}
</Radio>
<Radio value={2}>
{({ isChecked }) => (
<Badge
variant={isChecked ? "solid" : "subtle"}
colorScheme="pink"
fontSize="xl"
px="lg"
py="lg"
borderRadius="full"
mx="sm"
>
Option 2
</Badge>
)}
</Radio>
<Radio value={3}>
{({ isChecked }) => (
<Badge
variant={isChecked ? "solid" : "subtle"}
colorScheme="pink"
fontSize="xl"
px="lg"
py="lg"
borderRadius="full"
mx="sm"
>
Option 3
</Badge>
)}
</Radio>
</RadioGroup>
</ExampleSection>
</SafeAreaView>
);
};

export default RadioComponent;
2 changes: 2 additions & 0 deletions apps/examples/app/items-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import TouchableHighlightComponent from './components-v2/TouchableHighlight';
import TouchableOpacityComponent from './components-v2/TouchableOpacity';
import TouchableWithoutFeedbackComponent from './components-v2/TouchableWithoutFeedback';
import PressableComponent from './components-v2/Pressable';
import RadioComponent from '@/app/components-v2/Radio';

type ExampleComponentType = {
onScreenName: string;
Expand All @@ -31,4 +32,5 @@ export const components: ExampleComponentType[] = [
{ navigationPath: 'TouchableOpacity', onScreenName: 'TouchableOpacity', component: TouchableOpacityComponent },
{ navigationPath: 'TouchableWithoutFeedback', onScreenName: 'TouchableWithoutFeedback', component: TouchableWithoutFeedbackComponent },
{ navigationPath: 'Pressable', onScreenName: 'Pressable', component: PressableComponent },
{ navigationPath: 'Radio', onScreenName: 'Radio', component: RadioComponent },
]
1 change: 1 addition & 0 deletions packages/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ export * from './center';
export * from './badge';
export * from './touchables';
export * from './pressable';
export * from './radio';

export { ThemeProvider } from '@ficus-ui/theme';
62 changes: 62 additions & 0 deletions packages/components/src/radio/group.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import * as React from 'react';
import { useState } from 'react';

import { type NativeFicusProps, ficus, forwardRef } from '../system';
import { RadioOptions } from './radio';

export interface RadioProps
extends Omit<NativeFicusProps<'View'>, 'children'>,
RadioOptions {}

export const RadioGroup = forwardRef<RadioProps, 'View'>(
function Radio(props, ref) {
const [value, setValue] = useState(
props.value ?? props.defaultValue ?? null
);
const {
children,
onChange: onChangeProp,
value: propsValue,
colorScheme,
...rest
} = props;

/**
* checks if checked value is already in the state or not,
* if it, remove it else add it
*
* @param value
*/
const onChange = (optionValue: any) => {
if (!('value' in props)) {
setValue(optionValue);
}

if (onChangeProp) {
onChangeProp(optionValue);
}
};

/**
* clones the children and add isChecked, onChange prop
*/
const renderChildren = () => {
return React.Children.map(
children as any,
(child: React.ReactElement) => {
return React.cloneElement(child, {
onChange,
isChecked: value === child.props.value,
...(colorScheme ? { colorScheme } : {}),
});
}
);
};

return (
<ficus.View ref={ref} {...rest}>
{renderChildren()}
</ficus.View>
);
}
);
2 changes: 2 additions & 0 deletions packages/components/src/radio/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Radio } from './radio';
export { RadioGroup } from './group';
Loading
Loading