From cb165ca45db00e0d06d38b6b5319d015eed65790 Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Mon, 16 Dec 2019 09:42:04 -0700 Subject: [PATCH 01/23] chore: Refactor canvasProvider and extract util function --- .../_labs/core/react/lib/CanvasProvider.tsx | 16 +++++++++++---- .../_labs/core/react/lib/theming/styled.ts | 11 ++++++++-- .../react/stories/stories_iconButton.tsx | 4 ++++ utils/storybook/CanvasProviderDecorator.tsx | 20 ++++++++++++++----- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/modules/_labs/core/react/lib/CanvasProvider.tsx b/modules/_labs/core/react/lib/CanvasProvider.tsx index 84f723e880..7063283dba 100644 --- a/modules/_labs/core/react/lib/CanvasProvider.tsx +++ b/modules/_labs/core/react/lib/CanvasProvider.tsx @@ -7,24 +7,32 @@ import styled from '@emotion/styled'; export interface CanvasProviderProps { theme: CanvasTheme; + provideInputProvider: boolean; } const DirectionContainer = styled('bdo')<{dir: ContentDirection}>(({dir}) => ({ - direction: dir, + direction: dir })); -export default class CanvasProvider extends React.Component { +export default class CanvasProvider extends React.Component< + CanvasProviderProps +> { static defaultProps = { theme: defaultCanvasTheme, + provideInputProvider: true }; render() { - const {children, theme} = this.props; + const {children, theme, provideInputProvider} = this.props; return ( - {children} + {provideInputProvider ? ( + {children} + ) : ( + children + )} ); diff --git a/modules/_labs/core/react/lib/theming/styled.ts b/modules/_labs/core/react/lib/theming/styled.ts index c342d034c2..a6aaff66df 100644 --- a/modules/_labs/core/react/lib/theming/styled.ts +++ b/modules/_labs/core/react/lib/theming/styled.ts @@ -1,4 +1,9 @@ -import {default as emotionStyled, CreateStyled, Interpolation, CSSObject} from '@emotion/styled'; +import { + default as emotionStyled, + CreateStyled, + Interpolation, + CSSObject +} from '@emotion/styled'; import {CanvasTheme, ContentDirection, useTheme} from './'; import rtlCSSJS from 'rtl-css-js'; @@ -10,7 +15,9 @@ type Interpolations = Array; function styled(node: any) { return (...args: Interpolation[]) => { const newArgs: Interpolations = args.map( - interpolation => (props: Props & {theme: CanvasTheme; direction: ContentDirection}) => { + interpolation => ( + props: Props & {theme: CanvasTheme; direction: ContentDirection} + ) => { props.theme = useTheme(props.theme); const direction = props.theme.direction; const maybeFlip = direction === ContentDirection.RTL ? rtlCSSJS : noop; diff --git a/modules/button/react/stories/stories_iconButton.tsx b/modules/button/react/stories/stories_iconButton.tsx index 9fd7a763a4..83d3aba97d 100644 --- a/modules/button/react/stories/stories_iconButton.tsx +++ b/modules/button/react/stories/stories_iconButton.tsx @@ -4,6 +4,7 @@ import {jsx, CSSObject} from '@emotion/core'; import * as React from 'react'; import {storiesOf} from '@storybook/react'; import withReadme from 'storybook-readme/with-readme'; +import {CanvasProvider} from '@workday/canvas-kit-labs-react-core'; import { activityStreamIcon, @@ -62,12 +63,14 @@ export class ToggleIconButtonWrapper extends React.Component< public render() { return ( + // + // ); } @@ -108,6 +111,7 @@ storiesOf('Components|Buttons/Button/React/Icon Button', module) .add('Circle', () => (

Medium Default

+ React.ReactNode) => ( - - {storyFn()} - -); +export default makeDecorator({ + name: 'withCanvasProviderDecorator', + parameterName: 'canvasProviderDecorator', + wrapper: (storyFn, context, {parameters}) => { + return ( + + {storyFn(context)} + + ); + }, +}); From acad35d8bda7b740589fcfea680b4c63019937d4 Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Mon, 16 Dec 2019 13:27:54 -0700 Subject: [PATCH 02/23] chore: Rename function --- .../react/lib/utils/changeToStaticClass.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 modules/common/react/lib/utils/changeToStaticClass.ts diff --git a/modules/common/react/lib/utils/changeToStaticClass.ts b/modules/common/react/lib/utils/changeToStaticClass.ts new file mode 100644 index 0000000000..f9b21516f3 --- /dev/null +++ b/modules/common/react/lib/utils/changeToStaticClass.ts @@ -0,0 +1,28 @@ +import {CSSObject} from '@emotion/core'; + +/** + * Allows the ability to force a state by a pseudo selector by changing the selector into a class creating a new styled object with the class names + * @param shouldChangePseudoSelectors If true, it will replace pseudo selectors from the styled object and change them to classes + * @param obj The styled object passed to the function to replace any pseudo selectors with a class name + */ + +export const changeToStaticClass = ( + shouldChangePseudoSelectors = false, + obj?: CSSObject +): CSSObject | undefined => { + if (!shouldChangePseudoSelectors || !obj) { + return obj; + } + + return Object.keys(obj).reduce((result, key) => { + const newKey = key + .replace(/^:/, '&:') + .replace(/:/g, '.') + .replace(/\.not/g, ':not') + .replace(/\.disabled/, ':disabled'); + const value = + typeof obj[key] === 'object' ? changeToStaticClass(true, obj[key] as CSSObject) : obj[key]; + const newObj = {...result, [newKey]: value}; + return newObj; + }, {}); +}; From 47e16e001de9a4163adff137d6253fb444113e28 Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Mon, 16 Dec 2019 13:44:07 -0700 Subject: [PATCH 03/23] fix: Rename prop name --- modules/button/react/stories/stories_iconButton.tsx | 2 -- utils/storybook/CanvasProviderDecorator.tsx | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/button/react/stories/stories_iconButton.tsx b/modules/button/react/stories/stories_iconButton.tsx index 83d3aba97d..acb89663ee 100644 --- a/modules/button/react/stories/stories_iconButton.tsx +++ b/modules/button/react/stories/stories_iconButton.tsx @@ -63,14 +63,12 @@ export class ToggleIconButtonWrapper extends React.Component< public render() { return ( - // - // ); } diff --git a/utils/storybook/CanvasProviderDecorator.tsx b/utils/storybook/CanvasProviderDecorator.tsx index 7b743fe416..8f0e91c785 100644 --- a/utils/storybook/CanvasProviderDecorator.tsx +++ b/utils/storybook/CanvasProviderDecorator.tsx @@ -15,7 +15,7 @@ export default makeDecorator({ wrapper: (storyFn, context, {parameters}) => { return ( {storyFn(context)} From 0ae64b38443e61c015183cd64cbfdc6101827a28 Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Mon, 16 Dec 2019 13:46:05 -0700 Subject: [PATCH 04/23] fix: Remove unused import --- modules/button/react/stories/stories_iconButton.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/button/react/stories/stories_iconButton.tsx b/modules/button/react/stories/stories_iconButton.tsx index acb89663ee..c94d34cbbf 100644 --- a/modules/button/react/stories/stories_iconButton.tsx +++ b/modules/button/react/stories/stories_iconButton.tsx @@ -4,7 +4,6 @@ import {jsx, CSSObject} from '@emotion/core'; import * as React from 'react'; import {storiesOf} from '@storybook/react'; import withReadme from 'storybook-readme/with-readme'; -import {CanvasProvider} from '@workday/canvas-kit-labs-react-core'; import { activityStreamIcon, From e2eb14d3bdb9eb7dc163a2ca83d9ac26c81f7e7d Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Mon, 16 Dec 2019 13:52:58 -0700 Subject: [PATCH 05/23] fix: Remove space added --- modules/button/react/stories/stories_iconButton.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/button/react/stories/stories_iconButton.tsx b/modules/button/react/stories/stories_iconButton.tsx index c94d34cbbf..9fd7a763a4 100644 --- a/modules/button/react/stories/stories_iconButton.tsx +++ b/modules/button/react/stories/stories_iconButton.tsx @@ -108,7 +108,6 @@ storiesOf('Components|Buttons/Button/React/Icon Button', module) .add('Circle', () => (

Medium Default

- Date: Mon, 16 Dec 2019 16:10:44 -0700 Subject: [PATCH 06/23] chore: Rebase and rename prop --- utils/storybook/CanvasProviderDecorator.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/storybook/CanvasProviderDecorator.tsx b/utils/storybook/CanvasProviderDecorator.tsx index 8f0e91c785..7b743fe416 100644 --- a/utils/storybook/CanvasProviderDecorator.tsx +++ b/utils/storybook/CanvasProviderDecorator.tsx @@ -15,7 +15,7 @@ export default makeDecorator({ wrapper: (storyFn, context, {parameters}) => { return ( {storyFn(context)} From f48e7cea9dbf7ef44d663c86edb6229a386e9ff4 Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Mon, 16 Dec 2019 16:13:42 -0700 Subject: [PATCH 07/23] fix: Fix merging conflicts --- .../_labs/core/react/lib/CanvasProvider.tsx | 18 ++++++------------ modules/_labs/core/react/lib/theming/styled.ts | 11 ++--------- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/modules/_labs/core/react/lib/CanvasProvider.tsx b/modules/_labs/core/react/lib/CanvasProvider.tsx index 7063283dba..1f97ae1e3c 100644 --- a/modules/_labs/core/react/lib/CanvasProvider.tsx +++ b/modules/_labs/core/react/lib/CanvasProvider.tsx @@ -7,32 +7,26 @@ import styled from '@emotion/styled'; export interface CanvasProviderProps { theme: CanvasTheme; - provideInputProvider: boolean; + includeInputProvider: boolean; } const DirectionContainer = styled('bdo')<{dir: ContentDirection}>(({dir}) => ({ - direction: dir + direction: dir, })); -export default class CanvasProvider extends React.Component< - CanvasProviderProps -> { +export default class CanvasProvider extends React.Component { static defaultProps = { theme: defaultCanvasTheme, - provideInputProvider: true + includeInputProvider: true, }; render() { - const {children, theme, provideInputProvider} = this.props; + const {children, theme, includeInputProvider} = this.props; return ( - {provideInputProvider ? ( - {children} - ) : ( - children - )} + {includeInputProvider ? {children} : children} ); diff --git a/modules/_labs/core/react/lib/theming/styled.ts b/modules/_labs/core/react/lib/theming/styled.ts index a6aaff66df..c342d034c2 100644 --- a/modules/_labs/core/react/lib/theming/styled.ts +++ b/modules/_labs/core/react/lib/theming/styled.ts @@ -1,9 +1,4 @@ -import { - default as emotionStyled, - CreateStyled, - Interpolation, - CSSObject -} from '@emotion/styled'; +import {default as emotionStyled, CreateStyled, Interpolation, CSSObject} from '@emotion/styled'; import {CanvasTheme, ContentDirection, useTheme} from './'; import rtlCSSJS from 'rtl-css-js'; @@ -15,9 +10,7 @@ type Interpolations = Array; function styled(node: any) { return (...args: Interpolation[]) => { const newArgs: Interpolations = args.map( - interpolation => ( - props: Props & {theme: CanvasTheme; direction: ContentDirection} - ) => { + interpolation => (props: Props & {theme: CanvasTheme; direction: ContentDirection}) => { props.theme = useTheme(props.theme); const direction = props.theme.direction; const maybeFlip = direction === ContentDirection.RTL ? rtlCSSJS : noop; From d49dc803fcb235a68c888d8aca67c3b717c4e08a Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Mon, 16 Dec 2019 16:15:50 -0700 Subject: [PATCH 08/23] fix: Rename prop for decorator --- utils/storybook/CanvasProviderDecorator.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/storybook/CanvasProviderDecorator.tsx b/utils/storybook/CanvasProviderDecorator.tsx index 7b743fe416..8f0e91c785 100644 --- a/utils/storybook/CanvasProviderDecorator.tsx +++ b/utils/storybook/CanvasProviderDecorator.tsx @@ -15,7 +15,7 @@ export default makeDecorator({ wrapper: (storyFn, context, {parameters}) => { return ( {storyFn(context)} From 39a06f1924f8eb3d7ccd86674ed78c1c73766478 Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Mon, 16 Dec 2019 17:16:01 -0700 Subject: [PATCH 09/23] fix: Rename prop and add readme --- modules/_labs/core/react/README.md | 22 +++++++++++++++++++ .../_labs/core/react/lib/CanvasProvider.tsx | 8 +++---- utils/storybook/CanvasProviderDecorator.tsx | 4 ++-- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/modules/_labs/core/react/README.md b/modules/_labs/core/react/README.md index 6299788ebb..116ce850e2 100644 --- a/modules/_labs/core/react/README.md +++ b/modules/_labs/core/react/README.md @@ -111,6 +111,16 @@ import {CanvasProvider} from '@workday/canvas-kit-react'; {/* All your components containing any Canvas components */}; ``` +If you'd like to disable `InputProvider` you can pass `disableInputProvider` which will disable InputProvider for all your components that are being wrapped by CanvasProvider + +```tsx +import * as React from 'react'; +import {CanvasProvider} from '@workday/canvas-kit-react'; + +{/* All your components containing any Canvas components */}; +``` + + #### Storybook Decorator We provide a [storybook decorator](../../utils/storybook/CanvasProviderDecorator.tsx) to wrap your @@ -134,6 +144,18 @@ storiesOf('My Story', module) .add('All', () => ); ``` +If you want to disable `InputProvider` for a specific story, you can add a parameter to disable it: + +```js +import {CanvasProviderDecorator} from '../../../../utils/storybook'; + +storiesOf('My Story', module) + .addDecorator(CanvasProviderDecorator) + .addParameters(canvasProviderDecorator: { disableInputProvider: true }) + .add('All', () => ); +``` + + ### Input Provider See the [@workday/canvas-kit-react-core docs](../../../core/react/README.md#input-provider) diff --git a/modules/_labs/core/react/lib/CanvasProvider.tsx b/modules/_labs/core/react/lib/CanvasProvider.tsx index 1f97ae1e3c..709faa830b 100644 --- a/modules/_labs/core/react/lib/CanvasProvider.tsx +++ b/modules/_labs/core/react/lib/CanvasProvider.tsx @@ -7,7 +7,7 @@ import styled from '@emotion/styled'; export interface CanvasProviderProps { theme: CanvasTheme; - includeInputProvider: boolean; + disableInputProvider: boolean; } const DirectionContainer = styled('bdo')<{dir: ContentDirection}>(({dir}) => ({ @@ -17,16 +17,16 @@ const DirectionContainer = styled('bdo')<{dir: ContentDirection}>(({dir}) => ({ export default class CanvasProvider extends React.Component { static defaultProps = { theme: defaultCanvasTheme, - includeInputProvider: true, + disableInputProvider: false, }; render() { - const {children, theme, includeInputProvider} = this.props; + const {children, theme, disableInputProvider} = this.props; return ( - {includeInputProvider ? {children} : children} + {!disableInputProvider ? {children} : children} ); diff --git a/utils/storybook/CanvasProviderDecorator.tsx b/utils/storybook/CanvasProviderDecorator.tsx index 8f0e91c785..b9606f1a78 100644 --- a/utils/storybook/CanvasProviderDecorator.tsx +++ b/utils/storybook/CanvasProviderDecorator.tsx @@ -10,12 +10,12 @@ import {makeDecorator} from '@storybook/addons'; const label = 'theme'; export default makeDecorator({ - name: 'withCanvasProviderDecorator', + name: 'canvasProviderDecorator', parameterName: 'canvasProviderDecorator', wrapper: (storyFn, context, {parameters}) => { return ( {storyFn(context)} From b57196e5ac3b738d1fd336c5c40aa4b22d9d51bb Mon Sep 17 00:00:00 2001 From: Nicholas Boll Date: Tue, 17 Dec 2019 15:55:28 -0700 Subject: [PATCH 10/23] feat: Add wrapper for staticState utility function --- modules/button/react/lib/Button.tsx | 5 +- modules/button/react/lib/ButtonBase.tsx | 35 ++++++----- modules/button/react/stories/stories.tsx | 56 +---------------- modules/common/react/index.ts | 1 + .../react/lib/utils/changeToStaticClass.ts | 28 --------- .../react/lib/utils/changeToStaticStates.ts | 62 +++++++++++++++++++ .../react/spec/changeToStaticStates.spec.ts | 13 ++++ 7 files changed, 100 insertions(+), 100 deletions(-) delete mode 100644 modules/common/react/lib/utils/changeToStaticClass.ts create mode 100644 modules/common/react/lib/utils/changeToStaticStates.ts create mode 100644 modules/common/react/spec/changeToStaticStates.spec.ts diff --git a/modules/button/react/lib/Button.tsx b/modules/button/react/lib/Button.tsx index 8c47cb43d2..4e8aa92aec 100644 --- a/modules/button/react/lib/Button.tsx +++ b/modules/button/react/lib/Button.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import {ButtonBaseCon, ButtonBaseLabel, ButtonLabelData, ButtonLabelIcon} from './ButtonBase'; import {DeprecatedButtonVariant, ButtonSize, ButtonVariant} from './types'; import {CanvasSystemIcon} from '@workday/design-assets-types'; -import {GrowthBehavior} from '@workday/canvas-kit-react-common'; +import {GrowthBehavior, ChangeStaticStateProps} from '@workday/canvas-kit-react-common'; import {labelDataBaseStyles} from './ButtonStyles'; export interface BaseButtonProps @@ -33,7 +33,8 @@ export interface BaseButtonProps export interface ButtonProps extends BaseButtonProps, - GrowthBehavior { + GrowthBehavior, + ChangeStaticStateProps { /** * Button cannot be empty. */ diff --git a/modules/button/react/lib/ButtonBase.tsx b/modules/button/react/lib/ButtonBase.tsx index f821e3104d..3b5bdbc7d4 100644 --- a/modules/button/react/lib/ButtonBase.tsx +++ b/modules/button/react/lib/ButtonBase.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import styled from '@emotion/styled'; import isPropValid from '@emotion/is-prop-valid'; +import {convertToStaticStates} from '@workday/canvas-kit-react-common'; import { ButtonSize, DeprecatedButtonVariant, @@ -16,23 +17,25 @@ import {getBaseButton, getButtonSize, getButtonStyle} from './utils'; export const ButtonBaseCon = styled('button', { shouldForwardProp: prop => isPropValid(prop) && prop !== 'size', })( - /* istanbul ignore next line for coverage */ - ({variant, size}) => { - if (variant === undefined) { - return {}; - } - - const baseButton = getBaseButton(variant); - const buttonStyles = getButtonStyle(baseButton, variant); - const sizeStyles = size !== undefined ? getButtonSize(baseButton, size) : {}; + convertToStaticStates( + /* istanbul ignore next line for coverage */ + ({variant, size}) => { + if (variant === undefined) { + return {}; + } - return { - ...baseButton.styles, - ...buttonStyles, - ...sizeStyles, - }; - }, - ({grow}) => grow && {width: '100%', maxWidth: '100%'} + const baseButton = getBaseButton(variant); + const buttonStyles = getButtonStyle(baseButton, variant); + const sizeStyles = size !== undefined ? getButtonSize(baseButton, size) : {}; + + return { + ...baseButton.styles, + ...buttonStyles, + ...sizeStyles, + }; + }, + ({grow}) => grow && {width: '100%', maxWidth: '100%'} + ) ); export const ButtonBaseLabel = styled('span', { diff --git a/modules/button/react/stories/stories.tsx b/modules/button/react/stories/stories.tsx index 488108ce17..e279de3082 100644 --- a/modules/button/react/stories/stories.tsx +++ b/modules/button/react/stories/stories.tsx @@ -43,66 +43,14 @@ storiesOf('Components|Buttons/Button/React', module) .add('Primary', () => (

Large Primary

- - - -

Medium Primary

- - - - -

Small Primary

- - -

Growing Primary

-
- -
)) .add('Secondary', () => ( diff --git a/modules/common/react/index.ts b/modules/common/react/index.ts index 319f8da8ef..3f6afbd1ca 100644 --- a/modules/common/react/index.ts +++ b/modules/common/react/index.ts @@ -4,6 +4,7 @@ export {default as accessibleHide} from './lib/styles/accessibleHide'; export {default as hideMouseFocus, mouseFocusBehavior} from './lib/styles/hideMouseFocus'; export {makeMq} from './lib/utils/makeMq'; export {getTranslateFromOrigin} from './lib/utils/getTranslateFromOrigin'; +export * from './lib/utils/changeToStaticStates'; export * from './lib/utils/colorUtils'; export * from './lib/parts/_brand-assets'; export * from './lib/types'; diff --git a/modules/common/react/lib/utils/changeToStaticClass.ts b/modules/common/react/lib/utils/changeToStaticClass.ts deleted file mode 100644 index f9b21516f3..0000000000 --- a/modules/common/react/lib/utils/changeToStaticClass.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {CSSObject} from '@emotion/core'; - -/** - * Allows the ability to force a state by a pseudo selector by changing the selector into a class creating a new styled object with the class names - * @param shouldChangePseudoSelectors If true, it will replace pseudo selectors from the styled object and change them to classes - * @param obj The styled object passed to the function to replace any pseudo selectors with a class name - */ - -export const changeToStaticClass = ( - shouldChangePseudoSelectors = false, - obj?: CSSObject -): CSSObject | undefined => { - if (!shouldChangePseudoSelectors || !obj) { - return obj; - } - - return Object.keys(obj).reduce((result, key) => { - const newKey = key - .replace(/^:/, '&:') - .replace(/:/g, '.') - .replace(/\.not/g, ':not') - .replace(/\.disabled/, ':disabled'); - const value = - typeof obj[key] === 'object' ? changeToStaticClass(true, obj[key] as CSSObject) : obj[key]; - const newObj = {...result, [newKey]: value}; - return newObj; - }, {}); -}; diff --git a/modules/common/react/lib/utils/changeToStaticStates.ts b/modules/common/react/lib/utils/changeToStaticStates.ts new file mode 100644 index 0000000000..38b54e0b9a --- /dev/null +++ b/modules/common/react/lib/utils/changeToStaticStates.ts @@ -0,0 +1,62 @@ +import {CSSObject, Interpolation} from '@emotion/core'; +import {WithTheme} from '@emotion/styled'; +import {Overwrapped} from '@emotion/styled-base/types/helper'; + +/** + * Allows the ability to force a state by a pseudo selector by changing the selector into a class creating a new styled object with the class names + * @param shouldChangePseudoSelectors If true, it will replace pseudo selectors from the styled object and change them to classes + * @param obj The styled object passed to the function to replace any pseudo selectors with a class name + */ + +export interface ChangeStaticStateProps { + /** @ignore */ + shouldChangeStyleToStaticStates?: boolean; +} + +export const changeStyleToStaticStates = ( + shouldChangePseudoSelectors = false, + obj?: CSSObject +): CSSObject | undefined => { + if (!shouldChangePseudoSelectors || !obj) { + return obj; + } + + return Object.keys(obj).reduce((result, key) => { + const newKey = key + .replace(/^:/, '&:') + .replace(/:/g, '.') + .replace(/\.not/g, ':not') + .replace(/\.disabled/, ':disabled'); + const value = + typeof obj[key] === 'object' + ? changeStyleToStaticStates(true, obj[key] as CSSObject) + : obj[key]; + const newObj = {...result, [newKey]: value}; + return newObj; + }, {}); +}; + +export const convertToStaticStates = < + InnerProps, + ExtraProps extends ChangeStaticStateProps, + StyleProps extends Omit< + Overwrapped, + keyof React.ComponentClass + > = Omit>, + Theme extends object = object +>( + ...styles: Array>> +): Array>> => { + return styles.map(style => { + if (typeof style === 'function') { + return ((props: ExtraProps) => { + return changeStyleToStaticStates(props.shouldChangeStyleToStaticStates, style( + props as any + ) as CSSObject); + }) as any; + } else { + return (props: ExtraProps) => + changeStyleToStaticStates(props.shouldChangeStyleToStaticStates, style as CSSObject); + } + }); +}; diff --git a/modules/common/react/spec/changeToStaticStates.spec.ts b/modules/common/react/spec/changeToStaticStates.spec.ts new file mode 100644 index 0000000000..5d73ba2994 --- /dev/null +++ b/modules/common/react/spec/changeToStaticStates.spec.ts @@ -0,0 +1,13 @@ +import {changeStyleToStaticStates} from '../lib/utils/changeToStaticStates'; + +describe('changeToStaticStates', () => { + it('should convert :hover to .hover', () => { + const input = {':hover': {display: 'none'}}; + const expected = { + '&.hover': { + display: 'none', + }, + }; + expect(changeStyleToStaticStates(true, input)).toEqual(expected); + }); +}); From cf4e352a42146aaf9b6dca3d455b2adddc9a1ceb Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Tue, 17 Dec 2019 17:07:19 -0700 Subject: [PATCH 11/23] fix: Add tests for changeToStaticStates and refactor decorator --- .../react/stories/stories_iconButton.tsx | 7 ++- .../react/spec/changeToStaticStates.spec.ts | 51 ++++++++++++++++++- utils/storybook/CanvasProviderDecorator.tsx | 4 +- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/modules/button/react/stories/stories_iconButton.tsx b/modules/button/react/stories/stories_iconButton.tsx index 9fd7a763a4..31224592a3 100644 --- a/modules/button/react/stories/stories_iconButton.tsx +++ b/modules/button/react/stories/stories_iconButton.tsx @@ -103,7 +103,12 @@ export class IconButtonToggleGroupWrapper extends React.Component< } storiesOf('Components|Buttons/Button/React/Icon Button', module) - .addParameters({component: IconButton}) + .addParameters({ + component: IconButton, + canvasProviderDecorator: { + disableInputProvider: true, + }, + }) .addDecorator(withReadme(README)) .add('Circle', () => (
diff --git a/modules/common/react/spec/changeToStaticStates.spec.ts b/modules/common/react/spec/changeToStaticStates.spec.ts index 5d73ba2994..5b498433cd 100644 --- a/modules/common/react/spec/changeToStaticStates.spec.ts +++ b/modules/common/react/spec/changeToStaticStates.spec.ts @@ -1,7 +1,7 @@ import {changeStyleToStaticStates} from '../lib/utils/changeToStaticStates'; describe('changeToStaticStates', () => { - it('should convert :hover to .hover', () => { + it('should convert ":hover" to "&.hover"', () => { const input = {':hover': {display: 'none'}}; const expected = { '&.hover': { @@ -10,4 +10,53 @@ describe('changeToStaticStates', () => { }; expect(changeStyleToStaticStates(true, input)).toEqual(expected); }); + it('should convert ":active" to "&.active"', () => { + const input = {':active': {display: 'none'}}; + const expected = { + '&.active': { + display: 'none', + }, + }; + expect(changeStyleToStaticStates(true, input)).toEqual(expected); + }); + it('should convert ":focus" to "&.focus"', () => { + const input = {':focus': {display: 'none'}}; + const expected = { + '&.focus': { + display: 'none', + }, + }; + expect(changeStyleToStaticStates(true, input)).toEqual(expected); + }); + it('should convert "div:focus" to "div.focus"', () => { + const input = {'div:focus': {display: 'none'}}; + const expected = { + 'div.focus': { + display: 'none', + }, + }; + expect(changeStyleToStaticStates(true, input)).toEqual(expected); + }); + it('should convert nested object', () => { + const input = { + div: { + span: { + ':hover': { + display: 'none', + }, + }, + }, + }; + const expected = { + div: { + span: { + '&.hover': { + display: 'none', + }, + }, + }, + }; + + expect(changeStyleToStaticStates(true, input)).toEqual(expected); + }); }); diff --git a/utils/storybook/CanvasProviderDecorator.tsx b/utils/storybook/CanvasProviderDecorator.tsx index b9606f1a78..32fb2dd69c 100644 --- a/utils/storybook/CanvasProviderDecorator.tsx +++ b/utils/storybook/CanvasProviderDecorator.tsx @@ -12,10 +12,10 @@ const label = 'theme'; export default makeDecorator({ name: 'canvasProviderDecorator', parameterName: 'canvasProviderDecorator', - wrapper: (storyFn, context, {parameters}) => { + wrapper: (storyFn, context, {parameters = {}}) => { return ( {storyFn(context)} From 45b512bd662633878c7e92dbfa502045d6b32e3b Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Tue, 17 Dec 2019 21:15:43 -0700 Subject: [PATCH 12/23] fix: Remove storybook parameter for testing --- modules/button/react/stories/stories_iconButton.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/button/react/stories/stories_iconButton.tsx b/modules/button/react/stories/stories_iconButton.tsx index 31224592a3..8c5a301b4d 100644 --- a/modules/button/react/stories/stories_iconButton.tsx +++ b/modules/button/react/stories/stories_iconButton.tsx @@ -105,9 +105,6 @@ export class IconButtonToggleGroupWrapper extends React.Component< storiesOf('Components|Buttons/Button/React/Icon Button', module) .addParameters({ component: IconButton, - canvasProviderDecorator: { - disableInputProvider: true, - }, }) .addDecorator(withReadme(README)) .add('Circle', () => ( From 7e311d8f8399ba56badb6c1dc54a0ee2b34bf62b Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Wed, 18 Dec 2019 13:54:19 -0700 Subject: [PATCH 13/23] fix: Remove test code for buttons --- modules/button/react/lib/ButtonBase.tsx | 35 +++++++++++------------- modules/button/react/stories/stories.tsx | 7 +---- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/modules/button/react/lib/ButtonBase.tsx b/modules/button/react/lib/ButtonBase.tsx index 3b5bdbc7d4..f821e3104d 100644 --- a/modules/button/react/lib/ButtonBase.tsx +++ b/modules/button/react/lib/ButtonBase.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import styled from '@emotion/styled'; import isPropValid from '@emotion/is-prop-valid'; -import {convertToStaticStates} from '@workday/canvas-kit-react-common'; import { ButtonSize, DeprecatedButtonVariant, @@ -17,25 +16,23 @@ import {getBaseButton, getButtonSize, getButtonStyle} from './utils'; export const ButtonBaseCon = styled('button', { shouldForwardProp: prop => isPropValid(prop) && prop !== 'size', })( - convertToStaticStates( - /* istanbul ignore next line for coverage */ - ({variant, size}) => { - if (variant === undefined) { - return {}; - } + /* istanbul ignore next line for coverage */ + ({variant, size}) => { + if (variant === undefined) { + return {}; + } + + const baseButton = getBaseButton(variant); + const buttonStyles = getButtonStyle(baseButton, variant); + const sizeStyles = size !== undefined ? getButtonSize(baseButton, size) : {}; - const baseButton = getBaseButton(variant); - const buttonStyles = getButtonStyle(baseButton, variant); - const sizeStyles = size !== undefined ? getButtonSize(baseButton, size) : {}; - - return { - ...baseButton.styles, - ...buttonStyles, - ...sizeStyles, - }; - }, - ({grow}) => grow && {width: '100%', maxWidth: '100%'} - ) + return { + ...baseButton.styles, + ...buttonStyles, + ...sizeStyles, + }; + }, + ({grow}) => grow && {width: '100%', maxWidth: '100%'} ); export const ButtonBaseLabel = styled('span', { diff --git a/modules/button/react/stories/stories.tsx b/modules/button/react/stories/stories.tsx index e279de3082..ad20270072 100644 --- a/modules/button/react/stories/stories.tsx +++ b/modules/button/react/stories/stories.tsx @@ -43,12 +43,7 @@ storiesOf('Components|Buttons/Button/React', module) .add('Primary', () => (

Large Primary

-
From c845fded67e65c63538c006d000f5090cdd70396 Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Wed, 18 Dec 2019 16:44:59 -0700 Subject: [PATCH 14/23] fix: Sort state stories last --- .storybook/config.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.storybook/config.js b/.storybook/config.js index 701483d904..7d1a43aac7 100644 --- a/.storybook/config.js +++ b/.storybook/config.js @@ -39,13 +39,16 @@ const prefix = (phrase, prefix) => value => (value.indexOf(phrase) > -1 ? prefix const pipe = (...fns) => value => fns.reduce((result, fn) => fn(result), value); function storySort(a, b) { + // console.warn('b', b); const prefixFn = pipe( prefix('welcome-', '0'), prefix('getting-started', '0'), prefix('tokens-', '1'), - prefix('components-', '2'), + prefix('components-', '3'), + prefix('states', '4'), prefix('labs-', '3') ); + const left = prefixFn(a[0]); const right = prefixFn(b[0]); return left === right ? 0 : left.localeCompare(right); From 5c8e2db3a6f633c670e72a4a3baa03f11aba61b6 Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Thu, 19 Dec 2019 09:33:02 -0700 Subject: [PATCH 15/23] fix: Rename function for converting pseudo to class --- .../react/stories/stories_iconButton.tsx | 4 +--- modules/common/react/index.ts | 2 +- ...ates.ts => convertPseudoStatesBehavior.ts} | 20 +++++++++---------- .../react/spec/changeToStaticStates.spec.ts | 12 +++++------ 4 files changed, 18 insertions(+), 20 deletions(-) rename modules/common/react/lib/utils/{changeToStaticStates.ts => convertPseudoStatesBehavior.ts} (72%) diff --git a/modules/button/react/stories/stories_iconButton.tsx b/modules/button/react/stories/stories_iconButton.tsx index 8c5a301b4d..9fd7a763a4 100644 --- a/modules/button/react/stories/stories_iconButton.tsx +++ b/modules/button/react/stories/stories_iconButton.tsx @@ -103,9 +103,7 @@ export class IconButtonToggleGroupWrapper extends React.Component< } storiesOf('Components|Buttons/Button/React/Icon Button', module) - .addParameters({ - component: IconButton, - }) + .addParameters({component: IconButton}) .addDecorator(withReadme(README)) .add('Circle', () => (
diff --git a/modules/common/react/index.ts b/modules/common/react/index.ts index 3f6afbd1ca..989a5e9bba 100644 --- a/modules/common/react/index.ts +++ b/modules/common/react/index.ts @@ -4,7 +4,7 @@ export {default as accessibleHide} from './lib/styles/accessibleHide'; export {default as hideMouseFocus, mouseFocusBehavior} from './lib/styles/hideMouseFocus'; export {makeMq} from './lib/utils/makeMq'; export {getTranslateFromOrigin} from './lib/utils/getTranslateFromOrigin'; -export * from './lib/utils/changeToStaticStates'; +export * from './lib/utils/convertPseudoStatesBehavior'; export * from './lib/utils/colorUtils'; export * from './lib/parts/_brand-assets'; export * from './lib/types'; diff --git a/modules/common/react/lib/utils/changeToStaticStates.ts b/modules/common/react/lib/utils/convertPseudoStatesBehavior.ts similarity index 72% rename from modules/common/react/lib/utils/changeToStaticStates.ts rename to modules/common/react/lib/utils/convertPseudoStatesBehavior.ts index 38b54e0b9a..69c1682f81 100644 --- a/modules/common/react/lib/utils/changeToStaticStates.ts +++ b/modules/common/react/lib/utils/convertPseudoStatesBehavior.ts @@ -8,16 +8,16 @@ import {Overwrapped} from '@emotion/styled-base/types/helper'; * @param obj The styled object passed to the function to replace any pseudo selectors with a class name */ -export interface ChangeStaticStateProps { +export interface ConvertPseudoStatesBehaviorProps { /** @ignore */ - shouldChangeStyleToStaticStates?: boolean; + _shouldConvertPseudoStatesToClasses?: boolean; } -export const changeStyleToStaticStates = ( - shouldChangePseudoSelectors = false, +export const convertPseudoStatesToClasses = ( + _shouldConvertPseudoStatesToClasses = false, obj?: CSSObject ): CSSObject | undefined => { - if (!shouldChangePseudoSelectors || !obj) { + if (!_shouldConvertPseudoStatesToClasses || !obj) { return obj; } @@ -29,16 +29,16 @@ export const changeStyleToStaticStates = ( .replace(/\.disabled/, ':disabled'); const value = typeof obj[key] === 'object' - ? changeStyleToStaticStates(true, obj[key] as CSSObject) + ? convertPseudoStatesToClasses(true, obj[key] as CSSObject) : obj[key]; const newObj = {...result, [newKey]: value}; return newObj; }, {}); }; -export const convertToStaticStates = < +export const convertPseudoStatesBehavior = < InnerProps, - ExtraProps extends ChangeStaticStateProps, + ExtraProps extends ConvertPseudoStatesBehaviorProps, StyleProps extends Omit< Overwrapped, keyof React.ComponentClass @@ -50,13 +50,13 @@ export const convertToStaticStates = < return styles.map(style => { if (typeof style === 'function') { return ((props: ExtraProps) => { - return changeStyleToStaticStates(props.shouldChangeStyleToStaticStates, style( + return convertPseudoStatesToClasses(props._shouldConvertPseudoStatesToClasses, style( props as any ) as CSSObject); }) as any; } else { return (props: ExtraProps) => - changeStyleToStaticStates(props.shouldChangeStyleToStaticStates, style as CSSObject); + convertPseudoStatesToClasses(props._shouldConvertPseudoStatesToClasses, style as CSSObject); } }); }; diff --git a/modules/common/react/spec/changeToStaticStates.spec.ts b/modules/common/react/spec/changeToStaticStates.spec.ts index 5b498433cd..1bfda284a9 100644 --- a/modules/common/react/spec/changeToStaticStates.spec.ts +++ b/modules/common/react/spec/changeToStaticStates.spec.ts @@ -1,4 +1,4 @@ -import {changeStyleToStaticStates} from '../lib/utils/changeToStaticStates'; +import {convertPseudoStatesToClasses} from '../lib/utils/convertPseudoStatesBehavior'; describe('changeToStaticStates', () => { it('should convert ":hover" to "&.hover"', () => { @@ -8,7 +8,7 @@ describe('changeToStaticStates', () => { display: 'none', }, }; - expect(changeStyleToStaticStates(true, input)).toEqual(expected); + expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); }); it('should convert ":active" to "&.active"', () => { const input = {':active': {display: 'none'}}; @@ -17,7 +17,7 @@ describe('changeToStaticStates', () => { display: 'none', }, }; - expect(changeStyleToStaticStates(true, input)).toEqual(expected); + expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); }); it('should convert ":focus" to "&.focus"', () => { const input = {':focus': {display: 'none'}}; @@ -26,7 +26,7 @@ describe('changeToStaticStates', () => { display: 'none', }, }; - expect(changeStyleToStaticStates(true, input)).toEqual(expected); + expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); }); it('should convert "div:focus" to "div.focus"', () => { const input = {'div:focus': {display: 'none'}}; @@ -35,7 +35,7 @@ describe('changeToStaticStates', () => { display: 'none', }, }; - expect(changeStyleToStaticStates(true, input)).toEqual(expected); + expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); }); it('should convert nested object', () => { const input = { @@ -57,6 +57,6 @@ describe('changeToStaticStates', () => { }, }; - expect(changeStyleToStaticStates(true, input)).toEqual(expected); + expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); }); }); From cd0d94e290243b214daf5495a927eb1a9994609b Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Thu, 19 Dec 2019 09:41:00 -0700 Subject: [PATCH 16/23] fix: Remove console.log and add back in stories --- .storybook/config.js | 3 +- modules/_labs/core/react/README.md | 9 ++-- modules/button/react/lib/Button.tsx | 5 +-- modules/button/react/stories/stories.tsx | 57 ++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/.storybook/config.js b/.storybook/config.js index 7d1a43aac7..8a3d7a9678 100644 --- a/.storybook/config.js +++ b/.storybook/config.js @@ -39,12 +39,11 @@ const prefix = (phrase, prefix) => value => (value.indexOf(phrase) > -1 ? prefix const pipe = (...fns) => value => fns.reduce((result, fn) => fn(result), value); function storySort(a, b) { - // console.warn('b', b); const prefixFn = pipe( prefix('welcome-', '0'), prefix('getting-started', '0'), prefix('tokens-', '1'), - prefix('components-', '3'), + prefix('components-', '2'), prefix('states', '4'), prefix('labs-', '3') ); diff --git a/modules/_labs/core/react/README.md b/modules/_labs/core/react/README.md index 116ce850e2..e26361338a 100644 --- a/modules/_labs/core/react/README.md +++ b/modules/_labs/core/react/README.md @@ -111,16 +111,18 @@ import {CanvasProvider} from '@workday/canvas-kit-react'; {/* All your components containing any Canvas components */}; ``` -If you'd like to disable `InputProvider` you can pass `disableInputProvider` which will disable InputProvider for all your components that are being wrapped by CanvasProvider +If you'd like to disable `InputProvider` you can pass `disableInputProvider` which will disable +InputProvider for all your components that are being wrapped by CanvasProvider ```tsx import * as React from 'react'; import {CanvasProvider} from '@workday/canvas-kit-react'; -{/* All your components containing any Canvas components */}; + + {/* All your components containing any Canvas components */} +; ``` - #### Storybook Decorator We provide a [storybook decorator](../../utils/storybook/CanvasProviderDecorator.tsx) to wrap your @@ -155,7 +157,6 @@ storiesOf('My Story', module) .add('All', () => ); ``` - ### Input Provider See the [@workday/canvas-kit-react-core docs](../../../core/react/README.md#input-provider) diff --git a/modules/button/react/lib/Button.tsx b/modules/button/react/lib/Button.tsx index 4e8aa92aec..8c47cb43d2 100644 --- a/modules/button/react/lib/Button.tsx +++ b/modules/button/react/lib/Button.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import {ButtonBaseCon, ButtonBaseLabel, ButtonLabelData, ButtonLabelIcon} from './ButtonBase'; import {DeprecatedButtonVariant, ButtonSize, ButtonVariant} from './types'; import {CanvasSystemIcon} from '@workday/design-assets-types'; -import {GrowthBehavior, ChangeStaticStateProps} from '@workday/canvas-kit-react-common'; +import {GrowthBehavior} from '@workday/canvas-kit-react-common'; import {labelDataBaseStyles} from './ButtonStyles'; export interface BaseButtonProps @@ -33,8 +33,7 @@ export interface BaseButtonProps export interface ButtonProps extends BaseButtonProps, - GrowthBehavior, - ChangeStaticStateProps { + GrowthBehavior { /** * Button cannot be empty. */ diff --git a/modules/button/react/stories/stories.tsx b/modules/button/react/stories/stories.tsx index ad20270072..488108ce17 100644 --- a/modules/button/react/stories/stories.tsx +++ b/modules/button/react/stories/stories.tsx @@ -46,6 +46,63 @@ storiesOf('Components|Buttons/Button/React', module) + + + +

Medium Primary

+ + + + +

Small Primary

+ + +

Growing Primary

+
+ +
)) .add('Secondary', () => ( From 7d5c375b116336610b1800193f62e65f95085b61 Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Thu, 19 Dec 2019 10:07:28 -0700 Subject: [PATCH 17/23] fix: Change styles to interpolation --- modules/common/react/lib/utils/convertPseudoStatesBehavior.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/common/react/lib/utils/convertPseudoStatesBehavior.ts b/modules/common/react/lib/utils/convertPseudoStatesBehavior.ts index 69c1682f81..637bb4a50d 100644 --- a/modules/common/react/lib/utils/convertPseudoStatesBehavior.ts +++ b/modules/common/react/lib/utils/convertPseudoStatesBehavior.ts @@ -45,9 +45,9 @@ export const convertPseudoStatesBehavior = < > = Omit>, Theme extends object = object >( - ...styles: Array>> + ...interpolations: Array>> ): Array>> => { - return styles.map(style => { + return interpolations.map(style => { if (typeof style === 'function') { return ((props: ExtraProps) => { return convertPseudoStatesToClasses(props._shouldConvertPseudoStatesToClasses, style( From 10285a073bf984485f10805ae3289b5ae20e9c9c Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Thu, 19 Dec 2019 11:00:46 -0700 Subject: [PATCH 18/23] test: Add test for &:state --- .../react/spec/changeToStaticStates.spec.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/modules/common/react/spec/changeToStaticStates.spec.ts b/modules/common/react/spec/changeToStaticStates.spec.ts index 1bfda284a9..c6ac672337 100644 --- a/modules/common/react/spec/changeToStaticStates.spec.ts +++ b/modules/common/react/spec/changeToStaticStates.spec.ts @@ -28,6 +28,24 @@ describe('changeToStaticStates', () => { }; expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); }); + it('should convert "&:hover" to "&.hover"', () => { + const input = {'&:hover': {display: 'none'}}; + const expected = { + '&.hover': { + display: 'none', + }, + }; + expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); + }); + it('should convert "&:focus" to "&.focus"', () => { + const input = {'&:focus': {display: 'none'}}; + const expected = { + '&.focus': { + display: 'none', + }, + }; + expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); + }); it('should convert "div:focus" to "div.focus"', () => { const input = {'div:focus': {display: 'none'}}; const expected = { From 63821d78fb2e44ff7e8b2cd11b072ba28b90aea3 Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Thu, 19 Dec 2019 13:02:37 -0700 Subject: [PATCH 19/23] fix: Change name of interface --- modules/common/react/lib/utils/convertPseudoStatesBehavior.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/common/react/lib/utils/convertPseudoStatesBehavior.ts b/modules/common/react/lib/utils/convertPseudoStatesBehavior.ts index 637bb4a50d..81045afc09 100644 --- a/modules/common/react/lib/utils/convertPseudoStatesBehavior.ts +++ b/modules/common/react/lib/utils/convertPseudoStatesBehavior.ts @@ -8,7 +8,7 @@ import {Overwrapped} from '@emotion/styled-base/types/helper'; * @param obj The styled object passed to the function to replace any pseudo selectors with a class name */ -export interface ConvertPseudoStatesBehaviorProps { +export interface ConvertPseudoStatesBehavior { /** @ignore */ _shouldConvertPseudoStatesToClasses?: boolean; } @@ -38,7 +38,7 @@ export const convertPseudoStatesToClasses = ( export const convertPseudoStatesBehavior = < InnerProps, - ExtraProps extends ConvertPseudoStatesBehaviorProps, + ExtraProps extends ConvertPseudoStatesBehavior, StyleProps extends Omit< Overwrapped, keyof React.ComponentClass From d9044960fab17c69dc9cf884ed8a05c5bbb938ae Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Thu, 19 Dec 2019 15:38:33 -0700 Subject: [PATCH 20/23] fix: Nicholas is dope --- .storybook/config.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.storybook/config.js b/.storybook/config.js index 8a3d7a9678..3b2ab35d4c 100644 --- a/.storybook/config.js +++ b/.storybook/config.js @@ -35,21 +35,26 @@ addDecorator(FontsDecorator); addDecorator(CanvasProviderDecorator); /** If the string contains a phrase, prefix it. This is useful for making ordering sections */ -const prefix = (phrase, prefix) => value => (value.indexOf(phrase) > -1 ? prefix + value : value); +const prefix = (phrase, prefix) => (/** @type {string} */ value) => { + const index = value.indexOf(phrase); + return index > -1 ? value.substr(0, index) + prefix + value.substr(index) : value; +}; const pipe = (...fns) => value => fns.reduce((result, fn) => fn(result), value); function storySort(a, b) { const prefixFn = pipe( prefix('welcome-', '0'), - prefix('getting-started', '0'), + prefix('getting-started', 'a'), prefix('tokens-', '1'), prefix('components-', '2'), - prefix('states', '4'), - prefix('labs-', '3') + prefix('labs-', '3'), + prefix('default', 'aa'), + prefix('states', 'zz') ); const left = prefixFn(a[0]); const right = prefixFn(b[0]); + return left === right ? 0 : left.localeCompare(right); } From 4b2952b137338d9eadc4be93faedfde2eb84d939 Mon Sep 17 00:00:00 2001 From: Nicholas Boll Date: Fri, 20 Dec 2019 09:54:00 -0700 Subject: [PATCH 21/23] chore: Removed unneeded type from styled.ts --- modules/_labs/core/react/lib/theming/styled.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/_labs/core/react/lib/theming/styled.ts b/modules/_labs/core/react/lib/theming/styled.ts index c342d034c2..63518bb39b 100644 --- a/modules/_labs/core/react/lib/theming/styled.ts +++ b/modules/_labs/core/react/lib/theming/styled.ts @@ -10,7 +10,7 @@ type Interpolations = Array; function styled(node: any) { return (...args: Interpolation[]) => { const newArgs: Interpolations = args.map( - interpolation => (props: Props & {theme: CanvasTheme; direction: ContentDirection}) => { + interpolation => (props: Props & {theme: CanvasTheme}) => { props.theme = useTheme(props.theme); const direction = props.theme.direction; const maybeFlip = direction === ContentDirection.RTL ? rtlCSSJS : noop; From d71362a7805ee45293a816fb3285b9c265fcb304 Mon Sep 17 00:00:00 2001 From: Nicholas Boll Date: Fri, 20 Dec 2019 11:38:40 -0700 Subject: [PATCH 22/23] feat: Move static state conversion into our theme --- .../_labs/core/react/lib/CanvasProvider.tsx | 2 +- modules/_labs/core/react/lib/StaticStates.tsx | 11 ++ .../_labs/core/react/lib/theming/styled.ts | 27 +++- modules/_labs/core/react/spec/styled.spec.ts | 134 ++++++++++++++++++ modules/common/react/index.ts | 1 - .../lib/utils/convertPseudoStatesBehavior.ts | 62 -------- .../react/spec/changeToStaticStates.spec.ts | 80 ----------- 7 files changed, 169 insertions(+), 148 deletions(-) create mode 100644 modules/_labs/core/react/lib/StaticStates.tsx create mode 100644 modules/_labs/core/react/spec/styled.spec.ts delete mode 100644 modules/common/react/lib/utils/convertPseudoStatesBehavior.ts delete mode 100644 modules/common/react/spec/changeToStaticStates.spec.ts diff --git a/modules/_labs/core/react/lib/CanvasProvider.tsx b/modules/_labs/core/react/lib/CanvasProvider.tsx index 709faa830b..a70ef9e5bc 100644 --- a/modules/_labs/core/react/lib/CanvasProvider.tsx +++ b/modules/_labs/core/react/lib/CanvasProvider.tsx @@ -26,7 +26,7 @@ export default class CanvasProvider extends React.Component return ( - {!disableInputProvider ? {children} : children} + {disableInputProvider ? children : {children}} ); diff --git a/modules/_labs/core/react/lib/StaticStates.tsx b/modules/_labs/core/react/lib/StaticStates.tsx new file mode 100644 index 0000000000..edd6482aaf --- /dev/null +++ b/modules/_labs/core/react/lib/StaticStates.tsx @@ -0,0 +1,11 @@ +import * as React from 'react'; +import {useTheme} from './theming/useTheme'; +import CanvasProvider from './CanvasProvider'; +import {CanvasTheme} from './theming'; + +export const StaticStates: React.FC = ({children}) => { + const theme: CanvasTheme & {_staticStates?: boolean} = useTheme(); + theme._staticStates = true; + + return {children}; +}; diff --git a/modules/_labs/core/react/lib/theming/styled.ts b/modules/_labs/core/react/lib/theming/styled.ts index 63518bb39b..d847138814 100644 --- a/modules/_labs/core/react/lib/theming/styled.ts +++ b/modules/_labs/core/react/lib/theming/styled.ts @@ -7,21 +7,40 @@ const noop = (styles: any) => styles; // Pulled from https://github.com/emotion-js/emotion/blob/master/packages/styled-base/src/utils.js#L6 (not exported) type Interpolations = Array; +export const convertToStaticStates = (obj?: CSSObject): CSSObject | undefined => { + if (!obj) { + return obj; + } + + return Object.keys(obj).reduce((result, key) => { + const newKey = key + .replace(/^:/, '&:') // handle shorthand like ":focus" + .replace(/,(\s+):/g, ',$1&:') // handle selectors like ":focus, :hover" + .replace(/:(focus|hover|active)/g, '.$1') + .replace(/\[data\-whatinput="?(mouse|touch|keyboard|pointer)"?]/g, '[data-whatinput="noop"]'); + const value = + typeof obj[key] === 'object' ? convertToStaticStates(obj[key] as CSSObject) : obj[key]; + const newObj = {...result, [newKey]: value}; + return newObj; + }, {}); +}; + function styled(node: any) { return (...args: Interpolation[]) => { const newArgs: Interpolations = args.map( - interpolation => (props: Props & {theme: CanvasTheme}) => { + interpolation => (props: Props & {theme: CanvasTheme & {_staticStates?: boolean}}) => { props.theme = useTheme(props.theme); const direction = props.theme.direction; const maybeFlip = direction === ContentDirection.RTL ? rtlCSSJS : noop; + const maybeConvert = props.theme._staticStates ? convertToStaticStates : noop; try { if (typeof interpolation === 'function') { - return maybeFlip(interpolation(props) as CSSObject); + return maybeFlip(maybeConvert(interpolation(props)) as CSSObject); } - return maybeFlip(interpolation as CSSObject); + return maybeFlip(maybeConvert(interpolation) as CSSObject); } catch (e) { - return interpolation; + return maybeConvert(interpolation); } } ); diff --git a/modules/_labs/core/react/spec/styled.spec.ts b/modules/_labs/core/react/spec/styled.spec.ts new file mode 100644 index 0000000000..2c9cbef16b --- /dev/null +++ b/modules/_labs/core/react/spec/styled.spec.ts @@ -0,0 +1,134 @@ +import {convertToStaticStates} from '../lib/theming/styled'; + +describe('changeToStaticStates', () => { + it('should convert ":hover" to "&.hover"', () => { + const input = {':hover': {display: 'none'}}; + const expected = { + '&.hover': { + display: 'none', + }, + }; + expect(convertToStaticStates(input)).toEqual(expected); + }); + + it('should convert ":active" to "&.active"', () => { + const input = {':active': {display: 'none'}}; + const expected = { + '&.active': { + display: 'none', + }, + }; + expect(convertToStaticStates(input)).toEqual(expected); + }); + + it('should convert ":focus" to "&.focus"', () => { + const input = {':focus': {display: 'none'}}; + const expected = { + '&.focus': { + display: 'none', + }, + }; + expect(convertToStaticStates(input)).toEqual(expected); + }); + + it('should convert "&:hover" to "&.hover"', () => { + const input = {'&:hover': {display: 'none'}}; + const expected = { + '&.hover': { + display: 'none', + }, + }; + expect(convertToStaticStates(input)).toEqual(expected); + }); + + it('should convert "&:focus" to "&.focus"', () => { + const input = {'&:focus': {display: 'none'}}; + const expected = { + '&.focus': { + display: 'none', + }, + }; + expect(convertToStaticStates(input)).toEqual(expected); + }); + + it('should convert "div:focus" to "div.focus"', () => { + const input = {'div:focus': {display: 'none'}}; + const expected = { + 'div.focus': { + display: 'none', + }, + }; + expect(convertToStaticStates(input)).toEqual(expected); + }); + + it('should convert nested object', () => { + const input = { + div: { + span: { + ':hover': { + display: 'none', + }, + }, + }, + }; + const expected = { + div: { + span: { + '&.hover': { + display: 'none', + }, + }, + }, + }; + + expect(convertToStaticStates(input)).toEqual(expected); + }); + + it('should convert multi-selectors', () => { + const input = { + [`:hover, :focus`]: { + display: 'none', + }, + }; + const expected = { + [`&.hover, &.focus`]: { + display: 'none', + }, + }; + + expect(convertToStaticStates(input)).toEqual(expected); + }); + + it('should not convert :not or :disabled', () => { + const input = { + '&:not(:disabled)': { + display: 'none', + }, + }; + const expected = { + '&:not(:disabled)': { + display: 'none', + }, + }; + + expect(convertToStaticStates(input)).toEqual(expected); + }); + + it('should handle falsy objects', () => { + expect(convertToStaticStates(undefined)).toEqual(undefined); + }); + + it('should remove data-whatinput modifiers', () => { + const input = { + '[data-whatinput="mouse"], [data-whatinput=keyboard], [data-whatinput="pointer"], [data-whatinput="touch"]': { + outline: 'none', + }, + }; + const expected = { + '[data-whatinput="noop"], [data-whatinput="noop"], [data-whatinput="noop"], [data-whatinput="noop"]': { + outline: 'none', + }, + }; + expect(convertToStaticStates(input)).toEqual(expected); + }); +}); diff --git a/modules/common/react/index.ts b/modules/common/react/index.ts index 989a5e9bba..319f8da8ef 100644 --- a/modules/common/react/index.ts +++ b/modules/common/react/index.ts @@ -4,7 +4,6 @@ export {default as accessibleHide} from './lib/styles/accessibleHide'; export {default as hideMouseFocus, mouseFocusBehavior} from './lib/styles/hideMouseFocus'; export {makeMq} from './lib/utils/makeMq'; export {getTranslateFromOrigin} from './lib/utils/getTranslateFromOrigin'; -export * from './lib/utils/convertPseudoStatesBehavior'; export * from './lib/utils/colorUtils'; export * from './lib/parts/_brand-assets'; export * from './lib/types'; diff --git a/modules/common/react/lib/utils/convertPseudoStatesBehavior.ts b/modules/common/react/lib/utils/convertPseudoStatesBehavior.ts deleted file mode 100644 index 81045afc09..0000000000 --- a/modules/common/react/lib/utils/convertPseudoStatesBehavior.ts +++ /dev/null @@ -1,62 +0,0 @@ -import {CSSObject, Interpolation} from '@emotion/core'; -import {WithTheme} from '@emotion/styled'; -import {Overwrapped} from '@emotion/styled-base/types/helper'; - -/** - * Allows the ability to force a state by a pseudo selector by changing the selector into a class creating a new styled object with the class names - * @param shouldChangePseudoSelectors If true, it will replace pseudo selectors from the styled object and change them to classes - * @param obj The styled object passed to the function to replace any pseudo selectors with a class name - */ - -export interface ConvertPseudoStatesBehavior { - /** @ignore */ - _shouldConvertPseudoStatesToClasses?: boolean; -} - -export const convertPseudoStatesToClasses = ( - _shouldConvertPseudoStatesToClasses = false, - obj?: CSSObject -): CSSObject | undefined => { - if (!_shouldConvertPseudoStatesToClasses || !obj) { - return obj; - } - - return Object.keys(obj).reduce((result, key) => { - const newKey = key - .replace(/^:/, '&:') - .replace(/:/g, '.') - .replace(/\.not/g, ':not') - .replace(/\.disabled/, ':disabled'); - const value = - typeof obj[key] === 'object' - ? convertPseudoStatesToClasses(true, obj[key] as CSSObject) - : obj[key]; - const newObj = {...result, [newKey]: value}; - return newObj; - }, {}); -}; - -export const convertPseudoStatesBehavior = < - InnerProps, - ExtraProps extends ConvertPseudoStatesBehavior, - StyleProps extends Omit< - Overwrapped, - keyof React.ComponentClass - > = Omit>, - Theme extends object = object ->( - ...interpolations: Array>> -): Array>> => { - return interpolations.map(style => { - if (typeof style === 'function') { - return ((props: ExtraProps) => { - return convertPseudoStatesToClasses(props._shouldConvertPseudoStatesToClasses, style( - props as any - ) as CSSObject); - }) as any; - } else { - return (props: ExtraProps) => - convertPseudoStatesToClasses(props._shouldConvertPseudoStatesToClasses, style as CSSObject); - } - }); -}; diff --git a/modules/common/react/spec/changeToStaticStates.spec.ts b/modules/common/react/spec/changeToStaticStates.spec.ts deleted file mode 100644 index c6ac672337..0000000000 --- a/modules/common/react/spec/changeToStaticStates.spec.ts +++ /dev/null @@ -1,80 +0,0 @@ -import {convertPseudoStatesToClasses} from '../lib/utils/convertPseudoStatesBehavior'; - -describe('changeToStaticStates', () => { - it('should convert ":hover" to "&.hover"', () => { - const input = {':hover': {display: 'none'}}; - const expected = { - '&.hover': { - display: 'none', - }, - }; - expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); - }); - it('should convert ":active" to "&.active"', () => { - const input = {':active': {display: 'none'}}; - const expected = { - '&.active': { - display: 'none', - }, - }; - expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); - }); - it('should convert ":focus" to "&.focus"', () => { - const input = {':focus': {display: 'none'}}; - const expected = { - '&.focus': { - display: 'none', - }, - }; - expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); - }); - it('should convert "&:hover" to "&.hover"', () => { - const input = {'&:hover': {display: 'none'}}; - const expected = { - '&.hover': { - display: 'none', - }, - }; - expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); - }); - it('should convert "&:focus" to "&.focus"', () => { - const input = {'&:focus': {display: 'none'}}; - const expected = { - '&.focus': { - display: 'none', - }, - }; - expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); - }); - it('should convert "div:focus" to "div.focus"', () => { - const input = {'div:focus': {display: 'none'}}; - const expected = { - 'div.focus': { - display: 'none', - }, - }; - expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); - }); - it('should convert nested object', () => { - const input = { - div: { - span: { - ':hover': { - display: 'none', - }, - }, - }, - }; - const expected = { - div: { - span: { - '&.hover': { - display: 'none', - }, - }, - }, - }; - - expect(convertPseudoStatesToClasses(true, input)).toEqual(expected); - }); -}); From 413e5b6ada19087f23ff94cd8d66d1bd6f93e8be Mon Sep 17 00:00:00 2001 From: Manuel Carrera Date: Fri, 20 Dec 2019 17:39:11 -0700 Subject: [PATCH 23/23] fix: Remove disable input provider prop --- modules/_labs/core/react/README.md | 23 ------------------- .../_labs/core/react/lib/CanvasProvider.tsx | 6 ++--- utils/storybook/CanvasProviderDecorator.tsx | 20 ++++------------ 3 files changed, 7 insertions(+), 42 deletions(-) diff --git a/modules/_labs/core/react/README.md b/modules/_labs/core/react/README.md index e26361338a..6299788ebb 100644 --- a/modules/_labs/core/react/README.md +++ b/modules/_labs/core/react/README.md @@ -111,18 +111,6 @@ import {CanvasProvider} from '@workday/canvas-kit-react'; {/* All your components containing any Canvas components */}; ``` -If you'd like to disable `InputProvider` you can pass `disableInputProvider` which will disable -InputProvider for all your components that are being wrapped by CanvasProvider - -```tsx -import * as React from 'react'; -import {CanvasProvider} from '@workday/canvas-kit-react'; - - - {/* All your components containing any Canvas components */} -; -``` - #### Storybook Decorator We provide a [storybook decorator](../../utils/storybook/CanvasProviderDecorator.tsx) to wrap your @@ -146,17 +134,6 @@ storiesOf('My Story', module) .add('All', () => ); ``` -If you want to disable `InputProvider` for a specific story, you can add a parameter to disable it: - -```js -import {CanvasProviderDecorator} from '../../../../utils/storybook'; - -storiesOf('My Story', module) - .addDecorator(CanvasProviderDecorator) - .addParameters(canvasProviderDecorator: { disableInputProvider: true }) - .add('All', () => ); -``` - ### Input Provider See the [@workday/canvas-kit-react-core docs](../../../core/react/README.md#input-provider) diff --git a/modules/_labs/core/react/lib/CanvasProvider.tsx b/modules/_labs/core/react/lib/CanvasProvider.tsx index a70ef9e5bc..84f723e880 100644 --- a/modules/_labs/core/react/lib/CanvasProvider.tsx +++ b/modules/_labs/core/react/lib/CanvasProvider.tsx @@ -7,7 +7,6 @@ import styled from '@emotion/styled'; export interface CanvasProviderProps { theme: CanvasTheme; - disableInputProvider: boolean; } const DirectionContainer = styled('bdo')<{dir: ContentDirection}>(({dir}) => ({ @@ -17,16 +16,15 @@ const DirectionContainer = styled('bdo')<{dir: ContentDirection}>(({dir}) => ({ export default class CanvasProvider extends React.Component { static defaultProps = { theme: defaultCanvasTheme, - disableInputProvider: false, }; render() { - const {children, theme, disableInputProvider} = this.props; + const {children, theme} = this.props; return ( - {disableInputProvider ? children : {children}} + {children} ); diff --git a/utils/storybook/CanvasProviderDecorator.tsx b/utils/storybook/CanvasProviderDecorator.tsx index 32fb2dd69c..1bd647fe33 100644 --- a/utils/storybook/CanvasProviderDecorator.tsx +++ b/utils/storybook/CanvasProviderDecorator.tsx @@ -5,21 +5,11 @@ import { createCanvasTheme, } from '@workday/canvas-kit-labs-react-core'; import {object} from '@storybook/addon-knobs'; -import {makeDecorator} from '@storybook/addons'; const label = 'theme'; -export default makeDecorator({ - name: 'canvasProviderDecorator', - parameterName: 'canvasProviderDecorator', - wrapper: (storyFn, context, {parameters = {}}) => { - return ( - - {storyFn(context)} - - ); - }, -}); +export default (storyFn: () => React.ReactNode) => ( + + {storyFn()} + +);