@memelabui/ui 0.3.0 → 0.5.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.cjs CHANGED
@@ -130,6 +130,82 @@ function useDebounce(value, delayMs = 300) {
130
130
  }, [value, delayMs]);
131
131
  return debouncedValue;
132
132
  }
133
+ function matchModifiers(e, mods) {
134
+ const ctrl = mods?.ctrl ?? false;
135
+ const shift = mods?.shift ?? false;
136
+ const alt = mods?.alt ?? false;
137
+ const meta = mods?.meta ?? false;
138
+ return e.ctrlKey === ctrl && e.shiftKey === shift && e.altKey === alt && e.metaKey === meta;
139
+ }
140
+ function useHotkeys(bindings, options = {}) {
141
+ const { enabled = true } = options;
142
+ React.useEffect(() => {
143
+ if (!enabled) return;
144
+ const onKeyDown = (e) => {
145
+ for (const binding of bindings) {
146
+ if (e.key === binding.key && matchModifiers(e, binding.modifiers)) {
147
+ binding.handler(e);
148
+ }
149
+ }
150
+ };
151
+ document.addEventListener("keydown", onKeyDown);
152
+ return () => document.removeEventListener("keydown", onKeyDown);
153
+ }, [enabled, ...bindings]);
154
+ }
155
+ function useIntersectionObserver(options = {}) {
156
+ const { root = null, rootMargin = "0px", threshold = 0, enabled = true } = options;
157
+ const [entry, setEntry] = React.useState(null);
158
+ const nodeRef = React.useRef(null);
159
+ const observerRef = React.useRef(null);
160
+ React.useEffect(() => {
161
+ if (!enabled) {
162
+ setEntry(null);
163
+ return;
164
+ }
165
+ observerRef.current = new IntersectionObserver(
166
+ ([e]) => setEntry(e),
167
+ { root, rootMargin, threshold }
168
+ );
169
+ if (nodeRef.current) {
170
+ observerRef.current.observe(nodeRef.current);
171
+ }
172
+ return () => {
173
+ observerRef.current?.disconnect();
174
+ observerRef.current = null;
175
+ };
176
+ }, [enabled, root, rootMargin, JSON.stringify(threshold)]);
177
+ const ref = (node) => {
178
+ if (nodeRef.current) {
179
+ observerRef.current?.unobserve(nodeRef.current);
180
+ }
181
+ nodeRef.current = node;
182
+ if (node) {
183
+ observerRef.current?.observe(node);
184
+ }
185
+ };
186
+ return {
187
+ ref,
188
+ entry,
189
+ isIntersecting: entry?.isIntersecting ?? false
190
+ };
191
+ }
192
+ function useSharedNow(options = {}) {
193
+ const { interval = 1e3, untilMs, enabled = true } = options;
194
+ const [now, setNow] = React.useState(Date.now);
195
+ React.useEffect(() => {
196
+ if (!enabled) return;
197
+ if (untilMs !== void 0 && Date.now() >= untilMs) return;
198
+ const id = setInterval(() => {
199
+ const current = Date.now();
200
+ setNow(current);
201
+ if (untilMs !== void 0 && current >= untilMs) {
202
+ clearInterval(id);
203
+ }
204
+ }, interval);
205
+ return () => clearInterval(id);
206
+ }, [interval, untilMs, enabled]);
207
+ return now;
208
+ }
133
209
 
134
210
  // src/tokens/colors.ts
