{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "data-table",
  "type": "registry:ui",
  "title": "DataTable",
  "description": "TanStack-powered DataTable workflow with semantic Table rendering, sorting, filtering (including a row predicate for FilterBar and a toolbar slot), pagination, row selection, column visibility, row actions, and accessible status states.",
  "dependencies": [
    "@tanstack/react-table@8.21.3"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://components.dethink.co.uk/r/dethink-base.json",
    "https://components.dethink.co.uk/r/table.json",
    "https://components.dethink.co.uk/r/button.json",
    "https://components.dethink.co.uk/r/checkbox.json",
    "https://components.dethink.co.uk/r/input.json"
  ],
  "files": [
    {
      "path": "packages/components/src/components/data-table/data-table.tsx",
      "type": "registry:file",
      "target": "~/components/dethink/components/data-table/data-table.tsx",
      "content": "import {\n  type HTMLAttributes,\n  type ReactNode,\n  useId,\n  useMemo,\n  useState,\n} from \"react\";\nimport {\n  flexRender,\n  getFilteredRowModel,\n  getCoreRowModel,\n  getPaginationRowModel,\n  getSortedRowModel,\n  useReactTable,\n  type Cell,\n  type Column,\n  type ColumnFiltersState,\n  type ColumnDef,\n  type FilterFnOption,\n  type Header,\n  type OnChangeFn,\n  type PaginationState,\n  type Row,\n  type RowData,\n  type RowSelectionState,\n  type SortingState,\n  type VisibilityState,\n} from \"@tanstack/react-table\";\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../button\";\nimport { Checkbox } from \"../checkbox\";\nimport { Input } from \"../input\";\nimport {\n  Table,\n  TableBody,\n  TableCaption,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n  type TableCaptionPlacement,\n  type TableDensity,\n} from \"../table\";\n\nexport type DataTableDensity = TableDensity;\nexport type DataTableSelectionMode = \"none\" | \"single\" | \"multiple\";\nexport type DataTableSortingState = SortingState;\nexport type DataTableColumnFiltersState = ColumnFiltersState;\nexport type DataTablePaginationState = PaginationState;\nexport type DataTableRowSelectionState = RowSelectionState;\nexport type DataTableVisibilityState = VisibilityState;\nexport type DataTableColumnDef<\n  TData extends RowData,\n  TValue = unknown,\n> = ColumnDef<TData, TValue>;\nexport type DataTableRow<TData extends RowData> = Row<TData>;\nexport type DataTableCell<TData extends RowData, TValue = unknown> = Cell<\n  TData,\n  TValue\n>;\nexport type DataTableHeader<TData extends RowData, TValue = unknown> = Header<\n  TData,\n  TValue\n>;\nexport type DataTableColumn<TData extends RowData, TValue = unknown> = Column<\n  TData,\n  TValue\n>;\n\nexport interface DataTableLabels {\n  clearGlobalFilter?: string;\n  columnVisibility?: string;\n  empty?: string;\n  error?: string;\n  globalFilter?: string;\n  loading?: string;\n  nextPage?: string;\n  pageLabel?: (page: number, pageCount: number) => string;\n  pageSize?: string;\n  previousPage?: string;\n  rowActions?: string;\n  rowCount?: (selectedCount: number, totalCount: number) => string;\n  selectAllRows?: string;\n  selectRow?: (rowId: string) => string;\n  sortAscending?: (column: string) => string;\n  sortDescending?: (column: string) => string;\n  clearSort?: (column: string) => string;\n}\n\nexport interface DataTableProps<TData extends RowData> extends Omit<\n  HTMLAttributes<HTMLDivElement>,\n  \"children\"\n> {\n  caption?: ReactNode;\n  captionPlacement?: TableCaptionPlacement;\n  columnFilters?: ColumnFiltersState;\n  columnVisibility?: VisibilityState;\n  columns: DataTableColumnDef<TData>[];\n  data: TData[];\n  defaultColumnFilters?: ColumnFiltersState;\n  defaultColumnVisibility?: VisibilityState;\n  defaultGlobalFilter?: string;\n  defaultPagination?: PaginationState;\n  defaultRowSelection?: RowSelectionState;\n  defaultSorting?: SortingState;\n  density?: DataTableDensity;\n  emptyContent?: ReactNode;\n  enableColumnFilters?: boolean;\n  enableColumnVisibility?: boolean;\n  enableGlobalFilter?: boolean;\n  enablePagination?: boolean;\n  enableSorting?: boolean;\n  error?: ReactNode;\n  globalFilter?: string;\n  /** Global filter function. Defaults to TanStack's `includesString`. */\n  globalFilterFn?: FilterFnOption<TData>;\n  globalFilterPlaceholder?: string;\n  getCellClassName?: (cell: DataTableCell<TData>) => string | undefined;\n  getRowClassName?: (row: DataTableRow<TData>) => string | undefined;\n  getRowId?: (\n    row: TData,\n    index: number,\n    parent?: DataTableRow<TData>,\n  ) => string;\n  labels?: DataTableLabels;\n  loading?: boolean;\n  loadingContent?: ReactNode;\n  manualFiltering?: boolean;\n  manualPagination?: boolean;\n  manualSorting?: boolean;\n  onColumnFiltersChange?: OnChangeFn<ColumnFiltersState>;\n  onColumnVisibilityChange?: OnChangeFn<VisibilityState>;\n  onGlobalFilterChange?: (value: string) => void;\n  onPaginationChange?: OnChangeFn<PaginationState>;\n  onRowSelectionChange?: OnChangeFn<RowSelectionState>;\n  onSortingChange?: OnChangeFn<SortingState>;\n  pageCount?: number;\n  pageSizeOptions?: number[];\n  pagination?: PaginationState;\n  renderColumnFilter?: (column: DataTableColumn<TData>) => ReactNode;\n  renderRowActions?: (row: DataTableRow<TData>) => ReactNode;\n  rowCount?: number;\n  /**\n   * Keeps only rows that pass the predicate, before sorting and pagination.\n   * Ignored when `manualFiltering` is set. Row ids stay tied to the original\n   * data index, so selection survives filter changes. Pair it with\n   * `createFilterPredicate` from the filter builder.\n   */\n  rowFilter?: (row: TData) => boolean;\n  rowSelection?: RowSelectionState;\n  selectionMode?: DataTableSelectionMode;\n  sorting?: SortingState;\n  tableClassName?: string;\n  tableContainerClassName?: string;\n  /** Content rendered at the start of the toolbar, such as a FilterBar. */\n  toolbar?: ReactNode;\n}\n\nconst defaultLabels = {\n  clearGlobalFilter: \"Clear search\",\n  columnVisibility: \"Columns\",\n  empty: \"No results.\",\n  error: \"Unable to load table data.\",\n  globalFilter: \"Search table\",\n  loading: \"Loading table data.\",\n  nextPage: \"Next page\",\n  pageLabel: (page: number, pageCount: number) =>\n    `Page ${page} of ${pageCount}`,\n  pageSize: \"Rows per page\",\n  previousPage: \"Previous page\",\n  rowActions: \"Actions\",\n  rowCount: (selectedCount: number, totalCount: number) =>\n    selectedCount > 0\n      ? `${selectedCount} of ${totalCount} row${totalCount === 1 ? \"\" : \"s\"} selected`\n      : `${totalCount} row${totalCount === 1 ? \"\" : \"s\"}`,\n  selectAllRows: \"Select all rows\",\n  selectRow: (rowId: string) => `Select row ${rowId}`,\n  sortAscending: (column: string) => `Sort ${column} ascending`,\n  sortDescending: (column: string) => `Sort ${column} descending`,\n  clearSort: (column: string) => `Clear ${column} sort`,\n} satisfies Required<DataTableLabels>;\n\nconst dataTableBaseClasses = \"w-full\";\n\nconst dataTableToolbarBaseClasses =\n  \"mb-[var(--dt-space-3)] flex flex-wrap items-end gap-[var(--dt-space-3)]\";\n\nconst dataTableToolbarContentBaseClasses = \"min-w-0 basis-full\";\n\nconst dataTableToolbarGroupBaseClasses =\n  \"flex min-w-0 flex-wrap items-center gap-[var(--dt-space-2)]\";\n\nconst dataTableControlLabelBaseClasses =\n  \"text-xs font-medium uppercase tracking-normal text-muted-foreground\";\n\nconst dataTableColumnVisibilityBaseClasses =\n  \"flex min-w-0 flex-wrap items-center gap-[var(--dt-space-2)] rounded-md border border-border bg-muted/30 px-[var(--dt-space-2)] py-[var(--dt-space-1-5)]\";\n\nconst dataTableColumnVisibilityOptionsBaseClasses =\n  \"flex flex-wrap items-center gap-[var(--dt-space-2)]\";\n\nconst dataTableCheckboxLabelBaseClasses =\n  \"inline-flex min-h-8 items-center gap-[var(--dt-space-2)] rounded-sm px-[var(--dt-space-1)] text-sm text-foreground\";\n\nconst dataTableHeaderCellFilterableClasses = \"min-w-40 align-top\";\n\nconst dataTableHeaderContentBaseClasses =\n  \"grid min-w-0 gap-[var(--dt-space-2)]\";\n\nconst dataTableHeaderLabelBaseClasses = \"block min-w-0 truncate\";\n\nconst dataTableColumnFilterBaseClasses = \"block min-w-0\";\n\nconst dataTablePaginationBaseClasses =\n  \"mt-[var(--dt-space-3)] flex flex-wrap items-center justify-between gap-[var(--dt-space-3)] text-sm text-muted-foreground\";\n\nconst dataTablePaginationControlsBaseClasses =\n  \"flex flex-wrap items-center gap-[var(--dt-space-2)]\";\n\nconst dataTablePageSizeSelectBaseClasses =\n  \"h-8 rounded-md border border-input bg-background px-[var(--dt-space-2)] text-sm text-foreground shadow-sm outline-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/20\";\n\nconst dataTableStateCellBaseClasses =\n  \"h-24 text-center text-sm text-muted-foreground\";\n\nconst dataTableErrorCellBaseClasses =\n  \"h-24 text-center text-sm font-medium text-destructive\";\n\nconst dataTableSortButtonBaseClasses =\n  \"group flex min-h-8 w-full min-w-0 items-center justify-start gap-[var(--dt-space-1-5)] rounded-sm text-start font-medium text-muted-foreground outline-none motion-safe:transition-colors motion-safe:duration-150 motion-safe:ease-out motion-reduce:transition-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\";\n\nconst dataTableSortLabelBaseClasses = \"min-w-0 truncate\";\n\nconst dataTableSortIndicatorBaseClasses =\n  \"ms-auto inline-flex size-5 shrink-0 items-center justify-center rounded-sm text-muted-foreground motion-safe:transition-colors motion-safe:duration-150 group-hover:text-foreground group-data-[sorted=asc]:text-foreground group-data-[sorted=desc]:text-foreground\";\n\nconst dataTableEmptyBaseClasses =\n  \"h-24 text-center text-sm text-muted-foreground\";\n\nexport function dataTableClassNames({\n  className,\n}: Pick<DataTableProps<RowData>, \"className\"> = {}) {\n  return cn(dataTableBaseClasses, className);\n}\n\nexport function dataTableSortButtonClassNames({\n  className,\n}: { className?: string } = {}) {\n  return cn(dataTableSortButtonBaseClasses, className);\n}\n\nexport function dataTableSortIndicatorClassNames({\n  className,\n}: { className?: string } = {}) {\n  return cn(dataTableSortIndicatorBaseClasses, className);\n}\n\nexport function dataTableToolbarClassNames({\n  className,\n}: { className?: string } = {}) {\n  return cn(dataTableToolbarBaseClasses, className);\n}\n\nexport function dataTablePaginationClassNames({\n  className,\n}: { className?: string } = {}) {\n  return cn(dataTablePaginationBaseClasses, className);\n}\n\nexport function dataTableEmptyClassNames({\n  className,\n}: { className?: string } = {}) {\n  return cn(dataTableEmptyBaseClasses, className);\n}\n\nfunction getHeaderLabel<TData extends RowData>(header: Header<TData, unknown>) {\n  const headerValue = header.column.columnDef.header;\n\n  if (typeof headerValue === \"string\") {\n    return headerValue;\n  }\n\n  return header.column.id;\n}\n\nfunction getNextSortLabel(\n  labels: Required<DataTableLabels>,\n  columnLabel: string,\n  sorted: false | \"asc\" | \"desc\",\n) {\n  if (sorted === \"asc\") {\n    return labels.sortDescending(columnLabel);\n  }\n\n  if (sorted === \"desc\") {\n    return labels.clearSort(columnLabel);\n  }\n\n  return labels.sortAscending(columnLabel);\n}\n\nfunction getAriaSort(sorted: false | \"asc\" | \"desc\") {\n  if (sorted === \"asc\") {\n    return \"ascending\";\n  }\n\n  if (sorted === \"desc\") {\n    return \"descending\";\n  }\n\n  return undefined;\n}\n\nfunction getColumnLabel<TData extends RowData>(column: Column<TData, unknown>) {\n  const headerValue = column.columnDef.header;\n\n  if (typeof headerValue === \"string\") {\n    return headerValue;\n  }\n\n  return column.id;\n}\n\nfunction resolveUpdater<T>(updater: T | ((old: T) => T), current: T) {\n  return typeof updater === \"function\"\n    ? (updater as (old: T) => T)(current)\n    : updater;\n}\n\nfunction getSelectedRowCount(rowSelection: RowSelectionState) {\n  return Object.values(rowSelection).filter(Boolean).length;\n}\n\nfunction SortIcon({ sorted }: { sorted: false | \"asc\" | \"desc\" }) {\n  return (\n    <svg\n      aria-hidden=\"true\"\n      data-slot=\"data-table-sort-icon\"\n      data-sort-state={sorted || \"none\"}\n      focusable=\"false\"\n      viewBox=\"0 0 16 16\"\n      className=\"size-4 motion-safe:[&>path]:transition-opacity motion-safe:[&>path]:duration-[var(--dt-motion-fast)]\"\n    >\n      <path\n        d=\"M4.5 3 2 5.5h5L4.5 3Z\"\n        fill=\"currentColor\"\n        opacity={sorted === \"desc\" ? 0.35 : 1}\n      />\n      <path\n        d=\"M11.5 13 14 10.5H9l2.5 2.5Z\"\n        fill=\"currentColor\"\n        opacity={sorted === \"asc\" ? 0.35 : 1}\n      />\n      <path\n        d=\"M4.5 5v8M11.5 11V3\"\n        fill=\"none\"\n        stroke=\"currentColor\"\n        strokeLinecap=\"round\"\n        strokeWidth=\"1.5\"\n        opacity={sorted ? 1 : 0.65}\n      />\n    </svg>\n  );\n}\n\nfunction DefaultColumnFilter<TData extends RowData>({\n  column,\n  label,\n}: {\n  column: Column<TData, unknown>;\n  label: string;\n}) {\n  return (\n    <label\n      data-slot=\"data-table-column-filter\"\n      className={dataTableColumnFilterBaseClasses}\n    >\n      <span className=\"sr-only\">Filter {label}</span>\n      <Input\n        aria-label={`Filter ${label}`}\n        controlSize=\"sm\"\n        value={(column.getFilterValue() ?? \"\") as string}\n        onChange={(event) => {\n          column.setFilterValue(event.currentTarget.value);\n        }}\n        placeholder={`Filter ${label}`}\n      />\n    </label>\n  );\n}\n\nexport function DataTable<TData extends RowData>({\n  \"aria-describedby\": ariaDescribedBy,\n  \"aria-label\": ariaLabel,\n  \"aria-labelledby\": ariaLabelledBy,\n  caption,\n  captionPlacement = \"bottom\",\n  className,\n  columnFilters,\n  columnVisibility,\n  columns,\n  data,\n  defaultColumnFilters = [],\n  defaultColumnVisibility = {},\n  defaultGlobalFilter = \"\",\n  defaultPagination = {\n    pageIndex: 0,\n    pageSize: 10,\n  },\n  defaultRowSelection = {},\n  defaultSorting = [],\n  density = \"default\",\n  emptyContent,\n  enableColumnFilters = false,\n  enableColumnVisibility = false,\n  enableGlobalFilter = false,\n  enablePagination = false,\n  enableSorting = true,\n  error,\n  globalFilter,\n  globalFilterFn = \"includesString\",\n  globalFilterPlaceholder,\n  getCellClassName,\n  getRowClassName,\n  getRowId,\n  labels,\n  loading = false,\n  loadingContent,\n  manualFiltering = false,\n  manualPagination = false,\n  manualSorting = false,\n  onColumnFiltersChange,\n  onColumnVisibilityChange,\n  onGlobalFilterChange,\n  onPaginationChange,\n  onRowSelectionChange,\n  onSortingChange,\n  pageCount,\n  pageSizeOptions = [10, 25, 50],\n  pagination,\n  renderColumnFilter,\n  renderRowActions,\n  rowCount,\n  rowFilter,\n  rowSelection,\n  selectionMode = \"none\",\n  sorting,\n  tableClassName,\n  tableContainerClassName,\n  toolbar,\n  ...props\n}: DataTableProps<TData>) {\n  const generatedId = useId();\n  const mergedLabels: Required<DataTableLabels> = {\n    clearGlobalFilter:\n      labels?.clearGlobalFilter ?? defaultLabels.clearGlobalFilter,\n    columnVisibility:\n      labels?.columnVisibility ?? defaultLabels.columnVisibility,\n    empty: labels?.empty ?? defaultLabels.empty,\n    error: labels?.error ?? defaultLabels.error,\n    globalFilter: labels?.globalFilter ?? defaultLabels.globalFilter,\n    loading: labels?.loading ?? defaultLabels.loading,\n    nextPage: labels?.nextPage ?? defaultLabels.nextPage,\n    pageLabel: labels?.pageLabel ?? defaultLabels.pageLabel,\n    pageSize: labels?.pageSize ?? defaultLabels.pageSize,\n    previousPage: labels?.previousPage ?? defaultLabels.previousPage,\n    rowActions: labels?.rowActions ?? defaultLabels.rowActions,\n    rowCount: labels?.rowCount ?? defaultLabels.rowCount,\n    selectAllRows: labels?.selectAllRows ?? defaultLabels.selectAllRows,\n    selectRow: labels?.selectRow ?? defaultLabels.selectRow,\n    sortAscending: labels?.sortAscending ?? defaultLabels.sortAscending,\n    sortDescending: labels?.sortDescending ?? defaultLabels.sortDescending,\n    clearSort: labels?.clearSort ?? defaultLabels.clearSort,\n  };\n  const [internalColumnFilters, setInternalColumnFilters] =\n    useState<ColumnFiltersState>(defaultColumnFilters);\n  const [internalColumnVisibility, setInternalColumnVisibility] =\n    useState<VisibilityState>(defaultColumnVisibility);\n  const [internalGlobalFilter, setInternalGlobalFilter] =\n    useState(defaultGlobalFilter);\n  const [internalPagination, setInternalPagination] =\n    useState<PaginationState>(defaultPagination);\n  const [internalRowSelection, setInternalRowSelection] =\n    useState<RowSelectionState>(defaultRowSelection);\n  const [internalSorting, setInternalSorting] =\n    useState<SortingState>(defaultSorting);\n  const currentColumnFilters = columnFilters ?? internalColumnFilters;\n  const currentColumnVisibility = columnVisibility ?? internalColumnVisibility;\n  const currentGlobalFilter = globalFilter ?? internalGlobalFilter;\n  const currentPagination = pagination ?? internalPagination;\n  const currentRowSelection = rowSelection ?? internalRowSelection;\n  const currentSorting = sorting ?? internalSorting;\n  const isColumnFiltersControlled = columnFilters !== undefined;\n  const isColumnVisibilityControlled = columnVisibility !== undefined;\n  const isGlobalFilterControlled = globalFilter !== undefined;\n  const isPaginationControlled = pagination !== undefined;\n  const isRowSelectionControlled = rowSelection !== undefined;\n  const isSortingControlled = sorting !== undefined;\n  const hasRowSelection = selectionMode !== \"none\";\n  const hasRowActions = renderRowActions !== undefined;\n  const applyRowFilter = rowFilter !== undefined && !manualFiltering;\n  // Source index of each kept row, by position, so duplicate row objects\n  // keep distinct ids.\n  const keptIndexes = useMemo(\n    () =>\n      applyRowFilter\n        ? data.flatMap((row, index) => (rowFilter(row) ? [index] : []))\n        : undefined,\n    [applyRowFilter, data, rowFilter],\n  );\n  const tableData = useMemo(\n    () => (keptIndexes ? keptIndexes.map((index) => data[index]!) : data),\n    [data, keptIndexes],\n  );\n  const resolvedGetRowId = useMemo(() => {\n    if (getRowId || !keptIndexes) {\n      return getRowId;\n    }\n\n    // Filtering changes positions, so default ids use the source index.\n    return (_row: TData, index: number, parent?: DataTableRow<TData>) =>\n      parent ? `${parent.id}.${index}` : String(keptIndexes[index] ?? index);\n  }, [getRowId, keptIndexes]);\n\n  // eslint-disable-next-line react-hooks/incompatible-library -- TanStack Table v8 returns mutable table methods; keep this call outside React Compiler memoization.\n  const table = useReactTable({\n    autoResetPageIndex: !manualPagination,\n    columnResizeMode: \"onChange\",\n    columns,\n    data: tableData,\n    enableColumnFilters,\n    enableGlobalFilter,\n    enableHiding: enableColumnVisibility,\n    enableMultiRowSelection: selectionMode === \"multiple\",\n    enableMultiSort: false,\n    enableRowSelection: hasRowSelection,\n    enableSorting,\n    getCoreRowModel: getCoreRowModel(),\n    getFilteredRowModel: manualFiltering ? undefined : getFilteredRowModel(),\n    getPaginationRowModel:\n      enablePagination && !manualPagination\n        ? getPaginationRowModel()\n        : undefined,\n    getRowId: resolvedGetRowId,\n    getSortedRowModel: manualSorting ? undefined : getSortedRowModel(),\n    globalFilterFn,\n    manualFiltering,\n    manualPagination,\n    manualSorting,\n    onColumnFiltersChange: (updater) => {\n      if (!isColumnFiltersControlled) {\n        setInternalColumnFilters(updater);\n      }\n\n      onColumnFiltersChange?.(updater);\n    },\n    onColumnVisibilityChange: (updater) => {\n      if (!isColumnVisibilityControlled) {\n        setInternalColumnVisibility(updater);\n      }\n\n      onColumnVisibilityChange?.(updater);\n    },\n    onGlobalFilterChange: (updater) => {\n      const nextValue = String(\n        resolveUpdater(updater, currentGlobalFilter) ?? \"\",\n      );\n\n      if (!isGlobalFilterControlled) {\n        setInternalGlobalFilter(nextValue);\n      }\n\n      if (!isPaginationControlled) {\n        setInternalPagination((current) => ({\n          ...current,\n          pageIndex: 0,\n        }));\n      }\n\n      onGlobalFilterChange?.(nextValue);\n    },\n    onPaginationChange: (updater) => {\n      if (!isPaginationControlled) {\n        setInternalPagination(updater);\n      }\n\n      onPaginationChange?.(updater);\n    },\n    onRowSelectionChange: (updater) => {\n      if (!isRowSelectionControlled) {\n        setInternalRowSelection(updater);\n      }\n\n      onRowSelectionChange?.(updater);\n    },\n    onSortingChange: (updater) => {\n      if (!isSortingControlled) {\n        setInternalSorting(updater);\n      }\n\n      onSortingChange?.(updater);\n    },\n    pageCount,\n    rowCount,\n    state: {\n      columnFilters: currentColumnFilters,\n      columnVisibility: currentColumnVisibility,\n      globalFilter: currentGlobalFilter,\n      pagination: currentPagination,\n      rowSelection: currentRowSelection,\n      sorting: currentSorting,\n    },\n    sortDescFirst: false,\n  });\n  const rows = table.getRowModel().rows;\n  const selectedRowCount = getSelectedRowCount(currentRowSelection);\n  const totalRowCount =\n    rowCount ?? table.getPrePaginationRowModel().rows.length;\n  const visibleColumnCount = Math.max(\n    table.getVisibleLeafColumns().length +\n      (hasRowSelection ? 1 : 0) +\n      (hasRowActions ? 1 : 0),\n    1,\n  );\n  const pageCountLabel = Math.max(table.getPageCount(), 1);\n  const currentStatus = error\n    ? \"error\"\n    : loading\n      ? \"loading\"\n      : rows.length === 0\n        ? \"empty\"\n        : \"idle\";\n  const globalFilterId = `${generatedId}-global-filter`;\n  const pageSizeId = `${generatedId}-page-size`;\n  const hasToolbar =\n    toolbar !== undefined ||\n    enableGlobalFilter ||\n    enableColumnVisibility ||\n    hasRowSelection;\n\n  return (\n    <div\n      {...props}\n      data-slot=\"data-table\"\n      data-density={density}\n      data-status={currentStatus}\n      data-manual-filtering={manualFiltering ? \"true\" : undefined}\n      data-manual-pagination={manualPagination ? \"true\" : undefined}\n      data-manual-sorting={manualSorting ? \"true\" : undefined}\n      className={dataTableClassNames({ className })}\n    >\n      {hasToolbar ? (\n        <div\n          data-slot=\"data-table-toolbar\"\n          className={dataTableToolbarClassNames()}\n        >\n          {toolbar !== undefined ? (\n            <div\n              data-slot=\"data-table-toolbar-content\"\n              className={dataTableToolbarContentBaseClasses}\n            >\n              {toolbar}\n            </div>\n          ) : null}\n          {enableGlobalFilter ? (\n            <div\n              data-slot=\"data-table-global-filter\"\n              className={dataTableToolbarGroupBaseClasses}\n            >\n              <label\n                htmlFor={globalFilterId}\n                className={dataTableControlLabelBaseClasses}\n              >\n                {mergedLabels.globalFilter}\n              </label>\n              <Input\n                id={globalFilterId}\n                controlSize=\"sm\"\n                value={currentGlobalFilter}\n                onChange={(event) => {\n                  table.setGlobalFilter(event.currentTarget.value);\n                }}\n                placeholder={\n                  globalFilterPlaceholder ?? mergedLabels.globalFilter\n                }\n              />\n              {currentGlobalFilter ? (\n                <Button\n                  size=\"sm\"\n                  variant=\"ghost\"\n                  onClick={() => {\n                    table.setGlobalFilter(\"\");\n                  }}\n                >\n                  {mergedLabels.clearGlobalFilter}\n                </Button>\n              ) : null}\n            </div>\n          ) : null}\n\n          {enableColumnVisibility ? (\n            <fieldset\n              data-slot=\"data-table-column-visibility\"\n              className={dataTableColumnVisibilityBaseClasses}\n            >\n              <legend className={dataTableControlLabelBaseClasses}>\n                {mergedLabels.columnVisibility}\n              </legend>\n              <div className={dataTableColumnVisibilityOptionsBaseClasses}>\n                {table\n                  .getAllLeafColumns()\n                  .filter((column) => column.getCanHide())\n                  .map((column) => {\n                    const label = getColumnLabel(column);\n\n                    return (\n                      <label\n                        key={column.id}\n                        className={dataTableCheckboxLabelBaseClasses}\n                      >\n                        <Checkbox\n                          aria-label={`Toggle ${label} column`}\n                          checked={column.getIsVisible()}\n                          controlSize=\"sm\"\n                          onCheckedChange={(checked) => {\n                            column.toggleVisibility(checked === true);\n                          }}\n                        />\n                        <span>{label}</span>\n                      </label>\n                    );\n                  })}\n              </div>\n            </fieldset>\n          ) : null}\n\n          {hasRowSelection ? (\n            <div\n              aria-live=\"polite\"\n              data-slot=\"data-table-selection-summary\"\n              className={dataTableControlLabelBaseClasses}\n            >\n              {mergedLabels.rowCount(selectedRowCount, totalRowCount)}\n            </div>\n          ) : null}\n        </div>\n      ) : null}\n\n      <Table\n        aria-describedby={ariaDescribedBy}\n        aria-label={ariaLabel}\n        aria-labelledby={ariaLabelledBy}\n        density={density}\n        className={tableClassName}\n        containerClassName={tableContainerClassName}\n      >\n        {caption ? (\n          <TableCaption placement={captionPlacement}>{caption}</TableCaption>\n        ) : null}\n        <TableHeader data-table-slot=\"header\">\n          {table.getHeaderGroups().map((headerGroup) => (\n            <TableRow\n              key={headerGroup.id}\n              hoverable={false}\n              data-table-slot=\"header-row\"\n            >\n              {hasRowSelection ? (\n                <TableHead\n                  data-table-slot=\"selection-header-cell\"\n                  className=\"w-density-control\"\n                >\n                  {selectionMode === \"multiple\" ? (\n                    <Checkbox\n                      aria-label={mergedLabels.selectAllRows}\n                      checked={\n                        table.getIsAllRowsSelected()\n                          ? true\n                          : table.getIsSomeRowsSelected()\n                            ? \"indeterminate\"\n                            : false\n                      }\n                      controlSize=\"sm\"\n                      onCheckedChange={(checked) => {\n                        table.toggleAllRowsSelected(checked === true);\n                      }}\n                    />\n                  ) : null}\n                </TableHead>\n              ) : null}\n              {headerGroup.headers.map((header) => {\n                const sorted = header.column.getIsSorted();\n                const canSort = header.column.getCanSort();\n                const canFilter =\n                  enableColumnFilters && header.column.getCanFilter();\n                const columnLabel = getHeaderLabel(header);\n                const headerContent = header.isPlaceholder\n                  ? null\n                  : flexRender(\n                      header.column.columnDef.header,\n                      header.getContext(),\n                    );\n\n                return (\n                  <TableHead\n                    key={header.id}\n                    colSpan={header.colSpan}\n                    aria-sort={getAriaSort(sorted)}\n                    data-table-slot=\"header-cell\"\n                    data-filterable={canFilter ? \"true\" : undefined}\n                    data-sortable={canSort ? \"true\" : undefined}\n                    data-sorted={sorted || undefined}\n                    className={cn(\n                      canFilter\n                        ? dataTableHeaderCellFilterableClasses\n                        : undefined,\n                    )}\n                  >\n                    <div\n                      data-slot=\"data-table-header-content\"\n                      className={dataTableHeaderContentBaseClasses}\n                    >\n                      {canSort && !header.isPlaceholder ? (\n                        <button\n                          type=\"button\"\n                          data-slot=\"data-table-sort-button\"\n                          data-sorted={sorted || undefined}\n                          aria-label={getNextSortLabel(\n                            mergedLabels,\n                            columnLabel,\n                            sorted,\n                          )}\n                          aria-pressed={sorted ? \"true\" : undefined}\n                          className={dataTableSortButtonClassNames()}\n                          onClick={header.column.getToggleSortingHandler()}\n                        >\n                          <span className={dataTableSortLabelBaseClasses}>\n                            {headerContent}\n                          </span>\n                          <span\n                            aria-hidden=\"true\"\n                            data-slot=\"data-table-sort-indicator\"\n                            className={dataTableSortIndicatorClassNames()}\n                          >\n                            <SortIcon sorted={sorted} />\n                          </span>\n                        </button>\n                      ) : (\n                        <span className={dataTableHeaderLabelBaseClasses}>\n                          {headerContent}\n                        </span>\n                      )}\n                      {canFilter && !header.isPlaceholder\n                        ? (renderColumnFilter?.(header.column) ?? (\n                            <DefaultColumnFilter\n                              column={header.column}\n                              label={columnLabel}\n                            />\n                          ))\n                        : null}\n                    </div>\n                  </TableHead>\n                );\n              })}\n              {hasRowActions ? (\n                <TableHead data-table-slot=\"actions-header-cell\" align=\"end\">\n                  <span className=\"sr-only\">{mergedLabels.rowActions}</span>\n                </TableHead>\n              ) : null}\n            </TableRow>\n          ))}\n        </TableHeader>\n        <TableBody data-table-slot=\"body\">\n          {error ? (\n            <TableRow hoverable={false} data-table-slot=\"error-row\">\n              <TableCell\n                colSpan={visibleColumnCount}\n                data-table-slot=\"error\"\n                className={dataTableErrorCellBaseClasses}\n              >\n                <div role=\"alert\">{error ?? mergedLabels.error}</div>\n              </TableCell>\n            </TableRow>\n          ) : loading ? (\n            <TableRow hoverable={false} data-table-slot=\"loading-row\">\n              <TableCell\n                colSpan={visibleColumnCount}\n                data-table-slot=\"loading\"\n                className={dataTableStateCellBaseClasses}\n              >\n                <div role=\"status\">\n                  {loadingContent ?? mergedLabels.loading}\n                </div>\n              </TableCell>\n            </TableRow>\n          ) : rows.length > 0 ? (\n            rows.map((row) => (\n              <TableRow\n                key={row.id}\n                data-table-slot=\"row\"\n                data-row-id={row.id}\n                selected={row.getIsSelected()}\n                className={getRowClassName?.(row)}\n              >\n                {hasRowSelection ? (\n                  <TableCell data-table-slot=\"selection-cell\">\n                    <Checkbox\n                      aria-label={mergedLabels.selectRow(row.id)}\n                      checked={row.getIsSelected()}\n                      controlSize=\"sm\"\n                      disabled={!row.getCanSelect()}\n                      onCheckedChange={(checked) => {\n                        row.toggleSelected(checked === true);\n                      }}\n                    />\n                  </TableCell>\n                ) : null}\n                {row.getVisibleCells().map((cell) => (\n                  <TableCell\n                    key={cell.id}\n                    data-table-slot=\"cell\"\n                    className={getCellClassName?.(cell)}\n                  >\n                    {flexRender(cell.column.columnDef.cell, cell.getContext())}\n                  </TableCell>\n                ))}\n                {hasRowActions ? (\n                  <TableCell data-table-slot=\"row-actions\" align=\"end\">\n                    {renderRowActions(row)}\n                  </TableCell>\n                ) : null}\n              </TableRow>\n            ))\n          ) : (\n            <TableRow hoverable={false} data-table-slot=\"empty-row\">\n              <TableCell\n                colSpan={visibleColumnCount}\n                data-table-slot=\"empty\"\n                className={dataTableEmptyClassNames()}\n              >\n                {emptyContent ?? mergedLabels.empty}\n              </TableCell>\n            </TableRow>\n          )}\n        </TableBody>\n      </Table>\n\n      {enablePagination ? (\n        <div\n          data-slot=\"data-table-pagination\"\n          className={dataTablePaginationClassNames()}\n        >\n          <div data-slot=\"data-table-page-summary\">\n            {mergedLabels.pageLabel(\n              table.getState().pagination.pageIndex + 1,\n              pageCountLabel,\n            )}\n          </div>\n          <div className={dataTablePaginationControlsBaseClasses}>\n            <label\n              htmlFor={pageSizeId}\n              className={dataTableControlLabelBaseClasses}\n            >\n              {mergedLabels.pageSize}\n            </label>\n            <select\n              id={pageSizeId}\n              aria-label={mergedLabels.pageSize}\n              className={dataTablePageSizeSelectBaseClasses}\n              value={table.getState().pagination.pageSize}\n              onChange={(event) => {\n                table.setPageSize(Number(event.currentTarget.value));\n              }}\n            >\n              {pageSizeOptions.map((pageSize) => (\n                <option key={pageSize} value={pageSize}>\n                  {pageSize}\n                </option>\n              ))}\n            </select>\n            <Button\n              size=\"sm\"\n              variant=\"outline\"\n              disabled={!table.getCanPreviousPage()}\n              onClick={() => {\n                table.previousPage();\n              }}\n            >\n              {mergedLabels.previousPage}\n            </Button>\n            <Button\n              size=\"sm\"\n              variant=\"outline\"\n              disabled={!table.getCanNextPage()}\n              onClick={() => {\n                table.nextPage();\n              }}\n            >\n              {mergedLabels.nextPage}\n            </Button>\n          </div>\n        </div>\n      ) : null}\n    </div>\n  );\n}\n"
    },
    {
      "path": "packages/components/src/components/data-table/index.ts",
      "type": "registry:file",
      "target": "~/components/dethink/components/data-table/index.ts",
      "content": "export {\n  DataTable,\n  dataTableClassNames,\n  dataTableEmptyClassNames,\n  dataTablePaginationClassNames,\n  dataTableSortButtonClassNames,\n  dataTableSortIndicatorClassNames,\n  dataTableToolbarClassNames,\n  type DataTableCell,\n  type DataTableColumn,\n  type DataTableColumnFiltersState,\n  type DataTableColumnDef,\n  type DataTableDensity,\n  type DataTableHeader,\n  type DataTableLabels,\n  type DataTablePaginationState,\n  type DataTableProps,\n  type DataTableRow,\n  type DataTableRowSelectionState,\n  type DataTableSelectionMode,\n  type DataTableSortingState,\n  type DataTableVisibilityState,\n} from \"./data-table\";\n"
    },
    {
      "path": "packages/components/src/utils/cn.ts",
      "type": "registry:file",
      "target": "~/components/dethink/utils/cn.ts",
      "content": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n"
    }
  ]
}
