newspack-components 4.8.0 → 4.8.1-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 +9 -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/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/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/index.js +8 -7
- package/dist/cjs/wizard/index.test.js +158 -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/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/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/index.js +11 -10
- package/dist/esm/wizard/index.test.js +158 -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/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/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/index.js +11 -9
- package/src/wizard/index.test.js +96 -3
- package/src/wizard/store/index.js +2 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Footer
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
@use "../mixins" as mixins;
|
|
5
6
|
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
6
7
|
|
|
7
8
|
.newspack-footer {
|
|
@@ -31,7 +32,8 @@
|
|
|
31
32
|
li {
|
|
32
33
|
margin: 8px;
|
|
33
34
|
|
|
34
|
-
a
|
|
35
|
+
a,
|
|
36
|
+
button {
|
|
35
37
|
align-items: flex-end;
|
|
36
38
|
color: inherit;
|
|
37
39
|
display: flex;
|
|
@@ -42,5 +44,19 @@
|
|
|
42
44
|
color: wp-colors.$gray-900;
|
|
43
45
|
}
|
|
44
46
|
}
|
|
47
|
+
|
|
48
|
+
button {
|
|
49
|
+
appearance: none;
|
|
50
|
+
background: none;
|
|
51
|
+
border: 0;
|
|
52
|
+
cursor: pointer;
|
|
53
|
+
font: inherit;
|
|
54
|
+
padding: 0;
|
|
55
|
+
text-decoration: underline;
|
|
56
|
+
|
|
57
|
+
&:focus-visible {
|
|
58
|
+
@include mixins.wpds-focus-ring;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
45
61
|
}
|
|
46
62
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -17,6 +17,7 @@ export { default as ColorPicker } from './color-picker';
|
|
|
17
17
|
export { default as ConfirmDialog } from './confirm-dialog';
|
|
18
18
|
export { default as CustomSelectControl } from './custom-select-control';
|
|
19
19
|
export { default as DataViews } from './dataviews';
|
|
20
|
+
export { default as DebugBadge } from './debug-badge';
|
|
20
21
|
export { default as Divider } from './divider';
|
|
21
22
|
export { default as Drawer } from './drawer';
|
|
22
23
|
export { default as EmptyState } from './empty-state';
|
package/dist/esm/notice/index.js
CHANGED
|
@@ -13,7 +13,7 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
|
|
|
13
13
|
* WordPress dependencies.
|
|
14
14
|
*/
|
|
15
15
|
import { Component, RawHTML } from '@wordpress/element';
|
|
16
|
-
import { Icon,
|
|
16
|
+
import { Icon, check, help, info } from '@wordpress/icons';
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Internal dependencies.
|
|
@@ -40,7 +40,6 @@ var Notice = /*#__PURE__*/function (_Component) {
|
|
|
40
40
|
function render() {
|
|
41
41
|
var _this$props = this.props,
|
|
42
42
|
className = _this$props.className,
|
|
43
|
-
debugMode = _this$props.debugMode,
|
|
44
43
|
isError = _this$props.isError,
|
|
45
44
|
isHandoff = _this$props.isHandoff,
|
|
46
45
|
isHelp = _this$props.isHelp,
|
|
@@ -52,14 +51,12 @@ var Notice = /*#__PURE__*/function (_Component) {
|
|
|
52
51
|
style = _this$props$style === void 0 ? {} : _this$props$style,
|
|
53
52
|
_this$props$children = _this$props.children,
|
|
54
53
|
children = _this$props$children === void 0 ? null : _this$props$children;
|
|
55
|
-
var classes = classnames('newspack-notice', className,
|
|
54
|
+
var classes = classnames('newspack-notice', className, isError && 'newspack-notice__is-error', isHandoff && 'newspack-notice__is-handoff', isHelp && 'newspack-notice__is-help', isSuccess && 'newspack-notice__is-success', isWarning && 'newspack-notice__is-warning');
|
|
56
55
|
var noticeIcon;
|
|
57
56
|
if (isHelp) {
|
|
58
57
|
noticeIcon = help;
|
|
59
58
|
} else if (isSuccess) {
|
|
60
59
|
noticeIcon = check;
|
|
61
|
-
} else if (debugMode) {
|
|
62
|
-
noticeIcon = bug;
|
|
63
60
|
} else {
|
|
64
61
|
noticeIcon = info;
|
|
65
62
|
}
|
|
@@ -22,25 +22,6 @@
|
|
|
22
22
|
margin-right: 4px;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
&__is-debug {
|
|
26
|
-
background: np-colors.$primary-600;
|
|
27
|
-
border-radius: 50%;
|
|
28
|
-
bottom: 16px;
|
|
29
|
-
box-shadow: 0 0 8px 4px rgba(black, 0.08);
|
|
30
|
-
color: white;
|
|
31
|
-
font-weight: bold;
|
|
32
|
-
margin: 0 16px;
|
|
33
|
-
padding: 6px;
|
|
34
|
-
position: fixed;
|
|
35
|
-
text-transform: uppercase;
|
|
36
|
-
z-index: 9997;
|
|
37
|
-
|
|
38
|
-
> svg {
|
|
39
|
-
fill: white;
|
|
40
|
-
margin: 0;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
25
|
&__is-error {
|
|
45
26
|
background: color.adjust(wp-colors.$alert-red, $lightness: 35%);
|
|
46
27
|
|
|
@@ -9,7 +9,7 @@ import { cloneElement } from '@wordpress/element';
|
|
|
9
9
|
/**
|
|
10
10
|
* Internal dependencies
|
|
11
11
|
*/
|
|
12
|
-
import { Button,
|
|
12
|
+
import { Button, DebugBadge, Handoff, HandoffMessage, TabbedNavigation, Page } from '../';
|
|
13
13
|
import { activeBreadcrumbs } from '../wizard/breadcrumbs-select';
|
|
14
14
|
import { buttonProps } from '../button-props';
|
|
15
15
|
import Router from '../proxied-imports/router';
|
|
@@ -111,9 +111,7 @@ export default function withWizardScreen(WrappedComponent) {
|
|
|
111
111
|
}];
|
|
112
112
|
}
|
|
113
113
|
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
114
|
-
children: [
|
|
115
|
-
debugMode: true
|
|
116
|
-
}), hideHeader ?
|
|
114
|
+
children: [/*#__PURE__*/_jsx(DebugBadge, {}), hideHeader ?
|
|
117
115
|
/*#__PURE__*/
|
|
118
116
|
// Without the Page shell the tabs still own the content: it
|
|
119
117
|
// renders inside the active tab's panel.
|
|
@@ -9,9 +9,6 @@ import { HashRouter } from 'react-router-dom';
|
|
|
9
9
|
*/
|
|
10
10
|
import withWizardScreen from './';
|
|
11
11
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
-
global.newspack_aux_data = {
|
|
13
|
-
is_debug_mode: false
|
|
14
|
-
};
|
|
15
12
|
describe('withWizardScreen', function () {
|
|
16
13
|
it('falls back to a single headerText breadcrumb when no breadcrumbItems are provided', function () {
|
|
17
14
|
var WrappedComponent = function WrappedComponent() {
|
package/dist/esm/wizard/index.js
CHANGED
|
@@ -10,19 +10,18 @@ import classnames from 'classnames';
|
|
|
10
10
|
/**
|
|
11
11
|
* WordPress dependencies.
|
|
12
12
|
*/
|
|
13
|
-
|
|
14
|
-
import { DropdownMenu, MenuGroup, MenuItem, Notice as CoreNotice, SlotFillProvider, createSlotFill,
|
|
13
|
+
import { DropdownMenu, MenuGroup, MenuItem, Notice, SlotFillProvider, createSlotFill,
|
|
15
14
|
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
|
|
16
15
|
__experimentalVStack as VStack } from '@wordpress/components';
|
|
17
16
|
import { useDispatch, useSelect } from '@wordpress/data';
|
|
18
|
-
import { cloneElement, createInterpolateElement, isValidElement,
|
|
17
|
+
import { cloneElement, createInterpolateElement, isValidElement, useLayoutEffect, useRef, useState, forwardRef } from '@wordpress/element';
|
|
19
18
|
import { __ } from '@wordpress/i18n';
|
|
20
19
|
import { category, chevronLeft, moreVertical } from '@wordpress/icons';
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
22
|
* Internal dependencies
|
|
24
23
|
*/
|
|
25
|
-
import { Footer,
|
|
24
|
+
import { Footer, DebugBadge, Button, TabbedNavigation, PluginInstaller, SectionHeader, HandoffMessage, Page, Waiting } from '../';
|
|
26
25
|
import { activeBreadcrumbs, appendSectionName } from './breadcrumbs-select';
|
|
27
26
|
import Router from '../proxied-imports/router';
|
|
28
27
|
import registerStore, { WIZARD_STORE_NAMESPACE } from './store';
|
|
@@ -97,7 +96,10 @@ var ResetHeaderData = function ResetHeaderData() {
|
|
|
97
96
|
var location = useLocation();
|
|
98
97
|
var _useDispatch = useDispatch(WIZARD_STORE_NAMESPACE),
|
|
99
98
|
resetHeaderData = _useDispatch.resetHeaderData;
|
|
100
|
-
|
|
99
|
+
|
|
100
|
+
// Must stay before paint: a passive effect here would run after a section that
|
|
101
|
+
// publishes from a layout effect, wiping the header it just set.
|
|
102
|
+
useLayoutEffect(function () {
|
|
101
103
|
resetHeaderData();
|
|
102
104
|
window.scrollTo(0, 0);
|
|
103
105
|
}, [location.pathname, resetHeaderData]);
|
|
@@ -203,6 +205,7 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
203
205
|
var actions = headerData.actions,
|
|
204
206
|
backNav = headerData.backNav,
|
|
205
207
|
badges = headerData.badges,
|
|
208
|
+
headerFullWidth = headerData.fullWidth,
|
|
206
209
|
sectionDescription = headerData.sectionDescription,
|
|
207
210
|
sectionMenu = headerData.sectionMenu,
|
|
208
211
|
sectionName = headerData.sectionName,
|
|
@@ -307,7 +310,7 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
307
310
|
// describes the state of the whole site, not of the section below it, so it reads
|
|
308
311
|
// as page chrome rather than as content.
|
|
309
312
|
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(
|
|
313
|
+
var inertGatingNotice = (inertGating === null || inertGating === void 0 ? void 0 : inertGating.show) && /*#__PURE__*/_jsx(Notice, {
|
|
311
314
|
status: "warning",
|
|
312
315
|
isDismissible: false,
|
|
313
316
|
className: "newspack-wizard__inert-gating-notice",
|
|
@@ -339,7 +342,7 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
339
342
|
render: function render(routerProps) {
|
|
340
343
|
return /*#__PURE__*/_jsxs("div", {
|
|
341
344
|
className: classnames('newspack-wizard__content', className, {
|
|
342
|
-
'newspack-wizard__content--full-width': section.fullWidth
|
|
345
|
+
'newspack-wizard__content--full-width': headerFullWidth !== null && headerFullWidth !== void 0 ? headerFullWidth : section.fullWidth
|
|
343
346
|
}),
|
|
344
347
|
children: ['function' === typeof renderAboveSections ? renderAboveSections() : null, (sectionTitle || section.title) && /*#__PURE__*/_jsx(SectionHeader, {
|
|
345
348
|
className: "newspack-wizard__section-header",
|
|
@@ -420,9 +423,7 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
420
423
|
}),
|
|
421
424
|
children: [/*#__PURE__*/_jsxs(HashRouter, {
|
|
422
425
|
hashType: "slash",
|
|
423
|
-
children: [
|
|
424
|
-
debugMode: true
|
|
425
|
-
}), /*#__PURE__*/_jsx(WizardHeaderRegion, {
|
|
426
|
+
children: [/*#__PURE__*/_jsx(DebugBadge, {}), /*#__PURE__*/_jsx(WizardHeaderRegion, {
|
|
426
427
|
hideHeader: hideHeader,
|
|
427
428
|
headerText: headerText,
|
|
428
429
|
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,156 @@ 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
|
+
})));
|
|
254
407
|
});
|
|
@@ -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;
|
package/src/action-card/index.js
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* WordPress dependencies
|
|
7
7
|
*/
|
|
8
|
-
import { Draggable, ExternalLink, ToggleControl } from '@wordpress/components';
|
|
9
|
-
import { useEffect, useState } from '@wordpress/element';
|
|
8
|
+
import { Draggable, ExternalLink, Notice, ToggleControl } from '@wordpress/components';
|
|
9
|
+
import { RawHTML, useEffect, useState } from '@wordpress/element';
|
|
10
|
+
import { decodeEntities } from '@wordpress/html-entities';
|
|
10
11
|
import { __ } from '@wordpress/i18n';
|
|
11
12
|
import { Icon, check, chevronDown, chevronUp, dragHandle } from '@wordpress/icons';
|
|
12
13
|
import { Badge } from '@wordpress/ui';
|
|
@@ -14,7 +15,7 @@ import { Badge } from '@wordpress/ui';
|
|
|
14
15
|
/**
|
|
15
16
|
* Internal dependencies
|
|
16
17
|
*/
|
|
17
|
-
import { Button, Card, Grid, Handoff,
|
|
18
|
+
import { Button, Card, Grid, Handoff, Waiting } from '../';
|
|
18
19
|
import { ActionCardProps } from './action-card.d.ts';
|
|
19
20
|
import './style.scss';
|
|
20
21
|
|
|
@@ -23,8 +24,76 @@ import './style.scss';
|
|
|
23
24
|
*/
|
|
24
25
|
import classnames from 'classnames';
|
|
25
26
|
|
|
27
|
+
const NOTIFICATION_LEVELS = [ 'error', 'info', 'success', 'warning' ];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Collect a notification's text, including text nested inside React elements.
|
|
31
|
+
*
|
|
32
|
+
* Segments join with a space so that adjacent elements do not weld together: by the
|
|
33
|
+
* time speak() sees this string the markup that separated them is already gone.
|
|
34
|
+
*
|
|
35
|
+
* @param {*} value Notification content.
|
|
36
|
+
* @return {string} The collected text.
|
|
37
|
+
*/
|
|
38
|
+
const getNotificationText = value => {
|
|
39
|
+
if ( typeof value === 'string' ) {
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
if ( typeof value === 'number' ) {
|
|
43
|
+
return String( value );
|
|
44
|
+
}
|
|
45
|
+
if ( value instanceof Error ) {
|
|
46
|
+
return value.message;
|
|
47
|
+
}
|
|
48
|
+
if ( Array.isArray( value ) ) {
|
|
49
|
+
return value.map( getNotificationText ).join( ' ' );
|
|
50
|
+
}
|
|
51
|
+
return value?.props?.children === undefined ? '' : getNotificationText( value.props.children );
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Derive a plain-text announcement from a notification.
|
|
56
|
+
*
|
|
57
|
+
* Notice defaults spokenMessage to its children and runs renderToString over them
|
|
58
|
+
* during render, which corrupts the hook dispatcher when those children are
|
|
59
|
+
* components. A notification can be any element, so the announcement is always
|
|
60
|
+
* built from its text instead of letting that default apply. Tags in an HTML
|
|
61
|
+
* notification stay in, since speak() strips them itself. Entities are decoded so
|
|
62
|
+
* the announcement matches the text on screen, which getNotificationContent decodes
|
|
63
|
+
* for the same reason.
|
|
64
|
+
*
|
|
65
|
+
* @param {*} notification Notification content.
|
|
66
|
+
* @return {string} Message to announce.
|
|
67
|
+
*/
|
|
68
|
+
const getSpokenNotification = notification => decodeEntities( getNotificationText( notification ) ).replace( /\s+/g, ' ' ).trim();
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Decode a notification's own text for display.
|
|
72
|
+
*
|
|
73
|
+
* React does not decode entities in text children, and notification text is often
|
|
74
|
+
* server-sourced, so a message carrying `’` would otherwise show the entity
|
|
75
|
+
* and announce the character. The HTML branch is left alone: there the browser's
|
|
76
|
+
* parser decodes as it renders.
|
|
77
|
+
*
|
|
78
|
+
* @param {*} value Notification content.
|
|
79
|
+
* @return {*} The content, with its own strings decoded.
|
|
80
|
+
*/
|
|
81
|
+
const getNotificationContent = value => {
|
|
82
|
+
if ( value instanceof Error ) {
|
|
83
|
+
return decodeEntities( value.message );
|
|
84
|
+
}
|
|
85
|
+
if ( typeof value === 'string' ) {
|
|
86
|
+
return decodeEntities( value );
|
|
87
|
+
}
|
|
88
|
+
if ( Array.isArray( value ) ) {
|
|
89
|
+
return value.map( getNotificationContent );
|
|
90
|
+
}
|
|
91
|
+
return value;
|
|
92
|
+
};
|
|
93
|
+
|
|
26
94
|
/**
|
|
27
95
|
* ActionCard component
|
|
96
|
+
*
|
|
28
97
|
* @param {ActionCardProps} props Component props.
|
|
29
98
|
* @return {JSX.Element} ActionCard component.
|
|
30
99
|
*/
|
|
@@ -107,6 +176,7 @@ const ActionCard = ( {
|
|
|
107
176
|
}, [ collapse ] );
|
|
108
177
|
|
|
109
178
|
const hasChildren = notification || children;
|
|
179
|
+
const notificationContent = getNotificationContent( notification );
|
|
110
180
|
const classes = classnames(
|
|
111
181
|
'newspack-action-card',
|
|
112
182
|
simple && 'newspack-card--is-clickable',
|
|
@@ -243,12 +313,15 @@ const ActionCard = ( {
|
|
|
243
313
|
</Button>
|
|
244
314
|
) }
|
|
245
315
|
</div>
|
|
246
|
-
{ notification && (
|
|
316
|
+
{ notification && NOTIFICATION_LEVELS.includes( notificationLevel ) && (
|
|
247
317
|
<div className="newspack-action-card__notification newspack-action-card__region-children">
|
|
248
|
-
{
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
318
|
+
<Notice status={ notificationLevel } isDismissible={ false } spokenMessage={ getSpokenNotification( notification ) }>
|
|
319
|
+
{ notificationHTML && typeof notification === 'string' ? (
|
|
320
|
+
<RawHTML className="newspack-action-card__notification-html">{ notification }</RawHTML>
|
|
321
|
+
) : (
|
|
322
|
+
notificationContent
|
|
323
|
+
) }
|
|
324
|
+
</Notice>
|
|
252
325
|
</div>
|
|
253
326
|
) }
|
|
254
327
|
{ children && ( ( expandable && expanded ) || ! expandable ) ? (
|