Skip to content

Commit

Permalink
Extract the getSupportedStyles selector to the blocks store as a priv…
Browse files Browse the repository at this point in the history
…ate selector (#47606)
  • Loading branch information
youknowriad authored Feb 3, 2023
1 parent 581eabf commit ddcaa70
Show file tree
Hide file tree
Showing 20 changed files with 432 additions and 206 deletions.
3 changes: 2 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/blocks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@wordpress/deprecated": "file:../deprecated",
"@wordpress/dom": "file:../dom",
"@wordpress/element": "file:../element",
"@wordpress/experiments": "file:../experiments",
"@wordpress/hooks": "file:../hooks",
"@wordpress/html-entities": "file:../html-entities",
"@wordpress/i18n": "file:../i18n",
Expand Down
55 changes: 18 additions & 37 deletions packages/blocks/src/api/raw-handling/test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,15 @@
*/
import deepFreeze from 'deep-freeze';

/**
* WordPress dependencies
*/
import { registerBlockType, unregisterBlockType } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import { getBlockContentSchemaFromTransforms, isPlain } from '../utils';
import { store as mockStore } from '../../../store';
import { STORE_NAME as mockStoreName } from '../../../store/constants';

jest.mock( '@wordpress/data', () => {
return {
select: jest.fn( ( store ) => {
switch ( store ) {
case [ mockStoreName ]:
case mockStore: {
return {
hasBlockSupport: ( blockName, supports ) => {
return (
blockName === 'core/paragraph' &&
supports === 'anchor'
);
},
};
}
}
} ),
combineReducers: () => {
const mock = jest.fn();
return mock;
},
createReduxStore: () => {
const mock = jest.fn();
return mock;
},
register: () => {
const mock = jest.fn();
return mock;
},
createRegistryControl() {
return jest.fn();
},
};
} );

describe( 'isPlain', () => {
it( 'should return true for plain text', () => {
Expand All @@ -65,6 +33,19 @@ describe( 'isPlain', () => {
} );

describe( 'getBlockContentSchema', () => {
beforeAll( () => {
registerBlockType( 'core/paragraph', {
title: 'Paragraph',
supports: {
anchor: true,
},
} );
} );

afterAll( () => {
unregisterBlockType( 'core/paragraph' );
} );

const myContentSchema = {
strong: {},
em: {},
Expand Down
10 changes: 10 additions & 0 deletions packages/blocks/src/experiments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* WordPress dependencies
*/
import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/experiments';

export const { lock, unlock } =
__dangerousOptInToUnstableAPIsOnlyForCoreModules(
'I know using unstable features means my plugin or theme will inevitably break on the next WordPress release.',
'@wordpress/blocks'
);
3 changes: 3 additions & 0 deletions packages/blocks/src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import { createReduxStore, register } from '@wordpress/data';
*/
import reducer from './reducer';
import * as selectors from './selectors';
import * as privateSelectors from './private-selectors';
import * as actions from './actions';
import { STORE_NAME } from './constants';
import { unlock } from '../experiments';

/**
* Store definition for the blocks namespace.
Expand All @@ -25,3 +27,4 @@ export const store = createReduxStore( STORE_NAME, {
} );

register( store );
unlock( store ).registerPrivateSelectors( privateSelectors );
155 changes: 155 additions & 0 deletions packages/blocks/src/store/private-selectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/**
* External dependencies
*/
import createSelector from 'rememo';
import { get } from 'lodash';

/**
* Internal dependencies
*/
import { getBlockType } from './selectors';
import { __EXPERIMENTAL_STYLE_PROPERTY as STYLE_PROPERTY } from '../api/constants';

const ROOT_BLOCK_SUPPORTS = [
'background',
'backgroundColor',
'color',
'linkColor',
'buttonColor',
'fontFamily',
'fontSize',
'fontStyle',
'fontWeight',
'lineHeight',
'padding',
'contentSize',
'wideSize',
'blockGap',
'textDecoration',
'textTransform',
'letterSpacing',
];

/**
* Filters the list of supported styles for a given element.
*
* @param {string[]} blockSupports list of supported styles.
* @param {string|undefined} name block name.
* @param {string|undefined} element element name.
*
* @return {string[]} filtered list of supported styles.
*/
function filterElementBlockSupports( blockSupports, name, element ) {
return blockSupports.filter( ( support ) => {
if ( support === 'fontSize' && element === 'heading' ) {
return false;
}

// This is only available for links
if ( support === 'textDecoration' && ! name && element !== 'link' ) {
return false;
}

// This is only available for heading
if (
support === 'textTransform' &&
! name &&
! [ 'heading', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ].includes(
element
)
) {
return false;
}

// This is only available for headings
if (
support === 'letterSpacing' &&
! name &&
! [ 'heading', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ].includes(
element
)
) {
return false;
}

return true;
} );
}

/**
* Returns the list of supported styles for a given block name and element.
*/
export const getSupportedStyles = createSelector(
( state, name, element ) => {
if ( ! name ) {
return filterElementBlockSupports(
ROOT_BLOCK_SUPPORTS,
name,
element
);
}

const blockType = getBlockType( state, name );

if ( ! blockType ) {
return [];
}

const supportKeys = [];

// Check for blockGap support.
// Block spacing support doesn't map directly to a single style property, so needs to be handled separately.
// Also, only allow `blockGap` support if serialization has not been skipped, to be sure global spacing can be applied.
if (
blockType?.supports?.spacing?.blockGap &&
blockType?.supports?.spacing?.__experimentalSkipSerialization !==
true &&
! blockType?.supports?.spacing?.__experimentalSkipSerialization?.some?.(
( spacingType ) => spacingType === 'blockGap'
)
) {
supportKeys.push( 'blockGap' );
}

// check for shadow support
if ( blockType?.supports?.shadow ) {
supportKeys.push( 'shadow' );
}

Object.keys( STYLE_PROPERTY ).forEach( ( styleName ) => {
if ( ! STYLE_PROPERTY[ styleName ].support ) {
return;
}

// Opting out means that, for certain support keys like background color,
// blocks have to explicitly set the support value false. If the key is
// unset, we still enable it.
if ( STYLE_PROPERTY[ styleName ].requiresOptOut ) {
if (
STYLE_PROPERTY[ styleName ].support[ 0 ] in
blockType.supports &&
get(
blockType.supports,
STYLE_PROPERTY[ styleName ].support
) !== false
) {
supportKeys.push( styleName );
return;
}
}

if (
get(
blockType.supports,
STYLE_PROPERTY[ styleName ].support,
false
)
) {
supportKeys.push( styleName );
}
} );

return filterElementBlockSupports( supportKeys, name, element );
},
( state, name ) => [ state.blockTypes[ name ] ]
);
Loading

1 comment on commit ddcaa70

@github-actions
Copy link

@github-actions github-actions bot commented on ddcaa70 Feb 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in ddcaa70.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/4086606358
📝 Reported issues:

Please sign in to comment.