@memelabui/ui 0.3.0 → 0.4.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/dist/index.d.ts CHANGED
@@ -158,6 +158,7 @@ type ToggleProps = {
158
158
  checked: boolean;
159
159
  onChange: (checked: boolean) => void;
160
160
  disabled?: boolean;
161
+ busy?: boolean;
161
162
  label?: string;
162
163
  size?: ToggleSize;
163
164
  id?: string;
@@ -473,6 +474,56 @@ type ProgressBarProps = {
473
474
  };
474
475
  declare function ProgressBar({ value, max, variant, label, showValue, size, className, }: ProgressBarProps): react_jsx_runtime.JSX.Element;
475
476
 
477
+ type CooldownRingSize = 'sm' | 'md' | 'lg';
478
+ type CooldownRingProps = {
479
+ duration: number;
480
+ remaining: number;
481
+ onTick?: () => void;
482
+ onComplete?: () => void;
483
+ size?: CooldownRingSize;
484
+ className?: string;
485
+ };
486
+ declare function CooldownRing({ duration, remaining, size, className, }: CooldownRingProps): react_jsx_runtime.JSX.Element;
487
+
488
+ type StageProgressProps = {
489
+ stages: string[];
490
+ activeStage: number;
491
+ className?: string;
492
+ };
493
+ declare function StageProgress({ stages, activeStage, className }: StageProgressProps): react_jsx_runtime.JSX.Element;
494
+
495
+ type DotIndicatorProps = {
496
+ remaining: number;
497
+ max: number;
498
+ showLabel?: boolean;
499
+ labelFormat?: (remaining: number, max: number) => string;
500
+ className?: string;
501
+ };
502
+ declare function DotIndicator({ remaining, max, showLabel, labelFormat, className, }: DotIndicatorProps): react_jsx_runtime.JSX.Element;
503
+
504
+ type FilterPill = {
505
+ key: string;
506
+ label: string;
507
+ };
508
+ type ActiveFilterPillsProps = {
509
+ filters: FilterPill[];
510
+ onRemove: (key: string) => void;
511
+ onClearAll?: () => void;
512
+ clearAllLabel?: string;
513
+ className?: string;
514
+ };
515
+ declare function ActiveFilterPills({ filters, onRemove, onClearAll, clearAllLabel, className, }: ActiveFilterPillsProps): react_jsx_runtime.JSX.Element | null;
516
+
517
+ type SectionCardProps = {
518
+ title: string;
519
+ description?: string;
520
+ right?: ReactNode;
521
+ overlay?: ReactNode;
522
+ children: ReactNode;
523
+ className?: string;
524
+ };
525
+ declare function SectionCard({ title, description, right, overlay, children, className, }: SectionCardProps): react_jsx_runtime.JSX.Element;
526
+
476
527
  type PageShellVariant = 'plain' | 'glass' | 'minimal';
477
528
  type PageShellProps = {
478
529
  header?: ReactNode;
@@ -569,4 +620,14 @@ type ToastContextValue = {
569
620
  declare function ToastProvider({ children, position, maxToasts }: ToastProviderProps): react_jsx_runtime.JSX.Element;
570
621
  declare function useToast(): ToastContextValue;
571
622
 
572
- export { Alert, type AlertProps, type AlertVariant, Avatar, type AvatarProps, type AvatarSize, Badge, type BadgeProps, type BadgeSize, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Card, type CardProps, type CardVariant, Checkbox, type CheckboxProps, CollapsibleSection, type CollapsibleSectionProps, ColorInput, type ColorInputProps, ConfirmDialog, type ConfirmDialogProps, type ConfirmDialogVariant, CopyField, type CopyFieldProps, DashboardLayout, type DashboardLayoutProps, Divider, type DividerProps, DropZone, type DropZoneProps, Dropdown, DropdownItem, type DropdownItemProps, DropdownMenu, type DropdownMenuProps, type DropdownProps, DropdownSeparator, type DropdownSeparatorProps, DropdownTrigger, type DropdownTriggerProps, EmptyState, type EmptyStateProps, FormField, type FormFieldProps, IconButton, type IconButtonProps, Input, type InputProps, Modal, type ModalProps, Navbar, type NavbarProps, PageShell, type PageShellProps, type PageShellVariant, Pagination, type PaginationProps, Pill, ProgressBar, type ProgressBarProps, type ProgressBarVariant, ProgressButton, type ProgressButtonProps, RadioGroup, type RadioGroupProps, RadioItem, type RadioItemProps, SearchInput, type SearchInputProps, Select, type SelectProps, Sidebar, type SidebarProps, type Size, Skeleton, type SkeletonProps, Slider, type SliderProps, Spinner, type SpinnerProps, type SpinnerSize, StatCard, type StatCardProps, type StatCardTrend, type Step, Stepper, type StepperProps, Tab, TabList, type TabListProps, TabPanel, type TabPanelProps, type TabProps, Table, TableBody, type TableBodyProps, TableCell, type TableCellProps, TableHead, type TableHeadProps, TableHeader, type TableHeaderProps, type TableProps, TableRow, type TableRowProps, Tabs, type TabsProps, type TabsVariant, TagInput, type TagInputProps, Textarea, type TextareaProps, type ToastData, type ToastPosition, ToastProvider, type ToastProviderProps, type ToastVariant, Toggle, type ToggleProps, type ToggleSize, Tooltip, type TooltipPlacement, type TooltipProps, type UseClipboardReturn, type UseDisclosureReturn, cn, focusSafely, getFocusableElements, useClipboard, useDebounce, useDisclosure, useMediaQuery, useToast };
623
+ type MutationOverlayStatus = 'idle' | 'saving' | 'saved' | 'error';
624
+ type MutationOverlayProps = {
625
+ status: MutationOverlayStatus;
626
+ savingText?: string;
627
+ savedText?: string;
628
+ errorText?: string;
629
+ className?: string;
630
+ };
631
+ declare function MutationOverlay({ status, savingText, savedText, errorText, className, }: MutationOverlayProps): react_jsx_runtime.JSX.Element | null;
632
+
633
+ export { ActiveFilterPills, type ActiveFilterPillsProps, Alert, type AlertProps, type AlertVariant, Avatar, type AvatarProps, type AvatarSize, Badge, type BadgeProps, type BadgeSize, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Card, type CardProps, type CardVariant, Checkbox, type CheckboxProps, CollapsibleSection, type CollapsibleSectionProps, ColorInput, type ColorInputProps, ConfirmDialog, type ConfirmDialogProps, type ConfirmDialogVariant, CooldownRing, type CooldownRingProps, type CooldownRingSize, CopyField, type CopyFieldProps, DashboardLayout, type DashboardLayoutProps, Divider, type DividerProps, DotIndicator, type DotIndicatorProps, DropZone, type DropZoneProps, Dropdown, DropdownItem, type DropdownItemProps, DropdownMenu, type DropdownMenuProps, type DropdownProps, DropdownSeparator, type DropdownSeparatorProps, DropdownTrigger, type DropdownTriggerProps, EmptyState, type EmptyStateProps, type FilterPill, FormField, type FormFieldProps, IconButton, type IconButtonProps, Input, type InputProps, Modal, type ModalProps, MutationOverlay, type MutationOverlayProps, type MutationOverlayStatus, Navbar, type NavbarProps, PageShell, type PageShellProps, type PageShellVariant, Pagination, type PaginationProps, Pill, ProgressBar, type ProgressBarProps, type ProgressBarVariant, ProgressButton, type ProgressButtonProps, RadioGroup, type RadioGroupProps, RadioItem, type RadioItemProps, SearchInput, type SearchInputProps, SectionCard, type SectionCardProps, Select, type SelectProps, Sidebar, type SidebarProps, type Size, Skeleton, type SkeletonProps, Slider, type SliderProps, Spinner, type SpinnerProps, type SpinnerSize, StageProgress, type StageProgressProps, StatCard, type StatCardProps, type StatCardTrend, type Step, Stepper, type StepperProps, Tab, TabList, type TabListProps, TabPanel, type TabPanelProps, type TabProps, Table, TableBody, type TableBodyProps, TableCell, type TableCellProps, TableHead, type TableHeadProps, TableHeader, type TableHeaderProps, type TableProps, TableRow, type TableRowProps, Tabs, type TabsProps, type TabsVariant, TagInput, type TagInputProps, Textarea, type TextareaProps, type ToastData, type ToastPosition, ToastProvider, type ToastProviderProps, type ToastVariant, Toggle, type ToggleProps, type ToggleSize, Tooltip, type TooltipPlacement, type TooltipProps, type UseClipboardReturn, type UseDisclosureReturn, cn, focusSafely, getFocusableElements, useClipboard, useDebounce, useDisclosure, useMediaQuery, useToast };
package/dist/index.js CHANGED
@@ -552,7 +552,7 @@ var thumbSize = {
552
552
  sm: { base: "w-4 h-4", translate: "translate-x-4" },
553
553
  md: { base: "w-5 h-5", translate: "translate-x-5" }
554
554
  };
555
- var Toggle = forwardRef(function Toggle2({ checked, onChange, disabled, label, size = "md", id: externalId, "aria-label": ariaLabel }, ref) {
555
+ var Toggle = forwardRef(function Toggle2({ checked, onChange, disabled, busy, label, size = "md", id: externalId, "aria-label": ariaLabel }, ref) {
556
556
  const generatedId = useId();
557
557
  const toggleId = externalId || generatedId;
558
558
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
@@ -565,7 +565,8 @@ var Toggle = forwardRef(function Toggle2({ checked, onChange, disabled, label, s
565
565
  role: "switch",
566
566
  "aria-checked": checked,
567
567
  "aria-label": ariaLabel || label,
568
- disabled,
568
+ disabled: disabled || busy,
569
+ "aria-busy": busy || void 0,
569
570
  onClick: () => onChange(!checked),
570
571
  className: cn(
571
572
  "relative rounded-full transition-colors duration-200 focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2 focus-visible:ring-offset-surface",
@@ -577,9 +578,18 @@ var Toggle = forwardRef(function Toggle2({ checked, onChange, disabled, label, s
577
578
  "span",
578
579
  {
579
580
  className: cn(
580
- "absolute top-0.5 left-0.5 rounded-full bg-white transition-transform duration-200",
581
+ "absolute top-0.5 left-0.5 rounded-full bg-white transition-transform duration-200 flex items-center justify-center",
581
582
  thumbSize[size].base,
582
583
  checked ? thumbSize[size].translate : "translate-x-0"
584
+ ),
585
+ children: busy && /* @__PURE__ */ jsx(
586
+ "span",
587
+ {
588
+ className: cn(
589
+ "border-2 border-primary/30 border-t-primary rounded-full animate-spin",
590
+ size === "sm" ? "w-2.5 h-2.5" : "w-3 h-3"
591
+ )
592
+ }
583
593
  )
584
594
  }
585
595
  )
@@ -2251,6 +2261,309 @@ function ProgressBar({
2251
2261
  )
2252
2262
  ] });
2253
2263
  }
2264
+ var sizeMap = {
2265
+ sm: "w-8 h-8 text-xs",
2266
+ md: "w-12 h-12 text-sm",
2267
+ lg: "w-16 h-16 text-base"
2268
+ };
2269
+ var strokeWidthMap = {
2270
+ sm: 3,
2271
+ md: 3.5,
2272
+ lg: 4
2273
+ };
2274
+ var RADIUS = 15.9155;
2275
+ var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
2276
+ function CooldownRing({
2277
+ duration,
2278
+ remaining,
2279
+ size = "md",
2280
+ className
2281
+ }) {
2282
+ const fraction = duration > 0 ? Math.max(0, Math.min(1, remaining / duration)) : 0;
2283
+ const offset = CIRCUMFERENCE * (1 - fraction);
2284
+ const color = fraction > 0.5 ? "text-primary" : fraction > 0.25 ? "text-amber-500" : "text-rose-500";
2285
+ const pulse = remaining <= 10 && remaining > 0;
2286
+ const strokeWidth = strokeWidthMap[size];
2287
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative inline-flex items-center justify-center", sizeMap[size], className), children: [
2288
+ /* @__PURE__ */ jsxs(
2289
+ "svg",
2290
+ {
2291
+ viewBox: "0 0 36 36",
2292
+ className: cn("w-full h-full -rotate-90", color, pulse && "animate-pulse"),
2293
+ "aria-label": `Cooldown: ${remaining} seconds remaining`,
2294
+ role: "img",
2295
+ children: [
2296
+ /* @__PURE__ */ jsx(
2297
+ "circle",
2298
+ {
2299
+ cx: "18",
2300
+ cy: "18",
2301
+ r: RADIUS,
2302
+ fill: "none",
2303
+ stroke: "currentColor",
2304
+ strokeWidth,
2305
+ className: "text-white/10"
2306
+ }
2307
+ ),
2308
+ /* @__PURE__ */ jsx(
2309
+ "circle",
2310
+ {
2311
+ cx: "18",
2312
+ cy: "18",
2313
+ r: RADIUS,
2314
+ fill: "none",
2315
+ stroke: "currentColor",
2316
+ strokeWidth,
2317
+ strokeDasharray: `${CIRCUMFERENCE} ${CIRCUMFERENCE}`,
2318
+ strokeDashoffset: offset,
2319
+ strokeLinecap: "round",
2320
+ style: { transition: "stroke-dashoffset 0.6s ease" }
2321
+ }
2322
+ )
2323
+ ]
2324
+ }
2325
+ ),
2326
+ /* @__PURE__ */ jsx(
2327
+ "span",
2328
+ {
2329
+ className: "absolute font-semibold tabular-nums text-white select-none",
2330
+ style: { lineHeight: 1 },
2331
+ children: Math.max(0, Math.ceil(remaining))
2332
+ }
2333
+ )
2334
+ ] });
2335
+ }
2336
+ function StageProgress({ stages, activeStage, className }) {
2337
+ const clampedActive = Math.max(0, Math.min(activeStage, stages.length - 1));
2338
+ const fillPercent = stages.length <= 1 ? 100 : clampedActive / (stages.length - 1) * 100;
2339
+ const isComplete = clampedActive >= stages.length - 1;
2340
+ const isAnimating = !isComplete;
2341
+ return /* @__PURE__ */ jsxs("div", { className: cn("w-full", className), children: [
2342
+ /* @__PURE__ */ jsx("div", { className: "flex justify-between", children: stages.map((stage, index) => {
2343
+ const isCompleted = index < clampedActive;
2344
+ const isActive = index === clampedActive;
2345
+ return /* @__PURE__ */ jsxs(
2346
+ "div",
2347
+ {
2348
+ className: cn(
2349
+ "flex items-center gap-1.5 text-xs font-medium transition-colors duration-300",
2350
+ isCompleted && "text-emerald-400",
2351
+ isActive && "text-white",
2352
+ !isCompleted && !isActive && "text-white/40"
2353
+ ),
2354
+ children: [
2355
+ isCompleted ? (
2356
+ // Completed: emerald check circle
2357
+ /* @__PURE__ */ jsx("span", { className: "flex h-3.5 w-3.5 items-center justify-center rounded-full bg-emerald-400/20", children: /* @__PURE__ */ jsx(
2358
+ "svg",
2359
+ {
2360
+ className: "h-2.5 w-2.5 text-emerald-400",
2361
+ viewBox: "0 0 10 10",
2362
+ fill: "none",
2363
+ xmlns: "http://www.w3.org/2000/svg",
2364
+ "aria-hidden": "true",
2365
+ children: /* @__PURE__ */ jsx(
2366
+ "path",
2367
+ {
2368
+ d: "M2 5.5L4 7.5L8 3",
2369
+ stroke: "currentColor",
2370
+ strokeWidth: "1.5",
2371
+ strokeLinecap: "round",
2372
+ strokeLinejoin: "round"
2373
+ }
2374
+ )
2375
+ }
2376
+ ) })
2377
+ ) : isActive ? (
2378
+ // Active: primary dot with ring
2379
+ /* @__PURE__ */ jsx("span", { className: "flex h-3.5 w-3.5 items-center justify-center rounded-full ring-2 ring-[var(--ml-primary)] ring-offset-1 ring-offset-black/50", children: /* @__PURE__ */ jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-[var(--ml-primary)]" }) })
2380
+ ) : (
2381
+ // Upcoming: hollow dim dot
2382
+ /* @__PURE__ */ jsx("span", { className: "h-3.5 w-3.5 rounded-full border border-white/20 bg-transparent" })
2383
+ ),
2384
+ stage
2385
+ ]
2386
+ },
2387
+ stage
2388
+ );
2389
+ }) }),
2390
+ /* @__PURE__ */ jsx(
2391
+ "div",
2392
+ {
2393
+ className: "relative mt-3 h-1.5 w-full overflow-hidden rounded-full bg-white/10",
2394
+ role: "progressbar",
2395
+ "aria-valuenow": clampedActive,
2396
+ "aria-valuemin": 0,
2397
+ "aria-valuemax": stages.length - 1,
2398
+ "aria-label": `Stage ${clampedActive + 1} of ${stages.length}: ${stages[clampedActive]}`,
2399
+ children: /* @__PURE__ */ jsx(
2400
+ "div",
2401
+ {
2402
+ className: "h-full rounded-full bg-gradient-to-r from-[var(--ml-accent)] to-[var(--ml-primary)] transition-[width] duration-500 ease-in-out",
2403
+ style: { width: `${fillPercent}%` },
2404
+ children: isAnimating && /* @__PURE__ */ jsx(
2405
+ "span",
2406
+ {
2407
+ className: "pointer-events-none absolute inset-0 -translate-x-full animate-[ml-shimmer_2s_ease-in-out_infinite] bg-gradient-to-r from-transparent via-white/30 to-transparent",
2408
+ "aria-hidden": "true"
2409
+ }
2410
+ )
2411
+ }
2412
+ )
2413
+ }
2414
+ )
2415
+ ] });
2416
+ }
2417
+ function getUrgencyClasses(remaining, max) {
2418
+ const ratio = max > 0 ? remaining / max : 0;
2419
+ if (ratio > 0.5) {
2420
+ return {
2421
+ filled: "bg-emerald-400",
2422
+ empty: "bg-emerald-400/30",
2423
+ label: "text-emerald-400"
2424
+ };
2425
+ }
2426
+ if (ratio > 0.25) {
2427
+ return {
2428
+ filled: "bg-amber-400",
2429
+ empty: "bg-amber-400/30",
2430
+ label: "text-amber-400"
2431
+ };
2432
+ }
2433
+ return {
2434
+ filled: "bg-rose-400",
2435
+ empty: "bg-rose-400/30",
2436
+ label: "text-rose-400"
2437
+ };
2438
+ }
2439
+ function DotIndicator({
2440
+ remaining,
2441
+ max,
2442
+ showLabel = false,
2443
+ labelFormat,
2444
+ className
2445
+ }) {
2446
+ const clampedRemaining = Math.max(0, Math.min(remaining, max));
2447
+ const used = max - clampedRemaining;
2448
+ const urgency = getUrgencyClasses(clampedRemaining, max);
2449
+ const defaultLabel = `${clampedRemaining}/${max}`;
2450
+ const label = labelFormat ? labelFormat(clampedRemaining, max) : defaultLabel;
2451
+ return /* @__PURE__ */ jsxs("div", { className: cn("inline-flex items-center gap-2", className), children: [
2452
+ /* @__PURE__ */ jsx(
2453
+ "div",
2454
+ {
2455
+ className: "flex items-center gap-1",
2456
+ role: "meter",
2457
+ "aria-valuenow": clampedRemaining,
2458
+ "aria-valuemin": 0,
2459
+ "aria-valuemax": max,
2460
+ "aria-label": label,
2461
+ children: Array.from({ length: max }, (_, index) => {
2462
+ const isFilled = index < used;
2463
+ return /* @__PURE__ */ jsx(
2464
+ "span",
2465
+ {
2466
+ className: cn(
2467
+ "h-2 w-2 rounded-full transition-colors duration-300",
2468
+ isFilled ? urgency.filled : urgency.empty
2469
+ ),
2470
+ "aria-hidden": "true"
2471
+ },
2472
+ index
2473
+ );
2474
+ })
2475
+ }
2476
+ ),
2477
+ showLabel && /* @__PURE__ */ jsx("span", { className: cn("text-xs font-medium tabular-nums", urgency.label), children: label })
2478
+ ] });
2479
+ }
2480
+ function ActiveFilterPills({
2481
+ filters,
2482
+ onRemove,
2483
+ onClearAll,
2484
+ clearAllLabel = "Clear all",
2485
+ className
2486
+ }) {
2487
+ if (filters.length === 0) return null;
2488
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-wrap items-center gap-1.5", className), children: [
2489
+ filters.map((filter) => /* @__PURE__ */ jsxs(
2490
+ "span",
2491
+ {
2492
+ className: "inline-flex items-center gap-1 rounded-full bg-white/10 px-2.5 py-1 text-xs text-white/80 ring-1 ring-white/10",
2493
+ children: [
2494
+ filter.label,
2495
+ /* @__PURE__ */ jsx(
2496
+ "button",
2497
+ {
2498
+ type: "button",
2499
+ onClick: () => onRemove(filter.key),
2500
+ className: "ml-0.5 text-white/50 transition-colors duration-150 hover:text-white focus:outline-none focus-visible:text-white",
2501
+ "aria-label": `Remove filter: ${filter.label}`,
2502
+ children: /* @__PURE__ */ jsx(
2503
+ "svg",
2504
+ {
2505
+ className: "h-3 w-3",
2506
+ viewBox: "0 0 12 12",
2507
+ fill: "none",
2508
+ xmlns: "http://www.w3.org/2000/svg",
2509
+ "aria-hidden": "true",
2510
+ children: /* @__PURE__ */ jsx(
2511
+ "path",
2512
+ {
2513
+ d: "M9 3L3 9M3 3L9 9",
2514
+ stroke: "currentColor",
2515
+ strokeWidth: "1.5",
2516
+ strokeLinecap: "round"
2517
+ }
2518
+ )
2519
+ }
2520
+ )
2521
+ }
2522
+ )
2523
+ ]
2524
+ },
2525
+ filter.key
2526
+ )),
2527
+ filters.length > 1 && onClearAll && /* @__PURE__ */ jsx(
2528
+ "button",
2529
+ {
2530
+ type: "button",
2531
+ onClick: onClearAll,
2532
+ className: "text-xs text-white/40 underline-offset-2 transition-colors duration-150 hover:text-white/70 focus:outline-none focus-visible:text-white/70",
2533
+ children: clearAllLabel
2534
+ }
2535
+ )
2536
+ ] });
2537
+ }
2538
+ function SectionCard({
2539
+ title,
2540
+ description,
2541
+ right,
2542
+ overlay,
2543
+ children,
2544
+ className
2545
+ }) {
2546
+ return /* @__PURE__ */ jsxs(
2547
+ "div",
2548
+ {
2549
+ className: cn(
2550
+ "relative bg-white/5 ring-1 ring-white/10 rounded-xl overflow-hidden",
2551
+ className
2552
+ ),
2553
+ children: [
2554
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3 px-5 py-4 border-b border-white/[0.06]", children: [
2555
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
2556
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-white", children: title }),
2557
+ description && /* @__PURE__ */ jsx("p", { className: "text-xs text-white/40 mt-0.5", children: description })
2558
+ ] }),
2559
+ right && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: right })
2560
+ ] }),
2561
+ /* @__PURE__ */ jsx("div", { className: "px-5 py-4", children }),
2562
+ overlay
2563
+ ]
2564
+ }
2565
+ );
2566
+ }
2254
2567
  var maxWidthClass = {
2255
2568
  sm: "max-w-2xl",
2256
2569
  md: "max-w-4xl",
@@ -2899,5 +3212,117 @@ function useToast() {
2899
3212
  }
2900
3213
  return ctx;
2901
3214
  }
