Skip to content

Commit e33f53f

Browse files
committed
Creates WizardStep and WizardFooter
Prompt: The Footer and Step components have been scaffolded. Create both components with the following spec: Step: A single Step in the multi-step flow. Must be rendered within a Wizard. ```ts title: ReactNode; description: ReactNode; children: ReactNode; ``` Footer: The footer element for the Wizard. A wrapper around LeafyGreen `FormFooter`, but allows us to optionally inject event handlers into the buttons. ``` backButtonProps: ButtonProps; cancelButtonProps: ButtonProps; primaryButtonProps: ButtonProps; ```
1 parent b53e9f9 commit e33f53f

17 files changed

+182
-24
lines changed

packages/wizard/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
"access": "public"
2929
},
3030
"dependencies": {
31+
"@leafygreen-ui/button": "workspace:^",
3132
"@leafygreen-ui/emotion": "workspace:^",
33+
"@leafygreen-ui/form-footer": "workspace:^",
3234
"@leafygreen-ui/lib": "workspace:^",
3335
"@lg-tools/test-harnesses": "workspace:^"
3436
},

packages/wizard/src/Wizard/Wizard.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import React, { Children, cloneElement, isValidElement, useState } from 'react';
22

3+
import { WizardFooter } from '../WizardFooter';
4+
import { WizardStep } from '../WizardStep';
5+
36
import { stepContentStyles, wizardContainerStyles } from './Wizard.styles';
47
import { WizardProps } from './Wizard.types';
58

@@ -74,3 +77,5 @@ export function Wizard({
7477
}
7578

7679
Wizard.displayName = 'Wizard';
80+
Wizard.Step = WizardStep;
81+
Wizard.Footer = WizardFooter;

packages/wizard/src/Wizard/Wizard.types.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { ComponentPropsWithRef, ReactNode } from 'react';
22

3+
import { WizardFooter } from '../WizardFooter';
4+
import { WizardStep } from '../WizardStep';
5+
36
export interface WizardProps extends ComponentPropsWithRef<'div'> {
47
/**
58
* The current active step index (0-based). If provided, the component operates in controlled mode.
@@ -16,3 +19,10 @@ export interface WizardProps extends ComponentPropsWithRef<'div'> {
1619
*/
1720
children: ReactNode;
1821
}
22+
23+
export interface WizardComponent {
24+
(props: WizardProps): JSX.Element;
25+
Step: typeof WizardStep;
26+
Footer: typeof WizardFooter;
27+
displayName: string;
28+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export { Wizard } from './Wizard';
2-
export { type WizardProps } from './Wizard.types';
2+
export { type WizardComponent, type WizardProps } from './Wizard.types';
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
21
import React from 'react';
32
import { render } from '@testing-library/react';
43

54
import { WizardFooter } from '.';
65

76
describe('packages/wizard-footer', () => {
8-
test('condition', () => {
9-
10-
})
11-
})
7+
test('condition', () => {});
8+
});
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import { css } from '@leafygreen-ui/emotion';
32

43
export const baseStyles = css``;
Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,70 @@
11
import React from 'react';
2+
3+
import FormFooter from '@leafygreen-ui/form-footer';
4+
25
import { WizardFooterProps } from './WizardFooter.types';
36

4-
export function WizardFooter({}: WizardFooterProps) {
5-
return <div>your content here</div>;
7+
export function WizardFooter({
8+
backButtonProps,
9+
cancelButtonProps,
10+
primaryButtonProps,
11+
activeStep = 0,
12+
totalSteps = 1,
13+
onStepChange,
14+
isControlled: _isControlled,
15+
}: WizardFooterProps) {
16+
// Handle back button click
17+
const handleBackClick = () => {
18+
if (activeStep > 0) {
19+
onStepChange?.(activeStep - 1);
20+
}
21+
};
22+
23+
// Handle primary button click (forward navigation)
24+
const handlePrimaryClick = () => {
25+
if (activeStep < totalSteps - 1) {
26+
onStepChange?.(activeStep + 1);
27+
}
28+
};
29+
30+
// Merge navigation handlers with user-provided props
31+
const mergedBackButtonProps = backButtonProps
32+
? {
33+
...backButtonProps,
34+
onClick: (event: React.MouseEvent<HTMLButtonElement>) => {
35+
backButtonProps.onClick?.(event);
36+
if (!event.defaultPrevented) {
37+
handleBackClick();
38+
}
39+
},
40+
}
41+
: undefined;
42+
43+
const mergedPrimaryButtonProps = primaryButtonProps
44+
? {
45+
...primaryButtonProps,
46+
onClick: (event: React.MouseEvent<HTMLButtonElement>) => {
47+
primaryButtonProps.onClick?.(event);
48+
if (!event.defaultPrevented) {
49+
handlePrimaryClick();
50+
}
51+
},
52+
}
53+
: undefined;
54+
55+
// Hide back button if we're on the first step
56+
const finalBackButtonProps =
57+
activeStep === 0 ? undefined : mergedBackButtonProps;
58+
59+
return (
60+
<FormFooter
61+
backButtonProps={finalBackButtonProps}
62+
cancelButtonProps={cancelButtonProps}
63+
primaryButtonProps={
64+
mergedPrimaryButtonProps || { children: 'Next', variant: 'primary' }
65+
}
66+
/>
67+
);
668
}
769

870
WizardFooter.displayName = 'WizardFooter';
Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,28 @@
1-
export interface WizardFooterProps {}
1+
import { FormFooterProps } from '@leafygreen-ui/form-footer';
2+
3+
export interface WizardFooterProps {
4+
/**
5+
* Props for the back button (left-most button)
6+
*/
7+
backButtonProps?: FormFooterProps['backButtonProps'];
8+
9+
/**
10+
* Props for the cancel button (center button)
11+
*/
12+
cancelButtonProps?: FormFooterProps['cancelButtonProps'];
13+
14+
/**
15+
* Props for the primary button (right-most button)
16+
*/
17+
primaryButtonProps?: FormFooterProps['primaryButtonProps'];
18+
19+
// Internal props passed by the Wizard component
20+
/** @internal */
21+
activeStep?: number;
22+
/** @internal */
23+
totalSteps?: number;
24+
/** @internal */
25+
onStepChange?: (step: number) => void;
26+
/** @internal */
27+
isControlled?: boolean;
28+
}
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
2-
export { WizardFooter } from './WizardFooter';
1+
export { WizardFooter } from './WizardFooter';
32
export { type WizardFooterProps } from './WizardFooter.types';
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
21
import React from 'react';
32
import { render } from '@testing-library/react';
43

54
import { WizardStep } from '.';
65

76
describe('packages/wizard-step', () => {
8-
test('condition', () => {
9-
10-
})
11-
})
7+
test('condition', () => {});
8+
});

0 commit comments

Comments
 (0)