newspack-components 4.8.0 → 4.9.0-alpha.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.
- package/CHANGELOG.md +10 -0
- package/DEVELOPMENT.md +18 -17
- package/dist/cjs/action-card/index.js +85 -18
- package/dist/cjs/action-card/index.test.js +192 -5
- package/dist/cjs/action-card/style.scss +3 -9
- package/dist/cjs/card-feature/index.js +28 -3
- package/dist/cjs/card-feature/index.test.js +100 -45
- package/dist/cjs/card-feature/style.scss +1 -5
- package/dist/cjs/debug-badge/index.js +44 -0
- package/dist/cjs/debug-badge/index.test.js +50 -0
- package/dist/cjs/debug-badge/style.scss +26 -0
- package/dist/cjs/empty-state/index.test.js +37 -24
- package/dist/cjs/empty-state/root.js +2 -1
- package/dist/cjs/footer/index.js +52 -16
- package/dist/cjs/footer/index.test.js +208 -0
- package/dist/cjs/footer/style.scss +17 -1
- package/dist/cjs/index.js +7 -0
- package/dist/cjs/integration-icon/index.js +4 -4
- package/dist/cjs/integration-icon/style.scss +18 -2
- package/dist/cjs/integration-icons/active-campaign.js +4 -7
- package/dist/cjs/integration-icons/beehiiv.js +19 -0
- package/dist/cjs/integration-icons/gravity-forms.js +19 -0
- package/dist/cjs/integration-icons/index.js +26 -6
- package/dist/cjs/integration-icons/salesforce.js +5 -3
- package/dist/cjs/notice/index.js +1 -4
- package/dist/cjs/notice/style.scss +0 -19
- package/dist/cjs/plugin-toggle/index.js +1 -1
- package/dist/cjs/with-wizard-screen/index.js +1 -3
- package/dist/cjs/with-wizard-screen/index.test.js +0 -3
- package/dist/cjs/wizard/breadcrumbs-select.js +17 -4
- package/dist/cjs/wizard/breadcrumbs-select.test.js +17 -0
- package/dist/cjs/wizard/index.js +50 -13
- package/dist/cjs/wizard/index.test.js +304 -5
- package/dist/cjs/wizard/store/index.js +2 -0
- package/dist/esm/action-card/index.js +86 -21
- package/dist/esm/action-card/index.test.js +192 -1
- package/dist/esm/action-card/style.scss +3 -9
- package/dist/esm/card-feature/index.js +29 -4
- package/dist/esm/card-feature/index.test.js +100 -45
- package/dist/esm/card-feature/style.scss +1 -5
- package/dist/esm/debug-badge/index.js +39 -0
- package/dist/esm/debug-badge/index.test.js +46 -0
- package/dist/esm/debug-badge/style.scss +26 -0
- package/dist/esm/empty-state/index.test.js +37 -24
- package/dist/esm/empty-state/root.js +2 -1
- package/dist/esm/footer/index.js +52 -17
- package/dist/esm/footer/index.test.js +210 -0
- package/dist/esm/footer/style.scss +17 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/integration-icon/index.js +5 -5
- package/dist/esm/integration-icon/style.scss +18 -2
- package/dist/esm/integration-icons/active-campaign.js +5 -8
- package/dist/esm/integration-icons/beehiiv.js +13 -0
- package/dist/esm/integration-icons/gravity-forms.js +13 -0
- package/dist/esm/integration-icons/index.js +15 -4
- package/dist/esm/integration-icons/salesforce.js +5 -3
- package/dist/esm/notice/index.js +2 -5
- package/dist/esm/notice/style.scss +0 -19
- package/dist/esm/plugin-toggle/index.js +1 -1
- package/dist/esm/with-wizard-screen/index.js +2 -4
- package/dist/esm/with-wizard-screen/index.test.js +0 -3
- package/dist/esm/wizard/breadcrumbs-select.js +16 -3
- package/dist/esm/wizard/breadcrumbs-select.test.js +18 -1
- package/dist/esm/wizard/index.js +53 -16
- package/dist/esm/wizard/index.test.js +304 -5
- package/dist/esm/wizard/store/index.js +2 -0
- package/package.json +1 -1
- package/src/action-card/action-card.d.ts +3 -2
- package/src/action-card/index.js +81 -8
- package/src/action-card/index.test.js +159 -0
- package/src/action-card/style.scss +3 -9
- package/src/card-feature/README.md +10 -11
- package/src/card-feature/index.test.js +45 -15
- package/src/card-feature/index.tsx +43 -24
- package/src/card-feature/style.scss +1 -5
- package/src/debug-badge/index.js +36 -0
- package/src/debug-badge/index.test.js +39 -0
- package/src/debug-badge/style.scss +26 -0
- package/src/empty-state/README.md +11 -10
- package/src/empty-state/index.test.js +10 -0
- package/src/empty-state/root.tsx +2 -1
- package/src/empty-state/types.ts +1 -1
- package/src/footer/index.js +47 -2
- package/src/footer/index.test.js +114 -0
- package/src/footer/style.scss +17 -1
- package/src/index.js +1 -0
- package/src/integration-icon/index.tsx +5 -5
- package/src/integration-icon/style.scss +18 -2
- package/src/integration-icons/active-campaign.js +1 -5
- package/src/integration-icons/beehiiv.js +10 -0
- package/src/integration-icons/gravity-forms.js +10 -0
- package/src/integration-icons/index.js +14 -3
- package/src/integration-icons/salesforce.js +3 -3
- package/src/notice/index.js +2 -17
- package/src/notice/style.scss +0 -19
- package/src/plugin-toggle/index.js +1 -1
- package/src/with-wizard-screen/index.js +2 -2
- package/src/with-wizard-screen/index.test.js +0 -2
- package/src/wizard/breadcrumbs-select.js +12 -4
- package/src/wizard/breadcrumbs-select.test.js +15 -1
- package/src/wizard/index.js +45 -14
- package/src/wizard/index.test.js +169 -3
- package/src/wizard/store/index.js +2 -0
|
@@ -13,15 +13,28 @@ import { matchesRoute } from '../route-match';
|
|
|
13
13
|
* @return {Array} Breadcrumb items `{ label, url? }`.
|
|
14
14
|
*/
|
|
15
15
|
export var activeBreadcrumbs = function activeBreadcrumbs() {
|
|
16
|
+
var _activeSection;
|
|
17
|
+
var sections = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
18
|
+
var pathname = arguments.length > 1 ? arguments[1] : undefined;
|
|
19
|
+
return ((_activeSection = activeSection(sections, pathname)) === null || _activeSection === void 0 ? void 0 : _activeSection.breadcrumbs) || [];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Select the section matching the current route, falling back to the first.
|
|
24
|
+
*
|
|
25
|
+
* @param {Array} sections Wizard sections.
|
|
26
|
+
* @param {string} pathname Current router pathname.
|
|
27
|
+
* @return {Object|undefined} The active section, if any.
|
|
28
|
+
*/
|
|
29
|
+
export var activeSection = function activeSection() {
|
|
16
30
|
var sections = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
17
31
|
var pathname = arguments.length > 1 ? arguments[1] : undefined;
|
|
18
32
|
if (!(sections !== null && sections !== void 0 && sections.length)) {
|
|
19
|
-
return
|
|
33
|
+
return undefined;
|
|
20
34
|
}
|
|
21
|
-
|
|
35
|
+
return sections.find(function (section) {
|
|
22
36
|
return matchesRoute(section, pathname);
|
|
23
37
|
}) || sections[0];
|
|
24
|
-
return match.breadcrumbs || [];
|
|
25
38
|
};
|
|
26
39
|
|
|
27
40
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Internal dependencies.
|
|
3
3
|
*/
|
|
4
|
-
import { activeBreadcrumbs, appendSectionName } from './breadcrumbs-select';
|
|
4
|
+
import { activeBreadcrumbs, activeSection, appendSectionName } from './breadcrumbs-select';
|
|
5
5
|
var SECTIONS = [{
|
|
6
6
|
path: '/',
|
|
7
7
|
breadcrumbs: [{
|
|
@@ -194,4 +194,21 @@ describe('appendSectionName', function () {
|
|
|
194
194
|
label: 'Access Control'
|
|
195
195
|
}]);
|
|
196
196
|
});
|
|
197
|
+
});
|
|
198
|
+
describe('activeSection', function () {
|
|
199
|
+
var sections = [{
|
|
200
|
+
path: '/settings',
|
|
201
|
+
exact: true,
|
|
202
|
+
subHeaderText: 'Intro'
|
|
203
|
+
}, {
|
|
204
|
+
path: '/settings/:integrationId'
|
|
205
|
+
}];
|
|
206
|
+
it('returns the section matching the route', function () {
|
|
207
|
+
expect(activeSection(sections, '/settings/esp')).toBe(sections[1]);
|
|
208
|
+
expect(activeSection(sections, '/settings').subHeaderText).toBe('Intro');
|
|
209
|
+
});
|
|
210
|
+
it('falls back to the first section, or nothing without sections', function () {
|
|
211
|
+
expect(activeSection(sections, '/unknown')).toBe(sections[0]);
|
|
212
|
+
expect(activeSection([], '/settings')).toBeUndefined();
|
|
213
|
+
});
|
|
197
214
|
});
|
package/dist/esm/wizard/index.js
CHANGED
|
@@ -2,6 +2,9 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
|
2
2
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
3
3
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
4
4
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
5
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
|
|
6
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
7
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
5
8
|
/**
|
|
6
9
|
* External dependencies.
|
|
7
10
|
*/
|
|
@@ -10,20 +13,19 @@ import classnames from 'classnames';
|
|
|
10
13
|
/**
|
|
11
14
|
* WordPress dependencies.
|
|
12
15
|
*/
|
|
13
|
-
|
|
14
|
-
import { DropdownMenu, MenuGroup, MenuItem, Notice as CoreNotice, SlotFillProvider, createSlotFill,
|
|
16
|
+
import { DropdownMenu, MenuGroup, MenuItem, Notice, SlotFillProvider, createSlotFill,
|
|
15
17
|
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
|
|
16
18
|
__experimentalVStack as VStack } from '@wordpress/components';
|
|
17
19
|
import { useDispatch, useSelect } from '@wordpress/data';
|
|
18
|
-
import { cloneElement, createInterpolateElement, isValidElement,
|
|
20
|
+
import { cloneElement, createInterpolateElement, isValidElement, useLayoutEffect, useRef, useState, forwardRef } from '@wordpress/element';
|
|
19
21
|
import { __ } from '@wordpress/i18n';
|
|
20
22
|
import { category, chevronLeft, moreVertical } from '@wordpress/icons';
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* Internal dependencies
|
|
24
26
|
*/
|
|
25
|
-
import { Footer,
|
|
26
|
-
import { activeBreadcrumbs, appendSectionName } from './breadcrumbs-select';
|
|
27
|
+
import { Footer, DebugBadge, Button, TabbedNavigation, PluginInstaller, SectionHeader, HandoffMessage, Page, Waiting } from '../';
|
|
28
|
+
import { activeBreadcrumbs, activeSection, appendSectionName } from './breadcrumbs-select';
|
|
27
29
|
import Router from '../proxied-imports/router';
|
|
28
30
|
import registerStore, { WIZARD_STORE_NAMESPACE } from './store';
|
|
29
31
|
import WizardSnackbar from './components/WizardSnackbar';
|
|
@@ -60,6 +62,7 @@ var HashRouter = Router.HashRouter,
|
|
|
60
62
|
Redirect = Router.Redirect,
|
|
61
63
|
Route = Router.Route,
|
|
62
64
|
Switch = Router.Switch,
|
|
65
|
+
matchPath = Router.matchPath,
|
|
63
66
|
useLocation = Router.useLocation;
|
|
64
67
|
|
|
65
68
|
/**
|
|
@@ -97,7 +100,10 @@ var ResetHeaderData = function ResetHeaderData() {
|
|
|
97
100
|
var location = useLocation();
|
|
98
101
|
var _useDispatch = useDispatch(WIZARD_STORE_NAMESPACE),
|
|
99
102
|
resetHeaderData = _useDispatch.resetHeaderData;
|
|
100
|
-
|
|
103
|
+
|
|
104
|
+
// Must stay before paint: a passive effect here would run after a section that
|
|
105
|
+
// publishes from a layout effect, wiping the header it just set.
|
|
106
|
+
useLayoutEffect(function () {
|
|
101
107
|
resetHeaderData();
|
|
102
108
|
window.scrollTo(0, 0);
|
|
103
109
|
}, [location.pathname, resetHeaderData]);
|
|
@@ -109,16 +115,46 @@ var ResetHeaderData = function ResetHeaderData() {
|
|
|
109
115
|
* can read the current route and derive the active-tab breadcrumb.
|
|
110
116
|
*/
|
|
111
117
|
var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
|
|
118
|
+
var _activeSection;
|
|
112
119
|
var hideHeader = _ref.hideHeader,
|
|
113
120
|
headerText = _ref.headerText,
|
|
114
121
|
sections = _ref.sections,
|
|
115
122
|
sectionName = _ref.sectionName,
|
|
116
123
|
subTitle = _ref.subTitle,
|
|
117
124
|
actions = _ref.actions,
|
|
118
|
-
|
|
125
|
+
wizardTabbedNavigation = _ref.tabbedNavigation,
|
|
119
126
|
children = _ref.children;
|
|
120
127
|
var _useLocation = useLocation(),
|
|
121
128
|
pathname = _useLocation.pathname;
|
|
129
|
+
|
|
130
|
+
// A section can carry its own tabs, built from its route params, in place of
|
|
131
|
+
// the wizard's. The first match wins, as it does in the wizard's `<Switch>`.
|
|
132
|
+
var tabbedNavigation = wizardTabbedNavigation;
|
|
133
|
+
var _iterator = _createForOfIteratorHelper(sections),
|
|
134
|
+
_step;
|
|
135
|
+
try {
|
|
136
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
137
|
+
var _section$exact;
|
|
138
|
+
var section = _step.value;
|
|
139
|
+
var match = matchPath(pathname, {
|
|
140
|
+
path: section.path,
|
|
141
|
+
exact: (_section$exact = section.exact) !== null && _section$exact !== void 0 ? _section$exact : false
|
|
142
|
+
});
|
|
143
|
+
if (match) {
|
|
144
|
+
if (typeof section.tabbedNavigation === 'function') {
|
|
145
|
+
tabbedNavigation = /*#__PURE__*/_jsx(TabbedNavigation, {
|
|
146
|
+
items: section.tabbedNavigation(match.params),
|
|
147
|
+
children: /*#__PURE__*/_jsx(WizardError, {})
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
} catch (err) {
|
|
154
|
+
_iterator.e(err);
|
|
155
|
+
} finally {
|
|
156
|
+
_iterator.f();
|
|
157
|
+
}
|
|
122
158
|
if (hideHeader) {
|
|
123
159
|
// Without the Page shell the tabs still own the content: it renders
|
|
124
160
|
// inside the active tab's panel.
|
|
@@ -138,9 +174,10 @@ var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
|
|
|
138
174
|
// Append any render-time leaf crumb(s) the section supplied via
|
|
139
175
|
// headerData.sectionName (deduped against the current trailing label).
|
|
140
176
|
breadcrumbItems = appendSectionName(breadcrumbItems, sectionName);
|
|
177
|
+
var sectionSubTitle = (_activeSection = activeSection(sections, pathname)) === null || _activeSection === void 0 ? void 0 : _activeSection.subHeaderText;
|
|
141
178
|
return /*#__PURE__*/_jsx(Page, {
|
|
142
179
|
breadcrumbItems: breadcrumbItems,
|
|
143
|
-
subTitle: subTitle,
|
|
180
|
+
subTitle: sectionSubTitle !== null && sectionSubTitle !== void 0 ? sectionSubTitle : subTitle,
|
|
144
181
|
actions: actions,
|
|
145
182
|
tabbedNavigation: tabbedNavigation,
|
|
146
183
|
children: children
|
|
@@ -153,7 +190,8 @@ var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
|
|
|
153
190
|
* @property {string} [subHeaderText] The sub-header text, optional.
|
|
154
191
|
* @property {string} [apiSlug] The API slug, optional.
|
|
155
192
|
* @property {string} [className] CSS classes, optional.
|
|
156
|
-
* @property {any[]} sections Array of sections.
|
|
193
|
+
* @property {any[]} sections Array of sections. A section's own `subHeaderText` replaces the wizard's while it is active.
|
|
194
|
+
* Its optional `tabbedNavigation( params )` returns the tab items shown while its route matches.
|
|
157
195
|
* @property {boolean} [hasSimpleFooter] Indicates if a simple footer is used, optional.
|
|
158
196
|
* @property {() => void} [renderAboveSections] Function to render content above sections, optional.
|
|
159
197
|
* @property {string[]} [requiredPlugins] Array of required plugin strings, optional.
|
|
@@ -203,6 +241,7 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
203
241
|
var actions = headerData.actions,
|
|
204
242
|
backNav = headerData.backNav,
|
|
205
243
|
badges = headerData.badges,
|
|
244
|
+
headerFullWidth = headerData.fullWidth,
|
|
206
245
|
sectionDescription = headerData.sectionDescription,
|
|
207
246
|
sectionMenu = headerData.sectionMenu,
|
|
208
247
|
sectionName = headerData.sectionName,
|
|
@@ -307,7 +346,7 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
307
346
|
// describes the state of the whole site, not of the section below it, so it reads
|
|
308
347
|
// as page chrome rather than as content.
|
|
309
348
|
var inertGating = (_window$newspack_aux_ = window.newspack_aux_data) === null || _window$newspack_aux_ === void 0 ? void 0 : _window$newspack_aux_.inert_gating;
|
|
310
|
-
var inertGatingNotice = (inertGating === null || inertGating === void 0 ? void 0 : inertGating.show) && /*#__PURE__*/_jsx(
|
|
349
|
+
var inertGatingNotice = (inertGating === null || inertGating === void 0 ? void 0 : inertGating.show) && /*#__PURE__*/_jsx(Notice, {
|
|
311
350
|
status: "warning",
|
|
312
351
|
isDismissible: false,
|
|
313
352
|
className: "newspack-wizard__inert-gating-notice",
|
|
@@ -330,16 +369,16 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
330
369
|
bubblesVirtually: true
|
|
331
370
|
}), /*#__PURE__*/_jsxs(Switch, {
|
|
332
371
|
children: [routedSections.map(function (section, index) {
|
|
333
|
-
var _section$
|
|
372
|
+
var _section$exact2;
|
|
334
373
|
var SectionComponent = section.render;
|
|
335
374
|
var sectionProps = section.props || {};
|
|
336
375
|
return /*#__PURE__*/_jsx(Route, {
|
|
337
|
-
exact: (_section$
|
|
376
|
+
exact: (_section$exact2 = section.exact) !== null && _section$exact2 !== void 0 ? _section$exact2 : false,
|
|
338
377
|
path: section.path,
|
|
339
378
|
render: function render(routerProps) {
|
|
340
379
|
return /*#__PURE__*/_jsxs("div", {
|
|
341
380
|
className: classnames('newspack-wizard__content', className, {
|
|
342
|
-
'newspack-wizard__content--full-width': section.fullWidth
|
|
381
|
+
'newspack-wizard__content--full-width': headerFullWidth !== null && headerFullWidth !== void 0 ? headerFullWidth : section.fullWidth
|
|
343
382
|
}),
|
|
344
383
|
children: ['function' === typeof renderAboveSections ? renderAboveSections() : null, (sectionTitle || section.title) && /*#__PURE__*/_jsx(SectionHeader, {
|
|
345
384
|
className: "newspack-wizard__section-header",
|
|
@@ -420,9 +459,7 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
420
459
|
}),
|
|
421
460
|
children: [/*#__PURE__*/_jsxs(HashRouter, {
|
|
422
461
|
hashType: "slash",
|
|
423
|
-
children: [
|
|
424
|
-
debugMode: true
|
|
425
|
-
}), /*#__PURE__*/_jsx(WizardHeaderRegion, {
|
|
462
|
+
children: [/*#__PURE__*/_jsx(DebugBadge, {}), /*#__PURE__*/_jsx(WizardHeaderRegion, {
|
|
426
463
|
hideHeader: hideHeader,
|
|
427
464
|
headerText: headerText,
|
|
428
465
|
sections: routedSections,
|
|
@@ -11,25 +11,26 @@ import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
|
|
|
11
11
|
* WordPress dependencies.
|
|
12
12
|
*/
|
|
13
13
|
import apiFetch from '@wordpress/api-fetch';
|
|
14
|
+
import { select, useDispatch } from '@wordpress/data';
|
|
15
|
+
import { useLayoutEffect, useState } from '@wordpress/element';
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Internal dependencies.
|
|
17
19
|
*/
|
|
18
20
|
import Wizard from './';
|
|
19
21
|
import { useWizardData } from './store/utils';
|
|
22
|
+
import { WIZARD_STORE_NAMESPACE } from './store';
|
|
20
23
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
21
24
|
jest.mock('@wordpress/api-fetch', function () {
|
|
22
25
|
return jest.fn();
|
|
23
26
|
});
|
|
24
27
|
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
window.newspack_aux_data = {
|
|
28
|
-
is_debug_mode: false
|
|
29
|
-
};
|
|
28
|
+
// Localized onto every real wizard screen; the footer's ExternalLink needs a
|
|
29
|
+
// string href.
|
|
30
30
|
window.newspack_urls = {
|
|
31
31
|
support: 'https://help.newspack.com/'
|
|
32
32
|
};
|
|
33
|
+
window.scrollTo = jest.fn();
|
|
33
34
|
var SETTINGS = {
|
|
34
35
|
minimumDonation: '5'
|
|
35
36
|
};
|
|
@@ -251,4 +252,302 @@ describe('Wizard', function () {
|
|
|
251
252
|
}
|
|
252
253
|
}, _callee4);
|
|
253
254
|
})));
|
|
255
|
+
});
|
|
256
|
+
var NarrowingSection = function NarrowingSection() {
|
|
257
|
+
var _useDispatch = useDispatch(WIZARD_STORE_NAMESPACE),
|
|
258
|
+
setHeaderData = _useDispatch.setHeaderData;
|
|
259
|
+
useLayoutEffect(function () {
|
|
260
|
+
setHeaderData({
|
|
261
|
+
fullWidth: false
|
|
262
|
+
});
|
|
263
|
+
}, [setHeaderData]);
|
|
264
|
+
return /*#__PURE__*/_jsx("div", {
|
|
265
|
+
children: "Narrowing section"
|
|
266
|
+
});
|
|
267
|
+
};
|
|
268
|
+
var RecoveringSection = function RecoveringSection() {
|
|
269
|
+
var _useDispatch2 = useDispatch(WIZARD_STORE_NAMESPACE),
|
|
270
|
+
setHeaderData = _useDispatch2.setHeaderData;
|
|
271
|
+
var _useState = useState(true),
|
|
272
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
273
|
+
failed = _useState2[0],
|
|
274
|
+
setFailed = _useState2[1];
|
|
275
|
+
useLayoutEffect(function () {
|
|
276
|
+
setHeaderData({
|
|
277
|
+
fullWidth: failed ? false : undefined
|
|
278
|
+
});
|
|
279
|
+
}, [setHeaderData, failed]);
|
|
280
|
+
return /*#__PURE__*/_jsx("button", {
|
|
281
|
+
onClick: function onClick() {
|
|
282
|
+
return setFailed(false);
|
|
283
|
+
},
|
|
284
|
+
children: "Retry"
|
|
285
|
+
});
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// Two sections, because that is what mounts ResetHeaderData: a single-section
|
|
289
|
+
// wizard never exercises the reset these overrides have to survive.
|
|
290
|
+
var widthSections = function widthSections(renderSection) {
|
|
291
|
+
return [{
|
|
292
|
+
label: 'List',
|
|
293
|
+
path: '/',
|
|
294
|
+
exact: true,
|
|
295
|
+
fullWidth: true,
|
|
296
|
+
render: renderSection
|
|
297
|
+
}, {
|
|
298
|
+
label: 'Other',
|
|
299
|
+
path: '/other',
|
|
300
|
+
render: function render() {
|
|
301
|
+
return /*#__PURE__*/_jsx("div", {
|
|
302
|
+
children: "Other section"
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}];
|
|
306
|
+
};
|
|
307
|
+
describe('Wizard content width', function () {
|
|
308
|
+
beforeEach(function () {
|
|
309
|
+
apiFetch.mockReset();
|
|
310
|
+
});
|
|
311
|
+
it('renders full-width when the section declares it and nothing overrides it', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() {
|
|
312
|
+
var _render, container, _t5;
|
|
313
|
+
return _regenerator().w(function (_context5) {
|
|
314
|
+
while (1) switch (_context5.n) {
|
|
315
|
+
case 0:
|
|
316
|
+
_render = render(/*#__PURE__*/_jsx(Wizard, {
|
|
317
|
+
headerText: "Test wizard",
|
|
318
|
+
sections: widthSections(function () {
|
|
319
|
+
return /*#__PURE__*/_jsx("div", {
|
|
320
|
+
children: "List content"
|
|
321
|
+
});
|
|
322
|
+
})
|
|
323
|
+
})), container = _render.container;
|
|
324
|
+
_t5 = expect;
|
|
325
|
+
_context5.n = 1;
|
|
326
|
+
return screen.findByText('List content');
|
|
327
|
+
case 1:
|
|
328
|
+
_t5(_context5.v).toBeInTheDocument();
|
|
329
|
+
expect(container.querySelector('.newspack-wizard__content')).toHaveClass('newspack-wizard__content--full-width');
|
|
330
|
+
case 2:
|
|
331
|
+
return _context5.a(2);
|
|
332
|
+
}
|
|
333
|
+
}, _callee5);
|
|
334
|
+
})));
|
|
335
|
+
it('falls back to the standard width when a section overrides fullWidth before paint', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
|
|
336
|
+
var _render2, container, _t6;
|
|
337
|
+
return _regenerator().w(function (_context6) {
|
|
338
|
+
while (1) switch (_context6.n) {
|
|
339
|
+
case 0:
|
|
340
|
+
_render2 = render(/*#__PURE__*/_jsx(Wizard, {
|
|
341
|
+
headerText: "Test wizard",
|
|
342
|
+
sections: widthSections(function () {
|
|
343
|
+
return /*#__PURE__*/_jsx(NarrowingSection, {});
|
|
344
|
+
})
|
|
345
|
+
})), container = _render2.container;
|
|
346
|
+
_t6 = expect;
|
|
347
|
+
_context6.n = 1;
|
|
348
|
+
return screen.findByText('Narrowing section');
|
|
349
|
+
case 1:
|
|
350
|
+
_t6(_context6.v).toBeInTheDocument();
|
|
351
|
+
expect(container.querySelector('.newspack-wizard__content')).not.toHaveClass('newspack-wizard__content--full-width');
|
|
352
|
+
case 2:
|
|
353
|
+
return _context6.a(2);
|
|
354
|
+
}
|
|
355
|
+
}, _callee6);
|
|
356
|
+
})));
|
|
357
|
+
it('restores the declared width when the section clears its override', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7() {
|
|
358
|
+
var _render3, container, retry;
|
|
359
|
+
return _regenerator().w(function (_context7) {
|
|
360
|
+
while (1) switch (_context7.n) {
|
|
361
|
+
case 0:
|
|
362
|
+
_render3 = render(/*#__PURE__*/_jsx(Wizard, {
|
|
363
|
+
headerText: "Test wizard",
|
|
364
|
+
sections: widthSections(function () {
|
|
365
|
+
return /*#__PURE__*/_jsx(RecoveringSection, {});
|
|
366
|
+
})
|
|
367
|
+
})), container = _render3.container;
|
|
368
|
+
_context7.n = 1;
|
|
369
|
+
return screen.findByRole('button', {
|
|
370
|
+
name: 'Retry'
|
|
371
|
+
});
|
|
372
|
+
case 1:
|
|
373
|
+
retry = _context7.v;
|
|
374
|
+
expect(container.querySelector('.newspack-wizard__content')).not.toHaveClass('newspack-wizard__content--full-width');
|
|
375
|
+
fireEvent.click(retry);
|
|
376
|
+
_context7.n = 2;
|
|
377
|
+
return waitFor(function () {
|
|
378
|
+
return expect(container.querySelector('.newspack-wizard__content')).toHaveClass('newspack-wizard__content--full-width');
|
|
379
|
+
});
|
|
380
|
+
case 2:
|
|
381
|
+
return _context7.a(2);
|
|
382
|
+
}
|
|
383
|
+
}, _callee7);
|
|
384
|
+
})));
|
|
385
|
+
it('keeps a section header published from a layout effect through the mount reset', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8() {
|
|
386
|
+
var _t7;
|
|
387
|
+
return _regenerator().w(function (_context8) {
|
|
388
|
+
while (1) switch (_context8.n) {
|
|
389
|
+
case 0:
|
|
390
|
+
render(/*#__PURE__*/_jsx(Wizard, {
|
|
391
|
+
headerText: "Test wizard",
|
|
392
|
+
sections: widthSections(function () {
|
|
393
|
+
return /*#__PURE__*/_jsx(NarrowingSection, {});
|
|
394
|
+
})
|
|
395
|
+
}));
|
|
396
|
+
_t7 = expect;
|
|
397
|
+
_context8.n = 1;
|
|
398
|
+
return screen.findByText('Narrowing section');
|
|
399
|
+
case 1:
|
|
400
|
+
_t7(_context8.v).toBeInTheDocument();
|
|
401
|
+
expect(select(WIZARD_STORE_NAMESPACE).getHeaderData().fullWidth).toBe(false);
|
|
402
|
+
case 2:
|
|
403
|
+
return _context8.a(2);
|
|
404
|
+
}
|
|
405
|
+
}, _callee8);
|
|
406
|
+
})));
|
|
407
|
+
});
|
|
408
|
+
describe('Wizard section tabs', function () {
|
|
409
|
+
var sections = [{
|
|
410
|
+
label: 'List',
|
|
411
|
+
path: '/',
|
|
412
|
+
exact: true,
|
|
413
|
+
render: function render() {
|
|
414
|
+
return /*#__PURE__*/_jsx("div", {
|
|
415
|
+
children: "List content"
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}, {
|
|
419
|
+
path: '/items/:itemId/logs/:tab?',
|
|
420
|
+
isHidden: true,
|
|
421
|
+
render: function render() {
|
|
422
|
+
return /*#__PURE__*/_jsx("div", {
|
|
423
|
+
children: "Logs content"
|
|
424
|
+
});
|
|
425
|
+
},
|
|
426
|
+
tabbedNavigation: function tabbedNavigation(_ref10) {
|
|
427
|
+
var itemId = _ref10.itemId;
|
|
428
|
+
return [{
|
|
429
|
+
label: 'First Tab',
|
|
430
|
+
path: "/items/".concat(itemId, "/logs"),
|
|
431
|
+
exact: true
|
|
432
|
+
}, {
|
|
433
|
+
label: 'Second Tab',
|
|
434
|
+
path: "/items/".concat(itemId, "/logs/second"),
|
|
435
|
+
exact: true
|
|
436
|
+
}];
|
|
437
|
+
}
|
|
438
|
+
}];
|
|
439
|
+
beforeEach(function () {
|
|
440
|
+
apiFetch.mockReset();
|
|
441
|
+
});
|
|
442
|
+
afterEach(function () {
|
|
443
|
+
window.location.hash = '';
|
|
444
|
+
});
|
|
445
|
+
it('shows the tabs a section builds from its route params while it matches', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9() {
|
|
446
|
+
var _t8;
|
|
447
|
+
return _regenerator().w(function (_context9) {
|
|
448
|
+
while (1) switch (_context9.n) {
|
|
449
|
+
case 0:
|
|
450
|
+
window.location.hash = '#/items/42/logs/second';
|
|
451
|
+
render(/*#__PURE__*/_jsx(Wizard, {
|
|
452
|
+
headerText: "Test wizard",
|
|
453
|
+
sections: sections
|
|
454
|
+
}));
|
|
455
|
+
_t8 = expect;
|
|
456
|
+
_context9.n = 1;
|
|
457
|
+
return screen.findByText('Logs content');
|
|
458
|
+
case 1:
|
|
459
|
+
_t8(_context9.v).toBeInTheDocument();
|
|
460
|
+
expect(screen.getByRole('tab', {
|
|
461
|
+
name: 'First Tab'
|
|
462
|
+
})).toHaveAttribute('href', '#/items/42/logs');
|
|
463
|
+
expect(screen.getByRole('tab', {
|
|
464
|
+
name: 'Second Tab'
|
|
465
|
+
})).toHaveAttribute('aria-selected', 'true');
|
|
466
|
+
case 2:
|
|
467
|
+
return _context9.a(2);
|
|
468
|
+
}
|
|
469
|
+
}, _callee9);
|
|
470
|
+
})));
|
|
471
|
+
it('leaves the tabs out on a route the section does not match', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0() {
|
|
472
|
+
var _t9;
|
|
473
|
+
return _regenerator().w(function (_context0) {
|
|
474
|
+
while (1) switch (_context0.n) {
|
|
475
|
+
case 0:
|
|
476
|
+
window.location.hash = '#/';
|
|
477
|
+
render(/*#__PURE__*/_jsx(Wizard, {
|
|
478
|
+
headerText: "Test wizard",
|
|
479
|
+
sections: sections
|
|
480
|
+
}));
|
|
481
|
+
_t9 = expect;
|
|
482
|
+
_context0.n = 1;
|
|
483
|
+
return screen.findByText('List content');
|
|
484
|
+
case 1:
|
|
485
|
+
_t9(_context0.v).toBeInTheDocument();
|
|
486
|
+
expect(screen.queryByRole('tab')).toBeNull();
|
|
487
|
+
case 2:
|
|
488
|
+
return _context0.a(2);
|
|
489
|
+
}
|
|
490
|
+
}, _callee0);
|
|
491
|
+
})));
|
|
492
|
+
});
|
|
493
|
+
describe('Wizard section subtitle', function () {
|
|
494
|
+
beforeEach(function () {
|
|
495
|
+
apiFetch.mockReset();
|
|
496
|
+
apiFetch.mockResolvedValue({});
|
|
497
|
+
});
|
|
498
|
+
it("shows the active section's subHeaderText in the header, falling back to the wizard's", /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee1() {
|
|
499
|
+
var _render4, container, subtitle, _t0, _t1;
|
|
500
|
+
return _regenerator().w(function (_context1) {
|
|
501
|
+
while (1) switch (_context1.n) {
|
|
502
|
+
case 0:
|
|
503
|
+
window.location.hash = '#/list';
|
|
504
|
+
_render4 = render(/*#__PURE__*/_jsx(Wizard, {
|
|
505
|
+
headerText: "Test wizard",
|
|
506
|
+
subHeaderText: "Wizard intro",
|
|
507
|
+
sections: [{
|
|
508
|
+
label: 'List',
|
|
509
|
+
path: '/list',
|
|
510
|
+
exact: true,
|
|
511
|
+
subHeaderText: 'List intro',
|
|
512
|
+
render: function render() {
|
|
513
|
+
return /*#__PURE__*/_jsx("div", {
|
|
514
|
+
children: "List view"
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
}, {
|
|
518
|
+
label: 'Item',
|
|
519
|
+
path: '/list/:id',
|
|
520
|
+
isHidden: true,
|
|
521
|
+
render: function render() {
|
|
522
|
+
return /*#__PURE__*/_jsx("div", {
|
|
523
|
+
children: "Item view"
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
}]
|
|
527
|
+
})), container = _render4.container;
|
|
528
|
+
subtitle = function subtitle() {
|
|
529
|
+
var _container$querySelec;
|
|
530
|
+
return (_container$querySelec = container.querySelector('.newspack-page__header-subtitle')) === null || _container$querySelec === void 0 ? void 0 : _container$querySelec.textContent;
|
|
531
|
+
};
|
|
532
|
+
_t0 = expect;
|
|
533
|
+
_context1.n = 1;
|
|
534
|
+
return screen.findByText('List view');
|
|
535
|
+
case 1:
|
|
536
|
+
_t0(_context1.v).toBeInTheDocument();
|
|
537
|
+
expect(subtitle()).toBe('List intro');
|
|
538
|
+
act(function () {
|
|
539
|
+
window.location.hash = '#/list/esp';
|
|
540
|
+
window.dispatchEvent(new HashChangeEvent('hashchange'));
|
|
541
|
+
});
|
|
542
|
+
_t1 = expect;
|
|
543
|
+
_context1.n = 2;
|
|
544
|
+
return screen.findByText('Item view');
|
|
545
|
+
case 2:
|
|
546
|
+
_t1(_context1.v).toBeInTheDocument();
|
|
547
|
+
expect(subtitle()).toBe('Wizard intro');
|
|
548
|
+
case 3:
|
|
549
|
+
return _context1.a(2);
|
|
550
|
+
}
|
|
551
|
+
}, _callee1);
|
|
552
|
+
})));
|
|
254
553
|
});
|
|
@@ -19,6 +19,8 @@ import { createReduxStore, register, dispatch, select } from '@wordpress/data';
|
|
|
19
19
|
import { createAction } from './utils.js';
|
|
20
20
|
export var WIZARD_STORE_NAMESPACE = 'newspack/wizards';
|
|
21
21
|
var DEFAULT_STATE = {
|
|
22
|
+
// `fullWidth` is deliberately absent: a default here would narrow every
|
|
23
|
+
// full-width section on reset, since Wizard only falls back when it is unset.
|
|
22
24
|
headerData: {
|
|
23
25
|
actions: [],
|
|
24
26
|
backNav: '',
|
package/package.json
CHANGED
|
@@ -10,8 +10,9 @@ export interface ActionCardProps {
|
|
|
10
10
|
badges?: CardBadge[];
|
|
11
11
|
className?: string;
|
|
12
12
|
indent?: string;
|
|
13
|
-
notification?:
|
|
14
|
-
notificationLevel?: 'error' | 'warning' | 'info';
|
|
13
|
+
notification?: React.ReactNode | Error | null;
|
|
14
|
+
notificationLevel?: 'error' | 'warning' | 'info' | 'success';
|
|
15
|
+
notificationHTML?: boolean;
|
|
15
16
|
isMedium?: boolean;
|
|
16
17
|
disabled?: boolean | string;
|
|
17
18
|
hasGreyHeader?: boolean;
|