newspack-components 4.7.0 → 4.8.0
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.
- package/CHANGELOG.md +20 -0
- package/DEVELOPMENT.md +42 -21
- package/dist/cjs/_mixins.scss +13 -0
- package/dist/cjs/_variables.scss +12 -0
- package/dist/cjs/action-card/index.js +18 -10
- package/dist/cjs/action-card/index.test.js +91 -0
- package/dist/cjs/action-card/style.scss +2 -40
- package/dist/cjs/button/index.js +8 -3
- package/dist/cjs/button/index.test.js +61 -5
- package/dist/cjs/card/core-card.js +0 -2
- package/dist/cjs/card/style-core.scss +7 -5
- package/dist/cjs/card-feature/index.js +75 -61
- package/dist/cjs/card-feature/index.test.js +396 -54
- package/dist/cjs/card-feature/style.scss +20 -31
- package/dist/cjs/card-form/index.js +5 -5
- package/dist/cjs/card-sortable-list/index.js +5 -3
- package/dist/cjs/card-sortable-list/index.test.js +50 -0
- package/dist/cjs/collapsible-group/context.js +19 -0
- package/dist/cjs/collapsible-group/index.js +24 -0
- package/dist/cjs/collapsible-group/index.test.js +215 -0
- package/dist/cjs/collapsible-group/item.js +61 -0
- package/dist/cjs/collapsible-group/root.js +62 -0
- package/dist/cjs/collapsible-group/style.scss +47 -0
- package/dist/cjs/collapsible-group/types.js +5 -0
- package/dist/cjs/empty-state/actions.js +45 -0
- package/dist/cjs/empty-state/context.js +41 -0
- package/dist/cjs/empty-state/header.js +66 -0
- package/dist/cjs/empty-state/index.js +31 -0
- package/dist/cjs/empty-state/index.test.js +303 -0
- package/dist/cjs/empty-state/root.js +56 -0
- package/dist/cjs/empty-state/style.scss +51 -0
- package/dist/cjs/empty-state/types.js +5 -0
- package/dist/cjs/index.js +34 -20
- package/dist/cjs/info-button/index.js +59 -43
- package/dist/cjs/info-button/index.test.js +199 -0
- package/dist/cjs/info-button/style.scss +41 -9
- package/dist/cjs/modal/style.scss +12 -12
- package/dist/cjs/newspack-icon/style.scss +4 -4
- package/dist/cjs/notice/style.scss +3 -3
- package/dist/cjs/page/style.scss +16 -16
- package/dist/cjs/plugin-installer/index.js +5 -9
- package/dist/cjs/plugin-installer/style.scss +3 -14
- package/dist/cjs/section-header/index.js +31 -18
- package/dist/cjs/section-header/index.test.js +40 -0
- package/dist/cjs/section-header/style.scss +22 -6
- package/dist/cjs/settings/DateRangeSetting.js +309 -0
- package/dist/cjs/settings/SettingsSection.js +19 -5
- package/dist/cjs/settings/SettingsSection.test.js +49 -0
- package/dist/cjs/settings/index.js +3 -1
- package/dist/cjs/settings/style.scss +40 -7
- package/dist/cjs/stat-card/body.js +41 -0
- package/dist/cjs/stat-card/constants.js +11 -0
- package/dist/cjs/stat-card/context.js +54 -0
- package/dist/cjs/stat-card/delta.js +91 -0
- package/dist/cjs/stat-card/footer.js +72 -0
- package/dist/cjs/stat-card/index.js +47 -0
- package/dist/cjs/stat-card/index.test.js +938 -0
- package/dist/cjs/stat-card/label.js +66 -0
- package/dist/cjs/stat-card/root.js +69 -0
- package/dist/cjs/stat-card/secondary.js +38 -0
- package/dist/cjs/stat-card/style.scss +89 -0
- package/dist/cjs/stat-card/types.js +5 -0
- package/dist/cjs/stat-card/value.js +78 -0
- package/dist/cjs/status-indicator/index.js +66 -0
- package/dist/cjs/status-indicator/index.test.js +101 -0
- package/dist/cjs/status-indicator/statuses.js +39 -0
- package/dist/cjs/status-indicator/style.scss +9 -0
- package/dist/cjs/status-indicator/types.js +5 -0
- package/dist/cjs/style.scss +9 -9
- package/dist/cjs/tabbed-navigation/style.scss +6 -4
- package/dist/cjs/types.js +5 -0
- package/dist/cjs/web-preview/style.scss +11 -11
- package/dist/cjs/with-wizard/style.scss +10 -10
- package/dist/cjs/with-wizard-screen/style.scss +9 -9
- package/dist/cjs/wizard/index.js +33 -4
- package/dist/cjs/wizard/store/index.js +23 -1
- package/dist/esm/_mixins.scss +13 -0
- package/dist/esm/_variables.scss +12 -0
- package/dist/esm/action-card/index.js +18 -10
- package/dist/esm/action-card/index.test.js +89 -0
- package/dist/esm/action-card/style.scss +2 -40
- package/dist/esm/button/index.js +9 -4
- package/dist/esm/button/index.test.js +63 -5
- package/dist/esm/card/core-card.js +0 -2
- package/dist/esm/card/style-core.scss +7 -5
- package/dist/esm/card-feature/index.js +78 -62
- package/dist/esm/card-feature/index.test.js +397 -55
- package/dist/esm/card-feature/style.scss +20 -31
- package/dist/esm/card-form/index.js +5 -5
- package/dist/esm/card-sortable-list/index.js +6 -4
- package/dist/esm/card-sortable-list/index.test.js +46 -0
- package/dist/esm/collapsible-group/context.js +13 -0
- package/dist/esm/collapsible-group/index.js +17 -0
- package/dist/esm/collapsible-group/index.test.js +215 -0
- package/dist/esm/collapsible-group/item.js +53 -0
- package/dist/esm/collapsible-group/root.js +54 -0
- package/dist/esm/collapsible-group/style.scss +47 -0
- package/dist/esm/collapsible-group/types.js +1 -0
- package/dist/esm/empty-state/actions.js +37 -0
- package/dist/esm/empty-state/context.js +35 -0
- package/dist/esm/empty-state/header.js +58 -0
- package/dist/esm/empty-state/index.js +23 -0
- package/dist/esm/empty-state/index.test.js +299 -0
- package/dist/esm/empty-state/root.js +56 -0
- package/dist/esm/empty-state/style.scss +51 -0
- package/dist/esm/empty-state/types.js +1 -0
- package/dist/esm/index.js +4 -2
- package/dist/esm/info-button/index.js +54 -43
- package/dist/esm/info-button/index.test.js +195 -0
- package/dist/esm/info-button/style.scss +41 -9
- package/dist/esm/modal/style.scss +12 -12
- package/dist/esm/newspack-icon/style.scss +4 -4
- package/dist/esm/notice/style.scss +3 -3
- package/dist/esm/page/style.scss +16 -16
- package/dist/esm/plugin-installer/index.js +5 -9
- package/dist/esm/plugin-installer/style.scss +3 -14
- package/dist/esm/section-header/index.js +27 -14
- package/dist/esm/section-header/index.test.js +36 -0
- package/dist/esm/section-header/style.scss +22 -6
- package/dist/esm/settings/DateRangeSetting.js +304 -0
- package/dist/esm/settings/SettingsSection.js +16 -3
- package/dist/esm/settings/SettingsSection.test.js +45 -0
- package/dist/esm/settings/index.js +3 -1
- package/dist/esm/settings/style.scss +40 -7
- package/dist/esm/stat-card/body.js +36 -0
- package/dist/esm/stat-card/constants.js +5 -0
- package/dist/esm/stat-card/context.js +48 -0
- package/dist/esm/stat-card/delta.js +86 -0
- package/dist/esm/stat-card/footer.js +67 -0
- package/dist/esm/stat-card/index.js +33 -0
- package/dist/esm/stat-card/index.test.js +939 -0
- package/dist/esm/stat-card/label.js +61 -0
- package/dist/esm/stat-card/root.js +64 -0
- package/dist/esm/stat-card/secondary.js +33 -0
- package/dist/esm/stat-card/style.scss +89 -0
- package/dist/esm/stat-card/types.js +1 -0
- package/dist/esm/stat-card/value.js +73 -0
- package/dist/esm/status-indicator/index.js +52 -0
- package/dist/esm/status-indicator/index.test.js +96 -0
- package/dist/esm/status-indicator/statuses.js +33 -0
- package/dist/esm/status-indicator/style.scss +9 -0
- package/dist/esm/status-indicator/types.js +1 -0
- package/dist/esm/style.scss +9 -9
- package/dist/esm/tabbed-navigation/style.scss +6 -4
- package/dist/esm/types.js +1 -0
- package/dist/esm/web-preview/style.scss +11 -11
- package/dist/esm/with-wizard/style.scss +10 -10
- package/dist/esm/with-wizard-screen/style.scss +9 -9
- package/dist/esm/wizard/index.js +38 -7
- package/dist/esm/wizard/store/index.js +23 -1
- package/package.json +1 -1
- package/src/_mixins.scss +13 -0
- package/src/_variables.scss +12 -0
- package/src/action-card/action-card.d.ts +3 -2
- package/src/action-card/index.js +12 -12
- package/src/action-card/index.test.js +56 -0
- package/src/action-card/style.scss +2 -40
- package/src/button/index.test.js +52 -5
- package/src/button/index.tsx +9 -4
- package/src/card/core-card.js +0 -2
- package/src/card/style-core.scss +7 -5
- package/src/card-feature/README.md +68 -27
- package/src/card-feature/index.test.js +242 -27
- package/src/card-feature/index.tsx +77 -67
- package/src/card-feature/style.scss +20 -31
- package/src/card-form/README.md +10 -10
- package/src/card-form/index.tsx +4 -8
- package/src/card-sortable-list/README.md +4 -5
- package/src/card-sortable-list/index.test.js +29 -0
- package/src/card-sortable-list/index.tsx +7 -4
- package/src/collapsible-group/README.md +50 -0
- package/src/collapsible-group/context.ts +13 -0
- package/src/collapsible-group/index.test.js +168 -0
- package/src/collapsible-group/index.tsx +17 -0
- package/src/collapsible-group/item.tsx +42 -0
- package/src/collapsible-group/root.tsx +42 -0
- package/src/collapsible-group/style.scss +47 -0
- package/src/collapsible-group/types.ts +22 -0
- package/src/drawer/README.md +2 -2
- package/src/empty-state/README.md +165 -0
- package/src/empty-state/actions.tsx +37 -0
- package/src/empty-state/context.ts +40 -0
- package/src/empty-state/header.tsx +48 -0
- package/src/empty-state/index.test.js +247 -0
- package/src/empty-state/index.tsx +22 -0
- package/src/empty-state/root.tsx +39 -0
- package/src/empty-state/style.scss +51 -0
- package/src/empty-state/types.ts +33 -0
- package/src/index.js +4 -2
- package/src/info-button/README.md +115 -0
- package/src/info-button/index.test.js +163 -0
- package/src/info-button/index.tsx +64 -0
- package/src/info-button/style.scss +41 -9
- package/src/modal/style.scss +12 -12
- package/src/newspack-icon/style.scss +4 -4
- package/src/notice/style.scss +3 -3
- package/src/page/style.scss +16 -16
- package/src/plugin-installer/index.js +3 -9
- package/src/plugin-installer/style.scss +3 -14
- package/src/section-header/index.js +27 -14
- package/src/section-header/index.test.js +28 -0
- package/src/section-header/style.scss +22 -6
- package/src/settings/DateRangeSetting.js +266 -0
- package/src/settings/SettingsSection.js +24 -4
- package/src/settings/SettingsSection.test.js +45 -0
- package/src/settings/index.js +2 -0
- package/src/settings/style.scss +40 -7
- package/src/stat-card/README.md +434 -0
- package/src/stat-card/body.tsx +28 -0
- package/src/stat-card/constants.ts +5 -0
- package/src/stat-card/context.ts +53 -0
- package/src/stat-card/delta.tsx +88 -0
- package/src/stat-card/footer.tsx +68 -0
- package/src/stat-card/index.test.js +818 -0
- package/src/stat-card/index.tsx +48 -0
- package/src/stat-card/label.tsx +61 -0
- package/src/stat-card/root.tsx +40 -0
- package/src/stat-card/secondary.tsx +27 -0
- package/src/stat-card/style.scss +89 -0
- package/src/stat-card/types.ts +84 -0
- package/src/stat-card/value.tsx +72 -0
- package/src/status-indicator/README.md +123 -0
- package/src/status-indicator/index.test.js +70 -0
- package/src/status-indicator/index.tsx +39 -0
- package/src/status-indicator/statuses.ts +35 -0
- package/src/status-indicator/style.scss +9 -0
- package/src/status-indicator/types.ts +28 -0
- package/src/style.scss +9 -9
- package/src/tabbed-navigation/style.scss +6 -4
- package/src/types.ts +25 -0
- package/src/web-preview/style.scss +11 -11
- package/src/with-wizard/style.scss +10 -10
- package/src/with-wizard-screen/style.scss +9 -9
- package/src/wizard/index.js +49 -7
- package/src/wizard/store/index.js +26 -1
- package/dist/cjs/accordion/index.js +0 -72
- package/dist/cjs/accordion/index.test.js +0 -80
- package/dist/cjs/accordion/style.scss +0 -35
- package/dist/cjs/badge/index.js +0 -32
- package/dist/cjs/badge/style.scss +0 -36
- package/dist/esm/accordion/index.js +0 -63
- package/dist/esm/accordion/index.test.js +0 -79
- package/dist/esm/accordion/style.scss +0 -35
- package/dist/esm/badge/index.js +0 -24
- package/dist/esm/badge/style.scss +0 -36
- package/src/accordion/index.js +0 -46
- package/src/accordion/index.test.js +0 -62
- package/src/accordion/style.scss +0 -35
- package/src/badge/index.tsx +0 -26
- package/src/badge/style.scss +0 -36
- package/src/info-button/index.js +0 -38
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
6
|
-
@use "../../../colors/colors.module" as colors;
|
|
6
|
+
@use "../../../colors/colors.module" as np-colors;
|
|
7
7
|
|
|
8
8
|
.newspack-wizard {
|
|
9
9
|
// Color
|
|
10
|
-
--wp-admin-theme-color: #{colors.$primary-600};
|
|
11
|
-
--wp-admin-theme-color--rgb: #{colors.$primary-600--rgb};
|
|
12
|
-
--wp-admin-theme-color-darker-10: #{colors.$primary-700};
|
|
13
|
-
--wp-admin-theme-color-darker-10--rgb: #{colors.$primary-700--rgb};
|
|
14
|
-
--wp-admin-theme-color-darker-20: #{colors.$primary-800};
|
|
15
|
-
--wp-admin-theme-color-darker-20--rgb: #{colors.$primary-800--rgb};
|
|
16
|
-
--wp-admin-theme-color-lighter-10: #{colors.$primary-000};
|
|
17
|
-
--wp-admin-theme-color-lighter-10--rgb: #{colors.$primary-000--rgb};
|
|
10
|
+
--wp-admin-theme-color: #{np-colors.$primary-600};
|
|
11
|
+
--wp-admin-theme-color--rgb: #{np-colors.$primary-600--rgb};
|
|
12
|
+
--wp-admin-theme-color-darker-10: #{np-colors.$primary-700};
|
|
13
|
+
--wp-admin-theme-color-darker-10--rgb: #{np-colors.$primary-700--rgb};
|
|
14
|
+
--wp-admin-theme-color-darker-20: #{np-colors.$primary-800};
|
|
15
|
+
--wp-admin-theme-color-darker-20--rgb: #{np-colors.$primary-800--rgb};
|
|
16
|
+
--wp-admin-theme-color-lighter-10: #{np-colors.$primary-000};
|
|
17
|
+
--wp-admin-theme-color-lighter-10--rgb: #{np-colors.$primary-000--rgb};
|
|
18
18
|
|
|
19
19
|
color: wp-colors.$gray-900;
|
|
20
20
|
|
package/dist/esm/wizard/index.js
CHANGED
|
@@ -11,16 +11,18 @@ import classnames from 'classnames';
|
|
|
11
11
|
* WordPress dependencies.
|
|
12
12
|
*/
|
|
13
13
|
// Notice is aliased: `Notice` below is Newspack's own, which this file also uses.
|
|
14
|
-
import { DropdownMenu, MenuGroup, MenuItem, Notice as CoreNotice, SlotFillProvider, createSlotFill
|
|
14
|
+
import { DropdownMenu, MenuGroup, MenuItem, Notice as CoreNotice, SlotFillProvider, createSlotFill,
|
|
15
|
+
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
|
|
16
|
+
__experimentalVStack as VStack } from '@wordpress/components';
|
|
15
17
|
import { useDispatch, useSelect } from '@wordpress/data';
|
|
16
|
-
import { cloneElement, createInterpolateElement, isValidElement,
|
|
18
|
+
import { cloneElement, createInterpolateElement, isValidElement, useEffect, useRef, useState, forwardRef } from '@wordpress/element';
|
|
17
19
|
import { __ } from '@wordpress/i18n';
|
|
18
20
|
import { category, chevronLeft, moreVertical } from '@wordpress/icons';
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
23
|
* Internal dependencies
|
|
22
24
|
*/
|
|
23
|
-
import { Footer, Notice, Button, TabbedNavigation, PluginInstaller, SectionHeader, HandoffMessage, Page } from '../';
|
|
25
|
+
import { Footer, Notice, Button, TabbedNavigation, PluginInstaller, SectionHeader, HandoffMessage, Page, Waiting } from '../';
|
|
24
26
|
import { activeBreadcrumbs, appendSectionName } from './breadcrumbs-select';
|
|
25
27
|
import Router from '../proxied-imports/router';
|
|
26
28
|
import registerStore, { WIZARD_STORE_NAMESPACE } from './store';
|
|
@@ -204,6 +206,7 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
204
206
|
sectionDescription = headerData.sectionDescription,
|
|
205
207
|
sectionMenu = headerData.sectionMenu,
|
|
206
208
|
sectionName = headerData.sectionName,
|
|
209
|
+
sectionSize = headerData.sectionSize,
|
|
207
210
|
sectionTitle = headerData.sectionTitle,
|
|
208
211
|
sectionPrimaryAction = headerData.sectionPrimaryAction,
|
|
209
212
|
sectionSecondaryAction = headerData.sectionSecondaryAction;
|
|
@@ -226,6 +229,14 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
226
229
|
_useState2 = _slicedToArray(_useState, 2),
|
|
227
230
|
pluginRequirementsSatisfied = _useState2[0],
|
|
228
231
|
setPluginRequirementsSatisfied = _useState2[1];
|
|
232
|
+
// Whether the requirements check has reported back. Until it has, the check
|
|
233
|
+
// shows the same fetching treatment as the rest of the wizard rather than
|
|
234
|
+
// the installer's own spinner and the swapped header; the installer only
|
|
235
|
+
// surfaces once a plugin is actually found missing.
|
|
236
|
+
var _useState3 = useState(requiredPlugins.length === 0),
|
|
237
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
238
|
+
pluginRequirementsKnown = _useState4[0],
|
|
239
|
+
setPluginRequirementsKnown = _useState4[1];
|
|
229
240
|
|
|
230
241
|
// The data fetch above runs once per mount, while the required plugins are
|
|
231
242
|
// still missing — endpoints that need them answer empty or error outright,
|
|
@@ -240,6 +251,7 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
240
251
|
// Leave the installer first: whatever happens to the refetch, the user
|
|
241
252
|
// should not be stranded on a required-plugins screen for a plugin they
|
|
242
253
|
// just installed.
|
|
254
|
+
setPluginRequirementsKnown(true);
|
|
243
255
|
setPluginRequirementsSatisfied(complete);
|
|
244
256
|
if (!complete) {
|
|
245
257
|
requirementsWereUnmet.current = true;
|
|
@@ -251,13 +263,31 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
251
263
|
}
|
|
252
264
|
};
|
|
253
265
|
if (!pluginRequirementsSatisfied) {
|
|
254
|
-
|
|
266
|
+
if (pluginRequirementsKnown) {
|
|
267
|
+
headerText = requiredPlugins.length > 1 ? __('Required plugins', 'newspack-plugin') : __('Required plugin', 'newspack-plugin');
|
|
268
|
+
}
|
|
255
269
|
displayedSections = [{
|
|
256
270
|
path: '/',
|
|
257
271
|
render: function render() {
|
|
258
|
-
return /*#__PURE__*/
|
|
259
|
-
|
|
260
|
-
|
|
272
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
273
|
+
children: [!pluginRequirementsKnown && /*#__PURE__*/_jsx("div", {
|
|
274
|
+
className: "newspack-wizard__loader",
|
|
275
|
+
children: /*#__PURE__*/_jsxs(VStack, {
|
|
276
|
+
alignment: "center",
|
|
277
|
+
spacing: 2,
|
|
278
|
+
children: [/*#__PURE__*/_jsx(Waiting, {
|
|
279
|
+
noMargin: true
|
|
280
|
+
}), /*#__PURE__*/_jsx("strong", {
|
|
281
|
+
children: __('Fetching…', 'newspack-plugin')
|
|
282
|
+
})]
|
|
283
|
+
})
|
|
284
|
+
}), /*#__PURE__*/_jsx("div", {
|
|
285
|
+
hidden: !pluginRequirementsKnown,
|
|
286
|
+
children: /*#__PURE__*/_jsx(PluginInstaller, {
|
|
287
|
+
plugins: requiredPlugins,
|
|
288
|
+
onStatus: onPluginStatus
|
|
289
|
+
})
|
|
290
|
+
})]
|
|
261
291
|
});
|
|
262
292
|
}
|
|
263
293
|
}];
|
|
@@ -321,6 +351,7 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
321
351
|
primaryAction: sectionPrimaryAction || section.primaryAction,
|
|
322
352
|
secondaryAction: sectionSecondaryAction || section.secondaryAction,
|
|
323
353
|
heading: 2,
|
|
354
|
+
size: sectionSize || section.size,
|
|
324
355
|
noMargin: true
|
|
325
356
|
}), /*#__PURE__*/_jsx(SectionComponent, _objectSpread(_objectSpread(_objectSpread({}, routerProps), sectionProps), sharedProps))]
|
|
326
357
|
});
|
|
@@ -257,6 +257,28 @@ var store = createReduxStore(WIZARD_STORE_NAMESPACE, {
|
|
|
257
257
|
})
|
|
258
258
|
}
|
|
259
259
|
});
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Register the wizard store, unless it already exists.
|
|
263
|
+
*
|
|
264
|
+
* This package is bundled separately into each consuming plugin, so more than one
|
|
265
|
+
* bundle can call this on the same page (e.g. the block editor loads assets from
|
|
266
|
+
* both newspack-blocks and newspack-manager). @wordpress/data keeps a single
|
|
267
|
+
* registry on `wp.data`, so the second call is a no-op that logs
|
|
268
|
+
* `Store "newspack/wizards" is already registered.` — guard it instead.
|
|
269
|
+
*
|
|
270
|
+
* The first bundle to register wins, and it is not necessarily the newest one:
|
|
271
|
+
* consumers rebuild on their own schedules, so an older copy of this package can
|
|
272
|
+
* get there first and leave newer selectors missing. That is worth knowing about
|
|
273
|
+
* while developing, so keep the breadcrumb outside production builds.
|
|
274
|
+
*/
|
|
260
275
|
export default (function () {
|
|
261
|
-
|
|
276
|
+
if (select(WIZARD_STORE_NAMESPACE)) {
|
|
277
|
+
if ('production' !== process.env.NODE_ENV) {
|
|
278
|
+
// eslint-disable-next-line no-console
|
|
279
|
+
console.warn("Wizard store: \"".concat(WIZARD_STORE_NAMESPACE, "\" is already registered, so this copy of newspack-components was ignored. Two bundles of the package are on this page and the first one to load wins."));
|
|
280
|
+
}
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
register(store);
|
|
262
284
|
});
|
package/package.json
CHANGED
package/src/_mixins.scss
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@use "../../colors/colors.module" as colors;
|
|
2
|
+
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
3
|
+
@use "~@wordpress/base-styles/variables" as wp-vars;
|
|
4
|
+
|
|
5
|
+
@mixin text-muted {
|
|
6
|
+
/* stylelint-disable-next-line plugin-wpds/no-unknown-ds-tokens -- the plugin's token list lags the prebuilt design-tokens.css names. */
|
|
7
|
+
color: var( --wpds-color-foreground-content-neutral-weak, #{wp-colors.$gray-700} );
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@mixin wpds-focus-ring {
|
|
11
|
+
/* stylelint-disable-next-line plugin-wpds/no-unknown-ds-tokens -- the plugin's token list lags the prebuilt design-tokens.css names. */
|
|
12
|
+
outline: var( --wpds-border-width-focus, var( --wp-admin-border-width-focus, #{wp-vars.$border-width-focus-fallback} ) ) solid var( --wpds-color-stroke-focus, var( --wp-admin-theme-color, #{colors.$primary-600} ) );
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SCSS Variables.
|
|
3
|
+
*
|
|
4
|
+
* The steps this package needs above the @wordpress/base-styles scale. Please
|
|
5
|
+
* reach for a base-styles variable first, and only add here when there is no
|
|
6
|
+
* counterpart and you're pretty sure the value will be reused in many places.
|
|
7
|
+
* It's purely for UI. Don't add component-specific values, which belong in that
|
|
8
|
+
* component's own stylesheet.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
$font-size-3x-large: 48px;
|
|
12
|
+
$font-line-height-3x-large: 1.125;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { CardBadge } from '../types';
|
|
2
|
+
|
|
1
3
|
export interface ActionCardProps {
|
|
2
4
|
id?: string | number;
|
|
3
5
|
title?: string | React.ReactNode;
|
|
@@ -5,8 +7,7 @@ export interface ActionCardProps {
|
|
|
5
7
|
href?: string;
|
|
6
8
|
description?: string | React.ReactNode;
|
|
7
9
|
actionText?: React.ReactNode | string | null;
|
|
8
|
-
|
|
9
|
-
badgeLevel?: 'success' | 'info' | 'warning' | 'error';
|
|
10
|
+
badges?: CardBadge[];
|
|
10
11
|
className?: string;
|
|
11
12
|
indent?: string;
|
|
12
13
|
notification?: string | Error | null;
|
package/src/action-card/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { Draggable, ExternalLink, ToggleControl } from '@wordpress/components';
|
|
|
9
9
|
import { useEffect, useState } from '@wordpress/element';
|
|
10
10
|
import { __ } from '@wordpress/i18n';
|
|
11
11
|
import { Icon, check, chevronDown, chevronUp, dragHandle } from '@wordpress/icons';
|
|
12
|
+
import { Badge } from '@wordpress/ui';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Internal dependencies
|
|
@@ -28,8 +29,7 @@ import classnames from 'classnames';
|
|
|
28
29
|
* @return {JSX.Element} ActionCard component.
|
|
29
30
|
*/
|
|
30
31
|
const ActionCard = ( {
|
|
31
|
-
|
|
32
|
-
badgeLevel,
|
|
32
|
+
badges,
|
|
33
33
|
className,
|
|
34
34
|
checkbox,
|
|
35
35
|
children,
|
|
@@ -78,6 +78,11 @@ const ActionCard = ( {
|
|
|
78
78
|
dragWrapperRef,
|
|
79
79
|
onDragCallback,
|
|
80
80
|
} ) => {
|
|
81
|
+
// A badge with no label paints an empty pill, since the library Badge styles its
|
|
82
|
+
// wrapper rather than its text. Callers derive labels from data that can be absent
|
|
83
|
+
// (a gateway with no connection status, an unmapped placement), so drop those here
|
|
84
|
+
// rather than asking every caller to guard its own array.
|
|
85
|
+
const visibleBadges = ( badges || [] ).filter( badge => badge?.label );
|
|
81
86
|
const [ expanded, setExpanded ] = useState( Boolean( isExpanded ) );
|
|
82
87
|
const [ dragging, setDragging ] = useState( false );
|
|
83
88
|
const [ targetIndex, setTargetIndex ] = useState( null );
|
|
@@ -124,7 +129,6 @@ const ActionCard = ( {
|
|
|
124
129
|
const togglePositionClass = togglePosition === 'trailing' ? 'is-toggle-trailing' : 'is-toggle-leading';
|
|
125
130
|
const hasInternalLink = href && href.indexOf( 'http' ) !== 0;
|
|
126
131
|
const isDisplayingSecondaryAction = secondaryActionText && onSecondaryActionClick;
|
|
127
|
-
const badges = ! Array.isArray( badge ) && badge ? [ badge ] : badge;
|
|
128
132
|
const HeadingTag = `h${ heading }`;
|
|
129
133
|
|
|
130
134
|
const cardContent = (
|
|
@@ -166,15 +170,11 @@ const ActionCard = ( {
|
|
|
166
170
|
) }
|
|
167
171
|
{ ! titleLink && ! expandable && title }
|
|
168
172
|
</span>
|
|
169
|
-
{
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
>
|
|
175
|
-
{ badgeText }
|
|
176
|
-
</span>
|
|
177
|
-
) ) }
|
|
173
|
+
{ visibleBadges.map( ( { label, intent }, i ) => (
|
|
174
|
+
<Badge key={ `badge-${ i }` } intent={ intent ?? 'none' }>
|
|
175
|
+
{ label }
|
|
176
|
+
</Badge>
|
|
177
|
+
) ) }
|
|
178
178
|
</HeadingTag>
|
|
179
179
|
{ description && (
|
|
180
180
|
<p>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies.
|
|
3
|
+
*/
|
|
4
|
+
import { render, screen } from '@testing-library/react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies.
|
|
8
|
+
*/
|
|
9
|
+
import ActionCard from './index';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The library Badge styles its wrapper rather than its text, so a badge with no label
|
|
13
|
+
* paints a bare coloured pill. Callers build the `badges` array from data that can be
|
|
14
|
+
* absent — a payment gateway reports no connection status until it is enabled, a prompt
|
|
15
|
+
* can sit on a placement with no entry in the placement map — and an array literal is
|
|
16
|
+
* always non-empty, so the component has to drop those itself.
|
|
17
|
+
*/
|
|
18
|
+
describe( 'ActionCard badges', () => {
|
|
19
|
+
const badgeText = () => screen.queryAllByText( ( _, node ) => /__badge/.test( node?.className || '' ) );
|
|
20
|
+
|
|
21
|
+
it( 'renders a badge that has a label', () => {
|
|
22
|
+
render( <ActionCard title="Stripe" badges={ [ { label: 'Connected', intent: 'stable' } ] } /> );
|
|
23
|
+
|
|
24
|
+
expect( screen.getByText( 'Connected' ) ).toBeInTheDocument();
|
|
25
|
+
} );
|
|
26
|
+
|
|
27
|
+
it( 'renders no badge when the label is null', () => {
|
|
28
|
+
const { container } = render( <ActionCard title="Stripe" badges={ [ { label: null, intent: 'informational' } ] } /> );
|
|
29
|
+
|
|
30
|
+
expect( container.querySelectorAll( '[class*="__badge"]' ) ).toHaveLength( 0 );
|
|
31
|
+
} );
|
|
32
|
+
|
|
33
|
+
it( 'renders no badge when the label is undefined or empty', () => {
|
|
34
|
+
const { container } = render( <ActionCard title="Stripe" badges={ [ { label: undefined }, { label: '' } ] } /> );
|
|
35
|
+
|
|
36
|
+
expect( container.querySelectorAll( '[class*="__badge"]' ) ).toHaveLength( 0 );
|
|
37
|
+
} );
|
|
38
|
+
|
|
39
|
+
it( 'keeps the labelled badges and drops only the empty ones', () => {
|
|
40
|
+
render( <ActionCard title="Plans" badges={ [ { label: 'Premium' }, { label: null }, { label: 'Archived', intent: 'draft' } ] } /> );
|
|
41
|
+
|
|
42
|
+
expect( screen.getByText( 'Premium' ) ).toBeInTheDocument();
|
|
43
|
+
expect( screen.getByText( 'Archived' ) ).toBeInTheDocument();
|
|
44
|
+
expect( badgeText() ).toHaveLength( 2 );
|
|
45
|
+
} );
|
|
46
|
+
|
|
47
|
+
it( 'renders nothing for an absent or empty badges prop', () => {
|
|
48
|
+
const { container: withoutProp } = render( <ActionCard title="Stripe" /> );
|
|
49
|
+
expect( withoutProp.querySelectorAll( '[class*="__badge"]' ) ).toHaveLength( 0 );
|
|
50
|
+
|
|
51
|
+
const { container: withEmptyArray } = render( <ActionCard title="Stripe" badges={ [] } /> );
|
|
52
|
+
expect( withEmptyArray.querySelectorAll( '[class*="__badge"]' ) ).toHaveLength( 0 );
|
|
53
|
+
// An empty array used to fall through as a literal `0` in the heading.
|
|
54
|
+
expect( withEmptyArray.textContent ).not.toContain( '0' );
|
|
55
|
+
} );
|
|
56
|
+
} );
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
@use "sass:color";
|
|
6
6
|
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
7
|
+
@use "~@wordpress/base-styles/variables" as wp-vars;
|
|
7
8
|
|
|
8
9
|
.newspack-card.newspack-action-card {
|
|
9
10
|
padding: 0;
|
|
@@ -196,11 +197,7 @@
|
|
|
196
197
|
align-items: center;
|
|
197
198
|
display: flex;
|
|
198
199
|
flex-wrap: wrap;
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
.newspack-action-card__title {
|
|
202
|
-
margin-right: 8px;
|
|
203
|
-
}
|
|
200
|
+
gap: wp-vars.$grid-unit-10;
|
|
204
201
|
|
|
205
202
|
a {
|
|
206
203
|
color: inherit;
|
|
@@ -372,41 +369,6 @@
|
|
|
372
369
|
margin: 0;
|
|
373
370
|
}
|
|
374
371
|
|
|
375
|
-
/* Badge */
|
|
376
|
-
.newspack-action-card__badge {
|
|
377
|
-
background: wp-colors.$gray-100;
|
|
378
|
-
border-radius: 2px;
|
|
379
|
-
color: wp-colors.$gray-900;
|
|
380
|
-
display: block;
|
|
381
|
-
flex: 0 0 auto;
|
|
382
|
-
font-size: 12px;
|
|
383
|
-
font-weight: 400;
|
|
384
|
-
line-height: 1.333;
|
|
385
|
-
margin: 0 8px 0 0;
|
|
386
|
-
padding: 2px 4px;
|
|
387
|
-
|
|
388
|
-
&.newspack-action-card__badge-level-warning {
|
|
389
|
-
background-color: color-mix(in srgb, #fff 90%, wp-colors.$alert-yellow);
|
|
390
|
-
color: color-mix(in srgb, #000 50%, wp-colors.$alert-yellow);
|
|
391
|
-
}
|
|
392
|
-
&.newspack-action-card__badge-level-error {
|
|
393
|
-
background-color: color-mix(in srgb, #fff 90%, wp-colors.$alert-red);
|
|
394
|
-
color: color-mix(in srgb, #000 50%, wp-colors.$alert-red);
|
|
395
|
-
}
|
|
396
|
-
&.newspack-action-card__badge-level-success {
|
|
397
|
-
background-color: color-mix(in srgb, #fff 90%, wp-colors.$alert-green);
|
|
398
|
-
color: color-mix(in srgb, #000 50%, wp-colors.$alert-green);
|
|
399
|
-
}
|
|
400
|
-
&.newspack-action-card__badge-level-brand {
|
|
401
|
-
background-color: color-mix(in srgb, #fff 90%, var(--wp-admin-theme-color));
|
|
402
|
-
color: color-mix(in srgb, #000 50%, var(--wp-admin-theme-color));
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
+ .newspack-action-card__badge {
|
|
406
|
-
margin-left: -4px;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
372
|
/* Description Card */
|
|
411
373
|
&.newspack-description-card {
|
|
412
374
|
font-style: italic;
|
package/src/button/index.test.js
CHANGED
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
import { act, render, screen } from '@testing-library/react';
|
|
5
5
|
import { MemoryRouter, useHistory } from 'react-router-dom';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* WordPress dependencies.
|
|
9
|
+
*/
|
|
10
|
+
import { createRef } from '@wordpress/element';
|
|
11
|
+
|
|
7
12
|
/**
|
|
8
13
|
* Internal dependencies.
|
|
9
14
|
*/
|
|
@@ -20,6 +25,16 @@ const clickButton = async () => {
|
|
|
20
25
|
} );
|
|
21
26
|
};
|
|
22
27
|
|
|
28
|
+
// React formats its warnings with `%s` placeholders and passes the values as
|
|
29
|
+
// further arguments, so assert against the whole call rather than one argument.
|
|
30
|
+
const messagesFrom = spy => spy.mock.calls.flat().join( ' ' );
|
|
31
|
+
|
|
32
|
+
// A failing assertion skips any `mockRestore()` left after it, which would leave
|
|
33
|
+
// the console swallowed for every later test in the file.
|
|
34
|
+
afterEach( () => {
|
|
35
|
+
jest.restoreAllMocks();
|
|
36
|
+
} );
|
|
37
|
+
|
|
23
38
|
describe( 'Button href with onClick', () => {
|
|
24
39
|
it( 'awaits the onClick, then pushes the route', async () => {
|
|
25
40
|
const historyRef = { current: null };
|
|
@@ -113,7 +128,6 @@ describe( 'Button href with onClick outside a router', () => {
|
|
|
113
128
|
expect( window.location.href ).toBe( '' );
|
|
114
129
|
} );
|
|
115
130
|
expect( warn ).toHaveBeenCalledWith( expect.stringContaining( 'javascript:' ) );
|
|
116
|
-
warn.mockRestore();
|
|
117
131
|
} );
|
|
118
132
|
} );
|
|
119
133
|
|
|
@@ -121,19 +135,18 @@ describe( 'Button with a javascript: href alone', () => {
|
|
|
121
135
|
const link = () => screen.getByText( 'Save' ).closest( 'a' );
|
|
122
136
|
|
|
123
137
|
it( 'renders no link', () => {
|
|
124
|
-
|
|
138
|
+
// Silenced only; the assertion below is about the markup, not the warning.
|
|
139
|
+
jest.spyOn( console, 'warn' ).mockImplementation( () => {} );
|
|
125
140
|
render( <Button href="JavaScript:alert(1)">Save</Button> );
|
|
126
141
|
|
|
127
142
|
expect( link() ).toBeNull();
|
|
128
|
-
warn.mockRestore();
|
|
129
143
|
} );
|
|
130
144
|
|
|
131
145
|
it( 'sees through interleaved control characters', () => {
|
|
132
|
-
|
|
146
|
+
jest.spyOn( console, 'warn' ).mockImplementation( () => {} );
|
|
133
147
|
render( <Button href={ 'java\nscript:alert(1)' }>Save</Button> );
|
|
134
148
|
|
|
135
149
|
expect( link() ).toBeNull();
|
|
136
|
-
warn.mockRestore();
|
|
137
150
|
} );
|
|
138
151
|
|
|
139
152
|
it( 'leaves an ordinary href alone', () => {
|
|
@@ -141,3 +154,37 @@ describe( 'Button with a javascript: href alone', () => {
|
|
|
141
154
|
expect( link() ).toHaveAttribute( 'href', '/wp-admin/admin.php?page=next' );
|
|
142
155
|
} );
|
|
143
156
|
} );
|
|
157
|
+
|
|
158
|
+
describe( 'Button loading prop', () => {
|
|
159
|
+
const button = () => screen.getByRole( 'button', { name: 'Save' } );
|
|
160
|
+
|
|
161
|
+
it( 'renders the core busy state without putting `loading` on the DOM node', () => {
|
|
162
|
+
const error = jest.spyOn( console, 'error' ).mockImplementation( () => {} );
|
|
163
|
+
const { rerender } = render( <Button>Save</Button> );
|
|
164
|
+
|
|
165
|
+
expect( button() ).not.toHaveClass( 'is-busy' );
|
|
166
|
+
|
|
167
|
+
rerender( <Button loading>Save</Button> );
|
|
168
|
+
|
|
169
|
+
expect( button() ).toHaveClass( 'is-busy' );
|
|
170
|
+
// React drops an unknown boolean-valued attribute instead of writing it, so
|
|
171
|
+
// the warning rather than the absent attribute is what a revert trips. It is
|
|
172
|
+
// also deduped per property name for the life of the module registry, which
|
|
173
|
+
// is why this names the message instead of asserting no errors at all.
|
|
174
|
+
expect( messagesFrom( error ) ).not.toContain( 'non-boolean attribute' );
|
|
175
|
+
} );
|
|
176
|
+
} );
|
|
177
|
+
|
|
178
|
+
// core's Button wraps itself in a Tooltip when it is given a `label`, and the
|
|
179
|
+
// Tooltip needs a ref on its child. Two call sites do that with this Button:
|
|
180
|
+
// the experimental-tools back button and the audience segment-group heading.
|
|
181
|
+
describe( 'Button ref', () => {
|
|
182
|
+
it( 'forwards the ref to the rendered button', () => {
|
|
183
|
+
const error = jest.spyOn( console, 'error' ).mockImplementation( () => {} );
|
|
184
|
+
const ref = createRef();
|
|
185
|
+
render( <Button ref={ ref }>Save</Button> );
|
|
186
|
+
|
|
187
|
+
expect( ref.current ).toBe( screen.getByRole( 'button', { name: 'Save' } ) );
|
|
188
|
+
expect( messagesFrom( error ) ).not.toContain( 'Function components cannot be given refs' );
|
|
189
|
+
} );
|
|
190
|
+
} );
|
package/src/button/index.tsx
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* WordPress dependencies.
|
|
7
7
|
*/
|
|
8
8
|
import { Button as BaseComponent } from '@wordpress/components';
|
|
9
|
-
import { useEffect, useState } from '@wordpress/element';
|
|
9
|
+
import { forwardRef, useEffect, useState } from '@wordpress/element';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Internal dependencies
|
|
@@ -32,7 +32,7 @@ const isJavascriptHref = ( href?: string ) =>
|
|
|
32
32
|
.toLowerCase()
|
|
33
33
|
.startsWith( 'javascript:' );
|
|
34
34
|
|
|
35
|
-
const Button = ( { href, loading = undefined, onClick, ...otherProps }: Props ) => {
|
|
35
|
+
const Button = forwardRef< HTMLElement, Props >( ( { href, loading = undefined, onClick, ...otherProps }: Props, ref ) => {
|
|
36
36
|
const history = useHistory();
|
|
37
37
|
const [ isAwaitingOnClick, setIsAwaitingOnClick ] = useState( false );
|
|
38
38
|
|
|
@@ -67,8 +67,13 @@ const Button = ( { href, loading = undefined, onClick, ...otherProps }: Props )
|
|
|
67
67
|
if ( isAwaitingOnClick ) {
|
|
68
68
|
otherProps.disabled = true;
|
|
69
69
|
}
|
|
70
|
+
// `loading` is this component's own prop name; @wordpress/components' Button
|
|
71
|
+
// expresses the same state as `isBusy`. Forwarding `loading` verbatim would
|
|
72
|
+
// land it on the DOM node, which React rejects as a non-boolean attribute.
|
|
70
73
|
// @ts-expect-error - @wordpress/components' Button can only have either href or onClick, not both.
|
|
71
|
-
return <BaseComponent
|
|
72
|
-
};
|
|
74
|
+
return <BaseComponent ref={ ref } isBusy={ loading ? true : undefined } { ...otherProps } />;
|
|
75
|
+
} );
|
|
76
|
+
|
|
77
|
+
Button.displayName = 'Button';
|
|
73
78
|
|
|
74
79
|
export default Button;
|
package/src/card/core-card.js
CHANGED
|
@@ -152,7 +152,6 @@ const CoreCard = ( {
|
|
|
152
152
|
<ToggleControl
|
|
153
153
|
className="newspack-card--core__action"
|
|
154
154
|
label={ otherProps.title }
|
|
155
|
-
hideLabelFromVision
|
|
156
155
|
checked={ isActive }
|
|
157
156
|
onChange={ onToggle }
|
|
158
157
|
/>
|
|
@@ -165,7 +164,6 @@ const CoreCard = ( {
|
|
|
165
164
|
<ToggleControl
|
|
166
165
|
className="newspack-card--core__action"
|
|
167
166
|
label={ otherProps.title }
|
|
168
|
-
hideLabelFromVision
|
|
169
167
|
checked={ isActive }
|
|
170
168
|
onChange={ onToggle }
|
|
171
169
|
/>
|
package/src/card/style-core.scss
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
6
6
|
@use "~@wordpress/base-styles/variables" as wp-vars;
|
|
7
|
-
@use "../../../colors/colors.module" as colors;
|
|
8
7
|
|
|
9
8
|
.newspack-card--core,
|
|
10
9
|
.newspack-wizard .newspack-card--core {
|
|
@@ -45,7 +44,13 @@
|
|
|
45
44
|
}
|
|
46
45
|
.newspack-card--core {
|
|
47
46
|
&__header-content {
|
|
48
|
-
|
|
47
|
+
h1,
|
|
48
|
+
h2,
|
|
49
|
+
h3,
|
|
50
|
+
h4,
|
|
51
|
+
h5,
|
|
52
|
+
h6,
|
|
53
|
+
p {
|
|
49
54
|
line-height: wp-vars.$font-line-height-small;
|
|
50
55
|
}
|
|
51
56
|
}
|
|
@@ -210,9 +215,6 @@
|
|
|
210
215
|
text-decoration: underline;
|
|
211
216
|
}
|
|
212
217
|
}
|
|
213
|
-
.newspack-badge {
|
|
214
|
-
font-weight: 400;
|
|
215
|
-
}
|
|
216
218
|
}
|
|
217
219
|
}
|
|
218
220
|
&__is-selectable {
|