UNPKG

@activecollab/components

Version:

ActiveCollab Components

118 lines (114 loc) 5.37 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose"; const _excluded = ["content", "components", "space"]; import React, { Fragment, forwardRef, useMemo } from "react"; import { portableTextDefaultBlockRenderers, portableTextDefaultMarkRenderers } from "./renderers"; import { isPortableTextBlock, isPortableTextContent, isPortableTextObjectNode, isPortableTextSpan } from "./types"; import { Stack } from "../Stack"; const defaultUnknownTypeHandler = (kind, type) => { console.warn("PortableText: no renderer for " + kind + " type \"" + type + "\"."); }; /** * A span's marks wrap its text inside out. An unknown mark is reported and * skipped — the text stays, because dropping a word would break the sentence. */ const renderSpan = (span, ctx) => { var _span$marks; return ((_span$marks = span.marks) != null ? _span$marks : []).reduce((children, mark) => { var _ctx$components$marks, _ctx$components; const type = typeof mark === "string" ? mark : mark.type; const Renderer = (_ctx$components$marks = (_ctx$components = ctx.components) == null || (_ctx$components = _ctx$components.marks) == null ? void 0 : _ctx$components[type]) != null ? _ctx$components$marks : portableTextDefaultMarkRenderers[type]; if (!Renderer) { ctx.report("mark", type); return children; } return /*#__PURE__*/React.createElement(Renderer, { mark: typeof mark === "string" ? undefined : mark }, children); }, span.text); }; /** * Traversal is structural, so the walker keeps no list of block types of its * own: a `children` array holds spans or nested blocks, a nested `content` * holds a node list, and anything else has no children to render. */ const renderBlockChildren = (block, ctx) => { const _ref = block, children = _ref.children, content = _ref.content; if (Array.isArray(children)) { return children.map((child, index) => /*#__PURE__*/React.createElement(Fragment, { key: index }, isPortableTextSpan(child) ? renderSpan(child, ctx) : isPortableTextBlock(child) ? renderBlock(child, ctx) : null)); } return isPortableTextContent(content) ? renderNodes(content, ctx) : undefined; }; const renderBlock = (block, ctx) => { var _ctx$components$block, _ctx$components2; const type = block.type; const Renderer = (_ctx$components$block = (_ctx$components2 = ctx.components) == null || (_ctx$components2 = _ctx$components2.blocks) == null ? void 0 : _ctx$components2[type]) != null ? _ctx$components$block : portableTextDefaultBlockRenderers[type]; if (!Renderer) { ctx.report("block", block.type); return null; } // Blocks that carry spans outside `children` (table cells) render them // through this engine-bound helper, so mark injection works there too. const renderSpans = spans => spans.map((span, index) => /*#__PURE__*/React.createElement(Fragment, { key: index }, renderSpan(span, ctx))); return /*#__PURE__*/React.createElement(Renderer, { block: block, renderSpans: renderSpans }, renderBlockChildren(block, ctx)); }; const renderObject = (node, ctx) => { var _ctx$components3; const Renderer = (_ctx$components3 = ctx.components) == null || (_ctx$components3 = _ctx$components3.objects) == null ? void 0 : _ctx$components3[node._type]; if (!Renderer) { ctx.report("object", node._type); return null; } return /*#__PURE__*/React.createElement(Renderer, { node: node }, isPortableTextContent(node.content) ? renderNodes(node.content, ctx) : undefined); }; const renderNodes = (nodes, ctx) => nodes.map((node, index) => /*#__PURE__*/React.createElement(Fragment, { key: index }, isPortableTextObjectNode(node) ? renderObject(node, ctx) : renderBlock(node, ctx))); /** * The Portable Text engine: walks a {@link PortableTextContent} envelope and * renders it with the default renderers for the universal set, plus whatever * the application injects through `components`. The engine itself is hollow — * it knows no product element; an unknown block or object renders nothing and * is reported once per type through `onUnknownType` (console.warn when the * hook is absent). */ export const PortableText = /*#__PURE__*/forwardRef((_ref2, ref) => { let content = _ref2.content, components = _ref2.components, _ref2$space = _ref2.space, space = _ref2$space === void 0 ? "md" : _ref2$space, rest = _objectWithoutPropertiesLoose(_ref2, _excluded); // Memoized so unknown types are reported once per type for a given // content/components pair, not again on every parent re-render. const nodes = useMemo(() => { const reported = new Set(); const report = (kind, type) => { var _components$onUnknown; const key = kind + ":" + type; if (reported.has(key)) return; reported.add(key); ((_components$onUnknown = components == null ? void 0 : components.onUnknownType) != null ? _components$onUnknown : defaultUnknownTypeHandler)(kind, type); }; return renderNodes(content, { components, report }); }, [content, components]); return /*#__PURE__*/React.createElement(Stack, _extends({ ref: ref, space: space }, rest), nodes); }); PortableText.displayName = "PortableText"; //# sourceMappingURL=PortableText.js.map