newspack-components 4.5.0 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/DEVELOPMENT.md +1 -1
  3. package/dist/cjs/accordion/index.js +43 -26
  4. package/dist/cjs/accordion/index.test.js +80 -0
  5. package/dist/cjs/accordion/style.scss +25 -21
  6. package/dist/cjs/action-card/style.scss +0 -22
  7. package/dist/cjs/breadcrumbs/index.js +80 -0
  8. package/dist/cjs/breadcrumbs/index.test.js +109 -0
  9. package/dist/cjs/breadcrumbs/style.scss +41 -0
  10. package/dist/cjs/card/core-card.js +8 -4
  11. package/dist/cjs/card/index.js +1 -1
  12. package/dist/cjs/card/style-core.scss +14 -0
  13. package/dist/cjs/card/style.scss +0 -9
  14. package/dist/cjs/card-feature/index.js +25 -13
  15. package/dist/cjs/card-settings-group/index.js +3 -0
  16. package/dist/cjs/confirm-dialog/index.js +34 -8
  17. package/dist/cjs/confirm-dialog/index.test.js +173 -0
  18. package/dist/cjs/divider/style.scss +4 -2
  19. package/dist/cjs/grid/style.scss +5 -0
  20. package/dist/cjs/handoff/index.js +8 -5
  21. package/dist/cjs/index.js +34 -1
  22. package/dist/cjs/integration-icon/index.js +40 -0
  23. package/dist/cjs/integration-icon/style.scss +42 -0
  24. package/dist/cjs/integration-icons/index.js +21 -2
  25. package/dist/cjs/modal/style.scss +4 -0
  26. package/dist/cjs/page/index.js +121 -0
  27. package/dist/cjs/page/index.test.js +69 -0
  28. package/dist/cjs/page/style.scss +86 -0
  29. package/dist/cjs/route-match.js +59 -0
  30. package/dist/cjs/route-match.test.js +77 -0
  31. package/dist/cjs/section-header/index.js +8 -1
  32. package/dist/cjs/section-header/style.scss +11 -11
  33. package/dist/cjs/select-control/GroupedSelectControl.js +1 -1
  34. package/dist/cjs/select-control/style.scss +4 -0
  35. package/dist/cjs/style.scss +1 -4
  36. package/dist/cjs/tabbed-navigation/index.js +188 -40
  37. package/dist/cjs/tabbed-navigation/index.test.js +299 -0
  38. package/dist/cjs/tabbed-navigation/style.scss +77 -57
  39. package/dist/cjs/with-wizard/index.js +34 -45
  40. package/dist/cjs/with-wizard-screen/index.js +82 -41
  41. package/dist/cjs/with-wizard-screen/index.test.js +50 -0
  42. package/dist/cjs/with-wizard-screen/style.scss +15 -118
  43. package/dist/cjs/wizard/breadcrumbs-select.js +70 -0
  44. package/dist/cjs/wizard/breadcrumbs-select.test.js +200 -0
  45. package/dist/cjs/wizard/components/WizardError.js +8 -4
  46. package/dist/cjs/wizard/index.js +162 -141
  47. package/dist/esm/accordion/index.js +42 -26
  48. package/dist/esm/accordion/index.test.js +79 -0
  49. package/dist/esm/accordion/style.scss +25 -21
  50. package/dist/esm/action-card/style.scss +0 -22
  51. package/dist/esm/breadcrumbs/index.js +75 -0
  52. package/dist/esm/breadcrumbs/index.test.js +105 -0
  53. package/dist/esm/breadcrumbs/style.scss +41 -0
  54. package/dist/esm/card/core-card.js +8 -4
  55. package/dist/esm/card/index.js +1 -1
  56. package/dist/esm/card/style-core.scss +14 -0
  57. package/dist/esm/card/style.scss +0 -9
  58. package/dist/esm/card-feature/index.js +25 -13
  59. package/dist/esm/card-settings-group/index.js +3 -0
  60. package/dist/esm/confirm-dialog/index.js +34 -8
  61. package/dist/esm/confirm-dialog/index.test.js +173 -0
  62. package/dist/esm/divider/style.scss +4 -2
  63. package/dist/esm/grid/style.scss +5 -0
  64. package/dist/esm/handoff/index.js +7 -5
  65. package/dist/esm/index.js +5 -1
  66. package/dist/esm/integration-icon/index.js +34 -0
  67. package/dist/esm/integration-icon/style.scss +42 -0
  68. package/dist/esm/integration-icons/index.js +22 -1
  69. package/dist/esm/modal/style.scss +4 -0
  70. package/dist/esm/page/index.js +113 -0
  71. package/dist/esm/page/index.test.js +65 -0
  72. package/dist/esm/page/style.scss +86 -0
  73. package/dist/esm/route-match.js +51 -0
  74. package/dist/esm/route-match.test.js +74 -0
  75. package/dist/esm/section-header/index.js +8 -1
  76. package/dist/esm/section-header/style.scss +11 -11
  77. package/dist/esm/select-control/GroupedSelectControl.js +1 -1
  78. package/dist/esm/select-control/style.scss +4 -0
  79. package/dist/esm/style.scss +1 -4
  80. package/dist/esm/tabbed-navigation/index.js +192 -38
  81. package/dist/esm/tabbed-navigation/index.test.js +296 -0
  82. package/dist/esm/tabbed-navigation/style.scss +77 -57
  83. package/dist/esm/with-wizard/index.js +33 -45
  84. package/dist/esm/with-wizard-screen/index.js +78 -41
  85. package/dist/esm/with-wizard-screen/index.test.js +46 -0
  86. package/dist/esm/with-wizard-screen/style.scss +15 -118
  87. package/dist/esm/wizard/breadcrumbs-select.js +63 -0
  88. package/dist/esm/wizard/breadcrumbs-select.test.js +197 -0
  89. package/dist/esm/wizard/components/WizardError.js +7 -5
  90. package/dist/esm/wizard/index.js +165 -144
  91. package/package.json +10 -2
  92. package/src/accordion/index.js +27 -15
  93. package/src/accordion/index.test.js +62 -0
  94. package/src/accordion/style.scss +25 -21
  95. package/src/action-card/style.scss +0 -22
  96. package/src/breadcrumbs/index.js +63 -0
  97. package/src/breadcrumbs/index.test.js +59 -0
  98. package/src/breadcrumbs/style.scss +41 -0
  99. package/src/card/core-card.js +11 -6
  100. package/src/card/index.js +0 -1
  101. package/src/card/style-core.scss +14 -0
  102. package/src/card/style.scss +0 -9
  103. package/src/card-feature/README.md +3 -3
  104. package/src/card-feature/index.tsx +37 -21
  105. package/src/card-settings-group/index.tsx +4 -0
  106. package/src/card-sortable-list/index.tsx +1 -1
  107. package/src/confirm-dialog/index.test.js +142 -0
  108. package/src/confirm-dialog/index.tsx +34 -7
  109. package/src/divider/style.scss +4 -2
  110. package/src/grid/style.scss +5 -0
  111. package/src/handoff/index.js +4 -3
  112. package/src/index.js +5 -1
  113. package/src/integration-icon/index.tsx +35 -0
  114. package/src/integration-icon/style.scss +42 -0
  115. package/src/integration-icons/index.js +23 -0
  116. package/src/modal/style.scss +4 -0
  117. package/src/page/index.js +89 -0
  118. package/src/page/index.test.js +43 -0
  119. package/src/page/style.scss +86 -0
  120. package/src/route-match.js +47 -0
  121. package/src/route-match.test.js +50 -0
  122. package/src/section-header/index.js +7 -3
  123. package/src/section-header/style.scss +11 -11
  124. package/src/select-control/GroupedSelectControl.js +1 -1
  125. package/src/select-control/style.scss +4 -0
  126. package/src/style.scss +1 -4
  127. package/src/tabbed-navigation/index.js +181 -34
  128. package/src/tabbed-navigation/index.test.js +228 -0
  129. package/src/tabbed-navigation/style.scss +77 -57
  130. package/src/with-wizard/index.js +18 -39
  131. package/src/with-wizard-screen/index.js +70 -35
  132. package/src/with-wizard-screen/index.test.js +36 -0
  133. package/src/with-wizard-screen/style.scss +15 -118
  134. package/src/wizard/breadcrumbs-select.js +51 -0
  135. package/src/wizard/breadcrumbs-select.test.js +124 -0
  136. package/src/wizard/components/WizardError.js +4 -3
  137. package/src/wizard/index.js +160 -146
  138. package/tsconfig.json +7 -0
