sonance-brand-mcp 1.3.109 → 1.3.111
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/dist/assets/api/sonance-ai-edit/route.ts +30 -7
- package/dist/assets/api/sonance-vision-apply/route.ts +33 -8
- package/dist/assets/api/sonance-vision-edit/route.ts +33 -8
- package/dist/assets/components/alert.tsx +35 -9
- package/dist/assets/components/badge.tsx +49 -20
- package/dist/assets/components/button.tsx +29 -20
- package/dist/assets/components/card.tsx +87 -33
- package/dist/assets/components/checkbox.tsx +36 -12
- package/dist/assets/components/dialog.tsx +73 -30
- package/dist/assets/components/dropdown-menu.tsx +57 -20
- package/dist/assets/components/input.tsx +35 -14
- package/dist/assets/components/pagination.tsx +86 -35
- package/dist/assets/components/popover.tsx +80 -36
- package/dist/assets/components/radio-group.tsx +40 -12
- package/dist/assets/components/select.tsx +62 -26
- package/dist/assets/components/switch.tsx +41 -13
- package/dist/assets/components/tabs.tsx +32 -12
- package/dist/assets/components/tooltip.tsx +34 -5
- package/dist/assets/dev-tools/SonanceDevTools.tsx +441 -365
- package/dist/assets/dev-tools/components/ChatHistory.tsx +141 -0
- package/dist/assets/dev-tools/components/ChatInterface.tsx +402 -294
- package/dist/assets/dev-tools/components/ChatTabBar.tsx +82 -0
- package/dist/assets/dev-tools/components/InlineDiffPreview.tsx +204 -0
- package/dist/assets/dev-tools/components/InspectorOverlay.tsx +12 -9
- package/dist/assets/dev-tools/components/PropertiesPanel.tsx +695 -0
- package/dist/assets/dev-tools/components/VisionModeBorder.tsx +16 -7
- package/dist/assets/dev-tools/constants.ts +38 -6
- package/dist/assets/dev-tools/hooks/useComputedStyles.ts +365 -0
- package/dist/assets/dev-tools/index.ts +3 -0
- package/dist/assets/dev-tools/panels/AnalysisPanel.tsx +32 -32
- package/dist/assets/dev-tools/panels/ComponentsPanel.tsx +277 -127
- package/dist/assets/dev-tools/types.ts +51 -2
- package/dist/index.js +22 -3
- package/package.json +2 -1
|
@@ -26,6 +26,11 @@ interface VariantStyles {
|
|
|
26
26
|
boxShadow: string;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
interface ChatHistoryMessage {
|
|
30
|
+
role: string;
|
|
31
|
+
content: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
29
34
|
interface AIEditRequest {
|
|
30
35
|
action: "edit" | "save";
|
|
31
36
|
componentType: string;
|
|
@@ -37,6 +42,8 @@ interface AIEditRequest {
|
|
|
37
42
|
editScope?: "component" | "variant";
|
|
38
43
|
variantId?: string;
|
|
39
44
|
variantStyles?: VariantStyles;
|
|
45
|
+
/** Conversation history for multi-turn context */
|
|
46
|
+
chatHistory?: ChatHistoryMessage[];
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
interface AIEditResponse {
|
|
@@ -240,7 +247,7 @@ export async function POST(request: Request) {
|
|
|
240
247
|
|
|
241
248
|
try {
|
|
242
249
|
const body: AIEditRequest = await request.json();
|
|
243
|
-
const { action, componentType, filePath, currentCode, modifiedCode, userRequest, editScope, variantId, variantStyles } = body;
|
|
250
|
+
const { action, componentType, filePath, currentCode, modifiedCode, userRequest, editScope, variantId, variantStyles, chatHistory } = body;
|
|
244
251
|
|
|
245
252
|
const projectRoot = process.cwd();
|
|
246
253
|
|
|
@@ -351,15 +358,31 @@ Return the complete modified file as JSON with these keys:
|
|
|
351
358
|
- "explanation": Brief description of changes made
|
|
352
359
|
- "previewCSS": CSS rules that will visually show the changes. Use selector [data-sonance-variant="${variantId || "selected"}"] to target the specific element(s). Example: "[data-sonance-variant='abc123'] { border-radius: 0.5rem; background-color: white; }"`;
|
|
353
360
|
|
|
361
|
+
// Build messages array with chat history for multi-turn context
|
|
362
|
+
const messages: Anthropic.MessageCreateParams["messages"] = [];
|
|
363
|
+
|
|
364
|
+
// Add conversation history if available (e.g., "make it darker", "undo that")
|
|
365
|
+
if (chatHistory && chatHistory.length > 0) {
|
|
366
|
+
for (const msg of chatHistory) {
|
|
367
|
+
if (msg.role === "user" || msg.role === "assistant") {
|
|
368
|
+
messages.push({
|
|
369
|
+
role: msg.role as "user" | "assistant",
|
|
370
|
+
content: msg.content,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Add current user request
|
|
377
|
+
messages.push({
|
|
378
|
+
role: "user",
|
|
379
|
+
content: userMessage,
|
|
380
|
+
});
|
|
381
|
+
|
|
354
382
|
const response = await anthropic.messages.create({
|
|
355
383
|
model: "claude-sonnet-4-20250514",
|
|
356
384
|
max_tokens: 8192,
|
|
357
|
-
messages
|
|
358
|
-
{
|
|
359
|
-
role: "user",
|
|
360
|
-
content: userMessage,
|
|
361
|
-
},
|
|
362
|
-
],
|
|
385
|
+
messages,
|
|
363
386
|
system: SYSTEM_PROMPT,
|
|
364
387
|
});
|
|
365
388
|
|
|
@@ -64,6 +64,11 @@ interface VisionFileModification {
|
|
|
64
64
|
explanation: string;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
interface ChatHistoryMessage {
|
|
68
|
+
role: string;
|
|
69
|
+
content: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
67
72
|
interface ApplyFirstRequest {
|
|
68
73
|
action: "apply" | "accept" | "revert" | "preview";
|
|
69
74
|
sessionId?: string;
|
|
@@ -73,6 +78,8 @@ interface ApplyFirstRequest {
|
|
|
73
78
|
focusedElements?: VisionFocusedElement[];
|
|
74
79
|
// For applying a previously previewed set of modifications
|
|
75
80
|
previewedModifications?: VisionFileModification[];
|
|
81
|
+
/** Conversation history for multi-turn context */
|
|
82
|
+
chatHistory?: ChatHistoryMessage[];
|
|
76
83
|
}
|
|
77
84
|
|
|
78
85
|
interface BackupManifest {
|
|
@@ -1929,7 +1936,7 @@ export async function POST(request: Request) {
|
|
|
1929
1936
|
|
|
1930
1937
|
try {
|
|
1931
1938
|
const body: ApplyFirstRequest = await request.json();
|
|
1932
|
-
const { action, sessionId, screenshot, pageRoute, userPrompt, focusedElements, previewedModifications } = body;
|
|
1939
|
+
const { action, sessionId, screenshot, pageRoute, userPrompt, focusedElements, previewedModifications, chatHistory } = body;
|
|
1933
1940
|
const projectRoot = process.cwd();
|
|
1934
1941
|
|
|
1935
1942
|
// ========== ACCEPT ACTION ==========
|
|
@@ -2840,13 +2847,31 @@ CRITICAL: Your "search" string MUST exist in the file. If you can't find the exa
|
|
|
2840
2847
|
let finalExplanation: string | undefined;
|
|
2841
2848
|
|
|
2842
2849
|
while (retryCount <= MAX_RETRIES) {
|
|
2843
|
-
// Build messages for this attempt
|
|
2844
|
-
const currentMessages: Anthropic.MessageCreateParams["messages"] = [
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
+
// Build messages for this attempt, starting with chat history if available
|
|
2851
|
+
const currentMessages: Anthropic.MessageCreateParams["messages"] = [];
|
|
2852
|
+
|
|
2853
|
+
// Add conversation history for multi-turn context (e.g., "make it darker", "undo that")
|
|
2854
|
+
if (chatHistory && chatHistory.length > 0) {
|
|
2855
|
+
for (const msg of chatHistory) {
|
|
2856
|
+
// Only include user and assistant messages, skip system messages
|
|
2857
|
+
if (msg.role === "user" || msg.role === "assistant") {
|
|
2858
|
+
currentMessages.push({
|
|
2859
|
+
role: msg.role as "user" | "assistant",
|
|
2860
|
+
content: msg.content,
|
|
2861
|
+
});
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
debugLog("Added chat history to context", {
|
|
2865
|
+
messageCount: chatHistory.length,
|
|
2866
|
+
preview: chatHistory.slice(-2).map(m => ({ role: m.role, content: m.content.substring(0, 50) }))
|
|
2867
|
+
});
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2870
|
+
// Add current user message with screenshot
|
|
2871
|
+
currentMessages.push({
|
|
2872
|
+
role: "user",
|
|
2873
|
+
content: messageContent,
|
|
2874
|
+
});
|
|
2850
2875
|
|
|
2851
2876
|
// If this is a retry, add feedback about what went wrong
|
|
2852
2877
|
if (retryCount > 0 && lastPatchErrors.length > 0) {
|
|
@@ -64,6 +64,11 @@ interface VisionFileModification {
|
|
|
64
64
|
previewCSS?: string;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
interface ChatHistoryMessage {
|
|
68
|
+
role: string;
|
|
69
|
+
content: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
67
72
|
interface VisionEditRequest {
|
|
68
73
|
action: "edit" | "save";
|
|
69
74
|
screenshot?: string;
|
|
@@ -71,6 +76,8 @@ interface VisionEditRequest {
|
|
|
71
76
|
userPrompt: string;
|
|
72
77
|
focusedElements?: VisionFocusedElement[];
|
|
73
78
|
modifications?: VisionFileModification[];
|
|
79
|
+
/** Conversation history for multi-turn context */
|
|
80
|
+
chatHistory?: ChatHistoryMessage[];
|
|
74
81
|
}
|
|
75
82
|
|
|
76
83
|
interface VisionEditResponse {
|
|
@@ -1925,7 +1932,7 @@ export async function POST(request: Request) {
|
|
|
1925
1932
|
|
|
1926
1933
|
try {
|
|
1927
1934
|
const body: VisionEditRequest = await request.json();
|
|
1928
|
-
const { action, screenshot, pageRoute, userPrompt, focusedElements, modifications } = body;
|
|
1935
|
+
const { action, screenshot, pageRoute, userPrompt, focusedElements, modifications, chatHistory } = body;
|
|
1929
1936
|
|
|
1930
1937
|
const projectRoot = process.cwd();
|
|
1931
1938
|
|
|
@@ -2800,13 +2807,31 @@ CRITICAL: Your "search" string MUST exist in the file. If you can't find the exa
|
|
|
2800
2807
|
let finalExplanation: string | undefined;
|
|
2801
2808
|
|
|
2802
2809
|
while (retryCount <= MAX_RETRIES) {
|
|
2803
|
-
// Build messages for this attempt
|
|
2804
|
-
const currentMessages: Anthropic.MessageCreateParams["messages"] = [
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
+
// Build messages for this attempt, starting with chat history if available
|
|
2811
|
+
const currentMessages: Anthropic.MessageCreateParams["messages"] = [];
|
|
2812
|
+
|
|
2813
|
+
// Add conversation history for multi-turn context (e.g., "make it darker", "undo that")
|
|
2814
|
+
if (chatHistory && chatHistory.length > 0) {
|
|
2815
|
+
for (const msg of chatHistory) {
|
|
2816
|
+
// Only include user and assistant messages, skip system messages
|
|
2817
|
+
if (msg.role === "user" || msg.role === "assistant") {
|
|
2818
|
+
currentMessages.push({
|
|
2819
|
+
role: msg.role as "user" | "assistant",
|
|
2820
|
+
content: msg.content,
|
|
2821
|
+
});
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
debugLog("Added chat history to context", {
|
|
2825
|
+
messageCount: chatHistory.length,
|
|
2826
|
+
preview: chatHistory.slice(-2).map(m => ({ role: m.role, content: m.content.substring(0, 50) }))
|
|
2827
|
+
});
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
// Add current user message with screenshot
|
|
2831
|
+
currentMessages.push({
|
|
2832
|
+
role: "user",
|
|
2833
|
+
content: messageContent,
|
|
2834
|
+
});
|
|
2810
2835
|
|
|
2811
2836
|
// If this is a retry, add feedback about what went wrong
|
|
2812
2837
|
if (retryCount > 0 && lastPatchErrors.length > 0) {
|
|
@@ -3,8 +3,10 @@ import { cva, type VariantProps } from "class-variance-authority";
|
|
|
3
3
|
import { AlertCircle, CheckCircle, Info, AlertTriangle, X } from "lucide-react";
|
|
4
4
|
import { cn } from "@/lib/utils";
|
|
5
5
|
|
|
6
|
+
export type AlertState = "default" | "hover" | "focus";
|
|
7
|
+
|
|
6
8
|
const alertVariants = cva(
|
|
7
|
-
"relative flex w-full items-start
|
|
9
|
+
"relative flex w-full items-start border transition-all duration-200",
|
|
8
10
|
{
|
|
9
11
|
variants: {
|
|
10
12
|
variant: {
|
|
@@ -14,13 +16,34 @@ const alertVariants = cva(
|
|
|
14
16
|
warning: "border-warning/30 bg-warning-light text-warning",
|
|
15
17
|
info: "border-info/30 bg-info-light text-info",
|
|
16
18
|
},
|
|
19
|
+
size: {
|
|
20
|
+
xs: "gap-2 p-2 rounded-lg text-xs",
|
|
21
|
+
sm: "gap-2.5 p-3 rounded-xl text-xs",
|
|
22
|
+
md: "gap-3 p-4 rounded-xl text-sm",
|
|
23
|
+
lg: "gap-4 p-5 rounded-2xl text-sm",
|
|
24
|
+
},
|
|
17
25
|
},
|
|
18
26
|
defaultVariants: {
|
|
19
27
|
variant: "default",
|
|
28
|
+
size: "sm",
|
|
20
29
|
},
|
|
21
30
|
}
|
|
22
31
|
);
|
|
23
32
|
|
|
33
|
+
const iconSizes = {
|
|
34
|
+
xs: "h-3.5 w-3.5",
|
|
35
|
+
sm: "h-4 w-4",
|
|
36
|
+
md: "h-5 w-5",
|
|
37
|
+
lg: "h-5 w-5",
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const closeSizes = {
|
|
41
|
+
xs: "h-3 w-3",
|
|
42
|
+
sm: "h-3.5 w-3.5",
|
|
43
|
+
md: "h-4 w-4",
|
|
44
|
+
lg: "h-4 w-4",
|
|
45
|
+
};
|
|
46
|
+
|
|
24
47
|
const iconMap = {
|
|
25
48
|
default: Info,
|
|
26
49
|
success: CheckCircle,
|
|
@@ -35,10 +58,12 @@ interface AlertProps
|
|
|
35
58
|
title?: string;
|
|
36
59
|
dismissible?: boolean;
|
|
37
60
|
onClose?: () => void;
|
|
61
|
+
/** Visual state for Storybook/Figma documentation */
|
|
62
|
+
state?: AlertState;
|
|
38
63
|
}
|
|
39
64
|
|
|
40
65
|
export const Alert = forwardRef<HTMLDivElement, AlertProps>(
|
|
41
|
-
({ className, variant = "default", title, children, dismissible, onClose, ...props }, ref) => {
|
|
66
|
+
({ className, variant = "default", size = "sm", title, children, dismissible, onClose, state, ...props }, ref) => {
|
|
42
67
|
const Icon = iconMap[variant || "default"];
|
|
43
68
|
const showCloseButton = dismissible || onClose;
|
|
44
69
|
|
|
@@ -47,18 +72,18 @@ export const Alert = forwardRef<HTMLDivElement, AlertProps>(
|
|
|
47
72
|
data-sonance-name="alert"
|
|
48
73
|
ref={ref}
|
|
49
74
|
role="alert"
|
|
50
|
-
className={cn(alertVariants({ variant }), className)}
|
|
75
|
+
className={cn(alertVariants({ variant, size }), className)}
|
|
51
76
|
{...props}
|
|
52
77
|
>
|
|
53
|
-
<Icon className="
|
|
54
|
-
<div className="flex-1">
|
|
78
|
+
<Icon className={cn("shrink-0", iconSizes[size || "sm"])} />
|
|
79
|
+
<div className="flex-1 min-w-0">
|
|
55
80
|
{title && (
|
|
56
|
-
<h5 id="icon-h5-title" className="mb-
|
|
81
|
+
<h5 id="icon-h5-title" className="mb-0.5 font-medium leading-tight tracking-tight">
|
|
57
82
|
{title}
|
|
58
83
|
</h5>
|
|
59
84
|
)}
|
|
60
85
|
{children && (
|
|
61
|
-
<div data-sonance-name="alert" className={cn(
|
|
86
|
+
<div data-sonance-name="alert" className={cn(variant === "default" && "text-foreground-secondary")}>
|
|
62
87
|
{children}
|
|
63
88
|
</div>
|
|
64
89
|
)}
|
|
@@ -66,9 +91,9 @@ export const Alert = forwardRef<HTMLDivElement, AlertProps>(
|
|
|
66
91
|
{showCloseButton && (
|
|
67
92
|
<button
|
|
68
93
|
onClick={onClose}
|
|
69
|
-
className="shrink-0 rounded-
|
|
94
|
+
className="shrink-0 rounded-lg p-1 opacity-70 transition-all duration-150 hover:opacity-100 hover:bg-secondary-hover"
|
|
70
95
|
>
|
|
71
|
-
<X className=
|
|
96
|
+
<X className={closeSizes[size || "sm"]} />
|
|
72
97
|
<span id="icon-span-close" className="sr-only">Close</span>
|
|
73
98
|
</button>
|
|
74
99
|
)}
|
|
@@ -79,3 +104,4 @@ export const Alert = forwardRef<HTMLDivElement, AlertProps>(
|
|
|
79
104
|
|
|
80
105
|
Alert.displayName = "Alert";
|
|
81
106
|
|
|
107
|
+
export { alertVariants };
|
|
@@ -1,58 +1,86 @@
|
|
|
1
1
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
2
2
|
import { cn } from "@/lib/utils";
|
|
3
3
|
|
|
4
|
+
export type BadgeState = "default" | "hover";
|
|
5
|
+
|
|
4
6
|
const badgeVariants = cva(
|
|
5
|
-
"inline-flex items-center font-medium transition-
|
|
7
|
+
"inline-flex items-center font-medium transition-all duration-150",
|
|
6
8
|
{
|
|
7
9
|
variants: {
|
|
8
10
|
variant: {
|
|
9
|
-
default: "bg-background-secondary text-foreground border border-border",
|
|
10
|
-
primary: "bg-primary text-primary-foreground",
|
|
11
|
-
secondary: "bg-secondary-hover text-secondary-foreground border border-border",
|
|
12
|
-
success: "bg-success text-white",
|
|
13
|
-
error: "bg-error text-white",
|
|
14
|
-
warning: "bg-warning text-white",
|
|
15
|
-
info: "bg-info text-white",
|
|
16
|
-
outline: "border border-border text-foreground bg-transparent",
|
|
11
|
+
default: "bg-background-secondary text-foreground border border-border hover:bg-secondary-hover",
|
|
12
|
+
primary: "bg-primary text-primary-foreground hover:bg-primary-hover",
|
|
13
|
+
secondary: "bg-secondary-hover text-secondary-foreground border border-border hover:bg-secondary",
|
|
14
|
+
success: "bg-success text-white hover:bg-success/90",
|
|
15
|
+
error: "bg-error text-white hover:bg-error/90",
|
|
16
|
+
warning: "bg-warning text-white hover:bg-warning/90",
|
|
17
|
+
info: "bg-info text-white hover:bg-info/90",
|
|
18
|
+
outline: "border border-border text-foreground bg-transparent hover:bg-secondary-hover",
|
|
19
|
+
glass: "bg-primary/20 text-primary border border-primary/30 backdrop-blur-sm hover:bg-primary/30",
|
|
17
20
|
},
|
|
18
21
|
size: {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
xs: "px-1.5 py-0.5 text-[10px] rounded-md",
|
|
23
|
+
sm: "px-2 py-0.5 text-xs rounded-lg",
|
|
24
|
+
md: "px-2.5 py-0.5 text-xs rounded-full",
|
|
25
|
+
lg: "px-3 py-1 text-sm rounded-full",
|
|
22
26
|
},
|
|
23
27
|
},
|
|
24
28
|
defaultVariants: {
|
|
25
29
|
variant: "default",
|
|
26
|
-
size: "
|
|
30
|
+
size: "sm",
|
|
27
31
|
},
|
|
28
32
|
}
|
|
29
33
|
);
|
|
30
34
|
|
|
31
35
|
interface BadgeProps
|
|
32
36
|
extends React.HTMLAttributes<HTMLSpanElement>,
|
|
33
|
-
VariantProps<typeof badgeVariants> {
|
|
37
|
+
VariantProps<typeof badgeVariants> {
|
|
38
|
+
/** Visual state for Storybook/Figma documentation */
|
|
39
|
+
state?: BadgeState;
|
|
40
|
+
}
|
|
34
41
|
|
|
35
|
-
export function Badge({ className, variant, size, ...props }: BadgeProps) {
|
|
42
|
+
export function Badge({ className, variant, size, state, ...props }: BadgeProps) {
|
|
36
43
|
return (
|
|
37
|
-
<span
|
|
44
|
+
<span
|
|
45
|
+
id="badge-span"
|
|
46
|
+
data-sonance-name="badge"
|
|
47
|
+
className={cn(
|
|
48
|
+
badgeVariants({ variant, size }),
|
|
49
|
+
state === "hover" && "bg-secondary-hover",
|
|
50
|
+
className
|
|
51
|
+
)}
|
|
52
|
+
{...props}
|
|
53
|
+
/>
|
|
38
54
|
);
|
|
39
55
|
}
|
|
40
56
|
|
|
57
|
+
const closeIconSizes = {
|
|
58
|
+
xs: "h-2.5 w-2.5",
|
|
59
|
+
sm: "h-3 w-3",
|
|
60
|
+
md: "h-3 w-3",
|
|
61
|
+
lg: "h-3.5 w-3.5",
|
|
62
|
+
};
|
|
63
|
+
|
|
41
64
|
// Chip variant with optional close button
|
|
42
65
|
interface ChipProps extends BadgeProps {
|
|
43
66
|
onClose?: () => void;
|
|
44
67
|
}
|
|
45
68
|
|
|
46
|
-
export function Chip({ className, variant, size, onClose, children, ...props }: ChipProps) {
|
|
69
|
+
export function Chip({ className, variant, size = "sm", onClose, children, ...props }: ChipProps) {
|
|
47
70
|
return (
|
|
48
|
-
<span
|
|
71
|
+
<span
|
|
72
|
+
id="chip-span"
|
|
73
|
+
className={cn(badgeVariants({ variant, size }), "gap-1", className)}
|
|
74
|
+
data-sonance-name="badge"
|
|
75
|
+
{...props}
|
|
76
|
+
>
|
|
49
77
|
{children}
|
|
50
78
|
{onClose && (
|
|
51
79
|
<button
|
|
52
80
|
onClick={onClose}
|
|
53
|
-
className="ml-
|
|
81
|
+
className="ml-0.5 rounded-full p-0.5 transition-colors hover:bg-black/10 dark:hover:bg-white/10"
|
|
54
82
|
>
|
|
55
|
-
<svg className=
|
|
83
|
+
<svg className={closeIconSizes[size || "sm"]} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
56
84
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
57
85
|
</svg>
|
|
58
86
|
<span id="chip-span-remove" className="sr-only">Remove</span>
|
|
@@ -62,3 +90,4 @@ export function Chip({ className, variant, size, onClose, children, ...props }:
|
|
|
62
90
|
);
|
|
63
91
|
}
|
|
64
92
|
|
|
93
|
+
export { badgeVariants };
|
|
@@ -5,28 +5,31 @@ import { forwardRef } from "react";
|
|
|
5
5
|
export type ButtonState = "default" | "hover" | "active" | "focus" | "disabled";
|
|
6
6
|
|
|
7
7
|
const buttonVariants = cva(
|
|
8
|
-
"inline-flex items-center justify-center font-medium uppercase tracking-wide transition-
|
|
8
|
+
"inline-flex items-center justify-center font-medium uppercase tracking-wide transition-all duration-200 ease-out focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/20 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.98]",
|
|
9
9
|
{
|
|
10
10
|
variants: {
|
|
11
11
|
variant: {
|
|
12
12
|
primary:
|
|
13
|
-
"bg-primary text-primary-foreground hover:bg-primary-hover active:bg-primary-active",
|
|
13
|
+
"bg-primary text-primary-foreground hover:bg-primary-hover active:bg-primary-active shadow-sm hover:shadow-md",
|
|
14
14
|
secondary:
|
|
15
|
-
"bg-secondary text-secondary-foreground border border-border hover:bg-secondary-hover hover:border-border-hover",
|
|
15
|
+
"bg-secondary text-secondary-foreground border border-border hover:bg-secondary-hover hover:border-border-hover shadow-sm hover:shadow-md",
|
|
16
16
|
ghost: "text-foreground hover:bg-secondary-hover",
|
|
17
17
|
inverted:
|
|
18
|
-
"bg-sonance-white text-sonance-charcoal hover:opacity-90",
|
|
18
|
+
"bg-sonance-white text-sonance-charcoal hover:opacity-90 shadow-sm hover:shadow-md",
|
|
19
|
+
glass:
|
|
20
|
+
"bg-primary/90 text-primary-foreground backdrop-blur-sm border border-white/10 hover:bg-primary/80 shadow-lg",
|
|
19
21
|
},
|
|
20
22
|
size: {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
xs: "h-6 px-2.5 text-[10px] rounded-md",
|
|
24
|
+
sm: "h-8 px-3.5 text-xs rounded-lg",
|
|
25
|
+
md: "h-9 px-4 text-sm rounded-lg",
|
|
26
|
+
lg: "h-10 px-5 text-sm rounded-xl",
|
|
27
|
+
icon: "h-9 w-9 rounded-full",
|
|
25
28
|
},
|
|
26
29
|
},
|
|
27
30
|
defaultVariants: {
|
|
28
31
|
variant: "primary",
|
|
29
|
-
size: "
|
|
32
|
+
size: "sm",
|
|
30
33
|
},
|
|
31
34
|
}
|
|
32
35
|
);
|
|
@@ -37,27 +40,33 @@ const getStateStyles = (variant: string | null | undefined, state?: ButtonState)
|
|
|
37
40
|
|
|
38
41
|
const stateMap: Record<string, Record<string, string>> = {
|
|
39
42
|
primary: {
|
|
40
|
-
hover: "bg-primary-hover",
|
|
41
|
-
active: "bg-primary-active",
|
|
42
|
-
focus: "ring-2 ring-
|
|
43
|
+
hover: "bg-primary-hover shadow-md",
|
|
44
|
+
active: "bg-primary-active scale-[0.98]",
|
|
45
|
+
focus: "ring-2 ring-primary/20 ring-offset-2 ring-offset-background",
|
|
43
46
|
disabled: "opacity-50 pointer-events-none",
|
|
44
47
|
},
|
|
45
48
|
secondary: {
|
|
46
|
-
hover: "bg-secondary-hover border-border-hover",
|
|
47
|
-
active: "bg-secondary-hover",
|
|
48
|
-
focus: "ring-2 ring-
|
|
49
|
+
hover: "bg-secondary-hover border-border-hover shadow-md",
|
|
50
|
+
active: "bg-secondary-hover scale-[0.98]",
|
|
51
|
+
focus: "ring-2 ring-primary/20 ring-offset-2 ring-offset-background",
|
|
49
52
|
disabled: "opacity-50 pointer-events-none",
|
|
50
53
|
},
|
|
51
54
|
ghost: {
|
|
52
55
|
hover: "bg-secondary-hover",
|
|
53
|
-
active: "bg-secondary-hover",
|
|
54
|
-
focus: "ring-2 ring-
|
|
56
|
+
active: "bg-secondary-hover scale-[0.98]",
|
|
57
|
+
focus: "ring-2 ring-primary/20 ring-offset-2 ring-offset-background",
|
|
55
58
|
disabled: "opacity-50 pointer-events-none",
|
|
56
59
|
},
|
|
57
60
|
inverted: {
|
|
58
|
-
hover: "opacity-90",
|
|
59
|
-
active: "opacity-80",
|
|
60
|
-
focus: "ring-2 ring-
|
|
61
|
+
hover: "opacity-90 shadow-md",
|
|
62
|
+
active: "opacity-80 scale-[0.98]",
|
|
63
|
+
focus: "ring-2 ring-primary/20 ring-offset-2 ring-offset-background",
|
|
64
|
+
disabled: "opacity-50 pointer-events-none",
|
|
65
|
+
},
|
|
66
|
+
glass: {
|
|
67
|
+
hover: "bg-primary/80 shadow-lg",
|
|
68
|
+
active: "bg-primary/70 scale-[0.98]",
|
|
69
|
+
focus: "ring-2 ring-primary/20 ring-offset-2 ring-offset-background",
|
|
61
70
|
disabled: "opacity-50 pointer-events-none",
|
|
62
71
|
},
|
|
63
72
|
};
|