-
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.
- Loading branch information
Showing
10 changed files
with
299 additions
and
34 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,35 @@ | ||
import type { JSX } from 'preact'; | ||
|
||
import type { CompositeProps, IconComponent } from '../../types'; | ||
import { RadioCheckedIcon, RadioIcon } from '../icons'; | ||
import ToggleInput from './ToggleInput'; | ||
|
||
type ComponentProps = { | ||
checked?: boolean; | ||
|
||
/** Custom icon to show when input is unchecked */ | ||
icon?: IconComponent; | ||
/** Custom icon to show when input is checked */ | ||
checkedIcon?: IconComponent; | ||
/** type is always `radio` */ | ||
type?: never; | ||
}; | ||
|
||
export type RadioButtonProps = CompositeProps & | ||
ComponentProps & | ||
Omit<JSX.HTMLAttributes<HTMLInputElement>, 'size' | 'icon'>; | ||
|
||
/** | ||
* Render a labeled radio input. The radio is styled with two icons: one for the | ||
* unchecked state and one for the checked state. The input itself is positioned | ||
* exactly on top of the icon, but is non-visible. | ||
*/ | ||
export default function RadioButton({ | ||
icon = RadioIcon, | ||
checkedIcon = RadioCheckedIcon, | ||
...rest | ||
}: RadioButtonProps) { | ||
return ( | ||
<ToggleInput icon={icon} checkedIcon={checkedIcon} type="radio" {...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
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,28 @@ | ||
import { mount } from 'enzyme'; | ||
|
||
import { testCompositeComponent } from '../../test/common-tests'; | ||
import RadioButton from '../RadioButton'; | ||
|
||
// Relatively simple test, as most of the logic is shared with Checkbox, and | ||
// covered by Checkbox-test | ||
describe('RadioButton', () => { | ||
const createComponent = (props = {}) => { | ||
return mount(<RadioButton {...props}>This is child content</RadioButton>); | ||
}; | ||
|
||
testCompositeComponent(RadioButton, { | ||
elementSelector: 'input[type="radio"]', | ||
}); | ||
|
||
it('shows an icon representing radio state', () => { | ||
const wrapper = createComponent(); | ||
|
||
assert.isTrue(wrapper.exists('RadioIcon')); | ||
assert.isFalse(wrapper.exists('RadioCheckedIcon')); | ||
|
||
wrapper.setProps({ checked: true }); | ||
|
||
assert.isFalse(wrapper.exists('RadioIcon')); | ||
assert.isTrue(wrapper.exists('RadioCheckedIcon')); | ||
}); | ||
}); |
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
106 changes: 106 additions & 0 deletions
106
src/pattern-library/components/patterns/input/RadioButtonPage.tsx
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,106 @@ | ||
import Library from '../../Library'; | ||
|
||
export default function RadioButtonPage() { | ||
return ( | ||
<Library.Page | ||
title="Radio button" | ||
intro={ | ||
<p> | ||
<code>RadioButton</code> is a composite component that includes a | ||
radio input and label. | ||
</p> | ||
} | ||
> | ||
<Library.Pattern> | ||
<Library.Usage componentName="RadioButton" /> | ||
<Library.Example> | ||
<Library.Demo | ||
title="Basic RadioButton" | ||
withSource | ||
exampleFile="radio-button-basic" | ||
/> | ||
</Library.Example> | ||
</Library.Pattern> | ||
|
||
<Library.Pattern title="Working with RadioButtons"> | ||
<Library.Example title="Controlled RadioButton"> | ||
<p> | ||
<code>RadioButton</code>s are always expected to be controlled, | ||
because only one in a group should be checked at once. | ||
</p> | ||
<p> | ||
Because of this, there should be a parent component handling the | ||
state for all of them, as <code>RadioButton</code>s do not know | ||
about each other. | ||
</p> | ||
</Library.Example> | ||
|
||
<Library.Example title="Customizing RadioButton icons"> | ||
<p> | ||
<code>RadioButton</code> uses icons to style the radio, in unchecked | ||
and checked states. Custom icons may be provided if desired. | ||
</p> | ||
<Library.Demo | ||
withSource | ||
title="RadioButton with custom icon and checkedIcon" | ||
exampleFile="radio-button-custom-icons" | ||
/> | ||
</Library.Example> | ||
</Library.Pattern> | ||
|
||
<Library.Pattern title="Component API"> | ||
<code>RadioButton</code> accepts all standard{' '} | ||
<Library.Link href="/using-components#presentational-components-api"> | ||
presentational component props | ||
</Library.Link> | ||
. | ||
<Library.Example title="checked"> | ||
<Library.Info> | ||
<Library.InfoItem label="description"> | ||
Set whether the <code>RadioButton</code> is checked. The presence | ||
of this component indicates that the <code>RadioButton</code> is | ||
being used as a controlled component. | ||
</Library.InfoItem> | ||
<Library.InfoItem label="type"> | ||
<code>{`boolean`}</code> | ||
</Library.InfoItem> | ||
<Library.InfoItem label="default"> | ||
<code>{`undefined`}</code> | ||
</Library.InfoItem> | ||
</Library.Info> | ||
</Library.Example> | ||
<Library.Example title="icon"> | ||
<Library.Info> | ||
<Library.InfoItem label="description"> | ||
<code>IconComponent</code> to use as the (unchecked) radio icon | ||
</Library.InfoItem> | ||
<Library.InfoItem label="type"> | ||
<code>{`IconComponent`}</code> | ||
</Library.InfoItem> | ||
</Library.Info> | ||
</Library.Example> | ||
<Library.Example title="checkedIcon"> | ||
<Library.Info> | ||
<Library.InfoItem label="description"> | ||
<code>IconComponent</code> to use as the (checked) radio icon | ||
</Library.InfoItem> | ||
<Library.InfoItem label="type"> | ||
<code>{`IconComponent`}</code> | ||
</Library.InfoItem> | ||
</Library.Info> | ||
</Library.Example> | ||
<Library.Example title="...htmlAttributes"> | ||
<Library.Info> | ||
<Library.InfoItem label="description"> | ||
<code>RadioButton</code> accepts HTML attributes for input | ||
elements | ||
</Library.InfoItem> | ||
<Library.InfoItem label="type"> | ||
<code>{`JSX.HTMLAttributes<HTMLInputElement>`}</code> | ||
</Library.InfoItem> | ||
</Library.Info> | ||
</Library.Example> | ||
</Library.Pattern> | ||
</Library.Page> | ||
); | ||
} |
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 { useCallback, useState } from 'preact/hooks'; | ||
|
||
import { RadioButton } from '../..'; | ||
|
||
export default function App() { | ||
const [value, setSelected] = useState<'one' | 'two' | 'three'>(); | ||
const onChange = useCallback((e: Event) => { | ||
setSelected( | ||
(e.target as HTMLInputElement).value as 'one' | 'two' | 'three', | ||
); | ||
}, []); | ||
|
||
return ( | ||
<form className=" flex flex-col"> | ||
<RadioButton | ||
name="option" | ||
value="one" | ||
checked={value === 'one'} | ||
onChange={onChange} | ||
> | ||
Click me | ||
</RadioButton> | ||
<RadioButton | ||
name="option" | ||
value="two" | ||
checked={value === 'two'} | ||
onChange={onChange} | ||
> | ||
No, click me | ||
</RadioButton> | ||
<RadioButton | ||
name="option" | ||
value="three" | ||
checked={value === 'three'} | ||
disabled | ||
> | ||
Disabled | ||
</RadioButton> | ||
</form> | ||
); | ||
} |
Oops, something went wrong.