@saasflare/ui 1.1.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -30
- package/dist/{button-B2DR7obe.d.mts → button-DUQJ0X7e.d.mts} +0 -23
- package/dist/{button-B2DR7obe.d.ts → button-DUQJ0X7e.d.ts} +0 -23
- package/dist/chunk-7UGPCRZ6.mjs +130 -0
- package/dist/chunk-CWW36RYE.js +59 -0
- package/dist/chunk-JOVJRQO3.js +0 -1
- package/dist/{chunk-O3CFRMDK.js → chunk-OYH6LQWR.js} +33 -65
- package/dist/{chunk-QEKYM3BT.mjs → chunk-QWLQV6FS.mjs} +3 -25
- package/dist/chunk-S26666D6.mjs +0 -1
- package/dist/chunk-VQQ6MF5I.js +161 -0
- package/dist/chunk-W53NTFPB.mjs +28 -0
- package/dist/dialog-CwyBJeNl.d.mts +22 -0
- package/dist/dialog-CwyBJeNl.d.ts +22 -0
- package/dist/entries/calendar.d.mts +13 -0
- package/dist/entries/calendar.d.ts +13 -0
- package/dist/entries/calendar.js +211 -0
- package/dist/entries/calendar.mjs +188 -0
- package/dist/entries/carousel.d.mts +1 -1
- package/dist/entries/carousel.d.ts +1 -1
- package/dist/entries/carousel.js +5 -3
- package/dist/entries/carousel.mjs +3 -1
- package/dist/entries/chart.js +1 -0
- package/dist/entries/chart.mjs +1 -0
- package/dist/entries/command.d.mts +21 -0
- package/dist/entries/command.d.ts +21 -0
- package/dist/entries/command.js +172 -0
- package/dist/entries/command.mjs +162 -0
- package/dist/entries/drawer.d.mts +16 -0
- package/dist/entries/drawer.d.ts +16 -0
- package/dist/entries/drawer.js +124 -0
- package/dist/entries/drawer.mjs +113 -0
- package/dist/entries/input-otp.d.mts +14 -0
- package/dist/entries/input-otp.d.ts +14 -0
- package/dist/entries/input-otp.js +89 -0
- package/dist/entries/input-otp.mjs +64 -0
- package/dist/entries/resizable.d.mts +10 -0
- package/dist/entries/resizable.d.ts +10 -0
- package/dist/entries/resizable.js +69 -0
- package/dist/entries/resizable.mjs +45 -0
- package/dist/index.d.mts +12 -103
- package/dist/index.d.ts +12 -103
- package/dist/index.js +1265 -832
- package/dist/index.mjs +1172 -740
- package/package.json +66 -21
package/README.md
CHANGED
|
@@ -57,30 +57,41 @@ pnpm add react react-dom next next-themes framer-motion
|
|
|
57
57
|
`tailwindcss` is **not** a peer dependency — it's a build-time tool. Install it
|
|
58
58
|
in your app and add a `@source` directive (see Setup below).
|
|
59
59
|
|
|
60
|
-
### Optional (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
`
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
|
68
|
-
|
|
|
69
|
-
| `
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
60
|
+
### Optional (in main barrel — tree-shake-friendly)
|
|
61
|
+
|
|
62
|
+
`Form` lives in the main barrel because `react-hook-form` declares
|
|
63
|
+
`"sideEffects": false`, so consumer bundlers reliably eliminate the import when
|
|
64
|
+
`Form` is unused. Install only if you use it. `peerDependenciesMeta.optional`
|
|
65
|
+
is set, so package managers won't warn if you skip it.
|
|
66
|
+
|
|
67
|
+
| Component | Install |
|
|
68
|
+
| ------------------ | -------------------------------------------------------- |
|
|
69
|
+
| `Form` + resolvers | `react-hook-form@^7`, `@hookform/resolvers@^5`, `zod@^4` |
|
|
70
|
+
|
|
71
|
+
### Bundled (no install required)
|
|
72
|
+
|
|
73
|
+
`Toaster` (sonner-based toast notifications) is bundled directly into
|
|
74
|
+
`@saasflare/ui` — no separate `sonner` install needed. Sonner injects ~6 KB
|
|
75
|
+
of toast CSS into the document at module load, which adds ~13 KB gzip to the
|
|
76
|
+
main barrel for all consumers, including those who don't render `<Toaster />`.
|
|
77
|
+
We accepted this trade-off because Toaster usage is >80 % across the Saasflare
|
|
78
|
+
codebase and consumers; the extra-import friction was worse than the byte cost.
|
|
79
|
+
|
|
80
|
+
### Subpath imports (heavy, low-frequency, or non-tree-shakeable peers)
|
|
81
|
+
|
|
82
|
+
These components are **not in the main barrel** — import them via their
|
|
83
|
+
subpath. This keeps the peer (and its side-effects, e.g. CSS injection) out of
|
|
84
|
+
consumers who don't use the component.
|
|
85
|
+
|
|
86
|
+
| Subpath | Install | Notes |
|
|
87
|
+
| -------------------------- | ---------------------------------------- | ---------------------------------------- |
|
|
88
|
+
| `@saasflare/ui/chart` | `recharts@^3` | ~95 KB gzip peer |
|
|
89
|
+
| `@saasflare/ui/carousel` | `embla-carousel-react@^8` | ~25 KB peer |
|
|
90
|
+
| `@saasflare/ui/calendar` | `react-day-picker@^9`, `date-fns@^4` | ~30 KB peer combined |
|
|
91
|
+
| `@saasflare/ui/drawer` | `vaul@^1` | Mobile drawer / bottom sheet |
|
|
92
|
+
| `@saasflare/ui/command` | (no extra install — `cmdk` bundled) | Full Command palette / cmdk-based modal |
|
|
93
|
+
| `@saasflare/ui/input-otp` | `input-otp@^1` | OTP / 2FA input |
|
|
94
|
+
| `@saasflare/ui/resizable` | `react-resizable-panels@^4` | Split-view panels |
|
|
84
95
|
|
|
85
96
|
---
|
|
86
97
|
|
|
@@ -152,11 +163,16 @@ export function Example() {
|
|
|
152
163
|
}
|
|
153
164
|
```
|
|
154
165
|
|
|
155
|
-
|
|
166
|
+
Components with heavy or low-frequency peers ship as subpaths:
|
|
156
167
|
|
|
157
168
|
```tsx
|
|
158
169
|
import { ChartContainer, ChartTooltip } from "@saasflare/ui/chart";
|
|
159
170
|
import { Carousel, CarouselContent, CarouselItem } from "@saasflare/ui/carousel";
|
|
171
|
+
import { Calendar } from "@saasflare/ui/calendar";
|
|
172
|
+
import { Drawer, DrawerContent, DrawerTrigger } from "@saasflare/ui/drawer";
|
|
173
|
+
import { Command, CommandInput, CommandList } from "@saasflare/ui/command";
|
|
174
|
+
import { InputOTP, InputOTPGroup, InputOTPSlot } from "@saasflare/ui/input-otp";
|
|
175
|
+
import { ResizablePanel, ResizablePanelGroup } from "@saasflare/ui/resizable";
|
|
160
176
|
```
|
|
161
177
|
|
|
162
178
|
---
|
|
@@ -215,9 +231,14 @@ the design system pick them up automatically.
|
|
|
215
231
|
|
|
216
232
|
| Path | What it is |
|
|
217
233
|
| --------------------------------- | ------------------------------------------------------------------- |
|
|
218
|
-
| `@saasflare/ui` | Core: components, hooks, providers, utilities
|
|
234
|
+
| `@saasflare/ui` | Core: components, hooks, providers, utilities (incl. Form, Toaster) |
|
|
235
|
+
| `@saasflare/ui/calendar` | Calendar (requires `react-day-picker`, `date-fns`) |
|
|
236
|
+
| `@saasflare/ui/carousel` | Carousel (requires `embla-carousel-react`) |
|
|
219
237
|
| `@saasflare/ui/chart` | Chart primitives (requires `recharts`) |
|
|
220
|
-
| `@saasflare/ui/
|
|
238
|
+
| `@saasflare/ui/command` | Command palette / cmdk modal |
|
|
239
|
+
| `@saasflare/ui/drawer` | Mobile drawer (requires `vaul`) |
|
|
240
|
+
| `@saasflare/ui/input-otp` | OTP input (requires `input-otp`) |
|
|
241
|
+
| `@saasflare/ui/resizable` | Resizable panels (requires `react-resizable-panels`) |
|
|
221
242
|
| `@saasflare/ui/styles` | Full CSS bundle (alias for `globals.css`) |
|
|
222
243
|
| `@saasflare/ui/globals.css` | Same as above, explicit |
|
|
223
244
|
| `@saasflare/ui/theme.css` | Token root only (advanced use) |
|
|
@@ -239,9 +260,9 @@ the design system pick them up automatically.
|
|
|
239
260
|
`Density`, …)
|
|
240
261
|
- **Composed widgets:** `ScrollToTopButton`, `ThemeModeToggle`,
|
|
241
262
|
`TopLoadingBar`, `UserAvatar`
|
|
242
|
-
- **All core UI primitives** from `components/ui` (
|
|
243
|
-
*not* here — see Subpath imports
|
|
244
|
-
the [catalog](https://ui.saasflare.io).
|
|
263
|
+
- **All core UI primitives** from `components/ui` (Calendar, Carousel, Chart,
|
|
264
|
+
Command, Drawer, InputOTP, and Resizable are *not* here — see Subpath imports
|
|
265
|
+
above) — full list and live examples in the [catalog](https://ui.saasflare.io).
|
|
245
266
|
|
|
246
267
|
---
|
|
247
268
|
|
|
@@ -181,29 +181,6 @@ type Surface = StyleVariant;
|
|
|
181
181
|
*/
|
|
182
182
|
type RadiusProp = Radius;
|
|
183
183
|
|
|
184
|
-
/**
|
|
185
|
-
* @fileoverview Base props and resolver hook for Saasflare components.
|
|
186
|
-
* @module packages/ui/providers/use-saasflare-props
|
|
187
|
-
* @package ui
|
|
188
|
-
*
|
|
189
|
-
* Every Saasflare component MUST:
|
|
190
|
-
* 1. Extend SaasflareComponentProps in its props interface
|
|
191
|
-
* 2. Call useSaasflareProps(props) to resolve effective values
|
|
192
|
-
*
|
|
193
|
-
* This ensures consistent precedence:
|
|
194
|
-
* component prop > provider context > hardcoded defaults
|
|
195
|
-
*
|
|
196
|
-
* @example
|
|
197
|
-
* interface CardProps extends SaasflareComponentProps {
|
|
198
|
-
* title: string
|
|
199
|
-
* }
|
|
200
|
-
*
|
|
201
|
-
* function Card({ title, ...sfProps }: CardProps) {
|
|
202
|
-
* const { surface, radius, animated } = useSaasflareProps(sfProps)
|
|
203
|
-
* // surface/radius are guaranteed to be resolved, never undefined
|
|
204
|
-
* }
|
|
205
|
-
*/
|
|
206
|
-
|
|
207
184
|
/** Props that every Saasflare component accepts for theme integration. */
|
|
208
185
|
interface SaasflareComponentProps {
|
|
209
186
|
/** Surface style override. Omit to inherit from provider. */
|
|
@@ -181,29 +181,6 @@ type Surface = StyleVariant;
|
|
|
181
181
|
*/
|
|
182
182
|
type RadiusProp = Radius;
|
|
183
183
|
|
|
184
|
-
/**
|
|
185
|
-
* @fileoverview Base props and resolver hook for Saasflare components.
|
|
186
|
-
* @module packages/ui/providers/use-saasflare-props
|
|
187
|
-
* @package ui
|
|
188
|
-
*
|
|
189
|
-
* Every Saasflare component MUST:
|
|
190
|
-
* 1. Extend SaasflareComponentProps in its props interface
|
|
191
|
-
* 2. Call useSaasflareProps(props) to resolve effective values
|
|
192
|
-
*
|
|
193
|
-
* This ensures consistent precedence:
|
|
194
|
-
* component prop > provider context > hardcoded defaults
|
|
195
|
-
*
|
|
196
|
-
* @example
|
|
197
|
-
* interface CardProps extends SaasflareComponentProps {
|
|
198
|
-
* title: string
|
|
199
|
-
* }
|
|
200
|
-
*
|
|
201
|
-
* function Card({ title, ...sfProps }: CardProps) {
|
|
202
|
-
* const { surface, radius, animated } = useSaasflareProps(sfProps)
|
|
203
|
-
* // surface/radius are guaranteed to be resolved, never undefined
|
|
204
|
-
* }
|
|
205
|
-
*/
|
|
206
|
-
|
|
207
184
|
/** Props that every Saasflare component accepts for theme integration. */
|
|
208
185
|
interface SaasflareComponentProps {
|
|
209
186
|
/** Surface style override. Omit to inherit from provider. */
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useReducedMotion, noMotion, springBouncy } from './chunk-W53NTFPB.mjs';
|
|
3
|
+
import { cn } from './chunk-S26666D6.mjs';
|
|
4
|
+
import { m } from 'motion/react';
|
|
5
|
+
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
6
|
+
import { XIcon } from 'lucide-react';
|
|
7
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
8
|
+
|
|
9
|
+
function Dialog({
|
|
10
|
+
...props
|
|
11
|
+
}) {
|
|
12
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
13
|
+
}
|
|
14
|
+
function DialogTrigger({
|
|
15
|
+
...props
|
|
16
|
+
}) {
|
|
17
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Trigger, { "data-slot": "dialog-trigger", ...props });
|
|
18
|
+
}
|
|
19
|
+
function DialogPortal({
|
|
20
|
+
...props
|
|
21
|
+
}) {
|
|
22
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props });
|
|
23
|
+
}
|
|
24
|
+
function DialogClose({
|
|
25
|
+
...props
|
|
26
|
+
}) {
|
|
27
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Close, { "data-slot": "dialog-close", ...props });
|
|
28
|
+
}
|
|
29
|
+
function DialogOverlay({
|
|
30
|
+
className,
|
|
31
|
+
...props
|
|
32
|
+
}) {
|
|
33
|
+
return /* @__PURE__ */ jsx(
|
|
34
|
+
DialogPrimitive.Overlay,
|
|
35
|
+
{
|
|
36
|
+
"data-slot": "dialog-overlay",
|
|
37
|
+
className: cn(
|
|
38
|
+
"fixed inset-0 z-50 bg-black/50 backdrop-blur-[2px] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
39
|
+
className
|
|
40
|
+
),
|
|
41
|
+
...props
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
function DialogContent({
|
|
46
|
+
className,
|
|
47
|
+
children,
|
|
48
|
+
...props
|
|
49
|
+
}) {
|
|
50
|
+
const reduced = useReducedMotion();
|
|
51
|
+
return /* @__PURE__ */ jsxs(DialogPortal, { children: [
|
|
52
|
+
/* @__PURE__ */ jsx(DialogOverlay, {}),
|
|
53
|
+
/* @__PURE__ */ jsx(
|
|
54
|
+
DialogPrimitive.Content,
|
|
55
|
+
{
|
|
56
|
+
"data-slot": "dialog-content",
|
|
57
|
+
asChild: true,
|
|
58
|
+
...props,
|
|
59
|
+
children: /* @__PURE__ */ jsxs(
|
|
60
|
+
m.div,
|
|
61
|
+
{
|
|
62
|
+
initial: reduced ? { opacity: 1 } : { opacity: 0, scale: 0.95, y: 10 },
|
|
63
|
+
animate: { opacity: 1, scale: 1, y: 0 },
|
|
64
|
+
exit: reduced ? { opacity: 0 } : { opacity: 0, scale: 0.95, y: 10 },
|
|
65
|
+
transition: reduced ? noMotion : springBouncy,
|
|
66
|
+
className: cn(
|
|
67
|
+
"fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg sm:max-w-lg",
|
|
68
|
+
className
|
|
69
|
+
),
|
|
70
|
+
children: [
|
|
71
|
+
children,
|
|
72
|
+
/* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none cursor-pointer [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", children: [
|
|
73
|
+
/* @__PURE__ */ jsx(XIcon, {}),
|
|
74
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
|
|
75
|
+
] })
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
] });
|
|
82
|
+
}
|
|
83
|
+
function DialogHeader({ className, ...props }) {
|
|
84
|
+
return /* @__PURE__ */ jsx(
|
|
85
|
+
"div",
|
|
86
|
+
{
|
|
87
|
+
"data-slot": "dialog-header",
|
|
88
|
+
className: cn("flex flex-col gap-2 text-center sm:text-left", className),
|
|
89
|
+
...props
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
function DialogFooter({ className, ...props }) {
|
|
94
|
+
return /* @__PURE__ */ jsx(
|
|
95
|
+
"div",
|
|
96
|
+
{
|
|
97
|
+
"data-slot": "dialog-footer",
|
|
98
|
+
className: cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className),
|
|
99
|
+
...props
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
function DialogTitle({
|
|
104
|
+
className,
|
|
105
|
+
...props
|
|
106
|
+
}) {
|
|
107
|
+
return /* @__PURE__ */ jsx(
|
|
108
|
+
DialogPrimitive.Title,
|
|
109
|
+
{
|
|
110
|
+
"data-slot": "dialog-title",
|
|
111
|
+
className: cn("text-lg leading-none font-semibold", className),
|
|
112
|
+
...props
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
function DialogDescription({
|
|
117
|
+
className,
|
|
118
|
+
...props
|
|
119
|
+
}) {
|
|
120
|
+
return /* @__PURE__ */ jsx(
|
|
121
|
+
DialogPrimitive.Description,
|
|
122
|
+
{
|
|
123
|
+
"data-slot": "dialog-description",
|
|
124
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
125
|
+
...props
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var React = require('react');
|
|
5
|
+
|
|
6
|
+
function _interopNamespace(e) {
|
|
7
|
+
if (e && e.__esModule) return e;
|
|
8
|
+
var n = Object.create(null);
|
|
9
|
+
if (e) {
|
|
10
|
+
Object.keys(e).forEach(function (k) {
|
|
11
|
+
if (k !== 'default') {
|
|
12
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
13
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function () { return e[k]; }
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
n.default = e;
|
|
21
|
+
return Object.freeze(n);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
25
|
+
|
|
26
|
+
// src/hooks/use-reduced-motion.ts
|
|
27
|
+
var QUERY = "(prefers-reduced-motion: reduce)";
|
|
28
|
+
var subscribe = (cb) => {
|
|
29
|
+
const mql = window.matchMedia(QUERY);
|
|
30
|
+
mql.addEventListener("change", cb);
|
|
31
|
+
return () => mql.removeEventListener("change", cb);
|
|
32
|
+
};
|
|
33
|
+
var getSnapshot = () => window.matchMedia(QUERY).matches;
|
|
34
|
+
var getServerSnapshot = () => false;
|
|
35
|
+
function useReducedMotion() {
|
|
36
|
+
return React__namespace.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/components/ui/motion-config.ts
|
|
40
|
+
var spring = { type: "spring", stiffness: 400, damping: 25 };
|
|
41
|
+
var springBouncy = { type: "spring", stiffness: 300, damping: 15 };
|
|
42
|
+
var springGentle = { type: "spring", stiffness: 200, damping: 20 };
|
|
43
|
+
var springStiff = { type: "spring", stiffness: 500, damping: 30 };
|
|
44
|
+
var noMotion = { duration: 0 };
|
|
45
|
+
var fadeIn = { initial: { opacity: 0 }, animate: { opacity: 1 } };
|
|
46
|
+
var scaleIn = { initial: { opacity: 0, scale: 0.95 }, animate: { opacity: 1, scale: 1 } };
|
|
47
|
+
var slideUp = { initial: { opacity: 0, y: 8 }, animate: { opacity: 1, y: 0 } };
|
|
48
|
+
var slideDown = { initial: { opacity: 0, y: -8 }, animate: { opacity: 1, y: 0 } };
|
|
49
|
+
|
|
50
|
+
exports.fadeIn = fadeIn;
|
|
51
|
+
exports.noMotion = noMotion;
|
|
52
|
+
exports.scaleIn = scaleIn;
|
|
53
|
+
exports.slideDown = slideDown;
|
|
54
|
+
exports.slideUp = slideUp;
|
|
55
|
+
exports.spring = spring;
|
|
56
|
+
exports.springBouncy = springBouncy;
|
|
57
|
+
exports.springGentle = springGentle;
|
|
58
|
+
exports.springStiff = springStiff;
|
|
59
|
+
exports.useReducedMotion = useReducedMotion;
|
package/dist/chunk-JOVJRQO3.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
var chunkCWW36RYE_js = require('./chunk-CWW36RYE.js');
|
|
4
5
|
var chunkJOVJRQO3_js = require('./chunk-JOVJRQO3.js');
|
|
5
|
-
var React = require('react');
|
|
6
6
|
var classVarianceAuthority = require('class-variance-authority');
|
|
7
|
+
var react = require('react');
|
|
7
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
9
|
var nextThemes = require('next-themes');
|
|
9
|
-
var react = require('motion/react');
|
|
10
|
+
var react$1 = require('motion/react');
|
|
10
11
|
var lucideReact = require('lucide-react');
|
|
11
12
|
var Slot = require('@radix-ui/react-slot');
|
|
12
13
|
|
|
@@ -28,7 +29,6 @@ function _interopNamespace(e) {
|
|
|
28
29
|
return Object.freeze(n);
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
32
32
|
var Slot__namespace = /*#__PURE__*/_interopNamespace(Slot);
|
|
33
33
|
|
|
34
34
|
// src/lib/color.ts
|
|
@@ -75,34 +75,12 @@ function srgbToLinear(c) {
|
|
|
75
75
|
function isHex(input) {
|
|
76
76
|
return typeof input === "string" && /^#?[0-9a-f]{3,8}$/i.test(input.trim());
|
|
77
77
|
}
|
|
78
|
-
var
|
|
79
|
-
var subscribe = (cb) => {
|
|
80
|
-
const mql = window.matchMedia(QUERY);
|
|
81
|
-
mql.addEventListener("change", cb);
|
|
82
|
-
return () => mql.removeEventListener("change", cb);
|
|
83
|
-
};
|
|
84
|
-
var getSnapshot = () => window.matchMedia(QUERY).matches;
|
|
85
|
-
var getServerSnapshot = () => false;
|
|
86
|
-
function useReducedMotion() {
|
|
87
|
-
return React__namespace.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// src/components/ui/motion-config.ts
|
|
91
|
-
var spring = { type: "spring", stiffness: 400, damping: 25 };
|
|
92
|
-
var springBouncy = { type: "spring", stiffness: 300, damping: 15 };
|
|
93
|
-
var springGentle = { type: "spring", stiffness: 200, damping: 20 };
|
|
94
|
-
var springStiff = { type: "spring", stiffness: 500, damping: 30 };
|
|
95
|
-
var noMotion = { duration: 0 };
|
|
96
|
-
var fadeIn = { initial: { opacity: 0 }, animate: { opacity: 1 } };
|
|
97
|
-
var scaleIn = { initial: { opacity: 0, scale: 0.95 }, animate: { opacity: 1, scale: 1 } };
|
|
98
|
-
var slideUp = { initial: { opacity: 0, y: 8 }, animate: { opacity: 1, y: 0 } };
|
|
99
|
-
var slideDown = { initial: { opacity: 0, y: -8 }, animate: { opacity: 1, y: 0 } };
|
|
100
|
-
var AnimationContext = React.createContext(
|
|
78
|
+
var AnimationContext = react.createContext(
|
|
101
79
|
void 0
|
|
102
80
|
);
|
|
103
81
|
function useAnimation() {
|
|
104
|
-
const context =
|
|
105
|
-
const prefersReduced = useReducedMotion();
|
|
82
|
+
const context = react.useContext(AnimationContext);
|
|
83
|
+
const prefersReduced = chunkCWW36RYE_js.useReducedMotion();
|
|
106
84
|
if (context) return context;
|
|
107
85
|
return { animated: !prefersReduced };
|
|
108
86
|
}
|
|
@@ -110,9 +88,9 @@ function SmoothScrollProvider({
|
|
|
110
88
|
children,
|
|
111
89
|
enabled = true
|
|
112
90
|
}) {
|
|
113
|
-
const reduced = useReducedMotion();
|
|
91
|
+
const reduced = chunkCWW36RYE_js.useReducedMotion();
|
|
114
92
|
const shouldSmooth = enabled && !reduced;
|
|
115
|
-
|
|
93
|
+
react.useEffect(() => {
|
|
116
94
|
if (!shouldSmooth) return;
|
|
117
95
|
const html = document.documentElement;
|
|
118
96
|
const previous = html.style.scrollBehavior;
|
|
@@ -161,18 +139,18 @@ function SaasflareScript({ nonce, palette, surface, radius, animated, storageKey
|
|
|
161
139
|
}
|
|
162
140
|
var SYNC_PREFIX = "sf-ls:";
|
|
163
141
|
function useLocalStorage(key, initialValue, options) {
|
|
164
|
-
const initialRef =
|
|
165
|
-
const optionsRef =
|
|
142
|
+
const initialRef = react.useRef(initialValue);
|
|
143
|
+
const optionsRef = react.useRef(options);
|
|
166
144
|
optionsRef.current = options;
|
|
167
|
-
const serialize =
|
|
145
|
+
const serialize = react.useCallback(
|
|
168
146
|
(value) => (optionsRef.current?.serializer ?? JSON.stringify)(value),
|
|
169
147
|
[]
|
|
170
148
|
);
|
|
171
|
-
const deserialize =
|
|
149
|
+
const deserialize = react.useCallback(
|
|
172
150
|
(raw) => (optionsRef.current?.deserializer ?? JSON.parse)(raw),
|
|
173
151
|
[]
|
|
174
152
|
);
|
|
175
|
-
const handleError =
|
|
153
|
+
const handleError = react.useCallback(
|
|
176
154
|
(error, operation) => {
|
|
177
155
|
if (optionsRef.current?.onError) {
|
|
178
156
|
optionsRef.current.onError(error, operation);
|
|
@@ -182,7 +160,7 @@ function useLocalStorage(key, initialValue, options) {
|
|
|
182
160
|
},
|
|
183
161
|
[key]
|
|
184
162
|
);
|
|
185
|
-
const readValue =
|
|
163
|
+
const readValue = react.useCallback(() => {
|
|
186
164
|
if (typeof window === "undefined") return initialRef.current;
|
|
187
165
|
try {
|
|
188
166
|
const item = window.localStorage.getItem(key);
|
|
@@ -192,8 +170,8 @@ function useLocalStorage(key, initialValue, options) {
|
|
|
192
170
|
return initialRef.current;
|
|
193
171
|
}
|
|
194
172
|
}, [key, deserialize, handleError]);
|
|
195
|
-
const [storedValue, setStoredValue] =
|
|
196
|
-
const setValue =
|
|
173
|
+
const [storedValue, setStoredValue] = react.useState(() => readValue());
|
|
174
|
+
const setValue = react.useCallback(
|
|
197
175
|
(value) => {
|
|
198
176
|
try {
|
|
199
177
|
setStoredValue((prev) => {
|
|
@@ -210,7 +188,7 @@ function useLocalStorage(key, initialValue, options) {
|
|
|
210
188
|
},
|
|
211
189
|
[key, serialize, handleError]
|
|
212
190
|
);
|
|
213
|
-
const removeValue =
|
|
191
|
+
const removeValue = react.useCallback(() => {
|
|
214
192
|
try {
|
|
215
193
|
if (typeof window !== "undefined") {
|
|
216
194
|
window.localStorage.removeItem(key);
|
|
@@ -221,7 +199,7 @@ function useLocalStorage(key, initialValue, options) {
|
|
|
221
199
|
handleError(error, "remove");
|
|
222
200
|
}
|
|
223
201
|
}, [key, handleError]);
|
|
224
|
-
|
|
202
|
+
react.useEffect(() => {
|
|
225
203
|
const onStorage = (e) => {
|
|
226
204
|
if (e.key === key) setStoredValue(readValue());
|
|
227
205
|
};
|
|
@@ -234,7 +212,7 @@ function useLocalStorage(key, initialValue, options) {
|
|
|
234
212
|
window.removeEventListener(syncEvent, onSync);
|
|
235
213
|
};
|
|
236
214
|
}, [key, readValue]);
|
|
237
|
-
|
|
215
|
+
react.useEffect(() => {
|
|
238
216
|
setStoredValue(readValue());
|
|
239
217
|
}, [readValue]);
|
|
240
218
|
return [storedValue, setValue, removeValue];
|
|
@@ -250,9 +228,9 @@ var DEFAULT_CONTEXT = {
|
|
|
250
228
|
setRadius: () => {
|
|
251
229
|
}
|
|
252
230
|
};
|
|
253
|
-
var SaasflareThemeContext =
|
|
231
|
+
var SaasflareThemeContext = react.createContext(DEFAULT_CONTEXT);
|
|
254
232
|
function useSaasflareTheme() {
|
|
255
|
-
return
|
|
233
|
+
return react.useContext(SaasflareThemeContext);
|
|
256
234
|
}
|
|
257
235
|
function applyColorAxis(root, prefix, value, injected) {
|
|
258
236
|
if (isHex(value)) {
|
|
@@ -277,7 +255,7 @@ function applyColorAxis(root, prefix, value, injected) {
|
|
|
277
255
|
}
|
|
278
256
|
function CustomPaletteInjector({ palette }) {
|
|
279
257
|
const { resolvedTheme } = nextThemes.useTheme();
|
|
280
|
-
|
|
258
|
+
react.useEffect(() => {
|
|
281
259
|
const root = document.documentElement;
|
|
282
260
|
const injected = [];
|
|
283
261
|
applyColorAxis(root, "primary", palette.primary, injected);
|
|
@@ -334,21 +312,21 @@ function SaasflareProvider({
|
|
|
334
312
|
const currentPalette = isCustomPalette ? palette.name : palette ?? persisted.palette;
|
|
335
313
|
const currentStyle = surface ?? persisted.surface ?? "flat";
|
|
336
314
|
const currentRadius = radius ?? persisted.radius ?? "rounded";
|
|
337
|
-
const setPalette =
|
|
315
|
+
const setPalette = react.useCallback(
|
|
338
316
|
(id) => setPersisted((prev) => ({ ...prev, palette: id })),
|
|
339
317
|
[setPersisted]
|
|
340
318
|
);
|
|
341
|
-
const setSurface =
|
|
319
|
+
const setSurface = react.useCallback(
|
|
342
320
|
(style) => setPersisted((prev) => ({ ...prev, surface: style })),
|
|
343
321
|
[setPersisted]
|
|
344
322
|
);
|
|
345
|
-
const setRadius =
|
|
323
|
+
const setRadius = react.useCallback(
|
|
346
324
|
(r) => setPersisted((prev) => ({ ...prev, radius: r })),
|
|
347
325
|
[setPersisted]
|
|
348
326
|
);
|
|
349
|
-
const prefersReduced = useReducedMotion();
|
|
327
|
+
const prefersReduced = chunkCWW36RYE_js.useReducedMotion();
|
|
350
328
|
const effectiveAnimated = animated && !prefersReduced;
|
|
351
|
-
|
|
329
|
+
react.useEffect(() => {
|
|
352
330
|
const root = document.documentElement;
|
|
353
331
|
if (currentPalette) {
|
|
354
332
|
root.setAttribute(SAASFLARE_DATA_ATTR.palette, currentPalette);
|
|
@@ -359,7 +337,7 @@ function SaasflareProvider({
|
|
|
359
337
|
root.setAttribute(SAASFLARE_DATA_ATTR.radius, currentRadius);
|
|
360
338
|
root.setAttribute(SAASFLARE_DATA_ATTR.animated, String(effectiveAnimated));
|
|
361
339
|
}, [currentPalette, currentStyle, currentRadius, effectiveAnimated]);
|
|
362
|
-
return /* @__PURE__ */ jsxRuntime.jsx(react.LazyMotion, { features: react.domAnimation, strict: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
340
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react$1.LazyMotion, { features: react$1.domAnimation, strict: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
363
341
|
nextThemes.ThemeProvider,
|
|
364
342
|
{
|
|
365
343
|
attribute: "class",
|
|
@@ -446,7 +424,7 @@ function SaasflareShell({
|
|
|
446
424
|
}
|
|
447
425
|
function useSaasflareProps(props = {}) {
|
|
448
426
|
const ctx = useSaasflareTheme();
|
|
449
|
-
const anim =
|
|
427
|
+
const anim = react.useContext(AnimationContext);
|
|
450
428
|
return {
|
|
451
429
|
surface: props.surface ?? ctx.surface,
|
|
452
430
|
radius: props.radius ?? ctx.radius,
|
|
@@ -454,7 +432,7 @@ function useSaasflareProps(props = {}) {
|
|
|
454
432
|
palette: ctx.palette
|
|
455
433
|
};
|
|
456
434
|
}
|
|
457
|
-
var MotionSlot = react.m.create(Slot__namespace.Root);
|
|
435
|
+
var MotionSlot = react$1.m.create(Slot__namespace.Root);
|
|
458
436
|
var LEGACY_VARIANT_MAP = {
|
|
459
437
|
default: { variant: "solid", intent: "primary" },
|
|
460
438
|
destructive: { variant: "solid", intent: "danger" },
|
|
@@ -506,7 +484,7 @@ function Button({
|
|
|
506
484
|
...props
|
|
507
485
|
}) {
|
|
508
486
|
const sfProps = useSaasflareProps({ surface, animated });
|
|
509
|
-
const reduced = useReducedMotion();
|
|
487
|
+
const reduced = chunkCWW36RYE_js.useReducedMotion();
|
|
510
488
|
const effectiveVariant = variantProp ?? (sfProps.surface === "glass" ? "glass" : "solid");
|
|
511
489
|
let resolvedVariant = effectiveVariant;
|
|
512
490
|
let resolvedIntent = intentProp;
|
|
@@ -518,7 +496,7 @@ function Button({
|
|
|
518
496
|
}
|
|
519
497
|
}
|
|
520
498
|
const motionDisabled = !sfProps.animated || reduced || disabled || loading;
|
|
521
|
-
const transition = !sfProps.animated || reduced ? noMotion : spring;
|
|
499
|
+
const transition = !sfProps.animated || reduced ? chunkCWW36RYE_js.noMotion : chunkCWW36RYE_js.spring;
|
|
522
500
|
if (asChild) {
|
|
523
501
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
524
502
|
MotionSlot,
|
|
@@ -542,7 +520,7 @@ function Button({
|
|
|
542
520
|
);
|
|
543
521
|
}
|
|
544
522
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
545
|
-
react.m.button,
|
|
523
|
+
react$1.m.button,
|
|
546
524
|
{
|
|
547
525
|
"data-slot": "button",
|
|
548
526
|
"data-variant": resolvedVariant,
|
|
@@ -575,16 +553,6 @@ exports.SaasflareScript = SaasflareScript;
|
|
|
575
553
|
exports.SaasflareShell = SaasflareShell;
|
|
576
554
|
exports.SmoothScrollProvider = SmoothScrollProvider;
|
|
577
555
|
exports.buttonVariants = buttonVariants;
|
|
578
|
-
exports.fadeIn = fadeIn;
|
|
579
|
-
exports.noMotion = noMotion;
|
|
580
|
-
exports.scaleIn = scaleIn;
|
|
581
|
-
exports.slideDown = slideDown;
|
|
582
|
-
exports.slideUp = slideUp;
|
|
583
|
-
exports.spring = spring;
|
|
584
|
-
exports.springBouncy = springBouncy;
|
|
585
|
-
exports.springGentle = springGentle;
|
|
586
|
-
exports.springStiff = springStiff;
|
|
587
556
|
exports.useAnimation = useAnimation;
|
|
588
|
-
exports.useReducedMotion = useReducedMotion;
|
|
589
557
|
exports.useSaasflareProps = useSaasflareProps;
|
|
590
558
|
exports.useSaasflareTheme = useSaasflareTheme;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { useReducedMotion, noMotion, spring } from './chunk-W53NTFPB.mjs';
|
|
2
3
|
import { cn } from './chunk-S26666D6.mjs';
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
import { createContext, useContext, useEffect, useCallback, useRef, useState } from 'react';
|
|
5
4
|
import { cva } from 'class-variance-authority';
|
|
5
|
+
import { createContext, useContext, useEffect, useCallback, useRef, useState } from 'react';
|
|
6
6
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
7
7
|
import { ThemeProvider, useTheme } from 'next-themes';
|
|
8
8
|
import { m, LazyMotion, domAnimation } from 'motion/react';
|
|
@@ -53,28 +53,6 @@ function srgbToLinear(c) {
|
|
|
53
53
|
function isHex(input) {
|
|
54
54
|
return typeof input === "string" && /^#?[0-9a-f]{3,8}$/i.test(input.trim());
|
|
55
55
|
}
|
|
56
|
-
var QUERY = "(prefers-reduced-motion: reduce)";
|
|
57
|
-
var subscribe = (cb) => {
|
|
58
|
-
const mql = window.matchMedia(QUERY);
|
|
59
|
-
mql.addEventListener("change", cb);
|
|
60
|
-
return () => mql.removeEventListener("change", cb);
|
|
61
|
-
};
|
|
62
|
-
var getSnapshot = () => window.matchMedia(QUERY).matches;
|
|
63
|
-
var getServerSnapshot = () => false;
|
|
64
|
-
function useReducedMotion() {
|
|
65
|
-
return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// src/components/ui/motion-config.ts
|
|
69
|
-
var spring = { type: "spring", stiffness: 400, damping: 25 };
|
|
70
|
-
var springBouncy = { type: "spring", stiffness: 300, damping: 15 };
|
|
71
|
-
var springGentle = { type: "spring", stiffness: 200, damping: 20 };
|
|
72
|
-
var springStiff = { type: "spring", stiffness: 500, damping: 30 };
|
|
73
|
-
var noMotion = { duration: 0 };
|
|
74
|
-
var fadeIn = { initial: { opacity: 0 }, animate: { opacity: 1 } };
|
|
75
|
-
var scaleIn = { initial: { opacity: 0, scale: 0.95 }, animate: { opacity: 1, scale: 1 } };
|
|
76
|
-
var slideUp = { initial: { opacity: 0, y: 8 }, animate: { opacity: 1, y: 0 } };
|
|
77
|
-
var slideDown = { initial: { opacity: 0, y: -8 }, animate: { opacity: 1, y: 0 } };
|
|
78
56
|
var AnimationContext = createContext(
|
|
79
57
|
void 0
|
|
80
58
|
);
|
|
@@ -547,4 +525,4 @@ function Button({
|
|
|
547
525
|
);
|
|
548
526
|
}
|
|
549
527
|
|
|
550
|
-
export { Button, SaasflareProvider, SaasflareScript, SaasflareShell, SmoothScrollProvider, buttonVariants,
|
|
528
|
+
export { Button, SaasflareProvider, SaasflareScript, SaasflareShell, SmoothScrollProvider, buttonVariants, useAnimation, useSaasflareProps, useSaasflareTheme };
|