@openedx/paragon 21.11.4 → 21.12.1

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 (103) hide show
  1. package/dist/Container/index.js +6 -2
  2. package/dist/Container/index.js.map +1 -1
  3. package/dist/DataTable/index.js +1 -0
  4. package/dist/DataTable/index.js.map +1 -1
  5. package/dist/DataTable/selection/BaseSelectionStatus.js +3 -2
  6. package/dist/DataTable/selection/BaseSelectionStatus.js.map +1 -1
  7. package/dist/Dropdown/index.js.map +1 -1
  8. package/dist/Form/FormSwitch.js +3 -0
  9. package/dist/Form/FormSwitch.js.map +1 -1
  10. package/dist/Hyperlink/index.js +7 -6
  11. package/dist/Hyperlink/index.js.map +1 -1
  12. package/dist/Icon/index.js +17 -10
  13. package/dist/Icon/index.js.map +1 -1
  14. package/dist/IconButton/index.js +1 -1
  15. package/dist/IconButton/index.js.map +1 -1
  16. package/dist/Layout/index.js.map +1 -1
  17. package/dist/Modal/ModalDialog.js +3 -0
  18. package/dist/Modal/ModalDialog.js.map +1 -1
  19. package/dist/Modal/index.js +11 -6
  20. package/dist/Modal/index.js.map +1 -1
  21. package/dist/Popover/index.js +8 -8
  22. package/dist/Popover/index.js.map +1 -1
  23. package/dist/ProductTour/Checkpoint.js +10 -8
  24. package/dist/ProductTour/Checkpoint.js.map +1 -1
  25. package/dist/ProductTour/messages.js +16 -0
  26. package/dist/SearchField/SearchFieldAdvanced.js +12 -7
  27. package/dist/SearchField/SearchFieldAdvanced.js.map +1 -1
  28. package/dist/SearchField/SearchFieldLabel.js +3 -3
  29. package/dist/SearchField/SearchFieldLabel.js.map +1 -1
  30. package/dist/SearchField/index.js +0 -1
  31. package/dist/SearchField/index.js.map +1 -1
  32. package/dist/Tabs/index.js +13 -13
  33. package/dist/Tabs/index.js.map +1 -1
  34. package/dist/hooks/useIndexOfLastVisibleChild.js +33 -38
  35. package/dist/hooks/useIndexOfLastVisibleChild.js.map +1 -1
  36. package/dist/i18n/messages/ar.json +2 -1
  37. package/dist/i18n/messages/ca.json +2 -1
  38. package/dist/i18n/messages/es_419.json +2 -1
  39. package/dist/i18n/messages/es_AR.json +2 -1
  40. package/dist/i18n/messages/es_ES.json +2 -1
  41. package/dist/i18n/messages/fr.json +2 -1
  42. package/dist/i18n/messages/he.json +2 -1
  43. package/dist/i18n/messages/id.json +2 -1
  44. package/dist/i18n/messages/it_IT.json +2 -1
  45. package/dist/i18n/messages/ko_KR.json +2 -1
  46. package/dist/i18n/messages/pl.json +2 -1
  47. package/dist/i18n/messages/pt_BR.json +2 -1
  48. package/dist/i18n/messages/pt_PT.json +2 -1
  49. package/dist/i18n/messages/ru.json +2 -1
  50. package/dist/i18n/messages/th.json +2 -1
  51. package/dist/i18n/messages/tr_TR.json +2 -1
  52. package/dist/i18n/messages/uk.json +2 -1
  53. package/dist/i18n/messages/zh_CN.json +2 -1
  54. package/icons/es5/RightSidebarFilled.js +15 -0
  55. package/icons/es5/RightSidebarOutlined.js +15 -0
  56. package/icons/es5/index.js +2 -0
  57. package/icons/jsx/RightSidebarFilled.jsx +19 -0
  58. package/icons/jsx/RightSidebarOutlined.jsx +19 -0
  59. package/icons/jsx/index.jsx +2 -0
  60. package/icons/svg/right_sidebar_filled.svg +3 -0
  61. package/icons/svg/right_sidebar_outlined.svg +3 -0
  62. package/package.json +1 -1
  63. package/src/Container/index.jsx +4 -0
  64. package/src/DataTable/index.jsx +1 -0
  65. package/src/DataTable/selection/BaseSelectionStatus.jsx +2 -2
  66. package/src/DataTable/tests/DataTable.test.jsx +31 -0
  67. package/src/Dropdown/index.jsx +4 -0
  68. package/src/Form/FormSwitch.jsx +3 -0
  69. package/src/Hyperlink/index.jsx +7 -6
  70. package/src/Icon/index.jsx +17 -10
  71. package/src/IconButton/index.jsx +1 -1
  72. package/src/Layout/index.jsx +1 -4
  73. package/src/Modal/ModalDialog.jsx +3 -0
  74. package/src/Modal/index.jsx +11 -6
  75. package/src/Popover/README.md +0 -1
  76. package/src/Popover/index.jsx +11 -11
  77. package/src/ProductTour/Checkpoint.jsx +9 -6
  78. package/src/ProductTour/messages.js +16 -0
  79. package/src/SearchField/SearchFieldAdvanced.jsx +12 -7
  80. package/src/SearchField/SearchFieldLabel.jsx +3 -3
  81. package/src/SearchField/index.jsx +0 -1
  82. package/src/Tabs/index.jsx +19 -13
  83. package/src/hooks/tests/useIndexOfLastVisibleChild.test.jsx +3 -3
  84. package/src/hooks/useIndexOfLastVisibleChild.jsx +36 -38
  85. package/src/hooks/useIndexOfLastVisibleChild.mdx +3 -3
  86. package/src/i18n/messages/ar.json +2 -1
  87. package/src/i18n/messages/ca.json +2 -1
  88. package/src/i18n/messages/es_419.json +2 -1
  89. package/src/i18n/messages/es_AR.json +2 -1
  90. package/src/i18n/messages/es_ES.json +2 -1
  91. package/src/i18n/messages/fr.json +2 -1
  92. package/src/i18n/messages/he.json +2 -1
  93. package/src/i18n/messages/id.json +2 -1
  94. package/src/i18n/messages/it_IT.json +2 -1
  95. package/src/i18n/messages/ko_KR.json +2 -1
  96. package/src/i18n/messages/pl.json +2 -1
  97. package/src/i18n/messages/pt_BR.json +2 -1
  98. package/src/i18n/messages/pt_PT.json +2 -1
  99. package/src/i18n/messages/ru.json +2 -1
  100. package/src/i18n/messages/th.json +2 -1
  101. package/src/i18n/messages/tr_TR.json +2 -1
  102. package/src/i18n/messages/uk.json +2 -1
  103. package/src/i18n/messages/zh_CN.json +2 -1
