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

83 lines
2.2 KiB
TypeScript

/**
* Internal dependencies
*/
import { RichTextValue } from "./types";
/** @typedef {import('./types').RichTextValue} RichTextValue */
/**
* Split a Rich Text value in two at the given `startIndex` and `endIndex`, or
* split at the given separator. This is similar to `String.prototype.split`.
* Indices are retrieved from the selection if none are provided.
*
* @param {RichTextValue} value
* @param {number|string} [string] Start index, or string at which to split.
*
* @return {Array<RichTextValue>|undefined} An array of new values.
*/
export function split( value: RichTextValue, string: number|string, endIndex?: number): RichTextValue[]|undefined {
if ( typeof string !== 'string' ) {
return splitAtSelection(value, string, endIndex);
}
const { formats, replacements, text, start, end } = value;
let nextStart = 0;
return text.split( string ).map( ( substring ) => {
const startIndex = nextStart;
const value: RichTextValue = {
formats: formats.slice( startIndex, startIndex + substring.length ),
replacements: replacements.slice(
startIndex,
startIndex + substring.length
),
text: substring,
};
nextStart += string.length + substring.length;
if ( start !== undefined && end !== undefined ) {
if ( start >= startIndex && start < nextStart ) {
value.start = start - startIndex;
} else if ( start < startIndex && end > startIndex ) {
value.start = 0;
}
if ( end >= startIndex && end < nextStart ) {
value.end = end - startIndex;
} else if ( start < nextStart && end > nextStart ) {
value.end = substring.length;
}
}
return value;
} );
}
function splitAtSelection(
{ formats, replacements, text, start, end }: RichTextValue,
startIndex: number|undefined = start,
endIndex: number|undefined = end
): RichTextValue[]|undefined {
if ( start === undefined || end === undefined ) {
return;
}
const before = {
formats: formats.slice( 0, startIndex ),
replacements: replacements.slice( 0, startIndex ),
text: text.slice( 0, startIndex ),
};
const after = {
formats: formats.slice( endIndex ),
replacements: replacements.slice( endIndex ),
text: text.slice( endIndex ),
start: 0,
end: 0,
};
return [ before, after ];
}