newspack-components 4.7.0 → 4.8.0-alpha.1

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