@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.js CHANGED
@@ -124,6 +124,82 @@ function useDebounce(value, delayMs = 300) {
124
124
  }, [value, delayMs]);
125
125
  return debouncedValue;
126
126
  }
127
+ function matchModifiers(e, mods) {
128
+ const ctrl = mods?.ctrl ?? false;
129
+ const shift = mods?.shift ?? false;
130
+ const alt = mods?.alt ?? false;
131
+ const meta = mods?.meta ?? false;
132
+ return e.ctrlKey === ctrl && e.shiftKey === shift && e.altKey === alt && e.metaKey === meta;
133
+ }
134
+ function useHotkeys(bindings, options = {}) {
135
+ const { enabled = true } = options;
136
+ useEffect(() => {
137
+ if (!enabled) return;
138
+ const onKeyDown = (e) => {
139
+ for (const binding of bindings) {
140
+ if (e.key === binding.key && matchModifiers(e, binding.modifiers)) {
141
+ binding.handler(e);
142
+ }
143
+ }
144
+ };
145
+ document.addEventListener("keydown", onKeyDown);
146
+ return () => document.removeEventListener("keydown", onKeyDown);
147
+ }, [enabled, ...bindings]);
148
+ }
149
+ function useIntersectionObserver(options = {}) {
150
+ const { root = null, rootMargin = "0px", threshold = 0, enabled = true } = options;
151
+ const [entry, setEntry] = useState(null);
152
+ const nodeRef = useRef(null);
153
+ const observerRef = useRef(null);
154
+ useEffect(() => {
155
+ if (!enabled) {
156
+ setEntry(null);
157
+ return;
158
+ }
159
+ observerRef.current = new IntersectionObserver(
160
+ ([e]) => setEntry(e),
161
+ { root, rootMargin, threshold }
162
+ );
163
+ if (nodeRef.current) {
164
+ observerRef.current.observe(nodeRef.current);
165
+ }
166
+ return () => {
167
+ observerRef.current?.disconnect();
168
+ observerRef.current = null;
169
+ };
170
+ }, [enabled, root, rootMargin, JSON.stringify(threshold)]);
171
+ const ref = (node) => {
172
+ if (nodeRef.current) {
173
+ observerRef.current?.unobserve(nodeRef.current);
174
+ }
175
+ nodeRef.current = node;
176
+ if (node) {
177
+ observerRef.current?.observe(node);
178
+ }
179
+ };
180
+ return {
181
+ ref,
182
+ entry,
183
+ isIntersecting: entry?.isIntersecting ?? false
184
+ };
185
+ }
186
+ function useSharedNow(options = {}) {
187
+ const { interval = 1e3, untilMs, enabled = true } = options;
188
+ const [now, setNow] = useState(Date.now);
189
+ useEffect(() => {
190
+ if (!enabled) return;
191
+ if (untilMs !== void 0 && Date.now() >= untilMs) return;
192
+ const id = setInterval(() => {
193
+ const current = Date.now();
194
+ setNow(current);
195
+ if (untilMs !== void 0 && current >= untilMs) {
196
+ clearInterval(id);
197
+ }
198
+ }, interval);
199
+ return () => clearInterval(id);
200
+ }, [interval, untilMs, enabled]);
201
+ return now;
202
+ }
127
203
 
128
204
  // src/tokens/colors.ts
