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.
Files changed (103) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/DEVELOPMENT.md +18 -17
  3. package/dist/cjs/action-card/index.js +85 -18
  4. package/dist/cjs/action-card/index.test.js +192 -5
  5. package/dist/cjs/action-card/style.scss +3 -9
  6. package/dist/cjs/card-feature/index.js +28 -3
  7. package/dist/cjs/card-feature/index.test.js +100 -45
  8. package/dist/cjs/card-feature/style.scss +1 -5
  9. package/dist/cjs/debug-badge/index.js +44 -0
  10. package/dist/cjs/debug-badge/index.test.js +50 -0
  11. package/dist/cjs/debug-badge/style.scss +26 -0
  12. package/dist/cjs/empty-state/index.test.js +37 -24
  13. package/dist/cjs/empty-state/root.js +2 -1
  14. package/dist/cjs/footer/index.js +52 -16
  15. package/dist/cjs/footer/index.test.js +208 -0
  16. package/dist/cjs/footer/style.scss +17 -1
  17. package/dist/cjs/index.js +7 -0
  18. package/dist/cjs/integration-icon/index.js +4 -4
  19. package/dist/cjs/integration-icon/style.scss +18 -2
  20. package/dist/cjs/integration-icons/active-campaign.js +4 -7
  21. package/dist/cjs/integration-icons/beehiiv.js +19 -0
  22. package/dist/cjs/integration-icons/gravity-forms.js +19 -0
  23. package/dist/cjs/integration-icons/index.js +26 -6
  24. package/dist/cjs/integration-icons/salesforce.js +5 -3
  25. package/dist/cjs/notice/index.js +1 -4
  26. package/dist/cjs/notice/style.scss +0 -19
  27. package/dist/cjs/plugin-toggle/index.js +1 -1
  28. package/dist/cjs/with-wizard-screen/index.js +1 -3
  29. package/dist/cjs/with-wizard-screen/index.test.js +0 -3
  30. package/dist/cjs/wizard/breadcrumbs-select.js +17 -4
  31. package/dist/cjs/wizard/breadcrumbs-select.test.js +17 -0
  32. package/dist/cjs/wizard/index.js +50 -13
  33. package/dist/cjs/wizard/index.test.js +304 -5
  34. package/dist/cjs/wizard/store/index.js +2 -0
  35. package/dist/esm/action-card/index.js +86 -21
  36. package/dist/esm/action-card/index.test.js +192 -1
  37. package/dist/esm/action-card/style.scss +3 -9
  38. package/dist/esm/card-feature/index.js +29 -4
  39. package/dist/esm/card-feature/index.test.js +100 -45
  40. package/dist/esm/card-feature/style.scss +1 -5
  41. package/dist/esm/debug-badge/index.js +39 -0
  42. package/dist/esm/debug-badge/index.test.js +46 -0
  43. package/dist/esm/debug-badge/style.scss +26 -0
  44. package/dist/esm/empty-state/index.test.js +37 -24
  45. package/dist/esm/empty-state/root.js +2 -1
  46. package/dist/esm/footer/index.js +52 -17
  47. package/dist/esm/footer/index.test.js +210 -0
  48. package/dist/esm/footer/style.scss +17 -1
  49. package/dist/esm/index.js +1 -0
  50. package/dist/esm/integration-icon/index.js +5 -5
  51. package/dist/esm/integration-icon/style.scss +18 -2
  52. package/dist/esm/integration-icons/active-campaign.js +5 -8
  53. package/dist/esm/integration-icons/beehiiv.js +13 -0
  54. package/dist/esm/integration-icons/gravity-forms.js +13 -0
  55. package/dist/esm/integration-icons/index.js +15 -4
  56. package/dist/esm/integration-icons/salesforce.js +5 -3
  57. package/dist/esm/notice/index.js +2 -5
  58. package/dist/esm/notice/style.scss +0 -19
  59. package/dist/esm/plugin-toggle/index.js +1 -1
  60. package/dist/esm/with-wizard-screen/index.js +2 -4
  61. package/dist/esm/with-wizard-screen/index.test.js +0 -3
  62. package/dist/esm/wizard/breadcrumbs-select.js +16 -3
  63. package/dist/esm/wizard/breadcrumbs-select.test.js +18 -1
  64. package/dist/esm/wizard/index.js +53 -16
  65. package/dist/esm/wizard/index.test.js +304 -5
  66. package/dist/esm/wizard/store/index.js +2 -0
  67. package/package.json +1 -1
  68. package/src/action-card/action-card.d.ts +3 -2
  69. package/src/action-card/index.js +81 -8
  70. package/src/action-card/index.test.js +159 -0
  71. package/src/action-card/style.scss +3 -9
  72. package/src/card-feature/README.md +10 -11
  73. package/src/card-feature/index.test.js +45 -15
  74. package/src/card-feature/index.tsx +43 -24
  75. package/src/card-feature/style.scss +1 -5
  76. package/src/debug-badge/index.js +36 -0
  77. package/src/debug-badge/index.test.js +39 -0
  78. package/src/debug-badge/style.scss +26 -0
  79. package/src/empty-state/README.md +11 -10
  80. package/src/empty-state/index.test.js +10 -0
  81. package/src/empty-state/root.tsx +2 -1
  82. package/src/empty-state/types.ts +1 -1
  83. package/src/footer/index.js +47 -2
  84. package/src/footer/index.test.js +114 -0
  85. package/src/footer/style.scss +17 -1
  86. package/src/index.js +1 -0
  87. package/src/integration-icon/index.tsx +5 -5
  88. package/src/integration-icon/style.scss +18 -2
  89. package/src/integration-icons/active-campaign.js +1 -5
  90. package/src/integration-icons/beehiiv.js +10 -0
  91. package/src/integration-icons/gravity-forms.js +10 -0
  92. package/src/integration-icons/index.js +14 -3
  93. package/src/integration-icons/salesforce.js +3 -3
  94. package/src/notice/index.js +2 -17
  95. package/src/notice/style.scss +0 -19
  96. package/src/plugin-toggle/index.js +1 -1
  97. package/src/with-wizard-screen/index.js +2 -2
  98. package/src/with-wizard-screen/index.test.js +0 -2
  99. package/src/wizard/breadcrumbs-select.js +12 -4
  100. package/src/wizard/breadcrumbs-select.test.js +15 -1
  101. package/src/wizard/index.js +45 -14
  102. package/src/wizard/index.test.js +169 -3
  103. package/src/wizard/store/index.js +2 -0
