@automattic/jetpack-components 6.1.0 → 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.
Files changed (33) hide show
  1. package/CHANGELOG.md +19 -2
  2. package/build/components/dot-pager/style.scss +2 -2
  3. package/build/components/global-notices/styles.module.scss +3 -3
  4. package/build/components/icons/style.module.scss +2 -2
  5. package/build/components/jetpack-footer/index.d.ts +4 -1
  6. package/build/components/jetpack-footer/index.js +5 -1
  7. package/build/components/jetpack-footer/jetpack-footer.d.ts +4 -4
  8. package/build/components/jetpack-footer/jetpack-footer.js +4 -4
  9. package/build/components/navigator-modal/styles.scss +11 -9
  10. package/build/components/selectable-card/_selectable-card.scss +2 -2
  11. package/build/components/sidebar-footer/index.d.ts +12 -0
  12. package/build/components/sidebar-footer/index.js +15 -0
  13. package/build/components/sidebar-footer/style.module.scss +24 -0
  14. package/build/components/sidebar-footer/types.d.ts +15 -0
  15. package/build/components/sidebar-footer/types.js +1 -0
  16. package/build/components/stat-card/index.js +2 -2
  17. package/build/components/swipeable/style.scss +2 -2
  18. package/build/index.d.ts +2 -0
  19. package/build/index.js +1 -0
  20. package/components/dot-pager/style.scss +2 -2
  21. package/components/global-notices/styles.module.scss +3 -3
  22. package/components/icons/style.module.scss +2 -2
  23. package/components/jetpack-footer/index.tsx +7 -1
  24. package/components/jetpack-footer/jetpack-footer.tsx +4 -4
  25. package/components/navigator-modal/styles.scss +11 -9
  26. package/components/selectable-card/_selectable-card.scss +2 -2
  27. package/components/sidebar-footer/index.tsx +26 -0
  28. package/components/sidebar-footer/style.module.scss +24 -0
  29. package/components/sidebar-footer/types.ts +16 -0
  30. package/components/stat-card/index.tsx +11 -6
  31. package/components/swipeable/style.scss +2 -2
  32. package/index.ts +2 -0
  33. package/package.json +27 -22