@@ -2,81 +2,101 @@
2
2
  * Tabbed Navigation
3
3
  */
4
4
 
5
+ @use "../../../colors/colors.module" as colors;
5
6
  @use "~@wordpress/base-styles/colors" as wp-colors;
7
+ @use "~@wordpress/base-styles/variables" as wp-vars;
8
+
9
+ // The Tabs.Root wrapper spans the tab bar and the tab panels so the panels can
10
+ // contain the routed content; it plays no layout role of its own.
11
+ .newspack-tabbed-navigation__root {
12
+ display: contents;
13
+ }
6
14
 
7
15
  .newspack-tabbed-navigation {
8
- background: white;
16
+ background: wp-colors.$white;
17
+ border-bottom: var( --wpds-border-width-xs, #{wp-vars.$border-width} ) solid var( --wpds-color-stroke-surface-neutral-weak, #{wp-colors.$gray-100} );
9
18
  width: 100%;
10
19
 
11
- @media only screen and ( min-width: 600px ) {
12
- position: sticky;
13
- top: 46px;
14
- z-index: 3;
15
- }
16
-
17
- @media only screen and ( min-width: 783px ) {
18
- top: 32px;
19
- }
20
+ /* stylelint-disable-next-line plugin-wpds/no-setting-wpds-custom-properties -- deliberate Newspack brand override of the indicator token. */
21
+ --wpds-color-stroke-interactive-neutral-strong: #{colors.$primary-600};
20
22
 
21
- ul {
22
- box-shadow: 0 -1px 0 inset wp-colors.$gray-300;
23
- display: flex;
24
- flex-wrap: wrap;
25
- margin: 0;
26
- }
23
+ a[role="tab"] {
24
+ text-decoration: none;
27
25
 
28
- li {
29
- margin-bottom: 0;
30
- width: 100%;
26
+ // wp-admin's unlayered `a { color }` beats every rule inside the design
27
+ // system's @layer wp-ui, so anchor tabs need their colors restated here:
28
+ // gray-900 for enabled tabs, and the DS disabled token for disabled ones.
29
+ &:not([data-disabled]):not([aria-disabled="true"]) {
30
+ color: wp-colors.$gray-900;
31
31
 
32
- @media screen and ( min-width: 600px ) {
33
- width: auto;
32
+ &:hover,
33
+ &:active,
34
+ &[aria-selected="true"] {
35
+ color: wp-colors.$gray-900;
36
+ }
34
37
  }
35
38
 
36
- a {
37
- align-items: center;
38
- color: wp-colors.$gray-900;
39
- display: flex;
40
- font-weight: bold;
41
- height: 48px;
39
+ // wp-admin's common.css and the wizard shell both decorate a:focus with a
40
+ // box-shadow ring, a 2px border-radius, and a transparent outline. Reset
41
+ // all three so the component's own :focus-visible ring (an inset outline
42
+ // on its ::after, shipped by @wordpress/ui) is the only focus treatment.
43
+ &:focus {
44
+ border-radius: 0;
45
+ box-shadow: none;
42
46
  outline: none;
43
- padding: 12px 15px;
44
- text-decoration: none;
47
+ }
45
48
 
46
- @media screen and ( min-width: 600px ) {
47
- border-bottom: 4px solid transparent;
48
- padding-bottom: 8px;
49
- }
49
+ // Square the component's focus ring corners.
50
+ &::after {
51
+ border-radius: 0;
52
+ }
50
53
 
51
- &:active,
52
- &:focus,
53
- &:hover {
54
- color: var(--wp-admin-theme-color);
55
- }
54
+ &[data-disabled],
55
+ &[aria-disabled="true"] {
56
+ color: var( --wpds-color-foreground-interactive-neutral-disabled, #{wp-colors.$gray-600} );
57
+ pointer-events: none;
58
+ }
59
+ }
56
60
 
57
- &:focus-visible {
58
- outline: 2px solid var(--wp-admin-theme-color);
59
- outline-offset: -2px;
60
- }
61
+ // Link-driven variant: plain navigation styled to match the tabs widget.
62
+ &--links {
63
+ align-items: stretch;
64
+ display: flex;
65
+ overflow-x: auto;
66
+ }
61
67
 
62
- &.selected {
63
- box-shadow: inset 0 0 0 2px white, inset 0 0 0 4px var(--wp-admin-theme-color);
68
+ .newspack-tabbed-navigation__link {
69
+ align-items: center;
70
+ color: wp-colors.$gray-900;
71
+ display: flex;
72
+ font-size: var( --wpds-typography-font-size-md, #{wp-vars.$default-font-size} );
73
+ height: wp-vars.$grid-unit-60; // Matches @wordpress/ui's horizontal tab height.
74
+ line-height: 1.2;
75
+ padding-inline: var( --wpds-dimension-padding-lg, #{wp-vars.$grid-unit-20} );
76
+ text-decoration: none;
77
+ white-space: nowrap;
64
78
 
65
- @media screen and ( min-width: 600px ) {
66
- border-color: var(--wp-admin-theme-color);
67
- box-shadow: none;
68
- }
69
- }
79
+ &:hover,
80
+ &:active,
81
+ &:focus {
82
+ color: wp-colors.$gray-900;
83
+ }
70
84
 
71
- &.disabled {
72
- cursor: not-allowed;
73
- opacity: 0.3;
74
- pointer-events: none;
85
+ // Mirror the tabs widget's focus ring (an inset outline) with plain
86
+ // outline + offset, replacing wp-admin's box-shadow focus decoration.
87
+ &:focus {
88
+ border-radius: 0;
89
+ box-shadow: none;
90
+ outline: none;
91
+ }
75
92
 
76
- &:hover {
77
- color: inherit;
78
- }
79
- }
93
+ &:focus-visible {
94
+ outline: var( --wpds-border-width-focus, var( --wp-admin-border-width-focus, #{wp-vars.$border-width-focus-fallback} ) ) solid var( --wpds-color-stroke-focus, var( --wp-admin-theme-color ) );
95
+ outline-offset: calc( var( --wpds-dimension-padding-md, #{wp-vars.$grid-unit-15} ) * -1 );
96
+ }
97
+
98
+ &[aria-current="page"] {
99
+ box-shadow: inset 0 calc( var( --wpds-border-width-focus, #{wp-vars.$border-width-focus-fallback} ) * -1 ) 0 var( --wpds-color-stroke-interactive-neutral-strong, #{colors.$primary-600} );
80
100
  }
81
101
  }
82
102
  }
@@ -14,7 +14,7 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
14
14
  var _element = require("@wordpress/element");
15
15
  var _i18n = require("@wordpress/i18n");
16
16
  var _apiFetch = _interopRequireDefault(require("@wordpress/api-fetch"));
17
- var _icons = require("@wordpress/icons");
17
+ var _components = require("@wordpress/components");
18
18
  var _ = require("../");
19
19
  var _router = _interopRequireDefault(require("../proxied-imports/router"));
20
20
  var _footer = _interopRequireDefault(require("../footer"));
@@ -25,7 +25,8 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
25
25
  function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2["default"])(o), (0, _possibleConstructorReturn2["default"])(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2["default"])(t).constructor) : o.apply(t, e)); }
26
26
  function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } /**
27
27
  * WordPress dependencies.
28
- */ /**
28
+ */ // eslint-disable-line @wordpress/no-unsafe-wp-apis
29
+ /**
29
30
  * Internal dependencies.
30
31
  */
31
32
  var Redirect = _router["default"].Redirect,
@@ -115,10 +116,11 @@ function withWizard(WrappedComponent, requiredPlugins) {
115
116
  noticeText: message,
116
117
  isError: true,
117
118
  rawHTML: true
118
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Card, {
119
- buttonsCard: true,
120
- noBorder: true,
121
- className: "justify-end",
119
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalHStack, {
120
+ justify: "flex-end",
121
+ spacing: 4,
122
+ wrap: true,
123
+ className: "newspack-modal__footer",
122
124
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Button, {
123
125
  isPrimary: true,
124
126
  href: fallbackURL,
@@ -230,43 +232,29 @@ function withWizard(WrappedComponent, requiredPlugins) {
230
232
  to: "/"
231
233
  });
232
234
  }
235
+ var headerText = requiredPlugins.length > 1 ? (0, _i18n.__)('Required plugins', 'newspack-plugin') : (0, _i18n.__)('Required plugin', 'newspack-plugin');
236
+ var content = /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
237
+ className: "newspack-wizard newspack-wizard__content",
238
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_.PluginInstaller, {
239
+ plugins: requiredPlugins,
240
+ onStatus: function onStatus(status) {
241
+ return _this.pluginInstallationStatus(status);
242
+ }
243
+ })
244
+ });
233
245
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(Route, {
234
246
  path: "/",
235
247
  render: function render() {
236
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_element.Fragment, {
237
- children: [complete !== null && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
238
- className: "newspack-wizard__header",
239
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
240
- className: "newspack-wizard__header__inner",
241
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
242
- className: "newspack-wizard__title",
243
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_.Button, {
244
- isLink: true,
245
- href: newspack_urls.dashboard,
246
- label: (0, _i18n.__)('Return to Dashboard', 'newspack-plugin'),
247
- showTooltip: true,
248
- icon: _icons.category,
249
- iconSize: 36,
250
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_.NewspackIcon, {
251
- size: 36
252
- })
253
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
254
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)("h2", {
255
- children: requiredPlugins.length > 1 ? (0, _i18n.__)('Required plugins', 'newspack-plugin') : (0, _i18n.__)('Required plugin', 'newspack-plugin')
256
- })
257
- })]
258
- })
259
- })
260
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
261
- className: "newspack-wizard newspack-wizard__content",
262
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_.PluginInstaller, {
263
- plugins: requiredPlugins,
264
- onStatus: function onStatus(status) {
265
- return _this.pluginInstallationStatus(status);
266
- }
267
- })
268
- })]
269
- });
248
+ return (
249
+ // While `complete` is still null the requirements are being
250
+ // determined; render content without a header (matches prior behavior).
251
+ complete === null ? content : /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Page, {
252
+ breadcrumbItems: [{
253
+ label: headerText
254
+ }],
255
+ children: content
256
+ })
257
+ );
270
258
  }
