# Button

Make the next action clear with one primary button and quieter supporting actions.

Version: 0.2.0-preview.1 (preview)
Content digest: 70ac710f4d22dce040e7ac593379ba8aca9dcb59a0b9c0f839819cae0e2bb721
Contract kind: curated
Source: packages/design-system/src/components/primitives/Button/Button.tsx

## Guidance

{
  "summary": "Make the next action clear with one primary button and quieter supporting actions.",
  "when_to_use": [
    "Initiate an action that changes the current state.",
    "Show one primary action per view.",
    "Use danger tone when the action is destructive."
  ],
  "avoid": [
    "Using a button to navigate to another URL; use a link.",
    "Treating the link variant as an anchor.",
    "Disabling an action without explaining what is needed."
  ],
  "accessibility": [
    "Use a descriptive visible label, or ariaLabel for icon-only buttons.",
    "Loading preserves the label, sets aria-busy, and blocks duplicate presses.",
    "Keyboard focus is visible in both themes."
  ],
  "constraints": [
    "Text buttons use children and optional leading/trailing content.",
    "Icon-only buttons require icon and ariaLabel and cannot have children or leading/trailing.",
    "Always renders type=button. A form must explicitly request submission."
  ]
}

## Contract and public API

```json
{
  "props": [
    {
      "name": "variant",
      "type": "ButtonVariant",
      "required": true,
      "description": "Visual treatment by action hierarchy."
    },
    {
      "name": "tone",
      "type": "ButtonTone",
      "required": false,
      "description": "Semantic action tone, independent of hierarchy."
    },
    {
      "name": "size",
      "type": "ButtonSize",
      "required": true,
      "description": "Height and padding tier; icon-only buttons use their own square size for each tier."
    },
    {
      "name": "onPress",
      "type": "() => void",
      "required": false,
      "description": "Fires on tap. Omitted, the button renders inert without looking disabled."
    },
    {
      "name": "disabled",
      "type": "boolean",
      "required": false,
      "description": "Blocks presses and dims the button. Use `loading` when the block is an in-flight action."
    },
    {
      "name": "loading",
      "type": "boolean",
      "required": false,
      "description": "Shows the loading treatment and prevents interaction."
    },
    {
      "name": "fullWidth",
      "type": "boolean",
      "required": false,
      "description": "Stretches the button to the width of its parent."
    },
    {
      "name": "ariaLabel",
      "type": "string",
      "required": false,
      "description": "Accessible label for icon-only buttons."
    },
    {
      "name": "className",
      "type": "string",
      "required": false,
      "description": ""
    },
    {
      "name": "style",
      "type": "React.CSSProperties",
      "required": false,
      "description": ""
    },
    {
      "name": "haptic",
      "type": "HapticFeedback",
      "required": false,
      "description": "Haptic feedback for successful presses. Defaults to `true` (`light`)."
    },
    {
      "name": "testId",
      "type": "string",
      "required": false,
      "description": "Selector on the `<button>` itself; nothing inside derives from it."
    }
  ],
  "prop_shapes": {
    "text": [
      {
        "name": "children",
        "type": "React.ReactNode",
        "required": true,
        "description": ""
      },
      {
        "name": "leading",
        "type": "React.ReactNode",
        "required": false,
        "description": "Optional leading visual, usually an Icon."
      },
      {
        "name": "trailing",
        "type": "React.ReactNode",
        "required": false,
        "description": "Optional trailing visual, usually an Icon."
      },
      {
        "name": "icon",
        "type": "never",
        "required": false,
        "description": "Text buttons use leading/trailing slots instead of icon-only glyphs."
      }
    ],
    "icon": [
      {
        "name": "icon",
        "type": "React.ReactNode",
        "required": true,
        "description": "The button's only content; its presence is what selects this shape."
      },
      {
        "name": "ariaLabel",
        "type": "string",
        "required": true,
        "description": "Accessible label for the icon-only button."
      },
      {
        "name": "children",
        "type": "never",
        "required": false,
        "description": "Icon buttons do not render visible text."
      },
      {
        "name": "leading",
        "type": "never",
        "required": false,
        "description": "Icon-only buttons do not support a separate leading slot."
      },
      {
        "name": "trailing",
        "type": "never",
        "required": false,
        "description": "Icon-only buttons do not support a separate trailing slot."
      }
    ]
  },
  "api": {
    "method": "typescript-type-checker",
    "typescript_version": "5.9.3",
    "public_export": "Button",
    "public_path": "Button",
    "import_path": "@cloakedinc/design-system",
    "root_kind": "component",
    "entrypoints": [
      {
        "name": "Button",
        "signature": 1,
        "visibility": "public",
        "source": {
          "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
          "line": 80
        },
        "props_type": "ButtonProps",
        "props": [
          {
            "name": "children",
            "type": "React.ReactNode",
            "declared_type": "React.ReactNode",
            "required": false,
            "description": "Icon buttons do not render visible text.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 46
            }
          },
          {
            "name": "leading",
            "type": "React.ReactNode",
            "declared_type": "React.ReactNode",
            "required": false,
            "description": "Optional leading visual, usually an Icon.\nIcon-only buttons do not support a separate leading slot.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 48
            }
          },
          {
            "name": "trailing",
            "type": "React.ReactNode",
            "declared_type": "React.ReactNode",
            "required": false,
            "description": "Optional trailing visual, usually an Icon.\nIcon-only buttons do not support a separate trailing slot.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 50
            }
          },
          {
            "name": "icon",
            "type": "never",
            "declared_type": "never",
            "required": false,
            "description": "Text buttons use leading/trailing slots instead of icon-only glyphs.\nThe button's only content; its presence is what selects this shape.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 52
            },
            "forbidden": true
          },
          {
            "name": "variant",
            "type": "ButtonVariant",
            "declared_type": "ButtonVariant",
            "required": true,
            "description": "Visual treatment by action hierarchy.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 18
            },
            "values": [
              "link",
              "primary",
              "secondary",
              "tertiary"
            ],
            "values_complete": true
          },
          {
            "name": "tone",
            "type": "ButtonTone | undefined",
            "declared_type": "ButtonTone",
            "required": false,
            "description": "Semantic action tone, independent of hierarchy.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 20
            },
            "values": [
              "danger",
              "default"
            ],
            "values_complete": true,
            "default": "'default'",
            "default_kind": "source-expression"
          },
          {
            "name": "size",
            "type": "ButtonSize",
            "declared_type": "ButtonSize",
            "required": true,
            "description": "Height and padding tier; icon-only buttons use their own square size for each tier.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 22
            },
            "values": [
              "md",
              "sm"
            ],
            "values_complete": true
          },
          {
            "name": "onPress",
            "type": "(() => void) | undefined",
            "declared_type": "() => void",
            "required": false,
            "description": "Fires on tap. Omitted, the button renders inert without looking disabled.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 24
            }
          },
          {
            "name": "disabled",
            "type": "boolean | undefined",
            "declared_type": "boolean",
            "required": false,
            "description": "Blocks presses and dims the button. Use `loading` when the block is an in-flight action.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 26
            },
            "values": [
              false,
              true
            ],
            "values_complete": true
          },
          {
            "name": "loading",
            "type": "boolean | undefined",
            "declared_type": "boolean",
            "required": false,
            "description": "Shows the loading treatment and prevents interaction.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 28
            },
            "values": [
              false,
              true
            ],
            "values_complete": true
          },
          {
            "name": "fullWidth",
            "type": "boolean | undefined",
            "declared_type": "boolean",
            "required": false,
            "description": "Stretches the button to the width of its parent.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 30
            },
            "values": [
              false,
              true
            ],
            "values_complete": true
          },
          {
            "name": "ariaLabel",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "Accessible label for icon-only buttons.\nAccessible label for the icon-only button.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 32
            }
          },
          {
            "name": "className",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 33
            }
          },
          {
            "name": "style",
            "type": "React.CSSProperties | undefined",
            "declared_type": "React.CSSProperties",
            "required": false,
            "description": "",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 34
            }
          },
          {
            "name": "haptic",
            "type": "HapticFeedback | undefined",
            "declared_type": "HapticFeedback",
            "required": false,
            "description": "Haptic feedback for successful presses. Defaults to `true` (`light`).",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 36
            },
            "values": [
              "error",
              "heavy",
              "light",
              "medium",
              "selection",
              "success",
              "warning",
              false,
              true
            ],
            "values_complete": true,
            "default": "true",
            "default_kind": "source-expression"
          },
          {
            "name": "testId",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "Selector on the `<button>` itself; nothing inside derives from it.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 38
            }
          }
        ],
        "branches": [
          {
            "name": "TextButtonProps",
            "props": [
              {
                "name": "children",
                "type": "React.ReactNode",
                "declared_type": "React.ReactNode",
                "required": true,
                "description": "",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 46
                }
              },
              {
                "name": "leading",
                "type": "React.ReactNode",
                "declared_type": "React.ReactNode",
                "required": false,
                "description": "Optional leading visual, usually an Icon.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 48
                }
              },
              {
                "name": "trailing",
                "type": "React.ReactNode",
                "declared_type": "React.ReactNode",
                "required": false,
                "description": "Optional trailing visual, usually an Icon.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 50
                }
              },
              {
                "name": "icon",
                "type": "never",
                "declared_type": "never",
                "required": false,
                "description": "Text buttons use leading/trailing slots instead of icon-only glyphs.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 52
                },
                "forbidden": true
              },
              {
                "name": "variant",
                "type": "ButtonVariant",
                "declared_type": "ButtonVariant",
                "required": true,
                "description": "Visual treatment by action hierarchy.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 18
                },
                "values": [
                  "link",
                  "primary",
                  "secondary",
                  "tertiary"
                ],
                "values_complete": true
              },
              {
                "name": "tone",
                "type": "ButtonTone | undefined",
                "declared_type": "ButtonTone",
                "required": false,
                "description": "Semantic action tone, independent of hierarchy.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 20
                },
                "values": [
                  "danger",
                  "default"
                ],
                "values_complete": true,
                "default": "'default'",
                "default_kind": "source-expression"
              },
              {
                "name": "size",
                "type": "ButtonSize",
                "declared_type": "ButtonSize",
                "required": true,
                "description": "Height and padding tier; icon-only buttons use their own square size for each tier.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 22
                },
                "values": [
                  "md",
                  "sm"
                ],
                "values_complete": true
              },
              {
                "name": "onPress",
                "type": "(() => void) | undefined",
                "declared_type": "() => void",
                "required": false,
                "description": "Fires on tap. Omitted, the button renders inert without looking disabled.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 24
                }
              },
              {
                "name": "disabled",
                "type": "boolean | undefined",
                "declared_type": "boolean",
                "required": false,
                "description": "Blocks presses and dims the button. Use `loading` when the block is an in-flight action.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 26
                },
                "values": [
                  false,
                  true
                ],
                "values_complete": true
              },
              {
                "name": "loading",
                "type": "boolean | undefined",
                "declared_type": "boolean",
                "required": false,
                "description": "Shows the loading treatment and prevents interaction.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 28
                },
                "values": [
                  false,
                  true
                ],
                "values_complete": true
              },
              {
                "name": "fullWidth",
                "type": "boolean | undefined",
                "declared_type": "boolean",
                "required": false,
                "description": "Stretches the button to the width of its parent.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 30
                },
                "values": [
                  false,
                  true
                ],
                "values_complete": true
              },
              {
                "name": "ariaLabel",
                "type": "string | undefined",
                "declared_type": "string",
                "required": false,
                "description": "Accessible label for icon-only buttons.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 32
                }
              },
              {
                "name": "className",
                "type": "string | undefined",
                "declared_type": "string",
                "required": false,
                "description": "",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 33
                }
              },
              {
                "name": "style",
                "type": "React.CSSProperties | undefined",
                "declared_type": "React.CSSProperties",
                "required": false,
                "description": "",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 34
                }
              },
              {
                "name": "haptic",
                "type": "HapticFeedback | undefined",
                "declared_type": "HapticFeedback",
                "required": false,
                "description": "Haptic feedback for successful presses. Defaults to `true` (`light`).",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 36
                },
                "values": [
                  "error",
                  "heavy",
                  "light",
                  "medium",
                  "selection",
                  "success",
                  "warning",
                  false,
                  true
                ],
                "values_complete": true,
                "default": "true",
                "default_kind": "source-expression"
              },
              {
                "name": "testId",
                "type": "string | undefined",
                "declared_type": "string",
                "required": false,
                "description": "Selector on the `<button>` itself; nothing inside derives from it.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 38
                }
              }
            ]
          },
          {
            "name": "IconButtonProps",
            "props": [
              {
                "name": "icon",
                "type": "React.ReactNode",
                "declared_type": "React.ReactNode",
                "required": true,
                "description": "The button's only content; its presence is what selects this shape.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 60
                }
              },
              {
                "name": "ariaLabel",
                "type": "string",
                "declared_type": "string",
                "required": true,
                "description": "Accessible label for the icon-only button.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 62
                }
              },
              {
                "name": "children",
                "type": "never",
                "declared_type": "never",
                "required": false,
                "description": "Icon buttons do not render visible text.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 64
                },
                "forbidden": true
              },
              {
                "name": "leading",
                "type": "never",
                "declared_type": "never",
                "required": false,
                "description": "Icon-only buttons do not support a separate leading slot.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 66
                },
                "forbidden": true
              },
              {
                "name": "trailing",
                "type": "never",
                "declared_type": "never",
                "required": false,
                "description": "Icon-only buttons do not support a separate trailing slot.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 68
                },
                "forbidden": true
              },
              {
                "name": "variant",
                "type": "ButtonVariant",
                "declared_type": "ButtonVariant",
                "required": true,
                "description": "Visual treatment by action hierarchy.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 18
                },
                "values": [
                  "link",
                  "primary",
                  "secondary",
                  "tertiary"
                ],
                "values_complete": true
              },
              {
                "name": "tone",
                "type": "ButtonTone | undefined",
                "declared_type": "ButtonTone",
                "required": false,
                "description": "Semantic action tone, independent of hierarchy.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 20
                },
                "values": [
                  "danger",
                  "default"
                ],
                "values_complete": true,
                "default": "'default'",
                "default_kind": "source-expression"
              },
              {
                "name": "size",
                "type": "ButtonSize",
                "declared_type": "ButtonSize",
                "required": true,
                "description": "Height and padding tier; icon-only buttons use their own square size for each tier.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 22
                },
                "values": [
                  "md",
                  "sm"
                ],
                "values_complete": true
              },
              {
                "name": "onPress",
                "type": "(() => void) | undefined",
                "declared_type": "() => void",
                "required": false,
                "description": "Fires on tap. Omitted, the button renders inert without looking disabled.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 24
                }
              },
              {
                "name": "disabled",
                "type": "boolean | undefined",
                "declared_type": "boolean",
                "required": false,
                "description": "Blocks presses and dims the button. Use `loading` when the block is an in-flight action.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 26
                },
                "values": [
                  false,
                  true
                ],
                "values_complete": true
              },
              {
                "name": "loading",
                "type": "boolean | undefined",
                "declared_type": "boolean",
                "required": false,
                "description": "Shows the loading treatment and prevents interaction.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 28
                },
                "values": [
                  false,
                  true
                ],
                "values_complete": true
              },
              {
                "name": "fullWidth",
                "type": "boolean | undefined",
                "declared_type": "boolean",
                "required": false,
                "description": "Stretches the button to the width of its parent.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 30
                },
                "values": [
                  false,
                  true
                ],
                "values_complete": true
              },
              {
                "name": "className",
                "type": "string | undefined",
                "declared_type": "string",
                "required": false,
                "description": "",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 33
                }
              },
              {
                "name": "style",
                "type": "React.CSSProperties | undefined",
                "declared_type": "React.CSSProperties",
                "required": false,
                "description": "",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 34
                }
              },
              {
                "name": "haptic",
                "type": "HapticFeedback | undefined",
                "declared_type": "HapticFeedback",
                "required": false,
                "description": "Haptic feedback for successful presses. Defaults to `true` (`light`).",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 36
                },
                "values": [
                  "error",
                  "heavy",
                  "light",
                  "medium",
                  "selection",
                  "success",
                  "warning",
                  false,
                  true
                ],
                "values_complete": true,
                "default": "true",
                "default_kind": "source-expression"
              },
              {
                "name": "testId",
                "type": "string | undefined",
                "declared_type": "string",
                "required": false,
                "description": "Selector on the `<button>` itself; nothing inside derives from it.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 38
                }
              }
            ]
          }
        ],
        "constraints": [
          {
            "kind": "union",
            "rule": "Props must satisfy one complete branch; a forbidden prop cannot be supplied.",
            "branches": [
              "TextButtonProps",
              "IconButtonProps"
            ]
          }
        ],
        "extraction_status": "extracted"
      }
    ],
    "type_sources": [
      {
        "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
        "line": 8,
        "name": "ButtonVariant",
        "code": "export type ButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'link';"
      },
      {
        "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
        "line": 9,
        "name": "ButtonSize",
        "code": "export type ButtonSize = 'sm' | 'md';"
      },
      {
        "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
        "line": 10,
        "name": "ButtonTone",
        "code": "export type ButtonTone = 'default' | 'danger';"
      },
      {
        "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
        "line": 16,
        "name": "ButtonBaseProps",
        "code": "interface ButtonBaseProps {\n    /** Visual treatment by action hierarchy. */\n    variant: ButtonVariant;\n    /** Semantic action tone, independent of hierarchy. */\n    tone?: ButtonTone;\n    /** Height and padding tier; icon-only buttons use their own square size for each tier. */\n    size: ButtonSize;\n    /** Fires on tap. Omitted, the button renders inert without looking disabled. */\n    onPress?: () => void;\n    /** Blocks presses and dims the button. Use `loading` when the block is an in-flight action. */\n    disabled?: boolean;\n    /** Shows the loading treatment and prevents interaction. */\n    loading?: boolean;\n    /** Stretches the button to the width of its parent. */\n    fullWidth?: boolean;\n    /** Accessible label for icon-only buttons. */\n    ariaLabel?: string;\n    className?: string;\n    style?: React.CSSProperties;\n    /** Haptic feedback for successful presses. Defaults to `true` (`light`). */\n    haptic?: HapticFeedback;\n    /** Selector on the `<button>` itself; nothing inside derives from it. */\n    testId?: string;\n}"
      },
      {
        "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
        "line": 45,
        "name": "TextButtonProps",
        "code": "interface TextButtonProps extends ButtonBaseProps {\n    children: React.ReactNode;\n    /** Optional leading visual, usually an Icon. */\n    leading?: React.ReactNode;\n    /** Optional trailing visual, usually an Icon. */\n    trailing?: React.ReactNode;\n    /** Text buttons use leading/trailing slots instead of icon-only glyphs. */\n    icon?: never;\n}"
      },
      {
        "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
        "line": 58,
        "name": "IconButtonProps",
        "code": "interface IconButtonProps extends ButtonBaseProps {\n    /** The button's only content; its presence is what selects this shape. */\n    icon: React.ReactNode;\n    /** Accessible label for the icon-only button. */\n    ariaLabel: string;\n    /** Icon buttons do not render visible text. */\n    children?: never;\n    /** Icon-only buttons do not support a separate leading slot. */\n    leading?: never;\n    /** Icon-only buttons do not support a separate trailing slot. */\n    trailing?: never;\n}"
      },
      {
        "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
        "line": 74,
        "name": "ButtonProps",
        "code": "export type ButtonProps = TextButtonProps | IconButtonProps;"
      },
      {
        "path": "packages/design-system/src/tokens/CdsHaptic.ts",
        "line": 6,
        "name": "HapticFeedback",
        "code": "export type HapticFeedback = boolean | HapticType;"
      },
      {
        "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": "Button",
      "status": "preview",
      "version": "1.0.0",
      "summary": "A pressable action primitive with text, optional leading or trailing content, or an icon-only presentation."
    },
    "parts": [
      {
        "id": "container",
        "label": "Container",
        "description": "Owns the tap target, action hierarchy treatment, size, and state."
      },
      {
        "id": "label",
        "label": "Label",
        "description": "Names the action for text buttons."
      },
      {
        "id": "leading",
        "label": "Leading visual",
        "description": "Optional visual placed before a text label."
      },
      {
        "id": "trailing",
        "label": "Trailing visual",
        "description": "Optional visual placed after a text label."
      },
      {
        "id": "icon",
        "label": "Icon",
        "description": "The sole visible part of an icon-only button."
      },
      {
        "id": "loading-indicator",
        "label": "Loading indicator",
        "description": "Replaces visible content while preserving the button geometry during loading."
      }
    ],
    "allowedDesignChoices": {
      "variants": {
        "primary": {
          "label": "Primary"
        },
        "secondary": {
          "label": "Secondary"
        },
        "tertiary": {
          "label": "Tertiary",
          "description": "A deliberate web-only extension."
        },
        "link": {
          "label": "Link"
        }
      },
      "sizes": {
        "sm": {
          "label": "Small"
        },
        "md": {
          "label": "Medium"
        }
      }
    },
    "variants": [
      {
        "id": "primary",
        "label": "Primary",
        "description": "Filled treatment for the highest-priority action in a group.",
        "platforms": [
          "ios",
          "android",
          "web"
        ]
      },
      {
        "id": "secondary",
        "label": "Secondary",
        "description": "Outlined text treatment; icon-only secondary buttons use the filled secondary container.",
        "platforms": [
          "ios",
          "android",
          "web"
        ]
      },
      {
        "id": "tertiary",
        "label": "Tertiary",
        "description": "Chrome-free text treatment that retains the full text-button tap target.",
        "platforms": [
          "web"
        ]
      },
      {
        "id": "link",
        "label": "Link",
        "description": "Inline, lowest-emphasis action without button padding.",
        "platforms": [
          "ios",
          "android",
          "web"
        ]
      }
    ],
    "sizes": [
      {
        "id": "sm",
        "label": "Small",
        "description": "Compact text or icon action for dense layouts."
      },
      {
        "id": "md",
        "label": "Medium",
        "description": "Default standalone text or icon action."
      }
    ],
    "measurements": [
      {
        "id": "text-md-height",
        "label": "Medium text button height",
        "kind": "exact",
        "token": "--cds-size-56",
        "value": 56,
        "unit": "px",
        "appliesTo": [
          "text",
          "md"
        ]
      },
      {
        "id": "text-md-horizontal-padding",
        "label": "Medium text button horizontal padding",
        "kind": "exact",
        "token": "--cds-space-32",
        "value": 32,
        "unit": "px",
        "appliesTo": [
          "text",
          "md"
        ]
      },
      {
        "id": "text-md-vertical-spacing",
        "label": "Medium text button vertical spacing",
        "kind": "automatic",
        "appliesTo": [
          "text",
          "md"
        ],
        "notes": "The exact 56px height centers the label and owns the vertical inset."
      },
      {
        "id": "text-sm-vertical-padding",
        "label": "Small text button vertical padding",
        "kind": "exact",
        "token": "--cds-space-8",
        "value": 8,
        "unit": "px",
        "appliesTo": [
          "text",
          "sm"
        ]
      },
      {
        "id": "text-sm-horizontal-padding",
        "label": "Small text button horizontal padding",
        "kind": "exact",
        "token": "--cds-space-20",
        "value": 20,
        "unit": "px",
        "appliesTo": [
          "text",
          "sm"
        ]
      },
      {
        "id": "content-gap",
        "label": "Content gap",
        "kind": "exact",
        "token": "--cds-space-4",
        "value": 4,
        "unit": "px",
        "appliesTo": [
          "text",
          "leading",
          "trailing"
        ],
        "notes": "Reconciles the design gap of 4px with the prior web implementation gap of 8px."
      },
      {
        "id": "icon-md-size",
        "label": "Medium icon-only button size",
        "kind": "exact",
        "token": "--cds-size-40",
        "value": 40,
        "unit": "px",
        "appliesTo": [
          "icon",
          "md"
        ]
      },
      {
        "id": "icon-sm-size",
        "label": "Small icon-only button size",
        "kind": "exact",
        "token": "--cds-size-24",
        "value": 24,
        "unit": "px",
        "appliesTo": [
          "icon",
          "sm"
        ]
      },
      {
        "id": "large-pill-radius",
        "label": "Large primary and secondary radius",
        "kind": "exact",
        "token": "--cds-radius-full",
        "value": "full",
        "unit": "none",
        "appliesTo": [
          "text",
          "md",
          "primary",
          "secondary"
        ]
      }
    ],
    "layout": {
      "alignment": "Label, slots, icon, and loading indicator are centered in both axes.",
      "flow": "Text buttons lay out leading visual, label, and trailing visual in one row; icon-only buttons render one icon.",
      "notes": [
        "Full-width text buttons stretch to their parent while preserving centered content.",
        "Icon-only secondary buttons use the filled secondary container rather than the text-button outline."
      ]
    },
    "typographyAndColor": {
      "typography": [
        {
          "label": "Medium text",
          "description": "Uses the 16px body style.",
          "token": "--cds-type-body-size"
        },
        {
          "label": "Small text",
          "description": "Uses the 14px body-small style.",
          "token": "--cds-type-body-small-size"
        },
        {
          "label": "Link text",
          "description": "Uses the compact link style.",
          "token": "--cds-type-link-size"
        }
      ],
      "colors": [
        {
          "label": "Primary container",
          "description": "Theme-aware primary action fill.",
          "token": "--cds-button-primary-container"
        },
        {
          "label": "Primary text",
          "description": "Theme-aware foreground on the primary fill.",
          "token": "--cds-button-primary-text"
        },
        {
          "label": "Secondary container",
          "description": "Theme-aware fill for icon-only secondary buttons.",
          "token": "--cds-button-secondary-container"
        },
        {
          "label": "Secondary text",
          "description": "Theme-aware foreground for secondary and tertiary text.",
          "token": "--cds-button-secondary-text"
        }
      ]
    },
    "states": [
      {
        "id": "active",
        "label": "Active",
        "description": "Available for press and uses the selected variant treatment."
      },
      {
        "id": "disabled",
        "label": "Disabled",
        "description": "Blocks presses and applies --cds-opacity-disabled."
      },
      {
        "id": "loading",
        "label": "Loading",
        "description": "Blocks presses, hides the visible content, and centers a Spinner without changing geometry."
      }
    ],
    "behavior": [
      {
        "label": "Press",
        "description": "Calls onPress once for an enabled, non-loading button."
      },
      {
        "label": "Loading",
        "description": "Treats loading as disabled and exposes the busy state to assistive technology."
      },
      {
        "label": "Haptic",
        "description": "Requests the light semantic haptic after a successful press unless haptics are disabled."
      }
    ],
    "accessibility": [
      {
        "label": "Icon-only label",
        "description": "Every icon-only button requires an accessible ariaLabel that names the action."
      },
      {
        "label": "Native semantics",
        "description": "Renders a native button element and forwards disabled and aria-busy state."
      },
      {
        "label": "Loading name",
        "description": "Keeps the original visible label in the accessibility tree while the Spinner is shown."
      }
    ],
    "contentAdaptation": [
      {
        "label": "Action labels",
        "description": "Use short verb-led labels; full-width layouts absorb longer localized text."
      },
      {
        "label": "Slots",
        "description": "Use leading and trailing visuals only when they clarify the action; icon-only buttons do not accept text slots."
      }
    ],
    "motionHaptics": {
      "motion": [
        {
          "label": "Press feedback",
          "description": "Uses the shared button press treatment and respects reduced-motion preferences."
        }
      ],
      "haptics": [
        {
          "label": "Default feedback",
          "description": "Uses a light haptic for successful presses when a native bridge is available."
        }
      ]
    },
    "platformDifferences": [
      {
        "platforms": [
          "web"
        ],
        "description": "The tertiary variant is web-only; it is not part of the shared cross-platform component set.",
        "rationale": "Commit e85ed8f16 added the intentional chrome-free app treatment, so the difference remains documented instead of being removed during design reconciliation."
      }
    ]
  },
  "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-size-56",
      "light": "56px",
      "dark": "56px"
    },
    {
      "name": "--cds-space-32",
      "light": "32px",
      "dark": "32px"
    },
    {
      "name": "--cds-space-8",
      "light": "8px",
      "dark": "8px"
    },
    {
      "name": "--cds-space-20",
      "light": "20px",
      "dark": "20px"
    },
    {
      "name": "--cds-space-4",
      "light": "4px",
      "dark": "4px"
    },
    {
      "name": "--cds-size-40",
      "light": "40px",
      "dark": "40px"
    },
    {
      "name": "--cds-size-24",
      "light": "24px",
      "dark": "24px"
    },
    {
      "name": "--cds-radius-full",
      "light": "9999px",
      "dark": "9999px"
    },
    {
      "name": "--cds-type-body-size",
      "light": "1rem",
      "dark": "1rem"
    },
    {
      "name": "--cds-type-body-small-size",
      "light": "0.875rem",
      "dark": "0.875rem"
    },
    {
      "name": "--cds-type-link-size",
      "light": "0.75rem",
      "dark": "0.75rem"
    },
    {
      "name": "--cds-button-primary-container",
      "light": "#0b0b0a",
      "dark": "#ffffff"
    },
    {
      "name": "--cds-button-primary-text",
      "light": "#ffffff",
      "dark": "#141410"
    },
    {
      "name": "--cds-button-secondary-container",
      "light": "#f3f1ed",
      "dark": "#ffffff0d"
    },
    {
      "name": "--cds-button-secondary-text",
      "light": "#141410",
      "dark": "#f3f1ed"
    },
    {
      "name": "--cds-opacity-disabled",
      "light": "0.3",
      "dark": "0.3"
    }
  ],
  "review": {
    "local_status": "not-reviewed",
    "source_approval": null,
    "imported_spec_status": "approved",
    "spec_origin": "imported-adapted",
    "local_spec_source_status": "preview",
    "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-primitives-button--playground&viewMode=story) | export: Playground | source: packages/design-system/src/components/primitives/Button/Button.stories.tsx

- [Icon Only](/storybook/iframe.html?id=cloaked-design-system-primitives-button--icon-only&viewMode=story) | export: IconOnly | source: packages/design-system/src/components/primitives/Button/Button.stories.tsx

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

- [Danger](/storybook/iframe.html?id=cloaked-design-system-primitives-button--danger&viewMode=story) | export: Danger | source: packages/design-system/src/components/primitives/Button/Button.stories.tsx

- [Full Width](/storybook/iframe.html?id=cloaked-design-system-primitives-button--full-width&viewMode=story) | export: FullWidth | source: packages/design-system/src/components/primitives/Button/Button.stories.tsx

- [One Primary](/storybook/iframe.html?id=cloaked-design-system-primitives-button--one-primary&viewMode=story) | export: OnePrimary | source: packages/design-system/src/components/primitives/Button/Button.stories.tsx

- [Two Primaries](/storybook/iframe.html?id=cloaked-design-system-primitives-button--two-primaries&viewMode=story) | export: TwoPrimaries | source: packages/design-system/src/components/primitives/Button/Button.stories.tsx

- [State Matrix](/storybook/iframe.html?id=cloaked-design-system-primitives-button--state-matrix&viewMode=story) | export: StateMatrix | source: packages/design-system/src/components/primitives/Button/Button.stories.tsx

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

## Button playground

Source: packages/design-system/examples/ButtonPlayground.tsx

```tsx
import { useState } from 'react';
import { Button, type ButtonVariant, type ButtonTone, type ButtonSize } from '../src';
import { DemoFrame, SelectControl } from './DemoFrame';
import { buttonExampleCode, initialButtonProps, type ButtonExampleProps } from './code';

