diff --git a/docs/designers-developers/developers/themes/theme-json.md b/docs/designers-developers/developers/themes/theme-json.md
index 3f89813a103207..eedc3278c3b302 100644
--- a/docs/designers-developers/developers/themes/theme-json.md
+++ b/docs/designers-developers/developers/themes/theme-json.md
@@ -93,6 +93,8 @@ The settings section has the following structure and default values:
},
"typography": {
"customFontSize": true, /* false to opt-out, as in add_theme_support( 'disable-custom-font-sizes' ) */
+ "customFontWeight": true, /* false to opt-out */
+ "customFontStyle": true, /* false to opt-out */
"customLineHeight": false, /* true to opt-in, as in add_theme_support( 'custom-line-height' ) */
"dropCap": true, /* false to opt-out */
"fontFamilies": [ ... ], /* font family presets */
diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php
index 548134f3cd2157..8f0071f0478abe 100644
--- a/lib/class-wp-theme-json.php
+++ b/lib/class-wp-theme-json.php
@@ -130,15 +130,15 @@ class WP_Theme_JSON {
'units' => null,
),
'typography' => array(
- 'customFontSize' => null,
- 'customLineHeight' => null,
- 'dropCap' => null,
- 'fontFamilies' => null,
- 'fontSizes' => null,
- 'fontStyles' => null,
- 'fontWeights' => null,
- 'textDecorations' => null,
- 'textTransforms' => null,
+ 'customFontSize' => null,
+ 'customLineHeight' => null,
+ 'dropCap' => null,
+ 'fontFamilies' => null,
+ 'fontSizes' => null,
+ 'customFontStyle' => null,
+ 'customFontWeight' => null,
+ 'customTextDecorations' => null,
+ 'customTextTransforms' => null,
),
'custom' => null,
),
@@ -221,50 +221,6 @@ class WP_Theme_JSON {
'css_var_infix' => 'font-family',
'classes' => array(),
),
- array(
- 'path' => array( 'settings', 'typography', 'fontStyles' ),
- 'value_key' => 'value',
- 'css_var_infix' => 'font-style',
- 'classes' => array(
- array(
- 'class_suffix' => 'font-style',
- 'property_name' => 'font-style',
- ),
- ),
- ),
- array(
- 'path' => array( 'settings', 'typography', 'fontWeights' ),
- 'value_key' => 'value',
- 'css_var_infix' => 'font-weight',
- 'classes' => array(
- array(
- 'class_suffix' => 'font-weight',
- 'property_name' => 'font-weight',
- ),
- ),
- ),
- array(
- 'path' => array( 'settings', 'typography', 'textDecorations' ),
- 'value_key' => 'value',
- 'css_var_infix' => 'text-decoration',
- 'classes' => array(
- array(
- 'class_suffix' => 'text-decoration',
- 'property_name' => 'text-decoration',
- ),
- ),
- ),
- array(
- 'path' => array( 'settings', 'typography', 'textTransforms' ),
- 'value_key' => 'slug',
- 'css_var_infix' => 'text-transform',
- 'classes' => array(
- array(
- 'class_suffix' => 'text-transform',
- 'property_name' => 'text-transform',
- ),
- ),
- ),
);
/**
diff --git a/lib/experimental-default-theme.json b/lib/experimental-default-theme.json
index b2a1c31a639dbe..15904819cfd7f5 100644
--- a/lib/experimental-default-theme.json
+++ b/lib/experimental-default-theme.json
@@ -134,6 +134,10 @@
"dropCap": true,
"customFontSize": true,
"customLineHeight": false,
+ "customFontStyle": true,
+ "customFontWeight": true,
+ "customTextTransforms": true,
+ "customTextDecorations": true,
"fontSizes": [
{
"name": "Small",
@@ -160,91 +164,6 @@
"slug": "huge",
"size": "42px"
}
- ],
- "fontStyles": [
- {
- "name": "Regular",
- "slug": "normal",
- "value": "normal"
- },
- {
- "name": "Italic",
- "slug": "italic",
- "value": "italic"
- }
- ],
- "fontWeights": [
- {
- "name": "Ultralight",
- "slug": "100",
- "value": "100"
- },
- {
- "name": "Thin",
- "slug": "200",
- "value": "200"
- },
- {
- "name": "Light",
- "slug": "300",
- "value": "300"
- },
- {
- "name": "Regular",
- "slug": "400",
- "value": "400"
- },
- {
- "name": "Medium",
- "slug": "500",
- "value": "500"
- },
- {
- "name": "Semibold",
- "slug": "600",
- "value": "600"
- },
- {
- "name": "Bold",
- "slug": "700",
- "value": "700"
- },
- {
- "name": "Heavy",
- "slug": "800",
- "value": "800"
- },
- {
- "name": "Black",
- "slug": "900",
- "value": "900"
- }
- ],
- "textTransforms": [
- {
- "name": "AB",
- "slug": "uppercase"
- },
- {
- "name": "ab",
- "slug": "lowercase"
- },
- {
- "name": "Ab",
- "slug": "capitalize"
- }
- ],
- "textDecorations": [
- {
- "name": "Underline",
- "slug": "underline",
- "value": "underline"
- },
- {
- "name": "Strikethrough",
- "slug": "strikethrough",
- "value": "line-through"
- }
]
},
"spacing": {
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 c6670368a03926..d318d3e2efcfd6 100644
--- a/packages/block-editor/src/components/font-appearance-control/index.js
+++ b/packages/block-editor/src/components/font-appearance-control/index.js
@@ -5,6 +5,56 @@ import { CustomSelectControl } from '@wordpress/components';
import { useMemo } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
+const FONT_STYLES = [
+ {
+ name: __( 'Regular' ),
+ value: 'normal',
+ },
+ {
+ name: __( 'Italic' ),
+ value: 'italic',
+ },
+];
+
+const FONT_WEIGHTS = [
+ {
+ name: __( 'Ultralight' ),
+ value: '100',
+ },
+ {
+ name: __( 'Thin' ),
+ value: '200',
+ },
+ {
+ name: __( 'Light' ),
+ value: '300',
+ },
+ {
+ name: __( 'Regular' ),
+ value: '400',
+ },
+ {
+ name: __( 'Medium' ),
+ value: '500',
+ },
+ {
+ name: __( 'Semibold' ),
+ value: '600',
+ },
+ {
+ name: __( 'Bold' ),
+ value: '700',
+ },
+ {
+ name: __( 'Heavy' ),
+ value: '800',
+ },
+ {
+ name: __( 'Black' ),
+ value: '900',
+ },
+];
+
/**
* Control to display unified font style and weight options.
*
@@ -14,12 +64,11 @@ import { __, sprintf } from '@wordpress/i18n';
export default function FontAppearanceControl( props ) {
const {
onChange,
- options: { fontStyles = [], fontWeights = [] },
+ hasFontStyles = true,
+ hasFontWeights = true,
value: { fontStyle, fontWeight },
} = props;
- const hasStyles = !! fontStyles.length;
- const hasWeights = !! fontWeights.length;
- const hasStylesOrWeights = hasStyles || hasWeights;
+ const hasStylesOrWeights = hasFontStyles || hasFontWeights;
const defaultOption = {
key: 'default',
name: __( 'Default' ),
@@ -30,24 +79,29 @@ export default function FontAppearanceControl( props ) {
const combineOptions = () => {
const combinedOptions = [ defaultOption ];
- fontStyles.forEach( ( { name: styleName, slug: styleSlug } ) => {
- fontWeights.forEach( ( { name: weightName, slug: weightSlug } ) => {
- const optionName =
- styleSlug === 'normal'
- ? weightName
- : sprintf(
- /* translators: 1: Font weight name. 2: Font style name. */
- __( '%1$s %2$s' ),
- weightName,
- styleName
- );
-
- combinedOptions.push( {
- key: `${ weightSlug }-${ styleSlug }`,
- name: optionName,
- style: { fontStyle: styleSlug, fontWeight: weightSlug },
- } );
- } );
+ FONT_STYLES.forEach( ( { name: styleName, value: styleValue } ) => {
+ FONT_WEIGHTS.forEach(
+ ( { name: weightName, value: weightValue } ) => {
+ const optionName =
+ styleValue === 'normal'
+ ? weightName
+ : sprintf(
+ /* translators: 1: Font weight name. 2: Font style name. */
+ __( '%1$s %2$s' ),
+ weightName,
+ styleName
+ );
+
+ combinedOptions.push( {
+ key: `${ styleValue }-${ weightValue }`,
+ name: optionName,
+ style: {
+ fontStyle: styleValue,
+ fontWeight: weightValue,
+ },
+ } );
+ }
+ );
} );
return combinedOptions;
@@ -56,11 +110,11 @@ export default function FontAppearanceControl( props ) {
// Generates select options for font styles only.
const styleOptions = () => {
const combinedOptions = [ defaultOption ];
- fontStyles.forEach( ( { name, slug } ) => {
+ FONT_STYLES.forEach( ( { name, value } ) => {
combinedOptions.push( {
- key: slug,
+ key: value,
name,
- style: { fontStyle: slug, fontWeight: undefined },
+ style: { fontStyle: value, fontWeight: undefined },
} );
} );
return combinedOptions;
@@ -69,11 +123,11 @@ export default function FontAppearanceControl( props ) {
// Generates select options for font weights only.
const weightOptions = () => {
const combinedOptions = [ defaultOption ];
- fontWeights.forEach( ( { name, slug } ) => {
+ FONT_WEIGHTS.forEach( ( { name, value } ) => {
combinedOptions.push( {
- key: slug,
+ key: value,
name,
- style: { fontStyle: undefined, fontWeight: slug },
+ style: { fontStyle: undefined, fontWeight: value },
} );
} );
return combinedOptions;
@@ -81,11 +135,11 @@ export default function FontAppearanceControl( props ) {
// Map font styles and weights to select options.
const selectOptions = useMemo( () => {
- if ( hasStyles && hasWeights ) {
+ if ( hasFontStyles && hasFontWeights ) {
return combineOptions();
}
- return hasStyles ? styleOptions() : weightOptions();
+ return hasFontStyles ? styleOptions() : weightOptions();
}, [ props.options ] );
// Find current selection by comparing font style & weight against options.
@@ -97,11 +151,11 @@ export default function FontAppearanceControl( props ) {
// Adjusts field label in case either styles or weights are disabled.
const getLabel = () => {
- if ( ! hasStyles ) {
+ if ( ! hasFontStyles ) {
return __( 'Font weight' );
}
- if ( ! hasWeights ) {
+ if ( ! hasFontWeights ) {
return __( 'Font style' );
}
diff --git a/packages/block-editor/src/components/text-decoration-control/index.js b/packages/block-editor/src/components/text-decoration-control/index.js
index d2be41e93622db..0385a5d6a943ec 100644
--- a/packages/block-editor/src/components/text-decoration-control/index.js
+++ b/packages/block-editor/src/components/text-decoration-control/index.js
@@ -5,71 +5,48 @@ import { Button } from '@wordpress/components';
import { formatStrikethrough, formatUnderline } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';
+const TEXT_DECORATIONS = [
+ {
+ name: __( 'Underline' ),
+ value: 'underline',
+ icon: formatUnderline,
+ },
+ {
+ name: __( 'Strikethrough' ),
+ value: 'line-through',
+ icon: formatStrikethrough,
+ },
+];
+
/**
* Control to facilitate text decoration selections.
*
* @param {Object} props Component props.
* @param {string} props.value Currently selected text decoration.
- * @param {Array} props.textDecorations Text decorations available for selection.
* @param {Function} props.onChange Handles change in text decoration selection.
* @return {WPElement} Text decoration control.
*/
-export default function TextDecorationControl( {
- value: textDecoration,
- textDecorations,
- onChange,
-} ) {
- /**
- * Determines the what the new text decoration is as a result of a user
- * interaction with the control. Then passes this on to the supplied
- * onChange handler.
- *
- * @param {string} newDecoration Slug for selected decoration.
- */
- const handleOnChange = ( newDecoration ) => {
- // Check if we are toggling a decoration off.
- const decoration =
- textDecoration === newDecoration ? undefined : newDecoration;
-
- // Ensure only defined text decorations are allowed.
- const presetDecoration = textDecorations.find(
- ( { slug } ) => slug === decoration
- );
-
- // Create string that will be turned into CSS custom property
- const newTextDecoration = presetDecoration
- ? `var:preset|text-decoration|${ presetDecoration.slug }`
- : undefined;
-
- onChange( newTextDecoration );
- };
-
- // Text Decoration icons to use.
- const icons = {
- strikethrough: formatStrikethrough,
- underline: formatUnderline,
- };
-
+export default function TextDecorationControl( { value, onChange } ) {
return (