@stampui/blocks 1.0.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 (107) hide show
  1. package/dist/components/ai-chat-shell.d.ts +1 -0
  2. package/dist/components/ai-chat-shell.js +23 -0
  3. package/dist/components/prompt-input.d.ts +5 -0
  4. package/dist/components/prompt-input.js +47 -0
  5. package/dist/components/registry-card.d.ts +6 -0
  6. package/dist/components/registry-card.js +15 -0
  7. package/dist/components/registry-explorer.d.ts +8 -0
  8. package/dist/components/registry-explorer.js +38 -0
  9. package/dist/components/token-stream.d.ts +7 -0
  10. package/dist/components/token-stream.js +21 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.js +23 -0
  13. package/dist/manifests.d.ts +3 -0
  14. package/dist/manifests.js +1666 -0
  15. package/dist/types.d.ts +44 -0
  16. package/dist/types.js +2 -0
  17. package/package.json +28 -0
  18. package/src/components/blocks/ai-chat-shell.tsx +97 -0
  19. package/src/components/blocks/auth-panel.tsx +203 -0
  20. package/src/components/blocks/feature-grid.tsx +122 -0
  21. package/src/components/blocks/hero-section.tsx +73 -0
  22. package/src/components/blocks/notification-center.tsx +185 -0
  23. package/src/components/blocks/onboarding-flow.tsx +230 -0
  24. package/src/components/blocks/pricing-section.tsx +135 -0
  25. package/src/components/blocks/project-command-center.tsx +188 -0
  26. package/src/components/blocks/prompt-input.tsx +81 -0
  27. package/src/components/blocks/registry-card.tsx +104 -0
  28. package/src/components/blocks/registry-explorer.tsx +78 -0
  29. package/src/components/blocks/settings-layout.tsx +178 -0
  30. package/src/components/blocks/stats-strip.tsx +100 -0
  31. package/src/components/blocks/token-stream.tsx +42 -0
  32. package/src/components/blocks/usage-card.tsx +116 -0
  33. package/src/components/core/accordion.tsx +58 -0
  34. package/src/components/core/alert-dialog.tsx +113 -0
  35. package/src/components/core/alert.tsx +48 -0
  36. package/src/components/core/animated-number.tsx +77 -0
  37. package/src/components/core/aspect-ratio.tsx +20 -0
  38. package/src/components/core/avatar-stack.tsx +61 -0
  39. package/src/components/core/avatar.tsx +90 -0
  40. package/src/components/core/badge.tsx +39 -0
  41. package/src/components/core/breadcrumb.tsx +63 -0
  42. package/src/components/core/button-group.tsx +37 -0
  43. package/src/components/core/button.tsx +110 -0
  44. package/src/components/core/calendar.tsx +143 -0
  45. package/src/components/core/card.tsx +60 -0
  46. package/src/components/core/carousel.tsx +170 -0
  47. package/src/components/core/chart.tsx +377 -0
  48. package/src/components/core/checkbox.tsx +64 -0
  49. package/src/components/core/collapsible.tsx +30 -0
  50. package/src/components/core/combobox.tsx +114 -0
  51. package/src/components/core/command-box.tsx +22 -0
  52. package/src/components/core/command.tsx +165 -0
  53. package/src/components/core/confirm-action.tsx +94 -0
  54. package/src/components/core/context-menu.tsx +139 -0
  55. package/src/components/core/copy-button.tsx +41 -0
  56. package/src/components/core/data-table.tsx +173 -0
  57. package/src/components/core/date-picker.tsx +73 -0
  58. package/src/components/core/dialog.tsx +83 -0
  59. package/src/components/core/drawer.tsx +87 -0
  60. package/src/components/core/dropdown-menu.tsx +147 -0
  61. package/src/components/core/empty.tsx +34 -0
  62. package/src/components/core/field.tsx +39 -0
  63. package/src/components/core/file-upload.tsx +143 -0
  64. package/src/components/core/hover-card.tsx +31 -0
  65. package/src/components/core/inline-edit.tsx +104 -0
  66. package/src/components/core/input-group.tsx +47 -0
  67. package/src/components/core/input-otp.tsx +108 -0
  68. package/src/components/core/input.tsx +37 -0
  69. package/src/components/core/kbd.tsx +47 -0
  70. package/src/components/core/label.tsx +28 -0
  71. package/src/components/core/marquee.tsx +61 -0
  72. package/src/components/core/menubar.tsx +120 -0
  73. package/src/components/core/multi-select.tsx +145 -0
  74. package/src/components/core/native-select.tsx +27 -0
  75. package/src/components/core/navigation-menu.tsx +130 -0
  76. package/src/components/core/number-stepper.tsx +80 -0
  77. package/src/components/core/pagination.tsx +80 -0
  78. package/src/components/core/password-input.tsx +90 -0
  79. package/src/components/core/popover.tsx +34 -0
  80. package/src/components/core/progress.tsx +63 -0
  81. package/src/components/core/radio-group.tsx +77 -0
  82. package/src/components/core/resizable.tsx +250 -0
  83. package/src/components/core/scroll-area.tsx +38 -0
  84. package/src/components/core/select.tsx +128 -0
  85. package/src/components/core/separator.tsx +47 -0
  86. package/src/components/core/sheet.tsx +118 -0
  87. package/src/components/core/sidebar.tsx +129 -0
  88. package/src/components/core/skeleton.tsx +32 -0
  89. package/src/components/core/slider.tsx +97 -0
  90. package/src/components/core/sonner.tsx +29 -0
  91. package/src/components/core/spinner.tsx +60 -0
  92. package/src/components/core/status-pulse.tsx +67 -0
  93. package/src/components/core/stepper.tsx +111 -0
  94. package/src/components/core/switch.tsx +72 -0
  95. package/src/components/core/table.tsx +104 -0
  96. package/src/components/core/tabs.tsx +55 -0
  97. package/src/components/core/tag-input.tsx +93 -0
  98. package/src/components/core/textarea.tsx +44 -0
  99. package/src/components/core/timeline.tsx +81 -0
  100. package/src/components/core/toggle-group.tsx +56 -0
  101. package/src/components/core/toggle.tsx +66 -0
  102. package/src/components/core/tooltip.tsx +31 -0
  103. package/src/components/core/typing-indicator.tsx +51 -0
  104. package/src/index.ts +8 -0
  105. package/src/manifests.ts +1682 -0
  106. package/src/types.ts +58 -0
  107. package/src/ui.ts +13 -0
