@patternfly/react-core 4.236.6 → 4.236.9

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 (189) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/esm/components/ApplicationLauncher/ApplicationLauncher.d.ts +2 -0
  3. package/dist/esm/components/ApplicationLauncher/ApplicationLauncher.d.ts.map +1 -1
  4. package/dist/esm/components/ApplicationLauncher/ApplicationLauncher.js +4 -3
  5. package/dist/esm/components/ApplicationLauncher/ApplicationLauncher.js.map +1 -1
  6. package/dist/esm/components/BackToTop/BackToTop.d.ts +1 -1
  7. package/dist/esm/components/ContextSelector/ContextSelector.d.ts +2 -0
  8. package/dist/esm/components/ContextSelector/ContextSelector.d.ts.map +1 -1
  9. package/dist/esm/components/ContextSelector/ContextSelector.js +4 -3
  10. package/dist/esm/components/ContextSelector/ContextSelector.js.map +1 -1
  11. package/dist/esm/components/Dropdown/Dropdown.d.ts +2 -0
  12. package/dist/esm/components/Dropdown/Dropdown.d.ts.map +1 -1
  13. package/dist/esm/components/Dropdown/Dropdown.js +2 -2
  14. package/dist/esm/components/Dropdown/Dropdown.js.map +1 -1
  15. package/dist/esm/components/Dropdown/DropdownWithContext.d.ts.map +1 -1
  16. package/dist/esm/components/Dropdown/DropdownWithContext.js +2 -2
  17. package/dist/esm/components/Dropdown/DropdownWithContext.js.map +1 -1
  18. package/dist/esm/components/DualListSelector/DualListSelectorControl.d.ts +1 -1
  19. package/dist/esm/components/DualListSelector/DualListSelectorControlsWrapper.d.ts +1 -1
  20. package/dist/esm/components/DualListSelector/DualListSelectorListItem.d.ts +1 -1
  21. package/dist/esm/components/DualListSelector/DualListSelectorListWrapper.d.ts +1 -1
  22. package/dist/esm/components/Menu/MenuContent.d.ts +1 -1
  23. package/dist/esm/components/Menu/MenuGroup.d.ts +1 -1
  24. package/dist/esm/components/Menu/MenuInput.d.ts +1 -1
  25. package/dist/esm/components/Menu/MenuItem.d.ts +1 -1
  26. package/dist/esm/components/Nav/NavItem.d.ts +2 -0
  27. package/dist/esm/components/Nav/NavItem.d.ts.map +1 -1
  28. package/dist/esm/components/Nav/NavItem.js +2 -2
  29. package/dist/esm/components/Nav/NavItem.js.map +1 -1
  30. package/dist/esm/components/NotificationDrawer/NotificationDrawer.d.ts +1 -1
  31. package/dist/esm/components/OptionsMenu/OptionsMenu.d.ts +2 -0
  32. package/dist/esm/components/OptionsMenu/OptionsMenu.d.ts.map +1 -1
  33. package/dist/esm/components/OptionsMenu/OptionsMenu.js +2 -2
  34. package/dist/esm/components/OptionsMenu/OptionsMenu.js.map +1 -1
  35. package/dist/esm/components/Panel/Panel.d.ts +1 -1
  36. package/dist/esm/components/Popover/Popover.d.ts +2 -0
  37. package/dist/esm/components/Popover/Popover.d.ts.map +1 -1
  38. package/dist/esm/components/Popover/Popover.js +2 -2
  39. package/dist/esm/components/Popover/Popover.js.map +1 -1
  40. package/dist/esm/components/Popover/PopoverCloseButton.d.ts.map +1 -1
  41. package/dist/esm/components/Popover/PopoverCloseButton.js +2 -11
  42. package/dist/esm/components/Popover/PopoverCloseButton.js.map +1 -1
  43. package/dist/esm/components/SearchInput/SearchInput.d.ts +2 -0
  44. package/dist/esm/components/SearchInput/SearchInput.d.ts.map +1 -1
  45. package/dist/esm/components/SearchInput/SearchInput.js +2 -2
  46. package/dist/esm/components/SearchInput/SearchInput.js.map +1 -1
  47. package/dist/esm/components/Select/Select.d.ts +2 -0
  48. package/dist/esm/components/Select/Select.d.ts.map +1 -1
  49. package/dist/esm/components/Select/Select.js +4 -3
  50. package/dist/esm/components/Select/Select.js.map +1 -1
  51. package/dist/esm/components/Tabs/OverflowTab.d.ts +2 -0
  52. package/dist/esm/components/Tabs/OverflowTab.d.ts.map +1 -1
  53. package/dist/esm/components/Tabs/OverflowTab.js +2 -2
  54. package/dist/esm/components/Tabs/OverflowTab.js.map +1 -1
  55. package/dist/esm/components/Tabs/Tab.d.ts +1 -1
  56. package/dist/esm/components/TimePicker/TimePicker.d.ts +3 -0
  57. package/dist/esm/components/TimePicker/TimePicker.d.ts.map +1 -1
  58. package/dist/esm/components/TimePicker/TimePicker.js +5 -4
  59. package/dist/esm/components/TimePicker/TimePicker.js.map +1 -1
  60. package/dist/esm/components/Tooltip/Tooltip.d.ts +2 -0
  61. package/dist/esm/components/Tooltip/Tooltip.d.ts.map +1 -1
  62. package/dist/esm/components/Tooltip/Tooltip.js +2 -2
  63. package/dist/esm/components/Tooltip/Tooltip.js.map +1 -1
  64. package/dist/esm/helpers/FocusTrap/FocusTrap.d.ts +5 -19
  65. package/dist/esm/helpers/FocusTrap/FocusTrap.d.ts.map +1 -1
  66. package/dist/esm/helpers/FocusTrap/FocusTrap.js +10 -6
  67. package/dist/esm/helpers/FocusTrap/FocusTrap.js.map +1 -1
  68. package/dist/esm/helpers/Popper/Popper.d.ts +5 -0
  69. package/dist/esm/helpers/Popper/Popper.d.ts.map +1 -1
  70. package/dist/esm/helpers/Popper/Popper.js +42 -7
  71. package/dist/esm/helpers/Popper/Popper.js.map +1 -1
  72. package/dist/esm/helpers/resizeObserver.d.ts +8 -1
  73. package/dist/esm/helpers/resizeObserver.d.ts.map +1 -1
  74. package/dist/esm/helpers/resizeObserver.js +18 -3
  75. package/dist/esm/helpers/resizeObserver.js.map +1 -1
  76. package/dist/js/components/ApplicationLauncher/ApplicationLauncher.d.ts +2 -0
  77. package/dist/js/components/ApplicationLauncher/ApplicationLauncher.d.ts.map +1 -1
  78. package/dist/js/components/ApplicationLauncher/ApplicationLauncher.js +4 -3
  79. package/dist/js/components/ApplicationLauncher/ApplicationLauncher.js.map +1 -1
  80. package/dist/js/components/BackToTop/BackToTop.d.ts +1 -1
  81. package/dist/js/components/ContextSelector/ContextSelector.d.ts +2 -0
  82. package/dist/js/components/ContextSelector/ContextSelector.d.ts.map +1 -1
  83. package/dist/js/components/ContextSelector/ContextSelector.js +4 -3
  84. package/dist/js/components/ContextSelector/ContextSelector.js.map +1 -1
  85. package/dist/js/components/Dropdown/Dropdown.d.ts +2 -0
  86. package/dist/js/components/Dropdown/Dropdown.d.ts.map +1 -1
  87. package/dist/js/components/Dropdown/Dropdown.js +2 -2
  88. package/dist/js/components/Dropdown/Dropdown.js.map +1 -1
  89. package/dist/js/components/Dropdown/DropdownWithContext.d.ts.map +1 -1
  90. package/dist/js/components/Dropdown/DropdownWithContext.js +2 -2
  91. package/dist/js/components/Dropdown/DropdownWithContext.js.map +1 -1
  92. package/dist/js/components/DualListSelector/DualListSelectorControl.d.ts +1 -1
  93. package/dist/js/components/DualListSelector/DualListSelectorControlsWrapper.d.ts +1 -1
  94. package/dist/js/components/DualListSelector/DualListSelectorListItem.d.ts +1 -1
  95. package/dist/js/components/DualListSelector/DualListSelectorListWrapper.d.ts +1 -1
  96. package/dist/js/components/Menu/MenuContent.d.ts +1 -1
  97. package/dist/js/components/Menu/MenuGroup.d.ts +1 -1
  98. package/dist/js/components/Menu/MenuInput.d.ts +1 -1
  99. package/dist/js/components/Menu/MenuItem.d.ts +1 -1
  100. package/dist/js/components/Nav/NavItem.d.ts +2 -0
  101. package/dist/js/components/Nav/NavItem.d.ts.map +1 -1
  102. package/dist/js/components/Nav/NavItem.js +2 -2
  103. package/dist/js/components/Nav/NavItem.js.map +1 -1
  104. package/dist/js/components/NotificationDrawer/NotificationDrawer.d.ts +1 -1
  105. package/dist/js/components/OptionsMenu/OptionsMenu.d.ts +2 -0
  106. package/dist/js/components/OptionsMenu/OptionsMenu.d.ts.map +1 -1
  107. package/dist/js/components/OptionsMenu/OptionsMenu.js +2 -2
  108. package/dist/js/components/OptionsMenu/OptionsMenu.js.map +1 -1
  109. package/dist/js/components/Panel/Panel.d.ts +1 -1
  110. package/dist/js/components/Popover/Popover.d.ts +2 -0
  111. package/dist/js/components/Popover/Popover.d.ts.map +1 -1
  112. package/dist/js/components/Popover/Popover.js +2 -2
  113. package/dist/js/components/Popover/Popover.js.map +1 -1
  114. package/dist/js/components/Popover/PopoverCloseButton.d.ts.map +1 -1
  115. package/dist/js/components/Popover/PopoverCloseButton.js +2 -11
  116. package/dist/js/components/Popover/PopoverCloseButton.js.map +1 -1
  117. package/dist/js/components/SearchInput/SearchInput.d.ts +2 -0
  118. package/dist/js/components/SearchInput/SearchInput.d.ts.map +1 -1
  119. package/dist/js/components/SearchInput/SearchInput.js +2 -2
  120. package/dist/js/components/SearchInput/SearchInput.js.map +1 -1
  121. package/dist/js/components/Select/Select.d.ts +2 -0
  122. package/dist/js/components/Select/Select.d.ts.map +1 -1
  123. package/dist/js/components/Select/Select.js +4 -3
  124. package/dist/js/components/Select/Select.js.map +1 -1
  125. package/dist/js/components/Tabs/OverflowTab.d.ts +2 -0
  126. package/dist/js/components/Tabs/OverflowTab.d.ts.map +1 -1
  127. package/dist/js/components/Tabs/OverflowTab.js +2 -2
  128. package/dist/js/components/Tabs/OverflowTab.js.map +1 -1
  129. package/dist/js/components/Tabs/Tab.d.ts +1 -1
  130. package/dist/js/components/TimePicker/TimePicker.d.ts +3 -0
  131. package/dist/js/components/TimePicker/TimePicker.d.ts.map +1 -1
  132. package/dist/js/components/TimePicker/TimePicker.js +5 -4
  133. package/dist/js/components/TimePicker/TimePicker.js.map +1 -1
  134. package/dist/js/components/Tooltip/Tooltip.d.ts +2 -0
  135. package/dist/js/components/Tooltip/Tooltip.d.ts.map +1 -1
  136. package/dist/js/components/Tooltip/Tooltip.js +2 -2
  137. package/dist/js/components/Tooltip/Tooltip.js.map +1 -1
  138. package/dist/js/helpers/FocusTrap/FocusTrap.d.ts +5 -19
  139. package/dist/js/helpers/FocusTrap/FocusTrap.d.ts.map +1 -1
  140. package/dist/js/helpers/FocusTrap/FocusTrap.js +10 -7
  141. package/dist/js/helpers/FocusTrap/FocusTrap.js.map +1 -1
  142. package/dist/js/helpers/Popper/Popper.d.ts +5 -0
  143. package/dist/js/helpers/Popper/Popper.d.ts.map +1 -1
  144. package/dist/js/helpers/Popper/Popper.js +42 -7
  145. package/dist/js/helpers/Popper/Popper.js.map +1 -1
  146. package/dist/js/helpers/resizeObserver.d.ts +8 -1
  147. package/dist/js/helpers/resizeObserver.d.ts.map +1 -1
  148. package/dist/js/helpers/resizeObserver.js +18 -3
  149. package/dist/js/helpers/resizeObserver.js.map +1 -1
  150. package/dist/umd/react-core.min.css +335 -335
  151. package/dist/umd/react-core.min.js +5 -5
  152. package/package.json +5 -5
  153. package/src/components/ApplicationLauncher/ApplicationLauncher.tsx +6 -1
  154. package/src/components/ApplicationLauncher/__tests__/ApplicationLauncher.test.tsx +10 -1
  155. package/src/components/ApplicationLauncher/__tests__/__snapshots__/ApplicationLauncher.test.tsx.snap +153 -7
  156. package/src/components/ContextSelector/ContextSelector.tsx +6 -1
  157. package/src/components/ContextSelector/__tests__/ContextSelector.test.tsx +18 -1
  158. package/src/components/ContextSelector/__tests__/__snapshots__/ContextSelector.test.tsx.snap +144 -0
  159. package/src/components/Dropdown/Dropdown.tsx +9 -1
  160. package/src/components/Dropdown/DropdownWithContext.tsx +2 -0
  161. package/src/components/Dropdown/__tests__/Dropdown.test.tsx +16 -0
  162. package/src/components/Dropdown/__tests__/__snapshots__/Dropdown.test.tsx.snap +131 -7
  163. package/src/components/Nav/NavItem.tsx +4 -0
  164. package/src/components/Nav/__tests__/Nav.test.tsx +19 -0
  165. package/src/components/Nav/__tests__/__snapshots__/Nav.test.tsx.snap +111 -42
  166. package/src/components/OptionsMenu/OptionsMenu.tsx +4 -0
  167. package/src/components/OptionsMenu/__tests__/OptionsMenu.test.tsx +17 -0
  168. package/src/components/OptionsMenu/__tests__/__snapshots__/OptionsMenu.test.tsx.snap +216 -20
  169. package/src/components/Popover/Popover.tsx +4 -0
  170. package/src/components/Popover/PopoverCloseButton.tsx +6 -17
  171. package/src/components/Popover/__tests__/Popover.test.tsx +25 -0
  172. package/src/components/Popover/__tests__/__snapshots__/Popover.test.tsx.snap +10 -0
  173. package/src/components/SearchInput/SearchInput.tsx +4 -0
  174. package/src/components/SearchInput/__tests__/SearchInput.test.tsx +27 -1
  175. package/src/components/SearchInput/__tests__/__snapshots__/SearchInput.test.tsx.snap +130 -6
  176. package/src/components/Select/Select.tsx +6 -1
  177. package/src/components/Select/__tests__/Select.test.tsx +23 -7
  178. package/src/components/Select/__tests__/__snapshots__/Select.test.tsx.snap +152 -46
  179. package/src/components/Tabs/OverflowTab.tsx +4 -0
  180. package/src/components/Tabs/__tests__/OverflowTab.test.tsx +31 -7
  181. package/src/components/Tabs/__tests__/__snapshots__/OverflowTab.test.tsx.snap +89 -0
  182. package/src/components/TimePicker/TimePicker.tsx +6 -1
  183. package/src/components/TimePicker/__tests__/TimePicker.test.tsx +16 -1
  184. package/src/components/Tooltip/Tooltip.tsx +4 -0
  185. package/src/components/Tooltip/__tests__/Tooltip.test.tsx +21 -0
  186. package/src/components/Tooltip/__tests__/__snapshots__/Tooltip.test.tsx.snap +10 -0
  187. package/src/helpers/FocusTrap/FocusTrap.tsx +21 -5
  188. package/src/helpers/Popper/Popper.tsx +54 -12
  189. package/src/helpers/resizeObserver.tsx +21 -3
