trix-ui 0.0.3 → 0.0.4
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/package.json +8 -1
- package/templates/components/ui/badge.tsx +175 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trix-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Lite UI CLI, registry tooling, and templates.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -37,15 +37,22 @@
|
|
|
37
37
|
"README.md"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
+
"@antfu/ni": "^28.2.0",
|
|
41
|
+
"chalk": "^5.6.2",
|
|
40
42
|
"commander": "^14.0.2",
|
|
41
43
|
"eslint-plugin-tailwindcss": "3.18.2",
|
|
44
|
+
"execa": "^9.6.1",
|
|
45
|
+
"ora": "^9.1.0",
|
|
46
|
+
"pino": "^10.2.1",
|
|
42
47
|
"postcss": "^8.5.6",
|
|
43
48
|
"postcss-selector-parser": "^7.1.1",
|
|
49
|
+
"prompts": "^2.4.2",
|
|
44
50
|
"ts-morph": "^27.0.2",
|
|
45
51
|
"zod": "^4.3.5"
|
|
46
52
|
},
|
|
47
53
|
"devDependencies": {
|
|
48
54
|
"@types/node": "^25.0.9",
|
|
55
|
+
"@types/prompts": "^2.4.9",
|
|
49
56
|
"tsx": "^4.21.0",
|
|
50
57
|
"typescript": "^5.9.3"
|
|
51
58
|
},
|
|
@@ -1,32 +1,182 @@
|
|
|
1
|
-
import * as React from "react"
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cn } from "@/lib/utils";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
type BadgeVariant = "default" | "secondary" | "destructive" | "success" | "warning" | "info";
|
|
5
|
+
type BadgeTone = "solid" | "soft" | "outline";
|
|
6
|
+
type BadgeSize = "sm" | "md" | "lg";
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
9
|
+
variant?: BadgeVariant;
|
|
10
|
+
tone?: BadgeTone;
|
|
11
|
+
size?: BadgeSize;
|
|
12
|
+
|
|
13
|
+
/** If true, applies pointer styles (auto true if onClick is provided) */
|
|
14
|
+
interactive?: boolean;
|
|
15
|
+
|
|
16
|
+
/** Truncate long content */
|
|
17
|
+
truncate?: boolean;
|
|
18
|
+
|
|
19
|
+
/** Semantic disabled state (span has no native disabled) */
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
|
|
22
|
+
/** Optional icons */
|
|
23
|
+
leftIcon?: React.ReactNode;
|
|
24
|
+
rightIcon?: React.ReactNode;
|
|
25
|
+
|
|
26
|
+
/** Status dot */
|
|
27
|
+
dot?: boolean;
|
|
28
|
+
dotClassName?: string;
|
|
29
|
+
|
|
30
|
+
/** Removable UX */
|
|
31
|
+
removable?: boolean;
|
|
32
|
+
onRemove?: () => void;
|
|
33
|
+
removeLabel?: string;
|
|
10
34
|
}
|
|
11
35
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
36
|
+
const BASE =
|
|
37
|
+
"inline-flex items-center gap-1.5 whitespace-nowrap select-none rounded-full font-medium leading-none " +
|
|
38
|
+
"border shadow-sm transition-colors " +
|
|
39
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 " +
|
|
40
|
+
"ring-offset-background";
|
|
41
|
+
|
|
42
|
+
const SIZE: Record<BadgeSize, string> = {
|
|
43
|
+
sm: "h-5 px-2 text-[11px]",
|
|
44
|
+
md: "h-6 px-2.5 text-xs",
|
|
45
|
+
lg: "h-7 px-3 text-sm",
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// These classes assume shadcn-like tokens exist (bg-primary, text-foreground, etc.)
|
|
49
|
+
// If you have different tokens, adjust here only.
|
|
50
|
+
const SOLID: Record<BadgeVariant, string> = {
|
|
51
|
+
default: "bg-primary text-primary-foreground border-transparent hover:bg-primary/90",
|
|
52
|
+
secondary: "bg-secondary text-secondary-foreground border-transparent hover:bg-secondary/85",
|
|
53
|
+
destructive: "bg-destructive text-destructive-foreground border-transparent hover:bg-destructive/90",
|
|
54
|
+
success: "bg-emerald-600 text-white border-transparent hover:bg-emerald-600/90",
|
|
55
|
+
warning: "bg-amber-500 text-black border-transparent hover:bg-amber-500/90",
|
|
56
|
+
info: "bg-sky-600 text-white border-transparent hover:bg-sky-600/90",
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const SOFT: Record<BadgeVariant, string> = {
|
|
60
|
+
default: "bg-muted text-foreground border-transparent hover:bg-muted/80",
|
|
61
|
+
secondary: "bg-secondary/20 text-secondary-foreground border-transparent hover:bg-secondary/25",
|
|
62
|
+
destructive: "bg-destructive/15 text-destructive border-transparent hover:bg-destructive/20",
|
|
63
|
+
success: "bg-emerald-500/15 text-emerald-700 dark:text-emerald-400 border-transparent hover:bg-emerald-500/20",
|
|
64
|
+
warning: "bg-amber-500/20 text-amber-800 dark:text-amber-300 border-transparent hover:bg-amber-500/25",
|
|
65
|
+
info: "bg-sky-500/15 text-sky-700 dark:text-sky-300 border-transparent hover:bg-sky-500/20",
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const OUTLINE: Record<BadgeVariant, string> = {
|
|
69
|
+
default: "bg-transparent text-foreground border-border hover:bg-accent hover:text-accent-foreground",
|
|
70
|
+
secondary: "bg-transparent text-foreground border-border hover:bg-accent hover:text-accent-foreground",
|
|
71
|
+
destructive: "bg-transparent text-destructive border-destructive/40 hover:bg-destructive/10",
|
|
72
|
+
success: "bg-transparent text-emerald-700 dark:text-emerald-400 border-emerald-500/40 hover:bg-emerald-500/10",
|
|
73
|
+
warning: "bg-transparent text-amber-800 dark:text-amber-300 border-amber-500/45 hover:bg-amber-500/10",
|
|
74
|
+
info: "bg-transparent text-sky-700 dark:text-sky-300 border-sky-500/40 hover:bg-sky-500/10",
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
function getVariantClass(variant: BadgeVariant, tone: BadgeTone) {
|
|
78
|
+
if (tone === "soft") return SOFT[variant];
|
|
79
|
+
if (tone === "outline") return OUTLINE[variant];
|
|
80
|
+
return SOLID[variant];
|
|
15
81
|
}
|
|
16
82
|
|
|
17
83
|
const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
|
|
18
|
-
(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
84
|
+
(
|
|
85
|
+
{
|
|
86
|
+
className,
|
|
87
|
+
variant = "default",
|
|
88
|
+
tone = "solid",
|
|
89
|
+
size = "md",
|
|
90
|
+
interactive,
|
|
91
|
+
truncate = false,
|
|
92
|
+
disabled = false,
|
|
93
|
+
|
|
94
|
+
leftIcon,
|
|
95
|
+
rightIcon,
|
|
96
|
+
|
|
97
|
+
dot = false,
|
|
98
|
+
dotClassName,
|
|
99
|
+
|
|
100
|
+
removable = false,
|
|
101
|
+
onRemove,
|
|
102
|
+
removeLabel = "Remove badge",
|
|
103
|
+
|
|
104
|
+
children,
|
|
105
|
+
onClick,
|
|
106
|
+
...props
|
|
107
|
+
},
|
|
108
|
+
ref
|
|
109
|
+
) => {
|
|
110
|
+
const isInteractive = (interactive ?? !!onClick) && !disabled;
|
|
111
|
+
const isRemovable = removable && typeof onRemove === "function" && !disabled;
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<span
|
|
115
|
+
ref={ref}
|
|
116
|
+
aria-disabled={disabled || undefined}
|
|
117
|
+
data-disabled={disabled ? "true" : undefined}
|
|
118
|
+
onClick={disabled ? undefined : onClick}
|
|
119
|
+
className={cn(
|
|
120
|
+
BASE,
|
|
121
|
+
SIZE[size],
|
|
122
|
+
getVariantClass(variant, tone),
|
|
123
|
+
isInteractive && "cursor-pointer",
|
|
124
|
+
disabled && "opacity-55 pointer-events-none",
|
|
125
|
+
truncate && "max-w-[18rem] overflow-hidden text-ellipsis",
|
|
126
|
+
className
|
|
127
|
+
)}
|
|
128
|
+
{...props}
|
|
129
|
+
>
|
|
130
|
+
{dot ? (
|
|
131
|
+
<span
|
|
132
|
+
aria-hidden="true"
|
|
133
|
+
className={cn("inline-block h-1.5 w-1.5 rounded-full bg-current opacity-70", dotClassName)}
|
|
134
|
+
/>
|
|
135
|
+
) : null}
|
|
136
|
+
|
|
137
|
+
{leftIcon ? (
|
|
138
|
+
<span aria-hidden="true" className="inline-flex items-center">
|
|
139
|
+
{leftIcon}
|
|
140
|
+
</span>
|
|
141
|
+
) : null}
|
|
142
|
+
|
|
143
|
+
<span className="min-w-0">{children}</span>
|
|
144
|
+
|
|
145
|
+
{rightIcon ? (
|
|
146
|
+
<span aria-hidden="true" className="inline-flex items-center">
|
|
147
|
+
{rightIcon}
|
|
148
|
+
</span>
|
|
149
|
+
) : null}
|
|
150
|
+
|
|
151
|
+
{isRemovable ? (
|
|
152
|
+
<button
|
|
153
|
+
type="button"
|
|
154
|
+
onClick={(e) => {
|
|
155
|
+
e.preventDefault();
|
|
156
|
+
e.stopPropagation();
|
|
157
|
+
onRemove();
|
|
158
|
+
}}
|
|
159
|
+
aria-label={removeLabel}
|
|
160
|
+
className={cn(
|
|
161
|
+
"ml-1 inline-flex h-4 w-4 items-center justify-center rounded-full",
|
|
162
|
+
"hover:bg-black/10 dark:hover:bg-white/10",
|
|
163
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
164
|
+
)}
|
|
165
|
+
>
|
|
166
|
+
<svg aria-hidden="true" viewBox="0 0 20 20" className="h-3 w-3" fill="currentColor">
|
|
167
|
+
<path
|
|
168
|
+
fillRule="evenodd"
|
|
169
|
+
d="M4.22 4.22a.75.75 0 011.06 0L10 8.94l4.72-4.72a.75.75 0 111.06 1.06L11.06 10l4.72 4.72a.75.75 0 11-1.06 1.06L10 11.06l-4.72 4.72a.75.75 0 11-1.06-1.06L8.94 10 4.22 5.28a.75.75 0 010-1.06z"
|
|
170
|
+
clipRule="evenodd"
|
|
171
|
+
/>
|
|
172
|
+
</svg>
|
|
173
|
+
</button>
|
|
174
|
+
) : null}
|
|
175
|
+
</span>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
Badge.displayName = "Badge";
|
|
181
|
+
|
|
182
|
+
export { Badge };
|