{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "gradient-picker",
  "type": "registry:ui",
  "title": "Amplo Gradient Picker",
  "description": "Linear / radial / conic gradient editing on Base UI primitives — TypeSwitcher/InterpSwitcher/RadialSizeSelect on Select, ReverseStops and the StopList editor as semantic buttons, and a StopEditor composed from this variant's own Hue/Alpha/FormatSwitcher/ChannelInput. Pulls the color picker plus the shared gradient engine (Bar, Area, Overlay, pads, Presets, CssInput, stop popover shell) as registry dependencies.",
  "version": "2.0.0",
  "categories": [
    "color",
    "input",
    "design",
    "accessibility"
  ],
  "dependencies": [
    "@base-ui/react",
    "culori",
    "@types/culori",
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "https://amplo.ale.design/r/color-picker.json",
    "https://amplo.ale.design/r/gradient-picker-engine.json"
  ],
  "files": [
    {
      "path": "registry/new-york/ui/fill-picker-base/parts/gradient/field.tsx",
      "type": "registry:ui",
      "target": "@ui/fill-picker-base/parts/gradient/field.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { Select } from \"@base-ui/react/select\";\nimport { Check, ChevronDown } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\n// Base UI variant of the gradient field shell.\n//\n// FieldShell / FieldDivider / FieldInput / FieldInputGroup / FieldSuffix are\n// plain, variant-agnostic markup — re-exported from the original so both\n// pickers share one implementation. Only FieldSelect (built on shadcn\n// `<Select>` / Radix in the original) is rebuilt here on `@base-ui/react/select`.\nexport {\n  FieldShell,\n  FieldDivider,\n  FieldInput,\n  FieldInputGroup,\n  FieldSuffix,\n  type FieldInputProps,\n} from \"@/registry/new-york/ui/fill-picker/parts/field\";\n\nexport interface FieldSelectProps {\n  /**\n   * `standalone` (default) — bordered chevron-select matching every\n   * picker dropdown (`FormatSwitcher`, `TypeSwitcher`, `InterpSwitcher`,\n   * `RadialSizeSelect`).\n   *\n   * `inline` — borderless variant that lives inside a `FieldShell` (used\n   * by `ChannelInput`'s format toggle on the left).\n   */\n  variant?: \"standalone\" | \"inline\";\n  value?: string;\n  defaultValue?: string;\n  onValueChange?: (value: string) => void;\n  disabled?: boolean;\n  placeholder?: string;\n  /** Trigger button class — extends the variant's defaults. */\n  className?: string;\n  /** Props forwarded to the outer wrapper `<div>`. Use for `data-slot`,\n   *  width overrides, etc. */\n  wrapperProps?: React.HTMLAttributes<HTMLDivElement> & {\n    [key: `data-${string}`]: string | undefined;\n  };\n  /**\n   * Class applied to the popup (Base UI `Select.Popup`). Defaults to a\n   * `font-mono text-xs tracking-wide` block so item rows match the\n   * trigger font.\n   */\n  contentClassName?: string;\n  \"aria-label\"?: string;\n  /**\n   * Value → label map for the trigger's collapsed display. Base UI's\n   * `<Select.Value>` shows the raw value unless the root is told about\n   * item labels via `items` — pass this whenever an option's display\n   * label differs from its value (e.g. `\"linear\"` → `\"Linear\"`).\n   */\n  items?: Record<string, React.ReactNode>;\n  /** Pass `<FieldSelectItem>`s as children. */\n  children?: React.ReactNode;\n}\n\n/**\n * Single source of truth for every dropdown in the Base UI gradient\n * picker. Built on `@base-ui/react/select` so keyboard navigation, focus\n * management, and positioning are Base UI's — this file only supplies the\n * visual layer, matching the Radix `FieldSelect`'s look pixel-for-pixel.\n *\n * Mirrors the original `FieldSelect` API exactly (same props, same two\n * variants) so gradient parts are drop-in replacements of their Radix\n * counterparts.\n *\n * The forwarded ref points at the trigger button so consumers can\n * imperatively focus it, matching the original.\n */\nexport const FieldSelect = React.forwardRef<\n  HTMLButtonElement,\n  FieldSelectProps\n>(function FieldSelect(\n  {\n    variant = \"standalone\",\n    value,\n    defaultValue,\n    onValueChange,\n    disabled,\n    placeholder,\n    className,\n    wrapperProps,\n    contentClassName,\n    children,\n    items,\n    \"aria-label\": ariaLabel,\n  },\n  ref,\n) {\n  const inline = variant === \"inline\";\n  const { className: wrapperClassName, ...wrapperRest } = wrapperProps ?? {};\n  return (\n    <div\n      className={cn(\n        inline\n          ? \"relative inline-flex h-full shrink-0 items-center\"\n          : \"relative inline-flex items-center\",\n        wrapperClassName,\n      )}\n      {...wrapperRest}\n    >\n      <Select.Root\n        items={items}\n        value={value}\n        defaultValue={defaultValue}\n        onValueChange={(v) => {\n          if (v != null) onValueChange?.(v);\n        }}\n        disabled={disabled}\n      >\n        <Select.Trigger\n          ref={ref}\n          aria-label={ariaLabel}\n          className={cn(\n            \"flex items-center justify-between gap-2 font-mono text-xs tracking-wide outline-none\",\n            \"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50\",\n            inline\n              ? \"h-full rounded-none border-0 bg-transparent px-2 focus-visible:ring-0\"\n              : \"h-8 w-full rounded-md border border-input bg-transparent px-3 shadow-xs focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50\",\n            className,\n          )}\n        >\n          <Select.Value placeholder={placeholder} />\n          <Select.Icon>\n            <ChevronDown className=\"size-4 shrink-0 opacity-50\" />\n          </Select.Icon>\n        </Select.Trigger>\n        <Select.Portal>\n          <Select.Positioner sideOffset={4} className=\"z-50 outline-none\">\n            <Select.Popup\n              className={cn(\n                \"min-w-[var(--anchor-width)] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md outline-none\",\n                \"font-mono text-xs tracking-wide\",\n                contentClassName,\n              )}\n            >\n              {children}\n            </Select.Popup>\n          </Select.Positioner>\n        </Select.Portal>\n      </Select.Root>\n    </div>\n  );\n});\n\nexport interface FieldSelectItemProps {\n  value: string;\n  className?: string;\n  children?: React.ReactNode;\n}\n\n/**\n * Base UI counterpart of shadcn's `<SelectItem>` — the item type\n * `<FieldSelect>` expects as children. Kept intentionally minimal (value +\n * children only) since every gradient dropdown option is plain text or a\n * text row with a trailing info tooltip.\n */\nexport const FieldSelectItem = React.forwardRef<\n  HTMLDivElement,\n  FieldSelectItemProps\n>(function FieldSelectItem({ value, className, children }, ref) {\n  return (\n    <Select.Item\n      ref={ref}\n      value={value}\n      className={cn(\n        \"relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-none select-none\",\n        \"data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground\",\n        \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n        className,\n      )}\n    >\n      <span\n        data-slot=\"select-item-indicator\"\n        className=\"absolute right-2 flex size-3.5 items-center justify-center\"\n      >\n        <Select.ItemIndicator>\n          <Check className=\"size-4\" />\n        </Select.ItemIndicator>\n      </span>\n      <Select.ItemText>{children}</Select.ItemText>\n    </Select.Item>\n  );\n});\n"
    },
    {
      "path": "registry/new-york/ui/fill-picker-base/parts/gradient/type-switcher.tsx",
      "type": "registry:ui",
      "target": "@ui/fill-picker-base/parts/gradient/type-switcher.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { useGradientPickerContext } from \"@/registry/new-york/ui/fill-picker/contexts/gradient\";\nimport type { GradientType } from \"@/registry/new-york/ui/fill-picker/lib/gradient\";\nimport { FieldSelect, FieldSelectItem } from \"./field\";\nimport { GRADIENT_TYPE_OPTIONS } from \"@/registry/new-york/ui/fill-picker/lib/gradient-options\";\n\nconst TYPES = GRADIENT_TYPE_OPTIONS;\n\nconst TYPE_ITEMS = Object.fromEntries(\n  TYPES.map((t) => [t.value, t.label]),\n) as Record<GradientType, string>;\n\n/**\n * Base UI port of `<GradientPicker.TypeSwitcher>`. Bound to `gradient.type`.\n * Built on `<FieldSelect>` (Base UI `Select` under the hood) so it shares\n * its border, focus ring, font, and chevron with every other dropdown in\n * the Base UI picker.\n *\n * Width is intrinsic (not `w-full`) so it can sit next to icon buttons\n * like `<GradientPickerBase.ReverseStops>` without stretching the row.\n */\nexport const TypeSwitcher = React.forwardRef<\n  HTMLButtonElement,\n  { className?: string }\n>(function TypeSwitcher({ className }, ref) {\n  const ctx = useGradientPickerContext();\n  return (\n    <FieldSelect\n      ref={ref}\n      aria-label=\"Gradient type\"\n      value={ctx.gradient.type}\n      onValueChange={(v) => ctx.setType(v as GradientType)}\n      items={TYPE_ITEMS}\n      wrapperProps={{\n        \"data-slot\": \"gradient-type-switcher\",\n        className,\n      }}\n    >\n      {TYPES.map((t) => (\n        <FieldSelectItem key={t.value} value={t.value}>\n          {t.label}\n        </FieldSelectItem>\n      ))}\n    </FieldSelect>\n  );\n});\n"
    },
    {
      "path": "registry/new-york/ui/fill-picker-base/parts/gradient/interp-switcher.tsx",
      "type": "registry:ui",
      "target": "@ui/fill-picker-base/parts/gradient/interp-switcher.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { Info } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { Tooltip } from \"@base-ui/react/tooltip\";\nimport { useGradientPickerContext } from \"@/registry/new-york/ui/fill-picker/contexts/gradient\";\nimport type { GradientInterp } from \"@/registry/new-york/ui/fill-picker/lib/gradient\";\nimport { FieldSelect, FieldSelectItem } from \"./field\";\nimport { GRADIENT_INTERP_OPTIONS } from \"@/registry/new-york/ui/fill-picker/lib/gradient-options\";\n\nconst OPTIONS = GRADIENT_INTERP_OPTIONS;\n\nconst INTERP_ITEMS = Object.fromEntries(\n  OPTIONS.map((o) => [o.value, o.label]),\n) as Record<GradientInterp, string>;\n\nexport interface InterpSwitcherProps {\n  className?: string;\n  /** Applied to the select trigger. */\n  triggerClassName?: string;\n}\n\n/**\n * Base UI port of `<GradientPicker.InterpSwitcher>`. Bound to the active\n * gradient's `interp` property. Switching only changes the blending math\n * between stops — stop positions and colors stay identical.\n *\n * Must render inside `<GradientPickerBase.Root>` — throws otherwise.\n */\nexport const InterpSwitcher = React.forwardRef<\n  HTMLButtonElement,\n  InterpSwitcherProps\n>(function InterpSwitcher({ className, triggerClassName }, ref) {\n  const ctx = useGradientPickerContext();\n  // delay=0: parity with the Radix shells, which inherit the shadcn wrapper default (0). Base UI's own default is 600.\n  return (\n    <Tooltip.Provider delay={0}>\n      <FieldSelect\n        ref={ref}\n        aria-label=\"Interpolation space\"\n        value={ctx.gradient.interp}\n        onValueChange={(v) => ctx.setInterp(v as GradientInterp)}\n        items={INTERP_ITEMS}\n        wrapperProps={{ \"data-slot\": \"gradient-interp-switcher\", className: \"w-full\" }}\n        className={cn(\"w-full\", triggerClassName, className)}\n      >\n        {OPTIONS.map((opt) => (\n          <RowWithInfo\n            key={opt.value}\n            value={opt.value}\n            label={opt.label}\n            description={opt.description}\n          />\n        ))}\n      </FieldSelect>\n    </Tooltip.Provider>\n  );\n});\n\nfunction RowWithInfo({\n  value,\n  label,\n  description,\n}: {\n  value: string;\n  label: string;\n  description: string;\n}) {\n  return (\n    <FieldSelectItem value={value} className=\"pr-8\">\n      <span className=\"flex w-full items-center gap-2\">\n        <span className=\"flex-1\">{label}</span>\n        <Tooltip.Root>\n          <Tooltip.Trigger\n            render={\n              <span\n                role=\"img\"\n                aria-label={`About ${label}`}\n                className=\"inline-flex shrink-0 cursor-help text-muted-foreground hover:text-foreground\"\n              >\n                <Info className=\"size-3\" aria-hidden />\n              </span>\n            }\n          />\n          <Tooltip.Portal>\n            {/* z-50 on the POSITIONER, not just the popup: the positioner is\n                the element that competes with the Select popup's z-50\n                positioner — with z-auto it renders behind the open menu. */}\n            <Tooltip.Positioner\n              side=\"right\"\n              align=\"center\"\n              sideOffset={4}\n              className=\"z-50\"\n            >\n              <Tooltip.Popup\n                className={cn(\n                  \"z-50 max-w-[220px] overflow-hidden rounded-md bg-foreground px-3 py-1.5 text-[11px] normal-case tracking-normal text-background\",\n                )}\n              >\n                {description}\n              </Tooltip.Popup>\n            </Tooltip.Positioner>\n          </Tooltip.Portal>\n        </Tooltip.Root>\n      </span>\n    </FieldSelectItem>\n  );\n}\n"
    },
    {
      "path": "registry/new-york/ui/fill-picker-base/parts/gradient/radial-size-select.tsx",
      "type": "registry:ui",
      "target": "@ui/fill-picker-base/parts/gradient/radial-size-select.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { Info } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { Tooltip } from \"@base-ui/react/tooltip\";\nimport { useGradientPickerContext } from \"@/registry/new-york/ui/fill-picker/contexts/gradient\";\nimport type { RadialSizeKeyword } from \"@/registry/new-york/ui/fill-picker/lib/gradient\";\nimport { FieldSelect, FieldSelectItem } from \"./field\";\nimport { RADIAL_SIZE_OPTIONS } from \"@/registry/new-york/ui/fill-picker/lib/gradient-options\";\n\nconst SIZE_OPTIONS = RADIAL_SIZE_OPTIONS;\n\nexport interface RadialSizeSelectProps {\n  className?: string;\n  /** Applied to the select trigger. */\n  triggerClassName?: string;\n}\n\n/** Base UI port of `<GradientPicker.RadialSizeSelect>`. */\nexport const RadialSizeSelect = React.forwardRef<\n  HTMLButtonElement,\n  RadialSizeSelectProps\n>(function RadialSizeSelect({ className, triggerClassName }, ref) {\n  const ctx = useGradientPickerContext();\n  if (ctx.gradient.type !== \"radial\") return null;\n  // delay=0: parity with the Radix shells, which inherit the shadcn wrapper default (0). Base UI's own default is 600.\n  return (\n    <Tooltip.Provider delay={0}>\n      <FieldSelect\n        ref={ref}\n        aria-label=\"Radial size\"\n        value={ctx.gradient.size}\n        onValueChange={(v) => ctx.setRadialSize(v as RadialSizeKeyword)}\n        wrapperProps={{ \"data-slot\": \"gradient-radial-size-select\", className: \"w-full\" }}\n        className={cn(\"w-full\", triggerClassName, className)}\n      >\n        {SIZE_OPTIONS.map((opt) => (\n          <RowWithInfo key={opt.value} value={opt.value} description={opt.description} />\n        ))}\n      </FieldSelect>\n    </Tooltip.Provider>\n  );\n});\n\nfunction RowWithInfo({\n  value,\n  description,\n}: {\n  value: string;\n  description: string;\n}) {\n  return (\n    <FieldSelectItem value={value} className=\"pr-8\">\n      <span className=\"flex w-full items-center gap-2\">\n        <span className=\"flex-1\">{value}</span>\n        <Tooltip.Root>\n          <Tooltip.Trigger\n            render={\n              // Span (not button) so Base UI Select still owns the click\n              // for row selection — the icon is just a hover affordance.\n              <span\n                role=\"img\"\n                aria-label={`About ${value}`}\n                className=\"inline-flex shrink-0 cursor-help text-muted-foreground hover:text-foreground\"\n              >\n                <Info className=\"size-3\" aria-hidden />\n              </span>\n            }\n          />\n          <Tooltip.Portal>\n            {/* z-50 on the POSITIONER, not just the popup: the positioner is\n                the element that competes with the Select popup's z-50\n                positioner — with z-auto it renders behind the open menu. */}\n            <Tooltip.Positioner\n              side=\"right\"\n              align=\"center\"\n              sideOffset={4}\n              className=\"z-50\"\n            >\n              <Tooltip.Popup\n                className={cn(\n                  \"z-50 max-w-[220px] overflow-hidden rounded-md bg-foreground px-3 py-1.5 text-[11px] normal-case tracking-normal text-background\",\n                )}\n              >\n                {description}\n              </Tooltip.Popup>\n            </Tooltip.Positioner>\n          </Tooltip.Portal>\n        </Tooltip.Root>\n      </span>\n    </FieldSelectItem>\n  );\n}\n"
    },
    {
      "path": "registry/new-york/ui/fill-picker-base/parts/gradient/reverse-stops.tsx",
      "type": "registry:ui",
      "target": "@ui/fill-picker-base/parts/gradient/reverse-stops.tsx",
      "content": "\"use client\";\n\n// Re-export, not a fork.\n//\n// This part is a plain shadcn `<Button>` over `ctx.reverseStops` with zero\n// Radix-specific surface — since the shared primitives moved to Base UI\n// (`useRender`, no Radix `Slot`), the original works unchanged in this\n// variant. Forking it bought nothing and risked the two copies drifting.\n//\n// The file is kept at this path (rather than dropped in favour of importing\n// the original directly in `gradient.tsx`) so anyone deep-importing\n// `.../fill-picker-base/parts/gradient/reverse-stops` keeps resolving.\nexport { ReverseStops } from \"@/registry/new-york/ui/fill-picker/parts/gradient/reverse-stops\";\n"
    },
    {
      "path": "registry/new-york/ui/fill-picker-base/parts/gradient/stop-list.tsx",
      "type": "registry:ui",
      "target": "@ui/fill-picker-base/parts/gradient/stop-list.tsx",
      "content": "\"use client\";\n\n// Re-export, not a fork.\n//\n// The original StopList touches no Radix primitive: its rows are plain markup,\n// its keyboard/selection/insert logic already lives in the shared\n// `stop-list-shared` helpers, its stop editor is a slot injected by whichever\n// barrel mounted the tree (`useGradientStopEditor` — so under this variant the\n// rows open ./stop-editor, the Base UI one), and the only field parts it uses\n// — FieldInput / FieldInputGroup / FieldShell / FieldSuffix — are re-exported\n// verbatim from the original by this variant's own `./field`. It never touches\n// `FieldSelect`, the one field part that genuinely differs between variants.\n//\n// So the fork was a byte-for-byte copy modulo import paths, and its only\n// effect was the risk of the two lists' keyboard behaviour drifting apart.\n//\n// The file is kept at this path (rather than dropped in favour of importing\n// the original directly in `gradient.tsx`) so anyone deep-importing\n// `.../fill-picker-base/parts/gradient/stop-list` keeps resolving.\nexport {\n  StopList,\n  type StopListProps,\n} from \"@/registry/new-york/ui/fill-picker/parts/gradient/stop-list\";\n"
    },
    {
      "path": "registry/new-york/ui/fill-picker-base/parts/gradient/stop-editor.tsx",
      "type": "registry:ui",
      "target": "@ui/fill-picker-base/parts/gradient/stop-editor.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { StopPopover } from \"@/registry/new-york/ui/fill-picker/parts/gradient/stop-popover\";\nimport { ColorPickerContext } from \"@/registry/new-york/ui/fill-picker/context\";\nimport type { GradientStopEditorRenderer } from \"@/registry/new-york/ui/fill-picker/contexts/gradient\";\nimport { useStopColorPickerState } from \"@/registry/new-york/ui/fill-picker/parts/gradient/stop-editor-shared\";\nimport { Area as ColorArea } from \"@/registry/new-york/ui/fill-picker/parts/area\";\nimport { EyeDropper } from \"@/registry/new-york/ui/fill-picker/parts/eye-dropper\";\n\nimport { Hue } from \"../hue\";\nimport { Alpha } from \"../alpha\";\nimport { ChannelInput } from \"../channel-input\";\nimport { FormatSwitcher } from \"../format-switcher\";\n\nexport interface StopEditorProps {\n  /** Stop the popover edits — color + per-stop format are read/written via gradient context. */\n  stopId: string;\n  /**\n   * Controlled open state. Required — open is always external because\n   * the anchor element typically has its own pointer handling (drag on\n   * Bar handles, click on StopList swatches) that would conflict with\n   * a trigger-managed open state.\n   */\n  open: boolean;\n  onOpenChange: (open: boolean) => void;\n  /** Anchor element. Positioned against; provides positioning only. */\n  children: React.ReactElement;\n}\n\n/**\n * Base UI variant of `<StopEditorPopover>`: same layout, same bound state\n * (`useStopColorPickerState`, shared with the original so the memoization\n * subtleties can't drift), but composed from this tree's Base UI parts —\n * Hue/Alpha on Slider, FormatSwitcher on Select, ChannelInput on NumberField.\n *\n * Area and EyeDropper come from the engine unchanged: they're pointer/canvas\n * logic and a plain shadcn Button, already shipped as-is by this variant's\n * `color-picker.tsx`.\n *\n * The popover shell is the engine's `StopPopover` — already built directly on\n * `@base-ui/react/popover` (anchor-without-trigger, z-50 positioner), so\n * there's nothing Radix-flavoured to re-do.\n */\nexport function StopEditor({\n  stopId,\n  open,\n  onOpenChange,\n  children,\n}: StopEditorProps) {\n  const state = useStopColorPickerState(stopId);\n  return (\n    <StopPopover\n      open={open}\n      onOpenChange={onOpenChange}\n      anchor={children}\n      className=\"flex w-72 flex-col gap-3\"\n      onContentClick={(e) => e.stopPropagation()}\n    >\n      <ColorPickerContext.Provider value={state}>\n        <ColorArea mode=\"oklch-cl\" />\n        <div className=\"flex flex-col gap-1.5\">\n          <Hue />\n          <Alpha />\n        </div>\n        <div className=\"flex items-center gap-2\">\n          <FormatSwitcher className=\"flex-1\" />\n          <EyeDropper className=\"h-8 w-full flex-1\" />\n        </div>\n        <ChannelInput showFormat={false} />\n      </ColorPickerContext.Provider>\n    </StopPopover>\n  );\n}\n\n/**\n * `<GradientPickerBase.Bar editOnClick>`'s stop-editor slot, filled with the\n * editor above. Injected as the default by the Base UI barrels\n * (`gradient.tsx`, `fill.tsx`).\n */\nexport const stopEditorSlot: GradientStopEditorRenderer = ({\n  children,\n  ...props\n}) => (\n  // The Bar always passes a single element (the stop handle) as `children`;\n  // the slot type is widened to ReactNode only because it is React's own\n  // children convention.\n  <StopEditor {...props}>{children as React.ReactElement}</StopEditor>\n);\n"
    },
    {
      "path": "registry/new-york/ui/fill-picker-base/gradient.tsx",
      "type": "registry:ui",
      "target": "@ui/fill-picker-base/gradient.tsx",
      "content": "\"use client\";\n\n// Base UI variant of the gradient picker.\n//\n// Mirrors `registry/new-york/ui/fill-picker/gradient-picker.tsx`'s public\n// surface. Only the parts that touch Radix/shadcn primitives directly are\n// rewritten on Base UI:\n//   - TypeSwitcher, InterpSwitcher, RadialSizeSelect → Select\n//   - ReverseStops                                   → plain button\n//   - StopList                                       → plain button (+\n//     the shared field shell), re-exported from the original (see\n//     stop-list.tsx for why)\n//   - the per-stop color editor → ./parts/gradient/stop-editor, injected\n//     below through the `stopEditor` slot. Both `<Bar editOnClick>` and\n//     `<StopList>` rows read that slot instead of importing an editor, so\n//     they stay dialect-free and open *this* variant's editor here.\n//\n// Everything else (Root/context, Bar, Area, Overlay, ShapeSwitcher, the\n// pad/input/group parts, StopColor, Presets, CssInput, RepeatingToggle) is\n// pure pointer/canvas logic or plain markup with zero Radix dependency, so\n// it's imported straight from the original — a single source of truth for\n// engine fixes.\n\nimport * as React from \"react\";\nimport { ColorPickerBase } from \"./color-picker\";\n\nimport {\n  Root as EngineGradientRoot,\n  type RootProps as GradientRootProps,\n} from \"@/registry/new-york/ui/fill-picker/parts/gradient/root\";\nimport { Bar } from \"@/registry/new-york/ui/fill-picker/parts/gradient/bar\";\nimport { Area as GradientArea } from \"@/registry/new-york/ui/fill-picker/parts/gradient/area\";\nimport { Overlay as GradientOverlay } from \"@/registry/new-york/ui/fill-picker/parts/gradient/overlay\";\nimport { RepeatingToggle } from \"@/registry/new-york/ui/fill-picker/parts/gradient/repeating-toggle\";\nimport { AnglePad } from \"@/registry/new-york/ui/fill-picker/parts/gradient/angle-pad\";\nimport { AngleInput } from \"@/registry/new-york/ui/fill-picker/parts/gradient/angle-input\";\nimport { PositionPad } from \"@/registry/new-york/ui/fill-picker/parts/gradient/position-pad\";\nimport { PositionInput } from \"@/registry/new-york/ui/fill-picker/parts/gradient/position-input\";\nimport { ShapeSwitcher } from \"@/registry/new-york/ui/fill-picker/parts/gradient/shape-switcher\";\nimport { RadiusInput } from \"@/registry/new-york/ui/fill-picker/parts/gradient/radius-input\";\nimport { EllipseRadiiInput } from \"@/registry/new-york/ui/fill-picker/parts/gradient/ellipse-radii-input\";\nimport { StopColor } from \"@/registry/new-york/ui/fill-picker/parts/gradient/stop-color\";\nimport { Presets, BUILTIN_GRADIENT_PRESETS } from \"@/registry/new-york/ui/fill-picker/parts/gradient/presets\";\nimport { CssInput as GradientCssInput } from \"@/registry/new-york/ui/fill-picker/parts/gradient/css-input\";\nimport { PositionGroup } from \"@/registry/new-york/ui/fill-picker/parts/gradient/position-group\";\nimport { AngleGroup } from \"@/registry/new-york/ui/fill-picker/parts/gradient/angle-group\";\n\nimport { TypeSwitcher } from \"./parts/gradient/type-switcher\";\nimport { ReverseStops } from \"./parts/gradient/reverse-stops\";\nimport { StopList } from \"./parts/gradient/stop-list\";\nimport { InterpSwitcher } from \"./parts/gradient/interp-switcher\";\nimport { RadialSizeSelect } from \"./parts/gradient/radial-size-select\";\nimport { stopEditorSlot } from \"./parts/gradient/stop-editor\";\n\nexport type {\n  Gradient,\n  GradientType,\n  GradientInterp,\n  GradientStop,\n  LinearGradient,\n  RadialGradient,\n  RadialSizeKeyword,\n  ConicGradient,\n} from \"@/registry/new-york/ui/fill-picker/lib/gradient\";\nexport {\n  formatGradient,\n  parseGradient,\n  DEFAULT_LINEAR,\n  DEFAULT_RADIAL,\n  DEFAULT_CONIC,\n} from \"@/registry/new-york/ui/fill-picker/lib/gradient\";\nexport { BUILTIN_GRADIENT_PRESETS };\nexport { useGradientPicker } from \"@/registry/new-york/ui/fill-picker/hooks/use-gradient-picker\";\nexport type {\n  UseGradientPickerProps,\n  GradientPickerState,\n} from \"@/registry/new-york/ui/fill-picker/hooks/use-gradient-picker\";\n\n// The gradient context surface, re-exported so the barrel is a complete\n// entry point for anyone composing custom gradient parts (a part needs\n// `useGradientPickerContext` to read state, and `GradientStopEditor*` to\n// fill the stop-editor slot). This also keeps the barrel self-consistent\n// with how the shadcn CLI rewrites installed imports: its import-fixup pass\n// resolves an aliased specifier by file BASENAME and prefers a `.tsx`\n// candidate over a `.ts` one, so `.../fill-picker/contexts/gradient.ts`\n// gets redirected to this file (`fill-picker-base/gradient.tsx`) in a\n// consumer project. Export-from specifiers are exempt from that pass, so\n// the re-exports below stay pointed at the real module.\n//\n// Cycle invariant: because of that same redirect, an INSTALLED consumer's\n// sibling parts (`./parts/gradient/{type,interp}-switcher`,\n// `radial-size-select`, `stop-editor`, and `./fill`) import their context\n// from *this barrel* rather than from `contexts/gradient` — and this barrel\n// imports those parts back. That module cycle is benign only because every\n// redirected binding is referenced inside a component body / hook call at\n// render time, never at module-eval time: by the time anything reads\n// `useGradientPickerContext`, both halves of the cycle have finished\n// evaluating. Keep new module-scope evaluation out of the base gradient\n// parts — a top-level `const x = useGradientPickerContext` or a\n// `Context.Provider` captured into a module constant would read a\n// still-uninitialized binding and blow up in consumer projects while\n// staying green in this repo (where TypeScript resolves the honest path\n// and there is no cycle at all). The build's basename-collision lint\n// guards the export side of this; nothing can guard the eval side but\n// this comment.\nexport {\n  GradientPickerContext,\n  GradientStopEditorContext,\n  useGradientPickerContext,\n  useGradientStopEditor,\n} from \"@/registry/new-york/ui/fill-picker/contexts/gradient\";\nexport type { GradientStopEditorRenderer } from \"@/registry/new-york/ui/fill-picker/contexts/gradient\";\n\nexport { ColorPickerBase };\n\n/**\n * The engine `Root` plus this variant's stop editor (Base UI Hue/Alpha/\n * FormatSwitcher/ChannelInput inside the shared popover shell). The Bar\n * imports no editor of its own — it renders whatever is injected here.\n */\nconst GradientRoot = React.forwardRef<HTMLDivElement, GradientRootProps>(\n  function Root({ stopEditor = stopEditorSlot, ...props }, ref) {\n    return <EngineGradientRoot ref={ref} stopEditor={stopEditor} {...props} />;\n  },\n);\n\nexport const GradientPickerBase = {\n  Root: GradientRoot,\n  Bar,\n  Area: GradientArea,\n  Overlay: GradientOverlay,\n  TypeSwitcher,\n  ReverseStops,\n  RepeatingToggle,\n  AnglePad,\n  AngleInput,\n  PositionPad,\n  PositionInput,\n  ShapeSwitcher,\n  RadiusInput,\n  EllipseRadiiInput,\n  RadialSizeSelect,\n  StopList,\n  StopColor,\n  InterpSwitcher,\n  Presets,\n  CssInput: GradientCssInput,\n  PositionGroup,\n  AngleGroup,\n};\n\n// Plain-name aliases so consumers (and docs snippets) can swap variants by\n// changing only the import path — mirrors `ColorPicker` in color-picker.tsx.\nexport const GradientPicker = GradientPickerBase;\nexport { ColorPicker } from \"./color-picker\";\n"
    }
  ]
}
