From a08020096403b2a97863d071e815d980cebf826a Mon Sep 17 00:00:00 2001 From: Mario Santos <34552881+SantosGuillamot@users.noreply.github.com> Date: Wed, 25 Sep 2024 16:15:18 +0200 Subject: [PATCH 01/25] Only pass context included in `usesContext` from block bindings (#65618) - Only pass context included in `usesContext` Co-authored-by: SantosGuillamot Co-authored-by: gziolo --- .../block-editor/src/components/rich-text/index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index 9c67476ed0ea6..46ddb2b70a113 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -179,11 +179,17 @@ export function RichTextWrapper( const blockBindingsSource = getBlockBindingsSource( relatedBinding.source ); + const blockBindingsContext = {}; + if ( blockBindingsSource?.usesContext?.length ) { + for ( const key of blockBindingsSource.usesContext ) { + blockBindingsContext[ key ] = blockContext[ key ]; + } + } const _disableBoundBlock = ! blockBindingsSource?.canUserEditValue?.( { select, - context: blockContext, + context: blockBindingsContext, args: relatedBinding.args, } ); @@ -201,7 +207,7 @@ export function RichTextWrapper( const blockAttributes = getBlockAttributes( clientId ); const fieldsList = blockBindingsSource?.getFieldsList?.( { registry, - context: blockContext, + context: blockBindingsContext, } ); const bindingKey = fieldsList?.[ relatedBinding?.args?.key ]?.label ?? From 69e00bd3375e2ed13fba8955b7b7298c15a47cb2 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 25 Sep 2024 23:39:33 +0900 Subject: [PATCH 02/25] LinkControl: Fix unneeded `props` prop (#65650) Co-authored-by: mirka <0mirka00@git.wordpress.org> Co-authored-by: getdave --- packages/block-editor/src/components/link-control/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/block-editor/src/components/link-control/index.js b/packages/block-editor/src/components/link-control/index.js index f9e2e0bc6d790..f0de14f3d6821 100644 --- a/packages/block-editor/src/components/link-control/index.js +++ b/packages/block-editor/src/components/link-control/index.js @@ -421,7 +421,6 @@ function LinkControl( { ) } - props /> { errorMessage && ( From cb44f51ad33d703015816e53aa98616b41ead2ea Mon Sep 17 00:00:00 2001 From: Luigi Teschio Date: Wed, 25 Sep 2024 17:00:53 +0200 Subject: [PATCH 03/25] Migrate store and actions from editor package to fields package #2 (#65289) Co-authored-by: gigitux Co-authored-by: louwie17 Co-authored-by: youknowriad Co-authored-by: oandregal --- package-lock.json | 2 + .../src/dataviews/actions/delete-post.tsx | 109 ------- .../src/dataviews/actions/reset-post.tsx | 147 --------- packages/editor/src/dataviews/fields/index.ts | 26 -- .../src/dataviews/store/private-actions.ts | 14 +- packages/fields/README.md | 20 ++ packages/fields/package.json | 1 + .../fields/src/actions/base-post/index.ts | 5 - packages/fields/src/actions/common/index.ts | 2 - packages/fields/src/actions/delete-post.tsx | 203 ++++++++++++ .../{pattern => }/duplicate-pattern.tsx | 4 +- .../{base-post => }/duplicate-post.native.tsx | 0 .../{base-post => }/duplicate-post.tsx | 6 +- .../{pattern => }/export-pattern.native.tsx | 0 .../actions/{pattern => }/export-pattern.tsx | 4 +- packages/fields/src/actions/index.ts | 18 +- packages/fields/src/actions/pattern/index.ts | 3 - .../{common => }/permanently-delete-post.tsx | 4 +- .../src}/actions/rename-post.tsx | 11 +- .../{base-post => }/reorder-page.native.tsx | 0 .../actions/{base-post => }/reorder-page.tsx | 4 +- packages/fields/src/actions/reset-post.tsx | 300 ++++++++++++++++++ .../src}/actions/restore-post.tsx | 0 .../src}/actions/trash-post.tsx | 0 .../{common => }/view-post-revisions.tsx | 2 +- .../src/actions/{base-post => }/view-post.tsx | 2 +- packages/fields/src/index.native.ts | 4 +- packages/fields/src/mutation/index.ts | 184 +++++++++++ packages/fields/src/types.ts | 1 + packages/fields/src/wordpress-editor.d.ts | 1 - packages/fields/tsconfig.json | 4 +- 31 files changed, 755 insertions(+), 326 deletions(-) delete mode 100644 packages/editor/src/dataviews/actions/delete-post.tsx delete mode 100644 packages/editor/src/dataviews/actions/reset-post.tsx delete mode 100644 packages/editor/src/dataviews/fields/index.ts delete mode 100644 packages/fields/src/actions/base-post/index.ts delete mode 100644 packages/fields/src/actions/common/index.ts create mode 100644 packages/fields/src/actions/delete-post.tsx rename packages/fields/src/actions/{pattern => }/duplicate-pattern.tsx (91%) rename packages/fields/src/actions/{base-post => }/duplicate-post.native.tsx (100%) rename packages/fields/src/actions/{base-post => }/duplicate-post.tsx (96%) rename packages/fields/src/actions/{pattern => }/export-pattern.native.tsx (100%) rename packages/fields/src/actions/{pattern => }/export-pattern.tsx (95%) delete mode 100644 packages/fields/src/actions/pattern/index.ts rename packages/fields/src/actions/{common => }/permanently-delete-post.tsx (96%) rename packages/{editor/src/dataviews => fields/src}/actions/rename-post.tsx (97%) rename packages/fields/src/actions/{base-post => }/reorder-page.native.tsx (100%) rename packages/fields/src/actions/{base-post => }/reorder-page.tsx (96%) create mode 100644 packages/fields/src/actions/reset-post.tsx rename packages/{editor/src/dataviews => fields/src}/actions/restore-post.tsx (100%) rename packages/{editor/src/dataviews => fields/src}/actions/trash-post.tsx (100%) rename packages/fields/src/actions/{common => }/view-post-revisions.tsx (96%) rename packages/fields/src/actions/{base-post => }/view-post.tsx (92%) create mode 100644 packages/fields/src/mutation/index.ts delete mode 100644 packages/fields/src/wordpress-editor.d.ts diff --git a/package-lock.json b/package-lock.json index a40aa8aab4934..93da356b222be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54197,6 +54197,7 @@ "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", + "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/blob": "file:../blob", "@wordpress/blocks": "file:../blocks", "@wordpress/components": "file:../components", @@ -68945,6 +68946,7 @@ "version": "file:packages/fields", "requires": { "@babel/runtime": "^7.16.0", + "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/blob": "file:../blob", "@wordpress/blocks": "file:../blocks", "@wordpress/components": "file:../components", diff --git a/packages/editor/src/dataviews/actions/delete-post.tsx b/packages/editor/src/dataviews/actions/delete-post.tsx deleted file mode 100644 index 381c2964f943f..0000000000000 --- a/packages/editor/src/dataviews/actions/delete-post.tsx +++ /dev/null @@ -1,109 +0,0 @@ -/** - * WordPress dependencies - */ -import { trash } from '@wordpress/icons'; -import { useDispatch } from '@wordpress/data'; -import { __, _n, sprintf } from '@wordpress/i18n'; -import { useState } from '@wordpress/element'; -import { - Button, - __experimentalText as Text, - __experimentalHStack as HStack, - __experimentalVStack as VStack, -} from '@wordpress/components'; -// @ts-ignore -import { privateApis as patternsPrivateApis } from '@wordpress/patterns'; -import type { Action } from '@wordpress/dataviews'; -import type { StoreDescriptor } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import { - isTemplateRemovable, - getItemTitle, - isTemplateOrTemplatePart, -} from './utils'; -// @ts-ignore -import { store as editorStore } from '../../store'; -import { unlock } from '../../lock-unlock'; -import type { Post } from '../types'; - -const { PATTERN_TYPES } = unlock( patternsPrivateApis ); - -// This action is used for templates, patterns and template parts. -// Every other post type uses the similar `trashPostAction` which -// moves the post to trash. -const deletePostAction: Action< Post > = { - id: 'delete-post', - label: __( 'Delete' ), - isPrimary: true, - icon: trash, - isEligible( post ) { - if ( isTemplateOrTemplatePart( post ) ) { - return isTemplateRemovable( post ); - } - // We can only remove user patterns. - return post.type === PATTERN_TYPES.user; - }, - supportsBulk: true, - hideModalHeader: true, - RenderModal: ( { items, closeModal, onActionPerformed } ) => { - const [ isBusy, setIsBusy ] = useState( false ); - const { removeTemplates } = unlock( - useDispatch( editorStore as StoreDescriptor ) - ); - return ( - - - { items.length > 1 - ? sprintf( - // translators: %d: number of items to delete. - _n( - 'Delete %d item?', - 'Delete %d items?', - items.length - ), - items.length - ) - : sprintf( - // translators: %s: The template or template part's titles - __( 'Delete "%s"?' ), - getItemTitle( items[ 0 ] ) - ) } - - - - - - - ); - }, -}; - -export default deletePostAction; diff --git a/packages/editor/src/dataviews/actions/reset-post.tsx b/packages/editor/src/dataviews/actions/reset-post.tsx deleted file mode 100644 index d0b5521a34833..0000000000000 --- a/packages/editor/src/dataviews/actions/reset-post.tsx +++ /dev/null @@ -1,147 +0,0 @@ -/** - * WordPress dependencies - */ -import { backup } from '@wordpress/icons'; -import { useDispatch } from '@wordpress/data'; -import { store as coreStore } from '@wordpress/core-data'; -import { __, sprintf } from '@wordpress/i18n'; -import { store as noticesStore } from '@wordpress/notices'; -import { useState } from '@wordpress/element'; -import { - Button, - __experimentalText as Text, - __experimentalHStack as HStack, - __experimentalVStack as VStack, -} from '@wordpress/components'; -import type { Action } from '@wordpress/dataviews'; -import type { StoreDescriptor } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import { TEMPLATE_POST_TYPE, TEMPLATE_ORIGINS } from '../../store/constants'; -import { store as editorStore } from '../../store'; -import { unlock } from '../../lock-unlock'; -import type { Post, CoreDataError } from '../types'; -import { isTemplateOrTemplatePart, getItemTitle } from './utils'; - -const resetPost: Action< Post > = { - id: 'reset-post', - label: __( 'Reset' ), - isEligible: ( item ) => { - return ( - isTemplateOrTemplatePart( item ) && - item?.source === TEMPLATE_ORIGINS.custom && - ( Boolean( item.type === 'wp_template' && item?.plugin ) || - item?.has_theme_file ) - ); - }, - icon: backup, - supportsBulk: true, - hideModalHeader: true, - RenderModal: ( { items, closeModal, onActionPerformed } ) => { - const [ isBusy, setIsBusy ] = useState( false ); - const { revertTemplate } = unlock( - useDispatch( editorStore as StoreDescriptor ) - ); - const { saveEditedEntityRecord } = useDispatch( coreStore ); - const { createSuccessNotice, createErrorNotice } = - useDispatch( noticesStore ); - const onConfirm = async () => { - try { - for ( const template of items ) { - await revertTemplate( template, { - allowUndo: false, - } ); - await saveEditedEntityRecord( - 'postType', - template.type, - template.id - ); - } - createSuccessNotice( - items.length > 1 - ? sprintf( - /* translators: The number of items. */ - __( '%s items reset.' ), - items.length - ) - : sprintf( - /* translators: The template/part's name. */ - __( '"%s" reset.' ), - getItemTitle( items[ 0 ] ) - ), - { - type: 'snackbar', - id: 'revert-template-action', - } - ); - } catch ( error ) { - let fallbackErrorMessage; - if ( items[ 0 ].type === TEMPLATE_POST_TYPE ) { - fallbackErrorMessage = - items.length === 1 - ? __( - 'An error occurred while reverting the template.' - ) - : __( - 'An error occurred while reverting the templates.' - ); - } else { - fallbackErrorMessage = - items.length === 1 - ? __( - 'An error occurred while reverting the template part.' - ) - : __( - 'An error occurred while reverting the template parts.' - ); - } - - const typedError = error as CoreDataError; - const errorMessage = - typedError.message && typedError.code !== 'unknown_error' - ? typedError.message - : fallbackErrorMessage; - - createErrorNotice( errorMessage, { type: 'snackbar' } ); - } - }; - return ( - - - { __( 'Reset to default and clear all customizations?' ) } - - - - - - - ); - }, -}; - -export default resetPost; diff --git a/packages/editor/src/dataviews/fields/index.ts b/packages/editor/src/dataviews/fields/index.ts deleted file mode 100644 index b215172eaf7f0..0000000000000 --- a/packages/editor/src/dataviews/fields/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import type { Field } from '@wordpress/dataviews'; - -/** - * Internal dependencies - */ -import type { BasePost } from '../types'; -import { getItemTitle } from '../actions/utils'; - -export const titleField: Field< BasePost > = { - type: 'text', - id: 'title', - label: __( 'Title' ), - placeholder: __( 'No title' ), - getValue: ( { item } ) => getItemTitle( item ), -}; - -export const orderField: Field< BasePost > = { - type: 'integer', - id: 'menu_order', - label: __( 'Order' ), - description: __( 'Determines the order of pages.' ), -}; diff --git a/packages/editor/src/dataviews/store/private-actions.ts b/packages/editor/src/dataviews/store/private-actions.ts index e685493641f3b..10f2b9ce872d5 100644 --- a/packages/editor/src/dataviews/store/private-actions.ts +++ b/packages/editor/src/dataviews/store/private-actions.ts @@ -8,11 +8,6 @@ import { doAction } from '@wordpress/hooks'; /** * Internal dependencies */ -import duplicateTemplatePart from '../actions/duplicate-template-part'; -import resetPost from '../actions/reset-post'; -import trashPost from '../actions/trash-post'; -import renamePost from '../actions/rename-post'; -import restorePost from '../actions/restore-post'; import type { PostType } from '../types'; import { store as editorStore } from '../../store'; import { unlock } from '../../lock-unlock'; @@ -24,8 +19,13 @@ import { reorderPage, exportPattern, permanentlyDeletePost, + restorePost, + trashPost, + renamePost, + resetPost, + deletePost, } from '@wordpress/fields'; -import deletePost from '../actions/delete-post'; +import duplicateTemplatePart from '../actions/duplicate-template-part'; export function registerEntityAction< Item >( kind: string, @@ -117,8 +117,8 @@ export const registerPostTypeActions = ? reorderPage : undefined, postTypeConfig.slug === 'wp_block' ? exportPattern : undefined, - resetPost, restorePost, + resetPost, deletePost, trashPost, permanentlyDeletePost, diff --git a/packages/fields/README.md b/packages/fields/README.md index 842fab02606af..b4e45103600da 100644 --- a/packages/fields/README.md +++ b/packages/fields/README.md @@ -14,6 +14,10 @@ npm install @wordpress/fields --save +### deletePost + +Undocumented declaration. + ### duplicatePattern Undocumented declaration. @@ -42,6 +46,10 @@ Undocumented declaration. Undocumented declaration. +### renamePost + +Undocumented declaration. + ### reorderPage Undocumented declaration. @@ -50,10 +58,22 @@ Undocumented declaration. Undocumented declaration. +### resetPost + +Undocumented declaration. + +### restorePost + +Undocumented declaration. + ### titleField Undocumented declaration. +### trashPost + +Undocumented declaration. + ### viewPost Undocumented declaration. diff --git a/packages/fields/package.json b/packages/fields/package.json index ba687e6db1bc8..3da913d1ee9ae 100644 --- a/packages/fields/package.json +++ b/packages/fields/package.json @@ -32,6 +32,7 @@ ], "dependencies": { "@babel/runtime": "^7.16.0", + "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/blob": "file:../blob", "@wordpress/blocks": "file:../blocks", "@wordpress/components": "file:../components", diff --git a/packages/fields/src/actions/base-post/index.ts b/packages/fields/src/actions/base-post/index.ts deleted file mode 100644 index 7541be86c48b1..0000000000000 --- a/packages/fields/src/actions/base-post/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { default as viewPost } from './view-post'; -export { default as reorderPage } from './reorder-page'; -export { default as reorderPageNative } from './reorder-page.native'; -export { default as duplicatePost } from './duplicate-post'; -export { default as duplicatePostNative } from './duplicate-post.native'; diff --git a/packages/fields/src/actions/common/index.ts b/packages/fields/src/actions/common/index.ts deleted file mode 100644 index 3590b2e270892..0000000000000 --- a/packages/fields/src/actions/common/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as viewPostRevisions } from './view-post-revisions'; -export { default as permanentlyDeletePost } from './permanently-delete-post'; diff --git a/packages/fields/src/actions/delete-post.tsx b/packages/fields/src/actions/delete-post.tsx new file mode 100644 index 0000000000000..c5ab866e12479 --- /dev/null +++ b/packages/fields/src/actions/delete-post.tsx @@ -0,0 +1,203 @@ +/** + * WordPress dependencies + */ +import { trash } from '@wordpress/icons'; +import { __, _n, sprintf } from '@wordpress/i18n'; +import { useState } from '@wordpress/element'; +import { + Button, + __experimentalText as Text, + __experimentalHStack as HStack, + __experimentalVStack as VStack, +} from '@wordpress/components'; +// @ts-ignore +import { privateApis as patternsPrivateApis } from '@wordpress/patterns'; +import type { Action } from '@wordpress/dataviews'; +import { decodeEntities } from '@wordpress/html-entities'; + +/** + * Internal dependencies + */ +import { + getItemTitle, + isTemplateOrTemplatePart, + isTemplateRemovable, +} from './utils'; +import type { Pattern, Template, TemplatePart } from '../types'; +import type { NoticeSettings } from '../mutation'; +import { deletePostWithNotices } from '../mutation'; +import { unlock } from '../lock-unlock'; + +const { PATTERN_TYPES } = unlock( patternsPrivateApis ); + +// This action is used for templates, patterns and template parts. +// Every other post type uses the similar `trashPostAction` which +// moves the post to trash. +const deletePostAction: Action< Template | TemplatePart | Pattern > = { + id: 'delete-post', + label: __( 'Delete' ), + isPrimary: true, + icon: trash, + isEligible( post ) { + if ( isTemplateOrTemplatePart( post ) ) { + return isTemplateRemovable( post ); + } + // We can only remove user patterns. + return post.type === PATTERN_TYPES.user; + }, + supportsBulk: true, + hideModalHeader: true, + RenderModal: ( { items, closeModal, onActionPerformed } ) => { + const [ isBusy, setIsBusy ] = useState( false ); + const isResetting = items.every( + ( item ) => isTemplateOrTemplatePart( item ) && item?.has_theme_file + ); + return ( + + + { items.length > 1 + ? sprintf( + // translators: %d: number of items to delete. + _n( + 'Delete %d item?', + 'Delete %d items?', + items.length + ), + items.length + ) + : sprintf( + // translators: %s: The template or template part's titles + __( 'Delete "%s"?' ), + getItemTitle( items[ 0 ] ) + ) } + + + + + + + ); + }, +}; + +export default deletePostAction; diff --git a/packages/fields/src/actions/pattern/duplicate-pattern.tsx b/packages/fields/src/actions/duplicate-pattern.tsx similarity index 91% rename from packages/fields/src/actions/pattern/duplicate-pattern.tsx rename to packages/fields/src/actions/duplicate-pattern.tsx index 7c71a271997f1..bf2820f951dba 100644 --- a/packages/fields/src/actions/pattern/duplicate-pattern.tsx +++ b/packages/fields/src/actions/duplicate-pattern.tsx @@ -9,8 +9,8 @@ import type { Action } from '@wordpress/dataviews'; /** * Internal dependencies */ -import { unlock } from '../../lock-unlock'; -import type { Pattern } from '../../types'; +import { unlock } from '../lock-unlock'; +import type { Pattern } from '../types'; // Patterns. const { CreatePatternModalContents, useDuplicatePatternProps } = diff --git a/packages/fields/src/actions/base-post/duplicate-post.native.tsx b/packages/fields/src/actions/duplicate-post.native.tsx similarity index 100% rename from packages/fields/src/actions/base-post/duplicate-post.native.tsx rename to packages/fields/src/actions/duplicate-post.native.tsx diff --git a/packages/fields/src/actions/base-post/duplicate-post.tsx b/packages/fields/src/actions/duplicate-post.tsx similarity index 96% rename from packages/fields/src/actions/base-post/duplicate-post.tsx rename to packages/fields/src/actions/duplicate-post.tsx index 0035a40c00934..d153073f4b6c1 100644 --- a/packages/fields/src/actions/base-post/duplicate-post.tsx +++ b/packages/fields/src/actions/duplicate-post.tsx @@ -18,9 +18,9 @@ import type { Action } from '@wordpress/dataviews'; /** * Internal dependencies */ -import { titleField } from '../../fields'; -import type { BasePost, CoreDataError } from '../../types'; -import { getItemTitle } from '../utils'; +import { titleField } from '../fields'; +import type { BasePost, CoreDataError } from '../types'; +import { getItemTitle } from './utils'; const fields = [ titleField ]; const formDuplicateAction = { diff --git a/packages/fields/src/actions/pattern/export-pattern.native.tsx b/packages/fields/src/actions/export-pattern.native.tsx similarity index 100% rename from packages/fields/src/actions/pattern/export-pattern.native.tsx rename to packages/fields/src/actions/export-pattern.native.tsx diff --git a/packages/fields/src/actions/pattern/export-pattern.tsx b/packages/fields/src/actions/export-pattern.tsx similarity index 95% rename from packages/fields/src/actions/pattern/export-pattern.tsx rename to packages/fields/src/actions/export-pattern.tsx index b0f6c3335544c..b6be83eeda84b 100644 --- a/packages/fields/src/actions/pattern/export-pattern.tsx +++ b/packages/fields/src/actions/export-pattern.tsx @@ -15,8 +15,8 @@ import type { Action } from '@wordpress/dataviews'; /** * Internal dependencies */ -import type { Pattern } from '../../types'; -import { getItemTitle } from '../utils'; +import type { Pattern } from '../types'; +import { getItemTitle } from './utils'; function getJsonFromItem( item: Pattern ) { return JSON.stringify( diff --git a/packages/fields/src/actions/index.ts b/packages/fields/src/actions/index.ts index cf4fd6833f3fb..08e22836e68fd 100644 --- a/packages/fields/src/actions/index.ts +++ b/packages/fields/src/actions/index.ts @@ -1,3 +1,15 @@ -export * from './base-post'; -export * from './common'; -export * from './pattern'; +export { default as viewPost } from './view-post'; +export { default as reorderPage } from './reorder-page'; +export { default as reorderPageNative } from './reorder-page.native'; +export { default as duplicatePost } from './duplicate-post'; +export { default as duplicatePostNative } from './duplicate-post.native'; +export { default as renamePost } from './rename-post'; +export { default as resetPost } from './reset-post'; +export { default as duplicatePattern } from './duplicate-pattern'; +export { default as exportPattern } from './export-pattern'; +export { default as exportPatternNative } from './export-pattern.native'; +export { default as viewPostRevisions } from './view-post-revisions'; +export { default as permanentlyDeletePost } from './permanently-delete-post'; +export { default as restorePost } from './restore-post'; +export { default as trashPost } from './trash-post'; +export { default as deletePost } from './delete-post'; diff --git a/packages/fields/src/actions/pattern/index.ts b/packages/fields/src/actions/pattern/index.ts deleted file mode 100644 index 827c2ce365c2c..0000000000000 --- a/packages/fields/src/actions/pattern/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { default as duplicatePattern } from './duplicate-pattern'; -export { default as exportPattern } from './export-pattern'; -export { default as exportPatternNative } from './export-pattern.native'; diff --git a/packages/fields/src/actions/common/permanently-delete-post.tsx b/packages/fields/src/actions/permanently-delete-post.tsx similarity index 96% rename from packages/fields/src/actions/common/permanently-delete-post.tsx rename to packages/fields/src/actions/permanently-delete-post.tsx index e0c1de96871f1..afbb84ae12c74 100644 --- a/packages/fields/src/actions/common/permanently-delete-post.tsx +++ b/packages/fields/src/actions/permanently-delete-post.tsx @@ -10,8 +10,8 @@ import { trash } from '@wordpress/icons'; /** * Internal dependencies */ -import { getItemTitle, isTemplateOrTemplatePart } from '../utils'; -import type { CoreDataError, PostWithPermissions } from '../../types'; +import { getItemTitle, isTemplateOrTemplatePart } from './utils'; +import type { CoreDataError, PostWithPermissions } from '../types'; const permanentlyDeletePost: Action< PostWithPermissions > = { id: 'permanently-delete', diff --git a/packages/editor/src/dataviews/actions/rename-post.tsx b/packages/fields/src/actions/rename-post.tsx similarity index 97% rename from packages/editor/src/dataviews/actions/rename-post.tsx rename to packages/fields/src/actions/rename-post.tsx index ef9da271111ea..da1fd46669f0d 100644 --- a/packages/editor/src/dataviews/actions/rename-post.tsx +++ b/packages/fields/src/actions/rename-post.tsx @@ -19,17 +19,16 @@ import { store as noticesStore } from '@wordpress/notices'; /** * Internal dependencies */ -import { - TEMPLATE_ORIGINS, - TEMPLATE_PART_POST_TYPE, - TEMPLATE_POST_TYPE, -} from '../../store/constants'; -import { unlock } from '../../lock-unlock'; + +import { unlock } from '../lock-unlock'; import { getItemTitle, isTemplateRemovable, isTemplate, isTemplatePart, + TEMPLATE_ORIGINS, + TEMPLATE_PART_POST_TYPE, + TEMPLATE_POST_TYPE, } from './utils'; import type { CoreDataError, PostWithPermissions } from '../types'; diff --git a/packages/fields/src/actions/base-post/reorder-page.native.tsx b/packages/fields/src/actions/reorder-page.native.tsx similarity index 100% rename from packages/fields/src/actions/base-post/reorder-page.native.tsx rename to packages/fields/src/actions/reorder-page.native.tsx diff --git a/packages/fields/src/actions/base-post/reorder-page.tsx b/packages/fields/src/actions/reorder-page.tsx similarity index 96% rename from packages/fields/src/actions/base-post/reorder-page.tsx rename to packages/fields/src/actions/reorder-page.tsx index 7f3bca59c471c..1820884d8d8c7 100644 --- a/packages/fields/src/actions/base-post/reorder-page.tsx +++ b/packages/fields/src/actions/reorder-page.tsx @@ -17,8 +17,8 @@ import type { Action, RenderModalProps } from '@wordpress/dataviews'; /** * Internal dependencies */ -import type { CoreDataError, BasePost } from '../../types'; -import { orderField } from '../../fields'; +import type { CoreDataError, BasePost } from '../types'; +import { orderField } from '../fields'; const fields = [ orderField ]; const formOrderAction = { diff --git a/packages/fields/src/actions/reset-post.tsx b/packages/fields/src/actions/reset-post.tsx new file mode 100644 index 0000000000000..105d7b283b833 --- /dev/null +++ b/packages/fields/src/actions/reset-post.tsx @@ -0,0 +1,300 @@ +/** + * WordPress dependencies + */ +import { backup } from '@wordpress/icons'; +import { dispatch, select, useDispatch } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; +import { __, sprintf } from '@wordpress/i18n'; +import { store as noticesStore } from '@wordpress/notices'; +import { useState } from '@wordpress/element'; +// @ts-ignore +import { parse, __unstableSerializeAndClean } from '@wordpress/blocks'; +import { + Button, + __experimentalText as Text, + __experimentalHStack as HStack, + __experimentalVStack as VStack, +} from '@wordpress/components'; +import type { Action } from '@wordpress/dataviews'; +import { addQueryArgs } from '@wordpress/url'; +import apiFetch from '@wordpress/api-fetch'; + +/** + * Internal dependencies + */ +import { + getItemTitle, + isTemplateOrTemplatePart, + TEMPLATE_ORIGINS, + TEMPLATE_POST_TYPE, +} from './utils'; +import type { CoreDataError, Template, TemplatePart } from '../types'; + +const isTemplateRevertable = ( + templateOrTemplatePart: Template | TemplatePart +) => { + if ( ! templateOrTemplatePart ) { + return false; + } + + return ( + templateOrTemplatePart.source === TEMPLATE_ORIGINS.custom && + ( Boolean( templateOrTemplatePart?.plugin ) || + templateOrTemplatePart?.has_theme_file ) + ); +}; + +/** + * Copied - pasted from https://github.com/WordPress/gutenberg/blob/bf1462ad37d4637ebbf63270b9c244b23c69e2a8/packages/editor/src/store/private-actions.js#L233-L365 + * + * @param {Object} template The template to revert. + * @param {Object} [options] + * @param {boolean} [options.allowUndo] Whether to allow the user to undo + * reverting the template. Default true. + */ +const revertTemplate = async ( + template: TemplatePart | Template, + { allowUndo = true } = {} +) => { + const noticeId = 'edit-site-template-reverted'; + dispatch( noticesStore ).removeNotice( noticeId ); + if ( ! isTemplateRevertable( template ) ) { + dispatch( noticesStore ).createErrorNotice( + __( 'This template is not revertable.' ), + { + type: 'snackbar', + } + ); + return; + } + + try { + const templateEntityConfig = select( coreStore ).getEntityConfig( + 'postType', + template.type + ); + + if ( ! templateEntityConfig ) { + dispatch( noticesStore ).createErrorNotice( + __( + 'The editor has encountered an unexpected error. Please reload.' + ), + { type: 'snackbar' } + ); + return; + } + + const fileTemplatePath = addQueryArgs( + `${ templateEntityConfig.baseURL }/${ template.id }`, + { context: 'edit', source: template.origin } + ); + + const fileTemplate = ( await apiFetch( { + path: fileTemplatePath, + } ) ) as any; + if ( ! fileTemplate ) { + dispatch( noticesStore ).createErrorNotice( + __( + 'The editor has encountered an unexpected error. Please reload.' + ), + { type: 'snackbar' } + ); + return; + } + + const serializeBlocks = ( { blocks: blocksForSerialization = [] } ) => + __unstableSerializeAndClean( blocksForSerialization ); + + const edited = select( coreStore ).getEditedEntityRecord( + 'postType', + template.type, + template.id + ) as any; + + // We are fixing up the undo level here to make sure we can undo + // the revert in the header toolbar correctly. + dispatch( coreStore ).editEntityRecord( + 'postType', + template.type, + template.id, + { + content: serializeBlocks, // Required to make the `undo` behave correctly. + blocks: edited.blocks, // Required to revert the blocks in the editor. + source: 'custom', // required to avoid turning the editor into a dirty state + }, + { + undoIgnore: true, // Required to merge this edit with the last undo level. + } + ); + + const blocks = parse( fileTemplate?.content?.raw ); + + dispatch( coreStore ).editEntityRecord( + 'postType', + template.type, + fileTemplate.id, + { + content: serializeBlocks, + blocks, + source: 'theme', + } + ); + + if ( allowUndo ) { + const undoRevert = () => { + dispatch( coreStore ).editEntityRecord( + 'postType', + template.type, + edited.id, + { + content: serializeBlocks, + blocks: edited.blocks, + source: 'custom', + } + ); + }; + + dispatch( noticesStore ).createSuccessNotice( + __( 'Template reset.' ), + { + type: 'snackbar', + id: noticeId, + actions: [ + { + label: __( 'Undo' ), + onClick: undoRevert, + }, + ], + } + ); + } + } catch ( error: any ) { + const errorMessage = + error.message && error.code !== 'unknown_error' + ? error.message + : __( 'Template revert failed. Please reload.' ); + + dispatch( noticesStore ).createErrorNotice( errorMessage, { + type: 'snackbar', + } ); + } +}; + +const resetPostAction: Action< Template | TemplatePart > = { + id: 'reset-post', + label: __( 'Reset' ), + isEligible: ( item ) => { + return ( + isTemplateOrTemplatePart( item ) && + item?.source === TEMPLATE_ORIGINS.custom && + ( Boolean( item.type === 'wp_template' && item?.plugin ) || + item?.has_theme_file ) + ); + }, + icon: backup, + supportsBulk: true, + hideModalHeader: true, + RenderModal: ( { items, closeModal, onActionPerformed } ) => { + const [ isBusy, setIsBusy ] = useState( false ); + + const { saveEditedEntityRecord } = useDispatch( coreStore ); + const { createSuccessNotice, createErrorNotice } = + useDispatch( noticesStore ); + const onConfirm = async () => { + try { + for ( const template of items ) { + await revertTemplate( template, { + allowUndo: false, + } ); + await saveEditedEntityRecord( + 'postType', + template.type, + template.id + ); + } + createSuccessNotice( + items.length > 1 + ? sprintf( + /* translators: The number of items. */ + __( '%s items reset.' ), + items.length + ) + : sprintf( + /* translators: The template/part's name. */ + __( '"%s" reset.' ), + getItemTitle( items[ 0 ] ) + ), + { + type: 'snackbar', + id: 'revert-template-action', + } + ); + } catch ( error ) { + let fallbackErrorMessage; + if ( items[ 0 ].type === TEMPLATE_POST_TYPE ) { + fallbackErrorMessage = + items.length === 1 + ? __( + 'An error occurred while reverting the template.' + ) + : __( + 'An error occurred while reverting the templates.' + ); + } else { + fallbackErrorMessage = + items.length === 1 + ? __( + 'An error occurred while reverting the template part.' + ) + : __( + 'An error occurred while reverting the template parts.' + ); + } + + const typedError = error as CoreDataError; + const errorMessage = + typedError.message && typedError.code !== 'unknown_error' + ? typedError.message + : fallbackErrorMessage; + + createErrorNotice( errorMessage, { type: 'snackbar' } ); + } + }; + return ( + + + { __( 'Reset to default and clear all customizations?' ) } + + + + + + + ); + }, +}; + +export default resetPostAction; diff --git a/packages/editor/src/dataviews/actions/restore-post.tsx b/packages/fields/src/actions/restore-post.tsx similarity index 100% rename from packages/editor/src/dataviews/actions/restore-post.tsx rename to packages/fields/src/actions/restore-post.tsx diff --git a/packages/editor/src/dataviews/actions/trash-post.tsx b/packages/fields/src/actions/trash-post.tsx similarity index 100% rename from packages/editor/src/dataviews/actions/trash-post.tsx rename to packages/fields/src/actions/trash-post.tsx diff --git a/packages/fields/src/actions/common/view-post-revisions.tsx b/packages/fields/src/actions/view-post-revisions.tsx similarity index 96% rename from packages/fields/src/actions/common/view-post-revisions.tsx rename to packages/fields/src/actions/view-post-revisions.tsx index 617a5263a707d..875b925b94f07 100644 --- a/packages/fields/src/actions/common/view-post-revisions.tsx +++ b/packages/fields/src/actions/view-post-revisions.tsx @@ -8,7 +8,7 @@ import type { Action } from '@wordpress/dataviews'; /** * Internal dependencies */ -import type { Post } from '../../types'; +import type { Post } from '../types'; const viewPostRevisions: Action< Post > = { id: 'view-post-revisions', diff --git a/packages/fields/src/actions/base-post/view-post.tsx b/packages/fields/src/actions/view-post.tsx similarity index 92% rename from packages/fields/src/actions/base-post/view-post.tsx rename to packages/fields/src/actions/view-post.tsx index 8c581877e473b..187faffafb5d3 100644 --- a/packages/fields/src/actions/base-post/view-post.tsx +++ b/packages/fields/src/actions/view-post.tsx @@ -8,7 +8,7 @@ import type { Action } from '@wordpress/dataviews'; /** * Internal dependencies */ -import type { BasePost } from '../../types'; +import type { BasePost } from '../types'; const viewPost: Action< BasePost > = { id: 'view-post', diff --git a/packages/fields/src/index.native.ts b/packages/fields/src/index.native.ts index e4d3134d72f84..33a26e3c2e6e2 100644 --- a/packages/fields/src/index.native.ts +++ b/packages/fields/src/index.native.ts @@ -1,2 +1,2 @@ -export * from './actions/base-post/duplicate-post.native'; -export * from './actions/base-post/reorder-page.native'; +export * from './actions/duplicate-post.native'; +export * from './actions/reorder-page.native'; diff --git a/packages/fields/src/mutation/index.ts b/packages/fields/src/mutation/index.ts new file mode 100644 index 0000000000000..80e399d74e947 --- /dev/null +++ b/packages/fields/src/mutation/index.ts @@ -0,0 +1,184 @@ +/** + * WordPress dependencies + */ +import { store as noticesStore } from '@wordpress/notices'; +import { store as coreStore } from '@wordpress/core-data'; +import { dispatch } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import type { CoreDataError, Post } from '../types'; + +const getErrorMessagesFromPromises = < T >( + allSettledResults: PromiseSettledResult< T >[] +) => { + const errorMessages = new Set< string >(); + // If there was at lease one failure. + if ( allSettledResults.length === 1 ) { + const typedError = allSettledResults[ 0 ] as { + reason?: CoreDataError; + }; + if ( typedError.reason?.message ) { + errorMessages.add( typedError.reason.message ); + } + } else { + const failedPromises = allSettledResults.filter( + ( { status } ) => status === 'rejected' + ); + for ( const failedPromise of failedPromises ) { + const typedError = failedPromise as { + reason?: CoreDataError; + }; + if ( typedError.reason?.message ) { + errorMessages.add( typedError.reason.message ); + } + } + } + return errorMessages; +}; + +export type NoticeSettings< T extends Post > = { + success: { + id?: string; + type?: string; + messages: { + getMessage: ( posts: T ) => string; + getBatchMessage: ( posts: T[] ) => string; + }; + }; + error: { + id?: string; + type?: string; + messages: { + getMessage: ( errors: Set< string > ) => string; + getBatchMessage: ( errors: Set< string > ) => string; + }; + }; +}; + +export const deletePostWithNotices = async < T extends Post >( + posts: T[], + notice: NoticeSettings< T >, + callbacks: { + onActionPerformed?: ( posts: T[] ) => void; + onActionError?: () => void; + } +) => { + const { createSuccessNotice, createErrorNotice } = dispatch( noticesStore ); + const { deleteEntityRecord } = dispatch( coreStore ); + const allSettledResults = await Promise.allSettled( + posts.map( ( post ) => { + return deleteEntityRecord( + 'postType', + post.type, + post.id, + { force: true }, + { throwOnError: true } + ); + } ) + ); + // If all the promises were fulfilled with success. + if ( allSettledResults.every( ( { status } ) => status === 'fulfilled' ) ) { + let successMessage; + if ( allSettledResults.length === 1 ) { + successMessage = notice.success.messages.getMessage( posts[ 0 ] ); + } else { + successMessage = notice.success.messages.getBatchMessage( posts ); + } + createSuccessNotice( successMessage, { + type: notice.success.type ?? 'snackbar', + id: notice.success.id, + } ); + callbacks.onActionPerformed?.( posts ); + } else { + const errorMessages = getErrorMessagesFromPromises( allSettledResults ); + let errorMessage = ''; + if ( allSettledResults.length === 1 ) { + errorMessage = notice.error.messages.getMessage( errorMessages ); + } else { + errorMessage = + notice.error.messages.getBatchMessage( errorMessages ); + } + + createErrorNotice( errorMessage, { + type: notice.error.type ?? 'snackbar', + id: notice.error.id, + } ); + callbacks.onActionError?.(); + } +}; + +export const editPostWithNotices = async < T extends Post >( + postsWithUpdates: { + originalPost: T; + changes: Partial< T >; + }[], + notice: NoticeSettings< T >, + callbacks: { + onActionPerformed?: ( posts: T[] ) => void; + onActionError?: () => void; + } +) => { + const { createSuccessNotice, createErrorNotice } = dispatch( noticesStore ); + const { editEntityRecord, saveEditedEntityRecord } = dispatch( coreStore ); + await Promise.allSettled( + postsWithUpdates.map( ( post ) => { + return editEntityRecord( + 'postType', + post.originalPost.type, + post.originalPost.id, + { + ...post.changes, + } + ); + } ) + ); + const allSettledResults = await Promise.allSettled( + postsWithUpdates.map( ( post ) => { + return saveEditedEntityRecord( + 'postType', + post.originalPost.type, + post.originalPost.id, + { + throwOnError: true, + } + ); + } ) + ); + // If all the promises were fulfilled with success. + if ( allSettledResults.every( ( { status } ) => status === 'fulfilled' ) ) { + let successMessage; + if ( allSettledResults.length === 1 ) { + successMessage = notice.success.messages.getMessage( + postsWithUpdates[ 0 ].originalPost + ); + } else { + successMessage = notice.success.messages.getBatchMessage( + postsWithUpdates.map( ( post ) => post.originalPost ) + ); + } + createSuccessNotice( successMessage, { + type: notice.success.type ?? 'snackbar', + id: notice.success.id, + } ); + callbacks.onActionPerformed?.( + postsWithUpdates.map( ( post ) => post.originalPost ) + ); + } else { + const errorMessages = getErrorMessagesFromPromises( allSettledResults ); + let errorMessage = ''; + if ( allSettledResults.length === 1 ) { + errorMessage = notice.error.messages.getMessage( errorMessages ); + } else { + errorMessage = + notice.error.messages.getBatchMessage( errorMessages ); + } + + createErrorNotice( errorMessage, { + type: notice.error.type ?? 'snackbar', + id: notice.error.id, + } ); + callbacks.onActionError?.(); + } +}; diff --git a/packages/fields/src/types.ts b/packages/fields/src/types.ts index 664c2dd417201..a5ed9596b07df 100644 --- a/packages/fields/src/types.ts +++ b/packages/fields/src/types.ts @@ -54,6 +54,7 @@ export interface TemplatePart extends CommonPost { has_theme_file: boolean; id: string; area: string; + plugin?: string; } export interface Pattern extends CommonPost { diff --git a/packages/fields/src/wordpress-editor.d.ts b/packages/fields/src/wordpress-editor.d.ts deleted file mode 100644 index 915dacd5f05a9..0000000000000 --- a/packages/fields/src/wordpress-editor.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '@wordpress/editor'; diff --git a/packages/fields/tsconfig.json b/packages/fields/tsconfig.json index c55be59acf40f..69dbd076d0574 100644 --- a/packages/fields/tsconfig.json +++ b/packages/fields/tsconfig.json @@ -7,6 +7,7 @@ "checkJs": false }, "references": [ + { "path": "../api-fetch" }, { "path": "../components" }, { "path": "../compose" }, { "path": "../data" }, @@ -24,6 +25,5 @@ { "path": "../hooks" }, { "path": "../html-entities" } ], - "include": [ "src" ], - "exclude": [ "@wordpress/editor" ] + "include": [ "src" ] } From d21a2d152b39e10b389075b983387598c27de352 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 25 Sep 2024 08:17:15 -0700 Subject: [PATCH 04/25] Block Editor: Don't memoize 'getContentLockingParent' and 'getParentSectionBlock' selectors (#65649) Co-authored-by: Mamaduka Co-authored-by: youknowriad --- .../src/store/private-selectors.js | 66 ++++++------------- 1 file changed, 21 insertions(+), 45 deletions(-) diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index a98c5af93c86a..7af83bed44b0d 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -474,69 +474,45 @@ export function getExpandedBlock( state ) { * with the provided client ID. * * @param {Object} state Global application state. - * @param {Object} clientId Client Id of the block. + * @param {string} clientId Client Id of the block. * * @return {?string} Client ID of the ancestor block that is content locking the block. */ -export const getContentLockingParent = createSelector( - ( state, clientId ) => { - let current = clientId; - let result; - while ( - ! result && - ( current = state.blocks.parents.get( current ) ) - ) { - if ( getTemplateLock( state, current ) === 'contentOnly' ) { - result = current; - } +export const getContentLockingParent = ( state, clientId ) => { + let current = clientId; + let result; + while ( ! result && ( current = state.blocks.parents.get( current ) ) ) { + if ( getTemplateLock( state, current ) === 'contentOnly' ) { + result = current; } - return result; - }, - ( state ) => [ - state.blocks.parents, - state.blockListSettings, - state.settings.templateLock, - ] -); + } + return result; +}; /** * Retrieves the client ID of the parent section block. * * @param {Object} state Global application state. - * @param {Object} clientId Client Id of the block. + * @param {string} clientId Client Id of the block. * * @return {?string} Client ID of the ancestor block that is content locking the block. */ -export const getParentSectionBlock = createSelector( - ( state, clientId ) => { - let current = clientId; - let result; - while ( - ! result && - ( current = state.blocks.parents.get( current ) ) - ) { - if ( isSectionBlock( state, current ) ) { - result = current; - } +export const getParentSectionBlock = ( state, clientId ) => { + let current = clientId; + let result; + while ( ! result && ( current = state.blocks.parents.get( current ) ) ) { + if ( isSectionBlock( state, current ) ) { + result = current; } - return result; - }, - ( state ) => [ - state.blocks.parents, - state.blocks.order, - state.blockListSettings, - state.editorMode, - state.settings.templateLock, - state.blocks.byClientId, - getSectionRootClientId( state ), - ] -); + } + return result; +}; /** * Retrieves the client ID is a content locking parent * * @param {Object} state Global application state. - * @param {Object} clientId Client Id of the block. + * @param {string} clientId Client Id of the block. * * @return {boolean} Whether the block is a content locking parent. */ From 7b5071548fa50a5008303f10351a8ccb6a796fdd Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Thu, 26 Sep 2024 00:39:11 +0900 Subject: [PATCH 05/25] Zoom out: Move the toggle button to before the device preview dropdown (#65446) Co-authored-by: t-hamano Co-authored-by: getdave Co-authored-by: MaggieCabrera Co-authored-by: draganescu Co-authored-by: afercia --- packages/editor/src/components/header/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/editor/src/components/header/index.js b/packages/editor/src/components/header/index.js index aca91daaac732..b5ec9032aac59 100644 --- a/packages/editor/src/components/header/index.js +++ b/packages/editor/src/components/header/index.js @@ -134,6 +134,9 @@ function Header( { */ ) } + + { isEditorIframed && isWideViewport && } + - { isEditorIframed && isWideViewport && } - { ( isWideViewport || ! showIconLabels ) && ( ) } From 0bfec0f91843b993a929e6aafe9548cf07690eea Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Wed, 25 Sep 2024 18:44:30 +0300 Subject: [PATCH 06/25] DatePicker: Use compact button size (#65653) * DatePicker: Use compact button size * CHANGELOG Co-authored-by: tyxla Co-authored-by: ciampo --- packages/components/CHANGELOG.md | 1 + packages/components/src/date-time/date/index.tsx | 2 ++ 2 files changed, 3 insertions(+) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 71aa08d693403..08e1027f3e787 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -10,6 +10,7 @@ ### Enhancements - `MenuGroup`: Simplify the MenuGroup styles within dropdown menus. ([#65561](https://github.com/WordPress/gutenberg/pull/65561)). +- `DatePicker`: Use compact button size. ([#65653](https://github.com/WordPress/gutenberg/pull/65653)). ## 28.8.0 (2024-09-19) diff --git a/packages/components/src/date-time/date/index.tsx b/packages/components/src/date-time/date/index.tsx index 33fc736564d5e..5a565ee38cec5 100644 --- a/packages/components/src/date-time/date/index.tsx +++ b/packages/components/src/date-time/date/index.tsx @@ -125,6 +125,7 @@ export function DatePicker( { ) ); } } + size="compact" /> @@ -150,6 +151,7 @@ export function DatePicker( { ) ); } } + size="compact" /> Date: Thu, 26 Sep 2024 01:23:04 +0900 Subject: [PATCH 07/25] Zoom out: Reset zoom out level when device type is changed (#65652) Co-authored-by: t-hamano Co-authored-by: draganescu Co-authored-by: AhmarZaidi --- packages/editor/src/components/preview-dropdown/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/editor/src/components/preview-dropdown/index.js b/packages/editor/src/components/preview-dropdown/index.js index 38565f4b04abe..0fbb2beb62665 100644 --- a/packages/editor/src/components/preview-dropdown/index.js +++ b/packages/editor/src/components/preview-dropdown/index.js @@ -28,6 +28,7 @@ import { ActionItem } from '@wordpress/interface'; import { store as editorStore } from '../../store'; import { store as blockEditorStore } from '@wordpress/block-editor'; import PostPreviewButton from '../post-preview-button'; +import { unlock } from '../../lock-unlock'; export default function PreviewDropdown( { forceIsAutosaveable, disabled } ) { const { deviceType, homeUrl, isTemplate, isViewable, showIconLabels } = @@ -46,10 +47,12 @@ export default function PreviewDropdown( { forceIsAutosaveable, disabled } ) { }, [] ); const { setDeviceType } = useDispatch( editorStore ); const { __unstableSetEditorMode } = useDispatch( blockEditorStore ); + const { resetZoomLevel } = unlock( useDispatch( blockEditorStore ) ); const handleDevicePreviewChange = ( newDeviceType ) => { setDeviceType( newDeviceType ); __unstableSetEditorMode( 'edit' ); + resetZoomLevel(); }; const isMobile = useViewportMatch( 'medium', '<' ); From c6025de88cd29dc3fe7b1fa528d39a26c1c1fd9a Mon Sep 17 00:00:00 2001 From: Mario Santos <34552881+SantosGuillamot@users.noreply.github.com> Date: Wed, 25 Sep 2024 18:46:33 +0200 Subject: [PATCH 08/25] Use `registry` instead of `select` in `canUserEditValue` (#65659) --- .../src/components/rich-text/index.js | 2 +- packages/block-library/src/button/edit.js | 5 +-- packages/block-library/src/image/edit.js | 5 +-- packages/block-library/src/image/image.js | 9 +++--- packages/editor/src/bindings/post-meta.js | 32 +++++++++++-------- 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index 46ddb2b70a113..1a412a3b2d7eb 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -188,7 +188,7 @@ export function RichTextWrapper( const _disableBoundBlock = ! blockBindingsSource?.canUserEditValue?.( { - select, + registry, context: blockBindingsContext, args: relatedBinding.args, } ); diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index d7b8e6486c3c6..2749199d1092a 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -48,7 +48,7 @@ import { store as blocksStore, } from '@wordpress/blocks'; import { useMergeRefs, useRefEffect } from '@wordpress/compose'; -import { useSelect, useDispatch } from '@wordpress/data'; +import { useSelect, useDispatch, useRegistry } from '@wordpress/data'; const LINK_SETTINGS = [ ...LinkControl.DEFAULT_LINK_SETTINGS, @@ -190,6 +190,7 @@ function ButtonEdit( props ) { const colorProps = useColorProps( attributes ); const spacingProps = useSpacingProps( attributes ); const shadowProps = useShadowProps( attributes ); + const registry = useRegistry(); const ref = useRef(); const richTextRef = useRef(); const blockProps = useBlockProps( { @@ -248,7 +249,7 @@ function ButtonEdit( props ) { lockUrlControls: !! metadata?.bindings?.url && ! blockBindingsSource?.canUserEditValue?.( { - select, + registry, context, args: metadata?.bindings?.url?.args, } ), diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index d44dc73abfd85..454b49dfb58b3 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -9,7 +9,7 @@ import clsx from 'clsx'; import { isBlobURL, createBlobURL } from '@wordpress/blob'; import { store as blocksStore, createBlock } from '@wordpress/blocks'; import { Placeholder } from '@wordpress/components'; -import { useDispatch, useSelect } from '@wordpress/data'; +import { useDispatch, useSelect, useRegistry } from '@wordpress/data'; import { BlockIcon, useBlockProps, @@ -113,6 +113,7 @@ export function ImageEdit( { const [ temporaryURL, setTemporaryURL ] = useState( attributes.blob ); + const registry = useRegistry(); const containerRef = useRef(); // Only observe the max width from the parent container when the parent layout is not flex nor grid. // This won't work for them because the container width changes with the image. @@ -380,7 +381,7 @@ export function ImageEdit( { lockUrlControls: !! metadata?.bindings?.url && ! blockBindingsSource?.canUserEditValue?.( { - select, + registry, context, args: metadata?.bindings?.url?.args, } ), diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index 1673d36e463d5..f0d2f00a68d53 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -17,7 +17,7 @@ import { Placeholder, } from '@wordpress/components'; import { useViewportMatch } from '@wordpress/compose'; -import { useSelect, useDispatch } from '@wordpress/data'; +import { useSelect, useDispatch, useRegistry } from '@wordpress/data'; import { BlockControls, InspectorControls, @@ -134,6 +134,7 @@ export default function Image( { const numericWidth = width ? parseInt( width, 10 ) : undefined; const numericHeight = height ? parseInt( height, 10 ) : undefined; + const registry = useRegistry(); const imageRef = useRef(); const { allowResize = true } = context; const { getBlock, getSettings } = useSelect( blockEditorStore ); @@ -496,7 +497,7 @@ export default function Image( { lockUrlControls: !! urlBinding && ! urlBindingSource?.canUserEditValue?.( { - select, + registry, context, args: urlBinding?.args, } ), @@ -511,7 +512,7 @@ export default function Image( { lockAltControls: !! altBinding && ! altBindingSource?.canUserEditValue?.( { - select, + registry, context, args: altBinding?.args, } ), @@ -525,7 +526,7 @@ export default function Image( { lockTitleControls: !! titleBinding && ! titleBindingSource?.canUserEditValue?.( { - select, + registry, context, args: titleBinding?.args, } ), diff --git a/packages/editor/src/bindings/post-meta.js b/packages/editor/src/bindings/post-meta.js index fae010e72d1c8..4cd05f594daf7 100644 --- a/packages/editor/src/bindings/post-meta.js +++ b/packages/editor/src/bindings/post-meta.js @@ -99,14 +99,15 @@ export default { meta: newMeta, } ); }, - canUserEditValue( { select, context, args } ) { + canUserEditValue( { registry, context, args } ) { // Lock editing in query loop. if ( context?.query || context?.queryId ) { return false; } const postType = - context?.postType || select( editorStore ).getCurrentPostType(); + context?.postType || + registry.select( editorStore ).getCurrentPostType(); // Check that editing is happening in the post editor and not a template. if ( postType === 'wp_template' ) { @@ -115,28 +116,31 @@ export default { // Check that the custom field is not protected and available in the REST API. // Empty string or `false` could be a valid value, so we need to check if the field value is undefined. - const fieldValue = select( coreDataStore ).getEntityRecord( - 'postType', - postType, - context?.postId - )?.meta?.[ args.key ]; + const fieldValue = registry + .select( coreDataStore ) + .getEntityRecord( 'postType', postType, context?.postId )?.meta?.[ + args.key + ]; if ( fieldValue === undefined ) { return false; } // Check that custom fields metabox is not enabled. - const areCustomFieldsEnabled = - select( editorStore ).getEditorSettings().enableCustomFields; + const areCustomFieldsEnabled = registry + .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', { - kind: 'postType', - name: context?.postType, - id: context?.postId, - } ); + const canUserEdit = registry + .select( coreDataStore ) + .canUser( 'update', { + kind: 'postType', + name: context?.postType, + id: context?.postId, + } ); if ( ! canUserEdit ) { return false; } From 05607f785ea7c653ef831a15e6b28985ae0fbd2a Mon Sep 17 00:00:00 2001 From: Cris Busquets Date: Wed, 25 Sep 2024 18:49:13 +0200 Subject: [PATCH 09/25] Adds envelope icon (#65638) Co-authored-by: crisbusquets --- packages/icons/CHANGELOG.md | 2 ++ packages/icons/src/index.js | 1 + packages/icons/src/library/envelope.js | 16 ++++++++++++++++ 3 files changed, 19 insertions(+) create mode 100644 packages/icons/src/library/envelope.js diff --git a/packages/icons/CHANGELOG.md b/packages/icons/CHANGELOG.md index be047e2181d4a..08c7ab95b4b4a 100644 --- a/packages/icons/CHANGELOG.md +++ b/packages/icons/CHANGELOG.md @@ -6,6 +6,8 @@ ### New Features +- Add new `envelope` icon. + - Add new `bell` and `bell-unread` icons. ## 10.7.0 (2024-09-05) diff --git a/packages/icons/src/index.js b/packages/icons/src/index.js index 9ab41bd362027..e61be2cc86bcd 100644 --- a/packages/icons/src/index.js +++ b/packages/icons/src/index.js @@ -79,6 +79,7 @@ export { default as drawerLeft } from './library/drawer-left'; export { default as drawerRight } from './library/drawer-right'; export { default as download } from './library/download'; export { default as edit } from './library/edit'; +export { default as envelope } from './library/envelope'; export { default as external } from './library/external'; export { default as file } from './library/file'; export { default as filter } from './library/filter'; diff --git a/packages/icons/src/library/envelope.js b/packages/icons/src/library/envelope.js new file mode 100644 index 0000000000000..45064b35785ec --- /dev/null +++ b/packages/icons/src/library/envelope.js @@ -0,0 +1,16 @@ +/** + * WordPress dependencies + */ +import { SVG, Path } from '@wordpress/primitives'; + +const envelope = ( + + + +); + +export default envelope; From 79a8904156237b9121feb10bd06886ff32115f66 Mon Sep 17 00:00:00 2001 From: Vipul Gupta <55375170+vipul0425@users.noreply.github.com> Date: Wed, 25 Sep 2024 22:20:18 +0530 Subject: [PATCH 10/25] Fix: Button Replace remaining 40px default size violations [Block Directory] (#65467) * fix: The button height for install button and keep as HTML. * Refactor downloadable list item to vanilla button * Remove unnecessary comment * Update package-lock.json --------- Co-authored-by: vipul0425 Co-authored-by: ciampo Co-authored-by: tyxla --- package-lock.json | 6 +- packages/block-directory/package.json | 3 +- .../downloadable-block-list-item/index.js | 137 +++++++++--------- .../downloadable-block-list-item/style.scss | 33 +++-- .../downloadable-blocks-panel/style.scss | 3 - .../src/plugins/get-install-missing/index.js | 3 +- .../get-install-missing/install-button.js | 3 +- 7 files changed, 101 insertions(+), 87 deletions(-) diff --git a/package-lock.json b/package-lock.json index 93da356b222be..c13e4cf2096cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52730,7 +52730,8 @@ "@wordpress/plugins": "file:../plugins", "@wordpress/private-apis": "file:../private-apis", "@wordpress/url": "file:../url", - "change-case": "^4.1.2" + "change-case": "^4.1.2", + "clsx": "^2.1.1" }, "engines": { "node": ">=18.12.0", @@ -67941,7 +67942,8 @@ "@wordpress/plugins": "file:../plugins", "@wordpress/private-apis": "file:../private-apis", "@wordpress/url": "file:../url", - "change-case": "^4.1.2" + "change-case": "^4.1.2", + "clsx": "^2.1.1" } }, "@wordpress/block-editor": { diff --git a/packages/block-directory/package.json b/packages/block-directory/package.json index beef057bf05f0..974125a5f3f2c 100644 --- a/packages/block-directory/package.json +++ b/packages/block-directory/package.json @@ -45,7 +45,8 @@ "@wordpress/plugins": "file:../plugins", "@wordpress/private-apis": "file:../private-apis", "@wordpress/url": "file:../url", - "change-case": "^4.1.2" + "change-case": "^4.1.2", + "clsx": "^2.1.1" }, "peerDependencies": { "react": "^18.0.0", 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 ac587dc2d6d0c..7a5f479174ab2 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 @@ -1,9 +1,14 @@ +/** + * External dependencies + */ +import clsx from 'clsx'; + /** * WordPress dependencies */ import { __, _n, sprintf } from '@wordpress/i18n'; import { - Button, + Tooltip, Spinner, VisuallyHidden, Composite, @@ -89,77 +94,75 @@ function DownloadableBlockListItem( { item, onClick } ) { statusText = __( 'Installing…' ); } + const itemLabel = getDownloadableBlockLabel( item, { + hasNotice, + isInstalled, + isInstalling, + } ); + return ( - { - event.preventDefault(); - onClick(); - } } - label={ getDownloadableBlockLabel( item, { - hasNotice, - isInstalled, - isInstalling, - } ) } - showTooltip - tooltipPosition="top center" - /> - } - disabled={ isInstalling || ! isInstallable } - > -
- - { isInstalling ? ( - - - - ) : ( - + + - - - { createInterpolateElement( - sprintf( - /* translators: %1$s: block title, %2$s: author name. */ - __( '%1$s by %2$s' ), - decodeEntities( title ), - author - ), - { - span: ( - + accessibleWhenDisabled + disabled={ isInstalling || ! isInstallable } + onClick={ ( event ) => { + event.preventDefault(); + onClick(); + } } + aria-label={ itemLabel } + type="button" + role="option" + > +
+ + { isInstalling ? ( + + + + ) : ( + + ) } +
+ + + { createInterpolateElement( + sprintf( + /* translators: %1$s: block title, %2$s: author name. */ + __( '%1$s by %2$s' ), + decodeEntities( title ), + author ), - } + { + span: ( + + ), + } + ) } + + { hasNotice ? ( + + ) : ( + <> + + { !! statusText + ? statusText + : decodeEntities( description ) } + + { isInstallable && + ! ( isInstalled || isInstalling ) && ( + + { __( 'Install block' ) } + + ) } + ) } - { hasNotice ? ( - - ) : ( - <> - - { !! statusText - ? statusText - : decodeEntities( description ) } - - { isInstallable && - ! ( isInstalled || isInstalling ) && ( - - { __( 'Install block' ) } - - ) } - - ) } - -
+ +
); } diff --git a/packages/block-directory/src/components/downloadable-block-list-item/style.scss b/packages/block-directory/src/components/downloadable-block-list-item/style.scss index 8f95297bd9ef0..fa5e5906cb1b9 100644 --- a/packages/block-directory/src/components/downloadable-block-list-item/style.scss +++ b/packages/block-directory/src/components/downloadable-block-list-item/style.scss @@ -1,10 +1,21 @@ .block-directory-downloadable-block-list-item { - padding: $grid-unit-15; + & + & { + margin-top: $grid-unit-05; + } + + display: grid; + grid-template-columns: auto 1fr; + width: 100%; height: auto; + padding: $grid-unit-15; + margin: 0; + + appearance: none; + background: none; + border: 0; text-align: left; - display: grid; - grid-template-columns: auto 1fr; + transition: box-shadow 0.1s linear; // The item contains absolutely positioned items. // Set `position: relative` on the parent to prevent overflow issues @@ -12,13 +23,20 @@ // See: https://github.com/WordPress/gutenberg/issues/63384 position: relative; + + &:not([aria-disabled="true"]) { + cursor: pointer; + } + &:hover { @include button-style__focus(); } - &.is-busy { - background: transparent; + &[data-focus-visible] { + @include button-style__focus(); + } + &.is-installing { .block-directory-downloadable-block-list-item__author { border: 0; clip: rect(1px, 1px, 1px, 1px); @@ -33,11 +51,6 @@ word-wrap: normal !important; } } - - &:disabled, - &[aria-disabled] { - opacity: 1; - } } .block-directory-downloadable-block-list-item__icon { diff --git a/packages/block-directory/src/components/downloadable-blocks-panel/style.scss b/packages/block-directory/src/components/downloadable-blocks-panel/style.scss index ff3fdb9ea8e31..f4df5ad4abda5 100644 --- a/packages/block-directory/src/components/downloadable-blocks-panel/style.scss +++ b/packages/block-directory/src/components/downloadable-blocks-panel/style.scss @@ -32,6 +32,3 @@ margin-top: 0; } -.block-directory-downloadable-blocks-panel button { - margin-top: $grid-unit-05; -} diff --git a/packages/block-directory/src/plugins/get-install-missing/index.js b/packages/block-directory/src/plugins/get-install-missing/index.js index 8b192cbe8fdc4..43c051cb9aa37 100644 --- a/packages/block-directory/src/plugins/get-install-missing/index.js +++ b/packages/block-directory/src/plugins/get-install-missing/index.js @@ -101,8 +101,7 @@ const ModifiedWarning = ( { originalBlock, ...props } ) => { ); actions.push( - } - /> - ) ) } + + + + ) + ) } diff --git a/packages/block-editor/src/components/inspector-popover-header/index.js b/packages/block-editor/src/components/inspector-popover-header/index.js index d543ab0298cc6..cf6bf0d3d6796 100644 --- a/packages/block-editor/src/components/inspector-popover-header/index.js +++ b/packages/block-editor/src/components/inspector-popover-header/index.js @@ -31,8 +31,7 @@ export default function InspectorPopoverHeader( { { actions.map( ( { label, icon, onClick } ) => ( + ); } diff --git a/packages/block-editor/src/components/list-view/style.scss b/packages/block-editor/src/components/list-view/style.scss index 3ad6d3bd4aab5..297fb9d0a6a2e 100644 --- a/packages/block-editor/src/components/list-view/style.scss +++ b/packages/block-editor/src/components/list-view/style.scss @@ -216,6 +216,15 @@ text-align: left; position: relative; white-space: nowrap; + border-radius: 2px; + box-sizing: border-box; + color: inherit; + font-family: inherit; + font-size: 13px; + font-weight: 400; + margin: 0; + text-decoration: none; + transition: box-shadow 0.1s linear; .components-modal__content & { padding-left: 0; diff --git a/packages/block-editor/src/components/media-placeholder/index.js b/packages/block-editor/src/components/media-placeholder/index.js index 4d41289f324c0..9482c9f418174 100644 --- a/packages/block-editor/src/components/media-placeholder/index.js +++ b/packages/block-editor/src/components/media-placeholder/index.js @@ -87,8 +87,7 @@ const URLSelectionUI = ( { src, onChangeSrc, onSelectURL } ) => { return (