@indico-data/design-system 2.58.2 → 2.59.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.
Files changed (50) hide show
  1. package/lib/components/index.d.ts +1 -0
  2. package/lib/components/stepper/Stepper.d.ts +2 -0
  3. package/lib/components/stepper/Stepper.stories.d.ts +9 -0
  4. package/lib/components/stepper/__tests__/Stepper.tests.d.ts +1 -0
  5. package/lib/components/stepper/components/BackNavigation.d.ts +6 -0
  6. package/lib/components/stepper/components/Legend.d.ts +2 -0
  7. package/lib/components/stepper/components/NextNavigation.d.ts +8 -0
  8. package/lib/components/stepper/examples/MixedExample.d.ts +1 -0
  9. package/lib/components/stepper/examples/OptionalStepsExample.d.ts +1 -0
  10. package/lib/components/stepper/examples/RequiredStepsExample.d.ts +1 -0
  11. package/lib/components/stepper/examples/commonExample/CommonExample.d.ts +1 -0
  12. package/lib/components/stepper/examples/commonExample/steps/StepOne.d.ts +3 -0
  13. package/lib/components/stepper/examples/commonExample/steps/StepThree.d.ts +3 -0
  14. package/lib/components/stepper/examples/commonExample/steps/StepTwo.d.ts +3 -0
  15. package/lib/components/stepper/examples/constants.d.ts +61 -0
  16. package/lib/components/stepper/index.d.ts +1 -0
  17. package/lib/components/stepper/types.d.ts +24 -0
  18. package/lib/index.css +100 -2
  19. package/lib/index.d.ts +23 -2
  20. package/lib/index.esm.css +100 -2
  21. package/lib/index.esm.js +95 -29
  22. package/lib/index.esm.js.map +1 -1
  23. package/lib/index.js +94 -27
  24. package/lib/index.js.map +1 -1
  25. package/package.json +1 -1
  26. package/src/components/index.ts +1 -0
  27. package/src/components/stepper/Stepper.mdx +140 -0
  28. package/src/components/stepper/Stepper.stories.tsx +196 -0
  29. package/src/components/stepper/Stepper.tsx +85 -0
  30. package/src/components/stepper/__tests__/Stepper.tests.tsx +213 -0
  31. package/src/components/stepper/components/BackNavigation.tsx +22 -0
  32. package/src/components/stepper/components/Legend.tsx +66 -0
  33. package/src/components/stepper/components/NextNavigation.tsx +38 -0
  34. package/src/components/stepper/examples/MixedExample.tsx +140 -0
  35. package/src/components/stepper/examples/OptionalStepsExample.tsx +139 -0
  36. package/src/components/stepper/examples/RequiredStepsExample.tsx +158 -0
  37. package/src/components/stepper/examples/commonExample/CommonExample.tsx +115 -0
  38. package/src/components/stepper/examples/commonExample/steps/StepOne.tsx +57 -0
  39. package/src/components/stepper/examples/commonExample/steps/StepThree.tsx +56 -0
  40. package/src/components/stepper/examples/commonExample/steps/StepTwo.tsx +52 -0
  41. package/src/components/stepper/examples/constants.ts +168 -0
  42. package/src/components/stepper/index.ts +1 -0
  43. package/src/components/stepper/styles/Stepper.scss +131 -0
  44. package/src/components/stepper/types.ts +27 -0
  45. package/src/components/tanstackTable/components/TableBody/TableBody.tsx +2 -1
  46. package/src/components/tanstackTable/styles/table.scss +2 -2
  47. package/src/components/toast/Toast.mdx +1 -1
  48. package/src/components/toast/Toast.stories.tsx +1 -1
  49. package/src/index.ts +4 -2
  50. package/src/styles/index.scss +1 -0