135
211
  var colors = {
@@ -558,7 +634,7 @@ var thumbSize = {
558
634
  sm: { base: "w-4 h-4", translate: "translate-x-4" },
559
635
  md: { base: "w-5 h-5", translate: "translate-x-5" }
560
636
  };
561
- var Toggle = React.forwardRef(function Toggle2({ checked, onChange, disabled, label, size = "md", id: externalId, "aria-label": ariaLabel }, ref) {
637
+ var Toggle = React.forwardRef(function Toggle2({ checked, onChange, disabled, busy, label, size = "md", id: externalId, "aria-label": ariaLabel }, ref) {
562
638
  const generatedId = React.useId();
563
639
  const toggleId = externalId || generatedId;
564
640
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
@@ -571,7 +647,8 @@ var Toggle = React.forwardRef(function Toggle2({ checked, onChange, disabled, la
571
647
  role: "switch",
572
648
  "aria-checked": checked,
573
649
  "aria-label": ariaLabel || label,
574
- disabled,
650
+ disabled: disabled || busy,
651
+ "aria-busy": busy || void 0,
575
652
  onClick: () => onChange(!checked),
576
653
  className: cn(
577
654
  "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",
@@ -583,9 +660,18 @@ var Toggle = React.forwardRef(function Toggle2({ checked, onChange, disabled, la
583
660
  "span",
584
661
  {
585
662
  className: cn(
586
- "absolute top-0.5 left-0.5 rounded-full bg-white transition-transform duration-200",
663
+ "absolute top-0.5 left-0.5 rounded-full bg-white transition-transform duration-200 flex items-center justify-center",
587
664
  thumbSize[size].base,
588
665
  checked ? thumbSize[size].translate : "translate-x-0"
666
+ ),
667
+ children: busy && /* @__PURE__ */ jsxRuntime.jsx(
668
+ "span",
669
+ {
670
+ className: cn(
671
+ "border-2 border-primary/30 border-t-primary rounded-full animate-spin",
672
+ size === "sm" ? "w-2.5 h-2.5" : "w-3 h-3"
673
+ )
674
+ }
589
675
  )
590
676
  }
591
677
  )
@@ -2257,6 +2343,309 @@ function ProgressBar({
2257
2343
  )
2258
2344
  ] });
2259
2345
  }
2346
+ var sizeMap = {
2347
+ sm: "w-8 h-8 text-xs",
2348
+ md: "w-12 h-12 text-sm",
2349
+ lg: "w-16 h-16 text-base"
2350
+ };
2351
+ var strokeWidthMap = {
2352
+ sm: 3,
2353
+ md: 3.5,
2354
+ lg: 4
2355
+ };
2356
+ var RADIUS = 15.9155;
2357
+ var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
2358
+ function CooldownRing({
2359
+ duration,
2360
+ remaining,
2361
+ size = "md",
2362
+ className
2363
+ }) {
2364
+ const fraction = duration > 0 ? Math.max(0, Math.min(1, remaining / duration)) : 0;
2365
+ const offset = CIRCUMFERENCE * (1 - fraction);
2366
+ const color = fraction > 0.5 ? "text-primary" : fraction > 0.25 ? "text-amber-500" : "text-rose-500";
2367
+ const pulse = remaining <= 10 && remaining > 0;
2368
+ const strokeWidth = strokeWidthMap[size];
2369
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative inline-flex items-center justify-center", sizeMap[size], className), children: [
2370
+ /* @__PURE__ */ jsxRuntime.jsxs(
2371
+ "svg",
2372
+ {
2373
+ viewBox: "0 0 36 36",
2374
+ className: cn("w-full h-full -rotate-90", color, pulse && "animate-pulse"),
2375
+ "aria-label": `Cooldown: ${remaining} seconds remaining`,
2376
+ role: "img",
2377
+ children: [
2378
+ /* @__PURE__ */ jsxRuntime.jsx(
2379
+ "circle",
2380
+ {
2381
+ cx: "18",
2382
+ cy: "18",
2383
+ r: RADIUS,
2384
+ fill: "none",
2385
+ stroke: "currentColor",
2386
+ strokeWidth,
2387
+ className: "text-white/10"
2388
+ }
2389
+ ),
2390
+ /* @__PURE__ */ jsxRuntime.jsx(
2391
+ "circle",
2392
+ {
2393
+ cx: "18",
2394
+ cy: "18",
2395
+ r: RADIUS,
2396
+ fill: "none",
2397
+ stroke: "currentColor",
2398
+ strokeWidth,
2399
+ strokeDasharray: `${CIRCUMFERENCE} ${CIRCUMFERENCE}`,
2400
+ strokeDashoffset: offset,
2401
+ strokeLinecap: "round",
2402
+ style: { transition: "stroke-dashoffset 0.6s ease" }
2403
+ }
2404
+ )
2405
+ ]
2406
+ }
2407
+ ),
2408
+ /* @__PURE__ */ jsxRuntime.jsx(
2409
+ "span",
2410
+ {
2411
+ className: "absolute font-semibold tabular-nums text-white select-none",
2412
+ style: { lineHeight: 1 },
2413
+ children: Math.max(0, Math.ceil(remaining))
2414
+ }
2415
+ )
2416
+ ] });
2417
+ }
2418
+ function StageProgress({ stages, activeStage, className }) {
2419
+ const clampedActive = Math.max(0, Math.min(activeStage, stages.length - 1));
2420
+ const fillPercent = stages.length <= 1 ? 100 : clampedActive / (stages.length - 1) * 100;
2421
+ const isComplete = clampedActive >= stages.length - 1;
2422
+ const isAnimating = !isComplete;
2423
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full", className), children: [
2424
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-between", children: stages.map((stage, index) => {
2425
+ const isCompleted = index < clampedActive;
2426
+ const isActive = index === clampedActive;
2427
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2428
+ "div",
2429
+ {
2430
+ className: cn(
2431
+ "flex items-center gap-1.5 text-xs font-medium transition-colors duration-300",
2432
+ isCompleted && "text-emerald-400",
2433
+ isActive && "text-white",
2434
+ !isCompleted && !isActive && "text-white/40"
2435
+ ),
2436
+ children: [
2437
+ isCompleted ? (
2438
+ // Completed: emerald check circle
2439
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-3.5 w-3.5 items-center justify-center rounded-full bg-emerald-400/20", children: /* @__PURE__ */ jsxRuntime.jsx(
2440
+ "svg",
2441
+ {
2442
+ className: "h-2.5 w-2.5 text-emerald-400",
2443
+ viewBox: "0 0 10 10",
2444
+ fill: "none",
2445
+ xmlns: "http://www.w3.org/2000/svg",
2446
+ "aria-hidden": "true",
2447
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2448
+ "path",
2449
+ {
2450
+ d: "M2 5.5L4 7.5L8 3",
2451
+ stroke: "currentColor",
2452
+ strokeWidth: "1.5",
2453
+ strokeLinecap: "round",
2454
+ strokeLinejoin: "round"
2455
+ }
2456
+ )
2457
+ }
2458
+ ) })
2459
+ ) : isActive ? (
2460
+ // Active: primary dot with ring
2461
+ /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-[var(--ml-primary)]" }) })
2462
+ ) : (
2463
+ // Upcoming: hollow dim dot
2464
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-3.5 w-3.5 rounded-full border border-white/20 bg-transparent" })
2465
+ ),
2466
+ stage
2467
+ ]
2468
+ },
2469
+ stage
2470
+ );
2471
+ }) }),
2472
+ /* @__PURE__ */ jsxRuntime.jsx(
2473
+ "div",
2474
+ {
2475
+ className: "relative mt-3 h-1.5 w-full overflow-hidden rounded-full bg-white/10",
2476
+ role: "progressbar",
2477
+ "aria-valuenow": clampedActive,
2478
+ "aria-valuemin": 0,
2479
+ "aria-valuemax": stages.length - 1,
2480
+ "aria-label": `Stage ${clampedActive + 1} of ${stages.length}: ${stages[clampedActive]}`,
2481
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2482
+ "div",
2483
+ {
2484
+ className: "h-full rounded-full bg-gradient-to-r from-[var(--ml-accent)] to-[var(--ml-primary)] transition-[width] duration-500 ease-in-out",
2485
+ style: { width: `${fillPercent}%` },
2486
+ children: isAnimating && /* @__PURE__ */ jsxRuntime.jsx(
2487
+ "span",
2488
+ {
2489
+ 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",
2490
+ "aria-hidden": "true"
2491
+ }
2492
+ )
2493
+ }
2494
+ )
2495
+ }
2496
+ )
2497
+ ] });
2498
+ }
2499
+ function getUrgencyClasses(remaining, max) {
2500
+ const ratio = max > 0 ? remaining / max : 0;
2501
+ if (ratio > 0.5) {
2502
+ return {
2503
+ filled: "bg-emerald-400",
2504
+ empty: "bg-emerald-400/30",
2505
+ label: "text-emerald-400"
2506
+ };
2507
+ }
2508
+ if (ratio > 0.25) {
2509
+ return {
2510
+ filled: "bg-amber-400",
2511
+ empty: "bg-amber-400/30",
2512
+ label: "text-amber-400"
2513
+ };
2514
+ }
2515
+ return {
2516
+ filled: "bg-rose-400",
2517
+ empty: "bg-rose-400/30",
2518
+ label: "text-rose-400"
2519
+ };
2520
+ }
2521
+ function DotIndicator({
2522
+ remaining,
2523
+ max,
2524
+ showLabel = false,
2525
+ labelFormat,
2526
+ className
2527
+ }) {
2528
+ const clampedRemaining = Math.max(0, Math.min(remaining, max));
2529
+ const used = max - clampedRemaining;
2530
+ const urgency = getUrgencyClasses(clampedRemaining, max);
2531
+ const defaultLabel = `${clampedRemaining}/${max}`;
2532
+ const label = labelFormat ? labelFormat(clampedRemaining, max) : defaultLabel;
2533
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("inline-flex items-center gap-2", className), children: [
2534
+ /* @__PURE__ */ jsxRuntime.jsx(
2535
+ "div",
2536
+ {
2537
+ className: "flex items-center gap-1",
2538
+ role: "meter",
2539
+ "aria-valuenow": clampedRemaining,
2540
+ "aria-valuemin": 0,
2541
+ "aria-valuemax": max,
2542
+ "aria-label": label,
2543
+ children: Array.from({ length: max }, (_, index) => {
2544
+ const isFilled = index < used;
2545
+ return /* @__PURE__ */ jsxRuntime.jsx(
2546
+ "span",
2547
+ {
2548
+ className: cn(
2549
+ "h-2 w-2 rounded-full transition-colors duration-300",
2550
+ isFilled ? urgency.filled : urgency.empty
2551
+ ),
2552
+ "aria-hidden": "true"
2553
+ },
2554
+ index
2555
+ );
2556
+ })
2557
+ }
2558
+ ),
2559
+ showLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-xs font-medium tabular-nums", urgency.label), children: label })
2560
+ ] });
2561
+ }
2562
+ function ActiveFilterPills({
2563
+ filters,
2564
+ onRemove,
2565
+ onClearAll,
2566
+ clearAllLabel = "Clear all",
2567
+ className
2568
+ }) {
2569
+ if (filters.length === 0) return null;
2570
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-wrap items-center gap-1.5", className), children: [
2571
+ filters.map((filter) => /* @__PURE__ */ jsxRuntime.jsxs(
2572
+ "span",
2573
+ {
2574
+ 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",
2575
+ children: [
2576
+ filter.label,
2577
+ /* @__PURE__ */ jsxRuntime.jsx(
2578
+ "button",
2579
+ {
2580
+ type: "button",
2581
+ onClick: () => onRemove(filter.key),
2582
+ className: "ml-0.5 text-white/50 transition-colors duration-150 hover:text-white focus:outline-none focus-visible:text-white",
2583
+ "aria-label": `Remove filter: ${filter.label}`,
2584
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2585
+ "svg",
2586
+ {
2587
+ className: "h-3 w-3",
2588
+ viewBox: "0 0 12 12",
2589
+ fill: "none",
2590
+ xmlns: "http://www.w3.org/2000/svg",
2591
+ "aria-hidden": "true",
2592
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2593
+ "path",
2594
+ {
2595
+ d: "M9 3L3 9M3 3L9 9",
2596
+ stroke: "currentColor",
2597
+ strokeWidth: "1.5",
2598
+ strokeLinecap: "round"
2599
+ }
2600
+ )
2601
+ }
2602
+ )
2603
+ }
2604
+ )
2605
+ ]
2606
+ },
2607
+ filter.key
2608
+ )),
2609
+ filters.length > 1 && onClearAll && /* @__PURE__ */ jsxRuntime.jsx(
2610
+ "button",
2611
+ {
2612
+ type: "button",
2613
+ onClick: onClearAll,
2614
+ 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",
2615
+ children: clearAllLabel
2616
+ }
2617
+ )
2618
+ ] });
2619
+ }
2620
+ function SectionCard({
2621
+ title,
2622
+ description,
2623
+ right,
2624
+ overlay,
2625
+ children,
2626
+ className
2627
+ }) {
2628
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2629
+ "div",
2630
+ {
2631
+ className: cn(
2632
+ "relative bg-white/5 ring-1 ring-white/10 rounded-xl overflow-hidden",
2633
+ className
2634
+ ),
2635
+ children: [
2636
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3 px-5 py-4 border-b border-white/[0.06]", children: [
2637
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
2638
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-white", children: title }),
2639
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-white/40 mt-0.5", children: description })
2640
+ ] }),
2641
+ right && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: right })
2642
+ ] }),
2643
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-5 py-4", children }),
2644
+ overlay
2645
+ ]
2646
+ }
2647
+ );
2648
+ }
2260
2649
  var maxWidthClass = {
2261
2650
  sm: "max-w-2xl",
2262
2651
  md: "max-w-4xl",
@@ -2905,7 +3294,190 @@ function useToast() {
2905
3294
  }
2906
3295
  return ctx;
2907
3296
  }
