@exitvibing/hqui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/setup.md ADDED
@@ -0,0 +1,146 @@
1
+ # Setup
2
+
3
+ ## Install
4
+
5
+ ```bash
6
+ bun add hqui
7
+ ```
8
+
9
+ **Peer dependencies** (install if not already in your project):
10
+
11
+ ```bash
12
+ bun add react react-dom
13
+ bun add -d tailwindcss@3 postcss autoprefixer
14
+ ```
15
+
16
+ ## Import CSS
17
+
18
+ In your app entry file (e.g. `main.tsx`):
19
+
20
+ ```tsx
21
+ import "hqui/dist/index.css";
22
+ ```
23
+
24
+ This is required. It provides CSS variables for colors, theme support, and base styles.
25
+
26
+ ## Tailwind Config
27
+
28
+ Create `tailwind.config.ts`:
29
+
30
+ ```ts
31
+ import type { Config } from "tailwindcss";
32
+
33
+ const config: Config = {
34
+ darkMode: ["class"],
35
+ content: ["./src/**/*.{ts,tsx}", "./node_modules/hqui/dist/**/*.{js,mjs}"],
36
+ theme: {
37
+ extend: {
38
+ colors: {
39
+ background: "hsl(var(--background))",
40
+ foreground: "hsl(var(--foreground))",
41
+ primary: {
42
+ DEFAULT: "hsl(var(--primary))",
43
+ foreground: "hsl(var(--primary-foreground))",
44
+ },
45
+ secondary: {
46
+ DEFAULT: "hsl(var(--secondary))",
47
+ foreground: "hsl(var(--secondary-foreground))",
48
+ },
49
+ muted: {
50
+ DEFAULT: "hsl(var(--muted))",
51
+ foreground: "hsl(var(--muted-foreground))",
52
+ },
53
+ accent: {
54
+ DEFAULT: "hsl(var(--accent))",
55
+ foreground: "hsl(var(--accent-foreground))",
56
+ },
57
+ destructive: {
58
+ DEFAULT: "hsl(var(--destructive))",
59
+ foreground: "hsl(var(--destructive-foreground))",
60
+ },
61
+ border: "hsl(var(--border))",
62
+ input: "hsl(var(--input))",
63
+ ring: "hsl(var(--ring))",
64
+ card: {
65
+ DEFAULT: "hsl(var(--card))",
66
+ foreground: "hsl(var(--card-foreground))",
67
+ },
68
+ },
69
+ borderRadius: {
70
+ lg: "var(--radius)",
71
+ md: "calc(var(--radius) - 2px)",
72
+ sm: "calc(var(--radius) - 4px)",
73
+ },
74
+ },
75
+ },
76
+ plugins: [],
77
+ };
78
+
79
+ export default config;
80
+ ```
81
+
82
+ ## PostCSS Config
83
+
84
+ Create `postcss.config.js`:
85
+
86
+ ```js
87
+ export default {
88
+ plugins: {
89
+ tailwindcss: {},
90
+ autoprefixer: {},
91
+ },
92
+ };
93
+ ```
94
+
95
+ ## Entry CSS
96
+
97
+ Your app's CSS file should start with:
98
+
99
+ ```css
100
+ @tailwind base;
101
+ @tailwind components;
102
+ @tailwind utilities;
103
+ ```
104
+
105
+ ## Dark Mode
106
+
107
+ Add `class="dark"` to `<html>` for dark mode. Or use the `ThemeToggle` component.
108
+
109
+ ```html
110
+ <html class="dark"></html>
111
+ ```
112
+
113
+ ## Vite Config (if needed)
114
+
115
+ If hqui is linked locally (e.g. monorepo), add dedupe to avoid duplicate React:
116
+
117
+ ```ts
118
+ import { defineConfig } from "vite";
119
+ import react from "@vitejs/plugin-react";
120
+
121
+ export default defineConfig({
122
+ plugins: [react()],
123
+ resolve: {
124
+ dedupe: ["react", "react-dom", "lucide-react"],
125
+ },
126
+ });
127
+ ```
128
+
129
+ ## cn() Utility
130
+
131
+ All components use `cn()` for class merging. You can import it too:
132
+
133
+ ```ts
134
+ import { cn } from "hqui";
135
+
136
+ cn("px-4 py-2", "px-6"); // "px-6 py-2" (later wins)
137
+ cn("bg-red-500", isActive && "bg-blue-500");
138
+ ```
139
+
140
+ ## Build
141
+
142
+ ```bash
143
+ bun run build
144
+ ```
145
+
146
+ Outputs: `dist/index.js`, `dist/index.mjs`, `dist/index.d.ts`, `dist/index.css`
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@exitvibing/hqui",
3
+ "version": "0.1.0",
4
+ "description": "React Tailwind UI library",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "tsup src/index.ts --format cjs,esm --dts && bunx tailwindcss -i ./src/index.css -o ./dist/index.css --minify",
10
+ "dev": "bunx tailwindcss -i ./src/index.css -o ./dist/index.css --watch"
11
+ },
12
+ "peerDependencies": {
13
+ "react": "^18.0.0",
14
+ "react-dom": "^18.0.0",
15
+ "tailwindcss": ">=3.0.0"
16
+ },
17
+ "devDependencies": {
18
+ "@types/node": "^20.11.24",
19
+ "@types/react": "^18.2.61",
20
+ "@types/react-dom": "^18.2.19",
21
+ "prettier": "^3.8.1",
22
+ "react": "^18.2.0",
23
+ "react-dom": "^18.2.0",
24
+ "tailwindcss": "^3.4.1",
25
+ "tsup": "^8.0.2",
26
+ "typescript": "^5.3.3"
27
+ },
28
+ "dependencies": {
29
+ "clsx": "^2.1.1",
30
+ "lucide-react": "^0.575.0",
31
+ "tailwind-merge": "^3.5.0"
32
+ }
33
+ }
@@ -0,0 +1,40 @@
1
+ import React, { HTMLAttributes, forwardRef } from "react";
2
+ import { cn } from "../lib/cn";
3
+
4
+ const colorVariants = {
5
+ default: "bg-primary text-primary-foreground shadow hover:bg-primary/80",
6
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
7
+ outline: "border border-border text-foreground",
8
+ white: "bg-foreground/10 text-foreground border border-foreground/20",
9
+ destructive:
10
+ "bg-[hsl(var(--red))] text-white shadow hover:bg-[hsl(var(--red))]/80",
11
+ purple:
12
+ "bg-[hsl(var(--purple))]/15 text-[hsl(var(--purple))] border border-[hsl(var(--purple))]/20",
13
+ orange:
14
+ "bg-[hsl(var(--orange))]/15 text-[hsl(var(--orange))] border border-[hsl(var(--orange))]/20",
15
+ blue: "bg-[hsl(var(--blue))]/15 text-[hsl(var(--blue))] border border-[hsl(var(--blue))]/20",
16
+ green:
17
+ "bg-[hsl(var(--green))]/15 text-[hsl(var(--green))] border border-[hsl(var(--green))]/20",
18
+ red: "bg-[hsl(var(--red))]/15 text-[hsl(var(--red))] border border-[hsl(var(--red))]/20",
19
+ };
20
+
21
+ export interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
22
+ variant?: keyof typeof colorVariants;
23
+ }
24
+
25
+ export const Badge = forwardRef<HTMLSpanElement, BadgeProps>(
26
+ ({ className, variant = "default", ...props }, ref) => {
27
+ return (
28
+ <span
29
+ ref={ref}
30
+ className={cn(
31
+ "inline-flex items-center rounded-md px-2 py-0.5 text-xs font-semibold transition-colors",
32
+ colorVariants[variant],
33
+ className,
34
+ )}
35
+ {...props}
36
+ />
37
+ );
38
+ },
39
+ );
40
+ Badge.displayName = "Badge";
@@ -0,0 +1,50 @@
1
+ import React, { ButtonHTMLAttributes, forwardRef } from "react";
2
+ import { cn } from "../lib/cn";
3
+
4
+ const variants = {
5
+ primary: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
6
+ secondary:
7
+ "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
8
+ destructive:
9
+ "bg-[hsl(var(--red))] text-white shadow-sm hover:bg-[hsl(var(--red))]/90",
10
+ outline:
11
+ "border border-border bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
12
+ ghost: "hover:bg-accent hover:text-accent-foreground",
13
+ purple:
14
+ "bg-[hsl(var(--purple))] text-white shadow-sm hover:bg-[hsl(var(--purple))]/90",
15
+ orange:
16
+ "bg-[hsl(var(--orange))] text-white shadow-sm hover:bg-[hsl(var(--orange))]/90",
17
+ blue: "bg-[hsl(var(--blue))] text-white shadow-sm hover:bg-[hsl(var(--blue))]/90",
18
+ green:
19
+ "bg-[hsl(var(--green))] text-white shadow-sm hover:bg-[hsl(var(--green))]/90",
20
+ };
21
+
22
+ const sizes = {
23
+ sm: "h-8 rounded-md px-3 text-xs gap-1.5",
24
+ default: "h-9 px-4 py-2 text-sm gap-2",
25
+ lg: "h-10 rounded-md px-6 text-base gap-2",
26
+ icon: "h-9 w-9 p-0",
27
+ };
28
+
29
+ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
30
+ variant?: keyof typeof variants;
31
+ size?: keyof typeof sizes;
32
+ }
33
+
34
+ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
35
+ ({ className, variant = "primary", size = "default", ...props }, ref) => {
36
+ return (
37
+ <button
38
+ ref={ref}
39
+ className={cn(
40
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
41
+ variants[variant],
42
+ sizes[size],
43
+ className,
44
+ )}
45
+ {...props}
46
+ />
47
+ );
48
+ },
49
+ );
50
+ Button.displayName = "Button";
@@ -0,0 +1,72 @@
1
+ import React, { HTMLAttributes, forwardRef } from "react";
2
+ import { cn } from "../lib/cn";
3
+
4
+ export const Card = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
5
+ ({ className, ...props }, ref) => (
6
+ <div
7
+ ref={ref}
8
+ className={cn(
9
+ "rounded-xl border border-border bg-card text-card-foreground shadow-sm transition-shadow hover:shadow-md",
10
+ className,
11
+ )}
12
+ {...props}
13
+ />
14
+ ),
15
+ );
16
+ Card.displayName = "Card";
17
+
18
+ export const CardHeader = forwardRef<
19
+ HTMLDivElement,
20
+ HTMLAttributes<HTMLDivElement>
21
+ >(({ className, ...props }, ref) => (
22
+ <div
23
+ ref={ref}
24
+ className={cn("flex flex-col space-y-1.5 p-6 pb-4", className)}
25
+ {...props}
26
+ />
27
+ ));
28
+ CardHeader.displayName = "CardHeader";
29
+
30
+ export const CardTitle = forwardRef<
31
+ HTMLHeadingElement,
32
+ HTMLAttributes<HTMLHeadingElement>
33
+ >(({ className, ...props }, ref) => (
34
+ <h3
35
+ ref={ref}
36
+ className={cn("font-semibold leading-none tracking-tight", className)}
37
+ {...props}
38
+ />
39
+ ));
40
+ CardTitle.displayName = "CardTitle";
41
+
42
+ export const CardDescription = forwardRef<
43
+ HTMLParagraphElement,
44
+ HTMLAttributes<HTMLParagraphElement>
45
+ >(({ className, ...props }, ref) => (
46
+ <p
47
+ ref={ref}
48
+ className={cn("text-sm text-muted-foreground", className)}
49
+ {...props}
50
+ />
51
+ ));
52
+ CardDescription.displayName = "CardDescription";
53
+
54
+ export const CardContent = forwardRef<
55
+ HTMLDivElement,
56
+ HTMLAttributes<HTMLDivElement>
57
+ >(({ className, ...props }, ref) => (
58
+ <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
59
+ ));
60
+ CardContent.displayName = "CardContent";
61
+
62
+ export const CardFooter = forwardRef<
63
+ HTMLDivElement,
64
+ HTMLAttributes<HTMLDivElement>
65
+ >(({ className, ...props }, ref) => (
66
+ <div
67
+ ref={ref}
68
+ className={cn("flex items-center p-6 pt-0", className)}
69
+ {...props}
70
+ />
71
+ ));
72
+ CardFooter.displayName = "CardFooter";
@@ -0,0 +1,47 @@
1
+ import React, { InputHTMLAttributes, forwardRef } from "react";
2
+ import { Check } from "lucide-react";
3
+ import { cn } from "../lib/cn";
4
+
5
+ export interface CheckboxProps extends Omit<
6
+ InputHTMLAttributes<HTMLInputElement>,
7
+ "type"
8
+ > {
9
+ label?: string;
10
+ }
11
+
12
+ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
13
+ ({ className, label, id, ...props }, ref) => {
14
+ const defaultId = React.useId();
15
+ const inputId = id || defaultId;
16
+
17
+ return (
18
+ <label
19
+ htmlFor={inputId}
20
+ className={cn(
21
+ "flex items-center gap-2 cursor-pointer select-none",
22
+ className,
23
+ )}
24
+ >
25
+ <div className="relative flex items-center justify-center">
26
+ <input
27
+ id={inputId}
28
+ type="checkbox"
29
+ className="peer h-4 w-4 shrink-0 rounded-sm border border-foreground/30 shadow appearance-none focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 checked:bg-foreground checked:border-foreground"
30
+ ref={ref}
31
+ {...props}
32
+ />
33
+ <Check
34
+ className="absolute h-3 w-3 text-background pointer-events-none opacity-0 peer-checked:opacity-100 transition-opacity"
35
+ strokeWidth={3}
36
+ />
37
+ </div>
38
+ {label && (
39
+ <span className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
40
+ {label}
41
+ </span>
42
+ )}
43
+ </label>
44
+ );
45
+ },
46
+ );
47
+ Checkbox.displayName = "Checkbox";
@@ -0,0 +1,24 @@
1
+ import React, { HTMLAttributes, forwardRef } from "react";
2
+ import { cn } from "../lib/cn";
3
+
4
+ export interface HighlightTextProps extends HTMLAttributes<HTMLSpanElement> {
5
+ children?: React.ReactNode;
6
+ }
7
+
8
+ export const HighlightText = forwardRef<HTMLSpanElement, HighlightTextProps>(
9
+ ({ className, children, ...props }, ref) => {
10
+ return (
11
+ <span
12
+ ref={ref}
13
+ className={cn(
14
+ "bg-foreground text-background px-1.5 py-0.5 rounded font-medium",
15
+ className,
16
+ )}
17
+ {...props}
18
+ >
19
+ {children}
20
+ </span>
21
+ );
22
+ },
23
+ );
24
+ HighlightText.displayName = "HighlightText";
@@ -0,0 +1,21 @@
1
+ import React, { InputHTMLAttributes, forwardRef } from "react";
2
+ import { cn } from "../lib/cn";
3
+
4
+ export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {}
5
+
6
+ export const Input = forwardRef<HTMLInputElement, InputProps>(
7
+ ({ className, type = "text", ...props }, ref) => {
8
+ return (
9
+ <input
10
+ type={type}
11
+ className={cn(
12
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
13
+ className,
14
+ )}
15
+ ref={ref}
16
+ {...props}
17
+ />
18
+ );
19
+ },
20
+ );
21
+ Input.displayName = "Input";
@@ -0,0 +1,64 @@
1
+ import React, { HTMLAttributes, forwardRef } from "react";
2
+ import { cn } from "../lib/cn";
3
+
4
+ const colorClasses = {
5
+ white: "bg-foreground",
6
+ purple: "bg-[hsl(var(--purple))]",
7
+ orange: "bg-[hsl(var(--orange))]",
8
+ blue: "bg-[hsl(var(--blue))]",
9
+ green: "bg-[hsl(var(--green))]",
10
+ };
11
+
12
+ export interface ProgressBarProps extends HTMLAttributes<HTMLDivElement> {
13
+ value?: number;
14
+ max?: number;
15
+ showLabel?: boolean;
16
+ color?: keyof typeof colorClasses;
17
+ }
18
+
19
+ export const ProgressBar = forwardRef<HTMLDivElement, ProgressBarProps>(
20
+ (
21
+ {
22
+ className,
23
+ value = 0,
24
+ max = 100,
25
+ showLabel = false,
26
+ color = "white",
27
+ ...props
28
+ },
29
+ ref,
30
+ ) => {
31
+ const percentage = Math.min(Math.max(0, (value / max) * 100), 100);
32
+
33
+ return (
34
+ <div className={cn("flex items-center gap-3", showLabel && "w-full")}>
35
+ <div
36
+ ref={ref}
37
+ role="progressbar"
38
+ aria-valuemin={0}
39
+ aria-valuemax={max}
40
+ aria-valuenow={value}
41
+ className={cn(
42
+ "relative h-2 w-full overflow-hidden rounded-full bg-secondary",
43
+ className,
44
+ )}
45
+ {...props}
46
+ >
47
+ <div
48
+ className={cn(
49
+ "h-full rounded-full transition-all duration-500 ease-out",
50
+ colorClasses[color],
51
+ )}
52
+ style={{ width: `${percentage}%` }}
53
+ />
54
+ </div>
55
+ {showLabel && (
56
+ <span className="text-xs font-medium text-muted-foreground tabular-nums w-10 text-right">
57
+ {Math.round(percentage)}%
58
+ </span>
59
+ )}
60
+ </div>
61
+ );
62
+ },
63
+ );
64
+ ProgressBar.displayName = "ProgressBar";
@@ -0,0 +1,25 @@
1
+ import React, { forwardRef } from "react";
2
+ import { cn } from "../lib/cn";
3
+
4
+ export interface SeparatorProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ orientation?: "horizontal" | "vertical";
6
+ }
7
+
8
+ export const Separator = forwardRef<HTMLDivElement, SeparatorProps>(
9
+ ({ className, orientation = "horizontal", ...props }, ref) => {
10
+ return (
11
+ <div
12
+ ref={ref}
13
+ role="separator"
14
+ aria-orientation={orientation}
15
+ className={cn(
16
+ "shrink-0 bg-border",
17
+ orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
18
+ className,
19
+ )}
20
+ {...props}
21
+ />
22
+ );
23
+ },
24
+ );
25
+ Separator.displayName = "Separator";
@@ -0,0 +1,43 @@
1
+ import React, { forwardRef, InputHTMLAttributes } from "react";
2
+ import { cn } from "../lib/cn";
3
+
4
+ export interface SwitchProps extends Omit<
5
+ InputHTMLAttributes<HTMLInputElement>,
6
+ "type" | "role"
7
+ > {
8
+ label?: string;
9
+ }
10
+
11
+ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
12
+ ({ className, label, id, ...props }, ref) => {
13
+ const defaultId = React.useId();
14
+ const inputId = id || defaultId;
15
+
16
+ return (
17
+ <label
18
+ htmlFor={inputId}
19
+ className={cn(
20
+ "inline-flex items-center gap-2 cursor-pointer select-none",
21
+ className,
22
+ )}
23
+ >
24
+ <div className="relative">
25
+ <input
26
+ id={inputId}
27
+ type="checkbox"
28
+ role="switch"
29
+ className="peer sr-only"
30
+ ref={ref}
31
+ {...props}
32
+ />
33
+ <div className="h-5 w-9 rounded-full border-2 border-transparent bg-input transition-colors peer-checked:bg-foreground peer-focus-visible:outline-none peer-focus-visible:ring-2 peer-focus-visible:ring-ring peer-focus-visible:ring-offset-2 peer-focus-visible:ring-offset-background peer-disabled:cursor-not-allowed peer-disabled:opacity-50" />
34
+ <div className="absolute left-0.5 top-0.5 h-4 w-4 rounded-full bg-background shadow-lg transition-transform peer-checked:translate-x-4 peer-checked:bg-background" />
35
+ </div>
36
+ {label && (
37
+ <span className="text-sm font-medium leading-none">{label}</span>
38
+ )}
39
+ </label>
40
+ );
41
+ },
42
+ );
43
+ Switch.displayName = "Switch";
@@ -0,0 +1,87 @@
1
+ import React, {
2
+ HTMLAttributes,
3
+ TdHTMLAttributes,
4
+ ThHTMLAttributes,
5
+ forwardRef,
6
+ } from "react";
7
+ import { cn } from "../lib/cn";
8
+
9
+ export const Table = forwardRef<
10
+ HTMLTableElement,
11
+ React.HTMLAttributes<HTMLTableElement>
12
+ >(({ className, ...props }, ref) => (
13
+ <div className="relative w-full overflow-auto rounded-lg border border-border">
14
+ <table
15
+ ref={ref}
16
+ className={cn("w-full caption-bottom text-sm", className)}
17
+ {...props}
18
+ />
19
+ </div>
20
+ ));
21
+ Table.displayName = "Table";
22
+
23
+ export const TableHeader = forwardRef<
24
+ HTMLTableSectionElement,
25
+ React.HTMLAttributes<HTMLTableSectionElement>
26
+ >(({ className, ...props }, ref) => (
27
+ <thead
28
+ ref={ref}
29
+ className={cn("bg-muted/50 [&_tr]:border-b", className)}
30
+ {...props}
31
+ />
32
+ ));
33
+ TableHeader.displayName = "TableHeader";
34
+
35
+ export const TableBody = forwardRef<
36
+ HTMLTableSectionElement,
37
+ React.HTMLAttributes<HTMLTableSectionElement>
38
+ >(({ className, ...props }, ref) => (
39
+ <tbody
40
+ ref={ref}
41
+ className={cn("[&_tr:last-child]:border-0", className)}
42
+ {...props}
43
+ />
44
+ ));
45
+ TableBody.displayName = "TableBody";
46
+
47
+ export const TableRow = forwardRef<
48
+ HTMLTableRowElement,
49
+ React.HTMLAttributes<HTMLTableRowElement>
50
+ >(({ className, ...props }, ref) => (
51
+ <tr
52
+ ref={ref}
53
+ className={cn(
54
+ "border-b border-border transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
55
+ className,
56
+ )}
57
+ {...props}
58
+ />
59
+ ));
60
+ TableRow.displayName = "TableRow";
61
+
62
+ export const TableHead = forwardRef<
63
+ HTMLTableCellElement,
64
+ ThHTMLAttributes<HTMLTableCellElement>
65
+ >(({ className, ...props }, ref) => (
66
+ <th
67
+ ref={ref}
68
+ className={cn(
69
+ "h-10 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
70
+ className,
71
+ )}
72
+ {...props}
73
+ />
74
+ ));
75
+ TableHead.displayName = "TableHead";
76
+
77
+ export const TableCell = forwardRef<
78
+ HTMLTableCellElement,
79
+ TdHTMLAttributes<HTMLTableCellElement>
80
+ >(({ className, ...props }, ref) => (
81
+ <td
82
+ ref={ref}
83
+ className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
84
+ {...props}
85
+ />
86
+ ));
87
+ TableCell.displayName = "TableCell";