rdesign/frontend/node_modules/@copilotkit/a2ui-renderer/dist/A2UIViewer.mjs

152 lines
3.9 KiB
JavaScript

"use client";
import { A2UIProvider, useA2UIActions } from "./react-renderer/core/A2UIProvider.mjs";
import A2UIRenderer from "./react-renderer/core/A2UIRenderer.mjs";
import { initializeDefaultCatalog } from "./react-renderer/registry/defaultCatalog.mjs";
import { injectStyles } from "./react-renderer/styles/index.mjs";
import { theme } from "./theme/viewer-theme.mjs";
import React, { useEffect, useId, useMemo, useRef } from "react";
import { jsx } from "react/jsx-runtime";
//#region src/A2UIViewer.tsx
let initialized = false;
function ensureInitialized() {
if (!initialized) {
initializeDefaultCatalog();
injectStyles();
initialized = true;
}
}
/**
* A2UIViewer renders an A2UI component tree from a JSON definition and data.
* It re-renders cleanly when props change, discarding previous state.
*/
function A2UIViewer({ root, components, data, onAction, styles, className }) {
ensureInitialized();
const baseId = useId();
const surfaceId = useMemo(() => {
const definitionKey = `${root}-${JSON.stringify(components)}`;
let hash = 0;
for (let i = 0; i < definitionKey.length; i++) {
const char = definitionKey.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash;
}
return `surface${baseId.replace(/:/g, "-")}${hash}`;
}, [
baseId,
root,
components
]);
const handleAction = useMemo(() => {
if (!onAction) return void 0;
return (message) => {
const userAction = message.userAction;
if (userAction) onAction({
actionName: userAction.name,
sourceComponentId: userAction.sourceComponentId,
timestamp: userAction.timestamp,
context: userAction.context ?? {}
});
};
}, [onAction]);
if (!components || components.length === 0) return /* @__PURE__ */ jsx("div", {
className,
style: {
padding: 16,
color: "#666",
fontFamily: "system-ui"
},
children: "No content to display"
});
return /* @__PURE__ */ jsx(A2UIProvider, {
onAction: handleAction,
theme,
children: /* @__PURE__ */ jsx(A2UIViewerInner, {
surfaceId,
root,
components,
data: data ?? {},
styles,
className
})
});
}
/**
* Inner component that processes messages within the provider context.
*/
function A2UIViewerInner({ surfaceId, root, components, data, styles, className }) {
const { processMessages } = useA2UIActions();
const lastProcessedRef = useRef("");
useEffect(() => {
const key = `${surfaceId}-${JSON.stringify(components)}-${JSON.stringify(data)}`;
if (key === lastProcessedRef.current) return;
lastProcessedRef.current = key;
const messages = [{ beginRendering: {
surfaceId,
root,
styles: styles ?? {}
} }, { surfaceUpdate: {
surfaceId,
components
} }];
if (data && Object.keys(data).length > 0) {
const contents = objectToValueMaps(data);
if (contents.length > 0) messages.push({ dataModelUpdate: {
surfaceId,
path: "/",
contents
} });
}
processMessages(messages);
}, [
processMessages,
surfaceId,
root,
components,
data,
styles
]);
return /* @__PURE__ */ jsx("div", {
className,
children: /* @__PURE__ */ jsx(A2UIRenderer, { surfaceId })
});
}
/**
* Converts a nested JavaScript object to the ValueMap[] format
* expected by A2UI's dataModelUpdate message.
*/
function objectToValueMaps(obj) {
return Object.entries(obj).map(([key, value]) => valueToValueMap(key, value));
}
/**
* Converts a single key-value pair to a ValueMap.
*/
function valueToValueMap(key, value) {
if (typeof value === "string") return {
key,
valueString: value
};
if (typeof value === "number") return {
key,
valueNumber: value
};
if (typeof value === "boolean") return {
key,
valueBoolean: value
};
if (value === null || value === void 0) return { key };
if (Array.isArray(value)) return {
key,
valueMap: value.map((item, index) => valueToValueMap(String(index), item))
};
if (typeof value === "object") return {
key,
valueMap: objectToValueMaps(value)
};
return { key };
}
//#endregion
export { A2UIViewer };
//# sourceMappingURL=A2UIViewer.mjs.map