feat: implement radio button

This commit is contained in:
jinhojang6 2023-02-28 01:38:19 +09:00
parent 0e512be105
commit 3dc8369b65
12 changed files with 227 additions and 0 deletions

View File

@ -16,6 +16,7 @@ import { IconButtonStyles } from '../IconButton/IconButton.styles'
import { LsdIconStyles } from '../Icons/LsdIcon/LsdIcon.styles'
import { ListBoxStyles } from '../ListBox/ListBox.styles'
import { QuoteStyles } from '../Quote/Quote.styles'
import { RadioButtonStyles } from '../RadioButton/RadioButton.styles'
import { TabItemStyles } from '../TabItem/TabItem.styles'
import { TabsStyles } from '../Tabs/Tabs.styles'
import { TagStyles } from '../Tag/Tag.styles'
@ -46,6 +47,7 @@ const componentStyles: Array<ReturnType<typeof withTheme> | SerializedStyles> =
QuoteStyles,
CollapseStyles,
CollapseHeaderStyles,
RadioButtonStyles,
]
export const CSSBaseline: React.FC<{ theme?: Theme }> = ({

View File

@ -0,0 +1,26 @@
import { LsdIcon } from '../LsdIcon'
export const RadioButtonFilledIcon = LsdIcon(
(props) => (
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M7.0013 1.16669C3.7813 1.16669 1.16797 3.78002 1.16797 7.00002C1.16797 10.22 3.7813 12.8334 7.0013 12.8334C10.2213 12.8334 12.8346 10.22 12.8346 7.00002C12.8346 3.78002 10.2213 1.16669 7.0013 1.16669ZM7.0013 11.6667C4.42297 11.6667 2.33464 9.57835 2.33464 7.00002C2.33464 4.42169 4.42297 2.33335 7.0013 2.33335C9.57964 2.33335 11.668 4.42169 11.668 7.00002C11.668 9.57835 9.57964 11.6667 7.0013 11.6667Z"
fill="black"
/>
<path
d="M7.0013 9.91669C8.61213 9.91669 9.91797 8.61085 9.91797 7.00002C9.91797 5.38919 8.61213 4.08335 7.0013 4.08335C5.39047 4.08335 4.08464 5.38919 4.08464 7.00002C4.08464 8.61085 5.39047 9.91669 7.0013 9.91669Z"
fill="black"
/>
</svg>
),
{
filled: true,
},
)

View File

@ -0,0 +1 @@
export * from './RadioButtonFilledIcon'

View File

@ -0,0 +1,22 @@
import { LsdIcon } from '../LsdIcon'
export const RadioButtonIcon = LsdIcon(
(props) => (
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M7.0013 1.16669C3.7813 1.16669 1.16797 3.78002 1.16797 7.00002C1.16797 10.22 3.7813 12.8334 7.0013 12.8334C10.2213 12.8334 12.8346 10.22 12.8346 7.00002C12.8346 3.78002 10.2213 1.16669 7.0013 1.16669ZM7.0013 11.6667C4.42297 11.6667 2.33464 9.57835 2.33464 7.00002C2.33464 4.42169 4.42297 2.33335 7.0013 2.33335C9.57964 2.33335 11.668 4.42169 11.668 7.00002C11.668 9.57835 9.57964 11.6667 7.0013 11.6667Z"
fill="black"
/>
</svg>
),
{
filled: true,
},
)

View File

@ -0,0 +1 @@
export * from './RadioButtonIcon'

View File

@ -17,3 +17,5 @@ export * from './NavigateNextIcon'
export * from './NewPageIcon'
export * from './SearchIcon'
export * from './PickIcon'
export * from './RadioButtonIcon'
export * from './RadioButtonFilledIcon'

View File

@ -0,0 +1,12 @@
export const radioButtonClasses = {
root: `lsd-radio-button`,
input: `lsd-radio-button__input`,
label: `lsd-radio-button__label`,
disabled: `lsd-radio-button--disabled`,
large: `lsd-radio-button--large`,
medium: `lsd-radio-button--medium`,
small: 'lsd-radio-button--small',
}

View File

@ -0,0 +1,27 @@
import { Meta, Story } from '@storybook/react'
import { RadioButton, RadioButtonProps } from './RadioButton'
export default {
title: 'RadioButton',
component: RadioButton,
argTypes: {
size: {
type: {
name: 'enum',
value: ['small', 'medium', 'large'],
},
defaultValue: 'large',
},
},
} as Meta
export const Root: Story<RadioButtonProps> = (args) => (
<RadioButton {...args}>RadioButton label</RadioButton>
)
Root.args = {
size: 'large',
disabled: false,
checked: undefined,
onChange: undefined,
}

View File

@ -0,0 +1,58 @@
import { css } from '@emotion/react'
import { radioButtonClasses } from './RadioButton.classes'
export const RadioButtonStyles = css`
.${radioButtonClasses.root} {
position: relative;
display: flex;
flex-direction: row;
align-items: center;
}
.${radioButtonClasses.input} {
opacity: 0;
position: absolute;
left: 0;
top: 0;
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
.${radioButtonClasses.root}:not(.${radioButtonClasses.disabled}) {
&:hover {
text-decoration: underline;
}
.${radioButtonClasses.input} {
cursor: pointer;
}
}
.${radioButtonClasses.disabled} {
opacity: 0.34;
}
.${radioButtonClasses.label} {
margin-left: 18px;
}
.${radioButtonClasses.large} {
.${radioButtonClasses.label} {
margin-left: 18px;
}
}
.${radioButtonClasses.medium} {
.${radioButtonClasses.label} {
margin-left: 14px;
}
}
.${radioButtonClasses.small} {
.${radioButtonClasses.label} {
margin-left: 12px;
}
}
`

View File

@ -0,0 +1,74 @@
import clsx from 'clsx'
import React, { useRef } from 'react'
import { useInput } from '../../utils/useInput'
import { RadioButtonFilledIcon, RadioButtonIcon } from '../Icons'
import { Typography } from '../Typography'
import { radioButtonClasses } from './RadioButton.classes'
export type RadioButtonProps = Omit<
React.LabelHTMLAttributes<HTMLLabelElement>,
'onChange' | 'value' | 'color'
> &
Pick<
React.InputHTMLAttributes<HTMLInputElement>,
'onChange' | 'checked' | 'defaultChecked'
> & {
disabled?: boolean
size?: 'small' | 'medium' | 'large'
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
}
export const RadioButton: React.FC<RadioButtonProps> & {
classes: typeof radioButtonClasses
} = ({
size = 'large',
onChange,
checked,
defaultChecked,
disabled = false,
inputProps = {},
children,
...props
}) => {
const ref = useRef<HTMLInputElement>(null)
const input = useInput({
value: checked,
defaultValue: defaultChecked ?? false,
onChange,
ref,
})
return (
<Typography
color="primary"
variant={size === 'large' ? 'label1' : 'label2'}
component="label"
aria-disabled={disabled ? 'true' : 'false'}
{...props}
className={clsx(
props.className,
radioButtonClasses.root,
radioButtonClasses[size],
disabled && radioButtonClasses.disabled,
)}
>
<input
ref={ref}
type="radio"
checked={input.value}
onChange={input.onChange}
defaultChecked={defaultChecked}
className={clsx(inputProps.className, radioButtonClasses.input)}
{...inputProps}
/>
{input.value ? (
<RadioButtonFilledIcon color="primary" focusable={false} />
) : (
<RadioButtonIcon color="primary" focusable={false} />
)}
<span className={radioButtonClasses.label}>{children}</span>
</Typography>
)
}
RadioButton.classes = radioButtonClasses

View File

@ -0,0 +1 @@
export * from './RadioButton'

View File

@ -18,3 +18,4 @@ export * from './components/TabItem'
export * from './components/Tabs'
export * from './components/Tag'
export * from './components/Theme'
export * from './components/RadioButton'