@revealui/presentation 0.3.0 → 0.3.3

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 (73) hide show
  1. package/README.md +14 -0
  2. package/dist/Text-mMOCv1lF.js +204 -0
  3. package/dist/Text-mMOCv1lF.js.map +1 -0
  4. package/dist/client.d.ts +3 -2
  5. package/dist/client.d.ts.map +1 -1
  6. package/dist/client.js +92 -266
  7. package/dist/client.js.map +1 -1
  8. package/dist/components/BuiltWithRevealUI.d.ts +6 -3
  9. package/dist/components/BuiltWithRevealUI.d.ts.map +1 -1
  10. package/dist/components/Button.d.ts +6 -3
  11. package/dist/components/Button.d.ts.map +1 -1
  12. package/dist/components/Card.d.ts.map +1 -1
  13. package/dist/components/Input.d.ts.map +1 -1
  14. package/dist/components/accordion.d.ts.map +1 -1
  15. package/dist/components/alert.d.ts.map +1 -1
  16. package/dist/components/avatar.d.ts.map +1 -1
  17. package/dist/components/badge.d.ts.map +1 -1
  18. package/dist/components/breadcrumb.d.ts.map +1 -1
  19. package/dist/components/button-headless.d.ts.map +1 -1
  20. package/dist/components/callout.d.ts.map +1 -1
  21. package/dist/components/checkbox-headless.d.ts.map +1 -1
  22. package/dist/components/combobox.d.ts.map +1 -1
  23. package/dist/components/dialog.d.ts.map +1 -1
  24. package/dist/components/drawer.d.ts.map +1 -1
  25. package/dist/components/dropdown.d.ts.map +1 -1
  26. package/dist/components/empty-state.d.ts.map +1 -1
  27. package/dist/components/fieldset.d.ts.map +1 -1
  28. package/dist/components/form-field.d.ts +23 -0
  29. package/dist/components/form-field.d.ts.map +1 -0
  30. package/dist/components/icon.d.ts +53 -0
  31. package/dist/components/icon.d.ts.map +1 -0
  32. package/dist/components/index.d.ts +1 -0
  33. package/dist/components/index.d.ts.map +1 -1
  34. package/dist/components/input-headless.d.ts.map +1 -1
  35. package/dist/components/kbd.d.ts.map +1 -1
  36. package/dist/components/listbox.d.ts.map +1 -1
  37. package/dist/components/navbar.d.ts.map +1 -1
  38. package/dist/components/radio.d.ts.map +1 -1
  39. package/dist/components/select-headless.d.ts.map +1 -1
  40. package/dist/components/sidebar.d.ts.map +1 -1
  41. package/dist/components/skeleton.d.ts.map +1 -1
  42. package/dist/components/stat.d.ts.map +1 -1
  43. package/dist/components/switch.d.ts.map +1 -1
  44. package/dist/components/table.d.ts.map +1 -1
  45. package/dist/components/tabs.d.ts.map +1 -1
  46. package/dist/components/textarea-headless.d.ts.map +1 -1
  47. package/dist/components/timeline.d.ts.map +1 -1
  48. package/dist/components/toast.d.ts.map +1 -1
  49. package/dist/components/tooltip.d.ts.map +1 -1
  50. package/dist/hooks/index.d.ts +1 -0
  51. package/dist/hooks/index.d.ts.map +1 -1
  52. package/dist/hooks/use-theme.d.ts +26 -0
  53. package/dist/hooks/use-theme.d.ts.map +1 -0
  54. package/dist/index.js +65 -224
  55. package/dist/index.js.map +1 -1
  56. package/dist/server.d.ts +5 -0
  57. package/dist/server.d.ts.map +1 -1
  58. package/dist/server.js +402 -32
  59. package/dist/server.js.map +1 -1
  60. package/dist/skeleton-CHPpiyJj.js +472 -0
  61. package/dist/skeleton-CHPpiyJj.js.map +1 -0
  62. package/dist/tokens.css +265 -0
  63. package/dist/use-theme-QxeZadnD.js +4024 -0
  64. package/dist/use-theme-QxeZadnD.js.map +1 -0
  65. package/dist/utils/cn.d.ts +21 -4
  66. package/dist/utils/cn.d.ts.map +1 -1
  67. package/package.json +13 -15
  68. package/dist/Box-DC3F8eRf.js +0 -430
  69. package/dist/Box-DC3F8eRf.js.map +0 -1
  70. package/dist/Text-jQVi12Hi.js +0 -218
  71. package/dist/Text-jQVi12Hi.js.map +0 -1
  72. package/dist/tooltip-DQYjYWbe.js +0 -5085
  73. package/dist/tooltip-DQYjYWbe.js.map +0 -1
