@patternfly/react-core 6.3.0-prerelease.21 → 6.3.0-prerelease.23

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 (190) hide show
  1. package/CHANGELOG.md +12 -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/FocusTrap/FocusTrap/package.json +1 -1
  91. package/dist/dynamic/helpers/GenerateId/GenerateId/package.json +1 -1
  92. package/dist/dynamic/helpers/KeyboardHandler/package.json +1 -1
  93. package/dist/dynamic/helpers/OUIA/ouia/package.json +1 -1
  94. package/dist/dynamic/helpers/Popper/Popper/package.json +1 -1
  95. package/dist/dynamic/helpers/constants/package.json +1 -1
  96. package/dist/dynamic/helpers/datetimeUtils/package.json +1 -1
  97. package/dist/dynamic/helpers/fileUtils/package.json +1 -1
  98. package/dist/dynamic/helpers/htmlConstants/package.json +1 -1
  99. package/dist/dynamic/helpers/package.json +1 -1
  100. package/dist/dynamic/helpers/resizeObserver/package.json +1 -1
  101. package/dist/dynamic/helpers/typeUtils/package.json +1 -1
  102. package/dist/dynamic/helpers/useInterval/package.json +1 -1
  103. package/dist/dynamic/helpers/useIsomorphicLayout/package.json +1 -1
  104. package/dist/dynamic/helpers/useUnmountEffect/package.json +1 -1
  105. package/dist/dynamic/helpers/util/package.json +1 -1
  106. package/dist/dynamic/layouts/Bullseye/package.json +1 -1
  107. package/dist/dynamic/layouts/Flex/package.json +1 -1
  108. package/dist/dynamic/layouts/Gallery/package.json +1 -1
  109. package/dist/dynamic/layouts/Grid/package.json +1 -1
  110. package/dist/dynamic/layouts/Level/package.json +1 -1
  111. package/dist/dynamic/layouts/Split/package.json +1 -1
  112. package/dist/dynamic/layouts/Stack/package.json +1 -1
  113. package/dist/dynamic/styles/package.json +1 -1
  114. package/dist/esm/components/Button/hamburgerIcon.js +1 -1
  115. package/dist/esm/components/Button/hamburgerIcon.js.map +1 -1
  116. package/dist/esm/components/ExpandableSection/ExpandableSection.d.ts +5 -1
  117. package/dist/esm/components/ExpandableSection/ExpandableSection.d.ts.map +1 -1
  118. package/dist/esm/components/ExpandableSection/ExpandableSection.js +6 -2
  119. package/dist/esm/components/ExpandableSection/ExpandableSection.js.map +1 -1
  120. package/dist/esm/components/ExpandableSection/ExpandableSectionToggle.d.ts +2 -0
  121. package/dist/esm/components/ExpandableSection/ExpandableSectionToggle.d.ts.map +1 -1
  122. package/dist/esm/components/ExpandableSection/ExpandableSectionToggle.js +4 -3
  123. package/dist/esm/components/ExpandableSection/ExpandableSectionToggle.js.map +1 -1
  124. package/dist/esm/components/TreeView/TreeView.d.ts +5 -0
  125. package/dist/esm/components/TreeView/TreeView.d.ts.map +1 -1
  126. package/dist/esm/components/TreeView/TreeView.js +5 -5
  127. package/dist/esm/components/TreeView/TreeView.js.map +1 -1
  128. package/dist/esm/components/TreeView/TreeViewListItem.d.ts +5 -0
  129. package/dist/esm/components/TreeView/TreeViewListItem.d.ts.map +1 -1
  130. package/dist/esm/components/TreeView/TreeViewListItem.js +7 -3
  131. package/dist/esm/components/TreeView/TreeViewListItem.js.map +1 -1
  132. package/dist/esm/components/TreeView/TreeViewRoot.d.ts.map +1 -1
  133. package/dist/esm/components/TreeView/TreeViewRoot.js +2 -2
  134. package/dist/esm/components/TreeView/TreeViewRoot.js.map +1 -1
  135. package/dist/js/components/Button/hamburgerIcon.js +1 -1
  136. package/dist/js/components/Button/hamburgerIcon.js.map +1 -1
  137. package/dist/js/components/ExpandableSection/ExpandableSection.d.ts +5 -1
  138. package/dist/js/components/ExpandableSection/ExpandableSection.d.ts.map +1 -1
  139. package/dist/js/components/ExpandableSection/ExpandableSection.js +6 -2
  140. package/dist/js/components/ExpandableSection/ExpandableSection.js.map +1 -1
  141. package/dist/js/components/ExpandableSection/ExpandableSectionToggle.d.ts +2 -0
  142. package/dist/js/components/ExpandableSection/ExpandableSectionToggle.d.ts.map +1 -1
  143. package/dist/js/components/ExpandableSection/ExpandableSectionToggle.js +4 -3
  144. package/dist/js/components/ExpandableSection/ExpandableSectionToggle.js.map +1 -1
  145. package/dist/js/components/TreeView/TreeView.d.ts +5 -0
  146. package/dist/js/components/TreeView/TreeView.d.ts.map +1 -1
  147. package/dist/js/components/TreeView/TreeView.js +5 -5
  148. package/dist/js/components/TreeView/TreeView.js.map +1 -1
  149. package/dist/js/components/TreeView/TreeViewListItem.d.ts +5 -0
  150. package/dist/js/components/TreeView/TreeViewListItem.d.ts.map +1 -1
  151. package/dist/js/components/TreeView/TreeViewListItem.js +6 -2
  152. package/dist/js/components/TreeView/TreeViewListItem.js.map +1 -1
  153. package/dist/js/components/TreeView/TreeViewRoot.d.ts.map +1 -1
  154. package/dist/js/components/TreeView/TreeViewRoot.js +2 -2
  155. package/dist/js/components/TreeView/TreeViewRoot.js.map +1 -1
  156. package/dist/umd/assets/{output-BDZoYci_.css → output-ftXPKR0C.css} +15450 -15319
  157. package/dist/umd/react-core.min.js +1 -1
  158. package/helpers/package.json +1 -1
  159. package/layouts/package.json +1 -1
  160. package/next/package.json +1 -1
  161. package/package.json +6 -6
  162. package/src/components/Button/hamburgerIcon.tsx +1 -1
  163. package/src/components/ExpandableSection/ExpandableSection.tsx +13 -1
  164. package/src/components/ExpandableSection/ExpandableSectionToggle.tsx +5 -1
  165. package/src/components/ExpandableSection/__tests__/ExpandableSection.test.tsx +85 -23
  166. package/src/components/ExpandableSection/__tests__/ExpandableSectionToggle.test.tsx +32 -0
  167. package/src/components/ExpandableSection/__tests__/__snapshots__/ExpandableSection.test.tsx.snap +1 -63
  168. package/src/components/ExpandableSection/examples/ExpandableSection.md +2 -0
  169. package/src/components/ExpandableSection/examples/ExpandableSectionDetached.tsx +1 -1
  170. package/src/components/TreeView/TreeView.tsx +9 -0
  171. package/src/components/TreeView/TreeViewListItem.tsx +17 -2
  172. package/src/components/TreeView/TreeViewRoot.tsx +4 -2
  173. package/src/components/TreeView/__tests__/TreeView.test.tsx +8 -1
  174. package/src/components/TreeView/__tests__/TreeViewList.test.tsx +39 -0
  175. package/src/components/TreeView/__tests__/TreeViewListItem.test.tsx +7 -3
  176. package/src/components/TreeView/__tests__/__snapshots__/TreeView.test.tsx.snap +3 -0
  177. package/src/components/TreeView/examples/TreeViewCompact.tsx +1 -1
  178. package/src/components/TreeView/examples/TreeViewCompactNoBackground.tsx +8 -1
  179. package/src/components/TreeView/examples/TreeViewGuides.tsx +1 -1
  180. package/src/components/TreeView/examples/TreeViewMultiselectable.tsx +1 -0
  181. package/src/components/TreeView/examples/TreeViewSelectionExpansion.tsx +1 -0
  182. package/src/components/TreeView/examples/TreeViewSingleSelectable.tsx +1 -0
  183. package/src/components/TreeView/examples/TreeViewWithActionItems.tsx +1 -0
  184. package/src/components/TreeView/examples/TreeViewWithBadges.tsx +1 -0
  185. package/src/components/TreeView/examples/TreeViewWithCheckboxes.tsx +9 -1
  186. package/src/components/TreeView/examples/TreeViewWithCustomBadges.tsx +1 -0
  187. package/src/components/TreeView/examples/TreeViewWithIconPerItem.tsx +1 -0
  188. package/src/components/TreeView/examples/TreeViewWithIcons.tsx +1 -0
  189. package/src/components/TreeView/examples/TreeViewWithMemoization.tsx +1 -0
  190. package/src/components/TreeView/examples/TreeViewWithSearch.tsx +1 -0
