@patternfly/react-core 4.248.0 → 4.250.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 (228) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/esm/components/Icon/Icon.d.ts +25 -0
  3. package/dist/esm/components/Icon/Icon.d.ts.map +1 -0
  4. package/dist/esm/components/Icon/Icon.js +14 -0
  5. package/dist/esm/components/Icon/Icon.js.map +1 -0
  6. package/dist/esm/components/Icon/index.d.ts +2 -0
  7. package/dist/esm/components/Icon/index.d.ts.map +1 -0
  8. package/dist/esm/components/Icon/index.js +2 -0
  9. package/dist/esm/components/Icon/index.js.map +1 -0
  10. package/dist/esm/components/index.d.ts +1 -0
  11. package/dist/esm/components/index.d.ts.map +1 -1
  12. package/dist/esm/components/index.js +1 -0
  13. package/dist/esm/components/index.js.map +1 -1
  14. package/dist/esm/next/components/Select/Select.d.ts +28 -0
  15. package/dist/esm/next/components/Select/Select.d.ts.map +1 -0
  16. package/dist/esm/next/components/Select/Select.js +62 -0
  17. package/dist/esm/next/components/Select/Select.js.map +1 -0
  18. package/dist/esm/next/components/Select/SelectGroup.d.ts +12 -0
  19. package/dist/esm/next/components/Select/SelectGroup.d.ts.map +1 -0
  20. package/dist/esm/next/components/Select/SelectGroup.js +10 -0
  21. package/dist/esm/next/components/Select/SelectGroup.js.map +1 -0
  22. package/dist/esm/next/components/Select/SelectList.d.ts +10 -0
  23. package/dist/esm/next/components/Select/SelectList.d.ts.map +1 -0
  24. package/dist/esm/next/components/Select/SelectList.js +10 -0
  25. package/dist/esm/next/components/Select/SelectList.js.map +1 -0
  26. package/dist/esm/next/components/Select/SelectOption.d.ts +20 -0
  27. package/dist/esm/next/components/Select/SelectOption.d.ts.map +1 -0
  28. package/dist/esm/next/components/Select/SelectOption.js +10 -0
  29. package/dist/esm/next/components/Select/SelectOption.js.map +1 -0
  30. package/dist/esm/next/components/Select/index.d.ts +5 -0
  31. package/dist/esm/next/components/Select/index.d.ts.map +1 -0
  32. package/dist/esm/next/components/Select/index.js +5 -0
  33. package/dist/esm/next/components/Select/index.js.map +1 -0
  34. package/dist/esm/next/components/Wizard/Wizard.d.ts +9 -7
  35. package/dist/esm/next/components/Wizard/Wizard.d.ts.map +1 -1
  36. package/dist/esm/next/components/Wizard/Wizard.js +62 -48
  37. package/dist/esm/next/components/Wizard/Wizard.js.map +1 -1
  38. package/dist/esm/next/components/Wizard/WizardBody.d.ts +2 -2
  39. package/dist/esm/next/components/Wizard/WizardBody.d.ts.map +1 -1
  40. package/dist/esm/next/components/Wizard/WizardBody.js +1 -1
  41. package/dist/esm/next/components/Wizard/WizardBody.js.map +1 -1
  42. package/dist/esm/next/components/Wizard/WizardContext.d.ts +21 -20
  43. package/dist/esm/next/components/Wizard/WizardContext.d.ts.map +1 -1
  44. package/dist/esm/next/components/Wizard/WizardContext.js +63 -32
  45. package/dist/esm/next/components/Wizard/WizardContext.js.map +1 -1
  46. package/dist/esm/next/components/Wizard/WizardFooter.d.ts +20 -6
  47. package/dist/esm/next/components/Wizard/WizardFooter.d.ts.map +1 -1
  48. package/dist/esm/next/components/Wizard/WizardFooter.js +13 -4
  49. package/dist/esm/next/components/Wizard/WizardFooter.js.map +1 -1
  50. package/dist/esm/next/components/Wizard/WizardHeader.d.ts +1 -1
  51. package/dist/esm/next/components/Wizard/WizardHeader.d.ts.map +1 -1
  52. package/dist/esm/next/components/Wizard/WizardHeader.js +2 -2
  53. package/dist/esm/next/components/Wizard/WizardHeader.js.map +1 -1
  54. package/dist/esm/next/components/Wizard/WizardNav.d.ts +5 -5
  55. package/dist/esm/next/components/Wizard/WizardNav.d.ts.map +1 -1
  56. package/dist/esm/next/components/Wizard/WizardNav.js +3 -4
  57. package/dist/esm/next/components/Wizard/WizardNav.js.map +1 -1
  58. package/dist/esm/next/components/Wizard/WizardNavInternal.d.ts +14 -0
  59. package/dist/esm/next/components/Wizard/WizardNavInternal.d.ts.map +1 -0
  60. package/dist/esm/next/components/Wizard/WizardNavInternal.js +49 -0
  61. package/dist/esm/next/components/Wizard/WizardNavInternal.js.map +1 -0
  62. package/dist/esm/next/components/Wizard/WizardNavItem.d.ts +12 -8
  63. package/dist/esm/next/components/Wizard/WizardNavItem.d.ts.map +1 -1
  64. package/dist/esm/next/components/Wizard/WizardNavItem.js +23 -12
  65. package/dist/esm/next/components/Wizard/WizardNavItem.js.map +1 -1
  66. package/dist/esm/next/components/Wizard/WizardStep.d.ts +22 -6
  67. package/dist/esm/next/components/Wizard/WizardStep.d.ts.map +1 -1
  68. package/dist/esm/next/components/Wizard/WizardStep.js +20 -1
  69. package/dist/esm/next/components/Wizard/WizardStep.js.map +1 -1
  70. package/dist/esm/next/components/Wizard/WizardToggle.d.ts +9 -15
  71. package/dist/esm/next/components/Wizard/WizardToggle.d.ts.map +1 -1
  72. package/dist/esm/next/components/Wizard/WizardToggle.js +15 -50
  73. package/dist/esm/next/components/Wizard/WizardToggle.js.map +1 -1
  74. package/dist/esm/next/components/Wizard/hooks/useWizardFooter.d.ts +2 -2
  75. package/dist/esm/next/components/Wizard/hooks/useWizardFooter.d.ts.map +1 -1
  76. package/dist/esm/next/components/Wizard/hooks/useWizardFooter.js +3 -3
  77. package/dist/esm/next/components/Wizard/hooks/useWizardFooter.js.map +1 -1
  78. package/dist/esm/next/components/Wizard/types.d.ts +37 -46
  79. package/dist/esm/next/components/Wizard/types.d.ts.map +1 -1
  80. package/dist/esm/next/components/Wizard/types.js +10 -2
  81. package/dist/esm/next/components/Wizard/types.js.map +1 -1
  82. package/dist/esm/next/components/Wizard/utils.d.ts +4 -5
  83. package/dist/esm/next/components/Wizard/utils.d.ts.map +1 -1
  84. package/dist/esm/next/components/Wizard/utils.js +20 -13
  85. package/dist/esm/next/components/Wizard/utils.js.map +1 -1
  86. package/dist/esm/next/components/index.d.ts +2 -1
  87. package/dist/esm/next/components/index.d.ts.map +1 -1
  88. package/dist/esm/next/components/index.js +2 -1
  89. package/dist/esm/next/components/index.js.map +1 -1
  90. package/dist/js/components/Icon/Icon.d.ts +25 -0
  91. package/dist/js/components/Icon/Icon.d.ts.map +1 -0
  92. package/dist/js/components/Icon/Icon.js +18 -0
  93. package/dist/js/components/Icon/Icon.js.map +1 -0
  94. package/dist/js/components/Icon/index.d.ts +2 -0
  95. package/dist/js/components/Icon/index.d.ts.map +1 -0
  96. package/dist/js/components/Icon/index.js +5 -0
  97. package/dist/js/components/Icon/index.js.map +1 -0
  98. package/dist/js/components/index.d.ts +1 -0
  99. package/dist/js/components/index.d.ts.map +1 -1
  100. package/dist/js/components/index.js +1 -0
  101. package/dist/js/components/index.js.map +1 -1
  102. package/dist/js/next/components/Select/Select.d.ts +28 -0
  103. package/dist/js/next/components/Select/Select.d.ts.map +1 -0
  104. package/dist/js/next/components/Select/Select.js +65 -0
  105. package/dist/js/next/components/Select/Select.js.map +1 -0
  106. package/dist/js/next/components/Select/SelectGroup.d.ts +12 -0
  107. package/dist/js/next/components/Select/SelectGroup.d.ts.map +1 -0
  108. package/dist/js/next/components/Select/SelectGroup.js +14 -0
  109. package/dist/js/next/components/Select/SelectGroup.js.map +1 -0
  110. package/dist/js/next/components/Select/SelectList.d.ts +10 -0
  111. package/dist/js/next/components/Select/SelectList.d.ts.map +1 -0
  112. package/dist/js/next/components/Select/SelectList.js +14 -0
  113. package/dist/js/next/components/Select/SelectList.js.map +1 -0
  114. package/dist/js/next/components/Select/SelectOption.d.ts +20 -0
  115. package/dist/js/next/components/Select/SelectOption.d.ts.map +1 -0
  116. package/dist/js/next/components/Select/SelectOption.js +14 -0
  117. package/dist/js/next/components/Select/SelectOption.js.map +1 -0
  118. package/dist/js/next/components/Select/index.d.ts +5 -0
  119. package/dist/js/next/components/Select/index.d.ts.map +1 -0
  120. package/dist/js/next/components/Select/index.js +8 -0
  121. package/dist/js/next/components/Select/index.js.map +1 -0
  122. package/dist/js/next/components/Wizard/Wizard.d.ts +9 -7
  123. package/dist/js/next/components/Wizard/Wizard.d.ts.map +1 -1
  124. package/dist/js/next/components/Wizard/Wizard.js +59 -45
  125. package/dist/js/next/components/Wizard/Wizard.js.map +1 -1
  126. package/dist/js/next/components/Wizard/WizardBody.d.ts +2 -2
  127. package/dist/js/next/components/Wizard/WizardBody.d.ts.map +1 -1
  128. package/dist/js/next/components/Wizard/WizardBody.js +1 -1
  129. package/dist/js/next/components/Wizard/WizardBody.js.map +1 -1
  130. package/dist/js/next/components/Wizard/WizardContext.d.ts +21 -20
  131. package/dist/js/next/components/Wizard/WizardContext.d.ts.map +1 -1
  132. package/dist/js/next/components/Wizard/WizardContext.js +61 -30
  133. package/dist/js/next/components/Wizard/WizardContext.js.map +1 -1
  134. package/dist/js/next/components/Wizard/WizardFooter.d.ts +20 -6
  135. package/dist/js/next/components/Wizard/WizardFooter.d.ts.map +1 -1
  136. package/dist/js/next/components/Wizard/WizardFooter.js +15 -6
  137. package/dist/js/next/components/Wizard/WizardFooter.js.map +1 -1
  138. package/dist/js/next/components/Wizard/WizardHeader.d.ts +1 -1
  139. package/dist/js/next/components/Wizard/WizardHeader.d.ts.map +1 -1
  140. package/dist/js/next/components/Wizard/WizardHeader.js +2 -2
  141. package/dist/js/next/components/Wizard/WizardHeader.js.map +1 -1
  142. package/dist/js/next/components/Wizard/WizardNav.d.ts +5 -5
  143. package/dist/js/next/components/Wizard/WizardNav.d.ts.map +1 -1
  144. package/dist/js/next/components/Wizard/WizardNav.js +3 -4
  145. package/dist/js/next/components/Wizard/WizardNav.js.map +1 -1
  146. package/dist/js/next/components/Wizard/WizardNavInternal.d.ts +14 -0
  147. package/dist/js/next/components/Wizard/WizardNavInternal.d.ts.map +1 -0
  148. package/dist/js/next/components/Wizard/WizardNavInternal.js +54 -0
  149. package/dist/js/next/components/Wizard/WizardNavInternal.js.map +1 -0
  150. package/dist/js/next/components/Wizard/WizardNavItem.d.ts +12 -8
  151. package/dist/js/next/components/Wizard/WizardNavItem.d.ts.map +1 -1
  152. package/dist/js/next/components/Wizard/WizardNavItem.js +23 -12
  153. package/dist/js/next/components/Wizard/WizardNavItem.js.map +1 -1
  154. package/dist/js/next/components/Wizard/WizardStep.d.ts +22 -6
  155. package/dist/js/next/components/Wizard/WizardStep.d.ts.map +1 -1
  156. package/dist/js/next/components/Wizard/WizardStep.js +20 -1
  157. package/dist/js/next/components/Wizard/WizardStep.js.map +1 -1
  158. package/dist/js/next/components/Wizard/WizardToggle.d.ts +9 -15
  159. package/dist/js/next/components/Wizard/WizardToggle.d.ts.map +1 -1
  160. package/dist/js/next/components/Wizard/WizardToggle.js +15 -51
  161. package/dist/js/next/components/Wizard/WizardToggle.js.map +1 -1
  162. package/dist/js/next/components/Wizard/hooks/useWizardFooter.d.ts +2 -2
  163. package/dist/js/next/components/Wizard/hooks/useWizardFooter.d.ts.map +1 -1
  164. package/dist/js/next/components/Wizard/hooks/useWizardFooter.js +3 -3
  165. package/dist/js/next/components/Wizard/hooks/useWizardFooter.js.map +1 -1
  166. package/dist/js/next/components/Wizard/types.d.ts +37 -46
  167. package/dist/js/next/components/Wizard/types.d.ts.map +1 -1
  168. package/dist/js/next/components/Wizard/types.js +12 -3
  169. package/dist/js/next/components/Wizard/types.js.map +1 -1
  170. package/dist/js/next/components/Wizard/utils.d.ts +4 -5
  171. package/dist/js/next/components/Wizard/utils.d.ts.map +1 -1
  172. package/dist/js/next/components/Wizard/utils.js +24 -15
  173. package/dist/js/next/components/Wizard/utils.js.map +1 -1
  174. package/dist/js/next/components/index.d.ts +2 -1
  175. package/dist/js/next/components/index.d.ts.map +1 -1
  176. package/dist/js/next/components/index.js +2 -1
  177. package/dist/js/next/components/index.js.map +1 -1
  178. package/dist/umd/react-core.min.css +337 -200
  179. package/dist/umd/react-core.min.js +1 -1
  180. package/package.json +2 -2
  181. package/src/components/Icon/Icon.tsx +66 -0
  182. package/src/components/Icon/__tests__/Icon.test.tsx +196 -0
  183. package/src/components/Icon/__tests__/__snapshots__/Icon.test.tsx.snap +82 -0
  184. package/src/components/Icon/examples/Icon.md +61 -0
  185. package/src/components/Icon/examples/IconBasic.tsx +23 -0
  186. package/src/components/Icon/examples/IconContentSizes.tsx +20 -0
  187. package/src/components/Icon/examples/IconCustomProgress.tsx +24 -0
  188. package/src/components/Icon/examples/IconInline.tsx +62 -0
  189. package/src/components/Icon/examples/IconProgress.tsx +24 -0
  190. package/src/components/Icon/examples/IconSizes.tsx +20 -0
  191. package/src/components/Icon/examples/IconStatus.tsx +27 -0
  192. package/src/components/Icon/index.ts +1 -0
  193. package/src/components/index.ts +1 -0
  194. package/src/next/components/Select/Select.tsx +129 -0
  195. package/src/next/components/Select/SelectGroup.tsx +24 -0
  196. package/src/next/components/Select/SelectList.tsx +21 -0
  197. package/src/next/components/Select/SelectOption.tsx +31 -0
  198. package/src/next/components/Select/examples/Select.md +37 -0
  199. package/src/next/components/Select/examples/SelectBasic.tsx +54 -0
  200. package/src/next/components/Select/examples/SelectCheckbox.tsx +67 -0
  201. package/src/next/components/Select/examples/SelectGrouped.tsx +63 -0
  202. package/src/next/components/Select/examples/SelectMultiTypeahead.tsx +195 -0
  203. package/src/next/components/Select/examples/SelectTypeahead.tsx +191 -0
  204. package/src/next/components/Select/index.ts +4 -0
  205. package/src/next/components/Wizard/Wizard.tsx +107 -64
  206. package/src/next/components/Wizard/WizardBody.tsx +4 -4
  207. package/src/next/components/Wizard/WizardContext.tsx +117 -65
  208. package/src/next/components/Wizard/WizardFooter.tsx +39 -17
  209. package/src/next/components/Wizard/WizardHeader.tsx +6 -3
  210. package/src/next/components/Wizard/WizardNav.tsx +9 -10
  211. package/src/next/components/Wizard/WizardNavInternal.tsx +137 -0
  212. package/src/next/components/Wizard/WizardNavItem.tsx +47 -20
  213. package/src/next/components/Wizard/WizardStep.tsx +52 -7
  214. package/src/next/components/Wizard/WizardToggle.tsx +24 -142
  215. package/src/next/components/Wizard/__tests__/Wizard.test.tsx +10 -13
  216. package/src/next/components/Wizard/__tests__/WizardBody.test.tsx +3 -3
  217. package/src/next/components/Wizard/__tests__/WizardFooter.test.tsx +11 -14
  218. package/src/next/components/Wizard/__tests__/WizardStep.test.tsx +100 -0
  219. package/src/next/components/Wizard/__tests__/WizardToggle.test.tsx +4 -4
  220. package/src/next/components/Wizard/examples/Wizard.md +40 -15
  221. package/src/next/components/Wizard/examples/WizardBasic.tsx +2 -2
  222. package/src/next/components/Wizard/examples/WizardCustomNav.tsx +4 -4
  223. package/src/next/components/Wizard/examples/WizardKitchenSink.tsx +126 -60
  224. package/src/next/components/Wizard/hooks/__tests__/useWizardFooter.test.tsx +23 -34
  225. package/src/next/components/Wizard/hooks/useWizardFooter.tsx +5 -5
  226. package/src/next/components/Wizard/types.tsx +59 -53
  227. package/src/next/components/Wizard/utils.ts +25 -16
  228. package/src/next/components/index.ts +2 -1