@@ -0,0 +1,472 @@
1
+ import React from "react";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ //#region src/utils/cn.ts
4
+ function cn(...inputs) {
5
+ const classes = [];
6
+ for (const input of inputs.flat(Infinity)) {
7
+ if (!input) continue;
8
+ if (typeof input === "string" || typeof input === "number") {
9
+ classes.push(String(input));
10
+ continue;
11
+ }
12
+ if (typeof input === "object") {
13
+ for (const [key, value] of Object.entries(input)) if (value) classes.push(key);
14
+ }
15
+ }
16
+ return classes.join(" ").trim();
17
+ }
18
+ function cva(base, config) {
19
+ const fn = (props) => {
20
+ const parts = [base];
21
+ for (const key of Object.keys(config.variants)) {
22
+ const propValue = props?.[key];
23
+ const selected = propValue === null ? null : propValue ?? config.defaultVariants?.[key];
24
+ if (selected != null) {
25
+ const value = config.variants[key]?.[selected];
26
+ if (value) parts.push(value);
27
+ }
28
+ }
29
+ if (props?.className) parts.push(props.className);
30
+ return parts.filter(Boolean).join(" ");
31
+ };
32
+ return fn;
33
+ }
34
+ //#endregion
35
+ //#region src/primitives/Slot.tsx
36
+ /**
37
+ * Slot component for polymorphic composition
38
+ * Allows components to merge props with child elements
39
+ */
40
+ function Slot({ children, asChild, ref, ...slotProps }) {
41
+ if (asChild && React.isValidElement(children)) return React.cloneElement(children, {
42
+ ...slotProps,
43
+ ...children.props,
44
+ ref
45
+ });
46
+ return /* @__PURE__ */ jsx("div", {
47
+ ...slotProps,
48
+ ref,
49
+ children
50
+ });
51
+ }
52
+ //#endregion
53
+ //#region src/components/Button.tsx
54
+ var buttonVariants = cva("inline-flex items-center justify-center whitespace-nowrap rounded text-sm font-medium ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 active:scale-[0.97]", {
55
+ defaultVariants: {
56
+ size: "default",
57
+ variant: "default"
58
+ },
59
+ variants: {
60
+ size: {
61
+ clear: "",
62
+ default: "h-10 px-4 py-2",
63
+ icon: "size-10",
64
+ lg: "h-11 rounded px-8",
65
+ sm: "h-9 rounded px-3"
66
+ },
67
+ variant: {
68
+ default: "bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm hover:shadow-md",
69
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-sm hover:shadow-md",
70
+ ghost: "hover:bg-card hover:text-accent-foreground",
71
+ link: "text-primary items-start justify-start underline-offset-4 hover:underline",
72
+ outline: "border border-border bg-background hover:bg-card hover:text-accent-foreground shadow-sm",
73
+ primary: "bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm hover:shadow-md",
74
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80"
75
+ }
76
+ }
77
+ });
78
+ function Button({ asChild = false, className, isLoading, size, variant, ref, children, disabled, ...props }) {
79
+ return /* @__PURE__ */ jsxs(asChild ? Slot : "button", {
80
+ className: cn(buttonVariants({
81
+ className,
82
+ size,
83
+ variant
84
+ })),
85
+ style: {
86
+ transition: "all var(--rvui-duration-normal, 200ms) var(--rvui-ease, cubic-bezier(0.22, 1, 0.36, 1))",
87
+ borderRadius: "var(--rvui-radius-md, 10px)"
88
+ },
89
+ ref,
90
+ disabled: disabled || isLoading,
91
+ "aria-busy": isLoading || void 0,
92
+ ...props,
93
+ children: [isLoading && /* @__PURE__ */ jsxs("svg", {
94
+ className: "mr-2 size-4 animate-spin",
95
+ xmlns: "http://www.w3.org/2000/svg",
96
+ fill: "none",
97
+ viewBox: "0 0 24 24",
98
+ "aria-hidden": "true",
99
+ children: [/* @__PURE__ */ jsx("circle", {
100
+ className: "opacity-25",
101
+ cx: "12",
102
+ cy: "12",
103
+ r: "10",
104
+ stroke: "currentColor",
105
+ strokeWidth: "4"
106
+ }), /* @__PURE__ */ jsx("path", {
107
+ className: "opacity-75",
108
+ fill: "currentColor",
109
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
110
+ })]
111
+ }), children]
112
+ });
113
+ }
114
+ //#endregion
115
+ //#region src/components/breadcrumb.tsx
116
+ function Breadcrumb({ items, separator, className }) {
117
+ const sep = separator ?? /* @__PURE__ */ jsx("svg", {
118
+ "aria-hidden": "true",
119
+ viewBox: "0 0 16 16",
120
+ fill: "none",
121
+ className: "size-3.5 text-zinc-400",
122
+ children: /* @__PURE__ */ jsx("path", {
123
+ d: "M6 4l4 4-4 4",
124
+ stroke: "currentColor",
125
+ strokeWidth: "1.5",
126
+ strokeLinecap: "round",
127
+ strokeLinejoin: "round"
128
+ })
129
+ });
130
+ return /* @__PURE__ */ jsx("nav", {
131
+ "aria-label": "Breadcrumb",
132
+ children: /* @__PURE__ */ jsx("ol", {
133
+ className: cn("flex flex-wrap items-center gap-1.5 text-sm", className),
134
+ children: items.map((item, index) => {
135
+ const isLast = index === items.length - 1;
136
+ return /* @__PURE__ */ jsxs("li", {
137
+ className: "flex items-center gap-1.5",
138
+ children: [isLast || !item.href ? /* @__PURE__ */ jsx("span", {
139
+ "aria-current": isLast ? "page" : void 0,
140
+ className: cn(isLast ? "font-medium text-zinc-950 dark:text-white" : "text-zinc-500 dark:text-zinc-400"),
141
+ children: item.label
142
+ }) : /* @__PURE__ */ jsx("a", {
143
+ href: item.href,
144
+ className: "text-zinc-500 transition-colors hover:text-zinc-950 dark:text-zinc-400 dark:hover:text-white",
145
+ children: item.label
146
+ }), !isLast && sep]
147
+ }, index);
148
+ })
149
+ })
150
+ });
151
+ }
152
+ //#endregion
153
+ //#region src/components/empty-state.tsx
154
+ function EmptyState({ icon, title, description, action, className }) {
155
+ return /* @__PURE__ */ jsxs("div", {
156
+ className: cn("flex flex-col items-center justify-center rounded-xl border border-dashed border-zinc-300 px-6 py-16 text-center dark:border-zinc-700", className),
157
+ children: [
158
+ icon && /* @__PURE__ */ jsx("div", {
159
+ className: "mb-4 flex size-12 items-center justify-center rounded-full bg-zinc-100 text-zinc-500 dark:bg-zinc-800 dark:text-zinc-400",
160
+ children: icon
161
+ }),
162
+ /* @__PURE__ */ jsx("h3", {
163
+ className: "text-sm font-semibold text-zinc-950 dark:text-white",
164
+ children: title
165
+ }),
166
+ description && /* @__PURE__ */ jsx("p", {
167
+ className: "mt-1 max-w-sm text-sm text-zinc-500 dark:text-zinc-400",
168
+ children: description
169
+ }),
170
+ action && /* @__PURE__ */ jsx("div", {
171
+ className: "mt-6",
172
+ children: action
173
+ })
174
+ ]
175
+ });
176
+ }
177
+ //#endregion
178
+ //#region src/components/Pagination.tsx
179
+ var ChevronLeft = ({ className }) => {
180
+ return /* @__PURE__ */ jsxs("svg", {
181
+ xmlns: "http://www.w3.org/2000/svg",
182
+ fill: "none",
183
+ viewBox: "0 0 24 24",
184
+ strokeWidth: 1.5,
185
+ stroke: "currentColor",
186
+ className: cn("size-6", className),
187
+ children: [/* @__PURE__ */ jsx("title", { children: "Previous page" }), /* @__PURE__ */ jsx("path", {
188
+ strokeLinecap: "round",
189
+ strokeLinejoin: "round",
190
+ d: "M15.75 19.5 8.25 12l7.5-7.5"
191
+ })]
192
+ });
193
+ };
194
+ var ChevronRight = ({ className }) => {
195
+ return /* @__PURE__ */ jsxs("svg", {
196
+ xmlns: "http://www.w3.org/2000/svg",
197
+ fill: "none",
198
+ viewBox: "0 0 24 24",
199
+ strokeWidth: 1.5,
200
+ stroke: "currentColor",
201
+ className: cn("size-6", className),
202
+ children: [/* @__PURE__ */ jsx("title", { children: "Next page" }), /* @__PURE__ */ jsx("path", {
203
+ strokeLinecap: "round",
204
+ strokeLinejoin: "round",
205
+ d: "m8.25 4.5 7.5 7.5-7.5 7.5"
206
+ })]
207
+ });
208
+ };
209
+ var MoreHorizontal = ({ className }) => {
210
+ return /* @__PURE__ */ jsxs("svg", {
211
+ xmlns: "http://www.w3.org/2000/svg",
212
+ fill: "none",
213
+ viewBox: "0 0 24 6",
214
+ className: cn("size-6", className),
215
+ children: [
216
+ /* @__PURE__ */ jsx("title", { children: "More pages" }),
217
+ /* @__PURE__ */ jsx("circle", {
218
+ cx: "6",
219
+ cy: "3",
220
+ r: "3",
221
+ fill: "currentColor"
222
+ }),
223
+ /* @__PURE__ */ jsx("circle", {
224
+ cx: "12",
225
+ cy: "3",
226
+ r: "3",
227
+ fill: "currentColor"
228
+ }),
229
+ /* @__PURE__ */ jsx("circle", {
230
+ cx: "18",
231
+ cy: "3",
232
+ r: "3",
233
+ fill: "currentColor"
234
+ })
235
+ ]
236
+ });
237
+ };
238
+ var Pagination = ({ className, ...props }) => /* @__PURE__ */ jsx("nav", {
239
+ "aria-label": "pagination",
240
+ className: cn("mx-auto flex w-full justify-center", className),
241
+ ...props
242
+ });
243
+ function PaginationContent({ className, ref, ...props }) {
244
+ return /* @__PURE__ */ jsx("ul", {
245
+ className: cn("flex flex-row items-center gap-1", className),
246
+ ref,
247
+ ...props
248
+ });
249
+ }
250
+ function PaginationItem({ className, ref, ...props }) {
251
+ return /* @__PURE__ */ jsx("li", {
252
+ className: cn("", className),
253
+ ref,
254
+ ...props
255
+ });
256
+ }
257
+ var PaginationLink = ({ className, isActive, size = "icon", disabled, ...props }) => /* @__PURE__ */ jsx("button", {
258
+ "aria-current": isActive ? "page" : void 0,
259
+ "aria-disabled": disabled ? true : void 0,
260
+ disabled,
261
+ className: cn(buttonVariants({
262
+ size,
263
+ variant: isActive ? "outline" : "ghost"
264
+ }), className),
265
+ ...props
266
+ });
267
+ var PaginationPrevious = ({ className, ...props }) => /* @__PURE__ */ jsxs(PaginationLink, {
268
+ "aria-label": "Go to previous page",
269
+ className: cn("gap-1 pl-2.5", className),
270
+ size: "default",
271
+ ...props,
272
+ children: [/* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" }), /* @__PURE__ */ jsx("span", { children: "Previous" })]
273
+ });
274
+ var PaginationNext = ({ className, ...props }) => /* @__PURE__ */ jsxs(PaginationLink, {
275
+ "aria-label": "Go to next page",
276
+ className: cn("gap-1 pr-2.5", className),
277
+ size: "default",
278
+ ...props,
279
+ children: [/* @__PURE__ */ jsx("span", { children: "Next" }), /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" })]
280
+ });
281
+ var PaginationEllipsis = ({ className, ...props }) => /* @__PURE__ */ jsxs("span", {
282
+ "aria-hidden": true,
283
+ className: cn("flex h-9 w-9 items-center justify-center", className),
284
+ ...props,
285
+ children: [/* @__PURE__ */ jsx(MoreHorizontal, { className: "size-4" }), /* @__PURE__ */ jsx("span", {
286
+ className: "sr-only",
287
+ children: "More pages"
288
+ })]
289
+ });
290
+ //#endregion
291
+ //#region src/components/pricing-table.tsx
292
+ function CheckIcon() {
293
+ return /* @__PURE__ */ jsx("svg", {
294
+ className: "h-4 w-4 shrink-0 text-blue-600 mt-0.5",
295
+ fill: "currentColor",
296
+ viewBox: "0 0 20 20",
297
+ "aria-hidden": "true",
298
+ children: /* @__PURE__ */ jsx("path", {
299
+ fillRule: "evenodd",
300
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z",
301
+ clipRule: "evenodd"
302
+ })
303
+ });
304
+ }
305
+ function PricingTable({ tiers, currentTier, compact = false, onSelectTier, className }) {
306
+ if (compact) return /* @__PURE__ */ jsx("div", {
307
+ className: cn("flex flex-col gap-4 sm:flex-row", className),
308
+ children: tiers.map((tier) => /* @__PURE__ */ jsx(PricingCardCompact, {
309
+ tier,
310
+ isCurrent: tier.id === currentTier,
311
+ onSelect: onSelectTier
312
+ }, tier.id))
313
+ });
314
+ return /* @__PURE__ */ jsx("div", {
315
+ className: cn("grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4", tiers.length === 3 && "lg:grid-cols-3", tiers.length === 2 && "lg:grid-cols-2 max-w-3xl mx-auto", className),
316
+ children: tiers.map((tier) => /* @__PURE__ */ jsx(PricingCardFull, {
317
+ tier,
318
+ isCurrent: tier.id === currentTier,
319
+ onSelect: onSelectTier
320
+ }, tier.id))
321
+ });
322
+ }
323
+ function PricingCardFull({ tier, isCurrent, onSelect }) {
324
+ const isHighlighted = tier.highlighted && !isCurrent;
325
+ return /* @__PURE__ */ jsxs("div", {
326
+ className: cn("relative rounded-2xl bg-white p-8 shadow-lg dark:bg-zinc-900", isHighlighted ? "ring-2 ring-blue-600" : isCurrent ? "ring-2 ring-emerald-500" : "ring-1 ring-zinc-200 dark:ring-zinc-800"),
327
+ children: [
328
+ isHighlighted && /* @__PURE__ */ jsx("div", {
329
+ className: "absolute -top-4 left-0 right-0 mx-auto w-32 rounded-full bg-gradient-to-r from-blue-600 to-indigo-600 px-3 py-1.5 text-sm font-semibold text-white text-center shadow-lg",
330
+ children: "Most Popular"
331
+ }),
332
+ isCurrent && /* @__PURE__ */ jsx("div", {
333
+ className: "absolute -top-4 left-0 right-0 mx-auto w-32 rounded-full bg-emerald-600 px-3 py-1.5 text-sm font-semibold text-white text-center shadow-lg",
334
+ children: "Current Plan"
335
+ }),
336
+ /* @__PURE__ */ jsxs("div", {
337
+ className: "mb-8",
338
+ children: [
339
+ /* @__PURE__ */ jsx("h3", {
340
+ className: "text-xl font-bold tracking-tight text-zinc-900 dark:text-white",
341
+ children: tier.name
342
+ }),
343
+ /* @__PURE__ */ jsx("p", {
344
+ className: "mt-2 text-sm text-zinc-600 dark:text-zinc-400",
345
+ children: tier.description
346
+ }),
347
+ /* @__PURE__ */ jsxs("p", {
348
+ className: "mt-6 flex items-baseline gap-x-1",
349
+ children: [/* @__PURE__ */ jsx("span", {
350
+ className: "text-4xl font-bold tracking-tight text-zinc-900 dark:text-white",
351
+ children: tier.price ?? "—"
352
+ }), tier.period && /* @__PURE__ */ jsx("span", {
353
+ className: "text-sm text-zinc-600 dark:text-zinc-400",
354
+ children: tier.period
355
+ })]
356
+ })
357
+ ]
358
+ }),
359
+ /* @__PURE__ */ jsx("ul", {
360
+ className: "mb-8 space-y-3",
361
+ children: tier.features.map((feature) => /* @__PURE__ */ jsxs("li", {
362
+ className: "flex items-start gap-x-3",
363
+ children: [/* @__PURE__ */ jsx(CheckIcon, {}), /* @__PURE__ */ jsx("span", {
364
+ className: "text-sm text-zinc-600 dark:text-zinc-400",
365
+ children: feature
366
+ })]
367
+ }, feature))
368
+ }),
369
+ onSelect ? /* @__PURE__ */ jsx("button", {
370
+ type: "button",
371
+ onClick: () => onSelect(tier.id),
372
+ disabled: isCurrent,
373
+ className: cn("block w-full rounded-md px-6 py-3 text-center text-sm font-semibold transition-colors", isCurrent ? "cursor-default bg-emerald-50 text-emerald-700 dark:bg-emerald-900/20 dark:text-emerald-400" : isHighlighted ? "bg-blue-600 text-white hover:bg-blue-500 shadow-sm" : "bg-zinc-100 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-100 dark:hover:bg-zinc-700"),
374
+ children: isCurrent ? "Current Plan" : tier.cta
375
+ }) : /* @__PURE__ */ jsx("a", {
376
+ href: tier.ctaHref,
377
+ className: cn("block w-full rounded-md px-6 py-3 text-center text-sm font-semibold transition-colors", isHighlighted ? "bg-blue-600 text-white hover:bg-blue-500 shadow-sm" : "bg-zinc-100 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-100 dark:hover:bg-zinc-700"),
378
+ children: tier.cta
379
+ })
380
+ ]
381
+ });
382
+ }
383
+ function PricingCardCompact({ tier, isCurrent, onSelect }) {
384
+ return /* @__PURE__ */ jsxs("div", {
385
+ className: cn("flex-1 rounded-xl p-5 shadow-sm dark:bg-zinc-900", isCurrent ? "ring-2 ring-emerald-500 bg-emerald-50/50 dark:bg-emerald-900/10" : tier.highlighted ? "ring-2 ring-blue-600 bg-blue-50/50 dark:bg-blue-900/10" : "ring-1 ring-zinc-200 bg-white dark:ring-zinc-800"),
386
+ children: [
387
+ /* @__PURE__ */ jsxs("div", {
388
+ className: "flex items-baseline justify-between gap-2",
389
+ children: [/* @__PURE__ */ jsx("h4", {
390
+ className: "text-sm font-bold text-zinc-900 dark:text-white",
391
+ children: tier.name
392
+ }), isCurrent && /* @__PURE__ */ jsx("span", {
393
+ className: "rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-medium text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400",
394
+ children: "Current"
395
+ })]
396
+ }),
397
+ /* @__PURE__ */ jsxs("p", {
398
+ className: "mt-1 flex items-baseline gap-x-1",
399
+ children: [/* @__PURE__ */ jsx("span", {
400
+ className: "text-2xl font-bold text-zinc-900 dark:text-white",
401
+ children: tier.price ?? "—"
402
+ }), tier.period && /* @__PURE__ */ jsx("span", {
403
+ className: "text-xs text-zinc-500 dark:text-zinc-400",
404
+ children: tier.period
405
+ })]
406
+ }),
407
+ /* @__PURE__ */ jsx("p", {
408
+ className: "mt-1 text-xs text-zinc-500 dark:text-zinc-400 line-clamp-2",
409
+ children: tier.description
410
+ }),
411
+ onSelect ? /* @__PURE__ */ jsx("button", {
412
+ type: "button",
413
+ onClick: () => onSelect(tier.id),
414
+ disabled: isCurrent,
415
+ className: cn("mt-3 block w-full rounded-md px-3 py-2 text-center text-xs font-semibold transition-colors", isCurrent ? "cursor-default bg-emerald-50 text-emerald-700 dark:bg-emerald-900/20 dark:text-emerald-400" : tier.highlighted ? "bg-blue-600 text-white hover:bg-blue-500" : "bg-zinc-100 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-100 dark:hover:bg-zinc-700"),
416
+ children: isCurrent ? "Current" : tier.cta
417
+ }) : /* @__PURE__ */ jsx("a", {
418
+ href: tier.ctaHref,
419
+ className: cn("mt-3 block w-full rounded-md px-3 py-2 text-center text-xs font-semibold transition-colors", tier.highlighted ? "bg-blue-600 text-white hover:bg-blue-500" : "bg-zinc-100 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-100 dark:hover:bg-zinc-700"),
420
+ children: tier.cta
421
+ })
422
+ ]
423
+ });
424
+ }
425
+ //#endregion
426
+ //#region src/primitives/Box.tsx
427
+ /**
428
+ * Box primitive - Basic container component
429
+ */
430
+ function Box({ as: Component = "div", className, ref, ...props }) {
431
+ return /* @__PURE__ */ jsx(Component, {
432
+ ref,
433
+ className: cn(className),
434
+ ...props
435
+ });
436
+ }
437
+ //#endregion
438
+ //#region src/components/skeleton.tsx
439
+ function Skeleton({ className, ...props }) {
440
+ return /* @__PURE__ */ jsx("div", {
441
+ "aria-hidden": "true",
442
+ ...props,
443
+ className: cn("animate-pulse rounded-md bg-zinc-200 dark:bg-zinc-700", className)
444
+ });
445
+ }
446
+ function SkeletonText({ lines = 3, className }) {
447
+ return /* @__PURE__ */ jsx("div", {
448
+ className: cn("space-y-2", className),
449
+ children: Array.from({ length: lines }).map((_, i) => {
450
+ return /* @__PURE__ */ jsx(Skeleton, { className: cn("h-4", i === lines - 1 && lines > 1 ? "w-4/5" : "w-full") }, i);
451
+ })
452
+ });
453
+ }
454
+ function SkeletonCard({ className }) {
455
+ return /* @__PURE__ */ jsxs("div", {
456
+ className: cn("rounded-xl border border-zinc-200 p-4 dark:border-zinc-700", className),
457
+ children: [/* @__PURE__ */ jsxs("div", {
458
+ className: "flex items-center gap-3",
459
+ children: [/* @__PURE__ */ jsx(Skeleton, { className: "size-10 rounded-full" }), /* @__PURE__ */ jsxs("div", {
460
+ className: "flex-1 space-y-2",
461
+ children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-1/3" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-1/2" })]
462
+ })]
463
+ }), /* @__PURE__ */ jsx(SkeletonText, {
464
+ lines: 3,
465
+ className: "mt-4"
466
+ })]
467
+ });
468
+ }
469
+ //#endregion
470
+ export { Slot as _, PricingTable as a, PaginationEllipsis as c, PaginationNext as d, PaginationPrevious as f, buttonVariants as g, Button as h, Box as i, PaginationItem as l, Breadcrumb as m, SkeletonCard as n, Pagination as o, EmptyState as p, SkeletonText as r, PaginationContent as s, Skeleton as t, PaginationLink as u, cn as v, cva as y };
471
+
472
+ //# sourceMappingURL=skeleton-CHPpiyJj.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skeleton-CHPpiyJj.js","names":[],"sources":["../src/utils/cn.ts","../src/primitives/Slot.tsx","../src/components/Button.tsx","../src/components/breadcrumb.tsx","../src/components/empty-state.tsx","../src/components/Pagination.tsx","../src/components/pricing-table.tsx","../src/primitives/Box.tsx","../src/components/skeleton.tsx"],"sourcesContent":["/**\n * Utility function for conditionally joining classNames together.\n * Drop-in replacement for clsx — supports strings, numbers, booleans,\n * objects, and arbitrarily nested arrays.\n */\ntype ClassValue =\n | string\n | number\n | boolean\n | undefined\n | null\n | { [key: string]: boolean }\n | ClassValue[];\n\nexport function cn(...inputs: ClassValue[]): string {\n const classes: string[] = [];\n\n for (const input of (inputs as readonly unknown[]).flat(Infinity) as Exclude<\n ClassValue,\n ClassValue[]\n >[]) {\n if (!input) continue;\n\n if (typeof input === 'string' || typeof input === 'number') {\n classes.push(String(input));\n continue;\n }\n\n if (typeof input === 'object') {\n for (const [key, value] of Object.entries(input)) {\n if (value) {\n classes.push(key);\n }\n }\n }\n }\n\n return classes.join(' ').trim();\n}\n\n/**\n * Lightweight class-variance-authority replacement.\n * Supports base classes, variants, and defaultVariants.\n */\ntype VariantValues = Record<string, string>;\ntype VariantConfig = Record<string, VariantValues>;\n\ninterface CvaConfig<V extends VariantConfig> {\n variants: V;\n defaultVariants?: { [K in keyof V]?: keyof V[K] };\n}\n\ntype VariantProps<T> = T extends (props?: infer P) => string ? P : never;\n\nfunction cva<V extends VariantConfig>(base: string, config: CvaConfig<V>) {\n type Props = { [K in keyof V]?: keyof V[K] | null } & { className?: string };\n\n const fn = (props?: Props): string => {\n const parts: string[] = [base];\n\n for (const key of Object.keys(config.variants)) {\n const propValue = props?.[key as keyof Props];\n const selected = propValue === null ? null : (propValue ?? config.defaultVariants?.[key]);\n if (selected != null) {\n const value = config.variants[key]?.[selected as string];\n if (value) parts.push(value);\n }\n }\n\n if (props?.className) parts.push(props.className);\n return parts.filter(Boolean).join(' ');\n };\n\n return fn;\n}\n\nexport { cva, type VariantProps };\n","import React, { type Ref } from 'react';\n\nexport interface SlotProps extends React.HTMLAttributes<HTMLElement> {\n children?: React.ReactNode;\n asChild?: boolean;\n ref?: React.Ref<HTMLElement>;\n}\n\n/**\n * Slot component for polymorphic composition\n * Allows components to merge props with child elements\n */\nfunction Slot({ children, asChild, ref, ...slotProps }: SlotProps) {\n if (asChild && React.isValidElement(children)) {\n return React.cloneElement(children, {\n ...slotProps,\n ...(children.props as Record<string, unknown>),\n ref,\n } as unknown as React.HTMLAttributes<HTMLElement>);\n }\n\n return (\n <div {...slotProps} ref={ref as Ref<HTMLDivElement>}>\n {children}\n </div>\n );\n}\n\nexport { Slot };\n","import type React from 'react';\nimport { Slot } from '../primitives/Slot.js';\nimport { cn, cva, type VariantProps } from '../utils/cn.js';\n\nconst buttonVariants = cva(\n 'inline-flex items-center justify-center whitespace-nowrap rounded text-sm font-medium ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 active:scale-[0.97]',\n {\n defaultVariants: {\n size: 'default',\n variant: 'default',\n },\n variants: {\n size: {\n clear: '',\n default: 'h-10 px-4 py-2',\n icon: 'size-10',\n lg: 'h-11 rounded px-8',\n sm: 'h-9 rounded px-3',\n },\n variant: {\n default: 'bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm hover:shadow-md',\n destructive:\n 'bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-sm hover:shadow-md',\n ghost: 'hover:bg-card hover:text-accent-foreground',\n link: 'text-primary items-start justify-start underline-offset-4 hover:underline',\n outline:\n 'border border-border bg-background hover:bg-card hover:text-accent-foreground shadow-sm',\n primary: 'bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm hover:shadow-md',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n },\n },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n isLoading?: boolean;\n ref?: React.Ref<HTMLButtonElement>;\n}\n\nfunction Button({\n asChild = false,\n className,\n isLoading,\n size,\n variant,\n ref,\n children,\n disabled,\n ...props\n}: ButtonProps) {\n const Comp = asChild ? Slot : 'button';\n return (\n <Comp\n className={cn(buttonVariants({ className, size, variant }))}\n style={{\n transition:\n 'all var(--rvui-duration-normal, 200ms) var(--rvui-ease, cubic-bezier(0.22, 1, 0.36, 1))',\n borderRadius: 'var(--rvui-radius-md, 10px)',\n }}\n ref={ref}\n disabled={disabled || isLoading}\n aria-busy={isLoading || undefined}\n {...props}\n >\n {isLoading && (\n <svg\n className=\"mr-2 size-4 animate-spin\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n )}\n {children}\n </Comp>\n );\n}\n\nexport { Button, buttonVariants };\n","import type React from 'react';\nimport { cn } from '../utils/cn.js';\n\nexport type BreadcrumbItem = {\n label: React.ReactNode;\n href?: string;\n};\n\nexport function Breadcrumb({\n items,\n separator,\n className,\n}: {\n items: BreadcrumbItem[];\n separator?: React.ReactNode;\n className?: string;\n}) {\n const sep = separator ?? (\n <svg aria-hidden=\"true\" viewBox=\"0 0 16 16\" fill=\"none\" className=\"size-3.5 text-zinc-400\">\n <path\n d=\"M6 4l4 4-4 4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n\n return (\n <nav aria-label=\"Breadcrumb\">\n <ol className={cn('flex flex-wrap items-center gap-1.5 text-sm', className)}>\n {items.map((item, index) => {\n const isLast = index === items.length - 1;\n return (\n // biome-ignore lint/suspicious/noArrayIndexKey: breadcrumb items are positionally ordered with no stable ID\n <li key={index} className=\"flex items-center gap-1.5\">\n {isLast || !item.href ? (\n <span\n aria-current={isLast ? 'page' : undefined}\n className={cn(\n isLast\n ? 'font-medium text-zinc-950 dark:text-white'\n : 'text-zinc-500 dark:text-zinc-400',\n )}\n >\n {item.label}\n </span>\n ) : (\n <a\n href={item.href}\n className=\"text-zinc-500 transition-colors hover:text-zinc-950 dark:text-zinc-400 dark:hover:text-white\"\n >\n {item.label}\n </a>\n )}\n {!isLast && sep}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n}\n","import type React from 'react';\nimport { cn } from '../utils/cn.js';\n\nexport function EmptyState({\n icon,\n title,\n description,\n action,\n className,\n}: {\n icon?: React.ReactNode;\n title: string;\n description?: string;\n action?: React.ReactNode;\n className?: string;\n}) {\n return (\n <div\n className={cn(\n 'flex flex-col items-center justify-center rounded-xl border border-dashed border-zinc-300 px-6 py-16 text-center dark:border-zinc-700',\n className,\n )}\n >\n {icon && (\n <div className=\"mb-4 flex size-12 items-center justify-center rounded-full bg-zinc-100 text-zinc-500 dark:bg-zinc-800 dark:text-zinc-400\">\n {icon}\n </div>\n )}\n <h3 className=\"text-sm font-semibold text-zinc-950 dark:text-white\">{title}</h3>\n {description && (\n <p className=\"mt-1 max-w-sm text-sm text-zinc-500 dark:text-zinc-400\">{description}</p>\n )}\n {action && <div className=\"mt-6\">{action}</div>}\n </div>\n );\n}\n","import type * as React from 'react';\nimport { cn } from '../utils/cn.js';\nimport type { ButtonProps } from './Button.js';\nimport { buttonVariants } from './Button.js';\n\nconst ChevronLeft = ({ className }: { className?: string }) => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n className={cn('size-6', className)}\n >\n <title>Previous page</title>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\n </svg>\n );\n};\n\nconst ChevronRight = ({ className }: { className?: string }) => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n className={cn('size-6', className)}\n >\n <title>Next page</title>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\n </svg>\n );\n};\n\nconst MoreHorizontal = ({ className }: { className?: string }) => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 6\"\n className={cn('size-6', className)}\n >\n <title>More pages</title>\n <circle cx=\"6\" cy=\"3\" r=\"3\" fill=\"currentColor\" />\n <circle cx=\"12\" cy=\"3\" r=\"3\" fill=\"currentColor\" />\n <circle cx=\"18\" cy=\"3\" r=\"3\" fill=\"currentColor\" />\n </svg>\n );\n};\n\nexport type PaginationProps = React.ComponentProps<'nav'>;\n\nconst Pagination = ({ className, ...props }: PaginationProps) => (\n <nav\n aria-label=\"pagination\"\n className={cn('mx-auto flex w-full justify-center', className)}\n {...props}\n />\n);\n\nfunction PaginationContent({\n className,\n ref,\n ...props\n}: React.ComponentProps<'ul'> & { ref?: React.Ref<HTMLUListElement> }) {\n return <ul className={cn('flex flex-row items-center gap-1', className)} ref={ref} {...props} />;\n}\n\nfunction PaginationItem({\n className,\n ref,\n ...props\n}: React.ComponentProps<'li'> & { ref?: React.Ref<HTMLLIElement> }) {\n return <li className={cn('', className)} ref={ref} {...props} />;\n}\n\nexport interface PaginationLinkProps\n extends Pick<ButtonProps, 'size'>,\n React.ComponentProps<'button'> {\n isActive?: boolean;\n}\n\nconst PaginationLink = ({\n className,\n isActive,\n size = 'icon',\n disabled,\n ...props\n}: PaginationLinkProps) => (\n <button\n aria-current={isActive ? 'page' : undefined}\n aria-disabled={disabled ? true : undefined}\n disabled={disabled}\n className={cn(\n buttonVariants({\n size,\n variant: isActive ? 'outline' : 'ghost',\n }),\n className,\n )}\n {...props}\n />\n);\n\nexport type PaginationPreviousProps = React.ComponentProps<typeof PaginationLink>;\n\nconst PaginationPrevious = ({ className, ...props }: PaginationPreviousProps) => (\n <PaginationLink\n aria-label=\"Go to previous page\"\n className={cn('gap-1 pl-2.5', className)}\n size=\"default\"\n {...props}\n >\n <ChevronLeft className=\"size-4\" />\n <span>Previous</span>\n </PaginationLink>\n);\n\nexport type PaginationNextProps = React.ComponentProps<typeof PaginationLink>;\n\nconst PaginationNext = ({ className, ...props }: PaginationNextProps) => (\n <PaginationLink\n aria-label=\"Go to next page\"\n className={cn('gap-1 pr-2.5', className)}\n size=\"default\"\n {...props}\n >\n <span>Next</span>\n <ChevronRight className=\"size-4\" />\n </PaginationLink>\n);\n\nexport type PaginationEllipsisProps = React.ComponentProps<'span'>;\n\nconst PaginationEllipsis = ({ className, ...props }: PaginationEllipsisProps) => (\n <span\n aria-hidden\n className={cn('flex h-9 w-9 items-center justify-center', className)}\n {...props}\n >\n <MoreHorizontal className=\"size-4\" />\n <span className=\"sr-only\">More pages</span>\n </span>\n);\n\nexport {\n Pagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n PaginationNext,\n PaginationPrevious,\n};\n","import { cn } from '../utils/cn.js';\n\n// =============================================================================\n// Types (mirrors @revealui/contracts/pricing — no import to avoid coupling)\n// =============================================================================\n\nexport interface PricingTier {\n id: string;\n name: string;\n price?: string;\n period?: string;\n description: string;\n features: string[];\n cta: string;\n ctaHref: string;\n highlighted: boolean;\n}\n\nexport interface PricingTableProps {\n tiers: PricingTier[];\n /** Highlights the active plan tier */\n currentTier?: string;\n /** Compact (horizontal row) vs full (grid) layout */\n compact?: boolean;\n /** Callback when a tier is selected */\n onSelectTier?: (id: string) => void;\n className?: string;\n}\n\n// =============================================================================\n// Check Icon (inline SVG — no external deps)\n// =============================================================================\n\nfunction CheckIcon() {\n return (\n <svg\n className=\"h-4 w-4 shrink-0 text-blue-600 mt-0.5\"\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\"\n clipRule=\"evenodd\"\n />\n </svg>\n );\n}\n\n// =============================================================================\n// PricingTable\n// =============================================================================\n\nexport function PricingTable({\n tiers,\n currentTier,\n compact = false,\n onSelectTier,\n className,\n}: PricingTableProps) {\n if (compact) {\n return (\n <div className={cn('flex flex-col gap-4 sm:flex-row', className)}>\n {tiers.map((tier) => (\n <PricingCardCompact\n key={tier.id}\n tier={tier}\n isCurrent={tier.id === currentTier}\n onSelect={onSelectTier}\n />\n ))}\n </div>\n );\n }\n\n return (\n <div\n className={cn(\n 'grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4',\n tiers.length === 3 && 'lg:grid-cols-3',\n tiers.length === 2 && 'lg:grid-cols-2 max-w-3xl mx-auto',\n className,\n )}\n >\n {tiers.map((tier) => (\n <PricingCardFull\n key={tier.id}\n tier={tier}\n isCurrent={tier.id === currentTier}\n onSelect={onSelectTier}\n />\n ))}\n </div>\n );\n}\n\n// =============================================================================\n// Full Card (marketing grid layout)\n// =============================================================================\n\nfunction PricingCardFull({\n tier,\n isCurrent,\n onSelect,\n}: {\n tier: PricingTier;\n isCurrent: boolean;\n onSelect?: (id: string) => void;\n}) {\n const isHighlighted = tier.highlighted && !isCurrent;\n\n return (\n <div\n className={cn(\n 'relative rounded-2xl bg-white p-8 shadow-lg dark:bg-zinc-900',\n isHighlighted\n ? 'ring-2 ring-blue-600'\n : isCurrent\n ? 'ring-2 ring-emerald-500'\n : 'ring-1 ring-zinc-200 dark:ring-zinc-800',\n )}\n >\n {isHighlighted && (\n <div className=\"absolute -top-4 left-0 right-0 mx-auto w-32 rounded-full bg-gradient-to-r from-blue-600 to-indigo-600 px-3 py-1.5 text-sm font-semibold text-white text-center shadow-lg\">\n Most Popular\n </div>\n )}\n {isCurrent && (\n <div className=\"absolute -top-4 left-0 right-0 mx-auto w-32 rounded-full bg-emerald-600 px-3 py-1.5 text-sm font-semibold text-white text-center shadow-lg\">\n Current Plan\n </div>\n )}\n\n <div className=\"mb-8\">\n <h3 className=\"text-xl font-bold tracking-tight text-zinc-900 dark:text-white\">\n {tier.name}\n </h3>\n <p className=\"mt-2 text-sm text-zinc-600 dark:text-zinc-400\">{tier.description}</p>\n <p className=\"mt-6 flex items-baseline gap-x-1\">\n <span className=\"text-4xl font-bold tracking-tight text-zinc-900 dark:text-white\">\n {tier.price ?? '—'}\n </span>\n {tier.period && (\n <span className=\"text-sm text-zinc-600 dark:text-zinc-400\">{tier.period}</span>\n )}\n </p>\n </div>\n\n <ul className=\"mb-8 space-y-3\">\n {tier.features.map((feature) => (\n <li key={feature} className=\"flex items-start gap-x-3\">\n <CheckIcon />\n <span className=\"text-sm text-zinc-600 dark:text-zinc-400\">{feature}</span>\n </li>\n ))}\n </ul>\n\n {onSelect ? (\n <button\n type=\"button\"\n onClick={() => onSelect(tier.id)}\n disabled={isCurrent}\n className={cn(\n 'block w-full rounded-md px-6 py-3 text-center text-sm font-semibold transition-colors',\n isCurrent\n ? 'cursor-default bg-emerald-50 text-emerald-700 dark:bg-emerald-900/20 dark:text-emerald-400'\n : isHighlighted\n ? 'bg-blue-600 text-white hover:bg-blue-500 shadow-sm'\n : 'bg-zinc-100 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-100 dark:hover:bg-zinc-700',\n )}\n >\n {isCurrent ? 'Current Plan' : tier.cta}\n </button>\n ) : (\n <a\n href={tier.ctaHref}\n className={cn(\n 'block w-full rounded-md px-6 py-3 text-center text-sm font-semibold transition-colors',\n isHighlighted\n ? 'bg-blue-600 text-white hover:bg-blue-500 shadow-sm'\n : 'bg-zinc-100 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-100 dark:hover:bg-zinc-700',\n )}\n >\n {tier.cta}\n </a>\n )}\n </div>\n );\n}\n\n// =============================================================================\n// Compact Card (embeddable in dialogs/prompts)\n// =============================================================================\n\nfunction PricingCardCompact({\n tier,\n isCurrent,\n onSelect,\n}: {\n tier: PricingTier;\n isCurrent: boolean;\n onSelect?: (id: string) => void;\n}) {\n return (\n <div\n className={cn(\n 'flex-1 rounded-xl p-5 shadow-sm dark:bg-zinc-900',\n isCurrent\n ? 'ring-2 ring-emerald-500 bg-emerald-50/50 dark:bg-emerald-900/10'\n : tier.highlighted\n ? 'ring-2 ring-blue-600 bg-blue-50/50 dark:bg-blue-900/10'\n : 'ring-1 ring-zinc-200 bg-white dark:ring-zinc-800',\n )}\n >\n <div className=\"flex items-baseline justify-between gap-2\">\n <h4 className=\"text-sm font-bold text-zinc-900 dark:text-white\">{tier.name}</h4>\n {isCurrent && (\n <span className=\"rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-medium text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400\">\n Current\n </span>\n )}\n </div>\n <p className=\"mt-1 flex items-baseline gap-x-1\">\n <span className=\"text-2xl font-bold text-zinc-900 dark:text-white\">\n {tier.price ?? '—'}\n </span>\n {tier.period && (\n <span className=\"text-xs text-zinc-500 dark:text-zinc-400\">{tier.period}</span>\n )}\n </p>\n <p className=\"mt-1 text-xs text-zinc-500 dark:text-zinc-400 line-clamp-2\">\n {tier.description}\n </p>\n\n {onSelect ? (\n <button\n type=\"button\"\n onClick={() => onSelect(tier.id)}\n disabled={isCurrent}\n className={cn(\n 'mt-3 block w-full rounded-md px-3 py-2 text-center text-xs font-semibold transition-colors',\n isCurrent\n ? 'cursor-default bg-emerald-50 text-emerald-700 dark:bg-emerald-900/20 dark:text-emerald-400'\n : tier.highlighted\n ? 'bg-blue-600 text-white hover:bg-blue-500'\n : 'bg-zinc-100 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-100 dark:hover:bg-zinc-700',\n )}\n >\n {isCurrent ? 'Current' : tier.cta}\n </button>\n ) : (\n <a\n href={tier.ctaHref}\n className={cn(\n 'mt-3 block w-full rounded-md px-3 py-2 text-center text-xs font-semibold transition-colors',\n tier.highlighted\n ? 'bg-blue-600 text-white hover:bg-blue-500'\n : 'bg-zinc-100 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-100 dark:hover:bg-zinc-700',\n )}\n >\n {tier.cta}\n </a>\n )}\n </div>\n );\n}\n","import type React from 'react';\nimport { cn } from '../utils/cn.js';\n\nexport interface BoxProps extends React.HTMLAttributes<HTMLDivElement> {\n as?: 'div' | 'span' | 'section' | 'article' | 'header' | 'footer' | 'main' | 'aside' | 'nav';\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/**\n * Box primitive - Basic container component\n */\nfunction Box({ as: Component = 'div', className, ref, ...props }: BoxProps) {\n return <Component ref={ref} className={cn(className)} {...props} />;\n}\n\nexport { Box };\n","import type React from 'react';\nimport { cn } from '../utils/cn.js';\n\nexport function Skeleton({ className, ...props }: React.ComponentPropsWithoutRef<'div'>) {\n return (\n <div\n aria-hidden=\"true\"\n {...props}\n className={cn('animate-pulse rounded-md bg-zinc-200 dark:bg-zinc-700', className)}\n />\n );\n}\n\nexport function SkeletonText({ lines = 3, className }: { lines?: number; className?: string }) {\n return (\n <div className={cn('space-y-2', className)}>\n {Array.from({ length: lines }).map((_, i) => {\n return (\n <Skeleton\n // biome-ignore lint/suspicious/noArrayIndexKey: skeleton lines are generated placeholders with no stable ID\n key={i}\n className={cn('h-4', i === lines - 1 && lines > 1 ? 'w-4/5' : 'w-full')}\n />\n );\n })}\n </div>\n );\n}\n\nexport function SkeletonCard({ className }: { className?: string }) {\n return (\n <div className={cn('rounded-xl border border-zinc-200 p-4 dark:border-zinc-700', className)}>\n <div className=\"flex items-center gap-3\">\n <Skeleton className=\"size-10 rounded-full\" />\n <div className=\"flex-1 space-y-2\">\n <Skeleton className=\"h-4 w-1/3\" />\n <Skeleton className=\"h-3 w-1/2\" />\n </div>\n </div>\n <SkeletonText lines={3} className=\"mt-4\" />\n </div>\n );\n}\n"],"mappings":"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"}