@@ -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.3.0-prerelease.20","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.3.0-prerelease.22","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.3.0-prerelease.20","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.3.0-prerelease.22","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.3.0-prerelease.20","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.3.0-prerelease.22","private":true}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/react-core",
3
- "version": "6.3.0-prerelease.21",
3
+ "version": "6.3.0-prerelease.23",
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,15 +46,15 @@
46
46
  "subpaths": "node ../../scripts/exportSubpaths.mjs --config subpaths.config.json"
47
47
  },
48
48
  "dependencies": {
49
- "@patternfly/react-icons": "^6.3.0-prerelease.6",
50
- "@patternfly/react-styles": "^6.3.0-prerelease.6",
51
- "@patternfly/react-tokens": "^6.3.0-prerelease.6",
49
+ "@patternfly/react-icons": "^6.3.0-prerelease.7",
50
+ "@patternfly/react-styles": "^6.3.0-prerelease.7",
51
+ "@patternfly/react-tokens": "^6.3.0-prerelease.7",
52
52
  "focus-trap": "7.6.4",
53
53
  "react-dropzone": "^14.3.5",
54
54
  "tslib": "^2.8.1"
55
55
  },
56
56
  "devDependencies": {
57
- "@patternfly/patternfly": "6.3.0-prerelease.29",
57
+ "@patternfly/patternfly": "6.3.0-prerelease.33",
58
58
  "case-anything": "^3.1.2",
59
59
  "css": "^3.0.0",
60
60
  "fs-extra": "^11.3.0"
@@ -63,5 +63,5 @@
63
63
  "react": "^17 || ^18 || ^19",
64
64
  "react-dom": "^17 || ^18 || ^19"
65
65
  },
