@terrafirmagreg-team/ui 0.0.0-stage → 0.1.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 (215) hide show
  1. package/package.json +93 -3
  2. package/src/components/blocks/button/icon-button.tsx +48 -0
  3. package/src/components/blocks/canvas/chevron-edge.tsx +134 -0
  4. package/src/components/blocks/canvas/flow-canvas.tsx +177 -0
  5. package/src/components/blocks/canvas/flow-toolbar.tsx +32 -0
  6. package/src/components/blocks/canvas/flow-viewport.tsx +243 -0
  7. package/src/components/blocks/git/github-info.tsx +77 -0
  8. package/src/components/blocks/lang/content.tsx +22 -0
  9. package/src/components/blocks/lang/flag.tsx +24 -0
  10. package/src/components/blocks/lang/link.tsx +22 -0
  11. package/src/components/blocks/lang/redirect.tsx +47 -0
  12. package/src/components/blocks/lang/switcher.tsx +53 -0
  13. package/src/components/blocks/lang/untranslated-callout.tsx +28 -0
  14. package/src/components/blocks/link/link-preview.tsx +256 -0
  15. package/src/components/blocks/list/row.tsx +91 -0
  16. package/src/components/blocks/media/glb/model.tsx +243 -0
  17. package/src/components/blocks/media/glb/scene.tsx +372 -0
  18. package/src/components/blocks/media/glb/viewer.tsx +51 -0
  19. package/src/components/blocks/media/image.tsx +135 -0
  20. package/src/components/blocks/media/slideshow.tsx +177 -0
  21. package/src/components/blocks/nav/breadcrumb.tsx +50 -0
  22. package/src/components/blocks/nav/link.tsx +85 -0
  23. package/src/components/blocks/nav/site-menu.tsx +77 -0
  24. package/src/components/blocks/nav/site-title.tsx +60 -0
  25. package/src/components/blocks/nav/switcher.tsx +205 -0
  26. package/src/components/blocks/page/empty-state.tsx +31 -0
  27. package/src/components/blocks/page/heading.tsx +53 -0
  28. package/src/components/blocks/page/pager.tsx +112 -0
  29. package/src/components/blocks/readability/menu.tsx +431 -0
  30. package/src/components/blocks/readability/track.tsx +164 -0
  31. package/src/components/blocks/search/command.tsx +79 -0
  32. package/src/components/blocks/search/dialog.tsx +712 -0
  33. package/src/components/blocks/search/provider.tsx +117 -0
  34. package/src/components/blocks/sidebar.tsx +406 -0
  35. package/src/components/blocks/theme/toggle.tsx +71 -0
  36. package/src/components/blocks/tooltip/hint.tsx +27 -0
  37. package/src/components/blocks/viewer/controls.tsx +279 -0
  38. package/src/components/blocks/viewer/float-bar.tsx +50 -0
  39. package/src/components/layouts/layout.tsx +93 -0
  40. package/src/components/layouts/left-sidebar/content.tsx +62 -0
  41. package/src/components/layouts/left-sidebar/context.tsx +54 -0
  42. package/src/components/layouts/left-sidebar/expand.tsx +22 -0
  43. package/src/components/layouts/left-sidebar/footer.tsx +105 -0
  44. package/src/components/layouts/left-sidebar/index.ts +28 -0
  45. package/src/components/layouts/left-sidebar/items.tsx +102 -0
  46. package/src/components/layouts/left-sidebar/search.tsx +74 -0
  47. package/src/components/layouts/left-sidebar/sidebar.tsx +188 -0
  48. package/src/components/layouts/left-sidebar/tree.tsx +156 -0
  49. package/src/components/layouts/right-sidebar.tsx +95 -0
  50. package/src/components/layouts/tree-context.tsx +41 -0
  51. package/src/components/mdx/accordion.tsx +184 -0
  52. package/src/components/mdx/banner.tsx +154 -0
  53. package/src/components/mdx/callout.tsx +96 -0
  54. package/src/components/mdx/card.tsx +49 -0
  55. package/src/components/mdx/codeblock.tsx +249 -0
  56. package/src/components/mdx/collapsible.tsx +32 -0
  57. package/src/components/mdx/files.tsx +62 -0
  58. package/src/components/mdx/glow-header.tsx +40 -0
  59. package/src/components/mdx/gradient-text.tsx +27 -0
  60. package/src/components/mdx/image-zoom.tsx +314 -0
  61. package/src/components/mdx/mermaid.tsx +16 -0
  62. package/src/components/mdx/multiblock.tsx +18 -0
  63. package/src/components/mdx/preview.tsx +100 -0
  64. package/src/components/mdx/steps.tsx +9 -0
  65. package/src/components/mdx/table.tsx +13 -0
  66. package/src/components/mdx/tabs.tsx +353 -0
  67. package/src/components/mdx/type-table.tsx +170 -0
  68. package/src/components/ui/accordion.tsx +71 -0
  69. package/src/components/ui/alert-dialog.tsx +187 -0
  70. package/src/components/ui/alert.tsx +75 -0
  71. package/src/components/ui/aspect-ratio.tsx +22 -0
  72. package/src/components/ui/attachment.tsx +207 -0
  73. package/src/components/ui/avatar.tsx +108 -0
  74. package/src/components/ui/badge.tsx +51 -0
  75. package/src/components/ui/breadcrumb.tsx +124 -0
  76. package/src/components/ui/bubble.tsx +127 -0
  77. package/src/components/ui/button-group.tsx +87 -0
  78. package/src/components/ui/button.tsx +57 -0
  79. package/src/components/ui/calendar.tsx +221 -0
  80. package/src/components/ui/card.tsx +102 -0
  81. package/src/components/ui/carousel.tsx +242 -0
  82. package/src/components/ui/chart.tsx +371 -0
  83. package/src/components/ui/checkbox.tsx +28 -0
  84. package/src/components/ui/collapsible.tsx +21 -0
  85. package/src/components/ui/combobox.tsx +297 -0
  86. package/src/components/ui/command.tsx +198 -0
  87. package/src/components/ui/context-menu.tsx +270 -0
  88. package/src/components/ui/dialog.tsx +160 -0
  89. package/src/components/ui/direction.tsx +6 -0
  90. package/src/components/ui/drawer.tsx +227 -0
  91. package/src/components/ui/dropdown-menu.tsx +269 -0
  92. package/src/components/ui/empty.tsx +103 -0
  93. package/src/components/ui/field.tsx +238 -0
  94. package/src/components/ui/hover-card.tsx +50 -0
  95. package/src/components/ui/input-group.tsx +158 -0
  96. package/src/components/ui/input-otp.tsx +86 -0
  97. package/src/components/ui/input.tsx +19 -0
  98. package/src/components/ui/item.tsx +201 -0
  99. package/src/components/ui/kbd.tsx +26 -0
  100. package/src/components/ui/label.tsx +19 -0
  101. package/src/components/ui/marker.tsx +70 -0
  102. package/src/components/ui/menubar.tsx +280 -0
  103. package/src/components/ui/message-scroller.tsx +131 -0
  104. package/src/components/ui/message.tsx +91 -0
  105. package/src/components/ui/native-select.tsx +60 -0
  106. package/src/components/ui/navigation-menu.tsx +167 -0
  107. package/src/components/ui/pagination.tsx +130 -0
  108. package/src/components/ui/popover.tsx +91 -0
  109. package/src/components/ui/progress.tsx +82 -0
  110. package/src/components/ui/questionnaire.tsx +324 -0
  111. package/src/components/ui/radio-group.tsx +37 -0
  112. package/src/components/ui/resizable.tsx +49 -0
  113. package/src/components/ui/scroll-area.tsx +54 -0
  114. package/src/components/ui/select.tsx +200 -0
  115. package/src/components/ui/separator.tsx +24 -0
  116. package/src/components/ui/sheet.tsx +138 -0
  117. package/src/components/ui/sidebar.tsx +730 -0
  118. package/src/components/ui/skeleton.tsx +13 -0
  119. package/src/components/ui/slider.tsx +51 -0
  120. package/src/components/ui/spinner.tsx +10 -0
  121. package/src/components/ui/switch.tsx +31 -0
  122. package/src/components/ui/table.tsx +115 -0
  123. package/src/components/ui/tabs.tsx +81 -0
  124. package/src/components/ui/textarea.tsx +17 -0
  125. package/src/components/ui/toast.tsx +234 -0
  126. package/src/components/ui/toggle-group.tsx +89 -0
  127. package/src/components/ui/toggle.tsx +44 -0
  128. package/src/components/ui/tooltip.tsx +65 -0
  129. package/src/hooks/canvas/use-flow-hover.ts +18 -0
  130. package/src/hooks/canvas/use-flow-viewport-persist.ts +33 -0
  131. package/src/hooks/lang.ts +8 -0
  132. package/src/hooks/layout.ts +18 -0
  133. package/src/hooks/page/use-fit-pages.ts +91 -0
  134. package/src/hooks/page/use-location-search.ts +25 -0
  135. package/src/hooks/page/use-page-preview.ts +40 -0
  136. package/src/hooks/page/use-paged-list.ts +20 -0
  137. package/src/hooks/readability/provider.ts +86 -0
  138. package/src/hooks/search/dialog.ts +41 -0
  139. package/src/hooks/search/provider.ts +25 -0
  140. package/src/hooks/search/use-highlight-query.ts +51 -0
  141. package/src/hooks/sidebar.ts +63 -0
  142. package/src/hooks/use-async-value.ts +57 -0
  143. package/src/hooks/use-close-on-scroll.ts +23 -0
  144. package/src/hooks/use-copy-button.ts +46 -0
  145. package/src/hooks/use-cycle-index.ts +75 -0
  146. package/src/hooks/use-document-title.ts +9 -0
  147. package/src/hooks/use-element-size.ts +35 -0
  148. package/src/hooks/use-external-meta.ts +132 -0
  149. package/src/hooks/use-hot-key.ts +33 -0
  150. package/src/hooks/use-hover-follow.ts +54 -0
  151. package/src/hooks/use-in-view.ts +30 -0
  152. package/src/hooks/use-last-value.ts +15 -0
  153. package/src/hooks/use-marquee.ts +51 -0
  154. package/src/hooks/use-media-query.ts +14 -0
  155. package/src/hooks/use-mobile.ts +19 -0
  156. package/src/hooks/use-modifier-keys.ts +31 -0
  157. package/src/hooks/use-on-change.ts +35 -0
  158. package/src/hooks/use-pane-keys.ts +28 -0
  159. package/src/hooks/use-swipe.ts +26 -0
  160. package/src/hooks/use-tree.ts +102 -0
  161. package/src/hooks/viewer/use-in-float-bar.ts +6 -0
  162. package/src/hooks/viewer/use-viewer-prefs.ts +77 -0
  163. package/src/lib/canvas/edge.ts +173 -0
  164. package/src/lib/canvas/geometry.ts +53 -0
  165. package/src/lib/canvas/state.ts +47 -0
  166. package/src/lib/canvas/viewport.ts +37 -0
  167. package/src/lib/canvas/xyflow.ts +1 -0
  168. package/src/lib/config.ts +81 -0
  169. package/src/lib/mdx/callout.ts +20 -0
  170. package/src/lib/mdx/gradient.ts +15 -0
  171. package/src/lib/mdx/mermaid.ts +14 -0
  172. package/src/lib/media/crop-opaque.ts +76 -0
  173. package/src/lib/media/nearby-indexes.ts +6 -0
  174. package/src/lib/media/trim-transparent.ts +117 -0
  175. package/src/lib/readability/config.ts +10 -0
  176. package/src/lib/readability/spotlight.ts +186 -0
  177. package/src/lib/readability/store.ts +146 -0
  178. package/src/lib/tree.ts +92 -0
  179. package/src/lib/utils/async-cache.ts +32 -0
  180. package/src/lib/utils/cn.ts +1 -0
  181. package/src/lib/utils/format.ts +22 -0
  182. package/src/lib/utils/history.ts +9 -0
  183. package/src/lib/utils/merge-refs.ts +13 -0
  184. package/src/lib/utils/nav-active.ts +58 -0
  185. package/src/lib/utils/stored-value.ts +136 -0
  186. package/src/lib/utils/urls.ts +17 -0
  187. package/src/locales/en_us.json +119 -0
  188. package/src/locales/pl_pl.json +35 -0
  189. package/src/locales/ru_ru.json +119 -0
  190. package/src/locales/uk_ua.json +35 -0
  191. package/src/locales/zh_cn.json +17 -0
  192. package/src/locales/zh_tw.json +17 -0
  193. package/src/locales.ts +5 -0
  194. package/src/provider.tsx +141 -0
  195. package/src/types/canvas.ts +49 -0
  196. package/src/types/glb.ts +25 -0
  197. package/src/types/nav.ts +95 -0
  198. package/src/types/preview.ts +9 -0
  199. package/src/types/readability.ts +28 -0
  200. package/src/types/search.ts +56 -0
  201. package/src/types/tree.ts +18 -0
  202. package/src/types/viewer.ts +53 -0
  203. package/styles/content/base.css +194 -0
  204. package/styles/content/default-colors.css +51 -0
  205. package/styles/content/shiki.css +108 -0
  206. package/styles/content/typography.mjs +3941 -0
  207. package/styles/content.css +7 -0
  208. package/styles/image-zoom.css +83 -0
  209. package/styles/layout.css +28 -0
  210. package/styles/left-sidebar.css +140 -0
  211. package/styles/readability.css +50 -0
  212. package/styles/right-sidebar.css +6 -0
  213. package/styles/workspace.css +26 -0
  214. package/styles.css +413 -0
  215. package/README.md +0 -3
