@copilotkit/a2ui-renderer
Version:
A2UI Renderer for CopilotKit - render A2UI surfaces in React applications
1 lines • 5.13 kB
Source Map (JSON)
{"version":3,"file":"adapter.mjs","names":[],"sources":["../../../src/react-renderer/a2ui-react/adapter.tsx"],"sourcesContent":["/**\n * Copyright 2026 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, {\n useRef,\n useSyncExternalStore,\n useCallback,\n memo,\n useEffect,\n} from \"react\";\nimport { type ComponentContext, GenericBinder } from \"@a2ui/web_core/v0_9\";\nimport type {\n ComponentApi,\n InferredComponentApiSchemaType,\n ResolveA2uiProps,\n} from \"@a2ui/web_core/v0_9\";\n\nexport interface ReactComponentImplementation extends ComponentApi {\n /** The framework-specific rendering wrapper. */\n render: React.FC<{\n context: ComponentContext;\n buildChild: (id: string, basePath?: string) => React.ReactNode;\n }>;\n}\n\nexport type ReactA2uiComponentProps<T> = {\n props: T;\n buildChild: (id: string, basePath?: string) => React.ReactNode;\n context: ComponentContext;\n};\n\n// --- Component Factories ---\n\n/**\n * Creates a React component implementation using the deep generic binder.\n */\nexport function createReactComponent<Api extends ComponentApi>(\n api: Api,\n RenderComponent: React.FC<\n ReactA2uiComponentProps<\n ResolveA2uiProps<InferredComponentApiSchemaType<Api>>\n >\n >,\n): ReactComponentImplementation {\n type Props = ResolveA2uiProps<InferredComponentApiSchemaType<Api>>;\n\n const MemoizedRender = memo(RenderComponent, (prev, next) => {\n if (prev.props !== next.props) return false;\n if (prev.context.componentModel.id !== next.context.componentModel.id)\n return false;\n if (prev.context.dataContext.path !== next.context.dataContext.path)\n return false;\n return true;\n });\n\n const ReactWrapper: React.FC<{\n context: ComponentContext;\n buildChild: (id: string, basePath?: string) => React.ReactNode;\n }> = ({ context, buildChild }) => {\n const bindingRef = useRef<GenericBinder<Props> | null>(null);\n\n // Create or recreate the binder if the context object changes.\n // DeferredChild memoizes `context`, so reference changes strictly correspond\n // to ComponentModel updates (like type changes) or Base Path adjustments.\n if (!bindingRef.current) {\n bindingRef.current = new GenericBinder<Props>(context, api.schema);\n } else if (\n (bindingRef.current as unknown as { context: ComponentContext })\n .context !== context\n ) {\n bindingRef.current.dispose();\n bindingRef.current = new GenericBinder<Props>(context, api.schema);\n }\n const binding = bindingRef.current;\n\n const subscribe = useCallback(\n (callback: () => void) => {\n const sub = binding.subscribe(callback);\n return () => sub.unsubscribe();\n },\n [binding],\n );\n\n const getSnapshot = useCallback(() => binding.snapshot, [binding]);\n const props = useSyncExternalStore(subscribe, getSnapshot);\n\n // Prevent DataModel subscription leaks on unmount\n useEffect(() => {\n return () => binding.dispose();\n }, [binding]);\n\n return (\n <MemoizedRender\n props={props || ({} as Props)}\n buildChild={buildChild}\n context={context}\n />\n );\n };\n\n return {\n name: api.name,\n schema: api.schema,\n render: ReactWrapper,\n };\n}\n\n/**\n * Creates a React component implementation that manages its own context bindings (no generic binder).\n */\nexport function createBinderlessComponent(\n api: ComponentApi,\n RenderComponent: React.FC<{\n context: ComponentContext;\n buildChild: (id: string, basePath?: string) => React.ReactNode;\n }>,\n): ReactComponentImplementation {\n return {\n name: api.name,\n schema: api.schema,\n render: RenderComponent,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAiDA,SAAgB,qBACd,KACA,iBAK8B;CAG9B,MAAM,iBAAiB,KAAK,kBAAkB,MAAM,SAAS;AAC3D,MAAI,KAAK,UAAU,KAAK,MAAO,QAAO;AACtC,MAAI,KAAK,QAAQ,eAAe,OAAO,KAAK,QAAQ,eAAe,GACjE,QAAO;AACT,MAAI,KAAK,QAAQ,YAAY,SAAS,KAAK,QAAQ,YAAY,KAC7D,QAAO;AACT,SAAO;GACP;CAEF,MAAM,gBAGA,EAAE,SAAS,iBAAiB;EAChC,MAAM,aAAa,OAAoC,KAAK;AAK5D,MAAI,CAAC,WAAW,QACd,YAAW,UAAU,IAAI,cAAqB,SAAS,IAAI,OAAO;WAEjE,WAAW,QACT,YAAY,SACf;AACA,cAAW,QAAQ,SAAS;AAC5B,cAAW,UAAU,IAAI,cAAqB,SAAS,IAAI,OAAO;;EAEpE,MAAM,UAAU,WAAW;EAW3B,MAAM,QAAQ,qBATI,aACf,aAAyB;GACxB,MAAM,MAAM,QAAQ,UAAU,SAAS;AACvC,gBAAa,IAAI,aAAa;KAEhC,CAAC,QAAQ,CACV,EAEmB,kBAAkB,QAAQ,UAAU,CAAC,QAAQ,CAAC,CACR;AAG1D,kBAAgB;AACd,gBAAa,QAAQ,SAAS;KAC7B,CAAC,QAAQ,CAAC;AAEb,SACE,oBAAC;GACC,OAAO,SAAU,EAAE;GACP;GACH;IACT;;AAIN,QAAO;EACL,MAAM,IAAI;EACV,QAAQ,IAAI;EACZ,QAAQ;EACT"}