@openedx/paragon 22.0.0-alpha.23 → 22.0.0-alpha.24

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 (135) hide show
  1. package/dist/Button/index.js +2 -2
  2. package/dist/Button/index.js.map +1 -1
  3. package/dist/Button/index.scss +3 -3
  4. package/dist/ColorPicker/index.js +48 -18
  5. package/dist/ColorPicker/index.js.map +1 -1
  6. package/dist/Container/index.js +6 -2
  7. package/dist/Container/index.js.map +1 -1
  8. package/dist/DataTable/index.js +2 -1
  9. package/dist/DataTable/index.js.map +1 -1
  10. package/dist/DataTable/selection/BaseSelectionStatus.js +3 -2
  11. package/dist/DataTable/selection/BaseSelectionStatus.js.map +1 -1
  12. package/dist/Dropdown/index.js.map +1 -1
  13. package/dist/Dropzone/index.js +2 -3
  14. package/dist/Dropzone/index.js.map +1 -1
  15. package/dist/Form/FormAutosuggest.js +9 -4
  16. package/dist/Form/FormAutosuggest.js.map +1 -1
  17. package/dist/Form/FormSwitch.js +3 -0
  18. package/dist/Form/FormSwitch.js.map +1 -1
  19. package/dist/Hyperlink/index.js +7 -6
  20. package/dist/Hyperlink/index.js.map +1 -1
  21. package/dist/Icon/index.js +18 -11
  22. package/dist/Icon/index.js.map +1 -1
  23. package/dist/IconButton/index.js +1 -1
  24. package/dist/IconButton/index.js.map +1 -1
  25. package/dist/Layout/index.js.map +1 -1
  26. package/dist/Menu/MenuItem.js +2 -2
  27. package/dist/Menu/MenuItem.js.map +1 -1
  28. package/dist/Modal/ModalDialog.js +3 -0
  29. package/dist/Modal/ModalDialog.js.map +1 -1
  30. package/dist/Popover/index.js +8 -8
  31. package/dist/Popover/index.js.map +1 -1
  32. package/dist/ProductTour/Checkpoint.js +10 -8
  33. package/dist/ProductTour/Checkpoint.js.map +1 -1
  34. package/dist/ProductTour/messages.js +16 -0
  35. package/dist/SearchField/SearchFieldAdvanced.js +12 -7
  36. package/dist/SearchField/SearchFieldAdvanced.js.map +1 -1
  37. package/dist/SearchField/SearchFieldLabel.js +3 -3
  38. package/dist/SearchField/SearchFieldLabel.js.map +1 -1
  39. package/dist/SearchField/index.js +0 -1
  40. package/dist/SearchField/index.js.map +1 -1
  41. package/dist/Tabs/index.js +13 -13
  42. package/dist/Tabs/index.js.map +1 -1
  43. package/dist/core.css +8 -6
  44. package/dist/core.css.map +1 -1
  45. package/dist/core.min.css +1 -1
  46. package/dist/hooks/useIndexOfLastVisibleChild.js +33 -38
  47. package/dist/hooks/useIndexOfLastVisibleChild.js.map +1 -1
  48. package/dist/i18n/messages/ar.json +2 -1
  49. package/dist/i18n/messages/ca.json +2 -1
  50. package/dist/i18n/messages/es_419.json +2 -1
  51. package/dist/i18n/messages/es_AR.json +2 -1
  52. package/dist/i18n/messages/es_ES.json +2 -1
  53. package/dist/i18n/messages/fr.json +2 -1
  54. package/dist/i18n/messages/he.json +2 -1
  55. package/dist/i18n/messages/id.json +2 -1
  56. package/dist/i18n/messages/it_IT.json +2 -1
  57. package/dist/i18n/messages/ko_KR.json +2 -1
  58. package/dist/i18n/messages/pl.json +2 -1
  59. package/dist/i18n/messages/pt_BR.json +2 -1
  60. package/dist/i18n/messages/pt_PT.json +2 -1
  61. package/dist/i18n/messages/ru.json +2 -1
  62. package/dist/i18n/messages/th.json +2 -1
  63. package/dist/i18n/messages/tr_TR.json +2 -1
  64. package/dist/i18n/messages/uk.json +2 -1
  65. package/dist/i18n/messages/zh_CN.json +2 -1
  66. package/dist/light.css +11 -11
  67. package/dist/light.css.map +1 -1
  68. package/dist/light.min.css +1 -1
  69. package/icons/es5/RightSidebarFilled.js +15 -0
  70. package/icons/es5/RightSidebarOutlined.js +15 -0
  71. package/icons/es5/index.js +2 -0
  72. package/icons/jsx/RightSidebarFilled.jsx +19 -0
  73. package/icons/jsx/RightSidebarOutlined.jsx +19 -0
  74. package/icons/jsx/index.jsx +2 -0
  75. package/icons/svg/right_sidebar_filled.svg +3 -0
  76. package/icons/svg/right_sidebar_outlined.svg +3 -0
  77. package/package.json +3 -3
  78. package/src/Button/README.md +94 -68
  79. package/src/Button/index.jsx +2 -2
  80. package/src/Button/index.scss +3 -3
  81. package/src/ColorPicker/ColorPicker.test.jsx +24 -2
  82. package/src/ColorPicker/index.jsx +56 -16
  83. package/src/Container/index.jsx +4 -0
  84. package/src/DataTable/README.md +3 -3
  85. package/src/DataTable/index.jsx +2 -1
  86. package/src/DataTable/selection/BaseSelectionStatus.jsx +2 -2
  87. package/src/DataTable/tablefilters.mdx +3 -3
  88. package/src/DataTable/tests/DataTable.test.jsx +31 -0
  89. package/src/Dropdown/index.jsx +4 -0
  90. package/src/Dropzone/index.jsx +2 -3
  91. package/src/Form/FormAutosuggest.jsx +11 -5
  92. package/src/Form/FormSwitch.jsx +3 -0
  93. package/src/Form/form-autosuggest.mdx +80 -72
  94. package/src/Form/tests/FormAutosuggest.test.jsx +21 -0
  95. package/src/Hyperlink/index.jsx +7 -6
  96. package/src/Icon/index.jsx +18 -11
  97. package/src/IconButton/index.jsx +1 -1
  98. package/src/Layout/index.jsx +1 -4
  99. package/src/Menu/MenuItem.jsx +2 -2
  100. package/src/Modal/ModalDialog.jsx +3 -0
  101. package/src/Overlay/README.md +1 -1
  102. package/src/Popover/README.md +0 -1
  103. package/src/Popover/index.jsx +11 -11
  104. package/src/ProductTour/Checkpoint.jsx +9 -6
  105. package/src/ProductTour/messages.js +16 -0
  106. package/src/SearchField/SearchFieldAdvanced.jsx +12 -7
  107. package/src/SearchField/SearchFieldLabel.jsx +3 -3
  108. package/src/SearchField/index.jsx +0 -1
  109. package/src/SelectableBox/tests/SelectableBoxSet.test.jsx +1 -1
  110. package/src/Tabs/index.jsx +19 -13
  111. package/src/hooks/tests/useIndexOfLastVisibleChild.test.jsx +3 -3
  112. package/src/hooks/useIndexOfLastVisibleChild.jsx +36 -38
  113. package/src/hooks/useIndexOfLastVisibleChild.mdx +3 -3
  114. package/src/i18n/messages/ar.json +2 -1
  115. package/src/i18n/messages/ca.json +2 -1
  116. package/src/i18n/messages/es_419.json +2 -1
  117. package/src/i18n/messages/es_AR.json +2 -1
  118. package/src/i18n/messages/es_ES.json +2 -1
  119. package/src/i18n/messages/fr.json +2 -1
  120. package/src/i18n/messages/he.json +2 -1
  121. package/src/i18n/messages/id.json +2 -1
  122. package/src/i18n/messages/it_IT.json +2 -1
  123. package/src/i18n/messages/ko_KR.json +2 -1
  124. package/src/i18n/messages/pl.json +2 -1
  125. package/src/i18n/messages/pt_BR.json +2 -1
  126. package/src/i18n/messages/pt_PT.json +2 -1
  127. package/src/i18n/messages/ru.json +2 -1
  128. package/src/i18n/messages/th.json +2 -1
  129. package/src/i18n/messages/tr_TR.json +2 -1
  130. package/src/i18n/messages/uk.json +2 -1
  131. package/src/i18n/messages/zh_CN.json +2 -1
  132. package/styles/css/core/variables.css +5 -3
  133. package/styles/css/themes/light/variables.css +11 -11
  134. package/tokens/src/core/components/Button/core.json +8 -4
  135. package/tokens/src/themes/light/alias/color.json +10 -10
