From 9e6bfa70d515bcba9e41a429445122910df8a8b7 Mon Sep 17 00:00:00 2001 From: Manzoor Wani Date: Wed, 14 Oct 2026 21:17:58 +0530 Subject: [PATCH 1/3] Block Editor: Convert the layout helpers and block gap utils to TypeScript --- .../block-editor/src/hooks/{gap.js => gap.ts} | 23 ++++- packages/block-editor/src/hooks/types.ts | 6 ++ .../{definitions.js => definitions.ts} | 4 +- packages/block-editor/src/layouts/types.ts | 39 ++++++++ .../src/layouts/{utils.js => utils.ts} | 91 +++++++++++-------- 5 files changed, 118 insertions(+), 45 deletions(-) rename packages/block-editor/src/hooks/{gap.js => gap.ts} (73%) rename packages/block-editor/src/layouts/{definitions.js => definitions.ts} (96%) create mode 100644 packages/block-editor/src/layouts/types.ts rename packages/block-editor/src/layouts/{utils.js => utils.ts} (50%) diff --git a/packages/block-editor/src/hooks/gap.js b/packages/block-editor/src/hooks/gap.ts similarity index 73% rename from packages/block-editor/src/hooks/gap.js rename to packages/block-editor/src/hooks/gap.ts index c9df4bd21293d4..dc15c0af5c40cc 100644 --- a/packages/block-editor/src/hooks/gap.js +++ b/packages/block-editor/src/hooks/gap.ts @@ -1,5 +1,7 @@ import { getSpacingPresetCssVar } from '../components/spacing-sizes-control/utils'; import { normalizeLegacyLayout } from '../layouts/utils'; +import type { Layout } from '../layouts/types'; +import type { BlockGapValue } from './types'; /** * Returns whether the current layout can use separate row and column gaps. @@ -8,10 +10,16 @@ import { normalizeLegacyLayout } from '../layouts/utils'; * @param {?Object} defaultLayout The block's default supported layout. * @return {boolean} Whether axial block gap controls should be available. */ -export function isAxialBlockGapAllowed( layout, defaultLayout ) { - const usedLayout = normalizeLegacyLayout( layout ) || defaultLayout || {}; +export function isAxialBlockGapAllowed( + layout: Layout | null | undefined, + defaultLayout?: Layout | null +): boolean { + const usedLayout: Layout = + normalizeLegacyLayout( layout ) || defaultLayout || {}; - return [ 'flex', 'grid' ].includes( usedLayout?.type ); + return ( [ 'flex', 'grid' ] as ( string | undefined )[] ).includes( + usedLayout?.type + ); } /** @@ -22,7 +30,9 @@ export function isAxialBlockGapAllowed( layout, defaultLayout ) { * @param {?string | ?Object} blockGapValue A block gap string or axial object value, e.g., '10px' or { top: '10px', left: '10px'}. * @return {Object|null} A value to pass to the BoxControl component. */ -export function getGapBoxControlValueFromStyle( blockGapValue ) { +export function getGapBoxControlValueFromStyle( + blockGapValue: BlockGapValue | null | undefined +): { top?: string; left?: string } | null { if ( ! blockGapValue ) { return null; } @@ -41,7 +51,10 @@ export function getGapBoxControlValueFromStyle( blockGapValue ) { * @param {?string} defaultValue A default gap value. * @return {string|null} The concatenated gap value (row and column). */ -export function getGapCSSValue( blockGapValue, defaultValue = '0' ) { +export function getGapCSSValue( + blockGapValue: BlockGapValue | null | undefined, + defaultValue: string | null = '0' +): string | null { const blockGapBoxControlValue = getGapBoxControlValueFromStyle( blockGapValue ); if ( ! blockGapBoxControlValue ) { diff --git a/packages/block-editor/src/hooks/types.ts b/packages/block-editor/src/hooks/types.ts index af87ef45ff868e..f3aead949d6997 100644 --- a/packages/block-editor/src/hooks/types.ts +++ b/packages/block-editor/src/hooks/types.ts @@ -144,3 +144,9 @@ export type ColorSupport = Partial< ColorProps > & { gradient?: boolean }; * A block's `__experimentalBorder` support, or `true` for all its features. */ export type BorderSupport = true | Record< string, unknown >; + +/** + * A block gap style: one value for both axes, or a `top` (row) and `left` + * (column) value. + */ +export type BlockGapValue = string | { top?: string; left?: string }; diff --git a/packages/block-editor/src/layouts/definitions.js b/packages/block-editor/src/layouts/definitions.ts similarity index 96% rename from packages/block-editor/src/layouts/definitions.js rename to packages/block-editor/src/layouts/definitions.ts index a5c6d431c50f20..392a1cd5eb4e1c 100644 --- a/packages/block-editor/src/layouts/definitions.js +++ b/packages/block-editor/src/layouts/definitions.ts @@ -1,8 +1,10 @@ +import type { LayoutDefinition } from './types'; + // Layout definitions keyed by layout type. // Provides a common definition of slugs, classnames, base styles, and spacing styles for each layout type. // If making changes or additions to layout definitions, be sure to update the corresponding PHP definitions in // `block-supports/layout.php` so that the server-side and client-side definitions match. -export const LAYOUT_DEFINITIONS = { +export const LAYOUT_DEFINITIONS: Record< string, LayoutDefinition > = { default: { name: 'default', slug: 'flow', diff --git a/packages/block-editor/src/layouts/types.ts b/packages/block-editor/src/layouts/types.ts new file mode 100644 index 00000000000000..c51851e0376a2d --- /dev/null +++ b/packages/block-editor/src/layouts/types.ts @@ -0,0 +1,39 @@ +/** + * CSS rules for a selector within a layout. A `null` rule value takes the + * block gap value. + */ +export interface LayoutStyle { + selector: string; + rules: Record< string, string | null >; +} + +/** + * The slugs, class name and styles of one layout type. + */ +export interface LayoutDefinition { + name: string; + slug: string; + className: string; + displayMode?: string; + baseStyles?: LayoutStyle[]; + spacingStyles?: LayoutStyle[]; +} + +/** + * A block's `layout` attribute or support. + */ +export interface Layout { + type?: string; + inherit?: boolean; + contentSize?: string; + wideSize?: string; + [ key: string ]: unknown; +} + +/** + * The size hint shown for each alignment. + */ +export interface AlignmentsInfo { + none?: string; + wide?: string; +} diff --git a/packages/block-editor/src/layouts/utils.js b/packages/block-editor/src/layouts/utils.ts similarity index 50% rename from packages/block-editor/src/layouts/utils.js rename to packages/block-editor/src/layouts/utils.ts index ef466f4e6852ed..1ca1fe2316c062 100644 --- a/packages/block-editor/src/layouts/utils.js +++ b/packages/block-editor/src/layouts/utils.ts @@ -1,15 +1,19 @@ import { __, sprintf } from '@wordpress/i18n'; import { LAYOUT_DEFINITIONS } from './definitions'; +import type { AlignmentsInfo, Layout, LayoutDefinition } from './types'; /** * Utility to generate the proper CSS selector for layout styles. * - * @param {string} selectors CSS selector, also supports multiple comma-separated selectors. - * @param {string} append The string to append. + * @param selectors CSS selector, also supports multiple comma-separated selectors. + * @param append The string to append. * - * @return {string} - CSS selector. + * @return - CSS selector. */ -export function appendSelectors( selectors, append = '' ) { +export function appendSelectors( + selectors: string, + append: string = '' +): string { return selectors .split( ',' ) .map( @@ -24,36 +28,42 @@ export function appendSelectors( selectors, append = '' ) { * Falsy values in the layout definition's spacingStyles rules will be swapped out * with the provided `blockGapValue`. * - * @param {string} selector The CSS selector to target for the generated rules. - * @param {Object} layoutDefinitions Layout definitions object. - * @param {string} layoutType The layout type (e.g. `default` or `flex`). - * @param {string} blockGapValue The current blockGap value to be applied. - * @return {string} The generated CSS rules. + * @param selector The CSS selector to target for the generated rules. + * @param layoutDefinitions Layout definitions object. + * @param layoutType The layout type (e.g. `default` or `flex`). + * @param blockGapValue The current blockGap value to be applied. + * @return The generated CSS rules. */ export function getBlockGapCSS( - selector, - layoutDefinitions = LAYOUT_DEFINITIONS, - layoutType, - blockGapValue -) { + selector: string, + layoutDefinitions: Record< + string, + Partial< LayoutDefinition > + > | null = LAYOUT_DEFINITIONS, + layoutType: string, + blockGapValue: string | null | undefined +): string { let output = ''; if ( layoutDefinitions?.[ layoutType ]?.spacingStyles?.length && blockGapValue ) { - layoutDefinitions[ layoutType ].spacingStyles.forEach( ( gapStyle ) => { - output += `${ appendSelectors( - selector, - gapStyle.selector.trim() - ) } { `; - output += Object.entries( gapStyle.rules ) - .map( - ( [ cssProperty, value ] ) => - `${ cssProperty }: ${ value ? value : blockGapValue }` - ) - .join( '; ' ); - output += '; }'; - } ); + // The check above guarantees the spacing styles. + layoutDefinitions[ layoutType ].spacingStyles!.forEach( + ( gapStyle ) => { + output += `${ appendSelectors( + selector, + gapStyle.selector.trim() + ) } { `; + output += Object.entries( gapStyle.rules ) + .map( + ( [ cssProperty, value ] ) => + `${ cssProperty }: ${ value ? value : blockGapValue }` + ) + .join( '; ' ); + output += '; }'; + } + ); } return output; } @@ -69,21 +79,22 @@ export function getBlockGapCSS( * * @see https://github.com/WordPress/gutenberg/pull/34710#issuecomment-918000752 * - * @param {Object} layout The layout object. - * @return {Object} An object with contextual info per alignment. + * @param layout The layout object. + * @return An object with contextual info per alignment. */ -export function getAlignmentsInfo( layout ) { +export function getAlignmentsInfo( layout: Layout ): AlignmentsInfo { const { contentSize, wideSize, type = 'default' } = layout; - const alignmentInfo = {}; + const alignmentInfo: AlignmentsInfo = {}; const sizeRegex = /^(?!0)\d+(px|em|rem|vw|vh|%|svw|lvw|dvw|svh|lvh|dvh|vi|svi|lvi|dvi|vb|svb|lvb|dvb|vmin|svmin|lvmin|dvmin|vmax|svmax|lvmax|dvmax)?$/i; - if ( sizeRegex.test( contentSize ) && type === 'constrained' ) { + // `test` reads a missing size as 'undefined', which never matches. + if ( sizeRegex.test( contentSize! ) && type === 'constrained' ) { // translators: %s: container size (i.e. 600px etc) - alignmentInfo.none = sprintf( __( 'Max %s wide' ), contentSize ); + alignmentInfo.none = sprintf( __( 'Max %s wide' ), contentSize! ); } - if ( sizeRegex.test( wideSize ) ) { + if ( sizeRegex.test( wideSize! ) ) { // translators: %s: container size (i.e. 600px etc) - alignmentInfo.wide = sprintf( __( 'Max %s wide' ), wideSize ); + alignmentInfo.wide = sprintf( __( 'Max %s wide' ), wideSize! ); } return alignmentInfo; } @@ -97,11 +108,13 @@ export function getAlignmentsInfo( layout ) { * still around, and consumers that read `type` alone would resolve it to the * flow layout. * - * @param {Object} layout The layout object. - * @return {Object} The layout, with `type: 'constrained'` set when it was - * expressed in the legacy form; otherwise the same object. + * @param layout The layout object. + * @return The layout, with `type: 'constrained'` set when it was + * expressed in the legacy form; otherwise the same object. */ -export function normalizeLegacyLayout( layout ) { +export function normalizeLegacyLayout< T extends Layout | null | undefined >( + layout: T +): T | Layout { return layout?.inherit || layout?.contentSize || layout?.wideSize ? { ...layout, type: 'constrained' } : layout; From 9730c821601db4b15db0d5564c89587911a3e18c Mon Sep 17 00:00:00 2001 From: Manzoor Wani Date: Wed, 14 Oct 2026 21:18:53 +0530 Subject: [PATCH 2/3] Block Editor: Convert the layout helpers and block gap tests to TypeScript --- packages/block-editor/src/hooks/test/{gap.js => gap.ts} | 0 packages/block-editor/src/layouts/test/{utils.js => utils.ts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename packages/block-editor/src/hooks/test/{gap.js => gap.ts} (100%) rename packages/block-editor/src/layouts/test/{utils.js => utils.ts} (100%) diff --git a/packages/block-editor/src/hooks/test/gap.js b/packages/block-editor/src/hooks/test/gap.ts similarity index 100% rename from packages/block-editor/src/hooks/test/gap.js rename to packages/block-editor/src/hooks/test/gap.ts diff --git a/packages/block-editor/src/layouts/test/utils.js b/packages/block-editor/src/layouts/test/utils.ts similarity index 100% rename from packages/block-editor/src/layouts/test/utils.js rename to packages/block-editor/src/layouts/test/utils.ts From 691314a84194bae526594c5d8d9365b125769112 Mon Sep 17 00:00:00 2001 From: Manzoor Wani Date: Wed, 14 Oct 2026 22:38:49 +0530 Subject: [PATCH 3/3] Block Editor: Add the CHANGELOG entry for #84722 --- packages/block-editor/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-editor/CHANGELOG.md b/packages/block-editor/CHANGELOG.md index e45f2b3fea025e..0236e3b4d77e2f 100644 --- a/packages/block-editor/CHANGELOG.md +++ b/packages/block-editor/CHANGELOG.md @@ -45,6 +45,7 @@ - Type `isValueSpacingPreset` as returning a boolean, since it returns `false` for custom values ([#84730](https://github.com/WordPress/gutenberg/pull/84730)). - Convert the hook utils, block style state and Global Styles hooks to TypeScript ([#84720](https://github.com/WordPress/gutenberg/pull/84720)). - Convert the block support helpers to TypeScript ([#84721](https://github.com/WordPress/gutenberg/pull/84721)). +- Convert the layout helpers and block gap utils to TypeScript ([#84722](https://github.com/WordPress/gutenberg/pull/84722)). ## 18.1.0 (2026-10-07)