@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
@@ -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": "22.0.0-alpha.23",
3
+ "version": "22.0.0-alpha.24",
4
4
  "description": "Accessible, responsive UI component library based on Bootstrap.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -116,11 +116,11 @@
116
116
  "@formatjs/cli": "^5.0.2",
117
117
  "@semantic-release/changelog": "^6.0.1",
118
118
  "@semantic-release/git": "^10.0.1",
119
- "@testing-library/jest-dom": "^5.16.3",
119
+ "@testing-library/jest-dom": "^6.1.4",
120
120
  "@testing-library/react": "^12.1.4",
121
121
  "@testing-library/react-hooks": "^8.0.1",
122
122
  "@testing-library/user-event": "^13.5.0",
123
- "@types/jest": "^27.5.0",
123
+ "@types/jest": "^29.5.10",
124
124
  "@types/react": "17.0.0",
125
125
  "@types/react-dom": "17.0.11",
126
126
  "@types/react-test-renderer": "^18.0.0",
@@ -20,11 +20,11 @@ This component utilizes `Button` from React-Bootstrap and extends it with an abi
20
20
 
21
21
  return (
22
22
  <Stack gap={2} direction={ isExtraSmall ? "vertical" : "horizontal" }>
23
- <Button variant="brand" className="mb-2 mb-sm-0">Brand</Button>
24
- <Button variant="outline-brand" className="mb-2 mb-sm-0">Outline Brand</Button>
25
- <Button variant="primary" className="mb-2 mb-sm-0">Primary</Button>
26
- <Button variant="outline-primary" className="mb-2 mb-sm-0">Outline Primary</Button>
27
- <Button variant="tertiary" className="mb-2 mb-sm-0">Tertiary</Button>
23
+ <Button variant="brand">Brand</Button>
24
+ <Button variant="outline-brand">Outline Brand</Button>
25
+ <Button variant="primary">Primary</Button>
26
+ <Button variant="outline-primary">Outline Primary</Button>
27
+ <Button variant="tertiary">Tertiary</Button>
28
28
  </Stack>
29
29
  )}
30
30
  ```
@@ -41,11 +41,11 @@ This component utilizes `Button` from React-Bootstrap and extends it with an abi
41
41
  gap={2}
42
42
  direction={ isExtraSmall ? "vertical" : "horizontal" }
43
43
  >
44
- <Button variant="inverse-brand" className="mb-2 mb-sm-0">Brand</Button>
45
- <Button variant="inverse-outline-brand" className="mb-2 mb-sm-0">Outline Brand</Button>
46
- <Button variant="inverse-primary" className="mb-2 mb-sm-0">Primary</Button>
47
- <Button variant="inverse-outline-primary" className="mb-2 mb-sm-0">Outline Primary</Button>
48
- <Button variant="inverse-tertiary" className="mb-2 mb-sm-0">Tertiary</Button>
44
+ <Button variant="inverse-brand">Brand</Button>
45
+ <Button variant="inverse-outline-brand">Outline Brand</Button>
46
+ <Button variant="inverse-primary">Primary</Button>
47
+ <Button variant="inverse-outline-primary">Outline Primary</Button>
48
+ <Button variant="inverse-tertiary">Tertiary</Button>
49
49
  </Stack>
50
50
  )}
51
51
  ```
@@ -63,20 +63,20 @@ This component utilizes `Button` from React-Bootstrap and extends it with an abi
63
63
  gap={2}
64
64
  direction={ isExtraSmall ? "vertical" : "horizontal" }
65
65
  >
66
- <Button variant="success" className="mb-2 mb-sm-0">Success</Button>
67
- <Button variant="danger" className="mb-2 mb-sm-0">Danger</Button>
68
- <Button variant="outline-success" className="mb-2 mb-sm-0">Success</Button>
69
- <Button variant="outline-danger" className="mb-2 mb-sm-0">Danger</Button>
66
+ <Button variant="success">Success</Button>
67
+ <Button variant="danger">Danger</Button>
68
+ <Button variant="outline-success">Success</Button>
69
+ <Button variant="outline-danger">Danger</Button>
70
70
  </Stack>
