{"version":3,"file":"A2uiSurface.mjs","names":[],"sources":["../../../src/react-renderer/a2ui-react/A2uiSurface.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, { useSyncExternalStore, memo, useMemo, useCallback } from \"react\";\nimport {\n  type SurfaceModel,\n  ComponentContext,\n  type ComponentModel,\n} from \"@a2ui/web_core/v0_9\";\nimport type { ReactComponentImplementation } from \"./adapter\";\n\nconst ResolvedChild = memo(\n  ({\n    surface,\n    id,\n    basePath,\n    compImpl,\n    componentModel,\n  }: {\n    surface: SurfaceModel<ReactComponentImplementation>;\n    id: string;\n    basePath: string;\n    componentModel: ComponentModel;\n    compImpl: ReactComponentImplementation;\n  }) => {\n    const ComponentToRender = compImpl.render;\n\n    // Create context. Recreate if the componentModel instance changes (e.g. type change recreation).\n    const context = useMemo(\n      () => new ComponentContext(surface, id, basePath),\n      // componentModel is used as a trigger for recreation even if not in the body\n      // eslint-disable-next-line react-hooks/exhaustive-deps\n      [surface, id, basePath, componentModel],\n    );\n\n    const buildChild = useCallback(\n      (childId: string, specificPath?: string) => {\n        const path = specificPath || context.dataContext.path;\n        return (\n          <DeferredChild\n            key={`${childId}-${path}`}\n            surface={surface}\n            id={childId}\n            basePath={path}\n          />\n        );\n      },\n      [surface, context.dataContext.path],\n    );\n\n    return <ComponentToRender context={context} buildChild={buildChild} />;\n  },\n);\nResolvedChild.displayName = \"ResolvedChild\";\n\nexport const DeferredChild: React.FC<{\n  surface: SurfaceModel<ReactComponentImplementation>;\n  id: string;\n  basePath: string;\n}> = memo(({ surface, id, basePath }) => {\n  // 1. Subscribe specifically to this component's existence\n  const store = useMemo(() => {\n    let version = 0;\n    return {\n      subscribe: (cb: () => void) => {\n        const unsub1 = surface.componentsModel.onCreated.subscribe((comp) => {\n          if (comp.id === id) {\n            version++;\n            cb();\n          }\n        });\n        const unsub2 = surface.componentsModel.onDeleted.subscribe((delId) => {\n          if (delId === id) {\n            version++;\n            cb();\n          }\n        });\n        return () => {\n          unsub1.unsubscribe();\n          unsub2.unsubscribe();\n        };\n      },\n      getSnapshot: () => {\n        const comp = surface.componentsModel.get(id);\n        // We use instance identity + version as the snapshot to ensure\n        // type replacements (e.g. Button -> Text) trigger a re-render.\n        return comp ? `${comp.type}-${version}` : `missing-${version}`;\n      },\n    };\n  }, [surface, id]);\n\n  useSyncExternalStore(store.subscribe, store.getSnapshot);\n\n  const componentModel = surface.componentsModel.get(id);\n\n  if (!componentModel) {\n    return (\n      <div\n        style={{\n          padding: \"12px 16px\",\n          borderRadius: \"8px\",\n          background:\n            \"linear-gradient(90deg, #f3f4f6 25%, #e5e7eb 50%, #f3f4f6 75%)\",\n          backgroundSize: \"200% 100%\",\n          animation: \"a2ui-shimmer 1.5s ease-in-out infinite\",\n          minHeight: \"2rem\",\n        }}\n      >\n        <style>{`@keyframes a2ui-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }`}</style>\n      </div>\n    );\n  }\n\n  const compImpl = surface.catalog.components.get(componentModel.type);\n\n  if (!compImpl) {\n    return (\n      <div style={{ color: \"red\" }}>\n        Unknown component: {componentModel.type}\n      </div>\n    );\n  }\n\n  return (\n    <ResolvedChild\n      surface={surface}\n      id={id}\n      basePath={basePath}\n      componentModel={componentModel}\n      compImpl={compImpl}\n    />\n  );\n});\nDeferredChild.displayName = \"DeferredChild\";\n\nexport const A2uiSurface: React.FC<{\n  surface: SurfaceModel<ReactComponentImplementation>;\n}> = ({ surface }) => {\n  // The root component always has ID 'root' and base path '/'\n  return <DeferredChild surface={surface} id=\"root\" basePath=\"/\" />;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAwBA,MAAM,gBAAgB,MACnB,EACC,SACA,IACA,UACA,UACA,qBAOI;CACJ,MAAM,oBAAoB,SAAS;CAGnC,MAAM,UAAU,cACR,IAAI,iBAAiB,SAAS,IAAI,SAAS,EAGjD;EAAC;EAAS;EAAI;EAAU;EAAe,CACxC;AAiBD,QAAO,oBAAC;EAA2B;EAAS,YAfzB,aAChB,SAAiB,iBAA0B;GAC1C,MAAM,OAAO,gBAAgB,QAAQ,YAAY;AACjD,UACE,oBAAC;IAEU;IACT,IAAI;IACJ,UAAU;MAHL,GAAG,QAAQ,GAAG,OAInB;KAGN,CAAC,SAAS,QAAQ,YAAY,KAAK,CACpC;GAEqE;EAEzE;AACD,cAAc,cAAc;AAE5B,MAAa,gBAIR,MAAM,EAAE,SAAS,IAAI,eAAe;CAEvC,MAAM,QAAQ,cAAc;EAC1B,IAAI,UAAU;AACd,SAAO;GACL,YAAY,OAAmB;IAC7B,MAAM,SAAS,QAAQ,gBAAgB,UAAU,WAAW,SAAS;AACnE,SAAI,KAAK,OAAO,IAAI;AAClB;AACA,UAAI;;MAEN;IACF,MAAM,SAAS,QAAQ,gBAAgB,UAAU,WAAW,UAAU;AACpE,SAAI,UAAU,IAAI;AAChB;AACA,UAAI;;MAEN;AACF,iBAAa;AACX,YAAO,aAAa;AACpB,YAAO,aAAa;;;GAGxB,mBAAmB;IACjB,MAAM,OAAO,QAAQ,gBAAgB,IAAI,GAAG;AAG5C,WAAO,OAAO,GAAG,KAAK,KAAK,GAAG,YAAY,WAAW;;GAExD;IACA,CAAC,SAAS,GAAG,CAAC;AAEjB,sBAAqB,MAAM,WAAW,MAAM,YAAY;CAExD,MAAM,iBAAiB,QAAQ,gBAAgB,IAAI,GAAG;AAEtD,KAAI,CAAC,eACH,QACE,oBAAC;EACC,OAAO;GACL,SAAS;GACT,cAAc;GACd,YACE;GACF,gBAAgB;GAChB,WAAW;GACX,WAAW;GACZ;YAED,oBAAC,qBAAO,2GAAiH;GACrH;CAIV,MAAM,WAAW,QAAQ,QAAQ,WAAW,IAAI,eAAe,KAAK;AAEpE,KAAI,CAAC,SACH,QACE,qBAAC;EAAI,OAAO,EAAE,OAAO,OAAO;aAAE,uBACR,eAAe;GAC/B;AAIV,QACE,oBAAC;EACU;EACL;EACM;EACM;EACN;GACV;EAEJ;AACF,cAAc,cAAc;AAE5B,MAAa,eAEP,EAAE,cAAc;AAEpB,QAAO,oBAAC;EAAuB;EAAS,IAAG;EAAO,UAAS;GAAM"}