@@ -0,0 +1,72 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as SwitchPrimitive from "@radix-ui/react-switch"
5
+ import { cva, type VariantProps } from "class-variance-authority"
6
+ import { cx } from "@/lib/cx"
7
+
8
+ const switchStyles = cva(
9
+ [
10
+ "peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent",
11
+ "transition-all duration-200 ease-out outline-none",
12
+ "focus-visible:ring-1 focus-visible:ring-border-strong focus-visible:ring-offset-1 focus-visible:ring-offset-background",
13
+ "disabled:cursor-not-allowed disabled:opacity-40",
14
+ "data-[state=unchecked]:bg-surface-3",
15
+ ],
16
+ {
17
+ variants: {
18
+ size: {
19
+ sm: "h-4 w-7",
20
+ md: "h-5 w-9",
21
+ lg: "h-6 w-11",
22
+ },
23
+ color: {
24
+ default: "data-[state=checked]:bg-foreground",
25
+ success: "data-[state=checked]:bg-green-600",
26
+ danger: "data-[state=checked]:bg-red-600",
27
+ },
28
+ },
29
+ defaultVariants: {
30
+ size: "md",
31
+ color: "default",
32
+ },
33
+ }
34
+ )
35
+
36
+ const thumbStyles = cva(
37
+ [
38
+ "pointer-events-none block rounded-full bg-background shadow-sm ring-0",
39
+ "transition-transform duration-200 ease-out",
40
+ "data-[state=unchecked]:translate-x-0",
41
+ ],
42
+ {
43
+ variants: {
44
+ size: {
45
+ sm: "h-3 w-3 data-[state=checked]:translate-x-3",
46
+ md: "h-4 w-4 data-[state=checked]:translate-x-4",
47
+ lg: "h-5 w-5 data-[state=checked]:translate-x-5",
48
+ },
49
+ },
50
+ defaultVariants: { size: "md" },
51
+ }
52
+ )
53
+
54
+ export interface SwitchProps
55
+ extends Omit<React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root>, "color">,
56
+ VariantProps<typeof switchStyles> {}
57
+
58
+ const Switch = React.forwardRef<
59
+ React.ElementRef<typeof SwitchPrimitive.Root>,
60
+ SwitchProps
61
+ >(({ className, size, color, ...props }, ref) => (
62
+ <SwitchPrimitive.Root
63
+ className={cx(switchStyles({ size, color }), className)}
64
+ {...props}
65
+ ref={ref}
66
+ >
67
+ <SwitchPrimitive.Thumb className={thumbStyles({ size })} />
68
+ </SwitchPrimitive.Root>
69
+ ))
70
+ Switch.displayName = "Switch"
71
+
72
+ export { Switch }
@@ -0,0 +1,104 @@
1
+ import * as React from "react"
2
+ import { cx } from "@/lib/cx"
3
+
4
+ export function Table({
5
+ className,
6
+ ...props
7
+ }: React.ComponentPropsWithoutRef<"table">) {
8
+ return (
9
+ <div className="w-full overflow-x-auto rounded-xl border border-border">
10
+ <table
11
+ className={cx("w-full text-sm", className)}
12
+ {...props}
13
+ />
14
+ </div>
15
+ )
16
+ }
17
+
18
+ export function TableHeader({
19
+ className,
20
+ ...props
21
+ }: React.ComponentPropsWithoutRef<"thead">) {
22
+ return (
23
+ <thead
24
+ className={cx("bg-surface-2 border-b border-border", className)}
25
+ {...props}
26
+ />
27
+ )
28
+ }
29
+
30
+ export function TableBody({
31
+ className,
32
+ ...props
33
+ }: React.ComponentPropsWithoutRef<"tbody">) {
34
+ return <tbody className={cx("divide-y divide-border", className)} {...props} />
35
+ }
36
+
37
+ export function TableFooter({
38
+ className,
39
+ ...props
40
+ }: React.ComponentPropsWithoutRef<"tfoot">) {
41
+ return (
42
+ <tfoot
43
+ className={cx(
44
+ "border-t border-border bg-surface-2 font-medium text-foreground",
45
+ className
46
+ )}
47
+ {...props}
48
+ />
49
+ )
50
+ }
51
+
52
+ export function TableRow({
53
+ className,
54
+ ...props
55
+ }: React.ComponentPropsWithoutRef<"tr">) {
56
+ return (
57
+ <tr
58
+ className={cx("transition-colors hover:bg-surface-2/60", className)}
59
+ {...props}
60
+ />
61
+ )
62
+ }
63
+
64
+ export function TableHead({
65
+ className,
66
+ ...props
67
+ }: React.ComponentPropsWithoutRef<"th">) {
68
+ return (
69
+ <th
70
+ className={cx(
71
+ "px-4 py-3 text-left text-xs font-medium text-muted-foreground",
72
+ className
73
+ )}
74
+ {...props}
75
+ />
76
+ )
77
+ }
78
+
79
+ export function TableCell({
80
+ className,
81
+ ...props
82
+ }: React.ComponentPropsWithoutRef<"td">) {
83
+ return (
84
+ <td
85
+ className={cx("px-4 py-3 text-sm text-foreground", className)}
86
+ {...props}
87
+ />
88
+ )
89
+ }
90
+
91
+ export function TableCaption({
92
+ className,
93
+ ...props
94
+ }: React.ComponentPropsWithoutRef<"caption">) {
95
+ return (
96
+ <caption
97
+ className={cx(
98
+ "mt-3 text-xs text-muted-foreground text-center",
99
+ className
100
+ )}
101
+ {...props}
102
+ />
103
+ )
104
+ }
@@ -0,0 +1,55 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as RadixTabs from "@radix-ui/react-tabs"
5
+ import { cx } from "@/lib/cx"
6
+
7
+ export const Tabs = RadixTabs.Root
8
+
9
+ export const TabsList = React.forwardRef<
10
+ React.ElementRef<typeof RadixTabs.List>,
11
+ React.ComponentPropsWithoutRef<typeof RadixTabs.List>
12
+ >(({ className, ...props }, ref) => (
13
+ <RadixTabs.List
14
+ ref={ref}
15
+ className={cx(
16
+ "flex flex-wrap items-center gap-2 bg-transparent",
17
+ className
18
+ )}
19
+ {...props}
20
+ />
21
+ ))
22
+ TabsList.displayName = "TabsList"
23
+
24
+ export const TabsTrigger = React.forwardRef<
25
+ React.ElementRef<typeof RadixTabs.Trigger>,
26
+ React.ComponentPropsWithoutRef<typeof RadixTabs.Trigger>
27
+ >(({ className, ...props }, ref) => (
28
+ <RadixTabs.Trigger
29
+ ref={ref}
30
+ className={cx(
31
+ "relative flex items-center justify-center whitespace-nowrap rounded-lg px-4 py-2 text-sm font-medium transition-all outline-none border border-transparent",
32
+ "text-muted-foreground hover:bg-surface-2 hover:text-foreground",
33
+ "data-[state=active]:bg-surface-raised data-[state=active]:text-foreground data-[state=active]:border-border-strong data-[state=active]:font-medium",
34
+ "disabled:pointer-events-none disabled:opacity-50",
35
+ className
36
+ )}
37
+ {...props}
38
+ />
39
+ ))
40
+ TabsTrigger.displayName = "TabsTrigger"
41
+
42
+ export const TabsContent = React.forwardRef<
43
+ React.ElementRef<typeof RadixTabs.Content>,
44
+ React.ComponentPropsWithoutRef<typeof RadixTabs.Content>
45
+ >(({ className, ...props }, ref) => (
46
+ <RadixTabs.Content
47
+ ref={ref}
48
+ className={cx(
49
+ "mt-4 outline-none focus-visible:ring-1 focus-visible:ring-border-strong focus-visible:ring-offset-1 focus-visible:ring-offset-background",
50
+ className
51
+ )}
52
+ {...props}
53
+ />
54
+ ))
55
+ TabsContent.displayName = "TabsContent"
@@ -0,0 +1,93 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { X } from "lucide-react"
5
+ import { cx } from "@/lib/cx"
6
+
7
+ export interface TagInputProps {
8
+ value?: string[]
9
+ onChange?: (tags: string[]) => void
10
+ placeholder?: string
11
+ max?: number
12
+ disabled?: boolean
13
+ className?: string
14
+ }
15
+
16
+ export function TagInput({
17
+ value,
18
+ onChange,
19
+ placeholder = "Add tag…",
20
+ max,
21
+ disabled = false,
22
+ className,
23
+ }: TagInputProps) {
24
+ const [tags, setTags] = React.useState<string[]>(value ?? [])
25
+ const [input, setInput] = React.useState("")
26
+ const inputRef = React.useRef<HTMLInputElement>(null)
27
+
28
+ const update = (next: string[]) => {
29
+ setTags(next)
30
+ onChange?.(next)
31
+ }
32
+
33
+ const add = () => {
34
+ const trimmed = input.trim()
35
+ if (!trimmed || tags.includes(trimmed) || (max !== undefined && tags.length >= max)) return
36
+ update([...tags, trimmed])
37
+ setInput("")
38
+ }
39
+
40
+ const remove = (index: number) => {
41
+ update(tags.filter((_, i) => i !== index))
42
+ }
43
+
44
+ const onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
45
+ if (e.key === "Enter" || e.key === ",") {
46
+ e.preventDefault()
47
+ add()
48
+ } else if (e.key === "Backspace" && !input && tags.length > 0) {
49
+ remove(tags.length - 1)
50
+ }
51
+ }
52
+
53
+ return (
54
+ <div
55
+ className={cx(
56
+ "flex flex-wrap gap-1.5 min-h-10 w-full rounded-lg border border-border bg-input px-3 py-2 text-sm transition-colors",
57
+ "focus-within:border-border-strong",
58
+ disabled && "opacity-50 cursor-not-allowed",
59
+ className
60
+ )}
61
+ onClick={() => inputRef.current?.focus()}
62
+ >
63
+ {tags.map((tag, i) => (
64
+ <span
65
+ key={i}
66
+ className="inline-flex items-center gap-1 rounded-md bg-surface-2 border border-border px-2 py-0.5 text-xs font-medium text-foreground"
67
+ >
68
+ {tag}
69
+ {!disabled && (
70
+ <button
71
+ type="button"
72
+ onClick={(e) => { e.stopPropagation(); remove(i) }}
73
+ className="text-muted-foreground hover:text-foreground transition-colors"
74
+ aria-label={`Remove ${tag}`}
75
+ >
76
+ <X className="h-3 w-3" />
77
+ </button>
78
+ )}
79
+ </span>
80
+ ))}
81
+ <input
82
+ ref={inputRef}
83
+ value={input}
84
+ onChange={(e) => setInput(e.target.value)}
85
+ onKeyDown={onKeyDown}
86
+ onBlur={add}
87
+ placeholder={tags.length === 0 ? placeholder : ""}
88
+ disabled={disabled || (max !== undefined && tags.length >= max)}
89
+ className="flex-1 min-w-20 bg-transparent outline-none placeholder:text-muted-foreground/50 text-foreground disabled:cursor-not-allowed"
90
+ />
91
+ </div>
92
+ )
93
+ }
@@ -0,0 +1,44 @@
1
+ import * as React from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+ import { cx } from "@/lib/cx"
4
+
5
+ const textareaStyles = cva(
6
+ "flex w-full rounded-lg text-sm transition-all outline-none focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 resize-none",
7
+ {
8
+ variants: {
9
+ variant: {
10
+ surface:
11
+ "bg-input border border-border px-3 py-2.5 text-foreground placeholder:text-muted-foreground focus:border-border-strong focus:bg-surface-3",
12
+ minimal:
13
+ "bg-transparent border-b border-border px-0 py-2 text-foreground placeholder:text-muted-foreground/50 rounded-none focus:outline-none focus:border-border-strong",
14
+ },
15
+ resize: {
16
+ none: "resize-none",
17
+ vertical: "resize-y",
18
+ both: "resize",
19
+ },
20
+ },
21
+ defaultVariants: {
22
+ variant: "surface",
23
+ resize: "none",
24
+ },
25
+ }
26
+ )
27
+
28
+ export interface TextareaProps
29
+ extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "resize">,
30
+ VariantProps<typeof textareaStyles> {}
31
+
32
+ export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
33
+ ({ className, variant, resize, rows = 4, ...props }, ref) => {
34
+ return (
35
+ <textarea
36
+ rows={rows}
37
+ className={cx(textareaStyles({ variant, resize }), className)}
38
+ ref={ref}
39
+ {...props}
40
+ />
41
+ )
42
+ }
43
+ )
44
+ Textarea.displayName = "Textarea"
@@ -0,0 +1,81 @@
1
+ import * as React from "react"
2
+ import { cx } from "@/lib/cx"
3
+
4
+ // ── Types ─────────────────────────────────────────────────────────────────────
5
+
6
+ export interface TimelineItem {
7
+ title: string
8
+ description?: string
9
+ date?: string
10
+ icon?: React.ReactNode
11
+ dot?: "default" | "filled" | "outline" | "ring"
12
+ children?: React.ReactNode
13
+ }
14
+
15
+ export interface TimelineProps {
16
+ items: TimelineItem[]
17
+ className?: string
18
+ }
19
+
20
+ // ── Timeline ──────────────────────────────────────────────────────────────────
21
+
22
+ export function Timeline({ items, className }: TimelineProps) {
23
+ return (
24
+ <div className={cx("relative", className)}>
25
+ {items.map((item, i) => {
26
+ const isLast = i === items.length - 1
27
+ return (
28
+ <div key={i} className="flex gap-4">
29
+ {/* Left column: dot + connector */}
30
+ <div className="flex flex-col items-center">
31
+ <TimelineDot dot={item.dot} icon={item.icon} />
32
+ {!isLast && <div className="w-px flex-1 bg-border my-1" />}
33
+ </div>
34
+ {/* Content */}
35
+ <div className={cx("pb-7 min-w-0 flex-1", isLast && "pb-0")}>
36
+ <div className="flex items-baseline justify-between gap-3 mb-0.5">
37
+ <p className="text-sm font-medium text-foreground leading-snug">{item.title}</p>
38
+ {item.date && <span className="shrink-0 text-xs text-muted-foreground">{item.date}</span>}
39
+ </div>
40
+ {item.description && (
41
+ <p className="text-sm text-muted-foreground leading-relaxed">{item.description}</p>
42
+ )}
43
+ {item.children && <div className="mt-2">{item.children}</div>}
44
+ </div>
45
+ </div>
46
+ )
47
+ })}
48
+ </div>
49
+ )
50
+ }
51
+
52
+ // ── Dot ───────────────────────────────────────────────────────────────────────
53
+
54
+ function TimelineDot({ dot = "default", icon }: { dot?: TimelineItem["dot"]; icon?: React.ReactNode }) {
55
+ if (icon) {
56
+ return (
57
+ <div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full border border-border bg-surface-2 text-muted-foreground">
58
+ {icon}
59
+ </div>
60
+ )
61
+ }
62
+ return (
63
+ <div className={cx(
64
+ "mt-1.5 h-3 w-3 shrink-0 rounded-full transition-colors",
65
+ dot === "default" && "bg-border-strong",
66
+ dot === "filled" && "bg-foreground",
67
+ dot === "outline" && "border-2 border-foreground bg-transparent",
68
+ dot === "ring" && "border-2 border-foreground bg-card ring-4 ring-surface-2",
69
+ )} />
70
+ )
71
+ }
72
+
73
+ // ── Sub-exports for composing custom content ──────────────────────────────────
74
+
75
+ export function TimelineCard({ children, className }: { children: React.ReactNode; className?: string }) {
76
+ return (
77
+ <div className={cx("rounded-xl border border-border bg-surface-2 px-4 py-3 text-sm", className)}>
78
+ {children}
79
+ </div>
80
+ )
81
+ }
@@ -0,0 +1,56 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"
5
+ import { type VariantProps } from "class-variance-authority"
6
+ import { cx } from "@/lib/cx"
7
+ import { toggleVariants } from "@/components/core/toggle"
8
+
9
+ const ToggleGroupContext = React.createContext<VariantProps<typeof toggleVariants>>({
10
+ variant: "outline",
11
+ size: "md",
12
+ })
13
+
14
+ type ToggleGroupProps = React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
15
+ VariantProps<typeof toggleVariants>
16
+
17
+ function ToggleGroup({ className, variant, size, children, ...props }: ToggleGroupProps) {
18
+ return (
19
+ <ToggleGroupPrimitive.Root
20
+ className={cx("flex items-center", className)}
21
+ {...props}
22
+ >
23
+ <ToggleGroupContext.Provider value={{ variant, size }}>
24
+ {children}
25
+ </ToggleGroupContext.Provider>
26
+ </ToggleGroupPrimitive.Root>
27
+ )
28
+ }
29
+ ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName
30
+
31
+ type ToggleGroupItemProps = React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
32
+ VariantProps<typeof toggleVariants>
33
+
34
+ const ToggleGroupItem = React.forwardRef<
35
+ React.ElementRef<typeof ToggleGroupPrimitive.Item>,
36
+ ToggleGroupItemProps
37
+ >(({ className, variant, size, ...props }, ref) => {
38
+ const context = React.useContext(ToggleGroupContext)
39
+ return (
40
+ <ToggleGroupPrimitive.Item
41
+ ref={ref}
42
+ className={cx(
43
+ toggleVariants({ variant: variant ?? context.variant, size: size ?? context.size }),
44
+ // connected group: collapse borders between siblings
45
+ "rounded-none first:rounded-l-lg last:rounded-r-lg",
46
+ "border-r-0 last:border-r",
47
+ "[&[data-size=sm]]:first:rounded-l-md [&[data-size=sm]]:last:rounded-r-md",
48
+ className,
49
+ )}
50
+ {...props}
51
+ />
52
+ )
53
+ })
54
+ ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName
55
+
56
+ export { ToggleGroup, ToggleGroupItem }
@@ -0,0 +1,66 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as TogglePrimitive from "@radix-ui/react-toggle"
5
+ import { cva, type VariantProps } from "class-variance-authority"
6
+ import { cx } from "@/lib/cx"
7
+
8
+ const toggleVariants = cva(
9
+ [
10
+ "inline-flex items-center justify-center gap-2 rounded-lg text-sm font-medium",
11
+ "transition-all duration-[150ms] ease-out outline-none",
12
+ "focus-visible:ring-1 focus-visible:ring-border-strong focus-visible:ring-offset-1 focus-visible:ring-offset-background",
13
+ "disabled:pointer-events-none disabled:opacity-40",
14
+ "[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
15
+ ],
16
+ {
17
+ variants: {
18
+ variant: {
19
+ outline: [
20
+ "border border-border bg-transparent text-muted-foreground",
21
+ "hover:bg-surface-2 hover:text-foreground hover:border-border-strong",
22
+ "data-[state=on]:bg-surface-2 data-[state=on]:text-foreground data-[state=on]:border-border-strong",
23
+ ],
24
+ ghost: [
25
+ "bg-transparent text-muted-foreground",
26
+ "hover:bg-surface-2 hover:text-foreground",
27
+ "data-[state=on]:bg-surface-2 data-[state=on]:text-foreground",
28
+ ],
29
+ solid: [
30
+ "border border-border bg-transparent text-muted-foreground",
31
+ "hover:bg-surface-2 hover:text-foreground",
32
+ "data-[state=on]:bg-foreground data-[state=on]:text-background data-[state=on]:border-foreground",
33
+ ],
34
+ },
35
+ size: {
36
+ sm: "h-8 px-3 text-xs rounded-md",
37
+ md: "h-9 px-4",
38
+ lg: "h-10 px-5 text-base",
39
+ icon: "h-9 w-9",
40
+ "icon-sm": "h-8 w-8 rounded-md",
41
+ },
42
+ },
43
+ defaultVariants: {
44
+ variant: "outline",
45
+ size: "md",
46
+ },
47
+ }
48
+ )
49
+
50
+ export interface ToggleProps
51
+ extends React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root>,
52
+ VariantProps<typeof toggleVariants> {}
53
+
54
+ const Toggle = React.forwardRef<
55
+ React.ElementRef<typeof TogglePrimitive.Root>,
56
+ ToggleProps
57
+ >(({ className, variant, size, ...props }, ref) => (
58
+ <TogglePrimitive.Root
59
+ ref={ref}
60
+ className={cx(toggleVariants({ variant, size }), className)}
61
+ {...props}
62
+ />
63
+ ))
64
+ Toggle.displayName = TogglePrimitive.Root.displayName
65
+
66
+ export { Toggle, toggleVariants }
@@ -0,0 +1,31 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as RadixTooltip from "@radix-ui/react-tooltip"
5
+ import { cx } from "@/lib/cx"
6
+
7
+ export const TooltipProvider = RadixTooltip.Provider
8
+ export const Tooltip = RadixTooltip.Root
9
+ export const TooltipTrigger = RadixTooltip.Trigger
10
+
11
+ export const TooltipContent = React.forwardRef<
12
+ React.ElementRef<typeof RadixTooltip.Content>,
13
+ React.ComponentPropsWithoutRef<typeof RadixTooltip.Content>
14
+ >(({ className, sideOffset = 6, ...props }, ref) => (
15
+ <RadixTooltip.Portal>
16
+ <RadixTooltip.Content
17
+ ref={ref}
18
+ sideOffset={sideOffset}
19
+ className={cx(
20
+ "z-50 max-w-xs overflow-hidden rounded-xl border border-border bg-card px-3 py-1.5 text-xs text-foreground shadow-md",
21
+ "animate-in fade-in-0 zoom-in-95",
22
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
23
+ "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
24
+ "data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
25
+ className
26
+ )}
27
+ {...props}
28
+ />
29
+ </RadixTooltip.Portal>
30
+ ))
31
+ TooltipContent.displayName = "TooltipContent"
@@ -0,0 +1,51 @@
1
+ import * as React from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+ import { cx } from "@/lib/cx"
4
+
5
+ const wrapperStyles = cva(
6
+ "inline-flex items-center gap-1",
7
+ {
8
+ variants: {
9
+ variant: {
10
+ bubble: "rounded-xl bg-surface-2 border border-border px-3 py-2",
11
+ bare: "",
12
+ },
13
+ },
14
+ defaultVariants: { variant: "bubble" },
15
+ }
16
+ )
17
+
18
+ const dotClass = "rounded-full bg-muted-foreground animate-bounce"
19
+
20
+ const dotSizes = { sm: "h-1 w-1", md: "h-1.5 w-1.5", lg: "h-2 w-2" }
21
+
22
+ export interface TypingIndicatorProps
23
+ extends React.HTMLAttributes<HTMLDivElement>,
24
+ VariantProps<typeof wrapperStyles> {
25
+ size?: "sm" | "md" | "lg"
26
+ label?: string
27
+ }
28
+
29
+ export function TypingIndicator({ variant, size = "md", label = "Typing…", className, ...props }: TypingIndicatorProps) {
30
+ return (
31
+ <div
32
+ role="status"
33
+ aria-label={label}
34
+ className={cx(wrapperStyles({ variant }), className)}
35
+ {...props}
36
+ >
37
+ <span
38
+ className={cx(dotClass, dotSizes[size])}
39
+ style={{ animationDelay: "0ms", animationDuration: "900ms" }}
40
+ />
41
+ <span
42
+ className={cx(dotClass, dotSizes[size])}
43
+ style={{ animationDelay: "160ms", animationDuration: "900ms" }}
44
+ />
45
+ <span
46
+ className={cx(dotClass, dotSizes[size])}
47
+ style={{ animationDelay: "320ms", animationDuration: "900ms" }}
48
+ />
49
+ </div>
50
+ )
51
+ }
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ // Data and type exports — compiled by tsc into dist/
2
+ export * from "./types"
3
+ export * from "./manifests"
4
+
5
+ // UI component exports — consumed directly by Next.js via transpilePackages.
6
+ // These are NOT compiled by tsc (they import from web app internals).
7
+ // Import paths for UI: "@stampui/blocks/src/components/registry-card"
8
+ // or via the web app's tsconfig path alias "@stampui/blocks" -> src/index.ts