{
  "name": "Toast",
  "type": "component",
  "description": "A transient message about something that has just happened, in five variants.",
  "export": "@gtmi/strix-react/atoms/toast",
  "path": "@gtmi/strix-react/atoms/toast",
  "figma": {
    "file": "zT3vGm4QlFEI2Jp9nxyFKI",
    "fileName": "Demo components library",
    "nodes": [
      {
        "node": "22:5320",
        "name": ".demo-notifications",
        "section": "Atoms"
      }
    ],
    "note": "`.demo-notifications` inks its border, title and glyph one status colour. Two of those (#83f969, #f7b955) are bound to no Figma variable and are minted as `--palette-status-green` / `--palette-status-amber`."
  },
  "props": [
    {
      "name": "title",
      "type": "string",
      "required": true
    },
    {
      "name": "description",
      "type": "ReactNode",
      "description": "Inline links are underlined as well as colored."
    },
    {
      "name": "variant",
      "type": "neutral | success | warning | error | loading",
      "default": "neutral"
    },
    {
      "name": "presentation",
      "type": "default | demo",
      "default": "default",
      "description": "`demo` is the Figma .demo-notifications pill: title and body inline from `md` up, stacked below it with the boundary moving from the root onto the title. Responsive by CSS rather than by a breakpoint prop."
    },
    {
      "name": "icon",
      "type": "ReactNode",
      "description": "Override the variant's icon."
    },
    {
      "name": "actionSlot",
      "type": "ReactNode",
      "description": "A single action, usually an undo."
    },
    {
      "name": "onDismiss",
      "type": "() => void"
    },
    {
      "name": "dismissActionOnClick",
      "type": "boolean",
      "default": "true",
      "description": "Dismiss after the action runs. Turn off for an action that starts a multi-step flow inside the toast."
    },
    {
      "name": "className",
      "type": "string",
      "description": "Merged through cn()."
    }
  ],
  "ai_tags": ["toast", "notification", "status", "primitive"],
  "since": "0.2.0",
  "tokens_used": [
    "--color-surface-base",
    "--color-text-primary",
    "--color-text-accent",
    "--color-icon-success",
    "--color-icon-warning",
    "--color-icon-error",
    "--color-icon-secondary",
    "--color-border-accent",
    "--shadow-md",
    "--radius-md",
    "--spacing-padding-horizontal-md",
    "--spacing-padding-vertical-md",
    "--spacing-gap-200",
    "--spacing-gap-250",
    "--color-text-subtle-figma",
    "--color-border-neutral-medium",
    "--color-border-notification-success",
    "--color-border-notification-warning",
    "--color-border-notification-error",
    "--color-text-notification-success",
    "--color-text-notification-warning",
    "--color-text-notification-error",
    "--color-icon-notification-success",
    "--color-icon-notification-warning",
    "--color-icon-notification-error"
  ],
  "notes": "THIS IS THE TOAST, NOT A TOAST SYSTEM. There is no provider, queue, positioning or auto-dismiss timing, because maker-ds has none either - upstream's toast is presentational and the consumer places and dismisses it. The Phase 3c plan assumed a provider and queue existed to port; inspection showed otherwise, and queueing/stacking/timing is a design problem rather than a port, so inventing it inside a port task would ship an API nobody specified. Not portalled, for the same reason, so there is no theme stamp here. role=\"status\" makes it an implicit polite live region. The icon is aria-hidden: the title carries the meaning, and a screen reader should not hear \"warning icon warning\". Inline links are underlined, a deliberate divergence from maker-ds's underline-none: in dark mode the accent link is 2.28:1 against the body text, under the 3:1 color alone needs. The action's own handler runs before dismissal, or the toast would unmount mid-handler.\n\nTHE `demo` PRESENTATION IS FIGMA `.demo-notifications` (22:5320), AND ITS ONE REAL MECHANISM IS A RESTRUCTURE RATHER THAN A RESTYLE. From `md` up the root is a bordered pill with the title and body inline; below `md` the border moves OFF the root and ONTO the title, which becomes its own pill with the body beneath it. The bordered element changes identity across the breakpoint, so both halves are written literally on both elements (`border-0 md:border` on the root, `border md:border-0` on the title). THE BREAKPOINT IS CSS AND NEVER A PROP: Figma models it as a `Breakpoint` variant, but a prop would make the caller responsible for measuring the viewport, and a caller cannot honour it inside a container narrower than the page.\n\nTWO DEFECTS IN THE FIRST VERSION OF THIS, BOTH INVISIBLE TO A className ASSERTION AND BOTH FOUND BY measure-story. (1) The demo classes were APPENDED to the card's own padding, so `cn()` resolved it in the card's favour: the pill measured 70px against Figma's 46px and its own `p-gap-200` generated nothing. (2) The root kept its border at the narrow width, so BOTH the root and the title were bordered — not the design. Both names were present on the element in each case, which is why `expect(className).toContain(...)` passed against a wrong render. The root is now a `cva` with exactly one padding, radius and fill set per presentation, and the tests assert the absence of the card's utilities rather than only the presence of the pill's. Measured after the fix: 390px gives a borderless root at radius 4 with a 1px bordered title, stacked; 1200px gives a 1px bordered root at radius 50 with the title's border gone and the two on one line.\n\nThe remaining height divergence is content, not geometry: Figma's desktop frame is 46px and mobile 114px for its own strings, where the stories measure 54px and 84px because the description wraps differently at `max-w-104`. Not chased — a frame height in Figma is a measurement of one string.\n\nTHE PER-STATUS TINT NOW SHIPS, REVERSING TWO DECLINES THIS FILE USED TO RECORD. They were \"#83f969 and #f7b955 are bound to no variable, so porting them means minting palette entries with no light value\" and \"the Error title ink #ef223a is 4.57:1, over the floor by 0.07\". Rule 3 voids the first — the file is dark-only, so there is no light value to invent, and the established precedent (`--color-border-field-error`) emits Figma's value into both layers. Rule 1 voids the second, and it PASSES anyway. Figma tints boundary, title and glyph together, which is why a neutral border under a white title was the whole of what made the port read wrong.\n\nNine roles rather than three, because 1.4.11 asks 3:1 of a boundary where 1.4.3 asks 4.5:1 of a text, and Error is Figma's own proof they diverge: border #ef223a, glyph `twilio-red` #db132a. Recomputed on #000d25: green 14.50, amber 11.09, #ef223a 4.57, #db132a 3.82 as a glyph. All pass, so nothing is logged in FIGMA-EXCEPTIONS. `neutral` and `loading` keep the neutral boundary and primary ink — Figma's Type axis is Success | Alert | Error and has no cell for them. The body ink is two colours across the breakpoint, not one: `gray-300` stacked, white inline.\n\nEach status colour is one class per element, supplied by a Record that includes the neutral fallback, rather than a status class layered over a neutral default. Layering would put two border-colour names in the string and let merge order decide the rendered colour — defect (2) above, again.\n\nTWO FIGMA DETAILS STILL DIVERGE, NEITHER A COLOUR. Figma centres the stacked body text; our title pill hugs its content where Figma's variant frame is fixed-width, so `text-center` would centre the body against a left-hugging pill. And Figma draws a padlock on Error where this component draws `AlertCircleIcon` — glyph shape belongs to Toast's variant iconography, not to the demo presentation."
}
