@patternfly/react-core 6.4.0-prerelease.5 → 6.4.1-prerelease.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 (186) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/components/package.json +1 -1
  3. package/deprecated/package.json +1 -1
  4. package/dist/dynamic/components/AboutModal/package.json +1 -1
  5. package/dist/dynamic/components/Accordion/package.json +1 -1
  6. package/dist/dynamic/components/ActionList/package.json +1 -1
  7. package/dist/dynamic/components/Alert/package.json +1 -1
  8. package/dist/dynamic/components/Avatar/package.json +1 -1
  9. package/dist/dynamic/components/BackToTop/package.json +1 -1
  10. package/dist/dynamic/components/Backdrop/package.json +1 -1
  11. package/dist/dynamic/components/BackgroundImage/package.json +1 -1
  12. package/dist/dynamic/components/Badge/package.json +1 -1
  13. package/dist/dynamic/components/Banner/package.json +1 -1
  14. package/dist/dynamic/components/Brand/package.json +1 -1
  15. package/dist/dynamic/components/Breadcrumb/package.json +1 -1
  16. package/dist/dynamic/components/Button/package.json +1 -1
  17. package/dist/dynamic/components/CalendarMonth/package.json +1 -1
  18. package/dist/dynamic/components/Card/package.json +1 -1
  19. package/dist/dynamic/components/Checkbox/package.json +1 -1
  20. package/dist/dynamic/components/ClipboardCopy/package.json +1 -1
  21. package/dist/dynamic/components/CodeBlock/package.json +1 -1
  22. package/dist/dynamic/components/Content/package.json +1 -1
  23. package/dist/dynamic/components/DataList/package.json +1 -1
  24. package/dist/dynamic/components/DatePicker/package.json +1 -1
  25. package/dist/dynamic/components/DescriptionList/package.json +1 -1
  26. package/dist/dynamic/components/Divider/package.json +1 -1
  27. package/dist/dynamic/components/Drawer/package.json +1 -1
  28. package/dist/dynamic/components/Dropdown/package.json +1 -1
  29. package/dist/dynamic/components/DualListSelector/package.json +1 -1
  30. package/dist/dynamic/components/EmptyState/package.json +1 -1
  31. package/dist/dynamic/components/ExpandableSection/package.json +1 -1
  32. package/dist/dynamic/components/FileUpload/package.json +1 -1
  33. package/dist/dynamic/components/Form/package.json +1 -1
  34. package/dist/dynamic/components/FormSelect/package.json +1 -1
  35. package/dist/dynamic/components/HelperText/package.json +1 -1
  36. package/dist/dynamic/components/Hint/package.json +1 -1
  37. package/dist/dynamic/components/Icon/package.json +1 -1
  38. package/dist/dynamic/components/InputGroup/package.json +1 -1
  39. package/dist/dynamic/components/JumpLinks/package.json +1 -1
  40. package/dist/dynamic/components/Label/package.json +1 -1
  41. package/dist/dynamic/components/List/package.json +1 -1
  42. package/dist/dynamic/components/LoginPage/package.json +1 -1
  43. package/dist/dynamic/components/Masthead/package.json +1 -1
  44. package/dist/dynamic/components/Menu/package.json +1 -1
  45. package/dist/dynamic/components/MenuToggle/package.json +1 -1
  46. package/dist/dynamic/components/Modal/package.json +1 -1
  47. package/dist/dynamic/components/MultipleFileUpload/package.json +1 -1
  48. package/dist/dynamic/components/Nav/package.json +1 -1
  49. package/dist/dynamic/components/NotificationBadge/package.json +1 -1
  50. package/dist/dynamic/components/NotificationDrawer/package.json +1 -1
  51. package/dist/dynamic/components/NumberInput/package.json +1 -1
  52. package/dist/dynamic/components/OverflowMenu/package.json +1 -1
  53. package/dist/dynamic/components/Page/package.json +1 -1
  54. package/dist/dynamic/components/Pagination/package.json +1 -1
  55. package/dist/dynamic/components/Panel/package.json +1 -1
  56. package/dist/dynamic/components/Popover/package.json +1 -1
  57. package/dist/dynamic/components/Progress/package.json +1 -1
  58. package/dist/dynamic/components/ProgressStepper/package.json +1 -1
  59. package/dist/dynamic/components/Radio/package.json +1 -1
  60. package/dist/dynamic/components/SearchInput/package.json +1 -1
  61. package/dist/dynamic/components/Select/package.json +1 -1
  62. package/dist/dynamic/components/Sidebar/package.json +1 -1
  63. package/dist/dynamic/components/SimpleList/package.json +1 -1
  64. package/dist/dynamic/components/Skeleton/package.json +1 -1
  65. package/dist/dynamic/components/SkipToContent/package.json +1 -1
  66. package/dist/dynamic/components/Slider/package.json +1 -1
  67. package/dist/dynamic/components/Spinner/package.json +1 -1
  68. package/dist/dynamic/components/Switch/package.json +1 -1
  69. package/dist/dynamic/components/Tabs/package.json +1 -1
  70. package/dist/dynamic/components/TextArea/package.json +1 -1
  71. package/dist/dynamic/components/TextInput/package.json +1 -1
  72. package/dist/dynamic/components/TextInputGroup/package.json +1 -1
  73. package/dist/dynamic/components/TimePicker/package.json +1 -1
  74. package/dist/dynamic/components/Timestamp/package.json +1 -1
  75. package/dist/dynamic/components/Title/package.json +1 -1
  76. package/dist/dynamic/components/ToggleGroup/package.json +1 -1
  77. package/dist/dynamic/components/Toolbar/package.json +1 -1
  78. package/dist/dynamic/components/Tooltip/package.json +1 -1
  79. package/dist/dynamic/components/TreeView/package.json +1 -1
  80. package/dist/dynamic/components/Truncate/package.json +1 -1
  81. package/dist/dynamic/components/Wizard/hooks/package.json +1 -1
  82. package/dist/dynamic/components/Wizard/package.json +1 -1
  83. package/dist/dynamic/deprecated/components/Chip/package.json +1 -1
  84. package/dist/dynamic/deprecated/components/DragDrop/package.json +1 -1
  85. package/dist/dynamic/deprecated/components/DualListSelector/package.json +1 -1
  86. package/dist/dynamic/deprecated/components/Modal/package.json +1 -1
  87. package/dist/dynamic/deprecated/components/Tile/package.json +1 -1
  88. package/dist/dynamic/deprecated/components/Wizard/package.json +1 -1
  89. package/dist/dynamic/deprecated/components/package.json +1 -1
  90. package/dist/dynamic/helpers/AnimationsProvider/AnimationsProvider/package.json +1 -1
  91. package/dist/dynamic/helpers/AnimationsProvider/package.json +1 -1
  92. package/dist/dynamic/helpers/FocusTrap/FocusTrap/package.json +1 -1
  93. package/dist/dynamic/helpers/GenerateId/GenerateId/package.json +1 -1
  94. package/dist/dynamic/helpers/KeyboardHandler/package.json +1 -1
  95. package/dist/dynamic/helpers/OUIA/ouia/package.json +1 -1
  96. package/dist/dynamic/helpers/Popper/Popper/package.json +1 -1
  97. package/dist/dynamic/helpers/constants/package.json +1 -1
  98. package/dist/dynamic/helpers/datetimeUtils/package.json +1 -1
  99. package/dist/dynamic/helpers/fileUtils/package.json +1 -1
  100. package/dist/dynamic/helpers/htmlConstants/package.json +1 -1
  101. package/dist/dynamic/helpers/package.json +1 -1
  102. package/dist/dynamic/helpers/resizeObserver/package.json +1 -1
  103. package/dist/dynamic/helpers/typeUtils/package.json +1 -1
  104. package/dist/dynamic/helpers/useInterval/package.json +1 -1
  105. package/dist/dynamic/helpers/useIsomorphicLayout/package.json +1 -1
  106. package/dist/dynamic/helpers/useUnmountEffect/package.json +1 -1
  107. package/dist/dynamic/helpers/util/package.json +1 -1
  108. package/dist/dynamic/layouts/Bullseye/package.json +1 -1
  109. package/dist/dynamic/layouts/Flex/package.json +1 -1
  110. package/dist/dynamic/layouts/Gallery/package.json +1 -1
  111. package/dist/dynamic/layouts/Grid/package.json +1 -1
  112. package/dist/dynamic/layouts/Level/package.json +1 -1
  113. package/dist/dynamic/layouts/Split/package.json +1 -1
  114. package/dist/dynamic/layouts/Stack/package.json +1 -1
  115. package/dist/dynamic/styles/package.json +1 -1
  116. package/dist/esm/components/Checkbox/Checkbox.d.ts +3 -0
  117. package/dist/esm/components/Checkbox/Checkbox.d.ts.map +1 -1
  118. package/dist/esm/components/Checkbox/Checkbox.js +14 -4
  119. package/dist/esm/components/Checkbox/Checkbox.js.map +1 -1
  120. package/dist/esm/components/Drawer/DrawerPanelContent.d.ts.map +1 -1
  121. package/dist/esm/components/Drawer/DrawerPanelContent.js +2 -4
  122. package/dist/esm/components/Drawer/DrawerPanelContent.js.map +1 -1
  123. package/dist/esm/components/Progress/ProgressContainer.js +2 -2
  124. package/dist/esm/components/Progress/ProgressContainer.js.map +1 -1
  125. package/dist/esm/components/Radio/Radio.d.ts +3 -0
  126. package/dist/esm/components/Radio/Radio.d.ts.map +1 -1
  127. package/dist/esm/components/Radio/Radio.js +15 -5
  128. package/dist/esm/components/Radio/Radio.js.map +1 -1
  129. package/dist/esm/components/Wizard/WizardNavItem.d.ts +1 -1
  130. package/dist/esm/components/Wizard/WizardNavItem.d.ts.map +1 -1
  131. package/dist/esm/components/Wizard/WizardNavItem.js +2 -1
  132. package/dist/esm/components/Wizard/WizardNavItem.js.map +1 -1
  133. package/dist/esm/components/Wizard/WizardStep.d.ts +1 -1
  134. package/dist/esm/components/Wizard/WizardStep.d.ts.map +1 -1
  135. package/dist/esm/components/Wizard/types.d.ts +3 -2
  136. package/dist/esm/components/Wizard/types.d.ts.map +1 -1
  137. package/dist/esm/components/Wizard/types.js +1 -0
  138. package/dist/esm/components/Wizard/types.js.map +1 -1
  139. package/dist/js/components/Checkbox/Checkbox.d.ts +3 -0
  140. package/dist/js/components/Checkbox/Checkbox.d.ts.map +1 -1
  141. package/dist/js/components/Checkbox/Checkbox.js +14 -4
  142. package/dist/js/components/Checkbox/Checkbox.js.map +1 -1
  143. package/dist/js/components/Drawer/DrawerPanelContent.d.ts.map +1 -1
  144. package/dist/js/components/Drawer/DrawerPanelContent.js +2 -4
  145. package/dist/js/components/Drawer/DrawerPanelContent.js.map +1 -1
  146. package/dist/js/components/Progress/ProgressContainer.js +2 -2
  147. package/dist/js/components/Progress/ProgressContainer.js.map +1 -1
  148. package/dist/js/components/Radio/Radio.d.ts +3 -0
  149. package/dist/js/components/Radio/Radio.d.ts.map +1 -1
  150. package/dist/js/components/Radio/Radio.js +15 -5
  151. package/dist/js/components/Radio/Radio.js.map +1 -1
  152. package/dist/js/components/Wizard/WizardNavItem.d.ts +1 -1
  153. package/dist/js/components/Wizard/WizardNavItem.d.ts.map +1 -1
  154. package/dist/js/components/Wizard/WizardNavItem.js +2 -1
  155. package/dist/js/components/Wizard/WizardNavItem.js.map +1 -1
  156. package/dist/js/components/Wizard/WizardStep.d.ts +1 -1
  157. package/dist/js/components/Wizard/WizardStep.d.ts.map +1 -1
  158. package/dist/js/components/Wizard/types.d.ts +3 -2
  159. package/dist/js/components/Wizard/types.d.ts.map +1 -1
  160. package/dist/js/components/Wizard/types.js +1 -0
  161. package/dist/js/components/Wizard/types.js.map +1 -1
  162. package/dist/umd/assets/{output-rGK8HlkA.css → output-CSllYx5z.css} +19902 -19902
  163. package/dist/umd/react-core.min.js +1 -1
  164. package/helpers/package.json +1 -1
  165. package/layouts/package.json +1 -1
  166. package/next/package.json +1 -1
  167. package/package.json +5 -5
  168. package/src/components/Checkbox/Checkbox.tsx +21 -2
  169. package/src/components/Checkbox/__tests__/Checkbox.test.tsx +34 -0
  170. package/src/components/Drawer/DrawerPanelContent.tsx +5 -3
  171. package/src/components/Drawer/__tests__/DrawerPanelContent.test.tsx +37 -0
  172. package/src/components/Progress/ProgressContainer.tsx +2 -2
  173. package/src/components/Progress/__tests__/Generated/__snapshots__/ProgressContainer.test.tsx.snap +1 -1
  174. package/src/components/Progress/__tests__/__snapshots__/Progress.test.tsx.snap +1 -1
  175. package/src/components/Radio/Radio.tsx +21 -3
  176. package/src/components/Radio/__tests__/Radio.test.tsx +44 -0
  177. package/src/components/Tabs/__tests__/Tabs.test.tsx +109 -1
  178. package/src/components/Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap +2 -2
  179. package/src/components/Tabs/examples/Tabs.md +38 -4
  180. package/src/components/Tabs/examples/TabsSeparateContent.tsx +3 -2
  181. package/src/components/Wizard/WizardNavItem.tsx +5 -2
  182. package/src/components/Wizard/WizardStep.tsx +1 -1
  183. package/src/components/Wizard/__tests__/WizardNavItem.test.tsx +6 -0
  184. package/src/components/Wizard/__tests__/WizardStep.test.tsx +2 -0
  185. package/src/components/Wizard/examples/WizardStepStatus.tsx +28 -7
  186. package/src/components/Wizard/types.tsx +3 -2