3297
+ function SavingIcon() {
3298
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3299
+ "svg",
3300
+ {
3301
+ className: "h-5 w-5 animate-spin text-white/70",
3302
+ viewBox: "0 0 24 24",
3303
+ fill: "none",
3304
+ "aria-hidden": "true",
3305
+ children: [
3306
+ /* @__PURE__ */ jsxRuntime.jsx(
3307
+ "circle",
3308
+ {
3309
+ className: "opacity-25",
3310
+ cx: "12",
3311
+ cy: "12",
3312
+ r: "10",
3313
+ stroke: "currentColor",
3314
+ strokeWidth: "4"
3315
+ }
3316
+ ),
3317
+ /* @__PURE__ */ jsxRuntime.jsx(
3318
+ "path",
3319
+ {
3320
+ className: "opacity-75",
3321
+ fill: "currentColor",
3322
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
3323
+ }
3324
+ )
3325
+ ]
3326
+ }
3327
+ );
3328
+ }
3329
+ function SavedIcon() {
3330
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3331
+ "svg",
3332
+ {
3333
+ className: "h-5 w-5 text-green-400",
3334
+ viewBox: "0 0 24 24",
3335
+ fill: "none",
3336
+ stroke: "currentColor",
3337
+ strokeWidth: 2,
3338
+ "aria-hidden": "true",
3339
+ children: [
3340
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", strokeOpacity: 0.4 }),
3341
+ /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 12l2 2 4-4" })
3342
+ ]
3343
+ }
3344
+ );
3345
+ }
3346
+ function ErrorIcon2() {
3347
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3348
+ "svg",
3349
+ {
3350
+ className: "h-5 w-5 text-red-400",
3351
+ viewBox: "0 0 24 24",
3352
+ fill: "none",
3353
+ stroke: "currentColor",
3354
+ strokeWidth: 2,
3355
+ "aria-hidden": "true",
3356
+ children: [
3357
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", strokeOpacity: 0.4 }),
3358
+ /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 9l-6 6M9 9l6 6" })
3359
+ ]
3360
+ }
3361
+ );
3362
+ }
3363
+ var statusConfig = {
3364
+ saving: {
3365
+ icon: SavingIcon,
3366
+ defaultText: "Saving...",
3367
+ textClass: "text-white/70"
3368
+ },
3369
+ saved: {
3370
+ icon: SavedIcon,
3371
+ defaultText: "Saved",
3372
+ textClass: "text-green-400"
3373
+ },
3374
+ error: {
3375
+ icon: ErrorIcon2,
3376
+ defaultText: "Error",
3377
+ textClass: "text-red-400"
3378
+ }
3379
+ };
3380
+ function MutationOverlay({
3381
+ status,
3382
+ savingText,
3383
+ savedText,
3384
+ errorText,
3385
+ className
3386
+ }) {
3387
+ if (status === "idle") return null;
3388
+ const config = statusConfig[status];
3389
+ const Icon = config.icon;
3390
+ const text = status === "saving" ? savingText ?? config.defaultText : status === "saved" ? savedText ?? config.defaultText : errorText ?? config.defaultText;
3391
+ return /* @__PURE__ */ jsxRuntime.jsx(
3392
+ "div",
3393
+ {
3394
+ className: cn(
3395
+ "absolute inset-0 z-10 flex items-center justify-center",
3396
+ "bg-surface-50/80 backdrop-blur-sm",
3397
+ "transition-opacity duration-200",
3398
+ className
3399
+ ),
3400
+ role: "status",
3401
+ "aria-live": "polite",
3402
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
3403
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, {}),
3404
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-sm font-medium", config.textClass), children: text })
3405
+ ] })
3406
+ }
3407
+ );
3408
+ }
3409
+ var sizeClass6 = {
3410
+ sm: "w-8 h-8",
3411
+ md: "w-10 h-10",
3412
+ lg: "w-12 h-12"
3413
+ };
3414
+ var iconSizeClass = {
3415
+ sm: "w-4 h-4",
3416
+ md: "w-5 h-5",
3417
+ lg: "w-6 h-6"
3418
+ };
3419
+ var badgeSizeClass = {
3420
+ sm: "min-w-[16px] h-4 text-[10px] px-1",
3421
+ md: "min-w-[18px] h-[18px] text-[11px] px-1",
3422
+ lg: "min-w-[20px] h-5 text-xs px-1.5"
3423
+ };
3424
+ var DefaultBellIcon = ({ className }) => /* @__PURE__ */ jsxRuntime.jsxs(
3425
+ "svg",
3426
+ {
3427
+ xmlns: "http://www.w3.org/2000/svg",
3428
+ viewBox: "0 0 24 24",
3429
+ fill: "none",
3430
+ stroke: "currentColor",
3431
+ strokeWidth: 2,
3432
+ strokeLinecap: "round",
3433
+ strokeLinejoin: "round",
3434
+ className,
3435
+ "aria-hidden": "true",
3436
+ children: [
3437
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" }),
3438
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0" })
3439
+ ]
3440
+ }
3441
+ );
3442
+ var NotificationBell = React.forwardRef(
3443
+ function NotificationBell2({ icon, count, maxCount = 99, size = "md", ping, className, disabled, ...props }, ref) {
3444
+ const displayCount = count && count > maxCount ? `${maxCount}+` : count;
3445
+ const hasCount = count !== void 0 && count > 0;
3446
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3447
+ "button",
3448
+ {
3449
+ ref,
3450
+ type: "button",
3451
+ ...props,
3452
+ disabled,
3453
+ "aria-label": props["aria-label"] || `Notifications${hasCount ? ` (${count})` : ""}`,
3454
+ className: cn(
3455
+ "relative inline-flex items-center justify-center rounded-xl text-white/70 transition-colors hover:text-white hover:bg-white/10 focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent disabled:opacity-60 disabled:pointer-events-none",
3456
+ sizeClass6[size],
3457
+ className
3458
+ ),
3459
+ children: [
3460
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: icon }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultBellIcon, { className: iconSizeClass[size] }),
3461
+ hasCount && /* @__PURE__ */ jsxRuntime.jsxs(
3462
+ "span",
3463
+ {
3464
+ className: cn(
3465
+ "absolute top-0 right-0 flex items-center justify-center rounded-full bg-rose-500 text-white font-semibold leading-none",
3466
+ badgeSizeClass[size]
3467
+ ),
3468
+ children: [
3469
+ ping && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 rounded-full bg-rose-500 animate-ping opacity-75" }),
3470
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative", children: displayCount })
3471
+ ]
3472
+ }
3473
+ )
3474
+ ]
3475
+ }
3476
+ );
3477
+ }
3478
+ );
2908
3479
 
