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.
- package/CHANGELOG.md +20 -0
- package/DEVELOPMENT.md +42 -21
- package/dist/cjs/_mixins.scss +13 -0
- package/dist/cjs/_variables.scss +12 -0
- package/dist/cjs/action-card/index.js +18 -10
- package/dist/cjs/action-card/index.test.js +91 -0
- package/dist/cjs/action-card/style.scss +2 -40
- package/dist/cjs/button/index.js +8 -3
- package/dist/cjs/button/index.test.js +61 -5
- package/dist/cjs/card/core-card.js +0 -2
- package/dist/cjs/card/style-core.scss +7 -5
- package/dist/cjs/card-feature/index.js +75 -61
- package/dist/cjs/card-feature/index.test.js +396 -54
- package/dist/cjs/card-feature/style.scss +20 -31
- package/dist/cjs/card-form/index.js +5 -5
- package/dist/cjs/card-sortable-list/index.js +5 -3
- package/dist/cjs/card-sortable-list/index.test.js +50 -0
- package/dist/cjs/collapsible-group/context.js +19 -0
- package/dist/cjs/collapsible-group/index.js +24 -0
- package/dist/cjs/collapsible-group/index.test.js +215 -0
- package/dist/cjs/collapsible-group/item.js +61 -0
- package/dist/cjs/collapsible-group/root.js +62 -0
- package/dist/cjs/collapsible-group/style.scss +47 -0
- package/dist/cjs/collapsible-group/types.js +5 -0
- package/dist/cjs/empty-state/actions.js +45 -0
- package/dist/cjs/empty-state/context.js +41 -0
- package/dist/cjs/empty-state/header.js +66 -0
- package/dist/cjs/empty-state/index.js +31 -0
- package/dist/cjs/empty-state/index.test.js +303 -0
- package/dist/cjs/empty-state/root.js +56 -0
- package/dist/cjs/empty-state/style.scss +51 -0
- package/dist/cjs/empty-state/types.js +5 -0
- package/dist/cjs/index.js +34 -20
- package/dist/cjs/info-button/index.js +59 -43
- package/dist/cjs/info-button/index.test.js +199 -0
- package/dist/cjs/info-button/style.scss +41 -9
- package/dist/cjs/modal/style.scss +12 -12
- package/dist/cjs/newspack-icon/style.scss +4 -4
- package/dist/cjs/notice/style.scss +3 -3
- package/dist/cjs/page/style.scss +16 -16
- package/dist/cjs/plugin-installer/index.js +5 -9
- package/dist/cjs/plugin-installer/style.scss +3 -14
- package/dist/cjs/section-header/index.js +31 -18
- package/dist/cjs/section-header/index.test.js +40 -0
- package/dist/cjs/section-header/style.scss +22 -6
- package/dist/cjs/settings/DateRangeSetting.js +309 -0
- package/dist/cjs/settings/SettingsSection.js +19 -5
- package/dist/cjs/settings/SettingsSection.test.js +49 -0
- package/dist/cjs/settings/index.js +3 -1
- package/dist/cjs/settings/style.scss +40 -7
- package/dist/cjs/stat-card/body.js +41 -0
- package/dist/cjs/stat-card/constants.js +11 -0
- package/dist/cjs/stat-card/context.js +54 -0
- package/dist/cjs/stat-card/delta.js +91 -0
- package/dist/cjs/stat-card/footer.js +72 -0
- package/dist/cjs/stat-card/index.js +47 -0
- package/dist/cjs/stat-card/index.test.js +938 -0
- package/dist/cjs/stat-card/label.js +66 -0
- package/dist/cjs/stat-card/root.js +69 -0
- package/dist/cjs/stat-card/secondary.js +38 -0
- package/dist/cjs/stat-card/style.scss +89 -0
- package/dist/cjs/stat-card/types.js +5 -0
- package/dist/cjs/stat-card/value.js +78 -0
- package/dist/cjs/status-indicator/index.js +66 -0
- package/dist/cjs/status-indicator/index.test.js +101 -0
- package/dist/cjs/status-indicator/statuses.js +39 -0
- package/dist/cjs/status-indicator/style.scss +9 -0
- package/dist/cjs/status-indicator/types.js +5 -0
- package/dist/cjs/style.scss +9 -9
- package/dist/cjs/tabbed-navigation/style.scss +6 -4
- package/dist/cjs/types.js +5 -0
- package/dist/cjs/web-preview/style.scss +11 -11
- package/dist/cjs/with-wizard/style.scss +10 -10
- package/dist/cjs/with-wizard-screen/style.scss +9 -9
- package/dist/cjs/wizard/index.js +33 -4
- package/dist/cjs/wizard/store/index.js +23 -1
- package/dist/esm/_mixins.scss +13 -0
- package/dist/esm/_variables.scss +12 -0
- package/dist/esm/action-card/index.js +18 -10
- package/dist/esm/action-card/index.test.js +89 -0
- package/dist/esm/action-card/style.scss +2 -40
- package/dist/esm/button/index.js +9 -4
- package/dist/esm/button/index.test.js +63 -5
- package/dist/esm/card/core-card.js +0 -2
- package/dist/esm/card/style-core.scss +7 -5
- package/dist/esm/card-feature/index.js +78 -62
- package/dist/esm/card-feature/index.test.js +397 -55
- package/dist/esm/card-feature/style.scss +20 -31
- package/dist/esm/card-form/index.js +5 -5
- package/dist/esm/card-sortable-list/index.js +6 -4
- package/dist/esm/card-sortable-list/index.test.js +46 -0
- package/dist/esm/collapsible-group/context.js +13 -0
- package/dist/esm/collapsible-group/index.js +17 -0
- package/dist/esm/collapsible-group/index.test.js +215 -0
- package/dist/esm/collapsible-group/item.js +53 -0
- package/dist/esm/collapsible-group/root.js +54 -0
- package/dist/esm/collapsible-group/style.scss +47 -0
- package/dist/esm/collapsible-group/types.js +1 -0
- package/dist/esm/empty-state/actions.js +37 -0
- package/dist/esm/empty-state/context.js +35 -0
- package/dist/esm/empty-state/header.js +58 -0
- package/dist/esm/empty-state/index.js +23 -0
- package/dist/esm/empty-state/index.test.js +299 -0
- package/dist/esm/empty-state/root.js +56 -0
- package/dist/esm/empty-state/style.scss +51 -0
- package/dist/esm/empty-state/types.js +1 -0
- package/dist/esm/index.js +4 -2
- package/dist/esm/info-button/index.js +54 -43
- package/dist/esm/info-button/index.test.js +195 -0
- package/dist/esm/info-button/style.scss +41 -9
- package/dist/esm/modal/style.scss +12 -12
- package/dist/esm/newspack-icon/style.scss +4 -4
- package/dist/esm/notice/style.scss +3 -3
- package/dist/esm/page/style.scss +16 -16
- package/dist/esm/plugin-installer/index.js +5 -9
- package/dist/esm/plugin-installer/style.scss +3 -14
- package/dist/esm/section-header/index.js +27 -14
- package/dist/esm/section-header/index.test.js +36 -0
- package/dist/esm/section-header/style.scss +22 -6
- package/dist/esm/settings/DateRangeSetting.js +304 -0
- package/dist/esm/settings/SettingsSection.js +16 -3
- package/dist/esm/settings/SettingsSection.test.js +45 -0
- package/dist/esm/settings/index.js +3 -1
- package/dist/esm/settings/style.scss +40 -7
- package/dist/esm/stat-card/body.js +36 -0
- package/dist/esm/stat-card/constants.js +5 -0
- package/dist/esm/stat-card/context.js +48 -0
- package/dist/esm/stat-card/delta.js +86 -0
- package/dist/esm/stat-card/footer.js +67 -0
- package/dist/esm/stat-card/index.js +33 -0
- package/dist/esm/stat-card/index.test.js +939 -0
- package/dist/esm/stat-card/label.js +61 -0
- package/dist/esm/stat-card/root.js +64 -0
- package/dist/esm/stat-card/secondary.js +33 -0
- package/dist/esm/stat-card/style.scss +89 -0
- package/dist/esm/stat-card/types.js +1 -0
- package/dist/esm/stat-card/value.js +73 -0
- package/dist/esm/status-indicator/index.js +52 -0
- package/dist/esm/status-indicator/index.test.js +96 -0
- package/dist/esm/status-indicator/statuses.js +33 -0
- package/dist/esm/status-indicator/style.scss +9 -0
- package/dist/esm/status-indicator/types.js +1 -0
- package/dist/esm/style.scss +9 -9
- package/dist/esm/tabbed-navigation/style.scss +6 -4
- package/dist/esm/types.js +1 -0
- package/dist/esm/web-preview/style.scss +11 -11
- package/dist/esm/with-wizard/style.scss +10 -10
- package/dist/esm/with-wizard-screen/style.scss +9 -9
- package/dist/esm/wizard/index.js +38 -7
- package/dist/esm/wizard/store/index.js +23 -1
- package/package.json +1 -1
- package/src/_mixins.scss +13 -0
- package/src/_variables.scss +12 -0
- package/src/action-card/action-card.d.ts +3 -2
- package/src/action-card/index.js +12 -12
- package/src/action-card/index.test.js +56 -0
- package/src/action-card/style.scss +2 -40
- package/src/button/index.test.js +52 -5
- package/src/button/index.tsx +9 -4
- package/src/card/core-card.js +0 -2
- package/src/card/style-core.scss +7 -5
- package/src/card-feature/README.md +68 -27
- package/src/card-feature/index.test.js +242 -27
- package/src/card-feature/index.tsx +77 -67
- package/src/card-feature/style.scss +20 -31
- package/src/card-form/README.md +10 -10
- package/src/card-form/index.tsx +4 -8
- package/src/card-sortable-list/README.md +4 -5
- package/src/card-sortable-list/index.test.js +29 -0
- package/src/card-sortable-list/index.tsx +7 -4
- package/src/collapsible-group/README.md +50 -0
- package/src/collapsible-group/context.ts +13 -0
- package/src/collapsible-group/index.test.js +168 -0
- package/src/collapsible-group/index.tsx +17 -0
- package/src/collapsible-group/item.tsx +42 -0
- package/src/collapsible-group/root.tsx +42 -0
- package/src/collapsible-group/style.scss +47 -0
- package/src/collapsible-group/types.ts +22 -0
- package/src/drawer/README.md +2 -2
- package/src/empty-state/README.md +165 -0
- package/src/empty-state/actions.tsx +37 -0
- package/src/empty-state/context.ts +40 -0
- package/src/empty-state/header.tsx +48 -0
- package/src/empty-state/index.test.js +247 -0
- package/src/empty-state/index.tsx +22 -0
- package/src/empty-state/root.tsx +39 -0
- package/src/empty-state/style.scss +51 -0
- package/src/empty-state/types.ts +33 -0
- package/src/index.js +4 -2
- package/src/info-button/README.md +115 -0
- package/src/info-button/index.test.js +163 -0
- package/src/info-button/index.tsx +64 -0
- package/src/info-button/style.scss +41 -9
- package/src/modal/style.scss +12 -12
- package/src/newspack-icon/style.scss +4 -4
- package/src/notice/style.scss +3 -3
- package/src/page/style.scss +16 -16
- package/src/plugin-installer/index.js +3 -9
- package/src/plugin-installer/style.scss +3 -14
- package/src/section-header/index.js +27 -14
- package/src/section-header/index.test.js +28 -0
- package/src/section-header/style.scss +22 -6
- package/src/settings/DateRangeSetting.js +266 -0
- package/src/settings/SettingsSection.js +24 -4
- package/src/settings/SettingsSection.test.js +45 -0
- package/src/settings/index.js +2 -0
- package/src/settings/style.scss +40 -7
- package/src/stat-card/README.md +434 -0
- package/src/stat-card/body.tsx +28 -0
- package/src/stat-card/constants.ts +5 -0
- package/src/stat-card/context.ts +53 -0
- package/src/stat-card/delta.tsx +88 -0
- package/src/stat-card/footer.tsx +68 -0
- package/src/stat-card/index.test.js +818 -0
- package/src/stat-card/index.tsx +48 -0
- package/src/stat-card/label.tsx +61 -0
- package/src/stat-card/root.tsx +40 -0
- package/src/stat-card/secondary.tsx +27 -0
- package/src/stat-card/style.scss +89 -0
- package/src/stat-card/types.ts +84 -0
- package/src/stat-card/value.tsx +72 -0
- package/src/status-indicator/README.md +123 -0
- package/src/status-indicator/index.test.js +70 -0
- package/src/status-indicator/index.tsx +39 -0
- package/src/status-indicator/statuses.ts +35 -0
- package/src/status-indicator/style.scss +9 -0
- package/src/status-indicator/types.ts +28 -0
- package/src/style.scss +9 -9
- package/src/tabbed-navigation/style.scss +6 -4
- package/src/types.ts +25 -0
- package/src/web-preview/style.scss +11 -11
- package/src/with-wizard/style.scss +10 -10
- package/src/with-wizard-screen/style.scss +9 -9
- package/src/wizard/index.js +49 -7
- package/src/wizard/store/index.js +26 -1
- package/dist/cjs/accordion/index.js +0 -72
- package/dist/cjs/accordion/index.test.js +0 -80
- package/dist/cjs/accordion/style.scss +0 -35
- package/dist/cjs/badge/index.js +0 -32
- package/dist/cjs/badge/style.scss +0 -36
- package/dist/esm/accordion/index.js +0 -63
- package/dist/esm/accordion/index.test.js +0 -79
- package/dist/esm/accordion/style.scss +0 -35
- package/dist/esm/badge/index.js +0 -24
- package/dist/esm/badge/style.scss +0 -36
- package/src/accordion/index.js +0 -46
- package/src/accordion/index.test.js +0 -62
- package/src/accordion/style.scss +0 -35
- package/src/badge/index.tsx +0 -26
- package/src/badge/style.scss +0 -36
- package/src/info-button/index.js +0 -38
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
# newspack-components [4.8.0](https://github.com/Automattic/newspack-workspace/compare/newspack-components@4.7.0...newspack-components@4.8.0) (2026-09-14)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **editor:** stop console warnings from Button, cards and Collections ([#907](https://github.com/Automattic/newspack-workspace/issues/907)) ([70e41cd](https://github.com/Automattic/newspack-workspace/commit/70e41cd116a295a391af966f924c269c567967a2))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **audience:** date range segmentation for ESP date fields ([#767](https://github.com/Automattic/newspack-workspace/issues/767)) ([21c4732](https://github.com/Automattic/newspack-workspace/commit/21c4732a2b8cbadea1e7d6710ca22d22b3282cef))
|
|
12
|
+
* **components:** Accordion becomes CollapsibleGroup (DSGNEWS-215) ([e6639f2](https://github.com/Automattic/newspack-workspace/commit/e6639f2214d591bba3bc38fb7f042719ca58d3ea))
|
|
13
|
+
* **components:** adopt design system badges (DSGNEWS-215) ([fc4c8f7](https://github.com/Automattic/newspack-workspace/commit/fc4c8f73ccba6ec4075e09578a43938a40eda60f))
|
|
14
|
+
* **components:** rebuild the info button on Popover (DSGNEWS-215) ([#887](https://github.com/Automattic/newspack-workspace/issues/887)) ([31f996d](https://github.com/Automattic/newspack-workspace/commit/31f996d25051a5f861e94cc03b42bb7d9afc10da))
|
|
15
|
+
* **components:** shared EmptyState component (DSGNEWS-211) ([#854](https://github.com/Automattic/newspack-workspace/issues/854)) ([6c31f8c](https://github.com/Automattic/newspack-workspace/commit/6c31f8cac683570e36f3768b0be6061b55d7c946))
|
|
16
|
+
* **components:** shared StatCard component (DSGNEWS-212) ([#864](https://github.com/Automattic/newspack-workspace/issues/864)) ([ac434c2](https://github.com/Automattic/newspack-workspace/commit/ac434c2bc6777f99b65e18fa70e10100ed077ca2))
|
|
17
|
+
* **components:** use an icon and label for DataViews Status columns (DSGNEWS-222) ([aa1d404](https://github.com/Automattic/newspack-workspace/commit/aa1d40422ccddad0d34de67ed444f73f6d14ea49))
|
|
18
|
+
* **content-gate:** share one metering allowance across gates (NPPD-2191, [#919](https://github.com/Automattic/newspack-workspace/issues/919)) ([cb79f9a](https://github.com/Automattic/newspack-workspace/commit/cb79f9a79990975d48acde04b57e2746fd694bdd))
|
|
19
|
+
* **subscriber-discounts:** subscriber discounts on WooCommerce products (NPPD-1794, [#760](https://github.com/Automattic/newspack-workspace/issues/760)) ([3ef9b8a](https://github.com/Automattic/newspack-workspace/commit/3ef9b8ac6f318437777027445ef835d30ec6c8c1)), closes [#8217](https://github.com/Automattic/newspack-workspace/issues/8217)
|
|
20
|
+
|
|
1
21
|
# newspack-components [4.7.0](https://github.com/Automattic/newspack-workspace/compare/newspack-components@4.6.3...newspack-components@4.7.0) (2026-08-31)
|
|
2
22
|
|
|
3
23
|
|
package/DEVELOPMENT.md
CHANGED
|
@@ -74,39 +74,44 @@ When building a screen, use the **spacing scale** (8px unit: 16, 24, 32, 48, 64)
|
|
|
74
74
|
|
|
75
75
|
### Layout Components
|
|
76
76
|
|
|
77
|
+
- **`BoxContrast`** – High-contrast content box for emphasis.
|
|
77
78
|
- **`Card`** – Container for a logical block of content; use for grouping related settings. Default vertical margin is 32px so cards stack with consistent rhythm. Use `noBorder` when cards sit inside another card (e.g. ActionCard children).
|
|
78
|
-
- **`Grid`** – Use for laying out several items in columns (e.g. multiple controls or cards). Default gap is 32px; use `columns` and `gutter` modifiers (8, 16, 24, 32) when you need tighter or looser spacing. For a single row or a simple vertical stack, prefer **VStack** (or HStack) in new code; Grid is still used that way in many places and is fine to leave as-is until we refactor.
|
|
79
79
|
- **`Divider`** – Use between logical sections (e.g. between ActionCards) to separate content without another card. Margins are 32px (64px at larger breakpoints) so spacing stays consistent with the rest of the layout.
|
|
80
|
+
- **`EmptyState`** – Use when a list has nothing in it yet, or an onboarding view stands in for a feature that is not set up. Compound: `EmptyState.Root` wraps `EmptyState.Header` and `EmptyState.Actions`. Render it only when the *unfiltered* collection is empty, so a search matching nothing keeps the DataViews "no results" treatment. See [src/empty-state/README.md](src/empty-state/README.md).
|
|
81
|
+
- **`Grid`** – Use for laying out several items in columns (e.g. multiple controls or cards). Default gap is 32px; use `columns` and `gutter` modifiers (8, 16, 24, 32) when you need tighter or looser spacing. For a single row or a simple vertical stack, prefer **VStack** (or HStack) in new code; Grid is still used that way in many places and is fine to leave as-is until we refactor.
|
|
80
82
|
- **`SectionHeader`** – Use to start a new section; pair with a short description so the section’s goal is clear. Top margin (64px) and bottom (32px) create clear separation from previous content and the section body.
|
|
81
|
-
- **`
|
|
83
|
+
- **`StatCard`** – Use for a single headline figure with a label above it and a description below. Compound: `StatCard.Root` wraps `Label`, `Body` (holding `Value` and an optional `Secondary`) and `Footer`, with `Delta` riding in the `Value`'s `suffix` for a change beside the figure. Format the figure yourself and pass a string; a `null`, `undefined` or blank `value` gets the shared null glyph rather than a misleading zero. The figure is sized by a container query, so give the cards a definite width (a Grid track, a `flex: 1` item) and equal widths across a row to keep one type scale. See [src/stat-card/README.md](src/stat-card/README.md).
|
|
82
84
|
|
|
83
85
|
### Form Components
|
|
84
86
|
|
|
85
|
-
- **`Button`** - Enhanced button component (wraps WordPress Button with routing support)
|
|
86
|
-
- **`TextControl`** - Text input with Newspack styling and required field support
|
|
87
|
-
- **`RadioControl`** - Radio button group control
|
|
88
|
-
- **`ColorPicker`** - Color selection component
|
|
89
|
-
- **`ImageUpload`** - Image upload and selection component
|
|
90
|
-
- **`FormTokenField`** - Token input field for tags/categories; prefer the Newspack component over the core `FormTokenField` because it also supports a `description` prop for help text like other controls.
|
|
91
87
|
- **`AutocompleteTokenField`** - Autocomplete token field (can be used in block editor)
|
|
92
|
-
- **`AutocompleteWithSuggestions`** - Autocomplete with custom suggestions
|
|
93
88
|
- **`AutocompleteWithLatestPosts`** - Autocomplete with latest posts
|
|
89
|
+
- **`AutocompleteWithSuggestions`** - Autocomplete with custom suggestions
|
|
90
|
+
- **`Button`** - Enhanced button component (wraps WordPress Button with routing support)
|
|
94
91
|
- **`CategoryAutocomplete`** - Category-specific autocomplete
|
|
92
|
+
- **`ColorPicker`** - Color selection component
|
|
95
93
|
- **`CustomSelectControl`** - Custom select dropdown component
|
|
94
|
+
- **`FormTokenField`** - Token input field for tags/categories; prefer the Newspack component over the core `FormTokenField` because it also supports a `description` prop for help text like other controls.
|
|
95
|
+
- **`ImageUpload`** - Image upload and selection component
|
|
96
|
+
- **`RadioControl`** - Radio button group control
|
|
97
|
+
- **`TextControl`** - Text input with Newspack styling and required field support
|
|
96
98
|
|
|
97
99
|
### Content Components
|
|
98
100
|
|
|
99
101
|
- **`ActionCard`** – Use when one concept (e.g. a feature or setting) can be toggled on/off and may have extra content below. Internal padding (24px default; 16px/8px for isMedium/isSmall) and 24px between regions keep hierarchy clear; expandable content uses 24px top padding and 24px between siblings.
|
|
102
|
+
- **`CollapsibleGroup`** / **`CollapsibleGroup.Item`** – A stack of independently collapsible items, separated by dividers and flush with the surrounding column. Not a W3C accordion: the items do not coordinate.
|
|
100
103
|
- **`Notice`** – Use for outcome feedback (success/error/warning) or short contextual messages. Vertical margin is 32px so notices don’t collide with cards; keep one primary message per area when possible.
|
|
101
|
-
- **`Waiting`** – Loading state indicator.
|
|
102
104
|
- **`ProgressBar`** – Progress indicator.
|
|
103
|
-
- **`Accordion`** / **`AccordionPanel`** – Container for one or more collapsible panels.
|
|
104
105
|
- **`StepsList`** / **`StepsListItem`** – Step-by-step list components.
|
|
105
106
|
- **`StyleCard`** – Style preview card.
|
|
107
|
+
- **`Waiting`** – Loading state indicator.
|
|
106
108
|
|
|
107
109
|
### Wizard Components
|
|
108
110
|
|
|
109
|
-
- **`
|
|
111
|
+
- **`Footer`** - Wizard footer component
|
|
112
|
+
- **`Handoff`** - Handoff message component for external integrations
|
|
113
|
+
- **`HandoffMessage`** - Handoff message display component
|
|
114
|
+
- **`TabbedNavigation`** - Tab navigation component
|
|
110
115
|
- **`withWizard`** - Higher-order component for wizard screens (legacy pattern, class-based)
|
|
111
116
|
- Provides plugin management, error handling, loading states
|
|
112
117
|
- Used in older wizards like Setup Wizard
|
|
@@ -116,25 +121,22 @@ When building a screen, use the **spacing scale** (8px unit: 16, 24, 32, 48, 64)
|
|
|
116
121
|
- Provides header, tabbed navigation, button actions, handoff messages
|
|
117
122
|
- Used in newer wizards like Audience Management
|
|
118
123
|
- Passes props: `renderPrimaryButton`, plus all original component props
|
|
119
|
-
- **`
|
|
120
|
-
- **`Footer`** - Wizard footer component
|
|
121
|
-
- **`Handoff`** - Handoff message component for external integrations
|
|
122
|
-
- **`HandoffMessage`** - Handoff message display component
|
|
124
|
+
- **`Wizard`** - Main wizard container with tabbed navigation and data fetching
|
|
123
125
|
|
|
124
126
|
### Plugin Management Components
|
|
125
127
|
|
|
126
128
|
- **`PluginInstaller`** - Plugin installation and activation component
|
|
127
|
-
- **`PluginToggle`** - Plugin enable/disable toggle
|
|
128
129
|
- **`PluginSettings`** - Plugin settings configuration component
|
|
130
|
+
- **`PluginToggle`** - Plugin enable/disable toggle
|
|
129
131
|
|
|
130
132
|
### Utility Components
|
|
131
133
|
|
|
134
|
+
- **`GlobalNotices`** - Global notice system component
|
|
135
|
+
- **`InfoButton`** - Reveals supplementary context from a `description` prop. Anything a reader needs in order to use a control belongs in visible help text instead
|
|
132
136
|
- **`Modal`** - Modal dialog component
|
|
137
|
+
- **`NewspackIcon`** - Newspack icon wrapper component
|
|
133
138
|
- **`Popover`** - Popover component
|
|
134
139
|
- **`WebPreview`** - Web preview iframe component
|
|
135
|
-
- **`NewspackIcon`** - Newspack icon wrapper component
|
|
136
|
-
- **`InfoButton`** - Info button with tooltip
|
|
137
|
-
- **`GlobalNotices`** - Global notice system component
|
|
138
140
|
|
|
139
141
|
### Settings Components
|
|
140
142
|
|
|
@@ -144,9 +146,9 @@ When building a screen, use the **spacing scale** (8px unit: 16, 24, 32, 48, 64)
|
|
|
144
146
|
### Utilities & Hooks
|
|
145
147
|
|
|
146
148
|
- **`hooks`** - Custom React hooks (e.g., `useObjectState`, `usePrompt`, `useOnClickOutside`)
|
|
147
|
-
- **`utils`** - Utility functions (e.g., `confirmAction`, color utilities)
|
|
148
149
|
- **`Router`** - Proxied React Router import (use instead of direct `react-router-dom` import)
|
|
149
150
|
- Note: This package currently uses [React Router v5](https://v5.reactrouter.com/). Please refer to v5 documentation for API details.
|
|
151
|
+
- **`utils`** - Utility functions (e.g., `confirmAction`, color utilities)
|
|
150
152
|
|
|
151
153
|
## Import Patterns
|
|
152
154
|
|
|
@@ -205,6 +207,24 @@ import { Button, Card, Notice } from '../../../../../packages/components/src';
|
|
|
205
207
|
import * as Components from '../../../../../packages/components/src';
|
|
206
208
|
```
|
|
207
209
|
|
|
210
|
+
**Reach past the barrel from inside the package.** `src/index.js` imports
|
|
211
|
+
`src/style.scss`, which redefines `--wp-admin-theme-color` and its variants on
|
|
212
|
+
`:root`. Any module that pulls in the barrel carries those global overrides into
|
|
213
|
+
whatever bundle it lands in, which is wrong for an editor or front-end bundle.
|
|
214
|
+
Import each component from its own directory instead:
|
|
215
|
+
|
|
216
|
+
```jsx
|
|
217
|
+
// ✅ CORRECT – within packages/components
|
|
218
|
+
import Grid from '../grid';
|
|
219
|
+
import InfoButton from '../info-button';
|
|
220
|
+
|
|
221
|
+
// ❌ WRONG – drags the package's :root overrides along
|
|
222
|
+
import { Grid, InfoButton } from '../';
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Most of the package still reaches the barrel. Treat this as the bar for new and
|
|
226
|
+
edited modules rather than a description of how things stand.
|
|
227
|
+
|
|
208
228
|
### Router Import Pattern
|
|
209
229
|
|
|
210
230
|
**Always use the proxied router** - Never import `react-router-dom` directly in source code:
|
|
@@ -591,6 +611,7 @@ Newspack components use SCSS with BEM-ish naming conventions and a consistent sp
|
|
|
591
611
|
- **Elements**: Use `__` for elements that are part of a larger block-level component (e.g. `.newspack-card__header-content`)
|
|
592
612
|
- **WordPress colors:** Use WordPress design system colors (see [Colors Development Guide](../colors/DEVELOPMENT.md))
|
|
593
613
|
- **Custom styles:** Component-specific styles live in `packages/components/src/{component}/style.scss`
|
|
614
|
+
- **Shared values:** Reach for a `@wordpress/base-styles` variable first. Where the scale has no counterpart, the value goes in `packages/components/src/_variables.scss` and is used by name, rather than written as a literal in one component's stylesheet
|
|
594
615
|
|
|
595
616
|
### Spacing scale (design system)
|
|
596
617
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@use "../../colors/colors.module" as colors;
|
|
2
|
+
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
3
|
+
@use "~@wordpress/base-styles/variables" as wp-vars;
|
|
4
|
+
|
|
5
|
+
@mixin text-muted {
|
|
6
|
+
/* stylelint-disable-next-line plugin-wpds/no-unknown-ds-tokens -- the plugin's token list lags the prebuilt design-tokens.css names. */
|
|
7
|
+
color: var( --wpds-color-foreground-content-neutral-weak, #{wp-colors.$gray-700} );
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@mixin wpds-focus-ring {
|
|
11
|
+
/* stylelint-disable-next-line plugin-wpds/no-unknown-ds-tokens -- the plugin's token list lags the prebuilt design-tokens.css names. */
|
|
12
|
+
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, #{colors.$primary-600} ) );
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SCSS Variables.
|
|
3
|
+
*
|
|
4
|
+
* The steps this package needs above the @wordpress/base-styles scale. Please
|
|
5
|
+
* reach for a base-styles variable first, and only add here when there is no
|
|
6
|
+
* counterpart and you're pretty sure the value will be reused in many places.
|
|
7
|
+
* It's purely for UI. Don't add component-specific values, which belong in that
|
|
8
|
+
* component's own stylesheet.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
$font-size-3x-large: 48px;
|
|
12
|
+
$font-line-height-3x-large: 1.125;
|
|
@@ -11,6 +11,7 @@ var _components = require("@wordpress/components");
|
|
|
11
11
|
var _element = require("@wordpress/element");
|
|
12
12
|
var _i18n = require("@wordpress/i18n");
|
|
13
13
|
var _icons = require("@wordpress/icons");
|
|
14
|
+
var _ui = require("@wordpress/ui");
|
|
14
15
|
var _ = require("../");
|
|
15
16
|
var _actionCardD = require("./action-card.d.ts");
|
|
16
17
|
require("./style.scss");
|
|
@@ -31,8 +32,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
31
32
|
* @return {JSX.Element} ActionCard component.
|
|
32
33
|
*/
|
|
33
34
|
var ActionCard = function ActionCard(_ref) {
|
|
34
|
-
var
|
|
35
|
-
badgeLevel = _ref.badgeLevel,
|
|
35
|
+
var badges = _ref.badges,
|
|
36
36
|
className = _ref.className,
|
|
37
37
|
checkbox = _ref.checkbox,
|
|
38
38
|
children = _ref.children,
|
|
@@ -85,6 +85,13 @@ var ActionCard = function ActionCard(_ref) {
|
|
|
85
85
|
dragIndex = _ref.dragIndex,
|
|
86
86
|
dragWrapperRef = _ref.dragWrapperRef,
|
|
87
87
|
onDragCallback = _ref.onDragCallback;
|
|
88
|
+
// A badge with no label paints an empty pill, since the library Badge styles its
|
|
89
|
+
// wrapper rather than its text. Callers derive labels from data that can be absent
|
|
90
|
+
// (a gateway with no connection status, an unmapped placement), so drop those here
|
|
91
|
+
// rather than asking every caller to guard its own array.
|
|
92
|
+
var visibleBadges = (badges || []).filter(function (badge) {
|
|
93
|
+
return badge === null || badge === void 0 ? void 0 : badge.label;
|
|
94
|
+
});
|
|
88
95
|
var _useState = (0, _element.useState)(Boolean(isExpanded)),
|
|
89
96
|
_useState2 = (0, _slicedToArray2["default"])(_useState, 2),
|
|
90
97
|
expanded = _useState2[0],
|
|
@@ -132,7 +139,6 @@ var ActionCard = function ActionCard(_ref) {
|
|
|
132
139
|
var togglePositionClass = togglePosition === 'trailing' ? 'is-toggle-trailing' : 'is-toggle-leading';
|
|
133
140
|
var hasInternalLink = href && href.indexOf('http') !== 0;
|
|
134
141
|
var isDisplayingSecondaryAction = secondaryActionText && onSecondaryActionClick;
|
|
135
|
-
var badges = !Array.isArray(badge) && badge ? [badge] : badge;
|
|
136
142
|
var HeadingTag = "h".concat(heading);
|
|
137
143
|
var cardContent = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
138
144
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
@@ -179,10 +185,12 @@ var ActionCard = function ActionCard(_ref) {
|
|
|
179
185
|
},
|
|
180
186
|
children: title
|
|
181
187
|
}), !titleLink && !expandable && title]
|
|
182
|
-
})),
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
188
|
+
})), visibleBadges.map(function (_ref2, i) {
|
|
189
|
+
var label = _ref2.label,
|
|
190
|
+
intent = _ref2.intent;
|
|
191
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ui.Badge, {
|
|
192
|
+
intent: intent !== null && intent !== void 0 ? intent : 'none',
|
|
193
|
+
children: label
|
|
186
194
|
}, "badge-".concat(i));
|
|
187
195
|
})]
|
|
188
196
|
}), description && /*#__PURE__*/(0, _jsxRuntime.jsxs)("p", {
|
|
@@ -315,9 +323,9 @@ var ActionCard = function ActionCard(_ref) {
|
|
|
315
323
|
onDragStart: handleDragStart,
|
|
316
324
|
onDragEnd: handleDragEnd,
|
|
317
325
|
onDragOver: handleDragOver,
|
|
318
|
-
children: function children(
|
|
319
|
-
var onDraggableStart =
|
|
320
|
-
onDraggableEnd =
|
|
326
|
+
children: function children(_ref3) {
|
|
327
|
+
var onDraggableStart = _ref3.onDraggableStart,
|
|
328
|
+
onDraggableEnd = _ref3.onDraggableEnd;
|
|
321
329
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_.Card, {
|
|
322
330
|
className: classes,
|
|
323
331
|
onClick: simple && onClick,
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _react = require("@testing-library/react");
|
|
5
|
+
var _index = _interopRequireDefault(require("./index"));
|
|
6
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
7
|
+
/**
|
|
8
|
+
* External dependencies.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Internal dependencies.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The library Badge styles its wrapper rather than its text, so a badge with no label
|
|
17
|
+
* paints a bare coloured pill. Callers build the `badges` array from data that can be
|
|
18
|
+
* absent — a payment gateway reports no connection status until it is enabled, a prompt
|
|
19
|
+
* can sit on a placement with no entry in the placement map — and an array literal is
|
|
20
|
+
* always non-empty, so the component has to drop those itself.
|
|
21
|
+
*/describe('ActionCard badges', function () {
|
|
22
|
+
var badgeText = function badgeText() {
|
|
23
|
+
return _react.screen.queryAllByText(function (_, node) {
|
|
24
|
+
return /__badge/.test((node === null || node === void 0 ? void 0 : node.className) || '');
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
it('renders a badge that has a label', function () {
|
|
28
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_index["default"], {
|
|
29
|
+
title: "Stripe",
|
|
30
|
+
badges: [{
|
|
31
|
+
label: 'Connected',
|
|
32
|
+
intent: 'stable'
|
|
33
|
+
}]
|
|
34
|
+
}));
|
|
35
|
+
expect(_react.screen.getByText('Connected')).toBeInTheDocument();
|
|
36
|
+
});
|
|
37
|
+
it('renders no badge when the label is null', function () {
|
|
38
|
+
var _render = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_index["default"], {
|
|
39
|
+
title: "Stripe",
|
|
40
|
+
badges: [{
|
|
41
|
+
label: null,
|
|
42
|
+
intent: 'informational'
|
|
43
|
+
}]
|
|
44
|
+
})),
|
|
45
|
+
container = _render.container;
|
|
46
|
+
expect(container.querySelectorAll('[class*="__badge"]')).toHaveLength(0);
|
|
47
|
+
});
|
|
48
|
+
it('renders no badge when the label is undefined or empty', function () {
|
|
49
|
+
var _render2 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_index["default"], {
|
|
50
|
+
title: "Stripe",
|
|
51
|
+
badges: [{
|
|
52
|
+
label: undefined
|
|
53
|
+
}, {
|
|
54
|
+
label: ''
|
|
55
|
+
}]
|
|
56
|
+
})),
|
|
57
|
+
container = _render2.container;
|
|
58
|
+
expect(container.querySelectorAll('[class*="__badge"]')).toHaveLength(0);
|
|
59
|
+
});
|
|
60
|
+
it('keeps the labelled badges and drops only the empty ones', function () {
|
|
61
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_index["default"], {
|
|
62
|
+
title: "Plans",
|
|
63
|
+
badges: [{
|
|
64
|
+
label: 'Premium'
|
|
65
|
+
}, {
|
|
66
|
+
label: null
|
|
67
|
+
}, {
|
|
68
|
+
label: 'Archived',
|
|
69
|
+
intent: 'draft'
|
|
70
|
+
}]
|
|
71
|
+
}));
|
|
72
|
+
expect(_react.screen.getByText('Premium')).toBeInTheDocument();
|
|
73
|
+
expect(_react.screen.getByText('Archived')).toBeInTheDocument();
|
|
74
|
+
expect(badgeText()).toHaveLength(2);
|
|
75
|
+
});
|
|
76
|
+
it('renders nothing for an absent or empty badges prop', function () {
|
|
77
|
+
var _render3 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_index["default"], {
|
|
78
|
+
title: "Stripe"
|
|
79
|
+
})),
|
|
80
|
+
withoutProp = _render3.container;
|
|
81
|
+
expect(withoutProp.querySelectorAll('[class*="__badge"]')).toHaveLength(0);
|
|
82
|
+
var _render4 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_index["default"], {
|
|
83
|
+
title: "Stripe",
|
|
84
|
+
badges: []
|
|
85
|
+
})),
|
|
86
|
+
withEmptyArray = _render4.container;
|
|
87
|
+
expect(withEmptyArray.querySelectorAll('[class*="__badge"]')).toHaveLength(0);
|
|
88
|
+
// An empty array used to fall through as a literal `0` in the heading.
|
|
89
|
+
expect(withEmptyArray.textContent).not.toContain('0');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
@use "sass:color";
|
|
6
6
|
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
7
|
+
@use "~@wordpress/base-styles/variables" as wp-vars;
|
|
7
8
|
|
|
8
9
|
.newspack-card.newspack-action-card {
|
|
9
10
|
padding: 0;
|
|
@@ -196,11 +197,7 @@
|
|
|
196
197
|
align-items: center;
|
|
197
198
|
display: flex;
|
|
198
199
|
flex-wrap: wrap;
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
.newspack-action-card__title {
|
|
202
|
-
margin-right: 8px;
|
|
203
|
-
}
|
|
200
|
+
gap: wp-vars.$grid-unit-10;
|
|
204
201
|
|
|
205
202
|
a {
|
|
206
203
|
color: inherit;
|
|
@@ -372,41 +369,6 @@
|
|
|
372
369
|
margin: 0;
|
|
373
370
|
}
|
|
374
371
|
|
|
375
|
-
/* Badge */
|
|
376
|
-
.newspack-action-card__badge {
|
|
377
|
-
background: wp-colors.$gray-100;
|
|
378
|
-
border-radius: 2px;
|
|
379
|
-
color: wp-colors.$gray-900;
|
|
380
|
-
display: block;
|
|
381
|
-
flex: 0 0 auto;
|
|
382
|
-
font-size: 12px;
|
|
383
|
-
font-weight: 400;
|
|
384
|
-
line-height: 1.333;
|
|
385
|
-
margin: 0 8px 0 0;
|
|
386
|
-
padding: 2px 4px;
|
|
387
|
-
|
|
388
|
-
&.newspack-action-card__badge-level-warning {
|
|
389
|
-
background-color: color-mix(in srgb, #fff 90%, wp-colors.$alert-yellow);
|
|
390
|
-
color: color-mix(in srgb, #000 50%, wp-colors.$alert-yellow);
|
|
391
|
-
}
|
|
392
|
-
&.newspack-action-card__badge-level-error {
|
|
393
|
-
background-color: color-mix(in srgb, #fff 90%, wp-colors.$alert-red);
|
|
394
|
-
color: color-mix(in srgb, #000 50%, wp-colors.$alert-red);
|
|
395
|
-
}
|
|
396
|
-
&.newspack-action-card__badge-level-success {
|
|
397
|
-
background-color: color-mix(in srgb, #fff 90%, wp-colors.$alert-green);
|
|
398
|
-
color: color-mix(in srgb, #000 50%, wp-colors.$alert-green);
|
|
399
|
-
}
|
|
400
|
-
&.newspack-action-card__badge-level-brand {
|
|
401
|
-
background-color: color-mix(in srgb, #fff 90%, var(--wp-admin-theme-color));
|
|
402
|
-
color: color-mix(in srgb, #000 50%, var(--wp-admin-theme-color));
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
+ .newspack-action-card__badge {
|
|
406
|
-
margin-left: -4px;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
372
|
/* Description Card */
|
|
411
373
|
&.newspack-description-card {
|
|
412
374
|
font-style: italic;
|
package/dist/cjs/button/index.js
CHANGED
|
@@ -34,7 +34,7 @@ var useHistory = _router["default"].useHistory;
|
|
|
34
34
|
var isJavascriptHref = function isJavascriptHref(href) {
|
|
35
35
|
return 'string' === typeof href && href.replace(/[\u0000-\u0020]/g, '').toLowerCase().startsWith('javascript:');
|
|
36
36
|
};
|
|
37
|
-
var Button = function
|
|
37
|
+
var Button = (0, _element.forwardRef)(function (_ref, ref) {
|
|
38
38
|
var href = _ref.href,
|
|
39
39
|
_ref$loading = _ref.loading,
|
|
40
40
|
loading = _ref$loading === void 0 ? undefined : _ref$loading,
|
|
@@ -89,9 +89,14 @@ var Button = function Button(_ref) {
|
|
|
89
89
|
if (isAwaitingOnClick) {
|
|
90
90
|
otherProps.disabled = true;
|
|
91
91
|
}
|
|
92
|
+
// `loading` is this component's own prop name; @wordpress/components' Button
|
|
93
|
+
// expresses the same state as `isBusy`. Forwarding `loading` verbatim would
|
|
94
|
+
// land it on the DOM node, which React rejects as a non-boolean attribute.
|
|
92
95
|
// @ts-expect-error - @wordpress/components' Button can only have either href or onClick, not both.
|
|
93
96
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Button, _objectSpread({
|
|
94
|
-
|
|
97
|
+
ref: ref,
|
|
98
|
+
isBusy: loading ? true : undefined
|
|
95
99
|
}, otherProps));
|
|
96
|
-
};
|
|
100
|
+
});
|
|
101
|
+
Button.displayName = 'Button';
|
|
97
102
|
var _default = exports["default"] = Button;
|
|
@@ -4,12 +4,15 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
5
5
|
var _react = require("@testing-library/react");
|
|
6
6
|
var _reactRouterDom = require("react-router-dom");
|
|
7
|
+
var _element = require("@wordpress/element");
|
|
7
8
|
var _ = _interopRequireDefault(require("./"));
|
|
8
9
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
9
10
|
function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i["return"]) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
|
|
10
11
|
function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); } r ? i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); }, _regeneratorDefine2(e, r, n, t); } /**
|
|
11
12
|
* External dependencies.
|
|
12
13
|
*/ /**
|
|
14
|
+
* WordPress dependencies.
|
|
15
|
+
*/ /**
|
|
13
16
|
* Internal dependencies.
|
|
14
17
|
*/
|
|
15
18
|
var HistoryGrabber = function HistoryGrabber(_ref) {
|
|
@@ -44,6 +47,18 @@ var clickButton = /*#__PURE__*/function () {
|
|
|
44
47
|
return _ref2.apply(this, arguments);
|
|
45
48
|
};
|
|
46
49
|
}();
|
|
50
|
+
|
|
51
|
+
// React formats its warnings with `%s` placeholders and passes the values as
|
|
52
|
+
// further arguments, so assert against the whole call rather than one argument.
|
|
53
|
+
var messagesFrom = function messagesFrom(spy) {
|
|
54
|
+
return spy.mock.calls.flat().join(' ');
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// A failing assertion skips any `mockRestore()` left after it, which would leave
|
|
58
|
+
// the console swallowed for every later test in the file.
|
|
59
|
+
afterEach(function () {
|
|
60
|
+
jest.restoreAllMocks();
|
|
61
|
+
});
|
|
47
62
|
describe('Button href with onClick', function () {
|
|
48
63
|
it('awaits the onClick, then pushes the route', /*#__PURE__*/(0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator().m(function _callee3() {
|
|
49
64
|
var historyRef, onClick;
|
|
@@ -234,7 +249,6 @@ describe('Button href with onClick outside a router', function () {
|
|
|
234
249
|
})));
|
|
235
250
|
case 1:
|
|
236
251
|
expect(warn).toHaveBeenCalledWith(expect.stringContaining('javascript:'));
|
|
237
|
-
warn.mockRestore();
|
|
238
252
|
case 2:
|
|
239
253
|
return _context10.a(2);
|
|
240
254
|
}
|
|
@@ -246,22 +260,21 @@ describe('Button with a javascript: href alone', function () {
|
|
|
246
260
|
return _react.screen.getByText('Save').closest('a');
|
|
247
261
|
};
|
|
248
262
|
it('renders no link', function () {
|
|
249
|
-
|
|
263
|
+
// Silenced only; the assertion below is about the markup, not the warning.
|
|
264
|
+
jest.spyOn(console, 'warn').mockImplementation(function () {});
|
|
250
265
|
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"], {
|
|
251
266
|
href: "JavaScript:alert(1)",
|
|
252
267
|
children: "Save"
|
|
253
268
|
}));
|
|
254
269
|
expect(link()).toBeNull();
|
|
255
|
-
warn.mockRestore();
|
|
256
270
|
});
|
|
257
271
|
it('sees through interleaved control characters', function () {
|
|
258
|
-
|
|
272
|
+
jest.spyOn(console, 'warn').mockImplementation(function () {});
|
|
259
273
|
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"], {
|
|
260
274
|
href: 'java\nscript:alert(1)',
|
|
261
275
|
children: "Save"
|
|
262
276
|
}));
|
|
263
277
|
expect(link()).toBeNull();
|
|
264
|
-
warn.mockRestore();
|
|
265
278
|
});
|
|
266
279
|
it('leaves an ordinary href alone', function () {
|
|
267
280
|
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"], {
|
|
@@ -270,4 +283,47 @@ describe('Button with a javascript: href alone', function () {
|
|
|
270
283
|
}));
|
|
271
284
|
expect(link()).toHaveAttribute('href', '/wp-admin/admin.php?page=next');
|
|
272
285
|
});
|
|
286
|
+
});
|
|
287
|
+
describe('Button loading prop', function () {
|
|
288
|
+
var button = function button() {
|
|
289
|
+
return _react.screen.getByRole('button', {
|
|
290
|
+
name: 'Save'
|
|
291
|
+
});
|
|
292
|
+
};
|
|
293
|
+
it('renders the core busy state without putting `loading` on the DOM node', function () {
|
|
294
|
+
var error = jest.spyOn(console, 'error').mockImplementation(function () {});
|
|
295
|
+
var _render = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"], {
|
|
296
|
+
children: "Save"
|
|
297
|
+
})),
|
|
298
|
+
rerender = _render.rerender;
|
|
299
|
+
expect(button()).not.toHaveClass('is-busy');
|
|
300
|
+
rerender(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"], {
|
|
301
|
+
loading: true,
|
|
302
|
+
children: "Save"
|
|
303
|
+
}));
|
|
304
|
+
expect(button()).toHaveClass('is-busy');
|
|
305
|
+
// React drops an unknown boolean-valued attribute instead of writing it, so
|
|
306
|
+
// the warning rather than the absent attribute is what a revert trips. It is
|
|
307
|
+
// also deduped per property name for the life of the module registry, which
|
|
308
|
+
// is why this names the message instead of asserting no errors at all.
|
|
309
|
+
expect(messagesFrom(error)).not.toContain('non-boolean attribute');
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// core's Button wraps itself in a Tooltip when it is given a `label`, and the
|
|
314
|
+
// Tooltip needs a ref on its child. Two call sites do that with this Button:
|
|
315
|
+
// the experimental-tools back button and the audience segment-group heading.
|
|
316
|
+
describe('Button ref', function () {
|
|
317
|
+
it('forwards the ref to the rendered button', function () {
|
|
318
|
+
var error = jest.spyOn(console, 'error').mockImplementation(function () {});
|
|
319
|
+
var ref = (0, _element.createRef)();
|
|
320
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"], {
|
|
321
|
+
ref: ref,
|
|
322
|
+
children: "Save"
|
|
323
|
+
}));
|
|
324
|
+
expect(ref.current).toBe(_react.screen.getByRole('button', {
|
|
325
|
+
name: 'Save'
|
|
326
|
+
}));
|
|
327
|
+
expect(messagesFrom(error)).not.toContain('Function components cannot be given refs');
|
|
328
|
+
});
|
|
273
329
|
});
|
|
@@ -141,7 +141,6 @@ var CoreCard = function CoreCard(_ref) {
|
|
|
141
141
|
}), (actions === null || actions === void 0 ? void 0 : actions.length) > 0 && actionType === 'toggle' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, {
|
|
142
142
|
className: "newspack-card--core__action",
|
|
143
143
|
label: otherProps.title,
|
|
144
|
-
hideLabelFromVision: true,
|
|
145
144
|
checked: isActive,
|
|
146
145
|
onChange: onToggle
|
|
147
146
|
}), header && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
@@ -155,7 +154,6 @@ var CoreCard = function CoreCard(_ref) {
|
|
|
155
154
|
}), !(actions !== null && actions !== void 0 && actions.length) > 0 && actionType === 'toggle' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, {
|
|
156
155
|
className: "newspack-card--core__action",
|
|
157
156
|
label: otherProps.title,
|
|
158
|
-
hideLabelFromVision: true,
|
|
159
157
|
checked: isActive,
|
|
160
158
|
onChange: onToggle
|
|
161
159
|
}), (actions === null || actions === void 0 ? void 0 : actions.length) > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.DropdownMenu, {
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
6
6
|
@use "~@wordpress/base-styles/variables" as wp-vars;
|
|
7
|
-
@use "../../../colors/colors.module" as colors;
|
|
8
7
|
|
|
9
8
|
.newspack-card--core,
|
|
10
9
|
.newspack-wizard .newspack-card--core {
|
|
@@ -45,7 +44,13 @@
|
|
|
45
44
|
}
|
|
46
45
|
.newspack-card--core {
|
|
47
46
|
&__header-content {
|
|
48
|
-
|
|
47
|
+
h1,
|
|
48
|
+
h2,
|
|
49
|
+
h3,
|
|
50
|
+
h4,
|
|
51
|
+
h5,
|
|
52
|
+
h6,
|
|
53
|
+
p {
|
|
49
54
|
line-height: wp-vars.$font-line-height-small;
|
|
50
55
|
}
|
|
51
56
|
}
|
|
@@ -210,9 +215,6 @@
|
|
|
210
215
|
text-decoration: underline;
|
|
211
216
|
}
|
|
212
217
|
}
|
|
213
|
-
.newspack-badge {
|
|
214
|
-
font-weight: 400;
|
|
215
|
-
}
|
|
216
218
|
}
|
|
217
219
|
}
|
|
218
220
|
&__is-selectable {
|