{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "recipes",
  "title": "Recipes",
  "description": "Helper used by the Get IT Done components.",
  "dependencies": [],
  "registryDependencies": [
    "https://zero-design.itdone.de/r/theme.json"
  ],
  "files": [
    {
      "path": "registry/lib/recipes.ts",
      "content": "// Shared Tailwind recipes consumed by several primitives so the interaction model stays identical everywhere. Tokens only: every class is a token-preset utility.\n\n// Shared keyboard focus ring (tokens 4.28): 2px ring in the `ring-default` role, offset 2px from the control by the page background.\nexport const focusRing = [\n  'focus-visible:outline-none',\n  'focus-visible:ring-focus',\n  'focus-visible:ring-offset-focus',\n  'focus-visible:ring-offset-background',\n  'focus-visible:ring-ring-default',\n] as const;\n\n// Shared focus ring for controls on an inverse surface (dark band in light mode, light band in dark mode): the ring takes the inverse text role and the gap takes the inverse background, so both follow the band in either theme.\nexport const focusRingInverse = [\n  'focus-visible:outline-none',\n  'focus-visible:ring-focus',\n  'focus-visible:ring-offset-focus',\n  'focus-visible:ring-offset-background-inverse',\n  'focus-visible:ring-text-inverse',\n] as const;\n\n// Text-field family (input, select, textarea, editors): the shared ring plus the `ring` border colour on the field edge.\nexport const focusRingField = [...focusRing, 'focus-visible:border-ring'] as const;\n\n// Same look as focusRingField but driven by a Radix `data-[state=open]` attribute (pointer-opened triggers).\nexport const openRing = [\n  'data-[state=open]:ring-focus',\n  'data-[state=open]:ring-offset-focus',\n  'data-[state=open]:ring-offset-background',\n  'data-[state=open]:ring-ring-default',\n  'data-[state=open]:border-ring',\n] as const;\n\n// Invalid state driven by `aria-invalid` (arbitrary-variant form: `aria-invalid` is not in the aria allow-list). The focus ring turns destructive.\nexport const invalidRing = [\n  'aria-[invalid=true]:border-destructive',\n  'aria-[invalid=true]:ring-destructive/20',\n  'aria-[invalid=true]:focus-visible:border-destructive',\n  'aria-[invalid=true]:focus-visible:ring-destructive',\n  'aria-[invalid=true]:data-[state=open]:ring-destructive',\n  'aria-[invalid=true]:data-[state=open]:border-destructive',\n] as const;\n\n/** Fast-in, fast-out interaction transition (150ms rest, 75ms on hover/press for a snappy response). */\nexport const transitionBase = [\n  'transition-[color,background-color,border-color,box-shadow]',\n  'duration-150',\n  'hover:duration-75',\n  'active:duration-75',\n] as const;\n\n/** Popover-like floating surface: menus, select lists, popovers, hover cards, nav viewport. */\nexport const overlaySurface = [\n  'bg-popover',\n  'text-popover-foreground',\n  'rounded-popover',\n  'border',\n  'border-solid',\n  'border-hairline',\n  'shadow-popover',\n] as const;\n\n/** Overlay open/close motion: fade + subtle zoom from 98%, 150ms, instant under reduced motion. */\nexport const overlayMotion = [\n  'data-[state=open]:animate-in',\n  'data-[state=closed]:animate-out',\n  'data-[state=closed]:fade-out-0',\n  'data-[state=open]:fade-in-0',\n  'data-[state=closed]:zoom-out-95',\n  'data-[state=open]:zoom-in-[0.98]',\n  'duration-150',\n  'motion-reduce:animate-none',\n  'motion-reduce:transition-none',\n] as const;\n\n// Keyboard focus on a menu row: an own inset 2px outline (3:1 against the grey highlight, WCAG 2.4.11). It replaces any app-wide :focus-visible outline instead of stacking on it, because it sets the same outline properties with a higher specificity.\nexport const menuItemFocusVisible = [\n  'focus-visible:outline',\n  'focus-visible:outline-2',\n  'focus-visible:-outline-offset-2',\n  'focus-visible:outline-ring-default',\n] as const;\n\n/** Menu / select / command row. Regular weight (owner decision), highlight uses `bg-muted`; no inset rings. */\nexport const menuItem = [\n  'relative',\n  'flex',\n  'cursor-default',\n  'select-none',\n  'items-center',\n  'gap-[10px]',\n  'rounded-item',\n  'px-2',\n  'py-[6px]',\n  'text-sm',\n  'font-normal',\n  'outline-none',\n  'transition-colors',\n  'focus:bg-muted',\n  'data-[highlighted]:bg-muted',\n  ...menuItemFocusVisible,\n  'data-[disabled]:pointer-events-none',\n  'data-[disabled]:opacity-disabled',\n] as const;\n\n/** Destructive menu row variant (`variant=\"destructive\"` on menu items). */\nexport const menuItemDestructive = [\n  'text-destructive',\n  'focus:bg-destructive/10',\n  'focus:text-destructive',\n  'data-[highlighted]:bg-destructive/10',\n] as const;\n\n// Zero preset field state: the 3px halo (`ring-halo`) at 15 percent (`--opacity-ring-halo`) on focus, open and invalid. Replaces focusRingField and openRing, it does not stack on them.\nexport const fieldHaloZero = [\n  'focus-visible:outline-none',\n  'focus-visible:ring-halo',\n  'focus-visible:ring-ring/ring-halo',\n  'focus-visible:border-ring',\n  'data-[state=open]:ring-halo',\n  'data-[state=open]:ring-ring/ring-halo',\n  'data-[state=open]:border-ring',\n  'aria-[invalid=true]:ring-halo',\n  'aria-[invalid=true]:ring-destructive/ring-halo',\n  'aria-[invalid=true]:focus-visible:ring-destructive/ring-halo',\n  'aria-[invalid=true]:data-[state=open]:ring-destructive/ring-halo',\n] as const;\n\n/** Zero preset overrides for {@link overlaySurface}: default border role and the raised elevation. Append after `overlaySurface`. */\nexport const overlaySurfaceZero = ['border-border-default', 'shadow-elevation-raised'] as const;\n\n/** Zero preset menu row: 32px (control-md) high, 13/400 ui role, 8px radius, 12px gap. Use instead of {@link menuItem}. */\nexport const menuItemZero = [\n  'relative',\n  'flex',\n  'cursor-default',\n  'select-none',\n  'items-center',\n  'gap-3',\n  'rounded-control',\n  'px-2',\n  'min-h-[var(--size-control-md)]',\n  'py-0',\n  'typography-ui',\n  'font-regular',\n  'outline-none',\n  'transition-colors',\n  'focus:bg-muted',\n  'data-[highlighted]:bg-muted',\n  ...menuItemFocusVisible,\n  'data-[disabled]:pointer-events-none',\n  'data-[disabled]:opacity-disabled',\n] as const;\n\n// Zero preset surface of the composite fields (SingleSelect, MultiSelect, DatePicker trigger): control height, control padding, the default border role and the focus halo. Use instead of the legacy border classes, do not stack.\nexport const compositeFieldZero = [\n  'min-h-[var(--size-control-md)]',\n  'pl-control-px-sm',\n  'border-input',\n  'hover:border-border-bold',\n  'focus-within:border-ring',\n  'focus-within:ring-halo',\n  'focus-within:ring-ring/ring-halo',\n  'aria-[invalid=true]:border-destructive',\n  'aria-[invalid=true]:ring-halo',\n  'aria-[invalid=true]:ring-destructive/ring-halo',\n] as const;\n\n// Legacy surface of the composite fields, kept for the default preset.\nexport const compositeFieldDefault = [\n  'border-form-border-default',\n  'hover:border-input-background-hover',\n  'aria-[invalid=true]:border-error',\n  'pl-2',\n] as const;\n",
      "type": "registry:lib"
    }
  ],
  "type": "registry:lib"
}