@@ -1 +1 @@
1
- {"name":"@patternfly/react-core-helpers","main":"../dist/js/helpers/index.js","module":"../dist/esm/helpers/index.js","typings":"../dist/esm/helpers/index.d.ts","version":"6.4.0-prerelease.4","private":true}
1
+ {"name":"@patternfly/react-core-helpers","main":"../dist/js/helpers/index.js","module":"../dist/esm/helpers/index.js","typings":"../dist/esm/helpers/index.d.ts","version":"6.4.0","private":true}
@@ -1 +1 @@
1
- {"name":"@patternfly/react-core-layouts","main":"../dist/js/layouts/index.js","module":"../dist/esm/layouts/index.js","typings":"../dist/esm/layouts/index.d.ts","version":"6.4.0-prerelease.4","private":true}
1
+ {"name":"@patternfly/react-core-layouts","main":"../dist/js/layouts/index.js","module":"../dist/esm/layouts/index.js","typings":"../dist/esm/layouts/index.d.ts","version":"6.4.0","private":true}
package/next/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@patternfly/react-core-next","main":"../dist/js/next/index.js","module":"../dist/esm/next/index.js","typings":"../dist/esm/next/index.d.ts","version":"6.4.0-prerelease.4","private":true}
1
+ {"name":"@patternfly/react-core-next","main":"../dist/js/next/index.js","module":"../dist/esm/next/index.js","typings":"../dist/esm/next/index.d.ts","version":"6.4.0","private":true}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/react-core",
3
- "version": "6.4.0-prerelease.5",
3
+ "version": "6.4.1-prerelease.0",
4
4
  "description": "This library provides a set of common React components for use with the PatternFly reference implementation.",