package/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
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
+
17
+ ## [6.1.1] - 2026-11-02
18
+ ### Changed
19
+ - Update package dependencies. [#53869]
20
+
5
21
  ## [6.1.0] - 2026-10-28
6
22
  ### Added
7
23
  - Add a PeriodSelector component: a dropdown of period presets with optional previous and next buttons. [#54149]
@@ -259,8 +275,7 @@
259
275
  ## [1.11.3] - 2026-05-21
260
276
  ### Changed
261
277
  - Mark ContextualUpgradeTrigger as @deprecated. Use Notice from @wordpress/ui instead. The implementation is unchanged. [#48909]
262
- - Update package dependencies. [#48405]
263
- - Update package dependencies. [#49012]
278
+ - Update package dependencies. [#48405] [#49012]
264
279
 
265
280
  ## [1.11.2] - 2026-05-19
266
281
  ### Changed
@@ -2048,6 +2063,8 @@
2048
2063
  ### Changed
2049
2064
  - Update node version requirement to 14.16.1
2050
2065
 
2066
+ [6.2.0]: https://github.com/Automattic/jetpack-components/compare/6.1.1...6.2.0
2067
+ [6.1.1]: https://github.com/Automattic/jetpack-components/compare/6.1.0...6.1.1
2051
2068
  [6.1.0]: https://github.com/Automattic/jetpack-components/compare/6.0.0...6.1.0
2052
2069
  [6.0.0]: https://github.com/Automattic/jetpack-components/compare/5.0.1...6.0.0
2053
2070
  [5.0.1]: https://github.com/Automattic/jetpack-components/compare/5.0.0...5.0.1
@@ -1,4 +1,4 @@
1
- @use "@automattic/jetpack-base-styles/gutenberg-base-styles" as gb;
1
+ @use "@wordpress/base-styles/mixins";
2
2
  @use "@automattic/jetpack-base-styles/root-variables";
3
3
 
4
4
  .dot-pager {
@@ -13,7 +13,7 @@
13
13
  opacity: 1;
14
14
  visibility: visible;
15
15
 
16
- @include gb.reduce-motion( "transition" );
16
+ @include mixins.reduce-motion( "transition" );
17
17
  }
18
18
 
19
19
  .dot-pager__controls {
@@ -1,4 +1,4 @@
1
- @use "@automattic/jetpack-base-styles/gutenberg-base-styles" as gb;
1
+ @use "@wordpress/base-styles/mixins";
2
2
 
3
3
  .global-notices {
4
4
 
@@ -10,14 +10,14 @@
10
10
  // Modals have 100000, so this needs to be above them
11
11
  z-index: 100001;
12
12
 
13
- @include gb.break-small {
13
+ @include mixins.break-small {
14
14
  width: auto;
15
15
  inset-inline: unset; // left and right
16
16
  inset-block-start: 4rem;
17
17
  inset-inline-end: 1rem;
18
18
  }
19
19
 
20
- @include gb.break-medium {
20
+ @include mixins.break-medium {
21
21
  inset-block-start: 3rem;
22
22
  }
23
23
  }
@@ -1,4 +1,4 @@
1
- @use "@automattic/jetpack-base-styles/gutenberg-base-styles" as gb;
1
+ @use "@wordpress/base-styles/colors";
2
2
 
3
3
  .star-icon {
4
4
  fill: #000;
@@ -10,7 +10,7 @@
10
10
  }
11
11
 
12
12
  .socialIcon {
13
- fill: gb.$gray-700;
13
+ fill: colors.$gray-700;
14
14
 
15
15
  &.bluesky {
16
16
  fill: var(--jetpack-social-logo-color-bluesky);
@@ -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;
@@ -1,4 +1,6 @@
1
- @use "@automattic/jetpack-base-styles/gutenberg-base-styles" as gb;
1
+ @use "@wordpress/base-styles/breakpoints";
2
+ @use "@wordpress/base-styles/colors";
3
+ @use "@wordpress/base-styles/mixins";
2
4
 
3
5
  .components-modal__screen-overlay:has(.jp-navigator-modal) {
4
6
  z-index: 99999; // Slightly lower than snackbar z-index (100001) so snackbars remain visible above the modal
@@ -9,7 +11,7 @@
9
11
  container-name: navigator-modal;
10
12
  width: 100%;
11
13
 
12
- @include gb.break-medium() {
14
+ @include mixins.break-medium() {
13
15
  max-height: 90%;
14
16
  }
15
17
 
@@ -37,7 +39,7 @@
37
39
  justify-content: space-between;
38
40
  padding: 1.5rem;
39
41
  height: 4.5rem;
40
- border-bottom: 1px solid gb.$gray-200;
42
+ border-bottom: 1px solid colors.$gray-200;
41
43
  flex-shrink: 0;
42
44
 
43
45
  h1 {
@@ -45,7 +47,7 @@
45
47
  font-size: 15px;
46
48
  font-weight: 500;
47
49
  line-height: 24px;
48
- color: gb.$gray-900;
50
+ color: colors.$gray-900;
49
51
  }
50
52
  }
51
53
 
@@ -60,7 +62,7 @@
60
62
  overflow: auto;
61
63
  flex-direction: column;
62
64
 
63
- @container navigator-modal (width >= #{gb.$break-small}) {
65
+ @container navigator-modal (width >= #{breakpoints.$break-small}) {
64
66
  flex-direction: row;
65
67
  }
66
68
  }
@@ -71,11 +73,11 @@
71
73
  flex-direction: column;
72
74
  gap: 1.5rem;
73
75
 
74
- @container navigator-modal (width >= #{gb.$break-small}) {
76
+ @container navigator-modal (width >= #{breakpoints.$break-small}) {
75
77
  flex-basis: 30%;
76
78
  height: 100%;
77
79
  flex-shrink: 0;
78
- border-inline-end: 1px solid gb.$gray-300;
80
+ border-inline-end: 1px solid colors.$gray-300;
79
81
  overflow: auto;
80
82
  }
81
83
  }
@@ -85,14 +87,14 @@
85
87
  height: 100%;
86
88
  flex: 1;
87
89
 
88
- @container navigator-modal (width >= #{gb.$break-small}) {
90
+ @container navigator-modal (width >= #{breakpoints.$break-small}) {
89
91
  overflow: auto;
90
92
  }
91
93
  }
92
94
 
93
95
  &__footer {
94
96
  padding: 1rem 1.5rem;
95
- border-top: 1px solid gb.$gray-300;
97
+ border-top: 1px solid colors.$gray-300;
96
98
  height: 4.5rem;
97
99
  flex-shrink: 0;
98
100
  }
@@ -1,4 +1,4 @@
1
- @use "@automattic/jetpack-base-styles/gutenberg-base-styles" as gb;
1
+ @use "@wordpress/base-styles/mixins";
2
2
 
3
3
  // Shared by CheckboxCard and RadioCard, which differ only in their control.
4
4
 
@@ -26,7 +26,7 @@
26
26
 
27
27
  &:has(:focus-visible) {
28
28
 
29
- @include gb.outset-ring__focus();
29
+ @include mixins.outset-ring__focus();
30
30
  }
31
31
 
32
32
  @media (prefers-reduced-motion: no-preference) {
@@ -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;
@@ -1,4 +1,4 @@
1
- @use "@automattic/jetpack-base-styles/gutenberg-base-styles" as gb;
1
+ @use "@wordpress/base-styles/mixins";
2
2
 
3
3
  .swipeable__container {
4
4
  width: 100%;
@@ -19,7 +19,7 @@
19
19
  transition: all 0.5s ease-in-out;
20
20
  transition-property: transform, height;
21
21
 
22
- @include gb.reduce-motion( "transition" );
22
+ @include mixins.reduce-motion( "transition" );
23
23
  }
24
24
 
25
25
  .swipeable__page {
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,4 +1,4 @@
1
- @use "@automattic/jetpack-base-styles/gutenberg-base-styles" as gb;
1
+ @use "@wordpress/base-styles/mixins";
2
2
  @use "@automattic/jetpack-base-styles/root-variables";
3
3
 
4
4
  .dot-pager {
@@ -13,7 +13,7 @@
13
13
  opacity: 1;
14
14
  visibility: visible;
15
15
 
16
- @include gb.reduce-motion( "transition" );
16
+ @include mixins.reduce-motion( "transition" );
17
17
  }
18
18
 
19
19
  .dot-pager__controls {
@@ -1,4 +1,4 @@
1
- @use "@automattic/jetpack-base-styles/gutenberg-base-styles" as gb;
1
+ @use "@wordpress/base-styles/mixins";
2
2
 
3
3
  .global-notices {
4
4
 
@@ -10,14 +10,14 @@
10
10
  // Modals have 100000, so this needs to be above them
11
11
  z-index: 100001;
12
12
 
13
- @include gb.break-small {
13
+ @include mixins.break-small {
14
14
  width: auto;
15
15
  inset-inline: unset; // left and right
16
16
  inset-block-start: 4rem;
17
17
  inset-inline-end: 1rem;
18
18
  }
19
19
 
20
- @include gb.break-medium {
20
+ @include mixins.break-medium {
21
21
  inset-block-start: 3rem;
22
22
  }
23
23
  }
@@ -1,4 +1,4 @@
1
- @use "@automattic/jetpack-base-styles/gutenberg-base-styles" as gb;
1
+ @use "@wordpress/base-styles/colors";
2
2
 
3
3
  .star-icon {
4
4
  fill: #000;
@@ -10,7 +10,7 @@
10
10
  }
11
11
 
12
12
  .socialIcon {
13
- fill: gb.$gray-700;
13
+ fill: colors.$gray-700;
14
14
 
15
15
  &.bluesky {
16
16
  fill: var(--jetpack-social-logo-color-bluesky);
@@ -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;
@@ -1,4 +1,6 @@
1
- @use "@automattic/jetpack-base-styles/gutenberg-base-styles" as gb;
1
+ @use "@wordpress/base-styles/breakpoints";
2
+ @use "@wordpress/base-styles/colors";
3
+ @use "@wordpress/base-styles/mixins";
2
4
 
3
5
  .components-modal__screen-overlay:has(.jp-navigator-modal) {
4
6
  z-index: 99999; // Slightly lower than snackbar z-index (100001) so snackbars remain visible above the modal
@@ -9,7 +11,7 @@
9
11
  container-name: navigator-modal;
10
12
  width: 100%;
11
13
 
12
- @include gb.break-medium() {
14
+ @include mixins.break-medium() {
13
15
  max-height: 90%;
14
16
  }
15
17
 
@@ -37,7 +39,7 @@
37
39
  justify-content: space-between;
38
40
  padding: 1.5rem;
39
41
  height: 4.5rem;
40
- border-bottom: 1px solid gb.$gray-200;
42
+ border-bottom: 1px solid colors.$gray-200;
41
43
  flex-shrink: 0;
42
44
 
43
45
  h1 {
@@ -45,7 +47,7 @@
45
47
  font-size: 15px;
46
48
  font-weight: 500;
47
49
  line-height: 24px;
48
- color: gb.$gray-900;
50
+ color: colors.$gray-900;
49
51
  }
50
52
  }
51
53
 
@@ -60,7 +62,7 @@
60
62
  overflow: auto;
61
63
  flex-direction: column;
62
64
 
63
- @container navigator-modal (width >= #{gb.$break-small}) {
65
+ @container navigator-modal (width >= #{breakpoints.$break-small}) {
64
66
  flex-direction: row;
65
67
  }
66
68
  }
@@ -71,11 +73,11 @@
71
73
  flex-direction: column;
72
74
  gap: 1.5rem;
73
75
 
74
- @container navigator-modal (width >= #{gb.$break-small}) {
76
+ @container navigator-modal (width >= #{breakpoints.$break-small}) {
75
77
  flex-basis: 30%;
76
78
  height: 100%;
77
79
  flex-shrink: 0;
78
- border-inline-end: 1px solid gb.$gray-300;
80
+ border-inline-end: 1px solid colors.$gray-300;
79
81
  overflow: auto;
80
82
  }
81
83
  }
@@ -85,14 +87,14 @@
85
87
  height: 100%;
86
88
  flex: 1;
87
89
 
88
- @container navigator-modal (width >= #{gb.$break-small}) {
90
+ @container navigator-modal (width >= #{breakpoints.$break-small}) {
89
91
  overflow: auto;
90
92
  }
91
93
  }
92
94
 
93
95
  &__footer {
94
96
  padding: 1rem 1.5rem;
95
- border-top: 1px solid gb.$gray-300;
97
+ border-top: 1px solid colors.$gray-300;
96
98
  height: 4.5rem;
97
99
  flex-shrink: 0;
98
100
  }
@@ -1,4 +1,4 @@
1
- @use "@automattic/jetpack-base-styles/gutenberg-base-styles" as gb;
1
+ @use "@wordpress/base-styles/mixins";
2
2
 
3
3
  // Shared by CheckboxCard and RadioCard, which differ only in their control.
4
4
 
@@ -26,7 +26,7 @@
26
26
 
27
27
  &:has(:focus-visible) {
28
28
 
29
- @include gb.outset-ring__focus();
29
+ @include mixins.outset-ring__focus();
30
30
  }
31
31
 
32
32
  @media (prefers-reduced-motion: no-preference) {
@@ -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 }
@@ -1,4 +1,4 @@
1
- @use "@automattic/jetpack-base-styles/gutenberg-base-styles" as gb;
1
+ @use "@wordpress/base-styles/mixins";
2
2
 
3
3
  .swipeable__container {
4
4
  width: 100%;
@@ -19,7 +19,7 @@
19
19
  transition: all 0.5s ease-in-out;
20
20
  transition-property: transform, height;
21
21
 
22
- @include gb.reduce-motion( "transition" );
22
+ @include mixins.reduce-motion( "transition" );
23
23
  }
24
24
 
25
25
  .swipeable__page {
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.0",
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,36 +93,36 @@
89
93
  "extends @wordpress/browserslist-config"
90
94
  ],
91
95
  "dependencies": {
92
- "@automattic/jetpack-api": "^2.2.3",
93
- "@automattic/jetpack-boost-score-api": "^1.3.0",
94
- "@automattic/jetpack-script-data": "^0.6.11",
95
- "@automattic/number-formatters": "^1.2.12",
96
+ "@automattic/jetpack-api": "^2.2.5",
97
+ "@automattic/jetpack-boost-score-api": "^1.3.2",
98
+ "@automattic/jetpack-script-data": "^0.6.12",
99
+ "@automattic/number-formatters": "^1.3.0",
96
100
  "@babel/runtime": "^7",
97
- "@gravatar-com/hovercards": "0.16.0",
98
- "@wordpress/a11y": "4.57.0",
99
- "@wordpress/admin-ui": "2.12.0",
100
- "@wordpress/browserslist-config": "6.57.0",
101
- "@wordpress/components": "42.0.0",
102
- "@wordpress/compose": "8.10.0",
103
- "@wordpress/data": "10.57.0",
104
- "@wordpress/date": "5.57.0",
105
- "@wordpress/dom": "4.57.0",
106
- "@wordpress/element": "9.0.0",
107
- "@wordpress/i18n": "6.30.0",
108
- "@wordpress/icons": "18.0.0",
109
- "@wordpress/notices": "5.57.0",
110
- "@wordpress/theme": "2.3.0",
111
- "@wordpress/ui": "0.24.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",
115
119
  "qrcode.react": "4.2.0",
116
- "social-logos": "^3.4.2",
120
+ "social-logos": "^3.4.3",
117
121
  "uplot": "1.6.31",
118
122
  "uplot-react": "1.1.4"
119
123
  },
120
124
  "devDependencies": {
121
- "@automattic/jetpack-base-styles": "^1.2.20",
125
+ "@automattic/jetpack-base-styles": "^2.0.0",
122
126
  "@babel/core": "7.29.7",
123
127
  "@jest/globals": "30.5.2",
124
128
  "@storybook/addon-docs": "10.6.3",
@@ -130,6 +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",
137
+ "@wordpress/base-styles": "15.0.0",
133
138
  "jest": "30.5.2",
134
139
  "react": "19.3.0",
135
140
  "react-dom": "19.3.0",