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.
Files changed (34) hide show
  1. package/dist/assets/api/sonance-ai-edit/route.ts +30 -7
  2. package/dist/assets/api/sonance-vision-apply/route.ts +33 -8
  3. package/dist/assets/api/sonance-vision-edit/route.ts +33 -8
  4. package/dist/assets/components/alert.tsx +35 -9
  5. package/dist/assets/components/badge.tsx +49 -20
  6. package/dist/assets/components/button.tsx +29 -20
  7. package/dist/assets/components/card.tsx +87 -33
  8. package/dist/assets/components/checkbox.tsx +36 -12
  9. package/dist/assets/components/dialog.tsx +73 -30
  10. package/dist/assets/components/dropdown-menu.tsx +57 -20
  11. package/dist/assets/components/input.tsx +35 -14
  12. package/dist/assets/components/pagination.tsx +86 -35
  13. package/dist/assets/components/popover.tsx +80 -36
  14. package/dist/assets/components/radio-group.tsx +40 -12
  15. package/dist/assets/components/select.tsx +62 -26
  16. package/dist/assets/components/switch.tsx +41 -13
  17. package/dist/assets/components/tabs.tsx +32 -12
  18. package/dist/assets/components/tooltip.tsx +34 -5
  19. package/dist/assets/dev-tools/SonanceDevTools.tsx +441 -365
  20. package/dist/assets/dev-tools/components/ChatHistory.tsx +141 -0
  21. package/dist/assets/dev-tools/components/ChatInterface.tsx +402 -294
  22. package/dist/assets/dev-tools/components/ChatTabBar.tsx +82 -0
  23. package/dist/assets/dev-tools/components/InlineDiffPreview.tsx +204 -0
  24. package/dist/assets/dev-tools/components/InspectorOverlay.tsx +12 -9
  25. package/dist/assets/dev-tools/components/PropertiesPanel.tsx +695 -0
  26. package/dist/assets/dev-tools/components/VisionModeBorder.tsx +16 -7
  27. package/dist/assets/dev-tools/constants.ts +38 -6
  28. package/dist/assets/dev-tools/hooks/useComputedStyles.ts +365 -0
  29. package/dist/assets/dev-tools/index.ts +3 -0
  30. package/dist/assets/dev-tools/panels/AnalysisPanel.tsx +32 -32
  31. package/dist/assets/dev-tools/panels/ComponentsPanel.tsx +277 -127
  32. package/dist/assets/dev-tools/types.ts +51 -2
  33. package/dist/index.js +22 -3
  34. 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
- role: "user",
2847
- content: messageContent,
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
- role: "user",
2807
- content: messageContent,
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 gap-4 border p-4 transition-colors",
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="h-5 w-5 shrink-0" />
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-1 font-medium leading-none tracking-tight">
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("text-sm", variant === "default" && "text-foreground-secondary")}>
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-sm p-1 opacity-70 transition-opacity hover:opacity-100"
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="h-4 w-4" />
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-colors",
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
- sm: "px-2 py-0.5 text-xs",
20
- md: "px-2.5 py-0.5 text-xs",
21
- lg: "px-3 py-1 text-sm",
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: "md",
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 id="badge-span" data-sonance-name="badge" className={cn(badgeVariants({ variant, size }), className)} {...props} />
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 id="chip-span" className={cn(badgeVariants({ variant, size }), "gap-1", className)} data-sonance-name="badge" {...props}>
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-1 rounded-full p-0.5 hover:bg-black/10 dark:hover:bg-white/10"
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="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
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-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50",
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
- sm: "h-9 px-4 text-xs",
22
- md: "h-11 px-6 text-sm",
23
- lg: "h-14 px-8 text-sm",
24
- icon: "h-10 w-10",
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: "md",
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-border-focus ring-offset-2 ring-offset-background",
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-border-focus ring-offset-2 ring-offset-background",
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-border-focus ring-offset-2 ring-offset-background",
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-border-focus ring-offset-2 ring-offset-background",
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
  };