@portabletext/editor
Version:
Portable Text Editor made in React
78 lines (75 loc) • 2.19 kB
text/typescript
import type {Path, PortableTextBlock} from '@sanity/types'
import {isEqual} from 'lodash'
import type {EditorSelection, EditorSelectionPoint} from '../types/editor'
export function normalizePoint(
point: EditorSelectionPoint,
value: PortableTextBlock[],
): EditorSelectionPoint | null {
if (!point || !value) {
return null
}
const newPath: Path = []
let newOffset: number = point.offset || 0
const blockKey =
typeof point.path[0] === 'object' &&
'_key' in point.path[0] &&
point.path[0]._key
const childKey =
typeof point.path[2] === 'object' &&
'_key' in point.path[2] &&
point.path[2]._key
const block: PortableTextBlock | undefined = value.find(
(blk) => blk._key === blockKey,
)
if (block) {
newPath.push({_key: block._key})
} else {
return null
}
if (block && point.path[1] === 'children') {
if (
!block.children ||
(Array.isArray(block.children) && block.children.length === 0)
) {
return null
}
const child =
Array.isArray(block.children) &&
block.children.find((cld) => cld._key === childKey)
if (child) {
newPath.push('children')
newPath.push({_key: child._key})
newOffset =
child.text && child.text.length >= point.offset
? point.offset
: (child.text && child.text.length) || 0
} else {
return null
}
}
return {path: newPath, offset: newOffset}
}
export function normalizeSelection(
selection: EditorSelection,
value: PortableTextBlock[] | undefined,
): EditorSelection | null {
if (!selection || !value || value.length === 0) {
return null
}
let newAnchor: EditorSelectionPoint | null = null
let newFocus: EditorSelectionPoint | null = null
const {anchor, focus} = selection
if (
anchor &&
value.find((blk) => isEqual({_key: blk._key}, anchor.path[0]))
) {
newAnchor = normalizePoint(anchor, value)
}
if (focus && value.find((blk) => isEqual({_key: blk._key}, focus.path[0]))) {
newFocus = normalizePoint(focus, value)
}
if (newAnchor && newFocus) {
return {anchor: newAnchor, focus: newFocus, backward: selection.backward}
}
return null
}