diff --git a/packages/block-editor/src/components/font-appearance-control/index.js b/packages/block-editor/src/components/font-appearance-control/index.js
index 5e7a4de57ca34..120ade21c568e 100644
--- a/packages/block-editor/src/components/font-appearance-control/index.js
+++ b/packages/block-editor/src/components/font-appearance-control/index.js
@@ -63,7 +63,7 @@ const FONT_WEIGHTS = [
* @param {boolean} hasFontWeights Whether font weights are enabled and present.
* @return {string} A label representing what font appearance is being edited.
*/
-export const getFontAppearanceLabel = ( hasFontStyles, hasFontWeights ) => {
+const getFontAppearanceLabel = ( hasFontStyles, hasFontWeights ) => {
if ( ! hasFontStyles ) {
return __( 'Font weight' );
}
diff --git a/packages/block-editor/src/components/global-styles/hooks.js b/packages/block-editor/src/components/global-styles/hooks.js
index 9778cc4ee6420..5b2151dbfaba4 100644
--- a/packages/block-editor/src/components/global-styles/hooks.js
+++ b/packages/block-editor/src/components/global-styles/hooks.js
@@ -7,16 +7,67 @@ import { get, set } from 'lodash';
/**
* WordPress dependencies
*/
-import { useContext, useCallback } from '@wordpress/element';
+import { useContext, useCallback, useMemo } from '@wordpress/element';
+import { useSelect } from '@wordpress/data';
+import { store as blocksStore } from '@wordpress/blocks';
/**
* Internal dependencies
*/
import { getValueFromVariable, getPresetVariableFromValue } from './utils';
import { GlobalStylesContext } from './context';
+import { unlock } from '../../lock-unlock';
const EMPTY_CONFIG = { settings: {}, styles: {} };
+const VALID_SETTINGS = [
+ 'appearanceTools',
+ 'useRootPaddingAwareAlignments',
+ 'border.color',
+ 'border.radius',
+ 'border.style',
+ 'border.width',
+ 'shadow.presets',
+ 'shadow.defaultPresets',
+ 'color.background',
+ 'color.custom',
+ 'color.customDuotone',
+ 'color.customGradient',
+ 'color.defaultDuotone',
+ 'color.defaultGradients',
+ 'color.defaultPalette',
+ 'color.duotone',
+ 'color.gradients',
+ 'color.link',
+ 'color.palette',
+ 'color.text',
+ 'custom',
+ 'dimensions.minHeight',
+ 'layout.contentSize',
+ 'layout.definitions',
+ 'layout.wideSize',
+ 'position.fixed',
+ 'position.sticky',
+ 'spacing.customSpacingSize',
+ 'spacing.spacingSizes',
+ 'spacing.spacingScale',
+ 'spacing.blockGap',
+ 'spacing.margin',
+ 'spacing.padding',
+ 'spacing.units',
+ 'typography.fuild',
+ 'typography.customFontSize',
+ 'typography.dropCap',
+ 'typography.fontFamilies',
+ 'typography.fontSizes',
+ 'typography.fontStyle',
+ 'typography.fontWeight',
+ 'typography.letterSpacing',
+ 'typography.lineHeight',
+ 'typography.textDecoration',
+ 'typography.textTransform',
+];
+
export const useGlobalStylesReset = () => {
const { user: config, setUserConfig } = useContext( GlobalStylesContext );
const canReset = !! config && ! fastDeepEqual( config, EMPTY_CONFIG );
@@ -29,68 +80,78 @@ export const useGlobalStylesReset = () => {
];
};
-export function useGlobalSetting( path, blockName, source = 'all' ) {
- const {
- merged: mergedConfig,
- base: baseConfig,
- user: userConfig,
- setUserConfig,
- } = useContext( GlobalStylesContext );
+export function useGlobalSetting( propertyPath, blockName, source = 'all' ) {
+ const { setUserConfig, ...configs } = useContext( GlobalStylesContext );
- const fullPath = ! blockName
- ? `settings.${ path }`
- : `settings.blocks.${ blockName }.${ path }`;
+ const appendedBlockPath = blockName ? '.blocks.' + blockName : '';
+ const appendedPropertyPath = propertyPath ? '.' + propertyPath : '';
+ const contextualPath = `settings${ appendedBlockPath }${ appendedPropertyPath }`;
+ const globalPath = `settings${ appendedPropertyPath }`;
+ const sourceKey = source === 'all' ? 'merged' : source;
+
+ const settingValue = useMemo( () => {
+ const configToUse = configs[ sourceKey ];
+ if ( ! configToUse ) {
+ throw 'Unsupported source';
+ }
+
+ if ( propertyPath ) {
+ return (
+ get( configToUse, contextualPath ) ??
+ get( configToUse, globalPath )
+ );
+ }
+
+ const result = {};
+ VALID_SETTINGS.forEach( ( setting ) => {
+ const value =
+ get(
+ configToUse,
+ `settings${ appendedBlockPath }.${ setting }`
+ ) ?? get( configToUse, `settings.${ setting }` );
+ if ( value ) {
+ set( result, setting, value );
+ }
+ } );
+ return result;
+ }, [
+ configs,
+ sourceKey,
+ propertyPath,
+ contextualPath,
+ globalPath,
+ appendedBlockPath,
+ ] );
const setSetting = ( newValue ) => {
setUserConfig( ( currentConfig ) => {
// Deep clone `currentConfig` to avoid mutating it later.
const newUserConfig = JSON.parse( JSON.stringify( currentConfig ) );
- set( newUserConfig, fullPath, newValue );
+ set( newUserConfig, contextualPath, newValue );
return newUserConfig;
} );
};
- const getSettingValueForContext = ( name ) => {
- const currentPath = ! name
- ? `settings.${ path }`
- : `settings.blocks.${ name }.${ path }`;
-
- let result;
- switch ( source ) {
- case 'all':
- result = get( mergedConfig, currentPath );
- break;
- case 'user':
- result = get( userConfig, currentPath );
- break;
- case 'base':
- result = get( baseConfig, currentPath );
- break;
- default:
- throw 'Unsupported source';
- }
-
- return result;
- };
-
- // Unlike styles settings get inherited from top level settings.
- const resultWithFallback =
- getSettingValueForContext( blockName ) ?? getSettingValueForContext();
-
- return [ resultWithFallback, setSetting ];
+ return [ settingValue, setSetting ];
}
-export function useGlobalStyle( path, blockName, source = 'all' ) {
+export function useGlobalStyle(
+ path,
+ blockName,
+ source = 'all',
+ { shouldDecodeEncode = true } = {}
+) {
const {
merged: mergedConfig,
base: baseConfig,
user: userConfig,
setUserConfig,
} = useContext( GlobalStylesContext );
+ const appendedPath = path ? '.' + path : '';
const finalPath = ! blockName
- ? `styles.${ path }`
- : `styles.blocks.${ blockName }.${ path }`;
+ ? `styles${ appendedPath }`
+ : `styles.blocks.${ blockName }${ appendedPath }`;
const setStyle = ( newValue ) => {
setUserConfig( ( currentConfig ) => {
@@ -99,43 +160,42 @@ export function useGlobalStyle( path, blockName, source = 'all' ) {
set(
newUserConfig,
finalPath,
- getPresetVariableFromValue(
- mergedConfig.settings,
- blockName,
- path,
- newValue
- )
+ shouldDecodeEncode
+ ? getPresetVariableFromValue(
+ mergedConfig.settings,
+ blockName,
+ path,
+ newValue
+ )
+ : newValue
);
return newUserConfig;
} );
};
- let result;
+ let rawResult, result;
switch ( source ) {
case 'all':
- result = getValueFromVariable(
- mergedConfig,
- blockName,
+ rawResult =
// 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 )
- );
+ : get( mergedConfig, finalPath );
+ result = shouldDecodeEncode
+ ? getValueFromVariable( mergedConfig, blockName, rawResult )
+ : rawResult;
break;
case 'user':
- result = getValueFromVariable(
- mergedConfig,
- blockName,
- get( userConfig, finalPath )
- );
+ rawResult = get( userConfig, finalPath );
+ result = shouldDecodeEncode
+ ? getValueFromVariable( mergedConfig, blockName, rawResult )
+ : rawResult;
break;
case 'base':
- result = getValueFromVariable(
- baseConfig,
- blockName,
- get( baseConfig, finalPath )
- );
+ rawResult = get( baseConfig, finalPath );
+ result = shouldDecodeEncode
+ ? getValueFromVariable( baseConfig, blockName, rawResult )
+ : rawResult;
break;
default:
throw 'Unsupported source';
@@ -143,3 +203,18 @@ export function useGlobalStyle( path, blockName, source = 'all' ) {
return [ result, setStyle ];
}
+
+export function useSupportedStyles( name, element ) {
+ const { supportedPanels } = useSelect(
+ ( select ) => {
+ return {
+ supportedPanels: unlock(
+ select( blocksStore )
+ ).getSupportedStyles( name, element ),
+ };
+ },
+ [ name, element ]
+ );
+
+ return supportedPanels;
+}
diff --git a/packages/block-editor/src/components/global-styles/index.js b/packages/block-editor/src/components/global-styles/index.js
index cd0c8cdf487c5..6581f46254985 100644
--- a/packages/block-editor/src/components/global-styles/index.js
+++ b/packages/block-editor/src/components/global-styles/index.js
@@ -5,3 +5,7 @@ export {
} from './hooks';
export { useGlobalStylesOutput } from './use-global-styles-output';
export { GlobalStylesContext } from './context';
+export {
+ default as TypographyPanel,
+ useHasTypographyPanel,
+} from './typography-panel';
diff --git a/packages/block-editor/src/components/global-styles/typography-panel.js b/packages/block-editor/src/components/global-styles/typography-panel.js
new file mode 100644
index 0000000000000..471055be391f7
--- /dev/null
+++ b/packages/block-editor/src/components/global-styles/typography-panel.js
@@ -0,0 +1,470 @@
+/**
+ * WordPress dependencies
+ */
+import {
+ FontSizePicker,
+ __experimentalToolsPanel as ToolsPanel,
+ __experimentalToolsPanelItem as ToolsPanelItem,
+} from '@wordpress/components';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import FontFamilyControl from '../font-family';
+import FontAppearanceControl from '../font-appearance-control';
+import LineHeightControl from '../line-height-control';
+import LetterSpacingControl from '../letter-spacing-control';
+import TextTransformControl from '../text-transform-control';
+import TextDecorationControl from '../text-decoration-control';
+import { useSupportedStyles } from './hooks';
+import { getValueFromVariable } from './utils';
+
+export function useHasTypographyPanel( name, element, settings ) {
+ const hasFontFamily = useHasFontFamilyControl( name, element, settings );
+ const hasLineHeight = useHasLineHeightControl( name, element, settings );
+ const hasFontAppearance = useHasAppearanceControl(
+ name,
+ element,
+ settings
+ );
+ const hasLetterSpacing = useHasLetterSpacingControl(
+ name,
+ element,
+ settings
+ );
+ const hasTextTransform = useHasTextTransformControl(
+ name,
+ element,
+ settings
+ );
+ const hasTextDecoration = useHasTextDecorationControl( name, element );
+ const hasFontSize = useHasFontSizeControl( name, element, settings );
+
+ return (
+ hasFontFamily ||
+ hasLineHeight ||
+ hasFontAppearance ||
+ hasLetterSpacing ||
+ hasTextTransform ||
+ hasFontSize ||
+ hasTextDecoration
+ );
+}
+
+function useHasFontSizeControl( name, element, settings ) {
+ const supports = useSupportedStyles( name, element );
+ const disableCustomFontSizes = ! settings?.typography?.customFontSize;
+ const fontSizesPerOrigin = settings?.typography?.fontSizes ?? {};
+ const fontSizes =
+ fontSizesPerOrigin?.custom ??
+ fontSizesPerOrigin?.theme ??
+ fontSizesPerOrigin.default;
+ return (
+ supports.includes( 'fontSize' ) &&
+ ( !! fontSizes?.length || ! disableCustomFontSizes )
+ );
+}
+
+function useHasFontFamilyControl( name, element, settings ) {
+ const supports = useSupportedStyles( name, element );
+ const fontFamiliesPerOrigin = settings?.typography?.fontFamilies;
+ const fontFamilies =
+ fontFamiliesPerOrigin?.custom ??
+ fontFamiliesPerOrigin?.theme ??
+ fontFamiliesPerOrigin?.default;
+ return supports.includes( 'fontFamily' ) && !! fontFamilies?.length;
+}
+
+function useHasLineHeightControl( name, element, settings ) {
+ const supports = useSupportedStyles( name, element );
+ return (
+ settings?.typography?.lineHeight && supports.includes( 'lineHeight' )
+ );
+}
+
+function useHasAppearanceControl( name, element, settings ) {
+ const supports = useSupportedStyles( name, element );
+ const hasFontStyles =
+ settings?.typography?.fontStyle && supports.includes( 'fontStyle' );
+ const hasFontWeights =
+ settings?.typography?.fontWeight && supports.includes( 'fontWeight' );
+ return hasFontStyles || hasFontWeights;
+}
+
+function useAppearanceControlLabel( name, element, settings ) {
+ const supports = useSupportedStyles( name, element );
+ const hasFontStyles =
+ settings?.typography?.fontStyle && supports.includes( 'fontStyle' );
+ const hasFontWeights =
+ settings?.typography?.fontWeight && supports.includes( 'fontWeight' );
+ if ( ! hasFontStyles ) {
+ return __( 'Font weight' );
+ }
+ if ( ! hasFontWeights ) {
+ return __( 'Font style' );
+ }
+ return __( 'Appearance' );
+}
+
+function useHasLetterSpacingControl( name, element, settings ) {
+ const setting = settings?.typography?.letterSpacing;
+ const supports = useSupportedStyles( name, element );
+ if ( ! setting ) {
+ return false;
+ }
+ return supports.includes( 'letterSpacing' );
+}
+
+function useHasTextTransformControl( name, element, settings ) {
+ const setting = settings?.typography?.textTransform;
+ const supports = useSupportedStyles( name, element );
+ if ( ! setting ) {
+ return false;
+ }
+ return supports.includes( 'textTransform' );
+}
+
+function useHasTextDecorationControl( name, element ) {
+ const supports = useSupportedStyles( name, element );
+ return supports.includes( 'textDecoration' );
+}
+
+function TypographyToolsPanel( { ...props } ) {
+ return ;
+}
+
+const DEFAULT_CONTROLS = {
+ fontFamily: true,
+ fontSize: true,
+ fontAppearance: true,
+ lineHeight: true,
+ letterSpacing: true,
+ textTransform: true,
+ textDecoration: true,
+};
+
+export default function TypographyPanel( {
+ as: Wrapper = TypographyToolsPanel,
+ name,
+ element,
+ value,
+ onChange,
+ inheritedValue = value,
+ settings,
+ panelId,
+ defaultControls = DEFAULT_CONTROLS,
+} ) {
+ const decodeValue = ( rawValue ) =>
+ getValueFromVariable( { settings }, '', rawValue );
+
+ // Font Family
+ const hasFontFamilyEnabled = useHasFontFamilyControl(
+ name,
+ element,
+ settings
+ );
+ const fontFamiliesPerOrigin = settings?.typography?.fontFamilies;
+ const fontFamilies =
+ fontFamiliesPerOrigin?.custom ??
+ fontFamiliesPerOrigin?.theme ??
+ fontFamiliesPerOrigin?.default;
+ const fontFamily = decodeValue( inheritedValue?.typography?.fontFamily );
+ const setFontFamily = ( newValue ) => {
+ const slug = fontFamilies?.find(
+ ( { fontFamily: f } ) => f === newValue
+ )?.slug;
+ onChange( {
+ ...value,
+ typography: {
+ ...value?.typography,
+ fontFamily: slug
+ ? `var:preset|font-family|${ slug }`
+ : newValue,
+ },
+ } );
+ };
+ const hasFontFamily = () => !! value?.typography?.fontFamily;
+ const resetFontFamily = () => setFontFamily( undefined );
+
+ // Font Size
+ const hasFontSizeEnabled = useHasFontSizeControl( name, element, settings );
+ const disableCustomFontSizes = ! settings?.typography?.customFontSize;
+ const fontSizesPerOrigin = settings?.typography?.fontSizes ?? {};
+ const fontSizes =
+ fontSizesPerOrigin?.custom ??
+ fontSizesPerOrigin?.theme ??
+ fontSizesPerOrigin.default;
+ const fontSize = decodeValue( inheritedValue?.typography?.fontSize );
+ const setFontSize = ( newValue, metadata ) => {
+ const actualValue = !! metadata?.slug
+ ? `var:preset|font-size|${ metadata?.slug }`
+ : newValue;
+
+ onChange( {
+ ...value,
+ typography: {
+ ...value?.typography,
+ fontSize: actualValue,
+ },
+ } );
+ };
+ const hasFontSize = () => !! value?.typography?.fontSize;
+ const resetFontSize = () => setFontSize( undefined );
+
+ // Appearance
+ const hasAppearanceControl = useHasAppearanceControl(
+ name,
+ element,
+ settings
+ );
+ const appearanceControlLabel = useAppearanceControlLabel(
+ name,
+ element,
+ settings
+ );
+ const hasFontStyles = settings?.typography?.fontStyle;
+ const hasFontWeights = settings?.typography?.fontWeight;
+ const fontStyle = decodeValue( inheritedValue?.typography?.fontStyle );
+ const fontWeight = decodeValue( inheritedValue?.typography?.fontWeight );
+ const setFontAppearance = ( {
+ fontStyle: newFontStyle,
+ fontWeight: newFontWeight,
+ } ) => {
+ onChange( {
+ ...value,
+ typography: {
+ ...value?.typography,
+ fontStyle: newFontStyle,
+ fontWeight: newFontWeight,
+ },
+ } );
+ };
+ const hasFontAppearance = () =>
+ !! value?.typography?.fontStyle || !! value?.typography?.fontWeight;
+ const resetFontAppearance = () => {
+ setFontAppearance( {} );
+ };
+
+ // Line Height
+ const hasLineHeightEnabled = useHasLineHeightControl(
+ name,
+ element,
+ settings
+ );
+ const lineHeight = decodeValue( inheritedValue?.typography?.lineHeight );
+ const setLineHeight = ( newValue ) => {
+ onChange( {
+ ...value,
+ typography: {
+ ...value?.typography,
+ lineHeight: newValue,
+ },
+ } );
+ };
+ const hasLineHeight = () => !! value?.typography?.lineHeight;
+ const resetLineHeight = () => setLineHeight( undefined );
+
+ // Letter Spacing
+ const hasLetterSpacingControl = useHasLetterSpacingControl(
+ name,
+ element,
+ settings
+ );
+ const letterSpacing = decodeValue(
+ inheritedValue?.typography?.letterSpacing
+ );
+ const setLetterSpacing = ( newValue ) => {
+ onChange( {
+ ...value,
+ typography: {
+ ...value?.typography,
+ letterSpacing: newValue,
+ },
+ } );
+ };
+ const hasLetterSpacing = () => !! value?.typography?.letterSpacing;
+ const resetLetterSpacing = () => setLetterSpacing( undefined );
+
+ // Text Transform
+ const hasTextTransformControl = useHasTextTransformControl(
+ name,
+ element,
+ settings
+ );
+ const textTransform = decodeValue(
+ inheritedValue?.typography?.textTransform
+ );
+ const setTextTransform = ( newValue ) => {
+ onChange( {
+ ...value,
+ typography: {
+ ...value?.typography,
+ textTransform: newValue,
+ },
+ } );
+ };
+ const hasTextTransform = () => !! value?.typography?.textTransform;
+ const resetTextTransform = () => setTextTransform( undefined );
+
+ // Text Decoration
+ const hasTextDecorationControl = useHasTextDecorationControl(
+ name,
+ element
+ );
+ const textDecoration = decodeValue(
+ inheritedValue?.typography?.textDecoration
+ );
+ const setTextDecoration = ( newValue ) => {
+ onChange( {
+ ...value,
+ typography: {
+ ...value?.typography,
+ textDecoration: newValue,
+ },
+ } );
+ };
+ const hasTextDecoration = () => !! value?.typography?.textDecoration;
+ const resetTextDecoration = () => setTextDecoration( undefined );
+
+ const resetAll = () => {
+ onChange( {
+ ...value,
+ typography: {},
+ } );
+ };
+
+ return (
+
+ { hasFontFamilyEnabled && (
+
+
+
+ ) }
+ { hasFontSizeEnabled && (
+
+
+
+ ) }
+ { hasAppearanceControl && (
+
+
+
+ ) }
+ { hasLineHeightEnabled && (
+
+
+
+ ) }
+ { hasLetterSpacingControl && (
+
+
+
+ ) }
+ { hasTextDecorationControl && (
+
+
+
+ ) }
+ { hasTextTransformControl && (
+
+
+
+ ) }
+
+ );
+}
diff --git a/packages/block-editor/src/hooks/font-appearance.js b/packages/block-editor/src/hooks/font-appearance.js
deleted file mode 100644
index af25daed0d30b..0000000000000
--- a/packages/block-editor/src/hooks/font-appearance.js
+++ /dev/null
@@ -1,146 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { hasBlockSupport } from '@wordpress/blocks';
-
-/**
- * Internal dependencies
- */
-import FontAppearanceControl from '../components/font-appearance-control';
-import useSetting from '../components/use-setting';
-import { cleanEmptyObject } from './utils';
-
-/**
- * Key within block settings' support array indicating support for font style.
- */
-export const FONT_STYLE_SUPPORT_KEY = 'typography.__experimentalFontStyle';
-
-/**
- * Key within block settings' support array indicating support for font weight.
- */
-export const FONT_WEIGHT_SUPPORT_KEY = 'typography.__experimentalFontWeight';
-
-/**
- * Inspector control panel containing the font appearance options.
- *
- * @param {Object} props Block properties.
- *
- * @return {WPElement} Font appearance edit element.
- */
-export function FontAppearanceEdit( props ) {
- const {
- attributes: { style },
- setAttributes,
- } = props;
-
- const hasFontStyles = ! useIsFontStyleDisabled( props );
- const hasFontWeights = ! useIsFontWeightDisabled( props );
-
- const onChange = ( newStyles ) => {
- setAttributes( {
- style: cleanEmptyObject( {
- ...style,
- typography: {
- ...style?.typography,
- fontStyle: newStyles.fontStyle,
- fontWeight: newStyles.fontWeight,
- },
- } ),
- } );
- };
-
- const fontStyle = style?.typography?.fontStyle;
- const fontWeight = style?.typography?.fontWeight;
-
- return (
-
- );
-}
-
-/**
- * Checks if font style support has been disabled either by not opting in for
- * support or by failing to provide preset styles.
- *
- * @param {Object} props Block properties.
- * @param {string} props.name Name for the block type.
- *
- * @return {boolean} Whether font style support has been disabled.
- */
-export function useIsFontStyleDisabled( { name: blockName } = {} ) {
- const styleSupport = hasBlockSupport( blockName, FONT_STYLE_SUPPORT_KEY );
- const hasFontStyles = useSetting( 'typography.fontStyle' );
-
- return ! styleSupport || ! hasFontStyles;
-}
-
-/**
- * Checks if font weight support has been disabled either by not opting in for
- * support or by failing to provide preset weights.
- *
- * @param {Object} props Block properties.
- * @param {string} props.name Name for the block type.
- *
- * @return {boolean} Whether font weight support has been disabled.
- */
-export function useIsFontWeightDisabled( { name: blockName } = {} ) {
- const weightSupport = hasBlockSupport( blockName, FONT_WEIGHT_SUPPORT_KEY );
- const hasFontWeights = useSetting( 'typography.fontWeight' );
-
- return ! weightSupport || ! hasFontWeights;
-}
-
-/**
- * Checks if font appearance support has been disabled.
- *
- * @param {Object} props Block properties.
- *
- * @return {boolean} Whether font appearance support has been disabled.
- */
-export function useIsFontAppearanceDisabled( props ) {
- const stylesDisabled = useIsFontStyleDisabled( props );
- const weightsDisabled = useIsFontWeightDisabled( props );
-
- return stylesDisabled && weightsDisabled;
-}
-
-/**
- * Checks if there is either a font style or weight value set within the
- * typography styles.
- *
- * @param {Object} props Block props.
- * @return {boolean} Whether or not the block has a font style or weight.
- */
-export function hasFontAppearanceValue( props ) {
- const { fontStyle, fontWeight } = props.attributes.style?.typography || {};
- return !! fontStyle || !! fontWeight;
-}
-
-/**
- * Resets the font style and weight block support attributes. This can be used
- * when disabling the font appearance support controls for a block via a
- * progressive discovery panel.
- *
- * @param {Object} props Block props.
- * @param {Object} props.attributes Block's attributes.
- * @param {Object} props.setAttributes Function to set block's attributes.
- */
-export function resetFontAppearance( { attributes = {}, setAttributes } ) {
- const { style } = attributes;
-
- setAttributes( {
- style: cleanEmptyObject( {
- ...style,
- typography: {
- ...style?.typography,
- fontStyle: undefined,
- fontWeight: undefined,
- },
- } ),
- } );
-}
diff --git a/packages/block-editor/src/hooks/font-family.js b/packages/block-editor/src/hooks/font-family.js
index 56335ced88707..754bcdd1b5bff 100644
--- a/packages/block-editor/src/hooks/font-family.js
+++ b/packages/block-editor/src/hooks/font-family.js
@@ -13,8 +13,6 @@ import TokenList from '@wordpress/token-list';
/**
* Internal dependencies
*/
-import useSetting from '../components/use-setting';
-import FontFamilyControl from '../components/font-family';
import { shouldSkipSerialization } from './utils';
import { TYPOGRAPHY_SUPPORT_KEY } from './typography';
@@ -105,62 +103,6 @@ function addEditProps( settings ) {
return settings;
}
-export function FontFamilyEdit( {
- setAttributes,
- attributes: { fontFamily },
-} ) {
- const fontFamilies = useSetting( 'typography.fontFamilies' );
-
- const value = fontFamilies?.find(
- ( { slug } ) => fontFamily === slug
- )?.fontFamily;
-
- function onChange( newValue ) {
- const predefinedFontFamily = fontFamilies?.find(
- ( { fontFamily: f } ) => f === newValue
- );
- setAttributes( {
- fontFamily: predefinedFontFamily?.slug,
- } );
- }
-
- return (
-
- );
-}
-
-/**
- * Custom hook that checks if font-family functionality is disabled.
- *
- * @param {string} name The name of the block.
- * @return {boolean} Whether setting is disabled.
- */
-export function useIsFontFamilyDisabled( { name } ) {
- const fontFamilies = useSetting( 'typography.fontFamilies' );
- return (
- ! fontFamilies ||
- fontFamilies.length === 0 ||
- ! hasBlockSupport( name, FONT_FAMILY_SUPPORT_KEY )
- );
-}
-
-/**
- * Checks if there is a current value set for the font family block support.
- *
- * @param {Object} props Block props.
- * @return {boolean} Whether or not the block has a font family value set.
- */
-export function hasFontFamilyValue( props ) {
- return !! props.attributes.fontFamily;
-}
-
/**
* Resets the font family block support attribute. This can be used when
* disabling the font family support controls for a block via a progressive
diff --git a/packages/block-editor/src/hooks/font-size.js b/packages/block-editor/src/hooks/font-size.js
index 0c7a71fd23d68..e03b73c56331d 100644
--- a/packages/block-editor/src/hooks/font-size.js
+++ b/packages/block-editor/src/hooks/font-size.js
@@ -157,41 +157,6 @@ export function FontSizeEdit( props ) {
);
}
-/**
- * Checks if there is a current value set for the font size block support.
- *
- * @param {Object} props Block props.
- * @return {boolean} Whether or not the block has a font size value set.
- */
-export function hasFontSizeValue( props ) {
- const { fontSize, style } = props.attributes;
- return !! fontSize || !! style?.typography?.fontSize;
-}
-
-/**
- * Resets the font size block support attribute. This can be used when
- * disabling the font size support controls for a block via a progressive
- * discovery panel.
- *
- * @param {Object} props Block props.
- * @param {Object} props.attributes Block's attributes.
- * @param {Object} props.setAttributes Function to set block's attributes.
- */
-export function resetFontSize( { attributes = {}, setAttributes } ) {
- const { style } = attributes;
-
- setAttributes( {
- fontSize: undefined,
- style: cleanEmptyObject( {
- ...style,
- typography: {
- ...style?.typography,
- fontSize: undefined,
- },
- } ),
- } );
-}
-
/**
* Custom hook that checks if font-size settings have been disabled.
*
@@ -268,7 +233,7 @@ const MIGRATION_PATHS = {
fontSize: [ [ 'fontSize' ], [ 'style', 'typography', 'fontSize' ] ],
};
-export function addTransforms( result, source, index, results ) {
+function addTransforms( result, source, index, results ) {
const destinationBlockType = result.name;
const activeSupports = {
fontSize: hasBlockSupport(
diff --git a/packages/block-editor/src/hooks/index.js b/packages/block-editor/src/hooks/index.js
index 84b3ba3a95a33..2077c143952f5 100644
--- a/packages/block-editor/src/hooks/index.js
+++ b/packages/block-editor/src/hooks/index.js
@@ -12,6 +12,7 @@ import './style';
import './settings';
import './color';
import './duotone';
+import './font-family';
import './font-size';
import './border';
import './position';
diff --git a/packages/block-editor/src/hooks/letter-spacing.js b/packages/block-editor/src/hooks/letter-spacing.js
deleted file mode 100644
index 9e214fd07d792..0000000000000
--- a/packages/block-editor/src/hooks/letter-spacing.js
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { hasBlockSupport } from '@wordpress/blocks';
-
-/**
- * Internal dependencies
- */
-import LetterSpacingControl from '../components/letter-spacing-control';
-import useSetting from '../components/use-setting';
-import { cleanEmptyObject } from './utils';
-
-/**
- * Key within block settings' supports array indicating support for letter-spacing
- * e.g. settings found in `block.json`.
- */
-export const LETTER_SPACING_SUPPORT_KEY =
- 'typography.__experimentalLetterSpacing';
-
-/**
- * Inspector control panel containing the letter-spacing options.
- *
- * @param {Object} props Block properties.
- * @return {WPElement} Letter-spacing edit element.
- */
-export function LetterSpacingEdit( props ) {
- const {
- attributes: { style },
- setAttributes,
- } = props;
-
- function onChange( newSpacing ) {
- setAttributes( {
- style: cleanEmptyObject( {
- ...style,
- typography: {
- ...style?.typography,
- letterSpacing: newSpacing,
- },
- } ),
- } );
- }
-
- return (
-
- );
-}
-
-/**
- * Checks if letter-spacing settings have been disabled.
- *
- * @param {string} name Name of the block.
- * @return {boolean} Whether or not the setting is disabled.
- */
-export function useIsLetterSpacingDisabled( { name: blockName } = {} ) {
- const notSupported = ! hasBlockSupport(
- blockName,
- LETTER_SPACING_SUPPORT_KEY
- );
- const hasLetterSpacing = useSetting( 'typography.letterSpacing' );
-
- return notSupported || ! hasLetterSpacing;
-}
-
-/**
- * Checks if there is a current value set for the letter spacing block support.
- *
- * @param {Object} props Block props.
- * @return {boolean} Whether or not the block has a letter spacing set.
- */
-export function hasLetterSpacingValue( props ) {
- return !! props.attributes.style?.typography?.letterSpacing;
-}
-
-/**
- * Resets the letter spacing block support attribute. This can be used when
- * disabling the letter spacing support controls for a block via a progressive
- * discovery panel.
- *
- * @param {Object} props Block props.
- * @param {Object} props.attributes Block's attributes.
- * @param {Object} props.setAttributes Function to set block's attributes.
- */
-export function resetLetterSpacing( { attributes = {}, setAttributes } ) {
- const { style } = attributes;
-
- setAttributes( {
- style: cleanEmptyObject( {
- ...style,
- typography: {
- ...style?.typography,
- letterSpacing: undefined,
- },
- } ),
- } );
-}
diff --git a/packages/block-editor/src/hooks/line-height.js b/packages/block-editor/src/hooks/line-height.js
index c8397d850a1e5..363766e91b497 100644
--- a/packages/block-editor/src/hooks/line-height.js
+++ b/packages/block-editor/src/hooks/line-height.js
@@ -60,36 +60,3 @@ export function useIsLineHeightDisabled( { name: blockName } = {} ) {
! hasBlockSupport( blockName, LINE_HEIGHT_SUPPORT_KEY ) || isDisabled
);
}
-
-/**
- * Checks if there is a current value set for the line height block support.
- *
- * @param {Object} props Block props.
- * @return {boolean} Whether or not the block has a line height value set.
- */
-export function hasLineHeightValue( props ) {
- return !! props.attributes.style?.typography?.lineHeight;
-}
-
-/**
- * Resets the line height block support attribute. This can be used when
- * disabling the line height support controls for a block via a progressive
- * discovery panel.
- *
- * @param {Object} props Block props.
- * @param {Object} props.attributes Block's attributes.
- * @param {Object} props.setAttributes Function to set block's attributes.
- */
-export function resetLineHeight( { attributes = {}, setAttributes } ) {
- const { style } = attributes;
-
- setAttributes( {
- style: cleanEmptyObject( {
- ...style,
- typography: {
- ...style?.typography,
- lineHeight: undefined,
- },
- } ),
- } );
-}
diff --git a/packages/block-editor/src/hooks/text-decoration.js b/packages/block-editor/src/hooks/text-decoration.js
deleted file mode 100644
index 17ba9ee73f698..0000000000000
--- a/packages/block-editor/src/hooks/text-decoration.js
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { hasBlockSupport } from '@wordpress/blocks';
-
-/**
- * Internal dependencies
- */
-import TextDecorationControl from '../components/text-decoration-control';
-import useSetting from '../components/use-setting';
-import { cleanEmptyObject } from './utils';
-
-/**
- * Key within block settings' supports array indicating support for text
- * decorations e.g. settings found in `block.json`.
- */
-export const TEXT_DECORATION_SUPPORT_KEY =
- 'typography.__experimentalTextDecoration';
-
-/**
- * Inspector control panel containing the text decoration options.
- *
- * @param {Object} props Block properties.
- *
- * @return {WPElement} Text decoration edit element.
- */
-export function TextDecorationEdit( props ) {
- const {
- attributes: { style },
- setAttributes,
- } = props;
-
- function onChange( newDecoration ) {
- setAttributes( {
- style: cleanEmptyObject( {
- ...style,
- typography: {
- ...style?.typography,
- textDecoration: newDecoration,
- },
- } ),
- } );
- }
-
- return (
-
- );
-}
-
-/**
- * Checks if text-decoration settings have been disabled.
- *
- * @param {string} name Name of the block.
- *
- * @return {boolean} Whether or not the setting is disabled.
- */
-export function useIsTextDecorationDisabled( { name: blockName } = {} ) {
- const notSupported = ! hasBlockSupport(
- blockName,
- TEXT_DECORATION_SUPPORT_KEY
- );
- const hasTextDecoration = useSetting( 'typography.textDecoration' );
-
- return notSupported || ! hasTextDecoration;
-}
-
-/**
- * Checks if there is a current value set for the text decoration block support.
- *
- * @param {Object} props Block props.
- * @return {boolean} Whether or not the block has a text decoration set.
- */
-export function hasTextDecorationValue( props ) {
- return !! props.attributes.style?.typography?.textDecoration;
-}
-
-/**
- * Resets the text decoration block support attribute. This can be used when
- * disabling the text decoration support controls for a block via a progressive
- * discovery panel.
- *
- * @param {Object} props Block props.
- * @param {Object} props.attributes Block's attributes.
- * @param {Object} props.setAttributes Function to set block's attributes.
- */
-export function resetTextDecoration( { attributes = {}, setAttributes } ) {
- const { style } = attributes;
-
- setAttributes( {
- style: cleanEmptyObject( {
- ...style,
- typography: {
- ...style?.typography,
- textDecoration: undefined,
- },
- } ),
- } );
-}
diff --git a/packages/block-editor/src/hooks/text-transform.js b/packages/block-editor/src/hooks/text-transform.js
deleted file mode 100644
index 588327633ecb8..0000000000000
--- a/packages/block-editor/src/hooks/text-transform.js
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { hasBlockSupport } from '@wordpress/blocks';
-
-/**
- * Internal dependencies
- */
-import TextTransformControl from '../components/text-transform-control';
-import useSetting from '../components/use-setting';
-import { cleanEmptyObject } from './utils';
-
-/**
- * Key within block settings' supports array indicating support for text
- * transforms e.g. settings found in `block.json`.
- */
-export const TEXT_TRANSFORM_SUPPORT_KEY =
- 'typography.__experimentalTextTransform';
-
-/**
- * Inspector control panel containing the text transform options.
- *
- * @param {Object} props Block properties.
- *
- * @return {WPElement} Text transform edit element.
- */
-export function TextTransformEdit( props ) {
- const {
- attributes: { style },
- setAttributes,
- } = props;
-
- function onChange( newTransform ) {
- setAttributes( {
- style: cleanEmptyObject( {
- ...style,
- typography: {
- ...style?.typography,
- textTransform: newTransform,
- },
- } ),
- } );
- }
-
- return (
-
- );
-}
-
-/**
- * Checks if text-transform settings have been disabled.
- *
- * @param {string} name Name of the block.
- *
- * @return {boolean} Whether or not the setting is disabled.
- */
-export function useIsTextTransformDisabled( { name: blockName } = {} ) {
- const notSupported = ! hasBlockSupport(
- blockName,
- TEXT_TRANSFORM_SUPPORT_KEY
- );
- const hasTextTransforms = useSetting( 'typography.textTransform' );
- return notSupported || ! hasTextTransforms;
-}
-
-/**
- * Checks if there is a current value set for the text transform block support.
- *
- * @param {Object} props Block props.
- * @return {boolean} Whether or not the block has a text transform set.
- */
-export function hasTextTransformValue( props ) {
- return !! props.attributes.style?.typography?.textTransform;
-}
-
-/**
- * Resets the text transform block support attribute. This can be used when
- * disabling the text transform support controls for a block via a progressive
- * discovery panel.
- *
- * @param {Object} props Block props.
- * @param {Object} props.attributes Block's attributes.
- * @param {Object} props.setAttributes Function to set block's attributes.
- */
-export function resetTextTransform( { attributes = {}, setAttributes } ) {
- const { style } = attributes;
-
- setAttributes( {
- style: cleanEmptyObject( {
- ...style,
- typography: {
- ...style?.typography,
- textTransform: undefined,
- },
- } ),
- } );
-}
diff --git a/packages/block-editor/src/hooks/typography.js b/packages/block-editor/src/hooks/typography.js
index 43fb56ccc008e..87e734b00667c 100644
--- a/packages/block-editor/src/hooks/typography.js
+++ b/packages/block-editor/src/hooks/typography.js
@@ -2,68 +2,34 @@
* WordPress dependencies
*/
import { getBlockSupport, hasBlockSupport } from '@wordpress/blocks';
-import { __experimentalToolsPanelItem as ToolsPanelItem } from '@wordpress/components';
-import { __ } from '@wordpress/i18n';
+import { useMemo } from '@wordpress/element';
/**
* Internal dependencies
*/
import InspectorControls from '../components/inspector-controls';
-import { getFontAppearanceLabel } from '../components/font-appearance-control';
-
-import {
- LINE_HEIGHT_SUPPORT_KEY,
- LineHeightEdit,
- hasLineHeightValue,
- resetLineHeight,
- useIsLineHeightDisabled,
-} from './line-height';
-import {
- FONT_STYLE_SUPPORT_KEY,
- FONT_WEIGHT_SUPPORT_KEY,
- FontAppearanceEdit,
- hasFontAppearanceValue,
- resetFontAppearance,
- useIsFontAppearanceDisabled,
- useIsFontStyleDisabled,
- useIsFontWeightDisabled,
-} from './font-appearance';
-import {
- FONT_FAMILY_SUPPORT_KEY,
- FontFamilyEdit,
- hasFontFamilyValue,
- resetFontFamily,
- useIsFontFamilyDisabled,
-} from './font-family';
-import {
- FONT_SIZE_SUPPORT_KEY,
- FontSizeEdit,
- hasFontSizeValue,
- resetFontSize,
- useIsFontSizeDisabled,
-} from './font-size';
-import {
- TEXT_DECORATION_SUPPORT_KEY,
- TextDecorationEdit,
- hasTextDecorationValue,
- resetTextDecoration,
- useIsTextDecorationDisabled,
-} from './text-decoration';
-import {
- TEXT_TRANSFORM_SUPPORT_KEY,
- TextTransformEdit,
- hasTextTransformValue,
- resetTextTransform,
- useIsTextTransformDisabled,
-} from './text-transform';
import {
- LETTER_SPACING_SUPPORT_KEY,
- LetterSpacingEdit,
- hasLetterSpacingValue,
- resetLetterSpacing,
- useIsLetterSpacingDisabled,
-} from './letter-spacing';
+ default as StylesTypographyPanel,
+ useHasTypographyPanel,
+} from '../components/global-styles/typography-panel';
+
+import { LINE_HEIGHT_SUPPORT_KEY } from './line-height';
+import { FONT_FAMILY_SUPPORT_KEY } from './font-family';
+import { FONT_SIZE_SUPPORT_KEY } from './font-size';
+import { useSetting } from '../components';
+import { cleanEmptyObject } from './utils';
+
+function omit( object, keys ) {
+ return Object.fromEntries(
+ Object.entries( object ).filter( ( [ key ] ) => ! keys.includes( key ) )
+ );
+}
+const LETTER_SPACING_SUPPORT_KEY = 'typography.__experimentalLetterSpacing';
+const TEXT_TRANSFORM_SUPPORT_KEY = 'typography.__experimentalTextTransform';
+const TEXT_DECORATION_SUPPORT_KEY = 'typography.__experimentalTextDecoration';
+const FONT_STYLE_SUPPORT_KEY = 'typography.__experimentalFontStyle';
+const FONT_WEIGHT_SUPPORT_KEY = 'typography.__experimentalFontWeight';
export const TYPOGRAPHY_SUPPORT_KEY = 'typography';
export const TYPOGRAPHY_SUPPORT_KEYS = [
LINE_HEIGHT_SUPPORT_KEY,
@@ -76,159 +42,98 @@ export const TYPOGRAPHY_SUPPORT_KEYS = [
LETTER_SPACING_SUPPORT_KEY,
];
-export function TypographyPanel( props ) {
- const { clientId } = props;
- const isFontFamilyDisabled = useIsFontFamilyDisabled( props );
- const isFontSizeDisabled = useIsFontSizeDisabled( props );
- const isFontAppearanceDisabled = useIsFontAppearanceDisabled( props );
- const isLineHeightDisabled = useIsLineHeightDisabled( props );
- const isTextDecorationDisabled = useIsTextDecorationDisabled( props );
- const isTextTransformDisabled = useIsTextTransformDisabled( props );
- const isLetterSpacingDisabled = useIsLetterSpacingDisabled( props );
+function TypographyInspectorControl( { children } ) {
+ return (
+ { children }
+ );
+}
+
+export function TypographyPanel( {
+ clientId,
+ name,
+ attributes,
+ setAttributes,
+} ) {
+ const settings = {
+ typography: {
+ fontFamilies: {
+ custom: useSetting( 'typography.fontFamilies' ),
+ },
+ fontSizes: {
+ custom: useSetting( 'typography.fontSizes' ),
+ },
+ customFontSize: useSetting( 'typography.customFontSize' ),
+ fontStyle: useSetting( 'typography.fontStyle' ),
+ fontWeight: useSetting( 'typography.fontWeight' ),
+ lineHeight: useSetting( 'typography.lineHeight' ),
+ textDecoration: useSetting( 'typography.textDecoration' ),
+ textTransform: useSetting( 'typography.textTransform' ),
+ letterSpacing: useSetting( 'typography.letterSpacing' ),
+ },
+ };
+
+ const isSupported = hasTypographySupport( name );
+ const isEnabled = useHasTypographyPanel( name, null, settings );
- const hasFontStyles = ! useIsFontStyleDisabled( props );
- const hasFontWeights = ! useIsFontWeightDisabled( props );
+ const value = useMemo( () => {
+ return {
+ ...attributes.style,
+ typography: {
+ ...attributes.style?.typography,
+ fontFamily: attributes.fontFamily
+ ? 'var:preset|font-family|' + attributes.fontFamily
+ : undefined,
+ fontSize: attributes.fontSize
+ ? 'var:preset|font-size|' + attributes.fontSize
+ : attributes.style?.typography?.fontSize,
+ },
+ };
+ }, [ attributes.style, attributes.fontSize, attributes.fontFamily ] );
- const isDisabled = useIsTypographyDisabled( props );
- const isSupported = hasTypographySupport( props.name );
+ const onChange = ( newStyle ) => {
+ const updatedStyle = { ...omit( newStyle, [ 'fontFamily' ] ) };
+ const fontSizeValue = newStyle?.typography?.fontSize;
+ const fontFamilyValue = newStyle?.typography?.fontFamily;
+ const fontSizeSlug = fontSizeValue?.startsWith(
+ 'var:preset|font-size|'
+ )
+ ? fontSizeValue.substring( 'var:preset|font-size|'.length )
+ : undefined;
+ const fontFamilySlug = fontFamilyValue?.startsWith(
+ 'var:preset|font-family|'
+ )
+ ? fontFamilyValue.substring( 'var:preset|font-family|'.length )
+ : undefined;
+ updatedStyle.typography = {
+ ...omit( updatedStyle.typography, [ 'fontFamily' ] ),
+ fontSize: fontSizeSlug ? undefined : fontSizeValue,
+ };
+ setAttributes( {
+ style: cleanEmptyObject( updatedStyle ),
+ fontFamily: fontFamilySlug,
+ fontSize: fontSizeSlug,
+ } );
+ };
- if ( isDisabled || ! isSupported ) return null;
+ if ( ! isEnabled || ! isSupported ) {
+ return null;
+ }
- const defaultControls = getBlockSupport( props.name, [
+ const defaultControls = getBlockSupport( name, [
TYPOGRAPHY_SUPPORT_KEY,
'__experimentalDefaultControls',
] );
- const createResetAllFilter = ( attribute ) => ( newAttributes ) => ( {
- ...newAttributes,
- style: {
- ...newAttributes.style,
- typography: {
- ...newAttributes.style?.typography,
- [ attribute ]: undefined,
- },
- },
- } );
-
return (
-
- { ! isFontFamilyDisabled && (
- hasFontFamilyValue( props ) }
- label={ __( 'Font family' ) }
- onDeselect={ () => resetFontFamily( props ) }
- isShownByDefault={ defaultControls?.fontFamily }
- resetAllFilter={ ( newAttributes ) => ( {
- ...newAttributes,
- fontFamily: undefined,
- } ) }
- panelId={ clientId }
- >
-
-
- ) }
- { ! isFontSizeDisabled && (
- hasFontSizeValue( props ) }
- /* translators: Ensure translation is distinct from "Letter case" */
- label={ __( 'Font size' ) }
- onDeselect={ () => resetFontSize( props ) }
- isShownByDefault={ defaultControls?.fontSize }
- resetAllFilter={ ( newAttributes ) => ( {
- ...newAttributes,
- fontSize: undefined,
- style: {
- ...newAttributes.style,
- typography: {
- ...newAttributes.style?.typography,
- fontSize: undefined,
- },
- },
- } ) }
- panelId={ clientId }
- >
-
-
- ) }
- { ! isFontAppearanceDisabled && (
- hasFontAppearanceValue( props ) }
- label={ getFontAppearanceLabel(
- hasFontStyles,
- hasFontWeights
- ) }
- onDeselect={ () => resetFontAppearance( props ) }
- isShownByDefault={ defaultControls?.fontAppearance }
- resetAllFilter={ ( newAttributes ) => ( {
- ...newAttributes,
- style: {
- ...newAttributes.style,
- typography: {
- ...newAttributes.style?.typography,
- fontStyle: undefined,
- fontWeight: undefined,
- },
- },
- } ) }
- panelId={ clientId }
- >
-
-
- ) }
- { ! isLineHeightDisabled && (
- hasLineHeightValue( props ) }
- label={ __( 'Line height' ) }
- onDeselect={ () => resetLineHeight( props ) }
- isShownByDefault={ defaultControls?.lineHeight }
- resetAllFilter={ createResetAllFilter( 'lineHeight' ) }
- panelId={ clientId }
- >
-
-
- ) }
- { ! isLetterSpacingDisabled && (
- hasLetterSpacingValue( props ) }
- label={ __( 'Letter spacing' ) }
- onDeselect={ () => resetLetterSpacing( props ) }
- isShownByDefault={ defaultControls?.letterSpacing }
- resetAllFilter={ createResetAllFilter( 'letterSpacing' ) }
- panelId={ clientId }
- >
-
-
- ) }
- { ! isTextDecorationDisabled && (
- hasTextDecorationValue( props ) }
- label={ __( 'Decoration' ) }
- onDeselect={ () => resetTextDecoration( props ) }
- isShownByDefault={ defaultControls?.textDecoration }
- resetAllFilter={ createResetAllFilter( 'textDecoration' ) }
- panelId={ clientId }
- >
-
-
- ) }
- { ! isTextTransformDisabled && (
- hasTextTransformValue( props ) }
- /* translators: Ensure translation is distinct from "Font size" */
- label={ __( 'Letter case' ) }
- onDeselect={ () => resetTextTransform( props ) }
- isShownByDefault={ defaultControls?.textTransform }
- resetAllFilter={ createResetAllFilter( 'textTransform' ) }
- panelId={ clientId }
- >
-
-
- ) }
-
+
);
}
@@ -237,17 +142,3 @@ export const hasTypographySupport = ( blockName ) => {
hasBlockSupport( blockName, key )
);
};
-
-function useIsTypographyDisabled( props = {} ) {
- const configs = [
- useIsFontAppearanceDisabled( props ),
- useIsFontSizeDisabled( props ),
- useIsLineHeightDisabled( props ),
- useIsFontFamilyDisabled( props ),
- useIsTextDecorationDisabled( props ),
- useIsTextTransformDisabled( props ),
- useIsLetterSpacingDisabled( props ),
- ];
-
- return configs.filter( Boolean ).length === configs.length;
-}
diff --git a/packages/edit-site/src/components/global-styles/color-utils.js b/packages/edit-site/src/components/global-styles/color-utils.js
index a80684344e7a0..b022b8506b0a2 100644
--- a/packages/edit-site/src/components/global-styles/color-utils.js
+++ b/packages/edit-site/src/components/global-styles/color-utils.js
@@ -1,7 +1,6 @@
/**
* Internal dependencies
*/
-
import { useSupportedStyles } from './hooks';
export function useHasColorPanel( name ) {
diff --git a/packages/edit-site/src/components/global-styles/context-menu.js b/packages/edit-site/src/components/global-styles/context-menu.js
index 96251c94d8c08..0e0cab1027650 100644
--- a/packages/edit-site/src/components/global-styles/context-menu.js
+++ b/packages/edit-site/src/components/global-styles/context-menu.js
@@ -21,6 +21,7 @@ import {
import { isRTL, __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
+import { experiments as blockEditorExperiments } from '@wordpress/block-editor';
/**
* Internal dependencies
@@ -28,15 +29,20 @@ import { store as coreStore } from '@wordpress/core-data';
import { useHasBorderPanel } from './border-panel';
import { useHasColorPanel } from './color-utils';
import { useHasDimensionsPanel } from './dimensions-panel';
-import { useHasTypographyPanel } from './typography-panel';
import { useHasVariationsPanel } from './variations-panel';
import { NavigationButtonAsItem } from './navigation-button';
import { IconWithCurrentColor } from './icon-with-current-color';
import { ScreenVariations } from './screen-variations';
import { useHasShadowControl } from './shadow-panel';
+import { unlock } from '../../experiments';
+
+const { useHasTypographyPanel, useGlobalSetting } = unlock(
+ blockEditorExperiments
+);
function ContextMenu( { name, parentMenu = '' } ) {
- const hasTypographyPanel = useHasTypographyPanel( name );
+ const [ settings ] = useGlobalSetting( '', name );
+ const hasTypographyPanel = useHasTypographyPanel( name, null, settings );
const hasColorPanel = useHasColorPanel( name );
const hasBorderPanel = useHasBorderPanel( name );
const hasEffectsPanel = useHasShadowControl( name );
diff --git a/packages/edit-site/src/components/global-styles/screen-block-list.js b/packages/edit-site/src/components/global-styles/screen-block-list.js
index 144bfba265f37..7b2e931bfcb00 100644
--- a/packages/edit-site/src/components/global-styles/screen-block-list.js
+++ b/packages/edit-site/src/components/global-styles/screen-block-list.js
@@ -10,7 +10,10 @@ import {
} from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useState, useMemo, useEffect, useRef } from '@wordpress/element';
-import { BlockIcon } from '@wordpress/block-editor';
+import {
+ BlockIcon,
+ experiments as blockEditorExperiments,
+} from '@wordpress/block-editor';
import { useDebounce } from '@wordpress/compose';
import { speak } from '@wordpress/a11y';
@@ -20,10 +23,14 @@ import { speak } from '@wordpress/a11y';
import { useHasBorderPanel } from './border-panel';
import { useHasColorPanel } from './color-utils';
import { useHasDimensionsPanel } from './dimensions-panel';
-import { useHasTypographyPanel } from './typography-panel';
import { useHasVariationsPanel } from './variations-panel';
import ScreenHeader from './header';
import { NavigationButtonAsItem } from './navigation-button';
+import { unlock } from '../../experiments';
+
+const { useHasTypographyPanel, useGlobalSetting } = unlock(
+ blockEditorExperiments
+);
function useSortedBlockTypes() {
const blockItems = useSelect(
@@ -49,7 +56,12 @@ function useSortedBlockTypes() {
}
function BlockMenuItem( { block } ) {
- const hasTypographyPanel = useHasTypographyPanel( block.name );
+ const [ settings ] = useGlobalSetting( '', block.name );
+ const hasTypographyPanel = useHasTypographyPanel(
+ block.name,
+ null,
+ settings
+ );
const hasColorPanel = useHasColorPanel( block.name );
const hasBorderPanel = useHasBorderPanel( block.name );
const hasDimensionsPanel = useHasDimensionsPanel( block.name );
diff --git a/packages/edit-site/src/components/global-styles/typography-panel.js b/packages/edit-site/src/components/global-styles/typography-panel.js
index 114ed4fb3ba67..214a08cf6e9f3 100644
--- a/packages/edit-site/src/components/global-styles/typography-panel.js
+++ b/packages/edit-site/src/components/global-styles/typography-panel.js
@@ -1,178 +1,18 @@
/**
* WordPress dependencies
*/
-import {
- LineHeightControl,
- __experimentalFontFamilyControl as FontFamilyControl,
- __experimentalFontAppearanceControl as FontAppearanceControl,
- __experimentalLetterSpacingControl as LetterSpacingControl,
- __experimentalTextTransformControl as TextTransformControl,
- __experimentalTextDecorationControl as TextDecorationControl,
- experiments as blockEditorExperiments,
-} from '@wordpress/block-editor';
-import {
- FontSizePicker,
- __experimentalToolsPanel as ToolsPanel,
- __experimentalToolsPanelItem as ToolsPanelItem,
-} from '@wordpress/components';
-import { __ } from '@wordpress/i18n';
+import { experiments as blockEditorExperiments } from '@wordpress/block-editor';
/**
* Internal dependencies
*/
-import { useSupportedStyles } from './hooks';
import { unlock } from '../../experiments';
-const { useGlobalSetting, useGlobalStyle } = unlock( blockEditorExperiments );
-
-export function useHasTypographyPanel( name ) {
- const hasFontFamily = useHasFontFamilyControl( name );
- const hasLineHeight = useHasLineHeightControl( name );
- const hasFontAppearance = useHasAppearanceControl( name );
- const hasLetterSpacing = useHasLetterSpacingControl( name );
- const supports = useSupportedStyles( name );
- return (
- hasFontFamily ||
- hasLineHeight ||
- hasFontAppearance ||
- hasLetterSpacing ||
- supports.includes( 'fontSize' )
- );
-}
-
-function useHasFontFamilyControl( name ) {
- const supports = useSupportedStyles( name );
- const [ fontFamiliesPerOrigin ] = useGlobalSetting(
- 'typography.fontFamilies',
- name
- );
- const fontFamilies =
- fontFamiliesPerOrigin?.custom ||
- fontFamiliesPerOrigin?.theme ||
- fontFamiliesPerOrigin?.default;
- return supports.includes( 'fontFamily' ) && !! fontFamilies?.length;
-}
-
-function useHasLineHeightControl( name ) {
- const supports = useSupportedStyles( name );
- return (
- useGlobalSetting( 'typography.lineHeight', name )[ 0 ] &&
- supports.includes( 'lineHeight' )
- );
-}
-
-function useHasAppearanceControl( name ) {
- const supports = useSupportedStyles( name );
- const hasFontStyles =
- useGlobalSetting( 'typography.fontStyle', name )[ 0 ] &&
- supports.includes( 'fontStyle' );
- const hasFontWeights =
- useGlobalSetting( 'typography.fontWeight', name )[ 0 ] &&
- supports.includes( 'fontWeight' );
- return hasFontStyles || hasFontWeights;
-}
-
-function useAppearanceControlLabel( name ) {
- const supports = useSupportedStyles( name );
- const hasFontStyles =
- useGlobalSetting( 'typography.fontStyle', name )[ 0 ] &&
- supports.includes( 'fontStyle' );
- const hasFontWeights =
- useGlobalSetting( 'typography.fontWeight', name )[ 0 ] &&
- supports.includes( 'fontWeight' );
- if ( ! hasFontStyles ) {
- return __( 'Font weight' );
- }
- if ( ! hasFontWeights ) {
- return __( 'Font style' );
- }
- return __( 'Appearance' );
-}
-
-function useHasLetterSpacingControl( name, element ) {
- const supports = useSupportedStyles( name, element );
- return (
- useGlobalSetting( 'typography.letterSpacing', name )[ 0 ] &&
- supports.includes( 'letterSpacing' )
- );
-}
-
-function useHasTextTransformControl( name, element ) {
- const supports = useSupportedStyles( name, element );
- return (
- useGlobalSetting( 'typography.textTransform', name )[ 0 ] &&
- supports.includes( 'textTransform' )
- );
-}
-
-function useHasTextDecorationControl( name, element ) {
- // This is an exception for link elements.
- // We shouldn't allow other blocks or elements to set textDecoration
- // because this will be inherited by their children.
- return ! name && element === 'link';
-}
-
-function useStyleWithReset( path, blockName ) {
- const [ style, setStyle ] = useGlobalStyle( path, blockName );
- const [ userStyle ] = useGlobalStyle( path, blockName, 'user' );
- const hasStyle = () => !! userStyle;
- const resetStyle = () => setStyle( undefined );
- return [ style, setStyle, hasStyle, resetStyle ];
-}
-
-function useFontSizeWithReset( path, blockName ) {
- const [ fontSize, setStyleCallback ] = useGlobalStyle( path, blockName );
- const [ userStyle ] = useGlobalStyle( path, blockName, 'user' );
- const hasFontSize = () => !! userStyle;
- const resetFontSize = () => setStyleCallback( undefined );
- const setFontSize = ( newValue, metadata ) => {
- if ( !! metadata?.slug ) {
- newValue = `var:preset|font-size|${ metadata?.slug }`;
- }
- setStyleCallback( newValue );
- };
-
- return {
- fontSize,
- setFontSize,
- hasFontSize,
- resetFontSize,
- };
-}
-
-function useFontAppearance( prefix, name ) {
- const [ fontStyle, setFontStyle ] = useGlobalStyle(
- prefix + 'typography.fontStyle',
- name
- );
- const [ userFontStyle ] = useGlobalStyle(
- prefix + 'typography.fontStyle',
- name,
- 'user'
- );
- const [ fontWeight, setFontWeight ] = useGlobalStyle(
- prefix + 'typography.fontWeight',
- name
- );
- const [ userFontWeight ] = useGlobalStyle(
- prefix + 'typography.fontWeight',
- name,
- 'user'
- );
- const hasFontAppearance = () => !! userFontStyle || !! userFontWeight;
- const resetFontAppearance = () => {
- setFontStyle( undefined );
- setFontWeight( undefined );
- };
- return {
- fontStyle,
- setFontStyle,
- fontWeight,
- setFontWeight,
- hasFontAppearance,
- resetFontAppearance,
- };
-}
+const {
+ useGlobalStyle,
+ useGlobalSetting,
+ TypographyPanel: StylesTypographyPanel,
+} = unlock( blockEditorExperiments );
export default function TypographyPanel( {
name,
@@ -180,234 +20,31 @@ export default function TypographyPanel( {
headingLevel,
variation = '',
} ) {
- const supports = useSupportedStyles( name );
- let prefix = '';
+ let prefixParts = [];
if ( element === 'heading' ) {
- prefix = `elements.${ headingLevel }.`;
+ prefixParts = prefixParts.concat( [ 'elements', headingLevel ] );
} else if ( element && element !== 'text' ) {
- prefix = `elements.${ element }.`;
+ prefixParts = prefixParts.concat( [ 'elements', element ] );
}
if ( variation ) {
- prefix = prefix
- ? `variations.${ variation }.${ prefix }`
- : `variations.${ variation }`;
+ prefixParts = [ 'variations', variation ].concat( prefixParts );
}
- const [ fontSizesPerOrigin ] = useGlobalSetting(
- 'typography.fontSizes',
- name
- );
- const fontSizes =
- fontSizesPerOrigin?.custom ||
- fontSizesPerOrigin?.theme ||
- fontSizesPerOrigin?.default;
-
- const disableCustomFontSizes = ! useGlobalSetting(
- 'typography.customFontSize',
- name
- )[ 0 ];
- const [ fontFamiliesPerOrigin ] = useGlobalSetting(
- 'typography.fontFamilies',
- name
- );
- const fontFamilies =
- fontFamiliesPerOrigin?.custom ||
- fontFamiliesPerOrigin?.theme ||
- fontFamiliesPerOrigin?.default;
- const hasFontStyles =
- useGlobalSetting( 'typography.fontStyle', name )[ 0 ] &&
- supports.includes( 'fontStyle' );
- const hasFontWeights =
- useGlobalSetting( 'typography.fontWeight', name )[ 0 ] &&
- supports.includes( 'fontWeight' );
- const hasFontFamilyEnabled = useHasFontFamilyControl( name );
- const hasLineHeightEnabled = useHasLineHeightControl( name );
- const hasAppearanceControl = useHasAppearanceControl( name );
- const appearanceControlLabel = useAppearanceControlLabel( name );
- const hasLetterSpacingControl = useHasLetterSpacingControl( name, element );
- const hasTextTransformControl = useHasTextTransformControl( name, element );
- const hasTextDecorationControl = useHasTextDecorationControl(
- name,
- element
- );
-
- /* Disable font size controls when the option to style all headings is selected. */
- let hasFontSizeEnabled = supports.includes( 'fontSize' );
- if ( element === 'heading' && headingLevel === 'heading' ) {
- hasFontSizeEnabled = false;
- }
-
- const [ fontFamily, setFontFamily, hasFontFamily, resetFontFamily ] =
- useStyleWithReset( prefix + 'typography.fontFamily', name );
- const { fontSize, setFontSize, hasFontSize, resetFontSize } =
- useFontSizeWithReset( prefix + 'typography.fontSize', name );
- const {
- fontStyle,
- setFontStyle,
- fontWeight,
- setFontWeight,
- hasFontAppearance,
- resetFontAppearance,
- } = useFontAppearance( prefix, name );
- const [ lineHeight, setLineHeight, hasLineHeight, resetLineHeight ] =
- useStyleWithReset( prefix + 'typography.lineHeight', name );
- const [
- letterSpacing,
- setLetterSpacing,
- hasLetterSpacing,
- resetLetterSpacing,
- ] = useStyleWithReset( prefix + 'typography.letterSpacing', name );
- const [
- textTransform,
- setTextTransform,
- hasTextTransform,
- resetTextTransform,
- ] = useStyleWithReset( prefix + 'typography.textTransform', name );
- const [
- textDecoration,
- setTextDecoration,
- hasTextDecoration,
- resetTextDecoration,
- ] = useStyleWithReset( prefix + 'typography.textDecoration', name );
+ const prefix = prefixParts.join( '.' );
- const resetAll = () => {
- resetFontFamily();
- resetFontSize();
- resetFontAppearance();
- resetLineHeight();
- resetLetterSpacing();
- resetTextTransform();
- };
+ const [ style ] = useGlobalStyle( prefix, name, 'user', false );
+ const [ inheritedStyle, setStyle ] = useGlobalStyle( prefix, name, 'all', {
+ shouldDecodeEncode: false,
+ } );
+ const [ settings ] = useGlobalSetting( '', name );
return (
-
- { hasFontFamilyEnabled && (
-
-
-
- ) }
- { hasFontSizeEnabled && (
-
-
-
- ) }
- { hasAppearanceControl && (
-
- {
- setFontStyle( newFontStyle );
- setFontWeight( newFontWeight );
- } }
- hasFontStyles={ hasFontStyles }
- hasFontWeights={ hasFontWeights }
- size="__unstable-large"
- __nextHasNoMarginBottom
- />
-
- ) }
- { hasLineHeightEnabled && (
-
-
-
- ) }
- { hasLetterSpacingControl && (
-
-
-
- ) }
- { hasTextTransformControl && (
-
-
-
- ) }
- { hasTextDecorationControl && (
-
-
-
- ) }
-
+
);
}