UNPKG

@portabletext/editor

Version:

Portable Text Editor made in React

151 lines (126 loc) 3.54 kB
import { isKeySegment, isPortableTextSpan, isPortableTextTextBlock, type KeyedSegment, type PortableTextSpan, } from '@sanity/types' import type {EditorSelector} from '../editor/editor-selector' /** * @public */ export const getSelectedSpans: EditorSelector< Array<{ node: PortableTextSpan path: [KeyedSegment, 'children', KeyedSegment] }> > = (snapshot) => { if (!snapshot.context.selection) { return [] } const selectedSpans: Array<{ node: PortableTextSpan path: [KeyedSegment, 'children', KeyedSegment] }> = [] const startPoint = snapshot.context.selection.backward ? snapshot.context.selection.focus : snapshot.context.selection.anchor const endPoint = snapshot.context.selection.backward ? snapshot.context.selection.anchor : snapshot.context.selection.focus const startBlockKey = isKeySegment(startPoint.path[0]) ? startPoint.path[0]._key : undefined const endBlockKey = isKeySegment(endPoint.path[0]) ? endPoint.path[0]._key : undefined if (!startBlockKey || !endBlockKey) { return selectedSpans } const startSpanKey = isKeySegment(startPoint.path[2]) ? startPoint.path[2]._key : undefined const endSpanKey = isKeySegment(endPoint.path[2]) ? endPoint.path[2]._key : undefined let startBlockFound = false for (const block of snapshot.context.value) { if (block._key === startBlockKey) { startBlockFound = true } if (!isPortableTextTextBlock(block)) { continue } if (block._key === startBlockKey) { for (const child of block.children) { if (!isPortableTextSpan(child)) { continue } if (startSpanKey && child._key === startSpanKey) { if (startPoint.offset < child.text.length) { selectedSpans.push({ node: child, path: [{_key: block._key}, 'children', {_key: child._key}], }) } if (startSpanKey === endSpanKey) { break } continue } if (endSpanKey && child._key === endSpanKey) { if (endPoint.offset > 0) { selectedSpans.push({ node: child, path: [{_key: block._key}, 'children', {_key: child._key}], }) } break } if (selectedSpans.length > 0) { selectedSpans.push({ node: child, path: [{_key: block._key}, 'children', {_key: child._key}], }) } } if (startBlockKey === endBlockKey) { break } continue } if (block._key === endBlockKey) { for (const child of block.children) { if (!isPortableTextSpan(child)) { continue } if (endSpanKey && child._key === endSpanKey) { if (endPoint.offset > 0) { selectedSpans.push({ node: child, path: [{_key: block._key}, 'children', {_key: child._key}], }) } break } selectedSpans.push({ node: child, path: [{_key: block._key}, 'children', {_key: child._key}], }) } break } if (startBlockFound) { for (const child of block.children) { if (!isPortableTextSpan(child)) { continue } selectedSpans.push({ node: child, path: [{_key: block._key}, 'children', {_key: child._key}], }) } } } return selectedSpans }