Skip to content

Commit

Permalink
Add settings hook (#40547)
Browse files Browse the repository at this point in the history
Co-authored-by: Miguel Fonseca <[email protected]>
  • Loading branch information
oandregal and mcsf authored Apr 29, 2022
1 parent a7e433a commit ea06ebc
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 23 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
78 changes: 57 additions & 21 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 @@ -102,7 +107,7 @@ const removeCustomPrefixes = ( path ) => {
* ```
*/
export default function useSetting( path ) {
const { name: blockName } = useBlockEditContext();
const { name: blockName, clientId } = useBlockEditContext();

const setting = useSelect(
( select ) => {
Expand All @@ -113,42 +118,73 @@ export default function useSetting( path ) {
);
return undefined;
}
const settings = select( blockEditorStore ).getSettings();

// 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 experimentalFeaturesResult =
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,
'__experimentalSettings',
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
1 change: 1 addition & 0 deletions packages/block-editor/src/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import './anchor';
import './custom-class-name';
import './generated-class-name';
import './style';
import './settings';
import './color';
import './duotone';
import './font-size';
Expand Down
32 changes: 32 additions & 0 deletions packages/block-editor/src/hooks/settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* WordPress dependencies
*/
import { addFilter } from '@wordpress/hooks';
import { hasBlockSupport } from '@wordpress/blocks';

const hasSettingsSupport = ( blockType ) =>
hasBlockSupport( blockType, '__experimentalSettings', false );

function addAttribute( settings ) {
if ( ! hasSettingsSupport( settings ) ) {
return settings;
}

// Allow blocks to specify their own attribute definition with default values if needed.
if ( ! settings?.attributes?.settings ) {
settings.attributes = {
...settings.attributes,
settings: {
type: 'object',
},
};
}

return settings;
}

addFilter(
'blocks.registerBlockType',
'core/settings/addAttribute',
addAttribute
);
48 changes: 48 additions & 0 deletions packages/block-editor/src/hooks/test/settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* WordPress dependencies
*/
import { applyFilters } from '@wordpress/hooks';

/**
* Internal dependencies
*/
import '../settings';

describe( 'with settings', () => {
const blockSettings = {
save: () => <div className="default" />,
category: 'text',
title: 'block title',
};

describe( 'addAttribute', () => {
const addAttribute = applyFilters.bind(
null,
'blocks.registerBlockType'
);

it( 'does not have settings att if settings block support is not enabled', () => {
const settings = addAttribute( {
...blockSettings,
supports: {
__experimentalSettings: false,
},
} );

expect( settings.attributes ).toBe( undefined );
} );

it( 'has settings att if settings block supports is enabled', () => {
const settings = addAttribute( {
...blockSettings,
supports: {
__experimentalSettings: true,
},
} );

expect( settings.attributes ).toStrictEqual( {
settings: { type: 'object' },
} );
} );
} );
} );
1 change: 1 addition & 0 deletions packages/block-library/src/group/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
}
},
"supports": {
"__experimentalSettings": true,
"align": [ "wide", "full" ],
"anchor": true,
"html": false,
Expand Down

0 comments on commit ea06ebc

Please sign in to comment.