diff --git a/package-lock.json b/package-lock.json index 1a4684312d137e..7ad9d9ff111d82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54209,6 +54209,8 @@ "@wordpress/wordcount": "file:../wordcount", "clsx": "^2.1.1", "date-fns": "^3.6.0", + "deepmerge": "^4.3.0", + "is-plain-object": "^5.0.0", "memize": "^2.1.0", "react-autosize-textarea": "^7.1.0", "remove-accents": "^0.5.0" @@ -69285,6 +69287,8 @@ "@wordpress/wordcount": "file:../wordcount", "clsx": "^2.1.1", "date-fns": "^3.6.0", + "deepmerge": "^4.3.0", + "is-plain-object": "^5.0.0", "memize": "^2.1.0", "react-autosize-textarea": "^7.1.0", "remove-accents": "^0.5.0" diff --git a/packages/block-editor/src/private-apis.js b/packages/block-editor/src/private-apis.js index f10fcc4df2c726..29cc5eecc37531 100644 --- a/packages/block-editor/src/private-apis.js +++ b/packages/block-editor/src/private-apis.js @@ -35,6 +35,7 @@ import { useFlashEditableBlocks } from './components/use-flash-editable-blocks'; import { selectBlockPatternsKey, reusableBlocksSelectKey, + globalStylesDataKey, } from './store/private-keys'; import { requiresWrapperOnCopy } from './components/writing-flow/utils'; import { PrivateRichText } from './components/rich-text/'; @@ -72,6 +73,7 @@ lock( privateApis, { useReusableBlocksRenameHint, usesContextKey, useFlashEditableBlocks, + globalStylesDataKey, selectBlockPatternsKey, requiresWrapperOnCopy, PrivateRichText, diff --git a/packages/block-editor/src/store/private-keys.js b/packages/block-editor/src/store/private-keys.js index f48612e7491c9c..82264ebe191579 100644 --- a/packages/block-editor/src/store/private-keys.js +++ b/packages/block-editor/src/store/private-keys.js @@ -1,2 +1,3 @@ +export const globalStylesDataKey = Symbol( 'globalStylesDataKey' ); export const selectBlockPatternsKey = Symbol( 'selectBlockPatternsKey' ); export const reusableBlocksSelectKey = Symbol( 'reusableBlocksSelect' ); diff --git a/packages/editor/package.json b/packages/editor/package.json index bab3a2c29107c0..65fa7deae1828c 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -66,6 +66,8 @@ "@wordpress/wordcount": "file:../wordcount", "clsx": "^2.1.1", "date-fns": "^3.6.0", + "deepmerge": "^4.3.0", + "is-plain-object": "^5.0.0", "memize": "^2.1.0", "react-autosize-textarea": "^7.1.0", "remove-accents": "^0.5.0" diff --git a/packages/editor/src/components/provider/use-block-editor-settings.js b/packages/editor/src/components/provider/use-block-editor-settings.js index 4d51025aed567a..3bdc01cb13c0ab 100644 --- a/packages/editor/src/components/provider/use-block-editor-settings.js +++ b/packages/editor/src/components/provider/use-block-editor-settings.js @@ -24,6 +24,7 @@ import inserterMediaCategories from '../media-categories'; import { mediaUpload } from '../../utils'; import { store as editorStore } from '../../store'; import { lock, unlock } from '../../lock-unlock'; +import { useGlobalStylesData } from '../use-global-styles-data'; const EMPTY_BLOCKS_LIST = []; @@ -173,6 +174,8 @@ function useBlockEditorSettings( settings, postType, postId, renderingMode ) { [ postType, postId, isLargeViewport, renderingMode ] ); + const { styles: globalStylesData } = useGlobalStylesData(); + const settingsBlockPatterns = settings.__experimentalAdditionalBlockPatterns ?? // WP 6.0 settings.__experimentalBlockPatterns; // WP 5.9 @@ -251,6 +254,8 @@ function useBlockEditorSettings( settings, postType, postId, renderingMode ) { }, [ settings.allowedBlockTypes, hiddenBlockTypes, blockTypes ] ); const forceDisableFocusMode = settings.focusMode === false; + const { globalStylesDataKey, selectBlockPatternsKey } = + unlock( privateApis ); return useMemo( () => { const blockEditorSettings = { @@ -259,6 +264,7 @@ function useBlockEditorSettings( settings, postType, postId, renderingMode ) { BLOCK_EDITOR_SETTINGS.includes( key ) ) ), + [ globalStylesDataKey ]: globalStylesData, allowedBlockTypes, allowRightClickOverrides, focusMode: focusMode && ! forceDisableFocusMode, @@ -267,7 +273,7 @@ function useBlockEditorSettings( settings, postType, postId, renderingMode ) { keepCaretInsideBlock, mediaUpload: hasUploadPermissions ? mediaUpload : undefined, __experimentalBlockPatterns: blockPatterns, - [ unlock( privateApis ).selectBlockPatternsKey ]: ( select ) => { + [ selectBlockPatternsKey ]: ( select ) => { const { hasFinishedResolution, getBlockPatternsForPostType } = unlock( select( coreStore ) ); const patterns = getBlockPatternsForPostType( postType ); @@ -331,6 +337,9 @@ function useBlockEditorSettings( settings, postType, postId, renderingMode ) { postType, setIsInserterOpened, sectionRootClientId, + globalStylesData, + globalStylesDataKey, + selectBlockPatternsKey, ] ); } diff --git a/packages/editor/src/components/use-global-styles-data/index.js b/packages/editor/src/components/use-global-styles-data/index.js new file mode 100644 index 00000000000000..8553fa90ad1aba --- /dev/null +++ b/packages/editor/src/components/use-global-styles-data/index.js @@ -0,0 +1,77 @@ +/** + * External dependencies + */ +import deepmerge from 'deepmerge'; +import { isPlainObject } from 'is-plain-object'; + +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { useMemo } from '@wordpress/element'; +import { store as coreStore } from '@wordpress/core-data'; + +const DEFAULT_STYLES = {}; + +function useGlobalStylesBaseData() { + const baseConfig = useSelect( ( select ) => { + return select( + coreStore + ).__experimentalGetCurrentThemeBaseGlobalStyles(); + }, [] ); + + return [ !! baseConfig, baseConfig?.styles ?? DEFAULT_STYLES ]; +} + +function useGlobalStylesUserData() { + return useSelect( ( select ) => { + const { + getEditedEntityRecord, + hasFinishedResolution, + __experimentalGetCurrentGlobalStylesId, + } = select( coreStore ); + + const globalStylesId = __experimentalGetCurrentGlobalStylesId(); + const record = globalStylesId + ? getEditedEntityRecord( 'root', 'globalStyles', globalStylesId ) + : undefined; + + let hasResolved = false; + if ( + hasFinishedResolution( '__experimentalGetCurrentGlobalStylesId' ) + ) { + hasResolved = globalStylesId + ? hasFinishedResolution( 'getEditedEntityRecord', [ + 'root', + 'globalStyles', + globalStylesId, + ] ) + : true; + } + + return [ hasResolved, record?.styles ?? DEFAULT_STYLES ]; + }, [] ); +} + +function mergeBaseAndUserStyles( base, user ) { + return deepmerge( base, user, { + // We only pass as arrays the presets, + // in which case we want the new array of values + // to override the old array (no merging). + isMergeableObject: isPlainObject, + } ); +} + +export function useGlobalStylesData() { + const [ isBaseStylesReady, baseStyles ] = useGlobalStylesBaseData(); + const [ isUserStylesReady, userStyles ] = useGlobalStylesUserData(); + const mergedStyles = useMemo( + () => mergeBaseAndUserStyles( baseStyles, userStyles ), + [ baseStyles, userStyles ] + ); + + return { + isReady: isBaseStylesReady && isUserStylesReady, + styles: mergedStyles, + }; +}