Skip to content

Commit

Permalink
Typescript Selection Controls (Switch, Checkbox, Radio) (#679)
Browse files Browse the repository at this point in the history
* Updated switch to typescript

* Tweaks to switch typings

* Radio Typescript

* Tweaked Radio

* Checkbox typescript
  • Loading branch information
Michael Marszalek authored Oct 15, 2020
1 parent 1acbcb3 commit e155605
Show file tree
Hide file tree
Showing 14 changed files with 148 additions and 154 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* eslint-disable no-undef */

import React, { useState } from 'react'
import PropTypes from 'prop-types'
import { render, cleanup, fireEvent, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
import 'jest-styled-components'
Expand All @@ -16,7 +15,11 @@ const StyledCheckbox = styled(Checkbox)`
clip-path: unset;
`

const ControlledCheckbox = ({ onChange }) => {
type ControlledProps = {
onChange: () => void
}

const ControlledCheckbox = ({ onChange }: ControlledProps) => {
const [checked, setChecked] = useState(true)
return (
<Checkbox
Expand All @@ -29,9 +32,6 @@ const ControlledCheckbox = ({ onChange }) => {
/>
)
}
ControlledCheckbox.propTypes = {
onChange: PropTypes.func.isRequired,
}

describe('Checkbox', () => {
it('Can extend the css for the component', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
/* eslint camelcase: "off" */
// @ts-nocheck
import React, { forwardRef } from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import {
checkbox,
checkbox_outline, // eslint-disable-line camelcase
checkbox_indeterminate, // eslint-disable-line camelcase
} from '@equinor/eds-icons'
import type { IconData } from '@equinor/eds-icons'

import { checkbox as tokens } from './Checkbox.tokens'
import { typographyTemplate } from '../../_common/templates'

const { color, enabled } = tokens

const StyledCheckbox = styled.label`
type StyledCheckboxProps = {
disabled: boolean
}

const StyledCheckbox = styled.label<StyledCheckboxProps>`
display: inline-flex;
align-items: center;
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
`
type StyledIconPathProps = {
icon: IconData
name: string
}

const StyledPath = styled.path.attrs(({ icon }) => ({
const StyledPath = styled.path.attrs<StyledIconPathProps>(({ icon }) => ({
fillRule: 'evenodd',
clipRule: 'evenodd',
d: icon.svgPathData,
}))``
}))<StyledIconPathProps>``

const Input = styled.input.attrs(({ type = 'checkbox' }) => ({
type,
Expand Down Expand Up @@ -65,7 +73,9 @@ const Svg = styled.svg.attrs(({ height, width, fill }) => ({
fill,
}))``

const InputWrapper = styled.span`
type StyledInputWrapperProps = { disabled: boolean }

const InputWrapper = styled.span<StyledInputWrapperProps>`
display: inline-flex;
border-radius: 50%;
padding: ${enabled.padding};
Expand All @@ -79,7 +89,18 @@ const LabelText = styled.span`
${typographyTemplate(enabled.typography)}
`

export const Checkbox = forwardRef((props, ref) => {
type Props = {
/** Label for the checkbox */
label: string
/** If true, the checkbox will be disabled */
disabled?: boolean
/** If true, the checkbox appears indeterminate. Important! You'll have to
* set the native element to indeterminate yourself.
*/
indeterminate?: boolean
} & Omit<JSX.IntrinsicElements['input'], 'disabled'>

export const Checkbox = forwardRef<HTMLInputElement, Props>((props, ref) => {
const { label, disabled, indeterminate, className, ...rest } = props

const iconSize = 24
Expand All @@ -100,7 +121,7 @@ export const Checkbox = forwardRef((props, ref) => {
fill={disabled ? color.disabled : color.primary}
aria-hidden
>
<StyledPath icon={checkbox_indeterminate} />
<StyledPath icon={checkbox_indeterminate} name="indeterminate" />
</Svg>
) : (
<Svg
Expand All @@ -121,22 +142,3 @@ export const Checkbox = forwardRef((props, ref) => {
})

Checkbox.displayName = 'eds-checkbox'

Checkbox.propTypes = {
/** Label for the checkbox */
label: PropTypes.string.isRequired,
/** If true, the checkbox will be disabled */
disabled: PropTypes.bool,
/** If true, the checkbox appears indeterminate. Important! You'll have to
* set the native element to indeterminate yourself.
*/
indeterminate: PropTypes.bool,
/** Additional class names */
className: PropTypes.string,
}

Checkbox.defaultProps = {
disabled: false,
indeterminate: false,
className: undefined,
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* eslint-disable no-undef */

import React from 'react'
import { render, cleanup, fireEvent, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-nocheck
import { tokens } from '@equinor/eds-tokens'

const {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
/* eslint camelcase: "off" */
// @ts-nocheck
import React, { forwardRef } from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import {
radio_button_selected, // eslint-disable-line camelcase
radio_button_unselected, // eslint-disable-line camelcase
} from '@equinor/eds-icons'
import type { IconData } from '@equinor/eds-icons'
import { radio as tokens } from './Radio.tokens'
import { typographyTemplate } from '../../_common/templates'

Expand Down Expand Up @@ -46,18 +45,24 @@ const Input = styled.input.attrs(({ type = 'radio' }) => ({
display: inline;
}
`
type StyledRadioProps = Pick<Props, 'disabled'>

const StyledRadio = styled.label`
const StyledRadio = styled.label<StyledRadioProps>`
display: inline-flex;
align-items: center;
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
`

const StyledPath = styled.path.attrs(({ icon }) => ({
type StyledIconPathProps = {
icon: IconData
name: string
}

const StyledPath = styled.path.attrs<StyledIconPathProps>(({ icon }) => ({
fillRule: 'evenodd',
clipRule: 'evenodd',
d: icon.svgPathData,
}))``
}))<StyledIconPathProps>``

const Svg = styled.svg.attrs(({ height, width, fill }) => ({
name: null,
Expand All @@ -71,7 +76,9 @@ const LabelText = styled.span`
${typographyTemplate(enabled.typography)}
`

const InputWrapper = styled.span`
type StyledInputWrapperProps = { disabled: boolean }

const InputWrapper = styled.span<StyledInputWrapperProps>`
display: inline-flex;
border-radius: 50%;
padding: ${enabled.padding};
Expand All @@ -80,8 +87,14 @@ const InputWrapper = styled.span`
disabled ? 'transparent' : color.hover};
}
`
type Props = {
/** Label for the radio */
label: string
/** If true, the radio button will be disabled */
disabled?: boolean
} & JSX.IntrinsicElements['input']

export const Radio = forwardRef(
export const Radio = forwardRef<HTMLInputElement, Props>(
({ label, disabled = false, className, ...rest }, ref) => {
const iconSize = 24
return (
Expand All @@ -106,17 +119,3 @@ export const Radio = forwardRef(
)

Radio.displayName = 'eds-radio'

Radio.propTypes = {
/** Label for the radio */
label: PropTypes.string.isRequired,
/** If true, the radio button will be disabled */
disabled: PropTypes.bool,
/** Additional class names */
className: PropTypes.string,
}

Radio.defaultProps = {
disabled: false,
className: undefined,
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// @ts-nocheck
import React, { forwardRef } 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<Props, 'disabled'>

const BaseInput = styled.input.attrs(({ type = 'checkbox' }) => ({
type,
}))`
}))<StyledProps>`
border: 0;
clip: rect(0 0 0 0);
height: 1px;
Expand Down Expand Up @@ -59,28 +60,23 @@ const DefaultInput = styled(BaseInput)`
}
`

export const Input = forwardRef(({ disabled, size, ...rest }, ref) => {
return (
<>
{size === 'small' ? (
<SmallInput {...rest} ref={ref} disabled={disabled} />
) : (
<DefaultInput {...rest} ref={ref} disabled={disabled} />
)}
</>
)
})

Input.displayName = 'eds-switch-input'
type Props = {
size?: Size
disabled?: boolean
} & React.HTMLAttributes<HTMLInputElement>

Input.propTypes = {
// If true, the component will be disabled
disabled: PropTypes.bool,
// Switch size, use the small version with caution
size: PropTypes.oneOf(['default', 'small']),
}
export const Input = forwardRef<HTMLInputElement, Props>(
({ size = 'default', ...rest }, ref) => {
return (
<>
{size === 'small' ? (
<SmallInput {...rest} ref={ref} />
) : (
<DefaultInput {...rest} ref={ref} />
)}
</>
)
},
)

Input.defaultProps = {
disabled: false,
size: 'default',
}
Input.displayName = 'eds-switch-input'
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// @ts-nocheck
import React from 'react'
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

const BaseInputWrapper = styled.span`
type StyledProps = Pick<Props, 'isDisabled'>

const BaseInputWrapper = styled.span<StyledProps>`
width: ${enabled.clickSize};
height: ${enabled.clickSize};
border-radius: 50%;
Expand All @@ -29,8 +31,17 @@ const InputWrapperSmall = styled(BaseInputWrapper)`
isDisabled ? 'transparent' : enabled.hover.background};
}
`
type Props = {
children: ReactNode
isDisabled?: boolean
size?: Size
}

export const InputWrapper = ({ children, isDisabled, size }) => {
export const InputWrapper = ({
children,
isDisabled,
size = 'default',
}: Props): JSX.Element => {
return (
<>
{size === 'small' ? (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-nocheck
import { tokens } from '@equinor/eds-tokens'

const {
Expand Down
Loading

0 comments on commit e155605

Please sign in to comment.