{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "table",
  "title": "Table",
  "description": "A table component.",
  "registryDependencies": [
    "@cubby-ui/scroll-area",
    "@cubby-ui/elevated"
  ],
  "files": [
    {
      "path": "registry/default/table/table.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\n\nimport { cn } from \"@/lib/utils\";\nimport {\n  elevatedSurface,\n  type SurfaceLevel,\n} from \"@/registry/default/lib/elevated\";\nimport {\n  ScrollArea,\n  type ScrollAreaProps,\n} from \"@/registry/default/scroll-area/scroll-area\";\n\nexport interface TableProps\n  extends\n    React.ComponentProps<\"table\">,\n    Pick<\n      ScrollAreaProps,\n      | \"nativeScroll\"\n      | \"fadeEdges\"\n      | \"scrollbarGutter\"\n      | \"persistScrollbar\"\n      | \"hideScrollbar\"\n    > {\n  bordered?: boolean;\n  striped?: boolean;\n  hoverable?: boolean;\n  rowDividers?: boolean;\n  /** Surface elevation level (1-8). Defaults to 3. */\n  level?: SurfaceLevel;\n  /** Shadow weight (1-8). Defaults to 1 — flat outlined card, just rim. */\n  shadowLevel?: SurfaceLevel;\n}\n\nfunction Table({\n  className,\n  bordered = false,\n  striped = false,\n  hoverable = true,\n  rowDividers = true,\n  nativeScroll = false,\n  fadeEdges = false,\n  scrollbarGutter = false,\n  persistScrollbar,\n  hideScrollbar,\n  level = 3,\n  shadowLevel = 1,\n  children,\n  ...props\n}: TableProps) {\n  return (\n    <div\n      data-slot=\"table-container\"\n      data-bordered={bordered ? \"\" : undefined}\n      data-striped={striped ? \"\" : undefined}\n      data-hoverable={hoverable ? \"\" : undefined}\n      data-row-dividers={rowDividers ? \"\" : undefined}\n      data-level={level}\n      className={cn(\n        \"group/table relative flex w-full flex-col overflow-hidden rounded-2xl p-1 pt-0 md:max-w-2xl\",\n        // Same pattern as Card inset outer — gray frame with elevation shadow + rim.\n        // Inner body cells drop to `bg-surface-3 dark:bg-surface-1` (see TableBody)\n        // to create the mode-asymmetric \"card-on-tray (light) / well (dark)\" look.\n        // pt-0 because TableHead's py-2 already provides the header's top padding —\n        // adding outer pt would stack and create a too-thick top strip.\n        // has-[tfoot]:pb-0 mirrors that logic: when a footer is present its own\n        // py-2 carries the bottom padding. Without a footer, the outer keeps\n        // pb-1 to give the body's last row breathing room before the frame edge.\n        \"has-[tfoot]:pb-0\",\n        // elevatedSurface (rim on ::after) because the sticky TableHeader is\n        // an opaque child near the top edge — solidSurface's combined shadow\n        // would let the header bg cover the rim line at the top in dark mode.\n        elevatedSurface(level, shadowLevel),\n        \"bg-muted\",\n        className,\n      )}\n    >\n      <ScrollArea\n        nativeScroll={nativeScroll}\n        fadeEdges={fadeEdges}\n        scrollbarGutter={scrollbarGutter}\n        persistScrollbar={persistScrollbar}\n        hideScrollbar={hideScrollbar}\n        className=\"min-h-0 flex-1 rounded-lg\"\n      >\n        <table\n          data-slot=\"table\"\n          className={cn(\n            \"w-full caption-bottom text-sm\",\n            bordered && \"border-separate border-spacing-0\",\n          )}\n          {...props}\n        >\n          {children}\n        </table>\n      </ScrollArea>\n    </div>\n  );\n}\n\nexport type TableHeaderProps = useRender.ComponentProps<\"thead\">;\n\nfunction TableHeader({ className, render, ...props }: TableHeaderProps) {\n  const defaultProps = {\n    \"data-slot\": \"table-header\",\n    className: cn(\n      \"[&_tr]:border-0\",\n      // th cells use bg-muted — same color as the outer Table frame, so the\n      // header strip blends into the frame visually. bg-muted also gives the\n      // sticky header an opaque bg so scrolling body content doesn't bleed\n      // through it.\n      \"[&_tr_th]:bg-muted\",\n      // z-1 keeps the header above scrolling body rows but below the table\n      // container's ::after rim (z-2) so the rim stays visible in dark mode.\n      \"sticky top-0 z-1\",\n      className,\n    ),\n  };\n\n  return useRender({\n    defaultTagName: \"thead\",\n    render,\n    props: mergeProps<\"thead\">(defaultProps, props),\n  });\n}\n\nexport type TableBodyProps = useRender.ComponentProps<\"tbody\">;\n\nfunction TableBody({ className, render, ...props }: TableBodyProps) {\n  const defaultProps = {\n    \"data-slot\": \"table-body\",\n    className: cn(\n      // Body cells form the \"inner card\" — bg-surface-3 (pure white) in light,\n      // bg-surface-1 (page color) in dark. Same mode-asymmetric pattern as Command.\n      \"[&_tr_td]:bg-surface-3 dark:[&_tr_td]:bg-surface-1\",\n      \"[&_tr:first-child_td:first-child]:rounded-tl-lg [&_tr:first-child_td:last-child]:rounded-tr-lg\",\n      \"[&_tr:last-child_td:first-child]:rounded-bl-lg [&_tr:last-child_td:last-child]:rounded-br-lg\",\n      \"group-data-[row-dividers]/table:[&_tr:not(:last-child)]:border-b group-data-[row-dividers]/table:[&_tr]:border-border/60\",\n      \"group-data-bordered/table:[&_tr:first-child_td]:border-t group-data-bordered/table:[&_tr:first-child_td]:border-border\",\n\n      \"group-data-hoverable/table:[&_tr:hover_td]:bg-surface-hover\",\n      \"group-data-striped/table:[&_tr:nth-child(even)_td]:bg-muted/50\",\n      className,\n    ),\n  };\n\n  return useRender({\n    defaultTagName: \"tbody\",\n    render,\n    props: mergeProps<\"tbody\">(defaultProps, props),\n  });\n}\n\nexport type TableFooterProps = useRender.ComponentProps<\"tfoot\">;\n\nfunction TableFooter({ className, render, ...props }: TableFooterProps) {\n  const defaultProps = {\n    \"data-slot\": \"table-footer\",\n    className: cn(\n      \"[&_tr]:border-0\",\n      \"[&_tr_td]:bg-muted\",\n      \"[&_tr_td:first-child]:rounded-l-lg [&_tr_td:last-child]:rounded-r-lg\",\n      \"[&_tr_td]:py-2\",\n      \"font-medium\",\n      className,\n    ),\n  };\n\n  return useRender({\n    defaultTagName: \"tfoot\",\n    render,\n    props: mergeProps<\"tfoot\">(defaultProps, props),\n  });\n}\n\nexport interface TableRowProps extends useRender.ComponentProps<\"tr\"> {\n  selected?: boolean;\n}\n\nfunction TableRow({ className, render, selected, ...props }: TableRowProps) {\n  const defaultProps = {\n    \"data-slot\": \"table-row\",\n    \"data-state\": selected ? \"selected\" : undefined,\n    className: cn(\n      \"transition-colors duration-100 hover:transition-none\",\n      className,\n    ),\n  };\n\n  return useRender({\n    defaultTagName: \"tr\",\n    render,\n    props: mergeProps<\"tr\">(defaultProps, props),\n  });\n}\n\nexport type TableHeadProps = useRender.ComponentProps<\"th\">;\n\nfunction TableHead({ className, render, ...props }: TableHeadProps) {\n  const defaultProps = {\n    \"data-slot\": \"table-head\",\n    className: cn(\n      \"text-muted-foreground relative px-3 py-2 text-left align-middle text-sm font-medium whitespace-nowrap\",\n      \"[&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]\",\n      // Short \"tick\" separator between header cells via ::after. Hidden on the\n      // last cell so the row ends cleanly. Uses bg-border (translucent) so it\n      // reads as a faint divider on the bg-muted header strip.\n      \"after:absolute after:right-0 after:top-1/2 after:h-4 after:w-px after:-translate-y-1/2 after:bg-border after:content-['']\",\n      \"last:after:hidden\",\n      \"group-data-[bordered]/table:border-r group-data-[bordered]/table:border-border group-data-[bordered]/table:last:border-r-0\",\n      className,\n    ),\n  };\n\n  return useRender({\n    defaultTagName: \"th\",\n    render,\n    props: mergeProps<\"th\">(defaultProps, props),\n  });\n}\n\nexport type TableCellProps = useRender.ComponentProps<\"td\">;\n\nfunction TableCell({ className, render, ...props }: TableCellProps) {\n  const defaultProps = {\n    \"data-slot\": \"table-cell\",\n    className: cn(\n      \"px-3 py-2.5 align-middle whitespace-nowrap\",\n      \"[&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]\",\n      \"group-data-bordered/table:border-b group-data-bordered/table:border-r group-data-bordered/table:first:border-l group-data-bordered/table:border-border\",\n      // ! to override the dark-mode TableBody base bg-surface-1 which would\n      // otherwise win on specificity (.dark .body tr td vs. [data-state=selected] td).\n      \"[[data-state=selected]_&]:bg-surface-selected dark:[[data-state=selected]_&]:bg-surface-selected\",\n      className,\n    ),\n  };\n\n  return useRender({\n    defaultTagName: \"td\",\n    render,\n    props: mergeProps<\"td\">(defaultProps, props),\n  });\n}\n\nexport type TableCaptionProps = useRender.ComponentProps<\"caption\">;\n\nfunction TableCaption({ className, render, ...props }: TableCaptionProps) {\n  const defaultProps = {\n    \"data-slot\": \"table-caption\",\n    className: cn(\"text-muted-foreground mt-4 text-xs\", className),\n  };\n\n  return useRender({\n    defaultTagName: \"caption\",\n    render,\n    props: mergeProps<\"caption\">(defaultProps, props),\n  });\n}\n\nexport {\n  Table,\n  TableHeader,\n  TableBody,\n  TableFooter,\n  TableHead,\n  TableRow,\n  TableCell,\n  TableCaption,\n};\n",
      "type": "registry:ui",
      "target": "components/ui/cubby-ui/table.tsx"
    }
  ],
  "type": "registry:ui"
}