5
5
  "main": "dist/js/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -46,9 +46,9 @@
46
46
  "subpaths": "node ../../scripts/exportSubpaths.mjs --config subpaths.config.json"
47
47
  },
48
48
  "dependencies": {
49
- "@patternfly/react-icons": "^6.4.0-prerelease.3",
50
- "@patternfly/react-styles": "^6.4.0-prerelease.3",
51
- "@patternfly/react-tokens": "^6.4.0-prerelease.3",
49
+ "@patternfly/react-icons": "^6.4.0",
50
+ "@patternfly/react-styles": "^6.4.0",
51
+ "@patternfly/react-tokens": "^6.4.0",
52
52
  "focus-trap": "7.6.4",
53
53
  "react-dropzone": "^14.3.5",
54
54
  "tslib": "^2.8.1"
@@ -63,5 +63,5 @@
63
63
  "react": "^17 || ^18 || ^19",
64
64
  "react-dom": "^17 || ^18 || ^19"
65
65
  },
66
- "gitHead": "201443e85688ffd5be3bdcd1bd37c9e67cf634e3"
66
+ "gitHead": "f783f064d4256000fec110dae7e4e04d42f7e9ac"
67
67
  }
@@ -3,6 +3,7 @@ import styles from '@patternfly/react-styles/css/components/Check/check';
3
3
  import { css } from '@patternfly/react-styles';
