@patternfly/react-core 4.211.1 → 4.211.4

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 (95) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/esm/components/Menu/Menu.js +1 -1
  3. package/dist/esm/components/Menu/Menu.js.map +1 -1
  4. package/dist/esm/components/Modal/Modal.d.ts +4 -0
  5. package/dist/esm/components/Modal/Modal.d.ts.map +1 -1
  6. package/dist/esm/components/Modal/Modal.js +2 -2
  7. package/dist/esm/components/Modal/Modal.js.map +1 -1
  8. package/dist/esm/components/Modal/ModalContent.d.ts +4 -0
  9. package/dist/esm/components/Modal/ModalContent.d.ts.map +1 -1
  10. package/dist/esm/components/Modal/ModalContent.js +3 -2
  11. package/dist/esm/components/Modal/ModalContent.js.map +1 -1
  12. package/dist/esm/components/Page/PageBreadcrumb.d.ts.map +1 -1
  13. package/dist/esm/components/Page/PageBreadcrumb.js +1 -1
  14. package/dist/esm/components/Page/PageBreadcrumb.js.map +1 -1
  15. package/dist/esm/components/Page/PageGroup.d.ts.map +1 -1
  16. package/dist/esm/components/Page/PageGroup.js +1 -1
  17. package/dist/esm/components/Page/PageGroup.js.map +1 -1
  18. package/dist/esm/components/Page/PageNavigation.d.ts.map +1 -1
  19. package/dist/esm/components/Page/PageNavigation.js +1 -1
  20. package/dist/esm/components/Page/PageNavigation.js.map +1 -1
  21. package/dist/esm/components/Page/PageSection.d.ts.map +1 -1
  22. package/dist/esm/components/Page/PageSection.js +1 -1
  23. package/dist/esm/components/Page/PageSection.js.map +1 -1
  24. package/dist/esm/components/Panel/Panel.d.ts +3 -1
  25. package/dist/esm/components/Panel/Panel.d.ts.map +1 -1
  26. package/dist/esm/components/Panel/Panel.js +4 -3
  27. package/dist/esm/components/Panel/Panel.js.map +1 -1
  28. package/dist/esm/components/Tooltip/Tooltip.d.ts +6 -0
  29. package/dist/esm/components/Tooltip/Tooltip.d.ts.map +1 -1
  30. package/dist/esm/components/Tooltip/Tooltip.js +2 -2
  31. package/dist/esm/components/Tooltip/Tooltip.js.map +1 -1
  32. package/dist/esm/helpers/KeyboardHandler.d.ts +2 -0
  33. package/dist/esm/helpers/KeyboardHandler.d.ts.map +1 -1
  34. package/dist/esm/helpers/KeyboardHandler.js +3 -2
  35. package/dist/esm/helpers/KeyboardHandler.js.map +1 -1
  36. package/dist/js/components/Menu/Menu.js +1 -1
  37. package/dist/js/components/Menu/Menu.js.map +1 -1
  38. package/dist/js/components/Modal/Modal.d.ts +4 -0
  39. package/dist/js/components/Modal/Modal.d.ts.map +1 -1
  40. package/dist/js/components/Modal/Modal.js +2 -2
  41. package/dist/js/components/Modal/Modal.js.map +1 -1
  42. package/dist/js/components/Modal/ModalContent.d.ts +4 -0
  43. package/dist/js/components/Modal/ModalContent.d.ts.map +1 -1
  44. package/dist/js/components/Modal/ModalContent.js +3 -2
  45. package/dist/js/components/Modal/ModalContent.js.map +1 -1
  46. package/dist/js/components/Page/PageBreadcrumb.d.ts.map +1 -1
  47. package/dist/js/components/Page/PageBreadcrumb.js +1 -1
  48. package/dist/js/components/Page/PageBreadcrumb.js.map +1 -1
  49. package/dist/js/components/Page/PageGroup.d.ts.map +1 -1
  50. package/dist/js/components/Page/PageGroup.js +1 -1
  51. package/dist/js/components/Page/PageGroup.js.map +1 -1
  52. package/dist/js/components/Page/PageNavigation.d.ts.map +1 -1
  53. package/dist/js/components/Page/PageNavigation.js +1 -1
  54. package/dist/js/components/Page/PageNavigation.js.map +1 -1
  55. package/dist/js/components/Page/PageSection.d.ts.map +1 -1
  56. package/dist/js/components/Page/PageSection.js +1 -1
  57. package/dist/js/components/Page/PageSection.js.map +1 -1
  58. package/dist/js/components/Panel/Panel.d.ts +3 -1
  59. package/dist/js/components/Panel/Panel.d.ts.map +1 -1
  60. package/dist/js/components/Panel/Panel.js +4 -4
  61. package/dist/js/components/Panel/Panel.js.map +1 -1
  62. package/dist/js/components/Tooltip/Tooltip.d.ts +6 -0
  63. package/dist/js/components/Tooltip/Tooltip.d.ts.map +1 -1
  64. package/dist/js/components/Tooltip/Tooltip.js +2 -2
  65. package/dist/js/components/Tooltip/Tooltip.js.map +1 -1
  66. package/dist/js/helpers/KeyboardHandler.d.ts +2 -0
  67. package/dist/js/helpers/KeyboardHandler.d.ts.map +1 -1
  68. package/dist/js/helpers/KeyboardHandler.js +3 -2
  69. package/dist/js/helpers/KeyboardHandler.js.map +1 -1
  70. package/dist/umd/react-core.css +5 -0
  71. package/dist/umd/react-core.js +19 -16
  72. package/dist/umd/react-core.min.css +5 -0
  73. package/dist/umd/react-core.min.js +4 -4
  74. package/package.json +6 -6
  75. package/src/components/Menu/Menu.tsx +1 -1
  76. package/src/components/Modal/Modal.tsx +8 -0
  77. package/src/components/Modal/ModalContent.tsx +14 -1
  78. package/src/components/Modal/__tests__/Modal.test.tsx +56 -0
  79. package/src/components/Modal/examples/Modal.md +7 -0
  80. package/src/components/Modal/examples/ModalWithOverflowingContent.tsx +71 -0
  81. package/src/components/Page/PageBreadcrumb.tsx +1 -0
  82. package/src/components/Page/PageGroup.tsx +1 -0
  83. package/src/components/Page/PageNavigation.tsx +1 -0
  84. package/src/components/Page/PageSection.tsx +1 -0
  85. package/src/components/Page/__tests__/__snapshots__/PageBreadcrumb.test.tsx.snap +1 -0
  86. package/src/components/Page/__tests__/__snapshots__/PageGroup.test.tsx.snap +1 -0
  87. package/src/components/Page/__tests__/__snapshots__/PageNavigation.test.tsx.snap +1 -0
  88. package/src/components/Page/__tests__/__snapshots__/PageSection.test.tsx.snap +1 -0
  89. package/src/components/Panel/Panel.tsx +8 -1
  90. package/src/components/Tabs/examples/Tabs.md +144 -25
  91. package/src/components/Tooltip/Tooltip.tsx +8 -0
  92. package/src/components/Tooltip/examples/Tooltip.md +86 -41
  93. package/src/demos/ComposableMenu/ComposableMenu.md +2 -0
  94. package/src/demos/ComposableMenu/examples/ComposableTreeViewMenu.tsx +62 -28
  95. package/src/helpers/KeyboardHandler.tsx +7 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/react-core",
