@moloodev/ui 0.0.0-stage → 0.2.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 (93) hide show
  1. package/package.json +139 -3
  2. package/registry/components.ts +135 -0
  3. package/registry/fonts.css +81 -0
  4. package/registry/suit-OFL.txt +94 -0
  5. package/registry/wanted-sans-OFL.txt +93 -0
  6. package/src/components/ui/accordion.tsx +74 -0
  7. package/src/components/ui/alert-dialog.tsx +187 -0
  8. package/src/components/ui/alert.tsx +83 -0
  9. package/src/components/ui/aspect-ratio.tsx +22 -0
  10. package/src/components/ui/attachment.tsx +207 -0
  11. package/src/components/ui/avatar.tsx +109 -0
  12. package/src/components/ui/badge.tsx +54 -0
  13. package/src/components/ui/breadcrumb.tsx +126 -0
  14. package/src/components/ui/bubble.tsx +128 -0
  15. package/src/components/ui/button-group.tsx +103 -0
  16. package/src/components/ui/button.tsx +68 -0
  17. package/src/components/ui/calendar.tsx +222 -0
  18. package/src/components/ui/card.tsx +103 -0
  19. package/src/components/ui/carousel.tsx +242 -0
  20. package/src/components/ui/chart.tsx +398 -0
  21. package/src/components/ui/checkbox.tsx +28 -0
  22. package/src/components/ui/collapsible.tsx +40 -0
  23. package/src/components/ui/combobox.tsx +299 -0
  24. package/src/components/ui/command.tsx +218 -0
  25. package/src/components/ui/context-menu.tsx +271 -0
  26. package/src/components/ui/data-table.tsx +919 -0
  27. package/src/components/ui/date-picker.tsx +65 -0
  28. package/src/components/ui/dialog.tsx +224 -0
  29. package/src/components/ui/drawer.tsx +231 -0
  30. package/src/components/ui/dropdown-menu.tsx +268 -0
  31. package/src/components/ui/dropzone.tsx +186 -0
  32. package/src/components/ui/empty.tsx +101 -0
  33. package/src/components/ui/field.tsx +238 -0
  34. package/src/components/ui/form.tsx +83 -0
  35. package/src/components/ui/highlighted-source.tsx +200 -0
  36. package/src/components/ui/hover-card.tsx +51 -0
  37. package/src/components/ui/image-field.tsx +796 -0
  38. package/src/components/ui/input-group.tsx +149 -0
  39. package/src/components/ui/input-otp.tsx +86 -0
  40. package/src/components/ui/input-step.ts +19 -0
  41. package/src/components/ui/input.tsx +100 -0
  42. package/src/components/ui/item.tsx +201 -0
  43. package/src/components/ui/kbd.tsx +91 -0
  44. package/src/components/ui/kind-icon-glob.ts +24 -0
  45. package/src/components/ui/kind-icon-load.ts +52 -0
  46. package/src/components/ui/kind-icon-static.ts +46 -0
  47. package/src/components/ui/kind-icon.tsx +84 -0
  48. package/src/components/ui/kind-mark.tsx +65 -0
  49. package/src/components/ui/label.tsx +29 -0
  50. package/src/components/ui/marker.tsx +71 -0
  51. package/src/components/ui/menubar.tsx +277 -0
  52. package/src/components/ui/message-scroller.tsx +137 -0
  53. package/src/components/ui/message.tsx +92 -0
  54. package/src/components/ui/moloo-logo.tsx +45 -0
  55. package/src/components/ui/native-select.tsx +61 -0
  56. package/src/components/ui/navigation-menu.tsx +168 -0
  57. package/src/components/ui/outline-list.tsx +73 -0
  58. package/src/components/ui/pagination.tsx +130 -0
  59. package/src/components/ui/panel.tsx +108 -0
  60. package/src/components/ui/popover.tsx +90 -0
  61. package/src/components/ui/progress.tsx +117 -0
  62. package/src/components/ui/radio-group.tsx +38 -0
  63. package/src/components/ui/resizable.tsx +52 -0
  64. package/src/components/ui/scroll-area.tsx +54 -0
  65. package/src/components/ui/select.tsx +205 -0
  66. package/src/components/ui/separator.tsx +25 -0
  67. package/src/components/ui/sheet.tsx +140 -0
  68. package/src/components/ui/sidebar.tsx +746 -0
  69. package/src/components/ui/skeleton.tsx +13 -0
  70. package/src/components/ui/slider.tsx +52 -0
  71. package/src/components/ui/spinner.tsx +18 -0
  72. package/src/components/ui/switch.tsx +32 -0
  73. package/src/components/ui/table.tsx +116 -0
  74. package/src/components/ui/tabs.tsx +83 -0
  75. package/src/components/ui/tag-list-input.tsx +194 -0
  76. package/src/components/ui/textarea.tsx +18 -0
  77. package/src/components/ui/timeline.tsx +265 -0
  78. package/src/components/ui/toast.tsx +237 -0
  79. package/src/components/ui/toggle-group.tsx +90 -0
  80. package/src/components/ui/toggle.tsx +45 -0
  81. package/src/components/ui/tooltip.tsx +66 -0
  82. package/src/css.d.ts +1 -0
  83. package/src/hooks/use-clipboard.ts +82 -0
  84. package/src/hooks/use-mobile.ts +21 -0
  85. package/src/index.ts +106 -0
  86. package/src/kind-icon.ts +4 -0
  87. package/src/lib/format-relative-time.ts +41 -0
  88. package/src/lib/list-selection.ts +61 -0
  89. package/src/lib/utils.ts +6 -0
  90. package/src/moloo.css +360 -0
  91. package/src/styles.css +36 -0
  92. package/src/typeset.css +518 -0
  93. package/README.md +0 -3