271
259
  });
272
260
  });
@@ -284,7 +272,7 @@ function withWizard(WrappedComponent, requiredPlugins) {
284
272
  (0, _defineProperty2["default"])(_this, "confirmAction", function (options) {
285
273
  var modalOptions = _objectSpread({
286
274
  title: null,
287
- message: (0, _i18n.__)('Are you sure?', 'newpack-plugin'),
275
+ message: (0, _i18n.__)('Are you sure?', 'newspack-plugin'),
288
276
  confirmText: (0, _i18n.__)('OK', 'newspack-plugin'),
289
277
  cancelText: (0, _i18n.__)('Cancel', 'newspack-plugin'),
290
278
  callback: null
@@ -320,10 +308,11 @@ function withWizard(WrappedComponent, requiredPlugins) {
320
308
  },
321
309
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
322
310
  children: message
323
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_.Card, {
324
- buttonsCard: true,
325
- noBorder: true,
326
- className: "justify-end",
311
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalHStack, {
312
+ justify: "flex-end",
313
+ spacing: 4,
314
+ wrap: true,
315
+ className: "newspack-modal__footer",
327
316
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_.Button, {
328
317
  variant: "secondary",
329
318
  onClick: function onClick() {
@@ -6,26 +6,51 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports["default"] = withWizardScreen;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
- var _i18n = require("@wordpress/i18n");
10
- var _icons = require("@wordpress/icons");
9
+ var _element = require("@wordpress/element");
11
10
  var _ = require("../");
11
+ var _breadcrumbsSelect = require("../wizard/breadcrumbs-select");
12
12
  var _buttonProps = require("../button-props");
13
+ var _router = _interopRequireDefault(require("../proxied-imports/router"));
13
14
  require("./style.scss");
14
15
  var _classnames = _interopRequireDefault(require("classnames"));
15
16
  var _jsxRuntime = require("react/jsx-runtime");
16
17
  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; }
17
18
  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) { (0, _defineProperty2["default"])(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; } /**
18
- * WordPress dependencies.
19
+ * WordPress dependencies
19
20
  */ /**
20
21
  * Internal dependencies
21
- */ /**
22
+ */
23
+ var useLocation = _router["default"].useLocation;
24
+
25
+ /**
22
26
  * External dependencies
23
- */ /**
27
+ */
28
+
29
+ /**
30
+ * Derives the active-tab breadcrumb trail from the current route. Only rendered
31
+ * for tabbed wizards, which always mount inside a Router, so calling useLocation
32
+ * here keeps router-free consumers (e.g. standalone multibranded) from crashing.
33
+ *
34
+ * @param {Object} props Component props.
35
+ * @param {Array} props.sections Tabbed navigation sections.
36
+ * @param {Function} props.render Renders the page given the breadcrumb trail.
37
+ * @return {JSX.Element} The rendered page.
38
+ */
39
+ var RouteBreadcrumbs = function RouteBreadcrumbs(_ref) {
40
+ var sections = _ref.sections,
41
+ render = _ref.render;
42
+ var _useLocation = useLocation(),
43
+ pathname = _useLocation.pathname;
44
+ return render((0, _breadcrumbsSelect.activeBreadcrumbs)(sections, pathname));
45
+ };
46
+
47
+ /**
24
48
  * Higher-Order Component to provide plugin management and error handling to Newspack Wizards.
25
49
  */
26
50
  function withWizardScreen(WrappedComponent) {
27
- var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
28
- hidePrimaryButton = _ref.hidePrimaryButton;
51
+ var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
52
+ hidePrimaryButton = _ref2.hidePrimaryButton,
53
+ hideHeader = _ref2.hideHeader;
29
54
  var WrappedWithWizardScreen = function WrappedWithWizardScreen(props) {
30
55
  var className = props.className,
31
56
  buttonText = props.buttonText,
@@ -34,6 +59,8 @@ function withWizardScreen(WrappedComponent) {
34
59
  headerText = props.headerText,
35
60
  subHeaderText = props.subHeaderText,
36
61
  tabbedNavigation = props.tabbedNavigation,
62
+ breadcrumbItems = props.breadcrumbItems,
63
+ headerActions = props.headerActions,
37
64
  secondaryButtonText = props.secondaryButtonText,
38
65
  secondaryButtonAction = props.secondaryButtonAction,
39
66
  renderAboveContent = props.renderAboveContent,
@@ -59,40 +86,14 @@ function withWizardScreen(WrappedComponent) {
59
86
  children: buttonText
60
87
  }, retrievedButtonProps), overridingProps));
61
88
  };
62
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
63
- children: [newspack_aux_data.is_debug_mode && /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Notice, {
64
- debugMode: true
65
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
66
- className: "newspack-wizard__header",
67
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
68
- className: "newspack-wizard__header__inner",
69
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
70
- className: "newspack-wizard__title",
71
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_.Button, {
72
- isLink: true,
73
- href: newspack_urls.dashboard,
74
- label: (0, _i18n.__)('Return to Dashboard', 'newspack-plugin'),
75
- showTooltip: true,
76
- icon: _icons.category,
77
- iconSize: 36,
78
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_.NewspackIcon, {
79
- size: 36
80
- })
81
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
82
- children: [headerText && /*#__PURE__*/(0, _jsxRuntime.jsx)("h2", {
83
- children: headerText
84
- }), subHeaderText && /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
85
- children: subHeaderText
86
- })]
87
- })]
88
- })
89
- })
90
- }), tabbedNavigation && /*#__PURE__*/(0, _jsxRuntime.jsx)(_.TabbedNavigation, {
91
- disableUpcoming: disableUpcomingInTabbedNavigation,
92
- items: tabbedNavigation.filter(function (item) {
93
- return !item.isHiddenInNav;
94
- })
95
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_.HandoffMessage, {}), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
89
+ var tabbedNavigationRegion = tabbedNavigation && /*#__PURE__*/(0, _jsxRuntime.jsx)(_.TabbedNavigation, {
90
+ disableUpcoming: disableUpcomingInTabbedNavigation,
91
+ items: tabbedNavigation.filter(function (item) {
92
+ return !item.isHiddenInNav;
93
+ })
94
+ });
95
+ var content = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
96
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_.HandoffMessage, {}), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
96
97
  className: (0, _classnames["default"])('newspack-wizard newspack-wizard__content', className),
