@vuer-ai/vuer-uikit 0.0.12 → 0.0.13

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 (45) hide show
  1. package/package.json +3 -2
  2. package/src/highlight-cursor/cursor-context.tsx +23 -0
  3. package/src/highlight-cursor/cursor-provider.tsx +264 -0
  4. package/src/highlight-cursor/enhanced-components.tsx +16 -0
  5. package/src/highlight-cursor/index.ts +21 -0
  6. package/src/highlight-cursor/tabs-cursor-context.tsx +121 -0
  7. package/src/highlight-cursor/types.ts +40 -0
  8. package/src/highlight-cursor/with-cursor.tsx +144 -0
  9. package/src/index.css +5 -0
  10. package/src/index.ts +5 -0
  11. package/src/styles/theme.css +80 -0
  12. package/src/styles/toast.css +64 -0
  13. package/src/styles/variables.css +194 -0
  14. package/src/ui/avatar.tsx +92 -0
  15. package/src/ui/badge.tsx +68 -0
  16. package/src/ui/button.tsx +100 -0
  17. package/src/ui/card.tsx +88 -0
  18. package/src/ui/checkbox.tsx +76 -0
  19. package/src/ui/collapsible.tsx +36 -0
  20. package/src/ui/dropdown.tsx +375 -0
  21. package/src/ui/index.ts +31 -0
  22. package/src/ui/input-numbers.tsx +201 -0
  23. package/src/ui/input.tsx +141 -0
  24. package/src/ui/layout.tsx +41 -0
  25. package/src/ui/modal.tsx +198 -0
  26. package/src/ui/popover.tsx +59 -0
  27. package/src/ui/radio-group.tsx +56 -0
  28. package/src/ui/select.tsx +292 -0
  29. package/src/ui/sheet.tsx +131 -0
  30. package/src/ui/slider.tsx +189 -0
  31. package/src/ui/switch.tsx +43 -0
  32. package/src/ui/tabs.tsx +128 -0
  33. package/src/ui/textarea.tsx +52 -0
  34. package/src/ui/theme-context.tsx +80 -0
  35. package/src/ui/timeline.tsx +717 -0
  36. package/src/ui/toast.tsx +27 -0
  37. package/src/ui/toggle-group.tsx +82 -0
  38. package/src/ui/toggle.tsx +88 -0
  39. package/src/ui/tooltip.tsx +132 -0
  40. package/src/ui/tree-view-v2.tsx +300 -0
  41. package/src/ui/tree-view.tsx +550 -0
  42. package/src/ui/version-badge.tsx +65 -0
  43. package/src/utils/cn.ts +21 -0
  44. package/src/utils/index.ts +2 -0
  45. package/src/utils/use-local-storage.ts +59 -0
