# BottomSheet

A mobile bottom-sheet dialog with sheet or full-screen chrome, height presets, swipe-to-dismiss, and optional header and body slots.

Version: 0.2.0-preview.1 (preview)
Content digest: 70ac710f4d22dce040e7ac593379ba8aca9dcb59a0b9c0f839819cae0e2bb721
Contract kind: source-derived
Source: packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx

## Guidance

{
  "summary": "A mobile bottom-sheet dialog with sheet or full-screen chrome, height presets, swipe-to-dismiss, and optional header and body slots.",
  "guidance": [
    {
      "heading": "Overview",
      "body": "The mobile bottom-sheet dialog — the standard way to present focused, dismissible\ncontent over a screen. It renders through a portal, so keep `isOpen` in parent\nstate and close it from `onDismiss`."
    },
    {
      "heading": "Use when",
      "body": "`size` sets the sheet height. Pick it by how much content the sheet carries.\n\n`small`, `large`, `auto`, and `full` are all in use today; `medium` is available\nbut currently unused in the app."
    },
    {
      "heading": "Presentation",
      "body": "`presentation` defaults to `sheet` — rounded bottom-sheet chrome with an optional\ndrag handle and swipe-to-dismiss. Switch to `fullScreen` to fill the viewport\nedge-to-edge with no radius or handle, for immersive flows. A `fullScreen` sheet\nreaches the notch, and `BottomSheet.Header` is what holds its content clear of\nit — so give one a header even when the chrome is only a title."
    },
    {
      "heading": "Composition",
      "body": "The sheet is composed entirely from slots. `BottomSheet.Header` is the top\nchrome, `BottomSheet.Title` names the sheet from inside it, and\n`BottomSheet.Body` holds the content and owns its own scrolling.\n\n```tsx\n<BottomSheet isOpen={isOpen} onDismiss={close} size='large' testId='privacy-detail-sheet'>\n    <BottomSheet.Header onClose={close} testId='privacy-detail-sheet-header'>\n        <BottomSheet.Title>Privacy detail</BottomSheet.Title>\n        <Text variant='body-small' color='secondary'>\n            Updated today\n        </Text>\n    </BottomSheet.Header>\n    <BottomSheet.Body>\n        <Text variant='body' color='secondary' as='p'>\n            Composed slots keep titles, close actions, and body spacing consistent.\n        </Text>\n    </BottomSheet.Body>\n</BottomSheet>\n```\n\n`BottomSheet.Title` must be a direct child of `BottomSheet.Header`. A fragment\nbetween the two is fine; a wrapper element is not, and\n`@cloakedinc/bottom-sheet-slots` fails the lint if you reach for one. The reason\nis the `fullScreen` presentation: `.header` is the single element that carries\nthe sheet's top safe-area inset, and a title that could also sit topmost gives\nthat inset two possible owners — the padding bug this containment closes.\n\nThe title shares a row with the close button, and every other header child\nstacks below that row. It draws no divider of its own; if a rule between header\nand body is what the design calls for, place a `Divider` yourself.\n\n`variant='serif'` swaps the title to the display serif. The default is `sans`."
    },
    {
      "heading": "Accessible name",
      "body": "The title doubles as the sheet's accessible name, so most sheets need nothing\nfurther. A sheet with no title — a picker whose options speak for themselves —\ntakes `ariaLabel` instead. A slot is invisible to the compiler, so this is the\none requirement the types cannot enforce. `@cloakedinc/bottom-sheet-slots` fails\nthe lint on a sheet with neither, and a sheet whose title only appears at runtime\nlogs a dev-time error — pass `ariaLabel` there, since a Title that does mount\ntakes the name back."
    },
    {
      "heading": "Required decisions",
      "body": "`disableSwipeToDismiss` forces a deliberate choice — the sheet closes only via the\nbackdrop or an in-content action, not a swipe."
    }
  ],
  "usage": [
    {
      "variant": "small",
      "use": "Brief content — a short option list, a confirm, an info blurb. The most common size in the app.",
      "avoid": "Long or scrolling content that will feel cramped.",
      "axis": "Size"
    },
    {
      "variant": "medium",
      "use": "A moderate amount of content that needs more room than a small sheet.",
      "axis": "Size"
    },
    {
      "variant": "large",
      "use": "Taller content — a catalog, results, or a detail with several rows.",
      "axis": "Size"
    },
    {
      "variant": "full",
      "use": "Long or scrolling content that should still read as a bottom sheet; reaches the sheet max-height, stopping below the status bar.",
      "axis": "Size"
    },
    {
      "variant": "auto",
      "use": "Content whose height you want the sheet to hug exactly, capped at the sheet max-height.",
      "avoid": "Content whose height varies enough that a fixed preset reads more predictably.",
      "axis": "Size"
    }
  ],
  "examples": [],
  "source": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.mdx",
  "status": "local-preview",
  "note": "Guidance is read from local documentation, originally imported from the frozen source. Platform assertions in guidance are not parity verification."
}

## Contract and public API