@@ -28,5 +28,6 @@
28
28
  "pgn.FormAutosuggest.iconButtonClosed": "Close the options menu",
29
29
  "pgn.FormAutosuggest.iconButtonOpened": "Open the options menu",
30
30
  "pgn.Toast.closeLabel": "Close",
31
- "pgn.ProductTour.Checkpoint.position-text": "Top of step {step}"
31
+ "pgn.ProductTour.Checkpoint.top-position-text": "Top of step {step}",
32
+ "pgn.ProductTour.Checkpoint.bottom-position-text": "Bottom of step {step}"
32
33
  }
@@ -0,0 +1,15 @@
1
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2
+ import * as React from "react";
3
+ const SvgRightSidebarFilled = props => /*#__PURE__*/React.createElement("svg", _extends({
4
+ width: 24,
5
+ height: 24,
6
+ viewBox: "0 0 24 24",
7
+ fill: "none",
8
+ xmlns: "http://www.w3.org/2000/svg"
9
+ }, props), /*#__PURE__*/React.createElement("path", {
10
+ fillRule: "evenodd",
11
+ clipRule: "evenodd",
12
+ d: "M2 22V2h20v20H2ZM14 4H4v16h10V4Z",
13
+ fill: "currentColor"
14
+ }));
15
+ export default SvgRightSidebarFilled;
@@ -0,0 +1,15 @@
1
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2
+ import * as React from "react";
3
+ const SvgRightSidebarOutlined = props => /*#__PURE__*/React.createElement("svg", _extends({
4
+ width: 24,
5
+ height: 24,
6
+ viewBox: "0 0 24 24",
7
+ fill: "none",
8
+ xmlns: "http://www.w3.org/2000/svg"
9
+ }, props), /*#__PURE__*/React.createElement("path", {
10
+ fillRule: "evenodd",
11
+ clipRule: "evenodd",
12
+ d: "M2 2v20h20V2H2Zm18 2h-4v16h4V4ZM4 4h10v16H4V4Z",
13
+ fill: "currentColor"
14
+ }));
15
+ export default SvgRightSidebarOutlined;
@@ -1694,6 +1694,8 @@ export { default as RestoreFromTrash } from "./RestoreFromTrash";
1694
1694
  export { default as RestorePage } from "./RestorePage";
