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
package/src/notice/style.scss
CHANGED
|
@@ -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
|
|
|
@@ -99,7 +99,7 @@ class PluginToggle extends Component {
|
|
|
99
99
|
toggleChecked={ this.isPluginInstalledAndActive( plugin ) }
|
|
100
100
|
toggleOnChange={ value => this.managePlugin( slug, value ) }
|
|
101
101
|
notification={ error }
|
|
102
|
-
notificationHTML
|
|
102
|
+
notificationHTML
|
|
103
103
|
notificationLevel="error"
|
|
104
104
|
/>
|
|
105
105
|
);
|
|
@@ -6,7 +6,7 @@ import { cloneElement } from '@wordpress/element';
|
|
|
6
6
|
/**
|
|
7
7
|
* Internal dependencies
|
|
8
8
|
*/
|
|
9
|
-
import { Button,
|
|
9
|
+
import { Button, DebugBadge, Handoff, HandoffMessage, TabbedNavigation, Page } from '../';
|
|
10
10
|
import { activeBreadcrumbs } from '../wizard/breadcrumbs-select';
|
|
11
11
|
import { buttonProps } from '../button-props';
|
|
12
12
|
import Router from '../proxied-imports/router';
|
|
@@ -112,7 +112,7 @@ export default function withWizardScreen( WrappedComponent, { hidePrimaryButton,
|
|
|
112
112
|
}
|
|
113
113
|
return (
|
|
114
114
|
<>
|
|
115
|
-
|
|
115
|
+
<DebugBadge />
|
|
116
116
|
{ hideHeader ? (
|
|
117
117
|
// Without the Page shell the tabs still own the content: it
|
|
118
118
|
// renders inside the active tab's panel.
|
|
@@ -9,8 +9,6 @@ import { HashRouter } from 'react-router-dom';
|
|
|
9
9
|
*/
|
|
10
10
|
import withWizardScreen from './';
|
|
11
11
|
|
|
12
|
-
global.newspack_aux_data = { is_debug_mode: false };
|
|
13
|
-
|
|
14
12
|
describe( 'withWizardScreen', () => {
|
|
15
13
|
it( 'falls back to a single headerText breadcrumb when no breadcrumbItems are provided', () => {
|
|
16
14
|
const WrappedComponent = () => <div>Body content</div>;
|
package/src/wizard/index.js
CHANGED
|
@@ -6,26 +6,25 @@ import classnames from 'classnames';
|
|
|
6
6
|
/**
|
|
7
7
|
* WordPress dependencies.
|
|
8
8
|
*/
|
|
9
|
-
// Notice is aliased: `Notice` below is Newspack's own, which this file also uses.
|
|
10
9
|
import {
|
|
11
10
|
DropdownMenu,
|
|
12
11
|
MenuGroup,
|
|
13
12
|
MenuItem,
|
|
14
|
-
Notice
|
|
13
|
+
Notice,
|
|
15
14
|
SlotFillProvider,
|
|
16
15
|
createSlotFill,
|
|
17
16
|
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
|
|
18
17
|
__experimentalVStack as VStack,
|
|
19
18
|
} from '@wordpress/components';
|
|
20
19
|
import { useDispatch, useSelect } from '@wordpress/data';
|
|
21
|
-
import { cloneElement, createInterpolateElement, isValidElement,
|
|
20
|
+
import { cloneElement, createInterpolateElement, isValidElement, useLayoutEffect, useRef, useState, forwardRef } from '@wordpress/element';
|
|
22
21
|
import { __ } from '@wordpress/i18n';
|
|
23
22
|
import { category, chevronLeft, moreVertical } from '@wordpress/icons';
|
|
24
23
|
|
|
25
24
|
/**
|
|
26
25
|
* Internal dependencies
|
|
27
26
|
*/
|
|
28
|
-
import { Footer,
|
|
27
|
+
import { Footer, DebugBadge, Button, TabbedNavigation, PluginInstaller, SectionHeader, HandoffMessage, Page, Waiting } from '../';
|
|
29
28
|
import { activeBreadcrumbs, appendSectionName } from './breadcrumbs-select';
|
|
30
29
|
import Router from '../proxied-imports/router';
|
|
31
30
|
import registerStore, { WIZARD_STORE_NAMESPACE } from './store';
|
|
@@ -92,7 +91,9 @@ const ResetHeaderData = () => {
|
|
|
92
91
|
const location = useLocation();
|
|
93
92
|
const { resetHeaderData } = useDispatch( WIZARD_STORE_NAMESPACE );
|
|
94
93
|
|
|
95
|
-
|
|
94
|
+
// Must stay before paint: a passive effect here would run after a section that
|
|
95
|
+
// publishes from a layout effect, wiping the header it just set.
|
|
96
|
+
useLayoutEffect( () => {
|
|
96
97
|
resetHeaderData();
|
|
97
98
|
window.scrollTo( 0, 0 );
|
|
98
99
|
}, [ location.pathname, resetHeaderData ] );
|
|
@@ -177,6 +178,7 @@ const Wizard = (
|
|
|
177
178
|
actions,
|
|
178
179
|
backNav,
|
|
179
180
|
badges,
|
|
181
|
+
fullWidth: headerFullWidth,
|
|
180
182
|
sectionDescription,
|
|
181
183
|
sectionMenu,
|
|
182
184
|
sectionName,
|
|
@@ -269,7 +271,7 @@ const Wizard = (
|
|
|
269
271
|
// as page chrome rather than as content.
|
|
270
272
|
const inertGating = window.newspack_aux_data?.inert_gating;
|
|
271
273
|
const inertGatingNotice = inertGating?.show && (
|
|
272
|
-
<
|
|
274
|
+
<Notice status="warning" isDismissible={ false } className="newspack-wizard__inert-gating-notice">
|
|
273
275
|
{ /* The conversion map takes childless elements and fills them from the
|
|
274
276
|
translated string, so jsx-a11y can't see the content they end up with. */ }
|
|
275
277
|
{ interpolateOrPlainText( inertGating.message, {
|
|
@@ -279,7 +281,7 @@ const Wizard = (
|
|
|
279
281
|
/* eslint-enable jsx-a11y/anchor-has-content */
|
|
280
282
|
strong: <strong />,
|
|
281
283
|
} ) }
|
|
282
|
-
</
|
|
284
|
+
</Notice>
|
|
283
285
|
);
|
|
284
286
|
|
|
285
287
|
const content = (
|
|
@@ -303,7 +305,7 @@ const Wizard = (
|
|
|
303
305
|
render={ routerProps => (
|
|
304
306
|
<div
|
|
305
307
|
className={ classnames( 'newspack-wizard__content', className, {
|
|
306
|
-
'newspack-wizard__content--full-width': section.fullWidth,
|
|
308
|
+
'newspack-wizard__content--full-width': headerFullWidth ?? section.fullWidth,
|
|
307
309
|
} ) }
|
|
308
310
|
>
|
|
309
311
|
{ 'function' === typeof renderAboveSections ? renderAboveSections() : null }
|
|
@@ -403,7 +405,7 @@ const Wizard = (
|
|
|
403
405
|
} ) }
|
|
404
406
|
>
|
|
405
407
|
<HashRouter hashType="slash">
|
|
406
|
-
|
|
408
|
+
<DebugBadge />
|
|
407
409
|
<WizardHeaderRegion
|
|
408
410
|
hideHeader={ hideHeader }
|
|
409
411
|
headerText={ headerText }
|
package/src/wizard/index.test.js
CHANGED
|
@@ -7,19 +7,22 @@ import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
|
|
|
7
7
|
* WordPress dependencies.
|
|
8
8
|
*/
|
|
9
9
|
import apiFetch from '@wordpress/api-fetch';
|
|
10
|
+
import { select, useDispatch } from '@wordpress/data';
|
|
11
|
+
import { useLayoutEffect, useState } from '@wordpress/element';
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* Internal dependencies.
|
|
13
15
|
*/
|
|
14
16
|
import Wizard from './';
|
|
15
17
|
import { useWizardData } from './store/utils';
|
|
18
|
+
import { WIZARD_STORE_NAMESPACE } from './store';
|
|
16
19
|
|
|
17
20
|
jest.mock( '@wordpress/api-fetch', () => jest.fn() );
|
|
18
21
|
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
window.newspack_aux_data = { is_debug_mode: false };
|
|
22
|
+
// Localized onto every real wizard screen; the footer's ExternalLink needs a
|
|
23
|
+
// string href.
|
|
22
24
|
window.newspack_urls = { support: 'https://help.newspack.com/' };
|
|
25
|
+
window.scrollTo = jest.fn();
|
|
23
26
|
|
|
24
27
|
const SETTINGS = { minimumDonation: '5' };
|
|
25
28
|
|
|
@@ -154,3 +157,93 @@ describe( 'Wizard', () => {
|
|
|
154
157
|
expect( counts.wizard ).toBe( 0 );
|
|
155
158
|
} );
|
|
156
159
|
} );
|
|
160
|
+
|
|
161
|
+
const NarrowingSection = () => {
|
|
162
|
+
const { setHeaderData } = useDispatch( WIZARD_STORE_NAMESPACE );
|
|
163
|
+
useLayoutEffect( () => {
|
|
164
|
+
setHeaderData( { fullWidth: false } );
|
|
165
|
+
}, [ setHeaderData ] );
|
|
166
|
+
return <div>Narrowing section</div>;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const RecoveringSection = () => {
|
|
170
|
+
const { setHeaderData } = useDispatch( WIZARD_STORE_NAMESPACE );
|
|
171
|
+
const [ failed, setFailed ] = useState( true );
|
|
172
|
+
useLayoutEffect( () => {
|
|
173
|
+
setHeaderData( { fullWidth: failed ? false : undefined } );
|
|
174
|
+
}, [ setHeaderData, failed ] );
|
|
175
|
+
return <button onClick={ () => setFailed( false ) }>Retry</button>;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Two sections, because that is what mounts ResetHeaderData: a single-section
|
|
179
|
+
// wizard never exercises the reset these overrides have to survive.
|
|
180
|
+
const widthSections = renderSection => [
|
|
181
|
+
{ label: 'List', path: '/', exact: true, fullWidth: true, render: renderSection },
|
|
182
|
+
{ label: 'Other', path: '/other', render: () => <div>Other section</div> },
|
|
183
|
+
];
|
|
184
|
+
|
|
185
|
+
describe( 'Wizard content width', () => {
|
|
186
|
+
beforeEach( () => {
|
|
187
|
+
apiFetch.mockReset();
|
|
188
|
+
} );
|
|
189
|
+
|
|
190
|
+
it( 'renders full-width when the section declares it and nothing overrides it', async () => {
|
|
191
|
+
const { container } = render(
|
|
192
|
+
<Wizard
|
|
193
|
+
headerText="Test wizard"
|
|
194
|
+
sections={ widthSections( () => (
|
|
195
|
+
<div>List content</div>
|
|
196
|
+
) ) }
|
|
197
|
+
/>
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
expect( await screen.findByText( 'List content' ) ).toBeInTheDocument();
|
|
201
|
+
expect( container.querySelector( '.newspack-wizard__content' ) ).toHaveClass( 'newspack-wizard__content--full-width' );
|
|
202
|
+
} );
|
|
203
|
+
|
|
204
|
+
it( 'falls back to the standard width when a section overrides fullWidth before paint', async () => {
|
|
205
|
+
const { container } = render(
|
|
206
|
+
<Wizard
|
|
207
|
+
headerText="Test wizard"
|
|
208
|
+
sections={ widthSections( () => (
|
|
209
|
+
<NarrowingSection />
|
|
210
|
+
) ) }
|
|
211
|
+
/>
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
expect( await screen.findByText( 'Narrowing section' ) ).toBeInTheDocument();
|
|
215
|
+
expect( container.querySelector( '.newspack-wizard__content' ) ).not.toHaveClass( 'newspack-wizard__content--full-width' );
|
|
216
|
+
} );
|
|
217
|
+
|
|
218
|
+
it( 'restores the declared width when the section clears its override', async () => {
|
|
219
|
+
const { container } = render(
|
|
220
|
+
<Wizard
|
|
221
|
+
headerText="Test wizard"
|
|
222
|
+
sections={ widthSections( () => (
|
|
223
|
+
<RecoveringSection />
|
|
224
|
+
) ) }
|
|
225
|
+
/>
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
const retry = await screen.findByRole( 'button', { name: 'Retry' } );
|
|
229
|
+
expect( container.querySelector( '.newspack-wizard__content' ) ).not.toHaveClass( 'newspack-wizard__content--full-width' );
|
|
230
|
+
|
|
231
|
+
fireEvent.click( retry );
|
|
232
|
+
|
|
233
|
+
await waitFor( () => expect( container.querySelector( '.newspack-wizard__content' ) ).toHaveClass( 'newspack-wizard__content--full-width' ) );
|
|
234
|
+
} );
|
|
235
|
+
|
|
236
|
+
it( 'keeps a section header published from a layout effect through the mount reset', async () => {
|
|
237
|
+
render(
|
|
238
|
+
<Wizard
|
|
239
|
+
headerText="Test wizard"
|
|
240
|
+
sections={ widthSections( () => (
|
|
241
|
+
<NarrowingSection />
|
|
242
|
+
) ) }
|
|
243
|
+
/>
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
expect( await screen.findByText( 'Narrowing section' ) ).toBeInTheDocument();
|
|
247
|
+
expect( select( WIZARD_STORE_NAMESPACE ).getHeaderData().fullWidth ).toBe( false );
|
|
248
|
+
} );
|
|
249
|
+
} );
|
|
@@ -16,6 +16,8 @@ import { createAction } from './utils.js';
|
|
|
16
16
|
export const WIZARD_STORE_NAMESPACE = 'newspack/wizards';
|
|
17
17
|
|
|
18
18
|
const DEFAULT_STATE = {
|
|
19
|
+
// `fullWidth` is deliberately absent: a default here would narrow every
|
|
20
|
+
// full-width section on reset, since Wizard only falls back when it is unset.
|
|
19
21
|
headerData: {
|
|
20
22
|
actions: [],
|
|
21
23
|
backNav: '',
|