@automattic/jetpack-components 5.0.1 → 6.0.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 (31) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/build/components/admin-page/index.d.ts +1 -0
  3. package/build/components/admin-page/index.js +10 -4
  4. package/build/components/admin-page/page-action-button.d.ts +5 -0
  5. package/build/components/admin-page/page-action-button.js +44 -0
  6. package/build/components/admin-page/types.d.ts +4 -0
  7. package/build/components/boost-score-bar/index.js +7 -7
  8. package/build/components/jetpack-footer/index.d.ts +1 -18
  9. package/build/components/jetpack-footer/index.js +1 -39
  10. package/build/components/jetpack-footer/jetpack-footer.d.ts +18 -0
  11. package/build/components/jetpack-footer/jetpack-footer.js +39 -0
  12. package/build/components/terms-of-service/index.js +3 -4
  13. package/build/components/terms-of-service/styles.scss +5 -2
  14. package/build/components/terms-of-service/types.d.ts +12 -2
  15. package/build/index.d.ts +1 -1
  16. package/build/index.js +1 -1
  17. package/components/admin-page/index.tsx +10 -2
  18. package/components/admin-page/page-action-button.tsx +69 -0
  19. package/components/admin-page/types.ts +5 -0
  20. package/components/boost-score-bar/index.tsx +9 -9
  21. package/components/jetpack-footer/README.md +9 -0
  22. package/components/jetpack-footer/index.tsx +1 -112
  23. package/components/jetpack-footer/jetpack-footer.tsx +113 -0
  24. package/components/terms-of-service/index.tsx +3 -4
  25. package/components/terms-of-service/styles.scss +5 -2
  26. package/components/terms-of-service/types.ts +13 -22
  27. package/index.ts +1 -1
  28. package/package.json +17 -12
  29. package/build/components/number-control/index.d.ts +0 -28
  30. package/build/components/number-control/index.js +0 -17
  31. package/components/number-control/index.tsx +0 -45
package/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  ### This is a list detailing changes for the Jetpack RNA Components package releases.
4
4
 
