Skip to content

Commit

Permalink
Add support for hierarchical block instance look up
Browse files Browse the repository at this point in the history
  • Loading branch information
oandregal committed Apr 26, 2022
1 parent ff74799 commit 5b81fc8
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 36 deletions.
6 changes: 4 additions & 2 deletions packages/block-editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -762,8 +762,10 @@ _Parameters_

### useSetting

Hook that retrieves the editor setting.
It works with nested objects using by finding the value at path.
Hook that retrieves the given setting for the block instance in use.

It looks up the settings first in the block instance hierarchy.
If none is found, it'll look it up in the block editor store.

_Usage_

Expand Down
87 changes: 53 additions & 34 deletions packages/block-editor/src/components/use-setting/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import { get } from 'lodash';
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { __EXPERIMENTAL_PATHS_WITH_MERGE as PATHS_WITH_MERGE } from '@wordpress/blocks';
import {
__EXPERIMENTAL_PATHS_WITH_MERGE as PATHS_WITH_MERGE,
hasBlockSupport,
} from '@wordpress/blocks';

/**
* Internal dependencies
Expand Down Expand Up @@ -91,8 +94,10 @@ const removeCustomPrefixes = ( path ) => {
};

/**
* Hook that retrieves the editor setting.
* It works with nested objects using by finding the value at path.
* Hook that retrieves the given setting for the block instance in use.
*
* It looks up the settings first in the block instance hierarchy.
* If none is found, it'll look it up in the block editor store.
*
* @param {string} path The path to the setting.
* @return {any} Returns the value defined for the setting.
Expand All @@ -113,55 +118,69 @@ export default function useSetting( path ) {
);
return undefined;
}
const settings = select( blockEditorStore ).getSettings();

// 0 - Use settings for this block instance, if there's any.
// Also, look up in the block hierarchy.
// todo: only check if the block type has support for settings to minimize the queries we make
// todo: how do we provide i18n for the presets defined by block instances? In PHP, they already do i18n.
// todo: the presets defined in a block instance are "custom" ones;
// remove the need for users to provide the custom key.
const blockAtts = select( blockEditorStore ).getBlockAttributes(
clientId
);

// 1 - Use __experimental features, if available.
// We cascade to the all value if the block one is not available.
let result;
const normalizedPath = removeCustomPrefixes( path );
const defaultsPath = `__experimentalFeatures.${ normalizedPath }`;
const blockPath = `__experimentalFeatures.blocks.${ blockName }.${ normalizedPath }`;
const blockInstancePath = `settings.${ normalizedPath }`;
const experimentalFeaturesResult =
get( blockAtts, blockInstancePath ) ??
get( settings, blockPath ) ??
get( settings, defaultsPath );

if ( experimentalFeaturesResult !== undefined ) {

// 1. Take settings from the block instance or its ancestors.
const candidates = [
...select( blockEditorStore ).getBlockParents( clientId ),
clientId, // The current block is added last, so it overwrites any ancestor.
];
candidates.forEach( ( candidateClientId ) => {
const candidateBlockName = select(
blockEditorStore
).getBlockName( candidateClientId );
if (
hasBlockSupport( candidateBlockName, 'settings', false )
) {
const candidateAtts = select(
blockEditorStore
).getBlockAttributes( candidateClientId );
const candidateResult =
get(
candidateAtts,
`settings.blocks.${ blockName }.${ normalizedPath }`
) ??
get( candidateAtts, `settings.${ normalizedPath }` );
if ( candidateResult !== undefined ) {
result = candidateResult;
}
}
} );

// 2. Fall back to the settings from the block editor store (__experimentalFeatures).
const settings = select( blockEditorStore ).getSettings();
if ( result === undefined ) {
const defaultsPath = `__experimentalFeatures.${ normalizedPath }`;
const blockPath = `__experimentalFeatures.blocks.${ blockName }.${ normalizedPath }`;
result =
get( settings, blockPath ) ?? get( settings, defaultsPath );
}

// Return if the setting was found in either the block instance or the store.
if ( result !== undefined ) {
if ( PATHS_WITH_MERGE[ normalizedPath ] ) {
return (
experimentalFeaturesResult.custom ??
experimentalFeaturesResult.theme ??
experimentalFeaturesResult.default
);
return result.custom ?? result.theme ?? result.default;
}
return experimentalFeaturesResult;
return result;
}

// 2 - Use deprecated settings, otherwise.
// 3. Otherwise, use deprecated settings.
const deprecatedSettingsValue = deprecatedFlags[ normalizedPath ]
? deprecatedFlags[ normalizedPath ]( settings )
: undefined;
if ( deprecatedSettingsValue !== undefined ) {
return deprecatedSettingsValue;
}

// 3 - Fall back for typography.dropCap:
// 4. Fallback for typography.dropCap:
// This is only necessary to support typography.dropCap.
// when __experimentalFeatures are not present (core without plugin).
// To remove when __experimentalFeatures are ported to core.
return normalizedPath === 'typography.dropCap' ? true : undefined;
},
[ blockName, path ]
[ blockName, clientId, path ]
);

return setting;
Expand Down

0 comments on commit 5b81fc8

Please sign in to comment.