@revealui/presentation 0.2.0 → 0.3.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 (130) hide show
  1. package/README.md +146 -42
  2. package/dist/Box-DC3F8eRf.js +430 -0
  3. package/dist/Box-DC3F8eRf.js.map +1 -0
  4. package/dist/Text-jQVi12Hi.js +218 -0
  5. package/dist/Text-jQVi12Hi.js.map +1 -0
  6. package/dist/client.d.ts +3 -1
  7. package/dist/client.d.ts.map +1 -1
  8. package/dist/client.js +134 -2803
  9. package/dist/client.js.map +1 -1
  10. package/dist/components/BuiltWithRevealUI.d.ts +12 -0
  11. package/dist/components/BuiltWithRevealUI.d.ts.map +1 -0
  12. package/dist/components/Button.d.ts +2 -1
  13. package/dist/components/Button.d.ts.map +1 -1
  14. package/dist/components/Card.d.ts +18 -6
  15. package/dist/components/Card.d.ts.map +1 -1
  16. package/dist/components/Checkbox.d.ts +6 -3
  17. package/dist/components/Checkbox.d.ts.map +1 -1
  18. package/dist/components/FormLabel.d.ts +5 -1
  19. package/dist/components/FormLabel.d.ts.map +1 -1
  20. package/dist/components/Input.d.ts +4 -2
  21. package/dist/components/Input.d.ts.map +1 -1
  22. package/dist/components/Label.d.ts +7 -2
  23. package/dist/components/Label.d.ts.map +1 -1
  24. package/dist/components/Pagination.d.ts +12 -23
  25. package/dist/components/Pagination.d.ts.map +1 -1
  26. package/dist/components/Select.d.ts +36 -13
  27. package/dist/components/Select.d.ts.map +1 -1
  28. package/dist/components/Textarea.d.ts +4 -2
  29. package/dist/components/Textarea.d.ts.map +1 -1
  30. package/dist/components/accordion.d.ts.map +1 -1
  31. package/dist/components/alert.d.ts.map +1 -1
  32. package/dist/components/auth-layout.d.ts +7 -2
  33. package/dist/components/auth-layout.d.ts.map +1 -1
  34. package/dist/components/avatar-group.d.ts.map +1 -1
  35. package/dist/components/avatar.d.ts +6 -5
  36. package/dist/components/avatar.d.ts.map +1 -1
  37. package/dist/components/badge.d.ts +5 -5
  38. package/dist/components/badge.d.ts.map +1 -1
  39. package/dist/components/breadcrumb.d.ts.map +1 -1
  40. package/dist/components/button-headless.d.ts +2 -1
  41. package/dist/components/button-headless.d.ts.map +1 -1
  42. package/dist/components/callout.d.ts.map +1 -1
  43. package/dist/components/checkbox-headless.d.ts.map +1 -1
  44. package/dist/components/code-block.d.ts.map +1 -1
  45. package/dist/components/combobox.d.ts.map +1 -1
  46. package/dist/components/dialog.d.ts.map +1 -1
  47. package/dist/components/drawer.d.ts.map +1 -1
  48. package/dist/components/dropdown.d.ts.map +1 -1
  49. package/dist/components/empty-state.d.ts.map +1 -1
  50. package/dist/components/fieldset.d.ts.map +1 -1
  51. package/dist/components/heading.d.ts.map +1 -1
  52. package/dist/components/index.d.ts +19 -1
  53. package/dist/components/index.d.ts.map +1 -1
  54. package/dist/components/input-headless.d.ts +5 -3
  55. package/dist/components/input-headless.d.ts.map +1 -1
  56. package/dist/components/kbd.d.ts.map +1 -1
  57. package/dist/components/link.d.ts +3 -2
  58. package/dist/components/link.d.ts.map +1 -1
  59. package/dist/components/listbox.d.ts.map +1 -1
  60. package/dist/components/navbar.d.ts +5 -5
  61. package/dist/components/navbar.d.ts.map +1 -1
  62. package/dist/components/pricing-table.d.ts +23 -0
  63. package/dist/components/pricing-table.d.ts.map +1 -0
  64. package/dist/components/progress.d.ts.map +1 -1
  65. package/dist/components/radio.d.ts.map +1 -1
  66. package/dist/components/rating.d.ts.map +1 -1
  67. package/dist/components/select-headless.d.ts +5 -2
  68. package/dist/components/select-headless.d.ts.map +1 -1
  69. package/dist/components/sidebar-layout.d.ts.map +1 -1
  70. package/dist/components/sidebar.d.ts +5 -5
  71. package/dist/components/sidebar.d.ts.map +1 -1
  72. package/dist/components/skeleton.d.ts.map +1 -1
  73. package/dist/components/slider.d.ts.map +1 -1
  74. package/dist/components/stacked-layout.d.ts.map +1 -1
  75. package/dist/components/stat.d.ts.map +1 -1
  76. package/dist/components/stepper.d.ts.map +1 -1
  77. package/dist/components/switch.d.ts.map +1 -1
  78. package/dist/components/table.d.ts.map +1 -1
  79. package/dist/components/tabs.d.ts.map +1 -1
  80. package/dist/components/text.d.ts.map +1 -1
  81. package/dist/components/textarea-headless.d.ts +5 -2
  82. package/dist/components/textarea-headless.d.ts.map +1 -1
  83. package/dist/components/timeline.d.ts.map +1 -1
  84. package/dist/components/toast.d.ts.map +1 -1
  85. package/dist/components/tooltip.d.ts +7 -5
  86. package/dist/components/tooltip.d.ts.map +1 -1
  87. package/dist/hooks/index.d.ts.map +1 -1
  88. package/dist/hooks/use-click-outside.d.ts.map +1 -1
  89. package/dist/hooks/use-close-context.d.ts.map +1 -1
  90. package/dist/hooks/use-controllable-state.d.ts.map +1 -1
  91. package/dist/hooks/use-data-interactive.d.ts.map +1 -1
  92. package/dist/hooks/use-field-context.d.ts.map +1 -1
  93. package/dist/hooks/use-focus-trap.d.ts.map +1 -1
  94. package/dist/hooks/use-layout-animation.d.ts.map +1 -1
  95. package/dist/hooks/use-popover.d.ts.map +1 -1
  96. package/dist/hooks/use-roving-tabindex.d.ts.map +1 -1
  97. package/dist/hooks/use-toggle.d.ts.map +1 -1
  98. package/dist/hooks/use-transition.d.ts.map +1 -1
  99. package/dist/hooks/use-type-ahead.d.ts.map +1 -1
  100. package/dist/index.d.ts +1 -0
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +206 -65
  103. package/dist/index.js.map +1 -1
  104. package/dist/primitives/Box.d.ts +3 -1
  105. package/dist/primitives/Box.d.ts.map +1 -1
  106. package/dist/primitives/Flex.d.ts +3 -1
  107. package/dist/primitives/Flex.d.ts.map +1 -1
  108. package/dist/primitives/Grid.d.ts +3 -1
  109. package/dist/primitives/Grid.d.ts.map +1 -1
  110. package/dist/primitives/Heading.d.ts +3 -1
  111. package/dist/primitives/Heading.d.ts.map +1 -1
  112. package/dist/primitives/Slot.d.ts +3 -1
  113. package/dist/primitives/Slot.d.ts.map +1 -1
  114. package/dist/primitives/Text.d.ts +3 -1
  115. package/dist/primitives/Text.d.ts.map +1 -1
  116. package/dist/primitives/index.d.ts.map +1 -1
  117. package/dist/server.d.ts +2 -1
  118. package/dist/server.d.ts.map +1 -1
  119. package/dist/server.js +14 -13
  120. package/dist/tooltip-DQYjYWbe.js +5085 -0
  121. package/dist/tooltip-DQYjYWbe.js.map +1 -0
  122. package/dist/utils/cn.d.ts.map +1 -1
  123. package/dist/utils/index.d.ts.map +1 -1
  124. package/package.json +7 -4
  125. package/dist/Box-DDhRNK02.js +0 -45
  126. package/dist/Box-DDhRNK02.js.map +0 -1
  127. package/dist/Text-BIym7IhD.js +0 -425
  128. package/dist/Text-BIym7IhD.js.map +0 -1
  129. package/dist/tooltip-oH4lAnkn.js +0 -2277
  130. package/dist/tooltip-oH4lAnkn.js.map +0 -1
