@patternfly/react-core 4.211.2 → 4.211.5

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 (45) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/esm/components/Modal/Modal.d.ts +4 -0
  3. package/dist/esm/components/Modal/Modal.d.ts.map +1 -1
  4. package/dist/esm/components/Modal/Modal.js +2 -2
  5. package/dist/esm/components/Modal/Modal.js.map +1 -1
  6. package/dist/esm/components/Modal/ModalContent.d.ts +4 -0
  7. package/dist/esm/components/Modal/ModalContent.d.ts.map +1 -1
  8. package/dist/esm/components/Modal/ModalContent.js +3 -2
  9. package/dist/esm/components/Modal/ModalContent.js.map +1 -1
  10. package/dist/esm/components/Tooltip/Tooltip.d.ts +6 -0
  11. package/dist/esm/components/Tooltip/Tooltip.d.ts.map +1 -1
  12. package/dist/esm/components/Tooltip/Tooltip.js +2 -2
  13. package/dist/esm/components/Tooltip/Tooltip.js.map +1 -1
  14. package/dist/esm/helpers/Popper/Popper.d.ts.map +1 -1
  15. package/dist/esm/helpers/Popper/Popper.js +7 -6
  16. package/dist/esm/helpers/Popper/Popper.js.map +1 -1
  17. package/dist/js/components/Modal/Modal.d.ts +4 -0
  18. package/dist/js/components/Modal/Modal.d.ts.map +1 -1
  19. package/dist/js/components/Modal/Modal.js +2 -2
  20. package/dist/js/components/Modal/Modal.js.map +1 -1
  21. package/dist/js/components/Modal/ModalContent.d.ts +4 -0
  22. package/dist/js/components/Modal/ModalContent.d.ts.map +1 -1
  23. package/dist/js/components/Modal/ModalContent.js +3 -2
  24. package/dist/js/components/Modal/ModalContent.js.map +1 -1
  25. package/dist/js/components/Tooltip/Tooltip.d.ts +6 -0
  26. package/dist/js/components/Tooltip/Tooltip.d.ts.map +1 -1
  27. package/dist/js/components/Tooltip/Tooltip.js +2 -2
  28. package/dist/js/components/Tooltip/Tooltip.js.map +1 -1
  29. package/dist/js/helpers/Popper/Popper.d.ts.map +1 -1
  30. package/dist/js/helpers/Popper/Popper.js +7 -6
  31. package/dist/js/helpers/Popper/Popper.js.map +1 -1
  32. package/dist/umd/react-core.css +74 -69
  33. package/dist/umd/react-core.js +14 -12
  34. package/dist/umd/react-core.min.css +82 -77
  35. package/dist/umd/react-core.min.js +3 -3
  36. package/package.json +6 -6
  37. package/src/components/Modal/Modal.tsx +8 -0
  38. package/src/components/Modal/ModalContent.tsx +14 -1
  39. package/src/components/Modal/__tests__/Modal.test.tsx +56 -0
  40. package/src/components/Modal/examples/Modal.md +7 -0
  41. package/src/components/Modal/examples/ModalWithOverflowingContent.tsx +71 -0
  42. package/src/components/Tabs/examples/Tabs.md +144 -25
  43. package/src/components/Tooltip/Tooltip.tsx +8 -0
  44. package/src/components/Tooltip/examples/Tooltip.md +86 -41
  45. package/src/helpers/Popper/Popper.tsx +10 -7
@@ -12,6 +12,7 @@ import './TooltipExamples.css';
12
12
  ## Examples
13
13
 
14
14
  ### Basic
15
+
15
16
  ```js
16
17
  import React from 'react';
17
18
  import { Tooltip } from '@patternfly/react-core';
@@ -22,12 +23,15 @@ import { Tooltip } from '@patternfly/react-core';
22
23
  <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.</div>
23
24
  }
24
25
  >
25
- <span tabIndex="0" style={{ border: '1px dashed' }}>I have a tooltip!</span>
26
+ <span tabIndex="0" style={{ border: '1px dashed' }}>
27
+ I have a tooltip!
28
+ </span>
26
29
  </Tooltip>
27
- </div>
30
+ </div>;
28
31
  ```
29
32
 
30
33
  ### Tooltip react ref
