@automattic/jetpack-components 6.1.1 → 6.2.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 CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ### This is a list detailing changes for the Jetpack RNA Components package releases.
4
4
 
5
+ ## [6.2.0] - 2026-11-04
6
+ ### Added
7
+ - Add a SidebarFooter component for actions pinned to the bottom of a sidebar. [#54229]
8
+
9
+ ### Changed
10
+ - Gravatar Hovercards: Update @gravatar-com/hovercards to 0.17.0, which adds defensive escaping of Gravatar profile data. [#54379]
11
+ - StatCard: Use the design system tooltip. [#54512]
12
+ - Update package dependencies. [#54512]
13
+
14
+ ### Fixed
15
+ - JetpackFooter: Keep the footer styles in production builds. [#54512]
16
+
5
17
  ## [6.1.1] - 2026-11-02
6
18
  ### Changed
7
19
  - Update package dependencies. [#53869]
@@ -2051,6 +2063,7 @@
2051
2063
  ### Changed
2052
2064
  - Update node version requirement to 14.16.1
2053
2065
 
2066
+ [6.2.0]: https://github.com/Automattic/jetpack-components/compare/6.1.1...6.2.0
2054
2067
  [6.1.1]: https://github.com/Automattic/jetpack-components/compare/6.1.0...6.1.1
2055
2068
  [6.1.0]: https://github.com/Automattic/jetpack-components/compare/6.0.0...6.1.0
2056
2069
  [6.0.0]: https://github.com/Automattic/jetpack-components/compare/5.0.1...6.0.0
@@ -1,2 +1,5 @@
1
1
  import './style.scss';
2
- export { default } from './jetpack-footer.tsx';
2
+ import type { JetpackFooterProps } from './types.ts';
3
+ import type { FC } from 'react';
4
+ declare const JetpackFooter: FC<JetpackFooterProps>;
5
+ export default JetpackFooter;
@@ -1,2 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
1
2
  import './style.scss';
2
- export { default } from './jetpack-footer.js';
3
+ import UnstyledJetpackFooter from './jetpack-footer.js';
4
+ // A pure re-export would let bundlers that honour `sideEffects` drop the style import above.
5
+ const JetpackFooter = props => _jsx(UnstyledJetpackFooter, { ...props });
6
+ export default JetpackFooter;
@@ -9,10 +9,10 @@ declare global {
9
9
  }
10
10
  }
11
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.
12
+ * UnstyledJetpackFooter displays a tiny Jetpack logo with the product name on the left and the Automattic Airline "by line" on the right, without loading its stylesheet.
13
13
  *
14
14
  * @param {JetpackFooterProps} props - Component properties.
15
- * @return {ReactNode} JetpackFooter component.
15
+ * @return {ReactNode} UnstyledJetpackFooter component.
16
16
  */
17
- declare const JetpackFooter: FC<JetpackFooterProps>;
18
- export default JetpackFooter;
17
+ declare const UnstyledJetpackFooter: FC<JetpackFooterProps>;
18
+ export default UnstyledJetpackFooter;
@@ -7,12 +7,12 @@ import getRedirectUrl from '../../tools/jp-redirect/index.js';
7
7
  import AutomatticBylineLogo from '../automattic-byline-logo/index.js';
8
8
  import JetpackLogo from '../jetpack-logo/index.js';
9
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.
10
+ * UnstyledJetpackFooter displays a tiny Jetpack logo with the product name on the left and the Automattic Airline "by line" on the right, without loading its stylesheet.
11
11
  *
12
12
  * @param {JetpackFooterProps} props - Component properties.
13
- * @return {ReactNode} JetpackFooter component.
13
+ * @return {ReactNode} UnstyledJetpackFooter component.
14
14
  */
15
- const JetpackFooter = ({ className, menu, ...otherProps }) => {
15
+ const UnstyledJetpackFooter = ({ className, menu, ...otherProps }) => {
16
16
  let items = [];
17
17
  if (getScriptData()?.myJetpack?.isAvailable === true &&
18
18
  !isWpcomPlatformSite() &&
@@ -36,4 +36,4 @@ const JetpackFooter = ({ className, menu, ...otherProps }) => {
36
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
37
  }) }), _jsx("a", { className: "jetpack-footer__a8c", href: getRedirectUrl('a8c-about'), rel: "noopener noreferrer", target: "_blank", children: _jsx(AutomatticBylineLogo, { height: 8 }) })] }));
38
38
  };
