From 4537585fb65a551464f76dbba2cb800d22d360ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rn=20=C3=98lmheim?= Date: Sat, 10 Oct 2020 19:10:20 +0200 Subject: [PATCH 1/2] Typescript conversion of Chips completed and working. --- .gitignore | 1 + .../src/Chip/{Chip.test.jsx => Chip.test.tsx} | 1 - .../Chip/{Chip.tokens.js => Chip.tokens.ts} | 1 - .../src/Chip/{Chip.jsx => Chip.tsx} | 111 ++++++++---------- .../src/Chip/{Icon.jsx => Icon.tsx} | 8 +- .../src/Chip/{index.js => index.ts} | 0 libraries/core-react/src/Icon/Icon.tsx | 6 +- 7 files changed, 61 insertions(+), 67 deletions(-) rename libraries/core-react/src/Chip/{Chip.test.jsx => Chip.test.tsx} (99%) rename libraries/core-react/src/Chip/{Chip.tokens.js => Chip.tokens.ts} (98%) rename libraries/core-react/src/Chip/{Chip.jsx => Chip.tsx} (70%) rename libraries/core-react/src/Chip/{Icon.jsx => Icon.tsx} (87%) rename libraries/core-react/src/Chip/{index.js => index.ts} (100%) diff --git a/.gitignore b/.gitignore index 578619a88d..27cf482fa7 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ yarn.lock public # local docz testing docz-fresh +.idea diff --git a/libraries/core-react/src/Chip/Chip.test.jsx b/libraries/core-react/src/Chip/Chip.test.tsx similarity index 99% rename from libraries/core-react/src/Chip/Chip.test.jsx rename to libraries/core-react/src/Chip/Chip.test.tsx index b9f1b9b4af..f49ed0a805 100644 --- a/libraries/core-react/src/Chip/Chip.test.jsx +++ b/libraries/core-react/src/Chip/Chip.test.tsx @@ -1,4 +1,3 @@ -/* eslint-disable no-undef */ import React from 'react' import { render, cleanup, fireEvent, screen } from '@testing-library/react' import '@testing-library/jest-dom' diff --git a/libraries/core-react/src/Chip/Chip.tokens.js b/libraries/core-react/src/Chip/Chip.tokens.ts similarity index 98% rename from libraries/core-react/src/Chip/Chip.tokens.js rename to libraries/core-react/src/Chip/Chip.tokens.ts index afc3c3293d..bd8181c06e 100644 --- a/libraries/core-react/src/Chip/Chip.tokens.js +++ b/libraries/core-react/src/Chip/Chip.tokens.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import { tokens } from '@equinor/eds-tokens' const { diff --git a/libraries/core-react/src/Chip/Chip.jsx b/libraries/core-react/src/Chip/Chip.tsx similarity index 70% rename from libraries/core-react/src/Chip/Chip.jsx rename to libraries/core-react/src/Chip/Chip.tsx index 732ac46409..f318233efc 100644 --- a/libraries/core-react/src/Chip/Chip.jsx +++ b/libraries/core-react/src/Chip/Chip.tsx @@ -1,8 +1,5 @@ -// @ts-nocheck import React, { forwardRef } from 'react' -import PropTypes from 'prop-types' import styled, { css } from 'styled-components' -import { close } from '@equinor/eds-icons' import { Icon } from './Icon' import { chip as tokens } from './Chip.tokens' import { @@ -11,8 +8,6 @@ import { typographyTemplate, } from '../_common/templates' -Icon.add({ close }) - const { enabled, disabled: disabledToken, @@ -23,10 +18,14 @@ const { outlineOffset, } = tokens -const StyledChips = styled.div.attrs(({ clickable, deletable }) => ({ - tabIndex: clickable || deletable ? 0 : null, - role: clickable ? 'button' : null, -}))` +type StyledChipsProps = { + clickable: boolean, + deletable: boolean, + variant: 'active' | 'error' | 'default', + disabled: boolean, +} + +const StyledChips = styled.div` background: ${enabled.background}; height: ${enabled.height}; width: fit-content; @@ -36,6 +35,8 @@ const StyledChips = styled.div.attrs(({ clickable, deletable }) => ({ grid-auto-columns: max-content; align-items: center; z-index: 999; + tabIndex: ${({ clickable, deletable }) => (clickable || deletable ? 0 : null)}, + role: ${({ clickable }) => (clickable ? 'button' : null)}, svg { fill: ${enabled.typography.color}; @@ -61,7 +62,6 @@ const StyledChips = styled.div.attrs(({ clickable, deletable }) => ({ ${spacingsTemplate(enabled.spacings)} ${typographyTemplate(enabled.typography)} - ${({ clickable }) => clickable && css` @@ -124,18 +124,29 @@ const StyledChips = styled.div.attrs(({ clickable, deletable }) => ({ padding-right: 4px; `} - ${({ onlyChild }) => - onlyChild && + ${({ children }) => + (typeof children === 'string') && css` padding-left: 8px; `} - ` - -export const Chip = forwardRef(function EdsChips( - { children, onDelete, disabled, onClick, variant, ...rest }, +type Props = { + disabled?: boolean, + onDelete?: (Event) => void, + variant?: 'active' | 'error' | 'default', +} & React.HTMLAttributes + +export const Chip = forwardRef(function EdsChips( + { + children, + onDelete, + disabled = false, + onClick, + variant= 'default', + ...other }, ref, ) { + const handleDelete = disabled ? undefined : onDelete const handleClick = disabled ? undefined : onClick @@ -143,8 +154,8 @@ export const Chip = forwardRef(function EdsChips( const clickable = handleClick !== undefined const onlyChild = typeof children === 'string' - const props = { - ...rest, + const chipProps = { + ...other, ref, disabled, deletable, @@ -159,14 +170,14 @@ export const Chip = forwardRef(function EdsChips( if (deletable) { handleDelete(event) } - // Delete takes presidens, else click action is activated + // Delete takes precedence, else click action is activated if (clickable && !deletable) { handleClick(event) } } } - const resizedChildren = React.Children.map(children, (child) => { + const resizedChildren = React.Children.map(children, (child: React.DetailedReactHTMLElement) => { // We force size on Icon & Avatar component if (child.props && child.props.size) { return React.cloneElement(child, { @@ -177,54 +188,34 @@ export const Chip = forwardRef(function EdsChips( return child }) + const onDeleteClick = (event) => { + event.stopPropagation() + if (deletable) { + handleDelete(event) + } + } + return ( clickable && handleClick(event)} onKeyPress={handleKeyPress} > {resizedChildren} - {onDelete && ( - { - event.stopPropagation() - if (deletable) { - handleDelete(event) - } - }} - size={16} - /> - )} + {onDelete && + ( + + ) + } ) }) Chip.displayName = 'eds-chip' - -Chip.propTypes = { - /** @ignore */ - className: PropTypes.string, - /** @ignore */ - children: PropTypes.node, - /** Disabled */ - disabled: PropTypes.bool, - /** Delete callback */ - onDelete: PropTypes.func, - /** Click callback */ - onClick: PropTypes.func, - /** Variant */ - variant: PropTypes.oneOf(['active', 'error', 'default']), -} - -Chip.defaultProps = { - className: '', - children: [], - disabled: false, - onDelete: undefined, - onClick: undefined, - variant: 'default', -} diff --git a/libraries/core-react/src/Chip/Icon.jsx b/libraries/core-react/src/Chip/Icon.tsx similarity index 87% rename from libraries/core-react/src/Chip/Icon.jsx rename to libraries/core-react/src/Chip/Icon.tsx index 0098dde4c6..3e4c280a6f 100644 --- a/libraries/core-react/src/Chip/Icon.jsx +++ b/libraries/core-react/src/Chip/Icon.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import styled, { css } from 'styled-components' import { close } from '@equinor/eds-icons' import { Icon as Icon_ } from '..' @@ -8,7 +7,12 @@ Icon_.add({ close }) const { enabled, hover, error } = tokens -export const Icon = styled(Icon_)` +type IconProps = { + variant: 'active' | 'error' | 'default', + disabled: boolean +} + +export const Icon = styled(Icon_)` cursor: pointer; padding: 1px; border-radius: ${enabled.icon.border.radius}; diff --git a/libraries/core-react/src/Chip/index.js b/libraries/core-react/src/Chip/index.ts similarity index 100% rename from libraries/core-react/src/Chip/index.js rename to libraries/core-react/src/Chip/index.ts diff --git a/libraries/core-react/src/Icon/Icon.tsx b/libraries/core-react/src/Icon/Icon.tsx index cb1a9fd0e9..a6220145c2 100644 --- a/libraries/core-react/src/Icon/Icon.tsx +++ b/libraries/core-react/src/Icon/Icon.tsx @@ -19,7 +19,7 @@ type SvgProps = { rotation?: number title?: string role?: string - 'aria-hidden'?: boolean + 'aria-hidden'?: boolean | 'true' | 'false' 'aria-labelledby'?: string } @@ -63,7 +63,7 @@ type Props = { name?: Name /** Manually specify which icon data to use */ data?: IconData -} +} & React.HTMLAttributes export const Icon = forwardRef(function EdsIcon( { @@ -113,7 +113,7 @@ export const Icon = forwardRef(function EdsIcon( ...svgProps, title, role: 'img', - 'aria-hidden': null, + 'aria-hidden': undefined, 'aria-labelledby': titleId, } } From 0023820cfa13761fdbd5492c2e50c876d5a749be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rn=20=C3=98lmheim?= Date: Mon, 19 Oct 2020 11:39:32 +0200 Subject: [PATCH 2/2] Fixed some comments and typings in tests. --- libraries/core-react/src/Chip/Chip.test.tsx | 14 ++-- libraries/core-react/src/Chip/Chip.tsx | 81 +++++++++++---------- libraries/core-react/src/Chip/Icon.tsx | 2 +- 3 files changed, 52 insertions(+), 45 deletions(-) diff --git a/libraries/core-react/src/Chip/Chip.test.tsx b/libraries/core-react/src/Chip/Chip.test.tsx index f49ed0a805..2ad2c9e25a 100644 --- a/libraries/core-react/src/Chip/Chip.test.tsx +++ b/libraries/core-react/src/Chip/Chip.test.tsx @@ -16,7 +16,7 @@ const StyledChips = styled(Chip)` const { active: activeToken, error } = tokens -const rgbaTrim = (x) => x.split(' ').join('') +const rgbaTrim = (x: string) => x.split(' ').join('') afterEach(cleanup) @@ -63,8 +63,8 @@ describe('Chips', () => { const chipText = 'hello, I am a chip' const chipId = 'avatar-chip-test' let callbackId = '' - const handleDelete = jest.fn((x) => { - callbackId = x.target.parentElement.id + const handleDelete = jest.fn((x: React.MouseEvent) => { + callbackId = (x.target as HTMLElement).parentElement.id }) const { queryAllByTitle } = render( @@ -84,8 +84,8 @@ describe('Chips', () => { const chipText = 'hello, I am a chip' const chipId = 'avatar-chip-test' let callbackId = '' - const handleClick = jest.fn((x) => { - callbackId = x.target.id + const handleClick = jest.fn((x: React.MouseEvent) => { + callbackId = (x.target as HTMLElement).id }) const { container } = render( @@ -103,8 +103,8 @@ describe('Chips', () => { const chipText = 'hello, I am a chip' const chipId = 'avatar-chip-test' let callbackId = '' - const handleClick = jest.fn((x) => { - callbackId = x.target.id + const handleClick = jest.fn((x: React.MouseEvent) => { + callbackId = (x.target as HTMLElement).id }) const { container } = render( diff --git a/libraries/core-react/src/Chip/Chip.tsx b/libraries/core-react/src/Chip/Chip.tsx index f318233efc..04fef432f6 100644 --- a/libraries/core-react/src/Chip/Chip.tsx +++ b/libraries/core-react/src/Chip/Chip.tsx @@ -18,14 +18,19 @@ const { outlineOffset, } = tokens -type StyledChipsProps = { - clickable: boolean, - deletable: boolean, - variant: 'active' | 'error' | 'default', - disabled: boolean, +type StyleProps = { + variant: 'active' | 'error' | 'default' + clickable: boolean + deletable: boolean + disabled: boolean } -const StyledChips = styled.div` +const StyledChips = styled.div.attrs( + ({ clickable, deletable }) => ({ + tabIndex: clickable || deletable ? 0 : null, + role: clickable ? 'button' : null, + }), +)` background: ${enabled.background}; height: ${enabled.height}; width: fit-content; @@ -35,8 +40,6 @@ const StyledChips = styled.div` grid-auto-columns: max-content; align-items: center; z-index: 999; - tabIndex: ${({ clickable, deletable }) => (clickable || deletable ? 0 : null)}, - role: ${({ clickable }) => (clickable ? 'button' : null)}, svg { fill: ${enabled.typography.color}; @@ -125,15 +128,18 @@ const StyledChips = styled.div` `} ${({ children }) => - (typeof children === 'string') && + typeof children === 'string' && css` padding-left: 8px; `} ` type Props = { - disabled?: boolean, - onDelete?: (Event) => void, - variant?: 'active' | 'error' | 'default', + /** Disabled */ + disabled?: boolean + /** Delete callback */ + onDelete?: (Event) => void + /** Variant */ + variant?: 'active' | 'error' | 'default' } & React.HTMLAttributes export const Chip = forwardRef(function EdsChips( @@ -142,11 +148,11 @@ export const Chip = forwardRef(function EdsChips( onDelete, disabled = false, onClick, - variant= 'default', - ...other }, + variant = 'default', + ...other + }, ref, ) { - const handleDelete = disabled ? undefined : onDelete const handleClick = disabled ? undefined : onClick @@ -177,16 +183,19 @@ export const Chip = forwardRef(function EdsChips( } } - const resizedChildren = React.Children.map(children, (child: React.DetailedReactHTMLElement) => { - // We force size on Icon & Avatar component - if (child.props && child.props.size) { - return React.cloneElement(child, { - size: 16, - disabled, - }) - } - return child - }) + const resizedChildren = React.Children.map( + children, + (child: React.ReactElement) => { + // We force size on Icon & Avatar component + if (child.props && child.props.size) { + return React.cloneElement(child, { + size: 16, + disabled, + }) + } + return child + }, + ) const onDeleteClick = (event) => { event.stopPropagation() @@ -202,18 +211,16 @@ export const Chip = forwardRef(function EdsChips( onKeyPress={handleKeyPress} > {resizedChildren} - {onDelete && - ( - - ) - } + {onDelete && ( + + )} ) }) diff --git a/libraries/core-react/src/Chip/Icon.tsx b/libraries/core-react/src/Chip/Icon.tsx index 3e4c280a6f..1961b2420d 100644 --- a/libraries/core-react/src/Chip/Icon.tsx +++ b/libraries/core-react/src/Chip/Icon.tsx @@ -8,7 +8,7 @@ Icon_.add({ close }) const { enabled, hover, error } = tokens type IconProps = { - variant: 'active' | 'error' | 'default', + variant: 'active' | 'error' | 'default' disabled: boolean }