@@ -1,6 +1,35 @@
1
1
  import React from 'react';
2
+
2
3
  import { render, screen } from '@testing-library/react';
4
+
3
5
  import { WizardStep } from '../WizardStep';
6
+ import * as useWizardFooter from '../hooks/useWizardFooter';
7
+ import * as WizardContext from '../WizardContext';
8
+ import { WizardStepProps } from '..';
9
+
10
+ const testStep: WizardStepProps = {
11
+ id: 'test-step',
12
+ name: 'Test step',
13
+ footer: <>Step footer</>
14
+ };
15
+ const wizardContext: WizardContext.WizardContextProps = {
16
+ steps: [testStep],
17
+ currentStep: testStep,
18
+ currentStepIndex: 1,
19
+ footer: <>Wizard footer</>,
20
+ onNext: jest.fn(),
21
+ onBack: jest.fn(),
22
+ onClose: jest.fn(),
23
+ goToStepById: jest.fn(),
24
+ goToStepByName: jest.fn(),
25
+ goToStepByIndex: jest.fn(),
26
+ setFooter: jest.fn(),
27
+ getStep: jest.fn(),
28
+ setStep: jest.fn(),
29
+ toggleStep: jest.fn()
30
+ };
31
+ const useWizardContextSpy = jest.spyOn(WizardContext, 'useWizardContext');
32
+ const useWizardFooterSpy = jest.spyOn(useWizardFooter, 'useWizardFooter');
4
33
 
