@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.
Files changed (44) hide show
  1. package/README.md +51 -30
  2. package/dist/{button-B2DR7obe.d.mts → button-DUQJ0X7e.d.mts} +0 -23
  3. package/dist/{button-B2DR7obe.d.ts → button-DUQJ0X7e.d.ts} +0 -23
  4. package/dist/chunk-7UGPCRZ6.mjs +130 -0
  5. package/dist/chunk-CWW36RYE.js +59 -0
  6. package/dist/chunk-JOVJRQO3.js +0 -1
  7. package/dist/{chunk-O3CFRMDK.js → chunk-OYH6LQWR.js} +33 -65
  8. package/dist/{chunk-QEKYM3BT.mjs → chunk-QWLQV6FS.mjs} +3 -25
  9. package/dist/chunk-S26666D6.mjs +0 -1
  10. package/dist/chunk-VQQ6MF5I.js +161 -0
  11. package/dist/chunk-W53NTFPB.mjs +28 -0
  12. package/dist/dialog-CwyBJeNl.d.mts +22 -0
  13. package/dist/dialog-CwyBJeNl.d.ts +22 -0
  14. package/dist/entries/calendar.d.mts +13 -0
  15. package/dist/entries/calendar.d.ts +13 -0
  16. package/dist/entries/calendar.js +211 -0
  17. package/dist/entries/calendar.mjs +188 -0
  18. package/dist/entries/carousel.d.mts +1 -1
  19. package/dist/entries/carousel.d.ts +1 -1
  20. package/dist/entries/carousel.js +5 -3
  21. package/dist/entries/carousel.mjs +3 -1
  22. package/dist/entries/chart.js +1 -0
  23. package/dist/entries/chart.mjs +1 -0
  24. package/dist/entries/command.d.mts +21 -0
  25. package/dist/entries/command.d.ts +21 -0
  26. package/dist/entries/command.js +172 -0
  27. package/dist/entries/command.mjs +162 -0
  28. package/dist/entries/drawer.d.mts +16 -0
  29. package/dist/entries/drawer.d.ts +16 -0
  30. package/dist/entries/drawer.js +124 -0
  31. package/dist/entries/drawer.mjs +113 -0
  32. package/dist/entries/input-otp.d.mts +14 -0
  33. package/dist/entries/input-otp.d.ts +14 -0
  34. package/dist/entries/input-otp.js +89 -0
  35. package/dist/entries/input-otp.mjs +64 -0
  36. package/dist/entries/resizable.d.mts +10 -0
  37. package/dist/entries/resizable.d.ts +10 -0
  38. package/dist/entries/resizable.js +69 -0
  39. package/dist/entries/resizable.mjs +45 -0
  40. package/dist/index.d.mts +12 -103
  41. package/dist/index.d.ts +12 -103
  42. package/dist/index.js +1265 -832
  43. package/dist/index.mjs +1172 -740
  44. 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 (per-component)
61
-
62
- These peers are only needed if you import the matching components.
63
- `peerDependenciesMeta.optional` is set, so package managers won't warn if you
64
- skip them.
65
-
66
- | Component(s) | Install |
67
- | ------------------------- | -------------------------------------------------------- |
68
- | `Form` + resolvers | `react-hook-form@^7`, `@hookform/resolvers@^5`, `zod@^4` |
69
- | `Toast` (`Toaster`) | `sonner@^2` |
70
- | `Drawer` | `vaul@^1` |
71
- | `Calendar` | `react-day-picker@^9`, `date-fns@^4` |
72
- | `Resizable` | `react-resizable-panels@^4` |
73
-
74
- ### Subpath imports (heavy peers install only when used)
75
-
76
- | Subpath | Install |
77
- | ------------------------ | -------------------------------- |
78
- | `@saasflare/ui/chart` | `recharts@^3` (~95 KB gzip) |
79
- | `@saasflare/ui/carousel` | `embla-carousel-react@^8` (~25 KB) |
80
-
81
- These two components are deliberately **not** in the main barrel — importing
82
- them through their subpath keeps the heavy peer out of consumers who don't use
83
- them.
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
- For chart/carousel:
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/carousel` | Carousel primitives (requires `embla-carousel-react`) |
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` (Chart and Carousel are
243
- *not* here — see Subpath imports above) — full list and live examples in
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;
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  'use strict';
3
2
 
4
3
  var clsx = require('clsx');
@@ -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 QUERY = "(prefers-reduced-motion: reduce)";
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 = React.useContext(AnimationContext);
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
- React.useEffect(() => {
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 = React.useRef(initialValue);
165
- const optionsRef = React.useRef(options);
142
+ const initialRef = react.useRef(initialValue);
143
+ const optionsRef = react.useRef(options);
166
144
  optionsRef.current = options;
167
- const serialize = React.useCallback(
145
+ const serialize = react.useCallback(
168
146
  (value) => (optionsRef.current?.serializer ?? JSON.stringify)(value),
169
147
  []
170
148
  );
171
- const deserialize = React.useCallback(
149
+ const deserialize = react.useCallback(
172
150
  (raw) => (optionsRef.current?.deserializer ?? JSON.parse)(raw),
173
151
  []
174
152
  );
175
- const handleError = React.useCallback(
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 = React.useCallback(() => {
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] = React.useState(() => readValue());
196
- const setValue = React.useCallback(
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 = React.useCallback(() => {
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
- React.useEffect(() => {
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
- React.useEffect(() => {
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 = React.createContext(DEFAULT_CONTEXT);
231
+ var SaasflareThemeContext = react.createContext(DEFAULT_CONTEXT);
254
232
  function useSaasflareTheme() {
255
- return React.useContext(SaasflareThemeContext);
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
- React.useEffect(() => {
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 = React.useCallback(
315
+ const setPalette = react.useCallback(
338
316
  (id) => setPersisted((prev) => ({ ...prev, palette: id })),
339
317
  [setPersisted]
340
318
  );
341
- const setSurface = React.useCallback(
319
+ const setSurface = react.useCallback(
342
320
  (style) => setPersisted((prev) => ({ ...prev, surface: style })),
343
321
  [setPersisted]
344
322
  );
345
- const setRadius = React.useCallback(
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
- React.useEffect(() => {
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 = React.useContext(AnimationContext);
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, fadeIn, noMotion, scaleIn, slideDown, slideUp, spring, springBouncy, springGentle, springStiff, useAnimation, useReducedMotion, useSaasflareProps, useSaasflareTheme };
528
+ export { Button, SaasflareProvider, SaasflareScript, SaasflareShell, SmoothScrollProvider, buttonVariants, useAnimation, useSaasflareProps, useSaasflareTheme };