@opensite/ui 0.0.1

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 (75) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +315 -0
  3. package/dist/animated-dialog.cjs +168 -0
  4. package/dist/animated-dialog.cjs.map +1 -0
  5. package/dist/animated-dialog.d.cts +24 -0
  6. package/dist/animated-dialog.d.ts +24 -0
  7. package/dist/animated-dialog.js +166 -0
  8. package/dist/animated-dialog.js.map +1 -0
  9. package/dist/badge.cjs +49 -0
  10. package/dist/badge.cjs.map +1 -0
  11. package/dist/badge.d.cts +13 -0
  12. package/dist/badge.d.ts +13 -0
  13. package/dist/badge.js +46 -0
  14. package/dist/badge.js.map +1 -0
  15. package/dist/button.cjs +63 -0
  16. package/dist/button.cjs.map +1 -0
  17. package/dist/button.d.cts +14 -0
  18. package/dist/button.d.ts +14 -0
  19. package/dist/button.js +60 -0
  20. package/dist/button.js.map +1 -0
  21. package/dist/card.cjs +99 -0
  22. package/dist/card.cjs.map +1 -0
  23. package/dist/card.d.cts +12 -0
  24. package/dist/card.d.ts +12 -0
  25. package/dist/card.js +91 -0
  26. package/dist/card.js.map +1 -0
  27. package/dist/components.cjs +533 -0
  28. package/dist/components.cjs.map +1 -0
  29. package/dist/components.d.cts +14 -0
  30. package/dist/components.d.ts +14 -0
  31. package/dist/components.js +494 -0
  32. package/dist/components.js.map +1 -0
  33. package/dist/container.cjs +47 -0
  34. package/dist/container.cjs.map +1 -0
  35. package/dist/container.d.cts +16 -0
  36. package/dist/container.d.ts +16 -0
  37. package/dist/container.js +41 -0
  38. package/dist/container.js.map +1 -0
  39. package/dist/index.cjs +534 -0
  40. package/dist/index.cjs.map +1 -0
  41. package/dist/index.d.cts +16 -0
  42. package/dist/index.d.ts +16 -0
  43. package/dist/index.js +494 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/page-hero-banner.cjs +119 -0
  46. package/dist/page-hero-banner.cjs.map +1 -0
  47. package/dist/page-hero-banner.d.cts +22 -0
  48. package/dist/page-hero-banner.d.ts +22 -0
  49. package/dist/page-hero-banner.js +113 -0
  50. package/dist/page-hero-banner.js.map +1 -0
  51. package/dist/popover.cjs +73 -0
  52. package/dist/popover.cjs.map +1 -0
  53. package/dist/popover.d.cts +10 -0
  54. package/dist/popover.d.ts +10 -0
  55. package/dist/popover.js +48 -0
  56. package/dist/popover.js.map +1 -0
  57. package/dist/section.cjs +96 -0
  58. package/dist/section.cjs.map +1 -0
  59. package/dist/section.d.cts +21 -0
  60. package/dist/section.d.ts +21 -0
  61. package/dist/section.js +90 -0
  62. package/dist/section.js.map +1 -0
  63. package/dist/types.cjs +4 -0
  64. package/dist/types.cjs.map +1 -0
  65. package/dist/types.d.cts +180 -0
  66. package/dist/types.d.ts +180 -0
  67. package/dist/types.js +3 -0
  68. package/dist/types.js.map +1 -0
  69. package/dist/utils.cjs +13 -0
  70. package/dist/utils.cjs.map +1 -0
  71. package/dist/utils.d.cts +5 -0
  72. package/dist/utils.d.ts +5 -0
  73. package/dist/utils.js +11 -0
  74. package/dist/utils.js.map +1 -0
  75. package/package.json +152 -0