34
+
31
35
  ```js
32
36
  import React from 'react';
33
37
  import { Tooltip } from '@patternfly/react-core';
@@ -36,35 +40,49 @@ TooltipReactRef = () => {
36
40
  const tooltipRef = React.useRef();
37
41
  return (
38
42
  <div style={{ margin: '100px' }}>
39
- <button ref={tooltipRef}>Tooltip attached via react ref</button>
43
+ <button aria-describedby="tooltip-ref1" ref={tooltipRef}>
44
+ Tooltip attached via react ref
45
+ </button>
40
46
  <Tooltip
47
+ id="tooltip-ref1"
41
48
  content={
42
- <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.</div>
49
+ <div>
50
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.
51
+ </div>
43
52
  }
44
53
  reference={tooltipRef}
45
54
  />
46
55
  </div>
47
56
  );
48
- }
57
+ };
49
58
  ```
50
59
 
51
60
  ### Tooltip selector ref
61
+
52
62
  ```js
53
63
  import React from 'react';
54
64
  import { Tooltip } from '@patternfly/react-core';
55
65
 
56
66
  <div style={{ margin: '100px' }}>
57
- <button id="tooltip-selector">Tooltip attached via selector ref</button>
67
+ <button aria-describedby="tooltip-ref2" id="tooltip-selector">
68
+ Tooltip attached via selector ref
69
+ </button>
58
70
  <Tooltip
71
+ id="tooltip-ref2"
59
72
  content={
60
73
  <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.</div>
61
74
  }
62
75
  reference={() => document.getElementById('tooltip-selector')}
63
76
  />
64
- </div>
77
+ </div>;
65
78
  ```
66
79
 
67
- ### On icon
80
+ ### On icon with dynamic content
81
+
82
+ When the tooltip is used as a wrapper and its content will dynamically update, the `aria` prop should have a value of "none" passed in. This prevents assistive technologies from announcing the tooltip contents more than once. Additionally, the `aria-live` prop should have a value of "polite" passed in, in order for assistive technologies to announce when the tooltip contents gets updated.
83
+
84
+ When using a React or selector ref with a tooltip that has dynamic content, the `aria` and `aria-live` props do not need to be manually passed in.
85
+
68
86
  ```js
69
87
  import React from 'react';
70
88
  import { Tooltip, Button } from '@patternfly/react-core';
@@ -77,8 +95,13 @@ IconExample = () => {
77
95
  const [content, setContent] = React.useState(copyText);
78
96
  return (
79
97
  <div style={{ margin: '100px' }}>
80
- <Tooltip content={showSuccessContent ? doneCopyText : copyText}>
81
- <Button variant="plain" aria-label="Icon with tooltip attached" id="tt-ref" onClick={() => setShowSuccessContent(!showSuccessContent)}>
98
+ <Tooltip aria="none" aria-live="polite" content={showSuccessContent ? doneCopyText : copyText}>
99
+ <Button
100
+ aria-label="Clipboard"
101
+ variant="plain"
102
+ id="tt-ref"
103
+ onClick={() => setShowSuccessContent(!showSuccessContent)}
104
+ >
82
105
  <CopyIcon />
83
106
  </Button>
84
107
  </Tooltip>
@@ -88,6 +111,7 @@ IconExample = () => {
88
111
  ```
89
112
 
90
113
  ### Options
