diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 3f7ebb7c28d21..ed395d2d6bc62 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -60,6 +60,11 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) { $has_line_height_support = gutenberg_experimental_get( $block_type->supports, array( 'lineHeight' ), false ); } + $has_font_family_support = false; + if ( property_exists( $block_type, 'supports' ) ) { + $has_font_family_support = gutenberg_experimental_get( $block_type->supports, array( '__experimentalFontFamily' ), false ); + } + // Font Size. if ( $has_font_size_support ) { $has_named_font_size = array_key_exists( 'fontSize', $block_attributes ); @@ -73,6 +78,23 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) { } } + // Font Family. + if ( $has_font_family_support ) { + $has_font_family = isset( $block_attributes['style']['typography']['fontFamily'] ); + // Apply required class and style. + if ( $has_font_family ) { + $font_family = $block_attributes['style']['typography']['fontFamily']; + if ( strpos( $font_family, 'var:preset|font-family' ) !== false ) { + // Get the name from the string and add proper styles. + $index_to_splice = strrpos( $font_family, '|' ) + 1; + $font_family_name = substr( $font_family, $index_to_splice ); + $styles[] = sprintf( 'font-family: var(--wp--preset--font-family--%s);', $font_family_name ); + } else { + $styles[] = sprintf( 'font-family: %s;', $block_attributes['style']['color']['fontFamily'] ); + } + } + } + // Line Height. if ( $has_line_height_support ) { $has_line_height = isset( $block_attributes['style']['typography']['lineHeight'] ); diff --git a/lib/global-styles.php b/lib/global-styles.php index 544ef9fce1eb7..1e574edaaf0e2 100644 --- a/lib/global-styles.php +++ b/lib/global-styles.php @@ -395,6 +395,8 @@ function gutenberg_experimental_global_styles_get_css_property( $style_property return 'font-size'; case 'lineHeight': return 'line-height'; + case 'fontFamily': + return 'font-family'; default: return $style_property; } @@ -412,6 +414,7 @@ function gutenberg_experimental_global_styles_get_style_property() { 'backgroundColor' => array( 'color', 'background' ), 'color' => array( 'color', 'text' ), 'fontSize' => array( 'typography', 'fontSize' ), + 'fontFamily' => array( 'typography', 'fontFamily' ), 'lineHeight' => array( 'typography', 'lineHeight' ), ); } @@ -429,6 +432,7 @@ function gutenberg_experimental_global_styles_get_support_keys() { 'color' => array( 'color' ), 'fontSize' => array( 'fontSize' ), 'lineHeight' => array( 'lineHeight' ), + 'fontFamily' => array( '__experimentalFontFamily' ), ); } @@ -439,18 +443,22 @@ function gutenberg_experimental_global_styles_get_support_keys() { */ function gutenberg_experimental_global_styles_get_presets_structure() { return array( - 'color' => array( + 'color' => array( 'path' => array( 'color', 'palette' ), 'key' => 'color', ), - 'gradient' => array( + 'gradient' => array( 'path' => array( 'color', 'gradients' ), 'key' => 'gradient', ), - 'fontSize' => array( + 'fontSize' => array( 'path' => array( 'typography', 'fontSizes' ), 'key' => 'size', ), + 'fontFamily' => array( + 'path' => array( 'typography', 'fontFamilies' ), + 'key' => 'fontFamily', + ), ); } @@ -489,9 +497,10 @@ function gutenberg_experimental_global_styles_get_block_data() { 'global', array( 'supports' => array( - '__experimentalSelector' => ':root', - 'fontSize' => true, - 'color' => array( + '__experimentalSelector' => ':root', + '__experimentalFontFamily' => true, + 'fontSize' => true, + 'color' => array( 'linkColor' => true, 'gradients' => true, ), diff --git a/packages/block-editor/src/components/font-family/index.js b/packages/block-editor/src/components/font-family/index.js new file mode 100644 index 0000000000000..0f15033ee55a8 --- /dev/null +++ b/packages/block-editor/src/components/font-family/index.js @@ -0,0 +1,53 @@ +/** + * External dependencies + */ +import { isEmpty } from 'lodash'; + +/** + * WordPress dependencies + */ +import { SelectControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import useEditorFeature from '../use-editor-feature'; + +export default function FontFamilyControl( { + value = '', + onChange, + fontFamilies, + ...props +} ) { + const blockLevelFontFamilies = useEditorFeature( + 'typography.fontFamilies' + ); + if ( ! fontFamilies ) { + fontFamilies = blockLevelFontFamilies; + } + + if ( isEmpty( fontFamilies ) ) { + return null; + } + + const options = [ + { value: '', label: __( 'Default' ) }, + ...fontFamilies.map( ( { fontFamily, name } ) => { + return { + value: fontFamily, + label: name || fontFamily, + }; + } ), + ]; + return ( + + ); +} diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index 021b511fe51aa..c6506c5c58f7a 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -29,6 +29,7 @@ export { default as ContrastChecker } from './contrast-checker'; export { default as __experimentalGradientPicker } from './gradient-picker'; export { default as __experimentalGradientPickerControl } from './gradient-picker/control'; export { default as __experimentalGradientPickerPanel } from './gradient-picker/panel'; +export { default as __experimentalFontFamilyControl } from './font-family'; export { default as __experimentalColorGradientControl } from './colors-gradients/control'; export { default as __experimentalPanelColorGradientSettings } from './colors-gradients/panel-color-gradient-settings'; export { default as __experimentalImageSizeControl } from './image-size-control'; diff --git a/packages/block-editor/src/hooks/font-family.js b/packages/block-editor/src/hooks/font-family.js new file mode 100644 index 0000000000000..89fa784abf6e1 --- /dev/null +++ b/packages/block-editor/src/hooks/font-family.js @@ -0,0 +1,88 @@ +/** + * External dependencies + */ +import { find } from 'lodash'; + +/** + * WordPress dependencies + */ +import { hasBlockSupport } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { cleanEmptyObject } from './utils'; +import useEditorFeature from '../components/use-editor-feature'; +import FontFamilyControl from '../components/font-family'; + +export const FONT_FAMILY_SUPPORT_KEY = '__experimentalFontFamily'; + +const getFontFamilyFromAttributeValue = ( fontFamilies, value ) => { + const attributeParsed = /var:preset\|font-family\|(.+)/.exec( value ); + if ( attributeParsed && attributeParsed[ 1 ] ) { + return find( fontFamilies, ( { slug } ) => { + return slug === attributeParsed[ 1 ]; + } ).fontFamily; + } + return value; +}; + +export function FontFamilyEdit( { + name, + setAttributes, + attributes: { style = {} }, +} ) { + const fontFamilies = useEditorFeature( 'typography.fontFamilies' ); + const isDisable = useIsFontFamilyDisabled( { name } ); + + if ( isDisable ) { + return null; + } + + const value = getFontFamilyFromAttributeValue( + fontFamilies, + style.typography?.fontFamily + ); + + function onChange( newValue ) { + const predefinedFontFamily = find( + fontFamilies, + ( { fontFamily } ) => fontFamily === newValue + ); + setAttributes( { + style: cleanEmptyObject( { + ...style, + typography: { + ...( style.typography || {} ), + fontFamily: predefinedFontFamily + ? `var:preset|font-family|${ predefinedFontFamily.slug }` + : newValue || undefined, + }, + } ), + } ); + } + + 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 = useEditorFeature( 'typography.fontFamilies' ); + return ( + ! fontFamilies || + fontFamilies.length === 0 || + ! hasBlockSupport( name, FONT_FAMILY_SUPPORT_KEY ) + ); +} diff --git a/packages/block-editor/src/hooks/typography.js b/packages/block-editor/src/hooks/typography.js index 49a281cb219ea..e219d50b2f3ee 100644 --- a/packages/block-editor/src/hooks/typography.js +++ b/packages/block-editor/src/hooks/typography.js @@ -16,6 +16,11 @@ import { LineHeightEdit, useIsLineHeightDisabled, } from './line-height'; +import { + FONT_FAMILY_SUPPORT_KEY, + FontFamilyEdit, + useIsFontFamilyDisabled, +} from './font-family'; import { FONT_SIZE_SUPPORT_KEY, FontSizeEdit, @@ -25,6 +30,7 @@ import { export const TYPOGRAPHY_SUPPORT_KEYS = [ LINE_HEIGHT_SUPPORT_KEY, FONT_SIZE_SUPPORT_KEY, + FONT_FAMILY_SUPPORT_KEY, ]; export function TypographyPanel( props ) { @@ -36,6 +42,7 @@ export function TypographyPanel( props ) { return ( + @@ -56,6 +63,7 @@ function useIsTypographyDisabled( props = {} ) { const configs = [ useIsFontSizeDisabled( props ), useIsLineHeightDisabled( props ), + useIsFontFamilyDisabled( props ), ]; return configs.filter( Boolean ).length === configs.length; diff --git a/packages/block-library/src/navigation/block.json b/packages/block-library/src/navigation/block.json index b22fdfad89a77..2dfc91d4fa301 100644 --- a/packages/block-library/src/navigation/block.json +++ b/packages/block-library/src/navigation/block.json @@ -53,6 +53,7 @@ "color": { "textColor": true, "backgroundColor": true - } + }, + "__experimentalFontFamily": true } } diff --git a/packages/block-library/src/post-title/block.json b/packages/block-library/src/post-title/block.json index 3c8c63031bcb2..3339d39cf74df 100644 --- a/packages/block-library/src/post-title/block.json +++ b/packages/block-library/src/post-title/block.json @@ -35,6 +35,7 @@ }, "fontSize": true, "lineHeight": true, + "__experimentalFontFamily": true, "__experimentalSelector": { "core/post-title/h1": "h1", "core/post-title/h2": "h2", diff --git a/packages/block-library/src/site-tagline/block.json b/packages/block-library/src/site-tagline/block.json index 17220173c408e..cf7ae739576b9 100644 --- a/packages/block-library/src/site-tagline/block.json +++ b/packages/block-library/src/site-tagline/block.json @@ -13,6 +13,7 @@ "gradients": true }, "fontSize": true, - "lineHeight": true + "lineHeight": true, + "__experimentalFontFamily": true } } diff --git a/packages/block-library/src/site-title/block.json b/packages/block-library/src/site-title/block.json index bd10511fd1b3b..6e51654c1d807 100644 --- a/packages/block-library/src/site-title/block.json +++ b/packages/block-library/src/site-title/block.json @@ -17,6 +17,7 @@ "gradients": true }, "fontSize": true, - "lineHeight": true + "lineHeight": true, + "__experimentalFontFamily": true } } diff --git a/packages/blocks/src/api/constants.js b/packages/blocks/src/api/constants.js index 18488d1db55f7..5cb1483ac4e9a 100644 --- a/packages/blocks/src/api/constants.js +++ b/packages/blocks/src/api/constants.js @@ -23,4 +23,5 @@ export const __EXPERIMENTAL_STYLE_PROPERTY = { paddingLeft: [ 'spacing', 'padding', 'left' ], paddingRight: [ 'spacing', 'padding', 'right' ], paddingTop: [ 'spacing', 'padding', 'top' ], + fontFamily: [ 'typography', 'fontFamily' ], }; diff --git a/packages/edit-site/src/components/editor/utils.js b/packages/edit-site/src/components/editor/utils.js index 6ae765c15df48..2746dfcf55682 100644 --- a/packages/edit-site/src/components/editor/utils.js +++ b/packages/edit-site/src/components/editor/utils.js @@ -13,6 +13,7 @@ export const PRESET_CATEGORIES = { color: { path: [ 'color', 'palette' ], key: 'color' }, gradient: { path: [ 'color', 'gradients' ], key: 'gradient' }, fontSize: { path: [ 'typography', 'fontSizes' ], key: 'size' }, + fontFamily: { path: [ 'typography', 'fontFamilies' ], key: 'fontFamily' }, }; export const LINK_COLOR = '--wp--style--color--link'; export const LINK_COLOR_DECLARATION = `a { color: var(${ LINK_COLOR }, #00e); }`; diff --git a/packages/edit-site/src/components/sidebar/typography-panel.js b/packages/edit-site/src/components/sidebar/typography-panel.js index 20855fd998d10..73d8a13f6c28e 100644 --- a/packages/edit-site/src/components/sidebar/typography-panel.js +++ b/packages/edit-site/src/components/sidebar/typography-panel.js @@ -1,7 +1,10 @@ /** * WordPress dependencies */ -import { LineHeightControl } from '@wordpress/block-editor'; +import { + LineHeightControl, + __experimentalFontFamilyControl as FontFamilyControl, +} from '@wordpress/block-editor'; import { PanelBody, FontSizePicker } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; @@ -24,9 +27,18 @@ export default function TypographyPanel( { 'typography.customFontSize', name ); + const fontFamilies = useEditorFeature( 'typography.fontFamilies', name ); return ( + { supports.includes( 'fontFamily' ) && ( + + setStyleProperty( name, 'fontFamily', value ) + } + /> + ) } { supports.includes( 'fontSize' ) && ( setStyleProperty( name, 'lineHeight', value )