package/README.md CHANGED
@@ -1,65 +1,169 @@
1
1
  # @revealui/presentation
2
2
 
3
- Shared UI components and presentation layer for RevealUI applications.
3
+ 50+ native UI components for RevealUI — built with React 19, Tailwind CSS v4, and CVA. Zero external UI library dependencies (only clsx + class-variance-authority).
4
4
 
5
- ## Purpose
5
+ ## Features
6
6
 
7
- This package provides reusable UI components that can be shared across multiple apps in the RevealUI monorepo. It serves as the design system foundation for consistent UI across:
7
+ - **48 Components** Forms, data display, feedback, navigation, media, and layout
8
+ - **6 Primitives** — Low-level building blocks (Box, Flex, Grid, Heading, Text, Slot)
9
+ - **14 Hooks** — Focus trap, click outside, popover, roving tabindex, scroll lock, and more
10
+ - **Headless + Styled** — Many components ship both unstyled (headless) and styled (CVA) variants
11
+ - **Accessible** — WCAG 2.1 patterns with proper ARIA attributes
12
+ - **React 19** — Server components, hooks, and modern patterns
13
+ - **Tailwind CSS v4** — Native v4 utility classes, no v3 compat layer
8
14
 
9
- - `apps/cms` - CMS admin interface
10
- - `apps/mainframe` - Public-facing web application
11
- - Future applications
15
+ ## Installation
12
16
 
