@lark-apaas/coding-templates 0.1.5 → 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 (82) 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/components/layout.tsx +0 -2
  5. package/template-vite-react/client/src/components/ui/README.md +134 -0
  6. package/template-vite-react/client/src/components/ui/accordion.tsx +22 -28
  7. package/template-vite-react/client/src/components/ui/alert-dialog.tsx +34 -64
  8. package/template-vite-react/client/src/components/ui/alert.tsx +10 -15
  9. package/template-vite-react/client/src/components/ui/aspect-ratio.tsx +5 -16
  10. package/template-vite-react/client/src/components/ui/avatar.tsx +11 -67
  11. package/template-vite-react/client/src/components/ui/badge.tsx +21 -31
  12. package/template-vite-react/client/src/components/ui/breadcrumb.tsx +23 -39
  13. package/template-vite-react/client/src/components/ui/button.tsx +36 -25
  14. package/template-vite-react/client/src/components/ui/calendar.tsx +37 -43
  15. package/template-vite-react/client/src/components/ui/card.tsx +73 -94
  16. package/template-vite-react/client/src/components/ui/carousel.tsx +7 -8
  17. package/template-vite-react/client/src/components/ui/chart.tsx +35 -49
  18. package/template-vite-react/client/src/components/ui/checkbox.tsx +10 -7
  19. package/template-vite-react/client/src/components/ui/collapsible.tsx +20 -6
  20. package/template-vite-react/client/src/components/ui/command.tsx +52 -40
  21. package/template-vite-react/client/src/components/ui/context-menu.tsx +170 -117
  22. package/template-vite-react/client/src/components/ui/dialog.tsx +37 -52
  23. package/template-vite-react/client/src/components/ui/drawer.tsx +12 -9
  24. package/template-vite-react/client/src/components/ui/dropdown-menu.tsx +194 -133
  25. package/template-vite-react/client/src/components/ui/hover-card.tsx +24 -29
  26. package/template-vite-react/client/src/components/ui/input-group.tsx +39 -29
  27. package/template-vite-react/client/src/components/ui/input-otp.tsx +7 -17
  28. package/template-vite-react/client/src/components/ui/input.tsx +4 -3
  29. package/template-vite-react/client/src/components/ui/label.tsx +9 -3
  30. package/template-vite-react/client/src/components/ui/menubar.tsx +160 -92
  31. package/template-vite-react/client/src/components/ui/navigation-menu.tsx +45 -45
  32. package/template-vite-react/client/src/components/ui/pagination.tsx +32 -35
  33. package/template-vite-react/client/src/components/ui/popover.tsx +20 -62
  34. package/template-vite-react/client/src/components/ui/progress.tsx +14 -64
  35. package/template-vite-react/client/src/components/ui/radio-group.tsx +20 -13
  36. package/template-vite-react/client/src/components/ui/resizable.tsx +18 -10
  37. package/template-vite-react/client/src/components/ui/scroll-area.tsx +13 -10
  38. package/template-vite-react/client/src/components/ui/select.tsx +122 -78
  39. package/template-vite-react/client/src/components/ui/separator.tsx +7 -4
  40. package/template-vite-react/client/src/components/ui/sheet.tsx +42 -41
  41. package/template-vite-react/client/src/components/ui/sidebar.tsx +162 -156
  42. package/template-vite-react/client/src/components/ui/skeleton.tsx +1 -1
  43. package/template-vite-react/client/src/components/ui/slider.tsx +52 -22
  44. package/template-vite-react/client/src/components/ui/sonner.tsx +44 -26
  45. package/template-vite-react/client/src/components/ui/switch.tsx +9 -8
  46. package/template-vite-react/client/src/components/ui/table.tsx +5 -5
  47. package/template-vite-react/client/src/components/ui/tabs.tsx +24 -38
  48. package/template-vite-react/client/src/components/ui/textarea.tsx +1 -1
  49. package/template-vite-react/client/src/components/ui/toggle-group.tsx +14 -20
  50. package/template-vite-react/client/src/components/ui/toggle.tsx +13 -10
  51. package/template-vite-react/client/src/components/ui/tooltip.tsx +30 -33
  52. package/template-vite-react/client/src/index.css +130 -0
  53. package/template-vite-react/client/src/main.tsx +1 -4
  54. package/template-vite-react/components.json +2 -6
  55. package/template-vite-react/eslint.config.js +11 -0
  56. package/template-vite-react/package.json +27 -2
  57. package/template-vite-react/client/src/components/header.tsx +0 -22
  58. package/template-vite-react/client/src/components/theme-provider.tsx +0 -45
  59. package/template-vite-react/client/src/components/ui/icons/file-ae-colorful-icon.tsx +0 -21
  60. package/template-vite-react/client/src/components/ui/icons/file-ai-colorful-icon.tsx +0 -36
  61. package/template-vite-react/client/src/components/ui/icons/file-android-colorful-icon.tsx +0 -33
  62. package/template-vite-react/client/src/components/ui/icons/file-audio-colorful-icon.tsx +0 -21
  63. package/template-vite-react/client/src/components/ui/icons/file-code-colorful-icon.tsx +0 -28
  64. package/template-vite-react/client/src/components/ui/icons/file-csv-colorful-icon.tsx +0 -21
  65. package/template-vite-react/client/src/components/ui/icons/file-eml-colorful-icon.tsx +0 -29
  66. package/template-vite-react/client/src/components/ui/icons/file-ios-colorful-icon.tsx +0 -25
  67. package/template-vite-react/client/src/components/ui/icons/file-keynote-colorful-icon.tsx +0 -29
  68. package/template-vite-react/client/src/components/ui/icons/file-pages-colorful-icon.tsx +0 -29
  69. package/template-vite-react/client/src/components/ui/icons/file-ps-colorful-icon.tsx +0 -21
  70. package/template-vite-react/client/src/components/ui/icons/file-sketch-colorful-icon.tsx +0 -21
  71. package/template-vite-react/client/src/components/ui/icons/file-slide-colorful-icon.tsx +0 -21
  72. package/template-vite-react/client/src/components/ui/icons/file-vcf-colorful-icon.tsx +0 -29
  73. package/template-vite-react/client/src/components/ui/icons/file-wiki-excel-colorful-icon.tsx +0 -23
  74. package/template-vite-react/client/src/components/ui/icons/file-wiki-image-colorful-icon.tsx +0 -27
  75. package/template-vite-react/client/src/components/ui/icons/file-wiki-pdf-colorful-icon.tsx +0 -20
  76. package/template-vite-react/client/src/components/ui/icons/file-wiki-ppt-colorful-icon.tsx +0 -21
  77. package/template-vite-react/client/src/components/ui/icons/file-wiki-text-colorful-icon.tsx +0 -12
  78. package/template-vite-react/client/src/components/ui/icons/file-wiki-unknown-colorful-icon.tsx +0 -14
  79. package/template-vite-react/client/src/components/ui/icons/file-wiki-video-colorful-icon.tsx +0 -23
  80. package/template-vite-react/client/src/components/ui/icons/file-wiki-word-colorful-icon.tsx +0 -38
  81. package/template-vite-react/client/src/components/ui/icons/file-wiki-zip-colorful-icon.tsx +0 -21
  82. package/template-vite-react/client/src/types/index.ts +0 -1
