Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -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)

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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
);
}

/**
Expand All @@ -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;
}
Expand All @@ -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 ) {
Expand Down
6 changes: 6 additions & 0 deletions packages/block-editor/src/hooks/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Original file line number Diff line number Diff line change
@@ -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',
Expand Down
39 changes: 39 additions & 0 deletions packages/block-editor/src/layouts/types.ts
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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(
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
Expand Down
Loading