@lark-apaas/coding-templates 0.1.4 → 0.1.6

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 (85) hide show
  1. package/package.json +1 -1
  2. package/template-vite-react/README.md +175 -0
  3. package/template-vite-react/client/index.html +2 -1
  4. package/template-vite-react/client/src/app.tsx +3 -1
  5. package/template-vite-react/client/src/components/layout.tsx +0 -2
  6. package/template-vite-react/client/src/components/ui/README.md +134 -0
  7. package/template-vite-react/client/src/components/ui/accordion.tsx +22 -28
  8. package/template-vite-react/client/src/components/ui/alert-dialog.tsx +34 -64
  9. package/template-vite-react/client/src/components/ui/alert.tsx +10 -15
  10. package/template-vite-react/client/src/components/ui/aspect-ratio.tsx +5 -16
  11. package/template-vite-react/client/src/components/ui/avatar.tsx +11 -67
  12. package/template-vite-react/client/src/components/ui/badge.tsx +21 -31
  13. package/template-vite-react/client/src/components/ui/breadcrumb.tsx +23 -39
  14. package/template-vite-react/client/src/components/ui/button.tsx +36 -25
  15. package/template-vite-react/client/src/components/ui/calendar.tsx +37 -43
  16. package/template-vite-react/client/src/components/ui/card.tsx +73 -94
  17. package/template-vite-react/client/src/components/ui/carousel.tsx +7 -8
  18. package/template-vite-react/client/src/components/ui/chart.tsx +35 -49
  19. package/template-vite-react/client/src/components/ui/checkbox.tsx +10 -7
  20. package/template-vite-react/client/src/components/ui/collapsible.tsx +20 -6
  21. package/template-vite-react/client/src/components/ui/command.tsx +52 -40
  22. package/template-vite-react/client/src/components/ui/context-menu.tsx +170 -117
  23. package/template-vite-react/client/src/components/ui/dialog.tsx +37 -52
  24. package/template-vite-react/client/src/components/ui/drawer.tsx +12 -9
  25. package/template-vite-react/client/src/components/ui/dropdown-menu.tsx +194 -133
  26. package/template-vite-react/client/src/components/ui/hover-card.tsx +24 -29
  27. package/template-vite-react/client/src/components/ui/input-group.tsx +39 -29
  28. package/template-vite-react/client/src/components/ui/input-otp.tsx +7 -17
  29. package/template-vite-react/client/src/components/ui/input.tsx +4 -3
  30. package/template-vite-react/client/src/components/ui/label.tsx +9 -3
  31. package/template-vite-react/client/src/components/ui/menubar.tsx +160 -92
  32. package/template-vite-react/client/src/components/ui/navigation-menu.tsx +45 -45
  33. package/template-vite-react/client/src/components/ui/pagination.tsx +32 -35
  34. package/template-vite-react/client/src/components/ui/popover.tsx +20 -62
  35. package/template-vite-react/client/src/components/ui/progress.tsx +14 -64
  36. package/template-vite-react/client/src/components/ui/radio-group.tsx +20 -13
  37. package/template-vite-react/client/src/components/ui/resizable.tsx +18 -10
  38. package/template-vite-react/client/src/components/ui/scroll-area.tsx +13 -10
  39. package/template-vite-react/client/src/components/ui/select.tsx +122 -78
  40. package/template-vite-react/client/src/components/ui/separator.tsx +7 -4
  41. package/template-vite-react/client/src/components/ui/sheet.tsx +42 -41
  42. package/template-vite-react/client/src/components/ui/sidebar.tsx +162 -156
  43. package/template-vite-react/client/src/components/ui/skeleton.tsx +1 -1
  44. package/template-vite-react/client/src/components/ui/slider.tsx +52 -22
  45. package/template-vite-react/client/src/components/ui/sonner.tsx +44 -26
  46. package/template-vite-react/client/src/components/ui/switch.tsx +9 -8
  47. package/template-vite-react/client/src/components/ui/table.tsx +5 -5
  48. package/template-vite-react/client/src/components/ui/tabs.tsx +24 -38
  49. package/template-vite-react/client/src/components/ui/textarea.tsx +1 -1
  50. package/template-vite-react/client/src/components/ui/toggle-group.tsx +14 -20
  51. package/template-vite-react/client/src/components/ui/toggle.tsx +13 -10
  52. package/template-vite-react/client/src/components/ui/tooltip.tsx +30 -33
  53. package/template-vite-react/client/src/index.css +130 -0
  54. package/template-vite-react/client/src/main.tsx +1 -4
  55. package/template-vite-react/client/src/pages/home/index.tsx +5 -5
  56. package/template-vite-react/components.json +2 -6
  57. package/template-vite-react/eslint.config.js +11 -0
  58. package/template-vite-react/package.json +27 -2
  59. package/template-vite-react/vite.config.ts +5 -0
  60. package/template-vite-react/client/src/components/header.tsx +0 -22
  61. package/template-vite-react/client/src/components/theme-provider.tsx +0 -45
  62. package/template-vite-react/client/src/components/ui/icons/file-ae-colorful-icon.tsx +0 -21
  63. package/template-vite-react/client/src/components/ui/icons/file-ai-colorful-icon.tsx +0 -36
  64. package/template-vite-react/client/src/components/ui/icons/file-android-colorful-icon.tsx +0 -33
  65. package/template-vite-react/client/src/components/ui/icons/file-audio-colorful-icon.tsx +0 -21
  66. package/template-vite-react/client/src/components/ui/icons/file-code-colorful-icon.tsx +0 -28
  67. package/template-vite-react/client/src/components/ui/icons/file-csv-colorful-icon.tsx +0 -21
  68. package/template-vite-react/client/src/components/ui/icons/file-eml-colorful-icon.tsx +0 -29
  69. package/template-vite-react/client/src/components/ui/icons/file-ios-colorful-icon.tsx +0 -25
  70. package/template-vite-react/client/src/components/ui/icons/file-keynote-colorful-icon.tsx +0 -29
  71. package/template-vite-react/client/src/components/ui/icons/file-pages-colorful-icon.tsx +0 -29
  72. package/template-vite-react/client/src/components/ui/icons/file-ps-colorful-icon.tsx +0 -21
  73. package/template-vite-react/client/src/components/ui/icons/file-sketch-colorful-icon.tsx +0 -21
  74. package/template-vite-react/client/src/components/ui/icons/file-slide-colorful-icon.tsx +0 -21
  75. package/template-vite-react/client/src/components/ui/icons/file-vcf-colorful-icon.tsx +0 -29
  76. package/template-vite-react/client/src/components/ui/icons/file-wiki-excel-colorful-icon.tsx +0 -23
  77. package/template-vite-react/client/src/components/ui/icons/file-wiki-image-colorful-icon.tsx +0 -27
  78. package/template-vite-react/client/src/components/ui/icons/file-wiki-pdf-colorful-icon.tsx +0 -20
  79. package/template-vite-react/client/src/components/ui/icons/file-wiki-ppt-colorful-icon.tsx +0 -21
  80. package/template-vite-react/client/src/components/ui/icons/file-wiki-text-colorful-icon.tsx +0 -12
  81. package/template-vite-react/client/src/components/ui/icons/file-wiki-unknown-colorful-icon.tsx +0 -14
  82. package/template-vite-react/client/src/components/ui/icons/file-wiki-video-colorful-icon.tsx +0 -23
  83. package/template-vite-react/client/src/components/ui/icons/file-wiki-word-colorful-icon.tsx +0 -38
  84. package/template-vite-react/client/src/components/ui/icons/file-wiki-zip-colorful-icon.tsx +0 -21
  85. package/template-vite-react/client/src/types/index.ts +0 -1