129
205
  var colors = {
@@ -552,7 +628,7 @@ var thumbSize = {
552
628
  sm: { base: "w-4 h-4", translate: "translate-x-4" },
553
629
  md: { base: "w-5 h-5", translate: "translate-x-5" }
554
630
  };
555
- var Toggle = forwardRef(function Toggle2({ checked, onChange, disabled, label, size = "md", id: externalId, "aria-label": ariaLabel }, ref) {
631
+ var Toggle = forwardRef(function Toggle2({ checked, onChange, disabled, busy, label, size = "md", id: externalId, "aria-label": ariaLabel }, ref) {
556
632
  const generatedId = useId();
557
633
  const toggleId = externalId || generatedId;
558
634
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
@@ -565,7 +641,8 @@ var Toggle = forwardRef(function Toggle2({ checked, onChange, disabled, label, s
565
641
  role: "switch",
566
642
  "aria-checked": checked,
567
643
  "aria-label": ariaLabel || label,
568
- disabled,
644
+ disabled: disabled || busy,
645
+ "aria-busy": busy || void 0,
569
646
  onClick: () => onChange(!checked),
570
647
  className: cn(
571
648
  "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 +654,18 @@ var Toggle = forwardRef(function Toggle2({ checked, onChange, disabled, label, s
577
654
  "span",
578
655
  {
579
656
  className: cn(
580
- "absolute top-0.5 left-0.5 rounded-full bg-white transition-transform duration-200",
657
+ "absolute top-0.5 left-0.5 rounded-full bg-white transition-transform duration-200 flex items-center justify-center",
581
658
  thumbSize[size].base,
582
659
  checked ? thumbSize[size].translate : "translate-x-0"
660
+ ),
661
+ children: busy && /* @__PURE__ */ jsx(
662
+ "span",
663
+ {
664
+ className: cn(
665
+ "border-2 border-primary/30 border-t-primary rounded-full animate-spin",
666
+ size === "sm" ? "w-2.5 h-2.5" : "w-3 h-3"
667
+ )
668
+ }
583
669
  )
584
670
  }
585
671
  )
@@ -2251,6 +2337,309 @@ function ProgressBar({
2251
2337
  )
2252
2338
  ] });
2253
2339
  }
2340
+ var sizeMap = {
2341
+ sm: "w-8 h-8 text-xs",
2342
+ md: "w-12 h-12 text-sm",
2343
+ lg: "w-16 h-16 text-base"
2344
+ };
2345
+ var strokeWidthMap = {
2346
+ sm: 3,
2347
+ md: 3.5,
2348
+ lg: 4
2349
+ };
2350
+ var RADIUS = 15.9155;
2351
+ var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
2352
+ function CooldownRing({
2353
+ duration,
2354
+ remaining,
2355
+ size = "md",
2356
+ className
2357
+ }) {
2358
+ const fraction = duration > 0 ? Math.max(0, Math.min(1, remaining / duration)) : 0;
2359
+ const offset = CIRCUMFERENCE * (1 - fraction);
2360
+ const color = fraction > 0.5 ? "text-primary" : fraction > 0.25 ? "text-amber-500" : "text-rose-500";
2361
+ const pulse = remaining <= 10 && remaining > 0;
2362
+ const strokeWidth = strokeWidthMap[size];
2363
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative inline-flex items-center justify-center", sizeMap[size], className), children: [
2364
+ /* @__PURE__ */ jsxs(
2365
+ "svg",
2366
+ {
2367
+ viewBox: "0 0 36 36",
2368
+ className: cn("w-full h-full -rotate-90", color, pulse && "animate-pulse"),
2369
+ "aria-label": `Cooldown: ${remaining} seconds remaining`,
2370
+ role: "img",
2371
+ children: [
2372
+ /* @__PURE__ */ jsx(
2373
+ "circle",
2374
+ {
2375
+ cx: "18",
2376
+ cy: "18",
2377
+ r: RADIUS,
2378
+ fill: "none",
2379
+ stroke: "currentColor",
2380
+ strokeWidth,
2381
+ className: "text-white/10"
2382
+ }
2383
+ ),
2384
+ /* @__PURE__ */ jsx(
2385
+ "circle",
2386
+ {
2387
+ cx: "18",
2388
+ cy: "18",
2389
+ r: RADIUS,
2390
+ fill: "none",
2391
+ stroke: "currentColor",
2392
+ strokeWidth,
2393
+ strokeDasharray: `${CIRCUMFERENCE} ${CIRCUMFERENCE}`,
2394
+ strokeDashoffset: offset,
2395
+ strokeLinecap: "round",
2396
+ style: { transition: "stroke-dashoffset 0.6s ease" }
2397
+ }
2398
+ )
2399
+ ]
2400
+ }
2401
+ ),
2402
+ /* @__PURE__ */ jsx(
2403
+ "span",
2404
+ {
2405
+ className: "absolute font-semibold tabular-nums text-white select-none",
2406
+ style: { lineHeight: 1 },
2407
+ children: Math.max(0, Math.ceil(remaining))
2408
+ }
2409
+ )
2410
+ ] });
2411
+ }
2412
+ function StageProgress({ stages, activeStage, className }) {
2413
+ const clampedActive = Math.max(0, Math.min(activeStage, stages.length - 1));
2414
+ const fillPercent = stages.length <= 1 ? 100 : clampedActive / (stages.length - 1) * 100;
2415
+ const isComplete = clampedActive >= stages.length - 1;
2416
+ const isAnimating = !isComplete;
2417
+ return /* @__PURE__ */ jsxs("div", { className: cn("w-full", className), children: [
2418
+ /* @__PURE__ */ jsx("div", { className: "flex justify-between", children: stages.map((stage, index) => {
2419
+ const isCompleted = index < clampedActive;
2420
+ const isActive = index === clampedActive;
2421
+ return /* @__PURE__ */ jsxs(
2422
+ "div",
2423
+ {
2424
+ className: cn(
2425
+ "flex items-center gap-1.5 text-xs font-medium transition-colors duration-300",
2426
+ isCompleted && "text-emerald-400",
2427
+ isActive && "text-white",
2428
+ !isCompleted && !isActive && "text-white/40"
2429
+ ),
2430
+ children: [
2431
+ isCompleted ? (
2432
+ // Completed: emerald check circle
2433
+ /* @__PURE__ */ jsx("span", { className: "flex h-3.5 w-3.5 items-center justify-center rounded-full bg-emerald-400/20", children: /* @__PURE__ */ jsx(
2434
+ "svg",
2435
+ {
2436
+ className: "h-2.5 w-2.5 text-emerald-400",
2437
+ viewBox: "0 0 10 10",
2438
+ fill: "none",
2439
+ xmlns: "http://www.w3.org/2000/svg",
2440
+ "aria-hidden": "true",
2441
+ children: /* @__PURE__ */ jsx(
2442
+ "path",
2443
+ {
2444
+ d: "M2 5.5L4 7.5L8 3",
2445
+ stroke: "currentColor",
2446
+ strokeWidth: "1.5",
2447
+ strokeLinecap: "round",
2448
+ strokeLinejoin: "round"
2449
+ }
2450
+ )
2451
+ }
2452
+ ) })
2453
+ ) : isActive ? (
2454
+ // Active: primary dot with ring
2455
+ /* @__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)]" }) })
2456
+ ) : (
2457
+ // Upcoming: hollow dim dot
2458
+ /* @__PURE__ */ jsx("span", { className: "h-3.5 w-3.5 rounded-full border border-white/20 bg-transparent" })
2459
+ ),
2460
+ stage
2461
+ ]
2462
+ },
2463
+ stage
2464
+ );
2465
+ }) }),
2466
+ /* @__PURE__ */ jsx(
2467
+ "div",
2468
+ {
2469
+ className: "relative mt-3 h-1.5 w-full overflow-hidden rounded-full bg-white/10",
2470
+ role: "progressbar",
2471
+ "aria-valuenow": clampedActive,
2472
+ "aria-valuemin": 0,
2473
+ "aria-valuemax": stages.length - 1,
2474
+ "aria-label": `Stage ${clampedActive + 1} of ${stages.length}: ${stages[clampedActive]}`,
2475
+ children: /* @__PURE__ */ jsx(
2476
+ "div",
2477
+ {
2478
+ className: "h-full rounded-full bg-gradient-to-r from-[var(--ml-accent)] to-[var(--ml-primary)] transition-[width] duration-500 ease-in-out",
2479
+ style: { width: `${fillPercent}%` },
2480
+ children: isAnimating && /* @__PURE__ */ jsx(
2481
+ "span",
2482
+ {
2483
+ 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",
2484
+ "aria-hidden": "true"
2485
+ }
2486
+ )
2487
+ }
2488
+ )
2489
+ }
2490
+ )
2491
+ ] });
2492
+ }
2493
+ function getUrgencyClasses(remaining, max) {
2494
+ const ratio = max > 0 ? remaining / max : 0;
2495
+ if (ratio > 0.5) {
2496
+ return {
2497
+ filled: "bg-emerald-400",
2498
+ empty: "bg-emerald-400/30",
2499
+ label: "text-emerald-400"
2500
+ };
2501
+ }
2502
+ if (ratio > 0.25) {
2503
+ return {
2504
+ filled: "bg-amber-400",
2505
+ empty: "bg-amber-400/30",
2506
+ label: "text-amber-400"
2507
+ };
2508
+ }
2509
+ return {
2510
+ filled: "bg-rose-400",
2511
+ empty: "bg-rose-400/30",
2512
+ label: "text-rose-400"
2513
+ };
2514
+ }
2515
+ function DotIndicator({
2516
+ remaining,
2517
+ max,
2518
+ showLabel = false,
2519
+ labelFormat,
2520
+ className
2521
+ }) {
2522
+ const clampedRemaining = Math.max(0, Math.min(remaining, max));
2523
+ const used = max - clampedRemaining;
2524
+ const urgency = getUrgencyClasses(clampedRemaining, max);
2525
+ const defaultLabel = `${clampedRemaining}/${max}`;
2526
+ const label = labelFormat ? labelFormat(clampedRemaining, max) : defaultLabel;
2527
+ return /* @__PURE__ */ jsxs("div", { className: cn("inline-flex items-center gap-2", className), children: [
2528
+ /* @__PURE__ */ jsx(
2529
+ "div",
2530
+ {
2531
+ className: "flex items-center gap-1",
2532
+ role: "meter",
2533
+ "aria-valuenow": clampedRemaining,
2534
+ "aria-valuemin": 0,
2535
+ "aria-valuemax": max,
2536
+ "aria-label": label,
2537
+ children: Array.from({ length: max }, (_, index) => {
2538
+ const isFilled = index < used;
2539
+ return /* @__PURE__ */ jsx(
2540
+ "span",
2541
+ {
2542
+ className: cn(
2543
+ "h-2 w-2 rounded-full transition-colors duration-300",
2544
+ isFilled ? urgency.filled : urgency.empty
2545
+ ),
2546
+ "aria-hidden": "true"
2547
+ },
2548
+ index
2549
+ );
2550
+ })
2551
+ }
2552
+ ),
2553
+ showLabel && /* @__PURE__ */ jsx("span", { className: cn("text-xs font-medium tabular-nums", urgency.label), children: label })
2554
+ ] });
2555
+ }
2556
+ function ActiveFilterPills({
2557
+ filters,
2558
+ onRemove,
2559
+ onClearAll,
2560
+ clearAllLabel = "Clear all",
2561
+ className
2562
+ }) {
2563
+ if (filters.length === 0) return null;
2564
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-wrap items-center gap-1.5", className), children: [
2565
+ filters.map((filter) => /* @__PURE__ */ jsxs(
2566
+ "span",
2567
+ {
2568
+ 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",
2569
+ children: [
2570
+ filter.label,
2571
+ /* @__PURE__ */ jsx(
2572
+ "button",
2573
+ {
2574
+ type: "button",
2575
+ onClick: () => onRemove(filter.key),
2576
+ className: "ml-0.5 text-white/50 transition-colors duration-150 hover:text-white focus:outline-none focus-visible:text-white",
2577
+ "aria-label": `Remove filter: ${filter.label}`,
2578
+ children: /* @__PURE__ */ jsx(
2579
+ "svg",
2580
+ {
2581
+ className: "h-3 w-3",
2582
+ viewBox: "0 0 12 12",
2583
+ fill: "none",
2584
+ xmlns: "http://www.w3.org/2000/svg",
2585
+ "aria-hidden": "true",
2586
+ children: /* @__PURE__ */ jsx(
2587
+ "path",
2588
+ {
2589
+ d: "M9 3L3 9M3 3L9 9",
2590
+ stroke: "currentColor",
2591
+ strokeWidth: "1.5",
2592
+ strokeLinecap: "round"
2593
+ }
2594
+ )
2595
+ }
2596
+ )
2597
+ }
2598
+ )
2599
+ ]
2600
+ },
2601
+ filter.key
2602
+ )),
2603
+ filters.length > 1 && onClearAll && /* @__PURE__ */ jsx(
2604
+ "button",
2605
+ {
2606
+ type: "button",
2607
+ onClick: onClearAll,
2608
+ 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",
2609
+ children: clearAllLabel
2610
+ }
2611
+ )
2612
+ ] });
2613
+ }
2614
+ function SectionCard({
2615
+ title,
2616
+ description,
2617
+ right,
2618
+ overlay,
2619
+ children,
2620
+ className
2621
+ }) {
2622
+ return /* @__PURE__ */ jsxs(
2623
+ "div",
2624
+ {
2625
+ className: cn(
2626
+ "relative bg-white/5 ring-1 ring-white/10 rounded-xl overflow-hidden",
2627
+ className
2628
+ ),
2629
+ children: [
2630
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3 px-5 py-4 border-b border-white/[0.06]", children: [
2631
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
2632
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-white", children: title }),
2633
+ description && /* @__PURE__ */ jsx("p", { className: "text-xs text-white/40 mt-0.5", children: description })
2634
+ ] }),
2635
+ right && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: right })
2636
+ ] }),
2637
+ /* @__PURE__ */ jsx("div", { className: "px-5 py-4", children }),
2638
+ overlay
2639
+ ]
2640
+ }
2641
+ );
2642
+ }
2254
2643
  var maxWidthClass = {
2255
2644
  sm: "max-w-2xl",
2256
2645
  md: "max-w-4xl",
@@ -2899,5 +3288,187 @@ function useToast() {
2899
3288
  }
2900
3289
  return ctx;
2901
3290
  }