```json
{
  "props": [
    {
      "name": "isOpen",
      "type": "boolean",
      "declared_type": "boolean",
      "required": true,
      "description": "Drives the sheet. Flipping to `false` starts the exit spring rather than unmounting — the\nsheet stays in the DOM until that motion settles.",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 45
      },
      "values": [
        false,
        true
      ],
      "values_complete": true
    },
    {
      "name": "onDismiss",
      "type": "() => void",
      "declared_type": "() => void",
      "required": true,
      "description": "Called when the user dismisses (backdrop tap, swipe, or escape).",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 47
      }
    },
    {
      "name": "size",
      "type": "BottomSheetSize",
      "declared_type": "BottomSheetSize",
      "required": true,
      "description": "Height preset — `small`/`medium`/`large` are fixed at 40/60/85vh, `full` at 100vh.",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 49
      },
      "values": [
        "auto",
        "full",
        "large",
        "medium",
        "small"
      ],
      "values_complete": true
    },
    {
      "name": "lowered",
      "type": "number | undefined",
      "declared_type": "number",
      "required": false,
      "description": "Slides the sheet down by this fraction of its own height (0–1) and fades the backdrop in step,\nwithout dismissing it.",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 54
      },
      "default": "0",
      "default_kind": "source-expression"
    },
    {
      "name": "scrimOpacity",
      "type": "number | undefined",
      "declared_type": "number",
      "required": false,
      "description": "Backdrop opacity while the sheet is at full height, clamped to 0-1.",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 56
      },
      "default": "1",
      "default_kind": "source-expression"
    },
    {
      "name": "presentation",
      "type": "BottomSheetPresentation | undefined",
      "declared_type": "BottomSheetPresentation",
      "required": false,
      "description": "Chrome treatment. `sheet` is rounded bottom-sheet chrome; `fullScreen` fills the viewport.",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 58
      },
      "values": [
        "fullScreen",
        "sheet"
      ],
      "values_complete": true,
      "default": "'sheet'",
      "default_kind": "source-expression"
    },
    {
      "name": "surface",
      "type": "\"page\" | \"surface\" | undefined",
      "declared_type": "CdsSurface",
      "required": false,
      "description": "Sheet surface token. Defaults to `surface`.",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 60
      },
      "values": [
        "page",
        "surface"
      ],
      "values_complete": true,
      "default": "'surface'",
      "default_kind": "source-expression"
    },
    {
      "name": "showDragHandle",
      "type": "boolean | undefined",
      "declared_type": "boolean",
      "required": false,
      "description": "Shows the drag handle. Defaults to `true`; it is also the only grab target for `swipeToDismissArea='handle'`.",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 62
      },
      "values": [
        false,
        true
      ],
      "values_complete": true,
      "default": "true",
      "default_kind": "source-expression"
    },
    {
      "name": "disableSwipeToDismiss",
      "type": "boolean | undefined",
      "declared_type": "boolean",
      "required": false,
      "description": "Turns off swipe-to-dismiss. Defaults to `false`; backdrop tap and Escape still dismiss.",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 64
      },
      "values": [
        false,
        true
      ],
      "values_complete": true,
      "default": "false",
      "default_kind": "source-expression"
    },
    {
      "name": "disableSwipeToDismissRef",
      "type": "React.RefObject<boolean> | undefined",
      "declared_type": "React.RefObject<boolean>",
      "required": false,
      "description": "Synchronous disable check (same tick) for nested swipe surfaces.",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 66
      }
    },
    {
      "name": "swipeToDismissArea",
      "type": "SwipeToDismissArea | undefined",
      "declared_type": "SwipeToDismissArea",
      "required": false,
      "description": "Region where a swipe-to-dismiss gesture can begin. Defaults to the whole sheet.",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 68
      },
      "values": [
        "chrome",
        "handle",
        "sheet"
      ],
      "values_complete": true,
      "default": "'sheet'",
      "default_kind": "source-expression"
    },
    {
      "name": "ariaLabel",
      "type": "string | undefined",
      "declared_type": "string",
      "required": false,
      "description": "Names the sheet when it has no `BottomSheet.Title`. A slot is invisible to the compiler, so\nunlike the old `title` prop this cannot be type-enforced — `@cloakedinc/bottom-sheet-slots`\nrejects a sheet with neither, and a dev-time check catches what lint cannot read statically.",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 74
      }
    },
    {
      "name": "portalTarget",
      "type": "HTMLElement | null | undefined",
      "declared_type": "HTMLElement | null",
      "required": false,
      "description": "Mount node for the portal. Defaults to `document.body`.",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 76
      }
    },
    {
      "name": "onBeforeDismiss",
      "type": "(() => void) | undefined",
      "declared_type": "() => void",
      "required": false,
      "description": "Fired right before dismissal completes — host hook for native effects (haptics).",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 78
      }
    },
    {
      "name": "onExited",
      "type": "(() => void) | undefined",
      "declared_type": "() => void",
      "required": false,
      "description": "Fired once the close animation fully settles and the sheet unmounts. Use this to sequence\npost-dismiss work (e.g. navigation) so it starts only after the sheet has visually left.",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 83
      }
    },
    {
      "name": "haptic",
      "type": "HapticFeedback | undefined",
      "declared_type": "HapticFeedback",
      "required": false,
      "description": "Haptic feedback for dismissal. Defaults to `true` (`light`).",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 85
      },
      "values": [
        "error",
        "heavy",
        "light",
        "medium",
        "selection",
        "success",
        "warning",
        false,
        true
      ],
      "values_complete": true,
      "default": "true",
      "default_kind": "source-expression"
    },
    {
      "name": "className",
      "type": "string | undefined",
      "declared_type": "string",
      "required": false,
      "description": "",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 86
      }
    },
    {
      "name": "style",
      "type": "React.CSSProperties | undefined",
      "declared_type": "React.CSSProperties",
      "required": false,
      "description": "",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 87
      }
    },
    {
      "name": "children",
      "type": "React.ReactNode",
      "declared_type": "React.ReactNode",
      "required": true,
      "description": "",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 88
      }
    },
    {
      "name": "testId",
      "type": "string | undefined",
      "declared_type": "string",
      "required": false,
      "description": "`data-testid` for the sheet; the backdrop gets `${testId}-overlay`.",
      "source": {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 90
      }
    },
    {
      "name": "padding",
      "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
      "declared_type": "CdsSpace",
      "required": false,
      "description": "Padding on all four sides.",
      "source": {
        "path": "packages/design-system/src/components/layout/resolvePadding.ts",
        "line": 10
      },
      "values": [
        0,
        12,
        120,
        16,
        20,
        24,
        240,
        32,
        4,
        40,
        48,
        56,
        64,
        72,
        8,
        80,
        96
      ],
      "values_complete": true
    },
    {
      "name": "paddingX",
      "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
      "declared_type": "CdsSpace",
      "required": false,
      "description": "Horizontal padding (left + right). Overrides `padding` on the X axis.",
      "source": {
        "path": "packages/design-system/src/components/layout/resolvePadding.ts",
        "line": 12
      },
      "values": [
        0,
        12,
        120,
        16,
        20,
        24,
        240,
        32,
        4,
        40,
        48,
        56,
        64,
        72,
        8,
        80,
        96
      ],
      "values_complete": true
    },
    {
      "name": "paddingY",
      "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
      "declared_type": "CdsSpace",
      "required": false,
      "description": "Vertical padding (top + bottom). Overrides `padding` on the Y axis.",
      "source": {
        "path": "packages/design-system/src/components/layout/resolvePadding.ts",
        "line": 14
      },
      "values": [
        0,
        12,
        120,
        16,
        20,
        24,
        240,
        32,
        4,
        40,
        48,
        56,
        64,
        72,
        8,
        80,
        96
      ],
      "values_complete": true
    },
    {
      "name": "paddingTop",
      "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
      "declared_type": "CdsSpace",
      "required": false,
      "description": "Top padding. Overrides `paddingY` and `padding`.",
      "source": {
        "path": "packages/design-system/src/components/layout/resolvePadding.ts",
        "line": 16
      },
      "values": [
        0,
        12,
        120,
        16,
        20,
        24,
        240,
        32,
        4,
        40,
        48,
        56,
        64,
        72,
        8,
        80,
        96
      ],
      "values_complete": true
    },
    {
      "name": "paddingRight",
      "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
      "declared_type": "CdsSpace",
      "required": false,
      "description": "Right padding. Overrides `paddingX` and `padding`.",
      "source": {
        "path": "packages/design-system/src/components/layout/resolvePadding.ts",
        "line": 18
      },
      "values": [
        0,
        12,
        120,
        16,
        20,
        24,
        240,
        32,
        4,
        40,
        48,
        56,
        64,
        72,
        8,
        80,
        96
      ],
      "values_complete": true
    },
    {
      "name": "paddingBottom",
      "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
      "declared_type": "CdsSpace",
      "required": false,
      "description": "Bottom padding. Overrides `paddingY` and `padding`.",
      "source": {
        "path": "packages/design-system/src/components/layout/resolvePadding.ts",
        "line": 20
      },
      "values": [
        0,
        12,
        120,
        16,
        20,
        24,
        240,
        32,
        4,
        40,
        48,
        56,
        64,
        72,
        8,
        80,
        96
      ],
      "values_complete": true
    },
    {
      "name": "paddingLeft",
      "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
      "declared_type": "CdsSpace",
      "required": false,
      "description": "Left padding. Overrides `paddingX` and `padding`.",
      "source": {
        "path": "packages/design-system/src/components/layout/resolvePadding.ts",
        "line": 22
      },
      "values": [
        0,
        12,
        120,
        16,
        20,
        24,
        240,
        32,
        4,
        40,
        48,
        56,
        64,
        72,
        8,
        80,
        96
      ],
      "values_complete": true
    }
  ],
  "prop_shapes": {},
  "api": {
    "method": "typescript-type-checker",
    "typescript_version": "5.9.3",
    "public_export": "BottomSheet",
    "public_path": "BottomSheet",
    "import_path": "@cloakedinc/design-system",
    "root_kind": "component",
    "entrypoints": [
      {
        "name": "BottomSheet",
        "signature": 1,
        "visibility": "public",
        "source": {
          "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
          "line": 104
        },
        "props_type": "BottomSheetBaseProps",
        "props": [
          {
            "name": "isOpen",
            "type": "boolean",
            "declared_type": "boolean",
            "required": true,
            "description": "Drives the sheet. Flipping to `false` starts the exit spring rather than unmounting — the\nsheet stays in the DOM until that motion settles.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 45
            },
            "values": [
              false,
              true
            ],
            "values_complete": true
          },
          {
            "name": "onDismiss",
            "type": "() => void",
            "declared_type": "() => void",
            "required": true,
            "description": "Called when the user dismisses (backdrop tap, swipe, or escape).",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 47
            }
          },
          {
            "name": "size",
            "type": "BottomSheetSize",
            "declared_type": "BottomSheetSize",
            "required": true,
            "description": "Height preset — `small`/`medium`/`large` are fixed at 40/60/85vh, `full` at 100vh.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 49
            },
            "values": [
              "auto",
              "full",
              "large",
              "medium",
              "small"
            ],
            "values_complete": true
          },
          {
            "name": "lowered",
            "type": "number | undefined",
            "declared_type": "number",
            "required": false,
            "description": "Slides the sheet down by this fraction of its own height (0–1) and fades the backdrop in step,\nwithout dismissing it.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 54
            },
            "default": "0",
            "default_kind": "source-expression"
          },
          {
            "name": "scrimOpacity",
            "type": "number | undefined",
            "declared_type": "number",
            "required": false,
            "description": "Backdrop opacity while the sheet is at full height, clamped to 0-1.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 56
            },
            "default": "1",
            "default_kind": "source-expression"
          },
          {
            "name": "presentation",
            "type": "BottomSheetPresentation | undefined",
            "declared_type": "BottomSheetPresentation",
            "required": false,
            "description": "Chrome treatment. `sheet` is rounded bottom-sheet chrome; `fullScreen` fills the viewport.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 58
            },
            "values": [
              "fullScreen",
              "sheet"
            ],
            "values_complete": true,
            "default": "'sheet'",
            "default_kind": "source-expression"
          },
          {
            "name": "surface",
            "type": "\"page\" | \"surface\" | undefined",
            "declared_type": "CdsSurface",
            "required": false,
            "description": "Sheet surface token. Defaults to `surface`.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 60
            },
            "values": [
              "page",
              "surface"
            ],
            "values_complete": true,
            "default": "'surface'",
            "default_kind": "source-expression"
          },
          {
            "name": "showDragHandle",
            "type": "boolean | undefined",
            "declared_type": "boolean",
            "required": false,
            "description": "Shows the drag handle. Defaults to `true`; it is also the only grab target for `swipeToDismissArea='handle'`.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 62
            },
            "values": [
              false,
              true
            ],
            "values_complete": true,
            "default": "true",
            "default_kind": "source-expression"
          },
          {
            "name": "disableSwipeToDismiss",
            "type": "boolean | undefined",
            "declared_type": "boolean",
            "required": false,
            "description": "Turns off swipe-to-dismiss. Defaults to `false`; backdrop tap and Escape still dismiss.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 64
            },
            "values": [
              false,
              true
            ],
            "values_complete": true,
            "default": "false",
            "default_kind": "source-expression"
          },
          {
            "name": "disableSwipeToDismissRef",
            "type": "React.RefObject<boolean> | undefined",
            "declared_type": "React.RefObject<boolean>",
            "required": false,
            "description": "Synchronous disable check (same tick) for nested swipe surfaces.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 66
            }
          },
          {
            "name": "swipeToDismissArea",
            "type": "SwipeToDismissArea | undefined",
            "declared_type": "SwipeToDismissArea",
            "required": false,
            "description": "Region where a swipe-to-dismiss gesture can begin. Defaults to the whole sheet.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 68
            },
            "values": [
              "chrome",
              "handle",
              "sheet"
            ],
            "values_complete": true,
            "default": "'sheet'",
            "default_kind": "source-expression"
          },
          {
            "name": "ariaLabel",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "Names the sheet when it has no `BottomSheet.Title`. A slot is invisible to the compiler, so\nunlike the old `title` prop this cannot be type-enforced — `@cloakedinc/bottom-sheet-slots`\nrejects a sheet with neither, and a dev-time check catches what lint cannot read statically.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 74
            }
          },
          {
            "name": "portalTarget",
            "type": "HTMLElement | null | undefined",
            "declared_type": "HTMLElement | null",
            "required": false,
            "description": "Mount node for the portal. Defaults to `document.body`.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 76
            }
          },
          {
            "name": "onBeforeDismiss",
            "type": "(() => void) | undefined",
            "declared_type": "() => void",
            "required": false,
            "description": "Fired right before dismissal completes — host hook for native effects (haptics).",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 78
            }
          },
          {
            "name": "onExited",
            "type": "(() => void) | undefined",
            "declared_type": "() => void",
            "required": false,
            "description": "Fired once the close animation fully settles and the sheet unmounts. Use this to sequence\npost-dismiss work (e.g. navigation) so it starts only after the sheet has visually left.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 83
            }
          },
          {
            "name": "haptic",
            "type": "HapticFeedback | undefined",
            "declared_type": "HapticFeedback",
            "required": false,
            "description": "Haptic feedback for dismissal. Defaults to `true` (`light`).",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 85
            },
            "values": [
              "error",
              "heavy",
              "light",
              "medium",
              "selection",
              "success",
              "warning",
              false,
              true
            ],
            "values_complete": true,
            "default": "true",
            "default_kind": "source-expression"
          },
          {
            "name": "className",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 86
            }
          },
          {
            "name": "style",
            "type": "React.CSSProperties | undefined",
            "declared_type": "React.CSSProperties",
            "required": false,
            "description": "",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 87
            }
          },
          {
            "name": "children",
            "type": "React.ReactNode",
            "declared_type": "React.ReactNode",
            "required": true,
            "description": "",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 88
            }
          },
          {
            "name": "testId",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "`data-testid` for the sheet; the backdrop gets `${testId}-overlay`.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
              "line": 90
            }
          },
          {
            "name": "padding",
            "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
            "declared_type": "CdsSpace",
            "required": false,
            "description": "Padding on all four sides.",
            "source": {
              "path": "packages/design-system/src/components/layout/resolvePadding.ts",
              "line": 10
            },
            "values": [
              0,
              12,
              120,
              16,
              20,
              24,
              240,
              32,
              4,
              40,
              48,
              56,
              64,
              72,
              8,
              80,
              96
            ],
            "values_complete": true
          },
          {
            "name": "paddingX",
            "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
            "declared_type": "CdsSpace",
            "required": false,
            "description": "Horizontal padding (left + right). Overrides `padding` on the X axis.",
            "source": {
              "path": "packages/design-system/src/components/layout/resolvePadding.ts",
              "line": 12
            },
            "values": [
              0,
              12,
              120,
              16,
              20,
              24,
              240,
              32,
              4,
              40,
              48,
              56,
              64,
              72,
              8,
              80,
              96
            ],
            "values_complete": true
          },
          {
            "name": "paddingY",
            "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
            "declared_type": "CdsSpace",
            "required": false,
            "description": "Vertical padding (top + bottom). Overrides `padding` on the Y axis.",
            "source": {
              "path": "packages/design-system/src/components/layout/resolvePadding.ts",
              "line": 14
            },
            "values": [
              0,
              12,
              120,
              16,
              20,
              24,
              240,
              32,
              4,
              40,
              48,
              56,
              64,
              72,
              8,
              80,
              96
            ],
            "values_complete": true
          },
          {
            "name": "paddingTop",
            "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
            "declared_type": "CdsSpace",
            "required": false,
            "description": "Top padding. Overrides `paddingY` and `padding`.",
            "source": {
              "path": "packages/design-system/src/components/layout/resolvePadding.ts",
              "line": 16
            },
            "values": [
              0,
              12,
              120,
              16,
              20,
              24,
              240,
              32,
              4,
              40,
              48,
              56,
              64,
              72,
              8,
              80,
              96
            ],
            "values_complete": true
          },
          {
            "name": "paddingRight",
            "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
            "declared_type": "CdsSpace",
            "required": false,
            "description": "Right padding. Overrides `paddingX` and `padding`.",
            "source": {
              "path": "packages/design-system/src/components/layout/resolvePadding.ts",
              "line": 18
            },
            "values": [
              0,
              12,
              120,
              16,
              20,
              24,
              240,
              32,
              4,
              40,
              48,
              56,
              64,
              72,
              8,
              80,
              96
            ],
            "values_complete": true
          },
          {
            "name": "paddingBottom",
            "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
            "declared_type": "CdsSpace",
            "required": false,
            "description": "Bottom padding. Overrides `paddingY` and `padding`.",
            "source": {
              "path": "packages/design-system/src/components/layout/resolvePadding.ts",
              "line": 20
            },
            "values": [
              0,
              12,
              120,
              16,
              20,
              24,
              240,
              32,
              4,
              40,
              48,
              56,
              64,
              72,
              8,
              80,
              96
            ],
            "values_complete": true
          },
          {
            "name": "paddingLeft",
            "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
            "declared_type": "CdsSpace",
            "required": false,
            "description": "Left padding. Overrides `paddingX` and `padding`.",
            "source": {
              "path": "packages/design-system/src/components/layout/resolvePadding.ts",
              "line": 22
            },
            "values": [
              0,
              12,
              120,
              16,
              20,
              24,
              240,
              32,
              4,
              40,
              48,
              56,
              64,
              72,
              8,
              80,
              96
            ],
            "values_complete": true
          }
        ],
        "branches": [],
        "constraints": [],
        "extraction_status": "extracted"
      },
      {
        "name": "BottomSheet.Header",
        "signature": 1,
        "visibility": "public",
        "source": {
          "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetHeader.tsx",
          "line": 30
        },
        "props_type": "BottomSheetHeaderProps",
        "props": [
          {
            "name": "onClose",
            "type": "(() => void) | undefined",
            "declared_type": "() => void",
            "required": false,
            "description": "Shows a close button when provided. Pressing it only fires this callback; actually closing\nthe sheet is the host's job.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetHeader.tsx",
              "line": 17
            }
          },
          {
            "name": "children",
            "type": "React.ReactNode",
            "declared_type": "React.ReactNode",
            "required": false,
            "description": "",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetHeader.tsx",
              "line": 18
            }
          },
          {
            "name": "className",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetHeader.tsx",
              "line": 19
            }
          },
          {
            "name": "style",
            "type": "React.CSSProperties | undefined",
            "declared_type": "React.CSSProperties",
            "required": false,
            "description": "",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetHeader.tsx",
              "line": 20
            }
          },
          {
            "name": "testId",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "`data-testid` for the header; the close button gets `${testId}-close`.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetHeader.tsx",
              "line": 22
            }
          }
        ],
        "branches": [],
        "constraints": [],
        "extraction_status": "extracted"
      },
      {
        "name": "BottomSheet.Title",
        "signature": 1,
        "visibility": "public",
        "source": {
          "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetTitle.tsx",
          "line": 24
        },
        "props_type": "BottomSheetTitleProps",
        "props": [
          {
            "name": "children",
            "type": "string",
            "declared_type": "string",
            "required": true,
            "description": "Doubles as the sheet's accessible name.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetTitle.tsx",
              "line": 13
            }
          },
          {
            "name": "variant",
            "type": "BottomSheetTitleVariant | undefined",
            "declared_type": "BottomSheetTitleVariant",
            "required": false,
            "description": "Type treatment. Defaults to `sans`.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetTitle.tsx",
              "line": 15
            },
            "values": [
              "sans",
              "serif"
            ],
            "values_complete": true,
            "default": "'sans'",
            "default_kind": "source-expression"
          },
          {
            "name": "testId",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "`data-testid` for the heading. Rarely needed — the title is not interactable.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetTitle.tsx",
              "line": 17
            }
          }
        ],
        "branches": [],
        "constraints": [],
        "extraction_status": "extracted"
      },
      {
        "name": "BottomSheet.Body",
        "signature": 1,
        "visibility": "public",
        "source": {
          "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetBody.tsx",
          "line": 28
        },
        "props_type": "BottomSheetBodyProps",
        "props": [
          {
            "name": "children",
            "type": "React.ReactNode",
            "declared_type": "React.ReactNode",
            "required": true,
            "description": "",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetBody.tsx",
              "line": 12
            }
          },
          {
            "name": "scroll",
            "type": "boolean | undefined",
            "declared_type": "boolean",
            "required": false,
            "description": "Scrolls within the slot, with overscroll contained so scrolling doesn't chain to ancestors.\nDefaults to `true`; `false` defers scrolling to the sheet's own content wrapper.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetBody.tsx",
              "line": 17
            },
            "values": [
              false,
              true
            ],
            "values_complete": true,
            "default": "true",
            "default_kind": "source-expression"
          },
          {
            "name": "className",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetBody.tsx",
              "line": 18
            }
          },
          {
            "name": "style",
            "type": "React.CSSProperties | undefined",
            "declared_type": "React.CSSProperties",
            "required": false,
            "description": "",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetBody.tsx",
              "line": 19
            }
          },
          {
            "name": "testId",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "`data-testid` for the slot element.",
            "source": {
              "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetBody.tsx",
              "line": 21
            }
          },
          {
            "name": "padding",
            "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
            "declared_type": "CdsSpace",
            "required": false,
            "description": "Padding on all four sides.",
            "source": {
              "path": "packages/design-system/src/components/layout/resolvePadding.ts",
              "line": 10
            },
            "values": [
              0,
              12,
              120,
              16,
              20,
              24,
              240,
              32,
              4,
              40,
              48,
              56,
              64,
              72,
              8,
              80,
              96
            ],
            "values_complete": true
          },
          {
            "name": "paddingX",
            "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
            "declared_type": "CdsSpace",
            "required": false,
            "description": "Horizontal padding (left + right). Overrides `padding` on the X axis.",
            "source": {
              "path": "packages/design-system/src/components/layout/resolvePadding.ts",
              "line": 12
            },
            "values": [
              0,
              12,
              120,
              16,
              20,
              24,
              240,
              32,
              4,
              40,
              48,
              56,
              64,
              72,
              8,
              80,
              96
            ],
            "values_complete": true
          },
          {
            "name": "paddingY",
            "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
            "declared_type": "CdsSpace",
            "required": false,
            "description": "Vertical padding (top + bottom). Overrides `padding` on the Y axis.",
            "source": {
              "path": "packages/design-system/src/components/layout/resolvePadding.ts",
              "line": 14
            },
            "values": [
              0,
              12,
              120,
              16,
              20,
              24,
              240,
              32,
              4,
              40,
              48,
              56,
              64,
              72,
              8,
              80,
              96
            ],
            "values_complete": true
          },
          {
            "name": "paddingTop",
            "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
            "declared_type": "CdsSpace",
            "required": false,
            "description": "Top padding. Overrides `paddingY` and `padding`.",
            "source": {
              "path": "packages/design-system/src/components/layout/resolvePadding.ts",
              "line": 16
            },
            "values": [
              0,
              12,
              120,
              16,
              20,
              24,
              240,
              32,
              4,
              40,
              48,
              56,
              64,
              72,
              8,
              80,
              96
            ],
            "values_complete": true
          },
          {
            "name": "paddingRight",
            "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
            "declared_type": "CdsSpace",
            "required": false,
            "description": "Right padding. Overrides `paddingX` and `padding`.",
            "source": {
              "path": "packages/design-system/src/components/layout/resolvePadding.ts",
              "line": 18
            },
            "values": [
              0,
              12,
              120,
              16,
              20,
              24,
              240,
              32,
              4,
              40,
              48,
              56,
              64,
              72,
              8,
              80,
              96
            ],
            "values_complete": true
          },
          {
            "name": "paddingBottom",
            "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
            "declared_type": "CdsSpace",
            "required": false,
            "description": "Bottom padding. Overrides `paddingY` and `padding`.",
            "source": {
              "path": "packages/design-system/src/components/layout/resolvePadding.ts",
              "line": 20
            },
            "values": [
              0,
              12,
              120,
              16,
              20,
              24,
              240,
              32,
              4,
              40,
              48,
              56,
              64,
              72,
              8,
              80,
              96
            ],
            "values_complete": true
          },
          {
            "name": "paddingLeft",
            "type": "0 | 4 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 96 | 120 | 240 | undefined",
            "declared_type": "CdsSpace",
            "required": false,
            "description": "Left padding. Overrides `paddingX` and `padding`.",
            "source": {
              "path": "packages/design-system/src/components/layout/resolvePadding.ts",
              "line": 22
            },
            "values": [
              0,
              12,
              120,
              16,
              20,
              24,
              240,
              32,
              4,
              40,
              48,
              56,
              64,
              72,
              8,
              80,
              96
            ],
            "values_complete": true
          }
        ],
        "branches": [],
        "constraints": [],
        "extraction_status": "extracted"
      }
    ],
    "type_sources": [
      {
        "path": "packages/design-system/src/components/layout/resolvePadding.ts",
        "line": 8,
        "name": "PaddingProps",
        "code": "export interface PaddingProps {\n    /** Padding on all four sides. */\n    padding?: CdsSpace;\n    /** Horizontal padding (left + right). Overrides `padding` on the X axis. */\n    paddingX?: CdsSpace;\n    /** Vertical padding (top + bottom). Overrides `padding` on the Y axis. */\n    paddingY?: CdsSpace;\n    /** Top padding. Overrides `paddingY` and `padding`. */\n    paddingTop?: CdsSpace;\n    /** Right padding. Overrides `paddingX` and `padding`. */\n    paddingRight?: CdsSpace;\n    /** Bottom padding. Overrides `paddingY` and `padding`. */\n    paddingBottom?: CdsSpace;\n    /** Left padding. Overrides `paddingX` and `padding`. */\n    paddingLeft?: CdsSpace;\n}"
      },
      {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 27,
        "name": "BottomSheetSize",
        "code": "export type BottomSheetSize = 'small' | 'medium' | 'large' | 'full' | 'auto';"
      },
      {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 29,
        "name": "BottomSheetPresentation",
        "code": "export type BottomSheetPresentation = 'sheet' | 'fullScreen';"
      },
      {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 40,
        "name": "BottomSheetBaseProps",
        "code": "interface BottomSheetBaseProps extends PaddingProps {\n    /**\n     * Drives the sheet. Flipping to `false` starts the exit spring rather than unmounting — the\n     * sheet stays in the DOM until that motion settles.\n     */\n    isOpen: boolean;\n    /** Called when the user dismisses (backdrop tap, swipe, or escape). */\n    onDismiss: () => void;\n    /** Height preset — `small`/`medium`/`large` are fixed at 40/60/85vh, `full` at 100vh. */\n    size: BottomSheetSize;\n    /**\n     * Slides the sheet down by this fraction of its own height (0–1) and fades the backdrop in step,\n     * without dismissing it.\n     */\n    lowered?: number;\n    /** Backdrop opacity while the sheet is at full height, clamped to 0-1. */\n    scrimOpacity?: number;\n    /** Chrome treatment. `sheet` is rounded bottom-sheet chrome; `fullScreen` fills the viewport. */\n    presentation?: BottomSheetPresentation;\n    /** Sheet surface token. Defaults to `surface`. */\n    surface?: CdsSurface;\n    /** Shows the drag handle. Defaults to `true`; it is also the only grab target for `swipeToDismissArea='handle'`. */\n    showDragHandle?: boolean;\n    /** Turns off swipe-to-dismiss. Defaults to `false`; backdrop tap and Escape still dismiss. */\n    disableSwipeToDismiss?: boolean;\n    /** Synchronous disable check (same tick) for nested swipe surfaces. */\n    disableSwipeToDismissRef?: React.RefObject<boolean>;\n    /** Region where a swipe-to-dismiss gesture can begin. Defaults to the whole sheet. */\n    swipeToDismissArea?: SwipeToDismissArea;\n    /**\n     * Names the sheet when it has no `BottomSheet.Title`. A slot is invisible to the compiler, so\n     * unlike the old `title` prop this cannot be type-enforced — `@cloakedinc/bottom-sheet-slots`\n     * rejects a sheet with neither, and a dev-time check catches what lint cannot read statically.\n     */\n    ariaLabel?: string;\n    /** Mount node for the portal. Defaults to `document.body`. */\n    portalTarget?: HTMLElement | null;\n    /** Fired right before dismissal completes — host hook for native effects (haptics). */\n    onBeforeDismiss?: () => void;\n    /**\n     * Fired once the close animation fully settles and the sheet unmounts. Use this to sequence\n     * post-dismiss work (e.g. navigation) so it starts only after the sheet has visually left.\n     */\n    onExited?: () => void;\n    /** Haptic feedback for dismissal. Defaults to `true` (`light`). */\n    haptic?: HapticFeedback;\n    className?: string;\n    style?: React.CSSProperties;\n    children: React.ReactNode;\n    /** `data-testid` for the sheet; the backdrop gets `${testId}-overlay`. */\n    testId?: string;\n}"
      },
      {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheet.tsx",
        "line": 96,
        "name": "BottomSheetProps",
        "code": "export type BottomSheetProps = BottomSheetBaseProps;"
      },
      {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetBody.tsx",
        "line": 11,
        "name": "BottomSheetBodyProps",
        "code": "export interface BottomSheetBodyProps extends PaddingProps {\n    children: React.ReactNode;\n    /**\n     * Scrolls within the slot, with overscroll contained so scrolling doesn't chain to ancestors.\n     * Defaults to `true`; `false` defers scrolling to the sheet's own content wrapper.\n     */\n    scroll?: boolean;\n    className?: string;\n    style?: React.CSSProperties;\n    /** `data-testid` for the slot element. */\n    testId?: string;\n}"
      },
      {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetHeader.tsx",
        "line": 12,
        "name": "BottomSheetHeaderProps",
        "code": "export interface BottomSheetHeaderProps {\n    /**\n     * Shows a close button when provided. Pressing it only fires this callback; actually closing\n     * the sheet is the host's job.\n     */\n    onClose?: () => void;\n    children?: React.ReactNode;\n    className?: string;\n    style?: React.CSSProperties;\n    /** `data-testid` for the header; the close button gets `${testId}-close`. */\n    testId?: string;\n}"
      },
      {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetTitle.tsx",
        "line": 6,
        "name": "BottomSheetTitleVariant",
        "code": "export type BottomSheetTitleVariant = 'sans' | 'serif';"
      },
      {
        "path": "packages/design-system/src/components/overlays/BottomSheet/BottomSheetTitle.tsx",
        "line": 11,
        "name": "BottomSheetTitleProps",
        "code": "export interface BottomSheetTitleProps {\n    /** Doubles as the sheet's accessible name. */\n    children: string;\n    /** Type treatment. Defaults to `sans`. */\n    variant?: BottomSheetTitleVariant;\n    /** `data-testid` for the heading. Rarely needed — the title is not interactable. */\n    testId?: string;\n}"
      },
      {
        "path": "packages/design-system/src/components/overlays/BottomSheet/hooks/useSwipeToDismiss.ts",
        "line": 19,
        "name": "SwipeToDismissArea",
        "code": "export type SwipeToDismissArea = 'sheet' | 'handle' | 'chrome';"
      },
      {
        "path": "packages/design-system/src/tokens/CdsHaptic.ts",
        "line": 6,
        "name": "HapticFeedback",
        "code": "export type HapticFeedback = boolean | HapticType;"
      },
      {
        "path": "packages/design-system/src/tokens/CdsSpace.ts",
        "line": 8,
        "name": "PUI_SPACES",
        "code": "PUI_SPACES = [0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 56, 64, 72, 80, 96, 120, 240] as const"
      },
      {
        "path": "packages/design-system/src/tokens/CdsSpace.ts",
        "line": 13,
        "name": "CdsSpace",
        "code": "export type CdsSpace = (typeof PUI_SPACES)[number];"
      },
      {
        "path": "packages/design-system/src/tokens/CdsSurface.ts",
        "line": 5,
        "name": "PUI_SURFACES",
        "code": "PUI_SURFACES = ['page', 'surface'] as const"
      },
      {
        "path": "packages/design-system/src/tokens/CdsSurface.ts",
        "line": 7,
        "name": "CdsSurface",
        "code": "export type CdsSurface = (typeof PUI_SURFACES)[number];"
      },
      {
        "path": "packages/design-system/src/tokens/HapticType.ts",
        "line": 2,
        "name": "HapticType",
        "code": "export type HapticType = 'light' | 'medium' | 'heavy' | 'success' | 'warning' | 'error' | 'selection';"
      }
    ],
    "defaults_policy": "Only explicit destructured parameter initializers are extracted. Other runtime defaults remain in implementation source."
  },
  "spec": {
    "$schema": "../../../specs/component-spec.schema.json",
    "identity": {
      "name": "BottomSheet",
      "status": "preview",
      "version": "1.3.0",
      "summary": "A mobile bottom-sheet dialog with sheet or full-screen chrome, height presets, swipe-to-dismiss, and optional header and body slots."
    },
    "parts": [
      {
        "id": "root",
        "label": "Root",
        "description": "The sheet surface presenting the dialog.",
        "required": true
      },
      {
        "id": "overlay",
        "label": "Overlay",
        "description": "Backdrop that dims and dismisses on tap."
      },
      {
        "id": "drag-handle",
        "label": "Drag handle",
        "description": "Optional grab affordance at the top of the sheet."
      },
      {
        "id": "content",
        "label": "Content",
        "description": "Scrollable content region."
      },
      {
        "id": "header",
        "label": "BottomSheet.Header",
        "description": "Top chrome slot: an optional BottomSheet.Title, an optional close button, and any content beneath them."
      },
      {
        "id": "title",
        "label": "BottomSheet.Title",
        "description": "Heading slot that names the sheet. Belongs inside BottomSheet.Header."
      },
      {
        "id": "body",
        "label": "BottomSheet.Body",
        "description": "Composed body slot with consistent spacing."
      }
    ],
    "allowedDesignChoices": {
      "variants": {
        "sheet": {
          "label": "Sheet",
          "description": "Rounded bottom-sheet chrome with an optional drag handle."
        },
        "full-screen": {
          "label": "Full screen",
          "description": "The fullScreen presentation fills the viewport with no radius."
        }
      },
      "sizes": {
        "small": {
          "label": "Small",
          "description": "40vh height preset."
        },
        "medium": {
          "label": "Medium",
          "description": "60vh height preset."
        },
        "large": {
          "label": "Large",
          "description": "85vh height preset."
        },
        "full": {
          "label": "Full",
          "description": "Fills the viewport height."
        },
        "auto": {
          "label": "Auto",
          "description": "Hugs content height, capped at the sheet max-height."
        }
      }
    },
    "variants": [
      {
        "id": "sheet",
        "label": "Sheet",
        "description": "Rounded bottom-sheet presentation.",
        "platforms": [
          "ios",
          "android",
          "web"
        ]
      },
      {
        "id": "full-screen",
        "label": "Full screen",
        "description": "Edge-to-edge fullScreen presentation.",
        "platforms": [
          "ios",
          "android",
          "web"
        ]
      }
    ],
    "sizes": [
      {
        "id": "small",
        "label": "Small",
        "description": "40vh sheet."
      },
      {
        "id": "medium",
        "label": "Medium",
        "description": "60vh sheet."
      },
      {
        "id": "large",
        "label": "Large",
        "description": "85vh sheet."
      },
      {
        "id": "full",
        "label": "Full",
        "description": "Full-viewport sheet."
      },
      {
        "id": "auto",
        "label": "Auto",
        "description": "Content-height sheet."
      }
    ],
    "measurements": [
      {
        "id": "sheet-padding-top",
        "label": "Sheet top inset",
        "kind": "exact",
        "token": "--cds-space-24",
        "value": 24,
        "unit": "px",
        "appliesTo": [
          "root"
        ]
      },
      {
        "id": "sheet-inline-inset",
        "label": "Content horizontal gutter",
        "kind": "exact",
        "token": "--cds-space-20",
        "value": 20,
        "unit": "px",
        "appliesTo": [
          "content"
        ],
        "notes": "Default gutter on the content region; padding props on the sheet override it, so paddingX={0} hosts edge-to-edge content. The built-in title keeps this inset either way."
      },
      {
        "id": "content-gap",
        "label": "Content gap",
        "kind": "exact",
        "token": "--cds-space-12",
        "value": 12,
        "unit": "px",
        "appliesTo": [
          "content"
        ]
      },
      {
        "id": "corner-radius",
        "label": "Sheet corner radius",
        "kind": "exact",
        "token": "--cds-radius-xl",
        "value": 24,
        "unit": "px",
        "appliesTo": [
          "root"
        ],
        "notes": "Top corners only; the sheet presentation rounds its top edge."
      }
    ],
    "layout": {
      "alignment": "The sheet anchors to the bottom edge and centers horizontally; content scrolls within it.",
      "flow": "A backdrop hosts the sheet, which stacks an optional drag handle, an optional header slot, and scrollable content.",
      "notes": [
        "Compose BottomSheet.Header with a BottomSheet.Title inside it; there is no title prop on the root.",
        "BottomSheet.Title must sit inside BottomSheet.Header. The header is the one element reserving the top safe-area inset, so a title that could also be topmost would need the inset in two places.",
        "The top safe-area inset is reserved only by the fullScreen presentation, which reads --cds-safe-area-top-chrome; a bottom-anchored sheet never reaches the notch.",
        "Padding props on the sheet set the content gutter and default to the 20px page inset; paddingX={0} lets a child run edge to edge.",
        "BottomSheet.Header keeps the 20px gutter whatever the padding props say, so paddingX={0} opens up the body without dragging the title to the screen edge."
      ]
    },
    "typographyAndColor": {
      "typography": [
        {
          "label": "Title",
          "description": "BottomSheet.Title uses the h4 ramp, or the h3-serif ramp with variant=\"serif\".",
          "token": "--cds-type-h4-size"
        }
      ],
      "colors": [
        {
          "label": "Surface",
          "description": "The sheet uses the raised surface by default.",
          "token": "--cds-bg-surface"
        },
        {
          "label": "Content text",
          "description": "Content uses primary text.",
          "token": "--cds-text-primary"
        }
      ]
    },
    "states": [
      {
        "id": "open",
        "label": "Open",
        "description": "Mounted and presented over the backdrop."
      },
      {
        "id": "dismissing",
        "label": "Dismissing",
        "description": "Sliding out after a dismiss gesture or backdrop tap."
      },
      {
        "id": "lowered",
        "label": "Lowered",
        "description": "Slid partway down with the scrim faded, revealing the screen behind without dismissing."
      },
      {
        "id": "swipe-locked",
        "label": "Swipe locked",
        "description": "Swipe-to-dismiss disabled for required decisions."
      }
    ],
    "behavior": [
      {
        "label": "Controlled open",
        "description": "Keep isOpen in parent state and close from onDismiss."
      },
      {
        "label": "Dismissal",
        "description": "Backdrop tap, swipe down, or Escape dismiss the sheet unless swipe is disabled."
      },
      {
        "label": "Lowering",
        "description": "A host can set lowered (0-1) to duck the sheet by that fraction of its height and bring it back; the scrim fades in step and the sheet stays mounted and controlled."
      },
      {
        "label": "Scrim opacity",
        "description": "scrimOpacity (0-1) caps how dark the backdrop may go, for a host that needs the screen behind the sheet readable while the sheet holds still. It composes with lowered by relief, not by multiplication: the scrim renders at whichever of the two asks for more, so a sheet that only ducks behaves exactly as it did before."
      }
    ],
    "accessibility": [
      {
        "label": "Dialog semantics",
        "description": "The sheet is role=dialog with aria-modal, named by its BottomSheet.Title when one is present and by ariaLabel otherwise. A slot is invisible to the compiler, so a sheet with neither is caught by a dev-time check rather than a type error."
      },
      {
        "label": "Focus management",
        "description": "Focus moves into the sheet once the entrance settles, and is restored to the launcher the moment a close becomes irreversible — a dismiss during the entrance cancels the pending move rather than pulling VoiceOver into a sheet that is already leaving. The sheet suppresses the focus outline: the runtime is touch-only, so a ring on its edge signals nothing."
      }
    ],
    "contentAdaptation": [
      {
        "label": "Height presets",
        "description": "size sets the sheet height; auto hugs content up to the max-height."
      },
      {
        "label": "Keyboard avoidance",
        "description": "The sheet insets its bottom padding when the keyboard is shown."
      },
      {
        "label": "Content gutter",
        "description": "The content region carries the page gutter by default. Pass paddingX={0} for edge-to-edge content such as a full-bleed list, and inset the sheet's own chrome instead."
      }
    ],
    "motionHaptics": {
      "motion": [
        {
          "label": "Slide and spring",
          "description": "The sheet slides up on open and spring-tracks the drag on dismiss."
        },
        {
          "label": "Lower and return",
          "description": "Lowering animates over 400ms with --cds-ease-in-out, on a separate property from the dismiss spring so the two never fight."
        }
      ],
      "haptics": [
        {
          "label": "Dismiss haptic",
          "description": "Dismissal requests a light haptic before it completes."
        }
      ]
    },
    "platformDifferences": [
      {
        "platforms": [
          "web"
        ],
        "description": "Web renders the sheet through a portal to document.body and supports Escape-to-dismiss for hardware keyboards.",
        "rationale": "The bottom-sheet interaction is the cross-platform product pattern; the portal and Escape support keep it usable in the web runtime."
      }
    ]
  },
  "platforms": {
    "implemented": [
      "web"
    ],
    "native": "Imported design guidance only; no native implementation or parity verification in this preview.",
    "react": {
      "implementation": "local",
      "status": "preview",
      "parity": "web-reference"
    },
    "vue": {
      "implementation": "absent",
      "parity": "not-verified",
      "status": "reference-only"
    },
    "swift": {
      "implementation": "absent",
      "parity": "not-verified",
      "status": "reference-only"
    },
    "kotlin": {
      "implementation": "absent",
      "parity": "not-verified",
      "status": "reference-only"
    }
  },
  "tokens": [
    {
      "name": "--cds-space-24",
      "light": "24px",
      "dark": "24px"
    },
    {
      "name": "--cds-space-20",
      "light": "20px",
      "dark": "20px"
    },
    {
      "name": "--cds-space-12",
      "light": "12px",
      "dark": "12px"
    },
    {
      "name": "--cds-radius-xl",
      "light": "24px",
      "dark": "24px"
    },
    {
      "name": "--cds-safe-area-top-chrome",
      "light": "0px",
      "dark": "0px"
    },
    {
      "name": "--cds-type-h4-size",
      "light": "1.25rem",
      "dark": "1.25rem"
    },
    {
      "name": "--cds-bg-surface",
      "light": "#ffffff",
      "dark": "#1b1b18"
    },
    {
      "name": "--cds-text-primary",
      "light": "#141410",
      "dark": "#f3f1ed"
    },
    {
      "name": "--cds-ease-in-out",
      "light": "cubic-bezier(0.77, 0, 0.175, 1)",
      "dark": "cubic-bezier(0.77, 0, 0.175, 1)"
    }
  ],
  "review": {
    "local_status": "not-reviewed",
    "source_approval": null,
    "imported_spec_status": "approved",
    "spec_origin": "imported-adapted",
    "local_spec_source_status": "approved",
    "imported_source_revision": "f96f416e1c3bfbfaffcd155a88b87b18b8bb25f1",
    "note": "Inherited specification status is provenance, not approval of the current local implementation or extracted contract."
  },
  "missing_facts": [
    {
      "code": "human-review-pending",
      "detail": "This local preview has no recorded human design or engineering sign-off."
    },
    {
      "code": "platform-parity-unverified",
      "detail": "Vue, Swift and Kotlin implementations are absent from this package; platform parity has not been verified."
    },
    {
      "code": "figma-mapping-unverified",
      "detail": "No current component-level Figma node and immutable revision have been verified for this contract."
    }
  ]
}
```

