@portabletext/editor
Version:
Portable Text Editor made in React
434 lines (433 loc) • 13.3 kB
JavaScript
function isTypedObject(object) {
return isRecord(object) && typeof object._type == "string";
}
function isRecord(value) {
return !!value && (typeof value == "object" || typeof value == "function");
}
function parseBlocks({
context,
blocks,
options
}) {
return Array.isArray(blocks) ? blocks.flatMap((block) => {
const parsedBlock = parseBlock({
context,
block,
options
});
return parsedBlock ? [parsedBlock] : [];
}) : [];
}
function parseBlock({
context,
block,
options
}) {
return parseTextBlock({
block,
context,
options
}) ?? parseBlockObject({
blockObject: block,
context,
options
});
}
function parseBlockObject({
blockObject,
context,
options
}) {
if (!isTypedObject(blockObject))
return;
const schemaType = context.schema.blockObjects.find(({
name
}) => name === blockObject._type);
if (schemaType)
return parseObject({
object: blockObject,
context: {
keyGenerator: context.keyGenerator,
schemaType
},
options
});
}
function isListBlock(context, block) {
return isTextBlock(context, block) && block.level !== void 0 && block.listItem !== void 0;
}
function isTextBlock(context, block) {
return !(!isTypedObject(block) || block._type !== context.schema.block.name || !Array.isArray(block.children));
}
function parseTextBlock({
block,
context,
options
}) {
if (!isTypedObject(block))
return;
const customFields = {};
for (const key of Object.keys(block))
key !== "_type" && key !== "_key" && key !== "children" && key !== "markDefs" && key !== "style" && key !== "listItem" && key !== "level" && (customFields[key] = block[key]);
if (block._type !== context.schema.block.name)
return;
const _key = options.refreshKeys ? context.keyGenerator() : typeof block._key == "string" ? block._key : context.keyGenerator(), unparsedMarkDefs = Array.isArray(block.markDefs) ? block.markDefs : [], markDefKeyMap = /* @__PURE__ */ new Map(), markDefs = unparsedMarkDefs.flatMap((markDef) => {
if (!isTypedObject(markDef))
return [];
const schemaType = context.schema.annotations.find(({
name
}) => name === markDef._type);
if (!schemaType)
return [];
if (typeof markDef._key != "string")
return [];
const parsedAnnotation = parseObject({
object: markDef,
context: {
schemaType,
keyGenerator: context.keyGenerator
},
options
});
return parsedAnnotation ? (markDefKeyMap.set(markDef._key, parsedAnnotation._key), [parsedAnnotation]) : [];
}), children = (Array.isArray(block.children) ? block.children : []).map((child) => parseSpan({
span: child,
context,
markDefKeyMap,
options
}) ?? parseInlineObject({
inlineObject: child,
context,
options
})).filter((child) => child !== void 0), parsedBlock = {
_type: context.schema.block.name,
_key,
children: children.length > 0 ? children : [{
_key: context.keyGenerator(),
_type: context.schema.span.name,
text: "",
marks: []
}],
markDefs,
...options.validateFields ? {} : customFields
};
if (typeof block.style == "string" && context.schema.styles.find((style) => style.name === block.style))
parsedBlock.style = block.style;
else {
const defaultStyle = context.schema.styles.at(0)?.name;
defaultStyle !== void 0 ? parsedBlock.style = defaultStyle : console.error("Expected default style");
}
return typeof block.listItem == "string" && context.schema.lists.find((list) => list.name === block.listItem) && (parsedBlock.listItem = block.listItem), typeof block.level == "number" && (parsedBlock.level = block.level), parsedBlock;
}
function isSpan$1(context, child) {
return !(!isTypedObject(child) || child._type !== context.schema.span.name || typeof child.text != "string");
}
function parseSpan({
span,
context,
markDefKeyMap,
options
}) {
if (!isTypedObject(span))
return;
const customFields = {};
for (const key of Object.keys(span))
key !== "_type" && key !== "_key" && key !== "text" && key !== "marks" && (customFields[key] = span[key]);
if (span._type !== context.schema.span.name || span._type !== "span")
return;
const marks = (Array.isArray(span.marks) ? span.marks : []).flatMap((mark) => {
if (typeof mark != "string")
return [];
const markDefKey = markDefKeyMap.get(mark);
return markDefKey !== void 0 ? [markDefKey] : context.schema.decorators.some((decorator) => decorator.name === mark) ? [mark] : [];
});
return {
_type: "span",
_key: options.refreshKeys ? context.keyGenerator() : typeof span._key == "string" ? span._key : context.keyGenerator(),
text: typeof span.text == "string" ? span.text : "",
marks,
...options.validateFields ? {} : customFields
};
}
function parseInlineObject({
inlineObject,
context,
options
}) {
if (!isTypedObject(inlineObject))
return;
const schemaType = context.schema.inlineObjects.find(({
name
}) => name === inlineObject._type);
if (schemaType)
return parseObject({
object: inlineObject,
context: {
keyGenerator: context.keyGenerator,
schemaType
},
options
});
}
function parseAnnotation({
annotation,
context,
options
}) {
if (!isTypedObject(annotation))
return;
const schemaType = context.schema.annotations.find(({
name
}) => name === annotation._type);
if (schemaType)
return parseObject({
object: annotation,
context: {
keyGenerator: context.keyGenerator,
schemaType
},
options
});
}
function parseObject({
object,
context,
options
}) {
const {
_type,
_key,
...customFields
} = object, values = options.validateFields ? context.schemaType.fields.reduce((fieldValues, field) => {
const fieldValue = object[field.name];
return fieldValue !== void 0 && (fieldValues[field.name] = fieldValue), fieldValues;
}, {}) : customFields;
return {
_type: context.schemaType.name,
_key: options.refreshKeys ? context.keyGenerator() : typeof object._key == "string" ? object._key : context.keyGenerator(),
...values
};
}
function blockOffsetToSpanSelectionPoint({
context,
blockOffset,
direction
}) {
let offsetLeft = blockOffset.offset, selectionPoint, skippedInlineObject = !1;
for (const block of context.value)
if (block._key === blockOffset.path[0]._key && isTextBlock(context, block))
for (const child of block.children) {
if (direction === "forward") {
if (!isSpan$1(context, child))
continue;
if (offsetLeft <= child.text.length) {
selectionPoint = {
path: [...blockOffset.path, "children", {
_key: child._key
}],
offset: offsetLeft
};
break;
}
offsetLeft -= child.text.length;
continue;
}
if (!isSpan$1(context, 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({
context,
selectionPoint
}) {
let offset = 0;
const blockKey = getBlockKeyFromSelectionPoint(selectionPoint), spanKey = getChildKeyFromSelectionPoint(selectionPoint);
if (!(!blockKey || !spanKey)) {
for (const block of context.value)
if (block._key === blockKey && isTextBlock(context, block)) {
for (const child of block.children)
if (isSpan$1(context, child)) {
if (child._key === spanKey)
return {
path: [{
_key: block._key
}],
offset: offset + selectionPoint.offset
};
offset += child.text.length;
}
}
}
}
function getBlockStartPoint({
context,
block
}) {
return isTextBlock(context, block.node) ? {
path: [...block.path, "children", {
_key: block.node.children[0]._key
}],
offset: 0
} : {
path: block.path,
offset: 0
};
}
function getSelectionEndPoint(selection) {
return selection ? selection.backward ? selection.anchor : selection.focus : null;
}
function getSelectionStartPoint(selection) {
return selection ? selection.backward ? selection.focus : selection.anchor : null;
}
function getTextBlockText(block) {
return block.children.map((child) => child.text ?? "").join("");
}
function isKeyedSegment(segment) {
return typeof segment == "object" && segment !== null && "_key" in segment;
}
function isSpan(context, child) {
return child._type === context.schema.span.name;
}
function sliceBlocks({
context,
blocks
}) {
const slice = [];
if (!context.selection)
return slice;
let startBlock;
const middleBlocks = [];
let endBlock;
const startPoint = getSelectionStartPoint(context.selection), endPoint = getSelectionEndPoint(context.selection), startBlockKey = getBlockKeyFromSelectionPoint(startPoint), startChildKey = getChildKeyFromSelectionPoint(startPoint), endBlockKey = getBlockKeyFromSelectionPoint(endPoint), endChildKey = getChildKeyFromSelectionPoint(endPoint);
if (!startBlockKey || !endBlockKey)
return slice;
for (const block of blocks) {
if (!isTextBlock(context, block) && block._key === startBlockKey && block._key === endBlockKey) {
startBlock = block;
break;
}
if (block._key === startBlockKey) {
if (!isTextBlock(context, block)) {
startBlock = block;
continue;
}
if (startChildKey) {
for (const child of block.children) {
if (child._key === startChildKey) {
if (isSpan$1(context, 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 && isTextBlock(context, startBlock) && (endChildKey && child._key === endChildKey && isSpan$1(context, 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 (!isTextBlock(context, block)) {
endBlock = block;
break;
}
if (endChildKey) {
endBlock = {
...block,
children: []
};
for (const child of block.children)
if (endBlock && isTextBlock(context, endBlock)) {
if (child._key === endChildKey && isSpan$1(context, 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] : []];
}
function getBlockKeyFromSelectionPoint(point) {
const blockPathSegment = point.path.at(0);
if (isKeyedSegment(blockPathSegment))
return blockPathSegment._key;
}
function getChildKeyFromSelectionPoint(point) {
const childPathSegment = point.path.at(2);
if (isKeyedSegment(childPathSegment))
return childPathSegment._key;
}
export {
blockOffsetToSpanSelectionPoint,
getBlockKeyFromSelectionPoint,
getBlockStartPoint,
getChildKeyFromSelectionPoint,
getSelectionEndPoint,
getSelectionStartPoint,
getTextBlockText,
isKeyedSegment,
isListBlock,
isSpan,
isSpan$1,
isTextBlock,
isTypedObject,
parseAnnotation,
parseBlock,
parseBlocks,
parseInlineObject,
sliceBlocks,
spanSelectionPointToBlockOffset
};
//# sourceMappingURL=selection-point.js.map