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,35 @@
1
+ /**
2
+ * WordPress dependencies.
3
+ */
4
+ import { caution, drafts, error, notAllowed, pending, published, scheduled, trash, update, lock } from '@wordpress/icons';
5
+
6
+ /**
7
+ * The glyph for each status a list can report.
8
+ *
9
+ * Two names may resolve to the same glyph where they read differently at the call
10
+ * site but mean the same to a reader: a sent newsletter is finished rather than
11
+ * live, and an ad that expired was not cancelled. Splitting them leaves room to
12
+ * draw them apart later without touching a consumer, and it means the rule a
13
+ * Status column keeps is about glyphs rather than names. `statusGlyph` is
14
+ * exported so a column's own test can assert it.
15
+ */
16
+ const STATUS_GLYPHS = {
17
+ active: published,
18
+ done: published,
19
+ scheduled,
20
+ draft: drafts,
21
+ pending,
22
+ attention: caution,
23
+ error,
24
+ progress: update,
25
+ cancelled: notAllowed,
26
+ ended: notAllowed,
27
+ private: lock,
28
+ trash,
29
+ } as const;
30
+
31
+ export type StatusName = keyof typeof STATUS_GLYPHS;
32
+
33
+ export const statusGlyph = ( status: StatusName ) => STATUS_GLYPHS[ status ];
34
+
35
+ export const STATUS_NAMES = Object.freeze( Object.keys( STATUS_GLYPHS ) as StatusName[] );
@@ -0,0 +1,9 @@
1
+ @use "~@wordpress/base-styles/variables" as wp-vars;
2
+
3
+ .newspack-status-indicator {
4
+ &__icon {
5
+ fill: currentcolor;
6
+ flex-shrink: 0;
7
+ margin: calc((#{wp-vars.$grid-unit-20} - #{wp-vars.$icon-size}) / 2);
8
+ }
9
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * WordPress dependencies.
3
+ */
4
+ import { Icon } from '@wordpress/components';
5
+
6
+ /**
7
+ * External dependencies.
8
+ */
9
+ import type { ComponentProps, ReactNode } from 'react';
10
+
11
+ /**
12
+ * Internal dependencies.
13
+ */
14
+ import type { StatusName } from './statuses';
15
+
16
+ // @wordpress/components does not export the Icon prop type, so the union is
17
+ // derived from the component to track the library instead of a copy kept here.
18
+ // `icon` is optional there, and indexing an optional property widens the union
19
+ // with `undefined`, so NonNullable is what keeps the glyph required here.
20
+ type StatusIcon = NonNullable< ComponentProps< typeof Icon >[ 'icon' ] >;
21
+
22
+ interface StatusIndicatorBaseProps extends Omit< ComponentProps< 'div' >, 'children' > {
23
+ /** The status label. @wordpress/primitives forces `aria-hidden` on the glyph, so this is the whole accessible name. */
24
+ children: ReactNode;
25
+ }
26
+
27
+ /** `icon` is the escape hatch for fields that classify rather than track a lifecycle. */
28
+ export type StatusIndicatorProps = StatusIndicatorBaseProps & ( { status: StatusName; icon?: never } | { status?: never; icon: StatusIcon } );
package/src/style.scss CHANGED
@@ -1,16 +1,16 @@
1
1
  @use "~@wordpress/base-styles/colors" as wp-colors;
2
- @use "../../colors/colors.module" as colors;
2
+ @use "../../colors/colors.module" as np-colors;
3
3
 
4
4
  :root {
5
5
  // WP Admin
6
- --wp-admin-theme-color: #{colors.$primary-600};
7
- --wp-admin-theme-color--rgb: #{colors.$primary-600--rgb};
8
- --wp-admin-theme-color-darker-10: #{colors.$primary-700};
9
- --wp-admin-theme-color-darker-10--rgb: #{colors.$primary-700--rgb};
10
- --wp-admin-theme-color-darker-20: #{colors.$primary-800};
11
- --wp-admin-theme-color-darker-20--rgb: #{colors.$primary-800--rgb};
12
- --wp-admin-theme-color-lighter-10: #{colors.$primary-000};
13
- --wp-admin-theme-color-lighter-10--rgb: #{colors.$primary-000--rgb};
6
+ --wp-admin-theme-color: #{np-colors.$primary-600};
7
+ --wp-admin-theme-color--rgb: #{np-colors.$primary-600--rgb};
8
+ --wp-admin-theme-color-darker-10: #{np-colors.$primary-700};
9
+ --wp-admin-theme-color-darker-10--rgb: #{np-colors.$primary-700--rgb};
10
+ --wp-admin-theme-color-darker-20: #{np-colors.$primary-800};
11
+ --wp-admin-theme-color-darker-20--rgb: #{np-colors.$primary-800--rgb};
12
+ --wp-admin-theme-color-lighter-10: #{np-colors.$primary-000};
13
+ --wp-admin-theme-color-lighter-10--rgb: #{np-colors.$primary-000--rgb};
14
14
  }
15
15
 
16
16
  // Buttons Card
@@ -2,7 +2,8 @@
2
2
  * Tabbed Navigation
3
3
  */
4
4
 
5
- @use "../../../colors/colors.module" as colors;
5
+ @use "../../../colors/colors.module" as np-colors;
6
+ @use "../mixins" as mixins;
6
7
  @use "~@wordpress/base-styles/colors" as wp-colors;
7
8
  @use "~@wordpress/base-styles/variables" as wp-vars;
8
9
 
@@ -18,7 +19,7 @@
18
19
  width: 100%;
19
20
 
20
21
  /* stylelint-disable-next-line plugin-wpds/no-setting-wpds-custom-properties -- deliberate Newspack brand override of the indicator token. */
21
- --wpds-color-stroke-interactive-neutral-strong: #{colors.$primary-600};
22
+ --wpds-color-stroke-interactive-neutral-strong: #{np-colors.$primary-600};
22
23
 
23
24
  a[role="tab"] {
24
25
  text-decoration: none;
@@ -53,6 +54,7 @@
53
54
 
54
55
  &[data-disabled],
55
56
  &[aria-disabled="true"] {
57
+ /* stylelint-disable-next-line plugin-wpds/no-unknown-ds-tokens -- the plugin's token list lags the prebuilt design-tokens.css names. */
56
58
  color: var( --wpds-color-foreground-interactive-neutral-disabled, #{wp-colors.$gray-600} );
57
59
  pointer-events: none;
58
60
  }
@@ -91,12 +93,12 @@
91
93
  }
92
94
 
93
95
  &:focus-visible {
94
- outline: var( --wpds-border-width-focus, var( --wp-admin-border-width-focus, #{wp-vars.$border-width-focus-fallback} ) ) solid var( --wpds-color-stroke-focus, var( --wp-admin-theme-color ) );
96
+ @include mixins.wpds-focus-ring;
95
97
  outline-offset: calc( var( --wpds-dimension-padding-md, #{wp-vars.$grid-unit-15} ) * -1 );
96
98
  }
97
99
 
98
100
  &[aria-current="page"] {
99
- box-shadow: inset 0 calc( var( --wpds-border-width-focus, #{wp-vars.$border-width-focus-fallback} ) * -1 ) 0 var( --wpds-color-stroke-interactive-neutral-strong, #{colors.$primary-600} );
101
+ box-shadow: inset 0 calc( var( --wpds-border-width-focus, #{wp-vars.$border-width-focus-fallback} ) * -1 ) 0 var( --wpds-color-stroke-interactive-neutral-strong, #{np-colors.$primary-600} );
100
102
  }
101
103
  }
102
104
  }
package/src/types.ts ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import type { Badge } from '@wordpress/ui';
5
+
6
+ /**
7
+ * Heading level for a component that renders a heading whose position in the
8
+ * document outline is the caller's to decide. Matches Core's `headingLevel` on
9
+ * `Page.Header`, `ToolsPanel` and `ColorPalette`. Level 1 is excluded: a card
10
+ * or panel is never a page's only heading.
11
+ */
12
+ export type HeadingLevel = 2 | 3 | 4 | 5 | 6;
13
+
14
+ // @wordpress/ui does not export BadgeProps, so the union is derived from the component.
15
+ export type BadgeIntent = NonNullable< React.ComponentProps< typeof Badge >[ 'intent' ] >;
16
+
17
+ /**
18
+ * A badge rendered beside a card title. The label is optional because cards drop
19
+ * a badge they cannot label rather than painting an empty pill, so a caller may
20
+ * build one straight from data that can be absent.
21
+ */
22
+ export type CardBadge = {
23
+ label?: string | null;
24
+ intent?: BadgeIntent;
25
+ };
@@ -3,20 +3,20 @@
3
3
  */
4
4
 
5
5
  @use "~@wordpress/base-styles/colors" as wp-colors;
6
- @use "../../../colors/colors.module" as colors;
6
+ @use "../../../colors/colors.module" as np-colors;
7
7
 
8
8
  .newspack-web-preview {
9
9
  // Color
10
- --wp-admin-theme-color: #{colors.$primary-600};
11
- --wp-admin-theme-color--rgb: #{colors.$primary-600--rgb};
12
- --wp-admin-theme-color-darker-10: #{colors.$primary-700};
13
- --wp-admin-theme-color-darker-10--rgb: #{colors.$primary-700--rgb};
14
- --wp-admin-theme-color-darker-20: #{colors.$primary-800};
15
- --wp-admin-theme-color-darker-20--rgb: #{colors.$primary-800--rgb};
16
- --wp-admin-theme-color-lighter-10: #{colors.$primary-000};
17
- --wp-admin-theme-color-lighter-10--rgb: #{colors.$primary-000--rgb};
18
-
19
- background: color-mix(in srgb, colors.$neutral-1000, transparent 65%);
10
+ --wp-admin-theme-color: #{np-colors.$primary-600};
11
+ --wp-admin-theme-color--rgb: #{np-colors.$primary-600--rgb};
12
+ --wp-admin-theme-color-darker-10: #{np-colors.$primary-700};
13
+ --wp-admin-theme-color-darker-10--rgb: #{np-colors.$primary-700--rgb};
14
+ --wp-admin-theme-color-darker-20: #{np-colors.$primary-800};
15
+ --wp-admin-theme-color-darker-20--rgb: #{np-colors.$primary-800--rgb};
16
+ --wp-admin-theme-color-lighter-10: #{np-colors.$primary-000};
17
+ --wp-admin-theme-color-lighter-10--rgb: #{np-colors.$primary-000--rgb};
18
+
19
+ background: color-mix(in srgb, np-colors.$neutral-1000, transparent 65%);
20
20
  box-sizing: border-box;
21
21
  height: 100%;
22
22
  left: 0;
@@ -3,19 +3,19 @@
3
3
  */
4
4
 
5
5
  @use "~@wordpress/base-styles/colors" as wp-colors;
6
- @use "../../../colors/colors.module" as colors;
6
+ @use "../../../colors/colors.module" as np-colors;
7
7
 
8
8
  // Styling for full-page-react Wizards (ignoring admin-header-only wizards).
9
9
  body.newspack-wizard-page:not(.newspack-admin-header) {
10
- --wp-admin-theme-color: #{colors.$primary-600};
11
- --wp-admin-theme-color--rgb: #{colors.$primary-600--rgb};
12
- --wp-admin-theme-color-darker-10: #{colors.$primary-700};
13
- --wp-admin-theme-color-darker-10--rgb: #{colors.$primary-700--rgb};
14
- --wp-admin-theme-color-darker-20: #{colors.$primary-800};
15
- --wp-admin-theme-color-darker-20--rgb: #{colors.$primary-800--rgb};
16
- --wp-admin-theme-color-lighter-10: #{colors.$primary-000};
17
- --wp-admin-theme-color-lighter-10--rgb: #{colors.$primary-000--rgb};
18
- --wp-components-color-accent: #{colors.$primary-600};
10
+ --wp-admin-theme-color: #{np-colors.$primary-600};
11
+ --wp-admin-theme-color--rgb: #{np-colors.$primary-600--rgb};
12
+ --wp-admin-theme-color-darker-10: #{np-colors.$primary-700};
13
+ --wp-admin-theme-color-darker-10--rgb: #{np-colors.$primary-700--rgb};
14
+ --wp-admin-theme-color-darker-20: #{np-colors.$primary-800};
15
+ --wp-admin-theme-color-darker-20--rgb: #{np-colors.$primary-800--rgb};
16
+ --wp-admin-theme-color-lighter-10: #{np-colors.$primary-000};
17
+ --wp-admin-theme-color-lighter-10--rgb: #{np-colors.$primary-000--rgb};
18
+ --wp-components-color-accent: #{np-colors.$primary-600};
19
19
 
20
20
  background: #{wp-colors.$white};
21
21
 
@@ -3,18 +3,18 @@
3
3
  */
4
4
 
5
5
  @use "~@wordpress/base-styles/colors" as wp-colors;
6
- @use "../../../colors/colors.module" as colors;
6
+ @use "../../../colors/colors.module" as np-colors;
7
7
 
8
8
  .newspack-wizard {
9
9
  // Color
10
- --wp-admin-theme-color: #{colors.$primary-600};
11
- --wp-admin-theme-color--rgb: #{colors.$primary-600--rgb};
12
- --wp-admin-theme-color-darker-10: #{colors.$primary-700};
13
- --wp-admin-theme-color-darker-10--rgb: #{colors.$primary-700--rgb};
14
- --wp-admin-theme-color-darker-20: #{colors.$primary-800};
15
- --wp-admin-theme-color-darker-20--rgb: #{colors.$primary-800--rgb};
16
- --wp-admin-theme-color-lighter-10: #{colors.$primary-000};
17
- --wp-admin-theme-color-lighter-10--rgb: #{colors.$primary-000--rgb};
10
+ --wp-admin-theme-color: #{np-colors.$primary-600};
11
+ --wp-admin-theme-color--rgb: #{np-colors.$primary-600--rgb};
12
+ --wp-admin-theme-color-darker-10: #{np-colors.$primary-700};
13
+ --wp-admin-theme-color-darker-10--rgb: #{np-colors.$primary-700--rgb};
14
+ --wp-admin-theme-color-darker-20: #{np-colors.$primary-800};
15
+ --wp-admin-theme-color-darker-20--rgb: #{np-colors.$primary-800--rgb};
16
+ --wp-admin-theme-color-lighter-10: #{np-colors.$primary-000};
17
+ --wp-admin-theme-color-lighter-10--rgb: #{np-colors.$primary-000--rgb};
18
18
 
19
19
  color: wp-colors.$gray-900;
20
20
 
@@ -7,16 +7,25 @@ import classnames from 'classnames';
7
7
  * WordPress dependencies.
8
8
  */
9
9
  // Notice is aliased: `Notice` below is Newspack's own, which this file also uses.
10
- import { DropdownMenu, MenuGroup, MenuItem, Notice as CoreNotice, SlotFillProvider, createSlotFill } from '@wordpress/components';
10
+ import {
11
+ DropdownMenu,
12
+ MenuGroup,
13
+ MenuItem,
14
+ Notice as CoreNotice,
15
+ SlotFillProvider,
16
+ createSlotFill,
17
+ // eslint-disable-next-line @wordpress/no-unsafe-wp-apis
18
+ __experimentalVStack as VStack,
19
+ } from '@wordpress/components';
11
20
  import { useDispatch, useSelect } from '@wordpress/data';
12
- import { cloneElement, createInterpolateElement, isValidElement, useRef, useEffect, useState, forwardRef } from '@wordpress/element';
21
+ import { cloneElement, createInterpolateElement, isValidElement, useEffect, useRef, useState, forwardRef } from '@wordpress/element';
13
22
  import { __ } from '@wordpress/i18n';
14
23
  import { category, chevronLeft, moreVertical } from '@wordpress/icons';
15
24
 
16
25
  /**
17
26
  * Internal dependencies
18
27
  */
19
- import { Footer, Notice, Button, TabbedNavigation, PluginInstaller, SectionHeader, HandoffMessage, Page } from '../';
28
+ import { Footer, Notice, Button, TabbedNavigation, PluginInstaller, SectionHeader, HandoffMessage, Page, Waiting } from '../';
20
29
  import { activeBreadcrumbs, appendSectionName } from './breadcrumbs-select';
21
30
  import Router from '../proxied-imports/router';
22
31
  import registerStore, { WIZARD_STORE_NAMESPACE } from './store';
@@ -164,8 +173,18 @@ const Wizard = (
164
173
  const headerData = useSelect( select => select( WIZARD_STORE_NAMESPACE ).getHeaderData() );
165
174
  const notices = useSelect( select => select( WIZARD_STORE_NAMESPACE ).getNotices() );
166
175
  const { invalidateResolution } = useDispatch( WIZARD_STORE_NAMESPACE );
167
- const { actions, backNav, badges, sectionDescription, sectionMenu, sectionName, sectionTitle, sectionPrimaryAction, sectionSecondaryAction } =
168
- headerData;
176
+ const {
177
+ actions,
178
+ backNav,
179
+ badges,
180
+ sectionDescription,
181
+ sectionMenu,
182
+ sectionName,
183
+ sectionSize,
184
+ sectionTitle,
185
+ sectionPrimaryAction,
186
+ sectionSecondaryAction,
187
+ } = headerData;
169
188
 
170
189
  const mainActions = actions?.filter( action => action.type === 'primary' || action.type === 'secondary' );
171
190
  const moreActions = actions?.filter( action => action.type === 'more' );
@@ -177,6 +196,11 @@ const Wizard = (
177
196
  let displayedSections = sections.filter( section => ! section.isHidden );
178
197
 
179
198
  const [ pluginRequirementsSatisfied, setPluginRequirementsSatisfied ] = useState( requiredPlugins.length === 0 );
199
+ // Whether the requirements check has reported back. Until it has, the check
200
+ // shows the same fetching treatment as the rest of the wizard rather than
201
+ // the installer's own spinner and the swapped header; the installer only
202
+ // surfaces once a plugin is actually found missing.
203
+ const [ pluginRequirementsKnown, setPluginRequirementsKnown ] = useState( requiredPlugins.length === 0 );
180
204
 
181
205
  // The data fetch above runs once per mount, while the required plugins are
182
206
  // still missing — endpoints that need them answer empty or error outright,
@@ -190,6 +214,7 @@ const Wizard = (
190
214
  // Leave the installer first: whatever happens to the refetch, the user
191
215
  // should not be stranded on a required-plugins screen for a plugin they
192
216
  // just installed.
217
+ setPluginRequirementsKnown( true );
193
218
  setPluginRequirementsSatisfied( complete );
194
219
  if ( ! complete ) {
195
220
  requirementsWereUnmet.current = true;
@@ -202,11 +227,27 @@ const Wizard = (
202
227
  };
203
228
 
204
229
  if ( ! pluginRequirementsSatisfied ) {
205
- headerText = requiredPlugins.length > 1 ? __( 'Required plugins', 'newspack-plugin' ) : __( 'Required plugin', 'newspack-plugin' );
230
+ if ( pluginRequirementsKnown ) {
231
+ headerText = requiredPlugins.length > 1 ? __( 'Required plugins', 'newspack-plugin' ) : __( 'Required plugin', 'newspack-plugin' );
232
+ }
206
233
  displayedSections = [
207
234
  {
208
235
  path: '/',
209
- render: () => <PluginInstaller plugins={ requiredPlugins } onStatus={ onPluginStatus } />,
236
+ render: () => (
237
+ <>
238
+ { ! pluginRequirementsKnown && (
239
+ <div className="newspack-wizard__loader">
240
+ <VStack alignment="center" spacing={ 2 }>
241
+ <Waiting noMargin />
242
+ <strong>{ __( 'Fetching…', 'newspack-plugin' ) }</strong>
243
+ </VStack>
244
+ </div>
245
+ ) }
246
+ <div hidden={ ! pluginRequirementsKnown }>
247
+ <PluginInstaller plugins={ requiredPlugins } onStatus={ onPluginStatus } />
248
+ </div>
249
+ </>
250
+ ),
210
251
  },
211
252
  ];
212
253
  }
@@ -277,6 +318,7 @@ const Wizard = (
277
318
  primaryAction={ sectionPrimaryAction || section.primaryAction }
278
319
  secondaryAction={ sectionSecondaryAction || section.secondaryAction }
279
320
  heading={ 2 }
321
+ size={ sectionSize || section.size }
280
322
  noMargin
281
323
  />
282
324
  ) }
@@ -160,4 +160,29 @@ const store = createReduxStore( WIZARD_STORE_NAMESPACE, {
160
160
  },
161
161
  } );
162
162
 
163
- export default () => register( store );
163
+ /**
164
+ * Register the wizard store, unless it already exists.
165
+ *
166
+ * This package is bundled separately into each consuming plugin, so more than one
167
+ * bundle can call this on the same page (e.g. the block editor loads assets from
168
+ * both newspack-blocks and newspack-manager). @wordpress/data keeps a single
169
+ * registry on `wp.data`, so the second call is a no-op that logs
170
+ * `Store "newspack/wizards" is already registered.` — guard it instead.
171
+ *
172
+ * The first bundle to register wins, and it is not necessarily the newest one:
173
+ * consumers rebuild on their own schedules, so an older copy of this package can
174
+ * get there first and leave newer selectors missing. That is worth knowing about
175
+ * while developing, so keep the breadcrumb outside production builds.
176
+ */
177
+ export default () => {
178
+ if ( select( WIZARD_STORE_NAMESPACE ) ) {
179
+ if ( 'production' !== process.env.NODE_ENV ) {
180
+ // eslint-disable-next-line no-console
181
+ console.warn(
182
+ `Wizard store: "${ WIZARD_STORE_NAMESPACE }" is already registered, so this copy of newspack-components was ignored. Two bundles of the package are on this page and the first one to load wins.`
183
+ );
184
+ }
185
+ return;
186
+ }
187
+ register( store );
188
+ };
@@ -1,72 +0,0 @@
1
- "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
- Object.defineProperty(exports, "__esModule", {
5
- value: true
6
- });
7
- exports["default"] = exports.AccordionPanel = void 0;
8
- var _components = require("@wordpress/components");
9
- var _element = require("@wordpress/element");
10
- var _classnames = _interopRequireDefault(require("classnames"));
11
- var _divider = _interopRequireDefault(require("../divider"));
12
- require("./style.scss");
13
- var _jsxRuntime = require("react/jsx-runtime");
14
- /**
15
- * WordPress dependencies
16
- */
17
- // eslint-disable-line @wordpress/no-unsafe-wp-apis
18
-
19
- /**
20
- * External dependencies
21
- */
22
-
23
- /**
24
- * Internal dependencies
25
- */
26
-
27
- var AccordionPanel = exports.AccordionPanel = function AccordionPanel(_ref) {
28
- var children = _ref.children,
29
- className = _ref.className,
30
- title = _ref.title,
31
- _ref$defaultOpen = _ref.defaultOpen,
32
- defaultOpen = _ref$defaultOpen === void 0 ? false : _ref$defaultOpen;
33
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.PanelBody, {
34
- className: className,
35
- title: title,
36
- initialOpen: defaultOpen,
37
- children: children
38
- });
39
- };
40
- var Accordion = function Accordion(_ref2) {
41
- var children = _ref2.children,
42
- className = _ref2.className,
43
- _ref2$hideSingleTitle = _ref2.hideSingleTitle,
44
- hideSingleTitle = _ref2$hideSingleTitle === void 0 ? false : _ref2$hideSingleTitle,
45
- _ref2$spacing = _ref2.spacing,
46
- spacing = _ref2$spacing === void 0 ? 6 : _ref2$spacing;
47
- var panels = _element.Children.toArray(children);
48
- // With nothing to collapse against, a lone panel can render open and untitled.
49
- if (hideSingleTitle && panels.length === 1) {
50
- return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
51
- className: (0, _classnames["default"])('newspack-accordion', className),
52
- children: (0, _element.cloneElement)(panels[0], {
53
- defaultOpen: true,
54
- title: undefined
55
- })
56
- });
57
- }
58
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalVStack, {
59
- className: (0, _classnames["default"])('newspack-accordion', className),
60
- spacing: spacing,
61
- children: panels.map(function (panel, index) {
62
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_element.Fragment, {
63
- children: [panel, index < panels.length - 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_divider["default"], {
64
- variant: "secondary",
65
- marginBottom: 0,
66
- marginTop: 0
67
- })]
68
- }, panel.key);
69
- })
70
- });
71
- };
72
- var _default = exports["default"] = Accordion;
@@ -1,80 +0,0 @@
1
- "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
- var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
5
- var _react = require("@testing-library/react");
6
- var _index = _interopRequireWildcard(require("./index"));
7
- var _jsxRuntime = require("react/jsx-runtime");
8
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
9
- 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
- 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) { (0, _defineProperty2["default"])(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
- * External dependencies
12
- */ /**
13
- * Internal dependencies
14
- */
15
- var renderPanels = function renderPanels(count) {
16
- var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
17
- return (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_index["default"], _objectSpread(_objectSpread({}, props), {}, {
18
- children: Array.from({
19
- length: count
20
- }, function (_, i) {
21
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index.AccordionPanel, {
22
- title: "Panel ".concat(i),
23
- children: "content"
24
- }, i);
25
- })
26
- })));
27
- };
28
- var dividers = function dividers(container) {
29
- return container.querySelectorAll('.newspack-divider');
30
- };
31
- describe('Accordion dividers', function () {
32
- it('renders no divider for a single panel', function () {
33
- var _renderPanels = renderPanels(1),
34
- container = _renderPanels.container;
35
- expect(container.querySelectorAll('.components-panel__body')).toHaveLength(1);
36
- expect(dividers(container)).toHaveLength(0);
37
- });
38
- it('renders a divider between panels but not after the last', function () {
39
- var _renderPanels2 = renderPanels(3),
40
- container = _renderPanels2.container;
41
- expect(container.querySelectorAll('.components-panel__body')).toHaveLength(3);
42
- expect(dividers(container)).toHaveLength(2);
43
- expect(container.querySelector('.newspack-accordion').lastElementChild).not.toHaveClass('newspack-divider');
44
- });
45
- it('renders secondary dividers', function () {
46
- var _renderPanels3 = renderPanels(2),
47
- container = _renderPanels3.container;
48
- expect(dividers(container)[0]).toHaveClass('newspack-divider--variant-secondary');
49
- });
50
- });
51
- describe('Accordion hideSingleTitle', function () {
52
- it('keeps the title on a lone panel by default', function () {
53
- renderPanels(1);
54
- expect(_react.screen.getByRole('button', {
55
- name: 'Panel 0'
56
- })).toBeInTheDocument();
57
- });
58
- it('drops the title and opens a lone panel when set', function () {
59
- var _renderPanels4 = renderPanels(1, {
60
- hideSingleTitle: true
61
- }),
62
- container = _renderPanels4.container;
63
- expect(_react.screen.queryByRole('button', {
64
- name: 'Panel 0'
65
- })).not.toBeInTheDocument();
66
- expect(container.querySelector('.components-panel__body')).toHaveClass('is-opened');
67
- expect(_react.screen.getByText('content')).toBeInTheDocument();
68
- });
69
- it('leaves titles alone when there is more than one panel', function () {
70
- renderPanels(2, {
71
- hideSingleTitle: true
72
- });
73
- expect(_react.screen.getByRole('button', {
74
- name: 'Panel 0'
75
- })).toBeInTheDocument();
76
- expect(_react.screen.getByRole('button', {
77
- name: 'Panel 1'
78
- })).toBeInTheDocument();
79
- });
80
- });
@@ -1,35 +0,0 @@
1
- @use "~@wordpress/base-styles/mixins" as wp-mixins;
2
- @use "~@wordpress/base-styles/variables" as wp-vars;
3
-
4
- // Sit flush with the surrounding column: core insets panels horizontally, which
5
- // would misalign them against the section they belong to.
6
- .newspack-accordion {
7
- .components-panel__body {
8
- border: 0;
9
-
10
- > .components-panel__body-title:hover {
11
- background: none;
12
- }
13
- }
14
-
15
- .components-panel__body.is-opened {
16
- padding: 0;
17
-
18
- > .components-panel__body-title {
19
- margin: 0 0 wp-vars.$grid-unit-30;
20
- }
21
- }
22
-
23
- .components-panel__body-toggle.components-button {
24
- @include wp-mixins.heading-large();
25
- padding: 0;
26
-
27
- .components-panel__arrow {
28
- right: 0;
29
- }
30
-
31
- &:focus:not(:focus-visible) {
32
- box-shadow: none;
33
- }
34
- }
35
- }
@@ -1,32 +0,0 @@
1
- "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
- Object.defineProperty(exports, "__esModule", {
5
- value: true
6
- });
7
- exports["default"] = void 0;
8
- require("./style.scss");
9
- var _classnames = _interopRequireDefault(require("classnames"));
10
- var _jsxRuntime = require("react/jsx-runtime");
11
- /**
12
- * Internal dependencies
13
- */
14
-
15
- /**
16
- * External dependencies
17
- */
18
-
19
- /**
20
- * Badge component
21
- */
22
- var Badge = function Badge(_ref) {
23
- var text = _ref.text,
24
- _ref$level = _ref.level,
25
- level = _ref$level === void 0 ? 'default' : _ref$level;
26
- var classes = (0, _classnames["default"])('newspack-badge', "is-".concat(level));
27
- return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
28
- className: classes,
29
- children: text
30
- });
31
- };
32
- var _default = exports["default"] = Badge;
@@ -1,36 +0,0 @@
1
- /**
2
- * Badge
3
- */
4
-
5
- @use "~@wordpress/base-styles/colors" as wp-colors;
6
- @use "../../../colors/colors.module" as colors;
7
-
8
- $badge-colors: (
9
- "info": colors.$primary-600,
10
- "warning": wp-colors.$alert-yellow,
11
- "error": wp-colors.$alert-red,
12
- "success": wp-colors.$alert-green,
13
- );
14
-
15
- .newspack-badge {
16
- background-color: color-mix(in srgb, wp-colors.$white 90%, var(--base-color));
17
- border-radius: 2px;
18
- color: color-mix(in srgb, wp-colors.$black 50%, var(--base-color));
19
- display: block;
20
- flex: 0 0 auto;
21
- font-size: 12px;
22
- line-height: 1.5;
23
- padding: 1px 4px;
24
-
25
- &:where(.is-default) {
26
- background-color: wp-colors.$gray-100;
27
- color: wp-colors.$gray-800;
28
- }
29
-
30
- // Generate color variants
31
- @each $type, $color in $badge-colors {
32
- &.is-#{$type} {
33
- --base-color: #{$color};
34
- }
35
- }
36
- }