Skip to content

Commit

Permalink
StepperForm component with storybook
Browse files Browse the repository at this point in the history
  • Loading branch information
dlcaldeira committed Jul 26, 2023
1 parent f65073e commit e43632e
Show file tree
Hide file tree
Showing 22 changed files with 67,535 additions and 5 deletions.
67,025 changes: 67,025 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions packages/stepper/.storybook/preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ThemeProvider } from '@talend/design-system';

export const decorators = [
(Story, context) => {
return (
<>
<style>
{`
.page {
overflow: auto;
height: 100%;
display: flex;
flex-direction: column;
}
.page__wrapper {
height: calc(100vh - 20px);
}
`}
</style>
<ThemeProvider>
<div className="page__wrapper">
<div className="page">
<Story {...context} />
</div>
</div>
</ThemeProvider>
</>
);
},
];
4 changes: 4 additions & 0 deletions packages/stepper/custom.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare module '*.scss' {
const contents: Record<string, string>;
export default contents;
}
3 changes: 2 additions & 1 deletion packages/stepper/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"test:watch": "cross-env TZ=Europe/Paris talend-scripts test --watch",
"test:cov": "cross-env TZ=Europe/Paris talend-scripts test --coverage",
"lint": "talend-scripts lint",
"start": "echo nothing to start"
"start": "talend-scripts start-storybook -p 6006"
},
"keywords": [
"react",
Expand All @@ -32,6 +32,7 @@
},
"dependencies": {
"@talend/react-components": "^11.0.0",
"@talend/design-system": "^7.12.1",
"classnames": "^2.3.2",
"invariant": "^2.2.4",
"keycode": "^2.2.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Stepper as StepperDS } from '@talend/design-system';
import { useStepperForm } from '../../hooks/useStepperForm/useStepperForm.hook';
import StepperFormContext from './StepperForm.context';
import style from './StepperForm.module.scss';
import { StepperProps } from './StepperForm.types';
import { getStepComponent } from './StepperForm.utils';
import { StepperFormFooter } from './StepperFormFooter/StepperFormFooter.component';
import { StepperFormHeader } from './StepperFormHeader/StepperFormHeader.component';

const StepperForm = ({ initalStepIndex = 0, footer, header, isLoading, steps }: StepperProps) => {
const {
onNextStep,
onPreviousStep,
currentStep,
steps: stepperSteps,
} = useStepperForm(steps, initalStepIndex);

const Component = steps[currentStep].component;
return (
<StepperFormContext.Provider value={{ currentStep, isLoading, stepperSteps }}>
<div className={style['stepper-form']}>
<div className={style['stepper-form__steps']}>
<StepperDS currentStepIndex={currentStep}>
{stepperSteps.map((step, index) => {
const { key, navigation, tooltip, ...rest } = step;
const Step = getStepComponent(currentStep, index, !!navigation?.disableCause);
return (
<Step key={`step-${key}`} tooltip={navigation?.disableCause ?? tooltip} {...rest} />
);
})}
</StepperDS>
</div>
<div className={style['stepper-form__container']}>
<StepperFormHeader {...header} />

<div className={style['stepper-form__content']}>
<Component />
</div>

<StepperFormFooter
{...footer}
isLoading={isLoading}
onPrevious={() => {
onPreviousStep();
footer.onPrevious?.();
}}
onNext={() => {
onNextStep();
footer.onNext?.();
}}
/>
</div>
</div>
</StepperFormContext.Provider>
);
};

export default StepperForm;
16 changes: 16 additions & 0 deletions packages/stepper/src/components/StepperForm/StepperForm.context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { createContext } from 'react';
import { StepperState } from '../../hooks/useStepperForm/useStepperForm.types';

const stepperFormContext = createContext({});

const StepperFormProvider = stepperFormContext.Provider;

export { StepperFormProvider };

export interface StepperFormContextApi {
currentStep: number;
isLoading?: boolean;
stepperSteps: StepperState;
}

export default createContext({} as StepperFormContextApi);
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@use '~@talend/design-tokens/lib/_tokens.scss';

.stepper-form {
display: flex;
height: calc(100% - tokens.$coral-sizing-m * 2);
padding: tokens.$coral-sizing-m 0;

&__header {
&__title {
font: tokens.$coral-heading-l;
}

&__subtitle {
font: tokens.$coral-paragraph-m;
color: tokens.$coral-color-neutral-text-weak;
}
}

&__steps {
display: flex;
height: fit-content;
padding-right: tokens.$coral-spacing-l;
width: 20rem;
}

&__container {
display: flex;
flex: 1;
flex-direction: column;
gap: tokens.$coral-spacing-l;
padding-right: tokens.$coral-spacing-l;
}

&__content {
height: calc(100% - 11.5rem);
}

&__footer {
display: flex;
flex: 0;

hr {
max-height: tokens.$coral-sizing-xxxs;
}
}

&__loading {
width: 50%;
}
}
24 changes: 24 additions & 0 deletions packages/stepper/src/components/StepperForm/StepperForm.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ComponentType } from 'react';
import { StepperFormFooter } from './StepperFormFooter/StepperFormFooter.types';
import { StepperFormHeader } from './StepperFormHeader/StepperFormHeader.types';

