-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: remove old radio button and components
- Loading branch information
1 parent
daa77ce
commit aba634d
Showing
11 changed files
with
0 additions
and
470 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,143 +0,0 @@ | ||
import type { SerializedStyles } from '@emotion/react'; | ||
import { css } from '@emotion/react'; | ||
import type { Theme } from 'theme'; | ||
import { BASE_SHADE } from 'theme/palette'; | ||
import type { ColorScheme } from 'theme/types'; | ||
import { rem } from 'theme/utils'; | ||
|
||
import type { RadioProps } from './Radio'; | ||
|
||
const lightHoverColor = 'rgba(23, 91, 245, 0.07)'; | ||
const darkHoverColor = 'rgba(255, 255, 255, 0.1)'; | ||
|
||
const boxShadow = ({ colorScheme }: { colorScheme: ColorScheme }) => css` | ||
box-shadow: 0 0 0 ${rem('6px')} ${colorScheme === 'dark' ? darkHoverColor : lightHoverColor}, | ||
inset 0 0 0 ${rem('12px')} ${colorScheme === 'dark' ? darkHoverColor : lightHoverColor}; | ||
`; | ||
|
||
export const inputStyles: SerializedStyles = css` | ||
top: 0; | ||
left: 0; | ||
width: 100%; | ||
cursor: inherit; | ||
height: 100%; | ||
margin: 0; | ||
padding: 0; | ||
z-index: 1; | ||
position: absolute; | ||
opacity: 0; | ||
&:disabled { | ||
cursor: default; | ||
} | ||
`; | ||
|
||
export const customRadioInnerHover = | ||
(isFocused: boolean, isDisabled: boolean) => | ||
(theme: Theme): SerializedStyles => | ||
css` | ||
position: absolute; | ||
border-radius: 50%; | ||
width: ${rem('24px')}; | ||
height: ${rem('24px')}; | ||
transition: all 0.2s ease; | ||
${isFocused && !isDisabled && boxShadow({ colorScheme: theme.colorScheme })}; | ||
`; | ||
|
||
export const customRadioWrapperStyles = | ||
(isFocused: boolean, isDisabled: boolean) => | ||
(theme: Theme): SerializedStyles => | ||
css` | ||
position: relative; | ||
border-radius: 50%; | ||
width: ${rem('24px')}; | ||
height: ${rem('24px')}; | ||
transition: box-shadow 0.3s ease; | ||
${isFocused && !isDisabled && boxShadow({ colorScheme: theme.colorScheme })}; | ||
`; | ||
|
||
const determineColorBasedOnState = | ||
({ | ||
isChecked, | ||
isDisabled, | ||
isFilled, | ||
}: Pick<RadioProps, 'isChecked' | 'isDisabled' | 'isFilled'>) => | ||
(theme: Theme) => { | ||
if (isChecked) { | ||
return `currentColor`; | ||
} | ||
if (isDisabled) { | ||
return `${theme.utils.getColor('lightGrey', 250)}`; | ||
} | ||
if (isFilled) { | ||
return `${theme.utils.getColor('lightGrey', 300)}`; | ||
} | ||
|
||
return `${theme.utils.getColor('lightGrey', 300)}`; | ||
}; | ||
|
||
export const customRadioStyles = | ||
(props: Pick<RadioProps, 'isChecked' | 'isDisabled' | 'isFilled'>) => | ||
(theme: Theme): SerializedStyles => { | ||
return css` | ||
transition: all 0.2s ease; | ||
border-radius: 50%; | ||
width: 100%; | ||
height: 100%; | ||
box-sizing: border-box; | ||
position: absolute; | ||
&:before { | ||
content: ''; | ||
display: inline-block; | ||
box-sizing: border-box; | ||
margin: ${rem('2px')} ${rem('12px')} ${rem('2px')} ${rem('2px')}; | ||
border: solid 2px ${determineColorBasedOnState(props)(theme)}; | ||
border-radius: 50%; | ||
width: ${rem('20px')}; | ||
height: ${rem('20px')}; | ||
vertical-align: top; | ||
transition: border-color 0.2s; | ||
} | ||
&:after { | ||
content: ''; | ||
display: block; | ||
position: absolute; | ||
top: ${rem('1px')}; | ||
left: ${rem('1px')}; | ||
border-radius: 50%; | ||
width: ${rem('12px')}; | ||
height: ${rem('12px')}; | ||
background-color: ${determineColorBasedOnState(props)(theme)}; | ||
transform: translate(5px, 5px) scale(${props.isChecked ? '1' : '0'}); | ||
transition: transform 0.2s; | ||
} | ||
`; | ||
}; | ||
|
||
export const wrapperStyles = | ||
(isDisabled: boolean) => | ||
(theme: Theme): SerializedStyles => | ||
css` | ||
position: relative; | ||
border-radius: 50%; | ||
width: ${rem('36px')}; | ||
height: ${rem('36px')}; | ||
color: ${theme.utils.getColor('primary', BASE_SHADE, 'normal')}; | ||
border: 0; | ||
opacity: ${isDisabled ? 0.5 : 1}; | ||
cursor: pointer; | ||
margin: 0; | ||
display: inline-flex; | ||
outline: 0; | ||
align-items: center; | ||
user-select: none; | ||
vertical-align: middle; | ||
-moz-appearance: none; | ||
justify-content: center; | ||
text-decoration: none; | ||
-webkit-appearance: none; | ||
-webkit-tap-highlight-color: transparent; | ||
`; | ||
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 |
---|---|---|
@@ -1,43 +0,0 @@ | ||
import React from 'react'; | ||
import { render } from 'test'; | ||
|
||
import { fireEvent } from '../../test'; | ||
import Radio from './Radio'; | ||
import { Mock } from 'vitest'; | ||
|
||
describe('Radio', () => { | ||
let mockOnClick: Mock<any, any>; | ||
|
||
beforeEach(() => { | ||
mockOnClick = vi.fn(); | ||
}); | ||
|
||
it('should render correctly', () => { | ||
const { container } = render(<Radio />); | ||
expect(container).toMatchSnapshot(); | ||
}); | ||
|
||
it('should change to checked on click', () => { | ||
const { container } = render(<Radio onChange={mockOnClick} dataTestId={'test-check'} />); | ||
|
||
const radio = container.querySelector('input[type="radio"]') as HTMLInputElement; | ||
|
||
fireEvent.click(radio); | ||
|
||
expect(mockOnClick).toHaveBeenCalledTimes(1); | ||
expect(radio.checked).toBeTruthy(); | ||
}); | ||
|
||
it('disabled should not change to checked on click', () => { | ||
const { container } = render( | ||
<Radio isDisabled={true} onChange={mockOnClick} dataTestId={'test-disabled'} /> | ||
); | ||
|
||
const radio = container.querySelector('input[type="radio"]') as HTMLInputElement; | ||
|
||
fireEvent.click(radio); | ||
|
||
expect(mockOnClick).toHaveBeenCalledTimes(0); | ||
expect(radio.checked).toBeFalsy(); | ||
}); | ||
}); | ||
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 |
---|---|---|
@@ -1,135 +0,0 @@ | ||
import * as React from 'react'; | ||
|
||
import { | ||
customRadioInnerHover, | ||
customRadioStyles, | ||
customRadioWrapperStyles, | ||
inputStyles, | ||
wrapperStyles, | ||
} from './Radio.style'; | ||
import useTheme from '../../hooks/useTheme'; | ||
import { generateTestDataId } from '../../utils/helpers'; | ||
import type { TestId } from '../../utils/types'; | ||
import useRadioGroup from '../RadioGroup/useRadioGroup'; | ||
|
||
export type RadioProps = { | ||
/** The value of the radio input. If no value is passed the default value, according to spec, is "on" | ||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio#value | ||
* | ||
* @default on | ||
* */ | ||
value?: string | number; | ||
/** Whether the radio input is selected or not. Defining this prop means the radio input is controlled */ | ||
isChecked?: boolean; | ||
/** The onChange event handler for the radio input */ | ||
onChange?: React.ReactEventHandler; | ||
/** The name of the radio input, in case you want to manually form a radio group */ | ||
name?: string; | ||
/** Whether the radio input is disabled | ||
* | ||
* @default false | ||
* */ | ||
isDisabled?: boolean; | ||
/** ID property of the radio input */ | ||
id?: string; | ||
/** Whether the radio input is required to be selected in the context of a form | ||
* | ||
* @default false | ||
* */ | ||
isRequired?: boolean; | ||
/** Whether the radio input is filled or outlined | ||
* | ||
* @default true | ||
* */ | ||
isFilled?: boolean; | ||
dataTestId?: TestId; | ||
}; | ||
|
||
const Radio = React.forwardRef<HTMLInputElement, RadioProps>((props, ref) => { | ||
const { | ||
isChecked: isExternallyControlledChecked, | ||
onChange, | ||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio#value | ||
value = 'on', | ||
name, | ||
isDisabled = false, | ||
id, | ||
isRequired = false, | ||
isFilled = true, | ||
dataTestId, | ||
} = props; | ||
const [isFocused, setIsFocused] = React.useState(false); | ||
const [isInternallyControlledChecked, setIsInternallyControlledChecked] = React.useState(false); | ||
const radioGroup = useRadioGroup(); | ||
const theme = useTheme(); | ||
|
||
const handleFocus = () => { | ||
setIsFocused(true); | ||
}; | ||
|
||
const handleBlur = () => { | ||
setIsFocused(false); | ||
}; | ||
|
||
const handleChange = (e: React.SyntheticEvent) => { | ||
if (isDisabled) return; | ||
|
||
if (isExternallyControlledChecked === undefined) { | ||
setIsInternallyControlledChecked((e.target as HTMLInputElement).checked); | ||
} | ||
|
||
if (onChange) { | ||
onChange(e); | ||
} | ||
|
||
if (radioGroup) { | ||
radioGroup.onChange(e); | ||
} | ||
}; | ||
|
||
// Checked value is either the externally controlled value, | ||
// or based on the radioGroup provided values, | ||
// or the internally controlled value | ||
const isCheckedValue = | ||
isExternallyControlledChecked ?? | ||
(radioGroup ? (radioGroup && radioGroup.value) === value : isInternallyControlledChecked); | ||
const nameValue = name ?? (radioGroup && radioGroup.name); | ||
|
||
return ( | ||
<span | ||
css={wrapperStyles(isDisabled)} | ||
data-testid={generateTestDataId('radio-input', dataTestId)} | ||
> | ||
<input | ||
css={inputStyles} | ||
onFocus={handleFocus} | ||
onBlur={handleBlur} | ||
onMouseLeave={handleBlur} | ||
onMouseOver={handleFocus} | ||
type="radio" | ||
onChange={handleChange} | ||
name={nameValue} | ||
value={value} | ||
disabled={isDisabled} | ||
id={id} | ||
required={isRequired} | ||
checked={isCheckedValue} | ||
ref={ref} | ||
/> | ||
<span css={customRadioWrapperStyles(isFocused, isDisabled)(theme)}> | ||
<span | ||
css={customRadioStyles({ | ||
isChecked: isCheckedValue, | ||
isDisabled, | ||
isFilled, | ||
})(theme)} | ||
/> | ||
<span css={customRadioInnerHover(isFocused, isDisabled)(theme)} /> | ||
</span> | ||
</span> | ||
); | ||
}); | ||
|
||
Radio.displayName = 'Radio'; | ||
|
||
export default Radio; | ||
This file was deleted.
Oops, something went wrong.
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 |
---|---|---|
@@ -1,45 +0,0 @@ | ||
import { Meta, Canvas, ArgTypes } from '@storybook/blocks'; | ||
import { withKnobs, boolean, array, select, text } from '@storybook/addon-knobs'; | ||
import Radio from '../Radio'; | ||
import RadioGroup from './RadioGroup'; | ||
import * as RadioGroupStories from './RadioGroup.stories'; | ||
|
||
<Meta of={RadioGroupStories} /> | ||
|
||
# RadioGroup | ||
|
||
A utility component for easily creating radio groups. | ||
`value` represents the current value of the `RadioGroup` as a whole. | ||
If the `value` prop is defined it means the `RadioGroup` is controlled. | ||
If the `defaultValue` prop is defined it means the `RadioGroup` is not controlled. | ||
`RadioGroup` does **not** wrap the children in any DOM element, that's left as a user implementation | ||
|
||
## Usage | ||
|
||
```jsx | ||
import { RadioGroup } from '@orfium/ictinus'; | ||
|
||
<RadioGroup | ||
value={value} | ||
name="group" | ||
onChange={(e) => { | ||
console.log(e.target.value); | ||
}} | ||
> | ||
<Radio value="a" /> | ||
<Radio value="b" /> | ||
<Radio value="c" /> | ||
</RadioGroup>; | ||
``` | ||
|
||
## Props | ||
|
||
<ArgTypes of={RadioGroup} /> | ||
|
||
# Self controlled radio group | ||
|
||
<Canvas of={RadioGroupStories.RadioWithOptions} /> | ||
|
||
# Self controlled radio group with onChange handler | ||
|
||
<Canvas of={RadioGroupStories.RadioWithOptionsWithOnChangeHandler} /> | ||
Oops, something went wrong.