{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "trigger-menu",
  "type": "registry:ui",
  "title": "Trigger Menu",
  "description": "Caret-anchored command or mention menu for text editors.",
  "dependencies": [
    "@base-ui/react@^1.7.0"
  ],
  "registryDependencies": [
    "https://control-ui.dev/r/core.json",
    "https://control-ui.dev/r/surface-variants.json"
  ],
  "files": [
    {
      "path": "src/registry/hooks/use-textarea-trigger-menu.ts",
      "target": "@components/control-ui/hooks/use-textarea-trigger-menu.ts",
      "type": "registry:hook",
      "content": "\"use client\";\n\nimport type { RefObject } from \"react\";\nimport { useEffect, useEffectEvent } from \"react\";\nimport { caretRectInTextarea, detectTrigger } from \"../lib/trigger-detect\";\nimport type { TriggerConfig, TriggerMenuItemData } from \"./use-trigger-menu\";\nimport { useTriggerMenu } from \"./use-trigger-menu\";\n\n// Same `triggers` config as ProseMirror path, so primitive works with no editor installed.\n\nfunction replaceRange(element: HTMLTextAreaElement, start: number, end: number, text: string) {\n  element.focus();\n  element.setSelectionRange(start, end);\n  // execCommand keeps caret, joins native undo, and fires real `input` event React can hear\n  const inserted = document.execCommand(\"insertText\", false, text);\n  if (inserted) return;\n  const next = element.value.slice(0, start) + text + element.value.slice(end);\n  const setter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, \"value\")?.set;\n  setter?.call(element, next);\n  element.dispatchEvent(new Event(\"input\", { bubbles: true }));\n  const caret = start + text.length;\n  element.setSelectionRange(caret, caret);\n}\n\nexport function useTextareaTriggerMenu<Item extends TriggerMenuItemData>(\n  ref: RefObject<HTMLTextAreaElement | null>,\n  options: { triggers: readonly TriggerConfig<Item>[] },\n) {\n  const controller = useTriggerMenu<Item>({\n    triggers: options.triggers,\n    onCommit: (item, trigger, match) => {\n      const element = ref.current;\n      if (!element) return;\n      const mode = trigger.insert ?? \"replace\";\n      const text = mode === \"none\" ? \"\" : (trigger.insertText?.(item) ?? `${trigger.char}${item.label} `);\n      replaceRange(element, match.start, match.end, text);\n      trigger.onSelect?.(item, { char: trigger.char, query: match.query });\n    },\n  });\n\n  const syncTrigger = useEffectEvent(() => {\n    const element = ref.current;\n    if (!element) return;\n    const caret = element.selectionStart ?? element.value.length;\n    const chars = options.triggers.map((trigger) => trigger.char);\n    const match = detectTrigger(element.value.slice(0, caret), chars);\n    controller.report(match, match === null ? null : caretRectInTextarea(element, match.start));\n  });\n\n  const handleKeyDown = useEffectEvent((event: KeyboardEvent) => {\n    if (controller.open && controller.handleKeyDown(event.key)) event.preventDefault();\n  });\n\n  const closeAfterBlur = useEffectEvent(() => {\n    controller.close();\n  });\n\n  useEffect(() => {\n    const element = ref.current;\n    if (!element) return;\n\n    function onKeyDown(event: KeyboardEvent) {\n      handleKeyDown(event);\n    }\n    function onBlur() {\n      window.setTimeout(closeAfterBlur, 120);\n    }\n\n    element.addEventListener(\"input\", syncTrigger);\n    element.addEventListener(\"keydown\", onKeyDown);\n    element.addEventListener(\"keyup\", syncTrigger);\n    element.addEventListener(\"click\", syncTrigger);\n    element.addEventListener(\"blur\", onBlur);\n    return () => {\n      element.removeEventListener(\"input\", syncTrigger);\n      element.removeEventListener(\"keydown\", onKeyDown);\n      element.removeEventListener(\"keyup\", syncTrigger);\n      element.removeEventListener(\"click\", syncTrigger);\n      element.removeEventListener(\"blur\", onBlur);\n    };\n  }, [ref]);\n\n  return controller;\n}\n"
    },
    {
      "path": "src/registry/hooks/use-trigger-menu.ts",
      "target": "@components/control-ui/hooks/use-trigger-menu.ts",
      "type": "registry:hook",
      "content": "import type { ReactNode } from \"react\";\nimport { useRef, useState } from \"react\";\nimport type { TriggerMatch } from \"../lib/trigger-detect\";\n\nexport type TriggerMenuItemData = {\n  id: string;\n  label: string;\n  description?: string;\n  icon?: ReactNode;\n  keywords?: readonly string[];\n  disabled?: boolean;\n  kind?: string;\n  image?: string;\n};\n\nexport type TriggerSelectContext = { char: string; query: string };\n\nexport type TriggerConfig<Item extends TriggerMenuItemData = TriggerMenuItemData> = {\n  char: string;\n  items: readonly Item[] | ((query: string) => readonly Item[]);\n  filter?: (item: Item, query: string) => boolean;\n  insert?: \"replace\" | \"none\";\n  insertText?: (item: Item) => string;\n  onSelect?: (item: Item, ctx: TriggerSelectContext) => void;\n};\n\n// Never touches DOM or editor: binding feeds state through `report` and performs insertion through `onCommit`,\n// which is what lets one popup serve plain <textarea> and ProseMirror editor unchanged.\n\nexport type UseTriggerMenuOptions<Item extends TriggerMenuItemData> = {\n  triggers: readonly TriggerConfig<Item>[];\n  // backend-specific mutation for chosen item — mention replace, slash-command, and so on\n  onCommit: (item: Item, trigger: TriggerConfig<Item>, match: TriggerMatch) => void;\n};\n\nexport type TriggerMenuController<Item extends TriggerMenuItemData> = {\n  open: boolean;\n  items: readonly Item[];\n  activeIndex: number;\n  anchorRect: DOMRect | null;\n  activeChar: string | null;\n  query: string;\n  /** Binding → engine: publish current trigger match (or null) and caret rect to anchor to. */\n  report: (match: TriggerMatch | null, anchorRect: DOMRect | null) => void;\n  /** Binding → engine: route keydown while open. Returns true when engine consumed key. */\n  handleKeyDown: (key: string) => boolean;\n  /** View → engine. */\n  setActiveIndex: (index: number) => void;\n  select: (item: Item) => void;\n  close: () => void;\n  setOpen: (open: boolean) => void;\n};\n\ntype MenuState = { open: boolean; char: string | null; query: string; anchorRect: DOMRect | null; activeIndex: number };\n\nconst CLOSED: MenuState = { open: false, char: null, query: \"\", anchorRect: null, activeIndex: 0 };\n\nfunction matchesQuery(item: TriggerMenuItemData, query: string): boolean {\n  if (query === \"\") return true;\n  const needle = query.toLowerCase();\n  if (item.label.toLowerCase().includes(needle)) return true;\n  return (item.keywords ?? []).some((keyword) => keyword.toLowerCase().includes(needle));\n}\n\nfunction resolveItems<Item extends TriggerMenuItemData>(trigger: TriggerConfig<Item>, query: string): readonly Item[] {\n  if (typeof trigger.items === \"function\") return trigger.items(query);\n  const filter = trigger.filter ?? matchesQuery;\n  return trigger.items.filter((item) => filter(item, query));\n}\n\nexport function useTriggerMenu<Item extends TriggerMenuItemData>({\n  triggers,\n  onCommit,\n}: UseTriggerMenuOptions<Item>): TriggerMenuController<Item> {\n  const [state, setState] = useState<MenuState>(CLOSED);\n  const lastMatch = useRef<TriggerMatch | null>(null);\n\n  const activeTrigger = state.char === null ? null : (triggers.find((trigger) => trigger.char === state.char) ?? null);\n  const items = activeTrigger === null ? [] : resolveItems(activeTrigger, state.query);\n\n  function close() {\n    lastMatch.current = null;\n    setState(CLOSED);\n  }\n\n  function select(item: Item) {\n    const match = lastMatch.current;\n    if (activeTrigger !== null && match !== null) onCommit(item, activeTrigger, match);\n    close();\n  }\n\n  function report(match: TriggerMatch | null, anchorRect: DOMRect | null) {\n    lastMatch.current = match;\n    const open = match !== null && triggers.some((trigger) => trigger.char === match.char);\n    setState((current) => {\n      if (!open || match === null) return CLOSED;\n      const activeIndex = current.char === match.char && current.query === match.query ? current.activeIndex : 0;\n      return { open: true, char: match.char, query: match.query, anchorRect, activeIndex };\n    });\n  }\n\n  function handleKeyDown(key: string): boolean {\n    if (!state.open) return false;\n    if (key === \"ArrowDown\") {\n      setState((current) => ({\n        ...current,\n        activeIndex: items.length === 0 ? 0 : (current.activeIndex + 1) % items.length,\n      }));\n      return true;\n    }\n    if (key === \"ArrowUp\") {\n      setState((current) => ({\n        ...current,\n        activeIndex: items.length === 0 ? 0 : (current.activeIndex - 1 + items.length) % items.length,\n      }));\n      return true;\n    }\n    if (key === \"Enter\" || key === \"Tab\") {\n      const item = items[state.activeIndex];\n      if (item && !item.disabled) select(item);\n      // Swallow Enter/Tab even on empty list so editor doesn't newline/blur while menu is up.\n      return true;\n    }\n    if (key === \"Escape\") {\n      close();\n      return true;\n    }\n    return false;\n  }\n\n  function setOpen(open: boolean) {\n    if (!open) close();\n  }\n\n  function setActiveIndex(activeIndex: number) {\n    setState((current) => ({ ...current, activeIndex }));\n  }\n\n  return {\n    open: state.open,\n    items,\n    activeIndex: state.activeIndex,\n    anchorRect: state.anchorRect,\n    activeChar: state.char,\n    query: state.query,\n    report,\n    handleKeyDown,\n    setActiveIndex,\n    select,\n    close,\n    setOpen,\n  };\n}\n"
    },
    {
      "path": "src/registry/knob-contracts/popup-knobs.ts",
      "target": "@components/control-ui/knob-contracts/popup-knobs.ts",
      "type": "registry:component",
      "content": "// Generated from src/registry/sources/control-ui/recipes/popup.css by scripts/gen-knob-contracts.ts — run `bun run sync:knobs`.\nexport const popupKnobs = [\n  \"--cui-popup-radius\",\n  \"--cui-popup-background\",\n  \"--cui-popup-foreground\",\n  \"--cui-popup-border-color\",\n  \"--cui-popup-border-width\",\n  \"--cui-popup-shadow\",\n  \"--cui-popup-backdrop-filter\",\n  \"--cui-popup-backdrop-background\",\n  \"--cui-popup-item-radius\",\n  \"--cui-popup-item-foreground\",\n  \"--cui-popup-item-highlight-background\",\n  \"--cui-popup-item-highlight-foreground\",\n  \"--cui-popup-item-highlight-muted-foreground\",\n  \"--cui-popup-item-disabled-opacity\",\n  \"--cui-popup-separator-color\",\n  \"--cui-popup-shortcut-foreground\",\n] as const;\nexport type PopupKnobStyle = Partial<Record<(typeof popupKnobs)[number], string>>;\n"
    },
    {
      "path": "src/registry/lib/trigger-detect.ts",
      "target": "@components/control-ui/lib/trigger-detect.ts",
      "type": "registry:lib",
      "content": "export type TriggerMatch = {\n  /** trigger character that opened menu (e.g. \"/\" or \"@\"). */\n  char: string;\n  /** Text typed after trigger char, up to caret (never contains whitespace). */\n  query: string;\n  /** Offset of trigger char in scanned text; token spans [start, end). */\n  start: number;\n  /** Offset of caret in scanned text (exclusive end of trigger token). */\n  end: number;\n};\n\nconst WHITESPACE = new Set([\" \", \"\\n\", \"\\t\", \" \"]);\n\n// only fires when char sits at start or after whitespace, so `path/to` never triggers on \"/\"\nexport function detectTrigger(textBeforeCaret: string, triggerChars: readonly string[]): TriggerMatch | null {\n  const triggerSet = new Set(triggerChars);\n  for (let i = textBeforeCaret.length - 1; i >= 0; i -= 1) {\n    const char = textBeforeCaret.at(i);\n    if (char === undefined) return null;\n    if (WHITESPACE.has(char)) return null;\n    if (triggerSet.has(char)) {\n      const preceding = i === 0 ? \"\" : (textBeforeCaret.at(i - 1) ?? \"\");\n      if (preceding === \"\" || WHITESPACE.has(preceding)) {\n        return { char, query: textBeforeCaret.slice(i + 1), start: i, end: textBeforeCaret.length };\n      }\n      return null;\n    }\n  }\n  return null;\n}\n\n// layout-affecting properties mirrored onto measuring div so its caret column matches textarea's\nconst MIRROR_PROPERTIES = [\n  \"box-sizing\",\n  \"width\",\n  \"font-family\",\n  \"font-size\",\n  \"font-weight\",\n  \"font-style\",\n  \"font-variant\",\n  \"letter-spacing\",\n  \"text-transform\",\n  \"text-indent\",\n  \"line-height\",\n  \"tab-size\",\n  \"padding-top\",\n  \"padding-right\",\n  \"padding-bottom\",\n  \"padding-left\",\n  \"border-top-width\",\n  \"border-right-width\",\n  \"border-bottom-width\",\n  \"border-left-width\",\n];\n\n// textarea exposes no caret geometry, so text is mirrored into off-screen div and marker's box is read at offset\nexport function caretRectInTextarea(element: HTMLTextAreaElement, offset: number): DOMRect {\n  const doc = element.ownerDocument;\n  const computed = doc.defaultView?.getComputedStyle(element);\n  const mirror = doc.createElement(\"div\");\n  const style = mirror.style;\n  style.position = \"absolute\";\n  style.visibility = \"hidden\";\n  style.whiteSpace = \"pre-wrap\";\n  style.overflowWrap = \"break-word\";\n  style.top = \"0\";\n  style.left = \"-9999px\";\n  if (computed) {\n    for (const property of MIRROR_PROPERTIES) style.setProperty(property, computed.getPropertyValue(property));\n  }\n\n  mirror.textContent = element.value.slice(0, offset);\n  const marker = doc.createElement(\"span\");\n  // must stay non-empty or it has no box at very end of text\n  marker.textContent = element.value.slice(offset) || \".\";\n  mirror.appendChild(marker);\n  doc.body.appendChild(mirror);\n\n  const elementRect = element.getBoundingClientRect();\n  const mirrorRect = mirror.getBoundingClientRect();\n  const markerRect = marker.getBoundingClientRect();\n  const lineHeight = computed ? Number.parseFloat(computed.lineHeight) : 0;\n  const height = markerRect.height || (Number.isFinite(lineHeight) ? lineHeight : 16);\n  const x = elementRect.left + (markerRect.left - mirrorRect.left) - element.scrollLeft;\n  const y = elementRect.top + (markerRect.top - mirrorRect.top) - element.scrollTop;\n\n  doc.body.removeChild(mirror);\n  return new DOMRect(x, y, 1, height);\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/recipes/popup-controls.css",
      "target": "@components/control-ui/styles/recipes/popup-controls.css",
      "type": "registry:file",
      "content": "@layer components {\n  :where([data-control-family=\"popup\"][data-popup-kind=\"alert-dialog\"][data-slot=\"content\"]) {\n    outline-style: none;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"hover-card\"][data-slot=\"positioner\"]) {\n    outline-style: none;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"navigation-menu\"][data-slot=\"link\"]) {\n    text-decoration-line: none;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"menubar\"][data-slot=\"sub-trigger-indicator\"]) {\n    line-height: 1;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"rich-tooltip\"][data-slot=\"content\"]) {\n    text-align: left;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"rich-tooltip\"][data-slot=\"content\"][data-starting-style]) {\n    --_popup-rich-tooltip-content-opacity: 0%;\n    opacity: var(--_popup-rich-tooltip-content-opacity);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"rich-tooltip\"][data-slot=\"content\"][data-ending-style]) {\n    --_popup-rich-tooltip-content-opacity: 0%;\n    opacity: var(--_popup-rich-tooltip-content-opacity);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"rich-tooltip\"][data-slot=\"positioner\"]) {\n    outline-style: none;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"dialog\"][data-slot=\"content\"]) {\n    outline-style: none;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"color-picker\"][data-slot=\"positioner\"]) {\n    outline-style: none;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"context-menu\"][data-slot=\"sub-trigger-indicator\"]) {\n    line-height: 1;\n  }\n\n  :where([data-control-family=\"button\"][data-slot=\"root\"][data-popup-part=\"close\"][data-icon-only=\"true\"]) {\n    --_popup-button-root-close-opacity: 70%;\n    opacity: var(--_popup-button-root-close-opacity);\n  }\n\n  @media (hover: hover) {\n    :where([data-control-family=\"button\"][data-slot=\"root\"][data-popup-part=\"close\"][data-icon-only=\"true\"]:hover) {\n      --_popup-button-root-close-opacity: 100%;\n      opacity: var(--_popup-button-root-close-opacity);\n    }\n  }\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/recipes/popup-lists.css",
      "target": "@components/control-ui/styles/recipes/popup-lists.css",
      "type": "registry:file",
      "content": "@layer components {\n  :where([data-control-family=\"popup\"][data-popup-kind=\"model-switcher\"][data-slot=\"hint\"]) {\n    font-size: var(--text-micro);\n    color: var(--muted-foreground);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"trigger-menu\"][data-slot=\"group-label\"]) {\n    font-size: var(--text-micro);\n    font-weight: var(--font-weight-medium);\n    letter-spacing: 0.08em;\n    color: var(--muted-foreground);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"trigger-menu\"][data-slot=\"empty\"]) {\n    font-size: var(--text-body);\n    color: var(--muted-foreground);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"trigger-menu\"][data-slot=\"icon\"]) {\n    color: var(--muted-foreground);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"trigger-menu\"][data-slot=\"positioner\"]) {\n    outline-style: none;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"combobox\"][data-slot=\"group-label\"]) {\n    font-size: var(--text-caption);\n    font-weight: var(--font-weight-medium);\n    color: var(--muted-foreground);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"combobox\"][data-slot=\"item-indicator\"]) {\n    color: var(--foreground);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"combobox\"][data-slot=\"empty\"]) {\n    text-align: center;\n    font-size: var(--text-body);\n    color: var(--muted-foreground);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"combobox\"][data-slot=\"positioner\"]) {\n    outline-style: none;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"command\"][data-slot=\"group\"] [cmdk-group-heading]) {\n    font-size: var(--text-caption);\n    font-weight: var(--font-weight-medium);\n    letter-spacing: 0.08em;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"command\"][data-slot=\"empty\"]) {\n    text-align: center;\n    font-size: var(--text-body);\n    color: var(--muted-foreground);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"command\"][data-slot=\"input-wrapper\"]) {\n    border-block-end: 1px solid var(--cui-popup-separator-color);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"command\"][data-slot=\"input\"]) {\n    background: transparent;\n    color: var(--foreground);\n    outline-style: none;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"command\"][data-slot=\"input\"])::placeholder,\n  :where([data-control-family=\"popup\"][data-popup-kind=\"command\"] [cmdk-group-heading]) {\n    color: var(--muted-foreground);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"command\"][data-slot=\"input\"]:disabled) {\n    opacity: 0.5;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"command\"][data-slot=\"group\"]) {\n    color: var(--foreground);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"command\"][data-slot=\"input-icon\"]) {\n    color: var(--muted-foreground);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"command\"][data-slot=\"dialog-root\"]) {\n    transition-property: grid-template-rows;\n    transition-duration: var(--duration-slow);\n    transition-timing-function: var(--ease-emphasized);\n    transition-delay: var(--duration-fast);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"autocomplete\"][data-slot=\"group-label\"]) {\n    font-size: var(--text-caption);\n    font-weight: var(--font-weight-medium);\n    color: var(--muted-foreground);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"autocomplete\"][data-slot=\"empty\"]) {\n    text-align: center;\n    font-size: var(--text-body);\n    color: var(--muted-foreground);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"autocomplete\"][data-slot=\"positioner\"]) {\n    outline-style: none;\n  }\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/recipes/popup-motion.css",
      "target": "@components/control-ui/styles/recipes/popup-motion.css",
      "type": "registry:file",
      "content": "@layer components {\n  :where([data-control-family=\"popup\"][data-popup-kind=\"sheet\"][data-popup-part=\"surface\"]) {\n    outline-style: none;\n    transition-property: translate;\n    transition-duration: var(--duration-base);\n    transition-timing-function: var(--ease-emphasized);\n    border-radius: 0;\n    border-style: solid;\n    border-width: 0px;\n  }\n\n  :where(\n    [data-control-family=\"popup\"][data-popup-kind=\"sheet\"][data-popup-part=\"surface\"][data-side=\"left\"]:is(\n      [data-starting-style],\n      [data-ending-style]\n    )\n  ) {\n    translate: -100% 0;\n  }\n\n  :where(\n    [data-control-family=\"popup\"][data-popup-kind=\"sheet\"][data-popup-part=\"surface\"][data-side=\"right\"]:is(\n      [data-starting-style],\n      [data-ending-style]\n    )\n  ) {\n    translate: 100% 0;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"tooltip\"][data-slot=\"arrow-shape\"]) {\n    fill: currentcolor;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"tooltip\"][data-slot=\"content\"]) {\n    font-size: var(--text-xs);\n    line-height: var(--text-xs--line-height);\n    text-wrap: balance;\n    outline-style: none;\n    --_popup-tooltip-content-transition-property: opacity, scale;\n    transition-property: var(--_popup-tooltip-content-transition-property);\n    transition-timing-function: var(--ease-standard);\n    transition-duration: var(--duration-fast);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"tooltip\"][data-slot=\"content\"][data-instant]) {\n    --_popup-tooltip-content-transition-property: none;\n    transition-property: var(--_popup-tooltip-content-transition-property);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"tooltip\"][data-slot=\"content\"][data-ending-style]) {\n    --_popup-tooltip-content-opacity: 0%;\n    opacity: var(--_popup-tooltip-content-opacity);\n    --_popup-tooltip-content-scale: 95% 95%;\n    scale: var(--_popup-tooltip-content-scale);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"tooltip\"][data-slot=\"content\"][data-starting-style]) {\n    --_popup-tooltip-content-opacity: 0%;\n    opacity: var(--_popup-tooltip-content-opacity);\n    --_popup-tooltip-content-scale: 95% 95%;\n    scale: var(--_popup-tooltip-content-scale);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"tooltip\"][data-slot=\"positioner\"]) {\n    outline-style: none;\n  }\n\n  :where(\n    [data-control-family=\"popup\"][data-popup-kind=\"tooltip\"][data-slot=\"content\"][data-popup-part=\"surface\"]:not([data-arrow=\"true\"])\n  ) {\n    --_popup-tooltip-content-radius: var(--cui-popup-radius);\n    border-radius: var(--_popup-tooltip-content-radius);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"tooltip\"][data-slot=\"content\"][data-popup-part=\"surface\"][data-arrow=\"true\"]) {\n    --_popup-tooltip-content-radius: clamp(0px, var(--cui-popup-radius), 3px);\n    border-radius: var(--_popup-tooltip-content-radius);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"tooltip\"][data-slot=\"arrow\"][data-side=\"top\"]) {\n    --_popup-tooltip-arrow-rotate: 180deg;\n    rotate: var(--_popup-tooltip-arrow-rotate);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"tooltip\"][data-slot=\"arrow\"][data-side=\"left\"]) {\n    --_popup-tooltip-arrow-rotate: 90deg;\n    rotate: var(--_popup-tooltip-arrow-rotate);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"tooltip\"][data-slot=\"arrow\"][data-side=\"right\"]) {\n    --_popup-tooltip-arrow-rotate: calc(90deg * -1);\n    rotate: var(--_popup-tooltip-arrow-rotate);\n  }\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/recipes/popup.css",
      "target": "@components/control-ui/styles/recipes/popup.css",
      "type": "registry:file",
      "content": "@layer components {\n  :where([data-control-family=\"popup\"][data-popup-part=\"surface\"]),\n  :where([data-control-family=\"popup\"][data-popup-part=\"list-surface\"]),\n  :where([data-control-family=\"popup\"][data-popup-part=\"bar\"]) {\n    --cui-popup-radius: var(--radius-popover);\n    --cui-popup-background: var(--popover);\n    --cui-popup-foreground: var(--popover-foreground);\n    --cui-popup-border-color: var(--border);\n    --cui-popup-border-width: 1px;\n    --cui-popup-shadow: var(--shadow-pop);\n    --cui-popup-backdrop-filter: blur(var(--backdrop-blur-popover));\n    --cui-popup-item-radius: var(--radius-popup-item);\n    --cui-popup-item-foreground: var(--foreground);\n    --cui-popup-item-highlight-background: oklch(from var(--foreground) l c h / 0.06);\n    --cui-popup-item-highlight-foreground: var(--cui-popup-item-foreground);\n    --cui-popup-item-highlight-muted-foreground: var(--muted-foreground);\n    --cui-popup-item-disabled-opacity: 0.4;\n    --cui-popup-separator-color: var(--border);\n    --cui-popup-shortcut-foreground: var(--muted-foreground);\n    --_popup-transform-origin: var(--transform-origin);\n    border-radius: var(--cui-popup-radius);\n    background-color: var(--cui-popup-background);\n    box-shadow:\n      inset 0 0 0 var(--cui-popup-border-width) var(--cui-popup-border-color),\n      var(--cui-popup-shadow);\n    color: var(--cui-popup-foreground);\n    outline: none;\n    -webkit-backdrop-filter: var(--cui-popup-backdrop-filter, none);\n    backdrop-filter: var(--cui-popup-backdrop-filter, none);\n    transform-origin: var(--_popup-transform-origin);\n  }\n  :where([data-control-family=\"popup\"][data-popup-part=\"surface\"]:not([data-popup-static]):not([data-slot=\"viewport\"])),\n  :where([data-control-family=\"popup\"][data-popup-part=\"list-surface\"]) {\n    transition-property: opacity, scale;\n    transition-duration: var(--duration-base);\n    transition-timing-function: var(--ease-emphasized);\n    transition-behavior: allow-discrete;\n  }\n  :where(\n    [data-control-family=\"popup\"][data-popup-part=\"surface\"]:not(\n      :is([data-popup-kind=\"sheet\"], [data-popup-kind=\"drawer\"], [data-popup-kind=\"toast\"])\n    ):not([data-slot=\"viewport\"]):where([data-starting-style], [data-ending-style])\n  ),\n  :where([data-control-family=\"popup\"][data-popup-part=\"list-surface\"]:where([data-starting-style], [data-ending-style])) {\n    scale: 0.95;\n    opacity: 0;\n  }\n  @starting-style {\n    :where(\n        [data-control-family=\"popup\"][data-popup-part=\"surface\"]:not(\n          :is([data-popup-kind=\"sheet\"], [data-popup-kind=\"drawer\"], [data-popup-kind=\"toast\"])\n        ):not([data-slot=\"viewport\"])\n      ),\n    :where([data-control-family=\"popup\"][data-popup-part=\"list-surface\"]) {\n      scale: 0.95;\n      opacity: 0;\n    }\n  }\n  :where([data-control-family=\"popup\"][data-popup-part=\"backdrop\"]) {\n    --cui-popup-backdrop-background: oklch(from var(--foreground) l c h / var(--overlay-opacity));\n    background-color: var(--cui-popup-backdrop-background);\n    -webkit-backdrop-filter: blur(var(--backdrop-blur-overlay));\n    backdrop-filter: blur(var(--backdrop-blur-overlay));\n    transition: opacity var(--duration-base) var(--ease-standard);\n  }\n  :where(.dark [data-control-family=\"popup\"][data-popup-part=\"backdrop\"]) {\n    --cui-popup-backdrop-background: oklch(from var(--background) l c h / var(--overlay-opacity));\n  }\n  :where([data-control-family=\"popup\"][data-popup-part=\"backdrop\"]:is([data-starting-style], [data-ending-style])) {\n    opacity: 0;\n  }\n  :where([data-control-family=\"popup\"][data-popup-part=\"list-surface\"]) {\n    padding: var(--popover-padding);\n  }\n  :where([data-control-family=\"popup\"][data-popup-part=\"bar\"]) {\n    --cui-popup-radius: var(--radius-control);\n    --cui-popup-background: var(--card);\n    --cui-popup-shadow: var(--shadow-xs);\n  }\n  :where([data-control-family=\"popup\"][data-popup-part=\"surface\"][data-surface=\"modal\"]) {\n    --cui-popup-radius: var(--radius-panel);\n    --cui-popup-shadow: var(--shadow-modal);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"tooltip\"][data-popup-part=\"surface\"]) {\n    --cui-popup-radius: var(--radius-control);\n    --cui-popup-background: var(--foreground);\n    --cui-popup-foreground: var(--background);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"sheet\"][data-popup-part=\"surface\"]) {\n    --cui-popup-radius: 0px;\n    --cui-popup-shadow: var(--shadow-modal);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"dialog\"][data-slot=\"title\"]),\n  :where([data-control-family=\"popup\"][data-popup-kind=\"alert-dialog\"][data-slot=\"title\"]) {\n    font-size: var(--text-heading-3);\n    font-weight: 600;\n    line-height: 1;\n    letter-spacing: -0.025em;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"dialog\"][data-slot=\"description\"]),\n  :where([data-control-family=\"popup\"][data-popup-kind=\"alert-dialog\"][data-slot=\"description\"]) {\n    color: var(--muted-foreground);\n    font-size: var(--text-body);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"sheet\"][data-slot=\"title\"]) {\n    font-weight: 600;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"sheet\"][data-slot=\"description\"]) {\n    color: var(--muted-foreground);\n    font-size: var(--text-body);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"tooltip\"][data-slot=\"arrow\"]) {\n    color: var(--cui-popup-background);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-part=\"item\"]),\n  :where([data-control-family=\"popup\"][data-popup-part=\"navigation-link\"]) {\n    cursor: pointer;\n    border-radius: var(--cui-popup-item-radius);\n    color: var(--cui-popup-item-foreground);\n    font-size: var(--text-body);\n    outline: none;\n    padding-block: 0.25rem;\n    padding-inline: calc(var(--padding-x) * 0.5);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-part=\"navigation-link\"]) {\n    font-size: var(--text-body);\n    transition-property: color, background-color, box-shadow, translate;\n    transition-duration: var(--duration-fast);\n    transition-timing-function: var(--ease-standard);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-part=\"navigation-link\"][data-variant=\"compact\"]) {\n    color: var(--muted-foreground);\n    font-size: var(--text-label);\n    font-weight: 500;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-part=\"navigation-link\"]:where(:hover, :focus-visible, [data-active])) {\n    background-color: var(--cui-popup-item-highlight-background);\n    color: var(--foreground);\n  }\n\n  :where(\n    [data-control-family=\"popup\"][data-popup-part=\"item\"]:where(\n      [data-highlighted],\n      [data-selected]:not([data-selected=\"false\"]),\n      [data-popup-open]\n    )\n  ) {\n    --cui-popup-shortcut-foreground: var(--cui-popup-item-highlight-foreground);\n    --muted-foreground: var(--cui-popup-item-highlight-muted-foreground);\n    background-color: var(--cui-popup-item-highlight-background);\n    color: var(--cui-popup-item-highlight-foreground);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-part=\"item\"]:is([data-disabled]:not([data-disabled=\"false\"]), [data-disabled=\"true\"])) {\n    cursor: not-allowed;\n    opacity: var(--cui-popup-item-disabled-opacity);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-part=\"label\"]) {\n    color: var(--muted-foreground);\n    font-size: var(--text-micro);\n    font-weight: 500;\n    letter-spacing: 0.08em;\n    text-transform: uppercase;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-part=\"separator\"]) {\n    background-color: var(--cui-popup-separator-color);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-part=\"shortcut\"]) {\n    --_popup-shortcut-font-size: var(--text-body);\n    color: var(--cui-popup-shortcut-foreground);\n    font-size: var(--_popup-shortcut-font-size);\n    letter-spacing: 0.02em;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"command\"][data-slot=\"shortcut\"]) {\n    --_popup-shortcut-font-size: var(--text-label);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"select\"][data-slot=\"icon\"]),\n  :where([data-control-family=\"popup\"][data-popup-kind=\"navigation-menu\"][data-slot=\"icon\"]) {\n    color: var(--muted-foreground);\n    transition-property: rotate;\n    transition-duration: var(--duration-base);\n    transition-timing-function: var(--ease-emphasized);\n  }\n\n  :where(\n    [data-control-family=\"button\"][data-popup-kind=\"select\"][data-slot=\"trigger\"][data-popup-open]\n      [data-control-family=\"popup\"][data-popup-kind=\"select\"][data-slot=\"icon\"]\n  ),\n  :where(\n    [data-control-family=\"button\"][data-popup-kind=\"navigation-menu\"][data-slot=\"trigger\"][data-popup-open]\n      :where([data-control-family=\"popup\"][data-popup-kind=\"navigation-menu\"][data-slot=\"icon\"])\n  ) {\n    rotate: 180deg;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"select\"][data-slot=\"item-indicator\"]) {\n    color: inherit;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"context-menu\"][data-slot=\"radio-indicator\"]) {\n    border-radius: 9999px;\n    background-color: currentColor;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"popover\"][data-slot=\"title\"]) {\n    font-size: var(--text-body);\n    font-weight: 600;\n    line-height: 1;\n    letter-spacing: -0.01em;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"popover\"][data-slot=\"description\"]) {\n    color: var(--muted-foreground);\n    font-size: var(--text-body);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"navigation-menu\"][data-slot=\"positioner\"]) {\n    transition-property: inset-block-start, inset-inline-start, inset-block-end, inset-inline-end;\n    transition-duration: var(--duration-base);\n    transition-timing-function: var(--ease-emphasized);\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"navigation-menu\"][data-slot=\"popup\"]) {\n    outline: none;\n    --_popup-transform-origin: var(--transform-origin);\n    transform-origin: var(--_popup-transform-origin);\n    transition-property: opacity, inline-size, block-size, scale;\n    transition-duration: var(--duration-base);\n    transition-timing-function: var(--ease-emphasized);\n  }\n\n  :where(\n    [data-control-family=\"popup\"][data-popup-kind=\"navigation-menu\"][data-slot=\"popup\"]:is([data-starting-style], [data-ending-style])\n  ) {\n    scale: 0.95;\n    opacity: 0;\n  }\n\n  :where([data-control-family=\"popup\"][data-popup-kind=\"navigation-menu\"][data-slot=\"content\"]) {\n    transition-property: opacity, translate;\n    transition-duration: var(--duration-base);\n    transition-timing-function: var(--ease-emphasized);\n  }\n\n  :where(\n    [data-control-family=\"popup\"][data-popup-kind=\"navigation-menu\"][data-slot=\"content\"]:is([data-starting-style], [data-ending-style])\n  ) {\n    opacity: 0;\n  }\n\n  :where(\n    [data-control-family=\"popup\"][data-popup-kind=\"navigation-menu\"][data-slot=\"content\"][data-starting-style][data-activation-direction=\"left\"]\n  ),\n  :where(\n    [data-control-family=\"popup\"][data-popup-kind=\"navigation-menu\"][data-slot=\"content\"][data-ending-style][data-activation-direction=\"right\"]\n  ) {\n    translate: -0.75rem 0;\n  }\n\n  :where(\n    [data-control-family=\"popup\"][data-popup-kind=\"navigation-menu\"][data-slot=\"content\"][data-starting-style][data-activation-direction=\"right\"]\n  ),\n  :where(\n    [data-control-family=\"popup\"][data-popup-kind=\"navigation-menu\"][data-slot=\"content\"][data-ending-style][data-activation-direction=\"left\"]\n  ) {\n    translate: 0.75rem 0;\n  }\n}\n\n@property --cui-popup-radius {\n  syntax: \"*\";\n  inherits: true;\n}\n\n@property --cui-popup-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-popup-foreground {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-popup-border-color {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-popup-border-width {\n  syntax: \"<length>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-popup-shadow {\n  syntax: \"*\";\n  inherits: true;\n}\n\n@property --cui-popup-backdrop-filter {\n  syntax: \"*\";\n  inherits: true;\n}\n\n@property --cui-popup-backdrop-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-popup-item-radius {\n  syntax: \"<length-percentage>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-popup-item-foreground {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-popup-item-highlight-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-popup-item-highlight-foreground {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-popup-item-highlight-muted-foreground {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-popup-item-disabled-opacity {\n  syntax: \"<number>\";\n  inherits: true;\n  initial-value: 1;\n}\n\n@property --cui-popup-separator-color {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-popup-shortcut-foreground {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/ui/trigger-menu.tsx",
      "target": "@components/control-ui/ui/trigger-menu.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport { Popover as PopoverPrimitive } from \"@base-ui/react/popover\";\nimport type { ComponentProps, CSSProperties, ReactNode } from \"react\";\nimport type { OpenChangeEventDetails } from \"@/components/control-ui/control-props\";\nimport type { PopupKnobStyle } from \"@/components/control-ui/knob-contracts/popup-knobs\";\nimport { cn } from \"@/components/control-ui/lib/cn\";\nimport { skinEffects, skinId } from \"@/components/control-ui/skin\";\nimport { popupItemStructureClasses } from \"@/components/control-ui/surface-variants\";\n\nexport type TriggerMenuProps = {\n  open: boolean;\n  onOpenChange?: (open: boolean, eventDetails: OpenChangeEventDetails) => void;\n  anchorRect: DOMRect | null;\n  side?: \"top\" | \"bottom\";\n  align?: \"start\" | \"center\" | \"end\";\n  sideOffset?: number;\n  className?: string;\n  children?: ReactNode;\n} & { style?: CSSProperties & PopupKnobStyle };\n\nexport type TriggerMenuListProps = ComponentProps<\"div\"> & { style?: CSSProperties & PopupKnobStyle };\n\nexport type TriggerMenuItemProps = Omit<\n  Omit<ComponentProps<\"div\">, \"onSelect\"> & {\n    active?: boolean;\n    disabled?: boolean;\n  },\n  \"style\"\n> & { style?: CSSProperties & PopupKnobStyle };\n\nexport type TriggerMenuEmptyProps = Omit<ComponentProps<\"div\">, \"style\"> & { style?: CSSProperties & PopupKnobStyle };\n\nexport type TriggerMenuGroupProps = ComponentProps<\"div\"> & { style?: CSSProperties & PopupKnobStyle };\n\nexport type TriggerMenuGroupLabelProps = Omit<ComponentProps<\"div\">, \"style\"> & { style?: CSSProperties & PopupKnobStyle };\n\nexport type TriggerMenuIconProps = Omit<ComponentProps<\"span\">, \"style\"> & { style?: CSSProperties & PopupKnobStyle };\n\n// Controlled by headless engine and anchored to virtual caret rect, with no trigger button of its own.\n// initialFocus/finalFocus={false} keep focus in editor, so arrows and Enter keep flowing to caret while menu is up.\n\nexport function TriggerMenu({\n  open,\n  onOpenChange,\n  anchorRect,\n  side = \"top\",\n  align = \"start\",\n  sideOffset = 8,\n  className,\n  children,\n}: TriggerMenuProps) {\n  return (\n    <PopoverPrimitive.Root open={open} onOpenChange={(next, eventDetails) => onOpenChange?.(next, eventDetails)} modal={false}>\n      <PopoverPrimitive.Portal>\n        {/* portal escapes both token scope and ChatLayout's overflow clip, so scope is re-asserted here */}\n        <PopoverPrimitive.Positioner\n          data-control-ui=\"trigger-menu\"\n          data-popup-kind=\"trigger-menu\"\n          data-control-family=\"popup\"\n          data-slot=\"positioner\"\n          data-skin={skinId()}\n          data-effects={skinEffects()}\n          anchor={anchorRect === null ? undefined : () => ({ getBoundingClientRect: () => anchorRect })}\n          side={side}\n          align={align}\n          sideOffset={sideOffset}\n          className=\"z-[80]\"\n        >\n          <PopoverPrimitive.Popup\n            data-control-ui=\"trigger-menu\"\n            data-popup-kind=\"trigger-menu\"\n            data-control-family=\"popup\"\n            data-slot=\"root\"\n            data-surface=\"floating\"\n            data-popup-part=\"list-surface\"\n            initialFocus={false}\n            finalFocus={false}\n            className={cn(\"max-h-[min(18rem,var(--available-height))] w-64 max-w-[var(--available-width)] overflow-y-auto\", className)}\n          >\n            {children}\n          </PopoverPrimitive.Popup>\n        </PopoverPrimitive.Positioner>\n      </PopoverPrimitive.Portal>\n    </PopoverPrimitive.Root>\n  );\n}\n\nexport function TriggerMenuList({ className, ...props }: TriggerMenuListProps) {\n  return (\n    <div\n      data-control-ui=\"trigger-menu\"\n      data-popup-kind=\"trigger-menu\"\n      data-slot=\"list\"\n      data-control-family=\"popup\"\n      data-popup-part=\"list-content\"\n      role=\"listbox\"\n      className={cn(\"flex flex-col gap-0.5\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function TriggerMenuItem({ className, active = false, disabled = false, onMouseDown, ...props }: TriggerMenuItemProps) {\n  return (\n    <div\n      data-control-ui=\"trigger-menu\"\n      data-popup-kind=\"trigger-menu\"\n      data-control-family=\"popup\"\n      data-slot=\"item\"\n      data-popup-part=\"item\"\n      role=\"option\"\n      // driven by editor's keyboard, not tab focus, so -1 keeps rows out of tab order\n      tabIndex={-1}\n      aria-selected={active}\n      aria-disabled={disabled || undefined}\n      data-highlighted={active ? \"\" : undefined}\n      data-disabled={disabled ? \"\" : undefined}\n      // keeps focus in editor on click, so insertion still targets caret\n      onMouseDown={(event) => {\n        event.preventDefault();\n        if (disabled) return;\n        onMouseDown?.(event);\n      }}\n      className={cn(popupItemStructureClasses, className)}\n      {...props}\n    />\n  );\n}\n\nexport function TriggerMenuIcon({ className, ...props }: TriggerMenuIconProps) {\n  return (\n    <span\n      data-control-ui=\"trigger-menu\"\n      data-control-family=\"popup\"\n      data-popup-kind=\"trigger-menu\"\n      data-slot=\"icon\"\n      className={cn(\"flex size-5 shrink-0 items-center justify-center [&_svg]:size-4\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function TriggerMenuEmpty({ className, ...props }: TriggerMenuEmptyProps) {\n  return (\n    <div\n      data-control-ui=\"trigger-menu\"\n      data-control-family=\"popup\"\n      data-popup-kind=\"trigger-menu\"\n      data-slot=\"empty\"\n      className={cn(\"px-[calc(var(--padding-x)*0.5)] py-2\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function TriggerMenuGroup({ className, ...props }: TriggerMenuGroupProps) {\n  return (\n    <div\n      data-control-ui=\"trigger-menu\"\n      data-control-family=\"popup\"\n      data-popup-kind=\"trigger-menu\"\n      data-slot=\"group\"\n      className={cn(\"flex flex-col gap-0.5\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function TriggerMenuGroupLabel({ className, ...props }: TriggerMenuGroupLabelProps) {\n  return (\n    <div\n      data-control-ui=\"trigger-menu\"\n      data-popup-kind=\"trigger-menu\"\n      data-slot=\"group-label\"\n      data-control-family=\"popup\"\n      data-popup-part=\"label\"\n      className={cn(\"px-[calc(var(--padding-x)*0.5)] pb-0.5 pt-1 uppercase\", className)}\n      {...props}\n    />\n  );\n}\n"
    }
  ],
  "css": {
    "@import \"../components/control-ui/styles/recipes/popup.css\"": {},
    "@import \"../components/control-ui/styles/recipes/popup-controls.css\"": {},
    "@import \"../components/control-ui/styles/recipes/popup-lists.css\"": {},
    "@import \"../components/control-ui/styles/recipes/popup-motion.css\"": {}
  },
  "meta": {}
}
