newspack-components 4.7.0 → 4.8.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 (251) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/DEVELOPMENT.md +42 -21
  3. package/dist/cjs/_mixins.scss +13 -0
  4. package/dist/cjs/_variables.scss +12 -0
  5. package/dist/cjs/action-card/index.js +18 -10
  6. package/dist/cjs/action-card/index.test.js +91 -0
  7. package/dist/cjs/action-card/style.scss +2 -40
  8. package/dist/cjs/button/index.js +8 -3
  9. package/dist/cjs/button/index.test.js +61 -5
  10. package/dist/cjs/card/core-card.js +0 -2
  11. package/dist/cjs/card/style-core.scss +7 -5
  12. package/dist/cjs/card-feature/index.js +75 -61
  13. package/dist/cjs/card-feature/index.test.js +396 -54
  14. package/dist/cjs/card-feature/style.scss +20 -31
  15. package/dist/cjs/card-form/index.js +5 -5
  16. package/dist/cjs/card-sortable-list/index.js +5 -3
  17. package/dist/cjs/card-sortable-list/index.test.js +50 -0
  18. package/dist/cjs/collapsible-group/context.js +19 -0
  19. package/dist/cjs/collapsible-group/index.js +24 -0
  20. package/dist/cjs/collapsible-group/index.test.js +215 -0
  21. package/dist/cjs/collapsible-group/item.js +61 -0
  22. package/dist/cjs/collapsible-group/root.js +62 -0
  23. package/dist/cjs/collapsible-group/style.scss +47 -0
  24. package/dist/cjs/collapsible-group/types.js +5 -0
  25. package/dist/cjs/empty-state/actions.js +45 -0
  26. package/dist/cjs/empty-state/context.js +41 -0
  27. package/dist/cjs/empty-state/header.js +66 -0
  28. package/dist/cjs/empty-state/index.js +31 -0
  29. package/dist/cjs/empty-state/index.test.js +303 -0
  30. package/dist/cjs/empty-state/root.js +56 -0
  31. package/dist/cjs/empty-state/style.scss +51 -0
  32. package/dist/cjs/empty-state/types.js +5 -0
  33. package/dist/cjs/index.js +34 -20
  34. package/dist/cjs/info-button/index.js +59 -43
  35. package/dist/cjs/info-button/index.test.js +199 -0
  36. package/dist/cjs/info-button/style.scss +41 -9
  37. package/dist/cjs/modal/style.scss +12 -12
  38. package/dist/cjs/newspack-icon/style.scss +4 -4
  39. package/dist/cjs/notice/style.scss +3 -3
  40. package/dist/cjs/page/style.scss +16 -16
  41. package/dist/cjs/plugin-installer/index.js +5 -9
  42. package/dist/cjs/plugin-installer/style.scss +3 -14
  43. package/dist/cjs/section-header/index.js +31 -18
  44. package/dist/cjs/section-header/index.test.js +40 -0
  45. package/dist/cjs/section-header/style.scss +22 -6
  46. package/dist/cjs/settings/DateRangeSetting.js +309 -0
  47. package/dist/cjs/settings/SettingsSection.js +19 -5
  48. package/dist/cjs/settings/SettingsSection.test.js +49 -0
  49. package/dist/cjs/settings/index.js +3 -1
  50. package/dist/cjs/settings/style.scss +40 -7
  51. package/dist/cjs/stat-card/body.js +41 -0
  52. package/dist/cjs/stat-card/constants.js +11 -0
  53. package/dist/cjs/stat-card/context.js +54 -0
  54. package/dist/cjs/stat-card/delta.js +91 -0
  55. package/dist/cjs/stat-card/footer.js +72 -0
  56. package/dist/cjs/stat-card/index.js +47 -0
  57. package/dist/cjs/stat-card/index.test.js +938 -0
  58. package/dist/cjs/stat-card/label.js +66 -0
  59. package/dist/cjs/stat-card/root.js +69 -0
  60. package/dist/cjs/stat-card/secondary.js +38 -0
  61. package/dist/cjs/stat-card/style.scss +89 -0
  62. package/dist/cjs/stat-card/types.js +5 -0
  63. package/dist/cjs/stat-card/value.js +78 -0
  64. package/dist/cjs/status-indicator/index.js +66 -0
  65. package/dist/cjs/status-indicator/index.test.js +101 -0
  66. package/dist/cjs/status-indicator/statuses.js +39 -0
  67. package/dist/cjs/status-indicator/style.scss +9 -0
  68. package/dist/cjs/status-indicator/types.js +5 -0
  69. package/dist/cjs/style.scss +9 -9
  70. package/dist/cjs/tabbed-navigation/style.scss +6 -4
  71. package/dist/cjs/types.js +5 -0
  72. package/dist/cjs/web-preview/style.scss +11 -11
  73. package/dist/cjs/with-wizard/style.scss +10 -10
  74. package/dist/cjs/with-wizard-screen/style.scss +9 -9
  75. package/dist/cjs/wizard/index.js +33 -4
  76. package/dist/cjs/wizard/store/index.js +23 -1
  77. package/dist/esm/_mixins.scss +13 -0
  78. package/dist/esm/_variables.scss +12 -0
  79. package/dist/esm/action-card/index.js +18 -10
  80. package/dist/esm/action-card/index.test.js +89 -0
  81. package/dist/esm/action-card/style.scss +2 -40
  82. package/dist/esm/button/index.js +9 -4
  83. package/dist/esm/button/index.test.js +63 -5
  84. package/dist/esm/card/core-card.js +0 -2
  85. package/dist/esm/card/style-core.scss +7 -5
  86. package/dist/esm/card-feature/index.js +78 -62
  87. package/dist/esm/card-feature/index.test.js +397 -55
  88. package/dist/esm/card-feature/style.scss +20 -31
  89. package/dist/esm/card-form/index.js +5 -5
  90. package/dist/esm/card-sortable-list/index.js +6 -4
  91. package/dist/esm/card-sortable-list/index.test.js +46 -0
  92. package/dist/esm/collapsible-group/context.js +13 -0
  93. package/dist/esm/collapsible-group/index.js +17 -0
  94. package/dist/esm/collapsible-group/index.test.js +215 -0
  95. package/dist/esm/collapsible-group/item.js +53 -0
  96. package/dist/esm/collapsible-group/root.js +54 -0
  97. package/dist/esm/collapsible-group/style.scss +47 -0
  98. package/dist/esm/collapsible-group/types.js +1 -0
  99. package/dist/esm/empty-state/actions.js +37 -0
  100. package/dist/esm/empty-state/context.js +35 -0
  101. package/dist/esm/empty-state/header.js +58 -0
  102. package/dist/esm/empty-state/index.js +23 -0
  103. package/dist/esm/empty-state/index.test.js +299 -0
  104. package/dist/esm/empty-state/root.js +56 -0
  105. package/dist/esm/empty-state/style.scss +51 -0
  106. package/dist/esm/empty-state/types.js +1 -0
  107. package/dist/esm/index.js +4 -2
  108. package/dist/esm/info-button/index.js +54 -43
  109. package/dist/esm/info-button/index.test.js +195 -0
  110. package/dist/esm/info-button/style.scss +41 -9
  111. package/dist/esm/modal/style.scss +12 -12
  112. package/dist/esm/newspack-icon/style.scss +4 -4
  113. package/dist/esm/notice/style.scss +3 -3
  114. package/dist/esm/page/style.scss +16 -16
  115. package/dist/esm/plugin-installer/index.js +5 -9
  116. package/dist/esm/plugin-installer/style.scss +3 -14
  117. package/dist/esm/section-header/index.js +27 -14
  118. package/dist/esm/section-header/index.test.js +36 -0
  119. package/dist/esm/section-header/style.scss +22 -6
  120. package/dist/esm/settings/DateRangeSetting.js +304 -0
  121. package/dist/esm/settings/SettingsSection.js +16 -3
  122. package/dist/esm/settings/SettingsSection.test.js +45 -0
  123. package/dist/esm/settings/index.js +3 -1
  124. package/dist/esm/settings/style.scss +40 -7
  125. package/dist/esm/stat-card/body.js +36 -0
  126. package/dist/esm/stat-card/constants.js +5 -0
  127. package/dist/esm/stat-card/context.js +48 -0
  128. package/dist/esm/stat-card/delta.js +86 -0
  129. package/dist/esm/stat-card/footer.js +67 -0
  130. package/dist/esm/stat-card/index.js +33 -0
  131. package/dist/esm/stat-card/index.test.js +939 -0
  132. package/dist/esm/stat-card/label.js +61 -0
  133. package/dist/esm/stat-card/root.js +64 -0
  134. package/dist/esm/stat-card/secondary.js +33 -0
  135. package/dist/esm/stat-card/style.scss +89 -0
  136. package/dist/esm/stat-card/types.js +1 -0
  137. package/dist/esm/stat-card/value.js +73 -0
  138. package/dist/esm/status-indicator/index.js +52 -0
  139. package/dist/esm/status-indicator/index.test.js +96 -0
  140. package/dist/esm/status-indicator/statuses.js +33 -0
  141. package/dist/esm/status-indicator/style.scss +9 -0
  142. package/dist/esm/status-indicator/types.js +1 -0
  143. package/dist/esm/style.scss +9 -9
  144. package/dist/esm/tabbed-navigation/style.scss +6 -4
  145. package/dist/esm/types.js +1 -0
  146. package/dist/esm/web-preview/style.scss +11 -11
  147. package/dist/esm/with-wizard/style.scss +10 -10
  148. package/dist/esm/with-wizard-screen/style.scss +9 -9
  149. package/dist/esm/wizard/index.js +38 -7
  150. package/dist/esm/wizard/store/index.js +23 -1
  151. package/package.json +1 -1
  152. package/src/_mixins.scss +13 -0
  153. package/src/_variables.scss +12 -0
  154. package/src/action-card/action-card.d.ts +3 -2
  155. package/src/action-card/index.js +12 -12
  156. package/src/action-card/index.test.js +56 -0
  157. package/src/action-card/style.scss +2 -40
  158. package/src/button/index.test.js +52 -5
  159. package/src/button/index.tsx +9 -4
  160. package/src/card/core-card.js +0 -2
  161. package/src/card/style-core.scss +7 -5
  162. package/src/card-feature/README.md +68 -27
  163. package/src/card-feature/index.test.js +242 -27
  164. package/src/card-feature/index.tsx +77 -67
  165. package/src/card-feature/style.scss +20 -31
  166. package/src/card-form/README.md +10 -10
  167. package/src/card-form/index.tsx +4 -8
  168. package/src/card-sortable-list/README.md +4 -5
  169. package/src/card-sortable-list/index.test.js +29 -0
  170. package/src/card-sortable-list/index.tsx +7 -4
  171. package/src/collapsible-group/README.md +50 -0
  172. package/src/collapsible-group/context.ts +13 -0
  173. package/src/collapsible-group/index.test.js +168 -0
  174. package/src/collapsible-group/index.tsx +17 -0
  175. package/src/collapsible-group/item.tsx +42 -0
  176. package/src/collapsible-group/root.tsx +42 -0
  177. package/src/collapsible-group/style.scss +47 -0
  178. package/src/collapsible-group/types.ts +22 -0
  179. package/src/drawer/README.md +2 -2
  180. package/src/empty-state/README.md +165 -0
  181. package/src/empty-state/actions.tsx +37 -0
  182. package/src/empty-state/context.ts +40 -0
  183. package/src/empty-state/header.tsx +48 -0
  184. package/src/empty-state/index.test.js +247 -0
  185. package/src/empty-state/index.tsx +22 -0
  186. package/src/empty-state/root.tsx +39 -0
  187. package/src/empty-state/style.scss +51 -0
  188. package/src/empty-state/types.ts +33 -0
  189. package/src/index.js +4 -2
  190. package/src/info-button/README.md +115 -0
  191. package/src/info-button/index.test.js +163 -0
  192. package/src/info-button/index.tsx +64 -0
  193. package/src/info-button/style.scss +41 -9
  194. package/src/modal/style.scss +12 -12
  195. package/src/newspack-icon/style.scss +4 -4
  196. package/src/notice/style.scss +3 -3
  197. package/src/page/style.scss +16 -16
  198. package/src/plugin-installer/index.js +3 -9
  199. package/src/plugin-installer/style.scss +3 -14
  200. package/src/section-header/index.js +27 -14
  201. package/src/section-header/index.test.js +28 -0
  202. package/src/section-header/style.scss +22 -6
  203. package/src/settings/DateRangeSetting.js +266 -0
  204. package/src/settings/SettingsSection.js +24 -4
  205. package/src/settings/SettingsSection.test.js +45 -0
  206. package/src/settings/index.js +2 -0
  207. package/src/settings/style.scss +40 -7
  208. package/src/stat-card/README.md +434 -0
  209. package/src/stat-card/body.tsx +28 -0
  210. package/src/stat-card/constants.ts +5 -0
  211. package/src/stat-card/context.ts +53 -0
  212. package/src/stat-card/delta.tsx +88 -0
  213. package/src/stat-card/footer.tsx +68 -0
  214. package/src/stat-card/index.test.js +818 -0
  215. package/src/stat-card/index.tsx +48 -0
  216. package/src/stat-card/label.tsx +61 -0
  217. package/src/stat-card/root.tsx +40 -0
  218. package/src/stat-card/secondary.tsx +27 -0
  219. package/src/stat-card/style.scss +89 -0
  220. package/src/stat-card/types.ts +84 -0
  221. package/src/stat-card/value.tsx +72 -0
  222. package/src/status-indicator/README.md +123 -0
  223. package/src/status-indicator/index.test.js +70 -0
  224. package/src/status-indicator/index.tsx +39 -0
  225. package/src/status-indicator/statuses.ts +35 -0
  226. package/src/status-indicator/style.scss +9 -0
  227. package/src/status-indicator/types.ts +28 -0
  228. package/src/style.scss +9 -9
  229. package/src/tabbed-navigation/style.scss +6 -4
  230. package/src/types.ts +25 -0
  231. package/src/web-preview/style.scss +11 -11
  232. package/src/with-wizard/style.scss +10 -10
  233. package/src/with-wizard-screen/style.scss +9 -9
  234. package/src/wizard/index.js +49 -7
  235. package/src/wizard/store/index.js +26 -1
  236. package/dist/cjs/accordion/index.js +0 -72
  237. package/dist/cjs/accordion/index.test.js +0 -80
  238. package/dist/cjs/accordion/style.scss +0 -35
  239. package/dist/cjs/badge/index.js +0 -32
  240. package/dist/cjs/badge/style.scss +0 -36
  241. package/dist/esm/accordion/index.js +0 -63
  242. package/dist/esm/accordion/index.test.js +0 -79
  243. package/dist/esm/accordion/style.scss +0 -35
  244. package/dist/esm/badge/index.js +0 -24
  245. package/dist/esm/badge/style.scss +0 -36
  246. package/src/accordion/index.js +0 -46
  247. package/src/accordion/index.test.js +0 -62
  248. package/src/accordion/style.scss +0 -35
  249. package/src/badge/index.tsx +0 -26
  250. package/src/badge/style.scss +0 -36
  251. package/src/info-button/index.js +0 -38
