{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "table",
  "title": "Table",
  "description": "Rows of data with a header, footer and caption, divided by faint edges.",
  "dependencies": [
    "@stylexjs/stylex"
  ],
  "registryDependencies": [
    "https://constella.aayush.cv/r/base.json",
    "https://constella.aayush.cv/r/scroll-fade.json"
  ],
  "files": [
    {
      "path": "src/components/primitives/table.tsx",
      "content": "\"use client\";\n\nimport * as stylex from \"@stylexjs/stylex\";\nimport { createContext, use } from \"react\";\nimport type { ComponentProps } from \"react\";\n\nimport { scrollFade } from \"@/lib/constella/scroll-fade\";\nimport type { Sx } from \"@/lib/constella/styles\";\nimport { typeStyles } from \"@/lib/constella/styles\";\nimport { tableVars } from \"@/lib/constella/table.stylex\";\nimport {\n  colors,\n  durations,\n  fontWeights,\n  media,\n  sizes,\n  space,\n  strokes,\n} from \"@/lib/constella/tokens.stylex\";\n\nconst tableSizes = [\"sm\", \"default\"] as const;\n\ntype TableSize = (typeof tableSizes)[number];\n\ntype Styled<T> = Omit<T, \"className\" | \"style\"> & {\n  sx?: Sx;\n};\n\ntype TableProps = Styled<ComponentProps<\"table\">> & {\n  interactive?: boolean;\n  size?: TableSize;\n};\n\nconst marked = \":is([data-state='selected'], [aria-current='true'])\";\nconst open = \"[aria-current='true']\";\nconst checked = \"[data-state='selected']\";\nconst idle = \":not([data-state='selected'], [aria-current='true'])\";\n// As in the sidebar: an inset shadow, not a second fill, so hover stacks on a marked row's fill and still fades.\nconst lit = `inset 0 0 0 100vmax ${colors.fillSubtle}`;\nconst unlit = \"inset 0 0 0 100vmax transparent\";\nconst lastRow = \":is(tbody > :last-child > *, tfoot > :last-child > *)\";\n// A cell holding a checkbox hugs it, so the column stays as narrow as the box.\nconst checkbox = \":has([data-slot='checkbox'])\";\n\nconst styles = stylex.create({\n  container: {\n    overflowX: \"auto\",\n    position: \"relative\",\n    scrollbarWidth: \"none\",\n    width: \"100%\",\n  },\n  // Separate, so the cells draw the dividers: collapsed, Chrome hides them under a selected row's fill in a cell that clips.\n  table: {\n    borderCollapse: \"separate\",\n    borderSpacing: 0,\n    captionSide: \"bottom\",\n    color: colors.textPrimary,\n    fontVariantNumeric: \"tabular-nums\",\n    width: \"100%\",\n  },\n  footer: {\n    backgroundColor: colors.fillSubtle,\n    fontWeight: fontWeights.medium,\n  },\n  // Rows are divided by the faint edge; the last row of a body or footer needs none.\n  divider: {\n    borderBlockEndColor: colors.borderSubtle,\n    borderBlockEndStyle: \"solid\",\n    borderBlockEndWidth: { default: strokes.border, [lastRow]: 0 },\n  },\n  row: {\n    backgroundColor: {\n      default: \"transparent\",\n      [media.hover]: {\n        default: \"transparent\",\n        [`:hover${idle}`]: colors.fillSubtle,\n        [checked]: colors.fill,\n        [open]: colors.fillStrong,\n      },\n      [`:has([aria-expanded='true'])${idle}`]: colors.fillSubtle,\n      [`:active${idle}`]: colors.fillSubtle,\n      [checked]: colors.fill,\n      // One row at a time, so it can stand a step above the checked ones.\n      [open]: colors.fillStrong,\n    },\n    boxShadow: {\n      default: null,\n      [marked]: {\n        default: unlit,\n        [media.hover]: { default: unlit, \":hover\": lit },\n        \":has([aria-expanded='true'])\": lit,\n      },\n    },\n    // A row selected from the keyboard fills at once.\n    transitionDuration: { default: durations.hover, \":focus-visible\": \"0s\" },\n    transitionProperty: \"background-color, box-shadow\",\n    transitionTimingFunction: \"ease\",\n  },\n  // Reference tables a reader only reads: rows keep their marked fills but don't answer the pointer.\n  rowStatic: {\n    backgroundColor: {\n      default: \"transparent\",\n      [checked]: colors.fill,\n      [open]: colors.fillStrong,\n    },\n    boxShadow: null,\n  },\n  head: {\n    color: colors.textSecondary,\n    fontWeight: fontWeights.regular,\n    height: `calc(${sizes.controlLg} + ${space.xxs})`,\n    paddingBlock: 0,\n    paddingInlineEnd: {\n      default: space.sm,\n      [checkbox]: 0,\n      \":last-child\": tableVars.inset,\n    },\n    paddingInlineStart: { default: space.sm, \":first-child\": tableVars.inset },\n    textAlign: \"start\",\n    verticalAlign: \"middle\",\n    whiteSpace: \"nowrap\",\n  },\n  cell: {\n    // The footer's top edge; a row group can't draw a border in the separate model.\n    borderBlockStartColor: colors.borderSubtle,\n    borderBlockStartStyle: \"solid\",\n    borderBlockStartWidth: {\n      default: 0,\n      \":is(tfoot > :first-child > *)\": strokes.border,\n    },\n    paddingBlock: space.xs,\n    paddingInlineEnd: {\n      default: space.sm,\n      [checkbox]: 0,\n      \":last-child\": tableVars.inset,\n    },\n    paddingInlineStart: { default: space.sm, \":first-child\": tableVars.inset },\n    verticalAlign: \"middle\",\n    whiteSpace: \"nowrap\",\n  },\n  // Dense rows for data a reader scans, like logs and usage.\n  headSm: {\n    height: sizes.controlMd,\n  },\n  cellSm: {\n    paddingBlock: space.xxs,\n  },\n  caption: {\n    color: colors.textMuted,\n    marginBlockStart: space.md,\n  },\n});\n\nconst TableSizeContext = createContext<TableSize>(\"default\");\nconst TableInteractiveContext = createContext(true);\n\nfunction Table({\n  interactive = true,\n  size = \"default\",\n  sx,\n  ...props\n}: TableProps) {\n  return (\n    <TableInteractiveContext value={interactive}>\n      <TableSizeContext value={size}>\n        <div\n          data-slot=\"table-container\"\n          {...stylex.props(styles.container, scrollFade.x)}\n        >\n          <table\n            data-size={size}\n            data-slot=\"table\"\n            {...props}\n            {...stylex.props([typeStyles.textMd, styles.table], sx)}\n          />\n        </div>\n      </TableSizeContext>\n    </TableInteractiveContext>\n  );\n}\n\nfunction TableHeader({ sx, ...props }: Styled<ComponentProps<\"thead\">>) {\n  return <thead data-slot=\"table-header\" {...props} {...stylex.props(sx)} />;\n}\n\nfunction TableBody({ sx, ...props }: Styled<ComponentProps<\"tbody\">>) {\n  return <tbody data-slot=\"table-body\" {...props} {...stylex.props(sx)} />;\n}\n\nfunction TableFooter({ sx, ...props }: Styled<ComponentProps<\"tfoot\">>) {\n  return (\n    <tfoot\n      data-slot=\"table-footer\"\n      {...props}\n      {...stylex.props(styles.footer, sx)}\n    />\n  );\n}\n\nfunction TableRow({ sx, ...props }: Styled<ComponentProps<\"tr\">>) {\n  const interactive = use(TableInteractiveContext);\n  return (\n    <tr\n      data-slot=\"table-row\"\n      {...props}\n      {...stylex.props(styles.row, !interactive && styles.rowStatic, sx)}\n    />\n  );\n}\n\nfunction TableHead({ sx, ...props }: Styled<ComponentProps<\"th\">>) {\n  const size = use(TableSizeContext);\n  return (\n    <th\n      data-slot=\"table-head\"\n      {...props}\n      {...stylex.props(\n        styles.divider,\n        styles.head,\n        size === \"sm\" && styles.headSm,\n        sx\n      )}\n    />\n  );\n}\n\nfunction TableCell({ sx, ...props }: Styled<ComponentProps<\"td\">>) {\n  const size = use(TableSizeContext);\n  return (\n    <td\n      data-slot=\"table-cell\"\n      {...props}\n      {...stylex.props(\n        styles.divider,\n        styles.cell,\n        size === \"sm\" && styles.cellSm,\n        sx\n      )}\n    />\n  );\n}\n\nfunction TableCaption({ sx, ...props }: Styled<ComponentProps<\"caption\">>) {\n  return (\n    <caption\n      data-slot=\"table-caption\"\n      {...props}\n      {...stylex.props([typeStyles.textSm, styles.caption], sx)}\n    />\n  );\n}\n\nexport {\n  Table,\n  TableBody,\n  TableCaption,\n  TableCell,\n  TableFooter,\n  TableHead,\n  TableHeader,\n  TableRow,\n  tableSizes,\n};\nexport type { TableProps, TableSize };\n",
      "type": "registry:component"
    },
    {
      "path": "src/lib/constella/table.stylex.ts",
      "content": "import * as stylex from \"@stylexjs/stylex\";\n\nimport { space } from \"./tokens.stylex\";\n\n// How far a row's first and last cells keep their content from the table's edges.\nexport const tableVars = stylex.defineVars({\n  inset: space.sm,\n});\n",
      "type": "registry:lib"
    }
  ],
  "docs": "Usage: https://constella.aayush.cv/docs/components/table/index.md",
  "type": "registry:ui"
}