@omnibase/shadcn 0.1.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.
package/dist/index.cjs ADDED
@@ -0,0 +1,787 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ CustomFlowForm: () => CustomFlowForm,
34
+ PricingTable: () => PricingTable,
35
+ SwitchActiveTenant: () => SwitchActiveTenant
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+
39
+ // src/components/ui/card.tsx
40
+ var React = require("react");
41
+
42
+ // src/lib/utils.ts
43
+ var import_clsx = require("clsx");
44
+ var import_tailwind_merge = require("tailwind-merge");
45
+ function cn(...inputs) {
46
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
47
+ }
48
+
49
+ // src/components/ui/card.tsx
50
+ var import_jsx_runtime = require("react/jsx-runtime");
51
+ function Card({ className, ...props }) {
52
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
53
+ "div",
54
+ {
55
+ "data-slot": "card",
56
+ className: cn(
57
+ "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
58
+ className
59
+ ),
60
+ ...props
61
+ }
62
+ );
63
+ }
64
+ function CardHeader({ className, ...props }) {
65
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
66
+ "div",
67
+ {
68
+ "data-slot": "card-header",
69
+ className: cn(
70
+ "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
71
+ className
72
+ ),
73
+ ...props
74
+ }
75
+ );
76
+ }
77
+ function CardTitle({ className, ...props }) {
78
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
79
+ "div",
80
+ {
81
+ "data-slot": "card-title",
82
+ className: cn("leading-none font-semibold", className),
83
+ ...props
84
+ }
85
+ );
86
+ }
87
+ function CardDescription({ className, ...props }) {
88
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
89
+ "div",
90
+ {
91
+ "data-slot": "card-description",
92
+ className: cn("text-muted-foreground text-sm", className),
93
+ ...props
94
+ }
95
+ );
96
+ }
97
+ function CardContent({ className, ...props }) {
98
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
99
+ "div",
100
+ {
101
+ "data-slot": "card-content",
102
+ className: cn("px-6", className),
103
+ ...props
104
+ }
105
+ );
106
+ }
107
+ function CardFooter({ className, ...props }) {
108
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
109
+ "div",
110
+ {
111
+ "data-slot": "card-footer",
112
+ className: cn("flex items-center px-6 [.border-t]:pt-6", className),
113
+ ...props
114
+ }
115
+ );
116
+ }
117
+
118
+ // src/components/ui/button.tsx
119
+ var React2 = require("react");
120
+ var import_react_slot = require("@radix-ui/react-slot");
121
+ var import_class_variance_authority = require("class-variance-authority");
122
+ var import_jsx_runtime2 = require("react/jsx-runtime");
123
+ var buttonVariants = (0, import_class_variance_authority.cva)(
124
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
125
+ {
126
+ variants: {
127
+ variant: {
128
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
129
+ destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
130
+ outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
131
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
132
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
133
+ link: "text-primary underline-offset-4 hover:underline"
134
+ },
135
+ size: {
136
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
137
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
138
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
139
+ icon: "size-9"
140
+ }
141
+ },
142
+ defaultVariants: {
143
+ variant: "default",
144
+ size: "default"
145
+ }
146
+ }
147
+ );
148
+ function Button({
149
+ className,
150
+ variant,
151
+ size,
152
+ asChild = false,
153
+ ...props
154
+ }) {
155
+ const Comp = asChild ? import_react_slot.Slot : "button";
156
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
157
+ Comp,
158
+ {
159
+ "data-slot": "button",
160
+ className: cn(buttonVariants({ variant, size, className })),
161
+ ...props
162
+ }
163
+ );
164
+ }
165
+
166
+ // src/components/ui/input.tsx
167
+ var React3 = require("react");
168
+ var import_jsx_runtime3 = require("react/jsx-runtime");
169
+ function Input({ className, type, ...props }) {
170
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
171
+ "input",
172
+ {
173
+ type,
174
+ "data-slot": "input",
175
+ className: cn(
176
+ "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
177
+ "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
178
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
179
+ className
180
+ ),
181
+ ...props
182
+ }
183
+ );
184
+ }
185
+
186
+ // src/components/ui/label.tsx
187
+ var React4 = require("react");
188
+ var LabelPrimitive = __toESM(require("@radix-ui/react-label"), 1);
189
+ var import_jsx_runtime4 = require("react/jsx-runtime");
190
+ function Label({
191
+ className,
192
+ ...props
193
+ }) {
194
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
195
+ LabelPrimitive.Root,
196
+ {
197
+ "data-slot": "label",
198
+ className: cn(
199
+ "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
200
+ className
201
+ ),
202
+ ...props
203
+ }
204
+ );
205
+ }
206
+
207
+ // src/form/index.tsx
208
+ var import_jsx_runtime5 = require("react/jsx-runtime");
209
+ function isUiNodeInputAttributes(attributes) {
210
+ return attributes && typeof attributes === "object" && "name" in attributes && "type" in attributes;
211
+ }
212
+ function CustomFlowForm({ flow, Header }) {
213
+ const hasSubmitButton = flow.ui.nodes.some(
214
+ (node) => isUiNodeInputAttributes(node.attributes) && node.attributes.type === "submit"
215
+ );
216
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Card, { className: "w-full max-w-md mx-auto", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("form", { action: flow.ui.action, method: flow.ui.method, children: [
217
+ Header && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardTitle, { className: "text-center pb-4", children: Header }) }),
218
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(CardContent, { className: "space-y-4", children: [
219
+ flow.ui.nodes.map((node) => {
220
+ if (isUiNodeInputAttributes(node.attributes)) {
221
+ const isSubmitButton = node.attributes.type === "submit";
222
+ const isHiddenField = node.attributes.type === "hidden";
223
+ const isVisibleField = !isHiddenField && !isSubmitButton;
224
+ if (isHiddenField) {
225
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
226
+ "input",
227
+ {
228
+ name: node.attributes.name,
229
+ type: "hidden",
230
+ value: node.attributes.value || "",
231
+ readOnly: true
232
+ },
233
+ node.attributes.name
234
+ );
235
+ }
236
+ if (isSubmitButton) {
237
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
238
+ Button,
239
+ {
240
+ type: "submit",
241
+ name: node.attributes.name,
242
+ value: node.attributes.value || "",
243
+ className: "w-full mt-2",
244
+ children: node.meta.label?.text || node.attributes.value || "Submit"
245
+ },
246
+ node.attributes.name
247
+ );
248
+ }
249
+ if (isVisibleField && [
250
+ "default",
251
+ "password",
252
+ "code",
253
+ "webauthn",
254
+ "passkey",
255
+ "totp",
256
+ "lookup_secret"
257
+ ].includes(node.group)) {
258
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
259
+ "div",
260
+ {
261
+ className: "space-y-2",
262
+ children: [
263
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Label, { htmlFor: node.attributes.name, children: [
264
+ node.meta.label?.text,
265
+ node.attributes.required && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-destructive ml-1", children: "*" })
266
+ ] }),
267
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
268
+ Input,
269
+ {
270
+ id: node.attributes.name,
271
+ name: node.attributes.name,
272
+ type: node.attributes.type,
273
+ defaultValue: node.attributes.value || "",
274
+ required: node.attributes.required,
275
+ placeholder: `Enter your ${node.meta.label?.text?.toLowerCase() || node.attributes.name}`
276
+ }
277
+ )
278
+ ]
279
+ },
280
+ node.meta.label?.id || node.attributes.name
281
+ );
282
+ }
283
+ }
284
+ return null;
285
+ }),
286
+ !hasSubmitButton && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Button, { type: "submit", className: "w-full", children: "Submit" })
287
+ ] })
288
+ ] }) }) });
289
+ }
290
+
291
+ // src/tenant-switcher/index.tsx
292
+ var React6 = __toESM(require("react"), 1);
293
+
294
+ // src/components/ui/select.tsx
295
+ var React5 = __toESM(require("react"), 1);
296
+ var SelectPrimitive = __toESM(require("@radix-ui/react-select"), 1);
297
+ var import_lucide_react = require("lucide-react");
298
+ var import_jsx_runtime6 = require("react/jsx-runtime");
299
+ var Select = SelectPrimitive.Root;
300
+ var SelectValue = SelectPrimitive.Value;
301
+ var SelectTrigger = React5.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
302
+ SelectPrimitive.Trigger,
303
+ {
304
+ ref,
305
+ className: cn(
306
+ "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
307
+ className
308
+ ),
309
+ ...props,
310
+ children: [
311
+ children,
312
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.ChevronDown, { className: "h-4 w-4 opacity-50" }) })
313
+ ]
314
+ }
315
+ ));
316
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
317
+ var SelectScrollUpButton = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
318
+ SelectPrimitive.ScrollUpButton,
319
+ {
320
+ ref,
321
+ className: cn(
322
+ "flex cursor-default items-center justify-center py-1",
323
+ className
324
+ ),
325
+ ...props,
326
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.ChevronUp, { className: "h-4 w-4" })
327
+ }
328
+ ));
329
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
330
+ var SelectScrollDownButton = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
331
+ SelectPrimitive.ScrollDownButton,
332
+ {
333
+ ref,
334
+ className: cn(
335
+ "flex cursor-default items-center justify-center py-1",
336
+ className
337
+ ),
338
+ ...props,
339
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.ChevronDown, { className: "h-4 w-4" })
340
+ }
341
+ ));
342
+ SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
343
+ var SelectContent = React5.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SelectPrimitive.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
344
+ SelectPrimitive.Content,
345
+ {
346
+ ref,
347
+ className: cn(
348
+ "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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",
349
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
350
+ className
351
+ ),
352
+ position,
353
+ ...props,
354
+ children: [
355
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SelectScrollUpButton, {}),
356
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
357
+ SelectPrimitive.Viewport,
358
+ {
359
+ className: cn(
360
+ "p-1",
361
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
362
+ ),
363
+ children
364
+ }
365
+ ),
366
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SelectScrollDownButton, {})
367
+ ]
368
+ }
369
+ ) }));
370
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
371
+ var SelectLabel = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
372
+ SelectPrimitive.Label,
373
+ {
374
+ ref,
375
+ className: cn("px-2 py-1.5 text-sm font-semibold", className),
376
+ ...props
377
+ }
378
+ ));
379
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
380
+ var SelectItem = React5.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
381
+ SelectPrimitive.Item,
382
+ {
383
+ ref,
384
+ className: cn(
385
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
386
+ className
387
+ ),
388
+ ...props,
389
+ children: [
390
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Check, { className: "h-4 w-4" }) }) }),
391
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SelectPrimitive.ItemText, { children })
392
+ ]
393
+ }
394
+ ));
395
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
396
+ var SelectSeparator = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
397
+ SelectPrimitive.Separator,
398
+ {
399
+ ref,
400
+ className: cn("-mx-1 my-1 h-px bg-muted", className),
401
+ ...props
402
+ }
403
+ ));
404
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
405
+
406
+ // src/tenant-switcher/index.tsx
407
+ var import_jsx_runtime7 = require("react/jsx-runtime");
408
+ function SwitchActiveTenant({
409
+ tenants,
410
+ currentTenantId,
411
+ formAction,
412
+ placeholder = "Select tenant...",
413
+ className,
414
+ onTenantChange
415
+ }) {
416
+ const [isLoading, setIsLoading] = React6.useState(false);
417
+ const handleTenantChange = async (tenantId) => {
418
+ if (tenantId === currentTenantId) return;
419
+ setIsLoading(true);
420
+ try {
421
+ onTenantChange?.(tenantId);
422
+ if (formAction) {
423
+ const formData = new FormData();
424
+ formData.append("tenant_id", tenantId);
425
+ await formAction(formData);
426
+ }
427
+ } catch (error) {
428
+ console.error("Failed to switch tenant:", error);
429
+ } finally {
430
+ setIsLoading(false);
431
+ }
432
+ };
433
+ const currentTenant = tenants.find((tenant) => tenant.id === currentTenantId);
434
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
435
+ Select,
436
+ {
437
+ value: currentTenantId,
438
+ onValueChange: handleTenantChange,
439
+ disabled: isLoading,
440
+ children: [
441
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SelectTrigger, { className: cn("max-w-64", className), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SelectValue, { placeholder, children: currentTenant ? currentTenant.name : placeholder }) }),
442
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SelectContent, { children: tenants.map((tenant) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SelectItem, { value: tenant.id, children: tenant.name }, tenant.id)) })
443
+ ]
444
+ }
445
+ );
446
+ }
447
+
448
+ // src/pricing-table/index.tsx
449
+ var React7 = __toESM(require("react"), 1);
450
+ var import_lucide_react2 = require("lucide-react");
451
+ var import_jsx_runtime8 = require("react/jsx-runtime");
452
+ var getCurrencySymbol = (currency) => {
453
+ const symbols = {
454
+ USD: "$",
455
+ EUR: "\u20AC",
456
+ GBP: "\xA3",
457
+ JPY: "\xA5",
458
+ CAD: "C$",
459
+ AUD: "A$"
460
+ };
461
+ return symbols[currency] || currency;
462
+ };
463
+ var formatPrice = (price) => {
464
+ const priceUI = price.ui || {};
465
+ if (priceUI.price_display?.custom_text)
466
+ return priceUI.price_display.custom_text;
467
+ if (!price.amount || price.amount === 0) return "Free";
468
+ const amount = price.amount / 100;
469
+ const currency = price.currency.toUpperCase();
470
+ let formattedPrice = priceUI.price_display?.show_currency !== false ? `${getCurrencySymbol(currency)}${amount.toFixed(2)}` : amount.toFixed(2);
471
+ if (priceUI.price_display?.suffix)
472
+ formattedPrice += ` ${priceUI.price_display.suffix}`;
473
+ return formattedPrice;
474
+ };
475
+ var formatBillingPeriod = (price) => {
476
+ const priceUI = price.ui || {};
477
+ if (priceUI.billing_period) return priceUI.billing_period;
478
+ if (price.interval) {
479
+ const count = price.interval_count || 1;
480
+ return `per ${count === 1 ? price.interval : `${count} ${price.interval}s`}`;
481
+ }
482
+ return "one-time";
483
+ };
484
+ function PricingCard({
485
+ product,
486
+ isSelected,
487
+ onPriceSelect,
488
+ displayedPrice
489
+ }) {
490
+ const ui = product.ui || {};
491
+ const isHighlighted = ui.highlighted;
492
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
493
+ "div",
494
+ {
495
+ className: cn(
496
+ "flex flex-col h-full pb-6",
497
+ isHighlighted ? "relative" : ""
498
+ ),
499
+ children: [
500
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "h-4 flex-shrink-0 relative", children: ui.badge && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "absolute top-0 left-1/2 transform -translate-x-1/2 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "bg-primary text-primary-foreground px-3 py-1 rounded-full text-sm font-medium flex items-center gap-1 whitespace-nowrap shadow-md", children: [
501
+ ui.badge === "Most Popular" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Star, { className: "w-3 h-3" }),
502
+ ui.badge
503
+ ] }) }) }),
504
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
505
+ Card,
506
+ {
507
+ className: cn(
508
+ "flex flex-col flex-1 w-full transition-all duration-200 hover:shadow-lg",
509
+ isHighlighted && "border-primary shadow-lg",
510
+ isSelected && "ring-2 ring-primary"
511
+ ),
512
+ children: [
513
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(CardHeader, { className: "text-center", children: [
514
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CardTitle, { className: "text-xl font-bold", children: ui.display_name || product.name }),
515
+ ui.tagline && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CardDescription, { className: "text-base", children: ui.tagline })
516
+ ] }),
517
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(CardContent, { className: "flex-1 space-y-6", children: [
518
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "text-center", children: [
519
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "text-3xl font-bold", children: formatPrice(displayedPrice) }),
520
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "text-sm text-muted-foreground", children: formatBillingPeriod(displayedPrice) })
521
+ ] }),
522
+ (ui.features && ui.features.length > 0 || displayedPrice.ui?.features?.length > 0 || displayedPrice.ui?.limits?.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-4", children: [
523
+ ui.features && ui.features.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-2", children: [
524
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { className: "font-medium text-sm text-muted-foreground uppercase tracking-wide", children: "Features" }),
525
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { className: "space-y-2", children: ui.features.map((feature, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { className: "flex items-start gap-2", children: [
526
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Check, { className: "w-4 h-4 text-green-500 mt-0.5 flex-shrink-0" }),
527
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm", children: feature })
528
+ ] }, index)) })
529
+ ] }),
530
+ displayedPrice.ui?.features && displayedPrice.ui.features.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-2", children: [
531
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { className: "font-medium text-sm text-muted-foreground uppercase tracking-wide", children: "This Plan" }),
532
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { className: "space-y-2", children: displayedPrice.ui.features.map(
533
+ (feature, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { className: "flex items-start gap-2", children: [
534
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Check, { className: "w-4 h-4 text-blue-500 mt-0.5 flex-shrink-0" }),
535
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm", children: feature })
536
+ ] }, index)
537
+ ) })
538
+ ] }),
539
+ displayedPrice.ui?.limits && displayedPrice.ui.limits.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-2", children: [
540
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { className: "font-medium text-sm text-muted-foreground uppercase tracking-wide", children: "Usage Limits" }),
541
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { className: "space-y-1", children: displayedPrice.ui.limits.map(
542
+ (limit, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
543
+ "li",
544
+ {
545
+ className: "text-sm text-muted-foreground",
546
+ children: limit.text
547
+ },
548
+ index
549
+ )
550
+ ) })
551
+ ] })
552
+ ] })
553
+ ] }),
554
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CardFooter, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
555
+ Button,
556
+ {
557
+ className: "w-full",
558
+ variant: isHighlighted ? "default" : "outline",
559
+ size: "lg",
560
+ onClick: () => onPriceSelect?.(displayedPrice.id, product.id),
561
+ children: ui.cta_text || "Choose Plan"
562
+ }
563
+ ) })
564
+ ]
565
+ }
566
+ )
567
+ ]
568
+ }
569
+ );
570
+ }
571
+ var CARD_WIDTH = 320;
572
+ var GAP = 24;
573
+ function PricingTable({
574
+ products,
575
+ selectedPriceId,
576
+ onPriceSelect,
577
+ className,
578
+ showPricingToggle = false,
579
+ defaultInterval = "month"
580
+ }) {
581
+ const [selectedInterval, setSelectedInterval] = React7.useState(defaultInterval);
582
+ const [carouselIndex, setCarouselIndex] = React7.useState(0);
583
+ const sortedProducts = React7.useMemo(
584
+ () => [...products].sort(
585
+ (a, b) => (a.ui?.sort_order ?? 999) - (b.ui?.sort_order ?? 999)
586
+ ),
587
+ [products]
588
+ );
589
+ const hasMultipleIntervals = React7.useMemo(
590
+ () => products.some(
591
+ (p) => new Set(p.prices.map((price) => price.interval)).size > 1
592
+ ),
593
+ [products]
594
+ );
595
+ const getDisplayedPrice = (product) => product.prices.find((p) => p.interval === selectedInterval) || product.prices[0];
596
+ const renderCard = (product) => {
597
+ const displayedPrice = getDisplayedPrice(product);
598
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
599
+ PricingCard,
600
+ {
601
+ product,
602
+ displayedPrice,
603
+ isSelected: selectedPriceId === displayedPrice.id,
604
+ onPriceSelect
605
+ }
606
+ );
607
+ };
608
+ const desktopCarousel = /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "relative max-w-7xl mx-auto", children: [
609
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
610
+ Button,
611
+ {
612
+ variant: "ghost",
613
+ size: "icon",
614
+ className: "absolute left-0 top-1/2 transform -translate-y-1/2 -translate-x-4 z-10 bg-white shadow-lg border hover:bg-gray-50 disabled:opacity-50",
615
+ onClick: () => setCarouselIndex(Math.max(0, carouselIndex - 1)),
616
+ disabled: carouselIndex === 0,
617
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.ChevronLeft, { className: "w-4 h-4" })
618
+ }
619
+ ),
620
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
621
+ "div",
622
+ {
623
+ className: "overflow-hidden mx-auto",
624
+ style: { width: `${3 * CARD_WIDTH + 2 * GAP}px` },
625
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
626
+ "div",
627
+ {
628
+ className: "flex items-stretch transition-transform duration-300 ease-in-out",
629
+ style: {
630
+ transform: `translateX(-${carouselIndex * (CARD_WIDTH + GAP)}px)`,
631
+ gap: `${GAP}px`
632
+ },
633
+ children: sortedProducts.map((p) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
634
+ "div",
635
+ {
636
+ style: { width: `${CARD_WIDTH}px` },
637
+ className: "flex-shrink-0",
638
+ children: renderCard(p)
639
+ },
640
+ p.id
641
+ ))
642
+ }
643
+ )
644
+ }
645
+ ),
646
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
647
+ Button,
648
+ {
649
+ variant: "ghost",
650
+ size: "icon",
651
+ className: "absolute right-0 top-1/2 transform -translate-y-1/2 translate-x-4 z-10 bg-white shadow-lg border hover:bg-gray-50 disabled:opacity-50",
652
+ onClick: () => setCarouselIndex(
653
+ Math.min(sortedProducts.length - 3, carouselIndex + 1)
654
+ ),
655
+ disabled: carouselIndex >= sortedProducts.length - 3,
656
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.ChevronRight, { className: "w-4 h-4" })
657
+ }
658
+ ),
659
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex justify-center mt-6 space-x-2", children: Array.from(
660
+ { length: Math.max(1, sortedProducts.length - 2) },
661
+ (_, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
662
+ "button",
663
+ {
664
+ onClick: () => setCarouselIndex(i),
665
+ className: cn(
666
+ "w-2 h-2 rounded-full transition-colors",
667
+ i === carouselIndex ? "bg-primary" : "bg-gray-300"
668
+ ),
669
+ "aria-label": `Go to slide ${i + 1}`
670
+ },
671
+ i
672
+ )
673
+ ) })
674
+ ] });
675
+ const staticLayout = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
676
+ "div",
677
+ {
678
+ className: "flex flex-row items-stretch justify-center",
679
+ style: { gap: `${GAP}px` },
680
+ children: sortedProducts.map((p) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
681
+ "div",
682
+ {
683
+ style: { width: `${CARD_WIDTH}px` },
684
+ className: "flex-shrink-0",
685
+ children: renderCard(p)
686
+ },
687
+ p.id
688
+ ))
689
+ }
690
+ );
691
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: cn("w-full", className), children: [
692
+ showPricingToggle && hasMultipleIntervals && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex bg-gray-100 p-1 rounded-lg", children: [
693
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
694
+ Button,
695
+ {
696
+ variant: selectedInterval === "month" ? "default" : "ghost",
697
+ size: "sm",
698
+ onClick: () => setSelectedInterval("month"),
699
+ className: "rounded-md",
700
+ children: "Monthly"
701
+ }
702
+ ),
703
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
704
+ Button,
705
+ {
706
+ variant: selectedInterval === "year" ? "default" : "ghost",
707
+ size: "sm",
708
+ onClick: () => setSelectedInterval("year"),
709
+ className: "rounded-md",
710
+ children: "Yearly"
711
+ }
712
+ )
713
+ ] }) }),
714
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "lg:hidden relative", children: [
715
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
716
+ "div",
717
+ {
718
+ className: "overflow-hidden mx-auto",
719
+ style: { width: `${CARD_WIDTH}px` },
720
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
721
+ "div",
722
+ {
723
+ className: "flex transition-transform duration-300 ease-in-out items-stretch",
724
+ style: {
725
+ transform: `translateX(-${carouselIndex * CARD_WIDTH}px)`
726
+ },
727
+ children: sortedProducts.map((product) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
728
+ "div",
729
+ {
730
+ className: "flex-shrink-0",
731
+ style: { width: `${CARD_WIDTH}px` },
732
+ children: renderCard(product)
733
+ },
734
+ product.id
735
+ ))
736
+ }
737
+ )
738
+ }
739
+ ),
740
+ sortedProducts.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
741
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
742
+ Button,
743
+ {
744
+ variant: "ghost",
745
+ size: "icon",
746
+ className: "absolute left-0 top-1/2 -translate-y-1/2 -translate-x-2 z-10 bg-white shadow-lg border hover:bg-gray-50 disabled:opacity-50",
747
+ onClick: () => setCarouselIndex((prev) => Math.max(0, prev - 1)),
748
+ disabled: carouselIndex === 0,
749
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.ChevronLeft, { className: "w-5 h-5" })
750
+ }
751
+ ),
752
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
753
+ Button,
754
+ {
755
+ variant: "ghost",
756
+ size: "icon",
757
+ className: "absolute right-0 top-1/2 -translate-y-1/2 translate-x-2 z-10 bg-white shadow-lg border hover:bg-gray-50 disabled:opacity-50",
758
+ onClick: () => setCarouselIndex(
759
+ (prev) => Math.min(sortedProducts.length - 1, prev + 1)
760
+ ),
761
+ disabled: carouselIndex >= sortedProducts.length - 1,
762
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.ChevronRight, { className: "w-5 h-5" })
763
+ }
764
+ ),
765
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex justify-center mt-6 space-x-2", children: Array.from({ length: sortedProducts.length }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
766
+ "button",
767
+ {
768
+ onClick: () => setCarouselIndex(i),
769
+ className: cn(
770
+ "w-2 h-2 rounded-full transition-colors",
771
+ i === carouselIndex ? "bg-primary" : "bg-gray-300"
772
+ ),
773
+ "aria-label": `Go to slide ${i + 1}`
774
+ },
775
+ i
776
+ )) })
777
+ ] })
778
+ ] }),
779
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hidden lg:block", children: sortedProducts.length <= 3 ? staticLayout : desktopCarousel })
780
+ ] });
781
+ }
782
+ // Annotate the CommonJS export names for ESM import in node:
783
+ 0 && (module.exports = {
784
+ CustomFlowForm,
785
+ PricingTable,
786
+ SwitchActiveTenant
787
+ });