## Visual states

- [Playground](/storybook/iframe.html?id=cloaked-design-system-overlays-bottomsheet--playground&viewMode=story) | export: Playground | source: packages/design-system/src/components/overlays/BottomSheet/BottomSheet.stories.tsx

- [Size Matrix](/storybook/iframe.html?id=cloaked-design-system-overlays-bottomsheet--size-matrix&viewMode=story) | export: SizeMatrix | source: packages/design-system/src/components/overlays/BottomSheet/BottomSheet.stories.tsx

- [Small](/storybook/iframe.html?id=cloaked-design-system-overlays-bottomsheet--small&viewMode=story) | export: Small | source: packages/design-system/src/components/overlays/BottomSheet/BottomSheet.stories.tsx

- [Medium](/storybook/iframe.html?id=cloaked-design-system-overlays-bottomsheet--medium&viewMode=story) | export: Medium | source: packages/design-system/src/components/overlays/BottomSheet/BottomSheet.stories.tsx

- [Large](/storybook/iframe.html?id=cloaked-design-system-overlays-bottomsheet--large&viewMode=story) | export: Large | source: packages/design-system/src/components/overlays/BottomSheet/BottomSheet.stories.tsx

- [Full](/storybook/iframe.html?id=cloaked-design-system-overlays-bottomsheet--full&viewMode=story) | export: Full | source: packages/design-system/src/components/overlays/BottomSheet/BottomSheet.stories.tsx

