Skip to content
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

Ux 603 New Radio component #261

Merged
merged 35 commits into from Dec 4, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
bf7fa17
Add readme and setup initial state
tristanjasper Oct 31, 2019
ad69545
adding canDeselect
tristanjasper Nov 1, 2019
6ca72ec
minor cleanup
tristanjasper Nov 1, 2019
52c81a1
move onclick to input
tristanjasper Nov 1, 2019
affbc8f
Merge branch 'master' into ux-603-radio-component
tristanjasper Nov 12, 2019
d59d097
Merge branch 'master' into ux-603-radio-component
tristanjasper Nov 15, 2019
2266270
cleanup
tristanjasper Nov 15, 2019
ce38f1e
Merge branch 'master' into ux-603-radio-component
tristanjasper Nov 19, 2019
141a64d
adding grouping
tristanjasper Nov 20, 2019
ec0b2c7
Merge branch 'master' into ux-603-radio-component
tristanjasper Nov 20, 2019
0f9aea1
adjust to support api on radio group element
tristanjasper Nov 21, 2019
cc9a443
Merge branch 'master' into ux-603-radio-component
tristanjasper Nov 21, 2019
4d3391c
better readme example
tristanjasper Nov 21, 2019
56e7e9c
readme cleanup
tristanjasper Nov 25, 2019
055fa5f
Merge branch 'master' into ux-603-radio-component
tristanjasper Nov 27, 2019
50db165
use nanoid
tristanjasper Nov 27, 2019
9d77e50
move props into inputProps
tristanjasper Nov 27, 2019
2d5aabc
adding name and fix onchange
tristanjasper Nov 28, 2019
e78df4d
fix focus colour
tristanjasper Nov 28, 2019
04d0335
change to a11y
tristanjasper Nov 28, 2019
d5d7436
Merge branch 'master' into ux-603-radio-component
tristanjasper Nov 29, 2019
b81d563
adding name and value to props
tristanjasper Nov 29, 2019
b6b39a0
add ways to selections
tristanjasper Nov 30, 2019
061b369
use value on select
tristanjasper Nov 30, 2019
4cae770
removed isSelectedProp
tristanjasper Dec 2, 2019
d5bf522
use context instead of cloning
tristanjasper Dec 2, 2019
4fe25c0
ux-603-update readme
tristanjasper Dec 2, 2019
9dfba7c
Merge branch 'master' into ux-603-radio-component
tristanjasper Dec 2, 2019
215deb4
remove function
tristanjasper Dec 2, 2019
42d1ca8
Merge branch 'master' into ux-603-radio-component
tristanjasper Dec 2, 2019
622137f
Change back to use cloneElement
tristanjasper Dec 4, 2019
3a8dcad
Merge branch 'master' of github.com:acl-services/paprika into ux-603-…
tristanjasper Dec 4, 2019
665cfcd
Merge branch 'master' into ux-603-radio-component
tristanjasper Dec 4, 2019
f5a10d6
Use react.children
tristanjasper Dec 4, 2019
a6452cc
change function title
tristanjasper Dec 4, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 15 additions & 3 deletions packages/Radio/src/Radio.js
Expand Up @@ -7,24 +7,36 @@ import radioStyles from "./Radio.styles";
import Group from "./components/Group";

const propTypes = {
/** Used for aria-label on the radio input */
a11yText: PropTypes.string,
/** Used for label contents */
children: PropTypes.node,
/** Describe if the radio is checked or not */
isChecked: PropTypes.bool,
/** Describe if the radio is disabled or not */
isDisabled: PropTypes.bool,
/* Controls if the radio is selected or not, never combine it with defaultIsSelected */
isSelected: PropTypes.bool,
/** Describe if the radio started as selected or not */
defaultIsSelected: PropTypes.bool,
/** Describe if the radio started as selected or not */
canDeselect: PropTypes.bool,
/** On click prop added by Group component */
onClick: PropTypes.func,
/** On click prop added by Group component */
size: PropTypes.oneOf(ShirtSizes.DEFAULT),
value: PropTypes.shape({ id: PropTypes.string }).isRequired,
};
tristanjasper marked this conversation as resolved.
Show resolved Hide resolved

const defaultProps = {
a11yText: null,
isChecked: false,
canDeselect: false,
children: null,
isChecked: false,
isDisabled: false,
size: ShirtSizes.MEDIUM,
isSelected: false,
defaultIsSelected: false,
onClick: () => {},
size: ShirtSizes.MEDIUM,
};