1695
1695
  export { default as Reviews } from "./Reviews";
1696
1696
  export { default as RiceBowl } from "./RiceBowl";
1697
+ export { default as RightSidebarFilled } from "./RightSidebarFilled";
1698
+ export { default as RightSidebarOutlined } from "./RightSidebarOutlined";
1697
1699
  export { default as RingVolume } from "./RingVolume";
1698
1700
  export { default as Rocket } from "./Rocket";
1699
1701
  export { default as RocketLaunch } from "./RocketLaunch";
@@ -0,0 +1,19 @@
1
+ import * as React from "react";
2
+ const SvgRightSidebarFilled = (props) => (
3
+ <svg
4
+ width={24}
5
+ height={24}
6
+ viewBox="0 0 24 24"
7
+ fill="none"
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ {...props}
10
+ >
11
+ <path
12
+ fillRule="evenodd"
13
+ clipRule="evenodd"
14
+ d="M2 22V2h20v20H2ZM14 4H4v16h10V4Z"
15
+ fill="currentColor"
16
+ />
17
+ </svg>
18
+ );
19
+ export default SvgRightSidebarFilled;
@@ -0,0 +1,19 @@
1
+ import * as React from "react";
2
+ const SvgRightSidebarOutlined = (props) => (
3
+ <svg
4
+ width={24}
5
+ height={24}
6
+ viewBox="0 0 24 24"
7
+ fill="none"
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ {...props}
10
+ >
11
+ <path
12
+ fillRule="evenodd"
13
+ clipRule="evenodd"
14
+ d="M2 2v20h20V2H2Zm18 2h-4v16h4V4ZM4 4h10v16H4V4Z"
15
+ fill="currentColor"
16
+ />
17
+ </svg>
18
+ );
19
+ export default SvgRightSidebarOutlined;
@@ -1694,6 +1694,8 @@ export { default as RestoreFromTrash } from "./RestoreFromTrash";
1694
1694
  export { default as RestorePage } from "./RestorePage";
1695
1695
  export { default as Reviews } from "./Reviews";
1696
1696
  export { default as RiceBowl } from "./RiceBowl";
1697
+ export { default as RightSidebarFilled } from "./RightSidebarFilled";
1698
+ export { default as RightSidebarOutlined } from "./RightSidebarOutlined";
1697
1699
  export { default as RingVolume } from "./RingVolume";
1698
1700
  export { default as Rocket } from "./Rocket";
1699
1701
  export { default as RocketLaunch } from "./RocketLaunch";
