From acf5bdfb1669b27cbfaa319dd9f18add5b5d4110 Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Wed, 8 Jul 2026 19:30:18 -0300 Subject: [PATCH 1/6] My Jetpack: migrate Add License activation screen to @wordpress/ui buttons and links Migrate the license activation screen (js-packages/licensing ActivationScreen, rendered at My Jetpack -> Add license) off legacy @wordpress/components and custom-styled primitives onto @wordpress/ui: - Activate button: @wordpress/ui Button with the built-in `loading` prop (replaces the manual Spinner) and disabled while activating. - Success-screen buttons: @wordpress/ui Button navigating via onClick (native button, no anchor); loading state uses the `loading` prop. - Support/product links (x3): normalized to native @wordpress/ui Link, dropping the green and black/underline overrides and the raw . - Button/link styling reduced to WPDS tokens; container spacing moved to a flex gap so the button and its paired link keep their spacing. Co-Authored-By: Claude Opus 4.8 (1M context) --- ...e-licensing-activation-screen-wpds-buttons | 4 ++ .../activation-screen-controls/index.jsx | 9 ++- .../activation-screen-controls/style.scss | 48 ++-------------- .../activation-screen-error/style.scss | 9 --- .../activation-screen-illustration/index.jsx | 10 +++- .../primary-link/index.jsx | 44 +++++++++----- .../primary-link/style.scss | 57 ++++--------------- .../product-link/style.scss | 17 +++--- .../activation-screen-success-info/style.scss | 6 +- 9 files changed, 80 insertions(+), 124 deletions(-) create mode 100644 projects/js-packages/licensing/changelog/update-licensing-activation-screen-wpds-buttons diff --git a/projects/js-packages/licensing/changelog/update-licensing-activation-screen-wpds-buttons b/projects/js-packages/licensing/changelog/update-licensing-activation-screen-wpds-buttons new file mode 100644 index 000000000000..55a7e3093537 --- /dev/null +++ b/projects/js-packages/licensing/changelog/update-licensing-activation-screen-wpds-buttons @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Activation screen: migrate the license activation buttons and support links to @wordpress/ui primitives. diff --git a/projects/js-packages/licensing/components/activation-screen-controls/index.jsx b/projects/js-packages/licensing/components/activation-screen-controls/index.jsx index 56c81675cc18..2aadc893a433 100644 --- a/projects/js-packages/licensing/components/activation-screen-controls/index.jsx +++ b/projects/js-packages/licensing/components/activation-screen-controls/index.jsx @@ -1,8 +1,9 @@ import jetpackAnalytics from '@automattic/jetpack-analytics'; import { JetpackLogo } from '@automattic/jetpack-components'; -import { Button, TextControl, SelectControl, Spinner } from '@wordpress/components'; +import { TextControl, SelectControl } from '@wordpress/components'; import { createInterpolateElement } from '@wordpress/element'; import { sprintf, __ } from '@wordpress/i18n'; +import { Button } from '@wordpress/ui'; import PropTypes from 'prop-types'; import { useCallback, useEffect, useMemo, useState } from 'react'; import ActivationScreenError from '../activation-screen-error'; @@ -213,9 +214,11 @@ const ActivationScreenControls = props => { diff --git a/projects/js-packages/licensing/components/activation-screen-controls/style.scss b/projects/js-packages/licensing/components/activation-screen-controls/style.scss index 677c18bf3a79..ac505037fb9c 100644 --- a/projects/js-packages/licensing/components/activation-screen-controls/style.scss +++ b/projects/js-packages/licensing/components/activation-screen-controls/style.scss @@ -83,47 +83,11 @@ } } - .jp-license-activation-screen-controls--button, - .jp-license-activation-screen-controls--button:active { - background-color: var(--jp-black); - border-radius: 4px; - color: var(--jp-white); - display: flex; - font-size: 16px; - font-size: var(--font-body); - font-style: normal; - font-weight: 600; - justify-content: center; - line-height: 24px; - margin-top: 24px; - min-height: 48px; - min-width: 158px; - padding: 13.5px 45px 13.5px 45px; - width: 100%; - - @media screen and (min-width: 480px) { - width: auto; - } - - &.components-button:hover { - background-color: var(--jp-black-80); - color: var(--jp-white); - } - - &:focus { - background-color: var(--jp-black-80); - border: 1px solid var(--jp-white); - color: var(--jp-white); - } - - &[disabled], - &:disabled { - background-color: var(--jp-gray); - color: var(--jp-gray-20); - } - - .components-spinner { - width: 100%; - } + .jp-license-activation-screen-controls--button { + font-weight: var(--wpds-typography-font-weight-medium); + font-size: var(--wpds-typography-font-size-lg); + width: auto; + padding-inline: var(--wpds-dimension-padding-3xl); + padding-block: var(--wpds-dimension-padding-lg); } } diff --git a/projects/js-packages/licensing/components/activation-screen-error/style.scss b/projects/js-packages/licensing/components/activation-screen-error/style.scss index c61dfa403d45..534abbbfa27a 100644 --- a/projects/js-packages/licensing/components/activation-screen-error/style.scss +++ b/projects/js-packages/licensing/components/activation-screen-error/style.scss @@ -55,15 +55,6 @@ ol > li::marker { font-weight: 700; } - - a { - color: var(--jp-green-50); - } - - a:hover, - a:active { - color: var(--jp-green-70); - } } .jp-license-activation-screen-controls { diff --git a/projects/js-packages/licensing/components/activation-screen-illustration/index.jsx b/projects/js-packages/licensing/components/activation-screen-illustration/index.jsx index b9b154cfd8ef..13950c4817ae 100644 --- a/projects/js-packages/licensing/components/activation-screen-illustration/index.jsx +++ b/projects/js-packages/licensing/components/activation-screen-illustration/index.jsx @@ -1,6 +1,7 @@ import { getRedirectUrl } from '@automattic/jetpack-components'; import { createInterpolateElement } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; +import { Link } from '@wordpress/ui'; import PropTypes from 'prop-types'; import './style.scss'; @@ -25,7 +26,14 @@ const ActivationScreenIllustration = props => { { createInterpolateElement( __( 'Do you need help? Contact us.', 'jetpack-licensing' ), { - a: , + a: ( + + ), } ) }

diff --git a/projects/js-packages/licensing/components/activation-screen-success-info/primary-link/index.jsx b/projects/js-packages/licensing/components/activation-screen-success-info/primary-link/index.jsx index 0e0553288f1d..3c6222c2b5c9 100644 --- a/projects/js-packages/licensing/components/activation-screen-success-info/primary-link/index.jsx +++ b/projects/js-packages/licensing/components/activation-screen-success-info/primary-link/index.jsx @@ -1,6 +1,6 @@ import { getRedirectUrl } from '@automattic/jetpack-components'; -import { Button, Spinner } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; +import { Button } from '@wordpress/ui'; import PropTypes from 'prop-types'; import useActivePlugins from '../../../hooks/use-active-plugins'; import { getProductGroup } from '../../activation-screen/utils'; @@ -21,11 +21,20 @@ const PrimaryLink = props => { productGroup === 'jetpack_social_advanced' || productGroup === 'jetpack_social_basic'; const isJetpackProtectActive = isPluginActive( 'Jetpack Protect' ); + // The success-screen CTAs only navigate the current tab. Using onClick keeps + // a native @wordpress/ui + @@ -53,7 +62,10 @@ const PrimaryLink = props => { ? siteAdminUrl + 'admin.php?page=jetpack-protect' : getRedirectUrl( 'jetpack-license-activation-success-scan', { site: siteRawUrl } ); return ( - ); @@ -64,7 +76,7 @@ const PrimaryLink = props => { return ( @@ -74,7 +86,9 @@ const PrimaryLink = props => { return ( diff --git a/projects/js-packages/licensing/components/activation-screen-success-info/primary-link/style.scss b/projects/js-packages/licensing/components/activation-screen-success-info/primary-link/style.scss index ccd9c929a157..a67ae44fae78 100644 --- a/projects/js-packages/licensing/components/activation-screen-success-info/primary-link/style.scss +++ b/projects/js-packages/licensing/components/activation-screen-success-info/primary-link/style.scss @@ -1,48 +1,13 @@ -@use "@automattic/jetpack-base-styles/style"; - -.components-button { - - &.jp-license-activation-screen-success-info--button, - &.jp-license-activation-screen-success-info--button:active, - &.jp-license-activation-screen-success-info--button:visited { - background-color: var(--jp-black); - border-radius: 4px; - color: var(--jp-white); - font-size: 16px; - font-size: var(--font-body); - font-style: normal; - font-weight: 600; - justify-content: center; - line-height: 24px; - min-height: 48px; - min-width: 158px; - padding: 13.5px 45px 13.5px 45px; - width: 100%; - margin: 0 40px 20px 0; - - @media screen and (min-width: 480px) { - width: auto; - } - - &:hover { - background-color: var(--jp-black-80); - color: var(--jp-white); - } - - &:focus { - background-color: var(--jp-black-80); - border: 1px solid var(--jp-white); - color: var(--jp-white); - } - - &[disabled], - &:disabled { - background-color: var(--jp-gray); - color: var(--jp-gray-20); - } - - .components-spinner { - width: 100%; - } +// Scoped under the container to reach specificity (0,2,0), matching the +// Activate button's rule. A bare `--button` selector (0,1,0) only ties +// @wordpress/ui's runtime-injected button reset and loses on source order. +.jp-license-activation-screen-success-info { + + .jp-license-activation-screen-success-info--button { + font-weight: var(--wpds-typography-font-weight-medium); + font-size: var(--wpds-typography-font-size-lg); + width: auto; + padding-inline: var(--wpds-dimension-padding-3xl); + padding-block: var(--wpds-dimension-padding-lg); } } diff --git a/projects/js-packages/licensing/components/activation-screen-success-info/product-link/style.scss b/projects/js-packages/licensing/components/activation-screen-success-info/product-link/style.scss index 30a350db18be..b6c45e39d806 100644 --- a/projects/js-packages/licensing/components/activation-screen-success-info/product-link/style.scss +++ b/projects/js-packages/licensing/components/activation-screen-success-info/product-link/style.scss @@ -1,8 +1,11 @@ -.jp-license-activation-screen-success-info--external-link { - text-decoration: underline !important; - color: var(--jp-black); - font-size: 16px; - font-style: normal; - font-weight: 600; - white-space: nowrap; +// Match the primary button's font so the link reads as its pair. Scoped under +// the container to reach 0,2,0 and override @wordpress/ui's injected reset +// (same reason as the button rule). +.jp-license-activation-screen-success-info { + + .jp-license-activation-screen-success-info--external-link { + font-weight: var(--wpds-typography-font-weight-medium); + font-size: var(--wpds-typography-font-size-lg); + white-space: nowrap; + } } diff --git a/projects/js-packages/licensing/components/activation-screen-success-info/style.scss b/projects/js-packages/licensing/components/activation-screen-success-info/style.scss index 566ebebfe5ec..595f21f91260 100644 --- a/projects/js-packages/licensing/components/activation-screen-success-info/style.scss +++ b/projects/js-packages/licensing/components/activation-screen-success-info/style.scss @@ -39,9 +39,13 @@ } .jp-license-activation-screen-success-info--buttons { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--wpds-dimension-gap-lg) var(--wpds-dimension-gap-3xl); @media screen and (max-width: 480px) { - text-align: center; + justify-content: center; } } } From 21d8d9765974ffc17e7fda728b1156b9e596bb1f Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Thu, 9 Jul 2026 09:35:30 -0300 Subject: [PATCH 2/6] =?UTF-8?q?My=20Jetpack:=20second=20pass=20=E2=80=94?= =?UTF-8?q?=20migrate=20activation-screen=20form=20controls=20and=20error?= =?UTF-8?q?=20notice=20to=20@wordpress/ui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses review feedback (simison) and continues the @wordpress/ui migration: - Form controls: TextControl -> @wordpress/ui InputControl and SelectControl -> @wordpress/ui SelectControl (onValueChange; SelectControl items/value object). Drops the field styling that targeted @wordpress/components markup, including the red/green border feedback (the error notice still communicates it). - Error notice: replace the hand-rolled icon+div/info-box with @wordpress/ui Notice (intent-driven color/icon) + Stack + Text; delete its stylesheet. - Illustration "Contact us" link: drop `rel` (not needed; matches Gutenberg's ExternalLink change). - primary-link: add a TODO to switch the onClick-nav buttons to @wordpress/ui LinkButton once it ships (Gutenberg #77098). The Activate button's WPDS-token overrides are kept intentionally (prominent CTA). Golden-token Modal -> Dialog is deferred to a follow-up. Co-Authored-By: Claude Opus 4.8 (1M context) --- ...e-licensing-activation-screen-wpds-buttons | 2 +- .../activation-screen-controls/index.jsx | 26 +++---- .../activation-screen-controls/style.scss | 37 ---------- .../activation-screen-error/index.tsx | 27 +++---- .../activation-screen-error/style.scss | 73 ------------------- .../activation-screen-illustration/index.jsx | 1 - .../primary-link/index.jsx | 1 + 7 files changed, 23 insertions(+), 144 deletions(-) delete mode 100644 projects/js-packages/licensing/components/activation-screen-error/style.scss diff --git a/projects/js-packages/licensing/changelog/update-licensing-activation-screen-wpds-buttons b/projects/js-packages/licensing/changelog/update-licensing-activation-screen-wpds-buttons index 55a7e3093537..6c5f21f9d662 100644 --- a/projects/js-packages/licensing/changelog/update-licensing-activation-screen-wpds-buttons +++ b/projects/js-packages/licensing/changelog/update-licensing-activation-screen-wpds-buttons @@ -1,4 +1,4 @@ Significance: patch Type: changed -Activation screen: migrate the license activation buttons and support links to @wordpress/ui primitives. +Activation screen: migrate the buttons, form controls, error notice, and support links to @wordpress/ui primitives. diff --git a/projects/js-packages/licensing/components/activation-screen-controls/index.jsx b/projects/js-packages/licensing/components/activation-screen-controls/index.jsx index 2aadc893a433..7eb5b8d25390 100644 --- a/projects/js-packages/licensing/components/activation-screen-controls/index.jsx +++ b/projects/js-packages/licensing/components/activation-screen-controls/index.jsx @@ -1,9 +1,8 @@ import jetpackAnalytics from '@automattic/jetpack-analytics'; import { JetpackLogo } from '@automattic/jetpack-components'; -import { TextControl, SelectControl } from '@wordpress/components'; import { createInterpolateElement } from '@wordpress/element'; import { sprintf, __ } from '@wordpress/i18n'; -import { Button } from '@wordpress/ui'; +import { Button, InputControl, SelectControl } from '@wordpress/ui'; import PropTypes from 'prop-types'; import { useCallback, useEffect, useMemo, useState } from 'react'; import ActivationScreenError from '../activation-screen-error'; @@ -24,13 +23,11 @@ const ManualLicenseKeyInput = props => { const { className, disabled, onChange, value } = props; return ( - ); @@ -90,7 +87,8 @@ const SelectableLicenseKeyInput = props => { }, [ options ] ); const onSelectionChange = useCallback( - val => { + item => { + const val = item?.value ?? ''; setSelectedOption( val ); onChange( val ); }, @@ -100,24 +98,20 @@ const SelectableLicenseKeyInput = props => { return ( <> option.value === selectedOption ) ?? null } + items={ options } + onValueChange={ onSelectionChange } /> { ! isFetching && ! selectedOption && ( - ) } diff --git a/projects/js-packages/licensing/components/activation-screen-controls/style.scss b/projects/js-packages/licensing/components/activation-screen-controls/style.scss index ac505037fb9c..ee1f851490c2 100644 --- a/projects/js-packages/licensing/components/activation-screen-controls/style.scss +++ b/projects/js-packages/licensing/components/activation-screen-controls/style.scss @@ -44,43 +44,6 @@ .jp-license-activation-screen-controls--license-field-with-success { max-width: 500px; margin-top: 10px; - - .components-input-control__label.components-input-control__label.components-input-control__label { - font-weight: 600; - font-size: var(--font-body); - } - - input.components-text-control__input, - select.components-select-control__input { - border-radius: var(--jp-border-radius); - font-size: 18px; - line-height: 24px; - margin: 0; - min-height: 48px; - } - } - - .jp-license-activation-screen-controls--license-field { - - input.components-text-control__input { - border: 1px solid var(--jp-gray-40); - } - } - - .jp-license-activation-screen-controls--license-field-with-error { - - input.components-text-control__input, - select.components-select-control__input { - border: 1px solid var(--jp-red); - } - } - - .jp-license-activation-screen-controls--license-field-with-success { - - input.components-text-control__input, - select.components-select-control__input { - border: 1px solid var(--jp-green); - } } .jp-license-activation-screen-controls--button { diff --git a/projects/js-packages/licensing/components/activation-screen-error/index.tsx b/projects/js-packages/licensing/components/activation-screen-error/index.tsx index 0bec429164de..615f25307bf5 100644 --- a/projects/js-packages/licensing/components/activation-screen-error/index.tsx +++ b/projects/js-packages/licensing/components/activation-screen-error/index.tsx @@ -1,12 +1,10 @@ import jetpackAnalytics from '@automattic/jetpack-analytics'; -import { Icon, cautionFilled as warning, check } from '@wordpress/icons'; +import { Notice, Stack, Text } from '@wordpress/ui'; import { useEffect } from 'react'; import { LICENSE_ERRORS } from './constants'; import { useGetErrorContent } from './use-get-error-content'; import type { FC } from 'react'; -import './style.scss'; - type LicenseErrorKeysType = keyof typeof LICENSE_ERRORS; type LicenseErrorValuesType = ( typeof LICENSE_ERRORS )[ LicenseErrorKeysType ]; @@ -31,21 +29,18 @@ const ActivationScreenError: FC< Props > = ( { licenseError, errorType } ) => { return null; } - const { ACTIVE_ON_SAME_SITE } = LICENSE_ERRORS; - const isLicenseAlreadyAttached = ACTIVE_ON_SAME_SITE === errorType; - - const errorMessageClass = isLicenseAlreadyAttached - ? 'activation-screen-error__message--success' - : 'activation-screen-error__message--error'; + const isLicenseAlreadyAttached = LICENSE_ERRORS.ACTIVE_ON_SAME_SITE === errorType; return ( - <> -
- - { errorMessage } -
- { errorInfo &&
{ errorInfo }
} - + + + { errorMessage } + { errorInfo } + + ); }; diff --git a/projects/js-packages/licensing/components/activation-screen-error/style.scss b/projects/js-packages/licensing/components/activation-screen-error/style.scss deleted file mode 100644 index 534abbbfa27a..000000000000 --- a/projects/js-packages/licensing/components/activation-screen-error/style.scss +++ /dev/null @@ -1,73 +0,0 @@ -.activation-screen-error__message { - display: flex; - flex-direction: row; - align-items: flex-start; - max-width: 500px; - margin-top: calc(var(--spacing-base) * 0.5); - - svg { - margin-left: -3px; - } - - span { - font-size: 13px; - line-height: 20px; - font-weight: 500; - letter-spacing: -0.044em; - } -} - -.activation-screen-error__message--error { - color: var(--jp-red); - - svg { - fill: var(--jp-red); - } -} - -.activation-screen-error__message--success { - color: var(--jp-green); - - svg { - fill: var(--jp-green); - } -} - -.activation-screen-error__info { - background-color: var(--jp-gray-0); - color: var(--jp-gray-80); - font-size: var(--font-body-small); - line-height: calc(var(--font-title-small) - 2px); - border: 1px solid var(--jp-green-0); - border-radius: var(--jp-border-radius); - padding: var(--jp-modal-padding-small); - margin: 32px 0 8px; - - > p { - margin: 0 0 1em; - font-size: var(--font-body-small); - } - - > p:last-child { - margin-bottom: 0; - } - - ol > li::marker { - font-weight: 700; - } -} - -.jp-license-activation-screen-controls { - - .activation-screen-error__info { - - > p { - margin: 0 0 1em; - font-size: var(--font-body-small); - } - - > p:last-child { - margin-bottom: 0; - } - } -} diff --git a/projects/js-packages/licensing/components/activation-screen-illustration/index.jsx b/projects/js-packages/licensing/components/activation-screen-illustration/index.jsx index 13950c4817ae..5c02aaf52ebc 100644 --- a/projects/js-packages/licensing/components/activation-screen-illustration/index.jsx +++ b/projects/js-packages/licensing/components/activation-screen-illustration/index.jsx @@ -30,7 +30,6 @@ const ActivationScreenIllustration = props => { ), diff --git a/projects/js-packages/licensing/components/activation-screen-success-info/primary-link/index.jsx b/projects/js-packages/licensing/components/activation-screen-success-info/primary-link/index.jsx index 3c6222c2b5c9..66d7eb3cb7e1 100644 --- a/projects/js-packages/licensing/components/activation-screen-success-info/primary-link/index.jsx +++ b/projects/js-packages/licensing/components/activation-screen-success-info/primary-link/index.jsx @@ -24,6 +24,7 @@ const PrimaryLink = props => { // The success-screen CTAs only navigate the current tab. Using onClick keeps // a native @wordpress/ui - + ); }; diff --git a/projects/js-packages/licensing/components/activation-screen-controls/style.scss b/projects/js-packages/licensing/components/activation-screen-controls/style.scss index ee1f851490c2..6706eccccd5f 100644 --- a/projects/js-packages/licensing/components/activation-screen-controls/style.scss +++ b/projects/js-packages/licensing/components/activation-screen-controls/style.scss @@ -3,47 +3,15 @@ .jp-license-activation-screen-controls { background: var(--jp-white); padding: 32px; - display: flex; - flex-direction: column; - justify-content: space-between; - - h1 { - // typography-exception - font-size: 44px; - font-weight: 700; - - // This is inherited in the Jetpack plugin from the top-level - // Jetpack page. Doesn't carry over to My Jetpack. - line-height: 1.4; - - // Exception here due to being overridden by Text component - // styles when used in My Jetpack. - margin: 0.67em 0; - } - - p { - font-size: var(--font-body); - - // Exception here due to being overridden by Text component - // styles when used in My Jetpack. - margin: 1em 0; - } - - label { - font-weight: 600; - font-size: var(--font-body); - } @media screen and (min-width: 780px) { padding: 64px; } - .jp-license-activation-screen-controls--license-field, .jp-license-activation-screen-controls--license-field-with-error, .jp-license-activation-screen-controls--license-field-with-success { max-width: 500px; - margin-top: 10px; } .jp-license-activation-screen-controls--button { From 388229444a30be6b47abe87d3f99baf76e59d37b Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Thu, 9 Jul 2026 16:49:16 -0300 Subject: [PATCH 6/6] Licensing: SelectControl manual-entry, two-column width, and stale-error fixes - Manual-entry option uses a sentinel value so the SelectControl shows its label (not the empty-value placeholder) while the manual text input is displayed. - Two-column layout: give each column a determinate width (flex:1 + min-width:0) so a long SelectControl value truncates (built-in ellipsis) instead of reflowing the columns; drop the now-redundant field width:100%. - Clear the activation error when the license changes (select pick or manual input) so a stale invalid-key notice doesn't linger. - ProductLink companion link: add line-height so it doesn't look cramped on mobile. - Error notice: drop its external margin (the controls Stack gap owns spacing). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../activation-screen-controls/index.jsx | 15 +++++++++++---- .../components/activation-screen-error/style.scss | 4 ---- .../product-link/style.scss | 1 + .../components/activation-screen/index.jsx | 9 ++++++++- .../components/activation-screen/style.scss | 8 ++++++++ 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/projects/js-packages/licensing/components/activation-screen-controls/index.jsx b/projects/js-packages/licensing/components/activation-screen-controls/index.jsx index 3e93d178f27e..b67355562854 100644 --- a/projects/js-packages/licensing/components/activation-screen-controls/index.jsx +++ b/projects/js-packages/licensing/components/activation-screen-controls/index.jsx @@ -9,6 +9,11 @@ import ActivationScreenError from '../activation-screen-error'; import { LICENSE_ERRORS } from '../activation-screen-error/constants'; import './style.scss'; +// Sentinel value for the "add a license key manually" option so the SelectControl +// shows that option (rather than the empty-value placeholder) while the manual +// text input is displayed. +const MANUAL_ENTRY = '__manual_entry__'; + /** * The Activation Screen Controls component. * @@ -73,7 +78,7 @@ const SelectableLicenseKeyInput = props => { } ), { label: __( 'I want to add a license key manually', 'jetpack-licensing' ), - value: '', + value: MANUAL_ENTRY, }, ]; }, [ availableLicenses, isFetching ] ); @@ -90,7 +95,9 @@ const SelectableLicenseKeyInput = props => { item => { const val = item?.value ?? ''; setSelectedOption( val ); - onChange( val ); + // Manual entry has no key yet — clear the stored license so the button + // stays disabled until the user types one. + onChange( val === MANUAL_ENTRY ? '' : val ); }, [ onChange ] ); @@ -106,7 +113,7 @@ const SelectableLicenseKeyInput = props => { onValueChange={ onSelectionChange } /> - { ! isFetching && ! selectedOption && ( + { ! isFetching && selectedOption === MANUAL_ENTRY && ( { className="jp-license-activation-screen-controls" direction="column" justify="space-between" - gap="2xl" + gap="xl" > diff --git a/projects/js-packages/licensing/components/activation-screen-error/style.scss b/projects/js-packages/licensing/components/activation-screen-error/style.scss index b00357728d8d..9714a377a670 100644 --- a/projects/js-packages/licensing/components/activation-screen-error/style.scss +++ b/projects/js-packages/licensing/components/activation-screen-error/style.scss @@ -1,8 +1,4 @@ .activation-screen-error { - // External spacing from the input above and the Activate button below; the - // Notice's own grid owns the internal Title/Description spacing. - margin: 16px 0; - // errorInfo renders raw

/

    /
      (from useGetErrorContent); the parent // controls set `p { font-size: 16px }`, so match them to the notice body text. :where(p, ol, ul) { diff --git a/projects/js-packages/licensing/components/activation-screen-success-info/product-link/style.scss b/projects/js-packages/licensing/components/activation-screen-success-info/product-link/style.scss index b6c45e39d806..cae168d34bb3 100644 --- a/projects/js-packages/licensing/components/activation-screen-success-info/product-link/style.scss +++ b/projects/js-packages/licensing/components/activation-screen-success-info/product-link/style.scss @@ -6,6 +6,7 @@ .jp-license-activation-screen-success-info--external-link { font-weight: var(--wpds-typography-font-weight-medium); font-size: var(--wpds-typography-font-size-lg); + line-height: var(--wpds-typography-line-height-2xl); white-space: nowrap; } } diff --git a/projects/js-packages/licensing/components/activation-screen/index.jsx b/projects/js-packages/licensing/components/activation-screen/index.jsx index 09d71fbe0d8a..7cd412066943 100644 --- a/projects/js-packages/licensing/components/activation-screen/index.jsx +++ b/projects/js-packages/licensing/components/activation-screen/index.jsx @@ -79,6 +79,13 @@ const ActivationScreen = props => { } }, [ availableLicenses ] ); + const onLicenseChange = useCallback( newLicense => { + setLicense( newLicense ); + // Changing the license (via the select or the manual input) invalidates + // any prior activation error, so clear the stale notice. + setLicenseError( null ); + }, [] ); + const activateLicense = useCallback( () => { if ( isSaving ) { return Promise.resolve(); @@ -134,7 +141,7 @@ const ActivationScreen = props => { isActivating={ isSaving } license={ license } licenseError={ licenseError } - onLicenseChange={ setLicense } + onLicenseChange={ onLicenseChange } siteUrl={ siteRawUrl } /> diff --git a/projects/js-packages/licensing/components/activation-screen/style.scss b/projects/js-packages/licensing/components/activation-screen/style.scss index 74776caee3d4..3362edde0237 100644 --- a/projects/js-packages/licensing/components/activation-screen/style.scss +++ b/projects/js-packages/licensing/components/activation-screen/style.scss @@ -9,6 +9,14 @@ @media screen and ( min-width: 780px ) { flex-direction: row; + + // Give each column a determinate width (and allow shrinking) so the + // controls don't reflow when the SelectControl's selected value length + // changes — its trigger ellipsis engages instead. + > * { + flex: 1; + min-width: 0; + } } }