3215
+ function SavingIcon() {
3216
+ return /* @__PURE__ */ jsxs(
3217
+ "svg",
3218
+ {
3219
+ className: "h-5 w-5 animate-spin text-white/70",
3220
+ viewBox: "0 0 24 24",
3221
+ fill: "none",
3222
+ "aria-hidden": "true",
3223
+ children: [
3224
+ /* @__PURE__ */ jsx(
3225
+ "circle",
3226
+ {
3227
+ className: "opacity-25",
3228
+ cx: "12",
3229
+ cy: "12",
3230
+ r: "10",
3231
+ stroke: "currentColor",
3232
+ strokeWidth: "4"
3233
+ }
3234
+ ),
3235
+ /* @__PURE__ */ jsx(
3236
+ "path",
3237
+ {
3238
+ className: "opacity-75",
3239
+ fill: "currentColor",
3240
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
3241
+ }
3242
+ )
3243
+ ]
3244
+ }
3245
+ );
3246
+ }
3247
+ function SavedIcon() {
3248
+ return /* @__PURE__ */ jsxs(
3249
+ "svg",
3250
+ {
3251
+ className: "h-5 w-5 text-green-400",
3252
+ viewBox: "0 0 24 24",
3253
+ fill: "none",
3254
+ stroke: "currentColor",
3255
+ strokeWidth: 2,
3256
+ "aria-hidden": "true",
3257
+ children: [
3258
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", strokeOpacity: 0.4 }),
3259
+ /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 12l2 2 4-4" })
3260
+ ]
3261
+ }
3262
+ );
3263
+ }
3264
+ function ErrorIcon2() {
3265
+ return /* @__PURE__ */ jsxs(
3266
+ "svg",
3267
+ {
3268
+ className: "h-5 w-5 text-red-400",
3269
+ viewBox: "0 0 24 24",
3270
+ fill: "none",
3271
+ stroke: "currentColor",
3272
+ strokeWidth: 2,
3273
+ "aria-hidden": "true",
3274
+ children: [
3275
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", strokeOpacity: 0.4 }),
3276
+ /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 9l-6 6M9 9l6 6" })
3277
+ ]
3278
+ }
3279
+ );
3280
+ }
3281
+ var statusConfig = {
3282
+ saving: {
3283
+ icon: SavingIcon,
3284
+ defaultText: "Saving...",
3285
+ textClass: "text-white/70"
3286
+ },
3287
+ saved: {
3288
+ icon: SavedIcon,
3289
+ defaultText: "Saved",
3290
+ textClass: "text-green-400"
3291
+ },
3292
+ error: {
3293
+ icon: ErrorIcon2,
3294
+ defaultText: "Error",
3295
+ textClass: "text-red-400"
3296
+ }
3297
+ };
3298
+ function MutationOverlay({
3299
+ status,
3300
+ savingText,
3301
+ savedText,
3302
+ errorText,
3303
+ className
3304
+ }) {
3305
+ if (status === "idle") return null;
3306
+ const config = statusConfig[status];
3307
+ const Icon = config.icon;
3308
+ const text = status === "saving" ? savingText ?? config.defaultText : status === "saved" ? savedText ?? config.defaultText : errorText ?? config.defaultText;
3309
+ return /* @__PURE__ */ jsx(
3310
+ "div",
3311
+ {
3312
+ className: cn(
3313
+ "absolute inset-0 z-10 flex items-center justify-center",
3314
+ "bg-surface-50/80 backdrop-blur-sm",
3315
+ "transition-opacity duration-200",
3316
+ className
3317
+ ),
3318
+ role: "status",
3319
+ "aria-live": "polite",
3320
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3321
+ /* @__PURE__ */ jsx(Icon, {}),
3322
+ /* @__PURE__ */ jsx("span", { className: cn("text-sm font-medium", config.textClass), children: text })
3323
+ ] })
3324
+ }
3325
+ );
3326
+ }
2902
3327
 
