-
Notifications
You must be signed in to change notification settings - Fork 150
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #148 from kiwicom/add-new-radiobutton-component
Update Radio component
- Loading branch information
Showing
13 changed files
with
3,735 additions
and
308 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 |
---|---|---|
@@ -0,0 +1,140 @@ | ||
// @flow | ||
import * as React from "react"; | ||
import styled from "styled-components"; | ||
import defaultTokens from "@kiwicom/orbit-design-tokens"; | ||
|
||
type Props = {| | ||
label: string, | ||
value?: string, | ||
hasError: boolean, | ||
disabled: boolean, | ||
checked: boolean, | ||
info?: React.Node, | ||
onChange: (SyntheticEvent<HTMLInputElement>) => void, | ||
theme: typeof defaultTokens, | ||
|}; | ||
|
||
const Glyph = styled.span` | ||
visibility: hidden; | ||
width: 12px; | ||
height: 12px; | ||
background-color: ${({ theme, disabled }) => | ||
disabled ? theme.colorIconCheckboxDisabled : theme.colorIconCheckbox}; | ||
border-radius: ${({ theme }) => theme.borderRadiusCircle}; | ||
`; | ||
|
||
const IconContainer = styled.div` | ||
position: relative; | ||
box-sizing: border-box; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
background-color: ${({ theme }) => theme.backgroundInput}; | ||
height: ${({ theme }) => theme.heightCheckbox}; | ||
width: ${({ theme }) => theme.widthCheckbox}; | ||
border-radius: ${({ theme }) => theme.borderRadiusCircle}; | ||
overflow: hidden; | ||
border: 1px solid ${({ tokens }) => tokens.borderColor}; | ||
transform: scale(1); | ||
transition: all ${({ theme }) => theme.durationFast} ease-in-out; | ||
} | ||
`; | ||
|
||
const TextContainer = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
margin-left: ${({ theme }) => theme.spaceXSmall}; | ||
`; | ||
|
||
const Info = styled.span` | ||
font-size: ${({ theme }) => theme.fontSizeMessageForm}; | ||
color: ${({ theme }) => theme.paletteInkLight}; // TODO create token | ||
line-height: ${({ theme }) => theme.lineHeightText}; | ||
`; | ||
|
||
const LabelText = styled.span` | ||
font-weight: ${({ theme }) => theme.fontWeightNormal}; | ||
font-size: ${({ theme }) => theme.fontSizeLabelForm}; | ||
color: ${({ theme }) => theme.colorLabelForm}; | ||
height: ${({ theme }) => theme.heightCheckbox}; | ||
line-height: ${({ theme }) => theme.heightCheckbox}; | ||
`; | ||
|
||
const Input = styled.input` | ||
visibility: hidden; | ||
display: none; | ||
&:checked ~ ${TextContainer} > ${LabelText} { | ||
font-weight: ${({ theme }) => theme.fontWeightMedium}; | ||
} | ||
&:checked + ${IconContainer} > ${Glyph} { | ||
visibility: visible; | ||
} | ||
`; | ||
|
||
const Label = styled(({ tokens, disabled, theme, type, ...props }) => ( | ||
<label {...props}>{props.children}</label> | ||
))` | ||
font-family: ${({ theme }) => theme.fontFamily}; | ||
display: flex; | ||
flex-direction: row; | ||
align-items: self-start; | ||
opacity: ${({ disabled, theme }) => (disabled ? theme.opacityCheckboxDisabled : "1")}; | ||
cursor: ${({ disabled }) => (disabled ? "default" : "pointer")}; | ||
position: relative; | ||
&:hover ${IconContainer} { | ||
border-color: ${({ disabled, theme }) => | ||
disabled ? theme.borderColorInputHover : theme.paletteInkLight}; // TODO create token | ||
} | ||
&:active ${IconContainer} { | ||
border-color: ${({ disabled, theme, tokens }) => | ||
disabled ? tokens.borderColor : theme.paletteInkNormal}; // TODO create token | ||
transform: ${({ disabled, theme }) => !disabled && `scale(${theme.modifierScaleButtonActive})`}; | ||
} | ||
&:focus { | ||
outline: 0; | ||
& ${IconContainer} { | ||
box-shadow: 0 0 3px ${({ theme }) => theme.paletteBlueNormal}; // TODO create token | ||
} | ||
} | ||
`; | ||
|
||
const Radio = (props: Props) => { | ||
const { label, value, hasError, disabled, checked, onChange, theme, info } = props; | ||
|
||
const tokens = { | ||
borderColor: | ||
hasError && !disabled && !checked ? theme.borderColorInputError : theme.borderColorInput, | ||
}; | ||
|
||
return ( | ||
<Label theme={theme} disabled={disabled} tokens={tokens}> | ||
<Input | ||
value={value} | ||
type="checkbox" | ||
disabled={disabled} | ||
checked={checked} | ||
onChange={onChange} | ||
theme={theme} | ||
/> | ||
<IconContainer tokens={tokens} theme={theme}> | ||
<Glyph theme={theme} disabled={disabled} /> | ||
</IconContainer> | ||
<TextContainer theme={theme}> | ||
{label && <LabelText theme={theme}>{label}</LabelText>} | ||
{info && <Info theme={theme}>{info}</Info>} | ||
</TextContainer> | ||
</Label> | ||
); | ||
}; | ||
|
||
Radio.defaultProps = { | ||
hasError: false, | ||
disabled: false, | ||
checked: false, | ||
theme: defaultTokens, | ||
}; | ||
|
||
export default Radio; |
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,86 @@ | ||
// @flow | ||
import * as React from "react"; | ||
import { storiesOf, setAddon } from "@storybook/react"; | ||
import { action } from "@storybook/addon-actions"; | ||
import styles from "@sambego/storybook-styles"; | ||
import chaptersAddon from "react-storybook-addon-chapters"; | ||
import { withKnobs, text, boolean } from "@storybook/addon-knobs/react"; | ||
|
||
import Radio from "./Radio"; | ||
|
||
setAddon(chaptersAddon); | ||
|
||
storiesOf("Radio", module) | ||
.addDecorator(withKnobs) | ||
.addDecorator( | ||
styles({ | ||
padding: "20px", | ||
}), | ||
) | ||
.addWithChapters("Default", () => { | ||
const label = text("Label", "Label"); | ||
const checked = boolean("Checked", false); | ||
return { | ||
info: "Radio needs only label and onChange by default.", | ||
chapters: [ | ||
{ | ||
sections: [ | ||
{ | ||
sectionFn: () => ( | ||
<Radio label={label} checked={checked} onChange={action("changed")} /> | ||
), | ||
}, | ||
], | ||
}, | ||
], | ||
}; | ||
}) | ||
.addWithChapters("With help", () => { | ||
const label = text("Label", "Label"); | ||
const value = text("Value", "value"); | ||
const info = text("Info", "Additional information to this choice"); | ||
return { | ||
info: "Additionally you can add info to this component.", | ||
chapters: [ | ||
{ | ||
sections: [ | ||
{ | ||
sectionFn: () => ( | ||
<Radio label={label} value={value} info={info} onChange={action("changed")} /> | ||
), | ||
}, | ||
], | ||
}, | ||
], | ||
}; | ||
}) | ||
.addWithChapters("Playground", () => { | ||
const label = text("Label", "Label"); | ||
const value = text("Value", "value"); | ||
const checked = boolean("Checked", true); | ||
const disabled = boolean("Disabled", true); | ||
const hasError = boolean("hasError", false); | ||
const info = text("Info", "Additional information for this choice"); | ||
return { | ||
info: "Playground of Radio", | ||
chapters: [ | ||
{ | ||
sections: [ | ||
{ | ||
sectionFn: () => ( | ||
<Radio | ||
label={label} | ||
value={value} | ||
checked={checked} | ||
disabled={disabled} | ||
hasError={hasError} | ||
info={info} | ||
onChange={action("changed")} | ||
/> | ||
), | ||
}, | ||
], | ||
}, | ||
], | ||
}; | ||
}); |
Oops, something went wrong.