66
- "gitHead": "c40f2f81ebe65b6bd785bc38da66330532ac7a30"
66
+ "gitHead": "96fdb620440615b569e4a95c570e46dc24bfa079"
67
67
  }
@@ -4,7 +4,7 @@ import { css } from '@patternfly/react-styles';
4
4
  // Because this is such a specific icon that requires being wrapped in a pf-v[current version]-c-button element,
5
5
  // we don't want to export this to consumers nor include it in the react-icons package as a custom icon.
6
6
  export const hamburgerIcon = (
7
- <svg viewBox="0 0 10 10" className="pf-v6-c-button--hamburger-icon pf-v6-svg" width="1em" height="1em">
7
+ <svg viewBox="0 0 10 10" className={css(styles.buttonHamburgerIcon, 'pf-v6-svg')} width="1em" height="1em">
8
8
  <path className={css(styles.buttonHamburgerIconTop)} d="M1,1 L9,1"></path>
9
9
  <path className={css(styles.buttonHamburgerIconMiddle)} d="M1,5 L9,5"></path>
10
10
  <path className={css(styles.buttonHamburgerIconArrow)} d="M1,5 L1,5 L1,5"></path>
@@ -32,7 +32,7 @@ export interface ExpandableSectionProps extends Omit<React.HTMLProps<HTMLDivElem
32
32
  toggleId?: string;
33
33
  /** Display size variant. Set to "lg" for disclosure styling. */
34
34
  displaySize?: 'default' | 'lg';
35
- /** Indicates the expandable section has a detached toggle. */
35
+ /** Flag indicating that the expandable section and expandable toggle are detached from one another. */
36
36
  isDetached?: boolean;
37
37
  /** Flag to indicate if the content is expanded. */
38
38
  isExpanded?: boolean;
@@ -64,6 +64,10 @@ export interface ExpandableSectionProps extends Omit<React.HTMLProps<HTMLDivElem
64
64
  * variant, the expandable content will be truncated after 3 lines by default.
65
65
  */
66
66
  variant?: 'default' | 'truncate';
67
+ /** Sets the direction of the expandable animation when isDetached is true. If this prop is not passed,
68
+ * animation will not occur.
69
+ */
70
+ direction?: 'up' | 'down';
67
71
  }
68
72
 
69
73
  interface ExpandableSectionState {
@@ -72,6 +76,11 @@ interface ExpandableSectionState {
72
76
  previousWidth: number;
73
77
  }
74
78
 
79
+ const directionClassMap = {
80
+ up: styles.modifiers.expandTop,
81
+ down: styles.modifiers.expandBottom
82
+ };
83
+
75
84
  const setLineClamp = (lines: number, element: HTMLDivElement) => {
76
85
  if (!element || lines < 1) {
77
86
  return;
@@ -198,6 +207,7 @@ class ExpandableSection extends Component<ExpandableSectionProps, ExpandableSect
198
207
  variant,
199
208
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
200
209
  truncateMaxLines,
210
+ direction,
201
211
  ...props
202
212
  } = this.props;
203
213
 
@@ -258,6 +268,8 @@ class ExpandableSection extends Component<ExpandableSectionProps, ExpandableSect
258
268
  displaySize === 'lg' && styles.modifiers.displayLg,
259
269
  isWidthLimited && styles.modifiers.limitWidth,
260
270
  isIndented && styles.modifiers.indented,
271
+ isDetached && direction && directionClassMap[direction],
272
+ isDetached && direction && 'pf-m-detached',
261
273
  variant === ExpandableSectionVariant.truncate && styles.modifiers.truncate,
262
274
  className
263
275
  )}
@@ -28,6 +28,8 @@ export interface ExpandableSectionToggleProps extends Omit<React.HTMLProps<HTMLD
28
28
  isExpanded?: boolean;
29
29
  /** Callback function to toggle the expandable content. */
30
30
  onToggle?: (isExpanded: boolean) => void;
31
+ /** Flag indicating that the expandable section and expandable toggle are detached from one another. */
32
+ isDetached?: boolean;
31
33
  }
32
34
 
