@portabletext/editor
Version:
Portable Text Editor made in React
240 lines (239 loc) • 7.5 kB
JavaScript
import { isPortableTextTextBlock, isPortableTextSpan, isKeySegment } from "@sanity/types";
function isKeyedSegment(segment) {
return typeof segment == "object" && segment !== null && "_key" in segment;
}
function blockOffsetToSpanSelectionPoint({
value,
blockOffset,
direction
}) {
let offsetLeft = blockOffset.offset, selectionPoint, skippedInlineObject = !1;
for (const block of value)
if (block._key === blockOffset.path[0]._key && isPortableTextTextBlock(block))
for (const child of block.children) {
if (direction === "forward") {
if (!isPortableTextSpan(child))
continue;
if (offsetLeft <= child.text.length) {
selectionPoint = {
path: [...blockOffset.path, "children", {
_key: child._key
}],
offset: offsetLeft
};
break;
}
offsetLeft -= child.text.length;
continue;
}
if (!isPortableTextSpan(child)) {
skippedInlineObject = !0;
continue;
}
if (offsetLeft === 0 && selectionPoint && !skippedInlineObject) {
skippedInlineObject && (selectionPoint = {
path: [...blockOffset.path, "children", {
_key: child._key
}],
offset: 0
});
break;
}
if (offsetLeft > child.text.length) {
offsetLeft -= child.text.length;
continue;
}
if (offsetLeft <= child.text.length && (selectionPoint = {
path: [...blockOffset.path, "children", {
_key: child._key
}],
offset: offsetLeft
}, offsetLeft -= child.text.length, offsetLeft !== 0))
break;
}
return selectionPoint;
}
function spanSelectionPointToBlockOffset({
value,
selectionPoint
}) {
let offset = 0;
const blockKey = isKeyedSegment(selectionPoint.path[0]) ? selectionPoint.path[0]._key : void 0, spanKey = isKeyedSegment(selectionPoint.path[2]) ? selectionPoint.path[2]._key : void 0;
if (!(!blockKey || !spanKey)) {
for (const block of value)
if (block._key === blockKey && isPortableTextTextBlock(block)) {
for (const child of block.children)
if (isPortableTextSpan(child)) {
if (child._key === spanKey)
return {
path: [{
_key: block._key
}],
offset: offset + selectionPoint.offset
};
offset += child.text.length;
}
}
}
}
function getBlockEndPoint({
node,
path
}) {
if (isPortableTextTextBlock(node)) {
const lastChild = node.children[node.children.length - 1];
if (lastChild)
return {
path: [...path, "children", {
_key: lastChild._key
}],
offset: isPortableTextSpan(lastChild) ? lastChild.text.length : 0
};
}
return {
path,
offset: 0
};
}
function getBlockStartPoint({
node,
path
}) {
return isPortableTextTextBlock(node) ? {
path: [...path, "children", {
_key: node.children[0]._key
}],
offset: 0
} : {
path,
offset: 0
};
}
function getTextBlockText(block) {
return block.children.map((child) => child.text ?? "").join("");
}
function isEmptyTextBlock(block) {
if (!isPortableTextTextBlock(block))
return !1;
const onlyText = block.children.every(isPortableTextSpan), blockText = getTextBlockText(block);
return onlyText && blockText === "";
}
function isEqualSelectionPoints(a, b) {
return a.offset === b.offset && JSON.stringify(a.path) === JSON.stringify(b.path);
}
function isSpan(context, child) {
return child._type === context.schema.span.name;
}
function reverseSelection(selection) {
return selection && (selection.backward ? {
anchor: selection.focus,
focus: selection.anchor,
backward: !1
} : {
anchor: selection.focus,
focus: selection.anchor,
backward: !0
});
}
function sliceBlocks({
blocks,
selection
}) {
const slice = [];
if (!selection)
return slice;
let startBlock;
const middleBlocks = [];
let endBlock;
const startPoint = selection.backward ? selection.focus : selection.anchor, endPoint = selection.backward ? selection.anchor : selection.focus, startBlockKey = isKeySegment(startPoint.path[0]) ? startPoint.path[0]._key : void 0, endBlockKey = isKeySegment(endPoint.path[0]) ? endPoint.path[0]._key : void 0, startChildKey = isKeySegment(startPoint.path[2]) ? startPoint.path[2]._key : void 0, endChildKey = isKeySegment(endPoint.path[2]) ? endPoint.path[2]._key : void 0;
if (!startBlockKey || !endBlockKey)
return slice;
for (const block of blocks) {
if (!isPortableTextTextBlock(block) && block._key === startBlockKey && block._key === endBlockKey) {
startBlock = block;
break;
}
if (block._key === startBlockKey) {
if (!isPortableTextTextBlock(block)) {
startBlock = block;
continue;
}
if (startChildKey) {
for (const child of block.children) {
if (child._key === startChildKey) {
if (isPortableTextSpan(child)) {
const text = child._key === endChildKey ? child.text.slice(startPoint.offset, endPoint.offset) : child.text.slice(startPoint.offset);
startBlock = {
...block,
children: [{
...child,
text
}]
};
} else
startBlock = {
...block,
children: [child]
};
if (startChildKey === endChildKey)
break;
continue;
}
if (startBlock && isPortableTextTextBlock(startBlock) && (endChildKey && child._key === endChildKey && isPortableTextSpan(child) ? startBlock.children.push({
...child,
text: child.text.slice(0, endPoint.offset)
}) : startBlock.children.push(child), block._key === endBlockKey && endChildKey && child._key === endChildKey))
break;
}
if (startBlockKey === endBlockKey)
break;
continue;
}
if (startBlock = block, startBlockKey === endBlockKey)
break;
}
if (block._key === endBlockKey) {
if (!isPortableTextTextBlock(block)) {
endBlock = block;
break;
}
if (endChildKey) {
endBlock = {
...block,
children: []
};
for (const child of block.children)
if (endBlock && isPortableTextTextBlock(endBlock)) {
if (child._key === endChildKey && isPortableTextSpan(child)) {
endBlock.children.push({
...child,
text: child.text.slice(0, endPoint.offset)
});
break;
}
if (endBlock.children.push(child), endChildKey && child._key === endChildKey)
break;
}
break;
}
endBlock = block;
break;
}
startBlock && middleBlocks.push(block);
}
return [...startBlock ? [startBlock] : [], ...middleBlocks, ...endBlock ? [endBlock] : []];
}
export {
blockOffsetToSpanSelectionPoint,
getBlockEndPoint,
getBlockStartPoint,
getTextBlockText,
isEmptyTextBlock,
isEqualSelectionPoints,
isKeyedSegment,
isSpan,
reverseSelection,
sliceBlocks,
spanSelectionPointToBlockOffset
};
//# sourceMappingURL=util.slice-blocks.js.map