@@ -4,13 +4,18 @@ import { cva, type VariantProps } from "class-variance-authority"
4
4
  import { cn } from "@/lib/utils"
5
5
 
6
6
  const alertVariants = cva(
7
- "group/alert relative grid w-full gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4",
7
+ "relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
8
8
  {
9
9
  variants: {
10
10
  variant: {
11
11
  default: "bg-card text-card-foreground",
12
12
  destructive:
13
- "bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current",
13
+ "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
14
+ // 新增语义化 success/warning variant
15
+ success:
16
+ "bg-success text-success-foreground border-success/50 [&>svg]:text-success-foreground *:data-[slot=alert-description]:text-success-foreground/90",
17
+ warning:
18
+ "bg-warning text-warning-foreground border-warning/50 [&>svg]:text-warning-foreground *:data-[slot=alert-description]:text-warning-foreground/90",
14
19
  },
15
20
  },
16
21
  defaultVariants: {
@@ -39,7 +44,7 @@ function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
39
44
  <div
40
45
  data-slot="alert-title"
41
46
  className={cn(
42
- "font-medium group-has-[>svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground",
47
+ "col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
43
48
  className
44
49
  )}
45
50
  {...props}
@@ -55,7 +60,7 @@ function AlertDescription({
55
60
  <div
56
61
  data-slot="alert-description"
57
62
  className={cn(
58
- "text-sm text-balance text-muted-foreground md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4",
63
+ "text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
59
64
  className
60
65
  )}
61
66
  {...props}
@@ -63,14 +68,4 @@ function AlertDescription({
63
68
  )
64
69
  }
65
70
 
66
- function AlertAction({ className, ...props }: React.ComponentProps<"div">) {
67
- return (
68
- <div
69
- data-slot="alert-action"
70
- className={cn("absolute top-2 right-2", className)}
71
- {...props}
72
- />
73
- )
74
- }
75
-
76
- export { Alert, AlertTitle, AlertDescription, AlertAction }
71
+ export { Alert, AlertTitle, AlertDescription }
@@ -1,22 +1,11 @@
1
- import { cn } from "@/lib/utils"
1
+ "use client"
2
+
3
+ import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
2
4
 
3
5
  function AspectRatio({
4
- ratio,
5
- className,
6
6
  ...props
7
- }: React.ComponentProps<"div"> & { ratio: number }) {
8
- return (
9
- <div
10
- data-slot="aspect-ratio"
11
- style={
12
- {
13
- "--ratio": ratio,
14
- } as React.CSSProperties
15
- }
16
- className={cn("relative aspect-(--ratio)", className)}
17
- {...props}
18
- />
19
- )
7
+ }: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {
8
+ return <AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} />
20
9
  }
21
10
 
22
11
  export { AspectRatio }
@@ -1,23 +1,19 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from "react"
4
- import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar"
4
+ import * as AvatarPrimitive from "@radix-ui/react-avatar"
5
5
 
6
6
  import { cn } from "@/lib/utils"
7
7
 
8
8
  function Avatar({
9
9
  className,
10
- size = "default",
11
10
  ...props
12
- }: AvatarPrimitive.Root.Props & {
13
- size?: "default" | "sm" | "lg"
14
- }) {
11
+ }: React.ComponentProps<typeof AvatarPrimitive.Root>) {
15
12
  return (
16
13
  <AvatarPrimitive.Root
17
14
  data-slot="avatar"
18
- data-size={size}
19
15
  className={cn(
20
- "group/avatar relative flex size-8 shrink-0 rounded-full select-none after:absolute after:inset-0 after:rounded-full after:border after:border-border after:mix-blend-darken data-[size=lg]:size-10 data-[size=sm]:size-6 dark:after:mix-blend-lighten",
16
+ "relative flex size-8 shrink-0 overflow-hidden rounded-full",
21
17
  className
22
18
  )}
23
19
  {...props}
@@ -25,14 +21,14 @@ function Avatar({
25
21
  )
26
22
  }
27
23
 
28
- function AvatarImage({ className, ...props }: AvatarPrimitive.Image.Props) {
24
+ function AvatarImage({
25
+ className,
26
+ ...props
27
+ }: React.ComponentProps<typeof AvatarPrimitive.Image>) {
29
28
  return (
30
29
  <AvatarPrimitive.Image
31
30
  data-slot="avatar-image"
32
- className={cn(
33
- "aspect-square size-full rounded-full object-cover",
34
- className
35
- )}
31
+ className={cn("aspect-square size-full", className)}
36
32
  {...props}
37
33
  />
38
34
  )
@@ -41,28 +37,12 @@ function AvatarImage({ className, ...props }: AvatarPrimitive.Image.Props) {
41
37
  function AvatarFallback({
42
38
  className,
43
39
  ...props
44
- }: AvatarPrimitive.Fallback.Props) {
40
+ }: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
45
41
  return (
46
42
  <AvatarPrimitive.Fallback
47
43
  data-slot="avatar-fallback"
48
44
  className={cn(
49
- "flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs",
50
- className
51
- )}
52
- {...props}
53
- />
54
- )
55
- }
56
-
57
- function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) {
58
- return (
59
- <span
60
- data-slot="avatar-badge"
61
- className={cn(
62
- "absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground bg-blend-color ring-2 ring-background select-none",
63
- "group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden",
64
- "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2",
65
- "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2",
45
+ "bg-muted flex size-full items-center justify-center rounded-full",
66
46
  className
67
47
  )}
68
48
  {...props}
@@ -70,40 +50,4 @@ function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) {
70
50
  )
71
51
  }
72
52
 
73
- function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) {
74
- return (
75
- <div
76
- data-slot="avatar-group"
77
- className={cn(
78
- "group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background",
79
- className
80
- )}
81
- {...props}
82
- />
83
- )
84
- }
85
-
86
- function AvatarGroupCount({
87
- className,
88
- ...props
89
- }: React.ComponentProps<"div">) {
90
- return (
91
- <div
92
- data-slot="avatar-group-count"
93
- className={cn(
94
- "relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3",
95
- className
96
- )}
97
- {...props}
98
- />
99
- )
100
- }
101
-
102
- export {
103
- Avatar,
104
- AvatarImage,
105
- AvatarFallback,
106
- AvatarGroup,
107
- AvatarGroupCount,
108
- AvatarBadge,
109
- }
53
+ export { Avatar, AvatarImage, AvatarFallback }
@@ -1,24 +1,26 @@
1
- import { mergeProps } from "@base-ui/react/merge-props"
2
- import { useRender } from "@base-ui/react/use-render"
1
+ import * as React from "react"
3
2
  import { cva, type VariantProps } from "class-variance-authority"
4
3
 
5
4
  import { cn } from "@/lib/utils"
6
5
 
7
6
  const badgeVariants = cva(
8
- "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!",
7
+ // Whitespace-nowrap: Badges should never wrap.
8
+ // hover-elevate: adds subtle dark overlay on hover for interactive feedback
9
+ "whitespace-nowrap inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold hover-elevate",
9
10
  {
10
11
  variants: {
11
12
  variant: {
12
- default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
13
+ default:
14
+ // Primary badge with subtle shadow for elevation
15
+ "border-transparent bg-primary text-primary-foreground shadow-xs",
13
16
  secondary:
14
- "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
17
+ // Subtle filled badge for secondary information
18
+ "border-transparent bg-secondary text-secondary-foreground",
15
19
  destructive:
16
- "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
17
- outline:
18
- "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
19
- ghost:
20
- "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
21
- link: "text-primary underline-offset-4 hover:underline",
20
+ // Error/danger state with matching shadow
21
+ "border-transparent bg-destructive text-destructive-foreground shadow-xs",
22
+ // Outline uses badge-outline variable to blend with parent background
23
+ outline: "border [border-color:var(--badge-outline)] shadow-xs",
22
24
  },
23
25
  },
24
26
  defaultVariants: {
@@ -27,26 +29,14 @@ const badgeVariants = cva(
27
29
  }
28
30
  )
29
31
 
30
- function Badge({
31
- className,
32
- variant = "default",
33
- render,
34
- ...props
35
- }: useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>) {
36
- return useRender({
37
- defaultTagName: "span",
38
- props: mergeProps<"span">(
39
- {
40
- className: cn(badgeVariants({ variant }), className),
41
- },
42
- props
43
- ),
44
- render,
45
- state: {
46
- slot: "badge",
47
- variant,
48
- },
49
- })
32
+ export interface BadgeProps
33
+ extends React.HTMLAttributes<HTMLDivElement>,
34
+ VariantProps<typeof badgeVariants> {}
35
+
36
+ function Badge({ className, variant, ...props }: BadgeProps) {
37
+ return (
38
+ <div className={cn(badgeVariants({ variant }), className)} {...props} />
39
+ );
50
40
  }
51
41
 
52
42
  export { Badge, badgeVariants }
@@ -1,19 +1,11 @@
1
1
  import * as React from "react"
2
- import { mergeProps } from "@base-ui/react/merge-props"
3
- import { useRender } from "@base-ui/react/use-render"
2
+ import { Slot } from "@radix-ui/react-slot"
3
+ import { ChevronRight, MoreHorizontal } from "lucide-react"
4
4
 
5
5
  import { cn } from "@/lib/utils"
6
- import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"
7
6
 
8
- function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
9
- return (
10
- <nav
11
- aria-label="breadcrumb"
12
- data-slot="breadcrumb"
13
- className={cn(className)}
14
- {...props}
15
- />
16
- )
7
+ function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
8
+ return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />
17
9
  }
18
10
 
19
11
  function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
@@ -21,7 +13,7 @@ function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
21
13
  <ol
22
14
  data-slot="breadcrumb-list"
23
15
  className={cn(
24
- "flex flex-wrap items-center gap-1.5 text-sm wrap-break-word text-muted-foreground",
16
+ "text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5",
25
17
  className
26
18
  )}
27
19
  {...props}
@@ -33,30 +25,28 @@ function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
33
25
  return (
34
26
  <li
35
27
  data-slot="breadcrumb-item"
36
- className={cn("inline-flex items-center gap-1", className)}
28
+ className={cn("inline-flex items-center gap-1.5", className)}
37
29
  {...props}
38
30
  />
39
31
  )
40
32
  }
41
33
 
42
34
  function BreadcrumbLink({
35
+ asChild,
43
36
  className,
44
- render,
45
37
  ...props
46
- }: useRender.ComponentProps<"a">) {
47
- return useRender({
48
- defaultTagName: "a",
49
- props: mergeProps<"a">(
50
- {
51
- className: cn("transition-colors hover:text-foreground", className),
52
- },
53
- props
54
- ),
55
- render,
56
- state: {
57
- slot: "breadcrumb-link",
58
- },
59
- })
38
+ }: React.ComponentProps<"a"> & {
39
+ asChild?: boolean
40
+ }) {
41
+ const Comp = asChild ? Slot : "a"
42
+
43
+ return (
44
+ <Comp
45
+ data-slot="breadcrumb-link"
46
+ className={cn("hover:text-foreground transition-colors", className)}
47
+ {...props}
48
+ />
49
+ )
60
50
  }
61
51
 
62
52
  function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
@@ -66,7 +56,7 @@ function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
66
56
  role="link"
67
57
  aria-disabled="true"
68
58
  aria-current="page"
69
- className={cn("font-normal text-foreground", className)}
59
+ className={cn("text-foreground font-normal", className)}
70
60
  {...props}
71
61
  />
72
62
  )
@@ -85,9 +75,7 @@ function BreadcrumbSeparator({
85
75
  className={cn("[&>svg]:size-3.5", className)}
86
76
  {...props}
87
77
  >
88
- {children ?? (
89
- <ChevronRightIcon />
90
- )}
78
+ {children ?? <ChevronRight />}
91
79
  </li>
92
80
  )
93
81
  }
@@ -101,14 +89,10 @@ function BreadcrumbEllipsis({
101
89
  data-slot="breadcrumb-ellipsis"
102
90
  role="presentation"
103
91
  aria-hidden="true"
104
- className={cn(
105
- "flex size-5 items-center justify-center [&>svg]:size-4",
106
- className
107
- )}
92
+ className={cn("flex size-9 items-center justify-center", className)}
108
93
  {...props}
109
94
  >
110
- <MoreHorizontalIcon
111
- />
95
+ <MoreHorizontal className="size-4" />
112
96
  <span className="sr-only">More</span>
113
97
  </span>
114
98
  )
@@ -1,36 +1,41 @@
1
- import { Button as ButtonPrimitive } from "@base-ui/react/button"
1
+ import * as React from "react"
2
+ import { Slot } from "@radix-ui/react-slot"
2
3
  import { cva, type VariantProps } from "class-variance-authority"
3
4
 
4
5
  import { cn } from "@/lib/utils"
5
6
 
6
7
  const buttonVariants = cva(
7
- "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
8
+ // Base button styles with elevate system for hover/active states.
9
+ // hover-elevate: applies subtle dark overlay on hover
10
+ // active-elevate-2: applies stronger dark overlay when pressed
11
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 hover-elevate active-elevate-2",
8
12
  {
9
13
  variants: {
10
14
  variant: {
11
- default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
15
+ default:
16
+ // Solid primary button with computed border for depth
17
+ "bg-primary text-primary-foreground border border-primary-border",
18
+ destructive:
19
+ // Destructive action button with matching border
20
+ "bg-destructive text-destructive-foreground border border-destructive-border",
12
21
  outline:
13
- "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
22
+ // Shows the background color of whatever card / sidebar / accent background it is inside of.
23
+ // Inherits the current text color.
24
+ "border [border-color:var(--button-outline)] shadow-xs active:shadow-none",
14
25
  secondary:
15
- "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
16
- ghost:
17
- "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
18
- destructive:
19
- "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
20
- link: "text-primary underline-offset-4 hover:underline",
26
+ // Subtle filled button for secondary actions
27
+ "bg-secondary text-secondary-foreground border border-secondary-border",
28
+ // Add a transparent border so that when someone toggles a border on later, it doesn't shift layout/size.
29
+ ghost: "border border-transparent",
21
30
  },
31
+ // Heights are set as "min" heights, because sometimes AI will place large amount of content
32
+ // inside buttons. With a min-height they will look appropriate with small amounts of content,
33
+ // but will expand to fit large amounts of content.
22
34
  size: {
23
- default:
24
- "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
25
- xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
26
- sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
27
- lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
28
- icon: "size-8",
29
- "icon-xs":
30
- "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
31
- "icon-sm":
32
- "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
33
- "icon-lg": "size-9",
35
+ default: "min-h-9 px-4 py-2",
36
+ sm: "min-h-8 rounded-md px-3 text-xs",
37
+ lg: "min-h-10 rounded-md px-8",
38
+ icon: "h-9 w-9",
34
39
  },
35
40
  },
36
41
  defaultVariants: {
@@ -42,12 +47,18 @@ const buttonVariants = cva(
42
47
 
43
48
  function Button({
44
49
  className,
45
- variant = "default",
46
- size = "default",
50
+ variant,
51
+ size,
52
+ asChild = false,
47
53
  ...props
48
- }: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
54
+ }: React.ComponentProps<"button"> &
55
+ VariantProps<typeof buttonVariants> & {
56
+ asChild?: boolean
57
+ }) {
58
+ const Comp = asChild ? Slot : "button"
59
+
49
60
  return (
50
- <ButtonPrimitive
61
+ <Comp
51
62
  data-slot="button"
52
63
  className={cn(buttonVariants({ variant, size, className }))}
53
64
  {...props}