97
98
  children: [typeof renderAboveContent === 'function' ? renderAboveContent() : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(WrappedComponent, _objectSpread(_objectSpread({}, props), {}, {
98
99
  renderPrimaryButton: renderPrimaryButton
@@ -106,6 +107,46 @@ function withWizardScreen(WrappedComponent) {
106
107
  })]
107
108
  })]
108
109
  });
110
+ var renderPage = function renderPage(crumbs) {
111
+ var pageBreadcrumbs = crumbs !== null && crumbs !== void 0 ? crumbs : [];
112
+ if (!pageBreadcrumbs.length && headerText) {
113
+ pageBreadcrumbs = [{
114
+ label: headerText
115
+ }];
116
+ }
117
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
118
+ children: [newspack_aux_data.is_debug_mode && /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Notice, {
119
+ debugMode: true
120
+ }), hideHeader ?
121
+ /*#__PURE__*/
122
+ // Without the Page shell the tabs still own the content: it
123
+ // renders inside the active tab's panel.
124
+ (0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
125
+ children: tabbedNavigationRegion ? (0, _element.cloneElement)(tabbedNavigationRegion, {
126
+ content: content
127
+ }) : content
128
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Page, {
129
+ breadcrumbItems: pageBreadcrumbs,
130
+ subTitle: subHeaderText,
131
+ actions: headerActions,
132
+ tabbedNavigation: tabbedNavigationRegion,
133
+ children: content
134
+ })]
135
+ });
136
+ };
137
+ if (hideHeader) {
138
+ return renderPage();
139
+ }
140
+ if (breadcrumbItems) {
141
+ return renderPage(breadcrumbItems);
142
+ }
143
+ if (tabbedNavigation) {
144
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(RouteBreadcrumbs, {
145
+ sections: tabbedNavigation,
146
+ render: renderPage
147
+ });
148
+ }
149
+ return renderPage();
109
150
  };
