Skip to content

Commit

Permalink
Move Global Styles APIs to @wordpress/block-editor (#47098)
Browse files Browse the repository at this point in the history
* Move things around

* lock() the Global Styles APIs

* Update package-lock.json

* Move tests to block-editor
  • Loading branch information
noisysocks authored Jan 20, 2023
1 parent 64c6912 commit 77c6c5d
Show file tree
Hide file tree
Showing 44 changed files with 1,068 additions and 815 deletions.
2 changes: 2 additions & 0 deletions package-lock.json

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

4 changes: 4 additions & 0 deletions packages/block-editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,10 @@ _Returns_

Undocumented declaration.

### experiments

Experimental @wordpress/block-editor APIs.

### FontSizePicker

_Related_
Expand Down
1 change: 1 addition & 0 deletions packages/block-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@wordpress/dom": "file:../dom",
"@wordpress/element": "file:../element",
"@wordpress/escape-html": "file:../escape-html",
"@wordpress/experiments": "file:../experiments",
"@wordpress/hooks": "file:../hooks",
"@wordpress/html-entities": "file:../html-entities",
"@wordpress/i18n": "file:../i18n",
Expand Down
78 changes: 78 additions & 0 deletions packages/block-editor/src/components/global-styles/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Global Styles

This folder contains all the necessary APIs to manipulate the global styles data. It can be potentially extracted to its own package.

# Available public APIs

## useGlobalStylesReset

A React hook used to retrieve whether the Global Styles have been edited and a callback to reset to the default theme values.

```js
import { useGlobalStylesReset } from '@wordpress/block-editor';

function MyComponent() {
const [ canReset, reset ] = useGlobalStylesReset();

return canReset
? <Button onClick={ () => reset() }>Reset</Button>
: null;
}
```

## useGlobalStylesOutput

A React hook used to retrieve the styles array and settings to provide for block editor instances based on the current global styles.

```js
import { useGlobalStylesOutput, BlockEditorProvider, BlockList } from '@wordpress/block-editor';

function MyComponent() {
const [ styles, settings ] = useGlobalStylesOutput();

return <BlockEditorProvider settings={{
styles,
__experimentalFeatures: settings
}}>
<BlockList />
</BlockEditorProvider>
}
```

## useGlobalStyle

A react hook used to retrieve the style applied to a given context.

```js
import { useGlobalStyle } from '@wordpress/block-editor';

function MyComponent() {
// Text color for the site root.
const [ color, setColor ] = useGlobalStyle( 'color.text' );

// The user modified color for the core paragraph block.
const [ pColor, setPColor ] = useGlobalStyle( 'color.text', 'core/paragraph', 'user' );

return "Something";
}
```

## useGlobalSetting

A react hook used to retrieve the setting applied to a given context.

```js
import { useGlobalSetting } from '@wordpress/block-editor';

function MyComponent() {
// The default color palette.
const [ colorPalette, setColorPalette ] = useGlobalSetting( 'color.palette' );

// The base (theme + core) color palette for the paragraph block,
// ignoring user provided palette.
// If the palette is not defined for the paragraph block, the root one is returned.
const [ pColor, setPColor ] = useGlobalSetting( 'color.palette', 'core/paragraph', 'base' );

return "Something";
}
```
157 changes: 157 additions & 0 deletions packages/block-editor/src/components/global-styles/hooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/**
* External dependencies
*/
import fastDeepEqual from 'fast-deep-equal/es6';
import { get, set } from 'lodash';

/**
* WordPress dependencies
*/
import { useContext, useCallback } from '@wordpress/element';
import { __EXPERIMENTAL_PATHS_WITH_MERGE as PATHS_WITH_MERGE } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import { getValueFromVariable, getPresetVariableFromValue } from './utils';
import { GlobalStylesContext } from './context';

const EMPTY_CONFIG = { settings: {}, styles: {} };

export const useGlobalStylesReset = () => {
const { user: config, setUserConfig } = useContext( GlobalStylesContext );
const canReset = !! config && ! fastDeepEqual( config, EMPTY_CONFIG );
return [
canReset,
useCallback(
() => setUserConfig( () => EMPTY_CONFIG ),
[ setUserConfig ]
),
];
};

export function useGlobalSetting( path, blockName, source = 'all' ) {
const {
merged: mergedConfig,
base: baseConfig,
user: userConfig,
setUserConfig,
} = useContext( GlobalStylesContext );

const fullPath = ! blockName
? `settings.${ path }`
: `settings.blocks.${ blockName }.${ path }`;

const setSetting = ( newValue ) => {
setUserConfig( ( currentConfig ) => {
// Deep clone `currentConfig` to avoid mutating it later.
const newUserConfig = JSON.parse( JSON.stringify( currentConfig ) );
const pathToSet = PATHS_WITH_MERGE[ path ]
? fullPath + '.custom'
: fullPath;
set( newUserConfig, pathToSet, newValue );

return newUserConfig;
} );
};

const getSettingValueForContext = ( name ) => {
const currentPath = ! name
? `settings.${ path }`
: `settings.blocks.${ name }.${ path }`;

const getSettingValue = ( configToUse ) => {
const result = get( configToUse, currentPath );
if ( PATHS_WITH_MERGE[ path ] ) {
return result?.custom ?? result?.theme ?? result?.default;
}
return result;
};

let result;
switch ( source ) {
case 'all':
result = getSettingValue( mergedConfig );
break;
case 'user':
result = getSettingValue( userConfig );
break;
case 'base':
result = getSettingValue( baseConfig );
break;
default:
throw 'Unsupported source';
}

return result;
};

// Unlike styles settings get inherited from top level settings.
const resultWithFallback =
getSettingValueForContext( blockName ) ?? getSettingValueForContext();

return [ resultWithFallback, setSetting ];
}

export function useGlobalStyle( path, blockName, source = 'all' ) {
const {
merged: mergedConfig,
base: baseConfig,
user: userConfig,
setUserConfig,
} = useContext( GlobalStylesContext );
const finalPath = ! blockName
? `styles.${ path }`
: `styles.blocks.${ blockName }.${ path }`;

const setStyle = ( newValue ) => {
setUserConfig( ( currentConfig ) => {
// Deep clone `currentConfig` to avoid mutating it later.
const newUserConfig = JSON.parse( JSON.stringify( currentConfig ) );
set(
newUserConfig,
finalPath,
getPresetVariableFromValue(
mergedConfig.settings,
blockName,
path,
newValue
)
);
return newUserConfig;
} );
};

let result;
switch ( source ) {
case 'all':
result = getValueFromVariable(
mergedConfig,
blockName,
// The stlyes.css path is allowed to be empty, so don't revert to base if undefined.
finalPath === 'styles.css'
? get( userConfig, finalPath )
: get( userConfig, finalPath ) ??
get( baseConfig, finalPath )
);
break;
case 'user':
result = getValueFromVariable(
mergedConfig,
blockName,
get( userConfig, finalPath )
);
break;
case 'base':
result = getValueFromVariable(
baseConfig,
blockName,
get( baseConfig, finalPath )
);
break;
default:
throw 'Unsupported source';
}

return [ result, setStyle ];
}
7 changes: 7 additions & 0 deletions packages/block-editor/src/components/global-styles/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export {
useGlobalStylesReset,
useGlobalSetting,
useGlobalStyle,
} from './hooks';
export { useGlobalStylesOutput } from './use-global-styles-output';
export { GlobalStylesContext } from './context';
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
*/

/**
* WordPress dependencies
* Internal dependencies
*/
import { getComputedFluidTypographyValue } from '@wordpress/block-editor';
import { getComputedFluidTypographyValue } from '../font-sizes/fluid-utils';

/**
* @typedef {Object} FluidPreset
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,17 @@ import {
import { useSelect } from '@wordpress/data';
import { useContext, useMemo } from '@wordpress/element';
import { getCSSRules } from '@wordpress/style-engine';
import {
__unstablePresetDuotoneFilter as PresetDuotoneFilter,
__experimentalGetGapCSSValue as getGapCSSValue,
store as blockEditorStore,
} from '@wordpress/block-editor';

/**
* Internal dependencies
*/
import { PRESET_METADATA, ROOT_BLOCK_SELECTOR, scopeSelector } from './utils';
import { getTypographyFontSizeValue } from './typography-utils';
import { GlobalStylesContext } from './context';
import { useSetting } from './hooks';
import { useGlobalSetting } from './hooks';
import { PresetDuotoneFilter } from '../duotone/components';
import { getGapCSSValue } from '../../hooks/gap';
import { store as blockEditorStore } from '../../store';

// List of block support features that can have their related styles
// generated under their own feature level selector rather than the block's.
Expand Down Expand Up @@ -999,7 +997,7 @@ function updateConfigWithSeparator( config ) {
export function useGlobalStylesOutput() {
let { merged: mergedConfig } = useContext( GlobalStylesContext );

const [ blockGap ] = useSetting( 'spacing.blockGap' );
const [ blockGap ] = useGlobalSetting( 'spacing.blockGap' );
const hasBlockGapSupport = blockGap !== null;
const hasFallbackGapSupport = ! hasBlockGapSupport; // This setting isn't useful yet: it exists as a placeholder for a future explicit fallback styles support.
const disableLayoutStyles = useSelect( ( select ) => {
Expand Down
Loading

0 comments on commit 77c6c5d

Please sign in to comment.