From 27aaa262cbfbe5cddcfa0e5f16abc1da06b4ffb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Wed, 2 Jan 2019 20:55:38 +0100 Subject: [PATCH 1/6] refactor: simplify Checkbox/Toggle + type Box css --- src/Box.tsx | 8 ++- src/Checkbox.tsx | 142 +++++++++++++++---------------------------- src/Menu.tsx | 8 +-- src/Toggle.tsx | 155 ++++++++++++++++++----------------------------- 4 files changed, 117 insertions(+), 196 deletions(-) diff --git a/src/Box.tsx b/src/Box.tsx index 03d0f9d7..3865a57c 100644 --- a/src/Box.tsx +++ b/src/Box.tsx @@ -1,6 +1,6 @@ /* @jsx jsx */ -import { jsx } from '@emotion/core'; +import { Interpolation, jsx } from '@emotion/core'; import { ComponentClass, CSSProperties, forwardRef, FunctionComponent, HTMLAttributes, ReactHTML } from 'react'; import * as ss from 'styled-system'; @@ -108,7 +108,7 @@ export const Box = forwardRef>((props, /** User provided style get pushed on last. */ if (style) css.push(style); - return jsx>>( + return jsx>>( as, { ...rest, @@ -119,6 +119,8 @@ export const Box = forwardRef>((props, ); }); +export type IBoxCSS = Interpolation | Interpolation[]; + export interface IBox extends HTMLAttributes, sl.ITextDecorationProps, @@ -156,6 +158,6 @@ export interface IBox as?: keyof ReactHTML | FunctionComponent | ComponentClass; children?: any; style?: CSSProperties; - css?: any; + css?: IBoxCSS; [key: string]: any; } diff --git a/src/Checkbox.tsx b/src/Checkbox.tsx index b2aced59..dfd40544 100644 --- a/src/Checkbox.tsx +++ b/src/Checkbox.tsx @@ -2,115 +2,73 @@ import { jsx } from '@emotion/core'; import { Omit } from '@stoplight/types'; -import noop = require('lodash/noop'); -import { FunctionComponent, ReactEventHandler, useState } from 'react'; +import { ChangeEventHandler, FunctionComponent, useCallback, useState } from 'react'; -import { Box, Flex, IBox, Icon, useTheme } from './'; +import { Box, Flex, IBox, useTheme } from './'; -interface ICheckboxInputProps { - id: IBox['id']; - onChange: ReactEventHandler; -} +export const Checkbox: FunctionComponent = props => { + const { id, disabled: isDisabled, onChange, ...rest } = props; -interface ICheckboxInput extends ICheckboxInputProps {} + const [checked, setValue] = useState(props.checked || false); + const isChecked = props.hasOwnProperty('checked') ? props.checked : checked; -const CheckboxInput: FunctionComponent = props => { - return jsx(Box, { - ...props, - as: 'input', - type: 'checkbox', - position: 'absolute', - style: { - clip: 'rect(1px, 1px, 1px, 1px)', - }, - }); + const css = checkboxStyles({ isDisabled, isChecked }); + + const handleChange = useCallback>(({ target }) => { + setValue(target.checked); + if (onChange !== undefined) { + onChange(target.checked); + } + }, []); + + return ( + + + + + ); }; -interface ICheckboxInnerProps { - isChecked: boolean; - isDisabled: boolean; - width?: IBox['width']; - height?: IBox['height']; +export interface ICheckboxProps { + id: IBox['id']; + onChange?: (checked: boolean) => void; } -export interface ICheckboxInner extends ICheckboxInnerProps {} - -const CheckboxInner: FunctionComponent = props => { - const css = checkboxInnerStyles(props); - - return jsx( - Flex, - { - as: 'span', - css, - }, - props.isChecked && [jsx(Icon, { icon: 'check', backgroundColor: 'inherit' })] - ); -}; +export interface ICheckbox extends ICheckboxProps, Omit, 'as|onChange'> {} -const checkboxInnerStyles = ({ isDisabled, isChecked, height = '20px', width = '20px' }: ICheckboxInner) => { +export const checkboxStyles = ({ isChecked, isDisabled }: ICheckboxStyles) => { const theme = useTheme(); return { - margin: 0, - padding: 0, - borderRadius: '5px', + alignItems: 'center', backgroundColor: isChecked ? theme.checkbox.checkedBg : theme.checkbox.bg, - color: theme.checkbox.fg, + borderRadius: '5px', + color: isChecked ? theme.checkbox.fg : theme.checkbox.bg, cursor: isDisabled ? 'not-allowed' : 'pointer', - width, - height, - opacity: isDisabled ? 0.6 : 1, - fontSize: '14px', - alignItems: 'center', + height: '20px', justifyContent: 'center', - transition: 'background-color .15s ease-in-out', + opacity: isDisabled ? 0.6 : 1, overflow: 'hidden', + margin: 0, + padding: 0, + width: '20px', + transition: 'background-color .15s ease-in-out', }; }; -export const Checkbox: FunctionComponent = props => { - const { id, disabled: isDisabled, width, height, onChange = noop, ...rest } = props; - const css = checkboxStyles(); - - const [checked, setValue] = useState(props.checked || false); - const isChecked = props.hasOwnProperty('checked') ? props.checked : checked; - - const handleChange: ReactEventHandler = event => { - setValue(event.currentTarget.checked); - onChange(event.currentTarget.checked); - }; - - return jsx( - Box, - { - ...rest, - as: 'label', - htmlFor: id, - css, - }, - [ - jsx(CheckboxInput, { - id, - onChange: handleChange, - }), - jsx(CheckboxInner, { - isChecked, - isDisabled, - height, - width, - }), - ] - ); -}; - -export interface ICheckboxProps { - id: IBox['id']; - onChange?: (checked: boolean) => void; +interface ICheckboxStyles { + isChecked: boolean; + isDisabled: boolean; } - -export interface ICheckbox extends ICheckboxProps, Omit, 'as|onChange'> {} - -export const checkboxStyles = () => ({ - display: 'inline-block', -}); diff --git a/src/Menu.tsx b/src/Menu.tsx index fe5cb8fc..13a7854b 100644 --- a/src/Menu.tsx +++ b/src/Menu.tsx @@ -4,7 +4,7 @@ import { jsx } from '@emotion/core'; import { FunctionComponent, ReactNode } from 'react'; -import { Box } from './Box'; +import { Box, IBoxCSS } from './Box'; import { Flex, IFlex } from './Flex'; import { useHover } from './hooks/useHover'; import { Icon, IIcon } from './Icon'; @@ -167,15 +167,15 @@ export interface IMenuItemProps { export interface IMenuItem extends IMenuItemProps, Pick> {} -const menuItemStyles = ({ disabled, onClick }: Partial) => { +const menuItemStyles = ({ disabled, onClick }: Partial): IBoxCSS => { const theme = useTheme(); return [ { alignItems: 'center', - padding: '6px 10px', // @md @lg' + padding: '6px 10px', cursor: disabled ? 'not-allowed' : onClick ? 'pointer' : 'default', - opacity: disabled && 0.6, + opacity: disabled ? 0.6 : 1, ':hover': { backgroundColor: theme.menu.hoverBg, diff --git a/src/Toggle.tsx b/src/Toggle.tsx index c3e49957..0f563616 100644 --- a/src/Toggle.tsx +++ b/src/Toggle.tsx @@ -2,130 +2,91 @@ import { jsx } from '@emotion/core'; import { Omit } from '@stoplight/types'; -import noop = require('lodash/noop'); -import { FunctionComponent, ReactEventHandler, SyntheticEvent, useState } from 'react'; +import { ChangeEventHandler, FunctionComponent, useCallback, useState } from 'react'; -import { Box, Flex, IBox, useTheme } from './'; -import { Icon } from './Icon'; +import { Box, Flex, IBox, IBoxCSS, useTheme } from './'; -interface IToggleInputProps { - id?: string; - onChange: ReactEventHandler; -} +const ToggleCircle: FunctionComponent = props => { + const css = circleStyles(props); -const ToggleInput: FunctionComponent = props => { - return jsx(Box, { - ...props, - as: 'input', - type: 'checkbox', - css: { - position: 'absolute', - }, - style: { - clip: 'rect(1px, 1px, 1px, 1px)', - }, - }); + return ; }; -interface IToggleInnerProps { +interface IToggleCircleProps { isChecked: boolean; - isDisabled: boolean; - height?: IBox['height']; - width?: IBox['width']; } -const ToggleInnerIcon: FunctionComponent = props => { - const css = toggleInnerIconStyles(props); - - return jsx(Icon, { - icon: 'circle', - css, - }); -}; +interface IToggleCircle extends IToggleCircleProps {} -const toggleInnerIconStyles = ({ isChecked }: IToggleInnerProps) => { +const circleStyles = ({ isChecked }: IToggleCircleProps) => { const theme = useTheme(); return { - color: isChecked ? theme.toggle.checkedFg : theme.toggle.checkedBg, - paddingLeft: isChecked ? '22px' : '4px', - transition: 'padding-left .15s ease-in-out, color .25s ease-in-out', + display: 'inline-block', + borderRadius: '50%', + width: '14px', + height: '14px', + backgroundColor: isChecked ? theme.toggle.checkedFg : theme.toggle.checkedBg, + marginLeft: isChecked ? '22px' : '4px', + transition: 'margin-left .15s ease-in-out, background-color .25s ease-in-out', }; }; -const ToggleInner: FunctionComponent = props => { - const css = toggleInnerStyles(props); +export const Toggle: FunctionComponent = props => { + const { id, disabled: isDisabled, onChange, ...rest } = props; - return jsx( - Flex, - { - as: 'span', - css, - }, - [jsx(ToggleInnerIcon, props)] + const [checked, setValue] = useState(props.checked || false); + const isChecked = props.hasOwnProperty('checked') ? props.checked : checked; + + const css = toggleStyles({ isDisabled, isChecked }); + + const handleChange = useCallback>(({ target }) => { + setValue(target.checked); + if (onChange !== undefined) { + onChange(target.checked); + } + }, []); + + return ( + + + + ); }; -const toggleInnerStyles = ({ isDisabled, isChecked, height = '20px', width = '40px' }: IToggleInnerProps) => { +export interface IToggleProps { + onChange?: (checked: boolean) => void; +} + +export interface IToggle extends IToggleProps, Omit, 'as|onChange'> {} + +const toggleStyles = ({ isDisabled, isChecked }: IToggleStyles): IBoxCSS => { const theme = useTheme(); return { - display: 'block', - margin: 0, - padding: 0, - borderRadius: '100px', + alignItems: 'center', backgroundColor: isChecked ? theme.toggle.checkedBg : theme.toggle.bg, + borderRadius: '100px', cursor: isDisabled ? 'not-allowed' : 'pointer', - width, - height, - opacity: isDisabled ? 0.6 : 1, fontSize: '14px', - alignItems: 'center', + height: '20px', + opacity: isDisabled ? 0.6 : 1, + padding: 0, + margin: 0, + width: '40px', transition: 'background-color .15s ease-in-out', }; }; -export const Toggle: FunctionComponent = props => { - const { id, disabled, height, width, onChange = noop, ...rest } = props; - const css = toggleStyles(); - - const [checked, setValue] = useState(props.checked || false); - const isChecked = props.hasOwnProperty('checked') ? props.checked : checked; - - const handleChange = (event: SyntheticEvent) => { - setValue(event.currentTarget.checked); - onChange(event.currentTarget.checked); - }; - - return jsx( - Box, - { - ...rest, - as: 'label', - htmlFor: id, - css, - }, - [ - jsx(ToggleInput, { - id, - onChange: handleChange, - }), - jsx(ToggleInner, { - isChecked, - isDisabled: !!disabled, - height, - width, - }), - ] - ); -}; - -export interface IToggleProps { - onChange?: (checked: boolean) => void; +interface IToggleStyles { + isChecked: boolean; + isDisabled: boolean; } - -export interface IToggle extends IToggleProps, Omit, 'as|onChange'> {} - -const toggleStyles = () => ({ - display: 'inline-block', -}); From 5cc8b71eea1b73274d8b3316f05e562d3985e2fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Wed, 2 Jan 2019 21:08:48 +0100 Subject: [PATCH 2/6] feat: box component supports cursor and visibility --- src/Box.tsx | 13 ++++++++++--- src/List.tsx | 10 +++------- src/__stories__/Typography/Text.tsx | 2 +- src/styles.ts | 18 ++++++++++++++++++ 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/Box.tsx b/src/Box.tsx index 3865a57c..01672438 100644 --- a/src/Box.tsx +++ b/src/Box.tsx @@ -19,6 +19,7 @@ export const Box = forwardRef>((props, borderRight, borderRadius, boxShadow, + cursor, display, fontSize, fontWeight, @@ -62,6 +63,7 @@ export const Box = forwardRef>((props, color, backgroundColor, transform, + visibility, ...rest } = props; @@ -103,6 +105,8 @@ export const Box = forwardRef>((props, sl.color({ color, backgroundColor }), sl.textTransform({ textTransform }), sl.textDecoration({ textDecoration, textDecorationColor }), + sl.cursor({ cursor }), + sl.visibility({ visibility }), ]; /** User provided style get pushed on last. */ @@ -119,12 +123,13 @@ export const Box = forwardRef>((props, ); }); -export type IBoxCSS = Interpolation | Interpolation[]; - export interface IBox extends HTMLAttributes, + sl.IColorProps, sl.ITextDecorationProps, - sl.IListStyleProps, + sl.ITextTransformProps, + sl.IVisibilityProps, + sl.ICursorProps, ss.BorderProps, ss.BorderTopProps, ss.BorderBottomProps, @@ -161,3 +166,5 @@ export interface IBox css?: IBoxCSS; [key: string]: any; } + +export type IBoxCSS = Interpolation | Interpolation[]; diff --git a/src/List.tsx b/src/List.tsx index 374d26ec..bbc68c60 100644 --- a/src/List.tsx +++ b/src/List.tsx @@ -10,16 +10,12 @@ import * as sl from './styles'; export const List: FunctionComponent = props => { const { as = 'ul', listStyle, listStylePosition, ...rest } = props; - const css = [sl.listStyle({ listStyle, listStylePosition })]; + const css = sl.listStyle({ listStyle, listStylePosition }); - return jsx(Box, { - ...rest, - css, - as, - }); + return ; }; -export interface IList extends IListProps, sl.IColorProps, Omit, 'as'> {} +export interface IList extends IListProps, sl.IListStyleProps, Omit, 'as'> {} export interface IListProps { as?: 'ul' | 'ol'; diff --git a/src/__stories__/Typography/Text.tsx b/src/__stories__/Typography/Text.tsx index b109b5c9..8d3922ec 100644 --- a/src/__stories__/Typography/Text.tsx +++ b/src/__stories__/Typography/Text.tsx @@ -14,7 +14,7 @@ export const textKnobs = (tabName = 'Text'): IText => ({ ...boxKnobs(), tracking: select('tracking', LetterSpacing, '', tabName), leading: select('leading', LineHeight, '', tabName), - casing: select('casing', Casing, '', tabName), + casing: select('casing', Casing, '', tabName) as IText['textTransform'], textDecoration: select('textDecoration', Decoration, '', tabName), textDecorationColor: text('textDecorationColor', 'valid-color', tabName), italic: boolean('italic', false, tabName), diff --git a/src/styles.ts b/src/styles.ts index f5a6ca8d..0dd041c1 100644 --- a/src/styles.ts +++ b/src/styles.ts @@ -1,6 +1,7 @@ import { BackgroundColorProperty, ColorProperty, + CursorProperty, FlexFlowProperty, ListStylePositionProperty, ListStyleProperty, @@ -8,6 +9,7 @@ import { TextDecorationProperty, TextTransformProperty, TransformProperty, + VisibilityProperty, } from 'csstype'; export interface IColorProps { @@ -63,3 +65,19 @@ export interface IFlexFlowProperty { export const flexFlow = (props: IFlexFlowProperty) => ({ flexFlow: props.flexFlow, }); + +export interface ICursorProps { + cursor?: CursorProperty; +} + +export const cursor = (props: ICursorProps) => ({ + cursor: props.cursor, +}); + +export interface IVisibilityProps { + visibility?: VisibilityProperty; +} + +export const visibility = (props: IVisibilityProps) => ({ + visibility: props.visibility, +}); From ec9285f9efa33c39a3a0df534fe619f9049e9baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Wed, 2 Jan 2019 23:18:30 +0100 Subject: [PATCH 3/6] test: some smoke tests for Checkbox and Toggle --- src/__tests__/Checkbox.spec.tsx | 67 +++++++++++++++++++++++++++++++++ src/__tests__/Toggle.spec.tsx | 64 +++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 src/__tests__/Checkbox.spec.tsx create mode 100644 src/__tests__/Toggle.spec.tsx diff --git a/src/__tests__/Checkbox.spec.tsx b/src/__tests__/Checkbox.spec.tsx new file mode 100644 index 00000000..5105394e --- /dev/null +++ b/src/__tests__/Checkbox.spec.tsx @@ -0,0 +1,67 @@ +import { mount } from 'enzyme'; +import 'jest-enzyme'; +import * as React from 'react'; + +import { ICheckbox } from '../Checkbox'; +import { ITheme } from '../theme'; + +describe('Checkbox component', () => { + let Checkbox: React.FunctionComponent; + + const theme: Partial = { + checkbox: { + fg: 'blue', + bg: 'red', + checkedBg: 'green', + }, + }; + + beforeAll(async () => { + jest.mock('../theme', () => ({ + useTheme: jest.fn().mockReturnValue(theme), + })); + + ({ Checkbox } = await import('../')); + }); + + afterAll(() => { + jest.unmock('../theme'); + }); + + it('passes all custom props', () => { + const props = { + onBlur: jest.fn(), + onFocus: jest.fn(), + }; + + const wrapper = mount(); + expect(wrapper).toHaveProp(props); + wrapper.unmount(); + }); + + it('renders svg icon', () => { + const wrapper = mount(); + expect(wrapper.find('svg')).toExist(); + wrapper.unmount(); + }); + + it('calls onChange handler with given state', () => { + const onChange = jest.fn(); + + const wrapper = mount(); + wrapper.find('input').simulate('change', { + target: { + checked: true, + }, + }); + expect(onChange).toHaveBeenLastCalledWith(true); + + wrapper.find('input').simulate('change', { + target: { + checked: false, + }, + }); + expect(onChange).toHaveBeenLastCalledWith(false); + wrapper.unmount(); + }); +}); diff --git a/src/__tests__/Toggle.spec.tsx b/src/__tests__/Toggle.spec.tsx new file mode 100644 index 00000000..da6baa5c --- /dev/null +++ b/src/__tests__/Toggle.spec.tsx @@ -0,0 +1,64 @@ +import { mount } from 'enzyme'; +import 'jest-enzyme'; +import * as React from 'react'; + +import { ITheme } from '../theme'; +import { IToggle } from '../Toggle'; + +describe('Toggle component', () => { + let Toggle: React.FunctionComponent; + + const theme: Partial = { + toggle: { + fg: 'blue', + bg: 'red', + border: 'green', + checkedBg: 'orange', + checkedFg: 'black', + checkedBorder: 'white', + }, + }; + + beforeAll(async () => { + jest.mock('../theme', () => ({ + useTheme: jest.fn().mockReturnValue(theme), + })); + + ({ Toggle } = await import('../')); + }); + + afterAll(() => { + jest.unmock('../theme'); + }); + + it('passes all custom props', () => { + const props = { + onBlur: jest.fn(), + onFocus: jest.fn(), + }; + + const wrapper = mount(); + expect(wrapper).toHaveProp(props); + wrapper.unmount(); + }); + + it('calls onChange handler with given state', () => { + const onChange = jest.fn(); + + const wrapper = mount(); + wrapper.find('input').simulate('change', { + target: { + checked: true, + }, + }); + expect(onChange).toHaveBeenLastCalledWith(true); + + wrapper.find('input').simulate('change', { + target: { + checked: false, + }, + }); + expect(onChange).toHaveBeenLastCalledWith(false); + wrapper.unmount(); + }); +}); From 5c1caaa7b57f6993786b10156877b9b3822069fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Thu, 3 Jan 2019 23:30:31 +0100 Subject: [PATCH 4/6] fix: support overflow, cursor and visibility rules --- src/Box.tsx | 11 ++++++++--- src/styles.ts | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/Box.tsx b/src/Box.tsx index 01672438..b6b7a5c8 100644 --- a/src/Box.tsx +++ b/src/Box.tsx @@ -18,6 +18,7 @@ export const Box = forwardRef>((props, borderLeft, borderRight, borderRadius, + borderColor, boxShadow, cursor, display, @@ -57,6 +58,8 @@ export const Box = forwardRef>((props, maxWidth, opacity, overflow, + overflowX, + overflowY, textDecoration, textDecorationColor, textTransform, @@ -68,8 +71,9 @@ export const Box = forwardRef>((props, } = props; /** Add all the supported styles, passing in the relevant props. */ - const css = [ + const css: IBoxCSS = [ ss.borders({ border, borderTop, borderBottom, borderLeft, borderRight }), + ss.borderColor({ borderColor }), ss.borderRadius({ borderRadius }), ss.boxShadow({ boxShadow }), ss.space({ m, mt, mb, ml, mr, mx, my, p, pt, pb, pl, pr, px, py }), @@ -91,7 +95,6 @@ export const Box = forwardRef>((props, ss.minWidth({ minWidth }), ss.maxWidth({ maxWidth }), - ss.overflow({ overflow }), ss.position({ position }), ss.top({ top }), ss.bottom({ bottom }), @@ -107,10 +110,11 @@ export const Box = forwardRef>((props, sl.textDecoration({ textDecoration, textDecorationColor }), sl.cursor({ cursor }), sl.visibility({ visibility }), + sl.overflow({ overflow, overflowX, overflowY }), ]; /** User provided style get pushed on last. */ - if (style) css.push(style); + if (style) css.push(style as IBoxCSS); return jsx>>( as, @@ -129,6 +133,7 @@ export interface IBox sl.ITextDecorationProps, sl.ITextTransformProps, sl.IVisibilityProps, + sl.IOverflowProps, sl.ICursorProps, ss.BorderProps, ss.BorderTopProps, diff --git a/src/styles.ts b/src/styles.ts index 0dd041c1..1404b8b5 100644 --- a/src/styles.ts +++ b/src/styles.ts @@ -5,6 +5,9 @@ import { FlexFlowProperty, ListStylePositionProperty, ListStyleProperty, + OverflowProperty, + OverflowXProperty, + OverflowYProperty, TextDecorationColorProperty, TextDecorationProperty, TextTransformProperty, @@ -81,3 +84,15 @@ export interface IVisibilityProps { export const visibility = (props: IVisibilityProps) => ({ visibility: props.visibility, }); + +export const overflow = (props: IOverflowProps) => ({ + overflow: props.overflow, + overflowX: props.overflowX, + overflowY: props.overflowY, +}); + +export interface IOverflowProps { + overflow?: OverflowProperty; + overflowX?: OverflowXProperty; + overflowY?: OverflowYProperty; +} From 9164cb7146a7e2c299f81199fb5e56d76b02e574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Fri, 4 Jan 2019 10:21:05 +0100 Subject: [PATCH 5/6] fix: ts error --- src/__stories__/Layout/Box.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/__stories__/Layout/Box.tsx b/src/__stories__/Layout/Box.tsx index f58b538d..ecdc8496 100644 --- a/src/__stories__/Layout/Box.tsx +++ b/src/__stories__/Layout/Box.tsx @@ -63,9 +63,9 @@ export const boxKnobs = (tabName = 'Box' ), display: select('display', Display, '', tabName), overflow: select('overflow', OverFlow, '', tabName), - overflowX: select('overflowX', OverFlow, '', tabName), - overflowY: select('overflowY', OverFlow, '', tabName), - position: select('position', PositionOpts, '', tabName) as ss.PositionProps['position'], + overflowX: select('overflowX', OverFlow, '', tabName) as IBox['overflowX'], + overflowY: select('overflowX', OverFlow, '', tabName) as IBox['overflowY'], + position: select('position', PositionOpts, '', tabName) as IBox['position'], top: number('top', 0, {}, tabName), bottom: number('bottom', 0, {}, tabName), left: number('left', 0, {}, tabName), From 22522fccaa5d67560eb2001632d7aaf32e3f7707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Sun, 6 Jan 2019 20:51:12 +0100 Subject: [PATCH 6/6] fix: pass checked prop to Input --- src/Checkbox.tsx | 1 + src/Toggle.tsx | 1 + src/__tests__/Checkbox.spec.tsx | 10 ++++++++++ src/__tests__/Toggle.spec.tsx | 10 ++++++++++ 4 files changed, 22 insertions(+) diff --git a/src/Checkbox.tsx b/src/Checkbox.tsx index dfd40544..a49fe11e 100644 --- a/src/Checkbox.tsx +++ b/src/Checkbox.tsx @@ -27,6 +27,7 @@ export const Checkbox: FunctionComponent = props => { as="input" type="checkbox" id={id} + checked={checked} onChange={handleChange} position="absolute" css={{ clip: 'rect(1px, 1px, 1px, 1px)' }} diff --git a/src/Toggle.tsx b/src/Toggle.tsx index 0f563616..33bc1ce6 100644 --- a/src/Toggle.tsx +++ b/src/Toggle.tsx @@ -53,6 +53,7 @@ export const Toggle: FunctionComponent = props => { as="input" type="checkbox" id={id} + checked={checked} onChange={handleChange} position="absolute" css={{ clip: 'rect(1px, 1px, 1px, 1px)' }} diff --git a/src/__tests__/Checkbox.spec.tsx b/src/__tests__/Checkbox.spec.tsx index 5105394e..46137609 100644 --- a/src/__tests__/Checkbox.spec.tsx +++ b/src/__tests__/Checkbox.spec.tsx @@ -64,4 +64,14 @@ describe('Checkbox component', () => { expect(onChange).toHaveBeenLastCalledWith(false); wrapper.unmount(); }); + + it('passes checked prop to inner Input', () => { + let wrapper = mount(); + expect(wrapper.find('input')).toHaveProp('checked', true); + wrapper.unmount(); + + wrapper = mount(); + expect(wrapper.find('input')).toHaveProp('checked', false); + wrapper.unmount(); + }); }); diff --git a/src/__tests__/Toggle.spec.tsx b/src/__tests__/Toggle.spec.tsx index da6baa5c..5f1e1388 100644 --- a/src/__tests__/Toggle.spec.tsx +++ b/src/__tests__/Toggle.spec.tsx @@ -61,4 +61,14 @@ describe('Toggle component', () => { expect(onChange).toHaveBeenLastCalledWith(false); wrapper.unmount(); }); + + it('passes checked prop to inner Input', () => { + let wrapper = mount(); + expect(wrapper.find('input')).toHaveProp('checked', true); + wrapper.unmount(); + + wrapper = mount(); + expect(wrapper.find('input')).toHaveProp('checked', false); + wrapper.unmount(); + }); });