Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f594358
Block Editor: Convert LineHeightControl to TypeScript
manzoorwanijk Oct 15, 2026
6290c34
Block Editor: Convert the LineHeightControl tests to TypeScript
manzoorwanijk Oct 15, 2026
49ab81f
Block Editor: Convert the LineHeightControl story to TypeScript
manzoorwanijk Oct 15, 2026
f384a42
Block Editor: Convert TextTransformControl to TypeScript
manzoorwanijk Oct 15, 2026
446fe42
Block Editor: Convert the TextTransformControl story to TypeScript
manzoorwanijk Oct 15, 2026
ce40f88
Block Editor: Convert TextDecorationControl to TypeScript
manzoorwanijk Oct 15, 2026
a09274d
Block Editor: Convert the TextDecorationControl story to TypeScript
manzoorwanijk Oct 15, 2026
fa6a511
Block Editor: Convert LetterSpacingControl to TypeScript
manzoorwanijk Oct 15, 2026
8fadad8
Block Editor: Convert the LetterSpacingControl story to TypeScript
manzoorwanijk Oct 15, 2026
4839ec7
Block Editor: Convert TextAlignmentControl to TypeScript
manzoorwanijk Oct 15, 2026
7333b64
Block Editor: Convert the TextAlignmentControl story to TypeScript
manzoorwanijk Oct 15, 2026
ddd2f03
Block Editor: Convert WritingModeControl to TypeScript
manzoorwanijk Oct 15, 2026
c97e9fe
Block Editor: Convert the WritingModeControl story to TypeScript
manzoorwanijk Oct 15, 2026
4f5c070
Block Editor: Convert FontFamilyControl to TypeScript
manzoorwanijk Oct 15, 2026
3c9661d
Block Editor: Convert the FontFamilyControl story to TypeScript
manzoorwanijk Oct 15, 2026
075450f
Block Editor: Convert FontAppearanceControl to TypeScript
manzoorwanijk Oct 15, 2026
6900cdb
Block Editor: Convert the FontAppearanceControl tests to TypeScript
manzoorwanijk Oct 15, 2026
123782a
Block Editor: Convert TextIndentControl to TypeScript
manzoorwanijk Oct 15, 2026
c0e5bcf
Block Editor: Convert the font size utilities, FontSizePicker and wit…
manzoorwanijk Oct 15, 2026
b484445
Block Editor: Convert the font size tests to TypeScript
manzoorwanijk Oct 15, 2026
63b38f3
Block Editor: Update the ESLint suppressions of the converted typogra…
manzoorwanijk Oct 15, 2026
29526a9
Block Editor: Add the CHANGELOG entry for #84848
manzoorwanijk Oct 15, 2026
6b9f007
Block Editor: Accept font families without a name or slug in FontFami…
manzoorwanijk Oct 16, 2026
63f8adb
Block Editor: Type the props withFontSizes injects
manzoorwanijk Oct 16, 2026
e83febf
Block Editor: Infer the own props of the component withFontSizes wraps
manzoorwanijk Oct 16, 2026
3efccde
Block Editor: Reject injected props of another type in withFontSizes
manzoorwanijk Oct 16, 2026
cf395e3
Block Editor: Accept class components declaring only some injected pr…
manzoorwanijk Oct 16, 2026
19d8684
Block Editor: Check that the props withFontSizes injects fit the wrap…
manzoorwanijk Oct 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/block-editor/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
- Convert `LinkControl` and `URLInput` to TypeScript ([#84844](https://github.com/WordPress/gutenberg/pull/84844)).
- Convert `Warning`, `BlockEdit` and `PrivateBlockContext`, the `BlockControls` test and the store performance test to TypeScript ([#84846](https://github.com/WordPress/gutenberg/pull/84846)).
- Convert the layouts, `LayoutStyle`, the `align` hook, `BlockAlignmentControl`, `BlockVerticalAlignmentControl` and `JustifyContentControl` to TypeScript ([#84847](https://github.com/WordPress/gutenberg/pull/84847)).
- Convert the typography controls, the font size utilities and `withFontSizes` to TypeScript ([#84848](https://github.com/WordPress/gutenberg/pull/84848)).

## 18.1.0 (2026-10-07)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import { Field, Select } from '@wordpress/ui';
import { __ } from '@wordpress/i18n';
import { getFontStylesAndWeights } from '../../utils/get-font-styles-and-weights';
import type { FontAppearanceControlProps, FontAppearanceValue } from './types';

interface FontAppearanceOption {
key: string | undefined;
name: string | undefined;
style: FontAppearanceValue;
}

/**
* Adjusts font appearance field label in case either font styles or weights
* are disabled.
*
* @param {boolean} hasFontStyles Whether font styles are enabled and present.
* @param {boolean} hasFontWeights Whether font weights are enabled and present.
* @return {string} A label representing what font appearance is being edited.
* @param hasFontStyles Whether font styles are enabled and present.
* @param hasFontWeights Whether font weights are enabled and present.
* @return A label representing what font appearance is being edited.
*/
const getFontAppearanceLabel = ( hasFontStyles, hasFontWeights ) => {
const getFontAppearanceLabel = (
hasFontStyles: boolean,
hasFontWeights: boolean
): string => {
if ( ! hasFontStyles ) {
return __( 'Font weight' );
}
Expand All @@ -25,11 +35,13 @@ const getFontAppearanceLabel = ( hasFontStyles, hasFontWeights ) => {
/**
* Control to display font style and weight options of the active font.
*
* @param {Object} props Component props.
* @param props Component props.
*
* @return {Element} Font appearance control.
* @return Font appearance control.
*/
export default function FontAppearanceControl( props ) {
export default function FontAppearanceControl(
props: FontAppearanceControlProps
) {
const {
/**
* Start opting into the larger default height that will become the default size in a future version.
Expand Down Expand Up @@ -67,7 +79,7 @@ export default function FontAppearanceControl( props ) {

// Generates select options for combined font styles and weights.
const combineOptions = () => {
const combinedOptions = [ defaultOption ];
const combinedOptions: FontAppearanceOption[] = [ defaultOption ];
if ( combinedStyleAndWeightOptions ) {
combinedOptions.push( ...combinedStyleAndWeightOptions );
}
Expand All @@ -76,7 +88,7 @@ export default function FontAppearanceControl( props ) {

// Generates select options for font styles only.
const styleOptions = () => {
const combinedOptions = [ defaultOption ];
const combinedOptions: FontAppearanceOption[] = [ defaultOption ];
fontStyles.forEach( ( { name, value } ) => {
combinedOptions.push( {
key: value,
Expand All @@ -89,7 +101,7 @@ export default function FontAppearanceControl( props ) {

// Generates select options for font weights only.
const weightOptions = () => {
const combinedOptions = [ defaultOption ];
const combinedOptions: FontAppearanceOption[] = [ defaultOption ];
fontWeights.forEach( ( { name, value } ) => {
combinedOptions.push( {
key: value,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import type { ComponentProps } from 'react';
import type { Select } from '@wordpress/ui';
import type { FontFamilyFace } from '../../utils/types';

/**
* A font style and weight.
*/
export interface FontAppearanceValue {
fontStyle?: string;
fontWeight?: string;
}

/**
* Props of `FontAppearanceControl`. The props forwarded to the select's
* trigger, such as event handlers, are accepted too.
*/
export interface FontAppearanceControlProps extends Omit<
ComponentProps< typeof Select.Trigger >,
'onChange' | 'value'
> {
/**
* Start opting into the larger default height that will become the
* default size in a future version.
*
* @deprecated Default behavior since WordPress 7.1. Prop can be safely removed.
*/
__next40pxDefaultSize?: boolean;
/**
* Called with the selected font style and weight.
*/
onChange: ( value: FontAppearanceValue ) => void;
/**
* Whether font styles are enabled and present.
*/
hasFontStyles?: boolean;
/**
* Whether font weights are enabled and present.
*/
hasFontWeights?: boolean;
/**
* The font faces of the active font family.
*/
fontFamilyFaces?: FontFamilyFace[];
/**
* The current font style and weight.
*/
value: FontAppearanceValue;
hideLabelFromVision?: boolean;
disabled?: boolean;
/*
* Props of the previous implementation, accepted and ignored so they
* don't reach the trigger.
*/
className?: string;
label?: string;
describedBy?: string;
options?: unknown;
showSelectedHint?: boolean;
__experimentalShowSelectedHint?: boolean;
__nextUnconstrainedWidth?: boolean;
__nextHasNoMarginBottom?: boolean;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import clsx from 'clsx';
import { CustomSelectControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import type { FontFamilyPreset } from '@wordpress/global-styles-engine';
import { useSettings } from '../use-settings';
import type { FontFamilyControlProps } from './types';

export default function FontFamilyControl( {
/**
Expand All @@ -15,10 +17,11 @@ export default function FontFamilyControl( {
fontFamilies,
className,
...props
} ) {
}: FontFamilyControlProps ) {
const [ blockLevelFontFamilies ] = useSettings( 'typography.fontFamilies' );
if ( ! fontFamilies ) {
fontFamilies = blockLevelFontFamilies;
// The setting lists the font family presets.
fontFamilies = blockLevelFontFamilies as FontFamilyPreset[] | undefined;
}

if ( ! fontFamilies || fontFamilies.length === 0 ) {
Expand All @@ -42,7 +45,8 @@ export default function FontFamilyControl( {
return (
<CustomSelectControl
label={ __( 'Font' ) }
value={ selectedValue }
// As before, an unmatched value is passed as an empty string.
value={ selectedValue as ( typeof options )[ number ] }
onChange={ ( { selectedItem } ) => onChange( selectedItem.key ) }
options={ options }
className={ clsx( 'block-editor-font-family-control', className ) }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import { useState } from '@wordpress/element';
import FontFamilyControl from '..';
import type { FontFamilyControlProps } from '../types';

export default {
component: FontFamilyControl,
id: 'blockeditor-fontfamilycontrol',
title: 'Editor/Block Editor/FontFamilyControl',
};
} satisfies Meta< typeof FontFamilyControl >;

type Story = StoryObj< typeof FontFamilyControl >;

export const Default = {
render: function Template( props ) {
const [ value, setValue ] = useState();
export const Default: Story = {
render: function Template( props: Partial< FontFamilyControlProps > ) {
const [ value, setValue ] = useState< string >();
return (
<FontFamilyControl
onChange={ setValue }
Expand Down
39 changes: 39 additions & 0 deletions packages/block-editor/src/components/font-family/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { ComponentProps } from 'react';
import type { CustomSelectControl } from '@wordpress/components';
import type { FontFamilyPreset } from '@wordpress/global-styles-engine';

type CustomSelectControlProps = ComponentProps< typeof CustomSelectControl >;

/**
* A font family the control offers, labelled by its name or its CSS value.
*/
export type FontFamilyOption = Pick< FontFamilyPreset, 'fontFamily' > &
Partial< FontFamilyPreset >;

/**
* Props of `FontFamilyControl`.
*/
export interface FontFamilyControlProps extends Partial<
Omit< CustomSelectControlProps, 'value' | 'onChange' | 'options' >
> {
/**
* Start opting into the larger default height that will become the
* default size in a future version.
*
* @deprecated Default behavior since WordPress 7.1. Prop can be safely removed.
*/
__next40pxDefaultSize?: boolean;
/**
* The selected font family.
*/
value?: string;
/**
* Called with the selected font family, or `''` for the default.
*/
onChange: ( value: string ) => void;
/**
* The font families to choose from, in place of the block's settings.
*/
fontFamilies?: FontFamilyOption[];
className?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ const DEFAULT_MINIMUM_FONT_SIZE_FACTOR_MIN = 0.25;
const DEFAULT_MINIMUM_FONT_SIZE_FACTOR_MAX = 0.75;
const DEFAULT_MINIMUM_FONT_SIZE_LIMIT = '14px';

import type {
FluidTypographyArgs,
TypographyValueAndUnit,
TypographyValueAndUnitOptions,
} from './types';

/**
* Computes a fluid font-size value that uses clamp(). A minimum and maximum
* font size OR a single font size can be specified.
Expand Down Expand Up @@ -50,7 +56,7 @@ export function getComputedFluidTypographyValue( {
maximumViewportWidth = DEFAULT_MAXIMUM_VIEWPORT_WIDTH,
scaleFactor = DEFAULT_SCALE_FACTOR,
minimumFontSizeLimit,
} ) {
}: FluidTypographyArgs ): string | null {
// Validate incoming settings and set defaults.
minimumFontSizeLimit = !! getTypographyValueAndUnit( minimumFontSizeLimit )
? minimumFontSizeLimit
Expand Down Expand Up @@ -131,7 +137,9 @@ export function getComputedFluidTypographyValue( {
// Only use calculated min font size if it's > $minimum_font_size_limit value.
if (
!! minimumFontSizeLimitParsed?.value &&
calculatedMinimumFontSize < minimumFontSizeLimitParsed?.value
// A finite size rounds to a number.
( calculatedMinimumFontSize as number ) <
minimumFontSizeLimitParsed?.value
) {
minimumFontSize = `${ minimumFontSizeLimitParsed.value }${ minimumFontSizeLimitParsed.unit }`;
} else {
Expand Down Expand Up @@ -196,13 +204,16 @@ export function getComputedFluidTypographyValue( {
);

const viewportWidthOffset =
roundToPrecision( minViewportWidthOffsetValue, 3 ) + fontSizeUnit;
// A finite width rounds to a number.
roundToPrecision( minViewportWidthOffsetValue as number, 3 ) +
fontSizeUnit;
const linearFactor =
100 *
( ( maximumFontSizeParsed.value - minimumFontSizeParsed.value ) /
linearDenominator );
const linearFactorScaled = roundToPrecision(
( linearFactor || 1 ) * scaleFactor,
// A `null` factor multiplies as `0`, as before.
( linearFactor || 1 ) * ( scaleFactor as number ),
3
);
const fluidTargetFontSize = `${ minimumFontSizeRem.value }${ minimumFontSizeRem.unit } + ((1vw - ${ viewportWidthOffset }) * ${ linearFactorScaled })`;
Expand All @@ -214,18 +225,22 @@ export function getComputedFluidTypographyValue( {
* Internal method that checks a string for a unit and value and returns an array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ].
* A raw font size of `value + unit` is expected. If the value is an integer, it will convert to `value + 'px'`.
*
* @param {string|number} rawValue Raw size value from theme.json.
* @param {Object|undefined} options Calculation options.
* @param rawValue Raw size value from theme.json.
* @param options Calculation options.
*
* @return {{ unit: string, value: number }|null} An object consisting of `'value'` and `'unit'` properties.
* @return An object consisting of `'value'` and `'unit'` properties.
*/
export function getTypographyValueAndUnit( rawValue, options = {} ) {
export function getTypographyValueAndUnit(
rawValue: unknown,
options: TypographyValueAndUnitOptions = {}
): TypographyValueAndUnit | null {
if ( typeof rawValue !== 'string' && typeof rawValue !== 'number' ) {
return null;
}

// Converts numeric values to pixel values by default.
if ( isFinite( rawValue ) ) {
// `isFinite` coerces a numeric string.
if ( isFinite( rawValue as number ) ) {
rawValue = `${ rawValue }px`;
}

Expand All @@ -242,7 +257,8 @@ export function getTypographyValueAndUnit( rawValue, options = {} ) {
`^(\\d*\\.?\\d+)(${ acceptableUnitsGroup }){1,1}$`
);

const matches = rawValue.match( regexUnits );
// A number was turned into a string above.
const matches = ( rawValue as string ).match( regexUnits );

// We need a number value and a unit.
if ( ! matches || matches.length < 3 ) {
Expand Down Expand Up @@ -276,7 +292,8 @@ export function getTypographyValueAndUnit( rawValue, options = {} ) {
}

return {
value: roundToPrecision( returnValue, 3 ),
// A parsed number is finite, so it rounds to a number.
value: roundToPrecision( returnValue, 3 ) as number,
unit,
};
}
Expand All @@ -285,14 +302,20 @@ export function getTypographyValueAndUnit( rawValue, options = {} ) {
* Returns a value rounded to defined precision.
* Returns `undefined` if the value is not a valid finite number.
*
* @param {number} value Raw value.
* @param {number} digits The number of digits to appear after the decimal point
* @param value Raw value.
* @param digits The number of digits to appear after the decimal point
*
* @return {number|undefined} Value rounded to standard precision.
* @return Value rounded to standard precision.
*/
export function roundToPrecision( value, digits = 3 ) {
export function roundToPrecision(
value: number,
digits = 3
): number | undefined {
const base = Math.pow( 10, digits );
return Number.isFinite( value )
? parseFloat( Math.round( value * base ) / base )
? // `parseFloat` reads the rounded number as its string form.
parseFloat(
( Math.round( value * base ) / base ) as unknown as string
)
: undefined;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { FontSizePicker as BaseFontSizePicker } from '@wordpress/components';
import { useSettings } from '../use-settings';
import type { FontSizePickerProps } from './types';

function FontSizePicker( props ) {
function FontSizePicker( props: FontSizePickerProps ) {
const [ fontSizes, customFontSize ] = useSettings(
'typography.fontSizes',
'typography.customFontSize'
Expand All @@ -10,7 +11,8 @@ function FontSizePicker( props ) {
return (
<BaseFontSizePicker
{ ...props }
fontSizes={ fontSizes }
// The setting lists the font size presets.
fontSizes={ fontSizes as FontSizePickerProps[ 'fontSizes' ] }
disableCustomFontSizes={ ! customFontSize }
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ describe( 'getComputedFluidTypographyValue()', () => {
it( 'should return a fluid font size when given a scale factor', () => {
const fluidTypographyValues = getComputedFluidTypographyValue( {
fontSize: '30px',
// @ts-expect-error A numeric string multiplies like the number.
scaleFactor: '2',
} );
expect( fluidTypographyValues ).toBe(
Expand Down
Loading
Loading