| import CustomerGrid from "./customer-grid/CustomerGrid"; | |
| import { OverlayProvider } from "./customer-grid/OverlaySurface"; | |
| import { isStreamlitComponent } from "./customer-grid/hostBridge"; | |
| import Shell from "./shell/Shell"; | |
| // HOSTED = either Streamlit path (the component iframe, or the legacy injected | |
| // payload). There the surrounding app owns all chrome and this tree renders the | |
| // BARE grid, byte-for-byte the behavior the embed always had. Only the | |
| // standalone build gets the shell (wave 4, the strangler frame). Computed once | |
| // at module level, like useCustomerData's own mode constants — the host mode | |
| // cannot change within a page lifetime. | |
| // EXPORTED (EXIT wave 1): main.tsx needs the same answer to decide whether to | |
| // install the standalone event sink, and two copies of a mode predicate is how | |
| // the two halves of "standalone-only" end up disagreeing. | |
| export const HOSTED = | |
| isStreamlitComponent() || | |
| typeof (window as unknown as { __AIOS_GRID__?: unknown }).__AIOS_GRID__ !== "undefined"; | |
| export default function App() { | |
| if (HOSTED) { | |
| return ( | |
| <div style={{ width: "100%", height: "100%", overflow: "hidden" }}> | |
| <OverlayProvider> | |
| <CustomerGrid /> | |
| </OverlayProvider> | |
| </div> | |
| ); | |
| } | |
| return <Shell />; | |
| } | |