export function ButtonPlayground() {
  const [props, setProps] = useState<ButtonExampleProps>(initialButtonProps);
  const [presses, setPresses] = useState(0);
  const change = (value: Partial<ButtonExampleProps>) => { setProps(previous => ({ ...previous, ...value })); setPresses(0); };
  return <DemoFrame code={buttonExampleCode(props)} controls={<ButtonControls props={props} change={change} />}>
    <div className="demo-button-stage">
      <Button variant={props.variant} tone={props.tone} size={props.size}
        disabled={props.disabled} loading={props.loading} onPress={() => setPresses(value => value + 1)}>
        {props.label}
      </Button>
      <p className="demo-feedback" role="status">{presses ? `Pressed ${presses} ${presses === 1 ? 'time' : 'times'}.` : 'Try the button, then explore its states.'}</p>
    </div>
  </DemoFrame>;
}

function ButtonControls({ props, change }: { props: ButtonExampleProps; change: (value: Partial<ButtonExampleProps>) => void }) {
  const state = props.loading ? 'loading' : props.disabled ? 'disabled' : 'default';
  return <>
    <SelectControl label="Hierarchy" value={props.variant} options={['primary', 'secondary', 'tertiary', 'link']}
      onChange={value => change({ variant: value as ButtonVariant })} />
    <SelectControl label="Tone" value={props.tone} options={['default', 'danger']}
      onChange={value => change({ tone: value as ButtonTone })} />
    <SelectControl label="Size" value={props.size} options={['md', 'sm']}
      onChange={value => change({ size: value as ButtonSize })} />
    <SelectControl label="State" value={state} options={['default', 'loading', 'disabled']}
      onChange={value => change({ disabled: value === 'disabled', loading: value === 'loading' })} />
  </>;
}