@@ -0,0 +1,201 @@
1
+ import { useGesture } from "@use-gesture/react";
2
+ import { ChangeEvent, forwardRef, ReactNode, useCallback, useRef } from "react";
3
+
4
+ import { InputRoot, InputRootProps, InputSlot } from "./input";
5
+ import { cn } from "../utils";
6
+
7
+ const getHoverElementAndIndex = (
8
+ element: Element | null,
9
+ inputs: Map<string, HTMLInputElement | null>,
10
+ ) => {
11
+ if (!element) return null;
12
+ const container = element?.closest("[data-input]");
13
+
14
+ const currentInput = container?.querySelector("input");
15
+
16
+ if (!currentInput) return null;
17
+
18
+ return Array.from(inputs.values()).indexOf(currentInput);
19
+ };
20
+
21
+ // down y x none
22
+ const changeElementsHoverState = (
23
+ inputs: Map<string, HTMLInputElement | null>,
24
+ range: [number | null, number | null],
25
+ changed: "x" | "y" | "none",
26
+ ) => {
27
+ const [first, last] = range;
28
+ Array.from(inputs.values()).forEach((input, i) => {
29
+ const container = input?.closest("[data-input]");
30
+ if (first === null || last === null) {
31
+ container?.setAttribute("data-hover", "none");
32
+ } else if (i >= Math.min(first, last) && i <= Math.max(first, last)) {
33
+ container?.setAttribute("data-hover", changed !== "none" ? changed : "down");
34
+ } else {
35
+ container?.setAttribute("data-hover", "none");
36
+ }
37
+ });
38
+ };
39
+
40
+ interface InputNumbersProps extends Pick<InputRootProps, "size"> {
41
+ step?: number;
42
+ value: number[];
43
+ prefix?: ReactNode[];
44
+ onValuesChange?: (value: Array<number>) => void;
45
+ }
46
+
47
+ const InputNumbers = forwardRef<HTMLDivElement, InputNumbersProps>(function InputNumbers(
48
+ { size, value, onValuesChange, prefix, step = 0.1 },
49
+ ref,
50
+ ) {
51
+ const inputs = useRef<Map<string, HTMLInputElement | null>>(new Map());
52
+ const selectRange = useRef<[number | null, number | null]>([null, null]);
53
+ const inputChange = useRef(false);
54
+
55
+ const stopClick = useCallback(() => {
56
+ if (typeof document === "undefined") return;
57
+
58
+ const stopClick = (e: MouseEvent) => {
59
+ e.stopPropagation();
60
+ e.preventDefault();
61
+ document.removeEventListener("click", stopClick, true);
62
+ };
63
+ document.addEventListener("click", stopClick, true);
64
+ }, []);
65
+
66
+ const bind = useGesture({
67
+ onDrag: ({ delta: [dx], event, initial, distance: [, oy], xy, memo = 0 }) => {
68
+ event.stopPropagation();
69
+ event.preventDefault();
70
+
71
+ if (selectRange.current[0] === null) {
72
+ selectRange.current[0] = getHoverElementAndIndex(
73
+ typeof document !== "undefined" ? document.elementFromPoint(...initial) : null,
74
+ inputs.current,
75
+ );
76
+ }
77
+
78
+ let newMX: number = memo + dx / 2;
79
+
80
+ if (Math.abs(newMX) >= (inputChange.current ? 1 : 5)) {
81
+ const multiplyStep = event.shiftKey ? 5 : event.altKey ? 1 / 5 : 1;
82
+
83
+ const newValue = value.map((v, i) => {
84
+ const [first, last] = selectRange.current;
85
+ if (first === null || last === null) {
86
+ return v;
87
+ } else if (i <= Math.max(first, last) && i >= Math.min(first, last)) {
88
+ return Number(((v || 0) + Math.floor(newMX) * step * multiplyStep).toPrecision(6));
89
+ } else {
90
+ return v;
91
+ }
92
+ });
93
+ onValuesChange?.(newValue);
94
+ newMX = 0;
95
+ inputChange.current = true;
96
+
97
+ changeElementsHoverState(inputs.current, selectRange.current, "x");
98
+
99
+ stopClick();
100
+ }
101
+
102
+ if (!inputChange.current) {
103
+ const currentElement =
104
+ typeof document !== "undefined" ? document.elementFromPoint(...xy) : null;
105
+
106
+ const currentIndex = getHoverElementAndIndex(currentElement, inputs.current);
107
+ selectRange.current[1] = currentIndex ?? selectRange.current[1];
108
+
109
+ changeElementsHoverState(inputs.current, selectRange.current, oy !== 0 ? "y" : "none");
110
+
111
+ stopClick();
112
+ }
113
+
114
+ return newMX;
115
+ },
116
+ onDragEnd: () => {
117
+ selectRange.current = [null, null];
118
+ inputChange.current = false;
119
+ changeElementsHoverState(inputs.current, selectRange.current, "none");
120
+ },
121
+ });
122
+
123
+ const valueChangeHandler = useCallback(
124
+ (index: number) => {
125
+ return (e: ChangeEvent<HTMLInputElement>) => {
126
+ const inputValue = e.target.value;
127
+ if (inputValue === "" || !isNaN(Number(inputValue))) {
128
+ const newValue = value.map((v, i) => {
129
+ if (inputValue === "") {
130
+ return "" as unknown as number;
131
+ }
132
+ return i === index ? Number(inputValue) : v;
133
+ });
134
+ onValuesChange?.(newValue);
135
+ }
136
+ };
137
+ },
138
+ [onValuesChange, value],
139
+ );
140
+
141
+ if (value?.length === 0) {
142
+ throw new Error("`value` cannot be an empty array");
143
+ }
144
+
145
+ return (
146
+ <div
147
+ ref={ref}
148
+ {...bind()}
149
+ className={cn("gap-xs flex cursor-crosshair touch-none flex-col select-none")}
150
+ >
151
+ {value.map((item, index) => (
152
+ <InputRoot
153
+ key={index}
154
+ ref={(r) => {
155
+ inputs.current.set(index.toString(), r);
156
+ return () => {
157
+ inputs.current.delete(index.toString());
158
+ };
159
+ }}
160
+ size={size}
161
+ value={item}
162
+ onClick={() => {
163
+ inputs.current.get(index.toString())?.focus();
164
+ }}
165
+ onChange={valueChangeHandler(index)}
166
+ data-hover="none"
167
+ className={cn([
168
+ "group/number-input",
169
+ "cursor-crosshair",
170
+ "data-[hover=down]:bg-bg-tertiary",
171
+ "data-[hover=x]:bg-bg-tertiary",
172
+ "data-[hover=y]:bg-bg-tertiary",
173
+ "data-[hover=down]:cursor-move",
174
+ "data-[hover=x]:cursor-col-resize",
175
+ "data-[hover=y]:cursor-ns-resize",
176
+ ])}
177
+ inputClassName={cn([
178
+ "cursor-crosshair",
179
+ "group-data-[hover=down]/number-input:cursor-move",
180
+ "group-data-[hover=x]/number-input:cursor-col-resize",
181
+ "group-data-[hover=y]/number-input:cursor-ns-resize",
182
+ ])}
183
+ >
184
+ <InputSlot
185
+ className={cn(
186
+ "cursor-crosshair",
187
+ "group-data-[hover=down]/number-input:cursor-move",
188
+ "group-data-[hover=x]/number-input:cursor-col-resize",
189
+ "group-data-[hover=y]/number-input:cursor-ns-resize",
190
+ )}
191
+ >
192
+ {prefix?.[index]}
193
+ </InputSlot>
194
+ </InputRoot>
195
+ ))}
196
+ </div>
197
+ );
198
+ });
199
+
200
+ export { InputNumbers };
201
+ export type { InputNumbersProps };
@@ -0,0 +1,141 @@
1
+ import { composeRefs } from "@radix-ui/react-compose-refs";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { type ComponentProps, forwardRef, useRef } from "react";
4
+
5
+ import { cn } from "../utils";
6
+
7
+ const inputRootVariants = cva(
8
+ [
9
+ "px-1.5",
10
+ "flex",
11
+ "gap-md",
12
+ "items-center",
13
+ "rounded-uk-sm",
14
+ "overflow-hidden",
15
+ "bg-bg-secondary",
16
+ ],
17
+ {
18
+ variants: {
19
+ state: {
20
+ default: ["hover:bg-bg-tertiary", "has-[input:focus]:bg-bg-quaternary"],
21
+ disabled: ["disabled:cursor-not-allowed", "bg-bg-tertiary", "text-text-tertiary"],
22
+ error: ["hover:bg-danger-primary/10", "bg-danger-primary/20"],
23
+ },
24
+ size: {
25
+ sm: ["h-5.5", "text-uk-sm", "[&_.input-slot>svg:not([class*='size-'])]:size-lg"],
26
+ base: ["h-7", "text-uk-md", "[&_.input-slot>svg:not([class*='size-'])]:size-[14px]"],
27
+ lg: ["h-8", "text-uk-lg", "[&_.input-slot>svg:not([class*='size-'])]:size-xl"],
28
+ },
29
+ },
30
+ defaultVariants: {
31
+ state: "default",
32
+ size: "base",
33
+ },
34
+ },
35
+ );
36
+
37
+ interface InputRootProps
38
+ extends Omit<ComponentProps<"input">, "size">,
39
+ VariantProps<typeof inputRootVariants> {
40
+ state?: "default" | "error";
41
+ side?: "left" | "right";
42
+ asChild?: boolean;
43
+ inputClassName?: string;
44
+ }
45
+
46
+ const InputRoot = forwardRef<HTMLInputElement, InputRootProps>(function InputRoot(
47
+ { style, className, side, children, disabled, state, size, type, inputClassName, ...props },
48
+ ref,
49
+ ) {
50
+ const inputRef = useRef<HTMLInputElement>(null);
51
+
52
+ return (
53
+ <div
54
+ style={style}
55
+ data-input
56
+ className={cn(inputRootVariants({ size, state: disabled ? "disabled" : state }), className)}
57
+ onClick={(event) => {
58
+ const target = event.target as HTMLElement;
59
+ if (target.closest("input, button, a")) return;
60
+
61
+ const input = inputRef.current;
62
+ if (!input) return;
63
+
64
+ // Same selector as in the CSS to find the right slot
65
+ const isRightSlot = target.closest(`
66
+ .input-slot[data-side='right'],
67
+ .input-slot:not([data-side='right']) ~ .input-slot:not([data-side='left'])
68
+ `);
69
+
70
+ const cursorPosition = isRightSlot ? input.value.length : 0;
71
+
72
+ requestAnimationFrame(() => {
73
+ // Only some input types support this, browsers will throw an error if not supported
74
+ // See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange#:~:text=Note%20that%20according,not%20support%20selection%22.
75
+ try {
76
+ input.setSelectionRange(cursorPosition, cursorPosition);
77
+ } catch {
78
+ /* empty */
79
+ }
80
+ input.focus();
81
+ });
82
+ }}
83
+ >
84
+ <input
85
+ spellCheck="false"
86
+ {...props}
87
+ type={type}
88
+ data-side={side}
89
+ disabled={disabled}
90
+ name={type ?? "text"}
91
+ ref={composeRefs(inputRef, ref)}
92
+ className={cn(
93
+ [
94
+ "w-full",
95
+ "h-full",
96
+ "outline-none",
97
+ "data-[side=right]:text-right",
98
+ "[input[type=number]]:font-number-input",
99
+ "[&::-webkit-inner-spin-button]:appearance-none",
100
+ "[&::-webkit-outer-spin-button]:appearance-none",
101
+ ],
102
+ inputClassName,
103
+ )}
104
+ />
105
+ {children}
106
+ </div>
107
+ );
108
+ });
109
+
110
+ interface InputSlotProps extends ComponentProps<"div"> {
111
+ side?: "left" | "right";
112
+ }
113
+
114
+ const InputSlot = forwardRef<HTMLDivElement, InputSlotProps>(function (
115
+ { className, children, side = "left", ...props },
116
+ ref,
117
+ ) {
118
+ return (
119
+ <div
120
+ data-side={side}
121
+ {...props}
122
+ ref={ref}
123
+ className={cn(
124
+ [
125
+ "input-slot",
126
+ "cursor-text",
127
+ "shrink-0",
128
+ "order-[0]",
129
+ "text-text-tertiary",
130
+ "data-[side=left]:-order-1",
131
+ ],
132
+ className,
133
+ )}
134
+ >
135
+ {children}
136
+ </div>
137
+ );
138
+ });
139
+
140
+ export { InputRoot, InputSlot };
141
+ export type { InputRootProps, InputSlotProps };
@@ -0,0 +1,41 @@
1
+ import { Slot } from "@radix-ui/react-slot";
2
+ import { PropsWithChildren } from "react";
3
+
4
+ import { cn } from "../utils";
5
+
6
+ interface Props extends PropsWithChildren {
7
+ align?: "start" | "center" | "end";
8
+ asChild?: boolean;
9
+ className?: string;
10
+ orientation?: "horizontal" | "vertical";
11
+ }
12
+
13
+ function Layout({
14
+ asChild,
15
+ className,
16
+ children,
17
+ align = "start",
18
+ orientation = "horizontal",
19
+ }: Props) {
20
+ const Com = asChild ? Slot : "div";
21
+
22
+ return (
23
+ <Com
24
+ className={cn(
25
+ {
26
+ "gap-xs flex flex-col": orientation === "horizontal",
27
+ "gap-xs grid grid-cols-[1fr_2fr] text-center": orientation === "vertical",
28
+ "items-baseline": align === "start",
29
+ "items-center": align === "center",
30
+ "items-end": align === "end",
31
+ },
32
+ className,
33
+ )}
34
+ >
35
+ {children}
36
+ </Com>
37
+ );
38
+ }
39
+
40
+ export { Layout };
41
+ export type { Props as LayoutProps };
@@ -0,0 +1,198 @@
1
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
2
+ import { cva } from "class-variance-authority";
3
+ import { XIcon } from "lucide-react";
4
+ import { type ComponentProps } from "react";
5
+
6
+ import { cn } from "../utils";
7
+
8
+ type ModalProps = ComponentProps<typeof DialogPrimitive.Root>;
9
+
10
+ function Modal({ ...props }: ModalProps) {
11
+ return <DialogPrimitive.Root data-slot="modal" {...props} />;
12
+ }
13
+
14
+ type ModalTriggerProps = ComponentProps<typeof DialogPrimitive.Trigger>;
15
+
16
+ function ModalTrigger({ ...props }: ModalTriggerProps) {
17
+ return <DialogPrimitive.Trigger data-slot="modal-trigger" {...props} />;
18
+ }
19
+
20
+ type ModalPortalProps = ComponentProps<typeof DialogPrimitive.Portal>;
21
+
22
+ function ModalPortal({ ...props }: ModalPortalProps) {
23
+ return <DialogPrimitive.Portal data-slot="modal-portal" {...props} />;
24
+ }
25
+
26
+ type ModalCloseProps = ComponentProps<typeof DialogPrimitive.Close>;
27
+
28
+ function ModalClose({ ...props }: ModalCloseProps) {
29
+ return <DialogPrimitive.Close data-slot="modal-close" {...props} />;
30
+ }
31
+
32
+ const modalOverlayVariants = cva([
33
+ "fixed",
34
+ "inset-0",
35
+ "z-100",
36
+ "bg-bg-mask",
37
+ "transition-all",
38
+ "duration-200",
39
+ ]);
40
+
41
+ type ModalOverlayProps = ComponentProps<typeof DialogPrimitive.Overlay>;
42
+
43
+ function ModalOverlay({ className, ...props }: ModalOverlayProps) {
44
+ return (
45
+ <DialogPrimitive.Overlay
46
+ data-slot="modal-overlay"
47
+ className={cn(modalOverlayVariants(), className)}
48
+ {...props}
49
+ />
50
+ );
51
+ }
52
+
53
+ const modalContentVariants = cva([
54
+ "pb-xl",
55
+ "px-xl",
56
+ "bg-bg-primary",
57
+ "rounded-uk-xl",
58
+ "shadow-[0_4px_16px_0_var(--color-shadow-secondary)]",
59
+ "min-w-[280px]",
60
+ "duration-200",
61
+ "transition-all",
62
+ "fixed",
63
+ "translate-x-[-50%]",
64
+ "translate-y-[-50%]",
65
+ "z-101",
66
+ "left-1/2",
67
+ "top-1/2",
68
+ "data-[state=open]:animate-in",
69
+ "data-[state=closed]:animate-out",
70
+ "data-[state=closed]:fade-out-0",
71
+ "data-[state=open]:fade-in-0",
72
+ "data-[state=closed]:zoom-out-95",
73
+ "data-[state=open]:zoom-in-95",
74
+ "liquid:liquid-bg",
75
+ ]);
76
+
77
+ interface ModalContentProps extends ComponentProps<typeof DialogPrimitive.Content> {
78
+ showCloseButton?: boolean;
79
+ }
80
+
81
+ function ModalContent({
82
+ className,
83
+ children,
84
+ showCloseButton = true,
85
+ ...props
86
+ }: ModalContentProps) {
87
+ return (
88
+ <ModalPortal>
89
+ <ModalOverlay />
90
+ <DialogPrimitive.Content
91
+ data-slot="modal-content"
92
+ className={cn(modalContentVariants(), className)}
93
+ {...props}
94
+ >
95
+ {children}
96
+ {showCloseButton && (
97
+ <DialogPrimitive.Close
98
+ data-slot="modal-close"
99
+ className={cn(
100
+ "absolute",
101
+ "right-[16px]",
102
+ "top-[16px]",
103
+ "w-[16px]",
104
+ "h-[16px]",
105
+ "rounded-uk-sm",
106
+ "cursor-pointer",
107
+ "hover:text-icon-highlight",
108
+ "text-icon-primary",
109
+ "flex",
110
+ "items-center",
111
+ "justify-center",
112
+ )}
113
+ >
114
+ <XIcon />
115
+ <span className="sr-only">Close</span>
116
+ </DialogPrimitive.Close>
117
+ )}
118
+ </DialogPrimitive.Content>
119
+ </ModalPortal>
120
+ );
121
+ }
122
+
123
+ type ModalHeaderProps = ComponentProps<"div">;
124
+
125
+ function ModalHeader({ className, ...props }: ModalHeaderProps) {
126
+ return <div data-slot="modal-header" className={cn("flex flex-col", className)} {...props} />;
127
+ }
128
+
129
+ type ModalTitleProps = ComponentProps<typeof DialogPrimitive.Title>;
130
+
131
+ function ModalTitle({ className, ...props }: ModalTitleProps) {
132
+ return (
133
+ <DialogPrimitive.Title
134
+ data-slot="modal-title"
135
+ className={cn(
136
+ "text-text-highlight",
137
+ "text-uk-lg",
138
+ "leading-uk-lg",
139
+ "font-medium",
140
+ "py-lg",
141
+ "px-xl",
142
+ "text-center",
143
+ className,
144
+ )}
145
+ {...props}
146
+ />
147
+ );
148
+ }
149
+
150
+ type ModalDescriptionProps = ComponentProps<typeof DialogPrimitive.Description>;
151
+
152
+ function ModalDescription({ className, ...props }: ModalDescriptionProps) {
153
+ return (
154
+ <DialogPrimitive.Description
155
+ data-slot="modal-description"
156
+ className={cn("text-text-primary", "text-uk-md", "leading-uk-md", "text-start", className)}
157
+ {...props}
158
+ />
159
+ );
160
+ }
161
+
162
+ type ModalFooterProps = ComponentProps<"div">;
163
+
164
+ function ModalFooter({ className, ...props }: ModalFooterProps) {
165
+ return (
166
+ <div
167
+ data-slot="modal-footer"
168
+ className={cn("w-full", "flex", "justify-end", "gap-xs", className)}
169
+ {...props}
170
+ />
171
+ );
172
+ }
173
+
174
+ export {
175
+ Modal,
176
+ ModalTrigger,
177
+ ModalPortal,
178
+ ModalOverlay,
179
+ ModalContent,
180
+ ModalHeader,
181
+ ModalTitle,
182
+ ModalDescription,
183
+ ModalFooter,
184
+ ModalClose,
185
+ };
186
+
187
+ export type {
188
+ ModalProps,
189
+ ModalTriggerProps,
190
+ ModalPortalProps,
191
+ ModalOverlayProps,
192
+ ModalContentProps,
193
+ ModalHeaderProps,
194
+ ModalTitleProps,
195
+ ModalDescriptionProps,
196
+ ModalFooterProps,
197
+ ModalCloseProps,
198
+ };
@@ -0,0 +1,59 @@
1
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
2
+ import { ComponentProps } from "react";
3
+
4
+ import { cn } from "../utils";
5
+
6
+ function Popover({ ...props }: ComponentProps<typeof PopoverPrimitive.Root>) {
7
+ return <PopoverPrimitive.Root data-slot="popover" {...props} />;
8
+ }
9
+
10
+ function PopoverTrigger({ ...props }: ComponentProps<typeof PopoverPrimitive.Trigger>) {
11
+ return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
12
+ }
13
+
14
+ function PopoverContent({
15
+ className,
16
+ align = "center",
17
+ sideOffset = 4,
18
+ ...props
19
+ }: ComponentProps<typeof PopoverPrimitive.Content>) {
20
+ return (
21
+ <PopoverPrimitive.Portal>
22
+ <PopoverPrimitive.Content
23
+ data-slot="popover-content"
24
+ align={align}
25
+ sideOffset={sideOffset}
26
+ className={cn(
27
+ "bg-bg-primary",
28
+ "rounded-uk-lg",
29
+ "p-xl",
30
+ "w-[320px]",
31
+ "shadow-[0_4px_16px_0_var(--color-shadow-secondary)]",
32
+ "data-[state=open]:animate-in",
33
+ "data-[state=closed]:animate-out",
34
+ "data-[state=closed]:fade-out-0",
35
+ "data-[state=open]:fade-in-0",
36
+ "data-[state=closed]:zoom-out-95",
37
+ "data-[state=open]:zoom-in-95",
38
+ "data-[side=bottom]:slide-in-from-top-2",
39
+ "data-[side=left]:slide-in-from-right-2",
40
+ "data-[side=right]:slide-in-from-left-2",
41
+ "data-[side=top]:slide-in-from-bottom-2",
42
+ "z-50",
43
+ "origin-(--radix-popover-content-transform-origin)",
44
+ "border-none",
45
+ "outline-hidden",
46
+ "liquid:liquid-bg",
47
+ className,
48
+ )}
49
+ {...props}
50
+ />
51
+ </PopoverPrimitive.Portal>
52
+ );
53
+ }
54
+
55
+ function PopoverAnchor({ ...props }: ComponentProps<typeof PopoverPrimitive.Anchor>) {
56
+ return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
57
+ }
58
+
59
+ export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
@@ -0,0 +1,56 @@
1
+ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
2
+ import { type ComponentProps } from "react";
3
+
4
+ import { cn } from "../utils";
5
+
6
+ function RadioGroup({ className, ...props }: ComponentProps<typeof RadioGroupPrimitive.Root>) {
7
+ return (
8
+ <RadioGroupPrimitive.Root
9
+ data-slot="radio-group"
10
+ className={cn("grid gap-2", className)}
11
+ {...props}
12
+ />
13
+ );
14
+ }
15
+
16
+ function RadioGroupItem({ className, ...props }: ComponentProps<typeof RadioGroupPrimitive.Item>) {
17
+ return (
18
+ <RadioGroupPrimitive.Item
19
+ data-slot="radio-group-item"
20
+ className={cn(
21
+ "group",
22
+ "w-[16px]",
23
+ "h-[16px]",
24
+ "rounded-full",
25
+ "border-[1.5px]",
26
+ "border-solid",
27
+ "border-bg-tertiary",
28
+ "data-[state=checked]:border-brand-primary",
29
+ "disabled:cursor-not-allowed",
30
+ "disabled:bg-bg-secondary",
31
+ "disabled:data-[state=checked]:border-bg-tertiary",
32
+ className,
33
+ )}
34
+ {...props}
35
+ >
36
+ <RadioGroupPrimitive.Indicator
37
+ data-slot="radio-group-indicator"
38
+ className="relative flex items-center justify-center"
39
+ >
40
+ <div
41
+ className={cn(
42
+ "absolute",
43
+ "inset-0",
44
+ "m-auto",
45
+ "size-[8px]",
46
+ "rounded-full",
47
+ "bg-brand-primary",
48
+ "group-disabled:bg-bg-tertiary",
49
+ )}
50
+ />
51
+ </RadioGroupPrimitive.Indicator>
52
+ </RadioGroupPrimitive.Item>
53
+ );
54
+ }
55
+
56
+ export { RadioGroup, RadioGroupItem };