33
35
  export const ExpandableSectionToggle: React.FunctionComponent<ExpandableSectionToggleProps> = ({
@@ -39,6 +41,7 @@ export const ExpandableSectionToggle: React.FunctionComponent<ExpandableSectionT
39
41
  toggleId,
40
42
  direction = 'down',
41
43
  hasTruncatedContent = false,
44
+ isDetached,
42
45
  ...props
43
46
  }: ExpandableSectionToggleProps) => (
44
47
  <div
@@ -46,6 +49,7 @@ export const ExpandableSectionToggle: React.FunctionComponent<ExpandableSectionT
46
49
  styles.expandableSection,
47
50
  isExpanded && styles.modifiers.expanded,
48
51
  hasTruncatedContent && styles.modifiers.truncate,
52
+ isDetached && 'pf-m-detached',
49
53
  className
50
54
  )}
51
55
  {...props}
@@ -63,7 +67,7 @@ export const ExpandableSectionToggle: React.FunctionComponent<ExpandableSectionT
63
67
  <span
64
68
  className={css(
65
69
  styles.expandableSectionToggleIcon,
66
- isExpanded && direction === 'up' && styles.modifiers.expandTop
70
+ isExpanded && direction === 'up' && styles.modifiers.expandTop // TODO: next breaking change move this class to the outer styles.expandableSection wrapper
67
71
  )}
68
72
  >
69
73
  <AngleRightIcon />
@@ -1,9 +1,8 @@
1
- import { Fragment } from 'react';
2
1
  import { render, screen } from '@testing-library/react';
3
2
  import userEvent from '@testing-library/user-event';
4
3
 
5
4
  import { ExpandableSection, ExpandableSectionVariant } from '../ExpandableSection';
6
- import { ExpandableSectionToggle } from '../ExpandableSectionToggle';
5
+ import styles from '@patternfly/react-styles/css/components/ExpandableSection/expandable-section';
7
6
 
8
7
  const props = { contentId: 'content-id', toggleId: 'toggle-id' };
9
8
 
@@ -22,7 +21,7 @@ test('Renders ExpandableSection expanded', () => {
22
21
  expect(asFragment()).toMatchSnapshot();
23
22
  });
24
23
 
