{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "tradecn",
  "homepage": "https://github.com/tradecn/ui",
  "items": [
    {
      "name": "format",
      "type": "registry:lib",
      "title": "Format",
      "description": "Number formatting for trading screens: tick-derived precision, 32nds and 64ths with + halves, yields, basis points, DV01, compact notional, signed values, one null sentinel.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/tradecn/lib/format.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "format"
      ],
      "docs": "Pure functions, no dependencies. Bind a convention per instrument with createInstrumentFormatter and pass its price() to a grid column."
    },
    {
      "name": "row-store",
      "type": "registry:lib",
      "title": "Row Store",
      "description": "Store-agnostic row store for high-rate feeds: apply one delta batch per frame, subscribe per row, sorted and filtered views with a reorder hold, and a frame batcher for message-driven feeds.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/tradecn/lib/row-store.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/tradecn/hooks/use-row-store.ts",
          "type": "registry:hook"
        }
      ],
      "categories": [
        "grid",
        "feed"
      ],
      "docs": "Your feed calls store.applyDeltas(batch) once per frame. Components read rows with useRow(store, id) and re-render only when that row changes. Wrap message-at-a-time feeds in createFrameBatcher."
    },
    {
      "name": "flash-cell",
      "type": "registry:ui",
      "title": "Flash Cell",
      "description": "A cell that flashes on change, colored up, down, or flat, as a fill or an inset ring. Web Animations on the existing element, a shared memory so virtualized rows resume mid-flash, reduced-motion aware. Introduces the up/down/flat tokens.",
      "dependencies": [
        "cn@^0.3.0"
      ],
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/tradecn/ui/flash-cell.tsx",
          "type": "registry:ui"
        },
        {
          "path": "registry/tradecn/hooks/use-flash.ts",
          "type": "registry:hook"
        }
      ],
      "categories": [
        "grid",
        "feed"
      ],
      "docs": "Adds up, down, flat and their -soft tokens to your stylesheet as bg-up-soft, text-down and so on. Override --up and --down in your own CSS; later installs keep your values. Zero change is flat, never up.",
      "meta": {
        "components": [
          {
            "title": "FlashCell",
            "description": "Cell wrapper that flashes on value change."
          }
        ]
      },
      "cssVars": {
        "light": {
          "down": "oklch(0.58 0.19 45)",
          "down-soft": "oklch(0.58 0.19 45 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.55 0 0 / 14%)",
          "up": "oklch(0.58 0.14 165)",
          "up-soft": "oklch(0.58 0.14 165 / 18%)"
        },
        "dark": {
          "down": "oklch(0.74 0.18 45)",
          "down-soft": "oklch(0.74 0.18 45 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.7 0 0 / 14%)",
          "up": "oklch(0.74 0.15 165)",
          "up-soft": "oklch(0.74 0.15 165 / 18%)"
        }
      }
    },
    {
      "name": "data-grid",
      "type": "registry:ui",
      "title": "Data Grid",
      "description": "Virtualized grid fed by a row store one row at a time: a delta re-renders one row, numeric cells flash by direction, frozen and resizable columns, keyboard selection by row id, a reorder hold, a right-click menu, presets for blotter, watchlist, RFQ, and option chain.",
      "dependencies": [
        "cn@^0.3.0",
        "@tanstack/react-virtual@^3.14.13"
      ],
      "registryDependencies": [
        "checkbox",
        "context-menu",
        "dropdown-menu"
      ],
      "files": [
        {
          "path": "registry/tradecn/ui/data-grid.tsx",
          "type": "registry:ui"
        },
        {
          "path": "registry/tradecn/hooks/use-flash.ts",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/hooks/use-row-store.ts",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/lib/row-store.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/tradecn/lib/format.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "grid",
        "blotter",
        "watchlist"
      ],
      "docs": "Feed it a RowStore (installed alongside) and column definitions. Fixed row height; the grid positions rows itself. Adds @tanstack/react-virtual and the up/down/flat tokens. Composes your checkbox, context-menu, and dropdown-menu.",
      "meta": {
        "components": [
          {
            "title": "DataGrid",
            "description": "The grid."
          },
          {
            "title": "DATA_GRID_PRESETS",
            "description": "Density and behavior bundles: blotter, watchlist, rfq, option-chain."
          },
          {
            "title": "exportCsv",
            "description": "CSV of given rows through the column formatters."
          }
        ]
      },
      "cssVars": {
        "light": {
          "down": "oklch(0.58 0.19 45)",
          "down-soft": "oklch(0.58 0.19 45 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.55 0 0 / 14%)",
          "up": "oklch(0.58 0.14 165)",
          "up-soft": "oklch(0.58 0.14 165 / 18%)"
        },
        "dark": {
          "down": "oklch(0.74 0.18 45)",
          "down-soft": "oklch(0.74 0.18 45 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.7 0 0 / 14%)",
          "up": "oklch(0.74 0.15 165)",
          "up-soft": "oklch(0.74 0.15 165 / 18%)"
        }
      }
    },
    {
      "name": "feed-health",
      "type": "registry:ui",
      "title": "Feed Health",
      "description": "A strip that shows each feed's connection state, the age of its data, and a staleness tier, with drop counts for coalesced lanes and gap indicators for ordered ones. Pluggable thresholds and session calendar; only the leaves tick.",
      "dependencies": [
        "cn@^0.3.0"
      ],
      "registryDependencies": [
        "badge",
        "separator",
        "spinner",
        "tooltip"
      ],
      "files": [
        {
          "path": "registry/tradecn/ui/feed-health.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "feed",
        "chrome"
      ],
      "docs": "Adds the stale and up tokens. The default thresholds (2 s aging, 10 s stale) are placeholders: agree real ones with the people who trade on the data and pass them in.",
      "meta": {
        "components": [
          {
            "title": "FeedHealth",
            "description": "The strip."
          },
          {
            "title": "FeedAge",
            "description": "A self-ticking age for one feed."
          },
          {
            "title": "stalenessTier",
            "description": "Pure tiering: live, aging, stale, offline, closed."
          },
          {
            "title": "createClock",
            "description": "A shared interval that runs only while subscribed."
          }
        ]
      },
      "cssVars": {
        "light": {
          "stale": "oklch(0.72 0.16 75)",
          "stale-soft": "oklch(0.72 0.16 75 / 16%)",
          "up": "oklch(0.58 0.14 165)"
        },
        "dark": {
          "stale": "oklch(0.8 0.15 80)",
          "stale-soft": "oklch(0.8 0.15 80 / 16%)",
          "up": "oklch(0.74 0.15 165)"
        }
      }
    },
    {
      "name": "use-hotkeys",
      "type": "registry:hook",
      "title": "Hotkeys",
      "description": "A hotkey registry: bindings declared as data with an id, keys, a scope, and a description; one keydown listener; scopes read from the DOM so a panel's keys beat global ones; chords with a timeout; conflict detection; remapping with the consumer's persistence. Typing is protected, menus are left alone, and a dialog is a wall.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/tradecn/hooks/use-hotkeys.tsx",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/lib/hotkeys.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "hotkeys"
      ],
      "docs": "Declare bindings once, wrap the app in HotkeysProvider, attach handlers with useHotkey. list() is the single source for a palette's shortcut column and a help overlay. No dependencies beyond React.",
      "meta": {
        "components": [
          {
            "title": "HotkeysProvider",
            "description": "Puts a registry in context and listens for keydown."
          },
          {
            "title": "HotkeyScope",
            "description": "Marks a subtree as a scope; keys pressed inside it reach that scope's bindings first."
          },
          {
            "title": "useHotkey",
            "description": "Attaches a handler to a declared binding while the component is mounted."
          },
          {
            "title": "useHotkeys",
            "description": "The registry from context."
          },
          {
            "title": "useHotkeyList",
            "description": "Every binding with its keys in force, live."
          },
          {
            "title": "usePendingChord",
            "description": "The chord typed so far, or null."
          }
        ]
      }
    },
    {
      "name": "command-palette",
      "type": "registry:ui",
      "title": "Command Palette",
      "description": "A command palette on your own shadcn command: actions from a registry, a second action per row on Shift+Enter, async symbol search through an adapter you supply, recents, and shortcuts rendered live from the hotkey registry. A go-bar variant renders inline and reads SYMBOL FUNCTION commands through your grammar.",
      "dependencies": [
        "cn@^0.3.0"
      ],
      "registryDependencies": [
        "badge",
        "command",
        "kbd"
      ],
      "files": [
        {
          "path": "registry/tradecn/ui/command-palette.tsx",
          "type": "registry:ui"
        },
        {
          "path": "registry/tradecn/hooks/use-hotkeys.tsx",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/lib/hotkeys.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "palette",
        "hotkeys"
      ],
      "docs": "Composes your command (and the dialog and input-group it brings), kbd, and badge. Installs the hotkey registry alongside; inside a HotkeysProvider the palette declares palette.open on mod+k, and remaps show on the rows. No dependency beyond cn: cmdk comes with your own command component.",
      "meta": {
        "components": [
          {
            "title": "CommandPalette",
            "description": "The palette, as a dialog or an inline go-bar."
          },
          {
            "title": "createActionRegistry",
            "description": "Actions and recents, shared by every palette that reads it."
          },
          {
            "title": "scorePaletteAction",
            "description": "The ranking the palette filters with, as a pure function."
          }
        ]
      }
    },
    {
      "name": "panel",
      "type": "registry:ui",
      "title": "Panel",
      "description": "The frame around a book, a chart, or a blotter. A panel is a hotkey scope, so its keys and its palette actions come with it. A header that is a drag handle, a symbol tag you click to retype, link groups that carry a symbol between panels and between windows, and a popout that moves the panel to its own window without remounting it.",
      "dependencies": [
        "cn@^0.3.0"
      ],
      "registryDependencies": [
        "input"
      ],
      "files": [
        {
          "path": "registry/tradecn/ui/panel.tsx",
          "type": "registry:ui"
        },
        {
          "path": "registry/tradecn/hooks/use-link-group.tsx",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/hooks/use-popout.ts",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/hooks/use-hotkeys.tsx",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/lib/link-group.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/tradecn/lib/hotkeys.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "layout",
        "chrome"
      ],
      "docs": "Adds the panel-active, panel-drag-target, panel-error, panel-sync, and link-1 to link-4 tokens. Composes your input. Link groups need a LinkGroupProvider above the panels; it opens a BroadcastChannel so other windows follow, and transport={null} keeps links in one window. Installs the hotkey registry alongside; a Panel works without a HotkeysProvider and its keys start working inside one.",
      "meta": {
        "components": [
          {
            "title": "Panel",
            "description": "The frame, and the hotkey scope panel:<kind>."
          },
          {
            "title": "PanelHeader",
            "description": "The strip along the top, and the drag handle."
          },
          {
            "title": "PanelTitle",
            "description": "Names the panel, to the eye and to a screen reader."
          },
          {
            "title": "PanelActions",
            "description": "Your buttons at the far end of the header."
          },
          {
            "title": "PanelContent",
            "description": "The scrolling body."
          },
          {
            "title": "SymbolTag",
            "description": "The panel's symbol: click to retype, Enter commits, Escape and clicking away cancel."
          },
          {
            "title": "LinkGroupDot",
            "description": "The panel's link group as a color and a number; click to move to the next."
          },
          {
            "title": "PanelPopout",
            "description": "Renders its children in the page or in the popout window, without remounting them."
          }
        ]
      },
      "cssVars": {
        "light": {
          "link-1": "oklch(0.62 0.2 25)",
          "link-2": "oklch(0.62 0.15 250)",
          "link-3": "oklch(0.65 0.15 150)",
          "link-4": "oklch(0.8 0.16 90)",
          "panel-active": "var(--color-primary)",
          "panel-drag-target": "var(--color-ring)",
          "panel-error": "var(--color-destructive)",
          "panel-sync": "oklch(0.7 0.12 220)"
        },
        "dark": {
          "link-1": "oklch(0.7 0.19 25)",
          "link-2": "oklch(0.7 0.14 250)",
          "link-3": "oklch(0.74 0.14 150)",
          "link-4": "oklch(0.85 0.15 90)",
          "panel-active": "var(--color-primary)",
          "panel-drag-target": "var(--color-ring)",
          "panel-error": "var(--color-destructive)",
          "panel-sync": "oklch(0.78 0.12 220)"
        }
      }
    },
    {
      "name": "sparkline",
      "type": "registry:ui",
      "title": "Sparkline",
      "description": "A line small enough for a grid cell that still says which way, how far, and between what. Colored by direction against the first reading or a baseline, with the same direction in words for a screen reader. A missing reading is a gap, not a shift. Fixed size for a grid column, or it fills its box through one shared ResizeObserver. An optional crosshair that moves with the pointer and the arrow keys.",
      "dependencies": [
        "cn@^0.3.0"
      ],
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/tradecn/ui/sparkline.tsx",
          "type": "registry:ui"
        },
        {
          "path": "registry/tradecn/hooks/use-flash.ts",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/lib/sparkline-geometry.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "grid",
        "watchlist"
      ],
      "docs": "Adds the up, down, flat tokens and their -soft variants, the same ones flash-cell uses. Give it width and height inside a grid column and it observes nothing. It draws every reading you pass; decimate a long history before it gets here.",
      "meta": {
        "components": [
          {
            "title": "Sparkline",
            "description": "The line, and the crosshair when interactive."
          }
        ]
      },
      "cssVars": {
        "light": {
          "down": "oklch(0.58 0.19 45)",
          "down-soft": "oklch(0.58 0.19 45 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.55 0 0 / 14%)",
          "up": "oklch(0.58 0.14 165)",
          "up-soft": "oklch(0.58 0.14 165 / 18%)"
        },
        "dark": {
          "down": "oklch(0.74 0.18 45)",
          "down-soft": "oklch(0.74 0.18 45 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.7 0 0 / 14%)",
          "up": "oklch(0.74 0.15 165)",
          "up-soft": "oklch(0.74 0.15 165 / 18%)"
        }
      }
    },
    {
      "name": "watchlist",
      "type": "registry:ui",
      "title": "Watchlist",
      "description": "The data grid as a watchlist: symbol, last, bid, ask, change, change %, and volume, with prices printed through your convention per row. A field that adds a symbol and goes to it instead when it is already there, and three ways to take one off: Delete, a button on the row, and the right-click menu. The list stays yours.",
      "dependencies": [
        "cn@^0.3.0",
        "@tanstack/react-virtual@^3.14.13"
      ],
      "registryDependencies": [
        "button",
        "checkbox",
        "context-menu",
        "dropdown-menu",
        "input"
      ],
      "files": [
        {
          "path": "registry/tradecn/ui/watchlist.tsx",
          "type": "registry:ui"
        },
        {
          "path": "registry/tradecn/ui/data-grid.tsx",
          "type": "registry:ui"
        },
        {
          "path": "registry/tradecn/hooks/use-flash.ts",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/hooks/use-row-store.ts",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/lib/row-store.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/tradecn/lib/format.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "watchlist",
        "grid"
      ],
      "docs": "Installs the data grid, the row store, and format alongside, and adds @tanstack/react-virtual and the up/down/flat tokens. Composes your input, button, and context-menu, plus the checkbox and dropdown-menu the grid uses. Rows are keyed by symbol: createRowStore({ getRowId: (r) => r.symbol }).",
      "meta": {
        "components": [
          {
            "title": "Watchlist",
            "description": "The grid, the add field, and the remove affordances."
          },
          {
            "title": "watchlistColumns",
            "description": "The default columns, as a list to spread into your own."
          }
        ]
      },
      "cssVars": {
        "light": {
          "down": "oklch(0.58 0.19 45)",
          "down-soft": "oklch(0.58 0.19 45 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.55 0 0 / 14%)",
          "up": "oklch(0.58 0.14 165)",
          "up-soft": "oklch(0.58 0.14 165 / 18%)"
        },
        "dark": {
          "down": "oklch(0.74 0.18 45)",
          "down-soft": "oklch(0.74 0.18 45 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.7 0 0 / 14%)",
          "up": "oklch(0.74 0.15 165)",
          "up-soft": "oklch(0.74 0.15 165 / 18%)"
        }
      }
    },
    {
      "name": "blotter",
      "type": "registry:ui",
      "title": "Blotter",
      "description": "The data grid as an order blotter: time, symbol, side, quantity, filled, price, status, and account. The status is the server's word, printed as it arrives and never worked out. An action such as Cancel is offered only for the orders whose allowedActions the server put it in, the button says how many that is, and the check is made again against the store as the click lands.",
      "dependencies": [
        "cn@^0.3.0",
        "@tanstack/react-virtual@^3.14.13"
      ],
      "registryDependencies": [
        "button",
        "checkbox",
        "context-menu",
        "dropdown-menu"
      ],
      "files": [
        {
          "path": "registry/tradecn/ui/blotter.tsx",
          "type": "registry:ui"
        },
        {
          "path": "registry/tradecn/ui/data-grid.tsx",
          "type": "registry:ui"
        },
        {
          "path": "registry/tradecn/hooks/use-flash.ts",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/hooks/use-row-store.ts",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/lib/row-store.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/tradecn/lib/format.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "blotter",
        "grid"
      ],
      "docs": "Installs the data grid, the row store, and format alongside, and adds @tanstack/react-virtual and the up/down/flat tokens. Composes your button and context-menu, plus the checkbox and dropdown-menu the grid uses. Delete cancels nothing until you name the action it runs.",
      "meta": {
        "components": [
          {
            "title": "Blotter",
            "description": "The grid, the toolbar, and the actions."
          },
          {
            "title": "blotterColumns",
            "description": "The default columns, as a list to spread into your own."
          },
          {
            "title": "allowedRows",
            "description": "The orders among some ids that allow an action, read from the store now."
          }
        ]
      },
      "cssVars": {
        "light": {
          "down": "oklch(0.58 0.19 45)",
          "down-soft": "oklch(0.58 0.19 45 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.55 0 0 / 14%)",
          "up": "oklch(0.58 0.14 165)",
          "up-soft": "oklch(0.58 0.14 165 / 18%)"
        },
        "dark": {
          "down": "oklch(0.74 0.18 45)",
          "down-soft": "oklch(0.74 0.18 45 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.7 0 0 / 14%)",
          "up": "oklch(0.74 0.15 165)",
          "up-soft": "oklch(0.74 0.15 165 / 18%)"
        }
      }
    },
    {
      "name": "workspace",
      "type": "registry:ui",
      "title": "Workspace",
      "description": "Panels that dock, tab, float, and pop out, on dockview. The dock owns where things sit; tradecn owns what each panel is: a kind, a title, and the small JSON it asked to keep. Every docked panel is a hotkey scope of its kind with the active border, and the dock decides which one is active. A layout is written out some milliseconds after the last change, carries its own persistence boundaries, and is read back through a parser that takes nothing on trust.",
      "dependencies": [
        "cn@^0.3.0",
        "dockview-react@^8.3.1"
      ],
      "registryDependencies": [
        "input"
      ],
      "files": [
        {
          "path": "registry/tradecn/ui/workspace.tsx",
          "type": "registry:ui"
        },
        {
          "path": "registry/tradecn/ui/panel.tsx",
          "type": "registry:ui"
        },
        {
          "path": "registry/tradecn/hooks/use-link-group.tsx",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/hooks/use-popout.ts",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/hooks/use-hotkeys.tsx",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/lib/workspace-layout.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/tradecn/lib/link-group.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/tradecn/lib/hotkeys.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "layout",
        "chrome"
      ],
      "docs": "Adds dockview-react, which brings dockview and dockview-core: three MIT packages from one repository and nothing under them. Installs panel and the hotkey registry alongside, composes your input, and adds the panel and link tokens. Appends one class to your stylesheet, dockview-theme-tradecn, that maps the dock onto your own tokens. A popout opens /popout.html on your origin, so serve one, or pass popoutUrl.",
      "meta": {
        "components": [
          {
            "title": "Workspace",
            "description": "The dock, with your panels by kind."
          },
          {
            "title": "useWorkspacePanel",
            "description": "Inside a panel: its id, kind, title, kept state, whether it is active, and close, float, pop out, maximize."
          }
        ]
      },
      "css": {
        "@layer components": {
          ".dockview-theme-tradecn": {
            "--dv-group-view-background-color": "var(--background)",
            "--dv-tabs-and-actions-container-background-color": "var(--muted)",
            "--dv-tabs-and-actions-container-font-size": "0.75rem",
            "--dv-tabs-and-actions-container-height": "1.75rem",
            "--dv-activegroup-visiblepanel-tab-background-color": "var(--background)",
            "--dv-activegroup-hiddenpanel-tab-background-color": "var(--muted)",
            "--dv-inactivegroup-visiblepanel-tab-background-color": "var(--background)",
            "--dv-inactivegroup-hiddenpanel-tab-background-color": "var(--muted)",
            "--dv-activegroup-visiblepanel-tab-color": "var(--foreground)",
            "--dv-activegroup-hiddenpanel-tab-color": "var(--muted-foreground)",
            "--dv-inactivegroup-visiblepanel-tab-color": "var(--muted-foreground)",
            "--dv-inactivegroup-hiddenpanel-tab-color": "var(--muted-foreground)",
            "--dv-tab-divider-color": "var(--border)",
            "--dv-tab-font-size": "inherit",
            "--dv-tab-margin": "0",
            "--dv-tab-border-radius": "0px",
            "--dv-tab-close-icon-size": "inherit",
            "--dv-tabs-container-scrollbar-color": "var(--border)",
            "--dv-separator-border": "var(--border)",
            "--dv-border-radius": "0px",
            "--dv-spacing-padding": "0px",
            "--dv-sash-color": "transparent",
            "--dv-sash-border-radius": "0px",
            "--dv-active-sash-color": "var(--ring)",
            "--dv-active-sash-transition-duration": "0.1s",
            "--dv-active-sash-transition-delay": "0.3s",
            "--dv-drag-over-background-color": "color-mix(in oklab, var(--ring) 20%, transparent)",
            "--dv-drag-over-border-color": "var(--ring)",
            "--dv-drag-over-border": "1px solid var(--ring)",
            "--dv-edge-dock-indicator-color": "var(--ring)",
            "--dv-icon-hover-background-color": "var(--accent)",
            "--dv-scrollbar-background-color": "var(--border)",
            "--dv-paneview-active-outline-color": "var(--ring)",
            "--dv-paneview-header-border-color": "var(--border)",
            "--dv-dropdown-border-radius": "var(--radius)",
            "--dv-overlay-z-index": "30",
            "--dv-floating-box-shadow": "0 8px 32px rgb(0 0 0 / 0.25), 0 2px 8px rgb(0 0 0 / 0.15)",
            "--dv-floating-border": "1px solid var(--border)",
            "--dv-floating-group-border": "1px solid var(--border)",
            "--dv-floating-group-dragging-opacity": "0.6",
            "--dv-floating-titlebar-height": "1.75rem",
            "--dv-floating-titlebar-background-color": "var(--muted)",
            "--dv-floating-titlebar-border-bottom": "1px solid var(--border)",
            "--dv-tab-group-color-grey": "var(--muted-foreground)",
            "--dv-tab-group-color-blue": "var(--chart-1)",
            "--dv-tab-group-color-red": "var(--chart-2)",
            "--dv-tab-group-color-yellow": "var(--chart-3)",
            "--dv-tab-group-color-green": "var(--chart-4)",
            "--dv-tab-group-color-pink": "var(--chart-5)",
            "--dv-tab-group-color-purple": "var(--chart-1)",
            "--dv-tab-group-color-cyan": "var(--chart-2)",
            "--dv-tab-group-color-orange": "var(--chart-3)",
            "--dv-tab-group-chip-padding": "0 0.375rem",
            "--dv-tab-group-chip-border-radius": "var(--radius)",
            "--dv-tab-group-chip-font-size": "0.6875rem",
            "--dv-tab-group-line-height": "2px",
            "--dv-tab-group-line-opacity": "0.6"
          }
        }
      },
      "cssVars": {
        "light": {
          "link-1": "oklch(0.62 0.2 25)",
          "link-2": "oklch(0.62 0.15 250)",
          "link-3": "oklch(0.65 0.15 150)",
          "link-4": "oklch(0.8 0.16 90)",
          "panel-active": "var(--color-primary)",
          "panel-drag-target": "var(--color-ring)",
          "panel-error": "var(--color-destructive)",
          "panel-sync": "oklch(0.7 0.12 220)"
        },
        "dark": {
          "link-1": "oklch(0.7 0.19 25)",
          "link-2": "oklch(0.7 0.14 250)",
          "link-3": "oklch(0.74 0.14 150)",
          "link-4": "oklch(0.85 0.15 90)",
          "panel-active": "var(--color-primary)",
          "panel-drag-target": "var(--color-ring)",
          "panel-error": "var(--color-destructive)",
          "panel-sync": "oklch(0.78 0.12 220)"
        }
      }
    },
    {
      "name": "ticket",
      "type": "registry:block",
      "title": "Ticket",
      "description": "An order ticket that types a price the way the instrument quotes it (99-16+), steps it by the tick with the arrows and the buttons, and hands a checked draft to the action you named. Buttons are the actions the server allowed and nothing else; the status is the server word, printed as it is; an acknowledgement rings the ticket once in primary. Its keys work while you type in it, and inside a dialog.",
      "dependencies": [
        "cn@^0.3.0"
      ],
      "registryDependencies": [
        "button",
        "button-group",
        "field",
        "input",
        "input-group",
        "kbd",
        "native-select"
      ],
      "files": [
        {
          "path": "registry/tradecn/blocks/ticket/ticket.tsx",
          "type": "registry:block"
        },
        {
          "path": "registry/tradecn/hooks/use-flash.ts",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/hooks/use-hotkeys.tsx",
          "type": "registry:hook"
        },
        {
          "path": "registry/tradecn/lib/format.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/tradecn/lib/hotkeys.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "ticket"
      ],
      "docs": "The registry first block: ticket.tsx goes to your components alias, not components/ui. Installs format, use-flash, and the hotkey registry alongside, composes your button, button-group, field, input, input-group, kbd, and native-select, and adds the up and down tokens. Inside a HotkeysProvider it declares ticket.send (mod+enter), ticket.flip, ticket.tick-up, and ticket.tick-down as editing bindings unless you did.",
      "meta": {
        "components": [
          {
            "title": "Ticket",
            "description": "The ticket."
          },
          {
            "title": "TICKET_BINDINGS",
            "description": "Its four editing bindings, to spread into your own list or leave to it."
          },
          {
            "title": "describeDraft",
            "description": "A draft in words: Buy 5 ZN @ 99-16+."
          },
          {
            "title": "checkDraft",
            "description": "What stops a draft from being sent, as a pure function."
          },
          {
            "title": "parseQuantity",
            "description": "Whole numbers with or without separators, or null."
          }
        ]
      },
      "cssVars": {
        "light": {
          "down": "oklch(0.58 0.19 45)",
          "down-soft": "oklch(0.58 0.19 45 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.55 0 0 / 14%)",
          "up": "oklch(0.58 0.14 165)",
          "up-soft": "oklch(0.58 0.14 165 / 18%)"
        },
        "dark": {
          "down": "oklch(0.74 0.18 45)",
          "down-soft": "oklch(0.74 0.18 45 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.7 0 0 / 14%)",
          "up": "oklch(0.74 0.15 165)",
          "up-soft": "oklch(0.74 0.15 165 / 18%)"
        }
      }
    },
    {
      "name": "tradecn-terminal",
      "type": "registry:theme",
      "title": "Terminal",
      "description": "A terminal look for the whole app: black background, near-black cards, amber primary, square corners, and a monospace stack in place of the sans. Both modes get the same palette, so it is a terminal whether or not the app sets a dark class. It keeps the colorblind-safe up and down pair.",
      "registryDependencies": [],
      "files": [],
      "categories": [
        "theme"
      ],
      "docs": "This one overwrites. It replaces your background, foreground, primary, border, radius, font-sans and the rest of shadcn's variables, in light and dark alike, and sets every tradecn token to its dark-tuned value. Review it with --diff first. Components are untouched.",
      "cssVars": {
        "theme": {
          "font-sans": "ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace"
        },
        "light": {
          "accent": "oklch(0.26 0.03 70)",
          "accent-foreground": "oklch(0.9 0.08 80)",
          "background": "oklch(0 0 0)",
          "border": "oklch(0.28 0 0)",
          "card": "oklch(0.155 0 0)",
          "card-foreground": "oklch(0.92 0.02 85)",
          "chart-1": "oklch(0.78 0.16 70)",
          "chart-2": "oklch(0.75 0.12 220)",
          "chart-3": "oklch(0.74 0.15 165)",
          "chart-4": "oklch(0.72 0.17 330)",
          "chart-5": "oklch(0.85 0.15 95)",
          "destructive": "oklch(0.65 0.22 25)",
          "down": "oklch(0.74 0.18 45)",
          "down-soft": "oklch(0.74 0.18 45 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.7 0 0 / 14%)",
          "foreground": "oklch(0.92 0.02 85)",
          "input": "oklch(0.3 0 0)",
          "link-1": "oklch(0.7 0.19 25)",
          "link-2": "oklch(0.7 0.14 250)",
          "link-3": "oklch(0.74 0.14 150)",
          "link-4": "oklch(0.85 0.15 90)",
          "muted": "oklch(0.2 0 0)",
          "muted-foreground": "oklch(0.68 0.01 85)",
          "panel-active": "var(--color-primary)",
          "panel-drag-target": "var(--color-ring)",
          "panel-error": "var(--color-destructive)",
          "panel-sync": "oklch(0.78 0.12 220)",
          "popover": "oklch(0.175 0 0)",
          "popover-foreground": "oklch(0.92 0.02 85)",
          "primary": "oklch(0.78 0.16 70)",
          "primary-foreground": "oklch(0.16 0.02 70)",
          "radius": "0rem",
          "ring": "oklch(0.7 0.15 70)",
          "secondary": "oklch(0.22 0 0)",
          "secondary-foreground": "oklch(0.92 0.02 85)",
          "sidebar": "oklch(0.1 0 0)",
          "sidebar-accent": "oklch(0.26 0.03 70)",
          "sidebar-accent-foreground": "oklch(0.9 0.08 80)",
          "sidebar-border": "oklch(0.28 0 0)",
          "sidebar-foreground": "oklch(0.92 0.02 85)",
          "sidebar-primary": "oklch(0.78 0.16 70)",
          "sidebar-primary-foreground": "oklch(0.16 0.02 70)",
          "sidebar-ring": "oklch(0.7 0.15 70)",
          "stale": "oklch(0.8 0.15 80)",
          "stale-soft": "oklch(0.8 0.15 80 / 16%)",
          "up": "oklch(0.74 0.15 165)",
          "up-soft": "oklch(0.74 0.15 165 / 18%)"
        },
        "dark": {
          "accent": "oklch(0.26 0.03 70)",
          "accent-foreground": "oklch(0.9 0.08 80)",
          "background": "oklch(0 0 0)",
          "border": "oklch(0.28 0 0)",
          "card": "oklch(0.155 0 0)",
          "card-foreground": "oklch(0.92 0.02 85)",
          "chart-1": "oklch(0.78 0.16 70)",
          "chart-2": "oklch(0.75 0.12 220)",
          "chart-3": "oklch(0.74 0.15 165)",
          "chart-4": "oklch(0.72 0.17 330)",
          "chart-5": "oklch(0.85 0.15 95)",
          "destructive": "oklch(0.65 0.22 25)",
          "down": "oklch(0.74 0.18 45)",
          "down-soft": "oklch(0.74 0.18 45 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.7 0 0 / 14%)",
          "foreground": "oklch(0.92 0.02 85)",
          "input": "oklch(0.3 0 0)",
          "link-1": "oklch(0.7 0.19 25)",
          "link-2": "oklch(0.7 0.14 250)",
          "link-3": "oklch(0.74 0.14 150)",
          "link-4": "oklch(0.85 0.15 90)",
          "muted": "oklch(0.2 0 0)",
          "muted-foreground": "oklch(0.68 0.01 85)",
          "panel-active": "var(--color-primary)",
          "panel-drag-target": "var(--color-ring)",
          "panel-error": "var(--color-destructive)",
          "panel-sync": "oklch(0.78 0.12 220)",
          "popover": "oklch(0.175 0 0)",
          "popover-foreground": "oklch(0.92 0.02 85)",
          "primary": "oklch(0.78 0.16 70)",
          "primary-foreground": "oklch(0.16 0.02 70)",
          "ring": "oklch(0.7 0.15 70)",
          "secondary": "oklch(0.22 0 0)",
          "secondary-foreground": "oklch(0.92 0.02 85)",
          "sidebar": "oklch(0.1 0 0)",
          "sidebar-accent": "oklch(0.26 0.03 70)",
          "sidebar-accent-foreground": "oklch(0.9 0.08 80)",
          "sidebar-border": "oklch(0.28 0 0)",
          "sidebar-foreground": "oklch(0.92 0.02 85)",
          "sidebar-primary": "oklch(0.78 0.16 70)",
          "sidebar-primary-foreground": "oklch(0.16 0.02 70)",
          "sidebar-ring": "oklch(0.7 0.15 70)",
          "stale": "oklch(0.8 0.15 80)",
          "stale-soft": "oklch(0.8 0.15 80 / 16%)",
          "up": "oklch(0.74 0.15 165)",
          "up-soft": "oklch(0.74 0.15 165 / 18%)"
        }
      }
    },
    {
      "name": "tradecn-terminal-classic",
      "type": "registry:theme",
      "title": "Terminal Classic",
      "description": "The terminal theme with green for up and red for down. Everything else is tradecn-terminal: black background, amber primary, square corners, a monospace stack, the same palette in both modes. Green and red are the pair the most common kinds of color blindness confuse, so direction leans harder on the sign and the words.",
      "registryDependencies": [],
      "files": [],
      "categories": [
        "theme"
      ],
      "docs": "This one overwrites, the same as tradecn-terminal: it replaces shadcn's variables and sets every tradecn token, in light and dark alike. Review it with --diff first. It differs from tradecn-terminal in four tokens only: up, down, up-soft, and down-soft. Install one or the other, not both.",
      "cssVars": {
        "theme": {
          "font-sans": "ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace"
        },
        "light": {
          "accent": "oklch(0.26 0.03 70)",
          "accent-foreground": "oklch(0.9 0.08 80)",
          "background": "oklch(0 0 0)",
          "border": "oklch(0.28 0 0)",
          "card": "oklch(0.155 0 0)",
          "card-foreground": "oklch(0.92 0.02 85)",
          "chart-1": "oklch(0.78 0.16 70)",
          "chart-2": "oklch(0.75 0.12 220)",
          "chart-3": "oklch(0.74 0.15 165)",
          "chart-4": "oklch(0.72 0.17 330)",
          "chart-5": "oklch(0.85 0.15 95)",
          "destructive": "oklch(0.65 0.22 25)",
          "down": "oklch(0.66 0.22 25)",
          "down-soft": "oklch(0.66 0.22 25 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.7 0 0 / 14%)",
          "foreground": "oklch(0.92 0.02 85)",
          "input": "oklch(0.3 0 0)",
          "link-1": "oklch(0.7 0.19 25)",
          "link-2": "oklch(0.7 0.14 250)",
          "link-3": "oklch(0.74 0.14 150)",
          "link-4": "oklch(0.85 0.15 90)",
          "muted": "oklch(0.2 0 0)",
          "muted-foreground": "oklch(0.68 0.01 85)",
          "panel-active": "var(--color-primary)",
          "panel-drag-target": "var(--color-ring)",
          "panel-error": "var(--color-destructive)",
          "panel-sync": "oklch(0.78 0.12 220)",
          "popover": "oklch(0.175 0 0)",
          "popover-foreground": "oklch(0.92 0.02 85)",
          "primary": "oklch(0.78 0.16 70)",
          "primary-foreground": "oklch(0.16 0.02 70)",
          "radius": "0rem",
          "ring": "oklch(0.7 0.15 70)",
          "secondary": "oklch(0.22 0 0)",
          "secondary-foreground": "oklch(0.92 0.02 85)",
          "sidebar": "oklch(0.1 0 0)",
          "sidebar-accent": "oklch(0.26 0.03 70)",
          "sidebar-accent-foreground": "oklch(0.9 0.08 80)",
          "sidebar-border": "oklch(0.28 0 0)",
          "sidebar-foreground": "oklch(0.92 0.02 85)",
          "sidebar-primary": "oklch(0.78 0.16 70)",
          "sidebar-primary-foreground": "oklch(0.16 0.02 70)",
          "sidebar-ring": "oklch(0.7 0.15 70)",
          "stale": "oklch(0.8 0.15 80)",
          "stale-soft": "oklch(0.8 0.15 80 / 16%)",
          "up": "oklch(0.76 0.2 145)",
          "up-soft": "oklch(0.76 0.2 145 / 18%)"
        },
        "dark": {
          "accent": "oklch(0.26 0.03 70)",
          "accent-foreground": "oklch(0.9 0.08 80)",
          "background": "oklch(0 0 0)",
          "border": "oklch(0.28 0 0)",
          "card": "oklch(0.155 0 0)",
          "card-foreground": "oklch(0.92 0.02 85)",
          "chart-1": "oklch(0.78 0.16 70)",
          "chart-2": "oklch(0.75 0.12 220)",
          "chart-3": "oklch(0.74 0.15 165)",
          "chart-4": "oklch(0.72 0.17 330)",
          "chart-5": "oklch(0.85 0.15 95)",
          "destructive": "oklch(0.65 0.22 25)",
          "down": "oklch(0.66 0.22 25)",
          "down-soft": "oklch(0.66 0.22 25 / 18%)",
          "flat": "var(--color-muted-foreground)",
          "flat-soft": "oklch(0.7 0 0 / 14%)",
          "foreground": "oklch(0.92 0.02 85)",
          "input": "oklch(0.3 0 0)",
          "link-1": "oklch(0.7 0.19 25)",
          "link-2": "oklch(0.7 0.14 250)",
          "link-3": "oklch(0.74 0.14 150)",
          "link-4": "oklch(0.85 0.15 90)",
          "muted": "oklch(0.2 0 0)",
          "muted-foreground": "oklch(0.68 0.01 85)",
          "panel-active": "var(--color-primary)",
          "panel-drag-target": "var(--color-ring)",
          "panel-error": "var(--color-destructive)",
          "panel-sync": "oklch(0.78 0.12 220)",
          "popover": "oklch(0.175 0 0)",
          "popover-foreground": "oklch(0.92 0.02 85)",
          "primary": "oklch(0.78 0.16 70)",
          "primary-foreground": "oklch(0.16 0.02 70)",
          "ring": "oklch(0.7 0.15 70)",
          "secondary": "oklch(0.22 0 0)",
          "secondary-foreground": "oklch(0.92 0.02 85)",
          "sidebar": "oklch(0.1 0 0)",
          "sidebar-accent": "oklch(0.26 0.03 70)",
          "sidebar-accent-foreground": "oklch(0.9 0.08 80)",
          "sidebar-border": "oklch(0.28 0 0)",
          "sidebar-foreground": "oklch(0.92 0.02 85)",
          "sidebar-primary": "oklch(0.78 0.16 70)",
          "sidebar-primary-foreground": "oklch(0.16 0.02 70)",
          "sidebar-ring": "oklch(0.7 0.15 70)",
          "stale": "oklch(0.8 0.15 80)",
          "stale-soft": "oklch(0.8 0.15 80 / 16%)",
          "up": "oklch(0.76 0.2 145)",
          "up-soft": "oklch(0.76 0.2 145 / 18%)"
        }
      }
    }
  ]
}