114
+
91
115
  ```js
92
116
  import React from 'react';
93
117
  import { Button, Tooltip, Checkbox, Select, SelectOption, TextInput } from '@patternfly/react-core';
@@ -105,26 +129,26 @@ OptionsTooltip = () => {
105
129
  const [exitDelayInput, setExitDelayInput] = React.useState(0);
106
130
  const [animationDuration, setAnimationDuration] = React.useState(300);
107
131
  const tipBoxRef = React.useRef(null);
108
-
132
+
109
133
  const scrollToRef = ref => {
110
134
  if (ref && ref.current) {
111
135
  ref.current.scrollTop = 400;
112
136
  ref.current.scrollLeft = 300;
113
137
  }
114
- }
115
-
138
+ };
139
+
116
140
  React.useEffect(() => {
117
141
  scrollToRef(tipBoxRef);
118
142
  }, []);
119
-
143
+
120
144
  return (
121
145
  <>
122
146
  <div>
123
- <div style={{ border: '1px solid'}}>
147
+ <div style={{ border: '1px solid' }}>
124
148
  <Checkbox
125
149
  label="trigger: mouseenter"
126
150
  isChecked={trigger.includes('mouseenter')}
127
- onChange={(checked) => {
151
+ onChange={checked => {
128
152
  let updatedTrigger;
129
153
  checked && (updatedTrigger = trigger.concat('mouseenter'));
130
154
  !checked && (updatedTrigger = trigger.filter(t => t !== 'mouseenter'));
@@ -137,7 +161,7 @@ OptionsTooltip = () => {
137
161
  <Checkbox
138
162
  label="trigger: focus"
139
163
  isChecked={trigger.includes('focus')}
140
- onChange={(checked) => {
164
+ onChange={checked => {
141
165
  let updatedTrigger;
142
166
  checked && (updatedTrigger = trigger.concat('focus'));
143
167
  !checked && (updatedTrigger = trigger.filter(t => t !== 'focus'));
@@ -150,7 +174,7 @@ OptionsTooltip = () => {
150
174
  <Checkbox
151
175
  label="trigger: click"
152
176
  isChecked={trigger.includes('click')}
153
- onChange={(checked) => {
177
+ onChange={checked => {
154
178
  let updatedTrigger;
155
179
  checked && (updatedTrigger = trigger.concat('click'));
156
180
  !checked && (updatedTrigger = trigger.filter(t => t !== 'click'));
@@ -163,36 +187,36 @@ OptionsTooltip = () => {
163
187
  <Checkbox
164
188
  label="trigger: manual"
165
189
  isChecked={trigger.includes('manual')}
166
- onChange={(checked) => {
190
+ onChange={checked => {
167
191
  let updatedTrigger;
168
192
  checked && (updatedTrigger = trigger.concat('manual'));
169
193
  !checked && (updatedTrigger = trigger.filter(t => t !== 'manual'));
170
194
  setIsVisible(false);
171
195
  setTrigger(updatedTrigger);
172
196
  }}
173
- aria-label="trigger: manual"
174
- id="trigger_manual"
197
+ aria-label="trigger: manual"
198
+ id="trigger_manual"
175
199
  />
176
200
  </div>
177
- <div style={{ border: '1px solid'}}>
201
+ <div style={{ border: '1px solid' }}>
178
202
  <Checkbox
179
203
  label="content left-aligned"
180
204
  isChecked={contentLeftAligned}
181
- onChange={(checked) => setContentLeftAligned(checked)}
205
+ onChange={checked => setContentLeftAligned(checked)}
182
206
  aria-label="content left-aligned"
183
- id="content_left_aligned"
207
+ id="content_left_aligned"
184
208
  />
185
209
  </div>
186
- <div style={{ border: '1px solid'}}>
210
+ <div style={{ border: '1px solid' }}>
187
211
  <Checkbox
188
212
  label="enableFlip"
189
213
  isChecked={enableFlip}
190
- onChange={(checked) => setEnableFlip(checked)}
191
- aria-label="enableFlip"
192
- id="enable_flip"
214
+ onChange={checked => setEnableFlip(checked)}
215
+ aria-label="enableFlip"
216
+ id="enable_flip"
193
217
  />
194
218
  </div>
195
- <div style={{ border: '1px solid'}}>
219
+ <div style={{ border: '1px solid' }}>
196
220
  position (will flip if enableFlip is true). The 'auto' position requires enableFlip to be set to true.
197
221
  <Select
198
222
  onToggle={() => setPositionSelectOpen(!positionSelectOpen)}
@@ -219,22 +243,41 @@ OptionsTooltip = () => {
219
243
  <SelectOption value="right-end" />
220
244
  </Select>
221
245
  </div>
222
- <div style={{ border: '1px solid'}}>
246
+ <div style={{ border: '1px solid' }}>
223
247
  <Checkbox
224
248
  label="isVisible (also set trigger to only manual to programmatically control it)"
225
249
  isChecked={isVisible}
226
- onChange={(checked) => setIsVisible(checked)}
227
- aria-label="isVisible"
228
- id="is_visible"
250
+ onChange={checked => setIsVisible(checked)}
251
+ aria-label="isVisible"
252
+ id="is_visible"
229
253
  />
230
254
  </div>
231
- <div style={{ border: '1px solid'}}>
232
- Entry delay (ms) <TextInput value={entryDelayInput} type="number" onChange={val => setEntryDelayInput(val)} aria-label="entry delay" />
233
- Exit delay (ms) <TextInput value={exitDelayInput} type="number" onChange={val => setExitDelayInput(val)} aria-label="exit delay" />
234
- Animation duration (ms) <TextInput value={animationDuration} type="number" onChange={val => setAnimationDuration(val)} aria-label="animation duration" />
255
+ <div style={{ border: '1px solid' }}>
256
+ Entry delay (ms){' '}
257
+ <TextInput
258
+ value={entryDelayInput}
259
+ type="number"
260
+ onChange={val => setEntryDelayInput(val)}
261
+ aria-label="entry delay"
262
+ />
263
+ Exit delay (ms) <TextInput
264
+ value={exitDelayInput}
265
+ type="number"
266
+ onChange={val => setExitDelayInput(val)}
267
+ aria-label="exit delay"
268
+ />
269
+ Animation duration (ms){' '}
270
+ <TextInput
271
+ value={animationDuration}
272
+ type="number"
273
+ onChange={val => setAnimationDuration(val)}
274
+ aria-label="animation duration"
275
+ />
235
276
  </div>
236
- <div style={{ border: '1px solid'}}>
237
- flip behavior examples (enableFlip has to be true). "flip" will try to flip the tooltip to the opposite of the starting position. The second option ensures that there are 3 escape positions for every possible starting position (default). This setting is ignored if position prop is set to 'auto'.
277
+ <div style={{ border: '1px solid' }}>
278
+ flip behavior examples (enableFlip has to be true). "flip" will try to flip the tooltip to the opposite of the
279
+ starting position. The second option ensures that there are 3 escape positions for every possible starting
280
+ position (default). This setting is ignored if position prop is set to 'auto'.
238
281
  <Select
239
282
  onToggle={() => setFlipSelectOpen(!flipSelectOpen)}
240
283
  onSelect={(event, selection) => {
@@ -254,7 +297,9 @@ OptionsTooltip = () => {
254
297
  <div id="tooltip-boundary" className="tooltip-box" ref={tipBoxRef}>
255
298
  <Tooltip
256
299
  content={
257
- <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.</div>
300
+ <div>
301
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.
302
+ </div>
258
303
  }
259
304
  trigger={trigger.join(' ')}
260
305
  enableFlip={enableFlip}
@@ -272,5 +317,5 @@ OptionsTooltip = () => {
272
317
  </div>
273
318
  </>
274
319
  );
275
- }
320
+ };
276
321
  ```