25
- test('ExpandableSection onToggle called', async () => {
24
+ test('Calls onToggle when clicked', async () => {
26
25
  const mockfn = jest.fn();
27
26
  const user = userEvent.setup();
28
27
 
@@ -32,6 +31,21 @@ test('ExpandableSection onToggle called', async () => {
32
31
  expect(mockfn.mock.calls).toHaveLength(1);
33
32
  });
34
33
 
34
+ test('Does not call onToggle when not clicked', async () => {
35
+ const mockfn = jest.fn();
36
+ const user = userEvent.setup();
37
+
38
+ render(
39
+ <>
40
+ <ExpandableSection onToggle={mockfn}> test </ExpandableSection>
41
+ <button onClick={() => {}}>Test clicker</button>
42
+ </>
43
+ );
44
+
45
+ await user.click(screen.getByRole('button', { name: 'Test clicker' }));
46
+ expect(mockfn).not.toHaveBeenCalled();
47
+ });
48
+
35
49
  test('Renders Uncontrolled ExpandableSection', () => {
36
50
  const { asFragment } = render(
37
51
  <ExpandableSection {...props} toggleText="Show More">
@@ -42,20 +56,6 @@ test('Renders Uncontrolled ExpandableSection', () => {
42
56
  expect(asFragment()).toMatchSnapshot();
43
57
  });
44
58
 
45
- test('Detached ExpandableSection renders successfully', () => {
46
- const { asFragment } = render(
47
- <Fragment>
48
- <ExpandableSection isExpanded isDetached {...props}>
49
- test
50
- </ExpandableSection>
51
- <ExpandableSectionToggle isExpanded direction="up" {...props}>
52
- Toggle text
53
- </ExpandableSectionToggle>
54
- </Fragment>
55
- );
56
- expect(asFragment()).toMatchSnapshot();
57
- });
58
-
59
59
  test('Disclosure ExpandableSection', () => {
60
60
  const { asFragment } = render(
61
61
  <ExpandableSection {...props} displaySize="lg" isWidthLimited>
@@ -75,22 +75,22 @@ test('Renders ExpandableSection indented', () => {
75
75
  expect(asFragment()).toMatchSnapshot();
76
76
  });
77
77
 
78
- test('Does not render with pf-m-truncate class when variant is not passed', () => {
78
+ test(`Does not render with ${styles.modifiers.truncate} class when variant is not passed`, () => {
79
79
  render(<ExpandableSection>test</ExpandableSection>);
80
80
 
81
- expect(screen.getByText('test').parentElement).not.toHaveClass('pf-m-truncate');
81
+ expect(screen.getByText('test').parentElement).not.toHaveClass(styles.modifiers.truncate);
82
82
  });
83
83
 
84
- test('Does not render with pf-m-truncate class when variant is not truncate', () => {
84
+ test(`Does not render with ${styles.modifiers.truncate} class when variant is not truncate`, () => {
85
85
  render(<ExpandableSection variant={ExpandableSectionVariant.default}>test</ExpandableSection>);
86
86
 
87
- expect(screen.getByText('test').parentElement).not.toHaveClass('pf-m-truncate');
87
+ expect(screen.getByText('test').parentElement).not.toHaveClass(styles.modifiers.truncate);
88
88
  });
89
89
 
90
- test('Renders with pf-m-truncate class when variant is truncate', () => {
90
+ test(`Renders with ${styles.modifiers.truncate} class when variant is truncate`, () => {
91
91
  render(<ExpandableSection variant={ExpandableSectionVariant.truncate}>test</ExpandableSection>);
92
92
 
93
- expect(screen.getByText('test').parentElement).toHaveClass('pf-m-truncate');
93
+ expect(screen.getByText('test').parentElement).toHaveClass(styles.modifiers.truncate);
94
94
  });
95
95
 
96
96
  test('Renders with value passed to contentId', () => {
@@ -129,3 +129,65 @@ test('Renders with ARIA attributes when contentId and toggleId are passed', () =
129
129
  expect(wrapper).toContainHTML('aria-labelledby="toggle-id"');
130
130
  expect(wrapper).toContainHTML('aria-controls="content-id"');
131
131
  });
132
+
133
+ test(`Does not render with classes ${styles.modifiers.expandTop} nor ${styles.modifiers.expandBottom} by default`, () => {
134
+ render(<ExpandableSection>Test content</ExpandableSection>);
135
+
136
+ expect(screen.getByText('Test content').parentElement).not.toHaveClass('pf-m-expand-top');
137
+ expect(screen.getByText('Test content').parentElement).not.toHaveClass('pf-m-expand-bottom');
138
+ });
139
+
140
+ test(`Does not render with classes ${styles.modifiers.expandTop} nor ${styles.modifiers.expandBottom} when only isDetached is true`, () => {
141
+ render(<ExpandableSection isDetached>Test content</ExpandableSection>);
142
+
143
+ expect(screen.getByText('Test content').parentElement).not.toHaveClass('pf-m-expand-top');
144
+ expect(screen.getByText('Test content').parentElement).not.toHaveClass('pf-m-expand-bottom');
145
+ });
146
+
147
+ test(`Does not render with class ${styles.modifiers.expandTop} when direction="up" and isDetached is false`, () => {
148
+ render(<ExpandableSection direction="up">Test content</ExpandableSection>);
149
+
150
+ expect(screen.getByText('Test content').parentElement).not.toHaveClass('pf-m-expand-top');
151
+ });
152
+
153
+ test(`Does not render with class ${styles.modifiers.expandBottom} when direction="down" and isDetached is false`, () => {
154
+ render(<ExpandableSection direction="down">Test content</ExpandableSection>);
155
+
156
+ expect(screen.getByText('Test content').parentElement).not.toHaveClass('pf-m-expand-bottom');
157
+ });
158
+
159
+ test(`Renders with class ${styles.modifiers.expandTop} when isDetached is true and direction="up"`, () => {
160
+ render(
161
+ <ExpandableSection isDetached direction="up">
162
+ Test content
163
+ </ExpandableSection>
164
+ );
165
+
166
+ expect(screen.getByText('Test content').parentElement).toHaveClass('pf-m-expand-top');
167
+ });
168
+
169
+ test(`Renders with class ${styles.modifiers.expandBottom} when isDetached is true and direction="down"`, () => {
170
+ render(
171
+ <ExpandableSection isDetached direction="down">
172
+ Test content
173
+ </ExpandableSection>
174
+ );
175
+
176
+ expect(screen.getByText('Test content').parentElement).toHaveClass('pf-m-expand-bottom');
177
+ });
178
+
179
+ test('Does not render with class pf-m-detached when isDetached is true and direction is not passed', () => {
180
+ render(<ExpandableSection isDetached>Test content</ExpandableSection>);
181
+
182
+ expect(screen.getByText('Test content').parentElement).not.toHaveClass('pf-m-detached');
183
+ });
184
+
185
+ test('Renders with class pf-m-detached when isDetached is true and direction is passed', () => {
186
+ render(
187
+ <ExpandableSection isDetached direction="up">
188
+ Test content
189
+ </ExpandableSection>
190
+ );
191
+
192
+ expect(screen.getByText('Test content').parentElement).toHaveClass('pf-m-detached');
193
+ });
@@ -0,0 +1,32 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { ExpandableSectionToggle } from '../ExpandableSectionToggle';
4
+ import styles from '@patternfly/react-styles/css/components/ExpandableSection/expandable-section';
5
+
6
+ test('Renders without children', () => {
7
+ render(<ExpandableSectionToggle></ExpandableSectionToggle>);
8
+
9
+ expect(screen.getByRole('button')).toBeInTheDocument();
10
+ });
11
+
12
+ test('Renders with children', () => {
13
+ render(<ExpandableSectionToggle>Toggle test</ExpandableSectionToggle>);
14
+
15
+ expect(screen.getByRole('button')).toHaveTextContent('Toggle test');
16
+ });
17
+
18
+ test('Does not render with class pf-m-detached by default', () => {
19
+ render(<ExpandableSectionToggle data-testid="test-id">Toggle test</ExpandableSectionToggle>);
20
+
21
+ expect(screen.getByTestId('test-id')).not.toHaveClass('pf-m-detached');
22
+ });
23
+
24
+ test('Renders with class pf-m-detached when isDetached is true', () => {
25
+ render(
26
+ <ExpandableSectionToggle data-testid="test-id" isDetached>
27
+ Toggle test
28
+ </ExpandableSectionToggle>
29
+ );
30
+
31
+ expect(screen.getByTestId('test-id')).toHaveClass('pf-m-detached');
32
+ });
@@ -1,67 +1,5 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`Detached ExpandableSection renders successfully 1`] = `
4
- <DocumentFragment>
5
- <div
6
- class="pf-v6-c-expandable-section pf-m-expanded"
7
- >
8
- <div
9
- aria-labelledby="toggle-id"
10
- class="pf-v6-c-expandable-section__content"
11
- id="content-id"
12
- role="region"
13
- >
14
- test
15
- </div>
16
- </div>
17
- <div
18
- class="pf-v6-c-expandable-section pf-m-expanded"
19
- >
20
- <div
21
- class="pf-v6-c-expandable-section__toggle"
22
- >
23
- <button
24
- aria-controls="content-id"
25
- aria-expanded="true"
26
- class="pf-v6-c-button pf-m-link"
27
- data-ouia-component-id="OUIA-Generated-Button-link-5"
28
- data-ouia-component-type="PF6/Button"
29
- data-ouia-safe="true"
30
- id="toggle-id"
31
- type="button"
32
- >
33
- <span
34
- class="pf-v6-c-button__icon pf-m-start"
35
- >
36
- <span
37
- class="pf-v6-c-expandable-section__toggle-icon pf-m-expand-top"
38
- >
39
- <svg
40
- aria-hidden="true"
41
- class="pf-v6-svg"
42
- fill="currentColor"
43
- height="1em"
44
- role="img"
45
- viewBox="0 0 256 512"
46
- width="1em"
47
- >
48
- <path
49
- d="M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34z"
50
- />
51
- </svg>
52
- </span>
53
- </span>
54
- <span
55
- class="pf-v6-c-button__text"
56
- >
57
- Toggle text
58
- </span>
59
- </button>
60
- </div>
61
- </div>
62
- </DocumentFragment>
63
- `;
64
-
65
3
  exports[`Disclosure ExpandableSection 1`] = `
66
4
  <DocumentFragment>
67
5
  <div
@@ -285,7 +223,7 @@ exports[`Renders Uncontrolled ExpandableSection 1`] = `
285
223
  <button
286
224
  aria-controls="content-id"
287
225
  class="pf-v6-c-button pf-m-link"
288
- data-ouia-component-id="OUIA-Generated-Button-link-4"
226
+ data-ouia-component-id="OUIA-Generated-Button-link-5"
289
227
  data-ouia-component-type="PF6/Button"
290
228
  data-ouia-safe="true"
291
229
  id="toggle-id"
@@ -32,6 +32,8 @@ import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle
32
32
 
33
33
  When passing the `isDetached` property into `<ExpandableSection>`, you must also manually pass in the same `toggleId` and `contentId` properties to both `<ExpandableSection>` and `<ExpandableSectionToggle>`. This will link the content to the toggle via ARIA attributes.
34
34
 
35
+ By default animations will not be enabled for a detached `<ExpandableSection>`. You must manually pass the `direction` property with an appropriate value based on where the expandable content is rendered. If the expandable content is above the expandable toggle, `direction="up"` must be passed like in this example.
36
+
35
37
  ```ts file="ExpandableSectionDetached.tsx"
36
38
 
37
39
  ```
@@ -13,7 +13,7 @@ export const ExpandableSectionDetached: React.FunctionComponent = () => {
13
13
  return (
14
14
  <Stack hasGutter>
15
15
  <StackItem>
16
- <ExpandableSection isExpanded={isExpanded} isDetached toggleId={toggleId} contentId={contentId}>
16
+ <ExpandableSection isExpanded={isExpanded} isDetached direction="up" toggleId={toggleId} contentId={contentId}>
17
17
  This content is visible only when the component is expanded.
18
18
  </ExpandableSection>
19
19
  </StackItem>
@@ -103,6 +103,11 @@ export interface TreeViewProps {
103
103
  useMemo?: boolean;
104
104
  /** Variant presentation styles for the tree view. */
105
105
  variant?: 'default' | 'compact' | 'compactNoBackground';
106
+ /** Flag indicating whether a tree view has animations. This will always render
107
+ * nested tree view items rather than dynamically rendering them. This prop will be removed in
108
+ * the next breaking change release in favor of defaulting to always-rendered items.
109
+ */
110
+ hasAnimations?: boolean;
106
111
  }
107
112
 
108
113
  export const TreeView: React.FunctionComponent<TreeViewProps> = ({
@@ -130,6 +135,7 @@ export const TreeView: React.FunctionComponent<TreeViewProps> = ({
130
135
  useMemo,
131
136
  'aria-label': ariaLabel,
132
137
  'aria-labelledby': ariaLabelledby,
138
+ hasAnimations,
133
139
  ...props
134
140
  }: TreeViewProps) => {
135
141
  const treeViewList = (
@@ -139,11 +145,13 @@ export const TreeView: React.FunctionComponent<TreeViewProps> = ({
139
145
  isMultiSelectable={isMultiSelectable}
140
146
  aria-label={ariaLabel}
141
147
  aria-labelledby={ariaLabelledby}
148
+ {...props}
142
149
  >
143
150
  {data.map((item) => (
144
151
  <TreeViewListItem
145
152
  key={item.id?.toString() || item.name?.toString()}
146
153
  name={item.name}
154
+ hasAnimations={hasAnimations}
147
155
  title={item.title}
148
156
  id={item.id}
149
157
  isExpanded={allExpanded}
@@ -172,6 +180,7 @@ export const TreeView: React.FunctionComponent<TreeViewProps> = ({
172
180
  <TreeView
173
181
  data={item.children}
174
182
  isNested
183
+ hasAnimations={hasAnimations}
175
184
  parentItem={item}
176
185
  hasCheckboxes={hasCheckboxes}
177
186
  hasBadges={hasBadges}
@@ -1,4 +1,4 @@
1
- import { memo, useState, useEffect } from 'react';
1
+ import { memo, useState, useEffect, Children, isValidElement, cloneElement } from 'react';
2
2
  import { css } from '@patternfly/react-styles';
3
3
  import styles from '@patternfly/react-styles/css/components/TreeView/tree-view';
4
4
  import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon';
@@ -68,6 +68,11 @@ export interface TreeViewListItemProps {
68
68
  * every node in the selected item's path.
69
69
  */
70
70
  useMemo?: boolean;
71
+ /** Flag indicating whether a tree view has animations. This will always render
72
+ * nested tree view items rather than dynamically rendering them. This prop will be removed in
73
+ * the next breaking change release in favor of defaulting to always-rendered items.
74
+ */
75
+ hasAnimations?: boolean;
71
76
  }
72
77
 
73
78
  const TreeViewListItemBase: React.FunctionComponent<TreeViewListItemProps> = ({
@@ -97,6 +102,7 @@ const TreeViewListItemBase: React.FunctionComponent<TreeViewListItemProps> = ({
97
102
  expandedIcon,
98
103
  action,
99
104
  compareItems,
105
+ hasAnimations,
100
106
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
101
107
  useMemo
102
108
  }: TreeViewListItemProps) => {
@@ -203,6 +209,15 @@ const TreeViewListItemBase: React.FunctionComponent<TreeViewListItemProps> = ({
203
209
  activeItems.length > 0 &&
204
210
  activeItems.some((item) => compareItems && item && compareItems(item, itemData));
205
211
 
212
+ const clonedChildren = Children.map(
213
+ children,
214
+ (child) =>
215
+ isValidElement(child) &&
216
+ cloneElement(child as React.ReactElement<any>, {
217
+ inert: internalIsExpanded ? undefined : ''
218
+ })
219
+ );
220
+
206
221
  return (
207
222
  <li
208
223
  id={id}
@@ -247,7 +262,7 @@ const TreeViewListItemBase: React.FunctionComponent<TreeViewListItemProps> = ({
247
262
  </GenerateId>
248
263
  {action && <div className={css(styles.treeViewAction)}>{action}</div>}
249
264
  </div>
250
- {internalIsExpanded && children}
265
+ {(internalIsExpanded || hasAnimations) && clonedChildren}
251
266
  </li>
252
267
  );
253
268
  };
@@ -72,7 +72,7 @@ class TreeViewRoot extends Component<TreeViewRootProps> {
72
72
  const activeElement = document.activeElement;
73
73
  const key = event.key;
74
74
  const treeItems = Array.from(this.treeRef.current?.getElementsByClassName(styles.treeViewNode)).filter(
75
- (el) => !el.classList.contains('pf-m-disabled')
75
+ (el) => !el.classList.contains('pf-m-disabled') && !el.closest(`.${styles.treeViewList}[inert]`)
76
76
  );
77
77
 
78
78
  if (key === KeyTypes.Space) {
@@ -138,7 +138,9 @@ class TreeViewRoot extends Component<TreeViewRootProps> {
138
138
  event.preventDefault();
139
139
  }
140
140
 
141
- const treeNodes = Array.from(this.treeRef.current?.getElementsByClassName(styles.treeViewNode));
141
+ const treeNodes = Array.from(this.treeRef.current?.getElementsByClassName(styles.treeViewNode)).filter(
142
+ (el) => !el.closest(`.${styles.treeViewList}[inert]`)
143
+ );
142
144
 
143
145
  handleArrows(
144
146
  event,
@@ -47,7 +47,8 @@ jest.mock('../TreeViewListItem', () => ({
47
47
  onCollapse,
48
48
  parentItem,
49
49
  title,
50
- useMemo
50
+ useMemo,
51
+ hasAnimations
51
52
  }) => (
52
53
  <div data-testid="TreeViewListItem-mock">
53
54
  <p>{`TreeViewListItem action: ${action}`}</p>
@@ -69,6 +70,7 @@ jest.mock('../TreeViewListItem', () => ({
69
70
  <p>{`TreeViewListItem parentItem: ${parentItem?.name}`}</p>
70
71
  <p>{`TreeViewListItem title: ${title}`}</p>
71
72
  <p>{`TreeViewListItem useMemo: ${useMemo}`}</p>
73
+ <p>{`TreeViewListItem hasAnimations: ${hasAnimations}`}</p>
72
74
  <button onClick={compareItems}>compareItems clicker</button>
73
75
  <button onClick={onCheck}>onCheck clicker</button>
74
76
  <button onClick={onSelect}>onSelect clicker</button>
@@ -286,6 +288,11 @@ test('Passes useMemo to TreeViewListItem', () => {
286
288
 
287
289
  expect(screen.getByText('TreeViewListItem useMemo: true')).toBeVisible();
288
290
  });
291
+ test('Passes hasAnimations to TreeViewListItem', () => {
292
+ render(<TreeView data={[basicData]} hasAnimations={true} />);
293
+
294
+ expect(screen.getByText('TreeViewListItem hasAnimations: true')).toBeVisible();
295
+ });
289
296
  test('Passes data.children to TreeViewListItem', () => {
290
297
  render(<TreeView data={[{ ...basicData, children: [{ name: 'Child 1' }] }]} />);
291
298
 
@@ -1,5 +1,7 @@
1
1
  import { render, screen } from '@testing-library/react';
2
2
  import { TreeViewList } from '../TreeViewList';
3
+ import { TreeViewListItem } from '../TreeViewListItem';
4
+ import { TreeView } from '../TreeView';
3
5
  import styles from '@patternfly/react-styles/css/components/TreeView/tree-view';
4
6
 
5
7
  test(`Renders with class ${styles.treeView}__list by default`, () => {
@@ -84,6 +86,43 @@ test(`Does not render toolbar content when toolbar prop is not passed`, () => {
84
86
  expect(screen.queryByRole('separator')).not.toBeInTheDocument();
85
87
  });
86
88
 
89
+ test('Renders with inert attribute by default when TreeView is passed hasAnimations', () => {
90
+ const options = [
91
+ {
92
+ name: 'Parent 1',
93
+ id: 'parent-1',
94
+ children: [
95
+ {
96
+ name: 'Child 1',
97
+ id: 'child-1'
98
+ }
99
+ ]
100
+ }
101
+ ];
102
+ render(<TreeView hasAnimations data={options} />);
103
+
104
+ expect(screen.getByRole('group')).toHaveAttribute('inert', '');
105
+ });
106
+
107
+ test('Does not render with inert attribute when expanded and TreeView is passed hasAnimations', () => {
108
+ const options = [
109
+ {
110
+ name: 'Parent 1',
111
+ id: 'parent-1',
112
+ defaultExpanded: true,
113
+ children: [
114
+ {
115
+ name: 'Child 1',
116
+ id: 'child-1'
117
+ }
118
+ ]
119
+ }
120
+ ];
121
+ render(<TreeView hasAnimations data={options} />);
122
+
123
+ expect(screen.getByRole('group')).not.toHaveAttribute('inert');
124
+ });
125
+
87
126
  test('Matches snapshot by default', () => {
88
127
  const { asFragment } = render(<TreeViewList>Content</TreeViewList>);
89
128
 
@@ -28,7 +28,7 @@ test(`Does not render children by default`, () => {
28
28
  test(`Renders children if defaultExpanded is true`, () => {
29
29
  render(
30
30
  <TreeViewListItem defaultExpanded={true} {...requiredProps}>
31
- Content
31
+ <div>Content</div>
32
32
  </TreeViewListItem>
33
33
  );
34
34
 
@@ -38,7 +38,7 @@ test(`Renders children if defaultExpanded is true`, () => {
38
38
  test(`Renders children if isExpanded is true`, () => {
39
39
  render(
40
40
  <TreeViewListItem isExpanded={true} {...requiredProps}>
41
- Content
41
+ <div>Content</div>
42
42
  </TreeViewListItem>
43
43
  );
44
44
 
@@ -47,7 +47,11 @@ test(`Renders children if isExpanded is true`, () => {
47
47
 
48
48
  test(`Renders children when toggle is clicked`, async () => {
49
49
  const user = userEvent.setup();
50
- render(<TreeViewListItem {...requiredProps}>Content</TreeViewListItem>);
50
+ render(
51
+ <TreeViewListItem {...requiredProps}>
52
+ <div>Content</div>
53
+ </TreeViewListItem>
54
+ );
51
55
 
52
56
  await user.click(screen.getByRole('button', { name: requiredProps.name }));
53
57