{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "table",
  "type": "registry:ui",
  "registryDependencies": [],
  "dependencies": ["motion", "lucide-react"],
  "devDependencies": [],
  "files": [
    {
      "path": "table.tsx",
      "content": "\"use client\";\n\nimport { ArrowUpDown, ChevronLeft, ChevronRight } from \"lucide-react\";\nimport {\n  AnimatePresence,\n  LayoutGroup,\n  motion,\n  useReducedMotion,\n} from \"motion/react\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst componentThemeClassName =\n  \"[--ic-background:#ffffff] [--ic-foreground:#111111] [--ic-primary:#111111] [--ic-secondary:#646b75] [--ic-surface-border:#e9edf2] [--ic-border:#e3e7ec] [--ic-card:#ffffff] [--ic-card-foreground:#111111] [--ic-muted:#f5f7fa] [--ic-muted-foreground:#6d7480] [--ic-accent:#f3f5f8] [--color-accent:var(--ic-accent)] [--color-accent-foreground:var(--ic-accent-foreground)] [--ic-accent-foreground:#111111] [--ic-input:#e3e7ec] [--ic-ring:rgba(17,17,17,0.16)] [--ic-destructive:#dc2626] [--ic-paper:#fcfcfd] [--ic-popover-foreground:#111111] [--ic-brand:#0ea5e9] [--ic-brand-soft:#bae6fd] [--ic-shadow-soft:0_18px_38px_-24px_rgba(15,23,42,0.35)] [--ic-chart-1:oklch(0.52_0.19_254)] [--ic-chart-2:oklch(0.74_0.11_232)] [--ic-chart-3:oklch(0.42_0.16_262)] [--ic-chart-4:oklch(0.84_0.07_228)] [--ic-chart-5:oklch(0.62_0.14_240)] [--color-background:var(--ic-background)] [--color-foreground:var(--ic-foreground)] [--color-primary:var(--ic-primary)] [--color-secondary:var(--ic-secondary)] [--color-border:var(--ic-border)] [--color-card:var(--ic-card)] [--color-card-foreground:var(--ic-card-foreground)] [--color-muted:var(--ic-muted)] [--color-muted-foreground:var(--ic-muted-foreground)] [--color-accent:var(--ic-accent)] [--color-accent-foreground:var(--ic-accent-foreground)] [--color-input:var(--ic-input)] [--color-ring:var(--ic-ring)] [--color-destructive:var(--ic-destructive)] [--color-paper:var(--ic-paper)] [--color-popover-foreground:var(--ic-popover-foreground)] [--color-brand:var(--ic-brand)] [--color-brand-soft:var(--ic-brand-soft)] [--color-chart-1:var(--ic-chart-1)] [--color-chart-2:var(--ic-chart-2)] [--color-chart-3:var(--ic-chart-3)] [--color-chart-4:var(--ic-chart-4)] [--color-chart-5:var(--ic-chart-5)] dark:[--ic-background:#111111] dark:[--ic-foreground:#f6f3ec] dark:[--ic-primary:#f6f3ec] dark:[--ic-secondary:#cbc6bb] dark:[--ic-surface-border:#2a2a25] dark:[--ic-border:#2b2a25] dark:[--ic-card:#111111] dark:[--ic-card-foreground:#f6f3ec] dark:[--ic-muted:#171716] dark:[--ic-muted-foreground:#9a958a] dark:[--ic-accent:#1a1a18] [--color-accent:var(--ic-accent)] [--color-accent-foreground:var(--ic-accent-foreground)] dark:[--ic-accent-foreground:#f6f3ec] dark:[--ic-input:#2b2a25] dark:[--ic-ring:rgba(246,243,236,0.18)] dark:[--ic-destructive:#f87171] dark:[--ic-paper:#171716] dark:[--ic-popover-foreground:#f6f3ec] dark:[--ic-brand:#38bdf8] dark:[--ic-brand-soft:#0c4a6e] dark:[--ic-shadow-soft:0_20px_44px_-28px_rgba(0,0,0,0.6)] dark:[--ic-chart-1:oklch(0.68_0.17_250)] dark:[--ic-chart-2:oklch(0.82_0.09_225)] dark:[--ic-chart-3:oklch(0.58_0.15_260)] dark:[--ic-chart-4:oklch(0.75_0.12_235)] dark:[--ic-chart-5:oklch(0.88_0.06_220)]\";\n\nexport const TABLE_DEFAULT_COLUMNS =\n  \"minmax(0,1.4fr) minmax(0,1fr) minmax(0,1fr) minmax(0,1fr)\";\n\nexport type TableAlign = \"left\" | \"center\" | \"right\";\nexport type TableRowVariant = \"body\" | \"header\";\nexport type TableSize = \"default\" | \"compact\";\nexport type TableSortDirection = \"asc\" | \"desc\";\nexport type TableSortState = TableSortDirection | \"none\";\n\ntype TableContextValue = {\n  columnCount: number;\n  columns: string;\n  size: TableSize;\n  stickyHeader: boolean;\n};\n\nconst TableContext = React.createContext<TableContextValue | null>(null);\n\nconst selectCheckboxClassName =\n  \"size-4 shrink-0 rounded border border-border accent-foreground\";\n\nfunction getColumnTokens(columns: string) {\n  const tokens: string[] = [];\n  let token = \"\";\n  let depth = 0;\n\n  for (const char of columns) {\n    if (char === \"(\") {\n      depth += 1;\n    }\n\n    if (char === \")\") {\n      depth = Math.max(0, depth - 1);\n    }\n\n    if (char === \" \" && depth === 0) {\n      const nextToken = token.trim();\n\n      if (nextToken) {\n        tokens.push(nextToken);\n      }\n\n      token = \"\";\n      continue;\n    }\n\n    token += char;\n  }\n\n  const lastToken = token.trim();\n\n  if (lastToken) {\n    tokens.push(lastToken);\n  }\n\n  return tokens;\n}\n\nfunction useTableContext(componentName: string) {\n  const context = React.useContext(TableContext);\n\n  if (!context) {\n    throw new Error(`${componentName} must be used within Table.`);\n  }\n\n  return context;\n}\n\nfunction alignClassName(align: TableAlign) {\n  if (align === \"right\") {\n    return \"text-right\";\n  }\n\n  if (align === \"center\") {\n    return \"text-center\";\n  }\n\n  return \"text-left\";\n}\n\nfunction sortButtonAlignClassName(align: TableAlign) {\n  if (align === \"right\") {\n    return \"justify-end text-right\";\n  }\n\n  if (align === \"center\") {\n    return \"justify-center text-center\";\n  }\n\n  return \"\";\n}\n\nfunction getAriaSortValue(\n  sortDirection?: TableSortState\n): \"ascending\" | \"descending\" | \"none\" | undefined {\n  if (sortDirection === \"asc\") {\n    return \"ascending\";\n  }\n\n  if (sortDirection === \"desc\") {\n    return \"descending\";\n  }\n\n  if (sortDirection === \"none\") {\n    return \"none\";\n  }\n\n  return undefined;\n}\n\nfunction countRowCells(children: React.ReactNode) {\n  return React.Children.toArray(children).filter(React.isValidElement).length;\n}\n\nfunction useRowColumnCountWarning(\n  componentName: string,\n  children: React.ReactNode,\n  columnCount: number\n) {\n  const cellCount = countRowCells(children);\n\n  React.useEffect(() => {\n    if (process.env.NODE_ENV === \"production\") {\n      return;\n    }\n\n    if (cellCount > 0 && cellCount !== columnCount) {\n      console.warn(\n        `[Iconiq Table] ${componentName} rendered ${cellCount} cells but Table columns defines ${columnCount}. Update the \\`columns\\` prop or cell count to keep rows aligned.`\n      );\n    }\n  }, [cellCount, columnCount, componentName]);\n}\n\nfunction getSortButtonLabel(\n  children: React.ReactNode,\n  active: boolean,\n  direction: TableSortDirection\n) {\n  if (typeof children !== \"string\" || !children.trim()) {\n    return \"Sort column\";\n  }\n\n  if (!active) {\n    return `Sort by ${children}`;\n  }\n\n  return `Sort by ${children}, ${direction === \"desc\" ? \"descending\" : \"ascending\"}`;\n}\n\nfunction useTableMotionEnabled() {\n  const reduceMotion = useReducedMotion();\n  const [mounted, setMounted] = React.useState(false);\n\n  React.useEffect(() => {\n    setMounted(true);\n  }, []);\n\n  return mounted && reduceMotion !== true;\n}\n\nexport interface TableProps\n  extends React.TableHTMLAttributes<HTMLTableElement> {\n  columns?: string;\n  size?: TableSize;\n  stickyHeader?: boolean;\n}\n\nconst Table = React.forwardRef<HTMLTableElement, TableProps>(\n  (\n    {\n      children,\n      className,\n      columns = TABLE_DEFAULT_COLUMNS,\n      size = \"default\",\n      stickyHeader = false,\n      ...props\n    },\n    ref\n  ) => {\n    const columnCount = React.useMemo(\n      () => Math.max(1, getColumnTokens(columns).length),\n      [columns]\n    );\n    const contextValue = React.useMemo(\n      () => ({ columns, columnCount, size, stickyHeader }),\n      [columnCount, columns, size, stickyHeader]\n    );\n\n    return (\n      <TableContext.Provider value={contextValue}>\n        <div\n          className={cn(componentThemeClassName, \"w-full overflow-x-auto\")}\n          data-slot=\"table-wrapper\"\n        >\n          <table\n            className={cn(\n              \"w-full caption-bottom border-separate border-spacing-0\",\n              className\n            )}\n            data-slot=\"table\"\n            ref={ref}\n            {...props}\n          >\n            {children}\n          </table>\n        </div>\n      </TableContext.Provider>\n    );\n  }\n);\nTable.displayName = \"Table\";\n\nexport interface TableToolbarProps\n  extends React.HTMLAttributes<HTMLDivElement> {\n  tableId?: string;\n}\n\nconst TableToolbar = React.forwardRef<HTMLDivElement, TableToolbarProps>(\n  ({ className, tableId, ...props }, ref) => (\n    <div\n      {...(tableId\n        ? { \"aria-controls\": tableId, role: \"toolbar\" as const }\n        : {})}\n      className={cn(\"mb-6 flex items-center justify-between gap-3\", className)}\n      data-slot=\"table-toolbar\"\n      ref={ref}\n      {...props}\n    />\n  )\n);\nTableToolbar.displayName = \"TableToolbar\";\n\nexport interface TableHeaderProps\n  extends React.HTMLAttributes<HTMLTableSectionElement> {\n  sticky?: boolean;\n}\n\nconst TableHeader = React.forwardRef<HTMLTableSectionElement, TableHeaderProps>(\n  ({ className, sticky, ...props }, ref) => {\n    const { stickyHeader } = useTableContext(\"TableHeader\");\n    const isSticky = sticky ?? stickyHeader;\n\n    return (\n      <thead\n        className={cn(\n          isSticky &&\n            \"sticky top-0 z-10 bg-background shadow-[0_1px_0_0_var(--ic-border)]\",\n          className\n        )}\n        data-slot=\"table-header\"\n        data-sticky={isSticky ? \"true\" : \"false\"}\n        ref={ref}\n        {...props}\n      />\n    );\n  }\n);\nTableHeader.displayName = \"TableHeader\";\n\nexport interface TableBodyProps\n  extends React.HTMLAttributes<HTMLTableSectionElement> {}\n\nconst TableBody = React.forwardRef<HTMLTableSectionElement, TableBodyProps>(\n  ({ children, className, ...props }, ref) => (\n    <tbody\n      className={cn(\"relative\", className)}\n      data-slot=\"table-body\"\n      ref={ref}\n      {...props}\n    >\n      <LayoutGroup>\n        <AnimatePresence initial={false}>{children}</AnimatePresence>\n      </LayoutGroup>\n    </tbody>\n  )\n);\nTableBody.displayName = \"TableBody\";\n\nexport interface TableFooterProps\n  extends React.HTMLAttributes<HTMLTableSectionElement> {}\n\nconst TableFooter = React.forwardRef<HTMLTableSectionElement, TableFooterProps>(\n  ({ className, ...props }, ref) => (\n    <tfoot\n      className={cn(\n        \"border-border border-t text-muted-foreground text-sm\",\n        className\n      )}\n      data-slot=\"table-footer\"\n      ref={ref}\n      {...props}\n    />\n  )\n);\nTableFooter.displayName = \"TableFooter\";\n\nexport interface TableRowProps\n  extends Omit<React.ComponentPropsWithoutRef<typeof motion.tr>, \"children\"> {\n  children?: React.ReactNode;\n  hoverable?: boolean;\n  index?: number;\n  selected?: boolean;\n  variant?: TableRowVariant;\n}\n\nfunction getTableRowClassName({\n  className,\n  isCompact,\n  isHeader,\n  isHoverable,\n  selected,\n}: {\n  className?: string;\n  isCompact: boolean;\n  isHeader: boolean;\n  isHoverable: boolean;\n  selected: boolean;\n}) {\n  return cn(\n    \"grid items-center\",\n    isHeader\n      ? \"border-border border-y text-muted-foreground text-xs uppercase tracking-wider\"\n      : cn(\n          \"border-border border-b\",\n          isCompact ? \"text-xs\" : \"text-sm\",\n          selected && \"bg-accent\"\n        ),\n    isHoverable ? \"rounded-lg\" : \"\",\n    className\n  );\n}\n\nfunction getTableRowMotionProps({\n  animate,\n  exit,\n  index,\n  initial,\n  isHeader,\n  layout,\n  motionEnabled,\n  transition,\n}: {\n  animate: TableRowProps[\"animate\"];\n  exit: TableRowProps[\"exit\"];\n  index: number;\n  initial: TableRowProps[\"initial\"];\n  isHeader: boolean;\n  layout: TableRowProps[\"layout\"];\n  motionEnabled: boolean;\n  transition: TableRowProps[\"transition\"];\n}) {\n  const bodyMotionEnabled = motionEnabled && !isHeader;\n\n  return {\n    animate: animate ?? (bodyMotionEnabled ? { opacity: 1, y: 0 } : undefined),\n    exit:\n      exit ??\n      (bodyMotionEnabled\n        ? { opacity: 0, x: -16, transition: { duration: 0.2 } }\n        : undefined),\n    initial: initial ?? (bodyMotionEnabled ? { opacity: 0, y: 8 } : false),\n    layout: motionEnabled ? (layout ?? !isHeader) : false,\n    transition:\n      transition ??\n      (bodyMotionEnabled\n        ? {\n            delay: index * 0.02,\n            type: \"spring\" as const,\n            stiffness: 380,\n            damping: 32,\n            mass: 0.6,\n          }\n        : undefined),\n  };\n}\n\nconst TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>(\n  (\n    {\n      animate,\n      children,\n      className,\n      exit,\n      hoverable,\n      index = 0,\n      initial,\n      layout,\n      selected = false,\n      style,\n      transition,\n      variant = \"body\",\n      whileHover,\n      ...props\n    },\n    ref\n  ) => {\n    const { columnCount, columns, size } = useTableContext(\"TableRow\");\n    const motionEnabled = useTableMotionEnabled();\n    const isHeader = variant === \"header\";\n    const isHoverable = hoverable ?? false;\n    const isCompact = size === \"compact\";\n    const rowMotion = getTableRowMotionProps({\n      animate,\n      exit,\n      index,\n      initial,\n      isHeader,\n      layout,\n      motionEnabled,\n      transition,\n    });\n\n    useRowColumnCountWarning(\"TableRow\", children, columnCount);\n\n    return (\n      <motion.tr\n        {...rowMotion}\n        className={getTableRowClassName({\n          className,\n          isCompact,\n          isHeader,\n          isHoverable,\n          selected,\n        })}\n        data-hoverable={isHoverable ? \"true\" : \"false\"}\n        data-selected={selected ? \"true\" : \"false\"}\n        data-slot=\"table-row\"\n        data-state={selected ? \"selected\" : undefined}\n        data-variant={variant}\n        ref={ref}\n        style={{ ...style, gridTemplateColumns: columns }}\n        whileHover={\n          isHoverable\n            ? (whileHover ?? { backgroundColor: \"var(--ic-muted)\" })\n            : undefined\n        }\n        {...props}\n      >\n        {children}\n      </motion.tr>\n    );\n  }\n);\nTableRow.displayName = \"TableRow\";\n\nexport interface TableHeadProps\n  extends React.ThHTMLAttributes<HTMLTableCellElement> {\n  align?: TableAlign;\n  sortDirection?: TableSortState;\n}\n\nconst TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(\n  (\n    {\n      align = \"left\",\n      \"aria-sort\": ariaSort,\n      children,\n      className,\n      scope = \"col\",\n      sortDirection,\n      ...props\n    },\n    ref\n  ) => {\n    const { size } = useTableContext(\"TableHead\");\n    const isCompact = size === \"compact\";\n\n    return (\n      <th\n        aria-sort={ariaSort ?? getAriaSortValue(sortDirection)}\n        className={cn(\n          \"min-w-0 px-2 font-normal\",\n          isCompact ? \"py-2\" : \"py-3\",\n          alignClassName(align),\n          className\n        )}\n        data-align={align}\n        data-slot=\"table-head\"\n        ref={ref}\n        scope={scope}\n        {...props}\n      >\n        {children}\n      </th>\n    );\n  }\n);\nTableHead.displayName = \"TableHead\";\n\nexport interface TableCellProps\n  extends React.TdHTMLAttributes<HTMLTableCellElement> {\n  align?: TableAlign;\n}\n\nconst TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps>(\n  ({ align = \"left\", className, ...props }, ref) => {\n    const { size } = useTableContext(\"TableCell\");\n    const isCompact = size === \"compact\";\n\n    return (\n      <td\n        className={cn(\n          \"min-w-0 px-2 align-middle\",\n          isCompact ? \"py-2\" : \"py-4\",\n          alignClassName(align),\n          className\n        )}\n        data-align={align}\n        data-slot=\"table-cell\"\n        ref={ref}\n        {...props}\n      />\n    );\n  }\n);\nTableCell.displayName = \"TableCell\";\n\nexport interface TableSelectHeadProps\n  extends Omit<React.ThHTMLAttributes<HTMLTableCellElement>, \"children\"> {\n  \"aria-label\"?: string;\n  checked?: boolean;\n  indeterminate?: boolean;\n  onCheckedChange?: (checked: boolean) => void;\n}\n\nconst TableSelectHead = React.forwardRef<\n  HTMLTableCellElement,\n  TableSelectHeadProps\n>(\n  (\n    {\n      \"aria-label\": ariaLabel = \"Select all rows\",\n      checked = false,\n      className,\n      indeterminate = false,\n      onCheckedChange,\n      ...props\n    },\n    ref\n  ) => {\n    const inputRef = React.useRef<HTMLInputElement>(null);\n    const { size } = useTableContext(\"TableSelectHead\");\n    const isCompact = size === \"compact\";\n\n    React.useEffect(() => {\n      if (inputRef.current) {\n        inputRef.current.indeterminate = indeterminate;\n      }\n    }, [indeterminate]);\n\n    return (\n      <th\n        className={cn(\n          \"w-10 min-w-0 px-2 text-center\",\n          isCompact ? \"py-2\" : \"py-3\",\n          className\n        )}\n        data-slot=\"table-select-head\"\n        ref={ref}\n        scope=\"col\"\n        {...props}\n      >\n        <input\n          aria-label={ariaLabel}\n          checked={checked}\n          className={selectCheckboxClassName}\n          onChange={(event) => onCheckedChange?.(event.target.checked)}\n          ref={inputRef}\n          type=\"checkbox\"\n        />\n      </th>\n    );\n  }\n);\nTableSelectHead.displayName = \"TableSelectHead\";\n\nexport interface TableSelectCellProps\n  extends Omit<React.TdHTMLAttributes<HTMLTableCellElement>, \"children\"> {\n  \"aria-label\"?: string;\n  checked?: boolean;\n  onCheckedChange?: (checked: boolean) => void;\n}\n\nconst TableSelectCell = React.forwardRef<\n  HTMLTableCellElement,\n  TableSelectCellProps\n>(\n  (\n    {\n      \"aria-label\": ariaLabel = \"Select row\",\n      checked = false,\n      className,\n      onCheckedChange,\n      ...props\n    },\n    ref\n  ) => {\n    const { size } = useTableContext(\"TableSelectCell\");\n    const isCompact = size === \"compact\";\n\n    return (\n      <td\n        className={cn(\n          \"w-10 min-w-0 px-2 text-center align-middle\",\n          isCompact ? \"py-2\" : \"py-4\",\n          className\n        )}\n        data-slot=\"table-select-cell\"\n        ref={ref}\n        {...props}\n      >\n        <input\n          aria-label={ariaLabel}\n          checked={checked}\n          className={selectCheckboxClassName}\n          onChange={(event) => onCheckedChange?.(event.target.checked)}\n          type=\"checkbox\"\n        />\n      </td>\n    );\n  }\n);\nTableSelectCell.displayName = \"TableSelectCell\";\n\nexport interface TableCaptionProps\n  extends React.HTMLAttributes<HTMLTableCaptionElement> {}\n\nconst TableCaption = React.forwardRef<\n  HTMLTableCaptionElement,\n  TableCaptionProps\n>(({ className, ...props }, ref) => (\n  <caption\n    className={cn(\"pt-6 text-muted-foreground text-xs\", className)}\n    data-slot=\"table-caption\"\n    ref={ref}\n    {...props}\n  />\n));\nTableCaption.displayName = \"TableCaption\";\n\nexport interface TableEmptyProps\n  extends Omit<React.ComponentPropsWithoutRef<typeof motion.tr>, \"children\"> {\n  colSpan?: number;\n  children?: React.ReactNode;\n}\n\nconst TableEmpty = React.forwardRef<HTMLTableRowElement, TableEmptyProps>(\n  (\n    {\n      animate,\n      children,\n      className,\n      colSpan,\n      initial,\n      style,\n      transition,\n      ...props\n    },\n    ref\n  ) => {\n    const { columnCount, columns } = useTableContext(\"TableEmpty\");\n    const motionEnabled = useTableMotionEnabled();\n\n    return (\n      <motion.tr\n        animate={animate ?? (motionEnabled ? { opacity: 1 } : undefined)}\n        className={cn(\"grid border-border border-b\", className)}\n        data-slot=\"table-empty\"\n        initial={initial ?? (motionEnabled ? { opacity: 0 } : false)}\n        ref={ref}\n        style={{ ...style, gridTemplateColumns: columns }}\n        transition={\n          transition ?? (motionEnabled ? { duration: 0.2 } : undefined)\n        }\n        {...props}\n      >\n        <td\n          className=\"col-span-full px-2 py-16 text-center text-muted-foreground text-sm\"\n          colSpan={colSpan ?? columnCount}\n        >\n          {children}\n        </td>\n      </motion.tr>\n    );\n  }\n);\nTableEmpty.displayName = \"TableEmpty\";\n\nfunction TableLoadingBar({ className }: { className?: string }) {\n  return (\n    <div\n      aria-hidden=\"true\"\n      className={cn(\"h-3.5 animate-pulse rounded-md bg-muted\", className)}\n    />\n  );\n}\n\nexport interface TableLoadingProps\n  extends Omit<TableRowProps, \"children\" | \"variant\"> {\n  rows?: number;\n}\n\nconst TableLoading = ({ rows = 3, ...props }: TableLoadingProps) => {\n  const { columnCount } = useTableContext(\"TableLoading\");\n  const safeRows = Math.max(0, rows);\n\n  return Array.from({ length: safeRows }, (_, rowIndex) => (\n    <TableRow index={rowIndex} key={`table-loading-${rowIndex}`} {...props}>\n      {Array.from({ length: columnCount }, (_, columnIndex) => (\n        <TableCell key={`table-loading-${rowIndex}-${columnIndex}`}>\n          <TableLoadingBar\n            className={cn(\n              columnIndex === 0 && \"w-36\",\n              columnIndex > 0 && columnIndex < columnCount - 1 && \"w-24\",\n              columnIndex === columnCount - 1 && \"ml-auto w-16\"\n            )}\n          />\n        </TableCell>\n      ))}\n    </TableRow>\n  ));\n};\nTableLoading.displayName = \"TableLoading\";\n\nexport interface TableSortButtonProps\n  extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n  active?: boolean;\n  align?: TableAlign;\n  direction?: TableSortDirection;\n}\n\nconst TableSortButton = React.forwardRef<\n  HTMLButtonElement,\n  TableSortButtonProps\n>(\n  (\n    {\n      active = false,\n      align = \"left\",\n      \"aria-label\": ariaLabel,\n      children,\n      className,\n      direction = \"asc\",\n      type = \"button\",\n      ...props\n    },\n    ref\n  ) => {\n    const motionEnabled = useTableMotionEnabled();\n    const resolvedAriaLabel =\n      ariaLabel ?? getSortButtonLabel(children, active, direction);\n\n    return (\n      <button\n        aria-label={resolvedAriaLabel}\n        className={cn(\n          componentThemeClassName,\n          \"flex min-h-10 w-full items-center gap-2 rounded-md px-3 py-2 text-left outline-none transition-colors transition-shadow focus-visible:ring-2 focus-visible:ring-foreground/20 focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n          active\n            ? \"text-foreground\"\n            : \"text-muted-foreground hover:text-foreground\",\n          sortButtonAlignClassName(align),\n          className\n        )}\n        data-align={align}\n        data-slot=\"table-sort-button\"\n        data-state={active ? \"active\" : \"inactive\"}\n        ref={ref}\n        type={type}\n        {...props}\n      >\n        <span className={cn(\"truncate\", active ? \"font-medium\" : undefined)}>\n          {children}\n        </span>\n        <motion.span\n          animate={\n            motionEnabled\n              ? {\n                  opacity: active ? 1 : 0.45,\n                  rotate: active && direction === \"desc\" ? 180 : 0,\n                  scale: active ? 1 : 0.95,\n                }\n              : undefined\n          }\n          className={cn(\n            \"shrink-0\",\n            active ? \"text-foreground\" : \"text-muted-foreground\"\n          )}\n          transition={motionEnabled ? { duration: 0.2 } : undefined}\n        >\n          <ArrowUpDown className=\"h-3.5 w-3.5\" />\n        </motion.span>\n      </button>\n    );\n  }\n);\nTableSortButton.displayName = \"TableSortButton\";\n\nexport interface TablePaginationProps\n  extends React.HTMLAttributes<HTMLDivElement> {\n  align?: TableAlign;\n  onPageChange: (page: number) => void;\n  page: number;\n  pageCount: number;\n  pageSize?: number;\n  showPageInfo?: boolean;\n  totalItems?: number;\n}\n\nconst paginationAlignClassName: Record<TableAlign, string> = {\n  left: \"justify-start\",\n  center: \"justify-center\",\n  right: \"justify-end\",\n};\n\nconst paginationButtonClassName =\n  \"inline-flex size-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40\";\n\nconst TablePagination = React.forwardRef<HTMLDivElement, TablePaginationProps>(\n  (\n    {\n      align = \"right\",\n      className,\n      onPageChange,\n      page,\n      pageCount,\n      pageSize,\n      showPageInfo = true,\n      totalItems,\n      ...props\n    },\n    ref\n  ) => {\n    const safePageCount = Math.max(0, pageCount);\n    const safePage =\n      safePageCount === 0 ? 1 : Math.min(Math.max(page, 1), safePageCount);\n    const canPrevious = safePageCount > 0 && safePage > 1;\n    const canNext = safePageCount > 0 && safePage < safePageCount;\n    const rangeStart =\n      totalItems !== undefined && pageSize !== undefined\n        ? totalItems === 0\n          ? 0\n          : Math.min((safePage - 1) * pageSize + 1, totalItems)\n        : undefined;\n    const rangeEnd =\n      totalItems !== undefined && pageSize !== undefined\n        ? totalItems === 0\n          ? 0\n          : Math.min(safePage * pageSize, totalItems)\n        : undefined;\n\n    return (\n      <div\n        className={cn(\n          \"flex items-center gap-3 px-2 py-3\",\n          paginationAlignClassName[align],\n          className\n        )}\n        data-align={align}\n        data-slot=\"table-pagination\"\n        ref={ref}\n        {...props}\n      >\n        {showPageInfo ? (\n          <p className=\"text-muted-foreground text-xs\">\n            {rangeStart !== undefined &&\n            rangeEnd !== undefined &&\n            totalItems !== undefined\n              ? `${rangeStart}–${rangeEnd} of ${totalItems}`\n              : safePageCount === 0\n                ? \"No pages\"\n                : `Page ${safePage} of ${safePageCount}`}\n          </p>\n        ) : null}\n        <div className=\"flex items-center gap-1\">\n          <button\n            aria-label=\"Previous page\"\n            className={paginationButtonClassName}\n            disabled={!canPrevious}\n            onClick={() => onPageChange(Math.max(1, safePage - 1))}\n            type=\"button\"\n          >\n            <ChevronLeft className=\"size-4\" />\n          </button>\n          <button\n            aria-label=\"Next page\"\n            className={paginationButtonClassName}\n            disabled={!canNext}\n            onClick={() =>\n              onPageChange(Math.min(safePageCount || 1, safePage + 1))\n            }\n            type=\"button\"\n          >\n            <ChevronRight className=\"size-4\" />\n          </button>\n        </div>\n      </div>\n    );\n  }\n);\nTablePagination.displayName = \"TablePagination\";\n\nexport {\n  Table,\n  TableToolbar,\n  TableHeader,\n  TableBody,\n  TableFooter,\n  TableRow,\n  TableHead,\n  TableCell,\n  TableSelectHead,\n  TableSelectCell,\n  TableCaption,\n  TableEmpty,\n  TableLoading,\n  TableSortButton,\n  TablePagination,\n  Table as table,\n};\n\nexport default Table;\n",
      "type": "registry:ui"
    }
  ],
  "title": "Table",
  "description": "Composable table primitives with grid-aligned rows, optional animated sort buttons, and layout-preserving row transitions."
}
