@availity/mui-stepper 0.1.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
+
5
+ ## 0.1.0 (2024-07-22)
6
+
7
+ ### Dependency Updates
8
+
9
+ * `mui-button` updated to version `0.1.0`
10
+ * `mui-layout` updated to version `0.1.0`
11
+ * `mui-typography` updated to version `0.1.0`
12
+ * `mui-icon` updated to version `0.1.0`
13
+
14
+ ### Features
15
+
16
+ * **mui-stepper:** add Stepper component ([04e21e8](https://github.com/Availity/element/commit/04e21e8f5117c79f0e110308482ed1277a9a16e7))
package/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # @availity/mui-stepper
2
+
3
+ > Availity MUI Stepper component to be used with @availity/element design system.
4
+
5
+ [![Version](https://img.shields.io/npm/v/@availity/mui-stepper.svg?style=for-the-badge)](https://www.npmjs.com/package/@availity/mui-stepper)
6
+ [![NPM Downloads](https://img.shields.io/npm/dt/@availity/mui-stepper.svg?style=for-the-badge)](https://www.npmjs.com/package/@availity/mui-stepper)
7
+ [![Dependency Status](https://img.shields.io/librariesio/release/npm/@availity/mui-stepper?style=for-the-badge)](https://github.com/Availity/element/blob/main/packages/mui-stepper/package.json)
8
+
9
+ ## Documentation
10
+
11
+ This package extends the MUI Stepper component: [MUI Stepper Docs](https://mui.com/components/stepper/)
12
+
13
+ Live demo and documentation in our [Storybook](https://availity.github.io/element/?path=/docs/components-stepper-introduction--docs)
14
+
15
+ Availity standards for design and usage can be found in the [Availity Design Guide](https://zeroheight.com/2e36e50c7)
16
+
17
+ ## Installation
18
+
19
+ ### Import Through @availity/element (Recommended)
20
+
21
+ #### NPM
22
+
23
+ ```bash
24
+ npm install @availity/element
25
+ ```
26
+
27
+ #### Yarn
28
+
29
+ ```bash
30
+ yarn add @availity/element
31
+ ```
32
+
33
+ ### Direct Import
34
+
35
+ #### NPM
36
+
37
+ _This package has a few peer dependencies. Add `@mui/material` & `@emotion/react` to your project if not already installed._
38
+
39
+ ```bash
40
+ npm install @availity/mui-stepper
41
+ ```
42
+
43
+ #### Yarn
44
+
45
+ ```bash
46
+ yarn add @availity/mui-stepper
47
+ ```
48
+
49
+ ### Usage
50
+
51
+ #### Import through @availity/element
52
+
53
+ ```tsx
54
+ import { Stepper } from '@availity/element';
55
+ ```
56
+
57
+ #### Direct import
58
+
59
+ ```tsx
60
+ import { Stepper } from '@availity/mui-stepper';
61
+ ```
62
+
63
+ #### Simple Stepper
64
+
65
+ ```jsx
66
+ import { useState } from 'react';
67
+ import { Stepper, Step, StepLabel } from '@availity/element';
68
+
69
+ const steps = ['Step 1', 'Step 2', 'Step 3'];
70
+
71
+ const Example = () => {
72
+ const [activeStep, setActiveStep] = useState(0);
73
+
74
+ const handleBack = () => {
75
+ setActiveStep((prevActiveStep) => prevActiveStep - 1);
76
+ };
77
+
78
+ const handleNext = () => {
79
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
80
+ };
81
+
82
+ return (
83
+ <>
84
+ <Stepper activeStep={0}>
85
+ {steps.map((label, index) => {
86
+ return (
87
+ <Step key={label}>
88
+ <StepLabel>{label}</StepLabel>
89
+ </Step>
90
+ );
91
+ })}
92
+ </Stepper>
93
+ <Button color="secondary" disabled={activeStep === 0} onClick={handleBack} sx={{ mr: 1 }}>
94
+ Back
95
+ </Button>
96
+ <Button color={activeStep === steps.length - 1 ? 'primary' : 'secondary'} onClick={handleNext}>
97
+ {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
98
+ </Button>
99
+ </>
100
+ );
101
+ };
102
+ ```
@@ -0,0 +1,6 @@
1
+ import { StepperProps as StepperProps$1 } from '@mui/material/Stepper';
2
+
3
+ type StepperProps = Omit<StepperProps$1, 'alternativeLabel' | 'elevation'>;
4
+ declare const Stepper: ({ children, orientation, ...rest }: StepperProps) => JSX.Element;
5
+
6
+ export { Stepper, type StepperProps };
@@ -0,0 +1,6 @@
1
+ import { StepperProps as StepperProps$1 } from '@mui/material/Stepper';
2
+
3
+ type StepperProps = Omit<StepperProps$1, 'alternativeLabel' | 'elevation'>;
4
+ declare const Stepper: ({ children, orientation, ...rest }: StepperProps) => JSX.Element;
5
+
6
+ export { Stepper, type StepperProps };
package/dist/index.js ADDED
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __defProps = Object.defineProperties;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
9
+ var __getProtoOf = Object.getPrototypeOf;
10
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
11
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
12
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
+ var __spreadValues = (a, b) => {
14
+ for (var prop in b || (b = {}))
15
+ if (__hasOwnProp.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ if (__getOwnPropSymbols)
18
+ for (var prop of __getOwnPropSymbols(b)) {
19
+ if (__propIsEnum.call(b, prop))
20
+ __defNormalProp(a, prop, b[prop]);
21
+ }
22
+ return a;
23
+ };
24
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
25
+ var __objRest = (source, exclude) => {
26
+ var target = {};
27
+ for (var prop in source)
28
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
29
+ target[prop] = source[prop];
30
+ if (source != null && __getOwnPropSymbols)
31
+ for (var prop of __getOwnPropSymbols(source)) {
32
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
33
+ target[prop] = source[prop];
34
+ }
35
+ return target;
36
+ };
37
+ var __export = (target, all) => {
38
+ for (var name in all)
39
+ __defProp(target, name, { get: all[name], enumerable: true });
40
+ };
41
+ var __copyProps = (to, from, except, desc) => {
42
+ if (from && typeof from === "object" || typeof from === "function") {
43
+ for (let key of __getOwnPropNames(from))
44
+ if (!__hasOwnProp.call(to, key) && key !== except)
45
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
46
+ }
47
+ return to;
48
+ };
49
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
50
+ // If the importer is in node compatibility mode or this is not an ESM
51
+ // file that has been converted to a CommonJS file using a Babel-
52
+ // compatible transform (i.e. "__esModule" has not been set), then set
53
+ // "default" to the CommonJS "module.exports" for node compatibility.
54
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
55
+ mod
56
+ ));
57
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
58
+
59
+ // src/index.ts
60
+ var src_exports = {};
61
+ __export(src_exports, {
62
+ Stepper: () => Stepper
63
+ });
64
+ module.exports = __toCommonJS(src_exports);
65
+
66
+ // src/lib/Stepper.tsx
67
+ var import_Stepper = __toESM(require("@mui/material/Stepper"));
68
+ var import_jsx_runtime = require("react/jsx-runtime");
69
+ var Stepper = (_a) => {
70
+ var _b = _a, { children, orientation } = _b, rest = __objRest(_b, ["children", "orientation"]);
71
+ const alternativeLabel = orientation !== "vertical";
72
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_Stepper.default, __spreadProps(__spreadValues({}, rest), { orientation, alternativeLabel, children }));
73
+ };
74
+ // Annotate the CommonJS export names for ESM import in node:
75
+ 0 && (module.exports = {
76
+ Stepper
77
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,43 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __objRest = (source, exclude) => {
21
+ var target = {};
22
+ for (var prop in source)
23
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
+ target[prop] = source[prop];
25
+ if (source != null && __getOwnPropSymbols)
26
+ for (var prop of __getOwnPropSymbols(source)) {
27
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
+ target[prop] = source[prop];
29
+ }
30
+ return target;
31
+ };
32
+
33
+ // src/lib/Stepper.tsx
34
+ import MuiStepper from "@mui/material/Stepper";
35
+ import { jsx } from "react/jsx-runtime";
36
+ var Stepper = (_a) => {
37
+ var _b = _a, { children, orientation } = _b, rest = __objRest(_b, ["children", "orientation"]);
38
+ const alternativeLabel = orientation !== "vertical";
39
+ return /* @__PURE__ */ jsx(MuiStepper, __spreadProps(__spreadValues({}, rest), { orientation, alternativeLabel, children }));
40
+ };
41
+ export {
42
+ Stepper
43
+ };
@@ -0,0 +1,7 @@
1
+ import { Markdown } from '@storybook/blocks';
2
+ import { Meta } from '@storybook/addon-docs';
3
+ import ReadMe from './README.md?raw';
4
+
5
+ <Meta title="Components/Stepper/Introduction" />
6
+
7
+ <Markdown>{ReadMe}</Markdown>
package/jest.config.js ADDED
@@ -0,0 +1,7 @@
1
+ const global = require('../../jest.config.global');
2
+
3
+ module.exports = {
4
+ ...global,
5
+ displayName: 'stepper',
6
+ coverageDirectory: '../../coverage/stepper',
7
+ };
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@availity/mui-stepper",
3
+ "version": "0.1.0",
4
+ "description": "Availity MUI Stepper Component - part of the @availity/element design system",
5
+ "keywords": [
6
+ "react",
7
+ "typescript",
8
+ "availity",
9
+ "mui"
10
+ ],
11
+ "homepage": "https://availity.github.io/element/?path=/docs/components-stepper-introduction--docs",
12
+ "bugs": {
13
+ "url": "https://github.com/Availity/element/issues"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/Availity/element.git",
18
+ "directory": "packages/stepper"
19
+ },
20
+ "license": "MIT",
21
+ "author": "Availity Developers <AVOSS@availity.com>",
22
+ "browser": "./dist/index.js",
23
+ "main": "./dist/index.js",
24
+ "module": "./dist/index.mjs",
25
+ "types": "./dist/index.d.ts",
26
+ "scripts": {
27
+ "build": "tsup src/index.ts --format esm,cjs --dts",
28
+ "dev": "tsup src/index.ts --format esm,cjs --watch --dts",
29
+ "clean": "rm -rf dist",
30
+ "clean:nm": "rm -rf node_modules",
31
+ "publish": "yarn npm publish --tolerate-republish --access public",
32
+ "publish:canary": "yarn npm publish --access public --tag canary"
33
+ },
34
+ "dependencies": {
35
+ "@availity/mui-icon": "^0.9.0"
36
+ },
37
+ "devDependencies": {
38
+ "@availity/mui-button": "^0.6.8",
39
+ "@availity/mui-layout": "^0.1.6",
40
+ "@availity/mui-typography": "^0.2.0",
41
+ "@mui/material": "^5.15.15",
42
+ "react": "18.2.0",
43
+ "react-dom": "18.2.0",
44
+ "tsup": "^8.0.2",
45
+ "typescript": "^5.4.5"
46
+ },
47
+ "peerDependencies": {
48
+ "@mui/material": "^5.11.9",
49
+ "react": ">=16.3.0"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public"
53
+ }
54
+ }
package/project.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "mui-stepper",
3
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "packages/stepper/src",
5
+ "projectType": "library",
6
+ "tags": [],
7
+ "targets": {
8
+ "lint": {
9
+ "executor": "@nx/eslint:lint",
10
+ "options": {
11
+ "eslintConfig": ".eslintrc.json",
12
+ "silent": false,
13
+ "fix": false,
14
+ "cache": true,
15
+ "cacheLocation": "./node_modules/.cache/stepper/.eslintcache",
16
+ "maxWarnings": -1,
17
+ "quiet": false,
18
+ "noEslintrc": false,
19
+ "hasTypeAwareRules": true,
20
+ "cacheStrategy": "metadata"
21
+ }
22
+ },
23
+ "test": {
24
+ "executor": "@nx/jest:jest",
25
+ "outputs": ["{workspaceRoot}/coverage/stepper"],
26
+ "options": {
27
+ "jestConfig": "packages/stepper/jest.config.js"
28
+ }
29
+ },
30
+ "version": {
31
+ "executor": "@jscutlery/semver:version",
32
+ "options": {
33
+ "preset": "conventional",
34
+ "commitMessageFormat": "chore({projectName}): release version ${version} [skip ci]",
35
+ "tagPrefix": "@availity/{projectName}@",
36
+ "trackDeps": true,
37
+ "skipCommitTypes": ["docs"]
38
+ }
39
+ }
40
+ }
41
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './lib/Stepper';
@@ -0,0 +1,11 @@
1
+ import { render, screen } from '@testing-library/react';
2
+
3
+ import { Step } from './Step';
4
+
5
+ describe('Step', () => {
6
+ test('should render successfully', () => {
7
+ render(<Step>Test</Step>);
8
+
9
+ expect(screen.getByText('Test')).toBeTruthy();
10
+ });
11
+ });
@@ -0,0 +1,7 @@
1
+ import MuiStep, { StepProps as MuiStepProps } from '@mui/material/Step';
2
+
3
+ export type StepProps = MuiStepProps;
4
+
5
+ export const Step = ({ children, ...rest }: StepProps): JSX.Element => {
6
+ return <MuiStep {...rest}>{children}</MuiStep>;
7
+ };
@@ -0,0 +1,20 @@
1
+ import { fireEvent, render, screen } from '@testing-library/react';
2
+
3
+ import { StepButton } from './StepButton';
4
+
5
+ describe('StepButton', () => {
6
+ test('should render successfully', () => {
7
+ render(<StepButton>Next</StepButton>);
8
+
9
+ expect(screen.getByText('Next')).toBeTruthy();
10
+ });
11
+
12
+ test('should handle clicks', () => {
13
+ const fn = jest.fn();
14
+ render(<StepButton onClick={fn}>Next</StepButton>);
15
+
16
+ fireEvent.click(screen.getByText('Next'));
17
+
18
+ expect(fn).toHaveBeenCalled();
19
+ });
20
+ });
@@ -0,0 +1,7 @@
1
+ import MuiStepButton, { StepButtonProps as MuiStepButtonProps } from '@mui/material/StepButton';
2
+
3
+ export type StepButtonProps = MuiStepButtonProps;
4
+
5
+ export const StepButton = ({ children, ...rest }: StepButtonProps): JSX.Element => {
6
+ return <MuiStepButton {...rest}>{children}</MuiStepButton>;
7
+ };
@@ -0,0 +1,11 @@
1
+ import { render, screen } from '@testing-library/react';
2
+
3
+ import { StepConnector } from './StepConnector';
4
+
5
+ describe('StepConnector', () => {
6
+ test('should render successfully', () => {
7
+ render(<StepConnector data-testid="connector" />);
8
+
9
+ expect(screen.getByTestId('connector').className).toContain('MuiStepConnector-root');
10
+ });
11
+ });
@@ -0,0 +1,7 @@
1
+ import MuiStepConnector, { StepConnectorProps as MuiStepConnectorProps } from '@mui/material/StepConnector';
2
+
3
+ export type StepConnectorProps = MuiStepConnectorProps;
4
+
5
+ export const StepConnector = (props: StepConnectorProps): JSX.Element => {
6
+ return <MuiStepConnector {...props} />;
7
+ };
@@ -0,0 +1,11 @@
1
+ import { render, screen } from '@testing-library/react';
2
+
3
+ import { StepContent } from './StepContent';
4
+
5
+ describe('StepContent', () => {
6
+ test('should render successfully', () => {
7
+ render(<StepContent data-testid="content" />);
8
+
9
+ expect(screen.getByTestId('content').className).toContain('MuiStepContent-root');
10
+ });
11
+ });
@@ -0,0 +1,7 @@
1
+ import MuiStepContent, { StepContentProps as MuiStepContentProps } from '@mui/material/StepContent';
2
+
3
+ export type StepContentProps = MuiStepContentProps;
4
+
5
+ export const StepContent = ({ children, ...rest }: StepContentProps): JSX.Element => {
6
+ return <MuiStepContent {...rest}>{children}</MuiStepContent>;
7
+ };
@@ -0,0 +1,11 @@
1
+ import { render, screen } from '@testing-library/react';
2
+
3
+ import { StepIcon } from './StepIcon';
4
+
5
+ describe('StepIcon', () => {
6
+ test('should render successfully', () => {
7
+ render(<StepIcon icon={1} />);
8
+
9
+ expect(screen.getByText('1')).toBeTruthy();
10
+ });
11
+ });
@@ -0,0 +1,23 @@
1
+ import MuiStepIcon, { StepIconProps as MuiStepIconProps } from '@mui/material/StepIcon';
2
+ import { CheckCircleIcon, WarningCircleIcon } from '@availity/mui-icon';
3
+ import { SvgIconProps } from '@mui/material/SvgIcon';
4
+
5
+ type Tag = ((props: SvgIconProps) => JSX.Element) | null;
6
+
7
+ declare module '@mui/material/StepIcon' {
8
+ interface StepIconProps {
9
+ as?: Tag;
10
+ warning?: boolean;
11
+ }
12
+ }
13
+
14
+ export type StepIconProps = { warning?: boolean } & MuiStepIconProps;
15
+
16
+ export const StepIcon = ({ error, completed, warning, ...rest }: StepIconProps): JSX.Element => {
17
+ let tag: Tag = null;
18
+ if (error) tag = WarningCircleIcon;
19
+ if (warning) tag = (props: SvgIconProps) => <WarningCircleIcon color="warning" {...props} />;
20
+ if (completed) tag = CheckCircleIcon;
21
+
22
+ return <MuiStepIcon {...rest} error={error} completed={completed} as={tag} />;
23
+ };
@@ -0,0 +1,11 @@
1
+ import { render } from '@testing-library/react';
2
+
3
+ import { StepLabel } from './StepLabel';
4
+
5
+ describe('StepLabel', () => {
6
+ test('should render successfully', () => {
7
+ const { getByText } = render(<StepLabel>step 1</StepLabel>);
8
+
9
+ expect(getByText('step 1')).toBeTruthy();
10
+ });
11
+ });
@@ -0,0 +1,15 @@
1
+ import MuiStepLabel, { StepLabelProps as MuiStepLabelProps } from '@mui/material/StepLabel';
2
+
3
+ import { StepIcon } from './StepIcon';
4
+
5
+ export type StepLabelProps = {
6
+ warning?: boolean;
7
+ } & MuiStepLabelProps;
8
+
9
+ export const StepLabel = ({ children, error, warning, ...rest }: StepLabelProps): JSX.Element => {
10
+ return (
11
+ <MuiStepLabel StepIconProps={{ error, warning }} StepIconComponent={StepIcon} error={error} {...rest}>
12
+ {children}
13
+ </MuiStepLabel>
14
+ );
15
+ };
@@ -0,0 +1,162 @@
1
+ // Each exported component in the package should have its own stories file
2
+ import { useState } from 'react';
3
+ import type { Meta, StoryObj } from '@storybook/react';
4
+ import { Button } from '@availity/mui-button';
5
+ import { Typography } from '@availity/mui-typography';
6
+ import { Box } from '@availity/mui-layout';
7
+
8
+ import { Stepper, StepperProps } from './Stepper';
9
+ import { Step } from './Step';
10
+ import { StepLabel } from './StepLabel';
11
+
12
+ const meta: Meta<typeof Stepper> = {
13
+ title: 'Components/Stepper/Stepper',
14
+ component: Stepper,
15
+ tags: ['autodocs'],
16
+ argTypes: {
17
+ orientation: {
18
+ options: ['horizontal', 'vertical'],
19
+ },
20
+ },
21
+ };
22
+
23
+ export default meta;
24
+
25
+ const steps = ['Select', 'Another Step', 'Form Data', 'Create a new one'];
26
+
27
+ export const _Stepper: StoryObj<typeof Stepper> = {
28
+ render: (args: StepperProps) => {
29
+ const [activeStep, setActiveStep] = useState(0);
30
+ const [skipped, setSkipped] = useState(new Set<number>());
31
+
32
+ const isStepOptional = (step: number) => {
33
+ return step > 1;
34
+ };
35
+
36
+ const isStepSkipped = (step: number) => {
37
+ return skipped.has(step);
38
+ };
39
+
40
+ const isStepError = (step: number) => {
41
+ return step === 2 && activeStep < 2;
42
+ };
43
+
44
+ const isStepWarning = (step: number) => {
45
+ return step === 3 && activeStep < 3;
46
+ };
47
+
48
+ const handleNext = () => {
49
+ let newSkipped = skipped;
50
+ if (isStepSkipped(activeStep)) {
51
+ newSkipped = new Set(newSkipped.values());
52
+ newSkipped.delete(activeStep);
53
+ }
54
+
55
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
56
+ setSkipped(newSkipped);
57
+ };
58
+
59
+ const handleBack = () => {
60
+ setActiveStep((prevActiveStep) => prevActiveStep - 1);
61
+ };
62
+
63
+ const handleSkip = () => {
64
+ if (!isStepOptional(activeStep)) {
65
+ // You probably want to guard against something like this,
66
+ // it should never occur unless someone's actively trying to break something.
67
+ throw new Error("You can't skip a step that isn't optional.");
68
+ }
69
+
70
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
71
+ setSkipped((prevSkipped) => {
72
+ const newSkipped = new Set(prevSkipped.values());
73
+ newSkipped.add(activeStep);
74
+ return newSkipped;
75
+ });
76
+ };
77
+
78
+ const handleReset = () => {
79
+ setActiveStep(0);
80
+ };
81
+
82
+ return (
83
+ <Box maxWidth="75vw" marginX="auto">
84
+ <Stepper activeStep={activeStep} {...args}>
85
+ {steps.map((label, index) => {
86
+ const stepProps: { completed?: boolean } = {};
87
+ const labelProps: { optional?: React.ReactNode; error?: boolean; warning?: boolean } = {};
88
+
89
+ if (isStepOptional(index)) {
90
+ labelProps.optional = <Typography variant="caption">Optional</Typography>;
91
+ }
92
+
93
+ if (isStepSkipped(index)) {
94
+ stepProps.completed = false;
95
+ }
96
+
97
+ if (isStepError(index)) {
98
+ labelProps.error = true;
99
+ }
100
+
101
+ if (isStepWarning(index)) {
102
+ labelProps.warning = true;
103
+ }
104
+
105
+ return (
106
+ <Step key={label} {...stepProps}>
107
+ <StepLabel {...labelProps}>{label}</StepLabel>
108
+ </Step>
109
+ );
110
+ })}
111
+ </Stepper>
112
+ {activeStep === steps.length ? (
113
+ <>
114
+ <Typography sx={{ mt: 2, mb: 1 }}>All steps completed - you&apos;re finished</Typography>
115
+ <Box sx={{ display: 'flex', flexDirection: 'row', pt: 2 }}>
116
+ <Box sx={{ flex: '1 1 auto' }} />
117
+ <Button color="tertiary" onClick={handleReset}>
118
+ Reset
119
+ </Button>
120
+ </Box>
121
+ </>
122
+ ) : (
123
+ <>
124
+ <Typography sx={{ mt: 2, mb: 1 }}>Step {activeStep + 1}</Typography>
125
+ <Box sx={{ display: 'flex', flexDirection: 'row', pt: 2 }}>
126
+ <Button color="secondary" disabled={activeStep === 0} onClick={handleBack} sx={{ mr: 1 }}>
127
+ Back
128
+ </Button>
129
+ <Box sx={{ flex: '1 1 auto' }} />
130
+ {isStepOptional(activeStep) && (
131
+ <Button color="secondary" onClick={handleSkip} sx={{ mr: 1 }}>
132
+ Skip
133
+ </Button>
134
+ )}
135
+ <Button color={activeStep === steps.length - 1 ? 'primary' : 'secondary'} onClick={handleNext}>
136
+ {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
137
+ </Button>
138
+ </Box>
139
+ </>
140
+ )}
141
+ </Box>
142
+ );
143
+ },
144
+ args: {},
145
+ };
146
+
147
+ export const _StepLabel: StoryObj<typeof StepLabel> = {
148
+ render: (args) => <StepLabel {...args} />,
149
+ args: {
150
+ children: 'Step Label',
151
+ },
152
+ };
153
+
154
+ export const _Step: StoryObj<typeof Step> = {
155
+ render: (args) => (
156
+ <Stepper>
157
+ <Step {...args}>
158
+ <StepLabel>Label</StepLabel>
159
+ </Step>
160
+ </Stepper>
161
+ ),
162
+ };
@@ -0,0 +1,19 @@
1
+ import { render, screen } from '@testing-library/react';
2
+
3
+ import { Stepper } from './Stepper';
4
+ import { Step } from './Step';
5
+ import { StepLabel } from './StepLabel';
6
+
7
+ describe('Stepper', () => {
8
+ test('should render successfully', () => {
9
+ render(
10
+ <Stepper activeStep={0}>
11
+ <Step>
12
+ <StepLabel>step 1</StepLabel>
13
+ </Step>
14
+ </Stepper>
15
+ );
16
+
17
+ expect(screen.getByText('step 1')).toBeTruthy();
18
+ });
19
+ });
@@ -0,0 +1,13 @@
1
+ import MuiStepper, { StepperProps as MuiStepperProps } from '@mui/material/Stepper';
2
+
3
+ export type StepperProps = Omit<MuiStepperProps, 'alternativeLabel' | 'elevation'>;
4
+
5
+ export const Stepper = ({ children, orientation, ...rest }: StepperProps): JSX.Element => {
6
+ const alternativeLabel = orientation !== 'vertical';
7
+
8
+ return (
9
+ <MuiStepper {...rest} orientation={orientation} alternativeLabel={alternativeLabel}>
10
+ {children}
11
+ </MuiStepper>
12
+ );
13
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "include": ["."],
4
+ "exclude": ["dist", "build", "node_modules"]
5
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../dist/out-tsc",
5
+ "module": "commonjs",
6
+ "types": ["jest", "node", "@testing-library/jest-dom"],
7
+ "allowJs": true
8
+ },
9
+ "include": ["**/*.test.js", "**/*.test.ts", "**/*.test.tsx", "**/*.d.ts"]
10
+ }