@@ -6,6 +6,8 @@ import { IntlProvider } from 'react-intl';
6
6
 
7
7
  import DataTable from '..';
8
8
  import DataTableContext from '../DataTableContext';
9
+ import { TextFilter } from '../..';
10
+ import { SELECT_ALL_TEST_ID } from '../selection/data/constants';
9
11
 
10
12
  const additionalColumns = [
11
13
  {
@@ -198,6 +200,35 @@ describe('<DataTable />', () => {
198
200
 
199
201
  expect(spinner).toBeTruthy();
200
202
  });
203
+ it('displays the total number of items when applying filter and selecting all items', async () => {
204
+ const propsWithSelection = {
205
+ ...props,
206
+ isSelectable: true,
207
+ isFilterable: true,
208
+ manualFilters: true,
209
+ defaultColumnValues: { Filter: TextFilter },
210
+ isPaginated: true,
211
+ initialState: { pageSize: 3, pageIndex: 0 },
212
+ pageCount: 3,
213
+ fetchData: jest.fn(),
214
+ };
215
+
216
+ render(<DataTableWrapper {...propsWithSelection} />);
217
+ const filtersButton = screen.getByRole('button', { name: 'Filters' });
218
+
219
+ await userEvent.click(filtersButton);
220
+
221
+ const searchFormControl = screen.getByPlaceholderText('Search coat color');
222
+ await userEvent.type(searchFormControl, 'brown tabby');
223
+
224
+ const selectAllCheckBox = screen.getByTitle('Toggle All Current Page Rows Selected');
225
+ await userEvent.click(selectAllCheckBox);
226
+
227
+ const selectAllButton = screen.getByTestId(SELECT_ALL_TEST_ID);
228
+ // A filtered array is returned from the backend,
229
+ // and the element counter displays its length.
230
+ expect(selectAllButton).toHaveTextContent('Select all 7');
231
+ });
201
232
 
202
233
  describe('[legacy] controlled table selections', () => {
203
234
  it('passes initial controlledTableSelections to context', async () => {
@@ -68,6 +68,7 @@ const Dropdown = React.forwardRef(
68
68
  );
69
69
  },
70
70
  );
71
+
71
72
  Dropdown.propTypes = {
72
73
  autoClose: PropTypes.oneOfType([
73
74
  PropTypes.string,
@@ -78,6 +79,7 @@ Dropdown.propTypes = {
78
79
  show: PropTypes.bool,
79
80
  variant: PropTypes.oneOf(['light', 'dark']),
80
81
  };
82
+
81
83
  Dropdown.defaultProps = {
82
84
  autoClose: true,
83
85
  className: '',
@@ -126,9 +128,11 @@ Dropdown.Item = React.forwardRef(
126
128
  );
127
129
  },
128
130
  );
131
+
129
132
  Dropdown.Item.propTypes = {
130
133
  className: PropTypes.string,
131
134
  };
135
+
132
136
  Dropdown.Item.defaultProps = {
133
137
  className: undefined,
134
138
  };
@@ -178,8 +178,7 @@ function Dropzone({
178
178
  <div
179
179
  data-testid="dropzone-container"
180
180
  {...getRootProps({
181
- className: classNames('pgn__dropzone', {
182
- className,
181
+ className: classNames('pgn__dropzone', className, {
183
182
  'pgn__dropzone-validation-error': isMultipleDragged || errors.length > 0 || isDragReject,
184
183
  'pgn__dropzone-active': isDragActive && !isDragReject,
185
184
  }),
@@ -271,7 +270,7 @@ Dropzone.propTypes = {
271
270
  */
272
271
  validator: PropTypes.func,
273
272
  /** A component to display initial state of the `Dropzone`. */
274
- inputComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
273
+ inputComponent: PropTypes.oneOfType([PropTypes.elementType, PropTypes.node]),
275
274
  };
276
275
 
277
276
  export default Dropzone;
@@ -6,7 +6,7 @@ import { v4 as uuidv4 } from 'uuid';
6
6
  import { useIntl } from 'react-intl';
7
7
  import { KeyboardArrowUp, KeyboardArrowDown } from '../../icons';
8
8
  import Icon from '../Icon';
9
- import FormGroup from './FormGroup';
9
+ import { FormGroupContextProvider, useFormGroupContext } from './FormGroupContext';
10
10
  import FormControl from './FormControl';
11
11
  import FormControlFeedback from './FormControlFeedback';
12
12
  import IconButton from '../IconButton';
@@ -239,12 +239,18 @@ function FormAutosuggest({
239
239
  setDisplayValue(e.target.value);
240
240
  };
241
241
 
242
+ const { getControlProps } = useFormGroupContext();
243
+ const controlProps = getControlProps(props);
244
+
242
245
  return (
243
246
  <div className="pgn__form-autosuggest__wrapper" ref={parentRef}>
244
247
  <div aria-live="assertive" className="sr-only" data-testid="autosuggest-screen-reader-options-count">
245
248
  {`${state.dropDownItems.length} options found`}
246
249
  </div>
247
- <FormGroup isInvalid={!!state.errorMessage}>
250
+ <FormGroupContextProvider
251
+ controlId={controlProps.id}
252
+ isInvalid={!!state.errorMessage}
253
+ >
248
254
  <FormControl
249
255
  ref={formControlRef}
250
256
  aria-expanded={(state.dropDownItems.length > 0).toString()}
@@ -259,7 +265,7 @@ function FormAutosuggest({
259
265
  onClick={handleClick}
260
266
  trailingElement={iconToggle}
261
267
  data-testid="autosuggest-textbox-input"
262
- {...props}
268
+ {...controlProps}
263
269
  />
264
270
 
265
271
  {helpMessage && !state.errorMessage && (
@@ -269,11 +275,11 @@ function FormAutosuggest({
269
275
  )}
270
276
 
271
277
  {state.errorMessage && (
272
- <FormControlFeedback type="invalid" feedback-for={props.name}>
278
+ <FormControlFeedback type="invalid" feedback-for={controlProps.name}>
273
279
  {errorMessageText}
274
280
  </FormControlFeedback>
275
281
  )}
276
- </FormGroup>
282
+ </FormGroupContextProvider>
277
283
 
278
284
  <ul
279
285
  id="pgn__form-autosuggest__dropdown-box"
@@ -79,8 +79,11 @@ FormSwitch.propTypes = {
79
79
  children: PropTypes.node.isRequired,
80
80
  /** Specifies class name to append to the base element. */
81
81
  className: PropTypes.string,
82
+ /** Specifies class name to append to the label element. */
82
83
  labelClassName: PropTypes.string,
84
+ /** Specifies helper text to display below the switch. */
83
85
  helperText: PropTypes.node,
86
+ /** Determines whether the label should float to the left when the switch is active. */
84
87
  floatLabelLeft: PropTypes.bool,
85
88
  };
86
89
 
@@ -19,93 +19,101 @@ Form auto-suggest enables users to manually select or type to find matching opti
19
19
 
20
20
  ```jsx live
21
21
  () => {
22
- const [selected, setSelected] = useState('');
22
+ const [selected, setSelected] = useState('');
23
23
 
24
- return (
25
- <Form.Autosuggest
26
- floatingLabel="Programming language"
27
- aria-label="form autosuggest"
28
- helpMessage="Select language"
29
- errorMessageText="Error, no selected value"
30
- value={selected}
31
- onSelected={(value) => setSelected(value)}
32
- >
33
- <Form.AutosuggestOption>JavaScript</Form.AutosuggestOption>
34
- <Form.AutosuggestOption>Python</Form.AutosuggestOption>
35
- <Form.AutosuggestOption>Rube</Form.AutosuggestOption>
36
- <Form.AutosuggestOption onClick={(e) => alert(e.currentTarget.getAttribute('data-value'))}>
37
- Option with custom onClick
38
- </Form.AutosuggestOption>
39
- </Form.Autosuggest>
40
- );
41
- }
24
+ return (
25
+ <Form.Group>
26
+ <Form.Label>
27
+ <h4>Programming language</h4>
28
+ </Form.Label>
29
+ <Form.Autosuggest
30
+ aria-label="form autosuggest"
31
+ helpMessage="Select language"
32
+ errorMessageText="Error, no selected value"
33
+ value={selected}
34
+ onSelected={(value) => setSelected(value)}
35
+ >
36
+ <Form.AutosuggestOption>JavaScript</Form.AutosuggestOption>
37
+ <Form.AutosuggestOption>Python</Form.AutosuggestOption>
38
+ <Form.AutosuggestOption>Rube</Form.AutosuggestOption>
39
+ <Form.AutosuggestOption onClick={(e) => alert(e.currentTarget.getAttribute('data-value'))}>
40
+ Option with custom onClick
41
+ </Form.AutosuggestOption>
42
+ </Form.Autosuggest>
43
+ </Form.Group>
44
+ );
45
+ };
42
46
  ```
43
47
 
44
48
  ## Search Usage
45
49
 
46
50
  ```jsx live
47
51
  () => {
48
- const [selected, setSelected] = useState('');
52
+ const [selected, setSelected] = useState('');
49
53
 
50
- return (
51
- <Form.Autosuggest
52
- placeholder="Type 'T'"
53
- aria-label="form autosuggest"
54
- errorMessageText="Error, no selected value"
55
- helpMessage="Select language"
56
- value={selected}
57
- onSelected={(value) => setSelected(value)}
58
- >
59
- <Form.AutosuggestOption>PHP</Form.AutosuggestOption>
60
- <Form.AutosuggestOption>Java</Form.AutosuggestOption>
61
- <Form.AutosuggestOption>Turbo Pascal</Form.AutosuggestOption>
62
- <Form.AutosuggestOption>Flask</Form.AutosuggestOption>
63
- </Form.Autosuggest>
64
- );
65
- }
54
+ return (
55
+ <Form.Autosuggest
56
+ placeholder="Type 'T'"
57
+ aria-label="form autosuggest"
58
+ errorMessageText="Error, no selected value"
59
+ helpMessage="Select language"
60
+ value={selected}
61
+ onSelected={(value) => setSelected(value)}
62
+ >
63
+ <Form.AutosuggestOption>PHP</Form.AutosuggestOption>
64
+ <Form.AutosuggestOption>Java</Form.AutosuggestOption>
65
+ <Form.AutosuggestOption>Turbo Pascal</Form.AutosuggestOption>
66
+ <Form.AutosuggestOption>Flask</Form.AutosuggestOption>
67
+ </Form.Autosuggest>
68
+ );
69
+ };
66
70
  ```
67
71
 
68
72
  ## Loading state
69
73
 
70
74
  ```jsx live
71
75
  () => {
72
- const [data, setData] = useState([]);
73
- const [showLoading, setShowLoading] = useState(false);
76
+ const [data, setData] = useState([]);
77
+ const [showLoading, setShowLoading] = useState(false);
74
78
 
75
- useEffect(() => {
76
- setShowLoading(true);
77
- fetch('https://api.sampleapis.com/coffee/hot')
78
- .then(data => data.json())
79
- .then(items => {
80
- setTimeout(() => {
81
- setData(items);
82
- setShowLoading(false);
83
- }, 1500);
84
- });
85
- }, [])
79
+ useEffect(() => {
80
+ setShowLoading(true);
81
+ fetch('https://api.sampleapis.com/coffee/hot')
82
+ .then(data => data.json())
83
+ .then(items => {
84
+ setTimeout(() => {
85
+ setData(items);
86
+ setShowLoading(false);
87
+ }, 1500);
88
+ });
89
+ }, []);
86
90
 
87
- const searchCoffee = (title) => {
88
- setShowLoading(true);
89
- fetch('https://api.sampleapis.com/coffee/hot')
90
- .then(data => data.json())
91
- .then(items => setTimeout(() => {
92
- const filteredCoffee = items.filter(res => res.title.toLowerCase().includes(title.toLowerCase()));
93
- setShowLoading(false);
94
- if (filteredCoffee) { return filteredCoffee }
95
- return { ...title, filteredCoffee }
96
- }, 1500));
97
- };
91
+ const searchCoffee = (title) => {
92
+ setShowLoading(true);
93
+ fetch('https://api.sampleapis.com/coffee/hot')
94
+ .then(data => data.json())
95
+ .then(items => setTimeout(() => {
96
+ const filteredCoffee = items.filter(res => res.title.toLowerCase().includes(title.toLowerCase()));
97
+ setShowLoading(false);
98
+ if (filteredCoffee) { return filteredCoffee; }
99
+ return { ...title, filteredCoffee };
100
+ }, 1500));
101
+ };
98
102
 
99
- return (
100
- <Form.Autosuggest
101
- isLoading={showLoading}
102
- placeholder="This is placeholder"
103
- floatingLabel="This is floating label"
104
- screenReaderText="Loading..."
105
- onChange={searchCoffee}
106
- >
107
- {data.map((item, index) => <Form.AutosuggestOption key={index}>{item.title}</Form.AutosuggestOption>)}
108
- </Form.Autosuggest>
109
- );
110
- }
103
+ return (
104
+ <Form.Group>
105
+ <Form.Label>
106
+ <h4>Café API</h4>
107
+ </Form.Label>
108
+ <Form.Autosuggest
109
+ isLoading={showLoading}
110
+ placeholder="This is placeholder"
111
+ screenReaderText="Loading..."
112
+ onChange={searchCoffee}
113
+ >
114
+ {data.map((item, index) => <Form.AutosuggestOption key={index}>{item.title}</Form.AutosuggestOption>)}
115
+ </Form.Autosuggest>
116
+ </Form.Group>
117
+ );
118
+ };
111
119
  ```
@@ -6,6 +6,8 @@ import userEvent from '@testing-library/user-event';
6
6
  import { IntlProvider } from 'react-intl';
7
7
  import FormAutosuggest from '../FormAutosuggest';
8
8
  import FormAutosuggestOption from '../FormAutosuggestOption';
9
+ import FormGroup from '../FormGroup';
10
+ import FormLabel from '../FormLabel';
9
11
 
10
12
  function FormAutosuggestWrapper(props) {
11
13
  return (
@@ -31,6 +33,19 @@ function FormAutosuggestTestComponent(props) {
31
33
  );
32
34
  }
33
35
 
36
+ function FormAutosuggestLabelTestComponent() {
37
+ return (
38
+ <FormGroup>
39
+ <FormLabel data-testid="autosuggest-label">
40
+ <h3>Label</h3>
41
+ </FormLabel>
42
+ <FormAutosuggestWrapper>
43
+ <FormAutosuggestOption>Option</FormAutosuggestOption>
44
+ </FormAutosuggestWrapper>
45
+ </FormGroup>
46
+ );
47
+ }
48
+
34
49
  FormAutosuggestTestComponent.defaultProps = {
35
50
  onSelected: jest.fn(),
36
51
  onClick: jest.fn(),
@@ -112,6 +127,12 @@ describe('render behavior', () => {
112
127
 
113
128
  expect(getByText('3 options found')).toBeInTheDocument();
114
129
  });
130
+
131
+ it('associates labels with the input textbox', () => {
132
+ const { getByTestId } = render(<FormAutosuggestLabelTestComponent />);
133
+
134
+ expect(getByTestId('autosuggest-label').getAttribute('for')).toEqual(getByTestId('autosuggest-textbox-input').getAttribute('id'));
135
+ });
115
136
  });
116
137
 
117
138
  describe('controlled behavior', () => {
@@ -101,18 +101,19 @@ Hyperlink.propTypes = {
101
101
  children: PropTypes.node.isRequired,
102
102
  /** Custom class names for the hyperlink */
103
103
  className: PropTypes.string,
104
- /** specifies where the link should open. The default behavior is `_self`, which means that the URL will be loaded into the same browsing context as the current one. If the target is `_blank` (opening a new window) `rel='noopener'` will be added to the anchor tag to prevent any potential [reverse tabnabbing attack](https://www.owasp.org/index.php/Reverse_Tabnabbing).
105
- */
104
+ /** specifies where the link should open. The default behavior is `_self`, which means that the URL will be
105
+ * loaded into the same browsing context as the current one.
106
+ * If the target is `_blank` (opening a new window) `rel='noopener'` will be added to the anchor tag to prevent
107
+ * any potential [reverse tabnabbing attack](https://www.owasp.org/index.php/Reverse_Tabnabbing).
108
+ */
106
109
  target: PropTypes.string,
107
110
  /** specifies the callback function when the link is clicked */
108
111
  onClick: PropTypes.func,
109
- // eslint-disable-next-line max-len
110
112
  /** specifies the text for links with a `_blank` target (which loads the URL in a new browsing context). */
111
113
  externalLinkAlternativeText: isRequiredIf(
112
114
  PropTypes.string,
113
115
  props => props.target === '_blank',
114
116
  ),
115
- // eslint-disable-next-line max-len
116
117
  /** specifies the title for links with a `_blank` target (which loads the URL in a new browsing context). */
117
118
  externalLinkTitle: isRequiredIf(
118
119
  PropTypes.string,
@@ -120,9 +121,9 @@ Hyperlink.propTypes = {
120
121
  ),
121
122
  /** type of hyperlink */
122
123
  variant: PropTypes.oneOf(['default', 'muted', 'brand']),
123
- /** specify the link style. By default it will be underlined. */
124
+ /** specify the link style. By default, it will be underlined. */
124
125
  isInline: PropTypes.bool,
125
- /** specify if we need to show launch Icon. By default it will be visible. */
126
+ /** specify if we need to show launch Icon. By default, it will be visible. */
126
127
  showLaunchIcon: PropTypes.bool,
127
128
  };
128
129
 
@@ -70,28 +70,35 @@ function Icon({
70
70
  }
71
71
 
72
72
  Icon.propTypes = {
73
- // eslint-disable-next-line max-len
74
- /** An icon component to render. Example import of a Paragon icon component: `import { Check } from '@edx/paragon/dist/icon';` */
75
- src: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
73
+ /**
74
+ * An icon component to render.
75
+ * Example import of a Paragon icon component: `import { Check } from '@edx/paragon/icons';`
76
+ */
77
+ src: PropTypes.oneOfType([PropTypes.element, PropTypes.elementType]),
76
78
  /** HTML element attributes to pass through to the underlying svg element */
77
79
  svgAttrs: PropTypes.shape({
78
80
  'aria-label': PropTypes.string,
79
81
  'aria-labelledby': PropTypes.string,
80
82
  }),
81
- // eslint-disable-next-line max-len
82
- /** the `id` property of the Icon element, by default this value is generated with the `newId` function with the `prefix` of `Icon`. */
83
+ /**
84
+ * the `id` property of the Icon element, by default this value is generated
85
+ * with the `newId` function with the `prefix` of `Icon`.
86
+ */
83
87
  id: PropTypes.string,
84
- // eslint-disable-next-line max-len
85
88
  /** The size of the icon. */
86
89
  size: PropTypes.oneOf(['xs', 'sm', 'md', 'lg']),
87
- // eslint-disable-next-line max-len
88
90
  /** A class name that will define what the Icon looks like. */
89
91
  className: PropTypes.string,
90
- // eslint-disable-next-line max-len
91
- /** a boolean that determines the value of `aria-hidden` attribute on the Icon span, this value is `true` by default. */
92
+ /**
93
+ * a boolean that determines the value of `aria-hidden` attribute on the Icon span,
94
+ * this value is `true` by default.
95
+ */
92
96
  hidden: PropTypes.bool,
93
- // eslint-disable-next-line max-len
94
- /** a string or an element that will be used on a secondary span leveraging the `sr-only` style for screenreader only text, this value is `undefined` by default. This value is recommended for use unless the Icon is being used in a way that is purely decorative or provides no additional context for screen reader users. This field should be thought of the same way an `alt` attribute would be used for `image` tags.
97
+ /**
98
+ * a string or an element that will be used on a secondary span leveraging the `sr-only` style
99
+ * for screenreader only text, this value is `undefined` by default. This value is recommended for use unless
100
+ * the Icon is being used in a way that is purely decorative or provides no additional context for screen
101
+ * reader users. This field should be thought of the same way an `alt` attribute would be used for `image` tags.
95
102
  */
96
103
  screenReaderText: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
97
104
  };
@@ -73,7 +73,7 @@ IconButton.propTypes = {
73
73
  /** An icon component to render. Example import of a Paragon icon component:
74
74
  * `import { Check } from '@edx/paragon/dist/icon';`
75
75
  * */
76
- src: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
76
+ src: PropTypes.oneOfType([PropTypes.element, PropTypes.elementType]),
77
77
  /** Alt text for your icon. For best practice, avoid using alt text to describe
78
78
  * the image in the `IconButton`. Instead, we recommend describing the function
79
79
  * of the button. */
@@ -84,9 +84,6 @@ SIZES.forEach(size => {
84
84
  Layout.defaultProps[size] = sizeDefaultProps;
85
85
  });
86
86
 
87
- export {
88
- Col,
89
- Row,
90
- };
87
+ export { Col, Row };
91
88
  Layout.Element = LayoutElement;
92
89
  export default Layout;
@@ -40,9 +40,9 @@ MenuItem.propTypes = {
40
40
  /** Specifies the base element */
41
41
  as: PropTypes.elementType,
42
42
  /** Specifies the jsx before the content of the ``MenuItem`` */
43
- iconBefore: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
43
+ iconBefore: PropTypes.oneOfType([PropTypes.element, PropTypes.elementType]),
44
44
  /** Specifies the jsx after the content of the ``MenuItem`` */
45
- iconAfter: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
45
+ iconAfter: PropTypes.oneOfType([PropTypes.element, PropTypes.elementType]),
46
46
  };
47
47
 
48
48
  MenuItem.defaultProps = {
@@ -116,6 +116,9 @@ ModalDialog.propTypes = {
116
116
  * Prevent clicking on the backdrop to close the modal
117
117
  */
118
118
  isBlocking: PropTypes.bool,
119
+ /**
120
+ * Specifies the z-index of the modal
121
+ */
119
122
  zIndex: PropTypes.number,
120
123
  };
121
124
 
@@ -38,7 +38,7 @@ This component is used to power Tooltips and Popovers.
38
38
  Click me to see
39
39
  </Button>
40
40
  </div>
41
- <Overlay target={target.current} show={open} placement="right">
41
+ <Overlay target={target.current} show={isOpen} placement="right">
42
42
  {({ placement, arrowProps, show: _show, popper, ...props }) => (
43
43
  <div
44
44
  {...props}
@@ -3,7 +3,6 @@ title: 'Popover'
3
3
  type: 'component'
4
4
  components:
5
5
  - Popover
6
- - WrapperPopover
7
6
  - PopoverTitle
8
7
  - PopoverContent
9
8
  categories:
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import classNames from 'classnames';
4
- import Popover from 'react-bootstrap/Popover';
4
+ import BasePopover from 'react-bootstrap/Popover';
5
5
  import BasePopoverTitle from 'react-bootstrap/PopoverTitle';
6
6
  import BasePopoverContent from 'react-bootstrap/PopoverContent';
7
7
 
@@ -13,18 +13,18 @@ const PLACEMENT_VARIANTS = [
13
13
  'right',
14
14
  ];
15
15
 
16
- const WrapperPopover = React.forwardRef(({
16
+ const Popover = React.forwardRef(({
17
17
  children,
18
18
  variant,
19
19
  ...props
20
20
  }, ref) => (
21
- <Popover
21
+ <BasePopover
22
22
  {...props}
23
23
  className={classNames({ [`popover-${variant}`]: !!variant }, props.className)}
24
24
  ref={ref}
25
25
  >
26
26
  {children}
27
- </Popover>
27
+ </BasePopover>
28
28
  ));
29
29
 
30
30
  function PopoverTitle(props) {
@@ -44,8 +44,8 @@ const commonPropTypes = {
44
44
  PopoverTitle.propTypes = commonPropTypes;
45
45
  PopoverContent.propTypes = commonPropTypes;
46
46
 
47
- WrapperPopover.propTypes = {
48
- ...Popover.propTypes,
47
+ Popover.propTypes = {
48
+ ...BasePopover.propTypes,
49
49
  /** An html id attribute, necessary for accessibility. */
50
50
  id: PropTypes.string.isRequired,
51
51
  /**
@@ -88,8 +88,8 @@ WrapperPopover.propTypes = {
88
88
  variant: PropTypes.string,
89
89
  };
90
90
 
91
- WrapperPopover.defaultProps = {
92
- ...Popover.defaultProps,
91
+ Popover.defaultProps = {
92
+ ...BasePopover.defaultProps,
93
93
  placement: 'right',
94
94
  title: undefined,
95
95
  arrowProps: undefined,
@@ -111,8 +111,8 @@ PopoverContent.defaultProps = {
111
111
  bsPrefix: 'popover-body',
112
112
  };
113
113
 
114
- WrapperPopover.Title = PopoverTitle;
115
- WrapperPopover.Content = PopoverContent;
114
+ Popover.Title = PopoverTitle;
115
+ Popover.Content = PopoverContent;
116
116
 
117
117
  export { PopoverTitle, PopoverContent };
118
- export default WrapperPopover;
118
+ export default Popover;
@@ -10,6 +10,7 @@ import CheckpointActionRow from './CheckpointActionRow';
10
10
  import CheckpointBody from './CheckpointBody';
11
11
  import CheckpointBreadcrumbs from './CheckpointBreadcrumbs';
12
12
  import CheckpointTitle from './CheckpointTitle';
13
+ import messages from './messages';
13
14
 
14
15
  const Checkpoint = React.forwardRef(({
15
16
  body,
@@ -99,10 +100,8 @@ const Checkpoint = React.forwardRef(({
99
100
  >
100
101
  <span className="sr-only">
101
102
  <FormattedMessage
102
- id="pgn.ProductTour.Checkpoint.position-text"
103
- defaultMessage="Top of step {step}"
104
- value={{ step: index + 1 }}
105
- description="Screen-reader message to indicate the user's position in a sequence of checkpoints."
103
+ {...messages.topPositionText}
104
+ values={{ step: index + 1 }}
106
105
  />
107
106
  </span>
108
107
  {(title || !isOnlyCheckpoint) && (
@@ -118,8 +117,12 @@ const Checkpoint = React.forwardRef(({
118
117
  {...props}
119
118
  />
120
119
  <div id="pgn__checkpoint-arrow" data-popper-arrow />
121
- {/* This text is not translated due to Paragon's lack of i18n support */}
122
- <span className="sr-only">Bottom of step {index + 1}</span>
120
+ <span className="sr-only">
121
+ <FormattedMessage
122
+ {...messages.bottomPositionText}
123
+ values={{ step: index + 1 }}
124
+ />
125
+ </span>
123
126
  </div>
124
127
  );
125
128
  });
@@ -0,0 +1,16 @@
1
+ import { defineMessages } from 'react-intl';
2
+
3
+ const messages = defineMessages({
4
+ topPositionText: {
5
+ id: 'pgn.ProductTour.Checkpoint.top-position-text',
6
+ defaultMessage: 'Top of step {step}',
7
+ description: 'Screen-reader message to notify user that they are located at the bottom of the product tour step.',
8
+ },
9
+ bottomPositionText: {
10
+ id: 'pgn.ProductTour.Checkpoint.bottom-position-text',
11
+ defaultMessage: 'Bottom of step {step}',
12
+ description: 'Screen-reader message to notify user that they are located at the bottom of the product tour step.',
13
+ },
14
+ });
15
+
16
+ export default messages;