110
151
  return WrappedWithWizardScreen;
111
152
  }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _react = require("@testing-library/react");
5
+ var _reactRouterDom = require("react-router-dom");
6
+ var _ = _interopRequireDefault(require("./"));
7
+ var _jsxRuntime = require("react/jsx-runtime");
8
+ /**
9
+ * External dependencies.
10
+ */
11
+
12
+ /**
13
+ * Internal dependencies.
14
+ */
15
+
16
+ global.newspack_aux_data = {
17
+ is_debug_mode: false
18
+ };
19
+ describe('withWizardScreen', function () {
20
+ it('falls back to a single headerText breadcrumb when no breadcrumbItems are provided', function () {
21
+ var WrappedComponent = function WrappedComponent() {
22
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
23
+ children: "Body content"
24
+ });
25
+ };
26
+ var ScreenWithHeader = (0, _["default"])(WrappedComponent);
27
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactRouterDom.HashRouter, {
28
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(ScreenWithHeader, {
29
+ headerText: "Brands"
30
+ })
31
+ }));
32
+ expect(_react.screen.getByRole('heading', {
33
+ level: 1
34
+ })).toHaveTextContent('Brands');
35
+ });
36
+ it('renders without a Router when no tabbed navigation is provided', function () {
37
+ var WrappedComponent = function WrappedComponent() {
38
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
39
+ children: "Body content"
40
+ });
41
+ };
42
+ var ScreenWithHeader = (0, _["default"])(WrappedComponent);
43
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(ScreenWithHeader, {
44
+ headerText: "Brands"
45
+ }));
46
+ expect(_react.screen.getByRole('heading', {
47
+ level: 1
48
+ })).toHaveTextContent('Brands');
49
+ });
50
+ });
@@ -45,129 +45,12 @@
45
45
  }