@@ -6,6 +6,21 @@ import userEvent from '@testing-library/user-event';
6
6
  import { TimePicker, TimePickerProps } from '../TimePicker';
7
7
 
8
8
  describe('TimePicker', () => {
9
+ test('Renders in strict mode', () => {
10
+ const validateTime = (_time: string) => {
11
+ return true;
12
+ };
13
+
14
+ const consoleError = jest.spyOn(console, 'error');
15
+ const { asFragment } = render(
16
+ <React.StrictMode>
17
+ <TimePicker removeFindDomNode value={'00:00'} validateTime={validateTime} aria-label="time picker" />
18
+ </React.StrictMode>
19
+ );
20
+ expect(consoleError).not.toHaveBeenCalled();
21
+ expect(screen.getByLabelText('time picker')).not.toHaveClass('pf-m-error');
22
+ });
23
+
9
24
  describe('test timepicker onChange method with valid values', () => {
10
25
  const testOnChange = async ({
11
26
  inputProps,
@@ -20,7 +35,7 @@ describe('TimePicker', () => {
20
35
  render(<TimePicker onChange={onChange} {...inputProps} aria-label="time picker" />);
21
36
 
22
37
  await user.type(screen.getByLabelText('time picker'), String(inputProps.value));
23
- expect(onChange).toHaveBeenCalledWith(inputProps.value, expects.hour, expects.minutes, expects.seconds, true)
38
+ expect(onChange).toHaveBeenCalledWith(inputProps.value, expects.hour, expects.minutes, expects.seconds, true);
24
39
  };
25
40
 
26
41
  test('should return the correct value using the AM/PM pattern - midnight', async () => {
@@ -138,6 +138,8 @@ export interface TooltipProps extends Omit<React.HTMLProps<HTMLDivElement>, 'con
138
138
  isAppLauncher?: boolean;
139
139
  /** @deprecated - no longer used */
140
140
  tippyProps?: Partial<TippyProps>;
141
+ /** @beta Opt-in for updated popper that does not use findDOMNode. */
142
+ removeFindDomNode?: boolean;
141
143
  }
142
144
 
143
145
  // id for associating trigger with the content aria-describedby or aria-labelledby
@@ -168,6 +170,7 @@ export const Tooltip: React.FunctionComponent<TooltipProps> = ({
168
170
  boundary,
169
171
  isAppLauncher,
170
172
  tippyProps,
173
+ removeFindDomNode = false,
171
174
  ...rest
172
175
  }: TooltipProps) => {
173
176
  if (process.env.NODE_ENV !== 'production') {
@@ -331,6 +334,7 @@ export const Tooltip: React.FunctionComponent<TooltipProps> = ({
331
334
  enableFlip={enableFlip}
332
335
  zIndex={zIndex}
333
336
  flipBehavior={flipBehavior}
337
+ removeFindDomNode={removeFindDomNode}
334
338
  />
335
339
  );
336
340
  };
@@ -17,3 +17,24 @@ test('tooltip renders', () => {
17
17
  );
18
18
  expect(asFragment()).toMatchSnapshot();
19
19
  });
20
+
21
+ test('tooltip renders in strict mode', () => {
22
+ const consoleError = jest.spyOn(console, 'error');
23
+ const { asFragment } = render(
24
+ <React.StrictMode>
25
+ <Tooltip
26
+ removeFindDomNode
27
+ position="top"
28
+ content={
29
+ <div>
30
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.
31
+ </div>
32
+ }
33
+ >
34
+ <div>Toggle tooltip</div>
35
+ </Tooltip>
36
+ </React.StrictMode>
37
+ );
38
+ expect(consoleError).not.toHaveBeenCalled();
39
+ expect(asFragment()).toMatchSnapshot();
40
+ });
@@ -7,3 +7,13 @@ exports[`tooltip renders 1`] = `
7
7
  </div>
8
8
  </DocumentFragment>
9
9
  `;
10
+
11
+ exports[`tooltip renders in strict mode 1`] = `
12
+ <DocumentFragment>
13
+ <div>
14
+ <div>
15
+ Toggle tooltip
16
+ </div>
17
+ </div>
18
+ </DocumentFragment>
19
+ `;
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { createFocusTrap, Options as FocusTrapOptions, FocusTrap as IFocusTrap } from 'focus-trap';
3
3
 
4
- interface FocusTrapProps extends React.HTMLProps<HTMLDivElement> {
4
+ interface FocusTrapProps extends Omit<React.HTMLProps<HTMLDivElement>, 'ref'> {
5
5
  children: React.ReactNode;
6
6
  className?: string;
7
7
  active?: boolean;
@@ -9,13 +9,15 @@ interface FocusTrapProps extends React.HTMLProps<HTMLDivElement> {
9
9
  focusTrapOptions?: FocusTrapOptions;
10
10
  /** Prevent from scrolling to the previously focused element on deactivation */
11
11
  preventScrollOnDeactivate?: boolean;
12
+ /** @hide Forwarded ref */
13
+ innerRef?: React.Ref<HTMLDivElement>;
12
14
  }
13
15
 
14
- export class FocusTrap extends React.Component<FocusTrapProps> {
16
+ class FocusTrapBase extends React.Component<FocusTrapProps> {
15
17
  static displayName = 'FocusTrap';
16
18
  previouslyFocusedElement: HTMLElement;
17
19
  focusTrap: IFocusTrap;
18
- divRef = React.createRef<HTMLDivElement>();
20
+ divRef = (this.props.innerRef as React.RefObject<HTMLDivElement>) || React.createRef<HTMLDivElement>();
19
21
 
20
22
  static defaultProps = {
21
23
  active: true,
@@ -76,8 +78,18 @@ export class FocusTrap extends React.Component<FocusTrapProps> {
76
78
  }
77
79
 
78
80
  render() {
79
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
80
- const { children, className, focusTrapOptions, active, paused, preventScrollOnDeactivate, ...rest } = this.props;
81
+ const {
82
+ children,
83
+ className,
84
+ /* eslint-disable @typescript-eslint/no-unused-vars */
85
+ focusTrapOptions,
86
+ active,
87
+ paused,
88
+ preventScrollOnDeactivate,
89
+ innerRef,
90
+ /* eslint-enable @typescript-eslint/no-unused-vars */
91
+ ...rest
92
+ } = this.props;
81
93
  return (
82
94
  <div ref={this.divRef} className={className} {...rest}>
83
95
  {children}
@@ -85,3 +97,7 @@ export class FocusTrap extends React.Component<FocusTrapProps> {
85
97
  );
86
98
  }
87
99
  }
100
+
101
+ export const FocusTrap = React.forwardRef((props: FocusTrapProps, ref: React.Ref<any>) => (
102
+ <FocusTrapBase innerRef={ref} {...props} />
103
+ ));
@@ -1,9 +1,9 @@
1
1
  import * as React from 'react';
2
2
  import * as ReactDOM from 'react-dom';
3
- import { FindRefWrapper } from './FindRefWrapper';
4
3
  import { usePopper } from './thirdparty/react-popper/usePopper';
5
4
  import { Placement, BasePlacement, Modifier } from './thirdparty/popper-core';
6
5
  import { css } from '@patternfly/react-styles';
6
+ import { FindRefWrapper } from './FindRefWrapper';
7
7
  import '@patternfly/react-styles/css/components/Popper/Popper.css';
8
8
 
9
9
  const hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' };
@@ -38,6 +38,7 @@ export interface PopperProps {
38
38
  /**
39
39
  * The reference element to which the Popover is relatively placed to.
40
40
  * Use either trigger or reference, not both.
41
+ * Passing this property or the removeFindDomNode property, will bypass the use of findDOMNode for the trigger in react strict mode.
41
42
  */
42
43
  reference?: HTMLElement | (() => HTMLElement) | React.RefObject<any>;
43
44
  /** The popper (menu/tooltip/popover) element */
@@ -122,6 +123,10 @@ export interface PopperProps {
122
123
  | 'right-start'
123
124
  | 'right-end'
124
125
  )[];
126
+ /** @beta Bypasses the use of findDOMNode for both the popper and trigger in react strict mode. Without this flag, the trigger and popper will require passed references via the reference property (trigger) and popperRef property (popper) for strict mode. */
127
+ removeFindDomNode?: boolean;
128
+ /** @beta Reference to the popper (menu/tooltip/popover) element. Passing this property or the removeFindDomNode property, will bypass the use of findDOMNode for the popper in react strict mode. The popper property is still required. */
129
+ popperRef?: HTMLElement | (() => HTMLElement) | React.RefObject<any>;
125
130
  }
126
131
 
127
132
  export const Popper: React.FunctionComponent<PopperProps> = ({
@@ -149,11 +154,13 @@ export const Popper: React.FunctionComponent<PopperProps> = ({
149
154
  onDocumentKeyDown,
150
155
  enableFlip = true,
151
156
  flipBehavior = 'flip',
152
- reference
157
+ reference,
158
+ removeFindDomNode = false,
159
+ popperRef
153
160
  }) => {
154
161
  const [triggerElement, setTriggerElement] = React.useState(null);
155
162
  const [refElement, setRefElement] = React.useState<HTMLElement>(null);
156
- const [popperElement, setPopperElement] = React.useState(null);
163
+ const [popperElement, setPopperElement] = React.useState<HTMLElement>(null);
157
164
  const [ready, setReady] = React.useState(false);
158
165
  const refOrTrigger = refElement || triggerElement;
159
166
  const onDocumentClickCallback = React.useCallback(
@@ -173,6 +180,16 @@ export const Popper: React.FunctionComponent<PopperProps> = ({
173
180
  }
174
181
  }
175
182
  }, [reference]);
183
+ React.useEffect(() => {
184
+ // When the popperRef is defined or the popper visiblity changes, ensure the popper element is up to date
185
+ if (popperRef) {
186
+ if ((popperRef as React.RefObject<any>).current) {
187
+ setPopperElement((popperRef as React.RefObject<any>).current);
188
+ } else if (typeof popperRef === 'function') {
189
+ setPopperElement(popperRef());
190
+ }
191
+ }
192
+ }, [isVisible, popperRef]);
176
193
  const addEventListener = (listener: any, element: Document | HTMLElement, event: string) => {
177
194
  if (listener && element) {
178
195
  element.addEventListener(event, listener);
@@ -305,7 +322,7 @@ export const Popper: React.FunctionComponent<PopperProps> = ({
305
322
  return positionModifiers.top;
306
323
  };
307
324
 
308
- const menuWithPopper = React.cloneElement(popper, {
325
+ const options = {
309
326
  className: css(popper.props && popper.props.className, positionModifiers && modifierFromPopperPosition()),
310
327
  style: {
311
328
  ...((popper.props && popper.props.style) || {}),
@@ -313,7 +330,9 @@ export const Popper: React.FunctionComponent<PopperProps> = ({
313
330
  zIndex
314
331
  },
315
332
  ...attributes.popper
316
- });
333
+ };
334
+
335
+ const menuWithPopper = React.cloneElement(popper, options);
317
336
 
318
337
  const getTarget: () => HTMLElement = () => {
319
338
  if (typeof appendTo === 'function') {
@@ -322,17 +341,40 @@ export const Popper: React.FunctionComponent<PopperProps> = ({
322
341
  return appendTo;
323
342
  };
324
343
 
344
+ /**
345
+ * To enable strict mode, the popper must either have its reference defined via the popperRef property,
346
+ * or the removeFindDomNode flag must be present. Even if the reference is passed in, unlike the trigger,
347
+ * the popper property must still be passed.
348
+ * The trigger must similarly have either its reference defined via the reference property, or the
349
+ * removeFindDomNode flag must be present. The trigger property is not required when the reference is passed.
350
+ *
351
+ * Strict mode may be enabled by passing both reference properties to Popper, or by passing the
352
+ * removeFindDomNode flag with either reference property, or by solely passing the removeFindDomNode
353
+ * flag.
354
+ */
355
+ let popperPortal;
356
+ if (removeFindDomNode) {
357
+ // If removeFindDomNode is passed, use the removeFindDomNode method of wrapping divs
358
+ popperPortal = <div ref={node => setPopperElement(node?.firstElementChild as HTMLElement)}>{menuWithPopper}</div>;
359
+ } else if (popperRef) {
360
+ // If removeFindDomNode is not passed and popperRef is passed, use the popperRef method
361
+ popperPortal = menuWithPopper;
362
+ } else {
363
+ // If neither removeFindDomNode and popperRef exist, use the old method of FindRefWrapper
364
+ popperPortal = (
365
+ <FindRefWrapper onFoundRef={(foundRef: any) => setPopperElement(foundRef)}>{menuWithPopper}</FindRefWrapper>
366
+ );
367
+ }
368
+
325
369
  return (
326
370
  <>
327
- {!reference && trigger && (
371
+ {!reference && trigger && React.isValidElement(trigger) && !removeFindDomNode && (
328
372
  <FindRefWrapper onFoundRef={(foundRef: any) => setTriggerElement(foundRef)}>{trigger}</FindRefWrapper>
329
373
  )}
330
- {ready &&
331
- isVisible &&
332
- ReactDOM.createPortal(
333
- <FindRefWrapper onFoundRef={(foundRef: any) => setPopperElement(foundRef)}>{menuWithPopper}</FindRefWrapper>,
334
- getTarget()
335
- )}
374
+ {!reference && trigger && React.isValidElement(trigger) && removeFindDomNode && (
375
+ <div ref={node => setTriggerElement(node?.firstElementChild as HTMLElement)}>{trigger}</div>
376
+ )}
377
+ {ready && isVisible && ReactDOM.createPortal(popperPortal, getTarget())}
336
378
  </>
337
379
  );
338
380
  };
@@ -56,11 +56,22 @@ import { canUseDOM } from './util';
56
56
  * );
57
57
  * }
58
58
  *
59
+ * Example 3 - With debounced method passed in:
60
+ *
61
+ * public componentDidMount() {
62
+ * this.observer = getResizeObserver(this.inputRef.current, debounce(this.handleResize, 250), false);
63
+ * }
64
+ *
59
65
  * @param {Element} containerRefElement The container reference to observe
60
66
  * @param {Function} handleResize The function to call for resize events
67
+ * @param {boolean} useRequestAnimationFrame Whether to pass the handleResize function as a callback to requestAnimationFrame. Pass in false when the function passed in is debounced. Defaults to true.
61
68
  * @return {Function} The function used to unobserve resize events
62
69
  */
63
- export const getResizeObserver = (containerRefElement: Element, handleResize: () => void) => {
70
+ export const getResizeObserver = (
71
+ containerRefElement: Element,
72
+ handleResize: () => void,
73
+ useRequestAnimationFrame: boolean = true
74
+ ) => {
64
75
  let unobserve: any;
65
76
 
66
77
  if (canUseDOM) {
@@ -69,11 +80,18 @@ export const getResizeObserver = (containerRefElement: Element, handleResize: ()
69
80
  if (containerRefElement && ResizeObserver) {
70
81
  const resizeObserver = new ResizeObserver((entries: any) => {
71
82
  // Wrap resize function in requestAnimationFrame to avoid "ResizeObserver loop limit exceeded" errors
72
- window.requestAnimationFrame(() => {
83
+ if (useRequestAnimationFrame) {
84
+ window.requestAnimationFrame(() => {
85
+ if (Array.isArray(entries) && entries.length > 0) {
86
+ handleResize();
87
+ }
88
+ });
89
+ // Avoid wrapping function in requestAnimationFrame if the function is debounced
90
+ } else {
73
91
  if (Array.isArray(entries) && entries.length > 0) {
74
92
  handleResize();
75
93
  }
76
- });
94
+ }
77
95
  });
78
96
  resizeObserver.observe(containerRefElement);
79
97
  unobserve = () => resizeObserver.unobserve(containerRefElement);