newspack-components 4.11.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.
Files changed (66) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/DEVELOPMENT.md +79 -38
  3. package/dist/cjs/breadcrumbs/index.js +1 -0
  4. package/dist/cjs/breadcrumbs/style.scss +3 -10
  5. package/dist/cjs/card/style-core.scss +1 -1
  6. package/dist/cjs/card-sortable-list/index.js +17 -9
  7. package/dist/cjs/drawer/body.js +4 -6
  8. package/dist/cjs/drawer/content.js +7 -37
  9. package/dist/cjs/drawer/footer.js +10 -1
  10. package/dist/cjs/drawer/header.js +9 -1
  11. package/dist/cjs/drawer/index.test.js +3 -4
  12. package/dist/cjs/drawer/slots.test.js +25 -67
  13. package/dist/cjs/drawer/style.scss +0 -18
  14. package/dist/cjs/index.js +7 -0
  15. package/dist/cjs/page/index.js +10 -2
  16. package/dist/cjs/page/style.scss +24 -2
  17. package/dist/cjs/tabbed-navigation/style.scss +5 -0
  18. package/dist/cjs/tooltip-badge/index.js +50 -0
  19. package/dist/cjs/tooltip-badge/index.test.js +30 -0
  20. package/dist/cjs/wizard/index.js +21 -8
  21. package/dist/cjs/wizard/index.test.js +78 -0
  22. package/dist/cjs/wizard/store/index.js +2 -1
  23. package/dist/esm/breadcrumbs/index.js +1 -0
  24. package/dist/esm/breadcrumbs/style.scss +3 -10
  25. package/dist/esm/card/style-core.scss +1 -1
  26. package/dist/esm/card-sortable-list/index.js +20 -11
  27. package/dist/esm/drawer/body.js +4 -5
  28. package/dist/esm/drawer/content.js +7 -36
  29. package/dist/esm/drawer/footer.js +10 -1
  30. package/dist/esm/drawer/header.js +9 -1
  31. package/dist/esm/drawer/index.test.js +3 -4
  32. package/dist/esm/drawer/slots.test.js +25 -67
  33. package/dist/esm/drawer/style.scss +0 -18
  34. package/dist/esm/index.js +1 -0
  35. package/dist/esm/page/index.js +10 -2
  36. package/dist/esm/page/style.scss +24 -2
  37. package/dist/esm/tabbed-navigation/style.scss +5 -0
  38. package/dist/esm/tooltip-badge/index.js +43 -0
  39. package/dist/esm/tooltip-badge/index.test.js +26 -0
  40. package/dist/esm/wizard/index.js +23 -12
  41. package/dist/esm/wizard/index.test.js +78 -0
  42. package/dist/esm/wizard/store/index.js +2 -1
  43. package/package.json +2 -2
  44. package/src/breadcrumbs/index.js +1 -1
  45. package/src/breadcrumbs/style.scss +3 -10
  46. package/src/card/style-core.scss +1 -1
  47. package/src/card-form/README.md +2 -2
  48. package/src/card-sortable-list/index.tsx +27 -11
  49. package/src/drawer/README.md +10 -16
  50. package/src/drawer/body.tsx +4 -5
  51. package/src/drawer/content.tsx +7 -33
  52. package/src/drawer/footer.tsx +8 -1
  53. package/src/drawer/header.tsx +8 -1
  54. package/src/drawer/index.test.js +3 -4
  55. package/src/drawer/slots.test.js +14 -48
  56. package/src/drawer/style.scss +0 -18
  57. package/src/drawer/types.ts +8 -3
  58. package/src/index.js +1 -0
  59. package/src/page/index.js +7 -3
  60. package/src/page/style.scss +24 -2
  61. package/src/tabbed-navigation/style.scss +5 -0
  62. package/src/tooltip-badge/index.test.js +24 -0
  63. package/src/tooltip-badge/index.tsx +40 -0
  64. package/src/wizard/index.js +25 -14
  65. package/src/wizard/index.test.js +38 -0
  66. package/src/wizard/store/index.js +1 -0
@@ -7,23 +7,24 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
7
7
  * Card - Sortable list component.
8
8
  */
9
9
 
10
+ /**
11
+ * External dependencies
12
+ */
13
+ import classNames from 'classnames';
14
+
10
15
  /**
11
16
  * WordPress dependencies.
12
17
  */
13
- import { Disabled, Draggable, __experimentalVStack as VStack } from '@wordpress/components'; // eslint-disable-line @wordpress/no-unsafe-wp-apis
18
+ import { Disabled, Draggable } from '@wordpress/components';
14
19
  import { useEffect, useLayoutEffect, useRef, useState } from '@wordpress/element';
15
- import { Badge } from '@wordpress/ui';
20
+ import { Badge, Stack } from '@wordpress/ui';
16
21
 
17
22
  /**
18
23
  * Internal dependencies
19
24
  */
20
25
  import Card from '../card';
26
+ import TooltipBadge from '../tooltip-badge';
21
27
  import './style.scss';
22
-
23
- /**
24
- * External dependencies
25
- */
26
- import classNames from 'classnames';
27
28
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
28
29
  var DROP_ANIMATION_DURATION = 400; // ms — must match $drop-duration in style.scss
29
30
  var BUTTON_MOVE_DURATION = 200; // ms — must match $shift-duration in style.scss
@@ -346,13 +347,14 @@ var CardSortableList = function CardSortableList(_ref) {
346
347
  return 0;
347
348
  };
348
349
  var isDragging = draggingIndex !== null;
349
- return /*#__PURE__*/_jsx(VStack, {
350
+ return /*#__PURE__*/_jsx(Stack, {
351
+ direction: "column",
352
+ gap: "lg",
350
353
  ref: listRef,
351
354
  className: classNames('newspack-card--core--sortable-list', disabled && 'newspack-card--core--sortable-list__is-disabled', isDragging && 'newspack-card--core--sortable-list__is-dragging'),
352
355
  style: measurements ? {
353
356
  height: measurements.lockedHeight
354
357
  } : undefined,
355
- spacing: 4,
356
358
  children: sortedItems.map(function (item, index) {
357
359
  var translateY = getTranslateY(index);
358
360
  return /*#__PURE__*/_jsx(Disabled, {
@@ -384,7 +386,7 @@ var CardSortableList = function CardSortableList(_ref) {
384
386
  onDragEnd: handleDragEnd,
385
387
  appendToOwnerDocument: true,
386
388
  children: function children(_ref2) {
387
- var _item$badge, _item$badge$intent;
389
+ var _item$badge, _item$badge$intent, _item$secondaryBadge, _item$secondaryBadge$;
388
390
  var onDraggableStart = _ref2.onDraggableStart,
389
391
  onDraggableEnd = _ref2.onDraggableEnd;
390
392
  return /*#__PURE__*/_jsx(Card, {
@@ -399,7 +401,14 @@ var CardSortableList = function CardSortableList(_ref) {
399
401
  children: [item.title, ((_item$badge = item.badge) === null || _item$badge === void 0 ? void 0 : _item$badge.label) && /*#__PURE__*/_jsx(Badge, {
400
402
  intent: (_item$badge$intent = item.badge.intent) !== null && _item$badge$intent !== void 0 ? _item$badge$intent : 'none',
401
403
  children: item.badge.label
402
- })]
404
+ }), ((_item$secondaryBadge = item.secondaryBadge) === null || _item$secondaryBadge === void 0 ? void 0 : _item$secondaryBadge.label) && (item.secondaryBadge.tooltip ? /*#__PURE__*/_jsx(TooltipBadge, {
405
+ label: item.secondaryBadge.label,
406
+ tooltip: item.secondaryBadge.tooltip,
407
+ intent: item.secondaryBadge.intent
408
+ }) : /*#__PURE__*/_jsx(Badge, {
409
+ intent: (_item$secondaryBadge$ = item.secondaryBadge.intent) !== null && _item$secondaryBadge$ !== void 0 ? _item$secondaryBadge$ : 'none',
410
+ children: item.secondaryBadge.label
411
+ }))]
403
412
  }), item.description && /*#__PURE__*/_jsx("p", {
404
413
  children: item.description
405
414
  })]
@@ -2,9 +2,9 @@ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
2
  /**
3
3
  * WordPress dependencies.
4
4
  */
5
- import { __experimentalVStack as VStack } from '@wordpress/components'; // eslint-disable-line @wordpress/no-unsafe-wp-apis
6
5
  import { useEffect, useState } from '@wordpress/element';
7
6
  import { __ } from '@wordpress/i18n';
7
+ import { Stack } from '@wordpress/ui';
8
8
 
9
9
  /**
10
10
  * Internal dependencies.
@@ -54,11 +54,10 @@ var Body = function Body(_ref) {
54
54
  mutation.disconnect();
55
55
  };
56
56
  }, [node]);
57
- return /*#__PURE__*/_jsx(VStack, {
57
+ return /*#__PURE__*/_jsx(Stack, {
58
58
  ref: setNode,
59
- className: "newspack-drawer__body",
60
- spacing: 0,
61
- justify: "flex-start"
59
+ direction: "column",
60
+ className: "newspack-drawer__body"
62
61
  // A bare div is role=generic, where ARIA prohibits an author name.
63
62
  ,
64
63
  role: isScrollable ? 'group' : undefined,
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies.
3
3
  */
4
- import { __experimentalVStack as VStack } from '@wordpress/components'; // eslint-disable-line @wordpress/no-unsafe-wp-apis
5
- import { Children, isValidElement } from '@wordpress/element';
4
+ import { Stack } from '@wordpress/ui';
6
5
 
7
6
  /**
8
7
  * External dependencies.
@@ -13,51 +12,23 @@ import classnames from 'classnames';
13
12
  * Internal dependencies.
14
13
  */
15
14
  import { jsx as _jsx } from "react/jsx-runtime";
16
- // VStack drops non-elements, a lone string aside. A run shares one wrapper so
17
- // `Edited by { name }` is one row, not three.
18
- var asRows = function asRows(children) {
19
- if ('string' === typeof children) {
20
- return children;
21
- }
22
- var rows = [];
23
- var text = [];
24
- var flushText = function flushText() {
25
- if (text.some(function (part) {
26
- return '' !== String(part).trim();
27
- })) {
28
- rows.push(/*#__PURE__*/_jsx("div", {
29
- children: text
30
- }, "text-".concat(rows.length)));
31
- }
32
- text = [];
33
- };
34
- Children.toArray(children).forEach(function (child) {
35
- if (isValidElement(child)) {
36
- flushText();
37
- rows.push(child);
38
- } else {
39
- text.push(child);
40
- }
41
- });
42
- flushText();
43
- return rows;
44
- };
45
15
  var Content = function Content(_ref) {
46
16
  var _ref$padding = _ref.padding,
47
17
  padding = _ref$padding === void 0 ? 6 : _ref$padding,
48
18
  _ref$gap = _ref.gap,
49
- gap = _ref$gap === void 0 ? 4 : _ref$gap,
19
+ gap = _ref$gap === void 0 ? 'lg' : _ref$gap,
50
20
  className = _ref.className,
51
21
  children = _ref.children;
52
- return /*#__PURE__*/_jsx(VStack, {
53
- className: classnames('newspack-drawer__content', className),
54
- spacing: gap
22
+ return /*#__PURE__*/_jsx(Stack, {
23
+ direction: "column",
24
+ gap: gap,
25
+ className: classnames('newspack-drawer__content', className)
55
26
  // A custom property, not inline padding, so the stylesheet's seam rules win.
56
27
  ,
57
28
  style: {
58
29
  '--newspack-drawer-content-padding': "".concat(padding * 4, "px")
59
30
  },
60
- children: asRows(children)
31
+ children: children
61
32
  });
62
33
  };
63
34
  export default Content;
@@ -1,3 +1,8 @@
1
+ /**
2
+ * WordPress dependencies.
3
+ */
4
+ import { Stack } from '@wordpress/ui';
5
+
1
6
  /**
2
7
  * External dependencies.
3
8
  */
@@ -10,7 +15,11 @@ import { jsx as _jsx } from "react/jsx-runtime";
10
15
  var Footer = function Footer(_ref) {
11
16
  var className = _ref.className,
12
17
  children = _ref.children;
13
- return /*#__PURE__*/_jsx("div", {
18
+ return /*#__PURE__*/_jsx(Stack, {
19
+ direction: "row",
20
+ justify: "flex-end",
21
+ wrap: "wrap",
22
+ gap: "sm",
14
23
  className: classnames('newspack-drawer__footer', className),
15
24
  children: children
16
25
  });
@@ -1,3 +1,8 @@
1
+ /**
2
+ * WordPress dependencies.
3
+ */
4
+ import { Stack } from '@wordpress/ui';
5
+
1
6
  /**
2
7
  * External dependencies.
3
8
  */
@@ -10,7 +15,10 @@ import { jsx as _jsx } from "react/jsx-runtime";
10
15
  var Header = function Header(_ref) {
11
16
  var className = _ref.className,
12
17
  children = _ref.children;
13
- return /*#__PURE__*/_jsx("div", {
18
+ return /*#__PURE__*/_jsx(Stack, {
19
+ direction: "row",
20
+ align: "center",
21
+ gap: "sm",
14
22
  className: classnames('newspack-drawer__header', className),
15
23
  children: children
16
24
  });
@@ -429,16 +429,15 @@ describe('Drawer sections', function () {
429
429
  });
430
430
 
431
431
  // The `> * { flex: none }` rule that stops sections compressing depends on this.
432
- it('lays the scroll container out as a flush VStack', function () {
432
+ it('lays the scroll container out as a flush column', function () {
433
433
  renderDrawer({
434
434
  contents: [/*#__PURE__*/_jsx(Drawer.Content, {
435
435
  children: "One"
436
436
  }, "one")]
437
437
  });
438
438
  var body = bodyOf(screen.getByText('One'));
439
- expect(body).toHaveClass('components-v-stack');
440
- expect(window.getComputedStyle(body).gap).toBe('0');
441
- expect(window.getComputedStyle(body).justifyContent).toBe('flex-start');
439
+ expect(body.style.flexDirection).toBe('column');
440
+ expect(body.style.gap).toBe('');
442
441
  });
443
442
  it('starts a new container after a non-content child', function () {
444
443
  renderDrawer({
@@ -132,86 +132,35 @@ describe('Drawer.Content', function () {
132
132
  container = _render2.container;
133
133
  expect(sectionOf(container).style.getPropertyValue('--newspack-drawer-content-padding')).toBe('0px');
134
134
  });
135
- it('renders each section as a VStack', function () {
135
+ it('spaces its children by the lg gap token, and by the gap prop', function () {
136
136
  var _render3 = render(/*#__PURE__*/_jsx(Content, {
137
137
  children: "stacked"
138
138
  })),
139
- container = _render3.container;
140
- expect(sectionOf(container)).toHaveClass('newspack-drawer__content', 'components-v-stack');
141
- });
142
-
143
- // VStack emits its spacing as a `calc()` on the 4px base, not as pixels.
144
- it('spaces its children by 16px, and by the gap prop', function () {
145
- var _render4 = render(/*#__PURE__*/_jsx(Content, {
146
- children: "stacked"
147
- })),
148
- container = _render4.container,
149
- rerender = _render4.rerender;
150
- expect(window.getComputedStyle(sectionOf(container)).gap).toBe('calc(4px * 4)');
139
+ container = _render3.container,
140
+ rerender = _render3.rerender;
141
+ expect(sectionOf(container).style.gap).toContain('gap-lg');
151
142
  rerender(/*#__PURE__*/_jsx(Content, {
152
- gap: 2,
143
+ gap: "sm",
153
144
  children: "stacked"
154
145
  }));
155
- expect(window.getComputedStyle(sectionOf(container)).gap).toBe('calc(4px * 2)');
146
+ expect(sectionOf(container).style.gap).toContain('gap-sm');
156
147
  });
157
-
158
- // VStack keeps only elements, so these would otherwise vanish without warning.
159
148
  it('keeps plain text sitting beside an element', function () {
160
- render(/*#__PURE__*/_jsxs(Content, {
161
- children: ["Lead text", /*#__PURE__*/_jsx("span", {
162
- children: "an element"
163
- }), 42]
164
- }));
165
- expect(screen.getByText('Lead text')).toBeInTheDocument();
166
- expect(screen.getByText('an element')).toBeInTheDocument();
167
- expect(screen.getByText('42')).toBeInTheDocument();
168
- });
169
- it('keeps a run of text and interpolations on one row', function () {
170
- var _render5 = render(/*#__PURE__*/_jsxs(Content, {
171
- children: ["Edited by ", 'Ada', " just now"]
172
- })),
173
- container = _render5.container;
174
- var rows = sectionOf(container).children;
175
- expect(rows).toHaveLength(1);
176
- expect(rows[0]).toHaveTextContent('Edited by Ada just now');
177
- });
178
- it('starts a new row either side of an element', function () {
179
- var _render6 = render(/*#__PURE__*/_jsxs(Content, {
180
- children: ["before", /*#__PURE__*/_jsx("span", {
181
- children: "middle"
182
- }), "after"]
183
- })),
184
- container = _render6.container;
185
- expect(Array.from(sectionOf(container).children).map(function (row) {
186
- return row.textContent;
187
- })).toEqual(['before', 'middle', 'after']);
188
- });
189
- it('emits no row for whitespace or empty text between elements', function () {
190
- var _render7 = render(/*#__PURE__*/_jsxs(Content, {
191
- children: [/*#__PURE__*/_jsx("span", {
192
- children: "one"
193
- }), " ", '', /*#__PURE__*/_jsx("span", {
194
- children: "two"
195
- })]
149
+ var _render4 = render(/*#__PURE__*/_jsxs(Content, {
150
+ children: ["Lead text", /*#__PURE__*/_jsx("span", {
151
+ children: "an element"
152
+ }), 42]
196
153
  })),
197
- container = _render7.container;
198
- expect(Array.from(sectionOf(container).children).map(function (row) {
199
- return row.textContent;
200
- })).toEqual(['one', 'two']);
201
- });
202
- it('keeps a lone string', function () {
203
- render(/*#__PURE__*/_jsx(Content, {
204
- children: "on its own"
205
- }));
206
- expect(screen.getByText('on its own')).toBeInTheDocument();
154
+ container = _render4.container;
155
+ expect(sectionOf(container)).toHaveTextContent('Lead textan element42');
207
156
  });
208
157
  });
209
158
  describe('Drawer.Divider', function () {
210
159
  it('renders a separator, merging className', function () {
211
- var _render8 = render(/*#__PURE__*/_jsx(Divider, {
160
+ var _render5 = render(/*#__PURE__*/_jsx(Divider, {
212
161
  className: "custom"
213
162
  })),
214
- container = _render8.container;
163
+ container = _render5.container;
215
164
  var divider = container.querySelector('hr');
216
165
  expect(divider).toHaveClass('newspack-drawer__divider', 'custom');
217
166
  expect(screen.getByRole('separator')).toBe(divider);
@@ -224,8 +173,17 @@ describe('Drawer.Footer', function () {
224
173
  }));
225
174
  expect(screen.getByText('actions')).toHaveClass('newspack-drawer__footer');
226
175
  });
176
+ it('lays its actions out in one end-aligned row that wraps', function () {
177
+ render(/*#__PURE__*/_jsx(Footer, {
178
+ children: "actions"
179
+ }));
180
+ var footer = screen.getByText('actions');
181
+ expect(footer.style.flexDirection).toBe('row');
182
+ expect(footer.style.justifyContent).toBe('flex-end');
183
+ expect(footer.style.flexWrap).toBe('wrap');
184
+ });
227
185
  it('renders its actions as direct children', function () {
228
- var _render9 = render(/*#__PURE__*/_jsxs(Footer, {
186
+ var _render6 = render(/*#__PURE__*/_jsxs(Footer, {
229
187
  children: [/*#__PURE__*/_jsx(Action, {
230
188
  children: "One"
231
189
  }), /*#__PURE__*/_jsx(Action, {
@@ -234,7 +192,7 @@ describe('Drawer.Footer', function () {
234
192
  children: "Three"
235
193
  })]
236
194
  })),
237
- container = _render9.container;
195
+ container = _render6.container;
238
196
  var footer = container.querySelector('.newspack-drawer__footer');
239
197
  expect(Array.from(footer.children)).toEqual([screen.getByRole('button', {
240
198
  name: 'One'
@@ -80,10 +80,7 @@ $drawer-size-x-large: 640px;
80
80
  }
81
81
 
82
82
  .newspack-drawer__header {
83
- align-items: center;
84
- display: flex;
85
83
  flex: 0 0 auto;
86
- gap: wp-vars.$grid-unit-10;
87
84
  padding: wp-vars.$grid-unit-30 wp-vars.$grid-unit-30 wp-vars.$grid-unit-20;
88
85
  }
89
86
 
@@ -139,23 +136,8 @@ $drawer-size-x-large: 640px;
139
136
 
140
137
  .newspack-drawer__footer {
141
138
  background: wp-colors.$white;
142
- display: flex;
143
139
  flex: 0 0 auto;
144
- gap: wp-vars.$grid-unit-10;
145
140
  padding: wp-vars.$grid-unit-20 wp-vars.$grid-unit-30 wp-vars.$grid-unit-30;
146
-
147
- > .components-button {
148
- flex: 1;
149
- justify-content: center;
150
- }
151
-
152
- &:has(> :nth-child(3)) {
153
- flex-direction: column;
154
-
155
- > .components-button {
156
- flex: 0 0 auto;
157
- }
158
- }
159
141
  }
160
142
 
161
143
  @keyframes newspack-drawer-slide-in {
package/dist/esm/index.js CHANGED
@@ -51,6 +51,7 @@ export { default as StyleCard } from './style-card';
51
51
  export { default as TabbedNavigation } from './tabbed-navigation';
52
52
  export { default as TableCard } from './table-card';
53
53
  export { default as TextControl } from './text-control';
54
+ export { default as TooltipBadge } from './tooltip-badge';
54
55
  export { default as Waiting } from './waiting';
55
56
  export { default as WebPreview } from './web-preview';
56
57
  export { default as Wizard } from './wizard';
@@ -66,11 +66,13 @@ var Page = function Page(_ref) {
66
66
  direction: "row",
67
67
  gap: "sm",
68
68
  justify: "space-between",
69
+ wrap: "wrap",
69
70
  children: [/*#__PURE__*/_jsxs(Stack, {
70
71
  direction: "row",
71
72
  gap: "sm",
72
- align: "center",
73
+ align: "start",
73
74
  justify: "start",
75
+ className: "newspack-page__header-title",
74
76
  children: [/*#__PURE__*/_jsx("div", {
75
77
  className: "newspack-page__header-visual",
76
78
  "aria-hidden": "true",
@@ -83,7 +85,13 @@ var Page = function Page(_ref) {
83
85
  children: /*#__PURE__*/_jsx(Breadcrumbs, {
84
86
  items: breadcrumbItems
85
87
  })
86
- }), badges]
88
+ }), badges && /*#__PURE__*/_jsx(Stack, {
89
+ direction: "row",
90
+ gap: "sm",
91
+ align: "center",
92
+ className: "newspack-page__header-badges",
93
+ children: badges
94
+ })]
87
95
  }), actions && /*#__PURE__*/_jsx(Stack, {
88
96
  direction: "row",
89
97
  gap: "sm",
@@ -56,8 +56,29 @@
56
56
  padding: var(--wpds-dimension-padding-lg) var(--wpds-dimension-padding-2xl);
57
57
  }
58
58
 
59
+ .newspack-page__header-title {
60
+ min-width: 0;
61
+ }
62
+
59
63
  .newspack-page__header-actions {
64
+ flex-basis: 100%;
65
+ flex-shrink: 0;
66
+ justify-content: flex-end;
67
+ margin-inline-start: auto;
68
+
69
+ @include wp-mixins.break-medium {
70
+ flex-basis: auto;
71
+ }
72
+
73
+ &:empty,
74
+ &:has(> :only-child:empty) {
75
+ display: none;
76
+ }
77
+ }
78
+
79
+ .newspack-page__header-badges {
60
80
  flex-shrink: 0;
81
+ min-height: wp-vars.$button-size;
61
82
  }
62
83
 
63
84
  .newspack-page__header-subtitle {
@@ -68,7 +89,7 @@
68
89
  .newspack-page__header-visual {
69
90
  display: grid;
70
91
  flex-shrink: 0;
71
- height: 24px;
92
+ height: wp-vars.$button-size;
72
93
  place-items: center;
73
94
  width: 24px;
74
95
 
@@ -80,5 +101,6 @@
80
101
  }
81
102
 
82
103
  .newspack-page__breadcrumbs {
83
- min-height: wp-vars.$button-size;
104
+ min-width: 0;
105
+ padding-block: calc((#{wp-vars.$button-size} - var(--wpds-typography-line-height-md)) / 2);
84
106
  }
@@ -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
+ });