{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "table-selection",
  "title": "Selection table",
  "description": "Styled table: the Selection set. 5 decorative table variations (CheckboxTable, RadioTable, RowTable, AllTable, HighlightTable) on the ai2 token system, driven by CSS token transitions and sized sm to xl. Part of the free styled layer.",
  "dependencies": [],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/table-selection.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Selection table family: 5 tables with real working row selection. The selection\n   state is held in React state and the rows are GENUINELY marked: checkbox, radio\n   (single select), row click, select-all (an indeterminate header) and a highlighted\n   selection. The boxes have sr-only labels and the ids are produced with\n   React.useId(). Controls under 24px gain a touch area with after:-inset-1.5. Color\n   comes ONLY from semantic tokens, via alpha color-mix. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\ntype Column = { key: string; label: React.ReactNode }\ntype Row = Record<string, React.ReactNode>\n\ntype TableProps = {\n  className?: string\n  size?: StyledSize\n  columns?: Column[]\n  rows?: Row[]\n}\n\n/* A sensible default data set so it renders without props. */\nconst defaultColumns: Column[] = [\n  { key: \"name\", label: \"Name\" },\n  { key: \"role\", label: \"Role\" },\n  { key: \"status\", label: \"Status\" },\n]\n\nconst defaultRows: Row[] = [\n  { name: \"Ada Lovelace\", role: \"Engineer\", status: \"Active\" },\n  { name: \"Alan Turing\", role: \"Researcher\", status: \"Active\" },\n  { name: \"Grace Hopper\", role: \"Architect\", status: \"Away\" },\n  { name: \"Katherine Johnson\", role: \"Analyst\", status: \"Active\" },\n]\n\n/* Hucre yogunlugu: padding + metin olcegi. */\nconst cell: Record<StyledSize, string> = {\n  sm: \"px-2.5 py-1.5 text-xs\",\n  md: \"px-3 py-2 text-sm\",\n  lg: \"px-4 py-2.5 text-sm\",\n  xl: \"px-5 py-3 text-base\",\n}\n\nconst headCell: Record<StyledSize, string> = {\n  sm: \"px-2.5 py-1.5 text-xs\",\n  md: \"px-3 py-2 text-xs\",\n  lg: \"px-4 py-2.5 text-sm\",\n  xl: \"px-5 py-3 text-sm\",\n}\n\nconst tableBase = \"w-full border-collapse text-left align-middle text-foreground\"\nconst headBase = \"font-medium text-muted-foreground\"\n\n/* An invisible touch-area extension for controls that stay under 24px. */\nconst control =\n  \"relative size-4 shrink-0 cursor-pointer accent-primary outline-none after:absolute after:-inset-1.5 after:content-[''] focus-visible:ring-[3px] focus-visible:ring-ring/50\"\n\nfunction resolve(columns?: Column[], rows?: Row[]) {\n  return {\n    cols: columns && columns.length > 0 ? columns : defaultColumns,\n    data: rows && rows.length > 0 ? rows : defaultRows,\n  }\n}\n\n/* Satir etiketi: ilk kolonun metni, degilse sira numarasi. */\nfunction rowLabel(row: Row, cols: Column[], i: number): string {\n  const v = row[cols[0]?.key ?? \"\"]\n  if (typeof v === \"string\") return v\n  if (typeof v === \"number\") return String(v)\n  return `row ${i + 1}`\n}\n\n/* Cok secimli durum: indeksler uzerinden Set. */\nfunction useMultiSelection() {\n  const [selected, setSelected] = React.useState<ReadonlySet<number>>(() => new Set<number>())\n  const toggle = React.useCallback((i: number) => {\n    setSelected((prev) => {\n      const next = new Set(prev)\n      if (next.has(i)) next.delete(i)\n      else next.add(i)\n      return next\n    })\n  }, [])\n  const setAll = React.useCallback((indices: number[]) => {\n    setSelected(new Set(indices))\n  }, [])\n  return { selected, toggle, setAll }\n}\n\n/* Checkbox: an independent checkbox column on every row. */\nexport function CheckboxTable({ className, size = \"md\", columns, rows }: TableProps) {\n  const { cols, data } = resolve(columns, rows)\n  const { selected, toggle } = useMultiSelection()\n  const uid = React.useId()\n\n  return (\n    <div\n      data-slot=\"styled-table\"\n      className={cn(\"w-full overflow-x-auto rounded-lg border border-border\", className)}\n    >\n      <table className={tableBase}>\n        <thead>\n          <tr className=\"border-b border-border bg-muted\">\n            <th scope=\"col\" className={cn(headBase, headCell[size], \"w-10\")}>\n              <span className=\"sr-only\">Select</span>\n            </th>\n            {cols.map((col) => (\n              <th key={col.key} scope=\"col\" className={cn(headBase, headCell[size])}>\n                {col.label}\n              </th>\n            ))}\n          </tr>\n        </thead>\n        <tbody>\n          {data.map((row, i) => {\n            const on = selected.has(i)\n            return (\n              <tr\n                key={i}\n                data-state={on ? \"selected\" : undefined}\n                className={cn(\n                  \"border-b border-border/60 transition-colors duration-(--motion-fast) ease-(--motion-ease) last:border-b-0\",\n                  on && \"bg-[color-mix(in_oklab,var(--color-primary)_10%,transparent)]\"\n                )}\n              >\n                <td className={cell[size]}>\n                  <input\n                    type=\"checkbox\"\n                    id={`${uid}-cb-${i}`}\n                    className={control}\n                    checked={on}\n                    onChange={() => toggle(i)}\n                  />\n                  <label htmlFor={`${uid}-cb-${i}`} className=\"sr-only\">\n                    {`Select ${rowLabel(row, cols, i)}`}\n                  </label>\n                </td>\n                {cols.map((col) => (\n                  <td key={col.key} className={cell[size]}>\n                    {row[col.key]}\n                  </td>\n                ))}\n              </tr>\n            )\n          })}\n        </tbody>\n      </table>\n    </div>\n  )\n}\n\n/* Radio: one row can be selected, and the radio group covers the whole table. */\nexport function RadioTable({ className, size = \"md\", columns, rows }: TableProps) {\n  const { cols, data } = resolve(columns, rows)\n  const [selected, setSelected] = React.useState<number | null>(null)\n  const uid = React.useId()\n\n  return (\n    <div\n      data-slot=\"styled-table\"\n      className={cn(\"w-full overflow-x-auto rounded-lg border border-border\", className)}\n    >\n      <table className={tableBase}>\n        <thead>\n          <tr className=\"border-b border-border bg-muted\">\n            <th scope=\"col\" className={cn(headBase, headCell[size], \"w-10\")}>\n              <span className=\"sr-only\">Choose</span>\n            </th>\n            {cols.map((col) => (\n              <th key={col.key} scope=\"col\" className={cn(headBase, headCell[size])}>\n                {col.label}\n              </th>\n            ))}\n          </tr>\n        </thead>\n        <tbody>\n          {data.map((row, i) => {\n            const on = selected === i\n            return (\n              <tr\n                key={i}\n                data-state={on ? \"selected\" : undefined}\n                className={cn(\n                  \"border-b border-border/60 transition-colors duration-(--motion-fast) ease-(--motion-ease) last:border-b-0\",\n                  on && \"bg-[color-mix(in_oklab,var(--color-primary)_10%,transparent)]\"\n                )}\n              >\n                <td className={cell[size]}>\n                  <input\n                    type=\"radio\"\n                    name={`${uid}-radio`}\n                    id={`${uid}-rd-${i}`}\n                    className={control}\n                    checked={on}\n                    onChange={() => setSelected(i)}\n                  />\n                  <label htmlFor={`${uid}-rd-${i}`} className=\"sr-only\">\n                    {`Choose ${rowLabel(row, cols, i)}`}\n                  </label>\n                </td>\n                {cols.map((col) => (\n                  <td key={col.key} className={cell[size]}>\n                    {row[col.key]}\n                  </td>\n                ))}\n              </tr>\n            )\n          })}\n        </tbody>\n      </table>\n    </div>\n  )\n}\n\n/* Row: clicking anywhere in the row changes the selection. */\nexport function RowTable({ className, size = \"md\", columns, rows }: TableProps) {\n  const { cols, data } = resolve(columns, rows)\n  const { selected, toggle } = useMultiSelection()\n  const uid = React.useId()\n\n  return (\n    <div\n      data-slot=\"styled-table\"\n      className={cn(\"w-full overflow-x-auto rounded-lg border border-border\", className)}\n    >\n      <table className={tableBase}>\n        <thead>\n          <tr className=\"border-b border-border bg-muted\">\n            <th scope=\"col\" className={cn(headBase, headCell[size], \"w-10\")}>\n              <span className=\"sr-only\">Select</span>\n            </th>\n            {cols.map((col) => (\n              <th key={col.key} scope=\"col\" className={cn(headBase, headCell[size])}>\n                {col.label}\n              </th>\n            ))}\n          </tr>\n        </thead>\n        <tbody>\n          {data.map((row, i) => {\n            const on = selected.has(i)\n            return (\n              <tr\n                key={i}\n                data-state={on ? \"selected\" : undefined}\n                onClick={() => toggle(i)}\n                className={cn(\n                  \"cursor-pointer border-b border-border/60 transition-colors duration-(--motion-fast) ease-(--motion-ease) last:border-b-0 hover:bg-[color-mix(in_oklab,var(--color-foreground)_5%,transparent)]\",\n                  on && \"bg-[color-mix(in_oklab,var(--color-primary)_12%,transparent)]\"\n                )}\n              >\n                <td className={cell[size]}>\n                  <input\n                    type=\"checkbox\"\n                    id={`${uid}-row-${i}`}\n                    className={control}\n                    checked={on}\n                    onChange={() => toggle(i)}\n                    onClick={(e) => e.stopPropagation()}\n                  />\n                  <label htmlFor={`${uid}-row-${i}`} className=\"sr-only\">\n                    {`Select ${rowLabel(row, cols, i)}`}\n                  </label>\n                </td>\n                {cols.map((col) => (\n                  <td key={col.key} className={cell[size]}>\n                    {row[col.key]}\n                  </td>\n                ))}\n              </tr>\n            )\n          })}\n        </tbody>\n      </table>\n    </div>\n  )\n}\n\n/* All: baslikta tumunu sec kutucugu, kismi secimde indeterminate gorunur. */\nexport function AllTable({ className, size = \"md\", columns, rows }: TableProps) {\n  const { cols, data } = resolve(columns, rows)\n  const { selected, toggle, setAll } = useMultiSelection()\n  const uid = React.useId()\n  const allRef = React.useRef<HTMLInputElement>(null)\n\n  const count = selected.size\n  const all = count === data.length && data.length > 0\n  const some = count > 0 && !all\n\n  React.useEffect(() => {\n    if (allRef.current) allRef.current.indeterminate = some\n  }, [some])\n\n  return (\n    <div\n      data-slot=\"styled-table\"\n      className={cn(\"w-full overflow-x-auto rounded-lg border border-border\", className)}\n    >\n      <table className={tableBase}>\n        <thead>\n          <tr className=\"border-b border-border bg-muted\">\n            <th scope=\"col\" className={cn(headBase, headCell[size], \"w-10\")}>\n              <input\n                ref={allRef}\n                type=\"checkbox\"\n                id={`${uid}-all`}\n                className={control}\n                checked={all}\n                onChange={() => setAll(all ? [] : data.map((_, i) => i))}\n              />\n              <label htmlFor={`${uid}-all`} className=\"sr-only\">\n                Select all rows\n              </label>\n            </th>\n            {cols.map((col) => (\n              <th key={col.key} scope=\"col\" className={cn(headBase, headCell[size])}>\n                {col.label}\n              </th>\n            ))}\n          </tr>\n        </thead>\n        <tbody>\n          {data.map((row, i) => {\n            const on = selected.has(i)\n            return (\n              <tr\n                key={i}\n                data-state={on ? \"selected\" : undefined}\n                className={cn(\n                  \"border-b border-border/60 transition-colors duration-(--motion-fast) ease-(--motion-ease) last:border-b-0\",\n                  on && \"bg-[color-mix(in_oklab,var(--color-primary)_10%,transparent)]\"\n                )}\n              >\n                <td className={cell[size]}>\n                  <input\n                    type=\"checkbox\"\n                    id={`${uid}-all-cb-${i}`}\n                    className={control}\n                    checked={on}\n                    onChange={() => toggle(i)}\n                  />\n                  <label htmlFor={`${uid}-all-cb-${i}`} className=\"sr-only\">\n                    {`Select ${rowLabel(row, cols, i)}`}\n                  </label>\n                </td>\n                {cols.map((col) => (\n                  <td key={col.key} className={cell[size]}>\n                    {row[col.key]}\n                  </td>\n                ))}\n              </tr>\n            )\n          })}\n        </tbody>\n      </table>\n    </div>\n  )\n}\n\n/* Highlight: the selected row takes a primary tint plus a pronounced strip on its left edge. */\nexport function HighlightTable({ className, size = \"md\", columns, rows }: TableProps) {\n  const { cols, data } = resolve(columns, rows)\n  const { selected, toggle } = useMultiSelection()\n  const uid = React.useId()\n\n  return (\n    <div\n      data-slot=\"styled-table\"\n      className={cn(\"w-full overflow-x-auto rounded-lg border border-border\", className)}\n    >\n      <table className={tableBase}>\n        <thead>\n          <tr className=\"border-b border-border bg-muted\">\n            <th scope=\"col\" className={cn(headBase, headCell[size], \"w-10\")}>\n              <span className=\"sr-only\">Select</span>\n            </th>\n            {cols.map((col) => (\n              <th key={col.key} scope=\"col\" className={cn(headBase, headCell[size])}>\n                {col.label}\n              </th>\n            ))}\n          </tr>\n        </thead>\n        <tbody>\n          {data.map((row, i) => {\n            const on = selected.has(i)\n            return (\n              <tr\n                key={i}\n                data-state={on ? \"selected\" : undefined}\n                className={cn(\n                  \"border-b border-border/60 transition-colors duration-(--motion-fast) ease-(--motion-ease) last:border-b-0\",\n                  on &&\n                    \"bg-[color-mix(in_oklab,var(--color-primary)_16%,transparent)] font-medium text-foreground\"\n                )}\n              >\n                <td\n                  className={cn(\n                    cell[size],\n                    \"relative\",\n                    on && \"before:absolute before:inset-y-0 before:left-0 before:w-0.5 before:bg-primary\"\n                  )}\n                >\n                  <input\n                    type=\"checkbox\"\n                    id={`${uid}-hl-${i}`}\n                    className={control}\n                    checked={on}\n                    onChange={() => toggle(i)}\n                  />\n                  <label htmlFor={`${uid}-hl-${i}`} className=\"sr-only\">\n                    {`Select ${rowLabel(row, cols, i)}`}\n                  </label>\n                </td>\n                {cols.map((col) => (\n                  <td key={col.key} className={cell[size]}>\n                    {row[col.key]}\n                  </td>\n                ))}\n              </tr>\n            )\n          })}\n        </tbody>\n      </table>\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/table-selection.tsx"
    }
  ],
  "categories": [
    "styled",
    "table"
  ],
  "type": "registry:component"
}