UNPKG

@portabletext/editor

Version:

Portable Text Editor made in React

291 lines (290 loc) 13.9 kB
"use strict"; var types = require("@sanity/types"), selector_isOverlappingSelection = require("./selector.is-overlapping-selection.cjs"), parseBlocks = require("./parse-blocks.cjs"), util_sliceBlocks = require("./util.slice-blocks.cjs"); const getSelectedSpans = (snapshot) => { if (!snapshot.context.selection) return []; const selectedSpans = [], 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, startBlockKey = types.isKeySegment(startPoint.path[0]) ? startPoint.path[0]._key : void 0, endBlockKey = types.isKeySegment(endPoint.path[0]) ? endPoint.path[0]._key : void 0; if (!startBlockKey || !endBlockKey) return selectedSpans; const startSpanKey = types.isKeySegment(startPoint.path[2]) ? startPoint.path[2]._key : void 0, endSpanKey = types.isKeySegment(endPoint.path[2]) ? endPoint.path[2]._key : void 0; let startBlockFound = !1; for (const block of snapshot.context.value) if (block._key === startBlockKey && (startBlockFound = !0), !!types.isPortableTextTextBlock(block)) { if (block._key === startBlockKey) { for (const child of block.children) if (types.isPortableTextSpan(child)) { if (startSpanKey && child._key === startSpanKey) { if (startPoint.offset < child.text.length && selectedSpans.push({ node: child, path: [{ _key: block._key }, "children", { _key: child._key }] }), startSpanKey === endSpanKey) break; continue; } if (endSpanKey && child._key === endSpanKey) { endPoint.offset > 0 && selectedSpans.push({ node: child, path: [{ _key: block._key }, "children", { _key: child._key }] }); break; } 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 (types.isPortableTextSpan(child)) { if (endSpanKey && child._key === endSpanKey) { 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) types.isPortableTextSpan(child) && selectedSpans.push({ node: child, path: [{ _key: block._key }, "children", { _key: child._key }] }); } return selectedSpans; }, getActiveAnnotations = (snapshot) => { if (!snapshot.context.selection) return []; const selectedBlocks = selector_isOverlappingSelection.getSelectedBlocks(snapshot), selectedSpans = getSelectedSpans(snapshot), focusSpan = selector_isOverlappingSelection.getFocusSpan(snapshot); if (selectedSpans.length === 0 || !focusSpan) return []; if (selectedSpans.length === 1 && selector_isOverlappingSelection.isSelectionCollapsed(snapshot)) { if (snapshot.context.selection.focus.offset === 0) return []; if (snapshot.context.selection.focus.offset === focusSpan.node.text.length) return []; } return selectedBlocks.flatMap((block) => types.isPortableTextTextBlock(block.node) ? block.node.markDefs ?? [] : []).filter((markDef) => selectedSpans.some((span) => span.node.marks?.includes(markDef._key))); }, getActiveListItem = (snapshot) => { if (!snapshot.context.selection) return; const guards = selector_isOverlappingSelection.createGuards(snapshot.context), selectedTextBlocks = selector_isOverlappingSelection.getSelectedBlocks(snapshot).map((block) => block.node).filter(guards.isTextBlock), 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 guards = selector_isOverlappingSelection.createGuards(snapshot.context), selectedTextBlocks = selector_isOverlappingSelection.getSelectedBlocks(snapshot).map((block) => block.node).filter(guards.isTextBlock), firstTextBlock = selectedTextBlocks.at(0); if (!firstTextBlock) return; const firstStyle = firstTextBlock.style; if (firstStyle && selectedTextBlocks.every((block) => block.style === firstStyle)) return firstStyle; }, getSelectedTextBlocks = (snapshot) => { if (!snapshot.context.selection) return []; const selectedTextBlocks = [], startKey = snapshot.context.selection.backward ? util_sliceBlocks.isKeyedSegment(snapshot.context.selection.focus.path[0]) ? snapshot.context.selection.focus.path[0]._key : void 0 : util_sliceBlocks.isKeyedSegment(snapshot.context.selection.anchor.path[0]) ? snapshot.context.selection.anchor.path[0]._key : void 0, endKey = snapshot.context.selection.backward ? util_sliceBlocks.isKeyedSegment(snapshot.context.selection.anchor.path[0]) ? snapshot.context.selection.anchor.path[0]._key : void 0 : util_sliceBlocks.isKeyedSegment(snapshot.context.selection.focus.path[0]) ? snapshot.context.selection.focus.path[0]._key : void 0; if (!startKey || !endKey) return selectedTextBlocks; for (const block of snapshot.context.value) { if (block._key === startKey) { if (parseBlocks.isTextBlock(snapshot.context.schema, block) && selectedTextBlocks.push({ node: block, path: [{ _key: block._key }] }), startKey === endKey) break; continue; } if (block._key === endKey) { parseBlocks.isTextBlock(snapshot.context.schema, block) && selectedTextBlocks.push({ node: block, path: [{ _key: block._key }] }); break; } selectedTextBlocks.length > 0 && parseBlocks.isTextBlock(snapshot.context.schema, block) && selectedTextBlocks.push({ node: block, path: [{ _key: block._key }] }); } return selectedTextBlocks; }, getTrimmedSelection = (snapshot) => { if (!snapshot.context.selection) return snapshot.context.selection; const startPoint = selector_isOverlappingSelection.getSelectionStartPoint(snapshot), endPoint = selector_isOverlappingSelection.getSelectionEndPoint(snapshot); if (!startPoint || !endPoint) return snapshot.context.selection; const startBlockKey = util_sliceBlocks.isKeyedSegment(startPoint.path[0]) ? startPoint.path[0]._key : null, startChildKey = util_sliceBlocks.isKeyedSegment(startPoint.path[2]) ? startPoint.path[2]._key : null, endBlockKey = util_sliceBlocks.isKeyedSegment(endPoint.path[0]) ? endPoint.path[0]._key : null, endChildKey = util_sliceBlocks.isKeyedSegment(endPoint.path[2]) ? endPoint.path[2]._key : null; if (!startBlockKey || !endBlockKey) return snapshot.context.selection; let startBlockFound = !1, adjustedStartPoint, trimStartPoint = !1, adjustedEndPoint, trimEndPoint = !1, previousPotentialEndpoint; for (const block of snapshot.context.value) if (!(block._key === startBlockKey && (startBlockFound = !0, types.isPortableTextTextBlock(block) && util_sliceBlocks.isEmptyTextBlock(block))) && startBlockFound && types.isPortableTextTextBlock(block)) { if (block._key === endBlockKey && util_sliceBlocks.isEmptyTextBlock(block)) break; for (const child of block.children) { if (child._key === endChildKey && (!types.isPortableTextSpan(child) || endPoint.offset === 0)) { adjustedEndPoint = previousPotentialEndpoint ? { path: [{ _key: previousPotentialEndpoint.blockKey }, "children", { _key: previousPotentialEndpoint.span._key }], offset: previousPotentialEndpoint.span.text.length } : void 0, trimEndPoint = !0; break; } if (trimStartPoint) { const lonelySpan = types.isPortableTextSpan(child) && block.children.length === 1; (types.isPortableTextSpan(child) && child.text.length > 0 || lonelySpan) && (adjustedStartPoint = { path: [{ _key: block._key }, "children", { _key: child._key }], offset: 0 }, previousPotentialEndpoint = { blockKey: block._key, span: child }, trimStartPoint = !1); continue; } if (child._key === startChildKey) { if (!types.isPortableTextSpan(child)) { trimStartPoint = !0; continue; } if (startPoint.offset === child.text.length) { trimStartPoint = !0, previousPotentialEndpoint = child.text.length > 0 ? { blockKey: block._key, span: child } : previousPotentialEndpoint; continue; } } previousPotentialEndpoint = types.isPortableTextSpan(child) && child.text.length > 0 ? { blockKey: block._key, span: child } : previousPotentialEndpoint; } if (block._key === endBlockKey) break; } const trimmedSelection = snapshot.context.selection.backward ? { anchor: trimEndPoint && adjustedEndPoint ? adjustedEndPoint : endPoint, focus: adjustedStartPoint ?? startPoint, backward: !0 } : { anchor: adjustedStartPoint ?? startPoint, focus: trimEndPoint && adjustedEndPoint ? adjustedEndPoint : endPoint }; if (selector_isOverlappingSelection.isSelectionCollapsed({ context: { ...snapshot.context, selection: trimmedSelection } })) { const focusTextBlock = selector_isOverlappingSelection.getFocusTextBlock({ context: { ...snapshot.context, selection: trimmedSelection } }); if (focusTextBlock && !util_sliceBlocks.isEmptyTextBlock(focusTextBlock.node)) return null; } return trimmedSelection; }; function isActiveAnnotation(annotation) { return (snapshot) => { if (!snapshot.context.selection) return !1; const selectedBlocks = selector_isOverlappingSelection.getSelectedBlocks(snapshot), focusSpan = selector_isOverlappingSelection.getFocusSpan(snapshot), selectedSpans = selector_isOverlappingSelection.isSelectionExpanded(snapshot) ? getSelectedSpans(snapshot) : focusSpan ? [focusSpan] : []; if (selectedSpans.length === 0 || selectedSpans.some((span) => !span.node.marks || span.node.marks?.length === 0)) return !1; const selectionMarkDefs = selectedBlocks.flatMap((block) => types.isPortableTextTextBlock(block.node) ? block.node.markDefs ?? [] : []); return selectedSpans.every((span) => (span.node.marks?.flatMap((mark) => { const markDef = selectionMarkDefs.find((markDef2) => markDef2._key === mark); return markDef ? [markDef._type] : []; }) ?? []).includes(annotation)); }; } function isActiveDecorator(decorator) { return (snapshot) => { if (selector_isOverlappingSelection.isSelectionExpanded(snapshot)) { const selectedSpans = getSelectedSpans(snapshot); return selectedSpans.length > 0 && selectedSpans.every((span) => span.node.marks?.includes(decorator)); } return snapshot.context.activeDecorators.includes(decorator); }; } function isActiveListItem(listItem) { return (snapshot) => getActiveListItem(snapshot) === listItem; } function isActiveStyle(style) { return (snapshot) => getActiveStyle(snapshot) === style; } 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 = selector_isOverlappingSelection.getSelectionStartBlock(snapshot), endBlock = selector_isOverlappingSelection.getSelectionEndBlock(snapshot); if (!startBlock || !endBlock) return !1; const startBlockStartPoint = util_sliceBlocks.getBlockStartPoint(startBlock), endBlockEndPoint = util_sliceBlocks.getBlockEndPoint(endBlock); return util_sliceBlocks.isEqualSelectionPoints(startBlockStartPoint, startPoint) && util_sliceBlocks.isEqualSelectionPoints(endBlockEndPoint, endPoint); }; exports.getActiveAnnotations = getActiveAnnotations; exports.getActiveListItem = getActiveListItem; exports.getActiveStyle = getActiveStyle; exports.getSelectedSpans = getSelectedSpans; exports.getSelectedTextBlocks = getSelectedTextBlocks; exports.getTrimmedSelection = getTrimmedSelection; exports.isActiveAnnotation = isActiveAnnotation; exports.isActiveDecorator = isActiveDecorator; exports.isActiveListItem = isActiveListItem; exports.isActiveStyle = isActiveStyle; exports.isSelectingEntireBlocks = isSelectingEntireBlocks; //# sourceMappingURL=selector.is-selecting-entire-blocks.cjs.map