Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: changed

Mark ContextualUpgradeTrigger as @deprecated. Use Notice from @wordpress/ui instead. The implementation is unchanged.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ import styles from './style.module.scss';
import { CutBaseProps } from './types.ts';
import type { FC } from 'react';

/**
* ContextualUpgradeTrigger component.
*
* @deprecated Use `Notice` from `@wordpress/ui` instead. Compose with `Notice.Root` (`intent="info"`), `Notice.Description` for the body, and `Notice.Actions` + `Notice.ActionLink` / `Notice.ActionButton` for the CTA. See https://github.com/Automattic/jetpack/issues/48160 for migration guidance.
*
* @param props - The component properties.
* @param props.description - The body copy describing the upgrade context.
* @param props.cta - The CTA label.
* @param props.onClick - Click handler when rendered as a button.
* @param props.href - When provided, renders as an anchor instead of a button.
* @param props.openInNewTab - Whether to open the link in a new tab.
* @param props.className - Optional class for the root element.
* @param props.tooltipText - Optional tooltip body shown next to the description.
* @return The rendered upgrade trigger.
*/
const ContextualUpgradeTrigger: FC< CutBaseProps > = ( {
description,
cta,
Expand Down
4 changes: 4 additions & 0 deletions projects/js-packages/scan/changelog/change-migrate-cut-wp-ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: changed

Replace internal ContextualUpgradeTrigger upgrade prompts with @wordpress/ui Notice composition. Internal refactor with a Notice-style visual refresh.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ContextualUpgradeTrigger, Text } from '@automattic/jetpack-components';
import { Text } from '@automattic/jetpack-components';
import { __, sprintf } from '@wordpress/i18n';
import { Notice } from '@wordpress/ui';
import { useMemo, useContext } from 'react';
import { getFixerDescription } from '@automattic/jetpack-scan';
import { ThreatModalContext } from './index.tsx';
Expand Down Expand Up @@ -48,14 +49,16 @@ const ThreatFixDetails = (): JSX.Element => {
<Text variant="title-small">{ title }</Text>
<Text>{ fix }</Text>
{ handleUpgradeClick && (
<ContextualUpgradeTrigger
description={ __(
'Looking for advanced scan results and one-click fixes?',
'jetpack-scan'
) }
cta={ __( 'Upgrade Jetpack now', 'jetpack-scan' ) }
onClick={ handleUpgradeClick }
/>
<Notice.Root intent="info">
<Notice.Description>
{ __( 'Looking for advanced scan results and one-click fixes?', 'jetpack-scan' ) }
</Notice.Description>
<Notice.Actions>
<Notice.ActionButton onClick={ handleUpgradeClick }>
{ __( 'Upgrade Jetpack now', 'jetpack-scan' ) }
</Notice.ActionButton>
</Notice.Actions>
</Notice.Root>
) }
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ describe( 'SocialModuleToggle', () => {
clearMockedScriptData();
} );

// @wordpress/ui Notice triggers @wordpress/a11y speak() which renders the
// same description text into a visually-hidden .a11y-speak-region. Exclude
// that region from text queries so the assertions target the visible Notice.
const ignoreA11ySpeak = { ignore: 'script, style, .a11y-speak-region' };

it( 'should render connection management component by default', () => {
render( <SocialModuleToggle /> );

Expand All @@ -25,7 +30,9 @@ describe( 'SocialModuleToggle', () => {
it( 'should show upgrade trigger when no paid features', () => {
render( <SocialModuleToggle /> );

expect( screen.getByText( /Unlock advanced sharing options/i ) ).toBeInTheDocument();
expect(
screen.getByText( /Unlock advanced sharing options/i, ignoreA11ySpeak )
).toBeInTheDocument();
} );

it( 'should not show upgrade trigger with paid features', () => {
Expand All @@ -40,6 +47,8 @@ describe( 'SocialModuleToggle', () => {
} );
render( <SocialModuleToggle /> );

expect( screen.queryByText( /Unlock advanced sharing options/i ) ).not.toBeInTheDocument();
expect(
screen.queryByText( /Unlock advanced sharing options/i, ignoreA11ySpeak )
).not.toBeInTheDocument();
} );
} );
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {
ContextualUpgradeTrigger,
IconTooltip,
Text,
getRedirectUrl,
useBreakpointMatch,
} from '@automattic/jetpack-components';
import { getScriptData, isWpcomPlatformSite } from '@automattic/jetpack-script-data';
import { useSelect, useDispatch } from '@wordpress/data';
import { __, _x } from '@wordpress/i18n';
import { Link } from '@wordpress/ui';
import { Link, Notice } from '@wordpress/ui';
import clsx from 'clsx';
import { useCallback } from 'react';
import { store as socialStore } from '../../../../social-store';
Expand Down Expand Up @@ -93,19 +93,29 @@ const SocialModuleToggle: FC = () => {
</Link>
</Text>
{ ! isWpcomPlatformSite() && ! hasSocialPaidFeatures() ? (
<ContextualUpgradeTrigger
className={ clsx( styles.cut, { [ styles.small ]: isSmall } ) }
description={ __( 'Unlock advanced sharing options', 'jetpack-publicize-pkg' ) }
cta={ __( 'Power up Jetpack Social', 'jetpack-publicize-pkg' ) }
href={ getRedirectUrl( 'jetpack-social-admin-page-upsell', {
site: `${ wpcom.blog_id ?? siteSuffix }`,
query: getRefreshPlanQuery(),
} ) }
tooltipText={ __(
'Share custom images and videos that capture attention, use our powerful Social Image Generator to create stunning visuals, and access priority support for expert help whenever you need it.',
'jetpack-publicize-pkg'
) }
/>
<Notice.Root intent="info" className={ clsx( styles.cut, { [ styles.small ]: isSmall } ) }>
<Notice.Description>
{ __( 'Unlock advanced sharing options', 'jetpack-publicize-pkg' ) }{ ' ' }
<IconTooltip className={ styles[ 'upgrade-tooltip' ] } iconSize={ 16 } offset={ 4 }>
<Text variant="body-small">
{ __(
'Share custom images and videos that capture attention, use our powerful Social Image Generator to create stunning visuals, and access priority support for expert help whenever you need it.',
'jetpack-publicize-pkg'
) }
</Text>
</IconTooltip>
</Notice.Description>
<Notice.Actions>
<Notice.ActionLink
href={ getRedirectUrl( 'jetpack-social-admin-page-upsell', {
site: `${ wpcom.blog_id ?? siteSuffix }`,
query: getRefreshPlanQuery(),
} ) }
>
{ __( 'Power up Jetpack Social', 'jetpack-publicize-pkg' ) }
</Notice.ActionLink>
</Notice.Actions>
</Notice.Root>
) : null }
{ isModuleEnabled && <MessageTemplateSection disabled={ isUpdating } /> }
{ renderConnectionManagement() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@
.learn {
text-wrap: nowrap;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: changed

Replace internal ContextualUpgradeTrigger upgrade prompts with @wordpress/ui Notice composition. Internal refactor with a Notice-style visual refresh.
4 changes: 4 additions & 0 deletions projects/packages/search/changelog/change-migrate-cut-wp-ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: changed

Replace internal ContextualUpgradeTrigger upgrade prompts with @wordpress/ui Notice composition. Internal refactor with a Notice-style visual refresh.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ContextualUpgradeTrigger, ThemeProvider } from '@automattic/jetpack-components';
import { createInterpolateElement } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { Link } from '@wordpress/ui';
import { Link, Notice } from '@wordpress/ui';
import { useState, useCallback, useMemo } from 'react';
import DonutMeterContainer, { formatNumber } from '../../donut-meter-container';
import PlanSummary from './plan-summary';
Expand Down Expand Up @@ -300,17 +299,17 @@ const getUpgradeMessages = () => {
};

const UpgradeTrigger = ( { upgradeMessage, ctaCallback } ) => {
// const upgradeMessage = type && getUpgradeMessages()[ type ];
const triggerData = upgradeMessage && { ...upgradeMessage, onClick: ctaCallback };
if ( ! upgradeMessage ) {
return null;
}

return (
<>
{ triggerData && (
<ThemeProvider>
<ContextualUpgradeTrigger { ...triggerData } />
</ThemeProvider>
) }
</>
<Notice.Root intent="info">
<Notice.Description>{ upgradeMessage.description }</Notice.Description>
<Notice.Actions>
<Notice.ActionButton onClick={ ctaCallback }>{ upgradeMessage.cta }</Notice.ActionButton>
</Notice.Actions>
</Notice.Root>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { render, screen } from '@testing-library/react';
import PlanUsageSection from '../plan-usage-section';

jest.mock( '@automattic/jetpack-components', () => ( {
ContextualUpgradeTrigger: ( { description, cta } ) => (
<div data-testid="upgrade-trigger">
<span data-testid="upgrade-description">{ description }</span>
<span data-testid="upgrade-cta">{ cta }</span>
</div>
),
ThemeProvider: ( { children } ) => <>{ children }</>,
} ) );

jest.mock( '@wordpress/ui', () => ( {
Link: ( { children, href } ) => <a href={ href }>{ children }</a>,
Notice: {
Root: ( { children } ) => <div data-testid="upgrade-trigger">{ children }</div>,
Description: ( { children } ) => <span data-testid="upgrade-description">{ children }</span>,
Actions: ( { children } ) => <div>{ children }</div>,
ActionButton: ( { children, onClick } ) => (
<button data-testid="upgrade-cta" onClick={ onClick }>
{ children }
</button>
),
},
} ) );

jest.mock( '../../../donut-meter-container', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ jest.mock(
Button: ( { children, ...rest } ) => <button { ...rest }>{ children }</button>,
Container: ( { children } ) => <div>{ children }</div>,
Col: ( { children } ) => <div>{ children }</div>,
ContextualUpgradeTrigger: ( { children } ) => <div>{ children }</div>,
DonutMeter: () => <div data-testid="donut-meter" />,
Gridicon: () => <span data-testid="gridicon" />,
IconTooltip: ( { children } ) => <div>{ children }</div>,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: changed

Replace internal ContextualUpgradeTrigger upgrade prompts with @wordpress/ui Notice composition. Internal refactor with a Notice-style visual refresh.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
Button,
Col,
useBreakpointMatch,
ContextualUpgradeTrigger,
} from '@automattic/jetpack-components';
import {
useProductCheckoutWorkflow,
Expand All @@ -19,6 +18,7 @@ import {
} from '@automattic/jetpack-connection';
import { FormFileUpload } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { Notice } from '@wordpress/ui';
import clsx from 'clsx';
import { useState } from 'react';
/**
Expand Down Expand Up @@ -246,11 +246,11 @@ const UpgradeTrigger = ( { hasUsedVideo = false }: { hasUsedVideo: boolean } ) =
);

return (
<ContextualUpgradeTrigger
description={ description }
cta={ cta }
className={ styles[ 'upgrade-trigger' ] }
onClick={ onButtonClickHandler }
/>
<Notice.Root intent="info" className={ styles[ 'upgrade-trigger' ] }>
{ description && <Notice.Description>{ description }</Notice.Description> }
<Notice.Actions>
<Notice.ActionButton onClick={ onButtonClickHandler }>{ cta }</Notice.ActionButton>
</Notice.Actions>
</Notice.Root>
);
};
4 changes: 4 additions & 0 deletions projects/plugins/protect/changelog/change-migrate-cut-wp-ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: changed

Replace internal ContextualUpgradeTrigger upgrade prompts with @wordpress/ui Notice composition. Internal refactor with a Notice-style visual refresh.
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Text, Button, ContextualUpgradeTrigger } from '@automattic/jetpack-components';
import { Text, Button } from '@automattic/jetpack-components';
import { __, sprintf } from '@wordpress/i18n';
import { useCallback } from 'react';
import useAnalyticsTracks from '../../hooks/use-analytics-tracks';
import usePlan from '../../hooks/use-plan';
import FreeAccordion, { FreeAccordionItem } from '../free-accordion';
import UpgradeNotice from '../upgrade-notice';
import Pagination from './pagination';
import styles from './styles.module.scss';

Expand Down Expand Up @@ -65,7 +66,7 @@ const ThreatAccordionItem = ( {
sprintf( __( 'Update to %1$s %2$s', 'jetpack-protect' ), name, fixedIn )
}
</Text>
<ContextualUpgradeTrigger
<UpgradeNotice
description={ __(
'Looking for advanced scan results and one-click fixes?',
'jetpack-protect'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Notice } from '@wordpress/ui';
import type { FC, MouseEventHandler, ReactNode } from 'react';

interface UpgradeNoticeProps {
/**
* The body copy describing the upgrade context.
*/
description: ReactNode;
/**
* The CTA label for the action.
*/
cta: ReactNode;
/**
* Click handler for the CTA. Used when `href` is not set — renders an ActionButton.
*/
onClick?: MouseEventHandler< HTMLButtonElement >;
/**
* Optional href. When set, renders an ActionLink instead of an ActionButton.
*/
href?: string;
/**
* Whether to open the link in a new tab. Only applies when `href` is set.
*/
openInNewTab?: boolean;
/**
* Forwarded to the underlying Notice.Root for layout overrides.
*/
className?: string;
}

/**
* Package-local upgrade-notice helper, built on `@wordpress/ui` `Notice`.
*
* Wraps the `Notice.Root` + `Notice.Description` + `Notice.Actions` composition so the
* three Protect upgrade-trigger sites stay terse. Replaces the deprecated
* `ContextualUpgradeTrigger` from `@automattic/jetpack-components`.
*
* @param props - Component properties.
* @param props.description - Body copy describing the upgrade context.
* @param props.cta - CTA label for the action.
* @param props.onClick - Click handler for the CTA (used when `href` is unset).
* @param props.href - Optional href. When set, renders an ActionLink.
* @param props.openInNewTab - Whether to open the link in a new tab. Only applies when `href` is set.
* @param props.className - Optional class forwarded to the underlying Notice.Root.
* @return The rendered upgrade notice.
*/
const UpgradeNotice: FC< UpgradeNoticeProps > = ( {
description,
cta,
onClick,
href,
openInNewTab = false,
className,
} ) => {
return (
<Notice.Root intent="info" className={ className }>
<Notice.Description>{ description }</Notice.Description>
<Notice.Actions>
{ href !== undefined ? (
<Notice.ActionLink href={ href } openInNewTab={ openInNewTab }>
{ cta }
</Notice.ActionLink>
) : (
<Notice.ActionButton onClick={ onClick }>{ cta }</Notice.ActionButton>
) }
</Notice.Actions>
</Notice.Root>
);
};

export default UpgradeNotice;
Loading
Loading