@portabletext/editor
Version:
Portable Text Editor made in React
193 lines (192 loc) • 6.22 kB
JavaScript
import { isTextBlock } from "@portabletext/schema";
function isTypedObject(object) {
return isRecord(object) && typeof object._type == "string";
}
function isRecord(value) {
return !!value && (typeof value == "object" || typeof value == "function");
}
function isObjectNode(context, node) {
return isTypedObject(node) && node._type !== context.schema.block.name && node._type !== context.schema.span.name;
}
function isKeyedSegment(segment) {
return typeof segment == "object" && segment !== null && "_key" in segment;
}
function getChildren(snapshot, path) {
let currentChildren = snapshot.context.value, currentFieldName = "value", currentPath = [], isRoot = !0, currentParent;
for (const segment of path) {
if (typeof segment == "string")
continue;
let node;
if (isKeyedSegment(segment) ? node = currentChildren.find((child) => child._key === segment._key) : typeof segment == "number" && (node = currentChildren.at(segment)), !node)
return [];
currentPath = isRoot ? [{
_key: node._key
}] : [...currentPath, currentFieldName, {
_key: node._key
}], isRoot = !1;
const next = getNodeChildren(snapshot.context, node, currentParent);
if (!next)
return [];
currentChildren = next.children, currentFieldName = next.fieldName, currentParent = next.parent;
}
return currentChildren.map((child) => ({
node: child,
path: isRoot ? [{
_key: child._key
}] : [...currentPath, currentFieldName, {
_key: child._key
}]
}));
}
function getNodeChildren(context, node, parent) {
if (isTextBlock(context, node))
return {
children: node.children,
fieldName: "children",
parent: void 0
};
if (isObjectNode(context, node)) {
const resolved = resolveNodeContainer(context.containers, parent, node);
if (!resolved)
return;
const fieldValue = node[resolved.field.name];
return Array.isArray(fieldValue) ? {
children: fieldValue,
fieldName: resolved.field.name,
parent: resolved
} : void 0;
}
if ("value" in node && Array.isArray(node.value) && !("_key" in node) && !("_type" in node))
return {
children: node.value,
fieldName: "value",
parent: void 0
};
}
function resolveNodeContainer(containers, parent, node) {
if (parent?.of) {
for (const entry of parent.of)
if (entry.type === node._type)
return "field" in entry ? entry : void 0;
}
return containers.get(node._type);
}
function getNode(snapshot, path) {
if (path.length === 0)
return;
const {
context,
blockIndexMap
} = snapshot;
let currentChildren = context.value, node, currentParent;
const resolvedPath = [];
let isRootLevel = !0;
for (let i = 0; i < path.length; i++) {
const segment = path[i];
if (typeof segment == "string") {
resolvedPath.push(segment);
continue;
}
if (isKeyedSegment(segment)) {
if (isRootLevel && blockIndexMap.size === currentChildren.length) {
const index = blockIndexMap.get(segment._key);
if (index !== void 0) {
const candidate = currentChildren[index];
candidate && candidate._key === segment._key ? node = candidate : node = currentChildren.find((child) => child._key === segment._key);
} else
node = currentChildren.find((child) => child._key === segment._key);
} else
node = currentChildren.find((child) => child._key === segment._key);
resolvedPath.push(segment), isRootLevel = !1;
} else if (typeof segment == "number")
node = currentChildren.at(segment), node && resolvedPath.push({
_key: node._key
});
else
return;
if (!node)
return;
let hasMoreSegments = !1;
for (let j = i + 1; j < path.length; j++) {
const s = path[j];
if (isKeyedSegment(s) || typeof s == "number") {
hasMoreSegments = !0;
break;
}
}
if (hasMoreSegments) {
const next = getNodeChildren(context, node, currentParent);
if (!next)
return;
currentChildren = next.children, currentParent = next.parent;
}
}
if (node)
return {
node,
path: resolvedPath
};
}
function getAncestors(snapshot, path) {
const keyedIndices = [];
for (let i = 0; i < path.length; i++)
isKeyedSegment(path[i]) && keyedIndices.push(i);
if (keyedIndices.length <= 1)
return [];
const {
context,
blockIndexMap
} = snapshot;
let currentChildren = context.value, isRootLevel = !0, currentParent;
const ancestorsByDepth = [], resolvedPath = [], targetKeyedIndex = keyedIndices[keyedIndices.length - 1];
let segmentIndex = 0;
for (; segmentIndex < targetKeyedIndex; ) {
const segment = path[segmentIndex];
if (typeof segment == "string") {
resolvedPath.push(segment), segmentIndex++;
continue;
}
let node;
if (isKeyedSegment(segment)) {
if (isRootLevel && blockIndexMap.size === currentChildren.length) {
const index = blockIndexMap.get(segment._key);
node = index !== void 0 ? currentChildren[index] : currentChildren.find((child) => child._key === segment._key);
} else
node = currentChildren.find((child) => child._key === segment._key);
resolvedPath.push(segment), isRootLevel = !1;
} else if (typeof segment == "number")
node = currentChildren.at(segment), node && resolvedPath.push({
_key: node._key
});
else
return [];
if (!node)
return [];
const next = getNodeChildren(context, node, currentParent);
if (!next)
return [];
ancestorsByDepth.push({
node,
path: resolvedPath.slice()
}), currentChildren = next.children, currentParent = next.parent, segmentIndex++;
}
return ancestorsByDepth.reverse();
}
function getAncestor(snapshot, path, match) {
const ancestors = getAncestors(snapshot, path);
for (const ancestor of ancestors)
if (match(ancestor.node, ancestor.path))
return ancestor;
}
export {
getAncestor,
getAncestors,
getChildren,
getNode,
getNodeChildren,
isKeyedSegment,
isObjectNode,
isRecord,
isTypedObject
};
//# sourceMappingURL=get-ancestor.js.map