- [Full Screen](/storybook/iframe.html?id=cloaked-design-system-overlays-bottomsheet--full-screen&viewMode=story) | export: FullScreen | source: packages/design-system/src/components/overlays/BottomSheet/BottomSheet.stories.tsx

- [Raised Surface](/storybook/iframe.html?id=cloaked-design-system-overlays-bottomsheet--raised-surface&viewMode=story) | export: RaisedSurface | source: packages/design-system/src/components/overlays/BottomSheet/BottomSheet.stories.tsx

- [Serif Header](/storybook/iframe.html?id=cloaked-design-system-overlays-bottomsheet--serif-header&viewMode=story) | export: SerifHeader | source: packages/design-system/src/components/overlays/BottomSheet/BottomSheet.stories.tsx

- [With Slots](/storybook/iframe.html?id=cloaked-design-system-overlays-bottomsheet--with-slots&viewMode=story) | export: WithSlots | source: packages/design-system/src/components/overlays/BottomSheet/BottomSheet.stories.tsx

- [Swipe Dismiss Disabled](/storybook/iframe.html?id=cloaked-design-system-overlays-bottomsheet--swipe-dismiss-disabled&viewMode=story) | export: SwipeDismissDisabled | source: packages/design-system/src/components/overlays/BottomSheet/BottomSheet.stories.tsx

- [Dark Theme](/storybook/iframe.html?id=cloaked-design-system-overlays-bottomsheet--dark-theme&viewMode=story) | export: DarkTheme | source: packages/design-system/src/components/overlays/BottomSheet/BottomSheet.stories.tsx

Preview pending human sign-off. Source-derived APIs and successful checks do not certify accessibility, native parity or approval.
