generated from timelessco/react-components-template
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(radio): added radio component (#45)
* feat(radio): added initial radio styles * feat(radio): radio with tailwind forms (#46) * chore(radio): radio with tailwind forms * chore(radio): added disabled state styles * chore: purge fix * chore: added controllable state * chore: addComponent for radio styles * chore(radio): added RadioLabel * chore(radio): radio label improvements * chore: remove css file * chore: changed spinner types to getThemeValue * chore: added Box in radio label * feat(radio): added size prop * fix(radio): fix radio state context * chore: radio types cleanup * feat(radio): added radio v2 (#49) * feat(radio): migrate radio to use conditional rendering * refactor(radio): added size support and refactored all types * chore: radio controlled state * chore: review updates * fix(radio): fixed radio controlled state * fix(radio): fixed radio controlled state * refactor: rearrange imports * refactor(radio): added radio icons with css * Revert "refactor(radio): added radio icons with css" This reverts commit 5572582. * refactor(radio): minor updates * feat(radio): added icon props in radio * chore: refactor & remove old code
- Loading branch information
1 parent
67c9498
commit a341146
Showing
14 changed files
with
887 additions
and
390 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import * as React from "react"; | ||
import { createIcon } from "../icon"; | ||
|
||
export const RadioCheckedIcon = createIcon({ | ||
displayName: "RadioChecked", | ||
viewBox: "0 0 16 16", | ||
path: ( | ||
<> | ||
<circle cx="8" cy="8" r="8" fill="currentColor" /> | ||
<circle cx="8" cy="8" r="3" fill="white" /> | ||
</> | ||
), | ||
}); | ||
|
||
export const RadioUncheckedIcon = createIcon({ | ||
displayName: "RadioUnchecked", | ||
viewBox: "0 0 16 16", | ||
path: ( | ||
<> | ||
<circle | ||
cx="8" | ||
cy="8" | ||
r="7" | ||
fill="white" | ||
stroke="currentColor" | ||
strokeWidth="1.5" | ||
/> | ||
</> | ||
), | ||
}); | ||
|
||
export const RadioDisabledIcon = createIcon({ | ||
displayName: "RadioDisabled", | ||
viewBox: "0 0 16 16", | ||
path: ( | ||
<> | ||
<circle cx="8" cy="8" r="8" fill="#E4E4E7" /> | ||
<circle cx="8" cy="8" r="3" fill="currentColor" /> | ||
</> | ||
), | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import React from "react"; | ||
import { | ||
RadioHTMLProps, | ||
Radio as ReakitRadio, | ||
RadioProps as ReakitRadioProps, | ||
} from "reakit"; | ||
import { cx } from "@renderlesskit/react"; | ||
|
||
import { useTheme } from "../theme"; | ||
import { RadioIcon } from "./RadioIcon"; | ||
import { useRadioContext } from "./RadioGroup"; | ||
import { forwardRefWithAs } from "../utils/types"; | ||
|
||
export type RadioCommonProps = Partial< | ||
Pick<ReakitRadioProps, "value" | "disabled"> | ||
> & { | ||
size?: keyof Renderlesskit.GetThemeValue<"radio", "icon">["size"]; | ||
}; | ||
|
||
export const RadioInput: React.FC<RadioHTMLProps & RadioCommonProps> = ({ | ||
className, | ||
...rest | ||
}) => { | ||
const theme = useTheme(); | ||
const { radioState } = useRadioContext(); | ||
|
||
const radioStyles = cx(theme.radio.input, className); | ||
|
||
return <ReakitRadio className={radioStyles} {...radioState} {...rest} />; | ||
}; | ||
|
||
export const Radio = forwardRefWithAs< | ||
RadioHTMLProps & | ||
RadioCommonProps & { | ||
checkedIcon?: React.ReactNode; | ||
uncheckedIcon?: React.ReactNode; | ||
disabledIcon?: React.ReactNode; | ||
}, | ||
HTMLInputElement, | ||
"input" | ||
>((props, ref) => { | ||
const { checkedIcon, uncheckedIcon, disabledIcon } = props; | ||
return ( | ||
<> | ||
<RadioInput ref={ref} {...props} /> | ||
<RadioIcon | ||
value={props.value} | ||
disabled={props.disabled} | ||
checkedIcon={checkedIcon} | ||
uncheckedIcon={uncheckedIcon} | ||
disabledIcon={disabledIcon} | ||
/> | ||
</> | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import React from "react"; | ||
import { RadioInitialState, RadioStateReturn } from "reakit"; | ||
|
||
import { createContext } from "../utils"; | ||
import { RadioCommonProps } from "./Radio"; | ||
import { useRadioState } from "./useRadioState"; | ||
|
||
type RadioContextType = { | ||
radioState?: RadioStateReturn; | ||
radioSize?: RadioCommonProps["size"]; | ||
}; | ||
|
||
const [RadioProvider, useRadioContext] = createContext<RadioContextType>({ | ||
errorMessage: "Radio must be used within RadioProvider", | ||
name: "RadioContext", | ||
strict: true, | ||
}); | ||
|
||
export { RadioProvider, useRadioContext }; | ||
|
||
export type RadioGroupProps = RadioInitialState & | ||
Pick<RadioCommonProps, "size"> & { | ||
onStateChange?: (state: RadioCommonProps["value"]) => void; | ||
state?: RadioCommonProps["value"]; | ||
defaultState?: RadioCommonProps["value"]; | ||
}; | ||
|
||
export const RadioGroup: React.FC<RadioGroupProps> = ({ | ||
children, | ||
size = "sm", | ||
...props | ||
}) => { | ||
const radioState = useRadioState(props); | ||
|
||
return ( | ||
<RadioProvider value={{ radioState: radioState, radioSize: size }}> | ||
{children} | ||
</RadioProvider> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import React from "react"; | ||
import { cx } from "@renderlesskit/react"; | ||
import { Box, BoxProps, RadioState } from "reakit"; | ||
|
||
import { | ||
RadioCheckedIcon, | ||
RadioDisabledIcon, | ||
RadioUncheckedIcon, | ||
} from "../icons/RadioIcons"; | ||
import { useTheme } from ".."; | ||
import { RadioCommonProps } from "./Radio"; | ||
import { useRadioContext } from "./RadioGroup"; | ||
import { forwardRefWithAs } from "../utils/types"; | ||
|
||
export type RadioIconProps = BoxProps & | ||
RadioState & | ||
RadioCommonProps & { | ||
checkedIcon?: React.ReactNode; | ||
uncheckedIcon?: React.ReactNode; | ||
disabledIcon?: React.ReactNode; | ||
}; | ||
|
||
export const RadioIcon = forwardRefWithAs< | ||
Partial<RadioIconProps>, | ||
HTMLDivElement, | ||
"div" | ||
>((props, ref) => { | ||
const { radioState, radioSize } = useRadioContext(); | ||
const { value, size, disabled, ...mainProps } = props; | ||
const { className, children, ...rest } = mainProps; | ||
|
||
const _size = size || radioSize || "sm"; | ||
const stateProp = radioState?.state === value; | ||
|
||
const theme = useTheme(); | ||
const radioIconStyles = cx( | ||
theme.radio.icon.base, | ||
theme.radio.icon.size[_size], | ||
disabled | ||
? theme.radio.icon.disabled | ||
: stateProp | ||
? theme.radio.icon.checked | ||
: theme.radio.icon.unchecked, | ||
className, | ||
); | ||
|
||
const iconMap = { | ||
checked: props.checkedIcon || <RadioCheckedIcon />, | ||
unchecked: props.uncheckedIcon || <RadioUncheckedIcon />, | ||
disabled: props.disabledIcon || <RadioDisabledIcon />, | ||
}; | ||
|
||
return ( | ||
<Box | ||
ref={ref} | ||
role="img" | ||
aria-hidden="true" | ||
className={radioIconStyles} | ||
{...rest} | ||
> | ||
{children | ||
? children | ||
: disabled | ||
? iconMap.disabled | ||
: stateProp | ||
? iconMap.checked | ||
: iconMap.unchecked} | ||
</Box> | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import React from "react"; | ||
import { BoxProps } from "reakit"; | ||
import { cx } from "@renderlesskit/react"; | ||
|
||
import { Box } from "../box"; | ||
import { useTheme } from ".."; | ||
import { RadioCommonProps } from "./Radio"; | ||
import { useRadioContext } from "./RadioGroup"; | ||
import { forwardRefWithAs } from "../utils/types"; | ||
|
||
export type RadioLabelProps = BoxProps & Omit<RadioCommonProps, "value">; | ||
|
||
export const RadioLabel = forwardRefWithAs< | ||
RadioLabelProps, | ||
HTMLLabelElement, | ||
"label" | ||
>((props, ref) => { | ||
const { size, disabled = false, ...mainProps } = props; | ||
const { className, ...rest } = mainProps; | ||
const theme = useTheme(); | ||
const { radioSize } = useRadioContext(); | ||
const _size = size || radioSize || "sm"; | ||
|
||
const radioStyles = cx( | ||
theme.radio.base, | ||
theme.radio.label.base, | ||
theme.radio.label.size[_size], | ||
disabled ? theme.radio.disabled : "", | ||
className, | ||
); | ||
|
||
return <Box as="label" ref={ref} className={radioStyles} {...rest} />; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export * from "./Radio"; | ||
export * from "./RadioIcon"; | ||
export * from "./RadioLabel"; | ||
export * from "./RadioGroup"; | ||
export * from "./useRadioState"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import React from "react"; | ||
import { Meta } from "@storybook/react"; | ||
|
||
import { Button } from "../../button"; | ||
import { | ||
storyTemplate, | ||
createUnionControl, | ||
} from "../../../.storybook/storybookUtils"; | ||
import { | ||
RadioIcon, | ||
RadioInput, | ||
RadioGroup, | ||
RadioLabel, | ||
Radio, | ||
RadioGroupProps, | ||
} from "../index"; | ||
import { WheelIcon } from "../../icons"; | ||
import { InfoCircle } from "../../icon/stories/Icon.stories"; | ||
|
||
export default { | ||
title: "Radio", | ||
component: Radio, | ||
argTypes: { | ||
size: createUnionControl(["xs", "sm", "lg"]), | ||
}, | ||
} as Meta; | ||
|
||
const base = storyTemplate<RadioGroupProps>( | ||
args => { | ||
return ( | ||
<RadioGroup {...args}> | ||
<div className="flex gap-3"> | ||
<RadioLabel> | ||
<Radio value="1" /> | ||
label 1 | ||
</RadioLabel> | ||
|
||
<RadioLabel> | ||
<Radio value="2" /> | ||
label 2 | ||
</RadioLabel> | ||
</div> | ||
</RadioGroup> | ||
); | ||
}, | ||
{ | ||
defaultState: "2", | ||
size: "sm", | ||
}, | ||
); | ||
|
||
export const Default = base({}); | ||
|
||
export const States = () => { | ||
return ( | ||
<RadioGroup defaultState={"2"}> | ||
<div className="flex flex-col gap-2"> | ||
<RadioLabel className="hover:bg-gray-100 p-2 rounded-md"> | ||
<Radio value="1" /> | ||
Unchecked | ||
</RadioLabel> | ||
<RadioLabel className="hover:bg-gray-100 p-2 rounded-md"> | ||
<Radio value="2" /> | ||
Checked | ||
</RadioLabel> | ||
<RadioLabel className="hover:bg-gray-100 p-2 rounded-md"> | ||
<Radio value="3" disabled /> | ||
Disabled | ||
</RadioLabel> | ||
</div> | ||
</RadioGroup> | ||
); | ||
}; | ||
|
||
export const Controlled = () => { | ||
const [state, setState] = React.useState("1"); | ||
return ( | ||
<> | ||
<RadioGroup state={state} onStateChange={e => setState(e as string)}> | ||
<div className="flex flex-col gap-2"> | ||
<RadioLabel className="hover:bg-gray-100 p-2 rounded-md"> | ||
<Radio value="1" /> | ||
Unchecked | ||
</RadioLabel> | ||
<RadioLabel className="hover:bg-gray-100 p-2 rounded-md"> | ||
<Radio value="2" /> | ||
Checked | ||
</RadioLabel> | ||
<RadioLabel className="hover:bg-gray-100 p-2 rounded-md"> | ||
<Radio value="3" /> | ||
Disabled | ||
</RadioLabel> | ||
</div> | ||
</RadioGroup> | ||
<Button onClick={() => setState("2")}>change</Button> | ||
</> | ||
); | ||
}; | ||
|
||
export const CustomIcon = () => { | ||
const [state, setState] = React.useState("1"); | ||
return ( | ||
<> | ||
<RadioGroup state={state} onStateChange={e => setState(e as string)}> | ||
<div className="flex flex-col gap-2"> | ||
<RadioLabel className="hover:bg-gray-100 p-2 rounded-md"> | ||
<RadioInput value="1" /> | ||
<RadioIcon | ||
value="1" | ||
checkedIcon={<WheelIcon />} | ||
uncheckedIcon={<InfoCircle />} | ||
/> | ||
Two | ||
</RadioLabel> | ||
<RadioLabel className="hover:bg-gray-100 p-2 rounded-md"> | ||
<RadioInput value="2" /> | ||
<RadioIcon | ||
value="2" | ||
checkedIcon={<WheelIcon />} | ||
uncheckedIcon={<InfoCircle />} | ||
/> | ||
Two | ||
</RadioLabel> | ||
</div> | ||
</RadioGroup> | ||
<Button onClick={() => setState("2")}>change</Button> | ||
</> | ||
); | ||
}; |
Oops, something went wrong.
a341146
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs: