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
@@ -7,18 +7,18 @@ import classnames from 'classnames';
7
7
  * WordPress dependencies
8
8
  */
9
9
  import { __, _x, sprintf } from '@wordpress/i18n';
10
- import { isValidElement } from '@wordpress/element';
11
- import { DropdownMenu, __experimentalHStack as HStack } from '@wordpress/components'; // eslint-disable-line @wordpress/no-unsafe-wp-apis
10
+ import { createElement, isValidElement } from '@wordpress/element';
11
+ import { useInstanceId } from '@wordpress/compose';
12
+ import { DropdownMenu } from '@wordpress/components';
12
13
  import { moreVertical } from '@wordpress/icons';
14
+ import { Badge, Card, Stack } from '@wordpress/ui';
13
15
 
14
16
  /**
15
17
  * Internal dependencies
16
18
  */
17
- import Badge from '../badge';
18
19
  import Button from '../button';
19
- import Card from '../card';
20
20
  import './style.scss';
21
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
21
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
22
22
  /**
23
23
  * CardFeature component.
24
24
  *
@@ -26,8 +26,10 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
26
26
  * action model: a primary button, an optional "More" dropdown when enabled,
27
27
  * and an automatic badge reflecting the current state.
28
28
  */
29
- var CardFeature = function CardFeature(_ref) {
29
+ var _CardFeature = function CardFeature(_ref) {
30
30
  var title = _ref.title,
31
+ _ref$headingLevel = _ref.headingLevel,
32
+ headingLevel = _ref$headingLevel === void 0 ? 3 : _ref$headingLevel,
31
33
  description = _ref.description,
32
34
  icon = _ref.icon,
33
35
  _ref$enabled = _ref.enabled,
@@ -42,10 +44,11 @@ var CardFeature = function CardFeature(_ref) {
42
44
  onEnable = _ref.onEnable,
43
45
  onConfigure = _ref.onConfigure,
44
46
  moreControls = _ref.moreControls,
45
- badgeText = _ref.badgeText,
46
- _ref$badgeLevel = _ref.badgeLevel,
47
- badgeLevel = _ref$badgeLevel === void 0 ? 'success' : _ref$badgeLevel,
47
+ badgeProp = _ref.badge,
48
48
  className = _ref.className;
49
+ var instanceId = useInstanceId(_CardFeature, 'newspack-card-feature');
50
+ var badgeId = "".concat(instanceId, "__badge");
51
+ var describedById = requirements ? badgeId : undefined;
49
52
  var isMuted = !!requirements;
50
53
  var classes = classnames('newspack-card-feature', className, {
51
54
  'newspack-card-feature--muted': isMuted
@@ -53,13 +56,14 @@ var CardFeature = function CardFeature(_ref) {
53
56
  var badge;
54
57
  if (requirements) {
55
58
  badge = {
56
- text: requirements,
57
- level: 'error'
59
+ label: requirements,
60
+ intent: 'high'
58
61
  };
59
62
  } else if (enabled) {
63
+ var _badgeProp$label, _badgeProp$intent;
60
64
  badge = {
61
- text: badgeText !== null && badgeText !== void 0 ? badgeText : __('Enabled', 'newspack-plugin'),
62
- level: badgeLevel
65
+ label: (_badgeProp$label = badgeProp === null || badgeProp === void 0 ? void 0 : badgeProp.label) !== null && _badgeProp$label !== void 0 ? _badgeProp$label : __('Enabled', 'newspack-plugin'),
66
+ intent: (_badgeProp$intent = badgeProp === null || badgeProp === void 0 ? void 0 : badgeProp.intent) !== null && _badgeProp$intent !== void 0 ? _badgeProp$intent : 'stable'
63
67
  };
64
68
  }
65
69
  var isConfigureState = enabled && !requirements;
@@ -84,7 +88,11 @@ var CardFeature = function CardFeature(_ref) {
84
88
  if (isValidElement(icon)) {
85
89
  renderedIcon = icon;
86
90
  } else if (iconDescriptor) {
87
- renderedIcon = /*#__PURE__*/_jsx("div", {
91
+ renderedIcon =
92
+ /*#__PURE__*/
93
+ // Decorative: a vendor mark passed as `node` carries no aria-hidden of its own.
94
+ _jsx("div", {
95
+ "aria-hidden": "true",
88
96
  className: iconClasses,
89
97
  style: {
90
98
  backgroundColor: iconDescriptor.backgroundColor,
@@ -93,57 +101,65 @@ var CardFeature = function CardFeature(_ref) {
93
101
  children: iconDescriptor.node
94
102
  });
95
103
  }
96
- return /*#__PURE__*/_jsx(Card, {
104
+ return /*#__PURE__*/_jsxs(Card.Root, {
97
105
  className: classes,
98
- __experimentalCoreCard: true,
99
- __experimentalCoreProps: {
100
- headerStyle: {
101
- padding: 32
102
- },
103
- header: /*#__PURE__*/_jsxs(_Fragment, {
104
- children: [/*#__PURE__*/_jsxs(HStack, {
105
- alignment: "top",
106
- spacing: 4,
107
- children: [/*#__PURE__*/_jsxs("div", {
108
- className: "newspack-card-feature__content",
109
- children: [/*#__PURE__*/_jsx("h2", {
110
- className: "newspack-card-feature__title",
111
- children: title
112
- }), description && /*#__PURE__*/_jsx("p", {
113
- className: "newspack-card-feature__description",
114
- children: description
115
- })]
116
- }), renderedIcon]
117
- }), /*#__PURE__*/_jsxs(HStack, {
118
- alignment: "edge",
119
- children: [/*#__PURE__*/_jsxs(HStack, {
120
- expanded: false,
121
- spacing: "8px",
122
- children: [/*#__PURE__*/_jsx(Button, {
123
- variant: isConfigureState ? 'tertiary' : 'secondary',
124
- disabled: isMuted && !requirementsActionable || busy,
125
- isBusy: busy,
126
- onClick: handleButtonClick,
127
- size: "compact",
128
- "aria-label": buttonAccessibleLabel,
129
- children: buttonLabel
130
- }), showMoreControls && /*#__PURE__*/_jsx(DropdownMenu, {
131
- icon: moreVertical,
132
- label: sprintf(
133
- // translators: %s: the feature's name.
134
- __('More options for %s', 'newspack-plugin'), title),
135
- controls: moreControls,
136
- toggleProps: {
137
- size: 'compact'
138
- }
139
- })]
140
- }), badge && /*#__PURE__*/_jsx(Badge, {
141
- text: badge.text,
142
- level: badge.level
106
+ children: [/*#__PURE__*/_jsx(Card.Header, {
107
+ children: /*#__PURE__*/_jsxs(Stack, {
108
+ direction: "row",
109
+ align: "start",
110
+ gap: "lg",
111
+ children: [/*#__PURE__*/_jsxs(Stack, {
112
+ className: "newspack-card-feature__content",
113
+ direction: "column",
114
+ gap: "sm",
115
+ children: [createElement("h".concat(headingLevel), {
116
+ className: 'newspack-card-feature__title'
117
+ }, title), description && /*#__PURE__*/_jsx("p", {
118
+ className: "newspack-card-feature__description",
119
+ children: description
120
+ })]
121
+ }), renderedIcon]
122
+ })
123
+ }), /*#__PURE__*/_jsx(Card.Content, {
124
+ className: "newspack-card-feature__actions",
125
+ children: /*#__PURE__*/_jsxs(Stack, {
126
+ direction: "row",
127
+ align: "center",
128
+ justify: "space-between",
129
+ gap: "sm",
130
+ wrap: "wrap",
131
+ children: [/*#__PURE__*/_jsxs(Stack, {
132
+ direction: "row",
133
+ align: "center",
134
+ gap: "sm",
135
+ children: [/*#__PURE__*/_jsx(Button, {
136
+ variant: isConfigureState ? 'tertiary' : 'secondary',
137
+ accessibleWhenDisabled: true,
138
+ "aria-describedby": describedById,
139
+ "aria-label": buttonAccessibleLabel,
140
+ disabled: isMuted && !requirementsActionable || busy,
141
+ isBusy: busy,
142
+ onClick: handleButtonClick,
143
+ size: "compact",
144
+ children: buttonLabel
145
+ }), showMoreControls && /*#__PURE__*/_jsx(DropdownMenu, {
146
+ icon: moreVertical,
147
+ label: sprintf(
148
+ // translators: %s: the feature's name.
149
+ __('More options for %s', 'newspack-plugin'), title),
150
+ controls: moreControls,
151
+ toggleProps: {
152
+ size: 'compact'
153
+ }
143
154
  })]
155
+ }), badge && /*#__PURE__*/_jsx(Badge, {
156
+ id: describedById,
157
+ className: "newspack-card-feature__badge",
158
+ intent: badge.intent,
159
+ children: badge.label
144
160
  })]
145
161
  })
146
- }
162
+ })]
147
163
  });
148
164
  };
149
- export default CardFeature;
165
+ export default _CardFeature;
@@ -4,7 +4,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
4
4
  /**
5
5
  * External dependencies.
6
6
  */
7
- import { render, screen } from '@testing-library/react';
7
+ import { fireEvent, render, screen } from '@testing-library/react';
8
8
 
9
9
  /**
10
10
  * WordPress dependencies.
@@ -27,70 +27,412 @@ jest.mock('@wordpress/i18n', function () {
27
27
  })
28
28
  });
29
29
  });
30
+ var primaryButton = function primaryButton() {
31
+ return screen.getByRole('button', {
32
+ name: /Enable|Configure/
33
+ });
34
+ };
35
+ var moreMenu = function moreMenu() {
36
+ return screen.queryByRole('button', {
37
+ name: /^More options for/
38
+ });
39
+ };
30
40
  describe('CardFeature', function () {
31
41
  beforeEach(function () {
32
42
  _x.mockClear();
33
43
  });
34
- it('names the feature in the primary button, keeping the visible label first', function () {
35
- render(/*#__PURE__*/_jsx(CardFeature, {
36
- title: "Metered Countdown"
37
- }));
38
- var button = screen.getByRole('button', {
39
- name: 'Enable Metered Countdown'
44
+ describe('structure', function () {
45
+ it('renders the title as a level-3 heading and the description alongside it', function () {
46
+ render(/*#__PURE__*/_jsx(CardFeature, {
47
+ title: "Content gifting",
48
+ description: "Let subscribers share gated articles."
49
+ }));
50
+ expect(screen.getByRole('heading', {
51
+ level: 3
52
+ })).toHaveTextContent('Content gifting');
53
+ expect(screen.getByText('Let subscribers share gated articles.')).toBeInTheDocument();
54
+ });
55
+ it('renders the title at the requested heading level', function () {
56
+ render(/*#__PURE__*/_jsx(CardFeature, {
57
+ title: "Content gifting",
58
+ headingLevel: 4
59
+ }));
60
+ expect(screen.getByRole('heading', {
61
+ level: 4
62
+ })).toHaveTextContent('Content gifting');
63
+ expect(screen.queryByRole('heading', {
64
+ level: 3
65
+ })).not.toBeInTheDocument();
66
+ });
67
+ it('omits the description paragraph when none is passed', function () {
68
+ var _render = render(/*#__PURE__*/_jsx(CardFeature, {
69
+ title: "Content gifting"
70
+ })),
71
+ container = _render.container;
72
+ expect(container.querySelector('.newspack-card-feature__description')).toBeNull();
40
73
  });
41
- expect(button).toHaveTextContent('Enable');
42
- expect(button.getAttribute('aria-label').startsWith(button.textContent)).toBe(true);
43
74
  });
44
- it('carries a custom label into the accessible name', function () {
45
- render(/*#__PURE__*/_jsx(CardFeature, {
46
- title: "Subscription retention",
47
- enableLabel: "Change"
48
- }));
49
- expect(screen.getByRole('button', {
50
- name: 'Change Subscription retention'
51
- })).toHaveTextContent('Change');
75
+ describe('accessible names', function () {
76
+ it('names the feature in the primary button, keeping the visible label first', function () {
77
+ render(/*#__PURE__*/_jsx(CardFeature, {
78
+ title: "Metered Countdown"
79
+ }));
80
+ var button = screen.getByRole('button', {
81
+ name: 'Enable Metered Countdown'
82
+ });
83
+ expect(button).toHaveTextContent('Enable');
84
+ expect(button.getAttribute('aria-label').startsWith(button.textContent)).toBe(true);
85
+ });
86
+ it('carries a custom label into the accessible name', function () {
87
+ render(/*#__PURE__*/_jsx(CardFeature, {
88
+ title: "Subscription retention",
89
+ enableLabel: "Change"
90
+ }));
91
+ expect(screen.getByRole('button', {
92
+ name: 'Change Subscription retention'
93
+ })).toHaveTextContent('Change');
94
+ });
95
+ it('names the feature in the configure state too', function () {
96
+ render(/*#__PURE__*/_jsx(CardFeature, {
97
+ title: "Content Gifting",
98
+ enabled: true
99
+ }));
100
+ expect(screen.getByRole('button', {
101
+ name: 'Configure Content Gifting'
102
+ })).toBeInTheDocument();
103
+ });
104
+ it('names the feature in the More menu', function () {
105
+ render(/*#__PURE__*/_jsx(CardFeature, {
106
+ title: "Content Gifting",
107
+ enabled: true,
108
+ moreControls: [{
109
+ title: 'Disable',
110
+ onClick: function onClick() {}
111
+ }]
112
+ }));
113
+ expect(screen.getByRole('button', {
114
+ name: 'More options for Content Gifting'
115
+ })).toBeInTheDocument();
116
+ });
117
+ it('gives the accessible-name order its own catalogue entry', function () {
118
+ render(/*#__PURE__*/_jsx(CardFeature, {
119
+ title: "Metered Countdown"
120
+ }));
121
+ expect(_x).toHaveBeenCalledWith('%1$s %2$s', 'accessible button name: visible action label, then feature name', 'newspack-plugin');
122
+ });
123
+ it('distinguishes two cards that share a button label', function () {
124
+ render(/*#__PURE__*/_jsxs(_Fragment, {
125
+ children: [/*#__PURE__*/_jsx(CardFeature, {
126
+ title: "Metered Countdown"
127
+ }), /*#__PURE__*/_jsx(CardFeature, {
128
+ title: "Content Gifting"
129
+ })]
130
+ }));
131
+ expect(screen.getByRole('button', {
132
+ name: 'Enable Metered Countdown'
133
+ })).toBeInTheDocument();
134
+ expect(screen.getByRole('button', {
135
+ name: 'Enable Content Gifting'
136
+ })).toBeInTheDocument();
137
+ });
52
138
  });
53
- it('names the feature in the configure state too', function () {
54
- render(/*#__PURE__*/_jsx(CardFeature, {
55
- title: "Content Gifting",
56
- enabled: true
57
- }));
58
- expect(screen.getByRole('button', {
59
- name: 'Configure Content Gifting'
60
- })).toBeInTheDocument();
139
+ describe('primary button', function () {
140
+ it('reads Enable and calls onEnable when the feature is off', function () {
141
+ var onEnable = jest.fn();
142
+ var onConfigure = jest.fn();
143
+ render(/*#__PURE__*/_jsx(CardFeature, {
144
+ title: "Content gifting",
145
+ onEnable: onEnable,
146
+ onConfigure: onConfigure
147
+ }));
148
+ expect(primaryButton()).toHaveTextContent('Enable');
149
+ fireEvent.click(primaryButton());
150
+ expect(onEnable).toHaveBeenCalledTimes(1);
151
+ expect(onConfigure).not.toHaveBeenCalled();
152
+ });
153
+ it('reads Configure and calls onConfigure once enabled', function () {
154
+ var onEnable = jest.fn();
155
+ var onConfigure = jest.fn();
156
+ render(/*#__PURE__*/_jsx(CardFeature, {
157
+ title: "Content gifting",
158
+ enabled: true,
159
+ onEnable: onEnable,
160
+ onConfigure: onConfigure
161
+ }));
162
+ expect(primaryButton()).toHaveTextContent('Configure');
163
+ fireEvent.click(primaryButton());
164
+ expect(onConfigure).toHaveBeenCalledTimes(1);
165
+ expect(onEnable).not.toHaveBeenCalled();
166
+ });
167
+ it('still routes to onEnable when enabled with an unmet requirement, since the button reads Enable', function () {
168
+ var onEnable = jest.fn();
169
+ var onConfigure = jest.fn();
170
+ render(/*#__PURE__*/_jsx(CardFeature, {
171
+ title: "Content gifting",
172
+ enabled: true,
173
+ requirements: "Requires metering",
174
+ requirementsActionable: true,
175
+ onEnable: onEnable,
176
+ onConfigure: onConfigure
177
+ }));
178
+ expect(primaryButton()).toHaveTextContent('Enable');
179
+ fireEvent.click(primaryButton());
180
+ expect(onEnable).toHaveBeenCalledTimes(1);
181
+ expect(onConfigure).not.toHaveBeenCalled();
182
+ });
183
+ it('keeps the button live on an actionable requirement before the feature is on, which is how Activate reaches the user', function () {
184
+ var onEnable = jest.fn();
185
+ render(/*#__PURE__*/_jsx(CardFeature, {
186
+ title: "Mailchimp",
187
+ requirements: "Requires WooCommerce",
188
+ requirementsActionable: true,
189
+ enableLabel: "Activate",
190
+ onEnable: onEnable
191
+ }));
192
+ var button = screen.getByRole('button', {
193
+ name: 'Activate Mailchimp'
194
+ });
195
+ expect(button).not.toHaveAttribute('aria-disabled');
196
+ fireEvent.click(button);
197
+ expect(onEnable).toHaveBeenCalledTimes(1);
198
+ expect(screen.getByText('Requires WooCommerce')).toBeInTheDocument();
199
+ });
200
+ it('does not fire when a requirement is not actionable, but stays reachable', function () {
201
+ var onEnable = jest.fn();
202
+ render(/*#__PURE__*/_jsx(CardFeature, {
203
+ title: "Content gifting",
204
+ requirements: "Managed by site configuration",
205
+ onEnable: onEnable
206
+ }));
207
+ expect(primaryButton()).toHaveAttribute('aria-disabled', 'true');
208
+ expect(primaryButton()).not.toHaveAttribute('disabled');
209
+ fireEvent.click(primaryButton());
210
+ expect(onEnable).not.toHaveBeenCalled();
211
+ });
212
+ it('points the blocked button at the badge that explains why', function () {
213
+ render(/*#__PURE__*/_jsx(CardFeature, {
214
+ title: "Content gifting",
215
+ requirements: "Managed by site configuration"
216
+ }));
217
+ var describedBy = primaryButton().getAttribute('aria-describedby');
218
+ expect(describedBy).toBeTruthy();
219
+ expect(document.getElementById(describedBy)).toHaveTextContent('Managed by site configuration');
220
+ });
221
+ it('leaves the enabled badge unlinked, since it explains nothing about the button', function () {
222
+ render(/*#__PURE__*/_jsx(CardFeature, {
223
+ title: "Content gifting",
224
+ enabled: true
225
+ }));
226
+ expect(primaryButton()).not.toHaveAttribute('aria-describedby');
227
+ });
228
+ it('disables the button while an action is in flight, even with an actionable requirement', function () {
229
+ var onEnable = jest.fn();
230
+ var _render2 = render(/*#__PURE__*/_jsx(CardFeature, {
231
+ title: "Content gifting",
232
+ busy: true,
233
+ onEnable: onEnable
234
+ })),
235
+ rerender = _render2.rerender;
236
+ expect(primaryButton()).toHaveAttribute('aria-disabled', 'true');
237
+ fireEvent.click(primaryButton());
238
+ expect(onEnable).not.toHaveBeenCalled();
239
+ rerender(/*#__PURE__*/_jsx(CardFeature, {
240
+ title: "Content gifting",
241
+ busy: true,
242
+ requirements: "Requires metering",
243
+ requirementsActionable: true,
244
+ onEnable: onEnable
245
+ }));
246
+ expect(primaryButton()).toHaveAttribute('aria-disabled', 'true');
247
+ });
248
+ it('accepts custom labels for both states', function () {
249
+ var _render3 = render(/*#__PURE__*/_jsx(CardFeature, {
250
+ title: "Apple News",
251
+ enableLabel: "Connect",
252
+ configureLabel: "Manage connection"
253
+ })),
254
+ rerender = _render3.rerender;
255
+ expect(screen.getByRole('button', {
256
+ name: 'Connect Apple News'
257
+ })).toBeInTheDocument();
258
+ rerender(/*#__PURE__*/_jsx(CardFeature, {
259
+ title: "Apple News",
260
+ enabled: true,
261
+ enableLabel: "Connect",
262
+ configureLabel: "Manage connection"
263
+ }));
264
+ expect(screen.getByRole('button', {
265
+ name: 'Manage connection Apple News'
266
+ })).toBeInTheDocument();
267
+ });
61
268
  });
62
- it('names the feature in the More menu', function () {
63
- render(/*#__PURE__*/_jsx(CardFeature, {
64
- title: "Content Gifting",
65
- enabled: true,
66
- moreControls: [{
67
- title: 'Disable',
68
- onClick: function onClick() {}
69
- }]
70
- }));
71
- expect(screen.getByRole('button', {
72
- name: 'More options for Content Gifting'
73
- })).toBeInTheDocument();
269
+ describe('badge', function () {
270
+ it('shows nothing when off, and the enabled badge when on', function () {
271
+ var _render4 = render(/*#__PURE__*/_jsx(CardFeature, {
272
+ title: "Content gifting"
273
+ })),
274
+ rerender = _render4.rerender;
275
+ expect(screen.queryByText('Enabled')).not.toBeInTheDocument();
276
+ rerender(/*#__PURE__*/_jsx(CardFeature, {
277
+ title: "Content gifting",
278
+ enabled: true
279
+ }));
280
+ expect(screen.getByText('Enabled')).toBeInTheDocument();
281
+ });
282
+ it('lets the requirements badge win over the enabled badge', function () {
283
+ render(/*#__PURE__*/_jsx(CardFeature, {
284
+ title: "Content gifting",
285
+ enabled: true,
286
+ requirements: "Requires metering"
287
+ }));
288
+ expect(screen.getByText('Requires metering')).toBeInTheDocument();
289
+ expect(screen.queryByText('Enabled')).not.toBeInTheDocument();
290
+ });
291
+ it('accepts custom badge text', function () {
292
+ render(/*#__PURE__*/_jsx(CardFeature, {
293
+ title: "Stripe",
294
+ enabled: true,
295
+ badge: {
296
+ label: 'Live mode',
297
+ intent: 'informational'
298
+ }
299
+ }));
300
+ expect(screen.getByText('Live mode')).toBeInTheDocument();
301
+ });
74
302
  });
75
- it('gives the accessible-name order its own catalogue entry', function () {
76
- render(/*#__PURE__*/_jsx(CardFeature, {
77
- title: "Metered Countdown"
78
- }));
79
- expect(_x).toHaveBeenCalledWith('%1$s %2$s', 'accessible button name: visible action label, then feature name', 'newspack-plugin');
303
+ describe('More menu', function () {
304
+ var controls = [{
305
+ title: 'Disable',
306
+ onClick: jest.fn()
307
+ }];
308
+ it('appears only when enabled and controls are supplied', function () {
309
+ var _render5 = render(/*#__PURE__*/_jsx(CardFeature, {
310
+ title: "Content gifting",
311
+ moreControls: controls
312
+ })),
313
+ rerender = _render5.rerender;
314
+ expect(moreMenu()).not.toBeInTheDocument();
315
+ rerender(/*#__PURE__*/_jsx(CardFeature, {
316
+ title: "Content gifting",
317
+ enabled: true
318
+ }));
319
+ expect(moreMenu()).not.toBeInTheDocument();
320
+ rerender(/*#__PURE__*/_jsx(CardFeature, {
321
+ title: "Content gifting",
322
+ enabled: true,
323
+ moreControls: controls
324
+ }));
325
+ expect(moreMenu()).toBeInTheDocument();
326
+ });
327
+ it('stays available on an actionable requirement and hides on a locked one', function () {
328
+ var _render6 = render(/*#__PURE__*/_jsx(CardFeature, {
329
+ title: "Content gifting",
330
+ enabled: true,
331
+ requirements: "Requires metering",
332
+ requirementsActionable: true,
333
+ moreControls: controls
334
+ })),
335
+ rerender = _render6.rerender;
336
+ expect(moreMenu()).toBeInTheDocument();
337
+ rerender(/*#__PURE__*/_jsx(CardFeature, {
338
+ title: "Content gifting",
339
+ enabled: true,
340
+ requirements: "Managed by site configuration",
341
+ moreControls: controls
342
+ }));
343
+ expect(moreMenu()).not.toBeInTheDocument();
344
+ });
80
345
  });
81
- it('distinguishes two cards that share a button label', function () {
82
- render(/*#__PURE__*/_jsxs(_Fragment, {
83
- children: [/*#__PURE__*/_jsx(CardFeature, {
84
- title: "Metered Countdown"
85
- }), /*#__PURE__*/_jsx(CardFeature, {
86
- title: "Content Gifting"
87
- })]
346
+ describe('icon', function () {
347
+ it('renders a ready element as-is, without the descriptor container', function () {
348
+ var _render7 = render(/*#__PURE__*/_jsx(CardFeature, {
349
+ title: "Content gifting",
350
+ icon: /*#__PURE__*/_jsx("span", {
351
+ "data-testid": "ready-icon"
352
+ })
353
+ })),
354
+ container = _render7.container;
355
+ expect(screen.getByTestId('ready-icon')).toBeInTheDocument();
356
+ expect(container.querySelector('.newspack-card-feature__icon')).toBeNull();
357
+ });
358
+ it('applies the descriptor colours inline and rounds fully on request', function () {
359
+ var _render8 = render(/*#__PURE__*/_jsx(CardFeature, {
360
+ title: "Content gifting",
361
+ icon: {
362
+ node: /*#__PURE__*/_jsx("span", {
363
+ "data-testid": "descriptor-icon"
364
+ }),
365
+ fill: '#003da5',
366
+ backgroundColor: '#dfe7f4',
367
+ radius: 'full'
368
+ }
369
+ })),
370
+ container = _render8.container;
371
+ var iconContainer = container.querySelector('.newspack-card-feature__icon');
372
+ expect(screen.getByTestId('descriptor-icon')).toBeInTheDocument();
373
+ expect(iconContainer).toHaveClass('newspack-card-feature__icon--radius-full');
374
+ expect(iconContainer).toHaveStyle({
375
+ backgroundColor: '#dfe7f4',
376
+ color: '#003da5'
377
+ });
378
+ });
379
+ it('hides the descriptor container from assistive tech, since the title already names the feature', function () {
380
+ var _render9 = render(/*#__PURE__*/_jsx(CardFeature, {
381
+ title: "Content gifting",
382
+ icon: {
383
+ node: /*#__PURE__*/_jsx("svg", {})
384
+ }
385
+ })),
386
+ container = _render9.container;
387
+ expect(container.querySelector('.newspack-card-feature__icon')).toHaveAttribute('aria-hidden', 'true');
388
+ });
389
+ it('falls back to small corners when a background is set without a radius', function () {
390
+ var _render0 = render(/*#__PURE__*/_jsx(CardFeature, {
391
+ title: "Content gifting",
392
+ icon: {
393
+ node: /*#__PURE__*/_jsx("span", {}),
394
+ backgroundColor: '#dfe7f4'
395
+ }
396
+ })),
397
+ container = _render0.container;
398
+ var iconContainer = container.querySelector('.newspack-card-feature__icon');
399
+ expect(iconContainer).toHaveClass('newspack-card-feature__icon--radius-small');
400
+ expect(iconContainer).not.toHaveClass('newspack-card-feature__icon--radius-full');
401
+ });
402
+ it('leaves an unbacked descriptor icon without a radius class', function () {
403
+ var _render1 = render(/*#__PURE__*/_jsx(CardFeature, {
404
+ title: "Content gifting",
405
+ icon: {
406
+ node: /*#__PURE__*/_jsx("span", {}),
407
+ fill: '#003da5'
408
+ }
409
+ })),
410
+ container = _render1.container;
411
+ var iconContainer = container.querySelector('.newspack-card-feature__icon');
412
+ expect(iconContainer).not.toHaveClass('newspack-card-feature__icon--radius-small');
413
+ });
414
+ });
415
+ it('passes className through to the card element', function () {
416
+ var _render10 = render(/*#__PURE__*/_jsx(CardFeature, {
417
+ title: "Content gifting",
418
+ className: "newspack-subscribers__card"
419
+ })),
420
+ container = _render10.container;
421
+ expect(container.querySelector('.newspack-card-feature')).toHaveClass('newspack-subscribers__card');
422
+ });
423
+ it('marks the card as muted only when requirements are set', function () {
424
+ var _render11 = render(/*#__PURE__*/_jsx(CardFeature, {
425
+ title: "Content gifting",
426
+ enabled: true
427
+ })),
428
+ container = _render11.container,
429
+ rerender = _render11.rerender;
430
+ expect(container.querySelector('.newspack-card-feature--muted')).toBeNull();
431
+ rerender(/*#__PURE__*/_jsx(CardFeature, {
432
+ title: "Content gifting",
433
+ enabled: true,
434
+ requirements: "Requires metering"
88
435
  }));
89
- expect(screen.getByRole('button', {
90
- name: 'Enable Metered Countdown'
91
- })).toBeInTheDocument();
92
- expect(screen.getByRole('button', {
93
- name: 'Enable Content Gifting'
94
- })).toBeInTheDocument();
436
+ expect(container.querySelector('.newspack-card-feature--muted')).toBeInTheDocument();
95
437
  });
96
438
  });