3480
+ exports.ActiveFilterPills = ActiveFilterPills;
2909
3481
  exports.Alert = Alert;
2910
3482
  exports.Avatar = Avatar;
2911
3483
  exports.Badge = Badge;
@@ -2915,9 +3487,11 @@ exports.Checkbox = Checkbox;
2915
3487
  exports.CollapsibleSection = CollapsibleSection;
2916
3488
  exports.ColorInput = ColorInput;
2917
3489
  exports.ConfirmDialog = ConfirmDialog;
3490
+ exports.CooldownRing = CooldownRing;
2918
3491
  exports.CopyField = CopyField;
2919
3492
  exports.DashboardLayout = DashboardLayout;
2920
3493
  exports.Divider = Divider;
3494
+ exports.DotIndicator = DotIndicator;
2921
3495
  exports.DropZone = DropZone;
2922
3496
  exports.Dropdown = Dropdown;
2923
3497
  exports.DropdownItem = DropdownItem;
@@ -2929,7 +3503,9 @@ exports.FormField = FormField;
2929
3503
  exports.IconButton = IconButton;
2930
3504
  exports.Input = Input;
2931
3505
  exports.Modal = Modal;
3506
+ exports.MutationOverlay = MutationOverlay;
2932
3507
  exports.Navbar = Navbar;
