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.
- package/CHANGELOG.md +40 -0
- package/DEVELOPMENT.md +1 -1
- package/dist/cjs/accordion/index.js +43 -26
- package/dist/cjs/accordion/index.test.js +80 -0
- package/dist/cjs/accordion/style.scss +25 -21
- package/dist/cjs/action-card/style.scss +0 -22
- package/dist/cjs/breadcrumbs/index.js +80 -0
- package/dist/cjs/breadcrumbs/index.test.js +109 -0
- package/dist/cjs/breadcrumbs/style.scss +41 -0
- package/dist/cjs/card/core-card.js +8 -4
- package/dist/cjs/card/index.js +1 -1
- package/dist/cjs/card/style-core.scss +14 -0
- package/dist/cjs/card/style.scss +0 -9
- package/dist/cjs/card-feature/index.js +25 -13
- package/dist/cjs/card-settings-group/index.js +3 -0
- package/dist/cjs/confirm-dialog/index.js +34 -8
- package/dist/cjs/confirm-dialog/index.test.js +173 -0
- package/dist/cjs/divider/style.scss +4 -2
- package/dist/cjs/grid/style.scss +5 -0
- package/dist/cjs/handoff/index.js +8 -5
- package/dist/cjs/index.js +34 -1
- package/dist/cjs/integration-icon/index.js +40 -0
- package/dist/cjs/integration-icon/style.scss +42 -0
- package/dist/cjs/integration-icons/index.js +21 -2
- package/dist/cjs/modal/style.scss +4 -0
- package/dist/cjs/page/index.js +121 -0
- package/dist/cjs/page/index.test.js +69 -0
- package/dist/cjs/page/style.scss +86 -0
- package/dist/cjs/route-match.js +59 -0
- package/dist/cjs/route-match.test.js +77 -0
- package/dist/cjs/section-header/index.js +8 -1
- package/dist/cjs/section-header/style.scss +11 -11
- package/dist/cjs/select-control/GroupedSelectControl.js +1 -1
- package/dist/cjs/select-control/style.scss +4 -0
- package/dist/cjs/style.scss +1 -4
- package/dist/cjs/tabbed-navigation/index.js +188 -40
- package/dist/cjs/tabbed-navigation/index.test.js +299 -0
- package/dist/cjs/tabbed-navigation/style.scss +77 -57
- package/dist/cjs/with-wizard/index.js +34 -45
- package/dist/cjs/with-wizard-screen/index.js +82 -41
- package/dist/cjs/with-wizard-screen/index.test.js +50 -0
- package/dist/cjs/with-wizard-screen/style.scss +15 -118
- package/dist/cjs/wizard/breadcrumbs-select.js +70 -0
- package/dist/cjs/wizard/breadcrumbs-select.test.js +200 -0
- package/dist/cjs/wizard/components/WizardError.js +8 -4
- package/dist/cjs/wizard/index.js +162 -141
- package/dist/esm/accordion/index.js +42 -26
- package/dist/esm/accordion/index.test.js +79 -0
- package/dist/esm/accordion/style.scss +25 -21
- package/dist/esm/action-card/style.scss +0 -22
- package/dist/esm/breadcrumbs/index.js +75 -0
- package/dist/esm/breadcrumbs/index.test.js +105 -0
- package/dist/esm/breadcrumbs/style.scss +41 -0
- package/dist/esm/card/core-card.js +8 -4
- package/dist/esm/card/index.js +1 -1
- package/dist/esm/card/style-core.scss +14 -0
- package/dist/esm/card/style.scss +0 -9
- package/dist/esm/card-feature/index.js +25 -13
- package/dist/esm/card-settings-group/index.js +3 -0
- package/dist/esm/confirm-dialog/index.js +34 -8
- package/dist/esm/confirm-dialog/index.test.js +173 -0
- package/dist/esm/divider/style.scss +4 -2
- package/dist/esm/grid/style.scss +5 -0
- package/dist/esm/handoff/index.js +7 -5
- package/dist/esm/index.js +5 -1
- package/dist/esm/integration-icon/index.js +34 -0
- package/dist/esm/integration-icon/style.scss +42 -0
- package/dist/esm/integration-icons/index.js +22 -1
- package/dist/esm/modal/style.scss +4 -0
- package/dist/esm/page/index.js +113 -0
- package/dist/esm/page/index.test.js +65 -0
- package/dist/esm/page/style.scss +86 -0
- package/dist/esm/route-match.js +51 -0
- package/dist/esm/route-match.test.js +74 -0
- package/dist/esm/section-header/index.js +8 -1
- package/dist/esm/section-header/style.scss +11 -11
- package/dist/esm/select-control/GroupedSelectControl.js +1 -1
- package/dist/esm/select-control/style.scss +4 -0
- package/dist/esm/style.scss +1 -4
- package/dist/esm/tabbed-navigation/index.js +192 -38
- package/dist/esm/tabbed-navigation/index.test.js +296 -0
- package/dist/esm/tabbed-navigation/style.scss +77 -57
- package/dist/esm/with-wizard/index.js +33 -45
- package/dist/esm/with-wizard-screen/index.js +78 -41
- package/dist/esm/with-wizard-screen/index.test.js +46 -0
- package/dist/esm/with-wizard-screen/style.scss +15 -118
- package/dist/esm/wizard/breadcrumbs-select.js +63 -0
- package/dist/esm/wizard/breadcrumbs-select.test.js +197 -0
- package/dist/esm/wizard/components/WizardError.js +7 -5
- package/dist/esm/wizard/index.js +165 -144
- package/package.json +10 -2
- package/src/accordion/index.js +27 -15
- package/src/accordion/index.test.js +62 -0
- package/src/accordion/style.scss +25 -21
- package/src/action-card/style.scss +0 -22
- package/src/breadcrumbs/index.js +63 -0
- package/src/breadcrumbs/index.test.js +59 -0
- package/src/breadcrumbs/style.scss +41 -0
- package/src/card/core-card.js +11 -6
- package/src/card/index.js +0 -1
- package/src/card/style-core.scss +14 -0
- package/src/card/style.scss +0 -9
- package/src/card-feature/README.md +3 -3
- package/src/card-feature/index.tsx +37 -21
- package/src/card-settings-group/index.tsx +4 -0
- package/src/card-sortable-list/index.tsx +1 -1
- package/src/confirm-dialog/index.test.js +142 -0
- package/src/confirm-dialog/index.tsx +34 -7
- package/src/divider/style.scss +4 -2
- package/src/grid/style.scss +5 -0
- package/src/handoff/index.js +4 -3
- package/src/index.js +5 -1
- package/src/integration-icon/index.tsx +35 -0
- package/src/integration-icon/style.scss +42 -0
- package/src/integration-icons/index.js +23 -0
- package/src/modal/style.scss +4 -0
- package/src/page/index.js +89 -0
- package/src/page/index.test.js +43 -0
- package/src/page/style.scss +86 -0
- package/src/route-match.js +47 -0
- package/src/route-match.test.js +50 -0
- package/src/section-header/index.js +7 -3
- package/src/section-header/style.scss +11 -11
- package/src/select-control/GroupedSelectControl.js +1 -1
- package/src/select-control/style.scss +4 -0
- package/src/style.scss +1 -4
- package/src/tabbed-navigation/index.js +181 -34
- package/src/tabbed-navigation/index.test.js +228 -0
- package/src/tabbed-navigation/style.scss +77 -57
- package/src/with-wizard/index.js +18 -39
- package/src/with-wizard-screen/index.js +70 -35
- package/src/with-wizard-screen/index.test.js +36 -0
- package/src/with-wizard-screen/style.scss +15 -118
- package/src/wizard/breadcrumbs-select.js +51 -0
- package/src/wizard/breadcrumbs-select.test.js +124 -0
- package/src/wizard/components/WizardError.js +4 -3
- package/src/wizard/index.js +160 -146
- package/tsconfig.json +7 -0
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
1
|
/**
|
|
3
2
|
* WordPress dependencies
|
|
4
3
|
*/
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { __experimentalVStack as VStack, PanelBody } from '@wordpress/components'; // eslint-disable-line @wordpress/no-unsafe-wp-apis
|
|
5
|
+
import { Children, Fragment, cloneElement } from '@wordpress/element';
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* External dependencies
|
|
@@ -13,35 +12,52 @@ import classNames from 'classnames';
|
|
|
13
12
|
/**
|
|
14
13
|
* Internal dependencies
|
|
15
14
|
*/
|
|
15
|
+
import Divider from '../divider';
|
|
16
16
|
import './style.scss';
|
|
17
17
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
-
var
|
|
18
|
+
export var AccordionPanel = function AccordionPanel(_ref) {
|
|
19
19
|
var children = _ref.children,
|
|
20
|
+
className = _ref.className,
|
|
20
21
|
title = _ref.title,
|
|
21
22
|
_ref$defaultOpen = _ref.defaultOpen,
|
|
22
23
|
defaultOpen = _ref$defaultOpen === void 0 ? false : _ref$defaultOpen;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
24
|
+
return /*#__PURE__*/_jsx(PanelBody, {
|
|
25
|
+
className: className,
|
|
26
|
+
title: title,
|
|
27
|
+
initialOpen: defaultOpen,
|
|
28
|
+
children: children
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
var Accordion = function Accordion(_ref2) {
|
|
32
|
+
var children = _ref2.children,
|
|
33
|
+
className = _ref2.className,
|
|
34
|
+
_ref2$hideSingleTitle = _ref2.hideSingleTitle,
|
|
35
|
+
hideSingleTitle = _ref2$hideSingleTitle === void 0 ? false : _ref2$hideSingleTitle,
|
|
36
|
+
_ref2$spacing = _ref2.spacing,
|
|
37
|
+
spacing = _ref2$spacing === void 0 ? 6 : _ref2$spacing;
|
|
38
|
+
var panels = Children.toArray(children);
|
|
39
|
+
// With nothing to collapse against, a lone panel can render open and untitled.
|
|
40
|
+
if (hideSingleTitle && panels.length === 1) {
|
|
41
|
+
return /*#__PURE__*/_jsx("div", {
|
|
42
|
+
className: classNames('newspack-accordion', className),
|
|
43
|
+
children: cloneElement(panels[0], {
|
|
44
|
+
defaultOpen: true,
|
|
45
|
+
title: undefined
|
|
46
|
+
})
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return /*#__PURE__*/_jsx(VStack, {
|
|
50
|
+
className: classNames('newspack-accordion', className),
|
|
51
|
+
spacing: spacing,
|
|
52
|
+
children: panels.map(function (panel, index) {
|
|
53
|
+
return /*#__PURE__*/_jsxs(Fragment, {
|
|
54
|
+
children: [panel, index < panels.length - 1 && /*#__PURE__*/_jsx(Divider, {
|
|
55
|
+
variant: "secondary",
|
|
56
|
+
marginBottom: 0,
|
|
57
|
+
marginTop: 0
|
|
58
|
+
})]
|
|
59
|
+
}, panel.key);
|
|
60
|
+
})
|
|
45
61
|
});
|
|
46
62
|
};
|
|
47
63
|
export default Accordion;
|
|
@@ -0,0 +1,79 @@
|
|
|
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; }
|
|
4
|
+
/**
|
|
5
|
+
* External dependencies
|
|
6
|
+
*/
|
|
7
|
+
import { render, screen } from '@testing-library/react';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Internal dependencies
|
|
11
|
+
*/
|
|
12
|
+
import Accordion, { AccordionPanel } from './index';
|
|
13
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
|
+
var renderPanels = function renderPanels(count) {
|
|
15
|
+
var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
16
|
+
return render(/*#__PURE__*/_jsx(Accordion, _objectSpread(_objectSpread({}, props), {}, {
|
|
17
|
+
children: Array.from({
|
|
18
|
+
length: count
|
|
19
|
+
}, function (_, i) {
|
|
20
|
+
return /*#__PURE__*/_jsx(AccordionPanel, {
|
|
21
|
+
title: "Panel ".concat(i),
|
|
22
|
+
children: "content"
|
|
23
|
+
}, i);
|
|
24
|
+
})
|
|
25
|
+
})));
|
|
26
|
+
};
|
|
27
|
+
var dividers = function dividers(container) {
|
|
28
|
+
return container.querySelectorAll('.newspack-divider');
|
|
29
|
+
};
|
|
30
|
+
describe('Accordion dividers', function () {
|
|
31
|
+
it('renders no divider for a single panel', function () {
|
|
32
|
+
var _renderPanels = renderPanels(1),
|
|
33
|
+
container = _renderPanels.container;
|
|
34
|
+
expect(container.querySelectorAll('.components-panel__body')).toHaveLength(1);
|
|
35
|
+
expect(dividers(container)).toHaveLength(0);
|
|
36
|
+
});
|
|
37
|
+
it('renders a divider between panels but not after the last', function () {
|
|
38
|
+
var _renderPanels2 = renderPanels(3),
|
|
39
|
+
container = _renderPanels2.container;
|
|
40
|
+
expect(container.querySelectorAll('.components-panel__body')).toHaveLength(3);
|
|
41
|
+
expect(dividers(container)).toHaveLength(2);
|
|
42
|
+
expect(container.querySelector('.newspack-accordion').lastElementChild).not.toHaveClass('newspack-divider');
|
|
43
|
+
});
|
|
44
|
+
it('renders secondary dividers', function () {
|
|
45
|
+
var _renderPanels3 = renderPanels(2),
|
|
46
|
+
container = _renderPanels3.container;
|
|
47
|
+
expect(dividers(container)[0]).toHaveClass('newspack-divider--variant-secondary');
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe('Accordion hideSingleTitle', function () {
|
|
51
|
+
it('keeps the title on a lone panel by default', function () {
|
|
52
|
+
renderPanels(1);
|
|
53
|
+
expect(screen.getByRole('button', {
|
|
54
|
+
name: 'Panel 0'
|
|
55
|
+
})).toBeInTheDocument();
|
|
56
|
+
});
|
|
57
|
+
it('drops the title and opens a lone panel when set', function () {
|
|
58
|
+
var _renderPanels4 = renderPanels(1, {
|
|
59
|
+
hideSingleTitle: true
|
|
60
|
+
}),
|
|
61
|
+
container = _renderPanels4.container;
|
|
62
|
+
expect(screen.queryByRole('button', {
|
|
63
|
+
name: 'Panel 0'
|
|
64
|
+
})).not.toBeInTheDocument();
|
|
65
|
+
expect(container.querySelector('.components-panel__body')).toHaveClass('is-opened');
|
|
66
|
+
expect(screen.getByText('content')).toBeInTheDocument();
|
|
67
|
+
});
|
|
68
|
+
it('leaves titles alone when there is more than one panel', function () {
|
|
69
|
+
renderPanels(2, {
|
|
70
|
+
hideSingleTitle: true
|
|
71
|
+
});
|
|
72
|
+
expect(screen.getByRole('button', {
|
|
73
|
+
name: 'Panel 0'
|
|
74
|
+
})).toBeInTheDocument();
|
|
75
|
+
expect(screen.getByRole('button', {
|
|
76
|
+
name: 'Panel 1'
|
|
77
|
+
})).toBeInTheDocument();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -1,31 +1,35 @@
|
|
|
1
|
-
@use "~@wordpress/base-styles/
|
|
1
|
+
@use "~@wordpress/base-styles/mixins" as wp-mixins;
|
|
2
|
+
@use "~@wordpress/base-styles/variables" as wp-vars;
|
|
2
3
|
|
|
4
|
+
// Sit flush with the surrounding column: core insets panels horizontally, which
|
|
5
|
+
// would misalign them against the section they belong to.
|
|
3
6
|
.newspack-accordion {
|
|
4
|
-
|
|
7
|
+
.components-panel__body {
|
|
8
|
+
border: 0;
|
|
5
9
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
> .components-panel__body-title:hover {
|
|
11
|
+
background: none;
|
|
12
|
+
}
|
|
9
13
|
}
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
.components-panel__body.is-opened {
|
|
16
|
+
padding: 0;
|
|
17
|
+
|
|
18
|
+
> .components-panel__body-title {
|
|
19
|
+
margin: 0 0 wp-vars.$grid-unit-30;
|
|
16
20
|
}
|
|
17
21
|
}
|
|
18
|
-
summary {
|
|
19
|
-
padding: 16px 32px;
|
|
20
|
-
display: flex;
|
|
21
|
-
align-items: center;
|
|
22
|
-
justify-content: space-between;
|
|
23
|
-
cursor: pointer;
|
|
24
|
-
font-size: 14px;
|
|
25
|
-
font-weight: bold;
|
|
26
|
-
}
|
|
27
22
|
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
.components-panel__body-toggle.components-button {
|
|
24
|
+
@include wp-mixins.heading-large();
|
|
25
|
+
padding: 0;
|
|
26
|
+
|
|
27
|
+
.components-panel__arrow {
|
|
28
|
+
right: 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&:focus:not(:focus-visible) {
|
|
32
|
+
box-shadow: none;
|
|
33
|
+
}
|
|
30
34
|
}
|
|
31
35
|
}
|
|
@@ -77,28 +77,6 @@
|
|
|
77
77
|
padding: 0 4px;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
&.mv0 {
|
|
81
|
-
border-left-color: wp-colors.$gray-300;
|
|
82
|
-
border-radius: 0;
|
|
83
|
-
border-right-color: wp-colors.$gray-300;
|
|
84
|
-
|
|
85
|
-
&:first-of-type {
|
|
86
|
-
border-top-color: wp-colors.$gray-300;
|
|
87
|
-
border-top-left-radius: 3px;
|
|
88
|
-
border-top-right-radius: 3px;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
&:last-of-type {
|
|
92
|
-
border-bottom-color: wp-colors.$gray-300;
|
|
93
|
-
border-bottom-left-radius: 3px;
|
|
94
|
-
border-bottom-right-radius: 3px;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
& + & {
|
|
98
|
-
margin-top: -1px;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
80
|
&.newspack-card__is-disabled,
|
|
103
81
|
&.newspack-card__is-primary,
|
|
104
82
|
&.newspack-card__is-secondary,
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies.
|
|
3
|
+
*/
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
import { Link, Stack, Text } from '@wordpress/ui';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Internal dependencies.
|
|
9
|
+
*/
|
|
10
|
+
import './style.scss';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Newspack breadcrumb trail.
|
|
14
|
+
*
|
|
15
|
+
* Data-driven: the last item is the current page (the single h1, never a link);
|
|
16
|
+
* every other item renders as a link when it has a `url`, otherwise plain text.
|
|
17
|
+
* A plain `<a href>` drives both full admin URLs and hash routes, so the
|
|
18
|
+
* component needs no router context.
|
|
19
|
+
*
|
|
20
|
+
* @param {Object} props
|
|
21
|
+
* @param {Array} props.items Trail items: `{ label, url? }`.
|
|
22
|
+
* @return {JSX.Element|null} Breadcrumbs component.
|
|
23
|
+
*/
|
|
24
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
25
|
+
var Breadcrumbs = function Breadcrumbs(_ref) {
|
|
26
|
+
var _ref$items = _ref.items,
|
|
27
|
+
items = _ref$items === void 0 ? [] : _ref$items;
|
|
28
|
+
if (!items.length) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
var preceding = items.slice(0, -1);
|
|
32
|
+
var last = items[items.length - 1];
|
|
33
|
+
return /*#__PURE__*/_jsx("nav", {
|
|
34
|
+
"aria-label": __('Breadcrumbs', 'newspack-plugin'),
|
|
35
|
+
children: /*#__PURE__*/_jsxs(Stack, {
|
|
36
|
+
render: /*#__PURE__*/_jsx("ul", {}),
|
|
37
|
+
direction: "row",
|
|
38
|
+
align: "center",
|
|
39
|
+
className: "newspack-breadcrumbs__list",
|
|
40
|
+
children: [preceding.map(function (item, index) {
|
|
41
|
+
return /*#__PURE__*/_jsxs("li", {
|
|
42
|
+
children: [item.url ?
|
|
43
|
+
/*#__PURE__*/
|
|
44
|
+
// eslint-disable-next-line jsx-a11y/anchor-has-content -- content is supplied via the Text children through @wordpress/ui's render prop.
|
|
45
|
+
_jsx(Text, {
|
|
46
|
+
variant: "body-lg",
|
|
47
|
+
render: /*#__PURE__*/_jsx(Link, {
|
|
48
|
+
tone: "neutral",
|
|
49
|
+
render: /*#__PURE__*/_jsx("a", {
|
|
50
|
+
href: item.url
|
|
51
|
+
})
|
|
52
|
+
}),
|
|
53
|
+
children: item.label
|
|
54
|
+
}) : /*#__PURE__*/_jsx(Text, {
|
|
55
|
+
variant: "body-lg",
|
|
56
|
+
children: item.label
|
|
57
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
58
|
+
variant: "body-lg",
|
|
59
|
+
"aria-hidden": "true",
|
|
60
|
+
className: "newspack-breadcrumbs__separator",
|
|
61
|
+
children: "/"
|
|
62
|
+
})]
|
|
63
|
+
}, item.url || index);
|
|
64
|
+
}), last && last.label && /*#__PURE__*/_jsx("li", {
|
|
65
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
66
|
+
variant: "heading-lg",
|
|
67
|
+
render: /*#__PURE__*/_jsx("h1", {}),
|
|
68
|
+
className: "newspack-breadcrumbs__current",
|
|
69
|
+
children: last.label
|
|
70
|
+
})
|
|
71
|
+
})]
|
|
72
|
+
})
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
export default Breadcrumbs;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies.
|
|
3
|
+
*/
|
|
4
|
+
import { render, screen } from '@testing-library/react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies.
|
|
8
|
+
*/
|
|
9
|
+
import Breadcrumbs from './';
|
|
10
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
11
|
+
describe('Breadcrumbs', function () {
|
|
12
|
+
it('renders the last item as the only h1 and never a link', function () {
|
|
13
|
+
render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
14
|
+
items: [{
|
|
15
|
+
label: 'Newsletters'
|
|
16
|
+
}, {
|
|
17
|
+
label: 'Settings',
|
|
18
|
+
url: '#/x'
|
|
19
|
+
}]
|
|
20
|
+
}));
|
|
21
|
+
var h1s = screen.getAllByRole('heading', {
|
|
22
|
+
level: 1
|
|
23
|
+
});
|
|
24
|
+
expect(h1s).toHaveLength(1);
|
|
25
|
+
expect(h1s[0]).toHaveTextContent('Settings');
|
|
26
|
+
expect(screen.queryByRole('link', {
|
|
27
|
+
name: 'Settings'
|
|
28
|
+
})).not.toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
it('renders a non-last item with a url as a link, without a url as text', function () {
|
|
31
|
+
render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
32
|
+
items: [{
|
|
33
|
+
label: 'Advertising'
|
|
34
|
+
}, {
|
|
35
|
+
label: 'Sponsors',
|
|
36
|
+
url: '/wp-admin/x'
|
|
37
|
+
}, {
|
|
38
|
+
label: 'All sponsors'
|
|
39
|
+
}]
|
|
40
|
+
}));
|
|
41
|
+
var links = screen.getAllByRole('link');
|
|
42
|
+
expect(links).toHaveLength(1);
|
|
43
|
+
expect(links[0]).toHaveTextContent('Sponsors');
|
|
44
|
+
expect(links[0].getAttribute('href')).toBe('/wp-admin/x');
|
|
45
|
+
expect(screen.getByText('Advertising')).toBeInTheDocument();
|
|
46
|
+
});
|
|
47
|
+
it('does not special-case the first item: it links when it has a url', function () {
|
|
48
|
+
render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
49
|
+
items: [{
|
|
50
|
+
label: 'Audience',
|
|
51
|
+
url: '#/'
|
|
52
|
+
}, {
|
|
53
|
+
label: 'Donations'
|
|
54
|
+
}]
|
|
55
|
+
}));
|
|
56
|
+
var link = screen.getByRole('link', {
|
|
57
|
+
name: 'Audience'
|
|
58
|
+
});
|
|
59
|
+
expect(link.getAttribute('href')).toBe('#/');
|
|
60
|
+
});
|
|
61
|
+
it('renders a single-item trail as just the h1 with no separator', function () {
|
|
62
|
+
var _render = render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
63
|
+
items: [{
|
|
64
|
+
label: 'Dashboard'
|
|
65
|
+
}]
|
|
66
|
+
})),
|
|
67
|
+
container = _render.container;
|
|
68
|
+
expect(screen.getByRole('heading', {
|
|
69
|
+
level: 1
|
|
70
|
+
})).toHaveTextContent('Dashboard');
|
|
71
|
+
expect(container.querySelector('.newspack-breadcrumbs__separator')).toBeNull();
|
|
72
|
+
expect(screen.queryByRole('link')).not.toBeInTheDocument();
|
|
73
|
+
});
|
|
74
|
+
it('renders a "/" separator after each preceding item', function () {
|
|
75
|
+
var _render2 = render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
76
|
+
items: [{
|
|
77
|
+
label: 'Audience'
|
|
78
|
+
}, {
|
|
79
|
+
label: 'Access control'
|
|
80
|
+
}]
|
|
81
|
+
})),
|
|
82
|
+
container = _render2.container;
|
|
83
|
+
var separators = container.querySelectorAll('.newspack-breadcrumbs__separator');
|
|
84
|
+
expect(separators).toHaveLength(1);
|
|
85
|
+
expect(separators[0]).toHaveTextContent('/');
|
|
86
|
+
expect(separators[0]).toHaveAttribute('aria-hidden', 'true');
|
|
87
|
+
});
|
|
88
|
+
it('renders no heading when the last item has no label', function () {
|
|
89
|
+
render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
90
|
+
items: [{
|
|
91
|
+
label: undefined
|
|
92
|
+
}]
|
|
93
|
+
}));
|
|
94
|
+
expect(screen.queryByRole('heading', {
|
|
95
|
+
level: 1
|
|
96
|
+
})).not.toBeInTheDocument();
|
|
97
|
+
});
|
|
98
|
+
it('renders nothing when there are no items', function () {
|
|
99
|
+
var _render3 = render(/*#__PURE__*/_jsx(Breadcrumbs, {
|
|
100
|
+
items: []
|
|
101
|
+
})),
|
|
102
|
+
container = _render3.container;
|
|
103
|
+
expect(container.querySelector('nav')).not.toBeInTheDocument();
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
2
|
+
|
|
3
|
+
.newspack-breadcrumbs__list {
|
|
4
|
+
list-style: none;
|
|
5
|
+
margin: 0;
|
|
6
|
+
padding: 0;
|
|
7
|
+
|
|
8
|
+
> li {
|
|
9
|
+
flex-shrink: 0;
|
|
10
|
+
margin: 0;
|
|
11
|
+
|
|
12
|
+
a {
|
|
13
|
+
color: wp-colors.$gray-900;
|
|
14
|
+
|
|
15
|
+
&:hover,
|
|
16
|
+
&:focus,
|
|
17
|
+
&:active {
|
|
18
|
+
color: wp-colors.$gray-900;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
> li:last-child {
|
|
24
|
+
flex-shrink: 1;
|
|
25
|
+
min-width: 0;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.newspack-breadcrumbs__separator {
|
|
30
|
+
color: var(--wpds-color-stroke-surface-neutral, #dbdbdb);
|
|
31
|
+
margin: 0 var(--wpds-dimension-gap-sm, 8px);
|
|
32
|
+
user-select: none;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.newspack-breadcrumbs__list h1.newspack-breadcrumbs__current {
|
|
36
|
+
overflow: hidden;
|
|
37
|
+
text-overflow: ellipsis;
|
|
38
|
+
white-space: nowrap;
|
|
39
|
+
padding: 0;
|
|
40
|
+
line-height: normal;
|
|
41
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
|
|
3
|
-
var _excluded = ["actions", "actionType", "as", "buttonsCard", "className", "footer", "header", "headerAction", "headerStyle", "childrenStyle", "footerStyle", "disabled", "icon", "iconBackgroundColor", "isActive", "isDraggable", "isFirstTarget", "isLastTarget", "isNarrow", "isSmall", "dragIndex", "onDragCallback", "onToggle", "onHeaderClick", "noBorder", "noMargin", "children", "hasGreyHeader", "hasHeaderBorder"];
|
|
3
|
+
var _excluded = ["actions", "actionType", "as", "buttonsCard", "className", "footer", "header", "headerAction", "headerStyle", "childrenStyle", "footerStyle", "disabled", "icon", "iconElement", "iconBackgroundColor", "isActive", "isDraggable", "isFirstTarget", "isLastTarget", "isNarrow", "isSmall", "dragIndex", "onDragCallback", "onToggle", "onHeaderClick", "noBorder", "noMargin", "children", "hasGreyHeader", "hasHeaderBorder"];
|
|
4
4
|
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; }
|
|
5
5
|
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; }
|
|
6
6
|
/**
|
|
@@ -39,6 +39,7 @@ var CoreCard = function CoreCard(_ref) {
|
|
|
39
39
|
footerStyle = _ref.footerStyle,
|
|
40
40
|
disabled = _ref.disabled,
|
|
41
41
|
icon = _ref.icon,
|
|
42
|
+
iconElement = _ref.iconElement,
|
|
42
43
|
iconBackgroundColor = _ref.iconBackgroundColor,
|
|
43
44
|
isActive = _ref.isActive,
|
|
44
45
|
isDraggable = _ref.isDraggable,
|
|
@@ -60,7 +61,7 @@ var CoreCard = function CoreCard(_ref) {
|
|
|
60
61
|
_ref$hasHeaderBorder = _ref.hasHeaderBorder,
|
|
61
62
|
hasHeaderBorder = _ref$hasHeaderBorder === void 0 ? true : _ref$hasHeaderBorder,
|
|
62
63
|
otherProps = _objectWithoutProperties(_ref, _excluded);
|
|
63
|
-
var classes = classNames('newspack-card--core', className, (buttonsCard || as === 'a') && 'newspack-card--core__buttons-card', (actions === null || actions === void 0 ? void 0 : actions.length) > 0 && 'newspack-card--core__header--has-actions', isDraggable && 'newspack-card--core__is-draggable', isNarrow && 'newspack-card--core__is-narrow', isSmall && 'newspack-card--core__is-small', icon && 'newspack-card--core__has-icon', iconBackgroundColor && 'newspack-card--core__has-icon-background-color', isActive && 'newspack-card--core__is-active', disabled && 'newspack-card--core__is-disabled', children && 'newspack-card--core__has-children', noMargin && 'newspack-card--core__no-margin', hasGreyHeader && 'newspack-card--core__has-grey-header');
|
|
64
|
+
var classes = classNames('newspack-card--core', className, (buttonsCard || as === 'a') && 'newspack-card--core__buttons-card', (actions === null || actions === void 0 ? void 0 : actions.length) > 0 && 'newspack-card--core__header--has-actions', isDraggable && 'newspack-card--core__is-draggable', isNarrow && 'newspack-card--core__is-narrow', isSmall && 'newspack-card--core__is-small', (icon || iconElement) && 'newspack-card--core__has-icon', iconBackgroundColor && 'newspack-card--core__has-icon-background-color', isActive && 'newspack-card--core__is-active', disabled && 'newspack-card--core__is-disabled', children && 'newspack-card--core__has-children', noMargin && 'newspack-card--core__no-margin', hasGreyHeader && 'newspack-card--core__has-grey-header');
|
|
64
65
|
var sizeProps = isSmall ? 'small' : otherProps.size;
|
|
65
66
|
if (buttonsCard || as === 'a') {
|
|
66
67
|
if (!isSmall) {
|
|
@@ -82,7 +83,7 @@ var CoreCard = function CoreCard(_ref) {
|
|
|
82
83
|
as: as,
|
|
83
84
|
className: classes
|
|
84
85
|
}, otherProps), {}, {
|
|
85
|
-
children: [(header || icon) && /*#__PURE__*/_jsxs(CardHeader, {
|
|
86
|
+
children: [(header || icon || iconElement) && /*#__PURE__*/_jsxs(CardHeader, {
|
|
86
87
|
as: headerIsButton ? 'button' : undefined,
|
|
87
88
|
className: classNames('newspack-card--core__header', isDraggable && 'newspack-card--core__header--is-draggable', !hasHeaderBorder && 'newspack-card--core__header--no-border'),
|
|
88
89
|
style: headerStyle,
|
|
@@ -118,7 +119,10 @@ var CoreCard = function CoreCard(_ref) {
|
|
|
118
119
|
size: "small"
|
|
119
120
|
})]
|
|
120
121
|
})]
|
|
121
|
-
}),
|
|
122
|
+
}), iconElement ? /*#__PURE__*/_jsx("div", {
|
|
123
|
+
className: "newspack-card--core__icon-slot",
|
|
124
|
+
children: iconElement
|
|
125
|
+
}) : icon && /*#__PURE__*/_jsx("div", {
|
|
122
126
|
className: "newspack-card--core__icon",
|
|
123
127
|
children: /*#__PURE__*/_jsx(Icon, {
|
|
124
128
|
icon: icon,
|
package/dist/esm/card/index.js
CHANGED
|
@@ -81,7 +81,7 @@ var Card = /*#__PURE__*/function (_Component) {
|
|
|
81
81
|
}, otherProps), __experimentalCoreProps);
|
|
82
82
|
return /*#__PURE__*/_jsx(CoreCard, _objectSpread({}, props));
|
|
83
83
|
}
|
|
84
|
-
var classes = classNames('newspack-card', className,
|
|
84
|
+
var classes = classNames('newspack-card', className, headerActions && 'newspack-card__header-actions', isMedium && 'newspack-card__is-medium', isNarrow && 'newspack-card__is-narrow', isSmall && 'newspack-card__is-small', isWhite && 'newspack-card__is-white', noBorder && 'newspack-card__no-border');
|
|
85
85
|
return /*#__PURE__*/_jsx("div", _objectSpread({
|
|
86
86
|
className: classes
|
|
87
87
|
}, otherProps));
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
svg {
|
|
15
15
|
transition: fill 125ms ease-in-out;
|
|
16
16
|
}
|
|
17
|
+
// Slot for a pre-rendered icon element that owns its own badge.
|
|
18
|
+
&__icon-slot {
|
|
19
|
+
align-items: center;
|
|
20
|
+
display: flex;
|
|
21
|
+
}
|
|
17
22
|
&__icon {
|
|
18
23
|
border-radius: wp-vars.$radius-round;
|
|
19
24
|
display: grid;
|
|
@@ -149,6 +154,15 @@
|
|
|
149
154
|
border: none;
|
|
150
155
|
cursor: pointer;
|
|
151
156
|
text-align: left;
|
|
157
|
+
|
|
158
|
+
// The header becomes a real button (headerIsButton) with no border, so
|
|
159
|
+
// give keyboard focus an explicit on-brand ring. Inset so it isn't clipped
|
|
160
|
+
// by the card; the transparent outline keeps it visible under Windows High
|
|
161
|
+
// Contrast / forced-colors mode.
|
|
162
|
+
&:focus-visible {
|
|
163
|
+
box-shadow: inset 0 0 0 2px var(--wp-admin-theme-color);
|
|
164
|
+
outline: 2px solid transparent;
|
|
165
|
+
}
|
|
152
166
|
}
|
|
153
167
|
&__header-content {
|
|
154
168
|
display: grid;
|
package/dist/esm/card/style.scss
CHANGED
|
@@ -7,6 +7,7 @@ import classnames from 'classnames';
|
|
|
7
7
|
* WordPress dependencies
|
|
8
8
|
*/
|
|
9
9
|
import { __ } from '@wordpress/i18n';
|
|
10
|
+
import { isValidElement } from '@wordpress/element';
|
|
10
11
|
import { DropdownMenu, __experimentalHStack as HStack } from '@wordpress/components'; // eslint-disable-line @wordpress/no-unsafe-wp-apis
|
|
11
12
|
import { moreVertical } from '@wordpress/icons';
|
|
12
13
|
|
|
@@ -35,6 +36,8 @@ var CardFeature = function CardFeature(_ref) {
|
|
|
35
36
|
_ref$requirementsActi = _ref.requirementsActionable,
|
|
36
37
|
requirementsActionable = _ref$requirementsActi === void 0 ? false : _ref$requirementsActi,
|
|
37
38
|
enableLabel = _ref.enableLabel,
|
|
39
|
+
_ref$busy = _ref.busy,
|
|
40
|
+
busy = _ref$busy === void 0 ? false : _ref$busy,
|
|
38
41
|
configureLabel = _ref.configureLabel,
|
|
39
42
|
onEnable = _ref.onEnable,
|
|
40
43
|
onConfigure = _ref.onConfigure,
|
|
@@ -61,6 +64,7 @@ var CardFeature = function CardFeature(_ref) {
|
|
|
61
64
|
}
|
|
62
65
|
var isConfigureState = enabled && !requirements;
|
|
63
66
|
var buttonLabel = isConfigureState ? configureLabel !== null && configureLabel !== void 0 ? configureLabel : __('Configure', 'newspack-plugin') : enableLabel !== null && enableLabel !== void 0 ? enableLabel : __('Enable', 'newspack-plugin');
|
|
67
|
+
var showMoreControls = enabled && !!(moreControls !== null && moreControls !== void 0 && moreControls.length) && (!requirements || requirementsActionable);
|
|
64
68
|
var handleButtonClick = function handleButtonClick() {
|
|
65
69
|
if (isConfigureState) {
|
|
66
70
|
onConfigure === null || onConfigure === void 0 || onConfigure();
|
|
@@ -68,10 +72,24 @@ var CardFeature = function CardFeature(_ref) {
|
|
|
68
72
|
onEnable === null || onEnable === void 0 || onEnable();
|
|
69
73
|
}
|
|
70
74
|
};
|
|
71
|
-
var
|
|
72
|
-
|
|
73
|
-
'newspack-card-feature__icon--radius-
|
|
75
|
+
var iconDescriptor = icon && !isValidElement(icon) ? icon : null;
|
|
76
|
+
var iconClasses = iconDescriptor ? classnames('newspack-card-feature__icon', {
|
|
77
|
+
'newspack-card-feature__icon--radius-small': !!iconDescriptor.backgroundColor && iconDescriptor.radius !== 'full',
|
|
78
|
+
'newspack-card-feature__icon--radius-full': iconDescriptor.radius === 'full'
|
|
74
79
|
}) : undefined;
|
|
80
|
+
var renderedIcon = null;
|
|
81
|
+
if (isValidElement(icon)) {
|
|
82
|
+
renderedIcon = icon;
|
|
83
|
+
} else if (iconDescriptor) {
|
|
84
|
+
renderedIcon = /*#__PURE__*/_jsx("div", {
|
|
85
|
+
className: iconClasses,
|
|
86
|
+
style: {
|
|
87
|
+
backgroundColor: iconDescriptor.backgroundColor,
|
|
88
|
+
color: iconDescriptor.fill
|
|
89
|
+
},
|
|
90
|
+
children: iconDescriptor.node
|
|
91
|
+
});
|
|
92
|
+
}
|
|
75
93
|
return /*#__PURE__*/_jsx(Card, {
|
|
76
94
|
className: classes,
|
|
77
95
|
__experimentalCoreCard: true,
|
|
@@ -92,14 +110,7 @@ var CardFeature = function CardFeature(_ref) {
|
|
|
92
110
|
className: "newspack-card-feature__description",
|
|
93
111
|
children: description
|
|
94
112
|
})]
|
|
95
|
-
}),
|
|
96
|
-
className: iconClasses,
|
|
97
|
-
style: {
|
|
98
|
-
backgroundColor: icon.backgroundColor,
|
|
99
|
-
color: icon.fill
|
|
100
|
-
},
|
|
101
|
-
children: icon.node
|
|
102
|
-
})]
|
|
113
|
+
}), renderedIcon]
|
|
103
114
|
}), /*#__PURE__*/_jsxs(HStack, {
|
|
104
115
|
alignment: "edge",
|
|
105
116
|
children: [/*#__PURE__*/_jsxs(HStack, {
|
|
@@ -107,11 +118,12 @@ var CardFeature = function CardFeature(_ref) {
|
|
|
107
118
|
spacing: "8px",
|
|
108
119
|
children: [/*#__PURE__*/_jsx(Button, {
|
|
109
120
|
variant: isConfigureState ? 'tertiary' : 'secondary',
|
|
110
|
-
disabled: isMuted && !requirementsActionable,
|
|
121
|
+
disabled: isMuted && !requirementsActionable || busy,
|
|
122
|
+
isBusy: busy,
|
|
111
123
|
onClick: handleButtonClick,
|
|
112
124
|
size: "compact",
|
|
113
125
|
children: buttonLabel
|
|
114
|
-
}),
|
|
126
|
+
}), showMoreControls && /*#__PURE__*/_jsx(DropdownMenu, {
|
|
115
127
|
icon: moreVertical,
|
|
116
128
|
label: __('More', 'newspack-plugin'),
|
|
117
129
|
controls: moreControls,
|