46
46
  }
47
47
 
48
- &__header {
49
- align-items: center;
50
- background: white;
51
- border-bottom: 1px solid wp-colors.$gray-300;
52
- display: flex;
53
- .newspack-wizard__fixed-header & {
54
- position: sticky;
55
- top: 0;
56
- width: 100%;
57
- z-index: 1000;
58
- .admin-bar & {
59
- @media only screen and ( min-width: 601px ) {
60
- top: 46px;
61
- }
62
- @media only screen and ( min-width: 782px ) {
63
- top: 32px;
64
- }
65
- }
66
- }
67
- &__inner {
68
- flex: 1 1 100%;
69
- }
70
- &__actions {
71
- align-items: center;
72
- display: flex;
73
- gap: 8px;
74
- justify-content: flex-end;
75
- padding: 0 24px 0 0;
76
- > .newspack-wizard__header__actions__main {
77
- display: none;
78
- }
79
- @media only screen and ( min-width: 782px ) {
80
- flex: 1 1 auto;
81
- > .newspack-wizard__header__actions__main {
82
- display: flex;
83
- }
84
- &__more {
85
- &--primary-only,
86
- .newspack-wizard__header__actions__more__main {
87
- display: none;
88
- }
89
- }
90
- }
91
- }
92
- }
93
-
94
48
  &__main {
95
- overflow-x: hidden;
49
+ overflow: hidden;
96
50
  padding-bottom: 1px; /* Prevents borders from being cut off */
97
51
  }
