newspack-components 4.6.2 → 4.7.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 +23 -0
- package/colors/colors.module.scss +13 -7
- package/dist/cjs/autocomplete-tokenfield/style.scss +4 -2
- package/dist/cjs/breadcrumbs/format-count.js +33 -0
- package/dist/cjs/breadcrumbs/index.js +78 -20
- package/dist/cjs/breadcrumbs/index.test.js +110 -0
- package/dist/cjs/breadcrumbs/style.scss +6 -0
- package/dist/cjs/button/index.js +41 -17
- package/dist/cjs/button/index.test.js +273 -0
- package/dist/cjs/card/core-card.js +9 -4
- package/dist/cjs/card/core-card.test.js +29 -0
- package/dist/cjs/card/index.js +4 -2
- package/dist/cjs/card/style-core.scss +59 -0
- package/dist/cjs/card-feature/index.js +7 -1
- package/dist/cjs/card-feature/index.test.js +92 -0
- package/dist/cjs/color-picker/index.js +1 -1
- package/dist/cjs/confirm-dialog/index.js +26 -9
- package/dist/cjs/confirm-dialog/index.test.js +176 -0
- package/dist/cjs/dataviews/index.js +11 -2
- package/dist/cjs/divider/index.js +13 -0
- package/dist/cjs/drawer/action.js +74 -0
- package/dist/cjs/drawer/body.js +79 -0
- package/dist/cjs/drawer/close-icon.js +45 -0
- package/dist/cjs/drawer/content.js +72 -0
- package/dist/cjs/drawer/context.js +23 -0
- package/dist/cjs/drawer/context.test.js +43 -0
- package/dist/cjs/drawer/divider.js +24 -0
- package/dist/cjs/drawer/footer.js +26 -0
- package/dist/cjs/drawer/header.js +26 -0
- package/dist/cjs/drawer/index.js +42 -0
- package/dist/cjs/drawer/index.test.js +1287 -0
- package/dist/cjs/drawer/root.js +350 -0
- package/dist/cjs/drawer/slots.test.js +422 -0
- package/dist/cjs/drawer/style.scss +205 -0
- package/dist/cjs/drawer/title.js +54 -0
- package/dist/cjs/drawer/types.js +5 -0
- package/dist/cjs/drawer/use-exit-animation.js +59 -0
- package/dist/cjs/hooks/use-confirm-dialog.js +15 -3
- package/dist/cjs/hooks/use-unsaved-changes-dialog.js +19 -4
- package/dist/cjs/index.js +28 -1
- package/dist/cjs/page/index.js +1 -1
- package/dist/cjs/page-control/index.js +82 -0
- package/dist/cjs/plugin-settings/SettingsSection.js +7 -1
- package/dist/cjs/section-header/index.js +5 -2
- package/dist/cjs/section-header/style.scss +25 -12
- package/dist/cjs/table-card/index.js +67 -0
- package/dist/cjs/table-card/index.test.js +153 -0
- package/dist/cjs/with-wizard-screen/style.scss +8 -0
- package/dist/cjs/wizard/index.js +102 -38
- package/dist/esm/autocomplete-tokenfield/style.scss +4 -2
- package/dist/esm/breadcrumbs/format-count.js +27 -0
- package/dist/esm/breadcrumbs/index.js +81 -20
- package/dist/esm/breadcrumbs/index.test.js +110 -0
- package/dist/esm/breadcrumbs/style.scss +6 -0
- package/dist/esm/button/index.js +42 -18
- package/dist/esm/button/index.test.js +273 -0
- package/dist/esm/card/core-card.js +9 -4
- package/dist/esm/card/core-card.test.js +29 -0
- package/dist/esm/card/index.js +4 -2
- package/dist/esm/card/style-core.scss +59 -0
- package/dist/esm/card-feature/index.js +8 -2
- package/dist/esm/card-feature/index.test.js +96 -0
- package/dist/esm/color-picker/index.js +1 -1
- package/dist/esm/confirm-dialog/index.js +26 -9
- package/dist/esm/confirm-dialog/index.test.js +176 -0
- package/dist/esm/dataviews/index.js +11 -2
- package/dist/esm/divider/index.js +14 -0
- package/dist/esm/drawer/action.js +68 -0
- package/dist/esm/drawer/body.js +70 -0
- package/dist/esm/drawer/close-icon.js +37 -0
- package/dist/esm/drawer/content.js +63 -0
- package/dist/esm/drawer/context.js +17 -0
- package/dist/esm/drawer/context.test.js +40 -0
- package/dist/esm/drawer/divider.js +16 -0
- package/dist/esm/drawer/footer.js +18 -0
- package/dist/esm/drawer/header.js +18 -0
- package/dist/esm/drawer/index.js +35 -0
- package/dist/esm/drawer/index.test.js +1285 -0
- package/dist/esm/drawer/root.js +342 -0
- package/dist/esm/drawer/slots.test.js +422 -0
- package/dist/esm/drawer/style.scss +205 -0
- package/dist/esm/drawer/title.js +46 -0
- package/dist/esm/drawer/types.js +1 -0
- package/dist/esm/drawer/use-exit-animation.js +52 -0
- package/dist/esm/hooks/use-confirm-dialog.js +15 -3
- package/dist/esm/hooks/use-unsaved-changes-dialog.js +20 -5
- package/dist/esm/index.js +4 -0
- package/dist/esm/page/index.js +1 -1
- package/dist/esm/page-control/index.js +82 -0
- package/dist/esm/plugin-settings/SettingsSection.js +8 -2
- package/dist/esm/section-header/index.js +5 -2
- package/dist/esm/section-header/style.scss +25 -12
- package/dist/esm/table-card/index.js +60 -0
- package/dist/esm/table-card/index.test.js +150 -0
- package/dist/esm/with-wizard-screen/style.scss +8 -0
- package/dist/esm/wizard/index.js +104 -38
- package/package.json +2 -2
- package/src/autocomplete-tokenfield/style.scss +4 -2
- package/src/breadcrumbs/format-count.js +27 -0
- package/src/breadcrumbs/index.js +68 -8
- package/src/breadcrumbs/index.test.js +57 -0
- package/src/breadcrumbs/style.scss +6 -0
- package/src/button/index.test.js +143 -0
- package/src/button/index.tsx +32 -7
- package/src/card/core-card.js +15 -2
- package/src/card/core-card.test.js +19 -0
- package/src/card/index.js +3 -0
- package/src/card/style-core.scss +59 -0
- package/src/card-feature/README.md +4 -0
- package/src/card-feature/index.test.js +65 -0
- package/src/card-feature/index.tsx +13 -2
- package/src/color-picker/index.js +1 -1
- package/src/confirm-dialog/README.md +3 -2
- package/src/confirm-dialog/index.test.js +146 -0
- package/src/confirm-dialog/index.tsx +23 -9
- package/src/dataviews/index.tsx +11 -2
- package/src/divider/index.js +13 -0
- package/src/drawer/README.md +454 -0
- package/src/drawer/action.tsx +67 -0
- package/src/drawer/body.tsx +60 -0
- package/src/drawer/close-icon.tsx +37 -0
- package/src/drawer/content.tsx +54 -0
- package/src/drawer/context.test.js +31 -0
- package/src/drawer/context.ts +25 -0
- package/src/drawer/divider.tsx +13 -0
- package/src/drawer/footer.tsx +15 -0
- package/src/drawer/header.tsx +15 -0
- package/src/drawer/index.test.js +1012 -0
- package/src/drawer/index.tsx +33 -0
- package/src/drawer/root.tsx +328 -0
- package/src/drawer/slots.test.js +314 -0
- package/src/drawer/style.scss +205 -0
- package/src/drawer/title.tsx +40 -0
- package/src/drawer/types.ts +79 -0
- package/src/drawer/use-exit-animation.ts +46 -0
- package/src/hooks/use-confirm-dialog.tsx +14 -3
- package/src/hooks/use-unsaved-changes-dialog.tsx +17 -5
- package/src/index.js +4 -0
- package/src/page/index.js +1 -1
- package/src/page-control/index.js +63 -0
- package/src/plugin-settings/SettingsSection.js +8 -2
- package/src/section-header/index.js +5 -2
- package/src/section-header/style.scss +25 -12
- package/src/table-card/README.md +100 -0
- package/src/table-card/index.test.js +112 -0
- package/src/table-card/index.tsx +56 -0
- package/src/with-wizard-screen/style.scss +8 -0
- package/src/wizard/index.js +95 -34
package/dist/cjs/wizard/index.js
CHANGED
|
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports["default"] = void 0;
|
|
7
|
+
exports["default"] = exports.WizardBanner = void 0;
|
|
8
8
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
9
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
10
10
|
var _classnames = _interopRequireDefault(require("classnames"));
|
|
@@ -26,11 +26,19 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
26
26
|
* External dependencies.
|
|
27
27
|
*/ /**
|
|
28
28
|
* WordPress dependencies.
|
|
29
|
-
*/
|
|
29
|
+
*/ // Notice is aliased: `Notice` below is Newspack's own, which this file also uses.
|
|
30
|
+
/**
|
|
30
31
|
* Internal dependencies
|
|
31
32
|
*/
|
|
32
33
|
(0, _store["default"])();
|
|
33
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Renders a view's page-level banner outside the padded content column, so it sits
|
|
37
|
+
* flush beneath the header rather than indented within the section it describes.
|
|
38
|
+
*/
|
|
39
|
+
var _createSlotFill = (0, _components.createSlotFill)('NewspackWizardBanner'),
|
|
40
|
+
WizardBannerSlot = _createSlotFill.Slot,
|
|
41
|
+
WizardBanner = exports.WizardBanner = _createSlotFill.Fill;
|
|
34
42
|
/**
|
|
35
43
|
* Icon registry for resolving icon name strings passed through the data store.
|
|
36
44
|
* React elements from @wordpress/icons can't cross webpack entry point boundaries
|
|
@@ -53,6 +61,34 @@ var HashRouter = _router["default"].HashRouter,
|
|
|
53
61
|
Switch = _router["default"].Switch,
|
|
54
62
|
useLocation = _router["default"].useLocation;
|
|
55
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Interpolate a translated message's named tags, falling back to plain text.
|
|
66
|
+
*
|
|
67
|
+
* The message is translated, so its tags are site-controlled: any .mo file under
|
|
68
|
+
* wp-content/languages/plugins, any GlotPress export, or any `gettext`-filter
|
|
69
|
+
* plugin can supply one. `createInterpolateElement` throws on an unbalanced
|
|
70
|
+
* closing tag whose name is in the conversion map - verified against core's own
|
|
71
|
+
* element.js, which is what runs here since the bundle externalizes wp-element.
|
|
72
|
+
* Nothing above this renders an error boundary, so an uncaught throw would blank
|
|
73
|
+
* the whole wizard, including the screen the inert-gating notice links to as the
|
|
74
|
+
* fix. Degraded copy is recoverable; a blank screen is not.
|
|
75
|
+
*
|
|
76
|
+
* The other malformed cases already degrade on their own and are left alone: an
|
|
77
|
+
* unclosed opener drops that tag and renders the rest as text, and a tag not in
|
|
78
|
+
* the map renders literally.
|
|
79
|
+
*
|
|
80
|
+
* @param {string} message Translated message carrying named tags.
|
|
81
|
+
* @param {Object} conversion Conversion map for createInterpolateElement.
|
|
82
|
+
* @return {JSX.Element|string} The interpolated message, or the message with its tags stripped.
|
|
83
|
+
*/
|
|
84
|
+
var interpolateOrPlainText = function interpolateOrPlainText(message, conversion) {
|
|
85
|
+
try {
|
|
86
|
+
return (0, _element.createInterpolateElement)(message, conversion);
|
|
87
|
+
} catch (_unused) {
|
|
88
|
+
return message.replace(/<\/?[a-zA-Z][a-zA-Z0-9]*\s*\/?>/g, '');
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
56
92
|
/**
|
|
57
93
|
* Reset the header data when a new section is rendered.
|
|
58
94
|
*/
|
|
@@ -112,7 +148,7 @@ var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
|
|
|
112
148
|
|
|
113
149
|
/**
|
|
114
150
|
* @typedef {Object} WizardProps
|
|
115
|
-
* @property {string} headerText
|
|
151
|
+
* @property {string} [headerText] Fallback heading, used only when no section declares breadcrumbs.
|
|
116
152
|
* @property {string} [subHeaderText] The sub-header text, optional.
|
|
117
153
|
* @property {string} [apiSlug] The API slug, optional.
|
|
118
154
|
* @property {string} [className] CSS classes, optional.
|
|
@@ -132,6 +168,7 @@ var WizardHeaderRegion = function WizardHeaderRegion(_ref) {
|
|
|
132
168
|
* @return {JSX.Element} Wizard component
|
|
133
169
|
*/
|
|
134
170
|
var Wizard = function Wizard(_ref2, ref) {
|
|
171
|
+
var _window$newspack_aux_;
|
|
135
172
|
var _ref2$sections = _ref2.sections,
|
|
136
173
|
sections = _ref2$sections === void 0 ? [] : _ref2$sections,
|
|
137
174
|
headerText = _ref2.headerText,
|
|
@@ -211,10 +248,35 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
211
248
|
items: displayedSections,
|
|
212
249
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_WizardError["default"], {})
|
|
213
250
|
});
|
|
251
|
+
|
|
252
|
+
// Rendered here rather than as a core admin notice, which wizards strip at
|
|
253
|
+
// priority -9999. Sits as the first child of .newspack-wizard__main so it lands
|
|
254
|
+
// flush beneath the header region and spans the full width in every view: this
|
|
255
|
+
// describes the state of the whole site, not of the section below it, so it reads
|
|
256
|
+
// as page chrome rather than as content.
|
|
257
|
+
var inertGating = (_window$newspack_aux_ = window.newspack_aux_data) === null || _window$newspack_aux_ === void 0 ? void 0 : _window$newspack_aux_.inert_gating;
|
|
258
|
+
var inertGatingNotice = (inertGating === null || inertGating === void 0 ? void 0 : inertGating.show) && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Notice, {
|
|
259
|
+
status: "warning",
|
|
260
|
+
isDismissible: false,
|
|
261
|
+
className: "newspack-wizard__inert-gating-notice",
|
|
262
|
+
children: interpolateOrPlainText(inertGating.message, {
|
|
263
|
+
/* eslint-disable jsx-a11y/anchor-has-content */
|
|
264
|
+
accessControl: /*#__PURE__*/(0, _jsxRuntime.jsx)("a", {
|
|
265
|
+
href: inertGating.urls.accessControl
|
|
266
|
+
}),
|
|
267
|
+
audience: /*#__PURE__*/(0, _jsxRuntime.jsx)("a", {
|
|
268
|
+
href: inertGating.urls.audience
|
|
269
|
+
}),
|
|
270
|
+
/* eslint-enable jsx-a11y/anchor-has-content */
|
|
271
|
+
strong: /*#__PURE__*/(0, _jsxRuntime.jsx)("strong", {})
|
|
272
|
+
})
|
|
273
|
+
});
|
|
214
274
|
var content = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
215
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_.HandoffMessage, {}), sections.length > 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(ResetHeaderData, {}), /*#__PURE__*/(0, _jsxRuntime.
|
|
275
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_.HandoffMessage, {}), sections.length > 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(ResetHeaderData, {}), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
216
276
|
className: "newspack-wizard__main",
|
|
217
|
-
children: /*#__PURE__*/(0, _jsxRuntime.
|
|
277
|
+
children: [inertGatingNotice, /*#__PURE__*/(0, _jsxRuntime.jsx)(WizardBannerSlot, {
|
|
278
|
+
bubblesVirtually: true
|
|
279
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(Switch, {
|
|
218
280
|
children: [routedSections.map(function (section, index) {
|
|
219
281
|
var _section$exact;
|
|
220
282
|
var SectionComponent = section.render;
|
|
@@ -245,7 +307,7 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
245
307
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(Redirect, {
|
|
246
308
|
to: displayedSections[0].path
|
|
247
309
|
})]
|
|
248
|
-
})
|
|
310
|
+
})]
|
|
249
311
|
})]
|
|
250
312
|
});
|
|
251
313
|
var headerActions = (actions === null || actions === void 0 ? void 0 : actions.length) > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
@@ -296,40 +358,42 @@ var Wizard = function Wizard(_ref2, ref) {
|
|
|
296
358
|
}
|
|
297
359
|
})]
|
|
298
360
|
}) : undefined;
|
|
299
|
-
return /*#__PURE__*/(0, _jsxRuntime.
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
'newspack-wizard__is-loading
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
361
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.SlotFillProvider, {
|
|
362
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
363
|
+
ref: ref,
|
|
364
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
365
|
+
className: (0, _classnames["default"])(isLoading ? 'newspack-wizard__is-loading' : 'newspack-wizard__is-loaded', {
|
|
366
|
+
'newspack-wizard__is-loading-quiet': isQuietLoading
|
|
367
|
+
}),
|
|
368
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(HashRouter, {
|
|
369
|
+
hashType: "slash",
|
|
370
|
+
children: [newspack_aux_data.is_debug_mode && /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Notice, {
|
|
371
|
+
debugMode: true
|
|
372
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(WizardHeaderRegion, {
|
|
373
|
+
hideHeader: hideHeader,
|
|
374
|
+
headerText: headerText,
|
|
375
|
+
sections: routedSections,
|
|
376
|
+
sectionName: sectionName,
|
|
377
|
+
subTitle: subHeaderText,
|
|
378
|
+
actions: headerActions,
|
|
379
|
+
tabbedNavigation: tabbedNavigation,
|
|
380
|
+
children: content
|
|
381
|
+
})]
|
|
382
|
+
}), (notices === null || notices === void 0 ? void 0 : notices.length) > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
383
|
+
className: "newspack-wizard__snackbar-list",
|
|
384
|
+
children: notices.map(function (notice, index) {
|
|
385
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_WizardSnackbar["default"], {
|
|
386
|
+
id: notice.id,
|
|
387
|
+
type: notice.type,
|
|
388
|
+
actions: notice.actions,
|
|
389
|
+
children: notice.message
|
|
390
|
+
}, notice.id || index);
|
|
391
|
+
})
|
|
318
392
|
})]
|
|
319
|
-
}),
|
|
320
|
-
|
|
321
|
-
children: notices.map(function (notice, index) {
|
|
322
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_WizardSnackbar["default"], {
|
|
323
|
-
id: notice.id,
|
|
324
|
-
type: notice.type,
|
|
325
|
-
actions: notice.actions,
|
|
326
|
-
children: notice.message
|
|
327
|
-
}, notice.id || index);
|
|
328
|
-
})
|
|
393
|
+
}), !isLoading && /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Footer, {
|
|
394
|
+
simple: hasSimpleFooter
|
|
329
395
|
})]
|
|
330
|
-
})
|
|
331
|
-
simple: hasSimpleFooter
|
|
332
|
-
})]
|
|
396
|
+
})
|
|
333
397
|
});
|
|
334
398
|
};
|
|
335
399
|
var _default = exports["default"] = (0, _element.forwardRef)(Wizard);
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
6
|
+
@use "~@wordpress/base-styles/variables" as wp-vars;
|
|
6
7
|
|
|
7
8
|
.newspack-autocomplete-tokenfield {
|
|
8
9
|
.components-spinner {
|
|
@@ -34,8 +35,9 @@
|
|
|
34
35
|
|
|
35
36
|
.newspack-autocomplete-tokenfield__help {
|
|
36
37
|
color: wp-colors.$gray-700;
|
|
37
|
-
font-size:
|
|
38
|
-
|
|
38
|
+
font-size: wp-vars.$helptext-font-size;
|
|
39
|
+
line-height: wp-vars.$default-line-height;
|
|
40
|
+
margin: wp-vars.$grid-unit-10 0 0;
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
.components-form-token-field__suggestions-list {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Group a number for the site's locale rather than the browser's, so a crumb's count
|
|
3
|
+
* matches both the translated phrasing beside it and every server-rendered figure on
|
|
4
|
+
* the page. Callers that build their own `countLabel` share this so the visible count
|
|
5
|
+
* and the spoken one are grouped the same way.
|
|
6
|
+
*
|
|
7
|
+
* WordPress ships locales `Intl` rejects outright — `pt_PT_ao90` yields the BCP-47
|
|
8
|
+
* tag `pt-PT-ao90`, whose four-character variant subtag must start with a digit — so
|
|
9
|
+
* the tag is shortened a subtag at a time until one is accepted. Falling straight
|
|
10
|
+
* through to the browser's locale would group `1,234` beside a server-rendered
|
|
11
|
+
* `1.234`, which is the divergence this helper exists to prevent.
|
|
12
|
+
*
|
|
13
|
+
* @param {number} count Number to format.
|
|
14
|
+
* @return {string} The grouped number.
|
|
15
|
+
*/
|
|
16
|
+
export var formatCount = function formatCount(count) {
|
|
17
|
+
var lang = typeof document !== 'undefined' && document.documentElement.lang || '';
|
|
18
|
+
var subtags = lang.replace(/_/g, '-').split('-').filter(Boolean);
|
|
19
|
+
while (subtags.length) {
|
|
20
|
+
try {
|
|
21
|
+
return Number(count).toLocaleString(subtags.join('-'));
|
|
22
|
+
} catch (_unused) {
|
|
23
|
+
subtags.pop();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return Number(count).toLocaleString();
|
|
27
|
+
};
|
|
@@ -1,14 +1,71 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
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; }
|
|
3
|
+
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; }
|
|
1
4
|
/**
|
|
2
5
|
* WordPress dependencies.
|
|
3
6
|
*/
|
|
4
|
-
import { __ } from '@wordpress/i18n';
|
|
7
|
+
import { __, _n, sprintf } from '@wordpress/i18n';
|
|
5
8
|
import { Link, Stack, Text } from '@wordpress/ui';
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* Internal dependencies.
|
|
9
12
|
*/
|
|
13
|
+
import { formatCount } from './format-count';
|
|
10
14
|
import './style.scss';
|
|
11
15
|
|
|
16
|
+
/**
|
|
17
|
+
* A crumb's count, shown in parentheses and spoken as a phrase.
|
|
18
|
+
*
|
|
19
|
+
* @param {Object} props
|
|
20
|
+
* @param {number} [props.count] Item count.
|
|
21
|
+
* @param {string} [props.countLabel] Translated accessible phrasing for the count.
|
|
22
|
+
* @return {JSX.Element|null} The count, or null when the crumb carries none.
|
|
23
|
+
*/
|
|
24
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
25
|
+
var CrumbCount = function CrumbCount(_ref) {
|
|
26
|
+
var count = _ref.count,
|
|
27
|
+
countLabel = _ref.countLabel;
|
|
28
|
+
if (!Number.isFinite(count)) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
var formatted = formatCount(count);
|
|
32
|
+
return /*#__PURE__*/_jsxs("span", {
|
|
33
|
+
className: "newspack-breadcrumbs__count",
|
|
34
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
35
|
+
"aria-hidden": "true",
|
|
36
|
+
children: "(".concat(formatted, ")")
|
|
37
|
+
}), /*#__PURE__*/_jsx("span", {
|
|
38
|
+
className: "screen-reader-text",
|
|
39
|
+
children: countLabel || sprintf(/* translators: %s: number of items in the current view. */
|
|
40
|
+
_n('%s item', '%s items', count, 'newspack-plugin'), formatted)
|
|
41
|
+
})]
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A crumb's label, with its count appended when the item carries one.
|
|
47
|
+
*
|
|
48
|
+
* @param {Object} props
|
|
49
|
+
* @param {string} props.label Crumb label.
|
|
50
|
+
* @param {number} [props.count] Item count to annotate the label with.
|
|
51
|
+
* @param {string} [props.countLabel] Translated accessible phrasing for the count.
|
|
52
|
+
* @return {JSX.Element|string} The label, annotated when a count is present.
|
|
53
|
+
*/
|
|
54
|
+
var CrumbLabel = function CrumbLabel(_ref2) {
|
|
55
|
+
var label = _ref2.label,
|
|
56
|
+
count = _ref2.count,
|
|
57
|
+
countLabel = _ref2.countLabel;
|
|
58
|
+
if (!Number.isFinite(count)) {
|
|
59
|
+
return label;
|
|
60
|
+
}
|
|
61
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
62
|
+
children: [label, " ", /*#__PURE__*/_jsx(CrumbCount, {
|
|
63
|
+
count: count,
|
|
64
|
+
countLabel: countLabel
|
|
65
|
+
})]
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
|
|
12
69
|
/**
|
|
13
70
|
* Newspack breadcrumb trail.
|
|
14
71
|
*
|
|
@@ -18,13 +75,12 @@ import './style.scss';
|
|
|
18
75
|
* component needs no router context.
|
|
19
76
|
*
|
|
20
77
|
* @param {Object} props
|
|
21
|
-
* @param {Array} props.items Trail items: `{ label, url? }`.
|
|
78
|
+
* @param {Array} props.items Trail items: `{ label, url?, count?, countLabel? }`.
|
|
22
79
|
* @return {JSX.Element|null} Breadcrumbs component.
|
|
23
80
|
*/
|
|
24
|
-
|
|
25
|
-
var
|
|
26
|
-
|
|
27
|
-
items = _ref$items === void 0 ? [] : _ref$items;
|
|
81
|
+
var Breadcrumbs = function Breadcrumbs(_ref3) {
|
|
82
|
+
var _ref3$items = _ref3.items,
|
|
83
|
+
items = _ref3$items === void 0 ? [] : _ref3$items;
|
|
28
84
|
if (!items.length) {
|
|
29
85
|
return null;
|
|
30
86
|
}
|
|
@@ -39,21 +95,26 @@ var Breadcrumbs = function Breadcrumbs(_ref) {
|
|
|
39
95
|
className: "newspack-breadcrumbs__list",
|
|
40
96
|
children: [preceding.map(function (item, index) {
|
|
41
97
|
return /*#__PURE__*/_jsxs("li", {
|
|
42
|
-
children: [item.url ?
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}),
|
|
53
|
-
|
|
98
|
+
children: [item.url ? /*#__PURE__*/_jsxs(_Fragment, {
|
|
99
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
100
|
+
variant: "body-lg",
|
|
101
|
+
render: /*#__PURE__*/_jsx(Link, {
|
|
102
|
+
tone: "neutral",
|
|
103
|
+
render: /*#__PURE__*/_jsx("a", {
|
|
104
|
+
href: item.url
|
|
105
|
+
})
|
|
106
|
+
}),
|
|
107
|
+
children: item.label
|
|
108
|
+
}), Number.isFinite(item.count) && /*#__PURE__*/_jsxs(Text, {
|
|
109
|
+
variant: "body-lg",
|
|
110
|
+
children: [' ', /*#__PURE__*/_jsx(CrumbCount, {
|
|
111
|
+
count: item.count,
|
|
112
|
+
countLabel: item.countLabel
|
|
113
|
+
})]
|
|
114
|
+
})]
|
|
54
115
|
}) : /*#__PURE__*/_jsx(Text, {
|
|
55
116
|
variant: "body-lg",
|
|
56
|
-
children: item
|
|
117
|
+
children: /*#__PURE__*/_jsx(CrumbLabel, _objectSpread({}, item))
|
|
57
118
|
}), /*#__PURE__*/_jsx(Text, {
|
|
58
119
|
variant: "body-lg",
|
|
59
120
|
"aria-hidden": "true",
|
|
@@ -66,7 +127,7 @@ var Breadcrumbs = function Breadcrumbs(_ref) {
|
|
|
66
127
|
variant: "heading-lg",
|
|
67
128
|
render: /*#__PURE__*/_jsx("h1", {}),
|
|
68
129
|
className: "newspack-breadcrumbs__current",
|
|
69
|
-
children: last
|
|
130
|
+
children: /*#__PURE__*/_jsx(CrumbLabel, _objectSpread({}, last))
|
|
70
131
|
})
|
|
71
132
|
})]
|
|
72
133
|
})
|
|
@@ -9,6 +9,10 @@ import { render, screen } from '@testing-library/react';
|
|
|
9
9
|
import Breadcrumbs from './';
|
|
10
10
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
11
11
|
describe('Breadcrumbs', function () {
|
|
12
|
+
// Unconditional, so a failing assertion cannot leak a language into later tests.
|
|
13
|
+
afterEach(function () {
|
|
14
|
+
document.documentElement.lang = '';
|
|
15
|
+
});
|
|
12
16
|
it('renders the last item as the only h1 and never a link', function () {
|
|
13
17
|
render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
14
18
|
items: [{
|
|
@@ -102,4 +106,110 @@ describe('Breadcrumbs', function () {
|
|
|
102
106
|
container = _render3.container;
|
|
103
107
|
expect(container.querySelector('nav')).not.toBeInTheDocument();
|
|
104
108
|
});
|
|
109
|
+
it('annotates a crumb with its count, hiding the parens from assistive tech', function () {
|
|
110
|
+
var _render4 = render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
111
|
+
items: [{
|
|
112
|
+
label: 'Plans'
|
|
113
|
+
}, {
|
|
114
|
+
label: 'Subscriptions',
|
|
115
|
+
count: 33
|
|
116
|
+
}]
|
|
117
|
+
})),
|
|
118
|
+
container = _render4.container;
|
|
119
|
+
var count = container.querySelector('.newspack-breadcrumbs__count');
|
|
120
|
+
expect(count).not.toBeNull();
|
|
121
|
+
expect(count.querySelector('[aria-hidden="true"]')).toHaveTextContent('(33)');
|
|
122
|
+
expect(count.querySelector('.screen-reader-text')).toHaveTextContent('33 items');
|
|
123
|
+
expect(screen.getByRole('heading', {
|
|
124
|
+
level: 1
|
|
125
|
+
})).toContainElement(count);
|
|
126
|
+
});
|
|
127
|
+
it('announces a single item in the singular', function () {
|
|
128
|
+
var _render5 = render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
129
|
+
items: [{
|
|
130
|
+
label: 'Donations',
|
|
131
|
+
count: 1
|
|
132
|
+
}]
|
|
133
|
+
})),
|
|
134
|
+
container = _render5.container;
|
|
135
|
+
expect(container.querySelector('.newspack-breadcrumbs__count .screen-reader-text').textContent).toBe('1 item');
|
|
136
|
+
});
|
|
137
|
+
it('renders a zero count rather than dropping the annotation', function () {
|
|
138
|
+
var _render6 = render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
139
|
+
items: [{
|
|
140
|
+
label: 'Donations',
|
|
141
|
+
count: 0
|
|
142
|
+
}]
|
|
143
|
+
})),
|
|
144
|
+
container = _render6.container;
|
|
145
|
+
expect(container.querySelector('.newspack-breadcrumbs__count [aria-hidden="true"]')).toHaveTextContent('(0)');
|
|
146
|
+
});
|
|
147
|
+
it('omits the annotation when a crumb carries no usable count', function () {
|
|
148
|
+
var _render7 = render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
149
|
+
items: [{
|
|
150
|
+
label: 'Plans'
|
|
151
|
+
}, {
|
|
152
|
+
label: 'Bundles',
|
|
153
|
+
count: undefined
|
|
154
|
+
}]
|
|
155
|
+
})),
|
|
156
|
+
container = _render7.container;
|
|
157
|
+
expect(container.querySelector('.newspack-breadcrumbs__count')).toBeNull();
|
|
158
|
+
expect(screen.getByRole('heading', {
|
|
159
|
+
level: 1
|
|
160
|
+
})).toHaveTextContent('Bundles');
|
|
161
|
+
});
|
|
162
|
+
it('prefers a supplied countLabel for the accessible phrasing', function () {
|
|
163
|
+
var _render8 = render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
164
|
+
items: [{
|
|
165
|
+
label: 'Subscribers',
|
|
166
|
+
count: 85,
|
|
167
|
+
countLabel: '85 subscribers total'
|
|
168
|
+
}]
|
|
169
|
+
})),
|
|
170
|
+
container = _render8.container;
|
|
171
|
+
expect(container.querySelector('.newspack-breadcrumbs__count .screen-reader-text')).toHaveTextContent('85 subscribers total');
|
|
172
|
+
});
|
|
173
|
+
it('annotates a linked crumb outside the link, so the link is named for its destination', function () {
|
|
174
|
+
var _render9 = render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
175
|
+
items: [{
|
|
176
|
+
label: 'Plans',
|
|
177
|
+
url: '#/',
|
|
178
|
+
count: 12
|
|
179
|
+
}, {
|
|
180
|
+
label: 'Add plan'
|
|
181
|
+
}]
|
|
182
|
+
})),
|
|
183
|
+
container = _render9.container;
|
|
184
|
+
var link = screen.getByRole('link', {
|
|
185
|
+
name: 'Plans'
|
|
186
|
+
});
|
|
187
|
+
expect(link.getAttribute('href')).toBe('#/');
|
|
188
|
+
expect(link).not.toHaveTextContent('(12)');
|
|
189
|
+
var count = container.querySelector('.newspack-breadcrumbs__count');
|
|
190
|
+
expect(count.querySelector('[aria-hidden="true"]')).toHaveTextContent('(12)');
|
|
191
|
+
expect(link).not.toContainElement(count);
|
|
192
|
+
});
|
|
193
|
+
it('groups the count for the document language', function () {
|
|
194
|
+
document.documentElement.lang = 'de-DE';
|
|
195
|
+
var _render0 = render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
196
|
+
items: [{
|
|
197
|
+
label: 'Abonnenten',
|
|
198
|
+
count: 1234
|
|
199
|
+
}]
|
|
200
|
+
})),
|
|
201
|
+
container = _render0.container;
|
|
202
|
+
expect(container.querySelector('.newspack-breadcrumbs__count [aria-hidden="true"]')).toHaveTextContent('(1.234)');
|
|
203
|
+
});
|
|
204
|
+
it('falls back to the default grouping when the document language is not a locale Intl accepts', function () {
|
|
205
|
+
document.documentElement.lang = 'pt-PT-ao90';
|
|
206
|
+
var _render1 = render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
207
|
+
items: [{
|
|
208
|
+
label: 'Planos',
|
|
209
|
+
count: 1234
|
|
210
|
+
}]
|
|
211
|
+
})),
|
|
212
|
+
container = _render1.container;
|
|
213
|
+
expect(container.querySelector('.newspack-breadcrumbs__count [aria-hidden="true"]').textContent).toMatch(/^\(1\D?234\)$/);
|
|
214
|
+
});
|
|
105
215
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
2
|
+
@use "~@wordpress/base-styles/variables" as wp-vars;
|
|
2
3
|
|
|
3
4
|
.newspack-breadcrumbs__list {
|
|
4
5
|
list-style: none;
|
|
@@ -26,6 +27,11 @@
|
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
.newspack-breadcrumbs__count {
|
|
31
|
+
color: var(--wpds-color-foreground-content-neutral-weak, #{wp-colors.$gray-700});
|
|
32
|
+
font-weight: wp-vars.$font-weight-regular;
|
|
33
|
+
}
|
|
34
|
+
|
|
29
35
|
.newspack-breadcrumbs__separator {
|
|
30
36
|
color: var(--wpds-color-stroke-surface-neutral, #dbdbdb);
|
|
31
37
|
margin: 0 var(--wpds-dimension-gap-sm, 8px);
|
package/dist/esm/button/index.js
CHANGED
|
@@ -15,7 +15,7 @@ function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try {
|
|
|
15
15
|
* WordPress dependencies.
|
|
16
16
|
*/
|
|
17
17
|
import { Button as BaseComponent } from '@wordpress/components';
|
|
18
|
-
import { useState } from '@wordpress/element';
|
|
18
|
+
import { useEffect, useState } from '@wordpress/element';
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Internal dependencies
|
|
@@ -24,6 +24,11 @@ import Router from '../proxied-imports/router';
|
|
|
24
24
|
import './style.scss';
|
|
25
25
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
26
26
|
var useHistory = Router.useHistory;
|
|
27
|
+
// Control characters are stripped first, as browsers do, so `java\nscript:`
|
|
28
|
+
// cannot slip past.
|
|
29
|
+
var isJavascriptHref = function isJavascriptHref(href) {
|
|
30
|
+
return 'string' === typeof href && href.replace(/[\u0000-\u0020]/g, '').toLowerCase().startsWith('javascript:');
|
|
31
|
+
};
|
|
27
32
|
var Button = function Button(_ref) {
|
|
28
33
|
var href = _ref.href,
|
|
29
34
|
_ref$loading = _ref.loading,
|
|
@@ -35,26 +40,45 @@ var Button = function Button(_ref) {
|
|
|
35
40
|
_useState2 = _slicedToArray(_useState, 2),
|
|
36
41
|
isAwaitingOnClick = _useState2[0],
|
|
37
42
|
setIsAwaitingOnClick = _useState2[1];
|
|
43
|
+
var isUnsafeHref = isJavascriptHref(href);
|
|
44
|
+
var safeHref = isUnsafeHref ? undefined : href;
|
|
45
|
+
useEffect(function () {
|
|
46
|
+
if ('production' === process.env.NODE_ENV || !isUnsafeHref) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// eslint-disable-next-line no-console
|
|
50
|
+
console.warn('Button: a `javascript:` href is not a link and has been dropped.');
|
|
51
|
+
}, [isUnsafeHref]);
|
|
38
52
|
|
|
39
53
|
// If both onClick and href are present, await the onClick action an then redirect.
|
|
40
|
-
if (
|
|
41
|
-
otherProps.onClick = /*#__PURE__*/
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
if (safeHref && onClick) {
|
|
55
|
+
otherProps.onClick = /*#__PURE__*/function () {
|
|
56
|
+
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(event) {
|
|
57
|
+
return _regenerator().w(function (_context) {
|
|
58
|
+
while (1) switch (_context.n) {
|
|
59
|
+
case 0:
|
|
60
|
+
setIsAwaitingOnClick(true);
|
|
61
|
+
_context.n = 1;
|
|
62
|
+
return onClick(event);
|
|
63
|
+
case 1:
|
|
64
|
+
setIsAwaitingOnClick(false);
|
|
65
|
+
// Outside a Router the href can only mean a real URL.
|
|
66
|
+
if (history) {
|
|
67
|
+
history.push(safeHref.replace('#', ''));
|
|
68
|
+
} else {
|
|
69
|
+
window.location.href = safeHref;
|
|
70
|
+
}
|
|
71
|
+
case 2:
|
|
72
|
+
return _context.a(2);
|
|
73
|
+
}
|
|
74
|
+
}, _callee);
|
|
75
|
+
}));
|
|
76
|
+
return function (_x) {
|
|
77
|
+
return _ref2.apply(this, arguments);
|
|
78
|
+
};
|
|
79
|
+
}();
|
|
56
80
|
} else {
|
|
57
|
-
otherProps.href =
|
|
81
|
+
otherProps.href = safeHref;
|
|
58
82
|
otherProps.onClick = onClick;
|
|
59
83
|
}
|
|
60
84
|
if (isAwaitingOnClick) {
|