@@ -0,0 +1,58 @@
1
+ /**
2
+ * WordPress dependencies.
3
+ */
4
+ import { Icon } from '@wordpress/icons';
5
+ import { Stack } from '@wordpress/ui';
6
+
7
+ /**
8
+ * External dependencies.
9
+ */
10
+ import classnames from 'classnames';
11
+
12
+ /**
13
+ * Internal dependencies.
14
+ */
15
+ import { useEmptyStateContext } from './context';
16
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
17
+ var Header = function Header(_ref) {
18
+ var icon = _ref.icon,
19
+ title = _ref.title,
20
+ description = _ref.description,
21
+ heading = _ref.heading,
22
+ className = _ref.className;
23
+ var _useEmptyStateContext = useEmptyStateContext(),
24
+ size = _useEmptyStateContext.size;
25
+ var isSmall = size === 'small';
26
+
27
+ // Heading level is a document-outline concern, so the size only sets a default.
28
+ var level = heading !== null && heading !== void 0 ? heading : isSmall ? 3 : 2;
29
+ var HeadingTag = "h".concat(level);
30
+
31
+ // Two stacks so each gap belongs to exactly one of them: the inner one spaces the
32
+ // icon from the title, the outer one the title from the description.
33
+ return /*#__PURE__*/_jsxs(Stack, {
34
+ direction: "column",
35
+ align: "center",
36
+ gap: "sm",
37
+ className: classnames('newspack-empty-state__header', isSmall && 'newspack-empty-state__header--small', className),
38
+ children: [/*#__PURE__*/_jsxs(Stack, {
39
+ direction: "column",
40
+ align: "center",
41
+ gap: isSmall ? 'md' : 'lg',
42
+ children: [icon && /*#__PURE__*/_jsx("div", {
43
+ className: "newspack-empty-state__icon",
44
+ children: /*#__PURE__*/_jsx(Icon, {
45
+ icon: icon,
46
+ size: isSmall ? 24 : 48
47
+ })
48
+ }), /*#__PURE__*/_jsx(HeadingTag, {
49
+ className: "newspack-empty-state__title",
50
+ children: title
51
+ })]
52
+ }), description && /*#__PURE__*/_jsx("p", {
53
+ className: "newspack-empty-state__description",
54
+ children: description
55
+ })]
56
+ });
57
+ };
58
+ export default Header;
@@ -0,0 +1,23 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ /**
3
+ * EmptyState
4
+ */
5
+
6
+ /**
7
+ * Internal dependencies.
8
+ */
9
+ import Actions from './actions';
10
+ import Header from './header';
11
+ import Root from './root';
12
+ export var EmptyState = {
13
+ Root: Root,
14
+ Header: Header,
15
+ Actions: Actions
16
+ };
17
+ Object.entries(EmptyState).forEach(function (_ref) {
18
+ var _ref2 = _slicedToArray(_ref, 2),
19
+ name = _ref2[0],
20
+ part = _ref2[1];
21
+ part.displayName = "EmptyState.".concat(name);
22
+ });
23
+ export default EmptyState;
@@ -0,0 +1,299 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { render, screen } from '@testing-library/react';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import EmptyState from '.';
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ describe('EmptyState.Root', function () {
12
+ it('renders the four-column grid spine', function () {
13
+ var _render = render(/*#__PURE__*/_jsx(EmptyState.Root, {
14
+ children: /*#__PURE__*/_jsx("p", {
15
+ children: "body"
16
+ })
17
+ })),
18
+ container = _render.container;
19
+ var grid = container.querySelector('.newspack-empty-state');
20
+ expect(grid).toHaveClass('newspack-grid');
21
+ expect(grid).toHaveClass('newspack-grid__columns-4');
22
+ expect(grid).toHaveClass('newspack-grid--no-margin');
23
+ });
24
+
25
+ // grid/style.scss matches on these attributes, so they are a contract.
26
+ it('gives the inner stack the data attributes the Grid stylesheet matches on', function () {
27
+ var _render2 = render(/*#__PURE__*/_jsx(EmptyState.Root, {
28
+ children: /*#__PURE__*/_jsx("p", {
29
+ children: "body"
30
+ })
31
+ })),
32
+ container = _render2.container;
33
+ var stack = container.querySelector('.newspack-empty-state').firstElementChild;
34
+ expect(stack).toHaveAttribute('data-start', '2');
35
+ expect(stack).toHaveAttribute('data-end', '4');
36
+ });
37
+
38
+ // The width cap hangs off this class, so losing it silently widens the block.
39
+ it('carries the stack class hook', function () {
40
+ var _render3 = render(/*#__PURE__*/_jsx(EmptyState.Root, {
41
+ children: /*#__PURE__*/_jsx("p", {
42
+ children: "body"
43
+ })
44
+ })),
45
+ container = _render3.container;
46
+ var stack = container.querySelector('.newspack-empty-state').firstElementChild;
47
+ expect(stack).toHaveClass('newspack-empty-state__stack');
48
+ expect(stack).toHaveStyle({
49
+ gap: 'var(--wpds-dimension-gap-2xl, 32px)'
50
+ });
51
+ });
52
+
53
+ // Consumers key `:has()` selectors off this class, so losing it changes their
54
+ // layout without failing anything.
55
+ it('merges className onto the grid', function () {
56
+ var _render4 = render(/*#__PURE__*/_jsx(EmptyState.Root, {
57
+ className: "consumer-empty-state",
58
+ children: /*#__PURE__*/_jsx("p", {
59
+ children: "body"
60
+ })
61
+ })),
62
+ container = _render4.container;
63
+ expect(container.querySelector('.newspack-empty-state')).toHaveClass('consumer-empty-state');
64
+ });
65
+
66
+ // Elements, not a bare string: the stack keeps a lone string but drops one sitting
67
+ // beside an element.
68
+ it('renders its children', function () {
69
+ render(/*#__PURE__*/_jsx(EmptyState.Root, {
70
+ children: /*#__PURE__*/_jsx("p", {
71
+ children: "body"
72
+ })
73
+ }));
74
+ expect(screen.getByText('body')).toBeInTheDocument();
75
+ });
76
+ });
77
+ describe('EmptyState.Header', function () {
78
+ it('renders the title and description in the header', function () {
79
+ var _render5 = render(/*#__PURE__*/_jsx(EmptyState.Root, {
80
+ children: /*#__PURE__*/_jsx(EmptyState.Header, {
81
+ title: "Get started with newsletters",
82
+ description: "Compose and send."
83
+ })
84
+ })),
85
+ container = _render5.container;
86
+ expect(container.querySelector('.newspack-empty-state__title')).toHaveTextContent('Get started with newsletters');
87
+ expect(container.querySelector('.newspack-empty-state__description')).toHaveTextContent('Compose and send.');
88
+ });
89
+
90
+ // Spacing comes from the stacks, so a margin creeping back onto the heading or
91
+ // paragraph would silently widen every gap.
92
+ it('spaces the header from its stacks rather than from margins', function () {
93
+ var _render6 = render(/*#__PURE__*/_jsx(EmptyState.Root, {
94
+ children: /*#__PURE__*/_jsx(EmptyState.Header, {
95
+ title: "Get started with newsletters",
96
+ description: "Compose and send."
97
+ })
98
+ })),
99
+ container = _render6.container;
100
+ var header = container.querySelector('.newspack-empty-state__header');
101
+ expect(header).toHaveStyle({
102
+ flexDirection: 'column',
103
+ alignItems: 'center',
104
+ gap: 'var(--wpds-dimension-gap-sm, 8px)'
105
+ });
106
+ expect(header.firstElementChild).toHaveStyle({
107
+ flexDirection: 'column',
108
+ alignItems: 'center',
109
+ gap: 'var(--wpds-dimension-gap-lg, 16px)'
110
+ });
111
+ });
112
+ it('wraps the icon in the disc', function () {
113
+ var _render7 = render(/*#__PURE__*/_jsx(EmptyState.Root, {
114
+ children: /*#__PURE__*/_jsx(EmptyState.Header, {
115
+ title: "Get started with newsletters",
116
+ icon: /*#__PURE__*/_jsx("svg", {})
117
+ })
118
+ })),
119
+ container = _render7.container;
120
+ expect(container.querySelector('.newspack-empty-state__icon svg')).toBeInTheDocument();
121
+ });
122
+ it('omits the description and the icon when they are not given', function () {
123
+ var _render8 = render(/*#__PURE__*/_jsx(EmptyState.Root, {
124
+ children: /*#__PURE__*/_jsx(EmptyState.Header, {
125
+ title: "Get started with newsletters"
126
+ })
127
+ })),
128
+ container = _render8.container;
129
+ expect(container.querySelector('.newspack-empty-state__description')).not.toBeInTheDocument();
130
+ expect(container.querySelector('.newspack-empty-state__icon')).not.toBeInTheDocument();
131
+ });
132
+ it('renders an h2 and a 48px icon at the default size', function () {
133
+ var _render9 = render(/*#__PURE__*/_jsx(EmptyState.Root, {
134
+ children: /*#__PURE__*/_jsx(EmptyState.Header, {
135
+ title: "Get started with newsletters",
136
+ icon: /*#__PURE__*/_jsx("svg", {})
137
+ })
138
+ })),
139
+ container = _render9.container;
140
+ expect(screen.getByRole('heading', {
141
+ level: 2,
142
+ name: 'Get started with newsletters'
143
+ })).toBeInTheDocument();
144
+ expect(container.querySelector('.newspack-empty-state__header--small')).not.toBeInTheDocument();
145
+ expect(container.querySelector('.newspack-empty-state__icon svg')).toHaveAttribute('width', '48');
146
+ });
147
+ it('drops to an h3, the small modifier and a 24px icon when the root is small', function () {
148
+ var _render0 = render(/*#__PURE__*/_jsx(EmptyState.Root, {
149
+ size: "small",
150
+ children: /*#__PURE__*/_jsx(EmptyState.Header, {
151
+ title: "No products match this rule",
152
+ icon: /*#__PURE__*/_jsx("svg", {})
153
+ })
154
+ })),
155
+ container = _render0.container;
156
+ expect(container.querySelector('.newspack-empty-state__header--small')).toBeInTheDocument();
157
+ expect(screen.getByRole('heading', {
158
+ level: 3,
159
+ name: 'No products match this rule'
160
+ })).toBeInTheDocument();
161
+ expect(container.querySelector('.newspack-empty-state__icon svg')).toHaveAttribute('width', '24');
162
+ expect(container.querySelector('.newspack-empty-state__header').firstElementChild).toHaveStyle({
163
+ gap: 'var(--wpds-dimension-gap-md, 12px)'
164
+ });
165
+ });
166
+ it('lets heading override the level the size implies', function () {
167
+ render(/*#__PURE__*/_jsx(EmptyState.Root, {
168
+ size: "small",
169
+ children: /*#__PURE__*/_jsx(EmptyState.Header, {
170
+ title: "No products match this rule",
171
+ heading: 1
172
+ })
173
+ }));
174
+ expect(screen.getByRole('heading', {
175
+ level: 1,
176
+ name: 'No products match this rule'
177
+ })).toBeInTheDocument();
178
+ });
179
+ it('carries its own class hook alongside any className', function () {
180
+ var _render1 = render(/*#__PURE__*/_jsx(EmptyState.Root, {
181
+ children: /*#__PURE__*/_jsx(EmptyState.Header, {
182
+ title: "Get started with newsletters",
183
+ className: "consumer-header"
184
+ })
185
+ })),
186
+ container = _render1.container;
187
+ var header = container.querySelector('.newspack-empty-state__header');
188
+ expect(header).toBeInTheDocument();
189
+ expect(header).toHaveClass('consumer-header');
190
+ });
191
+ it('throws outside Root in development', function () {
192
+ var consoleError = jest.spyOn(console, 'error').mockImplementation(function () {});
193
+ try {
194
+ expect(function () {
195
+ return render(/*#__PURE__*/_jsx(EmptyState.Header, {
196
+ title: "Orphan"
197
+ }));
198
+ }).toThrow('EmptyState subcomponents must be rendered inside EmptyState.Root.');
199
+ } finally {
200
+ consoleError.mockRestore();
201
+ }
202
+ });
203
+
204
+ // Header is the visible half, so a misplaced one blanking an admin screen costs more
205
+ // than the default size it falls back to.
206
+ it('falls back to the default size outside Root in production', function () {
207
+ var previous = process.env.NODE_ENV;
208
+ process.env.NODE_ENV = 'production';
209
+ try {
210
+ var _render10 = render(/*#__PURE__*/_jsx(EmptyState.Header, {
211
+ title: "Orphan",
212
+ icon: /*#__PURE__*/_jsx("svg", {})
213
+ })),
214
+ container = _render10.container;
215
+ expect(screen.getByRole('heading', {
216
+ level: 2,
217
+ name: 'Orphan'
218
+ })).toBeInTheDocument();
219
+ expect(container.querySelector('.newspack-empty-state__header--small')).not.toBeInTheDocument();
220
+ expect(container.querySelector('.newspack-empty-state__icon svg')).toHaveAttribute('width', '48');
221
+ } finally {
222
+ process.env.NODE_ENV = previous;
223
+ }
224
+ });
225
+ });
226
+ describe('EmptyState.Actions', function () {
227
+ it('renders its children in a centred row', function () {
228
+ var _render11 = render(/*#__PURE__*/_jsx(EmptyState.Root, {
229
+ children: /*#__PURE__*/_jsx(EmptyState.Actions, {
230
+ children: /*#__PURE__*/_jsx("button", {
231
+ type: "button",
232
+ children: "Add Newsletter"
233
+ })
234
+ })
235
+ })),
236
+ container = _render11.container;
237
+ expect(container.querySelector('.newspack-empty-state__actions')).toBeInTheDocument();
238
+ expect(container.querySelector('.newspack-empty-state__actions')).toHaveStyle({
239
+ justifyContent: 'center',
240
+ gap: 'var(--wpds-dimension-gap-sm, 8px)'
241
+ });
242
+ expect(screen.getByRole('button', {
243
+ name: 'Add Newsletter'
244
+ })).toBeInTheDocument();
245
+ });
246
+ it('stacks into a column while keeping the hook class', function () {
247
+ var _render12 = render(/*#__PURE__*/_jsx(EmptyState.Root, {
248
+ children: /*#__PURE__*/_jsxs(EmptyState.Actions, {
249
+ orientation: "column",
250
+ children: [/*#__PURE__*/_jsx("button", {
251
+ type: "button",
252
+ children: "Set up Audience Management"
253
+ }), /*#__PURE__*/_jsx("a", {
254
+ href: "https://example.com",
255
+ children: "Learn more"
256
+ })]
257
+ })
258
+ })),
259
+ container = _render12.container;
260
+ var actions = container.querySelector('.newspack-empty-state__actions');
261
+ expect(actions).toBeInTheDocument();
262
+ expect(actions).toHaveStyle({
263
+ flexDirection: 'column'
264
+ });
265
+ // A stack's own default is `stretch`, so without align="center" the buttons
266
+ // would go full-bleed while flexDirection stayed correct.
267
+ expect(actions).toHaveStyle({
268
+ alignItems: 'center'
269
+ });
270
+ });
271
+ it('throws outside Root in development', function () {
272
+ var consoleError = jest.spyOn(console, 'error').mockImplementation(function () {});
273
+ try {
274
+ expect(function () {
275
+ return render(/*#__PURE__*/_jsx(EmptyState.Actions, {
276
+ children: "x"
277
+ }));
278
+ }).toThrow('EmptyState subcomponents must be rendered inside EmptyState.Root.');
279
+ } finally {
280
+ consoleError.mockRestore();
281
+ }
282
+ });
283
+
284
+ // Actions reads nothing from context, so the invariant is a development aid. A
285
+ // stray one must not blank an admin screen in production over a layout hint.
286
+ it('renders outside Root in production', function () {
287
+ var previous = process.env.NODE_ENV;
288
+ process.env.NODE_ENV = 'production';
289
+ try {
290
+ var _render13 = render(/*#__PURE__*/_jsx(EmptyState.Actions, {
291
+ children: "x"
292
+ })),
293
+ container = _render13.container;
294
+ expect(container.querySelector('.newspack-empty-state__actions')).toBeInTheDocument();
295
+ } finally {
296
+ process.env.NODE_ENV = previous;
297
+ }
298
+ });
299
+ });
@@ -0,0 +1,56 @@
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
+ * WordPress dependencies.
6
+ */
7
+ import { useMemo } from '@wordpress/element';
8
+ import { Stack } from '@wordpress/ui';
9
+
10
+ /**
11
+ * External dependencies.
12
+ */
13
+ import classnames from 'classnames';
14
+
15
+ /**
16
+ * Internal dependencies.
17
+ */
18
+ import Grid from '../grid';
19
+ import { EmptyStateContext } from './context';
20
+ import './style.scss';
21
+
22
+ // Positions the stack in columns 2 to 4. `data-` attributes because that is the form
23
+ // grid/style.scss standardised on, after prop filtering was found to drop a bare `end`
24
+ // before it reached the DOM. That file carries the full note.
25
+ import { jsx as _jsx } from "react/jsx-runtime";
26
+ var gridColumn = {
27
+ 'data-start': '2',
28
+ 'data-end': '4'
29
+ };
30
+ var Root = function Root(_ref) {
31
+ var _ref$size = _ref.size,
32
+ size = _ref$size === void 0 ? 'default' : _ref$size,
33
+ className = _ref.className,
34
+ children = _ref.children;
35
+ var context = useMemo(function () {
36
+ return {
37
+ size: size
38
+ };
39
+ }, [size]);
40
+ return /*#__PURE__*/_jsx(EmptyStateContext.Provider, {
41
+ value: context,
42
+ children: /*#__PURE__*/_jsx(Grid, {
43
+ className: classnames('newspack-empty-state', className),
44
+ columns: 4,
45
+ noMargin: true,
46
+ children: /*#__PURE__*/_jsx(Stack, _objectSpread(_objectSpread({
47
+ className: "newspack-empty-state__stack",
48
+ direction: "column",
49
+ gap: "2xl"
50
+ }, gridColumn), {}, {
51
+ children: children
52
+ }))
53
+ })
54
+ });
55
+ };
56
+ export default Root;
@@ -0,0 +1,51 @@
1
+ @use "~@wordpress/base-styles/colors" as wp-colors;
2
+ @use "~@wordpress/base-styles/mixins" as wp-mixins;
3
+ @use "~@wordpress/base-styles/variables" as wp-vars;
4
+ @use "../../../colors/colors.module" as np-colors;
5
+
6
+ .newspack-empty-state {
7
+ &__stack {
8
+ margin-inline: auto;
9
+ max-width: var(--wpds-dimension-surface-width-lg, 560px);
10
+ }
11
+
12
+ &__header {
13
+ text-align: center;
14
+ text-wrap: balance;
15
+ }
16
+
17
+ &__icon {
18
+ background-color: var(--wp-admin-theme-color-lighter-10, #{np-colors.$primary-000});
19
+ border-radius: 100%;
20
+ display: grid;
21
+ height: wp-vars.$grid-unit-50 * 2;
22
+ place-items: center;
23
+ width: wp-vars.$grid-unit-50 * 2;
24
+
25
+ svg {
26
+ fill: var(--wp-admin-theme-color, #{np-colors.$primary-600});
27
+ }
28
+ }
29
+
30
+ &__title {
31
+ @include wp-mixins.heading-x-large();
32
+ color: var(--wpds-color-foreground-content-neutral, #{wp-colors.$gray-900});
33
+ margin: 0;
34
+ }
35
+
36
+ &__description {
37
+ color: var(--wpds-color-foreground-content-neutral-weak, #{wp-colors.$gray-700});
38
+ margin: 0;
39
+ }
40
+
41
+ &__header--small {
42
+ .newspack-empty-state__icon {
43
+ height: wp-vars.$grid-unit-50;
44
+ width: wp-vars.$grid-unit-50;
45
+ }
46
+
47
+ .newspack-empty-state__title {
48
+ @include wp-mixins.heading-large();
49
+ }
50
+ }
51
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/esm/index.js CHANGED
@@ -1,9 +1,7 @@
1
- export { default as Accordion, AccordionPanel } from './accordion';
2
1
  export { default as ActionCard } from './action-card';
3
2
  export { default as AutocompleteTokenField } from './autocomplete-tokenfield';
4
3
  export { default as AutocompleteWithSuggestions } from './autocomplete-with-suggestions';
5
4
  export { default as AutocompleteWithLatestPosts } from './autocomplete-with-latest-posts';
6
- export { default as Badge } from './badge';
7
5
  export { default as Breadcrumbs } from './breadcrumbs';
8
6
  export { default as Button } from './button';
9
7
  export { default as BoxContrast } from './box-contrast';
@@ -14,12 +12,14 @@ export { default as CardSettingsGroup } from './card-settings-group';
14
12
  export { default as CardSortableList } from './card-sortable-list';
15
13
  export { default as IntegrationIcon } from './integration-icon';
16
14
  export { default as CategoryAutocomplete } from './category-autocomplete';
15
+ export { default as CollapsibleGroup } from './collapsible-group';
17
16
  export { default as ColorPicker } from './color-picker';
18
17
  export { default as ConfirmDialog } from './confirm-dialog';
19
18
  export { default as CustomSelectControl } from './custom-select-control';
20
19
  export { default as DataViews } from './dataviews';
21
20
  export { default as Divider } from './divider';
22
21
  export { default as Drawer } from './drawer';
22
+ export { default as EmptyState } from './empty-state';
23
23
  export { default as FormTokenField } from './form-token-field';
24
24
  export { default as Footer } from './footer';
25
25
  export { default as Handoff } from './handoff';
@@ -42,6 +42,8 @@ export { default as RadioControl } from './radio-control';
42
42
  export { default as SectionHeader } from './section-header';
43
43
  export { default as SelectControl } from './select-control';
44
44
  export { default as Settings } from './settings';
45
+ export { default as StatCard, STAT_CARD_NULL_GLYPH } from './stat-card';
46
+ export { default as StatusIndicator } from './status-indicator';
45
47
  export { default as StepsList } from './steps-list';
46
48
  export { default as StepsListItem } from './steps-list-item';
47
49
  export { default as StyleCard } from './style-card';
@@ -1,61 +1,72 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
- import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
4
- import _createClass from "@babel/runtime/helpers/createClass";
5
- import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
6
- import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
7
- import _inherits from "@babel/runtime/helpers/inherits";
8
- var _excluded = ["className"];
3
+ var _excluded = ["description", "className", "triggerLabel", "aria-label"];
9
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; }
10
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; }
11
- function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
12
- function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
13
6
  /**
14
- * Info Button
7
+ * External dependencies.
15
8
  */
9
+ import classnames from 'classnames';
16
10
 
17
11
  /**
18
12
  * WordPress dependencies.
19
13
  */
20
- import { Component } from '@wordpress/element';
21
- import { Tooltip } from '@wordpress/components';
14
+ import { forwardRef } from '@wordpress/element';
15
+ import { __ } from '@wordpress/i18n';
22
16
  import { Icon, info } from '@wordpress/icons';
23
-
24
- /**
25
- * External dependencies.
26
- */
27
- import classnames from 'classnames';
17
+ import { getWpCompatOverlaySlot, Popover, VisuallyHidden } from '@wordpress/ui';
28
18
 
29
19
  /**
30
20
  * Internal dependencies.
31
21
  */
32
22
  import './style.scss';
33
- import { jsx as _jsx } from "react/jsx-runtime";
34
- var InfoButton = /*#__PURE__*/function (_Component) {
35
- function InfoButton() {
36
- _classCallCheck(this, InfoButton);
37
- return _callSuper(this, InfoButton, arguments);
23
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
24
+ /**
25
+ * Uses `Popover` rather than `Tooltip`: a tooltip never opens from a touch
26
+ * pointer, and its popup is not exposed to assistive technology.
27
+ */
28
+ var InfoButton = forwardRef(function InfoButton(_ref, ref) {
29
+ var description = _ref.description,
30
+ className = _ref.className,
31
+ triggerLabel = _ref.triggerLabel,
32
+ ariaLabel = _ref['aria-label'],
33
+ rest = _objectWithoutProperties(_ref, _excluded);
34
+ if (!description) {
35
+ return null;
38
36
  }
39
- _inherits(InfoButton, _Component);
40
- return _createClass(InfoButton, [{
41
- key: "render",
42
- value:
43
- /**
44
- * Render.
45
- */
46
- function render() {
47
- var _this$props = this.props,
48
- className = _this$props.className,
49
- otherProps = _objectWithoutProperties(_this$props, _excluded);
50
- return /*#__PURE__*/_jsx(Tooltip, _objectSpread(_objectSpread({}, otherProps), {}, {
51
- children: /*#__PURE__*/_jsx("span", {
52
- className: classnames('newspack-info-button', className),
53
- children: /*#__PURE__*/_jsx(Icon, {
54
- icon: info
55
- })
56
- })
57
- }));
58
- }
59
- }]);
60
- }(Component);
37
+ var name = triggerLabel || ariaLabel || __('More information', 'newspack-plugin');
38
+ return /*#__PURE__*/_jsxs(Popover.Root, {
39
+ children: [/*#__PURE__*/_jsx(Popover.Trigger, _objectSpread(_objectSpread({
40
+ ref: ref,
41
+ openOnHover: true,
42
+ delay: 200,
43
+ closeDelay: 200,
44
+ "aria-label": name,
45
+ className: classnames('newspack-info-button', className)
46
+ }, rest), {}, {
47
+ children: /*#__PURE__*/_jsx(Icon, {
48
+ icon: info,
49
+ size: 20
50
+ })
51
+ })), /*#__PURE__*/_jsxs(Popover.Popup, {
52
+ variant: "unstyled",
53
+ className: "newspack-info-button__popup",
54
+ portal: /*#__PURE__*/_jsx(Popover.Portal, {
55
+ className: "newspack-info-button__portal",
56
+ container: getWpCompatOverlaySlot()
57
+ }),
58
+ positioner: /*#__PURE__*/_jsx(Popover.Positioner, {
59
+ className: "newspack-info-button__positioner",
60
+ side: "top",
61
+ sideOffset: 4
62
+ }),
63
+ children: [/*#__PURE__*/_jsx(VisuallyHidden, {
64
+ render: /*#__PURE__*/_jsx(Popover.Title, {}),
65
+ children: name
66
+ }), /*#__PURE__*/_jsx(Popover.Description, {
67
+ children: description
68
+ })]
69
+ })]
70
+ });
71
+ });
61
72
  export default InfoButton;