export interface StepperStepNavigation {
disableCause?: string;
previous?: string;
next?: string;
}

export interface StepperStep {
component: ComponentType;
key: string;
title: string;
tooltip?: string;
}

export interface StepperProps {
footer: StepperFormFooter;
header: StepperFormHeader;
initalStepIndex?: number;
isLoading?: boolean;
steps: StepperStep[];
}
18 changes: 18 additions & 0 deletions packages/stepper/src/components/StepperForm/StepperForm.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { ElementType } from 'react';

import { Stepper } from '@talend/design-system';

export const getStepComponent = (
current: number,
index: number,
isDisabled = false,
): ElementType => {
if (isDisabled) {
return Stepper.Step.Disabled;
} else if (current === index) {
return Stepper.Step.InProgress;
} else if (current > index) {
return Stepper.Step.Validated;
}
return Stepper.Step.Enabled;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { ButtonPrimary, ButtonSecondary, Divider, StackHorizontal } from '@talend/design-system';
import { useContext } from 'react';
import { useTranslation } from 'react-i18next';
import I18N from '../../../constants/i18n';
import StepperFormContext from '../StepperForm.context';
import style from '../StepperForm.module.scss';
import { StepperFormFooterProps } from './StepperFormFooter.types';

export const StepperFormFooter = ({
dataFeature,
extraActions,
isLoading,
onCancel,
onPrevious,
onNext,
onSubmit,
}: StepperFormFooterProps) => {
const { t } = useTranslation(I18N.STEPPER_NAMESPACE);
const hasRightButtons = onPrevious || onNext || extraActions;
const { currentStep, stepperSteps } = useContext(StepperFormContext);

const currentStepNavigation = stepperSteps[currentStep].navigation;

const showNextButton = currentStepNavigation?.next && currentStep < stepperSteps.length - 1;
const showPreviousButton = currentStepNavigation?.previous;
const showRunButton = currentStep === stepperSteps.length - 1;

return (
<div className={style['stepper-form__footer']}>
<StackHorizontal gap="M" align="center">
<ButtonSecondary onClick={onCancel} data-feature={dataFeature?.cancel}>
{t('CANCEL', 'Cancel')}
</ButtonSecondary>
{hasRightButtons && <Divider orientation="vertical" />}

{showPreviousButton && onPrevious && (
<ButtonSecondary onClick={onPrevious} data-feature={dataFeature?.previous}>
{t('PREVIOUS', 'Previous')}
</ButtonSecondary>
)}

{extraActions?.map(action => action)}

{showNextButton && onNext && (
<ButtonPrimary onClick={onNext} data-feature={dataFeature?.next} disabled={isLoading}>
{t('NEXT', 'Next')}
</ButtonPrimary>
)}

{showRunButton && onSubmit && (
<ButtonPrimary onClick={onSubmit} data-feature={dataFeature?.submit} disabled={isLoading}>
{t('VALIDATE', 'Validate')}
</ButtonPrimary>
)}
</StackHorizontal>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export interface StepperFormFooterProps {
dataFeature?: {
cancel?: string;
next?: string;
previous?: string;
submit?: string;
};
extraActions?: JSX.Element[];
isLoading?: boolean;
onCancel(): void;
onNext?(): void;
onPrevious?(): void;
onSubmit?(): void;
}

export type StepperFormFooter = StepperFormFooterProps;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { StepperFormHeaderProps } from './StepperFormHeader.types';
import style from '../StepperForm.module.scss';

export const StepperFormHeader = ({ title, subtitle }: StepperFormHeaderProps) => {
return (
<>
<h2 className={style['stepper-form__header__title']}>{title}</h2>
{subtitle && <span className={style['stepper-form__header__subtitle']}>{subtitle}</span>}
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface StepperFormHeaderProps {
title: string;
subtitle?: string;
}

export type StepperFormHeader = StepperFormHeaderProps;
3 changes: 3 additions & 0 deletions packages/stepper/src/components/StepperForm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import StepperForm from './StepperForm.component';

export default StepperForm;
File renamed without changes.
5 changes: 5 additions & 0 deletions packages/stepper/src/constants/i18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const STEPPER_NAMESPACE = 'stepper-app';

export default {
STEPPER_NAMESPACE,
};
Loading

0 comments on commit e43632e

Please sign in to comment.