@portabletext/block-tools
Version:
Sanity-flavored HTML to Portable Text conversion (wraps @portabletext/html)
113 lines (112 loc) • 3.88 kB
JavaScript
import { htmlToPortableText } from "@portabletext/html";
import { sanitySchemaToPortableTextSchema } from "@portabletext/sanity-bridge";
import { isSpan } from "@portabletext/schema";
function isEqualMarks(a, b) {
if (!a || !b)
return a === b;
if (a.length !== b.length)
return !1;
for (let index = 0; index < a.length; index++)
if (a[index] !== b[index])
return !1;
return !0;
}
function keyGenerator() {
return randomKey(12);
}
function whatwgRNG(length = 16) {
const rnds8 = new Uint8Array(length);
return crypto.getRandomValues(rnds8), rnds8;
}
const byteToHex = [];
for (let i = 0; i < 256; ++i)
byteToHex[i] = (i + 256).toString(16).slice(1);
function randomKey(length) {
return whatwgRNG(length).reduce((str, n) => str + byteToHex[n], "").slice(0, length);
}
function normalizeBlock(node, options = {}) {
const schema = {
block: {
name: options.blockTypeName || "block"
},
span: {
name: "span"
},
styles: [],
lists: [],
decorators: [],
annotations: [],
blockObjects: [],
inlineObjects: []
};
if (node._type !== (options.blockTypeName || "block"))
return "_key" in node ? node : {
...node,
_key: options.keyGenerator ? options.keyGenerator() : keyGenerator()
};
const block = {
_key: options.keyGenerator ? options.keyGenerator() : keyGenerator(),
children: [],
markDefs: [],
...node
}, lastChild = block.children[block.children.length - 1];
if (!lastChild)
return block.children = [
{
_type: "span",
_key: options.keyGenerator ? options.keyGenerator() : keyGenerator(),
text: "",
marks: []
}
], block;
const usedMarkDefs = [], allowedDecorators = options.allowedDecorators && Array.isArray(options.allowedDecorators) ? options.allowedDecorators : !1;
return block.children = block.children.reduce(
(acc, child) => {
const previousChild = acc[acc.length - 1];
return previousChild && isSpan({ schema }, child) && isSpan({ schema }, previousChild) && isEqualMarks(previousChild.marks, child.marks) ? (lastChild && lastChild === child && child.text === "" && block.children.length > 1 || (previousChild.text += child.text), acc) : (acc.push(child), acc);
},
[]
).map((child) => {
if (!child)
throw new Error("missing child");
return child._key = options.keyGenerator ? options.keyGenerator() : keyGenerator(), isSpan({ schema }, child) && (child.marks ? allowedDecorators && (child.marks = child.marks.filter((mark) => {
const isAllowed = allowedDecorators.includes(mark), isUsed = block.markDefs?.some((def) => def._key === mark);
return isAllowed || isUsed;
})) : child.marks = [], usedMarkDefs.push(...child.marks)), child;
}), block.markDefs = (block.markDefs || []).filter(
(markDef) => usedMarkDefs.includes(markDef._key)
), block;
}
function htmlToBlocks(html, schemaType, options = {}) {
const schema = isSanitySchema(schemaType) ? sanitySchemaToPortableTextSchema(schemaType) : schemaType;
return htmlToPortableText(html, {
schema,
keyGenerator: options.keyGenerator,
parseHtml: options.parseHtml,
rules: options.rules,
whitespaceMode: options.unstable_whitespaceOnPasteMode,
types: adaptMatchers(options.matchers)
});
}
function adaptMatchers(matchers) {
if (!(!matchers?.image && !matchers?.inlineImage))
return {
image: ({ context, value, isInline }) => {
const matcher = isInline ? matchers.inlineImage : matchers.image;
if (!matcher)
return;
const result = matcher({ context, props: value });
if (result)
return result;
}
};
}
function isSanitySchema(schema) {
return schema.hasOwnProperty("jsonType");
}
export {
htmlToBlocks,
normalizeBlock,
randomKey
};
//# sourceMappingURL=index.js.map