@@ -0,0 +1,124 @@
1
+ import * as React from "react"
2
+ import { mergeProps } from "@base-ui/react/merge-props"
3
+ import { useRender } from "@base-ui/react/use-render"
4
+ import { cn } from "cn"
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
+ className,
43
+ render,
44
+ ...props
45
+ }: useRender.ComponentProps<"a">) {
46
+ return useRender({
47
+ defaultTagName: "a",
48
+ props: mergeProps<"a">(
49
+ {
50
+ className: cn("transition-colors hover:text-foreground", className),
51
+ },
52
+ props
53
+ ),
54
+ render,
55
+ state: {
56
+ slot: "breadcrumb-link",
57
+ },
58
+ })
59
+ }
60
+
61
+ function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
62
+ return (
63
+ <span
64
+ data-slot="breadcrumb-page"
65
+ role="link"
66
+ aria-disabled="true"
67
+ aria-current="page"
68
+ className={cn("font-normal text-foreground", className)}
69
+ {...props}
70
+ />
71
+ )
72
+ }
73
+
74
+ function BreadcrumbSeparator({
75
+ children,
76
+ className,
77
+ ...props
78
+ }: React.ComponentProps<"li">) {
79
+ return (
80
+ <li
81
+ data-slot="breadcrumb-separator"
82
+ role="presentation"
83
+ aria-hidden="true"
84
+ className={cn("[&>svg]:size-3.5", className)}
85
+ {...props}
86
+ >
87
+ {children ?? (
88
+ <ChevronRightIcon />
89
+ )}
90
+ </li>
91
+ )
92
+ }
93
+
94
+ function BreadcrumbEllipsis({
95
+ className,
96
+ ...props
97
+ }: React.ComponentProps<"span">) {
98
+ return (
99
+ <span
100
+ data-slot="breadcrumb-ellipsis"
101
+ role="presentation"
102
+ aria-hidden="true"
103
+ className={cn(
104
+ "flex size-5 items-center justify-center [&>svg]:size-4",
105
+ className
106
+ )}
107
+ {...props}
108
+ >
109
+ <MoreHorizontalIcon
110
+ />
111
+ <span className="sr-only">More</span>
112
+ </span>
113
+ )
114
+ }
115
+
116
+ export {
117
+ Breadcrumb,
118
+ BreadcrumbList,
119
+ BreadcrumbItem,
120
+ BreadcrumbLink,
121
+ BreadcrumbPage,
122
+ BreadcrumbSeparator,
123
+ BreadcrumbEllipsis,
124
+ }
@@ -0,0 +1,127 @@
1
+ import * as React from "react"
2
+ import { mergeProps } from "@base-ui/react/merge-props"
3
+ import { useRender } from "@base-ui/react/use-render"
4
+ import { cva, type VariantProps } from "class-variance-authority"
5
+ import { cn } from "cn"
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
+ className,
66
+ render,
67
+ ...props
68
+ }: useRender.ComponentProps<"div">) {
69
+ return useRender({
70
+ defaultTagName: "div",
71
+ props: mergeProps<"div">(
72
+ {
73
+ className: cn(
74
+ "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",
75
+ className
76
+ ),
77
+ },
78
+ props
79
+ ),
80
+ render,
81
+ state: {
82
+ slot: "bubble-content",
83
+ },
84
+ })
85
+ }
86
+
87
+ const bubbleReactionsVariants = cva(
88
+ "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",
89
+ {
90
+ variants: {
91
+ side: {
92
+ top: "top-0 -translate-y-3/4",
93
+ bottom: "bottom-0 translate-y-3/4",
94
+ },
95
+ align: {
96
+ start: "left-3",
97
+ end: "right-3",
98
+ },
99
+ },
100
+ defaultVariants: {
101
+ side: "bottom",
102
+ align: "end",
103
+ },
104
+ }
105
+ )
106
+
107
+ function BubbleReactions({
108
+ side = "bottom",
109
+ align = "end",
110
+ className,
111
+ ...props
112
+ }: React.ComponentProps<"div"> & {
113
+ align?: "start" | "end"
114
+ side?: "top" | "bottom"
115
+ }) {
116
+ return (
117
+ <div
118
+ data-slot="bubble-reactions"
119
+ data-align={align}
120
+ data-side={side}
121
+ className={cn(bubbleReactionsVariants({ side, align }), className)}
122
+ {...props}
123
+ />
124
+ )
125
+ }
126
+
127
+ export { BubbleGroup, Bubble, BubbleContent, BubbleReactions }
@@ -0,0 +1,87 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props"
2
+ import { useRender } from "@base-ui/react/use-render"
3
+ import { cva, type VariantProps } from "class-variance-authority"
4
+ import { cn } from "cn"
5
+
6
+ import { Separator } from "./separator"
7
+
8
+ const buttonGroupVariants = cva(
9
+ "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",
10
+ {
11
+ variants: {
12
+ orientation: {
13
+ horizontal:
14
+ "*:data-slot:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-lg! [&>[data-slot]~[data-slot]]:rounded-l-none [&>[data-slot]~[data-slot]]:border-l-0",
15
+ vertical:
16
+ "flex-col *:data-slot:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-lg! [&>[data-slot]~[data-slot]]:rounded-t-none [&>[data-slot]~[data-slot]]:border-t-0",
17
+ },
18
+ },
19
+ defaultVariants: {
20
+ orientation: "horizontal",
21
+ },
22
+ }
23
+ )
24
+
25
+ function ButtonGroup({
26
+ className,
27
+ orientation,
28
+ ...props
29
+ }: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) {
30
+ return (
31
+ <div
32
+ role="group"
33
+ data-slot="button-group"
34
+ data-orientation={orientation}
35
+ className={cn(buttonGroupVariants({ orientation }), className)}
36
+ {...props}
37
+ />
38
+ )
39
+ }
40
+
41
+ function ButtonGroupText({
42
+ className,
43
+ render,
44
+ ...props
45
+ }: useRender.ComponentProps<"div">) {
46
+ return useRender({
47
+ defaultTagName: "div",
48
+ props: mergeProps<"div">(
49
+ {
50
+ className: cn(
51
+ "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",
52
+ className
53
+ ),
54
+ },
55
+ props
56
+ ),
57
+ render,
58
+ state: {
59
+ slot: "button-group-text",
60
+ },
61
+ })
62
+ }
63
+
64
+ function ButtonGroupSeparator({
65
+ className,
66
+ orientation = "vertical",
67
+ ...props
68
+ }: React.ComponentProps<typeof Separator>) {
69
+ return (
70
+ <Separator
71
+ data-slot="button-group-separator"
72
+ orientation={orientation}
73
+ className={cn(
74
+ "relative self-stretch bg-input data-[orientation=horizontal]:mx-px data-[orientation=horizontal]:w-auto data-[orientation=vertical]:my-px data-[orientation=vertical]:h-auto",
75
+ className
76
+ )}
77
+ {...props}
78
+ />
79
+ )
80
+ }
81
+
82
+ export {
83
+ ButtonGroup,
84
+ ButtonGroupSeparator,
85
+ ButtonGroupText,
86
+ buttonGroupVariants,
87
+ }
@@ -0,0 +1,57 @@
1
+ import { Button as ButtonPrimitive } from "@base-ui/react/button"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+ import { cn } from "cn"
4
+
5
+ const buttonVariants = cva(
6
+ "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",
7
+ {
8
+ variants: {
9
+ variant: {
10
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
11
+ outline:
12
+ "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",
13
+ secondary:
14
+ "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",
15
+ ghost:
16
+ "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
17
+ destructive:
18
+ "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",
19
+ link: "text-primary underline-offset-4 hover:underline",
20
+ },
21
+ size: {
22
+ default:
23
+ "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
24
+ 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",
25
+ 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",
26
+ lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
27
+ icon: "size-8",
28
+ "icon-xs":
29
+ "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
30
+ "icon-sm":
31
+ "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
32
+ "icon-lg": "size-9",
33
+ },
34
+ },
35
+ defaultVariants: {
36
+ variant: "default",
37
+ size: "default",
38
+ },
39
+ }
40
+ )
41
+
42
+ function Button({
43
+ className,
44
+ variant = "default",
45
+ size = "default",
46
+ ...props
47
+ }: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
48
+ return (
49
+ <ButtonPrimitive
50
+ data-slot="button"
51
+ className={cn(buttonVariants({ variant, size, className }))}
52
+ {...props}
53
+ />
54
+ )
55
+ }
56
+
57
+ export { Button, buttonVariants }
@@ -0,0 +1,221 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "cn"
5
+ import {
6
+ DayPicker,
7
+ getDefaultClassNames,
8
+ type DayButton,
9
+ type Locale,
10
+ } from "react-day-picker"
11
+
12
+ import { Button, buttonVariants } from "./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
+ variant="ghost"
200
+ size="icon"
201
+ data-day={day.date.toLocaleDateString(locale?.code)}
202
+ data-selected-single={
203
+ modifiers.selected &&
204
+ !modifiers.range_start &&
205
+ !modifiers.range_end &&
206
+ !modifiers.range_middle
207
+ }
208
+ data-range-start={modifiers.range_start}
209
+ data-range-end={modifiers.range_end}
210
+ data-range-middle={modifiers.range_middle}
211
+ className={cn(
212
+ "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",
213
+ defaultClassNames.day,
214
+ className
215
+ )}
216
+ {...props}
217
+ />
218
+ )
219
+ }
220
+
221
+ export { Calendar, CalendarDayButton }