@@ -0,0 +1,265 @@
1
+ import { createContext, useCallback, useContext, useState } from "react"
2
+ import { mergeProps } from "@base-ui/react/merge-props"
3
+ import { useRender } from "@base-ui/react/use-render"
4
+
5
+ import { cn } from "../../lib/utils"
6
+
7
+ type TimelineContextValue = {
8
+ activeStep: number
9
+ setActiveStep: (step: number) => void
10
+ }
11
+
12
+ const TimelineContext = createContext<TimelineContextValue | undefined>(
13
+ undefined
14
+ )
15
+
16
+ function useTimeline() {
17
+ const context = useContext(TimelineContext)
18
+ if (!context) {
19
+ throw new Error("useTimeline must be used within a Timeline")
20
+ }
21
+ return context
22
+ }
23
+
24
+ function Timeline({
25
+ defaultValue = 1,
26
+ value,
27
+ onValueChange,
28
+ orientation = "vertical",
29
+ className,
30
+ render,
31
+ children,
32
+ ...props
33
+ }: useRender.ComponentProps<"div"> & {
34
+ defaultValue?: number
35
+ value?: number
36
+ onValueChange?: (value: number) => void
37
+ orientation?: "horizontal" | "vertical"
38
+ }) {
39
+ const [activeStep, setInternalStep] = useState(defaultValue)
40
+
41
+ const setActiveStep = useCallback(
42
+ (step: number) => {
43
+ if (value === undefined) {
44
+ setInternalStep(step)
45
+ }
46
+ onValueChange?.(step)
47
+ },
48
+ [value, onValueChange]
49
+ )
50
+
51
+ const currentStep = value ?? activeStep
52
+
53
+ return (
54
+ <TimelineContext.Provider
55
+ value={{ activeStep: currentStep, setActiveStep }}
56
+ >
57
+ {useRender({
58
+ defaultTagName: "div",
59
+ render,
60
+ props: mergeProps<"div">(
61
+ {
62
+ role: "list",
63
+ className: cn(
64
+ "group/timeline flex data-[orientation=horizontal]:w-full data-[orientation=horizontal]:flex-row data-[orientation=vertical]:flex-col",
65
+ className
66
+ ),
67
+ children,
68
+ },
69
+ props
70
+ ),
71
+ state: {
72
+ slot: "timeline",
73
+ orientation,
74
+ },
75
+ })}
76
+ </TimelineContext.Provider>
77
+ )
78
+ }
79
+
80
+ function TimelineContent({
81
+ className,
82
+ render,
83
+ children,
84
+ ...props
85
+ }: useRender.ComponentProps<"div">) {
86
+ return useRender({
87
+ defaultTagName: "div",
88
+ render,
89
+ props: mergeProps<"div">(
90
+ {
91
+ className: cn("text-sm text-muted-foreground", className),
92
+ children,
93
+ },
94
+ props
95
+ ),
96
+ state: {
97
+ slot: "timeline-content",
98
+ },
99
+ })
100
+ }
101
+
102
+ function TimelineDate({
103
+ className,
104
+ render,
105
+ children,
106
+ ...props
107
+ }: useRender.ComponentProps<"time">) {
108
+ return useRender({
109
+ defaultTagName: "time",
110
+ render,
111
+ props: mergeProps<"time">(
112
+ {
113
+ className: cn(
114
+ "mb-1 block text-xs font-semibold text-muted-foreground",
115
+ className
116
+ ),
117
+ children,
118
+ },
119
+ props
120
+ ),
121
+ state: {
122
+ slot: "timeline-date",
123
+ },
124
+ })
125
+ }
126
+
127
+ function TimelineHeader({
128
+ className,
129
+ render,
130
+ children,
131
+ ...props
132
+ }: useRender.ComponentProps<"div">) {
133
+ return useRender({
134
+ defaultTagName: "div",
135
+ render,
136
+ props: mergeProps<"div">(
137
+ {
138
+ className,
139
+ children,
140
+ },
141
+ props
142
+ ),
143
+ state: {
144
+ slot: "timeline-header",
145
+ },
146
+ })
147
+ }
148
+
149
+ function TimelineIndicator({
150
+ className,
151
+ children,
152
+ render,
153
+ ...props
154
+ }: useRender.ComponentProps<"div">) {
155
+ return useRender({
156
+ defaultTagName: "div",
157
+ render,
158
+ props: mergeProps<"div">(
159
+ {
160
+ "aria-hidden": true,
161
+ className: cn(
162
+ "absolute flex size-4 items-center justify-center rounded-full border-2 border-border bg-card group-data-completed/timeline-item:border-primary group-data-[orientation=horizontal]/timeline:left-0 group-data-[orientation=horizontal]/timeline:-top-6 group-data-[orientation=horizontal]/timeline:-translate-y-1/2 group-data-[orientation=vertical]/timeline:top-0 group-data-[orientation=vertical]/timeline:-left-6 group-data-[orientation=vertical]/timeline:-translate-x-1/2 after:size-2 after:rounded-full after:bg-border group-data-completed/timeline-item:after:bg-primary has-[*]:after:hidden",
163
+ className
164
+ ),
165
+ children,
166
+ },
167
+ props
168
+ ),
169
+ state: {
170
+ slot: "timeline-indicator",
171
+ },
172
+ })
173
+ }
174
+
175
+ function TimelineItem({
176
+ step,
177
+ className,
178
+ render,
179
+ children,
180
+ ...props
181
+ }: useRender.ComponentProps<"div"> & { step: number }) {
182
+ const { activeStep } = useTimeline()
183
+
184
+ return useRender({
185
+ defaultTagName: "div",
186
+ render,
187
+ props: mergeProps<"div">(
188
+ {
189
+ role: "listitem",
190
+ className: cn(
191
+ "group/timeline-item relative flex flex-1 flex-col gap-0.5 outline-none moloo-focus group-data-[orientation=vertical]/timeline:ms-8 group-data-[orientation=vertical]/timeline:not-last:pb-6 group-data-[orientation=horizontal]/timeline:mt-8 group-data-[orientation=horizontal]/timeline:not-last:pe-8 has-[+[data-completed]]:**:data-[slot=timeline-separator]:bg-primary",
192
+ className
193
+ ),
194
+ children,
195
+ },
196
+ props
197
+ ),
198
+ state: {
199
+ slot: "timeline-item",
200
+ completed: step <= activeStep || undefined,
201
+ },
202
+ })
203
+ }
204
+
205
+ function TimelineSeparator({
206
+ className,
207
+ render,
208
+ children,
209
+ ...props
210
+ }: useRender.ComponentProps<"div">) {
211
+ return useRender({
212
+ defaultTagName: "div",
213
+ render,
214
+ props: mergeProps<"div">(
215
+ {
216
+ "aria-hidden": true,
217
+ className: cn(
218
+ "absolute self-start bg-border group-last/timeline-item:hidden group-data-[orientation=horizontal]/timeline:left-0 group-data-[orientation=horizontal]/timeline:-top-6 group-data-[orientation=horizontal]/timeline:h-px group-data-[orientation=horizontal]/timeline:w-[calc(100%-1rem-0.25rem)] group-data-[orientation=horizontal]/timeline:-translate-y-1/2 group-data-[orientation=horizontal]/timeline:translate-x-4.5 group-data-[orientation=vertical]/timeline:-left-6 group-data-[orientation=vertical]/timeline:h-[calc(100%-1rem-0.25rem)] group-data-[orientation=vertical]/timeline:w-px group-data-[orientation=vertical]/timeline:-translate-x-1/2 group-data-[orientation=vertical]/timeline:translate-y-4.5",
219
+ className
220
+ ),
221
+ children,
222
+ },
223
+ props
224
+ ),
225
+ state: {
226
+ slot: "timeline-separator",
227
+ },
228
+ })
229
+ }
230
+
231
+ function TimelineTitle({
232
+ className,
233
+ render,
234
+ children,
235
+ ...props
236
+ }: useRender.ComponentProps<"h3">) {
237
+ return useRender({
238
+ defaultTagName: "h3",
239
+ render,
240
+ props: mergeProps<"h3">(
241
+ {
242
+ className: cn(
243
+ "font-display text-sm font-bold tracking-[-0.02em]",
244
+ className
245
+ ),
246
+ children,
247
+ },
248
+ props
249
+ ),
250
+ state: {
251
+ slot: "timeline-title",
252
+ },
253
+ })
254
+ }
255
+
256
+ export {
257
+ Timeline,
258
+ TimelineContent,
259
+ TimelineDate,
260
+ TimelineHeader,
261
+ TimelineIndicator,
262
+ TimelineItem,
263
+ TimelineSeparator,
264
+ TimelineTitle,
265
+ }
@@ -0,0 +1,237 @@
1
+ "use client"
2
+
3
+ import { Toast as ToastPrimitive } from "@base-ui/react/toast"
4
+
5
+ import { cn } from "../../lib/utils"
6
+ import { Button } from "./button"
7
+ import { IconX, IconLoader2 } from "@tabler/icons-react"
8
+
9
+ const toast = ToastPrimitive.createToastManager()
10
+
11
+ function toastToneClass(type: string | undefined) {
12
+ switch (type) {
13
+ case "success":
14
+ case "info":
15
+ return "border-transparent bg-primary text-primary-foreground"
16
+ case "warning":
17
+ return "border-transparent bg-accent text-accent-foreground"
18
+ case "error":
19
+ return "border-transparent bg-destructive text-[#2a0814]"
20
+ case "loading":
21
+ return "border-2 border-border bg-card text-card-foreground"
22
+ default:
23
+ return "border-2 border-border bg-card text-card-foreground"
24
+ }
25
+ }
26
+
27
+ function ToastProvider({ ...props }: ToastPrimitive.Provider.Props) {
28
+ return <ToastPrimitive.Provider {...props} />
29
+ }
30
+
31
+ function ToastPortal({ ...props }: ToastPrimitive.Portal.Props) {
32
+ return <ToastPrimitive.Portal data-slot="toast-portal" {...props} />
33
+ }
34
+
35
+ function ToastViewport({ className, ...props }: ToastPrimitive.Viewport.Props) {
36
+ return (
37
+ <ToastPrimitive.Viewport
38
+ data-slot="toast-viewport"
39
+ className={cn(
40
+ "pointer-events-none fixed inset-x-4 bottom-4 z-[100] mx-auto w-auto max-w-sm outline-none sm:right-4 sm:left-auto sm:mx-0 sm:w-full",
41
+ className
42
+ )}
43
+ {...props}
44
+ />
45
+ )
46
+ }
47
+
48
+ function Toast({
49
+ className,
50
+ ...props
51
+ }: ToastPrimitive.Root.Props) {
52
+ return (
53
+ <ToastPrimitive.Root
54
+ data-slot="toast"
55
+ className={cn(
56
+ "group/toast pointer-events-auto absolute right-0 bottom-0 z-[calc(1000-var(--toast-index))] w-full origin-bottom rounded-md shadow-moloo will-change-transform outline-none select-none",
57
+ "[--gap:0.75rem] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))]",
58
+ "h-(--height) [transform:translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] [transition:transform_500ms_cubic-bezier(0.22,1,0.36,1),opacity_500ms,height_150ms]",
59
+ "after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-['']",
60
+ "data-expanded:h-(--toast-height) data-expanded:[transform:translateX(var(--toast-swipe-movement-x))_translateY(var(--offset-y))]",
61
+ "data-limited:opacity-0 data-starting-style:[transform:translateY(150%)]",
62
+ "[&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:[transform:translateY(150%)]",
63
+ "data-ending-style:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y)+150%))]",
64
+ "data-ending-style:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))]",
65
+ "data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))]",
66
+ "data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))]",
67
+ "data-expanded:data-ending-style:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y)+150%))]",
68
+ "data-expanded:data-ending-style:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))]",
69
+ "data-expanded:data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))]",
70
+ "data-expanded:data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))]",
71
+ className
72
+ )}
73
+ {...props}
74
+ />
75
+ )
76
+ }
77
+
78
+ function ToastContent({ className, ...props }: ToastPrimitive.Content.Props) {
79
+ return (
80
+ <ToastPrimitive.Content
81
+ data-slot="toast-content"
82
+ className={cn(
83
+ "flex h-full items-center gap-2.5 overflow-hidden px-3.5 py-2.5 transition-opacity duration-250 ease-[cubic-bezier(0.22,1,0.36,1)] data-behind:opacity-0 data-expanded:opacity-100",
84
+ className
85
+ )}
86
+ {...props}
87
+ />
88
+ )
89
+ }
90
+
91
+ function ToastTitle({ className, ...props }: ToastPrimitive.Title.Props) {
92
+ return (
93
+ <ToastPrimitive.Title
94
+ data-slot="toast-title"
95
+ className={cn(
96
+ "font-display text-sm font-bold tracking-[-0.02em] text-current",
97
+ className
98
+ )}
99
+ {...props}
100
+ />
101
+ )
102
+ }
103
+
104
+ function ToastDescription({
105
+ className,
106
+ ...props
107
+ }: ToastPrimitive.Description.Props) {
108
+ return (
109
+ <ToastPrimitive.Description
110
+ data-slot="toast-description"
111
+ className={cn("text-sm font-semibold text-current/80", className)}
112
+ {...props}
113
+ />
114
+ )
115
+ }
116
+
117
+ function ToastAction({
118
+ className,
119
+ render = <Button variant="outline" size="sm" />,
120
+ ...props
121
+ }: ToastPrimitive.Action.Props) {
122
+ return (
123
+ <ToastPrimitive.Action
124
+ data-slot="toast-action"
125
+ render={render}
126
+ className={cn("shrink-0", className)}
127
+ {...props}
128
+ />
129
+ )
130
+ }
131
+
132
+ function ToastClose({
133
+ className,
134
+ children,
135
+ closeLabel = "Close toast",
136
+ render = <Button variant="ghost" size="icon-xs" />,
137
+ ...props
138
+ }: ToastPrimitive.Close.Props & {
139
+ closeLabel?: string
140
+ }) {
141
+ return (
142
+ <ToastPrimitive.Close
143
+ data-slot="toast-close"
144
+ aria-label={closeLabel}
145
+ render={render}
146
+ className={cn(
147
+ "relative shrink-0 text-current/70 after:absolute after:-inset-2 after:content-[''] hover:bg-black/10 hover:text-current",
148
+ className
149
+ )}
150
+ {...props}
151
+ >
152
+ {children ?? <IconX aria-hidden="true" />}
153
+ </ToastPrimitive.Close>
154
+ )
155
+ }
156
+
157
+ function ToastIcon({ type }: { type: string | undefined }) {
158
+ if (type !== "loading") {
159
+ return null
160
+ }
161
+
162
+ return (
163
+ <span
164
+ data-slot="toast-icon"
165
+ className="shrink-0 text-current [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4"
166
+ >
167
+ <IconLoader2 className="animate-spin" aria-hidden="true" />
168
+ </span>
169
+ )
170
+ }
171
+
172
+ function ToastList({ closeLabel }: { closeLabel: string }) {
173
+ const { toasts } = ToastPrimitive.useToastManager()
174
+
175
+ return toasts.map((toastItem) => (
176
+ <Toast
177
+ key={toastItem.id}
178
+ toast={toastItem}
179
+ data-type={toastItem.type}
180
+ className={toastToneClass(toastItem.type)}
181
+ >
182
+ <ToastContent>
183
+ <ToastIcon type={toastItem.type} />
184
+ <div className="flex min-w-0 flex-1 flex-col gap-0.5">
185
+ <ToastTitle />
186
+ <ToastDescription />
187
+ </div>
188
+ <ToastAction />
189
+ <ToastClose closeLabel={closeLabel} />
190
+ </ToastContent>
191
+ </Toast>
192
+ ))
193
+ }
194
+
195
+ function Toaster({
196
+ children,
197
+ toastManager = toast,
198
+ closeLabel = "Close toast",
199
+ ...props
200
+ }: ToastPrimitive.Provider.Props & {
201
+ closeLabel?: string
202
+ }) {
203
+ return (
204
+ <ToastProvider toastManager={toastManager} {...props}>
205
+ {children}
206
+ <ToastPortal>
207
+ <ToastViewport>
208
+ <ToastList closeLabel={closeLabel} />
209
+ </ToastViewport>
210
+ </ToastPortal>
211
+ </ToastProvider>
212
+ )
213
+ }
214
+
215
+ const createToastManager = ToastPrimitive.createToastManager
216
+ const useToastManager = ToastPrimitive.useToastManager
217
+
218
+ function toastError(title: string) {
219
+ toast.add({ title, type: "error", priority: "high" })
220
+ }
221
+
222
+ export {
223
+ Toaster,
224
+ Toast,
225
+ ToastAction,
226
+ ToastClose,
227
+ ToastContent,
228
+ ToastDescription,
229
+ ToastPortal,
230
+ ToastProvider,
231
+ ToastTitle,
232
+ ToastViewport,
233
+ createToastManager,
234
+ toast,
235
+ toastError,
236
+ useToastManager,
237
+ }
@@ -0,0 +1,90 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Toggle as TogglePrimitive } from "@base-ui/react/toggle"
5
+ import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group"
6
+ import { type VariantProps } from "class-variance-authority"
7
+
8
+ import { cn } from "../../lib/utils"
9
+ import { toggleVariants } from "./toggle"
10
+
11
+ const ToggleGroupContext = React.createContext<
12
+ VariantProps<typeof toggleVariants> & {
13
+ spacing?: number
14
+ orientation?: "horizontal" | "vertical"
15
+ }
16
+ >({
17
+ size: "default",
18
+ variant: "default",
19
+ spacing: 2,
20
+ orientation: "horizontal",
21
+ })
22
+
23
+ function ToggleGroup({
24
+ className,
25
+ variant,
26
+ size,
27
+ spacing = 2,
28
+ orientation = "horizontal",
29
+ children,
30
+ ...props
31
+ }: ToggleGroupPrimitive.Props &
32
+ VariantProps<typeof toggleVariants> & {
33
+ spacing?: number
34
+ orientation?: "horizontal" | "vertical"
35
+ }) {
36
+ return (
37
+ <ToggleGroupPrimitive
38
+ data-slot="toggle-group"
39
+ data-variant={variant}
40
+ data-size={size}
41
+ data-spacing={spacing}
42
+ data-orientation={orientation}
43
+ orientation={orientation}
44
+ style={{ "--gap": spacing } as React.CSSProperties}
45
+ className={cn(
46
+ "group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] rounded-md data-[size=sm]:rounded-md data-vertical:flex-col data-vertical:items-stretch",
47
+ className
48
+ )}
49
+ {...props}
50
+ >
51
+ <ToggleGroupContext.Provider
52
+ value={{ variant, size, spacing, orientation }}
53
+ >
54
+ {children}
55
+ </ToggleGroupContext.Provider>
56
+ </ToggleGroupPrimitive>
57
+ )
58
+ }
59
+
60
+ function ToggleGroupItem({
61
+ className,
62
+ children,
63
+ variant = "default",
64
+ size = "default",
65
+ ...props
66
+ }: TogglePrimitive.Props & VariantProps<typeof toggleVariants>) {
67
+ const context = React.useContext(ToggleGroupContext)
68
+
69
+ return (
70
+ <TogglePrimitive
71
+ data-slot="toggle-group-item"
72
+ data-variant={context.variant || variant}
73
+ data-size={context.size || size}
74
+ data-spacing={context.spacing}
75
+ className={cn(
76
+ "shrink-0 group-data-[spacing=0]/toggle-group:rounded-md group-data-[spacing=0]/toggle-group:px-2 focus:z-10 focus-visible:z-10 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-1.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-1.5 group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-md group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-md group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-md group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-md group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l-2 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t-2",
77
+ toggleVariants({
78
+ variant: context.variant || variant,
79
+ size: context.size || size,
80
+ }),
81
+ className
82
+ )}
83
+ {...props}
84
+ >
85
+ {children}
86
+ </TogglePrimitive>
87
+ )
88
+ }
89
+
90
+ export { ToggleGroup, ToggleGroupItem }
@@ -0,0 +1,45 @@
1
+ "use client"
2
+
3
+ import { Toggle as TogglePrimitive } from "@base-ui/react/toggle"
4
+ import { cva, type VariantProps } from "class-variance-authority"
5
+
6
+ import { cn } from "../../lib/utils"
7
+
8
+ const toggleVariants = cva(
9
+ "group/toggle moloo-press moloo-focus inline-flex items-center justify-center gap-1 rounded-md font-display text-sm font-bold tracking-[-0.02em] whitespace-nowrap shadow-moloo transition-all outline-none hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-2 aria-invalid:border-destructive aria-pressed:bg-muted data-pressed:bg-muted [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
10
+ {
11
+ variants: {
12
+ variant: {
13
+ default: "bg-transparent",
14
+ outline: "border-2 border-input bg-transparent hover:bg-muted",
15
+ },
16
+ size: {
17
+ default:
18
+ "h-9 min-w-9 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
19
+ sm: "h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5",
20
+ lg: "h-10 min-w-10 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
21
+ },
22
+ },
23
+ defaultVariants: {
24
+ variant: "default",
25
+ size: "default",
26
+ },
27
+ }
28
+ )
29
+
30
+ function Toggle({
31
+ className,
32
+ variant = "default",
33
+ size = "default",
34
+ ...props
35
+ }: TogglePrimitive.Props & VariantProps<typeof toggleVariants>) {
36
+ return (
37
+ <TogglePrimitive
38
+ data-slot="toggle"
39
+ className={cn(toggleVariants({ variant, size, className }))}
40
+ {...props}
41
+ />
42
+ )
43
+ }
44
+
45
+ export { Toggle, toggleVariants }
@@ -0,0 +1,66 @@
1
+ "use client"
2
+
3
+ import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip"
4
+
5
+ import { cn } from "../../lib/utils"
6
+
7
+ function TooltipProvider({
8
+ delay = 0,
9
+ ...props
10
+ }: TooltipPrimitive.Provider.Props) {
11
+ return (
12
+ <TooltipPrimitive.Provider
13
+ data-slot="tooltip-provider"
14
+ delay={delay}
15
+ {...props}
16
+ />
17
+ )
18
+ }
19
+
20
+ function Tooltip({ ...props }: TooltipPrimitive.Root.Props) {
21
+ return <TooltipPrimitive.Root data-slot="tooltip" {...props} />
22
+ }
23
+
24
+ function TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {
25
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
26
+ }
27
+
28
+ function TooltipContent({
29
+ className,
30
+ side = "top",
31
+ sideOffset = 4,
32
+ align = "center",
33
+ alignOffset = 0,
34
+ children,
35
+ ...props
36
+ }: TooltipPrimitive.Popup.Props &
37
+ Pick<
38
+ TooltipPrimitive.Positioner.Props,
39
+ "align" | "alignOffset" | "side" | "sideOffset"
40
+ >) {
41
+ return (
42
+ <TooltipPrimitive.Portal>
43
+ <TooltipPrimitive.Positioner
44
+ align={align}
45
+ alignOffset={alignOffset}
46
+ side={side}
47
+ sideOffset={sideOffset}
48
+ className="isolate z-50"
49
+ >
50
+ <TooltipPrimitive.Popup
51
+ data-slot="tooltip-content"
52
+ className={cn(
53
+ "z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-sm text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-md data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
54
+ className
55
+ )}
56
+ {...props}
57
+ >
58
+ {children}
59
+ <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-md bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-left-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-right-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5" />
60
+ </TooltipPrimitive.Popup>
61
+ </TooltipPrimitive.Positioner>
62
+ </TooltipPrimitive.Portal>
63
+ )
64
+ }
65
+
66
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
package/src/css.d.ts ADDED
@@ -0,0 +1 @@
1
+ declare module "*.css" {}