newspack-components 4.10.0 → 4.12.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/DEVELOPMENT.md +80 -38
- package/dist/cjs/breadcrumbs/index.js +1 -0
- package/dist/cjs/breadcrumbs/style.scss +3 -10
- package/dist/cjs/card/style-core.scss +1 -1
- package/dist/cjs/card-sortable-list/index.js +23 -12
- package/dist/cjs/card-sortable-list/index.test.js +21 -0
- package/dist/cjs/card-sortable-list/style.scss +8 -0
- package/dist/cjs/drawer/body.js +4 -6
- package/dist/cjs/drawer/content.js +7 -37
- package/dist/cjs/drawer/footer.js +10 -1
- package/dist/cjs/drawer/header.js +9 -1
- package/dist/cjs/drawer/index.test.js +3 -4
- package/dist/cjs/drawer/slots.test.js +25 -67
- package/dist/cjs/drawer/style.scss +0 -18
- package/dist/cjs/index.js +14 -0
- package/dist/cjs/page/index.js +10 -2
- package/dist/cjs/page/style.scss +24 -2
- package/dist/cjs/reorder-modal/index.js +521 -0
- package/dist/cjs/reorder-modal/index.test.js +1223 -0
- package/dist/cjs/reorder-modal/style.scss +114 -0
- package/dist/cjs/tabbed-navigation/style.scss +5 -0
- package/dist/cjs/tooltip-badge/index.js +50 -0
- package/dist/cjs/tooltip-badge/index.test.js +30 -0
- package/dist/cjs/wizard/index.js +21 -8
- package/dist/cjs/wizard/index.test.js +78 -0
- package/dist/cjs/wizard/store/index.js +2 -1
- package/dist/esm/breadcrumbs/index.js +1 -0
- package/dist/esm/breadcrumbs/style.scss +3 -10
- package/dist/esm/card/style-core.scss +1 -1
- package/dist/esm/card-sortable-list/index.js +25 -13
- package/dist/esm/card-sortable-list/index.test.js +21 -0
- package/dist/esm/card-sortable-list/style.scss +8 -0
- package/dist/esm/drawer/body.js +4 -5
- package/dist/esm/drawer/content.js +7 -36
- package/dist/esm/drawer/footer.js +10 -1
- package/dist/esm/drawer/header.js +9 -1
- package/dist/esm/drawer/index.test.js +3 -4
- package/dist/esm/drawer/slots.test.js +25 -67
- package/dist/esm/drawer/style.scss +0 -18
- package/dist/esm/index.js +2 -0
- package/dist/esm/page/index.js +10 -2
- package/dist/esm/page/style.scss +24 -2
- package/dist/esm/reorder-modal/index.js +514 -0
- package/dist/esm/reorder-modal/index.test.js +1224 -0
- package/dist/esm/reorder-modal/style.scss +114 -0
- package/dist/esm/tabbed-navigation/style.scss +5 -0
- package/dist/esm/tooltip-badge/index.js +43 -0
- package/dist/esm/tooltip-badge/index.test.js +26 -0
- package/dist/esm/wizard/index.js +23 -12
- package/dist/esm/wizard/index.test.js +78 -0
- package/dist/esm/wizard/store/index.js +2 -1
- package/package.json +2 -2
- package/src/breadcrumbs/index.js +1 -1
- package/src/breadcrumbs/style.scss +3 -10
- package/src/card/style-core.scss +1 -1
- package/src/card-form/README.md +2 -2
- package/src/card-sortable-list/index.test.js +13 -0
- package/src/card-sortable-list/index.tsx +31 -12
- package/src/card-sortable-list/style.scss +8 -0
- package/src/drawer/README.md +10 -16
- package/src/drawer/body.tsx +4 -5
- package/src/drawer/content.tsx +7 -33
- package/src/drawer/footer.tsx +8 -1
- package/src/drawer/header.tsx +8 -1
- package/src/drawer/index.test.js +3 -4
- package/src/drawer/slots.test.js +14 -48
- package/src/drawer/style.scss +0 -18
- package/src/drawer/types.ts +8 -3
- package/src/index.js +2 -0
- package/src/page/index.js +7 -3
- package/src/page/style.scss +24 -2
- package/src/reorder-modal/index.js +484 -0
- package/src/reorder-modal/index.test.js +566 -0
- package/src/reorder-modal/style.scss +114 -0
- package/src/tabbed-navigation/style.scss +5 -0
- package/src/tooltip-badge/index.test.js +24 -0
- package/src/tooltip-badge/index.tsx +40 -0
- package/src/wizard/index.js +25 -14
- package/src/wizard/index.test.js +38 -0
- package/src/wizard/store/index.js +1 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
2
|
+
@use "~@wordpress/base-styles/mixins" as wp-mixins;
|
|
3
|
+
@use "~@wordpress/base-styles/variables" as wp-vars;
|
|
4
|
+
|
|
5
|
+
.newspack-reorder-modal {
|
|
6
|
+
&__body {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
min-height: calc(#{wp-vars.$grid-unit} * 23);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
&__loading {
|
|
13
|
+
align-items: center;
|
|
14
|
+
display: flex;
|
|
15
|
+
flex: 1;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
&__notice {
|
|
20
|
+
margin: 0 0 wp-vars.$grid-unit-10;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&__list {
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-direction: column;
|
|
26
|
+
gap: wp-vars.$grid-unit-10;
|
|
27
|
+
list-style: none;
|
|
28
|
+
margin: 0;
|
|
29
|
+
padding: 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&__item {
|
|
33
|
+
--newspack-reorder-modal-divider: #{wp-colors.$gray-100};
|
|
34
|
+
--wp-ui-card-padding: #{wp-vars.$grid-unit-15};
|
|
35
|
+
|
|
36
|
+
align-items: stretch;
|
|
37
|
+
cursor: grab;
|
|
38
|
+
flex-direction: row;
|
|
39
|
+
margin: 0;
|
|
40
|
+
|
|
41
|
+
&:focus-within,
|
|
42
|
+
&:hover {
|
|
43
|
+
--newspack-reorder-modal-divider: #{wp-colors.$gray-300};
|
|
44
|
+
|
|
45
|
+
border-color: wp-colors.$gray-300;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&.is-dragging {
|
|
49
|
+
cursor: grabbing;
|
|
50
|
+
opacity: 0.5;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&__grip {
|
|
55
|
+
align-items: center;
|
|
56
|
+
color: wp-colors.$gray-700;
|
|
57
|
+
display: flex;
|
|
58
|
+
padding-left: wp-vars.$grid-unit-05;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&__move {
|
|
62
|
+
align-items: center;
|
|
63
|
+
border-right: 1px solid var(--newspack-reorder-modal-divider);
|
|
64
|
+
display: flex;
|
|
65
|
+
flex-direction: column;
|
|
66
|
+
padding: wp-vars.$grid-unit-05;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
&__content {
|
|
70
|
+
align-items: center;
|
|
71
|
+
align-self: center;
|
|
72
|
+
display: flex;
|
|
73
|
+
flex: 1;
|
|
74
|
+
gap: wp-vars.$grid-unit-10;
|
|
75
|
+
min-width: 0;
|
|
76
|
+
padding-block-end: var(--wp-ui-card-padding);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&__title {
|
|
80
|
+
@include wp-mixins.heading-large();
|
|
81
|
+
|
|
82
|
+
min-width: 0;
|
|
83
|
+
overflow: hidden;
|
|
84
|
+
text-overflow: ellipsis;
|
|
85
|
+
white-space: nowrap;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&__badge {
|
|
89
|
+
display: flex;
|
|
90
|
+
flex-shrink: 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
&__toggle {
|
|
94
|
+
align-items: center;
|
|
95
|
+
display: flex;
|
|
96
|
+
padding-inline-end: wp-vars.$grid-unit-15;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
&__description {
|
|
100
|
+
margin: 0 0 wp-vars.$grid-unit-20;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
&__item.is-off &__title {
|
|
104
|
+
color: wp-colors.$gray-700;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
&__footer {
|
|
108
|
+
display: flex;
|
|
109
|
+
gap: wp-vars.$grid-unit-10;
|
|
110
|
+
justify-content: flex-end;
|
|
111
|
+
margin-top: auto;
|
|
112
|
+
padding-top: wp-vars.$grid-unit-30;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -21,6 +21,11 @@
|
|
|
21
21
|
/* stylelint-disable-next-line plugin-wpds/no-setting-wpds-custom-properties -- deliberate Newspack brand override of the indicator token. */
|
|
22
22
|
--wpds-color-stroke-interactive-neutral-strong: #{np-colors.$primary-600};
|
|
23
23
|
|
|
24
|
+
[role="tablist"] {
|
|
25
|
+
max-width: 100%;
|
|
26
|
+
overflow-x: auto;
|
|
27
|
+
}
|
|
28
|
+
|
|
24
29
|
a[role="tab"] {
|
|
25
30
|
text-decoration: none;
|
|
26
31
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useInstanceId } from '@wordpress/compose';
|
|
5
|
+
import { Badge, Tooltip } from '@wordpress/ui';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Internal dependencies
|
|
9
|
+
*/
|
|
10
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
11
|
+
/**
|
|
12
|
+
* A badge whose tooltip explains it. The tooltip serves mouse and keyboard users;
|
|
13
|
+
* screen readers get the same text as the trigger's description, which keeps it
|
|
14
|
+
* out of the accessible name of a heading the badge sits in.
|
|
15
|
+
*/
|
|
16
|
+
var _TooltipBadge = function TooltipBadge(_ref) {
|
|
17
|
+
var label = _ref.label,
|
|
18
|
+
tooltip = _ref.tooltip,
|
|
19
|
+
_ref$intent = _ref.intent,
|
|
20
|
+
intent = _ref$intent === void 0 ? 'none' : _ref$intent;
|
|
21
|
+
var descriptionId = useInstanceId(_TooltipBadge, 'newspack-tooltip-badge');
|
|
22
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
23
|
+
children: [/*#__PURE__*/_jsxs(Tooltip.Root, {
|
|
24
|
+
children: [/*#__PURE__*/_jsx(Tooltip.Trigger, {
|
|
25
|
+
render: /*#__PURE__*/_jsx("span", {
|
|
26
|
+
tabIndex: 0,
|
|
27
|
+
"aria-describedby": descriptionId
|
|
28
|
+
}),
|
|
29
|
+
children: /*#__PURE__*/_jsx(Badge, {
|
|
30
|
+
intent: intent,
|
|
31
|
+
children: label
|
|
32
|
+
})
|
|
33
|
+
}), /*#__PURE__*/_jsx(Tooltip.Popup, {
|
|
34
|
+
children: tooltip
|
|
35
|
+
})]
|
|
36
|
+
}), /*#__PURE__*/_jsx("span", {
|
|
37
|
+
id: descriptionId,
|
|
38
|
+
hidden: true,
|
|
39
|
+
children: tooltip
|
|
40
|
+
})]
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
export default _TooltipBadge;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { render, screen } from '@testing-library/react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import TooltipBadge from './';
|
|
10
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
+
describe('TooltipBadge', function () {
|
|
12
|
+
it('describes its focusable trigger with the tooltip text, keeping it out of a surrounding heading name', function () {
|
|
13
|
+
render(/*#__PURE__*/_jsxs("h3", {
|
|
14
|
+
children: ["Registration wall", /*#__PURE__*/_jsx(TooltipBadge, {
|
|
15
|
+
label: "Overrides paid access",
|
|
16
|
+
tooltip: "This grants registered readers access.",
|
|
17
|
+
intent: "low"
|
|
18
|
+
})]
|
|
19
|
+
}));
|
|
20
|
+
expect(screen.getByRole('heading', {
|
|
21
|
+
name: 'Registration wall Overrides paid access'
|
|
22
|
+
})).toBeInTheDocument();
|
|
23
|
+
var trigger = screen.getByText('Overrides paid access').closest('[tabindex="0"]');
|
|
24
|
+
expect(trigger).toHaveAccessibleDescription('This grants registered readers access.');
|
|
25
|
+
});
|
|
26
|
+
});
|
package/dist/esm/wizard/index.js
CHANGED
|
@@ -13,9 +13,8 @@ import classnames from 'classnames';
|
|
|
13
13
|
/**
|
|
14
14
|
* WordPress dependencies.
|
|
15
15
|
*/
|
|
16
|
-
import { DropdownMenu, MenuGroup, MenuItem, Notice, SlotFillProvider, createSlotFill
|
|
17
|
-
|
|
18
|
-
__experimentalVStack as VStack } from '@wordpress/components';
|
|
16
|
+
import { DropdownMenu, MenuGroup, MenuItem, Notice, SlotFillProvider, createSlotFill } from '@wordpress/components';
|
|
17
|
+
import { Stack } from '@wordpress/ui';
|
|
19
18
|
import { useDispatch, useSelect } from '@wordpress/data';
|
|
20
19
|
import { cloneElement, createInterpolateElement, isValidElement, useLayoutEffect, useRef, useState, forwardRef } from '@wordpress/element';
|
|
21
20
|
import { __ } from '@wordpress/i18n';
|
|
@@ -30,7 +29,7 @@ import Router from '../proxied-imports/router';
|
|
|
30
29
|
import registerStore, { WIZARD_STORE_NAMESPACE } from './store';
|
|
31
30
|
import WizardSnackbar from './components/WizardSnackbar';
|
|
32
31
|
import WizardError from './components/WizardError';
|
|
33
|
-
import { jsx as _jsx,
|
|
32
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
34
33
|
registerStore();
|
|
35
34
|
|
|
36
35
|
/**
|
|
@@ -115,12 +114,13 @@ var ResetHeaderData = function ResetHeaderData() {
|
|
|
115
114
|
* can read the current route and derive the active-tab breadcrumb.
|
|
116
115
|
*/
|
|
117
116
|
var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
|
|
118
|
-
var _activeSection;
|
|
117
|
+
var _activeSection, _activeSection2;
|
|
119
118
|
var hideHeader = _ref.hideHeader,
|
|
120
119
|
headerText = _ref.headerText,
|
|
121
120
|
sections = _ref.sections,
|
|
122
121
|
sectionName = _ref.sectionName,
|
|
123
122
|
subTitle = _ref.subTitle,
|
|
123
|
+
headerSubTitle = _ref.headerSubTitle,
|
|
124
124
|
actions = _ref.actions,
|
|
125
125
|
wizardTabbedNavigation = _ref.tabbedNavigation,
|
|
126
126
|
children = _ref.children;
|
|
@@ -150,11 +150,19 @@ var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
|
|
|
150
150
|
break;
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
+
|
|
154
|
+
// WizardError normally mounts inside the tab bar, so a route without one renders it itself.
|
|
153
155
|
} catch (err) {
|
|
154
156
|
_iterator.e(err);
|
|
155
157
|
} finally {
|
|
156
158
|
_iterator.f();
|
|
157
159
|
}
|
|
160
|
+
if ((_activeSection = activeSection(sections, pathname)) !== null && _activeSection !== void 0 && _activeSection.hideTabbedNavigation && tabbedNavigation) {
|
|
161
|
+
tabbedNavigation = null;
|
|
162
|
+
children = /*#__PURE__*/_jsxs(_Fragment, {
|
|
163
|
+
children: [/*#__PURE__*/_jsx(WizardError, {}), children]
|
|
164
|
+
});
|
|
165
|
+
}
|
|
158
166
|
if (hideHeader) {
|
|
159
167
|
// Without the Page shell the tabs still own the content: it renders
|
|
160
168
|
// inside the active tab's panel.
|
|
@@ -174,10 +182,10 @@ var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
|
|
|
174
182
|
// Append any render-time leaf crumb(s) the section supplied via
|
|
175
183
|
// headerData.sectionName (deduped against the current trailing label).
|
|
176
184
|
breadcrumbItems = appendSectionName(breadcrumbItems, sectionName);
|
|
177
|
-
var sectionSubTitle = (
|
|
185
|
+
var sectionSubTitle = (_activeSection2 = activeSection(sections, pathname)) === null || _activeSection2 === void 0 ? void 0 : _activeSection2.subHeaderText;
|
|
178
186
|
return /*#__PURE__*/_jsx(Page, {
|
|
179
187
|
breadcrumbItems: breadcrumbItems,
|
|
180
|
-
subTitle: sectionSubTitle !== null && sectionSubTitle !== void 0 ? sectionSubTitle : subTitle,
|
|
188
|
+
subTitle: headerSubTitle || (sectionSubTitle !== null && sectionSubTitle !== void 0 ? sectionSubTitle : subTitle),
|
|
181
189
|
actions: actions,
|
|
182
190
|
tabbedNavigation: tabbedNavigation,
|
|
183
191
|
children: children
|
|
@@ -190,7 +198,7 @@ var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
|
|
|
190
198
|
* @property {string} [subHeaderText] The sub-header text, optional.
|
|
191
199
|
* @property {string} [apiSlug] The API slug, optional.
|
|
192
200
|
* @property {string} [className] CSS classes, optional.
|
|
193
|
-
* @property {any[]} sections Array of sections. A section's own `subHeaderText` replaces the wizard's while it is active.
|
|
201
|
+
* @property {any[]} sections Array of sections. A section's own `subHeaderText` replaces the wizard's while it is active, and `hideTabbedNavigation` hides the tab bar on its route.
|
|
194
202
|
* Its optional `tabbedNavigation( params )` returns the tab items shown while its route matches.
|
|
195
203
|
* @property {boolean} [hasSimpleFooter] Indicates if a simple footer is used, optional.
|
|
196
204
|
* @property {() => void} [renderAboveSections] Function to render content above sections, optional.
|
|
@@ -248,7 +256,8 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
248
256
|
sectionSize = headerData.sectionSize,
|
|
249
257
|
sectionTitle = headerData.sectionTitle,
|
|
250
258
|
sectionPrimaryAction = headerData.sectionPrimaryAction,
|
|
251
|
-
sectionSecondaryAction = headerData.sectionSecondaryAction
|
|
259
|
+
sectionSecondaryAction = headerData.sectionSecondaryAction,
|
|
260
|
+
headerSubTitle = headerData.subTitle;
|
|
252
261
|
var mainActions = actions === null || actions === void 0 ? void 0 : actions.filter(function (action) {
|
|
253
262
|
return action.type === 'primary' || action.type === 'secondary';
|
|
254
263
|
});
|
|
@@ -311,9 +320,10 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
311
320
|
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
312
321
|
children: [!pluginRequirementsKnown && /*#__PURE__*/_jsx("div", {
|
|
313
322
|
className: "newspack-wizard__loader",
|
|
314
|
-
children: /*#__PURE__*/_jsxs(
|
|
315
|
-
|
|
316
|
-
|
|
323
|
+
children: /*#__PURE__*/_jsxs(Stack, {
|
|
324
|
+
direction: "column",
|
|
325
|
+
align: "center",
|
|
326
|
+
gap: "sm",
|
|
317
327
|
children: [/*#__PURE__*/_jsx(Waiting, {
|
|
318
328
|
noMargin: true
|
|
319
329
|
}), /*#__PURE__*/_jsx("strong", {
|
|
@@ -467,6 +477,7 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
467
477
|
sections: routedSections,
|
|
468
478
|
sectionName: sectionName,
|
|
469
479
|
subTitle: subHeaderText,
|
|
480
|
+
headerSubTitle: headerSubTitle,
|
|
470
481
|
actions: headerActions,
|
|
471
482
|
tabbedNavigation: tabbedNavigation,
|
|
472
483
|
children: content
|
|
@@ -550,4 +550,82 @@ describe('Wizard section subtitle', function () {
|
|
|
550
550
|
}
|
|
551
551
|
}, _callee1);
|
|
552
552
|
})));
|
|
553
|
+
});
|
|
554
|
+
describe('Wizard tab bar on hidden routes', function () {
|
|
555
|
+
beforeEach(function () {
|
|
556
|
+
apiFetch.mockReset();
|
|
557
|
+
apiFetch.mockResolvedValue({});
|
|
558
|
+
});
|
|
559
|
+
it('hides the tab bar on a hideTabbedNavigation route and restores it on a tab route', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee10() {
|
|
560
|
+
var _t10, _t11, _t12;
|
|
561
|
+
return _regenerator().w(function (_context10) {
|
|
562
|
+
while (1) switch (_context10.n) {
|
|
563
|
+
case 0:
|
|
564
|
+
window.location.hash = '#/list';
|
|
565
|
+
render(/*#__PURE__*/_jsx(Wizard, {
|
|
566
|
+
headerText: "Test wizard",
|
|
567
|
+
sections: [{
|
|
568
|
+
label: 'List',
|
|
569
|
+
path: '/list',
|
|
570
|
+
exact: true,
|
|
571
|
+
render: function render() {
|
|
572
|
+
return /*#__PURE__*/_jsx("div", {
|
|
573
|
+
children: "List view"
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
}, {
|
|
577
|
+
label: 'Other',
|
|
578
|
+
path: '/other',
|
|
579
|
+
exact: true,
|
|
580
|
+
render: function render() {
|
|
581
|
+
return /*#__PURE__*/_jsx("div", {
|
|
582
|
+
children: "Other view"
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
}, {
|
|
586
|
+
path: '/list/:id',
|
|
587
|
+
isHidden: true,
|
|
588
|
+
hideTabbedNavigation: true,
|
|
589
|
+
render: function render() {
|
|
590
|
+
return /*#__PURE__*/_jsx("div", {
|
|
591
|
+
children: "Item view"
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
}]
|
|
595
|
+
}));
|
|
596
|
+
_t10 = expect;
|
|
597
|
+
_context10.n = 1;
|
|
598
|
+
return screen.findByText('List view');
|
|
599
|
+
case 1:
|
|
600
|
+
_t10(_context10.v).toBeInTheDocument();
|
|
601
|
+
expect(screen.getByRole('tab', {
|
|
602
|
+
name: 'Other'
|
|
603
|
+
})).toBeInTheDocument();
|
|
604
|
+
act(function () {
|
|
605
|
+
window.location.hash = '#/list/esp';
|
|
606
|
+
window.dispatchEvent(new HashChangeEvent('hashchange'));
|
|
607
|
+
});
|
|
608
|
+
_t11 = expect;
|
|
609
|
+
_context10.n = 2;
|
|
610
|
+
return screen.findByText('Item view');
|
|
611
|
+
case 2:
|
|
612
|
+
_t11(_context10.v).toBeInTheDocument();
|
|
613
|
+
expect(screen.queryByRole('tab')).not.toBeInTheDocument();
|
|
614
|
+
act(function () {
|
|
615
|
+
window.location.hash = '#/list';
|
|
616
|
+
window.dispatchEvent(new HashChangeEvent('hashchange'));
|
|
617
|
+
});
|
|
618
|
+
_t12 = expect;
|
|
619
|
+
_context10.n = 3;
|
|
620
|
+
return screen.findByText('List view');
|
|
621
|
+
case 3:
|
|
622
|
+
_t12(_context10.v).toBeInTheDocument();
|
|
623
|
+
expect(screen.getByRole('tab', {
|
|
624
|
+
name: 'Other'
|
|
625
|
+
})).toBeInTheDocument();
|
|
626
|
+
case 4:
|
|
627
|
+
return _context10.a(2);
|
|
628
|
+
}
|
|
629
|
+
}, _callee10);
|
|
630
|
+
})));
|
|
553
631
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newspack-components",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.12.0-alpha.1",
|
|
4
4
|
"description": "Newspack design system components",
|
|
5
5
|
"author": "Automattic",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"classnames": "^2.3.1",
|
|
31
31
|
"lodash": "^4.17.21",
|
|
32
32
|
"moment-range": "^3.1.1",
|
|
33
|
-
"newspack-icons": "1.
|
|
33
|
+
"newspack-icons": "1.3.0-alpha.1",
|
|
34
34
|
"qs": "^6.15.2",
|
|
35
35
|
"react-router-dom": "^5.3.4",
|
|
36
36
|
"@babel/runtime": "^7.29.7",
|
package/src/breadcrumbs/index.js
CHANGED
|
@@ -80,7 +80,7 @@ const Breadcrumbs = ( { items = [] } ) => {
|
|
|
80
80
|
|
|
81
81
|
return (
|
|
82
82
|
<nav aria-label={ __( 'Breadcrumbs', 'newspack-plugin' ) }>
|
|
83
|
-
<Stack render={ <ul /> } direction="row" align="center" className="newspack-breadcrumbs__list">
|
|
83
|
+
<Stack render={ <ul /> } direction="row" align="center" wrap="wrap" className="newspack-breadcrumbs__list">
|
|
84
84
|
{ preceding.map( ( item, index ) => (
|
|
85
85
|
<li key={ item.url || index }>
|
|
86
86
|
{ item.url ? (
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
padding: 0;
|
|
8
8
|
|
|
9
9
|
> li {
|
|
10
|
-
flex-shrink: 0;
|
|
11
10
|
margin: 0;
|
|
11
|
+
min-width: 0;
|
|
12
12
|
|
|
13
13
|
a {
|
|
14
14
|
color: wp-colors.$gray-900;
|
|
@@ -20,11 +20,6 @@
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
> li:last-child {
|
|
25
|
-
flex-shrink: 1;
|
|
26
|
-
min-width: 0;
|
|
27
|
-
}
|
|
28
23
|
}
|
|
29
24
|
|
|
30
25
|
.newspack-breadcrumbs__count {
|
|
@@ -39,9 +34,7 @@
|
|
|
39
34
|
}
|
|
40
35
|
|
|
41
36
|
.newspack-breadcrumbs__list h1.newspack-breadcrumbs__current {
|
|
42
|
-
overflow:
|
|
43
|
-
text-overflow: ellipsis;
|
|
44
|
-
white-space: nowrap;
|
|
37
|
+
overflow-wrap: break-word;
|
|
45
38
|
padding: 0;
|
|
46
|
-
line-height:
|
|
39
|
+
line-height: var(--wpds-typography-line-height-md, #{wp-vars.$grid-unit-30});
|
|
47
40
|
}
|
package/src/card/style-core.scss
CHANGED
package/src/card-form/README.md
CHANGED
|
@@ -4,8 +4,8 @@ A card component for presenting a named setting or feature with an expandable in
|
|
|
4
4
|
|
|
5
5
|
## Layout rules
|
|
6
6
|
|
|
7
|
-
- Stack multiple `CardForm` cards inside a `<
|
|
8
|
-
- The `actions` slot sits to the right of the badge. Keep it to one button; if you need multiple actions,
|
|
7
|
+
- Stack multiple `CardForm` cards inside a `<Stack direction="column" gap="lg">` from `@wordpress/ui`; they are designed to appear as a list.
|
|
8
|
+
- The `actions` slot sits to the right of the badge. Keep it to one button; if you need multiple actions, wrap them in a `<Stack gap="sm" align="center">` from `@wordpress/ui`.
|
|
9
9
|
- The form body (`children`) is only mounted when `isOpen` is `true`.
|
|
10
10
|
|
|
11
11
|
## States
|
|
@@ -26,4 +26,17 @@ describe( 'CardSortableList', () => {
|
|
|
26
26
|
// An unguarded Badge would still emit an empty span, so assert on element children.
|
|
27
27
|
expect( container.querySelector( 'h3' ).children ).toHaveLength( 0 );
|
|
28
28
|
} );
|
|
29
|
+
|
|
30
|
+
it( 'names each toggle after its item', () => {
|
|
31
|
+
render(
|
|
32
|
+
<CardSortableList
|
|
33
|
+
items={ [
|
|
34
|
+
{ id: 1, title: 'Homepage', toggleChecked: true, onToggleChange: () => {} },
|
|
35
|
+
{ id: 2, title: 'About', toggleChecked: false, onToggleChange: () => {} },
|
|
36
|
+
] }
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
expect( screen.getByRole( 'checkbox', { name: 'Homepage' } ) ).toBeChecked();
|
|
40
|
+
expect( screen.getByRole( 'checkbox', { name: 'About' } ) ).not.toBeChecked();
|
|
41
|
+
} );
|
|
29
42
|
} );
|
|
@@ -2,25 +2,26 @@
|
|
|
2
2
|
* Card - Sortable list component.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* External dependencies
|
|
7
|
+
*/
|
|
8
|
+
import classNames from 'classnames';
|
|
9
|
+
|
|
5
10
|
/**
|
|
6
11
|
* WordPress dependencies.
|
|
7
12
|
*/
|
|
8
|
-
import { Disabled, Draggable
|
|
13
|
+
import { Disabled, Draggable } from '@wordpress/components';
|
|
9
14
|
import { useEffect, useLayoutEffect, useRef, useState } from '@wordpress/element';
|
|
10
|
-
import { Badge } from '@wordpress/ui';
|
|
15
|
+
import { Badge, Stack } from '@wordpress/ui';
|
|
11
16
|
|
|
12
17
|
/**
|
|
13
18
|
* Internal dependencies
|
|
14
19
|
*/
|
|
15
|
-
import
|
|
20
|
+
import Card from '../card';
|
|
21
|
+
import TooltipBadge from '../tooltip-badge';
|
|
16
22
|
import type { CardBadge } from '../types';
|
|
17
23
|
import './style.scss';
|
|
18
24
|
|
|
19
|
-
/**
|
|
20
|
-
* External dependencies
|
|
21
|
-
*/
|
|
22
|
-
import classNames from 'classnames';
|
|
23
|
-
|
|
24
25
|
const DROP_ANIMATION_DURATION = 400; // ms — must match $drop-duration in style.scss
|
|
25
26
|
const BUTTON_MOVE_DURATION = 200; // ms — must match $shift-duration in style.scss
|
|
26
27
|
|
|
@@ -37,6 +38,8 @@ type DraggableItem = {
|
|
|
37
38
|
title: string;
|
|
38
39
|
description?: React.ReactNode;
|
|
39
40
|
badge?: CardBadge;
|
|
41
|
+
/** A second badge, e.g. a warning, whose tooltip explains it. */
|
|
42
|
+
secondaryBadge?: CardBadge & { tooltip?: string };
|
|
40
43
|
toggleChecked?: boolean;
|
|
41
44
|
onToggleChange?: () => void;
|
|
42
45
|
actions?: DraggableItemAction[];
|
|
@@ -45,7 +48,7 @@ type DraggableItem = {
|
|
|
45
48
|
type DragMeasurements = {
|
|
46
49
|
lockedHeight: number;
|
|
47
50
|
sourceHeight: number;
|
|
48
|
-
// Height of each item (including the
|
|
51
|
+
// Height of each item (including the Stack gap after it, except the last).
|
|
49
52
|
itemStrides: number[];
|
|
50
53
|
// Top edge of each item, used for drop position hit-testing in onDragEnd.
|
|
51
54
|
itemTops: number[];
|
|
@@ -357,7 +360,9 @@ const CardSortableList = ( {
|
|
|
357
360
|
const isDragging = draggingIndex !== null;
|
|
358
361
|
|
|
359
362
|
return (
|
|
360
|
-
<
|
|
363
|
+
<Stack
|
|
364
|
+
direction="column"
|
|
365
|
+
gap="lg"
|
|
361
366
|
ref={ listRef }
|
|
362
367
|
className={ classNames(
|
|
363
368
|
'newspack-card--core--sortable-list',
|
|
@@ -365,7 +370,6 @@ const CardSortableList = ( {
|
|
|
365
370
|
isDragging && 'newspack-card--core--sortable-list__is-dragging'
|
|
366
371
|
) }
|
|
367
372
|
style={ measurements ? { height: measurements.lockedHeight } : undefined }
|
|
368
|
-
spacing={ 4 }
|
|
369
373
|
>
|
|
370
374
|
{ sortedItems.map( ( item, index ) => {
|
|
371
375
|
const translateY = getTranslateY( index );
|
|
@@ -406,6 +410,18 @@ const CardSortableList = ( {
|
|
|
406
410
|
{ item.badge?.label && (
|
|
407
411
|
<Badge intent={ item.badge.intent ?? 'none' }>{ item.badge.label }</Badge>
|
|
408
412
|
) }
|
|
413
|
+
{ item.secondaryBadge?.label &&
|
|
414
|
+
( item.secondaryBadge.tooltip ? (
|
|
415
|
+
<TooltipBadge
|
|
416
|
+
label={ item.secondaryBadge.label }
|
|
417
|
+
tooltip={ item.secondaryBadge.tooltip }
|
|
418
|
+
intent={ item.secondaryBadge.intent }
|
|
419
|
+
/>
|
|
420
|
+
) : (
|
|
421
|
+
<Badge intent={ item.secondaryBadge.intent ?? 'none' }>
|
|
422
|
+
{ item.secondaryBadge.label }
|
|
423
|
+
</Badge>
|
|
424
|
+
) ) }
|
|
409
425
|
</h3>
|
|
410
426
|
{ item.description && <p>{ item.description }</p> }
|
|
411
427
|
</>
|
|
@@ -419,6 +435,9 @@ const CardSortableList = ( {
|
|
|
419
435
|
actionType: 'toggle',
|
|
420
436
|
isActive: item.toggleChecked,
|
|
421
437
|
onToggle: item.onToggleChange,
|
|
438
|
+
// Names the toggle for assistive tech. The card hides this
|
|
439
|
+
// label, since the header already shows the title.
|
|
440
|
+
title: item.title,
|
|
422
441
|
} ),
|
|
423
442
|
...( item.actions !== undefined && {
|
|
424
443
|
actions: item.actions,
|
|
@@ -431,7 +450,7 @@ const CardSortableList = ( {
|
|
|
431
450
|
</Disabled>
|
|
432
451
|
);
|
|
433
452
|
} ) }
|
|
434
|
-
</
|
|
453
|
+
</Stack>
|
|
435
454
|
);
|
|
436
455
|
};
|
|
437
456
|
|
|
@@ -6,6 +6,14 @@ $drop-duration: 400ms; /* must match DROP_ANIMATION_DURATION in index.tsx */
|
|
|
6
6
|
&__item {
|
|
7
7
|
cursor: grab;
|
|
8
8
|
|
|
9
|
+
/*
|
|
10
|
+
* Keep a card's title in the case it was written in. The block editor
|
|
11
|
+
* sidebar uppercases every h3 (`.interface-complementary-area h3`).
|
|
12
|
+
*/
|
|
13
|
+
.newspack-card--core__header-content h3 {
|
|
14
|
+
text-transform: none;
|
|
15
|
+
}
|
|
16
|
+
|
|
9
17
|
/*
|
|
10
18
|
* Animate items sliding to fill/make space around the dragged item.
|
|
11
19
|
*/
|
package/src/drawer/README.md
CHANGED
|
@@ -148,9 +148,9 @@ unsaved-changes confirmation always applies.
|
|
|
148
148
|
|
|
149
149
|
## `Drawer.Content`
|
|
150
150
|
|
|
151
|
-
The body. Repeatable: each `Drawer.Content` is a section
|
|
152
|
-
|
|
153
|
-
alone; their own top and bottom margins are reset.
|
|
151
|
+
The body. Repeatable: each `Drawer.Content` is a section that stacks its
|
|
152
|
+
children in a column, 16px apart by default; `gap` changes it. Children space
|
|
153
|
+
through the gap alone; their own top and bottom margins are reset.
|
|
154
154
|
|
|
155
155
|
Anything can go in a section: an element, a control, a nested stack, or plain
|
|
156
156
|
text. Each child becomes a row separated by the gap, and a run of plain text and
|
|
@@ -165,8 +165,8 @@ with markup in your own element and hand the section that instead.
|
|
|
165
165
|
|------|------|---------|-------------|
|
|
166
166
|
| `children` | `React.ReactNode` | — | Section content. |
|
|
167
167
|
| `className` | `string` | — | Additional CSS class. |
|
|
168
|
-
| `gap` | `
|
|
169
|
-
| `padding` | `number` | `6` | On the 4px scale
|
|
168
|
+
| `gap` | `string` | `'lg'` | Space between the section's children, as a `Stack` gap token from `@wordpress/ui`. `'lg'` is 16px. |
|
|
169
|
+
| `padding` | `number` | `6` | On the 4px scale. `6` is 24px; `0` is a flush section that brings its own padding. |
|
|
170
170
|
|
|
171
171
|
Consecutive sections share one scroll container, so they scroll together between
|
|
172
172
|
the pinned header and footer. Sections are not self-separating: put a
|
|
@@ -234,18 +234,12 @@ separator.
|
|
|
234
234
|
|
|
235
235
|
## `Drawer.Footer`
|
|
236
236
|
|
|
237
|
-
A pinned container for `Drawer.Action` elements.
|
|
238
|
-
|
|
237
|
+
A pinned container for `Drawer.Action` elements. Whatever the number of
|
|
238
|
+
actions, they sit in one row aligned to the end, each at its natural width. The
|
|
239
|
+
row wraps when the actions don't fit side by side.
|
|
239
240
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
| 1 | Row, the button fills it |
|
|
243
|
-
| 2 | Row, split 50/50 |
|
|
244
|
-
| 3 or more | Column, full-width buttons |
|
|
245
|
-
|
|
246
|
-
Convention, not enforced: with two actions pass the secondary first, so the
|
|
247
|
-
primary sits on the right; with three pass primary, secondary, tertiary
|
|
248
|
-
top-down.
|
|
241
|
+
Convention, not enforced: pass the primary action last, so it sits at the end
|
|
242
|
+
of the row.
|
|
249
243
|
|
|
250
244
|
Takes `className` and `children`.
|
|
251
245
|
|