71
71
  <Stack
72
72
  gap={2}
73
73
  direction={ isExtraSmall ? "vertical" : "horizontal" }
74
74
  >
75
- <Button variant="link" className="mb-2 mb-sm-0">Link</Button>
76
- <Button variant="light" className="mb-2 mb-sm-0">Light</Button>
77
- <Button variant="dark" className="mb-2 mb-sm-0">Dark</Button>
78
- <Button variant="outline-light" className="mb-2 mb-sm-0">Light</Button>
79
- <Button variant="outline-dark" className="mb-2 mb-sm-0">Dark</Button>
75
+ <Button variant="link">Link</Button>
76
+ <Button variant="light">Light</Button>
77
+ <Button variant="dark">Dark</Button>
78
+ <Button variant="outline-light">Light</Button>
79
+ <Button variant="outline-dark">Dark</Button>
80
80
  </Stack>
81
81
  </>
82
82
  )}
@@ -90,34 +90,41 @@ This component utilizes `Button` from React-Bootstrap and extends it with an abi
90
90
 
91
91
  return (
92
92
  <>
93
- <Stack
94
- className="mb-2"
95
- gap={2}
96
- direction={ isExtraSmall ? "vertical" : "horizontal" }
97
- >
98
- <Button variant="primary" size="lg" className="mb-2 mb-sm-0">
99
- Large button
100
- </Button>
101
- <Button variant="outline-primary" size="lg" className="mb-2 mb-sm-0">
102
- Large button
103
- </Button>
104
- </Stack>
105
- <Stack
106
- className="mb-2"
107
- gap={2}
108
- direction={ isExtraSmall ? "vertical" : "horizontal" }
109
- >
110
- <Button variant="primary" size="sm" className="mb-2 mb-sm-0">
111
- Small button
112
- </Button>
113
- <Button variant="outline-primary" size="sm" className="mb-2 mb-sm-0">
114
- Small button
115
- </Button>
116
- </Stack>
117
- <Button variant="link" size="inline" className="mb-2 mb-sm-0">Inline button</Button>
118
- <Button variant="link" size="inline" className="mb-2 mb-sm-0">Inline button</Button>
93
+ <Stack
94
+ className="mb-2"
95
+ gap={2}
96
+ direction={ isExtraSmall ? "vertical" : "horizontal" }
97
+ >
98
+ <Button variant="primary" size="lg">
99
+ Large button
100
+ </Button>
101
+ <Button variant="outline-primary" size="lg">
102
+ Large button
103
+ </Button>
104
+ </Stack>
105
+ <Stack
106
+ className="mb-2"
107
+ gap={2}
108
+ direction={ isExtraSmall ? "vertical" : "horizontal" }
109
+ >
110
+ <Button variant="primary" size="sm">
111
+ Small button
112
+ </Button>
113
+ <Button variant="outline-primary" size="sm">
114
+ Small button
115
+ </Button>
116
+ </Stack>
117
+ <Stack
118
+ className="mb-2"
119
+ gap={2}
120
+ direction={ isExtraSmall ? "vertical" : "horizontal" }
121
+ >
122
+ <Button variant="link" size="inline">Inline button</Button>
123
+ <Button variant="link" size="inline">Inline button</Button>
124
+ </Stack>
119
125
  </>
120
- )}
126
+ )
127
+ }
121
128
  ```
122
129
 
123
130
  ### When to use the inline size
@@ -125,13 +132,11 @@ This component utilizes `Button` from React-Bootstrap and extends it with an abi
125
132
  Use inline size buttons for when a button sits with a line of text.
126
133
 
127
134
  ```jsx live
