schlechtenburg/packages/rich-text/lib/update-formats.ts
2024-10-08 09:15:26 +02:00

54 lines
1.6 KiB
TypeScript

/**
* Internal dependencies
*/
import { isFormatEqual } from './is-format-equal';
/** @typedef {import('./types').RichTextValue} RichTextValue */
/**
* Efficiently updates all the formats from `start` (including) until `end`
* (excluding) with the active formats. Mutates `value`.
*
* @param {Object} $1 Named paramentes.
* @param {RichTextValue} $1.value Value te update.
* @param {number} $1.start Index to update from.
* @param {number} $1.end Index to update until.
* @param {Array} $1.formats Replacement formats.
*
* @return {RichTextValue} Mutated value.
*/
export function updateFormats( { value, start, end, formats } ) {
// Start and end may be switched in case of delete.
const min = Math.min( start, end );
const max = Math.max( start, end );
const formatsBefore = value.formats[ min - 1 ] || [];
const formatsAfter = value.formats[ max ] || [];
// First, fix the references. If any format right before or after are
// equal, the replacement format should use the same reference.
value.activeFormats = formats.map( ( format, index ) => {
if ( formatsBefore[ index ] ) {
if ( isFormatEqual( format, formatsBefore[ index ] ) ) {
return formatsBefore[ index ];
}
} else if ( formatsAfter[ index ] ) {
if ( isFormatEqual( format, formatsAfter[ index ] ) ) {
return formatsAfter[ index ];
}
}
return format;
} );
while ( --end >= start ) {
if ( value.activeFormats.length > 0 ) {
value.formats[ end ] = value.activeFormats;
} else {
delete value.formats[ end ];
}
}
return value;
}