export function ButtonHierarchy() {
  const [message, setMessage] = useState('Choose one primary action. Let supporting actions step back.');
  return <DemoFrame>
    <div className="demo-decision-card">
      <span className="demo-eyebrow">A clear next step</span>
      <h2>Keep your personal email private.</h2>
      <p>Create an address you can turn off when you no longer need it.</p>
      <div className="demo-actions">
        <Button variant="secondary" size="sm" onPress={() => setMessage('Secondary action selected. This example stays on the page.')}>Maybe later</Button>
        <Button variant="primary" size="sm" onPress={() => setMessage('Primary action selected. See the complete flow below.')}>Create an address</Button>
      </div>
      <p className="demo-feedback" role="status">{message}</p>
    </div>
  </DemoFrame>;
}
```

## One clear next step

Source: packages/design-system/examples/ButtonPlayground.tsx

```tsx
import { useState } from 'react';
import { Button, type ButtonVariant, type ButtonTone, type ButtonSize } from '../src';
import { DemoFrame, SelectControl } from './DemoFrame';
import { buttonExampleCode, initialButtonProps, type ButtonExampleProps } from './code';

export function ButtonPlayground() {
  const [props, setProps] = useState<ButtonExampleProps>(initialButtonProps);
  const [presses, setPresses] = useState(0);
  const change = (value: Partial<ButtonExampleProps>) => { setProps(previous => ({ ...previous, ...value })); setPresses(0); };
  return <DemoFrame code={buttonExampleCode(props)} controls={<ButtonControls props={props} change={change} />}>
    <div className="demo-button-stage">
      <Button variant={props.variant} tone={props.tone} size={props.size}
        disabled={props.disabled} loading={props.loading} onPress={() => setPresses(value => value + 1)}>
        {props.label}
      </Button>
      <p className="demo-feedback" role="status">{presses ? `Pressed ${presses} ${presses === 1 ? 'time' : 'times'}.` : 'Try the button, then explore its states.'}</p>
    </div>
  </DemoFrame>;
}