128
- <>
129
- <p>
130
- <span className="mr-1">2 items selected.</span>
131
- <Button variant="link" size="inline" className="mr-1">Select all</Button>
132
- <Button variant="link" size="inline">Clear</Button>
133
- </p>
134
- </>
135
+ <p>
136
+ <span className="mr-1">2 items selected.</span>
137
+ <Button variant="link" size="inline" className="mr-1">Select all</Button>
138
+ <Button variant="link" size="inline">Clear</Button>
139
+ </p>
135
140
  ```
136
141
 
137
142
  ## Block Buttons
@@ -150,21 +155,41 @@ Use inline size buttons for when a button sits with a line of text.
150
155
  ### Disabled
151
156
 
152
157
  ```jsx live
153
- <>
154
- <Button variant="primary" disabled>Primary disabled</Button>
155
- <Button variant="secondary" disabled>Secondary disabled</Button>
156
- <Button as="a" href="https://edx.org" disabled>Link disabled</Button>
157
- </>
158
+ () => {
159
+ const isExtraSmall = useMediaQuery({ maxWidth: breakpoints.extraSmall.maxWidth });
160
+
161
+ return (
162
+ <Stack
163
+ className="mb-2"
164
+ gap={2}
165
+ direction={ isExtraSmall ? "vertical" : "horizontal" }
166
+ >
167
+ <Button variant="primary" disabled>Primary disabled</Button>
168
+ <Button variant="secondary" disabled>Secondary disabled</Button>
169
+ <Button as="a" href="https://edx.org" disabled>Link disabled</Button>
170
+ </Stack>
171
+ )
172
+ }
158
173
  ```
159
174
 
160
175
  ### With empty href
161
176
  For link to be `disabled`, it must have href defined with some value.
162
177
 
163
178
  ```jsx live
164
- <>
165
- <Button as='a' disabled>No href</Button>
166
- <Button as='a' href='' disabled>Empty string href</Button>
167
- </>
179
+ () => {
180
+ const isExtraSmall = useMediaQuery({ maxWidth: breakpoints.extraSmall.maxWidth });
181
+
182
+ return (
183
+ <Stack
184
+ className="mb-2"
185
+ gap={2}
186
+ direction={ isExtraSmall ? "vertical" : "horizontal" }
187
+ >
188
+ <Button as="a" disabled>No href</Button>
189
+ <Button as="a" href="" disabled>Empty string href</Button>
190
+ </Stack>
191
+ )
192
+ }
168
193
  ```
169
194
 
170
195
  ### With Icons before or after
@@ -179,23 +204,24 @@ For link to be `disabled`, it must have href defined with some value.
179
204
  gap={2}
180
205
  direction={ isExtraSmall ? "vertical" : "horizontal" }
181
206
  >
182
- <Button variant="brand" iconBefore={ArrowBack} className="mb-2 mb-sm-0">
207
+ <Button variant="brand" iconBefore={ArrowBack}>
183
208
  Brand
184
209
  </Button>
185
- <Button variant="outline-brand" iconAfter={ArrowDropDown} className="mb-2 mb-sm-0">
210
+ <Button variant="outline-brand" iconAfter={ArrowDropDown}>
186
211
  Outline Brand
187
212
  </Button>
188
- <Button variant="primary" iconBefore={Remove} iconAfter={Add} className="mb-2 mb-sm-0">
213
+ <Button variant="primary" iconBefore={Remove} iconAfter={Add}>
189
214
  Primary
190
215
  </Button>
191
- <Button variant="outline-primary" iconBefore={Highlight} className="mb-2 mb-sm-0">
216
+ <Button variant="outline-primary" iconBefore={Highlight}>
192
217
  Outline Primary
193
218
  </Button>
194
- <Button variant="tertiary" iconAfter={Add} className="mb-2 mb-sm-0">
219
+ <Button variant="tertiary" iconAfter={Add}>
195
220
  Tertiary
196
221
  </Button>
197
222
  </Stack>
198
- )}
223
+ )
224
+ }
199
225
  ```
200
226
 
201
227
  ## Stateful buttons