98
52
 
99
53
 
100
- &__title {
101
- align-items: center;
102
- display: flex;
103
-
104
- h2 {
105
- margin: 0;
106
- padding: 0;
107
- }
108
-
109
- > div {
110
- align-items: baseline;
111
- display: flex;
112
- padding: 0 24px;
113
-
114
- > span {
115
- color: wp-colors.$gray-700;
116
- display: none;
117
- margin-left: 8px;
118
-
119
- @media screen and ( min-width: 744px ) {
120
- display: block;
121
- }
122
- }
123
- }
124
-
125
- svg {
126
- fill: white;
127
- margin: 0 !important;
128
-
129
- &.newspack-icon {
130
- flex: 0 0 36px;
131
- margin-bottom: -1px !important;
132
- }
133
-
134
- &:not(.newspack-icon) {
135
- background: var(--wp-admin-theme-color);
136
- left: 50%;
137
- margin: -28px 0 0 -28px !important;
138
- opacity: 0;
139
- padding: 10px;
140
- position: absolute;
141
- top: 50%;
142
- transition: opacity 125ms ease-in-out;
143
- }
144
- }
145
-
146
- .components-button.has-icon {
147
- padding: 0;
148
- position: relative;
149
-
150
- &:hover {
151
- svg {
152
- opacity: 1;
153
- }
154
- }
155
-
156
- &:focus-visible {
157
- outline: none !important;
158
-
159
- &::before {
160
- border: 2px solid white;
161
- border-radius: 2px;
162
- content: "";
163
- display: block;
164
- inset: 6px 6px 5px;
165
- position: absolute;
166
- }
167
- }
168
- }
169
- }
170
-
171
54
  &__section-header {
172
55
  margin: 0 auto 32px;
173
56
  max-width: calc(calc(var(--newspack-wizard-section-space) * 2) + var(--newspack-wizard-section-width));
@@ -182,6 +65,7 @@
182
65
 
183
66
  &__content {
184
67
  margin: 0 auto;
68
+ width: 100%;
185
69
  max-width: calc(calc(var(--newspack-wizard-section-space) * 2) + var(--newspack-wizard-section-width));
186
70
  padding: calc(var(--newspack-wizard-section-space) * 2) var(--newspack-wizard-section-space) 0;
187
71
 
@@ -225,3 +109,16 @@
225
109
  margin: 0;
226
110
  }
227
111
  }
112
+
113
+ /**
114
+ * Wizard header overflow ("More") menu, rendered by the Wizard component into
115
+ * admin-ui's Page actions slot. Hide the toggle when there are no overflow
116
+ * actions, and hide the duplicated primary items inside the menu on wide
117
+ * viewports.
118
+ */
119
+ @media only screen and ( min-width: 782px ) {
120
+ .newspack-wizard__actions__more--primary-only,
121
+ .newspack-wizard__actions__more .newspack-wizard__actions__more__main {
122
+ display: none;
123
+ }
124
+ }