4
4
  import { PickOptional } from '../../helpers/typeUtils';
5
5
  import { getDefaultOUIAId, getOUIAProps, OUIAProps } from '../../helpers';
6
+ import { getUniqueId } from '../../helpers/util';
6
7
  import { ASTERISK } from '../../helpers/htmlConstants';
7
8
 
8
9
  export interface CheckboxProps
@@ -39,6 +40,8 @@ export interface CheckboxProps
39
40
  description?: React.ReactNode;
40
41
  /** Body text of the checkbox */
41
42
  body?: React.ReactNode;
43
+ /** Custom aria-describedby value for the checkbox input. If not provided and description is set, a unique ID will be generated automatically. */
44
+ 'aria-describedby'?: string;
42
45
  /** Sets the checkbox wrapper component to render. Defaults to "div". If set to "label", behaves the same as if isLabelWrapped prop was specified. */
43
46
  component?: React.ElementType;
44
47
  /** Value to overwrite the randomly generated data-ouia-component-id.*/
@@ -52,6 +55,7 @@ const defaultOnChange = () => {};
52
55
 
53
56
  interface CheckboxState {
54
57
  ouiaStateId: string;
58
+ descriptionId: string;
55
59
  }
56
60
 
57
61
  class Checkbox extends Component<CheckboxProps, CheckboxState> {
@@ -70,7 +74,8 @@ class Checkbox extends Component<CheckboxProps, CheckboxState> {
70
74
  constructor(props: any) {
71
75
  super(props);
72
76
  this.state = {
73
- ouiaStateId: getDefaultOUIAId(Checkbox.displayName)
77
+ ouiaStateId: getDefaultOUIAId(Checkbox.displayName),
78
+ descriptionId: getUniqueId('pf-checkbox-description')
74
79
  };
75
80
  }
76
81
 
@@ -81,6 +86,7 @@ class Checkbox extends Component<CheckboxProps, CheckboxState> {
81
86
  render() {
82
87
  const {
83
88
  'aria-label': ariaLabel,
89
+ 'aria-describedby': ariaDescribedBy,
84
90
  className,
85
91
  inputClassName,
86
92
  onChange,
@@ -115,6 +121,14 @@ class Checkbox extends Component<CheckboxProps, CheckboxState> {
115
121
  checkedProps.defaultChecked = defaultChecked;
116
122
  }
117
123
 
124
+ // Handle aria-describedby logic
125
+ let ariaDescribedByValue: string | undefined;
126
+ if (ariaDescribedBy !== undefined) {
127
+ ariaDescribedByValue = ariaDescribedBy === '' ? undefined : ariaDescribedBy;
128
+ } else if (description) {
129
+ ariaDescribedByValue = this.state.descriptionId;
130
+ }
131
+
118
132
  const inputRendered = (
119
133
  <input
120
134
  {...props}
@@ -123,6 +137,7 @@ class Checkbox extends Component<CheckboxProps, CheckboxState> {
123
137
  onChange={this.handleChange}
124
138
  aria-invalid={!isValid}
125
139
  aria-label={ariaLabel}
140
+ aria-describedby={ariaDescribedByValue}
126
141
  disabled={isDisabled}
127
142
  required={isRequired}
128
143
  ref={(elem) => {
@@ -169,7 +184,11 @@ class Checkbox extends Component<CheckboxProps, CheckboxState> {
169
184
  {labelRendered}
170
185
  </>
171
186
  )}
172
- {description && <span className={css(styles.checkDescription)}>{description}</span>}
187
+ {description && (
188
+ <span id={this.state.descriptionId} className={css(styles.checkDescription)}>
189
+ {description}
190
+ </span>
191
+ )}
173
192
  {body && <span className={css(styles.checkBody)}>{body}</span>}
174
193
  </Component>
175
194
  );
@@ -287,3 +287,37 @@ test('Matches snapshot', () => {
287
287
 
288
288
  expect(asFragment()).toMatchSnapshot();
289
289
  });
290
+
291
+ test('Sets aria-describedby when description is provided', () => {
292
+ render(<Checkbox id="test-id" description="test description" />);
293
+
294
+ const checkbox = screen.getByRole('checkbox');
295
+ const descriptionElement = screen.getByText('test description');
296
+
297
+ expect(checkbox).toHaveAttribute('aria-describedby', descriptionElement.id);
298
+ expect(descriptionElement).toHaveAttribute('id');
299
+ });
300
+
301
+ test('Sets custom aria-describedby when provided', () => {
302
+ render(<Checkbox id="test-id" description="test description" aria-describedby="custom-id" />);
303
+
304
+ const checkbox = screen.getByRole('checkbox');
305
+
306
+ expect(checkbox).toHaveAttribute('aria-describedby', 'custom-id');
307
+ });
308
+
309
+ test('Does not set aria-describedby when no description is provided', () => {
310
+ render(<Checkbox id="test-id" />);
311
+
312
+ const checkbox = screen.getByRole('checkbox');
313
+
314
+ expect(checkbox).not.toHaveAttribute('aria-describedby');
315
+ });
316
+
317
+ test('Does not set aria-describedby when description is provided but aria-describedby is empty string', () => {
318
+ render(<Checkbox id="test-id" description="test description" aria-describedby="" />);
319
+
320
+ const checkbox = screen.getByRole('checkbox');
321
+
322
+ expect(checkbox).not.toHaveAttribute('aria-describedby');
323
+ });
@@ -77,6 +77,7 @@ export const DrawerPanelContent: React.FunctionComponent<DrawerPanelContentProps
77
77
  widths,
78
78
  colorVariant = DrawerColorVariant.default,
79
79
  focusTrap,
80
+ style,
80
81
  ...props
81
82
  }: DrawerPanelContentProps) => {
82
83
  const panel = useRef<HTMLDivElement>(undefined);
@@ -381,9 +382,10 @@ export const DrawerPanelContent: React.FunctionComponent<DrawerPanelContentProps
381
382
  }
382
383
  }}
383
384
  hidden={hidden}
384
- {...((defaultSize || minSize || maxSize) && {
385
- style: boundaryCssVars as React.CSSProperties
386
- })}
385
+ style={{
386
+ ...((defaultSize || minSize || maxSize) && boundaryCssVars),
387
+ ...style
388
+ }}
387
389
  {...props}
388
390
  ref={panel}
389
391
  >
@@ -121,3 +121,40 @@ test('Renders with role="dialog" when focusTrap.enabled is true', () => {
121
121
 
122
122
  expect(screen.getByRole('dialog')).toBeInTheDocument();
123
123
  });
124
+
125
+ test('Applies style prop as expected', () => {
126
+ render(
127
+ <Drawer isExpanded>
128
+ <DrawerPanelContent style={{ backgroundColor: 'red', padding: '20px' }}>Drawer panel content</DrawerPanelContent>
129
+ </Drawer>
130
+ );
131
+
132
+ const panelContent = screen.getByText('Drawer panel content');
133
+ expect(panelContent).toHaveStyle({ backgroundColor: 'red', padding: '20px' });
134
+ });
135
+
136
+ test('Style prop overrides boundaryCssVars', () => {
137
+ render(
138
+ <Drawer isExpanded>
139
+ <DrawerPanelContent
140
+ defaultSize="200px"
141
+ minSize="100px"
142
+ maxSize="400px"
143
+ style={{
144
+ '--pf-v6-c-drawer__panel--md--FlexBasis': '300px',
145
+ '--pf-v6-c-drawer__panel--md--FlexBasis--min': '150px',
146
+ '--pf-v6-c-drawer__panel--md--FlexBasis--max': '500px'
147
+ }}
148
+ >
149
+ Drawer panel content
150
+ </DrawerPanelContent>
151
+ </Drawer>
152
+ );
153
+
154
+ const panelContent = screen.getByText('Drawer panel content');
155
+ expect(panelContent).toHaveStyle({
156
+ '--pf-v6-c-drawer__panel--md--FlexBasis': '300px',
157
+ '--pf-v6-c-drawer__panel--md--FlexBasis--min': '150px',
158
+ '--pf-v6-c-drawer__panel--md--FlexBasis--max': '500px'
159
+ });
160
+ });
@@ -3,7 +3,7 @@ import progressStyle from '@patternfly/react-styles/css/components/Progress/prog
3
3
  import { css } from '@patternfly/react-styles';
4
4
  import { Tooltip, TooltipPosition } from '../Tooltip';
5
5
  import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle-icon';
6
- import TimesCircleIcon from '@patternfly/react-icons/dist/esm/icons/times-circle-icon';
6
+ import ExclamationCircleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon';
7
7
  import ExclamationTriangleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon';
8
8
  import { AriaProps, ProgressBar } from './ProgressBar';
9
9
  import { ProgressHelperText } from './ProgressHelperText';
@@ -61,7 +61,7 @@ export interface ProgressContainerProps extends Omit<React.HTMLProps<HTMLDivElem
61
61
  }
62
62
 
63
63
  const variantToIcon = {
64
- danger: TimesCircleIcon,
64
+ danger: ExclamationCircleIcon,
65
65
  success: CheckCircleIcon,
66
66
  warning: ExclamationTriangleIcon
67
67
  };
@@ -31,7 +31,7 @@ exports[`ProgressContainer should match snapshot (auto-generated) 1`] = `
31
31
  width="1em"
32
32
  >
33
33
  <path
34
- d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z"
34
+ d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
35
35
  />
36
36
  </svg>
37
37
  </span>
@@ -298,7 +298,7 @@ exports[`Progress variant danger 1`] = `
298
298
  width="1em"
299
299
  >
300
300
  <path
301
- d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z"
301
+ d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
302
302
  />
303
303
  </svg>
304
304
  </span>
@@ -3,6 +3,7 @@ import styles from '@patternfly/react-styles/css/components/Radio/radio';
3
3
  import { css } from '@patternfly/react-styles';
4
4
  import { PickOptional } from '../../helpers/typeUtils';
5
5
  import { getOUIAProps, OUIAProps, getDefaultOUIAId } from '../../helpers';
6
+ import { getUniqueId } from '../../helpers/util';
6
7
 
7
8
  export interface RadioProps
8
9
  extends Omit<React.HTMLProps<HTMLInputElement>, 'disabled' | 'label' | 'onChange' | 'type'>,
@@ -39,6 +40,8 @@ export interface RadioProps
39
40
  description?: React.ReactNode;
40
41
  /** Body of the radio. */
41
42
  body?: React.ReactNode;
43
+ /** Custom aria-describedby value for the radio input. If not provided and description is set, a unique ID will be generated automatically. */
44
+ 'aria-describedby'?: string;
42
45
  /** Sets the radio wrapper component to render. Defaults to "div". If set to "label", behaves the same as if isLabelWrapped prop was specified. */
43
46
  component?: React.ElementType;
44
47
  /** Value to overwrite the randomly generated data-ouia-component-id.*/
@@ -47,7 +50,7 @@ export interface RadioProps
47
50
  ouiaSafe?: boolean;
48
51
  }
49
52
 
50
- class Radio extends Component<RadioProps, { ouiaStateId: string }> {
53
+ class Radio extends Component<RadioProps, { ouiaStateId: string; descriptionId: string }> {
51
54
  static displayName = 'Radio';
52
55
  static defaultProps: PickOptional<RadioProps> = {
53
56
  className: '',
@@ -63,7 +66,8 @@ class Radio extends Component<RadioProps, { ouiaStateId: string }> {
63
66
  console.error('Radio:', 'Radio requires an aria-label to be specified');
64
67
  }
65
68
  this.state = {
66
- ouiaStateId: getDefaultOUIAId(Radio.displayName)
69
+ ouiaStateId: getDefaultOUIAId(Radio.displayName),
70
+ descriptionId: getUniqueId('pf-radio-description')
67
71
  };
68
72
  }
69
73
 
@@ -74,6 +78,7 @@ class Radio extends Component<RadioProps, { ouiaStateId: string }> {
74
78
  render() {
75
79
  const {
76
80
  'aria-label': ariaLabel,
81
+ 'aria-describedby': ariaDescribedBy,
77
82
  checked,
78
83
  className,
79
84
  inputClassName,
@@ -98,6 +103,14 @@ class Radio extends Component<RadioProps, { ouiaStateId: string }> {
98
103
  console.error('Radio:', 'id is required to make input accessible');
99
104
  }
100
105
 
106
+ // Handle aria-describedby logic
107
+ let ariaDescribedByValue: string | undefined;
108
+ if (ariaDescribedBy !== undefined) {
109
+ ariaDescribedByValue = ariaDescribedBy === '' ? undefined : ariaDescribedBy;
110
+ } else if (description) {
111
+ ariaDescribedByValue = this.state.descriptionId;
112
+ }
113
+
101
114
  const inputRendered = (
102
115
  <input
103
116
  {...props}
@@ -105,6 +118,7 @@ class Radio extends Component<RadioProps, { ouiaStateId: string }> {
105
118
  type="radio"
106
119
  onChange={this.handleChange}
107
120
  aria-invalid={!isValid}
121
+ aria-describedby={ariaDescribedByValue}
108
122
  disabled={isDisabled}
109
123
  checked={checked || isChecked}
110
124
  {...(checked === undefined && { defaultChecked })}
@@ -143,7 +157,11 @@ class Radio extends Component<RadioProps, { ouiaStateId: string }> {
143
157
  {labelRendered}
144
158
  </>
145
159
  )}
146
- {description && <span className={css(styles.radioDescription)}>{description}</span>}
160
+ {description && (
161
+ <span id={this.state.descriptionId} className={css(styles.radioDescription)}>
162
+ {description}
163
+ </span>
164
+ )}
147
165
  {body && <span className={css(styles.radioBody)}>{body}</span>}
148
166
  </Component>
149
167
  );
@@ -139,4 +139,48 @@ describe('Radio', () => {
139
139
  expect(wrapper.children[0].tagName).toBe('LABEL');
140
140
  expect(wrapper.children[1].tagName).toBe('INPUT');
141
141
  });
142
+
143
+ test('Sets aria-describedby when description is provided', () => {
144
+ render(<Radio id="test-id" name="check" aria-label="test radio" description="test description" />);
145
+
146
+ const radio = screen.getByRole('radio');
147
+ const descriptionElement = screen.getByText('test description');
148
+
149
+ expect(radio).toHaveAttribute('aria-describedby', descriptionElement.id);
150
+ expect(descriptionElement).toHaveAttribute('id');
151
+ });
152
+
153
+ test('Sets custom aria-describedby when provided', () => {
154
+ render(
155
+ <Radio
156
+ id="test-id"
157
+ name="check"
158
+ aria-label="test radio"
159
+ description="test description"
160
+ aria-describedby="custom-id"
161
+ />
162
+ );
163
+
164
+ const radio = screen.getByRole('radio');
165
+
166
+ expect(radio).toHaveAttribute('aria-describedby', 'custom-id');
167
+ });
168
+
169
+ test('Does not set aria-describedby when no description is provided', () => {
170
+ render(<Radio id="test-id" name="check" aria-label="test radio" />);
171
+
172
+ const radio = screen.getByRole('radio');
173
+
174
+ expect(radio).not.toHaveAttribute('aria-describedby');
175
+ });
176
+
177
+ test('Does not set aria-describedby when description is provided but aria-describedby is empty string', () => {
178
+ render(
179
+ <Radio id="test-id" name="check" aria-label="test radio" description="test description" aria-describedby="" />
180
+ );
181
+
182
+ const radio = screen.getByRole('radio');
183
+
184
+ expect(radio).not.toHaveAttribute('aria-describedby');
185
+ });
142
186
  });
@@ -1,15 +1,83 @@
1
1
  import { render, screen, act } from '@testing-library/react';
2
2
  import userEvent from '@testing-library/user-event';
3
- import { Tabs } from '../Tabs';
3
+ import { Tabs, TabsProps } from '../Tabs';
4
4
  import styles from '@patternfly/react-styles/css/components/Tabs/tabs';
5
5
  import { Tab } from '../Tab';
6
6
  import { TabTitleText } from '../TabTitleText';
7
7
  import { TabTitleIcon } from '../TabTitleIcon';
8
8
  import { TabContent } from '../TabContent';
9
9
  import { TabContentBody } from '../TabContentBody';
10
+ import { createRef } from 'react';
10
11
 
11
12
  jest.mock('../../../helpers/GenerateId/GenerateId');
12
13
 
14
+ const renderSeparateTabs = (props?: Pick<TabsProps, 'activeKey' | 'defaultActiveKey'>) => {
15
+ const contentRef1 = createRef<HTMLElement>();
16
+ const contentRef2 = createRef<HTMLElement>();
17
+ const contentRef3 = createRef<HTMLElement>();
18
+
19
+ let calculatedActiveKey;
20
+ if (props?.defaultActiveKey) {
21
+ calculatedActiveKey = props?.defaultActiveKey;
22
+ } else {
23
+ calculatedActiveKey = props?.activeKey;
24
+ }
25
+
26
+ return (
27
+ <>
28
+ <Tabs id="separateTabs" {...props}>
29
+ <Tab
30
+ eventKey={0}
31
+ title={<TabTitleText>Tab item 1</TabTitleText>}
32
+ tabContentId="refTab1Section"
33
+ tabContentRef={contentRef1}
34
+ />
35
+ <Tab
36
+ eventKey={1}
37
+ title={<TabTitleText>Tab item 2</TabTitleText>}
38
+ tabContentId="refTab2Section"
39
+ tabContentRef={contentRef2}
40
+ />
41
+ <Tab
42
+ eventKey={2}
43
+ title={<TabTitleText>Tab item 3</TabTitleText>}
44
+ tabContentId="refTab3Section"
45
+ tabContentRef={contentRef3}
46
+ />
47
+ </Tabs>
48
+ <div>
49
+ <TabContent
50
+ eventKey={0}
51
+ id="refTab1Section"
52
+ ref={contentRef1}
53
+ aria-label="Tab item 1"
54
+ hidden={calculatedActiveKey !== 0}
55
+ >
56
+ Tab 1 section
57
+ </TabContent>
58
+ <TabContent
59
+ eventKey={1}
60
+ id="refTab2Section"
61
+ ref={contentRef2}
62
+ aria-label="Tab item 2"
63
+ hidden={calculatedActiveKey !== 1}
64
+ >
65
+ <TabContentBody>Tab 2 section</TabContentBody>
66
+ </TabContent>
67
+ <TabContent
68
+ eventKey={2}
69
+ id="refTab3Section"
70
+ ref={contentRef3}
71
+ aria-label="Tab item 3"
72
+ hidden={calculatedActiveKey !== 2}
73
+ >
74
+ <TabContentBody hasPadding>Tab 3 section with padding </TabContentBody>
75
+ </TabContent>
76
+ </div>
77
+ </>
78
+ );
79
+ };
80
+
13
81
  test(`Renders with classes ${styles.tabs} and ${styles.modifiers.animateCurrent} by default`, () => {
14
82
  render(
15
83
  <Tabs role="region">
@@ -429,6 +497,46 @@ test('should render tabs with separate content', () => {
429
497
  expect(asFragment()).toMatchSnapshot();
430
498
  });
431
499
 
500
+ test('should render correct tab content for uncontrolled tabs with separate content', () => {
501
+ render(renderSeparateTabs({ defaultActiveKey: 1 }));
502
+
503
+ expect(screen.getByText(/Tab 1 section/i)).not.toBeVisible();
504
+ expect(screen.getByText(/Tab 2 section/i)).toBeVisible();
505
+ expect(screen.getByText(/Tab 3 section with padding/i)).not.toBeVisible();
506
+ });
507
+
508
+ test('should correctly advance tab content for uncontrolled tabs with separate content', async () => {
509
+ render(renderSeparateTabs({ defaultActiveKey: 1 }));
510
+
511
+ userEvent.setup();
512
+ expect(screen.getByText(/Tab 1 section/i)).not.toBeVisible();
513
+ expect(screen.getByText(/Tab 2 section/i)).toBeVisible();
514
+ expect(screen.getByText(/Tab 3 section with padding/i)).not.toBeVisible();
515
+ await userEvent.click(screen.getByRole('tab', { name: /Tab item 1/i }));
516
+ expect(screen.getByText(/Tab 1 section/i)).toBeVisible();
517
+ expect(screen.getByText(/Tab 2 section/i)).not.toBeVisible();
518
+ });
519
+
520
+ test('should render correct tab content for controlled tabs with separate content', () => {
521
+ render(renderSeparateTabs({ activeKey: 1 }));
522
+
523
+ expect(screen.getByText(/Tab 1 section/i)).not.toBeVisible();
524
+ expect(screen.getByText(/Tab 2 section/i)).toBeVisible();
525
+ expect(screen.getByText(/Tab 3 section with padding/i)).not.toBeVisible();
526
+ });
527
+
528
+ test('should correctly advance tab content for controlled tabs with separate content', async () => {
529
+ render(renderSeparateTabs({ activeKey: 1 }));
530
+
531
+ userEvent.setup();
532
+ expect(screen.getByText(/Tab 1 section/i)).not.toBeVisible();
533
+ expect(screen.getByText(/Tab 2 section/i)).toBeVisible();
534
+ expect(screen.getByText(/Tab 3 section with padding/i)).not.toBeVisible();
535
+ await userEvent.click(screen.getByRole('tab', { name: /Tab item 1/i }));
536
+ expect(screen.getByText(/Tab 1 section/i)).toBeVisible();
537
+ expect(screen.getByText(/Tab 2 section/i)).not.toBeVisible();
538
+ });
539
+
432
540
  test('should render box tabs of secondary variant', () => {
433
541
  const { asFragment } = render(
434
542
  <Tabs id="boxSecondaryVariantTabs" isBox variant="secondary">
@@ -281,7 +281,7 @@ exports[`should render box tabs of secondary variant 1`] = `
281
281
  <DocumentFragment>
282
282
  <div
283
283
  class="pf-v6-c-tabs pf-m-animate-current pf-m-box pf-m-secondary pf-m-initializing-accent"
284
- data-ouia-component-id="OUIA-Generated-Tabs-20"
284
+ data-ouia-component-id="OUIA-Generated-Tabs-24"
285
285
  data-ouia-component-type="PF6/Tabs"
286
286
  data-ouia-safe="true"
287
287
  id="boxSecondaryVariantTabs"
@@ -1228,7 +1228,7 @@ exports[`should render tabs with no bottom border 1`] = `
1228
1228
  <DocumentFragment>
1229
1229
  <div
1230
1230
  class="pf-v6-c-tabs pf-m-animate-current pf-m-no-border-bottom pf-m-initializing-accent"
1231
- data-ouia-component-id="OUIA-Generated-Tabs-21"
1231
+ data-ouia-component-id="OUIA-Generated-Tabs-25"
1232
1232
  data-ouia-component-type="PF6/Tabs"
1233
1233
  data-ouia-safe="true"
1234
1234
  id="noBottomBorderTabs"