@@ -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}
@@ -1,14 +1,15 @@
1
+ "use client"
2
+
1
3
  import * as React from "react"
2
4
  import {
3
- DayPicker,
4
- getDefaultClassNames,
5
- type DayButton,
6
- type Locale,
7
- } from "react-day-picker"
5
+ ChevronDownIcon,
6
+ ChevronLeftIcon,
7
+ ChevronRightIcon,
8
+ } from "lucide-react"
9
+ import { DayButton, DayPicker, getDefaultClassNames } from "react-day-picker"
8
10
 
9
11
  import { cn } from "@/lib/utils"
10
12
  import { Button, buttonVariants } from "@/components/ui/button"
11
- import { ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon } from "lucide-react"
12
13
 
13
14
  function Calendar({
14
15
  className,
@@ -16,7 +17,6 @@ function Calendar({
16
17
  showOutsideDays = true,
17
18
  captionLayout = "label",
18
19
  buttonVariant = "ghost",
19
- locale,
20
20
  formatters,
21
21
  components,
22
22
  ...props
@@ -29,95 +29,88 @@ function Calendar({
29
29
  <DayPicker
30
30
  showOutsideDays={showOutsideDays}
31
31
  className={cn(
32
- "group/calendar bg-background p-2 [--cell-radius:var(--radius-md)] [--cell-size:--spacing(7)] in-data-[slot=card-content]:bg-transparent in-data-[slot=popover-content]:bg-transparent",
32
+ "bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
33
33
  String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
34
34
  String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
35
35
  className
36
36
  )}
37
37
  captionLayout={captionLayout}
38
- locale={locale}
39
38
  formatters={{
40
39
  formatMonthDropdown: (date) =>
41
- date.toLocaleString(locale?.code, { month: "short" }),
40
+ date.toLocaleString("default", { month: "short" }),
42
41
  ...formatters,
43
42
  }}
44
43
  classNames={{
45
44
  root: cn("w-fit", defaultClassNames.root),
46
45
  months: cn(
47
- "relative flex flex-col gap-4 md:flex-row",
46
+ "flex gap-4 flex-col md:flex-row relative",
48
47
  defaultClassNames.months
49
48
  ),
50
- month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
49
+ month: cn("flex flex-col w-full gap-4", defaultClassNames.month),
51
50
  nav: cn(
52
- "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
51
+ "flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between",
53
52
  defaultClassNames.nav
54
53
  ),
55
54
  button_previous: cn(
56
55
  buttonVariants({ variant: buttonVariant }),
57
- "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
56
+ "size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
58
57
  defaultClassNames.button_previous
59
58
  ),
60
59
  button_next: cn(
61
60
  buttonVariants({ variant: buttonVariant }),
62
- "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
61
+ "size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
63
62
  defaultClassNames.button_next
64
63
  ),
65
64
  month_caption: cn(
66
- "flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)",
65
+ "flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)",
67
66
  defaultClassNames.month_caption
68
67
  ),
69
68
  dropdowns: cn(
70
- "flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium",
69
+ "w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5",
71
70
  defaultClassNames.dropdowns
72
71
  ),
73
72
  dropdown_root: cn(
74
- "relative rounded-(--cell-radius)",
73
+ "relative has-focus:border-ring border border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] rounded-md",
75
74
  defaultClassNames.dropdown_root
76
75
  ),
77
76
  dropdown: cn(
78
- "absolute inset-0 bg-popover opacity-0",
77
+ "absolute bg-popover inset-0 opacity-0",
79
78
  defaultClassNames.dropdown
80
79
  ),
81
80
  caption_label: cn(
82
- "font-medium select-none",
81
+ "select-none font-medium",
83
82
  captionLayout === "label"
84
83
  ? "text-sm"
85
- : "flex items-center gap-1 rounded-(--cell-radius) text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
84
+ : "rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5",
86
85
  defaultClassNames.caption_label
87
86
  ),
88
87
  table: "w-full border-collapse",
89
88
  weekdays: cn("flex", defaultClassNames.weekdays),
90
89
  weekday: cn(
91
- "flex-1 rounded-(--cell-radius) text-[0.8rem] font-normal text-muted-foreground select-none",
90
+ "text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none",
92
91
  defaultClassNames.weekday
93
92
  ),
94
- week: cn("mt-2 flex w-full", defaultClassNames.week),
93
+ week: cn("flex w-full mt-2", defaultClassNames.week),
95
94
  week_number_header: cn(
96
- "w-(--cell-size) select-none",
95
+ "select-none w-(--cell-size)",
97
96
  defaultClassNames.week_number_header
98
97
  ),
99
98
  week_number: cn(
100
- "text-[0.8rem] text-muted-foreground select-none",
99
+ "text-[0.8rem] select-none text-muted-foreground",
101
100
  defaultClassNames.week_number
102
101
  ),
103
102
  day: cn(
104
- "group/day relative aspect-square h-full w-full rounded-(--cell-radius) p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius)",
105
- props.showWeekNumber
106
- ? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)"
107
- : "[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)",
103
+ "relative w-full h-full p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none",
108
104
  defaultClassNames.day
109
105
  ),
110
106
  range_start: cn(
111
- "relative isolate z-0 rounded-l-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:right-0 after:w-4 after:bg-muted",
107
+ "rounded-l-md bg-accent",
112
108
  defaultClassNames.range_start
113
109
  ),
114
110
  range_middle: cn("rounded-none", defaultClassNames.range_middle),
115
- range_end: cn(
116
- "relative isolate z-0 rounded-r-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:left-0 after:w-4 after:bg-muted",
117
- defaultClassNames.range_end
118
- ),
111
+ range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
119
112
  today: cn(
120
- "rounded-(--cell-radius) bg-muted text-foreground data-[selected=true]:rounded-none",
113
+ "bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",
121
114
  defaultClassNames.today
122
115
  ),
123
116
  outside: cn(
@@ -151,7 +144,10 @@ function Calendar({
151
144
 
152
145
  if (orientation === "right") {
153
146
  return (
154
- <ChevronRightIcon className={cn("size-4", className)} {...props} />
147
+ <ChevronRightIcon
148
+ className={cn("size-4", className)}
149
+ {...props}
150
+ />
155
151
  )
156
152
  }
157
153
 
@@ -159,9 +155,7 @@ function Calendar({
159
155
  <ChevronDownIcon className={cn("size-4", className)} {...props} />
160
156
  )
161
157
  },
162
- DayButton: ({ ...props }) => (
163
- <CalendarDayButton locale={locale} {...props} />
164
- ),
158
+ DayButton: CalendarDayButton,
165
159
  WeekNumber: ({ children, ...props }) => {
166
160
  return (
167
161
  <td {...props}>
@@ -182,9 +176,8 @@ function CalendarDayButton({
182
176
  className,
183
177
  day,
184
178
  modifiers,
185
- locale,
186
179
  ...props
187
- }: React.ComponentProps<typeof DayButton> & { locale?: Partial<Locale> }) {
180
+ }: React.ComponentProps<typeof DayButton>) {
188
181
  const defaultClassNames = getDefaultClassNames()
189
182
 
190
183
  const ref = React.useRef<HTMLButtonElement>(null)
@@ -194,9 +187,10 @@ function CalendarDayButton({
194
187
 
195
188
  return (
196
189
  <Button
190
+ ref={ref}
197
191
  variant="ghost"
198
192
  size="icon"
199
- data-day={day.date.toLocaleDateString(locale?.code)}
193
+ data-day={day.date.toLocaleDateString()}
200
194
  data-selected-single={
201
195
  modifiers.selected &&
202
196
  !modifiers.range_start &&
@@ -207,7 +201,7 @@ function CalendarDayButton({
207
201
  data-range-end={modifiers.range_end}
208
202
  data-range-middle={modifiers.range_middle}
209
203
  className={cn(
210
- "relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 border-0 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-ring/50 data-[range-end=true]:rounded-(--cell-radius) data-[range-end=true]:rounded-r-(--cell-radius) data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-muted data-[range-middle=true]:text-foreground data-[range-start=true]:rounded-(--cell-radius) data-[range-start=true]:rounded-l-(--cell-radius) data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-foreground [&>span]:text-xs [&>span]:opacity-70",
204
+ "data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 dark:hover:text-accent-foreground flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md [&>span]:text-xs [&>span]:opacity-70",
211
205
  defaultClassNames.day,
212
206
  className
213
207
  )}