@@ -0,0 +1,66 @@
1
+ import classNames from 'classnames';
2
+ import { Icon } from '../../icons/Icon';
3
+ import { Col, Row } from '../../grid/';
4
+ import { Button } from '../../button';
5
+ import { StepperLegendProps } from '../types';
6
+
7
+ export const Legend = ({ currentStep, steps, onStepClick }: StepperLegendProps) => {
8
+ const totalSteps = steps?.length || 0;
9
+ return (
10
+ <div className="stepper-legend">
11
+ {steps?.map((step, index) => {
12
+ const isCompleted = steps[index].isCompleted;
13
+ const isCurrent = index === currentStep;
14
+ const isSidebarEnabled = step.isSidebarEnabled;
15
+
16
+ return (
17
+ <div key={index}>
18
+ <Row nogutter align="center">
19
+ <Col xs="content">
20
+ <div
21
+ className={classNames('stepper-legend-circle', {
22
+ completed: isCompleted,
23
+ current: isCurrent,
24
+ })}
25
+ >
26
+ {isCompleted ? <Icon name="check" /> : index + 1}
27
+ </div>
28
+ </Col>
29
+ <Col>
30
+ <div
31
+ className={classNames('stepper-legend-step', {
32
+ 'stepper-legend-step--current-step': isCurrent,
33
+ 'stepper-legend-step--completed-step': isCompleted,
34
+ 'stepper-legend-step--disabled-step': !isSidebarEnabled,
35
+ })}
36
+ >
37
+ <Button
38
+ data-testid={`stepper-legend-step-${index}`}
39
+ onClick={() => onStepClick(index)}
40
+ isDisabled={!isSidebarEnabled}
41
+ ariaLabel={step.label}
42
+ size="sm"
43
+ variant="link"
44
+ >
45
+ {step.label}
46
+ </Button>
47
+ </div>
48
+ </Col>
49
+ </Row>
50
+ {index !== totalSteps - 1 && (
51
+ <Row>
52
+ <Col>
53
+ <div
54
+ className={classNames('stepper-legend-line', {
55
+ 'stepper-legend-line--completed': isCompleted,
56
+ })}
57
+ ></div>
58
+ </Col>
59
+ </Row>
60
+ )}
61
+ </div>
62
+ );
63
+ })}
64
+ </div>
65
+ );
66
+ };
@@ -0,0 +1,38 @@
1
+ import { Button } from '../../button';
2
+ type Props = {
3
+ isLastStep: boolean;
4
+ onNextClick: () => void;
5
+ onFinishClick: () => void;
6
+ isDisabled: boolean;
7
+ };
8
+
9
+ export const NextNavigation = ({ isLastStep, onNextClick, onFinishClick, isDisabled }: Props) => {
10
+ return (
11
+ <div className="stepper-navigation">
12
+ {!isLastStep ? (
13
+ <div className="stepper-navigation-next">
14
+ <Button
15
+ data-testid="stepper-next-button"
16
+ iconRight="fa-arrow-right"
17
+ ariaLabel="Next Step"
18
+ onClick={onNextClick}
19
+ isDisabled={isDisabled}
20
+ >
21
+ Next Step
22
+ </Button>
23
+ </div>
24
+ ) : (
25
+ <div className="stepper-navigation-finish">
26
+ <Button
27
+ data-testid="stepper-finish-button"
28
+ ariaLabel="Finish"
29
+ onClick={onFinishClick}
30
+ isDisabled={isDisabled}
31
+ >
32
+ Finish
33
+ </Button>
34
+ </div>
35
+ )}
36
+ </div>
37
+ );
38
+ };
@@ -0,0 +1,140 @@
1
+ import React, { useState } from 'react';
2
+ import { Stepper } from '../Stepper';
3
+ import { Button } from '../../button';
4
+ import { MIXED_EXAMPLE_STEPS, STEP_CONTENT_DATA, INFO_BOX_STYLE } from './constants';
5
+
6
+ export const MixedExample = () => {
7
+ // Value of the current step.
8
+ const [currentStep, setCurrentStep] = useState(0);
9
+
10
+ // Array of all steps using the MIXED_EXAMPLE_STEPS constant
11
+ const [steps, setSteps] = useState(
12
+ MIXED_EXAMPLE_STEPS.map((step, index) => ({
13
+ ...step,
14
+ label: `Step ${index + 1}: ${
15
+ index === 0
16
+ ? 'Start'
17
+ : index === MIXED_EXAMPLE_STEPS.length - 1
18
+ ? 'Complete'
19
+ : index === 1
20
+ ? 'Details'
21
+ : index === 2
22
+ ? 'Review'
23
+ : 'Confirm'
24
+ }`,
25
+ // Only override isNextDisabled for non-optional steps that aren't completed yet
26
+ isNextDisabled: !step.isOptional && !step.isCompleted,
27
+ })),
28
+ );
29
+
30
+ //=========Navigation Functions=========
31
+
32
+ // This function handles what happens when the user clicks the back button.
33
+ const handleBackClick = () => {
34
+ setCurrentStep(currentStep - 1);
35
+ };
36
+
37
+ // This function handles what happens when the user clicks the next button. This is important because it allows you to navigate the side legend.
38
+ const handleNextClick = () => {
39
+ const currentStepData = steps[currentStep];
40
+ // if step is optional, then enable next step
41
+ if (currentStepData?.isOptional) {
42
+ setSteps(
43
+ steps.map((step, index) =>
44
+ index === currentStep + 1 ? { ...step, isNextDisabled: false } : step,
45
+ ),
46
+ );
47
+ setCurrentStep(currentStep + 1);
48
+ // If the current step is completed and not optional, then enable the next step
49
+ } else if (currentStepData && currentStepData.isCompleted) {
50
+ setSteps(
51
+ steps.map((step, index) =>
52
+ index === currentStep + 1 ? { ...step, isNextDisabled: false } : step,
53
+ ),
54
+ );
55
+ setCurrentStep(currentStep + 1);
56
+ }
57
+ };
58
+
59
+ // This function allows the legend to navigate to a specific step
60
+ const handleStepClick = (step: number) => {
61
+ setCurrentStep(step);
62
+ };
63
+
64
+ //=========Step Completion Functions=========
65
+
66
+ // This function handles what happens when the user finishes the last step
67
+ const handleFinishClick = () => {
68
+ alert('Finished!');
69
+ };
70
+
71
+ // This function fires when the conditions for the current step are met.
72
+ const handleCompleteStep = (step: number) => {
73
+ setSteps(
74
+ steps.map((currentStep, index) =>
75
+ index === step ? { ...currentStep, isCompleted: true, isNextDisabled: false } : currentStep,
76
+ ),
77
+ );
78
+ };
79
+
80
+ return (
81
+ <>
82
+ <div style={INFO_BOX_STYLE}>
83
+ <h3>Mixed Steps Example (Default)</h3>
84
+ <p>This is the default stepper configuration with mixed step requirements:</p>
85
+ <ul>
86
+ <li>The first step is required and must be completed before proceeding</li>
87
+ <li>Steps 2-5 are optional and can be skipped</li>
88
+ <li>All steps are accessible from the sidebar at any time</li>
89
+ <li>The Next button is enabled for optional steps or completed required steps</li>
90
+ </ul>
91
+ <p>This provides a flexible experience while ensuring critical steps are completed.</p>
92
+ </div>
93
+
94
+ <Stepper
95
+ steps={steps}
96
+ currentStep={currentStep}
97
+ onBackClick={handleBackClick}
98
+ onNextClick={handleNextClick}
99
+ onFinishClick={handleFinishClick}
100
+ onStepClick={handleStepClick}
101
+ >
102
+ <div className="step" id={steps[0].id}>
103
+ <h3>{STEP_CONTENT_DATA.step1.title}</h3>
104
+ <p>{STEP_CONTENT_DATA.step1.content}</p>
105
+ <Button onClick={() => handleCompleteStep(0)} ariaLabel="Complete Step 1">
106
+ Press To Complete Step
107
+ </Button>
108
+ </div>
109
+ <div className="step" id={steps[1].id}>
110
+ <h3>{STEP_CONTENT_DATA.step2.title}</h3>
111
+ <p>{STEP_CONTENT_DATA.step2.content}</p>
112
+ <Button onClick={() => handleCompleteStep(1)} ariaLabel="Complete Step 2">
113
+ Press To Complete Step
114
+ </Button>
115
+ </div>
116
+ <div className="step" id={steps[2].id}>
117
+ <h3>{STEP_CONTENT_DATA.step3.title}</h3>
118
+ <p>{STEP_CONTENT_DATA.step3.content}</p>
119
+ <Button onClick={() => handleCompleteStep(2)} ariaLabel="Complete Step 3">
120
+ Press To Complete Step
121
+ </Button>
122
+ </div>
123
+ <div className="step" id={steps[3].id}>
124
+ <h3>{STEP_CONTENT_DATA.step4.title}</h3>
125
+ <p>{STEP_CONTENT_DATA.step4.content}</p>
126
+ <Button onClick={() => handleCompleteStep(3)} ariaLabel="Complete Step 4">
127
+ Press To Complete Step
128
+ </Button>
129
+ </div>
130
+ <div className="step" id={steps[4].id}>
131
+ <h3>{STEP_CONTENT_DATA.step5.title}</h3>
132
+ <p>{STEP_CONTENT_DATA.step5.content}</p>
133
+ <Button onClick={() => handleCompleteStep(4)} ariaLabel="Complete Step 5">
134
+ Press To Complete Step
135
+ </Button>
136
+ </div>
137
+ </Stepper>
138
+ </>
139
+ );
140
+ };
@@ -0,0 +1,139 @@
1
+ import React, { useState } from 'react';
2
+ import { Stepper } from '../Stepper';
3
+ import { Button } from '../../button';
4
+ import { OPTIONAL_STEPS, INFO_BOX_STYLE, STATUS_INDICATOR_STYLE } from './constants';
5
+
6
+ export const OptionalStepsExample = () => {
7
+ const [currentStep, setCurrentStep] = useState(0);
8
+ const [steps, setSteps] = useState(
9
+ OPTIONAL_STEPS.map((step, index) => ({
10
+ ...step,
11
+ label: `Step ${index + 1}: Optional`,
12
+ // Optional steps keep the default isNextDisabled: false from constants
13
+ })),
14
+ );
15
+
16
+ // Count completed steps for summary
17
+ const completedCount = steps.filter((step) => step.isCompleted).length;
18
+
19
+ // Handles back button click
20
+ const handleBackClick = () => {
21
+ setCurrentStep(Math.max(0, currentStep - 1));
22
+ };
23
+
24
+ // Handles next button click - always proceeds regardless of completion
25
+ const handleNextClick = () => {
26
+ // Move to the next step without checking completion status
27
+ setCurrentStep(Math.min(steps.length - 1, currentStep + 1));
28
+ };
29
+
30
+ // Handle sidebar navigation - always allows any step
31
+ const handleStepClick = (step: number) => {
32
+ setCurrentStep(step);
33
+ };
34
+
35
+ // When the user completes a step
36
+ const handleCompleteStep = (step: number) => {
37
+ setSteps(
38
+ steps.map((currentStep, index) =>
39
+ index === step ? { ...currentStep, isCompleted: true } : currentStep,
40
+ ),
41
+ );
42
+ };
43
+
44
+ // Handle finish button click - no validation needed
45
+ const handleFinishClick = () => {
46
+ // Show summary of what was completed
47
+ alert(`Process finished! You completed ${completedCount} out of ${steps.length} steps.`);
48
+ };
49
+
50
+ // Status indicator to show optional status
51
+ const StepStatus = ({ isCompleted }: { isCompleted: boolean }) => (
52
+ <div className="step-status">
53
+ <div style={STATUS_INDICATOR_STYLE(isCompleted ? 'green' : 'orange')} />
54
+ {isCompleted ? 'Completed' : 'Optional - Not Completed'}
55
+ </div>
56
+ );
57
+
58
+ return (
59
+ <>
60
+ <div style={INFO_BOX_STYLE}>
61
+ <h3>Optional Steps Example</h3>
62
+ <p>In this example, all steps are optional. You can:</p>
63
+ <ul>
64
+ <li>Navigate freely between steps using the sidebar</li>
65
+ <li>Skip any step by clicking Next without completing it</li>
66
+ <li>Finish the process at any time regardless of completion status</li>
67
+ </ul>
68
+ <p>
69
+ <strong>Completed steps:</strong> {completedCount} of {steps.length}
70
+ </p>
71
+ </div>
72
+
73
+ <Stepper
74
+ steps={steps}
75
+ currentStep={currentStep}
76
+ onBackClick={handleBackClick}
77
+ onNextClick={handleNextClick}
78
+ onFinishClick={handleFinishClick}
79
+ onStepClick={handleStepClick}
80
+ >
81
+ <div className="step" id={steps[0].id}>
82
+ <h3>Step 1: Profile Preferences (Optional)</h3>
83
+ <p>Set your profile preferences if you want. You can always skip this step.</p>
84
+ <StepStatus isCompleted={steps[0].isCompleted} />
85
+ <div style={{ marginTop: '20px' }}>
86
+ <Button onClick={() => handleCompleteStep(0)} ariaLabel="Complete Step 1">
87
+ Complete Optional Step
88
+ </Button>
89
+ <div style={{ marginTop: '10px' }}>
90
+ <em>Or click Next to skip this step</em>
91
+ </div>
92
+ </div>
93
+ </div>
94
+
95
+ <div className="step" id={steps[1].id}>
96
+ <h3>Step 2: Additional Information (Optional)</h3>
97
+ <p>Provide additional information if you want. This step is completely optional.</p>
98
+ <StepStatus isCompleted={steps[1].isCompleted} />
99
+ <div style={{ marginTop: '20px' }}>
100
+ <Button onClick={() => handleCompleteStep(1)} ariaLabel="Complete Step 2">
101
+ Complete Optional Step
102
+ </Button>
103
+ <div style={{ marginTop: '10px' }}>
104
+ <em>Or click Next to skip this step</em>
105
+ </div>
106
+ </div>
107
+ </div>
108
+
109
+ <div className="step" id={steps[2].id}>
110
+ <h3>Step 3: Notification Preferences (Optional)</h3>
111
+ <p>Configure your notification preferences. You can always set these later.</p>
112
+ <StepStatus isCompleted={steps[2].isCompleted} />
113
+ <div style={{ marginTop: '20px' }}>
114
+ <Button onClick={() => handleCompleteStep(2)} ariaLabel="Complete Step 3">
115
+ Complete Optional Step
116
+ </Button>
117
+ <div style={{ marginTop: '10px' }}>
118
+ <em>Or click Next to skip this step</em>
119
+ </div>
120
+ </div>
121
+ </div>
122
+
123
+ <div className="step" id={steps[3].id}>
124
+ <h3>Step 4: Feedback (Optional)</h3>
125
+ <p>Share your feedback with us. This information is optional but helps us improve.</p>
126
+ <StepStatus isCompleted={steps[3].isCompleted} />
127
+ <div style={{ marginTop: '20px' }}>
128
+ <Button onClick={() => handleCompleteStep(3)} ariaLabel="Complete Step 4">
129
+ Complete Optional Step
130
+ </Button>
131
+ <div style={{ marginTop: '10px' }}>
132
+ <em>Or click Finish to complete without feedback</em>
133
+ </div>
134
+ </div>
135
+ </div>
136
+ </Stepper>
137
+ </>
138
+ );
139
+ };
@@ -0,0 +1,158 @@
1
+ import React, { useState } from 'react';
2
+ import { Stepper } from '../Stepper';
3
+ import { Button } from '../../button';
4
+ import { REQUIRED_STEPS, INFO_BOX_STYLE, STATUS_INDICATOR_STYLE } from './constants';
5
+
6
+ export const RequiredStepsExample = () => {
7
+ const [currentStep, setCurrentStep] = useState(0);
8
+ const [steps, setSteps] = useState(
9
+ REQUIRED_STEPS.map((step, index) => ({
10
+ ...step,
11
+ label: `Step ${index + 1}: Required`,
12
+ // For required steps, override to true initially until completed
13
+ isNextDisabled: true,
14
+ })),
15
+ );
16
+
17
+ // Handles back button click
18
+ const handleBackClick = () => {
19
+ setCurrentStep(currentStep - 1);
20
+ };
21
+
22
+ // Handles next button click - only proceeds if current step is completed
23
+ const handleNextClick = () => {
24
+ const currentStepData = steps[currentStep];
25
+
26
+ // Can only proceed if the current step is completed
27
+ if (currentStepData && currentStepData.isCompleted) {
28
+ // Enable the next step in the sidebar
29
+ setSteps(
30
+ steps.map((step, index) =>
31
+ index === currentStep + 1
32
+ ? { ...step, isSidebarEnabled: true, isNextDisabled: false }
33
+ : step,
34
+ ),
35
+ );
36
+ // Move to the next step
37
+ setCurrentStep(currentStep + 1);
38
+ }
39
+ };
40
+
41
+ // Handle sidebar navigation
42
+ const handleStepClick = (step: number) => {
43
+ // Only allow clicking on enabled steps in the sidebar
44
+ if (steps[step].isSidebarEnabled) {
45
+ setCurrentStep(step);
46
+ } else {
47
+ alert('You must complete the previous steps first.');
48
+ }
49
+ };
50
+
51
+ // When the user completes a step
52
+ const handleCompleteStep = (step: number) => {
53
+ setSteps(
54
+ steps.map((currentStep, index) =>
55
+ index === step ? { ...currentStep, isCompleted: true, isNextDisabled: false } : currentStep,
56
+ ),
57
+ );
58
+ };
59
+
60
+ // Handle finish button click
61
+ const handleFinishClick = () => {
62
+ // Check if all steps are completed
63
+ const allCompleted = steps.every((step) => step.isCompleted);
64
+
65
+ if (allCompleted) {
66
+ alert('Successfully completed all required steps!');
67
+ } else {
68
+ alert('You must complete all steps before finishing.');
69
+ }
70
+ };
71
+
72
+ // Status indicator to show what's required for each step
73
+ const StepStatus = ({ isCompleted }: { isCompleted: boolean }) => (
74
+ <div className="step-status">
75
+ <div style={STATUS_INDICATOR_STYLE(isCompleted ? 'green' : 'red')} />
76
+ {isCompleted ? 'Completed' : 'Required - Not Completed'}
77
+ </div>
78
+ );
79
+
80
+ return (
81
+ <>
82
+ <div style={INFO_BOX_STYLE}>
83
+ <h3>Required Steps Example</h3>
84
+ <p>In this example, all steps are required with strict validation:</p>
85
+ <ul>
86
+ <li>Every step must be completed before proceeding to the next</li>
87
+ <li>Only completed steps and the current step are accessible in the sidebar</li>
88
+ <li>The Next button is disabled until the current step is completed</li>
89
+ <li>All steps must be completed before the process can be finished</li>
90
+ </ul>
91
+ <p>This enforces a structured workflow where all information must be provided.</p>
92
+ </div>
93
+
94
+ <Stepper
95
+ steps={steps}
96
+ currentStep={currentStep}
97
+ onBackClick={handleBackClick}
98
+ onNextClick={handleNextClick}
99
+ onFinishClick={handleFinishClick}
100
+ onStepClick={handleStepClick}
101
+ >
102
+ <div className="step" id={steps[0].id}>
103
+ <h3>Step 1: Personal Information</h3>
104
+ <p>All fields in this form are required before you can proceed.</p>
105
+ <StepStatus isCompleted={steps[0].isCompleted} />
106
+ <div style={{ marginTop: '20px' }}>
107
+ <Button onClick={() => handleCompleteStep(0)} ariaLabel="Complete Step 1">
108
+ Complete Required Step
109
+ </Button>
110
+ </div>
111
+ </div>
112
+
113
+ <div className="step" id={steps[1].id}>
114
+ <h3>Step 2: Contact Details</h3>
115
+ <p>All contact information must be provided to continue.</p>
116
+ <StepStatus isCompleted={steps[1].isCompleted} />
117
+ <div style={{ marginTop: '20px' }}>
118
+ <Button onClick={() => handleCompleteStep(1)} ariaLabel="Complete Step 2">
119
+ Complete Required Step
120
+ </Button>
121
+ </div>
122
+ </div>
123
+
124
+ <div className="step" id={steps[2].id}>
125
+ <h3>Step 3: Security Questions</h3>
126
+ <p>You must set up security questions to protect your account.</p>
127
+ <StepStatus isCompleted={steps[2].isCompleted} />
128
+ <div style={{ marginTop: '20px' }}>
129
+ <Button onClick={() => handleCompleteStep(2)} ariaLabel="Complete Step 3">
130
+ Complete Required Step
131
+ </Button>
132
+ </div>
133
+ </div>
134
+
135
+ <div className="step" id={steps[3].id}>
136
+ <h3>Step 4: Terms & Conditions</h3>
137
+ <p>You must agree to the terms and conditions to complete registration.</p>
138
+ <StepStatus isCompleted={steps[3].isCompleted} />
139
+ <div style={{ marginTop: '20px' }}>
140
+ <Button onClick={() => handleCompleteStep(3)} ariaLabel="Complete Step 4">
141
+ Complete Required Step
142
+ </Button>
143
+ </div>
144
+ </div>
145
+ <div className="step" id={steps[4].id}>
146
+ <h3>Step 4: Terms & Conditions</h3>
147
+ <p>You must agree to the terms and conditions to complete registration.</p>
148
+ <StepStatus isCompleted={steps[4].isCompleted} />
149
+ <div style={{ marginTop: '20px' }}>
150
+ <Button onClick={() => handleCompleteStep(4)} ariaLabel="Complete Step 4">
151
+ Complete Required Step
152
+ </Button>
153
+ </div>
154
+ </div>
155
+ </Stepper>
156
+ </>
157
+ );
158
+ };
@@ -0,0 +1,115 @@
1
+ import React, { useState } from 'react';
2
+ import { Stepper } from '../../Stepper';
3
+ import { StepOne } from './steps/StepOne';
4
+ import { StepTwo } from './steps/StepTwo';
5
+ import { StepThree } from './steps/StepThree';
6
+
7
+ export const CommonExample = () => {
8
+ const exampleSteps = [
9
+ {
10
+ id: 'step1',
11
+ label: 'Application Information',
12
+ isCompleted: false,
13
+ isOptional: false,
14
+ isSidebarEnabled: true,
15
+ isNextDisabled: false,
16
+ },
17
+ {
18
+ id: 'step2',
19
+ label: 'Agent Information',
20
+ isCompleted: false,
21
+ isOptional: false,
22
+ isSidebarEnabled: false,
23
+ isNextDisabled: true,
24
+ },
25
+ {
26
+ id: 'step3',
27
+ label: 'User Information',
28
+ isCompleted: false,
29
+ isOptional: false,
30
+ isSidebarEnabled: false,
31
+ isNextDisabled: true,
32
+ },
33
+ ];
34
+
35
+ const [currentStep, setCurrentStep] = useState(0);
36
+ const [steps, setSteps] = useState(exampleSteps);
37
+
38
+ const handleBackClick = () => {
39
+ setCurrentStep(currentStep - 1);
40
+ };
41
+
42
+ // Handles next button click - only proceeds if current step is completed
43
+ const handleNextClick = () => {
44
+ const currentStepData = steps[currentStep];
45
+ if (currentStepData && currentStepData.isCompleted) {
46
+ setSteps(
47
+ steps.map((step, index) =>
48
+ index === currentStep + 1
49
+ ? { ...step, isSidebarEnabled: true, isNextDisabled: false }
50
+ : step,
51
+ ),
52
+ );
53
+ setCurrentStep(currentStep + 1);
54
+ }
55
+ };
56
+
57
+ const handleSidebarNavigationItemClick = (step: number) => {
58
+ // Only allow clicking on enabled steps in the sidebar
59
+ if (steps[step].isSidebarEnabled) {
60
+ setCurrentStep(step);
61
+ }
62
+ };
63
+
64
+ const handleOnStepCompletion = (step: number) => {
65
+ setSteps(
66
+ steps.map((currentStep, index) => {
67
+ if (index === step) {
68
+ // Mark current step as completed
69
+ return { ...currentStep, isCompleted: true, isNextDisabled: false };
70
+ } else if (index === step + 1) {
71
+ // Enable the next step in the sidebar
72
+ return { ...currentStep, isSidebarEnabled: true };
73
+ } else {
74
+ return currentStep;
75
+ }
76
+ }),
77
+ );
78
+ };
79
+
80
+ const handleCompleteStepperClick = () => {
81
+ // if all steps are completed, then show a success message
82
+ if (steps.every((step) => step.isCompleted)) {
83
+ alert('Successfully completed all required steps!');
84
+ } else {
85
+ alert('You must complete all steps before finishing.');
86
+ }
87
+ };
88
+
89
+ return (
90
+ <Stepper
91
+ steps={steps}
92
+ currentStep={currentStep}
93
+ legendHeader={
94
+ <div>
95
+ <h1>Publish Agent To Gallery</h1>
96
+ <p className="subtitle-2 color-tertiary-200 mt-2 mb-6">
97
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
98
+ incididunt ut labore et dolore.
99
+ </p>
100
+ </div>
101
+ }
102
+ legendFooter={
103
+ <p className="subtitle-2 color-tertiary-200 mt-6">Example of a legend footer</p>
104
+ }
105
+ onBackClick={handleBackClick}
106
+ onNextClick={handleNextClick}
107
+ onFinishClick={handleCompleteStepperClick}
108
+ onStepClick={handleSidebarNavigationItemClick}
109
+ >
110
+ <StepOne onCompletion={() => handleOnStepCompletion(0)} />
111
+ <StepTwo onCompletion={() => handleOnStepCompletion(1)} />
112
+ <StepThree onCompletion={() => handleOnStepCompletion(2)} />
113
+ </Stepper>
114
+ );
115
+ };