diff --git a/.eslintrc.js b/.eslintrc.js index 6e87caa1ccc34..b5349d2de0a1f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -336,6 +336,7 @@ module.exports = { 'SelectControl', 'TextControl', 'ToggleGroupControl', + 'UnitControl', ].map( ( componentName ) => ( { // Falsy `__next40pxDefaultSize` without a non-default `size` prop. selector: `JSXOpeningElement[name.name="${ componentName }"]:not(:has(JSXAttribute[name.name="__next40pxDefaultSize"][value.expression.value!=false])):not(:has(JSXAttribute[name.name="size"][value.value!="default"]))`, @@ -351,7 +352,7 @@ module.exports = { 'FormFileUpload should have the `__next40pxDefaultSize` prop to opt-in to the new default size.', }, // Temporary rules until all existing components have the `__next40pxDefaultSize` prop. - ...[ 'Button', 'UnitControl' ].map( ( componentName ) => ( { + ...[ 'Button' ].map( ( componentName ) => ( { // Not strict. Allows pre-existing __next40pxDefaultSize={ false } usage until they are all manually updated. selector: `JSXOpeningElement[name.name="${ componentName }"]:not(:has(JSXAttribute[name.name="__next40pxDefaultSize"])):not(:has(JSXAttribute[name.name="size"]))`, message: diff --git a/.github/workflows/bundle-size.yml b/.github/workflows/bundle-size.yml index 6106eee492c32..499a2c020255c 100644 --- a/.github/workflows/bundle-size.yml +++ b/.github/workflows/bundle-size.yml @@ -52,5 +52,5 @@ jobs: - uses: preactjs/compressed-size-action@f780fd104362cfce9e118f9198df2ee37d12946c # v2.6.0 with: repo-token: '${{ secrets.GITHUB_TOKEN }}' - pattern: '{build/**/*.min.js,build/**/*.css}' + pattern: '{build/**/*.min.js,build/**/*.css,build-module/**/*.min.js}' clean-script: 'distclean' diff --git a/backport-changelog/6.7/7258.md b/backport-changelog/6.7/7258.md new file mode 100644 index 0000000000000..6714b13b70b8d --- /dev/null +++ b/backport-changelog/6.7/7258.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/7258 + +* https://github.com/WordPress/gutenberg/pull/64570 \ No newline at end of file diff --git a/bin/build-plugin-zip.sh b/bin/build-plugin-zip.sh index 4ba931c4a4aeb..ad627e05f0c69 100755 --- a/bin/build-plugin-zip.sh +++ b/bin/build-plugin-zip.sh @@ -98,6 +98,7 @@ zip -r gutenberg.zip \ packages/block-serialization-default-parser/*.php \ post-content.php \ $build_files \ + build-module \ readme.txt \ changelog.txt \ README.md diff --git a/changelog.txt b/changelog.txt index 0fb2b93056b9b..b0e6c8e907582 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,374 @@ == Changelog == += 19.2.0 = + +## Changelog + +### Enhancements + +- Add: Reorder control at the field level on the new view configuration UI. ([64381](https://github.com/WordPress/gutenberg/pull/64381)) +- Core Data Types: `recordId` can be a number. ([64796](https://github.com/WordPress/gutenberg/pull/64796)) +- Core Data: Derive collection totals for unbound queries. ([64772](https://github.com/WordPress/gutenberg/pull/64772)) +- Create Block: Set minimum supported WordPress version to 6.6. ([64920](https://github.com/WordPress/gutenberg/pull/64920)) +- Dataviews Filter search widget: Do not use Composite store. ([64985](https://github.com/WordPress/gutenberg/pull/64985)) +- Dataviews list view: Do not use Composite store. ([64987](https://github.com/WordPress/gutenberg/pull/64987)) +- Move bulk actions menu to the Footer, consolidate with floating toolbar and total items display. ([64268](https://github.com/WordPress/gutenberg/pull/64268)) +- Try: Update block warnings. ([64997](https://github.com/WordPress/gutenberg/pull/64997)) + +#### Components +- Add variants to InputControl prefix/suffix wrappers. ([64824](https://github.com/WordPress/gutenberg/pull/64824)) +- AlignmentMatrixControl: Do not use Composite store. ([64850](https://github.com/WordPress/gutenberg/pull/64850)) +- CircularOptionPicker: Stop using composite store. ([64833](https://github.com/WordPress/gutenberg/pull/64833)) +- Composite: Accept store props on top level component. ([64832](https://github.com/WordPress/gutenberg/pull/64832)) +- DataViews: Adds two new stories for edge cases. ([64975](https://github.com/WordPress/gutenberg/pull/64975)) +- Decrease standard padding to 12px. ([64708](https://github.com/WordPress/gutenberg/pull/64708)) +- DropdownMenuV2: Add GroupLabel subcomponent. ([64854](https://github.com/WordPress/gutenberg/pull/64854)) +- DropdownMenuV2: Update animation. ([64868](https://github.com/WordPress/gutenberg/pull/64868)) +- DropdownMenuV2: Use overloaded naming conventions. ([64654](https://github.com/WordPress/gutenberg/pull/64654)) +- InputControl: Tighten gap between input and prefix/suffix. ([64908](https://github.com/WordPress/gutenberg/pull/64908)) +- Navigator: Polish Storybook examples. ([64798](https://github.com/WordPress/gutenberg/pull/64798)) +- Navigator: Remove location history, simplify internal logic. ([64675](https://github.com/WordPress/gutenberg/pull/64675)) +- UnitControl: Update unit select styles. ([64712](https://github.com/WordPress/gutenberg/pull/64712)) +- Update hard-coded border-radius instances. ([64693](https://github.com/WordPress/gutenberg/pull/64693)) +- Update modal animation. ([64580](https://github.com/WordPress/gutenberg/pull/64580)) + +#### Block bindings +- Add warning in attributes connected to invalid sources. ([65002](https://github.com/WordPress/gutenberg/pull/65002)) +- Allow only admin users to create and modify bindings by default. ([64570](https://github.com/WordPress/gutenberg/pull/64570)) +- Lock editing in fields in editor if meta fields panel is opened. ([64738](https://github.com/WordPress/gutenberg/pull/64738)) +- Rely on `Text` component instead of `Truncate` in bindings panel. ([65007](https://github.com/WordPress/gutenberg/pull/65007)) +- Remove `getPlaceholder` API and rely on `key` argument or source label. ([64910](https://github.com/WordPress/gutenberg/pull/64910)) + +#### Data Views +- Add: Reorder control at the field level on the new view configuration UI. ([64381](https://github.com/WordPress/gutenberg/pull/64381)) +- Dataviews Filter search widget: Do not use Composite store. ([64985](https://github.com/WordPress/gutenberg/pull/64985)) +- Dataviews list view: Do not use Composite store. ([64987](https://github.com/WordPress/gutenberg/pull/64987)) +- Move bulk actions menu to the Footer, consolidate with floating toolbar and total items display. ([64268](https://github.com/WordPress/gutenberg/pull/64268)) + +#### Block Editor +- Add 'Reset' option to MediaReplaceFlow component. ([64826](https://github.com/WordPress/gutenberg/pull/64826)) +- Block Patterns List: Do not use Composite store. ([64983](https://github.com/WordPress/gutenberg/pull/64983)) +- Remove the Shuffle block toolbar button. ([64954](https://github.com/WordPress/gutenberg/pull/64954)) +- Show block icon in contentOnly toolbar. ([64694](https://github.com/WordPress/gutenberg/pull/64694)) + +#### Block Library +- Cover Block: Move Clear Media button from Inspector Controls to Block Controls. ([64630](https://github.com/WordPress/gutenberg/pull/64630)) +- Improve Social Icons setup and appending. ([64877](https://github.com/WordPress/gutenberg/pull/64877)) +- Pagination Block: Fix inconsistent margins between editor and frontend. ([64874](https://github.com/WordPress/gutenberg/pull/64874)) +- Tag Cloud: Improve state of block with no tags. ([63774](https://github.com/WordPress/gutenberg/pull/63774)) + +#### Block Locking +- ContentOnly: Add support for block styles on top-level contentOnly locked blocks. ([64872](https://github.com/WordPress/gutenberg/pull/64872)) +- Only show title in content only toolbar if has title value. ([64840](https://github.com/WordPress/gutenberg/pull/64840)) +- Remove ability to crop image if content only mode. ([64838](https://github.com/WordPress/gutenberg/pull/64838)) +- Rename Alt to Alternative Text in content only image toolbar. ([64841](https://github.com/WordPress/gutenberg/pull/64841)) + +#### Interactivity API +- Categories Block: Add iAPI directive for client-side routing. ([64907](https://github.com/WordPress/gutenberg/pull/64907)) +- Improve internal `deepMerge` function. ([64879](https://github.com/WordPress/gutenberg/pull/64879)) + +#### Global Styles +- Hide typeset button when there are no typesets available. ([64515](https://github.com/WordPress/gutenberg/pull/64515)) +- Use four color palette colors instead of five for useStylesPreviewColors. ([64700](https://github.com/WordPress/gutenberg/pull/64700)) + +#### Zoom Out +- Add "Edit" button to Zoom Out mode toolbar. ([64571](https://github.com/WordPress/gutenberg/pull/64571)) +- Double click block to exit zoom out mode. ([64573](https://github.com/WordPress/gutenberg/pull/64573)) + +#### Design Tools +- Comment Edit Link: Add Border Block Support. ([64239](https://github.com/WordPress/gutenberg/pull/64239)) +- Comment Reply Link: Add border support. ([64271](https://github.com/WordPress/gutenberg/pull/64271)) + +#### Icons +- Add thumbs up and down icons. ([65004](https://github.com/WordPress/gutenberg/pull/65004)) + +#### Site Editor +- Apply radius scale in the editor. ([64930](https://github.com/WordPress/gutenberg/pull/64930)) + +#### Post Editor +- Post publish upload media dialog: Handle upload errors. ([64823](https://github.com/WordPress/gutenberg/pull/64823)) + +#### Typography +- Fluid typography: Allow individual preset overrides. ([64790](https://github.com/WordPress/gutenberg/pull/64790)) + +#### Media +- Add experiment for client-side media processing. ([64650](https://github.com/WordPress/gutenberg/pull/64650)) + +#### REST API +- Core Data: Resolve entity collection user permissions. ([64504](https://github.com/WordPress/gutenberg/pull/64504)) + +#### Block Transforms +- Details block: Add transform from any block type. ([63422](https://github.com/WordPress/gutenberg/pull/63422)) + + +### New APIs + +#### Extensibility +- Editor: Add extensibility to PreviewOptions v2. ([64644](https://github.com/WordPress/gutenberg/pull/64644)) + + +### Bug Fixes + +- Add safeguard to `mediaUploadMiddleware`. ([64843](https://github.com/WordPress/gutenberg/pull/64843)) +- Allow multi-select on iOS Safari/touch devices. ([63671](https://github.com/WordPress/gutenberg/pull/63671)) +- Core Data: Fix the 'query._fields' property check inside 'getEntityRecord' resolver. ([65079](https://github.com/WordPress/gutenberg/pull/65079)) +- Fix Modify content-locked menu item not showing if the block is not selected. ([61605](https://github.com/WordPress/gutenberg/pull/61605)) +- Fix editor error in Safari due to availability of checkVisibility method. ([65069](https://github.com/WordPress/gutenberg/pull/65069)) +- Fix: Pagination arrows are pointing in the wrong direction in RTL languages. ([64962](https://github.com/WordPress/gutenberg/pull/64962)) +- Footnotes: Only replace attribute if footnotes were detected. ([63935](https://github.com/WordPress/gutenberg/pull/63935)) +- Paste: Fix image paste from Google Forms. ([64502](https://github.com/WordPress/gutenberg/pull/64502)) +- Revert Focus pattern inserter search when activating zoom out inserter. ([64748](https://github.com/WordPress/gutenberg/pull/64748)) +- Try: Update block warnings. ([64997](https://github.com/WordPress/gutenberg/pull/64997)) + +#### Block Library +- De-duplicate block toolbar icons for patterns. ([65054](https://github.com/WordPress/gutenberg/pull/65054)) +- Fix: Page list: Pages without a title has no link text. ([64297](https://github.com/WordPress/gutenberg/pull/64297)) +- Position BlockToolbar below all of the selected block's descendants. ([62711](https://github.com/WordPress/gutenberg/pull/62711)) +- Site Logo Block: Fix non-admin users seeing zero character. ([65010](https://github.com/WordPress/gutenberg/pull/65010)) +- Site Logo: Fix loader alignment issue. ([64919](https://github.com/WordPress/gutenberg/pull/64919)) +- Template Part: Hide Advanced panel for non-admin users. ([64721](https://github.com/WordPress/gutenberg/pull/64721)) +- Video Block: Fix layout issue. ([64834](https://github.com/WordPress/gutenberg/pull/64834)) + +#### Components +- ColorPalette utils: Do not normalize undefined color values. ([64969](https://github.com/WordPress/gutenberg/pull/64969)) +- DatePicker: Restore round radius for event dot. ([65031](https://github.com/WordPress/gutenberg/pull/65031)) +- DropdownMenuV2: Fix active and focus-visible item glitches. ([64942](https://github.com/WordPress/gutenberg/pull/64942)) +- DropdownMenuV2: Remove flashing styles when moving focus with keyboard. ([64873](https://github.com/WordPress/gutenberg/pull/64873)) +- Fixes "delete" action in DataViews' storybook. ([64901](https://github.com/WordPress/gutenberg/pull/64901)) +- Navigator: Fix isInitial, refine focusSelector logic. ([64786](https://github.com/WordPress/gutenberg/pull/64786)) +- Range control: Restore bottom margin rule. ([65035](https://github.com/WordPress/gutenberg/pull/65035)) + +#### Post Editor +- Add back editor-post-locked-modal to post lock component. ([64257](https://github.com/WordPress/gutenberg/pull/64257)) +- Add context to `View` string in post actions. ([65046](https://github.com/WordPress/gutenberg/pull/65046)) +- Apply space below content using a pseudo-element instead of padding-bottom. ([64639](https://github.com/WordPress/gutenberg/pull/64639)) +- Post Title: Fix pasting in Safari. ([64671](https://github.com/WordPress/gutenberg/pull/64671)) +- Post Title: Move selection at the end after pasting over the text. ([64665](https://github.com/WordPress/gutenberg/pull/64665)) +- Post publish upload media dialog: Fix silent failure. ([64741](https://github.com/WordPress/gutenberg/pull/64741)) + +#### Data Views +- DataViews: Fix field reordering and visibility logic. ([64999](https://github.com/WordPress/gutenberg/pull/64999)) +- Fix actions scrim in list layout. ([64696](https://github.com/WordPress/gutenberg/pull/64696)) +- Fix data views style inheritance. ([64933](https://github.com/WordPress/gutenberg/pull/64933)) +- Fix: Impossible to see pagination on viewports between small and medium. ([64844](https://github.com/WordPress/gutenberg/pull/64844)) +- List layout: Update broken styles. ([64837](https://github.com/WordPress/gutenberg/pull/64837)) + +#### Block Editor +- Add conditions when the Shuffle button can be displayed. ([64888](https://github.com/WordPress/gutenberg/pull/64888)) +- Inserter: Fix subtle media insertion error. ([65057](https://github.com/WordPress/gutenberg/pull/65057)) +- Post Editor: Fix click space after post content to append. ([64992](https://github.com/WordPress/gutenberg/pull/64992)) +- Writing flow: Fix triple click inside text blocks. ([64928](https://github.com/WordPress/gutenberg/pull/64928)) + +#### Global Styles +- Adjust spacing of background panel. ([64880](https://github.com/WordPress/gutenberg/pull/64880)) +- Cast globalFluid value to boolean. ([64882](https://github.com/WordPress/gutenberg/pull/64882)) +- Fix site editor broken when fontWeight is not defined or is an integer in theme.json or theme styles. ([64953](https://github.com/WordPress/gutenberg/pull/64953)) +- Fixes the default fluid value on the UI based on the global typography fluid value. ([64803](https://github.com/WordPress/gutenberg/pull/64803)) + +#### Block bindings +- Change placeholder when attribute is bound. ([64903](https://github.com/WordPress/gutenberg/pull/64903)) +- Fix empty custom fields not being editable in bindings. ([64881](https://github.com/WordPress/gutenberg/pull/64881)) + +#### CSS & Styling +- Featured Image Block: Reduce CSS specificity. ([64463](https://github.com/WordPress/gutenberg/pull/64463)) +- Retain the same specificity for non iframed selectors. ([64534](https://github.com/WordPress/gutenberg/pull/64534)) + +#### Patterns +- Pass 'blocks' as inner blocks value. ([65029](https://github.com/WordPress/gutenberg/pull/65029)) + +#### Synced Patterns +- Pattern: Don't render block controls when an entity is missing. ([65028](https://github.com/WordPress/gutenberg/pull/65028)) + +#### Site Editor +- DataViews: Fix pattern title direction in RTL languages. ([64967](https://github.com/WordPress/gutenberg/pull/64967)) + +#### Typography +- Site Title, Post Title: Fix typography for blocks with `a` children. ([64911](https://github.com/WordPress/gutenberg/pull/64911)) + +#### NUX +- Fix visibility of the template Welcome Guide in the Site Editor. ([64789](https://github.com/WordPress/gutenberg/pull/64789)) + +#### Document Settings +- Fix: Adjust Site URL Styles to Prevent Overflow in Pre-Publish Component. ([64745](https://github.com/WordPress/gutenberg/pull/64745)) + +#### Zoom Out +- Focus selected block in editor canvas when clicking edit button on zoom out mode toolbar. ([64725](https://github.com/WordPress/gutenberg/pull/64725)) + +#### Templates API +- Make plugin-registered templates overriden by themes to fall back to plugin-registered title and description. ([64610](https://github.com/WordPress/gutenberg/pull/64610)) + +#### Block Style Variations +- Block Styles: Ensure unique classname generation for variations. ([64511](https://github.com/WordPress/gutenberg/pull/64511)) + +#### Distraction Free +- Make Distraction Free not conditional on viewport width. ([63949](https://github.com/WordPress/gutenberg/pull/63949)) + +#### Media +- Limit the max width of image to its container size. ([63341](https://github.com/WordPress/gutenberg/pull/63341)) + + +### Accessibility + +#### Components +- AlignmentMatrixControl: Simplify styles and markup. ([64827](https://github.com/WordPress/gutenberg/pull/64827)) +- TimePicker: Use ToggleGroupControl for AM/PM toggle. ([64800](https://github.com/WordPress/gutenberg/pull/64800)) + +#### Block Editor +- Layout content and wide width controls: Remove confusing icon and clarify labels. ([64891](https://github.com/WordPress/gutenberg/pull/64891)) + +#### Font Library +- Font Library Modal: Group font variations as a list. ([64029](https://github.com/WordPress/gutenberg/pull/64029)) + +#### Post Editor +- Fix the post summary Status toggle button accessibility. ([63988](https://github.com/WordPress/gutenberg/pull/63988)) + + +### Performance + +- Core Data: Avoid loops in 'registry.batch' calls. ([64955](https://github.com/WordPress/gutenberg/pull/64955)) +- Core data: Performance: Fix receive user permissions. ([64894](https://github.com/WordPress/gutenberg/pull/64894)) +- Reusable blocks: Fix performance of __experimentalGetAllowedPatterns. ([64871](https://github.com/WordPress/gutenberg/pull/64871)) + +#### Site Editor +- Add 'OPTIONS /page' to preloaded paths. ([64890](https://github.com/WordPress/gutenberg/pull/64890)) +- Editor: Don't use selector shortcuts for the Site data. ([64884](https://github.com/WordPress/gutenberg/pull/64884)) + +#### Interactivity API +- Prevent calling `proxifyContext` with context proxies inside `wp-context`. ([65090](https://github.com/WordPress/gutenberg/pull/65090)) + +#### Block Library +- Media & Text: Don't use background-image. ([64981](https://github.com/WordPress/gutenberg/pull/64981)) + +#### Post Editor +- Editor: Remove create template permission check in 'VisualEditor'. ([64905](https://github.com/WordPress/gutenberg/pull/64905)) + +#### Block Editor +- Inserter: Use lighter grammar parse to check allowed status. ([64902](https://github.com/WordPress/gutenberg/pull/64902)) + +#### Patterns +- Shuffle: Don't call '__experimentalGetAllowedPatterns' for every block. ([64736](https://github.com/WordPress/gutenberg/pull/64736)) + + +### Experiments + +#### Zoom Out +- Add new zoom out experiment. ([65048](https://github.com/WordPress/gutenberg/pull/65048)) +- Remove the experiment that connects zoom out to the pattern inserter. ([65045](https://github.com/WordPress/gutenberg/pull/65045)) + + +### Documentation + +- Add a new section to the SlotFill reference to show how to conditionally render Fills. ([64807](https://github.com/WordPress/gutenberg/pull/64807)) +- Added Global Documentation in several php file. ([64956](https://github.com/WordPress/gutenberg/pull/64956)) +- Components: Move displayName assignment to top-level files. ([64793](https://github.com/WordPress/gutenberg/pull/64793)) +- Composite: Add context-forwarding with SlotFill example. ([65051](https://github.com/WordPress/gutenberg/pull/65051)) +- Composite: Fix Storybook docgen. ([64682](https://github.com/WordPress/gutenberg/pull/64682)) +- Corrected HTML Syntax for Closing Tags in api-reference.md file. ([64778](https://github.com/WordPress/gutenberg/pull/64778)) +- DataViews docs: Fix typo in `direction` values. ([64973](https://github.com/WordPress/gutenberg/pull/64973)) +- DataViews: Add story about combining fields. ([64984](https://github.com/WordPress/gutenberg/pull/64984)) +- DataViews: Document combined fields. ([64904](https://github.com/WordPress/gutenberg/pull/64904)) +- Dataviews docs: Layout properties checks and link. ([64918](https://github.com/WordPress/gutenberg/pull/64918)) +- Docs/iAPI: Fix wrong code snippets in API reference. ([64416](https://github.com/WordPress/gutenberg/pull/64416)) +- Docs: Update design resources to indicate edit isn't free. ([64792](https://github.com/WordPress/gutenberg/pull/64792)) +- PluginSidebarMoreMenuItem: Update example, screenshot and description. ([64761](https://github.com/WordPress/gutenberg/pull/64761)) +- Provide better examples and remove outdating site edit references for the MainDashboardButton SlotFill. ([64753](https://github.com/WordPress/gutenberg/pull/64753)) +- Removing ryanwelcher as a documentation codeowner because my inbox is dead. ([64762](https://github.com/WordPress/gutenberg/pull/64762)) +- Storybook: Hide deprecated `__next36pxDefaultSize` prop. ([64806](https://github.com/WordPress/gutenberg/pull/64806)) +- Update screenshot and description for PluginSidebar slot. ([64759](https://github.com/WordPress/gutenberg/pull/64759)) +- Update text to match code examples. ([64751](https://github.com/WordPress/gutenberg/pull/64751)) +- Update the import for PluginBlockSettingsMenuItem. ([64758](https://github.com/WordPress/gutenberg/pull/64758)) +- Updated Several Typos in Doc files. ([64787](https://github.com/WordPress/gutenberg/pull/64787)) +- [Docs]: Update Usage Example for block variation picker: Fix Import from Wrong Package. ([55555](https://github.com/WordPress/gutenberg/pull/55555)) + + +### Code Quality + +- Button: Add lint rule for 40px size prop usage. ([64835](https://github.com/WordPress/gutenberg/pull/64835)) +- Dataviews filter: Move resetValueOnSelect prop to combobox item. ([64852](https://github.com/WordPress/gutenberg/pull/64852)) +- Rename refs to fix tons of 'Mutating a value' errors in react-compiler. ([64718](https://github.com/WordPress/gutenberg/pull/64718)) +- Rich text: Add comment on placeholder approach. ([64945](https://github.com/WordPress/gutenberg/pull/64945)) +- SelectControl: Fix remaining 40px size violations. ([64831](https://github.com/WordPress/gutenberg/pull/64831)) +- Simplify useResizeObserver. ([64820](https://github.com/WordPress/gutenberg/pull/64820)) +- Typography: Backport comment changes only. ([64859](https://github.com/WordPress/gutenberg/pull/64859)) +- UnitControl: Add lint rule for 40px size prop usage. ([64520](https://github.com/WordPress/gutenberg/pull/64520)) +- UnitControl: Move to stricter lint rule for 40px size adherence. ([65017](https://github.com/WordPress/gutenberg/pull/65017)) +- Use rectIntersect instead of a custom argument to rectUnion. ([64855](https://github.com/WordPress/gutenberg/pull/64855)) + +#### Site Editor +- Add Custom Template modal: Do not use Composite store. ([65044](https://github.com/WordPress/gutenberg/pull/65044)) +- Add units to avoid console warning. ([64810](https://github.com/WordPress/gutenberg/pull/64810)) +- Edit Site Layout: Remove redundant fullResizer. ([64821](https://github.com/WordPress/gutenberg/pull/64821)) +- Remove unused 'useSiteEditorSettings' hook. ([64892](https://github.com/WordPress/gutenberg/pull/64892)) +- Style Book: Do not use Composite store. ([65047](https://github.com/WordPress/gutenberg/pull/65047)) + +#### Block Editor +- Block Inserter Listbox: Do not use Composite store. ([65042](https://github.com/WordPress/gutenberg/pull/65042)) +- Block Inserter Media List: Do not use Composite store. ([65043](https://github.com/WordPress/gutenberg/pull/65043)) +- Block Pattern Setup: Do not use Composite store. ([65039](https://github.com/WordPress/gutenberg/pull/65039)) +- Global Styles Shadow Panel: Do not use Composite store. ([65041](https://github.com/WordPress/gutenberg/pull/65041)) +- Pattern Transformations Menu: Do not use Composite store. ([65040](https://github.com/WordPress/gutenberg/pull/65040)) + +#### Zoom Out +- Add selector for getting section root clientId. ([65001](https://github.com/WordPress/gutenberg/pull/65001)) +- Don't pass 'rootClientId' to block lock selectors. ([64887](https://github.com/WordPress/gutenberg/pull/64887)) +- Fix error and improve privacy of sectionRootClientId setting. ([65000](https://github.com/WordPress/gutenberg/pull/65000)) + +#### Components +- AlignmentMatrixControl: Promote to stable. ([60913](https://github.com/WordPress/gutenberg/pull/60913)) +- Deprecate `DimensionControl`. ([64951](https://github.com/WordPress/gutenberg/pull/64951)) + +#### Block Library +- Block Bindings: Fix ESLint warnings. ([64684](https://github.com/WordPress/gutenberg/pull/64684)) +- Video Block: Remove custom CSS code for placeholder style. ([64861](https://github.com/WordPress/gutenberg/pull/64861)) + +#### Global Styles +- Allow referenced zero value and simplify getValueFromObjectPath calls. ([64836](https://github.com/WordPress/gutenberg/pull/64836)) +- Navigator: Replace deprecated NavigatorToParentButton with NavigatorBackButton. ([64775](https://github.com/WordPress/gutenberg/pull/64775)) + +#### Block Directory +- Downloadable Block List: Do not use composite store. ([65038](https://github.com/WordPress/gutenberg/pull/65038)) + +#### Design Tools +- Color panel hook: Rename to remove ambiguity. ([64993](https://github.com/WordPress/gutenberg/pull/64993)) + + +### Tools + +- Add remaining i18n rules to recommended ESLint ruleset. ([64710](https://github.com/WordPress/gutenberg/pull/64710)) +- Scripts: Added chunk filename in webpack configuration to avoid reading stale files. ([58176](https://github.com/WordPress/gutenberg/pull/58176)) +- Scripts: Import CSS files before optimization. ([61121](https://github.com/WordPress/gutenberg/pull/61121)) +- Scripts: Update `puppeteer-core` dependency. ([64597](https://github.com/WordPress/gutenberg/pull/64597)) + +#### Testing +- Flaky Test: Fix "Sorting" test in new-templates-list.spec.js. ([64776](https://github.com/WordPress/gutenberg/pull/64776)) +- Revert "Downgrade node 22(.5) unit tests to 22.4 (#63728)". ([63758](https://github.com/WordPress/gutenberg/pull/63758)) + + +### Various + +- Dataviews docs: Fixed property name for defaultLayouts settings. ([64897](https://github.com/WordPress/gutenberg/pull/64897)) +- task: Remove dcalhoun code owner. ([64886](https://github.com/WordPress/gutenberg/pull/64886)) + + +## First-time contributors + +The following PRs were merged by first-time contributors: + +- @Imran92: Fix site editor broken when fontWeight is not defined or is an integer in theme.json or theme styles. ([64953](https://github.com/WordPress/gutenberg/pull/64953)) +- @jacobcassidy: Scripts: Update `puppeteer-core` dependency. ([64597](https://github.com/WordPress/gutenberg/pull/64597)) +- @jawadmalikdev: [Docs]: Update Usage Example for block variation picker: Fix Import from Wrong Package. ([55555](https://github.com/WordPress/gutenberg/pull/55555)) +- @lezama: Editor: Add extensibility to PreviewOptions v2. ([64644](https://github.com/WordPress/gutenberg/pull/64644)) +- @rithik56: Scripts: Added chunk filename in webpack configuration to avoid reading stale files. ([58176](https://github.com/WordPress/gutenberg/pull/58176)) +- @rohitmathur-7: Cover Block: Move Clear Media button from Inspector Controls to Block Controls. ([64630](https://github.com/WordPress/gutenberg/pull/64630)) + + +## Contributors + +The following contributors merged PRs in this release: + +@aaronrobertshaw @afercia @akasunil @Aljullu @andrewserong @atachibana @benoitchantre @carolinan @cbravobernal @ciampo @DAreRodz @dcalhoun @desrosj @dsas @ellatrix @fullofcaffeine @getdave @gziolo @Imran92 @imrraaj @jacobcassidy @jameskoster @jasmussen @jawadmalikdev @jeryj @jorgefilipecosta @jsnajdr @juanmaguitar @kevin940726 @lezama @Mamaduka @matiasbenedetto @mirka @noisysocks @ntsekouras @oandregal @ockham @rafaelgallani @ramonjd @richtabor @rithik56 @rohitmathur-7 @ryanwelcher @SantosGuillamot @scruffian @sgomes @shail-mehta @spacedmonkey @stokesman @swissspidy @t-hamano @talldan @tjcafferkey @tyxla + + = 19.1.0 = ## Changelog diff --git a/docs/manifest.json b/docs/manifest.json index e4eba19d99fa2..d7f74d47995b6 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1697,6 +1697,12 @@ "markdown_source": "../packages/eslint-plugin/README.md", "parent": "packages" }, + { + "title": "@wordpress/fields", + "slug": "packages-fields", + "markdown_source": "../packages/fields/README.md", + "parent": "packages" + }, { "title": "@wordpress/format-library", "slug": "packages-format-library", diff --git a/docs/reference-guides/block-api/block-context.md b/docs/reference-guides/block-api/block-context.md index 5fdc670fe6040..09c33dfb71b7c 100644 --- a/docs/reference-guides/block-api/block-context.md +++ b/docs/reference-guides/block-api/block-context.md @@ -141,7 +141,7 @@ export default function Edit( props ) { return (
setAttributes( { recordId: Number( val ) } ) diff --git a/gutenberg.php b/gutenberg.php index f0e2f94ef57fd..c9c6e09a8092b 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -5,7 +5,7 @@ * Description: Printing since 1440. This is the development plugin for the block editor, site editor, and other future WordPress core functionality. * Requires at least: 6.5 * Requires PHP: 7.2 - * Version: 19.1.0 + * Version: 19.2.0 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/lib/compat/wordpress-6.6/rest-api.php b/lib/compat/wordpress-6.6/rest-api.php index fee9c71b86c07..eadd3b1d376a7 100644 --- a/lib/compat/wordpress-6.6/rest-api.php +++ b/lib/compat/wordpress-6.6/rest-api.php @@ -88,76 +88,116 @@ function gutenberg_register_global_styles_revisions_endpoints() { add_action( 'rest_api_init', 'gutenberg_register_global_styles_revisions_endpoints' ); -if ( ! function_exists( 'gutenberg_register_wp_rest_themes_stylesheet_directory_uri_field' ) ) { - /** - * Adds `stylesheet_uri` fields to WP_REST_Themes_Controller class. - */ - function gutenberg_register_wp_rest_themes_stylesheet_directory_uri_field() { - register_rest_field( - 'theme', - 'stylesheet_uri', - array( - 'get_callback' => function ( $item ) { - if ( ! empty( $item['stylesheet'] ) ) { - $theme = wp_get_theme( $item['stylesheet'] ); - $current_theme = wp_get_theme(); - if ( $theme->get_stylesheet() === $current_theme->get_stylesheet() ) { - return get_stylesheet_directory_uri(); - } else { - return $theme->get_stylesheet_directory_uri(); - } +/** + * Adds `stylesheet_uri` fields to WP_REST_Themes_Controller class. + */ +function gutenberg_register_wp_rest_themes_stylesheet_directory_uri_field() { + register_rest_field( + 'theme', + 'stylesheet_uri', + array( + 'get_callback' => function ( $item ) { + if ( ! empty( $item['stylesheet'] ) ) { + $theme = wp_get_theme( $item['stylesheet'] ); + $current_theme = wp_get_theme(); + if ( $theme->get_stylesheet() === $current_theme->get_stylesheet() ) { + return get_stylesheet_directory_uri(); + } else { + return $theme->get_stylesheet_directory_uri(); } + } - return null; - }, - 'schema' => array( - 'type' => 'string', - 'description' => __( 'The uri for the theme\'s stylesheet directory.', 'gutenberg' ), - 'format' => 'uri', - 'readonly' => true, - 'context' => array( 'view', 'edit', 'embed' ), - ), - ) - ); - } + return null; + }, + 'schema' => array( + 'type' => 'string', + 'description' => __( 'The uri for the theme\'s stylesheet directory.', 'gutenberg' ), + 'format' => 'uri', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + ) + ); } add_action( 'rest_api_init', 'gutenberg_register_wp_rest_themes_stylesheet_directory_uri_field' ); -if ( ! function_exists( 'gutenberg_register_wp_rest_themes_template_directory_uri_field' ) ) { - /** - * Adds `template_uri` fields to WP_REST_Themes_Controller class. - */ - function gutenberg_register_wp_rest_themes_template_directory_uri_field() { - register_rest_field( - 'theme', - 'template_uri', - array( - 'get_callback' => function ( $item ) { - if ( ! empty( $item['stylesheet'] ) ) { - $theme = wp_get_theme( $item['stylesheet'] ); - $current_theme = wp_get_theme(); - if ( $theme->get_stylesheet() === $current_theme->get_stylesheet() ) { - return get_template_directory_uri(); - } else { - return $theme->get_template_directory_uri(); - } +/** + * Adds `template_uri` fields to WP_REST_Themes_Controller class. + */ +function gutenberg_register_wp_rest_themes_template_directory_uri_field() { + register_rest_field( + 'theme', + 'template_uri', + array( + 'get_callback' => function ( $item ) { + if ( ! empty( $item['stylesheet'] ) ) { + $theme = wp_get_theme( $item['stylesheet'] ); + $current_theme = wp_get_theme(); + if ( $theme->get_stylesheet() === $current_theme->get_stylesheet() ) { + return get_template_directory_uri(); + } else { + return $theme->get_template_directory_uri(); } + } - return null; - }, - 'schema' => array( - 'type' => 'string', - 'description' => __( 'The uri for the theme\'s template directory. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme\'s stylesheet directory.', 'gutenberg' ), - 'format' => 'uri', - 'readonly' => true, - 'context' => array( 'view', 'edit', 'embed' ), - ), - ) - ); - } + return null; + }, + 'schema' => array( + 'type' => 'string', + 'description' => __( 'The uri for the theme\'s template directory. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme\'s stylesheet directory.', 'gutenberg' ), + 'format' => 'uri', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + ) + ); } add_action( 'rest_api_init', 'gutenberg_register_wp_rest_themes_template_directory_uri_field' ); +/** + * Adds `template` and `template_lock` fields to WP_REST_Post_Types_Controller class. + */ +function gutenberg_register_wp_rest_post_types_controller_fields() { + register_rest_field( + 'type', + 'template', + array( + 'get_callback' => function ( $item ) { + $post_type = get_post_type_object( $item['slug'] ); + if ( ! empty( $post_type ) ) { + return $post_type->template ?? array(); + } + }, + 'schema' => array( + 'type' => 'array', + 'description' => __( 'The block template associated with the post type.', 'gutenberg' ), + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + ) + ); + register_rest_field( + 'type', + 'template_lock', + array( + 'get_callback' => function ( $item ) { + $post_type = get_post_type_object( $item['slug'] ); + if ( ! empty( $post_type ) ) { + return ! empty( $post_type->template_lock ) ? $post_type->template_lock : false; + } + }, + 'schema' => array( + 'type' => array( 'string', 'boolean' ), + 'enum' => array( 'all', 'insert', 'contentOnly', false ), + 'description' => __( 'The template_lock associated with the post type, or false if none.', 'gutenberg' ), + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + ) + ); +} +add_action( 'rest_api_init', 'gutenberg_register_wp_rest_post_types_controller_fields' ); + /** * Preload theme and global styles paths to avoid flash of variation styles in post editor. * diff --git a/lib/compat/wordpress-6.7/block-bindings.php b/lib/compat/wordpress-6.7/block-bindings.php index 398b53b340673..9e82c1843f35a 100644 --- a/lib/compat/wordpress-6.7/block-bindings.php +++ b/lib/compat/wordpress-6.7/block-bindings.php @@ -38,3 +38,18 @@ function gutenberg_add_server_block_bindings_sources_to_editor_settings( $editor } add_filter( 'block_editor_settings_all', 'gutenberg_add_server_block_bindings_sources_to_editor_settings', 10 ); + +/** + * Initialize `canUpdateBlockBindings` editor setting if it doesn't exist. By default, it is `true` only for admin users. + * + * @param array $settings The block editor settings from the `block_editor_settings_all` filter. + * @return array The editor settings including `canUpdateBlockBindings`. + */ +function gutenberg_add_can_update_block_bindings_editor_setting( $editor_settings ) { + if ( empty( $editor_settings['canUpdateBlockBindings'] ) ) { + $editor_settings['canUpdateBlockBindings'] = current_user_can( 'manage_options' ); + } + return $editor_settings; +} + +add_filter( 'block_editor_settings_all', 'gutenberg_add_can_update_block_bindings_editor_setting', 10 ); diff --git a/lib/compat/wordpress-6.7/block-templates.php b/lib/compat/wordpress-6.7/block-templates.php index e270ab226c1d9..d1f2859070b8b 100644 --- a/lib/compat/wordpress-6.7/block-templates.php +++ b/lib/compat/wordpress-6.7/block-templates.php @@ -10,7 +10,6 @@ * Register a template. * * @param string $template_name Template name in the form of `plugin_uri//template_name`. - * @param array|string $args Object type or array of object types with which the taxonomy should be associated. * @param array|string $args { * @type string $title Optional. Title of the template as it will be shown in the Site Editor * and other UI elements. @@ -33,7 +32,8 @@ function wp_register_block_template( $template_name, $args = array() ) { * Unregister a template. * * @param string $template_name Template name in the form of `plugin_uri//template_name`. - * @return true|WP_Error True on success, WP_Error on failure or if the template doesn't exist. + * @return WP_Block_Template|WP_Error The unregistered template object on success, WP_Error object on failure or if + * the template doesn't exist. */ function wp_unregister_block_template( $template_name ) { return WP_Block_Templates_Registry::get_instance()->unregister( $template_name ); diff --git a/lib/compat/wordpress-6.7/class-wp-block-templates-registry.php b/lib/compat/wordpress-6.7/class-wp-block-templates-registry.php index db53f735e13b3..92673c0bf50f9 100644 --- a/lib/compat/wordpress-6.7/class-wp-block-templates-registry.php +++ b/lib/compat/wordpress-6.7/class-wp-block-templates-registry.php @@ -36,7 +36,7 @@ final class WP_Block_Templates_Registry { * * @param string $template_name Template name including namespace. * @param array $args Optional. Array of template arguments. - * @return WP_Block_Template|WP_Error The registered template on success, or false on failure. + * @return WP_Block_Template|WP_Error The registered template on success, or WP_Error on failure. */ public function register( $template_name, $args = array() ) { @@ -100,7 +100,7 @@ public function register( $template_name, $args = array() ) { * * @since 6.7.0 * - * @return WP_Block_Template[]|false Associative array of `$template_name => $template` pairs. + * @return WP_Block_Template[] Associative array of `$template_name => $template` pairs. */ public function get_all_registered() { return $this->registered_templates; @@ -112,7 +112,7 @@ public function get_all_registered() { * @since 6.7.0 * * @param string $template_name Template name including namespace. - * @return WP_Block_Template|null|false The registered template, or null if it is not registered. + * @return WP_Block_Template|null The registered template, or null if it is not registered. */ public function get_registered( $template_name ) { if ( ! $this->is_registered( $template_name ) ) { @@ -216,7 +216,7 @@ public function is_registered( $template_name ) { * @since 6.7.0 * * @param string $template_name Template name including namespace. - * @return WP_Block_Template|false The unregistered template on success, or false on failure. + * @return WP_Block_Template|WP_Error The unregistered template on success, or WP_Error on failure. */ public function unregister( $template_name ) { if ( ! $this->is_registered( $template_name ) ) { diff --git a/lib/experimental/blocks.php b/lib/experimental/blocks.php index bfe57c26b3eca..68113276ec1c0 100644 --- a/lib/experimental/blocks.php +++ b/lib/experimental/blocks.php @@ -78,45 +78,42 @@ function wp_enqueue_block_view_script( $block_name, $args ) { } } -/* +/** + * Registers a new block style for one or more block types. + * * WP_Block_Styles_Registry was marked as `final` in core so it cannot be * updated via Gutenberg to allow registration of a style across multiple * block types as well as with an optional style object. This function will * support the desired functionality until the styles registry can be updated * in core. + * + * @param string|array $block_name Block type name including namespace or array of namespaced block type names. + * @param array $style_properties Array containing the properties of the style name, label, + * style_handle (name of the stylesheet to be enqueued), + * inline_style (string containing the CSS to be added), + * style_data (theme.json-like object to generate CSS from). + * + * @return bool True if all block styles were registered with success and false otherwise. */ -if ( ! function_exists( 'gutenberg_register_block_style' ) ) { - /** - * Registers a new block style for one or more block types. - * - * @param string|array $block_name Block type name including namespace or array of namespaced block type names. - * @param array $style_properties Array containing the properties of the style name, label, - * style_handle (name of the stylesheet to be enqueued), - * inline_style (string containing the CSS to be added), - * style_data (theme.json-like object to generate CSS from). - * - * @return bool True if all block styles were registered with success and false otherwise. - */ - function gutenberg_register_block_style( $block_name, $style_properties ) { - if ( ! is_string( $block_name ) && ! is_array( $block_name ) ) { - _doing_it_wrong( - __METHOD__, - __( 'Block name must be a string or array.', 'gutenberg' ), - '6.6.0' - ); +function gutenberg_register_block_style( $block_name, $style_properties ) { + if ( ! is_string( $block_name ) && ! is_array( $block_name ) ) { + _doing_it_wrong( + __METHOD__, + __( 'Block name must be a string or array.', 'gutenberg' ), + '6.6.0' + ); - return false; - } + return false; + } - $block_names = is_string( $block_name ) ? array( $block_name ) : $block_name; - $result = true; + $block_names = is_string( $block_name ) ? array( $block_name ) : $block_name; + $result = true; - foreach ( $block_names as $name ) { - if ( ! WP_Block_Styles_Registry::get_instance()->register( $name, $style_properties ) ) { - $result = false; - } + foreach ( $block_names as $name ) { + if ( ! WP_Block_Styles_Registry::get_instance()->register( $name, $style_properties ) ) { + $result = false; } - - return $result; } + + return $result; } diff --git a/lib/experimental/editor-settings.php b/lib/experimental/editor-settings.php index c6bd99a18bf4c..919be2e6e34a4 100644 --- a/lib/experimental/editor-settings.php +++ b/lib/experimental/editor-settings.php @@ -28,18 +28,15 @@ function gutenberg_enable_experiments() { if ( gutenberg_is_experiment_enabled( 'gutenberg-full-page-client-side-navigation' ) ) { wp_add_inline_script( 'wp-block-library', 'window.__experimentalFullPageClientSideNavigation = true', 'before' ); } - if ( $gutenberg_experiments && array_key_exists( 'gutenberg-zoomed-out-patterns-tab', $gutenberg_experiments ) ) { - wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEnableZoomedOutPatternsTab = true', 'before' ); - } if ( $gutenberg_experiments && array_key_exists( 'gutenberg-quick-edit-dataviews', $gutenberg_experiments ) ) { wp_add_inline_script( 'wp-block-editor', 'window.__experimentalQuickEditDataViews = true', 'before' ); } - if ( $gutenberg_experiments && array_key_exists( 'gutenberg-block-bindings-ui', $gutenberg_experiments ) ) { - wp_add_inline_script( 'wp-block-editor', 'window.__experimentalBlockBindingsUI = true', 'before' ); - } if ( $gutenberg_experiments && array_key_exists( 'gutenberg-media-processing', $gutenberg_experiments ) ) { wp_add_inline_script( 'wp-block-editor', 'window.__experimentalMediaProcessing = true', 'before' ); } + if ( $gutenberg_experiments && array_key_exists( 'gutenberg-zoom-out-experiment', $gutenberg_experiments ) ) { + wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEnableZoomOutExperiment = true', 'before' ); + } } add_action( 'admin_init', 'gutenberg_enable_experiments' ); diff --git a/lib/experiments-page.php b/lib/experiments-page.php index f76dcdca7d18c..5acd5f0f19236 100644 --- a/lib/experiments-page.php +++ b/lib/experiments-page.php @@ -139,18 +139,6 @@ function gutenberg_initialize_experiments_settings() { ) ); - add_settings_field( - 'gutenberg-zoomed-out-patterns-tab', - __( 'Enable zoomed out view when patterns are browsed in the inserter', 'gutenberg' ), - 'gutenberg_display_experiment_field', - 'gutenberg-experiments', - 'gutenberg_experiments_section', - array( - 'label' => __( 'Enable zoomed out view when selecting a pattern category in the main inserter.', 'gutenberg' ), - 'id' => 'gutenberg-zoomed-out-patterns-tab', - ) - ); - add_settings_field( 'gutenberg-new-posts-dashboard', __( 'Redesigned posts dashboard', 'gutenberg' ), @@ -176,29 +164,28 @@ function gutenberg_initialize_experiments_settings() { ); add_settings_field( - 'gutenberg-block-bindings-ui', - __( 'UI to create block bindings', 'gutenberg' ), + 'gutenberg-media-processing', + __( 'Client-side media processing', 'gutenberg' ), 'gutenberg_display_experiment_field', 'gutenberg-experiments', 'gutenberg_experiments_section', array( - 'label' => __( 'Add UI to create and update block bindings in block inspector controls.', 'gutenberg' ), - 'id' => 'gutenberg-block-bindings-ui', + 'label' => __( 'Enable client-side media processing.', 'gutenberg' ), + 'id' => 'gutenberg-media-processing', ) ); add_settings_field( - 'gutenberg-media-processing', - __( 'Client-side media processing', 'gutenberg' ), + 'gutenberg-zoom-out-experiment', + __( 'Zoom out experiments', 'gutenberg' ), 'gutenberg_display_experiment_field', 'gutenberg-experiments', 'gutenberg_experiments_section', array( - 'label' => __( 'Enable client-side media processing.', 'gutenberg' ), - 'id' => 'gutenberg-media-processing', + 'label' => __( 'Enable zoom out experiments; shows zoom out in the device preview and other zoom out experiments.', 'gutenberg' ), + 'id' => 'gutenberg-zoom-out-experiment', ) ); - register_setting( 'gutenberg-experiments', 'gutenberg-experiments' diff --git a/lib/interactivity-api.php b/lib/interactivity-api.php index 6f04a3ba8fc92..90535f1ebaa42 100644 --- a/lib/interactivity-api.php +++ b/lib/interactivity-api.php @@ -16,14 +16,14 @@ function gutenberg_reregister_interactivity_script_modules() { wp_register_script_module( '@wordpress/interactivity', - gutenberg_url( '/build/interactivity/' . ( SCRIPT_DEBUG ? 'debug.min.js' : 'index.min.js' ) ), + gutenberg_url( '/build-module/' . ( SCRIPT_DEBUG ? 'interactivity/debug.min.js' : 'interactivity/index.min.js' ) ), array(), $default_version ); wp_register_script_module( '@wordpress/interactivity-router', - gutenberg_url( '/build/interactivity/router.min.js' ), + gutenberg_url( '/build-module/interactivity-router/index.min.js' ), array( '@wordpress/interactivity' ), $default_version ); diff --git a/lib/rest-api.php b/lib/rest-api.php index ea87f42463704..0becbc4a72d35 100644 --- a/lib/rest-api.php +++ b/lib/rest-api.php @@ -19,60 +19,12 @@ function gutenberg_register_global_styles_endpoints() { } add_action( 'rest_api_init', 'gutenberg_register_global_styles_endpoints' ); -if ( ! function_exists( 'gutenberg_register_edit_site_export_controller_endpoints' ) ) { - /** - * Registers the Edit Site Export REST API routes. - */ - function gutenberg_register_edit_site_export_controller_endpoints() { - $edit_site_export_controller = new WP_REST_Edit_Site_Export_Controller_Gutenberg(); - $edit_site_export_controller->register_routes(); - } -} - -add_action( 'rest_api_init', 'gutenberg_register_edit_site_export_controller_endpoints' ); -if ( ! function_exists( 'gutenberg_register_wp_rest_post_types_controller_fields' ) ) { - /** - * Adds `template` and `template_lock` fields to WP_REST_Post_Types_Controller class. - */ - function gutenberg_register_wp_rest_post_types_controller_fields() { - register_rest_field( - 'type', - 'template', - array( - 'get_callback' => function ( $item ) { - $post_type = get_post_type_object( $item['slug'] ); - if ( ! empty( $post_type ) ) { - return $post_type->template ?? array(); - } - }, - 'schema' => array( - 'type' => 'array', - 'description' => __( 'The block template associated with the post type.', 'gutenberg' ), - 'readonly' => true, - 'context' => array( 'view', 'edit', 'embed' ), - ), - ) - ); - register_rest_field( - 'type', - 'template_lock', - array( - 'get_callback' => function ( $item ) { - $post_type = get_post_type_object( $item['slug'] ); - if ( ! empty( $post_type ) ) { - return ! empty( $post_type->template_lock ) ? $post_type->template_lock : false; - } - }, - 'schema' => array( - 'type' => array( 'string', 'boolean' ), - 'enum' => array( 'all', 'insert', 'contentOnly', false ), - 'description' => __( 'The template_lock associated with the post type, or false if none.', 'gutenberg' ), - 'readonly' => true, - 'context' => array( 'view', 'edit', 'embed' ), - ), - ) - ); - } +/** + * Registers the Edit Site Export REST API routes. + */ +function gutenberg_register_edit_site_export_controller_endpoints() { + $edit_site_export_controller = new WP_REST_Edit_Site_Export_Controller_Gutenberg(); + $edit_site_export_controller->register_routes(); } -add_action( 'rest_api_init', 'gutenberg_register_wp_rest_post_types_controller_fields' ); +add_action( 'rest_api_init', 'gutenberg_register_edit_site_export_controller_endpoints' ); diff --git a/package-lock.json b/package-lock.json index 85ed527a624a4..32819be602f72 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gutenberg", - "version": "19.1.0", + "version": "19.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "gutenberg", - "version": "19.1.0", + "version": "19.2.0", "hasInstallScript": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -40,12 +40,14 @@ "@wordpress/editor": "file:packages/editor", "@wordpress/element": "file:packages/element", "@wordpress/escape-html": "file:packages/escape-html", + "@wordpress/fields": "file:packages/fields", "@wordpress/format-library": "file:packages/format-library", "@wordpress/hooks": "file:packages/hooks", "@wordpress/html-entities": "file:packages/html-entities", "@wordpress/i18n": "file:packages/i18n", "@wordpress/icons": "file:packages/icons", "@wordpress/interactivity": "file:packages/interactivity", + "@wordpress/interactivity-router": "file:packages/interactivity-router", "@wordpress/interface": "file:packages/interface", "@wordpress/is-shallow-equal": "file:packages/is-shallow-equal", "@wordpress/keyboard-shortcuts": "file:packages/keyboard-shortcuts", @@ -79,8 +81,7 @@ "@wordpress/viewport": "file:packages/viewport", "@wordpress/warning": "file:packages/warning", "@wordpress/widgets": "file:packages/widgets", - "@wordpress/wordcount": "file:packages/wordcount", - "es-module-shims": "^1.8.2" + "@wordpress/wordcount": "file:packages/wordcount" }, "devDependencies": { "@actions/core": "1.9.1", @@ -99,7 +100,7 @@ "@octokit/rest": "16.26.0", "@octokit/types": "6.34.0", "@octokit/webhooks-types": "5.8.0", - "@playwright/test": "1.46.0", + "@playwright/test": "1.47.0", "@pmmmwh/react-refresh-webpack-plugin": "0.5.11", "@react-native/babel-preset": "0.73.10", "@react-native/metro-babel-transformer": "0.73.10", @@ -221,6 +222,7 @@ "postcss-local-keyframes": "^0.0.2", "prettier": "npm:wp-prettier@3.0.3", "progress": "2.0.3", + "puppeteer-core": "23.1.0", "react": "18.3.1", "react-dom": "18.3.1", "react-native": "0.73.3", @@ -7045,12 +7047,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.46.0.tgz", - "integrity": "sha512-/QYft5VArOrGRP5pgkrfKksqsKA6CEFyGQ/gjNe6q0y4tZ1aaPfq4gIjudr1s3D+pXyrPRdsy4opKDrjBabE5w==", + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.47.0.tgz", + "integrity": "sha512-SgAdlSwYVpToI4e/IH19IHHWvoijAYH5hu2MWSXptRypLSnzj51PcGD+rsOXFayde4P9ZLi+loXVwArg6IUkCA==", "dev": true, "dependencies": { - "playwright": "1.46.0" + "playwright": "1.47.0" }, "bin": { "playwright": "cli.js" @@ -17152,6 +17154,10 @@ "resolved": "packages/eslint-plugin", "link": true }, + "node_modules/@wordpress/fields": { + "resolved": "packages/fields", + "link": true + }, "node_modules/@wordpress/format-library": { "resolved": "packages/format-library", "link": true @@ -22672,15 +22678,6 @@ "node": ">=4.0" } }, - "node_modules/cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", - "dev": true, - "dependencies": { - "node-fetch": "2.6.7" - } - }, "node_modules/cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -24223,10 +24220,11 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.981744", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.981744.tgz", - "integrity": "sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==", - "dev": true + "version": "0.0.1312386", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz", + "integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==", + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/diff": { "version": "4.0.2", @@ -24962,11 +24960,6 @@ "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", "dev": true }, - "node_modules/es-module-shims": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/es-module-shims/-/es-module-shims-1.8.2.tgz", - "integrity": "sha512-7vIYVzpOhXtpc3Yn03itB+GSgVZFW7oL4kdydA+iL+IEi7HiSLBUxM05QFw4SxTl6e++pMpGqZPo2+vdNs3TbA==" - }, "node_modules/es-set-tostringtag": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", @@ -41179,12 +41172,12 @@ "dev": true }, "node_modules/playwright": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.46.0.tgz", - "integrity": "sha512-XYJ5WvfefWONh1uPAUAi0H2xXV5S3vrtcnXe6uAOgdGi3aSpqOSXX08IAjXW34xitfuOJsvXU5anXZxPSEQiJw==", + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.0.tgz", + "integrity": "sha512-jOWiRq2pdNAX/mwLiwFYnPHpEZ4rM+fRSQpRHwEwZlP2PUANvL3+aJOF/bvISMhFD30rqMxUB4RJx9aQbfh4Ww==", "dev": true, "dependencies": { - "playwright-core": "1.46.0" + "playwright-core": "1.47.0" }, "bin": { "playwright": "cli.js" @@ -41197,9 +41190,9 @@ } }, "node_modules/playwright-core": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.46.0.tgz", - "integrity": "sha512-9Y/d5UIwuJk8t3+lhmMSAJyNP1BUC/DqP3cQJDQQL/oWqAiuPTLgy7Q5dzglmTLwcBRdetzgNM/gni7ckfTr6A==", + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.0.tgz", + "integrity": "sha512-1DyHT8OqkcfCkYUD9zzUTfg7EfTd+6a8MkD/NWOvjo0u/SCNd5YmY/lJwFvUZOxJbWNds+ei7ic2+R/cRz/PDg==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -42452,33 +42445,120 @@ } }, "node_modules/puppeteer-core": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-13.7.0.tgz", - "integrity": "sha512-rXja4vcnAzFAP1OVLq/5dWNfwBGuzcOARJ6qGV7oAZhnLmVRU8G5MsdeQEAOy332ZhkIOnn9jp15R89LKHyp2Q==", + "version": "23.1.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.1.0.tgz", + "integrity": "sha512-SvAsu+xnLN2FMXE/59bp3s3WXp8ewqUGzVV4AQtml/2xmsciZnU/bXcCW+eETHPWQ6Agg2vTI7QzWXPpEARK2g==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "cross-fetch": "3.1.5", - "debug": "4.3.4", - "devtools-protocol": "0.0.981744", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.1", - "pkg-dir": "4.2.0", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "ws": "8.5.0" + "@puppeteer/browsers": "2.3.1", + "chromium-bidi": "0.6.4", + "debug": "^4.3.6", + "devtools-protocol": "0.0.1312386", + "typed-query-selector": "^2.12.0", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core/node_modules/@puppeteer/browsers": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.3.1.tgz", + "integrity": "sha512-uK7o3hHkK+naEobMSJ+2ySYyXtQkBxIH8Gn4MK9ciePjNV+Pf+PgY/W7iPzn2MTjl3stcYB5AlcTmPYw7AXDwA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.3.6", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.4.0", + "semver": "^7.6.3", + "tar-fs": "^3.0.6", + "unbzip2-stream": "^1.4.3", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/puppeteer-core/node_modules/chromium-bidi": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.6.4.tgz", + "integrity": "sha512-8zoq6ogmhQQkAKZVKO2ObFTl4uOkqoX1PlKQX3hZQ5E9cbUotcAb7h4pTNVAGGv8Z36PF3CtdOriEp/Rz82JqQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "mitt": "3.0.1", + "urlpattern-polyfill": "10.0.0", + "zod": "3.23.8" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/puppeteer-core/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/puppeteer-core/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" }, "engines": { - "node": ">=10.18.1" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, + "node_modules/puppeteer-core/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, "node_modules/puppeteer-core/node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", @@ -42494,99 +42574,199 @@ "@types/yauzl": "^2.9.1" } }, - "node_modules/puppeteer-core/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/puppeteer-core/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, + "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": ">=8" + "node": ">= 14" } }, - "node_modules/puppeteer-core/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/puppeteer-core/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dev": true, + "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" + "agent-base": "^7.0.2", + "debug": "4" }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/puppeteer-core/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/puppeteer-core/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/puppeteer-core/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/puppeteer-core/node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, + "node_modules/puppeteer-core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/puppeteer-core/node_modules/proxy-agent": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", + "dev": true, + "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 14" } }, - "node_modules/puppeteer-core/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/puppeteer-core/node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, + "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/puppeteer-core/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/puppeteer-core/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "node_modules/puppeteer-core/node_modules/socks-proxy-agent": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, "engines": { - "node": ">=6" + "node": ">= 14" } }, - "node_modules/puppeteer-core/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/puppeteer-core/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, "engines": { "node": ">=8" } }, - "node_modules/puppeteer-core/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "node_modules/puppeteer-core/node_modules/tar-fs": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", + "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", "dev": true, + "license": "MIT", "dependencies": { - "find-up": "^4.0.0" + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^2.1.1", + "bare-path": "^2.1.0" + } + }, + "node_modules/puppeteer-core/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/puppeteer-core/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/puppeteer-core/node_modules/ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -42597,6 +42777,45 @@ } } }, + "node_modules/puppeteer-core/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/puppeteer-core/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/puppeteer-core/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/pure-rand": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", @@ -48926,6 +49145,12 @@ "node": ">= 10" } }, + "node_modules/typed-query-selector": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", + "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==", + "dev": true + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -49611,6 +49836,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/urlpattern-polyfill": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", + "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", + "dev": true + }, "node_modules/use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -49648,18 +49879,6 @@ "react": ">=16.8" } }, - "node_modules/use-lilius": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/use-lilius/-/use-lilius-2.0.5.tgz", - "integrity": "sha512-IbPjJe4T6B0zQV6ahftVtHvCAxi6RAuDpEcO8TmnHh4nBtx7JbGdpbgXWOUj/9YjrzEbdT/lW7JWcBVbX3MbrA==", - "dependencies": { - "date-fns": "^3.6.0" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, "node_modules/use-memo-one": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.1.tgz", @@ -52345,7 +52564,7 @@ }, "packages/a11y": { "name": "@wordpress/a11y", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -52359,7 +52578,7 @@ }, "packages/annotations": { "name": "@wordpress/annotations", - "version": "3.6.0", + "version": "3.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -52387,7 +52606,7 @@ }, "packages/api-fetch": { "name": "@wordpress/api-fetch", - "version": "7.6.0", + "version": "7.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -52401,7 +52620,7 @@ }, "packages/autop": { "name": "@wordpress/autop", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -52413,7 +52632,7 @@ }, "packages/babel-plugin-import-jsx-pragma": { "name": "@wordpress/babel-plugin-import-jsx-pragma", - "version": "5.6.0", + "version": "5.7.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -52426,7 +52645,7 @@ }, "packages/babel-plugin-makepot": { "name": "@wordpress/babel-plugin-makepot", - "version": "6.6.0", + "version": "6.7.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -52444,7 +52663,7 @@ }, "packages/babel-preset-default": { "name": "@wordpress/babel-preset-default", - "version": "8.6.0", + "version": "8.7.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -52467,7 +52686,7 @@ }, "packages/base-styles": { "name": "@wordpress/base-styles", - "version": "5.6.0", + "version": "5.7.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -52477,7 +52696,7 @@ }, "packages/blob": { "name": "@wordpress/blob", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -52489,7 +52708,7 @@ }, "packages/block-directory": { "name": "@wordpress/block-directory", - "version": "5.6.0", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -52524,7 +52743,7 @@ }, "packages/block-editor": { "name": "@wordpress/block-editor", - "version": "14.1.0", + "version": "14.2.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -52623,7 +52842,7 @@ }, "packages/block-library": { "name": "@wordpress/block-library", - "version": "9.6.1", + "version": "9.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -52689,7 +52908,7 @@ }, "packages/block-serialization-default-parser": { "name": "@wordpress/block-serialization-default-parser", - "version": "5.6.0", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -52701,7 +52920,7 @@ }, "packages/block-serialization-spec-parser": { "name": "@wordpress/block-serialization-spec-parser", - "version": "5.6.0", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "pegjs": "^0.10.0", @@ -52714,7 +52933,7 @@ }, "packages/blocks": { "name": "@wordpress/blocks", - "version": "13.6.0", + "version": "13.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -52768,7 +52987,7 @@ }, "packages/browserslist-config": { "name": "@wordpress/browserslist-config", - "version": "6.6.0", + "version": "6.7.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -52778,7 +52997,7 @@ }, "packages/commands": { "name": "@wordpress/commands", - "version": "1.6.0", + "version": "1.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -52951,7 +53170,7 @@ }, "packages/components": { "name": "@wordpress/components", - "version": "28.6.0", + "version": "28.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@ariakit/react": "^0.4.10", @@ -52998,7 +53217,6 @@ "re-resizable": "^6.4.0", "react-colorful": "^5.3.1", "remove-accents": "^0.5.0", - "use-lilius": "^2.0.5", "uuid": "^9.0.1" }, "engines": { @@ -53072,7 +53290,7 @@ }, "packages/compose": { "name": "@wordpress/compose", - "version": "7.6.0", + "version": "7.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -53109,7 +53327,7 @@ }, "packages/core-commands": { "name": "@wordpress/core-commands", - "version": "1.6.0", + "version": "1.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -53137,7 +53355,7 @@ }, "packages/core-data": { "name": "@wordpress/core-data", - "version": "7.6.0", + "version": "7.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -53182,7 +53400,7 @@ }, "packages/create-block": { "name": "@wordpress/create-block", - "version": "4.49.0", + "version": "4.50.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -53210,7 +53428,7 @@ }, "packages/create-block-tutorial-template": { "name": "@wordpress/create-block-tutorial-template", - "version": "4.6.0", + "version": "4.7.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -53220,7 +53438,7 @@ }, "packages/customize-widgets": { "name": "@wordpress/customize-widgets", - "version": "5.6.1", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -53258,7 +53476,7 @@ }, "packages/data": { "name": "@wordpress/data", - "version": "10.6.0", + "version": "10.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -53287,7 +53505,7 @@ }, "packages/data-controls": { "name": "@wordpress/data-controls", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -53305,7 +53523,7 @@ }, "packages/dataviews": { "name": "@wordpress/dataviews", - "version": "4.2.0", + "version": "4.3.0", "license": "GPL-2.0-or-later", "dependencies": { "@ariakit/react": "^0.4.10", @@ -53362,7 +53580,7 @@ }, "packages/date": { "name": "@wordpress/date", - "version": "5.6.0", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -53377,7 +53595,7 @@ }, "packages/dependency-extraction-webpack-plugin": { "name": "@wordpress/dependency-extraction-webpack-plugin", - "version": "6.6.0", + "version": "6.7.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -53393,7 +53611,7 @@ }, "packages/deprecated": { "name": "@wordpress/deprecated", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -53406,7 +53624,7 @@ }, "packages/docgen": { "name": "@wordpress/docgen", - "version": "2.6.0", + "version": "2.7.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -53428,7 +53646,7 @@ }, "packages/dom": { "name": "@wordpress/dom", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -53441,7 +53659,7 @@ }, "packages/dom-ready": { "name": "@wordpress/dom-ready", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -53453,7 +53671,7 @@ }, "packages/e2e-test-utils": { "name": "@wordpress/e2e-test-utils", - "version": "11.6.0", + "version": "11.7.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -53476,7 +53694,7 @@ }, "packages/e2e-test-utils-playwright": { "name": "@wordpress/e2e-test-utils-playwright", - "version": "1.6.0", + "version": "1.7.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -53504,7 +53722,7 @@ }, "packages/e2e-tests": { "name": "@wordpress/e2e-tests", - "version": "8.6.0", + "version": "8.7.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -53544,7 +53762,7 @@ }, "packages/edit-post": { "name": "@wordpress/edit-post", - "version": "8.6.1", + "version": "8.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -53591,7 +53809,7 @@ }, "packages/edit-site": { "name": "@wordpress/edit-site", - "version": "6.6.1", + "version": "6.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -53653,7 +53871,7 @@ }, "packages/edit-widgets": { "name": "@wordpress/edit-widgets", - "version": "6.6.1", + "version": "6.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -53696,7 +53914,7 @@ }, "packages/editor": { "name": "@wordpress/editor", - "version": "14.6.0", + "version": "14.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -53757,7 +53975,7 @@ }, "packages/element": { "name": "@wordpress/element", - "version": "6.6.0", + "version": "6.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -53776,7 +53994,7 @@ }, "packages/env": { "name": "@wordpress/env", - "version": "10.6.0", + "version": "10.7.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -53918,7 +54136,7 @@ }, "packages/escape-html": { "name": "@wordpress/escape-html", - "version": "3.6.0", + "version": "3.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -53930,7 +54148,7 @@ }, "packages/eslint-plugin": { "name": "@wordpress/eslint-plugin", - "version": "20.3.0", + "version": "21.0.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -53971,9 +54189,24 @@ } } }, + "packages/fields": { + "name": "@wordpress/fields", + "version": "0.0.1", + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, "packages/format-library": { "name": "@wordpress/format-library", - "version": "5.6.0", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54001,7 +54234,7 @@ }, "packages/hooks": { "name": "@wordpress/hooks", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -54013,7 +54246,7 @@ }, "packages/html-entities": { "name": "@wordpress/html-entities", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -54025,7 +54258,7 @@ }, "packages/i18n": { "name": "@wordpress/i18n", - "version": "5.6.0", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54045,7 +54278,7 @@ }, "packages/icons": { "name": "@wordpress/icons", - "version": "10.6.0", + "version": "10.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54059,7 +54292,7 @@ }, "packages/interactivity": { "name": "@wordpress/interactivity", - "version": "6.6.0", + "version": "6.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@preact/signals": "^1.2.2", @@ -54072,7 +54305,7 @@ }, "packages/interactivity-router": { "name": "@wordpress/interactivity-router", - "version": "2.6.0", + "version": "2.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@wordpress/interactivity": "file:../interactivity" @@ -54108,7 +54341,7 @@ }, "packages/interface": { "name": "@wordpress/interface", - "version": "6.6.0", + "version": "6.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54137,7 +54370,7 @@ }, "packages/is-shallow-equal": { "name": "@wordpress/is-shallow-equal", - "version": "5.6.0", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -54149,7 +54382,7 @@ }, "packages/jest-console": { "name": "@wordpress/jest-console", - "version": "8.6.0", + "version": "8.7.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -54166,7 +54399,7 @@ }, "packages/jest-preset-default": { "name": "@wordpress/jest-preset-default", - "version": "12.6.0", + "version": "12.7.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -54184,7 +54417,7 @@ }, "packages/jest-puppeteer-axe": { "name": "@wordpress/jest-puppeteer-axe", - "version": "7.6.0", + "version": "7.7.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -54207,7 +54440,7 @@ }, "packages/keyboard-shortcuts": { "name": "@wordpress/keyboard-shortcuts", - "version": "5.6.0", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54225,7 +54458,7 @@ }, "packages/keycodes": { "name": "@wordpress/keycodes", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54238,7 +54471,7 @@ }, "packages/lazy-import": { "name": "@wordpress/lazy-import", - "version": "2.6.0", + "version": "2.7.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -54253,7 +54486,7 @@ }, "packages/list-reusable-blocks": { "name": "@wordpress/list-reusable-blocks", - "version": "5.6.0", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54276,7 +54509,7 @@ }, "packages/media-utils": { "name": "@wordpress/media-utils", - "version": "5.6.0", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54292,7 +54525,7 @@ }, "packages/notices": { "name": "@wordpress/notices", - "version": "5.6.0", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54309,7 +54542,7 @@ }, "packages/npm-package-json-lint-config": { "name": "@wordpress/npm-package-json-lint-config", - "version": "5.6.0", + "version": "5.7.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -54322,7 +54555,7 @@ }, "packages/nux": { "name": "@wordpress/nux", - "version": "9.6.0", + "version": "9.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54345,7 +54578,7 @@ }, "packages/patterns": { "name": "@wordpress/patterns", - "version": "2.6.0", + "version": "2.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54375,7 +54608,7 @@ }, "packages/plugins": { "name": "@wordpress/plugins", - "version": "7.6.0", + "version": "7.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54398,7 +54631,7 @@ }, "packages/postcss-plugins-preset": { "name": "@wordpress/postcss-plugins-preset", - "version": "5.6.0", + "version": "5.7.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -54415,7 +54648,7 @@ }, "packages/postcss-themes": { "name": "@wordpress/postcss-themes", - "version": "6.6.0", + "version": "6.7.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -54428,7 +54661,7 @@ }, "packages/preferences": { "name": "@wordpress/preferences", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54454,7 +54687,7 @@ }, "packages/preferences-persistence": { "name": "@wordpress/preferences-persistence", - "version": "2.6.0", + "version": "2.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54467,7 +54700,7 @@ }, "packages/prettier-config": { "name": "@wordpress/prettier-config", - "version": "4.6.0", + "version": "4.7.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -54480,7 +54713,7 @@ }, "packages/primitives": { "name": "@wordpress/primitives", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54497,7 +54730,7 @@ }, "packages/priority-queue": { "name": "@wordpress/priority-queue", - "version": "3.6.0", + "version": "3.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54510,7 +54743,7 @@ }, "packages/private-apis": { "name": "@wordpress/private-apis", - "version": "1.6.0", + "version": "1.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -54522,7 +54755,7 @@ }, "packages/project-management-automation": { "name": "@wordpress/project-management-automation", - "version": "2.6.0", + "version": "2.7.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -54552,7 +54785,7 @@ }, "packages/react-i18n": { "name": "@wordpress/react-i18n", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54708,7 +54941,7 @@ }, "packages/readable-js-assets-webpack-plugin": { "name": "@wordpress/readable-js-assets-webpack-plugin", - "version": "3.6.0", + "version": "3.7.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -54721,7 +54954,7 @@ }, "packages/redux-routine": { "name": "@wordpress/redux-routine", - "version": "5.6.0", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54766,7 +54999,7 @@ }, "packages/reusable-blocks": { "name": "@wordpress/reusable-blocks", - "version": "5.6.0", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54793,7 +55026,7 @@ }, "packages/rich-text": { "name": "@wordpress/rich-text", - "version": "7.6.0", + "version": "7.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54817,7 +55050,7 @@ }, "packages/router": { "name": "@wordpress/router", - "version": "1.6.0", + "version": "1.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54836,7 +55069,7 @@ }, "packages/scripts": { "name": "@wordpress/scripts", - "version": "28.6.0", + "version": "29.0.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -54884,7 +55117,7 @@ "postcss-import": "^16.1.0", "postcss-loader": "^6.2.1", "prettier": "npm:wp-prettier@3.0.3", - "puppeteer-core": "^13.2.0", + "puppeteer-core": "^23.1.0", "react-refresh": "^0.14.0", "read-pkg-up": "^7.0.1", "resolve-bin": "^0.4.0", @@ -54909,7 +55142,7 @@ "npm": ">=8.19.2" }, "peerDependencies": { - "@playwright/test": "^1.46.0", + "@playwright/test": "^1.47.0", "react": "^18.0.0", "react-dom": "^18.0.0" } @@ -55291,7 +55524,7 @@ }, "packages/server-side-render": { "name": "@wordpress/server-side-render", - "version": "5.6.0", + "version": "5.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55317,7 +55550,7 @@ }, "packages/shortcode": { "name": "@wordpress/shortcode", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55330,7 +55563,7 @@ }, "packages/style-engine": { "name": "@wordpress/style-engine", - "version": "2.6.0", + "version": "2.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55343,7 +55576,7 @@ }, "packages/stylelint-config": { "name": "@wordpress/stylelint-config", - "version": "22.6.0", + "version": "22.7.0", "dev": true, "license": "MIT", "dependencies": { @@ -55461,7 +55694,7 @@ }, "packages/sync": { "name": "@wordpress/sync", - "version": "1.6.0", + "version": "1.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55482,7 +55715,7 @@ }, "packages/token-list": { "name": "@wordpress/token-list", - "version": "3.6.0", + "version": "3.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -55494,7 +55727,7 @@ }, "packages/undo-manager": { "name": "@wordpress/undo-manager", - "version": "1.6.0", + "version": "1.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55507,7 +55740,7 @@ }, "packages/url": { "name": "@wordpress/url", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55520,7 +55753,7 @@ }, "packages/viewport": { "name": "@wordpress/viewport", - "version": "6.6.0", + "version": "6.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55538,7 +55771,7 @@ }, "packages/warning": { "name": "@wordpress/warning", - "version": "3.6.0", + "version": "3.7.0", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -55547,7 +55780,7 @@ }, "packages/widgets": { "name": "@wordpress/widgets", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55575,7 +55808,7 @@ }, "packages/wordcount": { "name": "@wordpress/wordcount", - "version": "4.6.0", + "version": "4.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -60453,12 +60686,12 @@ } }, "@playwright/test": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.46.0.tgz", - "integrity": "sha512-/QYft5VArOrGRP5pgkrfKksqsKA6CEFyGQ/gjNe6q0y4tZ1aaPfq4gIjudr1s3D+pXyrPRdsy4opKDrjBabE5w==", + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.47.0.tgz", + "integrity": "sha512-SgAdlSwYVpToI4e/IH19IHHWvoijAYH5hu2MWSXptRypLSnzj51PcGD+rsOXFayde4P9ZLi+loXVwArg6IUkCA==", "dev": true, "requires": { - "playwright": "1.46.0" + "playwright": "1.47.0" } }, "@pmmmwh/react-refresh-webpack-plugin": { @@ -68020,7 +68253,6 @@ "re-resizable": "^6.4.0", "react-colorful": "^5.3.1", "remove-accents": "^0.5.0", - "use-lilius": "^2.0.5", "uuid": "^9.0.1" }, "dependencies": { @@ -68684,6 +68916,12 @@ "requireindex": "^1.2.0" } }, + "@wordpress/fields": { + "version": "file:packages/fields", + "requires": { + "@babel/runtime": "^7.16.0" + } + }, "@wordpress/format-library": { "version": "file:packages/format-library", "requires": { @@ -69218,7 +69456,7 @@ "postcss-import": "^16.1.0", "postcss-loader": "^6.2.1", "prettier": "npm:wp-prettier@3.0.3", - "puppeteer-core": "^13.2.0", + "puppeteer-core": "^23.1.0", "react-refresh": "^0.14.0", "read-pkg-up": "^7.0.1", "resolve-bin": "^0.4.0", @@ -73813,15 +74051,6 @@ "is-windows": "^1.0.0" } }, - "cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", - "dev": true, - "requires": { - "node-fetch": "2.6.7" - } - }, "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -74951,9 +75180,9 @@ } }, "devtools-protocol": { - "version": "0.0.981744", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.981744.tgz", - "integrity": "sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==", + "version": "0.0.1312386", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz", + "integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==", "dev": true }, "diff": { @@ -75556,11 +75785,6 @@ "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", "dev": true }, - "es-module-shims": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/es-module-shims/-/es-module-shims-1.8.2.tgz", - "integrity": "sha512-7vIYVzpOhXtpc3Yn03itB+GSgVZFW7oL4kdydA+iL+IEi7HiSLBUxM05QFw4SxTl6e++pMpGqZPo2+vdNs3TbA==" - }, "es-set-tostringtag": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", @@ -87842,19 +88066,19 @@ "dev": true }, "playwright": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.46.0.tgz", - "integrity": "sha512-XYJ5WvfefWONh1uPAUAi0H2xXV5S3vrtcnXe6uAOgdGi3aSpqOSXX08IAjXW34xitfuOJsvXU5anXZxPSEQiJw==", + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.0.tgz", + "integrity": "sha512-jOWiRq2pdNAX/mwLiwFYnPHpEZ4rM+fRSQpRHwEwZlP2PUANvL3+aJOF/bvISMhFD30rqMxUB4RJx9aQbfh4Ww==", "dev": true, "requires": { "fsevents": "2.3.2", - "playwright-core": "1.46.0" + "playwright-core": "1.47.0" } }, "playwright-core": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.46.0.tgz", - "integrity": "sha512-9Y/d5UIwuJk8t3+lhmMSAJyNP1BUC/DqP3cQJDQQL/oWqAiuPTLgy7Q5dzglmTLwcBRdetzgNM/gni7ckfTr6A==", + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.0.tgz", + "integrity": "sha512-1DyHT8OqkcfCkYUD9zzUTfg7EfTd+6a8MkD/NWOvjo0u/SCNd5YmY/lJwFvUZOxJbWNds+ei7ic2+R/cRz/PDg==", "dev": true }, "please-upgrade-node": { @@ -88769,25 +88993,81 @@ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" }, "puppeteer-core": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-13.7.0.tgz", - "integrity": "sha512-rXja4vcnAzFAP1OVLq/5dWNfwBGuzcOARJ6qGV7oAZhnLmVRU8G5MsdeQEAOy332ZhkIOnn9jp15R89LKHyp2Q==", + "version": "23.1.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.1.0.tgz", + "integrity": "sha512-SvAsu+xnLN2FMXE/59bp3s3WXp8ewqUGzVV4AQtml/2xmsciZnU/bXcCW+eETHPWQ6Agg2vTI7QzWXPpEARK2g==", "dev": true, "requires": { - "cross-fetch": "3.1.5", - "debug": "4.3.4", - "devtools-protocol": "0.0.981744", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.1", - "pkg-dir": "4.2.0", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "ws": "8.5.0" + "@puppeteer/browsers": "2.3.1", + "chromium-bidi": "0.6.4", + "debug": "^4.3.6", + "devtools-protocol": "0.0.1312386", + "typed-query-selector": "^2.12.0", + "ws": "^8.18.0" }, "dependencies": { + "@puppeteer/browsers": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.3.1.tgz", + "integrity": "sha512-uK7o3hHkK+naEobMSJ+2ySYyXtQkBxIH8Gn4MK9ciePjNV+Pf+PgY/W7iPzn2MTjl3stcYB5AlcTmPYw7AXDwA==", + "dev": true, + "requires": { + "debug": "^4.3.6", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.4.0", + "semver": "^7.6.3", + "tar-fs": "^3.0.6", + "unbzip2-stream": "^1.4.3", + "yargs": "^17.7.2" + } + }, + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, + "chromium-bidi": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.6.4.tgz", + "integrity": "sha512-8zoq6ogmhQQkAKZVKO2ObFTl4uOkqoX1PlKQX3hZQ5E9cbUotcAb7h4pTNVAGGv8Z36PF3CtdOriEp/Rz82JqQ==", + "dev": true, + "requires": { + "mitt": "3.0.1", + "urlpattern-polyfill": "10.0.0", + "zod": "3.23.8" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -88800,68 +89080,169 @@ "yauzl": "^2.10.0" } }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "agent-base": "^7.1.0", + "debug": "^4.3.4" } }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dev": true, "requires": { - "p-locate": "^4.1.0" + "agent-base": "^7.0.2", + "debug": "4" } }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, + "mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "proxy-agent": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", "dev": true, "requires": { - "p-try": "^2.0.0" + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" } }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { - "p-limit": "^2.2.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true + "socks-proxy-agent": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", + "dev": true, + "requires": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.8.3" + } }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { - "find-up": "^4.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "tar-fs": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", + "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", + "dev": true, + "requires": { + "bare-fs": "^2.1.1", + "bare-path": "^2.1.0", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "requires": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } }, "ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true } } @@ -93684,6 +94065,12 @@ "integrity": "sha512-bctQIOqx2iVbWGDGPWwIm18QScpu2XRmkC19D8rQGFsjKSgteq/o1hTZvIG/wuDq8fanpBDrLkLq+aEN/6y5XQ==", "dev": true }, + "typed-query-selector": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", + "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==", + "dev": true + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -94211,6 +94598,12 @@ "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==", "dev": true }, + "urlpattern-polyfill": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", + "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", + "dev": true + }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -94230,14 +94623,6 @@ "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.1.9.tgz", "integrity": "sha512-CL/29uS74AwreI/f2oz2hLTW7ZqVeV5+gxFeGudzQrgkCytrHw33G4KbnQOrRlAEzzAFXi7dDLMC9zhWcVpzmw==" }, - "use-lilius": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/use-lilius/-/use-lilius-2.0.5.tgz", - "integrity": "sha512-IbPjJe4T6B0zQV6ahftVtHvCAxi6RAuDpEcO8TmnHh4nBtx7JbGdpbgXWOUj/9YjrzEbdT/lW7JWcBVbX3MbrA==", - "requires": { - "date-fns": "^3.6.0" - } - }, "use-memo-one": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.1.tgz", diff --git a/package.json b/package.json index c0a7853a41817..29e5f10b6f7a5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "19.1.0", + "version": "19.2.0", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", @@ -52,12 +52,14 @@ "@wordpress/editor": "file:packages/editor", "@wordpress/element": "file:packages/element", "@wordpress/escape-html": "file:packages/escape-html", + "@wordpress/fields": "file:packages/fields", "@wordpress/format-library": "file:packages/format-library", "@wordpress/hooks": "file:packages/hooks", "@wordpress/html-entities": "file:packages/html-entities", "@wordpress/i18n": "file:packages/i18n", "@wordpress/icons": "file:packages/icons", "@wordpress/interactivity": "file:packages/interactivity", + "@wordpress/interactivity-router": "file:packages/interactivity-router", "@wordpress/interface": "file:packages/interface", "@wordpress/is-shallow-equal": "file:packages/is-shallow-equal", "@wordpress/keyboard-shortcuts": "file:packages/keyboard-shortcuts", @@ -91,8 +93,7 @@ "@wordpress/viewport": "file:packages/viewport", "@wordpress/warning": "file:packages/warning", "@wordpress/widgets": "file:packages/widgets", - "@wordpress/wordcount": "file:packages/wordcount", - "es-module-shims": "^1.8.2" + "@wordpress/wordcount": "file:packages/wordcount" }, "devDependencies": { "@actions/core": "1.9.1", @@ -111,7 +112,7 @@ "@octokit/rest": "16.26.0", "@octokit/types": "6.34.0", "@octokit/webhooks-types": "5.8.0", - "@playwright/test": "1.46.0", + "@playwright/test": "1.47.0", "@pmmmwh/react-refresh-webpack-plugin": "0.5.11", "@react-native/babel-preset": "0.73.10", "@react-native/metro-babel-transformer": "0.73.10", @@ -233,6 +234,7 @@ "postcss-local-keyframes": "^0.0.2", "prettier": "npm:wp-prettier@3.0.3", "progress": "2.0.3", + "puppeteer-core": "23.1.0", "react": "18.3.1", "react-dom": "18.3.1", "react-native": "0.73.3", diff --git a/packages/a11y/CHANGELOG.md b/packages/a11y/CHANGELOG.md index 5a90a6cc98f0d..36973cce020f3 100644 --- a/packages/a11y/CHANGELOG.md +++ b/packages/a11y/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.7.0 (2024-09-05) + ## 4.6.0 (2024-08-21) ## 4.5.0 (2024-08-07) diff --git a/packages/a11y/package.json b/packages/a11y/package.json index 0e307e813c56a..88123b3c6c712 100644 --- a/packages/a11y/package.json +++ b/packages/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/a11y", - "version": "4.6.0", + "version": "4.7.0", "description": "Accessibility (a11y) utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/annotations/CHANGELOG.md b/packages/annotations/CHANGELOG.md index b3e0dbab635b8..6211cf30688e5 100644 --- a/packages/annotations/CHANGELOG.md +++ b/packages/annotations/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.7.0 (2024-09-05) + ## 3.6.0 (2024-08-21) ## 3.5.0 (2024-08-07) diff --git a/packages/annotations/package.json b/packages/annotations/package.json index 95ceadb1d990e..c189dcc11fd09 100644 --- a/packages/annotations/package.json +++ b/packages/annotations/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/annotations", - "version": "3.6.0", + "version": "3.7.0", "description": "Annotate content in the Gutenberg editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/api-fetch/CHANGELOG.md b/packages/api-fetch/CHANGELOG.md index 49319c18ab754..01b37d4e14a7d 100644 --- a/packages/api-fetch/CHANGELOG.md +++ b/packages/api-fetch/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 7.7.0 (2024-09-05) + ## 7.6.0 (2024-08-21) ## 7.5.0 (2024-08-07) diff --git a/packages/api-fetch/package.json b/packages/api-fetch/package.json index abbe8cce374c3..76d797f4ddfa5 100644 --- a/packages/api-fetch/package.json +++ b/packages/api-fetch/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/api-fetch", - "version": "7.6.0", + "version": "7.7.0", "description": "Utility to make WordPress REST API requests.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/autop/CHANGELOG.md b/packages/autop/CHANGELOG.md index 353495eae8983..ed19f1ceafbc5 100644 --- a/packages/autop/CHANGELOG.md +++ b/packages/autop/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.7.0 (2024-09-05) + ## 4.6.0 (2024-08-21) ## 4.5.0 (2024-08-07) diff --git a/packages/autop/package.json b/packages/autop/package.json index 03bb56412195e..4e1cf577ebd09 100644 --- a/packages/autop/package.json +++ b/packages/autop/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/autop", - "version": "4.6.0", + "version": "4.7.0", "description": "WordPress's automatic paragraph functions `autop` and `removep`.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md b/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md index d96d2315e2a51..c916b788243a0 100644 --- a/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md +++ b/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.7.0 (2024-09-05) + ## 5.6.0 (2024-08-21) ## 5.5.0 (2024-08-07) diff --git a/packages/babel-plugin-import-jsx-pragma/package.json b/packages/babel-plugin-import-jsx-pragma/package.json index be1dbc4235f28..1af6bdf93cb04 100644 --- a/packages/babel-plugin-import-jsx-pragma/package.json +++ b/packages/babel-plugin-import-jsx-pragma/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-import-jsx-pragma", - "version": "5.6.0", + "version": "5.7.0", "description": "Babel transform plugin for automatically injecting an import to be used as the pragma for the React JSX Transform plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-plugin-makepot/CHANGELOG.md b/packages/babel-plugin-makepot/CHANGELOG.md index 98da250e2ba6b..e7345f314d578 100644 --- a/packages/babel-plugin-makepot/CHANGELOG.md +++ b/packages/babel-plugin-makepot/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.7.0 (2024-09-05) + ## 6.6.0 (2024-08-21) ## 6.5.0 (2024-08-07) diff --git a/packages/babel-plugin-makepot/package.json b/packages/babel-plugin-makepot/package.json index 4d439baf28163..a7c18d891538d 100644 --- a/packages/babel-plugin-makepot/package.json +++ b/packages/babel-plugin-makepot/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-makepot", - "version": "6.6.0", + "version": "6.7.0", "description": "WordPress Babel internationalization (i18n) plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-preset-default/CHANGELOG.md b/packages/babel-preset-default/CHANGELOG.md index 43c9675fcb885..70a740f60cad3 100644 --- a/packages/babel-preset-default/CHANGELOG.md +++ b/packages/babel-preset-default/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 8.7.0 (2024-09-05) + ## 8.6.0 (2024-08-21) ## 8.5.0 (2024-08-07) diff --git a/packages/babel-preset-default/package.json b/packages/babel-preset-default/package.json index 2559b60401790..be5b3786346eb 100644 --- a/packages/babel-preset-default/package.json +++ b/packages/babel-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-preset-default", - "version": "8.6.0", + "version": "8.7.0", "description": "Default Babel preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/base-styles/CHANGELOG.md b/packages/base-styles/CHANGELOG.md index ce98cebeae1c2..cad2f94c98da7 100644 --- a/packages/base-styles/CHANGELOG.md +++ b/packages/base-styles/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.7.0 (2024-09-05) + ## 5.6.0 (2024-08-21) ## 5.5.0 (2024-08-07) diff --git a/packages/base-styles/_mixins.scss b/packages/base-styles/_mixins.scss index d6c3857c43c62..91017c8bb9932 100644 --- a/packages/base-styles/_mixins.scss +++ b/packages/base-styles/_mixins.scss @@ -74,7 +74,7 @@ @mixin input-style__neutral() { box-shadow: 0 0 0 transparent; transition: box-shadow 0.1s linear; - border-radius: $radius-block-ui; + border-radius: $radius-small; border: $border-width solid $gray-600; @include reduce-motion("transition"); } @@ -227,7 +227,7 @@ border: $border-width solid $gray-900; margin-right: $grid-unit-15; transition: none; - border-radius: $radius-block-ui; + border-radius: $radius-small; &:focus { box-shadow: 0 0 0 ($border-width * 2) $white, 0 0 0 ($border-width * 2 + $border-width-focus-fallback) var(--wp-admin-theme-color); @@ -363,7 +363,7 @@ &:focus { color: var(--wp-admin-theme-color--rgb); box-shadow: 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color, #007cba); - border-radius: $radius-block-ui; + border-radius: $radius-small; } } @@ -375,7 +375,7 @@ padding: $grid-unit-15 !important; border: $border-width solid $gray-900 !important; box-shadow: none !important; - border-radius: $radius-block-ui !important; + border-radius: $radius-small !important; // Fonts smaller than 16px causes mobile safari to zoom. font-size: $mobile-text-min-font-size !important; diff --git a/packages/base-styles/package.json b/packages/base-styles/package.json index fbe3bf149b1cd..6839a8081e04a 100644 --- a/packages/base-styles/package.json +++ b/packages/base-styles/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/base-styles", - "version": "5.6.0", + "version": "5.7.0", "description": "Base SCSS utilities and variables for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blob/CHANGELOG.md b/packages/blob/CHANGELOG.md index 5c21e96d7269c..f95598025a8b6 100644 --- a/packages/blob/CHANGELOG.md +++ b/packages/blob/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.7.0 (2024-09-05) + ## 4.6.0 (2024-08-21) ## 4.5.0 (2024-08-07) diff --git a/packages/blob/package.json b/packages/blob/package.json index 58feea189bed0..3dea70c977197 100644 --- a/packages/blob/package.json +++ b/packages/blob/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blob", - "version": "4.6.0", + "version": "4.7.0", "description": "Blob utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-directory/CHANGELOG.md b/packages/block-directory/CHANGELOG.md index 4d15343f0c092..70914f293ca99 100644 --- a/packages/block-directory/CHANGELOG.md +++ b/packages/block-directory/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.7.0 (2024-09-05) + ## 5.6.0 (2024-08-21) ## 5.5.0 (2024-08-07) diff --git a/packages/block-directory/package.json b/packages/block-directory/package.json index 85222ecaa3882..39f239edfcb44 100644 --- a/packages/block-directory/package.json +++ b/packages/block-directory/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-directory", - "version": "5.6.0", + "version": "5.7.0", "description": "Extend editor with block directory features to search, download and install blocks.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-directory/src/components/downloadable-block-list-item/index.js b/packages/block-directory/src/components/downloadable-block-list-item/index.js index 03e6e79d8928e..ac587dc2d6d0c 100644 --- a/packages/block-directory/src/components/downloadable-block-list-item/index.js +++ b/packages/block-directory/src/components/downloadable-block-list-item/index.js @@ -6,7 +6,7 @@ import { Button, Spinner, VisuallyHidden, - privateApis as componentsPrivateApis, + Composite, } from '@wordpress/components'; import { createInterpolateElement } from '@wordpress/element'; import { decodeEntities } from '@wordpress/html-entities'; @@ -20,9 +20,6 @@ import BlockRatings from '../block-ratings'; import DownloadableBlockIcon from '../downloadable-block-icon'; import DownloadableBlockNotice from '../downloadable-block-notice'; import { store as blockDirectoryStore } from '../../store'; -import { unlock } from '../../lock-unlock'; - -const { CompositeItemV2: CompositeItem } = unlock( componentsPrivateApis ); // Return the appropriate block item label, given the block data and status. function getDownloadableBlockLabel( @@ -65,7 +62,7 @@ function getDownloadableBlockLabel( ); } -function DownloadableBlockListItem( { composite, item, onClick } ) { +function DownloadableBlockListItem( { item, onClick } ) { const { author, description, icon, rating, title } = item; // getBlockType returns a block object if this block exists, or null if not. const isInstalled = !! getBlockType( item.name ); @@ -93,7 +90,7 @@ function DownloadableBlockListItem( { composite, item, onClick } ) { } return ( - } - store={ composite } disabled={ isInstalling || ! isInstallable } >
@@ -163,7 +159,7 @@ function DownloadableBlockListItem( { composite, item, onClick } ) { ) } - + ); } diff --git a/packages/block-directory/src/components/downloadable-blocks-list/index.js b/packages/block-directory/src/components/downloadable-blocks-list/index.js index 09f509c4ed49c..3e44aa423bfa5 100644 --- a/packages/block-directory/src/components/downloadable-blocks-list/index.js +++ b/packages/block-directory/src/components/downloadable-blocks-list/index.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { privateApis as componentsPrivateApis } from '@wordpress/components'; +import { Composite } from '@wordpress/components'; import { getBlockType } from '@wordpress/blocks'; import { useDispatch } from '@wordpress/data'; @@ -11,14 +11,10 @@ import { useDispatch } from '@wordpress/data'; */ import DownloadableBlockListItem from '../downloadable-block-list-item'; import { store as blockDirectoryStore } from '../../store'; -import { unlock } from '../../lock-unlock'; -const { CompositeV2: Composite, useCompositeStoreV2: useCompositeStore } = - unlock( componentsPrivateApis ); const noop = () => {}; function DownloadableBlocksList( { items, onHover = noop, onSelect } ) { - const composite = useCompositeStore(); const { installBlockType } = useDispatch( blockDirectoryStore ); if ( ! items.length ) { @@ -27,7 +23,6 @@ function DownloadableBlocksList( { items, onHover = noop, onSelect } ) { return ( { // Check if the block is registered (`getBlockType` // will return an object). If so, insert the block. diff --git a/packages/block-editor/CHANGELOG.md b/packages/block-editor/CHANGELOG.md index 0b365c18ae8ad..da44ebc4149f5 100644 --- a/packages/block-editor/CHANGELOG.md +++ b/packages/block-editor/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 14.2.0 (2024-09-05) + ## 14.1.0 (2024-08-21) ## 14.0.0 (2024-08-07) diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index 1f4fa7588ec6c..d3064c78dbe65 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-editor", - "version": "14.1.0", + "version": "14.2.0", "description": "Generic block editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-editor/src/components/block-breadcrumb/index.js b/packages/block-editor/src/components/block-breadcrumb/index.js index 8a70616d358d9..440d9611d278b 100644 --- a/packages/block-editor/src/components/block-breadcrumb/index.js +++ b/packages/block-editor/src/components/block-breadcrumb/index.js @@ -66,10 +66,8 @@ function BlockBreadcrumb( { rootLabelText } ) { > { hasSelection && ( , , ] } secondaryActions={ secondaryActions } > - { __( 'This block contains unexpected or invalid content.' ) } + { __( 'Block contains unexpected or invalid content.' ) } { compare && ( .block-editor-block-list__zoom-out-separator, +.block-editor-block-list__layout.is-root-container.has-global-padding > .block-editor-block-list__zoom-out-separator { + max-width: none; + // Additional -1px is required to avoid sub pixel rounding errors allowing background to show. + margin: 0 calc(-1 * var(--wp--style--root--padding-right) - 1px) 0 calc(-1 * var(--wp--style--root--padding-left) - 1px) !important; +} diff --git a/packages/block-editor/src/components/block-list/index.js b/packages/block-editor/src/components/block-list/index.js index 37dba80511d92..ea6128f153464 100644 --- a/packages/block-editor/src/components/block-list/index.js +++ b/packages/block-editor/src/components/block-list/index.js @@ -39,6 +39,7 @@ import { DEFAULT_BLOCK_EDIT_CONTEXT, } from '../block-edit/context'; import { useTypingObserver } from '../observe-typing'; +import { ZoomOutSeparator } from './zoom-out-separator'; import { unlock } from '../../lock-unlock'; export const IntersectionObserver = createContext(); @@ -174,49 +175,55 @@ function Items( { // function on every render. const hasAppender = CustomAppender !== false; const hasCustomAppender = !! CustomAppender; - const { order, selectedBlocks, visibleBlocks, shouldRenderAppender } = - useSelect( - ( select ) => { - const { - getSettings, - getBlockOrder, - getSelectedBlockClientId, - getSelectedBlockClientIds, - __unstableGetVisibleBlocks, - getTemplateLock, - getBlockEditingMode, - __unstableGetEditorMode, - } = select( blockEditorStore ); - - const _order = getBlockOrder( rootClientId ); + const { + order, + isZoomOut, + selectedBlocks, + visibleBlocks, + shouldRenderAppender, + } = useSelect( + ( select ) => { + const { + getSettings, + getBlockOrder, + getSelectedBlockClientId, + getSelectedBlockClientIds, + __unstableGetVisibleBlocks, + getTemplateLock, + getBlockEditingMode, + __unstableGetEditorMode, + } = select( blockEditorStore ); - if ( getSettings().__unstableIsPreviewMode ) { - return { - order: _order, - selectedBlocks: EMPTY_ARRAY, - visibleBlocks: EMPTY_SET, - }; - } + const _order = getBlockOrder( rootClientId ); - const selectedBlockClientId = getSelectedBlockClientId(); + if ( getSettings().__unstableIsPreviewMode ) { return { order: _order, - selectedBlocks: getSelectedBlockClientIds(), - visibleBlocks: __unstableGetVisibleBlocks(), - shouldRenderAppender: - hasAppender && - __unstableGetEditorMode() !== 'zoom-out' && - ( hasCustomAppender - ? ! getTemplateLock( rootClientId ) && - getBlockEditingMode( rootClientId ) !== 'disabled' - : rootClientId === selectedBlockClientId || - ( ! rootClientId && - ! selectedBlockClientId && - ! _order.length ) ), + selectedBlocks: EMPTY_ARRAY, + visibleBlocks: EMPTY_SET, }; - }, - [ rootClientId, hasAppender, hasCustomAppender ] - ); + } + + const selectedBlockClientId = getSelectedBlockClientId(); + return { + order: _order, + selectedBlocks: getSelectedBlockClientIds(), + visibleBlocks: __unstableGetVisibleBlocks(), + isZoomOut: __unstableGetEditorMode() === 'zoom-out', + shouldRenderAppender: + hasAppender && + __unstableGetEditorMode() !== 'zoom-out' && + ( hasCustomAppender + ? ! getTemplateLock( rootClientId ) && + getBlockEditingMode( rootClientId ) !== 'disabled' + : rootClientId === selectedBlockClientId || + ( ! rootClientId && + ! selectedBlockClientId && + ! _order.length ) ), + }; + }, + [ rootClientId, hasAppender, hasCustomAppender ] + ); return ( @@ -230,10 +237,24 @@ function Items( { ! selectedBlocks.includes( clientId ) } > + { isZoomOut && ( + + ) } + { isZoomOut && ( + + ) } ) ) } { order.length < 1 && placeholder } diff --git a/packages/block-editor/src/components/block-list/use-block-props/index.js b/packages/block-editor/src/components/block-list/use-block-props/index.js index 15fb83139237c..c3a279a618b5d 100644 --- a/packages/block-editor/src/components/block-list/use-block-props/index.js +++ b/packages/block-editor/src/components/block-list/use-block-props/index.js @@ -26,6 +26,7 @@ import { import { useFocusHandler } from './use-focus-handler'; import { useEventHandlers } from './use-selected-block-event-handlers'; import { useNavModeExit } from './use-nav-mode-exit'; +import { useZoomOutModeExit } from './use-zoom-out-mode-exit'; import { useBlockRefProvider } from './use-block-refs'; import { useIntersectionObserver } from './use-intersection-observer'; import { useScrollIntoView } from './use-scroll-into-view'; @@ -85,6 +86,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) { name, blockApiVersion, blockTitle, + editorMode, isSelected, isSubtreeDisabled, hasOverlay, @@ -115,6 +117,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) { useFocusHandler( clientId ), useEventHandlers( { clientId, isSelected } ), useNavModeExit( clientId ), + useZoomOutModeExit( { editorMode } ), useIsHovered( { clientId } ), useIntersectionObserver(), useMovingAnimation( { triggerAnimationOnChange: index, clientId } ), diff --git a/packages/block-editor/src/components/block-list/use-block-props/use-zoom-out-mode-exit.js b/packages/block-editor/src/components/block-list/use-block-props/use-zoom-out-mode-exit.js new file mode 100644 index 0000000000000..bb6edd066f06f --- /dev/null +++ b/packages/block-editor/src/components/block-list/use-block-props/use-zoom-out-mode-exit.js @@ -0,0 +1,44 @@ +/** + * WordPress dependencies + */ +import { useDispatch } from '@wordpress/data'; +import { useRefEffect } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import { store as blockEditorStore } from '../../../store'; +import { unlock } from '../../../lock-unlock'; + +/** + * Allows Zoom Out mode to be exited by double clicking in the selected block. + * + * @param {string} clientId Block client ID. + */ +export function useZoomOutModeExit( { editorMode } ) { + const { __unstableSetEditorMode } = unlock( + useDispatch( blockEditorStore ) + ); + + return useRefEffect( + ( node ) => { + if ( editorMode !== 'zoom-out' ) { + return; + } + + function onDoubleClick( event ) { + if ( ! event.defaultPrevented ) { + event.preventDefault(); + __unstableSetEditorMode( 'edit' ); + } + } + + node.addEventListener( 'dblclick', onDoubleClick ); + + return () => { + node.removeEventListener( 'dblclick', onDoubleClick ); + }; + }, + [ editorMode, __unstableSetEditorMode ] + ); +} diff --git a/packages/block-editor/src/components/block-list/zoom-out-separator.js b/packages/block-editor/src/components/block-list/zoom-out-separator.js new file mode 100644 index 0000000000000..be5af54963060 --- /dev/null +++ b/packages/block-editor/src/components/block-list/zoom-out-separator.js @@ -0,0 +1,110 @@ +/** + * External dependencies + */ +import clsx from 'clsx'; + +/** + * WordPress dependencies + */ +import { + __unstableMotion as motion, + __unstableAnimatePresence as AnimatePresence, +} from '@wordpress/components'; +import { useReducedMotion } from '@wordpress/compose'; +import { useSelect } from '@wordpress/data'; +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { store as blockEditorStore } from '../../store'; +import { unlock } from '../../lock-unlock'; + +export function ZoomOutSeparator( { + clientId, + rootClientId = '', + position = 'top', +} ) { + const [ isDraggedOver, setIsDraggedOver ] = useState( false ); + const { + sectionRootClientId, + sectionClientIds, + blockInsertionPoint, + blockInsertionPointVisible, + } = useSelect( ( select ) => { + const { + getBlockInsertionPoint, + getBlockOrder, + isBlockInsertionPointVisible, + getSectionRootClientId, + } = unlock( select( blockEditorStore ) ); + + const root = getSectionRootClientId(); + const sectionRootClientIds = getBlockOrder( root ); + return { + sectionRootClientId: root, + sectionClientIds: sectionRootClientIds, + blockOrder: getBlockOrder( root ), + blockInsertionPoint: getBlockInsertionPoint(), + blockInsertionPointVisible: isBlockInsertionPointVisible(), + }; + }, [] ); + + const isReducedMotion = useReducedMotion(); + + if ( ! clientId ) { + return; + } + + let isVisible = false; + + const isSectionBlock = + rootClientId === sectionRootClientId && + sectionClientIds && + sectionClientIds.includes( clientId ); + + if ( ! isSectionBlock ) { + return null; + } + + if ( position === 'top' ) { + isVisible = + blockInsertionPointVisible && + blockInsertionPoint.index === 0 && + clientId === sectionClientIds[ blockInsertionPoint.index ]; + } + + if ( position === 'bottom' ) { + isVisible = + blockInsertionPointVisible && + clientId === sectionClientIds[ blockInsertionPoint.index - 1 ]; + } + + return ( + + { isVisible && ( + setIsDraggedOver( true ) } + onDragLeave={ () => setIsDraggedOver( false ) } + > + ) } + + ); +} diff --git a/packages/block-editor/src/components/block-lock/style.scss b/packages/block-editor/src/components/block-lock/style.scss index 8dc6bfb2021f0..ad59030a8f440 100644 --- a/packages/block-editor/src/components/block-lock/style.scss +++ b/packages/block-editor/src/components/block-lock/style.scss @@ -41,7 +41,7 @@ &:hover { background-color: $gray-100; - border-radius: $radius-block-ui; + border-radius: $radius-small; } } diff --git a/packages/block-editor/src/components/block-mover/button.js b/packages/block-editor/src/components/block-mover/button.js index 98c0aff79eff3..76b46701758e8 100644 --- a/packages/block-editor/src/components/block-mover/button.js +++ b/packages/block-editor/src/components/block-mover/button.js @@ -129,8 +129,7 @@ const BlockMoverButton = forwardRef( return ( <>
) } diff --git a/packages/block-editor/src/components/block-patterns-list/style.scss b/packages/block-editor/src/components/block-patterns-list/style.scss index 6b23c1e844dad..84e95563737c3 100644 --- a/packages/block-editor/src/components/block-patterns-list/style.scss +++ b/packages/block-editor/src/components/block-patterns-list/style.scss @@ -36,12 +36,12 @@ display: flex; align-items: center; overflow: hidden; - border-radius: $radius-block-ui; + border-radius: $radius-medium; &::after { outline: $border-width solid rgba($black, 0.1); outline-offset: -$border-width; - border-radius: $radius-block-ui; + border-radius: $radius-medium; } } diff --git a/packages/block-editor/src/components/block-switcher/index.js b/packages/block-editor/src/components/block-switcher/index.js index c8ee422091ad1..98e7f7b2d2142 100644 --- a/packages/block-editor/src/components/block-switcher/index.js +++ b/packages/block-editor/src/components/block-switcher/index.js @@ -198,6 +198,7 @@ const BlockIndicator = ( { icon, showTitle, blockTitle } ) => ( export const BlockSwitcher = ( { clientIds, disabled, isUsingBindings } ) => { const { + hasContentOnlyLocking, canRemove, hasBlockStyles, icon, @@ -206,8 +207,12 @@ export const BlockSwitcher = ( { clientIds, disabled, isUsingBindings } ) => { isTemplate, } = useSelect( ( select ) => { - const { getBlocksByClientId, getBlockAttributes, canRemoveBlocks } = - select( blockEditorStore ); + const { + getTemplateLock, + getBlocksByClientId, + getBlockAttributes, + canRemoveBlocks, + } = select( blockEditorStore ); const { getBlockStyles, getBlockType, getActiveBlockVariation } = select( blocksStore ); const _blocks = getBlocksByClientId( clientIds ); @@ -219,6 +224,7 @@ export const BlockSwitcher = ( { clientIds, disabled, isUsingBindings } ) => { const blockType = getBlockType( firstBlockName ); let _icon; + let _hasTemplateLock; if ( _isSingleBlockSelected ) { const match = getActiveBlockVariation( firstBlockName, @@ -226,9 +232,14 @@ export const BlockSwitcher = ( { clientIds, disabled, isUsingBindings } ) => { ); // Take into account active block variations. _icon = match?.icon || blockType.icon; + _hasTemplateLock = + getTemplateLock( clientIds[ 0 ] ) === 'contentOnly'; } else { const isSelectionOfSameType = new Set( _blocks.map( ( { name } ) => name ) ).size === 1; + _hasTemplateLock = clientIds.some( + ( id ) => getTemplateLock( id ) === 'contentOnly' + ); // When selection consists of blocks of multiple types, display an // appropriate icon to communicate the non-uniformity. _icon = isSelectionOfSameType ? blockType.icon : copy; @@ -244,6 +255,7 @@ export const BlockSwitcher = ( { clientIds, disabled, isUsingBindings } ) => { _isSingleBlockSelected && isReusableBlock( _blocks[ 0 ] ), isTemplate: _isSingleBlockSelected && isTemplatePart( _blocks[ 0 ] ), + hasContentOnlyLocking: _hasTemplateLock, }; }, [ clientIds ] @@ -252,6 +264,7 @@ export const BlockSwitcher = ( { clientIds, disabled, isUsingBindings } ) => { clientId: clientIds?.[ 0 ], maximumLength: 35, } ); + if ( invalidBlocks ) { return null; } @@ -261,7 +274,10 @@ export const BlockSwitcher = ( { clientIds, disabled, isUsingBindings } ) => { ? blockTitle : __( 'Multiple blocks selected' ); - const hideDropdown = disabled || ( ! hasBlockStyles && ! canRemove ); + const hideDropdown = + disabled || + ( ! hasBlockStyles && ! canRemove ) || + hasContentOnlyLocking; if ( hideDropdown ) { return ( diff --git a/packages/block-editor/src/components/block-switcher/pattern-transformations-menu.js b/packages/block-editor/src/components/block-switcher/pattern-transformations-menu.js index 46fd83c92d91f..7d66e19a214a2 100644 --- a/packages/block-editor/src/components/block-switcher/pattern-transformations-menu.js +++ b/packages/block-editor/src/components/block-switcher/pattern-transformations-menu.js @@ -7,11 +7,11 @@ import { useInstanceId, useViewportMatch } from '@wordpress/compose'; import { chevronRight } from '@wordpress/icons'; import { + Composite, MenuGroup, MenuItem, Popover, VisuallyHidden, - privateApis as componentsPrivateApis, } from '@wordpress/components'; /** @@ -19,13 +19,6 @@ import { */ import BlockPreview from '../block-preview'; import useTransformedPatterns from './use-transformed-patterns'; -import { unlock } from '../../lock-unlock'; - -const { - CompositeV2: Composite, - CompositeItemV2: CompositeItem, - useCompositeStoreV2: useCompositeStore, -} = unlock( componentsPrivateApis ); function PatternTransformationsMenu( { blocks, @@ -82,10 +75,8 @@ function PreviewPatternsPopover( { patterns, onSelect } ) { } function BlockPatternsList( { patterns, onSelect } ) { - const composite = useCompositeStore(); return ( - { pattern.title }
- + { !! pattern.description && ( { pattern.description } diff --git a/packages/block-editor/src/components/block-switcher/style.scss b/packages/block-editor/src/components/block-switcher/style.scss index 287afaed4055c..3dc2a7d591c92 100644 --- a/packages/block-editor/src/components/block-switcher/style.scss +++ b/packages/block-editor/src/components/block-switcher/style.scss @@ -55,30 +55,6 @@ } } -// Style this the same as the block buttons in the library. -// Needs specificity to override the icon button. -.block-editor-block-toolbar .components-toolbar-group .components-button.block-editor-block-switcher__no-switcher-icon.has-icon.has-icon, -.block-editor-block-toolbar .components-toolbar .components-button.block-editor-block-switcher__no-switcher-icon.has-icon.has-icon, -.block-editor-block-toolbar .components-toolbar-group .components-button.block-editor-block-switcher__toggle.has-icon.has-icon, -.block-editor-block-toolbar .components-toolbar .components-button.block-editor-block-switcher__toggle.has-icon.has-icon { - .block-editor-block-icon { - height: 100%; - position: relative; - margin: 0 auto; - display: flex; - align-items: center; - min-width: 100%; - } - - // Position the focus style correctly. - &::before { - top: $grid-unit-10; - right: $grid-unit-10; - bottom: $grid-unit-10; - left: $grid-unit-10; - } -} - .components-popover.block-editor-block-switcher__popover .components-popover__content { min-width: 300px; } @@ -99,7 +75,7 @@ width: 300px; border: $border-width solid $gray-900; background: $white; - border-radius: $radius-block-ui; + border-radius: $radius-medium; outline: none; box-shadow: none; overflow: auto; @@ -161,7 +137,7 @@ .block-editor-block-switcher__preview-patterns-container-list__item { height: 100%; - border-radius: $radius-block-ui; + border-radius: $radius-small; transition: all 0.05s ease-in-out; position: relative; border: $border-width solid transparent; diff --git a/packages/block-editor/src/components/block-toolbar/index.js b/packages/block-editor/src/components/block-toolbar/index.js index 13dfd6b33e56a..6c4789cb2924f 100644 --- a/packages/block-editor/src/components/block-toolbar/index.js +++ b/packages/block-editor/src/components/block-toolbar/index.js @@ -65,6 +65,8 @@ export function PrivateBlockToolbar( { shouldShowVisualToolbar, showParentSelector, isUsingBindings, + hasParentPattern, + hasContentOnlyLocking, } = useSelect( ( select ) => { const { getBlockName, @@ -74,6 +76,8 @@ export function PrivateBlockToolbar( { isBlockValid, getBlockEditingMode, getBlockAttributes, + getBlockParentsByBlockName, + getTemplateLock, } = select( blockEditorStore ); const selectedBlockClientIds = getSelectedBlockClientIds(); const selectedBlockClientId = selectedBlockClientIds[ 0 ]; @@ -94,6 +98,17 @@ export function PrivateBlockToolbar( { ( clientId ) => !! getBlockAttributes( clientId )?.metadata?.bindings ); + + const _hasParentPattern = selectedBlockClientIds.every( + ( clientId ) => + getBlockParentsByBlockName( clientId, 'core/block', true ) + .length > 0 + ); + + // If one or more selected blocks are locked, do not show the BlockGroupToolbar. + const _hasTemplateLock = selectedBlockClientIds.some( + ( id ) => getTemplateLock( id ) === 'contentOnly' + ); return { blockClientId: selectedBlockClientId, blockClientIds: selectedBlockClientIds, @@ -113,6 +128,8 @@ export function PrivateBlockToolbar( { selectedBlockClientIds.length === 1 && _isDefaultEditingMode, isUsingBindings: _isUsingBindings, + hasParentPattern: _hasParentPattern, + hasContentOnlyLocking: _hasTemplateLock, }; }, [] ); @@ -167,7 +184,7 @@ export function PrivateBlockToolbar( { isDefaultEditingMode && } { ( shouldShowVisualToolbar || isMultiToolbar ) && ( isDefaultEditingMode || - isContentOnlyEditingMode || + ( isContentOnlyEditingMode && ! hasParentPattern ) || isSynced ) && (
) } - { shouldShowVisualToolbar && isMultiToolbar && ( - - ) } + { ! hasContentOnlyLocking && + shouldShowVisualToolbar && + isMultiToolbar && } { shouldShowVisualToolbar && ( <> - { ! isTyping && ( + { ! isTyping && ! isZoomOutMode && ( diff --git a/packages/block-editor/src/components/block-tools/style.scss b/packages/block-editor/src/components/block-tools/style.scss index a37271e609b17..9f1325d7f95a1 100644 --- a/packages/block-editor/src/components/block-tools/style.scss +++ b/packages/block-editor/src/components/block-tools/style.scss @@ -63,7 +63,6 @@ .block-editor-inserter__toggle.components-button.has-icon { // Basic look background: $gray-900; - border-radius: $radius-block-ui; color: $white; padding: 0; @@ -95,7 +94,7 @@ z-index: z-index(".block-editor-block-list__block-selection-button"); // Dark block UI appearance. - border-radius: $radius-block-ui; + border-radius: $radius-small; background-color: $gray-900; font-size: $default-font-size; @@ -188,7 +187,7 @@ .block-editor-block-contextual-toolbar { border: $border-width solid $gray-900; - border-radius: $radius-block-ui; + border-radius: $radius-small; overflow: visible; // allow the parent selector to be visible position: static; width: auto; diff --git a/packages/block-editor/src/components/block-tools/zoom-out-mode-inserters.js b/packages/block-editor/src/components/block-tools/zoom-out-mode-inserters.js index bb044f9479c02..79f8be3f9cfe9 100644 --- a/packages/block-editor/src/components/block-tools/zoom-out-mode-inserters.js +++ b/packages/block-editor/src/components/block-tools/zoom-out-mode-inserters.js @@ -32,8 +32,11 @@ function ZoomOutModeInserters() { getSelectedBlockClientId, getHoveredBlockClientId, isBlockInsertionPointVisible, - } = select( blockEditorStore ); - const { sectionRootClientId: root } = unlock( getSettings() ); + getSectionRootClientId, + } = unlock( select( blockEditorStore ) ); + + const root = getSectionRootClientId(); + return { hasSelection: !! getSelectionStart().clientId, blockInsertionPoint: getBlockInsertionPoint(), @@ -85,18 +88,6 @@ function ZoomOutModeInserters() { previousClientId={ previousClientId } nextClientId={ nextClientId } > - { shouldRenderInsertionPoint && ( -
- ) } { ! shouldRenderInsertionPoint && ( { - let label; - if ( hasSingleBlockType ) { - label = sprintf( - // translators: %s: the name of the block when there is only one - _x( 'Add %s', 'directly add the only allowed block' ), - blockTitle - ); - } else { - label = _x( - 'Add block', - 'Generic label for block inserter button' - ); - } const isToggleButton = ! hasSingleBlockType; + const label = hasSingleBlockType + ? sprintf( + // translators: %s: the name of the block when there is only one + _x( + 'Add %s', + 'directly add the only allowed block' + ), + blockTitle + ) + : _x( + 'Add block', + 'Generic label for block inserter button' + ); - let inserterButton = ( + return ( ); - - if ( isToggleButton || hasSingleBlockType ) { - inserterButton = ( - { inserterButton } - ); - } - return inserterButton; } } isAppender /> diff --git a/packages/block-editor/src/components/colors-gradients/style.scss b/packages/block-editor/src/components/colors-gradients/style.scss index b3539637a9904..fc1b1a4d46903 100644 --- a/packages/block-editor/src/components/colors-gradients/style.scss +++ b/packages/block-editor/src/components/colors-gradients/style.scss @@ -73,15 +73,15 @@ $swatch-gap: 12px; // Identify the first visible instance as placeholder items will not have this class. &:nth-child(1 of &) { margin-top: $grid-unit-30; - border-top-left-radius: $radius-block-ui; - border-top-right-radius: $radius-block-ui; + border-top-left-radius: $radius-small; + border-top-right-radius: $radius-small; border-top: 1px solid $gray-300; } // Identify the last visible instance as placeholder items will not have this class. &:nth-last-child(1 of &) { - border-bottom-left-radius: $radius-block-ui; - border-bottom-right-radius: $radius-block-ui; + border-bottom-left-radius: $radius-small; + border-bottom-right-radius: $radius-small; } > div, diff --git a/packages/block-editor/src/components/default-block-appender/content.scss b/packages/block-editor/src/components/default-block-appender/content.scss index 77725d2508ec5..51e0b4381a15d 100644 --- a/packages/block-editor/src/components/default-block-appender/content.scss +++ b/packages/block-editor/src/components/default-block-appender/content.scss @@ -48,7 +48,6 @@ .block-editor-inserter__toggle.components-button.has-icon { // Basic look background: $gray-900; - border-radius: $radius-block-ui; color: $white; padding: 0; diff --git a/packages/block-editor/src/components/global-styles/color-panel.js b/packages/block-editor/src/components/global-styles/color-panel.js index 15f06310176c7..87c19adedbb27 100644 --- a/packages/block-editor/src/components/global-styles/color-panel.js +++ b/packages/block-editor/src/components/global-styles/color-panel.js @@ -33,7 +33,7 @@ import { unlock } from '../../lock-unlock'; export function useHasColorPanel( settings ) { const hasTextPanel = useHasTextPanel( settings ); - const hasBackgroundPanel = useHasBackgroundPanel( settings ); + const hasBackgroundPanel = useHasBackgroundColorPanel( settings ); const hasLinkPanel = useHasLinkPanel( settings ); const hasHeadingPanel = useHasHeadingPanel( settings ); const hasButtonPanel = useHasButtonPanel( settings ); @@ -97,7 +97,7 @@ export function useHasButtonPanel( settings ) { ); } -export function useHasBackgroundPanel( settings ) { +export function useHasBackgroundColorPanel( settings ) { const colors = useColorsPerOrigin( settings ); const gradients = useGradientsPerOrigin( settings ); return ( @@ -347,7 +347,7 @@ export default function ColorPanel( { }; // BackgroundColor - const showBackgroundPanel = useHasBackgroundPanel( settings ); + const showBackgroundPanel = useHasBackgroundColorPanel( settings ); const backgroundColor = decodeValue( inheritedValue?.color?.background ); const userBackgroundColor = decodeValue( value?.color?.background ); const gradient = decodeValue( inheritedValue?.color?.gradient ); diff --git a/packages/block-editor/src/components/global-styles/color-panel.native.js b/packages/block-editor/src/components/global-styles/color-panel.native.js index fcbff4e5a07d7..87002b5fa3e22 100644 --- a/packages/block-editor/src/components/global-styles/color-panel.native.js +++ b/packages/block-editor/src/components/global-styles/color-panel.native.js @@ -18,7 +18,7 @@ import InspectorControls from '../inspector-controls'; import { useHasColorPanel, useHasTextPanel, - useHasBackgroundPanel, + useHasBackgroundColorPanel, } from './color-panel.js'; import { useGlobalStyles } from './use-global-styles-context'; @@ -95,7 +95,7 @@ const ColorPanel = ( { ); // BackgroundColor - const showBackgroundPanel = useHasBackgroundPanel( settings ); + const showBackgroundPanel = useHasBackgroundColorPanel( settings ); const backgroundColor = decodeValue( inheritedValue?.color?.background ); const gradient = decodeValue( inheritedValue?.color?.gradient ); const setBackgroundColor = useCallback( diff --git a/packages/block-editor/src/components/global-styles/dimensions-panel.js b/packages/block-editor/src/components/global-styles/dimensions-panel.js index 241d3bb93d1b1..8430703aec966 100644 --- a/packages/block-editor/src/components/global-styles/dimensions-panel.js +++ b/packages/block-editor/src/components/global-styles/dimensions-panel.js @@ -11,12 +11,11 @@ import { __experimentalToolsPanel as ToolsPanel, __experimentalToolsPanelItem as ToolsPanelItem, __experimentalBoxControl as BoxControl, - __experimentalHStack as HStack, __experimentalUnitControl as UnitControl, __experimentalUseCustomUnits as useCustomUnits, - __experimentalView as View, + __experimentalInputControlPrefixWrapper as InputControlPrefixWrapper, } from '@wordpress/components'; -import { Icon, positionCenter, stretchWide } from '@wordpress/icons'; +import { Icon, alignNone, stretchWide } from '@wordpress/icons'; import { useCallback, useState, Platform } from '@wordpress/element'; /** @@ -252,7 +251,7 @@ export default function DimensionsPanel( { const minimumMargin = -Infinity; const [ minMarginValue, setMinMarginValue ] = useState( minimumMargin ); - // Content Size + // Content Width const showContentSizeControl = useHasContentSize( settings ) && includeLayoutControls; const contentSizeValue = decodeValue( inheritedValue?.layout?.contentSize ); @@ -268,7 +267,7 @@ export default function DimensionsPanel( { const hasUserSetContentSizeValue = () => !! value?.layout?.contentSize; const resetContentSizeValue = () => setContentSizeValue( undefined ); - // Wide Size + // Wide Width const showWideSizeControl = useHasWideSize( settings ) && includeLayoutControls; const wideSizeValue = decodeValue( inheritedValue?.layout?.wideSize ); @@ -464,8 +463,7 @@ export default function DimensionsPanel( { ) } { showContentSizeControl && ( - - { - setContentSizeValue( nextContentSize ); - } } - units={ units } - /> - - - - + { + setContentSizeValue( nextContentSize ); + } } + units={ units } + prefix={ + + + + } + /> ) } { showWideSizeControl && ( - - { - setWideSizeValue( nextWideSize ); - } } - units={ units } - /> - - - - + { + setWideSizeValue( nextWideSize ); + } } + units={ units } + prefix={ + + + + } + /> ) } { showPaddingControl && ( diff --git a/packages/block-editor/src/components/global-styles/shadow-panel-components.js b/packages/block-editor/src/components/global-styles/shadow-panel-components.js index e3a6c71adf8fc..1ed367e3c3ad0 100644 --- a/packages/block-editor/src/components/global-styles/shadow-panel-components.js +++ b/packages/block-editor/src/components/global-styles/shadow-panel-components.js @@ -10,7 +10,7 @@ import { Button, FlexItem, Dropdown, - privateApis as componentsPrivateApis, + Composite, } from '@wordpress/components'; import { useMemo } from '@wordpress/element'; import { shadow as shadowIcon, Icon, check } from '@wordpress/icons'; @@ -20,11 +20,6 @@ import { shadow as shadowIcon, Icon, check } from '@wordpress/icons'; */ import clsx from 'clsx'; -/** - * Internal dependencies - */ -import { unlock } from '../../lock-unlock'; - /** * Shared reference to an empty array for cases where it is important to avoid * returning a new array reference on every invocation. @@ -32,11 +27,6 @@ import { unlock } from '../../lock-unlock'; * @type {Array} */ const EMPTY_ARRAY = []; -const { - CompositeItemV2: CompositeItem, - CompositeV2: Composite, - useCompositeStoreV2: useCompositeStore, -} = unlock( componentsPrivateApis ); export function ShadowPopoverContainer( { shadow, onShadowChange, settings } ) { const shadows = useShadowPresets( settings ); @@ -66,10 +56,8 @@ export function ShadowPopoverContainer( { shadow, onShadowChange, settings } ) { } export function ShadowPresets( { presets, activeShadow, onSelect } ) { - const compositeStore = useCompositeStore(); return ! presets ? null : ( { nearestFontWeight: '400', }, }, + { + message: + 'should return nearest fontStyle and fontWeight for normal/400 when fontFamilyFaces contain numerical fontWeight value', + fontFamilyFaces: [ + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'normal', + fontWeight: 400, + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Regular.woff2', + ], + }, + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'italic', + fontWeight: '400', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Italic.woff2', + ], + }, + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'normal', + fontWeight: '700', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Bold.woff2', + ], + }, + ], + fontStyle: 'normal', + fontWeight: '400', + expected: { + nearestFontStyle: 'normal', + nearestFontWeight: '400', + }, + }, + { + message: + 'should return nearest fontStyle and fontWeight for normal/400 when fontFamilyFaces contain undefined fontWeight value', + fontFamilyFaces: [ + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'normal', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Regular.woff2', + ], + }, + ], + fontStyle: 'normal', + fontWeight: '400', + expected: { + nearestFontStyle: 'normal', + nearestFontWeight: '700', + }, + }, ].forEach( ( { message, diff --git a/packages/block-editor/src/components/global-styles/typography-utils.js b/packages/block-editor/src/components/global-styles/typography-utils.js index 32fbd50db2dbf..4b7c90ae4f222 100644 --- a/packages/block-editor/src/components/global-styles/typography-utils.js +++ b/packages/block-editor/src/components/global-styles/typography-utils.js @@ -174,6 +174,10 @@ export function findNearestFontWeight( availableFontWeights, newFontWeightValue ) { + newFontWeightValue = + 'number' === typeof newFontWeightValue + ? newFontWeightValue.toString() + : newFontWeightValue; if ( ! newFontWeightValue || typeof newFontWeightValue !== 'string' ) { return ''; } @@ -260,7 +264,7 @@ export function findNearestStyleAndWeight( ( { value: fs } ) => fs === fontStyle ); const hasFontWeight = fontWeights?.some( - ( { value: fw } ) => fw === fontWeight + ( { value: fw } ) => fw?.toString() === fontWeight?.toString() ); if ( ! hasFontStyle ) { diff --git a/packages/block-editor/src/components/grid/style.scss b/packages/block-editor/src/components/grid/style.scss index 6790d683ca7d0..3a04eb006e791 100644 --- a/packages/block-editor/src/components/grid/style.scss +++ b/packages/block-editor/src/components/grid/style.scss @@ -117,7 +117,7 @@ content: ""; position: absolute; display: block; - border-radius: $radius-block-ui; + border-radius: $radius-small; height: $grid-unit-40; // Position the focus rectangle. diff --git a/packages/block-editor/src/components/iframe/get-compatibility-styles.js b/packages/block-editor/src/components/iframe/get-compatibility-styles.js index ab80e0e8eb43e..0eae82b11e01f 100644 --- a/packages/block-editor/src/components/iframe/get-compatibility-styles.js +++ b/packages/block-editor/src/components/iframe/get-compatibility-styles.js @@ -40,7 +40,12 @@ export function getCompatibilityStyles() { // Don't try to add the reset styles, which were removed as a dependency // from `edit-blocks` for the iframe since we don't need to reset admin // styles. - if ( ownerNode.id === 'wp-reset-editor-styles-css' ) { + if ( + [ + 'wp-reset-editor-styles-css', + 'wp-reset-editor-styles-rtl-css', + ].includes( ownerNode.id ) + ) { return accumulator; } diff --git a/packages/block-editor/src/components/inner-blocks/index.js b/packages/block-editor/src/components/inner-blocks/index.js index c8db9f8cebf90..0d35b459190fe 100644 --- a/packages/block-editor/src/components/inner-blocks/index.js +++ b/packages/block-editor/src/components/inner-blocks/index.js @@ -203,7 +203,7 @@ export function useInnerBlocksProps( props = {}, options = {} ) { getBlockEditingMode, getBlockSettings, isDragging, - getSettings, + getSectionRootClientId, } = unlock( select( blockEditorStore ) ); let _isDropZoneDisabled; @@ -225,7 +225,7 @@ export function useInnerBlocksProps( props = {}, options = {} ) { // In zoom out mode, we want to disable the drop zone for the sections. // The inner blocks belonging to the section drop zone is // already disabled by the blocks themselves being disabled. - const { sectionRootClientId } = unlock( getSettings() ); + const sectionRootClientId = getSectionRootClientId(); _isDropZoneDisabled = clientId !== sectionRootClientId; } diff --git a/packages/block-editor/src/components/inserter-list-item/style.scss b/packages/block-editor/src/components/inserter-list-item/style.scss index f91e4365db30c..435f60ed9e2f1 100644 --- a/packages/block-editor/src/components/inserter-list-item/style.scss +++ b/packages/block-editor/src/components/inserter-list-item/style.scss @@ -43,7 +43,6 @@ cursor: pointer; background: transparent; word-break: break-word; - border-radius: $radius-block-ui; transition: all 0.05s ease-in-out; @include reduce-motion("transition"); position: relative; @@ -72,7 +71,7 @@ bottom: 0; left: 0; right: 0; - border-radius: $radius-block-ui; + border-radius: $radius-small; opacity: 0.04; background: var(--wp-admin-theme-color); // This fixes drag-and-drop in Firefox. @@ -97,7 +96,6 @@ .block-editor-block-types-list__item-icon { padding: 12px 20px; - border-radius: $radius-block-ui; color: $gray-900; transition: all 0.05s ease-in-out; @include reduce-motion("transition"); diff --git a/packages/block-editor/src/components/inserter-listbox/index.js b/packages/block-editor/src/components/inserter-listbox/index.js index 6af26a1d746bf..bc833b0e4c36b 100644 --- a/packages/block-editor/src/components/inserter-listbox/index.js +++ b/packages/block-editor/src/components/inserter-listbox/index.js @@ -1,28 +1,19 @@ /** * WordPress dependencies */ -import { privateApis as componentsPrivateApis } from '@wordpress/components'; +import { Composite } from '@wordpress/components'; /** * Internal dependencies */ -import { unlock } from '../../lock-unlock'; export { default as InserterListboxGroup } from './group'; export { default as InserterListboxRow } from './row'; export { default as InserterListboxItem } from './item'; -const { CompositeV2: Composite, useCompositeStoreV2: useCompositeStore } = - unlock( componentsPrivateApis ); - function InserterListbox( { children } ) { - const store = useCompositeStore( { - focusShift: true, - focusWrap: 'horizontal', - } ); - return ( - }> + }> { children } ); diff --git a/packages/block-editor/src/components/inserter-listbox/item.js b/packages/block-editor/src/components/inserter-listbox/item.js index 825c3fdfc353c..69c316bdbbcce 100644 --- a/packages/block-editor/src/components/inserter-listbox/item.js +++ b/packages/block-editor/src/components/inserter-listbox/item.js @@ -1,28 +1,18 @@ /** * WordPress dependencies */ -import { - Button, - privateApis as componentsPrivateApis, -} from '@wordpress/components'; +import { Button, Composite } from '@wordpress/components'; import { forwardRef } from '@wordpress/element'; -/** - * Internal dependencies - */ -import { unlock } from '../../lock-unlock'; - -const { CompositeItemV2: CompositeItem } = unlock( componentsPrivateApis ); - function InserterListboxItem( { isFirst, as: Component, children, ...props }, ref ) { return ( - ; + return ; } export default forwardRef( InserterListboxRow ); diff --git a/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js b/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js index 3703381b23a14..61716f616dafa 100644 --- a/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js +++ b/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js @@ -17,6 +17,7 @@ import { __experimentalText as Text, FlexBlock, } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; /** * Internal dependencies @@ -32,6 +33,7 @@ import { myPatternsCategory, INSERTER_PATTERN_TYPES, } from './utils'; +import { store as blockEditorStore } from '../../../store'; const noop = () => {}; @@ -42,6 +44,11 @@ export function PatternCategoryPreviews( { category, showTitlesAsTooltip, } ) { + const isZoomOutMode = useSelect( + ( select ) => + select( blockEditorStore ).__unstableGetEditorMode() === 'zoom-out', + [] + ); const [ allPatterns, , onClickPattern ] = usePatternsState( onInsert, rootClientId, @@ -163,22 +170,32 @@ export function PatternCategoryPreviews( { ) } - { currentCategoryPatterns.length > 0 && ( - + <> + { isZoomOutMode && ( + + { __( 'Drag and drop patterns into the canvas.' ) } + + ) } + + ) } ); diff --git a/packages/block-editor/src/components/inserter/index.js b/packages/block-editor/src/components/inserter/index.js index d3e7dba0df683..1af81d0231a1a 100644 --- a/packages/block-editor/src/components/inserter/index.js +++ b/packages/block-editor/src/components/inserter/index.js @@ -9,7 +9,7 @@ import clsx from 'clsx'; import { speak } from '@wordpress/a11y'; import { __, _x, sprintf } from '@wordpress/i18n'; import { Dropdown, Button } from '@wordpress/components'; -import { forwardRef, Component } from '@wordpress/element'; +import { Component } from '@wordpress/element'; import { withDispatch, withSelect } from '@wordpress/data'; import { compose, ifCondition } from '@wordpress/compose'; import { createBlock, store as blocksStore } from '@wordpress/blocks'; @@ -76,7 +76,7 @@ const defaultRenderToggle = ( { ); }; -class PrivateInserter extends Component { +class Inserter extends Component { constructor() { super( ...arguments ); @@ -222,7 +222,7 @@ class PrivateInserter extends Component { } } -export const ComposedPrivateInserter = compose( [ +export default compose( [ withSelect( ( select, { clientId, rootClientId, shouldDirectInsert = true } ) => { const { @@ -418,10 +418,4 @@ export const ComposedPrivateInserter = compose( [ ( { hasItems, isAppender, rootClientId, clientId } ) => hasItems || ( ! isAppender && ! rootClientId && ! clientId ) ), -] )( PrivateInserter ); - -const Inserter = forwardRef( ( props, ref ) => { - return ; -} ); - -export default Inserter; +] )( Inserter ); diff --git a/packages/block-editor/src/components/inserter/media-tab/media-list.js b/packages/block-editor/src/components/inserter/media-tab/media-list.js index bfc858bc8c4de..73f38cfc306fb 100644 --- a/packages/block-editor/src/components/inserter/media-tab/media-list.js +++ b/packages/block-editor/src/components/inserter/media-tab/media-list.js @@ -1,17 +1,13 @@ /** * WordPress dependencies */ -import { privateApis as componentsPrivateApis } from '@wordpress/components'; +import { Composite } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ import { MediaPreview } from './media-preview'; -import { unlock } from '../../../lock-unlock'; - -const { CompositeV2: Composite, useCompositeStoreV2: useCompositeStore } = - unlock( componentsPrivateApis ); function MediaList( { mediaList, @@ -19,10 +15,8 @@ function MediaList( { onClick, label = __( 'Media List' ), } ) { - const compositeStore = useCompositeStore(); return ( - ) }
- + { ! isInserting && ( {}; function InserterMenu( @@ -102,12 +101,12 @@ function InserterMenu( window.requestAnimationFrame( () => { if ( ! shouldFocusBlock && - ! blockTypesTabRef?.current.contains( + ! blockTypesTabRef.current?.contains( ref.current.ownerDocument.activeElement ) ) { // There has been a focus loss, so focus the first button in the block types tab - blockTypesTabRef?.current.querySelector( 'button' ).focus(); + blockTypesTabRef.current?.querySelector( 'button' ).focus(); } } ); }, @@ -147,11 +146,6 @@ function InserterMenu( const showMediaPanel = selectedTab === 'media' && !! selectedMediaCategory; - const showZoomOut = - showPatternPanel && !! window.__experimentalEnableZoomedOutPatternsTab; - - useZoomOut( showZoomOut ); - const inserterSearch = useMemo( () => { if ( selectedTab === 'media' ) { return null; diff --git a/packages/block-editor/src/components/inserter/quick-inserter.js b/packages/block-editor/src/components/inserter/quick-inserter.js index 0852c562828a4..e28ae1f3896c4 100644 --- a/packages/block-editor/src/components/inserter/quick-inserter.js +++ b/packages/block-editor/src/components/inserter/quick-inserter.js @@ -9,7 +9,7 @@ import clsx from 'clsx'; import { useState, useEffect } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { Button, SearchControl } from '@wordpress/components'; -import { useDispatch, useSelect } from '@wordpress/data'; +import { useSelect } from '@wordpress/data'; /** * Internal dependencies @@ -82,8 +82,6 @@ export default function QuickInserter( { } }, [ setInserterIsOpened ] ); - const { showInsertionPoint } = useDispatch( blockEditorStore ); - // When clicking Browse All select the appropriate block so as // the insertion point can work as expected. const onBrowseAll = () => { @@ -93,7 +91,6 @@ export default function QuickInserter( { filterValue, onSelect, } ); - showInsertionPoint( rootClientId, insertionIndex ); }; let maxBlockPatterns = 0; diff --git a/packages/block-editor/src/components/inserter/style.scss b/packages/block-editor/src/components/inserter/style.scss index 21f8abfa59c9e..289acecb5c1c3 100644 --- a/packages/block-editor/src/components/inserter/style.scss +++ b/packages/block-editor/src/components/inserter/style.scss @@ -44,12 +44,12 @@ $block-inserter-tabs-height: 44px; &:first-child { border-top: $border-width solid $gray-400; - border-radius: $radius-block-ui $radius-block-ui 0 0; + border-radius: $radius-medium $radius-medium 0 0; } &:last-child { border-bottom: $border-width solid $gray-400; - border-radius: 0 0 $radius-block-ui $radius-block-ui; + border-radius: 0 0 $radius-medium $radius-medium; } &.components-button { @@ -276,7 +276,7 @@ $block-inserter-tabs-height: 44px; bottom: 0; left: 0; right: 0; - border-radius: $radius-block-ui; + border-radius: $radius-small; opacity: 0.04; background: var(--wp-admin-theme-color); height: 100%; @@ -359,7 +359,7 @@ $block-inserter-tabs-height: 44px; min-height: $grid-unit-60 * 3; color: $gray-700; background: $gray-100; - border-radius: $radius-block-ui; + border-radius: $radius-small; } .block-editor-inserter__tips { @@ -577,7 +577,6 @@ $block-inserter-tabs-height: 44px; > button { background: $white; - border-radius: $radius-block-ui; display: none; // These styles are important so as focus isn't lost @@ -611,7 +610,6 @@ $block-inserter-tabs-height: 44px; max-width: 100%; outline: $border-width solid rgba($black, 0.1); outline-offset: -$border-width; - border-radius: $radius-block-ui; } .block-editor-inserter__media-list__item-preview-spinner { @@ -711,3 +709,7 @@ $block-inserter-tabs-height: 44px; } } } + +.block-editor-tabbed-sidebar__tabpanel .block-editor-inserter__help-text { + padding: 0 $grid-unit-30 $grid-unit-20; +} diff --git a/packages/block-editor/src/components/inspector-controls-tabs/settings-tab.js b/packages/block-editor/src/components/inspector-controls-tabs/settings-tab.js index ec34035b754a9..ea2f45114bf9c 100644 --- a/packages/block-editor/src/components/inspector-controls-tabs/settings-tab.js +++ b/packages/block-editor/src/components/inspector-controls-tabs/settings-tab.js @@ -9,6 +9,7 @@ const SettingsTab = ( { showAdvancedControls = false } ) => ( <> + { showAdvancedControls && (
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js b/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js index ff68be82a829f..6a80d47f02481 100644 --- a/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js +++ b/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js @@ -32,6 +32,7 @@ function getShowTabs( blockName, tabSettings = {} ) { export default function useInspectorControlsTabs( blockName ) { const tabs = []; const { + bindings: bindingsGroup, border: borderGroup, color: colorGroup, default: defaultGroup, @@ -64,8 +65,10 @@ export default function useInspectorControlsTabs( blockName ) { // (i.e. both list view and styles), check only the default and position // InspectorControls slots. If we have multiple tabs, we'll need to check // the advanced controls slot as well to ensure they are rendered. - const advancedFills = - useSlotFills( InspectorAdvancedControls.slotName ) || []; + const advancedFills = [ + ...( useSlotFills( InspectorAdvancedControls.slotName ) || [] ), + ...( useSlotFills( bindingsGroup.Slot.__unstableName ) || [] ), + ]; const settingsFills = [ ...( useSlotFills( defaultGroup.Slot.__unstableName ) || [] ), diff --git a/packages/block-editor/src/components/inspector-controls/groups.js b/packages/block-editor/src/components/inspector-controls/groups.js index 9ca1a72b9918a..34ec49a5e1cb4 100644 --- a/packages/block-editor/src/components/inspector-controls/groups.js +++ b/packages/block-editor/src/components/inspector-controls/groups.js @@ -5,6 +5,7 @@ import { createSlotFill } from '@wordpress/components'; const InspectorControlsDefault = createSlotFill( 'InspectorControls' ); const InspectorControlsAdvanced = createSlotFill( 'InspectorAdvancedControls' ); +const InspectorControlsBindings = createSlotFill( 'InspectorControlsBindings' ); const InspectorControlsBackground = createSlotFill( 'InspectorControlsBackground' ); @@ -26,6 +27,7 @@ const groups = { default: InspectorControlsDefault, advanced: InspectorControlsAdvanced, background: InspectorControlsBackground, + bindings: InspectorControlsBindings, border: InspectorControlsBorder, color: InspectorControlsColor, dimensions: InspectorControlsDimensions, diff --git a/packages/block-editor/src/components/link-control/style.scss b/packages/block-editor/src/components/link-control/style.scss index 1390a285fe163..b0a5f6af2651b 100644 --- a/packages/block-editor/src/components/link-control/style.scss +++ b/packages/block-editor/src/components/link-control/style.scss @@ -78,7 +78,6 @@ $block-editor-link-control-number-of-actions: 1; @include input-control; display: block; border: $border-width solid $gray-600; - border-radius: $radius-block-ui; height: $button-size-next-default-40px; // components do not properly support unstable-large yet. margin: 0; padding: $grid-unit-10 $button-size-next-default-40px $grid-unit-10 $grid-unit-20; @@ -230,7 +229,7 @@ $block-editor-link-control-number-of-actions: 1; background-color: $gray-100; width: $grid-unit-40; height: $grid-unit-40; - border-radius: $radius-block-ui; + border-radius: $radius-small; } .block-editor-link-control__search-item-icon { @@ -252,7 +251,6 @@ $block-editor-link-control-number-of-actions: 1; } .block-editor-link-control__search-item-title { - border-radius: $radius-block-ui; line-height: 1.1; diff --git a/packages/block-editor/src/components/list-view/style.scss b/packages/block-editor/src/components/list-view/style.scss index 406053af89317..3d25597d2af90 100644 --- a/packages/block-editor/src/components/list-view/style.scss +++ b/packages/block-editor/src/components/list-view/style.scss @@ -101,16 +101,16 @@ // Border radius for corners of the selected item. &.is-first-selected td:first-child { - border-top-left-radius: $radius-block-ui; + border-top-left-radius: $radius-small; } &.is-first-selected td:last-child { - border-top-right-radius: $radius-block-ui; + border-top-right-radius: $radius-small; } &.is-last-selected td:first-child { - border-bottom-left-radius: $radius-block-ui; + border-bottom-left-radius: $radius-small; } &.is-last-selected td:last-child { - border-bottom-right-radius: $radius-block-ui; + border-bottom-right-radius: $radius-small; } &.is-branch-selected:not(.is-selected):not(.is-synced-branch) { background: rgba(var(--wp-admin-theme-color--rgb), 0.04); @@ -119,23 +119,23 @@ background: rgba(var(--wp-block-synced-color--rgb), 0.04); } &.is-branch-selected.is-first-selected td:first-child { - border-top-left-radius: $radius-block-ui; + border-top-left-radius: $radius-small; } &.is-branch-selected.is-first-selected td:last-child { - border-top-right-radius: $radius-block-ui; + border-top-right-radius: $radius-small; } &[data-expanded="false"] { &.is-branch-selected.is-first-selected td:first-child { - border-top-left-radius: $radius-block-ui; + border-top-left-radius: $radius-small; } &.is-branch-selected.is-first-selected td:last-child { - border-top-right-radius: $radius-block-ui; + border-top-right-radius: $radius-small; } &.is-branch-selected.is-last-selected td:first-child { - border-bottom-left-radius: $radius-block-ui; + border-bottom-left-radius: $radius-small; } &.is-branch-selected.is-last-selected td:last-child { - border-bottom-right-radius: $radius-block-ui; + border-bottom-right-radius: $radius-small; } } &.is-branch-selected:not(.is-selected) td { @@ -214,7 +214,6 @@ height: $grid-unit-40; padding: ($grid-unit-15 * 0.5) $grid-unit-05 ($grid-unit-15 * 0.5) 0; text-align: left; - border-radius: $radius-block-ui; position: relative; white-space: nowrap; @@ -406,7 +405,7 @@ right: 0; transform: translateY(-50%); background: rgba($black, 0.1); - border-radius: $radius-block-ui; + border-radius: $radius-x-small; padding: 2px 6px; max-width: 100%; box-sizing: border-box; @@ -429,10 +428,10 @@ background-size: cover; width: 18px; height: 18px; - border-radius: $radius-block-ui; + border-radius: $radius-x-small; &:not(:only-child) { - box-shadow: 0 0 0 $radius-block-ui $white; + box-shadow: 0 0 0 $radius-small $white; } &:not(:first-child) { @@ -442,7 +441,7 @@ &.is-selected .block-editor-list-view-block-select-button__image { &:not(:only-child) { - box-shadow: 0 0 0 $radius-block-ui var(--wp-admin-theme-color); + box-shadow: 0 0 0 $radius-small var(--wp-admin-theme-color); } } } diff --git a/packages/block-editor/src/components/media-placeholder/README.md b/packages/block-editor/src/components/media-placeholder/README.md index 6cb00206d93d7..68fcf150c4edc 100644 --- a/packages/block-editor/src/components/media-placeholder/README.md +++ b/packages/block-editor/src/components/media-placeholder/README.md @@ -198,9 +198,9 @@ Callback called when urls can be configured. No media insertion from url will be ### handleUpload -When set to false the handling of the upload is left to the calling component. +When the value is set to `false` or returned as `false`, the handling of the upload is left to the consumer component. The function signature accepts an array containing the files to be uploaded. -- Type: `Boolean` +- Type: `Boolean|Function` - Required: No - Default: `true` - Platform: Web diff --git a/packages/block-editor/src/components/media-placeholder/index.js b/packages/block-editor/src/components/media-placeholder/index.js index a5b4eb0bf19b3..4d41289f324c0 100644 --- a/packages/block-editor/src/components/media-placeholder/index.js +++ b/packages/block-editor/src/components/media-placeholder/index.js @@ -172,7 +172,10 @@ export function MediaPlaceholder( { }; const onFilesUpload = ( files ) => { - if ( ! handleUpload ) { + if ( + ! handleUpload || + ( typeof handleUpload === 'function' && ! handleUpload( files ) ) + ) { return onSelect( files ); } onFilesPreUpload( files ); @@ -320,15 +323,15 @@ export function MediaPlaceholder( { if ( isAudio ) { instructions = __( - 'Upload an audio file, pick one from your media library, or add one with a URL.' + 'Upload or drag an audio file here, or pick one from your library.' ); } else if ( isImage ) { instructions = __( - 'Upload an image file, pick one from your media library, or add one with a URL.' + 'Upload or drag an image file here, or pick one from your library.' ); } else if ( isVideo ) { instructions = __( - 'Upload a video file, pick one from your media library, or add one with a URL.' + 'Upload or drag a video file here, or pick one from your library.' ); } } diff --git a/packages/block-editor/src/components/responsive-block-control/README.md b/packages/block-editor/src/components/responsive-block-control/README.md index 379e245f03ff3..16183ccd6314f 100644 --- a/packages/block-editor/src/components/responsive-block-control/README.md +++ b/packages/block-editor/src/components/responsive-block-control/README.md @@ -27,9 +27,6 @@ import { InspectorControls, __experimentalResponsiveBlockControl as ResponsiveBlockControl, } from '@wordpress/block-editor'; -import { - DimensionControl, -} from '@wordpress/components'; registerBlockType( 'my-plugin/my-block', { // ... @@ -37,34 +34,13 @@ registerBlockType( 'my-plugin/my-block', { edit( { attributes, setAttributes } ) { const [ isResponsive, setIsResponsive ] = useState( false ); - - // Used for example purposes only - const sizeOptions = [ - { - label: 'Small', - value: 'small', - }, - { - label: 'Medium', - value: 'medium', - }, - { - label: 'Large', - value: 'large', - }, - ]; - const { paddingSize } = attributes; - // Your custom control can be anything you'd like to use. - // You are not restricted to `DimensionControl`s, but this - // makes life easier if dealing with standard CSS values. - // see `packages/components/src/dimension-control/README.md` const paddingControl = ( labelComponent, viewport ) => { return ( - { // id: 'small', // label: 'All' // } - return ; + return ; }; ``` diff --git a/packages/block-editor/src/components/rich-text/style.scss b/packages/block-editor/src/components/rich-text/style.scss index a3bb78b2521db..ca274d378d408 100644 --- a/packages/block-editor/src/components/rich-text/style.scss +++ b/packages/block-editor/src/components/rich-text/style.scss @@ -12,7 +12,7 @@ } .components-toolbar { - border-radius: $radius-block-ui; + border-radius: $radius-small; } .components-toolbar__control, diff --git a/packages/block-editor/src/components/spacing-sizes-control/style.scss b/packages/block-editor/src/components/spacing-sizes-control/style.scss index cbcc8e30c5825..a387e5369d01e 100644 --- a/packages/block-editor/src/components/spacing-sizes-control/style.scss +++ b/packages/block-editor/src/components/spacing-sizes-control/style.scss @@ -19,6 +19,7 @@ .spacing-sizes-control__range-control, .spacing-sizes-control__custom-value-range { flex: 1; + margin-bottom: 0; // Needed for some instances of the range control, such as the Spacer block. } .components-range-control__mark { diff --git a/packages/block-editor/src/components/use-block-drop-zone/index.js b/packages/block-editor/src/components/use-block-drop-zone/index.js index 8115fe8f72a64..ff4d52aaa493b 100644 --- a/packages/block-editor/src/components/use-block-drop-zone/index.js +++ b/packages/block-editor/src/components/use-block-drop-zone/index.js @@ -274,6 +274,23 @@ export function isDropTargetValid( return areBlocksAllowed && targetMatchesDraggedBlockParents; } +/** + * Checks if the given element is an insertion point. + * + * @param {EventTarget|null} targetToCheck - The element to check. + * @param {Document} ownerDocument - The owner document of the element. + * @return {boolean} True if the element is a insertion point, false otherwise. + */ +function isInsertionPoint( targetToCheck, ownerDocument ) { + const { defaultView } = ownerDocument; + + return !! ( + defaultView && + targetToCheck instanceof defaultView.HTMLElement && + targetToCheck.dataset.isInsertionPoint + ); +} + /** * @typedef {Object} WPBlockDropZoneConfig * @property {?HTMLElement} dropZoneElement Optional element to be used as the drop zone. @@ -313,8 +330,8 @@ export default function useBlockDropZone( { getAllowedBlocks, isDragging, isGroupable, - getSettings, isZoomOutMode, + getSectionRootClientId, } = unlock( useSelect( blockEditorStore ) ); const { showInsertionPoint, @@ -360,7 +377,7 @@ export default function useBlockDropZone( { return; } - const { sectionRootClientId } = unlock( getSettings() ); + const sectionRootClientId = getSectionRootClientId(); // In Zoom Out mode, if the target is not the section root provided by settings then // do not allow dropping as the drop target is not within the root (that which is @@ -422,6 +439,10 @@ export default function useBlockDropZone( { const [ targetIndex, operation, nearestSide ] = dropTargetPosition; + if ( isZoomOutMode() && operation !== 'insert' ) { + return; + } + if ( operation === 'group' ) { const targetBlock = blocks[ targetIndex ]; const areAllImages = [ @@ -492,6 +513,8 @@ export default function useBlockDropZone( { getBlockNamesByClientId, getDraggedBlockClientIds, getBlockType, + getSectionRootClientId, + isZoomOutMode, getBlocks, getBlockListSettings, dropZoneElement, @@ -504,8 +527,6 @@ export default function useBlockDropZone( { isGroupable, getBlockVariations, getGroupingBlockName, - getSettings, - isZoomOutMode, ] ), 200 @@ -521,7 +542,18 @@ export default function useBlockDropZone( { // https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget throttled( event, event.currentTarget.ownerDocument ); }, - onDragLeave() { + onDragLeave( event ) { + const { ownerDocument } = event.currentTarget; + + // If the drag event is leaving the drop zone and entering an insertion point, + // do not hide the insertion point as it is conceptually within the dropzone. + if ( + isInsertionPoint( event.relatedTarget, ownerDocument ) || + isInsertionPoint( event.target, ownerDocument ) + ) { + return; + } + throttled.cancel(); hideInsertionPoint(); }, diff --git a/packages/block-editor/src/components/warning/content.scss b/packages/block-editor/src/components/warning/content.scss index f4eeb253c1c2f..9380a224b2ff9 100644 --- a/packages/block-editor/src/components/warning/content.scss +++ b/packages/block-editor/src/components/warning/content.scss @@ -7,7 +7,7 @@ // Block UI appearance. border: $border-width solid $gray-900; - border-radius: $radius-block-ui; + border-radius: $radius-small; background-color: $white; .block-editor-warning__message { @@ -30,21 +30,14 @@ flex-wrap: wrap; align-items: baseline; width: 100%; + gap: $grid-unit-15; } .block-editor-warning__actions { align-items: center; display: flex; - margin-top: 1em; + gap: $grid-unit-10; } - - .block-editor-warning__action { - margin: 0 $grid-unit-10 0 0; - } -} - -.block-editor-warning__secondary { - margin: auto 0 auto $grid-unit-10; } .components-popover.block-editor-warning__dropdown { diff --git a/packages/block-editor/src/hooks/block-bindings.js b/packages/block-editor/src/hooks/block-bindings.js index 3b90ecc1a0c17..3b59de2238b96 100644 --- a/packages/block-editor/src/hooks/block-bindings.js +++ b/packages/block-editor/src/hooks/block-bindings.js @@ -9,11 +9,10 @@ import { __experimentalText as Text, __experimentalToolsPanel as ToolsPanel, __experimentalToolsPanelItem as ToolsPanelItem, - __experimentalTruncate as Truncate, __experimentalVStack as VStack, privateApis as componentsPrivateApis, } from '@wordpress/components'; -import { useRegistry } from '@wordpress/data'; +import { useRegistry, useSelect } from '@wordpress/data'; import { useContext, Fragment } from '@wordpress/element'; import { useViewportMatch } from '@wordpress/compose'; @@ -28,6 +27,7 @@ import { unlock } from '../lock-unlock'; import InspectorControls from '../components/inspector-controls'; import BlockContext from '../components/block-context'; import { useBlockBindingsUtils } from '../utils/block-bindings'; +import { store as blockEditorStore } from '../store'; const { DropdownMenuV2 } = unlock( componentsPrivateApis ); @@ -96,17 +96,19 @@ function BlockBindingsAttribute( { attribute, binding } ) { const { source: sourceName, args } = binding || {}; const sourceProps = unlock( blocksPrivateApis ).getBlockBindingsSource( sourceName ); + const isSourceInvalid = ! sourceProps; return ( - - { attribute } + + { attribute } { !! binding && ( - - { args?.key || sourceProps?.label || sourceName } - + { isSourceInvalid + ? __( 'Invalid source' ) + : args?.key || sourceProps?.label || sourceName } ) } @@ -195,6 +197,13 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => { } } ); + const { canUpdateBlockBindings } = useSelect( ( select ) => { + return { + canUpdateBlockBindings: + select( blockEditorStore ).getSettings().canUpdateBlockBindings, + }; + }, [] ); + if ( ! bindableAttributes || bindableAttributes.length === 0 ) { return null; } @@ -230,17 +239,16 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => { } } ); - // Lock the UI when the experiment is not enabled or there are no fields to connect to. + // Lock the UI when the user can't update bindings or there are no fields to connect to. const readOnly = - ! window.__experimentalBlockBindingsUI || - ! Object.keys( fieldsList ).length; + ! canUpdateBlockBindings || ! Object.keys( fieldsList ).length; if ( readOnly && Object.keys( filteredBindings ).length === 0 ) { return null; } return ( - + { @@ -262,9 +270,13 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => { /> ) } - - { __( 'Attributes connected to various sources.' ) } - + + + { __( + 'Attributes connected to custom fields or other dynamic data.' + ) } + + ); diff --git a/packages/block-editor/src/hooks/block-bindings.scss b/packages/block-editor/src/hooks/block-bindings.scss index 69eaa18d57dae..e8f05895922f0 100644 --- a/packages/block-editor/src/hooks/block-bindings.scss +++ b/packages/block-editor/src/hooks/block-bindings.scss @@ -1,6 +1,6 @@ div.block-editor-bindings__panel { grid-template-columns: repeat(auto-fit, minmax(100%, 1fr)); - button:hover .block-editor-bindings__item-explanation { + button:hover .block-editor-bindings__item span { color: inherit; } } diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index 2ea8c5f37c9e7..22d916d7b791b 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -233,7 +233,6 @@ function LayoutPanelPure( { <> + { allowCustomContentAndWideSize && ( <> -
-
- { - nextWidth = - 0 > parseFloat( nextWidth ) - ? '0' - : nextWidth; - onChange( { - ...layout, - contentSize: nextWidth, - } ); - } } - units={ units } - /> - -
-
- { - nextWidth = - 0 > parseFloat( nextWidth ) - ? '0' - : nextWidth; - onChange( { - ...layout, - wideSize: nextWidth, - } ); - } } - units={ units } - /> - -
-
-

+ { + nextWidth = + 0 > parseFloat( nextWidth ) + ? '0' + : nextWidth; + onChange( { + ...layout, + contentSize: nextWidth, + } ); + } } + units={ units } + prefix={ + + + + } + /> + { + nextWidth = + 0 > parseFloat( nextWidth ) + ? '0' + : nextWidth; + onChange( { + ...layout, + wideSize: nextWidth, + } ); + } } + units={ units } + prefix={ + + + + } + /> +

{ __( 'Customize the width for all elements that are assigned to the center or wide columns.' ) } @@ -149,7 +150,7 @@ export default { ) } ) } - + ); }, toolBarControls: function DefaultLayoutToolbarControls( { diff --git a/packages/block-editor/src/layouts/grid.js b/packages/block-editor/src/layouts/grid.js index 7ab5c7ebbc8c3..f1573b5c94960 100644 --- a/packages/block-editor/src/layouts/grid.js +++ b/packages/block-editor/src/layouts/grid.js @@ -13,6 +13,7 @@ import { __experimentalToggleGroupControlOption as ToggleGroupControlOption, __experimentalUnitControl as UnitControl, __experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue, + __experimentalVStack as VStack, } from '@wordpress/components'; import { useState } from '@wordpress/element'; @@ -74,7 +75,8 @@ export default { // In the experiment we want to also show column control in Auto mode, and // the minimum width control in Manual mode. const showColumnsControl = - window.__experimentalEnableGridInteractivity || layout?.columnCount; + window.__experimentalEnableGridInteractivity || + !! layout?.columnCount; const showMinWidthControl = window.__experimentalEnableGridInteractivity || ! layout?.columnCount; @@ -84,19 +86,21 @@ export default { layout={ layout } onChange={ onChange } /> - { showColumnsControl && ( - - ) } - { showMinWidthControl && ( - - ) } + + { showColumnsControl && ( + + ) } + { showMinWidthControl && ( + + ) } + ); }, @@ -317,7 +321,7 @@ function GridLayoutColumnsAndRowsControl( { const defaultNewColumnCount = isManualPlacement ? 1 : undefined; const newColumnCount = - value === '' + value === '' || value === '0' ? defaultNewColumnCount : parseInt( value, 10 ); onChange( { @@ -327,7 +331,7 @@ function GridLayoutColumnsAndRowsControl( { } else { // Don't allow unsetting the column count. const newColumnCount = - value === '' + value === '' || value === '0' ? 1 : parseInt( value, 10 ); onChange( { @@ -337,7 +341,7 @@ function GridLayoutColumnsAndRowsControl( { } } } value={ columnCount } - min={ 0 } + min={ 1 } label={ __( 'Columns' ) } hideLabelFromVision={ ! window.__experimentalEnableGridInteractivity || @@ -355,7 +359,7 @@ function GridLayoutColumnsAndRowsControl( { onChange={ ( value ) => { // Don't allow unsetting the row count. const newRowCount = - value === '' + value === '' || value === '0' ? 1 : parseInt( value, 10 ); onChange( { @@ -364,21 +368,24 @@ function GridLayoutColumnsAndRowsControl( { } ); } } value={ rowCount } - min={ 0 } + min={ 1 } label={ __( 'Rows' ) } /> ) : ( onChange( { ...layout, - columnCount: value, + columnCount: + value === '' || value === '0' + ? 1 + : value, } ) } - min={ 0 } + min={ 1 } max={ 16 } withInputField={ false } label={ __( 'Columns' ) } diff --git a/packages/block-editor/src/private-apis.js b/packages/block-editor/src/private-apis.js index 788bb2bef56ef..12f477a95a196 100644 --- a/packages/block-editor/src/private-apis.js +++ b/packages/block-editor/src/private-apis.js @@ -6,7 +6,6 @@ import { ExperimentalBlockEditorProvider } from './components/provider'; import { lock } from './lock-unlock'; import { getRichTextValues } from './components/rich-text/get-rich-text-values'; import ResizableBoxPopover from './components/resizable-box-popover'; -import { ComposedPrivateInserter as PrivateInserter } from './components/inserter'; import { default as PrivateQuickInserter } from './components/inserter/quick-inserter'; import { extractWords, @@ -38,6 +37,7 @@ import { reusableBlocksSelectKey, globalStylesDataKey, globalStylesLinksDataKey, + sectionRootClientIdKey, } from './store/private-keys'; import { requiresWrapperOnCopy } from './components/writing-flow/utils'; import { PrivateRichText } from './components/rich-text/'; @@ -59,7 +59,6 @@ lock( privateApis, { ExperimentalBlockEditorProvider, getDuotoneFilter, getRichTextValues, - PrivateInserter, PrivateQuickInserter, extractWords, getNormalizedSearchTerms, @@ -94,4 +93,5 @@ lock( privateApis, { __unstableBlockStyleVariationOverridesWithConfig, setBackgroundStyleDefaults, useBlockBindingsUtils, + sectionRootClientIdKey, } ); diff --git a/packages/block-editor/src/store/actions.js b/packages/block-editor/src/store/actions.js index 319398667293e..e91f997ca6783 100644 --- a/packages/block-editor/src/store/actions.js +++ b/packages/block-editor/src/store/actions.js @@ -34,8 +34,6 @@ import { __experimentalUpdateSettings, privateRemoveBlocks, } from './private-actions'; -import { STORE_NAME } from './constants'; -import { unlock } from '../lock-unlock'; /** @typedef {import('../components/use-on-block-drop/types').WPDropOperation} WPDropOperation */ @@ -1670,13 +1668,13 @@ export const setNavigationMode = */ export const __unstableSetEditorMode = ( mode ) => - ( { dispatch, select, registry } ) => { + ( { dispatch, select } ) => { // When switching to zoom-out mode, we need to select the parent section if ( mode === 'zoom-out' ) { const firstSelectedClientId = select.getBlockSelectionStart(); - const { sectionRootClientId } = unlock( - registry.select( STORE_NAME ).getSettings() - ); + + const sectionRootClientId = select.getSectionRootClientId(); + if ( firstSelectedClientId ) { let sectionClientId; diff --git a/packages/block-editor/src/store/private-keys.js b/packages/block-editor/src/store/private-keys.js index 00fac5531b9c3..e24b4a6264e72 100644 --- a/packages/block-editor/src/store/private-keys.js +++ b/packages/block-editor/src/store/private-keys.js @@ -2,3 +2,4 @@ export const globalStylesDataKey = Symbol( 'globalStylesDataKey' ); export const globalStylesLinksDataKey = Symbol( 'globalStylesLinks' ); export const selectBlockPatternsKey = Symbol( 'selectBlockPatternsKey' ); export const reusableBlocksSelectKey = Symbol( 'reusableBlocksSelect' ); +export const sectionRootClientIdKey = Symbol( 'sectionRootClientIdKey' ); diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index 9cc793362296c..b72ebd1818337 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -28,6 +28,7 @@ import { unlock } from '../lock-unlock'; import { selectBlockPatternsKey, reusableBlocksSelectKey, + sectionRootClientIdKey, } from './private-keys'; export { getBlockSettings } from './get-block-settings'; @@ -421,9 +422,11 @@ const EMPTY_ARRAY = []; export const getReusableBlocks = createRegistrySelector( ( select ) => ( state ) => { const reusableBlocksSelect = state.settings[ reusableBlocksSelectKey ]; - return reusableBlocksSelect - ? reusableBlocksSelect( select ) - : state.settings.__experimentalReusableBlocks ?? EMPTY_ARRAY; + return ( + ( reusableBlocksSelect + ? reusableBlocksSelect( select ) + : state.settings.__experimentalReusableBlocks ) ?? EMPTY_ARRAY + ); } ); @@ -543,3 +546,7 @@ export const getBlockStyles = createSelector( export function isZoomOutMode( state ) { return state.editorMode === 'zoom-out'; } + +export function getSectionRootClientId( state ) { + return state.settings?.[ sectionRootClientIdKey ]; +} diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index 91d853a50a6a4..cd4569c45e580 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -1624,8 +1624,6 @@ export function insertionPoint( state = null, action ) { } case 'HIDE_INSERTION_POINT': - case 'CLEAR_SELECTED_BLOCK': - case 'SELECT_BLOCK': return null; } diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index b30a719d21fd4..30fdb76bdbe78 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -37,6 +37,7 @@ import { getContentLockingParent, getTemporarilyEditingAsBlocks, getTemporarilyEditingFocusModeToRevert, + getSectionRootClientId, } from './private-selectors'; /** @@ -2058,9 +2059,8 @@ export const getInserterItems = createRegistrySelector( ( select ) => if ( ! item.rootClientId ) { let sectionRootClientId; try { - sectionRootClientId = unlock( - getSettings( state ) - ).sectionRootClientId; + sectionRootClientId = + getSectionRootClientId( state ); } catch ( e ) {} if ( sectionRootClientId && @@ -2838,7 +2838,7 @@ export function __unstableHasActiveBlockOverlayActive( state, clientId ) { // In zoom-out mode, the block overlay is always active for section level blocks. if ( editorMode === 'zoom-out' ) { - const { sectionRootClientId } = unlock( getSettings( state ) ); + const sectionRootClientId = getSectionRootClientId( state ); if ( sectionRootClientId ) { const sectionClientIds = getBlockOrder( state, @@ -2931,7 +2931,8 @@ export const getBlockEditingMode = createRegistrySelector( // sections. const editorMode = __unstableGetEditorMode( state ); if ( editorMode === 'zoom-out' ) { - const { sectionRootClientId } = unlock( getSettings( state ) ); + const sectionRootClientId = getSectionRootClientId( state ); + if ( clientId === '' /* ROOT_CONTAINER_CLIENT_ID */ ) { return sectionRootClientId ? 'disabled' : 'contentOnly'; } diff --git a/packages/block-editor/src/utils/dom.js b/packages/block-editor/src/utils/dom.js index bfdce60b9f006..9c2e813ef742b 100644 --- a/packages/block-editor/src/utils/dom.js +++ b/packages/block-editor/src/utils/dom.js @@ -96,11 +96,26 @@ function isElementVisible( element ) { return false; } - return element.checkVisibility( { - opacityProperty: true, - contentVisibilityAuto: true, - visibilityProperty: true, - } ); + // Older browsers, e.g. Safari < 17.4 may not support the `checkVisibility` method. + if ( element.checkVisibility ) { + return element.checkVisibility?.( { + opacityProperty: true, + contentVisibilityAuto: true, + visibilityProperty: true, + } ); + } + + const style = viewport.getComputedStyle( element ); + + if ( + style.display === 'none' || + style.visibility === 'hidden' || + style.opacity === '0' + ) { + return false; + } + + return true; } /** diff --git a/packages/block-editor/src/utils/get-font-styles-and-weights.js b/packages/block-editor/src/utils/get-font-styles-and-weights.js index 88b40a5aacfeb..dcb56fc86b267 100644 --- a/packages/block-editor/src/utils/get-font-styles-and-weights.js +++ b/packages/block-editor/src/utils/get-font-styles-and-weights.js @@ -79,7 +79,10 @@ export function getFontStylesAndWeights( fontFamilyFaces ) { fontFamilyFaces?.forEach( ( face ) => { // Check for variable font by looking for a space in the font weight value. e.g. "100 900" - if ( /\s/.test( face.fontWeight.trim() ) ) { + if ( + 'string' === typeof face.fontWeight && + /\s/.test( face.fontWeight.trim() ) + ) { isVariableFont = true; // Find font weight start and end values. @@ -105,11 +108,15 @@ export function getFontStylesAndWeights( fontFamilyFaces ) { } // Format font style and weight values. - const fontWeight = formatFontWeight( face.fontWeight ); + const fontWeight = formatFontWeight( + 'number' === typeof face.fontWeight + ? face.fontWeight.toString() + : face.fontWeight + ); const fontStyle = formatFontStyle( face.fontStyle ); // Create font style and font weight lists without duplicates. - if ( fontStyle ) { + if ( fontStyle && Object.keys( fontStyle ).length ) { if ( ! fontStyles.some( ( style ) => style.value === fontStyle.value @@ -118,7 +125,8 @@ export function getFontStylesAndWeights( fontFamilyFaces ) { fontStyles.push( fontStyle ); } } - if ( fontWeight ) { + + if ( fontWeight && Object.keys( fontWeight ).length ) { if ( ! fontWeights.some( ( weight ) => weight.value === fontWeight.value diff --git a/packages/block-editor/src/utils/test/get-font-styles-and-weights.js b/packages/block-editor/src/utils/test/get-font-styles-and-weights.js index ffc1a635aa1fb..7c50409bae1ac 100644 --- a/packages/block-editor/src/utils/test/get-font-styles-and-weights.js +++ b/packages/block-editor/src/utils/test/get-font-styles-and-weights.js @@ -343,6 +343,17 @@ describe( 'getFontStylesAndWeights', () => { fontWeight: '400', src: 'http://www.wordpress.org/wp-content/uploads/fonts/N0b52SlTPu5rIkWIZjVKKtYtfxYqZ4RJBFzFfYUjkSDdlqZgy7LYxnL31AHfAAy5.woff2', }, + { + fontFamily: 'Piazzolla', + fontStyle: 'normal', + fontWeight: 600, + src: 'http://www.wordpress.org/wp-content/uploads/fonts/N0b52SlTPu5rIkWIZjVKKtYtfxYqZ4RJBFzFfYUjkSDdlqZgy7JxwXL31AHfAAy5.woff2', + }, + { + fontFamily: 'Piazzolla', + fontStyle: 'normal', + src: 'http://www.wordpress.org/wp-content/uploads/fonts/N0b52SlTPu5rIkWIZjVKKtYtfxYqZ4RJBFzFfYUjkSDdlqZgy7JxwXL31AHfAAy5.woff2', + }, { fontFamily: 'Piazzolla', fontStyle: 'normal', @@ -378,6 +389,10 @@ describe( 'getFontStylesAndWeights', () => { name: 'Regular', value: '400', }, + { + name: 'Semi Bold', + value: '600', + }, { name: 'Black', value: '900', @@ -396,6 +411,14 @@ describe( 'getFontStylesAndWeights', () => { fontWeight: '400', }, }, + { + key: 'normal-600', + name: 'Semi Bold', + style: { + fontStyle: 'normal', + fontWeight: '600', + }, + }, { key: 'normal-900', name: 'Black', @@ -420,6 +443,14 @@ describe( 'getFontStylesAndWeights', () => { fontWeight: '400', }, }, + { + key: 'italic-600', + name: 'Semi Bold Italic', + style: { + fontStyle: 'italic', + fontWeight: '600', + }, + }, { key: 'italic-900', name: 'Black Italic', @@ -510,4 +541,121 @@ describe( 'getFontStylesAndWeights', () => { isVariableFont: false, } ); } ); + + it( 'should return available styles and weights for a font without fontWeight', () => { + const fontFamilyFaces = [ + { + fontFamily: 'AR One Sans', + fontStyle: 'normal', + src: 'http://www.wordpress.org/wp-content/uploads/fonts/AROneSans-VariableFont_ARRRwght.ttf', + }, + ]; + expect( getFontStylesAndWeights( fontFamilyFaces ) ).toEqual( { + fontStyles: [ + { + name: 'Regular', + value: 'normal', + }, + { + name: 'Italic', + value: 'italic', + }, + ], + fontWeights: [ + { + name: 'Bold', + value: '700', + }, + ], + combinedStyleAndWeightOptions: [ + { + key: 'normal-700', + name: 'Bold', + style: { + fontStyle: 'normal', + fontWeight: '700', + }, + }, + { + key: 'italic-700', + name: 'Bold Italic', + style: { + fontStyle: 'italic', + fontWeight: '700', + }, + }, + ], + isSystemFont: false, + isVariableFont: false, + } ); + } ); + + it( 'should return available styles and weights for a font with numeric fontWeight', () => { + const fontFamilyFaces = [ + { + fontFamily: 'AR One Sans', + fontStyle: 'normal', + fontWeight: 400, + src: 'http://www.wordpress.org/wp-content/uploads/fonts/AROneSans-VariableFont_ARRRwght.ttf', + }, + ]; + expect( getFontStylesAndWeights( fontFamilyFaces ) ).toEqual( { + fontStyles: [ + { + name: 'Regular', + value: 'normal', + }, + { + name: 'Italic', + value: 'italic', + }, + ], + fontWeights: [ + { + name: 'Regular', + value: '400', + }, + { + name: 'Bold', + value: '700', + }, + ], + combinedStyleAndWeightOptions: [ + { + key: 'normal-400', + name: 'Regular', + style: { + fontStyle: 'normal', + fontWeight: '400', + }, + }, + { + key: 'normal-700', + name: 'Bold', + style: { + fontStyle: 'normal', + fontWeight: '700', + }, + }, + { + key: 'italic-400', + name: 'Regular Italic', + style: { + fontStyle: 'italic', + fontWeight: '400', + }, + }, + { + key: 'italic-700', + name: 'Bold Italic', + style: { + fontStyle: 'italic', + fontWeight: '700', + }, + }, + ], + isSystemFont: false, + isVariableFont: false, + } ); + } ); } ); diff --git a/packages/block-library/CHANGELOG.md b/packages/block-library/CHANGELOG.md index 319d2b04a3168..4ee3ebc7564b5 100644 --- a/packages/block-library/CHANGELOG.md +++ b/packages/block-library/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 9.7.0 (2024-09-05) + ## 9.6.0 (2024-08-21) ## 9.5.0 (2024-08-07) diff --git a/packages/block-library/package.json b/packages/block-library/package.json index 5b522f01ea778..1353ef24c77d8 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-library", - "version": "9.6.1", + "version": "9.7.0", "description": "Block library for the WordPress editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -30,6 +30,13 @@ "src/**/*.scss", "{src,build,build-module}/*/init.js" ], + "wpScriptModuleExports": { + "./file/view": "./build-module/file/view.js", + "./image/view": "./build-module/image/view.js", + "./navigation/view": "./build-module/navigation/view.js", + "./query/view": "./build-module/query/view.js", + "./search/view": "./build-module/search/view.js" + }, "dependencies": { "@babel/runtime": "^7.16.0", "@wordpress/a11y": "file:../a11y", diff --git a/packages/block-library/src/archives/edit.js b/packages/block-library/src/archives/edit.js index ee9bf60fb77ec..60b8715988ed9 100644 --- a/packages/block-library/src/archives/edit.js +++ b/packages/block-library/src/archives/edit.js @@ -53,7 +53,7 @@ export default function ArchivesEdit( { attributes, setAttributes } ) { { - const { - getBlocks, - getSettings, - getBlockEditingMode: _getBlockEditingMode, - } = select( blockEditorStore ); + const { getBlocks, getSettings, getBlockEditingMode } = + select( blockEditorStore ); const { getBlockBindingsSource } = unlock( select( blocksStore ) ); // For editing link to the site editor if the theme and user permissions support it. return { innerBlocks: getBlocks( patternClientId ), - getBlockEditingMode: _getBlockEditingMode, onNavigateToEntityRecord: getSettings().onNavigateToEntityRecord, - editingMode: _getBlockEditingMode( patternClientId ), + editingMode: getBlockEditingMode( patternClientId ), hasPatternOverridesSource: !! getBlockBindingsSource( 'core/pattern-overrides' ), @@ -247,14 +244,15 @@ function ReusableBlockEdit( { ), } ); - // Use `blocks` variable until `innerBlocks` is populated, which has the proper clientIds. const innerBlocksProps = useInnerBlocksProps( blockProps, { templateLock: 'all', layout, - value: innerBlocks.length > 0 ? innerBlocks : blocks, + value: blocks, onInput: NOOP, onChange: NOOP, - renderAppender: blocks?.length ? undefined : blocks.ButtonBlockAppender, + renderAppender: blocks?.length + ? undefined + : InnerBlocks.ButtonBlockAppender, } ); const handleEditOriginal = () => { @@ -292,7 +290,7 @@ function ReusableBlockEdit( { return ( <> - { hasResolved && ( + { hasResolved && ! isMissing && ( context['enhancedPagination'] ) ) { + $p = new WP_HTML_Tag_Processor( $items_markup ); + while ( $p->next_tag( 'a' ) ) { + $p->set_attribute( 'data-wp-on--click', 'core/query::actions.navigate' ); + } + $items_markup = $p->get_updated_html(); + } } $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => "wp-block-categories-{$type}" ) ); diff --git a/packages/block-library/src/comment-edit-link/block.json b/packages/block-library/src/comment-edit-link/block.json index a49f9a23161b8..578b284715c2a 100644 --- a/packages/block-library/src/comment-edit-link/block.json +++ b/packages/block-library/src/comment-edit-link/block.json @@ -30,7 +30,11 @@ }, "spacing": { "margin": true, - "padding": true + "padding": true, + "__experimentalDefaultControls": { + "margin": false, + "padding": false + } }, "typography": { "fontSize": true, @@ -47,6 +51,13 @@ }, "interactivity": { "clientNavigation": true + }, + "__experimentalBorder": { + "radius": true, + "color": true, + "width": true, + "style": true } - } + }, + "style": "wp-block-comment-edit-link" } diff --git a/packages/block-library/src/comment-edit-link/style.scss b/packages/block-library/src/comment-edit-link/style.scss new file mode 100644 index 0000000000000..1ae7daf55009e --- /dev/null +++ b/packages/block-library/src/comment-edit-link/style.scss @@ -0,0 +1,4 @@ +.wp-block-comment-edit-link { + // This block has customizable padding, border-box makes that more predictable. + box-sizing: border-box; +} diff --git a/packages/block-library/src/comment-reply-link/block.json b/packages/block-library/src/comment-reply-link/block.json index c10129412145c..68aa93c3c1526 100644 --- a/packages/block-library/src/comment-reply-link/block.json +++ b/packages/block-library/src/comment-reply-link/block.json @@ -25,7 +25,11 @@ }, "spacing": { "margin": true, - "padding": true + "padding": true, + "__experimentalDefaultControls": { + "margin": false, + "padding": false + } }, "typography": { "fontSize": true, @@ -40,6 +44,13 @@ "fontSize": true } }, + "__experimentalBorder": { + "radius": true, + "color": true, + "width": true, + "style": true + }, "html": false - } + }, + "style": "wp-block-comment-reply-link" } diff --git a/packages/block-library/src/comment-reply-link/style.scss b/packages/block-library/src/comment-reply-link/style.scss new file mode 100644 index 0000000000000..7eca6cee1aa97 --- /dev/null +++ b/packages/block-library/src/comment-reply-link/style.scss @@ -0,0 +1,4 @@ +.wp-block-comment-reply-link { + // This block has customizable padding, border-box makes that more predictable. + box-sizing: border-box; +} diff --git a/packages/block-library/src/comments/edit/comments-legacy.js b/packages/block-library/src/comments/edit/comments-legacy.js index b5a12e34343da..dbe89a4e3a83e 100644 --- a/packages/block-library/src/comments/edit/comments-legacy.js +++ b/packages/block-library/src/comments/edit/comments-legacy.js @@ -29,8 +29,7 @@ export default function CommentsLegacy( { const actions = [ { ' ' } ' - ), - { - button: ( - ' + ), + { + button: ( +

- - - - ); - }, - }, - { - id: 'secondary', - label: 'Secondary action', - callback() {}, - }, -]; - -export const fields = [ - { - label: 'Image', - id: 'image', - header: ( - - - Image - - ), - render: ( { item } ) => { - return ( - - ); - }, - enableSorting: false, - }, - { - label: 'Title', - id: 'title', - enableHiding: false, - enableGlobalSearch: true, - render: ( { item } ) => { - return { item.title }; - }, - }, - { - id: 'date', - label: 'Date', - type: 'datetime', - }, - { - label: 'Type', - id: 'type', - enableHiding: false, - elements: [ - { value: 'Not a planet', label: 'Not a planet' }, - { value: 'Ice giant', label: 'Ice giant' }, - { value: 'Terrestrial', label: 'Terrestrial' }, - { value: 'Gas giant', label: 'Gas giant' }, - ], - }, - { - label: 'Satellites', - id: 'satellites', - type: 'integer', - enableSorting: true, - }, - { - label: 'Description', - id: 'description', - enableSorting: false, - enableGlobalSearch: true, - }, - { - label: 'Categories', - id: 'categories', - header: ( - - - Categories - - ), - elements: [ - { value: 'Space', label: 'Space' }, - { value: 'NASA', label: 'NASA' }, - { value: 'Planet', label: 'Planet' }, - { value: 'Solar system', label: 'Solar system' }, - { value: 'Ice giant', label: 'Ice giant' }, - ], - filterBy: { - operators: [ 'isAny', 'isNone', 'isAll', 'isNotAll' ], - }, - getValue: ( { item } ) => { - return item.categories; - }, - render: ( { item } ) => { - return item.categories.join( ',' ); - }, - enableSorting: false, - }, -]; diff --git a/packages/dataviews/src/components/dataviews/stories/fixtures.tsx b/packages/dataviews/src/components/dataviews/stories/fixtures.tsx new file mode 100644 index 0000000000000..ff098209b3468 --- /dev/null +++ b/packages/dataviews/src/components/dataviews/stories/fixtures.tsx @@ -0,0 +1,698 @@ +/** + * WordPress dependencies + */ +import { trash, image, Icon, category } from '@wordpress/icons'; +import { + Button, + __experimentalText as Text, + __experimentalHStack as HStack, + __experimentalVStack as VStack, +} from '@wordpress/components'; + +/** + * Internal dependencies + */ +import type { Field, Action } from '../../../types'; + +export type Theme = { + slug: string; + name: string; + description: string; + requires: string; + tested: string; + tags: string[]; +}; + +export type SpaceObject = { + id: number; + title: string; + description: string; + image: string; + type: string; + categories: string[]; + satellites: number; + date: string; +}; + +export const data: SpaceObject[] = [ + { + id: 1, + title: 'Apollo', + description: 'Apollo description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + type: 'Not a planet', + categories: [ 'Space', 'NASA' ], + satellites: 0, + date: '2021-01-01T00:00:00Z', + }, + { + id: 2, + title: 'Space', + description: 'Space description', + image: 'https://live.staticflickr.com/5678/21911065441_92e2d44708_b.jpg', + type: 'Not a planet', + categories: [ 'Space' ], + satellites: 0, + date: '2019-01-02T00:00:00Z', + }, + { + id: 3, + title: 'NASA', + description: 'NASA photo', + image: 'https://live.staticflickr.com/742/21712365770_8f70a2c91e_b.jpg', + type: 'Not a planet', + categories: [ 'NASA' ], + satellites: 0, + date: '2025-01-03T00:00:00Z', + }, + { + id: 4, + title: 'Neptune', + description: 'Neptune description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + type: 'Ice giant', + categories: [ 'Space', 'Planet', 'Solar system' ], + satellites: 14, + date: '2020-01-01T00:00:00Z', + }, + { + id: 5, + title: 'Mercury', + description: 'Mercury description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + type: 'Terrestrial', + categories: [ 'Space', 'Planet', 'Solar system' ], + satellites: 0, + date: '2020-01-02T01:00:00Z', + }, + { + id: 6, + title: 'Venus', + description: 'La planète Vénus', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + type: 'Terrestrial', + categories: [ 'Space', 'Planet', 'Solar system' ], + satellites: 0, + date: '2020-01-02T00:00:00Z', + }, + { + id: 7, + title: 'Earth', + description: 'Earth description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + type: 'Terrestrial', + categories: [ 'Space', 'Planet', 'Solar system' ], + satellites: 1, + date: '2023-01-03T00:00:00Z', + }, + { + id: 8, + title: 'Mars', + description: 'Mars description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + type: 'Terrestrial', + categories: [ 'Space', 'Planet', 'Solar system' ], + satellites: 2, + date: '2020-01-01T00:00:00Z', + }, + { + id: 9, + title: 'Jupiter', + description: 'Jupiter description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + type: 'Gas giant', + categories: [ 'Space', 'Planet', 'Solar system' ], + satellites: 95, + date: '2017-01-01T00:01:00Z', + }, + { + id: 10, + title: 'Saturn', + description: 'Saturn description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + type: 'Gas giant', + categories: [ 'Space', 'Planet', 'Solar system' ], + satellites: 146, + date: '2020-02-01T00:02:00Z', + }, + { + id: 11, + title: 'Uranus', + description: 'Uranus description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + type: 'Ice giant', + categories: [ 'Space', 'Ice giant', 'Solar system' ], + satellites: 28, + date: '2020-03-01T00:00:00Z', + }, +]; + +export const themeData: Theme[] = [ + { + slug: 'twentyeleven', + name: 'Twenty Eleven', + description: + 'The 2011 theme for WordPress is sophisticated, lightweight, and adaptable. Make it yours with a custom menu, header image, and background -- then go further with available theme options for light or dark color scheme, custom link colors, and three layout choices. Twenty Eleven comes equipped with a Showcase page template that transforms your front page into a showcase to show off your best content, widget support galore (sidebar, three footer areas, and a Showcase page widget area), and a custom "Ephemera" widget to display your Aside, Link, Quote, or Status posts. Included are styles for print and for the admin editor, support for featured images (as custom header images on posts and pages and as large images on featured "sticky" posts), and special styles for six different post formats.', + requires: '3.2', + tested: '6.6', + tags: [ + 'blog', + 'one-column', + 'two-columns', + 'left-sidebar', + 'right-sidebar', + 'custom-background', + 'custom-colors', + 'custom-header', + 'custom-menu', + 'editor-style', + 'featured-image-header', + 'featured-images', + 'flexible-header', + 'footer-widgets', + 'full-width-template', + 'microformats', + 'post-formats', + 'rtl-language-support', + 'sticky-post', + 'theme-options', + 'translation-ready', + 'block-patterns', + ], + }, + { + slug: 'twentyfifteen', + name: 'Twenty Fifteen', + description: + "Our 2015 default theme is clean, blog-focused, and designed for clarity. Twenty Fifteen's simple, straightforward typography is readable on a wide variety of screen sizes, and suitable for multiple languages. We designed it using a mobile-first approach, meaning your content takes center-stage, regardless of whether your visitors arrive by smartphone, tablet, laptop, or desktop computer.", + requires: '4.1', + tested: '6.6', + tags: [ + 'blog', + 'two-columns', + 'left-sidebar', + 'accessibility-ready', + 'custom-background', + 'custom-colors', + 'custom-header', + 'custom-logo', + 'custom-menu', + 'editor-style', + 'featured-images', + 'microformats', + 'post-formats', + 'rtl-language-support', + 'sticky-post', + 'threaded-comments', + 'translation-ready', + 'block-patterns', + ], + }, + { + slug: 'twentyfourteen', + name: 'Twenty Fourteen', + description: + "In 2014, our default theme lets you create a responsive magazine website with a sleek, modern design. Feature your favorite homepage content in either a grid or a slider. Use the three widget areas to customize your website, and change your content's layout with a full-width page template and a contributor page to show off your authors. Creating a magazine website with WordPress has never been easier.", + requires: '3.6', + tested: '6.6', + tags: [ + 'blog', + 'news', + 'two-columns', + 'three-columns', + 'left-sidebar', + 'right-sidebar', + 'custom-background', + 'custom-header', + 'custom-menu', + 'editor-style', + 'featured-images', + 'flexible-header', + 'footer-widgets', + 'full-width-template', + 'microformats', + 'post-formats', + 'rtl-language-support', + 'sticky-post', + 'theme-options', + 'translation-ready', + 'accessibility-ready', + 'block-patterns', + ], + }, + { + slug: 'twentynineteen', + name: 'Twenty Nineteen', + description: + "Our 2019 default theme is designed to show off the power of the block editor. It features custom styles for all the default blocks, and is built so that what you see in the editor looks like what you'll see on your website. Twenty Nineteen is designed to be adaptable to a wide range of websites, whether you’re running a photo blog, launching a new business, or supporting a non-profit. Featuring ample whitespace and modern sans-serif headlines paired with classic serif body text, it's built to be beautiful on all screen sizes.", + requires: '4.7', + tested: '6.6', + tags: [ + 'one-column', + 'accessibility-ready', + 'custom-colors', + 'custom-menu', + 'custom-logo', + 'editor-style', + 'featured-images', + 'footer-widgets', + 'rtl-language-support', + 'sticky-post', + 'threaded-comments', + 'translation-ready', + 'block-patterns', + ], + }, + { + slug: 'twentyseventeen', + name: 'Twenty Seventeen', + description: + 'Twenty Seventeen brings your site to life with header video and immersive featured images. With a focus on business sites, it features multiple sections on the front page as well as widgets, navigation and social menus, a logo, and more. Personalize its asymmetrical grid with a custom color scheme and showcase your multimedia content with post formats. Our default theme for 2017 works great in many languages, for any abilities, and on any device.', + requires: '4.7', + tested: '6.6', + tags: [ + 'one-column', + 'two-columns', + 'right-sidebar', + 'flexible-header', + 'accessibility-ready', + 'custom-colors', + 'custom-header', + 'custom-menu', + 'custom-logo', + 'editor-style', + 'featured-images', + 'footer-widgets', + 'post-formats', + 'rtl-language-support', + 'sticky-post', + 'theme-options', + 'threaded-comments', + 'translation-ready', + 'block-patterns', + ], + }, + { + slug: 'twentysixteen', + name: 'Twenty Sixteen', + description: + 'Twenty Sixteen is a modernized take on an ever-popular WordPress layout — the horizontal masthead with an optional right sidebar that works perfectly for blogs and websites. It has custom color options with beautiful default color schemes, a harmonious fluid grid using a mobile-first approach, and impeccable polish in every detail. Twenty Sixteen will make your WordPress look beautiful everywhere.', + requires: '4.4', + tested: '6.6', + tags: [ + 'one-column', + 'two-columns', + 'right-sidebar', + 'accessibility-ready', + 'custom-background', + 'custom-colors', + 'custom-header', + 'custom-menu', + 'editor-style', + 'featured-images', + 'flexible-header', + 'microformats', + 'post-formats', + 'rtl-language-support', + 'sticky-post', + 'threaded-comments', + 'translation-ready', + 'blog', + 'block-patterns', + ], + }, + { + slug: 'twentyten', + name: 'Twenty Ten', + description: + 'The 2010 theme for WordPress is stylish, customizable, simple, and readable -- make it yours with a custom menu, header image, and background. Twenty Ten supports six widgetized areas (two in the sidebar, four in the footer) and featured images (thumbnails for gallery posts and custom header images for posts and pages). It includes stylesheets for print and the admin Visual Editor, special styles for posts in the "Asides" and "Gallery" categories, and has an optional one-column page template that removes the sidebar.', + requires: '5.6', + tested: '6.6', + tags: [ + 'blog', + 'two-columns', + 'custom-header', + 'custom-background', + 'threaded-comments', + 'sticky-post', + 'translation-ready', + 'microformats', + 'rtl-language-support', + 'editor-style', + 'custom-menu', + 'flexible-header', + 'featured-images', + 'footer-widgets', + 'featured-image-header', + 'block-patterns', + ], + }, + { + slug: 'twentythirteen', + name: 'Twenty Thirteen', + description: + 'The 2013 theme for WordPress takes us back to the blog, featuring a full range of post formats, each displayed beautifully in their own unique way. Design details abound, starting with a vibrant color scheme and matching header images, beautiful typography and icons, and a flexible layout that looks great on any device, big or small.', + requires: '3.6', + tested: '6.6', + tags: [ + 'blog', + 'one-column', + 'two-columns', + 'right-sidebar', + 'custom-header', + 'custom-menu', + 'editor-style', + 'featured-images', + 'footer-widgets', + 'microformats', + 'post-formats', + 'rtl-language-support', + 'sticky-post', + 'translation-ready', + 'accessibility-ready', + 'block-patterns', + ], + }, + { + slug: 'twentytwelve', + name: 'Twenty Twelve', + description: + 'The 2012 theme for WordPress is a fully responsive theme that looks great on any device. Features include a front page template with its own widgets, an optional display font, styling for post formats on both index and single views, and an optional no-sidebar page template. Make it yours with a custom menu, header image, and background.', + requires: '3.5', + tested: '6.6', + tags: [ + 'blog', + 'one-column', + 'two-columns', + 'right-sidebar', + 'custom-background', + 'custom-header', + 'custom-menu', + 'editor-style', + 'featured-images', + 'flexible-header', + 'footer-widgets', + 'full-width-template', + 'microformats', + 'post-formats', + 'rtl-language-support', + 'sticky-post', + 'theme-options', + 'translation-ready', + 'block-patterns', + ], + }, + { + slug: 'twentytwenty', + name: 'Twenty Twenty', + description: + 'Our default theme for 2020 is designed to take full advantage of the flexibility of the block editor. Organizations and businesses have the ability to create dynamic landing pages with endless layouts using the group and column blocks. The centered content column and fine-tuned typography also makes it perfect for traditional blogs. Complete editor styles give you a good idea of what your content will look like, even before you publish. You can give your site a personal touch by changing the background colors and the accent color in the Customizer. The colors of all elements on your site are automatically calculated based on the colors you pick, ensuring a high, accessible color contrast for your visitors.', + requires: '4.7', + tested: '6.6', + tags: [ + 'blog', + 'one-column', + 'custom-background', + 'custom-colors', + 'custom-logo', + 'custom-menu', + 'editor-style', + 'featured-images', + 'footer-widgets', + 'full-width-template', + 'rtl-language-support', + 'sticky-post', + 'theme-options', + 'threaded-comments', + 'translation-ready', + 'block-patterns', + 'block-styles', + 'wide-blocks', + 'accessibility-ready', + ], + }, + { + slug: 'twentytwentyfour', + name: 'Twenty Twenty-Four', + description: + 'Twenty Twenty-Four is designed to be flexible, versatile and applicable to any website. Its collection of templates and patterns tailor to different needs, such as presenting a business, blogging and writing or showcasing work. A multitude of possibilities open up with just a few adjustments to color and typography. Twenty Twenty-Four comes with style variations and full page designs to help speed up the site building process, is fully compatible with the site editor, and takes advantage of new design tools introduced in WordPress 6.4.', + requires: '6.4', + tested: '6.6', + tags: [ + 'one-column', + 'custom-colors', + 'custom-menu', + 'custom-logo', + 'editor-style', + 'featured-images', + 'full-site-editing', + 'block-patterns', + 'rtl-language-support', + 'sticky-post', + 'threaded-comments', + 'translation-ready', + 'wide-blocks', + 'block-styles', + 'style-variations', + 'accessibility-ready', + 'blog', + 'portfolio', + 'news', + ], + }, + { + slug: 'twentytwentyone', + name: 'Twenty Twenty-One', + description: + 'Twenty Twenty-One is a blank canvas for your ideas and it makes the block editor your best brush. With new block patterns, which allow you to create a beautiful layout in a matter of seconds, this theme’s soft colors and eye-catching — yet timeless — design will let your work shine. Take it for a spin! See how Twenty Twenty-One elevates your portfolio, business website, or personal blog.', + requires: '5.3', + tested: '6.6', + tags: [ + 'one-column', + 'accessibility-ready', + 'custom-colors', + 'custom-menu', + 'custom-logo', + 'editor-style', + 'featured-images', + 'footer-widgets', + 'block-patterns', + 'rtl-language-support', + 'sticky-post', + 'threaded-comments', + 'translation-ready', + 'blog', + 'portfolio', + ], + }, + { + slug: 'twentytwentythree', + name: 'Twenty Twenty-Three', + description: + 'Twenty Twenty-Three is designed to take advantage of the new design tools introduced in WordPress 6.1. With a clean, blank base as a starting point, this default theme includes ten diverse style variations created by members of the WordPress community. Whether you want to build a complex or incredibly simple website, you can do it quickly and intuitively through the bundled styles or dive into creation and full customization yourself.', + requires: '6.1', + tested: '6.6', + tags: [ + 'one-column', + 'custom-colors', + 'custom-menu', + 'custom-logo', + 'editor-style', + 'featured-images', + 'full-site-editing', + 'block-patterns', + 'rtl-language-support', + 'sticky-post', + 'threaded-comments', + 'translation-ready', + 'wide-blocks', + 'block-styles', + 'style-variations', + 'accessibility-ready', + 'blog', + 'portfolio', + 'news', + ], + }, + { + slug: 'twentytwentytwo', + name: 'Twenty Twenty-Two', + description: + 'Built on a solidly designed foundation, Twenty Twenty-Two embraces the idea that everyone deserves a truly unique website. The theme’s subtle styles are inspired by the diversity and versatility of birds: its typography is lightweight yet strong, its color palette is drawn from nature, and its layout elements sit gently on the page. The true richness of Twenty Twenty-Two lies in its opportunity for customization. The theme is built to take advantage of the Site Editor features introduced in WordPress 5.9, which means that colors, typography, and the layout of every single page on your site can be customized to suit your vision. It also includes dozens of block patterns, opening the door to a wide range of professionally designed layouts in just a few clicks. Whether you’re building a single-page website, a blog, a business website, or a portfolio, Twenty Twenty-Two will help you create a site that is uniquely yours.', + requires: '5.9', + tested: '6.6', + tags: [ + 'one-column', + 'custom-colors', + 'custom-menu', + 'custom-logo', + 'editor-style', + 'featured-images', + 'full-site-editing', + 'block-patterns', + 'rtl-language-support', + 'sticky-post', + 'threaded-comments', + 'style-variations', + 'wide-blocks', + 'block-styles', + 'accessibility-ready', + 'blog', + 'portfolio', + 'news', + ], + }, +]; + +export const themeFields: Field< Theme >[] = [ + { id: 'slug', label: 'Slug' }, + { id: 'name', label: 'Name' }, + { + id: 'description', + label: 'Description', + render: ( { item } ) => ( + + { item.description } + + ), + }, + { id: 'requires', label: 'Requires at least' }, + { id: 'tested', label: 'Tested up to' }, + { + id: 'tags', + label: 'Tags', + render: ( { item } ) => item.tags.join( ', ' ), + }, +]; + +export const DEFAULT_VIEW = { + type: 'table' as const, + search: '', + page: 1, + perPage: 10, + layout: {}, + filters: [], +}; + +export const actions: Action< SpaceObject >[] = [ + { + id: 'delete', + label: 'Delete item', + isPrimary: true, + icon: trash, + hideModalHeader: true, + RenderModal: ( { items, closeModal } ) => { + return ( + + + { `Are you sure you want to delete "${ items[ 0 ].title }"?` } + + + + + + + ); + }, + }, + { + id: 'secondary', + label: 'Secondary action', + callback() {}, + }, +]; + +export const fields: Field< SpaceObject >[] = [ + { + label: 'Image', + id: 'image', + header: ( + + + Image + + ), + render: ( { item } ) => { + return ( + + ); + }, + enableSorting: false, + }, + { + label: 'Title', + id: 'title', + enableHiding: false, + enableGlobalSearch: true, + render: ( { item } ) => { + return { item.title }; + }, + }, + { + id: 'date', + label: 'Date', + type: 'datetime', + }, + { + label: 'Type', + id: 'type', + enableHiding: false, + elements: [ + { value: 'Not a planet', label: 'Not a planet' }, + { value: 'Ice giant', label: 'Ice giant' }, + { value: 'Terrestrial', label: 'Terrestrial' }, + { value: 'Gas giant', label: 'Gas giant' }, + ], + }, + { + label: 'Satellites', + id: 'satellites', + type: 'integer', + enableSorting: true, + }, + { + label: 'Description', + id: 'description', + enableSorting: false, + enableGlobalSearch: true, + }, + { + label: 'Categories', + id: 'categories', + header: ( + + + Categories + + ), + elements: [ + { value: 'Space', label: 'Space' }, + { value: 'NASA', label: 'NASA' }, + { value: 'Planet', label: 'Planet' }, + { value: 'Solar system', label: 'Solar system' }, + { value: 'Ice giant', label: 'Ice giant' }, + ], + filterBy: { + operators: [ 'isAny', 'isNone', 'isAll', 'isNotAll' ], + }, + getValue: ( { item } ) => { + return item.categories; + }, + render: ( { item } ) => { + return item.categories.join( ',' ); + }, + enableSorting: false, + }, +]; diff --git a/packages/dataviews/src/components/dataviews/stories/index.story.js b/packages/dataviews/src/components/dataviews/stories/index.story.js deleted file mode 100644 index 75fb0786ecfee..0000000000000 --- a/packages/dataviews/src/components/dataviews/stories/index.story.js +++ /dev/null @@ -1,111 +0,0 @@ -/** - * WordPress dependencies - */ -import { useState, useMemo } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import DataViews from '../index'; -import { DEFAULT_VIEW, actions, data, fields } from './fixtures'; -import { LAYOUT_GRID, LAYOUT_LIST, LAYOUT_TABLE } from '../../../constants'; -import { filterSortAndPaginate } from '../../../filter-and-sort-data-view'; - -const meta = { - title: 'DataViews/DataViews', - component: DataViews, -}; -export default meta; - -export const Default = ( props ) => { - const [ view, setView ] = useState( DEFAULT_VIEW ); - const { data: shownData, paginationInfo } = useMemo( () => { - return filterSortAndPaginate( data, view, fields ); - }, [ view ] ); - return ( - - ); -}; - -export const Empty = ( props ) => { - const [ view, setView ] = useState( DEFAULT_VIEW ); - - return ( - - ); -}; - -export const FieldsNoSortableNoHidable = ( props ) => { - const [ view, setView ] = useState( DEFAULT_VIEW ); - const { data: shownData, paginationInfo } = useMemo( () => { - return filterSortAndPaginate( data, view, fields ); - }, [ view ] ); - - const _fields = fields.map( ( field ) => ( { - ...field, - enableSorting: false, - enableHiding: false, - } ) ); - - return ( - - ); -}; - -Default.args = { - actions, - defaultLayouts: { - [ LAYOUT_TABLE ]: { - layout: { - primaryField: 'title', - styles: { - image: { - width: 50, - }, - title: { - maxWidth: 400, - }, - type: { - maxWidth: 400, - }, - description: { - maxWidth: 200, - }, - }, - }, - }, - [ LAYOUT_GRID ]: { - layout: { - mediaField: 'image', - primaryField: 'title', - }, - }, - [ LAYOUT_LIST ]: { - layout: { - mediaField: 'image', - primaryField: 'title', - }, - }, - }, -}; diff --git a/packages/dataviews/src/components/dataviews/stories/index.story.tsx b/packages/dataviews/src/components/dataviews/stories/index.story.tsx new file mode 100644 index 0000000000000..3b3e1326115b0 --- /dev/null +++ b/packages/dataviews/src/components/dataviews/stories/index.story.tsx @@ -0,0 +1,186 @@ +/** + * WordPress dependencies + */ +import { useState, useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import DataViews from '../index'; +import { + DEFAULT_VIEW, + actions, + data, + fields, + themeData, + themeFields, +} from './fixtures'; +import { LAYOUT_GRID, LAYOUT_LIST, LAYOUT_TABLE } from '../../../constants'; +import { filterSortAndPaginate } from '../../../filter-and-sort-data-view'; +import type { CombinedField, View } from '../../../types'; + +import './style.css'; + +const meta = { + title: 'DataViews/DataViews', + component: DataViews, +}; +export default meta; + +const defaultLayouts = { + [ LAYOUT_TABLE ]: { + layout: { + primaryField: 'title', + styles: { + image: { + width: 50, + }, + title: { + maxWidth: 400, + }, + type: { + maxWidth: 400, + }, + description: { + maxWidth: 200, + }, + }, + }, + }, + [ LAYOUT_GRID ]: { + layout: { + mediaField: 'image', + primaryField: 'title', + }, + }, + [ LAYOUT_LIST ]: { + layout: { + mediaField: 'image', + primaryField: 'title', + }, + }, +}; + +export const Default = () => { + const [ view, setView ] = useState< View >( { + ...DEFAULT_VIEW, + fields: [ 'title', 'description', 'categories' ], + } ); + const { data: shownData, paginationInfo } = useMemo( () => { + return filterSortAndPaginate( data, view, fields ); + }, [ view ] ); + return ( + item.id.toString() } + paginationInfo={ paginationInfo } + data={ shownData } + view={ view } + fields={ fields } + onChangeView={ setView } + actions={ actions } + defaultLayouts={ defaultLayouts } + /> + ); +}; + +export const Empty = () => { + const [ view, setView ] = useState< View >( { + ...DEFAULT_VIEW, + fields: [ 'title', 'description', 'categories' ], + } ); + + return ( + item.id.toString() } + paginationInfo={ { totalItems: 0, totalPages: 0 } } + data={ [] } + view={ view } + fields={ fields } + onChangeView={ setView } + actions={ actions } + defaultLayouts={ defaultLayouts } + /> + ); +}; + +export const FieldsNoSortableNoHidable = () => { + const [ view, setView ] = useState< View >( { + ...DEFAULT_VIEW, + fields: [ 'title', 'description', 'categories' ], + } ); + const { data: shownData, paginationInfo } = useMemo( () => { + return filterSortAndPaginate( data, view, fields ); + }, [ view ] ); + + const _fields = fields.map( ( field ) => ( { + ...field, + enableSorting: false, + enableHiding: false, + } ) ); + + return ( + item.id.toString() } + paginationInfo={ paginationInfo } + data={ shownData } + view={ view } + fields={ _fields } + onChangeView={ setView } + defaultLayouts={ { + table: {}, + } } + /> + ); +}; + +export const CombinedFields = () => { + const defaultLayoutsThemes = { + table: { + fields: [ 'theme', 'requires', 'tested' ], + layout: { + primaryField: 'name', + combinedFields: [ + { + id: 'theme', + label: 'Theme', + children: [ 'name', 'description' ], + direction: 'vertical', + }, + ] as CombinedField[], + styles: { + theme: { + maxWidth: 300, + }, + }, + }, + }, + grid: { + fields: [ 'description', 'requires', 'tested' ], + layout: { primaryField: 'name', columnFields: [ 'description' ] }, + }, + list: { + fields: [ 'requires', 'tested' ], + layout: { primaryField: 'name' }, + }, + }; + const [ view, setView ] = useState< View >( { + ...DEFAULT_VIEW, + fields: defaultLayoutsThemes.table.fields, + layout: defaultLayoutsThemes.table.layout, + } ); + const { data: shownData, paginationInfo } = useMemo( () => { + return filterSortAndPaginate( themeData, view, themeFields ); + }, [ view ] ); + + return ( + item.name } + paginationInfo={ paginationInfo } + data={ shownData } + view={ view } + fields={ themeFields } + onChangeView={ setView } + defaultLayouts={ defaultLayoutsThemes } + /> + ); +}; diff --git a/packages/dataviews/src/components/dataviews/stories/style.css b/packages/dataviews/src/components/dataviews/stories/style.css new file mode 100644 index 0000000000000..7c0c6565a6edf --- /dev/null +++ b/packages/dataviews/src/components/dataviews/stories/style.css @@ -0,0 +1,4 @@ +.theme-field-description { + text-wrap: balance; + text-wrap: pretty; +} \ No newline at end of file diff --git a/packages/dataviews/src/dataviews-layouts/grid/style.scss b/packages/dataviews/src/dataviews-layouts/grid/style.scss index d154d2b614def..5fab362b0b47b 100644 --- a/packages/dataviews/src/dataviews-layouts/grid/style.scss +++ b/packages/dataviews/src/dataviews-layouts/grid/style.scss @@ -118,7 +118,7 @@ background: $gray-100; padding: 0 $grid-unit-10; min-height: $grid-unit-30; - border-radius: $radius-block-ui; + border-radius: $radius-small; display: flex; align-items: center; font-size: 12px; diff --git a/packages/dataviews/src/dataviews-layouts/index.ts b/packages/dataviews/src/dataviews-layouts/index.ts index 9c96475777c00..eece17d0f4f10 100644 --- a/packages/dataviews/src/dataviews-layouts/index.ts +++ b/packages/dataviews/src/dataviews-layouts/index.ts @@ -16,7 +16,7 @@ import ViewTable from './table'; import ViewGrid from './grid'; import ViewList from './list'; import { LAYOUT_GRID, LAYOUT_LIST, LAYOUT_TABLE } from '../constants'; -import type { View } from '../types'; +import type { View, Field } from '../types'; export const VIEW_LAYOUTS = [ { @@ -39,7 +39,7 @@ export const VIEW_LAYOUTS = [ }, ]; -export function getMandatoryFields( view: View ): string[] { +export function getNotHidableFieldIds( view: View ): string[] { if ( view.type === 'table' ) { return [ view.layout?.primaryField ] .concat( @@ -64,3 +64,64 @@ export function getMandatoryFields( view: View ): string[] { return []; } + +function getCombinedFieldIds( view: View ): string[] { + const combinedFields: string[] = []; + if ( view.type === LAYOUT_TABLE && view.layout?.combinedFields ) { + view.layout.combinedFields.forEach( ( combination ) => { + combinedFields.push( ...combination.children ); + } ); + } + return combinedFields; +} + +export function getVisibleFieldIds( + view: View, + fields: Field< any >[] +): string[] { + const fieldsToExclude = getCombinedFieldIds( view ); + + if ( view.fields ) { + return view.fields.filter( ( id ) => ! fieldsToExclude.includes( id ) ); + } + + const visibleFields = []; + if ( view.type === LAYOUT_TABLE && view.layout?.combinedFields ) { + visibleFields.push( + ...view.layout.combinedFields.map( ( { id } ) => id ) + ); + } + visibleFields.push( + ...fields + .filter( ( { id } ) => ! fieldsToExclude.includes( id ) ) + .map( ( { id } ) => id ) + ); + + return visibleFields; +} + +export function getHiddenFieldIds( + view: View, + fields: Field< any >[] +): string[] { + const fieldsToExclude = [ + ...getCombinedFieldIds( view ), + ...getVisibleFieldIds( view, fields ), + ]; + + // The media field does not need to be in the view.fields to be displayed. + if ( view.type === LAYOUT_GRID && view.layout?.mediaField ) { + fieldsToExclude.push( view.layout?.mediaField ); + } + + if ( view.type === LAYOUT_LIST && view.layout?.mediaField ) { + fieldsToExclude.push( view.layout?.mediaField ); + } + + return fields + .filter( + ( { id, enableHiding } ) => + ! fieldsToExclude.includes( id ) && enableHiding + ) + .map( ( { id } ) => id ); +} diff --git a/packages/dataviews/src/dataviews-layouts/list/index.tsx b/packages/dataviews/src/dataviews-layouts/list/index.tsx index d8889f25b24e9..fb46521fe217b 100644 --- a/packages/dataviews/src/dataviews-layouts/list/index.tsx +++ b/packages/dataviews/src/dataviews-layouts/list/index.tsx @@ -2,17 +2,11 @@ * External dependencies */ import clsx from 'clsx'; -// TODO: use the @wordpress/components one once public -// eslint-disable-next-line no-restricted-imports -import { useStoreState } from '@ariakit/react'; -// Import CompositeStore type, which is not exported from @wordpress/components. -// eslint-disable-next-line no-restricted-imports -import type { CompositeStore } from '@ariakit/react'; /** * WordPress dependencies */ -import { useInstanceId } from '@wordpress/compose'; +import { useInstanceId, usePrevious } from '@wordpress/compose'; import { __experimentalHStack as HStack, __experimentalVStack as VStack, @@ -20,6 +14,7 @@ import { privateApis as componentsPrivateApis, Spinner, VisuallyHidden, + Composite, } from '@wordpress/components'; import { useCallback, @@ -44,39 +39,110 @@ import type { Action, NormalizedField, ViewListProps } from '../../types'; interface ListViewItemProps< Item > { actions: Action< Item >[]; - id?: string; + idPrefix: string; isSelected: boolean; item: Item; mediaField?: NormalizedField< Item >; onSelect: ( item: Item ) => void; primaryField?: NormalizedField< Item >; - store: CompositeStore; visibleFields: NormalizedField< Item >[]; + onDropdownTriggerKeyDown: React.KeyboardEventHandler< HTMLButtonElement >; } -const { - useCompositeStoreV2: useCompositeStore, - CompositeV2: Composite, - CompositeItemV2: CompositeItem, - CompositeRowV2: CompositeRow, - DropdownMenuV2: DropdownMenu, -} = unlock( componentsPrivateApis ); +const { DropdownMenuV2: DropdownMenu } = unlock( componentsPrivateApis ); + +function generateItemWrapperCompositeId( idPrefix: string ) { + return `${ idPrefix }-item-wrapper`; +} +function generatePrimaryActionCompositeId( + idPrefix: string, + primaryActionId: string +) { + return `${ idPrefix }-primary-action-${ primaryActionId }`; +} +function generateDropdownTriggerCompositeId( idPrefix: string ) { + return `${ idPrefix }-dropdown`; +} + +function PrimaryActionGridCell< Item >( { + idPrefix, + primaryAction, + item, +}: { + idPrefix: string; + primaryAction: Action< Item >; + item: Item; +} ) { + const registry = useRegistry(); + const [ isModalOpen, setIsModalOpen ] = useState( false ); + + const compositeItemId = generatePrimaryActionCompositeId( + idPrefix, + primaryAction.id + ); + + const label = + typeof primaryAction.label === 'string' + ? primaryAction.label + : primaryAction.label( [ item ] ); + + return 'RenderModal' in primaryAction ? ( +
+ setIsModalOpen( true ) } + /> + } + > + { isModalOpen && ( + + action={ primaryAction } + items={ [ item ] } + closeModal={ () => setIsModalOpen( false ) } + /> + ) } + +
+ ) : ( +
+ { + primaryAction.callback( [ item ], { registry } ); + } } + /> + } + /> +
+ ); +} function ListItem< Item >( { actions, - id, + idPrefix, isSelected, item, mediaField, onSelect, primaryField, - store, visibleFields, + onDropdownTriggerKeyDown, }: ListViewItemProps< Item > ) { - const registry = useRegistry(); - const itemRef = useRef< HTMLElement >( null ); - const labelId = `${ id }-label`; - const descriptionId = `${ id }-description`; + const itemRef = useRef< HTMLDivElement >( null ); + const labelId = `${ idPrefix }-label`; + const descriptionId = `${ idPrefix }-description`; const [ isHovered, setIsHovered ] = useState( false ); const handleMouseEnter = () => { @@ -111,13 +177,6 @@ function ListItem< Item >( { }; }, [ actions, item ] ); - const [ isModalOpen, setIsModalOpen ] = useState( false ); - const primaryActionLabel = - primaryAction && - ( typeof primaryAction.label === 'string' - ? primaryAction.label - : primaryAction.label( [ item ] ) ); - const renderedMediaField = mediaField?.render ? ( ) : ( @@ -129,7 +188,7 @@ function ListItem< Item >( { ) : null; return ( - } role="row" @@ -146,11 +205,10 @@ function ListItem< Item >( { spacing={ 0 } >
- } role="button" - id={ id } + id={ generateItemWrapperCompositeId( idPrefix ) } aria-pressed={ isSelected } aria-labelledby={ labelId } aria-describedby={ descriptionId } @@ -198,7 +256,7 @@ function ListItem< Item >( {
- + { eligibleActions?.length > 0 && ( ( { width: 'auto', } } > - { primaryAction && 'RenderModal' in primaryAction && ( -
- - setIsModalOpen( true ) - } - /> - } - > - { isModalOpen && ( - - action={ primaryAction } - items={ [ item ] } - closeModal={ () => - setIsModalOpen( false ) - } - /> - ) } - -
+ { primaryAction && ( + ) } - { primaryAction && - ! ( 'RenderModal' in primaryAction ) && ( -
- { - primaryAction.callback( - [ item ], - { registry } - ); - } } - /> - } - /> -
- ) }
( { label={ __( 'Actions' ) } accessibleWhenDisabled disabled={ ! actions.length } - onKeyDown={ ( event: { - key: string; - preventDefault: () => void; - } ) => { - if ( - event.key === - 'ArrowDown' - ) { - // Prevent the default behaviour (open dropdown menu) and go down. - event.preventDefault(); - store.move( - store.down() - ); - } - if ( - event.key === 'ArrowUp' - ) { - // Prevent the default behavior (open dropdown menu) and go up. - event.preventDefault(); - store.move( - store.up() - ); - } - } } + onKeyDown={ + onDropdownTriggerKeyDown + } /> } /> @@ -315,7 +307,7 @@ function ListItem< Item >( { ) } - + ); } @@ -331,6 +323,7 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) { view, } = props; const baseId = useInstanceId( ViewList, 'view-list' ); + const selectedItem = data?.findLast( ( item ) => selection.includes( getItemId( item ) ) ); @@ -353,34 +346,111 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) { const onSelect = ( item: Item ) => onChangeSelection( [ getItemId( item ) ] ); - const getItemDomId = useCallback( - ( item?: Item ) => - item ? `${ baseId }-${ getItemId( item ) }` : undefined, + const generateCompositeItemIdPrefix = useCallback( + ( item: Item ) => `${ baseId }-${ getItemId( item ) }`, [ baseId, getItemId ] ); - const store = useCompositeStore( { - defaultActiveId: getItemDomId( selectedItem ), - } ) as CompositeStore; // TODO, remove once composite APIs are public - - // Manage focused item, when the active one is removed from the list. - const isActiveIdInList = useStoreState( - store, - ( state: { items: any[]; activeId: any } ) => - state.items.some( - ( item: { id: any } ) => item.id === state.activeId - ) + const isActiveCompositeItem = useCallback( + ( item: Item, idToCheck: string ) => { + // All composite items use the same prefix in their IDs. + return idToCheck.startsWith( + generateCompositeItemIdPrefix( item ) + ); + }, + [ generateCompositeItemIdPrefix ] ); + + // Controlled state for the active composite item. + const [ activeCompositeId, setActiveCompositeId ] = useState< + string | null | undefined + >( undefined ); + + // Update the active composite item when the selected item changes. useEffect( () => { - if ( ! isActiveIdInList ) { - // Prefer going down, except if there is no item below (last item), then go up (last item in list). - if ( store.down() ) { - store.move( store.down() ); - } else if ( store.up() ) { - store.move( store.up() ); + if ( selectedItem ) { + setActiveCompositeId( + generateItemWrapperCompositeId( + generateCompositeItemIdPrefix( selectedItem ) + ) + ); + } + }, [ selectedItem, generateCompositeItemIdPrefix ] ); + + const activeItemIndex = data.findIndex( ( item ) => + isActiveCompositeItem( item, activeCompositeId ?? '' ) + ); + const previousActiveItemIndex = usePrevious( activeItemIndex ); + const isActiveIdInList = activeItemIndex !== -1; + + const selectCompositeItem = useCallback( + ( + targetIndex: number, + // Allows invokers to specify a custom function to generate the + // target composite item ID + generateCompositeId: ( idPrefix: string ) => string + ) => { + // Clamping between 0 and data.length - 1 to avoid out of bounds. + const clampedIndex = Math.min( + data.length - 1, + Math.max( 0, targetIndex ) + ); + if ( ! data[ clampedIndex ] ) { + return; } + const itemIdPrefix = generateCompositeItemIdPrefix( + data[ clampedIndex ] + ); + const targetCompositeItemId = generateCompositeId( itemIdPrefix ); + + setActiveCompositeId( targetCompositeItemId ); + document.getElementById( targetCompositeItemId )?.focus(); + }, + [ data, generateCompositeItemIdPrefix ] + ); + + // Select a new active composite item when the current active item + // is removed from the list. + useEffect( () => { + const wasActiveIdInList = + previousActiveItemIndex !== undefined && + previousActiveItemIndex !== -1; + if ( ! isActiveIdInList && wasActiveIdInList ) { + // By picking `previousActiveItemIndex` as the next item index, we are + // basically picking the item that would have been after the deleted one. + // If the previously active (and removed) item was the last of the list, + // we will select the item before it — which is the new last item. + selectCompositeItem( + previousActiveItemIndex, + generateItemWrapperCompositeId + ); } - }, [ isActiveIdInList ] ); + }, [ isActiveIdInList, selectCompositeItem, previousActiveItemIndex ] ); + + // Prevent the default behavior (open dropdown menu) and instead select the + // dropdown menu trigger on the previous/next row. + // https://github.com/ariakit/ariakit/issues/3768 + const onDropdownTriggerKeyDown = useCallback( + ( event: React.KeyboardEvent< HTMLButtonElement > ) => { + if ( event.key === 'ArrowDown' ) { + // Select the dropdown menu trigger item in the next row. + event.preventDefault(); + selectCompositeItem( + activeItemIndex + 1, + generateDropdownTriggerCompositeId + ); + } + if ( event.key === 'ArrowUp' ) { + // Select the dropdown menu trigger item in the previous row. + event.preventDefault(); + selectCompositeItem( + activeItemIndex - 1, + generateDropdownTriggerCompositeId + ); + } + }, + [ selectCompositeItem, activeItemIndex ] + ); const hasData = data?.length; if ( ! hasData ) { @@ -404,22 +474,23 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) { render={
    } className="dataviews-view-list" role="grid" - store={ store } + activeId={ activeCompositeId } + setActiveId={ setActiveCompositeId } > { data.map( ( item ) => { - const id = getItemDomId( item ); + const id = generateCompositeItemIdPrefix( item ); return ( ); } ) } diff --git a/packages/dataviews/src/dataviews-layouts/list/style.scss b/packages/dataviews/src/dataviews-layouts/list/style.scss index 7344af6c3d1e8..ea3236f6d75e1 100644 --- a/packages/dataviews/src/dataviews-layouts/list/style.scss +++ b/packages/dataviews/src/dataviews-layouts/list/style.scss @@ -114,12 +114,12 @@ ul.dataviews-view-list { &::before { position: absolute; content: ""; - top: calc(var(--wp-admin-border-width-focus) + 1px); + top: var(--wp-admin-border-width-focus); right: var(--wp-admin-border-width-focus); bottom: var(--wp-admin-border-width-focus); left: var(--wp-admin-border-width-focus); box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color); - border-radius: $radius-block-ui; + border-radius: $radius-small; } } .dataviews-view-list__primary-field { diff --git a/packages/dataviews/src/dataviews-layouts/table/column-header-menu.tsx b/packages/dataviews/src/dataviews-layouts/table/column-header-menu.tsx index b019cbae36ab3..aff211fb613dc 100644 --- a/packages/dataviews/src/dataviews-layouts/table/column-header-menu.tsx +++ b/packages/dataviews/src/dataviews-layouts/table/column-header-menu.tsx @@ -25,7 +25,9 @@ import type { NormalizedField, SortDirection, ViewTable as ViewTableType, + Operator, } from '../../types'; +import { getVisibleFieldIds } from '../index'; const { DropdownMenuV2 } = unlock( componentsPrivateApis ); @@ -60,30 +62,43 @@ const _HeaderMenu = forwardRef( function HeaderMenu< Item >( }: HeaderMenuProps< Item >, ref: Ref< HTMLButtonElement > ) { + const visibleFieldIds = getVisibleFieldIds( view, fields ); + const index = visibleFieldIds?.indexOf( fieldId ) as number; + const isSorted = view.sort?.field === fieldId; + let isHidable = false; + let isSortable = false; + let canAddFilter = false; + let header; + let operators: Operator[] = []; + const combinedField = view.layout?.combinedFields?.find( ( f ) => f.id === fieldId ); - const index = view.fields?.indexOf( fieldId ) as number; - if ( !! combinedField ) { - return combinedField.header || combinedField.label; - } const field = fields.find( ( f ) => f.id === fieldId ); - if ( ! field ) { - return null; + + if ( ! combinedField ) { + if ( ! field ) { + // No combined or regular field found. + return null; + } + + isHidable = field.enableHiding !== false; + isSortable = field.enableSorting !== false; + header = field.header; + + operators = sanitizeOperators( field ); + // Filter can be added: + // 1. If the field is not already part of a view's filters. + // 2. If the field meets the type and operator requirements. + // 3. If it's not primary. If it is, it should be already visible. + canAddFilter = + ! view.filters?.some( ( _filter ) => fieldId === _filter.field ) && + !! field.elements?.length && + !! operators.length && + ! field.filterBy?.isPrimary; + } else { + header = combinedField.header || combinedField.label; } - const isHidable = field.enableHiding !== false; - const isSortable = field.enableSorting !== false; - const isSorted = view.sort?.field === field.id; - const operators = sanitizeOperators( field ); - // Filter can be added: - // 1. If the field is not already part of a view's filters. - // 2. If the field meets the type and operator requirements. - // 3. If it's not primary. If it is, it should be already visible. - const canAddFilter = - ! view.filters?.some( ( _filter ) => field.id === _filter.field ) && - !! field.elements?.length && - !! operators.length && - ! field.filterBy?.isPrimary; return ( ( ref={ ref } variant="tertiary" > - { field.header } + { header } { view.sort && isSorted && (
); diff --git a/packages/edit-site/src/components/style-book/style.scss b/packages/edit-site/src/components/style-book/style.scss index 3b2c6ab0867db..ab66ec288da31 100644 --- a/packages/edit-site/src/components/style-book/style.scss +++ b/packages/edit-site/src/components/style-book/style.scss @@ -3,13 +3,13 @@ // This is useful when the style book is used to fill a frame. height: 100%; &.is-button { - border-radius: $radius-block-ui * 4; + border-radius: $radius-large; } } .edit-site-style-book__iframe { &.is-button { - border-radius: $radius-block-ui * 4; + border-radius: $radius-large; } &.is-focused { outline: calc(2 * var(--wp-admin-border-width-focus)) solid var(--wp-admin-theme-color); diff --git a/packages/edit-site/src/components/welcome-guide/template.js b/packages/edit-site/src/components/welcome-guide/template.js index 0e699e6b4b242..e6568a23bb3a3 100644 --- a/packages/edit-site/src/components/welcome-guide/template.js +++ b/packages/edit-site/src/components/welcome-guide/template.js @@ -10,29 +10,23 @@ import { store as editorStore } from '@wordpress/editor'; /** * Internal dependencies */ -import { store as editSiteStore } from '../../store'; +import useEditedEntityRecord from '../use-edited-entity-record'; export default function WelcomeGuideTemplate() { const { toggle } = useDispatch( preferencesStore ); - const isVisible = useSelect( ( select ) => { - const isTemplateActive = !! select( preferencesStore ).get( - 'core/edit-site', - 'welcomeGuideTemplate' - ); - const isEditorActive = !! select( preferencesStore ).get( - 'core/edit-site', - 'welcomeGuide' - ); - const { isPage } = select( editSiteStore ); - const { getCurrentPostType } = select( editorStore ); - return ( - isTemplateActive && - ! isEditorActive && - isPage() && - getCurrentPostType() === 'wp_template' - ); + const { isLoaded, record } = useEditedEntityRecord(); + const isPostTypeTemplate = isLoaded && record.type === 'wp_template'; + const { isActive, hasPreviousEntity } = useSelect( ( select ) => { + const { getEditorSettings } = select( editorStore ); + const { get } = select( preferencesStore ); + return { + isActive: get( 'core/edit-site', 'welcomeGuideTemplate' ), + hasPreviousEntity: + !! getEditorSettings().onNavigateToPreviousEntityRecord, + }; }, [] ); + const isVisible = isActive && isPostTypeTemplate && hasPreviousEntity; if ( ! isVisible ) { return null; diff --git a/packages/edit-site/src/index.js b/packages/edit-site/src/index.js index 9face28c1bfe1..1aceecc4d8b1f 100644 --- a/packages/edit-site/src/index.js +++ b/packages/edit-site/src/index.js @@ -79,8 +79,16 @@ export function initializeEditor( id, settings ) { openPanels: [ 'post-status' ], showBlockBreadcrumbs: true, showListViewByDefault: false, + enableChoosePatternModal: true, } ); + if ( window.__experimentalMediaProcessing ) { + dispatch( preferencesStore ).setDefaults( 'core/media', { + requireApproval: true, + optimizeOnUpload: true, + } ); + } + dispatch( editSiteStore ).updateSettings( settings ); // Keep the defaultTemplateTypes in the core/editor settings too, diff --git a/packages/edit-site/src/posts.js b/packages/edit-site/src/posts.js index 9e2582ac23328..78d823b56c4c1 100644 --- a/packages/edit-site/src/posts.js +++ b/packages/edit-site/src/posts.js @@ -72,6 +72,7 @@ export function initializePostsDashboard( id, settings ) { openPanels: [ 'post-status' ], showBlockBreadcrumbs: true, showListViewByDefault: false, + enableChoosePatternModal: true, } ); dispatch( editSiteStore ).updateSettings( settings ); diff --git a/packages/edit-widgets/CHANGELOG.md b/packages/edit-widgets/CHANGELOG.md index eb185d530887d..f1cbcef0667d7 100644 --- a/packages/edit-widgets/CHANGELOG.md +++ b/packages/edit-widgets/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.7.0 (2024-09-05) + ## 6.6.0 (2024-08-21) ## 6.5.0 (2024-08-07) diff --git a/packages/edit-widgets/package.json b/packages/edit-widgets/package.json index ed48d07a1d1e5..d24857f0f8a0c 100644 --- a/packages/edit-widgets/package.json +++ b/packages/edit-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-widgets", - "version": "6.6.1", + "version": "6.7.0", "description": "Widgets Page module for WordPress..", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-widgets/src/components/header/index.js b/packages/edit-widgets/src/components/header/index.js index 0aadec83d5d2f..80dda479d59ed 100644 --- a/packages/edit-widgets/src/components/header/index.js +++ b/packages/edit-widgets/src/components/header/index.js @@ -61,8 +61,8 @@ function Header() { ) }
- +
diff --git a/packages/editor/CHANGELOG.md b/packages/editor/CHANGELOG.md index 05bb9beb3b1fc..b380c2fd296d5 100644 --- a/packages/editor/CHANGELOG.md +++ b/packages/editor/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 14.7.0 (2024-09-05) + ## 14.6.0 (2024-08-21) ## 14.5.0 (2024-08-07) diff --git a/packages/editor/README.md b/packages/editor/README.md index 89ea15ef37849..d18513b151bea 100644 --- a/packages/editor/README.md +++ b/packages/editor/README.md @@ -862,6 +862,43 @@ _Returns_ - `Component`: The component to be rendered. +### PluginPreviewMenuItem + +Renders a menu item in the Preview dropdown, which can be used as a button or link depending on the props provided. The text within the component appears as the menu item label. + +_Usage_ + +```jsx +import { __ } from '@wordpress/i18n'; +import { PluginPreviewMenuItem } from '@wordpress/editor'; +import { external } from '@wordpress/icons'; + +function onPreviewClick() { + // Handle preview action +} + +const ExternalPreviewMenuItem = () => ( + + { __( 'Preview in new tab' ) } + +); +registerPlugin( 'external-preview-menu-item', { + render: ExternalPreviewMenuItem, +} ); +``` + +_Parameters_ + +- _props_ `Object`: Component properties. +- _props.href_ `[string]`: When `href` is provided, the menu item is rendered as an anchor instead of a button. It corresponds to the `href` attribute of the anchor. +- _props.icon_ `[WPBlockTypeIconRender]`: The icon to be rendered to the left of the menu item label. Can be a Dashicon slug or an SVG WP element. +- _props.onClick_ `[Function]`: The callback function to be executed when the user clicks the menu item. +- _props.other_ `[...*]`: Any additional props are passed through to the underlying MenuItem component. + +_Returns_ + +- `Component`: The rendered menu item component. + ### PluginSidebar Renders a sidebar when activated. The contents within the `PluginSidebar` will appear as content within the sidebar. It also automatically renders a corresponding `PluginSidebarMenuItem` component when `isPinnable` flag is set to `true`. If you wish to display the sidebar, you can with use the `PluginSidebarMoreMenuItem` component or the `wp.data.dispatch` API: @@ -1434,6 +1471,10 @@ Undocumented declaration. Displays the Post Trash Button and Confirm Dialog in the Editor. +_Parameters_ + +- _An_ `?{onActionPerformed: Object}`: object containing the onActionPerformed function. + _Returns_ - `JSX.Element|null`: The rendered PostTrash component. diff --git a/packages/editor/package.json b/packages/editor/package.json index 7e120895c782f..a9d486b74e79c 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/editor", - "version": "14.6.0", + "version": "14.7.0", "description": "Enhanced block editor for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/editor/src/bindings/post-meta.js b/packages/editor/src/bindings/post-meta.js index 1ecd6ea50ba27..7618ba6c36023 100644 --- a/packages/editor/src/bindings/post-meta.js +++ b/packages/editor/src/bindings/post-meta.js @@ -22,7 +22,7 @@ export default { for ( const [ attributeName, source ] of Object.entries( bindings ) ) { // Use the key if the value is not set. newValues[ attributeName ] = - meta?.[ source.args.key ] || source.args.key; + meta?.[ source.args.key ] ?? source.args.key; } return newValues; }, @@ -62,6 +62,12 @@ export default { if ( fieldValue === undefined ) { return false; } + // Check that custom fields metabox is not enabled. + const areCustomFieldsEnabled = + select( editorStore ).getEditorSettings().enableCustomFields; + if ( areCustomFieldsEnabled ) { + return false; + } // Check that the user has the capability to edit post meta. const canUserEdit = select( coreDataStore ).canUser( 'update', { diff --git a/packages/editor/src/components/document-outline/style.scss b/packages/editor/src/components/document-outline/style.scss index efd2606b82d39..49ce0c9b2d132 100644 --- a/packages/editor/src/components/document-outline/style.scss +++ b/packages/editor/src/components/document-outline/style.scss @@ -51,7 +51,7 @@ padding: 2px 5px 2px 1px; color: $gray-900; text-align: left; - border-radius: $radius-block-ui; + border-radius: $radius-small; &:disabled { cursor: default; diff --git a/packages/editor/src/components/editor/index.js b/packages/editor/src/components/editor/index.js index b094c3ceb4437..21becea43cd7e 100644 --- a/packages/editor/src/components/editor/index.js +++ b/packages/editor/src/components/editor/index.js @@ -74,11 +74,11 @@ function Editor( { { extraContent } + { children } - { children } ) } diff --git a/packages/editor/src/components/global-styles-provider/index.js b/packages/editor/src/components/global-styles-provider/index.js index 8426593d8f5f5..8268997d1f1de 100644 --- a/packages/editor/src/components/global-styles-provider/index.js +++ b/packages/editor/src/components/global-styles-provider/index.js @@ -146,13 +146,17 @@ function useGlobalStylesUserConfig() { function useGlobalStylesBaseConfig() { const baseConfig = useSelect( ( select ) => { - const { __experimentalGetCurrentThemeBaseGlobalStyles, canUser } = - select( coreStore ); - - return ( - canUser( 'read', { kind: 'root', name: 'theme' } ) && - __experimentalGetCurrentThemeBaseGlobalStyles() - ); + const { + __experimentalGetCurrentThemeBaseGlobalStyles, + getCurrentTheme, + canUser, + } = select( coreStore ); + const currentTheme = getCurrentTheme(); + + return currentTheme && + canUser( 'read', 'global-styles/themes', currentTheme.stylesheet ) + ? __experimentalGetCurrentThemeBaseGlobalStyles() + : undefined; }, [] ); return [ !! baseConfig, baseConfig ]; diff --git a/packages/editor/src/components/header/index.js b/packages/editor/src/components/header/index.js index b8eda30c72186..2e045ad732942 100644 --- a/packages/editor/src/components/header/index.js +++ b/packages/editor/src/components/header/index.js @@ -142,6 +142,9 @@ function Header( { forceIsAutosaveable={ forceIsDirty } /> + { ( isWideViewport || ! showIconLabels ) && ( + + ) } { ! customSaveButton && ( ) } { customSaveButton } - { ( isWideViewport || ! showIconLabels ) && ( - - ) } diff --git a/packages/editor/src/components/header/style.scss b/packages/editor/src/components/header/style.scss index 99c9cc70e166e..8712121fff3ea 100644 --- a/packages/editor/src/components/header/style.scss +++ b/packages/editor/src/components/header/style.scss @@ -243,7 +243,7 @@ width: 100%; @include break-medium { - border-bottom: 1px solid #e0e0e0; + box-shadow: 0 $border-width 0 0 rgba($color: #000, $alpha: 0.133); // 0.133 = $gray-200 but with alpha. position: absolute; } diff --git a/packages/editor/src/components/index.js b/packages/editor/src/components/index.js index 91dcc883d661b..b42566aac653b 100644 --- a/packages/editor/src/components/index.js +++ b/packages/editor/src/components/index.js @@ -32,6 +32,7 @@ export { default as PluginMoreMenuItem } from './plugin-more-menu-item'; export { default as PluginPostPublishPanel } from './plugin-post-publish-panel'; export { default as PluginPostStatusInfo } from './plugin-post-status-info'; export { default as PluginPrePublishPanel } from './plugin-pre-publish-panel'; +export { default as PluginPreviewMenuItem } from './plugin-preview-menu-item'; export { default as PluginSidebar } from './plugin-sidebar'; export { default as PluginSidebarMoreMenuItem } from './plugin-sidebar-more-menu-item'; export { default as PostTemplatePanel } from './post-template/panel'; diff --git a/packages/editor/src/components/inserter-sidebar/index.js b/packages/editor/src/components/inserter-sidebar/index.js index bf613b5c8c001..b98770b7afe8f 100644 --- a/packages/editor/src/components/inserter-sidebar/index.js +++ b/packages/editor/src/components/inserter-sidebar/index.js @@ -22,7 +22,6 @@ const { PrivateInserterLibrary } = unlock( blockEditorPrivateApis ); export default function InserterSidebar() { const { - blockInsertionPoint, blockSectionRootClientId, inserterSidebarToggleRef, insertionPoint, @@ -35,16 +34,16 @@ export default function InserterSidebar() { isPublishSidebarOpened, } = unlock( select( editorStore ) ); const { - getBlockInsertionPoint, getBlockRootClientId, __unstableGetEditorMode, - getSettings, - } = select( blockEditorStore ); + getSectionRootClientId, + } = unlock( select( blockEditorStore ) ); const { get } = select( preferencesStore ); const { getActiveComplementaryArea } = select( interfaceStore ); const getBlockSectionRootClientId = () => { if ( __unstableGetEditorMode() === 'zoom-out' ) { - const { sectionRootClientId } = unlock( getSettings() ); + const sectionRootClientId = getSectionRootClientId(); + if ( sectionRootClientId ) { return sectionRootClientId; } @@ -52,7 +51,6 @@ export default function InserterSidebar() { return getBlockRootClientId(); }; return { - blockInsertionPoint: getBlockInsertionPoint(), inserterSidebarToggleRef: getInserterSidebarToggleRef(), insertionPoint: getInsertionPoint(), showMostUsedBlocks: get( 'core', 'mostUsedBlocks' ), @@ -91,9 +89,9 @@ export default function InserterSidebar() { showInserterHelpPanel shouldFocusBlock={ isMobileViewport } rootClientId={ - blockSectionRootClientId ?? blockInsertionPoint.rootClientId + blockSectionRootClientId ?? insertionPoint.rootClientId } - __experimentalInsertionIndex={ blockInsertionPoint.index } + __experimentalInsertionIndex={ insertionPoint.insertionIndex } onSelect={ insertionPoint.onSelect } __experimentalInitialTab={ insertionPoint.tab } __experimentalInitialCategory={ insertionPoint.category } diff --git a/packages/editor/src/components/plugin-preview-menu-item/index.js b/packages/editor/src/components/plugin-preview-menu-item/index.js new file mode 100644 index 0000000000000..422248e17b88e --- /dev/null +++ b/packages/editor/src/components/plugin-preview-menu-item/index.js @@ -0,0 +1,52 @@ +/** + * WordPress dependencies + */ +import { compose } from '@wordpress/compose'; +import { MenuItem } from '@wordpress/components'; +import { withPluginContext } from '@wordpress/plugins'; +import { ActionItem } from '@wordpress/interface'; + +/** + * Renders a menu item in the Preview dropdown, which can be used as a button or link depending on the props provided. + * The text within the component appears as the menu item label. + * + * @param {Object} props Component properties. + * @param {string} [props.href] When `href` is provided, the menu item is rendered as an anchor instead of a button. It corresponds to the `href` attribute of the anchor. + * @param {WPBlockTypeIconRender} [props.icon=inherits from the plugin] The icon to be rendered to the left of the menu item label. Can be a Dashicon slug or an SVG WP element. + * @param {Function} [props.onClick] The callback function to be executed when the user clicks the menu item. + * @param {...*} [props.other] Any additional props are passed through to the underlying MenuItem component. + * + * @example + * ```jsx + * import { __ } from '@wordpress/i18n'; + * import { PluginPreviewMenuItem } from '@wordpress/editor'; + * import { external } from '@wordpress/icons'; + * + * function onPreviewClick() { + * // Handle preview action + * } + * + * const ExternalPreviewMenuItem = () => ( + * + * { __( 'Preview in new tab' ) } + * + * ); + * registerPlugin( 'external-preview-menu-item', { + * render: ExternalPreviewMenuItem, + * } ); + * ``` + * + * @return {Component} The rendered menu item component. + */ +export default compose( + withPluginContext( ( context, ownProps ) => { + return { + as: ownProps.as ?? MenuItem, + icon: ownProps.icon || context.icon, + name: 'core/plugin-preview-menu', + }; + } ) +)( ActionItem ); diff --git a/packages/editor/src/components/post-card-panel/style.scss b/packages/editor/src/components/post-card-panel/style.scss index 3547b0ab10493..73b638673f3e9 100644 --- a/packages/editor/src/components/post-card-panel/style.scss +++ b/packages/editor/src/components/post-card-panel/style.scss @@ -46,7 +46,7 @@ background: $gray-100; color: $gray-700; padding: 0 $grid-unit-05; - border-radius: $radius-block-ui; + border-radius: $radius-small; font-size: 12px; font-weight: 400; flex-shrink: 0; diff --git a/packages/editor/src/components/post-featured-image/style.scss b/packages/editor/src/components/post-featured-image/style.scss index d3a4fbbcaef68..3a537471b42f2 100644 --- a/packages/editor/src/components/post-featured-image/style.scss +++ b/packages/editor/src/components/post-featured-image/style.scss @@ -22,7 +22,7 @@ } .components-drop-zone__content { - border-radius: $radius-block-ui; + border-radius: $radius-small; } // Align text and icons horizontally to avoid clipping when the featured image is not set. @@ -65,7 +65,6 @@ } .editor-post-featured-image__toggle { - border-radius: $radius-block-ui; height: 100%; line-height: 20px; padding: $grid-unit-10 0; diff --git a/packages/editor/src/components/post-locked-modal/style.scss b/packages/editor/src/components/post-locked-modal/style.scss index 03e86642493df..7f68002234466 100644 --- a/packages/editor/src/components/post-locked-modal/style.scss +++ b/packages/editor/src/components/post-locked-modal/style.scss @@ -3,7 +3,7 @@ } .editor-post-locked-modal__avatar { - border-radius: $radius-block-ui; + border-radius: $radius-round; margin-top: $grid-unit-20; min-width: initial !important; } diff --git a/packages/editor/src/components/post-publish-panel/maybe-upload-media.js b/packages/editor/src/components/post-publish-panel/maybe-upload-media.js index b090e25cd4dbf..6b252b9f2b399 100644 --- a/packages/editor/src/components/post-publish-panel/maybe-upload-media.js +++ b/packages/editor/src/components/post-publish-panel/maybe-upload-media.js @@ -14,6 +14,11 @@ import { store as blockEditorStore } from '@wordpress/block-editor'; import { useState } from '@wordpress/element'; import { isBlobURL } from '@wordpress/blob'; +/** + * Internal dependencies + */ +import { fetchMedia } from './media-util'; + function flattenBlocks( blocks ) { const result = []; @@ -25,7 +30,53 @@ function flattenBlocks( blocks ) { return result; } -function Image( block ) { +/** + * Determine whether a block has external media. + * + * Different blocks use different attribute names (and potentially + * different logic as well) in determining whether the media is + * present, and whether it's external. + * + * @param {{name: string, attributes: Object}} block The block. + * @return {boolean?} Whether the block has external media + */ +function hasExternalMedia( block ) { + if ( block.name === 'core/image' || block.name === 'core/cover' ) { + return block.attributes.url && ! block.attributes.id; + } + + if ( block.name === 'core/media-text' ) { + return block.attributes.mediaUrl && ! block.attributes.mediaId; + } + + return undefined; +} + +/** + * Retrieve media info from a block. + * + * Different blocks use different attribute names, so we need this + * function to normalize things into a consistent naming scheme. + * + * @param {{name: string, attributes: Object}} block The block. + * @return {{url: ?string, alt: ?string, id: ?number}} The media info for the block. + */ +function getMediaInfo( block ) { + if ( block.name === 'core/image' || block.name === 'core/cover' ) { + const { url, alt, id } = block.attributes; + return { url, alt, id }; + } + + if ( block.name === 'core/media-text' ) { + const { mediaUrl: url, mediaAlt: alt, mediaId: id } = block.attributes; + return { url, alt, id }; + } + + return {}; +} + +// Image component to represent a single image in the upload dialog. +function Image( { clientId, alt, url } ) { const { selectBlock } = useDispatch( blockEditorStore ); return ( { - selectBlock( block.clientId ); + selectBlock( clientId ); } } onKeyDown={ ( event ) => { if ( event.key === 'Enter' || event.key === ' ' ) { - selectBlock( block.clientId ); + selectBlock( clientId ); event.preventDefault(); } } } - key={ block.clientId } - alt={ block.attributes.alt } - src={ block.attributes.url } + key={ clientId } + alt={ alt } + src={ url } animate={ { opacity: 1 } } exit={ { opacity: 0, scale: 0 } } style={ { @@ -58,7 +109,7 @@ function Image( block ) { ); } -export default function PostFormatPanel() { +export default function MaybeUploadMediaPanel() { const [ isUploading, setIsUploading ] = useState( false ); const [ isAnimating, setIsAnimating ] = useState( false ); const [ hadUploadError, setHadUploadError ] = useState( false ); @@ -69,15 +120,14 @@ export default function PostFormatPanel() { } ), [] ); - const externalImages = flattenBlocks( editorBlocks ).filter( - ( block ) => - block.name === 'core/image' && - block.attributes.url && - ! block.attributes.id + + // Get a list of blocks with external media. + const blocksWithExternalMedia = flattenBlocks( editorBlocks ).filter( + ( block ) => hasExternalMedia( block ) ); const { updateBlockAttributes } = useDispatch( blockEditorStore ); - if ( ! mediaUpload || ! externalImages.length ) { + if ( ! mediaUpload || ! blocksWithExternalMedia.length ) { return null; } @@ -88,43 +138,86 @@ export default function PostFormatPanel() { , ]; + /** + * Update an individual block to point to newly-added library media. + * + * Different blocks use different attribute names, so we need this + * function to ensure we modify the correct attributes for each type. + * + * @param {{name: string, attributes: Object}} block The block. + * @param {{id: number, url: string}} media Media library file info. + */ + function updateBlockWithUploadedMedia( block, media ) { + if ( block.name === 'core/image' || block.name === 'core/cover' ) { + updateBlockAttributes( block.clientId, { + id: media.id, + url: media.url, + } ); + } + + if ( block.name === 'core/media-text' ) { + updateBlockAttributes( block.clientId, { + mediaId: media.id, + mediaUrl: media.url, + } ); + } + } + + // Handle fetching and uploading all external media in the post. function uploadImages() { setIsUploading( true ); setHadUploadError( false ); - Promise.all( - externalImages.map( ( image ) => - window - .fetch( - image.attributes.url.includes( '?' ) - ? image.attributes.url - : image.attributes.url + '?' - ) - .then( ( response ) => response.blob() ) - .then( ( blob ) => - new Promise( ( resolve, reject ) => { - mediaUpload( { - filesList: [ blob ], - onFileChange: ( [ media ] ) => { - if ( isBlobURL( media.url ) ) { - return; - } - - updateBlockAttributes( image.clientId, { - id: media.id, - url: media.url, - } ); - resolve(); - }, - onError() { - reject(); - }, - } ); - } ).then( () => setIsAnimating( true ) ) - ) - .catch( () => { - setHadUploadError( true ); - } ) + + // Multiple blocks can be using the same URL, so we + // should ensure we only fetch and upload each of them once. + const mediaUrls = new Set( + blocksWithExternalMedia.map( ( block ) => { + const { url } = getMediaInfo( block ); + return url; + } ) + ); + + // Create an upload promise for each URL, that we can wait for in all + // blocks that make use of that media. + const uploadPromises = Object.fromEntries( + Object.entries( fetchMedia( [ ...mediaUrls ] ) ).map( + ( [ url, filePromise ] ) => { + const uploadPromise = filePromise.then( + ( blob ) => + new Promise( ( resolve, reject ) => { + mediaUpload( { + filesList: [ blob ], + onFileChange: ( [ media ] ) => { + if ( isBlobURL( media.url ) ) { + return; + } + + resolve( media ); + }, + onError() { + reject(); + }, + } ); + } ) + ); + + return [ url, uploadPromise ]; + } ) + ); + + // Wait for all blocks to be updated with library media. + Promise.allSettled( + blocksWithExternalMedia.map( ( block ) => { + const { url } = getMediaInfo( block ); + + return uploadPromises[ url ] + .then( ( media ) => + updateBlockWithUploadedMedia( block, media ) + ) + .then( () => setIsAnimating( true ) ) + .catch( () => setHadUploadError( true ) ); + } ) ).finally( () => { setIsUploading( false ); } ); @@ -147,8 +240,16 @@ export default function PostFormatPanel() { setIsAnimating( false ) } > - { externalImages.map( ( image ) => { - return ; + { blocksWithExternalMedia.map( ( block ) => { + const { url, alt } = getMediaInfo( block ); + return ( + { + ); } ) } { isUploading || isAnimating ? ( diff --git a/packages/editor/src/components/post-publish-panel/media-util.js b/packages/editor/src/components/post-publish-panel/media-util.js new file mode 100644 index 0000000000000..995802b0eebb4 --- /dev/null +++ b/packages/editor/src/components/post-publish-panel/media-util.js @@ -0,0 +1,87 @@ +/** + * External dependencies + */ +import { v4 as uuid } from 'uuid'; + +/** + * WordPress dependencies + */ +import { getFilename } from '@wordpress/url'; + +/** + * Generate a list of unique basenames given a list of URLs. + * + * We want all basenames to be unique, since sometimes the extension + * doesn't reflect the mime type, and may end up getting changed by + * the server, on upload. + * + * @param {string[]} urls The list of URLs + * @return {Record< string, string >} A URL => basename record. + */ +export function generateUniqueBasenames( urls ) { + const basenames = new Set(); + + return Object.fromEntries( + urls.map( ( url ) => { + // We prefer to match the remote filename, if possible. + const filename = getFilename( url ); + let basename = ''; + + if ( filename ) { + const parts = filename.split( '.' ); + if ( parts.length > 1 ) { + // Assume the last part is the extension. + parts.pop(); + } + basename = parts.join( '.' ); + } + + if ( ! basename ) { + // It looks like we don't have a basename, so let's use a UUID. + basename = uuid(); + } + + if ( basenames.has( basename ) ) { + // Append a UUID to deduplicate the basename. + // The server will try to deduplicate on its own if we don't do this, + // but it may run into a race condition + // (see https://github.com/WordPress/gutenberg/issues/64899). + // Deduplicating the filenames before uploading is safer. + basename = `${ basename }-${ uuid() }`; + } + + basenames.add( basename ); + + return [ url, basename ]; + } ) + ); +} + +/** + * Fetch a list of URLs, turning those into promises for files with + * unique filenames. + * + * @param {string[]} urls The list of URLs + * @return {Record< string, Promise< File > >} A URL => File promise record. + */ +export function fetchMedia( urls ) { + return Object.fromEntries( + Object.entries( generateUniqueBasenames( urls ) ).map( + ( [ url, basename ] ) => { + const filePromise = window + .fetch( url.includes( '?' ) ? url : url + '?' ) + .then( ( response ) => response.blob() ) + .then( ( blob ) => { + // The server will reject the upload if it doesn't have an extension, + // even though it'll rewrite the file name to match the mime type. + // Here we provide it with a safe extension to get it past that check. + return new File( [ blob ], `${ basename }.png`, { + type: blob.type, + } ); + } ); + + return [ url, filePromise ]; + } + ) + ); +} diff --git a/packages/editor/src/components/post-publish-panel/style.scss b/packages/editor/src/components/post-publish-panel/style.scss index bcd7c798c7e9f..9892cf5430f9a 100644 --- a/packages/editor/src/components/post-publish-panel/style.scss +++ b/packages/editor/src/components/post-publish-panel/style.scss @@ -37,7 +37,7 @@ .components-site-icon { border: none; - border-radius: $radius-block-ui; + border-radius: $radius-small; margin-right: $grid-unit-15; flex-shrink: 0; diff --git a/packages/editor/src/components/post-publish-panel/test/media-util.js b/packages/editor/src/components/post-publish-panel/test/media-util.js new file mode 100644 index 0000000000000..b91583cc3f17b --- /dev/null +++ b/packages/editor/src/components/post-publish-panel/test/media-util.js @@ -0,0 +1,118 @@ +/** + * Internal dependencies + */ +import { generateUniqueBasenames } from '../media-util'; + +describe( 'generateUniqueBasenames', () => { + it( 'should prefer the original basenames', () => { + const urls = [ + 'https://example.com/images/image1.jpg', + 'https://example.com/images/image2.jpg', + 'https://example.com/images/image3.jpg', + 'https://example.com/images/image4.jpg', + ]; + + expect( generateUniqueBasenames( urls ) ).toEqual( { + 'https://example.com/images/image1.jpg': 'image1', + 'https://example.com/images/image2.jpg': 'image2', + 'https://example.com/images/image3.jpg': 'image3', + 'https://example.com/images/image4.jpg': 'image4', + } ); + } ); + + it( 'should handle filenames with no extensions', () => { + const urls = [ + 'https://example.com/images/image1', + 'https://example.com/images/image2', + 'https://example.com/images/image3', + 'https://example.com/images/image4', + ]; + + expect( generateUniqueBasenames( urls ) ).toEqual( { + 'https://example.com/images/image1': 'image1', + 'https://example.com/images/image2': 'image2', + 'https://example.com/images/image3': 'image3', + 'https://example.com/images/image4': 'image4', + } ); + } ); + + it( 'should handle query parameters correctly', () => { + const urls = [ + 'https://example.com/images/image1.jpg?a=notafile.npg', + 'https://example.com/images/image2.jpg?a=notafile.npg', + 'https://example.com/images/image3.jpg?a=notafile.npg', + 'https://example.com/images/image4.jpg?a=notafile.npg', + ]; + + expect( generateUniqueBasenames( urls ) ).toEqual( { + 'https://example.com/images/image1.jpg?a=notafile.npg': 'image1', + 'https://example.com/images/image2.jpg?a=notafile.npg': 'image2', + 'https://example.com/images/image3.jpg?a=notafile.npg': 'image3', + 'https://example.com/images/image4.jpg?a=notafile.npg': 'image4', + } ); + } ); + + it( 'should deduplicate identical filenames', () => { + const urls = [ + 'https://example.com/image1/image.jpg', + 'https://example.com/image2/image.jpg', + 'https://example.com/image3/image.jpg', + 'https://example.com/image4/image.jpg', + ]; + + const results = generateUniqueBasenames( urls ); + const resultLength = Object.entries( results ).length; + expect( resultLength ).toBe( urls.length ); + + const basenames = new Set( Object.values( results ) ); + expect( basenames.size ).toBe( resultLength ); + } ); + + it( 'should deduplicate identical basenames', () => { + const urls = [ + 'https://example.com/images/image.jpg', + 'https://example.com/images/image.png', + 'https://example.com/images/image.webp', + 'https://example.com/images/image.avif', + ]; + + const results = generateUniqueBasenames( urls ); + const resultLength = Object.entries( results ).length; + expect( resultLength ).toBe( urls.length ); + + const basenames = new Set( Object.values( results ) ); + expect( basenames.size ).toBe( resultLength ); + } ); + + it( 'should deduplicate filenames without extensions', () => { + const urls = [ + 'https://example.com/image1/image', + 'https://example.com/image2/image', + 'https://example.com/image3/image', + 'https://example.com/image4/image', + ]; + + const results = generateUniqueBasenames( urls ); + const resultLength = Object.entries( results ).length; + expect( resultLength ).toBe( urls.length ); + + const basenames = new Set( Object.values( results ) ); + expect( basenames.size ).toBe( resultLength ); + } ); + + it( 'should deduplicate paths with no filename', () => { + const urls = [ + 'https://example.com/image1/dir/', + 'https://example.com/image2/dir/', + 'https://example.com/image3/dir/', + 'https://example.com/image4/dir/', + ]; + + const results = generateUniqueBasenames( urls ); + const resultLength = Object.entries( results ).length; + expect( resultLength ).toBe( urls.length ); + + const basenames = new Set( Object.values( results ) ); + expect( basenames.size ).toBe( resultLength ); + } ); +} ); diff --git a/packages/editor/src/components/post-status/index.js b/packages/editor/src/components/post-status/index.js index ca89e40366b23..1d3050e7e3dd6 100644 --- a/packages/editor/src/components/post-status/index.js +++ b/packages/editor/src/components/post-status/index.js @@ -171,7 +171,7 @@ export default function PostStatus() { contentClassName="editor-change-status__content" popoverProps={ popoverProps } focusOnMount - renderToggle={ ( { onToggle } ) => ( + renderToggle={ ( { onToggle, isOpen } ) => ( diff --git a/packages/editor/src/components/post-template/block-theme.js b/packages/editor/src/components/post-template/block-theme.js index 7fcc5ead14f5b..62de10a2c715f 100644 --- a/packages/editor/src/components/post-template/block-theme.js +++ b/packages/editor/src/components/post-template/block-theme.js @@ -8,6 +8,7 @@ import { __ } from '@wordpress/i18n'; import { useEntityRecord, store as coreStore } from '@wordpress/core-data'; import { check } from '@wordpress/icons'; import { store as noticesStore } from '@wordpress/notices'; +import { store as preferencesStore } from '@wordpress/preferences'; /** * Internal dependencies @@ -43,6 +44,8 @@ export default function BlockThemeControl( { id } ) { }; }, [] ); + const { get: getPreference } = useSelect( preferencesStore ); + const { editedRecord: template, hasResolved } = useEntityRecord( 'postType', 'wp_template', @@ -75,6 +78,17 @@ export default function BlockThemeControl( { id } ) { }, ] : undefined; + + const mayShowTemplateEditNotice = () => { + if ( ! getPreference( 'core/edit-site', 'welcomeGuideTemplate' ) ) { + createSuccessNotice( + __( + 'Editing template. Changes made here affect all posts and pages that use the template.' + ), + { type: 'snackbar', actions: notificationAction } + ); + } + }; return ( { __( 'Edit template' ) } diff --git a/packages/editor/src/components/post-trash/check.js b/packages/editor/src/components/post-trash/check.js index 8f51df175c898..7edc7c0f18c27 100644 --- a/packages/editor/src/components/post-trash/check.js +++ b/packages/editor/src/components/post-trash/check.js @@ -8,6 +8,7 @@ import { store as coreStore } from '@wordpress/core-data'; * Internal dependencies */ import { store as editorStore } from '../../store'; +import { GLOBAL_POST_TYPES } from '../../store/constants'; /** * Wrapper component that renders its children only if the post can trashed. @@ -34,10 +35,12 @@ export default function PostTrashCheck( { children } ) { : false; return { - canTrashPost: ( ! isNew || postId ) && canUserDelete, + canTrashPost: + ( ! isNew || postId ) && + canUserDelete && + ! GLOBAL_POST_TYPES.includes( postType ), }; }, [] ); - if ( ! canTrashPost ) { return null; } diff --git a/packages/editor/src/components/post-trash/index.js b/packages/editor/src/components/post-trash/index.js index c29dfd66a2d8c..743512e9efd7d 100644 --- a/packages/editor/src/components/post-trash/index.js +++ b/packages/editor/src/components/post-trash/index.js @@ -1,31 +1,35 @@ /** * WordPress dependencies */ -import { __ } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; import { Button, __experimentalConfirmDialog as ConfirmDialog, } from '@wordpress/components'; -import { useSelect, useDispatch } from '@wordpress/data'; +import { useSelect, useDispatch, useRegistry } from '@wordpress/data'; import { useState } from '@wordpress/element'; /** * Internal dependencies */ import { store as editorStore } from '../../store'; +import PostTrashCheck from './check'; /** * Displays the Post Trash Button and Confirm Dialog in the Editor. * + * @param {?{onActionPerformed: Object}} An object containing the onActionPerformed function. * @return {JSX.Element|null} The rendered PostTrash component. */ -export default function PostTrash() { - const { isNew, isDeleting, postId } = useSelect( ( select ) => { +export default function PostTrash( { onActionPerformed } ) { + const registry = useRegistry(); + const { isNew, isDeleting, postId, title } = useSelect( ( select ) => { const store = select( editorStore ); return { isNew: store.isEditedPostNew(), isDeleting: store.isDeletingPost(), postId: store.getCurrentPostId(), + title: store.getCurrentPostAttribute( 'title' ), }; }, [] ); const { trashPost } = useDispatch( editorStore ); @@ -35,13 +39,18 @@ export default function PostTrash() { return null; } - const handleConfirm = () => { + const handleConfirm = async () => { setShowConfirmDialog( false ); - trashPost(); + await trashPost(); + const item = await registry + .resolveSelect( editorStore ) + .getCurrentPost(); + // After the post is trashed, we want to trigger the onActionPerformed callback, so the user is redirect + // to the post view depending on if the user is on post editor or site editor. + onActionPerformed?.( 'move-to-trash', [ item ] ); }; - return ( - <> +