create-ec-app 1.8.0 → 1.9.0

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 (103) hide show
  1. package/README.md +72 -17
  2. package/dist/cssScope.js +3 -5
  3. package/dist/cssScope.js.map +1 -1
  4. package/dist/index.d.ts +46 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +129 -53
  7. package/dist/index.js.map +1 -1
  8. package/dist/libFunctions.d.ts +13 -6
  9. package/dist/libFunctions.d.ts.map +1 -1
  10. package/dist/libFunctions.js +24 -9
  11. package/dist/libFunctions.js.map +1 -1
  12. package/dist/pcf.d.ts.map +1 -1
  13. package/dist/pcf.js +4 -1
  14. package/dist/pcf.js.map +1 -1
  15. package/dist/portalContainers.js +7 -5
  16. package/dist/portalContainers.js.map +1 -1
  17. package/package.json +18 -11
  18. package/scripts/build-generated.mjs +59 -0
  19. package/scripts/refresh-shadcn-template.ts +406 -0
  20. package/scripts/smoke-scaffold.mjs +245 -0
  21. package/templates/base/eslint.config.js +1 -1
  22. package/templates/base/package-lock.json +380 -476
  23. package/templates/base/package.json +14 -19
  24. package/templates/pcf/base/package-lock.json +35 -53
  25. package/templates/targets/code-apps/AGENTS.md +1 -1
  26. package/templates/targets/code-apps/CLAUDE.md +1 -0
  27. package/templates/targets/code-apps/package.patch.json +1 -1
  28. package/templates/targets/power-pages/AGENTS.md +1 -1
  29. package/templates/targets/power-pages/CLAUDE.md +1 -0
  30. package/templates/targets/power-pages/README.md +22 -2
  31. package/templates/targets/power-pages/src/App.patch.tsx +3 -1
  32. package/templates/targets/power-pages/src/components/shared/AuthError.tsx +18 -0
  33. package/templates/targets/power-pages/src/context/AuthContext.tsx +0 -4
  34. package/templates/targets/swa/CLAUDE.md +1 -0
  35. package/templates/targets/webresource/AGENTS.md +5 -4
  36. package/templates/targets/webresource/CLAUDE.md +1 -0
  37. package/templates/targets/webresource/README.md +5 -5
  38. package/templates/ui/kendo/package.patch.json +2 -2
  39. package/templates/ui/shadcn-ui/SHADCN_TEMPLATE.md +20 -0
  40. package/templates/ui/shadcn-ui/package.patch.json +18 -9
  41. package/templates/ui/shadcn-ui/src/components/ui/accordion.tsx +79 -0
  42. package/templates/ui/shadcn-ui/src/components/ui/alert-dialog.tsx +199 -0
  43. package/templates/ui/shadcn-ui/src/components/ui/alert.tsx +76 -0
  44. package/templates/ui/shadcn-ui/src/components/ui/aspect-ratio.tsx +11 -0
  45. package/templates/ui/shadcn-ui/src/components/ui/attachment.tsx +206 -0
  46. package/templates/ui/shadcn-ui/src/components/ui/avatar.tsx +110 -0
  47. package/templates/ui/shadcn-ui/src/components/ui/badge.tsx +49 -0
  48. package/templates/ui/shadcn-ui/src/components/ui/breadcrumb.tsx +122 -0
  49. package/templates/ui/shadcn-ui/src/components/ui/bubble.tsx +125 -0
  50. package/templates/ui/shadcn-ui/src/components/ui/button-group.tsx +83 -0
  51. package/templates/ui/shadcn-ui/src/components/ui/button.tsx +67 -0
  52. package/templates/ui/shadcn-ui/src/components/ui/calendar.tsx +222 -0
  53. package/templates/ui/shadcn-ui/src/components/ui/card.tsx +103 -0
  54. package/templates/ui/shadcn-ui/src/components/ui/carousel.tsx +240 -0
  55. package/templates/ui/shadcn-ui/src/components/ui/chart.tsx +373 -0
  56. package/templates/ui/shadcn-ui/src/components/ui/checkbox.tsx +31 -0
  57. package/templates/ui/shadcn-ui/src/components/ui/collapsible.tsx +33 -0
  58. package/templates/ui/shadcn-ui/src/components/ui/combobox.tsx +299 -0
  59. package/templates/ui/shadcn-ui/src/components/ui/command.tsx +195 -0
  60. package/templates/ui/shadcn-ui/src/components/ui/context-menu.tsx +264 -0
  61. package/templates/ui/shadcn-ui/src/components/ui/dialog.tsx +170 -0
  62. package/templates/ui/shadcn-ui/src/components/ui/direction.tsx +22 -0
  63. package/templates/ui/shadcn-ui/src/components/ui/drawer.tsx +134 -0
  64. package/templates/ui/shadcn-ui/src/components/ui/dropdown-menu.tsx +272 -0
  65. package/templates/ui/shadcn-ui/src/components/ui/empty.tsx +104 -0
  66. package/templates/ui/shadcn-ui/src/components/ui/field.tsx +236 -0
  67. package/templates/ui/shadcn-ui/src/components/ui/hover-card.tsx +44 -0
  68. package/templates/ui/shadcn-ui/src/components/ui/input-group.tsx +156 -0
  69. package/templates/ui/shadcn-ui/src/components/ui/input-otp.tsx +87 -0
  70. package/templates/ui/shadcn-ui/src/components/ui/input.tsx +19 -0
  71. package/templates/ui/shadcn-ui/src/components/ui/item.tsx +196 -0
  72. package/templates/ui/shadcn-ui/src/components/ui/kbd.tsx +26 -0
  73. package/templates/ui/shadcn-ui/src/components/ui/label.tsx +22 -0
  74. package/templates/ui/shadcn-ui/src/components/ui/marker.tsx +69 -0
  75. package/templates/ui/shadcn-ui/src/components/ui/menubar.tsx +282 -0
  76. package/templates/ui/shadcn-ui/src/components/ui/message-scroller.tsx +129 -0
  77. package/templates/ui/shadcn-ui/src/components/ui/message.tsx +92 -0
  78. package/templates/ui/shadcn-ui/src/components/ui/native-select.tsx +61 -0
  79. package/templates/ui/shadcn-ui/src/components/ui/navigation-menu.tsx +164 -0
  80. package/templates/ui/shadcn-ui/src/components/ui/pagination.tsx +129 -0
  81. package/templates/ui/shadcn-ui/src/components/ui/popover.tsx +89 -0
  82. package/templates/ui/shadcn-ui/src/components/ui/progress.tsx +31 -0
  83. package/templates/ui/shadcn-ui/src/components/ui/radio-group.tsx +42 -0
  84. package/templates/ui/shadcn-ui/src/components/ui/resizable.tsx +50 -0
  85. package/templates/ui/shadcn-ui/src/components/ui/scroll-area.tsx +53 -0
  86. package/templates/ui/shadcn-ui/src/components/ui/select.tsx +194 -0
  87. package/templates/ui/shadcn-ui/src/components/ui/separator.tsx +26 -0
  88. package/templates/ui/shadcn-ui/src/components/ui/sheet.tsx +149 -0
  89. package/templates/ui/shadcn-ui/src/components/ui/sidebar.tsx +702 -0
  90. package/templates/ui/shadcn-ui/src/components/ui/skeleton.tsx +13 -0
  91. package/templates/ui/shadcn-ui/src/components/ui/slider.tsx +59 -0
  92. package/templates/ui/shadcn-ui/src/components/ui/sonner.tsx +47 -0
  93. package/templates/ui/shadcn-ui/src/components/ui/spinner.tsx +10 -0
  94. package/templates/ui/shadcn-ui/src/components/ui/switch.tsx +33 -0
  95. package/templates/ui/shadcn-ui/src/components/ui/table.tsx +114 -0
  96. package/templates/ui/shadcn-ui/src/components/ui/tabs.tsx +90 -0
  97. package/templates/ui/shadcn-ui/src/components/ui/textarea.tsx +18 -0
  98. package/templates/ui/shadcn-ui/src/components/ui/toggle-group.tsx +87 -0
  99. package/templates/ui/shadcn-ui/src/components/ui/toggle.tsx +45 -0
  100. package/templates/ui/shadcn-ui/src/components/ui/tooltip.tsx +59 -0
  101. package/templates/ui/shadcn-ui/src/index.patch.css +0 -118
  102. package/templates/ui/shadcn-ui/src/runtime/PortalContainer.ts +8 -0
  103. package/templates/base/biome.json +0 -54
