{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "data-table-core",
  "title": "Data Table Core",
  "author": "Poyraz Avsever",
  "description": "Poyraz Soft Glass data-table-core with semantic states and composable variants.",
  "dependencies": [
    "lucide-react@^0.574.0"
  ],
  "registryDependencies": [
    "@poyraz/poyraz-utils",
    "@poyraz/poyraz-theme",
    "@poyraz/checkbox"
  ],
  "files": [
    {
      "path": "registry/poyraz/ui/phase7/organisms/data-table-core.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { ArrowDown, ArrowUp, ArrowUpDown } from \"lucide-react\";\n\nimport { Checkbox } from \"@/components/ui/atoms/checkbox\";\nimport { cn } from \"@/lib/utils\";\n\nexport type SortDirection = \"asc\" | \"desc\" | null;\nexport type DataTableState = \"populated\" | \"empty\" | \"loading\" | \"error\";\n\nexport interface DataTableColumnDef<T> {\n  id: string;\n  header: string;\n  accessorFn?: (row: T) => unknown;\n  accessorKey?: keyof T;\n  cell?: (row: T) => React.ReactNode;\n  sortable?: boolean;\n  filterable?: boolean;\n  className?: string;\n  hidden?: boolean;\n}\n\nexport function getDataTableCellValue<T>(row: T, column: DataTableColumnDef<T>): unknown {\n  if (column.accessorFn) return column.accessorFn(row);\n  if (column.accessorKey) return (row as Record<string, unknown>)[column.accessorKey as string];\n  return (row as Record<string, unknown>)[column.id];\n}\n\nexport function stringifyDataTableValue(value: unknown): string {\n  if (value == null) return \"\";\n  if ([\"string\", \"number\", \"boolean\"].includes(typeof value)) return String(value);\n  return JSON.stringify(value);\n}\n\nexport interface DataTableCoreProps<T> extends Omit<\n  React.HTMLAttributes<HTMLDivElement>,\n  \"children\"\n> {\n  columns: DataTableColumnDef<T>[];\n  data: T[];\n  getRowId?: (row: T, index: number) => string;\n  state?: DataTableState;\n  emptyContent?: React.ReactNode;\n  errorContent?: React.ReactNode;\n  loadingRows?: number;\n  selectable?: boolean;\n  selectedIds?: ReadonlySet<string>;\n  onToggleRow?: (id: string, row: T) => void;\n  onToggleAll?: () => void;\n  sortColumn?: string | null;\n  sortDirection?: SortDirection;\n  onSort?: (columnId: string) => void;\n  caption?: string;\n  stickyHeader?: boolean;\n  density?: \"compact\" | \"default\" | \"spacious\";\n  surface?: \"solid\" | \"soft\" | \"glass\";\n  radius?: \"none\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\n  maxHeight?: string | number;\n}\n\nfunction DataTableCoreInner<T>(\n  {\n    caption,\n    className,\n    columns,\n    data,\n    density = \"default\",\n    emptyContent = \"No results found.\",\n    errorContent = \"Unable to load data.\",\n    getRowId,\n    loadingRows = 5,\n    maxHeight,\n    onSort,\n    onToggleAll,\n    onToggleRow,\n    radius = \"lg\",\n    selectable = false,\n    selectedIds = new Set<string>(),\n    sortColumn,\n    sortDirection,\n    state = data.length ? \"populated\" : \"empty\",\n    stickyHeader = false,\n    surface = \"solid\",\n    style,\n    ...props\n  }: DataTableCoreProps<T>,\n  ref: React.ForwardedRef<HTMLDivElement>,\n) {\n  const rowId = (row: T, index: number) => getRowId?.(row, index) ?? String(index);\n  const allSelected =\n    data.length > 0 && data.every((row, index) => selectedIds.has(rowId(row, index)));\n  const padding =\n    density === \"compact\" ? \"px-2.5 py-2\" : density === \"spacious\" ? \"px-4 py-3.5\" : \"px-3 py-2.5\";\n\n  return (\n    <div\n      ref={ref}\n      data-slot=\"data-table-core\"\n      data-state={state}\n      data-surface={surface}\n      className={cn(\n        \"relative w-full overflow-auto border\",\n        surface === \"solid\" && \"border-border bg-surface\",\n        surface === \"soft\" && \"border-transparent bg-surface-subtle\",\n        surface === \"glass\" && \"border-glass-border-outer bg-glass shadow-md backdrop-blur-glass\",\n        radius === \"none\" && \"rounded-none\",\n        radius === \"sm\" && \"rounded-sm\",\n        radius === \"md\" && \"rounded-md\",\n        radius === \"lg\" && \"rounded-lg\",\n        radius === \"xl\" && \"rounded-xl\",\n        className,\n      )}\n      style={{ maxHeight, ...style }}\n      {...props}\n    >\n      <table className=\"w-full min-w-max border-separate border-spacing-0 text-sm\">\n        {caption && <caption className=\"sr-only\">{caption}</caption>}\n        <thead className={cn(stickyHeader && \"sticky top-0 z-10\")}>\n          <tr className=\"bg-surface-subtle/95 backdrop-blur-md\">\n            {selectable && (\n              <th className={cn(\"w-12 border-b border-border text-center\", padding)}>\n                <Checkbox\n                  checked={allSelected}\n                  onCheckedChange={onToggleAll}\n                  aria-label=\"Select all rows\"\n                />\n              </th>\n            )}\n            {columns.map((column) => {\n              const sortable = column.sortable !== false && Boolean(onSort);\n              const active = sortColumn === column.id;\n              const ariaSort = active\n                ? sortDirection === \"asc\"\n                  ? \"ascending\"\n                  : \"descending\"\n                : \"none\";\n              return (\n                <th\n                  key={column.id}\n                  scope=\"col\"\n                  aria-sort={sortable ? ariaSort : undefined}\n                  className={cn(\n                    \"border-b border-border text-left text-[11px] font-semibold uppercase tracking-wider text-muted-foreground\",\n                    padding,\n                    column.className,\n                  )}\n                >\n                  <button\n                    type=\"button\"\n                    disabled={!sortable}\n                    onClick={() => onSort?.(column.id)}\n                    className={cn(\n                      \"inline-flex items-center gap-1.5 whitespace-nowrap outline-none transition-colors\",\n                      sortable\n                        ? \"cursor-pointer hover:text-foreground focus-visible:text-foreground\"\n                        : \"cursor-default\",\n                    )}\n                  >\n                    {column.header}\n                    {sortable &&\n                      (active && sortDirection === \"asc\" ? (\n                        <ArrowUp className=\"size-3.5 text-primary animate-poyraz-scale-in\" />\n                      ) : active && sortDirection === \"desc\" ? (\n                        <ArrowDown className=\"size-3.5 text-primary animate-poyraz-scale-in\" />\n                      ) : (\n                        <ArrowUpDown className=\"size-3.5 opacity-45\" />\n                      ))}\n                  </button>\n                </th>\n              );\n            })}\n          </tr>\n        </thead>\n        <tbody>\n          {state === \"loading\" &&\n            Array.from({ length: loadingRows }, (_, rowIndex) => (\n              <tr key={`loading-${rowIndex}`} aria-hidden=\"true\" className=\"animate-poyraz-fade-in\">\n                {selectable && (\n                  <td className={cn(\"border-b border-border/70\", padding)}>\n                    <div className=\"mx-auto size-4 animate-pulse rounded bg-muted\" />\n                  </td>\n                )}\n                {columns.map((column) => (\n                  <td key={column.id} className={cn(\"border-b border-border/70\", padding)}>\n                    <div className=\"h-3.5 w-24 max-w-full animate-pulse rounded bg-muted\" />\n                  </td>\n                ))}\n              </tr>\n            ))}\n          {state === \"error\" && (\n            <tr>\n              <td\n                colSpan={columns.length + (selectable ? 1 : 0)}\n                className=\"p-10 text-center text-sm text-destructive-muted-foreground animate-poyraz-fade-in\"\n                role=\"alert\"\n              >\n                {errorContent}\n              </td>\n            </tr>\n          )}\n          {state === \"empty\" && (\n            <tr>\n              <td\n                colSpan={columns.length + (selectable ? 1 : 0)}\n                className=\"p-10 text-center text-sm text-muted-foreground animate-poyraz-fade-in\"\n              >\n                {emptyContent}\n              </td>\n            </tr>\n          )}\n          {state === \"populated\" &&\n            data.map((row, index) => {\n              const id = rowId(row, index);\n              const selected = selectedIds.has(id);\n              return (\n                <tr\n                  key={id}\n                  data-state={selected ? \"selected\" : undefined}\n                  className=\"transition-colors hover:bg-accent/55 data-[state=selected]:bg-primary-muted/55\"\n                >\n                  {selectable && (\n                    <td className={cn(\"border-b border-border/70 text-center\", padding)}>\n                      <Checkbox\n                        checked={selected}\n                        onCheckedChange={() => onToggleRow?.(id, row)}\n                        aria-label={`Select row ${index + 1}`}\n                      />\n                    </td>\n                  )}\n                  {columns.map((column) => (\n                    <td\n                      key={column.id}\n                      className={cn(\n                        \"border-b border-border/70 text-secondary-foreground\",\n                        padding,\n                        column.className,\n                      )}\n                    >\n                      {column.cell\n                        ? column.cell(row)\n                        : stringifyDataTableValue(getDataTableCellValue(row, column))}\n                    </td>\n                  ))}\n                </tr>\n              );\n            })}\n        </tbody>\n      </table>\n    </div>\n  );\n}\n\nconst DataTableCore = React.forwardRef(DataTableCoreInner) as <T>(\n  props: DataTableCoreProps<T> & { ref?: React.Ref<HTMLDivElement> },\n) => React.ReactElement;\n\nexport { DataTableCore };\n",
      "type": "registry:ui",
      "target": "@ui/organisms/data-table-core.tsx"
    }
  ],
  "meta": {
    "category": "phase-7-composite",
    "phase": "beta"
  },
  "type": "registry:ui"
}