diff --git a/apps/storybook-react/stories/SelectionControls.Checkbox.stories.jsx b/apps/storybook-react/stories/SelectionControls.Checkbox.stories.jsx deleted file mode 100644 index 123cef7d36..0000000000 --- a/apps/storybook-react/stories/SelectionControls.Checkbox.stories.jsx +++ /dev/null @@ -1,221 +0,0 @@ -import React, { useState, useRef } from 'react' -import { Checkbox, Icon, Typography, Button } from '@equinor/eds-core-react' -import styled from 'styled-components' -import { action } from '@storybook/addon-actions' -import { checkbox } from '@equinor/eds-icons' -import { useForm } from 'react-hook-form' - -Icon.add({ checkbox }) -const Wrapper = styled.div` - display: grid; - grid-template-rows: min-width; - padding: 32px; - padding-bottom: 8rem; - grid-gap: 2rem; - position: relative; - transition: all 0.36s; -` - -const BlockCheckbox = styled(Checkbox)` - display: flex; -` - -const UnstyledList = styled.ul` - margin: 0; - padding: 0; - list-style-type: none; -` - -export default { - title: 'Components/Selection controls/Checkbox', - component: Checkbox, -} - -export const CheckboxControl = () => { - // Use this to set the input to indeterminate = true as this must be done via JavaScript - // (cannot use an HTML attribute for this) - const indeterminateRef = useRef() - // State for controlled example - const [checked, updateChecked] = useState(false) - - return ( - -
- - Single checkbox examples - - -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - { - updateChecked(e.target.checked) - }} - checked={checked} - /> -
  • -
    -
    -
    - ) -} - -export const CheckboxGroupControl = () => { - return ( - - - Multiple checkboxes in a group - -
    - - We are in this together! - - ๐Ÿ™Œ - - - -
  • - -
  • -
  • - -
  • -
  • - -
  • -
    -
    -
    - ) -} - -export const WithFormsControl = () => { - // Example with external forms library, react-hook-form - const { register, handleSubmit, watch, errors } = useForm() - const [isSubmitted, updateIsSubmitted] = useState(false) - const [formData, updateFormData] = useState(null) - - const onSubmit = (data) => { - updateFormData(JSON.stringify(data)) - updateIsSubmitted(true) - action('onSubmit')(data) - } - console.log(watch('example')) - return ( - -
    - - Example with React Hook Form - - - Real life example with an external{' '} - - form library - - -
    - {isSubmitted ? ( - <> - Submitted data: -

    {formData}

    - - - ) : ( -
    -
    - Whatโ€˜s your favourites? - {/* Just to demonstrate style addons, a list would have been better for semantic */} - - - - -
    - - - Hey you! This field is required - -
    - -
    -
    - )} -
    -
    -
    - ) -} - -CheckboxControl.storyName = 'Single' -CheckboxGroupControl.storyName = 'Multiple' -WithFormsControl.storyName = 'With React Hooks Forms' diff --git a/apps/storybook-react/stories/SelectionControls.Checkbox.stories.tsx b/apps/storybook-react/stories/SelectionControls.Checkbox.stories.tsx new file mode 100644 index 0000000000..de68be310a --- /dev/null +++ b/apps/storybook-react/stories/SelectionControls.Checkbox.stories.tsx @@ -0,0 +1,211 @@ +import React, { useState, useRef } from 'react' +import { + Checkbox, + Icon, + Typography, + Button, + CheckboxProps, +} from '@equinor/eds-core-react' +import styled from 'styled-components' +import { action } from '@storybook/addon-actions' +import { checkbox } from '@equinor/eds-icons' +import { useForm } from 'react-hook-form' +import { Meta, Story } from '@storybook/react' + +Icon.add({ checkbox }) + +const BlockCheckbox = styled(Checkbox)` + display: flex; +` + +const UnstyledList = styled.ul` + margin: 0; + padding: 0; + list-style-type: none; +` + +export default { + title: 'Components/Selection controls/Checkbox', + component: Checkbox, +} as Meta + +export const Default: Story = (args) => ( + +) + +export const SingleCheckbox: Story = () => { + // Use this to set the input to indeterminate = true as this must be done via JavaScript + // (cannot use an HTML attribute for this) + const indeterminateRef = useRef() + // State for controlled example + const [checked, updateChecked] = useState(false) + + return ( + +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + { + updateChecked(e.target.checked) + }} + checked={checked} + /> +
  • +
    + ) +} + +export const GroupedCheckbox: Story = () => { + return ( +
    + + We are in this together! + + ๐Ÿ™Œ + + + +
  • + +
  • +
  • + +
  • +
  • + +
  • +
    +
    + ) +} + +type FormData = { + favourites: string[] + agree: string +} + +export const WithFormsControl: Story = () => { + // Example with external forms library, react-hook-form + // eslint-disable-next-line @typescript-eslint/unbound-method + const { register, handleSubmit, watch, errors } = useForm() + const [isSubmitted, updateIsSubmitted] = useState(false) + const [formData, updateFormData] = useState(null) + + const onSubmit = (data: FormData) => { + updateFormData(data) + updateIsSubmitted(true) + action('onSubmit')(data) + } + console.log(watch('example')) + return ( +
    + + Real life example with an external{' '} + + form library + + +
    + {isSubmitted ? ( + <> + Submitted data: +

    {JSON.stringify(formData)}

    + + + ) : ( +
    +
    + Whatโ€˜s your favourites? + {/* Just to demonstrate style addons, a list would have been better for semantic */} + + + + +
    + + + Hey you! This field is required + +
    + +
    +
    + )} +
    +
    + ) +} + +GroupedCheckbox.storyName = 'Multiple checkboxes in a group' +WithFormsControl.storyName = 'Example with React Hook Form' diff --git a/apps/storybook-react/stories/SelectionControls.Radio.stories.jsx b/apps/storybook-react/stories/SelectionControls.Radio.stories.jsx deleted file mode 100644 index 122a84b17d..0000000000 --- a/apps/storybook-react/stories/SelectionControls.Radio.stories.jsx +++ /dev/null @@ -1,99 +0,0 @@ -import React, { useState } from 'react' -import { Radio, Icon, Typography } from '@equinor/eds-core-react' -import styled from 'styled-components' -import { checkbox } from '@equinor/eds-icons' - -Icon.add({ checkbox }) -const Wrapper = styled.div` - padding: 32px; - padding-bottom: 8rem; -` - -const BlockRadio = styled(Radio)` - display: flex; -` - -const UnstyledList = styled.ul` - margin: 0; - padding: 0; - list-style-type: none; -` - -export default { - title: 'Components/Selection controls/Radio', - component: Radio, -} - -export const RadioControl = () => { - return ( - - - Single radiobox examples - -
    - - - - -
    -
    - ) -} -export const RadioGroupControl = () => { - const [checked, updateChecked] = useState('one') - const onChange = (event) => { - updateChecked(event.target.value) - } - return ( - - - Group example as controlled components and onChange - -
    - - We are in this together! - - ๐Ÿ™Œ - - - -
  • - -
  • -
  • - -
  • -
  • - -
  • -
    -
    -
    - ) -} - -RadioControl.storyName = 'Single' -RadioGroupControl.storyName = 'Group' diff --git a/apps/storybook-react/stories/SelectionControls.Radio.stories.tsx b/apps/storybook-react/stories/SelectionControls.Radio.stories.tsx new file mode 100644 index 0000000000..58fbacf25c --- /dev/null +++ b/apps/storybook-react/stories/SelectionControls.Radio.stories.tsx @@ -0,0 +1,90 @@ +import React, { useState } from 'react' +import { Radio, RadioProps, Icon } from '@equinor/eds-core-react' +import styled from 'styled-components' +import { checkbox } from '@equinor/eds-icons' +import { Meta, Story } from '@storybook/react' + +Icon.add({ checkbox }) + +const BlockRadio = styled(Radio)` + display: flex; +` + +const UnstyledList = styled.ul` + margin: 0; + padding: 0; + list-style-type: none; +` + +export default { + title: 'Components/Selection controls/Radio', + component: Radio, +} as Meta + +export const Default: Story = (args) => ( + +) + +export const SingleRadio: Story = () => { + return ( +
    + + + + +
    + ) +} +export const GroupedRadio: Story = () => { + const [checked, updateChecked] = useState('one') + const onChange = (event: React.ChangeEvent) => { + updateChecked(event.target.value) + } + return ( +
    + + We are in this together! + + ๐Ÿ™Œ + + + +
  • + +
  • +
  • + +
  • +
  • + +
  • +
    +
    + ) +} + +GroupedRadio.storyName = 'Multiple radio buttons in a group' +SingleRadio.storyName = 'Single radio buttons' diff --git a/apps/storybook-react/stories/SelectionControls.Switch.stories.jsx b/apps/storybook-react/stories/SelectionControls.Switch.stories.tsx similarity index 76% rename from apps/storybook-react/stories/SelectionControls.Switch.stories.jsx rename to apps/storybook-react/stories/SelectionControls.Switch.stories.tsx index 0e02fe8177..b5133b3718 100644 --- a/apps/storybook-react/stories/SelectionControls.Switch.stories.jsx +++ b/apps/storybook-react/stories/SelectionControls.Switch.stories.tsx @@ -1,10 +1,12 @@ import React, { useState } from 'react' -import { Switch, Icon, Typography } from '@equinor/eds-core-react' +import { Switch, SwitchProps } from '@equinor/eds-core-react' import styled from 'styled-components' -import { checkbox } from '@equinor/eds-icons' +import { Meta, Story } from '@storybook/react' -Icon.add({ checkbox }) -const Wrapper = styled.div` +type WrapperStyleProps = { + darkMode?: boolean +} +const Wrapper = styled.div` display: grid; grid-template-rows: min-width; padding: 32px; @@ -22,15 +24,6 @@ const UnstyledList = styled.ul` list-style-type: none; ` -const DarkModeTypography = styled(Typography)` - margin: '1rem 0'; - ${({ darkMode }) => - darkMode && { - color: 'white', - }}; - transition: all 0.36s; -` - const Examples = styled.div` display: grid; grid-gap: 3rem; @@ -41,9 +34,13 @@ const Examples = styled.div` export default { title: 'Components/Selection controls/Switch', component: Switch, -} +} as Meta + +export const Default: Story = (args) => ( + +) -export const SwitchControl = () => { +export const Variants: Story = () => { return ( @@ -91,16 +88,12 @@ export const SwitchControl = () => { ) } -export const ControlledSwitchControl = () => { +export const ControlledSwitchControl: Story = () => { const [darkMode, setDarkMode] = useState(false) return ( - - Use case with controlled component - setDarkMode(!darkMode)} label="Dark mode" /> @@ -108,5 +101,4 @@ export const ControlledSwitchControl = () => { ) } -SwitchControl.storyName = 'Examples' -ControlledSwitchControl.storyName = 'Controlled' +ControlledSwitchControl.storyName = 'Use case with controlled component' diff --git a/libraries/core-react/src/SelectionControls/Checkbox/Checkbox.tsx b/libraries/core-react/src/SelectionControls/Checkbox/Checkbox.tsx index ab77de6158..9224b5df2e 100644 --- a/libraries/core-react/src/SelectionControls/Checkbox/Checkbox.tsx +++ b/libraries/core-react/src/SelectionControls/Checkbox/Checkbox.tsx @@ -1,5 +1,5 @@ /* eslint camelcase: "off" */ -import React, { forwardRef } from 'react' +import React, { forwardRef, Ref } from 'react' import styled from 'styled-components' import { checkbox, @@ -89,7 +89,7 @@ const LabelText = styled.span` ${typographyTemplate(enabled.typography)} ` -type Props = { +export type CheckboxProps = { /** Label for the checkbox */ label: string /** If true, the checkbox will be disabled */ @@ -98,47 +98,49 @@ type Props = { * set the native element to indeterminate yourself. */ indeterminate?: boolean -} & Omit - -export const Checkbox = forwardRef((props, ref) => { - const { label, disabled, indeterminate, className, ...rest } = props +} & Omit & { + ref?: Ref + } - const iconSize = 24 - return ( - - - - {indeterminate ? ( - - - - ) : ( - - - - - )} - - {label} - - ) -}) +export const Checkbox = forwardRef( + ({ label, disabled = false, indeterminate, className, ...rest }, ref) => { + const iconSize = 24 + return ( + + + + {indeterminate ? ( + + + + ) : ( + + + + + )} + + {label} + + ) + }, +) Checkbox.displayName = 'Checkbox' diff --git a/libraries/core-react/src/SelectionControls/Radio/Radio.tsx b/libraries/core-react/src/SelectionControls/Radio/Radio.tsx index e14cfa6059..8b7c83854d 100644 --- a/libraries/core-react/src/SelectionControls/Radio/Radio.tsx +++ b/libraries/core-react/src/SelectionControls/Radio/Radio.tsx @@ -1,5 +1,5 @@ /* eslint camelcase: "off" */ -import React, { forwardRef } from 'react' +import React, { forwardRef, Ref } from 'react' import styled from 'styled-components' import { radio_button_selected, // eslint-disable-line camelcase @@ -45,7 +45,7 @@ const Input = styled.input.attrs(({ type = 'radio' }) => ({ display: inline; } ` -type StyledRadioProps = Pick +type StyledRadioProps = Pick const StyledRadio = styled.label` display: inline-flex; @@ -87,14 +87,16 @@ const InputWrapper = styled.span` disabled ? 'transparent' : color.hover}; } ` -type Props = { +export type RadioProps = { /** Label for the radio */ label: string /** If true, the radio button will be disabled */ disabled?: boolean -} & JSX.IntrinsicElements['input'] +} & JSX.IntrinsicElements['input'] & { + ref?: Ref + } -export const Radio = forwardRef( +export const Radio = forwardRef( ({ label, disabled = false, className, ...rest }, ref) => { const iconSize = 24 return ( diff --git a/libraries/core-react/src/SelectionControls/Switch/Input.tsx b/libraries/core-react/src/SelectionControls/Switch/Input.tsx index 1bc44a62cb..444f63792a 100644 --- a/libraries/core-react/src/SelectionControls/Switch/Input.tsx +++ b/libraries/core-react/src/SelectionControls/Switch/Input.tsx @@ -5,7 +5,7 @@ import type { Size } from './Switch.types' const { enabled, disabled: _disabled } = tokens -type StyledProps = Pick +type StyledProps = Pick const BaseInput = styled.input.attrs(({ type = 'checkbox' }) => ({ type, @@ -60,12 +60,12 @@ const DefaultInput = styled(BaseInput)` } ` -type Props = { +type InputProps = { size?: Size disabled?: boolean } & React.HTMLAttributes -export const Input = forwardRef( +export const Input = forwardRef( ({ size = 'default', ...rest }, ref) => { return ( <> diff --git a/libraries/core-react/src/SelectionControls/Switch/InputWrapper.tsx b/libraries/core-react/src/SelectionControls/Switch/InputWrapper.tsx index 1ec7f621c1..c9ec2576aa 100644 --- a/libraries/core-react/src/SelectionControls/Switch/InputWrapper.tsx +++ b/libraries/core-react/src/SelectionControls/Switch/InputWrapper.tsx @@ -1,12 +1,11 @@ import React, { ReactNode } from 'react' -import PropTypes from 'prop-types' import styled from 'styled-components' import { switchControl as tokens } from './Switch.tokens' import type { Size } from './Switch.types' const { enabled, disabled: _disabled } = tokens -type StyledProps = Pick +type StyledProps = Pick const BaseInputWrapper = styled.span` width: ${enabled.clickSize}; @@ -31,7 +30,7 @@ const InputWrapperSmall = styled(BaseInputWrapper)` isDisabled ? 'transparent' : enabled.hover.background}; } ` -type Props = { +type InputWrapperProps = { children: ReactNode isDisabled?: boolean size?: Size @@ -41,7 +40,7 @@ export const InputWrapper = ({ children, isDisabled, size = 'default', -}: Props): JSX.Element => { +}: InputWrapperProps): JSX.Element => { return ( <> {size === 'small' ? ( @@ -56,17 +55,3 @@ export const InputWrapper = ({ ) } - -InputWrapper.propTypes = { - // Track and handle - children: PropTypes.node.isRequired, - // Whether styles should be reflecting disabled state or not - isDisabled: PropTypes.bool, - // Default or small version - size: PropTypes.oneOf(['default', 'small']), -} - -InputWrapper.defaultProps = { - isDisabled: false, - size: 'default', -} diff --git a/libraries/core-react/src/SelectionControls/Switch/Switch.tsx b/libraries/core-react/src/SelectionControls/Switch/Switch.tsx index 5806cbb976..5e7d421ad6 100644 --- a/libraries/core-react/src/SelectionControls/Switch/Switch.tsx +++ b/libraries/core-react/src/SelectionControls/Switch/Switch.tsx @@ -1,4 +1,4 @@ -import React, { forwardRef } from 'react' +import React, { forwardRef, Ref } from 'react' import styled from 'styled-components' import { SwitchSmall } from './SwitchSmall' import { SwitchDefault } from './SwitchDefault' @@ -25,16 +25,18 @@ const Label = styled.span` ${typographyTemplate(enabled.typography)} ` -type Props = { +export type SwitchProps = { /** Label for the switch. Required to make it a11y compliant */ label: string /** Switch size, use the small version with caution */ size?: Size /** If true, the switch will be disabled */ disabled?: boolean -} & Omit +} & Omit & { + ref?: Ref + } -export const Switch = forwardRef( +export const Switch = forwardRef( ({ size = 'default', disabled, label, className, ...rest }, ref) => { return ( diff --git a/libraries/core-react/src/SelectionControls/Switch/SwitchDefault.tsx b/libraries/core-react/src/SelectionControls/Switch/SwitchDefault.tsx index e8587a7f2a..960abd42ea 100644 --- a/libraries/core-react/src/SelectionControls/Switch/SwitchDefault.tsx +++ b/libraries/core-react/src/SelectionControls/Switch/SwitchDefault.tsx @@ -42,11 +42,11 @@ const Handle = styled.span` transition: transform 0.36s cubic-bezier(0.78, 0.14, 0.15, 0.86); ` -type Props = { +type SwitchDefaultProps = { disabled?: boolean } -export const SwitchDefault = forwardRef( +export const SwitchDefault = forwardRef( ({ disabled, ...rest }, ref) => { return ( <> diff --git a/libraries/core-react/src/SelectionControls/Switch/SwitchSmall.tsx b/libraries/core-react/src/SelectionControls/Switch/SwitchSmall.tsx index ff0c8b8084..13be70fe6f 100644 --- a/libraries/core-react/src/SelectionControls/Switch/SwitchSmall.tsx +++ b/libraries/core-react/src/SelectionControls/Switch/SwitchSmall.tsx @@ -34,11 +34,11 @@ const Handle = styled.span` transition: transform 0.36s cubic-bezier(0.78, 0.14, 0.15, 0.86); ` -type Props = { +type SwitchSmallProps = { disabled?: boolean } -export const SwitchSmall = forwardRef( +export const SwitchSmall = forwardRef( ({ disabled, ...rest }, ref) => { return ( <> diff --git a/libraries/core-react/src/SelectionControls/index.js b/libraries/core-react/src/SelectionControls/index.js deleted file mode 100644 index ed50d472f5..0000000000 --- a/libraries/core-react/src/SelectionControls/index.js +++ /dev/null @@ -1,4 +0,0 @@ -// @ts-nocheck -export { Radio } from './Radio/Radio' -export { Checkbox } from './Checkbox/Checkbox' -export { Switch } from './Switch/Switch' diff --git a/libraries/core-react/src/SelectionControls/index.ts b/libraries/core-react/src/SelectionControls/index.ts new file mode 100644 index 0000000000..54e0aa5037 --- /dev/null +++ b/libraries/core-react/src/SelectionControls/index.ts @@ -0,0 +1,3 @@ +export * from './Radio/Radio' +export * from './Checkbox/Checkbox' +export * from './Switch/Switch' diff --git a/libraries/core-react/src/index.ts b/libraries/core-react/src/index.ts index becd05a829..ff36d93aa9 100644 --- a/libraries/core-react/src/index.ts +++ b/libraries/core-react/src/index.ts @@ -23,7 +23,7 @@ export { Tooltip } from './Tooltip' export { Snackbar } from './Snackbar' export { Popover } from './Popover' export * from './Banner' -export { Radio, Checkbox, Switch } from './SelectionControls' +export * from './SelectionControls' export * from './Progress' export { Breadcrumbs } from './Breadcrumbs' export { Menu } from './Menu'