@@ -0,0 +1,122 @@
1
+ import * as React from "react"
2
+ import { Slot } from "radix-ui"
3
+
4
+ import { cn } from "@/lib/utils"
5
+ import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"
6
+
7
+ function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
8
+ return (
9
+ <nav
10
+ aria-label="breadcrumb"
11
+ data-slot="breadcrumb"
12
+ className={cn(className)}
13
+ {...props}
14
+ />
15
+ )
16
+ }
17
+
18
+ function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
19
+ return (
20
+ <ol
21
+ data-slot="breadcrumb-list"
22
+ className={cn(
23
+ "flex flex-wrap items-center gap-1.5 text-sm wrap-break-word text-muted-foreground",
24
+ className
25
+ )}
26
+ {...props}
27
+ />
28
+ )
29
+ }
30
+
31
+ function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
32
+ return (
33
+ <li
34
+ data-slot="breadcrumb-item"
35
+ className={cn("inline-flex items-center gap-1", className)}
36
+ {...props}
37
+ />
38
+ )
39
+ }
40
+
41
+ function BreadcrumbLink({
42
+ asChild,
43
+ className,
44
+ ...props
45
+ }: React.ComponentProps<"a"> & {
46
+ asChild?: boolean
47
+ }) {
48
+ const Comp = asChild ? Slot.Root : "a"
49
+
50
+ return (
51
+ <Comp
52
+ data-slot="breadcrumb-link"
53
+ className={cn("transition-colors hover:text-foreground", className)}
54
+ {...props}
55
+ />
56
+ )
57
+ }
58
+
59
+ function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
60
+ return (
61
+ <span
62
+ data-slot="breadcrumb-page"
63
+ role="link"
64
+ aria-disabled="true"
65
+ aria-current="page"
66
+ className={cn("font-normal text-foreground", className)}
67
+ {...props}
68
+ />
69
+ )
70
+ }
71
+
72
+ function BreadcrumbSeparator({
73
+ children,
74
+ className,
75
+ ...props
76
+ }: React.ComponentProps<"li">) {
77
+ return (
78
+ <li
79
+ data-slot="breadcrumb-separator"
80
+ role="presentation"
81
+ aria-hidden="true"
82
+ className={cn("[&>svg]:size-3.5", className)}
83
+ {...props}
84
+ >
85
+ {children ?? (
86
+ <ChevronRightIcon />
87
+ )}
88
+ </li>
89
+ )
90
+ }
91
+
92
+ function BreadcrumbEllipsis({
93
+ className,
94
+ ...props
95
+ }: React.ComponentProps<"span">) {
96
+ return (
97
+ <span
98
+ data-slot="breadcrumb-ellipsis"
99
+ role="presentation"
100
+ aria-hidden="true"
101
+ className={cn(
102
+ "flex size-5 items-center justify-center [&>svg]:size-4",
103
+ className
104
+ )}
105
+ {...props}
106
+ >
107
+ <MoreHorizontalIcon
108
+ />
109
+ <span className="sr-only">More</span>
110
+ </span>
111
+ )
112
+ }
113
+
114
+ export {
115
+ Breadcrumb,
116
+ BreadcrumbList,
117
+ BreadcrumbItem,
118
+ BreadcrumbLink,
119
+ BreadcrumbPage,
120
+ BreadcrumbSeparator,
121
+ BreadcrumbEllipsis,
122
+ }
@@ -0,0 +1,125 @@
1
+ import * as React from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+ import { Slot } from "radix-ui"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ function BubbleGroup({ className, ...props }: React.ComponentProps<"div">) {
8
+ return (
9
+ <div
10
+ data-slot="bubble-group"
11
+ className={cn("flex min-w-0 flex-col gap-2", className)}
12
+ {...props}
13
+ />
14
+ )
15
+ }
16
+
17
+ const bubbleVariants = cva(
18
+ "group/bubble relative flex w-fit max-w-[80%] min-w-0 flex-col gap-1 group-data-[align=end]/message:self-end data-[align=end]:self-end data-[variant=ghost]:max-w-full",
19
+ {
20
+ variants: {
21
+ variant: {
22
+ default:
23
+ "*:data-[slot=bubble-content]:bg-primary *:data-[slot=bubble-content]:text-primary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-primary/80",
24
+ secondary:
25
+ "*:data-[slot=bubble-content]:bg-secondary *:data-[slot=bubble-content]:text-secondary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)]",
26
+ muted:
27
+ "*:data-[slot=bubble-content]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--muted),var(--foreground)_5%)]",
28
+ tinted:
29
+ "*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.93_calc(c*0.4)_h)] *:data-[slot=bubble-content]:text-foreground dark:*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.3_calc(c*0.4)_h)] [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.88_calc(c*0.5)_h)] dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.35_calc(c*0.5)_h)]",
30
+ outline:
31
+ "*:data-[slot=bubble-content]:border-border *:data-[slot=bubble-content]:bg-background [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-input/30",
32
+ ghost:
33
+ "border-none *:data-[slot=bubble-content]:rounded-none *:data-[slot=bubble-content]:bg-transparent *:data-[slot=bubble-content]:p-0 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted/50",
34
+ destructive:
35
+ "*:data-[slot=bubble-content]:bg-destructive/10 *:data-[slot=bubble-content]:text-destructive dark:*:data-[slot=bubble-content]:bg-destructive/20 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/20 dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/30",
36
+ },
37
+ },
38
+ defaultVariants: {
39
+ variant: "default",
40
+ },
41
+ }
42
+ )
43
+
44
+ function Bubble({
45
+ variant = "default",
46
+ align = "start",
47
+ className,
48
+ ...props
49
+ }: React.ComponentProps<"div"> &
50
+ VariantProps<typeof bubbleVariants> & {
51
+ align?: "start" | "end"
52
+ }) {
53
+ return (
54
+ <div
55
+ data-slot="bubble"
56
+ data-variant={variant}
57
+ data-align={align}
58
+ className={cn(bubbleVariants({ variant }), className)}
59
+ {...props}
60
+ />
61
+ )
62
+ }
63
+
64
+ function BubbleContent({
65
+ asChild = false,
66
+ className,
67
+ ...props
68
+ }: React.ComponentProps<"div"> & {
69
+ asChild?: boolean
70
+ }) {
71
+ const Comp = asChild ? Slot.Root : "div"
72
+
73
+ return (
74
+ <Comp
75
+ data-slot="bubble-content"
76
+ className={cn(
77
+ "w-fit max-w-full min-w-0 overflow-hidden rounded-xl border border-transparent px-3 py-2 text-sm leading-relaxed wrap-break-word group-data-[align=end]/bubble:self-end [button]:text-left [button,a]:transition-colors [button,a]:outline-none [button,a]:focus-visible:border-ring [button,a]:focus-visible:ring-3 [button,a]:focus-visible:ring-ring/50",
78
+ className
79
+ )}
80
+ {...props}
81
+ />
82
+ )
83
+ }
84
+
85
+ const bubbleReactionsVariants = cva(
86
+ "absolute z-10 flex w-fit shrink-0 items-center justify-center gap-1 rounded-full bg-muted px-1.5 py-0.5 text-sm ring-3 ring-card has-[button]:p-0",
87
+ {
88
+ variants: {
89
+ side: {
90
+ top: "top-0 -translate-y-3/4",
91
+ bottom: "bottom-0 translate-y-3/4",
92
+ },
93
+ align: {
94
+ start: "left-3",
95
+ end: "right-3",
96
+ },
97
+ },
98
+ defaultVariants: {
99
+ side: "bottom",
100
+ align: "end",
101
+ },
102
+ }
103
+ )
104
+
105
+ function BubbleReactions({
106
+ side = "bottom",
107
+ align = "end",
108
+ className,
109
+ ...props
110
+ }: React.ComponentProps<"div"> & {
111
+ align?: "start" | "end"
112
+ side?: "top" | "bottom"
113
+ }) {
114
+ return (
115
+ <div
116
+ data-slot="bubble-reactions"
117
+ data-align={align}
118
+ data-side={side}
119
+ className={cn(bubbleReactionsVariants({ side, align }), className)}
120
+ {...props}
121
+ />
122
+ )
123
+ }
124
+
125
+ export { BubbleGroup, Bubble, BubbleContent, BubbleReactions }
@@ -0,0 +1,83 @@
1
+ import { cva, type VariantProps } from "class-variance-authority"
2
+ import { Slot } from "radix-ui"
3
+
4
+ import { cn } from "@/lib/utils"
5
+ import { Separator } from "@/components/ui/separator"
6
+
7
+ const buttonGroupVariants = cva(
8
+ "group/button-group flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-lg [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
9
+ {
10
+ variants: {
11
+ orientation: {
12
+ horizontal:
13
+ "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-lg!",
14
+ vertical:
15
+ "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-lg!",
16
+ },
17
+ },
18
+ defaultVariants: {
19
+ orientation: "horizontal",
20
+ },
21
+ }
22
+ )
23
+
24
+ function ButtonGroup({
25
+ className,
26
+ orientation,
27
+ ...props
28
+ }: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) {
29
+ return (
30
+ <div
31
+ role="group"
32
+ data-slot="button-group"
33
+ data-orientation={orientation}
34
+ className={cn(buttonGroupVariants({ orientation }), className)}
35
+ {...props}
36
+ />
37
+ )
38
+ }
39
+
40
+ function ButtonGroupText({
41
+ className,
42
+ asChild = false,
43
+ ...props
44
+ }: React.ComponentProps<"div"> & {
45
+ asChild?: boolean
46
+ }) {
47
+ const Comp = asChild ? Slot.Root : "div"
48
+
49
+ return (
50
+ <Comp
51
+ className={cn(
52
+ "flex items-center gap-2 rounded-lg border bg-muted px-2.5 text-sm font-medium [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
53
+ className
54
+ )}
55
+ {...props}
56
+ />
57
+ )
58
+ }
59
+
60
+ function ButtonGroupSeparator({
61
+ className,
62
+ orientation = "vertical",
63
+ ...props
64
+ }: React.ComponentProps<typeof Separator>) {
65
+ return (
66
+ <Separator
67
+ data-slot="button-group-separator"
68
+ orientation={orientation}
69
+ className={cn(
70
+ "relative self-stretch bg-input data-horizontal:mx-px data-horizontal:w-auto data-vertical:my-px data-vertical:h-auto",
71
+ className
72
+ )}
73
+ {...props}
74
+ />
75
+ )
76
+ }
77
+
78
+ export {
79
+ ButtonGroup,
80
+ ButtonGroupSeparator,
81
+ ButtonGroupText,
82
+ buttonGroupVariants,
83
+ }
@@ -0,0 +1,67 @@
1
+ import * as React from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+ import { Slot } from "radix-ui"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const buttonVariants = cva(
8
+ "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",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
13
+ outline:
14
+ "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",
15
+ secondary:
16
+ "bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
17
+ ghost:
18
+ "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
19
+ destructive:
20
+ "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",
21
+ link: "text-primary underline-offset-4 hover:underline",
22
+ },
23
+ size: {
24
+ default:
25
+ "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
26
+ 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",
27
+ 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",
28
+ lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
29
+ icon: "size-8",
30
+ "icon-xs":
31
+ "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
32
+ "icon-sm":
33
+ "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
34
+ "icon-lg": "size-9",
35
+ },
36
+ },
37
+ defaultVariants: {
38
+ variant: "default",
39
+ size: "default",
40
+ },
41
+ }
42
+ )
43
+
44
+ function Button({
45
+ className,
46
+ variant = "default",
47
+ size = "default",
48
+ asChild = false,
49
+ ...props
50
+ }: React.ComponentProps<"button"> &
51
+ VariantProps<typeof buttonVariants> & {
52
+ asChild?: boolean
53
+ }) {
54
+ const Comp = asChild ? Slot.Root : "button"
55
+
56
+ return (
57
+ <Comp
58
+ data-slot="button"
59
+ data-variant={variant}
60
+ data-size={size}
61
+ className={cn(buttonVariants({ variant, size, className }))}
62
+ {...props}
63
+ />
64
+ )
65
+ }
66
+
67
+ export { Button, buttonVariants }
@@ -0,0 +1,222 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import {
5
+ DayPicker,
6
+ getDefaultClassNames,
7
+ type DayButton,
8
+ type Locale,
9
+ } from "react-day-picker"
10
+
11
+ import { cn } from "@/lib/utils"
12
+ import { Button, buttonVariants } from "@/components/ui/button"
13
+ import { ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon } from "lucide-react"
14
+
15
+ function Calendar({
16
+ className,
17
+ classNames,
18
+ showOutsideDays = true,
19
+ captionLayout = "label",
20
+ buttonVariant = "ghost",
21
+ locale,
22
+ formatters,
23
+ components,
24
+ ...props
25
+ }: React.ComponentProps<typeof DayPicker> & {
26
+ buttonVariant?: React.ComponentProps<typeof Button>["variant"]
27
+ }) {
28
+ const defaultClassNames = getDefaultClassNames()
29
+
30
+ return (
31
+ <DayPicker
32
+ showOutsideDays={showOutsideDays}
33
+ className={cn(
34
+ "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",
35
+ String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
36
+ String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
37
+ className
38
+ )}
39
+ captionLayout={captionLayout}
40
+ locale={locale}
41
+ formatters={{
42
+ formatMonthDropdown: (date) =>
43
+ date.toLocaleString(locale?.code, { month: "short" }),
44
+ ...formatters,
45
+ }}
46
+ classNames={{
47
+ root: cn("w-fit", defaultClassNames.root),
48
+ months: cn(
49
+ "relative flex flex-col gap-4 md:flex-row",
50
+ defaultClassNames.months
51
+ ),
52
+ month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
53
+ nav: cn(
54
+ "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
55
+ defaultClassNames.nav
56
+ ),
57
+ button_previous: cn(
58
+ buttonVariants({ variant: buttonVariant }),
59
+ "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
60
+ defaultClassNames.button_previous
61
+ ),
62
+ button_next: cn(
63
+ buttonVariants({ variant: buttonVariant }),
64
+ "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
65
+ defaultClassNames.button_next
66
+ ),
67
+ month_caption: cn(
68
+ "flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)",
69
+ defaultClassNames.month_caption
70
+ ),
71
+ dropdowns: cn(
72
+ "flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium",
73
+ defaultClassNames.dropdowns
74
+ ),
75
+ dropdown_root: cn(
76
+ "relative rounded-(--cell-radius)",
77
+ defaultClassNames.dropdown_root
78
+ ),
79
+ dropdown: cn(
80
+ "absolute inset-0 bg-popover opacity-0",
81
+ defaultClassNames.dropdown
82
+ ),
83
+ caption_label: cn(
84
+ "font-medium select-none",
85
+ captionLayout === "label"
86
+ ? "text-sm"
87
+ : "flex items-center gap-1 rounded-(--cell-radius) text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
88
+ defaultClassNames.caption_label
89
+ ),
90
+ month_grid: cn("w-full border-collapse", defaultClassNames.month_grid),
91
+ weekdays: cn("flex", defaultClassNames.weekdays),
92
+ weekday: cn(
93
+ "flex-1 rounded-(--cell-radius) text-[0.8rem] font-normal text-muted-foreground select-none",
94
+ defaultClassNames.weekday
95
+ ),
96
+ week: cn("mt-2 flex w-full", defaultClassNames.week),
97
+ week_number_header: cn(
98
+ "w-(--cell-size) select-none",
99
+ defaultClassNames.week_number_header
100
+ ),
101
+ week_number: cn(
102
+ "text-[0.8rem] text-muted-foreground select-none",
103
+ defaultClassNames.week_number
104
+ ),
105
+ day: cn(
106
+ "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)",
107
+ props.showWeekNumber
108
+ ? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)"
109
+ : "[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)",
110
+ defaultClassNames.day
111
+ ),
112
+ range_start: cn(
113
+ "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",
114
+ defaultClassNames.range_start
115
+ ),
116
+ range_middle: cn("rounded-none", defaultClassNames.range_middle),
117
+ range_end: cn(
118
+ "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",
119
+ defaultClassNames.range_end
120
+ ),
121
+ today: cn(
122
+ "rounded-(--cell-radius) bg-muted text-foreground data-[selected=true]:rounded-none",
123
+ defaultClassNames.today
124
+ ),
125
+ outside: cn(
126
+ "text-muted-foreground aria-selected:text-muted-foreground",
127
+ defaultClassNames.outside
128
+ ),
129
+ disabled: cn(
130
+ "text-muted-foreground opacity-50",
131
+ defaultClassNames.disabled
132
+ ),
133
+ hidden: cn("invisible", defaultClassNames.hidden),
134
+ ...classNames,
135
+ }}
136
+ components={{
137
+ Root: ({ className, rootRef, ...props }) => {
138
+ return (
139
+ <div
140
+ data-slot="calendar"
141
+ ref={rootRef}
142
+ className={cn(className)}
143
+ {...props}
144
+ />
145
+ )
146
+ },
147
+ Chevron: ({ className, orientation, ...props }) => {
148
+ if (orientation === "left") {
149
+ return (
150
+ <ChevronLeftIcon className={cn("size-4", className)} {...props} />
151
+ )
152
+ }
153
+
154
+ if (orientation === "right") {
155
+ return (
156
+ <ChevronRightIcon className={cn("size-4", className)} {...props} />
157
+ )
158
+ }
159
+
160
+ return (
161
+ <ChevronDownIcon className={cn("size-4", className)} {...props} />
162
+ )
163
+ },
164
+ DayButton: ({ ...props }) => (
165
+ <CalendarDayButton locale={locale} {...props} />
166
+ ),
167
+ WeekNumber: ({ children, ...props }) => {
168
+ return (
169
+ <td {...props}>
170
+ <div className="flex size-(--cell-size) items-center justify-center text-center">
171
+ {children}
172
+ </div>
173
+ </td>
174
+ )
175
+ },
176
+ ...components,
177
+ }}
178
+ {...props}
179
+ />
180
+ )
181
+ }
182
+
183
+ function CalendarDayButton({
184
+ className,
185
+ day,
186
+ modifiers,
187
+ locale,
188
+ ...props
189
+ }: React.ComponentProps<typeof DayButton> & { locale?: Partial<Locale> }) {
190
+ const defaultClassNames = getDefaultClassNames()
191
+
192
+ const ref = React.useRef<HTMLButtonElement>(null)
193
+ React.useEffect(() => {
194
+ if (modifiers.focused) ref.current?.focus()
195
+ }, [modifiers.focused])
196
+
197
+ return (
198
+ <Button
199
+ ref={ref}
200
+ variant="ghost"
201
+ size="icon"
202
+ data-day={day.date.toLocaleDateString(locale?.code)}
203
+ data-selected-single={
204
+ modifiers.selected &&
205
+ !modifiers.range_start &&
206
+ !modifiers.range_end &&
207
+ !modifiers.range_middle
208
+ }
209
+ data-range-start={modifiers.range_start}
210
+ data-range-end={modifiers.range_end}
211
+ data-range-middle={modifiers.range_middle}
212
+ className={cn(
213
+ "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",
214
+ defaultClassNames.day,
215
+ className
216
+ )}
217
+ {...props}
218
+ />
219
+ )
220
+ }
221
+
222
+ export { Calendar, CalendarDayButton }