{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "core-preset-selector",
  "type": "registry:ui",
  "title": "Preset Selector",
  "description": "A controlled preset dropdown with Quiet, Panel and Glass skins, previous/next stepping, favorites, search, and collision-aware menu placement. The shared headless hook supplies accessible prop getters for custom renderers. Options accept strings or common name/label/note shapes and normalize to stable ids. The popup portals into the fullscreen element while the face is in browser fullscreen, so it stays visible there.",
  "dependencies": [
    "@base-ui/react",
    "maruaudio@>=0.0.3 <0.1.0"
  ],
  "registryDependencies": [
    "https://pluginui.com/r/core-popover.json"
  ],
  "files": [
    {
      "path": "components/ui/preset-selector.tsx",
      "content": "/**\n * Source: https://maru.audio/ui-kit/preset-selector\n * Copyright © [Maru](https://maru.audio)\n *\n * Maru UI Kit — https://maru.audio/ui-kit\n *\n * Installed from the Maru UI registry. This file is yours now: edit it\n * freely, it will not be overwritten unless you re-run the add command.\n *\n * Keep this item’s companion files and CSS imports together. Dependencies\n * declared by the registry are installed with the source.\n */\nimport {\n  Fragment,\n  useCallback,\n  useEffect,\n  useId,\n  useLayoutEffect,\n  useMemo,\n  useRef,\n  useState,\n  type ChangeEvent,\n  type ComponentProps,\n  type KeyboardEvent,\n  type ReactNode,\n} from \"react\"\nimport { PopoverParts as Popover } from \"@/components/ui/popover\"\nimport { overlayContainerFor } from \"maruaudio/ui/shared/overlay-container\"\nimport { UI_KIT_PORTABLE_STYLES } from \"maruaudio/ui/shared/portable-styles\"\nimport { token } from \"maruaudio/ui/shared/theme\"\n\nexport type PresetOptionInput =\n  | string\n  | {\n      id?: string\n      name?: string\n      label?: string\n      note?: string\n      description?: string\n      disabled?: boolean\n      /** Display grouping; adjacent equal groups share a heading. */\n      group?: string\n      badges?: readonly string[]\n    }\n\nexport interface PresetOption {\n  id: string\n  label: string\n  description?: string\n  disabled: boolean\n  group?: string\n  badges?: readonly string[]\n}\n\nexport interface ParamPresetOptionInput {\n  id?: string\n  name?: string\n  label?: string\n  note?: string\n  description?: string\n  disabled?: boolean\n  group?: string\n  badges?: readonly string[]\n  params: Readonly<Record<string, number>>\n}\n\nexport interface ParamPresetOption extends PresetOption {\n  params: Readonly<Record<string, number>>\n}\n\nexport function presetOptionId(\n  option: Exclude<PresetOptionInput, string>,\n  index: number\n): string {\n  return option.id ?? option.name ?? option.label ?? String(index)\n}\n\nfunction uniquePresetIds(options: readonly PresetOptionInput[]): string[] {\n  const used = new Set<string>()\n  return options.map((option, index) => {\n    const baseId = presetOptionId(\n      typeof option === \"string\" ? { id: option } : option,\n      index\n    )\n    let id = baseId\n    let suffix = 2\n    while (used.has(id)) id = `${baseId}#${suffix++}`\n    used.add(id)\n    return id\n  })\n}\n\nexport interface PresetFavoritesSource {\n  load(scope: string): Promise<ReadonlySet<string>>\n  setFavorite(scope: string, presetId: string, favorite: boolean): Promise<void>\n}\n\nexport interface PresetSelectorClassNames {\n  root?: string\n  controls?: string\n  step?: string\n  trigger?: string\n  menu?: string\n  search?: string\n  option?: string\n  favorite?: string\n  /** The modified marker beside the label. */\n  dirty?: string\n  /** The Save / Browse row (menu footer or trailing buttons). */\n  actions?: string\n  action?: string\n}\n\n/**\n * Where the prev/next paging chevrons sit — or whether they exist at all.\n * - `inside`: the two round chevrons flank the label as one grouped shape.\n * - `outside`: the chevrons detach to the edges, label + caret alone in the\n *   middle, so paging reads as separate from opening the menu.\n * - `off`: no chevrons; only the label + caret dropdown remains.\n */\nexport type PresetPaging = \"inside\" | \"outside\" | \"after\" | \"off\"\nexport type PresetSelectorVariant = \"quiet\" | \"panel\" | \"glass\"\n\nexport function normalizePresetOption(\n  option: PresetOptionInput,\n  index: number\n): PresetOption {\n  if (typeof option === \"string\") {\n    return { id: option, label: option, disabled: false }\n  }\n  const label = option.label ?? option.name ?? `Preset ${index + 1}`\n  return {\n    id: presetOptionId(option, index),\n    label,\n    description: option.description ?? option.note,\n    disabled: option.disabled ?? false,\n    ...(option.group?.trim() ? { group: option.group.trim() } : {}),\n    ...(option.badges\n      ? { badges: [...new Set(option.badges.map((badge) => badge.trim()).filter(Boolean))] }\n      : {}),\n  }\n}\n\nexport function normalizePresetOptions(\n  options: readonly PresetOptionInput[]\n): PresetOption[] {\n  const ids = uniquePresetIds(options)\n  return options.map((option, index) => ({\n    ...normalizePresetOption(option, index),\n    id: ids[index]!,\n  }))\n}\n\nexport function normalizeParamPresetOption(\n  option: ParamPresetOptionInput,\n  index: number\n): ParamPresetOption {\n  return { ...normalizePresetOption(option, index), params: option.params }\n}\n\nexport function normalizeParamPresetOptions(\n  options: readonly ParamPresetOptionInput[]\n): ParamPresetOption[] {\n  const ids = uniquePresetIds(options)\n  return options.map((option, index) => ({\n    ...normalizeParamPresetOption(option, index),\n    id: ids[index]!,\n  }))\n}\n\n/** Find the first preset whose declared params match the current live values. */\nexport function findActivePreset(\n  options: readonly ParamPresetOptionInput[],\n  values: Readonly<Record<string, number>>,\n  epsilon = 1e-6\n): ParamPresetOptionInput | undefined {\n  return options.find((option) => presetMatchesValues(option, values, epsilon))\n}\n\nexport function presetMatchesValues(\n  preset: ParamPresetOptionInput,\n  values: Readonly<Record<string, number>>,\n  epsilon = 1e-6\n): boolean {\n  return Object.entries(preset.params).every(([path, target]) => {\n    const current = values[path]\n    return (\n      typeof current === \"number\" &&\n      Number.isFinite(current) &&\n      Number.isFinite(target) &&\n      Math.abs(current - target) <= epsilon\n    )\n  })\n}\n\n/** Apply only the params a preset declares; transient performance state stays put. */\nexport function applyPresetParams(\n  preset: ParamPresetOptionInput,\n  onParamChange: (path: string, value: number) => void\n): void {\n  for (const [path, value] of Object.entries(preset.params)) {\n    if (Number.isFinite(value)) onParamChange(path, value)\n  }\n}\n\nexport interface UseParamPresetControllerOptions {\n  presets: readonly ParamPresetOptionInput[]\n  values: Readonly<Record<string, number>>\n  onParamChange: (path: string, value: number) => void\n  /** Replace UI writes with one host-owned factory-preset operation. */\n  onPresetSelect?: (preset: ParamPresetOptionInput, id: string) => void\n  epsilon?: number\n}\n\n/**\n * Dispatch one selector choice. Keeping the branch here makes the production\n * selector path auditable: a host-owned callback receives one atomic action,\n * while legacy callers alone get the per-parameter compatibility fallback.\n */\nexport function selectParamPreset(\n  presets: readonly ParamPresetOptionInput[],\n  id: string,\n  onParamChange: (path: string, value: number) => void,\n  onPresetSelect?: (preset: ParamPresetOptionInput, id: string) => void\n): void {\n  const index = uniquePresetIds(presets).indexOf(id)\n  const preset = presets[index]\n  if (!preset) return\n  if (onPresetSelect) onPresetSelect(preset, id)\n  else applyPresetParams(preset, onParamChange)\n}\n\n/** Controlled adapter from a live named-param record to PresetSelector props. */\nexport function useParamPresetController({\n  presets,\n  values,\n  onParamChange,\n  onPresetSelect,\n  epsilon,\n}: UseParamPresetControllerOptions) {\n  const active = findActivePreset(presets, values, epsilon)\n  const [chosenId, setChosenId] = useState<string | undefined>()\n  const confirmedId = useRef<string | undefined>(undefined)\n  const ids = uniquePresetIds(presets)\n  const activeIndex = active ? presets.indexOf(active) : -1\n  const chosen = presets.find((_, index) => ids[index] === chosenId)\n  useEffect(() => {\n    if (!chosenId) return\n    if (!chosen) {\n      confirmedId.current = undefined\n      setChosenId(undefined)\n    } else if (presetMatchesValues(chosen, values, epsilon)) {\n      confirmedId.current = chosenId\n    } else if (confirmedId.current === chosenId) {\n      confirmedId.current = undefined\n      setChosenId(undefined)\n    }\n  }, [chosen, chosenId, epsilon, values])\n  const value = chosenId ?? (activeIndex >= 0 ? ids[activeIndex] : undefined)\n  const onValueChange = useCallback(\n    (id: string) => {\n      confirmedId.current = undefined\n      setChosenId(id)\n      selectParamPreset(presets, id, onParamChange, onPresetSelect)\n    },\n    [onParamChange, onPresetSelect, presets]\n  )\n  const clearSelection = useCallback(() => {\n    confirmedId.current = undefined\n    setChosenId(undefined)\n  }, [])\n  return { active, value, onValueChange, clearSelection }\n}\n\nexport function nextPresetId(\n  options: readonly PresetOption[],\n  value: string | undefined,\n  delta: number\n): string | undefined {\n  const enabled = options.filter((option) => !option.disabled)\n  if (enabled.length === 0) return undefined\n  const current = enabled.findIndex((option) => option.id === value)\n  const from = current < 0 ? (delta > 0 ? -1 : 0) : current\n  const index =\n    (((from + delta) % enabled.length) + enabled.length) % enabled.length\n  return enabled[index]?.id\n}\n\nexport type PresetFocusRequest =\n  { kind: \"none\" } | { kind: \"search\" } | { kind: \"option\"; index: number }\n\n/** Pure keyboard navigation contract used by the popup's roving focus handler. */\nexport function presetFocusRequest(\n  key: string,\n  currentIndex: number,\n  optionCount: number,\n  searchFocused: boolean,\n  searchAvailable = true\n): PresetFocusRequest {\n  if (!optionCount || ![\"ArrowDown\", \"ArrowUp\", \"Home\", \"End\"].includes(key)) {\n    return { kind: \"none\" }\n  }\n  if (searchFocused && key !== \"ArrowDown\") return { kind: \"none\" }\n  if (\n    searchAvailable &&\n    !searchFocused &&\n    key === \"ArrowUp\" &&\n    currentIndex === 0\n  ) {\n    return { kind: \"search\" }\n  }\n  const index = searchFocused\n    ? 0\n    : key === \"Home\"\n      ? 0\n      : key === \"End\"\n        ? optionCount - 1\n        : key === \"ArrowDown\"\n          ? (currentIndex + 1 + optionCount) % optionCount\n          : (currentIndex - 1 + optionCount) % optionCount\n  return { kind: \"option\", index }\n}\n\nexport interface UsePresetSelectorOptions {\n  options: readonly PresetOptionInput[]\n  value?: string\n  onValueChange: (value: string) => void\n  /**\n   * Override where previous/next lands, e.g. a preset library stepping over\n   * its currently FILTERED list. Return undefined to stay put. The choice\n   * still goes through `onValueChange` with the usual pending display.\n   */\n  resolveStep?: (delta: -1 | 1, value: string | undefined) => string | undefined\n}\n\ninterface PendingPresetSelection {\n  readonly id: string\n  /** Last host value when this selection was requested. */\n  readonly from: string | undefined\n  /** Host echoes of earlier requests must not roll a newer choice backward. */\n  readonly earlierIds: readonly string[]\n}\n\nfunction pendingPresetId(\n  value: string | undefined,\n  pending: PendingPresetSelection | null,\n  options: readonly PresetOption[]\n): string | undefined {\n  if (!pending || !options.some((option) => option.id === pending.id))\n    return value\n  if (value === pending.from || pending.earlierIds.includes(value ?? \"\"))\n    return pending.id\n  // The host confirmed the latest choice or supplied a different selection.\n  return value\n}\n\nexport function usePresetSelector({\n  options: input,\n  value,\n  onValueChange,\n  resolveStep,\n}: UsePresetSelectorOptions) {\n  const options = useMemo(() => normalizePresetOptions(input), [input])\n  const [pending, setPending] = useState<PendingPresetSelection | null>(null)\n  const selectedId = pendingPresetId(value, pending, options)\n  const selected = options.find((option) => option.id === selectedId)\n  useEffect(() => {\n    if (\n      pending &&\n      (value === pending.id ||\n        !options.some((option) => option.id === pending.id) ||\n        (value !== pending.from && !pending.earlierIds.includes(value ?? \"\")))\n    )\n      setPending(null)\n  }, [options, pending, value])\n  const choose = useCallback(\n    (id: string) => {\n      setPending((current) => ({\n        id,\n        from: value,\n        earlierIds:\n          current && pendingPresetId(value, current, options) === current.id\n            ? [...new Set([...current.earlierIds, current.id])]\n            : [],\n      }))\n      onValueChange(id)\n    },\n    [onValueChange, options, value]\n  )\n  const step = useCallback(\n    (delta: number) => {\n      const next = resolveStep\n        ? resolveStep(delta < 0 ? -1 : 1, selectedId)\n        : nextPresetId(options, selectedId, delta)\n      if (next !== undefined) choose(next)\n    },\n    [choose, options, resolveStep, selectedId]\n  )\n  return { options, selected, step, choose }\n}\n\nexport interface PresetSelectorProps extends UsePresetSelectorOptions {\n  /** Overrides the shared Base UI positioning policy. */\n  positionerProps?: Omit<ComponentProps<typeof Popover.Positioner>, \"children\">\n  placeholder?: string\n  favorites?: PresetFavoritesSource\n  favoriteScope?: string\n  /**\n   * Prev/next chevron placement. Not every preset bank wants paging — pass\n   * `\"off\"` to drop the chevrons entirely. Defaults to `\"inside\"`.\n   */\n  paging?: PresetPaging\n  /**\n   * Show a text filter pinned to the top of the open dropdown. Left undefined,\n   * it auto-enables once the bank passes `searchThreshold` presets; pass `true`\n   * or `false` to force it either way.\n   */\n  search?: boolean\n  /** Preset count at or above which search auto-enables. Defaults to 10. */\n  searchThreshold?: number\n  /** Placeholder for the search field when search is shown. */\n  searchPlaceholder?: string\n  className?: string\n  classNames?: PresetSelectorClassNames\n  /** Appearance only; all variants share the same headless behavior. */\n  variant?: PresetSelectorVariant\n  /**\n   * The current sound differs from the selected preset (host-owned). Shows a\n   * modified marker beside the label and announces \"modified\".\n   */\n  dirty?: boolean\n  /** Offer Save; called when pressed. Omit to hide the action. */\n  onSave?: () => void\n  saveLabel?: string\n  /** Offer Browse (a full preset browser); called when pressed. */\n  onBrowse?: () => void\n  /** Text or an icon. The trailing button is named \"Browse presets\" either way. */\n  browseLabel?: ReactNode\n  /**\n   * A first line in the trigger, over the preset's name — what the presets\n   * are OF (an instrument, a bank). The two lines are one control: the\n   * chevrons and the caret flank both.\n   */\n  heading?: ReactNode\n  /**\n   * Where Save/Browse sit: `menu` (default) is a footer row inside the open\n   * dropdown; `trailing` puts compact buttons after the selector itself.\n   */\n  actionPlacement?: \"menu\" | \"trailing\"\n  /**\n   * The dropdown. `false` shows the title as a label, with no caret and no\n   * menu, for a place that already lists the presets beside it (a library\n   * sidebar); the chevrons and actions stay. Defaults to true.\n   */\n  menu?: boolean\n}\n\nconst base = {\n  // The full-zone box is gone: no border/background on the root. Grouping is\n  // carried by the inner `group` shape (paging=\"inside\") or by the caret pill\n  // alone (paging=\"outside\"/\"off\").\n  root: \"relative inline-flex min-w-0 items-center gap-1.5 text-xs\",\n  // paging=\"inside\": a single soft shape holds the whole group. It stays quiet\n  // until hovered so the pieces read as one control without a hard border box.\n  controls:\n    \"group/preset inline-flex min-w-0 items-center gap-0.5 rounded-[var(--preset-radius)] p-0.5 transition-colors hover:bg-[var(--preset-surface)]\",\n  // paging=\"outside\": the chevrons detach; the label + caret carry their own\n  // grouping and the row spreads to the slot edges.\n  controlsOutside:\n    \"inline-flex min-w-0 flex-1 items-center justify-between gap-1.5\",\n  // paging=\"off\": nothing but the caret pill; keep it centered and compact.\n  controlsBare: \"inline-flex min-w-0 items-center\",\n  // Round chevron button. A subtle ring appears on hover so \"page prev/next\"\n  // is legible on its own, distinct from opening the menu.\n  step: \"uikit-control grid size-7 shrink-0 place-items-center rounded-[var(--preset-radius)] text-[0.95em] leading-none text-current/70 transition-[background-color,color,box-shadow] hover:bg-[var(--preset-surface-strong)] hover:text-current hover:shadow-[inset_0_0_0_1px_var(--preset-border)] focus-visible:bg-[var(--preset-surface-strong)] focus-visible:text-current disabled:cursor-not-allowed disabled:opacity-30 disabled:shadow-none\",\n  // The label + caret. Reads as plain text at rest; a faint pill on hover/open\n  // signals it opens the menu, without the old hard-bordered trigger. A fixed\n  // width keeps the flanking chevrons still while the label swaps and truncates.\n  trigger:\n    \"uikit-control flex h-7 w-[var(--preset-label-width,11rem)] max-w-[calc(100vw-6rem)] items-center justify-center gap-1.5 rounded-[var(--preset-radius)] px-2.5 text-center font-medium text-current transition-colors hover:bg-[var(--preset-surface-strong)] aria-expanded:bg-[var(--preset-surface-strong)]\",\n  dirty: \"shrink-0 text-[0.85em] leading-none text-[var(--preset-accent)]\",\n  actions:\n    \"mt-1 flex shrink-0 items-center gap-1 border-t border-[color:var(--preset-border)] pt-1\",\n  actionsTrailing: \"inline-flex shrink-0 items-center gap-1\",\n  action:\n    \"uikit-control inline-flex h-7 min-w-0 flex-1 items-center justify-center gap-1 rounded-[var(--preset-radius)] px-2.5 text-current/80 transition-colors hover:bg-[var(--preset-surface-strong)] hover:text-current focus-visible:bg-[var(--preset-surface-strong)] disabled:cursor-not-allowed disabled:opacity-40\",\n  actionTrailing:\n    \"uikit-control inline-flex h-7 shrink-0 items-center justify-center gap-1 rounded-[var(--preset-radius)] px-2 text-current/75 transition-colors hover:bg-[var(--preset-surface-strong)] hover:text-current focus-visible:bg-[var(--preset-surface-strong)] disabled:cursor-not-allowed disabled:opacity-40\",\n  menu: \"relative z-[100] m-0 flex max-h-[min(24rem,var(--available-height,calc(100dvh-1rem)))] w-60 max-w-[calc(100dvw-1rem)] flex-col overflow-hidden rounded-[var(--preset-menu-radius)] border border-[color:var(--preset-border)] bg-[var(--preset-menu-surface,var(--color-background,#111))] p-1 text-[var(--preset-menu-text,var(--color-foreground,currentColor))] shadow-xl outline-none\",\n  search:\n    \"mb-1 w-full shrink-0 rounded-md border border-[color:var(--preset-border)] bg-[var(--preset-surface)] px-2.5 py-1.5 text-current outline-none placeholder:text-current/40 focus-visible:border-[color:var(--preset-accent)]\",\n  // Thin, subtle scrollbar instead of the platform's full track chrome.\n  list: \"min-h-0 flex-1 overflow-x-hidden overflow-y-auto overscroll-contain [scrollbar-width:thin] [scrollbar-color:var(--preset-border)_transparent] [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-[var(--preset-border)]\",\n  empty: \"px-2.5 py-3 text-center text-current/45\",\n  option:\n    \"flex min-h-10 w-full items-center gap-2 rounded-sm text-left hover:bg-[var(--preset-option-hover,var(--color-muted,rgba(255,255,255,0.08)))] focus-within:bg-[var(--preset-option-hover,var(--color-muted,rgba(255,255,255,0.08)))] data-[selected]:bg-[var(--preset-option-hover,var(--color-muted,rgba(255,255,255,0.08)))]\",\n  // Grayscale stars, not accent-colored: a filled star reads at full opacity,\n  // an empty one stays dim, and the whole column brightens on hover.\n  favorite:\n    \"uikit-control ml-auto grid size-8 shrink-0 place-items-center rounded-sm text-base text-current opacity-45 transition-opacity hover:bg-[var(--preset-option-hover,var(--color-muted,rgba(255,255,255,0.08)))] hover:opacity-80 aria-pressed:opacity-90\",\n} as const\n\nconst variantClasses: Record<PresetSelectorVariant, string> = {\n  quiet:\n    \"[--preset-radius:999px] [--preset-menu-radius:var(--uikit-radius,8px)] [--preset-accent:var(--uikit-accent,#fbbf24)] [--preset-border:var(--uikit-border,color-mix(in_oklab,currentColor_18%,transparent))] [--preset-surface:color-mix(in_oklab,currentColor_8%,transparent)] [--preset-surface-strong:color-mix(in_oklab,currentColor_14%,transparent)] [--preset-menu-surface:var(--uikit-surface,#171717)] [--preset-menu-text:var(--uikit-text,currentColor)] [--preset-option-hover:var(--uikit-cap,color-mix(in_oklab,currentColor_12%,transparent))]\",\n  panel:\n    \"[--preset-radius:var(--uikit-radius,12px)] [--preset-menu-radius:var(--uikit-radius,12px)] [--preset-accent:var(--uikit-accent,#6366f1)] [--preset-border:var(--uikit-border,color-mix(in_oklab,currentColor_18%,transparent))] [--preset-surface:var(--uikit-surface,color-mix(in_oklab,currentColor_8%,transparent))] [--preset-surface-strong:var(--uikit-cap,color-mix(in_oklab,currentColor_14%,transparent))] [--preset-menu-surface:var(--uikit-surface,#171717)] [--preset-menu-text:var(--uikit-text,currentColor)] [--preset-option-hover:var(--uikit-cap,color-mix(in_oklab,currentColor_12%,transparent))] border border-[color:var(--preset-border)] rounded-[var(--preset-radius)] bg-[var(--preset-surface)] shadow-sm\",\n  glass:\n    \"[--preset-radius:var(--uikit-radius,16px)] [--preset-menu-radius:var(--uikit-radius,16px)] [--preset-accent:var(--uikit-accent,#6366f1)] [--preset-border:var(--uikit-border,color-mix(in_oklab,currentColor_28%,transparent))] [--preset-surface:color-mix(in_oklab,var(--uikit-surface,#fff)_65%,transparent)] [--preset-surface-strong:color-mix(in_oklab,var(--uikit-surface,#fff)_85%,transparent)] [--preset-menu-surface:var(--uikit-surface,#fff)] [--preset-menu-text:var(--uikit-text,currentColor)] [--preset-option-hover:var(--uikit-cap,color-mix(in_oklab,currentColor_12%,transparent))] border border-[color:var(--preset-border)] rounded-[var(--preset-radius)] bg-[var(--preset-surface)] shadow-lg backdrop-blur-xl\",\n}\n\nfunction classes(baseClass: string, override?: string): string {\n  return override ? `${baseClass} ${override}` : baseClass\n}\n\n/** Behavior shared by the ready-made selector and fully custom face renderers. */\nexport function usePresetSelectorHeadless({\n  options: input,\n  value,\n  onValueChange,\n  favorites,\n  favoriteScope = \"presets\",\n  paging = \"inside\",\n  search,\n  searchThreshold = 10,\n  resolveStep,\n  dirty = false,\n  onSave,\n  onBrowse,\n}: Omit<\n  PresetSelectorProps,\n  \"className\" | \"classNames\" | \"variant\" | \"searchPlaceholder\"\n>) {\n  const {\n    options,\n    selected,\n    step,\n    choose: select,\n  } = usePresetSelector({\n    options: input,\n    value,\n    onValueChange,\n    resolveStep,\n  })\n  const [open, setOpen] = useState(false)\n  const [query, setQuery] = useState(\"\")\n  const searchRef = useRef<HTMLInputElement>(null)\n  // Undefined → auto: search shows once the bank is long enough to warrant it.\n  const showSearch = search ?? options.length >= searchThreshold\n  const visibleOptions = useMemo(() => {\n    const q = query.trim().toLowerCase()\n    if (!showSearch || !q) return options\n    return options.filter(\n      (option) =>\n        option.label.toLowerCase().includes(q) ||\n        option.description?.toLowerCase().includes(q) ||\n        option.group?.toLowerCase().includes(q) ||\n        option.badges?.some((badge) => badge.toLowerCase().includes(q))\n    )\n  }, [options, query, showSearch])\n  const visibleGroups = useMemo(() => {\n    const groups: Array<{ label?: string; options: PresetOption[] }> = []\n    for (const option of visibleOptions) {\n      const previous = groups.at(-1)\n      if (previous && previous.label === option.group) previous.options.push(option)\n      else groups.push({ label: option.group, options: [option] })\n    }\n    return groups\n  }, [visibleOptions])\n  const [favoriteIds, setFavoriteIds] = useState<ReadonlySet<string>>(new Set())\n  const favoriteIdsRef = useRef<ReadonlySet<string>>(new Set())\n  const [favoritesReady, setFavoritesReady] = useState(false)\n  const rootRef = useRef<HTMLDivElement>(null)\n  const menuRef = useRef<HTMLDivElement>(null)\n  const menuId = useId()\n  const [menuTheme, setMenuTheme] = useState<Record<string, string>>({})\n  // Where the popup is portaled: the fullscreen element while the face is in\n  // browser fullscreen (a popup on the body would be invisible), else the\n  // body. Chosen as the popup opens, because fullscreen can change meanwhile.\n  const [portalContainer, setPortalContainer] = useState<HTMLElement | null>(\n    null\n  )\n  const openPopup = () => {\n    setPortalContainer(overlayContainerFor(rootRef.current))\n    setOpen(true)\n  }\n  const hasEnabledOptions = options.some((option) => !option.disabled)\n\n  useEffect(() => {\n    let current = true\n    favoriteIdsRef.current = new Set()\n    setFavoriteIds(favoriteIdsRef.current)\n    if (!favorites) {\n      setFavoritesReady(false)\n      return\n    }\n    setFavoritesReady(false)\n    void favorites\n      .load(favoriteScope)\n      .then((ids) => {\n        if (!current) return\n        favoriteIdsRef.current = new Set(ids)\n        setFavoriteIds(favoriteIdsRef.current)\n        setFavoritesReady(true)\n      })\n      .catch(() => {\n        if (current) setFavoritesReady(true)\n      })\n    return () => {\n      current = false\n    }\n  }, [favoriteScope, favorites])\n\n  useEffect(() => {\n    if (!open) {\n      setQuery(\"\")\n    }\n  }, [open])\n\n  useLayoutEffect(() => {\n    const root = rootRef.current\n    if (!open || !root) return\n    // The popup is portaled by Base UI, so copy the face palette across the\n    // portal boundary. currentColor would otherwise resolve against the page\n    // after portaling, which can make light-on-dark faces render dark menu text.\n    // Base UI owns positioning, collision handling and events.\n    const style = window.getComputedStyle(root)\n    const tokens = Object.fromEntries(\n      [\n        \"--preset-accent\",\n        \"--preset-border\",\n        \"--preset-surface\",\n        \"--preset-surface-strong\",\n        \"--preset-menu-surface\",\n        \"--preset-menu-text\",\n        \"--preset-option-hover\",\n        \"--preset-radius\",\n        \"--preset-menu-radius\",\n        \"--uikit-radius\",\n        \"--uikit-accent\",\n        \"--uikit-border\",\n        \"--uikit-surface\",\n        \"--uikit-cap\",\n        \"--uikit-text\",\n        \"--uikit-font\",\n        \"--uikit-font-mono\",\n        \"--uikit-focus\",\n        \"--color-background\",\n        \"--color-foreground\",\n      ].flatMap((name) => {\n        const value = style.getPropertyValue(name).trim()\n        return value ? [[name, value]] : []\n      })\n    )\n    const menuText = tokens[\"--preset-menu-text\"]\n    const foreground =\n      !menuText ||\n      (menuText.toLowerCase().includes(\"currentcolor\") &&\n        !tokens[\"--uikit-text\"])\n        ? style.color\n        : menuText\n    setMenuTheme({\n      ...tokens,\n      \"--preset-menu-text\": foreground,\n      color: foreground,\n    })\n  }, [open])\n\n  const choose = (id: string) => {\n    select(id)\n    setOpen(false)\n  }\n\n  // An action that opens its own overlay (Browse, Save) closes the menu\n  // without returning focus to the trigger, so the overlay keeps the focus it\n  // takes on open.\n  const actionClosing = useRef(false)\n  const runAction = (action: (() => void) | undefined) => {\n    if (!action) return\n    if (open) {\n      actionClosing.current = true\n      setOpen(false)\n    }\n    action()\n  }\n\n  const toggleFavorite = (id: string) => {\n    if (!favorites || !favoritesReady) return\n    const next = !favoriteIdsRef.current.has(id)\n    const copy = new Set(favoriteIdsRef.current)\n    if (next) copy.add(id)\n    else copy.delete(id)\n    favoriteIdsRef.current = copy\n    setFavoriteIds(copy)\n    void favorites?.setFavorite(favoriteScope, id, next)\n  }\n\n  const focusOption = (option: HTMLElement | undefined | null) => {\n    if (!option) return\n    // Browser focus scrolling can walk past the menu into a scrollable face.\n    // Focus without scrolling, then reveal only inside the owning list.\n    option.focus({ preventScroll: true })\n    const list = menuRef.current\n    if (!list) return\n    const row = option.getBoundingClientRect()\n    const viewport = list.getBoundingClientRect()\n    if (row.top < viewport.top) list.scrollTop += row.top - viewport.top\n    else if (row.bottom > viewport.bottom)\n      list.scrollTop += row.bottom - viewport.bottom\n  }\n\n  const onMenuKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n    const candidates = Array.from(\n      event.currentTarget.querySelectorAll<HTMLButtonElement>(\n        \"[data-preset-option]:not(:disabled)\"\n      )\n    )\n    const onSearch = document.activeElement === searchRef.current\n    const current = candidates.indexOf(\n      document.activeElement as HTMLButtonElement\n    )\n    const request = presetFocusRequest(\n      event.key,\n      current,\n      candidates.length,\n      onSearch,\n      showSearch\n    )\n    if (request.kind === \"none\") return\n    event.preventDefault()\n    if (request.kind === \"search\" && searchRef.current) {\n      searchRef.current.focus({ preventScroll: true })\n      return\n    }\n    if (request.kind === \"option\") focusOption(candidates[request.index])\n  }\n\n  const onOpenChange: NonNullable<\n    ComponentProps<typeof Popover.Root>[\"onOpenChange\"]\n  > = (next, details) => {\n    // Keep the popup open when paging controls are outside the popup itself.\n    // This behavior belongs to the shared hook contract, not to one skin.\n    if (!next && details.reason === \"outside-press\") {\n      const target = details.event.target\n      if (\n        target instanceof Element &&\n        rootRef.current?.contains(target) &&\n        target.closest(\"[data-preset-step]\")\n      ) {\n        details.cancel()\n        return\n      }\n    }\n    if (!next && details.reason === \"focus-out\") {\n      const target =\n        \"relatedTarget\" in details.event ? details.event.relatedTarget : null\n      if (\n        target instanceof Element &&\n        rootRef.current?.contains(target) &&\n        target.closest(\"[data-preset-step]\")\n      ) {\n        details.cancel()\n        return\n      }\n    }\n    if (next) openPopup()\n    else setOpen(false)\n  }\n\n  return {\n    options,\n    selected,\n    open,\n    setOpen,\n    query,\n    visibleOptions,\n    visibleGroups,\n    showSearch,\n    paging,\n    favoriteIds,\n    favoritesReady,\n    dirty,\n    hasSave: onSave !== undefined,\n    hasBrowse: onBrowse !== undefined,\n    rootRef,\n    menuRef,\n    menuId,\n    menuTheme,\n    onMenuKeyDown,\n    searchRef,\n    portalContainer,\n    getRootProps() {\n      return {\n        ref: rootRef,\n        \"data-module-preset-control\": true,\n        \"data-paging\": paging,\n        \"data-preset-count\": options.length,\n        \"data-dirty\": dirty || undefined,\n      }\n    },\n    getControlsProps() {\n      return {\n        role: \"group\" as const,\n        \"aria-label\": \"Preset\",\n        \"data-preset-controls\": true,\n        \"data-paging\": paging,\n      }\n    },\n    getStepProps(direction: -1 | 1) {\n      return {\n        type: \"button\" as const,\n        \"aria-label\": direction < 0 ? \"Previous preset\" : \"Next preset\",\n        onClick: () => step(direction),\n        disabled: !hasEnabledOptions,\n      }\n    },\n    /** Spread onto Base UI Popover.Root; it owns dismissal and focus return. */\n    getPopoverRootProps() {\n      return { open, onOpenChange }\n    },\n    getTriggerProps() {\n      return {\n        type: \"button\" as const,\n        \"aria-label\": \"Preset\",\n        // Base UI Trigger owns click, expanded state and popup ARIA attributes.\n        onKeyDown: (event: KeyboardEvent<HTMLButtonElement>) => {\n          if (event.key !== \"ArrowDown\" && event.key !== \"ArrowUp\") return\n          event.preventDefault()\n          if (hasEnabledOptions) openPopup()\n        },\n      }\n    },\n    /** The modified marker; render it only while `dirty`. */\n    getDirtyProps() {\n      return {\n        \"aria-hidden\": true as const,\n        \"data-preset-dirty\": true,\n      }\n    },\n    /** Save or Browse; absent actions are not rendered. */\n    getActionProps(kind: \"save\" | \"browse\") {\n      const action = kind === \"save\" ? onSave : onBrowse\n      return {\n        type: \"button\" as const,\n        disabled: !action,\n        \"data-preset-action\": kind,\n        onClick: () => runAction(action),\n      }\n    },\n    /** Spread onto Base UI Popover.Popup for shared focus and keyboard behavior. */\n    getPopupProps() {\n      return {\n        initialFocus: showSearch\n          ? searchRef\n          : () =>\n              menuRef.current?.querySelector<HTMLElement>(\n                '[data-preset-option][aria-selected=\"true\"]'\n              ) ?? true,\n        onKeyDown: onMenuKeyDown,\n        finalFocus: () => {\n          if (!actionClosing.current) return true\n          actionClosing.current = false\n          return false\n        },\n        style: {\n          ...menuTheme,\n          maxHeight: \"min(24rem, var(--available-height, calc(100dvh - 1rem)))\",\n          overflow: \"hidden\" as const,\n        },\n      }\n    },\n    getMenuProps() {\n      return {\n        ref: menuRef,\n        id: menuId,\n        role: \"listbox\" as const,\n        \"aria-label\": \"Presets\",\n      }\n    },\n    getSearchProps(searchPlaceholder = \"Search presets…\") {\n      return {\n        ref: searchRef,\n        type: \"search\" as const,\n        value: query,\n        onChange: (event: ChangeEvent<HTMLInputElement>) =>\n          setQuery(event.target.value),\n        placeholder: searchPlaceholder,\n        \"aria-label\": \"Search presets\",\n        onKeyDown: (event: KeyboardEvent<HTMLInputElement>) => {\n          if (event.key === \"ArrowDown\") {\n            const first = menuRef.current?.querySelector<HTMLButtonElement>(\n              \"[data-preset-option]:not(:disabled)\"\n            )\n            if (first) {\n              event.preventDefault()\n              event.stopPropagation()\n              focusOption(first)\n              return\n            }\n          }\n          if (event.key === \"Escape\" && query) {\n            event.preventDefault()\n            event.stopPropagation()\n            setQuery(\"\")\n          }\n        },\n      }\n    },\n    getOptionProps(option: PresetOption) {\n      return {\n        type: \"button\" as const,\n        role: \"option\" as const,\n        \"aria-selected\": option.id === value,\n        \"aria-label\": option.badges?.length\n          ? [option.label, ...option.badges, option.description].filter(Boolean).join(\", \")\n          : undefined,\n        disabled: option.disabled,\n        onClick: () => choose(option.id),\n      }\n    },\n    getFavoriteProps(option: PresetOption) {\n      const favorite = favoriteIds.has(option.id)\n      return {\n        type: \"button\" as const,\n        \"aria-label\": `${favorite ? \"Remove\" : \"Add\"} ${option.label} ${favorite ? \"from\" : \"to\"} favorites`,\n        \"aria-pressed\": favorite,\n        disabled: !favoritesReady,\n        onClick: () => toggleFavorite(option.id),\n      }\n    },\n  }\n}\n\n/** Visually hidden but announced (no Tailwind needed in isolated faces). */\nconst PRESET_VISUALLY_HIDDEN = {\n  position: \"absolute\",\n  width: 1,\n  height: 1,\n  margin: -1,\n  padding: 0,\n  overflow: \"hidden\",\n  clip: \"rect(0 0 0 0)\",\n  whiteSpace: \"nowrap\",\n  border: 0,\n} as const\n\n/* The two-line trigger's layout, inline: the registry's portable stylesheet\n * carries only the classes the single-line trigger uses. */\nconst HEADED_TRIGGER_STYLE = { height: \"auto\", paddingBlock: 4 } as const\nconst HEADED_STACK_STYLE = {\n  display: \"flex\",\n  flex: \"1 1 auto\",\n  minWidth: 0,\n  flexDirection: \"column\",\n  alignItems: \"center\",\n  gap: 2,\n} as const\n/* Arrows after the title: the title keeps its left edge. */\nconst HEADED_STACK_START_STYLE = { ...HEADED_STACK_STYLE, alignItems: \"flex-start\" } as const\nconst HEADED_LABEL_STYLE = { maxWidth: \"100%\", flex: \"none\" } as const\nconst START_LABEL_STYLE = { textAlign: \"start\" } as const\n\nexport function PresetSelector({\n  variant = \"quiet\",\n  className,\n  classNames,\n  searchPlaceholder = \"Search presets…\",\n  positionerProps,\n  saveLabel = \"Save…\",\n  browseLabel = \"Browse…\",\n  actionPlacement = \"menu\",\n  heading,\n  menu = true,\n  ...behavior\n}: PresetSelectorProps) {\n  const {\n    options,\n    selected,\n    query,\n    visibleOptions,\n    visibleGroups,\n    showSearch,\n    paging,\n    favoriteIds,\n    getRootProps,\n    getControlsProps,\n    getStepProps,\n    getPopoverRootProps,\n    getPopupProps,\n    getTriggerProps,\n    getMenuProps,\n    getSearchProps,\n    getOptionProps,\n    getFavoriteProps,\n    getDirtyProps,\n    getActionProps,\n    dirty,\n    hasSave,\n    hasBrowse,\n    portalContainer,\n  } = usePresetSelectorHeadless(behavior)\n  const hasActions = hasSave || hasBrowse\n  const actionButtons = (trailing: boolean) => (\n    <>\n      {hasSave ? (\n        <button\n          {...getActionProps(\"save\")}\n          className={classes(\n            trailing ? base.actionTrailing : base.action,\n            classNames?.action\n          )}\n          aria-label={trailing ? \"Save preset\" : undefined}\n        >\n          {saveLabel}\n        </button>\n      ) : null}\n      {hasBrowse ? (\n        <button\n          {...getActionProps(\"browse\")}\n          className={classes(\n            trailing ? base.actionTrailing : base.action,\n            classNames?.action\n          )}\n          aria-label={trailing ? \"Browse presets\" : undefined}\n        >\n          {browseLabel}\n        </button>\n      ) : null}\n    </>\n  )\n  const { value, placeholder = \"Custom\", favorites } = behavior\n  const showChevrons = paging !== \"off\"\n\n  const chevron = (direction: -1 | 1) => (\n    <button\n      {...getStepProps(direction)}\n      className={classes(base.step, classNames?.step)}\n      data-preset-step\n    >\n      <svg\n        aria-hidden=\"true\"\n        width=\"16\"\n        height=\"16\"\n        viewBox=\"0 0 16 16\"\n        fill=\"none\"\n      >\n        <path\n          d={direction < 0 ? \"m9.5 3.5-5 4.5 5 4.5\" : \"m6.5 3.5 5 4.5-5 4.5\"}\n          stroke=\"currentColor\"\n          strokeWidth=\"2\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n      </svg>\n    </button>\n  )\n\n  const label = (\n    <span\n      className=\"min-w-0 flex-1 truncate text-center\"\n      data-preset-label\n      aria-live=\"polite\"\n      aria-atomic=\"true\"\n      style={\n        heading !== undefined\n          ? HEADED_LABEL_STYLE\n          : paging === \"after\"\n            ? START_LABEL_STYLE\n            : undefined\n      }\n    >\n      {selected?.label ?? placeholder}\n      {dirty ? <span style={PRESET_VISUALLY_HIDDEN}> (modified)</span> : null}\n    </span>\n  )\n  const titles =\n    heading === undefined ? (\n      label\n    ) : (\n      <span\n        style={paging === \"after\" ? HEADED_STACK_START_STYLE : HEADED_STACK_STYLE}\n        data-preset-titles\n      >\n        <span className=\"truncate\" style={HEADED_LABEL_STYLE} data-preset-heading>\n          {heading}\n        </span>\n        {label}\n      </span>\n    )\n  const dirtyMark = dirty ? (\n    <span\n      {...getDirtyProps()}\n      className={classes(base.dirty, classNames?.dirty)}\n    >\n      ●\n    </span>\n  ) : null\n  const trigger = menu ? (\n    <Popover.Trigger\n      {...getTriggerProps()}\n      className={classes(base.trigger, classNames?.trigger)}\n      data-preset-trigger\n      data-preset-headed={heading === undefined ? undefined : \"\"}\n      style={heading === undefined ? undefined : HEADED_TRIGGER_STYLE}\n    >\n      {titles}\n      {dirtyMark}\n      <svg\n        aria-hidden=\"true\"\n        className=\"shrink-0 opacity-70\"\n        data-preset-caret\n        width=\"16\"\n        height=\"16\"\n        viewBox=\"0 0 16 16\"\n        fill=\"none\"\n      >\n        <path\n          d=\"m3.5 6 4.5 4.5L12.5 6\"\n          stroke=\"currentColor\"\n          strokeWidth=\"2.2\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n      </svg>\n    </Popover.Trigger>\n  ) : (\n    <span\n      className={classes(base.trigger, classNames?.trigger)}\n      data-preset-trigger\n      data-preset-static=\"\"\n      data-preset-headed={heading === undefined ? undefined : \"\"}\n      style={{ ...(heading === undefined ? null : HEADED_TRIGGER_STYLE), cursor: \"default\" }}\n    >\n      {titles}\n      {dirtyMark}\n    </span>\n  )\n\n  return (\n    <Popover.Root {...getPopoverRootProps()}>\n      <div\n        {...getRootProps()}\n        style={{ fontFamily: token.font }}\n        className={classes(\n          classes(base.root, variantClasses[variant]),\n          `${className ?? \"\"} ${classNames?.root ?? \"\"}`.trim()\n        )}\n        data-variant={variant}\n      >\n        {/* Local injection keeps this registry item standalone in iframe/webview consumers. */}\n        <style data-maru-ui-kit-portable>{UI_KIT_PORTABLE_STYLES}</style>\n        {paging === \"outside\" ? (\n          <div\n            {...getControlsProps()}\n            className={classes(base.controlsOutside, classNames?.controls)}\n          >\n            {chevron(-1)}\n            {trigger}\n            {chevron(1)}\n          </div>\n        ) : paging === \"after\" ? (\n          <div\n            {...getControlsProps()}\n            className={classes(base.controls, classNames?.controls)}\n          >\n            {trigger}\n            {chevron(-1)}\n            {chevron(1)}\n          </div>\n        ) : showChevrons ? (\n          <div\n            {...getControlsProps()}\n            className={classes(base.controls, classNames?.controls)}\n          >\n            {chevron(-1)}\n            {trigger}\n            {chevron(1)}\n          </div>\n        ) : (\n          <div\n            {...getControlsProps()}\n            className={classes(base.controlsBare, classNames?.controls)}\n          >\n            {trigger}\n          </div>\n        )}\n        {hasActions && actionPlacement === \"trailing\" ? (\n          <div\n            className={classes(base.actionsTrailing, classNames?.actions)}\n            data-preset-actions=\"trailing\"\n          >\n            {actionButtons(true)}\n          </div>\n        ) : null}\n\n        {menu ? (\n        <Popover.Portal container={portalContainer ?? undefined}>\n          <Popover.Positioner\n            side=\"bottom\"\n            align=\"center\"\n            sideOffset={6}\n            collisionPadding={8}\n            className=\"z-[100] outline-none\"\n            // Inline too, for hosts without a Tailwind build.\n            style={{ zIndex: 100 }}\n            {...positionerProps}\n          >\n            <Popover.Popup\n              {...getPopupProps()}\n              aria-label=\"Preset chooser\"\n              className={classes(base.menu, classNames?.menu)}\n              data-variant={variant}\n              data-preset-menu\n            >\n              {showSearch ? (\n                <input\n                  {...getSearchProps(searchPlaceholder)}\n                  className={classes(base.search, classNames?.search)}\n                  data-preset-search\n                />\n              ) : null}\n              {showSearch && query.trim() ? (\n                <div role=\"status\" style={{ padding: \"0.25rem 0.625rem\", opacity: 0.65 }} data-preset-results>\n                  {visibleOptions.length} of {options.length} presets\n                </div>\n              ) : null}\n              <div {...getMenuProps()} className={base.list} data-preset-list data-preset-result-count={visibleOptions.length}>\n                {visibleOptions.length === 0 ? (\n                  <p className={base.empty} data-preset-empty>\n                    {query.trim() === \"\"\n                      ? \"No presets yet.\"\n                      : `No presets match “${query.trim()}”. Try a different search.`}\n                  </p>\n                ) : (\n                  visibleGroups.map((group, index) => {\n                    const rows = group.options.map((option) => {\n                      const favorite = favoriteIds.has(option.id)\n                      return (\n                        <div\n                          key={option.id}\n                          className={classes(base.option, classNames?.option)}\n                          data-selected={option.id === value || undefined}\n                          data-preset-row\n                        >\n                          <button\n                            {...getOptionProps(option)}\n                            data-preset-option\n                            className=\"min-h-10 min-w-0 flex-1 rounded-sm px-2.5 py-1.5 text-left disabled:opacity-40\"\n                          >\n                            <span className=\"block truncate font-medium\">\n                              {option.label}\n                            </span>\n                            {option.badges?.length ? (\n                              <span style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"0.25rem\", marginTop: \"0.125rem\" }} data-preset-badges>\n                                {option.badges.map((badge) => (\n                                  <span key={badge} data-preset-badge style={{ border: \"1px solid var(--preset-border)\", padding: \"0 0.25rem\", fontSize: \"0.85em\" }}>{badge}</span>\n                                ))}\n                              </span>\n                            ) : null}\n                            {option.description ? (\n                              <span className=\"block truncate text-[0.9em] opacity-65\">\n                                {option.description}\n                              </span>\n                            ) : null}\n                          </button>\n                          {favorites ? (\n                            <button\n                              {...getFavoriteProps(option)}\n                              className={classes(\n                                base.favorite,\n                                classNames?.favorite\n                              )}\n                              data-preset-favorite\n                            >\n                              <span aria-hidden>{favorite ? \"★\" : \"☆\"}</span>\n                            </button>\n                          ) : null}\n                        </div>\n                      )\n                    })\n                    return group.label ? (\n                      <div key={index} role=\"group\" aria-label={group.label} data-preset-group>\n                        <div aria-hidden=\"true\" data-preset-group-heading style={{ padding: \"0.5rem 0.625rem 0.25rem\", fontWeight: 600, opacity: 0.65 }}>{group.label}</div>\n                        {rows}\n                      </div>\n                    ) : <Fragment key={index}>{rows}</Fragment>\n                  })\n                )}\n              </div>\n              {hasActions && actionPlacement === \"menu\" ? (\n                <div\n                  className={classes(base.actions, classNames?.actions)}\n                  data-preset-actions=\"menu\"\n                >\n                  {actionButtons(false)}\n                </div>\n              ) : null}\n            </Popover.Popup>\n          </Popover.Positioner>\n        </Popover.Portal>\n        ) : null}\n      </div>\n    </Popover.Root>\n  )\n}\n",
      "type": "registry:component",
      "target": "@ui/preset-selector.tsx"
    }
  ]
}
