{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "command-accent",
  "title": "Accent command",
  "description": "Styled command: the Accent set. 5 decorative command variations (BarCommand, GlowCommand, FillCommand, RingCommand, EdgeCommand) on the ai2 token system, powered by framer-motion, reduced-motion aware and sized sm to xl. Part of the free styled layer.",
  "dependencies": [
    "motion@^12.42.2",
    "lucide-react@^1.23.0"
  ],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/command-accent.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { motion, useReducedMotion } from \"motion/react\"\nimport {\n  Calculator,\n  Calendar,\n  CreditCard,\n  FileText,\n  Search,\n  Settings,\n  Smile,\n  User,\n} from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Accent command family: 5 SELF-CONTAINED command palettes. NO cmdk, NO radix, NO\n   portal. The skeleton is the same (a search input + a filtered list); the only\n   difference is the highlight language of the selected row: a left bar, an\n   overflowing glow, a filled background, an inner ring and a right-edge marker.\n   The highlight marker flows from row to row with motion layoutId. The arrow keys\n   move the highlight, Enter selects, Escape clears. Color comes ONLY from tokens,\n   via alpha color-mix; the primary shades are derived with color-mix. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\nconst paletteWidth: Record<StyledSize, string> = {\n  sm: \"w-64\",\n  md: \"w-80\",\n  lg: \"w-96\",\n  xl: \"w-[28rem]\",\n}\n\nexport interface CommandItem {\n  label: React.ReactNode\n  group?: string\n  icon?: React.ReactNode\n  onSelect?: () => void\n}\n\ninterface CommandProps {\n  className?: string\n  size?: StyledSize\n  placeholder?: string\n  items?: CommandItem[]\n}\n\n/* The label can be a ReactNode; flatten it to plain text for filtering. */\nfunction nodeText(node: React.ReactNode): string {\n  if (node === null || node === undefined || typeof node === \"boolean\") return \"\"\n  if (typeof node === \"string\" || typeof node === \"number\") return String(node)\n  if (Array.isArray(node)) return node.map(nodeText).join(\"\")\n  if (React.isValidElement(node)) {\n    return nodeText((node.props as { children?: React.ReactNode }).children)\n  }\n  return \"\"\n}\n\n/* Varsayilan liste: prop'suz render eder. */\nconst defaultItems: CommandItem[] = [\n  { label: \"Calendar\", group: \"Suggestions\", icon: <Calendar /> },\n  { label: \"Search Emoji\", group: \"Suggestions\", icon: <Smile /> },\n  { label: \"Calculator\", group: \"Suggestions\", icon: <Calculator /> },\n  { label: \"Profile\", group: \"Settings\", icon: <User /> },\n  { label: \"Billing\", group: \"Settings\", icon: <CreditCard /> },\n  { label: \"Settings\", group: \"Settings\", icon: <Settings /> },\n  { label: \"New Document\", group: \"Actions\", icon: <FileText /> },\n]\n\n/* Shared state plus combobox/listbox ids. useId keeps several instances on\n   the same page from colliding. */\nfunction usePalette(source: CommandItem[]) {\n  const uid = React.useId()\n  const [query, setQuery] = React.useState(\"\")\n  const [active, setActive] = React.useState(0)\n\n  const filtered = React.useMemo(() => {\n    const q = query.trim().toLowerCase()\n    if (q.length === 0) return source\n    return source.filter((item) => nodeText(item.label).toLowerCase().includes(q))\n  }, [query, source])\n\n  React.useEffect(() => {\n    setActive((prev) => (prev >= filtered.length ? 0 : prev))\n  }, [filtered.length])\n\n  const select = React.useCallback(\n    (index: number) => {\n      const item = filtered[index]\n      if (item) item.onSelect?.()\n    },\n    [filtered]\n  )\n\n  const onKeyDown = React.useCallback(\n    (e: React.KeyboardEvent<HTMLInputElement>) => {\n      if (e.key === \"ArrowDown\") {\n        e.preventDefault()\n        setActive((prev) => (filtered.length === 0 ? 0 : (prev + 1) % filtered.length))\n      } else if (e.key === \"ArrowUp\") {\n        e.preventDefault()\n        setActive((prev) =>\n          filtered.length === 0 ? 0 : (prev - 1 + filtered.length) % filtered.length\n        )\n      } else if (e.key === \"Enter\") {\n        e.preventDefault()\n        select(active)\n      } else if (e.key === \"Escape\") {\n        e.preventDefault()\n        setQuery(\"\")\n        setActive(0)\n      }\n    },\n    [filtered.length, active, select]\n  )\n\n  const listId = `${uid}-list`\n  const optionId = React.useCallback((i: number) => `${uid}-option-${i}`, [uid])\n\n  return {\n    uid,\n    query,\n    setQuery,\n    active,\n    setActive,\n    filtered,\n    select,\n    onKeyDown,\n    listId,\n    optionId,\n  }\n}\n\nconst rootBase =\n  \"flex flex-col overflow-hidden rounded-xl border border-border bg-popover text-popover-foreground shadow-lg outline-none\"\n\nconst inputRowBase = \"flex items-center gap-2 border-b border-border px-3\"\n\nconst inputBase =\n  \"h-11 w-full rounded-md bg-transparent py-3 text-sm text-popover-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50\"\n\nconst listBase = \"max-h-72 overflow-y-auto p-1.5\"\n\nconst optionBase =\n  \"relative flex cursor-pointer select-none items-center gap-2 rounded-lg px-2.5 py-2 text-sm outline-none transition-colors focus-visible:ring-[3px] focus-visible:ring-ring/50 [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\"\n\nconst emptyBase = \"py-6 text-center text-sm text-muted-foreground\"\n\n/* Bir vurgu dili: aktif satirin sinifi + istege bagli isaret dugumu. */\ninterface Accent {\n  /** The classes added to the active row. */\n  activeClassName: string\n  /** Extra class for the icon and text tone of a disabled row. */\n  idleClassName?: string\n  /** Aktif satirda render edilen isaret (layoutId ile akar). */\n  marker?: (layoutId: string, reduce: boolean) => React.ReactNode\n}\n\n/* Shared shell: every accent uses this, only Accent changes. */\nfunction AccentPalette({ props, accent }: { props: CommandProps; accent: Accent }) {\n  const {\n    className,\n    size = \"md\",\n    placeholder = \"Type a command...\",\n    items = defaultItems,\n  } = props\n  const p = usePalette(items)\n  const reduce = useReducedMotion() ?? false\n  const layoutId = `${p.uid}-accent`\n\n  return (\n    <div data-slot=\"styled-command\" className={cn(rootBase, paletteWidth[size], className)}>\n      <div className={inputRowBase}>\n        <Search className=\"size-4 shrink-0 text-muted-foreground\" />\n        <input\n          role=\"combobox\"\n          aria-expanded={true}\n          aria-controls={p.listId}\n          aria-autocomplete=\"list\"\n          aria-activedescendant={p.filtered.length > 0 ? p.optionId(p.active) : undefined}\n          value={p.query}\n          placeholder={placeholder}\n          onChange={(e) => p.setQuery(e.target.value)}\n          onKeyDown={p.onKeyDown}\n          className={inputBase}\n        />\n      </div>\n      <div id={p.listId} role=\"listbox\" aria-label=\"Command palette\" className={listBase}>\n        {p.filtered.length === 0 ? (\n          <p className={emptyBase}>No results found.</p>\n        ) : (\n          p.filtered.map((item, i) => {\n            const isActive = i === p.active\n            return (\n              <div\n                key={nodeText(item.label) || String(i)}\n                id={p.optionId(i)}\n                role=\"option\"\n                aria-selected={isActive}\n                tabIndex={-1}\n                onMouseEnter={() => p.setActive(i)}\n                onClick={() => p.select(i)}\n                className={cn(\n                  optionBase,\n                  isActive ? accent.activeClassName : accent.idleClassName\n                )}\n              >\n                {isActive && accent.marker ? accent.marker(layoutId, reduce) : null}\n                <span className=\"relative flex min-w-0 flex-1 items-center gap-2\">\n                  {item.icon}\n                  <span className=\"flex-1 truncate\">{item.label}</span>\n                </span>\n              </div>\n            )\n          })\n        )}\n      </div>\n    </div>\n  )\n}\n\nconst markerSpring = { type: \"spring\" as const, stiffness: 480, damping: 36 }\n\n/* BarCommand: secili satirin solunda primary bir bar. */\nexport function BarCommand(props: CommandProps) {\n  return (\n    <AccentPalette\n      props={props}\n      accent={{\n        activeClassName:\n          \"bg-[color-mix(in_oklab,var(--color-primary)_10%,transparent)] text-foreground [&_svg]:text-primary [&_i]:text-primary\",\n        idleClassName:\n          \"text-muted-foreground [&_svg]:text-muted-foreground [&_i]:text-muted-foreground\",\n        marker: (layoutId, reduce) => (\n          <motion.span\n            layoutId={reduce ? undefined : layoutId}\n            transition={reduce ? { duration: 0 } : markerSpring}\n            className=\"absolute inset-y-1 left-0 w-0.5 rounded-full bg-primary\"\n          />\n        ),\n      }}\n    />\n  )\n}\n\n/* GlowCommand: the selected row carries a primary glow halo. */\nexport function GlowCommand(props: CommandProps) {\n  return (\n    <AccentPalette\n      props={props}\n      accent={{\n        activeClassName:\n          \"bg-[color-mix(in_oklab,var(--color-primary)_14%,transparent)] text-foreground shadow-[0_0_18px_color-mix(in_oklab,var(--color-primary)_35%,transparent)] [&_svg]:text-primary [&_i]:text-primary\",\n        idleClassName:\n          \"text-muted-foreground [&_svg]:text-muted-foreground [&_i]:text-muted-foreground\",\n      }}\n    />\n  )\n}\n\n/* FillCommand: the selected row sits on a fully primary ground. */\nexport function FillCommand(props: CommandProps) {\n  return (\n    <AccentPalette\n      props={props}\n      accent={{\n        activeClassName:\n          \"text-primary-foreground [&_svg]:text-primary-foreground [&_i]:text-primary-foreground\",\n        idleClassName:\n          \"text-muted-foreground [&_svg]:text-muted-foreground [&_i]:text-muted-foreground\",\n        marker: (layoutId, reduce) => (\n          <motion.span\n            layoutId={reduce ? undefined : layoutId}\n            transition={reduce ? { duration: 0 } : markerSpring}\n            className=\"absolute inset-0 z-0 rounded-lg bg-primary\"\n          />\n        ),\n      }}\n    />\n  )\n}\n\n/* RingCommand: the selected row is framed by an inner primary ring. */\nexport function RingCommand(props: CommandProps) {\n  return (\n    <AccentPalette\n      props={props}\n      accent={{\n        activeClassName:\n          \"bg-[color-mix(in_oklab,var(--color-primary)_6%,transparent)] text-foreground ring-1 ring-[color-mix(in_oklab,var(--color-primary)_55%,transparent)] [&_svg]:text-primary [&_i]:text-primary\",\n        idleClassName:\n          \"text-muted-foreground [&_svg]:text-muted-foreground [&_i]:text-muted-foreground\",\n      }}\n    />\n  )\n}\n\n/* EdgeCommand: soldan saga sonen bir kenar gradyani + sag kenar isareti. */\nexport function EdgeCommand(props: CommandProps) {\n  return (\n    <AccentPalette\n      props={props}\n      accent={{\n        activeClassName:\n          \"bg-gradient-to-r from-[color-mix(in_oklab,var(--color-primary)_18%,transparent)] to-transparent text-foreground [&_svg]:text-primary [&_i]:text-primary\",\n        idleClassName:\n          \"text-muted-foreground [&_svg]:text-muted-foreground [&_i]:text-muted-foreground\",\n        marker: (layoutId, reduce) => (\n          <motion.span\n            layoutId={reduce ? undefined : layoutId}\n            transition={reduce ? { duration: 0 } : markerSpring}\n            className=\"absolute inset-y-1.5 right-1.5 w-1 rounded-full bg-[color-mix(in_oklab,var(--color-primary)_70%,transparent)]\"\n          />\n        ),\n      }}\n    />\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/command-accent.tsx"
    }
  ],
  "categories": [
    "styled",
    "command"
  ],
  "type": "registry:component"
}