@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/README.md +18 -3
- package/dist/index.cjs +584 -3
- package/dist/index.d.cts +151 -1
- package/dist/index.d.ts +151 -1
- package/dist/index.js +575 -4
- package/dist/styles/index.css +170 -0
- package/package.json +1 -1
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;
|