@saasflare/ui 1.0.0 → 1.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.
@@ -0,0 +1,590 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var chunkJOVJRQO3_js = require('./chunk-JOVJRQO3.js');
5
+ var React = require('react');
6
+ var classVarianceAuthority = require('class-variance-authority');
7
+ var jsxRuntime = require('react/jsx-runtime');
8
+ var nextThemes = require('next-themes');
9
+ var framerMotion = require('framer-motion');
10
+ var lucideReact = require('lucide-react');
11
+ var Slot = require('@radix-ui/react-slot');
12
+
13
+ function _interopNamespace(e) {
14
+ if (e && e.__esModule) return e;
15
+ var n = Object.create(null);
16
+ if (e) {
17
+ Object.keys(e).forEach(function (k) {
18
+ if (k !== 'default') {
19
+ var d = Object.getOwnPropertyDescriptor(e, k);
20
+ Object.defineProperty(n, k, d.get ? d : {
21
+ enumerable: true,
22
+ get: function () { return e[k]; }
23
+ });
24
+ }
25
+ });
26
+ }
27
+ n.default = e;
28
+ return Object.freeze(n);
29
+ }
30
+
31
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
32
+ var Slot__namespace = /*#__PURE__*/_interopNamespace(Slot);
33
+
34
+ // src/lib/color.ts
35
+ function hexToOklch(hex) {
36
+ const normalized = normalizeHex(hex);
37
+ if (!normalized) return null;
38
+ const r = srgbToLinear(parseInt(normalized.slice(0, 2), 16) / 255);
39
+ const g = srgbToLinear(parseInt(normalized.slice(2, 4), 16) / 255);
40
+ const b = srgbToLinear(parseInt(normalized.slice(4, 6), 16) / 255);
41
+ const l_ = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
42
+ const m_ = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
43
+ const s_ = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
44
+ const lc = Math.cbrt(l_);
45
+ const mc = Math.cbrt(m_);
46
+ const sc = Math.cbrt(s_);
47
+ const L = 0.2104542553 * lc + 0.793617785 * mc - 0.0040720468 * sc;
48
+ const a = 1.9779984951 * lc - 2.428592205 * mc + 0.4505937099 * sc;
49
+ const b2 = 0.0259040371 * lc + 0.7827717662 * mc - 0.808675766 * sc;
50
+ const c = Math.sqrt(a * a + b2 * b2);
51
+ let h = Math.atan2(b2, a) * 180 / Math.PI;
52
+ if (h < 0) h += 360;
53
+ return { l: L, c, h };
54
+ }
55
+ function normalizeHex(input) {
56
+ if (typeof input !== "string") return null;
57
+ const s = input.trim().replace(/^#/, "").toLowerCase();
58
+ if (/^[0-9a-f]{3}$/.test(s)) {
59
+ return s[0] + s[0] + s[1] + s[1] + s[2] + s[2];
60
+ }
61
+ if (/^[0-9a-f]{4}$/.test(s)) {
62
+ return s[0] + s[0] + s[1] + s[1] + s[2] + s[2];
63
+ }
64
+ if (/^[0-9a-f]{6}$/.test(s)) {
65
+ return s;
66
+ }
67
+ if (/^[0-9a-f]{8}$/.test(s)) {
68
+ return s.slice(0, 6);
69
+ }
70
+ return null;
71
+ }
72
+ function srgbToLinear(c) {
73
+ return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
74
+ }
75
+ function isHex(input) {
76
+ return typeof input === "string" && /^#?[0-9a-f]{3,8}$/i.test(input.trim());
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(
101
+ void 0
102
+ );
103
+ function useAnimation() {
104
+ const context = React.useContext(AnimationContext);
105
+ const prefersReduced = useReducedMotion();
106
+ if (context) return context;
107
+ return { animated: !prefersReduced };
108
+ }
109
+ function SmoothScrollProvider({
110
+ children,
111
+ enabled = true
112
+ }) {
113
+ const reduced = useReducedMotion();
114
+ const shouldSmooth = enabled && !reduced;
115
+ React.useEffect(() => {
116
+ if (!shouldSmooth) return;
117
+ const html = document.documentElement;
118
+ const previous = html.style.scrollBehavior;
119
+ html.style.scrollBehavior = "smooth";
120
+ return () => {
121
+ html.style.scrollBehavior = previous;
122
+ };
123
+ }, [shouldSmooth]);
124
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
125
+ }
126
+
127
+ // src/lib/constants.ts
128
+ var UI_PREFS_STORAGE_KEY = "sf-ui-prefs";
129
+ var THEME_STORAGE_KEY = "theme";
130
+ var SAASFLARE_DATA_ATTR = {
131
+ /** Active brand palette id (matches `:root[data-palette="…"]` in palettes.css). */
132
+ palette: "data-palette",
133
+ /** Active surface style (matches `[data-style="…"]` in surfaces.css). */
134
+ style: "data-style",
135
+ /** Active radius preset (matches `:root[data-radius="…"]` in theme.css). */
136
+ radius: "data-radius",
137
+ /** Animation kill-switch (matches `[data-animated="false"]` in motion.css). */
138
+ animated: "data-animated"
139
+ };
140
+ function encode(value) {
141
+ return JSON.stringify(value ?? null).replace(/</g, "\\u003c");
142
+ }
143
+ function buildSaasflareScript(palette, surface, radius, animated, storageKey = UI_PREFS_STORAGE_KEY) {
144
+ return buildScript(palette, surface, radius, animated, storageKey);
145
+ }
146
+ function buildScript(palette, surface, radius, animated, storageKey) {
147
+ const forcePalette = palette || null;
148
+ const forceSurface = surface || null;
149
+ const forceRadius = radius || null;
150
+ const forceAnimated = typeof animated === "boolean" ? animated : null;
151
+ return `(function(){try{var r=document.documentElement;var p={};try{p=JSON.parse(localStorage.getItem(${encode(storageKey)})||"{}")||{}}catch(_){}var t=${encode(forcePalette)};if(t===null&&typeof p.palette==="string")t=p.palette;if(typeof t==="string"&&t.length)r.setAttribute(${encode(SAASFLARE_DATA_ATTR.palette)},t);var s=${encode(forceSurface)};if(s===null&&typeof p.surface==="string")s=p.surface;if(typeof s==="string"&&s.length)r.setAttribute(${encode(SAASFLARE_DATA_ATTR.style)},s);var d=${encode(forceRadius)};if(d===null&&typeof p.radius==="string")d=p.radius;if(typeof d==="string"&&d.length)r.setAttribute(${encode(SAASFLARE_DATA_ATTR.radius)},d);var a=${encode(forceAnimated)};if(a===null&&typeof p.animated==="boolean")a=p.animated;if(typeof a==="boolean")r.setAttribute(${encode(SAASFLARE_DATA_ATTR.animated)},String(a));}catch(e){}})();`;
152
+ }
153
+ function SaasflareScript({ nonce, palette, surface, radius, animated, storageKey = UI_PREFS_STORAGE_KEY }) {
154
+ return /* @__PURE__ */ jsxRuntime.jsx(
155
+ "script",
156
+ {
157
+ nonce,
158
+ dangerouslySetInnerHTML: { __html: buildScript(palette, surface, radius, animated, storageKey) }
159
+ }
160
+ );
161
+ }
162
+ var SYNC_PREFIX = "sf-ls:";
163
+ function useLocalStorage(key, initialValue, options) {
164
+ const initialRef = React.useRef(initialValue);
165
+ const optionsRef = React.useRef(options);
166
+ optionsRef.current = options;
167
+ const serialize = React.useCallback(
168
+ (value) => (optionsRef.current?.serializer ?? JSON.stringify)(value),
169
+ []
170
+ );
171
+ const deserialize = React.useCallback(
172
+ (raw) => (optionsRef.current?.deserializer ?? JSON.parse)(raw),
173
+ []
174
+ );
175
+ const handleError = React.useCallback(
176
+ (error, operation) => {
177
+ if (optionsRef.current?.onError) {
178
+ optionsRef.current.onError(error, operation);
179
+ } else {
180
+ console.warn(`useLocalStorage: ${operation} failed for "${key}"`, error);
181
+ }
182
+ },
183
+ [key]
184
+ );
185
+ const readValue = React.useCallback(() => {
186
+ if (typeof window === "undefined") return initialRef.current;
187
+ try {
188
+ const item = window.localStorage.getItem(key);
189
+ return item !== null ? deserialize(item) : initialRef.current;
190
+ } catch (error) {
191
+ handleError(error, "read");
192
+ return initialRef.current;
193
+ }
194
+ }, [key, deserialize, handleError]);
195
+ const [storedValue, setStoredValue] = React.useState(() => readValue());
196
+ const setValue = React.useCallback(
197
+ (value) => {
198
+ try {
199
+ setStoredValue((prev) => {
200
+ const next = typeof value === "function" ? value(prev) : value;
201
+ if (typeof window !== "undefined") {
202
+ window.localStorage.setItem(key, serialize(next));
203
+ window.dispatchEvent(new CustomEvent(`${SYNC_PREFIX}${key}`));
204
+ }
205
+ return next;
206
+ });
207
+ } catch (error) {
208
+ handleError(error, "write");
209
+ }
210
+ },
211
+ [key, serialize, handleError]
212
+ );
213
+ const removeValue = React.useCallback(() => {
214
+ try {
215
+ if (typeof window !== "undefined") {
216
+ window.localStorage.removeItem(key);
217
+ window.dispatchEvent(new CustomEvent(`${SYNC_PREFIX}${key}`));
218
+ }
219
+ setStoredValue(initialRef.current);
220
+ } catch (error) {
221
+ handleError(error, "remove");
222
+ }
223
+ }, [key, handleError]);
224
+ React.useEffect(() => {
225
+ const onStorage = (e) => {
226
+ if (e.key === key) setStoredValue(readValue());
227
+ };
228
+ const onSync = () => setStoredValue(readValue());
229
+ const syncEvent = `${SYNC_PREFIX}${key}`;
230
+ window.addEventListener("storage", onStorage);
231
+ window.addEventListener(syncEvent, onSync);
232
+ return () => {
233
+ window.removeEventListener("storage", onStorage);
234
+ window.removeEventListener(syncEvent, onSync);
235
+ };
236
+ }, [key, readValue]);
237
+ React.useEffect(() => {
238
+ setStoredValue(readValue());
239
+ }, [readValue]);
240
+ return [storedValue, setValue, removeValue];
241
+ }
242
+ var DEFAULT_CONTEXT = {
243
+ palette: null,
244
+ surface: "flat",
245
+ radius: "rounded",
246
+ setPalette: () => {
247
+ },
248
+ setSurface: () => {
249
+ },
250
+ setRadius: () => {
251
+ }
252
+ };
253
+ var SaasflareThemeContext = React.createContext(DEFAULT_CONTEXT);
254
+ function useSaasflareTheme() {
255
+ return React.useContext(SaasflareThemeContext);
256
+ }
257
+ function applyColorAxis(root, prefix, value, injected) {
258
+ if (isHex(value)) {
259
+ const oklch = hexToOklch(value);
260
+ if (oklch) {
261
+ const hKey = `--${prefix}-h`;
262
+ const cKey = `--${prefix}-c`;
263
+ const lKey = `--${prefix}-l`;
264
+ root.style.setProperty(hKey, oklch.h.toFixed(2));
265
+ root.style.setProperty(cKey, oklch.c.toFixed(4));
266
+ if (prefix === "primary") {
267
+ root.style.setProperty(lKey, oklch.l.toFixed(4));
268
+ injected.push(lKey);
269
+ }
270
+ injected.push(hKey, cKey);
271
+ return;
272
+ }
273
+ }
274
+ const key = `--${prefix}`;
275
+ root.style.setProperty(key, value);
276
+ injected.push(key);
277
+ }
278
+ function CustomPaletteInjector({ palette }) {
279
+ const { resolvedTheme } = nextThemes.useTheme();
280
+ React.useEffect(() => {
281
+ const root = document.documentElement;
282
+ const injected = [];
283
+ applyColorAxis(root, "primary", palette.primary, injected);
284
+ if (palette.neutral) {
285
+ applyColorAxis(root, "neutral", palette.neutral, injected);
286
+ }
287
+ if (palette.radius) {
288
+ root.style.setProperty("--radius", palette.radius);
289
+ injected.push("--radius");
290
+ }
291
+ const extras = resolvedTheme === "dark" ? palette.dark : palette.light;
292
+ if (extras) {
293
+ for (const [key, value] of Object.entries(extras)) {
294
+ root.style.setProperty(key, value);
295
+ injected.push(key);
296
+ }
297
+ }
298
+ return () => {
299
+ for (const key of injected) {
300
+ root.style.removeProperty(key);
301
+ }
302
+ };
303
+ }, [resolvedTheme, palette]);
304
+ return null;
305
+ }
306
+ var PERSISTED_DEFAULTS = {
307
+ palette: null,
308
+ surface: null,
309
+ radius: null,
310
+ animated: null
311
+ };
312
+ function SaasflareProvider({
313
+ children,
314
+ theme = "system",
315
+ palette,
316
+ surface,
317
+ radius,
318
+ animated = true,
319
+ smoothScrolling = false,
320
+ disableScript = false,
321
+ scriptNonce,
322
+ storageKey = UI_PREFS_STORAGE_KEY,
323
+ themeStorageKey = THEME_STORAGE_KEY
324
+ }) {
325
+ const isCustomPalette = typeof palette === "object";
326
+ const scriptPalette = !isCustomPalette && typeof palette === "string" ? palette : void 0;
327
+ const scriptSurface = typeof surface === "string" ? surface : void 0;
328
+ const scriptRadius = typeof radius === "string" ? radius : void 0;
329
+ const scriptHtml = disableScript ? null : buildSaasflareScript(scriptPalette, scriptSurface, scriptRadius, animated, storageKey);
330
+ const [persisted, setPersisted] = useLocalStorage(
331
+ storageKey,
332
+ PERSISTED_DEFAULTS
333
+ );
334
+ const currentPalette = isCustomPalette ? palette.name : palette ?? persisted.palette;
335
+ const currentStyle = surface ?? persisted.surface ?? "flat";
336
+ const currentRadius = radius ?? persisted.radius ?? "rounded";
337
+ const setPalette = React.useCallback(
338
+ (id) => setPersisted((prev) => ({ ...prev, palette: id })),
339
+ [setPersisted]
340
+ );
341
+ const setSurface = React.useCallback(
342
+ (style) => setPersisted((prev) => ({ ...prev, surface: style })),
343
+ [setPersisted]
344
+ );
345
+ const setRadius = React.useCallback(
346
+ (r) => setPersisted((prev) => ({ ...prev, radius: r })),
347
+ [setPersisted]
348
+ );
349
+ const prefersReduced = useReducedMotion();
350
+ const effectiveAnimated = animated && !prefersReduced;
351
+ React.useEffect(() => {
352
+ const root = document.documentElement;
353
+ if (currentPalette) {
354
+ root.setAttribute(SAASFLARE_DATA_ATTR.palette, currentPalette);
355
+ } else {
356
+ root.removeAttribute(SAASFLARE_DATA_ATTR.palette);
357
+ }
358
+ root.setAttribute(SAASFLARE_DATA_ATTR.style, currentStyle);
359
+ root.setAttribute(SAASFLARE_DATA_ATTR.radius, currentRadius);
360
+ root.setAttribute(SAASFLARE_DATA_ATTR.animated, String(effectiveAnimated));
361
+ }, [currentPalette, currentStyle, currentRadius, effectiveAnimated]);
362
+ return /* @__PURE__ */ jsxRuntime.jsx(framerMotion.LazyMotion, { features: framerMotion.domAnimation, strict: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
363
+ nextThemes.ThemeProvider,
364
+ {
365
+ attribute: "class",
366
+ defaultTheme: theme,
367
+ enableSystem: theme === "system",
368
+ storageKey: themeStorageKey,
369
+ disableTransitionOnChange: true,
370
+ children: [
371
+ scriptHtml !== null && /* @__PURE__ */ jsxRuntime.jsx(
372
+ "script",
373
+ {
374
+ nonce: scriptNonce,
375
+ dangerouslySetInnerHTML: { __html: scriptHtml }
376
+ }
377
+ ),
378
+ /* @__PURE__ */ jsxRuntime.jsx(
379
+ SaasflareThemeContext.Provider,
380
+ {
381
+ value: {
382
+ palette: currentPalette,
383
+ surface: currentStyle,
384
+ radius: currentRadius,
385
+ setPalette,
386
+ setSurface,
387
+ setRadius
388
+ },
389
+ children: /* @__PURE__ */ jsxRuntime.jsxs(AnimationContext.Provider, { value: { animated: effectiveAnimated }, children: [
390
+ isCustomPalette && /* @__PURE__ */ jsxRuntime.jsx(CustomPaletteInjector, { palette }),
391
+ /* @__PURE__ */ jsxRuntime.jsx(SmoothScrollProvider, { enabled: smoothScrolling, children })
392
+ ] })
393
+ }
394
+ )
395
+ ]
396
+ }
397
+ ) });
398
+ }
399
+ function SaasflareShell({
400
+ children,
401
+ lang = "en",
402
+ className,
403
+ bodyClassName,
404
+ head,
405
+ palette,
406
+ surface,
407
+ radius,
408
+ animated,
409
+ theme,
410
+ smoothScrolling,
411
+ storageKey,
412
+ themeStorageKey
413
+ }) {
414
+ const dataPalette = typeof palette === "object" ? palette.name : palette;
415
+ const dataAnimated = typeof animated === "boolean" ? String(animated) : void 0;
416
+ return /* @__PURE__ */ jsxRuntime.jsxs(
417
+ "html",
418
+ {
419
+ lang,
420
+ className,
421
+ suppressHydrationWarning: true,
422
+ "data-palette": dataPalette,
423
+ "data-style": surface,
424
+ "data-radius": radius,
425
+ "data-animated": dataAnimated,
426
+ children: [
427
+ head ? /* @__PURE__ */ jsxRuntime.jsx("head", { children: head }) : null,
428
+ /* @__PURE__ */ jsxRuntime.jsx("body", { className: bodyClassName, children: /* @__PURE__ */ jsxRuntime.jsx(
429
+ SaasflareProvider,
430
+ {
431
+ palette,
432
+ surface,
433
+ radius,
434
+ animated,
435
+ theme,
436
+ smoothScrolling,
437
+ storageKey,
438
+ themeStorageKey,
439
+ disableScript: true,
440
+ children
441
+ }
442
+ ) })
443
+ ]
444
+ }
445
+ );
446
+ }
447
+ function useSaasflareProps(props = {}) {
448
+ const ctx = useSaasflareTheme();
449
+ const anim = React.useContext(AnimationContext);
450
+ return {
451
+ surface: props.surface ?? ctx.surface,
452
+ radius: props.radius ?? ctx.radius,
453
+ animated: props.animated ?? anim?.animated ?? true,
454
+ palette: ctx.palette
455
+ };
456
+ }
457
+ var MotionSlot = framerMotion.m.create(Slot__namespace.Root);
458
+ var LEGACY_VARIANT_MAP = {
459
+ default: { variant: "solid", intent: "primary" },
460
+ destructive: { variant: "solid", intent: "danger" },
461
+ secondary: { variant: "soft", intent: "neutral" }
462
+ };
463
+ var buttonVariants = classVarianceAuthority.cva(
464
+ "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
465
+ {
466
+ variants: {
467
+ variant: {
468
+ solid: "bg-[var(--intent)] text-[var(--intent-fg)] shadow-xs hover:brightness-110 dark:hover:brightness-125",
469
+ soft: "bg-[var(--intent)]/15 text-[var(--intent)] hover:bg-[var(--intent)]/25 dark:bg-[var(--intent)]/20 dark:hover:bg-[var(--intent)]/30",
470
+ outline: "border border-[var(--intent)]/30 text-[var(--intent)] shadow-xs hover:bg-[var(--intent)]/10 dark:border-[var(--intent)]/40 dark:hover:bg-[var(--intent)]/15",
471
+ ghost: "text-[var(--intent)] hover:bg-[var(--intent)]/10 dark:hover:bg-[var(--intent)]/15",
472
+ link: "text-[var(--intent)] underline-offset-4 hover:underline",
473
+ glass: "bg-[var(--glass-bg)] text-[var(--intent)] border border-[var(--glass-border)] backdrop-blur-lg shadow-[var(--glass-shadow)] hover:bg-[var(--glass-bg-hover)] hover:border-[var(--glass-border-hover)]",
474
+ shadow: "bg-[var(--intent)] text-[var(--intent-fg)] shadow-[var(--btn-shadow)] hover:shadow-[var(--btn-shadow-hover)] hover:brightness-110 dark:hover:brightness-125"
475
+ },
476
+ size: {
477
+ xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
478
+ sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
479
+ md: "h-9 px-4 py-2 has-[>svg]:px-3",
480
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
481
+ xl: "h-12 rounded-lg px-8 text-base has-[>svg]:px-5 [&_svg:not([class*='size-'])]:size-5",
482
+ icon: "size-9",
483
+ "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
484
+ "icon-sm": "size-8",
485
+ "icon-lg": "size-10"
486
+ }
487
+ },
488
+ defaultVariants: {
489
+ variant: "solid",
490
+ size: "md"
491
+ }
492
+ }
493
+ );
494
+ function Button({
495
+ className,
496
+ variant: variantProp,
497
+ size = "md",
498
+ intent: intentProp = "primary",
499
+ asChild = false,
500
+ loading = false,
501
+ fullWidth = false,
502
+ surface,
503
+ animated,
504
+ disabled,
505
+ children,
506
+ ...props
507
+ }) {
508
+ const sfProps = useSaasflareProps({ surface, animated });
509
+ const reduced = useReducedMotion();
510
+ const effectiveVariant = variantProp ?? (sfProps.surface === "glass" ? "glass" : "solid");
511
+ let resolvedVariant = effectiveVariant;
512
+ let resolvedIntent = intentProp;
513
+ const legacy = LEGACY_VARIANT_MAP[effectiveVariant];
514
+ if (legacy) {
515
+ resolvedVariant = legacy.variant;
516
+ if (legacy.intent) {
517
+ resolvedIntent = legacy.intent;
518
+ }
519
+ }
520
+ const motionDisabled = !sfProps.animated || reduced || disabled || loading;
521
+ const transition = !sfProps.animated || reduced ? noMotion : spring;
522
+ if (asChild) {
523
+ return /* @__PURE__ */ jsxRuntime.jsx(
524
+ MotionSlot,
525
+ {
526
+ "data-slot": "button",
527
+ "data-variant": resolvedVariant,
528
+ "data-intent": resolvedIntent,
529
+ "data-size": size,
530
+ "data-surface": sfProps.surface,
531
+ whileHover: motionDisabled ? void 0 : { scale: 1.02 },
532
+ whileTap: motionDisabled ? void 0 : { scale: 0.97 },
533
+ transition,
534
+ className: chunkJOVJRQO3_js.cn(
535
+ buttonVariants({ variant: resolvedVariant, size }),
536
+ fullWidth && "w-full",
537
+ className
538
+ ),
539
+ ...props,
540
+ children
541
+ }
542
+ );
543
+ }
544
+ return /* @__PURE__ */ jsxRuntime.jsxs(
545
+ framerMotion.m.button,
546
+ {
547
+ "data-slot": "button",
548
+ "data-variant": resolvedVariant,
549
+ "data-intent": resolvedIntent,
550
+ "data-size": size,
551
+ "data-surface": sfProps.surface,
552
+ whileHover: motionDisabled ? void 0 : { scale: 1.02 },
553
+ whileTap: motionDisabled ? void 0 : { scale: 0.97 },
554
+ transition,
555
+ className: chunkJOVJRQO3_js.cn(
556
+ buttonVariants({ variant: resolvedVariant, size }),
557
+ fullWidth && "w-full",
558
+ className
559
+ ),
560
+ disabled,
561
+ "aria-busy": loading || void 0,
562
+ "aria-disabled": disabled || void 0,
563
+ ...props,
564
+ children: [
565
+ loading && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2Icon, { className: "animate-spin", "aria-hidden": "true" }),
566
+ children
567
+ ]
568
+ }
569
+ );
570
+ }
571
+
572
+ exports.Button = Button;
573
+ exports.SaasflareProvider = SaasflareProvider;
574
+ exports.SaasflareScript = SaasflareScript;
575
+ exports.SaasflareShell = SaasflareShell;
576
+ exports.SmoothScrollProvider = SmoothScrollProvider;
577
+ 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
+ exports.useAnimation = useAnimation;
588
+ exports.useReducedMotion = useReducedMotion;
589
+ exports.useSaasflareProps = useSaasflareProps;
590
+ exports.useSaasflareTheme = useSaasflareTheme;
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var clsx = require('clsx');
5
+ var tailwindMerge = require('tailwind-merge');
6
+ require('react');
7
+
8
+ // src/lib/utils.ts
9
+ function cn(...inputs) {
10
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
11
+ }
12
+
13
+ exports.cn = cn;