@vvedantb/ui 0.1.0 → 0.1.2

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 (74) hide show
  1. package/LICENSE +21 -21
  2. package/package.json +3 -2
  3. package/src/ai-elements/artifact.tsx +99 -99
  4. package/src/ai-elements/attachments.tsx +366 -366
  5. package/src/ai-elements/chain-of-thought.tsx +212 -212
  6. package/src/ai-elements/code-block.tsx +478 -478
  7. package/src/ai-elements/conversation.tsx +157 -157
  8. package/src/ai-elements/image.tsx +25 -25
  9. package/src/ai-elements/inline-citation.tsx +252 -252
  10. package/src/ai-elements/message.tsx +269 -269
  11. package/src/ai-elements/model-selector.tsx +211 -211
  12. package/src/ai-elements/prompt-input.tsx +1018 -1018
  13. package/src/ai-elements/queue.tsx +251 -251
  14. package/src/ai-elements/reasoning.tsx +178 -178
  15. package/src/ai-elements/shimmer.tsx +56 -56
  16. package/src/ai-elements/sources.tsx +77 -77
  17. package/src/ai-elements/speech-input.tsx +290 -290
  18. package/src/ai-elements/suggestion.tsx +191 -191
  19. package/src/css.d.ts +2 -2
  20. package/src/index.ts +96 -96
  21. package/src/motion/presets.ts +35 -35
  22. package/src/motion/presets.vibot.ts +105 -105
  23. package/src/ui/_menu-classes.ts +30 -30
  24. package/src/ui/_menu-classes.vibot.ts +33 -33
  25. package/src/ui/accordion.tsx +81 -81
  26. package/src/ui/accordion.verve.tsx +56 -56
  27. package/src/ui/badge.tsx +34 -34
  28. package/src/ui/breadcrumb.tsx +83 -83
  29. package/src/ui/button-group.tsx +84 -84
  30. package/src/ui/button.tsx +57 -57
  31. package/src/ui/card.tsx +27 -27
  32. package/src/ui/carousel.tsx +211 -211
  33. package/src/ui/checkbox.tsx +27 -27
  34. package/src/ui/clear-input.tsx +170 -170
  35. package/src/ui/clear-input.vibot.tsx +76 -76
  36. package/src/ui/clearInputDissolve.ts +214 -214
  37. package/src/ui/collapsible.tsx +7 -7
  38. package/src/ui/command.tsx +148 -148
  39. package/src/ui/context-menu.tsx +173 -173
  40. package/src/ui/dialog.tsx +149 -149
  41. package/src/ui/dropdown-menu.tsx +178 -178
  42. package/src/ui/hover-card.tsx +31 -31
  43. package/src/ui/input-group.tsx +162 -162
  44. package/src/ui/input-group.verve.tsx +150 -150
  45. package/src/ui/input.tsx +21 -21
  46. package/src/ui/kbd.tsx +18 -18
  47. package/src/ui/label.tsx +20 -20
  48. package/src/ui/labeled-switch-row.tsx +53 -53
  49. package/src/ui/modalTransition.ts +85 -85
  50. package/src/ui/pagination.tsx +47 -47
  51. package/src/ui/popover.tsx +33 -33
  52. package/src/ui/progress.tsx +25 -25
  53. package/src/ui/radix-select.tsx +202 -202
  54. package/src/ui/scroll-area.tsx +55 -55
  55. package/src/ui/scroll-area.verve.tsx +43 -43
  56. package/src/ui/search-input.tsx +29 -29
  57. package/src/ui/select.tsx +163 -163
  58. package/src/ui/separator.tsx +28 -28
  59. package/src/ui/sheet.tsx +87 -87
  60. package/src/ui/skeleton.tsx +18 -18
  61. package/src/ui/sonner.css +16 -16
  62. package/src/ui/sonner.tsx +47 -47
  63. package/src/ui/spinner.tsx +27 -27
  64. package/src/ui/surface-classes.ts +55 -55
  65. package/src/ui/switch.tsx +26 -26
  66. package/src/ui/table.tsx +123 -123
  67. package/src/ui/tabs.tsx +140 -140
  68. package/src/ui/tabsSliding.ts +56 -56
  69. package/src/ui/textarea.tsx +21 -21
  70. package/src/ui/time-picker.tsx +170 -170
  71. package/src/ui/tooltip.tsx +25 -25
  72. package/src/ui/visually-hidden.tsx +3 -3
  73. package/src/utils/cn.ts +16 -16
  74. package/src/utils/ref.ts +10 -10
