Structural patterns provide the foundational architecture that every extension uses to bootstrap, render surfaces, manage navigation, and handle loading states. Understanding these patterns ensures your extension integrates smoothly with the host application.

## Bootstrap — Entry Point

Set up your extension entry point in `src/index.tsx`. The `createExtension` factory
bootstraps the sandboxed runtime and registers all surfaces with the framework.

```tsx
import { createExtension } from '@stackable-labs/sdk-extension-react'
import { Header } from './surfaces/Header'
import { Content } from './surfaces/Content'
import { Footer } from './surfaces/Footer'

const Extension = () => (
  <>
    <Header />
    <Content />
    <Footer />
  </>
)

// NOTE: extensionId is optional — used when connected to a registered extension
createExtension(() => <Extension />, { extensionId: 'my-extension' })
```

## Surfaces — Declaring UI Slots

Each surface renders into a specific layout slot in the embedding application.
The `id` prop must match a target declared in your `manifest.json`.

### Header

```tsx
import { Surface, ui } from '@stackable-labs/sdk-extension-react'

export function Header() {
  return (
    <Surface id="slot.header">
      <ui.Text className="text-sm font-medium">Header content</ui.Text>
    </Surface>
  )
}
```

### Content

```tsx
import { Surface, ui } from '@stackable-labs/sdk-extension-react'

export function Content() {
  return (
    <Surface id="slot.content">
      <ui.Card>
        <ui.CardContent>
          <ui.Text>Extension content</ui.Text>
        </ui.CardContent>
      </ui.Card>
    </Surface>
  )
}
```

### Footer

```tsx
import { Surface, ui } from '@stackable-labs/sdk-extension-react'

export function Footer() {
  return (
    <Surface id="slot.footer">
      <ui.Text className="text-xs">Powered by My Extension</ui.Text>
    </Surface>
  )
}
```

### Footer Links

```tsx
import { Surface, ui } from '@stackable-labs/sdk-extension-react'

export function FooterLinks() {
  return (
    <Surface id="slot.footer-links">
      <ui.FooterLink href="https://example.com">My Extension</ui.FooterLink>
    </Surface>
  )
}
```

## Store — Cross-Surface State & Navigation

Extensions use `createStore` for shared state across surfaces. The store replaces
traditional URL routing — there are no URLs inside the sandbox. Use discriminated
unions for view state to get exhaustive type checking.

```tsx
import { createStore, useStore, Surface, ui } from '@stackable-labs/sdk-extension-react'

// store.ts
type ViewState = { type: 'list' } | { type: 'detail'; id: string }

interface AppState {
  viewState: ViewState
}

export const appStore = createStore<AppState>({
  viewState: { type: 'list' },
})

// Content.tsx
export function Content(): React.ReactElement {
  const viewState = useStore(appStore, (s) => s.viewState)

  const goToDetail = (id: string) => appStore.set({ viewState: { type: 'detail', id } })
  const goBack = () => appStore.set({ viewState: { type: 'list' } })

  return (
    <Surface id="slot.content">
      {(viewState.type === 'list') && (
        <ui.Button onClick={() => goToDetail('abc123')}>View Detail</ui.Button>
      )}
      {(viewState.type === 'detail') && (
        <ui.Stack direction="column" gap="2">
          <ui.Text>Viewing: {viewState.id}</ui.Text>
          <ui.Button onClick={goBack}>Back</ui.Button>
        </ui.Stack>
      )}
    </Surface>
  )
}
```

## Loading States & Guards

Handle loading states and missing context gracefully. Always show a skeleton
while context loads, and guard against missing data before rendering.

```tsx
import { useContextData, Surface, ui } from '@stackable-labs/sdk-extension-react'

export function Content(): React.ReactElement {
  const { loading, customerId } = useContextData()

  if (loading) {
    return (
      <Surface id="slot.content">
        <ui.Skeleton />
      </Surface>
    )
  }

  if (!customerId) {
    return (
      <Surface id="slot.content">
        <ui.Stack direction="column" gap="1" className="p-4 items-center">
          <ui.Icon name="user" size="sm" />
          <ui.Text className="text-xs text-muted-foreground">No customer selected</ui.Text>
        </ui.Stack>
      </Surface>
    )
  }

  return (
    <Surface id="slot.content">
      <ui.Text className="text-sm">Customer: {customerId}</ui.Text>
    </Surface>
  )
}
```

## Surface Context

Read host-pushed context for a specific surface using the lower-level
`useSurfaceContext` hook.

```tsx
import { useSurfaceContext, Surface, ui } from '@stackable-labs/sdk-extension-react'
import type { ContextData } from '@stackable-labs/sdk-extension-contracts'

export function Header(): React.ReactElement {
  // Lower-level hook — reads host-pushed context for this specific surface
  const context = useSurfaceContext() as ContextData

  return (
    <Surface id="slot.header">
      <ui.Text className="text-xs">{context.customerId ?? 'No customer'}</ui.Text>
    </Surface>
  )
}
```