13
- ## Structure
14
-
15
- ```
16
- packages/presentation/
17
- ├── src/
18
- │ ├── components/ # High-level, styled components
19
- │ ├── primitives/ # Low-level, base components
20
- │ └── index.ts # Main entry point
21
- ├── package.json
22
- ├── tsconfig.json
23
- └── README.md
17
+ ```bash
18
+ pnpm add @revealui/presentation
24
19
  ```
25
20
 
26
21
  ## Usage
27
22
 
28
- ### In Apps
29
-
30
23
  ```typescript
31
- // Import from the package
32
- import { Button, Card } from '@revealui/presentation';
33
-
34
- // Or import specific modules
35
- import { Button } from '@revealui/presentation/components';
24
+ import { Button, Card, Input, Badge } from '@revealui/presentation'
25
+ import { Box, Flex } from '@revealui/presentation/primitives'
26
+ import { useClickOutside, useFocusTrap } from '@revealui/presentation/hooks'
36
27
  ```
37
28
 
38
- ### Adding New Components
39
-
40
- 1. Create component in `src/components/` or `src/primitives/`
41
- 2. Export from the respective `index.ts` file
42
- 3. Re-export from main `src/index.ts` if needed
43
- 4. Build: `pnpm --filter @revealui/presentation build`
44
-
45
- ## Guidelines
46
-
47
- - **Components**: High-level, styled, feature-complete components
48
- - **Primitives**: Low-level, unstyled/minimally styled building blocks
49
- - Use TypeScript for all components
50
- - Follow React 19 patterns
51
- - Support Tailwind CSS 4.0
52
- - Ensure accessibility (WCAG 2.1)
29
+ ## Components (48)
30
+
31
+ ### Layout
32
+ | Component | Description |
33
+ |-----------|-------------|
34
+ | AuthLayout | Authentication page layout |
35
+ | SidebarLayout | Sidebar + content layout |
36
+ | StackedLayout | Stacked page layout |
37
+ | Navbar | Top navigation bar |
38
+ | Sidebar | Side navigation |
39
+
40
+ ### Form Controls
41
+ | Component | Description |
42
+ |-----------|-------------|
43
+ | Button / ButtonCVA | Action trigger (headless + styled) |
44
+ | Input / InputCVA | Text input (headless + styled) |
45
+ | Textarea / TextareaCVA | Multi-line text (headless + styled) |
46
+ | Checkbox / CheckboxCVA | Checkbox (headless + styled) |
47
+ | Select / SelectCVA | Dropdown select with subcomponents |
48
+ | Combobox | Searchable select |
49
+ | Listbox | List selection |
50
+ | Radio | Radio group |
51
+ | Switch | Toggle switch |
52
+ | Label / FormLabel | Form labels |
53
+ | Fieldset | Form field grouping |
54
+
55
+ ### Data Display
56
+ | Component | Description |
57
+ |-----------|-------------|
58
+ | Card | Content container (header, title, description, content, footer) |
59
+ | Table | Data table |
60
+ | Pagination | Page navigation |
61
+ | Badge | Status indicator |
62
+ | Text | Styled text |
63
+ | Heading | Section heading |
64
+ | Divider | Horizontal rule |
65
+ | DescriptionList | Key-value pairs |
66
+ | Breadcrumb | Navigation trail |
67
+
68
+ ### Feedback
69
+ | Component | Description |
70
+ |-----------|-------------|
71
+ | Alert | Inline alert message |
72
+ | Callout | Highlighted information |
73
+ | Toast | Temporary notification (with provider + hook) |
74
+ | Tooltip | Hover information |
75
+ | Progress | Progress bar |
76
+ | Slider | Range input |
77
+ | Skeleton | Loading placeholder |
78
+ | EmptyState | No-data placeholder |
79
+ | Stat | Metric display (with StatGroup) |
80
+ | Rating | Star rating |
81
+
82
+ ### Navigation
83
+ | Component | Description |
84
+ |-----------|-------------|
85
+ | Accordion | Collapsible sections |
86
+ | Tabs | Tab panels |
87
+ | Stepper | Step-by-step progress |
88
+ | Timeline | Chronological events |
89
+ | Dropdown | Action menu |
90
+ | Drawer | Slide-out panel |
91
+ | Dialog | Modal dialog |
92
+
93
+ ### Media & Misc
94
+ | Component | Description |
95
+ |-----------|-------------|
96
+ | Avatar / AvatarGroup | User avatars |
97
+ | CodeBlock | Syntax-highlighted code |
98
+ | Kbd / KbdShortcut | Keyboard shortcut display |
99
+ | Link | Styled anchor |
100
+
101
+ ## Primitives (6)
102
+
103
+ | Primitive | Description |
104
+ |-----------|-------------|
105
+ | Box | Generic container |
106
+ | Flex | Flexbox layout |
107
+ | Grid | CSS Grid layout |
108
+ | Heading | Semantic heading |
109
+ | Text | Text content |
110
+ | Slot | Component composition utility |
111
+
112
+ ## Hooks (14)
113
+
114
+ | Hook | Purpose |
115
+ |------|---------|
116
+ | useClickOutside | Detect clicks outside an element |
117
+ | useCloseContext | Shared close handler context |
118
+ | useControllableState | Controlled/uncontrolled state |
119
+ | useDataInteractive | Interactive element data attributes |
120
+ | useEscapeKey | Escape key handler |
121
+ | useFieldContext | Form field context (label, error, description) |
122
+ | useFocusTrap | Trap focus within an element |
123
+ | useLayoutAnimation | Animated layout transitions |
124
+ | usePopover | Popover positioning |
125
+ | useRovingTabindex | Keyboard navigation in groups |
126
+ | useScrollLock | Prevent body scroll |
127
+ | useToggle | Boolean toggle state |
128
+ | useTransition | CSS transitions |
129
+ | useTypeAhead | Type-ahead search in lists |
130
+
131
+ ## Exports
132
+
133
+ | Subpath | Contents |
134
+ |---------|----------|
135
+ | `@revealui/presentation` | All components, primitives, and hooks |
136
+ | `@revealui/presentation/server` | Server components |
137
+ | `@revealui/presentation/client` | Client components |
138
+ | `@revealui/presentation/components` | Components only |
139
+ | `@revealui/presentation/primitives` | Primitives only |
140
+ | `@revealui/presentation/hooks` | Hooks only |
53
141
 
54
142
  ## Development
55
143
 
56
144
  ```bash
