UNPKG

@portabletext/editor

Version:

Portable Text Editor made in React

125 lines (110 loc) 3.74 kB
import {isPortableTextBlock, isPortableTextSpan} from '@portabletext/toolkit' import type {PortableTextBlock} from '@sanity/types' import type {EditorSelection, EditorSelectionPoint} from '../types/editor' import {collapseSelection} from './collapse-selection' import {splitString} from './split-string' import {stringOverlap} from './string-overlap' export function getTextSelection( value: Array<PortableTextBlock> | undefined, text: string, ): EditorSelection { if (!value) { throw new Error(`Unable to find selection for value ${value}`) } let anchor: EditorSelectionPoint | undefined let focus: EditorSelectionPoint | undefined for (const block of value) { if (isPortableTextBlock(block)) { for (const child of block.children) { if (isPortableTextSpan(child)) { if (child.text === text) { anchor = { path: [{_key: block._key}, 'children', {_key: child._key}], offset: 0, } focus = { path: [{_key: block._key}, 'children', {_key: child._key}], offset: text.length, } break } const splitChildText = splitString(child.text, text) if (splitChildText[0] === '' && splitChildText[1] !== '') { anchor = { path: [{_key: block._key}, 'children', {_key: child._key}], offset: 0, } focus = { path: [{_key: block._key}, 'children', {_key: child._key}], offset: text.length, } break } if ( splitChildText[0] !== '' && splitChildText[1] === '' && child.text.indexOf(text) !== -1 ) { anchor = { path: [{_key: block._key}, 'children', {_key: child._key}], offset: child.text.length - text.length, } focus = { path: [{_key: block._key}, 'children', {_key: child._key}], offset: child.text.length, } break } if (splitChildText[0] !== '' && splitChildText[1] !== '') { anchor = { path: [{_key: block._key}, 'children', {_key: child._key}], offset: splitChildText[0].length, } focus = { path: [{_key: block._key}, 'children', {_key: child._key}], offset: splitChildText[0].length + text.length, } break } const overlap = stringOverlap(child.text, text) if (overlap !== '') { if (child.text.lastIndexOf(overlap) >= 0 && !anchor) { anchor = { path: [{_key: block._key}, 'children', {_key: child._key}], offset: child.text.lastIndexOf(overlap), } continue } if (child.text.indexOf(overlap) === 0) { focus = { path: [{_key: block._key}, 'children', {_key: child._key}], offset: overlap.length, } } } } } } } if (!anchor || !focus) { throw new Error( `Unable to find selection for text "${text}" in value "${JSON.stringify(value)}"`, ) } return { anchor, focus, } } export function getSelectionBeforeText( value: Array<PortableTextBlock> | undefined, text: string, ): EditorSelection { return collapseSelection(getTextSelection(value, text), 'start') } export function getSelectionAfterText( value: Array<PortableTextBlock> | undefined, text: string, ): EditorSelection { return collapseSelection(getTextSelection(value, text), 'end') }