39
- export default JetpackFooter;
39
+ export default UnstyledJetpackFooter;
@@ -0,0 +1,12 @@
1
+ import type { SidebarFooterProps } from './types.ts';
2
+ import type { JSX } from 'react';
3
+ /**
4
+ * Actions pinned to the bottom of a sidebar, with the content scrolling under them.
5
+ *
6
+ * Render it last inside a flex column that fills the sidebar. Use `@wordpress/ui` buttons at
7
+ * their default size, which is 40px tall.
8
+ *
9
+ * @param {SidebarFooterProps} props - Component props.
10
+ * @return {JSX.Element} The footer.
11
+ */
12
+ export default function SidebarFooter({ children, description, className, }: SidebarFooterProps): JSX.Element;
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import clsx from 'clsx';
3
+ import styles from './style.module.scss';
4
+ /**
5
+ * Actions pinned to the bottom of a sidebar, with the content scrolling under them.
6
+ *
7
+ * Render it last inside a flex column that fills the sidebar. Use `@wordpress/ui` buttons at
8
+ * their default size, which is 40px tall.
9
+ *
10
+ * @param {SidebarFooterProps} props - Component props.
11
+ * @return {JSX.Element} The footer.
12
+ */
13
+ export default function SidebarFooter({ children, description, className, }) {
14
+ return (_jsxs("div", { className: clsx(styles.footer, className), children: [description, _jsx("div", { className: styles.actions, children: children })] }));
15
+ }
@@ -0,0 +1,24 @@
1
+ .footer {
2
+ position: sticky;
3
+ inset-block-end: 0;
4
+ // Above positioned content scrolling under it, such as the hidden checkbox
5
+ // of wp-components toggles before 33.0, which would take the footer's clicks.
6
+ z-index: 1;
7
+ display: flex;
8
+ flex-direction: column;
9
+ gap: var(--wpds-dimension-gap-md);
10
+ margin-block-start: auto;
11
+ // Matches the admin-ui Page title bar, lining the actions up with the content.
12
+ padding: var(--wpds-dimension-padding-lg) var(--wpds-dimension-padding-2xl);
13
+ border-block-start:
14
+ var(--wpds-border-width-xs) solid
15
+ var(--wpds-color-stroke-surface-neutral);
16
+ background: var(--wpds-color-background-surface-neutral);
17
+ }
18
+
19
+ .actions {
20
+ display: grid;
21
+ grid-auto-columns: minmax(0, 1fr);
22
+ grid-auto-flow: column;
23
+ gap: var(--wpds-dimension-gap-sm);
24
+ }
@@ -0,0 +1,15 @@
1
+ import type { ReactNode } from 'react';
2
+ export type SidebarFooterProps = {
3
+ /**
4
+ * The actions, usually one or two buttons. Each gets an equal-width column and fills it.
5
+ */
6
+ children: ReactNode;
7
+ /**
8
+ * Shown above the actions, such as a note on what an action is doing.
9
+ */
10
+ description?: ReactNode;
11
+ /**
12
+ * Extra class name for the footer.
13
+ */
14
+ className?: string;
15
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  * External dependencies
4
4
  */
5
5
  import { formatNumber, formatNumberCompact } from '@automattic/number-formatters';
6
- import { Tooltip } from '@wordpress/components';
6
+ import { Tooltip } from '@wordpress/ui';
7
7
  import clsx from 'clsx';
8
8
  /**
9
9
  * Internal dependencies
@@ -19,6 +19,6 @@ import styles from './style.module.scss';
19
19
  const StatCard = ({ className, hideValue, icon, label, value, variant = 'square', }) => {
20
20
  const formattedValue = formatNumber(value);
21
21
  const compactValue = formatNumberCompact(value);
22
- return (_jsxs("div", { className: clsx(className, styles.wrapper, styles[variant]), children: [_jsx("div", { className: clsx(styles.icon), children: icon }), _jsxs("div", { className: clsx(styles.info), children: [_jsx(Text, { className: styles.label, children: label }), variant === 'square' ? (_jsx(Tooltip, { text: formattedValue, placement: "top", children: _jsx(Text, { variant: "headline-small", className: clsx(styles.value), children: hideValue ? '-' : compactValue }) })) : (_jsx(Text, { variant: "title-medium-semi-bold", className: clsx(styles.value), children: hideValue ? '-' : formattedValue }))] })] }));
22
+ return (_jsxs("div", { className: clsx(className, styles.wrapper, styles[variant]), children: [_jsx("div", { className: clsx(styles.icon), children: icon }), _jsxs("div", { className: clsx(styles.info), children: [_jsx(Text, { className: styles.label, children: label }), variant === 'square' ? (_jsxs(Tooltip.Root, { children: [_jsx(Tooltip.Trigger, { render: _jsx(Text, { variant: "headline-small", className: clsx(styles.value), children: hideValue ? '-' : compactValue }) }), _jsx(Tooltip.Popup, { children: formattedValue })] })) : (_jsx(Text, { variant: "title-medium-semi-bold", className: clsx(styles.value), children: hideValue ? '-' : formattedValue }))] })] }));
23
23
  };
24
24
  export default StatCard;
package/build/index.d.ts CHANGED
@@ -52,5 +52,7 @@ export type { PeriodPreset, PeriodSelectorProps } from './components/period-sele
52
52
  export { default as DiffViewer } from './components/diff-viewer/index.tsx';
53
53
  export { default as MarkedLines } from './components/marked-lines/index.tsx';
54
54
  export { default as DetailsViewer } from './components/details-viewer/index.tsx';
55
+ export { default as SidebarFooter } from './components/sidebar-footer/index.tsx';
56
+ export type { SidebarFooterProps } from './components/sidebar-footer/types.ts';
55
57
  export * from './components/global-notices/index.ts';
56
58
  export * from './components/navigator-modal/index.tsx';
package/build/index.js CHANGED
@@ -61,5 +61,6 @@ export { default as PeriodSelector } from './components/period-selector/index.js
61
61
  export { default as DiffViewer } from './components/diff-viewer/index.js';
62
62
  export { default as MarkedLines } from './components/marked-lines/index.js';
63
63
  export { default as DetailsViewer } from './components/details-viewer/index.js';
64
+ export { default as SidebarFooter } from './components/sidebar-footer/index.js';
64
65
  export * from './components/global-notices/index.js';
65
66
  export * from './components/navigator-modal/index.js';
@@ -1,3 +1,9 @@
1
1
  import './style.scss';
2
+ import UnstyledJetpackFooter from './jetpack-footer.tsx';
3
+ import type { JetpackFooterProps } from './types.ts';
4
+ import type { FC } from 'react';
2
5
 
3
- export { default } from './jetpack-footer.tsx';
6
+ // A pure re-export would let bundlers that honour `sideEffects` drop the style import above.
7
+ const JetpackFooter: FC< JetpackFooterProps > = props => <UnstyledJetpackFooter { ...props } />;
8
+
9
+ export default JetpackFooter;
@@ -18,12 +18,12 @@ declare global {
18
18
  }
19
19
 
20
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.
21
+ * UnstyledJetpackFooter displays a tiny Jetpack logo with the product name on the left and the Automattic Airline "by line" on the right, without loading its stylesheet.
22
22
  *
23
23
  * @param {JetpackFooterProps} props - Component properties.
24
- * @return {ReactNode} JetpackFooter component.
24
+ * @return {ReactNode} UnstyledJetpackFooter component.
25
25
  */
26
- const JetpackFooter: FC< JetpackFooterProps > = ( { className, menu, ...otherProps } ) => {
26
+ const UnstyledJetpackFooter: FC< JetpackFooterProps > = ( { className, menu, ...otherProps } ) => {
27
27
  let items: JetpackFooterMenuItem[] = [];
28
28
 
29
29
  if (
@@ -110,4 +110,4 @@ const JetpackFooter: FC< JetpackFooterProps > = ( { className, menu, ...otherPro
110
110
  );
111
111
  };
112
112
 
113
- export default JetpackFooter;
113
+ export default UnstyledJetpackFooter;
@@ -0,0 +1,26 @@
1
+ import clsx from 'clsx';
2
+ import styles from './style.module.scss';
3
+ import type { SidebarFooterProps } from './types.ts';
4
+ import type { JSX } from 'react';
5
+
6
+ /**
7
+ * Actions pinned to the bottom of a sidebar, with the content scrolling under them.
8
+ *
9
+ * Render it last inside a flex column that fills the sidebar. Use `@wordpress/ui` buttons at
10
+ * their default size, which is 40px tall.
11
+ *
12
+ * @param {SidebarFooterProps} props - Component props.
13
+ * @return {JSX.Element} The footer.
14
+ */
15
+ export default function SidebarFooter( {
16
+ children,
17
+ description,
18
+ className,
19
+ }: SidebarFooterProps ): JSX.Element {
20
+ return (
21
+ <div className={ clsx( styles.footer, className ) }>
22
+ { description }
23
+ <div className={ styles.actions }>{ children }</div>
24
+ </div>
25
+ );
26
+ }
@@ -0,0 +1,24 @@
1
+ .footer {
2
+ position: sticky;
3
+ inset-block-end: 0;
4
+ // Above positioned content scrolling under it, such as the hidden checkbox
5
+ // of wp-components toggles before 33.0, which would take the footer's clicks.
6
+ z-index: 1;
7
+ display: flex;
8
+ flex-direction: column;
9
+ gap: var(--wpds-dimension-gap-md);
10
+ margin-block-start: auto;
11
+ // Matches the admin-ui Page title bar, lining the actions up with the content.
12
+ padding: var(--wpds-dimension-padding-lg) var(--wpds-dimension-padding-2xl);
13
+ border-block-start:
14
+ var(--wpds-border-width-xs) solid
15
+ var(--wpds-color-stroke-surface-neutral);
16
+ background: var(--wpds-color-background-surface-neutral);
17
+ }
18
+
19
+ .actions {
20
+ display: grid;
21
+ grid-auto-columns: minmax(0, 1fr);
22
+ grid-auto-flow: column;
23
+ gap: var(--wpds-dimension-gap-sm);
24
+ }
@@ -0,0 +1,16 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export type SidebarFooterProps = {
4
+ /**
5
+ * The actions, usually one or two buttons. Each gets an equal-width column and fills it.
6
+ */
7
+ children: ReactNode;
8
+ /**
9
+ * Shown above the actions, such as a note on what an action is doing.
10
+ */
11
+ description?: ReactNode;
12
+ /**
13
+ * Extra class name for the footer.
14
+ */
15
+ className?: string;
16
+ };
@@ -2,7 +2,7 @@
2
2
  * External dependencies
3
3
  */
4
4
  import { formatNumber, formatNumberCompact } from '@automattic/number-formatters';
5
- import { Tooltip } from '@wordpress/components';
5
+ import { Tooltip } from '@wordpress/ui';
6
6
  import clsx from 'clsx';
7
7
  /**
8
8
  * Internal dependencies
@@ -35,11 +35,16 @@ const StatCard = ( {
35
35
  <div className={ clsx( styles.info ) }>
36
36
  <Text className={ styles.label }>{ label }</Text>
37
37
  { variant === 'square' ? (
38
- <Tooltip text={ formattedValue } placement="top">
39
- <Text variant="headline-small" className={ clsx( styles.value ) }>
40
- { hideValue ? '-' : compactValue }
41
- </Text>
42
- </Tooltip>
38
+ <Tooltip.Root>
39
+ <Tooltip.Trigger
40
+ render={
41
+ <Text variant="headline-small" className={ clsx( styles.value ) }>
42
+ { hideValue ? '-' : compactValue }
43
+ </Text>
44
+ }
45
+ />
46
+ <Tooltip.Popup>{ formattedValue }</Tooltip.Popup>
47
+ </Tooltip.Root>
43
48
  ) : (
44
49
  <Text variant="title-medium-semi-bold" className={ clsx( styles.value ) }>
45
50
  { hideValue ? '-' : formattedValue }
package/index.ts CHANGED
@@ -72,5 +72,7 @@ export type { PeriodPreset, PeriodSelectorProps } from './components/period-sele
72
72
  export { default as DiffViewer } from './components/diff-viewer/index.tsx';
73
73
  export { default as MarkedLines } from './components/marked-lines/index.tsx';
74
74
  export { default as DetailsViewer } from './components/details-viewer/index.tsx';
75
+ export { default as SidebarFooter } from './components/sidebar-footer/index.tsx';
76
+ export type { SidebarFooterProps } from './components/sidebar-footer/types.ts';
75
77
  export * from './components/global-notices/index.ts';
76
78
  export * from './components/navigator-modal/index.tsx';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/jetpack-components",
3
- "version": "6.1.1",
3
+ "version": "6.2.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": {
@@ -71,6 +71,10 @@
71
71
  "types": "./build/components/radio-card/index.d.ts",
72
72
  "default": "./build/components/radio-card/index.js"
73
73
  },
74
+ "./sidebar-footer": {
75
+ "types": "./build/components/sidebar-footer/index.d.ts",
76
+ "default": "./build/components/sidebar-footer/index.js"
77
+ },
74
78
  "./tools/jp-redirect": {
75
79
  "types": "./build/tools/jp-redirect/index.d.ts",
76
80
  "default": "./build/tools/jp-redirect/index.js"
@@ -89,26 +93,26 @@
89
93
  "extends @wordpress/browserslist-config"
90
94
  ],
91
95
  "dependencies": {
92
- "@automattic/jetpack-api": "^2.2.4",
93
- "@automattic/jetpack-boost-score-api": "^1.3.1",
96
+ "@automattic/jetpack-api": "^2.2.5",
97
+ "@automattic/jetpack-boost-score-api": "^1.3.2",
94
98
  "@automattic/jetpack-script-data": "^0.6.12",
95
99
  "@automattic/number-formatters": "^1.3.0",
96
100
  "@babel/runtime": "^7",
97
- "@gravatar-com/hovercards": "0.16.0",
98
- "@wordpress/a11y": "5.0.0",
99
- "@wordpress/admin-ui": "3.0.0",
100
- "@wordpress/browserslist-config": "7.0.0",
101
- "@wordpress/components": "43.0.0",
102
- "@wordpress/compose": "9.0.0",
103
- "@wordpress/data": "11.0.0",
104
- "@wordpress/date": "6.0.0",
105
- "@wordpress/dom": "5.0.0",
106
- "@wordpress/element": "10.0.0",
107
- "@wordpress/i18n": "7.0.0",
108
- "@wordpress/icons": "19.0.0",
109
- "@wordpress/notices": "6.0.0",
110
- "@wordpress/theme": "3.0.0",
111
- "@wordpress/ui": "0.25.0",
101
+ "@gravatar-com/hovercards": "0.17.0",
102
+ "@wordpress/a11y": "5.1.0",
103
+ "@wordpress/admin-ui": "3.1.0",
104
+ "@wordpress/browserslist-config": "7.1.0",
105
+ "@wordpress/components": "44.0.0",
106
+ "@wordpress/compose": "9.1.0",
107
+ "@wordpress/data": "11.1.0",
108
+ "@wordpress/date": "6.1.0",
109
+ "@wordpress/dom": "5.1.0",
110
+ "@wordpress/element": "10.1.0",
111
+ "@wordpress/i18n": "7.1.0",
112
+ "@wordpress/icons": "20.0.0",
113
+ "@wordpress/notices": "6.1.0",
114
+ "@wordpress/theme": "4.0.0",
115
+ "@wordpress/ui": "0.26.0",
112
116
  "clsx": "2.1.1",
113
117
  "js-sha256": "0.11.1",
114
118
  "prop-types": "^15.7.2",
@@ -130,7 +134,7 @@
130
134
  "@types/react": "19.3.0",
131
135
  "@types/react-dom": "19.3.0",
132
136
  "@typescript/native-preview": "7.0.0-dev.20260707.2",
133
- "@wordpress/base-styles": "14.0.0",
137
+ "@wordpress/base-styles": "15.0.0",
134
138
  "jest": "30.5.2",
135
139
  "react": "19.3.0",
136
140
  "react-dom": "19.3.0",