154 lines
4.4 KiB
JavaScript
154 lines
4.4 KiB
JavaScript
"use client";
|
|
|
|
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
const require_A2UIProvider = require('./react-renderer/core/A2UIProvider.cjs');
|
|
const require_A2UIRenderer = require('./react-renderer/core/A2UIRenderer.cjs');
|
|
const require_defaultCatalog = require('./react-renderer/registry/defaultCatalog.cjs');
|
|
const require_index = require('./react-renderer/styles/index.cjs');
|
|
const require_viewer_theme = require('./theme/viewer-theme.cjs');
|
|
let react = require("react");
|
|
react = require_runtime.__toESM(react);
|
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
|
|
//#region src/A2UIViewer.tsx
|
|
let initialized = false;
|
|
function ensureInitialized() {
|
|
if (!initialized) {
|
|
require_defaultCatalog.initializeDefaultCatalog();
|
|
require_index.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 = (0, react.useId)();
|
|
const surfaceId = (0, react.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 = (0, react.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__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
className,
|
|
style: {
|
|
padding: 16,
|
|
color: "#666",
|
|
fontFamily: "system-ui"
|
|
},
|
|
children: "No content to display"
|
|
});
|
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_A2UIProvider.A2UIProvider, {
|
|
onAction: handleAction,
|
|
theme: require_viewer_theme.theme,
|
|
children: /* @__PURE__ */ (0, react_jsx_runtime.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 } = require_A2UIProvider.useA2UIActions();
|
|
const lastProcessedRef = (0, react.useRef)("");
|
|
(0, react.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__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
className,
|
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_A2UIRenderer.default, { 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
|
|
exports.A2UIViewer = A2UIViewer;
|
|
//# sourceMappingURL=A2UIViewer.cjs.map
|