function ButtonControls({ props, change }: { props: ButtonExampleProps; change: (value: Partial<ButtonExampleProps>) => void }) {
  const state = props.loading ? 'loading' : props.disabled ? 'disabled' : 'default';
  return <>
    <SelectControl label="Hierarchy" value={props.variant} options={['primary', 'secondary', 'tertiary', 'link']}
      onChange={value => change({ variant: value as ButtonVariant })} />
    <SelectControl label="Tone" value={props.tone} options={['default', 'danger']}
      onChange={value => change({ tone: value as ButtonTone })} />
    <SelectControl label="Size" value={props.size} options={['md', 'sm']}
      onChange={value => change({ size: value as ButtonSize })} />
    <SelectControl label="State" value={state} options={['default', 'loading', 'disabled']}
      onChange={value => change({ disabled: value === 'disabled', loading: value === 'loading' })} />
  </>;
}

export function ButtonHierarchy() {
  const [message, setMessage] = useState('Choose one primary action. Let supporting actions step back.');
  return <DemoFrame>
    <div className="demo-decision-card">
      <span className="demo-eyebrow">A clear next step</span>
      <h2>Keep your personal email private.</h2>
      <p>Create an address you can turn off when you no longer need it.</p>
      <div className="demo-actions">
        <Button variant="secondary" size="sm" onPress={() => setMessage('Secondary action selected. This example stays on the page.')}>Maybe later</Button>
        <Button variant="primary" size="sm" onPress={() => setMessage('Primary action selected. See the complete flow below.')}>Create an address</Button>
      </div>
      <p className="demo-feedback" role="status">{message}</p>
    </div>
  </DemoFrame>;
}
```

## Create a protected email

Source: packages/design-system/examples/ProtectedEmailFlow.tsx

```tsx
import { useEffect, useLayoutEffect, useRef, useState, type FormEvent } from 'react';
import { Button, Field, Input } from '../src';
import { DemoFrame } from './DemoFrame';
import { createSampleIdentity, validateIdentity, type IdentityDraft, type IdentityErrors } from './protected-email';