function Radio(props) {
Expand Down
37 changes: 23 additions & 14 deletions packages/Radio/src/components/Group/Group.js
Expand Up @@ -10,9 +10,6 @@ const propTypes = {
/** Can deselect any radio */
canDeselect: PropTypes.bool,

/** Function used to evaluate which radio is selected by default. */
defaultCheck: PropTypes.func,

/** The individual radio items. */
children: PropTypes.node,

Expand All @@ -30,21 +27,33 @@ const defaultProps = {
a11yText: "",
canDeselect: false,
children: null,
defaultCheck: () => {},
isDisabled: false,
size: ShirtSizes.MEDIUM,
};

function Group(props) {
const { a11yText, canDeselect, children, defaultCheck, onChange, ...moreGroupProps } = props;
const defaultCheckedId = React.Children.toArray(children).find(defaultCheck).props.value.id;
const [checkedId, setCheckedId] = React.useState(defaultCheckedId || null);
const deselectableId = id => (checkedId === id ? null : id);
const { a11yText, canDeselect, children, onChange, ...moreGroupProps } = props;
const defaultCheckedIndex = React.Children.toArray(children).findIndex(child => child.props.defaultIsSelected);
const selectedIndex = React.Children.toArray(children).findIndex(child => child.props.isSelected);

const defaultIndex = () => {
tristanjasper marked this conversation as resolved.
Show resolved Hide resolved
if (defaultCheckedIndex !== -1) {
return defaultCheckedIndex;
}

return false;
};

const [checkedIndex, setCheckedIndex] = React.useState(defaultIndex());
if (selectedIndex !== -1 && selectedIndex !== checkedIndex) {
setCheckedIndex(selectedIndex);
}

const deselectableIndex = index => (checkedIndex === index ? null : index);
const name = nanoid();
const handleRadioClick = child => {
const id = child.props.value.id;
onChange(id);
setCheckedId(canDeselect ? deselectableId(id) : id);
const handleRadioClick = index => {
onChange(index);
setCheckedIndex(canDeselect ? deselectableIndex(index) : index);
};

return (
Expand All @@ -53,8 +62,8 @@ function Group(props) {
if (child && child.type && child.type.displayName === "Radio") {
const childKey = { key: `Radio${index}` };
tristanjasper marked this conversation as resolved.
Show resolved Hide resolved
return React.cloneElement(child, {
tristanjasper marked this conversation as resolved.
Show resolved Hide resolved
onClick: () => handleRadioClick(child),
isChecked: checkedId === child.props.value.id,
onClick: () => handleRadioClick(index),
isChecked: checkedIndex === index,
canDeselect,
name,
...childKey,
Expand Down
4 changes: 3 additions & 1 deletion packages/Radio/stories/Radio.stories.js
@@ -1,7 +1,9 @@
import { storiesOf } from "@storybook/react";
import { withKnobs } from "@storybook/addon-knobs";
import ShowcaseStory from "./examples/Showcase";
import ControlledStory from "./examples/Controlled";

storiesOf("Radio", module)
.addDecorator(withKnobs)
.add("Showcase", ShowcaseStory);
.add("Showcase", ShowcaseStory)
.add("Controlled", ControlledStory);
69 changes: 69 additions & 0 deletions packages/Radio/stories/examples/Controlled.js
@@ -0,0 +1,69 @@
import React from "react";
import { action } from "@storybook/addon-actions";
import { Rule } from "storybook/assets/styles/common.styles";
import Heading from "@paprika/heading";
import { RadioStory } from "../Radio.stories.styles";
import Radio from "../../src/Radio";

export const radioItems = ["Radio 1", "Radio 2 label", "Radio 3 option"];

const ExampleStory = props => {
const [selectedIndex, setSelectedIndex] = React.useState(1);
const handleIndexChange = e => {
setSelectedIndex(Number(e.target.value));
};
return (
<RadioStory>
<Heading level={2} displayLevel={3} isLight>
Setting a item as default selected
</Heading>
<Rule />
<Radio.Group
onChange={activeIndex => {
action("Radio selection changed to index ")(activeIndex);
}}
{...props}
>
{radioItems.map((item, index) => {
return (
<Radio key={item} defaultIsSelected={index === 2}>
{item}
</Radio>
);
})}
</Radio.Group>
<Rule />
<Heading level={2} displayLevel={3} isLight>
Controlling which item is selected
</Heading>
<Rule />
<Radio.Group
onChange={activeIndex => {
setSelectedIndex(activeIndex);
action("Radio selection changed to index ")(activeIndex);
}}
{...props}
>
{radioItems.map((item, index) => {
return (
<Radio key={item} isSelected={index === selectedIndex}>
{item}
</Radio>
);
})}
</Radio.Group>
<br />
Set Selected Index
<br />
<select onChange={handleIndexChange}>
{radioItems.map((item, index) => (
<option selected={index === selectedIndex} value={index}>
{item}
</option>
))}
</select>
</RadioStory>
);
};

export default () => <ExampleStory />;
13 changes: 6 additions & 7 deletions packages/Radio/stories/examples/Showcase.js
Expand Up @@ -23,16 +23,15 @@ const ExampleStory = props => {
<Tagline>Use the knobs to tinker with the props.</Tagline>
<Rule />
<Radio.Group
defaultCheck={check => check.props.value.id === "value 1"}
onChange={value => {
action("Radio selection changed to ")(value);
onChange={activeIndex => {
action("Radio selection changed to index ")(activeIndex);
}}
{...props}
>
<Radio value={{ id: "value 1" }}>Radio 1</Radio>
<Radio value={{ id: "value 2" }}>Radio 2</Radio>
<Radio value={{ id: "value 3" }}>Radio 3</Radio>
<Radio value={{ id: "value 4" }}>Radio 4</Radio>
<Radio defaultIsSelected>Radio 1</Radio>
<Radio>Radio 2</Radio>
<Radio>Radio 3</Radio>
<Radio>Radio 4</Radio>
</Radio.Group>
<Rule />
</RadioStory>
Expand Down