UNPKG

@portabletext/editor

Version:

Portable Text Editor made in React

799 lines (798 loc) 36.4 kB
import { isTextBlock, isSpan } from "@portabletext/schema"; import { isSelectionCollapsed as isSelectionCollapsed$1, getBlockKeyFromSelectionPoint, getChildKeyFromSelectionPoint, getSelectionEndPoint as getSelectionEndPoint$1, getSelectionStartPoint as getSelectionStartPoint$1, blockOffsetToSpanSelectionPoint, isKeyedSegment, sliceBlocks, isEqualPaths, spanSelectionPointToBlockOffset, getBlockStartPoint, getBlockEndPoint, isListBlock, isEqualSelectionPoints } from "./util.slice-blocks.js"; function isBlockPath(path) { const firstSegment = path.at(0); return path.length === 1 && firstSegment !== void 0 && isRecord(firstSegment) && "_key" in firstSegment && typeof firstSegment._key == "string"; } function isRecord(value) { return !!value && (typeof value == "object" || typeof value == "function"); } function isSelectionExpanded$1(selection) { return selection ? !isSelectionCollapsed$1(selection) : !1; } const getFocusBlock = (snapshot) => { if (!snapshot.context.selection) return; const key = getBlockKeyFromSelectionPoint(snapshot.context.selection.focus), index = key ? snapshot.blockIndexMap.get(key) : void 0, node = index !== void 0 ? snapshot.context.value.at(index) : void 0; return node && key ? { node, path: [{ _key: key }] } : void 0; }, getFocusTextBlock = (snapshot) => { const focusBlock = getFocusBlock(snapshot); return focusBlock && isTextBlock(snapshot.context, focusBlock.node) ? { node: focusBlock.node, path: focusBlock.path } : void 0; }, getFocusChild = (snapshot) => { if (!snapshot.context.selection) return; const focusBlock = getFocusTextBlock(snapshot); if (!focusBlock) return; const key = getChildKeyFromSelectionPoint(snapshot.context.selection.focus), node = key ? focusBlock.node.children.find((span) => span._key === key) : void 0; return node && key ? { node, path: [...focusBlock.path, "children", { _key: key }] } : void 0; }, getFocusSpan = (snapshot) => { const focusChild = getFocusChild(snapshot); return focusChild && isSpan(snapshot.context, focusChild.node) ? { node: focusChild.node, path: focusChild.path } : void 0; }, getSelectionEndBlock = (snapshot) => { const endPoint = getSelectionEndPoint$1(snapshot.context.selection); if (endPoint) return getFocusBlock({ ...snapshot, context: { ...snapshot.context, selection: { anchor: endPoint, focus: endPoint } } }); }, getSelectionEndPoint = (snapshot) => { if (snapshot.context.selection) return snapshot.context.selection.backward ? snapshot.context.selection.anchor : snapshot.context.selection.focus; }, getNextSpan = (snapshot) => { const selectionEndBlock = getSelectionEndBlock(snapshot), selectionEndPoint = getSelectionEndPoint(snapshot); if (!selectionEndBlock || !selectionEndPoint || !isTextBlock(snapshot.context, selectionEndBlock.node)) return; const selectionEndPointChildKey = getChildKeyFromSelectionPoint(selectionEndPoint); let endPointChildFound = !1, nextSpan; for (const child of selectionEndBlock.node.children) { if (child._key === selectionEndPointChildKey) { endPointChildFound = !0; continue; } if (isSpan(snapshot.context, child) && endPointChildFound) { nextSpan = { node: child, path: [...selectionEndBlock.path, "children", { _key: child._key }] }; break; } } return nextSpan; }, getSelectionStartBlock = (snapshot) => { const startPoint = getSelectionStartPoint$1(snapshot.context.selection); if (startPoint) return getFocusBlock({ ...snapshot, context: { ...snapshot.context, selection: { anchor: startPoint, focus: startPoint } } }); }, getSelectionStartPoint = (snapshot) => { if (snapshot.context.selection) return snapshot.context.selection.backward ? snapshot.context.selection.focus : snapshot.context.selection.anchor; }, getPreviousSpan = (snapshot) => { const selectionStartBlock = getSelectionStartBlock(snapshot), selectionStartPoint = getSelectionStartPoint(snapshot); if (!selectionStartBlock || !selectionStartPoint || !isTextBlock(snapshot.context, selectionStartBlock.node)) return; const selectionStartPointChildKey = getChildKeyFromSelectionPoint(selectionStartPoint); let previousSpan; for (const child of selectionStartBlock.node.children) { if (child._key === selectionStartPointChildKey) break; isSpan(snapshot.context, child) && (previousSpan = { node: child, path: [...selectionStartBlock.path, "children", { _key: child._key }] }); } return previousSpan; }; function getSelectedChildren(options) { const filter = options?.filter; return (snapshot) => { const startPoint = getSelectionStartPoint(snapshot), endPoint = getSelectionEndPoint(snapshot); if (!startPoint || !endPoint) return []; const startBlockKey = getBlockKeyFromSelectionPoint(startPoint), endBlockKey = getBlockKeyFromSelectionPoint(endPoint), startChildKey = getChildKeyFromSelectionPoint(startPoint), endChildKey = getChildKeyFromSelectionPoint(endPoint); if (!startBlockKey || !endBlockKey) return []; const startBlockIndex = snapshot.blockIndexMap.get(startBlockKey), endBlockIndex = snapshot.blockIndexMap.get(endBlockKey); if (startBlockIndex === void 0 || endBlockIndex === void 0) return []; const selectedChildren = [], minBlockIndex = Math.min(startBlockIndex, endBlockIndex), maxBlockIndex = Math.max(startBlockIndex, endBlockIndex), blocks = snapshot.context.value.slice(minBlockIndex, maxBlockIndex + 1); let startChildFound = !1; for (const block of blocks) { if (!isTextBlock(snapshot.context, block)) continue; const isStartBlock = block._key === startBlockKey, isEndBlock = block._key === endBlockKey, isMiddleBlock = !isStartBlock && !isEndBlock; for (const child of block.children) { const isStartChild = child._key === startChildKey, isEndChild = child._key === endChildKey, addChild = () => { (!filter || filter(child)) && selectedChildren.push({ node: child, path: [{ _key: block._key }, "children", { _key: child._key }] }); }; if (isMiddleBlock) { addChild(); continue; } if (isStartChild) { if (startChildFound = !0, isSpan(snapshot.context, child) ? startPoint.offset < child.text.length && addChild() : addChild(), startChildKey === endChildKey) break; continue; } if (isEndChild) { isSpan(snapshot.context, child) ? endPoint.offset > 0 && addChild() : addChild(); break; } startChildFound && addChild(); } if (isStartBlock && startBlockKey === endBlockKey) break; isStartBlock && (startChildFound = !0); } return selectedChildren; }; } const getSelectedSpans = (snapshot) => snapshot.context.selection ? getSelectedChildren({ filter: (child) => isSpan(snapshot.context, child) })(snapshot) : [], getMarkState = (snapshot) => { if (!snapshot.context.selection) return; let selection = snapshot.context.selection; if (!getFocusTextBlock(snapshot)) return; if (isBlockPath(selection.anchor.path)) { const spanSelectionPoint = blockOffsetToSpanSelectionPoint({ context: snapshot.context, blockOffset: { path: selection.anchor.path, offset: selection.anchor.offset }, direction: selection.backward ? "backward" : "forward" }); selection = spanSelectionPoint ? { ...selection, anchor: spanSelectionPoint } : selection; } if (isBlockPath(selection.focus.path)) { const spanSelectionPoint = blockOffsetToSpanSelectionPoint({ context: snapshot.context, blockOffset: { path: selection.focus.path, offset: selection.focus.offset }, direction: selection.backward ? "backward" : "forward" }); selection = spanSelectionPoint ? { ...selection, focus: spanSelectionPoint } : selection; } const focusSpan = getFocusSpan({ ...snapshot, context: { ...snapshot.context, selection } }); if (!focusSpan) return; if (isSelectionExpanded$1(selection)) { const selectedSpans = getSelectedSpans({ ...snapshot, context: { ...snapshot.context, selection } }); let index = 0, marks2 = []; for (const span of selectedSpans) { if (index === 0) marks2 = span.node.marks ?? []; else { if (span.node.marks?.length === 0) { marks2 = []; continue; } marks2 = marks2.filter((mark) => (span.node.marks ?? []).some((spanMark) => spanMark === mark)); } index++; } return { state: "unchanged", marks: marks2 }; } const decorators = snapshot.context.schema.decorators.map((decorator) => decorator.name), marks = focusSpan.node.marks ?? [], marksWithoutAnnotations = marks.filter((mark) => decorators.includes(mark)), spanHasAnnotations = marks.length > marksWithoutAnnotations.length, spanIsEmpty = focusSpan.node.text.length === 0, atTheBeginningOfSpan = snapshot.context.selection.anchor.offset === 0, atTheEndOfSpan = snapshot.context.selection.anchor.offset === focusSpan.node.text.length, previousSpan = getPreviousSpan({ ...snapshot, context: { ...snapshot.context, selection } }), nextSpan = getNextSpan({ ...snapshot, context: { ...snapshot.context, selection } }), nextSpanAnnotations = nextSpan?.node?.marks?.filter((mark) => !decorators.includes(mark)) ?? [], spanAnnotations = marks.filter((mark) => !decorators.includes(mark)), previousSpanHasAnnotations = previousSpan ? previousSpan.node.marks?.some((mark) => !decorators.includes(mark)) : !1, previousSpanHasSameAnnotations = previousSpan ? previousSpan.node.marks?.filter((mark) => !decorators.includes(mark)).every((mark) => marks.includes(mark)) : !1, previousSpanHasSameAnnotation = previousSpan ? previousSpan.node.marks?.some((mark) => !decorators.includes(mark) && marks.includes(mark)) : !1, previousSpanHasSameMarks = previousSpan ? previousSpan.node.marks?.every((mark) => marks.includes(mark)) : !1, nextSpanSharesSomeAnnotations = spanAnnotations.some((mark) => nextSpanAnnotations?.includes(mark)); if (spanHasAnnotations && !spanIsEmpty) { if (atTheBeginningOfSpan) { if (previousSpanHasSameMarks) return { state: "changed", previousMarks: marks, marks: previousSpan?.node.marks ?? [] }; if (previousSpanHasSameAnnotations) return { state: "changed", previousMarks: marks, marks: previousSpan?.node.marks ?? [] }; if (previousSpanHasSameAnnotation) return { state: "unchanged", marks: focusSpan.node.marks ?? [] }; if (!previousSpan) return { state: "changed", previousMarks: marks, marks: [] }; } if (atTheEndOfSpan) { if (!nextSpan) return { state: "changed", previousMarks: marks, marks: [] }; if (nextSpanAnnotations.length > 0 && !nextSpanSharesSomeAnnotations) return { state: "changed", previousMarks: marks, marks: [] }; if (nextSpanSharesSomeAnnotations && nextSpanAnnotations.length < spanAnnotations.length || !nextSpanSharesSomeAnnotations) return { state: "changed", previousMarks: marks, marks: nextSpan?.node.marks ?? [] }; } } return atTheBeginningOfSpan && !spanIsEmpty && previousSpan ? previousSpanHasAnnotations ? { state: "changed", marks, previousMarks: previousSpan?.node.marks ?? [] } : { state: "changed", previousMarks: marks, marks: (previousSpan?.node.marks ?? []).filter((mark) => decorators.includes(mark)) } : { state: "unchanged", marks }; }, getSelectedBlocks = (snapshot) => { if (!snapshot.context.selection) return []; const selectedBlocks = [], startPoint = getSelectionStartPoint$1(snapshot.context.selection), endPoint = getSelectionEndPoint$1(snapshot.context.selection), startKey = getBlockKeyFromSelectionPoint(startPoint), endKey = getBlockKeyFromSelectionPoint(endPoint); if (!startKey || !endKey) return selectedBlocks; const startBlockIndex = snapshot.blockIndexMap.get(startKey), endBlockIndex = snapshot.blockIndexMap.get(endKey); if (startBlockIndex === void 0 || endBlockIndex === void 0) return selectedBlocks; const slicedValue = snapshot.context.value.slice(startBlockIndex, endBlockIndex + 1); for (const block of slicedValue) { if (block._key === startKey) { if (selectedBlocks.push({ node: block, path: [{ _key: block._key }] }), startKey === endKey) break; continue; } if (block._key === endKey) { selectedBlocks.push({ node: block, path: [{ _key: block._key }] }); break; } selectedBlocks.length > 0 && selectedBlocks.push({ node: block, path: [{ _key: block._key }] }); } return selectedBlocks; }, getActiveAnnotations = (snapshot) => { if (!snapshot.context.selection) return []; const selectedBlocks = getSelectedBlocks(snapshot), activeAnnotations = (getMarkState(snapshot)?.marks ?? []).filter((mark) => !snapshot.context.schema.decorators.map((decorator) => decorator.name).includes(mark)); return selectedBlocks.flatMap((block) => isTextBlock(snapshot.context, block.node) ? block.node.markDefs ?? [] : []).filter((markDef) => activeAnnotations.includes(markDef._key)); }, getActiveListItem = (snapshot) => { if (!snapshot.context.selection) return; const selectedTextBlocks = getSelectedBlocks(snapshot).map((block) => block.node).filter((block) => isTextBlock(snapshot.context, block)), firstTextBlock = selectedTextBlocks.at(0); if (!firstTextBlock) return; const firstListItem = firstTextBlock.listItem; if (firstListItem && selectedTextBlocks.every((block) => block.listItem === firstListItem)) return firstListItem; }, getActiveStyle = (snapshot) => { if (!snapshot.context.selection) return; const selectedTextBlocks = getSelectedBlocks(snapshot).map((block) => block.node).filter((block) => isTextBlock(snapshot.context, block)), firstTextBlock = selectedTextBlocks.at(0); if (!firstTextBlock) return; const firstStyle = firstTextBlock.style; if (firstStyle && selectedTextBlocks.every((block) => block.style === firstStyle)) return firstStyle; }, getNextInlineObject = (snapshot) => { const focusTextBlock = getFocusTextBlock(snapshot), selectionEndPoint = getSelectionEndPoint(snapshot), selectionEndPointChildKey = selectionEndPoint && isKeyedSegment(selectionEndPoint.path[2]) ? selectionEndPoint.path[2]._key : void 0; if (!focusTextBlock || !selectionEndPointChildKey) return; let endPointChildFound = !1, inlineObject; for (const child of focusTextBlock.node.children) { if (child._key === selectionEndPointChildKey) { endPointChildFound = !0; continue; } if (!isSpan(snapshot.context, child) && endPointChildFound) { inlineObject = { node: child, path: [...focusTextBlock.path, "children", { _key: child._key }] }; break; } } return inlineObject; }, getPreviousInlineObject = (snapshot) => { const focusTextBlock = getFocusTextBlock(snapshot), selectionStartPoint = getSelectionStartPoint(snapshot), selectionStartPointChildKey = selectionStartPoint && isKeyedSegment(selectionStartPoint.path[2]) ? selectionStartPoint.path[2]._key : void 0; if (!focusTextBlock || !selectionStartPointChildKey) return; let inlineObject; for (const child of focusTextBlock.node.children) { if (child._key === selectionStartPointChildKey) break; isSpan(snapshot.context, child) || (inlineObject = { node: child, path: [...focusTextBlock.path, "children", { _key: child._key }] }); } return inlineObject; }, getSelectedValue = (snapshot) => { const selection = snapshot.context.selection; if (!selection) return []; const startPoint = getSelectionStartPoint$1(selection), endPoint = getSelectionEndPoint$1(selection), startBlockKey = getBlockKeyFromSelectionPoint(startPoint), endBlockKey = getBlockKeyFromSelectionPoint(endPoint); if (!startBlockKey || !endBlockKey) return []; const startBlockIndex = snapshot.blockIndexMap.get(startBlockKey), endBlockIndex = snapshot.blockIndexMap.get(endBlockKey); if (startBlockIndex === void 0 || endBlockIndex === void 0) return []; const startBlock = snapshot.context.value.at(startBlockIndex), slicedStartBlock = startBlock ? sliceBlocks({ context: snapshot.context, blocks: [startBlock] }).at(0) : void 0; if (startBlockIndex === endBlockIndex) return slicedStartBlock ? [slicedStartBlock] : []; const endBlock = snapshot.context.value.at(endBlockIndex), slicedEndBlock = endBlock ? sliceBlocks({ context: snapshot.context, blocks: [endBlock] }).at(0) : void 0, middleBlocks = snapshot.context.value.slice(startBlockIndex + 1, endBlockIndex); return [...slicedStartBlock ? [slicedStartBlock] : [], ...middleBlocks, ...slicedEndBlock ? [slicedEndBlock] : []]; }, getSelectionText = (snapshot) => getSelectedValue(snapshot).reduce((text, block) => isTextBlock(snapshot.context, block) ? text + block.children.reduce((text2, child) => isSpan(snapshot.context, child) ? text2 + child.text : text2, "") : text, ""), isSelectionCollapsed = (snapshot) => snapshot.context.selection ? isEqualPaths(snapshot.context.selection.anchor.path, snapshot.context.selection.focus.path) && snapshot.context.selection.anchor.offset === snapshot.context.selection.focus.offset : !1, isSelectionExpanded = (snapshot) => snapshot.context.selection !== null && !isSelectionCollapsed(snapshot), getCaretWordSelection = (snapshot) => { if (!snapshot.context.selection || !isSelectionCollapsed(snapshot)) return null; const focusTextBlock = getFocusTextBlock(snapshot), selectionStartPoint = getSelectionStartPoint(snapshot), selectionStartOffset = selectionStartPoint ? spanSelectionPointToBlockOffset({ context: snapshot.context, selectionPoint: selectionStartPoint }) : void 0; if (!focusTextBlock || !selectionStartPoint || !selectionStartOffset) return null; const previousInlineObject = getPreviousInlineObject(snapshot), blockStartPoint = getBlockStartPoint({ context: snapshot.context, block: focusTextBlock }), textDirectlyBefore = getSelectionText({ ...snapshot, context: { ...snapshot.context, selection: { anchor: previousInlineObject ? { path: previousInlineObject.path, offset: 0 } : blockStartPoint, focus: selectionStartPoint } } }).split(/\s+/).at(-1), nextInlineObject = getNextInlineObject(snapshot), blockEndPoint = getBlockEndPoint({ context: snapshot.context, block: focusTextBlock }), textDirectlyAfter = getSelectionText({ ...snapshot, context: { ...snapshot.context, selection: { anchor: selectionStartPoint, focus: nextInlineObject ? { path: nextInlineObject.path, offset: 0 } : blockEndPoint } } }).split(/\s+/).at(0); if ((textDirectlyBefore === void 0 || textDirectlyBefore === "") && (textDirectlyAfter === void 0 || textDirectlyAfter === "")) return null; const caretWordStartOffset = textDirectlyBefore ? { ...selectionStartOffset, offset: selectionStartOffset.offset - textDirectlyBefore.length } : selectionStartOffset, caretWordEndOffset = textDirectlyAfter ? { ...selectionStartOffset, offset: selectionStartOffset.offset + textDirectlyAfter.length } : selectionStartOffset, caretWordStartSelectionPoint = blockOffsetToSpanSelectionPoint({ context: snapshot.context, blockOffset: caretWordStartOffset, direction: "backward" }), caretWordEndSelectionPoint = blockOffsetToSpanSelectionPoint({ context: snapshot.context, blockOffset: caretWordEndOffset, direction: "forward" }); if (!caretWordStartSelectionPoint || !caretWordEndSelectionPoint) return null; const caretWordSelection = { anchor: caretWordStartSelectionPoint, focus: caretWordEndSelectionPoint }; return isSelectionExpanded({ context: { ...snapshot.context, selection: caretWordSelection } }) ? caretWordSelection : null; }, getFocusBlockObject = (snapshot) => { const focusBlock = getFocusBlock(snapshot); return focusBlock && !isTextBlock(snapshot.context, focusBlock.node) ? { node: focusBlock.node, path: focusBlock.path } : void 0; }, getFocusInlineObject = (snapshot) => { const focusChild = getFocusChild(snapshot); return focusChild && !isSpan(snapshot.context, focusChild.node) ? { node: focusChild.node, path: focusChild.path } : void 0; }, getFocusListBlock = (snapshot) => { const focusTextBlock = getFocusTextBlock(snapshot); return focusTextBlock && isListBlock(snapshot.context, focusTextBlock.node) ? { node: focusTextBlock.node, path: focusTextBlock.path } : void 0; }, getLastBlock = (snapshot) => { const node = snapshot.context.value[snapshot.context.value.length - 1] ? snapshot.context.value[snapshot.context.value.length - 1] : void 0; return node ? { node, path: [{ _key: node._key }] } : void 0; }, getNextBlock = (snapshot) => { const selectionEndBlock = getSelectionEndBlock(snapshot); if (!selectionEndBlock) return; const index = snapshot.blockIndexMap.get(selectionEndBlock.node._key); if (index === void 0 || index === snapshot.context.value.length - 1) return; const nextBlock = snapshot.context.value.at(index + 1); return nextBlock ? { node: nextBlock, path: [{ _key: nextBlock._key }] } : void 0; }, getPreviousBlock = (snapshot) => { const selectionStartBlock = getSelectionStartBlock(snapshot); if (!selectionStartBlock) return; const index = snapshot.blockIndexMap.get(selectionStartBlock.node._key); if (index === void 0 || index === 0) return; const previousBlock = snapshot.context.value.at(index - 1); return previousBlock ? { node: previousBlock, path: [{ _key: previousBlock._key }] } : void 0; }, getSelectedTextBlocks = (snapshot) => { if (!snapshot.context.selection) return []; const selectedTextBlocks = [], startPoint = getSelectionStartPoint$1(snapshot.context.selection), endPoint = getSelectionEndPoint$1(snapshot.context.selection), startBlockKey = getBlockKeyFromSelectionPoint(startPoint), endBlockKey = getBlockKeyFromSelectionPoint(endPoint); if (!startBlockKey || !endBlockKey) return selectedTextBlocks; const startBlockIndex = snapshot.blockIndexMap.get(startBlockKey), endBlockIndex = snapshot.blockIndexMap.get(endBlockKey); if (startBlockIndex === void 0 || endBlockIndex === void 0) return selectedTextBlocks; const slicedValue = snapshot.context.value.slice(startBlockIndex, endBlockIndex + 1); for (const block of slicedValue) { if (block._key === startBlockKey) { if (isTextBlock(snapshot.context, block) && selectedTextBlocks.push({ node: block, path: [{ _key: block._key }] }), startBlockKey === endBlockKey) break; continue; } if (block._key === endBlockKey) { isTextBlock(snapshot.context, block) && selectedTextBlocks.push({ node: block, path: [{ _key: block._key }] }); break; } selectedTextBlocks.length > 0 && isTextBlock(snapshot.context, block) && selectedTextBlocks.push({ node: block, path: [{ _key: block._key }] }); } return selectedTextBlocks; }, getSelectionEndChild = (snapshot) => { const endPoint = getSelectionEndPoint$1(snapshot.context.selection); if (endPoint) return getFocusChild({ ...snapshot, context: { ...snapshot.context, selection: { anchor: endPoint, focus: endPoint } } }); }, getSelectionStartChild = (snapshot) => { const startPoint = getSelectionStartPoint$1(snapshot.context.selection); if (startPoint) return getFocusChild({ ...snapshot, context: { ...snapshot.context, selection: { anchor: startPoint, focus: startPoint } } }); }; function getActiveAnnotationsMarks(snapshot) { const schema = snapshot.context.schema; return (getMarkState(snapshot)?.marks ?? []).filter((mark) => !schema.decorators.map((decorator) => decorator.name).includes(mark)); } function isActiveAnnotation(annotation, options) { return (snapshot) => { if ((options?.mode ?? "full") === "partial") return getSelectedValue(snapshot).flatMap((block) => isTextBlock(snapshot.context, block) ? block.markDefs ?? [] : []).some((markDef) => markDef._type === annotation); const selectionMarkDefs = getSelectedBlocks(snapshot).flatMap((block) => isTextBlock(snapshot.context, block.node) ? block.node.markDefs ?? [] : []), activeAnnotations = getActiveAnnotationsMarks(snapshot); return selectionMarkDefs.filter((markDef) => markDef._type === annotation && activeAnnotations.includes(markDef._key)).length > 0; }; } function getActiveDecorators(snapshot) { const schema = snapshot.context.schema, decoratorState = snapshot.decoratorState, markState = getMarkState(snapshot), decorators = schema.decorators.map((decorator) => decorator.name); let activeDecorators = (markState?.marks ?? []).filter((mark) => decorators.includes(mark)); for (const decorator in decoratorState) decoratorState[decorator] === !1 ? activeDecorators = activeDecorators.filter((activeDecorator) => activeDecorator !== decorator) : decoratorState[decorator] === !0 && (activeDecorators.includes(decorator) || activeDecorators.push(decorator)); return activeDecorators; } function isActiveDecorator(decorator) { return (snapshot) => { if (isSelectionExpanded(snapshot)) { const selectedSpans = getSelectedSpans(snapshot); return selectedSpans.length > 0 && selectedSpans.every((span) => span.node.marks?.includes(decorator)); } return getActiveDecorators(snapshot).includes(decorator); }; } function isActiveListItem(listItem) { return (snapshot) => getActiveListItem(snapshot) === listItem; } function isActiveStyle(style) { return (snapshot) => getActiveStyle(snapshot) === style; } function isAtTheEndOfBlock(block) { return (snapshot) => { if (!snapshot.context.selection || !isSelectionCollapsed(snapshot)) return !1; const blockEndPoint = getBlockEndPoint({ context: snapshot.context, block }); return isEqualSelectionPoints(snapshot.context.selection.focus, blockEndPoint); }; } function isAtTheStartOfBlock(block) { return (snapshot) => { if (!snapshot.context.selection || !isSelectionCollapsed(snapshot)) return !1; const blockStartPoint = getBlockStartPoint({ context: snapshot.context, block }); return isEqualSelectionPoints(snapshot.context.selection.focus, blockStartPoint); }; } function comparePoints(snapshot, pointA, pointB) { const blockKeyA = getBlockKeyFromSelectionPoint(pointA), blockKeyB = getBlockKeyFromSelectionPoint(pointB); if (!blockKeyA) throw new Error(`Cannot compare points: no block key found for ${pointA}`); if (!blockKeyB) throw new Error(`Cannot compare points: no block key found for ${pointB}`); const blockIndexA = snapshot.blockIndexMap.get(blockKeyA), blockIndexB = snapshot.blockIndexMap.get(blockKeyB); if (blockIndexA === void 0) throw new Error(`Cannot compare points: block "${blockKeyA}" not found`); if (blockIndexB === void 0) throw new Error(`Cannot compare points: block "${blockKeyB}" not found`); if (blockIndexA < blockIndexB) return -1; if (blockIndexA > blockIndexB) return 1; const block = snapshot.context.value.at(blockIndexA); if (!block || !isTextBlock(snapshot.context, block)) return 0; const childKeyA = getChildKeyFromSelectionPoint(pointA), childKeyB = getChildKeyFromSelectionPoint(pointB); if (!childKeyA) throw new Error(`Cannot compare points: no child key found for ${pointA}`); if (!childKeyB) throw new Error(`Cannot compare points: no child key found for ${pointB}`); let childIndexA, childIndexB; for (let i = 0; i < block.children.length; i++) { const child = block.children.at(i); if (child) { if (child._key === childKeyA && child._key === childKeyB) return pointA.offset < pointB.offset ? -1 : pointA.offset > pointB.offset ? 1 : 0; if (child._key === childKeyA && (childIndexA = i), child._key === childKeyB && (childIndexB = i), childIndexA !== void 0 && childIndexB !== void 0) break; } } if (childIndexA === void 0) throw new Error(`Cannot compare points: child "${childKeyA}" not found`); if (childIndexB === void 0) throw new Error(`Cannot compare points: child "${childKeyB}" not found`); return childIndexA < childIndexB ? -1 : childIndexA > childIndexB ? 1 : 0; } function isOverlappingSelection(selection) { return (snapshot) => { const editorSelection = snapshot.context.selection; if (!selection || !editorSelection) return !1; const selectionStart = getSelectionStartPoint$1(selection), selectionEnd = getSelectionEndPoint$1(selection), editorSelectionStart = getSelectionStartPoint$1(editorSelection), editorSelectionEnd = getSelectionEndPoint$1(editorSelection), selectionStartBlockKey = getBlockKeyFromSelectionPoint(selectionStart), selectionEndBlockKey = getBlockKeyFromSelectionPoint(selectionEnd), editorSelectionStartBlockKey = getBlockKeyFromSelectionPoint(editorSelectionStart), editorSelectionEndBlockKey = getBlockKeyFromSelectionPoint(editorSelectionEnd); if (!selectionStartBlockKey || !selectionEndBlockKey || !editorSelectionStartBlockKey || !editorSelectionEndBlockKey) return !1; const selectionStartBlockIndex = snapshot.blockIndexMap.get(selectionStartBlockKey), selectionEndBlockIndex = snapshot.blockIndexMap.get(selectionEndBlockKey), editorSelectionStartBlockIndex = snapshot.blockIndexMap.get(editorSelectionStartBlockKey), editorSelectionEndBlockIndex = snapshot.blockIndexMap.get(editorSelectionEndBlockKey); if (selectionStartBlockIndex === void 0 || selectionEndBlockIndex === void 0 || editorSelectionStartBlockIndex === void 0 || editorSelectionEndBlockIndex === void 0) return !1; const [selectionMinBlockIndex, selectionMaxBlockIndex] = selectionStartBlockIndex <= selectionEndBlockIndex ? [selectionStartBlockIndex, selectionEndBlockIndex] : [selectionEndBlockIndex, selectionStartBlockIndex], [editorSelectionMinBlockIndex, editorSelectionMaxBlockIndex] = editorSelectionStartBlockIndex <= editorSelectionEndBlockIndex ? [editorSelectionStartBlockIndex, editorSelectionEndBlockIndex] : [editorSelectionEndBlockIndex, editorSelectionStartBlockIndex]; return selectionMaxBlockIndex < editorSelectionMinBlockIndex || selectionMinBlockIndex > editorSelectionMaxBlockIndex ? !1 : hasPointLevelOverlap(snapshot, selectionStart, selectionEnd, editorSelectionStart, editorSelectionEnd); }; } function hasPointLevelOverlap(snapshot, selectionStart, selectionEnd, editorSelectionStart, editorSelectionEnd) { if (isEqualSelectionPoints(selectionStart, editorSelectionStart) && isEqualSelectionPoints(selectionEnd, editorSelectionEnd)) return !0; const selectionStartVsEditorSelectionStart = comparePoints(snapshot, selectionStart, editorSelectionStart), selectionStartVsEditorSelectionEnd = comparePoints(snapshot, selectionStart, editorSelectionEnd), selectionEndVsEditorSelectionStart = comparePoints(snapshot, selectionEnd, editorSelectionStart), selectionEndVsEditorSelectionEnd = comparePoints(snapshot, selectionEnd, editorSelectionEnd), editorSelectionStartVsSelectionStart = comparePoints(snapshot, editorSelectionStart, selectionStart), editorSelectionEndVsSelectionEnd = comparePoints(snapshot, editorSelectionEnd, selectionEnd), selectionStartBeforeEditorSelectionStart = selectionStartVsEditorSelectionStart === -1, selectionStartAfterEditorSelectionEnd = selectionStartVsEditorSelectionEnd === 1, selectionEndBeforeEditorSelectionStart = selectionEndVsEditorSelectionStart === -1, selectionEndAfterEditorSelectionEnd = selectionEndVsEditorSelectionEnd === 1, editorSelectionStartBeforeSelectionStart = editorSelectionStartVsSelectionStart === -1, editorSelectionStartAfterSelectionStart = editorSelectionStartVsSelectionStart === 1, editorSelectionEndBeforeSelectionEnd = editorSelectionEndVsSelectionEnd === -1, editorSelectionEndAfterSelectionEnd = editorSelectionEndVsSelectionEnd === 1, selectionStartEqualEditorSelectionEnd = isEqualSelectionPoints(selectionStart, editorSelectionEnd), selectionEndEqualEditorSelectionStart = isEqualSelectionPoints(selectionEnd, editorSelectionStart); return !selectionEndEqualEditorSelectionStart && !selectionStartEqualEditorSelectionEnd && !editorSelectionStartBeforeSelectionStart && !editorSelectionStartAfterSelectionStart && !editorSelectionEndBeforeSelectionEnd && !editorSelectionEndAfterSelectionEnd || selectionEndBeforeEditorSelectionStart && !selectionEndEqualEditorSelectionStart || selectionStartAfterEditorSelectionEnd && !selectionStartEqualEditorSelectionEnd ? !1 : !editorSelectionStartBeforeSelectionStart && editorSelectionStartAfterSelectionStart && !editorSelectionEndBeforeSelectionEnd && editorSelectionEndAfterSelectionEnd ? !selectionEndEqualEditorSelectionStart : editorSelectionStartBeforeSelectionStart && !editorSelectionStartAfterSelectionStart && editorSelectionEndBeforeSelectionEnd && !editorSelectionEndAfterSelectionEnd ? !selectionStartEqualEditorSelectionEnd : !selectionStartAfterEditorSelectionEnd || !selectionStartBeforeEditorSelectionStart || !selectionEndAfterEditorSelectionEnd || !selectionEndBeforeEditorSelectionStart; } const isSelectingEntireBlocks = (snapshot) => { if (!snapshot.context.selection) return !1; const startPoint = snapshot.context.selection.backward ? snapshot.context.selection.focus : snapshot.context.selection.anchor, endPoint = snapshot.context.selection.backward ? snapshot.context.selection.anchor : snapshot.context.selection.focus, startBlock = getSelectionStartBlock(snapshot), endBlock = getSelectionEndBlock(snapshot); if (!startBlock || !endBlock) return !1; const startBlockStartPoint = getBlockStartPoint({ context: snapshot.context, block: startBlock }), endBlockEndPoint = getBlockEndPoint({ context: snapshot.context, block: endBlock }); return isEqualSelectionPoints(startBlockStartPoint, startPoint) && isEqualSelectionPoints(endBlockEndPoint, endPoint); }; export { comparePoints, getActiveAnnotations, getActiveAnnotationsMarks, getActiveDecorators, getActiveListItem, getActiveStyle, getCaretWordSelection, getFocusBlock, getFocusBlockObject, getFocusChild, getFocusInlineObject, getFocusListBlock, getFocusSpan, getFocusTextBlock, getLastBlock, getMarkState, getNextBlock, getNextInlineObject, getNextSpan, getPreviousBlock, getPreviousInlineObject, getPreviousSpan, getSelectedBlocks, getSelectedChildren, getSelectedSpans, getSelectedTextBlocks, getSelectedValue, getSelectionEndBlock, getSelectionEndChild, getSelectionEndPoint, getSelectionStartBlock, getSelectionStartChild, getSelectionStartPoint, getSelectionText, isActiveAnnotation, isActiveDecorator, isActiveListItem, isActiveStyle, isAtTheEndOfBlock, isAtTheStartOfBlock, isOverlappingSelection, isSelectingEntireBlocks, isSelectionCollapsed, isSelectionExpanded }; //# sourceMappingURL=selector.is-selecting-entire-blocks.js.map