const EMPTY_DRAFT: IdentityDraft = { name: '', website: '' };

export function ProtectedEmailFlow() {
  const [draft, setDraft] = useState<IdentityDraft>(EMPTY_DRAFT);
  const [errors, setErrors] = useState<IdentityErrors>({});
  const [stage, setStage] = useState<'editing' | 'loading' | 'success'>('editing');
  const form = useRef<HTMLFormElement>(null);
  const success = useRef<HTMLHeadingElement>(null);
  useEffect(() => {
    if (stage !== 'loading') return;
    const timer = window.setTimeout(() => setStage('success'), 700);
    return () => window.clearTimeout(timer);
  }, [stage]);
  useEffect(() => { if (stage === 'success') success.current?.focus(); }, [stage]);
  useLayoutEffect(() => {
    if (Object.keys(errors).length) form.current?.querySelector<HTMLInputElement>('[aria-invalid="true"]')?.focus();
  }, [errors]);
  const restart = () => {
    setDraft(EMPTY_DRAFT); setErrors({}); setStage('editing');
    requestAnimationFrame(() => form.current?.querySelector<HTMLInputElement>('input')?.focus());
  };
  const submit = (event: FormEvent) => {
    event.preventDefault();
    if (stage !== 'editing') return;
    const nextErrors = validateIdentity(draft);
    setErrors(nextErrors);
    if (Object.keys(nextErrors).length) return;
    setStage('loading');
  };
  return <DemoFrame><section className="demo-flow" aria-label="Create a protected email example">
    <p className="demo-sample-note">Interactive example · Sample data only. Nothing is sent or saved.</p>
    {stage === 'success' ? <FlowSuccess draft={draft} headingRef={success} restart={restart} /> :
      <form ref={form} noValidate onSubmit={submit} aria-busy={stage === 'loading'}>
        <FlowHeading />
        <FlowFields draft={draft} errors={errors} loading={stage === 'loading'} change={setDraft} submit={() => form.current?.requestSubmit()} />
        <Button variant="primary" size="md" fullWidth loading={stage === 'loading'} onPress={() => form.current?.requestSubmit()}>Create protected email</Button>
        <p className="demo-feedback" role="status">{stage === 'loading' ? 'Creating your sample address…' : 'Your personal email stays yours.'}</p>
      </form>}
  </section></DemoFrame>;
}

