From 2c663e20a29224d9bac342680c9e77a702d0fd3a Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Fri, 24 Apr 2026 15:24:12 +0300 Subject: [PATCH 01/20] Update AI settings page to use wp-ui components --- routes/ai-home/ai-icon.tsx | 36 ++++-- routes/ai-home/stage.tsx | 116 +++++++++++------- routes/ai-home/style.scss | 41 +------ .../components/ReviewNotesPlugin.tsx | 109 ++++++++-------- 4 files changed, 150 insertions(+), 152 deletions(-) diff --git a/routes/ai-home/ai-icon.tsx b/routes/ai-home/ai-icon.tsx index 337de51d2..04c2144ed 100644 --- a/routes/ai-home/ai-icon.tsx +++ b/routes/ai-home/ai-icon.tsx @@ -1,19 +1,33 @@ /** * WordPress dependencies */ -import { Path, SVG } from '@wordpress/primitives'; +import { Path, SVG } from '@wordpress/components'; -export default function AIIcon( { - className = 'wpai-icon', -}: { - className?: string; -} ) { +export default function AIIcon() { return ( - - - - - + + + + + ); } diff --git a/routes/ai-home/stage.tsx b/routes/ai-home/stage.tsx index 2ed21bb2b..e58c6ea78 100644 --- a/routes/ai-home/stage.tsx +++ b/routes/ai-home/stage.tsx @@ -3,11 +3,18 @@ */ import { Page } from '@wordpress/admin-ui'; import { + Text, + Card, + Stack, + Badge, Button, - ExternalLink, - Spinner, - ToggleControl, -} from '@wordpress/components'; + Link, + Icon, + Notice, + Popover, + VisuallyHidden, +} from '@wordpress/ui'; +import { Spinner, ToggleControl } from '@wordpress/components'; import { store as coreStore } from '@wordpress/core-data'; import { useDispatch, useRegistry, useSelect } from '@wordpress/data'; import type { DataFormControlProps, Field, Form } from '@wordpress/dataviews'; @@ -16,7 +23,6 @@ import { useCallback, useMemo, useState } from '@wordpress/element'; import { __, _n, sprintf } from '@wordpress/i18n'; import { info as infoIcon } from '@wordpress/icons'; import { store as noticesStore } from '@wordpress/notices'; -import { Icon, Notice, Popover, VisuallyHidden } from '@wordpress/ui'; /** * Internal dependencies @@ -394,9 +400,9 @@ function SectionActions( { }, [ experimentSettings, data, onBulkChange ] ); return ( -
+ -
+ ); } @@ -520,9 +526,8 @@ function InlineFeatureSettings( { feature }: { feature: FeatureData } ) { { isDirty && (
) } @@ -586,28 +594,50 @@ function VisualCardToggle( { const checked = !! field.getValue( { item: data } ); return ( -
- { feature?.image && ( -
- -
- ) } -
- - onChange( { [ field.id ]: value } ) - } - disabled={ ! globalEnabled } - help={ field.description } - /> -
-
+ + + { field.label } + + { feature?.image && ( + + + + ) } + + { field.description } + + + + { checked && ( + { __( 'Enabled', 'ai' ) } + ) } + + + ); } @@ -907,13 +937,13 @@ function AISettingsPage() { 'ai' ) } actions={ -
- + <> + { __( 'Docs', 'ai' ) } - - + + { __( 'Contribute', 'ai' ) } - +
-
+ } > -
+ { ! PAGE_DATA.hasValidCredentials && ( { PAGE_DATA.connectorsUrl && ( - - - { __( 'Manage Connectors', 'ai' ) } - - + + { __( 'Manage Connectors', 'ai' ) } + ) } ) } @@ -968,7 +994,7 @@ function AISettingsPage() { onChange={ handleChange } /> ) } -
+ ); } diff --git a/routes/ai-home/style.scss b/routes/ai-home/style.scss index 15f36b4e1..df8a43ef9 100644 --- a/routes/ai-home/style.scss +++ b/routes/ai-home/style.scss @@ -23,13 +23,6 @@ margin-bottom: 24px; } -.ai-settings-page__actions { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 16px; -} - .ai-settings-page__global-toggle { display: flex; align-items: center; @@ -60,15 +53,6 @@ line-height: 1.5; } -.ai-settings-page__link { - display: inline-flex; - align-items: center; - gap: 4px; - - svg { - fill: currentColor; - } -} .ai-feature-settings-form { margin-top: 4px; @@ -89,37 +73,22 @@ } .ai-section-actions { - border-top: 1px solid var(--wp-components-color-gray-200); - display: flex; - gap: 8px; + border-top: 1px solid var(--wpds-color-stroke-surface-neutral-weak); margin-top: 16px; padding-top: 12px; } -.ai-showcase-card { - display: flex; - flex-direction: column; - border: 1px solid #ddd; - border-radius: 8px; - overflow: hidden; - background: #fff; -} - .ai-showcase-card__image { - width: 100%; - display: flex; - align-items: center; - justify-content: center; - overflow: hidden; - + margin-bottom: var(--wp-ui-card-padding); img { + aspect-ratio: 16 / 9; width: 100%; height: 100%; } } -.ai-showcase-card__content { - padding: 24px; +.ai-showcase-card__actions { + margin-top: 4px; } .ai-showcase-card--disabled { diff --git a/src/experiments/review-notes/components/ReviewNotesPlugin.tsx b/src/experiments/review-notes/components/ReviewNotesPlugin.tsx index 2d45dc335..71afd3e85 100644 --- a/src/experiments/review-notes/components/ReviewNotesPlugin.tsx +++ b/src/experiments/review-notes/components/ReviewNotesPlugin.tsx @@ -5,13 +5,8 @@ /** * WordPress dependencies */ -import { - Button, - Flex, - FlexItem, - MenuItem, - Spinner, -} from '@wordpress/components'; +import { Button, Icon, Link, Stack } from '@wordpress/ui'; +import { MenuItem, Spinner } from '@wordpress/components'; import { BlockSettingsMenuControls } from '@wordpress/block-editor'; import { useDispatch } from '@wordpress/data'; import { store as editPostStore } from '@wordpress/edit-post'; @@ -62,62 +57,56 @@ export default function ReviewNotesPlugin() { return ( <> - - - - + + { lastRunCount !== null && ( - - - { lastRunCount === 0 - ? __( 'No new suggestions found.', 'ai' ) - : createInterpolateElement( - sprintf( - /* translators: %d: number of suggestions added. The tags wrap a link to open the Notes panel. */ - _n( - '%d suggestion added, view those Notes here.', - '%d suggestions added, view those Notes here.', - lastRunCount, - 'ai' - ), - lastRunCount + + { lastRunCount === 0 + ? __( 'No new suggestions found.', 'ai' ) + : createInterpolateElement( + sprintf( + /* translators: %d: number of suggestions added. The tags wrap a link to open the Notes panel. */ + _n( + '%d suggestion added, view those Notes here.', + '%d suggestions added, view those Notes here.', + lastRunCount, + 'ai' ), - { - a: ( - - + ) } ); @@ -600,41 +604,38 @@ function VisualCardToggle( { }` } > - - { field.label } - { feature?.image && ( ) } - - { field.description } - - - - { checked && ( - { __( 'Enabled', 'ai' ) } - ) } + { field.description } + + + + { checked && ( + + { __( 'Enabled', 'ai' ) } + + ) } + @@ -989,7 +990,13 @@ function AISettingsPage() { ) } { isLoading ? ( - + + + ) : ( data={ data } diff --git a/routes/ai-home/style.scss b/routes/ai-home/style.scss index ae9da3b88..bfb8b7234 100644 --- a/routes/ai-home/style.scss +++ b/routes/ai-home/style.scss @@ -49,12 +49,6 @@ margin-top: 4px; padding-left: 40px; max-width: 480px; - - .components-base-control__label, - .components-input-control__label, - .dataforms-layouts-regular__field-label { - text-transform: none !important; - } } .ai-feature-settings-form__actions { @@ -69,6 +63,7 @@ .ai-showcase-card__image { margin-bottom: var(--wp-ui-card-padding); + margin-top: calc(-1 * var(--wp-ui-card-padding)); // Negative to bump against top border. img { aspect-ratio: 16 / 9; width: 100%; @@ -83,3 +78,7 @@ .ai-showcase-card--disabled { opacity: 0.6; } + +.ai-settings-page__loading { + min-height: calc(50vh); // Leave space for the page header. +} From 621d8e9d964af5cf4ced180fd1c5c5291949bb6a Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Fri, 24 Apr 2026 16:41:21 +0300 Subject: [PATCH 04/20] Revert review-notes changes --- .../components/ReviewNotesPlugin.tsx | 109 ++++++++++-------- 1 file changed, 60 insertions(+), 49 deletions(-) diff --git a/src/experiments/review-notes/components/ReviewNotesPlugin.tsx b/src/experiments/review-notes/components/ReviewNotesPlugin.tsx index 71afd3e85..2d45dc335 100644 --- a/src/experiments/review-notes/components/ReviewNotesPlugin.tsx +++ b/src/experiments/review-notes/components/ReviewNotesPlugin.tsx @@ -5,8 +5,13 @@ /** * WordPress dependencies */ -import { Button, Icon, Link, Stack } from '@wordpress/ui'; -import { MenuItem, Spinner } from '@wordpress/components'; +import { + Button, + Flex, + FlexItem, + MenuItem, + Spinner, +} from '@wordpress/components'; import { BlockSettingsMenuControls } from '@wordpress/block-editor'; import { useDispatch } from '@wordpress/data'; import { store as editPostStore } from '@wordpress/edit-post'; @@ -57,56 +62,62 @@ export default function ReviewNotesPlugin() { return ( <> - - + + + + { lastRunCount !== null && ( - - { lastRunCount === 0 - ? __( 'No new suggestions found.', 'ai' ) - : createInterpolateElement( - sprintf( - /* translators: %d: number of suggestions added. The tags wrap a link to open the Notes panel. */ - _n( - '%d suggestion added, view those Notes here.', - '%d suggestions added, view those Notes here.', - lastRunCount, - 'ai' - ), - lastRunCount - ), - { - a: ( - { - e.preventDefault(); - openNotesPanel(); - } } - /> + + + { lastRunCount === 0 + ? __( 'No new suggestions found.', 'ai' ) + : createInterpolateElement( + sprintf( + /* translators: %d: number of suggestions added. The tags wrap a link to open the Notes panel. */ + _n( + '%d suggestion added, view those Notes here.', + '%d suggestions added, view those Notes here.', + lastRunCount, + 'ai' + ), + lastRunCount ), - } - ) } - + { + a: ( + ) } From 23c4b6b356a2eda51365e3a7407090e2dec9ff1f Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Mon, 4 May 2026 14:05:32 +0300 Subject: [PATCH 11/20] Update `@wordpress/ui` --- package-lock.json | 489 ++++++++++++++++++++++++++++++++++++---------- package.json | 2 +- 2 files changed, 385 insertions(+), 106 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9f51ed3d0..c4e0b3a87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "@wordpress/notices": "^5.44.0", "@wordpress/plugins": "^7.44.0", "@wordpress/primitives": "^4.45.0", - "@wordpress/ui": "^0.11.0", + "@wordpress/ui": "^0.12.0", "@wordpress/url": "^4.44.0", "@wordpress/wordcount": "^4.44.0", "react": "^18.3.1" @@ -10194,97 +10194,6 @@ "react": "^18.0.0" } }, - "node_modules/@wordpress/admin-ui/node_modules/@wordpress/ui": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@wordpress/ui/-/ui-0.12.0.tgz", - "integrity": "sha512-n/xfyagM90CcikLtlvNcjsFZtpt1wTpboOZPyCp9wqF6akAyJ4SUg9hXb/UA7pC8JqGe1Dg/hXJnFn/td8pvRA==", - "license": "GPL-2.0-or-later", - "dependencies": { - "@base-ui/react": "^1.4.1", - "@wordpress/a11y": "^4.45.0", - "@wordpress/compose": "^7.45.0", - "@wordpress/element": "^6.45.0", - "@wordpress/i18n": "^6.18.0", - "@wordpress/icons": "^13.0.0", - "@wordpress/keycodes": "^4.45.0", - "@wordpress/primitives": "^4.45.0", - "@wordpress/private-apis": "^1.45.0", - "@wordpress/theme": "^0.12.0", - "clsx": "^2.1.1", - "tabbable": "^6.4.0" - }, - "engines": { - "node": ">=20.10.0", - "npm": ">=10.2.3" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@wordpress/admin-ui/node_modules/@wordpress/ui/node_modules/@base-ui/react": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@base-ui/react/-/react-1.4.1.tgz", - "integrity": "sha512-Ab5/LIhcmL8BQcsBUYiOfkSDRdLpvgUBzMK30cu684JPcLclYlztharvCZyNNgzJtbAiREzI9q0pI5erHCMgCw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.29.2", - "@base-ui/utils": "0.2.8", - "@floating-ui/react-dom": "^2.1.8", - "@floating-ui/utils": "^0.2.11", - "use-sync-external-store": "^1.6.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@date-fns/tz": "^1.2.0", - "@types/react": "^17 || ^18 || ^19", - "date-fns": "^4.0.0", - "react": "^17 || ^18 || ^19", - "react-dom": "^17 || ^18 || ^19" - }, - "peerDependenciesMeta": { - "@date-fns/tz": { - "optional": true - }, - "@types/react": { - "optional": true - }, - "date-fns": { - "optional": true - } - } - }, - "node_modules/@wordpress/admin-ui/node_modules/@wordpress/ui/node_modules/@floating-ui/react-dom": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", - "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", - "license": "MIT", - "dependencies": { - "@floating-ui/dom": "^1.7.6" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@wordpress/admin-ui/node_modules/@wordpress/ui/node_modules/date-fns": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", - "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", - "license": "MIT", - "optional": true, - "peer": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/kossnocorp" - } - }, "node_modules/@wordpress/api-fetch": { "version": "7.44.0", "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-7.44.0.tgz", @@ -11045,6 +10954,85 @@ "react-dom": "^18.0.0" } }, + "node_modules/@wordpress/dataviews/node_modules/@base-ui/react": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@base-ui/react/-/react-1.4.1.tgz", + "integrity": "sha512-Ab5/LIhcmL8BQcsBUYiOfkSDRdLpvgUBzMK30cu684JPcLclYlztharvCZyNNgzJtbAiREzI9q0pI5erHCMgCw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@base-ui/utils": "0.2.8", + "@floating-ui/react-dom": "^2.1.8", + "@floating-ui/utils": "^0.2.11", + "use-sync-external-store": "^1.6.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@date-fns/tz": "^1.2.0", + "@types/react": "^17 || ^18 || ^19", + "date-fns": "^4.0.0", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@date-fns/tz": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "date-fns": { + "optional": true + } + } + }, + "node_modules/@wordpress/dataviews/node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@wordpress/dataviews/node_modules/@wordpress/ui": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@wordpress/ui/-/ui-0.11.0.tgz", + "integrity": "sha512-V1R3CTQ8MltuajZ53PCHGe9mmRwyx1RpjHA2wWOv+79dV0qQ1Y/psL0YTMY4eteL4SNAlBcjJVP66zD5O6yF8Q==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@base-ui/react": "^1.4.0", + "@wordpress/a11y": "^4.44.0", + "@wordpress/compose": "^7.44.0", + "@wordpress/element": "^6.44.0", + "@wordpress/i18n": "^6.17.0", + "@wordpress/icons": "^12.2.0", + "@wordpress/keycodes": "^4.44.0", + "@wordpress/primitives": "^4.44.0", + "@wordpress/private-apis": "^1.44.0", + "@wordpress/theme": "^0.11.0", + "clsx": "^2.1.1", + "tabbable": "^6.4.0" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, "node_modules/@wordpress/dataviews/node_modules/date-fns": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", @@ -11201,6 +11189,57 @@ "react-dom": "^18.0.0" } }, + "node_modules/@wordpress/edit-post/node_modules/@base-ui/react": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@base-ui/react/-/react-1.4.1.tgz", + "integrity": "sha512-Ab5/LIhcmL8BQcsBUYiOfkSDRdLpvgUBzMK30cu684JPcLclYlztharvCZyNNgzJtbAiREzI9q0pI5erHCMgCw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@base-ui/utils": "0.2.8", + "@floating-ui/react-dom": "^2.1.8", + "@floating-ui/utils": "^0.2.11", + "use-sync-external-store": "^1.6.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@date-fns/tz": "^1.2.0", + "@types/react": "^17 || ^18 || ^19", + "date-fns": "^4.0.0", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@date-fns/tz": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "date-fns": { + "optional": true + } + } + }, + "node_modules/@wordpress/edit-post/node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@wordpress/edit-post/node_modules/@wordpress/admin-ui": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/@wordpress/admin-ui/-/admin-ui-1.12.0.tgz", @@ -11224,6 +11263,46 @@ "react": "^18.0.0" } }, + "node_modules/@wordpress/edit-post/node_modules/@wordpress/ui": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@wordpress/ui/-/ui-0.11.0.tgz", + "integrity": "sha512-V1R3CTQ8MltuajZ53PCHGe9mmRwyx1RpjHA2wWOv+79dV0qQ1Y/psL0YTMY4eteL4SNAlBcjJVP66zD5O6yF8Q==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@base-ui/react": "^1.4.0", + "@wordpress/a11y": "^4.44.0", + "@wordpress/compose": "^7.44.0", + "@wordpress/element": "^6.44.0", + "@wordpress/i18n": "^6.17.0", + "@wordpress/icons": "^12.2.0", + "@wordpress/keycodes": "^4.44.0", + "@wordpress/primitives": "^4.44.0", + "@wordpress/private-apis": "^1.44.0", + "@wordpress/theme": "^0.11.0", + "clsx": "^2.1.1", + "tabbable": "^6.4.0" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@wordpress/edit-post/node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "optional": true, + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/@wordpress/editor": { "version": "14.44.0", "resolved": "https://registry.npmjs.org/@wordpress/editor/-/editor-14.44.0.tgz", @@ -11666,6 +11745,57 @@ "react-dom": "^18.0.0" } }, + "node_modules/@wordpress/interface/node_modules/@base-ui/react": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@base-ui/react/-/react-1.4.1.tgz", + "integrity": "sha512-Ab5/LIhcmL8BQcsBUYiOfkSDRdLpvgUBzMK30cu684JPcLclYlztharvCZyNNgzJtbAiREzI9q0pI5erHCMgCw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@base-ui/utils": "0.2.8", + "@floating-ui/react-dom": "^2.1.8", + "@floating-ui/utils": "^0.2.11", + "use-sync-external-store": "^1.6.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@date-fns/tz": "^1.2.0", + "@types/react": "^17 || ^18 || ^19", + "date-fns": "^4.0.0", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@date-fns/tz": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "date-fns": { + "optional": true + } + } + }, + "node_modules/@wordpress/interface/node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@wordpress/interface/node_modules/@wordpress/admin-ui": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/@wordpress/admin-ui/-/admin-ui-1.12.0.tgz", @@ -11689,6 +11819,46 @@ "react": "^18.0.0" } }, + "node_modules/@wordpress/interface/node_modules/@wordpress/ui": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@wordpress/ui/-/ui-0.11.0.tgz", + "integrity": "sha512-V1R3CTQ8MltuajZ53PCHGe9mmRwyx1RpjHA2wWOv+79dV0qQ1Y/psL0YTMY4eteL4SNAlBcjJVP66zD5O6yF8Q==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@base-ui/react": "^1.4.0", + "@wordpress/a11y": "^4.44.0", + "@wordpress/compose": "^7.44.0", + "@wordpress/element": "^6.44.0", + "@wordpress/i18n": "^6.17.0", + "@wordpress/icons": "^12.2.0", + "@wordpress/keycodes": "^4.44.0", + "@wordpress/primitives": "^4.44.0", + "@wordpress/private-apis": "^1.44.0", + "@wordpress/theme": "^0.11.0", + "clsx": "^2.1.1", + "tabbable": "^6.4.0" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@wordpress/interface/node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "optional": true, + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/@wordpress/is-shallow-equal": { "version": "5.45.0", "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-5.45.0.tgz", @@ -11859,6 +12029,97 @@ "react": "^18.0.0" } }, + "node_modules/@wordpress/media-utils/node_modules/@base-ui/react": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@base-ui/react/-/react-1.4.1.tgz", + "integrity": "sha512-Ab5/LIhcmL8BQcsBUYiOfkSDRdLpvgUBzMK30cu684JPcLclYlztharvCZyNNgzJtbAiREzI9q0pI5erHCMgCw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@base-ui/utils": "0.2.8", + "@floating-ui/react-dom": "^2.1.8", + "@floating-ui/utils": "^0.2.11", + "use-sync-external-store": "^1.6.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@date-fns/tz": "^1.2.0", + "@types/react": "^17 || ^18 || ^19", + "date-fns": "^4.0.0", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@date-fns/tz": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "date-fns": { + "optional": true + } + } + }, + "node_modules/@wordpress/media-utils/node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@wordpress/media-utils/node_modules/@wordpress/ui": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@wordpress/ui/-/ui-0.11.0.tgz", + "integrity": "sha512-V1R3CTQ8MltuajZ53PCHGe9mmRwyx1RpjHA2wWOv+79dV0qQ1Y/psL0YTMY4eteL4SNAlBcjJVP66zD5O6yF8Q==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@base-ui/react": "^1.4.0", + "@wordpress/a11y": "^4.44.0", + "@wordpress/compose": "^7.44.0", + "@wordpress/element": "^6.44.0", + "@wordpress/i18n": "^6.17.0", + "@wordpress/icons": "^12.2.0", + "@wordpress/keycodes": "^4.44.0", + "@wordpress/primitives": "^4.44.0", + "@wordpress/private-apis": "^1.44.0", + "@wordpress/theme": "^0.11.0", + "clsx": "^2.1.1", + "tabbable": "^6.4.0" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@wordpress/media-utils/node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "optional": true, + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/@wordpress/notices": { "version": "5.44.0", "resolved": "https://registry.npmjs.org/@wordpress/notices/-/notices-5.44.0.tgz", @@ -12723,21 +12984,21 @@ } }, "node_modules/@wordpress/ui": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@wordpress/ui/-/ui-0.11.0.tgz", - "integrity": "sha512-V1R3CTQ8MltuajZ53PCHGe9mmRwyx1RpjHA2wWOv+79dV0qQ1Y/psL0YTMY4eteL4SNAlBcjJVP66zD5O6yF8Q==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@wordpress/ui/-/ui-0.12.0.tgz", + "integrity": "sha512-n/xfyagM90CcikLtlvNcjsFZtpt1wTpboOZPyCp9wqF6akAyJ4SUg9hXb/UA7pC8JqGe1Dg/hXJnFn/td8pvRA==", "license": "GPL-2.0-or-later", "dependencies": { - "@base-ui/react": "^1.4.0", - "@wordpress/a11y": "^4.44.0", - "@wordpress/compose": "^7.44.0", - "@wordpress/element": "^6.44.0", - "@wordpress/i18n": "^6.17.0", - "@wordpress/icons": "^12.2.0", - "@wordpress/keycodes": "^4.44.0", - "@wordpress/primitives": "^4.44.0", - "@wordpress/private-apis": "^1.44.0", - "@wordpress/theme": "^0.11.0", + "@base-ui/react": "^1.4.1", + "@wordpress/a11y": "^4.45.0", + "@wordpress/compose": "^7.45.0", + "@wordpress/element": "^6.45.0", + "@wordpress/i18n": "^6.18.0", + "@wordpress/icons": "^13.0.0", + "@wordpress/keycodes": "^4.45.0", + "@wordpress/primitives": "^4.45.0", + "@wordpress/private-apis": "^1.45.0", + "@wordpress/theme": "^0.12.0", "clsx": "^2.1.1", "tabbable": "^6.4.0" }, @@ -12801,6 +13062,24 @@ "react-dom": ">=16.8.0" } }, + "node_modules/@wordpress/ui/node_modules/@wordpress/icons": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-13.0.0.tgz", + "integrity": "sha512-+CLbvNdzMUHxQK5I6gFdHb3X6EVAH6SOSIj0xtMWm6PZO+Nnf7tXHfNBuxqTnGfxT5grtfb6D3A9ZMBU+Tpv+Q==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@wordpress/element": "^6.45.0", + "@wordpress/primitives": "^4.45.0", + "change-case": "4.1.2" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, "node_modules/@wordpress/ui/node_modules/date-fns": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", diff --git a/package.json b/package.json index 5c8e683b0..744faffd9 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "@wordpress/notices": "^5.44.0", "@wordpress/plugins": "^7.44.0", "@wordpress/primitives": "^4.45.0", - "@wordpress/ui": "^0.11.0", + "@wordpress/ui": "^0.12.0", "@wordpress/url": "^4.44.0", "@wordpress/wordcount": "^4.44.0", "react": "^18.3.1" From 2c43485e442d5c4e1b1c17c3fece09f7843aea02 Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Mon, 4 May 2026 14:06:45 +0300 Subject: [PATCH 12/20] restore rebased AI icon --- routes/ai-home/ai-icon.tsx | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/routes/ai-home/ai-icon.tsx b/routes/ai-home/ai-icon.tsx index 04c2144ed..337de51d2 100644 --- a/routes/ai-home/ai-icon.tsx +++ b/routes/ai-home/ai-icon.tsx @@ -1,33 +1,19 @@ /** * WordPress dependencies */ -import { Path, SVG } from '@wordpress/components'; +import { Path, SVG } from '@wordpress/primitives'; -export default function AIIcon() { +export default function AIIcon( { + className = 'wpai-icon', +}: { + className?: string; +} ) { return ( - - - - - + + + + + ); } From 833819e29a7c2822d58bb5cf46b48dc5f8c2e6b0 Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Mon, 4 May 2026 14:09:14 +0300 Subject: [PATCH 13/20] Leave note about margins --- routes/ai-home/style.scss | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/routes/ai-home/style.scss b/routes/ai-home/style.scss index 1b2d47819..a5a16d7ab 100644 --- a/routes/ai-home/style.scss +++ b/routes/ai-home/style.scss @@ -58,8 +58,11 @@ } .ai-showcase-card__image { + // Negative top margin to bump against top border. + // Remove margins when Card supports this natively: + // https://github.com/WordPress/gutenberg/pull/77856 margin-bottom: var(--wp-ui-card-padding); - margin-top: calc(-1 * var(--wp-ui-card-padding)); // Negative to bump against top border. + margin-top: calc(-1 * var(--wp-ui-card-padding)); img { aspect-ratio: 16 / 9; width: 100%; From c14c75197760c707f32ca3430020c8a05b4b3343 Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Mon, 4 May 2026 14:10:44 +0300 Subject: [PATCH 14/20] Use Stack instead of CSS for header toggle --- routes/ai-home/stage.tsx | 4 ++-- routes/ai-home/style.scss | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/routes/ai-home/stage.tsx b/routes/ai-home/stage.tsx index a36cc5330..617d63ad4 100644 --- a/routes/ai-home/stage.tsx +++ b/routes/ai-home/stage.tsx @@ -948,7 +948,7 @@ function AISettingsPage() { > { __( 'Contribute', 'ai' ) } -
+ -
+ } > diff --git a/routes/ai-home/style.scss b/routes/ai-home/style.scss index a5a16d7ab..f75648f59 100644 --- a/routes/ai-home/style.scss +++ b/routes/ai-home/style.scss @@ -14,11 +14,6 @@ margin-bottom: 24px; } -.ai-settings-page__global-toggle { - display: flex; - align-items: center; - gap: 4px; -} .ai-settings-page__infotip-trigger { background: none; From 2e20e9a2e4505aed0e30c0edeb756d9ced8a5a8f Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Mon, 4 May 2026 14:16:11 +0300 Subject: [PATCH 15/20] Spacing to vars --- routes/ai-home/style.scss | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/routes/ai-home/style.scss b/routes/ai-home/style.scss index f75648f59..6e433da1c 100644 --- a/routes/ai-home/style.scss +++ b/routes/ai-home/style.scss @@ -10,11 +10,6 @@ } } -.ai-settings-page__notice { - margin-bottom: 24px; -} - - .ai-settings-page__infotip-trigger { background: none; border: none; @@ -41,15 +36,15 @@ .ai-feature-settings-form { - margin-top: 4px; + margin-top: var(--wpds-dimension-padding-xs); padding-left: 40px; max-width: 480px; } .ai-section-actions { border-top: 1px solid var(--wpds-color-stroke-surface-neutral-weak); - margin-top: 16px; - padding-top: 12px; + margin-top: var(--wpds-dimension-padding-md); + padding-top: var(--wpds-dimension-padding-sm); } .ai-showcase-card__image { From 4bdb7f60fc3e7f9ad6bfbcda11ea2d82e424da54 Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Tue, 5 May 2026 17:25:01 +0300 Subject: [PATCH 16/20] Simplify Card + image --- routes/ai-home/stage.tsx | 13 ++++++++----- routes/ai-home/style.scss | 14 ++++---------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/routes/ai-home/stage.tsx b/routes/ai-home/stage.tsx index 617d63ad4..55c4180a4 100644 --- a/routes/ai-home/stage.tsx +++ b/routes/ai-home/stage.tsx @@ -600,12 +600,15 @@ function VisualCardToggle( { ! globalEnabled ? ' ai-showcase-card--disabled' : '' }` } > + { feature?.image && ( + + ) } - { feature?.image && ( - - - - ) } { field.label } Date: Thu, 7 May 2026 10:46:35 +0300 Subject: [PATCH 17/20] Finish rebase --- routes/ai-home/stage.tsx | 44 ++++++++++----------------------------- routes/ai-home/style.scss | 4 ---- 2 files changed, 11 insertions(+), 37 deletions(-) diff --git a/routes/ai-home/stage.tsx b/routes/ai-home/stage.tsx index 55c4180a4..e71df230f 100644 --- a/routes/ai-home/stage.tsx +++ b/routes/ai-home/stage.tsx @@ -596,7 +596,7 @@ function VisualCardToggle( { return ( @@ -609,34 +609,15 @@ function VisualCardToggle( { /> ) } - - { field.label } - - { field.description } - - - - { checked && ( - - { __( 'Enabled', 'ai' ) } - - ) } - - + + onChange( { [ field.id ]: value } ) + } + disabled={ ! globalEnabled } + help={ field.description } + /> ); @@ -969,10 +950,7 @@ function AISettingsPage() { > { ! PAGE_DATA.hasValidCredentials && ( - + { ! PAGE_DATA.hasCredentials ? __( diff --git a/routes/ai-home/style.scss b/routes/ai-home/style.scss index 1396866fc..c2cd11bcf 100644 --- a/routes/ai-home/style.scss +++ b/routes/ai-home/style.scss @@ -54,10 +54,6 @@ object-fit: cover; } -.ai-showcase-card__actions { - margin-top: 4px; -} - .ai-showcase-card--disabled { opacity: 0.6; } From 40409853cc54604513bdffa11c2f0e54dafac78e Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Thu, 7 May 2026 11:59:05 +0300 Subject: [PATCH 18/20] Remove reduntant image styles --- routes/ai-home/stage.tsx | 7 +------ routes/ai-home/style.scss | 7 ------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/routes/ai-home/stage.tsx b/routes/ai-home/stage.tsx index e71df230f..ba444ecdd 100644 --- a/routes/ai-home/stage.tsx +++ b/routes/ai-home/stage.tsx @@ -601,12 +601,7 @@ function VisualCardToggle( { }` } > { feature?.image && ( - + ) } Date: Thu, 7 May 2026 12:02:22 +0300 Subject: [PATCH 19/20] Clean up imports --- routes/ai-home/stage.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/routes/ai-home/stage.tsx b/routes/ai-home/stage.tsx index ba444ecdd..2e12a56f3 100644 --- a/routes/ai-home/stage.tsx +++ b/routes/ai-home/stage.tsx @@ -3,15 +3,13 @@ */ import { Page } from '@wordpress/admin-ui'; import { - Text, - Card, - Stack, - Badge, Button, - Link, + Card, Icon, + Link, Notice, Popover, + Stack, VisuallyHidden, } from '@wordpress/ui'; import { Spinner, ToggleControl } from '@wordpress/components'; From 846fe986cb43fd096e51a752e9f1a63c828bb356 Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Thu, 7 May 2026 12:05:50 +0300 Subject: [PATCH 20/20] Simplify test helpers --- tests/e2e/utils/helpers.ts | 62 +++++++++----------------------------- 1 file changed, 14 insertions(+), 48 deletions(-) diff --git a/tests/e2e/utils/helpers.ts b/tests/e2e/utils/helpers.ts index 73ae9ea59..164a90806 100644 --- a/tests/e2e/utils/helpers.ts +++ b/tests/e2e/utils/helpers.ts @@ -198,34 +198,17 @@ export const enableExperiment = async ( ) => { await visitSettingsPage( admin ); - // Visual-card features use a showcase card with an Enable/Disable button - // instead of a toggle input. - const showcaseCard = page - .locator( '.ai-showcase-card' ) - .filter( { hasText: experimentLabel } ); - - // Wait for either the showcase card or the toggle to appear. const toggle = page.getByLabel( experimentLabel ); - await expect( showcaseCard.or( toggle ) ).toBeVisible( { - timeout: 10000, - } ); - - if ( await showcaseCard.isVisible() ) { - // Already enabled if the "Enabled" badge is visible. - if ( await showcaseCard.getByText( 'Enabled' ).isVisible() ) { - return; - } + await expect( toggle ).toBeVisible( { timeout: 10000 } ); + await expect( toggle ).toBeEnabled( { timeout: 10000 } ); - await showcaseCard.getByRole( 'button', { name: 'Enable' } ).click(); - } else { - // Nothing to do if this experiment is already enabled. - if ( await toggle.isChecked() ) { - return; - } - - await toggle.check(); + // Nothing to do if this experiment is already enabled. + if ( await toggle.isChecked() ) { + return; } + await toggle.check(); + // Ensure the save was successful. await expect( page.locator( '.components-snackbar__content', { @@ -248,34 +231,17 @@ export const disableExperiment = async ( ) => { await visitSettingsPage( admin ); - // Visual-card features use a showcase card with an Enable/Disable button - // instead of a toggle input. - const showcaseCard = page - .locator( '.ai-showcase-card' ) - .filter( { hasText: experimentLabel } ); - - // Wait for either the showcase card or the toggle to appear. const toggle = page.getByLabel( experimentLabel ); - await expect( showcaseCard.or( toggle ) ).toBeVisible( { - timeout: 10000, - } ); - - if ( await showcaseCard.isVisible() ) { - // Already disabled if there's no "Enabled" badge. - if ( ! ( await showcaseCard.getByText( 'Enabled' ).isVisible() ) ) { - return; - } + await expect( toggle ).toBeVisible( { timeout: 10000 } ); + await expect( toggle ).toBeEnabled( { timeout: 10000 } ); - await showcaseCard.getByRole( 'button', { name: 'Disable' } ).click(); - } else { - // Nothing to do if this experiment is already disabled. - if ( ! ( await toggle.isChecked() ) ) { - return; - } - - await toggle.uncheck(); + // Nothing to do if this experiment is already disabled. + if ( ! ( await toggle.isChecked() ) ) { + return; } + await toggle.uncheck(); + // Ensure the save was successful. await expect( page.locator( '.components-snackbar__content', {