@@ -51,10 +51,10 @@ Button.propTypes = {
51
51
  variant: PropTypes.string,
52
52
  /** An icon component to render.
53
53
  * Example import of a Paragon icon component: `import { Check } from '@edx/paragon/icons';` */
54
- iconBefore: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
54
+ iconBefore: PropTypes.oneOfType([PropTypes.elementType, PropTypes.node]),
55
55
  /** An icon component to render.
56
56
  * Example import of a Paragon icon component: `import { Check } from '@edx/paragon/icons';` */
57
- iconAfter: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
57
+ iconAfter: PropTypes.oneOfType([PropTypes.elementType, PropTypes.node]),
58
58
  };
59
59
 
60
60
  Button.defaultProps = {
@@ -41,15 +41,15 @@
41
41
  bottom: calc(var(--pgn-spacing-btn-focus-distance-to-border) * -1);
42
42
  left: calc(var(--pgn-spacing-btn-focus-distance-to-border) * -1);
43
43
  border: solid var(--pgn-size-btn-focus-width) var(--pgn-btn-focus-outline-color, var(--pgn-color-body-base));
44
- border-radius: var(--pgn-size-btn-focus-border-radius);
44
+ border-radius: var(--pgn-size-btn-focus-border-radius-base);
45
45
  }
46
46
 
47
47
  &.btn-lg::before {
48
- border-radius: var(--pgn-size-btn-focus-border-radius);
48
+ border-radius: var(--pgn-size-btn-focus-border-radius-lg);
49
49
  }
50
50
 
51
51
  &.btn-sm::before {
52
- border-radius: var(--pgn-size-btn-focus-border-radius);
52
+ border-radius: var(--pgn-size-btn-focus-border-radius-sm);
53
53
  }
54
54
 
55
55
  &:active,
@@ -29,13 +29,35 @@ describe('picker works as expected', () => {
29
29
  const color = 'wassap';
30
30
  const setColor = jest.fn();
31
31
  it('validates hex color', async () => {
32
- const { rerender } = render(<ColorPicker color={color} setColor={setColor} />);
32
+ render(<ColorPicker color={color} setColor={setColor} />);
33
+
33
34
  await act(async () => {
34
35
  await userEvent.click(screen.getByRole('button'));
35
36
  });
37
+ expect(screen.queryByTestId('hex-input').value).toEqual('#wassap');
36
38
  expect(screen.queryByText('Colors must be in hexadecimal format.')).toBeInTheDocument();
37
39
 
38
- rerender(<ColorPicker color="#32116c" setColor={setColor} />);
40
+ await act(async () => {
41
+ await userEvent.clear(screen.getByTestId('hex-input'));
42
+ await userEvent.paste(screen.getByTestId('hex-input'), '32116c');
43
+ });
44
+ expect(screen.queryByTestId('hex-input').value).toEqual('#32116c');
45
+ expect(screen.queryByText('Colors must be in hexadecimal format.')).not.toBeInTheDocument();
46
+
47
+ await act(async () => {
48
+ await userEvent.clear(screen.getByTestId('hex-input'));
49
+ await userEvent.paste(screen.getByTestId('hex-input'), 'yuk');
50
+ });
51
+
52
+ expect(screen.queryByTestId('hex-input').value).toEqual('#yuk');
53
+ expect(screen.queryByText('Colors must be in hexadecimal format.')).toBeInTheDocument();
54
+
55
+ await act(async () => {
56
+ await userEvent.clear(screen.getByTestId('hex-input'));
57
+ await userEvent.paste(screen.getByTestId('hex-input'), '#fad');
58
+ });
59
+
60
+ expect(screen.queryByTestId('hex-input').value).toEqual('#fad');
39
61
  expect(screen.queryByText('Colors must be in hexadecimal format.')).not.toBeInTheDocument();
40
62
  });
41
63
  });
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useEffect } from 'react';
1
+ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import classNames from 'classnames';
4
4
  import { HexColorPicker } from 'react-colorful';