57
145
  # Build
58
- pnpm --filter @revealui/presentation build
146
+ pnpm build
59
147
 
60
148
  # Type check
61
- pnpm --filter @revealui/presentation typecheck
149
+ pnpm typecheck
62
150
 
63
151
  # Watch mode
64
- pnpm --filter @revealui/presentation dev
152
+ pnpm dev
65
153
  ```
154
+
155
+ ## Adding Components
156
+
157
+ 1. Create component in `src/components/` (styled) or `src/primitives/` (unstyled)
158
+ 2. Export from the respective `index.ts`
159
+ 3. Use CVA for variant-based styling
160
+ 4. Follow WCAG 2.1 accessibility patterns
161
+
162
+ ## Related
163
+
164
+ - [Core Package](../core/README.md) — CMS engine (uses presentation components)
165
+ - [Architecture Guide](../../docs/ARCHITECTURE.md)
166
+
167
+ ## License
168
+
169
+ MIT
@@ -0,0 +1,430 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import React from "react";
3
+ function r(e) {
4
+ var t, f, n = "";
5
+ if ("string" == typeof e || "number" == typeof e) n += e;
6
+ else if ("object" == typeof e) if (Array.isArray(e)) {
7
+ var o = e.length;
8
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
9
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
10
+ return n;
11
+ }
12
+ function clsx() {
13
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
14
+ return n;
15
+ }
16
+ const falsyToString = (value) => typeof value === "boolean" ? `${value}` : value === 0 ? "0" : value;
17
+ const cx = clsx;
18
+ const cva = (base, config) => (props) => {
19
+ var _config_compoundVariants;
20
+ if ((config === null || config === void 0 ? void 0 : config.variants) == null) return cx(base, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
21
+ const { variants, defaultVariants } = config;
22
+ const getVariantClassNames = Object.keys(variants).map((variant) => {
23
+ const variantProp = props === null || props === void 0 ? void 0 : props[variant];
24
+ const defaultVariantProp = defaultVariants === null || defaultVariants === void 0 ? void 0 : defaultVariants[variant];
25
+ if (variantProp === null) return null;
26
+ const variantKey = falsyToString(variantProp) || falsyToString(defaultVariantProp);
27
+ return variants[variant][variantKey];
28
+ });
29
+ const propsWithoutUndefined = props && Object.entries(props).reduce((acc, param) => {
30
+ let [key, value] = param;
31
+ if (value === void 0) {
32
+ return acc;
33
+ }
34
+ acc[key] = value;
35
+ return acc;
36
+ }, {});
37
+ const getCompoundVariantClassNames = config === null || config === void 0 ? void 0 : (_config_compoundVariants = config.compoundVariants) === null || _config_compoundVariants === void 0 ? void 0 : _config_compoundVariants.reduce((acc, param) => {
38
+ let { class: cvClass, className: cvClassName, ...compoundVariantOptions } = param;
39
+ return Object.entries(compoundVariantOptions).every((param2) => {
40
+ let [key, value] = param2;
41
+ return Array.isArray(value) ? value.includes({
42
+ ...defaultVariants,
43
+ ...propsWithoutUndefined
44
+ }[key]) : {
45
+ ...defaultVariants,
46
+ ...propsWithoutUndefined
47
+ }[key] === value;
48
+ }) ? [
49
+ ...acc,
50
+ cvClass,
51
+ cvClassName
52
+ ] : acc;
53
+ }, []);
54
+ return cx(base, getVariantClassNames, getCompoundVariantClassNames, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
55
+ };
56
+ function cn(...inputs) {
57
+ const classes = [];
58
+ for (const input of inputs.flat()) {
59
+ if (!input) continue;
60
+ if (typeof input === "string" || typeof input === "number") {
61
+ classes.push(String(input));
62
+ continue;
63
+ }
64
+ if (typeof input === "object") {
65
+ for (const [key, value] of Object.entries(input)) {
66
+ if (value) {
67
+ classes.push(key);
68
+ }
69
+ }
70
+ }
71
+ }
72
+ return classes.join(" ").trim();
73
+ }
74
+ function Slot({ children, asChild, ref, ...slotProps }) {
75
+ if (asChild && React.isValidElement(children)) {
76
+ return React.cloneElement(children, {
77
+ ...slotProps,
78
+ ...children.props,
79
+ ref
80
+ });
81
+ }
82
+ return /* @__PURE__ */ jsx("div", { ...slotProps, ref, children });
83
+ }
84
+ const buttonVariants = cva(
85
+ "inline-flex items-center justify-center whitespace-nowrap rounded text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
86
+ {
87
+ defaultVariants: {
88
+ size: "default",
89
+ variant: "default"
90
+ },
91
+ variants: {
92
+ size: {
93
+ clear: "",
94
+ default: "h-10 px-4 py-2",
95
+ icon: "size-10",
96
+ lg: "h-11 rounded px-8",
97
+ sm: "h-9 rounded px-3"
98
+ },
99
+ variant: {
100
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
101
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
102
+ ghost: "hover:bg-card hover:text-accent-foreground",
103
+ link: "text-primary items-start justify-start underline-offset-4 hover:underline",
104
+ outline: "border border-border bg-background hover:bg-card hover:text-accent-foreground",
105
+ primary: "bg-primary text-primary-foreground hover:bg-primary/90",
106
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80"
107
+ }
108
+ }
109
+ }
110
+ );
111
+ function Button({ asChild = false, className, size, variant, ref, ...props }) {
112
+ const Comp = asChild ? Slot : "button";
113
+ return /* @__PURE__ */ jsx(Comp, { className: cn(buttonVariants({ className, size, variant })), ref, ...props });
114
+ }
115
+ const ChevronLeft = ({ className }) => {
116
+ return /* @__PURE__ */ jsxs(
117
+ "svg",
118
+ {
119
+ xmlns: "http://www.w3.org/2000/svg",
120
+ fill: "none",
121
+ viewBox: "0 0 24 24",
122
+ strokeWidth: 1.5,
123
+ stroke: "currentColor",
124
+ className: cn("size-6", className),
125
+ children: [
126
+ /* @__PURE__ */ jsx("title", { children: "Previous page" }),
127
+ /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15.75 19.5 8.25 12l7.5-7.5" })
128
+ ]
129
+ }
130
+ );
131
+ };
132
+ const ChevronRight = ({ className }) => {
133
+ return /* @__PURE__ */ jsxs(
134
+ "svg",
135
+ {
136
+ xmlns: "http://www.w3.org/2000/svg",
137
+ fill: "none",
138
+ viewBox: "0 0 24 24",
139
+ strokeWidth: 1.5,
140
+ stroke: "currentColor",
141
+ className: cn("size-6", className),
142
+ children: [
143
+ /* @__PURE__ */ jsx("title", { children: "Next page" }),
144
+ /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m8.25 4.5 7.5 7.5-7.5 7.5" })
145
+ ]
146
+ }
147
+ );
148
+ };
149
+ const MoreHorizontal = ({ className }) => {
150
+ return /* @__PURE__ */ jsxs(
151
+ "svg",
152
+ {
153
+ xmlns: "http://www.w3.org/2000/svg",
154
+ fill: "none",
155
+ viewBox: "0 0 24 6",
156
+ className: cn("size-6", className),
157
+ children: [
158
+ /* @__PURE__ */ jsx("title", { children: "More pages" }),
159
+ /* @__PURE__ */ jsx("circle", { cx: "6", cy: "3", r: "3", fill: "currentColor" }),
160
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "3", r: "3", fill: "currentColor" }),
161
+ /* @__PURE__ */ jsx("circle", { cx: "18", cy: "3", r: "3", fill: "currentColor" })
162
+ ]
163
+ }
164
+ );
165
+ };
166
+ const Pagination = ({ className, ...props }) => /* @__PURE__ */ jsx(
167
+ "nav",
168
+ {
169
+ "aria-label": "pagination",
170
+ className: cn("mx-auto flex w-full justify-center", className),
171
+ ...props
172
+ }
173
+ );
174
+ function PaginationContent({
175
+ className,
176
+ ref,
177
+ ...props
178
+ }) {
179
+ return /* @__PURE__ */ jsx("ul", { className: cn("flex flex-row items-center gap-1", className), ref, ...props });
180
+ }
181
+ function PaginationItem({
182
+ className,
183
+ ref,
184
+ ...props
185
+ }) {
186
+ return /* @__PURE__ */ jsx("li", { className: cn("", className), ref, ...props });
187
+ }
188
+ const PaginationLink = ({
189
+ className,
190
+ isActive,
191
+ size = "icon",
192
+ disabled,
193
+ ...props
194
+ }) => /* @__PURE__ */ jsx(
195
+ "button",
196
+ {
197
+ "aria-current": isActive ? "page" : void 0,
198
+ "aria-disabled": disabled ? true : void 0,
199
+ disabled,
200
+ className: cn(
201
+ buttonVariants({
202
+ size,
203
+ variant: isActive ? "outline" : "ghost"
204
+ }),
205
+ className
206
+ ),
207
+ ...props
208
+ }
209
+ );
210
+ const PaginationPrevious = ({ className, ...props }) => /* @__PURE__ */ jsxs(
211
+ PaginationLink,
212
+ {
213
+ "aria-label": "Go to previous page",
214
+ className: cn("gap-1 pl-2.5", className),
215
+ size: "default",
216
+ ...props,
217
+ children: [
218
+ /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" }),
219
+ /* @__PURE__ */ jsx("span", { children: "Previous" })
220
+ ]
221
+ }
222
+ );
223
+ const PaginationNext = ({ className, ...props }) => /* @__PURE__ */ jsxs(
224
+ PaginationLink,
225
+ {
226
+ "aria-label": "Go to next page",
227
+ className: cn("gap-1 pr-2.5", className),
228
+ size: "default",
229
+ ...props,
230
+ children: [
231
+ /* @__PURE__ */ jsx("span", { children: "Next" }),
232
+ /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" })
233
+ ]
234
+ }
235
+ );
236
+ const PaginationEllipsis = ({ className, ...props }) => /* @__PURE__ */ jsxs(
237
+ "span",
238
+ {
239
+ "aria-hidden": true,
240
+ className: cn("flex h-9 w-9 items-center justify-center", className),
241
+ ...props,
242
+ children: [
243
+ /* @__PURE__ */ jsx(MoreHorizontal, { className: "size-4" }),
244
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "More pages" })
245
+ ]
246
+ }
247
+ );
248
+ function CheckIcon() {
249
+ return /* @__PURE__ */ jsx(
250
+ "svg",
251
+ {
252
+ className: "h-4 w-4 shrink-0 text-blue-600 mt-0.5",
253
+ fill: "currentColor",
254
+ viewBox: "0 0 20 20",
255
+ "aria-hidden": "true",
256
+ children: /* @__PURE__ */ jsx(
257
+ "path",
258
+ {
259
+ fillRule: "evenodd",
260
+ 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",
261
+ clipRule: "evenodd"
262
+ }
263
+ )
264
+ }
265
+ );
266
+ }
267
+ function PricingTable({
268
+ tiers,
269
+ currentTier,
270
+ compact = false,
271
+ onSelectTier,
272
+ className
273
+ }) {
274
+ if (compact) {
275
+ return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col gap-4 sm:flex-row", className), children: tiers.map((tier) => /* @__PURE__ */ jsx(
276
+ PricingCardCompact,
277
+ {
278
+ tier,
279
+ isCurrent: tier.id === currentTier,
280
+ onSelect: onSelectTier
281
+ },
282
+ tier.id
283
+ )) });
284
+ }
285
+ return /* @__PURE__ */ jsx(
286
+ "div",
287
+ {
288
+ className: cn(
289
+ "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4",
290
+ tiers.length === 3 && "lg:grid-cols-3",
291
+ tiers.length === 2 && "lg:grid-cols-2 max-w-3xl mx-auto",
292
+ className
293
+ ),
294
+ children: tiers.map((tier) => /* @__PURE__ */ jsx(
295
+ PricingCardFull,
296
+ {
297
+ tier,
298
+ isCurrent: tier.id === currentTier,
299
+ onSelect: onSelectTier
300
+ },
301
+ tier.id
302
+ ))
303
+ }
304
+ );
305
+ }
306
+ function PricingCardFull({
307
+ tier,
308
+ isCurrent,
309
+ onSelect
310
+ }) {
311
+ const isHighlighted = tier.highlighted && !isCurrent;
312
+ return /* @__PURE__ */ jsxs(
313
+ "div",
314
+ {
315
+ className: cn(
316
+ "relative rounded-2xl bg-white p-8 shadow-lg dark:bg-zinc-900",
317
+ isHighlighted ? "ring-2 ring-blue-600" : isCurrent ? "ring-2 ring-emerald-500" : "ring-1 ring-zinc-200 dark:ring-zinc-800"
318
+ ),
319
+ children: [
320
+ isHighlighted && /* @__PURE__ */ jsx("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", children: "Most Popular" }),
321
+ isCurrent && /* @__PURE__ */ jsx("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", children: "Current Plan" }),
322
+ /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
323
+ /* @__PURE__ */ jsx("h3", { className: "text-xl font-bold tracking-tight text-zinc-900 dark:text-white", children: tier.name }),
324
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-zinc-600 dark:text-zinc-400", children: tier.description }),
325
+ /* @__PURE__ */ jsxs("p", { className: "mt-6 flex items-baseline gap-x-1", children: [
326
+ /* @__PURE__ */ jsx("span", { className: "text-4xl font-bold tracking-tight text-zinc-900 dark:text-white", children: tier.price ?? "—" }),
327
+ tier.period && /* @__PURE__ */ jsx("span", { className: "text-sm text-zinc-600 dark:text-zinc-400", children: tier.period })
328
+ ] })
329
+ ] }),
330
+ /* @__PURE__ */ jsx("ul", { className: "mb-8 space-y-3", children: tier.features.map((feature) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-x-3", children: [
331
+ /* @__PURE__ */ jsx(CheckIcon, {}),
332
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-zinc-600 dark:text-zinc-400", children: feature })
333
+ ] }, feature)) }),
334
+ onSelect ? /* @__PURE__ */ jsx(
335
+ "button",
336
+ {
337
+ type: "button",
338
+ onClick: () => onSelect(tier.id),
339
+ disabled: isCurrent,
340
+ className: cn(
341
+ "block w-full rounded-md px-6 py-3 text-center text-sm font-semibold transition-colors",
342
+ 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"
343
+ ),
344
+ children: isCurrent ? "Current Plan" : tier.cta
345
+ }
346
+ ) : /* @__PURE__ */ jsx(
347
+ "a",
348
+ {
349
+ href: tier.ctaHref,
350
+ className: cn(
351
+ "block w-full rounded-md px-6 py-3 text-center text-sm font-semibold transition-colors",
352
+ 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"
353
+ ),
354
+ children: tier.cta
355
+ }
356
+ )
357
+ ]
358
+ }
359
+ );
360
+ }
361
+ function PricingCardCompact({
362
+ tier,
363
+ isCurrent,
364
+ onSelect
365
+ }) {
366
+ return /* @__PURE__ */ jsxs(
367
+ "div",
368
+ {
369
+ className: cn(
370
+ "flex-1 rounded-xl p-5 shadow-sm dark:bg-zinc-900",
371
+ 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"
372
+ ),
373
+ children: [
374
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [
375
+ /* @__PURE__ */ jsx("h4", { className: "text-sm font-bold text-zinc-900 dark:text-white", children: tier.name }),
376
+ isCurrent && /* @__PURE__ */ jsx("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", children: "Current" })
377
+ ] }),
378
+ /* @__PURE__ */ jsxs("p", { className: "mt-1 flex items-baseline gap-x-1", children: [
379
+ /* @__PURE__ */ jsx("span", { className: "text-2xl font-bold text-zinc-900 dark:text-white", children: tier.price ?? "—" }),
380
+ tier.period && /* @__PURE__ */ jsx("span", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: tier.period })
381
+ ] }),
382
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-zinc-500 dark:text-zinc-400 line-clamp-2", children: tier.description }),
383
+ onSelect ? /* @__PURE__ */ jsx(
384
+ "button",
385
+ {
386
+ type: "button",
387
+ onClick: () => onSelect(tier.id),
388
+ disabled: isCurrent,
389
+ className: cn(
390
+ "mt-3 block w-full rounded-md px-3 py-2 text-center text-xs font-semibold transition-colors",
391
+ 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"
392
+ ),
393
+ children: isCurrent ? "Current" : tier.cta
394
+ }
395
+ ) : /* @__PURE__ */ jsx(
396
+ "a",
397
+ {
398
+ href: tier.ctaHref,
399
+ className: cn(
400
+ "mt-3 block w-full rounded-md px-3 py-2 text-center text-xs font-semibold transition-colors",
401
+ 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"
402
+ ),
403
+ children: tier.cta
404
+ }
405
+ )
406
+ ]
407
+ }
408
+ );
409
+ }
410
+ function Box({ as: Component = "div", className, ref, ...props }) {
411
+ return /* @__PURE__ */ jsx(Component, { ref, className: cn(className), ...props });
412
+ }
413
+ export {
414
+ Box as B,
415
+ Pagination as P,
416
+ Slot as S,
417
+ Button as a,
418
+ PaginationContent as b,
419
+ PaginationEllipsis as c,
420
+ PaginationItem as d,
421
+ PaginationLink as e,
422
+ PaginationNext as f,
423
+ PaginationPrevious as g,
424
+ PricingTable as h,
425
+ buttonVariants as i,
426
+ cn as j,
427
+ cva as k,
428
+ clsx as l
429
+ };
430
+ //# sourceMappingURL=Box-DC3F8eRf.js.map