diff --git a/bin/packages/check-build-type-declaration-files.js b/bin/packages/check-build-type-declaration-files.js index cd8bad2a70b53..fff0b51e32fc2 100644 --- a/bin/packages/check-build-type-declaration-files.js +++ b/bin/packages/check-build-type-declaration-files.js @@ -83,7 +83,7 @@ async function checkUnverifiedDeclarationFiles() { const packageDir = path.resolve( 'packages' ); const packageDirs = ( await fs.readdir( packageDir, { withFileTypes: true } ) - ) + ) .filter( ( dirent ) => dirent.isDirectory() ) .map( ( dirent ) => path.join( packageDir, dirent.name ) ); @@ -97,7 +97,7 @@ async function checkUnverifiedDeclarationFiles() { : null ) ) - ).filter( Boolean ); + ).filter( Boolean ); const tscResults = await Promise.allSettled( declarations.map( typecheckDeclarations ) diff --git a/bin/plugin/commands/packages.js b/bin/plugin/commands/packages.js index 4cf509764436c..fb83060b6e924 100644 --- a/bin/plugin/commands/packages.js +++ b/bin/plugin/commands/packages.js @@ -198,10 +198,9 @@ async function updatePackages( config ) { ); const changelogFilesPublicPackages = changelogFiles.filter( ( changelogPath ) => { - const pkg = require( path.join( - path.dirname( changelogPath ), - 'package.json' - ) ); + const pkg = require( + path.join( path.dirname( changelogPath ), 'package.json' ) + ); return pkg.private !== true; } ); diff --git a/bin/plugin/commands/performance.js b/bin/plugin/commands/performance.js index e153f482137e5..4be675a0a5d40 100644 --- a/bin/plugin/commands/performance.js +++ b/bin/plugin/commands/performance.js @@ -1,6 +1,7 @@ /** * External dependencies */ +const os = require( 'os' ); const fs = require( 'fs' ); const path = require( 'path' ); const SimpleGit = require( 'simple-git' ); @@ -13,7 +14,6 @@ const { runShellScript, readJSONFile, askForConfirmation, - getRandomTemporaryPath, getFilesFromDir, } = require( '../lib/utils' ); const config = require( '../config' ); @@ -31,6 +31,19 @@ const RESULTS_FILE_SUFFIX = '.performance-results.json'; * @property {string=} wpVersion The WordPress version to be used as the base install for testing. */ +/** + * A logging helper for printing steps and their substeps. + * + * @param {number} indent Value to indent the log. + * @param {any} msg Message to log. + * @param {...any} args Rest of the arguments to pass to console.log. + */ +function logAtIndent( indent, msg, ...args ) { + const prefix = indent === 0 ? '▶ ' : '> '; + const newline = indent === 0 ? '\n' : ''; + return log( newline + ' '.repeat( indent ) + prefix + msg, ...args ); +} + /** * Sanitizes branch name to be used in a path or a filename. * @@ -64,14 +77,14 @@ function median( array ) { /** * Runs the performance tests on the current branch. * - * @param {string} testSuite Name of the tests set. - * @param {string} performanceTestDirectory Path to the performance tests' clone. - * @param {string} runKey Unique identifier for the test run. + * @param {string} testSuite Name of the tests set. + * @param {string} testRunnerDir Path to the performance tests' clone. + * @param {string} runKey Unique identifier for the test run. */ -async function runTestSuite( testSuite, performanceTestDirectory, runKey ) { +async function runTestSuite( testSuite, testRunnerDir, runKey ) { await runShellScript( `npm run test:performance -- ${ testSuite }`, - performanceTestDirectory, + testRunnerDir, { ...process.env, WP_ARTIFACTS_PATH: ARTIFACTS_PATH, @@ -95,23 +108,23 @@ async function runPerformanceTests( branches, options ) { branches = [ 'trunk' ]; } + log( formats.title( '\n💃 Performance Tests 🕺' ) ); log( - formats.title( '\n💃 Performance Tests 🕺\n' ), - '\nWelcome! This tool runs the performance tests on multiple branches and displays a comparison table.\n' + - 'In order to run the tests, the tool is going to load a WordPress environment on ports 8888 and 8889.\n' + - 'Make sure these ports are not used before continuing.\n' + '\nWelcome! This tool runs the performance tests on multiple branches and displays a comparison table.' ); if ( ! runningInCI ) { + log( + formats.warning( + '\nIn order to run the tests, the tool is going to load a WordPress environment on ports 8888 and 8889.' + + '\nMake sure these ports are not used before continuing.\n' + ) + ); + await askForConfirmation( 'Ready to go? ' ); } - /* - * 1- Preparing the tests directory. - */ - - log( '\n>> Preparing the tests directories' ); - log( ' >> Cloning the repository' ); + logAtIndent( 0, 'Setting up' ); /** * @type {string[]} git refs against which to run tests; @@ -121,121 +134,162 @@ async function runPerformanceTests( branches, options ) { throw new Error( `Need at least two git refs to run` ); } - const baseDirectory = getRandomTemporaryPath(); - fs.mkdirSync( baseDirectory, { recursive: true } ); + const baseDir = path.join( os.tmpdir(), 'wp-performance-tests' ); + + if ( fs.existsSync( baseDir ) ) { + logAtIndent( 1, 'Removing existing files' ); + fs.rmSync( baseDir, { recursive: true } ); + } + + logAtIndent( 1, 'Creating base directory:', formats.success( baseDir ) ); + fs.mkdirSync( baseDir ); + + logAtIndent( 1, 'Setting up repository' ); + const sourceDir = path.join( baseDir, 'source' ); + + logAtIndent( 2, 'Creating directory:', formats.success( sourceDir ) ); + fs.mkdirSync( sourceDir ); // @ts-ignore - const git = SimpleGit( baseDirectory ); - await git + const sourceGit = SimpleGit( sourceDir ); + logAtIndent( + 2, + 'Initializing:', + formats.success( config.gitRepositoryURL ) + ); + await sourceGit .raw( 'init' ) .raw( 'remote', 'add', 'origin', config.gitRepositoryURL ); - for ( const branch of branches ) { - await git.raw( 'fetch', '--depth=1', 'origin', branch ); + for ( const [ i, branch ] of branches.entries() ) { + logAtIndent( + 2, + `Fetching environment branch (${ i + 1 } of ${ branches.length }):`, + formats.success( branch ) + ); + await sourceGit.raw( 'fetch', '--depth=1', 'origin', branch ); } - await git.raw( 'checkout', branches[ 0 ] ); + const testRunnerBranch = options.testsBranch || branches[ 0 ]; + if ( options.testsBranch && ! branches.includes( options.testsBranch ) ) { + logAtIndent( + 2, + 'Fetching test runner branch:', + formats.success( options.testsBranch ) + ); + // @ts-ignore + await sourceGit.raw( + 'fetch', + '--depth=1', + 'origin', + options.testsBranch + ); + } else { + logAtIndent( + 2, + 'Using test runner branch:', + formats.success( testRunnerBranch ) + ); + } - const rootDirectory = getRandomTemporaryPath(); - const performanceTestDirectory = rootDirectory + '/tests'; - await runShellScript( 'mkdir -p ' + rootDirectory ); - await runShellScript( - 'cp -R ' + baseDirectory + ' ' + performanceTestDirectory - ); + logAtIndent( 1, 'Setting up test runner' ); - if ( !! options.testsBranch ) { - const branchName = formats.success( options.testsBranch ); - log( ` >> Fetching the test-runner branch: ${ branchName }` ); + const testRunnerDir = path.join( baseDir + '/tests' ); - // @ts-ignore - await SimpleGit( performanceTestDirectory ) - .raw( 'fetch', '--depth=1', 'origin', options.testsBranch ) - .raw( 'checkout', options.testsBranch ); - } + logAtIndent( 2, 'Copying source to:', formats.success( testRunnerDir ) ); + await runShellScript( `cp -R ${ sourceDir } ${ testRunnerDir }` ); - log( ' >> Installing dependencies and building packages' ); + logAtIndent( + 2, + 'Checking out branch:', + formats.success( testRunnerBranch ) + ); + // @ts-ignore + await SimpleGit( testRunnerDir ).raw( 'checkout', testRunnerBranch ); + + logAtIndent( 2, 'Installing dependencies and building' ); await runShellScript( - `bash -c "${ [ - 'source $HOME/.nvm/nvm.sh', - 'nvm install', - 'npm ci', - 'npx playwright install chromium --with-deps', - 'npm run build:packages', - ].join( ' && ' ) }"`, - performanceTestDirectory + `bash -c "source $HOME/.nvm/nvm.sh && nvm install && npm ci && npx playwright install chromium --with-deps && npm run build:packages"`, + testRunnerDir ); - log( ' >> Creating the environment folders' ); - await runShellScript( 'mkdir -p ' + rootDirectory + '/envs' ); - /* - * 2- Preparing the environment directories per branch. - */ + logAtIndent( 1, 'Setting up test environments' ); + + const envsDir = path.join( baseDir, 'environments' ); + logAtIndent( 2, 'Creating parent directory:', formats.success( envsDir ) ); + fs.mkdirSync( envsDir ); + + let wpZipUrl = null; + if ( options.wpVersion ) { + // In order to match the topology of ZIP files at wp.org, remap .0 + // patch versions to major versions: + // + // 5.7 -> 5.7 (unchanged) + // 5.7.0 -> 5.7 (changed) + // 5.7.2 -> 5.7.2 (unchanged) + const zipVersion = options.wpVersion.replace( /^(\d+\.\d+).0/, '$1' ); + wpZipUrl = `https://wordpress.org/wordpress-${ zipVersion }.zip`; + } - log( '\n>> Preparing an environment directory per branch' ); - const branchDirectories = {}; + const branchDirs = {}; for ( const branch of branches ) { - log( ` >> Branch: ${ branch }` ); - const sanitizedBranch = sanitizeBranchName( branch ); - const environmentDirectory = rootDirectory + '/envs/' + sanitizedBranch; + logAtIndent( 2, 'Branch:', formats.success( branch ) ); + const sanitizedBranchName = sanitizeBranchName( branch ); + const envDir = path.join( envsDir, sanitizedBranchName ); + + logAtIndent( 3, 'Creating directory:', formats.success( envDir ) ); + fs.mkdirSync( envDir ); // @ts-ignore - branchDirectories[ branch ] = environmentDirectory; - const buildPath = `${ environmentDirectory }/plugin`; - await runShellScript( 'mkdir ' + environmentDirectory ); - await runShellScript( `cp -R ${ baseDirectory } ${ buildPath }` ); + branchDirs[ branch ] = envDir; + const buildDir = path.join( envDir, 'plugin' ); - const fancyBranch = formats.success( branch ); + logAtIndent( 3, 'Copying source to:', formats.success( buildDir ) ); + await runShellScript( `cp -R ${ sourceDir } ${ buildDir }` ); - if ( branch === options.testsBranch ) { - log( - ` >> Re-using the testing branch for ${ fancyBranch }` - ); - await runShellScript( - `cp -R ${ performanceTestDirectory } ${ buildPath }` - ); - } else { - log( ` >> Fetching the ${ fancyBranch } branch` ); - // @ts-ignore - await SimpleGit( buildPath ).reset( 'hard' ).checkout( branch ); - } + logAtIndent( 3, 'Checking out:', formats.success( branch ) ); + // @ts-ignore + await SimpleGit( buildDir ).raw( 'checkout', branch ); - log( ` >> Building the ${ fancyBranch } branch` ); + logAtIndent( 3, 'Installing dependencies and building' ); await runShellScript( - 'bash -c "source $HOME/.nvm/nvm.sh && nvm install && npm ci && npm run prebuild:packages && node ./bin/packages/build.js && npx wp-scripts build"', - buildPath + `bash -c "source $HOME/.nvm/nvm.sh && nvm install && npm ci && npm run build"`, + buildDir + ); + + const wpEnvConfigPath = path.join( envDir, '.wp-env.json' ); + + logAtIndent( + 3, + 'Saving wp-env config to:', + formats.success( wpEnvConfigPath ) ); - // Create the config file for the current env. fs.writeFileSync( - path.join( environmentDirectory, '.wp-env.json' ), + wpEnvConfigPath, JSON.stringify( { config: { WP_DEBUG: false, SCRIPT_DEBUG: false, }, - core: 'WordPress/WordPress', - plugins: [ path.join( environmentDirectory, 'plugin' ) ], - themes: [ - path.join( - performanceTestDirectory, - 'test/emptytheme' - ), - ], + core: wpZipUrl || 'WordPress/WordPress', + plugins: [ buildDir ], + themes: [ path.join( testRunnerDir, 'test/emptytheme' ) ], env: { tests: { mappings: { 'wp-content/mu-plugins': path.join( - performanceTestDirectory, + testRunnerDir, 'packages/e2e-tests/mu-plugins' ), 'wp-content/plugins/gutenberg-test-plugins': path.join( - performanceTestDirectory, + testRunnerDir, 'packages/e2e-tests/plugins' ), 'wp-content/themes/gutenberg-test-themes': path.join( - performanceTestDirectory, + testRunnerDir, 'test/gutenberg-test-themes' ), 'wp-content/themes/gutenberg-test-themes/twentytwentyone': @@ -251,99 +305,61 @@ async function runPerformanceTests( branches, options ) { ), 'utf8' ); - - if ( options.wpVersion ) { - // In order to match the topology of ZIP files at wp.org, remap .0 - // patch versions to major versions: - // - // 5.7 -> 5.7 (unchanged) - // 5.7.0 -> 5.7 (changed) - // 5.7.2 -> 5.7.2 (unchanged) - const zipVersion = options.wpVersion.replace( - /^(\d+\.\d+).0/, - '$1' - ); - const zipUrl = `https://wordpress.org/wordpress-${ zipVersion }.zip`; - log( ` Using WordPress version ${ zipVersion }` ); - - // Patch the environment's .wp-env.json config to use the specified WP - // version: - // - // { - // "core": "https://wordpress.org/wordpress-$VERSION.zip", - // ... - // } - const confPath = `${ environmentDirectory }/.wp-env.json`; - const conf = { ...readJSONFile( confPath ), core: zipUrl }; - await fs.writeFileSync( - confPath, - JSON.stringify( conf, null, 2 ), - 'utf8' - ); - } } - // Printing the used folders. - log( - '\n>> Perf Tests Directory : ' + - formats.success( performanceTestDirectory ) - ); - for ( const branch of branches ) { - // @ts-ignore - const envPath = formats.success( branchDirectories[ branch ] ); - log( `>> Environment Directory (${ branch }) : ${ envPath }` ); - } - - /* - * 3- Running the tests. - */ - - log( '\n>> Running the tests' ); + logAtIndent( 0, 'Looking for test files' ); const testSuites = getFilesFromDir( - path.join( performanceTestDirectory, 'test/performance/specs' ) - ).map( ( file ) => path.basename( file, '.spec.js' ) ); + path.join( testRunnerDir, 'test/performance/specs' ) + ).map( ( file ) => { + logAtIndent( 1, 'Found:', formats.success( file ) ); + return path.basename( file, '.spec.js' ); + } ); + + logAtIndent( 0, 'Running tests' ); + + if ( wpZipUrl ) { + logAtIndent( + 1, + 'Using:', + formats.success( `WordPress v${ options.wpVersion }` ) + ); + } else { + logAtIndent( 1, 'Using:', formats.success( 'WordPress trunk' ) ); + } - const wpEnvPath = path.join( - performanceTestDirectory, - 'node_modules/.bin/wp-env' - ); + const wpEnvPath = path.join( testRunnerDir, 'node_modules/.bin/wp-env' ); for ( const testSuite of testSuites ) { for ( let i = 1; i <= TEST_ROUNDS; i++ ) { - const roundInfo = `round ${ i } of ${ TEST_ROUNDS }`; - log( ` >> Suite: ${ testSuite } (${ roundInfo })` ); + logAtIndent( + 1, + // prettier-ignore + `Suite: ${ formats.success( testSuite ) } (round ${ i } of ${ TEST_ROUNDS })` + ); + for ( const branch of branches ) { - const sanitizedBranch = sanitizeBranchName( branch ); - const runKey = `${ testSuite }_${ sanitizedBranch }_round-${ i }`; + logAtIndent( 2, 'Branch:', formats.success( branch ) ); + + const sanitizedBranchName = sanitizeBranchName( branch ); + const runKey = `${ testSuite }_${ sanitizedBranchName }_round-${ i }`; // @ts-ignore - const environmentDirectory = branchDirectories[ branch ]; - log( ` >> Branch: ${ branch }` ); - log( ' >> Starting the environment.' ); - await runShellScript( - `${ wpEnvPath } start`, - environmentDirectory - ); - log( ' >> Running the test.' ); - await runTestSuite( - testSuite, - performanceTestDirectory, - runKey - ); - log( ' >> Stopping the environment' ); - await runShellScript( - `${ wpEnvPath } stop`, - environmentDirectory - ); + const envDir = branchDirs[ branch ]; + + logAtIndent( 3, 'Starting environment' ); + await runShellScript( `${ wpEnvPath } start`, envDir ); + + logAtIndent( 3, 'Running tests' ); + await runTestSuite( testSuite, testRunnerDir, runKey ); + + logAtIndent( 3, 'Stopping environment' ); + await runShellScript( `${ wpEnvPath } stop`, envDir ); } } } - /* - * 4- Formatting and saving the results. - */ + logAtIndent( 0, 'Calculating results' ); - // Load curated results from each round. const resultFiles = getFilesFromDir( ARTIFACTS_PATH ).filter( ( file ) => file.endsWith( RESULTS_FILE_SUFFIX ) ); @@ -352,17 +368,21 @@ async function runPerformanceTests( branches, options ) { // Calculate medians from all rounds. for ( const testSuite of testSuites ) { - results[ testSuite ] = {}; + logAtIndent( 1, 'Test suite:', formats.success( testSuite ) ); + results[ testSuite ] = {}; for ( const branch of branches ) { - const sanitizedBranch = sanitizeBranchName( branch ); + const sanitizedBranchName = sanitizeBranchName( branch ); const resultsRounds = resultFiles .filter( ( file ) => file.includes( - `${ testSuite }_${ sanitizedBranch }_round-` + `${ testSuite }_${ sanitizedBranchName }_round-` ) ) - .map( ( file ) => readJSONFile( file ) ); + .map( ( file ) => { + logAtIndent( 2, 'Reading from:', formats.success( file ) ); + return readJSONFile( file ); + } ); const metrics = Object.keys( resultsRounds[ 0 ] ); results[ testSuite ][ branch ] = {}; @@ -378,25 +398,31 @@ async function runPerformanceTests( branches, options ) { } } } + const calculatedResultsPath = path.join( + ARTIFACTS_PATH, + testSuite + RESULTS_FILE_SUFFIX + ); - // Save calculated results to file. + logAtIndent( + 2, + 'Saving curated results to:', + formats.success( calculatedResultsPath ) + ); fs.writeFileSync( - path.join( ARTIFACTS_PATH, testSuite + RESULTS_FILE_SUFFIX ), + calculatedResultsPath, JSON.stringify( results[ testSuite ], null, 2 ) ); } - /* - * 5- Displaying the results. - */ - - log( '\n>> 🎉 Results.\n' ); + logAtIndent( 0, 'Printing results' ); log( - '\nPlease note that client side metrics EXCLUDE the server response time.\n' + formats.warning( + '\nPlease note that client side metrics EXCLUDE the server response time.' + ) ); for ( const testSuite of testSuites ) { - log( `\n>> ${ testSuite }\n` ); + logAtIndent( 0, formats.success( testSuite ) ); // Invert the results so we can display them in a table. /** @type {Record>} */ diff --git a/docs/contributors/code/coding-guidelines.md b/docs/contributors/code/coding-guidelines.md index e7ff0a4084306..12c3ad96cb85f 100644 --- a/docs/contributors/code/coding-guidelines.md +++ b/docs/contributors/code/coding-guidelines.md @@ -207,24 +207,25 @@ You can attach private selectors and actions to a public store: ```js // In packages/package1/store.js: -import { privateHasContentRoleAttribute, ...selectors } from './selectors'; -import { privateToggleFeature, ...actions } from './selectors'; +import { privateHasContentRoleAttribute } from './private-selectors'; +import { privateToggleFeature } from './private-actions'; // The `lock` function is exported from the internal private-apis.js file where // the opt-in function was called. import { lock, unlock } from './lock-unlock'; -export const store = registerStore(/* ... */); +export const store = registerStore( /* ... */ ); // Attach a private action to the exported store: -unlock( store ).registerPrivateActions({ - privateToggleFeature +unlock( store ).registerPrivateActions( { + privateToggleFeature, } ); // Attach a private action to the exported store: -unlock( store ).registerPrivateSelectors({ - privateHasContentRoleAttribute +unlock( store ).registerPrivateSelectors( { + privateHasContentRoleAttribute, } ); +``` - +```js // In packages/package2/MyComponent.js: import { store } from '@wordpress/package1'; import { useSelect } from '@wordpress/data'; @@ -233,17 +234,18 @@ import { useSelect } from '@wordpress/data'; import { unlock } from './lock-unlock'; function MyComponent() { - const hasRole = useSelect( ( select ) => ( - // Use the private selector: - unlock( select( store ) ).privateHasContentRoleAttribute() + const hasRole = useSelect( + ( select ) => + // Use the private selector: + unlock( select( store ) ).privateHasContentRoleAttribute() // Note the unlock() is required. This line wouldn't work: - // select( store ).privateHasContentRoleAttribute() - ) ); + // select( store ).privateHasContentRoleAttribute() + ); // Use the private action: unlock( useDispatch( store ) ).privateToggleFeature(); - // ... + // ... } ``` @@ -263,7 +265,9 @@ lock( privateApis, { privateClass: class PrivateClass {}, privateVariable: 5, } ); +``` +```js // In packages/package2/index.js: import { privateApis } from '@wordpress/package1'; import { unlock } from './lock-unlock'; @@ -336,7 +340,9 @@ export function validateBlocks( blocks ) { export const privateApis = {}; lock( privateApis, { privateValidateBlocks } ); +``` +```js // In @wordpress/package2/index.js: import { privateApis as package1PrivateApis } from '@wordpress/package1'; import { unlock } from './lock-unlock'; @@ -363,30 +369,30 @@ const PrivateMyButton = ( { title, privateShowIcon = true } ) => { return ( ); -} +}; // The stable public component is a thin wrapper that calls the // private component with the private features disabled -export const MyButton = ( { title } ) => - +export const MyButton = ( { title } ) => ( + +); export const privateApis = {}; lock( privateApis, { PrivateMyButton } ); +``` - +```js // In @wordpress/package2/index.js: import { privateApis } from '@wordpress/package1'; import { unlock } from './lock-unlock'; // The private component may be "unlocked" given the stable component: -const { PrivateMyButton } = unlock(privateApis); +const { PrivateMyButton } = unlock( privateApis ); export function MyComponent() { - return ( - - ) + return ; } ``` @@ -438,13 +444,14 @@ function privateInCorePublicInPlugin() {} // Gutenberg treats both functions as private APIs internally: const privateApis = {}; -lock(privateApis, { privateEverywhere, privateInCorePublicInPlugin }); +lock( privateApis, { privateEverywhere, privateInCorePublicInPlugin } ); // The privateInCorePublicInPlugin function is explicitly exported, // but this export will not be merged into WordPress core thanks to // the process.env.IS_GUTENBERG_PLUGIN check. if ( process.env.IS_GUTENBERG_PLUGIN ) { - export const privateInCorePublicInPlugin = unlock( privateApis ).privateInCorePublicInPlugin; + export const privateInCorePublicInPlugin = + unlock( privateApis ).privateInCorePublicInPlugin; } ``` @@ -459,7 +466,7 @@ const a = 10; // Bad: const object = { a: a, - performAction: function() { + performAction: function () { // ... }, }; @@ -771,7 +778,7 @@ Documenting a function component should be treated the same as any other functio * * @return {?string} Block title. */ -``` +```` For class components, there is no recommendation for documenting the props of the component. Gutenberg does not use or endorse the [`propTypes` static class member](https://react.dev/reference/react/Component#static-proptypes). diff --git a/docs/getting-started/devenv/README.md b/docs/getting-started/devenv/README.md index 7c55bcb6393f1..0b578e3df3b6a 100644 --- a/docs/getting-started/devenv/README.md +++ b/docs/getting-started/devenv/README.md @@ -1,228 +1,51 @@ -# Development Environment +# Block Development Environment -This guide is for setting up your local environment for JavaScript development for creating plugins and tools to extend WordPress and the block editor. If you are looking to contribute to Gutenberg project itself, see additional documentation in the [Getting Started guide](/docs/contributors/code/getting-started-with-code-contribution.md). +This guide will help you set up the right development environment to create blocks and other plugins that extend and modify the Block Editor in WordPress. -A development environment is a catch-all term for what you need setup on your computer to work. The three main pieces needed for our development environment are: +To contribute to the Gutenberg project itself, refer to the additional documentation in the [code contribution guide](/docs/contributors/code/getting-started-with-code-contribution.md).` -1. Node/NPM Development Tools -2. WordPress Development Site -3. Code Editor +A block development environment includes the tools you need on your computer to successfully develop for the Block Editor. The three essential requirements are: -## Quick Start +1. [Code editor](#code-editor) +2. [Node.js development tools](#nodejs-development-tools) +3. [Local WordPress environment (site)](#local-wordpress-environment) -Here is a summary of the guide. See each section for additional details and explanations. +## Code editor -**1. Install Node development tools** +A code editor is used to write code, and you can use whichever editor you're most comfortable with. The key is having a way to open, edit, and save text files. -Download and install [Node Version Manager](https://github.com/nvm-sh/nvm) (nvm) +If you do not already have a preferred code editor, [Visual Studio Code](https://code.visualstudio.com/) (VS Code) is a popular choice for JavaScript development among Core contributors. It works well across the three major platforms (Windows, Linux, and Mac) and is open-source and actively maintained by Microsoft. VS Code also has a vibrant community providing plugins and extensions, including many for WordPress development. -``` -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash -``` +## Node.js development tools -Quit and restart terminal -Install Node.js v16. +Node.js (`node`) is an open-source runtime environment that allows you to execute JavaScript outside of the web browser. While Node.js is not required for all WordPress JavaScript development, it's essential when working with modern JavaScript tools and developing for the Block Editor. -``` -nvm install 16 -``` +Node.js and its accompanying development tools allow you to: -**2. WordPress Development Site** +- Install and run WordPress packages needed for Block Editor development, such as `wp-scripts` +- Setup local WordPress environments with `wp-env` and `wp-now` +- Use the latest ECMAScript features and write code in ESNext +- Lint, format, and test JavaScript code +- Scaffold custom blocks with the `create-block` package -First download, install, and start [Docker Desktop](https://www.docker.com/products/docker-desktop) following the instructions for your OS. +The list goes on. While modern JavaScript development can be challenging, WordPress provides several tools, like [`wp-scripts`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/) and [`create-block`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/), that streamline the process and are made possible by Node.js development tools. -- Install WordPress environment tool +**The recommended Node.js version for block development is [Active LTS](https://nodejs.dev/en/about/releases/) (Long Term Support)**. However, there are times when you need to to use different versions. A Node.js version manager tool like `nvm` is strongly recommended and allows you to easily change your `node` version when required. You will also need Node Package Manager (`npm`) and the Node Package eXecute (`npx`) to work with some WordPress packages. Both are installed automatically with Node.js. -``` -npm -g install @wordpress/env -``` +To be able to use the Node.js tools and [packages provided by WordPress](https://github.com/WordPress/gutenberg/tree/trunk/packages) for block development, you'll need to set a proper Node.js runtime environment on your machine.. To learn more about how to do this, refer to the links below. -Start the environment from an existing plugin or theme directory, or a new working directory: +- [Install Node.js for Mac and Linux](/docs/getting-started/devenv/nodejs-development-environment.md#node-js-installation-on-mac-and-linux-with-nvm) +- [Install Node.js for Windows](/docs/getting-started/devenv/nodejs-development-environment.md#node-js-installation-on-windows-and-others) -``` -wp-env start -``` +## Local WordPress environment -You will have a full WordPress site installed, navigate to: http://localhost:8888/ using your browser, log in to the WordPress dashboard at http://localhost:8888/wp-admin/ using Username "admin" and Password "password", without the quotes. +A local WordPress environment (site) provides a controlled, efficient, and secure space for development, allowing you to build and test your code before deploying it to a production site. The [same requirements](https://en-gb.wordpress.org/about/requirements/) for WordPress apply to local sites. -**3. Code Editor** +Many tools are available for setting up a local WordPress environment on your computer. The Block Editor Handbook covers `wp-env` and `wp-now`, both of which are open-source and maintained by the WordPress project itself. -You can use any text editor to write code. For example, [Visual Studio Code](https://code.visualstudio.com/) is a popular open-source editor. You can follow instructions on their site to install it for your OS. +Refer to the individual guides below for setup instructions. -## Node Development Tools +- [Get started with `wp-env`](/docs/getting-started/devenv/get-started-with-wp-env.md) +- [Get started with `wp-now`](/docs/getting-started/devenv/get-started-with-wp-now.md) -The tools needed for development are **Node** and **NPM**. **Nodejs** is a runtime environment that allows running JavaScript outside of the browser. NPM is the Node Package Manager, it is used for installing dependencies and running scripts. The script `npx` is also installed with Nodejs—this script is used to run packages not yet installed—we will use `npx` to bootstrap a block. - -The tools are used to convert the JavaScript we are going to write into a format that browsers can run. This is called transpiling or the build step. - -For Mac and Linux, it is recommended to use the [Node Version Manager](https://github.com/nvm-sh/nvm) (nvm). Using `nvm` to install node allows installing specific versions, plus installs locally in your home directory and avoids any global permission issues. - -For Windows, or alternative installs, you can [download a Nodejs installer](https://nodejs.org/en/download/) directly from the main Node.js website, v14 is recommended. Installers are available for Windows and Mac, and binaries available for Linux. See Node.js site for additional installation methods. - -Here are the quick instructions to install using nvm, see the [full installation instructions](https://github.com/nvm-sh/nvm#installing-and-updating) for additional details. - -Run the following on the command-line to install nvm: - -```sh -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash -``` - -Note: On macOS, the required developer tools are not installed by default, if not already installed you may be prompted to download the install. - -Mac git command requires command line developer tools - -After installing nvm, you need to use it to install Node.js, to install v16, run: - -```sh -nvm install 16 -``` - -If there is an error running the above command, for example a common error that occurs is: - -```sh -$ nvm install 16 -zsh: command not found: nvm -``` - -First, try quitting and restarting your terminal to pick up the installed config. - -If restarting did not resolve the problem, you might need to create the default profile file. - -On macOS Catalina, the default shell is zsh, to create the profile file type `touch ~/.zshrc` on the command-line. It is fine to run if the file already exists. Note, `~/` is a shortcut to your home directory. For Ubuntu, including WSL, the default profile is bash, use `touch ~/.bashrc` to create. - -After creating the profile file, re-run the install command: - -```sh -nvm install 16 -``` - -The important part after installing is being able to use them in your terminal. Open a terminal command-line and type `node -v` and `npm -v` to confirm they are installed. - -```sh -> node -v -v16.20.1 - -> npm -v -8.19.4 -``` - -Your versions may not match exactly, that is fine. The minimum version for Node.js is >= 12 and for npm >= 6.9, using v14 will be supported until upgrade is required. - -## WordPress Development Site - -There are several ways to run WordPress locally on your own computer, or you could even develop on a cloud hosted computer, though this may be slower. - -The WordPress [wp-env package](https://www.npmjs.com/package/@wordpress/env) lets you set up a local WordPress environment for building and testing plugins and themes, without any additional configuration. - -The `wp-env` tool uses Docker to create a virtual machine that runs the WordPress site. There are instructions available for installing Docker on [Windows 10 Pro](https://docs.docker.com/docker-for-windows/install/), [other versions of Windows 10](https://docs.docker.com/docker-for-windows/wsl/), [macOS](https://docs.docker.com/docker-for-mac/install/), and [Linux](https://docs.docker.com/v17.12/install/linux/docker-ce/ubuntu/#install-using-the-convenience-script). If using Ubuntu, see our additional notes for [help installing Docker on Ubuntu](/docs/getting-started/devenv/docker-ubuntu.md). - -After you have installed Docker, go ahead and install the `wp-env` tool. This command will install the tool globally, which means you can run it from any directory: - -```sh -npm -g install @wordpress/env -``` - -To confirm it is installed and available, run: - -```sh -wp-env --version -> 1.6.0 -``` - -The `wp-env` script is used to create a Docker WordPress environment. You can use this script to start an environment with your plugin activated by running it from the directory containing your plugin. For example if you are following the create block tutorial, this would be in the generated directory like so: - -```sh -npx @wordpress/create-block starter-block -cd starter-block -wp-env start -``` - -You can access your environment in your browser at: [http://localhost:8888/](http://localhost:8888/), the default username is `admin` and default password is `password`. For more information controlling the Docker environment see the [@wordpress/env package readme](/packages/env/README.md). - -When using the script while developing a single plugin, `wp-env start` can mount and activate the plugin automatically when run from the directory containing the plugin. Note: This also works for themes when run from the directory in which you are developing the theme. - -If you run `wp-env start` from a directory that is not a plugin or theme, a generic WordPress environment will be created. The script will display the following warning, it is fine if this is your intention. - -``` -!! Warning: could not find a .wp-env.json configuration file and could not determine if 'DIR' is a WordPress installation, a plugin, or a theme. -``` - -You can use the `.wp-env.json` configuration file to create an environment that works with multiple plugins and/or themes. See the [@wordpress/env package for additional details](/packages/env/README.md#wp-envjson). - -#### Troubleshooting - -A common issue when running `wp-env` is `Error while running docker-compose command.` - -- Check that Docker Desktop is started and running. -- Check Docker Desktop dashboard for logs, restart, or remove existing VMs. - -If you see the error: `Host is already in use by another container` - -- The container is already running, or another one is. You can stop an existing container running use `wp-env stop` from the directory you started it. -- If you do not remember the directory you started wp-env in, you can stop all containers with `docker stop $(docker ps -q)`. Please note, this will stop all containers, use caution with this command. - -### Alternative to Docker - -Docker is just one method to run a local WordPress environment. Block development and extending WordPress is done using normal plugins, so any WordPress environment can be used. Here are some alternatives that you can consider which do not require installing Docker. - -- [Local](https://localwp.com/) - Local is a single application you download and install. You will need to know where the plugin directory is located after install. If you create a site called `mywp` typically the plugin directory is installed at `~\Local Sites\mywp\app\public\wp-content\plugins`. When working with gutenberg it is recommended to place your install in your own gutenberg folder. This avoids potential issue with the build processes. - -- [WampServer](http://www.wampserver.com/en/) or [MAMP](https://www.mamp.info/) environments, both are quite similar to Local, combining a web server, PHP, and database. However these tools are not WordPress specific, so if you are not already using them, Local might be an easier option. - -- Remote server - you can work on a remote server, most hosts provide a quick WordPress setup. However, this will require additional time thorughout development syncing to the server, or working directly on the remote server. - -The important part is having a WordPress site installed, and know where and how to update files in the plugins directory. - -## Code Editor - -[Visual Studio Code](https://code.visualstudio.com/) is a popular code editor for JavaScript development. It works quite well across the three major platforms (Windows, Linux, and Mac), it is open-source and actively maintained by Microsoft. Plus Visual Studio Code has a vibrant community providing plugins and extensions; it is becoming the defacto standard for web development. - -Alternative editors include [Sublime Text](https://www.sublimetext.com/) that is also available across platforms, though is a commercial product; or other free alternatives include [Vim](https://www.vim.org/), [Atom](https://atom.io/), and [Notepad++](https://notepad-plus-plus.org/) all support standard JavaScript style development. - -You can use any editor you're comfortable with, it is more a personal preference. The development setup for WordPress block editor is a common JavaScript environment and most editors have plugins and support. The key is having a way to open, edit, and save text files. - -## Uninstall - Start Over - -Here are a few instructions if you need to start over, or want to remove what was installed. - -### Local Environment - -- If you just want to reset and clean the WordPress database: - -``` -wp-env clean all -``` - -- To remove the local environment completely for a specific project: - -``` -wp-env destroy -``` - -- To completely uninstall wp-env tool: - -``` -npm -g uninstall @wordpress/env -``` - -- To uninstall Docker, or Visual Studio Code use your OS method to remove packages. For example, on Windows run "Add or remove programs". You can additionally uninstall from the Docker Desktop app, click the bug icon at the top to switch to this Troubleshoot screen. Click Uninstall or remove. - -![Docker Troubleshoot Screenshot](https://developer.wordpress.org/files/2020/08/docker-uninstall-screen.png) - -### Uninstall Node/NVM - -To uninstall Node/NVM, delete the NVM directory, this is typically installed at `$HOME/.nvm`, delete using - -``` -rm -rf "$HOME/.nvm" -``` - -If this does not work and the `$NVM_DIR` environment variable is set you can remove using `rm -rf "$NVM_DIR"` - -To clean up any installed JavaScript packages remove the global `.npm` directory at `$HOME/.npm`, - -``` -rm -rf "$HOME/.npm" -``` - -Just as you confirmed the installation worked, you can confirm the uninstall worked. First quit and restart terminal and then try to run `npm -v`, `node -v`, and `nvm -v` you should then see a "command not found" error in the terminal. +Of the two, `wp-env` is the more solid and complete solution. It's also the recommended tool for Gutenberg development. On the other hand, `wp-now` offers a simplified setup but is more limited than `wp-env`. Both are valid options, so the choice is yours. diff --git a/docs/getting-started/devenv/docker-ubuntu.md b/docs/getting-started/devenv/docker-ubuntu.md deleted file mode 100644 index 680798d74f4e8..0000000000000 --- a/docs/getting-started/devenv/docker-ubuntu.md +++ /dev/null @@ -1,60 +0,0 @@ -# How to setup local WordPress environment on Ubuntu - -This article covers setting up the local WordPress development environment using Docker on Ubuntu. - -For Ubuntu 20.04.1, the standard docker binaries in the repository work as needed: - -``` -sudo apt install docker.io docker-compose -``` - -For earlier versions of Ubuntu, the docker binaries included in repositories did not support the features needed for the WordPress environment. - -- For Ubuntu prior to 20.04.1, follow these [directions from Docker to install](https://docs.docker.com/install/linux/docker-ce/ubuntu/). Additionally `docker-compose` is required, you may need to install separately, see [ Docker compose documentation](https://docs.docker.com/compose/install/). - -## Troubleshooting - -If you run into this error, when running `npm run wp-env` from the Gutenberg directory: - -``` -ERROR: Couldn't connect to Docker daemon at http+docker://localhost - is it running? - -If it's at a non-standard location, specify the URL with the DOCKER_HOST environment variable. -``` - -First, make sure docker is running. You can check using `ps -ef | grep docker` which should show something like: - -``` -/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -``` - -If docker is not running, try to start the service using: - -``` -sudo systemctl start docker.service -``` - -If docker is running, then it is not listening how the WordPress environment is trying to communicate. Try adding the following service override file to include listening on tcp. See [this Docker documentation](https://docs.docker.com/config/daemon/remote-access/) on how to configure remote access for Docker daemon. - -``` -# /etc/systemd/system/docker.service.d/override.conf -[Service] -ExecStart= -ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376 -``` - -Restart the service from the command-line - -``` -sudo systemctl daemon-reload -sudo systemctl restart docker.service -``` - -After restarting the services, set the environment variable DOCKER_HOST and try starting using: - -``` -export DOCKER_HOST=tcp://127.0.0.1:2376 -npm run wp-env start -``` - -Your environment should be setup at: http://localhost:8888/ diff --git a/docs/getting-started/devenv/get-started-with-wp-env.md b/docs/getting-started/devenv/get-started-with-wp-env.md new file mode 100644 index 0000000000000..11a23fd9ac9e2 --- /dev/null +++ b/docs/getting-started/devenv/get-started-with-wp-env.md @@ -0,0 +1,140 @@ +# Get started with wp-env + +The [@wordpress/env](https://www.npmjs.com/package/@wordpress/env) package (`wp-env`) lets you set up a local WordPress environment (site) for building and testing plugins and themes, without any additional configuration. + +Before following this guide, install [Node.js development tools](/docs/getting-started/devenv#node-js-development-tools) if you have not already done so. + +## Quick start + +1. Download, install, and start [Docker Desktop](https://www.docker.com/products/docker-desktop) following the instructions for your operating system. +2. Run `npm -g install @wordpress/env` in the terminal to install `wp-env` globally. +3. In the terminal, navigate to an existing plugin directory, theme directory, or a new working directory. +4. Run `wp-env start` in the terminal to start the local WordPress environment. +5. After the script runs, navigate to `http://localhost:8888/wp-admin/` and log into the WordPress dashboard using username `admin` and password `password`. + +## Set up Docker Desktop + +The `wp-env` tool uses [Docker](https://www.docker.com/) to create a virtual machine that runs the local WordPress site. The Docker Desktop application is free for small businesses, personal use, education, and non-commercial open-source projects. See their [FAQ](https://docs.docker.com/desktop/faqs/general/#do-i-need-to-pay-to-use-docker-desktop) for more information. + +Use the links below to download and install Docker Desktop for your operating system. + +- [Docker Desktop for Mac](https://docs.docker.com/desktop/install/mac-install/) +- [Docker Desktop for Windows](https://docs.docker.com/desktop/install/windows-install/) +- [Docker Desktop for Linux](https://docs.docker.com/desktop/install/linux-install/) + +If you are using a version of Ubuntu prior to 20.04.1, see the additional [troubleshooting notes](#ubuntu-docker-setup) below. + +After successful installation, start the Docker Desktop application and follow the prompts to get set up. You should generally use the recommended (default) settings, and creating a Docker account is optional. + +## Install and run `wp-env` + +The `wp-env` tool is used to create a local WordPress environment with Docker. So, after you have set up Docker Desktop, open the terminal and install the `wp-env` by running the command: + +```sh +npm -g install @wordpress/env +``` + +This will install the `wp-env` globally, allowing the tool to be run from any directory. To confirm it's installed and available, run `wp-env --version`, and the version number should appear. + +Next, navigate to an existing plugin directory, theme directory, or a new working directory in the terminal and run: + +```sh +wp-env start +``` + +Once the script completes, you can access the local environment at: `http://localhost:8888`. Log into the WordPress dashboard using username `admin` and password `password`. + +
+ Some projects, like Gutenberg, include their own specific wp-env configurations, and the documentation might prompt you to run npm run start wp-env instead. +
+ +For more information on controlling the Docker environment, see the [@wordpress/env package](/packages/env/README.md) readme. + +### Where to run `wp-env` + +The `wp-env` tool can run from practically anywhere. When using the script while developing a single plugin, `wp-env start` can mount and activate the plugin automatically when run from the directory containing the plugin. This also works for themes when run from the directory in which you are developing the theme. + +A generic WordPress environment will be created if you run `wp-env start` from a directory that is not a plugin or theme. The script will display the following warning, but ignore if this is your intention. + +``` +!! Warning: could not find a .wp-env.json configuration file and could not determine if 'DIR' is a WordPress installation, a plugin, or a theme. +``` + +You can also use the `.wp-env.json` configuration file to create an environment that works with multiple plugins and/or themes. See the [@wordpress/env package](/packages/env/README.md#wp-envjson) readme for more configuration details. + +### Uninstall or reset `wp-env` + +Here are a few instructions if you need to start over or want to remove what was installed. + +- If you just want to reset and clean the WordPress database, run `wp-env clean all` +- To remove the local environment completely for a specific project, run `wp-env destroy` +- To globally uninstall the `wp-env` tool, run `npm -g uninstall @wordpress/env` + +## Troubleshooting + +### Common errors + +When using `wp-env`, it's common to get the error: `Error while running docker-compose command` + +- Check that Docker Desktop is started and running. +- Check Docker Desktop dashboard for logs, restart, or remove existing virtual machines. +- Then try rerunning `wp-env start`. + +If you see the error: `Host is already in use by another container` + +- The container you are attempting to start is already running, or another container is. You can stop an existing container by running `wp-env stop` from the directory that you started it in. +- If you do not remember the directory where you started `wp-env`, you can stop all containers by running `docker stop $(docker ps -q)`. This will stop all Docker containers, so use with caution. +- Then try rerunning `wp-env start`. + +### Ubuntu Docker setup + +If you are using a version of Ubuntu prior to 20.04.1, you may encounter errors when setting up a local WordPress environment with `wp-env`. + +To resolve this, start by following the [installation guide](https://docs.docker.com/install/linux/docker-ce/ubuntu/) from Docker. `docker-compose` is also required, which you may need to install separately. Refer to the [Docker compose documentation](https://docs.docker.com/compose/install/). + +Once Docker and `wp-env` are installed, and assuming `wp-env` is configured globally, try running `wp-env start` in a directory. If you run into this error: + +``` +ERROR: Couldn't connect to Docker daemon at http+docker://localhost - is it running? + +If it's at a non-standard location, specify the URL with the DOCKER_HOST environment variable. +``` + +First, make sure Docker is running. You can check by running `ps -ef | grep docker`, which should return something like: + +``` +/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock +``` + +If Docker is not running, try starting the service by running `sudo systemctl start docker.service`. + +If Docker is running, then it is not listening to how the WordPress environment is trying to communicate. Try adding the following service override file to include listening on `tcp`. See [this Docker documentation](https://docs.docker.com/config/daemon/remote-access/) on how to configure remote access for Docker daemon. + +``` +# /etc/systemd/system/docker.service.d/override.conf +[Service] +ExecStart= +ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376 +``` + +Restart the service from the command-line: + +``` +sudo systemctl daemon-reload +sudo systemctl restart docker.service +``` + +After restarting the services, set the environment variable `DOCKER_HOST` and try starting `wp-env` with: + +``` +export DOCKER_HOST=tcp://127.0.0.1:2376 +wp-env start +``` + +Your environment should now be set up at `http://localhost:8888/`. + +## Additional resources + +- [@wordpress/env](https://www.npmjs.com/package/@wordpress/env) (Official documentation) +- [Docker Desktop](https://docs.docker.com/desktop) (Official documentation) +- [Quick and easy local WordPress development with wp-env](https://developer.wordpress.org/news/2023/03/quick-and-easy-local-wordpress-development-with-wp-env/) (WordPress Developer Blog) diff --git a/docs/getting-started/devenv/get-started-with-wp-now.md b/docs/getting-started/devenv/get-started-with-wp-now.md new file mode 100644 index 0000000000000..cb0fd4986328f --- /dev/null +++ b/docs/getting-started/devenv/get-started-with-wp-now.md @@ -0,0 +1,66 @@ +# Get started with wp-now + +The [@wp-now/wp-now](https://www.npmjs.com/package/@wordpress/env) package (`wp-now`) is a lightweight tool powered by [WordPress Playground](https://developer.wordpress.org/playground/) that streamlines setting up a local WordPress environment. + +Before following this guide, install [Node.js development tools](/docs/getting-started/devenv#nodejs-development-tools) if you have not already done so. It's recommended that you use the latest version of `node`. `wp-now` requires at least `node` v18 and v20 if you intend to use its [Blueprints](https://github.com/WordPress/playground-tools/tree/trunk/packages/wp-now#using-blueprints) feature. + +## Quick start + +1. Run `npm -g install @wp-now/wp-now` in the terminal to install `wp-now` globally. +2. In the terminal, navigate to an existing plugin directory, theme directory, or a new working directory. +3. Run `wp-now start` in the terminal to start the local WordPress environment. +4. After the script runs, your default web browser will automatically open the new local site, and you'll be logged in with the username `admin` and the password `password`. + +## Install and run `wp-now` + +Under the hood, `wp-now` is powered by WordPress Playground and only requires Node.js, unlike `wp-env`, which also requires Docker. To install `wp-now`, open the terminal and run the command: + +```sh +npm -g install @wp-now/wp-now +``` + +This will install the `wp-now` globally, allowing the tool to be run from any directory. To confirm it's installed and available, run `wp-now --version`, and the version number should appear. + +Next, navigate to an existing plugin directory, theme directory, or a new working directory in the terminal and run: + +```sh +wp-now start +``` + +After the script runs, your default web browser will automatically open the new local site, and you'll be logged in with the username `admin` and the password `password`. + +
+ If you encounter any errors when running wp-now start, make sure that you are using at least node v18, or v20 if you are using the Blueprint feature. +
+ +When running `wp-now` you can also pass arguments that modify the behavior of the WordPress environment. For example, `wp-now start --wp=6.3 --php=8` will start a site running WordPress 6.3 and PHP 8, which can be useful for testing purposes. + +Refer to the [@wp-now/wp-now](https://github.com/WordPress/playground-tools/tree/trunk/packages/wp-now) documentation for all available arguments. + +### Where to run `wp-now` + +The `wp-now` tool can be used practically anywhere and has different modes depending on how the directory is set up when you run `wp-now start`. Despite the many options, when developing for the Block Editor, you will likely use: + +- `plugin`, `theme`, or `wp-content`: Loads the project files into a virtual filesystem with WordPress and a SQLite-based database. Everything (including WordPress core files, the database, wp-config.php, etc.) is stored in the user's home directory and loaded into the virtual filesystem. The mode will be determined by: + - `plugin`: Presence of a PHP file with 'Plugin Name:' in its contents. + - `theme`: Presence of a `style.css` file with 'Theme Name:' in its contents. + - `wp-content`: Presence of `/plugins` and `/themes` subdirectories. +- `playground`: If no other mode conditions are matched, `wp-now` launches a completely virtualized WordPress site. + +Refer to the [@wp-now/wp-now](https://github.com/WordPress/playground-tools/tree/trunk/packages/wp-now) documentation for a more detailed explanation of all modes. + +### Known issues + +Since `wp-now` is a relatively new tool, there are a few [known issues](https://github.com/WordPress/playground-tools/tree/trunk/packages/wp-now#known-issues) to be aware of. However, these issues are unlikely to impact most block, theme, or plugin development. + +### Uninstall or reset `wp-now` + +Here are a few instructions if you need to start over or want to remove what was installed. + +- If you just want to reset and clean the WordPress database, run `wp-now --reset` +- To globally uninstall the `wp-now` tool, run `npm -g uninstall @wp-now/wp-now` + +## Additional resources + +- [@wp-now/wp-now](https://github.com/WordPress/playground-tools/tree/trunk/packages/wp-now) (Official documentation) +- [WordPress Playground](https://developer.wordpress.org/playground/) (Developer overview) \ No newline at end of file diff --git a/docs/getting-started/devenv/nodejs-development-environment.md b/docs/getting-started/devenv/nodejs-development-environment.md new file mode 100644 index 0000000000000..30cd2c861f229 --- /dev/null +++ b/docs/getting-started/devenv/nodejs-development-environment.md @@ -0,0 +1,50 @@ +# Node.js development environment + +When developing for the Block Editor, you will need [Node.js](https://nodejs.org/en) development tools along with a code editor and a local WordPress environment (see [Block Development Environment](README.md)). Node.js (`node`) is an open-source runtime environment that allows you to execute JavaScript code from the terminal (also known as a command-line interface, CLI, or shell) + +Installing `node` will automatically include the Node Package Manager (`npm`) and the Node Package eXecute (`npx`), two tools you will frequently use in block and plugin development. + +Node Package Manager ([`npm`](https://docs.npmjs.com/cli/v10/commands/npm)) serves multiple purposes, including dependency management and script execution. It's the recommended package manager and is extensively featured in all documentation. + +The Node Package eXecute ([`npx`](https://docs.npmjs.com/cli/v10/commands/npx)) tool is used to run commands from packages without installing them globally and is commonly used when scaffolding blocks with the [`create-block`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/) package. + + +## Node.js installation on Mac and Linux (with `nvm`) + +It's recommended that you use [Node Version Manager](https://github.com/nvm-sh/nvm) (`nvm`) to install Node.js. This allows you to install and manage specific versions of `node`, which are installed locally in your home directory, avoiding any global permission issues. + +Here are the quick instructions for installing `node` using `nvm` and setting the recommended Node.js version for block development. See the [complete installation guide](https://github.com/nvm-sh/nvm#installing-and-updating) for more details. + +1. Open the terminal and run the following to install `nvm`. On macOS, the required developer tools are not installed by default. Install them if prompted. + +```sh +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash +``` + +2. Quit and restart the terminal. +3. Run `nvm install --lts` in the terminal to install the latest [LTS](https://nodejs.dev/en/about/releases/) (Long Term Support) version of Node.js. +4. Run `node -v` and `npm -v` in the terminal to verify the installed `node` and `npm` versions. + +If needed, you can also install specific versions of `node`. For example, install version 18 by running `nvm install 18`, and switch between different versions by running `nvm use [version-number]`. See the `nvm` [usage guide](https://github.com/nvm-sh/nvm#usage) for more details. + +Some projects, like Gutenberg, include an [`.nvmrc`](https://github.com/WordPress/gutenberg/blob/trunk/.nvmrc) file which specifies the version of `node` that should be used. In this case, running `nvm use` will automatically select the correct version. If the version is not yet installed, you will get an error that tells you what version needs to be added. Run `nvm install [version-number]` followed by `nvm use`. + +## Node.js installation on Windows and others + +You can [download a Node.js installer](https://nodejs.org/en/download/) directly from the main Node.js website. The latest version is recommended. Installers are available for Windows and Mac, and binaries are available for Linux. + +Microsoft also provides a [detailed guide](https://learn.microsoft.com/en-us/windows/dev-environment/javascript/nodejs-on-windows#install-nvm-windows-nodejs-and-npm) on how to install `nvm` and Node.js on Windows and WSL. + +## Troubleshooting + +If you encounter the error `zsh: command not found: nvm` when attempting to install `node`, you might need to create the default profile file. + +The default shell is `zsh` on macOS, so create the profile file by running `touch ~/.zshrc` in the terminal. It's fine to run if the file already exists. The default profile is `bash` for Ubuntu, including WSL, so use `touch ~/.bashrc` instead. Then repeat steps 2-4. + +The latest `node` version should work for most development projects, but be aware that some packages and tools have specific requirements. If you encounter issues, you might need to install and use a previous `node` version. Also, make sure to check if the project has an `.nvmrc` and use the `node` version indicated. + +## Additional resources + +- [Node.js](https://nodejs.org/en) (Official documentation) +- [Node Version Manager](https://github.com/nvm-sh/nvm) (Official documentation) +- [Installing Node.js and npm for local WordPress development](https://learn.wordpress.org/tutorial/installing-node-js-and-npm-for-local-wordpress-development/) (Learn WordPress tutorial) \ No newline at end of file diff --git a/docs/manifest.json b/docs/manifest.json index abaf2d4515c98..7ceebaf69a449 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -12,15 +12,27 @@ "parent": null }, { - "title": "Development Environment", + "title": "Block Development Environment", "slug": "devenv", "markdown_source": "../docs/getting-started/devenv/README.md", "parent": "getting-started" }, { - "title": "How to setup local WordPress environment on Ubuntu", - "slug": "docker-ubuntu", - "markdown_source": "../docs/getting-started/devenv/docker-ubuntu.md", + "title": "Node.js development environment", + "slug": "nodejs-development-environment", + "markdown_source": "../docs/getting-started/devenv/nodejs-development-environment.md", + "parent": "devenv" + }, + { + "title": "Get started with wp-env", + "slug": "get-started-with-wp-env", + "markdown_source": "../docs/getting-started/devenv/get-started-with-wp-env.md", + "parent": "devenv" + }, + { + "title": "Get started with wp-now", + "slug": "get-started-with-wp-now", + "markdown_source": "../docs/getting-started/devenv/get-started-with-wp-now.md", "parent": "devenv" }, { diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 2c54c7d044c64..98a744e30cf02 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -310,7 +310,7 @@ Introduce new sections and organize content to help visitors (and search engines - **Name:** core/heading - **Category:** text -- **Supports:** align (full, wide), anchor, className, color (background, gradients, link, text), spacing (margin, padding), typography (fontSize, lineHeight) +- **Supports:** __unstablePasteTextInline, align (full, wide), anchor, className, color (background, gradients, link, text), spacing (margin, padding), typography (fontSize, lineHeight) - **Attributes:** content, level, placeholder, textAlign ## Home Link @@ -420,7 +420,7 @@ A collection of blocks that allow visitors to get around your site. ([Source](ht - **Name:** core/navigation - **Category:** theme -- **Supports:** align (full, wide), inserter, interactivity, layout (allowSizingOnChildren, default, ~~allowInheriting~~, ~~allowSwitching~~, ~~allowVerticalAlignment~~), spacing (blockGap, units), typography (fontSize, lineHeight), ~~html~~ +- **Supports:** align (full, wide), ariaLabel, inserter, interactivity, layout (allowSizingOnChildren, default, ~~allowInheriting~~, ~~allowSwitching~~, ~~allowVerticalAlignment~~), spacing (blockGap, units), typography (fontSize, lineHeight), ~~html~~ - **Attributes:** __unstableLocation, backgroundColor, customBackgroundColor, customOverlayBackgroundColor, customOverlayTextColor, customTextColor, hasIcon, icon, maxNestingLevel, openSubmenusOnClick, overlayBackgroundColor, overlayMenu, overlayTextColor, ref, rgbBackgroundColor, rgbTextColor, showSubmenuIcon, templateLock, textColor ## Custom Link diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index a3d6bd5b6f392..acaaa5f23f1b9 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -413,7 +413,7 @@ _Parameters_ _Returns_ -- `UserPatternCategories`: User patterns category array and map keyed by id. +- `Array< UserPatternCategory >`: User patterns category array. ### getUserQueryResults diff --git a/docs/toc.json b/docs/toc.json index 30c5544d28298..c9f24dd9fad70 100644 --- a/docs/toc.json +++ b/docs/toc.json @@ -7,7 +7,13 @@ { "docs/getting-started/devenv/README.md": [ { - "docs/getting-started/devenv/docker-ubuntu.md": [] + "docs/getting-started/devenv/nodejs-development-environment.md": [] + }, + { + "docs/getting-started/devenv/get-started-with-wp-env.md": [] + }, + { + "docs/getting-started/devenv/get-started-with-wp-now.md": [] } ] }, diff --git a/lib/compat/wordpress-6.4/block-patterns.php b/lib/compat/wordpress-6.4/block-patterns.php index 3a0a9ed1a9e52..922dea910b47a 100644 --- a/lib/compat/wordpress-6.4/block-patterns.php +++ b/lib/compat/wordpress-6.4/block-patterns.php @@ -16,19 +16,20 @@ */ function gutenberg_register_taxonomy_patterns() { $args = array( - 'public' => true, - 'hierarchical' => false, - 'labels' => array( + 'public' => true, + 'publicly_queryable' => false, + 'hierarchical' => false, + 'labels' => array( 'name' => _x( 'Pattern Categories', 'taxonomy general name' ), 'singular_name' => _x( 'Pattern Category', 'taxonomy singular name' ), ), - 'query_var' => false, - 'rewrite' => false, - 'show_ui' => true, - '_builtin' => true, - 'show_in_nav_menus' => false, - 'show_in_rest' => true, - 'show_admin_column' => true, + 'query_var' => false, + 'rewrite' => false, + 'show_ui' => true, + '_builtin' => true, + 'show_in_nav_menus' => false, + 'show_in_rest' => true, + 'show_admin_column' => true, ); register_taxonomy( 'wp_pattern_category', array( 'wp_block' ), $args ); } diff --git a/lib/compat/wordpress-6.4/kses.php b/lib/compat/wordpress-6.4/kses.php new file mode 100644 index 0000000000000..019d1cc9b06db --- /dev/null +++ b/lib/compat/wordpress-6.4/kses.php @@ -0,0 +1,18 @@ + true, + 'public' => false, + '_builtin' => true, /* internal use only. don't use this when registering your own post type. */ 'label' => 'Font Library', 'show_in_rest' => true, ); diff --git a/lib/load.php b/lib/load.php index dab2cc732115a..40ab9c129af97 100644 --- a/lib/load.php +++ b/lib/load.php @@ -97,6 +97,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-6.4/block-hooks.php'; require __DIR__ . '/compat/wordpress-6.4/block-patterns.php'; require __DIR__ . '/compat/wordpress-6.4/script-loader.php'; +require __DIR__ . '/compat/wordpress-6.4/kses.php'; // Experimental features. require __DIR__ . '/experimental/block-editor-settings-mobile.php'; diff --git a/package-lock.json b/package-lock.json index 124be7f72bd69..fb31bdaa0276b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -183,6 +183,7 @@ "eslint-plugin-import": "2.25.2", "eslint-plugin-jest": "27.2.3", "eslint-plugin-jest-dom": "5.0.2", + "eslint-plugin-prettier": "5.0.0", "eslint-plugin-ssr-friendly": "1.0.6", "eslint-plugin-storybook": "0.6.13", "eslint-plugin-testing-library": "5.7.2", @@ -213,7 +214,7 @@ "patch-package": "6.2.2", "postcss": "8.4.16", "postcss-loader": "6.2.1", - "prettier": "npm:wp-prettier@2.8.5", + "prettier": "npm:wp-prettier@3.0.3-beta-3", "progress": "2.0.3", "react": "18.2.0", "react-dom": "18.2.0", @@ -5651,6 +5652,155 @@ "node": ">=14" } }, + "node_modules/@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@pkgr/utils/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/utils/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@pkgr/utils/node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/@pkgr/utils/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@pkgr/utils/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@pkgr/utils/node_modules/open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "dependencies": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@pkgr/utils/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@pkgr/utils/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@pkgr/utils/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@pkgr/utils/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@playwright/test": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.32.0.tgz", @@ -10449,6 +10599,21 @@ "node": ">=8" } }, + "node_modules/@storybook/cli/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/@storybook/cli/node_modules/puppeteer-core": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-2.1.1.tgz", @@ -10947,6 +11112,21 @@ "node": ">=8" } }, + "node_modules/@storybook/codemod/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/@storybook/codemod/node_modules/recast": { "version": "0.23.3", "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.3.tgz", @@ -12659,6 +12839,21 @@ "node": ">=4.0" } }, + "node_modules/@storybook/source-loader/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/@storybook/telemetry": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-7.2.2.tgz", @@ -24225,6 +24420,21 @@ "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", "dev": true }, + "node_modules/bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "dependencies": { + "run-applescript": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/byte-size": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-8.1.1.tgz", @@ -27382,6 +27592,24 @@ } } }, + "node_modules/default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "dependencies": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/default-browser-id": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", @@ -27398,6 +27626,187 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/default-browser/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/default-browser/node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/default-browser/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/default-browser/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-browser/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-browser/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-browser/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/default-gateway": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", @@ -29145,22 +29554,30 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.0.tgz", - "integrity": "sha512-tMTwO8iUWlSRZIwS9k7/E4vrTsfvsrcM5p1eftyuqWH25nKsz/o6/54I7jwQ/3zobISyC7wMy9ZsFwgTxOcOpQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz", + "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==", "dev": true, "dependencies": { - "prettier-linter-helpers": "^1.0.0" + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.5" }, "engines": { - "node": ">=6.0.0" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/prettier" }, "peerDependencies": { - "eslint": ">=5.0.0", - "prettier": ">=1.13.0" + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "prettier": ">=3.0.0" }, "peerDependenciesMeta": { - "eslint-plugin-prettier": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { "optional": true } } @@ -33653,6 +34070,39 @@ "integrity": "sha512-but/G3sapV3MNyqiDBLrOi4x8uCIw0RY3o/Vb5GT0sMFHrVV7731wFSVy41T5FO1og7G0gXLJh0MkgPRouko/A==", "dev": true }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -45293,10 +45743,19 @@ }, "node_modules/prettier": { "name": "wp-prettier", - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-2.8.5.tgz", - "integrity": "sha512-gkphzYtVksWV6D7/V530bTehKkhrABUru/Gy4reOLOHJoKH4i9lcE1SxqU2VDxC3gCOx/Nk9alZmWk6xL/IBCw==", - "dev": true + "version": "3.0.3-beta-3", + "resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-3.0.3-beta-3.tgz", + "integrity": "sha512-R3+TD7j0rnqEpMgylrUrHdi1W6ypwh4QGeFOZQ9YjP9WvNnZzBAS71yry1h7xIcG/bVaNKBCoWNqbqJY6vkOKQ==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } }, "node_modules/prettier-linter-helpers": { "version": "1.0.0", @@ -48171,6 +48630,172 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/run-applescript/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/run-applescript/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/run-applescript/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/run-applescript/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-applescript/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-applescript/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-applescript/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-applescript/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -50654,6 +51279,22 @@ "integrity": "sha512-k8uzYIkIVwmT+TcglpdN50pS2y1BDcUnBPK9iJeGu0Pl1lOI8pD6wtzgw91Pjpe+RxtTncw32tLxs/R0yNL2Mg==", "dev": true }, + "node_modules/synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dev": true, + "dependencies": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/table": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", @@ -51209,6 +51850,18 @@ "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==", "dev": true }, + "node_modules/titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -55667,7 +56320,7 @@ "eslint-plugin-jsdoc": "^46.4.6", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-playwright": "^0.15.3", - "eslint-plugin-prettier": "^3.3.0", + "eslint-plugin-prettier": "^5.0.0", "eslint-plugin-react": "^7.27.0", "eslint-plugin-react-hooks": "^4.3.0", "globals": "^13.12.0", @@ -56450,7 +57103,7 @@ "playwright-core": "1.32.0", "postcss": "^8.4.5", "postcss-loader": "^6.2.1", - "prettier": "npm:wp-prettier@2.8.5", + "prettier": "npm:wp-prettier@3.0.3-beta-3", "puppeteer-core": "^13.2.0", "react-refresh": "^0.10.0", "read-pkg-up": "^7.0.1", @@ -60527,6 +61180,112 @@ "dev": true, "optional": true }, + "@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true + }, + "fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "requires": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "@playwright/test": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.32.0.tgz", @@ -63921,6 +64680,12 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true + }, "puppeteer-core": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-2.1.1.tgz", @@ -64310,6 +65075,12 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true + }, "recast": { "version": "0.23.3", "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.3.tgz", @@ -65529,6 +66300,12 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true + }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true } } }, @@ -68383,7 +69160,7 @@ "eslint-plugin-jsdoc": "^46.4.6", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-playwright": "^0.15.3", - "eslint-plugin-prettier": "^3.3.0", + "eslint-plugin-prettier": "^5.0.0", "eslint-plugin-react": "^7.27.0", "eslint-plugin-react-hooks": "^4.3.0", "globals": "^13.12.0", @@ -68853,7 +69630,7 @@ "playwright-core": "1.32.0", "postcss": "^8.4.5", "postcss-loader": "^6.2.1", - "prettier": "npm:wp-prettier@2.8.5", + "prettier": "npm:wp-prettier@3.0.3-beta-3", "puppeteer-core": "^13.2.0", "react-refresh": "^0.10.0", "read-pkg-up": "^7.0.1", @@ -77148,6 +77925,15 @@ "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", "dev": true }, + "bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "requires": { + "run-applescript": "^5.0.0" + } + }, "byte-size": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-8.1.1.tgz", @@ -79571,6 +80357,134 @@ "resolved": "https://registry.npmjs.org/deepsignal/-/deepsignal-1.3.6.tgz", "integrity": "sha512-yjd+vtiznL6YaMptOsKnEKkPr60OEApa+LRe+Qe6Ile/RfCOrELKk/YM3qVpXFZiyOI3Ng67GDEyjAlqVc697g==" }, + "default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "requires": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true + }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true + }, + "mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true + }, + "npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "requires": { + "path-key": "^4.0.0" + }, + "dependencies": { + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true + } + } + }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "requires": { + "mimic-fn": "^4.0.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "default-browser-id": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", @@ -81130,12 +82044,13 @@ "dev": true }, "eslint-plugin-prettier": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.0.tgz", - "integrity": "sha512-tMTwO8iUWlSRZIwS9k7/E4vrTsfvsrcM5p1eftyuqWH25nKsz/o6/54I7jwQ/3zobISyC7wMy9ZsFwgTxOcOpQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz", + "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==", "dev": true, "requires": { - "prettier-linter-helpers": "^1.0.0" + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.5" } }, "eslint-plugin-react": { @@ -84390,6 +85305,23 @@ "integrity": "sha512-but/G3sapV3MNyqiDBLrOi4x8uCIw0RY3o/Vb5GT0sMFHrVV7731wFSVy41T5FO1og7G0gXLJh0MkgPRouko/A==", "dev": true }, + "is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "requires": { + "is-docker": "^3.0.0" + }, + "dependencies": { + "is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true + } + } + }, "is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -93303,9 +94235,9 @@ "dev": true }, "prettier": { - "version": "npm:wp-prettier@2.8.5", - "resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-2.8.5.tgz", - "integrity": "sha512-gkphzYtVksWV6D7/V530bTehKkhrABUru/Gy4reOLOHJoKH4i9lcE1SxqU2VDxC3gCOx/Nk9alZmWk6xL/IBCw==", + "version": "npm:wp-prettier@3.0.3-beta-3", + "resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-3.0.3-beta-3.tgz", + "integrity": "sha512-R3+TD7j0rnqEpMgylrUrHdi1W6ypwh4QGeFOZQ9YjP9WvNnZzBAS71yry1h7xIcG/bVaNKBCoWNqbqJY6vkOKQ==", "dev": true }, "prettier-linter-helpers": { @@ -95481,6 +96413,117 @@ } } }, + "run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "requires": { + "execa": "^5.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -97424,6 +98467,16 @@ "integrity": "sha512-k8uzYIkIVwmT+TcglpdN50pS2y1BDcUnBPK9iJeGu0Pl1lOI8pD6wtzgw91Pjpe+RxtTncw32tLxs/R0yNL2Mg==", "dev": true }, + "synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dev": true, + "requires": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" + } + }, "table": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", @@ -97845,6 +98898,12 @@ "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==", "dev": true }, + "titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", diff --git a/package.json b/package.json index 1cd8535bfc803..df1b0c7ba348a 100644 --- a/package.json +++ b/package.json @@ -195,6 +195,7 @@ "eslint-plugin-import": "2.25.2", "eslint-plugin-jest": "27.2.3", "eslint-plugin-jest-dom": "5.0.2", + "eslint-plugin-prettier": "5.0.0", "eslint-plugin-ssr-friendly": "1.0.6", "eslint-plugin-storybook": "0.6.13", "eslint-plugin-testing-library": "5.7.2", @@ -225,7 +226,7 @@ "patch-package": "6.2.2", "postcss": "8.4.16", "postcss-loader": "6.2.1", - "prettier": "npm:wp-prettier@2.8.5", + "prettier": "npm:wp-prettier@3.0.3-beta-3", "progress": "2.0.3", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index 9db5d4c87b2e0..b998614e4b089 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -71,6 +71,7 @@ function BlockStyles( { clientId, onSwitch = noop, onHoverClassName = noop } ) { return ( ); + // Convert legacy `position` values to be used with the new `placement` prop + let computedPlacement; + // if `tooltipPosition` is defined, compute value to `placement` + if ( tooltipPosition !== undefined ) { + computedPlacement = positionToPlacement( tooltipPosition ); + } + if ( ! shouldShowTooltip ) { return ( <> @@ -248,7 +256,7 @@ export function UnforwardedButton( : label } shortcut={ shortcut } - position={ tooltipPosition } + placement={ computedPlacement } > { element } diff --git a/packages/components/src/circular-option-picker/types.ts b/packages/components/src/circular-option-picker/types.ts index 5a54a33412435..da443c7691a95 100644 --- a/packages/components/src/circular-option-picker/types.ts +++ b/packages/components/src/circular-option-picker/types.ts @@ -69,7 +69,7 @@ type FullListboxCircularOptionPickerProps = CommonCircularOptionPickerProps & { 'aria-label'?: never; 'aria-labelledby': string; } - ); + ); export type ListboxCircularOptionPickerProps = WithBaseId & Omit< FullListboxCircularOptionPickerProps, 'asButtons' >; diff --git a/packages/components/src/color-palette/types.ts b/packages/components/src/color-palette/types.ts index 0b097aa108d38..b2a7a884fec57 100644 --- a/packages/components/src/color-palette/types.ts +++ b/packages/components/src/color-palette/types.ts @@ -121,4 +121,4 @@ export type ColorPaletteProps = Pick< PaletteProps, 'onChange' > & { 'aria-labelledby'?: string; 'aria-label'?: never; } - ); + ); diff --git a/packages/components/src/custom-gradient-picker/gradient-bar/control-points.tsx b/packages/components/src/custom-gradient-picker/gradient-bar/control-points.tsx index e761df24823b9..4d09f25662021 100644 --- a/packages/components/src/custom-gradient-picker/gradient-bar/control-points.tsx +++ b/packages/components/src/custom-gradient-picker/gradient-bar/control-points.tsx @@ -93,7 +93,7 @@ function GradientColorPickerDropdown( { ( { placement: 'bottom', offset: 8, - } as const ), + } ) as const, [] ); diff --git a/packages/components/src/custom-gradient-picker/gradient-bar/test/utils.ts b/packages/components/src/custom-gradient-picker/gradient-bar/test/utils.ts index 01396d94f0581..53804696ba2d3 100644 --- a/packages/components/src/custom-gradient-picker/gradient-bar/test/utils.ts +++ b/packages/components/src/custom-gradient-picker/gradient-bar/test/utils.ts @@ -13,7 +13,7 @@ describe( 'getHorizontalRelativeGradientPosition', () => { ( { x: 0, width: 1000, - } as DOMRect ) + } ) as DOMRect ); const containerElement = document.createElement( 'div' ); @@ -31,7 +31,7 @@ describe( 'getHorizontalRelativeGradientPosition', () => { ( { x: 50, width: 1000, - } as DOMRect ) + } ) as DOMRect ); const containerElement = document.createElement( 'div' ); @@ -49,7 +49,7 @@ describe( 'getHorizontalRelativeGradientPosition', () => { ( { x: 0, width: 1000, - } as DOMRect ) + } ) as DOMRect ); const containerElement = document.createElement( 'div' ); @@ -68,7 +68,7 @@ describe( 'getHorizontalRelativeGradientPosition', () => { ( { x: 50, width: 1000, - } as DOMRect ) + } ) as DOMRect ); const containerElement = document.createElement( 'div' ); @@ -86,7 +86,7 @@ describe( 'getHorizontalRelativeGradientPosition', () => { ( { x: 50, width: 1000, - } as DOMRect ) + } ) as DOMRect ); const containerElement = document.createElement( 'div' ); diff --git a/packages/components/src/date-time/time/timezone.tsx b/packages/components/src/date-time/time/timezone.tsx index f878deddaa782..9fac1ec094ed8 100644 --- a/packages/components/src/date-time/time/timezone.tsx +++ b/packages/components/src/date-time/time/timezone.tsx @@ -38,7 +38,7 @@ const TimeZone = () => { : `(${ zoneAbbr }) ${ timezone.string.replace( '_', ' ' ) }`; return ( - + { zoneAbbr } diff --git a/packages/components/src/dropdown-menu/index.tsx b/packages/components/src/dropdown-menu/index.tsx index b5ccd92d68b90..9105555927f47 100644 --- a/packages/components/src/dropdown-menu/index.tsx +++ b/packages/components/src/dropdown-menu/index.tsx @@ -22,7 +22,7 @@ import type { } from './types'; function mergeProps< - T extends { className?: string; [ key: string ]: unknown } + T extends { className?: string; [ key: string ]: unknown }, >( defaultProps: Partial< T > = {}, props: T = {} as T ) { const mergedProps: T = { ...defaultProps, diff --git a/packages/components/src/duotone-picker/types.ts b/packages/components/src/duotone-picker/types.ts index 9c5a71439f7cf..382f7b364ba7f 100644 --- a/packages/components/src/duotone-picker/types.ts +++ b/packages/components/src/duotone-picker/types.ts @@ -72,7 +72,7 @@ export type DuotonePickerProps = { 'aria-labelledby'?: string; 'aria-label'?: never; } - ); +); type Color = { color: string; diff --git a/packages/components/src/form-token-field/types.ts b/packages/components/src/form-token-field/types.ts index e343601106f41..e7eabd381a66a 100644 --- a/packages/components/src/form-token-field/types.ts +++ b/packages/components/src/form-token-field/types.ts @@ -194,7 +194,7 @@ export interface FormTokenFieldProps * `T` can be either a `string` or an object which must have a `value` prop as a string. */ export interface SuggestionsListProps< - T = string | ( Record< string, unknown > & { value: string } ) + T = string | ( Record< string, unknown > & { value: string } ), > { selectedIndex: number; scrollIntoView: boolean; diff --git a/packages/components/src/gradient-picker/types.ts b/packages/components/src/gradient-picker/types.ts index b26a464df5e18..8deb9513cc0db 100644 --- a/packages/components/src/gradient-picker/types.ts +++ b/packages/components/src/gradient-picker/types.ts @@ -75,7 +75,7 @@ type GradientPickerBaseProps = { 'aria-labelledby'?: string; 'aria-label'?: never; } - ); +); export type GradientPickerComponentProps = GradientPickerBaseProps & { /** diff --git a/packages/components/src/higher-order/navigate-regions/index.tsx b/packages/components/src/higher-order/navigate-regions/index.tsx index f2b9c31bfbe95..1f4e79654e5bc 100644 --- a/packages/components/src/higher-order/navigate-regions/index.tsx +++ b/packages/components/src/higher-order/navigate-regions/index.tsx @@ -139,11 +139,10 @@ export function useNavigateRegions( shortcuts: Shortcuts = defaultShortcuts ) { */ export default createHigherOrderComponent( ( Component ) => - ( { shortcuts, ...props } ) => - ( -
- -
- ), + ( { shortcuts, ...props } ) => ( +
+ +
+ ), 'navigateRegions' ); diff --git a/packages/components/src/higher-order/with-filters/test/index.tsx b/packages/components/src/higher-order/with-filters/test/index.tsx index 0f84054cee737..fd816df59cfcf 100644 --- a/packages/components/src/higher-order/with-filters/test/index.tsx +++ b/packages/components/src/higher-order/with-filters/test/index.tsx @@ -52,13 +52,12 @@ describe( 'withFilters', () => { addFilter( hookName, 'test/enhanced-component-compose', - ( FilteredComponent ) => () => - ( -
- - -
- ) + ( FilteredComponent ) => () => ( +
+ + +
+ ) ); const EnhancedComponent = withFilters( hookName )( MyComponent ); @@ -72,12 +71,11 @@ describe( 'withFilters', () => { addFilter( hookName, 'test/enhanced-component-spy-1', - ( FilteredComponent ) => () => - ( -
- -
- ) + ( FilteredComponent ) => () => ( +
+ +
+ ) ); const EnhancedComponent = withFilters( hookName )( SpiedComponent ); @@ -100,12 +98,11 @@ describe( 'withFilters', () => { addFilter( hookName, 'test/enhanced-component-spy-1', - ( FilteredComponent ) => () => - ( -
- -
- ) + ( FilteredComponent ) => () => ( +
+ +
+ ) ); await waitFor( () => @@ -125,22 +122,20 @@ describe( 'withFilters', () => { addFilter( hookName, 'test/enhanced-component-spy-1', - ( FilteredComponent ) => () => - ( -
- -
- ) + ( FilteredComponent ) => () => ( +
+ +
+ ) ); addFilter( hookName, 'test/enhanced-component-spy-2', - ( FilteredComponent ) => () => - ( -
- -
- ) + ( FilteredComponent ) => () => ( +
+ +
+ ) ); await waitFor( () => @@ -159,12 +154,11 @@ describe( 'withFilters', () => { addFilter( hookName, 'test/enhanced-component-spy', - ( FilteredComponent ) => () => - ( -
- -
- ) + ( FilteredComponent ) => () => ( +
+ +
+ ) ); await waitFor( () => @@ -196,12 +190,11 @@ describe( 'withFilters', () => { addFilter( hookName, 'test/enhanced-component-spy-1', - ( FilteredComponent ) => () => - ( -
- -
- ) + ( FilteredComponent ) => () => ( +
+ +
+ ) ); await waitFor( () => diff --git a/packages/components/src/higher-order/with-spoken-messages/index.tsx b/packages/components/src/higher-order/with-spoken-messages/index.tsx index 4302c8f252d4f..b987d44c4be31 100644 --- a/packages/components/src/higher-order/with-spoken-messages/index.tsx +++ b/packages/components/src/higher-order/with-spoken-messages/index.tsx @@ -17,13 +17,12 @@ import { speak } from '@wordpress/a11y'; * @return {WPComponent} The wrapped component. */ export default createHigherOrderComponent( - ( Component ) => ( props ) => - ( - - ), + ( Component ) => ( props ) => ( + + ), 'withSpokenMessages' ); diff --git a/packages/components/src/mobile/global-styles-context/index.native.js b/packages/components/src/mobile/global-styles-context/index.native.js index d5457c836223b..cc9f6baf93348 100644 --- a/packages/components/src/mobile/global-styles-context/index.native.js +++ b/packages/components/src/mobile/global-styles-context/index.native.js @@ -92,13 +92,12 @@ export const useGlobalStyles = () => { return globalStyles; }; -export const withGlobalStyles = ( WrappedComponent ) => ( props ) => - ( - - { ( globalStyles ) => ( - - ) } - - ); +export const withGlobalStyles = ( WrappedComponent ) => ( props ) => ( + + { ( globalStyles ) => ( + + ) } + +); export default GlobalStylesContext; diff --git a/packages/components/src/navigation/use-navigation-tree-nodes.tsx b/packages/components/src/navigation/use-navigation-tree-nodes.tsx index 2d13b967acbc7..45ed86e026230 100644 --- a/packages/components/src/navigation/use-navigation-tree-nodes.tsx +++ b/packages/components/src/navigation/use-navigation-tree-nodes.tsx @@ -4,7 +4,7 @@ import { useState } from '@wordpress/element'; export function useNavigationTreeNodes< - TNode extends { children?: React.ReactNode; [ key: string ]: unknown } + TNode extends { children?: React.ReactNode; [ key: string ]: unknown }, >() { const [ nodes, setNodes ] = useState< Record< string, Omit< TNode, 'children' > > diff --git a/packages/components/src/popover/test/index.tsx b/packages/components/src/popover/test/index.tsx index fa96c74cffbf3..33a2d8758c09d 100644 --- a/packages/components/src/popover/test/index.tsx +++ b/packages/components/src/popover/test/index.tsx @@ -23,17 +23,17 @@ import { PopoverInsideIframeRenderedInExternalSlot } from './utils'; type PositionToPlacementTuple = [ NonNullable< PopoverProps[ 'position' ] >, - NonNullable< PopoverProps[ 'placement' ] > + NonNullable< PopoverProps[ 'placement' ] >, ]; type PlacementToAnimationOriginTuple = [ NonNullable< PopoverProps[ 'placement' ] >, number, - number + number, ]; type PlacementToInitialTranslationTuple = [ NonNullable< PopoverProps[ 'placement' ] >, 'translateY' | 'translateX', - CSSProperties[ 'translate' ] + CSSProperties[ 'translate' ], ]; // There's no matching `placement` for 'middle center' positions, diff --git a/packages/components/src/text/styles.js b/packages/components/src/text/styles.js index 171e34fab9f46..ed821923db9ff 100644 --- a/packages/components/src/text/styles.js +++ b/packages/components/src/text/styles.js @@ -34,7 +34,8 @@ export const highlighterText = css` mark { background: ${ COLORS.alert.yellow }; border-radius: 2px; - box-shadow: 0 0 0 1px rgba( 0, 0, 0, 0.05 ) inset, + box-shadow: + 0 0 0 1px rgba( 0, 0, 0, 0.05 ) inset, 0 -1px 0 rgba( 0, 0, 0, 0.1 ) inset; } `; diff --git a/packages/components/src/toggle-group-control/toggle-group-control-option-base/component.tsx b/packages/components/src/toggle-group-control/toggle-group-control-option-base/component.tsx index 572a4b70785eb..3682aa3a5f1f6 100644 --- a/packages/components/src/toggle-group-control/toggle-group-control-option-base/component.tsx +++ b/packages/components/src/toggle-group-control/toggle-group-control-option-base/component.tsx @@ -38,7 +38,7 @@ const LAYOUT_ID = 'toggle-group-backdrop-shared-layout-id'; const WithToolTip = ( { showTooltip, text, children }: WithToolTipProps ) => { if ( showTooltip && text ) { return ( - + { children } ); diff --git a/packages/components/src/toggle-group-control/toggle-group-control-option-base/styles.ts b/packages/components/src/toggle-group-control/toggle-group-control-option-base/styles.ts index e097f13cc6bf3..dac297fd3ddfa 100644 --- a/packages/components/src/toggle-group-control/toggle-group-control-option-base/styles.ts +++ b/packages/components/src/toggle-group-control/toggle-group-control-option-base/styles.ts @@ -50,8 +50,10 @@ export const buttonView = ( { padding: 0 12px; position: relative; text-align: center; - transition: background ${ CONFIG.transitionDurationFast } linear, - color ${ CONFIG.transitionDurationFast } linear, font-weight 60ms linear; + transition: + background ${ CONFIG.transitionDurationFast } linear, + color ${ CONFIG.transitionDurationFast } linear, + font-weight 60ms linear; ${ reduceMotion( 'transition' ) } user-select: none; width: 100%; @@ -82,7 +84,8 @@ const deselectable = css` color: ${ COLORS.gray[ 900 ] }; &:focus { - box-shadow: inset 0 0 0 1px ${ COLORS.white }, + box-shadow: + inset 0 0 0 1px ${ COLORS.white }, 0 0 0 ${ CONFIG.borderWidthFocus } ${ COLORS.theme.accent }; outline: 2px solid transparent; } diff --git a/packages/components/src/toggle-group-control/toggle-group-control/as-button-group.tsx b/packages/components/src/toggle-group-control/toggle-group-control/as-button-group.tsx index e425bd135f21c..7836cfa116a6f 100644 --- a/packages/components/src/toggle-group-control/toggle-group-control/as-button-group.tsx +++ b/packages/components/src/toggle-group-control/toggle-group-control/as-button-group.tsx @@ -62,7 +62,7 @@ function UnforwardedToggleGroupControlAsButtonGroup( isBlock: ! isAdaptiveWidth, isDeselectable: true, size, - } as ToggleGroupControlContextProps ), + } ) as ToggleGroupControlContextProps, [ baseId, selectedValue, setSelectedValue, isAdaptiveWidth, size ] ); diff --git a/packages/components/src/toggle-group-control/toggle-group-control/as-radio-group.tsx b/packages/components/src/toggle-group-control/toggle-group-control/as-radio-group.tsx index cc842782312de..e83306b91cb7c 100644 --- a/packages/components/src/toggle-group-control/toggle-group-control/as-radio-group.tsx +++ b/packages/components/src/toggle-group-control/toggle-group-control/as-radio-group.tsx @@ -78,7 +78,7 @@ function UnforwardedToggleGroupControlAsRadioGroup( size, value: selectedValue, setValue, - } as ToggleGroupControlContextProps ), + } ) as ToggleGroupControlContextProps, [ baseId, isAdaptiveWidth, size, selectedValue, setValue ] ); diff --git a/packages/components/src/toolbar/toolbar-group/types.ts b/packages/components/src/toolbar/toolbar-group/types.ts index 6475f3cf927f4..ea25a5ea85527 100644 --- a/packages/components/src/toolbar/toolbar-group/types.ts +++ b/packages/components/src/toolbar/toolbar-group/types.ts @@ -72,7 +72,7 @@ export type ToolbarGroupProps = ToolbarGroupPropsBase & */ title: string; } - ); + ); export type ToolbarGroupCollapsedProps = DropdownMenuProps; diff --git a/packages/components/src/tooltip/README.md b/packages/components/src/tooltip/README.md index 5b4caecf6d5c7..9b214e8fc6b00 100644 --- a/packages/components/src/tooltip/README.md +++ b/packages/components/src/tooltip/README.md @@ -42,12 +42,21 @@ Option to hide the tooltip when the anchor is clicked. - Required: No - Default: `true` +#### `placement`: `'top' | 'top-start' | 'top-end' | 'right' | 'right-start' | 'right-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end'` + +Used to specify the tooltip's placement with respect to its anchor. + +- Required: No +- Default: `'bottom'` + #### `position`: `string` -The direction in which the tooltip should open relative to its parent node. Specify y- and x-axis as a space-separated string. Supports `"top"`, `"middle"`, `"bottom"` y axis, and `"left"`, `"center"`, `"right"` x axis. +_Note: use the `placement` prop instead when possible._ + +Legacy way to specify the popover's position with respect to its anchor. Specify y- and x-axis as a space-separated string. Supports `'top'`, `'middle'`, `'bottom'` y axis, and `'left'`, `'center'`, `'right'` x axis. - Required: No -- Default: `"bottom"` +- Default: `'bottom'` #### `shortcut`: `string` | `object` diff --git a/packages/components/src/tooltip/index.tsx b/packages/components/src/tooltip/index.tsx index f86bd5d2ade9c..f31a2a4f264d9 100644 --- a/packages/components/src/tooltip/index.tsx +++ b/packages/components/src/tooltip/index.tsx @@ -8,6 +8,7 @@ import * as Ariakit from '@ariakit/react/tooltip'; */ import { useInstanceId } from '@wordpress/compose'; import { Children } from '@wordpress/element'; +import deprecated from '@wordpress/deprecated'; /** * Internal dependencies @@ -26,7 +27,8 @@ function Tooltip( props: TooltipProps ) { children, delay = TOOLTIP_DELAY, hideOnClick = true, - position = 'bottom', + placement, + position, shortcut, text, } = props; @@ -45,8 +47,24 @@ function Tooltip( props: TooltipProps ) { } } + // Compute tooltip's placement: + // - give priority to `placement` prop, if defined + // - otherwise, compute it from the legacy `position` prop (if defined) + // - finally, fallback to the default placement: 'bottom' + let computedPlacement; + if ( placement !== undefined ) { + computedPlacement = placement; + } else if ( position !== undefined ) { + computedPlacement = positionToPlacement( position ); + deprecated( '`position` prop in wp.components.tooltip', { + since: '6.4', + alternative: '`placement` prop', + } ); + } + computedPlacement = computedPlacement || 'bottom'; + const tooltipStore = Ariakit.useTooltipStore( { - placement: positionToPlacement( position ), + placement: computedPlacement, timeout: delay, } ); diff --git a/packages/components/src/tooltip/types.ts b/packages/components/src/tooltip/types.ts index 1487a382ff1b8..8708ae7005f5b 100644 --- a/packages/components/src/tooltip/types.ts +++ b/packages/components/src/tooltip/types.ts @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import type { Placement } from '@floating-ui/react-dom'; + /** * Internal dependencies */ @@ -24,10 +29,20 @@ export type TooltipProps = { */ delay?: number; /** - * The direction in which the tooltip should open relative to its parent node. + * Where the tooltip should be positioned relative to its parent. + * + * @default bottom + */ + placement?: Placement; + /** + * _Note: this prop is deprecated. Please use the `placement` prop instead._ + * + * Legacy way of specifying the tooltip's position relative to its parent. + * * Specify y- and x-axis as a space-separated string. Supports `"top"`, * `"bottom"` y axis, and `"left"`, `"center"`, `"right"` x axis. * + * @deprecated * @default bottom */ position?: PopoverProps[ 'position' ]; diff --git a/packages/components/src/ui/context/context-connect.ts b/packages/components/src/ui/context/context-connect.ts index 4e5fcfbf26795..8db2bbc987c0d 100644 --- a/packages/components/src/ui/context/context-connect.ts +++ b/packages/components/src/ui/context/context-connect.ts @@ -18,7 +18,7 @@ import type { WordPressComponentFromProps } from '.'; type AcceptsTwoArgs< F extends ( ...args: any ) => any, - ErrorMessage = never + ErrorMessage = never, > = Parameters< F >[ 'length' ] extends 2 ? {} : ErrorMessage; type ContextConnectOptions = { @@ -34,7 +34,7 @@ type ContextConnectOptions = { * @return The connected WordPressComponent */ export function contextConnect< - C extends ( props: any, ref: ForwardedRef< any > ) => JSX.Element | null + C extends ( props: any, ref: ForwardedRef< any > ) => JSX.Element | null, >( Component: C & AcceptsTwoArgs< @@ -66,7 +66,7 @@ export function contextConnectWithoutRef< P >( // component wrappers. function _contextConnect< C extends ( props: any, ref: ForwardedRef< any > ) => JSX.Element | null, - O extends ContextConnectOptions + O extends ContextConnectOptions, >( Component: C, namespace: string, diff --git a/packages/components/src/ui/context/wordpress-component.ts b/packages/components/src/ui/context/wordpress-component.ts index bf70924b40bbb..57e69abdc3809 100644 --- a/packages/components/src/ui/context/wordpress-component.ts +++ b/packages/components/src/ui/context/wordpress-component.ts @@ -10,7 +10,7 @@ export type WordPressComponentProps< /** The HTML element to inherit props from. */ T extends React.ElementType, /** Supports polymorphism through the `as` prop. */ - IsPolymorphic extends boolean = true + IsPolymorphic extends boolean = true, > = P & // The `children` prop is being explicitly omitted since it is otherwise implicitly added // by `ComponentPropsWithRef`. The context is that components should require the `children` @@ -26,7 +26,7 @@ export type WordPressComponentProps< export type WordPressComponent< T extends React.ElementType, O, - IsPolymorphic extends boolean + IsPolymorphic extends boolean, > = { < TT extends React.ElementType >( props: WordPressComponentProps< O, TT, IsPolymorphic > & @@ -49,7 +49,7 @@ export type WordPressComponent< export type WordPressComponentFromProps< Props, - ForwardsRef extends boolean = true + ForwardsRef extends boolean = true, > = Props extends WordPressComponentProps< infer P, infer T, infer I > ? WordPressComponent< T, diff --git a/packages/components/src/unit-control/index.tsx b/packages/components/src/unit-control/index.tsx index cd5bf4e478768..ed57f4cc703fe 100644 --- a/packages/components/src/unit-control/index.tsx +++ b/packages/components/src/unit-control/index.tsx @@ -76,10 +76,15 @@ function UnforwardedUnitControl( unitsProp ); const [ { value: firstUnitValue = '' } = {}, ...rest ] = list; - const firstCharacters = rest.reduce( ( carry, { value } ) => { - const first = escapeRegExp( value?.substring( 0, 1 ) || '' ); - return carry.includes( first ) ? carry : `${ carry }|${ first }`; - }, escapeRegExp( firstUnitValue.substring( 0, 1 ) ) ); + const firstCharacters = rest.reduce( + ( carry, { value } ) => { + const first = escapeRegExp( value?.substring( 0, 1 ) || '' ); + return carry.includes( first ) + ? carry + : `${ carry }|${ first }`; + }, + escapeRegExp( firstUnitValue.substring( 0, 1 ) ) + ); return [ list, new RegExp( `^(?:${ firstCharacters })$`, 'i' ) ]; }, [ nonNullValueProp, unitProp, unitsProp ] ); const [ parsedQuantity, parsedUnit ] = getParsedQuantityAndUnit( diff --git a/packages/components/src/unit-control/styles/unit-control-styles.ts b/packages/components/src/unit-control/styles/unit-control-styles.ts index e5557307b0b0d..92b1f5f2fd8b4 100644 --- a/packages/components/src/unit-control/styles/unit-control-styles.ts +++ b/packages/components/src/unit-control/styles/unit-control-styles.ts @@ -82,7 +82,9 @@ const unitSelectSizes = ( { selectSize = 'default' }: SelectProps ) => { default: css` height: 100%; border: 1px solid transparent; - transition: box-shadow 0.1s linear, border 0.1s linear; + transition: + box-shadow 0.1s linear, + border 0.1s linear; ${ rtl( { borderTopLeftRadius: 0, borderBottomLeftRadius: 0 } )() } diff --git a/packages/components/src/unit-control/test/utils.ts b/packages/components/src/unit-control/test/utils.ts index b843764f4a57e..c35167ae49243 100644 --- a/packages/components/src/unit-control/test/utils.ts +++ b/packages/components/src/unit-control/test/utils.ts @@ -248,7 +248,7 @@ describe( 'UnitControl utils', () => { const cases: [ number | string | undefined, number | undefined, - string | undefined + string | undefined, ][] = [ // Test undefined. [ undefined, undefined, undefined ], diff --git a/packages/components/src/utils/use-deprecated-props.ts b/packages/components/src/utils/use-deprecated-props.ts index ee5dcc67a7530..8c102906970d0 100644 --- a/packages/components/src/utils/use-deprecated-props.ts +++ b/packages/components/src/utils/use-deprecated-props.ts @@ -7,7 +7,7 @@ export function useDeprecated36pxDefaultSizeProp< P extends Record< string, any > & { __next36pxDefaultSize?: boolean; __next40pxDefaultSize?: boolean; - } + }, >( props: P, /** The component identifier in dot notation, e.g. `wp.components.ComponentName`. */ diff --git a/packages/compose/README.md b/packages/compose/README.md index b0cff6e7128db..5a3ec6437b1fd 100644 --- a/packages/compose/README.md +++ b/packages/compose/README.md @@ -116,9 +116,7 @@ _Usage_ ```ts type Props = { foo: string }; const Component = ( props: Props ) =>
{ props.foo }
; -const ConditionalComponent = ifCondition( - ( props: Props ) => props.foo.length !== 0 -)( Component ); +const ConditionalComponent = ifCondition( ( props: Props ) => props.foo.length !== 0 )( Component ); ; // => null ; // =>
bar
; ``` diff --git a/packages/compose/src/higher-order/pure/index.tsx b/packages/compose/src/higher-order/pure/index.tsx index 28b2f45fada97..65684738b708a 100644 --- a/packages/compose/src/higher-order/pure/index.tsx +++ b/packages/compose/src/higher-order/pure/index.tsx @@ -41,7 +41,6 @@ const pure = createHigherOrderComponent( function < Props extends {} >( return ; } }; -}, -'pure' ); +}, 'pure' ); export default pure; diff --git a/packages/compose/src/hooks/use-dialog/index.ts b/packages/compose/src/hooks/use-dialog/index.ts index dd7e47422eb56..66974b60e0703 100644 --- a/packages/compose/src/hooks/use-dialog/index.ts +++ b/packages/compose/src/hooks/use-dialog/index.ts @@ -34,7 +34,7 @@ type DialogOptions = { type useDialogReturn = [ RefCallback< HTMLElement >, - ReturnType< typeof useFocusOutside > & Pick< HTMLElement, 'tabIndex' > + ReturnType< typeof useFocusOutside > & Pick< HTMLElement, 'tabIndex' >, ]; /** diff --git a/packages/compose/src/hooks/use-resize-observer/index.tsx b/packages/compose/src/hooks/use-resize-observer/index.tsx index 2f531d9f9bffd..b2ff87f2c025f 100644 --- a/packages/compose/src/hooks/use-resize-observer/index.tsx +++ b/packages/compose/src/hooks/use-resize-observer/index.tsx @@ -336,7 +336,7 @@ function useResizeObserver< T extends HTMLElement >( */ export default function useResizeAware(): [ WPElement, - { width: number | null; height: number | null } + { width: number | null; height: number | null }, ] { const { ref, width, height } = useResizeObserver(); const sizes = useMemo( () => { diff --git a/packages/compose/src/utils/create-higher-order-component/index.ts b/packages/compose/src/utils/create-higher-order-component/index.ts index 62da02d6c08db..7c297b18ab212 100644 --- a/packages/compose/src/utils/create-higher-order-component/index.ts +++ b/packages/compose/src/utils/create-higher-order-component/index.ts @@ -23,7 +23,7 @@ export type WithInjectedProps< C, I > = ComponentType< */ export function createHigherOrderComponent< TInner extends ComponentType< any >, - TOuter extends ComponentType< any > + TOuter extends ComponentType< any >, >( mapComponent: ( Inner: TInner ) => TOuter, modifierName: string ) { return ( Inner: TInner ) => { const Outer = mapComponent( Inner ); diff --git a/packages/core-data/README.md b/packages/core-data/README.md index 43ce17f98f8e4..6024f4db2f12d 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -590,7 +590,7 @@ _Parameters_ _Returns_ -- `UserPatternCategories`: User patterns category array and map keyed by id. +- `Array< UserPatternCategory >`: User patterns category array. ### getUserQueryResults diff --git a/packages/core-data/src/entity-types/helpers.ts b/packages/core-data/src/entity-types/helpers.ts index 59ed25a72bc8b..943dece90e353 100644 --- a/packages/core-data/src/entity-types/helpers.ts +++ b/packages/core-data/src/entity-types/helpers.ts @@ -64,7 +64,7 @@ export type Context = 'view' | 'edit' | 'embed'; export type ContextualField< FieldType, AvailableInContexts extends Context, - C extends Context + C extends Context, > = AvailableInContexts extends C ? FieldType : never; /** @@ -93,7 +93,7 @@ export type OmitNevers< : T[ K ] extends Record< string, unknown > ? OmitNevers< T[ K ] > : T[ K ]; - } + }, > = Pick< Nevers, { diff --git a/packages/core-data/src/hooks/use-resource-permissions.ts b/packages/core-data/src/hooks/use-resource-permissions.ts index 1c9e95429d14c..7da7189e2e506 100644 --- a/packages/core-data/src/hooks/use-resource-permissions.ts +++ b/packages/core-data/src/hooks/use-resource-permissions.ts @@ -38,7 +38,7 @@ type ResourcePermissionsResolution< IdType > = [ HasResolved, ResolutionDetails & GlobalResourcePermissionsResolution & - ( IdType extends void ? SpecificResourcePermissionsResolution : {} ) + ( IdType extends void ? SpecificResourcePermissionsResolution : {} ), ]; /** diff --git a/packages/core-data/src/selectors.ts b/packages/core-data/src/selectors.ts index 3536a3ef55adf..7d6cbeb4daeee 100644 --- a/packages/core-data/src/selectors.ts +++ b/packages/core-data/src/selectors.ts @@ -80,7 +80,7 @@ interface UserState { byId: Record< EntityRecordKey, ET.User< 'edit' > >; } -interface UserPatternCategory { +export interface UserPatternCategory { id: number; name: string; label: string; @@ -88,11 +88,6 @@ interface UserPatternCategory { description: string; } -export interface UserPatternCategories { - patternCategories: Array< UserPatternCategory >; - patternCategoriesMap: Map< number, UserPatternCategory >; -} - type Optional< T > = T | undefined; /** @@ -278,7 +273,7 @@ export interface GetEntityRecord { < EntityRecord extends | ET.EntityRecord< any > - | Partial< ET.EntityRecord< any > > + | Partial< ET.EntityRecord< any > >, >( state: State, kind: string, @@ -290,7 +285,7 @@ export interface GetEntityRecord { CurriedSignature: < EntityRecord extends | ET.EntityRecord< any > - | Partial< ET.EntityRecord< any > > + | Partial< ET.EntityRecord< any > >, >( kind: string, name: string, @@ -317,7 +312,7 @@ export const getEntityRecord = createSelector( ( < EntityRecord extends | ET.EntityRecord< any > - | Partial< ET.EntityRecord< any > > + | Partial< ET.EntityRecord< any > >, >( state: State, kind: string, @@ -381,7 +376,7 @@ export const getEntityRecord = createSelector( * @return Record. */ export function __experimentalGetEntityRecordNoResolver< - EntityRecord extends ET.EntityRecord< any > + EntityRecord extends ET.EntityRecord< any >, >( state: State, kind: string, name: string, key: EntityRecordKey ) { return getEntityRecord< EntityRecord >( state, kind, name, key ); } @@ -478,7 +473,7 @@ export interface GetEntityRecords { < EntityRecord extends | ET.EntityRecord< any > - | Partial< ET.EntityRecord< any > > + | Partial< ET.EntityRecord< any > >, >( state: State, kind: string, @@ -489,7 +484,7 @@ export interface GetEntityRecords { CurriedSignature: < EntityRecord extends | ET.EntityRecord< any > - | Partial< ET.EntityRecord< any > > + | Partial< ET.EntityRecord< any > >, >( kind: string, name: string, @@ -511,7 +506,7 @@ export interface GetEntityRecords { export const getEntityRecords = ( < EntityRecord extends | ET.EntityRecord< any > - | Partial< ET.EntityRecord< any > > + | Partial< ET.EntityRecord< any > >, >( state: State, kind: string, @@ -1241,21 +1236,13 @@ export function getBlockPatternCategories( state: State ): Array< any > { * * @param state Data state. * - * @return User patterns category array and map keyed by id. + * @return User patterns category array. */ export function getUserPatternCategories( state: State -): UserPatternCategories { - const patternCategoriesMap = new Map< number, UserPatternCategory >(); - state.userPatternCategories?.forEach( - ( userCategory: UserPatternCategory ) => - patternCategoriesMap.set( userCategory.id, userCategory ) - ); - return { - patternCategories: state.userPatternCategories, - patternCategoriesMap, - }; +): Array< UserPatternCategory > { + return state.userPatternCategories; } /** diff --git a/packages/create-block/lib/index.js b/packages/create-block/lib/index.js index 785e593a379fe..8e3d43c140460 100644 --- a/packages/create-block/lib/index.js +++ b/packages/create-block/lib/index.js @@ -185,9 +185,8 @@ program ], variant ).filter( filterOptionsProvided ); - const result = await inquirer.prompt( - pluginPrompts - ); + const result = + await inquirer.prompt( pluginPrompts ); return result; } ) : {}; diff --git a/packages/create-block/lib/templates.js b/packages/create-block/lib/templates.js index 29f713499e3f2..e835e31c08425 100644 --- a/packages/create-block/lib/templates.js +++ b/packages/create-block/lib/templates.js @@ -202,9 +202,11 @@ const getPluginTemplate = async ( templateName ) => { const { name } = npmPackageArg( templateName ); return await configToTemplate( - require( require.resolve( name, { - paths: [ tempCwd ], - } ) ) + require( + require.resolve( name, { + paths: [ tempCwd ], + } ) + ) ); } catch ( error ) { if ( error instanceof CLIError ) { diff --git a/packages/data/src/components/with-registry/index.js b/packages/data/src/components/with-registry/index.js index a5a6ce9503f88..faf3da8c009ad 100644 --- a/packages/data/src/components/with-registry/index.js +++ b/packages/data/src/components/with-registry/index.js @@ -17,14 +17,13 @@ import { RegistryConsumer } from '../registry-provider'; * @return {WPComponent} Enhanced component. */ const withRegistry = createHigherOrderComponent( - ( OriginalComponent ) => ( props ) => - ( - - { ( registry ) => ( - - ) } - - ), + ( OriginalComponent ) => ( props ) => ( + + { ( registry ) => ( + + ) } + + ), 'withRegistry' ); diff --git a/packages/data/src/dispatch.ts b/packages/data/src/dispatch.ts index c1f28c21187cc..348865112a59c 100644 --- a/packages/data/src/dispatch.ts +++ b/packages/data/src/dispatch.ts @@ -24,7 +24,7 @@ import defaultRegistry from './default-registry'; * @return Object containing the action creators. */ export function dispatch< - StoreNameOrDescriptor extends StoreDescriptor< AnyConfig > | string + StoreNameOrDescriptor extends StoreDescriptor< AnyConfig > | string, >( storeNameOrDescriptor: StoreNameOrDescriptor ): DispatchReturn< StoreNameOrDescriptor > { diff --git a/packages/data/src/types.ts b/packages/data/src/types.ts index af8cf82385275..570bb1e1890ce 100644 --- a/packages/data/src/types.ts +++ b/packages/data/src/types.ts @@ -33,7 +33,7 @@ export interface StoreDescriptor< Config extends AnyConfig > { export interface ReduxStoreConfig< State, ActionCreators extends MapOf< ActionCreator >, - Selectors + Selectors, > { initialState?: State; reducer: ( state: any, action: any ) => any; @@ -182,7 +182,7 @@ export type ActionCreatorsOf< Config extends AnyConfig > = // return type of each action creator to account for internal registry details -- // for example, dispatched actions are wrapped with a Promise. export type PromisifiedActionCreators< - ActionCreators extends MapOf< ActionCreator > + ActionCreators extends MapOf< ActionCreator >, > = { [ Action in keyof ActionCreators ]: PromisifyActionCreator< ActionCreators[ Action ] diff --git a/packages/e2e-test-utils/src/inserter.js b/packages/e2e-test-utils/src/inserter.js index 68f2ffaff49ac..ebbda244d1856 100644 --- a/packages/e2e-test-utils/src/inserter.js +++ b/packages/e2e-test-utils/src/inserter.js @@ -238,7 +238,7 @@ export async function insertFromGlobalInserter( category, searchTerm ) { await page.$x( `//*[@role='option' and contains(., '${ searchTerm }')]` ) - )[ 0 ]; + )[ 0 ]; } catch ( error ) { // noop } diff --git a/packages/e2e-tests/specs/editor/plugins/annotations.test.js b/packages/e2e-tests/specs/editor/plugins/annotations.test.js index 24eaebb765966..50290aa1cc68b 100644 --- a/packages/e2e-tests/specs/editor/plugins/annotations.test.js +++ b/packages/e2e-tests/specs/editor/plugins/annotations.test.js @@ -50,7 +50,7 @@ describe( 'Annotations', () => { // Click add annotation button. const addAnnotationButton = ( await page.$x( "//button[contains(text(), 'Add annotation')]" ) - )[ 0 ]; + )[ 0 ]; await addAnnotationButton.click(); await canvas().evaluate( () => document.querySelector( '.wp-block-paragraph' ).focus() @@ -66,7 +66,7 @@ describe( 'Annotations', () => { // Click remove annotations button. const addAnnotationButton = ( await page.$x( "//button[contains(text(), 'Remove annotations')]" ) - )[ 0 ]; + )[ 0 ]; await addAnnotationButton.click(); await canvas().evaluate( () => document.querySelector( '[contenteditable]' ).focus() diff --git a/packages/e2e-tests/specs/editor/plugins/container-blocks.test.js b/packages/e2e-tests/specs/editor/plugins/container-blocks.test.js index 88c1a7fc8271a..7393b2700ff2b 100644 --- a/packages/e2e-tests/specs/editor/plugins/container-blocks.test.js +++ b/packages/e2e-tests/specs/editor/plugins/container-blocks.test.js @@ -121,7 +121,7 @@ describe( 'Container block without paragraph support', () => { // Insert an image block. const insertButton = ( await page.$x( `//button//span[contains(text(), 'Image')]` ) - )[ 0 ]; + )[ 0 ]; await insertButton.click(); // Check the inserted content. diff --git a/packages/e2e-tests/specs/editor/plugins/custom-taxonomies.test.js b/packages/e2e-tests/specs/editor/plugins/custom-taxonomies.test.js index 42c476f9cf12a..3d65b1ebc98f7 100644 --- a/packages/e2e-tests/specs/editor/plugins/custom-taxonomies.test.js +++ b/packages/e2e-tests/specs/editor/plugins/custom-taxonomies.test.js @@ -32,7 +32,7 @@ describe( 'Custom Taxonomies labels are used', () => { // Get the classes from the panel. const buttonClassName = await ( await openButton.getProperty( 'className' ) - ).jsonValue(); + ).jsonValue(); // Open the panel if needed. if ( -1 === buttonClassName.indexOf( 'is-opened' ) ) { diff --git a/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js b/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js index 81a7d943331bb..1322713b033e2 100644 --- a/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js +++ b/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js @@ -58,7 +58,7 @@ describe( 'RenderAppender prop of InnerBlocks', () => { const inserterPopover = await page.$( INSERTER_RESULTS_SELECTOR ); const quoteButton = ( await inserterPopover.$x( QUOTE_INSERT_BUTTON_SELECTOR ) - )[ 0 ]; + )[ 0 ]; // Insert a quote block. await quoteButton.click(); @@ -93,7 +93,7 @@ describe( 'RenderAppender prop of InnerBlocks', () => { const inserterPopover = await page.$( INSERTER_RESULTS_SELECTOR ); const quoteButton = ( await inserterPopover.$x( QUOTE_INSERT_BUTTON_SELECTOR ) - )[ 0 ]; + )[ 0 ]; // Insert a quote block. await quoteButton.click(); diff --git a/packages/e2e-tests/specs/editor/plugins/meta-boxes.test.js b/packages/e2e-tests/specs/editor/plugins/meta-boxes.test.js index 6b3001c96d80b..3a75f9656c71e 100644 --- a/packages/e2e-tests/specs/editor/plugins/meta-boxes.test.js +++ b/packages/e2e-tests/specs/editor/plugins/meta-boxes.test.js @@ -103,9 +103,8 @@ describe( 'Meta boxes', () => { // Open the excerpt panel. await openDocumentSettingsSidebar(); - const excerptButton = await findSidebarPanelToggleButtonWithTitle( - 'Excerpt' - ); + const excerptButton = + await findSidebarPanelToggleButtonWithTitle( 'Excerpt' ); if ( excerptButton ) { await excerptButton.click( 'button' ); } diff --git a/packages/e2e-tests/specs/editor/various/change-detection.test.js b/packages/e2e-tests/specs/editor/various/change-detection.test.js index 97157060d3624..32e5115094533 100644 --- a/packages/e2e-tests/specs/editor/various/change-detection.test.js +++ b/packages/e2e-tests/specs/editor/various/change-detection.test.js @@ -102,7 +102,7 @@ describe( 'Change detection', () => { const postPendingReviewButton = ( await page.$x( "//label[contains(text(), 'Pending review')]" ) - )[ 0 ]; + )[ 0 ]; await postPendingReviewButton.click( 'button' ); // Force autosave to occur immediately. diff --git a/packages/e2e-tests/specs/editor/various/inserting-blocks.test.js b/packages/e2e-tests/specs/editor/various/inserting-blocks.test.js index 84c251d653468..bed9002e303a2 100644 --- a/packages/e2e-tests/specs/editor/various/inserting-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/inserting-blocks.test.js @@ -259,7 +259,7 @@ describe( 'Inserting blocks', () => { const headingButton = ( await page.$x( `//button//span[contains(text(), 'Heading')]` ) - )[ 0 ]; + )[ 0 ]; // Hover over the block should show the blue line indicator. await headingButton.hover(); @@ -354,7 +354,7 @@ describe( 'Inserting blocks', () => { await openGlobalBlockInserter(); const paragraphButton = ( await page.$x( `//button//span[contains(text(), 'Paragraph')]` ) - )[ 0 ]; + )[ 0 ]; await paragraphButton.hover(); const preview = await page.waitForSelector( '.block-editor-inserter__preview', diff --git a/packages/e2e-tests/specs/site-editor/multi-entity-saving.test.js b/packages/e2e-tests/specs/site-editor/multi-entity-saving.test.js index c2bd3cb6d7507..fe5334d2a1276 100644 --- a/packages/e2e-tests/specs/site-editor/multi-entity-saving.test.js +++ b/packages/e2e-tests/specs/site-editor/multi-entity-saving.test.js @@ -77,9 +77,8 @@ describe( 'Multi-entity save flow', () => { // Reusable assertions inside Post editor. const assertMultiSaveEnabled = async () => { - const multiSaveButton = await page.waitForSelector( - multiSaveSelector - ); + const multiSaveButton = + await page.waitForSelector( multiSaveSelector ); expect( multiSaveButton ).not.toBeNull(); }; const assertMultiSaveDisabled = async () => { diff --git a/packages/e2e-tests/specs/widgets/editing-widgets.test.js b/packages/e2e-tests/specs/widgets/editing-widgets.test.js index 2d77e297aaeab..9292867159e61 100644 --- a/packages/e2e-tests/specs/widgets/editing-widgets.test.js +++ b/packages/e2e-tests/specs/widgets/editing-widgets.test.js @@ -388,9 +388,8 @@ describe( 'Widgets screen', () => { name: 'Block: Widget Area', } ); await firstWidgetArea.focus(); - const marqueeBlock = await getBlockInGlobalInserter( - 'Marquee Greeting' - ); + const marqueeBlock = + await getBlockInGlobalInserter( 'Marquee Greeting' ); await marqueeBlock.click(); await page.waitForFunction( ( expectedMarquees ) => { @@ -721,9 +720,8 @@ describe( 'Widgets screen', () => { const [ firstWidgetArea, secondWidgetArea ] = widgetAreas; // Insert a paragraph it should be in the first widget area. - const inserterParagraphBlock = await getBlockInGlobalInserter( - 'Paragraph' - ); + const inserterParagraphBlock = + await getBlockInGlobalInserter( 'Paragraph' ); await inserterParagraphBlock.hover(); await inserterParagraphBlock.click(); const addedParagraphBlockInFirstWidgetArea = await find( diff --git a/packages/edit-site/src/components/add-new-template/index.js b/packages/edit-site/src/components/add-new-template/index.js index ffdf1b8937690..1f1e855ccf38d 100644 --- a/packages/edit-site/src/components/add-new-template/index.js +++ b/packages/edit-site/src/components/add-new-template/index.js @@ -8,9 +8,10 @@ import { store as coreStore } from '@wordpress/core-data'; * Internal dependencies */ import NewTemplate from './new-template'; +import { TEMPLATE_POST_TYPE } from '../../utils/constants'; export default function AddNewTemplate( { - templateType = 'wp_template', + templateType = TEMPLATE_POST_TYPE, ...props } ) { const postType = useSelect( @@ -22,7 +23,7 @@ export default function AddNewTemplate( { return null; } - if ( templateType === 'wp_template' ) { + if ( templateType === TEMPLATE_POST_TYPE ) { return ; } diff --git a/packages/edit-site/src/components/add-new-template/new-template.js b/packages/edit-site/src/components/add-new-template/new-template.js index 31ddd754562db..377b26a8106e5 100644 --- a/packages/edit-site/src/components/add-new-template/new-template.js +++ b/packages/edit-site/src/components/add-new-template/new-template.js @@ -42,6 +42,11 @@ import { __, sprintf } from '@wordpress/i18n'; import { store as noticesStore } from '@wordpress/notices'; import { privateApis as routerPrivateApis } from '@wordpress/router'; +/** + * Internal dependencies + */ +import { TEMPLATE_POST_TYPE } from '../../utils/constants'; + /** * Internal dependencies */ @@ -190,7 +195,7 @@ export default function NewTemplate( { const { title, description, slug } = template; const newTemplate = await saveEntityRecord( 'postType', - 'wp_template', + TEMPLATE_POST_TYPE, { description, // Slugs need to be strings, so this is for template `404` diff --git a/packages/edit-site/src/components/add-new-template/utils.js b/packages/edit-site/src/components/add-new-template/utils.js index 1869cdb72f592..f94c230196053 100644 --- a/packages/edit-site/src/components/add-new-template/utils.js +++ b/packages/edit-site/src/components/add-new-template/utils.js @@ -9,6 +9,11 @@ import { useMemo, useCallback } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import { blockMeta, post, archive } from '@wordpress/icons'; +/** + * Internal dependencies + */ +import { TEMPLATE_POST_TYPE } from '../../utils/constants'; + /** * @typedef IHasNameAndId * @property {string|number} id The entity's id. @@ -48,9 +53,13 @@ export const mapToIHasNameAndId = ( entities, path ) => { export const useExistingTemplates = () => { return useSelect( ( select ) => - select( coreStore ).getEntityRecords( 'postType', 'wp_template', { - per_page: -1, - } ), + select( coreStore ).getEntityRecords( + 'postType', + TEMPLATE_POST_TYPE, + { + per_page: -1, + } + ), [] ); }; diff --git a/packages/edit-site/src/components/block-editor/back-button.js b/packages/edit-site/src/components/block-editor/back-button.js index ebe5af44c0250..924dedd4f853e 100644 --- a/packages/edit-site/src/components/block-editor/back-button.js +++ b/packages/edit-site/src/components/block-editor/back-button.js @@ -9,6 +9,10 @@ import { privateApis as routerPrivateApis } from '@wordpress/router'; /** * Internal dependencies */ +import { + TEMPLATE_PART_POST_TYPE, + NAVIGATION_POST_TYPE, +} from '../../utils/constants'; import { unlock } from '../../lock-unlock'; const { useLocation, useHistory } = unlock( routerPrivateApis ); @@ -16,8 +20,8 @@ const { useLocation, useHistory } = unlock( routerPrivateApis ); function BackButton() { const location = useLocation(); const history = useHistory(); - const isTemplatePart = location.params.postType === 'wp_template_part'; - const isNavigationMenu = location.params.postType === 'wp_navigation'; + const isTemplatePart = location.params.postType === TEMPLATE_PART_POST_TYPE; + const isNavigationMenu = location.params.postType === NAVIGATION_POST_TYPE; const previousTemplateId = location.state?.fromTemplateId; const isFocusMode = isTemplatePart || isNavigationMenu; diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 4bdd98b5d170e..25fcbff830553 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -44,6 +44,7 @@ import CanvasLoader from '../canvas-loader'; import { unlock } from '../../lock-unlock'; import useEditedEntityRecord from '../use-edited-entity-record'; import { SidebarFixedBottomSlot } from '../sidebar-edit-mode/sidebar-fixed-bottom'; +import { POST_TYPE_LABELS, TEMPLATE_POST_TYPE } from '../../utils/constants'; const { BlockRemovalWarningModal } = unlock( blockEditorPrivateApis ); @@ -58,13 +59,6 @@ const interfaceLabels = { footer: __( 'Editor footer' ), }; -const typeLabels = { - wp_template: __( 'Template' ), - wp_template_part: __( 'Template Part' ), - wp_block: __( 'Pattern' ), - wp_navigation: __( 'Navigation' ), -}; - // Prevent accidental removal of certain blocks, asking the user for // confirmation. const blockRemovalRules = { @@ -171,7 +165,8 @@ export default function Editor( { isLoading } ) { // translators: A breadcrumb trail in browser tab. %1$s: title of template being edited, %2$s: type of template (Template or Template Part). __( '%1$s ‹ %2$s ‹ Editor' ), getTitle(), - typeLabels[ editedPostType ] ?? typeLabels.wp_template + POST_TYPE_LABELS[ editedPostType ] ?? + POST_TYPE_LABELS[ TEMPLATE_POST_TYPE ] ); } diff --git a/packages/edit-site/src/components/global-styles/dimensions-panel.js b/packages/edit-site/src/components/global-styles/dimensions-panel.js index 461ed7ab8dce8..d70dd03e603c0 100644 --- a/packages/edit-site/src/components/global-styles/dimensions-panel.js +++ b/packages/edit-site/src/components/global-styles/dimensions-panel.js @@ -33,6 +33,7 @@ export default function DimensionsPanel() { const [ inheritedStyle, setStyle ] = useGlobalStyle( '', undefined, 'all', { shouldDecodeEncode: false, } ); + const [ userSettings ] = useGlobalSetting( '', undefined, 'user' ); const [ rawSettings, setSettings ] = useGlobalSetting( '' ); const settings = useSettingsForBlockElement( rawSettings ); @@ -48,17 +49,20 @@ export default function DimensionsPanel() { const styleWithLayout = useMemo( () => { return { ...style, - layout: settings.layout, + layout: userSettings.layout, }; - }, [ style, settings.layout ] ); + }, [ style, userSettings.layout ] ); const onChange = ( newStyle ) => { const updatedStyle = { ...newStyle }; delete updatedStyle.layout; setStyle( updatedStyle ); - if ( newStyle.layout !== settings.layout ) { - const updatedSettings = { ...rawSettings, layout: newStyle.layout }; + if ( newStyle.layout !== userSettings.layout ) { + const updatedSettings = { + ...userSettings, + layout: newStyle.layout, + }; // Ensure any changes to layout definitions are not persisted. if ( updatedSettings.layout?.definitions ) { diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index 14b786ff08534..07c2da701e9e0 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -253,7 +253,7 @@ function FontLibraryProvider( { children } ) { const deactivateFontFamily = ( font ) => { // If the user doesn't have custom fonts defined, include as custom fonts all the theme fonts // We want to save as active all the theme fonts at the beginning - const initialCustomFonts = fontFamilies[ font.source ] || []; + const initialCustomFonts = fontFamilies?.[ font.source ] ?? []; const newCustomFonts = initialCustomFonts.filter( ( f ) => f.slug !== font.slug ); @@ -266,7 +266,7 @@ function FontLibraryProvider( { children } ) { const activateCustomFontFamilies = ( fontsToAdd ) => { // Merge the existing custom fonts with the new fonts. const newCustomFonts = mergeFontFamilies( - fontFamilies.custom, + fontFamilies?.custom, fontsToAdd ); // Activate the fonts by set the new custom fonts array. @@ -290,7 +290,7 @@ function FontLibraryProvider( { children } ) { const toggleActivateFont = ( font, face ) => { // If the user doesn't have custom fonts defined, include as custom fonts all the theme fonts // We want to save as active all the theme fonts at the beginning - const initialFonts = fontFamilies[ font.source ] || []; + const initialFonts = fontFamilies?.[ font.source ] ?? []; // Toggles the received font family or font face const newFonts = toggleFont( font, face, initialFonts ); // Updates the font families activated in global settings: diff --git a/packages/edit-site/src/components/global-styles/screen-block.js b/packages/edit-site/src/components/global-styles/screen-block.js index f2bc5e920067d..b5ef99f96abf5 100644 --- a/packages/edit-site/src/components/global-styles/screen-block.js +++ b/packages/edit-site/src/components/global-styles/screen-block.js @@ -91,8 +91,8 @@ function ScreenBlock( { name, variation } ) { const [ inheritedStyle, setStyle ] = useGlobalStyle( prefix, name, 'all', { shouldDecodeEncode: false, } ); - const [ rawSettings, setSettings ] = useGlobalSetting( '', name ); const [ userSettings ] = useGlobalSetting( '', name, 'user' ); + const [ rawSettings, setSettings ] = useGlobalSetting( '', name ); const settings = useSettingsForBlockElement( rawSettings, name ); const blockType = getBlockType( name ); @@ -151,17 +151,17 @@ function ScreenBlock( { name, variation } ) { const styleWithLayout = useMemo( () => { return { ...style, - layout: settings.layout, + layout: userSettings.layout, }; - }, [ style, settings.layout ] ); + }, [ style, userSettings.layout ] ); const onChangeDimensions = ( newStyle ) => { const updatedStyle = { ...newStyle }; delete updatedStyle.layout; setStyle( updatedStyle ); - if ( newStyle.layout !== settings.layout ) { + if ( newStyle.layout !== userSettings.layout ) { setSettings( { - ...rawSettings, + ...userSettings, layout: newStyle.layout, } ); } @@ -308,7 +308,7 @@ function ScreenBlock( { name, variation } ) { { sprintf( // translators: %s: is the name of a block e.g., 'Image' or 'Table'. __( - 'Add your own CSS to customize the appearance of the %s block.' + 'Add your own CSS to customize the appearance of the %s block. You do not need to include a CSS selector, just add the property and value.' ), blockType?.title ) } diff --git a/packages/edit-site/src/components/page-patterns/duplicate-menu-item.js b/packages/edit-site/src/components/page-patterns/duplicate-menu-item.js index 324b22e460447..c562ffbeeb6c8 100644 --- a/packages/edit-site/src/components/page-patterns/duplicate-menu-item.js +++ b/packages/edit-site/src/components/page-patterns/duplicate-menu-item.js @@ -11,7 +11,11 @@ import { privateApis as routerPrivateApis } from '@wordpress/router'; /** * Internal dependencies */ -import { TEMPLATE_PARTS, PATTERNS, SYNC_TYPES, USER_PATTERNS } from './utils'; +import { + TEMPLATE_PART_POST_TYPE, + PATTERN_TYPES, + PATTERN_SYNC_TYPES, +} from '../../utils/constants'; import { useExistingTemplateParts, getUniqueTemplatePartTitle, @@ -23,12 +27,12 @@ import usePatternCategories from '../sidebar-navigation-screen-patterns/use-patt const { useHistory } = unlock( routerPrivateApis ); function getPatternMeta( item ) { - if ( item.type === PATTERNS ) { - return { wp_pattern_sync_status: SYNC_TYPES.unsynced }; + if ( item.type === PATTERN_TYPES.theme ) { + return { wp_pattern_sync_status: PATTERN_SYNC_TYPES.unsynced }; } const syncStatus = item.patternBlock.wp_pattern_sync_status; - const isUnsynced = syncStatus === SYNC_TYPES.unsynced; + const isUnsynced = syncStatus === PATTERN_SYNC_TYPES.unsynced; return { ...item.patternBlock.meta, @@ -84,9 +88,9 @@ export default function DuplicateMenuItem( { ); history.push( { - postType: TEMPLATE_PARTS, + postType: TEMPLATE_PART_POST_TYPE, postId: result?.id, - categoryType: TEMPLATE_PARTS, + categoryType: TEMPLATE_PART_POST_TYPE, categoryId, } ); @@ -148,7 +152,7 @@ export default function DuplicateMenuItem( { async function createPattern() { try { - const isThemePattern = item.type === PATTERNS; + const isThemePattern = item.type === PATTERN_TYPES.theme; const title = sprintf( /* translators: %s: Existing pattern title */ __( '%s (Copy)' ), @@ -184,9 +188,9 @@ export default function DuplicateMenuItem( { ); history.push( { - categoryType: PATTERNS, + categoryType: PATTERN_TYPES.theme, categoryId, - postType: USER_PATTERNS, + postType: PATTERN_TYPES.user, postId: result?.id, } ); @@ -206,7 +210,9 @@ export default function DuplicateMenuItem( { } const createItem = - item.type === TEMPLATE_PARTS ? createTemplatePart : createPattern; + item.type === TEMPLATE_PART_POST_TYPE + ? createTemplatePart + : createPattern; return { label }; } diff --git a/packages/edit-site/src/components/page-patterns/grid-item.js b/packages/edit-site/src/components/page-patterns/grid-item.js index 25aab2646cdfd..a9c6fdc2d9d1a 100644 --- a/packages/edit-site/src/components/page-patterns/grid-item.js +++ b/packages/edit-site/src/components/page-patterns/grid-item.js @@ -6,7 +6,10 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { BlockPreview } from '@wordpress/block-editor'; +import { + BlockPreview, + privateApis as blockEditorPrivateApis, +} from '@wordpress/block-editor'; import { Button, __experimentalConfirmDialog as ConfirmDialog, @@ -38,15 +41,23 @@ import { store as reusableBlocksStore } from '@wordpress/reusable-blocks'; */ import RenameMenuItem from './rename-menu-item'; import DuplicateMenuItem from './duplicate-menu-item'; -import { PATTERNS, TEMPLATE_PARTS, USER_PATTERNS, SYNC_TYPES } from './utils'; +import { + PATTERN_TYPES, + TEMPLATE_PART_POST_TYPE, + PATTERN_SYNC_TYPES, +} from '../../utils/constants'; import { store as editSiteStore } from '../../store'; import { useLink } from '../routes/link'; +import { unlock } from '../../lock-unlock'; + +const { useGlobalStyle } = unlock( blockEditorPrivateApis ); const templatePartIcons = { header, footer, uncategorized }; function GridItem( { categoryId, item, ...props } ) { const descriptionId = useId(); const [ isDeleteDialogOpen, setIsDeleteDialogOpen ] = useState( false ); + const [ backgroundColor ] = useGlobalStyle( 'color.background' ); const { removeTemplate } = useDispatch( editSiteStore ); const { __experimentalDeleteReusableBlock } = @@ -54,9 +65,9 @@ function GridItem( { categoryId, item, ...props } ) { const { createErrorNotice, createSuccessNotice } = useDispatch( noticesStore ); - const isUserPattern = item.type === USER_PATTERNS; - const isNonUserPattern = item.type === PATTERNS; - const isTemplatePart = item.type === TEMPLATE_PARTS; + const isUserPattern = item.type === PATTERN_TYPES.user; + const isNonUserPattern = item.type === PATTERN_TYPES.theme; + const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE; const { onClick } = useLink( { postType: item.type, @@ -123,7 +134,8 @@ function GridItem( { categoryId, item, ...props } ) { if ( ! isUserPattern && templatePartIcons[ categoryId ] ) { itemIcon = templatePartIcons[ categoryId ]; } else { - itemIcon = item.syncStatus === SYNC_TYPES.full ? symbol : undefined; + itemIcon = + item.syncStatus === PATTERN_SYNC_TYPES.full ? symbol : undefined; } const confirmButtonText = hasThemeFile ? __( 'Clear' ) : __( 'Delete' ); @@ -135,6 +147,10 @@ function GridItem( { categoryId, item, ...props } ) { item.title ); + const additionalStyles = ! backgroundColor + ? [ { css: 'body { background: #fff; }' } ] + : undefined; + return (
  • { ariaDescriptions.map( ( ariaDescription, index ) => (
    { itemIcon && ! isNonUserPattern && ( ) } - { item.type === PATTERNS ? ( + { item.type === PATTERN_TYPES.theme ? ( item.title ) : ( @@ -209,9 +234,9 @@ function GridItem( { categoryId, item, ...props } ) { ) } - { item.type === PATTERNS && ( + { item.type === PATTERN_TYPES.theme && ( area.area === categoryId ); title = templatePartArea?.label; description = templatePartArea?.description; - } else if ( type === PATTERNS ) { + } else if ( type === PATTERN_TYPES.theme ) { const patternCategory = patternCategories.find( ( category ) => category.name === categoryId ); diff --git a/packages/edit-site/src/components/page-patterns/index.js b/packages/edit-site/src/components/page-patterns/index.js index d90fc74844244..6861b26d65387 100644 --- a/packages/edit-site/src/components/page-patterns/index.js +++ b/packages/edit-site/src/components/page-patterns/index.js @@ -8,7 +8,7 @@ import { getQueryArgs } from '@wordpress/url'; /** * Internal dependencies */ -import { DEFAULT_CATEGORY, DEFAULT_TYPE } from './utils'; +import { PATTERN_DEFAULT_CATEGORY, PATTERN_TYPES } from '../../utils/constants'; import Page from '../page'; import PatternsList from './patterns-list'; import usePatternSettings from './use-pattern-settings'; @@ -18,8 +18,8 @@ const { ExperimentalBlockEditorProvider } = unlock( blockEditorPrivateApis ); export default function PagePatterns() { const { categoryType, categoryId } = getQueryArgs( window.location.href ); - const type = categoryType || DEFAULT_TYPE; - const category = categoryId || DEFAULT_CATEGORY; + const type = categoryType || PATTERN_TYPES.user; + const category = categoryId || PATTERN_DEFAULT_CATEGORY; const settings = usePatternSettings(); // Wrap everything in a block editor provider. diff --git a/packages/edit-site/src/components/page-patterns/patterns-list.js b/packages/edit-site/src/components/page-patterns/patterns-list.js index 57c342ca3caa9..95e6824c58144 100644 --- a/packages/edit-site/src/components/page-patterns/patterns-list.js +++ b/packages/edit-site/src/components/page-patterns/patterns-list.js @@ -27,23 +27,23 @@ import usePatterns from './use-patterns'; import SidebarButton from '../sidebar-button'; import useDebouncedInput from '../../utils/use-debounced-input'; import { unlock } from '../../lock-unlock'; -import { SYNC_TYPES, PATTERNS } from './utils'; +import { PATTERN_SYNC_TYPES, PATTERN_TYPES } from '../../utils/constants'; import Pagination from './pagination'; const { useLocation, useHistory } = unlock( routerPrivateApis ); const SYNC_FILTERS = { all: __( 'All' ), - [ SYNC_TYPES.full ]: __( 'Synced' ), - [ SYNC_TYPES.unsynced ]: __( 'Standard' ), + [ PATTERN_SYNC_TYPES.full ]: __( 'Synced' ), + [ PATTERN_SYNC_TYPES.unsynced ]: __( 'Standard' ), }; const SYNC_DESCRIPTIONS = { all: '', - [ SYNC_TYPES.full ]: __( + [ PATTERN_SYNC_TYPES.full ]: __( 'Patterns that are kept in sync across the site.' ), - [ SYNC_TYPES.unsynced ]: __( + [ PATTERN_SYNC_TYPES.unsynced ]: __( 'Patterns that can be changed freely without affecting the site.' ), }; @@ -64,7 +64,7 @@ export default function PatternsList( { categoryId, type } ) { const deferredSyncedFilter = useDeferredValue( syncFilter ); const isUncategorizedThemePatterns = - type === PATTERNS && categoryId === 'uncategorized'; + type === PATTERN_TYPES.theme && categoryId === 'uncategorized'; const { patterns, isResolving } = usePatterns( type, @@ -155,7 +155,7 @@ export default function PatternsList( { categoryId, type } ) { __nextHasNoMarginBottom /> - { type === PATTERNS && ( + { type === PATTERN_TYPES.theme && ( item.title ); @@ -29,7 +29,7 @@ export default function RenameMenuItem( { item, onClose } ) { const { createSuccessNotice, createErrorNotice } = useDispatch( noticesStore ); - if ( item.type === TEMPLATE_PARTS && ! item.isCustom ) { + if ( item.type === TEMPLATE_PART_POST_TYPE && ! item.isCustom ) { return null; } @@ -50,7 +50,7 @@ export default function RenameMenuItem( { item, onClose } ) { } ); createSuccessNotice( - item.type === TEMPLATE_PARTS + item.type === TEMPLATE_PART_POST_TYPE ? __( 'Template part renamed.' ) : __( 'Pattern renamed.' ), { @@ -59,7 +59,7 @@ export default function RenameMenuItem( { item, onClose } ) { ); } catch ( error ) { const fallbackErrorMessage = - item.type === TEMPLATE_PARTS + item.type === TEMPLATE_PART_POST_TYPE ? __( 'An error occurred while reverting the template part.' ) diff --git a/packages/edit-site/src/components/page-patterns/search-items.js b/packages/edit-site/src/components/page-patterns/search-items.js index 4ba9b9356af3c..3c9beca587c24 100644 --- a/packages/edit-site/src/components/page-patterns/search-items.js +++ b/packages/edit-site/src/components/page-patterns/search-items.js @@ -7,7 +7,7 @@ import { noCase } from 'change-case'; /** * Internal dependencies */ -import { ALL_PATTERNS_CATEGORY } from './utils'; +import { PATTERN_DEFAULT_CATEGORY } from '../../utils/constants'; // Default search helpers. const defaultGetName = ( item ) => item.name || ''; @@ -89,8 +89,9 @@ const removeMatchingTerms = ( unmatchedTerms, unprocessedTerms ) => { */ export const searchItems = ( items = [], searchInput = '', config = {} ) => { const normalizedSearchTerms = getNormalizedSearchTerms( searchInput ); + // Filter patterns by category: the default category indicates that all patterns will be shown. const onlyFilterByCategory = - config.categoryId !== ALL_PATTERNS_CATEGORY && + config.categoryId !== PATTERN_DEFAULT_CATEGORY && ! normalizedSearchTerms.length; const searchRankConfig = { ...config, onlyFilterByCategory }; @@ -139,7 +140,8 @@ function getItemSearchRank( item, searchTerm, config ) { } = config; let rank = - categoryId === ALL_PATTERNS_CATEGORY || hasCategory( item, categoryId ) + categoryId === PATTERN_DEFAULT_CATEGORY || + hasCategory( item, categoryId ) ? 1 : 0; diff --git a/packages/edit-site/src/components/page-patterns/use-patterns.js b/packages/edit-site/src/components/page-patterns/use-patterns.js index 25919d5556710..daaa9dd7822da 100644 --- a/packages/edit-site/src/components/page-patterns/use-patterns.js +++ b/packages/edit-site/src/components/page-patterns/use-patterns.js @@ -10,14 +10,13 @@ import { decodeEntities } from '@wordpress/html-entities'; /** * Internal dependencies */ +import { filterOutDuplicatesByName } from './utils'; import { - CORE_PATTERN_SOURCES, - PATTERNS, - SYNC_TYPES, - TEMPLATE_PARTS, - USER_PATTERNS, - filterOutDuplicatesByName, -} from './utils'; + PATTERN_CORE_SOURCES, + PATTERN_TYPES, + PATTERN_SYNC_TYPES, + TEMPLATE_PART_POST_TYPE, +} from '../../utils/constants'; import { unlock } from '../../lock-unlock'; import { searchItems } from './search-items'; import { store as editSiteStore } from '../../store'; @@ -50,7 +49,7 @@ const selectTemplatePartsAsPatterns = ( const { __experimentalGetDefaultTemplatePartAreas } = select( editorStore ); const query = { per_page: -1 }; const rawTemplateParts = - getEntityRecords( 'postType', TEMPLATE_PARTS, query ) ?? + getEntityRecords( 'postType', TEMPLATE_PART_POST_TYPE, query ) ?? EMPTY_PATTERN_LIST; const templateParts = rawTemplateParts.map( ( templatePart ) => templatePartToPattern( templatePart ) @@ -101,14 +100,14 @@ const selectThemePatterns = ( select ) => { ...( restBlockPatterns || [] ), ] .filter( - ( pattern ) => ! CORE_PATTERN_SOURCES.includes( pattern.source ) + ( pattern ) => ! PATTERN_CORE_SOURCES.includes( pattern.source ) ) .filter( filterOutDuplicatesByName ) .filter( ( pattern ) => pattern.inserter !== false ) .map( ( pattern ) => ( { ...pattern, keywords: pattern.keywords || [], - type: 'pattern', + type: PATTERN_TYPES.theme, blocks: parse( pattern.content, { __unstableSkipMigrationLogs: true, } ), @@ -159,9 +158,9 @@ const patternBlockToPattern = ( patternBlock, categories ) => ( { } ), id: patternBlock.id, name: patternBlock.slug, - syncStatus: patternBlock.wp_pattern_sync_status || SYNC_TYPES.full, + syncStatus: patternBlock.wp_pattern_sync_status || PATTERN_SYNC_TYPES.full, title: patternBlock.title.raw, - type: USER_PATTERNS, + type: PATTERN_TYPES.user, patternBlock, } ); @@ -170,18 +169,21 @@ const selectUserPatterns = ( select, { search = '', syncStatus } = {} ) => { select( coreStore ); const query = { per_page: -1 }; - const records = getEntityRecords( 'postType', USER_PATTERNS, query ); - const categories = getUserPatternCategories(); - + const records = getEntityRecords( 'postType', PATTERN_TYPES.user, query ); + const userPatternCategories = getUserPatternCategories(); + const categories = new Map(); + userPatternCategories.forEach( ( userCategory ) => + categories.set( userCategory.id, userCategory ) + ); let patterns = records ? records.map( ( record ) => - patternBlockToPattern( record, categories.patternCategoriesMap ) + patternBlockToPattern( record, categories ) ) : EMPTY_PATTERN_LIST; const isResolving = getIsResolving( 'getEntityRecords', [ 'postType', - USER_PATTERNS, + PATTERN_TYPES.user, query, ] ); @@ -198,7 +200,7 @@ const selectUserPatterns = ( select, { search = '', syncStatus } = {} ) => { hasCategory: () => true, } ); - return { patterns, isResolving, categories: categories.patternCategories }; + return { patterns, isResolving, categories: userPatternCategories }; }; export const usePatterns = ( @@ -208,18 +210,18 @@ export const usePatterns = ( ) => { return useSelect( ( select ) => { - if ( categoryType === TEMPLATE_PARTS ) { + if ( categoryType === TEMPLATE_PART_POST_TYPE ) { return selectTemplatePartsAsPatterns( select, { categoryId, search, } ); - } else if ( categoryType === PATTERNS ) { + } else if ( categoryType === PATTERN_TYPES.theme ) { return selectPatterns( select, { categoryId, search, syncStatus, } ); - } else if ( categoryType === USER_PATTERNS ) { + } else if ( categoryType === PATTERN_TYPES.user ) { return selectUserPatterns( select, { search, syncStatus } ); } return { patterns: EMPTY_PATTERN_LIST, isResolving: false }; diff --git a/packages/edit-site/src/components/page-patterns/utils.js b/packages/edit-site/src/components/page-patterns/utils.js index 5ed57982e7cf1..f400d9855c513 100644 --- a/packages/edit-site/src/components/page-patterns/utils.js +++ b/packages/edit-site/src/components/page-patterns/utils.js @@ -1,21 +1,2 @@ -export const ALL_PATTERNS_CATEGORY = 'all-patterns'; -export const DEFAULT_CATEGORY = ALL_PATTERNS_CATEGORY; -export const PATTERNS = 'pattern'; -export const DEFAULT_TYPE = PATTERNS; -export const TEMPLATE_PARTS = 'wp_template_part'; -export const USER_PATTERNS = 'wp_block'; - -export const CORE_PATTERN_SOURCES = [ - 'core', - 'pattern-directory/core', - 'pattern-directory/featured', - 'pattern-directory/theme', -]; - -export const SYNC_TYPES = { - full: 'fully', - unsynced: 'unsynced', -}; - export const filterOutDuplicatesByName = ( currentItem, index, items ) => index === items.findIndex( ( item ) => currentItem.name === item.name ); diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js index ea84610c3de58..fb6be8c7fa2f9 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js @@ -38,10 +38,15 @@ export default function usePatternDetails( postType, postId ) { const { currentTheme, patternCategories } = useSelect( ( select ) => { const { getCurrentTheme, getUserPatternCategories } = select( coreStore ); + const userPatternCategories = getUserPatternCategories(); + const categories = new Map(); + userPatternCategories.forEach( ( userCategory ) => + categories.set( userCategory.id, userCategory ) + ); return { currentTheme: getCurrentTheme(), - patternCategories: getUserPatternCategories().patternCategoriesMap, + patternCategories: categories, }; }, [] ); diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/index.js b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/index.js index 0f77cd8e5c1af..0b7be99812dd6 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/index.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/index.js @@ -19,7 +19,7 @@ import AddNewPattern from '../add-new-pattern'; import SidebarNavigationItem from '../sidebar-navigation-item'; import SidebarNavigationScreen from '../sidebar-navigation-screen'; import CategoryItem from './category-item'; -import { DEFAULT_CATEGORY, DEFAULT_TYPE } from '../page-patterns/utils'; +import { PATTERN_DEFAULT_CATEGORY, PATTERN_TYPES } from '../../utils/constants'; import { useLink } from '../routes/link'; import usePatternCategories from './use-pattern-categories'; import useTemplatePartAreas from './use-template-part-areas'; @@ -70,8 +70,8 @@ function PatternCategoriesGroup( { type="pattern" isActive={ currentCategory === `${ category.name }` && - ( currentType === 'pattern' || - currentType === 'wp_block' ) + ( currentType === PATTERN_TYPES.theme || + currentType === PATTERN_TYPES.user ) } /> ) ) } @@ -83,8 +83,8 @@ function PatternCategoriesGroup( { export default function SidebarNavigationScreenPatterns() { const isMobileViewport = useViewportMatch( 'medium', '<' ); const { categoryType, categoryId } = getQueryArgs( window.location.href ); - const currentCategory = categoryId || DEFAULT_CATEGORY; - const currentType = categoryType || DEFAULT_TYPE; + const currentCategory = categoryId || PATTERN_DEFAULT_CATEGORY; + const currentType = categoryType || PATTERN_TYPES.user; const { templatePartAreas, hasTemplateParts, isLoading } = useTemplatePartAreas(); diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-pattern-categories.js b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-pattern-categories.js index e3ab86e8b0615..367b293f2206d 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-pattern-categories.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-pattern-categories.js @@ -10,7 +10,7 @@ import { __ } from '@wordpress/i18n'; import useDefaultPatternCategories from './use-default-pattern-categories'; import useThemePatterns from './use-theme-patterns'; import usePatterns from '../page-patterns/use-patterns'; -import { USER_PATTERNS, ALL_PATTERNS_CATEGORY } from '../page-patterns/utils'; +import { PATTERN_TYPES, PATTERN_DEFAULT_CATEGORY } from '../../utils/constants'; export default function usePatternCategories() { const defaultCategories = useDefaultPatternCategories(); @@ -20,7 +20,7 @@ export default function usePatternCategories() { } ); const themePatterns = useThemePatterns(); const { patterns: userPatterns, categories: userPatternCategories } = - usePatterns( USER_PATTERNS ); + usePatterns( PATTERN_TYPES.user ); const patternCategories = useMemo( () => { const categoryMap = {}; @@ -81,7 +81,7 @@ export default function usePatternCategories() { a.label.localeCompare( b.label ) ); sortedCategories.unshift( { - name: ALL_PATTERNS_CATEGORY, + name: PATTERN_DEFAULT_CATEGORY, label: __( 'All Patterns' ), description: __( 'A list of all patterns from all sources' ), count: themePatterns.length + userPatterns.length, diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-theme-patterns.js b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-theme-patterns.js index bf6decf341422..9e4983450ae5a 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-theme-patterns.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-theme-patterns.js @@ -8,10 +8,8 @@ import { useMemo } from '@wordpress/element'; /** * Internal dependencies */ -import { - CORE_PATTERN_SOURCES, - filterOutDuplicatesByName, -} from '../page-patterns/utils'; +import { filterOutDuplicatesByName } from '../page-patterns/utils'; +import { PATTERN_CORE_SOURCES } from '../../utils/constants'; import { unlock } from '../../lock-unlock'; import { store as editSiteStore } from '../../store'; @@ -34,7 +32,7 @@ export default function useThemePatterns() { [ ...( blockPatterns || [] ), ...( restBlockPatterns || [] ) ] .filter( ( pattern ) => - ! CORE_PATTERN_SOURCES.includes( pattern.source ) + ! PATTERN_CORE_SOURCES.includes( pattern.source ) ) .filter( filterOutDuplicatesByName ) .filter( ( pattern ) => pattern.inserter !== false ), diff --git a/packages/edit-site/src/components/welcome-guide/styles.js b/packages/edit-site/src/components/welcome-guide/styles.js index e6ec75ed7243f..03a3014b1b9fa 100644 --- a/packages/edit-site/src/components/welcome-guide/styles.js +++ b/packages/edit-site/src/components/welcome-guide/styles.js @@ -77,7 +77,7 @@ export default function WelcomeGuideStyles() {

    { __( - 'You can customize your site as much as you like with different colors, typography, and layouts. Or if you prefer, just leave it up to your theme to handle! ' + 'You can customize your site as much as you like with different colors, typography, and layouts. Or if you prefer, just leave it up to your theme to handle!' ) }

    @@ -117,7 +117,7 @@ export default function WelcomeGuideStyles() {

    { __( - 'New to block themes and styling your site? ' + 'New to block themes and styling your site?' ) } slug === currentTemplateSlug ); + )?.find( ( { slug } ) => slug === currentTemplateSlug ); if ( currentTemplate ) { template = currentTemplate; } else { diff --git a/packages/edit-site/src/utils/constants.js b/packages/edit-site/src/utils/constants.js index ed88c3e14c947..d12c7f84cc356 100644 --- a/packages/edit-site/src/utils/constants.js +++ b/packages/edit-site/src/utils/constants.js @@ -1,5 +1,40 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { privateApis as patternPrivateApis } from '@wordpress/patterns'; + +/** + * Internal dependencies + */ +import { unlock } from '../lock-unlock'; + +// Navigation +export const NAVIGATION_POST_TYPE = 'wp_navigation'; + +// Templates. +export const TEMPLATE_POST_TYPE = 'wp_template'; +export const TEMPLATE_PART_POST_TYPE = 'wp_template_part'; +export const TEMPLATE_CUSTOM_SOURCE = 'custom'; + +// Patterns. +export const { + PATTERN_TYPES, + PATTERN_DEFAULT_CATEGORY, + PATTERN_CORE_SOURCES, + PATTERN_SYNC_TYPES, +} = unlock( patternPrivateApis ); + +// Entities that are editable in focus mode. export const FOCUSABLE_ENTITIES = [ - 'wp_template_part', - 'wp_navigation', - 'wp_block', + TEMPLATE_PART_POST_TYPE, + NAVIGATION_POST_TYPE, + PATTERN_TYPES.user, ]; + +export const POST_TYPE_LABELS = { + [ TEMPLATE_POST_TYPE ]: __( 'Template' ), + [ TEMPLATE_PART_POST_TYPE ]: __( 'Template Part' ), + [ PATTERN_TYPES.user ]: __( 'Pattern' ), + [ NAVIGATION_POST_TYPE ]: __( 'Navigation' ), +}; diff --git a/packages/edit-site/src/utils/is-template-removable.js b/packages/edit-site/src/utils/is-template-removable.js index 7ec203a9e0db5..02682e97334e5 100644 --- a/packages/edit-site/src/utils/is-template-removable.js +++ b/packages/edit-site/src/utils/is-template-removable.js @@ -1,3 +1,8 @@ +/** + * Internal dependencies + */ +import { TEMPLATE_CUSTOM_SOURCE } from './constants'; + /** * Check if a template is removable. * @@ -9,5 +14,7 @@ export default function isTemplateRemovable( template ) { return false; } - return template.source === 'custom' && ! template.has_theme_file; + return ( + template.source === TEMPLATE_CUSTOM_SOURCE && ! template.has_theme_file + ); } diff --git a/packages/edit-site/src/utils/is-template-revertable.js b/packages/edit-site/src/utils/is-template-revertable.js index c2d42f51c9701..89d1d8ea552a1 100644 --- a/packages/edit-site/src/utils/is-template-revertable.js +++ b/packages/edit-site/src/utils/is-template-revertable.js @@ -1,3 +1,8 @@ +/** + * Internal dependencies + */ +import { TEMPLATE_CUSTOM_SOURCE } from './constants'; + /** * Check if a template is revertable to its original theme-provided template file. * @@ -9,6 +14,8 @@ export default function isTemplateRevertable( template ) { return false; } /* eslint-disable camelcase */ - return template?.source === 'custom' && template?.has_theme_file; + return ( + template?.source === TEMPLATE_CUSTOM_SOURCE && template?.has_theme_file + ); /* eslint-enable camelcase */ } diff --git a/packages/editor/src/components/provider/use-block-editor-settings.js b/packages/editor/src/components/provider/use-block-editor-settings.js index b430c3212556b..705374b727ea7 100644 --- a/packages/editor/src/components/provider/use-block-editor-settings.js +++ b/packages/editor/src/components/provider/use-block-editor-settings.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { Platform, useMemo } from '@wordpress/element'; +import { Platform, useMemo, useCallback } from '@wordpress/element'; import { useDispatch, useSelect } from '@wordpress/data'; import { store as coreStore, @@ -182,14 +182,19 @@ function useBlockEditorSettings( settings, hasTemplate ) { * @param {Object} options parameters for the post being created. These mirror those used on 3rd param of saveEntityRecord. * @return {Object} the post type object that was created. */ - const createPageEntity = ( options ) => { - if ( ! userCanCreatePages ) { - return Promise.reject( { - message: __( 'You do not have permission to create Pages.' ), - } ); - } - return saveEntityRecord( 'postType', 'page', options ); - }; + const createPageEntity = useCallback( + ( options ) => { + if ( ! userCanCreatePages ) { + return Promise.reject( { + message: __( + 'You do not have permission to create Pages.' + ), + } ); + } + return saveEntityRecord( 'postType', 'page', options ); + }, + [ saveEntityRecord, userCanCreatePages ] + ); return useMemo( () => ( { diff --git a/packages/env/lib/download-sources.js b/packages/env/lib/download-sources.js index aec47f23203d1..45c65fe715de4 100644 --- a/packages/env/lib/download-sources.js +++ b/packages/env/lib/download-sources.js @@ -176,7 +176,7 @@ async function downloadZipSource( source, { onProgress, spinner, debug } ) { rimraf( source.path ), fs.promises.readdir( tempDir ), ] ) - )[ 2 ]; + )[ 2 ]; /** * The plugin container is the extracted directory which is the direct parent diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index e7ffc1345957b..a5b8cbc05f26a 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -7,9 +7,10 @@ - The bundled `@typescript-eslint/parser` and `@typescript-eslint/eslint-plugin` dependencies has been updated from requiring ^5.62.0 to requiring ^6.4.1 ([#53975](https://github.com/WordPress/gutenberg/pull/53975)): - Removes the deprecated `@typescript-eslint/no-duplicate-imports` rule in favor of `import/no-duplicates`. -### Enhancement +### Enhancements - Added a new `test-playwright` ruleset using [`eslint-plugin-playwright`](https://www.npmjs.com/package/eslint-plugin-playwright). +- The bundled `eslint-plugin-prettier` dependency has been updated from requiring `^3.3.0` to requiring `^5.0.0` ([#54539](https://github.com/WordPress/gutenberg/pull/54539)). ## 15.1.0 (2023-08-31) diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index a354b04626f55..473e6cf9269c4 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -43,7 +43,7 @@ "eslint-plugin-jsdoc": "^46.4.6", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-playwright": "^0.15.3", - "eslint-plugin-prettier": "^3.3.0", + "eslint-plugin-prettier": "^5.0.0", "eslint-plugin-react": "^7.27.0", "eslint-plugin-react-hooks": "^4.3.0", "globals": "^13.12.0", diff --git a/packages/icons/CHANGELOG.md b/packages/icons/CHANGELOG.md index 3c1715455ad49..ec07610cee52d 100644 --- a/packages/icons/CHANGELOG.md +++ b/packages/icons/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Enhancement + +- `` now forwards ref to the underlying child component ([#54492](https://github.com/WordPress/gutenberg/pull/54492)). + ## 9.32.0 (2023-08-31) ### Bug Fix diff --git a/packages/icons/src/icon/index.js b/packages/icons/src/icon/index.js index e8bd1477dcd02..c83a5179a41b8 100644 --- a/packages/icons/src/icon/index.js +++ b/packages/icons/src/icon/index.js @@ -1,25 +1,27 @@ /** * WordPress dependencies */ -import { cloneElement } from '@wordpress/element'; +import { cloneElement, forwardRef } from '@wordpress/element'; /** @typedef {{icon: JSX.Element, size?: number} & import('@wordpress/primitives').SVGProps} IconProps */ /** * Return an SVG icon. * - * @param {IconProps} props icon is the SVG component to render - * size is a number specifiying the icon size in pixels - * Other props will be passed to wrapped SVG component + * @param {IconProps} props icon is the SVG component to render + * size is a number specifiying the icon size in pixels + * Other props will be passed to wrapped SVG component + * @param {import('react').ForwardedRef} ref The forwarded ref to the SVG element. * * @return {JSX.Element} Icon component */ -function Icon( { icon, size = 24, ...props } ) { +function Icon( { icon, size = 24, ...props }, ref ) { return cloneElement( icon, { width: size, height: size, ...props, + ref, } ); } -export default Icon; +export default forwardRef( Icon ); diff --git a/packages/icons/src/library/settings.js b/packages/icons/src/library/settings.js index 31d6da68a7195..cc1593cf489d3 100644 --- a/packages/icons/src/library/settings.js +++ b/packages/icons/src/library/settings.js @@ -5,7 +5,8 @@ import { SVG, Path } from '@wordpress/primitives'; const settings = ( - + + ); diff --git a/packages/icons/src/library/sides-all.js b/packages/icons/src/library/sides-all.js index d6e027685640a..31717e244aadf 100644 --- a/packages/icons/src/library/sides-all.js +++ b/packages/icons/src/library/sides-all.js @@ -5,10 +5,7 @@ import { SVG, Path } from '@wordpress/primitives'; const sidesAll = ( - + ); diff --git a/packages/icons/src/library/sides-bottom.js b/packages/icons/src/library/sides-bottom.js index d1615ebc2a93b..48cd1516e7c16 100644 --- a/packages/icons/src/library/sides-bottom.js +++ b/packages/icons/src/library/sides-bottom.js @@ -5,11 +5,11 @@ import { SVG, Path } from '@wordpress/primitives'; const sidesBottom = ( - + ); diff --git a/packages/icons/src/library/sides-horizontal.js b/packages/icons/src/library/sides-horizontal.js index 87402487689e3..05509ef8dc2b5 100644 --- a/packages/icons/src/library/sides-horizontal.js +++ b/packages/icons/src/library/sides-horizontal.js @@ -6,13 +6,11 @@ import { SVG, Path } from '@wordpress/primitives'; const sidesHorizontal = ( - + + ); diff --git a/packages/icons/src/library/sides-left.js b/packages/icons/src/library/sides-left.js index ff2189f76a0dc..39a917e7d05b0 100644 --- a/packages/icons/src/library/sides-left.js +++ b/packages/icons/src/library/sides-left.js @@ -5,11 +5,11 @@ import { SVG, Path } from '@wordpress/primitives'; const sidesLeft = ( - + ); diff --git a/packages/icons/src/library/sides-right.js b/packages/icons/src/library/sides-right.js index 1abb83ad1bb68..b21e0668aeb55 100644 --- a/packages/icons/src/library/sides-right.js +++ b/packages/icons/src/library/sides-right.js @@ -5,11 +5,11 @@ import { SVG, Path } from '@wordpress/primitives'; const sidesRight = ( - + ); diff --git a/packages/icons/src/library/sides-top.js b/packages/icons/src/library/sides-top.js index 8519397ffd63e..f416a4c235f3b 100644 --- a/packages/icons/src/library/sides-top.js +++ b/packages/icons/src/library/sides-top.js @@ -6,10 +6,10 @@ import { SVG, Path } from '@wordpress/primitives'; const sidesTop = ( - + ); diff --git a/packages/icons/src/library/sides-vertical.js b/packages/icons/src/library/sides-vertical.js index 09306cf72549a..5352dffd4e50b 100644 --- a/packages/icons/src/library/sides-vertical.js +++ b/packages/icons/src/library/sides-vertical.js @@ -6,13 +6,11 @@ import { SVG, Path } from '@wordpress/primitives'; const sidesVertical = ( - + + ); diff --git a/packages/lazy-import/README.md b/packages/lazy-import/README.md index af19716c2ebc1..cd3dcb16eb6ab 100644 --- a/packages/lazy-import/README.md +++ b/packages/lazy-import/README.md @@ -55,7 +55,7 @@ function onInstall() { lazyImport( 'fbjs@^1.0.0', { localPath: './lib/shallowEqual', onInstall, -} ).then(/* ... */); +} ).then( /* ... */ ); ``` Note that `lazyImport` can throw an error when offline and unable to install the dependency using NPM. You may want to anticipate this and provide remediation steps for a failed install, such as logging a warning messsage: diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index 2b8d89cbfae36..44f08f53ba876 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -14,12 +14,10 @@ import { useState, useCallback } from '@wordpress/element'; import { useDispatch } from '@wordpress/data'; import { store as noticesStore } from '@wordpress/notices'; -export const ALL_PATTERNS_CATEGORY = 'all-patterns'; - -export const SYNC_TYPES = { - full: undefined, - unsynced: 'unsynced', -}; +/** + * Internal dependencies + */ +import { PATTERN_DEFAULT_CATEGORY, PATTERN_SYNC_TYPES } from '../constants'; /** * Internal dependencies @@ -34,7 +32,7 @@ export default function CreatePatternModal( { onClose, className = 'patterns-menu-items__convert-modal', } ) { - const [ syncType, setSyncType ] = useState( SYNC_TYPES.full ); + const [ syncType, setSyncType ] = useState( PATTERN_SYNC_TYPES.full ); const [ categories, setCategories ] = useState( [] ); const [ title, setTitle ] = useState( '' ); const { createPattern } = useDispatch( store ); @@ -51,7 +49,7 @@ export default function CreatePatternModal( { ); onSuccess( { pattern: newPattern, - categoryId: ALL_PATTERNS_CATEGORY, + categoryId: PATTERN_DEFAULT_CATEGORY, } ); } catch ( error ) { createErrorNotice( error.message, { @@ -108,12 +106,12 @@ export default function CreatePatternModal( { help={ __( 'Editing the pattern will update it anywhere it is used.' ) } - checked={ ! syncType } + checked={ syncType === PATTERN_SYNC_TYPES.full } onChange={ () => { setSyncType( - syncType === SYNC_TYPES.full - ? SYNC_TYPES.unsynced - : SYNC_TYPES.full + syncType === PATTERN_SYNC_TYPES.full + ? PATTERN_SYNC_TYPES.unsynced + : PATTERN_SYNC_TYPES.full ); } } /> diff --git a/packages/patterns/src/constants.js b/packages/patterns/src/constants.js new file mode 100644 index 0000000000000..ecf7c7ddb3740 --- /dev/null +++ b/packages/patterns/src/constants.js @@ -0,0 +1,16 @@ +export const PATTERN_TYPES = { + theme: 'pattern', + user: 'wp_block', +}; + +export const PATTERN_DEFAULT_CATEGORY = 'all-patterns'; +export const PATTERN_CORE_SOURCES = [ + 'core', + 'pattern-directory/core', + 'pattern-directory/featured', + 'pattern-directory/theme', +]; +export const PATTERN_SYNC_TYPES = { + full: 'fully', + unsynced: 'unsynced', +}; diff --git a/packages/patterns/src/private-apis.js b/packages/patterns/src/private-apis.js index 31f507c2b9914..306476efc3121 100644 --- a/packages/patterns/src/private-apis.js +++ b/packages/patterns/src/private-apis.js @@ -4,9 +4,19 @@ import { lock } from './lock-unlock'; import CreatePatternModal from './components/create-pattern-modal'; import PatternsMenuItems from './components'; +import { + PATTERN_TYPES, + PATTERN_DEFAULT_CATEGORY, + PATTERN_CORE_SOURCES, + PATTERN_SYNC_TYPES, +} from './constants'; export const privateApis = {}; lock( privateApis, { CreatePatternModal, PatternsMenuItems, + PATTERN_TYPES, + PATTERN_DEFAULT_CATEGORY, + PATTERN_CORE_SOURCES, + PATTERN_SYNC_TYPES, } ); diff --git a/packages/patterns/src/store/actions.js b/packages/patterns/src/store/actions.js index 07680757762c3..589dad326d3b6 100644 --- a/packages/patterns/src/store/actions.js +++ b/packages/patterns/src/store/actions.js @@ -6,6 +6,11 @@ import { parse, serialize, createBlock } from '@wordpress/blocks'; import { store as coreStore } from '@wordpress/core-data'; import { store as blockEditorStore } from '@wordpress/block-editor'; +/** + * Internal dependencies + */ +import { PATTERN_SYNC_TYPES } from '../constants'; + /** * Returns a generator converting one or more static blocks into a pattern, or creating a new empty pattern. * @@ -18,7 +23,7 @@ export const createPattern = ( title, syncType, clientIds, categories ) => async ( { registry, dispatch } ) => { const meta = - syncType === 'unsynced' + syncType === PATTERN_SYNC_TYPES.unsynced ? { wp_pattern_sync_status: syncType, } diff --git a/packages/primitives/CHANGELOG.md b/packages/primitives/CHANGELOG.md index 6beb37c1b9dd8..a762a52ffbf97 100644 --- a/packages/primitives/CHANGELOG.md +++ b/packages/primitives/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Enhancement + +- `` now forwards ref to the underlying `` element ([#54492](https://github.com/WordPress/gutenberg/pull/54492)). + ## 3.39.0 (2023-08-31) ## 3.38.0 (2023-08-16) diff --git a/packages/primitives/src/svg/index.js b/packages/primitives/src/svg/index.js index 79a5e7f58e55d..420432d0543e1 100644 --- a/packages/primitives/src/svg/index.js +++ b/packages/primitives/src/svg/index.js @@ -6,7 +6,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { createElement } from '@wordpress/element'; +import { createElement, forwardRef } from '@wordpress/element'; /** @typedef {{isPressed?: boolean} & import('react').ComponentPropsWithoutRef<'svg'>} SVGProps */ @@ -82,23 +82,27 @@ export const LinearGradient = ( props ) => */ export const Stop = ( props ) => createElement( 'stop', props ); -/** - * - * @param {SVGProps} props isPressed indicates whether the SVG should appear as pressed. - * Other props will be passed through to svg component. - * - * @return {JSX.Element} Stop component - */ -export const SVG = ( { className, isPressed, ...props } ) => { - const appliedProps = { - ...props, - className: - classnames( className, { 'is-pressed': isPressed } ) || undefined, - 'aria-hidden': true, - focusable: false, - }; +export const SVG = forwardRef( + /** + * @param {SVGProps} props isPressed indicates whether the SVG should appear as pressed. + * Other props will be passed through to svg component. + * @param {import('react').ForwardedRef} ref The forwarded ref to the SVG element. + * + * @return {JSX.Element} Stop component + */ + ( { className, isPressed, ...props }, ref ) => { + const appliedProps = { + ...props, + className: + classnames( className, { 'is-pressed': isPressed } ) || + undefined, + 'aria-hidden': true, + focusable: false, + }; - // Disable reason: We need to have a way to render HTML tag for web. - // eslint-disable-next-line react/forbid-elements - return ; -}; + // Disable reason: We need to have a way to render HTML tag for web. + // eslint-disable-next-line react/forbid-elements + return ; + } +); +SVG.displayName = 'SVG'; diff --git a/packages/react-native-editor/__device-tests__/helpers/utils.js b/packages/react-native-editor/__device-tests__/helpers/utils.js index 64fb2ed510a45..9fb43452dcffc 100644 --- a/packages/react-native-editor/__device-tests__/helpers/utils.js +++ b/packages/react-native-editor/__device-tests__/helpers/utils.js @@ -526,9 +526,8 @@ const dragAndDropAfterElement = async ( driver, element, nextElement ) => { const toggleHtmlMode = async ( driver, toggleOn ) => { if ( isAndroid() ) { - const moreOptionsButton = await driver.elementByAccessibilityId( - 'More options' - ); + const moreOptionsButton = + await driver.elementByAccessibilityId( 'More options' ); await moreOptionsButton.click(); const showHtmlButtonXpath = @@ -536,9 +535,8 @@ const toggleHtmlMode = async ( driver, toggleOn ) => { await clickIfClickable( driver, showHtmlButtonXpath ); } else if ( toggleOn ) { - const moreOptionsButton = await driver.elementByAccessibilityId( - 'editor-menu-button' - ); + const moreOptionsButton = + await driver.elementByAccessibilityId( 'editor-menu-button' ); await moreOptionsButton.click(); await clickIfClickable( @@ -548,9 +546,8 @@ const toggleHtmlMode = async ( driver, toggleOn ) => { } else { // This is to wait for the clipboard paste notification to disappear, currently it overlaps with the menu button await driver.sleep( 3000 ); - const moreOptionsButton = await driver.elementByAccessibilityId( - 'editor-menu-button' - ); + const moreOptionsButton = + await driver.elementByAccessibilityId( 'editor-menu-button' ); await moreOptionsButton.click(); await clickIfClickable( driver, diff --git a/packages/react-native-editor/__device-tests__/pages/editor-page.js b/packages/react-native-editor/__device-tests__/pages/editor-page.js index 8e2bc02d657b9..65446ca4b5dda 100644 --- a/packages/react-native-editor/__device-tests__/pages/editor-page.js +++ b/packages/react-native-editor/__device-tests__/pages/editor-page.js @@ -57,9 +57,8 @@ class EditorPage { await launchApp( this.driver, { initialData } ); // Stores initial values from the editor for different helpers. - const addButton = await this.driver.elementsByAccessibilityId( - ADD_BLOCK_ID - ); + const addButton = + await this.driver.elementsByAccessibilityId( ADD_BLOCK_ID ); if ( addButton.length !== 0 ) { this.initialValues.addButtonLocation = @@ -74,9 +73,8 @@ class EditorPage { } async getAddBlockButton() { - const elements = await this.driver.elementsByAccessibilityId( - ADD_BLOCK_ID - ); + const elements = + await this.driver.elementsByAccessibilityId( ADD_BLOCK_ID ); return elements[ 0 ]; } @@ -197,9 +195,8 @@ class EditorPage { await swipeDown( this.driver ); } - const elements = await this.driver.elementsByAccessibilityId( - titleElement - ); + const elements = + await this.driver.elementsByAccessibilityId( titleElement ); if ( elements.length === 0 || @@ -530,9 +527,8 @@ class EditorPage { } async clickToolBarButton( buttonName ) { - const toolBarButton = await this.driver.elementByAccessibilityId( - buttonName - ); + const toolBarButton = + await this.driver.elementByAccessibilityId( buttonName ); await toolBarButton.click(); } @@ -540,9 +536,8 @@ class EditorPage { let navigateUpElements = []; do { await this.driver.sleep( 2000 ); - navigateUpElements = await this.driver.elementsByAccessibilityId( - 'Navigate Up' - ); + navigateUpElements = + await this.driver.elementsByAccessibilityId( 'Navigate Up' ); if ( navigateUpElements.length > 0 ) { await navigateUpElements[ 0 ].click(); } @@ -784,9 +779,8 @@ class EditorPage { this.driver, '//XCUIElementTypeOther[@name="Media Add image or video"]' ); - const addMediaButton = await mediaSection.elementByAccessibilityId( - 'Add image or video' - ); + const addMediaButton = + await mediaSection.elementByAccessibilityId( 'Add image or video' ); await addMediaButton.click(); } @@ -810,9 +804,8 @@ class EditorPage { this.accessibilityIdKey ); const blockLocator = `//*[@${ this.accessibilityIdXPathAttrib }="${ accessibilityId }"]//XCUIElementTypeButton[@name="Image block. Empty"]`; - const imageBlockInnerElement = await this.driver.elementByXPath( - blockLocator - ); + const imageBlockInnerElement = + await this.driver.elementByXPath( blockLocator ); await imageBlockInnerElement.click(); } diff --git a/packages/rich-text/src/component/use-copy-handler.js b/packages/rich-text/src/component/use-copy-handler.js index c62d83351971c..3be5935443215 100644 --- a/packages/rich-text/src/component/use-copy-handler.js +++ b/packages/rich-text/src/component/use-copy-handler.js @@ -28,17 +28,10 @@ export function useCopyHandler( props ) { const selectedRecord = slice( record.current ); const plainText = getTextContent( selectedRecord ); - const tagName = element.tagName.toLowerCase(); - - let html = toHTMLString( { + const html = toHTMLString( { value: selectedRecord, preserveWhiteSpace, } ); - - if ( tagName && tagName !== 'span' && tagName !== 'div' ) { - html = `<${ tagName }>${ html }`; - } - event.clipboardData.setData( 'text/plain', plainText ); event.clipboardData.setData( 'text/html', html ); event.clipboardData.setData( 'rich-text', 'true' ); diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index acf24a423c0af..2c507e288f1c2 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -2,9 +2,10 @@ ## Unreleased -### Enhancement +### Enhancements - Added support for `test-playwright` script ([#53108](https://github.com/WordPress/gutenberg/pull/53108)). +- The bundled `wp-prettier` dependency has been upgraded from `2.8.5` to `3.0.3` ([#54539](https://github.com/WordPress/gutenberg/pull/54539)). ### Bug Fix diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 12ca7854da191..b5af25a0eb1cf 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -75,7 +75,7 @@ "playwright-core": "1.32.0", "postcss": "^8.4.5", "postcss-loader": "^6.2.1", - "prettier": "npm:wp-prettier@2.8.5", + "prettier": "npm:wp-prettier@3.0.3-beta-3", "puppeteer-core": "^13.2.0", "react-refresh": "^0.10.0", "read-pkg-up": "^7.0.1", diff --git a/phpunit/style-engine/style-engine-test.php b/phpunit/style-engine/style-engine-test.php index 7e71deb0dbf96..6fb485e9a6f31 100644 --- a/phpunit/style-engine/style-engine-test.php +++ b/phpunit/style-engine/style-engine-test.php @@ -192,11 +192,12 @@ public function data_wp_style_engine_get_styles() { 'textDecoration' => 'underline', 'textTransform' => 'uppercase', 'letterSpacing' => '2', + 'writingMode' => 'vertical-rl', ), ), 'options' => null, 'expected_output' => array( - 'css' => 'font-size:clamp(2em, 2vw, 4em);font-family:Roboto,Oxygen-Sans,Ubuntu,sans-serif;font-style:italic;font-weight:800;line-height:1.3;column-count:2;text-decoration:underline;text-transform:uppercase;letter-spacing:2;', + 'css' => 'font-size:clamp(2em, 2vw, 4em);font-family:Roboto,Oxygen-Sans,Ubuntu,sans-serif;font-style:italic;font-weight:800;line-height:1.3;column-count:2;text-decoration:underline;text-transform:uppercase;letter-spacing:2;writing-mode:vertical-rl;', 'declarations' => array( 'font-size' => 'clamp(2em, 2vw, 4em)', 'font-family' => 'Roboto,Oxygen-Sans,Ubuntu,sans-serif', @@ -207,6 +208,7 @@ public function data_wp_style_engine_get_styles() { 'text-decoration' => 'underline', 'text-transform' => 'uppercase', 'letter-spacing' => '2', + 'writing-mode' => 'vertical-rl', ), ), ), diff --git a/platform-docs/docs/basic-concepts/internationalization.md b/platform-docs/docs/basic-concepts/internationalization.md index e4cfd4c757330..3b808bd71e61b 100644 --- a/platform-docs/docs/basic-concepts/internationalization.md +++ b/platform-docs/docs/basic-concepts/internationalization.md @@ -1,5 +1,5 @@ --- -sidebar_position: 5 +sidebar_position: 6 --- # Internationalization diff --git a/platform-docs/docs/basic-concepts/rendering.md b/platform-docs/docs/basic-concepts/rendering.md index e4a24b19ae3e5..f5458df2e81e7 100644 --- a/platform-docs/docs/basic-concepts/rendering.md +++ b/platform-docs/docs/basic-concepts/rendering.md @@ -1,5 +1,5 @@ --- -sidebar_position: 6 +sidebar_position: 7 --- # Rendering blocks diff --git a/platform-docs/docs/basic-concepts/rich-text.md b/platform-docs/docs/basic-concepts/rich-text.md index 349224aa9fbe3..e3517bc93203e 100644 --- a/platform-docs/docs/basic-concepts/rich-text.md +++ b/platform-docs/docs/basic-concepts/rich-text.md @@ -1,5 +1,5 @@ --- -sidebar_position: 4 +sidebar_position: 5 --- # RichText and Format Library diff --git a/platform-docs/docs/basic-concepts/settings.md b/platform-docs/docs/basic-concepts/settings.md index 3e68f712cecfe..66d0691aef5f7 100644 --- a/platform-docs/docs/basic-concepts/settings.md +++ b/platform-docs/docs/basic-concepts/settings.md @@ -1,5 +1,5 @@ --- -sidebar_position: 3 +sidebar_position: 4 --- # Block Editor Settings diff --git a/platform-docs/docs/basic-concepts/undo-redo.md b/platform-docs/docs/basic-concepts/undo-redo.md new file mode 100644 index 0000000000000..26981e6e0f5c1 --- /dev/null +++ b/platform-docs/docs/basic-concepts/undo-redo.md @@ -0,0 +1,67 @@ +--- +sidebar_position: 3 +--- + +# Undo Redo + +## Undo/Redo using `useStateWithHistory` + +By default, the block editor doesn't enable undo/redo. This is because in most scenarios, the block editor is rendered as part of a larger application that already has its own undo/redo functionality. However, to help you implement undo/redo in your application, the block editor provides a set of APIs that you can use. + +The simplest approach is to rely on the `useStateWithHistory` hook provided by the `@wordpress/compose` package. This hook is a wrapper around the `useState` hook that adds undo/redo functionality to the state. + +First, make sure you add the `@wordpress/compose` package to your dependencies, then use the hook like so: + +```jsx +import { useStateWithHistory } from '@wordpress/compose'; +import { createRoot, createElement, useState } from "@wordpress/element"; +import { + BlockEditorProvider, + BlockCanvas, +} from "@wordpress/block-editor"; + +function Editor() { + const { value, setValue, hasUndo, hasRedo, undo, redo } = + useStateWithHistory( { blocks: [] } ); + + return ( + + setValue( { blocks, selection }, true ) + } + onChange={ ( blocks, { selection } ) => + setValue( { blocks, selection }, false ) + } + > +

    + + +
    + + + ); +} +``` + +The `useStateWithHistory` hook returns an object with the following properties: + +- `value`: the current value of the state. +- `setValue`: a function that can be used to update the state. +- `hasUndo`: a boolean indicating whether there are any actions that can be undone. +- `hasRedo`: a boolean indicating whether there are any actions that can be redone. +- `undo`: a function that can be used to undo the last action. +- `redo`: a function that can be used to redo the last action. + +Notice that in addition to the `blocks` property, the `value` object also tracks a `selection` property. This property is used to store and control the cursor position within the block editor. This allows the editor to restore the right position when undoing or redoing changes. + +## Going Further... + +Oftentimes, editors allow to track changes across multiple objects and properties. For instance, a basic writing experience might allow editing the title of a post in a normal input and the content of the post in the block editor. Or your editor might allow edits to related objects like categories, tags, etc... In these cases, you might want to implement undo/redo functionality that can be used to track changes across all of these objects and properties. + +The `useStateWithHistory` might not always be the right approach in these situations. Consider checking the `@wordpress/undo-manager` package that offers a lower level undo manager that can be adapted more easily to your specific needs. diff --git a/schemas/json/theme.json b/schemas/json/theme.json index e0f3efc01eb1f..5a0b049f6d0d5 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -298,7 +298,6 @@ }, "settingsPropertiesLightbox": { "type": "object", - "additionalProperties": false, "properties": { "lightbox": { "description": "Settings related to the lightbox.", @@ -312,7 +311,8 @@ "description": "Defines whether to show the Lightbox UI in the block editor. If set to `false`, the user won't be able to change the lightbox settings in the block editor.", "type": "boolean" } - } + }, + "additionalProperties": false } } }, diff --git a/test/e2e/specs/editor/blocks/cover.spec.js b/test/e2e/specs/editor/blocks/cover.spec.js index e6042648b0e8d..98be7b8530409 100644 --- a/test/e2e/specs/editor/blocks/cover.spec.js +++ b/test/e2e/specs/editor/blocks/cover.spec.js @@ -40,9 +40,8 @@ test.describe( 'Cover', () => { await expect( blackColorSwatch ).toBeVisible(); // Get the RGB value of Black. - const [ blackRGB ] = await coverBlockUtils.getBackgroundColorAndOpacity( - coverBlock - ); + const [ blackRGB ] = + await coverBlockUtils.getBackgroundColorAndOpacity( coverBlock ); // Create the block by clicking selected color button. await blackColorSwatch.click(); diff --git a/test/e2e/specs/editor/blocks/image.spec.js b/test/e2e/specs/editor/blocks/image.spec.js index 6006d5976d98f..21ec3e2486c3a 100644 --- a/test/e2e/specs/editor/blocks/image.spec.js +++ b/test/e2e/specs/editor/blocks/image.spec.js @@ -853,9 +853,8 @@ test.describe.skip( 'Image - interactivity', () => { '.entry-content figure img' ); - const wpContext = await contentFigure.getAttribute( - 'data-wp-context' - ); + const wpContext = + await contentFigure.getAttribute( 'data-wp-context' ); const imageUploadedSrc = JSON.parse( wpContext ).core.image.imageUploadedSrc; diff --git a/test/e2e/specs/editor/blocks/navigation-list-view.spec.js b/test/e2e/specs/editor/blocks/navigation-list-view.spec.js index 77039281faded..6064ff394171b 100644 --- a/test/e2e/specs/editor/blocks/navigation-list-view.spec.js +++ b/test/e2e/specs/editor/blocks/navigation-list-view.spec.js @@ -140,9 +140,8 @@ test.describe( 'Navigation block - List view editing', () => { requestUtils, linkControl, } ) => { - const { id: menuId } = await requestUtils.createNavigationMenu( - navMenuBlocksFixture - ); + const { id: menuId } = + await requestUtils.createNavigationMenu( navMenuBlocksFixture ); // Insert x2 blocks as a stress test as several bugs have been found with inserting // blocks into the navigation block when there are multiple blocks referencing the @@ -213,9 +212,8 @@ test.describe( 'Navigation block - List view editing', () => { const firstResult = await linkControl.getNthSearchResult( 0 ); // Grab the text from the first result so we can check (later on) that it was inserted. - const firstResultText = await linkControl.getSearchResultText( - firstResult - ); + const firstResultText = + await linkControl.getSearchResultText( firstResult ); // Create the link. await firstResult.click(); @@ -454,9 +452,8 @@ test.describe( 'Navigation block - List view editing', () => { // inserted block even if the block had been deselected and then reselected. // See: https://github.com/WordPress/gutenberg/issues/50601 - const { id: menuId } = await requestUtils.createNavigationMenu( - navMenuBlocksFixture - ); + const { id: menuId } = + await requestUtils.createNavigationMenu( navMenuBlocksFixture ); // Insert x2 blocks as a stress test as several bugs have been found with inserting // blocks into the navigation block when there are multiple blocks referencing the diff --git a/test/e2e/specs/editor/blocks/paragraph.spec.js b/test/e2e/specs/editor/blocks/paragraph.spec.js index 1c35f6ddc8958..fa42fa59a09ed 100644 --- a/test/e2e/specs/editor/blocks/paragraph.spec.js +++ b/test/e2e/specs/editor/blocks/paragraph.spec.js @@ -78,9 +78,8 @@ test.describe( 'Paragraph', () => { testImageName ); - const { dragOver, drop } = await pageUtils.dragFiles( - testImagePath - ); + const { dragOver, drop } = + await pageUtils.dragFiles( testImagePath ); await dragOver( editor.canvas.locator( '[data-type="core/paragraph"]' ) diff --git a/test/e2e/specs/editor/various/draggable-blocks.spec.js b/test/e2e/specs/editor/various/draggable-blocks.spec.js index a66efe4540f38..cd5fa12fca6f4 100644 --- a/test/e2e/specs/editor/various/draggable-blocks.spec.js +++ b/test/e2e/specs/editor/various/draggable-blocks.spec.js @@ -394,9 +394,8 @@ test.describe( 'Draggable block', () => { ); { - const { dragOver, drop } = await pageUtils.dragFiles( - testImagePath - ); + const { dragOver, drop } = + await pageUtils.dragFiles( testImagePath ); const rowBlock = editor.canvas.getByRole( 'document', { name: 'Block: Row', @@ -434,9 +433,8 @@ test.describe( 'Draggable block', () => { } { - const { dragOver, drop } = await pageUtils.dragFiles( - testImagePath - ); + const { dragOver, drop } = + await pageUtils.dragFiles( testImagePath ); const columnAppender = editor.canvas .getByRole( 'document', { diff --git a/test/e2e/specs/editor/various/rich-text.spec.js b/test/e2e/specs/editor/various/rich-text.spec.js index d39264eccc1ea..4ebd2cd450e70 100644 --- a/test/e2e/specs/editor/various/rich-text.spec.js +++ b/test/e2e/specs/editor/various/rich-text.spec.js @@ -656,11 +656,7 @@ test.describe( 'RichText', () => { innerBlocks: [ { name: 'core/list-item', - attributes: { content: '1' }, - }, - { - name: 'core/list-item', - attributes: { content: '2' }, + attributes: { content: '1
    2' }, }, ], }, @@ -802,25 +798,4 @@ test.describe( 'RichText', () => { }, ] ); } ); - - test( 'should copy/paste heading', async ( { - page, - editor, - pageUtils, - } ) => { - await editor.insertBlock( { name: 'core/heading' } ); - await page.keyboard.type( 'Heading' ); - await pageUtils.pressKeys( 'primary+a' ); - await pageUtils.pressKeys( 'primary+c' ); - await page.keyboard.press( 'ArrowRight' ); - await page.keyboard.press( 'Enter' ); - await pageUtils.pressKeys( 'primary+v' ); - - expect( await editor.getBlocks() ).toMatchObject( - Array( 2 ).fill( { - name: 'core/heading', - attributes: { content: 'Heading' }, - } ) - ); - } ); } ); diff --git a/test/e2e/specs/interactivity/directive-bind.spec.ts b/test/e2e/specs/interactivity/directive-bind.spec.ts index 401bbcd6b24dd..525fceab5ca6a 100644 --- a/test/e2e/specs/interactivity/directive-bind.spec.ts +++ b/test/e2e/specs/interactivity/directive-bind.spec.ts @@ -126,7 +126,7 @@ test.describe( 'data-wp-bind', () => { * Value that the HTMLElement instance property should * contain after hydration. */ - entityPropValue: any + entityPropValue: any, ] >; }; diff --git a/test/e2e/specs/widgets/customizing-widgets.spec.js b/test/e2e/specs/widgets/customizing-widgets.spec.js index 8b2a585dc4e66..d51d5cffbebb2 100644 --- a/test/e2e/specs/widgets/customizing-widgets.spec.js +++ b/test/e2e/specs/widgets/customizing-widgets.spec.js @@ -352,9 +352,8 @@ test.describe( 'Widgets Customizer', () => { await widgetsCustomizerPage.visitCustomizerPage(); await widgetsCustomizerPage.expandWidgetArea( 'Footer #1' ); - const legacyWidgetBlock = await widgetsCustomizerPage.addBlock( - 'Legacy Widget' - ); + const legacyWidgetBlock = + await widgetsCustomizerPage.addBlock( 'Legacy Widget' ); await page .locator( 'role=combobox[name="Select a legacy widget to display:"i]' @@ -401,9 +400,8 @@ test.describe( 'Widgets Customizer', () => { await page.click( 'role=menuitem[name=/Delete/]' ); // Add it back again using the variant. - const testWidgetBlock = await widgetsCustomizerPage.addBlock( - 'Test Widget' - ); + const testWidgetBlock = + await widgetsCustomizerPage.addBlock( 'Test Widget' ); titleInput = testWidgetBlock.locator( 'role=textbox[name="Title:"i]' ); diff --git a/test/integration/blocks-raw-handling.test.js b/test/integration/blocks-raw-handling.test.js index 733ae308c851a..2a31d0b0ceaa2 100644 --- a/test/integration/blocks-raw-handling.test.js +++ b/test/integration/blocks-raw-handling.test.js @@ -291,11 +291,9 @@ describe( 'Blocks raw handling', () => { HTML: '

    FOO

    ', plainText: 'FOO\n', mode: 'AUTO', - } ) - .map( getBlockContent ) - .join( '' ); + } ); - expect( filtered ).toBe( '

    FOO

    ' ); + expect( filtered ).toBe( 'FOO' ); expect( console ).toHaveLogged(); } ); diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v8-deprecate-behaviors-lightbox.html b/test/integration/fixtures/blocks/core__image__deprecated-v8-deprecate-behaviors-lightbox.html index 9feeb105951da..3cdb772864b4d 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v8-deprecate-behaviors-lightbox.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v8-deprecate-behaviors-lightbox.html @@ -1,3 +1,3 @@ - +
    diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v8-deprecate-behaviors-lightbox.json b/test/integration/fixtures/blocks/core__image__deprecated-v8-deprecate-behaviors-lightbox.json index a32f031dd34f4..73a483d911a78 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v8-deprecate-behaviors-lightbox.json +++ b/test/integration/fixtures/blocks/core__image__deprecated-v8-deprecate-behaviors-lightbox.json @@ -6,12 +6,12 @@ "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "", "caption": "", - "lightbox": { - "enabled": true - }, "id": 8, "sizeSlug": "large", - "linkDestination": "none" + "linkDestination": "none", + "lightbox": { + "enabled": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v8-deprecate-behaviors-lightbox.parsed.json b/test/integration/fixtures/blocks/core__image__deprecated-v8-deprecate-behaviors-lightbox.parsed.json index 0ca652ff77f83..a582b93cab43b 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v8-deprecate-behaviors-lightbox.parsed.json +++ b/test/integration/fixtures/blocks/core__image__deprecated-v8-deprecate-behaviors-lightbox.parsed.json @@ -2,8 +2,11 @@ { "blockName": "core/image", "attrs": { - "lightbox": { - "enabled": true + "behaviors": { + "lightbox": { + "enabled": true, + "animation": "fade" + } }, "id": 8, "sizeSlug": "large",