diff --git a/.github/workflows/php-changes-detection.yml b/.github/workflows/php-changes-detection.yml index 2eeaea561eb7e..d003d149a9a09 100644 --- a/.github/workflows/php-changes-detection.yml +++ b/.github/workflows/php-changes-detection.yml @@ -54,7 +54,7 @@ jobs: This pull request has changed or added PHP files. Please confirm whether these changes need to be synced to WordPress Core, and therefore featured in the next release of WordPress. - If so, it is recommended to create a [new Trac ticket](https://core.trac.wordpress.org/newticket) and submit a pull request to the [WordPress Core Github repository](https://github.com/WordPress/wordpress-develop) soon after this pull request is merged. + If so, it is recommended to create a [new Trac ticket](https://core.trac.wordpress.org/newticket) and submit a pull request to the [WordPress Core GitHub repository](https://github.com/WordPress/wordpress-develop) soon after this pull request is merged. If you're unsure, you can always ask for help in the #core-editor channel in [WordPress Slack](https://make.wordpress.org/chat/). @@ -76,7 +76,7 @@ jobs: This pull request has changed or added PHP files. Please confirm whether these changes need to be synced to WordPress Core, and therefore featured in the next release of WordPress. - If so, it is recommended to create a [new Trac ticket](https://core.trac.wordpress.org/newticket) and submit a pull request to the [WordPress Core Github repository](https://github.com/WordPress/wordpress-develop) soon after this pull request is merged. + If so, it is recommended to create a [new Trac ticket](https://core.trac.wordpress.org/newticket) and submit a pull request to the [WordPress Core GitHub repository](https://github.com/WordPress/wordpress-develop) soon after this pull request is merged. If you're unsure, you can always ask for help in the #core-editor channel in [WordPress Slack](https://make.wordpress.org/chat/). diff --git a/.github/workflows/upload-release-to-plugin-repo.yml b/.github/workflows/upload-release-to-plugin-repo.yml index 60ecacb2a8d70..9bb40a3f06cbc 100644 --- a/.github/workflows/upload-release-to-plugin-repo.yml +++ b/.github/workflows/upload-release-to-plugin-repo.yml @@ -51,7 +51,7 @@ jobs: return $? } - # Only update trunk *if* the published release's version in Github is GREATER + # Only update trunk *if* the published release's version in GitHub is GREATER # than the version currently published in the WP plugins repo. If not, then it # will upload it as a new tag. shouldUpdateTrunk=false diff --git a/backport-changelog/6.6/6785.md b/backport-changelog/6.6/6785.md new file mode 100644 index 0000000000000..ad26227bf1256 --- /dev/null +++ b/backport-changelog/6.6/6785.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6785 + +* https://github.com/WordPress/gutenberg/pull/62459 diff --git a/backport-changelog/6.6/6797.md b/backport-changelog/6.6/6797.md new file mode 100644 index 0000000000000..630b677655ddc --- /dev/null +++ b/backport-changelog/6.6/6797.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6797 + +* https://github.com/WordPress/gutenberg/pull/62526 \ No newline at end of file diff --git a/backport-changelog/6.6/6824.md b/backport-changelog/6.6/6824.md new file mode 100644 index 0000000000000..7dc6e090f0149 --- /dev/null +++ b/backport-changelog/6.6/6824.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6824 + +* https://github.com/WordPress/gutenberg/pull/62550 diff --git a/backport-changelog/6.6/6825.md b/backport-changelog/6.6/6825.md new file mode 100644 index 0000000000000..73e5f46600d89 --- /dev/null +++ b/backport-changelog/6.6/6825.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6825 + +* https://github.com/WordPress/gutenberg/pull/62552 diff --git a/backport-changelog/6.7/6750.md b/backport-changelog/6.7/6750.md new file mode 100644 index 0000000000000..257ebe3a5aa69 --- /dev/null +++ b/backport-changelog/6.7/6750.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6750 + +* https://github.com/WordPress/gutenberg/pull/62357 \ No newline at end of file diff --git a/bin/cherry-pick.mjs b/bin/cherry-pick.mjs index d81bc017fc0be..e6b2b6f0692a5 100644 --- a/bin/cherry-pick.mjs +++ b/bin/cherry-pick.mjs @@ -466,7 +466,7 @@ function getCurrentBranch() { */ async function reportGhUnavailable() { console.log( - 'Github CLI is not setup. This script will not be able to automatically' + 'GitHub CLI is not setup. This script will not be able to automatically' ); console.log( 'comment on the processed PRs and remove the backport label from them.' diff --git a/bin/packages/build-worker.js b/bin/packages/build-worker.js index 3f1512ef0feb7..06e30efc6c6dc 100644 --- a/bin/packages/build-worker.js +++ b/bin/packages/build-worker.js @@ -13,6 +13,8 @@ const postcss = require( 'postcss' ); */ const getBabelConfig = require( './get-babel-config' ); +const isDev = process.env.NODE_ENV === 'development'; + /** * Path to packages directory. * @@ -27,10 +29,12 @@ const PACKAGES_DIR = path * * @type {Object} */ -const JS_ENVIRONMENTS = { - main: 'build', - module: 'build-module', -}; +const JS_ENVIRONMENTS = isDev + ? { module: 'build-module' } + : { + main: 'build', + module: 'build-module', + }; /** * Promisified fs.readFile. @@ -122,9 +126,10 @@ async function buildCSS( file ) { data: ''.concat( '@use "sass:math";', importLists, contents ), } ); - const result = await postcss( - require( '@wordpress/postcss-plugins-preset' ) - ).process( builtSass.css, { + const result = await postcss( [ + require( 'postcss-local-keyframes' ), + ...require( '@wordpress/postcss-plugins-preset' ), + ] ).process( builtSass.css, { from: 'src/app.css', to: 'dest/app.css', } ); diff --git a/bin/packages/check-build-type-declaration-files.js b/bin/packages/check-build-type-declaration-files.js index 3d70145ceb588..ffc68c83b8da8 100644 --- a/bin/packages/check-build-type-declaration-files.js +++ b/bin/packages/check-build-type-declaration-files.js @@ -70,7 +70,7 @@ async function getDecFile( packagePath ) { async function typecheckDeclarations( file ) { return new Promise( ( resolve, reject ) => { exec( - `npx tsc --target esnext --moduleResolution node --noEmit "${ file }"`, + `npx tsc --target esnext --moduleResolution node --noEmit --skipLibCheck "${ file }"`, ( error, stdout, stderr ) => { if ( error ) { reject( { file, error, stderr, stdout } ); diff --git a/bin/plugin/commands/changelog.js b/bin/plugin/commands/changelog.js index 652c6e97a6c0a..43164a80ab24a 100644 --- a/bin/plugin/commands/changelog.js +++ b/bin/plugin/commands/changelog.js @@ -606,11 +606,11 @@ function getEntry( issue ) { /** * Builds a formatted string of the Issue/PR title with a link - * to the Github URL for that item. + * to the GitHub URL for that item. * * @param {string} title the title of the Issue/PR. * @param {number} number the ID/number of the Issue/PR. - * @param {string} url the URL of the Github Issue/PR. + * @param {string} url the URL of the GitHub Issue/PR. * @return {string} the formatted item */ function getFormattedItemDescription( title, number, url ) { @@ -856,7 +856,7 @@ function sortFeatureGroups( featureGroups ) { } /** - * Returns a list of PRs created by first time contributors based on the Github + * Returns a list of PRs created by first time contributors based on the GitHub * label associated with the PR. Also filters out any "bots". * * @param {IssuesListForRepoResponseItem[]} pullRequests List of pull requests. diff --git a/bin/plugin/commands/test/changelog.js b/bin/plugin/commands/test/changelog.js index 12420fd1e4b6f..9c9d423d18d1c 100644 --- a/bin/plugin/commands/test/changelog.js +++ b/bin/plugin/commands/test/changelog.js @@ -25,7 +25,7 @@ import _pullRequests from './fixtures/pull-requests.json'; import botPullRequestFixture from './fixtures/bot-pull-requests.json'; /** - * pull-requests.json is a static snapshot of real data from the Github API. + * pull-requests.json is a static snapshot of real data from the GitHub API. * We merge this with dummy fixture data for a "bot" pull request so as to * ensure future updates to the pull-requests.json doesn't reduce test coverage * of filtering out of bot PRs. diff --git a/changelog.txt b/changelog.txt index decdb88ea9a7a..8679f4a40ba9e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1378,7 +1378,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@tellthemachines @arthur791004 +@tellthemachines @arthur791004 = 18.1.1 = @@ -1392,7 +1392,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@okmttdhr @ntsekouras +@okmttdhr @ntsekouras = 18.1.0 = @@ -2423,7 +2423,7 @@ The following contributors merged PRs in this release: - Rich text: Fix typing into empty flex element. ([59473](https://github.com/WordPress/gutenberg/pull/59473)) - URLPopover: Fix a problem with the layout of link settings. ([58906](https://github.com/WordPress/gutenberg/pull/58906)) - Fix issue with appender jumping when creating a new pattern. ([59582](https://github.com/WordPress/gutenberg/pull/59582)) -- Allow event bubbling even if keydown is passed. ([59474](https://github.com/WordPress/gutenberg/pull/59474)) +- Allow event bubbling even if keydown is passed. ([59474](https://github.com/WordPress/gutenberg/pull/59474)) #### Custom Fields - Block Bindings: Fix console error when selecting a bound block. ([59598](https://github.com/WordPress/gutenberg/pull/59598)) @@ -3344,7 +3344,7 @@ The following contributors merged PRs in this release: - Docs: Copy and formatting edits for the "Static or Dynamic rendering" guide. ([58681](https://github.com/WordPress/gutenberg/pull/58681)) - Docs: Copy and formatting edits for the "The block in the Editor" guide. ([58697](https://github.com/WordPress/gutenberg/pull/58697)) - Docs: Copy and formatting edits for the "The block wrapper" guide. ([58704](https://github.com/WordPress/gutenberg/pull/58704)) -- Docs: Copy and formatting edits for the "Working with Javascript for the Block Editor" guide. ([58651](https://github.com/WordPress/gutenberg/pull/58651)) +- Docs: Copy and formatting edits for the "Working with JavaScript for the Block Editor" guide. ([58651](https://github.com/WordPress/gutenberg/pull/58651)) - Docs: Copy and formatting edits for the "block.json" guide. ([58732](https://github.com/WordPress/gutenberg/pull/58732)) - Docs: Copy edits and list formatting for main Block Editor Handbook readme. ([58652](https://github.com/WordPress/gutenberg/pull/58652)) - Docs: Fix list formatting and some grammar in the Entities explanation doc. ([58655](https://github.com/WordPress/gutenberg/pull/58655)) @@ -3563,7 +3563,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@ramonjd +@ramonjd = 17.7.0-rc.1 = @@ -3918,7 +3918,7 @@ The following contributors merged PRs in this release: - Docs: Copy and formatting edits for the "Static or Dynamic rendering" guide. ([58681](https://github.com/WordPress/gutenberg/pull/58681)) - Docs: Copy and formatting edits for the "The block in the Editor" guide. ([58697](https://github.com/WordPress/gutenberg/pull/58697)) - Docs: Copy and formatting edits for the "The block wrapper" guide. ([58704](https://github.com/WordPress/gutenberg/pull/58704)) -- Docs: Copy and formatting edits for the "Working with Javascript for the Block Editor" guide. ([58651](https://github.com/WordPress/gutenberg/pull/58651)) +- Docs: Copy and formatting edits for the "Working with JavaScript for the Block Editor" guide. ([58651](https://github.com/WordPress/gutenberg/pull/58651)) - Docs: Copy and formatting edits for the "block.json" guide. ([58732](https://github.com/WordPress/gutenberg/pull/58732)) - Docs: Copy edits and list formatting for main Block Editor Handbook readme. ([58652](https://github.com/WordPress/gutenberg/pull/58652)) - Docs: Fix list formatting and some grammar in the Entities explanation doc. ([58655](https://github.com/WordPress/gutenberg/pull/58655)) @@ -4145,7 +4145,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@dd32 +@dd32 = 17.6.2 = @@ -4663,7 +4663,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@andrewserong @t-hamano @luisherranz @pbking +@andrewserong @t-hamano @luisherranz @pbking = 17.6.0-rc.1 = @@ -5090,7 +5090,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@fullofcaffeine +@fullofcaffeine @@ -5107,7 +5107,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@youknowriad @fullofcaffeine +@youknowriad @fullofcaffeine @@ -5380,7 +5380,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@glendaviesnz +@glendaviesnz @@ -5412,7 +5412,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@ellatrix +@ellatrix @@ -5487,7 +5487,7 @@ The following contributors merged PRs in this release: - Gallery: Hide some controls when multi-editing blocks. ([57378](https://github.com/WordPress/gutenberg/pull/57378)) - Image Block: Get lightbox trigger button ref via data-wp-init. ([57089](https://github.com/WordPress/gutenberg/pull/57089)) - Image: Hide caption control when multi-editing images. ([57357](https://github.com/WordPress/gutenberg/pull/57357)) -- Video: Hide some controls when multi-editing blocks. ([57375](https://github.com/WordPress/gutenberg/pull/57375)) +- Video: Hide some controls when multi-editing blocks. ([57375](https://github.com/WordPress/gutenberg/pull/57375)) - Image Block: Fix deprecation when width/height attribute is number. ([57063](https://github.com/WordPress/gutenberg/pull/57063)) #### Patterns @@ -5500,7 +5500,7 @@ The following contributors merged PRs in this release: - Fix image upload bug. ([57040](https://github.com/WordPress/gutenberg/pull/57040)) - Reduce clearance around the Frame in the site editor. ([57023](https://github.com/WordPress/gutenberg/pull/57023)) - Swap Template: Show the right templates for the right post type. ([57149](https://github.com/WordPress/gutenberg/pull/57149)) -- Save Button: Fix the translation of the Activate button. ([57147](https://github.com/WordPress/gutenberg/pull/57147)) +- Save Button: Fix the translation of the Activate button. ([57147](https://github.com/WordPress/gutenberg/pull/57147)) - SlotFill: Allow contextual SlotFillProviders. ([56779](https://github.com/WordPress/gutenberg/pull/56779)) #### Post Editor @@ -5729,7 +5729,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@glendaviesnz +@glendaviesnz @@ -6418,7 +6418,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@jorgefilipecosta +@jorgefilipecosta = 17.2.0 = @@ -6662,7 +6662,7 @@ The following contributors merged PRs in this release: - Docs: Fundamentals of Block Development - File structure of a block. ([56551](https://github.com/WordPress/gutenberg/pull/56551)) - Docs: Fundamentals of Block Development - Registration of a block. ([56334](https://github.com/WordPress/gutenberg/pull/56334)) - Docs: Fundamentals of Block Development - The block wrapper. ([56596](https://github.com/WordPress/gutenberg/pull/56596)) -- Docs: Fundamentals of Block Development - Working with Javascript in the Block Editor. ([56553](https://github.com/WordPress/gutenberg/pull/56553)) +- Docs: Fundamentals of Block Development - Working with JavaScript in the Block Editor. ([56553](https://github.com/WordPress/gutenberg/pull/56553)) - Docs: Fundamentals of Block Development - block.json. ([56435](https://github.com/WordPress/gutenberg/pull/56435)) - Docs: Improve downloadBlob example. ([56225](https://github.com/WordPress/gutenberg/pull/56225)) - Documentation - Block Editor Handbook - Add end user documentation about Block Editor as a resource on the Landing Page of the Block Editor Handbook. ([49854](https://github.com/WordPress/gutenberg/pull/49854)) @@ -6991,7 +6991,7 @@ The following contributors merged PRs in this release: - Docs: Fundamentals of Block Development - File structure of a block. ([56551](https://github.com/WordPress/gutenberg/pull/56551)) - Docs: Fundamentals of Block Development - Registration of a block. ([56334](https://github.com/WordPress/gutenberg/pull/56334)) - Docs: Fundamentals of Block Development - The block wrapper. ([56596](https://github.com/WordPress/gutenberg/pull/56596)) -- Docs: Fundamentals of Block Development - Working with Javascript in the Block Editor. ([56553](https://github.com/WordPress/gutenberg/pull/56553)) +- Docs: Fundamentals of Block Development - Working with JavaScript in the Block Editor. ([56553](https://github.com/WordPress/gutenberg/pull/56553)) - Docs: Fundamentals of Block Development - block.json. ([56435](https://github.com/WordPress/gutenberg/pull/56435)) - Docs: Improve downloadBlob example. ([56225](https://github.com/WordPress/gutenberg/pull/56225)) - Documentation - Block Editor Handbook - Add end user documentation about Block Editor as a resource on the Landing Page of the Block Editor Handbook. ([49854](https://github.com/WordPress/gutenberg/pull/49854)) @@ -8077,7 +8077,7 @@ The following contributors merged PRs in this release: ## Changelog This copies the commits from the 16.7.1 patch release into the 16.8.0 main release. - + ### Tools #### Build Tooling @@ -9536,7 +9536,7 @@ The following contributors merged PRs in this release: - Button: Remove default border from the destructive button. ([53607](https://github.com/WordPress/gutenberg/pull/53607)) - LineHeightControl: Allow for more granular control of decimal places. ([52902](https://github.com/WordPress/gutenberg/pull/52902)) - Snackbar: Design and motion improvements. ([53248](https://github.com/WordPress/gutenberg/pull/53248)) -- Modal: +- Modal: - Add `headerActions` prop to enable buttons or other elements to be injected in the header. ([53328](https://github.com/WordPress/gutenberg/pull/53328)) - Enhance overlay interactions, enabling outside interactions without dismissal. ([52994](https://github.com/WordPress/gutenberg/pull/52994)) - ProgressBar: Update colors, including gray 300 for track color ([53349](https://github.com/WordPress/gutenberg/pull/53349)), theme system accent for indicator color ([53347](https://github.com/WordPress/gutenberg/pull/53347)), and the theme accent color variable. ([53632](https://github.com/WordPress/gutenberg/pull/53632)). @@ -9546,7 +9546,7 @@ The following contributors merged PRs in this release: - Add a `stretch` option to block's vertical alignment options. ([53325](https://github.com/WordPress/gutenberg/pull/53325)) - Exit upon pressing enter in an empty paragraph at the end of the block. ([53311](https://github.com/WordPress/gutenberg/pull/53311)) - Classic block: Increase dimensions of modal and allow toggling fullscreen. ([53449](https://github.com/WordPress/gutenberg/pull/53449)) -- Details block: +- Details block: - Add `accordion` and `toggle` keywords to improve block's discoverability. ([53501](https://github.com/WordPress/gutenberg/pull/53501)) - Add layout and block spacing options. ([53282](https://github.com/WordPress/gutenberg/pull/53282)) - File block: Add block spacing options. ([45107](https://github.com/WordPress/gutenberg/pull/45107)) @@ -9586,7 +9586,7 @@ The following contributors merged PRs in this release: ### Bug Fixes -#### Commands +#### Commands - Style tweaks to fix metrics for resting and no results view in command palette. ([53497](https://github.com/WordPress/gutenberg/pull/53497)) - Order template results in Site Editor, to fix some templates not displaying. ([53286](https://github.com/WordPress/gutenberg/pull/53286)) - Don't allow access to Styles-related pages via the command palette in the hybrid theme. ([53123](https://github.com/WordPress/gutenberg/pull/53123)) @@ -9594,12 +9594,12 @@ The following contributors merged PRs in this release: #### Block Library - Button block: Avoid losing user changes when the `ButtonEdit` component re-renders. ([53507](https://github.com/WordPress/gutenberg/pull/53507)) - Cover block: Fix flickering when inserted in templates and also fix `isDark` calculation bugs. ([53253](https://github.com/WordPress/gutenberg/pull/53253)) -- Footnotes block: +- Footnotes block: - Ensure autosave works and escapes quotes as expected. ([53664](https://github.com/WordPress/gutenberg/pull/53664)) - Fix accidental override. ([53663](https://github.com/WordPress/gutenberg/pull/53663)) - Fix recursion into updating attributes when attributes is not an object. ([53257](https://github.com/WordPress/gutenberg/pull/53257)) - Remove Footnotes when interactive formatting is disabled. ([53474](https://github.com/WordPress/gutenberg/pull/53474)) -- Image block: +- Image block: - Fix image stretching with only height. ([53443](https://github.com/WordPress/gutenberg/pull/53443)) - Don't render `DimensionsTool` if it is not resizable. ([53181](https://github.com/WordPress/gutenberg/pull/53181)) - Fix stretched images constrained by max-width. ([53274](https://github.com/WordPress/gutenberg/pull/53274)) @@ -9715,7 +9715,7 @@ The following contributors merged PRs in this release: - Fix outdated specification in the "Anatomy of a Block". ([53581](https://github.com/WordPress/gutenberg/pull/53581)) #### How To Guides -- Block Tutorial: +- Block Tutorial: - Adds import from `@wordpress/i18n` in code example. ([53504](https://github.com/WordPress/gutenberg/pull/53504)) - Adds package.json configuration instructions to tutorial. ([53689](https://github.com/WordPress/gutenberg/pull/53689)) - Building a Custom Block Editor: Consolidate and update the guide. ([53159](https://github.com/WordPress/gutenberg/pull/53159)) @@ -9731,7 +9731,7 @@ The following contributors merged PRs in this release: - Edit Post: Update "PluginDocumentSettingPanel" documentation. ([53393](https://github.com/WordPress/gutenberg/pull/53393)) - Interface: Fix "complimentary" typo with "complementary". ([53413](https://github.com/WordPress/gutenberg/pull/53413)) -#### Interactivity API +#### Interactivity API - Revamp of README to include API Reference among other indications. ([53385](https://github.com/WordPress/gutenberg/pull/53385)) - Add missing section in ToC and minor improvements to Getting Started Guide. ([53362](https://github.com/WordPress/gutenberg/pull/53362)) - Update Interactivity API package README with clear references to documentation. ([53388](https://github.com/WordPress/gutenberg/pull/53388)) @@ -9753,7 +9753,7 @@ The following contributors merged PRs in this release: #### Block Library - Button block: Replace the `isSmall` deprecated prop in the `WidthPanel`. ([53472](https://github.com/WordPress/gutenberg/pull/53472)) - Details block: Remove unnecessary comment attributes. ([51610](https://github.com/WordPress/gutenberg/pull/51610)) -- Footnotes block: +- Footnotes block: - Add some test coverage for footnotes logic in useEntityBlockEditor. ([53376](https://github.com/WordPress/gutenberg/pull/53376)) - Checking type before using count(). ([53660](https://github.com/WordPress/gutenberg/pull/53660)) - LinkControl/LinkUI: Remove unused `className` prop. ([53348](https://github.com/WordPress/gutenberg/pull/53348)) @@ -10121,7 +10121,7 @@ The following contributors merged PRs in this release: ### Tools - Add GH action to enforce PR labels. ([52760](https://github.com/WordPress/gutenberg/pull/52760)) -- Changelog automation: +- Changelog automation: - Make Accessibility a top-level section. ([52900](https://github.com/WordPress/gutenberg/pull/52900)) - Update to work with consolidated a11y labels. ([52896](https://github.com/WordPress/gutenberg/pull/52896)) - Use the correct label to filter Mobile app PRs. ([53024](https://github.com/WordPress/gutenberg/pull/53024)) @@ -10420,7 +10420,7 @@ The following contributors merged PRs in this release: #### Project Management - Update issue gardening automation with new label. ([52173](https://github.com/WordPress/gutenberg/pull/52173)) - Revert "Update Changelog for 16.1.2". ([52433](https://github.com/WordPress/gutenberg/pull/52433)) -- Github workflow: Add a PHP backport changes action. ([52096](https://github.com/WordPress/gutenberg/pull/52096)) +- GitHub workflow: Add a PHP backport changes action. ([52096](https://github.com/WordPress/gutenberg/pull/52096)) ## First time contributors @@ -10459,7 +10459,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@getdave @mcsf +@getdave @mcsf = 16.2.0 = @@ -10523,13 +10523,13 @@ The following contributors merged PRs in this release: - Footnotes: save numbering through the entity provider (https://github.com/WordPress/gutenberg/pull/52423) #### Code Quality / Performance -- Iframe: avoid asset parsing & fix script localisation +- Iframe: avoid asset parsing & fix script localisation ## Contributors The following contributors merged PRs in this release: -@ellatrix @ockham @t-hamano +@ellatrix @ockham @t-hamano = 16.2.0-rc.1 = @@ -10782,7 +10782,7 @@ The following contributors merged PRs in this release: - Update delete page button label. ([51812](https://github.com/WordPress/gutenberg/pull/51812)) - Update versions in WP for 6.3. ([51984](https://github.com/WordPress/gutenberg/pull/51984)) - Wrap "Move to trash" and "Switch to draft" buttons when labels are too long to fit on a single row. ([52249](https://github.com/WordPress/gutenberg/pull/52249)) -- [Github-Actions-Workflows][Plugin-Release] Allow shipping a point-release for an older stable release. ([49082](https://github.com/WordPress/gutenberg/pull/49082)) +- [GitHub-Actions-Workflows][Plugin-Release] Allow shipping a point-release for an older stable release. ([49082](https://github.com/WordPress/gutenberg/pull/49082)) #### Block Library - Block Editor: Unify texts for Create pattern modal. ([52151](https://github.com/WordPress/gutenberg/pull/52151)) @@ -11097,7 +11097,7 @@ The following contributors merged PRs in this release: - Update delete page button label. ([51812](https://github.com/WordPress/gutenberg/pull/51812)) - Update versions in WP for 6.3. ([51984](https://github.com/WordPress/gutenberg/pull/51984)) - Wrap "Move to trash" and "Switch to draft" buttons when labels are too long to fit on a single row. ([52249](https://github.com/WordPress/gutenberg/pull/52249)) -- [Github-Actions-Workflows][Plugin-Release] Allow shipping a point-release for an older stable release. ([49082](https://github.com/WordPress/gutenberg/pull/49082)) +- [GitHub-Actions-Workflows][Plugin-Release] Allow shipping a point-release for an older stable release. ([49082](https://github.com/WordPress/gutenberg/pull/49082)) #### Block Library - Block Editor: Unify texts for Create pattern modal. ([52151](https://github.com/WordPress/gutenberg/pull/52151)) @@ -11423,7 +11423,7 @@ The following contributors merged PRs in this release: #### Block Variations - [Block Library - Post Terms]: Custom taxonomies do not show icons when transforming from the toolbar. ([51476](https://github.com/WordPress/gutenberg/pull/51476)) -#### Page Content Focus +#### Page Content Focus - Switch to Page panel when deselecting a block [51881](https://github.com/WordPress/gutenberg/pull/51881) - Don't show 'Back to page' notification when navigating away from page [51880](https://github.com/WordPress/gutenberg/pull/51880) - useBlockSync(): Reset inner blocks when component unmounts [51783](https://github.com/WordPress/gutenberg/pull/51783) @@ -11563,7 +11563,7 @@ The following contributors merged PRs in this release: - Babel config: Enable useSpread option for JSX transform to reduce transpilation. ([51574](https://github.com/WordPress/gutenberg/pull/51574)) - Lodash: Remove from lint staged type check. ([51698](https://github.com/WordPress/gutenberg/pull/51698)) - Performance Tests: Update the base point to compare against. ([51689](https://github.com/WordPress/gutenberg/pull/51689)) -- wp-env: Try to fix failing PHP Github actions. ([51513](https://github.com/WordPress/gutenberg/pull/51513)) +- wp-env: Try to fix failing PHP GitHub actions. ([51513](https://github.com/WordPress/gutenberg/pull/51513)) - npm lockfile: Hoist reakit and date-fns packages to the top. ([51500](https://github.com/WordPress/gutenberg/pull/51500)) #### Plugin @@ -11582,7 +11582,7 @@ The following PRs were merged by first time contributors: The following contributors merged PRs in this release: -@aaronrobertshaw @afercia @alexstine @andrewserong @aristath @artemiomorales @aurooba @bangank36 @c4rl0sbr4v0 @carolinan @ciampo @dcalhoun @derekblank @diegohaz @draganescu @ellatrix @fabiankaegy @fluiddot @geriux @getdave @glendaviesnz @jameskoster @jasmussen @jeryj @jhnstn @jsnajdr @juanfra @kozer @luisherranz @MaggieCabrera @Mamaduka @matiasbenedetto @mcliwanow @mcsf @mikachan @n2erjo00 @noahtallen @noisysocks @ntsekouras @oandregal @okmttdhr @paulopmt1 @pbking @peterwilsoncc @pooja-muchandikar @ramonjd @richtabor @samnajian @SantosGuillamot @SavPhill @SaxonF @scruffian @shimotmk @Sidsector9 @SiobhyB @spacedmonkey @stokesman @sunyatasattva @t-hamano @talldan @tellthemachines @tyxla @walbo @WunderBart @xerpa43 @youknowriad @priethor @ajlende @mirka +@aaronrobertshaw @afercia @alexstine @andrewserong @aristath @artemiomorales @aurooba @bangank36 @c4rl0sbr4v0 @carolinan @ciampo @dcalhoun @derekblank @diegohaz @draganescu @ellatrix @fabiankaegy @fluiddot @geriux @getdave @glendaviesnz @jameskoster @jasmussen @jeryj @jhnstn @jsnajdr @juanfra @kozer @luisherranz @MaggieCabrera @Mamaduka @matiasbenedetto @mcliwanow @mcsf @mikachan @n2erjo00 @noahtallen @noisysocks @ntsekouras @oandregal @okmttdhr @paulopmt1 @pbking @peterwilsoncc @pooja-muchandikar @ramonjd @richtabor @samnajian @SantosGuillamot @SavPhill @SaxonF @scruffian @shimotmk @Sidsector9 @SiobhyB @spacedmonkey @stokesman @sunyatasattva @t-hamano @talldan @tellthemachines @tyxla @walbo @WunderBart @xerpa43 @youknowriad @priethor @ajlende @mirka @@ -11840,7 +11840,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@hellofromtonya @ndiego +@hellofromtonya @ndiego = 15.9.0 = @@ -11900,7 +11900,7 @@ The following contributors merged PRs in this release: - Remove `unwrap` from transforms and add `ungroup` to more blocks. ([50385](https://github.com/WordPress/gutenberg/pull/50385)) - Add new API to allow inserter items to be prioritised. ([50510](https://github.com/WordPress/gutenberg/pull/50510)) - Integrate `prioritizedInserterBlocks` API to slash inserter. ([50658](https://github.com/WordPress/gutenberg/pull/50658)) - + #### Global Styles - Custom CSS: Force display of in custom css input boxes to LTR. ([50768](https://github.com/WordPress/gutenberg/pull/50768)) - Styles Navigation Screen: Add Style Book. ([50566](https://github.com/WordPress/gutenberg/pull/50566)) @@ -11919,7 +11919,7 @@ The following contributors merged PRs in this release: #### Accessibility - Modals: Update the Cancel action's button design. ([50544](https://github.com/WordPress/gutenberg/pull/50544)) - Writing flow: Improve keyboard navigation on certain input types. ([43667](https://github.com/WordPress/gutenberg/pull/43667)) - + #### Icons - Add new `HeadingLevel` icons. ([50856](https://github.com/WordPress/gutenberg/pull/50856)) - Smaller external link icon. ([50728](https://github.com/WordPress/gutenberg/pull/50728)) @@ -12631,7 +12631,7 @@ Continued the work refactor away from Lodash usages to reduce the build size - Re-write of the landing page. ([49643](https://github.com/WordPress/gutenberg/pull/49643)) - Improve insertBlock(s) documentation. ([50078](https://github.com/WordPress/gutenberg/pull/50078)) - Small Typo: Remove dots. ([49853](https://github.com/WordPress/gutenberg/pull/49853)) - + ### Code Quality - Fix PrivateInserter import. ([50038](https://github.com/WordPress/gutenberg/pull/50038)) @@ -12649,7 +12649,7 @@ Continued the work refactor away from Lodash usages to reduce the build size - Migrate CPT end-to-end tests to Playwright. ([50031](https://github.com/WordPress/gutenberg/pull/50031)) - Fonts API: Add tests for gutenberg_add_registered_fonts_to_theme_json(). ([50049](https://github.com/WordPress/gutenberg/pull/50049)) - Expand multi-line block tests. ([49732](https://github.com/WordPress/gutenberg/pull/49732)) -- Rich text test helpers mimic user events. ([49804](https://github.com/WordPress/gutenberg/pull/49804)) +- Rich text test helpers mimic user events. ([49804](https://github.com/WordPress/gutenberg/pull/49804)) - Fix editor canvas detaching error in end-to-end tests. ([49374](https://github.com/WordPress/gutenberg/pull/49374)) #### Build Tooling @@ -12819,7 +12819,7 @@ The following contributors merged PRs in this release: ### Performance -- Continued the work refactor away from Lodash usages to reduce the build size +- Continued the work refactor away from Lodash usages to reduce the build size ([49725](https://github.com/WordPress/gutenberg/pull/49725), [49724](https://github.com/WordPress/gutenberg/pull/49724), [49638](https://github.com/WordPress/gutenberg/pull/49638), [49654](https://github.com/WordPress/gutenberg/pull/49654), [49639](https://github.com/WordPress/gutenberg/pull/49639), [49637](https://github.com/WordPress/gutenberg/pull/49637), [49727](https://github.com/WordPress/gutenberg/pull/49727)) ### Documentation @@ -13515,7 +13515,7 @@ The following contributors merged PRs in this release: - Create automatic change higher order reducer. ([48312](https://github.com/WordPress/gutenberg/pull/48312)) - [Inserter]: Preload media categories empty check - client side. ([47503](https://github.com/WordPress/gutenberg/pull/47503)) -#### Post Editor +#### Post Editor - Revert iframed editor for WP core only. ([48076](https://github.com/WordPress/gutenberg/pull/48076)) - PageAttributesCheck: Return boolean value directly from the selector. ([48336](https://github.com/WordPress/gutenberg/pull/48336)) - Apply busy status to the publish button in progress and unify button width. ([48444](https://github.com/WordPress/gutenberg/pull/48444)) @@ -13633,7 +13633,7 @@ The following contributors merged PRs in this release: ### Performance -#### Block Editor +#### Block Editor - Block Editor: Improve empty `getBlockParents()` perf. ([48242](https://github.com/WordPress/gutenberg/pull/48242)) - Fix perf regression in duotone hooks. ([48401](https://github.com/WordPress/gutenberg/pull/48401)) - Writing flow: Avoid recalc style on every selection change. ([48409](https://github.com/WordPress/gutenberg/pull/48409)) @@ -13664,7 +13664,7 @@ The following contributors merged PRs in this release: - Lodash: Remove some `_.get()` from Image block. ([48489](https://github.com/WordPress/gutenberg/pull/48489)) - Playwright: Fix request utils for non Docker envs. ([48206](https://github.com/WordPress/gutenberg/pull/48206)) - [Private APIs] Only prevent module re-registration if IS_WORDPRESS_CORE. ([48352](https://github.com/WordPress/gutenberg/pull/48352)) -- Add a manual performance job that we can trigger from Github UI. ([48302](https://github.com/WordPress/gutenberg/pull/48302)) +- Add a manual performance job that we can trigger from GitHub UI. ([48302](https://github.com/WordPress/gutenberg/pull/48302)) - Track new front-end metric: LCP-TTFB. ([48288](https://github.com/WordPress/gutenberg/pull/48288)) ### Documentation @@ -13678,7 +13678,7 @@ The following contributors merged PRs in this release: - Updates to the curating the editor experience to include 6.1 & 6.2 items. ([48294](https://github.com/WordPress/gutenberg/pull/48294)) ### Tools -#### Testing +#### Testing - Migrate `switch-to-draft` to Playwright. ([48120](https://github.com/WordPress/gutenberg/pull/48120)) - VizReg end-to-end tests: Programmatically test all combinations of a given list of props/values. ([48260](https://github.com/WordPress/gutenberg/pull/48260)) - Update end-to-end test snapshots to Jest 29 default. ([48626](https://github.com/WordPress/gutenberg/pull/48626)) @@ -13740,7 +13740,7 @@ The following contributors merged PRs in this release: - Create automatic change higher order reducer. ([48312](https://github.com/WordPress/gutenberg/pull/48312)) - [Inserter]: Preload media categories empty check - client side. ([47503](https://github.com/WordPress/gutenberg/pull/47503)) -#### Post Editor +#### Post Editor - Revert iframed editor for WP core only. ([48076](https://github.com/WordPress/gutenberg/pull/48076)) - PageAttributesCheck: Return boolean value directly from the selector. ([48336](https://github.com/WordPress/gutenberg/pull/48336)) - Apply busy status to the publish button in progress and unify button width. ([48444](https://github.com/WordPress/gutenberg/pull/48444)) @@ -13858,7 +13858,7 @@ The following contributors merged PRs in this release: ### Performance -#### Block Editor +#### Block Editor - Block Editor: Improve empty `getBlockParents()` perf. ([48242](https://github.com/WordPress/gutenberg/pull/48242)) - Fix perf regression in duotone hooks. ([48401](https://github.com/WordPress/gutenberg/pull/48401)) - Writing flow: Avoid recalc style on every selection change. ([48409](https://github.com/WordPress/gutenberg/pull/48409)) @@ -13889,7 +13889,7 @@ The following contributors merged PRs in this release: - Lodash: Remove some `_.get()` from Image block. ([48489](https://github.com/WordPress/gutenberg/pull/48489)) - Playwright: Fix request utils for non Docker envs. ([48206](https://github.com/WordPress/gutenberg/pull/48206)) - [Private APIs] Only prevent module re-registration if IS_WORDPRESS_CORE. ([48352](https://github.com/WordPress/gutenberg/pull/48352)) -- Add a manual performance job that we can trigger from Github UI. ([48302](https://github.com/WordPress/gutenberg/pull/48302)) +- Add a manual performance job that we can trigger from GitHub UI. ([48302](https://github.com/WordPress/gutenberg/pull/48302)) - Track new front-end metric: LCP-TTFB. ([48288](https://github.com/WordPress/gutenberg/pull/48288)) ### Documentation @@ -13903,7 +13903,7 @@ The following contributors merged PRs in this release: - Updates to the curating the editor experience to include 6.1 & 6.2 items. ([48294](https://github.com/WordPress/gutenberg/pull/48294)) ### Tools -#### Testing +#### Testing - Migrate `switch-to-draft` to Playwright. ([48120](https://github.com/WordPress/gutenberg/pull/48120)) - VizReg end-to-end tests: Programmatically test all combinations of a given list of props/values. ([48260](https://github.com/WordPress/gutenberg/pull/48260)) - Update end-to-end test snapshots to Jest 29 default. ([48626](https://github.com/WordPress/gutenberg/pull/48626)) @@ -14162,7 +14162,7 @@ The following contributors merged PRs in this release: - [Automated Testing]: Fix wrong button fixture. ([48305](https://github.com/WordPress/gutenberg/pull/48305)) #### Build Tooling -- Add a manual performance job that we can trigger from Github UI. ([48302](https://github.com/WordPress/gutenberg/pull/48302)) +- Add a manual performance job that we can trigger from GitHub UI. ([48302](https://github.com/WordPress/gutenberg/pull/48302)) - Add command to run performance tests in debug mode. ([48614](https://github.com/WordPress/gutenberg/pull/48614)) - Make the performance tests more stable. ([48094](https://github.com/WordPress/gutenberg/pull/48094)) - SpacingSizesControl: Fix white dot on thumb. ([48574](https://github.com/WordPress/gutenberg/pull/48574)) @@ -14257,7 +14257,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@jsnajdr +@jsnajdr = 15.2.2 = @@ -15342,7 +15342,7 @@ The following contributors merged PRs in this release: ### Bug Fixes #### Block Editor -- Move block variation picker styles in the iframe ([47109](https://github.com/WordPress/gutenberg/pull/47109)) +- Move block variation picker styles in the iframe ([47109](https://github.com/WordPress/gutenberg/pull/47109)) - Add useBlockPreview styles in iframe ([47110](https://github.com/WordPress/gutenberg/pull/47110)) #### Block Library @@ -15897,7 +15897,7 @@ Fixes compatibility with WordPress 6.0.x. This includes the following PRs: - #46809 Broadly, this needed to include the two refactors of the Theme_JSON compatibility files, along with two fixes switching `wp_*` and `gutenberg_*` function variants as needed. - + ## Contributors The following contributors were involved with this release: @@ -16204,7 +16204,7 @@ The following contributors merged PRs in this release: ### Tools #### Build Tooling -- Adds Github Action to validate Gradle Wrapper. ([46247](https://github.com/WordPress/gutenberg/pull/46247)) +- Adds GitHub Action to validate Gradle Wrapper. ([46247](https://github.com/WordPress/gutenberg/pull/46247)) - Prevent api-fetch and core-data from being imported in the block editor package. ([46302](https://github.com/WordPress/gutenberg/pull/46302)) - Serialize the map objects properly in the Redux dev tools. ([46282](https://github.com/WordPress/gutenberg/pull/46282)) @@ -16482,7 +16482,7 @@ The following contributors merged PRs in this release: ### Tools #### Build Tooling -- Adds Github Action to validate Gradle Wrapper. ([46247](https://github.com/WordPress/gutenberg/pull/46247)) +- Adds GitHub Action to validate Gradle Wrapper. ([46247](https://github.com/WordPress/gutenberg/pull/46247)) - Prevent api-fetch and core-data from being imported in the block editor package. ([46302](https://github.com/WordPress/gutenberg/pull/46302)) - Serialize the map objects properly in the Redux dev tools. ([46282](https://github.com/WordPress/gutenberg/pull/46282)) @@ -16519,7 +16519,7 @@ The following contributors merged PRs in this release: The following contributors merged PRs in this release: -@youknowriad +@youknowriad = 14.7.2 = @@ -17880,7 +17880,7 @@ The following contributors merged PRs in this release: - Query Loop: Hide instructions for FormTokenField. ([44641](https://github.com/WordPress/gutenberg/pull/44641)) - Tag Cloud: Remove `strtolower` around taxonomy name. ([16112](https://github.com/WordPress/gutenberg/pull/16112)) - Video: Update placeholder style. ([44215](https://github.com/WordPress/gutenberg/pull/44215)) - + #### Components - FontSizePicker: Make control take up full width. ([44559](https://github.com/WordPress/gutenberg/pull/44559)) - Placeholder: Remove unnecessary background color. ([44497](https://github.com/WordPress/gutenberg/pull/44497)) @@ -18313,7 +18313,7 @@ The following PRs were merged by first time contributors: The following contributors merged PRs in this release: -@aaronrobertshaw @ajlende @annezazu @apmatthews @aristath @c4rl0sbr4v0 @carolinan @chad1008 @ciampo @dcalhoun @draganescu @ellatrix @geriux @glendaviesnz @gziolo @jasmussen @jorgefilipecosta @kebbet @kkoppenhaver @Mamaduka @matiasbenedetto @mcsf @michalczaplinski @mirka @mtias @noisysocks @ntsekouras @pagelab @ramonjd @t-hamano @talldan @tellthemachines @tyxla @walbo @youknowriad +@aaronrobertshaw @ajlende @annezazu @apmatthews @aristath @c4rl0sbr4v0 @carolinan @chad1008 @ciampo @dcalhoun @draganescu @ellatrix @geriux @glendaviesnz @gziolo @jasmussen @jorgefilipecosta @kebbet @kkoppenhaver @Mamaduka @matiasbenedetto @mcsf @michalczaplinski @mirka @mtias @noisysocks @ntsekouras @pagelab @ramonjd @t-hamano @talldan @tellthemachines @tyxla @walbo @youknowriad @@ -20690,7 +20690,7 @@ The following contributors merged PRs in this release: - JS Error Tracking: Allow custom error reporting logic to be called in Error Boundaries via a WP action hook. ([42024](https://github.com/WordPress/gutenberg/pull/42024)) -### Accessibility +### Accessibility - Add aria-checked to the selected heading level menu item. ([42273](https://github.com/WordPress/gutenberg/pull/42273)) - Fix tabbing from first or last block in site editor. ([42036](https://github.com/WordPress/gutenberg/pull/42036)) @@ -20799,7 +20799,7 @@ The following contributors merged PRs in this release: - Tip: Covert component to TypeScript. ([42262](https://github.com/WordPress/gutenberg/pull/42262)) - VisuallyHidden: Convert component to TypeScript. ([42220](https://github.com/WordPress/gutenberg/pull/42220)) - Spacer: Complete TypeScript migration of component. ([42013](https://github.com/WordPress/gutenberg/pull/42013)) -- +- #### Components - Add eslint to prevent SSR breakage. ([42248](https://github.com/WordPress/gutenberg/pull/42248)) - Fix typos in components changelog. ([42244](https://github.com/WordPress/gutenberg/pull/42244)) @@ -20889,7 +20889,7 @@ The following contributors merged PRs in this release: ### Enhancements -#### UI +#### UI - Increase fade intensity during spotlight mode. ([40454](https://github.com/WordPress/gutenberg/pull/40454)) - Improvements to "inherit default layout" toggle. ([41893](https://github.com/WordPress/gutenberg/pull/41893)) - Make it easier to select "Edit visually" when in "Edit as HTML. ([41516](https://github.com/WordPress/gutenberg/pull/41516)) @@ -20949,7 +20949,7 @@ The following contributors merged PRs in this release: - [Block Editor]: Fix content loss from `replaceInnerBlocks` with controlled blocks. ([41948](https://github.com/WordPress/gutenberg/pull/41948)) - Fix action button spacing on the widget editor. ([41915](https://github.com/WordPress/gutenberg/pull/41915)) - Render duotone presets in pattern preview. ([41249](https://github.com/WordPress/gutenberg/pull/41249)) - + #### Block Library - List v2: - Fix impossible to outdent multiple list items. ([41713](https://github.com/WordPress/gutenberg/pull/41713)) @@ -22265,7 +22265,7 @@ The following contributors merged PRs in this release: ### Bug Fixes -- Fix the position of the block inserter in between blocks ([40919](https://github.com/WordPress/gutenberg/pull/40919)) +- Fix the position of the block inserter in between blocks ([40919](https://github.com/WordPress/gutenberg/pull/40919)) = 13.2.0 = @@ -22635,7 +22635,7 @@ The following PRs were merged by first time contributors: - Fixed focus loss when navigating the guide component. ([40324](https://github.com/WordPress/gutenberg/pull/40324)) - Navigation block: After choosing an option from Select Menu, focus after block rerender. ([40390](https://github.com/WordPress/gutenberg/pull/40390)) - Block Styles: Remove unnecessary button role and 'onKeyDown' handler. ([40427](https://github.com/WordPress/gutenberg/pull/40427)) - + ### Performance - Added a context param to sidebar entity request. ([40148](https://github.com/WordPress/gutenberg/pull/40148)) @@ -22673,12 +22673,12 @@ The following PRs were merged by first time contributors: - Stop exporting individual color objects from color values file. ([40387](https://github.com/WordPress/gutenberg/pull/40387)) - Added reusable BlockPopover and BlockPopoverInbetween components. ([40441](https://github.com/WordPress/gutenberg/pull/40441)) - Cleaned BlockMover component and styles. ([40379](https://github.com/WordPress/gutenberg/pull/40379)) - + #### Packages - Block Editor: Remove unused sub-components in list view. ([40448](https://github.com/WordPress/gutenberg/pull/40448)) - Data: Cancel render queue in a more straightforward way. ([40433](https://github.com/WordPress/gutenberg/pull/40433)) - + #### Plugin - Added `edit` context to patterns REST controllers. ([40259](https://github.com/WordPress/gutenberg/pull/40259)) @@ -39722,7 +39722,7 @@ Add knobs to the [ColorIndicator Story](https://github.com/WordPress/gutenberg/p * `is_gutenberg_page` incorrectly assumes `get_current_screen` exists, add check. * Brings code inline with CSS standards by switching font weight to numeric values. * Wrapped component would not the most up-to-date store values if it incurred a store state change during its own mount (e.g. dispatching during its own constructor), resolved by rerunning selection. -* Display an error message if Javascript is disabled. +* Display an error message if JavaScript is disabled. * Update to React 16.6.3. * Adds missing components dependency for RichText. * Refactors list block to remove previously exposed RichText/TinyMCE logic. diff --git a/docs/contributors/code/release.md b/docs/contributors/code/release.md index 4c8950eb5e7cd..f304ec9cd3a48 100644 --- a/docs/contributors/code/release.md +++ b/docs/contributors/code/release.md @@ -320,13 +320,13 @@ If an RC already exists for a new version, you _need_ to cherry-pick the same co The cherry-picking process can be automated with the [`npm run cherry-pick`](/docs/contributors/code/auto-cherry-picking.md) script, but be sure to use the `Backport to Gutenberg Minor Release` label when running the script. -You must also ensure that all PRs being included are assigned to the Github Milestone on which the minor release is based. Bear in mind, that when PRs are _merged_ they are automatically assigned a milestone for the next _stable_ release. Therefore you will need to go back through each PR in Github and re-assign the Milestone. +You must also ensure that all PRs being included are assigned to the GitHub Milestone on which the minor release is based. Bear in mind, that when PRs are _merged_ they are automatically assigned a milestone for the next _stable_ release. Therefore you will need to go back through each PR in GitHub and re-assign the Milestone. For example, if you are releasing version `12.5.4`, then all PRs picked for that release must be unassigned from the `12.6` Milestone and instead assigned to the `12.5` Milestone. Once cherry picking is complete, you can also remove the `Backport to Gutenberg Minor Release` label from the PRs. -Once you have the stable release branch in order and the correct Milestone assigned to your PRs you can _push the branch to Github_ and continue with the release process using the Github website GUI. +Once you have the stable release branch in order and the correct Milestone assigned to your PRs you can _push the branch to GitHub_ and continue with the release process using the GitHub website GUI. #### Running the minor release diff --git a/docs/explanations/architecture/performance.md b/docs/explanations/architecture/performance.md index de3b7b5dcdbd5..4c8b6386b9263 100644 --- a/docs/explanations/architecture/performance.md +++ b/docs/explanations/architecture/performance.md @@ -69,7 +69,7 @@ The performance results for each commit are pushed to codevitals and can be seen It's thus very important to ensure that the metric being computed is stable. Meaning, if you run the same test twice with the same code and environment, you'll get results that are close. -Our performance job runs Github CI which means that we can't trust the consistency of the numbers that we get between two similar job runs. Github CI may allocate different CPU and memory resources for us over time for instance. To alleviate this problem, each time we run the performance job on the trunk branch, we compare the current commit's performance to a fixed reference commit hash, which allows us to track the relative difference between the current commit and the reference commit consistently regardless of environment changes. +Our performance job runs GitHub CI which means that we can't trust the consistency of the numbers that we get between two similar job runs. GitHub CI may allocate different CPU and memory resources for us over time for instance. To alleviate this problem, each time we run the performance job on the trunk branch, we compare the current commit's performance to a fixed reference commit hash, which allows us to track the relative difference between the current commit and the reference commit consistently regardless of environment changes. ### Update the reference commit @@ -77,7 +77,7 @@ Gutenberg supports only two WP versions, this impacts the performance job in two - The base WP version used to run the performance job needs to be updated, when the minimum version supported by Gutenberg changes. In order to do that, we rely on the `Tested up to` flag of the plugin's `readme.txt` file. So each time that flag is changed, the version used for the performance job is changed as well. - - Updating the WP version used for performance jobs means that there's a high chance that the reference commit used for performance test stability becomes incompatible with the WP version that is used. So every time, the `Tested up to` flag is updated in the `readme.txt` is changed, we also have to update the reference commit that is used in `.github/workflows/performance.yml`. + - Updating the WP version used for performance jobs means that there's a high chance that the reference commit used for performance test stability becomes incompatible with the WP version that is used. So every time, the `Tested up to` flag is updated in the `readme.txt` is changed, we also have to update the reference commit that is used in `.github/workflows/performance.yml`. The new reference commit hash that is chosen needs to meet the following requirements: diff --git a/docs/getting-started/fundamentals/README.md b/docs/getting-started/fundamentals/README.md index fd2941711dd01..42dbace9d7ba3 100644 --- a/docs/getting-started/fundamentals/README.md +++ b/docs/getting-started/fundamentals/README.md @@ -9,4 +9,4 @@ This section provides an introduction to the most relevant concepts in block dev 1. **[The block in the Editor](https://developer.wordpress.org/block-editor/getting-started/fundamentals/block-in-the-editor):** How a block, as a React component, is loaded in the Block Editor and an overview of its structure. 1. **[Markup representation of a block](https://developer.wordpress.org/block-editor/getting-started/fundamentals/markup-representation-block):** How blocks are represented in the database, theme templates, and patterns. 1. **[Static or Dynamic rendering of a block](https://developer.wordpress.org/block-editor/getting-started/fundamentals/static-dynamic-rendering):** How blocks generate their front-end output either dynamically or statically. -1. **[Javascript in the Block Editor](https://developer.wordpress.org/block-editor/getting-started/fundamentals/javascript-in-the-block-editor):** How to work with modern Javascript when developing for the Block Editor. +1. **[JavaScript in the Block Editor](https://developer.wordpress.org/block-editor/getting-started/fundamentals/javascript-in-the-block-editor):** How to work with modern JavaScript when developing for the Block Editor. diff --git a/docs/getting-started/fundamentals/javascript-in-the-block-editor.md b/docs/getting-started/fundamentals/javascript-in-the-block-editor.md index 42d7363b6aa4d..348b95ba88da3 100644 --- a/docs/getting-started/fundamentals/javascript-in-the-block-editor.md +++ b/docs/getting-started/fundamentals/javascript-in-the-block-editor.md @@ -1,20 +1,20 @@ -# Working with Javascript for the Block Editor +# Working with JavaScript for the Block Editor Developing blocks for the Block Editor often involves using modern JavaScript (ESNext and JSX), and most examples here in the Block Editor Handbook are written in these syntaxes. -However, this form of JavaScript must be transformed into a browser-compatible format, necessitating a build step. This process transforms, bundles, and optimizes JavaScript source code and related assets into a format suitable for production environments. +However, this form of JavaScript must be transformed into a browser-compatible format, necessitating a build step. This process transforms, bundles, and optimizes JavaScript source code and related assets into a format suitable for production environments. ## JavaScript with a build process Using a build process for block development unlocks the full potential of modern JavaScript, facilitating the use of ESNext and JSX. -[ESNext](https://developer.mozilla.org/en-US/docs/Web/JavaScript/JavaScript_technologies_overview#standardization_process) refers to Javascript's most recent syntax and features. [JSX](https://react.dev/learn/writing-markup-with-jsx) is a syntax extension developed by the React project that enables you to write JavaScript that resembles HTML. +[ESNext](https://developer.mozilla.org/en-US/docs/Web/JavaScript/JavaScript_technologies_overview#standardization_process) refers to JavaScript's most recent syntax and features. [JSX](https://react.dev/learn/writing-markup-with-jsx) is a syntax extension developed by the React project that enables you to write JavaScript that resembles HTML. Since browsers cannot directly execute ESNext and JSX, these syntaxes must be transformed into browser-compatible JavaScript. [webpack](https://webpack.js.org/concepts/why-webpack/) is a pluggable tool that processes and bundles JavaScript for browser compatibility. [Babel](https://babeljs.io/), a plugin for webpack, converts ESNext and JSX into standard JavaScript. -Configuring webpack and Babel can be challenging, so it's recommended that you use the [`@wordpress/scripts`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/) package. This tool simplifies development by preconfiguring both, so you rarely need to write custom webpack or Babel configurations. +Configuring webpack and Babel can be challenging, so it's recommended that you use the [`@wordpress/scripts`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/) package. This tool simplifies development by preconfiguring both, so you rarely need to write custom webpack or Babel configurations. For an introduction, refer to the [Get started with wp-scripts](/docs/getting-started/devenv/get-started-with-wp-scripts.md) guide. @@ -28,21 +28,21 @@ The diagram below provides an overview of the build process when using the `wp-s - **Development Mode (`npm run start`):** This mode is tailored for active development. It skips minification for easier debugging, generates source maps for better error tracking, and watches your source files for changes. When a change is detected, it automatically rebuilds the affected files, allowing you to see updates in real-time. -The `wp-scripts` package also facilitates the use of JavaScript modules, allowing code distribution across multiple files and resulting in a streamlined bundle after the build process. The [block-development-example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) GitHub repository provides some good examples. +The `wp-scripts` package also facilitates the use of JavaScript modules, allowing code distribution across multiple files and resulting in a streamlined bundle after the build process. The [block-development-example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) GitHub repository provides some good examples.
In most situations, no customization will be needed, but you can provide a webpack.config.js when using wp-scripts to modify the build process to suit your needs.
-## Javascript without a build process +## JavaScript without a build process Integrating JavaScript into your WordPress projects without a build process can be the most straightforward approach in specific scenarios. This is particularly true for projects that don't leverage JSX or other advanced JavaScript features requiring compilation. -When you opt out of a build process, you interact directly with WordPress's [Javascript APIs](/docs/reference-guides/packages/) through the global `wp` object. This means that all the methods and packages provided by WordPress are readily available, but with one caveat: you must manually manage script dependencies. This is done by adding [the handle](/docs/contributors/code/scripts.md) of each corresponding package to the dependency array of your enqueued JavaScript file. +When you opt out of a build process, you interact directly with WordPress's [JavaScript APIs](/docs/reference-guides/packages/) through the global `wp` object. This means that all the methods and packages provided by WordPress are readily available, but with one caveat: you must manually manage script dependencies. This is done by adding [the handle](/docs/contributors/code/scripts.md) of each corresponding package to the dependency array of your enqueued JavaScript file. For example, suppose you're creating a script that registers a new block [variation](/docs/reference-guides/block-api/block-variations.md) using the `registerBlockVariation` function from the [`blocks`](/docs/reference-guides/packages/packages-blocks.md) package. You must include `wp-blocks` in your script's dependency array. This guarantees that the `wp.blocks.registerBlockVariation` method is available and defined by the time your script executes. -In the following example, the `wp-blocks` dependency is defined when enqueuing the `variations.js` file. +In the following example, the `wp-blocks` dependency is defined when enqueuing the `variations.js` file. ```php function example_enqueue_block_variations() { @@ -84,10 +84,10 @@ Refer to [Enqueueing assets in the Editor](/docs/how-to-guides/enqueueing-assets ## Additional resources - [Package reference](/docs/reference-guides/packages.md) -- [Get started with wp-scripts](/docs/getting-started/devenv/get-started-with-wp-scripts.md) -- [Enqueueing assets in the Editor](/docs/how-to-guides/enqueueing-assets-in-the-editor.md) -- [WordPress package handles](/docs/contributors/code/scripts.md) -- [Javascript reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript) | MDN Web Docs +- [Get started with wp-scripts](/docs/getting-started/devenv/get-started-with-wp-scripts.md) +- [Enqueueing assets in the Editor](/docs/how-to-guides/enqueueing-assets-in-the-editor.md) +- [WordPress package handles](/docs/contributors/code/scripts.md) +- [JavaScript reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript) | MDN Web Docs - [block-development-examples](https://github.com/WordPress/block-development-examples) | GitHub repository - [block-theme-examples](https://github.com/wptrainingteam/block-theme-examples) | GitHub repository - [How webpack and WordPress packages interact](https://developer.wordpress.org/news/2023/04/how-webpack-and-wordpress-packages-interact/) | Developer Blog diff --git a/docs/getting-started/tutorial.md b/docs/getting-started/tutorial.md index b57391a806cf6..641ecad07ab9b 100644 --- a/docs/getting-started/tutorial.md +++ b/docs/getting-started/tutorial.md @@ -156,7 +156,7 @@ Save the file and select the block in the Editor. You will now see both Color an #### Removing unnecessary code -For simplicity, the styling for the Copyright Date Block will be controlled entirely by the color and typography block supports. This block also does not have any front-end Javascript. Therefore, you don't need to specify stylesheets or a `viewScript` in the `block.json` file. +For simplicity, the styling for the Copyright Date Block will be controlled entirely by the color and typography block supports. This block also does not have any front-end JavaScript. Therefore, you don't need to specify stylesheets or a `viewScript` in the `block.json` file. 1. Remove the line for `editorStyle` 2. Remove the line for `style` diff --git a/docs/how-to-guides/data-basics/3-building-an-edit-form.md b/docs/how-to-guides/data-basics/3-building-an-edit-form.md index 34136ff408080..65c4d0a5486a0 100644 --- a/docs/how-to-guides/data-basics/3-building-an-edit-form.md +++ b/docs/how-to-guides/data-basics/3-building-an-edit-form.md @@ -215,7 +215,7 @@ As you can see, the `title` of an Entity Record is an object, but the `title` of This is no accident. Fields like `title`, `excerpt`, and `content` may contain [shortcodes](https://developer.wordpress.org/apis/handbook/shortcode/) or [dynamic blocks](/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md), which means they can only be rendered on the server. For such fields, the REST API exposes both the `raw` markup _and_ the `rendered` string. For example, in the block editor, `content.rendered` could used as a visual preview, and `content.raw` could be used to populate the code editor. -So why is the `content` of an Edited Entity Record a string? Since Javascript is not be able to properly render arbitrary block markup, it stores only the `raw` markup without the `rendered` part. And since that's a string, the entire field becomes a string. +So why is the `content` of an Edited Entity Record a string? Since JavaScript is not be able to properly render arbitrary block markup, it stores only the `raw` markup without the `rendered` part. And since that's a string, the entire field becomes a string. We can now update `EditPageForm` accordingly. We can access the actions using the [`useDispatch`](/packages/data/README.md#usedispatch) hook similarly to how we use `useSelect` to access selectors: diff --git a/docs/how-to-guides/enqueueing-assets-in-the-editor.md b/docs/how-to-guides/enqueueing-assets-in-the-editor.md index 02d9020d351e3..fb0efb88e6796 100644 --- a/docs/how-to-guides/enqueueing-assets-in-the-editor.md +++ b/docs/how-to-guides/enqueueing-assets-in-the-editor.md @@ -18,7 +18,7 @@ There are different hooks to use depending on the answers to these questions, an Whenever you need to enqueue assets for the Editor itself (i.e. not the user-generated content), you should use the [`enqueue_block_editor_assets`](https://developer.wordpress.org/reference/hooks/enqueue_block_editor_assets/) hook coupled with the standard [`wp_enqueue_script`](https://developer.wordpress.org/reference/functions/wp_enqueue_script/) and [`wp_enqueue_style`](https://developer.wordpress.org/reference/functions/wp_enqueue_style/) functions. -Examples might be adding custom inspector or toolbar controls, registering block styles and variations in Javascript, registering Editor plugins, etc. +Examples might be adding custom inspector or toolbar controls, registering block styles and variations in JavaScript, registering Editor plugins, etc. ```php /** @@ -31,7 +31,7 @@ function example_enqueue_editor_assets() { ); wp_enqueue_style( 'example-editor-styles', - plugins_url( 'editor-styles.css', __FILE__ ) + plugins_url( 'editor-styles.css', __FILE__ ) ); } add_action( 'enqueue_block_editor_assets', 'example_enqueue_editor_assets' ); diff --git a/docs/manifest.json b/docs/manifest.json index ac269e4784633..1704e6d711510 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -102,7 +102,7 @@ "parent": "fundamentals" }, { - "title": "Working with Javascript for the Block Editor", + "title": "Working with JavaScript for the Block Editor", "slug": "javascript-in-the-block-editor", "markdown_source": "../docs/getting-started/fundamentals/javascript-in-the-block-editor.md", "parent": "fundamentals" diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 21bb576f12a1c..93ab0a031800f 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -616,7 +616,7 @@ Displays the contents of a post or page. ([Source](https://github.com/WordPress/ - **Name:** core/post-content - **Category:** theme -- **Supports:** align (full, wide), color (background, gradients, link, text), dimensions (minHeight), layout, spacing (blockGap), typography (fontSize, lineHeight), ~~html~~ +- **Supports:** align (full, wide), background (backgroundImage, backgroundSize), color (background, gradients, link, text), dimensions (minHeight), layout, spacing (blockGap, padding), typography (fontSize, lineHeight), ~~html~~ ## Date diff --git a/docs/reference-guides/data/data-core-block-editor.md b/docs/reference-guides/data/data-core-block-editor.md index f687eb79732b5..4b66ad9eb6cb4 100644 --- a/docs/reference-guides/data/data-core-block-editor.md +++ b/docs/reference-guides/data/data-core-block-editor.md @@ -81,7 +81,6 @@ _Parameters_ - _state_ `Object`: Editor state. - _clientId_ `string`: The block client Id. -- _rootClientId_ `?string`: Optional root client ID of block list. _Returns_ @@ -95,7 +94,6 @@ _Parameters_ - _state_ `Object`: Editor state. - _clientIds_ `string`: The block client IDs to be moved. -- _rootClientId_ `?string`: Optional root client ID of block list. _Returns_ @@ -109,7 +107,6 @@ _Parameters_ - _state_ `Object`: Editor state. - _clientId_ `string`: The block client Id. -- _rootClientId_ `?string`: Optional root client ID of block list. _Returns_ @@ -123,7 +120,6 @@ _Parameters_ - _state_ `Object`: Editor state. - _clientIds_ `string`: The block client IDs to be removed. -- _rootClientId_ `?string`: Optional root client ID of block list. _Returns_ diff --git a/docs/reference-guides/interactivity-api/README.md b/docs/reference-guides/interactivity-api/README.md index b6e0d639c3fc8..85255af785cbb 100644 --- a/docs/reference-guides/interactivity-api/README.md +++ b/docs/reference-guides/interactivity-api/README.md @@ -1,6 +1,6 @@ # Interactivity API Reference -The Interactivity API, [introduced in WordPress 6.5](https://make.wordpress.org/core/2024/02/19/merge-announcement-interactivity-api/), provides a standard way for developers to add interactions to the front end of their blocks. The API is also used in many Core WordPress blocks, including Search, Query, Navigation, and File. +The Interactivity API, [introduced in WordPress 6.5](https://make.wordpress.org/core/2024/02/19/merge-announcement-interactivity-api/), provides a standard way for developers to add interactions to the front end of their blocks. The API is also used in many Core WordPress blocks, including Search, Query, Navigation, and File. This standard makes it easier for developers to create rich, interactive user experiences, from simple counters or pop-ups to more complex features like instant page navigation, instant search, shopping carts, or checkouts. @@ -32,7 +32,7 @@ To get a deeper understanding of what the Interactivity API is or find answers t Interactivity API is included in Core in WordPress 6.5. For versions below, you'll need Gutenberg 17.5 or higher installed and activated in your WordPress installation. -It’s also important to highlight that the block creation workflow doesn’t change, and all the [prerequisites](https://developer.wordpress.org/block-editor/getting-started/devenv/) remain the same. These include: +It’s also important to highlight that the block creation workflow doesn’t change, and all the [prerequisites](https://developer.wordpress.org/block-editor/getting-started/devenv/) remain the same. These include: - [Code Editor](https://developer.wordpress.org/block-editor/getting-started/devenv/#code-editor) - [Node.js development tools](https://developer.wordpress.org/block-editor/getting-started/devenv/#node-js-development-tools) @@ -55,7 +55,7 @@ To indicate that the block [supports](https://developer.wordpress.org/block-edit Refer to the [`interactivity` support property docs](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#interactivity) to get a more detailed description of this property. -#### Load Interactivity API Javascript code with `viewScriptModule` +#### Load Interactivity API JavaScript code with `viewScriptModule` The Interactivity API provides the `@wordpress/interactivity` Script Module. JavaScript using the Interactivity API should be implemented as Script Modules so they can depend on `@wordpress/interactivity`. [Script Modules have been available since WordPress 6.5](https://make.wordpress.org/core/2024/03/04/script-modules-in-6-5/). Blocks can use [`viewScriptModule` block metadata](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#view-script-module) to enqueue their Script Modules easily: @@ -82,7 +82,7 @@ The use of `viewScriptModule` also requires the `--experimental-modules` flag fo #### Add `wp-interactive` directive to a DOM element -To "activate" the Interactivity API in a DOM element (and its children), add the [`wp-interactive`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-interactivity/packages-interactivity-api-reference/#wp-interactive) directive to the DOM element in the block's `render.php` or `save.js` files. +To "activate" the Interactivity API in a DOM element (and its children), add the [`wp-interactive`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-interactivity/packages-interactivity-api-reference/#wp-interactive) directive to the DOM element in the block's `render.php` or `save.js` files. diff --git a/lib/README.md b/lib/README.md index cbc86d67a18f7..8e22f676a153d 100644 --- a/lib/README.md +++ b/lib/README.md @@ -6,7 +6,7 @@ The Gutenberg plugin is continuously enhancing existing features and creating ne During a WordPress release, new features, bugfixes and other changes are "synced" between the Gutenberg plugin and WordPress Core. Consistent naming and directory structures make this process easier by preventing naming conflicts and compartmentalizing release-specific code. -The following documentation is intended to act as a guide only. If you're unsure about naming or where to place new PHP files, please don't hesitate to ping other contributors on Github or ask in the #core-editor channel on [WordPress Slack](https://make.wordpress.org/chat/). +The following documentation is intended to act as a guide only. If you're unsure about naming or where to place new PHP files, please don't hesitate to ping other contributors on GitHub or ask in the #core-editor channel on [WordPress Slack](https://make.wordpress.org/chat/). ## File structure @@ -194,10 +194,10 @@ Existing comments in `lib/load.php` should act as a guide. If you've changed or added PHP files to the Gutenberg plugin, you'll need to confirm whether the changes are to be synced to WordPress Core, and therefore featured in the next release of WordPress. -The Gutenberg Github pull request in question should be labeled with the `Needs PHP backport` label if the changes are to be synced to Core. +The Gutenberg GitHub pull request in question should be labeled with the `Needs PHP backport` label if the changes are to be synced to Core. -If so, it is recommended to create a [new Trac ticket](https://core.trac.wordpress.org/newticket) and submit a pull request to the [WordPress Core Github repository](https://github.com/WordPress/wordpress-develop) soon after your pull request is merged. +If so, it is recommended to create a [new Trac ticket](https://core.trac.wordpress.org/newticket) and submit a pull request to the [WordPress Core GitHub repository](https://github.com/WordPress/wordpress-develop) soon after your pull request is merged. -So too, if you've made changes in WordPress Core to code that also lives in the Gutenberg plugin, these changes will need to be synced (often called "backporting") to Gutenberg. The relevant Gutenberg Github pull request should be labeled with the `Backport from WordPress Core` label. +So too, if you've made changes in WordPress Core to code that also lives in the Gutenberg plugin, these changes will need to be synced (often called "backporting") to Gutenberg. The relevant Gutenberg GitHub pull request should be labeled with the `Backport from WordPress Core` label. If you're unsure, you can always ask for help in the #core-editor channel in [WordPress Slack](https://make.wordpress.org/chat/). diff --git a/lib/block-editor-settings.php b/lib/block-editor-settings.php index 53668e114e04c..defd7cd391b16 100644 --- a/lib/block-editor-settings.php +++ b/lib/block-editor-settings.php @@ -58,7 +58,7 @@ function gutenberg_get_block_editor_settings( $settings ) { * entered by users does not break other global styles. */ $global_styles[] = array( - 'css' => gutenberg_get_global_styles_custom_css(), + 'css' => gutenberg_get_global_stylesheet( array( 'custom-css' ) ), '__unstableType' => 'user', 'isGlobalStyles' => true, ); diff --git a/lib/block-supports/block-style-variations.php b/lib/block-supports/block-style-variations.php index f2bc6af92e9de..e078b50b19d5a 100644 --- a/lib/block-supports/block-style-variations.php +++ b/lib/block-supports/block-style-variations.php @@ -244,7 +244,7 @@ function gutenberg_resolve_block_style_variations( $variations ) { * Block style variations read in via standalone theme.json partials * need to have their name set to the kebab case version of their title. */ - $variation_name = $have_named_variations ? $key : _wp_to_kebab_case( $variation['title'] ); + $variation_name = $have_named_variations ? $key : ( $variation['slug'] ?? _wp_to_kebab_case( $variation['title'] ) ); foreach ( $supported_blocks as $block_type ) { // Add block style variation data under current block type. @@ -455,7 +455,7 @@ function gutenberg_register_block_style_variations_from_theme_json_data( $variat * Block style variations read in via standalone theme.json partials * need to have their name set to the kebab case version of their title. */ - $variation_name = $have_named_variations ? $key : _wp_to_kebab_case( $variation['title'] ); + $variation_name = $have_named_variations ? $key : ( $variation['slug'] ?? _wp_to_kebab_case( $variation['title'] ) ); $variation_label = $variation['title'] ?? $variation_name; foreach ( $supported_blocks as $block_type ) { diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index a1e79a56a683b..deb4d850d271f 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -357,6 +357,7 @@ class WP_Theme_JSON_Gutenberg { 'styles', 'templateParts', 'title', + 'slug', 'version', ); @@ -1355,6 +1356,12 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' $stylesheet .= $this->get_preset_classes( $setting_nodes, $origins ); } + // Load the custom CSS last so it has the highest specificity. + if ( in_array( 'custom-css', $types, true ) ) { + // Add the global styles root CSS. + $stylesheet .= _wp_array_get( $this->theme_json, array( 'styles', 'css' ) ); + } + return $stylesheet; } @@ -1399,10 +1406,12 @@ protected function process_blocks_custom_css( $css, $selector ) { * Returns the global styles custom css. * * @since 6.2.0 + * @deprecated 6.7.0 Use {@see 'get_stylesheet'} instead. * * @return string The global styles custom CSS. */ public function get_custom_css() { + _deprecated_function( __METHOD__, '6.7.0', 'get_stylesheet' ); $block_custom_css = ''; $block_nodes = $this->get_block_custom_css_nodes(); foreach ( $block_nodes as $node ) { @@ -1415,23 +1424,23 @@ public function get_custom_css() { /** * Returns the global styles base custom CSS. - * - * @since 6.6.0 + * This function is deprecated; please do not sync to core. * * @return string The global styles base custom CSS. */ public function get_base_custom_css() { + _deprecated_function( __METHOD__, 'Gutenberg 18.6.0', 'get_stylesheet' ); return isset( $this->theme_json['styles']['css'] ) ? $this->theme_json['styles']['css'] : ''; } /** * Returns the block nodes with custom CSS. - * - * @since 6.6.0 + * This function is deprecated; please do not sync to core. * * @return array The block nodes. */ public function get_block_custom_css_nodes() { + _deprecated_function( __METHOD__, 'Gutenberg 18.6.0', 'get_block_nodes' ); $block_nodes = array(); // Add the global styles block CSS. @@ -1455,8 +1464,7 @@ public function get_block_custom_css_nodes() { /** * Returns the global styles custom CSS for a single block. - * - * @since 6.6.0 + * This function is deprecated; please do not sync to core. * * @param array $css The block css node. * @param string $selector The block selector. @@ -1464,6 +1472,7 @@ public function get_block_custom_css_nodes() { * @return string The global styles custom CSS for the block. */ public function get_block_custom_css( $css, $selector ) { + _deprecated_function( __METHOD__, 'Gutenberg 18.6.0', 'get_styles_for_block' ); return $this->process_blocks_custom_css( $css, $selector ); } @@ -2646,6 +2655,7 @@ private static function get_block_nodes( $theme_json, $selectors = array() ) { 'selectors' => $feature_selectors, 'duotone' => $duotone_selector, 'variations' => $variation_selectors, + 'css' => $selector, ); if ( isset( $theme_json['styles']['blocks'][ $name ]['elements'] ) ) { @@ -2694,6 +2704,7 @@ public function get_styles_for_block( $block_metadata ) { // If there are style variations, generate the declarations for them, including any feature selectors the block may have. $style_variation_declarations = array(); + $style_variation_custom_css = array(); if ( ! empty( $block_metadata['variations'] ) ) { foreach ( $block_metadata['variations'] as $style_variation ) { $style_variation_node = _wp_array_get( $this->theme_json, $style_variation['path'], array() ); @@ -2720,9 +2731,12 @@ static function ( $split_selector ) use ( $clean_style_variation_selector ) { // Add the new declarations to the overall results under the modified selector. $style_variation_declarations[ $combined_selectors ] = $new_declarations; } - // Compute declarations for remaining styles not covered by feature level selectors. $style_variation_declarations[ $style_variation['selector'] ] = static::compute_style_properties( $style_variation_node, $settings, null, $this->theme_json ); + // Store custom CSS for the style variation. + if ( isset( $style_variation_node['css'] ) ) { + $style_variation_custom_css[ $style_variation['selector'] ] = $this->process_blocks_custom_css( $style_variation_node['css'], $style_variation['selector'] ); + } } } @@ -2853,6 +2867,14 @@ static function ( $pseudo_selector ) use ( $selector ) { // 6. Generate and append the style variation rulesets. foreach ( $style_variation_declarations as $style_variation_selector => $individual_style_variation_declarations ) { $block_rules .= static::to_ruleset( ":root :where($style_variation_selector)", $individual_style_variation_declarations ); + if ( isset( $style_variation_custom_css[ $style_variation_selector ] ) ) { + $block_rules .= $style_variation_custom_css[ $style_variation_selector ]; + } + } + + // 7. Generate and append any custom CSS rules. + if ( isset( $node['css'] ) && ! $is_root_selector ) { + $block_rules .= $this->process_blocks_custom_css( $node['css'], $selector ); } return $block_rules; diff --git a/lib/compat/wordpress-6.5/html-api/class-gutenberg-html-tag-processor-6-5.php b/lib/compat/wordpress-6.5/html-api/class-gutenberg-html-tag-processor-6-5.php index 5c371f4bf6569..f93a48515d93b 100644 --- a/lib/compat/wordpress-6.5/html-api/class-gutenberg-html-tag-processor-6-5.php +++ b/lib/compat/wordpress-6.5/html-api/class-gutenberg-html-tag-processor-6-5.php @@ -298,8 +298,8 @@ * * The special elements are: * - `SCRIPT` whose contents are treated as raw plaintext but supports a legacy - * style of including Javascript inside of HTML comments to avoid accidentally - * closing the SCRIPT from inside a Javascript string. E.g. `console.log( '' )`. + * style of including JavaScript inside of HTML comments to avoid accidentally + * closing the SCRIPT from inside a JavaScript string. E.g. `console.log( '' )`. * - `TITLE` and `TEXTAREA` whose contents are treated as plaintext and then any * character references are decoded. E.g. `1 < 2 < 3` becomes `1 < 2 < 3`. * - `IFRAME`, `NOSCRIPT`, `NOEMBED`, `NOFRAME`, `STYLE` whose contents are treated as diff --git a/lib/global-styles-and-settings.php b/lib/global-styles-and-settings.php index 4ceade6c7125b..79c7028e32543 100644 --- a/lib/global-styles-and-settings.php +++ b/lib/global-styles-and-settings.php @@ -144,6 +144,7 @@ function gutenberg_get_global_settings( $path = array(), $context = array() ) { * @return string */ function gutenberg_get_global_styles_custom_css() { + _deprecated_function( __FUNCTION__, 'Gutenberg 18.6.0', 'gutenberg_get_global_stylesheet' ); // Ignore cache when `WP_DEBUG` is enabled, so it doesn't interfere with the theme developers workflow. $can_use_cached = ! WP_DEBUG; $cache_key = 'gutenberg_get_global_custom_css'; @@ -177,6 +178,7 @@ function gutenberg_get_global_styles_custom_css() { * @return string The global base custom CSS. */ function gutenberg_get_global_styles_base_custom_css() { + _deprecated_function( __FUNCTION__, 'Gutenberg 18.6.0', 'gutenberg_get_global_stylesheet' ); if ( ! wp_theme_has_theme_json() ) { return ''; } @@ -211,6 +213,7 @@ function gutenberg_get_global_styles_base_custom_css() { * @global WP_Styles $wp_styles */ function gutenberg_add_global_styles_block_custom_css() { + _deprecated_function( __FUNCTION__, 'Gutenberg 18.6.0', 'gutenberg_add_global_styles_for_blocks' ); global $wp_styles; if ( ! wp_theme_has_theme_json() || ! wp_should_load_separate_core_block_assets() ) { diff --git a/lib/script-loader.php b/lib/script-loader.php index 01008a0da8967..59df13556e9cf 100644 --- a/lib/script-loader.php +++ b/lib/script-loader.php @@ -43,45 +43,29 @@ function gutenberg_enqueue_global_styles() { add_filter( 'wp_theme_json_get_style_nodes', 'wp_filter_out_block_nodes' ); $stylesheet = gutenberg_get_global_stylesheet(); - if ( empty( $stylesheet ) ) { - return; - } - - wp_register_style( 'global-styles', false ); - wp_add_inline_style( 'global-styles', $stylesheet ); - wp_enqueue_style( 'global-styles' ); - - // Add each block as an inline css. - gutenberg_add_global_styles_for_blocks(); /* - * Add the custom CSS for the global styles. - * Before that, dequeue the Customizer's custom CSS + * Dequeue the Customizer's custom CSS * and add it before the global styles custom CSS. - * Don't enqueue Customizer's custom CSS separately. */ remove_action( 'wp_head', 'wp_custom_css_cb', 101 ); + // Get the custom CSS from the Customizer and add it to the global stylesheet. + $custom_css = wp_get_custom_css(); + $stylesheet .= $custom_css; - $custom_css = wp_get_custom_css(); + // Add the global styles custom CSS at the end. + $stylesheet .= gutenberg_get_global_stylesheet( array( 'custom-css' ) ); - if ( ! wp_should_load_separate_core_block_assets() ) { - /* - * If loading all block assets together, add both - * the base and block custom CSS at once. Else load - * the base custom CSS only, and the block custom CSS - * will be added to the inline CSS for each block in - * gutenberg_add_global_styles_block_custom_css(). - */ - $custom_css .= gutenberg_get_global_styles_custom_css(); - } else { - $custom_css .= gutenberg_get_global_styles_base_custom_css(); + if ( empty( $stylesheet ) ) { + return; } - if ( ! empty( $custom_css ) ) { - wp_add_inline_style( 'global-styles', $custom_css ); - } + wp_register_style( 'global-styles', false ); + wp_add_inline_style( 'global-styles', $stylesheet ); + wp_enqueue_style( 'global-styles' ); - gutenberg_add_global_styles_block_custom_css(); + // Add each block as an inline css. + gutenberg_add_global_styles_for_blocks(); } add_action( 'wp_enqueue_scripts', 'gutenberg_enqueue_global_styles' ); add_action( 'wp_footer', 'gutenberg_enqueue_global_styles', 1 ); diff --git a/lib/theme-i18n.json b/lib/theme-i18n.json index e4d14502132cb..fe541e65c676b 100644 --- a/lib/theme-i18n.json +++ b/lib/theme-i18n.json @@ -81,6 +81,15 @@ } } }, + "styles": { + "blocks": { + "variations": { + "*": { + "title": "Style variation name" + } + } + } + }, "customTemplates": [ { "title": "Custom template name" diff --git a/package-lock.json b/package-lock.json index 4f2901c8fe8bd..7a297c7d427e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -80,7 +80,8 @@ "@wordpress/warning": "file:packages/warning", "@wordpress/widgets": "file:packages/widgets", "@wordpress/wordcount": "file:packages/wordcount", - "es-module-shims": "^1.8.2" + "es-module-shims": "^1.8.2", + "postcss-local-keyframes": "^0.0.2" }, "devDependencies": { "@actions/core": "1.9.1", @@ -42422,6 +42423,17 @@ "webpack": "^5.0.0" } }, + "node_modules/postcss-local-keyframes": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/postcss-local-keyframes/-/postcss-local-keyframes-0.0.2.tgz", + "integrity": "sha512-nRN01llvxnqLw1TZu4kBknHwpxPPK3DLLJClQ3eTGhS+jBNyoIAMx0hw+fdiDOy7TXjfnojamPwUm/UxBEZDTw==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.2.8" + } + }, "node_modules/postcss-media-query-parser": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", @@ -88797,6 +88809,11 @@ "semver": "^7.3.5" } }, + "postcss-local-keyframes": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/postcss-local-keyframes/-/postcss-local-keyframes-0.0.2.tgz", + "integrity": "sha512-nRN01llvxnqLw1TZu4kBknHwpxPPK3DLLJClQ3eTGhS+jBNyoIAMx0hw+fdiDOy7TXjfnojamPwUm/UxBEZDTw==" + }, "postcss-media-query-parser": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", diff --git a/package.json b/package.json index ca8ebb89876a6..382f09c9b81a1 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,8 @@ "@wordpress/warning": "file:packages/warning", "@wordpress/widgets": "file:packages/widgets", "@wordpress/wordcount": "file:packages/wordcount", - "es-module-shims": "^1.8.2" + "es-module-shims": "^1.8.2", + "postcss-local-keyframes": "^0.0.2" }, "devDependencies": { "@actions/core": "1.9.1", @@ -274,8 +275,8 @@ "build:plugin-zip": "bash ./bin/build-plugin-zip.sh", "clean:package-types": "tsc --build --clean && rimraf \"./packages/*/build-types\"", "clean:packages": "rimraf \"./packages/*/@(build|build-module|build-style)\"", - "dev": "npm run build:packages && concurrently \"wp-scripts start\" \"npm run dev:packages\"", - "dev:packages": "concurrently \"node ./bin/packages/watch.js\" \"tsc --build --watch\"", + "dev": "cross-env NODE_ENV=development npm run build:packages && concurrently \"wp-scripts start\" \"npm run dev:packages\"", + "dev:packages": "cross-env NODE_ENV=development concurrently \"node ./bin/packages/watch.js\" \"tsc --build --watch\"", "distclean": "git clean --force -d -X", "docs:api-ref": "node ./bin/api-docs/update-api-docs.js", "docs:blocks": "node ./bin/api-docs/gen-block-lib-list.js", diff --git a/packages/autop/CHANGELOG.md b/packages/autop/CHANGELOG.md index a1af20c63ba0b..ee2659f9bb6e6 100644 --- a/packages/autop/CHANGELOG.md +++ b/packages/autop/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Internal + +- Refactor to TypeScript ([#62583](https://github.com/WordPress/gutenberg/pull/62583)). + ## 4.0.0 (2024-05-31) ### Breaking Changes diff --git a/packages/autop/src/index.js b/packages/autop/src/index.ts similarity index 92% rename from packages/autop/src/index.js rename to packages/autop/src/index.ts index 596a028f46164..e4a4b7ff27cb2 100644 --- a/packages/autop/src/index.js +++ b/packages/autop/src/index.ts @@ -1,9 +1,7 @@ /** * The regular expression for an HTML element. - * - * @type {RegExp} */ -const htmlSplitRegex = ( () => { +const htmlSplitRegex: RegExp = ( () => { /* eslint-disable no-multi-spaces */ const comments = '!' + // Start of comment, after the <. @@ -51,11 +49,11 @@ const htmlSplitRegex = ( () => { /** * Separate HTML elements and comments from the text. * - * @param {string} input The text which has to be formatted. + * @param input The text which has to be formatted. * - * @return {string[]} The formatted text. + * @return The formatted text. */ -function htmlSplit( input ) { +function htmlSplit( input: string ): string[] { const parts = []; let workingInput = input; @@ -65,7 +63,7 @@ function htmlSplit( input ) { // If the `g` flag is omitted, `index` is included. // `htmlSplitRegex` does not have the `g` flag so we can assert it will have an index number. // Assert `match.index` is a number. - const index = /** @type {number} */ ( match.index ); + const index = match.index as number; parts.push( workingInput.slice( 0, index ) ); parts.push( match[ 0 ] ); @@ -82,12 +80,15 @@ function htmlSplit( input ) { /** * Replace characters or phrases within HTML elements only. * - * @param {string} haystack The text which has to be formatted. - * @param {Record} replacePairs In the form {from: 'to', …}. + * @param haystack The text which has to be formatted. + * @param replacePairs In the form {from: 'to', …}. * - * @return {string} The formatted text. + * @return The formatted text. */ -function replaceInHtmlTags( haystack, replacePairs ) { +function replaceInHtmlTags( + haystack: string, + replacePairs: Record< string, string > +): string { // Find all elements. const textArr = htmlSplit( haystack ); let changed = false; @@ -125,9 +126,9 @@ function replaceInHtmlTags( haystack, replacePairs ) { * replace double line-breaks with HTML paragraph tags. The remaining line- * breaks after conversion become `
` tags, unless br is set to 'false'. * - * @param {string} text The text which has to be formatted. - * @param {boolean} br Optional. If set, will convert all remaining line- - * breaks after paragraphing. Default true. + * @param text The text which has to be formatted. + * @param br Optional. If set, will convert all remaining line- + * breaks after paragraphing. Default true. * * @example *```js @@ -135,10 +136,10 @@ function replaceInHtmlTags( haystack, replacePairs ) { * autop( 'my text' ); // "

my text

" * ``` * - * @return {string} Text which has been converted into paragraph tags. + * @return Text which has been converted into paragraph tags. */ -export function autop( text, br = true ) { - const preTags = []; +export function autop( text: string, br: boolean = true ): string { + const preTags: Array< [ string, string ] > = []; if ( text.trim() === '' ) { return ''; @@ -330,7 +331,7 @@ export function autop( text, br = true ) { * Replaces `

` tags with two line breaks except where the `

` has attributes. * Unifies whitespace. Indents `

  • `, `
    ` and `
    ` for better readability. * - * @param {string} html The content from the editor. + * @param html The content from the editor. * * @example * ```js @@ -338,15 +339,14 @@ export function autop( text, br = true ) { * removep( '

    my text

    ' ); // "my text" * ``` * - * @return {string} The content with stripped paragraph tags. + * @return The content with stripped paragraph tags. */ -export function removep( html ) { +export function removep( html: string ): string { const blocklist = 'blockquote|ul|ol|li|dl|dt|dd|table|thead|tbody|tfoot|tr|th|td|h[1-6]|fieldset|figure'; const blocklist1 = blocklist + '|div|p'; const blocklist2 = blocklist + '|pre'; - /** @type {string[]} */ - const preserve = []; + const preserve: string[] = []; let preserveLinebreaks = false; let preserveBr = false; @@ -480,7 +480,7 @@ export function removep( html ) { // Restore preserved tags. if ( preserve.length ) { html = html.replace( //g, () => { - return /** @type {string} */ ( preserve.shift() ); + return preserve.shift() as string; } ); } diff --git a/packages/autop/src/test/index.test.js b/packages/autop/src/test/index.test.ts similarity index 98% rename from packages/autop/src/test/index.test.js rename to packages/autop/src/test/index.test.ts index 734a20ff37be2..466aade0f25f1 100644 --- a/packages/autop/src/test/index.test.js +++ b/packages/autop/src/test/index.test.ts @@ -311,7 +311,7 @@ test( 'that_autop_treats_block_level_elements_as_blocks', () => { ]; // Check whitespace normalization. - let content = []; + let content: string[] = []; blocks.forEach( ( block ) => { content.push( `<${ block }>foo` ); @@ -388,18 +388,18 @@ test( 'that autop treats inline elements as inline', () => { 'select', ]; - let content = []; - let expected = []; + const content: string[] = []; + const expected: string[] = []; inlines.forEach( ( inline ) => { content.push( `<${ inline }>foo` ); expected.push( `

    <${ inline }>foo

    ` ); } ); - content = content.join( '\n\n' ); - expected = expected.join( '\n' ); + const contentString = content.join( '\n\n' ); + const expectedString = expected.join( '\n' ); - expect( autop( content ).trim() ).toBe( expected ); + expect( autop( contentString ).trim() ).toBe( expectedString ); } ); test( 'element sanity', () => { diff --git a/packages/blob/CHANGELOG.md b/packages/blob/CHANGELOG.md index 50b6143dfb3e6..51fc2b54f9fa2 100644 --- a/packages/blob/CHANGELOG.md +++ b/packages/blob/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Internal + +- Refactor to TypeScript ([#62569](https://github.com/WordPress/gutenberg/pull/62569)). + ## 4.0.0 (2024-05-31) ### Breaking Changes diff --git a/packages/blob/README.md b/packages/blob/README.md index 64520a98bd6a7..d315cdab5e4a4 100644 --- a/packages/blob/README.md +++ b/packages/blob/README.md @@ -61,7 +61,7 @@ _Parameters_ _Returns_ -- `File|undefined`: The file for the blob URL. +- `File | undefined`: The file for the blob URL. ### getBlobTypeByURL @@ -73,7 +73,7 @@ _Parameters_ _Returns_ -- `string|undefined`: The blob type. +- `string | undefined`: The blob type. ### isBlobURL @@ -81,7 +81,7 @@ Check whether a url is a blob url. _Parameters_ -- _url_ `string|undefined`: The URL. +- _url_ `string | undefined`: The URL. _Returns_ diff --git a/packages/blob/src/index.js b/packages/blob/src/index.ts similarity index 66% rename from packages/blob/src/index.js rename to packages/blob/src/index.ts index 2493f81fc4c65..62a6671db6154 100644 --- a/packages/blob/src/index.js +++ b/packages/blob/src/index.ts @@ -1,16 +1,13 @@ -/** - * @type {Record} - */ -const cache = {}; +const cache: Record< string, File > = {}; /** * Create a blob URL from a file. * - * @param {File} file The file to create a blob URL for. + * @param file The file to create a blob URL for. * - * @return {string} The blob URL. + * @return The blob URL. */ -export function createBlobURL( file ) { +export function createBlobURL( file: File ): string { const url = window.URL.createObjectURL( file ); cache[ url ] = file; @@ -23,11 +20,11 @@ export function createBlobURL( file ) { * `createBlobURL` and not removed by `revokeBlobURL`, otherwise it will return * `undefined`. * - * @param {string} url The blob URL. + * @param url The blob URL. * - * @return {File|undefined} The file for the blob URL. + * @return The file for the blob URL. */ -export function getBlobByURL( url ) { +export function getBlobByURL( url: string ): File | undefined { return cache[ url ]; } @@ -36,20 +33,20 @@ export function getBlobByURL( url ) { * `createBlobURL` and not removed by `revokeBlobURL`, otherwise it will return * `undefined`. * - * @param {string} url The blob URL. + * @param url The blob URL. * - * @return {string|undefined} The blob type. + * @return The blob type. */ -export function getBlobTypeByURL( url ) { +export function getBlobTypeByURL( url: string ): string | undefined { return getBlobByURL( url )?.type.split( '/' )[ 0 ]; // 0: media type , 1: file extension eg ( type: 'image/jpeg' ). } /** * Remove the resource and file cache from memory. * - * @param {string} url The blob URL. + * @param url The blob URL. */ -export function revokeBlobURL( url ) { +export function revokeBlobURL( url: string ): void { if ( cache[ url ] ) { window.URL.revokeObjectURL( url ); } @@ -60,11 +57,11 @@ export function revokeBlobURL( url ) { /** * Check whether a url is a blob url. * - * @param {string|undefined} url The URL. + * @param url The URL. * - * @return {boolean} Is the url a blob url? + * @return Is the url a blob url? */ -export function isBlobURL( url ) { +export function isBlobURL( url: string | undefined ): boolean { if ( ! url || ! url.indexOf ) { return false; } @@ -90,11 +87,15 @@ export function isBlobURL( url ) { * downloadBlob( filename, fileContent, 'application/json' ); * ``` * - * @param {string} filename File name. - * @param {BlobPart} content File content (BufferSource | Blob | string). - * @param {string} contentType (Optional) File mime type. Default is `''`. + * @param filename File name. + * @param content File content (BufferSource | Blob | string). + * @param contentType (Optional) File mime type. Default is `''`. */ -export function downloadBlob( filename, content, contentType = '' ) { +export function downloadBlob( + filename: string, + content: BlobPart, + contentType: string = '' +): void { if ( ! filename || ! content ) { return; } diff --git a/packages/blob/src/test/index.js b/packages/blob/src/test/index.ts similarity index 83% rename from packages/blob/src/test/index.js rename to packages/blob/src/test/index.ts index 47dcb5019ee25..381b04fd817a6 100644 --- a/packages/blob/src/test/index.js +++ b/packages/blob/src/test/index.ts @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { isBlobURL, getBlobTypeByURL, downloadBlob } from '../'; +import { isBlobURL, getBlobTypeByURL, downloadBlob } from '..'; describe( 'isBlobURL', () => { it( 'returns true if the url starts with "blob:"', () => { @@ -13,17 +13,23 @@ describe( 'isBlobURL', () => { } ); it( 'returns false if the url is not defined', () => { - expect( isBlobURL() ).toBe( false ); + expect( + // @ts-expect-error This is not a valid call according to types. + isBlobURL() + ).toBe( false ); } ); } ); describe( 'getBlobTypeByURL', () => { it( 'returns undefined if the blob is not found', () => { - expect( getBlobTypeByURL( 'blob:notexisting' ) ).toBe( undefined ); + expect( getBlobTypeByURL( 'blob:notexisting' ) ).toBeUndefined(); } ); it( 'returns undefined if the url is not defined', () => { - expect( getBlobTypeByURL() ).toBe( undefined ); + expect( + // @ts-expect-error This is not a valid call according to types. + getBlobTypeByURL() + ).toBeUndefined(); } ); } ); @@ -36,13 +42,17 @@ describe( 'downloadBlob', () => { const createElementSpy = jest .spyOn( global.document, 'createElement' ) .mockReturnValue( mockAnchorElement ); + const mockBlob = jest.fn(); - const blobSpy = jest.spyOn( window, 'Blob' ).mockReturnValue( mockBlob ); + const blobSpy = jest + .spyOn( window, 'Blob' ) + .mockReturnValue( mockBlob as unknown as Blob ); jest.spyOn( document.body, 'appendChild' ); jest.spyOn( document.body, 'removeChild' ); beforeEach( () => { // Can't seem to spy on these static methods. They are `undefined`. // Possibly overwritten: https://github.com/WordPress/gutenberg/blob/trunk/packages/jest-preset-default/scripts/setup-globals.js#L5 + // @ts-expect-error This is not a valid URL object. window.URL = { createObjectURL, revokeObjectURL, diff --git a/packages/block-editor/src/components/block-actions/index.js b/packages/block-editor/src/components/block-actions/index.js index b34f8eea93615..5e12165c67942 100644 --- a/packages/block-editor/src/components/block-actions/index.js +++ b/packages/block-editor/src/components/block-actions/index.js @@ -31,12 +31,10 @@ export default function BlockActions( { getDirectInsertBlock, canMoveBlocks, canRemoveBlocks, - getBlockEditingMode, } = select( blockEditorStore ); const blocks = getBlocksByClientId( clientIds ); const rootClientId = getBlockRootClientId( clientIds[ 0 ] ); - const rootBlockEditingMode = getBlockEditingMode( rootClientId ); const canInsertDefaultBlock = canInsertBlockType( getDefaultBlockName(), rootClientId @@ -46,11 +44,9 @@ export default function BlockActions( { : null; return { - canMove: canMoveBlocks( clientIds, rootClientId ), - canRemove: canRemoveBlocks( clientIds, rootClientId ), - canInsertBlock: - ( canInsertDefaultBlock || !! directInsertBlock ) && - rootBlockEditingMode === 'default', + canMove: canMoveBlocks( clientIds ), + canRemove: canRemoveBlocks( clientIds ), + canInsertBlock: canInsertDefaultBlock || !! directInsertBlock, canCopyStyles: blocks.every( ( block ) => { return ( !! block && diff --git a/packages/block-editor/src/components/block-draggable/index.js b/packages/block-editor/src/components/block-draggable/index.js index c86bc55e8ed07..0ba2b857bc693 100644 --- a/packages/block-editor/src/components/block-draggable/index.js +++ b/packages/block-editor/src/components/block-draggable/index.js @@ -53,7 +53,7 @@ const BlockDraggable = ( { return { srcRootClientId: rootClientId, - isDraggable: canMoveBlocks( clientIds, rootClientId ), + isDraggable: canMoveBlocks( clientIds ), icon: variation?.icon || _getBlockType( blockName )?.icon, visibleInserter: isBlockInsertionPointVisible(), getBlockType: _getBlockType, diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 030d08b42ce4d..bdf33c944deb1 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -623,8 +623,8 @@ function BlockListBlockProvider( props ) { } const _isSelected = isBlockSelected( clientId ); - const canRemove = canRemoveBlock( clientId, rootClientId ); - const canMove = canMoveBlock( clientId, rootClientId ); + const canRemove = canRemoveBlock( clientId ); + const canMove = canMoveBlock( clientId ); const match = getActiveBlockVariation( blockName, attributes ); const isMultiSelected = isBlockMultiSelected( clientId ); const checkDeep = true; diff --git a/packages/block-editor/src/components/block-list/block.native.js b/packages/block-editor/src/components/block-list/block.native.js index f76021b50fc4b..4112d614da35f 100644 --- a/packages/block-editor/src/components/block-list/block.native.js +++ b/packages/block-editor/src/components/block-list/block.native.js @@ -432,8 +432,8 @@ const applyWithSelect = withSelect( ( select, { clientId, rootClientId } ) => { const attributes = getBlockAttributes( clientId ); const isSelected = isBlockSelected( clientId ); const templateLock = getTemplateLock( rootClientId ); - const canRemove = canRemoveBlock( clientId, rootClientId ); - const canMove = canMoveBlock( clientId, rootClientId ); + const canRemove = canRemoveBlock( clientId ); + const canMove = canMoveBlock( clientId ); // The fallback to `{}` is a temporary fix. // This function should never be called when a block is not present in diff --git a/packages/block-editor/src/components/block-list/use-in-between-inserter.js b/packages/block-editor/src/components/block-list/use-in-between-inserter.js index 044e5b185a224..68fa8628c54c7 100644 --- a/packages/block-editor/src/components/block-list/use-in-between-inserter.js +++ b/packages/block-editor/src/components/block-list/use-in-between-inserter.js @@ -40,7 +40,9 @@ export function useInBetweenInserter() { } function onMouseMove( event ) { - if ( openRef.current ) { + // openRef is the reference to the insertion point between blocks. + // If the reference is not set or the insertion point is already open, return. + if ( openRef === undefined || openRef.current ) { return; } diff --git a/packages/block-editor/src/components/block-lock/use-block-lock.js b/packages/block-editor/src/components/block-lock/use-block-lock.js index da6ccc4092096..9917a739eacd8 100644 --- a/packages/block-editor/src/components/block-lock/use-block-lock.js +++ b/packages/block-editor/src/components/block-lock/use-block-lock.js @@ -24,14 +24,12 @@ export default function useBlockLock( clientId ) { canRemoveBlock, canLockBlockType, getBlockName, - getBlockRootClientId, getTemplateLock, } = select( blockEditorStore ); - const rootClientId = getBlockRootClientId( clientId ); const canEdit = canEditBlock( clientId ); - const canMove = canMoveBlock( clientId, rootClientId ); - const canRemove = canRemoveBlock( clientId, rootClientId ); + const canMove = canMoveBlock( clientId ); + const canRemove = canRemoveBlock( clientId ); return { canEdit, diff --git a/packages/block-editor/src/components/block-mover/index.js b/packages/block-editor/src/components/block-mover/index.js index a143ab391a43f..24f259613351d 100644 --- a/packages/block-editor/src/components/block-mover/index.js +++ b/packages/block-editor/src/components/block-mover/index.js @@ -46,7 +46,7 @@ function BlockMover( { const blockOrder = getBlockOrder( _rootClientId ); return { - canMove: canMoveBlocks( clientIds, _rootClientId ), + canMove: canMoveBlocks( clientIds ), rootClientId: _rootClientId, isFirst: firstIndex === 0, isLast: lastIndex === blockOrder.length - 1, diff --git a/packages/block-editor/src/components/block-mover/index.native.js b/packages/block-editor/src/components/block-mover/index.native.js index 326479cd3bc6e..74a72aec01dbe 100644 --- a/packages/block-editor/src/components/block-mover/index.native.js +++ b/packages/block-editor/src/components/block-mover/index.native.js @@ -166,7 +166,7 @@ export default compose( numberOfBlocks: blockOrder.length - 1, isFirst: firstIndex === 0, isLast: lastIndex === blockOrder.length - 1, - canMove: canMoveBlocks( clientIds, rootClientId ), + canMove: canMoveBlocks( clientIds ), rootClientId, }; } ), diff --git a/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js b/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js index 62c5ff4a5f158..069bd2c9ff1ee 100644 --- a/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js +++ b/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js @@ -256,7 +256,7 @@ export function BlockSettingsDropdown( { { __( 'Duplicate' ) } ) } - { canInsertBlock && ( + { canInsertBlock && ! isContentOnly && ( <> { - const { - getBlockRootClientId, - getBlockAttributes, - canRemoveBlocks, - } = select( blockEditorStore ); + const { getBlockAttributes, canRemoveBlocks } = + select( blockEditorStore ); const { getActiveBlockVariation, getBlockVariations } = select( blocksStore ); - const rootClientId = getBlockRootClientId( - Array.isArray( clientIds ) ? clientIds[ 0 ] : clientIds - ); - const canRemove = canRemoveBlocks( clientIds, rootClientId ); + + const canRemove = canRemoveBlocks( clientIds ); // Only handle single selected blocks for now. if ( blocks.length !== 1 || ! canRemove ) { return EMPTY_OBJECT; diff --git a/packages/block-editor/src/components/block-switcher/index.js b/packages/block-editor/src/components/block-switcher/index.js index 87970d53c19f4..f7f75dd8fa2cc 100644 --- a/packages/block-editor/src/components/block-switcher/index.js +++ b/packages/block-editor/src/components/block-switcher/index.js @@ -191,21 +191,14 @@ export const BlockSwitcher = ( { clientIds, disabled, isUsingBindings } ) => { isTemplate, } = useSelect( ( select ) => { - const { - getBlockRootClientId, - getBlocksByClientId, - getBlockAttributes, - canRemoveBlocks, - } = select( blockEditorStore ); + const { getBlocksByClientId, getBlockAttributes, canRemoveBlocks } = + select( blockEditorStore ); const { getBlockStyles, getBlockType, getActiveBlockVariation } = select( blocksStore ); const _blocks = getBlocksByClientId( clientIds ); if ( ! _blocks.length || _blocks.some( ( block ) => ! block ) ) { return { invalidBlocks: true }; } - const rootClientId = getBlockRootClientId( - Array.isArray( clientIds ) ? clientIds[ 0 ] : clientIds - ); const [ { name: firstBlockName } ] = _blocks; const _isSingleBlockSelected = _blocks.length === 1; const blockType = getBlockType( firstBlockName ); @@ -227,7 +220,7 @@ export const BlockSwitcher = ( { clientIds, disabled, isUsingBindings } ) => { } return { - canRemove: canRemoveBlocks( clientIds, rootClientId ), + canRemove: canRemoveBlocks( clientIds ), hasBlockStyles: _isSingleBlockSelected && !! getBlockStyles( firstBlockName )?.length, diff --git a/packages/block-editor/src/components/block-toolbar/index.js b/packages/block-editor/src/components/block-toolbar/index.js index cffb46413c5bb..6c6acd662ed96 100644 --- a/packages/block-editor/src/components/block-toolbar/index.js +++ b/packages/block-editor/src/components/block-toolbar/index.js @@ -35,9 +35,8 @@ import { store as blockEditorStore } from '../../store'; import __unstableBlockNameContext from './block-name-context'; import NavigableToolbar from '../navigable-toolbar'; import Shuffle from './shuffle'; -import PatternOverridesToolbarIndicator from '../pattern-overrides-toolbar-indicator'; import { useHasBlockToolbar } from './use-has-block-toolbar'; -import { canBindBlock } from '../../hooks/use-bindings-attributes'; + /** * Renders the block toolbar. * @@ -62,18 +61,15 @@ export function PrivateBlockToolbar( { blockClientIds, isDefaultEditingMode, blockType, - blockName, toolbarKey, shouldShowVisualToolbar, showParentSelector, isUsingBindings, - hasParentPattern, } = useSelect( ( select ) => { const { getBlockName, getBlockMode, getBlockParents, - getBlockParentsByBlockName, getSelectedBlockClientIds, isBlockValid, getBlockRootClientId, @@ -96,18 +92,14 @@ export function PrivateBlockToolbar( { const isVisual = selectedBlockClientIds.every( ( id ) => getBlockMode( id ) === 'visual' ); - const bindings = getBlockAttributes( selectedBlockClientId )?.metadata - ?.bindings; - const parentPatternClientId = getBlockParentsByBlockName( - selectedBlockClientId, - 'core/block', - true - )[ 0 ]; + const _isUsingBindings = selectedBlockClientIds.every( + ( clientId ) => + !! getBlockAttributes( clientId )?.metadata?.bindings + ); return { blockClientId: selectedBlockClientId, blockClientIds: selectedBlockClientIds, isDefaultEditingMode: _isDefaultEditingMode, - blockName: _blockName, blockType: selectedBlockClientId && getBlockType( _blockName ), shouldShowVisualToolbar: isValid && isVisual, rootClientId: blockRootClientId, @@ -122,8 +114,7 @@ export function PrivateBlockToolbar( { ) && selectedBlockClientIds.length === 1 && _isDefaultEditingMode, - isUsingBindings: !! bindings, - hasParentPattern: !! parentPatternClientId, + isUsingBindings: _isUsingBindings, }; }, [] ); @@ -176,13 +167,6 @@ export function PrivateBlockToolbar( { { ! isMultiToolbar && isLargeViewport && isDefaultEditingMode && } - { isUsingBindings && - hasParentPattern && - canBindBlock( blockName ) && ( - - ) } { ( shouldShowVisualToolbar || isMultiToolbar ) && ( isDefaultEditingMode || isSynced ) && (
    { const canReset = !! config && ! fastDeepEqual( config, EMPTY_CONFIG ); return [ canReset, - useCallback( - () => setUserConfig( () => EMPTY_CONFIG ), - [ setUserConfig ] - ), + useCallback( () => setUserConfig( EMPTY_CONFIG ), [ setUserConfig ] ), ]; }; diff --git a/packages/block-editor/src/components/global-styles/use-global-styles-output.js b/packages/block-editor/src/components/global-styles/use-global-styles-output.js index 28e1ddac9ab1d..68839ea15d775 100644 --- a/packages/block-editor/src/components/global-styles/use-global-styles-output.js +++ b/packages/block-editor/src/components/global-styles/use-global-styles-output.js @@ -651,7 +651,9 @@ export const getNodesWithStyles = ( tree, blockSelectors ) => { ( [ variationName, variation ] ) => { variations[ variationName ] = pickStyleKeys( variation ); - + if ( variation?.css ) { + variations[ variationName ].css = variation.css; + } const variationSelector = blockSelectors[ blockName ] .styleVariationSelectors?.[ variationName ]; @@ -697,6 +699,14 @@ export const getNodesWithStyles = ( tree, blockSelectors ) => { .featureSelectors ); + const variationBlockStyleNodes = + pickStyleKeys( variationBlockStyles ); + + if ( variationBlockStyles?.css ) { + variationBlockStyleNodes.css = + variationBlockStyles.css; + } + nodes.push( { selector: variationBlockSelector, duotoneSelector: variationDuotoneSelector, @@ -707,9 +717,7 @@ export const getNodesWithStyles = ( tree, blockSelectors ) => { hasLayoutSupport: blockSelectors[ variationBlockName ] .hasLayoutSupport, - styles: pickStyleKeys( - variationBlockStyles - ), + styles: variationBlockStyleNodes, } ); // Process element styles for the inner blocks @@ -995,6 +1003,12 @@ export const toStyles = ( ';' ) };}`; } + if ( styles?.css ) { + ruleset += processCSSNesting( + styles.css, + `:root :where(${ selector })` + ); + } if ( styleVariationSelectors ) { Object.entries( styleVariationSelectors ).forEach( @@ -1041,6 +1055,12 @@ export const toStyles = ( ';' ) };}`; } + if ( styleVariations?.css ) { + ruleset += processCSSNesting( + styleVariations.css, + `:root :where(${ styleVariationSelector })` + ); + } } } ); diff --git a/packages/block-editor/src/components/list-view/block.js b/packages/block-editor/src/components/list-view/block.js index 4db12c4d8b77c..0f6541f9f5b3b 100644 --- a/packages/block-editor/src/components/list-view/block.js +++ b/packages/block-editor/src/components/list-view/block.js @@ -210,7 +210,7 @@ function ListViewBlock( { } = getBlocksToUpdate(); // Don't update the selection if the blocks cannot be deleted. - if ( ! canRemoveBlocks( blocksToDelete, firstBlockRootClientId ) ) { + if ( ! canRemoveBlocks( blocksToDelete ) ) { return; } diff --git a/packages/block-editor/src/components/list-view/use-clipboard-handler.js b/packages/block-editor/src/components/list-view/use-clipboard-handler.js index dd3ac65ac79d2..e7c3026e70f09 100644 --- a/packages/block-editor/src/components/list-view/use-clipboard-handler.js +++ b/packages/block-editor/src/components/list-view/use-clipboard-handler.js @@ -112,12 +112,7 @@ export default function useClipboardHandler( { selectBlock } ) { if ( event.type === 'cut' ) { // Don't update the selection if the blocks cannot be deleted. - if ( - ! canRemoveBlocks( - selectedBlockClientIds, - firstBlockRootClientId - ) - ) { + if ( ! canRemoveBlocks( selectedBlockClientIds ) ) { return; } diff --git a/packages/block-editor/src/components/pattern-overrides-toolbar-indicator/index.js b/packages/block-editor/src/components/pattern-overrides-toolbar-indicator/index.js deleted file mode 100644 index af359da542d37..0000000000000 --- a/packages/block-editor/src/components/pattern-overrides-toolbar-indicator/index.js +++ /dev/null @@ -1,120 +0,0 @@ -/** - * WordPress dependencies - */ -import { useId } from '@wordpress/element'; -import { __, sprintf } from '@wordpress/i18n'; -import { - DropdownMenu, - ToolbarGroup, - ToolbarItem, - __experimentalText as Text, -} from '@wordpress/components'; -import { store as blocksStore } from '@wordpress/blocks'; -import { useSelect } from '@wordpress/data'; -import { copy } from '@wordpress/icons'; - -/** - * Internal dependencies - */ -import { store as blockEditorStore } from '../../store'; -import BlockIcon from '../block-icon'; -import useBlockDisplayTitle from '../block-title/use-block-display-title'; - -/** - * This component is currently only for pattern overrides, which is a WP-only feature. - * Ideally, this should be moved to the `patterns` package once ready. - * @param {Object} props The component props. - * @param {Array} props.clientIds The client IDs of the selected blocks. - */ -export default function PatternOverridesToolbarIndicator( { clientIds } ) { - const isSingleBlockSelected = clientIds.length === 1; - const { icon, firstBlockName } = useSelect( - ( select ) => { - const { getBlockAttributes, getBlockNamesByClientId } = - select( blockEditorStore ); - const { getBlockType, getActiveBlockVariation } = - select( blocksStore ); - const blockTypeNames = getBlockNamesByClientId( clientIds ); - const _firstBlockTypeName = blockTypeNames[ 0 ]; - const firstBlockType = getBlockType( _firstBlockTypeName ); - let _icon; - if ( isSingleBlockSelected ) { - const match = getActiveBlockVariation( - _firstBlockTypeName, - getBlockAttributes( clientIds[ 0 ] ) - ); - // Take into account active block variations. - _icon = match?.icon || firstBlockType.icon; - } else { - const isSelectionOfSameType = - new Set( blockTypeNames ).size === 1; - // When selection consists of blocks of multiple types, display an - // appropriate icon to communicate the non-uniformity. - _icon = isSelectionOfSameType ? firstBlockType.icon : copy; - } - - return { - icon: _icon, - firstBlockName: getBlockAttributes( clientIds[ 0 ] ).metadata - .name, - }; - }, - [ clientIds, isSingleBlockSelected ] - ); - const firstBlockTitle = useBlockDisplayTitle( { - clientId: clientIds[ 0 ], - maximumLength: 35, - } ); - - const blockDescription = isSingleBlockSelected - ? sprintf( - /* translators: %1s: The block type's name; %2s: The block's user-provided name (the same as the override name). */ - __( 'This %1$s is editable using the "%2$s" override.' ), - firstBlockTitle.toLowerCase(), - firstBlockName - ) - : __( 'These blocks are editable using overrides.' ); - - const descriptionId = useId(); - - return ( - - - { ( toggleProps ) => ( - - - - } - toggleProps={ { - describedBy: blockDescription, - ...toggleProps, - } } - menuProps={ { - orientation: 'both', - 'aria-describedby': descriptionId, - } } - > - { () => ( - - { blockDescription } - - ) } - - ) } - - - ); -} diff --git a/packages/block-editor/src/components/pattern-overrides-toolbar-indicator/style.scss b/packages/block-editor/src/components/pattern-overrides-toolbar-indicator/style.scss deleted file mode 100644 index 90b2c1cdd79a5..0000000000000 --- a/packages/block-editor/src/components/pattern-overrides-toolbar-indicator/style.scss +++ /dev/null @@ -1,12 +0,0 @@ -.block-editor-pattern-overrides-toolbar-indicator__popover .components-popover__content { - min-width: 260px; - padding: $grid-unit-20; -} - -.block-editor-pattern-overrides-toolbar-indicator .block-editor-pattern-overrides-toolbar-indicator-icon.has-colors svg { - fill: var(--wp-block-synced-color); -} - -.editor-collapsible-block-toolbar .block-editor-pattern-overrides-toolbar-indicator { - height: 32px; -} diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js index 2697f5fdf154b..9390c71bdcf0b 100644 --- a/packages/block-editor/src/components/rich-text/index.native.js +++ b/packages/block-editor/src/components/rich-text/index.native.js @@ -80,6 +80,7 @@ export function RichTextWrapper( unstableOnFocus, __unstableAllowPrefixTransformations, // Native props. + __unstableUseSplitSelection, __unstableMobileNoFocusOnMount, deleteEnter, placeholderTextColor, @@ -178,6 +179,7 @@ export function RichTextWrapper( exitFormattedText, selectionChange, __unstableMarkAutomaticChange, + __unstableSplitSelection, clearSelectedBlock, } = useDispatch( blockEditorStore ); const adjustedAllowedFormats = getAllowedFormats( { @@ -345,6 +347,8 @@ export function RichTextWrapper( } } else if ( canSplit ) { splitValue( value ); + } else if ( __unstableUseSplitSelection ) { + __unstableSplitSelection(); } else if ( canSplitAtEnd ) { onSplitAtEnd(); } else if ( diff --git a/packages/block-editor/src/components/rich-text/native/index.native.js b/packages/block-editor/src/components/rich-text/native/index.native.js index aa06c4dd1e892..4eeaabe6d790a 100644 --- a/packages/block-editor/src/components/rich-text/native/index.native.js +++ b/packages/block-editor/src/components/rich-text/native/index.native.js @@ -424,7 +424,9 @@ export class RichText extends Component { return; } - onDelete( { isReverse, value } ); + if ( onDelete ) { + onDelete( { isReverse, value } ); + } event.preventDefault(); this.lastAztecEventType = 'input'; diff --git a/packages/block-editor/src/components/spacing-sizes-control/hooks/use-spacing-sizes.js b/packages/block-editor/src/components/spacing-sizes-control/hooks/use-spacing-sizes.js index 9943978c15af1..d822dd200b626 100644 --- a/packages/block-editor/src/components/spacing-sizes-control/hooks/use-spacing-sizes.js +++ b/packages/block-editor/src/components/spacing-sizes-control/hooks/use-spacing-sizes.js @@ -44,15 +44,8 @@ export default function useSpacingSizes() { ...defaultSizes, ]; - // Only sort if more than one origin has presets defined in order to - // preserve order for themes that don't include default presets and - // want a custom order. - if ( - ( customSizes.length && 1 ) + - ( themeSizes.length && 1 ) + - ( defaultSizes.length && 1 ) > - 1 - ) { + // Using numeric slugs opts-in to sorting by slug. + if ( sizes.every( ( { slug } ) => /^[0-9]/.test( slug ) ) ) { sizes.sort( ( a, b ) => compare( a.slug, b.slug ) ); } diff --git a/packages/block-editor/src/components/use-block-commands/index.js b/packages/block-editor/src/components/use-block-commands/index.js index 1b3a1d2215f81..8a09999ecdff3 100644 --- a/packages/block-editor/src/components/use-block-commands/index.js +++ b/packages/block-editor/src/components/use-block-commands/index.js @@ -65,7 +65,7 @@ export const useTransformCommands = () => { selectedBlocks, rootClientId ), - canRemove: canRemoveBlocks( selectedBlockClientIds, rootClientId ), + canRemove: canRemoveBlocks( selectedBlockClientIds ), invalidSelection: false, }; }, [] ); @@ -150,8 +150,7 @@ const useActionsCommands = () => { const rootClientId = getBlockRootClientId( clientIds[ 0 ] ); const canMove = - canMoveBlocks( clientIds, rootClientId ) && - getBlockCount( rootClientId ) !== 1; + canMoveBlocks( clientIds ) && getBlockCount( rootClientId ) !== 1; const commands = []; @@ -260,7 +259,7 @@ const useQuickActionsCommands = () => { canInsertBlockType( block.name, rootClientId ) ); } ); - const canRemove = canRemoveBlocks( clientIds, rootClientId ); + const canRemove = canRemoveBlocks( clientIds ); const commands = []; diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index 334c751bc01b0..7bd5df05d31eb 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -97,6 +97,9 @@ export const withBlockBindingSupport = createHigherOrderComponent( unlock( select( blocksStore ) ).getAllBlockBindingsSources() ); const { name, clientId, context } = props; + const hasPatternOverridesDefaultBinding = + props.attributes.metadata?.bindings?.[ DEFAULT_ATTRIBUTE ] + ?.source === 'core/pattern-overrides'; const bindings = useMemo( () => replacePatternOverrideDefaultBindings( @@ -213,7 +216,13 @@ export const withBlockBindingSupport = createHigherOrderComponent( } } - if ( Object.keys( keptAttributes ).length ) { + // Only apply normal attribute updates to blocks + // that have partial bindings. Currently this is + // only skipped for pattern overrides sources. + if ( + ! hasPatternOverridesDefaultBinding && + Object.keys( keptAttributes ).length + ) { setAttributes( keptAttributes ); } } ); @@ -226,6 +235,7 @@ export const withBlockBindingSupport = createHigherOrderComponent( context, setAttributes, sources, + hasPatternOverridesDefaultBinding, ] ); diff --git a/packages/block-editor/src/private-apis.js b/packages/block-editor/src/private-apis.js index 848a3ee49251b..e6f3fc4cc39d6 100644 --- a/packages/block-editor/src/private-apis.js +++ b/packages/block-editor/src/private-apis.js @@ -43,6 +43,7 @@ import { PrivateBlockPopover } from './components/block-popover'; import { PrivateInserterLibrary } from './components/inserter/library'; import { PrivatePublishDateTimePicker } from './components/publish-date-time-picker'; import useSpacingSizes from './components/spacing-sizes-control/hooks/use-spacing-sizes'; +import useBlockDisplayTitle from './components/block-title/use-block-display-title'; /** * Private @wordpress/block-editor APIs. @@ -86,4 +87,5 @@ lock( privateApis, { PrivateBlockPopover, PrivatePublishDateTimePicker, useSpacingSizes, + useBlockDisplayTitle, } ); diff --git a/packages/block-editor/src/store/actions.js b/packages/block-editor/src/store/actions.js index d44fa3e69f86a..d80b8202a371a 100644 --- a/packages/block-editor/src/store/actions.js +++ b/packages/block-editor/src/store/actions.js @@ -409,7 +409,7 @@ const createOnMove = ( clientIds, rootClientId ) => ( { select, dispatch } ) => { // If one of the blocks is locked or the parent is locked, we cannot move any block. - const canMoveBlocks = select.canMoveBlocks( clientIds, rootClientId ); + const canMoveBlocks = select.canMoveBlocks( clientIds ); if ( ! canMoveBlocks ) { return; } @@ -431,10 +431,7 @@ export const moveBlocksUp = createOnMove( 'MOVE_BLOCKS_UP' ); export const moveBlocksToPosition = ( clientIds, fromRootClientId = '', toRootClientId = '', index ) => ( { select, dispatch } ) => { - const canMoveBlocks = select.canMoveBlocks( - clientIds, - fromRootClientId - ); + const canMoveBlocks = select.canMoveBlocks( clientIds ); // If one of the blocks is locked or the parent is locked, we cannot move any block. if ( ! canMoveBlocks ) { @@ -443,10 +440,7 @@ export const moveBlocksToPosition = // If moving inside the same root block the move is always possible. if ( fromRootClientId !== toRootClientId ) { - const canRemoveBlocks = select.canRemoveBlocks( - clientIds, - fromRootClientId - ); + const canRemoveBlocks = select.canRemoveBlocks( clientIds ); // If we're moving to another block, it means we're deleting blocks from // the original block, so we need to check if removing is possible. diff --git a/packages/block-editor/src/store/private-actions.js b/packages/block-editor/src/store/private-actions.js index 5e4e0c7a222b0..74aec3c49d1e8 100644 --- a/packages/block-editor/src/store/private-actions.js +++ b/packages/block-editor/src/store/private-actions.js @@ -104,11 +104,7 @@ export const privateRemoveBlocks = } clientIds = castArray( clientIds ); - const rootClientId = select.getBlockRootClientId( clientIds[ 0 ] ); - const canRemoveBlocks = select.canRemoveBlocks( - clientIds, - rootClientId - ); + const canRemoveBlocks = select.canRemoveBlocks( clientIds ); if ( ! canRemoveBlocks ) { return; diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index bf98521dfe9b6..d78d75e4210c8 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -1712,13 +1712,12 @@ export function canInsertBlocks( state, clientIds, rootClientId = null ) { /** * Determines if the given block is allowed to be deleted. * - * @param {Object} state Editor state. - * @param {string} clientId The block client Id. - * @param {?string} rootClientId Optional root client ID of block list. + * @param {Object} state Editor state. + * @param {string} clientId The block client Id. * * @return {boolean} Whether the given block is allowed to be removed. */ -export function canRemoveBlock( state, clientId, rootClientId = null ) { +export function canRemoveBlock( state, clientId ) { const attributes = getBlockAttributes( state, clientId ); if ( attributes === null ) { return true; @@ -1726,6 +1725,8 @@ export function canRemoveBlock( state, clientId, rootClientId = null ) { if ( attributes.lock?.remove !== undefined ) { return ! attributes.lock.remove; } + + const rootClientId = getBlockRootClientId( state, clientId ); if ( getTemplateLock( state, rootClientId ) ) { return false; } @@ -1736,28 +1737,24 @@ export function canRemoveBlock( state, clientId, rootClientId = null ) { /** * Determines if the given blocks are allowed to be removed. * - * @param {Object} state Editor state. - * @param {string} clientIds The block client IDs to be removed. - * @param {?string} rootClientId Optional root client ID of block list. + * @param {Object} state Editor state. + * @param {string} clientIds The block client IDs to be removed. * * @return {boolean} Whether the given blocks are allowed to be removed. */ -export function canRemoveBlocks( state, clientIds, rootClientId = null ) { - return clientIds.every( ( clientId ) => - canRemoveBlock( state, clientId, rootClientId ) - ); +export function canRemoveBlocks( state, clientIds ) { + return clientIds.every( ( clientId ) => canRemoveBlock( state, clientId ) ); } /** * Determines if the given block is allowed to be moved. * - * @param {Object} state Editor state. - * @param {string} clientId The block client Id. - * @param {?string} rootClientId Optional root client ID of block list. + * @param {Object} state Editor state. + * @param {string} clientId The block client Id. * * @return {boolean | undefined} Whether the given block is allowed to be moved. */ -export function canMoveBlock( state, clientId, rootClientId = null ) { +export function canMoveBlock( state, clientId ) { const attributes = getBlockAttributes( state, clientId ); if ( attributes === null ) { return true; @@ -1765,6 +1762,8 @@ export function canMoveBlock( state, clientId, rootClientId = null ) { if ( attributes.lock?.move !== undefined ) { return ! attributes.lock.move; } + + const rootClientId = getBlockRootClientId( state, clientId ); if ( getTemplateLock( state, rootClientId ) === 'all' ) { return false; } @@ -1774,16 +1773,13 @@ export function canMoveBlock( state, clientId, rootClientId = null ) { /** * Determines if the given blocks are allowed to be moved. * - * @param {Object} state Editor state. - * @param {string} clientIds The block client IDs to be moved. - * @param {?string} rootClientId Optional root client ID of block list. + * @param {Object} state Editor state. + * @param {string} clientIds The block client IDs to be moved. * * @return {boolean} Whether the given blocks are allowed to be moved. */ -export function canMoveBlocks( state, clientIds, rootClientId = null ) { - return clientIds.every( ( clientId ) => - canMoveBlock( state, clientId, rootClientId ) - ); +export function canMoveBlocks( state, clientIds ) { + return clientIds.every( ( clientId ) => canMoveBlock( state, clientId ) ); } /** @@ -3041,10 +3037,7 @@ export const isGroupable = createRegistrySelector( rootClientId ); const _isGroupable = groupingBlockAvailable && _clientIds.length; - return ( - _isGroupable && - canRemoveBlocks( state, _clientIds, rootClientId ) - ); + return _isGroupable && canRemoveBlocks( state, _clientIds ); } ); diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss index d22ea9b3d0a28..cf4683b02c707 100644 --- a/packages/block-editor/src/style.scss +++ b/packages/block-editor/src/style.scss @@ -1,6 +1,5 @@ @import "./autocompleters/style.scss"; @import "./components/block-alignment-control/style.scss"; -@import "./components/pattern-overrides-toolbar-indicator/style.scss"; @import "./components/block-canvas/style.scss"; @import "./components/block-icon/style.scss"; @import "./components/block-inspector/style.scss"; diff --git a/packages/block-library/src/list-item/edit.native.js b/packages/block-library/src/list-item/edit.native.js index 89f7bd0ace0b7..2367529242ded 100644 --- a/packages/block-library/src/list-item/edit.native.js +++ b/packages/block-library/src/list-item/edit.native.js @@ -21,8 +21,7 @@ import { useState, useCallback, useRef } from '@wordpress/element'; /** * Internal dependencies */ -import { useSplit, useMerge, useEnter } from './hooks'; -import { convertToListItems } from './utils'; +import { useMerge, useEnter } from './hooks'; import { IndentUI } from './edit.js'; import styles from './style.scss'; import ListStyleType from './list-style-type'; @@ -32,7 +31,6 @@ const OPACITY = '9e'; export default function ListItemEdit( { attributes, setAttributes, - onReplace, clientId, style, mergeBlocks, @@ -118,24 +116,7 @@ export default function ListItemEdit( { const preventDefault = useRef( false ); const { onEnter } = useEnter( { content, clientId }, preventDefault ); - const onSplit = useSplit( clientId ); const onMerge = useMerge( clientId, mergeBlocks ); - const onSplitList = useCallback( - ( value ) => { - if ( ! preventDefault.current ) { - return onSplit( value ); - } - }, - [ clientId, onSplit ] - ); - const onReplaceList = useCallback( - ( blocks, ...args ) => { - if ( ! preventDefault.current ) { - onReplace( convertToListItems( blocks ), ...args ); - } - }, - [ clientId, onReplace, convertToListItems ] - ); const onLayout = useCallback( ( { nativeEvent } ) => { setContentWidth( ( prevState ) => { const { width } = nativeEvent.layout; @@ -166,6 +147,7 @@ export default function ListItemEdit( { onLayout={ onLayout } > @@ -176,9 +158,7 @@ export default function ListItemEdit( { placeholderTextColor={ defaultPlaceholderTextColorWithOpacity } - onSplit={ onSplitList } onMerge={ onMerge } - onReplace={ onReplaceList } onEnter={ onEnter } style={ styleWithPlaceholderOpacity } deleteEnter diff --git a/packages/block-library/src/post-content/block.json b/packages/block-library/src/post-content/block.json index b0e0487a0b824..a2d3094137545 100644 --- a/packages/block-library/src/post-content/block.json +++ b/packages/block-library/src/post-content/block.json @@ -11,11 +11,23 @@ "align": [ "wide", "full" ], "html": false, "layout": true, + "background": { + "backgroundImage": true, + "backgroundSize": true, + "__experimentalDefaultControls": { + "backgroundImage": true + } + }, "dimensions": { "minHeight": true }, "spacing": { - "blockGap": true + "blockGap": true, + "padding": true, + "__experimentalDefaultControls": { + "margin": false, + "padding": false + } }, "color": { "gradients": true, diff --git a/packages/core-data/src/entity-types/helpers.ts b/packages/core-data/src/entity-types/helpers.ts index 943dece90e353..5d5c5b44e6497 100644 --- a/packages/core-data/src/entity-types/helpers.ts +++ b/packages/core-data/src/entity-types/helpers.ts @@ -132,7 +132,7 @@ export interface RenderedText< C extends Context > { * For example, in the block editor, content.rendered could used as a visual preview, and * content.raw could be used to populate the code editor. * - * When updating these rendered fields, Javascript is not be able to properly render arbitrary block + * When updating these rendered fields, JavaScript is not be able to properly render arbitrary block * markup. Therefore, it stores only the raw markup without the rendered part. And since that's a string, * the entire field becomes a string. * diff --git a/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.js b/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.js deleted file mode 100644 index 3bba760b20c45..0000000000000 --- a/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.js +++ /dev/null @@ -1,237 +0,0 @@ -/** - * WordPress dependencies - */ -import apiFetch from '@wordpress/api-fetch'; -import { addQueryArgs } from '@wordpress/url'; -import { decodeEntities } from '@wordpress/html-entities'; -import { __ } from '@wordpress/i18n'; - -/** - * Filters the search by type - * - * @typedef { 'attachment' | 'post' | 'term' | 'post-format' } WPLinkSearchType - */ - -/** - * A link with an id may be of kind post-type or taxonomy - * - * @typedef { 'post-type' | 'taxonomy' } WPKind - */ - -/** - * @typedef WPLinkSearchOptions - * - * @property {boolean} [isInitialSuggestions] Displays initial search suggestions, when true. - * @property {WPLinkSearchType} [type] Filters by search type. - * @property {string} [subtype] Slug of the post-type or taxonomy. - * @property {number} [page] Which page of results to return. - * @property {number} [perPage] Search results per page. - */ - -/** - * @typedef WPLinkSearchResult - * - * @property {number} id Post or term id. - * @property {string} url Link url. - * @property {string} title Title of the link. - * @property {string} type The taxonomy or post type slug or type URL. - * @property {WPKind} [kind] Link kind of post-type or taxonomy - */ - -/** - * @typedef WPLinkSearchResultAugments - * - * @property {{kind: WPKind}} [meta] Contains kind information. - * @property {WPKind} [subtype] Optional subtype if it exists. - */ - -/** - * @typedef {WPLinkSearchResult & WPLinkSearchResultAugments} WPLinkSearchResultAugmented - */ - -/** - * @typedef WPEditorSettings - * - * @property {boolean} [ disablePostFormats ] Disables post formats, when true. - */ - -/** - * Fetches link suggestions from the API. - * - * @async - * @param {string} search - * @param {WPLinkSearchOptions} [searchOptions] - * @param {WPEditorSettings} [settings] - * - * @example - * ```js - * import { __experimentalFetchLinkSuggestions as fetchLinkSuggestions } from '@wordpress/core-data'; - * - * //... - * - * export function initialize( id, settings ) { - * - * settings.__experimentalFetchLinkSuggestions = ( - * search, - * searchOptions - * ) => fetchLinkSuggestions( search, searchOptions, settings ); - * ``` - * @return {Promise< WPLinkSearchResult[] >} List of search suggestions - */ -const fetchLinkSuggestions = async ( - search, - searchOptions = {}, - settings = {} -) => { - const { - isInitialSuggestions = false, - initialSuggestionsSearchOptions = undefined, - } = searchOptions; - - const { disablePostFormats = false } = settings; - - let { - type = undefined, - subtype = undefined, - page = undefined, - perPage = isInitialSuggestions ? 3 : 20, - } = searchOptions; - - /** @type {Promise[]} */ - const queries = []; - - if ( isInitialSuggestions && initialSuggestionsSearchOptions ) { - type = initialSuggestionsSearchOptions.type || type; - subtype = initialSuggestionsSearchOptions.subtype || subtype; - page = initialSuggestionsSearchOptions.page || page; - perPage = initialSuggestionsSearchOptions.perPage || perPage; - } - - if ( ! type || type === 'post' ) { - queries.push( - apiFetch( { - path: addQueryArgs( '/wp/v2/search', { - search, - page, - per_page: perPage, - type: 'post', - subtype, - } ), - } ) - .then( ( results ) => { - return results.map( ( result ) => { - return { - ...result, - meta: { kind: 'post-type', subtype }, - }; - } ); - } ) - .catch( () => [] ) // Fail by returning no results. - ); - } - - if ( ! type || type === 'term' ) { - queries.push( - apiFetch( { - path: addQueryArgs( '/wp/v2/search', { - search, - page, - per_page: perPage, - type: 'term', - subtype, - } ), - } ) - .then( ( results ) => { - return results.map( ( result ) => { - return { - ...result, - meta: { kind: 'taxonomy', subtype }, - }; - } ); - } ) - .catch( () => [] ) // Fail by returning no results. - ); - } - - if ( ! disablePostFormats && ( ! type || type === 'post-format' ) ) { - queries.push( - apiFetch( { - path: addQueryArgs( '/wp/v2/search', { - search, - page, - per_page: perPage, - type: 'post-format', - subtype, - } ), - } ) - .then( ( results ) => { - return results.map( ( result ) => { - return { - ...result, - meta: { kind: 'taxonomy', subtype }, - }; - } ); - } ) - .catch( () => [] ) // Fail by returning no results. - ); - } - - if ( ! type || type === 'attachment' ) { - queries.push( - apiFetch( { - path: addQueryArgs( '/wp/v2/media', { - search, - page, - per_page: perPage, - } ), - } ) - .then( ( results ) => { - return results.map( ( result ) => { - return { - ...result, - meta: { kind: 'media' }, - }; - } ); - } ) - .catch( () => [] ) // Fail by returning no results. - ); - } - - return Promise.all( queries ).then( ( results ) => { - return results - .reduce( - ( /** @type {WPLinkSearchResult[]} */ accumulator, current ) => - accumulator.concat( current ), // Flatten list. - [] - ) - .filter( - /** - * @param {{ id: number }} result - */ - ( result ) => { - return !! result.id; - } - ) - .slice( 0, perPage ) - .map( ( /** @type {WPLinkSearchResultAugmented} */ result ) => { - const isMedia = result.type === 'attachment'; - - return { - id: result.id, - // @ts-ignore fix when we make this a TS file - url: isMedia ? result.source_url : result.url, - title: - decodeEntities( - isMedia - ? // @ts-ignore fix when we make this a TS file - result.title.rendered - : result.title || '' - ) || __( '(no title)' ), - type: result.subtype || result.type, - kind: result?.meta?.kind, - }; - } ); - } ); -}; - -export default fetchLinkSuggestions; diff --git a/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.ts b/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.ts new file mode 100644 index 0000000000000..024a5931abbd8 --- /dev/null +++ b/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.ts @@ -0,0 +1,296 @@ +/** + * WordPress dependencies + */ +import apiFetch from '@wordpress/api-fetch'; +import { addQueryArgs } from '@wordpress/url'; +import { decodeEntities } from '@wordpress/html-entities'; +import { __ } from '@wordpress/i18n'; + +export type SearchOptions = { + /** + * Displays initial search suggestions, when true. + */ + isInitialSuggestions?: boolean; + /** + * Search options for initial suggestions. + */ + initialSuggestionsSearchOptions?: Omit< + SearchOptions, + 'isInitialSuggestions' | 'initialSuggestionsSearchOptions' + >; + /** + * Filters by search type. + */ + type?: 'attachment' | 'post' | 'term' | 'post-format'; + /** + * Slug of the post-type or taxonomy. + */ + subtype?: string; + /** + * Which page of results to return. + */ + page?: number; + /** + * Search results per page. + */ + perPage?: number; +}; + +export type EditorSettings = { + /** + * Disables post formats, when true. + */ + disablePostFormats?: boolean; +}; + +type SearchAPIResult = { + id: number; + title: string; + url: string; + type: string; + subtype: string; +}; + +type MediaAPIResult = { + id: number; + title: { rendered: string }; + source_url: string; + type: string; +}; + +export type SearchResult = { + /** + * Post or term id. + */ + id: number; + /** + * Link url. + */ + url: string; + /** + * Title of the link. + */ + title: string; + /** + * The taxonomy or post type slug or type URL. + */ + type: string; + /** + * Link kind of post-type or taxonomy + */ + kind?: string; +}; + +/** + * Fetches link suggestions from the WordPress API. + * + * WordPress does not support searching multiple tables at once, e.g. posts and terms, so we + * perform multiple queries at the same time and then merge the results together. + * + * @param search + * @param searchOptions + * @param editorSettings + * + * @example + * ```js + * import { __experimentalFetchLinkSuggestions as fetchLinkSuggestions } from '@wordpress/core-data'; + * + * //... + * + * export function initialize( id, settings ) { + * + * settings.__experimentalFetchLinkSuggestions = ( + * search, + * searchOptions + * ) => fetchLinkSuggestions( search, searchOptions, settings ); + * ``` + */ +export default async function fetchLinkSuggestions( + search: string, + searchOptions: SearchOptions = {}, + editorSettings: EditorSettings = {} +): Promise< SearchResult[] > { + const searchOptionsToUse = + searchOptions.isInitialSuggestions && + searchOptions.initialSuggestionsSearchOptions + ? { + ...searchOptions, + ...searchOptions.initialSuggestionsSearchOptions, + } + : searchOptions; + + const { + type, + subtype, + page, + perPage = searchOptions.isInitialSuggestions ? 3 : 20, + } = searchOptionsToUse; + + const { disablePostFormats = false } = editorSettings; + + const queries: Promise< SearchResult[] >[] = []; + + if ( ! type || type === 'post' ) { + queries.push( + apiFetch< SearchAPIResult[] >( { + path: addQueryArgs( '/wp/v2/search', { + search, + page, + per_page: perPage, + type: 'post', + subtype, + } ), + } ) + .then( ( results ) => { + return results.map( ( result ) => { + return { + id: result.id, + url: result.url, + title: + decodeEntities( result.title || '' ) || + __( '(no title)' ), + type: result.subtype || result.type, + kind: 'post-type', + }; + } ); + } ) + .catch( () => [] ) // Fail by returning no results. + ); + } + + if ( ! type || type === 'term' ) { + queries.push( + apiFetch< SearchAPIResult[] >( { + path: addQueryArgs( '/wp/v2/search', { + search, + page, + per_page: perPage, + type: 'term', + subtype, + } ), + } ) + .then( ( results ) => { + return results.map( ( result ) => { + return { + id: result.id, + url: result.url, + title: + decodeEntities( result.title || '' ) || + __( '(no title)' ), + type: result.subtype || result.type, + kind: 'taxonomy', + }; + } ); + } ) + .catch( () => [] ) // Fail by returning no results. + ); + } + + if ( ! disablePostFormats && ( ! type || type === 'post-format' ) ) { + queries.push( + apiFetch< SearchAPIResult[] >( { + path: addQueryArgs( '/wp/v2/search', { + search, + page, + per_page: perPage, + type: 'post-format', + subtype, + } ), + } ) + .then( ( results ) => { + return results.map( ( result ) => { + return { + id: result.id, + url: result.url, + title: + decodeEntities( result.title || '' ) || + __( '(no title)' ), + type: result.subtype || result.type, + kind: 'taxonomy', + }; + } ); + } ) + .catch( () => [] ) // Fail by returning no results. + ); + } + + if ( ! type || type === 'attachment' ) { + queries.push( + apiFetch< MediaAPIResult[] >( { + path: addQueryArgs( '/wp/v2/media', { + search, + page, + per_page: perPage, + } ), + } ) + .then( ( results ) => { + return results.map( ( result ) => { + return { + id: result.id, + url: result.source_url, + title: + decodeEntities( result.title.rendered || '' ) || + __( '(no title)' ), + type: result.type, + kind: 'media', + }; + } ); + } ) + .catch( () => [] ) // Fail by returning no results. + ); + } + + const responses = await Promise.all( queries ); + + let results = responses.flat(); + results = results.filter( ( result ) => !! result.id ); + results = sortResults( results, search ); + results = results.slice( 0, perPage ); + return results; +} + +/** + * Sort search results by relevance to the given query. + * + * Sorting is necessary as we're querying multiple endpoints and merging the results. For example + * a taxonomy title might be more relevant than a post title, but by default taxonomy results will + * be ordered after all the (potentially irrelevant) post results. + * + * We sort by scoring each result, where the score is the number of tokens in the title that are + * also in the search query, divided by the total number of tokens in the title. This gives us a + * score between 0 and 1, where 1 is a perfect match. + * + * @param results + * @param search + */ +export function sortResults( results: SearchResult[], search: string ) { + const searchTokens = new Set( tokenize( search ) ); + + const scores = {}; + for ( const result of results ) { + if ( result.title ) { + const titleTokens = tokenize( result.title ); + const matchingTokens = titleTokens.filter( ( token ) => + searchTokens.has( token ) + ); + scores[ result.id ] = matchingTokens.length / titleTokens.length; + } else { + scores[ result.id ] = 0; + } + } + + return results.sort( ( a, b ) => scores[ b.id ] - scores[ a.id ] ); +} + +/** + * Turns text into an array of tokens, with whitespace and punctuation removed. + * + * For example, `"I'm having a ball."` becomes `[ "im", "having", "a", "ball" ]`. + * + * @param text + */ +export function tokenize( text: string ): string[] { + // \p{L} matches any kind of letter from any language. + // \p{N} matches any kind of numeric character. + return text.toLowerCase().match( /[\p{L}\p{N}]+/gu ) || []; +} diff --git a/packages/core-data/src/fetch/test/__experimental-fetch-link-suggestions.js b/packages/core-data/src/fetch/test/__experimental-fetch-link-suggestions.js index d283226cca090..6878c74332c3d 100644 --- a/packages/core-data/src/fetch/test/__experimental-fetch-link-suggestions.js +++ b/packages/core-data/src/fetch/test/__experimental-fetch-link-suggestions.js @@ -1,7 +1,11 @@ /** * Internal dependencies */ -import fetchLinkSuggestions from '../__experimental-fetch-link-suggestions'; +import { + default as fetchLinkSuggestions, + sortResults, + tokenize, +} from '../__experimental-fetch-link-suggestions'; jest.mock( '@wordpress/api-fetch', () => jest.fn( ( { path } ) => { @@ -317,3 +321,93 @@ describe( 'fetchLinkSuggestions', () => { ); } ); } ); + +describe( 'sortResults', () => { + it( 'returns empty array for empty results', () => { + expect( sortResults( [], '' ) ).toEqual( [] ); + } ); + + it( 'orders results', () => { + const results = [ + { + id: 1, + title: 'How to get from Stockholm to Helsinki by boat', + url: 'http://wordpress.local/stockholm-helsinki-boat/', + type: 'page', + kind: 'post-type', + }, + { + id: 2, + title: 'A day trip from Stockholm to Swedish countryside towns', + url: 'http://wordpress.local/day-trip-stockholm/', + type: 'page', + kind: 'post-type', + }, + { + id: 3, + title: 'The art of packing lightly: How to travel with just a cabin bag', + url: 'http://wordpress.local/packing-lightly/', + type: 'page', + kind: 'post-type', + }, + { + id: 4, + title: 'Tips for travel with a young baby', + url: 'http://wordpress.local/young-baby-tips/', + type: 'page', + kind: 'post-type', + }, + { + id: 5, + title: '', // Test that empty titles don't cause an error. + url: 'http://wordpress.local/420/', + type: 'page', + kind: 'post-type', + }, + { + id: 6, + title: 'City Guides', + url: 'http://wordpress.local/city-guides/', + type: 'category', + kind: 'taxonomy', + }, + { + id: 7, + title: 'Travel Tips', + url: 'http://wordpress.local/travel-tips/', + type: 'category', + kind: 'taxonomy', + }, + ]; + const order = sortResults( results, 'travel tips' ).map( + ( result ) => result.id + ); + expect( order ).toEqual( [ + 7, // exact match + 4, // contains: travel, tips + 3, // contains: travel + // same order as input: + 1, + 2, + 5, + 6, + ] ); + } ); +} ); + +describe( 'tokenize', () => { + it( 'returns empty array for empty string', () => { + expect( tokenize( '' ) ).toEqual( [] ); + } ); + + it( 'tokenizes a string', () => { + expect( tokenize( 'Hello, world!' ) ).toEqual( [ 'hello', 'world' ] ); + } ); + + it( 'tokenizes non latin languages', () => { + expect( tokenize( 'こんにちは、世界!' ) ).toEqual( [ + 'こんにちは', + '世界', + ] ); + } ); +} ); diff --git a/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/style.scss b/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/style.scss index f26955fe3a497..638b8e7b42219 100644 --- a/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/style.scss +++ b/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/style.scss @@ -33,9 +33,6 @@ &__shortcut-description { flex: 1; margin: 0; - - // IE 11 flex item fix - ensure the item does not collapse. - flex-basis: auto; } &__shortcut-key-combination { diff --git a/packages/dataviews/README.md b/packages/dataviews/README.md index 41595b4d58adc..4256270d2dc84 100644 --- a/packages/dataviews/README.md +++ b/packages/dataviews/README.md @@ -92,7 +92,7 @@ const fields = [ ); }, elements: [ - { value: 1, label: 'Admin' } + { value: 1, label: 'Admin' }, { value: 2, label: 'User' } ], filterBy: { diff --git a/packages/e2e-tests/plugins/interactive-blocks/deferred-store/view.js b/packages/e2e-tests/plugins/interactive-blocks/deferred-store/view.js index 121727dcc467c..d3803788c0d1b 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/deferred-store/view.js +++ b/packages/e2e-tests/plugins/interactive-blocks/deferred-store/view.js @@ -3,8 +3,9 @@ */ import { store, getContext } from '@wordpress/interactivity'; -document.addEventListener( 'DOMContentLoaded', () => { - setTimeout( () => { +window.addEventListener( + '_test_proceed_', + () => { store( 'test/deferred-store', { state: { reversedText() { @@ -16,5 +17,6 @@ document.addEventListener( 'DOMContentLoaded', () => { }, }, } ); - }, 100 ); -} ); + }, + { once: true } +); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js b/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js index fd962618b510a..c644c219348a6 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js @@ -382,6 +382,7 @@ function ConfirmDeleteDialog( { confirmButtonText={ __( 'Delete' ) } onCancel={ handleCancelUninstall } onConfirm={ handleConfirmUninstall } + size="medium" > { font && sprintf( diff --git a/packages/edit-site/src/components/global-styles/screen-revisions/index.js b/packages/edit-site/src/components/global-styles/screen-revisions/index.js index e4ffb20996418..de27e92113b55 100644 --- a/packages/edit-site/src/components/global-styles/screen-revisions/index.js +++ b/packages/edit-site/src/components/global-styles/screen-revisions/index.js @@ -81,28 +81,11 @@ function ScreenRevisions() { }; const restoreRevision = ( revision ) => { - setUserConfig( () => ( { - styles: revision?.styles, - settings: revision?.settings, - _links: revision?._links, - } ) ); + setUserConfig( () => revision ); setIsLoadingRevisionWithUnsavedChanges( false ); onCloseRevisions(); }; - const selectRevision = ( revision ) => { - setCurrentlySelectedRevision( { - /* - * The default must be an empty object so that - * `mergeBaseAndUserConfigs()` can merge them correctly. - */ - styles: revision?.styles || {}, - settings: revision?.settings || {}, - _links: revision?._links || {}, - id: revision?.id, - } ); - }; - useEffect( () => { if ( ! editorCanvasContainerView || @@ -134,11 +117,7 @@ function ScreenRevisions() { * See: https://github.com/WordPress/gutenberg/issues/55866 */ if ( shouldSelectFirstItem ) { - setCurrentlySelectedRevision( { - styles: firstRevision?.styles || {}, - settings: firstRevision?.settings || {}, - id: firstRevision?.id, - } ); + setCurrentlySelectedRevision( firstRevision ); } }, [ shouldSelectFirstItem, firstRevision ] ); @@ -186,7 +165,7 @@ function ScreenRevisions() { /> ) ) } setIsLoadingRevisionWithUnsavedChanges( false ) } + size="medium" > { __( 'Are you sure you want to apply this revision? Any unsaved changes will be lost.' diff --git a/packages/edit-site/src/components/global-styles/shadows-edit-panel.js b/packages/edit-site/src/components/global-styles/shadows-edit-panel.js index 443d72deb9573..7a513cc250d66 100644 --- a/packages/edit-site/src/components/global-styles/shadows-edit-panel.js +++ b/packages/edit-site/src/components/global-styles/shadows-edit-panel.js @@ -201,6 +201,7 @@ export default function ShadowsEditPanel() { setIsConfirmDialogVisible( false ); } } confirmButtonText={ __( 'Delete' ) } + size="medium" > { sprintf( // translators: %s: name of the shadow diff --git a/packages/edit-site/src/components/global-styles/variations/variation.js b/packages/edit-site/src/components/global-styles/variations/variation.js index a3214149edec3..1c1418a54931f 100644 --- a/packages/edit-site/src/components/global-styles/variations/variation.js +++ b/packages/edit-site/src/components/global-styles/variations/variation.js @@ -15,6 +15,7 @@ import { privateApis as editorPrivateApis } from '@wordpress/editor'; /** * Internal dependencies */ +import { filterObjectByProperty } from '../../../hooks/use-theme-style-variations/use-theme-style-variations-by-property'; import { unlock } from '../../../lock-unlock'; const { mergeBaseAndUserConfigs } = unlock( editorPrivateApis ); @@ -22,30 +23,24 @@ const { GlobalStylesContext, areGlobalStyleConfigsEqual } = unlock( blockEditorPrivateApis ); -export default function Variation( { variation, children, isPill } ) { +export default function Variation( { variation, children, isPill, property } ) { const [ isFocused, setIsFocused ] = useState( false ); const { base, user, setUserConfig } = useContext( GlobalStylesContext ); - const context = useMemo( - () => ( { - user: { - settings: variation.settings ?? {}, - styles: variation.styles ?? {}, - _links: variation._links ?? {}, - }, + + const context = useMemo( () => { + let merged = mergeBaseAndUserConfigs( base, variation ); + if ( property ) { + merged = filterObjectByProperty( merged, property ); + } + return { + user: variation, base, - merged: mergeBaseAndUserConfigs( base, variation ), + merged, setUserConfig: () => {}, - } ), - [ variation, base ] - ); + }; + }, [ variation, base, property ] ); - const selectVariation = () => { - setUserConfig( () => ( { - settings: variation.settings, - styles: variation.styles, - _links: variation._links, - } ) ); - }; + const selectVariation = () => setUserConfig( variation ); const selectOnEnter = ( event ) => { if ( event.keyCode === ENTER ) { diff --git a/packages/edit-site/src/components/global-styles/variations/variations-color.js b/packages/edit-site/src/components/global-styles/variations/variations-color.js index 88361afcc58f8..e84145afe2858 100644 --- a/packages/edit-site/src/components/global-styles/variations/variations-color.js +++ b/packages/edit-site/src/components/global-styles/variations/variations-color.js @@ -27,7 +27,12 @@ export default function ColorVariations( { title, gap = 2 } ) { { title && { title } } { colorVariations.map( ( variation, index ) => ( - + { () => } ) ) } diff --git a/packages/edit-site/src/components/global-styles/variations/variations-typography.js b/packages/edit-site/src/components/global-styles/variations/variations-typography.js index 208ed822b5a6f..689340cee9bd8 100644 --- a/packages/edit-site/src/components/global-styles/variations/variations-typography.js +++ b/packages/edit-site/src/components/global-styles/variations/variations-typography.js @@ -35,7 +35,11 @@ export default function TypographyVariations( { title, gap = 2 } ) { { typographyVariations && typographyVariations.length && typographyVariations.map( ( variation, index ) => ( - + { ( isFocused ) => ( { __( 'Are you sure you want to delete this Navigation Menu?' ) } diff --git a/packages/edit-site/src/components/sidebar/style.scss b/packages/edit-site/src/components/sidebar/style.scss index a1f15f8c8229e..0b411e3180664 100644 --- a/packages/edit-site/src/components/sidebar/style.scss +++ b/packages/edit-site/src/components/sidebar/style.scss @@ -3,7 +3,7 @@ overflow-y: auto; } -@keyframes slide-from-right { +@keyframes local--slide-from-right { from { transform: translateX(50px); opacity: 0; @@ -14,7 +14,7 @@ } } -@keyframes slide-from-left { +@keyframes local--slide-from-left { from { transform: translateX(-50px); opacity: 0; @@ -47,11 +47,11 @@ } &.slide-from-left { - animation-name: slide-from-left; + animation-name: local--slide-from-left; } &.slide-from-right { - animation-name: slide-from-right; + animation-name: local--slide-from-right; } } diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index 9e876d39d7340..a81bc107a787c 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -287,7 +287,7 @@ function PushChangesToGlobalStylesControl( { // notification. __unstableMarkNextChangeAsNotPersistent(); setAttributes( newBlockAttributes ); - setUserConfig( () => newUserConfig, { undoIgnore: true } ); + setUserConfig( newUserConfig, { undoIgnore: true } ); createSuccessNotice( sprintf( // translators: %s: Title of the block e.g. 'Heading'. @@ -302,7 +302,7 @@ function PushChangesToGlobalStylesControl( { onClick() { __unstableMarkNextChangeAsNotPersistent(); setAttributes( attributes ); - setUserConfig( () => userConfig, { + setUserConfig( userConfig, { undoIgnore: true, } ); }, diff --git a/packages/edit-site/src/hooks/use-theme-style-variations/test/use-theme-style-variations-by-property.js b/packages/edit-site/src/hooks/use-theme-style-variations/test/use-theme-style-variations-by-property.js index 89a58166257f6..c45162a6f9dbe 100644 --- a/packages/edit-site/src/hooks/use-theme-style-variations/test/use-theme-style-variations-by-property.js +++ b/packages/edit-site/src/hooks/use-theme-style-variations/test/use-theme-style-variations-by-property.js @@ -1,12 +1,7 @@ -/** - * External dependencies - */ -import { renderHook } from '@testing-library/react'; - /** * Internal dependencies */ -import useThemeStyleVariationsByProperty, { +import { filterObjectByProperty, removePropertyFromObject, } from '../use-theme-style-variations-by-property'; @@ -95,875 +90,6 @@ describe( 'filterObjectByProperty', () => { ); } ); -describe( 'useThemeStyleVariationsByProperty', () => { - const mockVariations = [ - { - title: 'Title 1', - description: 'Description 1', - settings: { - color: { - duotone: [ - { - name: 'Dark grayscale', - colors: [ '#000000', '#7f7f7f' ], - slug: 'dark-grayscale', - }, - { - name: 'Grayscale', - colors: [ '#000000', '#ffffff' ], - slug: 'grayscale', - }, - { - name: 'Purple and yellow', - colors: [ '#8c00b7', '#fcff41' ], - slug: 'purple-yellow', - }, - ], - gradients: [ - { - name: 'Vivid cyan blue to vivid purple', - gradient: - 'linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)', - slug: 'vivid-cyan-blue-to-vivid-purple', - }, - { - name: 'Light green cyan to vivid green cyan', - gradient: - 'linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%)', - slug: 'light-green-cyan-to-vivid-green-cyan', - }, - { - name: 'Luminous vivid amber to luminous vivid orange', - gradient: - 'linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%)', - slug: 'luminous-vivid-amber-to-luminous-vivid-orange', - }, - ], - palette: [ - { - name: 'Vivid red', - slug: 'vivid-red', - color: '#cf2e2e', - }, - { - name: 'Luminous vivid orange', - slug: 'luminous-vivid-orange', - color: '#ff6900', - }, - { - name: 'Luminous vivid amber', - slug: 'luminous-vivid-amber', - color: '#fcb900', - }, - ], - }, - typography: { - fluid: true, - fontFamilies: { - theme: [ - { - name: 'Inter san-serif', - fontFamily: 'Inter san-serif', - slug: 'inter-san-serif', - fontFace: [ - { - src: 'inter-san-serif.woff2', - fontWeight: '400', - fontStyle: 'italic', - fontFamily: 'Inter san-serif', - }, - ], - }, - ], - }, - fontSizes: [ - { - name: 'Small', - slug: 'small', - size: '13px', - }, - { - name: 'Medium', - slug: 'medium', - size: '20px', - }, - { - name: 'Large', - slug: 'large', - size: '36px', - }, - ], - }, - layout: { - wideSize: '1200px', - }, - }, - styles: { - typography: { - letterSpacing: '3px', - }, - color: { - backgroundColor: 'red', - color: 'orange', - }, - elements: { - cite: { - color: { - text: 'white', - }, - }, - }, - blocks: { - 'core/quote': { - color: { - text: 'black', - background: 'white', - }, - typography: { - fontSize: '20px', - }, - }, - }, - }, - }, - { - title: 'Title 2', - description: 'Description 2', - settings: { - color: { - duotone: [ - { - name: 'Boom', - colors: [ '#000000', '#7f7f7f' ], - slug: 'boom', - }, - { - name: 'Gray to white', - colors: [ '#000000', '#ffffff' ], - slug: 'gray-to-white', - }, - { - name: 'Whatever to whatever', - colors: [ '#8c00b7', '#fcff41' ], - slug: 'whatever-to-whatever', - }, - ], - gradients: [ - { - name: 'Jam in the office', - gradient: - 'linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)', - slug: 'jam-in-the-office', - }, - { - name: 'Open source', - gradient: - 'linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%)', - slug: 'open-source', - }, - { - name: 'Here to there', - gradient: - 'linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%)', - slug: 'here-to-there', - }, - ], - palette: [ - { - name: 'Chunky Bacon', - slug: 'chunky-bacon', - color: '#cf2e2e', - }, - { - name: 'Burrito', - slug: 'burrito', - color: '#ff6900', - }, - { - name: 'Dinosaur', - slug: 'dinosaur', - color: '#fcb900', - }, - ], - }, - typography: { - fontSizes: [ - { - name: 'Smallish', - slug: 'smallish', - size: '15px', - }, - { - name: 'Mediumish', - slug: 'mediumish', - size: '22px', - }, - { - name: 'Largish', - slug: 'largish', - size: '44px', - }, - ], - }, - layout: { - contentSize: '300px', - }, - }, - styles: { - typography: { - letterSpacing: '3px', - }, - color: { - backgroundColor: 'red', - text: 'orange', - }, - elements: { - link: { - typography: { - textDecoration: 'underline', - }, - }, - }, - blocks: { - 'core/paragraph': { - color: { - text: 'purple', - background: 'green', - }, - typography: { - fontSize: '20px', - }, - }, - }, - }, - }, - ]; - const mockBaseVariation = { - settings: { - typography: { - fontFamilies: { - custom: [ - { - name: 'ADLaM Display', - fontFamily: 'ADLaM Display, system-ui', - slug: 'adlam-display', - fontFace: [ - { - src: 'adlam.woff2', - fontWeight: '400', - fontStyle: 'normal', - fontFamily: 'ADLaM Display', - }, - ], - }, - ], - }, - fontSizes: [ - { - name: 'Base small', - slug: 'base-small', - size: '1px', - }, - { - name: 'Base medium', - slug: 'base-medium', - size: '2px', - }, - { - name: 'Base large', - slug: 'base-large', - size: '3px', - }, - ], - }, - color: { - palette: { - custom: [ - { - color: '#c42727', - name: 'Color 1', - slug: 'custom-color-1', - }, - { - color: '#3b0f0f', - name: 'Color 2', - slug: 'custom-color-2', - }, - ], - }, - }, - layout: { - wideSize: '1137px', - contentSize: '400px', - }, - }, - styles: { - typography: { - fontSize: '12px', - lineHeight: '1.5', - }, - color: { - backgroundColor: 'cheese', - color: 'lettuce', - }, - blocks: { - 'core/quote': { - color: { - text: 'hello', - background: 'dolly', - }, - typography: { - fontSize: '111111px', - }, - }, - 'core/group': { - typography: { - fontFamily: 'var:preset|font-family|system-sans-serif', - }, - }, - }, - }, - }; - - it( 'should return variations if property is falsy', () => { - const { result } = renderHook( () => - useThemeStyleVariationsByProperty( { - variations: mockVariations, - property: '', - } ) - ); - - expect( result.current ).toEqual( mockVariations ); - } ); - - it( 'should return variations if variations is empty or falsy', () => { - const { result: emptyResult } = renderHook( () => - useThemeStyleVariationsByProperty( { - variations: [], - property: 'layout', - } ) - ); - - expect( emptyResult.current ).toEqual( [] ); - - const { result: falsyResult } = renderHook( () => - useThemeStyleVariationsByProperty( { - variations: null, - property: 'layout', - } ) - ); - - expect( falsyResult.current ).toEqual( null ); - } ); - - it( 'should return new, unreferenced object', () => { - const variations = [ - { - title: 'hey', - description: 'ho', - joe: { - where: { - you: 'going with that unit test in your hand', - }, - }, - }, - ]; - const { result } = renderHook( () => - useThemeStyleVariationsByProperty( { - variations, - property: 'where', - } ) - ); - - expect( result.current ).toEqual( [ - { - title: 'hey', - description: 'ho', - joe: { - where: { - you: 'going with that unit test in your hand', - }, - }, - }, - ] ); - - expect( result.current[ 0 ].joe.where ).not.toBe( - variations[ 0 ].joe.where - ); - expect( result.current[ 0 ].joe ).not.toBe( variations[ 0 ].joe ); - } ); - - it( "should return the variation's typography properties", () => { - const { result } = renderHook( () => - useThemeStyleVariationsByProperty( { - variations: mockVariations, - property: 'typography', - } ) - ); - - expect( result.current ).toEqual( [ - { - title: 'Title 1', - description: 'Description 1', - settings: { - typography: { - fluid: true, - fontFamilies: { - theme: [ - { - name: 'Inter san-serif', - fontFamily: 'Inter san-serif', - slug: 'inter-san-serif', - fontFace: [ - { - src: 'inter-san-serif.woff2', - fontWeight: '400', - fontStyle: 'italic', - fontFamily: 'Inter san-serif', - }, - ], - }, - ], - }, - fontSizes: [ - { - name: 'Small', - slug: 'small', - size: '13px', - }, - { - name: 'Medium', - slug: 'medium', - size: '20px', - }, - { - name: 'Large', - slug: 'large', - size: '36px', - }, - ], - }, - }, - styles: { - typography: { - letterSpacing: '3px', - }, - blocks: { - 'core/quote': { - typography: { - fontSize: '20px', - }, - }, - }, - }, - }, - { - title: 'Title 2', - description: 'Description 2', - settings: { - typography: { - fontSizes: [ - { - name: 'Smallish', - slug: 'smallish', - size: '15px', - }, - { - name: 'Mediumish', - slug: 'mediumish', - size: '22px', - }, - { - name: 'Largish', - slug: 'largish', - size: '44px', - }, - ], - }, - }, - styles: { - typography: { - letterSpacing: '3px', - }, - elements: { - link: { - typography: { - textDecoration: 'underline', - }, - }, - }, - blocks: { - 'core/paragraph': { - typography: { - fontSize: '20px', - }, - }, - }, - }, - }, - ] ); - } ); - - it( "should return the variation's color properties", () => { - const { result } = renderHook( () => - useThemeStyleVariationsByProperty( { - variations: mockVariations, - property: 'color', - } ) - ); - - expect( result.current ).toEqual( [ - { - title: 'Title 1', - description: 'Description 1', - settings: { - color: { - duotone: [ - { - name: 'Dark grayscale', - colors: [ '#000000', '#7f7f7f' ], - slug: 'dark-grayscale', - }, - { - name: 'Grayscale', - colors: [ '#000000', '#ffffff' ], - slug: 'grayscale', - }, - { - name: 'Purple and yellow', - colors: [ '#8c00b7', '#fcff41' ], - slug: 'purple-yellow', - }, - ], - gradients: [ - { - name: 'Vivid cyan blue to vivid purple', - gradient: - 'linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)', - slug: 'vivid-cyan-blue-to-vivid-purple', - }, - { - name: 'Light green cyan to vivid green cyan', - gradient: - 'linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%)', - slug: 'light-green-cyan-to-vivid-green-cyan', - }, - { - name: 'Luminous vivid amber to luminous vivid orange', - gradient: - 'linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%)', - slug: 'luminous-vivid-amber-to-luminous-vivid-orange', - }, - ], - palette: [ - { - name: 'Vivid red', - slug: 'vivid-red', - color: '#cf2e2e', - }, - { - name: 'Luminous vivid orange', - slug: 'luminous-vivid-orange', - color: '#ff6900', - }, - { - name: 'Luminous vivid amber', - slug: 'luminous-vivid-amber', - color: '#fcb900', - }, - ], - }, - }, - styles: { - color: { - backgroundColor: 'red', - color: 'orange', - }, - elements: { - cite: { - color: { - text: 'white', - }, - }, - }, - blocks: { - 'core/quote': { - color: { - text: 'black', - background: 'white', - }, - }, - }, - }, - }, - { - title: 'Title 2', - description: 'Description 2', - settings: { - color: { - duotone: [ - { - name: 'Boom', - colors: [ '#000000', '#7f7f7f' ], - slug: 'boom', - }, - { - name: 'Gray to white', - colors: [ '#000000', '#ffffff' ], - slug: 'gray-to-white', - }, - { - name: 'Whatever to whatever', - colors: [ '#8c00b7', '#fcff41' ], - slug: 'whatever-to-whatever', - }, - ], - gradients: [ - { - name: 'Jam in the office', - gradient: - 'linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)', - slug: 'jam-in-the-office', - }, - { - name: 'Open source', - gradient: - 'linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%)', - slug: 'open-source', - }, - { - name: 'Here to there', - gradient: - 'linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%)', - slug: 'here-to-there', - }, - ], - palette: [ - { - name: 'Chunky Bacon', - slug: 'chunky-bacon', - color: '#cf2e2e', - }, - { - name: 'Burrito', - slug: 'burrito', - color: '#ff6900', - }, - { - name: 'Dinosaur', - slug: 'dinosaur', - color: '#fcb900', - }, - ], - }, - }, - styles: { - color: { - backgroundColor: 'red', - text: 'orange', - }, - blocks: { - 'core/paragraph': { - color: { - text: 'purple', - background: 'green', - }, - }, - }, - }, - }, - ] ); - } ); - - it( 'should merge the user styles and settings with the supplied variation, but only for the specified property', () => { - const { result } = renderHook( () => - useThemeStyleVariationsByProperty( { - variations: [ mockVariations[ 0 ] ], - property: 'typography', - baseVariation: mockBaseVariation, - } ) - ); - - expect( result.current ).toEqual( [ - { - title: 'Title 1', - description: 'Description 1', - settings: { - typography: { - fluid: true, - fontFamilies: { - theme: [ - { - name: 'Inter san-serif', - fontFamily: 'Inter san-serif', - slug: 'inter-san-serif', - fontFace: [ - { - src: 'inter-san-serif.woff2', - fontWeight: '400', - fontStyle: 'italic', - fontFamily: 'Inter san-serif', - }, - ], - }, - ], - custom: [ - { - name: 'ADLaM Display', - fontFamily: 'ADLaM Display, system-ui', - slug: 'adlam-display', - fontFace: [ - { - src: 'adlam.woff2', - fontWeight: '400', - fontStyle: 'normal', - fontFamily: 'ADLaM Display', - }, - ], - }, - ], - }, - fontSizes: [ - { - name: 'Small', - slug: 'small', - size: '13px', - }, - { - name: 'Medium', - slug: 'medium', - size: '20px', - }, - { - name: 'Large', - slug: 'large', - size: '36px', - }, - ], - }, - color: { - palette: { - custom: [ - { - color: '#c42727', - name: 'Color 1', - slug: 'custom-color-1', - }, - { - color: '#3b0f0f', - name: 'Color 2', - slug: 'custom-color-2', - }, - ], - }, - }, - layout: { - wideSize: '1137px', - contentSize: '400px', - }, - }, - styles: { - color: { - backgroundColor: 'cheese', - color: 'lettuce', - }, - typography: { - fontSize: '12px', - letterSpacing: '3px', - lineHeight: '1.5', - }, - blocks: { - 'core/quote': { - color: { - text: 'hello', - background: 'dolly', - }, - typography: { - fontSize: '20px', - }, - }, - 'core/group': { - typography: { - fontFamily: - 'var:preset|font-family|system-sans-serif', - }, - }, - }, - }, - }, - ] ); - } ); - - it( 'should filter the output and return only variations that match filter', () => { - const { result } = renderHook( () => - useThemeStyleVariationsByProperty( { - variations: mockVariations, - property: 'typography', - filter: ( variation ) => - !! variation?.settings?.typography?.fontFamilies?.theme - ?.length, - } ) - ); - expect( result.current ).toEqual( [ - { - title: 'Title 1', - description: 'Description 1', - settings: { - typography: { - fluid: true, - fontFamilies: { - theme: [ - { - name: 'Inter san-serif', - fontFamily: 'Inter san-serif', - slug: 'inter-san-serif', - fontFace: [ - { - src: 'inter-san-serif.woff2', - fontWeight: '400', - fontStyle: 'italic', - fontFamily: 'Inter san-serif', - }, - ], - }, - ], - }, - fontSizes: [ - { - name: 'Small', - slug: 'small', - size: '13px', - }, - { - name: 'Medium', - slug: 'medium', - size: '20px', - }, - { - name: 'Large', - slug: 'large', - size: '36px', - }, - ], - }, - }, - styles: { - typography: { - letterSpacing: '3px', - }, - blocks: { - 'core/quote': { - typography: { - fontSize: '20px', - }, - }, - }, - }, - }, - ] ); - } ); -} ); - describe( 'removePropertyFromObject', () => { const mockBaseVariation = { settings: { diff --git a/packages/edit-site/src/hooks/use-theme-style-variations/use-theme-style-variations-by-property.js b/packages/edit-site/src/hooks/use-theme-style-variations/use-theme-style-variations-by-property.js index 2a914efc6ee52..401a7e1a71dfd 100644 --- a/packages/edit-site/src/hooks/use-theme-style-variations/use-theme-style-variations-by-property.js +++ b/packages/edit-site/src/hooks/use-theme-style-variations/use-theme-style-variations-by-property.js @@ -48,17 +48,15 @@ export function removePropertyFromObject( object, property ) { } /** - * A convenience wrapper for `useThemeStyleVariationsByProperty()` that fetches the current theme style variations, - * and user-defined global style/settings object. + * Fetches the current theme style variations that contain only the specified property + * and merges them with the user config. * - * @param {Object} props Object of hook args. - * @param {string} props.property The property to filter by. - * @param {Function} props.filter Optional. The filter function to apply to the variations. + * @param {Object} props Object of hook args. + * @param {string} props.property The property to filter by. * @return {Object[]|*} The merged object. */ export function useCurrentMergeThemeStyleVariationsWithUserConfig( { property, - filter, } ) { const { variationsFromTheme } = useSelect( ( select ) => { const _variationsFromTheme = @@ -70,28 +68,34 @@ export function useCurrentMergeThemeStyleVariationsWithUserConfig( { variationsFromTheme: _variationsFromTheme || [], }; }, [] ); - const { user: baseVariation } = useContext( GlobalStylesContext ); + const { user: userVariation } = useContext( GlobalStylesContext ); - const variations = useMemo( () => { - return [ - { - title: __( 'Default' ), - settings: {}, - styles: {}, - }, - ...variationsFromTheme, - ]; - }, [ variationsFromTheme ] ); + return useMemo( () => { + const clonedUserVariation = cloneDeep( userVariation ); - return useThemeStyleVariationsByProperty( { - variations, - property, - filter, - baseVariation: removePropertyFromObject( - cloneDeep( baseVariation ), + // Get user variation and remove the settings for the given property. + const userVariationWithoutProperty = removePropertyFromObject( + clonedUserVariation, property - ), - } ); + ); + userVariationWithoutProperty.title = __( 'Default' ); + + const variationsWithSinglePropertyAndBase = variationsFromTheme + .filter( ( variation ) => { + return isVariationWithSingleProperty( variation, property ); + } ) + .map( ( variation ) => { + return mergeBaseAndUserConfigs( + userVariationWithoutProperty, + variation + ); + } ); + + return [ + userVariationWithoutProperty, + ...variationsWithSinglePropertyAndBase, + ]; + }, [ property, userVariation, variationsFromTheme ] ); } /** @@ -123,98 +127,6 @@ export const filterObjectByProperty = ( object, property ) => { return newObject; }; -/** - * Returns a new object with only the properties specified in `property`. - * Optional merges the baseVariation object with the variation object. - * Note: this function will only overwrite the specified property in baseVariation if it exists. - * The baseVariation will not be otherwise modified. To strip a property from the baseVariation object, use `removePropertyFromObject`. - * See useCurrentMergeThemeStyleVariationsWithUserConfig for an example of how to use this function. - * - * @param {Object} props Object of hook args. - * @param {Object[]} props.variations The theme style variations to filter. - * @param {string} props.property The property to filter by. - * @param {Function} props.filter Optional. The filter function to apply to the variations. - * @param {Object} props.baseVariation Optional. Base or user settings to be updated with variation properties. - * @return {Object[]|*} The merged object. - */ -export default function useThemeStyleVariationsByProperty( { - variations, - property, - filter, - baseVariation, -} ) { - return useMemo( () => { - if ( ! property || ! variations || variations?.length === 0 ) { - return variations; - } - - const clonedBaseVariation = - typeof baseVariation === 'object' && - Object.keys( baseVariation ).length > 0 - ? cloneDeep( baseVariation ) - : null; - - let processedStyleVariations = variations.reduce( - ( accumulator, variation ) => { - const variationFilteredByProperty = filterObjectByProperty( - cloneDeep( variation ), - property - ); - - // Remove variations that are empty once the property is filtered out. - if ( - variation.title !== __( 'Default' ) && - Object.keys( variationFilteredByProperty ).length === 0 - ) { - return accumulator; - } - - let result = { - ...variationFilteredByProperty, - title: variation?.title, - description: variation?.description, - }; - - if ( clonedBaseVariation ) { - /* - * Overwrites all baseVariation object `styleProperty` properties - * with the theme variation `styleProperty` properties. - */ - result = mergeBaseAndUserConfigs( - clonedBaseVariation, - result - ); - } - - // Detect if this is a duplicate variation. - const isDuplicate = accumulator.some( ( item ) => { - return ( - JSON.stringify( item.styles ) === - JSON.stringify( result?.styles ) && - JSON.stringify( item.settings ) === - JSON.stringify( result?.settings ) - ); - } ); - if ( isDuplicate ) { - return accumulator; - } - - // If the variation is not a duplicate, add it to the accumulator. - accumulator.push( result ); - return accumulator; - }, - [] // Initial accumulator value. - ); - - if ( 'function' === typeof filter ) { - processedStyleVariations = - processedStyleVariations.filter( filter ); - } - - return processedStyleVariations; - }, [ variations, property, baseVariation, filter ] ); -} - /** * Compares a style variation to the same variation filtered by a single property. * Returns true if the variation contains only the property specified. diff --git a/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/style.scss b/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/style.scss index e00df74d97d91..5984ca13d57eb 100644 --- a/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/style.scss +++ b/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/style.scss @@ -33,9 +33,6 @@ &__shortcut-description { flex: 1; margin: 0; - - // IE 11 flex item fix - ensure the item does not collapse. - flex-basis: auto; } &__shortcut-key-combination { diff --git a/packages/editor/README.md b/packages/editor/README.md index 8279ec3e74360..9b4ec07bfded2 100644 --- a/packages/editor/README.md +++ b/packages/editor/README.md @@ -1276,11 +1276,24 @@ Undocumented declaration. ### PostSticky -Undocumented declaration. +Renders the PostSticky component. It provide toggle control for the sticky post feature. + +_Returns_ + +- `Component`: The component to be rendered. ### PostStickyCheck -Undocumented declaration. +Wrapper component that renders its children only if post has a sticky action. + +_Parameters_ + +- _props_ `Object`: Props. +- _props.children_ `Element`: Children to be rendered. + +_Returns_ + +- `Component`: The component to be rendered or null if post type is not 'post' or hasStickyAction is false. ### PostSwitchToDraftButton @@ -1399,11 +1412,24 @@ Undocumented declaration. ### PostTrash -Undocumented declaration. +Displays the Post Trash Button and Confirm Dialog in the Editor. + +_Returns_ + +- `JSX.Element|null`: The rendered PostTrash component. ### PostTrashCheck -Undocumented declaration. +Wrapper component that renders its children only if the post can trashed. + +_Parameters_ + +- _props_ `Object`: - The component props. +- _props.children_ `Element`: - The child components to render. + +_Returns_ + +- `Component|null`: The rendered child components or null if the post can not trashed. ### PostTypeSupportCheck @@ -1577,7 +1603,9 @@ _Returns_ ### TextEditorGlobalKeyboardShortcuts -Undocumented declaration. +Component handles the global keyboard shortcuts for the Text editor. + +It provides functionality for various keyboard shortcuts such as toggling editor mode, toggling distraction-free mode, undo/redo. ### ThemeSupportCheck @@ -1595,7 +1623,11 @@ _Returns_ ### TimeToRead -Undocumented declaration. +Component for showing Time To Read in Content. + +_Returns_ + +- `JSX.Element`: The rendered TimeToRead component. ### transformStyles diff --git a/packages/editor/src/components/document-tools/index.js b/packages/editor/src/components/document-tools/index.js index 6ec999bd04801..54121652bbf13 100644 --- a/packages/editor/src/components/document-tools/index.js +++ b/packages/editor/src/components/document-tools/index.js @@ -28,10 +28,6 @@ import { store as editorStore } from '../../store'; import EditorHistoryRedo from '../editor-history/redo'; import EditorHistoryUndo from '../editor-history/undo'; -const preventDefault = ( event ) => { - event.preventDefault(); -}; - function DocumentTools( { className, disableBlockTools = false } ) { const { setIsInserterOpened, setIsListViewOpened } = useDispatch( editorStore ); @@ -72,6 +68,19 @@ function DocumentTools( { className, disableBlockTools = false } ) { }; }, [] ); + const preventDefault = ( event ) => { + // Because the inserter behaves like a dialog, + // if the inserter is opened already then when we click on the toggle button + // then the initial click event will close the inserter and then be propagated + // to the inserter toggle and it will open it again. + // To prevent this we need to stop the propagation of the event. + // This won't be necessary when the inserter no longer behaves like a dialog. + + if ( isInserterOpened ) { + event.preventDefault(); + } + }; + const isLargeViewport = useViewportMatch( 'medium' ); const isWideViewport = useViewportMatch( 'wide' ); diff --git a/packages/editor/src/components/global-styles-provider/index.js b/packages/editor/src/components/global-styles-provider/index.js index 04a42ab7af819..4250910cc6320 100644 --- a/packages/editor/src/components/global-styles-provider/index.js +++ b/packages/editor/src/components/global-styles-provider/index.js @@ -163,7 +163,13 @@ function useGlobalStylesUserConfig() { }, [ settings, styles, _links ] ); const setConfig = useCallback( - ( callback, options = {} ) => { + /** + * Set the global styles config. + * @param {Function|Object} callbackOrObject If the callbackOrObject is a function, pass the current config to the callback so the consumer can merge values. + * Otherwise, overwrite the current config with the incoming object. + * @param {Object} options Options for editEntityRecord Core selector. + */ + ( callbackOrObject, options = {} ) => { const record = getEditedEntityRecord( 'root', 'globalStyles', @@ -175,7 +181,11 @@ function useGlobalStylesUserConfig() { settings: record?.settings ?? {}, _links: record?._links ?? {}, }; - const updatedConfig = callback( currentConfig ); + + const updatedConfig = + typeof callbackOrObject === 'function' + ? callbackOrObject( currentConfig ) + : callbackOrObject; editEntityRecord( 'root', diff --git a/packages/editor/src/components/index.js b/packages/editor/src/components/index.js index e84942345fb32..0e2410e7f456d 100644 --- a/packages/editor/src/components/index.js +++ b/packages/editor/src/components/index.js @@ -106,4 +106,11 @@ export { default as EditorProvider } from './provider'; export * from './deprecated'; export const VisualEditorGlobalKeyboardShortcuts = EditorKeyboardShortcuts; + +/** + * Component handles the global keyboard shortcuts for the Text editor. + * + * It provides functionality for various keyboard shortcuts such as toggling editor mode, + * toggling distraction-free mode, undo/redo. + */ export const TextEditorGlobalKeyboardShortcuts = EditorKeyboardShortcuts; diff --git a/packages/editor/src/components/keyboard-shortcut-help-modal/style.scss b/packages/editor/src/components/keyboard-shortcut-help-modal/style.scss index 1d15c31c47546..4eafa638cdfd9 100644 --- a/packages/editor/src/components/keyboard-shortcut-help-modal/style.scss +++ b/packages/editor/src/components/keyboard-shortcut-help-modal/style.scss @@ -33,9 +33,6 @@ &__shortcut-description { flex: 1; margin: 0; - - // IE 11 flex item fix - ensure the item does not collapse. - flex-basis: auto; } &__shortcut-key-combination { diff --git a/packages/editor/src/components/post-card-panel/style.scss b/packages/editor/src/components/post-card-panel/style.scss index 82d10eb85b693..f715f2318f842 100644 --- a/packages/editor/src/components/post-card-panel/style.scss +++ b/packages/editor/src/components/post-card-panel/style.scss @@ -35,6 +35,10 @@ .editor-post-card-panel__icon.is-sync { fill: var(--wp-block-synced-color); + + & + .editor-post-card-panel__title { + color: var(--wp-block-synced-color); + } } .editor-post-card-panel__title-badge { diff --git a/packages/editor/src/components/post-panel-row/style.scss b/packages/editor/src/components/post-panel-row/style.scss index 024394c3aaf33..5bb951feb53ed 100644 --- a/packages/editor/src/components/post-panel-row/style.scss +++ b/packages/editor/src/components/post-panel-row/style.scss @@ -6,7 +6,7 @@ } .editor-post-panel__row-label { - width: 30%; + width: 38%; flex-shrink: 0; min-height: $grid-unit-40; display: flex; diff --git a/packages/editor/src/components/post-sticky/check.js b/packages/editor/src/components/post-sticky/check.js index e31c145b9bbf0..f504effca82c6 100644 --- a/packages/editor/src/components/post-sticky/check.js +++ b/packages/editor/src/components/post-sticky/check.js @@ -8,6 +8,14 @@ import { useSelect } from '@wordpress/data'; */ import { store as editorStore } from '../../store'; +/** + * Wrapper component that renders its children only if post has a sticky action. + * + * @param {Object} props Props. + * @param {Element} props.children Children to be rendered. + * + * @return {Component} The component to be rendered or null if post type is not 'post' or hasStickyAction is false. + */ export default function PostStickyCheck( { children } ) { const { hasStickyAction, postType } = useSelect( ( select ) => { const post = select( editorStore ).getCurrentPost(); diff --git a/packages/editor/src/components/post-sticky/index.js b/packages/editor/src/components/post-sticky/index.js index f3d3085da7fd6..607e09ff507c9 100644 --- a/packages/editor/src/components/post-sticky/index.js +++ b/packages/editor/src/components/post-sticky/index.js @@ -12,6 +12,11 @@ import PostStickyCheck from './check'; import { store as editorStore } from '../../store'; import PostPanelRow from '../post-panel-row'; +/** + * Renders the PostSticky component. It provide toggle control for the sticky post feature. + * + * @return {Component} The component to be rendered. + */ export default function PostSticky() { const postSticky = useSelect( ( select ) => { return ( diff --git a/packages/editor/src/components/post-trash/check.js b/packages/editor/src/components/post-trash/check.js index b86cdf2e3d4d7..abb3b4381d95c 100644 --- a/packages/editor/src/components/post-trash/check.js +++ b/packages/editor/src/components/post-trash/check.js @@ -9,6 +9,14 @@ import { store as coreStore } from '@wordpress/core-data'; */ import { store as editorStore } from '../../store'; +/** + * Wrapper component that renders its children only if the post can trashed. + * + * @param {Object} props - The component props. + * @param {Element} props.children - The child components to render. + * + * @return {Component|null} The rendered child components or null if the post can not trashed. + */ export default function PostTrashCheck( { children } ) { const { canTrashPost } = useSelect( ( select ) => { const { isEditedPostNew, getCurrentPostId, getCurrentPostType } = diff --git a/packages/editor/src/components/post-trash/index.js b/packages/editor/src/components/post-trash/index.js index ebb078804da6d..c29dfd66a2d8c 100644 --- a/packages/editor/src/components/post-trash/index.js +++ b/packages/editor/src/components/post-trash/index.js @@ -14,6 +14,11 @@ import { useState } from '@wordpress/element'; */ import { store as editorStore } from '../../store'; +/** + * Displays the Post Trash Button and Confirm Dialog in the Editor. + * + * @return {JSX.Element|null} The rendered PostTrash component. + */ export default function PostTrash() { const { isNew, isDeleting, postId } = useSelect( ( select ) => { const store = select( editorStore ); @@ -55,6 +60,7 @@ export default function PostTrash() { onConfirm={ handleConfirm } onCancel={ () => setShowConfirmDialog( false ) } confirmButtonText={ __( 'Move to trash' ) } + size="medium" > { __( 'Are you sure you want to move this post to the trash?' diff --git a/packages/editor/src/components/post-visibility/index.js b/packages/editor/src/components/post-visibility/index.js index fef07d0033d36..e47f2acd66443 100644 --- a/packages/editor/src/components/post-visibility/index.js +++ b/packages/editor/src/components/post-visibility/index.js @@ -133,6 +133,7 @@ export default function PostVisibility( { onClose } ) { onConfirm={ confirmPrivate } onCancel={ handleDialogCancel } confirmButtonText={ __( 'Publish' ) } + size="medium" > { __( 'Would you like to privately publish this post now?' ) } diff --git a/packages/editor/src/components/sidebar/post-summary.js b/packages/editor/src/components/sidebar/post-summary.js index 1f0d2ee4776cf..2ae5be2256fc4 100644 --- a/packages/editor/src/components/sidebar/post-summary.js +++ b/packages/editor/src/components/sidebar/post-summary.js @@ -69,7 +69,7 @@ export default function PostSummary( { onActionPerformed } ) { { ! isRemovedPostStatusPanel && ( - + diff --git a/packages/editor/src/components/template-validation-notice/index.js b/packages/editor/src/components/template-validation-notice/index.js index 4aa1faac4bd9c..bfbc6319ffa8a 100644 --- a/packages/editor/src/components/template-validation-notice/index.js +++ b/packages/editor/src/components/template-validation-notice/index.js @@ -51,6 +51,7 @@ export default function TemplateValidationNotice() { synchronizeTemplate(); } } onCancel={ () => setShowConfirmDialog( false ) } + size="medium" > { __( 'Resetting the template may result in loss of content, do you want to continue?' diff --git a/packages/editor/src/components/time-to-read/index.js b/packages/editor/src/components/time-to-read/index.js index 41b458124c6f3..a71a4b1dac838 100644 --- a/packages/editor/src/components/time-to-read/index.js +++ b/packages/editor/src/components/time-to-read/index.js @@ -20,6 +20,11 @@ import { store as editorStore } from '../../store'; */ const AVERAGE_READING_RATE = 189; +/** + * Component for showing Time To Read in Content. + * + * @return {JSX.Element} The rendered TimeToRead component. + */ export default function TimeToRead() { const content = useSelect( ( select ) => select( editorStore ).getEditedPostAttribute( 'content' ), diff --git a/packages/editor/src/components/visual-editor/edit-template-blocks-notification.js b/packages/editor/src/components/visual-editor/edit-template-blocks-notification.js index ed96cae1c753e..775ef0f521363 100644 --- a/packages/editor/src/components/visual-editor/edit-template-blocks-notification.js +++ b/packages/editor/src/components/visual-editor/edit-template-blocks-notification.js @@ -80,6 +80,7 @@ export default function EditTemplateBlocksNotification( { contentRef } ) { } ); } } onCancel={ () => setIsDialogOpen( false ) } + size="medium" > { __( 'You’ve tried to select a block that is part of a template, which may be used on other posts and pages. Would you like to edit the template?' diff --git a/packages/editor/src/dataviews/store/private-selectors.ts b/packages/editor/src/dataviews/store/private-selectors.ts index 938228ad97ed7..b2f60d7b0f33e 100644 --- a/packages/editor/src/dataviews/store/private-selectors.ts +++ b/packages/editor/src/dataviews/store/private-selectors.ts @@ -1,8 +1,15 @@ +/** + * WordPress dependencies + */ +import type { Action } from '@wordpress/dataviews'; + /** * Internal dependencies */ import type { State } from './reducer'; +const EMPTY_ARRAY: Action< any >[] = []; + export function getEntityActions( state: State, kind: string, name: string ) { - return state.actions[ kind ]?.[ name ] ?? []; + return state.actions[ kind ]?.[ name ] ?? EMPTY_ARRAY; } diff --git a/packages/editor/src/hooks/pattern-overrides.js b/packages/editor/src/hooks/pattern-overrides.js index cd5f07aa8f48d..485cc3725d8d7 100644 --- a/packages/editor/src/hooks/pattern-overrides.js +++ b/packages/editor/src/hooks/pattern-overrides.js @@ -17,6 +17,7 @@ import { unlock } from '../lock-unlock'; const { PatternOverridesControls, ResetOverridesControl, + PatternOverridesBlockControls, PATTERN_TYPES, PARTIAL_SYNCING_SUPPORTED_BLOCKS, PATTERN_SYNC_TYPES, @@ -43,6 +44,7 @@ const withPatternOverrideControls = createHigherOrderComponent( { props.isSelected && isSupportedBlock && ( ) } + { isSupportedBlock && } ); } diff --git a/packages/escape-html/CHANGELOG.md b/packages/escape-html/CHANGELOG.md index 2562662aa2ce9..2a6282c050c8f 100644 --- a/packages/escape-html/CHANGELOG.md +++ b/packages/escape-html/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Internal + +- Refactor to TypeScript ([#62586](https://github.com/WordPress/gutenberg/pull/62586)). + ## 3.0.0 (2024-05-31) ### Breaking Changes diff --git a/packages/escape-html/src/escape-greater.js b/packages/escape-html/src/escape-greater.ts similarity index 68% rename from packages/escape-html/src/escape-greater.js rename to packages/escape-html/src/escape-greater.ts index f761a81e16ae6..6e5956dc47e8f 100644 --- a/packages/escape-html/src/escape-greater.js +++ b/packages/escape-html/src/escape-greater.ts @@ -6,10 +6,10 @@ * * See: https://core.trac.wordpress.org/ticket/45387 * - * @param {string} value Original string. + * @param value Original string. * - * @return {string} Escaped string. + * @return Escaped string. */ -export default function __unstableEscapeGreaterThan( value ) { +export default function __unstableEscapeGreaterThan( value: string ): string { return value.replace( />/g, '>' ); } diff --git a/packages/escape-html/src/index.js b/packages/escape-html/src/index.ts similarity index 72% rename from packages/escape-html/src/index.js rename to packages/escape-html/src/index.ts index 8ddce62c44325..71206695bb7d3 100644 --- a/packages/escape-html/src/index.js +++ b/packages/escape-html/src/index.ts @@ -11,10 +11,9 @@ import __unstableEscapeGreaterThan from './escape-greater'; * and noncharacters." * * @see https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 - * - * @type {RegExp} */ -const REGEXP_INVALID_ATTRIBUTE_NAME = /[\u007F-\u009F "'>/="\uFDD0-\uFDEF]/; +const REGEXP_INVALID_ATTRIBUTE_NAME: RegExp = + /[\u007F-\u009F "'>/="\uFDD0-\uFDEF]/; /** * Returns a string with ampersands escaped. Note that this is an imperfect @@ -26,33 +25,33 @@ const REGEXP_INVALID_ATTRIBUTE_NAME = /[\u007F-\u009F "'>/="\uFDD0-\uFDEF]/; * @see https://w3c.github.io/html/syntax.html#ambiguous-ampersand * @see https://w3c.github.io/html/syntax.html#named-character-references * - * @param {string} value Original string. + * @param value Original string. * - * @return {string} Escaped string. + * @return Escaped string. */ -export function escapeAmpersand( value ) { +export function escapeAmpersand( value: string ): string { return value.replace( /&(?!([a-z0-9]+|#[0-9]+|#x[a-f0-9]+);)/gi, '&' ); } /** * Returns a string with quotation marks replaced. * - * @param {string} value Original string. + * @param value Original string. * - * @return {string} Escaped string. + * @return Escaped string. */ -export function escapeQuotationMark( value ) { +export function escapeQuotationMark( value: string ): string { return value.replace( /"/g, '"' ); } /** * Returns a string with less-than sign replaced. * - * @param {string} value Original string. + * @param value Original string. * - * @return {string} Escaped string. + * @return Escaped string. */ -export function escapeLessThan( value ) { +export function escapeLessThan( value: string ): string { return value.replace( / string; + +function testUnstableEscapeGreaterThan( implementation: Implementation ) { it( 'should escape greater than', () => { const result = implementation( 'Chicken > Ribs' ); expect( result ).toBe( 'Chicken > Ribs' ); } ); } -function testEscapeAmpersand( implementation ) { +function testEscapeAmpersand( implementation: Implementation ) { it( 'should escape ampersand', () => { const result = implementation( 'foo & bar & & baz Σ &#bad; Σ Σ vil;' @@ -31,7 +33,7 @@ function testEscapeAmpersand( implementation ) { } ); } -function testEscapeQuotationMark( implementation ) { +function testEscapeQuotationMark( implementation: Implementation ) { it( 'should escape quotation mark', () => { const result = implementation( '"Be gone!"' ); @@ -39,7 +41,7 @@ function testEscapeQuotationMark( implementation ) { } ); } -function testEscapeLessThan( implementation ) { +function testEscapeLessThan( implementation: Implementation ) { it( 'should escape less than', () => { const result = implementation( 'Chicken < Ribs' ); diff --git a/packages/patterns/src/components/pattern-overrides-block-controls.js b/packages/patterns/src/components/pattern-overrides-block-controls.js new file mode 100644 index 0000000000000..ae8ef5e1bb7da --- /dev/null +++ b/packages/patterns/src/components/pattern-overrides-block-controls.js @@ -0,0 +1,155 @@ +/** + * WordPress dependencies + */ +import { useId } from '@wordpress/element'; +import { __, sprintf } from '@wordpress/i18n'; +import { + DropdownMenu, + ToolbarItem, + __experimentalText as Text, +} from '@wordpress/components'; +import { store as blocksStore } from '@wordpress/blocks'; +import { useSelect } from '@wordpress/data'; +import { copy } from '@wordpress/icons'; +import { + store as blockEditorStore, + BlockIcon, + privateApis as blockEditorPrivateApis, + BlockControls, +} from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import { unlock } from '../lock-unlock'; +import { PATTERN_OVERRIDES_BINDING_SOURCE } from '../constants'; + +const { useBlockDisplayTitle } = unlock( blockEditorPrivateApis ); + +function PatternOverridesToolbarIndicator( { clientIds } ) { + const isSingleBlockSelected = clientIds.length === 1; + const { icon, firstBlockName } = useSelect( + ( select ) => { + const { getBlockAttributes, getBlockNamesByClientId } = + select( blockEditorStore ); + const { getBlockType, getActiveBlockVariation } = + select( blocksStore ); + const blockTypeNames = getBlockNamesByClientId( clientIds ); + const _firstBlockTypeName = blockTypeNames[ 0 ]; + const firstBlockType = getBlockType( _firstBlockTypeName ); + let _icon; + if ( isSingleBlockSelected ) { + const match = getActiveBlockVariation( + _firstBlockTypeName, + getBlockAttributes( clientIds[ 0 ] ) + ); + // Take into account active block variations. + _icon = match?.icon || firstBlockType.icon; + } else { + const isSelectionOfSameType = + new Set( blockTypeNames ).size === 1; + // When selection consists of blocks of multiple types, display an + // appropriate icon to communicate the non-uniformity. + _icon = isSelectionOfSameType ? firstBlockType.icon : copy; + } + + return { + icon: _icon, + firstBlockName: getBlockAttributes( clientIds[ 0 ] ).metadata + .name, + }; + }, + [ clientIds, isSingleBlockSelected ] + ); + const firstBlockTitle = useBlockDisplayTitle( { + clientId: clientIds[ 0 ], + maximumLength: 35, + } ); + + const blockDescription = isSingleBlockSelected + ? sprintf( + /* translators: %1s: The block type's name; %2s: The block's user-provided name (the same as the override name). */ + __( 'This %1$s is editable using the "%2$s" override.' ), + firstBlockTitle.toLowerCase(), + firstBlockName + ) + : __( 'These blocks are editable using overrides.' ); + + const descriptionId = useId(); + + return ( + + { ( toggleProps ) => ( + + + + } + toggleProps={ { + describedBy: blockDescription, + ...toggleProps, + } } + menuProps={ { + orientation: 'both', + 'aria-describedby': descriptionId, + } } + > + { () => ( + { blockDescription } + ) } + + ) } + + ); +} + +export default function PatternOverridesBlockControls() { + const { clientIds, hasPatternOverrides, hasParentPattern } = useSelect( + ( select ) => { + const { + getBlockAttributes, + getSelectedBlockClientIds, + getBlockParentsByBlockName, + } = select( blockEditorStore ); + const selectedClientIds = getSelectedBlockClientIds(); + const _hasPatternOverrides = selectedClientIds.every( + ( clientId ) => + Object.values( + getBlockAttributes( clientId )?.metadata?.bindings ?? {} + ).some( + ( binding ) => + binding?.source === PATTERN_OVERRIDES_BINDING_SOURCE + ) + ); + const _hasParentPattern = selectedClientIds.every( + ( clientId ) => + getBlockParentsByBlockName( clientId, 'core/block', true ) + .length > 0 + ); + return { + clientIds: selectedClientIds, + hasPatternOverrides: _hasPatternOverrides, + hasParentPattern: _hasParentPattern, + }; + }, + [] + ); + + return hasPatternOverrides && hasParentPattern ? ( + + + + ) : null; +} diff --git a/packages/patterns/src/components/style.scss b/packages/patterns/src/components/style.scss index 86af3df7ff3b9..30fe0300503c4 100644 --- a/packages/patterns/src/components/style.scss +++ b/packages/patterns/src/components/style.scss @@ -44,3 +44,16 @@ justify-content: center; } + +.patterns-pattern-overrides-toolbar-indicator__popover .components-popover__content { + min-width: 260px; + padding: $grid-unit-20; +} + +.patterns-pattern-overrides-toolbar-indicator .patterns-pattern-overrides-toolbar-indicator-icon.has-colors svg { + fill: var(--wp-block-synced-color); +} + +.editor-collapsible-block-toolbar .patterns-pattern-overrides-toolbar-indicator { + height: 32px; +} diff --git a/packages/patterns/src/private-apis.js b/packages/patterns/src/private-apis.js index 0553378cb5604..8893b3c57d736 100644 --- a/packages/patterns/src/private-apis.js +++ b/packages/patterns/src/private-apis.js @@ -17,6 +17,7 @@ import PatternsMenuItems from './components'; import RenamePatternCategoryModal from './components/rename-pattern-category-modal'; import PatternOverridesControls from './components/pattern-overrides-controls'; import ResetOverridesControl from './components/reset-overrides-control'; +import PatternOverridesBlockControls from './components/pattern-overrides-block-controls'; import { useAddPatternCategory } from './private-hooks'; import { PATTERN_TYPES, @@ -41,6 +42,7 @@ lock( privateApis, { RenamePatternCategoryModal, PatternOverridesControls, ResetOverridesControl, + PatternOverridesBlockControls, useAddPatternCategory, PATTERN_TYPES, PATTERN_DEFAULT_CATEGORY, diff --git a/packages/react-native-editor/CHANGELOG.md b/packages/react-native-editor/CHANGELOG.md index d0f9d10f2fe68..07dbe7a245995 100644 --- a/packages/react-native-editor/CHANGELOG.md +++ b/packages/react-native-editor/CHANGELOG.md @@ -11,6 +11,8 @@ For each user feature we should also add a importance categorization label to i ## Unreleased - [internal] Fix Inserter items list filtering [#62334] +- [*] Prevent hiding the keyboard when creating new list items [#62446] +- [*] RichText - Fix undefined onDelete callback [#62486] ## 1.120.0 - [*] Prevent deleting content when backspacing in the first Paragraph block [#62069] diff --git a/packages/style-engine/CONTRIBUTING.md b/packages/style-engine/CONTRIBUTING.md index 70bfddb8eb501..ab65920229b60 100644 --- a/packages/style-engine/CONTRIBUTING.md +++ b/packages/style-engine/CONTRIBUTING.md @@ -4,7 +4,7 @@ This document contains information you might need to know when extending or debu ## Workflow and build tooling -The Style Engine PHP and Javascript (JS) files exist inside the `style-engine` package. +The Style Engine PHP and JavaScript (JS) files exist inside the `style-engine` package. In order to use the Style Engine in the Block Editor, these files must be compiled (in the case of JS) and copied to the build folder. @@ -29,9 +29,9 @@ To start the JS unit tests, run: `npm run test:unit packages/style-engine/src/test/` -[PHP unit tests](https://github.com/WordPress/gutenberg/tree/HEAD/phpunit/style-engine) are located in the root `phpunit` directory. +[PHP unit tests](https://github.com/WordPress/gutenberg/tree/HEAD/phpunit/style-engine) are located in the root `phpunit` directory. -In order to test the latest version of the Style Engine and avoid conflicts with existing Core equivalents, all PHP unit tests call the `gutenberg_` functions and `_Gutenberg` classes. +In order to test the latest version of the Style Engine and avoid conflicts with existing Core equivalents, all PHP unit tests call the `gutenberg_` functions and `_Gutenberg` classes. Therefore, Style Engine PHP source files should be parsed and copied to the build folder before running tests. During development, this will happen as part of the `npm run dev` script. You can also trigger a build by executing `npm run build`. diff --git a/packages/style-engine/README.md b/packages/style-engine/README.md index f26f8ff7e779b..44b78eed8a81a 100644 --- a/packages/style-engine/README.md +++ b/packages/style-engine/README.md @@ -17,7 +17,7 @@ Upcoming tasks on the roadmap include, but are not limited to, the following: - Propose a way to control hierarchy and specificity, and make the style hierarchy cascade accessible and predictable. This might include preparing for CSS cascade layers until they become more widely supported, and allowing for opt-in support in Gutenberg via theme.json. - Refactor all blocks to consistently use the "style" attribute for all customizations, that is, deprecate preset-specific attributes such as `attributes.fontSize`. -For more information about the roadmap, please refer to [Block editor styles: initiatives and goals](https://make.wordpress.org/core/2022/06/24/block-editor-styles-initiatives-and-goals/) and the [Github project board](https://github.com/orgs/WordPress/projects/19). +For more information about the roadmap, please refer to [Block editor styles: initiatives and goals](https://make.wordpress.org/core/2022/06/24/block-editor-styles-initiatives-and-goals/) and the [GitHub project board](https://github.com/orgs/WordPress/projects/19). If you're making changes or additions to the Style Engine, please take a moment to read the [notes on contributing](https://github.com/WordPress/gutenberg/tree/HEAD/packages/style-engine/CONTRIBUTING.md). diff --git a/packages/token-list/CHANGELOG.md b/packages/token-list/CHANGELOG.md index 3cd9c7e7aa592..de8184dfc9792 100644 --- a/packages/token-list/CHANGELOG.md +++ b/packages/token-list/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Internal + +- Refactor to TypeScript ([#62584](https://github.com/WordPress/gutenberg/pull/62584)). + ## 3.0.0 (2024-05-31) ### Breaking Changes diff --git a/packages/token-list/src/index.js b/packages/token-list/src/index.ts similarity index 65% rename from packages/token-list/src/index.js rename to packages/token-list/src/index.ts index efd4ab68c478e..f4da3d23293ed 100644 --- a/packages/token-list/src/index.js +++ b/packages/token-list/src/index.ts @@ -4,49 +4,33 @@ * @see https://dom.spec.whatwg.org/#domtokenlist */ export default class TokenList { + private _currentValue: string; + private _valueAsArray: string[]; + /** * Constructs a new instance of TokenList. * - * @param {string} initialValue Initial value to assign. + * @param initialValue Initial value to assign. */ - constructor( initialValue = '' ) { + constructor( initialValue: string = '' ) { + this._currentValue = ''; + this._valueAsArray = []; this.value = initialValue; - - // Disable reason: These are type hints on the class. - /* eslint-disable no-unused-expressions */ - /** @type {string} */ - this._currentValue; - - /** @type {string[]} */ - this._valueAsArray; - /* eslint-enable no-unused-expressions */ } - /** - * @param {Parameters['entries']>} args - */ - entries( ...args ) { + entries( ...args: Parameters< Array< string >[ 'entries' ] > ) { return this._valueAsArray.entries( ...args ); } - /** - * @param {Parameters['forEach']>} args - */ - forEach( ...args ) { + forEach( ...args: Parameters< Array< string >[ 'forEach' ] > ) { return this._valueAsArray.forEach( ...args ); } - /** - * @param {Parameters['keys']>} args - */ - keys( ...args ) { + keys( ...args: Parameters< Array< string >[ 'keys' ] > ) { return this._valueAsArray.keys( ...args ); } - /** - * @param {Parameters['values']>} args - */ - values( ...args ) { + values( ...args: Parameters< Array< string >[ 'values' ] > ) { return this._valueAsArray.values( ...args ); } @@ -55,9 +39,9 @@ export default class TokenList { * * @see https://dom.spec.whatwg.org/#dom-domtokenlist-value * - * @return {string} Token set as string. + * @return Token set as string. */ - get value() { + get value(): string { return this._currentValue; } @@ -66,9 +50,9 @@ export default class TokenList { * * @see https://dom.spec.whatwg.org/#dom-domtokenlist-value * - * @param {string} value New token set as string. + * @param value New token set as string. */ - set value( value ) { + set value( value: string ) { value = String( value ); this._valueAsArray = [ ...new Set( value.split( /\s+/g ).filter( Boolean ) ), @@ -81,9 +65,9 @@ export default class TokenList { * * @see https://dom.spec.whatwg.org/#dom-domtokenlist-length * - * @return {number} Number of tokens. + * @return Number of tokens. */ - get length() { + get length(): number { return this._valueAsArray.length; } @@ -93,9 +77,9 @@ export default class TokenList { * @see https://dom.spec.whatwg.org/#DOMTokenList-stringification-behavior * @see https://www.ecma-international.org/ecma-262/9.0/index.html#sec-tostring * - * @return {string} Token set as string. + * @return Token set as string. */ - toString() { + toString(): string { return this.value; } @@ -104,9 +88,9 @@ export default class TokenList { * * @see https://dom.spec.whatwg.org/#domtokenlist * - * @return {IterableIterator} TokenList iterator. + * @return TokenList iterator. */ - *[ Symbol.iterator ]() { + *[ Symbol.iterator ](): IterableIterator< string > { return yield* this._valueAsArray; } @@ -115,11 +99,11 @@ export default class TokenList { * * @see https://dom.spec.whatwg.org/#dom-domtokenlist-item * - * @param {number} index Index at which to return token. + * @param index Index at which to return token. * - * @return {string|undefined} Token at index. + * @return Token at index. */ - item( index ) { + item( index: number ): string | undefined { return this._valueAsArray[ index ]; } @@ -128,11 +112,11 @@ export default class TokenList { * * @see https://dom.spec.whatwg.org/#dom-domtokenlist-contains * - * @param {string} item Token to test. + * @param item Token to test. * - * @return {boolean} Whether token is present. + * @return Whether token is present. */ - contains( item ) { + contains( item: string ): boolean { return this._valueAsArray.indexOf( item ) !== -1; } @@ -141,9 +125,9 @@ export default class TokenList { * * @see https://dom.spec.whatwg.org/#dom-domtokenlist-add * - * @param {...string} items Items to add. + * @param items Items to add. */ - add( ...items ) { + add( ...items: string[] ): void { this.value += ' ' + items.join( ' ' ); } @@ -152,9 +136,9 @@ export default class TokenList { * * @see https://dom.spec.whatwg.org/#dom-domtokenlist-remove * - * @param {...string} items Items to remove. + * @param items Items to remove. */ - remove( ...items ) { + remove( ...items: string[] ): void { this.value = this._valueAsArray .filter( ( val ) => ! items.includes( val ) ) .join( ' ' ); @@ -168,12 +152,12 @@ export default class TokenList { * * @see https://dom.spec.whatwg.org/#dom-domtokenlist-toggle * - * @param {string} token Token to toggle. - * @param {boolean} [force] Presence to force. + * @param token Token to toggle. + * @param [force] Presence to force. * - * @return {boolean} Whether token is present after toggle. + * @return Whether token is present after toggle. */ - toggle( token, force ) { + toggle( token: string, force?: boolean ): boolean { if ( undefined === force ) { force = ! this.contains( token ); } @@ -193,12 +177,12 @@ export default class TokenList { * * @see https://dom.spec.whatwg.org/#dom-domtokenlist-replace * - * @param {string} token Token to replace with `newToken`. - * @param {string} newToken Token to use in place of `token`. + * @param token Token to replace with `newToken`. + * @param newToken Token to use in place of `token`. * - * @return {boolean} Whether replacement occurred. + * @return Whether replacement occurred. */ - replace( token, newToken ) { + replace( token: string, newToken: string ): boolean { if ( ! this.contains( token ) ) { return false; } @@ -215,11 +199,12 @@ export default class TokenList { * * Always returns `true` in this implementation. * + * @param _token * @see https://dom.spec.whatwg.org/#dom-domtokenlist-supports * - * @return {boolean} Whether token is supported. + * @return Whether token is supported. */ - supports() { + supports( _token: string ): boolean { return true; } } diff --git a/packages/token-list/src/test/index.js b/packages/token-list/src/test/index.ts similarity index 98% rename from packages/token-list/src/test/index.js rename to packages/token-list/src/test/index.ts index e208742d0fc6c..fda0de0c53e48 100644 --- a/packages/token-list/src/test/index.js +++ b/packages/token-list/src/test/index.ts @@ -64,6 +64,7 @@ describe( 'token-list', () => { it( 'sets to stringified value', () => { const list = new TokenList(); + // @ts-expect-error The value should be a string, for testing we pass a "bad" value. list.value = undefined; expect( list.value ).toBe( 'undefined' ); diff --git a/packages/warning/CHANGELOG.md b/packages/warning/CHANGELOG.md index cfc8338f86c59..c26fb1ea5d4ba 100644 --- a/packages/warning/CHANGELOG.md +++ b/packages/warning/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Internal + +- Refactor to TypeScript ([#62557](https://github.com/WordPress/gutenberg/pull/62557)). + ## 3.0.0 (2024-05-31) ### Breaking Changes @@ -147,3 +151,4 @@ ## 1.0.0 (2020-02-04) Initial release. + diff --git a/packages/warning/src/index.js b/packages/warning/src/index.ts similarity index 86% rename from packages/warning/src/index.js rename to packages/warning/src/index.ts index 5744e99d94fd2..a5a092abbd212 100644 --- a/packages/warning/src/index.js +++ b/packages/warning/src/index.ts @@ -3,7 +3,7 @@ */ import { logged } from './utils'; -function isDev() { +function isDev(): boolean { // eslint-disable-next-line @wordpress/wp-global-usage return globalThis.SCRIPT_DEBUG === true; } @@ -11,7 +11,7 @@ function isDev() { /** * Shows a warning with `message` if environment is not `production`. * - * @param {string} message Message to show in the warning. + * @param message Message to show in the warning. * * @example * ```js @@ -25,7 +25,7 @@ function isDev() { * } * ``` */ -export default function warning( message ) { +export default function warning( message: string ): void { if ( ! isDev() ) { return; } @@ -46,6 +46,5 @@ export default function warning( message ) { } catch ( x ) { // Do nothing. } - logged.add( message ); } diff --git a/packages/warning/src/utils.js b/packages/warning/src/utils.ts similarity index 66% rename from packages/warning/src/utils.js rename to packages/warning/src/utils.ts index fb087255f6bf6..4f4b5d3e1f797 100644 --- a/packages/warning/src/utils.js +++ b/packages/warning/src/utils.ts @@ -1,7 +1,5 @@ /** * Object map tracking messages which have been logged, for use in ensuring a * message is only logged once. - * - * @type {Set} */ -export const logged = new Set(); +export const logged: Set< string > = new Set(); diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index bcf0d238400a0..59dcf07c040b5 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -4850,12 +4850,31 @@ public function test_get_top_level_background_image_styles() { $this->assertSame( $expected_styles, $theme_json->get_stylesheet(), 'Styles returned from "::get_stylesheet()" with top-level background image as string type does not match expectations' ); } - public function test_get_custom_css_handles_global_custom_css() { + /** + * Tests that base custom CSS is generated correctly. + */ + public function test_get_stylesheet_handles_base_custom_css() { + $theme_json = new WP_Theme_JSON_Gutenberg( + array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'styles' => array( + 'css' => 'body {color:purple;}', + ), + ) + ); + + $custom_css = 'body {color:purple;}'; + $this->assertSame( $custom_css, $theme_json->get_stylesheet( array( 'custom-css' ) ) ); + } + + /** + * Tests that block custom CSS is generated correctly. + */ + public function test_get_styles_for_block_handles_block_custom_css() { $theme_json = new WP_Theme_JSON_Gutenberg( array( 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, 'styles' => array( - 'css' => 'body {color:purple;}', 'blocks' => array( 'core/paragraph' => array( 'css' => 'color:red;', @@ -4865,8 +4884,17 @@ public function test_get_custom_css_handles_global_custom_css() { ) ); - $custom_css = 'body {color:purple;}:root :where(p){color:red;}'; - $this->assertSame( $custom_css, $theme_json->get_custom_css() ); + $paragraph_node = array( + 'name' => 'core/paragraph', + 'path' => array( 'styles', 'blocks', 'core/paragraph' ), + 'selector' => 'p', + 'selectors' => array( + 'root' => 'p', + ), + ); + + $custom_css = ':root :where(p){color:red;}'; + $this->assertSame( $custom_css, $theme_json->get_styles_for_block( $paragraph_node ) ); } /** diff --git a/platform-docs/src/components/HomepageThanks/index.js b/platform-docs/src/components/HomepageThanks/index.js index f543e3aaee5d2..61cfddf2a8fb9 100644 --- a/platform-docs/src/components/HomepageThanks/index.js +++ b/platform-docs/src/components/HomepageThanks/index.js @@ -31,7 +31,7 @@ export default function HomepageThanks() {
    diff --git a/schemas/json/.wp-env.json b/schemas/json/.wp-env.json new file mode 100644 index 0000000000000..b559cb9d8a502 --- /dev/null +++ b/schemas/json/.wp-env.json @@ -0,0 +1,107 @@ +{ + "title": "JSON schema for WordPress wp-env configuration files", + "$schema": "http://json-schema.org/draft-04/schema#", + "definitions": { + "//": { + "reference": "https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/" + }, + "wpEnvProperties": { + "properties": { + "core": { + "description": "The WordPress installation to use. If null is specified, wp-env will use the latest production release of WordPress.", + "default": null, + "oneOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "phpVersion": { + "description": "The PHP version to use. If null is specified, wp-env will use the default version used with production release of WordPress.", + "default": null, + "oneOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "plugins": { + "description": "A list of plugins to install and activate in the environment.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "themes": { + "description": "A list of themes to install in the environment.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "port": { + "description": "The primary port number to use for the installation. You'll access the instance through the port: 'http://localhost:8888'.", + "default": 8888, + "type": "integer" + }, + "config": { + "description": "Mapping of wp-config.php constants to their desired values.", + "default": {}, + "type": "object" + }, + "mappings": { + "description": "Mapping of WordPress directories to local directories to be mounted in the WordPress instance.", + "default": {}, + "type": "object" + } + } + } + }, + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/wpEnvProperties" + }, + { + "properties": { + "$schema": { + "type": "string" + }, + "env": { + "description": "The key env is available to override any of the above options on an individual-environment basis.", + "type": "object", + "default": {}, + "patternProperties": { + "[a-zA-Z]": { + "type": "object", + "$ref": "#/definitions/wpEnvProperties", + "additionalProperties": false + } + } + } + } + }, + { + "properties": { + "$schema": {}, + "core": {}, + "phpVersion": {}, + "plugins": {}, + "themes": {}, + "port": {}, + "config": {}, + "mappings": {}, + "env": {} + }, + "additionalProperties": false + } + ] +} diff --git a/schemas/json/theme.json b/schemas/json/theme.json index bdfea7279f67a..5b9e37ef7378a 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -444,9 +444,8 @@ "type": "string" }, "slug": { - "description": "Unique identifier for the space size preset. Will be sorted numerically. For best cross theme compatibility these should be in the form '10','20','30','40','50','60', etc. with '50' representing the 'Medium' size step.", - "type": "string", - "pattern": "^[0-9].*$" + "description": "Unique identifier for the space size preset. For best cross theme compatibility these should be in the form '10','20','30','40','50','60', etc. with '50' representing the 'Medium' size step. If all slugs begin with a number they will be merged with default and user slugs and sorted numerically.", + "type": "string" }, "size": { "description": "CSS space-size value, including units.", @@ -2288,6 +2287,10 @@ }, { "properties": { + "title": { + "type": "string", + "description": "Style variation name." + }, "blockTypes": { "type": "array", "items": { @@ -2696,6 +2699,10 @@ "type": "string", "description": "Title of the global styles variation. If not defined, the file name will be used." }, + "slug": { + "type": "string", + "description": "Slug of the global styles variation. If not defined, the kebab-case title will be used." + }, "description": { "type": "string", "description": "Description of the global styles variation." diff --git a/test/e2e/specs/editor/various/pattern-overrides.spec.js b/test/e2e/specs/editor/various/pattern-overrides.spec.js index f4648a03efe95..3587296a6b2a0 100644 --- a/test/e2e/specs/editor/various/pattern-overrides.spec.js +++ b/test/e2e/specs/editor/various/pattern-overrides.spec.js @@ -742,6 +742,59 @@ test.describe( 'Pattern Overrides', () => { ).toBeHidden(); } ); + test( 'overridden images should not have unsupported attributes set', async ( { + admin, + requestUtils, + editor, + } ) => { + const imageName = 'Editable image'; + const TEST_IMAGE_FILE_PATH = path.resolve( + __dirname, + '../../../assets/10x10_e2e_test_image_z9T8jK.png' + ); + const { id } = await requestUtils.createBlock( { + title: 'Pattern', + content: ` +
    +`, + status: 'publish', + } ); + + await admin.createNewPost(); + + await editor.insertBlock( { + name: 'core/block', + attributes: { ref: id }, + } ); + + const imageBlock = editor.canvas.getByRole( 'document', { + name: 'Block: Image', + } ); + await editor.selectBlocks( imageBlock ); + await imageBlock + .getByTestId( 'form-file-upload-input' ) + .setInputFiles( TEST_IMAGE_FILE_PATH ); + await expect( imageBlock.getByRole( 'img' ) ).toHaveCount( 1 ); + await expect( imageBlock.getByRole( 'img' ) ).toHaveAttribute( + 'src', + /\/wp-content\/uploads\// + ); + + // Because the image is an inner block of a controlled pattern block, + // `getBlocks` has to be called using the pattern block's client id. + const patternBlock = editor.canvas.getByRole( 'document', { + name: 'Block: Pattern', + } ); + const patternClientId = await patternBlock.getAttribute( 'data-block' ); + const patternInnerBlocks = await editor.getBlocks( { + clientId: patternClientId, + } ); + + // Link is an unsupported attribute, so should be undefined, even though + // the image block tries to set its attribute. + expect( patternInnerBlocks[ 0 ].attributes.link ).toBe( undefined ); + } ); + test( 'blocks with the same name should be synced', async ( { page, admin, diff --git a/test/e2e/specs/interactivity/deferred-store.spec.ts b/test/e2e/specs/interactivity/deferred-store.spec.ts index 4521322e61dfc..b6a7853c40dcd 100644 --- a/test/e2e/specs/interactivity/deferred-store.spec.ts +++ b/test/e2e/specs/interactivity/deferred-store.spec.ts @@ -21,6 +21,9 @@ test.describe( 'deferred store', () => { } ) => { const resultInput = page.getByTestId( 'result' ); await expect( resultInput ).toHaveText( '' ); + await page.evaluate( () => { + window.dispatchEvent( new Event( '_test_proceed_' ) ); + } ); await expect( resultInput ).toHaveText( 'Hello, world!' ); } ); @@ -31,6 +34,9 @@ test.describe( 'deferred store', () => { } ) => { const resultInput = page.getByTestId( 'result-getter' ); await expect( resultInput ).toHaveText( '' ); + await page.evaluate( () => { + window.dispatchEvent( new Event( '_test_proceed_' ) ); + } ); await expect( resultInput ).toHaveText( 'Hello, world!' ); } ); } );