newspack-components 4.8.1-alpha.1 → 4.9.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 +9 -1
- 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/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/wizard/breadcrumbs-select.js +17 -4
- package/dist/cjs/wizard/breadcrumbs-select.test.js +17 -0
- package/dist/cjs/wizard/index.js +42 -6
- package/dist/cjs/wizard/index.test.js +146 -0
- 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/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/wizard/breadcrumbs-select.js +16 -3
- package/dist/esm/wizard/breadcrumbs-select.test.js +18 -1
- package/dist/esm/wizard/index.js +42 -6
- package/dist/esm/wizard/index.test.js +146 -0
- package/package.json +1 -1
- 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/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/wizard/breadcrumbs-select.js +12 -4
- package/src/wizard/breadcrumbs-select.test.js +15 -1
- package/src/wizard/index.js +34 -5
- package/src/wizard/index.test.js +73 -0
|
@@ -21,14 +21,26 @@
|
|
|
21
21
|
background: #004cff;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
&--
|
|
25
|
-
background: #
|
|
24
|
+
&--beehiiv {
|
|
25
|
+
background: #060419;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
&--constant-contact {
|
|
29
29
|
background: wp-colors.$gray-100;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
&--fundraiseup {
|
|
33
|
+
background: #2bb77b;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
&--gravity-forms {
|
|
37
|
+
background: #ff4f00;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&--mailchimp {
|
|
41
|
+
background: #ffe01b;
|
|
42
|
+
}
|
|
43
|
+
|
|
32
44
|
&--manual {
|
|
33
45
|
background: wp-colors.$gray-800;
|
|
34
46
|
color: wp-colors.$white;
|
|
@@ -39,4 +51,8 @@
|
|
|
39
51
|
fill: currentcolor;
|
|
40
52
|
}
|
|
41
53
|
}
|
|
54
|
+
|
|
55
|
+
&--salesforce {
|
|
56
|
+
background: #0d9dda;
|
|
57
|
+
}
|
|
42
58
|
}
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
var activeCampaign = /*#__PURE__*/
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
var activeCampaign = /*#__PURE__*/_jsx("svg", {
|
|
3
3
|
xmlns: "http://www.w3.org/2000/svg",
|
|
4
4
|
width: "24",
|
|
5
5
|
height: "24",
|
|
6
6
|
viewBox: "0 0 24 24",
|
|
7
7
|
fill: "none",
|
|
8
|
-
children:
|
|
9
|
-
d: "
|
|
8
|
+
children: /*#__PURE__*/_jsx("path", {
|
|
9
|
+
d: "M17.28 10.4037C17.8244 10.7666 18.115 11.3468 18.115 11.9637C18.115 12.5805 17.788 13.1609 17.28 13.5238L5.88501 21V19.4399C5.88501 18.9681 6.10324 18.4965 6.5387 18.2062L15.9375 11.9637L6.5387 5.68506C6.13946 5.43097 5.88501 4.95947 5.88501 4.45129V3L17.28 10.4037ZM5.88501 8.37122C5.88501 7.89959 6.4296 7.64482 6.79248 7.8988L12.7438 11.9275L11.9451 12.4713C11.4371 12.7977 10.7842 12.7978 10.2762 12.4713L8.96997 11.6375L5.88501 9.56873V8.37122Z",
|
|
10
10
|
fill: "white"
|
|
11
|
-
})
|
|
12
|
-
d: "M6.56445 8.77441C6.56445 8.35519 7.04853 8.12873 7.37109 8.35449L12.6611 11.9355L11.9512 12.4189C11.4996 12.7091 10.9193 12.7092 10.4678 12.4189L9.30664 11.6777L6.56445 9.83887V8.77441Z",
|
|
13
|
-
fill: "white"
|
|
14
|
-
})]
|
|
11
|
+
})
|
|
15
12
|
});
|
|
16
13
|
export default activeCampaign;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
var beehiiv = /*#__PURE__*/_jsx("svg", {
|
|
3
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4
|
+
width: "24",
|
|
5
|
+
height: "24",
|
|
6
|
+
viewBox: "0 0 24 24",
|
|
7
|
+
fill: "none",
|
|
8
|
+
children: /*#__PURE__*/_jsx("path", {
|
|
9
|
+
d: "M18.6602 11.4894H5.35668C5.19293 11.4883 5.03627 11.4225 4.92088 11.3063C4.80549 11.1901 4.74073 11.033 4.74073 10.8692V9.92487C4.7398 9.67122 4.78886 9.41988 4.88509 9.1852C4.98132 8.95052 5.12284 8.73709 5.30157 8.55712C5.4803 8.37714 5.69274 8.23414 5.92675 8.13629C6.16076 8.03843 6.41176 7.98764 6.6654 7.9868H17.3353C17.5889 7.98754 17.8398 8.03822 18.0738 8.13595C18.3078 8.23368 18.5203 8.37654 18.6991 8.55637C18.8779 8.7362 19.0195 8.94949 19.1158 9.18406C19.2122 9.41862 19.2614 9.66987 19.2607 9.92346V10.8685C19.2638 10.9491 19.2506 11.0296 19.2218 11.1049C19.193 11.1803 19.1492 11.249 19.0931 11.307C19.0369 11.365 18.9697 11.411 18.8953 11.4422C18.8209 11.4734 18.7409 11.4899 18.6602 11.4894ZM15.8574 6.96492H8.15947C7.99191 6.96343 7.8317 6.89593 7.71361 6.77704C7.59552 6.65816 7.52908 6.4975 7.52872 6.32994C7.52872 4.74919 8.80643 3.46302 10.3773 3.46302H13.641C15.2119 3.46302 16.4896 4.74919 16.4896 6.32994C16.4907 6.41334 16.4752 6.49613 16.4439 6.57345C16.4126 6.65077 16.3662 6.72106 16.3074 6.7802C16.2486 6.83934 16.1785 6.88615 16.1014 6.91787C16.0243 6.94959 15.9416 6.96558 15.8582 6.96492H15.8574ZM19.2755 12.5113H4.74073C3.7858 12.5113 3 13.3013 3 14.2619C3 15.2225 3.7858 16.0132 4.74073 16.0132H9.89879C10.0834 15.0216 10.9453 14.2619 11.9919 14.2619C12.4923 14.2631 12.9767 14.4386 13.3618 14.7582C13.7468 15.0778 14.0085 15.5216 14.1019 16.0132H19.2607C20.2149 16.0132 21 15.2225 21 14.2619C21 13.3013 20.2304 12.5113 19.2755 12.5113ZM18.6454 17.0358H14.1336V20.537H17.5214C18.4756 20.537 19.2607 19.7477 19.2607 18.7864V17.6708C19.2636 17.5882 19.2499 17.506 19.2202 17.4289C19.1906 17.3518 19.1457 17.2816 19.0883 17.2223C19.0308 17.163 18.962 17.1159 18.8859 17.0838C18.8098 17.0518 18.728 17.0354 18.6454 17.0358ZM5.35668 17.0358C5.189 17.0371 5.02861 17.1045 4.91037 17.2234C4.79213 17.3423 4.72559 17.5031 4.72523 17.6708V18.7864C4.72523 19.747 5.51102 20.537 6.46596 20.537H9.85298V17.0358H5.35668Z",
|
|
10
|
+
fill: "white"
|
|
11
|
+
})
|
|
12
|
+
});
|
|
13
|
+
export default beehiiv;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
var gravityForms = /*#__PURE__*/_jsx("svg", {
|
|
3
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4
|
+
width: "24",
|
|
5
|
+
height: "24",
|
|
6
|
+
viewBox: "0 0 24 24",
|
|
7
|
+
fill: "none",
|
|
8
|
+
children: /*#__PURE__*/_jsx("path", {
|
|
9
|
+
d: "M8.74072 8.98989H24V4.73383H8.77618C6.75022 4.67092 4.79489 5.46964 3.41 6.92583C0.0886559 10.4377 0 19.2696 0 19.2696H23.8818V11.2749H19.5912V15.0019H4.58018C4.67474 13.6123 5.31889 11.1296 6.53633 9.84462C7.10785 9.25496 7.91399 8.9424 8.74072 8.98989Z",
|
|
10
|
+
fill: "white"
|
|
11
|
+
})
|
|
12
|
+
});
|
|
13
|
+
export default gravityForms;
|
|
@@ -7,21 +7,32 @@ import { atSymbol } from '@wordpress/icons';
|
|
|
7
7
|
* Internal dependencies
|
|
8
8
|
*/
|
|
9
9
|
import activeCampaign from './active-campaign';
|
|
10
|
+
import beehiiv from './beehiiv';
|
|
10
11
|
import constantContact from './constant-contact';
|
|
12
|
+
import fundraiseUp from './fundraise-up';
|
|
13
|
+
import gravityForms from './gravity-forms';
|
|
11
14
|
import mailchimp from './mailchimp';
|
|
15
|
+
import salesforce from './salesforce';
|
|
12
16
|
export { default as activeCampaign } from './active-campaign';
|
|
17
|
+
export { default as beehiiv } from './beehiiv';
|
|
13
18
|
export { default as constantContact } from './constant-contact';
|
|
14
19
|
export { default as fundraiseUp } from './fundraise-up';
|
|
20
|
+
export { default as gravityForms } from './gravity-forms';
|
|
15
21
|
export { default as mailchimp } from './mailchimp';
|
|
16
22
|
export { default as salesforce } from './salesforce';
|
|
17
23
|
export { default as wisepops } from './wisepops';
|
|
18
24
|
|
|
19
|
-
//
|
|
20
|
-
// (`Newspack_Newsletters::service_provider()`)
|
|
21
|
-
|
|
25
|
+
// Brand marks keyed by the ESP slug the backend reports
|
|
26
|
+
// (`Newspack_Newsletters::service_provider()`), by integration ID, or by the
|
|
27
|
+
// brand slug an integration maps to. Rendered via IntegrationIcon.
|
|
28
|
+
export var providerIcons = {
|
|
22
29
|
active_campaign: activeCampaign,
|
|
23
30
|
mailchimp: mailchimp,
|
|
24
31
|
constant_contact: constantContact,
|
|
25
|
-
manual: atSymbol
|
|
32
|
+
manual: atSymbol,
|
|
33
|
+
salesforce: salesforce,
|
|
34
|
+
beehiiv: beehiiv,
|
|
35
|
+
fundraiseup: fundraiseUp,
|
|
36
|
+
gravity_forms: gravityForms
|
|
26
37
|
};
|
|
27
38
|
export var espProviderOrder = ['active_campaign', 'mailchimp', 'constant_contact', 'manual'];
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
var salesforce = /*#__PURE__*/_jsx("svg", {
|
|
3
3
|
xmlns: "http://www.w3.org/2000/svg",
|
|
4
|
-
|
|
4
|
+
width: "24",
|
|
5
|
+
height: "24",
|
|
6
|
+
viewBox: "0 0 24 24",
|
|
5
7
|
fill: "none",
|
|
6
8
|
children: /*#__PURE__*/_jsx("path", {
|
|
7
|
-
d: "
|
|
8
|
-
fill: "
|
|
9
|
+
d: "M10.0838 5.745C10.8213 4.9775 11.8463 4.5 12.9813 4.5C14.4913 4.5 15.8063 5.3425 16.5088 6.59C17.1188 6.3175 17.7938 6.165 18.5013 6.165C21.2238 6.165 23.4288 8.39 23.4288 11.1375C23.4288 13.885 21.2213 16.11 18.5013 16.11C18.1688 16.11 17.8438 16.0775 17.5313 16.0125C16.9138 17.1125 15.7363 17.8575 14.3863 17.8575C13.8213 17.8575 13.2863 17.7275 12.8113 17.495C12.1863 18.9675 10.7263 20 9.02876 20C7.33126 20 5.75126 18.88 5.17126 17.31C4.91876 17.3625 4.65626 17.3925 4.38626 17.3925C2.27876 17.3925 0.571259 15.6675 0.571259 13.5375C0.571259 12.11 1.33876 10.865 2.47876 10.1975C2.24376 9.6575 2.11376 9.06 2.11376 8.435C2.11376 5.985 4.10126 4 6.55376 4C7.99376 4 9.27376 4.685 10.0838 5.745Z",
|
|
10
|
+
fill: "white"
|
|
9
11
|
})
|
|
10
12
|
});
|
|
11
13
|
export default salesforce;
|
|
@@ -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
|
*/
|
|
@@ -22,7 +25,7 @@ import { category, chevronLeft, moreVertical } from '@wordpress/icons';
|
|
|
22
25
|
* Internal dependencies
|
|
23
26
|
*/
|
|
24
27
|
import { Footer, DebugBadge, Button, TabbedNavigation, PluginInstaller, SectionHeader, HandoffMessage, Page, Waiting } from '../';
|
|
25
|
-
import { activeBreadcrumbs, appendSectionName } from './breadcrumbs-select';
|
|
28
|
+
import { activeBreadcrumbs, activeSection, appendSectionName } from './breadcrumbs-select';
|
|
26
29
|
import Router from '../proxied-imports/router';
|
|
27
30
|
import registerStore, { WIZARD_STORE_NAMESPACE } from './store';
|
|
28
31
|
import WizardSnackbar from './components/WizardSnackbar';
|
|
@@ -59,6 +62,7 @@ var HashRouter = Router.HashRouter,
|
|
|
59
62
|
Redirect = Router.Redirect,
|
|
60
63
|
Route = Router.Route,
|
|
61
64
|
Switch = Router.Switch,
|
|
65
|
+
matchPath = Router.matchPath,
|
|
62
66
|
useLocation = Router.useLocation;
|
|
63
67
|
|
|
64
68
|
/**
|
|
@@ -111,16 +115,46 @@ var ResetHeaderData = function ResetHeaderData() {
|
|
|
111
115
|
* can read the current route and derive the active-tab breadcrumb.
|
|
112
116
|
*/
|
|
113
117
|
var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
|
|
118
|
+
var _activeSection;
|
|
114
119
|
var hideHeader = _ref.hideHeader,
|
|
115
120
|
headerText = _ref.headerText,
|
|
116
121
|
sections = _ref.sections,
|
|
117
122
|
sectionName = _ref.sectionName,
|
|
118
123
|
subTitle = _ref.subTitle,
|
|
119
124
|
actions = _ref.actions,
|
|
120
|
-
|
|
125
|
+
wizardTabbedNavigation = _ref.tabbedNavigation,
|
|
121
126
|
children = _ref.children;
|
|
122
127
|
var _useLocation = useLocation(),
|
|
123
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
|
+
}
|
|
124
158
|
if (hideHeader) {
|
|
125
159
|
// Without the Page shell the tabs still own the content: it renders
|
|
126
160
|
// inside the active tab's panel.
|
|
@@ -140,9 +174,10 @@ var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
|
|
|
140
174
|
// Append any render-time leaf crumb(s) the section supplied via
|
|
141
175
|
// headerData.sectionName (deduped against the current trailing label).
|
|
142
176
|
breadcrumbItems = appendSectionName(breadcrumbItems, sectionName);
|
|
177
|
+
var sectionSubTitle = (_activeSection = activeSection(sections, pathname)) === null || _activeSection === void 0 ? void 0 : _activeSection.subHeaderText;
|
|
143
178
|
return /*#__PURE__*/_jsx(Page, {
|
|
144
179
|
breadcrumbItems: breadcrumbItems,
|
|
145
|
-
subTitle: subTitle,
|
|
180
|
+
subTitle: sectionSubTitle !== null && sectionSubTitle !== void 0 ? sectionSubTitle : subTitle,
|
|
146
181
|
actions: actions,
|
|
147
182
|
tabbedNavigation: tabbedNavigation,
|
|
148
183
|
children: children
|
|
@@ -155,7 +190,8 @@ var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
|
|
|
155
190
|
* @property {string} [subHeaderText] The sub-header text, optional.
|
|
156
191
|
* @property {string} [apiSlug] The API slug, optional.
|
|
157
192
|
* @property {string} [className] CSS classes, optional.
|
|
158
|
-
* @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.
|
|
159
195
|
* @property {boolean} [hasSimpleFooter] Indicates if a simple footer is used, optional.
|
|
160
196
|
* @property {() => void} [renderAboveSections] Function to render content above sections, optional.
|
|
161
197
|
* @property {string[]} [requiredPlugins] Array of required plugin strings, optional.
|
|
@@ -333,11 +369,11 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
333
369
|
bubblesVirtually: true
|
|
334
370
|
}), /*#__PURE__*/_jsxs(Switch, {
|
|
335
371
|
children: [routedSections.map(function (section, index) {
|
|
336
|
-
var _section$
|
|
372
|
+
var _section$exact2;
|
|
337
373
|
var SectionComponent = section.render;
|
|
338
374
|
var sectionProps = section.props || {};
|
|
339
375
|
return /*#__PURE__*/_jsx(Route, {
|
|
340
|
-
exact: (_section$
|
|
376
|
+
exact: (_section$exact2 = section.exact) !== null && _section$exact2 !== void 0 ? _section$exact2 : false,
|
|
341
377
|
path: section.path,
|
|
342
378
|
render: function render(routerProps) {
|
|
343
379
|
return /*#__PURE__*/_jsxs("div", {
|
|
@@ -404,4 +404,150 @@ describe('Wizard content width', function () {
|
|
|
404
404
|
}
|
|
405
405
|
}, _callee8);
|
|
406
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
|
+
})));
|
|
407
553
|
});
|
package/package.json
CHANGED
|
@@ -11,13 +11,15 @@ A card component for presenting a named feature or setting with a predictable, s
|
|
|
11
11
|
|
|
12
12
|
Cards sit side by side, so a bare "Enable" names no feature out of context. The card appends `title` to the primary button's accessible name ("Enable Metered Countdown") and to the "More" menu ("More options for Metered Countdown"). The visible label leads, so voice control still matches on the word the user can see. Nothing to pass — this is automatic.
|
|
13
13
|
|
|
14
|
+
When enabling leaves nothing to configure, the primary button goes away while it still has focus; the card moves that focus to the "More" menu rather than letting it fall to the page.
|
|
15
|
+
|
|
14
16
|
## States
|
|
15
17
|
|
|
16
18
|
| State | Condition | Button | Dropdown | Badge |
|
|
17
19
|
|---|---|---|---|---|
|
|
18
20
|
| **Unmet requirements** | `requirements` is set | "Enable" — blocked but still focusable, and described by the badge (clickable if `requirementsActionable`) | Shown if `enabled` and `requirementsActionable` (and `moreControls` provided); otherwise hidden | High-intent badge with `requirements` text |
|
|
19
21
|
| **Disabled** | `!enabled`, no requirements | "Enable" | Hidden | None |
|
|
20
|
-
| **Enabled** | `enabled`, no requirements | "Configure" | Shown if `moreControls` provided | Stable-intent badge ("Enabled") |
|
|
22
|
+
| **Enabled** | `enabled`, no requirements | "Configure", or none without `onConfigure` | Shown if `moreControls` provided | Stable-intent badge ("Enabled") |
|
|
21
23
|
|
|
22
24
|
When `requirements` is set the title drops to the muted text colour. The description already uses that colour in every state, so the unmet-requirements state is signalled by the title colour plus the high-intent badge.
|
|
23
25
|
|
|
@@ -75,9 +77,9 @@ import { __ } from '@wordpress/i18n';
|
|
|
75
77
|
|
|
76
78
|
## With a custom icon
|
|
77
79
|
|
|
78
|
-
`icon` takes either a descriptor object or a ready React element. A descriptor gets the standard treatment: pass `node` for the icon element, `fill` for the SVG colour, `backgroundColor` for a container background
|
|
80
|
+
`icon` takes either a descriptor object or a ready React element. A descriptor gets the standard treatment: pass `node` for the icon element, `fill` for the SVG colour, and `backgroundColor` for a container background. A ready element renders exactly as given, with no container or background, which is the escape hatch for an icon that already carries its own chrome.
|
|
79
81
|
|
|
80
|
-
A descriptor's container is always **40 × 40 px** with the SVG at **24 × 24 px**. Setting `backgroundColor`
|
|
82
|
+
A descriptor's container is always **40 × 40 px** with the SVG at **24 × 24 px**. Setting `backgroundColor` makes the container a circle.
|
|
81
83
|
|
|
82
84
|
`fill` sets the container's `color`, which the SVG picks up through `fill: currentcolor`. That only recolours single-colour icons that inherit their fill, such as those from `@wordpress/icons`. A vendor's own mark carries `fill` on its paths and keeps its colours, so pair it with `backgroundColor` rather than trying to tint it.
|
|
83
85
|
|
|
@@ -101,9 +103,9 @@ import colors from 'newspack-colors';
|
|
|
101
103
|
|
|
102
104
|
// A vendor mark on its own brand background, keeping the mark's colours
|
|
103
105
|
<CardFeature
|
|
104
|
-
title=
|
|
106
|
+
title="Mailchimp"
|
|
105
107
|
description={ __( 'Sync reader activity with your Mailchimp audience.', 'newspack-plugin' ) }
|
|
106
|
-
icon={ { node: <MailchimpMark />, backgroundColor: '#ffe01b'
|
|
108
|
+
icon={ { node: <MailchimpMark />, backgroundColor: '#ffe01b' } }
|
|
107
109
|
enabled={ isEnabled }
|
|
108
110
|
onEnable={ handleEnable }
|
|
109
111
|
onConfigure={ handleConfigure }
|
|
@@ -112,7 +114,7 @@ import colors from 'newspack-colors';
|
|
|
112
114
|
|
|
113
115
|
// A ready element, rendered as-is
|
|
114
116
|
<CardFeature
|
|
115
|
-
title=
|
|
117
|
+
title="Mailchimp"
|
|
116
118
|
description={ __( 'Sync reader activity with your Mailchimp audience.', 'newspack-plugin' ) }
|
|
117
119
|
icon={ <IntegrationIcon provider="mailchimp" /> }
|
|
118
120
|
enabled={ isEnabled }
|
|
@@ -203,7 +205,7 @@ The card is built on `Card.Root`, `Card.Header` and `Card.Content` from `@wordpr
|
|
|
203
205
|
| `enableLabel` | `string` | `"Enable"` | Label for the primary button in its "Enable" states: not enabled, or enabled with an unmet requirement |
|
|
204
206
|
| `configureLabel` | `string` | `"Configure"` | Label for the primary button in its "Configure" state: enabled, with no unmet requirement |
|
|
205
207
|
| `onEnable` | `() => void` | — | Called when the primary button is clicked while it reads "Enable". That covers the not-enabled case and the enabled-with-unmet-requirements case, where the feature is on but the requirement is what the button acts on |
|
|
206
|
-
| `onConfigure` | `() => void` | — | Called when the primary button is clicked while it reads "Configure", which is the enabled state with no unmet requirements |
|
|
208
|
+
| `onConfigure` | `() => void` | — | Called when the primary button is clicked while it reads "Configure", which is the enabled state with no unmet requirements. Omit it for a feature with nothing to configure, and that state shows no primary button |
|
|
207
209
|
| `moreControls` | `MoreControl[]` | — | Items for the "More" dropdown. Shown when `enabled` and either there are no `requirements` or `requirementsActionable` is set |
|
|
208
210
|
| `badge` | `{ label?: string; intent?: BadgeIntent }` | `{ label: "Enabled", intent: "stable" }` | Badge shown when enabled. Ignored while `requirements` is set, which takes the badge |
|
|
209
211
|
| `busy` | `boolean` | `false` | Shows the primary button as busy and blocks it while an action is in flight |
|
|
@@ -215,10 +217,7 @@ The card is built on `Card.Root`, `Card.Header` and `Card.Content` from `@wordpr
|
|
|
215
217
|
type CardFeatureIcon = {
|
|
216
218
|
node: React.ReactNode; // The icon element to render
|
|
217
219
|
fill?: string; // SVG fill colour (applied via currentColor)
|
|
218
|
-
backgroundColor?: string; // Background colour of the 40×40 container
|
|
219
|
-
radius?: 'small' | 'full'; // 'small' = 2px ($radius-small), 'full' = 50% ($radius-round)
|
|
220
|
-
// Defaults to 'small' whenever backgroundColor is set,
|
|
221
|
-
// and has nothing to round without one.
|
|
220
|
+
backgroundColor?: string; // Background colour of the 40×40 container, always a circle
|
|
222
221
|
};
|
|
223
222
|
```
|
|
224
223
|
|