@transferwise/components 0.0.0-experimental-ae7c18d → 0.0.0-experimental-1aec3ea
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/stepper/Stepper.js +3 -6
- package/build/stepper/Stepper.js.map +1 -1
- package/build/stepper/Stepper.mjs +3 -6
- package/build/stepper/Stepper.mjs.map +1 -1
- package/build/types/stepper/Stepper.d.ts +1 -2
- package/build/types/stepper/Stepper.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/flowNavigation/__snapshots__/FlowNavigation.spec.js.snap +1 -3
- package/src/radioOption/RadioOption.spec.tsx +73 -0
- package/src/stepper/Stepper.spec.js +151 -154
- package/src/stepper/Stepper.tsx +4 -9
- package/src/radioOption/RadioOption.spec.js +0 -67
- package/src/stepper/Stepper.spec.story.tsx +0 -89
package/build/stepper/Stepper.js
CHANGED
|
@@ -40,8 +40,7 @@ function clamp(from, to, value) {
|
|
|
40
40
|
const Stepper = ({
|
|
41
41
|
steps,
|
|
42
42
|
activeStep = 0,
|
|
43
|
-
className
|
|
44
|
-
testId
|
|
43
|
+
className
|
|
45
44
|
}) => {
|
|
46
45
|
const {
|
|
47
46
|
isRTL
|
|
@@ -54,7 +53,7 @@ const Stepper = ({
|
|
|
54
53
|
const percentageCompleted = activeStepIndex / (steps.length - 1);
|
|
55
54
|
const getProgressWidth = () => {
|
|
56
55
|
if (percentageCompleted === 0) {
|
|
57
|
-
return '
|
|
56
|
+
return '0px';
|
|
58
57
|
}
|
|
59
58
|
/**
|
|
60
59
|
* Progress bar starts with left/right (depends on rtl) shift `--progress-bar-start-shift` for hiding Progress bar's left and right borders
|
|
@@ -94,15 +93,13 @@ const Stepper = ({
|
|
|
94
93
|
};
|
|
95
94
|
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
96
95
|
className: clsx.clsx('tw-stepper', className),
|
|
97
|
-
"data-testid": testId,
|
|
98
96
|
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
99
97
|
className: "progress",
|
|
100
98
|
children: /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
101
99
|
className: "progress-bar",
|
|
102
100
|
style: {
|
|
103
101
|
width: getProgressWidth()
|
|
104
|
-
}
|
|
105
|
-
"data-testid": "progress-bar"
|
|
102
|
+
}
|
|
106
103
|
})
|
|
107
104
|
}), /*#__PURE__*/jsxRuntime.jsx("ol", {
|
|
108
105
|
className: "tw-stepper-steps p-t-1 m-b-0",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stepper.js","sources":["../../src/stepper/Stepper.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport * as React from 'react';\n\nimport { Position } from '../common';\nimport { useDirection } from '../common/hooks';\nimport Tooltip from '../tooltip';\n\nimport { isTouchDevice } from './deviceDetection';\n\nfunction clamp(from: number, to: number, value: number) {\n return Math.max(Math.min(to, value), from);\n}\n\nexport interface Step {\n label: React.ReactNode;\n onClick?: () => void;\n hoverLabel?: React.ReactNode;\n}\n\nexport interface StepperProps {\n steps: readonly Step[];\n activeStep?: number;\n className?: string;\n
|
|
1
|
+
{"version":3,"file":"Stepper.js","sources":["../../src/stepper/Stepper.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport * as React from 'react';\n\nimport { Position } from '../common';\nimport { useDirection } from '../common/hooks';\nimport Tooltip from '../tooltip';\n\nimport { isTouchDevice } from './deviceDetection';\n\nfunction clamp(from: number, to: number, value: number) {\n return Math.max(Math.min(to, value), from);\n}\n\nexport interface Step {\n label: React.ReactNode;\n onClick?: () => void;\n hoverLabel?: React.ReactNode;\n}\n\nexport interface StepperProps {\n steps: readonly Step[];\n activeStep?: number;\n className?: string;\n}\n\n/**\n * This component is considered user-unfriendly and inaccessible on its own and will likely be made internal in the future. Please use `FlowNavigation` instead.\n * @see https://storybook.wise.design/?path=/story/navigation-flownavigation--variants\n */\nconst Stepper = ({ steps, activeStep = 0, className }: StepperProps) => {\n const { isRTL } = useDirection();\n\n if (steps.length === 0) {\n return null;\n }\n\n const activeStepIndex = clamp(0, steps.length - 1, activeStep);\n const stepPercentage = 1 / (steps.length - 1);\n const percentageCompleted = activeStepIndex / (steps.length - 1);\n\n const getProgressWidth = (): string => {\n if (percentageCompleted === 0) {\n return '0px';\n }\n /**\n * Progress bar starts with left/right (depends on rtl) shift `--progress-bar-start-shift` for hiding Progress bar's left and right borders\n * which are used for progress vertical delimiter.\n * When progress is completed, we need to add `--progress-bar-border-width` to the width to allow the right border be outside of the progress area.\n */\n return `calc(${percentageCompleted * 100}% + var(--progress-bar-start-shift) + var(--progress-bar-border-width))`;\n };\n\n const renderStep = (step: Step, index: number) => {\n const active = index === activeStepIndex;\n const clickable = step.onClick && !active;\n\n const labelButton = clickable ? (\n <button\n type=\"button\"\n className=\"btn-unstyled tw-stepper__step-label\"\n onClick={() => clickable && step.onClick?.()}\n >\n <small>{step.label}</small>\n </button>\n ) : (\n <span className=\"tw-stepper__step-label\">{step.label}</span>\n );\n\n return (\n <li\n key={index}\n className={clsx(\n 'hidden-xs',\n 'tw-stepper__step',\n active ? 'np-text-body-default-bold tw-stepper__step--active' : 'np-text-body-default',\n clickable && 'tw-stepper__step--clickable',\n step.hoverLabel && 'tw-stepper__step--has-tooltip',\n )}\n aria-current={active ? 'step' : false}\n style={\n isRTL\n ? { right: `${index * stepPercentage * 100}%` }\n : { left: `${index * stepPercentage * 100}%` }\n }\n >\n {step.hoverLabel && !isTouchDevice() ? (\n <Tooltip position={Position.BOTTOM} label={step.hoverLabel}>\n {labelButton}\n </Tooltip>\n ) : (\n labelButton\n )}\n </li>\n );\n };\n\n return (\n <div className={clsx('tw-stepper', className)}>\n <div className=\"progress\">\n <div className=\"progress-bar\" style={{ width: getProgressWidth() }} />\n </div>\n <ol className=\"tw-stepper-steps p-t-1 m-b-0\">{steps.map(renderStep)}</ol>\n </div>\n );\n};\n\nexport default Stepper;\n"],"names":["clamp","from","to","value","Math","max","min","Stepper","steps","activeStep","className","isRTL","useDirection","length","activeStepIndex","stepPercentage","percentageCompleted","getProgressWidth","renderStep","step","index","active","clickable","onClick","labelButton","_jsx","type","children","label","clsx","hoverLabel","style","right","left","isTouchDevice","Tooltip","position","Position","BOTTOM","_jsxs","width","map"],"mappings":"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"}
|
|
@@ -38,8 +38,7 @@ function clamp(from, to, value) {
|
|
|
38
38
|
const Stepper = ({
|
|
39
39
|
steps,
|
|
40
40
|
activeStep = 0,
|
|
41
|
-
className
|
|
42
|
-
testId
|
|
41
|
+
className
|
|
43
42
|
}) => {
|
|
44
43
|
const {
|
|
45
44
|
isRTL
|
|
@@ -52,7 +51,7 @@ const Stepper = ({
|
|
|
52
51
|
const percentageCompleted = activeStepIndex / (steps.length - 1);
|
|
53
52
|
const getProgressWidth = () => {
|
|
54
53
|
if (percentageCompleted === 0) {
|
|
55
|
-
return '
|
|
54
|
+
return '0px';
|
|
56
55
|
}
|
|
57
56
|
/**
|
|
58
57
|
* Progress bar starts with left/right (depends on rtl) shift `--progress-bar-start-shift` for hiding Progress bar's left and right borders
|
|
@@ -92,15 +91,13 @@ const Stepper = ({
|
|
|
92
91
|
};
|
|
93
92
|
return /*#__PURE__*/jsxs("div", {
|
|
94
93
|
className: clsx('tw-stepper', className),
|
|
95
|
-
"data-testid": testId,
|
|
96
94
|
children: [/*#__PURE__*/jsx("div", {
|
|
97
95
|
className: "progress",
|
|
98
96
|
children: /*#__PURE__*/jsx("div", {
|
|
99
97
|
className: "progress-bar",
|
|
100
98
|
style: {
|
|
101
99
|
width: getProgressWidth()
|
|
102
|
-
}
|
|
103
|
-
"data-testid": "progress-bar"
|
|
100
|
+
}
|
|
104
101
|
})
|
|
105
102
|
}), /*#__PURE__*/jsx("ol", {
|
|
106
103
|
className: "tw-stepper-steps p-t-1 m-b-0",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stepper.mjs","sources":["../../src/stepper/Stepper.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport * as React from 'react';\n\nimport { Position } from '../common';\nimport { useDirection } from '../common/hooks';\nimport Tooltip from '../tooltip';\n\nimport { isTouchDevice } from './deviceDetection';\n\nfunction clamp(from: number, to: number, value: number) {\n return Math.max(Math.min(to, value), from);\n}\n\nexport interface Step {\n label: React.ReactNode;\n onClick?: () => void;\n hoverLabel?: React.ReactNode;\n}\n\nexport interface StepperProps {\n steps: readonly Step[];\n activeStep?: number;\n className?: string;\n
|
|
1
|
+
{"version":3,"file":"Stepper.mjs","sources":["../../src/stepper/Stepper.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport * as React from 'react';\n\nimport { Position } from '../common';\nimport { useDirection } from '../common/hooks';\nimport Tooltip from '../tooltip';\n\nimport { isTouchDevice } from './deviceDetection';\n\nfunction clamp(from: number, to: number, value: number) {\n return Math.max(Math.min(to, value), from);\n}\n\nexport interface Step {\n label: React.ReactNode;\n onClick?: () => void;\n hoverLabel?: React.ReactNode;\n}\n\nexport interface StepperProps {\n steps: readonly Step[];\n activeStep?: number;\n className?: string;\n}\n\n/**\n * This component is considered user-unfriendly and inaccessible on its own and will likely be made internal in the future. Please use `FlowNavigation` instead.\n * @see https://storybook.wise.design/?path=/story/navigation-flownavigation--variants\n */\nconst Stepper = ({ steps, activeStep = 0, className }: StepperProps) => {\n const { isRTL } = useDirection();\n\n if (steps.length === 0) {\n return null;\n }\n\n const activeStepIndex = clamp(0, steps.length - 1, activeStep);\n const stepPercentage = 1 / (steps.length - 1);\n const percentageCompleted = activeStepIndex / (steps.length - 1);\n\n const getProgressWidth = (): string => {\n if (percentageCompleted === 0) {\n return '0px';\n }\n /**\n * Progress bar starts with left/right (depends on rtl) shift `--progress-bar-start-shift` for hiding Progress bar's left and right borders\n * which are used for progress vertical delimiter.\n * When progress is completed, we need to add `--progress-bar-border-width` to the width to allow the right border be outside of the progress area.\n */\n return `calc(${percentageCompleted * 100}% + var(--progress-bar-start-shift) + var(--progress-bar-border-width))`;\n };\n\n const renderStep = (step: Step, index: number) => {\n const active = index === activeStepIndex;\n const clickable = step.onClick && !active;\n\n const labelButton = clickable ? (\n <button\n type=\"button\"\n className=\"btn-unstyled tw-stepper__step-label\"\n onClick={() => clickable && step.onClick?.()}\n >\n <small>{step.label}</small>\n </button>\n ) : (\n <span className=\"tw-stepper__step-label\">{step.label}</span>\n );\n\n return (\n <li\n key={index}\n className={clsx(\n 'hidden-xs',\n 'tw-stepper__step',\n active ? 'np-text-body-default-bold tw-stepper__step--active' : 'np-text-body-default',\n clickable && 'tw-stepper__step--clickable',\n step.hoverLabel && 'tw-stepper__step--has-tooltip',\n )}\n aria-current={active ? 'step' : false}\n style={\n isRTL\n ? { right: `${index * stepPercentage * 100}%` }\n : { left: `${index * stepPercentage * 100}%` }\n }\n >\n {step.hoverLabel && !isTouchDevice() ? (\n <Tooltip position={Position.BOTTOM} label={step.hoverLabel}>\n {labelButton}\n </Tooltip>\n ) : (\n labelButton\n )}\n </li>\n );\n };\n\n return (\n <div className={clsx('tw-stepper', className)}>\n <div className=\"progress\">\n <div className=\"progress-bar\" style={{ width: getProgressWidth() }} />\n </div>\n <ol className=\"tw-stepper-steps p-t-1 m-b-0\">{steps.map(renderStep)}</ol>\n </div>\n );\n};\n\nexport default Stepper;\n"],"names":["clamp","from","to","value","Math","max","min","Stepper","steps","activeStep","className","isRTL","useDirection","length","activeStepIndex","stepPercentage","percentageCompleted","getProgressWidth","renderStep","step","index","active","clickable","onClick","labelButton","_jsx","type","children","label","clsx","hoverLabel","style","right","left","isTouchDevice","Tooltip","position","Position","BOTTOM","_jsxs","width","map"],"mappings":"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"}
|
|
@@ -8,12 +8,11 @@ export interface StepperProps {
|
|
|
8
8
|
steps: readonly Step[];
|
|
9
9
|
activeStep?: number;
|
|
10
10
|
className?: string;
|
|
11
|
-
testId?: string;
|
|
12
11
|
}
|
|
13
12
|
/**
|
|
14
13
|
* This component is considered user-unfriendly and inaccessible on its own and will likely be made internal in the future. Please use `FlowNavigation` instead.
|
|
15
14
|
* @see https://storybook.wise.design/?path=/story/navigation-flownavigation--variants
|
|
16
15
|
*/
|
|
17
|
-
declare const Stepper: ({ steps, activeStep, className
|
|
16
|
+
declare const Stepper: ({ steps, activeStep, className }: StepperProps) => React.JSX.Element | null;
|
|
18
17
|
export default Stepper;
|
|
19
18
|
//# sourceMappingURL=Stepper.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stepper.d.ts","sourceRoot":"","sources":["../../../src/stepper/Stepper.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAY/B,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"Stepper.d.ts","sourceRoot":"","sources":["../../../src/stepper/Stepper.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAY/B,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,QAAA,MAAM,OAAO,qCAA0C,YAAY,6BA2ElE,CAAC;AAEF,eAAe,OAAO,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transferwise/components",
|
|
3
|
-
"version": "0.0.0-experimental-
|
|
3
|
+
"version": "0.0.0-experimental-1aec3ea",
|
|
4
4
|
"description": "Neptune React components",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -91,9 +91,9 @@
|
|
|
91
91
|
"rollup": "^4.18.1",
|
|
92
92
|
"rollup-preserve-directives": "^1.1.1",
|
|
93
93
|
"storybook": "^8.2.2",
|
|
94
|
+
"@transferwise/less-config": "3.1.0",
|
|
94
95
|
"@transferwise/neptune-css": "14.20.1",
|
|
95
|
-
"@wise/components-theming": "1.6.1"
|
|
96
|
-
"@transferwise/less-config": "3.1.0"
|
|
96
|
+
"@wise/components-theming": "1.6.1"
|
|
97
97
|
},
|
|
98
98
|
"peerDependencies": {
|
|
99
99
|
"@transferwise/icons": "^3.13.1",
|
|
@@ -92,7 +92,6 @@ exports[`FlowNavigation on mobile renders as expected 1`] = `
|
|
|
92
92
|
>
|
|
93
93
|
<div
|
|
94
94
|
class="progress-bar"
|
|
95
|
-
data-testid="progress-bar"
|
|
96
95
|
/>
|
|
97
96
|
</div>
|
|
98
97
|
<ol
|
|
@@ -208,8 +207,7 @@ exports[`FlowNavigation renders as expected 1`] = `
|
|
|
208
207
|
>
|
|
209
208
|
<div
|
|
210
209
|
class="progress-bar"
|
|
211
|
-
|
|
212
|
-
style="width: 0%;"
|
|
210
|
+
style="width: 0px;"
|
|
213
211
|
/>
|
|
214
212
|
</div>
|
|
215
213
|
<ol
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { render, screen, userEvent } from '../test-utils';
|
|
2
|
+
import RadioOption, { type RadioOptionProps } from '.';
|
|
3
|
+
|
|
4
|
+
describe('Radio option', () => {
|
|
5
|
+
const initialProps = {
|
|
6
|
+
id: 'componentId',
|
|
7
|
+
name: 'componentName',
|
|
8
|
+
title: 'Component Title',
|
|
9
|
+
content: <img alt="contentImage" />,
|
|
10
|
+
onChange: jest.fn(),
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const customRender = (overrides: Partial<RadioOptionProps> = {}) =>
|
|
14
|
+
render(<RadioOption {...initialProps} {...overrides} />);
|
|
15
|
+
|
|
16
|
+
it('should render `media`', () => {
|
|
17
|
+
const Icon = <img alt="media" />;
|
|
18
|
+
customRender({ media: Icon });
|
|
19
|
+
expect(screen.getByRole('img', { name: 'media' })).toBeInTheDocument();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('passes props to radio button', () => {
|
|
23
|
+
customRender();
|
|
24
|
+
expect(screen.getByRole('radio')).toHaveAttribute('id', initialProps.id);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('passes name to radio button', () => {
|
|
28
|
+
customRender();
|
|
29
|
+
expect(screen.getByRole('radio')).toHaveAttribute('name', initialProps.name);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('checked', () => {
|
|
33
|
+
it('should be `false` by default', () => {
|
|
34
|
+
customRender();
|
|
35
|
+
expect(screen.getByRole('radio')).not.toBeChecked();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should respect the prop', () => {
|
|
39
|
+
customRender({ checked: true });
|
|
40
|
+
expect(screen.getByRole('radio')).toBeChecked();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('passes change handler to radio button', async () => {
|
|
45
|
+
customRender();
|
|
46
|
+
await userEvent.click(screen.getByRole('radio'));
|
|
47
|
+
expect(initialProps.onChange).toHaveBeenCalledTimes(1);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('disabled', () => {
|
|
51
|
+
it('should be `false` by default', () => {
|
|
52
|
+
customRender();
|
|
53
|
+
expect(screen.getByRole('radio')).toBeEnabled();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should respect the prop', () => {
|
|
57
|
+
customRender({ disabled: true });
|
|
58
|
+
expect(screen.getByRole('radio')).toBeDisabled();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('isContainerAligned', () => {
|
|
63
|
+
it('should not be aligned by default', () => {
|
|
64
|
+
const { container } = customRender();
|
|
65
|
+
expect(container.querySelector('.np-option')).not.toHaveClass('np-option__container-aligned');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('renders aligned with container content', () => {
|
|
69
|
+
const { container } = customRender({ isContainerAligned: true });
|
|
70
|
+
expect(container.querySelector('.np-option')).toHaveClass('np-option__container-aligned');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { shallow } from 'enzyme';
|
|
2
|
+
|
|
3
|
+
import { Tooltip } from '..';
|
|
2
4
|
|
|
3
5
|
import Stepper from './Stepper';
|
|
4
6
|
|
|
@@ -6,231 +8,226 @@ jest.mock('./deviceDetection', () => ({
|
|
|
6
8
|
isTouchDevice: jest.fn(() => false),
|
|
7
9
|
}));
|
|
8
10
|
|
|
9
|
-
const generateSteps = (stepsCount) =>
|
|
10
|
-
Array.from({ length: stepsCount }, () => ({
|
|
11
|
-
label: Math.random().toString(),
|
|
12
|
-
onClick: jest.fn(),
|
|
13
|
-
}));
|
|
14
|
-
|
|
15
11
|
describe('Stepper', () => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
steps: generateSteps(3),
|
|
19
|
-
};
|
|
12
|
+
let props;
|
|
13
|
+
let component;
|
|
20
14
|
let fakeDeviceDetection;
|
|
21
15
|
|
|
22
16
|
beforeEach(() => {
|
|
23
17
|
fakeDeviceDetection = require('./deviceDetection');
|
|
24
|
-
|
|
18
|
+
props = {
|
|
19
|
+
activeStep: 0,
|
|
20
|
+
steps: ['one', 'two', 'three'].map((label) => ({ label })),
|
|
21
|
+
};
|
|
22
|
+
component = shallow(<Stepper {...props} />);
|
|
25
23
|
});
|
|
26
24
|
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
const activeStep = (step) => component.setProps({ activeStep: step });
|
|
26
|
+
const steps = (howMany) =>
|
|
27
|
+
component.setProps({
|
|
28
|
+
steps: new Array(...new Array(howMany)).map((_, index) => ({ label: index.toString() })),
|
|
29
|
+
});
|
|
32
30
|
|
|
33
31
|
describe('progress bar', () => {
|
|
34
|
-
|
|
35
|
-
customRender({ steps: [] });
|
|
36
|
-
expect(screen.queryByTestId('progress-bar')).not.toBeInTheDocument();
|
|
37
|
-
});
|
|
38
|
-
});
|
|
32
|
+
const totalWidth = () => component.find('.progress-bar').prop('style').width;
|
|
39
33
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
customRender({ steps });
|
|
34
|
+
describe('when no steps are passed in', () => {
|
|
35
|
+
it('renders nothing', () => {
|
|
36
|
+
component.setProps({ steps: [] });
|
|
44
37
|
|
|
45
|
-
|
|
46
|
-
expect(step).toHaveTextContent(steps[index].label);
|
|
38
|
+
expect(component.isEmptyRender()).toBe(true);
|
|
47
39
|
});
|
|
48
40
|
});
|
|
49
41
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
{ label: '0' },
|
|
69
|
-
{ label: '1', onClick: jest.fn() },
|
|
70
|
-
{ label: '2', onClick: jest.fn() },
|
|
71
|
-
];
|
|
72
|
-
customRender({ steps, activeStep: 1 });
|
|
73
|
-
expectStepIsVisuallyInteractive(0).toBe(false);
|
|
74
|
-
expectStepIsVisuallyInteractive(1).toBe(false);
|
|
75
|
-
});
|
|
42
|
+
it('sets the widths of the progress bar to match where you are in the flow', () => {
|
|
43
|
+
expect(totalWidth()).toBe('0px');
|
|
44
|
+
activeStep(2);
|
|
45
|
+
expect(totalWidth()).toBe(
|
|
46
|
+
'calc(100% + var(--progress-bar-start-shift) + var(--progress-bar-border-width))',
|
|
47
|
+
);
|
|
48
|
+
steps(5);
|
|
49
|
+
expect(totalWidth()).toBe(
|
|
50
|
+
'calc(50% + var(--progress-bar-start-shift) + var(--progress-bar-border-width))',
|
|
51
|
+
);
|
|
52
|
+
activeStep(10000);
|
|
53
|
+
expect(totalWidth()).toBe(
|
|
54
|
+
'calc(100% + var(--progress-bar-start-shift) + var(--progress-bar-border-width))',
|
|
55
|
+
);
|
|
56
|
+
activeStep(-10);
|
|
57
|
+
expect(totalWidth()).toBe('0px');
|
|
58
|
+
});
|
|
59
|
+
});
|
|
76
60
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
expectStepIsVisuallyInteractive(0).toBe(true);
|
|
85
|
-
expectStepIsVisuallyInteractive(1).toBe(true);
|
|
86
|
-
expectStepIsVisuallyInteractive(2).toBe(false);
|
|
61
|
+
describe('steps', () => {
|
|
62
|
+
it('have rendered labels', () => {
|
|
63
|
+
steps(5);
|
|
64
|
+
[0, 1, 2, 3, 4].forEach((step) => {
|
|
65
|
+
expect(component.find('.tw-stepper__step').at(step).find('span').props().children).toBe(
|
|
66
|
+
step.toString(),
|
|
67
|
+
);
|
|
87
68
|
});
|
|
88
69
|
});
|
|
89
70
|
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
it('is not interactive if it is the active step', async () => {
|
|
94
|
-
const steps = [
|
|
95
|
-
{ label: '0', onClick: jest.fn() },
|
|
96
|
-
{ label: '1', onClick: jest.fn() },
|
|
97
|
-
{ label: '2', onClick: jest.fn() },
|
|
98
|
-
];
|
|
99
|
-
customRender({ steps, activeStep: 0 });
|
|
100
|
-
await userEvent.click(getStepChild(0));
|
|
101
|
-
expect(steps[0].onClick).not.toHaveBeenCalled();
|
|
102
|
-
});
|
|
71
|
+
it('are active when clickable and completed', () => {
|
|
72
|
+
const stepActive = (index) =>
|
|
73
|
+
component.find('.tw-stepper__step').at(index).hasClass('tw-stepper__step--clickable');
|
|
103
74
|
|
|
104
|
-
|
|
105
|
-
|
|
75
|
+
component.setProps({
|
|
76
|
+
steps: [
|
|
106
77
|
{ label: '0' },
|
|
107
|
-
{ label: '1', onClick:
|
|
108
|
-
{ label: '2', onClick:
|
|
109
|
-
]
|
|
110
|
-
|
|
111
|
-
await userEvent.click(getStepChild(0));
|
|
112
|
-
expect(steps[1].onClick).not.toHaveBeenCalled();
|
|
113
|
-
await userEvent.click(getStepChild(1));
|
|
114
|
-
expect(steps[1].onClick).not.toHaveBeenCalled();
|
|
78
|
+
{ label: '1', onClick: () => null },
|
|
79
|
+
{ label: '2', onClick: () => null },
|
|
80
|
+
],
|
|
81
|
+
activeStep: 0,
|
|
115
82
|
});
|
|
116
83
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
expect(steps[1].onClick).toHaveBeenCalledTimes(1);
|
|
126
|
-
});
|
|
84
|
+
expect(stepActive(0)).toBe(false);
|
|
85
|
+
activeStep(1);
|
|
86
|
+
expect(stepActive(0)).toBe(false);
|
|
87
|
+
expect(stepActive(1)).toBe(false);
|
|
88
|
+
activeStep(2);
|
|
89
|
+
expect(stepActive(0)).toBe(false);
|
|
90
|
+
expect(stepActive(1)).toBe(true);
|
|
91
|
+
expect(stepActive(2)).toBe(false);
|
|
127
92
|
});
|
|
128
93
|
|
|
129
|
-
it('are not clickable when active',
|
|
94
|
+
it('are not clickable when active', () => {
|
|
95
|
+
const clickOnStep = (index) => {
|
|
96
|
+
const buttonReference = component.find('.tw-stepper__step').at(index).find('button');
|
|
97
|
+
if (buttonReference.exists()) {
|
|
98
|
+
buttonReference.simulate('click');
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const buttonDisabled = (index) =>
|
|
102
|
+
!component.find('.tw-stepper__step').at(index).find('button').exists();
|
|
130
103
|
const clickedOnFirstStep = jest.fn();
|
|
131
104
|
const clickedOnSecondStep = jest.fn();
|
|
132
|
-
|
|
105
|
+
component.setProps({
|
|
133
106
|
steps: [
|
|
134
|
-
{ label: '
|
|
135
|
-
{ label: '
|
|
107
|
+
{ label: '0', onClick: clickedOnFirstStep },
|
|
108
|
+
{ label: '1', onClick: clickedOnSecondStep },
|
|
136
109
|
],
|
|
137
110
|
activeStep: 0,
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const clickOnStep = async (stepIndex) => {
|
|
142
|
-
const step = screen.getByText(initialProps.steps[stepIndex].label).parentElement;
|
|
143
|
-
if (step) {
|
|
144
|
-
return await userEvent.click(step);
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
await clickOnStep(0);
|
|
111
|
+
});
|
|
112
|
+
clickOnStep(0);
|
|
113
|
+
expect(buttonDisabled(0)).toBe(true);
|
|
149
114
|
expect(clickedOnFirstStep).not.toHaveBeenCalled();
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
115
|
+
activeStep(1);
|
|
116
|
+
expect(buttonDisabled(0)).toBe(false);
|
|
117
|
+
clickOnStep(0);
|
|
153
118
|
expect(clickedOnFirstStep).toHaveBeenCalledTimes(1);
|
|
154
|
-
|
|
155
|
-
await clickOnStep(1);
|
|
119
|
+
clickOnStep(1);
|
|
156
120
|
expect(clickedOnSecondStep).not.toHaveBeenCalled();
|
|
157
121
|
});
|
|
158
122
|
|
|
159
123
|
it('are active when they are the currently active step', () => {
|
|
160
|
-
const { rerender } = customRender({
|
|
161
|
-
steps: Array(4)
|
|
162
|
-
.fill()
|
|
163
|
-
.map((_, i) => ({ label: i.toString() })),
|
|
164
|
-
activeStep: 1,
|
|
165
|
-
});
|
|
166
|
-
|
|
167
124
|
const stepActive = (index) =>
|
|
168
|
-
|
|
169
|
-
|
|
125
|
+
component.find('.tw-stepper__step').at(index).hasClass('tw-stepper__step--active');
|
|
126
|
+
steps(4);
|
|
127
|
+
activeStep(1);
|
|
170
128
|
expect(stepActive(0)).toBe(false);
|
|
171
129
|
expect(stepActive(1)).toBe(true);
|
|
172
130
|
expect(stepActive(2)).toBe(false);
|
|
173
131
|
expect(stepActive(3)).toBe(false);
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
132
|
+
activeStep(2);
|
|
133
|
+
expect(stepActive(0)).toBe(false);
|
|
177
134
|
expect(stepActive(1)).toBe(false);
|
|
178
135
|
expect(stepActive(2)).toBe(true);
|
|
136
|
+
expect(stepActive(3)).toBe(false);
|
|
179
137
|
});
|
|
180
138
|
|
|
181
|
-
it('are
|
|
182
|
-
const
|
|
139
|
+
it('are marked as visited when active index is less than or equals to current index', () => {
|
|
140
|
+
const step = (index) => {
|
|
141
|
+
const buttonStates = ['tw-stepper__step--active', 'tw-stepper__step--clickable'];
|
|
142
|
+
const stepElement = component.find('.tw-stepper__step').at(index);
|
|
143
|
+
return {
|
|
144
|
+
active: stepElement.hasClass(buttonStates[0]),
|
|
145
|
+
clickable: stepElement.hasClass(buttonStates[1]),
|
|
146
|
+
clickableAndActive: buttonStates.every((c) => stepElement.hasClass(c)),
|
|
147
|
+
disabled: !stepElement.find('button').exists(),
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
component.setProps({
|
|
152
|
+
steps: [
|
|
153
|
+
{ label: '0', onClick: () => {} },
|
|
154
|
+
{ label: '1', onClick: () => {} },
|
|
155
|
+
{ label: '2', onClick: () => {} },
|
|
156
|
+
],
|
|
157
|
+
activeStep: 0,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
expect(step(0).active).toBe(true);
|
|
161
|
+
expect(step(0).disabled).toBe(true);
|
|
162
|
+
expect(step(1).clickableAndActive).toBe(false);
|
|
163
|
+
expect(step(2).clickableAndActive).toBe(false);
|
|
164
|
+
|
|
165
|
+
activeStep(2);
|
|
166
|
+
activeStep(0);
|
|
183
167
|
|
|
184
|
-
|
|
168
|
+
expect(step(1).clickable).toBe(true);
|
|
169
|
+
expect(step(2).clickable).toBe(true);
|
|
170
|
+
});
|
|
185
171
|
|
|
172
|
+
it('are aria-current=step when active', () => {
|
|
173
|
+
const stepCurrent = (index) =>
|
|
174
|
+
component.find('.tw-stepper__step').at(index).props()['aria-current'];
|
|
175
|
+
steps(4);
|
|
176
|
+
activeStep(1);
|
|
186
177
|
expect(stepCurrent(0)).toBe(false);
|
|
187
|
-
expect(stepCurrent(1)).toBe(
|
|
178
|
+
expect(stepCurrent(1)).toBe('step');
|
|
188
179
|
expect(stepCurrent(2)).toBe(false);
|
|
189
180
|
expect(stepCurrent(3)).toBe(false);
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
181
|
+
activeStep(2);
|
|
182
|
+
expect(stepCurrent(0)).toBe(false);
|
|
193
183
|
expect(stepCurrent(1)).toBe(false);
|
|
194
|
-
expect(stepCurrent(2)).toBe(
|
|
184
|
+
expect(stepCurrent(2)).toBe('step');
|
|
185
|
+
expect(stepCurrent(3)).toBe(false);
|
|
195
186
|
});
|
|
196
187
|
});
|
|
197
188
|
|
|
198
189
|
describe('hover labels', () => {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
steps: [{ hoverLabel, label: 'label' }, { label: 'label 2' }],
|
|
190
|
+
const step = (index) => component.find('.tw-stepper__step').at(index);
|
|
191
|
+
it('will be rendered when provided', () => {
|
|
192
|
+
component.setProps({
|
|
193
|
+
steps: [{ hoverLabel: 'hover', label: 'label' }, { label: 'label 2' }],
|
|
203
194
|
});
|
|
204
|
-
|
|
195
|
+
const firstStepHoverLabel = step(0).children();
|
|
196
|
+
expect(firstStepHoverLabel.type()).toBe(Tooltip);
|
|
197
|
+
expect(firstStepHoverLabel.children().render().text()).toBe('label');
|
|
198
|
+
expect(step(1).find('span').props().children).toBe('label 2');
|
|
205
199
|
});
|
|
206
200
|
|
|
207
|
-
it('renders jsx',
|
|
208
|
-
|
|
201
|
+
it('renders jsx', () => {
|
|
202
|
+
component.setProps({
|
|
209
203
|
steps: [
|
|
210
204
|
{
|
|
211
205
|
hoverLabel: (
|
|
212
206
|
<>
|
|
213
|
-
<
|
|
214
|
-
<p>hover label 2</p>
|
|
207
|
+
hover <p>label</p>
|
|
215
208
|
</>
|
|
216
209
|
),
|
|
217
|
-
label: '
|
|
210
|
+
label: '1',
|
|
218
211
|
},
|
|
219
212
|
],
|
|
220
213
|
});
|
|
221
214
|
|
|
222
|
-
expect(
|
|
223
|
-
|
|
215
|
+
expect(step(0).children().prop('label')).toStrictEqual(
|
|
216
|
+
<>
|
|
217
|
+
hover <p>label</p>
|
|
218
|
+
</>,
|
|
219
|
+
);
|
|
224
220
|
});
|
|
225
221
|
|
|
226
222
|
it('will not be rendered if the user is on a touch device', () => {
|
|
227
223
|
jest.spyOn(fakeDeviceDetection, 'isTouchDevice').mockImplementation(() => true);
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
steps: [{ hoverLabel: 'hover label', label: 'label' }, { label: 'label 2' }],
|
|
224
|
+
component.setProps({
|
|
225
|
+
steps: [{ hoverLabel: 'hover', label: 'label' }, { label: 'label 2' }],
|
|
231
226
|
});
|
|
232
|
-
|
|
233
|
-
expect(
|
|
227
|
+
const firstStepHoverLabel = step(0).children();
|
|
228
|
+
expect(firstStepHoverLabel.type()).toBe('span');
|
|
229
|
+
expect(firstStepHoverLabel.props().children).toBe('label');
|
|
230
|
+
expect(step(1).children().props().children).toBe('label 2');
|
|
234
231
|
});
|
|
235
232
|
});
|
|
236
233
|
});
|
package/src/stepper/Stepper.tsx
CHANGED
|
@@ -21,14 +21,13 @@ export interface StepperProps {
|
|
|
21
21
|
steps: readonly Step[];
|
|
22
22
|
activeStep?: number;
|
|
23
23
|
className?: string;
|
|
24
|
-
testId?: string;
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
/**
|
|
28
27
|
* This component is considered user-unfriendly and inaccessible on its own and will likely be made internal in the future. Please use `FlowNavigation` instead.
|
|
29
28
|
* @see https://storybook.wise.design/?path=/story/navigation-flownavigation--variants
|
|
30
29
|
*/
|
|
31
|
-
const Stepper = ({ steps, activeStep = 0, className
|
|
30
|
+
const Stepper = ({ steps, activeStep = 0, className }: StepperProps) => {
|
|
32
31
|
const { isRTL } = useDirection();
|
|
33
32
|
|
|
34
33
|
if (steps.length === 0) {
|
|
@@ -41,7 +40,7 @@ const Stepper = ({ steps, activeStep = 0, className, testId }: StepperProps) =>
|
|
|
41
40
|
|
|
42
41
|
const getProgressWidth = (): string => {
|
|
43
42
|
if (percentageCompleted === 0) {
|
|
44
|
-
return '
|
|
43
|
+
return '0px';
|
|
45
44
|
}
|
|
46
45
|
/**
|
|
47
46
|
* Progress bar starts with left/right (depends on rtl) shift `--progress-bar-start-shift` for hiding Progress bar's left and right borders
|
|
@@ -96,13 +95,9 @@ const Stepper = ({ steps, activeStep = 0, className, testId }: StepperProps) =>
|
|
|
96
95
|
};
|
|
97
96
|
|
|
98
97
|
return (
|
|
99
|
-
<div className={clsx('tw-stepper', className)}
|
|
98
|
+
<div className={clsx('tw-stepper', className)}>
|
|
100
99
|
<div className="progress">
|
|
101
|
-
<div
|
|
102
|
-
className="progress-bar"
|
|
103
|
-
style={{ width: getProgressWidth() }}
|
|
104
|
-
data-testid="progress-bar"
|
|
105
|
-
/>
|
|
100
|
+
<div className="progress-bar" style={{ width: getProgressWidth() }} />
|
|
106
101
|
</div>
|
|
107
102
|
<ol className="tw-stepper-steps p-t-1 m-b-0">{steps.map(renderStep)}</ol>
|
|
108
103
|
</div>
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { shallow } from 'enzyme';
|
|
2
|
-
|
|
3
|
-
import Option from '../common/Option';
|
|
4
|
-
|
|
5
|
-
import RadioOption from '.';
|
|
6
|
-
|
|
7
|
-
describe('Radio option', () => {
|
|
8
|
-
let component;
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
component = shallow(
|
|
11
|
-
<RadioOption media={<span />} id="" name="" title="" content="" onChange={jest.fn()} />,
|
|
12
|
-
);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('passes shared props to option', () => {
|
|
16
|
-
const Icon = () => <svg />;
|
|
17
|
-
const sharedProps = {
|
|
18
|
-
media: <Icon />,
|
|
19
|
-
title: 'A title',
|
|
20
|
-
content: 'A content',
|
|
21
|
-
name: 'a-name',
|
|
22
|
-
complex: true,
|
|
23
|
-
disabled: true,
|
|
24
|
-
};
|
|
25
|
-
component.setProps(sharedProps);
|
|
26
|
-
|
|
27
|
-
expect(option().props()).toStrictEqual(expect.objectContaining(sharedProps));
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('passes id to radio button passed as button', () => {
|
|
31
|
-
component.setProps({ id: 'some-id' });
|
|
32
|
-
expect(buttonProperty('id')).toBe('some-id');
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('passes name to radio button passed as button', () => {
|
|
36
|
-
component.setProps({ name: 'a-name' });
|
|
37
|
-
expect(buttonProperty('name')).toBe('a-name');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('passes checked to radio button passed as button', () => {
|
|
41
|
-
expect(buttonProperty('checked')).toBeFalsy();
|
|
42
|
-
component.setProps({ checked: true });
|
|
43
|
-
expect(buttonProperty('checked')).toBeTruthy();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('passes change handler to radio button passed as button', () => {
|
|
47
|
-
const onChange = jest.fn();
|
|
48
|
-
component.setProps({ onChange });
|
|
49
|
-
expect(buttonProperty('onChange')).toBe(onChange);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('passes disabled to radio button passed as button', () => {
|
|
53
|
-
expect(buttonProperty('disabled')).toBeFalsy();
|
|
54
|
-
component.setProps({ disabled: true });
|
|
55
|
-
expect(buttonProperty('disabled')).toBeTruthy();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('renders aligned with container content', () => {
|
|
59
|
-
component.setProps({ isContainerAligned: true });
|
|
60
|
-
expect(component.find(Option).shallow().prop('className')).toContain(
|
|
61
|
-
'np-option__container-aligned',
|
|
62
|
-
);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const option = () => component.find(Option);
|
|
66
|
-
const buttonProperty = (name) => option().prop('button').props[name];
|
|
67
|
-
});
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import { fn, within, expect, screen } from '@storybook/test';
|
|
3
|
-
import Stepper from './Stepper';
|
|
4
|
-
|
|
5
|
-
const STEPS = [
|
|
6
|
-
{
|
|
7
|
-
label: 'One',
|
|
8
|
-
onClick: fn(),
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
label: 'Two',
|
|
12
|
-
hoverLabel: (
|
|
13
|
-
<>
|
|
14
|
-
<div>
|
|
15
|
-
<strong>Diana Jaramillo</strong>
|
|
16
|
-
</div>
|
|
17
|
-
dianajarm123@gmail.com
|
|
18
|
-
</>
|
|
19
|
-
),
|
|
20
|
-
onClick: fn(),
|
|
21
|
-
},
|
|
22
|
-
{ label: 'Three', onClick: fn() },
|
|
23
|
-
{ label: 'Four', onClick: fn() },
|
|
24
|
-
{ label: 'Five', onClick: fn() },
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
const meta = {
|
|
28
|
-
component: Stepper,
|
|
29
|
-
title: 'Navigation/Stepper/tests',
|
|
30
|
-
argTypes: {
|
|
31
|
-
activeStep: {
|
|
32
|
-
control: 'radio',
|
|
33
|
-
options: [...Array(STEPS.length).keys()],
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
} satisfies Meta<typeof Stepper>;
|
|
37
|
-
export default meta;
|
|
38
|
-
|
|
39
|
-
type Story = StoryObj<typeof meta>;
|
|
40
|
-
|
|
41
|
-
export const ProgressbarWidth: Story = {
|
|
42
|
-
play: async ({ step }) => {
|
|
43
|
-
const getBarBaseWidth = (stepIndex: number) => {
|
|
44
|
-
const instance = screen.getByTestId(`stepper${stepIndex}`);
|
|
45
|
-
return within(instance).getByTestId('progress-bar')?.style.width;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
await step('activeStep: -10 (negative) ▸ width should be 0', async () => {
|
|
49
|
-
await expect(getBarBaseWidth(-10)).toBe(`0%`);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
await step('activeStep: 0 ▸ width should be 0', async () => {
|
|
53
|
-
await expect(getBarBaseWidth(0)).toBe(`0%`);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const WIDTHS = [0, 25, 50, 75, 100];
|
|
57
|
-
// eslint-disable-next-line no-plusplus
|
|
58
|
-
for (let stepIndex = 1; stepIndex < STEPS.length; stepIndex++) {
|
|
59
|
-
await step(
|
|
60
|
-
`activeStep: ${stepIndex} ▸ base width should be ${WIDTHS[stepIndex]}%`,
|
|
61
|
-
async () => {
|
|
62
|
-
await expect(getBarBaseWidth(stepIndex)).toMatch(
|
|
63
|
-
new RegExp(`^calc\\(${WIDTHS[stepIndex]}%.*?`),
|
|
64
|
-
);
|
|
65
|
-
},
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
await step('activeStep: 1000 ▸ base width should be 100%', async () => {
|
|
70
|
-
await expect(getBarBaseWidth(1000)).toMatch(/^calc\(100%.*?/);
|
|
71
|
-
});
|
|
72
|
-
},
|
|
73
|
-
render: function Render() {
|
|
74
|
-
return (
|
|
75
|
-
<>
|
|
76
|
-
<Stepper steps={STEPS} activeStep={0} testId="stepper-10" />
|
|
77
|
-
<Stepper steps={STEPS} activeStep={0} testId="stepper0" />
|
|
78
|
-
<Stepper steps={STEPS} activeStep={1} testId="stepper1" />
|
|
79
|
-
<Stepper steps={STEPS} activeStep={2} testId="stepper2" />
|
|
80
|
-
<Stepper steps={STEPS} activeStep={3} testId="stepper3" />
|
|
81
|
-
<Stepper steps={STEPS} activeStep={4} testId="stepper4" />
|
|
82
|
-
<Stepper steps={STEPS} activeStep={4} testId="stepper1000" />
|
|
83
|
-
</>
|
|
84
|
-
);
|
|
85
|
-
},
|
|
86
|
-
args: {
|
|
87
|
-
steps: STEPS,
|
|
88
|
-
},
|
|
89
|
-
};
|