3
- "version": "4.211.1",
3
+ "version": "4.211.4",
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",
@@ -34,16 +34,16 @@
34
34
  "generate": "node scripts/copyStyles.js"
35
35
  },
36
36
  "dependencies": {
37
- "@patternfly/react-icons": "^4.62.1",
38
- "@patternfly/react-styles": "^4.61.1",
39
- "@patternfly/react-tokens": "^4.63.1",
37
+ "@patternfly/react-icons": "^4.62.4",
38
+ "@patternfly/react-styles": "^4.61.4",
39
+ "@patternfly/react-tokens": "^4.63.4",
40
40
  "focus-trap": "6.2.2",
41
41
  "react-dropzone": "9.0.0",
42
42
  "tippy.js": "5.1.2",
43
43
  "tslib": "^2.0.0"
44
44
  },
45
45
  "devDependencies": {
46
- "@patternfly/patternfly": "4.194.0",
46
+ "@patternfly/patternfly": "4.194.1",
47
47
  "@rollup/plugin-commonjs": "^21.0.0",
48
48
  "@rollup/plugin-node-resolve": "^13.0.0",
49
49
  "@rollup/plugin-replace": "^3.0.0",
@@ -60,5 +60,5 @@
60
60
  "react": "^16.8.0 || ^17.0.0",
61
61
  "react-dom": "^16.8.0 || ^17.0.0"
62
62
  },
