From a1ffab9a2717d1b46e16d96ccb5c4ce14658e27d Mon Sep 17 00:00:00 2001 From: KamilaCoder Date: Tue, 6 Aug 2019 09:08:22 +0200 Subject: [PATCH 1/7] Created basic Step and Steps structure. --- .../coderskit/src/molecules/Steps/Steps.tsx | 61 +++++++++++++++++++ .../coderskit/src/molecules/Steps/index.ts | 1 + packages/coderskit/src/molecules/index.ts | 1 + .../src/molecules/Steps/Steps.stories.tsx | 26 ++++++++ 4 files changed, 89 insertions(+) create mode 100644 packages/coderskit/src/molecules/Steps/Steps.tsx create mode 100644 packages/coderskit/src/molecules/Steps/index.ts create mode 100644 packages/docs/src/molecules/Steps/Steps.stories.tsx diff --git a/packages/coderskit/src/molecules/Steps/Steps.tsx b/packages/coderskit/src/molecules/Steps/Steps.tsx new file mode 100644 index 0000000..688a366 --- /dev/null +++ b/packages/coderskit/src/molecules/Steps/Steps.tsx @@ -0,0 +1,61 @@ +import React, { HTMLAttributes, ReactNode } from 'react'; +import classnames from 'classnames'; +import styled from '@emotion/styled'; +import { Icon, IconProps } from '../..'; +import { Label } from '../..'; + +export type LabelLayout = 'vertical' | 'horizontal' + +export interface StepsProps extends HTMLAttributes { + children?: ReactNode; + labelLayout?: LabelLayout; +} + +export type StepState = 'success' | 'failure' | 'active' | 'pending'; + +export interface StepProps extends HTMLAttributes { + children?: ReactNode; + stepState?: StepState; +} + +export const StepContainer = styled.div(props => { + const { colors } = props.theme; + + + return { + display: 'flex', + borderRadius: '100%', + border: `1px solid ${colors.primary}`, + width: '32px', + height: '32px', + }; +}); + +export const Step = (props: StepProps) => { + const className = classnames(props.className, 'ck-step'); + + return ( + + {props.children} + + ); +}; + +const StepsWrapper = styled.div(props => { + + return { + display: 'flex', + } +}); + + +export const Steps = (props: StepsProps) => { + const className = classnames(props.className, 'ck-steps'); + + + return ( + + {props.children} + + ); +}; \ No newline at end of file diff --git a/packages/coderskit/src/molecules/Steps/index.ts b/packages/coderskit/src/molecules/Steps/index.ts new file mode 100644 index 0000000..b628698 --- /dev/null +++ b/packages/coderskit/src/molecules/Steps/index.ts @@ -0,0 +1 @@ +export * from './Steps'; diff --git a/packages/coderskit/src/molecules/index.ts b/packages/coderskit/src/molecules/index.ts index 1bbb3c5..3570876 100644 --- a/packages/coderskit/src/molecules/index.ts +++ b/packages/coderskit/src/molecules/index.ts @@ -1,3 +1,4 @@ export * from './Notification'; export * from './RadioGroup'; export * from './Dialog'; +export * from './Steps'; diff --git a/packages/docs/src/molecules/Steps/Steps.stories.tsx b/packages/docs/src/molecules/Steps/Steps.stories.tsx new file mode 100644 index 0000000..d25a841 --- /dev/null +++ b/packages/docs/src/molecules/Steps/Steps.stories.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import { text, select } from '@storybook/addon-knobs'; +import { Steps, Step } from 'coderskit'; + +const labelLayouts = { + horizontal: 'horizontal', + vertical: 'vertical' +} + + +storiesOf('Molecules', module).add('Steps', () => { + const props = { + labelLayout: select('labelLayout', labelLayouts, 'vertical') as keyof typeof labelLayouts, + }; + + return ( + + + + + + + ); + +}); \ No newline at end of file From 807af4103d329db9e2b9c5dc01558bb7e2851f34 Mon Sep 17 00:00:00 2001 From: KamilaCoder Date: Tue, 6 Aug 2019 11:11:58 +0200 Subject: [PATCH 2/7] Added color and size customization to a Step component. --- .../coderskit/src/molecules/Steps/Steps.tsx | 58 +++++++++++++++---- .../src/molecules/Steps/Steps.stories.tsx | 30 +++++++++- 2 files changed, 77 insertions(+), 11 deletions(-) diff --git a/packages/coderskit/src/molecules/Steps/Steps.tsx b/packages/coderskit/src/molecules/Steps/Steps.tsx index 688a366..aae9841 100644 --- a/packages/coderskit/src/molecules/Steps/Steps.tsx +++ b/packages/coderskit/src/molecules/Steps/Steps.tsx @@ -1,8 +1,7 @@ import React, { HTMLAttributes, ReactNode } from 'react'; import classnames from 'classnames'; import styled from '@emotion/styled'; -import { Icon, IconProps } from '../..'; -import { Label } from '../..'; +import { ThemeColorsKeys } from '../..'; export type LabelLayout = 'vertical' | 'horizontal' @@ -11,29 +10,59 @@ export interface StepsProps extends HTMLAttributes { labelLayout?: LabelLayout; } -export type StepState = 'success' | 'failure' | 'active' | 'pending'; +export type StepState = 'success' | 'failure'; +export type StepVariant = 'outlined' | 'contained'; export interface StepProps extends HTMLAttributes { - children?: ReactNode; - stepState?: StepState; + children?: ReactNode; + stepState?: StepState; + variant?: StepVariant; + size?: number; + color?: ThemeColorsKeys; + fontColor?: ThemeColorsKeys; } -export const StepContainer = styled.div(props => { +export const StepBase = styled.div(props => { const { colors } = props.theme; - + const color = colors[props.color!]; + const fontColor = colors[props.fontColor!]; return { display: 'flex', borderRadius: '100%', - border: `1px solid ${colors.primary}`, - width: '32px', - height: '32px', + alignItems: 'center', + justifyContent: 'center', + border: `1px solid ${color}`, + color: fontColor, + width: props.size, + height: props.size, + }; +}); + +const StepContained = styled(StepBase)(props => { + const { colors } = props.theme; + const color = colors[props.color!]; + + + return { + backgroundColor: color, + }; +}); + +const StepOutlined = styled(StepBase)(props => { + const { colors } = props.theme; + const color = colors[props.color!]; + + return { + backgroundColor: colors.white, }; }); export const Step = (props: StepProps) => { const className = classnames(props.className, 'ck-step'); + const StepContainer = props.variant === 'contained' ? StepContained : StepOutlined; + return ( {props.children} @@ -58,4 +87,13 @@ export const Steps = (props: StepsProps) => { {props.children} ); +}; + + +Step.defaultProps = { + size: 32, + variant: 'contained', + children: '', + color: 'primary', + fontColor: 'white' }; \ No newline at end of file diff --git a/packages/docs/src/molecules/Steps/Steps.stories.tsx b/packages/docs/src/molecules/Steps/Steps.stories.tsx index d25a841..96e256c 100644 --- a/packages/docs/src/molecules/Steps/Steps.stories.tsx +++ b/packages/docs/src/molecules/Steps/Steps.stories.tsx @@ -1,13 +1,41 @@ import React from 'react'; import { storiesOf } from '@storybook/react'; -import { text, select } from '@storybook/addon-knobs'; +import { text, select, number } from '@storybook/addon-knobs'; import { Steps, Step } from 'coderskit'; +import { Icon, colors as themeColors } from 'coderskit'; const labelLayouts = { horizontal: 'horizontal', vertical: 'vertical' } +const stepVariants = { + outlined: 'outlined', + contained: 'contained' +} + +const colors = { unset: 'unset', ...Object.keys(themeColors).reduce((a, key) => ({ ...a, [key]: key }), {}) }; + +storiesOf('Molecules', module).add('Step', () => { + const props = { + variant: select('variant', stepVariants, 'contained') as keyof typeof stepVariants, + size: number('size', 32), + children: number('children', 1), + color: select('color', colors, 'unset') as keyof typeof colors, + fontColor: select('fontColor', colors, 'unset') as keyof typeof colors, + }; + + const { children, ...rest } = props; + const color = props.color === 'unset' ? undefined : props.color; + const fontColor = props.fontColor === 'unset' ? undefined : props.fontColor; + + + return ( + + {children} + + ); +}); storiesOf('Molecules', module).add('Steps', () => { const props = { From 9736ac6e97bb8143558a85f13204d7f7eb0276d4 Mon Sep 17 00:00:00 2001 From: KamilaCoder Date: Fri, 9 Aug 2019 16:14:33 +0200 Subject: [PATCH 3/7] Add conditional rendering besed on step state. Create Steps component rendering a series of steps. --- packages/coderskit/src/icons/TimesSolid.tsx | 19 +++++ .../coderskit/src/icons/raw/times-solid.svg | 1 + .../coderskit/src/molecules/Steps/Steps.tsx | 72 ++++++++++++----- .../src/molecules/Steps/Steps.stories.tsx | 81 ++++++++++++++----- 4 files changed, 134 insertions(+), 39 deletions(-) create mode 100644 packages/coderskit/src/icons/TimesSolid.tsx create mode 100644 packages/coderskit/src/icons/raw/times-solid.svg diff --git a/packages/coderskit/src/icons/TimesSolid.tsx b/packages/coderskit/src/icons/TimesSolid.tsx new file mode 100644 index 0000000..32fc17f --- /dev/null +++ b/packages/coderskit/src/icons/TimesSolid.tsx @@ -0,0 +1,19 @@ +import React, { SVGProps } from 'react'; + +const SvgTimesSolid = (props: SVGProps) => ( + +); + +export default SvgTimesSolid; diff --git a/packages/coderskit/src/icons/raw/times-solid.svg b/packages/coderskit/src/icons/raw/times-solid.svg new file mode 100644 index 0000000..8144622 --- /dev/null +++ b/packages/coderskit/src/icons/raw/times-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/coderskit/src/molecules/Steps/Steps.tsx b/packages/coderskit/src/molecules/Steps/Steps.tsx index aae9841..478cee7 100644 --- a/packages/coderskit/src/molecules/Steps/Steps.tsx +++ b/packages/coderskit/src/molecules/Steps/Steps.tsx @@ -1,4 +1,4 @@ -import React, { HTMLAttributes, ReactNode } from 'react'; +import React, { HTMLAttributes, ReactNode, ReactElement } from 'react'; import classnames from 'classnames'; import styled from '@emotion/styled'; import { ThemeColorsKeys } from '../..'; @@ -8,15 +8,16 @@ export type LabelLayout = 'vertical' | 'horizontal' export interface StepsProps extends HTMLAttributes { children?: ReactNode; labelLayout?: LabelLayout; + activeStep?: number; + pendingSteps?: []; } -export type StepState = 'success' | 'failure'; -export type StepVariant = 'outlined' | 'contained'; +export type StepState = 'success' | 'failure' | 'active' | 'pending'; export interface StepProps extends HTMLAttributes { children?: ReactNode; - stepState?: StepState; - variant?: StepVariant; + number?: number; + state?: StepState; size?: number; color?: ThemeColorsKeys; fontColor?: ThemeColorsKeys; @@ -33,36 +34,59 @@ export const StepBase = styled.div(props => { alignItems: 'center', justifyContent: 'center', border: `1px solid ${color}`, + backgroundColor: color, color: fontColor, width: props.size, height: props.size, }; }); -const StepContained = styled(StepBase)(props => { +const StepSuccess = styled(StepBase)(props => { const { colors } = props.theme; - const color = colors[props.color!]; - return { - backgroundColor: color, + backgroundColor: colors.primary, + borderColor: colors.primary, + color: colors.white, + }; +}); + +const StepFailure = styled(StepBase)(props => { + const { colors } = props.theme; + + return { + backgroundColor: colors.error, + borderColor: colors.error, + color: colors.white, + }; +}); + +const StepActive = styled(StepBase)(props => { + const { colors } = props.theme; + + return { + backgroundColor: colors.white, + borderColor: colors.primary, + color: colors.primary, }; }); -const StepOutlined = styled(StepBase)(props => { +const StepPending = styled(StepBase)(props => { const { colors } = props.theme; - const color = colors[props.color!]; return { backgroundColor: colors.white, + borderColor: colors.fontDisabled, + color: colors.fontDisabled, }; }); + export const Step = (props: StepProps) => { const className = classnames(props.className, 'ck-step'); - const StepContainer = props.variant === 'contained' ? StepContained : StepOutlined; - + const StepContainer = props.state === 'success'? StepSuccess : props.state === 'failure' ? StepFailure : props.state === 'active' ? StepActive : props.state === 'pending' ? StepPending : StepBase; + return ( {props.children} @@ -78,22 +102,34 @@ const StepsWrapper = styled.div(props => { }); -export const Steps = (props: StepsProps) => { +export const Steps = ({children, ...props}: StepsProps) => { const className = classnames(props.className, 'ck-steps'); + const childrenStatus = React.Children.map(children, (child, index) => { + + if (index === props.activeStep) { + return React.cloneElement(child as ReactElement, { state: 'active' }); + } else if (index > props.activeStep!) { + return React.cloneElement(child as ReactElement, { state: 'pending' }); + } + return child; + }); return ( - {props.children} + {childrenStatus} ); }; Step.defaultProps = { + fontColor: 'white', + color: 'primary', size: 32, - variant: 'contained', children: '', - color: 'primary', - fontColor: 'white' +}; + +Steps.defaultProps = { + activeStep: 2 }; \ No newline at end of file diff --git a/packages/docs/src/molecules/Steps/Steps.stories.tsx b/packages/docs/src/molecules/Steps/Steps.stories.tsx index 96e256c..3e49a55 100644 --- a/packages/docs/src/molecules/Steps/Steps.stories.tsx +++ b/packages/docs/src/molecules/Steps/Steps.stories.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { Children } from 'react'; import { storiesOf } from '@storybook/react'; import { text, select, number } from '@storybook/addon-knobs'; import { Steps, Step } from 'coderskit'; @@ -9,43 +9,82 @@ const labelLayouts = { vertical: 'vertical' } -const stepVariants = { - outlined: 'outlined', - contained: 'contained' +const stepStates = { + success: 'success', + failure: 'failure', + active: 'active', + pending: 'pending', + unset: 'unset' } + const colors = { unset: 'unset', ...Object.keys(themeColors).reduce((a, key) => ({ ...a, [key]: key }), {}) }; -storiesOf('Molecules', module).add('Step', () => { - const props = { - variant: select('variant', stepVariants, 'contained') as keyof typeof stepVariants, +const getStepProps = () => ({ + state: select('state', stepStates, 'unset') as keyof typeof stepStates, size: number('size', 32), - children: number('children', 1), color: select('color', colors, 'unset') as keyof typeof colors, fontColor: select('fontColor', colors, 'unset') as keyof typeof colors, - }; +}) - const { children, ...rest } = props; - const color = props.color === 'unset' ? undefined : props.color; - const fontColor = props.fontColor === 'unset' ? undefined : props.fontColor; +storiesOf('Steps', module) + .add('Step with number', () => { - return ( - - {children} - - ); -}); + const inheritedProps = getStepProps(); + + const props = { + ...inheritedProps, + children: number('children', 1), + }; + + const color = props.color === 'unset' ? undefined : props.color; + const fontColor = props.fontColor === 'unset' ? undefined : props.fontColor; + const state = props.state === 'unset' ? undefined : props.state; + + const { children, ...rest } = props; -storiesOf('Molecules', module).add('Steps', () => { + return ( + + {children} + + ); + }) + .add('Step with icon', () => { + + const inheritedProps = getStepProps(); + + const props = { + ...inheritedProps, + children: text('children', 'check-solid.svg'), + }; + + const color = props.color === 'unset' ? undefined : props.color; + const fontColor = props.fontColor === 'unset' ? undefined : props.fontColor; + const state = props.state === 'unset' ? undefined : props.state; + + const {children, ...rest } = props; + + return ( + + + + ); + }); + +storiesOf('Steps', module).add('StepGroup', () => { const props = { labelLayout: select('labelLayout', labelLayouts, 'vertical') as keyof typeof labelLayouts, }; return ( - - + + + + + + From 34ada0a3016323e3df035748c9b858449a3314d8 Mon Sep 17 00:00:00 2001 From: KamilaCoder Date: Mon, 12 Aug 2019 18:41:33 +0200 Subject: [PATCH 4/7] Added step dividers. Work in progress. --- .../coderskit/src/molecules/Steps/Steps.tsx | 69 ++++++++++++------- .../src/molecules/Steps/Steps.stories.tsx | 33 ++++----- 2 files changed, 60 insertions(+), 42 deletions(-) diff --git a/packages/coderskit/src/molecules/Steps/Steps.tsx b/packages/coderskit/src/molecules/Steps/Steps.tsx index 478cee7..8cccadc 100644 --- a/packages/coderskit/src/molecules/Steps/Steps.tsx +++ b/packages/coderskit/src/molecules/Steps/Steps.tsx @@ -3,11 +3,11 @@ import classnames from 'classnames'; import styled from '@emotion/styled'; import { ThemeColorsKeys } from '../..'; -export type LabelLayout = 'vertical' | 'horizontal' +export type LabelLayout = 'vertical' | 'horizontal'; export interface StepsProps extends HTMLAttributes { children?: ReactNode; - labelLayout?: LabelLayout; + labelLayout?: LabelLayout; activeStep?: number; pendingSteps?: []; } @@ -24,9 +24,9 @@ export interface StepProps extends HTMLAttributes { } export const StepBase = styled.div(props => { - const { colors } = props.theme; - const color = colors[props.color!]; - const fontColor = colors[props.fontColor!]; + const { colors } = props.theme; + const color = colors[props.color!]; + const fontColor = colors[props.fontColor!]; return { display: 'flex', @@ -81,12 +81,20 @@ const StepPending = styled(StepBase)(props => { }; }); - export const Step = (props: StepProps) => { const className = classnames(props.className, 'ck-step'); - const StepContainer = props.state === 'success'? StepSuccess : props.state === 'failure' ? StepFailure : props.state === 'active' ? StepActive : props.state === 'pending' ? StepPending : StepBase; - + const StepContainer = + props.state === 'success' + ? StepSuccess + : props.state === 'failure' + ? StepFailure + : props.state === 'active' + ? StepActive + : props.state === 'pending' + ? StepPending + : StepBase; + return ( {props.children} @@ -95,33 +103,48 @@ export const Step = (props: StepProps) => { }; const StepsWrapper = styled.div(props => { - return { display: 'flex', - } + }; }); +const Divider = styled.div(props => { + const { colors } = props.theme; -export const Steps = ({children, ...props}: StepsProps) => { + return { + height: '3px', + width: '20px', + backgroundColor: colors.disabled, + }; +}); + +export const Steps = ({ children, ...props }: StepsProps) => { const className = classnames(props.className, 'ck-steps'); - const childrenStatus = React.Children.map(children, (child, index) => { - + const childrenWithState = React.Children.map(children, (child, index) => { if (index === props.activeStep) { - return React.cloneElement(child as ReactElement, { state: 'active' }); + return React.cloneElement(child as ReactElement, { state: 'active', children: index + 1 }); } else if (index > props.activeStep!) { - return React.cloneElement(child as ReactElement, { state: 'pending' }); + return React.cloneElement(child as ReactElement, { state: 'pending', children: index + 1 }); } return child; }); - return ( - - {childrenStatus} - - ); -}; + // const separator = Divider; + const childrenWithSeparators: ReactNode[] = []; + childrenWithState.forEach((element: ReactNode, index) => { + childrenWithSeparators.push(element); + if (index < childrenWithState.length - 1) { + childrenWithSeparators.push(React.createElement(Divider, null)); + } + }); + return ( + + {childrenWithSeparators} + + ); +}; Step.defaultProps = { fontColor: 'white', @@ -131,5 +154,5 @@ Step.defaultProps = { }; Steps.defaultProps = { - activeStep: 2 -}; \ No newline at end of file + activeStep: 2, +}; diff --git a/packages/docs/src/molecules/Steps/Steps.stories.tsx b/packages/docs/src/molecules/Steps/Steps.stories.tsx index 3e49a55..8dd64b4 100644 --- a/packages/docs/src/molecules/Steps/Steps.stories.tsx +++ b/packages/docs/src/molecules/Steps/Steps.stories.tsx @@ -5,34 +5,31 @@ import { Steps, Step } from 'coderskit'; import { Icon, colors as themeColors } from 'coderskit'; const labelLayouts = { - horizontal: 'horizontal', - vertical: 'vertical' -} + horizontal: 'horizontal', + vertical: 'vertical', +}; const stepStates = { success: 'success', failure: 'failure', active: 'active', pending: 'pending', - unset: 'unset' -} - + unset: 'unset', +}; const colors = { unset: 'unset', ...Object.keys(themeColors).reduce((a, key) => ({ ...a, [key]: key }), {}) }; const getStepProps = () => ({ - state: select('state', stepStates, 'unset') as keyof typeof stepStates, - size: number('size', 32), - color: select('color', colors, 'unset') as keyof typeof colors, - fontColor: select('fontColor', colors, 'unset') as keyof typeof colors, -}) - + state: select('state', stepStates, 'unset') as keyof typeof stepStates, + size: number('size', 32), + color: select('color', colors, 'unset') as keyof typeof colors, + fontColor: select('fontColor', colors, 'unset') as keyof typeof colors, +}); storiesOf('Steps', module) .add('Step with number', () => { - const inheritedProps = getStepProps(); - + const props = { ...inheritedProps, children: number('children', 1), @@ -51,9 +48,8 @@ storiesOf('Steps', module) ); }) .add('Step with icon', () => { - const inheritedProps = getStepProps(); - + const props = { ...inheritedProps, children: text('children', 'check-solid.svg'), @@ -63,7 +59,7 @@ storiesOf('Steps', module) const fontColor = props.fontColor === 'unset' ? undefined : props.fontColor; const state = props.state === 'unset' ? undefined : props.state; - const {children, ...rest } = props; + const { children, ...rest } = props; return ( @@ -89,5 +85,4 @@ storiesOf('Steps', module).add('StepGroup', () => { ); - -}); \ No newline at end of file +}); From 3f56d334dd8ca3bae970b963d9f15ccd37370e8b Mon Sep 17 00:00:00 2001 From: Kamila Spodymek Date: Sat, 17 Aug 2019 23:18:36 +0200 Subject: [PATCH 5/7] Add step labels, better positioning, divide Step component into Step Content and Step Label. --- .../coderskit/src/molecules/Steps/Steps.tsx | 209 ++++++++++++++---- .../src/molecules/Steps/Steps.stories.tsx | 104 ++++++--- 2 files changed, 235 insertions(+), 78 deletions(-) diff --git a/packages/coderskit/src/molecules/Steps/Steps.tsx b/packages/coderskit/src/molecules/Steps/Steps.tsx index 8cccadc..0e14447 100644 --- a/packages/coderskit/src/molecules/Steps/Steps.tsx +++ b/packages/coderskit/src/molecules/Steps/Steps.tsx @@ -1,29 +1,27 @@ -import React, { HTMLAttributes, ReactNode, ReactElement } from 'react'; +import React, { HTMLAttributes, ReactNode, ReactElement, LabelHTMLAttributes } from 'react'; import classnames from 'classnames'; import styled from '@emotion/styled'; import { ThemeColorsKeys } from '../..'; -export type LabelLayout = 'vertical' | 'horizontal'; -export interface StepsProps extends HTMLAttributes { - children?: ReactNode; - labelLayout?: LabelLayout; - activeStep?: number; - pendingSteps?: []; -} +// SINGLE STEP -export type StepState = 'success' | 'failure' | 'active' | 'pending'; +export type StepState = 'success' | 'error' | 'active' | 'pending'; export interface StepProps extends HTMLAttributes { - children?: ReactNode; - number?: number; state?: StepState; + labelLayout?: LabelLayout; + children?: ReactNode; +} + +interface StepContentProps extends StepProps { size?: number; color?: ThemeColorsKeys; fontColor?: ThemeColorsKeys; + children?: ReactNode; } -export const StepBase = styled.div(props => { +export const StepContentBase = styled.div(props => { const { colors } = props.theme; const color = colors[props.color!]; const fontColor = colors[props.fontColor!]; @@ -41,7 +39,7 @@ export const StepBase = styled.div(props => { }; }); -const StepSuccess = styled(StepBase)(props => { +const StepContentSuccess = styled(StepContentBase)(props => { const { colors } = props.theme; return { @@ -51,7 +49,7 @@ const StepSuccess = styled(StepBase)(props => { }; }); -const StepFailure = styled(StepBase)(props => { +const StepContentError = styled(StepContentBase)(props => { const { colors } = props.theme; return { @@ -61,7 +59,7 @@ const StepFailure = styled(StepBase)(props => { }; }); -const StepActive = styled(StepBase)(props => { +const StepContentActive = styled(StepContentBase)(props => { const { colors } = props.theme; return { @@ -71,7 +69,7 @@ const StepActive = styled(StepBase)(props => { }; }); -const StepPending = styled(StepBase)(props => { +const StepContentPending = styled(StepContentBase)(props => { const { colors } = props.theme; return { @@ -81,61 +79,175 @@ const StepPending = styled(StepBase)(props => { }; }); -export const Step = (props: StepProps) => { - const className = classnames(props.className, 'ck-step'); - const StepContainer = +const StepVertical = styled.div(() => { + + return { + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + }; +}); + +const StepHorizontal = styled.div(() => { + + return { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + + '.ck-step-content': { + marginRight: 8, + }, + }; +}); + +export const StepContent = (props: StepContentProps) => { + + const StepContent = props.state === 'success' - ? StepSuccess - : props.state === 'failure' - ? StepFailure + ? StepContentSuccess + : props.state === 'error' + ? StepContentError : props.state === 'active' - ? StepActive + ? StepContentActive : props.state === 'pending' - ? StepPending - : StepBase; + ? StepContentPending + : StepContentBase; + + return ( + + {props.children} + + ); + +}; + +export const Step = (props: StepProps) => { + + const StepWrapper = props.labelLayout === 'vertical' ? StepVertical : StepHorizontal; return ( - + {props.children} - + + ); }; -const StepsWrapper = styled.div(props => { + +// STEP LABEL + +export type LabelLayout = 'vertical' | 'horizontal'; + +export interface StepLabelProps extends LabelHTMLAttributes { + state?: StepState; + children?: ReactNode; +} + +const StepLabelWrapper = styled.label(props => { + const { theme, state } = props; + const { fontSizes, fontWeights, lineHeights, colors } = theme; + return { - display: 'flex', + width: 'fit-content', + whiteSpace: 'nowrap', + fontSize: fontSizes.body2, + lineHeight: lineHeights.body2, + fontWeight: fontWeights.regular, + color: colors[state === 'active' ? 'primary' : 'fontDisabled'], + }; }); -const Divider = styled.div(props => { + +export const StepLabel = ({ children, ...props }: StepLabelProps) => { + + return ( + + {children} + + ); +}; + + +// SEPARATOR + +export interface SeparatorProps extends HTMLAttributes { + width?: string; +} + +const Separator = styled.div(props => { const { colors } = props.theme; + const className = classnames(props.className, 'ck-steps-separator'); + + return { + height: '1px', + flexShrink: 100, + width: props.width, + backgroundColor: colors.fontDisabled, + }; +}); + + +// STEP GROUP + +export interface StepsProps extends HTMLAttributes { + children?: ReactNode; + activeStep?: number; + labelLayout?: LabelLayout; +} + +const StepsWrapper = styled.div(() => { return { - height: '3px', - width: '20px', - backgroundColor: colors.disabled, + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', }; }); + export const Steps = ({ children, ...props }: StepsProps) => { const className = classnames(props.className, 'ck-steps'); - const childrenWithState = React.Children.map(children, (child, index) => { - if (index === props.activeStep) { - return React.cloneElement(child as ReactElement, { state: 'active', children: index + 1 }); - } else if (index > props.activeStep!) { - return React.cloneElement(child as ReactElement, { state: 'pending', children: index + 1 }); - } + // Determine child's state (only if it's active or pending) + const childrenWithState = React.Children.map(children as ReactElement[], (child, index) => { + + const state = index === props.activeStep ? 'active' : index > props.activeStep! ? 'pending' : undefined; + + if (index >= props.activeStep!) { + let number = index + 1; + let updatedChildren = React.Children.map(child.props.children as ReactElement[], (innerChild, index) => { + if (index === 0) { + return React.cloneElement(innerChild as ReactElement, { state: state, children: number }); + } else { + return React.cloneElement(innerChild as ReactElement, { state: state}); + } + }); + return React.cloneElement(child, {}, updatedChildren); + } + return child; }); - // const separator = Divider; + // Pass label layout to children + const calcChildren = childrenWithState.length; + + const childrenWithLabels: ReactNode[] = []; + const labelLayout = props.labelLayout; + const separatorWidth = props.labelLayout === 'vertical' ? `${95 / calcChildren}%` : `${80 / calcChildren}%` + + childrenWithState.forEach((element: ReactNode) => { + childrenWithLabels.push(React.cloneElement(element as ReactElement, { labelLayout: labelLayout })) + }); + + // Add separators between steps const childrenWithSeparators: ReactNode[] = []; - childrenWithState.forEach((element: ReactNode, index) => { + childrenWithLabels.forEach((element: ReactNode, index) => { childrenWithSeparators.push(element); - if (index < childrenWithState.length - 1) { - childrenWithSeparators.push(React.createElement(Divider, null)); + if (index < calcChildren - 1) { + childrenWithSeparators.push(); } }); @@ -146,13 +258,22 @@ export const Steps = ({ children, ...props }: StepsProps) => { ); }; -Step.defaultProps = { + +StepContent.defaultProps = { fontColor: 'white', color: 'primary', size: 32, children: '', }; +Step.defaultProps = { + labelLeyout: 'vertical', +} + Steps.defaultProps = { activeStep: 2, }; + + +Step.Label = StepLabel; +Step.Content = StepContent; diff --git a/packages/docs/src/molecules/Steps/Steps.stories.tsx b/packages/docs/src/molecules/Steps/Steps.stories.tsx index 8dd64b4..ccd684a 100644 --- a/packages/docs/src/molecules/Steps/Steps.stories.tsx +++ b/packages/docs/src/molecules/Steps/Steps.stories.tsx @@ -1,4 +1,4 @@ -import React, { Children } from 'react'; +import React from 'react'; import { storiesOf } from '@storybook/react'; import { text, select, number } from '@storybook/addon-knobs'; import { Steps, Step } from 'coderskit'; @@ -11,7 +11,7 @@ const labelLayouts = { const stepStates = { success: 'success', - failure: 'failure', + error: 'error', active: 'active', pending: 'pending', unset: 'unset', @@ -20,31 +20,43 @@ const stepStates = { const colors = { unset: 'unset', ...Object.keys(themeColors).reduce((a, key) => ({ ...a, [key]: key }), {}) }; const getStepProps = () => ({ - state: select('state', stepStates, 'unset') as keyof typeof stepStates, - size: number('size', 32), - color: select('color', colors, 'unset') as keyof typeof colors, - fontColor: select('fontColor', colors, 'unset') as keyof typeof colors, + state: select('state', stepStates, 'unset', 'Step') as keyof typeof stepStates, + size: number('size', 32, undefined, 'Step'), + color: select('color', colors, 'unset', 'Step') as keyof typeof colors, + fontColor: select('fontColor', colors, 'unset', 'Step') as keyof typeof colors, + label: text('label', 'Step label', 'Label'), + labelLayout: select('labelLayout', labelLayouts, 'vertical', 'Label') as keyof typeof labelLayouts, }); +const setValues = (props = getStepProps()) => { + const color = props.color === 'unset' ? undefined : props.color; + const fontColor = props.fontColor === 'unset' ? undefined : props.fontColor; + const state = props.state === 'unset' ? undefined : props.state; + return { color, fontColor, state } +} + storiesOf('Steps', module) .add('Step with number', () => { const inheritedProps = getStepProps(); const props = { ...inheritedProps, - children: number('children', 1), + children: number('children', 1, undefined, 'Step'), }; - const color = props.color === 'unset' ? undefined : props.color; - const fontColor = props.fontColor === 'unset' ? undefined : props.fontColor; - const state = props.state === 'unset' ? undefined : props.state; - - const { children, ...rest } = props; + const { color, fontColor, state } = setValues(); + const { label, children, labelLayout, ...rest } = props; return ( - - {children} + + + {children} + + + {label} + + ); }) .add('Step with icon', () => { @@ -52,37 +64,61 @@ storiesOf('Steps', module) const props = { ...inheritedProps, - children: text('children', 'check-solid.svg'), + children: text('children', 'check-solid.svg', 'Step'), }; - const color = props.color === 'unset' ? undefined : props.color; - const fontColor = props.fontColor === 'unset' ? undefined : props.fontColor; - const state = props.state === 'unset' ? undefined : props.state; - - const { children, ...rest } = props; + const { color, fontColor, state } = setValues(); + const { label, children, labelLayout, ...rest } = props; return ( - - + + + + + + {label} + ); - }); - -storiesOf('Steps', module).add('StepGroup', () => { + }) +.add('StepGroup', () => { const props = { labelLayout: select('labelLayout', labelLayouts, 'vertical') as keyof typeof labelLayouts, }; + const label = 'Step label'; + const { labelLayout } = props; + return ( - - - - - - - - - + + + + + + + {label} + + + + + + + + {label} + + + + + + {label} + + + + + + {label} + + ); }); From 980f259f551fe17c09e627ca36f3baac4397d68b Mon Sep 17 00:00:00 2001 From: Kamila Spodymek Date: Sun, 18 Aug 2019 11:45:20 +0200 Subject: [PATCH 6/7] Set Separator top offset, remove separator width. Code cleanup. --- .../coderskit/src/molecules/Steps/Steps.tsx | 72 +++++++------------ .../icons/raw => docs/public}/times-solid.svg | 0 .../src/molecules/Steps/Steps.stories.tsx | 67 +++++++---------- 3 files changed, 54 insertions(+), 85 deletions(-) rename packages/{coderskit/src/icons/raw => docs/public}/times-solid.svg (100%) diff --git a/packages/coderskit/src/molecules/Steps/Steps.tsx b/packages/coderskit/src/molecules/Steps/Steps.tsx index 0e14447..8adfc0a 100644 --- a/packages/coderskit/src/molecules/Steps/Steps.tsx +++ b/packages/coderskit/src/molecules/Steps/Steps.tsx @@ -3,7 +3,6 @@ import classnames from 'classnames'; import styled from '@emotion/styled'; import { ThemeColorsKeys } from '../..'; - // SINGLE STEP export type StepState = 'success' | 'error' | 'active' | 'pending'; @@ -79,22 +78,21 @@ const StepContentPending = styled(StepContentBase)(props => { }; }); - const StepVertical = styled.div(() => { - return { display: 'flex', flexDirection: 'column', alignItems: 'center', + margin: '10px', }; }); const StepHorizontal = styled.div(() => { - return { display: 'flex', flexDirection: 'row', alignItems: 'center', + margin: '10px', '.ck-step-content': { marginRight: 8, @@ -103,7 +101,6 @@ const StepHorizontal = styled.div(() => { }); export const StepContent = (props: StepContentProps) => { - const StepContent = props.state === 'success' ? StepContentSuccess @@ -115,28 +112,20 @@ export const StepContent = (props: StepContentProps) => { ? StepContentPending : StepContentBase; - return ( - - {props.children} - - ); - + return ( + + {props.children} + + ); }; export const Step = (props: StepProps) => { - const StepWrapper = props.labelLayout === 'vertical' ? StepVertical : StepHorizontal; - return ( - - {props.children} - - - ); + return {props.children}; }; - -// STEP LABEL +// STEP LABEL export type LabelLayout = 'vertical' | 'horizontal'; @@ -156,13 +145,10 @@ const StepLabelWrapper = styled.label(props => { lineHeight: lineHeights.body2, fontWeight: fontWeights.regular, color: colors[state === 'active' ? 'primary' : 'fontDisabled'], - }; }); - export const StepLabel = ({ children, ...props }: StepLabelProps) => { - return ( {children} @@ -170,26 +156,23 @@ export const StepLabel = ({ children, ...props }: StepLabelProps) => { ); }; - // SEPARATOR -export interface SeparatorProps extends HTMLAttributes { - width?: string; +export interface SeparatorProps extends StepContentProps { + topOffset?: string; } const Separator = styled.div(props => { const { colors } = props.theme; - const className = classnames(props.className, 'ck-steps-separator'); - + return { height: '1px', - flexShrink: 100, - width: props.width, + width: '100%', + marginTop: props.topOffset, backgroundColor: colors.fontDisabled, }; }); - // STEP GROUP export interface StepsProps extends HTMLAttributes { @@ -199,21 +182,22 @@ export interface StepsProps extends HTMLAttributes { } const StepsWrapper = styled.div(() => { - return { display: 'flex', justifyContent: 'space-between', - alignItems: 'center', }; }); +const calculateSeparatorTopOffset = (StepWrapper: ReactElement) => { + const stepContent = StepWrapper!.props.children[0]; + return `${stepContent.props.size / 2 + 10}px`; +}; export const Steps = ({ children, ...props }: StepsProps) => { const className = classnames(props.className, 'ck-steps'); - // Determine child's state (only if it's active or pending) + // Determine child's state and pass number as a child (only if it's active or pending) const childrenWithState = React.Children.map(children as ReactElement[], (child, index) => { - const state = index === props.activeStep ? 'active' : index > props.activeStep! ? 'pending' : undefined; if (index >= props.activeStep!) { @@ -222,32 +206,32 @@ export const Steps = ({ children, ...props }: StepsProps) => { if (index === 0) { return React.cloneElement(innerChild as ReactElement, { state: state, children: number }); } else { - return React.cloneElement(innerChild as ReactElement, { state: state}); + return React.cloneElement(innerChild as ReactElement, { state: state }); } }); return React.cloneElement(child, {}, updatedChildren); - } - + } + return child; }); // Pass label layout to children const calcChildren = childrenWithState.length; - const childrenWithLabels: ReactNode[] = []; const labelLayout = props.labelLayout; - const separatorWidth = props.labelLayout === 'vertical' ? `${95 / calcChildren}%` : `${80 / calcChildren}%` childrenWithState.forEach((element: ReactNode) => { - childrenWithLabels.push(React.cloneElement(element as ReactElement, { labelLayout: labelLayout })) + childrenWithLabels.push(React.cloneElement(element as ReactElement, { labelLayout: labelLayout })); }); // Add separators between steps + const topOffset = calculateSeparatorTopOffset(children![0]); + const childrenWithSeparators: ReactNode[] = []; childrenWithLabels.forEach((element: ReactNode, index) => { childrenWithSeparators.push(element); if (index < calcChildren - 1) { - childrenWithSeparators.push(); + childrenWithSeparators.push(); } }); @@ -258,7 +242,6 @@ export const Steps = ({ children, ...props }: StepsProps) => { ); }; - StepContent.defaultProps = { fontColor: 'white', color: 'primary', @@ -268,12 +251,11 @@ StepContent.defaultProps = { Step.defaultProps = { labelLeyout: 'vertical', -} +}; Steps.defaultProps = { activeStep: 2, }; - Step.Label = StepLabel; Step.Content = StepContent; diff --git a/packages/coderskit/src/icons/raw/times-solid.svg b/packages/docs/public/times-solid.svg similarity index 100% rename from packages/coderskit/src/icons/raw/times-solid.svg rename to packages/docs/public/times-solid.svg diff --git a/packages/docs/src/molecules/Steps/Steps.stories.tsx b/packages/docs/src/molecules/Steps/Steps.stories.tsx index ccd684a..c79d176 100644 --- a/packages/docs/src/molecules/Steps/Steps.stories.tsx +++ b/packages/docs/src/molecules/Steps/Steps.stories.tsx @@ -29,11 +29,11 @@ const getStepProps = () => ({ }); const setValues = (props = getStepProps()) => { - const color = props.color === 'unset' ? undefined : props.color; - const fontColor = props.fontColor === 'unset' ? undefined : props.fontColor; - const state = props.state === 'unset' ? undefined : props.state; - return { color, fontColor, state } -} + const color = props.color === 'unset' ? undefined : props.color; + const fontColor = props.fontColor === 'unset' ? undefined : props.fontColor; + const state = props.state === 'unset' ? undefined : props.state; + return { color, fontColor, state }; +}; storiesOf('Steps', module) .add('Step with number', () => { @@ -48,15 +48,12 @@ storiesOf('Steps', module) const { label, children, labelLayout, ...rest } = props; return ( - - - {children} + + + {children} - - {label} - + {label} - ); }) .add('Step with icon', () => { @@ -71,54 +68,44 @@ storiesOf('Steps', module) const { label, children, labelLayout, ...rest } = props; return ( - - + + - - {label} - + {label} ); }) -.add('StepGroup', () => { - const props = { - labelLayout: select('labelLayout', labelLayouts, 'vertical') as keyof typeof labelLayouts, - }; + .add('StepGroup', () => { + const props = { + labelLayout: select('labelLayout', labelLayouts, 'vertical') as keyof typeof labelLayouts, + }; - const label = 'Step label'; - const { labelLayout } = props; + const label = 'Step label'; + const { labelLayout } = props; - return ( - + return ( + - - {label} - + {label} - - {label} - + {label} - - {label} - + {label} - - {label} - + {label} - - ); -}); + + ); + }); From 4df24d6315178940bb6e2fb85830c008eb0fa595 Mon Sep 17 00:00:00 2001 From: Kamila Spodymek Date: Sun, 18 Aug 2019 12:26:23 +0200 Subject: [PATCH 7/7] Fix merge issues --- packages/coderskit/src/components/index.ts | 1 + .../docs/src/{molecules => components}/Steps/Steps.stories.tsx | 0 2 files changed, 1 insertion(+) rename packages/docs/src/{molecules => components}/Steps/Steps.stories.tsx (100%) diff --git a/packages/coderskit/src/components/index.ts b/packages/coderskit/src/components/index.ts index 71465fa..41cc2fb 100644 --- a/packages/coderskit/src/components/index.ts +++ b/packages/coderskit/src/components/index.ts @@ -21,3 +21,4 @@ export * from './TextArea'; export * from './Tooltip'; export * from './Typography'; export * from './Upload'; +export * from './Steps'; diff --git a/packages/docs/src/molecules/Steps/Steps.stories.tsx b/packages/docs/src/components/Steps/Steps.stories.tsx similarity index 100% rename from packages/docs/src/molecules/Steps/Steps.stories.tsx rename to packages/docs/src/components/Steps/Steps.stories.tsx