2903
- export { Alert, Avatar, Badge, Button, Card, Checkbox, CollapsibleSection, ColorInput, ConfirmDialog, CopyField, DashboardLayout, Divider, DropZone, Dropdown, DropdownItem, DropdownMenu, DropdownSeparator, DropdownTrigger, EmptyState, FormField, IconButton, Input, Modal, Navbar, PageShell, Pagination, Pill, ProgressBar, ProgressButton, RadioGroup, RadioItem, SearchInput, Select, Sidebar, Skeleton, Slider, Spinner, StatCard, Stepper, Tab, TabList, TabPanel, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TagInput, Textarea, ToastProvider, Toggle, Tooltip, cn, colors, focusSafely, getFocusableElements, useClipboard, useDebounce, useDisclosure, useMediaQuery, useToast };
3328
+ export { ActiveFilterPills, Alert, Avatar, Badge, Button, Card, Checkbox, CollapsibleSection, ColorInput, ConfirmDialog, CooldownRing, CopyField, DashboardLayout, Divider, DotIndicator, DropZone, Dropdown, DropdownItem, DropdownMenu, DropdownSeparator, DropdownTrigger, EmptyState, FormField, IconButton, Input, Modal, MutationOverlay, Navbar, PageShell, Pagination, Pill, ProgressBar, ProgressButton, RadioGroup, RadioItem, SearchInput, SectionCard, Select, Sidebar, Skeleton, Slider, Spinner, StageProgress, StatCard, Stepper, Tab, TabList, TabPanel, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TagInput, Textarea, ToastProvider, Toggle, Tooltip, cn, colors, focusSafely, getFocusableElements, useClipboard, useDebounce, useDisclosure, useMediaQuery, useToast };