@@ -165,6 +165,7 @@ export const Popper: React.FunctionComponent<PopperProps> = ({
165
165
  element.removeEventListener(event, listener);
166
166
  }
167
167
  };
168
+
168
169
  React.useEffect(() => {
169
170
  addEventListener(onMouseEnter, refOrTrigger, 'mouseenter');
170
171
  addEventListener(onMouseLeave, refOrTrigger, 'mouseleave');
@@ -175,6 +176,13 @@ export const Popper: React.FunctionComponent<PopperProps> = ({
175
176
  addEventListener(onPopperClick, popperElement, 'click');
176
177
  onDocumentClick && addEventListener(onDocumentClickCallback, document, 'click');
177
178
  addEventListener(onDocumentKeyDown, document, 'keydown');
179
+
180
+ // Trigger a Popper update when content changes.
181
+ const observer = new MutationObserver(() => {
182
+ update && update();
183
+ });
184
+ popperElement && observer.observe(popperElement, { attributes: true, childList: true, subtree: true });
185
+
178
186
  return () => {
179
187
  removeEventListener(onMouseEnter, refOrTrigger, 'mouseenter');
180
188
  removeEventListener(onMouseLeave, refOrTrigger, 'mouseleave');
@@ -185,6 +193,7 @@ export const Popper: React.FunctionComponent<PopperProps> = ({
185
193
  removeEventListener(onPopperClick, popperElement, 'click');
186
194
  onDocumentClick && removeEventListener(onDocumentClickCallback, document, 'click');
187
195
  removeEventListener(onDocumentKeyDown, document, 'keydown');
196
+ observer.disconnect();
188
197
  };
189
198
  }, [
190
199
  triggerElement,
@@ -233,7 +242,7 @@ export const Popper: React.FunctionComponent<PopperProps> = ({
233
242
  [popperMatchesTriggerWidth]
234
243
  );
235
244
 
236
- const { styles: popperStyles, attributes, forceUpdate } = usePopper(refOrTrigger, popperElement, {
245
+ const { styles: popperStyles, attributes, update } = usePopper(refOrTrigger, popperElement, {
237
246
  placement: getPlacementMemo,
238
247
  modifiers: [
239
248
  {
@@ -262,12 +271,6 @@ export const Popper: React.FunctionComponent<PopperProps> = ({
262
271
  ]
263
272
  });
264
273
 
265
- // force update when content changes
266
- // https://github.com/patternfly/patternfly-react/issues/5620
267
- React.useEffect(() => {
268
- forceUpdate && forceUpdate();
269
- }, [popper]);
270
-
271
274
  // Returns the CSS modifier class in order to place the Popper's arrow properly
272
275
  // Depends on the position of the Popper relative to the reference element
273
276
  const modifierFromPopperPosition = () => {