From fdd576880db575af9537ddfe15966493012f306a Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Tue, 12 May 2026 14:16:39 -0400 Subject: [PATCH 1/4] Support for testing unmerged upstream changes. This adds support for testing mutable tags and pull requests published by the GitHub repository. This allows contributors to test unmerged changes from upstream, or to pin a mutable tag locally (`trunk` or `wp/7.0, for example) to test the latest changes as they are made. --- tools/gutenberg/download.js | 121 ++++++++++++++++++-------- tools/gutenberg/utils.js | 163 +++++++++++++++++++++++++++++++----- 2 files changed, 230 insertions(+), 54 deletions(-) diff --git a/tools/gutenberg/download.js b/tools/gutenberg/download.js index dcca072df39bd..787ec1fc4674f 100644 --- a/tools/gutenberg/download.js +++ b/tools/gutenberg/download.js @@ -8,8 +8,13 @@ * existing gutenberg directory is removed before extraction. * * The artifact is identified by the "gutenberg.sha" value in the root - * package.json, which is used as the OCI image tag for the gutenberg-build - * package on GitHub Container Registry. + * package.json, which is used as the OCI tag for the gutenberg-wp-develop-build + * package on GitHub Container Registry. The value is normally a Git SHA, but + * may also be a mutable tag (e.g. "trunk", "pr-12345") in a pull request that + * wants to track the latest build of a stream. When the ref is a mutable tag, + * the script resolves it to the immutable SHA tag for the actual blob fetch + * and falls back to the mutable tag's manifest when the immutable tag is + * unavailable. * * @package WordPress */ @@ -19,7 +24,58 @@ const fs = require( 'fs' ); const { Writable } = require( 'stream' ); const { pipeline } = require( 'stream/promises' ); const zlib = require( 'zlib' ); -const { gutenbergDir, readGutenbergConfig } = require( './utils' ); +const { + gutenbergDir, + readGutenbergConfig, + fetchGhcrToken, + fetchManifest, +} = require( './utils' ); + +/** + * Resolve the manifest to use for downloading. + * + * For immutable refs (SHA values), the ref is used directly. + * + * For mutable refs, the mutable tag's manifest is fetched first and the + * `image.revision` annotation is read. The corresponding immutable SHA tag is + * then preferred. If the immutable SHA tag is unavailable, fall back to the + * manifest already fetched via the mutable tag. + * + * @param {{ ref: string, ghcrRepo: string, isMutable: boolean }} config + * @param {string} token + * @return {Promise<{ manifest: Object, resolvedRef: string }>} + */ +async function resolveDownloadManifest( config, token ) { + const { ref, ghcrRepo, isMutable } = config; + + const initialManifest = await fetchManifest( ref, ghcrRepo, token ); + + if ( ! isMutable ) { + return { manifest: initialManifest, resolvedRef: ref }; + } + + const revision = + initialManifest?.annotations?.[ 'org.opencontainers.image.revision' ]; + if ( ! revision ) { + console.log( + `ℹ️ No image.revision annotation on "${ ref }"; using mutable tag for download.` + ); + return { manifest: initialManifest, resolvedRef: ref }; + } + + try { + const immutableManifest = await fetchManifest( revision, ghcrRepo, token ); + return { manifest: immutableManifest, resolvedRef: revision }; + } catch ( error ) { + if ( error.status === 404 ) { + console.log( + `ℹ️ Immutable SHA tag ${ revision } unavailable; falling back to mutable tag "${ ref }".` + ); + return { manifest: initialManifest, resolvedRef: ref }; + } + throw error; + } +} /** * Main execution function. @@ -31,13 +87,17 @@ async function main() { * Read Gutenberg configuration from package.json. * * Note: ghcr stands for GitHub Container Registry where wordpress-develop ready builds of the Gutenberg plugin - * are published on every repository push event. + * are published by the Gutenberg build-plugin-zip workflow. */ - let sha, ghcrRepo; + let config; try { - ( { sha, ghcrRepo } = readGutenbergConfig() ); - console.log( ` SHA: ${ sha }` ); - console.log( ` GHCR repository: ${ ghcrRepo }` ); + config = readGutenbergConfig(); + console.log( + ` Ref: ${ config.ref }${ + config.isMutable ? ' (mutable tag)' : '' + }` + ); + console.log( ` GHCR repository: ${ config.ghcrRepo }` ); } catch ( error ) { console.error( '❌ Error reading package.json:', error.message ); process.exit( 1 ); @@ -47,45 +107,36 @@ async function main() { console.log( '\n🔑 Fetching GHCR token...' ); let token; try { - const response = await fetch( `https://ghcr.io/token?scope=repository:${ ghcrRepo }:pull&service=ghcr.io` ); - if ( ! response.ok ) { - throw new Error( `Failed to fetch token: ${ response.status } ${ response.statusText }` ); - } - const data = await response.json(); - token = data.token; - if ( ! token ) { - throw new Error( 'No token in response' ); - } + token = await fetchGhcrToken( config.ghcrRepo ); console.log( '✅ Token acquired' ); } catch ( error ) { console.error( '❌ Failed to fetch token:', error.message ); process.exit( 1 ); } - // Step 2: Get the manifest to find the blob digest. - console.log( `\n📋 Fetching manifest for ${ sha }...` ); - let digest; + // Step 2: Resolve the manifest to use for download. + console.log( `\n📋 Fetching manifest for ${ config.ref }...` ); + let manifest, resolvedRef; try { - const response = await fetch( `https://ghcr.io/v2/${ ghcrRepo }/manifests/${ sha }`, { - headers: { - Authorization: `Bearer ${ token }`, - Accept: 'application/vnd.oci.image.manifest.v1+json', - }, - } ); - if ( ! response.ok ) { - throw new Error( `Failed to fetch manifest: ${ response.status } ${ response.statusText }` ); - } - const manifest = await response.json(); - digest = manifest?.layers?.[ 0 ]?.digest; - if ( ! digest ) { - throw new Error( 'No layer digest found in manifest' ); + ( { manifest, resolvedRef } = await resolveDownloadManifest( + config, + token + ) ); + if ( resolvedRef !== config.ref ) { + console.log( ` Resolved to immutable SHA tag: ${ resolvedRef }` ); } - console.log( `✅ Blob digest: ${ digest }` ); } catch ( error ) { console.error( '❌ Failed to fetch manifest:', error.message ); process.exit( 1 ); } + const digest = manifest?.layers?.[ 0 ]?.digest; + if ( ! digest ) { + console.error( '❌ No layer digest found in manifest' ); + process.exit( 1 ); + } + console.log( `✅ Blob digest: ${ digest }` ); + // Remove existing gutenberg directory so the extraction is clean. if ( fs.existsSync( gutenbergDir ) ) { console.log( '\n🗑️ Removing existing gutenberg directory...' ); @@ -100,7 +151,7 @@ async function main() { */ console.log( `\n📥 Downloading and extracting artifact...` ); try { - const response = await fetch( `https://ghcr.io/v2/${ ghcrRepo }/blobs/${ digest }`, { + const response = await fetch( `https://ghcr.io/v2/${ config.ghcrRepo }/blobs/${ digest }`, { headers: { Authorization: `Bearer ${ token }`, }, diff --git a/tools/gutenberg/utils.js b/tools/gutenberg/utils.js index dc696d5e7bfd7..87a09ddeaabc8 100644 --- a/tools/gutenberg/utils.js +++ b/tools/gutenberg/utils.js @@ -4,8 +4,8 @@ * Gutenberg build utilities. * * Shared helpers used by the Gutenberg download script. When run directly, - * verifies that the installed Gutenberg build matches the SHA in package.json, - * and automatically downloads the correct version when needed. + * verifies that the installed Gutenberg build matches the value in + * package.json and automatically downloads the correct version when needed. * * @package WordPress */ @@ -19,18 +19,32 @@ const rootDir = path.resolve( __dirname, '../..' ); const gutenbergDir = path.join( rootDir, 'gutenberg' ); const hashFilePath = path.join( gutenbergDir, '.gutenberg-hash' ); +// A 40-character lowercase hex string is treated as an immutable Git SHA tag. +// Anything else (e.g. "trunk", "release-19.5", "pr-12345") is treated as a +// mutable tag published by the Gutenberg build-plugin-zip workflow. +const SHA_PATTERN = /^[a-f0-9]{40}$/i; + +const MANIFEST_ACCEPT = 'application/vnd.oci.image.manifest.v1+json'; + /** * Read Gutenberg configuration from package.json. * - * @return {{ sha: string, ghcrRepo: string }} The Gutenberg configuration. + * `gutenberg.sha` is always committed as a pinned SHA, but a contributor + * may temporarily set it to a mutable tag published by the Gutenberg repository + * (e.g. "trunk", "release-19.5", "pr-12345") to track the latest build of that + * stream or test changes before merging. + * + * @return {{ ref: string, ghcrRepo: string, isMutable: boolean }} The + * resolved configuration. `ref` is the OCI tag to look up; `isMutable` + * is true when the value is not a SHA-shaped string. * @throws {Error} If the configuration is missing or invalid. */ function readGutenbergConfig() { const packageJson = require( path.join( rootDir, 'package.json' ) ); - const sha = packageJson.gutenberg?.sha; + const ref = packageJson.gutenberg?.sha; const ghcrRepo = packageJson.gutenberg?.ghcrRepo; - if ( ! sha ) { + if ( ! ref ) { throw new Error( 'Missing "gutenberg.sha" in package.json' ); } @@ -38,7 +52,87 @@ function readGutenbergConfig() { throw new Error( 'Missing "gutenberg.ghcrRepo" in package.json' ); } - return { sha, ghcrRepo }; + const isMutable = ! SHA_PATTERN.test( ref ); + + return { ref, ghcrRepo, isMutable }; +} + +/** + * Fetch an anonymous pull token for the given GHCR repository. + * + * @param {string} ghcrRepo The "owner/repo/package" path on ghcr.io. + * @return {Promise} The bearer token. + */ +async function fetchGhcrToken( ghcrRepo ) { + const response = await fetch( + `https://ghcr.io/token?scope=repository:${ ghcrRepo }:pull&service=ghcr.io` + ); + if ( ! response.ok ) { + throw new Error( + `Failed to fetch GHCR token: ${ response.status } ${ response.statusText }` + ); + } + const data = await response.json(); + if ( ! data.token ) { + throw new Error( 'No token in GHCR response' ); + } + return data.token; +} + +/** + * Fetch a manifest from GHCR by tag. + * + * @param {string} ref The tag (SHA or mutable tag). + * @param {string} ghcrRepo The "owner/repo/package" path on ghcr.io. + * @param {string} token Bearer token from fetchGhcrToken. + * @return {Promise} Parsed manifest JSON. + */ +async function fetchManifest( ref, ghcrRepo, token ) { + const response = await fetch( + `https://ghcr.io/v2/${ ghcrRepo }/manifests/${ ref }`, + { + headers: { + Authorization: `Bearer ${ token }`, + Accept: MANIFEST_ACCEPT, + }, + } + ); + if ( ! response.ok ) { + const error = new Error( + `Failed to fetch manifest for "${ ref }": ${ response.status } ${ response.statusText }` + ); + error.status = response.status; + throw error; + } + return response.json(); +} + +/** + * Resolve the expected source SHA for the configured ref. + * + * For immutable refs (SHA), the expected SHA is the ref itself and no network + * call is required. For mutable refs, the manifest's + * `org.opencontainers.image.revision` annotation is fetched and returned, + * which reflects the SHA value published to the mutable tag most recently. + * + * @param {{ ref: string, ghcrRepo: string, isMutable: boolean }} config + * @return {Promise} The expected SHA. + */ +async function resolveExpectedSha( { ref, ghcrRepo, isMutable } ) { + if ( ! isMutable ) { + return ref; + } + + const token = await fetchGhcrToken( ghcrRepo ); + const manifest = await fetchManifest( ref, ghcrRepo, token ); + const revision = + manifest?.annotations?.[ 'org.opencontainers.image.revision' ]; + if ( ! revision ) { + throw new Error( + `Manifest for "${ ref }" has no org.opencontainers.image.revision annotation` + ); + } + return revision; } /** @@ -59,22 +153,42 @@ function downloadGutenberg() { } /** - * Verify that the installed Gutenberg version matches the expected SHA in - * package.json. Automatically downloads the correct version when the directory - * is missing, the hash file is absent, or the hash does not match. Logs - * progress to the console and exits with a non-zero code on failure. + * Verify that the installed Gutenberg version matches the expected SHA. + * + * For SHA refs, the expected SHA is the configured value. For mutable refs, + * the expected SHA is whatever the mutable tag currently points to in GHCR + * (read from the manifest's image.revision annotation). The installed + * `.gutenberg-hash` is compared against the expected SHA; on mismatch, a + * fresh download is triggered. */ -function verifyGutenbergVersion() { +async function verifyGutenbergVersion() { console.log( '\n🔍 Verifying Gutenberg version...' ); - let sha; + let config; try { - ( { sha } = readGutenbergConfig() ); + config = readGutenbergConfig(); } catch ( error ) { console.error( '❌ Error reading package.json:', error.message ); process.exit( 1 ); } + const { ref, isMutable } = config; + console.log( + ` Ref: ${ ref }${ isMutable ? ' (mutable tag)' : '' }` + ); + + let expectedSha; + try { + expectedSha = await resolveExpectedSha( config ); + } catch ( error ) { + console.error( '❌ Failed to resolve expected SHA:', error.message ); + process.exit( 1 ); + } + + if ( isMutable ) { + console.log( ` Latest build for "${ ref }": ${ expectedSha }` ); + } + // Check for conditions that require a fresh download. if ( ! fs.existsSync( gutenbergDir ) ) { console.log( 'ℹ️ Gutenberg directory not found. Downloading...' ); @@ -93,8 +207,8 @@ function verifyGutenbergVersion() { if ( installedHash === null ) { console.log( 'ℹ️ Hash file not found. Downloading expected version...' ); downloadGutenberg(); - } else if ( installedHash !== sha ) { - console.log( `ℹ️ Hash mismatch (found ${ installedHash }, expected ${ sha }). Downloading expected version...` ); + } else if ( installedHash !== expectedSha ) { + console.log( `ℹ️ Hash mismatch (found ${ installedHash }, expected ${ expectedSha }). Downloading expected version...` ); downloadGutenberg(); } } @@ -102,8 +216,8 @@ function verifyGutenbergVersion() { // Final verification — confirms the download (if any) produced the correct version. try { const installedHash = fs.readFileSync( hashFilePath, 'utf8' ).trim(); - if ( installedHash !== sha ) { - console.error( `❌ SHA mismatch after download: expected ${ sha } but found ${ installedHash }.` ); + if ( installedHash !== expectedSha ) { + console.error( `❌ SHA mismatch after download: expected ${ expectedSha } but found ${ installedHash }.` ); process.exit( 1 ); } } catch ( error ) { @@ -118,8 +232,19 @@ function verifyGutenbergVersion() { console.log( '✅ Version verified' ); } -module.exports = { rootDir, gutenbergDir, readGutenbergConfig, verifyGutenbergVersion }; +module.exports = { + rootDir, + gutenbergDir, + readGutenbergConfig, + verifyGutenbergVersion, + fetchGhcrToken, + fetchManifest, + resolveExpectedSha, +}; if ( require.main === module ) { - verifyGutenbergVersion(); + verifyGutenbergVersion().catch( ( error ) => { + console.error( '❌ Unexpected error:', error ); + process.exit( 1 ); + } ); } From 6b510f117b239d422e8e9323271656ac4e11c04b Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Tue, 12 May 2026 14:21:01 -0400 Subject: [PATCH 2/4] Change the pinned SHA value for testing. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bcfc78d49508a..bd97abf8a2971 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "url": "https://develop.svn.wordpress.org/trunk" }, "gutenberg": { - "sha": "c15cef1d6b07f666df28dac0383bafb0edfe0914", + "sha": "pr-78211", "ghcrRepo": "WordPress/gutenberg/gutenberg-wp-develop-build" }, "engines": { From 1d82f9b385e316ff1df0d06f7154d2fbdacb7322 Mon Sep 17 00:00:00 2001 From: "wordpress-develop-pr-bot[bot]" <1178653+wordpress-develop-pr-bot[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 18:23:58 +0000 Subject: [PATCH 3/4] Automation: Updating built files with changes. --- .../assets/script-loader-packages.php | 113 +- .../assets/script-modules-packages.php | 54 +- src/wp-includes/blocks/accordion-item.php | 1 - .../blocks/accordion-item/block.json | 1 + src/wp-includes/blocks/blocks-json.php | 82 +- src/wp-includes/blocks/button.php | 68 + src/wp-includes/blocks/button/block.json | 14 +- src/wp-includes/blocks/cover.php | 8 +- src/wp-includes/blocks/group/block.json | 7 +- src/wp-includes/blocks/home-link.php | 47 +- src/wp-includes/blocks/icon.php | 4 +- src/wp-includes/blocks/latest-posts.php | 2 +- src/wp-includes/blocks/list-item/block.json | 1 + src/wp-includes/blocks/loginout.php | 13 + src/wp-includes/blocks/navigation-link.php | 68 +- .../blocks/navigation-link/block.json | 5 + src/wp-includes/blocks/navigation-submenu.php | 76 +- src/wp-includes/blocks/navigation.php | 23 +- src/wp-includes/blocks/page-list.php | 57 +- src/wp-includes/blocks/post-date/block.json | 4 +- .../blocks/post-excerpt/block.json | 4 +- .../blocks/post-featured-image.php | 6 +- .../blocks/post-navigation-link/block.json | 4 +- src/wp-includes/blocks/post-template.php | 3 + src/wp-includes/blocks/post-title/block.json | 7 +- src/wp-includes/blocks/pullquote/block.json | 5 +- src/wp-includes/blocks/query-title.php | 2 +- src/wp-includes/blocks/query-title/block.json | 4 +- src/wp-includes/blocks/search.php | 28 +- src/wp-includes/blocks/search/block.json | 10 +- .../blocks/site-tagline/block.json | 10 +- src/wp-includes/blocks/site-title/block.json | 4 +- src/wp-includes/build/constants.php | 2 +- src/wp-includes/build/pages.php | 24 +- .../pages/font-library/page-wp-admin.php | 17 +- .../build/pages/font-library/page.php | 17 +- .../options-connectors/page-wp-admin.php | 17 +- .../build/pages/options-connectors/page.php | 17 +- src/wp-includes/build/routes.php | 95 + .../build/routes/connectors-home/content.js | 10566 +++++++++++++++- .../connectors-home/content.min.asset.php | 2 +- .../routes/connectors-home/content.min.js | 26 +- .../build/routes/font-list/content.js | 1355 +- .../routes/font-list/content.min.asset.php | 2 +- .../build/routes/font-list/content.min.js | 14 +- src/wp-includes/build/routes/registry.php | 63 + src/wp-includes/images/icon-library/tab.svg | 2 +- src/wp-includes/theme.json | 25 + 48 files changed, 11945 insertions(+), 1034 deletions(-) diff --git a/src/wp-includes/assets/script-loader-packages.php b/src/wp-includes/assets/script-loader-packages.php index 840f4ba1c8b31..d8495e012f994 100644 --- a/src/wp-includes/assets/script-loader-packages.php +++ b/src/wp-includes/assets/script-loader-packages.php @@ -4,7 +4,7 @@ 'wp-dom-ready', 'wp-i18n' ), - 'version' => 'af934e5259bc51b8718e' + 'version' => '483af07a6016f640f456' ), 'annotations.js' => array( 'dependencies' => array( @@ -13,14 +13,14 @@ 'wp-i18n', 'wp-rich-text' ), - 'version' => '4b07d06c67c3b5ea590c' + 'version' => 'd4fe1eeb787c2fd5ee89' ), 'api-fetch.js' => array( 'dependencies' => array( 'wp-i18n', 'wp-url' ), - 'version' => 'd7efe4dc1468d36c39b8' + 'version' => 'b76aeca1c88ecc790e48' ), 'autop.js' => array( 'dependencies' => array( @@ -42,6 +42,8 @@ ), 'block-directory.js' => array( 'dependencies' => array( + 'react', + 'react-dom', 'react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', @@ -59,9 +61,11 @@ 'wp-notices', 'wp-plugins', 'wp-primitives', + 'wp-private-apis', + 'wp-theme', 'wp-url' ), - 'version' => '23207f52d0d266f6e1c4' + 'version' => '43a9d7ab2fbaa04615a1' ), 'block-editor.js' => array( 'dependencies' => array( @@ -69,7 +73,6 @@ 'react-dom', 'react-jsx-runtime', 'wp-a11y', - 'wp-api-fetch', 'wp-blob', 'wp-block-serialization-default-parser', 'wp-blocks', @@ -100,11 +103,12 @@ 'wp-url', 'wp-warning' ), - 'version' => '7e969d1c58fd6b032753' + 'version' => '5a398d1da02bf80f3f98' ), 'block-library.js' => array( 'dependencies' => array( 'react', + 'react-dom', 'react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', @@ -132,6 +136,8 @@ 'wp-private-apis', 'wp-rich-text', 'wp-server-side-render', + 'wp-shortcode', + 'wp-theme', 'wp-upload-media', 'wp-url', 'wp-wordcount' @@ -142,7 +148,7 @@ 'import' => 'dynamic' ) ), - 'version' => 'bbcc73335599ce2b8d51' + 'version' => '9c1171e882b2ba2f7411' ), 'block-serialization-default-parser.js' => array( 'dependencies' => array( @@ -175,7 +181,7 @@ 'wp-shortcode', 'wp-warning' ), - 'version' => 'ef38e42500165bfda301' + 'version' => 'ece1f172d5b708916ebc' ), 'commands.js' => array( 'dependencies' => array( @@ -187,10 +193,11 @@ 'wp-element', 'wp-i18n', 'wp-keyboard-shortcuts', + 'wp-preferences', 'wp-primitives', 'wp-private-apis' ), - 'version' => 'e3d8bba53f4ffea4fcd2' + 'version' => '8b8663311faa33540c1b' ), 'components.js' => array( 'dependencies' => array( @@ -214,7 +221,7 @@ 'wp-rich-text', 'wp-warning' ), - 'version' => '5dedfe13f08880193a28' + 'version' => '83936472a0d07a3a4c92' ), 'compose.js' => array( 'dependencies' => array( @@ -228,7 +235,7 @@ 'wp-priority-queue', 'wp-undo-manager' ), - 'version' => 'edb5a8c0b5bf71686403' + 'version' => '2b5a9d090a41c1120be7' ), 'core-commands.js' => array( 'dependencies' => array( @@ -245,7 +252,7 @@ 'wp-router', 'wp-url' ), - 'version' => 'b209152e7e51279d7c28' + 'version' => 'c5adbb84012bd7834c04' ), 'core-data.js' => array( 'dependencies' => array( @@ -257,20 +264,23 @@ 'wp-data', 'wp-deprecated', 'wp-element', - 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-private-apis', 'wp-rich-text', + 'wp-sync', 'wp-undo-manager', 'wp-url', 'wp-warning' ), - 'version' => '515bcc5a2962232ccea7' + 'version' => '21fd0114d22869dbe459' ), 'customize-widgets.js' => array( 'dependencies' => array( + 'react', + 'react-dom', 'react-jsx-runtime', + 'wp-a11y', 'wp-block-editor', 'wp-block-library', 'wp-blocks', @@ -289,9 +299,10 @@ 'wp-preferences', 'wp-primitives', 'wp-private-apis', + 'wp-theme', 'wp-widgets' ), - 'version' => '524dc7a4326b77064831' + 'version' => '4da0091c281df82bd222' ), 'data.js' => array( 'dependencies' => array( @@ -304,7 +315,7 @@ 'wp-private-apis', 'wp-redux-routine' ), - 'version' => 'dc7feb6ad8da53887680' + 'version' => 'ee4e907a070c9780da2b' ), 'data-controls.js' => array( 'dependencies' => array( @@ -319,7 +330,7 @@ 'moment', 'wp-deprecated' ), - 'version' => 'c9f8e7dd3232716f34e9' + 'version' => '2faaf49020b2074de156' ), 'deprecated.js' => array( 'dependencies' => array( @@ -331,7 +342,7 @@ 'dependencies' => array( 'wp-deprecated' ), - 'version' => '66a6cf58e0c4cd128af0' + 'version' => '1acdd4ebd6969685a9d3' ), 'dom-ready.js' => array( 'dependencies' => array( @@ -381,7 +392,7 @@ 'import' => 'static' ) ), - 'version' => '69ec189de328df478ab5' + 'version' => '063a9db26950e8524cf0' ), 'edit-site.js' => array( 'dependencies' => array( @@ -409,6 +420,7 @@ 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', + 'wp-media-utils', 'wp-notices', 'wp-patterns', 'wp-plugins', @@ -420,7 +432,8 @@ 'wp-theme', 'wp-url', 'wp-warning', - 'wp-widgets' + 'wp-widgets', + 'wp-wordcount' ), 'module_dependencies' => array( array( @@ -428,7 +441,7 @@ 'import' => 'static' ) ), - 'version' => '34fbf7f8c7d55055d9cd' + 'version' => '25ce07d8e96c49452e7a' ), 'edit-widgets.js' => array( 'dependencies' => array( @@ -469,7 +482,7 @@ 'import' => 'static' ) ), - 'version' => '899c5ac5dcb94e19d378' + 'version' => '3382b8166d24bc8ebc42' ), 'editor.js' => array( 'dependencies' => array( @@ -519,7 +532,7 @@ 'import' => 'static' ) ), - 'version' => 'f8cdc22abc621b3f9409' + 'version' => '3721e7b82c14b894cf2e' ), 'element.js' => array( 'dependencies' => array( @@ -527,7 +540,7 @@ 'react-dom', 'wp-escape-html' ), - 'version' => '15ba804677f72a8db97b' + 'version' => 'ce395381f7d64d2a6d71' ), 'escape-html.js' => array( 'dependencies' => array( @@ -537,6 +550,8 @@ ), 'format-library.js' => array( 'dependencies' => array( + 'react', + 'react-dom', 'react-jsx-runtime', 'wp-a11y', 'wp-block-editor', @@ -549,6 +564,7 @@ 'wp-primitives', 'wp-private-apis', 'wp-rich-text', + 'wp-theme', 'wp-url' ), 'module_dependencies' => array( @@ -557,7 +573,7 @@ 'import' => 'dynamic' ) ), - 'version' => 'f89be9586f2d9ce4545a' + 'version' => 'b38d376fe79b3eac1578' ), 'hooks.js' => array( 'dependencies' => array( @@ -575,7 +591,7 @@ 'dependencies' => array( 'wp-hooks' ), - 'version' => '781d11515ad3d91786ec' + 'version' => '125448662852c5e18937' ), 'is-shallow-equal.js' => array( 'dependencies' => array( @@ -590,7 +606,7 @@ 'wp-element', 'wp-keycodes' ), - 'version' => '2ed78d3b4c23f38804e0' + 'version' => '0dd268b2132a3f82b1d4' ), 'keycodes.js' => array( 'dependencies' => array( @@ -608,7 +624,7 @@ 'wp-element', 'wp-i18n' ), - 'version' => '2e35ebd5dbaccb5a90c5' + 'version' => 'a44da9be02cdfef6e44d' ), 'media-utils.js' => array( 'dependencies' => array( @@ -628,13 +644,14 @@ 'wp-i18n', 'wp-keycodes', 'wp-notices', + 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-theme', 'wp-url', 'wp-warning' ), - 'version' => '85f1375ab5f23cd5d13c' + 'version' => '744ed1f36d9fc95adf3f' ), 'notices.js' => array( 'dependencies' => array( @@ -642,7 +659,7 @@ 'wp-components', 'wp-data' ), - 'version' => '218d0173a31ae7269246' + 'version' => '1869781df3f0e4f0c6b8' ), 'nux.js' => array( 'dependencies' => array( @@ -655,7 +672,7 @@ 'wp-i18n', 'wp-primitives' ), - 'version' => '14d2335a0007b36b9112' + 'version' => 'ee8845ac5a9ad98ee3f7' ), 'patterns.js' => array( 'dependencies' => array( @@ -687,7 +704,7 @@ 'wp-is-shallow-equal', 'wp-primitives' ), - 'version' => '72e3cf01c2b3535a9432' + 'version' => '9bce3a8f6306f5380b9a' ), 'preferences.js' => array( 'dependencies' => array( @@ -703,7 +720,7 @@ 'wp-primitives', 'wp-private-apis' ), - 'version' => '035813168e404aa30193' + 'version' => '6595a0115a9c144c0f3a' ), 'preferences-persistence.js' => array( 'dependencies' => array( @@ -728,7 +745,7 @@ 'dependencies' => array( ), - 'version' => '835912f0086b9e59aed4' + 'version' => 'ebe55c7ec838043537c7' ), 'react-i18n.js' => array( 'dependencies' => array( @@ -758,7 +775,7 @@ 'wp-primitives', 'wp-url' ), - 'version' => '21d86e46535b79d9afda' + 'version' => '372c845659b9a298e4fb' ), 'rich-text.js' => array( 'dependencies' => array( @@ -773,7 +790,7 @@ 'wp-keycodes', 'wp-private-apis' ), - 'version' => '16449e6108f48327f368' + 'version' => '1b3e411a54ef29d2bf7a' ), 'router.js' => array( 'dependencies' => array( @@ -809,7 +826,15 @@ 'dependencies' => array( ), - 'version' => 'faa37ce61b7ec8394b2a' + 'version' => '10a88969c2fbccc89f91' + ), + 'sync.js' => array( + 'dependencies' => array( + 'wp-api-fetch', + 'wp-hooks', + 'wp-private-apis' + ), + 'version' => '63df27e4e1555a2ed89e' ), 'theme.js' => array( 'dependencies' => array( @@ -817,7 +842,7 @@ 'wp-element', 'wp-private-apis' ), - 'version' => 'e22ce547a4420507b323' + 'version' => '3b1949512f2ec0c938bd' ), 'token-list.js' => array( 'dependencies' => array( @@ -845,21 +870,21 @@ 'module_dependencies' => array( ), - 'version' => 'd359c2cccf866d7082d2' + 'version' => '1399274c1ad48fc29498' ), 'url.js' => array( 'dependencies' => array( ), - 'version' => 'bb0f766c3d2efe497871' + 'version' => '9dd5f16a5ce37bf4ba2c' ), 'viewport.js' => array( 'dependencies' => array( - 'react-jsx-runtime', 'wp-compose', - 'wp-data' + 'wp-data', + 'wp-element' ), - 'version' => '8614025b8075d220d78f' + 'version' => '97845df4d1a7269c5c2b' ), 'warning.js' => array( 'dependencies' => array( @@ -882,7 +907,7 @@ 'wp-notices', 'wp-primitives' ), - 'version' => '02b8dd683bc610f979fa' + 'version' => '3ab93e442c755a6b2b4e' ), 'wordcount.js' => array( 'dependencies' => array( diff --git a/src/wp-includes/assets/script-modules-packages.php b/src/wp-includes/assets/script-modules-packages.php index a3f51229f1e63..5bdc29f0e74eb 100644 --- a/src/wp-includes/assets/script-modules-packages.php +++ b/src/wp-includes/assets/script-modules-packages.php @@ -34,7 +34,7 @@ 'import' => 'static' ) ), - 'version' => '2af01b43d30739c3fb8d' + 'version' => 'f77b871ece5a791f449e' ), 'block-library/file/view.js' => array( 'dependencies' => array( @@ -46,7 +46,7 @@ 'import' => 'static' ) ), - 'version' => '7d4d261d10dca47ebecb' + 'version' => 'a9114a756e418400594c' ), 'block-library/form/view.js' => array( 'dependencies' => array( @@ -88,7 +88,7 @@ 'import' => 'static' ) ), - 'version' => '99f747d731f80246db11' + 'version' => '1ecf748f10b95c76b349' ), 'block-library/query/view.js' => array( 'dependencies' => array( @@ -166,7 +166,7 @@ 'import' => 'static' ) ), - 'version' => '42d3f09bba14cce3054d' + 'version' => '5e02fdb03b9e05e7ba82' ), 'connectors/index.js' => array( 'dependencies' => array( @@ -177,7 +177,41 @@ 'wp-i18n', 'wp-private-apis' ), - 'version' => '274797868955a828dfdc' + 'version' => 'dce5e2b0fc240815717b' + ), + 'content-types/index.js' => array( + 'dependencies' => array( + 'react', + 'react-dom', + 'react-jsx-runtime', + 'wp-components', + 'wp-compose', + 'wp-core-data', + 'wp-data', + 'wp-date', + 'wp-deprecated', + 'wp-element', + 'wp-i18n', + 'wp-is-shallow-equal', + 'wp-keycodes', + 'wp-notices', + 'wp-primitives', + 'wp-private-apis', + 'wp-theme', + 'wp-url', + 'wp-warning' + ), + 'module_dependencies' => array( + array( + 'id' => '@wordpress/a11y', + 'import' => 'static' + ), + array( + 'id' => '@wordpress/route', + 'import' => 'static' + ) + ), + 'version' => '36356fde364419c241ea' ), 'core-abilities/index.js' => array( 'dependencies' => array( @@ -205,13 +239,13 @@ 'import' => 'static' ) ), - 'version' => 'e57f44d1a9f69e75d2d9' + 'version' => '3e9b6e117adbaf70a10f' ), 'interactivity/index.js' => array( 'dependencies' => array( ), - 'version' => '4d2a3a72c7410d548881' + 'version' => 'efaa5193bbad9c60ffd1' ), 'interactivity-router/full-page.js' => array( 'dependencies' => array( @@ -273,7 +307,7 @@ 'wp-private-apis', 'wp-style-engine' ), - 'version' => '30ab62f45bfe9f971ea0' + 'version' => '8bd91519756b243fc835' ), 'route/index.js' => array( 'dependencies' => array( @@ -282,7 +316,7 @@ 'react-jsx-runtime', 'wp-private-apis' ), - 'version' => 'c5843b6c5e84b352f43b' + 'version' => '48a77bfa70722b4254e4' ), 'workflow/index.js' => array( 'dependencies' => array( @@ -303,6 +337,6 @@ 'import' => 'static' ) ), - 'version' => '13556bc597bbf2a8d620' + 'version' => 'c1055ffa9d3634a7dfe7' ) ); \ No newline at end of file diff --git a/src/wp-includes/blocks/accordion-item.php b/src/wp-includes/blocks/accordion-item.php index a16a1426e346d..8530b34de12d8 100644 --- a/src/wp-includes/blocks/accordion-item.php +++ b/src/wp-includes/blocks/accordion-item.php @@ -39,7 +39,6 @@ function block_core_accordion_item_render( array $attributes, string $content ): if ( $p->next_tag( array( 'class_name' => 'wp-block-accordion-heading__toggle' ) ) ) { $p->set_attribute( 'data-wp-on--click', 'actions.toggle' ); - $p->set_attribute( 'data-wp-on--keydown', 'actions.handleKeyDown' ); $p->set_attribute( 'id', $unique_id ); $p->set_attribute( 'aria-controls', $unique_id . '-panel' ); $p->set_attribute( 'data-wp-bind--aria-expanded', 'state.isOpen' ); diff --git a/src/wp-includes/blocks/accordion-item/block.json b/src/wp-includes/blocks/accordion-item/block.json index 74bfddde0e68b..22987b9558a5f 100644 --- a/src/wp-includes/blocks/accordion-item/block.json +++ b/src/wp-includes/blocks/accordion-item/block.json @@ -16,6 +16,7 @@ "interactivity": true, "spacing": { "margin": [ "top", "bottom" ], + "padding": true, "blockGap": true }, "__experimentalBorder": { diff --git a/src/wp-includes/blocks/blocks-json.php b/src/wp-includes/blocks/blocks-json.php index e905b113502ac..e35268ffe6c74 100644 --- a/src/wp-includes/blocks/blocks-json.php +++ b/src/wp-includes/blocks/blocks-json.php @@ -224,6 +224,7 @@ 'top', 'bottom' ), + 'padding' => true, 'blockGap' => true ), '__experimentalBorder' => array( @@ -759,9 +760,6 @@ ), 'gradient' => array( 'type' => 'string' - ), - 'width' => array( - 'type' => 'number' ) ), 'supports' => array( @@ -777,6 +775,15 @@ 'text' => true ) ), + 'dimensions' => array( + 'width' => true, + '__experimentalSkipSerialization' => array( + 'width' + ), + '__experimentalDefaultControls' => array( + 'width' => true + ) + ), 'typography' => array( '__experimentalSkipSerialization' => array( 'fontSize', @@ -851,6 +858,10 @@ 'root' => '.wp-block-button .wp-block-button__link', 'typography' => array( 'writingMode' => '.wp-block-button' + ), + 'dimensions' => array( + 'root' => '.wp-block-button', + 'width' => '.wp-block-button' ) ) ), @@ -2865,8 +2876,10 @@ 'background' => array( 'backgroundImage' => true, 'backgroundSize' => true, + 'gradient' => true, '__experimentalDefaultControls' => array( - 'backgroundImage' => true + 'backgroundImage' => true, + 'gradient' => true ) ), 'color' => array( @@ -2893,7 +2906,8 @@ ) ), 'dimensions' => array( - 'minHeight' => true + 'minHeight' => true, + 'minWidth' => true ), '__experimentalBorder' => array( 'color' => true, @@ -3711,6 +3725,7 @@ ), 'supports' => array( 'anchor' => true, + 'html' => false, 'className' => false, 'splitting' => true, '__experimentalBorder' => array( @@ -4378,6 +4393,11 @@ 'clientNavigation' => true ) ), + 'selectors' => array( + 'states' => array( + '@current' => '.wp-block-navigation .current-menu-item' + ) + ), 'editorStyle' => 'wp-block-navigation-link-editor', 'style' => 'wp-block-navigation-link' ), @@ -5348,9 +5368,6 @@ 'type' => 'string', 'role' => 'content' ), - 'textAlign' => array( - 'type' => 'string' - ), 'format' => array( 'type' => 'string' ), @@ -5387,6 +5404,7 @@ 'typography' => array( 'fontSize' => true, 'lineHeight' => true, + 'textAlign' => true, '__experimentalFontFamily' => true, '__experimentalFontWeight' => true, '__experimentalFontStyle' => true, @@ -5423,9 +5441,6 @@ 'description' => 'Display the excerpt.', 'textdomain' => 'default', 'attributes' => array( - 'textAlign' => array( - 'type' => 'string' - ), 'moreText' => array( 'type' => 'string', 'role' => 'content' @@ -5466,6 +5481,7 @@ 'typography' => array( 'fontSize' => true, 'lineHeight' => true, + 'textAlign' => true, 'textColumns' => true, '__experimentalFontFamily' => true, '__experimentalFontWeight' => true, @@ -5624,9 +5640,6 @@ 'description' => 'Displays the next or previous post link that is adjacent to the current post.', 'textdomain' => 'default', 'attributes' => array( - 'textAlign' => array( - 'type' => 'string' - ), 'type' => array( 'type' => 'string', 'default' => 'next' @@ -5665,6 +5678,7 @@ 'typography' => array( 'fontSize' => true, 'lineHeight' => true, + 'textAlign' => true, '__experimentalFontFamily' => true, '__experimentalFontWeight' => true, '__experimentalFontStyle' => true, @@ -5922,9 +5936,6 @@ 'queryId' ), 'attributes' => array( - 'textAlign' => array( - 'type' => 'string' - ), 'level' => array( 'type' => 'number', 'default' => 2 @@ -5947,6 +5958,9 @@ 'type' => 'string', 'default' => '_self', 'role' => 'content' + ), + 'placeholder' => array( + 'type' => 'string' ) ), 'example' => array( @@ -5975,6 +5989,7 @@ 'typography' => array( 'fontSize' => true, 'lineHeight' => true, + 'textAlign' => true, '__experimentalFontFamily' => true, '__experimentalFontWeight' => true, '__experimentalFontStyle' => true, @@ -6114,10 +6129,7 @@ ) ), 'dimensions' => array( - 'minHeight' => true, - '__experimentalDefaultControls' => array( - 'minHeight' => false - ) + 'minHeight' => true ), 'spacing' => array( 'margin' => true, @@ -6523,9 +6535,6 @@ 'type' => array( 'type' => 'string' ), - 'textAlign' => array( - 'type' => 'string' - ), 'level' => array( 'type' => 'number', 'default' => 1 @@ -6571,6 +6580,7 @@ 'typography' => array( 'fontSize' => true, 'lineHeight' => true, + 'textAlign' => true, '__experimentalFontFamily' => true, '__experimentalFontStyle' => true, '__experimentalFontWeight' => true, @@ -6984,10 +6994,6 @@ 'default' => array( ) - ), - 'isSearchFieldHidden' => array( - 'type' => 'boolean', - 'default' => false ) ), 'supports' => array( @@ -7038,7 +7044,11 @@ 'html' => false ), 'editorStyle' => 'wp-block-search-editor', - 'style' => 'wp-block-search' + 'style' => 'wp-block-search', + 'selectors' => array( + 'color' => '.wp-block-search .wp-block-search__button, .wp-block-search.wp-block-search__no-button .wp-block-search__input', + 'border' => '.wp-block-search.wp-block-search__button-outside .wp-block-search__input, .wp-block-search.wp-block-search__button-outside .wp-block-search__button, .wp-block-search.wp-block-search__no-button .wp-block-search__input, .wp-block-search.wp-block-search__button-only .wp-block-search__input, .wp-block-search.wp-block-search__button-only .wp-block-search__button, .wp-block-search.wp-block-search__button-inside .wp-block-search__inside-wrapper' + ) ), 'separator' => array( '$schema' => 'https://schemas.wp.org/trunk/block.json', @@ -7224,9 +7234,6 @@ ), 'textdomain' => 'default', 'attributes' => array( - 'textAlign' => array( - 'type' => 'string' - ), 'level' => array( 'type' => 'number', 'default' => 0 @@ -7247,7 +7254,11 @@ 'example' => array( 'viewportWidth' => 350, 'attributes' => array( - 'textAlign' => 'center' + 'style' => array( + 'typography' => array( + 'textAlign' => 'center' + ) + ) ) ), 'supports' => array( @@ -7276,6 +7287,7 @@ 'typography' => array( 'fontSize' => true, 'lineHeight' => true, + 'textAlign' => true, '__experimentalFontFamily' => true, '__experimentalTextTransform' => true, '__experimentalTextDecoration' => true, @@ -7325,9 +7337,6 @@ 6 ) ), - 'textAlign' => array( - 'type' => 'string' - ), 'isLink' => array( 'type' => 'boolean', 'default' => true, @@ -7369,6 +7378,7 @@ 'typography' => array( 'fontSize' => true, 'lineHeight' => true, + 'textAlign' => true, '__experimentalFontFamily' => true, '__experimentalTextTransform' => true, '__experimentalTextDecoration' => true, diff --git a/src/wp-includes/blocks/button.php b/src/wp-includes/blocks/button.php index 0d03440b1cb0f..8a7b43a2df315 100644 --- a/src/wp-includes/blocks/button.php +++ b/src/wp-includes/blocks/button.php @@ -60,6 +60,74 @@ function render_block_core_button( $attributes, $content ) { return ''; } + $width = $attributes['style']['dimensions']['width'] ?? null; + + if ( $width ) { + // Resolve preset references to their actual values. + $resolved_width = $width; + $is_preset = str_starts_with( $width, 'var:preset|dimension|' ); + + if ( $is_preset ) { + $slug = substr( $width, strlen( 'var:preset|dimension|' ) ); + $dimension_presets = wp_get_global_settings( + array( 'dimensions', 'dimensionSizes' ), + array( 'block_name' => 'core/button' ) + ); + + // Search origins in priority order: custom > theme > default. + if ( is_array( $dimension_presets ) ) { + foreach ( array( 'custom', 'theme', 'default' ) as $origin ) { + if ( empty( $dimension_presets[ $origin ] ) || ! is_array( $dimension_presets[ $origin ] ) ) { + continue; + } + foreach ( $dimension_presets[ $origin ] as $preset ) { + if ( isset( $preset['slug'] ) && $preset['slug'] === $slug ) { + $resolved_width = $preset['size'] ?? $width; + break 2; + } + } + } + } + } + + $is_percentage = str_ends_with( $resolved_width, '%' ); + + $processor = new WP_HTML_Tag_Processor( $content ); + // Target the outer wrapper div. + if ( $processor->next_tag( array( 'class_name' => 'wp-block-button' ) ) ) { + $processor->add_class( 'has-custom-width' ); + $existing_style = $processor->get_attribute( 'style' ); + $existing_style = is_string( $existing_style ) ? $existing_style : ''; + + if ( $is_percentage ) { + $numeric_width = (float) $resolved_width; + $processor->add_class( 'wp-block-button__width' ); + + // Maintain legacy class for the standard percentage widths. + $legacy_widths = array( + '25%' => 'wp-block-button__width-25', + '50%' => 'wp-block-button__width-50', + '75%' => 'wp-block-button__width-75', + '100%' => 'wp-block-button__width-100', + ); + if ( isset( $legacy_widths[ $resolved_width ] ) ) { + $processor->add_class( $legacy_widths[ $resolved_width ] ); + } + + $width_style = "--wp--block-button--width: $numeric_width;"; + $processor->set_attribute( 'style', $width_style . ( $existing_style ? ' ' . $existing_style : '' ) ); + } else { + $css_value = $is_preset + ? 'var(--wp--preset--dimension--' . _wp_to_kebab_case( $slug ) . ')' + : $width; + $width_style = "width: $css_value;"; + $processor->set_attribute( 'style', $width_style . ( $existing_style ? ' ' . $existing_style : '' ) ); + } + + $content = $processor->get_updated_html(); + } + } + return $content; } diff --git a/src/wp-includes/blocks/button/block.json b/src/wp-includes/blocks/button/block.json index 50ba4cda9c688..2e23a64c8f559 100644 --- a/src/wp-includes/blocks/button/block.json +++ b/src/wp-includes/blocks/button/block.json @@ -63,9 +63,6 @@ }, "gradient": { "type": "string" - }, - "width": { - "type": "number" } }, "supports": { @@ -81,6 +78,13 @@ "text": true } }, + "dimensions": { + "width": true, + "__experimentalSkipSerialization": [ "width" ], + "__experimentalDefaultControls": { + "width": true + } + }, "typography": { "__experimentalSkipSerialization": [ "fontSize", @@ -145,6 +149,10 @@ "root": ".wp-block-button .wp-block-button__link", "typography": { "writingMode": ".wp-block-button" + }, + "dimensions": { + "root": ".wp-block-button", + "width": ".wp-block-button" } } } diff --git a/src/wp-includes/blocks/cover.php b/src/wp-includes/blocks/cover.php index 8da5db23ddc3f..16533acacd764 100644 --- a/src/wp-includes/blocks/cover.php +++ b/src/wp-includes/blocks/cover.php @@ -39,13 +39,13 @@ function render_block_core_cover( $attributes, $content ) { $lower_src = strtolower( $iframe_src ); $provider = null; - if ( strpos( $lower_src, 'youtube.com' ) !== false || strpos( $lower_src, 'youtu.be' ) !== false ) { + if ( str_contains( $lower_src, 'youtube.com' ) || str_contains( $lower_src, 'youtu.be' ) ) { $provider = 'youtube'; - } elseif ( strpos( $lower_src, 'vimeo.com' ) !== false ) { + } elseif ( str_contains( $lower_src, 'vimeo.com' ) ) { $provider = 'vimeo'; - } elseif ( strpos( $lower_src, 'videopress.com' ) !== false ) { + } elseif ( str_contains( $lower_src, 'videopress.com' ) ) { $provider = 'videopress'; - } elseif ( strpos( $lower_src, 'wordpress.tv' ) !== false ) { + } elseif ( str_contains( $lower_src, 'wordpress.tv' ) ) { $provider = 'wordpress-tv'; } diff --git a/src/wp-includes/blocks/group/block.json b/src/wp-includes/blocks/group/block.json index e83fb60d31fc7..7fa2ad2ccf4c7 100644 --- a/src/wp-includes/blocks/group/block.json +++ b/src/wp-includes/blocks/group/block.json @@ -28,8 +28,10 @@ "background": { "backgroundImage": true, "backgroundSize": true, + "gradient": true, "__experimentalDefaultControls": { - "backgroundImage": true + "backgroundImage": true, + "gradient": true } }, "color": { @@ -53,7 +55,8 @@ } }, "dimensions": { - "minHeight": true + "minHeight": true, + "minWidth": true }, "__experimentalBorder": { "color": true, diff --git a/src/wp-includes/blocks/home-link.php b/src/wp-includes/blocks/home-link.php index d61aa0bc235e2..7ae02ed266f0b 100644 --- a/src/wp-includes/blocks/home-link.php +++ b/src/wp-includes/blocks/home-link.php @@ -5,6 +5,8 @@ * @package WordPress */ +require_once __DIR__ . '/navigation-link/shared/build-css-font-sizes.php'; + /** * Build an array with CSS classes and inline styles defining the colors * which will be applied to the home link markup in the front-end. @@ -59,36 +61,6 @@ function block_core_home_link_build_css_colors( $context ) { return $colors; } -/** - * Build an array with CSS classes and inline styles defining the font sizes - * which will be applied to the home link markup in the front-end. - * - * @since 6.0.0 - * - * @param array $context Home link block context. - * @return array Font size CSS classes and inline styles. - */ -function block_core_home_link_build_css_font_sizes( $context ) { - // CSS classes. - $font_sizes = array( - 'css_classes' => array(), - 'inline_styles' => '', - ); - - $has_named_font_size = array_key_exists( 'fontSize', $context ); - $has_custom_font_size = isset( $context['style']['typography']['fontSize'] ); - - if ( $has_named_font_size ) { - // Add the font size class. - $font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $context['fontSize'] ); - } elseif ( $has_custom_font_size ) { - // Add the custom font size inline style. - $font_sizes['inline_styles'] = sprintf( 'font-size: %s;', $context['style']['typography']['fontSize'] ); - } - - return $font_sizes; -} - /** * Builds an array with classes and style for the li wrapper * @@ -98,12 +70,21 @@ function block_core_home_link_build_css_font_sizes( $context ) { * @return string The li wrapper attributes. */ function block_core_home_link_build_li_wrapper_attributes( $context ) { - $colors = block_core_home_link_build_css_colors( $context ); - $font_sizes = block_core_home_link_build_css_font_sizes( $context ); - $classes = array_merge( + $colors = block_core_home_link_build_css_colors( $context ); + // The build system prefixes this function with "gutenberg_" to avoid + // collisions with the core version. Until this function is backported to + // core, we need to guard it's use and only call the prefixed name in + // the plugin. + if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { + $font_sizes = gutenberg_block_core_shared_navigation_build_css_font_sizes( $context ); + } else { + $font_sizes = block_core_shared_navigation_build_css_font_sizes( $context ); + } + $classes = array_merge( $colors['css_classes'], $font_sizes['css_classes'] ); + $style_attribute = ( $colors['inline_styles'] . $font_sizes['inline_styles'] ); $classes[] = 'wp-block-navigation-item'; diff --git a/src/wp-includes/blocks/icon.php b/src/wp-includes/blocks/icon.php index e09319cffea3b..1b7a27a147698 100644 --- a/src/wp-includes/blocks/icon.php +++ b/src/wp-includes/blocks/icon.php @@ -10,9 +10,7 @@ * * @since 7.0.0 * - * @param array $attributes The block attributes. - * @param string $content The block content. - * @param WP_Block $block The block instance. + * @param array $attributes The block attributes. * * @return string Returns the Icon. */ diff --git a/src/wp-includes/blocks/latest-posts.php b/src/wp-includes/blocks/latest-posts.php index 44231ac6d14a1..c829852f8cfde 100644 --- a/src/wp-includes/blocks/latest-posts.php +++ b/src/wp-includes/blocks/latest-posts.php @@ -163,7 +163,7 @@ function render_block_core_latest_posts( $attributes ) { $trimmed_excerpt = substr( $trimmed_excerpt, 0, -11 ); $trimmed_excerpt .= sprintf( /* translators: 1: A URL to a post, 2: Hidden accessibility text: Post title */ - __( '… Read more: %2$s' ), + __( '… Read more: %2$s' ), esc_url( $post_link ), esc_html( $title ) ); diff --git a/src/wp-includes/blocks/list-item/block.json b/src/wp-includes/blocks/list-item/block.json index 1cdba86f19b2e..cdefd6c232bf3 100644 --- a/src/wp-includes/blocks/list-item/block.json +++ b/src/wp-includes/blocks/list-item/block.json @@ -21,6 +21,7 @@ }, "supports": { "anchor": true, + "html": false, "className": false, "splitting": true, "__experimentalBorder": { diff --git a/src/wp-includes/blocks/loginout.php b/src/wp-includes/blocks/loginout.php index f83d8be424ece..a9e05f8630bfe 100644 --- a/src/wp-includes/blocks/loginout.php +++ b/src/wp-includes/blocks/loginout.php @@ -38,6 +38,19 @@ function render_block_core_loginout( $attributes ) { // Get the form. $contents = wp_login_form( array( 'echo' => false ) ); + + if ( wp_is_block_theme() ) { + $processor = new WP_HTML_Tag_Processor( $contents ); + + while ( $processor->next_tag( 'input' ) ) { + if ( 'submit' === $processor->get_attribute( 'type' ) && 'wp-submit' === $processor->get_attribute( 'name' ) ) { + $processor->add_class( 'wp-block-button__link' ); + $processor->add_class( wp_theme_get_element_class_name( 'button' ) ); + $contents = $processor->get_updated_html(); + break; + } + } + } } $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $classes ) ); diff --git a/src/wp-includes/blocks/navigation-link.php b/src/wp-includes/blocks/navigation-link.php index 0888d7b5acebd..f92a2ff344e50 100644 --- a/src/wp-includes/blocks/navigation-link.php +++ b/src/wp-includes/blocks/navigation-link.php @@ -5,14 +5,9 @@ * @package WordPress */ -// Path differs between source and build: './shared/' in source, './navigation-link/shared/' in build. -if ( file_exists( __DIR__ . '/shared/item-should-render.php' ) ) { - require_once __DIR__ . '/shared/item-should-render.php'; - require_once __DIR__ . '/shared/render-submenu-icon.php'; -} else { - require_once __DIR__ . '/navigation-link/shared/item-should-render.php'; - require_once __DIR__ . '/navigation-link/shared/render-submenu-icon.php'; -} +require_once __DIR__ . '/navigation-link/shared/item-should-render.php'; +require_once __DIR__ . '/navigation-link/shared/render-submenu-icon.php'; +require_once __DIR__ . '/navigation-link/shared/build-css-font-sizes.php'; /** * Build an array with CSS classes and inline styles defining the colors @@ -86,43 +81,6 @@ function block_core_navigation_link_build_css_colors( $context, $attributes, $is return $colors; } -/** - * Build an array with CSS classes and inline styles defining the font sizes - * which will be applied to the navigation markup in the front-end. - * - * @since 5.9.0 - * - * @param array $context Navigation block context. - * @return array Font size CSS classes and inline styles. - */ -function block_core_navigation_link_build_css_font_sizes( $context ) { - // CSS classes. - $font_sizes = array( - 'css_classes' => array(), - 'inline_styles' => '', - ); - - $has_named_font_size = array_key_exists( 'fontSize', $context ); - $has_custom_font_size = isset( $context['style']['typography']['fontSize'] ); - - if ( $has_named_font_size ) { - // Add the font size class. - $font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $context['fontSize'] ); - } elseif ( $has_custom_font_size ) { - // Add the custom font size inline style. - $font_sizes['inline_styles'] = sprintf( - 'font-size: %s;', - wp_get_typography_font_size_value( - array( - 'size' => $context['style']['typography']['fontSize'], - ) - ) - ); - } - - return $font_sizes; -} - /** * Decodes a url if it's encoded, returning the same url if not. * @@ -180,7 +138,15 @@ function render_block_core_navigation_link( $attributes, $content, $block ) { return ''; } - $font_sizes = block_core_navigation_link_build_css_font_sizes( $block->context ); + // The build system prefixes this function with "gutenberg_" to avoid + // collisions with the core version. Until this function is backported to + // core, we need to guard its use and only call the prefixed name in + // the plugin. + if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { + $font_sizes = gutenberg_block_core_shared_navigation_build_css_font_sizes( $block->context ); + } else { + $font_sizes = block_core_shared_navigation_build_css_font_sizes( $block->context ); + } $classes = array_merge( $font_sizes['css_classes'] ); @@ -262,7 +228,13 @@ function render_block_core_navigation_link( $attributes, $content, $block ) { if ( isset( $block->context['showSubmenuIcon'] ) && $block->context['showSubmenuIcon'] && $has_submenu ) { // The submenu icon can be hidden by a CSS rule on the Navigation Block. - $html .= '' . block_core_navigation_render_submenu_icon() . ''; + $html .= ''; + if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { + $html .= gutenberg_block_core_shared_navigation_render_submenu_icon(); + } else { + $html .= block_core_shared_navigation_render_submenu_icon(); + } + $html .= ''; } if ( $has_submenu ) { @@ -485,4 +457,4 @@ function register_block_core_navigation_link() { * Creates all variations for post types / taxonomies dynamically (= each time when variations are requested). * Do not use variation_callback, to also account for unregistering post types/taxonomies later on. */ -add_action( 'get_block_type_variations', 'block_core_navigation_link_filter_variations', 10, 2 ); +add_filter( 'get_block_type_variations', 'block_core_navigation_link_filter_variations', 10, 2 ); diff --git a/src/wp-includes/blocks/navigation-link/block.json b/src/wp-includes/blocks/navigation-link/block.json index 997275574f1ac..0735461d0b29a 100644 --- a/src/wp-includes/blocks/navigation-link/block.json +++ b/src/wp-includes/blocks/navigation-link/block.json @@ -85,6 +85,11 @@ "clientNavigation": true } }, + "selectors": { + "states": { + "@current": ".wp-block-navigation .current-menu-item" + } + }, "editorStyle": "wp-block-navigation-link-editor", "style": "wp-block-navigation-link" } diff --git a/src/wp-includes/blocks/navigation-submenu.php b/src/wp-includes/blocks/navigation-submenu.php index 9138b5a5e08da..2677988707836 100644 --- a/src/wp-includes/blocks/navigation-submenu.php +++ b/src/wp-includes/blocks/navigation-submenu.php @@ -5,6 +5,10 @@ * @package WordPress */ +require_once __DIR__ . '/navigation-link/shared/item-should-render.php'; +require_once __DIR__ . '/navigation-link/shared/render-submenu-icon.php'; +require_once __DIR__ . '/navigation-link/shared/build-css-font-sizes.php'; + /** * Returns the submenu visibility value with backward compatibility * for the deprecated openSubmenusOnClick attribute. @@ -46,52 +50,6 @@ function block_core_navigation_submenu_get_submenu_visibility( $context ) { return $submenu_visibility ?? 'hover'; } -// Path differs between source and build: '../navigation-link/shared/' in source, './navigation-link/shared/' in build. -if ( file_exists( __DIR__ . '/../navigation-link/shared/item-should-render.php' ) ) { - require_once __DIR__ . '/../navigation-link/shared/item-should-render.php'; - require_once __DIR__ . '/../navigation-link/shared/render-submenu-icon.php'; -} else { - require_once __DIR__ . '/navigation-link/shared/item-should-render.php'; - require_once __DIR__ . '/navigation-link/shared/render-submenu-icon.php'; -} - -/** - * Build an array with CSS classes and inline styles defining the font sizes - * which will be applied to the navigation markup in the front-end. - * - * @since 5.9.0 - * - * @param array $context Navigation block context. - * @return array Font size CSS classes and inline styles. - */ -function block_core_navigation_submenu_build_css_font_sizes( $context ) { - // CSS classes. - $font_sizes = array( - 'css_classes' => array(), - 'inline_styles' => '', - ); - - $has_named_font_size = array_key_exists( 'fontSize', $context ); - $has_custom_font_size = isset( $context['style']['typography']['fontSize'] ); - - if ( $has_named_font_size ) { - // Add the font size class. - $font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $context['fontSize'] ); - } elseif ( $has_custom_font_size ) { - // Add the custom font size inline style. - $font_sizes['inline_styles'] = sprintf( - 'font-size: %s;', - wp_get_typography_font_size_value( - array( - 'size' => $context['style']['typography']['fontSize'], - ) - ) - ); - } - - return $font_sizes; -} - /** * Renders the `core/navigation-submenu` block. * @@ -116,7 +74,15 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) { return ''; } - $font_sizes = block_core_navigation_submenu_build_css_font_sizes( $block->context ); + // The build system prefixes this function with "gutenberg_" to avoid + // collisions with the core version. Until this function is backported to + // core, we need to guard its use and only call the prefixed name in + // the plugin. + if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { + $font_sizes = gutenberg_block_core_shared_navigation_build_css_font_sizes( $block->context ); + } else { + $font_sizes = block_core_shared_navigation_build_css_font_sizes( $block->context ); + } $style_attribute = $font_sizes['inline_styles']; // Render inner blocks first to check if any menu items will actually display. @@ -240,7 +206,13 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) { if ( $show_submenu_indicators && $has_submenu ) { // The submenu icon is rendered in a button here // so that there's a clickable element to open the submenu. - $html .= ''; + $html .= ''; } } else { $html .= ''; if ( $has_submenu ) { - $html .= '' . block_core_navigation_render_submenu_icon() . ''; + $html .= ''; + if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { + $html .= gutenberg_block_core_shared_navigation_render_submenu_icon(); + } else { + $html .= block_core_shared_navigation_render_submenu_icon(); + } + $html .= ''; } } diff --git a/src/wp-includes/blocks/navigation.php b/src/wp-includes/blocks/navigation.php index 7863f80a9bdc4..a530494ff36e7 100644 --- a/src/wp-includes/blocks/navigation.php +++ b/src/wp-includes/blocks/navigation.php @@ -425,7 +425,11 @@ private static function get_overlay_blocks_from_template_part( $overlay_template $full_template_part_id = $theme . '//' . $slug; $block_template = get_block_file_template( $full_template_part_id, 'wp_template_part' ); if ( isset( $block_template->content ) ) { - $parsed_blocks = parse_blocks( $block_template->content ); + // Expand shortcodes before parsing blocks, matching the order in + // `render_block_core_template_part()`. + $content = shortcode_unautop( $block_template->content ); + $content = do_shortcode( $content ); + $parsed_blocks = parse_blocks( $content ); $blocks = block_core_navigation_filter_out_empty_blocks( $parsed_blocks ); // Disable overlay menu for any navigation blocks within the overlay to prevent nested overlays. $blocks = static::disable_overlay_menu_for_nested_navigation_blocks( $blocks ); @@ -449,6 +453,12 @@ private static function get_overlay_blocks_from_template_part( $overlay_template // Re-serialize, and run Block Hooks algorithm to inject hooked blocks. $markup = serialize_blocks( $blocks ); $markup = apply_block_hooks_to_content_from_post_object( $markup, $template_part_post ); + + // Expand shortcodes before parsing blocks, matching the order in + // `render_block_core_template_part()`. + $markup = shortcode_unautop( $markup ); + $markup = do_shortcode( $markup ); + $blocks = parse_blocks( $markup ); // Disable overlay menu for any navigation blocks within the overlay to prevent nested overlays. @@ -1344,17 +1354,6 @@ function block_core_navigation_build_css_font_sizes( $attributes ) { return $font_sizes; } -/** - * Returns the top-level submenu SVG chevron icon. - * - * @since 5.9.0 - * - * @return string - */ -function block_core_navigation_render_submenu_icon() { - return ''; -} - /** * Filter out empty "null" blocks from the block list. * 'parse_blocks' includes a null block with '\n\n' as the content when diff --git a/src/wp-includes/blocks/page-list.php b/src/wp-includes/blocks/page-list.php index 27e63f250a811..685f79331784b 100644 --- a/src/wp-includes/blocks/page-list.php +++ b/src/wp-includes/blocks/page-list.php @@ -5,6 +5,8 @@ * @package WordPress */ +require_once __DIR__ . '/navigation-link/shared/build-css-font-sizes.php'; + /** * Returns the submenu visibility value with backward compatibility * for the deprecated openSubmenusOnClick attribute. @@ -123,50 +125,12 @@ function block_core_page_list_build_css_colors( $attributes, $context ) { return $colors; } - -/** - * Build an array with CSS classes and inline styles defining the font sizes - * which will be applied to the pages markup in the front-end when it is a descendant of navigation. - * - * @since 5.8.0 - * - * @param array $context Navigation block context. - * @return array Font size CSS classes and inline styles. - */ -function block_core_page_list_build_css_font_sizes( $context ) { - // CSS classes. - $font_sizes = array( - 'css_classes' => array(), - 'inline_styles' => '', - ); - - $has_named_font_size = array_key_exists( 'fontSize', $context ); - $has_custom_font_size = isset( $context['style']['typography']['fontSize'] ); - - if ( $has_named_font_size ) { - // Add the font size class. - $font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $context['fontSize'] ); - } elseif ( $has_custom_font_size ) { - // Add the custom font size inline style. - $font_sizes['inline_styles'] = sprintf( - 'font-size: %s;', - wp_get_typography_font_size_value( - array( - 'size' => $context['style']['typography']['fontSize'], - ) - ) - ); - } - - return $font_sizes; -} - /** * Outputs Page list markup from an array of pages with nested children. * * @since 5.8.0 * - * @param boolean $open_submenus_on_click Whether to open submenus on click instead of hover. + * @param string $submenu_visibility The submenu visibility mode: 'hover', 'click', or 'always'. * @param boolean $show_submenu_icons Whether to show submenu indicator icons. * @param boolean $is_navigation_child If block is a child of Navigation block. * @param array $nested_pages The array of nested pages. @@ -342,12 +306,21 @@ function render_block_core_page_list( $attributes, $content, $block ) { } } - $colors = block_core_page_list_build_css_colors( $attributes, $block->context ); - $font_sizes = block_core_page_list_build_css_font_sizes( $block->context ); - $classes = array_merge( + $colors = block_core_page_list_build_css_colors( $attributes, $block->context ); + // The build system prefixes this function with "gutenberg_" to avoid + // collisions with the core version. Until this function is backported to + // core, we need to guard its use and only call the prefixed name in + // the plugin. + if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { + $font_sizes = gutenberg_block_core_shared_navigation_build_css_font_sizes( $block->context ); + } else { + $font_sizes = block_core_shared_navigation_build_css_font_sizes( $block->context ); + } + $classes = array_merge( $colors['css_classes'], $font_sizes['css_classes'] ); + $style_attribute = ( $colors['inline_styles'] . $font_sizes['inline_styles'] ); $css_classes = trim( implode( ' ', $classes ) ); diff --git a/src/wp-includes/blocks/post-date/block.json b/src/wp-includes/blocks/post-date/block.json index 7952e36af3661..75eb1eda38d8f 100644 --- a/src/wp-includes/blocks/post-date/block.json +++ b/src/wp-includes/blocks/post-date/block.json @@ -11,9 +11,6 @@ "type": "string", "role": "content" }, - "textAlign": { - "type": "string" - }, "format": { "type": "string" }, @@ -46,6 +43,7 @@ "typography": { "fontSize": true, "lineHeight": true, + "textAlign": true, "__experimentalFontFamily": true, "__experimentalFontWeight": true, "__experimentalFontStyle": true, diff --git a/src/wp-includes/blocks/post-excerpt/block.json b/src/wp-includes/blocks/post-excerpt/block.json index 99f6d5dcc99ed..17678a35c2950 100644 --- a/src/wp-includes/blocks/post-excerpt/block.json +++ b/src/wp-includes/blocks/post-excerpt/block.json @@ -7,9 +7,6 @@ "description": "Display the excerpt.", "textdomain": "default", "attributes": { - "textAlign": { - "type": "string" - }, "moreText": { "type": "string", "role": "content" @@ -46,6 +43,7 @@ "typography": { "fontSize": true, "lineHeight": true, + "textAlign": true, "textColumns": true, "__experimentalFontFamily": true, "__experimentalFontWeight": true, diff --git a/src/wp-includes/blocks/post-featured-image.php b/src/wp-includes/blocks/post-featured-image.php index e9fc60f7038f5..56cf9a66e4e03 100644 --- a/src/wp-includes/blocks/post-featured-image.php +++ b/src/wp-includes/blocks/post-featured-image.php @@ -166,10 +166,8 @@ function get_block_core_post_featured_image_overlay_element_markup( $attributes } // Apply overlay and gradient classes. - if ( $has_dim_background ) { - $class_names[] = 'has-background-dim'; - $class_names[] = "has-background-dim-{$attributes['dimRatio']}"; - } + $class_names[] = 'has-background-dim'; + $class_names[] = "has-background-dim-{$attributes['dimRatio']}"; if ( $has_solid_overlay ) { $class_names[] = "has-{$attributes['overlayColor']}-background-color"; diff --git a/src/wp-includes/blocks/post-navigation-link/block.json b/src/wp-includes/blocks/post-navigation-link/block.json index 6d51d619637c9..83cf63af7841b 100644 --- a/src/wp-includes/blocks/post-navigation-link/block.json +++ b/src/wp-includes/blocks/post-navigation-link/block.json @@ -7,9 +7,6 @@ "description": "Displays the next or previous post link that is adjacent to the current post.", "textdomain": "default", "attributes": { - "textAlign": { - "type": "string" - }, "type": { "type": "string", "default": "next" @@ -46,6 +43,7 @@ "typography": { "fontSize": true, "lineHeight": true, + "textAlign": true, "__experimentalFontFamily": true, "__experimentalFontWeight": true, "__experimentalFontStyle": true, diff --git a/src/wp-includes/blocks/post-template.php b/src/wp-includes/blocks/post-template.php index 72ebbe0e13d13..9ce4ce47343e1 100644 --- a/src/wp-includes/blocks/post-template.php +++ b/src/wp-includes/blocks/post-template.php @@ -94,6 +94,9 @@ function render_block_core_post_template( $attributes, $content, $block ) { if ( isset( $attributes['layout']['type'] ) && 'grid' === $attributes['layout']['type'] && ! empty( $attributes['layout']['columnCount'] ) ) { $classnames .= ' ' . sanitize_title( 'columns-' . $attributes['layout']['columnCount'] ); } + if ( isset( $attributes['layout']['type'] ) && 'grid' === $attributes['layout']['type'] && ! empty( $attributes['layout']['columnCount'] ) && ! empty( $attributes['layout']['minimumColumnWidth'] ) ) { + $classnames .= ' has-native-responsive-grid'; + } $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => trim( $classnames ) ) ); diff --git a/src/wp-includes/blocks/post-title/block.json b/src/wp-includes/blocks/post-title/block.json index 1fb7efcf82db5..d1ded484486bd 100644 --- a/src/wp-includes/blocks/post-title/block.json +++ b/src/wp-includes/blocks/post-title/block.json @@ -8,9 +8,6 @@ "textdomain": "default", "usesContext": [ "postId", "postType", "queryId" ], "attributes": { - "textAlign": { - "type": "string" - }, "level": { "type": "number", "default": 2 @@ -33,6 +30,9 @@ "type": "string", "default": "_self", "role": "content" + }, + "placeholder": { + "type": "string" } }, "example": { @@ -58,6 +58,7 @@ "typography": { "fontSize": true, "lineHeight": true, + "textAlign": true, "__experimentalFontFamily": true, "__experimentalFontWeight": true, "__experimentalFontStyle": true, diff --git a/src/wp-includes/blocks/pullquote/block.json b/src/wp-includes/blocks/pullquote/block.json index 271bba74d0252..9469f420d1db7 100644 --- a/src/wp-includes/blocks/pullquote/block.json +++ b/src/wp-includes/blocks/pullquote/block.json @@ -43,10 +43,7 @@ } }, "dimensions": { - "minHeight": true, - "__experimentalDefaultControls": { - "minHeight": false - } + "minHeight": true }, "spacing": { "margin": true, diff --git a/src/wp-includes/blocks/query-title.php b/src/wp-includes/blocks/query-title.php index d26a3d08ae42a..845a4bdc05aa7 100644 --- a/src/wp-includes/blocks/query-title.php +++ b/src/wp-includes/blocks/query-title.php @@ -13,7 +13,7 @@ * @since 5.8.0 * * @param array $attributes Block attributes. - * @param array $_content Block content. + * @param array $content Block content. * @param object $block Block instance. * * @return string Returns the query title based on the queried object. diff --git a/src/wp-includes/blocks/query-title/block.json b/src/wp-includes/blocks/query-title/block.json index 41e9e3fd29b62..786a46fe5cb1b 100644 --- a/src/wp-includes/blocks/query-title/block.json +++ b/src/wp-includes/blocks/query-title/block.json @@ -10,9 +10,6 @@ "type": { "type": "string" }, - "textAlign": { - "type": "string" - }, "level": { "type": "number", "default": 1 @@ -53,6 +50,7 @@ "typography": { "fontSize": true, "lineHeight": true, + "textAlign": true, "__experimentalFontFamily": true, "__experimentalFontStyle": true, "__experimentalFontWeight": true, diff --git a/src/wp-includes/blocks/search.php b/src/wp-includes/blocks/search.php index 7073d6ce8ab3f..07c051b8f6eb9 100644 --- a/src/wp-includes/blocks/search.php +++ b/src/wp-includes/blocks/search.php @@ -69,10 +69,13 @@ function render_block_core_search( $attributes ) { if ( ! empty( $typography_classes ) ) { $input_classes[] = $typography_classes; } + if ( ! $show_button && ! empty( $color_classes ) ) { + $input_classes[] = $color_classes; + } if ( $input->next_tag() ) { $input->add_class( implode( ' ', $input_classes ) ); $input->set_attribute( 'id', $input_id ); - $input->set_attribute( 'value', get_search_query() ); + $input->set_attribute( 'value', get_search_query( false ) ); $input->set_attribute( 'placeholder', $attributes['placeholder'] ); // If it's interactive, enqueue the script module and add the directives. @@ -430,20 +433,37 @@ function styles_for_block_core_search( $attributes ) { } } + $use_input_for_colors = ! empty( $attributes['buttonPosition'] ) && 'no-button' === $attributes['buttonPosition']; + // Add color styles. $has_text_color = ! empty( $attributes['style']['color']['text'] ); if ( $has_text_color ) { - $button_styles[] = sprintf( 'color: %s;', $attributes['style']['color']['text'] ); + $text_color_style = sprintf( 'color: %s;', $attributes['style']['color']['text'] ); + if ( $use_input_for_colors ) { + $input_styles[] = $text_color_style; + } else { + $button_styles[] = $text_color_style; + } } $has_background_color = ! empty( $attributes['style']['color']['background'] ); if ( $has_background_color ) { - $button_styles[] = sprintf( 'background-color: %s;', $attributes['style']['color']['background'] ); + $background_color_style = sprintf( 'background-color: %s;', $attributes['style']['color']['background'] ); + if ( $use_input_for_colors ) { + $input_styles[] = $background_color_style; + } else { + $button_styles[] = $background_color_style; + } } $has_custom_gradient = ! empty( $attributes['style']['color']['gradient'] ); if ( $has_custom_gradient ) { - $button_styles[] = sprintf( 'background: %s;', $attributes['style']['color']['gradient'] ); + $custom_gradient_style = sprintf( 'background: %s;', $attributes['style']['color']['gradient'] ); + if ( $use_input_for_colors ) { + $input_styles[] = $custom_gradient_style; + } else { + $button_styles[] = $custom_gradient_style; + } } // Get typography styles to be shared across inner elements. diff --git a/src/wp-includes/blocks/search/block.json b/src/wp-includes/blocks/search/block.json index a6146d4404041..be9c0e3cdc2d5 100644 --- a/src/wp-includes/blocks/search/block.json +++ b/src/wp-includes/blocks/search/block.json @@ -42,10 +42,6 @@ "query": { "type": "object", "default": {} - }, - "isSearchFieldHidden": { - "type": "boolean", - "default": false } }, "supports": { @@ -92,5 +88,9 @@ "html": false }, "editorStyle": "wp-block-search-editor", - "style": "wp-block-search" + "style": "wp-block-search", + "selectors": { + "color": ".wp-block-search .wp-block-search__button, .wp-block-search.wp-block-search__no-button .wp-block-search__input", + "border": ".wp-block-search.wp-block-search__button-outside .wp-block-search__input, .wp-block-search.wp-block-search__button-outside .wp-block-search__button, .wp-block-search.wp-block-search__no-button .wp-block-search__input, .wp-block-search.wp-block-search__button-only .wp-block-search__input, .wp-block-search.wp-block-search__button-only .wp-block-search__button, .wp-block-search.wp-block-search__button-inside .wp-block-search__inside-wrapper" + } } diff --git a/src/wp-includes/blocks/site-tagline/block.json b/src/wp-includes/blocks/site-tagline/block.json index 756b2dcb8183a..1b2764d0cfa9a 100644 --- a/src/wp-includes/blocks/site-tagline/block.json +++ b/src/wp-includes/blocks/site-tagline/block.json @@ -8,9 +8,6 @@ "keywords": [ "description" ], "textdomain": "default", "attributes": { - "textAlign": { - "type": "string" - }, "level": { "type": "number", "default": 0 @@ -23,7 +20,11 @@ "example": { "viewportWidth": 350, "attributes": { - "textAlign": "center" + "style": { + "typography": { + "textAlign": "center" + } + } } }, "supports": { @@ -49,6 +50,7 @@ "typography": { "fontSize": true, "lineHeight": true, + "textAlign": true, "__experimentalFontFamily": true, "__experimentalTextTransform": true, "__experimentalTextDecoration": true, diff --git a/src/wp-includes/blocks/site-title/block.json b/src/wp-includes/blocks/site-title/block.json index ac6a3c10e086a..0631de6560ba4 100644 --- a/src/wp-includes/blocks/site-title/block.json +++ b/src/wp-includes/blocks/site-title/block.json @@ -15,9 +15,6 @@ "type": "array", "default": [ 0, 1, 2, 3, 4, 5, 6 ] }, - "textAlign": { - "type": "string" - }, "isLink": { "type": "boolean", "default": true, @@ -56,6 +53,7 @@ "typography": { "fontSize": true, "lineHeight": true, + "textAlign": true, "__experimentalFontFamily": true, "__experimentalTextTransform": true, "__experimentalTextDecoration": true, diff --git a/src/wp-includes/build/constants.php b/src/wp-includes/build/constants.php index 37c81b5ccc21b..953e376d24bb3 100644 --- a/src/wp-includes/build/constants.php +++ b/src/wp-includes/build/constants.php @@ -9,6 +9,6 @@ */ return array( - 'version' => '22.6.0-rc.1', + 'version' => '23.1.1', 'build_url' => includes_url( 'build/' ), ); diff --git a/src/wp-includes/build/pages.php b/src/wp-includes/build/pages.php index 14ca6a08fbbc1..d9fa3cfef0f7f 100644 --- a/src/wp-includes/build/pages.php +++ b/src/wp-includes/build/pages.php @@ -6,7 +6,23 @@ * @package wp */ -require_once __DIR__ . '/pages/font-library/page.php'; -require_once __DIR__ . '/pages/font-library/page-wp-admin.php'; -require_once __DIR__ . '/pages/options-connectors/page.php'; -require_once __DIR__ . '/pages/options-connectors/page-wp-admin.php'; +foreach ( [ + __DIR__ . '/pages/media-editor/page.php', + __DIR__ . '/pages/media-editor/page-wp-admin.php', + __DIR__ . '/pages/font-library/page.php', + __DIR__ . '/pages/font-library/page-wp-admin.php', + __DIR__ . '/pages/options-connectors/page.php', + __DIR__ . '/pages/options-connectors/page-wp-admin.php', + __DIR__ . '/pages/guidelines/page.php', + __DIR__ . '/pages/guidelines/page-wp-admin.php', + __DIR__ . '/pages/experiments/page.php', + __DIR__ . '/pages/experiments/page-wp-admin.php', + __DIR__ . '/pages/content-types/page.php', + __DIR__ . '/pages/content-types/page-wp-admin.php', + __DIR__ . '/pages/dashboard/page.php', + __DIR__ . '/pages/dashboard/page-wp-admin.php', +] as $file ) { + if ( file_exists( $file ) ) { + require_once $file; + } +} diff --git a/src/wp-includes/build/pages/font-library/page-wp-admin.php b/src/wp-includes/build/pages/font-library/page-wp-admin.php index 4d41be02ae892..aa54ca9045668 100644 --- a/src/wp-includes/build/pages/font-library/page-wp-admin.php +++ b/src/wp-includes/build/pages/font-library/page-wp-admin.php @@ -89,7 +89,7 @@ function wp_font_library_wp_admin_preload_data() { // Define paths to preload - same for all pages // Please also change packages/core-data/src/entities.js when changing this. $preload_paths = array( - '/?_fields=description,gmt_offset,home,image_sizes,image_size_threshold,image_output_formats,jpeg_interlaced,png_interlaced,gif_interlaced,name,site_icon,site_icon_url,site_logo,timezone_string,url,page_for_posts,page_on_front,show_on_front', + '/?_fields=description,gmt_offset,home,image_sizes,image_size_threshold,name,site_icon,site_icon_url,site_logo,timezone_string,url,page_for_posts,page_on_front,show_on_front', array( '/wp/v2/settings', 'OPTIONS' ), ); @@ -196,6 +196,21 @@ function ( $handle ) { } } + /** + * Filters the boot script-module dependencies for the + * font-library-wp-admin page. + * + * Surfaces extending this page can append entries to the boot + * dependency list. Each entry is an array with 'import' (string + * 'static' or 'dynamic') and 'id' (script-module handle) keys. + * + * @param array $boot_dependencies Boot dependencies for the page. + */ + $boot_dependencies = apply_filters( + 'font-library-wp-admin_boot_dependencies', + $boot_dependencies + ); + // Dummy script module to ensure dependencies are loaded wp_register_script_module( 'font-library-wp-admin', diff --git a/src/wp-includes/build/pages/font-library/page.php b/src/wp-includes/build/pages/font-library/page.php index e2849c954ba37..f41ec1e443227 100644 --- a/src/wp-includes/build/pages/font-library/page.php +++ b/src/wp-includes/build/pages/font-library/page.php @@ -90,7 +90,7 @@ function wp_font_library_preload_data() { // Define paths to preload - same for all pages // Please also change packages/core-data/src/entities.js when changing this. $preload_paths = array( - '/?_fields=description,gmt_offset,home,image_sizes,image_size_threshold,image_output_formats,jpeg_interlaced,png_interlaced,gif_interlaced,name,site_icon,site_icon_url,site_logo,timezone_string,url,page_for_posts,page_on_front,show_on_front', + '/?_fields=description,gmt_offset,home,image_sizes,image_size_threshold,name,site_icon,site_icon_url,site_logo,timezone_string,url,page_for_posts,page_on_front,show_on_front', array( '/wp/v2/settings', 'OPTIONS' ), ); @@ -209,6 +209,21 @@ function ( $handle ) { } } + /** + * Filters the boot script-module dependencies for the + * font-library page. + * + * Surfaces extending this page can append entries to the boot + * dependency list. Each entry is an array with 'import' (string + * 'static' or 'dynamic') and 'id' (script-module handle) keys. + * + * @param array $boot_dependencies Boot dependencies for the page. + */ + $boot_dependencies = apply_filters( + 'font-library_boot_dependencies', + $boot_dependencies + ); + // Dummy script module to ensure dependencies are loaded wp_register_script_module( 'font-library', diff --git a/src/wp-includes/build/pages/options-connectors/page-wp-admin.php b/src/wp-includes/build/pages/options-connectors/page-wp-admin.php index 3f3048b8fb98b..e5c7b8dce0544 100644 --- a/src/wp-includes/build/pages/options-connectors/page-wp-admin.php +++ b/src/wp-includes/build/pages/options-connectors/page-wp-admin.php @@ -89,7 +89,7 @@ function wp_options_connectors_wp_admin_preload_data() { // Define paths to preload - same for all pages // Please also change packages/core-data/src/entities.js when changing this. $preload_paths = array( - '/?_fields=description,gmt_offset,home,image_sizes,image_size_threshold,image_output_formats,jpeg_interlaced,png_interlaced,gif_interlaced,name,site_icon,site_icon_url,site_logo,timezone_string,url,page_for_posts,page_on_front,show_on_front', + '/?_fields=description,gmt_offset,home,image_sizes,image_size_threshold,name,site_icon,site_icon_url,site_logo,timezone_string,url,page_for_posts,page_on_front,show_on_front', array( '/wp/v2/settings', 'OPTIONS' ), ); @@ -196,6 +196,21 @@ function ( $handle ) { } } + /** + * Filters the boot script-module dependencies for the + * options-connectors-wp-admin page. + * + * Surfaces extending this page can append entries to the boot + * dependency list. Each entry is an array with 'import' (string + * 'static' or 'dynamic') and 'id' (script-module handle) keys. + * + * @param array $boot_dependencies Boot dependencies for the page. + */ + $boot_dependencies = apply_filters( + 'options-connectors-wp-admin_boot_dependencies', + $boot_dependencies + ); + // Dummy script module to ensure dependencies are loaded wp_register_script_module( 'options-connectors-wp-admin', diff --git a/src/wp-includes/build/pages/options-connectors/page.php b/src/wp-includes/build/pages/options-connectors/page.php index 6009dbb2570a9..6be01a05641c0 100644 --- a/src/wp-includes/build/pages/options-connectors/page.php +++ b/src/wp-includes/build/pages/options-connectors/page.php @@ -90,7 +90,7 @@ function wp_options_connectors_preload_data() { // Define paths to preload - same for all pages // Please also change packages/core-data/src/entities.js when changing this. $preload_paths = array( - '/?_fields=description,gmt_offset,home,image_sizes,image_size_threshold,image_output_formats,jpeg_interlaced,png_interlaced,gif_interlaced,name,site_icon,site_icon_url,site_logo,timezone_string,url,page_for_posts,page_on_front,show_on_front', + '/?_fields=description,gmt_offset,home,image_sizes,image_size_threshold,name,site_icon,site_icon_url,site_logo,timezone_string,url,page_for_posts,page_on_front,show_on_front', array( '/wp/v2/settings', 'OPTIONS' ), ); @@ -209,6 +209,21 @@ function ( $handle ) { } } + /** + * Filters the boot script-module dependencies for the + * options-connectors page. + * + * Surfaces extending this page can append entries to the boot + * dependency list. Each entry is an array with 'import' (string + * 'static' or 'dynamic') and 'id' (script-module handle) keys. + * + * @param array $boot_dependencies Boot dependencies for the page. + */ + $boot_dependencies = apply_filters( + 'options-connectors_boot_dependencies', + $boot_dependencies + ); + // Dummy script module to ensure dependencies are loaded wp_register_script_module( 'options-connectors', diff --git a/src/wp-includes/build/routes.php b/src/wp-includes/build/routes.php index 2d87344225949..bb6177aee952e 100644 --- a/src/wp-includes/build/routes.php +++ b/src/wp-includes/build/routes.php @@ -111,6 +111,63 @@ function wp_register_options_connectors_wp_admin_page_routes() { } add_action( 'options-connectors-wp-admin_init', 'wp_register_options_connectors_wp_admin_page_routes' ); +// Page-specific route registration functions for content-types +/** + * Register routes for content-types page (full-page mode). + */ +function wp_register_content_types_page_routes() { + global $wp_content_types_routes_data; + wp_register_page_routes( $wp_content_types_routes_data, 'wp_register_content_types_route' ); +} +add_action( 'content-types_init', 'wp_register_content_types_page_routes' ); + +/** + * Register routes for content-types page (wp-admin mode). + */ +function wp_register_content_types_wp_admin_page_routes() { + global $wp_content_types_routes_data; + wp_register_page_routes( $wp_content_types_routes_data, 'wp_register_content_types_wp_admin_route' ); +} +add_action( 'content-types-wp-admin_init', 'wp_register_content_types_wp_admin_page_routes' ); + +// Page-specific route registration functions for dashboard +/** + * Register routes for dashboard page (full-page mode). + */ +function wp_register_dashboard_page_routes() { + global $wp_dashboard_routes_data; + wp_register_page_routes( $wp_dashboard_routes_data, 'wp_register_dashboard_route' ); +} +add_action( 'dashboard_init', 'wp_register_dashboard_page_routes' ); + +/** + * Register routes for dashboard page (wp-admin mode). + */ +function wp_register_dashboard_wp_admin_page_routes() { + global $wp_dashboard_routes_data; + wp_register_page_routes( $wp_dashboard_routes_data, 'wp_register_dashboard_wp_admin_route' ); +} +add_action( 'dashboard-wp-admin_init', 'wp_register_dashboard_wp_admin_page_routes' ); + +// Page-specific route registration functions for experiments +/** + * Register routes for experiments page (full-page mode). + */ +function wp_register_experiments_page_routes() { + global $wp_experiments_routes_data; + wp_register_page_routes( $wp_experiments_routes_data, 'wp_register_experiments_route' ); +} +add_action( 'experiments_init', 'wp_register_experiments_page_routes' ); + +/** + * Register routes for experiments page (wp-admin mode). + */ +function wp_register_experiments_wp_admin_page_routes() { + global $wp_experiments_routes_data; + wp_register_page_routes( $wp_experiments_routes_data, 'wp_register_experiments_wp_admin_route' ); +} +add_action( 'experiments-wp-admin_init', 'wp_register_experiments_wp_admin_page_routes' ); + // Page-specific route registration functions for font-library /** * Register routes for font-library page (full-page mode). @@ -130,3 +187,41 @@ function wp_register_font_library_wp_admin_page_routes() { } add_action( 'font-library-wp-admin_init', 'wp_register_font_library_wp_admin_page_routes' ); +// Page-specific route registration functions for guidelines +/** + * Register routes for guidelines page (full-page mode). + */ +function wp_register_guidelines_page_routes() { + global $wp_guidelines_routes_data; + wp_register_page_routes( $wp_guidelines_routes_data, 'wp_register_guidelines_route' ); +} +add_action( 'guidelines_init', 'wp_register_guidelines_page_routes' ); + +/** + * Register routes for guidelines page (wp-admin mode). + */ +function wp_register_guidelines_wp_admin_page_routes() { + global $wp_guidelines_routes_data; + wp_register_page_routes( $wp_guidelines_routes_data, 'wp_register_guidelines_wp_admin_route' ); +} +add_action( 'guidelines-wp-admin_init', 'wp_register_guidelines_wp_admin_page_routes' ); + +// Page-specific route registration functions for media-editor +/** + * Register routes for media-editor page (full-page mode). + */ +function wp_register_media_editor_page_routes() { + global $wp_media_editor_routes_data; + wp_register_page_routes( $wp_media_editor_routes_data, 'wp_register_media_editor_route' ); +} +add_action( 'media-editor_init', 'wp_register_media_editor_page_routes' ); + +/** + * Register routes for media-editor page (wp-admin mode). + */ +function wp_register_media_editor_wp_admin_page_routes() { + global $wp_media_editor_routes_data; + wp_register_page_routes( $wp_media_editor_routes_data, 'wp_register_media_editor_wp_admin_route' ); +} +add_action( 'media-editor-wp-admin_init', 'wp_register_media_editor_wp_admin_page_routes' ); + diff --git a/src/wp-includes/build/routes/connectors-home/content.js b/src/wp-includes/build/routes/connectors-home/content.js index dc250c11ac176..4cf53f6e548c5 100644 --- a/src/wp-includes/build/routes/connectors-home/content.js +++ b/src/wp-includes/build/routes/connectors-home/content.js @@ -7,6 +7,10 @@ var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) @@ -31,10 +35,17 @@ var require_i18n = __commonJS({ } }); -// package-external:@wordpress/components -var require_components = __commonJS({ - "package-external:@wordpress/components"(exports, module) { - module.exports = window.wp.components; +// package-external:@wordpress/element +var require_element = __commonJS({ + "package-external:@wordpress/element"(exports, module) { + module.exports = window.wp.element; + } +}); + +// vendor-external:react +var require_react = __commonJS({ + "vendor-external:react"(exports, module) { + module.exports = window.React; } }); @@ -45,17 +56,179 @@ var require_jsx_runtime = __commonJS({ } }); -// package-external:@wordpress/element -var require_element = __commonJS({ - "package-external:@wordpress/element"(exports, module) { - module.exports = window.wp.element; +// vendor-external:react-dom +var require_react_dom = __commonJS({ + "vendor-external:react-dom"(exports, module) { + module.exports = window.ReactDOM; } }); -// vendor-external:react -var require_react = __commonJS({ - "vendor-external:react"(exports, module) { - module.exports = window.React; +// node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js +var require_use_sync_external_store_shim_development = __commonJS({ + "node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js"(exports) { + "use strict"; + (function() { + function is(x, y) { + return x === y && (0 !== x || 1 / x === 1 / y) || x !== x && y !== y; + } + function useSyncExternalStore$2(subscribe, getSnapshot) { + didWarnOld18Alpha || void 0 === React53.startTransition || (didWarnOld18Alpha = true, console.error( + "You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release." + )); + var value = getSnapshot(); + if (!didWarnUncachedGetSnapshot) { + var cachedValue = getSnapshot(); + objectIs(value, cachedValue) || (console.error( + "The result of getSnapshot should be cached to avoid an infinite loop" + ), didWarnUncachedGetSnapshot = true); + } + cachedValue = useState14({ + inst: { value, getSnapshot } + }); + var inst = cachedValue[0].inst, forceUpdate = cachedValue[1]; + useLayoutEffect4( + function() { + inst.value = value; + inst.getSnapshot = getSnapshot; + checkIfSnapshotChanged(inst) && forceUpdate({ inst }); + }, + [subscribe, value, getSnapshot] + ); + useEffect15( + function() { + checkIfSnapshotChanged(inst) && forceUpdate({ inst }); + return subscribe(function() { + checkIfSnapshotChanged(inst) && forceUpdate({ inst }); + }); + }, + [subscribe] + ); + useDebugValue2(value); + return value; + } + function checkIfSnapshotChanged(inst) { + var latestGetSnapshot = inst.getSnapshot; + inst = inst.value; + try { + var nextValue = latestGetSnapshot(); + return !objectIs(inst, nextValue); + } catch (error2) { + return true; + } + } + function useSyncExternalStore$1(subscribe, getSnapshot) { + return getSnapshot(); + } + "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error()); + var React53 = require_react(), objectIs = "function" === typeof Object.is ? Object.is : is, useState14 = React53.useState, useEffect15 = React53.useEffect, useLayoutEffect4 = React53.useLayoutEffect, useDebugValue2 = React53.useDebugValue, didWarnOld18Alpha = false, didWarnUncachedGetSnapshot = false, shim = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2; + exports.useSyncExternalStore = void 0 !== React53.useSyncExternalStore ? React53.useSyncExternalStore : shim; + "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error()); + })(); + } +}); + +// node_modules/use-sync-external-store/shim/index.js +var require_shim = __commonJS({ + "node_modules/use-sync-external-store/shim/index.js"(exports, module) { + "use strict"; + if (false) { + module.exports = null; + } else { + module.exports = require_use_sync_external_store_shim_development(); + } + } +}); + +// node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.development.js +var require_with_selector_development = __commonJS({ + "node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.development.js"(exports) { + "use strict"; + (function() { + function is(x, y) { + return x === y && (0 !== x || 1 / x === 1 / y) || x !== x && y !== y; + } + "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error()); + var React53 = require_react(), shim = require_shim(), objectIs = "function" === typeof Object.is ? Object.is : is, useSyncExternalStore2 = shim.useSyncExternalStore, useRef21 = React53.useRef, useEffect15 = React53.useEffect, useMemo17 = React53.useMemo, useDebugValue2 = React53.useDebugValue; + exports.useSyncExternalStoreWithSelector = function(subscribe, getSnapshot, getServerSnapshot, selector, isEqual) { + var instRef = useRef21(null); + if (null === instRef.current) { + var inst = { hasValue: false, value: null }; + instRef.current = inst; + } else inst = instRef.current; + instRef = useMemo17( + function() { + function memoizedSelector(nextSnapshot) { + if (!hasMemo) { + hasMemo = true; + memoizedSnapshot = nextSnapshot; + nextSnapshot = selector(nextSnapshot); + if (void 0 !== isEqual && inst.hasValue) { + var currentSelection = inst.value; + if (isEqual(currentSelection, nextSnapshot)) + return memoizedSelection = currentSelection; + } + return memoizedSelection = nextSnapshot; + } + currentSelection = memoizedSelection; + if (objectIs(memoizedSnapshot, nextSnapshot)) + return currentSelection; + var nextSelection = selector(nextSnapshot); + if (void 0 !== isEqual && isEqual(currentSelection, nextSelection)) + return memoizedSnapshot = nextSnapshot, currentSelection; + memoizedSnapshot = nextSnapshot; + return memoizedSelection = nextSelection; + } + var hasMemo = false, memoizedSnapshot, memoizedSelection, maybeGetServerSnapshot = void 0 === getServerSnapshot ? null : getServerSnapshot; + return [ + function() { + return memoizedSelector(getSnapshot()); + }, + null === maybeGetServerSnapshot ? void 0 : function() { + return memoizedSelector(maybeGetServerSnapshot()); + } + ]; + }, + [getSnapshot, getServerSnapshot, selector, isEqual] + ); + var value = useSyncExternalStore2(subscribe, instRef[0], instRef[1]); + useEffect15( + function() { + inst.hasValue = true; + inst.value = value; + }, + [value] + ); + useDebugValue2(value); + return value; + }; + "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error()); + })(); + } +}); + +// node_modules/use-sync-external-store/shim/with-selector.js +var require_with_selector = __commonJS({ + "node_modules/use-sync-external-store/shim/with-selector.js"(exports, module) { + "use strict"; + if (false) { + module.exports = null; + } else { + module.exports = require_with_selector_development(); + } + } +}); + +// package-external:@wordpress/primitives +var require_primitives = __commonJS({ + "package-external:@wordpress/primitives"(exports, module) { + module.exports = window.wp.primitives; + } +}); + +// package-external:@wordpress/theme +var require_theme = __commonJS({ + "package-external:@wordpress/theme"(exports, module) { + module.exports = window.wp.theme; } }); @@ -66,6 +239,13 @@ var require_private_apis = __commonJS({ } }); +// package-external:@wordpress/components +var require_components = __commonJS({ + "package-external:@wordpress/components"(exports, module) { + module.exports = window.wp.components; + } +}); + // package-external:@wordpress/data var require_data = __commonJS({ "package-external:@wordpress/data"(exports, module) { @@ -110,27 +290,26 @@ function clsx() { } var clsx_default = clsx; -// packages/admin-ui/build-module/navigable-region/index.mjs -var import_element = __toESM(require_element(), 1); -var import_jsx_runtime = __toESM(require_jsx_runtime(), 1); -var NavigableRegion = (0, import_element.forwardRef)( - ({ children, className, ariaLabel, as: Tag = "div", ...props }, ref) => { - return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( - Tag, - { - ref, - className: clsx_default("admin-ui-navigable-region", className), - "aria-label": ariaLabel, - role: "region", - tabIndex: "-1", - ...props, - children - } - ); +// packages/ui/build-module/badge/badge.mjs +var import_element9 = __toESM(require_element(), 1); + +// node_modules/@base-ui/utils/esm/error.js +var set; +if (true) { + set = /* @__PURE__ */ new Set(); +} +function error(...messages) { + if (true) { + const messageKey = messages.join(" "); + if (!set.has(messageKey)) { + set.add(messageKey); + console.error(`Base UI: ${messageKey}`); + } } -); -NavigableRegion.displayName = "NavigableRegion"; -var navigable_region_default = NavigableRegion; +} + +// node_modules/@base-ui/utils/esm/useStableCallback.js +var React3 = __toESM(require_react(), 1); // node_modules/@base-ui/utils/esm/useRefWithInit.js var React2 = __toESM(require_react(), 1); @@ -143,8 +322,71 @@ function useRefWithInit(init, initArg) { return ref; } -// node_modules/@base-ui/react/esm/utils/useRenderElement.js +// node_modules/@base-ui/utils/esm/useStableCallback.js +var useInsertionEffect = React3[`useInsertionEffect${Math.random().toFixed(1)}`.slice(0, -3)]; +var useSafeInsertionEffect = ( + // React 17 doesn't have useInsertionEffect. + useInsertionEffect && // Preact replaces useInsertionEffect with useLayoutEffect and fires too late. + useInsertionEffect !== React3.useLayoutEffect ? useInsertionEffect : (fn) => fn() +); +function useStableCallback(callback) { + const stable = useRefWithInit(createStableCallback).current; + stable.next = callback; + useSafeInsertionEffect(stable.effect); + return stable.trampoline; +} +function createStableCallback() { + const stable = { + next: void 0, + callback: assertNotCalled, + trampoline: (...args) => stable.callback?.(...args), + effect: () => { + stable.callback = stable.next; + } + }; + return stable; +} +function assertNotCalled() { + if (true) { + throw ( + /* minify-error-disabled */ + new Error("Base UI: Cannot call an event handler while rendering.") + ); + } +} + +// node_modules/@base-ui/utils/esm/useIsoLayoutEffect.js +var React4 = __toESM(require_react(), 1); +var noop = () => { +}; +var useIsoLayoutEffect = typeof document !== "undefined" ? React4.useLayoutEffect : noop; + +// node_modules/@base-ui/utils/esm/warn.js +var set2; +if (true) { + set2 = /* @__PURE__ */ new Set(); +} +function warn(...messages) { + if (true) { + const messageKey = messages.join(" "); + if (!set2.has(messageKey)) { + set2.add(messageKey); + console.warn(`Base UI: ${messageKey}`); + } + } +} + +// node_modules/@base-ui/react/esm/internals/direction-context/DirectionContext.js var React5 = __toESM(require_react(), 1); +var DirectionContext = /* @__PURE__ */ React5.createContext(void 0); +if (true) DirectionContext.displayName = "DirectionContext"; +function useDirection() { + const context = React5.useContext(DirectionContext); + return context?.direction ?? "ltr"; +} + +// node_modules/@base-ui/react/esm/internals/useRenderElement.js +var React8 = __toESM(require_react(), 1); // node_modules/@base-ui/utils/esm/useMergedRefs.js function useMergedRefs(a, b, c, d) { @@ -172,7 +414,7 @@ function didChange(forkRef, a, b, c, d) { return forkRef.refs[0] !== a || forkRef.refs[1] !== b || forkRef.refs[2] !== c || forkRef.refs[3] !== d; } function didChangeN(forkRef, newRefs) { - return forkRef.refs.length !== newRefs.length || forkRef.refs.some((ref, index) => ref !== newRefs[index]); + return forkRef.refs.length !== newRefs.length || forkRef.refs.some((ref, index2) => ref !== newRefs[index2]); } function update(forkRef, refs) { forkRef.refs = refs; @@ -236,18 +478,18 @@ function update(forkRef, refs) { } // node_modules/@base-ui/utils/esm/getReactElementRef.js -var React4 = __toESM(require_react(), 1); +var React7 = __toESM(require_react(), 1); // node_modules/@base-ui/utils/esm/reactVersion.js -var React3 = __toESM(require_react(), 1); -var majorVersion = parseInt(React3.version, 10); +var React6 = __toESM(require_react(), 1); +var majorVersion = parseInt(React6.version, 10); function isReactVersionAtLeast(reactVersionToCheck) { return majorVersion >= reactVersionToCheck; } // node_modules/@base-ui/utils/esm/getReactElementRef.js function getReactElementRef(element) { - if (!/* @__PURE__ */ React4.isValidElement(element)) { + if (!/* @__PURE__ */ React7.isValidElement(element)) { return null; } const reactElement = element; @@ -272,7 +514,13 @@ function mergeObjects(a, b) { return void 0; } -// node_modules/@base-ui/react/esm/utils/getStateAttributesProps.js +// node_modules/@base-ui/utils/esm/empty.js +function NOOP() { +} +var EMPTY_ARRAY = Object.freeze([]); +var EMPTY_OBJECT = Object.freeze({}); + +// node_modules/@base-ui/react/esm/internals/getStateAttributesProps.js function getStateAttributesProps(state, customMapping) { const props = {}; for (const key in state) { @@ -306,20 +554,21 @@ function resolveStyle(style, state) { // node_modules/@base-ui/react/esm/merge-props/mergeProps.js var EMPTY_PROPS = {}; function mergeProps(a, b, c, d, e) { - let merged = { - ...resolvePropsGetter(a, EMPTY_PROPS) - }; + if (!c && !d && !e && !a) { + return createInitialMergedProps(b); + } + let merged = createInitialMergedProps(a); if (b) { - merged = mergeOne(merged, b); + merged = mergeInto(merged, b); } if (c) { - merged = mergeOne(merged, c); + merged = mergeInto(merged, c); } if (d) { - merged = mergeOne(merged, d); + merged = mergeInto(merged, d); } if (e) { - merged = mergeOne(merged, e); + merged = mergeInto(merged, e); } return merged; } @@ -328,22 +577,40 @@ function mergePropsN(props) { return EMPTY_PROPS; } if (props.length === 1) { - return resolvePropsGetter(props[0], EMPTY_PROPS); + return createInitialMergedProps(props[0]); } - let merged = { - ...resolvePropsGetter(props[0], EMPTY_PROPS) - }; + let merged = createInitialMergedProps(props[0]); for (let i = 1; i < props.length; i += 1) { - merged = mergeOne(merged, props[i]); + merged = mergeInto(merged, props[i]); } return merged; } -function mergeOne(merged, inputProps) { +function createInitialMergedProps(inputProps) { + if (isPropsGetter(inputProps)) { + return { + ...resolvePropsGetter(inputProps, EMPTY_PROPS) + }; + } + return copyInitialProps(inputProps); +} +function mergeInto(merged, inputProps) { if (isPropsGetter(inputProps)) { - return inputProps(merged); + return resolvePropsGetter(inputProps, merged); } return mutablyMergeInto(merged, inputProps); } +function copyInitialProps(inputProps) { + const copiedProps = { + ...inputProps + }; + for (const propName in copiedProps) { + const propValue = copiedProps[propName]; + if (isEventHandler(propName, propValue)) { + copiedProps[propName] = wrapEventHandler(propValue); + } + } + return copiedProps; +} function mutablyMergeInto(mergedProps, externalProps) { if (!externalProps) { return mergedProps; @@ -390,23 +657,36 @@ function mergeEventHandlers(ourHandler, theirHandler) { return ourHandler; } if (!ourHandler) { - return theirHandler; + return wrapEventHandler(theirHandler); } - return (event) => { + return (...args) => { + const event = args[0]; if (isSyntheticEvent(event)) { const baseUIEvent = event; makeEventPreventable(baseUIEvent); - const result2 = theirHandler(baseUIEvent); + const result2 = theirHandler(...args); if (!baseUIEvent.baseUIHandlerPrevented) { - ourHandler?.(baseUIEvent); + ourHandler?.(...args); } return result2; } - const result = theirHandler(event); - ourHandler?.(event); + const result = theirHandler(...args); + ourHandler?.(...args); return result; }; } +function wrapEventHandler(handler) { + if (!handler) { + return handler; + } + return (...args) => { + const event = args[0]; + if (isSyntheticEvent(event)) { + makeEventPreventable(event); + } + return handler(...args); + }; +} function makeEventPreventable(event) { event.preventBaseUIHandler = () => { event.baseUIHandlerPrevented = true; @@ -426,11 +706,7 @@ function isSyntheticEvent(event) { return event != null && typeof event === "object" && "nativeEvent" in event; } -// node_modules/@base-ui/utils/esm/empty.js -var EMPTY_ARRAY = Object.freeze([]); -var EMPTY_OBJECT = Object.freeze({}); - -// node_modules/@base-ui/react/esm/utils/useRenderElement.js +// node_modules/@base-ui/react/esm/internals/useRenderElement.js var import_react = __toESM(require_react(), 1); function useRenderElement(element, componentProps, params = {}) { const renderProp = componentProps.render; @@ -451,13 +727,14 @@ function useRenderElementProps(componentProps, params = {}) { state = EMPTY_OBJECT, ref, props, - stateAttributesMapping, + stateAttributesMapping: stateAttributesMapping3, enabled = true } = params; const className = enabled ? resolveClassName(classNameProp, state) : void 0; const style = enabled ? resolveStyle(styleProp, state) : void 0; - const stateProps = enabled ? getStateAttributesProps(state, stateAttributesMapping) : EMPTY_OBJECT; - const outProps = enabled ? mergeObjects(stateProps, Array.isArray(props) ? mergePropsN(props) : props) ?? EMPTY_OBJECT : EMPTY_OBJECT; + const stateProps = enabled ? getStateAttributesProps(state, stateAttributesMapping3) : EMPTY_OBJECT; + const resolvedProps = enabled && props ? resolveRenderFunctionProps(props) : void 0; + const outProps = enabled ? mergeObjects(stateProps, resolvedProps) ?? {} : EMPTY_OBJECT; if (typeof document !== "undefined") { if (!enabled) { useMergedRefs(null, null); @@ -467,199 +744,9846 @@ function useRenderElementProps(componentProps, params = {}) { outProps.ref = useMergedRefs(outProps.ref, getReactElementRef(renderProp), ref); } } - if (!enabled) { - return EMPTY_OBJECT; + if (!enabled) { + return EMPTY_OBJECT; + } + if (className !== void 0) { + outProps.className = mergeClassNames(outProps.className, className); + } + if (style !== void 0) { + outProps.style = mergeObjects(outProps.style, style); + } + return outProps; +} +function resolveRenderFunctionProps(props) { + if (Array.isArray(props)) { + return mergePropsN(props); + } + return mergeProps(void 0, props); +} +var REACT_LAZY_TYPE = /* @__PURE__ */ Symbol.for("react.lazy"); +var COMPONENT_IDENTIFIER_PATTERN = /^[A-Z][A-Za-z0-9$]*$/; +var LOWERCASE_CHARACTER_PATTERN = /[a-z]/; +function evaluateRenderProp(element, render, props, state) { + if (render) { + if (typeof render === "function") { + if (true) { + warnIfRenderPropLooksLikeComponent(render); + } + return render(props, state); + } + const mergedProps = mergeProps(props, render.props); + mergedProps.ref = props.ref; + let newElement = render; + if (newElement?.$$typeof === REACT_LAZY_TYPE) { + const children = React8.Children.toArray(render); + newElement = children[0]; + } + if (true) { + if (!/* @__PURE__ */ React8.isValidElement(newElement)) { + throw new Error(["Base UI: The `render` prop was provided an invalid React element as `React.isValidElement(render)` is `false`.", "A valid React element must be provided to the `render` prop because it is cloned with props to replace the default element.", "https://base-ui.com/r/invalid-render-prop"].join("\n")); + } + } + return /* @__PURE__ */ React8.cloneElement(newElement, mergedProps); + } + if (element) { + if (typeof element === "string") { + return renderTag(element, props); + } + } + throw new Error(true ? "Base UI: Render element or function are not defined." : formatErrorMessage_default(8)); +} +function warnIfRenderPropLooksLikeComponent(renderFn) { + const functionName = renderFn.name; + if (functionName.length === 0) { + return; + } + if (!COMPONENT_IDENTIFIER_PATTERN.test(functionName)) { + return; + } + if (!LOWERCASE_CHARACTER_PATTERN.test(functionName)) { + return; + } + warn(`The \`render\` prop received a function named \`${functionName}\` that starts with an uppercase letter.`, "This usually means a React component was passed directly as `render={Component}`.", "Base UI calls `render` as a plain function, which can break the Rules of Hooks during reconciliation.", "If this is an intentional render callback, rename it to start with a lowercase letter.", "Use `render={}` or `render={(props) => }` instead.", "https://base-ui.com/r/invalid-render-prop"); +} +function renderTag(Tag, props) { + if (Tag === "button") { + return /* @__PURE__ */ (0, import_react.createElement)("button", { + type: "button", + ...props, + key: props.key + }); + } + if (Tag === "img") { + return /* @__PURE__ */ (0, import_react.createElement)("img", { + alt: "", + ...props, + key: props.key + }); + } + return /* @__PURE__ */ React8.createElement(Tag, props); +} + +// node_modules/@base-ui/react/esm/internals/reason-parts.js +var reason_parts_exports = {}; +__export(reason_parts_exports, { + cancelOpen: () => cancelOpen, + chipRemovePress: () => chipRemovePress, + clearPress: () => clearPress, + closePress: () => closePress, + closeWatcher: () => closeWatcher, + decrementPress: () => decrementPress, + disabled: () => disabled, + drag: () => drag, + escapeKey: () => escapeKey, + focusOut: () => focusOut, + imperativeAction: () => imperativeAction, + incrementPress: () => incrementPress, + inputBlur: () => inputBlur, + inputChange: () => inputChange, + inputClear: () => inputClear, + inputPaste: () => inputPaste, + inputPress: () => inputPress, + itemPress: () => itemPress, + keyboard: () => keyboard, + linkPress: () => linkPress, + listNavigation: () => listNavigation, + none: () => none, + outsidePress: () => outsidePress, + pointer: () => pointer, + scrub: () => scrub, + siblingOpen: () => siblingOpen, + swipe: () => swipe, + trackPress: () => trackPress, + triggerFocus: () => triggerFocus, + triggerHover: () => triggerHover, + triggerPress: () => triggerPress, + wheel: () => wheel, + windowResize: () => windowResize +}); +var none = "none"; +var triggerPress = "trigger-press"; +var triggerHover = "trigger-hover"; +var triggerFocus = "trigger-focus"; +var outsidePress = "outside-press"; +var itemPress = "item-press"; +var closePress = "close-press"; +var linkPress = "link-press"; +var clearPress = "clear-press"; +var chipRemovePress = "chip-remove-press"; +var trackPress = "track-press"; +var incrementPress = "increment-press"; +var decrementPress = "decrement-press"; +var inputChange = "input-change"; +var inputClear = "input-clear"; +var inputBlur = "input-blur"; +var inputPaste = "input-paste"; +var inputPress = "input-press"; +var focusOut = "focus-out"; +var escapeKey = "escape-key"; +var closeWatcher = "close-watcher"; +var listNavigation = "list-navigation"; +var keyboard = "keyboard"; +var pointer = "pointer"; +var drag = "drag"; +var wheel = "wheel"; +var scrub = "scrub"; +var cancelOpen = "cancel-open"; +var siblingOpen = "sibling-open"; +var disabled = "disabled"; +var imperativeAction = "imperative-action"; +var swipe = "swipe"; +var windowResize = "window-resize"; + +// node_modules/@base-ui/react/esm/internals/createBaseUIEventDetails.js +function createChangeEventDetails(reason, event, trigger, customProperties) { + let canceled = false; + let allowPropagation = false; + const custom = customProperties ?? EMPTY_OBJECT; + const details = { + reason, + event: event ?? new Event("base-ui"), + cancel() { + canceled = true; + }, + allowPropagation() { + allowPropagation = true; + }, + get isCanceled() { + return canceled; + }, + get isPropagationAllowed() { + return allowPropagation; + }, + trigger, + ...custom + }; + return details; +} + +// node_modules/@base-ui/utils/esm/useId.js +var React10 = __toESM(require_react(), 1); + +// node_modules/@base-ui/utils/esm/safeReact.js +var React9 = __toESM(require_react(), 1); +var SafeReact = { + ...React9 +}; + +// node_modules/@base-ui/utils/esm/useId.js +var globalId = 0; +function useGlobalId(idOverride, prefix = "mui") { + const [defaultId, setDefaultId] = React10.useState(idOverride); + const id = idOverride || defaultId; + React10.useEffect(() => { + if (defaultId == null) { + globalId += 1; + setDefaultId(`${prefix}-${globalId}`); + } + }, [defaultId, prefix]); + return id; +} +var maybeReactUseId = SafeReact.useId; +function useId(idOverride, prefix) { + if (maybeReactUseId !== void 0) { + const reactId = maybeReactUseId(); + return idOverride ?? (prefix ? `${prefix}-${reactId}` : reactId); + } + return useGlobalId(idOverride, prefix); +} + +// node_modules/@base-ui/react/esm/internals/useBaseUiId.js +function useBaseUiId(idOverride) { + return useId(idOverride, "base-ui"); +} + +// node_modules/@base-ui/react/esm/internals/useAnimationsFinished.js +var ReactDOM = __toESM(require_react_dom(), 1); + +// node_modules/@base-ui/utils/esm/useOnMount.js +var React11 = __toESM(require_react(), 1); +var EMPTY = []; +function useOnMount(fn) { + React11.useEffect(fn, EMPTY); +} + +// node_modules/@base-ui/utils/esm/useAnimationFrame.js +var EMPTY2 = null; +var LAST_RAF = globalThis.requestAnimationFrame; +var Scheduler = class { + /* This implementation uses an array as a backing data-structure for frame callbacks. + * It allows `O(1)` callback cancelling by inserting a `null` in the array, though it + * never calls the native `cancelAnimationFrame` if there are no frames left. This can + * be much more efficient if there is a call pattern that alterns as + * "request-cancel-request-cancel-…". + * But in the case of "request-request-…-cancel-cancel-…", it leaves the final animation + * frame to run anyway. We turn that frame into a `O(1)` no-op via `callbacksCount`. */ + callbacks = []; + callbacksCount = 0; + nextId = 1; + startId = 1; + isScheduled = false; + tick = (timestamp) => { + this.isScheduled = false; + const currentCallbacks = this.callbacks; + const currentCallbacksCount = this.callbacksCount; + this.callbacks = []; + this.callbacksCount = 0; + this.startId = this.nextId; + if (currentCallbacksCount > 0) { + for (let i = 0; i < currentCallbacks.length; i += 1) { + currentCallbacks[i]?.(timestamp); + } + } + }; + request(fn) { + const id = this.nextId; + this.nextId += 1; + this.callbacks.push(fn); + this.callbacksCount += 1; + const didRAFChange = LAST_RAF !== requestAnimationFrame && (LAST_RAF = requestAnimationFrame, true); + if (!this.isScheduled || didRAFChange) { + requestAnimationFrame(this.tick); + this.isScheduled = true; + } + return id; + } + cancel(id) { + const index2 = id - this.startId; + if (index2 < 0 || index2 >= this.callbacks.length) { + return; + } + this.callbacks[index2] = null; + this.callbacksCount -= 1; + } +}; +var scheduler = new Scheduler(); +var AnimationFrame = class _AnimationFrame { + static create() { + return new _AnimationFrame(); + } + static request(fn) { + return scheduler.request(fn); + } + static cancel(id) { + return scheduler.cancel(id); + } + currentId = EMPTY2; + /** + * Executes `fn` after `delay`, clearing any previously scheduled call. + */ + request(fn) { + this.cancel(); + this.currentId = scheduler.request(() => { + this.currentId = EMPTY2; + fn(); + }); + } + cancel = () => { + if (this.currentId !== EMPTY2) { + scheduler.cancel(this.currentId); + this.currentId = EMPTY2; + } + }; + disposeEffect = () => { + return this.cancel; + }; +}; +function useAnimationFrame() { + const timeout = useRefWithInit(AnimationFrame.create).current; + useOnMount(timeout.disposeEffect); + return timeout; +} + +// node_modules/@base-ui/react/esm/utils/resolveRef.js +function resolveRef(maybeRef) { + if (maybeRef == null) { + return maybeRef; + } + return "current" in maybeRef ? maybeRef.current : maybeRef; +} + +// node_modules/@base-ui/react/esm/internals/stateAttributesMapping.js +var TransitionStatusDataAttributes = /* @__PURE__ */ (function(TransitionStatusDataAttributes2) { + TransitionStatusDataAttributes2["startingStyle"] = "data-starting-style"; + TransitionStatusDataAttributes2["endingStyle"] = "data-ending-style"; + return TransitionStatusDataAttributes2; +})({}); +var STARTING_HOOK = { + [TransitionStatusDataAttributes.startingStyle]: "" +}; +var ENDING_HOOK = { + [TransitionStatusDataAttributes.endingStyle]: "" +}; +var transitionStatusMapping = { + transitionStatus(value) { + if (value === "starting") { + return STARTING_HOOK; + } + if (value === "ending") { + return ENDING_HOOK; + } + return null; + } +}; + +// node_modules/@base-ui/react/esm/internals/useAnimationsFinished.js +function useAnimationsFinished(elementOrRef, waitForStartingStyleRemoved = false, treatAbortedAsFinished = true) { + const frame = useAnimationFrame(); + return useStableCallback((fnToExecute, signal = null) => { + frame.cancel(); + const element = resolveRef(elementOrRef); + if (element == null) { + return; + } + const resolvedElement = element; + const done = () => { + ReactDOM.flushSync(fnToExecute); + }; + if (typeof resolvedElement.getAnimations !== "function" || globalThis.BASE_UI_ANIMATIONS_DISABLED) { + fnToExecute(); + return; + } + function exec() { + Promise.all(resolvedElement.getAnimations().map((animation) => animation.finished)).then(() => { + if (!signal?.aborted) { + done(); + } + }).catch(() => { + if (treatAbortedAsFinished) { + if (!signal?.aborted) { + done(); + } + return; + } + const currentAnimations = resolvedElement.getAnimations(); + if (!signal?.aborted && currentAnimations.length > 0 && currentAnimations.some((animation) => animation.pending || animation.playState !== "finished")) { + exec(); + } + }); + } + if (waitForStartingStyleRemoved) { + const startingStyleAttribute = TransitionStatusDataAttributes.startingStyle; + if (!resolvedElement.hasAttribute(startingStyleAttribute)) { + frame.request(exec); + return; + } + const attributeObserver = new MutationObserver(() => { + if (!resolvedElement.hasAttribute(startingStyleAttribute)) { + attributeObserver.disconnect(); + exec(); + } + }); + attributeObserver.observe(resolvedElement, { + attributes: true, + attributeFilter: [startingStyleAttribute] + }); + signal?.addEventListener("abort", () => attributeObserver.disconnect(), { + once: true + }); + return; + } + frame.request(exec); + }); +} + +// node_modules/@base-ui/react/esm/internals/useTransitionStatus.js +var React12 = __toESM(require_react(), 1); +function useTransitionStatus(open, enableIdleState = false, deferEndingState = false) { + const [transitionStatus, setTransitionStatus] = React12.useState(open && enableIdleState ? "idle" : void 0); + const [mounted, setMounted] = React12.useState(open); + if (open && !mounted) { + setMounted(true); + setTransitionStatus("starting"); + } + if (!open && mounted && transitionStatus !== "ending" && !deferEndingState) { + setTransitionStatus("ending"); + } + if (!open && !mounted && transitionStatus === "ending") { + setTransitionStatus(void 0); + } + useIsoLayoutEffect(() => { + if (!open && mounted && transitionStatus !== "ending" && deferEndingState) { + const frame = AnimationFrame.request(() => { + setTransitionStatus("ending"); + }); + return () => { + AnimationFrame.cancel(frame); + }; + } + return void 0; + }, [open, mounted, transitionStatus, deferEndingState]); + useIsoLayoutEffect(() => { + if (!open || enableIdleState) { + return void 0; + } + const frame = AnimationFrame.request(() => { + setTransitionStatus(void 0); + }); + return () => { + AnimationFrame.cancel(frame); + }; + }, [enableIdleState, open]); + useIsoLayoutEffect(() => { + if (!open || !enableIdleState) { + return void 0; + } + if (open && mounted && transitionStatus !== "idle") { + setTransitionStatus("starting"); + } + const frame = AnimationFrame.request(() => { + setTransitionStatus("idle"); + }); + return () => { + AnimationFrame.cancel(frame); + }; + }, [enableIdleState, open, mounted, transitionStatus]); + return { + mounted, + setMounted, + transitionStatus + }; +} + +// node_modules/@base-ui/react/esm/internals/use-button/useButton.js +var React15 = __toESM(require_react(), 1); + +// node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.mjs +function hasWindow() { + return typeof window !== "undefined"; +} +function getNodeName(node) { + if (isNode(node)) { + return (node.nodeName || "").toLowerCase(); + } + return "#document"; +} +function getWindow(node) { + var _node$ownerDocument; + return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window; +} +function getDocumentElement(node) { + var _ref; + return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement; +} +function isNode(value) { + if (!hasWindow()) { + return false; + } + return value instanceof Node || value instanceof getWindow(value).Node; +} +function isElement(value) { + if (!hasWindow()) { + return false; + } + return value instanceof Element || value instanceof getWindow(value).Element; +} +function isHTMLElement(value) { + if (!hasWindow()) { + return false; + } + return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement; +} +function isShadowRoot(value) { + if (!hasWindow() || typeof ShadowRoot === "undefined") { + return false; + } + return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot; +} +function isOverflowElement(element) { + const { + overflow, + overflowX, + overflowY, + display + } = getComputedStyle2(element); + return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && display !== "inline" && display !== "contents"; +} +function isTableElement(element) { + return /^(table|td|th)$/.test(getNodeName(element)); +} +function isTopLayer(element) { + try { + if (element.matches(":popover-open")) { + return true; + } + } catch (_e) { + } + try { + return element.matches(":modal"); + } catch (_e) { + return false; + } +} +var willChangeRe = /transform|translate|scale|rotate|perspective|filter/; +var containRe = /paint|layout|strict|content/; +var isNotNone = (value) => !!value && value !== "none"; +var isWebKitValue; +function isContainingBlock(elementOrCss) { + const css = isElement(elementOrCss) ? getComputedStyle2(elementOrCss) : elementOrCss; + return isNotNone(css.transform) || isNotNone(css.translate) || isNotNone(css.scale) || isNotNone(css.rotate) || isNotNone(css.perspective) || !isWebKit() && (isNotNone(css.backdropFilter) || isNotNone(css.filter)) || willChangeRe.test(css.willChange || "") || containRe.test(css.contain || ""); +} +function getContainingBlock(element) { + let currentNode = getParentNode(element); + while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) { + if (isContainingBlock(currentNode)) { + return currentNode; + } else if (isTopLayer(currentNode)) { + return null; + } + currentNode = getParentNode(currentNode); + } + return null; +} +function isWebKit() { + if (isWebKitValue == null) { + isWebKitValue = typeof CSS !== "undefined" && CSS.supports && CSS.supports("-webkit-backdrop-filter", "none"); + } + return isWebKitValue; +} +function isLastTraversableNode(node) { + return /^(html|body|#document)$/.test(getNodeName(node)); +} +function getComputedStyle2(element) { + return getWindow(element).getComputedStyle(element); +} +function getNodeScroll(element) { + if (isElement(element)) { + return { + scrollLeft: element.scrollLeft, + scrollTop: element.scrollTop + }; + } + return { + scrollLeft: element.scrollX, + scrollTop: element.scrollY + }; +} +function getParentNode(node) { + if (getNodeName(node) === "html") { + return node; + } + const result = ( + // Step into the shadow DOM of the parent of a slotted node. + node.assignedSlot || // DOM Element detected. + node.parentNode || // ShadowRoot detected. + isShadowRoot(node) && node.host || // Fallback. + getDocumentElement(node) + ); + return isShadowRoot(result) ? result.host : result; +} +function getNearestOverflowAncestor(node) { + const parentNode = getParentNode(node); + if (isLastTraversableNode(parentNode)) { + return node.ownerDocument ? node.ownerDocument.body : node.body; + } + if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) { + return parentNode; + } + return getNearestOverflowAncestor(parentNode); +} +function getOverflowAncestors(node, list, traverseIframes) { + var _node$ownerDocument2; + if (list === void 0) { + list = []; + } + if (traverseIframes === void 0) { + traverseIframes = true; + } + const scrollableAncestor = getNearestOverflowAncestor(node); + const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body); + const win = getWindow(scrollableAncestor); + if (isBody) { + const frameElement = getFrameElement(win); + return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []); + } else { + return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes)); + } +} +function getFrameElement(win) { + return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null; +} + +// node_modules/@base-ui/react/esm/internals/composite/root/CompositeRootContext.js +var React13 = __toESM(require_react(), 1); +var CompositeRootContext = /* @__PURE__ */ React13.createContext(void 0); +if (true) CompositeRootContext.displayName = "CompositeRootContext"; +function useCompositeRootContext(optional = false) { + const context = React13.useContext(CompositeRootContext); + if (context === void 0 && !optional) { + throw new Error(true ? "Base UI: CompositeRootContext is missing. Composite parts must be placed within ." : formatErrorMessage_default(16)); + } + return context; +} + +// node_modules/@base-ui/react/esm/utils/useFocusableWhenDisabled.js +var React14 = __toESM(require_react(), 1); +function useFocusableWhenDisabled(parameters) { + const { + focusableWhenDisabled, + disabled: disabled2, + composite = false, + tabIndex: tabIndexProp = 0, + isNativeButton + } = parameters; + const isFocusableComposite = composite && focusableWhenDisabled !== false; + const isNonFocusableComposite = composite && focusableWhenDisabled === false; + const props = React14.useMemo(() => { + const additionalProps = { + // allow Tabbing away from focusableWhenDisabled elements + onKeyDown(event) { + if (disabled2 && focusableWhenDisabled && event.key !== "Tab") { + event.preventDefault(); + } + } + }; + if (!composite) { + additionalProps.tabIndex = tabIndexProp; + if (!isNativeButton && disabled2) { + additionalProps.tabIndex = focusableWhenDisabled ? tabIndexProp : -1; + } + } + if (isNativeButton && (focusableWhenDisabled || isFocusableComposite) || !isNativeButton && disabled2) { + additionalProps["aria-disabled"] = disabled2; + } + if (isNativeButton && (!focusableWhenDisabled || isNonFocusableComposite)) { + additionalProps.disabled = disabled2; + } + return additionalProps; + }, [composite, disabled2, focusableWhenDisabled, isFocusableComposite, isNonFocusableComposite, isNativeButton, tabIndexProp]); + return { + props + }; +} + +// node_modules/@base-ui/react/esm/internals/use-button/useButton.js +function useButton(parameters = {}) { + const { + disabled: disabled2 = false, + focusableWhenDisabled, + tabIndex = 0, + native: isNativeButton = true, + composite: compositeProp + } = parameters; + const elementRef = React15.useRef(null); + const compositeRootContext = useCompositeRootContext(true); + const isCompositeItem = compositeProp ?? compositeRootContext !== void 0; + const { + props: focusableWhenDisabledProps + } = useFocusableWhenDisabled({ + focusableWhenDisabled, + disabled: disabled2, + composite: isCompositeItem, + tabIndex, + isNativeButton + }); + if (true) { + React15.useEffect(() => { + if (!elementRef.current) { + return; + } + const isButtonTag = isButtonElement(elementRef.current); + if (isNativeButton) { + if (!isButtonTag) { + const ownerStackMessage = SafeReact.captureOwnerStack?.() || ""; + const message = "A component that acts as a button expected a native