function FlowHeading() {
  return <div className="demo-flow-heading">
    <span className="demo-symbol" aria-hidden="true">@</span>
    <span className="demo-eyebrow">A little more privacy</span>
    <h2>An email for this part of your life.</h2>
    <p>Give it a name so you know where you used it.</p>
  </div>;
}

function FlowFields({ draft, errors, loading, change, submit }: {
  draft: IdentityDraft; errors: IdentityErrors; loading: boolean;
  change: (draft: IdentityDraft) => void; submit: () => void;
}) {
  return <div className="demo-flow-fields">
    <Field label="Name" helperText="For example, shopping or a newsletter." error={errors.name} required disabled={loading}>
      <Input value={draft.name} onChange={name => change({ ...draft, name })} placeholder="Shopping"
        name="identity-name" autoComplete="off" maxLength={80} enterKeyHint="next" />
    </Field>
    <Field label="Website (optional)" helperText="A reminder of where you'll use this address." error={errors.website} disabled={loading}>
      <Input value={draft.website} onChange={website => change({ ...draft, website })} placeholder="example.com"
        name="identity-website" autoComplete="off" inputMode="url" autoCapitalize="none" maxLength={200}
        enterKeyHint="done" enterBehavior="callback" onEnter={submit} />
    </Field>
  </div>;
}