63
- "gitHead": "0ccd3c16db5a58d36fab9709f8a06c98b19a7852"
63
+ "gitHead": "ca785dd8aa7c1dfd9ab8be73445cd2d5820aeafe"
64
64
  }
@@ -210,7 +210,7 @@ class MenuBase extends React.Component<MenuProps, MenuState> {
210
210
  ? Array.from(this.activeMenu.getElementsByTagName('UL')[0].children).filter(
211
211
  el => !(el.classList.contains('pf-m-disabled') || el.classList.contains('pf-c-divider'))
212
212
  )
213
- : Array.from(this.activeMenu.getElementsByTagName('LI')).filter(
213
+ : Array.from(this.menuRef.current.getElementsByTagName('LI')).filter(
214
214
  el => !(el.classList.contains('pf-m-disabled') || el.classList.contains('pf-c-divider'))
215
215
  );
216
216
  };
@@ -31,6 +31,10 @@ export interface ModalProps extends React.HTMLProps<HTMLDivElement>, OUIAProps {
31
31
  'aria-label'?: string;
32
32
  /** Id to use for Modal Box descriptor */
33
33
  'aria-describedby'?: string;
34
+ /** Accessible label applied to the modal box body. This should be used to communicate important information about the modal box body div if needed, such as that it is scrollable */
35
+ bodyAriaLabel?: string;
36
+ /** Accessible role applied to the modal box body. This will default to region if a body aria label is applied. Set to a more appropriate role as applicable based on the modal content and context */
37
+ bodyAriaRole?: string;
34
38
  /** Flag to show the close button in the header area of the modal */
35
39
  showClose?: boolean;
36
40
  /** Custom footer */
@@ -206,6 +210,8 @@ export class Modal extends React.Component<ModalProps, ModalState> {
206
210
  'aria-labelledby': ariaLabelledby,
207
211
  'aria-label': ariaLabel,
208
212
  'aria-describedby': ariaDescribedby,
213
+ bodyAriaLabel,
214
+ bodyAriaRole,
209
215
  title,
210
216
  titleIconVariant,
211
217
  titleLabel,
@@ -231,6 +237,8 @@ export class Modal extends React.Component<ModalProps, ModalState> {
231
237
  aria-label={ariaLabel}
232
238
  aria-describedby={ariaDescribedby}
233
239
  aria-labelledby={ariaLabelledby}
240
+ bodyAriaLabel={bodyAriaLabel}
241
+ bodyAriaRole={bodyAriaRole}
234
242
  ouiaId={ouiaId !== undefined ? ouiaId : this.state.ouiaStateId}
235
243
  ouiaSafe={ouiaSafe}
236
244
  />,
@@ -47,6 +47,10 @@ export interface ModalContentProps extends OUIAProps {
47
47
  'aria-label'?: string;
48
48
  /** Id of Modal Box description */
49
49
  'aria-describedby'?: string;
50
+ /** Accessible label applied to the modal box body. This should be used to communicate important information about the modal box body div if needed, such as that it is scrollable */
51
+ bodyAriaLabel?: string;
52
+ /** Accessible role applied to the modal box body. This will default to region if a body aria label is applied. Set to a more appropriate role as applicable based on the modal content and context */
53
+ bodyAriaRole?: string;
50
54
  /** Flag to show the close button in the header area of the modal */
51
55
  showClose?: boolean;
52
56
  /** Default width of the content. */
@@ -82,6 +86,8 @@ export const ModalContent: React.FunctionComponent<ModalContentProps> = ({
82
86
  'aria-label': ariaLabel = '',
83
87
  'aria-describedby': ariaDescribedby,
84
88
  'aria-labelledby': ariaLabelledby,
89
+ bodyAriaLabel,
90
+ bodyAriaRole,
85
91
  showClose = true,
86
92
  footer = null,
87
93
  actions = [],
@@ -120,10 +126,17 @@ export const ModalContent: React.FunctionComponent<ModalContentProps> = ({
120
126
  actions.length > 0 && <ModalBoxFooter>{actions}</ModalBoxFooter>
121
127
  );
122
128
 
129
+ const defaultModalBodyAriaRole = bodyAriaLabel ? 'region' : undefined;
130
+
123
131
  const modalBody = hasNoBodyWrapper ? (
124
132
  children
125
133
  ) : (
126
- <ModalBoxBody {...props} {...(!description && !ariaDescribedby && { id: descriptorId })}>
134
+ <ModalBoxBody
135
+ aria-label={bodyAriaLabel}
136
+ role={bodyAriaRole || defaultModalBodyAriaRole}
137
+ {...props}
138
+ {...(!description && !ariaDescribedby && { id: descriptorId })}
139
+ >
127
140
  {children}
128
141
  </ModalBoxBody>
129
142
  );
@@ -85,4 +85,60 @@ describe('Modal', () => {
85
85
 
86
86
  expect(consoleErrorMock).toHaveBeenCalled();
87
87
  });
88
+
89
+ test('The modalBoxBody has no aria-label when bodyAriaLabel is not passed', () => {
90
+ const props = {
91
+ isOpen: true
92
+ };
93
+
94
+ render(<Modal {...props}>This is a ModalBox</Modal>);
95
+
96
+ const modalBoxBody = screen.getByText('This is a ModalBox');
97
+ expect(modalBoxBody).not.toHaveAccessibleName('modal box body aria label');
98
+ });
99
+
100
+ test('The modalBoxBody has the expected aria-label when bodyAriaLabel is passed', () => {
101
+ const props = {
102
+ isOpen: true
103
+ };
104
+
105
+ render(
106
+ <Modal bodyAriaLabel="modal box body aria label" {...props}>
107
+ This is a ModalBox
108
+ </Modal>
109
+ );
110
+
111
+ const modalBoxBody = screen.getByText('This is a ModalBox');
112
+ expect(modalBoxBody).toHaveAccessibleName('modal box body aria label');
113
+ });
114
+
115
+ test('The modalBoxBody has the expected aria role when bodyAriaLabel is passed and bodyAriaRole is not', () => {
116
+ const props = {
117
+ isOpen: true
118
+ };
119
+
120
+ render(
121
+ <Modal bodyAriaLabel="modal box body aria label" {...props}>
122
+ This is a ModalBox
123
+ </Modal>
124
+ );
125
+
126
+ const modalBoxBody = screen.getByRole('region', { name: 'modal box body aria label' });
127
+ expect(modalBoxBody).toBeInTheDocument();
128
+ });
129
+
130
+ test('The modalBoxBody has the expected aria role when bodyAriaRole is passed', () => {
131
+ const props = {
132
+ isOpen: true
133
+ };
134
+
135
+ render(
136
+ <Modal bodyAriaLabel="modal box body aria label" bodyAriaRole="article" {...props}>
137
+ This is a ModalBox
138
+ </Modal>
139
+ );
140
+
141
+ const modalBoxBody = screen.getByRole('article', { name: 'modal box body aria label' });
142
+ expect(modalBoxBody).toBeInTheDocument();
143
+ });
88
144
  });
@@ -869,3 +869,10 @@ class HelpModal extends React.Component {
869
869
  ```ts file="ModalWithForm.tsx"
870
870
 
871
871
  ```
872
+
873
+ ### With overflowing content
874
+
875
+ If the content that you're passing to the modal is likely to overflow the modal content area, pass tabIndex={0} to the modal to enable keyboard accessible scrolling.
876
+
877
+ ```ts file="ModalWithOverflowingContent.tsx"
878
+ ```
@@ -0,0 +1,71 @@
1
+ import React from 'react';
2
+ import { Modal, ModalVariant, Button } from '@patternfly/react-core';
3
+
4
+ export const ModalWithOverflowingContent: React.FunctionComponent = () => {
5
+ const [isModalOpen, setIsModalOpen] = React.useState(false);
6
+
7
+ const handleModalToggle = () => {
8
+ setIsModalOpen(prevIsModalOpen => !prevIsModalOpen);
9
+ };
10
+
11
+ return (
12
+ <React.Fragment>
13
+ <Button variant="primary" onClick={handleModalToggle}>
14
+ Show modal
15
+ </Button>
16
+ <Modal
17
+ bodyAriaLabel="Scrollable modal content"
18
+ tabIndex={0}
19
+ variant={ModalVariant.small}
20
+ title="Modal with overflowing content"
21
+ isOpen={isModalOpen}
22
+ onClose={handleModalToggle}
23
+ actions={[
24
+ <Button key="confirm" variant="primary" onClick={handleModalToggle}>
25
+ Confirm
26
+ </Button>,
27
+ <Button key="cancel" variant="link" onClick={handleModalToggle}>
28
+ Cancel
29
+ </Button>
30
+ ]}
31
+ >
32
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
33
+ magna aliqua. Quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus. Semper auctor neque vitae tempus.
34
+ Diam donec adipiscing tristique risus. Augue eget arcu dictum varius duis. Ut enim blandit volutpat maecenas
35
+ volutpat blandit aliquam. Sit amet mauris commodo quis imperdiet massa tincidunt. Habitant morbi tristique
36
+ senectus et netus. Fames ac turpis egestas sed tempus urna. Neque laoreet suspendisse interdum consectetur
37
+ libero id. Volutpat lacus laoreet non curabitur gravida arcu ac tortor. Porta nibh venenatis cras sed felis eget
38
+ velit. Nullam non nisi est sit amet facilisis. Nunc mi ipsum faucibus vitae. Lorem sed risus ultricies tristique
39
+ nulla aliquet enim tortor at. Egestas sed tempus urna et pharetra pharetra massa massa ultricies. Lacinia quis
40
+ vel eros donec ac odio tempor orci. Malesuada fames ac turpis egestas integer eget aliquet.
41
+ <br />
42
+ <br />
43
+ Neque aliquam vestibulum morbi blandit cursus risus at ultrices. Molestie at elementum eu facilisis sed odio
44
+ morbi. Elit pellentesque habitant morbi tristique. Consequat nisl vel pretium lectus quam id leo in vitae. Quis
45
+ varius quam quisque id diam vel quam elementum. Viverra nam libero justo laoreet sit amet cursus. Sollicitudin
46
+ tempor id eu nisl nunc. Orci nulla pellentesque dignissim enim sit amet venenatis. Dignissim enim sit amet
47
+ venenatis urna cursus eget. Iaculis at erat pellentesque adipiscing commodo elit. Faucibus pulvinar elementum
48
+ integer enim neque volutpat. Nullam vehicula ipsum a arcu cursus vitae congue mauris. Nunc mattis enim ut tellus
49
+ elementum sagittis vitae. Blandit cursus risus at ultrices. Tellus mauris a diam maecenas sed enim. Non diam
50
+ phasellus vestibulum lorem sed risus ultricies tristique nulla.
51
+ <br />
52
+ <br />
53
+ Nulla pharetra diam sit amet nisl suscipit adipiscing. Ac tortor vitae purus faucibus ornare suspendisse sed
54
+ nisi. Sed felis eget velit aliquet sagittis id consectetur purus. Tincidunt tortor aliquam nulla facilisi cras
55
+ fermentum. Volutpat est velit egestas dui id ornare arcu odio. Pharetra magna ac placerat vestibulum. Ultrices
56
+ sagittis orci a scelerisque purus semper eget duis at. Nisi est sit amet facilisis magna etiam tempor orci eu.
57
+ Convallis tellus id interdum velit. Facilisis sed odio morbi quis commodo odio aenean sed.
58
+ <br />
59
+ <br />
60
+ Eu scelerisque felis imperdiet proin fermentum leo vel orci porta. Facilisi etiam dignissim diam quis enim
61
+ lobortis scelerisque fermentum. Eleifend donec pretium vulputate sapien nec sagittis aliquam malesuada. Magna
62
+ etiam tempor orci eu lobortis elementum. Quis auctor elit sed vulputate mi sit. Eleifend quam adipiscing vitae
63
+ proin sagittis nisl rhoncus mattis rhoncus. Erat velit scelerisque in dictum non. Sit amet nulla facilisi morbi
64
+ tempus iaculis urna. Enim ut tellus elementum sagittis vitae et leo duis ut. Lectus arcu bibendum at varius vel
65
+ pharetra vel turpis. Morbi tristique senectus et netus et. Eget aliquet nibh praesent tristique magna sit amet
66
+ purus gravida. Nisl purus in mollis nunc sed id semper risus. Id neque aliquam vestibulum morbi. Mauris a diam
67
+ maecenas sed enim ut sem. Egestas tellus rutrum tellus pellentesque.
68
+ </Modal>
69
+ </React.Fragment>
70
+ );
71
+ };
@@ -40,6 +40,7 @@ export const PageBreadcrumb = ({
40
40
  hasOverflowScroll && styles.modifiers.overflowScroll,
41
41
  className
42
42
  )}
43
+ {...(hasOverflowScroll && { tabIndex: 0 })}
43
44
  {...props}
44
45
  >
45
46
  {isWidthLimited && <div className={css(styles.pageMainBody)}>{children}</div>}
@@ -37,6 +37,7 @@ export const PageGroup = ({
37
37
  hasOverflowScroll && styles.modifiers.overflowScroll,
38
38
  className
39
39
  )}
40
+ {...(hasOverflowScroll && { tabIndex: 0 })}
40
41
  >
41
42
  {children}
42
43
  </div>
@@ -40,6 +40,7 @@ export const PageNavigation = ({
40
40
  hasOverflowScroll && styles.modifiers.overflowScroll,
41
41
  className
42
42
  )}
43
+ {...(hasOverflowScroll && { tabIndex: 0 })}
43
44
  {...props}
44
45
  >
45
46
  {isWidthLimited && <div className={css(styles.pageMainBody)}>{children}</div>}
@@ -101,6 +101,7 @@ export const PageSection: React.FunctionComponent<PageSectionProps> = ({
101
101
  hasOverflowScroll && styles.modifiers.overflowScroll,
102
102
  className
103
103
  )}
104
+ {...(hasOverflowScroll && { tabIndex: 0 })}
104
105
  >
105
106
  {isWidthLimited && <div className={css(styles.pageMainBody)}>{children}</div>}
106
107
  {!isWidthLimited && children}
@@ -48,6 +48,7 @@ exports[`page breadcrumb Verify overflow scroll 1`] = `
48
48
  <DocumentFragment>
49
49
  <section
50
50
  class="pf-c-page__main-breadcrumb pf-m-overflow-scroll"
51
+ tabindex="0"
51
52
  >
52
53
  test
53
54
  </section>
@@ -34,6 +34,7 @@ exports[`page group Verify overflow scroll 1`] = `
34
34
  <DocumentFragment>
35
35
  <div
36
36
  class="pf-c-page__main-group pf-m-overflow-scroll"
37
+ tabindex="0"
37
38
  >
38
39
  test
39
40
  </div>
@@ -48,6 +48,7 @@ exports[`page navigation Verify overflow scroll 1`] = `
48
48
  <DocumentFragment>
49
49
  <div
50
50
  class="pf-c-page__main-nav pf-m-overflow-scroll"
51
+ tabindex="0"
51
52
  >
52
53
  test
53
54
  </div>
@@ -112,6 +112,7 @@ exports[`Verify page section overflow scroll 1`] = `
112
112
  <DocumentFragment>
113
113
  <section
114
114
  class="pf-c-page__main-section pf-m-overflow-scroll"
115
+ tabindex="0"
115
116
  >
116
117
  test
117
118
  </section>
@@ -11,13 +11,16 @@ export interface PanelProps extends React.HTMLProps<HTMLDivElement> {
11
11
  variant?: 'raised' | 'bordered';
12
12
  /** Flag to add scrollable styling to the panel */
13
13
  isScrollable?: boolean;
14
+ /** @hide Forwarded ref */
15
+ innerRef?: React.Ref<any>;
14
16
  }
15
17
 
16
- export const Panel: React.FunctionComponent<PanelProps> = ({
18
+ const PanelBase: React.FunctionComponent<PanelProps> = ({
17
19
  className,
18
20
  children,
19
21
  variant,
20
22
  isScrollable,
23
+ innerRef,
21
24
  ...props
22
25
  }: PanelProps) => (
23
26
  <div
@@ -28,10 +31,14 @@ export const Panel: React.FunctionComponent<PanelProps> = ({
28
31
  isScrollable && styles.modifiers.scrollable,
29
32
  className
30
33
  )}
34
+ ref={innerRef}
31
35
  {...props}
32
36
  >
33
37
  {children}
34
38
  </div>
35
39
  );
36
40
 
41
+ export const Panel = React.forwardRef((props: PanelProps, ref: React.Ref<any>) => (
42
+ <PanelBase innerRef={ref} {...props} />
43
+ ));
37
44
  Panel.displayName = 'Panel';