3291
+ function SavingIcon() {
3292
+ return /* @__PURE__ */ jsxs(
3293
+ "svg",
3294
+ {
3295
+ className: "h-5 w-5 animate-spin text-white/70",
3296
+ viewBox: "0 0 24 24",
3297
+ fill: "none",
3298
+ "aria-hidden": "true",
3299
+ children: [
3300
+ /* @__PURE__ */ jsx(
3301
+ "circle",
3302
+ {
3303
+ className: "opacity-25",
3304
+ cx: "12",
3305
+ cy: "12",
3306
+ r: "10",
3307
+ stroke: "currentColor",
3308
+ strokeWidth: "4"
3309
+ }
3310
+ ),
3311
+ /* @__PURE__ */ jsx(
3312
+ "path",
3313
+ {
3314
+ className: "opacity-75",
3315
+ fill: "currentColor",
3316
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
3317
+ }
3318
+ )
3319
+ ]
3320
+ }
3321
+ );
3322
+ }
3323
+ function SavedIcon() {
3324
+ return /* @__PURE__ */ jsxs(
3325
+ "svg",
3326
+ {
3327
+ className: "h-5 w-5 text-green-400",
3328
+ viewBox: "0 0 24 24",
3329
+ fill: "none",
3330
+ stroke: "currentColor",
3331
+ strokeWidth: 2,
3332
+ "aria-hidden": "true",
3333
+ children: [
3334
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", strokeOpacity: 0.4 }),
3335
+ /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 12l2 2 4-4" })
3336
+ ]
3337
+ }
3338
+ );
3339
+ }
3340
+ function ErrorIcon2() {
3341
+ return /* @__PURE__ */ jsxs(
3342
+ "svg",
3343
+ {
3344
+ className: "h-5 w-5 text-red-400",
3345
+ viewBox: "0 0 24 24",
3346
+ fill: "none",
3347
+ stroke: "currentColor",
3348
+ strokeWidth: 2,
3349
+ "aria-hidden": "true",
3350
+ children: [
3351
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", strokeOpacity: 0.4 }),
3352
+ /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 9l-6 6M9 9l6 6" })
3353
+ ]
3354
+ }
3355
+ );
3356
+ }
3357
+ var statusConfig = {
3358
+ saving: {
3359
+ icon: SavingIcon,
3360
+ defaultText: "Saving...",
3361
+ textClass: "text-white/70"
3362
+ },
3363
+ saved: {
3364
+ icon: SavedIcon,
3365
+ defaultText: "Saved",
3366
+ textClass: "text-green-400"
3367
+ },
3368
+ error: {
3369
+ icon: ErrorIcon2,
3370
+ defaultText: "Error",
3371
+ textClass: "text-red-400"
3372
+ }
3373
+ };
3374
+ function MutationOverlay({
3375
+ status,
3376
+ savingText,
3377
+ savedText,
3378
+ errorText,
3379
+ className
3380
+ }) {
3381
+ if (status === "idle") return null;
3382
+ const config = statusConfig[status];
3383
+ const Icon = config.icon;
3384
+ const text = status === "saving" ? savingText ?? config.defaultText : status === "saved" ? savedText ?? config.defaultText : errorText ?? config.defaultText;
3385
+ return /* @__PURE__ */ jsx(
3386
+ "div",
3387
+ {
3388
+ className: cn(
3389
+ "absolute inset-0 z-10 flex items-center justify-center",
3390
+ "bg-surface-50/80 backdrop-blur-sm",
3391
+ "transition-opacity duration-200",
3392
+ className
3393
+ ),
3394
+ role: "status",
3395
+ "aria-live": "polite",
3396
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3397
+ /* @__PURE__ */ jsx(Icon, {}),
3398
+ /* @__PURE__ */ jsx("span", { className: cn("text-sm font-medium", config.textClass), children: text })
3399
+ ] })
3400
+ }
3401
+ );
3402
+ }
3403
+ var sizeClass6 = {
3404
+ sm: "w-8 h-8",
3405
+ md: "w-10 h-10",
3406
+ lg: "w-12 h-12"
3407
+ };
3408
+ var iconSizeClass = {
3409
+ sm: "w-4 h-4",
3410
+ md: "w-5 h-5",
3411
+ lg: "w-6 h-6"
3412
+ };
3413
+ var badgeSizeClass = {
3414
+ sm: "min-w-[16px] h-4 text-[10px] px-1",
3415
+ md: "min-w-[18px] h-[18px] text-[11px] px-1",
3416
+ lg: "min-w-[20px] h-5 text-xs px-1.5"
3417
+ };
3418
+ var DefaultBellIcon = ({ className }) => /* @__PURE__ */ jsxs(
3419
+ "svg",
3420
+ {
3421
+ xmlns: "http://www.w3.org/2000/svg",
3422
+ viewBox: "0 0 24 24",
3423
+ fill: "none",
3424
+ stroke: "currentColor",
3425
+ strokeWidth: 2,
3426
+ strokeLinecap: "round",
3427
+ strokeLinejoin: "round",
3428
+ className,
3429
+ "aria-hidden": "true",
3430
+ children: [
3431
+ /* @__PURE__ */ jsx("path", { d: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" }),
3432
+ /* @__PURE__ */ jsx("path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0" })
3433
+ ]
3434
+ }
3435
+ );
3436
+ var NotificationBell = forwardRef(
3437
+ function NotificationBell2({ icon, count, maxCount = 99, size = "md", ping, className, disabled, ...props }, ref) {
3438
+ const displayCount = count && count > maxCount ? `${maxCount}+` : count;
3439
+ const hasCount = count !== void 0 && count > 0;
3440
+ return /* @__PURE__ */ jsxs(
3441
+ "button",
3442
+ {
3443
+ ref,
3444
+ type: "button",
3445
+ ...props,
3446
+ disabled,
3447
+ "aria-label": props["aria-label"] || `Notifications${hasCount ? ` (${count})` : ""}`,
3448
+ className: cn(
3449
+ "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",
3450
+ sizeClass6[size],
3451
+ className
3452
+ ),
3453
+ children: [
3454
+ icon ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: icon }) : /* @__PURE__ */ jsx(DefaultBellIcon, { className: iconSizeClass[size] }),
3455
+ hasCount && /* @__PURE__ */ jsxs(
3456
+ "span",
3457
+ {
3458
+ className: cn(
3459
+ "absolute top-0 right-0 flex items-center justify-center rounded-full bg-rose-500 text-white font-semibold leading-none",
3460
+ badgeSizeClass[size]
3461
+ ),
3462
+ children: [
3463
+ ping && /* @__PURE__ */ jsx("span", { className: "absolute inset-0 rounded-full bg-rose-500 animate-ping opacity-75" }),
3464
+ /* @__PURE__ */ jsx("span", { className: "relative", children: displayCount })
3465
+ ]
3466
+ }
3467
+ )
3468
+ ]
3469
+ }
3470
+ );
3471
+ }
3472
+ );
2902
3473
 
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 };
3474
+ 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, NotificationBell, 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, useHotkeys, useIntersectionObserver, useMediaQuery, useSharedNow, useToast };