diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6ee061220b24..3c111105450a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -4077,6 +4077,9 @@ importers:
'@wordpress/server-side-render':
specifier: 6.20.0
version: 6.20.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@wordpress/ui':
+ specifier: 0.11.0
+ version: 0.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@wordpress/url':
specifier: 4.44.0
version: 4.44.0
diff --git a/projects/packages/search/changelog/chore-search-notice-action-wp-ui-link b/projects/packages/search/changelog/chore-search-notice-action-wp-ui-link
new file mode 100644
index 000000000000..1b5ba85ba8c8
--- /dev/null
+++ b/projects/packages/search/changelog/chore-search-notice-action-wp-ui-link
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+Search: migrate dashboard notices to the @wordpress/ui Notice component. Removes the local SimpleNotice and NoticeAction wrappers along with their stylesheets.
diff --git a/projects/packages/search/package.json b/projects/packages/search/package.json
index be4cb14e03f3..7e98456623f1 100644
--- a/projects/packages/search/package.json
+++ b/projects/packages/search/package.json
@@ -59,6 +59,7 @@
"@wordpress/icons": "12.2.0",
"@wordpress/interactivity": "6.44.0",
"@wordpress/server-side-render": "6.20.0",
+ "@wordpress/ui": "0.11.0",
"@wordpress/url": "4.44.0",
"@wordpress/viewport": "6.44.0",
"clsx": "2.1.1",
diff --git a/projects/packages/search/src/dashboard/components/global-notices/index.jsx b/projects/packages/search/src/dashboard/components/global-notices/index.jsx
index a3cdb9560feb..fdef8a4d2bb4 100644
--- a/projects/packages/search/src/dashboard/components/global-notices/index.jsx
+++ b/projects/packages/search/src/dashboard/components/global-notices/index.jsx
@@ -1,8 +1,35 @@
-import SimpleNotice from 'components/notice/index.jsx';
-import NoticeAction from 'components/notice/notice-action';
+import { Notice } from '@wordpress/ui';
+import { useCallback, useEffect } from 'react';
import './style.scss';
+const STATUS_TO_INTENT = {
+ 'is-success': 'success',
+ 'is-error': 'error',
+ 'is-warning': 'warning',
+ 'is-info': 'info',
+};
+
+const NoticeItem = ( { notice, onDismissNotice } ) => {
+ const { id, duration, showDismiss = true, status, text } = notice;
+
+ const handleDismiss = useCallback( () => onDismissNotice( id ), [ onDismissNotice, id ] );
+
+ useEffect( () => {
+ if ( duration > 0 ) {
+ const timer = setTimeout( handleDismiss, duration );
+ return () => clearTimeout( timer );
+ }
+ }, [ duration, handleDismiss ] );
+
+ return (
+
+ { text && { text } }
+ { showDismiss && }
+
+ );
+};
+
/**
* NoticesList component
*
@@ -12,36 +39,24 @@ import './style.scss';
export default function NoticesList(
props = { handleLocalNoticeDismissClick: null, notices: Object.freeze( [] ) }
) {
- const noticesList = props.notices.map( function ( notice ) {
- const onDismissClick = theNotice => () => {
- theNotice && props.handleLocalNoticeDismissClick( theNotice.id );
- };
- return (
-
- { notice.button && (
-
- { notice.button }
-
- ) }
-
- );
- } );
-
- if ( ! noticesList.length ) {
+ const onDismissNotice = useCallback(
+ noticeId => props.handleLocalNoticeDismissClick?.( noticeId ),
+ [ props ]
+ );
+
+ if ( ! props.notices.length ) {
return null;
}
return (
- { noticesList }
+ { props.notices.map( notice => (
+
+ ) ) }
);
}
diff --git a/projects/packages/search/src/dashboard/components/global-notices/store/actions.js b/projects/packages/search/src/dashboard/components/global-notices/store/actions.js
index 612dbf8aec9f..2445f643c88f 100644
--- a/projects/packages/search/src/dashboard/components/global-notices/store/actions.js
+++ b/projects/packages/search/src/dashboard/components/global-notices/store/actions.js
@@ -18,8 +18,6 @@ export function createNotice( status, text, options = {} ) {
id: options.id || ++createNoticeCounter,
duration: options.duration ?? 2000,
showDismiss: typeof options.showDismiss === 'boolean' ? options.showDismiss : true,
- isPersistent: options.isPersistent || false,
- displayOnNextPage: options.displayOnNextPage || false,
status: status,
text: text,
};
diff --git a/projects/packages/search/src/dashboard/components/global-notices/style.scss b/projects/packages/search/src/dashboard/components/global-notices/style.scss
index 374e7f87583c..67023bf83dbb 100644
--- a/projects/packages/search/src/dashboard/components/global-notices/style.scss
+++ b/projects/packages/search/src/dashboard/components/global-notices/style.scss
@@ -1,5 +1,4 @@
@use "../../scss/z-index";
-@use "scss/calypso-colors";
@use "scss/calypso-mixins";
.global-notices {
@@ -38,45 +37,3 @@
max-width: calc(100% - 64px - 160px);
}
}
-
-.global-notices .dops-notice {
- flex-wrap: nowrap;
- margin-bottom: 0;
- text-align: left;
- pointer-events: auto;
- border-radius: 0;
- box-shadow:
- 0 2px 5px rgba(0, 0, 0, 0.2),
- 0 0 56px rgba(0, 0, 0, 0.15);
-
- .dops-notice__icon-wrapper {
- border-radius: 0;
- }
-
- @include calypso-mixins.breakpoint( ">660px" ) {
- display: flex;
- overflow: hidden;
- margin-bottom: 24px;
- border-radius: 3px;
-
- .dops-notice__icon-wrapper {
- border-radius: 3px 0 0 3px;
- }
- }
-}
-
-.global-notices .dops-notice a.dops-notice__action {
-
- @include calypso-mixins.breakpoint( ">660px" ) {
- font-size: 14px;
- padding: 13px 16px;
- }
-}
-
-.global-notices .dops-notice__dismiss {
- flex-shrink: 0;
-
- @include calypso-mixins.breakpoint( ">660px" ) {
- padding: 13px 16px 0;
- }
-}
diff --git a/projects/packages/search/src/dashboard/components/notice/index.jsx b/projects/packages/search/src/dashboard/components/notice/index.jsx
deleted file mode 100644
index 93f3696c679d..000000000000
--- a/projects/packages/search/src/dashboard/components/notice/index.jsx
+++ /dev/null
@@ -1,130 +0,0 @@
-import { Gridicon } from '@automattic/jetpack-components';
-import clsx from 'clsx';
-import PropTypes from 'prop-types';
-import { Component } from 'react';
-
-import './style.scss';
-
-const noop = () => {};
-
-export default class SimpleNotice extends Component {
- static displayName = 'SimpleNotice';
-
- static defaultProps = {
- duration: 0,
- status: null,
- showDismiss: true,
- className: '',
- onDismissClick: noop,
- };
-
- static propTypes = {
- // we should validate the allowed statuses
- status: PropTypes.string,
- showDismiss: PropTypes.bool,
- isCompact: PropTypes.bool,
- duration: PropTypes.number,
- text: PropTypes.oneOfType( [
- PropTypes.oneOfType( [ PropTypes.string, PropTypes.node ] ),
- PropTypes.arrayOf( PropTypes.oneOfType( [ PropTypes.string, PropTypes.node ] ) ),
- ] ),
- icon: PropTypes.string,
- onDismissClick: PropTypes.func,
- className: PropTypes.string,
- };
-
- dismissTimeout = null;
-
- componentDidMount() {
- if ( this.props.duration > 0 ) {
- this.dismissTimeout = setTimeout( this.props.onDismissClick, this.props.duration );
- }
- }
-
- componentWillUnmount() {
- if ( this.dismissTimeout ) {
- clearTimeout( this.dismissTimeout );
- }
- }
-
- getIcon = () => {
- let icon;
-
- switch ( this.props.status ) {
- case 'is-info':
- icon = 'info';
- break;
- case 'is-success':
- icon = 'checkmark';
- break;
- case 'is-error':
- icon = 'notice';
- break;
- case 'is-warning':
- icon = 'notice';
- break;
- default:
- icon = 'info';
- break;
- }
-
- return icon;
- };
-
- clearText = text => {
- if ( 'string' === typeof text ) {
- return text.replace( /(<([^>]+)>)/gi, '' );
- }
- return text;
- };
-
- onKeyDownCallback = callback => event => {
- if ( event.which === 13 || event.which === 32 ) {
- callback && callback( event );
- }
- };
-
- render() {
- const {
- children,
- className,
- icon,
- isCompact,
- onDismissClick,
- showDismiss = ! isCompact, // by default, show on normal notices, don't show on compact ones
- status,
- text,
- dismissText,
- } = this.props;
- const classes = clsx( 'dops-notice', status, className, {
- 'is-compact': isCompact,
- 'is-dismissable': showDismiss,
- } );
-
- return (
-
-
-
-
-
- { text ? this.clearText( text ) : children }
-
- { text ? children : null }
- { showDismiss && (
-
-
-
- { dismissText }
-
-
- ) }
-
- );
- }
-}
diff --git a/projects/packages/search/src/dashboard/components/notice/notice-action.jsx b/projects/packages/search/src/dashboard/components/notice/notice-action.jsx
deleted file mode 100644
index b50e4d5d23a5..000000000000
--- a/projects/packages/search/src/dashboard/components/notice/notice-action.jsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Gridicon } from '@automattic/jetpack-components';
-import PropTypes from 'prop-types';
-import { Component } from 'react';
-
-import './style.scss';
-
-export default class NoticeAction extends Component {
- static displayName = 'NoticeAction';
-
- static propTypes = {
- href: PropTypes.string,
- onClick: PropTypes.func,
- external: PropTypes.bool,
- icon: PropTypes.string,
- };
-
- static defaultProps = {
- external: false,
- };
-
- render() {
- const attributes = {
- className: 'dops-notice__action',
- href: this.props.href,
- onClick: this.props.onClick,
- };
-
- if ( this.props.external ) {
- attributes.target = '_blank';
- }
-
- return (
-
- { this.props.children }
- { this.props.icon && }
- { this.props.external && }
-
- );
- }
-}
diff --git a/projects/packages/search/src/dashboard/components/notice/style.scss b/projects/packages/search/src/dashboard/components/notice/style.scss
deleted file mode 100644
index 9e5960e8fb30..000000000000
--- a/projects/packages/search/src/dashboard/components/notice/style.scss
+++ /dev/null
@@ -1,287 +0,0 @@
-@use "scss/calypso-colors";
-@use "scss/layout";
-@use "scss/calypso-mixins";
-
-.dops-notice {
- display: flex;
- position: relative;
- width: 100%;
- margin-bottom: 24px;
- box-sizing: border-box;
- animation: appear 0.3s ease-in-out;
- background: calypso-colors.$gray-dark;
- color: calypso-colors.$white;
- border-radius: 3px;
- line-height: 1.5;
-
- // Success!
- &.is-success {
-
- .dops-notice__icon-wrapper {
- background: calypso-colors.$alert-green;
- }
- }
-
- // Warning
- &.is-warning {
-
- .dops-notice__icon-wrapper {
- background: calypso-colors.$alert-yellow;
- }
- }
-
- // Error! OHNO!
- &.is-error {
-
- .dops-notice__icon-wrapper {
- background: calypso-colors.$alert-red;
- }
- }
-
- // General notice
- &.is-info {
-
- .dops-notice__icon-wrapper {
- background: calypso-colors.$blue-medium;
- }
- }
-
- &.is-success,
- &.is-error,
- &.is-warning,
- &.is-info {
-
- .dops-notice__dismiss {
- overflow: hidden;
- }
- }
-}
-
-.dops-notice__icon-wrapper {
- background: calypso-colors.$gray-text-min;
- color: calypso-colors.$white;
- display: flex;
- align-items: baseline;
- width: 47px;
- justify-content: center;
- border-radius: 3px 0 0 3px;
- flex-shrink: 0;
- align-self: stretch;
-
- .gridicon {
- margin-top: 10px;
-
- @include calypso-mixins.breakpoint( ">480px" ) {
- margin-top: 12px;
- }
- }
-}
-
-.dops-notice__content.dops-notice__content {
- padding: 13px;
- font-size: 12px;
- flex-grow: 1;
-
- @include calypso-mixins.breakpoint( ">480px" ) {
- font-size: 14px;
- }
-
- a {
- text-decoration: underline;
- color: calypso-colors.$white;
- }
-
- a:hover {
- text-decoration: none;
- }
-}
-
-.dops-notice__text {
-
- a.dops-notice__text-no-underline {
- text-decoration: none;
- }
-
- a,
- a:visited {
- text-decoration: underline;
- color: calypso-colors.$white;
-
- &:hover {
- color: calypso-colors.$white;
- text-decoration: none;
- }
- }
-
- ul {
- margin-bottom: 0;
- margin-left: 0;
- }
-
- li {
- margin-left: 2em;
- margin-top: 0.5em;
- }
-
- p {
- margin-bottom: 0;
- margin-top: 0.5em;
-
- &:first-child {
- margin-top: 0;
- }
- }
-}
-
-.dops-notice__button {
- cursor: pointer;
- margin-left: 0.428em;
-}
-
-// "X" for dismissing a notice
-.dops-notice__dismiss {
- flex-shrink: 0;
- padding: 12px;
- cursor: pointer;
- padding-bottom: 0;
-
- .gridicon {
- width: 18px;
- height: 18px;
- }
-
- @include calypso-mixins.breakpoint( ">480px" ) {
- padding: 11px;
- padding-bottom: 0;
-
- .gridicon {
- width: 24px;
- height: 24px;
- }
- }
-
- .dops-notice & {
- overflow: hidden;
- color: calypso-colors.$gray-lighten-10;
-
- &:hover,
- &:focus {
- color: calypso-colors.$white;
- }
- }
-}
-
-// specificity for general `a` elements within notice is too great
-a.dops-notice__action {
- cursor: pointer;
- font-size: 12px;
- font-weight: 400;
- text-decoration: none;
- white-space: nowrap;
- color: calypso-colors.$gray-lighten-10;
- padding: 13px;
- display: flex;
- align-items: center;
-
- @include calypso-mixins.breakpoint( ">480px" ) {
- flex-shrink: 1;
- flex-grow: 0;
- align-items: center;
- border-radius: 0;
- font-size: 14px;
- margin: 0 0 0 auto; // forces the element to the right;
- padding: 13px 16px;
-
- .gridicon {
- width: 24px;
- height: 24px;
- }
- }
-
- &:visited {
- color: calypso-colors.$gray-lighten-10;
- }
-
- &:hover {
- color: calypso-colors.$white;
- }
-
- .gridicon {
- margin-left: 8px;
- opacity: 0.7;
- width: 18px;
- height: 18px;
- }
-}
-
-// Compact notices
-.dops-notice.is-compact {
- display: inline-flex;
- flex-wrap: nowrap;
- flex-direction: row;
- width: auto;
- border-radius: 3px;
- min-height: 20px;
- margin: 0;
- padding: 0;
- text-decoration: none;
- text-transform: none;
- vertical-align: middle;
- line-height: 1.5;
-
- .dops-notice__content {
- font-size: 12px;
- padding: 6px 10px;
- }
-
- .dops-notice__icon-wrapper {
- width: 28px;
-
- .dops-notice__icon {
- width: 18px;
- height: 18px;
- margin: 0;
- }
-
- .gridicon {
- margin-top: 6px;
- }
- }
-
- .dops-notice__dismiss {
- position: relative;
- align-self: center;
- flex: none;
- margin: 0 8px 0 0;
- padding: 0;
-
- .gridicon {
- width: 18px;
- height: 18px;
- }
- }
-
- a.dops-notice__action {
- background: transparent;
- display: inline-block;
- margin: 0;
- font-size: 12px;
- align-self: center;
- margin-left: 16px;
- padding: 0 10px;
-
- &:hover,
- &:active,
- &:focus {
- background: transparent;
- }
-
- .gridicon {
- margin-left: 8px;
- width: 14px;
- height: 14px;
- vertical-align: sub;
- opacity: 1;
- }
- }
-}
diff --git a/projects/packages/search/src/dashboard/components/notice/test/index.test.jsx b/projects/packages/search/src/dashboard/components/notice/test/index.test.jsx
deleted file mode 100644
index 9b1c592a2e45..000000000000
--- a/projects/packages/search/src/dashboard/components/notice/test/index.test.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { render } from '@testing-library/react';
-import SimpleNotice from 'components/notice';
-
-describe( 'SimpleNotice', function () {
- const testProps = {
- className: 'test-class',
- };
- describe( 'rendering', function () {
- it( 'can render', () => {
- const { container } = render( );
- expect(
- // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
- container.getElementsByClassName( 'dops-notice__icon-wrapper' ).length
- ).toBeGreaterThan( 0 );
- } );
-
- it( 'can render with class name passed in', () => {
- const { container } = render( Toggle Label );
- // eslint-disable-next-line testing-library/no-node-access
- expect( container.firstChild ).toHaveClass( 'test-class' );
- } );
- } );
-} );
diff --git a/projects/packages/search/src/dashboard/components/pages/sections/first-run-section.jsx b/projects/packages/search/src/dashboard/components/pages/sections/first-run-section.jsx
index 7c4a99fa7b7b..246e9173fb98 100644
--- a/projects/packages/search/src/dashboard/components/pages/sections/first-run-section.jsx
+++ b/projects/packages/search/src/dashboard/components/pages/sections/first-run-section.jsx
@@ -1,10 +1,8 @@
import { IndeterminateProgressBar, ThemeProvider } from '@automattic/jetpack-components';
import { __, sprintf } from '@wordpress/i18n';
-import SimpleNotice from 'components/notice';
+import { Notice } from '@wordpress/ui';
import PlanSummary from './plan-summary';
-// import './first-run-section.scss';
-
const FirstRunSection = ( { planInfo, siteTitle } ) => {
return (
@@ -21,9 +19,6 @@ const FirstRunSection = ( { planInfo, siteTitle } ) => {
);
};
-// TODO: Move this back inline.
-// Per Jason's feedback, doesn't think we should break this out.
-// https://github.com/Automattic/jetpack/pull/26639#discussion_r989592860
const ProgressWrapper = ( { siteTitle } ) => {
return (
@@ -41,28 +36,16 @@ const ProgressWrapper = ( { siteTitle } ) => {
);
};
-// TODO: Remove const variables.
-// Per Jason's feedback, thinks we should put these inline.
-// https://github.com/Automattic/jetpack/pull/26639#discussion_r989593312
-const NoticeWrapper = () => {
- const noticeBoxClassName = 'jp-search-notice-box';
- const header = __( "We're gathering your usage data.", 'jetpack-search-pkg' );
- const message = __(
- 'If you have recently set up Search, please allow a little time for indexing to complete.',
- 'jetpack-search-pkg'
- );
- return (
-
- { header }
- { message }
-
- );
-};
+const NoticeWrapper = () => (
+
+ { __( "We're gathering your usage data.", 'jetpack-search-pkg' ) }
+
+ { __(
+ 'If you have recently set up Search, please allow a little time for indexing to complete.',
+ 'jetpack-search-pkg'
+ ) }
+
+
+);
export default FirstRunSection;
diff --git a/projects/packages/search/src/dashboard/components/record-meter/notice-box.jsx b/projects/packages/search/src/dashboard/components/record-meter/notice-box.jsx
index fd4a833f5ddb..e5c70dacfad9 100644
--- a/projects/packages/search/src/dashboard/components/record-meter/notice-box.jsx
+++ b/projects/packages/search/src/dashboard/components/record-meter/notice-box.jsx
@@ -1,9 +1,6 @@
import { formatNumber } from '@automattic/number-formatters';
import { __, sprintf } from '@wordpress/i18n';
-import SimpleNotice from 'components/notice';
-import NoticeAction from 'components/notice/notice-action';
-
-import './notice-box.scss';
+import { Notice } from '@wordpress/ui';
const CLOSE_TO_LIMIT_PERCENT = 0.8;
@@ -96,26 +93,18 @@ export function NoticeBox( props ) {
const NOTICES = getNotices( props.tierMaximumRecords );
const notice = NOTICES[ activeNoticeIds[ 0 ] ];
- const noticeBoxClassName = notice.isImportant
- ? 'jp-search-notice-box jp-search-notice-box__important'
- : 'jp-search-notice-box';
-
return (
-
- { notice.header && { notice.header }
}
- { notice.message && { notice.message } }
+
+ { notice.header && { notice.header } }
+ { notice.message && { notice.message } }
{ notice.link && (
-
- { notice.link.text }
-
+
+
+ { notice.link.text }
+
+
) }
-
+
);
}
diff --git a/projects/packages/search/src/dashboard/components/record-meter/notice-box.scss b/projects/packages/search/src/dashboard/components/record-meter/notice-box.scss
deleted file mode 100644
index 345efe6c1550..000000000000
--- a/projects/packages/search/src/dashboard/components/record-meter/notice-box.scss
+++ /dev/null
@@ -1,79 +0,0 @@
-// Variables
-@use "@automattic/color-studio/dist/color-variables" as studio;
-
-.jp-search-notice-box {
- background-color: #fff;
- color: #000;
- border: studio.$studio-gray-5 0.5px solid;
- border-radius: 5px;
- padding: 24px;
-}
-
-.jp-search-notice-box .dops-notice__content {
- padding: 0 16px;
-}
-
-.jp-search-notice-box .dops-notice__body {
- display: block;
- padding-bottom: 4px;
- padding-top: 16px;
-}
-
-// Use dops classname for increased specificity.
-.jp-search-notice-box.dops-notice > span.dops-notice__icon-wrapper {
- background-color: rgba(255, 255, 255, 0);
- padding: 0;
-}
-
-.jp-search-notice-box .dops-notice__text,
-.jp-search-notice-box .dops-notice__text .dops-notice__header {
- margin: 0;
- display: block;
- font-size: 1em;
-}
-
-.jp-search-notice-box__important {
- border: studio.$studio-red-50 0.5px solid;
-}
-
-.jp-search-notice-box__important .dops-notice__content .dops-notice__header {
- font-weight: 700;
-}
-
-.jp-search-notice-box .dops-notice__action {
- color: #000;
- display: block;
- font-weight: 700;
- padding: 0 0 6px 0;
-}
-
-// Need to specify 'a.' to override component styles
-.jp-search-notice-box a.dops-notice__action {
-
- &:link,
- &:visited,
- &:hover,
- &:active {
- color: #000;
- text-decoration: underline;
- }
-}
-
-.jp-search-notice-box .dops-notice__icon-wrapper {
- color: #000;
- flex-grow: 0;
- justify-content: left;
- padding: 0;
- width: 24px;
-}
-
-.jp-search-notice-box__important .dops-notice__action,
-.jp-search-notice-box__important .dops-notice__icon-wrapper,
-.jp-search-notice-box__important,
-.jp-search-notice-box__important .dops-notice__header {
- color: studio.$studio-red-50;
-}
-
-.jp-search-notice-box > .dops-notice__icon-wrapper > svg {
- margin: 0;
-}