5
+ ## [6.0.0] - 2026-10-26
6
+ ### Added
7
+ - AdminPage: Add an ariaLabel prop that names the page region when the header shows breadcrumbs instead of a title. [#54055]
8
+ - AdminPage: Add a page action button that shows only its icon on screens 480px wide or narrower. [#53921]
9
+ - JetpackFooter: Add an entry without the stylesheet, and export the stylesheet on its own, so script-module builds can bundle the footer. [#53971]
10
+ - Support React 19. [#53882]
11
+
12
+ ### Changed
13
+ - TermsOfService: Render with Text from @wordpress/ui. The `variant` prop now takes a @wordpress/ui Text variant, and the legacy Text spacing and `component` props are removed. [#53892]
14
+ - Update package dependencies. [#53951]
15
+
16
+ ### Removed
17
+ - Remove the `NumberControl` component. Use `InputControl` from `@wordpress/ui` instead. [#54046]
18
+
19
+ ### Fixed
20
+ - AdminPage: Stop clearing the shared REST API nonce and root when a page doesn't pass them. [#53397]
21
+
5
22
  ## [5.0.1] - 2026-10-20
6
23
  ### Changed
7
24
  - Internal updates.
@@ -2019,6 +2036,7 @@
2019
2036
  ### Changed
2020
2037
  - Update node version requirement to 14.16.1
2021
2038
 
2039
+ [6.0.0]: https://github.com/Automattic/jetpack-components/compare/5.0.1...6.0.0
2022
2040
  [5.0.1]: https://github.com/Automattic/jetpack-components/compare/5.0.0...5.0.1
2023
2041
  [5.0.0]: https://github.com/Automattic/jetpack-components/compare/4.0.4...5.0.0
2024
2042
  [4.0.4]: https://github.com/Automattic/jetpack-components/compare/4.0.3...4.0.4
@@ -10,3 +10,4 @@ import type { FC } from 'react';
10
10
  */
11
11
  declare const AdminPage: FC<AdminPageProps>;
12
12
  export default AdminPage;
13
+ export { default as PageActionButton } from './page-action-button.tsx';
@@ -17,10 +17,15 @@ import styles from './style.module.scss';
17
17
  * @param {AdminPageProps} props - Component properties.
18
18
  * @return {ReactNode} AdminPage component.
19
19
  */
20
- const AdminPage = ({ children, className, showHeader = true, showFooter = true, showBackground = true, sandboxedDomain = '', apiRoot = '', apiNonce = '', optionalMenuItems, header, title, subTitle, logo, actions, globalControls, breadcrumbs, tabs, showBottomBorder = true, unwrapped = false, }) => {
20
+ const AdminPage = ({ children, className, showHeader = true, showFooter = true, showBackground = true, sandboxedDomain = '', apiRoot = '', apiNonce = '', optionalMenuItems, header, title, subTitle, logo, actions, globalControls, breadcrumbs, ariaLabel, tabs, showBottomBorder = true, unwrapped = false, }) => {
21
+ // Only set what was passed: the client is shared, so an empty default would wipe what the page set.
21
22
  useEffect(() => {
22
- restApi.setApiRoot(apiRoot);
23
- restApi.setApiNonce(apiNonce);
23
+ if (apiRoot) {
24
+ restApi.setApiRoot(apiRoot);
25
+ }
26
+ if (apiNonce) {
27
+ restApi.setApiNonce(apiNonce);
28
+ }
24
29
  }, [apiRoot, apiNonce]);
25
30
  // `jp-admin-page` is a stable, non-hashed hook for global stylesheets and
26
31
  // shared SCSS mixins (notably `jetpack-admin-page-layout` in
@@ -44,7 +49,7 @@ const AdminPage = ({ children, className, showHeader = true, showFooter = true,
44
49
  }, []);
45
50
  // When title or breadcrumbs are provided, use admin-ui Page for the full page layout.
46
51
  if (showHeader && (title || breadcrumbs)) {
47
- return (_jsx("div", { className: rootClassName, children: _jsxs(Page, { className: "jp-admin-page__page", visual: logo || _jsx(JetpackLogo, { showText: false, height: 20 }), breadcrumbs: breadcrumbs, title: title, subTitle: subTitle, actions: globalControls ? (_jsxs(_Fragment, { children: [actions, actions && (_jsx("span", { role: "separator", "aria-orientation": "vertical", className: styles['global-controls-separator'] })), globalControls] })) : (actions), showSidebarToggle: false, children: [tabs, unwrapped ? (children) : (_jsx(Container, { fluid: true, horizontalSpacing: 0, children: _jsx(Col, { children: children }) })), showFooter && _jsx(JetpackFooter, { menu: optionalMenuItems })] }) }));
52
+ return (_jsx("div", { className: rootClassName, children: _jsxs(Page, { className: "jp-admin-page__page", visual: logo || _jsx(JetpackLogo, { showText: false, height: 20 }), breadcrumbs: breadcrumbs, title: title, ariaLabel: ariaLabel, subTitle: subTitle, actions: globalControls ? (_jsxs(_Fragment, { children: [actions, actions && (_jsx("span", { role: "separator", "aria-orientation": "vertical", className: styles['global-controls-separator'] })), globalControls] })) : (actions), showSidebarToggle: false, children: [tabs, unwrapped ? (children) : (_jsx(Container, { fluid: true, horizontalSpacing: 0, children: _jsx(Col, { children: children }) })), showFooter && _jsx(JetpackFooter, { menu: optionalMenuItems })] }) }));
48
53
  }
49
54
  // Legacy path: no title provided, render the classic header.
50
55
  return (_jsxs("div", { className: rootClassName, children: [showHeader && (_jsx(Container, { horizontalSpacing: 5, children: _jsxs(Col, { className: clsx(styles['admin-page-header'], 'jp-admin-page-header'), children: [header ? header : _jsx(JetpackLogo, {}), sandboxedDomain && (_jsx("code", { className: styles['sandbox-domain-badge'], onClick: testConnection, onKeyDown: testConnection,
@@ -52,3 +57,4 @@ const AdminPage = ({ children, className, showHeader = true, showFooter = true,
52
57
  role: "button", tabIndex: 0, title: `Sandboxing via ${sandboxedDomain}. Click to test connection.`, children: "API Sandboxed" }))] }) })), _jsx(Container, { fluid: true, horizontalSpacing: 0, children: _jsx(Col, { children: children }) }), showFooter && _jsx(JetpackFooter, { menu: optionalMenuItems })] }));
53
58
  };
54
59
  export default AdminPage;
60
+ export { default as PageActionButton } from './page-action-button.js';
@@ -0,0 +1,5 @@
1
+ import { IconButton } from '@wordpress/ui';
2
+ import type { ComponentProps, ForwardRefExoticComponent, RefAttributes } from 'react';
3
+ type PageActionButtonProps = ComponentProps<typeof IconButton>;
4
+ declare const ForwardedPageActionButton: ForwardRefExoticComponent<PageActionButtonProps & RefAttributes<HTMLButtonElement>>;
5
+ export default ForwardedPageActionButton;
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useMergeRefs, useViewportMatch } from '@wordpress/compose';
3
+ import { Button, IconButton } from '@wordpress/ui';
4
+ import { forwardRef, useCallback, useRef } from 'react';
5
+ /**
6
+ * A page action for `AdminPage`'s `actions`: a labelled button, or an icon button on narrow screens.
7
+ *
8
+ * The label stays the button's accessible name, and becomes its tooltip when only the icon shows.
9
+ *
10
+ * @param props - Any `Button` prop, passed to whichever button renders, plus the ones below.
11
+ * @param props.label - The button's text, or its tooltip when only the icon shows.
12
+ * @param props.icon - The icon shown on narrow screens.
13
+ * @param props.shortcut - Shown in the icon button's tooltip, so on narrow screens only.
14
+ * @param props.positioner - Positions the icon button's tooltip, so on narrow screens only.
15
+ * @param ref - Forwarded to the rendered button.
16
+ * @return The button.
17
+ */
18
+ function PageActionButton({ label, icon, shortcut, positioner, ...buttonProps }, ref) {
19
+ // On phones, page actions show only their icon so the header's title keeps its room.
20
+ const isNarrowScreen = useViewportMatch('mobile', '<');
21
+ // Crossing the breakpoint swaps in a new button: move focus to it if the old one had it.
22
+ const button = useRef(null);
23
+ const hadFocus = useRef(false);
24
+ const keepFocus = useCallback((node) => {
25
+ const previous = button.current;
26
+ if (node) {
27
+ if (hadFocus.current) {
28
+ node.focus();
29
+ }
30
+ hadFocus.current = false;
31
+ }
32
+ else {
33
+ hadFocus.current = previous?.ownerDocument.activeElement === previous;
34
+ }
35
+ button.current = node;
36
+ }, []);
37
+ const mergedRef = useMergeRefs([ref, keepFocus]);
38
+ if (isNarrowScreen) {
39
+ return (_jsx(IconButton, { ref: mergedRef, label: label, icon: icon, shortcut: shortcut, positioner: positioner, ...buttonProps }));
40
+ }
41
+ return (_jsx(Button, { ref: mergedRef, ...buttonProps, children: label }));
42
+ }
43
+ const ForwardedPageActionButton = forwardRef(PageActionButton);
44
+ export default ForwardedPageActionButton;
@@ -41,6 +41,10 @@ export type AdminPageProps = {
41
41
  * Breadcrumb navigation displayed next to the title in the unified header.
42
42
  */
43
43
  breadcrumbs?: ReactNode;
44
+ /**
45
+ * Accessible name of the page region. Defaults to `title`, so pass it when the header shows `breadcrumbs` instead.
46
+ */
47
+ ariaLabel?: string;
44
48
  /**
45
49
  * Tab navigation displayed below the title/tagline in the unified header.
46
50
  */
@@ -1,8 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { getScoreTier } from '@automattic/jetpack-boost-score-api';
2
3
  import { __ } from '@wordpress/i18n';
3
4
  import { Icon, desktop, mobile } from '@wordpress/icons';
4
5
  import clsx from 'clsx';
5
6
  import './style.scss';
7
+ const TIER_FILLS = {
8
+ good: 'fill-good',
9
+ medium: 'fill-mediocre',
10
+ poor: 'fill-bad',
11
+ };
6
12
  export const BoostScoreBar = ({ score, isLoading, showPrevScores, active, prevScore = 0, scoreBarType, noBoostScoreTooltip, }) => {
7
13
  if (!active) {
8
14
  return null;
@@ -22,13 +28,7 @@ export const BoostScoreBar = ({ score, isLoading, showPrevScores, active, prevSc
22
28
  if (isLoading && !score) {
23
29
  return 'fill-loading';
24
30
  }
25
- if (score > 70) {
26
- return 'fill-good';
27
- }
28
- if (score > 50) {
29
- return 'fill-mediocre';
30
- }
31
- return 'fill-bad';
31
+ return TIER_FILLS[getScoreTier(score)];
32
32
  };
33
33
  return (_jsxs("div", { className: clsx('jb-score-bar', `jb-score-bar--${scoreBarType}`), children: [_jsxs("div", { className: "jb-score-bar__label", children: [getIcon(), _jsx("div", { children: scoreBarType === 'desktop' ? desktopIconLabel : mobileIconLabel })] }), _jsx("div", { className: "jb-score-bar__bounds", children: _jsxs("div", { className: clsx('jb-score-bar__filler', getFillColor()), style: { width: `${score}%` }, children: [isLoading ? (_jsx("div", { className: "jb-score-bar__loading", children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 128 128", children: _jsxs("g", { children: [_jsx("path", { d: "M64 0a7 7 0 11-7 7 7 7 0 017-7zm29.86 12.2a2.8 2.8 0 11-3.83 1.02 2.8 2.8 0 013.83-1.02zm22.16 21.68a3.15 3.15 0 11-4.3-1.15 3.15 3.15 0 014.3 1.15zm.87 60.53a4.2 4.2 0 11-1.57-5.7 4.2 4.2 0 011.54 5.73zm7.8-30.5a3.85 3.85 0 11-3.85-3.85 3.85 3.85 0 013.85 3.84zm-30 53.2a4.55 4.55 0 111.66-6.23 4.55 4.55 0 01-1.67 6.22zM64 125.9a4.9 4.9 0 114.9-4.9 4.9 4.9 0 01-4.9 4.9zm-31.06-8.22a5.25 5.25 0 117.17-1.93 5.25 5.25 0 01-7.14 1.93zM9.9 95.1a5.6 5.6 0 117.65 2.06A5.6 5.6 0 019.9 95.1zM1.18 63.9a5.95 5.95 0 115.95 5.94 5.95 5.95 0 01-5.96-5.94zm8.1-31.6a6.3 6.3 0 112.32 8.6 6.3 6.3 0 01-2.3-8.6zM32.25 8.87a6.65 6.65 0 11-2.44 9.1 6.65 6.65 0 012.46-9.1z" }), _jsx("animateTransform", { attributeName: "transform", type: "rotate", values: "0 64 64;30 64 64;60 64 64;90 64 64;120 64 64;150 64 64;180 64 64;210 64 64;240 64 64;270 64 64;300 64 64;330 64 64", calcMode: "discrete", dur: "1080ms", repeatCount: "indefinite" })] }) }) })) : (_jsx("div", { className: "jb-score-bar__score", children: score })), showPrevScores && !!prevScore && prevScore < score && (_jsxs("div", { className: "jb-score-bar__no_boost_score", style: { left: `min(${prevScoreOffset}%, calc( 100% - var(--clearance-space))` }, children: [prevScore, noBoostScoreTooltip && (_jsx("div", { role: "tooltip", className: "jb-score-bar__no_boost_score_tooltip", children: noBoostScoreTooltip }))] }))] }) })] }));
34
34
  };
@@ -1,19 +1,2 @@
1
1
  import './style.scss';
2
- import type { JetpackFooterProps } from './types.ts';
3
- import type { FC } from 'react';
4
- declare global {
5
- interface Window {
6
- JetpackNetworkAdminData?: {
7
- sitesUrl: string;
8
- settingsUrl: string;
9
- };
10
- }
11
- }
12
- /**
13
- * JetpackFooter component displays a tiny Jetpack logo with the product name on the left and the Automattic Airline "by line" on the right.
14
- *
15
- * @param {JetpackFooterProps} props - Component properties.
16
- * @return {ReactNode} JetpackFooter component.
17
- */
18
- declare const JetpackFooter: FC<JetpackFooterProps>;
19
- export default JetpackFooter;
2
+ export { default } from './jetpack-footer.tsx';
@@ -1,40 +1,2 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { isWpcomPlatformSite, getAdminUrl, getScriptData } from '@automattic/jetpack-script-data';
3
- import { __ } from '@wordpress/i18n';
4
- import { Stack, Text, Link } from '@wordpress/ui';
5
- import clsx from 'clsx';
6
- import { getRedirectUrl } from '../../index.js';
7
- import AutomatticBylineLogo from '../automattic-byline-logo/index.js';
8
1
  import './style.scss';
9
- import JetpackLogo from '../jetpack-logo/index.js';
10
- /**
11
- * JetpackFooter component displays a tiny Jetpack logo with the product name on the left and the Automattic Airline "by line" on the right.
12
- *
13
- * @param {JetpackFooterProps} props - Component properties.
14
- * @return {ReactNode} JetpackFooter component.
15
- */
16
- const JetpackFooter = ({ className, menu, ...otherProps }) => {
17
- let items = [];
18
- if (getScriptData()?.myJetpack?.isAvailable === true &&
19
- !isWpcomPlatformSite() &&
20
- !window?.JetpackNetworkAdminData) {
21
- items = [
22
- {
23
- label: __('Features', 'jetpack-components'),
24
- href: getAdminUrl('admin.php?page=my-jetpack#/features'),
25
- },
26
- {
27
- label: __('Help', 'jetpack-components'),
28
- href: getAdminUrl('admin.php?page=my-jetpack#/help'),
29
- },
30
- ...items,
31
- ];
32
- }
33
- if (menu) {
34
- items = [...items, ...menu];
35
- }
36
- return (_jsxs(Stack, { render: _jsx("footer", {}), className: clsx('jetpack-footer', className), "aria-label": __('Jetpack', 'jetpack-components'), role: "contentinfo", direction: "row", justify: "flex-start", align: "center", wrap: "wrap", gap: "xl", ...otherProps, children: [_jsxs(Stack, { className: "jetpack-footer__logo", direction: "row", gap: "sm", align: "center", children: [_jsx(JetpackLogo, { showText: false, height: 16, "aria-hidden": "true" }), _jsx(Text, { variant: "body-md", children: "Jetpack" })] }), _jsx(Stack, { render: _jsx("ul", {}), direction: "row", gap: "lg", wrap: "wrap", children: items.map(item => {
37
- return (_jsx("li", { children: _jsx(Text, { variant: "body-md", className: "jetpack-footer__menu-item", render: !item.href ? (_jsx(Link, { render: _jsx("span", {}), tabIndex: 0, title: item.title || '', onClick: item.onClick || undefined, onKeyDown: item.onKeyDown || undefined, role: "button" })) : (_jsx(Link, { href: item.href, title: item.title || '', onClick: item.onClick || undefined, onKeyDown: item.onKeyDown || undefined })), children: item.label }) }, item.label));
38
- }) }), _jsx("a", { className: "jetpack-footer__a8c", href: getRedirectUrl('a8c-about'), rel: "noopener noreferrer", target: "_blank", children: _jsx(AutomatticBylineLogo, { height: 8 }) })] }));
39
- };
40
- export default JetpackFooter;
2
+ export { default } from './jetpack-footer.js';
@@ -0,0 +1,18 @@
1
+ import type { JetpackFooterProps } from './types.ts';
2
+ import type { FC } from 'react';
3
+ declare global {
4
+ interface Window {
5
+ JetpackNetworkAdminData?: {
6
+ sitesUrl: string;
7
+ settingsUrl: string;
8
+ };
9
+ }
10
+ }
11
+ /**
12
+ * JetpackFooter component displays a tiny Jetpack logo with the product name on the left and the Automattic Airline "by line" on the right.
13
+ *
14
+ * @param {JetpackFooterProps} props - Component properties.
15
+ * @return {ReactNode} JetpackFooter component.
16
+ */
17
+ declare const JetpackFooter: FC<JetpackFooterProps>;
18
+ export default JetpackFooter;
@@ -0,0 +1,39 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { isWpcomPlatformSite, getAdminUrl, getScriptData } from '@automattic/jetpack-script-data';
3
+ import { __ } from '@wordpress/i18n';
4
+ import { Stack, Text, Link } from '@wordpress/ui';
5
+ import clsx from 'clsx';
6
+ import getRedirectUrl from '../../tools/jp-redirect/index.js';
7
+ import AutomatticBylineLogo from '../automattic-byline-logo/index.js';
8
+ import JetpackLogo from '../jetpack-logo/index.js';
9
+ /**
10
+ * JetpackFooter component displays a tiny Jetpack logo with the product name on the left and the Automattic Airline "by line" on the right.
11
+ *
12
+ * @param {JetpackFooterProps} props - Component properties.
13
+ * @return {ReactNode} JetpackFooter component.
14
+ */
15
+ const JetpackFooter = ({ className, menu, ...otherProps }) => {
16
+ let items = [];
17
+ if (getScriptData()?.myJetpack?.isAvailable === true &&
18
+ !isWpcomPlatformSite() &&
19
+ !window?.JetpackNetworkAdminData) {
20
+ items = [
21
+ {
22
+ label: __('Features', 'jetpack-components'),
23
+ href: getAdminUrl('admin.php?page=my-jetpack#/features'),
24
+ },
25
+ {
26
+ label: __('Help', 'jetpack-components'),
27
+ href: getAdminUrl('admin.php?page=my-jetpack#/help'),
28
+ },
29
+ ...items,
30
+ ];
31
+ }
32
+ if (menu) {
33
+ items = [...items, ...menu];
34
+ }
35
+ return (_jsxs(Stack, { render: _jsx("footer", {}), className: clsx('jetpack-footer', className), "aria-label": __('Jetpack', 'jetpack-components'), role: "contentinfo", direction: "row", justify: "flex-start", align: "center", wrap: "wrap", gap: "xl", ...otherProps, children: [_jsxs(Stack, { className: "jetpack-footer__logo", direction: "row", gap: "sm", align: "center", children: [_jsx(JetpackLogo, { showText: false, height: 16, "aria-hidden": "true" }), _jsx(Text, { variant: "body-md", children: "Jetpack" })] }), _jsx(Stack, { render: _jsx("ul", {}), direction: "row", gap: "lg", wrap: "wrap", children: items.map(item => {
36
+ return (_jsx("li", { children: _jsx(Text, { variant: "body-md", className: "jetpack-footer__menu-item", render: !item.href ? (_jsx(Link, { render: _jsx("span", {}), tabIndex: 0, title: item.title || '', onClick: item.onClick || undefined, onKeyDown: item.onKeyDown || undefined, role: "button" })) : (_jsx(Link, { href: item.href, title: item.title || '', onClick: item.onClick || undefined, onKeyDown: item.onKeyDown || undefined })), children: item.label }) }, item.label));
37
+ }) }), _jsx("a", { className: "jetpack-footer__a8c", href: getRedirectUrl('a8c-about'), rel: "noopener noreferrer", target: "_blank", children: _jsx(AutomatticBylineLogo, { height: 8 }) })] }));
38
+ };
39
+ export default JetpackFooter;
@@ -1,16 +1,15 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createInterpolateElement } from '@wordpress/element';
3
3
  import { __, sprintf } from '@wordpress/i18n';
4
- import { Link } from '@wordpress/ui';
4
+ import { Link, Text } from '@wordpress/ui';
5
5
  import clsx from 'clsx';
6
6
  // Deep import rather than the package barrel (`../../index.ts`): the barrel
7
7
  // pulls in heavy, asset-importing components (e.g. boost-score-graph) that the
8
8
  // wp-build esbuild pipeline can't bundle, which breaks any wp-build dashboard
9
9
  // that deep-imports pricing-table (which renders TermsOfService).
10
10
  import getRedirectUrl from '../../tools/jp-redirect/index.js';
11
- import Text from '../text/index.js';
12
11
  import './styles.scss';
13
- const TermsOfService = ({ className, multipleButtons, agreeButtonLabel, isTextOnly, ...textProps }) => {
12
+ const TermsOfService = ({ className, variant = 'body-lg', multipleButtons, agreeButtonLabel, isTextOnly, }) => {
14
13
  const getTOSContent = () => {
15
14
  if (isTextOnly) {
16
15
  return _jsx(TermsOfServiceTextOnly, {});
@@ -20,7 +19,7 @@ const TermsOfService = ({ className, multipleButtons, agreeButtonLabel, isTextOn
20
19
  }
21
20
  return _jsx(SingleButtonText, { agreeButtonLabel: agreeButtonLabel });
22
21
  };
23
- return (_jsx(Text, { className: clsx(className, 'terms-of-service'), ...textProps, children: getTOSContent() }));
22
+ return (_jsx(Text, { variant: variant, render: _jsx("p", {}), className: clsx(className, 'terms-of-service'), children: getTOSContent() }));
24
23
  };
25
24
  const MultipleButtonsText = ({ multipleButtonsLabels }) => {
26
25
  if (Array.isArray(multipleButtonsLabels) && multipleButtonsLabels.length > 1) {
@@ -1,6 +1,9 @@
1
- .terms-of-service {
2
- font-size: var(--font-body);
1
+ // No specificity, so any consumer class sets the colour without a tie.
2
+ :where(.terms-of-service) {
3
3
  color: var(--jp-black);
4
+ }
5
+
6
+ .terms-of-service {
4
7
 
5
8
  .terms-of-service__link {
6
9
  white-space: nowrap;
@@ -1,4 +1,5 @@
1
- import { TextProps } from '../text/types.ts';
1
+ import type { Text } from '@wordpress/ui';
2
+ import type { ComponentProps } from 'react';
2
3
  type MultipleButtonsProps = {
3
4
  /**
4
5
  * Indicates whether there are multiple buttons present that would imply agreement if clicked.
@@ -29,5 +30,14 @@ type OnlyTextProps = {
29
30
  multipleButtons?: undefined;
30
31
  agreeButtonLabel?: undefined;
31
32
  };
32
- export type TermsOfServiceProps = Pick<TextProps, 'variant' | 'm' | 'mt' | 'mr' | 'mb' | 'ml' | 'mx' | 'my' | 'p' | 'pt' | 'pr' | 'pb' | 'pl' | 'px' | 'py' | 'className' | 'component'> & (MultipleButtonsProps | SingleButtonProps | OnlyTextProps);
33
+ export type TermsOfServiceProps = {
34
+ /**
35
+ * HTML class.
36
+ */
37
+ className?: string;
38
+ /**
39
+ * The `@wordpress/ui` Text variant. Defaults to `body-lg`.
40
+ */
41
+ variant?: ComponentProps<typeof Text>['variant'];
42
+ } & (MultipleButtonsProps | SingleButtonProps | OnlyTextProps);
33
43
  export {};
package/build/index.d.ts CHANGED
@@ -17,6 +17,7 @@ export { default as PricingCard } from './components/pricing-card/index.tsx';
17
17
  export { default as AdminSection } from './components/admin-section/basic/index.tsx';
18
18
  export { default as AdminSectionHero } from './components/admin-section/hero/index.tsx';
19
19
  export { default as AdminPage } from './components/admin-page/index.tsx';
20
+ export { default as PageActionButton } from './components/admin-page/page-action-button.tsx';
20
21
  export { default as DecorativeCard } from './components/decorative-card/index.tsx';
21
22
  export { default as Col } from './components/layout/col/index.tsx';
22
23
  export { default as Testimonials } from './components/testimonials/index.tsx';
@@ -26,7 +27,6 @@ export { default as JitmSlot } from './components/jitm-slot/index.tsx';
26
27
  export * from './components/icons/index.tsx';
27
28
  export { default as ThemeProvider } from './components/theme-provider/index.tsx';
28
29
  export { default as Text, H2, H3, Title } from './components/text/index.tsx';
29
- export { default as NumberControl } from './components/number-control/index.tsx';
30
30
  export { default as QRCode } from './components/qr-code/index.tsx';
31
31
  export { default as Button } from './components/button/index.tsx';
32
32
  export type { ButtonProps } from './components/button/types.ts';
package/build/index.js CHANGED
@@ -29,6 +29,7 @@ export { default as PricingCard } from './components/pricing-card/index.js';
29
29
  export { default as AdminSection } from './components/admin-section/basic/index.js';
30
30
  export { default as AdminSectionHero } from './components/admin-section/hero/index.js';
31
31
  export { default as AdminPage } from './components/admin-page/index.js';
32
+ export { default as PageActionButton } from './components/admin-page/page-action-button.js';
32
33
  export { default as DecorativeCard } from './components/decorative-card/index.js';
33
34
  export { default as Col } from './components/layout/col/index.js';
34
35
  export { default as Testimonials } from './components/testimonials/index.js';
@@ -38,7 +39,6 @@ export { default as JitmSlot } from './components/jitm-slot/index.js';
38
39
  export * from './components/icons/index.js';
39
40
  export { default as ThemeProvider } from './components/theme-provider/index.js';
40
41
  export { default as Text, H2, H3, Title } from './components/text/index.js';
41
- export { default as NumberControl } from './components/number-control/index.js';
42
42
  export { default as QRCode } from './components/qr-code/index.js';
43
43
  export { default as Button } from './components/button/index.js';
44
44
  export { default as LoadingPlaceholder } from './components/loading-placeholder/index.js';
@@ -36,13 +36,19 @@ const AdminPage: FC< AdminPageProps > = ( {
36
36
  actions,
37
37
  globalControls,
38
38
  breadcrumbs,
39
+ ariaLabel,
39
40
  tabs,
40
41
  showBottomBorder = true,
41
42
  unwrapped = false,
42
43
  } ) => {
44
+ // Only set what was passed: the client is shared, so an empty default would wipe what the page set.
43
45
  useEffect( () => {
44
- restApi.setApiRoot( apiRoot );
45
- restApi.setApiNonce( apiNonce );
46
+ if ( apiRoot ) {
47
+ restApi.setApiRoot( apiRoot );
48
+ }
49
+ if ( apiNonce ) {
50
+ restApi.setApiNonce( apiNonce );
51
+ }
46
52
  }, [ apiRoot, apiNonce ] );
47
53
 
48
54
  // `jp-admin-page` is a stable, non-hashed hook for global stylesheets and
@@ -80,6 +86,7 @@ const AdminPage: FC< AdminPageProps > = ( {
80
86
  visual={ logo || <JetpackLogo showText={ false } height={ 20 } /> }
81
87
  breadcrumbs={ breadcrumbs }
82
88
  title={ title }
89
+ ariaLabel={ ariaLabel }
83
90
  subTitle={ subTitle }
84
91
  actions={
85
92
  globalControls ? (
@@ -146,3 +153,4 @@ const AdminPage: FC< AdminPageProps > = ( {
146
153
  };
147
154
 
148
155
  export default AdminPage;
156
+ export { default as PageActionButton } from './page-action-button.tsx';
@@ -0,0 +1,69 @@
1
+ import { useMergeRefs, useViewportMatch } from '@wordpress/compose';
2
+ import { Button, IconButton } from '@wordpress/ui';
3
+ import { forwardRef, useCallback, useRef } from 'react';
4
+ import type { ComponentProps, ForwardRefExoticComponent, ForwardedRef, RefAttributes } from 'react';
5
+
6
+ type PageActionButtonProps = ComponentProps< typeof IconButton >;
7
+
8
+ /**
9
+ * A page action for `AdminPage`'s `actions`: a labelled button, or an icon button on narrow screens.
10
+ *
11
+ * The label stays the button's accessible name, and becomes its tooltip when only the icon shows.
12
+ *
13
+ * @param props - Any `Button` prop, passed to whichever button renders, plus the ones below.
14
+ * @param props.label - The button's text, or its tooltip when only the icon shows.
15
+ * @param props.icon - The icon shown on narrow screens.
16
+ * @param props.shortcut - Shown in the icon button's tooltip, so on narrow screens only.
17
+ * @param props.positioner - Positions the icon button's tooltip, so on narrow screens only.
18
+ * @param ref - Forwarded to the rendered button.
19
+ * @return The button.
20
+ */
21
+ function PageActionButton(
22
+ { label, icon, shortcut, positioner, ...buttonProps }: PageActionButtonProps,
23
+ ref: ForwardedRef< HTMLButtonElement >
24
+ ) {
25
+ // On phones, page actions show only their icon so the header's title keeps its room.
26
+ const isNarrowScreen = useViewportMatch( 'mobile', '<' );
27
+
28
+ // Crossing the breakpoint swaps in a new button: move focus to it if the old one had it.
29
+ const button = useRef< HTMLButtonElement | null >( null );
30
+ const hadFocus = useRef( false );
31
+ const keepFocus = useCallback( ( node: HTMLButtonElement | null ) => {
32
+ const previous = button.current;
33
+ if ( node ) {
34
+ if ( hadFocus.current ) {
35
+ node.focus();
36
+ }
37
+ hadFocus.current = false;
38
+ } else {
39
+ hadFocus.current = previous?.ownerDocument.activeElement === previous;
40
+ }
41
+ button.current = node;
42
+ }, [] );
43
+ const mergedRef = useMergeRefs( [ ref, keepFocus ] );
44
+
45
+ if ( isNarrowScreen ) {
46
+ return (
47
+ <IconButton
48
+ ref={ mergedRef }
49
+ label={ label }
50
+ icon={ icon }
51
+ shortcut={ shortcut }
52
+ positioner={ positioner }
53
+ { ...buttonProps }
54
+ />
55
+ );
56
+ }
57
+
58
+ return (
59
+ <Button ref={ mergedRef } { ...buttonProps }>
60
+ { label }
61
+ </Button>
62
+ );
63
+ }
64
+
65
+ const ForwardedPageActionButton: ForwardRefExoticComponent<
66
+ PageActionButtonProps & RefAttributes< HTMLButtonElement >
67
+ > = forwardRef( PageActionButton );
68
+
69
+ export default ForwardedPageActionButton;
@@ -51,6 +51,11 @@ export type AdminPageProps = {
51
51
  */
52
52
  breadcrumbs?: ReactNode;
53
53
 
54
+ /**
55
+ * Accessible name of the page region. Defaults to `title`, so pass it when the header shows `breadcrumbs` instead.
56
+ */
57
+ ariaLabel?: string;
58
+
54
59
  /**
55
60
  * Tab navigation displayed below the title/tagline in the unified header.
56
61
  */
@@ -1,11 +1,19 @@
1
+ import { getScoreTier } from '@automattic/jetpack-boost-score-api';
1
2
  import { __ } from '@wordpress/i18n';
2
3
  import { Icon, desktop, mobile } from '@wordpress/icons';
3
4
  import clsx from 'clsx';
4
5
  import type { BoostScoreBarProps } from './types.ts';
6
+ import type { ScoreTier } from '@automattic/jetpack-boost-score-api';
5
7
  import type { FunctionComponent } from 'react';
6
8
 
7
9
  import './style.scss';
8
10
 
11
+ const TIER_FILLS: Record< ScoreTier, string > = {
12
+ good: 'fill-good',
13
+ medium: 'fill-mediocre',
14
+ poor: 'fill-bad',
15
+ };
16
+
9
17
  export const BoostScoreBar: FunctionComponent< BoostScoreBarProps > = ( {
10
18
  score,
11
19
  isLoading,
@@ -38,15 +46,7 @@ export const BoostScoreBar: FunctionComponent< BoostScoreBarProps > = ( {
38
46
  return 'fill-loading';
39
47
  }
40
48
 
41
- if ( score > 70 ) {
42
- return 'fill-good';
43
- }
44
-
45
- if ( score > 50 ) {
46
- return 'fill-mediocre';
47
- }
48
-
49
- return 'fill-bad';
49
+ return TIER_FILLS[ getScoreTier( score ) ];
50
50
  };
51
51
 
52
52
  return (
@@ -29,6 +29,15 @@ const menu = [
29
29
  <JetpackFooter menu={ menu } className="my-footer" />
30
30
  ```
31
31
 
32
+ ### Script-module builds
33
+
34
+ Builds that can't bundle Sass imported from a dependency, such as wp-build script modules, can import the component and its stylesheet separately. Use the two together, since `unstyled` ships no styles:
35
+
36
+ ```js
37
+ import '@automattic/jetpack-components/jetpack-footer/style.scss';
38
+ import JetpackFooter from '@automattic/jetpack-components/jetpack-footer/unstyled';
39
+ ```
40
+
32
41
  ## Props
33
42
 
34
43
  - `className`: String - (default: `jetpack-footer`) the additional class name set on the element.
@@ -1,114 +1,3 @@
1
- import { isWpcomPlatformSite, getAdminUrl, getScriptData } from '@automattic/jetpack-script-data';
2
- import { __ } from '@wordpress/i18n';
3
- import { Stack, Text, Link } from '@wordpress/ui';
4
- import clsx from 'clsx';
5
- import { getRedirectUrl } from '../../index.ts';
6
- import AutomatticBylineLogo from '../automattic-byline-logo/index.tsx';
7
1
  import './style.scss';
8
- import JetpackLogo from '../jetpack-logo/index.tsx';
9
- import type { JetpackFooterProps, JetpackFooterMenuItem } from './types.ts';
10
- import type { FC } from 'react';
11
2
 
12
- declare global {
13
- interface Window {
14
- JetpackNetworkAdminData?: {
15
- sitesUrl: string;
16
- settingsUrl: string;
17
- };
18
- }
19
- }
20
-
21
- /**
22
- * JetpackFooter component displays a tiny Jetpack logo with the product name on the left and the Automattic Airline "by line" on the right.
23
- *
24
- * @param {JetpackFooterProps} props - Component properties.
25
- * @return {ReactNode} JetpackFooter component.
26
- */
27
- const JetpackFooter: FC< JetpackFooterProps > = ( { className, menu, ...otherProps } ) => {
28
- let items: JetpackFooterMenuItem[] = [];
29
-
30
- if (
31
- getScriptData()?.myJetpack?.isAvailable === true &&
32
- ! isWpcomPlatformSite() &&
33
- ! window?.JetpackNetworkAdminData
34
- ) {
35
- items = [
36
- {
37
- label: __( 'Features', 'jetpack-components' ),
38
- href: getAdminUrl( 'admin.php?page=my-jetpack#/features' ),
39
- },
40
- {
41
- label: __( 'Help', 'jetpack-components' ),
42
- href: getAdminUrl( 'admin.php?page=my-jetpack#/help' ),
43
- },
44
- ...items,
45
- ];
46
- }
47
-
48
- if ( menu ) {
49
- items = [ ...items, ...menu ];
50
- }
51
-
52
- return (
53
- <Stack
54
- render={ <footer /> }
55
- className={ clsx( 'jetpack-footer', className ) }
56
- aria-label={ __( 'Jetpack', 'jetpack-components' ) }
57
- role="contentinfo"
58
- direction="row"
59
- justify="flex-start"
60
- align="center"
61
- wrap="wrap"
62
- gap="xl"
63
- { ...otherProps }
64
- >
65
- <Stack className="jetpack-footer__logo" direction="row" gap="sm" align="center">
66
- <JetpackLogo showText={ false } height={ 16 } aria-hidden="true" />
67
- <Text variant="body-md">Jetpack</Text>
68
- </Stack>
69
- <Stack render={ <ul /> } direction="row" gap="lg" wrap="wrap">
70
- { items.map( item => {
71
- return (
72
- <li key={ item.label }>
73
- <Text
74
- variant="body-md"
75
- className="jetpack-footer__menu-item"
76
- render={
77
- ! item.href ? (
78
- <Link
79
- render={ <span /> }
80
- tabIndex={ 0 }
81
- title={ item.title || '' }
82
- onClick={ item.onClick || undefined }
83
- onKeyDown={ item.onKeyDown || undefined }
84
- role="button"
85
- />
86
- ) : (
87
- <Link
88
- href={ item.href }
89
- title={ item.title || '' }
90
- onClick={ item.onClick || undefined }
91
- onKeyDown={ item.onKeyDown || undefined }
92
- />
93
- )
94
- }
95
- >
96
- { item.label }
97
- </Text>
98
- </li>
99
- );
100
- } ) }
101
- </Stack>
102
- <a
103
- className="jetpack-footer__a8c"
104
- href={ getRedirectUrl( 'a8c-about' ) }
105
- rel="noopener noreferrer"
106
- target="_blank"
107
- >
108
- <AutomatticBylineLogo height={ 8 } />
109
- </a>
110
- </Stack>
111
- );
112
- };
113
-
114
- export default JetpackFooter;
3
+ export { default } from './jetpack-footer.tsx';
@@ -0,0 +1,113 @@
1
+ import { isWpcomPlatformSite, getAdminUrl, getScriptData } from '@automattic/jetpack-script-data';
2
+ import { __ } from '@wordpress/i18n';
3
+ import { Stack, Text, Link } from '@wordpress/ui';
4
+ import clsx from 'clsx';
5
+ import getRedirectUrl from '../../tools/jp-redirect/index.ts';
6
+ import AutomatticBylineLogo from '../automattic-byline-logo/index.tsx';
7
+ import JetpackLogo from '../jetpack-logo/index.tsx';
8
+ import type { JetpackFooterProps, JetpackFooterMenuItem } from './types.ts';
9
+ import type { FC } from 'react';
10
+
11
+ declare global {
12
+ interface Window {
13
+ JetpackNetworkAdminData?: {
14
+ sitesUrl: string;
15
+ settingsUrl: string;
16
+ };
17
+ }
18
+ }
19
+
20
+ /**
21
+ * JetpackFooter component displays a tiny Jetpack logo with the product name on the left and the Automattic Airline "by line" on the right.
22
+ *
23
+ * @param {JetpackFooterProps} props - Component properties.
24
+ * @return {ReactNode} JetpackFooter component.
25
+ */
26
+ const JetpackFooter: FC< JetpackFooterProps > = ( { className, menu, ...otherProps } ) => {
27
+ let items: JetpackFooterMenuItem[] = [];
28
+
29
+ if (
30
+ getScriptData()?.myJetpack?.isAvailable === true &&
31
+ ! isWpcomPlatformSite() &&
32
+ ! window?.JetpackNetworkAdminData
33
+ ) {
34
+ items = [
35
+ {
36
+ label: __( 'Features', 'jetpack-components' ),
37
+ href: getAdminUrl( 'admin.php?page=my-jetpack#/features' ),
38
+ },
39
+ {
40
+ label: __( 'Help', 'jetpack-components' ),
41
+ href: getAdminUrl( 'admin.php?page=my-jetpack#/help' ),
42
+ },
43
+ ...items,
44
+ ];
45
+ }
46
+
47
+ if ( menu ) {
48
+ items = [ ...items, ...menu ];
49
+ }
50
+
51
+ return (
52
+ <Stack
53
+ render={ <footer /> }
54
+ className={ clsx( 'jetpack-footer', className ) }
55
+ aria-label={ __( 'Jetpack', 'jetpack-components' ) }
56
+ role="contentinfo"
57
+ direction="row"
58
+ justify="flex-start"
59
+ align="center"
60
+ wrap="wrap"
61
+ gap="xl"
62
+ { ...otherProps }
63
+ >
64
+ <Stack className="jetpack-footer__logo" direction="row" gap="sm" align="center">
65
+ <JetpackLogo showText={ false } height={ 16 } aria-hidden="true" />
66
+ <Text variant="body-md">Jetpack</Text>
67
+ </Stack>
68
+ <Stack render={ <ul /> } direction="row" gap="lg" wrap="wrap">
69
+ { items.map( item => {
70
+ return (
71
+ <li key={ item.label }>
72
+ <Text
73
+ variant="body-md"
74
+ className="jetpack-footer__menu-item"
75
+ render={
76
+ ! item.href ? (
77
+ <Link
78
+ render={ <span /> }
79
+ tabIndex={ 0 }
80
+ title={ item.title || '' }
81
+ onClick={ item.onClick || undefined }
82
+ onKeyDown={ item.onKeyDown || undefined }
83
+ role="button"
84
+ />
85
+ ) : (
86
+ <Link
87
+ href={ item.href }
88
+ title={ item.title || '' }
89
+ onClick={ item.onClick || undefined }
90
+ onKeyDown={ item.onKeyDown || undefined }
91
+ />
92
+ )
93
+ }
94
+ >
95
+ { item.label }
96
+ </Text>
97
+ </li>
98
+ );
99
+ } ) }
100
+ </Stack>
101
+ <a
102
+ className="jetpack-footer__a8c"
103
+ href={ getRedirectUrl( 'a8c-about' ) }
104
+ rel="noopener noreferrer"
105
+ target="_blank"
106
+ >
107
+ <AutomatticBylineLogo height={ 8 } />
108
+ </a>
109
+ </Stack>
110
+ );
111
+ };
112
+
113
+ export default JetpackFooter;
@@ -1,23 +1,22 @@
1
1
  import { createInterpolateElement } from '@wordpress/element';
2
2
  import { __, sprintf } from '@wordpress/i18n';
3
- import { Link } from '@wordpress/ui';
3
+ import { Link, Text } from '@wordpress/ui';
4
4
  import clsx from 'clsx';
5
5
  // Deep import rather than the package barrel (`../../index.ts`): the barrel
6
6
  // pulls in heavy, asset-importing components (e.g. boost-score-graph) that the
7
7
  // wp-build esbuild pipeline can't bundle, which breaks any wp-build dashboard
8
8
  // that deep-imports pricing-table (which renders TermsOfService).
9
9
  import getRedirectUrl from '../../tools/jp-redirect/index.ts';
10
- import Text from '../text/index.tsx';
11
10
  import type { TermsOfServiceProps } from './types.ts';
12
11
  import type { FC, ReactNode } from 'react';
13
12
  import './styles.scss';
14
13
 
15
14
  const TermsOfService: FC< TermsOfServiceProps > = ( {
16
15
  className,
16
+ variant = 'body-lg',
17
17
  multipleButtons,
18
18
  agreeButtonLabel,
19
19
  isTextOnly,
20
- ...textProps
21
20
  } ) => {
22
21
  const getTOSContent = () => {
23
22
  if ( isTextOnly ) {
@@ -30,7 +29,7 @@ const TermsOfService: FC< TermsOfServiceProps > = ( {
30
29
  };
31
30
 
32
31
  return (
33
- <Text className={ clsx( className, 'terms-of-service' ) } { ...textProps }>
32
+ <Text variant={ variant } render={ <p /> } className={ clsx( className, 'terms-of-service' ) }>
34
33
  { getTOSContent() }
35
34
  </Text>
36
35
  );
@@ -1,6 +1,9 @@
1
- .terms-of-service {
2
- font-size: var(--font-body);
1
+ // No specificity, so any consumer class sets the colour without a tie.
2
+ :where(.terms-of-service) {
3
3
  color: var(--jp-black);
4
+ }
5
+
6
+ .terms-of-service {
4
7
 
5
8
  .terms-of-service__link {
6
9
  white-space: nowrap;
@@ -1,4 +1,5 @@
1
- import { TextProps } from '../text/types.ts';
1
+ import type { Text } from '@wordpress/ui';
2
+ import type { ComponentProps } from 'react';
2
3
 
3
4
  type MultipleButtonsProps = {
4
5
  /**
@@ -37,24 +38,14 @@ type OnlyTextProps = {
37
38
  agreeButtonLabel?: undefined;
38
39
  };
39
40
 
40
- export type TermsOfServiceProps = Pick<
41
- TextProps,
42
- | 'variant'
43
- | 'm'
44
- | 'mt'
45
- | 'mr'
46
- | 'mb'
47
- | 'ml'
48
- | 'mx'
49
- | 'my'
50
- | 'p'
51
- | 'pt'
52
- | 'pr'
53
- | 'pb'
54
- | 'pl'
55
- | 'px'
56
- | 'py'
57
- | 'className'
58
- | 'component'
59
- > &
60
- ( MultipleButtonsProps | SingleButtonProps | OnlyTextProps );
41
+ export type TermsOfServiceProps = {
42
+ /**
43
+ * HTML class.
44
+ */
45
+ className?: string;
46
+
47
+ /**
48
+ * The `@wordpress/ui` Text variant. Defaults to `body-lg`.
49
+ */
50
+ variant?: ComponentProps< typeof Text >[ 'variant' ];
51
+ } & ( MultipleButtonsProps | SingleButtonProps | OnlyTextProps );
package/index.ts CHANGED
@@ -32,6 +32,7 @@ export { default as PricingCard } from './components/pricing-card/index.tsx';
32
32
  export { default as AdminSection } from './components/admin-section/basic/index.tsx';
33
33
  export { default as AdminSectionHero } from './components/admin-section/hero/index.tsx';
34
34
  export { default as AdminPage } from './components/admin-page/index.tsx';
35
+ export { default as PageActionButton } from './components/admin-page/page-action-button.tsx';
35
36
  export { default as DecorativeCard } from './components/decorative-card/index.tsx';
36
37
  export { default as Col } from './components/layout/col/index.tsx';
37
38
  export { default as Testimonials } from './components/testimonials/index.tsx';
@@ -41,7 +42,6 @@ export { default as JitmSlot } from './components/jitm-slot/index.tsx';
41
42
  export * from './components/icons/index.tsx';
42
43
  export { default as ThemeProvider } from './components/theme-provider/index.tsx';
43
44
  export { default as Text, H2, H3, Title } from './components/text/index.tsx';
44
- export { default as NumberControl } from './components/number-control/index.tsx';
45
45
  export { default as QRCode } from './components/qr-code/index.tsx';
46
46
  export { default as Button } from './components/button/index.tsx';
47
47
  export type { ButtonProps } from './components/button/types.ts';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/jetpack-components",
3
- "version": "5.0.1",
3
+ "version": "6.0.0",
4
4
  "description": "Jetpack Components Package",
5
5
  "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/components/#readme",
6
6
  "bugs": {
@@ -46,6 +46,11 @@
46
46
  "types": "./build/components/jetpack-footer/index.d.ts",
47
47
  "default": "./build/components/jetpack-footer/index.js"
48
48
  },
49
+ "./jetpack-footer/style.scss": "./build/components/jetpack-footer/style.scss",
50
+ "./jetpack-footer/unstyled": {
51
+ "types": "./build/components/jetpack-footer/jetpack-footer.d.ts",
52
+ "default": "./build/components/jetpack-footer/jetpack-footer.js"
53
+ },
49
54
  "./jetpack-logo": {
50
55
  "types": "./build/components/jetpack-logo/index.d.ts",
51
56
  "default": "./build/components/jetpack-logo/index.js"
@@ -81,7 +86,7 @@
81
86
  ],
82
87
  "dependencies": {
83
88
  "@automattic/jetpack-api": "^2.2.3",
84
- "@automattic/jetpack-boost-score-api": "^1.2.3",
89
+ "@automattic/jetpack-boost-score-api": "^1.3.0",
85
90
  "@automattic/jetpack-script-data": "^0.6.11",
86
91
  "@automattic/number-formatters": "^1.2.12",
87
92
  "@babel/runtime": "^7",
@@ -104,7 +109,7 @@
104
109
  "js-sha256": "0.11.1",
105
110
  "prop-types": "^15.7.2",
106
111
  "qrcode.react": "4.2.0",
107
- "social-logos": "^3.4.1",
112
+ "social-logos": "^3.4.2",
108
113
  "uplot": "1.6.31",
109
114
  "uplot-react": "1.1.4"
110
115
  },
@@ -112,27 +117,27 @@
112
117
  "@automattic/jetpack-base-styles": "^1.2.19",
113
118
  "@babel/core": "7.29.7",
114
119
  "@jest/globals": "30.5.2",
115
- "@storybook/addon-docs": "10.4.6",
116
- "@storybook/react": "10.4.6",
120
+ "@storybook/addon-docs": "10.6.3",
121
+ "@storybook/react": "10.6.3",
117
122
  "@testing-library/dom": "10.4.2",
118
123
  "@testing-library/react": "16.3.3",
119
124
  "@testing-library/user-event": "14.6.8",
120
125
  "@types/jest": "30.0.0",
121
- "@types/react": "18.3.31",
122
- "@types/react-dom": "18.3.7",
126
+ "@types/react": "19.3.0",
127
+ "@types/react-dom": "19.3.0",
123
128
  "@typescript/native-preview": "7.0.0-dev.20260707.2",
124
129
  "jest": "30.5.2",
125
- "react": "18.3.1",
126
- "react-dom": "18.3.1",
130
+ "react": "19.3.0",
131
+ "react-dom": "19.3.0",
127
132
  "require-from-string": "2.0.2",
128
- "storybook": "10.4.6",
133
+ "storybook": "10.6.3",
129
134
  "ts-dedent": "2.2.0",
130
135
  "typescript": "6.0.3",
131
136
  "webpack": "5.111.1",
132
137
  "webpack-cli": "7.2.1"
133
138
  },
134
139
  "peerDependencies": {
135
- "react": "^18.0.0",
136
- "react-dom": "^18.0.0"
140
+ "react": "^18.0.0 || ^19.0.0",
141
+ "react-dom": "^18.0.0 || ^19.0.0"
137
142
  }
138
143
  }
@@ -1,28 +0,0 @@
1
- import type { ComponentType, InputHTMLAttributes, ReactNode } from 'react';
2
- export type NumberControlProps = {
3
- /**
4
- * Matches common `@wordpress/components` control props without importing their internal types.
5
- */
6
- label?: ReactNode;
7
- help?: ReactNode;
8
- className?: string;
9
- hideLabelFromVision?: boolean;
10
- __nextHasNoMarginBottom?: boolean;
11
- /**
12
- * TextControl-style signature. (The experimental NumberControl can accept this too.)
13
- */
14
- onChange: (value: string) => void;
15
- value: string | number;
16
- __next40pxDefaultSize?: boolean;
17
- } & Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value' | 'className' | 'type' | 'children'>;
18
- /**
19
- * This uses the experimental NumberControl from the block
20
- * editor where available, otherwise it falls back to a
21
- * standard TextControl, limited to numbers.
22
- * @type {ComponentType<NumberControlProps>}
23
- *
24
- * @param {NumberControlProps} props - the NumberControl component props
25
- * @return {ReactNode} - NumberControl component
26
- */
27
- declare const NumberControl: ComponentType<NumberControlProps>;
28
- export default NumberControl;
@@ -1,17 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { __experimentalNumberControl as ExperimentalNumberControl, // eslint-disable-line @wordpress/no-unsafe-wp-apis
3
- TextControl, } from '@wordpress/components';
4
- /**
5
- * This uses the experimental NumberControl from the block
6
- * editor where available, otherwise it falls back to a
7
- * standard TextControl, limited to numbers.
8
- * @type {ComponentType<NumberControlProps>}
9
- *
10
- * @param {NumberControlProps} props - the NumberControl component props
11
- * @return {ReactNode} - NumberControl component
12
- */
13
- const NumberControl = ExperimentalNumberControl ||
14
- function CustomNumberControl(props) {
15
- return (_jsx(TextControl, { type: "number", inputMode: "numeric", ...props, __next40pxDefaultSize: true }));
16
- };
17
- export default NumberControl;
@@ -1,45 +0,0 @@
1
- import {
2
- __experimentalNumberControl as ExperimentalNumberControl, // eslint-disable-line @wordpress/no-unsafe-wp-apis
3
- TextControl,
4
- } from '@wordpress/components';
5
- import type { ComponentType, InputHTMLAttributes, ReactNode } from 'react';
6
-
7
- export type NumberControlProps = {
8
- /**
9
- * Matches common `@wordpress/components` control props without importing their internal types.
10
- */
11
- label?: ReactNode;
12
- help?: ReactNode;
13
- className?: string;
14
- hideLabelFromVision?: boolean;
15
- __nextHasNoMarginBottom?: boolean;
16
-
17
- /**
18
- * TextControl-style signature. (The experimental NumberControl can accept this too.)
19
- */
20
- onChange: ( value: string ) => void;
21
- value: string | number;
22
- __next40pxDefaultSize?: boolean;
23
- } & Omit<
24
- InputHTMLAttributes< HTMLInputElement >,
25
- 'onChange' | 'value' | 'className' | 'type' | 'children'
26
- >;
27
-
28
- /**
29
- * This uses the experimental NumberControl from the block
30
- * editor where available, otherwise it falls back to a
31
- * standard TextControl, limited to numbers.
32
- * @type {ComponentType<NumberControlProps>}
33
- *
34
- * @param {NumberControlProps} props - the NumberControl component props
35
- * @return {ReactNode} - NumberControl component
36
- */
37
- const NumberControl: ComponentType< NumberControlProps > =
38
- ( ExperimentalNumberControl as unknown as ComponentType< NumberControlProps > | undefined ) ||
39
- function CustomNumberControl( props: NumberControlProps ) {
40
- return (
41
- <TextControl type="number" inputMode="numeric" { ...props } __next40pxDefaultSize={ true } />
42
- );
43
- };
44
-
45
- export default NumberControl;