@@ -15,24 +15,63 @@ function ColorPicker({
15
15
  }) {
16
16
  const [isOpen, open, close] = useToggle(false);
17
17
  const [target, setTarget] = React.useState(null);
18
- const [hexValid, setHexValid] = React.useState(true);
19
18
 
20
- const validateHex = useCallback((input) => {
19
+ const colorIsValid = (colorToValidate) => {
21
20
  const hexRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
22
- if (input.length > 1 && !input.startsWith('#')) {
23
- setColor(`#${input}`);
24
- } else {
25
- setColor(input);
21
+ return hexRegex.test(colorToValidate);
22
+ };
23
+
24
+ const formatHexColorString = (colorString) => {
25
+ if (!colorString.startsWith('#')) {
26
+ return `#${colorString}`.slice(0, 7);
27
+ }
28
+
29
+ return colorString.slice(0, 7);
30
+ };
31
+
32
+ const [hexValid, setHexValid] = React.useState(() => (color === '' || colorIsValid(formatHexColorString(color))));
33
+
34
+ const [hexColorString, setHexColorString] = React.useState(() => {
35
+ if (color === '') {
36
+ return '';
37
+ }
38
+
39
+ return formatHexColorString(color);
40
+ });
41
+ const [colorToDisplay, setColorToDisplay] = React.useState(() => {
42
+ const formattedColor = formatHexColorString(color);
43
+ if (colorIsValid(formattedColor)) {
44
+ return formattedColor;
26
45
  }
27
- if (input === '' || hexRegex.test(input) === true) {
46
+
47
+ return '#fff';
48
+ });
49
+
50
+ const setValidatedColor = (newColor) => {
51
+ if (newColor === '') {
28
52
  setHexValid(true);
29
- } else {
30
- setHexValid(false);
53
+ setColor('');
54
+ setHexColorString('');
55
+ setColorToDisplay('#fff');
56
+ return;
31
57
  }
32
- }, [setColor]);
33
58
 
34
- // this is needed for when a user changes the color through the sliders
35
- useEffect(() => validateHex(color), [validateHex, color]);
59
+ const formattedColor = formatHexColorString(newColor);
60
+
61
+ if (colorIsValid(formattedColor)) {
62
+ setHexValid(true);
63
+ setColor(formattedColor);
64
+ setHexColorString(formattedColor);
65
+ setColorToDisplay(formattedColor);
66
+ return;
67
+ }
68
+
69
+ setHexValid(false);
70
+ setHexColorString(formattedColor);
71
+
72
+ // ensure the picker value stays in sync with the textbox
73
+ setColor(formattedColor);
74
+ };
36
75
 
37
76
  return (
38
77
  <>
@@ -65,16 +104,17 @@ function ColorPicker({
65
104
  className="pgn__color-modal rounded shadow"
66
105
  style={{ textAlign: 'start' }}
67
106
  >
68
- <HexColorPicker color={color || ''} onChange={setColor} />
107
+ <HexColorPicker color={colorToDisplay} onChange={setValidatedColor} />
69
108
  <Form.Group className="pgn__hex-form" size="sm">
70
109
  <div>
71
110
  <Form.Label className="pgn__hex-label">Hex</Form.Label>
72
111
  <Form.Control
73
112
  className="pgn__hex-field"
74
113
  isInvalid={!hexValid}
75
- value={color}
76
- onChange={(e) => validateHex(e.target.value)}
114
+ value={hexColorString}
115
+ onChange={(e) => setValidatedColor(e.target.value)}
77
116
  data-testid="hex-input"
117
+ spellCheck="false"
78
118
  />
79
119
  </div>
80
120
  {!hexValid && (
@@ -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;
@@ -28,11 +28,11 @@ designStatus: 'Done'
28
28
  devStatus: 'In progress'
29
29
  ---
30
30
 
31
- The DataTable component is a wrapper that uses the <a href="https://react-table.tanstack.com/docs/overview">react-table</a> library to
31
+ The DataTable component is a wrapper that uses the <a href="https://github.com/TanStack/table/tree/v7/docs/src/pages/docs" target="_blank" rel="noopener noreferrer">react-table</a> library to
32
32
  create tables. It can be used as is, or its subcomponents can be used on their own, allowing the developer full control.
33
33
 
34
34
  Paragon also exports all React hooks from ``react-table`` allowing the developers to use them and make customizations more freely without adding ``react-table`` as a separate dependency to their project.
35
- For full list of available hooks view <a href="https://react-table.tanstack.com/docs/api/overview">react-table API reference</a>.
35
+ For full list of available hooks view <a href="https://github.com/TanStack/table/tree/v7/docs/src/pages/docs/api" target="_blank" rel="noopener noreferrer">react-table API reference</a>.
36
36
 
37
37
  ## How children get information
38
38
 
@@ -49,7 +49,7 @@ const instance = useContext(DataTableContext)
49
49
  For small tables (less than ~10,000 rows), filtering, sorting and pagination can be done quickly and easily on the frontend.
50
50
 
51
51
  In this example, a default TextFilter component is used for all columns. A default filter can be passed in,
52
- or a filter component can be defined on the column. See <a href="https://react-table.tanstack.com/docs/api/useFilters">react-table filters documentation</a>
52
+ or a filter component can be defined on the column. See <a href="https://github.com/TanStack/table/blob/v7/docs/src/pages/docs/api/useFilters.md" target="_blank" rel="noopener noreferrer">react-table filters documentation</a>
53
53
  for more information.
54
54
 
55
55
  ```jsx live
@@ -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,
@@ -329,7 +330,7 @@ DataTable.propTypes = {
329
330
  /** Function that will fetch table data. Called when page size, page index or filters change.
330
331
  * Meant to be used with manual filters and pagination */
331
332
  fetchData: PropTypes.func,
332
- /** Initial state passed to react-table's documentation https://react-table.tanstack.com/docs/api/useTable */
333
+ /** Initial state passed to react-table's documentation https://github.com/TanStack/table/blob/v7/docs/src/pages/docs/api/useTable.md */
333
334
  initialState: PropTypes.shape({
334
335
  pageSize: requiredWhen(PropTypes.number, 'isPaginated'),
335
336
  pageIndex: requiredWhen(PropTypes.number, 'isPaginated'),
@@ -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 || (
@@ -14,18 +14,18 @@ devStatus: 'In progress'
14
14
  ---
15
15
 
16
16
 
17
- The ``DataTable`` component is a wrapper that uses the <a href="https://react-table.tanstack.com/docs">react-table</a> library to
17
+ The ``DataTable`` component is a wrapper that uses the <a href="https://github.com/TanStack/table/tree/v7/docs/src/pages/docs" target="_blank" rel="noopener noreferrer">react-table</a> library to
18
18
  create tables. It can be used as is, or its subcomponents can be used on their own, allowing the developer full control.
19
19
 
20
20
  ## Filtering and sorting
21
21
  Paragon currently provides a variety of filter types, and you can also define your own filter types.
22
22
 
23
23
  In the example below, a default ``TextFilter`` component is used as the default filter for all columns. A default filter can be passed in,
24
- or a filter component can be defined on the column using the ``Filter`` attribute. See <a href="https://react-table.tanstack.com/docs/api/useFilters">react-table filters documentation</a>
24
+ or a filter component can be defined on the column using the ``Filter`` attribute. See <a href="https://github.com/TanStack/table/blob/v7/docs/src/pages/docs/api/useFilters.md" target="_blank" rel="noopener noreferrer">react-table filters documentation</a>
25
25
  for more information.
26
26
 
27
27
  ## Available filter functions
28
- A filtering function can be defined on the column as well as the filter component. Custom filtering functions can also be defined, see <a href="https://react-table.tanstack.com/docs/api/useFilters#column-options">react-table filters documentation</a>
28
+ A filtering function can be defined on the column as well as the filter component. Custom filtering functions can also be defined, see <a href="https://github.com/TanStack/table/blob/v7/docs/src/pages/docs/api/useFilters.md#column-options" target="_blank" rel="noopener noreferrer">react-table filters documentation</a>
29
29
  for more information.
30
30
  Filter functions are defined on the column as the ``filter`` attribute.
31
31
  <dl>