@@ -1,170 +1,170 @@
1
- import * as React from "react";
2
- import { IconClock } from "@tabler/icons-react";
3
- import { Popover, PopoverContent, PopoverTrigger } from "./popover";
4
- import { cn } from "../utils/cn";
5
-
6
- // custom 24, hour "hh:mm" time picker replaces `<input type="time">` because the native picker varies wildly
7
- // across browsers and platforms (chrome/firefox/safari each render a
8
- // different control, and the spinner buttons feel laggy on windows) ux:, the trigger is styled like an input, same height/border/radius, so it slots into forms without bespoke alignment work, clicking the trigger (or its clock icon) opens a popover with two scrollable columns: hours 00, 23 on the left, minutes 00, 59 on the right click an item to select, the popover stays open so users can set both halves in one trip, selected items use the same `bg, surface, tertiary` treatment used elsewhere for active states, no rings or borders, matching the design system the component is fully controlled, `value` is always "hh:mm" 24h and
9
- // the consumer is responsible for any local↔utc conversion that keeps
10
- // the picker free of timezone logic and matches how the rest of the
11
- // codebase (e.g dream mode) shapes scheduling values
12
- interface TimePickerProps {
13
- value: string;
14
- onChange: (value: string) => void;
15
- className?: string;
16
- disabled?: boolean;
17
- ariaLabel?: string;
18
- // width of the trigger button defaults to a compact 110px
19
- triggerClassName?: string;
20
- }
21
-
22
- const HOURS = Array.from({ length: 24 }, (_, i) => String(i).padStart(2, "0"));
23
- const MINUTES = Array.from({ length: 60 }, (_, i) =>
24
- String(i).padStart(2, "0"),
25
- );
26
-
27
- function parseValue(value: string): { hour: string; minute: string } {
28
- const match = /^(\d{2}):(\d{2})$/.exec(value);
29
- if (match) {
30
- const hour = match[1];
31
- const minute = match[2];
32
- if (hour !== undefined && minute !== undefined) {
33
- return { hour, minute };
34
- }
35
- }
36
- return { hour: "00", minute: "00" };
37
- }
38
-
39
- // auto, scroll a column to its selected item when the popover opens using
40
- // `scrollintoview({ block: "centre" })` is good enough, the popover only
41
- // has 2 columns and a fixed height, so we don't need a custom scroll calc
42
- function useScrollSelectedIntoView(
43
- ref: React.RefObject<HTMLDivElement | null>,
44
- selector: string,
45
- open: boolean,
46
- ): void {
47
- React.useEffect(() => {
48
- if (!open) return;
49
- const root = ref.current;
50
- if (!root) return;
51
- const target = root.querySelector(selector);
52
- if (target instanceof HTMLElement) {
53
- target.scrollIntoView({ block: "center", behavior: "auto" });
54
- }
55
- }, [open, ref, selector]);
56
- }
57
-
58
- const TimePicker = React.forwardRef<HTMLButtonElement, TimePickerProps>(
59
- (
60
- { value, onChange, className, disabled, ariaLabel, triggerClassName },
61
- ref,
62
- ) => {
63
- const [open, setOpen] = React.useState(false);
64
- const { hour, minute } = parseValue(value);
65
- const hoursRef = React.useRef<HTMLDivElement | null>(null);
66
- const minutesRef = React.useRef<HTMLDivElement | null>(null);
67
-
68
- useScrollSelectedIntoView(hoursRef, `[data-time-value="${hour}"]`, open);
69
- useScrollSelectedIntoView(
70
- minutesRef,
71
- `[data-time-value="${minute}"]`,
72
- open,
73
- );
74
-
75
- const handleHourSelect = (h: string) => {
76
- onChange(`${h}:${minute}`);
77
- };
78
- const handleMinuteSelect = (m: string) => {
79
- onChange(`${hour}:${m}`);
80
- };
81
-
82
- return (
83
- <Popover open={open} onOpenChange={setOpen}>
84
- <PopoverTrigger asChild>
85
- <button
86
- ref={ref}
87
- type="button"
88
- disabled={disabled}
89
- aria-label={ariaLabel}
90
- className={cn(
91
- "inline-flex h-8 items-center justify-between gap-2 rounded-field border border-border bg-field-background px-2.5 text-xs font-medium tabular-nums transition-[border-color,box-shadow,background-color] duration-200 ease-smooth hover:bg-field-background/90 focus-visible:border-focus-border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring disabled:cursor-not-allowed disabled:opacity-50",
92
- triggerClassName ?? "w-[110px]",
93
- className,
94
- )}
95
- >
96
- <span>{`${hour}:${minute}`}</span>
97
- <IconClock className="h-3.5 w-3.5 text-muted" />
98
- </button>
99
- </PopoverTrigger>
100
- <PopoverContent
101
- align="end"
102
- sideOffset={4}
103
- className="flex w-auto gap-1 p-2"
104
- >
105
- <TimeColumn
106
- ref={hoursRef}
107
- label="Hours"
108
- values={HOURS}
109
- selected={hour}
110
- onSelect={handleHourSelect}
111
- />
112
- <TimeColumn
113
- ref={minutesRef}
114
- label="Minutes"
115
- values={MINUTES}
116
- selected={minute}
117
- onSelect={handleMinuteSelect}
118
- />
119
- </PopoverContent>
120
- </Popover>
121
- );
122
- },
123
- );
124
- TimePicker.displayName = "TimePicker";
125
-
126
- interface TimeColumnProps {
127
- label: string;
128
- values: string[];
129
- selected: string;
130
- onSelect: (value: string) => void;
131
- }
132
-
133
- const TimeColumn = React.forwardRef<HTMLDivElement, TimeColumnProps>(
134
- ({ label, values, selected, onSelect }, ref) => {
135
- return (
136
- <div className="flex w-14 flex-col">
137
- <div className="px-2 pb-1 text-[10px] uppercase tracking-wider text-muted">
138
- {label}
139
- </div>
140
- <div
141
- ref={ref}
142
- className="h-48 overflow-y-auto rounded-lg bg-segment py-1"
143
- >
144
- {values.map((v) => {
145
- const isSelected = v === selected;
146
- return (
147
- <button
148
- key={v}
149
- type="button"
150
- data-time-value={v}
151
- onClick={() => onSelect(v)}
152
- className={cn(
153
- "flex h-7 w-full items-center justify-center text-xs tabular-nums transition-colors",
154
- isSelected
155
- ? "bg-accent text-accent-foreground"
156
- : "text-foreground/80 hover:bg-surface-tertiary/50",
157
- )}
158
- >
159
- {v}
160
- </button>
161
- );
162
- })}
163
- </div>
164
- </div>
165
- );
166
- },
167
- );
168
- TimeColumn.displayName = "TimeColumn";
169
-
170
- export { TimePicker };
1
+ import * as React from "react";
2
+ import { IconClock } from "@tabler/icons-react";
3
+ import { Popover, PopoverContent, PopoverTrigger } from "./popover";
4
+ import { cn } from "../utils/cn";
5
+
6
+ // custom 24, hour "hh:mm" time picker replaces `<input type="time">` because the native picker varies wildly
7
+ // across browsers and platforms (chrome/firefox/safari each render a
8
+ // different control, and the spinner buttons feel laggy on windows) ux:, the trigger is styled like an input, same height/border/radius, so it slots into forms without bespoke alignment work, clicking the trigger (or its clock icon) opens a popover with two scrollable columns: hours 00, 23 on the left, minutes 00, 59 on the right click an item to select, the popover stays open so users can set both halves in one trip, selected items use the same `bg, surface, tertiary` treatment used elsewhere for active states, no rings or borders, matching the design system the component is fully controlled, `value` is always "hh:mm" 24h and
9
+ // the consumer is responsible for any local↔utc conversion that keeps
10
+ // the picker free of timezone logic and matches how the rest of the
11
+ // codebase (e.g dream mode) shapes scheduling values
12
+ interface TimePickerProps {
13
+ value: string;
14
+ onChange: (value: string) => void;
15
+ className?: string;
16
+ disabled?: boolean;
17
+ ariaLabel?: string;
18
+ // width of the trigger button defaults to a compact 110px
19
+ triggerClassName?: string;
20
+ }
21
+
22
+ const HOURS = Array.from({ length: 24 }, (_, i) => String(i).padStart(2, "0"));
23
+ const MINUTES = Array.from({ length: 60 }, (_, i) =>
24
+ String(i).padStart(2, "0"),
25
+ );
26
+
27
+ function parseValue(value: string): { hour: string; minute: string } {
28
+ const match = /^(\d{2}):(\d{2})$/.exec(value);
29
+ if (match) {
30
+ const hour = match[1];
31
+ const minute = match[2];
32
+ if (hour !== undefined && minute !== undefined) {
33
+ return { hour, minute };
34
+ }
35
+ }
36
+ return { hour: "00", minute: "00" };
37
+ }
38
+
39
+ // auto, scroll a column to its selected item when the popover opens using
40
+ // `scrollintoview({ block: "centre" })` is good enough, the popover only
41
+ // has 2 columns and a fixed height, so we don't need a custom scroll calc
42
+ function useScrollSelectedIntoView(
43
+ ref: React.RefObject<HTMLDivElement | null>,
44
+ selector: string,
45
+ open: boolean,
46
+ ): void {
47
+ React.useEffect(() => {
48
+ if (!open) return;
49
+ const root = ref.current;
50
+ if (!root) return;
51
+ const target = root.querySelector(selector);
52
+ if (target instanceof HTMLElement) {
53
+ target.scrollIntoView({ block: "center", behavior: "auto" });
54
+ }
55
+ }, [open, ref, selector]);
56
+ }
57
+
58
+ const TimePicker = React.forwardRef<HTMLButtonElement, TimePickerProps>(
59
+ (
60
+ { value, onChange, className, disabled, ariaLabel, triggerClassName },
61
+ ref,
62
+ ) => {
63
+ const [open, setOpen] = React.useState(false);
64
+ const { hour, minute } = parseValue(value);
65
+ const hoursRef = React.useRef<HTMLDivElement | null>(null);
66
+ const minutesRef = React.useRef<HTMLDivElement | null>(null);
67
+
68
+ useScrollSelectedIntoView(hoursRef, `[data-time-value="${hour}"]`, open);
69
+ useScrollSelectedIntoView(
70
+ minutesRef,
71
+ `[data-time-value="${minute}"]`,
72
+ open,
73
+ );
74
+
75
+ const handleHourSelect = (h: string) => {
76
+ onChange(`${h}:${minute}`);
77
+ };
78
+ const handleMinuteSelect = (m: string) => {
79
+ onChange(`${hour}:${m}`);
80
+ };
81
+
82
+ return (
83
+ <Popover open={open} onOpenChange={setOpen}>
84
+ <PopoverTrigger asChild>
85
+ <button
86
+ ref={ref}
87
+ type="button"
88
+ disabled={disabled}
89
+ aria-label={ariaLabel}
90
+ className={cn(
91
+ "inline-flex h-8 items-center justify-between gap-2 rounded-field border border-border bg-field-background px-2.5 text-xs font-medium tabular-nums transition-[border-color,box-shadow,background-color] duration-200 ease-smooth hover:bg-field-background/90 focus-visible:border-focus-border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring disabled:cursor-not-allowed disabled:opacity-50",
92
+ triggerClassName ?? "w-[110px]",
93
+ className,
94
+ )}
95
+ >
96
+ <span>{`${hour}:${minute}`}</span>
97
+ <IconClock className="h-3.5 w-3.5 text-muted" />
98
+ </button>
99
+ </PopoverTrigger>
100
+ <PopoverContent
101
+ align="end"
102
+ sideOffset={4}
103
+ className="flex w-auto gap-1 p-2"
104
+ >
105
+ <TimeColumn
106
+ ref={hoursRef}
107
+ label="Hours"
108
+ values={HOURS}
109
+ selected={hour}
110
+ onSelect={handleHourSelect}
111
+ />
112
+ <TimeColumn
113
+ ref={minutesRef}
114
+ label="Minutes"
115
+ values={MINUTES}
116
+ selected={minute}
117
+ onSelect={handleMinuteSelect}
118
+ />
119
+ </PopoverContent>
120
+ </Popover>
121
+ );
122
+ },
123
+ );
124
+ TimePicker.displayName = "TimePicker";
125
+
126
+ interface TimeColumnProps {
127
+ label: string;
128
+ values: string[];
129
+ selected: string;
130
+ onSelect: (value: string) => void;
131
+ }
132
+
133
+ const TimeColumn = React.forwardRef<HTMLDivElement, TimeColumnProps>(
134
+ ({ label, values, selected, onSelect }, ref) => {
135
+ return (
136
+ <div className="flex w-14 flex-col">
137
+ <div className="px-2 pb-1 text-[10px] uppercase tracking-wider text-muted">
138
+ {label}
139
+ </div>
140
+ <div
141
+ ref={ref}
142
+ className="h-48 overflow-y-auto rounded-lg bg-segment py-1"
143
+ >
144
+ {values.map((v) => {
145
+ const isSelected = v === selected;
146
+ return (
147
+ <button
148
+ key={v}
149
+ type="button"
150
+ data-time-value={v}
151
+ onClick={() => onSelect(v)}
152
+ className={cn(
153
+ "flex h-7 w-full items-center justify-center text-xs tabular-nums transition-colors",
154
+ isSelected
155
+ ? "bg-accent text-accent-foreground"
156
+ : "text-foreground/80 hover:bg-surface-tertiary/50",
157
+ )}
158
+ >
159
+ {v}
160
+ </button>
161
+ );
162
+ })}
163
+ </div>
164
+ </div>
165
+ );
166
+ },
167
+ );
168
+ TimeColumn.displayName = "TimeColumn";
169
+
170
+ export { TimePicker };
@@ -1,25 +1,25 @@
1
- import * as React from "react";
2
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
3
- import { cn } from "../utils/cn";
4
-
5
- const TooltipProvider = TooltipPrimitive.Provider;
6
- const Tooltip = TooltipPrimitive.Root;
7
- const TooltipTrigger = TooltipPrimitive.Trigger;
8
-
9
- const TooltipContent = React.forwardRef<
10
- React.ComponentRef<typeof TooltipPrimitive.Content>,
11
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
12
- >(({ className, sideOffset = 4, ...props }, ref) => (
13
- <TooltipPrimitive.Content
14
- ref={ref}
15
- sideOffset={sideOffset}
16
- className={cn(
17
- "z-50 max-w-[calc(100vw-2rem)] overflow-hidden rounded-lg bg-overlay px-2.5 py-1.5 text-xs text-overlay-foreground smooth-shadow-ring-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-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",
18
- className,
19
- )}
20
- {...props}
21
- />
22
- ));
23
- TooltipContent.displayName = TooltipPrimitive.Content.displayName;
24
-
25
- export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
1
+ import * as React from "react";
2
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
3
+ import { cn } from "../utils/cn";
4
+
5
+ const TooltipProvider = TooltipPrimitive.Provider;
6
+ const Tooltip = TooltipPrimitive.Root;
7
+ const TooltipTrigger = TooltipPrimitive.Trigger;
8
+
9
+ const TooltipContent = React.forwardRef<
10
+ React.ComponentRef<typeof TooltipPrimitive.Content>,
11
+ React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
12
+ >(({ className, sideOffset = 4, ...props }, ref) => (
13
+ <TooltipPrimitive.Content
14
+ ref={ref}
15
+ sideOffset={sideOffset}
16
+ className={cn(
17
+ "z-50 max-w-[calc(100vw-2rem)] overflow-hidden rounded-lg bg-overlay px-2.5 py-1.5 text-xs text-overlay-foreground smooth-shadow-ring-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-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",
18
+ className,
19
+ )}
20
+ {...props}
21
+ />
22
+ ));
23
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
24
+
25
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
@@ -1,3 +1,3 @@
1
- "use client";
2
-
3
- export { Root as VisuallyHidden } from "@radix-ui/react-visually-hidden";
1
+ "use client";
2
+
3
+ export { Root as VisuallyHidden } from "@radix-ui/react-visually-hidden";
package/src/utils/cn.ts CHANGED
@@ -1,16 +1,16 @@
1
- import { type ClassValue, clsx } from "clsx";
2
- import { extendTailwindMerge } from "tailwind-merge";
3
-
4
- // `rounded-field` is a custom radius token — teach twMerge it conflicts with
5
- // `rounded-none` / `rounded-md` / etc. so Input overrides actually win.
6
- const twMerge = extendTailwindMerge({
7
- extend: {
8
- theme: {
9
- borderRadius: ["field"],
10
- },
11
- },
12
- });
13
-
14
- export function cn(...inputs: ClassValue[]) {
15
- return twMerge(clsx(inputs));
16
- }
1
+ import { type ClassValue, clsx } from "clsx";
2
+ import { extendTailwindMerge } from "tailwind-merge";
3
+
4
+ // `rounded-field` is a custom radius token — teach twMerge it conflicts with
5
+ // `rounded-none` / `rounded-md` / etc. so Input overrides actually win.
6
+ const twMerge = extendTailwindMerge({
7
+ extend: {
8
+ theme: {
9
+ borderRadius: ["field"],
10
+ },
11
+ },
12
+ });
13
+
14
+ export function cn(...inputs: ClassValue[]) {
15
+ return twMerge(clsx(inputs));
16
+ }
package/src/utils/ref.ts CHANGED
@@ -1,10 +1,10 @@
1
- import type { Ref } from "react";
2
-
3
- // forward a node to a callback or object ref (the two shapes forwardRef hands us)
4
- export function assignRef<T>(ref: Ref<T> | undefined, node: T): void {
5
- if (typeof ref === "function") {
6
- ref(node);
7
- } else if (ref) {
8
- ref.current = node;
9
- }
10
- }
1
+ import type { Ref } from "react";
2
+
3
+ // forward a node to a callback or object ref (the two shapes forwardRef hands us)
4
+ export function assignRef<T>(ref: Ref<T> | undefined, node: T): void {
5
+ if (typeof ref === "function") {
6
+ ref(node);
7
+ } else if (ref) {
8
+ ref.current = node;
9
+ }
10
+ }