3508
+ exports.NotificationBell = NotificationBell;
2933
3509
  exports.PageShell = PageShell;
2934
3510
  exports.Pagination = Pagination;
2935
3511
  exports.Pill = Pill;
@@ -2938,11 +3514,13 @@ exports.ProgressButton = ProgressButton;
2938
3514
  exports.RadioGroup = RadioGroup;
2939
3515
  exports.RadioItem = RadioItem;
2940
3516
  exports.SearchInput = SearchInput;
3517
+ exports.SectionCard = SectionCard;
2941
3518
  exports.Select = Select;
2942
3519
  exports.Sidebar = Sidebar;
2943
3520
  exports.Skeleton = Skeleton;
2944
3521
  exports.Slider = Slider;
2945
3522
  exports.Spinner = Spinner;
3523
+ exports.StageProgress = StageProgress;
2946
3524
  exports.StatCard = StatCard;
2947
3525
  exports.Stepper = Stepper;
2948
3526
  exports.Tab = Tab;
@@ -2967,5 +3545,8 @@ exports.getFocusableElements = getFocusableElements;
2967
3545
  exports.useClipboard = useClipboard;
2968
3546
  exports.useDebounce = useDebounce;
2969
3547
  exports.useDisclosure = useDisclosure;
3548
+ exports.useHotkeys = useHotkeys;
3549
+ exports.useIntersectionObserver = useIntersectionObserver;
2970
3550
  exports.useMediaQuery = useMediaQuery;
3551
+ exports.useSharedNow = useSharedNow;
2971
3552
  exports.useToast = useToast;