@@ -0,0 +1,3 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M2 22V2H22V22H2ZM14 4H4V20H14V4Z" fill="black"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M2 2V22H22V2H2ZM20 4H16V20H20V4ZM4 4H14V20H4V4Z" fill="black"/>
3
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openedx/paragon",
3
- "version": "21.11.4",
3
+ "version": "21.12.1",
4
4
  "description": "Accessible, responsive UI component library based on Bootstrap.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -28,11 +28,14 @@ Container.propTypes = {
28
28
  ...RBContainer.propTypes,
29
29
  /** Override the base element */
30
30
  as: PropTypes.elementType,
31
+ /** Specifies the contents of the container */
31
32
  children: PropTypes.node,
32
33
  /** Fill all available space at any breakpoint */
33
34
  fluid: PropTypes.bool,
34
35
  /** Set the maximum width for the container */
35
36
  size: PropTypes.oneOf(Object.keys(SIZE_CLASS_NAMES)),
37
+ /** Overrides underlying component base CSS class name */
38
+ bsPrefix: PropTypes.string,
36
39
  };
37
40
 
38
41
  Container.defaultProps = {
@@ -40,6 +43,7 @@ Container.defaultProps = {
40
43
  children: undefined,
41
44
  fluid: true,
42
45
  size: undefined,
46
+ bsPrefix: 'container',
43
47
  };
44
48
 
45
49
  export default Container;
@@ -187,6 +187,7 @@ function DataTable({
187
187
 
188
188
  const enhancedInstance = {
189
189
  ...instance,
190
+ manualFilters,
190
191
  itemCount,
191
192
  numBreakoutFilters,
192
193
  bulkActions,
@@ -22,11 +22,11 @@ function BaseSelectionStatus({
22
22
  }) {
23
23
  const {
24
24
  itemCount, filteredRows, isPaginated, state,
25
- isSelectable, maxSelectedRows,
25
+ isSelectable, maxSelectedRows, manualFilters,
26
26
  } = useContext(DataTableContext);
27
27
  const hasAppliedFilters = state?.filters?.length > 0;
28
28
  const isAllRowsSelected = numSelectedRows === itemCount;
29
- const filteredItems = filteredRows?.length || itemCount;
29
+ const filteredItems = manualFilters ? itemCount : (filteredRows?.length || itemCount);
30
30
  const hasMaxSelectedRows = isSelectable && maxSelectedRows;
31
31
 
32
32
  const intlAllSelectedText = allSelectedText || (
@@ -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 () => {
@@ -69,6 +69,7 @@ const Dropdown = React.forwardRef(
69
69
  );
70
70
  },
71
71
  );
72
+
72
73
  Dropdown.propTypes = {
73
74
  autoClose: PropTypes.oneOfType([
74
75
  PropTypes.string,
@@ -79,6 +80,7 @@ Dropdown.propTypes = {
79
80
  show: PropTypes.bool,
80
81
  variant: PropTypes.oneOf(['light', 'dark']),
81
82
  };
83
+
82
84
  Dropdown.defaultProps = {
83
85
  autoClose: true,
84
86
  className: '',
@@ -127,9 +129,11 @@ Dropdown.Item = React.forwardRef(
127
129
  );
128
130
  },
129
131
  );
132
+
130
133
  Dropdown.Item.propTypes = {
131
134
  className: PropTypes.string,
132
135
  };
136
+
133
137
  Dropdown.Item.defaultProps = {
134
138
  className: undefined,
135
139
  };
@@ -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
 
@@ -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';` */
73
+ /**
74
+ * An icon component to render.
75
+ * Example import of a Paragon icon component: `import { Check } from '@edx/paragon/icons';`
76
+ */
75
77
  src: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
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
  };
@@ -87,7 +87,7 @@ IconButton.propTypes = {
87
87
  alt: PropTypes.string.isRequired,
88
88
  /** Changes icon styles for dark background */
89
89
  invertColors: PropTypes.bool,
90
- /** Accepts a React fontawesome icon. https://fontawesome.com/how-to-use/on-the-web/using-with/react */
90
+ /** Accepts a React fontawesome icon. */
91
91
  icon: PropTypes.shape({
92
92
  prefix: PropTypes.string,
93
93
  iconName: PropTypes.string,
@@ -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;
@@ -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
 
@@ -1,4 +1,3 @@
1
- /* eslint-disable max-len */
2
1
  import React from 'react';
3
2
  import ReactDOM from 'react-dom';
4
3
  import classNames from 'classnames';
@@ -271,21 +270,26 @@ class Modal extends React.Component {
271
270
  Modal.propTypes = {
272
271
  /** specifies whether the modal renders open or closed on the initial render. It defaults to false. */
273
272
  open: PropTypes.bool,
274
- /** is the selector for an element in the dom which the modal should be rendered under. It uses querySelector to find the first element that matches that selector, and then creates a react portal to a div underneath the parent element.
275
- */
273
+ /** is the selector for an element in the dom which the modal should be rendered under.
274
+ * It uses querySelector to find the first element that matches that selector,
275
+ * and then creates a React portal to a div underneath the parent element.
276
+ */
276
277
  parentSelector: PropTypes.string,
277
278
  /** a string or an element that is rendered inside of the modal title, above the modal body. */
278
279
  title: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
279
280
  /** a string or an element that is rendered inside of the modal body, between the title and the footer. */
280
281
  body: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
281
- /** an array of either elements or shapes that take the form of the buttonPropTypes. See the [buttonPropTypes](https://github.com/openedx/paragon/blob/master/src/Button/index.jsx#L40) for a list of acceptable props to pass as part of a button. */
282
+ /** an array of either elements or shapes that take the form of the buttonPropTypes.
283
+ * See the [buttonPropTypes](https://github.com/openedx/paragon/blob/master/src/Button/index.jsx#L40)
284
+ * for a list of acceptable props to pass as part of a button. */
282
285
  buttons: PropTypes.arrayOf(PropTypes.oneOfType([
283
286
  PropTypes.element,
284
287
  PropTypes.shape({}), // TODO: Only accept nodes in the future
285
288
  ])),
286
289
  /** specifies the display text of the default Close button. It defaults to "Close". */
287
290
  closeText: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
288
- /** a function that is called on close. It can be used to perform actions upon closing of the modal, such as restoring focus to the previous logical focusable element. */
291
+ /** a function that is called on close. It can be used to perform actions upon closing of the modal,
292
+ * such as restoring focus to the previous logical focusable element. */
289
293
  onClose: PropTypes.func.isRequired,
290
294
  variant: PropTypes.shape({
291
295
  status: PropTypes.string,
@@ -295,7 +299,8 @@ Modal.propTypes = {
295
299
  /** specifies whether a close button is rendered in the modal header. It defaults to true. */
296
300
  renderHeaderCloseButton: PropTypes.bool,
297
301
  /**
298
- * Specifies optional classes to add to the element with the '.modal-dialog' class. See Bootstrap documentation for possible classes. Some options: modal-lg, modal-sm, modal-dialog-centered
302
+ * Specifies optional classes to add to the element with the '.modal-dialog' class.
303
+ * See Bootstrap documentation for possible classes. Some options: modal-lg, modal-sm, modal-dialog-centered
299
304
  */
300
305
  dialogClassName: PropTypes.string,
301
306
  };
@@ -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;
@@ -1,4 +1,3 @@
1
- /* eslint-disable max-len */
2
1
  import React, {
3
2
  useRef, createContext, useState, useEffect,
4
3
  } from 'react';
@@ -138,27 +137,32 @@ SearchFieldAdvanced.propTypes = {
138
137
  onSubmit: PropTypes.func.isRequired,
139
138
  /** specifies a custom class name. */
140
139
  className: PropTypes.string,
141
- /** specifies a callback function for when the user loses focus in the `SearchField` component. The default is an empty function. For example:
140
+ /** specifies a callback function for when the user loses focus in the `SearchField` component.
141
+ * The default is an empty function. For example:
142
142
  ```jsx
143
143
  <SearchField onBlur={event => console.log(event)} />
144
144
  ``` */
145
145
  onBlur: PropTypes.func,
146
- /** specifies a callback function for when the value in `SearchField` is changed by the user. The default is an empty function. For example:
146
+ /** specifies a callback function for when the value in `SearchField` is changed by the user.
147
+ * The default is an empty function. For example:
147
148
  ```jsx
148
149
  <SearchField onChange={value => console.log(value)} />
149
150
  ``` */
150
151
  onChange: PropTypes.func,
151
- /** specifies a callback function for when the value in `SearchField` is cleared by the user. The default is an empty function. For example:
152
+ /** specifies a callback function for when the value in `SearchField` is cleared by the user.
153
+ * The default is an empty function. For example:
152
154
  ```jsx
153
155
  <SearchField onClear={() => console.log('search cleared')} />
154
156
  ``` */
155
157
  onClear: PropTypes.func,
156
- /** specifies a callback function for when the user focuses in the `SearchField` component. The default is an empty function. For example:
158
+ /** specifies a callback function for when the user focuses in the `SearchField` component.
159
+ * The default is an empty function. For example:
157
160
  ```jsx
158
161
  <SearchField onFocus={event => console.log(event)} />
159
162
  ``` */
160
163
  onFocus: PropTypes.func,
161
- /** specifies the screenreader text for both the clear and submit buttons (e.g., for i18n translations). The default is `{ label: 'search', clearButton: 'clear search', searchButton: 'submit search' }`. */
164
+ /** specifies the screenreader text for both the clear and submit buttons (e.g., for i18n translations).
165
+ * The default is `{ label: 'search', clearButton: 'clear search', searchButton: 'submit search' }`. */
162
166
  screenReaderText: PropTypes.shape({
163
167
  label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
164
168
  submitButton: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
@@ -171,7 +175,8 @@ SearchFieldAdvanced.propTypes = {
171
175
  submit: PropTypes.element.isRequired,
172
176
  clear: PropTypes.element,
173
177
  }),
174
- /** specifies the aria-label attribute on the form element. This is useful if you use the `SearchField` component more than once on a page. */
178
+ /** specifies the aria-label attribute on the form element. This is useful if you use the `SearchField` component
179
+ * more than once on a page. */
175
180
  formAriaLabel: PropTypes.string,
176
181
  /** Specifies whether the `SearchField` is disabled. */
177
182
  disabled: PropTypes.bool,
@@ -1,4 +1,3 @@
1
- /* eslint-disable max-len */
2
1
  import React, { useContext } from 'react';
3
2
  import PropTypes from 'prop-types';
4
3
  import classNames from 'classnames';
@@ -21,8 +20,9 @@ function SearchFieldLabel({ children, ...props }) {
21
20
 
22
21
  SearchFieldLabel.propTypes = {
23
22
  /**
24
- * specifies the label to use for the input field (e.g., for i18n translations). Note: if `children` is not provided,
25
- * a screenreader-only label will be used in its placed based on the `screenReaderText.label` prop for `SearchField.Advanced`.
23
+ * specifies the label to use for the input field (e.g., for i18n translations).
24
+ * Note: if `children` is not provided, a screenreader-only label will be used in
25
+ * its placed based on the `screenReaderText.label` prop for `SearchField.Advanced`.
26
26
  */
27
27
  children: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
28
28
  };
@@ -1,4 +1,3 @@
1
- /* eslint-disable max-len */
2
1
  import React, { useCallback } from 'react';
3
2
  import PropTypes from 'prop-types';
4
3