From 19d66bf2cf5556bc04cdbf232a12406753038702 Mon Sep 17 00:00:00 2001 From: namanda Date: Mon, 28 Jun 2021 16:35:13 -0500 Subject: [PATCH 1/3] add radio input --- ORGANIZATION.md | 1 + src/components/Input/Radio/RadioSvg.tsx | 42 +++++++++++++++++++++++++ src/components/Input/Radio/index.ts | 1 + src/components/Input/index.ts | 1 + src/index.ts | 2 +- src/stories/index.js | 1 + 6 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/components/Input/Radio/RadioSvg.tsx create mode 100644 src/components/Input/Radio/index.ts diff --git a/ORGANIZATION.md b/ORGANIZATION.md index 8c72741e..142922ce 100644 --- a/ORGANIZATION.md +++ b/ORGANIZATION.md @@ -56,6 +56,7 @@ Currently, there is no clear, definitive organization to our RoverUI component l - ListControlDefaultItem - MultiLineInput - PasswordInput + - Radio - Select - SmallCheckbox(?) - TextArea diff --git a/src/components/Input/Radio/RadioSvg.tsx b/src/components/Input/Radio/RadioSvg.tsx new file mode 100644 index 00000000..41f6ff86 --- /dev/null +++ b/src/components/Input/Radio/RadioSvg.tsx @@ -0,0 +1,42 @@ +import React from 'react'; + +import styles from './Radio.module.css'; + +const Svg = ({ title = 'Radio', ...passedProps }) => ( + + {title} + + + + + + +); + +export default Svg; diff --git a/src/components/Input/Radio/index.ts b/src/components/Input/Radio/index.ts new file mode 100644 index 00000000..61c95671 --- /dev/null +++ b/src/components/Input/Radio/index.ts @@ -0,0 +1 @@ +export { default } from './Radio'; diff --git a/src/components/Input/index.ts b/src/components/Input/index.ts index ae02d3a1..2dc95d20 100644 --- a/src/components/Input/index.ts +++ b/src/components/Input/index.ts @@ -1,3 +1,4 @@ export { default } from './Input'; export { default as Checkbox } from './Checkbox'; +export { default as Radio } from './Radio'; export type { InputProps } from './Input'; diff --git a/src/index.ts b/src/index.ts index 4e73a49b..f8bd9e62 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,7 +31,7 @@ export { } from './components/TabMenu'; export { default as Tooltip, EasyRichTooltip } from './components/Tooltip'; -export { default as Input, Checkbox } from './components/Input'; +export { default as Input, Checkbox, Radio } from './components/Input'; export { default as InputTime } from './components/InputTime'; export { default as Typography } from './components/Typography'; export { default as Modal } from './components/Modal'; diff --git a/src/stories/index.js b/src/stories/index.js index 01e96f87..0354abdf 100644 --- a/src/stories/index.js +++ b/src/stories/index.js @@ -22,6 +22,7 @@ import '../components/Avatar/story'; import '../components/Tooltip/story'; import '../components/Input/story'; import '../components/Input/Checkbox/story'; +import '../components/Input/Radio/story'; import '../components/InputTime/story'; import '../components/Typography/story'; From ae1631e0baf356479158df1c3d833b2ef190c315 Mon Sep 17 00:00:00 2001 From: namanda Date: Fri, 2 Jul 2021 18:26:23 -0500 Subject: [PATCH 2/3] radio svg and component --- example/src/App.js | 14 +++ src/components/Input/Radio/README.md | 9 ++ src/components/Input/Radio/Radio.module.css | 59 ++++++++++ src/components/Input/Radio/Radio.tsx | 42 +++++++ src/components/Input/Radio/story.tsx | 116 ++++++++++++++++++++ 5 files changed, 240 insertions(+) create mode 100644 src/components/Input/Radio/README.md create mode 100644 src/components/Input/Radio/Radio.module.css create mode 100644 src/components/Input/Radio/Radio.tsx create mode 100644 src/components/Input/Radio/story.tsx diff --git a/example/src/App.js b/example/src/App.js index 4482b92b..08845060 100644 --- a/example/src/App.js +++ b/example/src/App.js @@ -40,6 +40,7 @@ const App = () => { const [tooltipOpen, setTooltipOpen] = useState(false); const [inputValue, setInputValue] = useState(''); const [inputCheckboxValue, setInputCheckboxValue] = useState(false); + const [inputRadioValue, setInputRadioValue] = useState(false); const [inputTimeValue, setInputTimeValue] = useState(''); const [isModalOpen, setIsModalOpen] = useState(false); @@ -410,6 +411,19 @@ const App = () => { {JSON.stringify(inputCheckboxValue)} +
+

Input.Radio

+ + console.log(e.target.checked) || + setInputRadioValue(e.target.checked) + } + checked={inputRadioValue} + type="radio" + />{' '} + {JSON.stringify(inputRadioValue)} +
+
+ +### Radio component is a thin wrapper around an HTML input[type="radio"] element + +The basic `` delegates all normal input behavior to the HTML element, and adds custom styles. + +It also provides 1 custom prop: + +- _fauxDisabled_: Applies the same style as disabled, but, unlike the real thing, doesn't stop propagation of events. Useful for adding tooltips or other helpful behavior when a user tries to interact with a disabled field. Because it doesn't stop click or change events, the consumer is responsible for making faux-disabled fields read-only. diff --git a/src/components/Input/Radio/Radio.module.css b/src/components/Input/Radio/Radio.module.css new file mode 100644 index 00000000..9b9c102e --- /dev/null +++ b/src/components/Input/Radio/Radio.module.css @@ -0,0 +1,59 @@ +.Radio { + position: relative; + display: inline-block; + /* height: var(--rvr-radio-size); + width: var(--rvr-radio-size); */ + height: 24px; + width: 24px; +} + +.svg { + transition: var(--rvr-transition-duration-fast) var(--rvr-linear) box-shadow; + display: block; + height: 100%; + width: 100%; +} + +.input { + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + opacity: 0; + z-index: 1; + display: block; +} + +.outline { + fill: var(--rvr-color-font); + transition: var(--rvr-transition-duration-fast) var(--rvr-linear) fill; +} + +.inner { + fill: var(--rvr-white); +} + +input:checked + .svg .outline { + fill: var(--rvr-color-primary); +} + +input:hover + .svg .outline { + fill: var(--rvr-color-primary-hover); +} + +input:focus + .svg { + outline: 0 transparent none; + box-shadow: + 0px 0px 0px 2px var(--rvr-white), + 0px 0px 1px 3px var(--rvr-color-primary-hover), + 0px 0px 8px 2px var(--rvr-color-primary-hover); +} + +input:disabled + .svg .outline { + fill: var(--rvr-color-disabled); +} + +input:checked + .svg .inner { + display: none; +} diff --git a/src/components/Input/Radio/Radio.tsx b/src/components/Input/Radio/Radio.tsx new file mode 100644 index 00000000..ca87c140 --- /dev/null +++ b/src/components/Input/Radio/Radio.tsx @@ -0,0 +1,42 @@ +import React from 'react'; + +import classNames from 'classnames'; + +import type { InputProps } from '../Input'; + +import RadioSvg from './RadioSvg'; +import styles from './Radio.module.css'; + +interface RadioWithRefProps extends InputProps { + forwardedRef?: React.Ref; +} + +const RadioWithRef: React.FC = ({ + checked = false, + className = '', + forwardedRef: ref, + ...passedProps +}) => { + return ( +
+ + +
+ ); +}; + +const Radio = React.forwardRef((props, ref) => ( + +)); + +export default Radio; diff --git a/src/components/Input/Radio/story.tsx b/src/components/Input/Radio/story.tsx new file mode 100644 index 00000000..7101d1a9 --- /dev/null +++ b/src/components/Input/Radio/story.tsx @@ -0,0 +1,116 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import { boolean, text } from '@storybook/addon-knobs'; + +import Radio from '.'; +import Readme from './README.md'; + +import { InteractiveInput, Wrap } from '../../../stories/storybook-helpers'; + +storiesOf('Planets/Input/Radio', module) + .addParameters({ + readme: { + sidebar: Readme, + }, + }) + .add( + 'Overview', + () => ( + + {/* + Eslint doesn't recognise that the `InteractiveInput` wrappers are + putting IDs on input elements, but they are. + */} + {/* eslint-disable-next-line jsx-a11y/label-has-associated-control */} + + + ), + { + info: { + inline: true, + source: true, + }, + } + ) + .add( + 'Examples', + () => ( + +

Radio

+

+ + + Radio is a bare input - the labels are provided for documentation + purposes only. “Control” components with integrated + labels and validation messages are on the roadmap. + + +

+

+ + This component is identical to {'``'}. + +

+

+ + These examples use an `InteractiveInput` wrapper with an + `InputRenderer` prop. In actual implementations, just use a `Radio` + component, `onChange`, and `checked` props instead. + +

+
+ {[[], ['checked'], ['disabled'], ['checked', 'disabled']].map( + (attributes) => { + const attributesId = ['atts', ...attributes].join('-'); + const attributesLabel = attributes.join(' and ') || 'default'; + + const attributesProps = attributes.reduce( + (acc, attr) => ({ ...acc, [attr]: true }), + {} + ); + + return ( +
+ +
+ ); + } + )} +
+
+ ), + { + info: { + inline: false, + source: true, + }, + } + ); From 9846e5f02f4b0767560c452070d573d47504788c Mon Sep 17 00:00:00 2001 From: namanda Date: Mon, 30 Aug 2021 16:56:45 -0500 Subject: [PATCH 3/3] add fauxdisabled, radio group, remove onchange from interactiveinput --- src/components/Input/Radio/Radio.module.css | 37 ++++-- src/components/Input/Radio/Radio.tsx | 4 + src/components/Input/Radio/RadioSvg.tsx | 19 +--- src/components/Input/Radio/story.tsx | 119 ++++++++++++++++---- src/shared/sizing.css | 1 + src/stories/storybook-helpers.tsx | 3 +- 6 files changed, 133 insertions(+), 50 deletions(-) diff --git a/src/components/Input/Radio/Radio.module.css b/src/components/Input/Radio/Radio.module.css index 9b9c102e..4025b87e 100644 --- a/src/components/Input/Radio/Radio.module.css +++ b/src/components/Input/Radio/Radio.module.css @@ -1,10 +1,8 @@ .Radio { position: relative; display: inline-block; - /* height: var(--rvr-radio-size); - width: var(--rvr-radio-size); */ - height: 24px; - width: 24px; + height: var(--rvr-radio-size); + width: var(--rvr-radio-size); } .svg { @@ -24,14 +22,17 @@ z-index: 1; display: block; } - .outline { fill: var(--rvr-color-font); transition: var(--rvr-transition-duration-fast) var(--rvr-linear) fill; + border-width: medium; } .inner { - fill: var(--rvr-white); + fill: none; +} +.Radio.checked .outline { + fill: var(--rvr-color-primary); } input:checked + .svg .outline { @@ -55,5 +56,27 @@ input:disabled + .svg .outline { } input:checked + .svg .inner { - display: none; + fill: var(--rvr-color-primary); +} + +.Radio.checked .check, +.indeterminate + .svg .dash { + display: initial; + fill: var(--rvr-white); +} + +.Radio.disabled .svg { + box-shadow: none; +} + +input:disabled + .svg .outline, +.Radio.disabled .svg .outline { + fill: var(--rvr-color-disabled); + box-shadow: none; +} + +input:disabled + .svg .inner, +.Radio.disabled .svg .inner { + fill: var(--rvr-color-disabled); + box-shadow: none; } diff --git a/src/components/Input/Radio/Radio.tsx b/src/components/Input/Radio/Radio.tsx index ca87c140..070e0b99 100644 --- a/src/components/Input/Radio/Radio.tsx +++ b/src/components/Input/Radio/Radio.tsx @@ -8,12 +8,14 @@ import RadioSvg from './RadioSvg'; import styles from './Radio.module.css'; interface RadioWithRefProps extends InputProps { + fauxDisabled?: boolean; forwardedRef?: React.Ref; } const RadioWithRef: React.FC = ({ checked = false, className = '', + fauxDisabled = false, forwardedRef: ref, ...passedProps }) => { @@ -21,12 +23,14 @@ const RadioWithRef: React.FC = ({
diff --git a/src/components/Input/Radio/RadioSvg.tsx b/src/components/Input/Radio/RadioSvg.tsx index 41f6ff86..ad11d4a1 100644 --- a/src/components/Input/Radio/RadioSvg.tsx +++ b/src/components/Input/Radio/RadioSvg.tsx @@ -13,28 +13,13 @@ const Svg = ({ title = 'Radio', ...passedProps }) => ( > {title} - + - + ); diff --git a/src/components/Input/Radio/story.tsx b/src/components/Input/Radio/story.tsx index 7101d1a9..1c7a2ca1 100644 --- a/src/components/Input/Radio/story.tsx +++ b/src/components/Input/Radio/story.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { boolean, text } from '@storybook/addon-knobs'; @@ -38,6 +38,7 @@ storiesOf('Planets/Input/Radio', module) @@ -79,31 +80,35 @@ storiesOf('Planets/Input/Radio', module)

- {[[], ['checked'], ['disabled'], ['checked', 'disabled']].map( - (attributes) => { - const attributesId = ['atts', ...attributes].join('-'); - const attributesLabel = attributes.join(' and ') || 'default'; + {[ + [], + ['checked'], + ['disabled'], + ['fauxDisabled'], + ['checked', 'disabled'], + ].map((attributes) => { + const attributesId = ['atts', ...attributes].join('-'); + const attributesLabel = attributes.join(' and ') || 'default'; - const attributesProps = attributes.reduce( - (acc, attr) => ({ ...acc, [attr]: true }), - {} - ); + const attributesProps = attributes.reduce( + (acc, attr) => ({ ...acc, [attr]: true }), + {} + ); - return ( -
- -
- ); - } - )} + return ( +
+ +
+ ); + })}
), @@ -113,4 +118,70 @@ storiesOf('Planets/Input/Radio', module) source: true, }, } + ) + .add( + 'Radio Group Example', + () => { + const [brother, setBrother] = useState(''); + return ( + +
+

Example

+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+ ); + }, + { + info: { + inline: false, + source: true, + }, + } ); diff --git a/src/shared/sizing.css b/src/shared/sizing.css index 68e5bb98..92866221 100644 --- a/src/shared/sizing.css +++ b/src/shared/sizing.css @@ -66,6 +66,7 @@ /* Form elements */ --rvr-checkbox-size: calc(var(--rvr-baseSize) * 2.25); /* 18px */ + --rvr-radio-size: calc(var(--rvr-baseSize) * 2); /* 16px */ /* Dropdowns */ /* Default EasyDropdown menu item with text label */ diff --git a/src/stories/storybook-helpers.tsx b/src/stories/storybook-helpers.tsx index 9697341d..9519fc2c 100644 --- a/src/stories/storybook-helpers.tsx +++ b/src/stories/storybook-helpers.tsx @@ -56,7 +56,6 @@ interface InteractiveInputProps extends React.InputHTMLAttributes { fauxDisabled?: boolean; InputRenderer: React.FC>; - onChange?: () => void; } export const InteractiveInput: React.FC = ({ @@ -78,7 +77,7 @@ export const InteractiveInput: React.FC = ({ onChange={(e) => { setValue(e.target.value); setChecked(e.target.checked); - onChange(); + onChange(e); }} value={value !== undefined ? value : undefined} />