5
34
  test('renders without children', () => {
6
35
  const { container } = render(<WizardStep id="test-step" name="Test step" />);
@@ -31,3 +60,74 @@ test('uses body props for WizardBody when passed', () => {
31
60
 
32
61
  expect(screen.getByLabelText('Some label')).toBeVisible();
33
62
  });
63
+
64
+ test('calls useWizardFooter', () => {
65
+ useWizardContextSpy.mockReturnValueOnce(wizardContext);
66
+
67
+ render(<WizardStep {...testStep}>content</WizardStep>);
68
+ expect(useWizardFooterSpy).toHaveBeenCalledWith(testStep.footer, 'test-step');
69
+ });
70
+
71
+ test('updates "isDisabled" in context when the value changes', () => {
72
+ const setStep = jest.fn();
73
+ useWizardContextSpy.mockReturnValueOnce({ ...wizardContext, setStep });
74
+
75
+ render(<WizardStep {...testStep} isDisabled />);
76
+
77
+ expect(setStep).toHaveBeenCalledWith({ id: testStep.id, isDisabled: true, isVisited: true });
78
+ });
79
+
80
+ test('updates "navItem" in context when the value changes', () => {
81
+ const setStep = jest.fn();
82
+ const testNavItem = <>Some nav item</>;
83
+ useWizardContextSpy.mockReturnValueOnce({ ...wizardContext, setStep });
84
+
85
+ render(<WizardStep {...testStep} navItem={testNavItem} />);
86
+
87
+ expect(setStep).toHaveBeenCalledWith({ id: testStep.id, navItem: testNavItem, isVisited: true });
88
+ });
89
+
90
+ test('updates "status" in context when the value changes', () => {
91
+ const setStep = jest.fn();
92
+ useWizardContextSpy.mockReturnValueOnce({ ...wizardContext, setStep });
93
+
94
+ render(<WizardStep {...testStep} status="error" />);
95
+
96
+ expect(setStep).toHaveBeenCalledWith({ id: testStep.id, status: 'error', isVisited: true });
97
+ });
98
+
99
+ test('calls "toggleStep" when isHidden value changes and the previous value was not undefined', () => {
100
+ const toggleStep = jest.fn();
101
+ useWizardContextSpy.mockReturnValueOnce({ ...wizardContext, toggleStep });
102
+
103
+ render(<WizardStep {...testStep} isHidden />);
104
+
105
+ expect(toggleStep).toHaveBeenCalledWith(testStep.id, true);
106
+ });
107
+
108
+ test('does not call "toggleStep" when isHidden value changes and was previously undefined', () => {
109
+ const toggleStep = jest.fn();
110
+ useWizardContextSpy.mockReturnValueOnce({
111
+ ...wizardContext,
112
+ toggleStep
113
+ });
114
+
115
+ render(<WizardStep {...testStep} isHidden={undefined} />);
116
+
117
+ expect(toggleStep).not.toHaveBeenCalled();
118
+ });
119
+
120
+ test('does not update "isVisited" value in context when the step was previously visited', () => {
121
+ const setStep = jest.fn();
122
+ const visitedTestStep = { ...testStep, isVisited: true };
123
+ useWizardContextSpy.mockReturnValueOnce({
124
+ ...wizardContext,
125
+ currentStep: visitedTestStep,
126
+ steps: [visitedTestStep],
127
+ setStep
128
+ });
129
+
130
+ render(<WizardStep {...visitedTestStep} />);
131
+
132
+ expect(setStep).not.toHaveBeenCalled();
133
+ });
@@ -13,13 +13,13 @@ const steps = [
13
13
 
14
14
  const defaultProps: WizardToggleProps = {
15
15
  steps,
16
- activeStep: steps[0],
16
+ currentStep: steps[0],
17
17
  footer: <div>Some footer</div>,
18
18
  nav: <div>Some nav</div>,
19
19
  'aria-label': 'Some label'
20
20
  };
21
21
 
22
- test('renders provided footer, nav, and active step content', () => {
22
+ test('renders provided footer, nav, and current step content', () => {
23
23
  render(<WizardToggle {...defaultProps} />);
24
24
 
25
25
  expect(screen.getByText('Some footer')).toBeVisible();
@@ -58,8 +58,8 @@ test('renders only the active step content by default', async () => {
58
58
  expect(screen.queryByText('Second step content')).toBeNull;
59
59
  });
60
60
 
61
- test('renders all step content when unmountInactiveSteps is false', async () => {
62
- render(<WizardToggle {...defaultProps} unmountInactiveSteps={false} />);
61
+ test('renders all step content when hasUnmountedSteps is false', async () => {
62
+ render(<WizardToggle {...defaultProps} hasUnmountedSteps={false} />);
63
63
 
64
64
  expect(screen.getByText('First step content')).toBeInTheDocument();
65
65
  expect(screen.getByText('Second step content')).toBeInTheDocument();
@@ -16,8 +16,7 @@ propComponents:
16
16
  'WizardBasicStep',
17
17
  'WizardParentStep',
18
18
  'WizardSubStep',
19
- 'DefaultWizardNavProps',
20
- 'DefaultWizardFooterProps',
19
+ 'WizardNavStepData',
21
20
  ]
22
21
  beta: true
23
22
  ---
@@ -28,7 +27,9 @@ TextInput,
28
27
  Drawer,
29
28
  DrawerContent,
30
29
  Button,
30
+ Title,
31
31
  Flex,
32
+ Checkbox,
32
33
  DrawerPanelContent,
33
34
  DrawerColorVariant,
34
35
  DrawerHead,
@@ -38,6 +39,7 @@ DrawerCloseButton
38
39
  import {
39
40
  Wizard,
40
41
  WizardFooter,
42
+ WizardFooterWrapper,
41
43
  WizardToggle,
42
44
  WizardStep,
43
45
  WizardBody,
@@ -66,7 +68,7 @@ The `Wizard`'s `nav` property can be used to build your own navigation.
66
68
  export type CustomWizardNavFunction = (
67
69
  isExpanded: boolean,
68
70
  steps: WizardControlStep[],
69
- activeStep: WizardControlStep,
71
+ currentStep: WizardControlStep,
70
72
  goToStepByIndex: (index: number) => void
71
73
  ) => React.ReactElement<WizardNavProps>;
72
74
 
@@ -79,9 +81,18 @@ type WizardControlStep = WizardBasicStep | WizardParentStep | WizardSubStep;
79
81
 
80
82
  ### Kitchen sink
81
83
 
82
- Includes a header, custom footer, sub-steps, step content with a drawer, custom nav item, and nav prevention until step visitation.
84
+ Includes the following:
83
85
 
84
- Custom operations when navigating between steps can be achieved by utilizing `onNext`, `onBack` or `onNavByIndex` properties whose callback functions return the 'id' and 'name' of the currently focused step (currentStep), and the previously focused step (previousStep).
86
+ - Header
87
+ - Custom footer
88
+ - Sub-steps
89
+ - Step content with a drawer
90
+ - Custom navigation item
91
+ - Disabled navigation items until visited
92
+ - Action to toggle visibility of a step
93
+ - Action to toggle navigation item error status
94
+
95
+ Custom operations when navigating between steps can be achieved by utilizing `onNext`, `onBack`, or `onNavByIndex` properties whose callback functions return the 'id' and 'name' of the currently focused step (currentStep), and the previously focused step (previousStep).
85
96
 
86
97
  ```noLive
87
98
  /** Callback for the Wizard's 'onNext', 'onBack', and 'onNavByIndex' properties */
@@ -91,33 +102,47 @@ type WizardNavStepFunction = (currentStep: WizardNavStepData, previousStep: Wiza
91
102
  type WizardNavStepData = Pick<WizardControlStep, 'id' | 'name'>;
92
103
  ```
93
104
 
105
+ #
106
+
107
+ The `WizardStep`'s `navItem` property can be used to build your own nav item for that step.
108
+
109
+ ```noLive
110
+ /** Callback for the Wizard's 'navItem' property. Returns element which replaces the WizardStep's default navItem. */
111
+ export type CustomWizardNavItemFunction = (
112
+ step: WizardControlStep,
113
+ currentStep: WizardControlStep,
114
+ steps: WizardControlStep[],
115
+ goToStepByIndex: (index: number) => void
116
+ ) => React.ReactElement<WizardNavItemProps>;
117
+ ```
118
+
94
119
  ```ts file="./WizardKitchenSink.tsx"
95
120
  ```
96
121
 
97
122
  ## Hooks
98
123
 
99
- ### useWizardFooter
124
+ ### useWizardContext
100
125
 
101
- Used to set a unique footer for the wizard on any given step. See step 3 of [Kitchen sink](#kitchen-sink) for a live example.
126
+ Used to access any property of [WizardContext](#wizardcontextprops):
102
127
 
103
128
  ```noLive
104
- import { useWizardFooter } from '@patternfly/react-core/next';
129
+ import { useWizardContext } from '@patternfly/react-core/next';
105
130
 
106
131
  const StepContent = () => {
107
- useWizardFooter(<>Some footer</>);
108
- return <>Step content</>;
132
+ const { currentStep } = useWizardContext();
133
+ return <>This is the current step: {currentStep}</>;
109
134
  }
110
135
  ```
111
136
 
112
- ### useWizardContext
137
+ ### useWizardFooter
113
138
 
114
- Used to access any property of [WizardContext](#wizardcontextprops):
139
+ Used to set a unique footer for the wizard on any given step. See step 3 of [Kitchen sink](#kitchen-sink) for a live example.
115
140
 
116
141
  ```noLive
117
- import { useWizardContext } from '@patternfly/react-core/next';
142
+ import { useWizardFooter } from '@patternfly/react-core/next';
118
143
 
119
144
  const StepContent = () => {
120
- const { activeStep } = useWizardContext();
121
- return <>This is the active step: {activeStep}</>;
145
+ useWizardFooter(<>Some footer</>);
146
+ return <>Step content</>;
122
147
  }
123
148
  ```
@@ -13,9 +13,9 @@ export const WizardBasic: React.FunctionComponent = () => (
13
13
  <p>Step 3 content</p>
14
14
  </WizardStep>
15
15
  <WizardStep name="Fourth step" id="basic-fourth-step">
16
- <p>Step 4 content</p>{' '}
16
+ <p>Step 4 content</p>
17
17
  </WizardStep>
18
- <WizardStep name="Review" id="basic-review-step" nextButtonText="Finish">
18
+ <WizardStep name="Review" id="basic-review-step" footer={{ nextButtonText: 'Finish' }}>
19
19
  <p>Review step content</p>
20
20
  </WizardStep>
21
21
  </Wizard>
@@ -12,7 +12,7 @@ export const WizardCustomNav: React.FunctionComponent = () => {
12
12
  const nav: CustomWizardNavFunction = (
13
13
  isExpanded: boolean,
14
14
  steps: WizardControlStep[],
15
- activeStep: WizardControlStep,
15
+ currentStep: WizardControlStep,
16
16
  goToStepByIndex: (index: number) => void
17
17
  ) => (
18
18
  <WizardNav isExpanded={isExpanded}>
@@ -21,9 +21,9 @@ export const WizardCustomNav: React.FunctionComponent = () => {
21
21
  key={step.id}
22
22
  id={step.id}
23
23
  content={step.name}
24
- isCurrent={activeStep.id === step.id}
24
+ isCurrent={currentStep.id === step.id}
25
25
  isDisabled={step.isDisabled}
26
- step={index + 1}
26
+ stepIndex={index + 1}
27
27
  onNavItemClick={goToStepByIndex}
28
28
  />
29
29
  ))}
@@ -38,7 +38,7 @@ export const WizardCustomNav: React.FunctionComponent = () => {
38
38
  <WizardStep name="Second step" id="cnav-second-step">
39
39
  <p>Step 2 content</p>
40
40
  </WizardStep>
41
- <WizardStep name="Review" id="cnav-review-step" nextButtonText="Wrap it up">
41
+ <WizardStep name="Review" id="cnav-review-step" footer={{ nextButtonText: 'Wrap it up' }}>
42
42
  <p>Review step content</p>
43
43
  </WizardStep>
44
44
  </Wizard>
@@ -11,7 +11,8 @@ import {
11
11
  DrawerColorVariant,
12
12
  DrawerHead,
13
13
  DrawerActions,
14
- DrawerCloseButton
14
+ DrawerCloseButton,
15
+ Checkbox
15
16
  } from '@patternfly/react-core';
16
17
  import {
17
18
  Wizard,
@@ -19,32 +20,55 @@ import {
19
20
  WizardBody,
20
21
  WizardFooter,
21
22
  WizardStepProps,
22
- WizardControlStep,
23
- useWizardFooter,
24
23
  useWizardContext,
25
24
  WizardNavStepFunction,
26
25
  WizardNavStepData,
27
26
  WizardNavItem,
28
- WizardHeader
27
+ WizardHeader,
28
+ WizardFooterWrapper,
29
+ WizardNavItemType
29
30
  } from '@patternfly/react-core/next';
30
31
 
31
- const CustomWizardFooter = () => {
32
- const { activeStep, onNext, onBack, onClose } = useWizardContext();
33
- return <WizardFooter activeStep={activeStep} onNext={onNext} onBack={onBack} onClose={onClose} />;
32
+ const StepId = {
33
+ StepOne: 'sink-step-1',
34
+ StepTwo: 'sink-step-2',
35
+ StepTwoSubOne: 'sink-step-2-1',
36
+ StepTwoSubTwo: 'sink-step-2-2',
37
+ StepThree: 'sink-step-3',
38
+ StepFour: 'sink-step-4',
39
+ ReviewStep: 'sink-review-step'
40
+ };
41
+
42
+ interface SomeContextProps {
43
+ isToggleStepChecked: boolean;
44
+ errorMessage: string | undefined;
45
+ setIsToggleStepChecked(isHidden: boolean): void;
46
+ setErrorMessage(error: string | undefined): void;
47
+ }
48
+
49
+ const SomeContext = React.createContext({} as SomeContextProps);
50
+
51
+ const SomeContextProvider = ({ children }) => {
52
+ const [isToggleStepChecked, setIsToggleStepChecked] = React.useState(false);
53
+ const [errorMessage, setErrorMessage] = React.useState<string>();
54
+
55
+ return (
56
+ <SomeContext.Provider value={{ isToggleStepChecked, errorMessage, setIsToggleStepChecked, setErrorMessage }}>
57
+ {children}
58
+ </SomeContext.Provider>
59
+ );
34
60
  };
35
61
 
36
- const CustomNavItem = () => {
37
- const { steps, activeStep, goToStepByIndex } = useWizardContext();
38
- const step = (steps.find(step => step.id === 'third-step') || {}) as WizardControlStep;
62
+ const CustomWizardFooter = () => {
63
+ const { currentStep, currentStepIndex, onNext, onBack, onClose } = useWizardContext();
39
64
 
40
65
  return (
41
- <WizardNavItem
42
- id={step.id}
43
- content={<span style={{ color: 'var(--pf-global--default-color--200)' }}>Custom item</span>}
44
- isCurrent={activeStep.id === step.id}
45
- step={steps.indexOf(step) + 1}
46
- isDisabled={step.isDisabled || !step.visited}
47
- onNavItemClick={goToStepByIndex}
66
+ <WizardFooter
67
+ currentStep={currentStep}
68
+ onNext={onNext}
69
+ onBack={onBack}
70
+ onClose={onClose}
71
+ isBackDisabled={currentStepIndex === 1}
48
72
  />
49
73
  );
50
74
  };
@@ -84,7 +108,7 @@ const StepContentWithDrawer = () => {
84
108
  );
85
109
  };
86
110
 
87
- const StepWithCustomFooter = () => {
111
+ const StepWithCustomFooter = (props: WizardStepProps) => {
88
112
  const { onNext: goToNextStep, onBack, onClose } = useWizardContext();
89
113
  const [isLoading, setIsLoading] = React.useState(false);
90
114
 
@@ -98,7 +122,7 @@ const StepWithCustomFooter = () => {
98
122
 
99
123
  const footer = React.useMemo(
100
124
  () => (
101
- <>
125
+ <WizardFooterWrapper>
102
126
  <Button variant="primary" onClick={() => onNext(goToNextStep)} isLoading={isLoading} isDisabled={isLoading}>
103
127
  Async Next
104
128
  </Button>
@@ -108,55 +132,97 @@ const StepWithCustomFooter = () => {
108
132
  <Button variant="link" onClick={onClose}>
109
133
  Cancel
110
134
  </Button>
111
- </>
135
+ </WizardFooterWrapper>
112
136
  ),
113
- [isLoading, onBack, onClose, goToNextStep]
137
+ [goToNextStep, isLoading, onBack, onClose]
114
138
  );
115
- useWizardFooter(footer);
116
139
 
117
- return <>Step 3 content w/ custom async footer</>;
140
+ return (
141
+ <WizardStep {...props} footer={footer}>
142
+ Step 3 content w/ custom async footer
143
+ </WizardStep>
144
+ );
118
145
  };
119
146
 
120
- const CustomStepFour = (props: WizardStepProps) => <div {...props} id={props.id.toString()} />;
147
+ const StepWithContextActions = (props: WizardStepProps) => {
148
+ const { isToggleStepChecked, errorMessage, setIsToggleStepChecked, setErrorMessage } = React.useContext(SomeContext);
121
149
 
122
- export const WizardKitchenSink: React.FunctionComponent = () => {
123
- const onNext: WizardNavStepFunction = (currentStep: WizardNavStepData, previousStep: WizardNavStepData) => {
124
- // eslint-disable-next-line no-console
125
- console.log('currentStep: ', currentStep, '\n previousStep: ', previousStep);
126
- };
150
+ const navItem: WizardNavItemType = React.useCallback(
151
+ (step, currentStep, steps, goToStepByIndex) => (
152
+ <WizardNavItem
153
+ id={step.id}
154
+ content={step.name}
155
+ isCurrent={currentStep.id === step.id}
156
+ stepIndex={steps.indexOf(step) + 1}
157
+ isDisabled={step.isDisabled || !step.isVisited}
158
+ isVisited={step.isVisited}
159
+ onNavItemClick={goToStepByIndex}
160
+ status={errorMessage ? 'error' : 'default'}
161
+ />
162
+ ),
163
+ [errorMessage]
164
+ );
127
165
 
128
166
  return (
129
- <Wizard
130
- height={400}
131
- header={<WizardHeader title="You're a wizard, Harry" closeButtonAriaLabel="Close header" />}
132
- footer={<CustomWizardFooter />}
133
- nav={{ forceStepVisit: true, isExpandable: true }}
134
- onNext={onNext}
135
- >
136
- <WizardStep id="sink-first-step" name="First step" body={null}>
137
- <StepContentWithDrawer />
138
- </WizardStep>
139
- <WizardStep
140
- id="sink-second-step"
141
- name="Second step"
142
- steps={[
143
- <WizardStep id="sink-sub-step-one" key="substep-one" name="Substep 1">
144
- Substep 1 content
145
- </WizardStep>,
146
- <WizardStep id="sink-sub-step-two" key="substep-two" name="Substep 2">
147
- Substep 2 content
148
- </WizardStep>
149
- ]}
167
+ <WizardStep {...props} navItem={navItem}>
168
+ <Checkbox
169
+ label="Give this step an error status"
170
+ isChecked={!!errorMessage}
171
+ onChange={checked => setErrorMessage(checked ? 'Some error message' : undefined)}
172
+ id="toggle-error-checkbox"
173
+ name="Toggle Error Checkbox"
174
+ />
175
+ <Checkbox
176
+ label="Toggle visibility of the next step"
177
+ isChecked={isToggleStepChecked}
178
+ onChange={checked => setIsToggleStepChecked(checked)}
179
+ id="toggle-hide-step-checkbox"
180
+ name="Toggle Hide Step Checkbox"
150
181
  />
151
- <WizardStep id="sink-third-step" name="Third step" navItem={<CustomNavItem />}>
152
- <StepWithCustomFooter />
153
- </WizardStep>
154
- <CustomStepFour id="sink-fourth-step" name="Fourth step">
155
- <WizardBody>Step 4 content</WizardBody>
156
- </CustomStepFour>
157
- <WizardStep id="sink-review-step" name="Review" nextButtonText="Submit">
158
- Review step content
159
- </WizardStep>
160
- </Wizard>
182
+ </WizardStep>
183
+ );
184
+ };
185
+
186
+ const StepToHide = (props: WizardStepProps) => {
187
+ const { isToggleStepChecked } = React.useContext(SomeContext);
188
+ return <WizardStep {...props} isHidden={isToggleStepChecked} />;
189
+ };
190
+
191
+ export const WizardKitchenSink: React.FunctionComponent = () => {
192
+ const onNext: WizardNavStepFunction = (_currentStep: WizardNavStepData, _previousStep: WizardNavStepData) => {};
193
+
194
+ return (
195
+ <SomeContextProvider>
196
+ <Wizard
197
+ height={400}
198
+ header={<WizardHeader title="You're a wizard, Harry" closeButtonAriaLabel="Close header" />}
199
+ footer={<CustomWizardFooter />}
200
+ isStepVisitRequired
201
+ onNext={onNext}
202
+ hasUnmountedSteps={false}
203
+ >
204
+ <WizardStep id={StepId.StepOne} name="Step 1" body={null} status="error">
205
+ <StepContentWithDrawer />
206
+ </WizardStep>
207
+ <WizardStep
208
+ id={StepId.StepTwo}
209
+ name="Step 2"
210
+ steps={[
211
+ <StepWithContextActions id={StepId.StepTwoSubOne} key={StepId.StepTwoSubOne} name="Substep 1" />,
212
+ <StepToHide id={StepId.StepTwoSubTwo} key={StepId.StepTwoSubTwo} name="Substep 2">
213
+ Substep 2 content
214
+ </StepToHide>
215
+ ]}
216
+ />
217
+ <StepWithCustomFooter
218
+ id={StepId.StepThree}
219
+ name="Step 3"
220
+ navItem={{ content: <span style={{ color: 'var(--pf-global--default-color--200)' }}>Custom item</span> }}
221
+ />
222
+ <WizardStep id={StepId.ReviewStep} name="Review" footer={{ nextButtonText: 'Submit' }}>
223
+ Review step content
224
+ </WizardStep>
225
+ </Wizard>
226
+ </SomeContextProvider>
161
227
  );
162
228
  };
@@ -5,47 +5,36 @@ import { renderHook } from '@testing-library/react-hooks';
5
5
  import { useWizardFooter } from '../useWizardFooter';
6
6
  import * as WizardContext from '../../WizardContext';
7
7
 
8
- describe('useWizardFooter', () => {
9
- const customFooter = <>My custom footer</>;
10
- const useWizardContextSpy = jest.spyOn(WizardContext, 'useWizardContext');
11
- const setFooter = jest.fn();
8
+ const customFooter = <>My custom footer</>;
9
+ const useWizardContextSpy = jest.spyOn(WizardContext, 'useWizardContext');
10
+ const setFooter = jest.fn();
12
11
 
13
- it('sets the footer when one is provided without a stepId', () => {
14
- useWizardContextSpy.mockReturnValueOnce({ setFooter } as any);
12
+ test('sets the footer when one is provided without a stepId', () => {
13
+ useWizardContextSpy.mockReturnValueOnce({ setFooter } as any);
15
14
 
16
- renderHook(() => useWizardFooter(customFooter));
17
- expect(setFooter).toHaveBeenCalledWith(customFooter);
18
- });
19
-
20
- it(`sets the footer when the provided stepId matches the activeStep's id`, () => {
21
- useWizardContextSpy.mockReturnValueOnce({ setFooter, activeStep: { id: 'active-step-id' } } as any);
22
-
23
- renderHook(() => useWizardFooter(customFooter, 'active-step-id'));
24
- expect(setFooter).toHaveBeenCalledWith(customFooter);
25
- });
26
-
27
- it(`does not set the footer when the provided stepId does not match the activeStep's id`, () => {
28
- useWizardContextSpy.mockReturnValueOnce({ setFooter, activeStep: { id: 'active-step-id' } } as any);
15
+ renderHook(() => useWizardFooter(customFooter));
16
+ expect(setFooter).toHaveBeenCalledWith(customFooter);
17
+ });
29
18
 
30
- renderHook(() => useWizardFooter(customFooter, 'some-other-step-id'));
31
- expect(setFooter).not.toHaveBeenCalled();
32
- });
19
+ test(`sets the footer when the provided stepId matches the currentStep's id`, () => {
20
+ useWizardContextSpy.mockReturnValueOnce({ setFooter, currentStep: { id: 'curr-step-id' } } as any);
33
21
 
34
- it('sets the footer to null on unmount', () => {
35
- useWizardContextSpy.mockReturnValueOnce({ setFooter } as any);
22
+ renderHook(() => useWizardFooter(customFooter, 'curr-step-id'));
23
+ expect(setFooter).toHaveBeenCalledWith(customFooter);
24
+ });
36
25
 
37
- const { unmount } = renderHook(() => useWizardFooter(customFooter));
38
- unmount();
26
+ test(`does not set the footer when the provided stepId does not match the currentStep's id`, () => {
27
+ useWizardContextSpy.mockReturnValueOnce({ setFooter, currentStep: { id: 'curr-step-id' } } as any);
39
28
 
40
- expect(setFooter).toHaveBeenCalledWith(null);
41
- });
29
+ renderHook(() => useWizardFooter(customFooter, 'some-other-step-id'));
30
+ expect(setFooter).not.toHaveBeenCalled();
31
+ });
42
32
 
43
- it('sets footer with default props instead of react element', () => {
44
- const footerProps = { onNext: jest.fn(), onBack: jest.fn(), onClose: jest.fn() };
45
- useWizardContextSpy.mockReturnValueOnce({ setFooter } as any);
33
+ test('sets the footer to null on unmount', () => {
34
+ useWizardContextSpy.mockReturnValueOnce({ setFooter } as any);
46
35
 
47
- renderHook(() => useWizardFooter(footerProps));
36
+ const { unmount } = renderHook(() => useWizardFooter(customFooter));
37
+ unmount();
48
38
 
49
- expect(setFooter).toHaveBeenCalledWith(footerProps);
50
- });
39
+ expect(setFooter).toHaveBeenCalledWith(null);
51
40
  });
@@ -1,18 +1,18 @@
1
1
  import React from 'react';
2
2
 
3
- import { DefaultWizardFooterProps } from '../types';
4
3
  import { useWizardContext } from '../WizardContext';
4
+ import { WizardFooterProps } from '../WizardFooter';
5
5
 
6
6
  /**
7
7
  * Set a unique footer for the wizard. stepId is only required if inactive steps are hidden instead of unmounted.
8
8
  * @param footer
9
9
  * @param stepId
10
10
  */
11
- export const useWizardFooter = (footer: DefaultWizardFooterProps | React.ReactElement, stepId?: string | number) => {
12
- const { activeStep, setFooter } = useWizardContext();
11
+ export const useWizardFooter = (footer: React.ReactElement | Partial<WizardFooterProps>, stepId?: string | number) => {
12
+ const { currentStep, setFooter } = useWizardContext();
13
13
 
14
14
  React.useEffect(() => {
15
- if (!stepId || activeStep.id === stepId) {
15
+ if (footer && (!stepId || currentStep?.id === stepId)) {
16
16
  setFooter(footer);
17
17
 
18
18
  // Reset the footer on unmount.
@@ -20,5 +20,5 @@ export const useWizardFooter = (footer: DefaultWizardFooterProps | React.ReactEl
20
20
  setFooter(null);
21
21
  };
22
22
  }
23
- }, [activeStep, footer, setFooter, stepId]);
23
+ }, [currentStep, footer, setFooter, stepId]);
24
24
  };