UNPKG

@neo4j-ndl/react

Version:

React implementation of Neo4j Design System

210 lines 12.8 kB
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