@neo4j-ndl/react
Version:
React implementation of Neo4j Design System
210 lines • 12.8 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { jsx as _jsx } from "react/jsx-runtime";
/**
*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Code, TextLink, Typography } from '@neo4j-ndl/react';
import classNames from 'classnames';
import { memo, useMemo, useRef } from 'react';
import { Streamdown } from 'streamdown';
import { Languages } from '../../code-block/code-languages';
import { CodePreview } from '../code-preview';
/**
* The component is used to display the response from an LLM.
* It handles markdown rendering and streaming.
*
* @alpha - Changes to this component may be breaking.
*/
const Response = memo((_a) => {
var { className, children, isAnimating = false, ref, style, htmlAttributes } = _a, restProps = __rest(_a, ["className", "children", "isAnimating", "ref", "style", "htmlAttributes"]);
// Use a ref to store the current markdown content so we can check for unclosed fences
// without recreating the components object on every render
const childrenRef = useRef(children);
childrenRef.current = children;
const components = useMemo(() => ({
// oxlint-disable-next-line no-unused-vars
ol: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx("ol", Object.assign({ className: className }, props, { children: children })));
},
// oxlint-disable-next-line no-unused-vars
ul: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx("ul", Object.assign({ className: classNames(className) }, props, { children: children })));
},
// oxlint-disable-next-line no-unused-vars
li: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx("li", Object.assign({ className: className }, props, { children: children })));
},
// oxlint-disable-next-line no-unused-vars
hr: (_a) => {
var { node, className } = _a, props = __rest(_a, ["node", "className"]);
return (_jsx("hr", Object.assign({ className: classNames(className) }, props)));
},
// oxlint-disable-next-line no-unused-vars
strong: (_a) => {
var { node, children, className, style } = _a, props = __rest(_a, ["node", "children", "className", "style"]);
return (_jsx(Typography, Object.assign({ as: "strong", variant: "body-medium", className: className, style: Object.assign(Object.assign({}, style), { fontWeight: 'bold' }) }, props, { children: children })));
},
// oxlint-disable-next-line no-unused-vars
em: (_a) => {
var { node, children, className, style } = _a, props = __rest(_a, ["node", "children", "className", "style"]);
return (_jsx(Typography, Object.assign({ as: "em", variant: "body-medium", className: className, style: Object.assign(Object.assign({}, style), { fontStyle: 'italic' }) }, props, { children: children })));
},
// oxlint-disable-next-line no-unused-vars
a: (_a) => {
var { node, children, className, href } = _a, props = __rest(_a, ["node", "children", "className", "href"]);
return (_jsx(TextLink, { type: "internal-underline", className: className, href: href, htmlAttributes: props, children: children }));
},
// oxlint-disable-next-line no-unused-vars
h1: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx(Typography, { as: "h1", variant: "display", className: className, htmlAttributes: Object.assign({}, props), children: children }));
},
// oxlint-disable-next-line no-unused-vars
h2: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx(Typography, { as: "h2", variant: "title-1", className: className, htmlAttributes: Object.assign({}, props), children: children }));
},
// oxlint-disable-next-line no-unused-vars
h3: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx(Typography, { as: "h3", variant: "title-2", className: className, htmlAttributes: Object.assign({}, props), children: children }));
},
// oxlint-disable-next-line no-unused-vars
h4: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx(Typography, { as: "h4", variant: "title-3", className: className, htmlAttributes: Object.assign({}, props), children: children }));
},
// oxlint-disable-next-line no-unused-vars
h5: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx(Typography, { as: "h5", variant: "title-4", className: className, htmlAttributes: Object.assign({}, props), children: children }));
},
// oxlint-disable-next-line no-unused-vars
h6: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx(Typography, { as: "h6", variant: "label", className: className, htmlAttributes: Object.assign({}, props), children: children }));
},
// oxlint-disable-next-line no-unused-vars
table: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx("div", { className: "ndl-ai-response-table-wrapper", children: _jsx("table", Object.assign({ className: className }, props, { children: children })) }));
},
// oxlint-disable-next-line no-unused-vars
thead: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx("thead", Object.assign({ className: className }, props, { children: children })));
},
// oxlint-disable-next-line no-unused-vars
tbody: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx("tbody", Object.assign({ className: className }, props, { children: children })));
},
// oxlint-disable-next-line no-unused-vars
tr: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx("tr", Object.assign({ className: className }, props, { children: children })));
},
// oxlint-disable-next-line no-unused-vars
th: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx("th", Object.assign({ className: className }, props, { children: children })));
},
// oxlint-disable-next-line no-unused-vars
td: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx("td", Object.assign({ className: className }, props, { children: children })));
},
// oxlint-disable-next-line no-unused-vars
blockquote: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx("blockquote", Object.assign({ className: classNames(className) }, props, { children: children })));
},
code: (_a) => {
var _b, _c, _d, _e;
var { node, className, key, children: codeChildren } = _a, props = __rest(_a, ["node", "className", "key", "children"]);
const isInline = ((_b = node === null || node === void 0 ? void 0 : node.position) === null || _b === void 0 ? void 0 : _b.start.line) === ((_c = node === null || node === void 0 ? void 0 : node.position) === null || _c === void 0 ? void 0 : _c.end.line);
const nodeClassNamesRaw = (_d = node === null || node === void 0 ? void 0 : node.properties) === null || _d === void 0 ? void 0 : _d.className;
const nodeClassNamesArray = [];
if (typeof nodeClassNamesRaw === 'string') {
nodeClassNamesArray.push.apply(nodeClassNamesArray, nodeClassNamesRaw.split(' '));
}
else if (Array.isArray(nodeClassNamesRaw)) {
nodeClassNamesArray.push.apply(nodeClassNamesArray, nodeClassNamesRaw);
}
let language = 'text';
const rawLanguage = nodeClassNamesArray.find((string) => string.startsWith('language-'));
if (rawLanguage !== undefined) {
language =
(_e = rawLanguage.replace('language-', '')) !== null && _e !== void 0 ? _e : 'text';
}
language = Languages.includes(language)
? language
: 'text';
if (isInline) {
return (_jsx(Code, { isRunnable: false, className: className, htmlAttributes: props, children: codeChildren }));
}
if (typeof codeChildren === 'string') {
// Check if code fences are balanced in the markdown
// If there are an odd number of fences, it means there's an unclosed code block
const fenceMatches = childrenRef.current.match(/```/g);
const fenceCount = fenceMatches ? fenceMatches.length : 0;
const hasUnclosedFence = fenceCount % 2 !== 0;
// Show loading state when there's an unclosed fence (code block is streaming)
const isCodeBlockLoading = hasUnclosedFence;
return (_jsx(CodePreview, { code: codeChildren, isLoading: isCodeBlockLoading, language: language, className: className, htmlAttributes: Object.assign({}, props) }, key));
}
else {
return _jsx("code", { className: className, children: codeChildren });
}
},
// oxlint-disable-next-line no-unused-vars
pre: (_a) => {
var { node, className, children } = _a, props = __rest(_a, ["node", "className", "children"]);
return (_jsx("pre", Object.assign({ className: className }, props, { children: children })));
},
// oxlint-disable-next-line no-unused-vars
p: (_a) => {
var { node, children, className } = _a, props = __rest(_a, ["node", "children", "className"]);
return (_jsx(Typography, Object.assign({ as: "p", variant: "body-medium", className: classNames(className) }, props, { children: children })));
},
// oxlint-disable-next-line no-unused-vars
img: (_a) => {
var { node, className, src, alt } = _a, props = __rest(_a, ["node", "className", "src", "alt"]);
return (_jsx("img", Object.assign({ className: classNames(className), src: src, alt: alt }, props)));
},
}), []);
return (_jsx("div", Object.assign({ ref: ref, style: style, className: classNames('ndl-ai-response', className) }, restProps, htmlAttributes, { children: _jsx(Streamdown, { isAnimating: isAnimating, parseIncompleteMarkdown: true, components: components, children: children }) })));
}, (prevProps, nextProps) => prevProps.children === nextProps.children);
Response.displayName = 'Response';
export { Response };
//# sourceMappingURL=Response.js.map