function FlowSuccess({ draft, headingRef, restart }: {
  draft: IdentityDraft; headingRef: React.RefObject<HTMLHeadingElement>; restart: () => void;
}) {
  const identity = createSampleIdentity(draft);
  return <div className="demo-flow-success">
    <span className="demo-symbol demo-symbol-success" aria-hidden="true">✓</span>
    <span className="demo-eyebrow">Ready to use</span>
    <h2 ref={headingRef} tabIndex={-1}>A fresh address for {identity.name}.</h2>
    <p>This sample address demonstrates the result. It cannot receive email.</p>
    <div className="demo-email-result"><span>Protected email</span><strong>{identity.email}</strong></div>
    <Button variant="secondary" size="md" fullWidth onPress={restart}>Try the flow again</Button>
  </div>;
}
```

## Tokens together

Source: packages/design-system/examples/foundations/FoundationOverview.tsx

```tsx
import { useState } from 'react';
import { Button } from '../../src';
import { ContextCard, FoundationFrame, FoundationSelect } from './FoundationShared';
import { radiusSteps, spacingSteps } from './foundation-data';

export function FoundationOverview() {
  const [radius, setRadius] = useState('--cds-radius-xl');
  const [inset, setInset] = useState('--cds-space-24');
  const [selected, setSelected] = useState(false);
  return <FoundationFrame controls={<>
    <FoundationSelect label="Corner radius" value={radius} options={radiusSteps} onChange={setRadius} />
    <FoundationSelect label="Container spacing" value={inset} options={spacingSteps.filter(token => ['16px', '24px', '32px'].includes(token.value))} onChange={setInset} />
  </>} code={`const cardStyle = {\n  padding: 'var(${inset})',\n  borderRadius: 'var(${radius})',\n  background: 'var(--cds-bg-surface)',\n  boxShadow: 'var(--cds-shadow-card)',\n};\n// Text and Button consume their own semantic tokens.`}>
    <div className="foundation-overview-stage">
      <span className="demo-eyebrow">Small decisions. One coherent experience.</span>
      <ContextCard testId="overview-card" style={{ padding: `var(${inset})`, borderRadius: `var(${radius})` }}>
        <Button variant="primary" size="sm" onPress={() => setSelected(true)}>Create an address</Button>
      </ContextCard>
      <p className="foundation-caption" role="status">{selected ? 'Action selected. This is a local composition example.' : 'Change the container tokens. The real components keep their own behavior.'}</p>
    </div>
    <div className="foundation-token-connections">
      <span><b>Typography</b><code>--cds-type-h3-serif-*</code></span>
      <span><b>Surface</b><code>--cds-bg-surface</code></span>
      <span><b>Action</b><code>--cds-button-primary-*</code></span>
    </div>
  </FoundationFrame>;
}
```

## Motion

Source: packages/design-system/examples/foundations/FoundationMotion.tsx

```tsx
import { MotionShowcase } from '../../src/foundations/MotionShowcase';
import { FoundationFrame } from './FoundationShared';

/** The website and original Foundations Motion story render this same showcase. */
export function FoundationMotion() {
  return <FoundationFrame><MotionShowcase /></FoundationFrame>;
}
```

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