package/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2025, OpenSite AI. All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md ADDED
@@ -0,0 +1,315 @@
1
+ # @opensite/ui
2
+
3
+ Foundational UI component library for the OpenSite Semantic Site Builder ecosystem. Provides tree-shakable, performance-optimized components with abstract styling support.
4
+
5
+ ## Features
6
+
7
+ - 🎨 **Abstract Styling**: Components use CSS variables for full theme customization
8
+ - 📦 **Tree-Shakable**: Granular imports for optimal bundle sizes
9
+ - ⚡ **Performance First**: Optimized for Core Web Vitals (LCP ≤2.5s, INP ≤200ms, CLS ≤0.1)
10
+ - 🎯 **TypeScript**: Full type safety with strict mode
11
+ - 🧩 **shadcn/ui Compatible**: Built on shadcn/ui foundations with Tailwind CSS v4
12
+ - 🔧 **Flexible**: Support for both default Tailwind styles and custom semantic builder styles
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pnpm add @opensite/ui
18
+ # or
19
+ npm install @opensite/ui
20
+ ```
21
+
22
+ ### Peer Dependencies
23
+
24
+ This library requires React 16.8.0 or higher:
25
+
26
+ ```bash
27
+ pnpm add react react-dom
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ ### Tree-Shakable Imports (Recommended)
33
+
34
+ For optimal bundle sizes, import components individually:
35
+
36
+ ```tsx
37
+ // Import specific components
38
+ import { Container } from "@opensite/ui/components/container";
39
+ import { Section } from "@opensite/ui/components/section";
40
+
41
+ // Or import multiple from grouped export
42
+ import { Container, Section, Button } from "@opensite/ui/components";
43
+ ```
44
+
45
+ ### Full Import (Not Recommended)
46
+
47
+ ```tsx
48
+ // Import all (larger bundle)
49
+ import * as UI from "@opensite/ui";
50
+ ```
51
+
52
+ ## Components
53
+
54
+ ### Container
55
+
56
+ Layout container for consistent content width and centering.
57
+
58
+ ```tsx
59
+ import { Container } from "@opensite/ui/components/container";
60
+
61
+ <Container maxWidth="xl">
62
+ <h1>Page Content</h1>
63
+ </Container>
64
+ ```
65
+
66
+ **Props:**
67
+ - `maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl" | "4xl" | "full"` - Maximum width (default: "xl")
68
+ - `as?: keyof JSX.IntrinsicElements` - HTML element to render (default: "div")
69
+ - `className?: string` - Additional CSS classes
70
+ - All standard HTML attributes
71
+
72
+ ### Section
73
+
74
+ Section wrapper with optional title, subtitle, and background variants.
75
+
76
+ ```tsx
77
+ import { Section } from "@opensite/ui/components/section";
78
+
79
+ <Section
80
+ id="features"
81
+ title="Our Features"
82
+ subtitle="What we offer"
83
+ background="gradient"
84
+ spacing="lg"
85
+ >
86
+ <p>Section content here</p>
87
+ </Section>
88
+ ```
89
+
90
+ **Props:**
91
+ - `id?: string` - Section ID for anchor links
92
+ - `title?: string` - Section title (renders as h2)
93
+ - `subtitle?: string` - Section subtitle/eyebrow
94
+ - `background?: "white" | "gray" | "dark" | "gradient" | "primary" | "secondary" | "muted"` (default: "white")
95
+ - `spacing?: "sm" | "md" | "lg" | "xl"` (default: "lg")
96
+ - `className?: string` - Additional CSS classes
97
+ - All standard HTML attributes
98
+
99
+ ### AnimatedDialog
100
+
101
+ Animated modal dialog component using framer-motion.
102
+
103
+ ```tsx
104
+ import { AnimatedDialog } from "@opensite/ui/components/animated-dialog";
105
+ import { useState } from "react";
106
+
107
+ function MyComponent() {
108
+ const [open, setOpen] = useState(false);
109
+
110
+ return (
111
+ <AnimatedDialog
112
+ open={open}
113
+ onOpenChange={setOpen}
114
+ title="Welcome"
115
+ eyebrow="Hello"
116
+ description="This is a modal dialog"
117
+ size="lg"
118
+ footer={
119
+ <button onClick={() => setOpen(false)}>Close</button>
120
+ }
121
+ >
122
+ <p>Dialog content here</p>
123
+ </AnimatedDialog>
124
+ );
125
+ }
126
+ ```
127
+
128
+ **Props:**
129
+ - `open: boolean` - Whether the dialog is open (required)
130
+ - `onOpenChange: (open: boolean) => void` - Callback when dialog state changes (required)
131
+ - `title?: string` - Dialog title
132
+ - `eyebrow?: string` - Eyebrow text above title
133
+ - `description?: string` - Dialog description
134
+ - `header?: ReactNode` - Custom header (overrides title/eyebrow/description)
135
+ - `footer?: ReactNode` - Footer content
136
+ - `size?: "sm" | "md" | "lg" | "xl" | "full"` (default: "lg")
137
+ - `className?: string` - Additional CSS classes for container
138
+ - `contentClassName?: string` - Additional CSS classes for content area
139
+
140
+ ### PageHeroBanner
141
+
142
+ Hero banner component with image or video background support.
143
+
144
+ ```tsx
145
+ import { PageHeroBanner } from "@opensite/ui/components/page-hero-banner";
146
+
147
+ <PageHeroBanner
148
+ imageUrl="https://example.com/hero.jpg"
149
+ alt="Hero banner"
150
+ minHeight="600px"
151
+ showOverlay={true}
152
+ overlayOpacity={0.6}
153
+ contentMaxWidth="4xl"
154
+ >
155
+ <h1>Welcome to Our Site</h1>
156
+ <p>Discover amazing content</p>
157
+ </PageHeroBanner>
158
+ ```
159
+
160
+ **Props:**
161
+ - `imageUrl?: string` - Image URL or Media ID (either imageUrl or videoUrl required)
162
+ - `videoUrl?: string` - Video URL or Media ID (either imageUrl or videoUrl required)
163
+ - `alt?: string` - Alt text for image (default: "Hero banner")
164
+ - `loading?: "eager" | "lazy"` (default: "eager")
165
+ - `minHeight?: string` (default: "500px")
166
+ - `showOverlay?: boolean` (default: true)
167
+ - `overlayOpacity?: number` (default: 0.6)
168
+ - `contentMaxWidth?: ContainerMaxWidth` (default: "4xl")
169
+ - `className?: string` - Additional CSS classes
170
+ - All standard div attributes
171
+
172
+ ### shadcn/ui Components
173
+
174
+ Additional components from shadcn/ui are available:
175
+
176
+ ```tsx
177
+ import { Button } from "@opensite/ui/components/button";
178
+ import { Card, CardHeader, CardContent, CardFooter } from "@opensite/ui/components/card";
179
+ import { Badge } from "@opensite/ui/components/badge";
180
+ import { Popover, PopoverTrigger, PopoverContent } from "@opensite/ui/components/popover";
181
+ ```
182
+
183
+ ## Styling
184
+
185
+ ### CSS Variables
186
+
187
+ Components use CSS variables for theming. Define these in your global CSS:
188
+
189
+ ```css
190
+ :root {
191
+ --background: 0 0% 100%;
192
+ --foreground: 222.2 84% 4.9%;
193
+ --primary: 222.2 47.4% 11.2%;
194
+ --primary-foreground: 210 40% 98%;
195
+ --secondary: 210 40% 96.1%;
196
+ --secondary-foreground: 222.2 47.4% 11.2%;
197
+ --muted: 210 40% 96.1%;
198
+ --muted-foreground: 215.4 16.3% 46.9%;
199
+ /* ... more variables */
200
+ }
201
+ ```
202
+
203
+ ### Tailwind CSS Configuration
204
+
205
+ Ensure your `tailwind.config.js` includes the library components:
206
+
207
+ ```js
208
+ module.exports = {
209
+ content: [
210
+ "./src/**/*.{js,ts,jsx,tsx}",
211
+ "./node_modules/@opensite/ui/dist/**/*.{js,mjs}",
212
+ ],
213
+ theme: {
214
+ extend: {
215
+ // Your custom theme
216
+ },
217
+ },
218
+ };
219
+ ```
220
+
221
+ ### Custom Styling
222
+
223
+ Override component styles using the `className` prop:
224
+
225
+ ```tsx
226
+ <Container className="bg-blue-500 text-white px-8">
227
+ Custom styled container
228
+ </Container>
229
+ ```
230
+
231
+ ## TypeScript
232
+
233
+ Full TypeScript support with exported types:
234
+
235
+ ```tsx
236
+ import type {
237
+ ContainerProps,
238
+ ContainerMaxWidth,
239
+ SectionProps,
240
+ SectionBackground,
241
+ SectionSpacing,
242
+ AnimatedDialogProps,
243
+ PageHeroBannerProps,
244
+ } from "@opensite/ui/types";
245
+ ```
246
+
247
+ ## Performance
248
+
249
+ ### Bundle Sizes
250
+
251
+ - **Core Components**: ≤50KB gzipped
252
+ - **Individual Components**: Container (~1KB), Section (~2.5KB), AnimatedDialog (~5KB), PageHeroBanner (~3KB)
253
+
254
+ ### Core Web Vitals
255
+
256
+ All components are optimized for:
257
+ - **LCP** (Largest Contentful Paint): ≤2.5s
258
+ - **INP** (Interaction to Next Paint): ≤200ms
259
+ - **CLS** (Cumulative Layout Shift): ≤0.1
260
+
261
+ ### Tree-Shaking
262
+
263
+ The library is fully tree-shakable. Import only what you need:
264
+
265
+ ```tsx
266
+ // ✅ Good - Only imports Container (~1KB)
267
+ import { Container } from "@opensite/ui/components/container";
268
+
269
+ // ❌ Avoid - Imports everything (~50KB)
270
+ import * as UI from "@opensite/ui";
271
+ ```
272
+
273
+ ## Development
274
+
275
+ ### Building
276
+
277
+ ```bash
278
+ pnpm build
279
+ ```
280
+
281
+ ### Testing
282
+
283
+ ```bash
284
+ # Run tests
285
+ pnpm test
286
+
287
+ # Run tests in watch mode
288
+ pnpm test:watch
289
+
290
+ # Run tests with coverage
291
+ pnpm test -- --coverage
292
+ ```
293
+
294
+ ### Type Checking
295
+
296
+ ```bash
297
+ pnpm type-check
298
+ ```
299
+
300
+ ## Requirements
301
+
302
+ - **Node.js**: >=18.0.0
303
+ - **pnpm**: >=9.0.0
304
+ - **React**: >=16.8.0
305
+
306
+ ## License
307
+
308
+ MIT
309
+
310
+ ## Related Packages
311
+
312
+ - [@opensite/blocks](https://github.com/opensite-ai/opensite-blocks) - Ultra-lightweight React rendering runtime
313
+ - [@opensite/img](https://github.com/opensite-ai/opensite-img) - Performance-optimized image component
314
+ - [@opensite/video](https://github.com/opensite-ai/opensite-video) - Performance-optimized video component
315
+ - [@opensite/hooks](https://github.com/opensite-ai/opensite-hooks) - Custom React hooks library
@@ -0,0 +1,168 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var framerMotion = require('framer-motion');
5
+ var clsx = require('clsx');
6
+ var tailwindMerge = require('tailwind-merge');
7
+ var hooks = require('@opensite/hooks');
8
+ var jsxRuntime = require('react/jsx-runtime');
9
+
10
+ function cn(...inputs) {
11
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
12
+ }
13
+ var sizeStyles = {
14
+ sm: "max-w-md",
15
+ md: "max-w-2xl",
16
+ lg: "max-w-4xl",
17
+ xl: "max-w-5xl",
18
+ full: "max-w-7xl"
19
+ };
20
+ var dialogTransition = {
21
+ duration: 0.35,
22
+ ease: [0.16, 1, 0.3, 1]
23
+ };
24
+ function AnimatedDialog({
25
+ open,
26
+ onOpenChange,
27
+ title,
28
+ eyebrow,
29
+ description,
30
+ children,
31
+ header,
32
+ footer,
33
+ size = "lg",
34
+ className,
35
+ contentClassName
36
+ }) {
37
+ const titleId = react.useId();
38
+ const descriptionId = react.useId();
39
+ const containerRef = react.useRef(null);
40
+ hooks.useOnClickOutside(containerRef, () => {
41
+ if (open) {
42
+ onOpenChange(false);
43
+ }
44
+ });
45
+ react.useEffect(() => {
46
+ if (!open) {
47
+ return;
48
+ }
49
+ const onKeyDown = (event) => {
50
+ if (event.key === "Escape") {
51
+ onOpenChange(false);
52
+ }
53
+ };
54
+ const previousOverflow = document.body.style.overflow;
55
+ document.body.style.overflow = "hidden";
56
+ window.addEventListener("keydown", onKeyDown);
57
+ return () => {
58
+ document.body.style.overflow = previousOverflow;
59
+ window.removeEventListener("keydown", onKeyDown);
60
+ };
61
+ }, [open, onOpenChange]);
62
+ return /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: open ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50 h-screen overflow-y-auto", children: [
63
+ /* @__PURE__ */ jsxRuntime.jsx(
64
+ framerMotion.motion.div,
65
+ {
66
+ initial: { opacity: 0 },
67
+ animate: { opacity: 1, transition: dialogTransition },
68
+ exit: { opacity: 0, transition: dialogTransition },
69
+ className: "fixed inset-0 h-full w-full bg-foreground/80 backdrop-blur-lg"
70
+ }
71
+ ),
72
+ /* @__PURE__ */ jsxRuntime.jsxs(
73
+ framerMotion.motion.div,
74
+ {
75
+ initial: { opacity: 0, y: 24, scale: 0.98 },
76
+ animate: {
77
+ opacity: 1,
78
+ y: 0,
79
+ scale: 1,
80
+ transition: dialogTransition
81
+ },
82
+ exit: {
83
+ opacity: 0,
84
+ y: 12,
85
+ scale: 0.98,
86
+ transition: dialogTransition
87
+ },
88
+ ref: containerRef,
89
+ role: "dialog",
90
+ "aria-modal": "true",
91
+ "aria-labelledby": title ? titleId : void 0,
92
+ "aria-describedby": description ? descriptionId : void 0,
93
+ className: cn(
94
+ "relative z-[60] mx-auto my-10 flex w-[92vw] max-h-[85vh] flex-col overflow-hidden rounded-3xl bg-card p-4 shadow-2xl ring-1 ring-border/10 md:my-16 md:p-10",
95
+ sizeStyles[size],
96
+ className
97
+ ),
98
+ children: [
99
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-6", children: [
100
+ header ? header : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
101
+ eyebrow ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-[0.3em] text-primary", children: eyebrow }) : null,
102
+ title ? /* @__PURE__ */ jsxRuntime.jsx(
103
+ "h2",
104
+ {
105
+ id: titleId,
106
+ className: "text-2xl font-semibold text-card-foreground md:text-4xl",
107
+ children: title
108
+ }
109
+ ) : null,
110
+ description ? /* @__PURE__ */ jsxRuntime.jsx(
111
+ "p",
112
+ {
113
+ id: descriptionId,
114
+ className: "text-sm text-muted-foreground md:text-base",
115
+ children: description
116
+ }
117
+ ) : null
118
+ ] }),
119
+ /* @__PURE__ */ jsxRuntime.jsx(
120
+ "button",
121
+ {
122
+ type: "button",
123
+ "aria-label": "Close dialog",
124
+ className: "flex h-9 w-9 items-center justify-center rounded-full bg-foreground text-background transition hover:bg-foreground/80",
125
+ onClick: () => onOpenChange(false),
126
+ children: /* @__PURE__ */ jsxRuntime.jsx(
127
+ "svg",
128
+ {
129
+ xmlns: "http://www.w3.org/2000/svg",
130
+ width: "24",
131
+ height: "24",
132
+ viewBox: "0 0 24 24",
133
+ children: /* @__PURE__ */ jsxRuntime.jsx(
134
+ "path",
135
+ {
136
+ fill: "none",
137
+ stroke: "currentColor",
138
+ strokeLinecap: "round",
139
+ strokeLinejoin: "round",
140
+ strokeWidth: "2",
141
+ d: "M18 6L6 18M6 6l12 12"
142
+ }
143
+ )
144
+ }
145
+ )
146
+ }
147
+ )
148
+ ] }),
149
+ children ? /* @__PURE__ */ jsxRuntime.jsx(
150
+ "div",
151
+ {
152
+ className: cn(
153
+ "mt-6 flex-1 min-h-0 overflow-y-auto pr-2",
154
+ contentClassName
155
+ ),
156
+ children
157
+ }
158
+ ) : null,
159
+ footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-6", children: footer }) : null
160
+ ]
161
+ }
162
+ )
163
+ ] }) : null });
164
+ }
165
+
166
+ exports.AnimatedDialog = AnimatedDialog;
167
+ //# sourceMappingURL=animated-dialog.cjs.map
168
+ //# sourceMappingURL=animated-dialog.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../lib/utils.ts","../components/ui/animated-dialog.tsx"],"names":["twMerge","clsx","useId","useRef","useOnClickOutside","useEffect","AnimatePresence","jsxs","jsx","motion"],"mappings":"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","file":"animated-dialog.cjs","sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport React, { useEffect, useId, useRef } from \"react\";\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport { cn } from \"../../lib/utils\";\nimport { useOnClickOutside } from \"@opensite/hooks\";\nimport type { AnimatedDialogProps } from \"../../src/types\";\n\n/**\n * Size variants for the dialog\n */\nconst sizeStyles = {\n sm: \"max-w-md\",\n md: \"max-w-2xl\",\n lg: \"max-w-4xl\",\n xl: \"max-w-5xl\",\n full: \"max-w-7xl\",\n};\n\n/**\n * Animation transition configuration\n */\nconst dialogTransition = {\n duration: 0.35,\n ease: [0.16, 1, 0.3, 1] as const,\n};\n\n/**\n * Animated dialog component with framer-motion animations\n *\n * @example\n * ```tsx\n * const [open, setOpen] = useState(false);\n *\n * <AnimatedDialog\n * open={open}\n * onOpenChange={setOpen}\n * title=\"Dialog Title\"\n * description=\"Dialog description\"\n * >\n * <div>Dialog content</div>\n * </AnimatedDialog>\n * ```\n */\nexport function AnimatedDialog({\n open,\n onOpenChange,\n title,\n eyebrow,\n description,\n children,\n header,\n footer,\n size = \"lg\",\n className,\n contentClassName,\n}: AnimatedDialogProps) {\n const titleId = useId();\n const descriptionId = useId();\n const containerRef = useRef<HTMLDivElement>(null!);\n\n useOnClickOutside(containerRef, () => {\n if (open) {\n onOpenChange(false);\n }\n });\n\n useEffect(() => {\n if (!open) {\n return;\n }\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onOpenChange(false);\n }\n };\n\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n window.addEventListener(\"keydown\", onKeyDown);\n\n return () => {\n document.body.style.overflow = previousOverflow;\n window.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [open, onOpenChange]);\n\n return (\n <AnimatePresence>\n {open ? (\n <div className=\"fixed inset-0 z-50 h-screen overflow-y-auto\">\n {/* Backdrop */}\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1, transition: dialogTransition }}\n exit={{ opacity: 0, transition: dialogTransition }}\n className=\"fixed inset-0 h-full w-full bg-foreground/80 backdrop-blur-lg\"\n />\n\n {/* Dialog container */}\n <motion.div\n initial={{ opacity: 0, y: 24, scale: 0.98 }}\n animate={{\n opacity: 1,\n y: 0,\n scale: 1,\n transition: dialogTransition,\n }}\n exit={{\n opacity: 0,\n y: 12,\n scale: 0.98,\n transition: dialogTransition,\n }}\n ref={containerRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n aria-describedby={description ? descriptionId : undefined}\n className={cn(\n \"relative z-[60] mx-auto my-10 flex w-[92vw] max-h-[85vh] flex-col overflow-hidden rounded-3xl bg-card p-4 shadow-2xl ring-1 ring-border/10 md:my-16 md:p-10\",\n sizeStyles[size],\n className\n )}\n >\n {/* Header */}\n <div className=\"flex items-start justify-between gap-6\">\n {header ? (\n header\n ) : (\n <div className=\"space-y-3\">\n {eyebrow ? (\n <p className=\"text-xs font-semibold uppercase tracking-[0.3em] text-primary\">\n {eyebrow}\n </p>\n ) : null}\n {title ? (\n <h2\n id={titleId}\n className=\"text-2xl font-semibold text-card-foreground md:text-4xl\"\n >\n {title}\n </h2>\n ) : null}\n {description ? (\n <p\n id={descriptionId}\n className=\"text-sm text-muted-foreground md:text-base\"\n >\n {description}\n </p>\n ) : null}\n </div>\n )}\n\n {/* Close button */}\n <button\n type=\"button\"\n aria-label=\"Close dialog\"\n className=\"flex h-9 w-9 items-center justify-center rounded-full bg-foreground text-background transition hover:bg-foreground/80\"\n onClick={() => onOpenChange(false)}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n >\n <path\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n d=\"M18 6L6 18M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n\n {/* Content */}\n {children ? (\n <div\n className={cn(\n \"mt-6 flex-1 min-h-0 overflow-y-auto pr-2\",\n contentClassName\n )}\n >\n {children}\n </div>\n ) : null}\n\n {/* Footer */}\n {footer ? <div className=\"mt-6\">{footer}</div> : null}\n </motion.div>\n </div>\n ) : null}\n </AnimatePresence>\n );\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { AnimatedDialogProps } from './types.cjs';
3
+ import 'react';
4
+
5
+ /**
6
+ * Animated dialog component with framer-motion animations
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * const [open, setOpen] = useState(false);
11
+ *
12
+ * <AnimatedDialog
13
+ * open={open}
14
+ * onOpenChange={setOpen}
15
+ * title="Dialog Title"
16
+ * description="Dialog description"
17
+ * >
18
+ * <div>Dialog content</div>
19
+ * </AnimatedDialog>
20
+ * ```
21
+ */
22
+ declare function AnimatedDialog({ open, onOpenChange, title, eyebrow, description, children, header, footer, size, className, contentClassName, }: AnimatedDialogProps): react_jsx_runtime.JSX.Element;
23
+
24
+ export { AnimatedDialog };
@@ -0,0 +1,24 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { AnimatedDialogProps } from './types.js';
3
+ import 'react';
4
+
5
+ /**
6
+ * Animated dialog component with framer-motion animations
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * const [open, setOpen] = useState(false);
11
+ *
12
+ * <AnimatedDialog
13
+ * open={open}
14
+ * onOpenChange={setOpen}
15
+ * title="Dialog Title"
16
+ * description="Dialog description"
17
+ * >
18
+ * <div>Dialog content</div>
19
+ * </AnimatedDialog>
20
+ * ```
21
+ */
22
+ declare function AnimatedDialog({ open, onOpenChange, title, eyebrow, description, children, header, footer, size, className, contentClassName, }: AnimatedDialogProps): react_jsx_runtime.JSX.Element;
23
+
24
+ export { AnimatedDialog };