@@ -207,7 +207,7 @@ var PluginToggle = /*#__PURE__*/function (_Component) {
207
207
  return _this2.managePlugin(slug, value);
208
208
  },
209
209
  notification: error,
210
- notificationHTML: error,
210
+ notificationHTML: true,
211
211
  notificationLevel: "error"
212
212
  }, index);
213
213
  });
@@ -115,9 +115,7 @@ function withWizardScreen(WrappedComponent) {
115
115
  }];
116
116
  }
117
117
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
118
- children: [newspack_aux_data.is_debug_mode && /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Notice, {
119
- debugMode: true
120
- }), hideHeader ?
118
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_.DebugBadge, {}), hideHeader ?
121
119
  /*#__PURE__*/
122
120
  // Without the Page shell the tabs still own the content: it
123
121
  // renders inside the active tab's panel.
@@ -13,9 +13,6 @@ var _jsxRuntime = require("react/jsx-runtime");
13
13
  * Internal dependencies.
14
14
  */
15
15
 
16
- global.newspack_aux_data = {
17
- is_debug_mode: false
18
- };
19
16
  describe('withWizardScreen', function () {
20
17
  it('falls back to a single headerText breadcrumb when no breadcrumbItems are provided', function () {
21
18
  var WrappedComponent = function WrappedComponent() {
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.appendSectionName = exports.activeBreadcrumbs = void 0;
7
+ exports.appendSectionName = exports.activeSection = exports.activeBreadcrumbs = void 0;
8
8
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
9
  var _routeMatch = require("../route-match");
10
10
  /**
@@ -20,15 +20,28 @@ var _routeMatch = require("../route-match");
20
20
  * @return {Array} Breadcrumb items `{ label, url? }`.
21
21
  */
22
22
  var activeBreadcrumbs = exports.activeBreadcrumbs = function activeBreadcrumbs() {
23
+ var _activeSection;
24
+ var sections = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
25
+ var pathname = arguments.length > 1 ? arguments[1] : undefined;
26
+ return ((_activeSection = activeSection(sections, pathname)) === null || _activeSection === void 0 ? void 0 : _activeSection.breadcrumbs) || [];
27
+ };
28
+
29
+ /**
30
+ * Select the section matching the current route, falling back to the first.
31
+ *
32
+ * @param {Array} sections Wizard sections.
33
+ * @param {string} pathname Current router pathname.
34
+ * @return {Object|undefined} The active section, if any.
35
+ */
36
+ var activeSection = exports.activeSection = function activeSection() {
23
37
  var sections = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
24
38
  var pathname = arguments.length > 1 ? arguments[1] : undefined;
25
39
  if (!(sections !== null && sections !== void 0 && sections.length)) {
26
- return [];
40
+ return undefined;
27
41
  }
28
- var match = sections.find(function (section) {
42
+ return sections.find(function (section) {
29
43
  return (0, _routeMatch.matchesRoute)(section, pathname);
30
44
  }) || sections[0];
31
- return match.breadcrumbs || [];
32
45
  };
33
46
 
34
47
  /**
@@ -197,4 +197,21 @@ describe('appendSectionName', function () {
197
197
  label: 'Access Control'
198
198
  }]);
199
199
  });
200
+ });
201
+ describe('activeSection', function () {
202
+ var sections = [{
203
+ path: '/settings',
204
+ exact: true,
205
+ subHeaderText: 'Intro'
206
+ }, {
207
+ path: '/settings/:integrationId'
208
+ }];
209
+ it('returns the section matching the route', function () {
210
+ expect((0, _breadcrumbsSelect.activeSection)(sections, '/settings/esp')).toBe(sections[1]);
211
+ expect((0, _breadcrumbsSelect.activeSection)(sections, '/settings').subHeaderText).toBe('Intro');
212
+ });
213
+ it('falls back to the first section, or nothing without sections', function () {
214
+ expect((0, _breadcrumbsSelect.activeSection)(sections, '/unknown')).toBe(sections[0]);
215
+ expect((0, _breadcrumbsSelect.activeSection)([], '/settings')).toBeUndefined();
216
+ });
200
217
  });
@@ -22,12 +22,14 @@ var _WizardError = _interopRequireDefault(require("./components/WizardError"));
22
22
  var _jsxRuntime = require("react/jsx-runtime");
23
23
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
24
24
  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; }
25
- 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) { (0, _defineProperty2["default"])(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; } /**
25
+ 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) { (0, _defineProperty2["default"])(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; }
26
+ 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; } } }; }
27
+ 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; } }
28
+ 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; } /**
26
29
  * External dependencies.
27
30
  */ /**
28
31
  * WordPress dependencies.
29
- */ // Notice is aliased: `Notice` below is Newspack's own, which this file also uses.
30
- /**
32
+ */ /**
31
33
  * Internal dependencies
32
34
  */
33
35
  (0, _store["default"])();
@@ -59,6 +61,7 @@ var HashRouter = _router["default"].HashRouter,
59
61
  Redirect = _router["default"].Redirect,
60
62
  Route = _router["default"].Route,
61
63
  Switch = _router["default"].Switch,
64
+ matchPath = _router["default"].matchPath,
62
65
  useLocation = _router["default"].useLocation;
63
66
 
64
67
  /**
@@ -96,7 +99,10 @@ var ResetHeaderData = function ResetHeaderData() {
96
99
  var location = useLocation();
97
100
  var _useDispatch = (0, _data.useDispatch)(_store.WIZARD_STORE_NAMESPACE),
98
101
  resetHeaderData = _useDispatch.resetHeaderData;
99
- (0, _element.useEffect)(function () {
102
+
103
+ // Must stay before paint: a passive effect here would run after a section that
104
+ // publishes from a layout effect, wiping the header it just set.
105
+ (0, _element.useLayoutEffect)(function () {
100
106
  resetHeaderData();
101
107
  window.scrollTo(0, 0);
102
108
  }, [location.pathname, resetHeaderData]);
@@ -108,16 +114,46 @@ var ResetHeaderData = function ResetHeaderData() {
108
114
  * can read the current route and derive the active-tab breadcrumb.
109
115
  */
110
116
  var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
117
+ var _activeSection;
111
118
  var hideHeader = _ref.hideHeader,
112
119
  headerText = _ref.headerText,
113
120
  sections = _ref.sections,
114
121
  sectionName = _ref.sectionName,
115
122
  subTitle = _ref.subTitle,
116
123
  actions = _ref.actions,
117
- tabbedNavigation = _ref.tabbedNavigation,
124
+ wizardTabbedNavigation = _ref.tabbedNavigation,
118
125
  children = _ref.children;
119
126
  var _useLocation = useLocation(),
120
127
  pathname = _useLocation.pathname;
128
+
129
+ // A section can carry its own tabs, built from its route params, in place of
130
+ // the wizard's. The first match wins, as it does in the wizard's `<Switch>`.
131
+ var tabbedNavigation = wizardTabbedNavigation;
132
+ var _iterator = _createForOfIteratorHelper(sections),
133
+ _step;
134
+ try {
135
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
136
+ var _section$exact;
137
+ var section = _step.value;
138
+ var match = matchPath(pathname, {
139
+ path: section.path,
140
+ exact: (_section$exact = section.exact) !== null && _section$exact !== void 0 ? _section$exact : false
141
+ });
142
+ if (match) {
143
+ if (typeof section.tabbedNavigation === 'function') {
144
+ tabbedNavigation = /*#__PURE__*/(0, _jsxRuntime.jsx)(_.TabbedNavigation, {
145
+ items: section.tabbedNavigation(match.params),
146
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_WizardError["default"], {})
147
+ });
148
+ }
149
+ break;
150
+ }
151
+ }
152
+ } catch (err) {
153
+ _iterator.e(err);
154
+ } finally {
155
+ _iterator.f();
156
+ }
121
157
  if (hideHeader) {
122
158
  // Without the Page shell the tabs still own the content: it renders
123
159
  // inside the active tab's panel.
@@ -137,9 +173,10 @@ var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
137
173
  // Append any render-time leaf crumb(s) the section supplied via
138
174
  // headerData.sectionName (deduped against the current trailing label).
139
175
  breadcrumbItems = (0, _breadcrumbsSelect.appendSectionName)(breadcrumbItems, sectionName);
176
+ var sectionSubTitle = (_activeSection = (0, _breadcrumbsSelect.activeSection)(sections, pathname)) === null || _activeSection === void 0 ? void 0 : _activeSection.subHeaderText;
140
177
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Page, {
141
178
  breadcrumbItems: breadcrumbItems,
142
- subTitle: subTitle,
179
+ subTitle: sectionSubTitle !== null && sectionSubTitle !== void 0 ? sectionSubTitle : subTitle,
143
180
  actions: actions,
144
181
  tabbedNavigation: tabbedNavigation,
145
182
  children: children
@@ -152,7 +189,8 @@ var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
152
189
  * @property {string} [subHeaderText] The sub-header text, optional.
153
190
  * @property {string} [apiSlug] The API slug, optional.
154
191
  * @property {string} [className] CSS classes, optional.
155
- * @property {any[]} sections Array of sections.
192
+ * @property {any[]} sections Array of sections. A section's own `subHeaderText` replaces the wizard's while it is active.
193
+ * Its optional `tabbedNavigation( params )` returns the tab items shown while its route matches.
156
194
  * @property {boolean} [hasSimpleFooter] Indicates if a simple footer is used, optional.
157
195
  * @property {() => void} [renderAboveSections] Function to render content above sections, optional.
158
196
  * @property {string[]} [requiredPlugins] Array of required plugin strings, optional.
@@ -202,6 +240,7 @@ var Wizard = function Wizard(_ref2, ref) {
202
240
  var actions = headerData.actions,
203
241
  backNav = headerData.backNav,
204
242
  badges = headerData.badges,
243
+ headerFullWidth = headerData.fullWidth,
205
244
  sectionDescription = headerData.sectionDescription,
206
245
  sectionMenu = headerData.sectionMenu,
207
246
  sectionName = headerData.sectionName,
@@ -329,16 +368,16 @@ var Wizard = function Wizard(_ref2, ref) {
329
368
  bubblesVirtually: true
330
369
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(Switch, {
331
370
  children: [routedSections.map(function (section, index) {
332
- var _section$exact;
371
+ var _section$exact2;
333
372
  var SectionComponent = section.render;
334
373
  var sectionProps = section.props || {};
335
374
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(Route, {
336
- exact: (_section$exact = section.exact) !== null && _section$exact !== void 0 ? _section$exact : false,
375
+ exact: (_section$exact2 = section.exact) !== null && _section$exact2 !== void 0 ? _section$exact2 : false,
337
376
  path: section.path,
338
377
  render: function render(routerProps) {
339
378
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
340
379
  className: (0, _classnames["default"])('newspack-wizard__content', className, {
341
- 'newspack-wizard__content--full-width': section.fullWidth
380
+ 'newspack-wizard__content--full-width': headerFullWidth !== null && headerFullWidth !== void 0 ? headerFullWidth : section.fullWidth
342
381
  }),
343
382
  children: ['function' === typeof renderAboveSections ? renderAboveSections() : null, (sectionTitle || section.title) && /*#__PURE__*/(0, _jsxRuntime.jsx)(_.SectionHeader, {
344
383
  className: "newspack-wizard__section-header",
@@ -419,9 +458,7 @@ var Wizard = function Wizard(_ref2, ref) {
419
458
  }),
420
459
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(HashRouter, {
421
460
  hashType: "slash",
422
- children: [newspack_aux_data.is_debug_mode && /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Notice, {
423
- debugMode: true
424
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(WizardHeaderRegion, {
461
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_.DebugBadge, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(WizardHeaderRegion, {
425
462
  hideHeader: hideHeader,
426
463
  headerText: headerText,
427
464
  sections: routedSections,
@@ -5,8 +5,11 @@ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/sli
5
5
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
6
6
  var _react = require("@testing-library/react");
7
7
  var _apiFetch = _interopRequireDefault(require("@wordpress/api-fetch"));
8
+ var _data = require("@wordpress/data");
9
+ var _element = require("@wordpress/element");
8
10
  var _ = _interopRequireDefault(require("./"));
9
11
  var _utils = require("./store/utils");
12
+ var _store = require("./store");
10
13
  var _jsxRuntime = require("react/jsx-runtime");
11
14
  function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i["return"]) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
12
15
  function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); } r ? i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); }, _regeneratorDefine2(e, r, n, t); } /**
@@ -20,14 +23,12 @@ jest.mock('@wordpress/api-fetch', function () {
20
23
  return jest.fn();
21
24
  });
22
25
 
23
- // Both globals are localized onto every real wizard screen. The footer's
24
- // ExternalLink needs a string href, and the debug Notice reads aux data.
25
- window.newspack_aux_data = {
26
- is_debug_mode: false
27
- };
26
+ // Localized onto every real wizard screen; the footer's ExternalLink needs a
27
+ // string href.
28
28
  window.newspack_urls = {
29
29
  support: 'https://help.newspack.com/'
30
30
  };
31
+ window.scrollTo = jest.fn();
31
32
  var SETTINGS = {
32
33
  minimumDonation: '5'
33
34
  };
@@ -249,4 +250,302 @@ describe('Wizard', function () {
249
250
  }
250
251
  }, _callee4);
251
252
  })));
253
+ });
254
+ var NarrowingSection = function NarrowingSection() {
255
+ var _useDispatch = (0, _data.useDispatch)(_store.WIZARD_STORE_NAMESPACE),
256
+ setHeaderData = _useDispatch.setHeaderData;
257
+ (0, _element.useLayoutEffect)(function () {
258
+ setHeaderData({
259
+ fullWidth: false
260
+ });
261
+ }, [setHeaderData]);
262
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
263
+ children: "Narrowing section"
264
+ });
265
+ };
266
+ var RecoveringSection = function RecoveringSection() {
267
+ var _useDispatch2 = (0, _data.useDispatch)(_store.WIZARD_STORE_NAMESPACE),
268
+ setHeaderData = _useDispatch2.setHeaderData;
269
+ var _useState = (0, _element.useState)(true),
270
+ _useState2 = (0, _slicedToArray2["default"])(_useState, 2),
271
+ failed = _useState2[0],
272
+ setFailed = _useState2[1];
273
+ (0, _element.useLayoutEffect)(function () {
274
+ setHeaderData({
275
+ fullWidth: failed ? false : undefined
276
+ });
277
+ }, [setHeaderData, failed]);
278
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
279
+ onClick: function onClick() {
280
+ return setFailed(false);
281
+ },
282
+ children: "Retry"
283
+ });
284
+ };
285
+
286
+ // Two sections, because that is what mounts ResetHeaderData: a single-section
287
+ // wizard never exercises the reset these overrides have to survive.
288
+ var widthSections = function widthSections(renderSection) {
289
+ return [{
290
+ label: 'List',
291
+ path: '/',
292
+ exact: true,
293
+ fullWidth: true,
294
+ render: renderSection
295
+ }, {
296
+ label: 'Other',
297
+ path: '/other',
298
+ render: function render() {
299
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
300
+ children: "Other section"
301
+ });
302
+ }
303
+ }];
304
+ };
305
+ describe('Wizard content width', function () {
306
+ beforeEach(function () {
307
+ _apiFetch["default"].mockReset();
308
+ });
309
+ it('renders full-width when the section declares it and nothing overrides it', /*#__PURE__*/(0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator().m(function _callee5() {
310
+ var _render, container, _t5;
311
+ return _regenerator().w(function (_context5) {
312
+ while (1) switch (_context5.n) {
313
+ case 0:
314
+ _render = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"], {
315
+ headerText: "Test wizard",
316
+ sections: widthSections(function () {
317
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
318
+ children: "List content"
319
+ });
320
+ })
321
+ })), container = _render.container;
322
+ _t5 = expect;
323
+ _context5.n = 1;
324
+ return _react.screen.findByText('List content');
325
+ case 1:
326
+ _t5(_context5.v).toBeInTheDocument();
327
+ expect(container.querySelector('.newspack-wizard__content')).toHaveClass('newspack-wizard__content--full-width');
328
+ case 2:
329
+ return _context5.a(2);
330
+ }
331
+ }, _callee5);
332
+ })));
333
+ it('falls back to the standard width when a section overrides fullWidth before paint', /*#__PURE__*/(0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator().m(function _callee6() {
334
+ var _render2, container, _t6;
335
+ return _regenerator().w(function (_context6) {
336
+ while (1) switch (_context6.n) {
337
+ case 0:
338
+ _render2 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"], {
339
+ headerText: "Test wizard",
340
+ sections: widthSections(function () {
341
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(NarrowingSection, {});
342
+ })
343
+ })), container = _render2.container;
344
+ _t6 = expect;
345
+ _context6.n = 1;
346
+ return _react.screen.findByText('Narrowing section');
347
+ case 1:
348
+ _t6(_context6.v).toBeInTheDocument();
349
+ expect(container.querySelector('.newspack-wizard__content')).not.toHaveClass('newspack-wizard__content--full-width');
350
+ case 2:
351
+ return _context6.a(2);
352
+ }
353
+ }, _callee6);
354
+ })));
355
+ it('restores the declared width when the section clears its override', /*#__PURE__*/(0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator().m(function _callee7() {
356
+ var _render3, container, retry;
357
+ return _regenerator().w(function (_context7) {
358
+ while (1) switch (_context7.n) {
359
+ case 0:
360
+ _render3 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"], {
361
+ headerText: "Test wizard",
362
+ sections: widthSections(function () {
363
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(RecoveringSection, {});
364
+ })
365
+ })), container = _render3.container;
366
+ _context7.n = 1;
367
+ return _react.screen.findByRole('button', {
368
+ name: 'Retry'
369
+ });
370
+ case 1:
371
+ retry = _context7.v;
372
+ expect(container.querySelector('.newspack-wizard__content')).not.toHaveClass('newspack-wizard__content--full-width');
373
+ _react.fireEvent.click(retry);
374
+ _context7.n = 2;
375
+ return (0, _react.waitFor)(function () {
376
+ return expect(container.querySelector('.newspack-wizard__content')).toHaveClass('newspack-wizard__content--full-width');
377
+ });
378
+ case 2:
379
+ return _context7.a(2);
380
+ }
381
+ }, _callee7);
382
+ })));
383
+ it('keeps a section header published from a layout effect through the mount reset', /*#__PURE__*/(0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator().m(function _callee8() {
384
+ var _t7;
385
+ return _regenerator().w(function (_context8) {
386
+ while (1) switch (_context8.n) {
387
+ case 0:
388
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"], {
389
+ headerText: "Test wizard",
390
+ sections: widthSections(function () {
391
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(NarrowingSection, {});
392
+ })
393
+ }));
394
+ _t7 = expect;
395
+ _context8.n = 1;
396
+ return _react.screen.findByText('Narrowing section');
397
+ case 1:
398
+ _t7(_context8.v).toBeInTheDocument();
399
+ expect((0, _data.select)(_store.WIZARD_STORE_NAMESPACE).getHeaderData().fullWidth).toBe(false);
400
+ case 2:
401
+ return _context8.a(2);
402
+ }
403
+ }, _callee8);
404
+ })));
405
+ });
406
+ describe('Wizard section tabs', function () {
407
+ var sections = [{
408
+ label: 'List',
409
+ path: '/',
410
+ exact: true,
411
+ render: function render() {
412
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
413
+ children: "List content"
414
+ });
415
+ }
416
+ }, {
417
+ path: '/items/:itemId/logs/:tab?',
418
+ isHidden: true,
419
+ render: function render() {
420
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
421
+ children: "Logs content"
422
+ });
423
+ },
424
+ tabbedNavigation: function tabbedNavigation(_ref10) {
425
+ var itemId = _ref10.itemId;
426
+ return [{
427
+ label: 'First Tab',
428
+ path: "/items/".concat(itemId, "/logs"),
429
+ exact: true
430
+ }, {
431
+ label: 'Second Tab',
432
+ path: "/items/".concat(itemId, "/logs/second"),
433
+ exact: true
434
+ }];
435
+ }
436
+ }];
437
+ beforeEach(function () {
438
+ _apiFetch["default"].mockReset();
439
+ });
440
+ afterEach(function () {
441
+ window.location.hash = '';
442
+ });
443
+ it('shows the tabs a section builds from its route params while it matches', /*#__PURE__*/(0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator().m(function _callee9() {
444
+ var _t8;
445
+ return _regenerator().w(function (_context9) {
446
+ while (1) switch (_context9.n) {
447
+ case 0:
448
+ window.location.hash = '#/items/42/logs/second';
449
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"], {
450
+ headerText: "Test wizard",
451
+ sections: sections
452
+ }));
453
+ _t8 = expect;
454
+ _context9.n = 1;
455
+ return _react.screen.findByText('Logs content');
456
+ case 1:
457
+ _t8(_context9.v).toBeInTheDocument();
458
+ expect(_react.screen.getByRole('tab', {
459
+ name: 'First Tab'
460
+ })).toHaveAttribute('href', '#/items/42/logs');
461
+ expect(_react.screen.getByRole('tab', {
462
+ name: 'Second Tab'
463
+ })).toHaveAttribute('aria-selected', 'true');
464
+ case 2:
465
+ return _context9.a(2);
466
+ }
467
+ }, _callee9);
468
+ })));
469
+ it('leaves the tabs out on a route the section does not match', /*#__PURE__*/(0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator().m(function _callee0() {
470
+ var _t9;
471
+ return _regenerator().w(function (_context0) {
472
+ while (1) switch (_context0.n) {
473
+ case 0:
474
+ window.location.hash = '#/';
475
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"], {
476
+ headerText: "Test wizard",
477
+ sections: sections
478
+ }));
479
+ _t9 = expect;
480
+ _context0.n = 1;
481
+ return _react.screen.findByText('List content');
482
+ case 1:
483
+ _t9(_context0.v).toBeInTheDocument();
484
+ expect(_react.screen.queryByRole('tab')).toBeNull();
485
+ case 2:
486
+ return _context0.a(2);
487
+ }
488
+ }, _callee0);
489
+ })));
490
+ });
491
+ describe('Wizard section subtitle', function () {
492
+ beforeEach(function () {
493
+ _apiFetch["default"].mockReset();
494
+ _apiFetch["default"].mockResolvedValue({});
495
+ });
496
+ it("shows the active section's subHeaderText in the header, falling back to the wizard's", /*#__PURE__*/(0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator().m(function _callee1() {
497
+ var _render4, container, subtitle, _t0, _t1;
498
+ return _regenerator().w(function (_context1) {
499
+ while (1) switch (_context1.n) {
500
+ case 0:
501
+ window.location.hash = '#/list';
502
+ _render4 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"], {
503
+ headerText: "Test wizard",
504
+ subHeaderText: "Wizard intro",
505
+ sections: [{
506
+ label: 'List',
507
+ path: '/list',
508
+ exact: true,
509
+ subHeaderText: 'List intro',
510
+ render: function render() {
511
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
512
+ children: "List view"
513
+ });
514
+ }
515
+ }, {
516
+ label: 'Item',
517
+ path: '/list/:id',
518
+ isHidden: true,
519
+ render: function render() {
520
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
521
+ children: "Item view"
522
+ });
523
+ }
524
+ }]
525
+ })), container = _render4.container;
526
+ subtitle = function subtitle() {
527
+ var _container$querySelec;
528
+ return (_container$querySelec = container.querySelector('.newspack-page__header-subtitle')) === null || _container$querySelec === void 0 ? void 0 : _container$querySelec.textContent;
529
+ };
530
+ _t0 = expect;
531
+ _context1.n = 1;
532
+ return _react.screen.findByText('List view');
533
+ case 1:
534
+ _t0(_context1.v).toBeInTheDocument();
535
+ expect(subtitle()).toBe('List intro');
536
+ (0, _react.act)(function () {
537
+ window.location.hash = '#/list/esp';
538
+ window.dispatchEvent(new HashChangeEvent('hashchange'));
539
+ });
540
+ _t1 = expect;
541
+ _context1.n = 2;
542
+ return _react.screen.findByText('Item view');
543
+ case 2:
544
+ _t1(_context1.v).toBeInTheDocument();
545
+ expect(subtitle()).toBe('Wizard intro');
546
+ case 3:
547
+ return _context1.a(2);
548
+ }
549
+ }, _callee1);
550
+ })));
252
551
  });
@@ -23,6 +23,8 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
23
23
  */
24
24
  var WIZARD_STORE_NAMESPACE = exports.WIZARD_STORE_NAMESPACE = 'newspack/wizards';
25
25
  var DEFAULT_STATE = {
26
+ // `fullWidth` is deliberately absent: a default here would narrow every
27
+ // full-width section on reset, since Wizard only falls back when it is unset.
26
28
  headerData: {
27
29
  actions: [],
28
30
  backNav: '',