/** * WordPress dependencies */ import { renderToString } from '@wordpress/element'; import deprecated from '@wordpress/deprecated'; /** * Internal dependencies */ import * as node from './node'; /** * A representation of a block's rich text value. */ export type BlockChildren = Array< string | Record< string, unknown > >; /** * Given block children, returns a serialize-capable WordPress element. * * @param children Block children object to convert. * * @return A serialize-capable element. */ export function getSerializeCapableElement( children: BlockChildren ): BlockChildren { // The fact that block children are compatible with the element serializer is // merely an implementation detail that currently serves to be true, but // should not be mistaken as being a guarantee on the external API. The // public API only offers guarantees to work with strings (toHTML) and DOM // elements (fromDOM), and should provide utilities to manipulate the value // rather than expect consumers to inspect or construct its shape (concat). return children; } /** * Given block children, returns an array of block nodes. * * @param children Block children object to convert. * * @return An array of individual block nodes. */ function getChildrenArray( children: BlockChildren ): BlockChildren { deprecated( 'wp.blocks.children.getChildrenArray', { since: '6.1', version: '6.3', link: 'https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields/', } ); // The fact that block children are compatible with the element serializer // is merely an implementation detail that currently serves to be true, but // should not be mistaken as being a guarantee on the external API. return children; } /** * Given two or more block nodes, returns a new block node representing a * concatenation of its values. * * @param blockNodes Block nodes to concatenate. * * @return Concatenated block node. */ export function concat( ...blockNodes: Array< BlockChildren | string > ): BlockChildren { deprecated( 'wp.blocks.children.concat', { since: '6.1', version: '6.3', alternative: 'wp.richText.concat', link: 'https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields/', } ); const result: BlockChildren = []; for ( let i = 0; i < blockNodes.length; i++ ) { const blockNode = Array.isArray( blockNodes[ i ] ) ? blockNodes[ i ] : [ blockNodes[ i ] ]; for ( let j = 0; j < blockNode.length; j++ ) { const child = blockNode[ j ] as string | Record< string, unknown >; const canConcatToPreviousString = typeof child === 'string' && typeof result[ result.length - 1 ] === 'string'; if ( canConcatToPreviousString ) { result[ result.length - 1 ] += child; } else { result.push( child ); } } } return result; } /** * Given an iterable set of DOM nodes, returns equivalent block children. * Ignores any non-element/text nodes included in set. * * @param domNodes Iterable set of DOM nodes to convert. * * @return Block children equivalent to DOM nodes. */ export function fromDOM( domNodes: NodeListOf< ChildNode > | NodeList ): BlockChildren { deprecated( 'wp.blocks.children.fromDOM', { since: '6.1', version: '6.3', alternative: 'wp.richText.create', link: 'https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields/', } ); const result: BlockChildren = []; for ( let i = 0; i < domNodes.length; i++ ) { try { result.push( node.fromDOM( domNodes[ i ] ) ); } catch { // Simply ignore if DOM node could not be converted. } } return result; } /** * Given a block node, returns its HTML string representation. * * @param children Block node(s) to convert to string. * * @return String HTML representation of block node. */ export function toHTML( children: BlockChildren ): string { deprecated( 'wp.blocks.children.toHTML', { since: '6.1', version: '6.3', alternative: 'wp.richText.toHTMLString', link: 'https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields/', } ); const element = getSerializeCapableElement( children ); return renderToString( element as React.ReactNode ); } /** * Given a selector, returns an hpq matcher generating a BlockChildren value * matching the selector result. * * @param selector DOM selector. * * @return hpq matcher. */ export function matcher( selector?: string ): ( domNode: Element ) => BlockChildren { deprecated( 'wp.blocks.children.matcher', { since: '6.1', version: '6.3', alternative: 'html source', link: 'https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields/', } ); return ( domNode: Element ): BlockChildren => { let match: Element | null = domNode; if ( selector ) { match = domNode.querySelector( selector ); } if ( match ) { return fromDOM( match.childNodes ); } return []; }; } /** * Object of utility functions used in managing block attribute values of * source `children`. * * @see https://github.com/WordPress/gutenberg/pull/10439 * * @deprecated since 4.0. The `children` source should not be used, and can be * replaced by the `html` source. * * @private */ export default { concat, getChildrenArray, fromDOM, toHTML, matcher, };