{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "toast",
  "title": "Toast",
  "description": "Toast from the Get IT Done design system.",
  "dependencies": [
    "@radix-ui/react-toast@^1.3.1",
    "class-variance-authority@^0.7.0",
    "lucide-react@^0.379.0"
  ],
  "registryDependencies": [
    "https://zero-design.itdone.de/r/labels-context.json",
    "https://zero-design.itdone.de/r/utils.json",
    "https://zero-design.itdone.de/r/theme.json"
  ],
  "files": [
    {
      "path": "registry/ui/toast.tsx",
      "content": "'use client';\n\nimport * as ToastPrimitives from '@radix-ui/react-toast';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { X } from 'lucide-react';\nimport * as React from 'react';\n\nimport { cn } from '@/lib/utils';\nimport { useLabels, usePreset } from '@/components/ui/labels-context';\n\nconst ToastProvider = ToastPrimitives.Provider;\n\nconst ToastViewport = React.forwardRef<\n  React.ElementRef<typeof ToastPrimitives.Viewport>,\n  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport> & { clamp?: boolean }\n>(({ className, clamp = false, ...props }, ref) => (\n  <ToastPrimitives.Viewport\n    ref={ref}\n    className={cn(\n      'fixed top-0 z-toast flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]',\n      className,\n    )}\n    {...props}\n  />\n));\nToastViewport.displayName = ToastPrimitives.Viewport.displayName;\n\n// TOAST-TOK-01 (component-scoped surface token gap): unlike sibling overlay/portal-level\n// components — DropdownMenu (`dropdown-background-default`), Tooltip (`tooltip-background-default`) —\n// the token repo (the design tokens (`styles/theme.css`)) has not shipped a dedicated\n// `toast-background-default` / `toast-foreground-default` pair. The `default` variant below falls\n// back to the generic semantic `background-default` / `foreground-default` role tokens instead — the\n// same fallback Alert already uses for its own `default` variant (see alert.tsx) — a legitimate,\n// dark-mode-aware, already-shipped pair, not a fabricated value. Flagged for\n// design-tokens-maintainer as a candidate future `toast-*` namespace; not fixable from this file.\n//\n// destructive variant: the shipped token set actually carries TWO different \"solid destructive\n// surface\" pairs with different RGB values and different dark-mode awareness —\n// `background-destructive` / `foreground-destructive` (a single flat value, NOT redefined under\n// `.dark`, with no `-hover` / `-active` companion — see button.tsx's `destructive` variant) vs.\n// `general-error-default` / `general-error-on` (a complete, dark-mode-tuned family with `-hover` /\n// `-active` steps — see chip.tsx's `destructive` variant). Toast's destructive variant needs\n// hover/active-capable nested `ToastAction` / `ToastClose` states AND correct per-mode contrast —\n// only the `general-error-*` family satisfies both, so it (not the Button pair) is reused here,\n// matching Chip's already-verified-good destructive treatment. TOAST-TOK-02: flagging that two\n// divergent \"destructive fill\" token pairs ship at all, with no canonical one, to\n// design-tokens-maintainer — the ideal fix is consolidating on a single dark-mode-aware pair.\n//\n// The literal `destructive` class name below is not a Tailwind utility — it is a plain CSS marker\n// consumed by the `group-[.destructive]:` selectors on ToastAction/ToastClose (same technique\n// upstream shadcn/ui uses), letting those nested, genuinely-interactive controls re-theme themselves\n// off the parent's variant without threading a prop through three components.\n//\n// TOAST-TOK-03 (component-scoped border-contrast gap, `default` variant only): the base border was\n// `border-form-border-default` (slate.200 light / slate.700 dark), which computes to ~1.23:1 (light)\n// and ~1.95:1 (dark) against the generic `background-default` surface it sits on — both fail the\n// 3:1 floor for SC 1.4.11. Switched to `border-general-border-default` — an already-shipped,\n// dark-mode-aware semantic token Alert already uses for the identical \"generic default surface needs\n// a boundary\" problem (see alert.tsx's `default` variant) — which clears the floor in light mode\n// (slate.900 vs white, >15:1). In dark mode `general-border-default` and `form-border-default`\n// resolve to the SAME slate.700 value, so this does not regress dark mode but also does not clear\n// 3:1 there (~1.95:1 unchanged) — no shipped border or shadow token in the token repo currently\n// reaches 3:1 against the dark `background-default` surface (`shadow-lg`'s black/10% is equally\n// negligible on a near-black background, and there is no dark-mode-aware elevation/shadow token to\n// substitute). Flagged for design-tokens-maintainer: a dedicated `toast-border-default` (or a shared\n// elevated-surface border role) needs a lighter dark-mode value that clears 3:1 against\n// `background-default` dark. Not fabricated here per the \"never hardcode a missing token\" rule.\nconst toastVariants = cva(\n  'group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-default border border-solid border-general-border-default p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full motion-reduce:animate-none motion-reduce:transition-none motion-reduce:data-[state=closed]:animate-none',\n  {\n    variants: {\n      variant: {\n        default: 'bg-surface-canvas text-text-default',\n        destructive: 'destructive border-transparent bg-general-error-default text-general-error-on',\n        // Compact undo toast (Figma Toast): inverse surface, single line, text action and close inline.\n        inverse: 'inverse border-transparent bg-foreground px-4 py-3 text-background',\n      },\n      // Product preset (DesignSystemProvider `preset`). `zero` uses the 12px surface radius, a 40px single line and the raised elevation on the inverse toast.\n      preset: { default: '', zero: '' },\n    },\n    compoundVariants: [{ variant: 'inverse', preset: 'zero', className: 'rounded-surface py-control-py-md shadow-elevation-raised typography-ui' }],\n    defaultVariants: {\n      variant: 'default',\n      preset: 'default',\n    },\n  },\n);\n\n// TOAST-A11Y-07: the fluid-type `clamp` classes previously used Tailwind's `!` (`!important`)\n// modifier on `text-clamp-small`/`leading-clamp-small`. `!important` author declarations can only be\n// beaten by a user stylesheet's own `!important` rule — a low-specificity user/AT text-spacing\n// override (SC 1.4.12, e.g. a `body *` or element-selector rule, not itself `!important`) loses to\n// our single-class `!important` regardless of source order, silently blocking the user-override\n// mechanism SC 1.4.12 requires. Fixed via scoping/specificity instead of `!important`: the\n// descendant selectors below (`[&_div]:text-clamp-small`, `[&_button]:text-clamp-small`, scoped from\n// the Toast root) already carry a class+type-selector specificity (0,1,1) that beats the plain\n// `.text-sm` utility (0,1,0) deterministically regardless of CSS source order — no `!important`\n// needed, and any genuine (even non-important) user override still wins because it is no longer\n// fighting an `!important` declaration.\nconst Toast = React.forwardRef<\n  React.ElementRef<typeof ToastPrimitives.Root>,\n  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> & Omit<VariantProps<typeof toastVariants>, 'preset'> & { clamp?: boolean }\n>(({ className, variant, clamp = false, ...props }, ref) => {\n  const zero = usePreset() === 'zero';\n  return (\n    <ToastPrimitives.Root\n      ref={ref}\n      className={cn(\n        toastVariants({ variant: variant ?? (zero ? 'inverse' : 'default'), preset: zero ? 'zero' : 'default' }),\n        { '!p-6': clamp },\n        { '[&_div]:text-clamp-small [&_button]:text-clamp-small': clamp },\n        { '[&_div]:leading-clamp-small [&_button]:leading-clamp-small': clamp },\n        className,\n      )}\n      {...props}\n    />\n  );\n});\nToast.displayName = ToastPrimitives.Root.displayName;\n\n// TOAST-A11Y-05: the base border was `border border-solid` with no border-color utility, falling\n// back to the library's global base rule bound to `--colors-form-border-default` (light-only, no\n// dark override) — ~1.23:1 against the toast's background, far below the 3:1 SC 1.4.11 floor for an\n// interactive control boundary. Added the explicit `border-general-border-default` token — the same\n// dark-mode-aware pair already applied to the Toast root (see TOAST-TOK-03 above) — for the default\n// (non-destructive) treatment; the `destructive` variant keeps its own already-verified\n// `group-[.destructive]:border-general-error-on/40` boundary.\nconst ToastAction = React.forwardRef<\n  React.ElementRef<typeof ToastPrimitives.Action>,\n  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action> & { clamp?: boolean }\n>(({ className, clamp = false, ...props }, ref) => (\n  <ToastPrimitives.Action\n    ref={ref}\n    className={cn(\n      'inline-flex h-8 shrink-0 items-center justify-center rounded-default border border-solid border-general-border-default bg-transparent px-3 text-sm font-medium transition-colors',\n      'hover:bg-background-neutral-default',\n      'focus-visible:outline-none focus-visible:ring-focus focus-visible:ring-ring-default focus-visible:ring-offset-focus',\n      'active:bg-background-neutral-default active:brightness-95',\n      'disabled:pointer-events-none disabled:opacity-disabled',\n      'group-[.inverse]:h-auto group-[.inverse]:min-h-target group-[.inverse]:border-0 group-[.inverse]:bg-transparent group-[.inverse]:px-2 group-[.inverse]:py-0 group-[.inverse]:underline group-[.inverse]:hover:bg-transparent',\n      'group-[.inverse]:focus-visible:ring-background group-[.inverse]:focus-visible:ring-offset-0',\n      'group-[.destructive]:border-general-error-on/40',\n      'group-[.destructive]:hover:border-general-error-on/70',\n      'group-[.destructive]:hover:bg-general-error-hover',\n      'group-[.destructive]:active:bg-general-error-active',\n      'group-[.destructive]:focus-visible:ring-general-error-on',\n      'group-[.destructive]:focus-visible:ring-offset-general-error-default',\n      { '[.group_&]:text-clamp-small': clamp, '[.group_&]:leading-clamp-small': clamp },\n      className,\n    )}\n    {...props}\n  />\n));\nToastAction.displayName = ToastPrimitives.Action.displayName;\n\n// TOAST-A11Y-06: resting opacity was `opacity-0` — on touch/no-hover contexts (no `:hover` to\n// trigger `group-hover:opacity-100`) there was zero visible dismiss affordance for the full\n// TOAST_REMOVE_DELAY auto-dismiss window (use-toast.ts). Sibling dismissible overlays instead stay\n// persistently visible at rest: Dialog's close defaults to `opacity-disabled` (60%, dialog.tsx),\n// Sheet's defaults to `opacity-70` (sheet.tsx). Toast now matches Sheet's `opacity-70` baseline;\n// `hover:`/`focus-visible:`/`group-hover:` still raise it to full opacity.\nconst ToastClose = React.forwardRef<\n  React.ElementRef<typeof ToastPrimitives.Close>,\n  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>\n>(({ className, 'aria-label': ariaLabelProp, ...props }, ref) => {\n  const l = useLabels();\n  const ariaLabel = ariaLabelProp ?? l.dismiss;\n  return (\n  <ToastPrimitives.Close\n    ref={ref}\n    aria-label={ariaLabel}\n    className={cn(\n      'absolute right-1 top-1 rounded-default p-1 text-text-subtle opacity-70 transition-opacity',\n      'hover:text-text-default hover:opacity-100',\n      'focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-focus focus-visible:ring-ring-default focus-visible:ring-offset-focus',\n      'group-hover:opacity-100',\n      'group-[.inverse]:static group-[.inverse]:text-background group-[.inverse]:opacity-100 group-[.inverse]:focus-visible:ring-background group-[.inverse]:focus-visible:ring-offset-0',\n      'group-[.destructive]:text-general-error-on',\n      'group-[.destructive]:hover:text-general-error-on',\n      'group-[.destructive]:focus-visible:text-general-error-on',\n      'group-[.destructive]:focus-visible:ring-general-error-on',\n      'group-[.destructive]:focus-visible:ring-offset-general-error-default',\n      className,\n    )}\n    toast-close=\"\"\n    {...props}\n  >\n    <X className=\"h-4 w-4\" aria-hidden=\"true\" />\n  </ToastPrimitives.Close>\n  );\n});\nToastClose.displayName = ToastPrimitives.Close.displayName;\n\nconst ToastTitle = React.forwardRef<\n  React.ElementRef<typeof ToastPrimitives.Title>,\n  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title> & { clamp?: boolean }\n>(({ className, clamp = false, ...props }, ref) => (\n  <ToastPrimitives.Title\n    ref={ref}\n    className={cn(\n      'text-sm font-semibold [&+div]:text-xs',\n      { '[.group_&]:text-clamp-small': clamp, '[.group_&]:leading-clamp-small': clamp },\n      className,\n    )}\n    {...props}\n  />\n));\nToastTitle.displayName = ToastPrimitives.Title.displayName;\n\n// TOAST-A11Y-04: `opacity-90` alone blends the destructive variant's inherited `general-error-on`\n// text to ~3.96:1 (light) / ~4.36:1 (dark) against `general-error-default` — both below the 4.5:1 AA\n// floor for normal-size text (SC 1.4.3). `group-[.destructive]:opacity-100` restores full-strength\n// `general-error-on` for the destructive variant only (the default variant keeps the softer\n// `opacity-90` treatment, which already clears AA against its own `foreground-default`/\n// `background-default` pairing).\nconst ToastDescription = React.forwardRef<\n  React.ElementRef<typeof ToastPrimitives.Description>,\n  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description> & { clamp?: boolean }\n>(({ className, clamp = false, ...props }, ref) => (\n  <ToastPrimitives.Description\n    ref={ref}\n    className={cn(\n      'text-sm opacity-90 group-[.destructive]:opacity-100',\n      { '[.group_&]:text-clamp-small': clamp, '[.group_&]:leading-clamp-small': clamp },\n      className,\n    )}\n    {...props}\n  />\n));\nToastDescription.displayName = ToastPrimitives.Description.displayName;\n\ntype ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;\n\ntype ToastActionElement = React.ReactElement<typeof ToastAction>;\n\nexport {\n  Toast,\n  ToastAction,\n  ToastClose,\n  ToastDescription,\n  ToastProvider,\n  ToastTitle,\n  ToastViewport,\n  type ToastActionElement,\n  type ToastProps,\n};\n\n// --- Deliberately NOT added (documented rather than silently omitted) ---\n//\n// `selected`: like Alert (see alert.tsx), Toast has no resolvable Figma spec to confirm this\n// against — the \"Notification\" component_set is indexed in the published \"🚧 GetITDone Basic\" team\n// library (componentKey 774bcac2189d93af8b4c2789db620011ba9dc113, last updated 2024-07-26) but is\n// not present on any current page of file bzBnRLfRJNknGg9UYJIHb0 (checked Welcome, Button, Select,\n// Tooltips, CardMetrics, Logos, Utilities) — the same orphaned-publish issue already documented on\n// Alert/Chip (see alert.figma.tsx / chip.figma.tsx). Toast is also, by nature, an ephemeral one-shot\n// notification (Radix mounts/unmounts it), not a persisted/toggleable list item — nothing in this\n// codebase needs a selectable Toast. Fabricating a spec here would violate the \"never fabricate a\n// spec that isn't in Figma\" rule — flagged as NEEDS_DECISION instead of guessed.\n//\n// `invalid`: same reasoning as Alert — `variant=\"destructive\"` already means \"this is the\n// error/invalid message\"; a separate `invalid` boolean would duplicate it with no new information.\n//\n// `disabled` (on the Toast root itself): a whole toast cannot be \"disabled\" — there is no root-level\n// interaction to disable (Radix's `Root` is a passive, swipe-dismissible live region, not a control).\n// `ToastAction` and `ToastClose` are the real, keyboard-operable controls here, and both already\n// support the native `disabled` attribute with the token-driven `disabled:` states above.\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}