@almadar/ui 2.5.2 → 2.7.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/{chunk-2UMN2BLO.js → chunk-2QM732NQ.js} +47 -4
- package/dist/{chunk-45CTDYBT.js → chunk-RPYMP7ZC.js} +137 -1
- package/dist/{chunk-AL6BLHMG.js → chunk-VJP2HCLY.js} +2952 -461
- package/dist/{chunk-GOZKH7QW.js → chunk-WGJIL4YR.js} +267 -2
- package/dist/components/index.d.ts +527 -68
- package/dist/components/index.js +226 -321
- package/dist/hooks/index.d.ts +133 -3
- package/dist/hooks/index.js +3 -3
- package/dist/lib/index.d.ts +33 -2
- package/dist/lib/index.js +1 -2
- package/dist/providers/index.js +4 -5
- package/package.json +1 -1
- package/dist/chunk-KKCVDUK7.js +0 -104
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { useTheme, useUISlots } from './chunk-DKQN5FVU.js';
|
|
2
|
-
import { useTranslate, useQuerySingleton } from './chunk-
|
|
2
|
+
import { useTranslate, useInfiniteScroll, useQuerySingleton, useLongPress, useSwipeGesture, useDragReorder, usePullToRefresh } from './chunk-WGJIL4YR.js';
|
|
3
3
|
import { useEventBus } from './chunk-YXZM3WCF.js';
|
|
4
|
-
import { cn, debugGroup, debug, debugGroupEnd, getNestedValue, isDebugEnabled } from './chunk-
|
|
4
|
+
import { cn, debugGroup, debug, debugGroupEnd, getNestedValue, isDebugEnabled } from './chunk-RPYMP7ZC.js';
|
|
5
5
|
import { isPortalSlot } from './chunk-K2D5D3WK.js';
|
|
6
6
|
import { __publicField } from './chunk-PKBMQBKP.js';
|
|
7
7
|
import * as LucideIcons from 'lucide-react';
|
|
8
|
-
import { Loader2, ChevronDown, X, Check, Copy, AlertCircle, User, Sun, Moon, FileQuestion, Inbox, Search, Info, XCircle, CheckCircle, AlertTriangle, ChevronRight, Filter, Plus, ChevronLeft, HelpCircle, ChevronUp,
|
|
8
|
+
import { Loader2, ChevronDown, X, ArrowRight, TrendingDown, TrendingUp, Check, Copy, AlertCircle, User, Sun, Moon, FileQuestion, Inbox, Search, Info, XCircle, CheckCircle, AlertTriangle, ChevronRight, Filter, Plus, ChevronLeft, HelpCircle, ChevronUp, Minus, Star, FileWarning, Upload, MoreHorizontal, ArrowLeft, Calendar, Tag, Clock, CheckCircle2, DollarSign, FileText, Package } from 'lucide-react';
|
|
9
9
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
10
|
-
import * as
|
|
11
|
-
import
|
|
10
|
+
import * as React69 from 'react';
|
|
11
|
+
import React69__default, { useCallback, useState, useRef, useLayoutEffect, useEffect, lazy, createContext, useMemo, useId, useContext, Suspense } from 'react';
|
|
12
12
|
import { evaluate, createMinimalContext } from '@almadar/evaluator';
|
|
13
13
|
import { createPortal } from 'react-dom';
|
|
14
14
|
import ReactMarkdown from 'react-markdown';
|
|
@@ -157,7 +157,7 @@ var iconSizeStyles = {
|
|
|
157
157
|
md: "h-4 w-4",
|
|
158
158
|
lg: "h-5 w-5"
|
|
159
159
|
};
|
|
160
|
-
var Button =
|
|
160
|
+
var Button = React69__default.forwardRef(
|
|
161
161
|
({
|
|
162
162
|
className,
|
|
163
163
|
variant = "primary",
|
|
@@ -215,7 +215,7 @@ var Button = React50__default.forwardRef(
|
|
|
215
215
|
}
|
|
216
216
|
);
|
|
217
217
|
Button.displayName = "Button";
|
|
218
|
-
var Input =
|
|
218
|
+
var Input = React69__default.forwardRef(
|
|
219
219
|
({
|
|
220
220
|
className,
|
|
221
221
|
inputType,
|
|
@@ -327,7 +327,7 @@ var Input = React50__default.forwardRef(
|
|
|
327
327
|
}
|
|
328
328
|
);
|
|
329
329
|
Input.displayName = "Input";
|
|
330
|
-
var Label =
|
|
330
|
+
var Label = React69__default.forwardRef(
|
|
331
331
|
({ className, required, children, ...props }, ref) => {
|
|
332
332
|
return /* @__PURE__ */ jsxs(
|
|
333
333
|
"label",
|
|
@@ -347,7 +347,7 @@ var Label = React50__default.forwardRef(
|
|
|
347
347
|
}
|
|
348
348
|
);
|
|
349
349
|
Label.displayName = "Label";
|
|
350
|
-
var Textarea =
|
|
350
|
+
var Textarea = React69__default.forwardRef(
|
|
351
351
|
({ className, error, ...props }, ref) => {
|
|
352
352
|
return /* @__PURE__ */ jsx(
|
|
353
353
|
"textarea",
|
|
@@ -370,7 +370,7 @@ var Textarea = React50__default.forwardRef(
|
|
|
370
370
|
}
|
|
371
371
|
);
|
|
372
372
|
Textarea.displayName = "Textarea";
|
|
373
|
-
var Select =
|
|
373
|
+
var Select = React69__default.forwardRef(
|
|
374
374
|
({ className, options, placeholder, error, ...props }, ref) => {
|
|
375
375
|
return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
376
376
|
/* @__PURE__ */ jsxs(
|
|
@@ -406,7 +406,7 @@ var Select = React50__default.forwardRef(
|
|
|
406
406
|
}
|
|
407
407
|
);
|
|
408
408
|
Select.displayName = "Select";
|
|
409
|
-
var Checkbox =
|
|
409
|
+
var Checkbox = React69__default.forwardRef(
|
|
410
410
|
({ className, label, id, ...props }, ref) => {
|
|
411
411
|
const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
|
|
412
412
|
return /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
|
@@ -472,7 +472,7 @@ var shadowStyles = {
|
|
|
472
472
|
md: "shadow-[var(--shadow-main)]",
|
|
473
473
|
lg: "shadow-[var(--shadow-lg)]"
|
|
474
474
|
};
|
|
475
|
-
var Card =
|
|
475
|
+
var Card = React69__default.forwardRef(
|
|
476
476
|
({
|
|
477
477
|
className,
|
|
478
478
|
variant = "bordered",
|
|
@@ -508,9 +508,9 @@ var Card = React50__default.forwardRef(
|
|
|
508
508
|
}
|
|
509
509
|
);
|
|
510
510
|
Card.displayName = "Card";
|
|
511
|
-
var CardHeader =
|
|
511
|
+
var CardHeader = React69__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
|
|
512
512
|
CardHeader.displayName = "CardHeader";
|
|
513
|
-
var CardTitle =
|
|
513
|
+
var CardTitle = React69__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
514
514
|
"h3",
|
|
515
515
|
{
|
|
516
516
|
ref,
|
|
@@ -523,11 +523,11 @@ var CardTitle = React50__default.forwardRef(({ className, ...props }, ref) => /*
|
|
|
523
523
|
}
|
|
524
524
|
));
|
|
525
525
|
CardTitle.displayName = "CardTitle";
|
|
526
|
-
var CardContent =
|
|
526
|
+
var CardContent = React69__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
|
|
527
527
|
CardContent.displayName = "CardContent";
|
|
528
528
|
var CardBody = CardContent;
|
|
529
529
|
CardBody.displayName = "CardBody";
|
|
530
|
-
var CardFooter =
|
|
530
|
+
var CardFooter = React69__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
531
531
|
"div",
|
|
532
532
|
{
|
|
533
533
|
ref,
|
|
@@ -573,8 +573,8 @@ var sizeStyles2 = {
|
|
|
573
573
|
md: "px-2.5 py-1 text-sm",
|
|
574
574
|
lg: "px-3 py-1.5 text-base"
|
|
575
575
|
};
|
|
576
|
-
var Badge =
|
|
577
|
-
({ className, variant = "default", size = "sm", label, icon, children, ...props }, ref) => {
|
|
576
|
+
var Badge = React69__default.forwardRef(
|
|
577
|
+
({ className, variant = "default", size = "sm", amount, label, icon, children, ...props }, ref) => {
|
|
578
578
|
const iconSizes2 = { sm: "w-3 h-3", md: "w-3.5 h-3.5", lg: "w-4 h-4" };
|
|
579
579
|
const resolvedIcon = typeof icon === "string" ? (() => {
|
|
580
580
|
const I = resolveIcon(icon);
|
|
@@ -593,7 +593,7 @@ var Badge = React50__default.forwardRef(
|
|
|
593
593
|
...props,
|
|
594
594
|
children: [
|
|
595
595
|
resolvedIcon,
|
|
596
|
-
children || label
|
|
596
|
+
children || (amount != null ? `${label ? `${label} ` : ""}${amount}` : label)
|
|
597
597
|
]
|
|
598
598
|
}
|
|
599
599
|
);
|
|
@@ -606,7 +606,7 @@ var sizeStyles3 = {
|
|
|
606
606
|
md: "h-6 w-6",
|
|
607
607
|
lg: "h-8 w-8"
|
|
608
608
|
};
|
|
609
|
-
var Spinner =
|
|
609
|
+
var Spinner = React69__default.forwardRef(
|
|
610
610
|
({ className, size = "md", ...props }, ref) => {
|
|
611
611
|
return /* @__PURE__ */ jsx(
|
|
612
612
|
"div",
|
|
@@ -871,7 +871,7 @@ var positionStyles = {
|
|
|
871
871
|
fixed: "fixed",
|
|
872
872
|
sticky: "sticky"
|
|
873
873
|
};
|
|
874
|
-
var Box =
|
|
874
|
+
var Box = React69__default.forwardRef(
|
|
875
875
|
({
|
|
876
876
|
padding,
|
|
877
877
|
paddingX,
|
|
@@ -1216,7 +1216,7 @@ var ProgressBar = ({
|
|
|
1216
1216
|
return null;
|
|
1217
1217
|
};
|
|
1218
1218
|
ProgressBar.displayName = "ProgressBar";
|
|
1219
|
-
var Radio =
|
|
1219
|
+
var Radio = React69__default.forwardRef(
|
|
1220
1220
|
({
|
|
1221
1221
|
label,
|
|
1222
1222
|
helperText,
|
|
@@ -1320,7 +1320,7 @@ var Radio = React50__default.forwardRef(
|
|
|
1320
1320
|
}
|
|
1321
1321
|
);
|
|
1322
1322
|
Radio.displayName = "Radio";
|
|
1323
|
-
var Switch =
|
|
1323
|
+
var Switch = React69.forwardRef(
|
|
1324
1324
|
({
|
|
1325
1325
|
checked,
|
|
1326
1326
|
defaultChecked = false,
|
|
@@ -1331,10 +1331,10 @@ var Switch = React50.forwardRef(
|
|
|
1331
1331
|
name,
|
|
1332
1332
|
className
|
|
1333
1333
|
}, ref) => {
|
|
1334
|
-
const [isChecked, setIsChecked] =
|
|
1334
|
+
const [isChecked, setIsChecked] = React69.useState(
|
|
1335
1335
|
checked !== void 0 ? checked : defaultChecked
|
|
1336
1336
|
);
|
|
1337
|
-
|
|
1337
|
+
React69.useEffect(() => {
|
|
1338
1338
|
if (checked !== void 0) {
|
|
1339
1339
|
setIsChecked(checked);
|
|
1340
1340
|
}
|
|
@@ -1467,7 +1467,8 @@ var Stack = ({
|
|
|
1467
1467
|
role,
|
|
1468
1468
|
tabIndex,
|
|
1469
1469
|
action,
|
|
1470
|
-
actionPayload
|
|
1470
|
+
actionPayload,
|
|
1471
|
+
responsive = false
|
|
1471
1472
|
}) => {
|
|
1472
1473
|
const eventBus = useEventBus();
|
|
1473
1474
|
const handleClick = (e) => {
|
|
@@ -1476,7 +1477,8 @@ var Stack = ({
|
|
|
1476
1477
|
}
|
|
1477
1478
|
onClick?.(e);
|
|
1478
1479
|
};
|
|
1479
|
-
const
|
|
1480
|
+
const isHorizontal = direction === "horizontal";
|
|
1481
|
+
const directionClass = responsive && isHorizontal ? reverse ? "flex-col-reverse md:flex-row-reverse" : "flex-col md:flex-row" : isHorizontal ? reverse ? "flex-row-reverse" : "flex-row" : reverse ? "flex-col-reverse" : "flex-col";
|
|
1480
1482
|
return /* @__PURE__ */ jsx(
|
|
1481
1483
|
Component,
|
|
1482
1484
|
{
|
|
@@ -2005,8 +2007,8 @@ var LawReferenceTooltip = ({
|
|
|
2005
2007
|
position = "top",
|
|
2006
2008
|
className
|
|
2007
2009
|
}) => {
|
|
2008
|
-
const [isVisible, setIsVisible] =
|
|
2009
|
-
const timeoutRef =
|
|
2010
|
+
const [isVisible, setIsVisible] = React69__default.useState(false);
|
|
2011
|
+
const timeoutRef = React69__default.useRef(null);
|
|
2010
2012
|
const handleMouseEnter = () => {
|
|
2011
2013
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
2012
2014
|
timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
|
|
@@ -2015,7 +2017,7 @@ var LawReferenceTooltip = ({
|
|
|
2015
2017
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
2016
2018
|
setIsVisible(false);
|
|
2017
2019
|
};
|
|
2018
|
-
|
|
2020
|
+
React69__default.useEffect(() => {
|
|
2019
2021
|
return () => {
|
|
2020
2022
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
2021
2023
|
};
|
|
@@ -2182,6 +2184,567 @@ function TimeSlotCell({
|
|
|
2182
2184
|
);
|
|
2183
2185
|
}
|
|
2184
2186
|
TimeSlotCell.displayName = "TimeSlotCell";
|
|
2187
|
+
var statusColors = {
|
|
2188
|
+
online: "bg-[var(--color-success)]",
|
|
2189
|
+
offline: "bg-[var(--color-muted-foreground)]",
|
|
2190
|
+
away: "bg-[var(--color-warning)]",
|
|
2191
|
+
busy: "bg-[var(--color-error)]",
|
|
2192
|
+
warning: "bg-[var(--color-warning)]",
|
|
2193
|
+
critical: "bg-[var(--color-error)]"
|
|
2194
|
+
};
|
|
2195
|
+
var pulseRingColors = {
|
|
2196
|
+
online: "ring-[var(--color-success)]",
|
|
2197
|
+
offline: "ring-[var(--color-muted-foreground)]",
|
|
2198
|
+
away: "ring-[var(--color-warning)]",
|
|
2199
|
+
busy: "ring-[var(--color-error)]",
|
|
2200
|
+
warning: "ring-[var(--color-warning)]",
|
|
2201
|
+
critical: "ring-[var(--color-error)]"
|
|
2202
|
+
};
|
|
2203
|
+
var sizeStyles5 = {
|
|
2204
|
+
sm: "w-2 h-2",
|
|
2205
|
+
md: "w-2.5 h-2.5",
|
|
2206
|
+
lg: "w-3 h-3"
|
|
2207
|
+
};
|
|
2208
|
+
var StatusDot = React69__default.forwardRef(
|
|
2209
|
+
({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
|
|
2210
|
+
return /* @__PURE__ */ jsx(
|
|
2211
|
+
"span",
|
|
2212
|
+
{
|
|
2213
|
+
ref,
|
|
2214
|
+
className: cn(
|
|
2215
|
+
"inline-block rounded-full flex-shrink-0",
|
|
2216
|
+
statusColors[status],
|
|
2217
|
+
sizeStyles5[size],
|
|
2218
|
+
pulse && [
|
|
2219
|
+
"animate-pulse",
|
|
2220
|
+
"ring-2 ring-offset-1",
|
|
2221
|
+
pulseRingColors[status],
|
|
2222
|
+
"ring-opacity-40"
|
|
2223
|
+
],
|
|
2224
|
+
className
|
|
2225
|
+
),
|
|
2226
|
+
role: "status",
|
|
2227
|
+
"aria-label": label ?? status,
|
|
2228
|
+
...props
|
|
2229
|
+
}
|
|
2230
|
+
);
|
|
2231
|
+
}
|
|
2232
|
+
);
|
|
2233
|
+
StatusDot.displayName = "StatusDot";
|
|
2234
|
+
var sizeStyles6 = {
|
|
2235
|
+
sm: { icon: "w-3 h-3", text: "text-xs" },
|
|
2236
|
+
md: { icon: "w-4 h-4", text: "text-sm" },
|
|
2237
|
+
lg: { icon: "w-5 h-5", text: "text-base" }
|
|
2238
|
+
};
|
|
2239
|
+
function resolveDirection(value, direction) {
|
|
2240
|
+
if (direction) return direction;
|
|
2241
|
+
if (value === void 0 || value === 0) return "flat";
|
|
2242
|
+
return value > 0 ? "up" : "down";
|
|
2243
|
+
}
|
|
2244
|
+
function resolveColor(dir, invert) {
|
|
2245
|
+
if (dir === "flat") return "text-[var(--color-muted-foreground)]";
|
|
2246
|
+
const isPositive = dir === "up";
|
|
2247
|
+
const isGood = invert ? !isPositive : isPositive;
|
|
2248
|
+
return isGood ? "text-[var(--color-success)]" : "text-[var(--color-error)]";
|
|
2249
|
+
}
|
|
2250
|
+
var iconMap = {
|
|
2251
|
+
up: TrendingUp,
|
|
2252
|
+
down: TrendingDown,
|
|
2253
|
+
flat: ArrowRight
|
|
2254
|
+
};
|
|
2255
|
+
var TrendIndicator = React69__default.forwardRef(
|
|
2256
|
+
({
|
|
2257
|
+
className,
|
|
2258
|
+
value,
|
|
2259
|
+
direction,
|
|
2260
|
+
showValue = true,
|
|
2261
|
+
invert = false,
|
|
2262
|
+
label,
|
|
2263
|
+
size = "md",
|
|
2264
|
+
...props
|
|
2265
|
+
}, ref) => {
|
|
2266
|
+
const dir = resolveDirection(value, direction);
|
|
2267
|
+
const colorClass = resolveColor(dir, invert);
|
|
2268
|
+
const IconComponent = iconMap[dir];
|
|
2269
|
+
const styles = sizeStyles6[size];
|
|
2270
|
+
const formattedValue = value !== void 0 ? `${value > 0 ? "+" : ""}${value}%` : void 0;
|
|
2271
|
+
const ariaLabel = label ?? (formattedValue ? `${dir} ${formattedValue}` : dir);
|
|
2272
|
+
return /* @__PURE__ */ jsxs(
|
|
2273
|
+
"span",
|
|
2274
|
+
{
|
|
2275
|
+
ref,
|
|
2276
|
+
className: cn(
|
|
2277
|
+
"inline-flex items-center gap-1 font-medium",
|
|
2278
|
+
colorClass,
|
|
2279
|
+
styles.text,
|
|
2280
|
+
className
|
|
2281
|
+
),
|
|
2282
|
+
role: "status",
|
|
2283
|
+
"aria-label": ariaLabel,
|
|
2284
|
+
...props,
|
|
2285
|
+
children: [
|
|
2286
|
+
/* @__PURE__ */ jsx(IconComponent, { className: styles.icon }),
|
|
2287
|
+
showValue && formattedValue && /* @__PURE__ */ jsx("span", { children: formattedValue })
|
|
2288
|
+
]
|
|
2289
|
+
}
|
|
2290
|
+
);
|
|
2291
|
+
}
|
|
2292
|
+
);
|
|
2293
|
+
TrendIndicator.displayName = "TrendIndicator";
|
|
2294
|
+
function useSafeEventBus() {
|
|
2295
|
+
try {
|
|
2296
|
+
return useEventBus();
|
|
2297
|
+
} catch {
|
|
2298
|
+
return { emit: () => {
|
|
2299
|
+
}, on: () => () => {
|
|
2300
|
+
}, once: () => {
|
|
2301
|
+
} };
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
var trackSizes = {
|
|
2305
|
+
sm: "h-1",
|
|
2306
|
+
md: "h-1.5",
|
|
2307
|
+
lg: "h-2"
|
|
2308
|
+
};
|
|
2309
|
+
var thumbSizes = {
|
|
2310
|
+
sm: "w-3 h-3",
|
|
2311
|
+
md: "w-4 h-4",
|
|
2312
|
+
lg: "w-5 h-5"
|
|
2313
|
+
};
|
|
2314
|
+
var RangeSlider = React69__default.forwardRef(
|
|
2315
|
+
({
|
|
2316
|
+
className,
|
|
2317
|
+
min = 0,
|
|
2318
|
+
max = 100,
|
|
2319
|
+
value = 0,
|
|
2320
|
+
step = 1,
|
|
2321
|
+
showTooltip = false,
|
|
2322
|
+
showTicks = false,
|
|
2323
|
+
buffered,
|
|
2324
|
+
size = "md",
|
|
2325
|
+
disabled = false,
|
|
2326
|
+
action,
|
|
2327
|
+
actionPayload,
|
|
2328
|
+
onChange,
|
|
2329
|
+
formatValue: formatValue4,
|
|
2330
|
+
...props
|
|
2331
|
+
}, ref) => {
|
|
2332
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
2333
|
+
const [showTip, setShowTip] = useState(false);
|
|
2334
|
+
const inputRef = useRef(null);
|
|
2335
|
+
const eventBus = useSafeEventBus();
|
|
2336
|
+
const percentage = max !== min ? (value - min) / (max - min) * 100 : 0;
|
|
2337
|
+
const bufferedPercentage = buffered !== void 0 ? Math.min(buffered, 100) : void 0;
|
|
2338
|
+
const displayValue = formatValue4 ? formatValue4(value) : String(value);
|
|
2339
|
+
const handleChange = useCallback(
|
|
2340
|
+
(e) => {
|
|
2341
|
+
const newValue = Number(e.target.value);
|
|
2342
|
+
onChange?.(newValue);
|
|
2343
|
+
if (action) {
|
|
2344
|
+
eventBus.emit(`UI:${action}`, { ...actionPayload, value: newValue });
|
|
2345
|
+
}
|
|
2346
|
+
},
|
|
2347
|
+
[onChange, action, actionPayload, eventBus]
|
|
2348
|
+
);
|
|
2349
|
+
const tickCount = showTicks ? Math.min(Math.floor((max - min) / step), 20) : 0;
|
|
2350
|
+
return /* @__PURE__ */ jsxs(
|
|
2351
|
+
"div",
|
|
2352
|
+
{
|
|
2353
|
+
ref,
|
|
2354
|
+
className: cn(
|
|
2355
|
+
"relative w-full",
|
|
2356
|
+
disabled && "opacity-50 cursor-not-allowed",
|
|
2357
|
+
className
|
|
2358
|
+
),
|
|
2359
|
+
...props,
|
|
2360
|
+
children: [
|
|
2361
|
+
/* @__PURE__ */ jsxs("div", { className: "relative w-full py-2", children: [
|
|
2362
|
+
/* @__PURE__ */ jsx(
|
|
2363
|
+
"div",
|
|
2364
|
+
{
|
|
2365
|
+
className: cn(
|
|
2366
|
+
"absolute inset-x-0 rounded-full bg-[var(--color-muted)]",
|
|
2367
|
+
trackSizes[size]
|
|
2368
|
+
),
|
|
2369
|
+
style: { top: "50%", transform: "translateY(-50%)" }
|
|
2370
|
+
}
|
|
2371
|
+
),
|
|
2372
|
+
bufferedPercentage !== void 0 && /* @__PURE__ */ jsx(
|
|
2373
|
+
"div",
|
|
2374
|
+
{
|
|
2375
|
+
className: cn(
|
|
2376
|
+
"absolute rounded-full bg-[var(--color-muted-foreground)] opacity-30",
|
|
2377
|
+
trackSizes[size]
|
|
2378
|
+
),
|
|
2379
|
+
style: {
|
|
2380
|
+
top: "50%",
|
|
2381
|
+
transform: "translateY(-50%)",
|
|
2382
|
+
left: 0,
|
|
2383
|
+
width: `${bufferedPercentage}%`
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
),
|
|
2387
|
+
/* @__PURE__ */ jsx(
|
|
2388
|
+
"div",
|
|
2389
|
+
{
|
|
2390
|
+
className: cn(
|
|
2391
|
+
"absolute rounded-full bg-[var(--color-primary)]",
|
|
2392
|
+
trackSizes[size]
|
|
2393
|
+
),
|
|
2394
|
+
style: {
|
|
2395
|
+
top: "50%",
|
|
2396
|
+
transform: "translateY(-50%)",
|
|
2397
|
+
left: 0,
|
|
2398
|
+
width: `${percentage}%`
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
),
|
|
2402
|
+
/* @__PURE__ */ jsx(
|
|
2403
|
+
"input",
|
|
2404
|
+
{
|
|
2405
|
+
ref: inputRef,
|
|
2406
|
+
type: "range",
|
|
2407
|
+
min,
|
|
2408
|
+
max,
|
|
2409
|
+
step,
|
|
2410
|
+
value,
|
|
2411
|
+
disabled,
|
|
2412
|
+
onChange: handleChange,
|
|
2413
|
+
onMouseDown: () => {
|
|
2414
|
+
setIsDragging(true);
|
|
2415
|
+
setShowTip(true);
|
|
2416
|
+
},
|
|
2417
|
+
onMouseUp: () => {
|
|
2418
|
+
setIsDragging(false);
|
|
2419
|
+
setShowTip(false);
|
|
2420
|
+
},
|
|
2421
|
+
onTouchStart: () => {
|
|
2422
|
+
setIsDragging(true);
|
|
2423
|
+
setShowTip(true);
|
|
2424
|
+
},
|
|
2425
|
+
onTouchEnd: () => {
|
|
2426
|
+
setIsDragging(false);
|
|
2427
|
+
setShowTip(false);
|
|
2428
|
+
},
|
|
2429
|
+
onFocus: () => setShowTip(true),
|
|
2430
|
+
onBlur: () => {
|
|
2431
|
+
if (!isDragging) setShowTip(false);
|
|
2432
|
+
},
|
|
2433
|
+
className: cn(
|
|
2434
|
+
"absolute inset-0 w-full opacity-0 cursor-pointer",
|
|
2435
|
+
disabled && "cursor-not-allowed",
|
|
2436
|
+
// Thumb sizing via pseudo-element
|
|
2437
|
+
"[&::-webkit-slider-thumb]:appearance-none",
|
|
2438
|
+
"[&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:h-5",
|
|
2439
|
+
"[&::-moz-range-thumb]:w-5 [&::-moz-range-thumb]:h-5"
|
|
2440
|
+
),
|
|
2441
|
+
style: { height: "100%", margin: 0 },
|
|
2442
|
+
"aria-label": props["aria-label"] ?? "Range slider",
|
|
2443
|
+
"aria-valuemin": min,
|
|
2444
|
+
"aria-valuemax": max,
|
|
2445
|
+
"aria-valuenow": value,
|
|
2446
|
+
"aria-valuetext": displayValue
|
|
2447
|
+
}
|
|
2448
|
+
),
|
|
2449
|
+
/* @__PURE__ */ jsx(
|
|
2450
|
+
"div",
|
|
2451
|
+
{
|
|
2452
|
+
className: cn(
|
|
2453
|
+
"absolute rounded-full bg-[var(--color-primary-foreground)]",
|
|
2454
|
+
"border-2 border-[var(--color-primary)]",
|
|
2455
|
+
"shadow-[var(--shadow-sm)]",
|
|
2456
|
+
"pointer-events-none",
|
|
2457
|
+
"transition-transform duration-100",
|
|
2458
|
+
isDragging && "scale-110",
|
|
2459
|
+
thumbSizes[size]
|
|
2460
|
+
),
|
|
2461
|
+
style: {
|
|
2462
|
+
top: "50%",
|
|
2463
|
+
transform: `translateY(-50%) translateX(-50%)${isDragging ? " scale(1.1)" : ""}`,
|
|
2464
|
+
left: `${percentage}%`
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
),
|
|
2468
|
+
showTooltip && showTip && /* @__PURE__ */ jsx(
|
|
2469
|
+
"div",
|
|
2470
|
+
{
|
|
2471
|
+
className: cn(
|
|
2472
|
+
"absolute -top-8 px-2 py-0.5 rounded",
|
|
2473
|
+
"bg-[var(--color-foreground)] text-[var(--color-background)]",
|
|
2474
|
+
"text-xs font-medium whitespace-nowrap",
|
|
2475
|
+
"pointer-events-none"
|
|
2476
|
+
),
|
|
2477
|
+
style: {
|
|
2478
|
+
left: `${percentage}%`,
|
|
2479
|
+
transform: "translateX(-50%)"
|
|
2480
|
+
},
|
|
2481
|
+
children: displayValue
|
|
2482
|
+
}
|
|
2483
|
+
)
|
|
2484
|
+
] }),
|
|
2485
|
+
showTicks && tickCount > 0 && /* @__PURE__ */ jsx("div", { className: "relative w-full h-2 mt-1", children: Array.from({ length: tickCount + 1 }, (_, i) => {
|
|
2486
|
+
const tickPercent = i / tickCount * 100;
|
|
2487
|
+
return /* @__PURE__ */ jsx(
|
|
2488
|
+
"div",
|
|
2489
|
+
{
|
|
2490
|
+
className: "absolute w-px h-1.5 bg-[var(--color-muted-foreground)]",
|
|
2491
|
+
style: { left: `${tickPercent}%` }
|
|
2492
|
+
},
|
|
2493
|
+
i
|
|
2494
|
+
);
|
|
2495
|
+
}) })
|
|
2496
|
+
]
|
|
2497
|
+
}
|
|
2498
|
+
);
|
|
2499
|
+
}
|
|
2500
|
+
);
|
|
2501
|
+
RangeSlider.displayName = "RangeSlider";
|
|
2502
|
+
function easeOut(t) {
|
|
2503
|
+
return t * (2 - t);
|
|
2504
|
+
}
|
|
2505
|
+
var AnimatedCounter = ({
|
|
2506
|
+
value,
|
|
2507
|
+
duration = 600,
|
|
2508
|
+
prefix,
|
|
2509
|
+
suffix,
|
|
2510
|
+
className
|
|
2511
|
+
}) => {
|
|
2512
|
+
const [displayValue, setDisplayValue] = useState(value);
|
|
2513
|
+
const previousValueRef = useRef(value);
|
|
2514
|
+
const animationFrameRef = useRef(null);
|
|
2515
|
+
useEffect(() => {
|
|
2516
|
+
const from = previousValueRef.current;
|
|
2517
|
+
const to = value;
|
|
2518
|
+
previousValueRef.current = value;
|
|
2519
|
+
if (from === to) {
|
|
2520
|
+
setDisplayValue(to);
|
|
2521
|
+
return;
|
|
2522
|
+
}
|
|
2523
|
+
const startTime = performance.now();
|
|
2524
|
+
const diff = to - from;
|
|
2525
|
+
function animate(currentTime) {
|
|
2526
|
+
const elapsed = currentTime - startTime;
|
|
2527
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
2528
|
+
const easedProgress = easeOut(progress);
|
|
2529
|
+
setDisplayValue(from + diff * easedProgress);
|
|
2530
|
+
if (progress < 1) {
|
|
2531
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
2532
|
+
} else {
|
|
2533
|
+
setDisplayValue(to);
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
2537
|
+
return () => {
|
|
2538
|
+
if (animationFrameRef.current !== null) {
|
|
2539
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
2540
|
+
}
|
|
2541
|
+
};
|
|
2542
|
+
}, [value, duration]);
|
|
2543
|
+
const decimalPlaces = Number.isInteger(value) ? 0 : String(value).split(".")[1]?.length ?? 0;
|
|
2544
|
+
const formattedValue = displayValue.toFixed(decimalPlaces);
|
|
2545
|
+
return /* @__PURE__ */ jsxs(Typography, { variant: "h3", className: cn("tabular-nums", className), children: [
|
|
2546
|
+
prefix,
|
|
2547
|
+
formattedValue,
|
|
2548
|
+
suffix
|
|
2549
|
+
] });
|
|
2550
|
+
};
|
|
2551
|
+
AnimatedCounter.displayName = "AnimatedCounter";
|
|
2552
|
+
var InfiniteScrollSentinel = ({
|
|
2553
|
+
loadMoreEvent,
|
|
2554
|
+
loadMorePayload,
|
|
2555
|
+
isLoading = false,
|
|
2556
|
+
hasMore = true,
|
|
2557
|
+
threshold = "200px",
|
|
2558
|
+
className
|
|
2559
|
+
}) => {
|
|
2560
|
+
const eventBus = useEventBus();
|
|
2561
|
+
const onLoadMore = useCallback(() => {
|
|
2562
|
+
eventBus.emit(`UI:${loadMoreEvent}`, loadMorePayload ?? {});
|
|
2563
|
+
}, [eventBus, loadMoreEvent, loadMorePayload]);
|
|
2564
|
+
const { sentinelRef } = useInfiniteScroll(onLoadMore, {
|
|
2565
|
+
rootMargin: threshold,
|
|
2566
|
+
hasMore,
|
|
2567
|
+
isLoading
|
|
2568
|
+
});
|
|
2569
|
+
return /* @__PURE__ */ jsxs(
|
|
2570
|
+
Box,
|
|
2571
|
+
{
|
|
2572
|
+
className: cn("flex items-center justify-center py-4", className),
|
|
2573
|
+
children: [
|
|
2574
|
+
/* @__PURE__ */ jsx(Box, { ref: sentinelRef, className: "h-1 w-full", "aria-hidden": "true" }),
|
|
2575
|
+
isLoading && /* @__PURE__ */ jsx(Spinner, { size: "sm" })
|
|
2576
|
+
]
|
|
2577
|
+
}
|
|
2578
|
+
);
|
|
2579
|
+
};
|
|
2580
|
+
InfiniteScrollSentinel.displayName = "InfiniteScrollSentinel";
|
|
2581
|
+
var CONFETTI_COLORS = [
|
|
2582
|
+
"var(--color-primary)",
|
|
2583
|
+
"var(--color-success)",
|
|
2584
|
+
"var(--color-warning)",
|
|
2585
|
+
"var(--color-error)",
|
|
2586
|
+
"gold",
|
|
2587
|
+
"dodgerblue"
|
|
2588
|
+
];
|
|
2589
|
+
var particleIdCounter = 0;
|
|
2590
|
+
function createParticles(count) {
|
|
2591
|
+
return Array.from({ length: count }, () => {
|
|
2592
|
+
particleIdCounter += 1;
|
|
2593
|
+
return {
|
|
2594
|
+
id: particleIdCounter,
|
|
2595
|
+
color: CONFETTI_COLORS[Math.floor(Math.random() * CONFETTI_COLORS.length)],
|
|
2596
|
+
left: 30 + Math.random() * 40,
|
|
2597
|
+
delay: Math.random() * 300,
|
|
2598
|
+
angle: Math.random() * 360,
|
|
2599
|
+
distance: 40 + Math.random() * 80,
|
|
2600
|
+
rotation: Math.random() * 720 - 360,
|
|
2601
|
+
size: 4 + Math.random() * 6
|
|
2602
|
+
};
|
|
2603
|
+
});
|
|
2604
|
+
}
|
|
2605
|
+
var ConfettiEffect = ({
|
|
2606
|
+
trigger,
|
|
2607
|
+
duration = 2e3,
|
|
2608
|
+
particleCount = 30,
|
|
2609
|
+
className
|
|
2610
|
+
}) => {
|
|
2611
|
+
const [particles, setParticles] = useState([]);
|
|
2612
|
+
const previousTriggerRef = useRef(false);
|
|
2613
|
+
useEffect(() => {
|
|
2614
|
+
const wasFalse = !previousTriggerRef.current;
|
|
2615
|
+
previousTriggerRef.current = trigger;
|
|
2616
|
+
if (trigger && wasFalse) {
|
|
2617
|
+
const newParticles = createParticles(particleCount);
|
|
2618
|
+
setParticles(newParticles);
|
|
2619
|
+
const timer = window.setTimeout(() => {
|
|
2620
|
+
setParticles([]);
|
|
2621
|
+
}, duration);
|
|
2622
|
+
return () => {
|
|
2623
|
+
window.clearTimeout(timer);
|
|
2624
|
+
};
|
|
2625
|
+
}
|
|
2626
|
+
return void 0;
|
|
2627
|
+
}, [trigger, particleCount, duration]);
|
|
2628
|
+
if (particles.length === 0) {
|
|
2629
|
+
return null;
|
|
2630
|
+
}
|
|
2631
|
+
return /* @__PURE__ */ jsxs(
|
|
2632
|
+
Box,
|
|
2633
|
+
{
|
|
2634
|
+
position: "absolute",
|
|
2635
|
+
className: cn(
|
|
2636
|
+
"inset-0 pointer-events-none overflow-hidden z-50",
|
|
2637
|
+
className
|
|
2638
|
+
),
|
|
2639
|
+
"aria-hidden": "true",
|
|
2640
|
+
children: [
|
|
2641
|
+
particles.map((p) => {
|
|
2642
|
+
const rad = p.angle * Math.PI / 180;
|
|
2643
|
+
const tx = Math.cos(rad) * p.distance;
|
|
2644
|
+
const ty = Math.sin(rad) * p.distance - 20;
|
|
2645
|
+
return /* @__PURE__ */ jsx(
|
|
2646
|
+
Box,
|
|
2647
|
+
{
|
|
2648
|
+
className: "absolute rounded-sm",
|
|
2649
|
+
style: {
|
|
2650
|
+
left: `${p.left}%`,
|
|
2651
|
+
top: "50%",
|
|
2652
|
+
width: p.size,
|
|
2653
|
+
height: p.size,
|
|
2654
|
+
backgroundColor: p.color,
|
|
2655
|
+
animation: `confetti-burst ${duration - p.delay}ms ease-out ${p.delay}ms forwards`,
|
|
2656
|
+
opacity: 0,
|
|
2657
|
+
// Use CSS custom properties for the animation endpoint
|
|
2658
|
+
// @ts-expect-error -- CSS custom properties are not typed in CSSProperties
|
|
2659
|
+
"--confetti-tx": `${tx}px`,
|
|
2660
|
+
"--confetti-ty": `${ty}px`,
|
|
2661
|
+
"--confetti-rotate": `${p.rotation}deg`
|
|
2662
|
+
}
|
|
2663
|
+
},
|
|
2664
|
+
p.id
|
|
2665
|
+
);
|
|
2666
|
+
}),
|
|
2667
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
2668
|
+
@keyframes confetti-burst {
|
|
2669
|
+
0% {
|
|
2670
|
+
opacity: 1;
|
|
2671
|
+
transform: translate(0, 0) rotate(0deg) scale(1);
|
|
2672
|
+
}
|
|
2673
|
+
70% {
|
|
2674
|
+
opacity: 1;
|
|
2675
|
+
}
|
|
2676
|
+
100% {
|
|
2677
|
+
opacity: 0;
|
|
2678
|
+
transform: translate(var(--confetti-tx), var(--confetti-ty)) rotate(var(--confetti-rotate)) scale(0.5);
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
` })
|
|
2682
|
+
]
|
|
2683
|
+
}
|
|
2684
|
+
);
|
|
2685
|
+
};
|
|
2686
|
+
ConfettiEffect.displayName = "ConfettiEffect";
|
|
2687
|
+
var TypewriterText = ({
|
|
2688
|
+
text,
|
|
2689
|
+
speed = 40,
|
|
2690
|
+
startDelay = 0,
|
|
2691
|
+
className,
|
|
2692
|
+
onComplete
|
|
2693
|
+
}) => {
|
|
2694
|
+
const [charCount, setCharCount] = useState(0);
|
|
2695
|
+
const [started, setStarted] = useState(startDelay === 0);
|
|
2696
|
+
const onCompleteRef = useRef(onComplete);
|
|
2697
|
+
onCompleteRef.current = onComplete;
|
|
2698
|
+
useEffect(() => {
|
|
2699
|
+
if (startDelay <= 0) {
|
|
2700
|
+
setStarted(true);
|
|
2701
|
+
return void 0;
|
|
2702
|
+
}
|
|
2703
|
+
setStarted(false);
|
|
2704
|
+
setCharCount(0);
|
|
2705
|
+
const delayTimer = window.setTimeout(() => {
|
|
2706
|
+
setStarted(true);
|
|
2707
|
+
}, startDelay);
|
|
2708
|
+
return () => {
|
|
2709
|
+
window.clearTimeout(delayTimer);
|
|
2710
|
+
};
|
|
2711
|
+
}, [startDelay, text]);
|
|
2712
|
+
useEffect(() => {
|
|
2713
|
+
setCharCount(0);
|
|
2714
|
+
}, [text]);
|
|
2715
|
+
useEffect(() => {
|
|
2716
|
+
if (!started) return void 0;
|
|
2717
|
+
if (charCount >= text.length) {
|
|
2718
|
+
onCompleteRef.current?.();
|
|
2719
|
+
return void 0;
|
|
2720
|
+
}
|
|
2721
|
+
const interval = window.setInterval(() => {
|
|
2722
|
+
setCharCount((prev) => {
|
|
2723
|
+
const next = prev + 1;
|
|
2724
|
+
if (next >= text.length) {
|
|
2725
|
+
window.clearInterval(interval);
|
|
2726
|
+
}
|
|
2727
|
+
return next;
|
|
2728
|
+
});
|
|
2729
|
+
}, speed);
|
|
2730
|
+
return () => {
|
|
2731
|
+
window.clearInterval(interval);
|
|
2732
|
+
};
|
|
2733
|
+
}, [started, text, speed, charCount]);
|
|
2734
|
+
const isComplete = charCount >= text.length;
|
|
2735
|
+
const displayedText = text.slice(0, charCount);
|
|
2736
|
+
return /* @__PURE__ */ jsxs(Typography, { variant: "body", className: cn("inline", className), children: [
|
|
2737
|
+
displayedText,
|
|
2738
|
+
!isComplete && /* @__PURE__ */ jsx(
|
|
2739
|
+
"span",
|
|
2740
|
+
{
|
|
2741
|
+
className: "inline-block w-[2px] h-[1em] bg-[var(--color-foreground)] ml-[1px] align-text-bottom animate-pulse",
|
|
2742
|
+
"aria-hidden": "true"
|
|
2743
|
+
}
|
|
2744
|
+
)
|
|
2745
|
+
] });
|
|
2746
|
+
};
|
|
2747
|
+
TypewriterText.displayName = "TypewriterText";
|
|
2185
2748
|
var heartIcon = (filled, size) => /* @__PURE__ */ jsx(
|
|
2186
2749
|
"svg",
|
|
2187
2750
|
{
|
|
@@ -2264,9 +2827,9 @@ function ScoreDisplay({
|
|
|
2264
2827
|
animated = true,
|
|
2265
2828
|
locale = "en-US"
|
|
2266
2829
|
}) {
|
|
2267
|
-
const [displayValue, setDisplayValue] =
|
|
2268
|
-
const [isAnimating, setIsAnimating] =
|
|
2269
|
-
|
|
2830
|
+
const [displayValue, setDisplayValue] = React69.useState(value);
|
|
2831
|
+
const [isAnimating, setIsAnimating] = React69.useState(false);
|
|
2832
|
+
React69.useEffect(() => {
|
|
2270
2833
|
if (!animated || displayValue === value) {
|
|
2271
2834
|
setDisplayValue(value);
|
|
2272
2835
|
return;
|
|
@@ -2339,9 +2902,9 @@ function ControlButton({
|
|
|
2339
2902
|
className
|
|
2340
2903
|
}) {
|
|
2341
2904
|
const eventBus = useEventBus();
|
|
2342
|
-
const [isPressed, setIsPressed] =
|
|
2905
|
+
const [isPressed, setIsPressed] = React69.useState(false);
|
|
2343
2906
|
const actualPressed = pressed ?? isPressed;
|
|
2344
|
-
const handlePointerDown =
|
|
2907
|
+
const handlePointerDown = React69.useCallback(
|
|
2345
2908
|
(e) => {
|
|
2346
2909
|
e.preventDefault();
|
|
2347
2910
|
if (disabled) return;
|
|
@@ -2351,7 +2914,7 @@ function ControlButton({
|
|
|
2351
2914
|
},
|
|
2352
2915
|
[disabled, pressEvent, eventBus, onPress]
|
|
2353
2916
|
);
|
|
2354
|
-
const handlePointerUp =
|
|
2917
|
+
const handlePointerUp = React69.useCallback(
|
|
2355
2918
|
(e) => {
|
|
2356
2919
|
e.preventDefault();
|
|
2357
2920
|
if (disabled) return;
|
|
@@ -2361,7 +2924,7 @@ function ControlButton({
|
|
|
2361
2924
|
},
|
|
2362
2925
|
[disabled, releaseEvent, eventBus, onRelease]
|
|
2363
2926
|
);
|
|
2364
|
-
const handlePointerLeave =
|
|
2927
|
+
const handlePointerLeave = React69.useCallback(
|
|
2365
2928
|
(e) => {
|
|
2366
2929
|
if (isPressed) {
|
|
2367
2930
|
setIsPressed(false);
|
|
@@ -2589,7 +3152,7 @@ var ErrorState = ({
|
|
|
2589
3152
|
);
|
|
2590
3153
|
};
|
|
2591
3154
|
ErrorState.displayName = "ErrorState";
|
|
2592
|
-
var ErrorBoundary = class extends
|
|
3155
|
+
var ErrorBoundary = class extends React69__default.Component {
|
|
2593
3156
|
constructor(props) {
|
|
2594
3157
|
super(props);
|
|
2595
3158
|
__publicField(this, "reset", () => {
|
|
@@ -2993,7 +3556,7 @@ var variantIconColors = {
|
|
|
2993
3556
|
warning: "text-[var(--color-warning)]",
|
|
2994
3557
|
error: "text-[var(--color-error)]"
|
|
2995
3558
|
};
|
|
2996
|
-
var
|
|
3559
|
+
var iconMap2 = {
|
|
2997
3560
|
info: Info,
|
|
2998
3561
|
success: CheckCircle,
|
|
2999
3562
|
warning: AlertTriangle,
|
|
@@ -3032,7 +3595,7 @@ var Alert = ({
|
|
|
3032
3595
|
/* @__PURE__ */ jsx("div", { className: "flex-shrink-0 mt-0.5", children: /* @__PURE__ */ jsx(
|
|
3033
3596
|
Icon,
|
|
3034
3597
|
{
|
|
3035
|
-
icon:
|
|
3598
|
+
icon: iconMap2[variant],
|
|
3036
3599
|
size: "md",
|
|
3037
3600
|
className: variantIconColors[variant]
|
|
3038
3601
|
}
|
|
@@ -3144,7 +3707,7 @@ var Breadcrumb = ({
|
|
|
3144
3707
|
);
|
|
3145
3708
|
};
|
|
3146
3709
|
Breadcrumb.displayName = "Breadcrumb";
|
|
3147
|
-
function
|
|
3710
|
+
function useSafeEventBus2() {
|
|
3148
3711
|
try {
|
|
3149
3712
|
return useEventBus();
|
|
3150
3713
|
} catch {
|
|
@@ -3165,7 +3728,7 @@ var ButtonGroup = ({
|
|
|
3165
3728
|
entity: _entity,
|
|
3166
3729
|
filters
|
|
3167
3730
|
}) => {
|
|
3168
|
-
const eventBus =
|
|
3731
|
+
const eventBus = useSafeEventBus2();
|
|
3169
3732
|
const variantClasses2 = {
|
|
3170
3733
|
default: "gap-0",
|
|
3171
3734
|
segmented: "gap-0 [&>button]:rounded-none [&>button:first-child]:rounded-l-lg [&>button:last-child]:rounded-r-lg [&>button:not(:first-child)]:border-l-0",
|
|
@@ -3631,11 +4194,19 @@ function Card2({
|
|
|
3631
4194
|
children,
|
|
3632
4195
|
onClick,
|
|
3633
4196
|
className = "",
|
|
3634
|
-
action
|
|
4197
|
+
action,
|
|
4198
|
+
longPressEvent,
|
|
4199
|
+
longPressPayload
|
|
3635
4200
|
}) {
|
|
3636
4201
|
const eventBus = useEventBus();
|
|
3637
4202
|
const { t } = useTranslate();
|
|
3638
4203
|
const isClickable = !!onClick || !!action;
|
|
4204
|
+
const handleLongPress = useCallback(() => {
|
|
4205
|
+
if (longPressEvent) {
|
|
4206
|
+
eventBus.emit(`UI:${longPressEvent}`, longPressPayload ?? {});
|
|
4207
|
+
}
|
|
4208
|
+
}, [longPressEvent, longPressPayload, eventBus]);
|
|
4209
|
+
const longPress = useLongPress(handleLongPress);
|
|
3639
4210
|
const handleClick = () => {
|
|
3640
4211
|
if (action) eventBus.emit(`UI:${action}`, {});
|
|
3641
4212
|
onClick?.();
|
|
@@ -3654,6 +4225,12 @@ function Card2({
|
|
|
3654
4225
|
role: isClickable ? "button" : void 0,
|
|
3655
4226
|
tabIndex: isClickable ? 0 : void 0,
|
|
3656
4227
|
onKeyDown: isClickable ? (e) => e.key === "Enter" && handleClick() : void 0,
|
|
4228
|
+
...longPressEvent ? {
|
|
4229
|
+
onPointerDown: longPress.onPointerDown,
|
|
4230
|
+
onPointerMove: longPress.onPointerMove,
|
|
4231
|
+
onPointerUp: longPress.onPointerUp,
|
|
4232
|
+
onPointerCancel: longPress.onPointerCancel
|
|
4233
|
+
} : {},
|
|
3657
4234
|
children: [
|
|
3658
4235
|
image && /* @__PURE__ */ jsx("div", { className: "aspect-video w-full overflow-hidden rounded-t-lg", children: /* @__PURE__ */ jsx(
|
|
3659
4236
|
"img",
|
|
@@ -3694,7 +4271,7 @@ function Card2({
|
|
|
3694
4271
|
);
|
|
3695
4272
|
}
|
|
3696
4273
|
Card2.displayName = "Card";
|
|
3697
|
-
var
|
|
4274
|
+
var sizeStyles7 = {
|
|
3698
4275
|
xs: "max-w-xs",
|
|
3699
4276
|
// 320px
|
|
3700
4277
|
sm: "max-w-screen-sm",
|
|
@@ -3731,7 +4308,7 @@ var Container = ({
|
|
|
3731
4308
|
{
|
|
3732
4309
|
className: cn(
|
|
3733
4310
|
"w-full",
|
|
3734
|
-
|
|
4311
|
+
sizeStyles7[resolvedSize],
|
|
3735
4312
|
paddingStyles3[padding],
|
|
3736
4313
|
center && "mx-auto",
|
|
3737
4314
|
className
|
|
@@ -4197,8 +4774,8 @@ var Menu = ({
|
|
|
4197
4774
|
"bottom-start": "top-full left-0 mt-2",
|
|
4198
4775
|
"bottom-end": "top-full right-0 mt-2"
|
|
4199
4776
|
};
|
|
4200
|
-
const triggerChild =
|
|
4201
|
-
const triggerElement =
|
|
4777
|
+
const triggerChild = React69__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx("span", { children: trigger });
|
|
4778
|
+
const triggerElement = React69__default.cloneElement(
|
|
4202
4779
|
triggerChild,
|
|
4203
4780
|
{
|
|
4204
4781
|
ref: triggerRef,
|
|
@@ -4314,11 +4891,15 @@ var Modal = ({
|
|
|
4314
4891
|
closeOnOverlayClick = true,
|
|
4315
4892
|
closeOnEscape = true,
|
|
4316
4893
|
className,
|
|
4317
|
-
closeEvent
|
|
4894
|
+
closeEvent,
|
|
4895
|
+
swipeDownToClose = true
|
|
4318
4896
|
}) => {
|
|
4319
4897
|
const eventBus = useEventBus();
|
|
4320
4898
|
const modalRef = useRef(null);
|
|
4321
4899
|
const previousActiveElement = useRef(null);
|
|
4900
|
+
const [dragY, setDragY] = useState(0);
|
|
4901
|
+
const dragStartY = useRef(0);
|
|
4902
|
+
const isDragging = useRef(false);
|
|
4322
4903
|
useEffect(() => {
|
|
4323
4904
|
if (isOpen) {
|
|
4324
4905
|
previousActiveElement.current = document.activeElement;
|
|
@@ -4371,7 +4952,11 @@ var Modal = ({
|
|
|
4371
4952
|
className: "z-40"
|
|
4372
4953
|
}
|
|
4373
4954
|
),
|
|
4374
|
-
/* @__PURE__ */ jsx("div", { className:
|
|
4955
|
+
/* @__PURE__ */ jsx("div", { className: cn(
|
|
4956
|
+
"fixed inset-0 z-50 pointer-events-none",
|
|
4957
|
+
"flex items-center justify-center p-4",
|
|
4958
|
+
"max-sm:items-end max-sm:p-0"
|
|
4959
|
+
), children: /* @__PURE__ */ jsxs(
|
|
4375
4960
|
Box,
|
|
4376
4961
|
{
|
|
4377
4962
|
ref: modalRef,
|
|
@@ -4382,12 +4967,47 @@ var Modal = ({
|
|
|
4382
4967
|
className: cn(
|
|
4383
4968
|
"pointer-events-auto w-full flex flex-col max-h-[90vh]",
|
|
4384
4969
|
sizeClasses4[size],
|
|
4970
|
+
"max-sm:max-w-full max-sm:max-h-[85vh] max-sm:rounded-b-none max-sm:rounded-t-2xl",
|
|
4385
4971
|
className
|
|
4386
4972
|
),
|
|
4973
|
+
style: dragY > 0 ? {
|
|
4974
|
+
transform: `translateY(${dragY}px)`,
|
|
4975
|
+
transition: isDragging.current ? "none" : "transform 200ms ease-out"
|
|
4976
|
+
} : void 0,
|
|
4387
4977
|
role: "dialog",
|
|
4388
4978
|
"aria-modal": "true",
|
|
4389
4979
|
...title && { "aria-labelledby": "modal-title" },
|
|
4390
4980
|
children: [
|
|
4981
|
+
/* @__PURE__ */ jsx(
|
|
4982
|
+
"div",
|
|
4983
|
+
{
|
|
4984
|
+
className: "hidden max-sm:flex justify-center py-2 cursor-grab active:cursor-grabbing touch-none",
|
|
4985
|
+
onPointerDown: (e) => {
|
|
4986
|
+
if (!swipeDownToClose) return;
|
|
4987
|
+
dragStartY.current = e.clientY;
|
|
4988
|
+
isDragging.current = true;
|
|
4989
|
+
e.target.setPointerCapture(e.pointerId);
|
|
4990
|
+
},
|
|
4991
|
+
onPointerMove: (e) => {
|
|
4992
|
+
if (!isDragging.current) return;
|
|
4993
|
+
const dy = Math.max(0, e.clientY - dragStartY.current);
|
|
4994
|
+
setDragY(dy);
|
|
4995
|
+
},
|
|
4996
|
+
onPointerUp: () => {
|
|
4997
|
+
if (!isDragging.current) return;
|
|
4998
|
+
isDragging.current = false;
|
|
4999
|
+
if (dragY > 100) {
|
|
5000
|
+
handleClose();
|
|
5001
|
+
}
|
|
5002
|
+
setDragY(0);
|
|
5003
|
+
},
|
|
5004
|
+
onPointerCancel: () => {
|
|
5005
|
+
isDragging.current = false;
|
|
5006
|
+
setDragY(0);
|
|
5007
|
+
},
|
|
5008
|
+
children: /* @__PURE__ */ jsx("div", { className: "w-10 h-1 rounded-full bg-[var(--color-border)]" })
|
|
5009
|
+
}
|
|
5010
|
+
),
|
|
4391
5011
|
(title || showCloseButton) && /* @__PURE__ */ jsxs(
|
|
4392
5012
|
"div",
|
|
4393
5013
|
{
|
|
@@ -4660,8 +5280,8 @@ var Popover = ({
|
|
|
4660
5280
|
onMouseEnter: handleOpen,
|
|
4661
5281
|
onMouseLeave: handleClose
|
|
4662
5282
|
};
|
|
4663
|
-
const childElement =
|
|
4664
|
-
const triggerElement =
|
|
5283
|
+
const childElement = React69__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
|
|
5284
|
+
const triggerElement = React69__default.cloneElement(
|
|
4665
5285
|
childElement,
|
|
4666
5286
|
{
|
|
4667
5287
|
ref: triggerRef,
|
|
@@ -5241,7 +5861,7 @@ var variantClasses = {
|
|
|
5241
5861
|
info: "bg-[var(--color-card)] border-[length:var(--border-width)] border-[var(--color-info)]",
|
|
5242
5862
|
warning: "bg-[var(--color-card)] border-[length:var(--border-width)] border-[var(--color-warning)]"
|
|
5243
5863
|
};
|
|
5244
|
-
var
|
|
5864
|
+
var iconMap3 = {
|
|
5245
5865
|
success: CheckCircle,
|
|
5246
5866
|
error: AlertCircle,
|
|
5247
5867
|
info: Info,
|
|
@@ -5299,7 +5919,7 @@ var Toast = ({
|
|
|
5299
5919
|
/* @__PURE__ */ jsx("div", { className: "flex-shrink-0 mt-0.5", children: /* @__PURE__ */ jsx(
|
|
5300
5920
|
Icon,
|
|
5301
5921
|
{
|
|
5302
|
-
icon:
|
|
5922
|
+
icon: iconMap3[variant],
|
|
5303
5923
|
size: "md",
|
|
5304
5924
|
className: iconColors[variant]
|
|
5305
5925
|
}
|
|
@@ -5391,8 +6011,8 @@ var Tooltip = ({
|
|
|
5391
6011
|
if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
|
|
5392
6012
|
};
|
|
5393
6013
|
}, []);
|
|
5394
|
-
const triggerElement =
|
|
5395
|
-
const trigger =
|
|
6014
|
+
const triggerElement = React69__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
|
|
6015
|
+
const trigger = React69__default.cloneElement(triggerElement, {
|
|
5396
6016
|
ref: triggerRef,
|
|
5397
6017
|
onMouseEnter: handleMouseEnter,
|
|
5398
6018
|
onMouseLeave: handleMouseLeave,
|
|
@@ -5641,7 +6261,7 @@ var WizardProgress = ({
|
|
|
5641
6261
|
children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: steps.map((step, index) => {
|
|
5642
6262
|
const isActive = index === currentStep;
|
|
5643
6263
|
const isCompleted = index < currentStep;
|
|
5644
|
-
return /* @__PURE__ */ jsxs(
|
|
6264
|
+
return /* @__PURE__ */ jsxs(React69__default.Fragment, { children: [
|
|
5645
6265
|
/* @__PURE__ */ jsx(
|
|
5646
6266
|
"button",
|
|
5647
6267
|
{
|
|
@@ -5690,7 +6310,7 @@ var WizardProgress = ({
|
|
|
5690
6310
|
);
|
|
5691
6311
|
};
|
|
5692
6312
|
WizardProgress.displayName = "WizardProgress";
|
|
5693
|
-
function
|
|
6313
|
+
function useSafeEventBus3() {
|
|
5694
6314
|
try {
|
|
5695
6315
|
return useEventBus();
|
|
5696
6316
|
} catch {
|
|
@@ -5719,7 +6339,7 @@ var WizardNavigation = ({
|
|
|
5719
6339
|
compact = false,
|
|
5720
6340
|
className
|
|
5721
6341
|
}) => {
|
|
5722
|
-
const eventBus =
|
|
6342
|
+
const eventBus = useSafeEventBus3();
|
|
5723
6343
|
const { t } = useTranslate();
|
|
5724
6344
|
const resolvedBackLabel = backLabel ?? t("wizard.back");
|
|
5725
6345
|
const resolvedNextLabel = nextLabel ?? t("wizard.next");
|
|
@@ -5771,7 +6391,7 @@ var WizardNavigation = ({
|
|
|
5771
6391
|
);
|
|
5772
6392
|
};
|
|
5773
6393
|
WizardNavigation.displayName = "WizardNavigation";
|
|
5774
|
-
var MarkdownContent =
|
|
6394
|
+
var MarkdownContent = React69__default.memo(
|
|
5775
6395
|
({ content, direction, className }) => {
|
|
5776
6396
|
const { t: _t } = useTranslate();
|
|
5777
6397
|
return /* @__PURE__ */ jsx(
|
|
@@ -5872,7 +6492,7 @@ var MarkdownContent = React50__default.memo(
|
|
|
5872
6492
|
(prev, next) => prev.content === next.content && prev.className === next.className && prev.direction === next.direction
|
|
5873
6493
|
);
|
|
5874
6494
|
MarkdownContent.displayName = "MarkdownContent";
|
|
5875
|
-
var CodeBlock =
|
|
6495
|
+
var CodeBlock = React69__default.memo(
|
|
5876
6496
|
({
|
|
5877
6497
|
code,
|
|
5878
6498
|
language = "text",
|
|
@@ -6133,8 +6753,14 @@ function CalendarGrid({
|
|
|
6133
6753
|
onSlotClick,
|
|
6134
6754
|
onDayClick,
|
|
6135
6755
|
onEventClick,
|
|
6136
|
-
className
|
|
6756
|
+
className,
|
|
6757
|
+
longPressEvent,
|
|
6758
|
+
longPressPayload,
|
|
6759
|
+
swipeLeftEvent,
|
|
6760
|
+
swipeRightEvent
|
|
6137
6761
|
}) {
|
|
6762
|
+
const eventBus = useEventBus();
|
|
6763
|
+
const longPressTimer = useRef(null);
|
|
6138
6764
|
const resolvedWeekStart = useMemo(
|
|
6139
6765
|
() => weekStart ? getStartOfWeek(weekStart) : getStartOfWeek(/* @__PURE__ */ new Date()),
|
|
6140
6766
|
[weekStart]
|
|
@@ -6166,6 +6792,23 @@ function CalendarGrid({
|
|
|
6166
6792
|
).length,
|
|
6167
6793
|
[events]
|
|
6168
6794
|
);
|
|
6795
|
+
const swipeCallbacks = useMemo(() => ({
|
|
6796
|
+
onSwipeLeft: swipeLeftEvent ? () => eventBus.emit(`UI:${swipeLeftEvent}`, {}) : void 0,
|
|
6797
|
+
onSwipeRight: swipeRightEvent ? () => eventBus.emit(`UI:${swipeRightEvent}`, {}) : void 0
|
|
6798
|
+
}), [swipeLeftEvent, swipeRightEvent, eventBus]);
|
|
6799
|
+
const swipe = useSwipeGesture(swipeCallbacks);
|
|
6800
|
+
const clearLongPress = useCallback(() => {
|
|
6801
|
+
if (longPressTimer.current) {
|
|
6802
|
+
clearTimeout(longPressTimer.current);
|
|
6803
|
+
longPressTimer.current = null;
|
|
6804
|
+
}
|
|
6805
|
+
}, []);
|
|
6806
|
+
const startLongPress = useCallback((day, time) => {
|
|
6807
|
+
if (!longPressEvent) return;
|
|
6808
|
+
longPressTimer.current = setTimeout(() => {
|
|
6809
|
+
eventBus.emit(`UI:${longPressEvent}`, { date: day.toISOString(), time, ...longPressPayload });
|
|
6810
|
+
}, 500);
|
|
6811
|
+
}, [longPressEvent, longPressPayload, eventBus]);
|
|
6169
6812
|
const renderEvent = (event) => /* @__PURE__ */ jsx(
|
|
6170
6813
|
Box,
|
|
6171
6814
|
{
|
|
@@ -6181,70 +6824,87 @@ function CalendarGrid({
|
|
|
6181
6824
|
},
|
|
6182
6825
|
event.id
|
|
6183
6826
|
);
|
|
6184
|
-
return /* @__PURE__ */ jsx(
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6827
|
+
return /* @__PURE__ */ jsx(
|
|
6828
|
+
Box,
|
|
6829
|
+
{
|
|
6830
|
+
className: cn("overflow-x-auto", className),
|
|
6831
|
+
...swipeLeftEvent || swipeRightEvent ? {
|
|
6832
|
+
onPointerDown: swipe.onPointerDown,
|
|
6833
|
+
onPointerMove: swipe.onPointerMove,
|
|
6834
|
+
onPointerUp: swipe.onPointerUp,
|
|
6835
|
+
onPointerCancel: swipe.onPointerCancel
|
|
6836
|
+
} : {},
|
|
6837
|
+
children: /* @__PURE__ */ jsxs(Box, { className: "min-w-[800px]", children: [
|
|
6838
|
+
/* @__PURE__ */ jsxs(Box, { className: "grid grid-cols-8 border-b border-[var(--color-border)]", children: [
|
|
6839
|
+
/* @__PURE__ */ jsx(Box, { className: "p-2" }),
|
|
6840
|
+
weekDays.map((day) => {
|
|
6841
|
+
const isToday = day.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
|
|
6842
|
+
const count = eventsForDayCount(day);
|
|
6843
|
+
return /* @__PURE__ */ jsxs(
|
|
6844
|
+
Box,
|
|
6845
|
+
{
|
|
6846
|
+
className: "border-l border-[var(--color-border)]",
|
|
6847
|
+
children: [
|
|
6848
|
+
/* @__PURE__ */ jsx(
|
|
6849
|
+
DayCell,
|
|
6850
|
+
{
|
|
6851
|
+
date: day,
|
|
6852
|
+
isToday,
|
|
6853
|
+
onClick: onDayClick
|
|
6854
|
+
}
|
|
6855
|
+
),
|
|
6856
|
+
count > 0 && /* @__PURE__ */ jsx(Box, { className: "text-center pb-1", children: /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: count }) })
|
|
6857
|
+
]
|
|
6858
|
+
},
|
|
6859
|
+
day.toISOString()
|
|
6860
|
+
);
|
|
6861
|
+
})
|
|
6862
|
+
] }),
|
|
6863
|
+
/* @__PURE__ */ jsx(Box, { className: "max-h-[500px] overflow-y-auto", children: resolvedTimeSlots.map((time) => /* @__PURE__ */ jsxs(
|
|
6191
6864
|
Box,
|
|
6192
6865
|
{
|
|
6193
|
-
className: "border-
|
|
6866
|
+
className: "grid grid-cols-8 border-b border-[var(--color-border)]",
|
|
6194
6867
|
children: [
|
|
6195
|
-
/* @__PURE__ */ jsx(
|
|
6196
|
-
|
|
6868
|
+
/* @__PURE__ */ jsx(Box, { className: "p-2 text-right pr-3", children: /* @__PURE__ */ jsx(
|
|
6869
|
+
Typography,
|
|
6197
6870
|
{
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6871
|
+
variant: "small",
|
|
6872
|
+
className: "text-[var(--color-muted-foreground)]",
|
|
6873
|
+
children: time
|
|
6201
6874
|
}
|
|
6202
|
-
),
|
|
6203
|
-
|
|
6875
|
+
) }),
|
|
6876
|
+
weekDays.map((day) => {
|
|
6877
|
+
const slotEvents = events.filter(
|
|
6878
|
+
(ev) => eventInSlot(ev, day, time)
|
|
6879
|
+
);
|
|
6880
|
+
const isToday = day.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
|
|
6881
|
+
return /* @__PURE__ */ jsx(
|
|
6882
|
+
TimeSlotCell,
|
|
6883
|
+
{
|
|
6884
|
+
time,
|
|
6885
|
+
isOccupied: slotEvents.length > 0,
|
|
6886
|
+
onClick: () => handleSlotClick(day, time),
|
|
6887
|
+
className: cn(
|
|
6888
|
+
"border-l border-[var(--color-border)]",
|
|
6889
|
+
isToday && "bg-blue-50/30"
|
|
6890
|
+
),
|
|
6891
|
+
...longPressEvent ? {
|
|
6892
|
+
onPointerDown: () => startLongPress(day, time),
|
|
6893
|
+
onPointerUp: clearLongPress,
|
|
6894
|
+
onPointerCancel: clearLongPress
|
|
6895
|
+
} : {},
|
|
6896
|
+
children: /* @__PURE__ */ jsx(VStack, { gap: "xs", children: slotEvents.map(renderEvent) })
|
|
6897
|
+
},
|
|
6898
|
+
`${day.toISOString()}-${time}`
|
|
6899
|
+
);
|
|
6900
|
+
})
|
|
6204
6901
|
]
|
|
6205
6902
|
},
|
|
6206
|
-
|
|
6207
|
-
)
|
|
6208
|
-
})
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
Box,
|
|
6212
|
-
{
|
|
6213
|
-
className: "grid grid-cols-8 border-b border-[var(--color-border)]",
|
|
6214
|
-
children: [
|
|
6215
|
-
/* @__PURE__ */ jsx(Box, { className: "p-2 text-right pr-3", children: /* @__PURE__ */ jsx(
|
|
6216
|
-
Typography,
|
|
6217
|
-
{
|
|
6218
|
-
variant: "small",
|
|
6219
|
-
className: "text-[var(--color-muted-foreground)]",
|
|
6220
|
-
children: time
|
|
6221
|
-
}
|
|
6222
|
-
) }),
|
|
6223
|
-
weekDays.map((day) => {
|
|
6224
|
-
const slotEvents = events.filter(
|
|
6225
|
-
(ev) => eventInSlot(ev, day, time)
|
|
6226
|
-
);
|
|
6227
|
-
const isToday = day.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
|
|
6228
|
-
return /* @__PURE__ */ jsx(
|
|
6229
|
-
TimeSlotCell,
|
|
6230
|
-
{
|
|
6231
|
-
time,
|
|
6232
|
-
isOccupied: slotEvents.length > 0,
|
|
6233
|
-
onClick: () => handleSlotClick(day, time),
|
|
6234
|
-
className: cn(
|
|
6235
|
-
"border-l border-[var(--color-border)]",
|
|
6236
|
-
isToday && "bg-blue-50/30"
|
|
6237
|
-
),
|
|
6238
|
-
children: /* @__PURE__ */ jsx(VStack, { gap: "xs", children: slotEvents.map(renderEvent) })
|
|
6239
|
-
},
|
|
6240
|
-
`${day.toISOString()}-${time}`
|
|
6241
|
-
);
|
|
6242
|
-
})
|
|
6243
|
-
]
|
|
6244
|
-
},
|
|
6245
|
-
time
|
|
6246
|
-
)) })
|
|
6247
|
-
] }) });
|
|
6903
|
+
time
|
|
6904
|
+
)) })
|
|
6905
|
+
] })
|
|
6906
|
+
}
|
|
6907
|
+
);
|
|
6248
6908
|
}
|
|
6249
6909
|
CalendarGrid.displayName = "CalendarGrid";
|
|
6250
6910
|
var RepeatableFormSection = ({
|
|
@@ -6880,8 +7540,8 @@ function DPad({
|
|
|
6880
7540
|
}) {
|
|
6881
7541
|
const eventBus = useEventBus();
|
|
6882
7542
|
const sizes = sizeMap5[size];
|
|
6883
|
-
const [activeDirections, setActiveDirections] =
|
|
6884
|
-
const handlePress =
|
|
7543
|
+
const [activeDirections, setActiveDirections] = React69.useState(/* @__PURE__ */ new Set());
|
|
7544
|
+
const handlePress = React69.useCallback(
|
|
6885
7545
|
(direction) => {
|
|
6886
7546
|
setActiveDirections((prev) => new Set(prev).add(direction));
|
|
6887
7547
|
if (directionEvent) eventBus.emit(`UI:${directionEvent}`, { direction, pressed: true });
|
|
@@ -6889,7 +7549,7 @@ function DPad({
|
|
|
6889
7549
|
},
|
|
6890
7550
|
[directionEvent, eventBus, onDirection]
|
|
6891
7551
|
);
|
|
6892
|
-
const handleRelease =
|
|
7552
|
+
const handleRelease = React69.useCallback(
|
|
6893
7553
|
(direction) => {
|
|
6894
7554
|
setActiveDirections((prev) => {
|
|
6895
7555
|
const next = new Set(prev);
|
|
@@ -6947,8 +7607,8 @@ function ActionButtons({
|
|
|
6947
7607
|
disabled
|
|
6948
7608
|
}) {
|
|
6949
7609
|
const eventBus = useEventBus();
|
|
6950
|
-
const [activeButtons, setActiveButtons] =
|
|
6951
|
-
const handlePress =
|
|
7610
|
+
const [activeButtons, setActiveButtons] = React69.useState(/* @__PURE__ */ new Set());
|
|
7611
|
+
const handlePress = React69.useCallback(
|
|
6952
7612
|
(id) => {
|
|
6953
7613
|
setActiveButtons((prev) => new Set(prev).add(id));
|
|
6954
7614
|
if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: true });
|
|
@@ -6956,7 +7616,7 @@ function ActionButtons({
|
|
|
6956
7616
|
},
|
|
6957
7617
|
[actionEvent, eventBus, onAction]
|
|
6958
7618
|
);
|
|
6959
|
-
const handleRelease =
|
|
7619
|
+
const handleRelease = React69.useCallback(
|
|
6960
7620
|
(id) => {
|
|
6961
7621
|
setActiveButtons((prev) => {
|
|
6962
7622
|
const next = new Set(prev);
|
|
@@ -7545,217 +8205,667 @@ function MapView({
|
|
|
7545
8205
|
}
|
|
7546
8206
|
);
|
|
7547
8207
|
}
|
|
7548
|
-
function
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
|
|
7557
|
-
return "default";
|
|
7558
|
-
}
|
|
7559
|
-
function formatDate(value) {
|
|
7560
|
-
if (!value) return "";
|
|
7561
|
-
const d = new Date(String(value));
|
|
7562
|
-
if (isNaN(d.getTime())) return String(value);
|
|
7563
|
-
return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
|
|
7564
|
-
}
|
|
7565
|
-
function formatValue(value, format) {
|
|
7566
|
-
if (value === void 0 || value === null) return "";
|
|
7567
|
-
switch (format) {
|
|
7568
|
-
case "date":
|
|
7569
|
-
return formatDate(value);
|
|
7570
|
-
case "currency":
|
|
7571
|
-
return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
|
|
7572
|
-
case "number":
|
|
7573
|
-
return typeof value === "number" ? value.toLocaleString() : String(value);
|
|
7574
|
-
case "percent":
|
|
7575
|
-
return typeof value === "number" ? `${Math.round(value)}%` : String(value);
|
|
7576
|
-
case "boolean":
|
|
7577
|
-
return value ? "Yes" : "No";
|
|
7578
|
-
default:
|
|
7579
|
-
return String(value);
|
|
8208
|
+
function useSafeEventBus4() {
|
|
8209
|
+
try {
|
|
8210
|
+
return useEventBus();
|
|
8211
|
+
} catch {
|
|
8212
|
+
return { emit: () => {
|
|
8213
|
+
}, on: () => () => {
|
|
8214
|
+
}, once: () => {
|
|
8215
|
+
} };
|
|
7580
8216
|
}
|
|
7581
8217
|
}
|
|
7582
|
-
var
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7587
|
-
|
|
8218
|
+
var sizeStyles8 = {
|
|
8219
|
+
sm: {
|
|
8220
|
+
button: "w-7 h-7",
|
|
8221
|
+
text: "text-sm min-w-[2rem]",
|
|
8222
|
+
icon: "w-3 h-3"
|
|
8223
|
+
},
|
|
8224
|
+
md: {
|
|
8225
|
+
button: "w-9 h-9",
|
|
8226
|
+
text: "text-base min-w-[2.5rem]",
|
|
8227
|
+
icon: "w-4 h-4"
|
|
8228
|
+
},
|
|
8229
|
+
lg: {
|
|
8230
|
+
button: "w-11 h-11",
|
|
8231
|
+
text: "text-lg min-w-[3rem]",
|
|
8232
|
+
icon: "w-5 h-5"
|
|
8233
|
+
}
|
|
7588
8234
|
};
|
|
7589
|
-
var
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
8235
|
+
var LONG_PRESS_DELAY = 400;
|
|
8236
|
+
var LONG_PRESS_INTERVAL = 100;
|
|
8237
|
+
var NumberStepper = ({
|
|
8238
|
+
value = 0,
|
|
8239
|
+
min,
|
|
8240
|
+
max,
|
|
8241
|
+
step = 1,
|
|
8242
|
+
size = "md",
|
|
8243
|
+
disabled = false,
|
|
8244
|
+
onChange,
|
|
8245
|
+
action,
|
|
8246
|
+
actionPayload,
|
|
7597
8247
|
className,
|
|
7598
|
-
|
|
7599
|
-
error = null,
|
|
7600
|
-
imageField
|
|
8248
|
+
label
|
|
7601
8249
|
}) => {
|
|
7602
|
-
const eventBus =
|
|
7603
|
-
const
|
|
7604
|
-
const
|
|
7605
|
-
const
|
|
7606
|
-
const
|
|
7607
|
-
const
|
|
7608
|
-
const
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
8250
|
+
const eventBus = useSafeEventBus4();
|
|
8251
|
+
const intervalRef = useRef(null);
|
|
8252
|
+
const timeoutRef = useRef(null);
|
|
8253
|
+
const isAtMin = min !== void 0 && value <= min;
|
|
8254
|
+
const isAtMax = max !== void 0 && value >= max;
|
|
8255
|
+
const styles = sizeStyles8[size];
|
|
8256
|
+
const emitChange = useCallback(
|
|
8257
|
+
(newValue) => {
|
|
8258
|
+
const clamped = Math.round(newValue / step) * step;
|
|
8259
|
+
const finalValue = Math.max(min ?? -Infinity, Math.min(max ?? Infinity, clamped));
|
|
8260
|
+
onChange?.(finalValue);
|
|
8261
|
+
if (action) {
|
|
8262
|
+
eventBus.emit(`UI:${action}`, { ...actionPayload, value: finalValue });
|
|
8263
|
+
}
|
|
8264
|
+
},
|
|
8265
|
+
[onChange, action, actionPayload, eventBus, min, max, step]
|
|
8266
|
+
);
|
|
8267
|
+
const startLongPress = useCallback(
|
|
8268
|
+
(delta) => {
|
|
8269
|
+
timeoutRef.current = setTimeout(() => {
|
|
8270
|
+
intervalRef.current = setInterval(() => {
|
|
8271
|
+
emitChange(value + delta);
|
|
8272
|
+
}, LONG_PRESS_INTERVAL);
|
|
8273
|
+
}, LONG_PRESS_DELAY);
|
|
8274
|
+
},
|
|
8275
|
+
[emitChange, value]
|
|
8276
|
+
);
|
|
8277
|
+
const stopLongPress = useCallback(() => {
|
|
8278
|
+
if (timeoutRef.current) {
|
|
8279
|
+
clearTimeout(timeoutRef.current);
|
|
8280
|
+
timeoutRef.current = null;
|
|
8281
|
+
}
|
|
8282
|
+
if (intervalRef.current) {
|
|
8283
|
+
clearInterval(intervalRef.current);
|
|
8284
|
+
intervalRef.current = null;
|
|
8285
|
+
}
|
|
8286
|
+
}, []);
|
|
8287
|
+
useEffect(() => {
|
|
8288
|
+
return () => {
|
|
8289
|
+
stopLongPress();
|
|
8290
|
+
};
|
|
8291
|
+
}, [stopLongPress]);
|
|
8292
|
+
const handleDecrement = () => {
|
|
8293
|
+
if (!isAtMin) emitChange(value - step);
|
|
7614
8294
|
};
|
|
7615
|
-
const
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
8295
|
+
const handleIncrement = () => {
|
|
8296
|
+
if (!isAtMax) emitChange(value + step);
|
|
8297
|
+
};
|
|
8298
|
+
return /* @__PURE__ */ jsxs(
|
|
8299
|
+
"div",
|
|
8300
|
+
{
|
|
8301
|
+
className: cn(
|
|
8302
|
+
"inline-flex items-center",
|
|
8303
|
+
"rounded-[var(--radius-sm)]",
|
|
8304
|
+
"border-[length:var(--border-width)] border-[var(--color-border)]",
|
|
8305
|
+
"bg-[var(--color-surface)]",
|
|
8306
|
+
disabled && "opacity-50 cursor-not-allowed",
|
|
8307
|
+
className
|
|
8308
|
+
),
|
|
8309
|
+
role: "group",
|
|
8310
|
+
"aria-label": label ?? "Number stepper",
|
|
8311
|
+
children: [
|
|
8312
|
+
/* @__PURE__ */ jsx(
|
|
8313
|
+
"button",
|
|
8314
|
+
{
|
|
8315
|
+
type: "button",
|
|
8316
|
+
onClick: handleDecrement,
|
|
8317
|
+
onMouseDown: () => !isAtMin && startLongPress(-step),
|
|
8318
|
+
onMouseUp: stopLongPress,
|
|
8319
|
+
onMouseLeave: stopLongPress,
|
|
8320
|
+
onTouchStart: () => !isAtMin && startLongPress(-step),
|
|
8321
|
+
onTouchEnd: stopLongPress,
|
|
8322
|
+
disabled: disabled || isAtMin,
|
|
8323
|
+
className: cn(
|
|
8324
|
+
"inline-flex items-center justify-center",
|
|
8325
|
+
"rounded-l-[var(--radius-sm)]",
|
|
8326
|
+
"text-[var(--color-foreground)]",
|
|
8327
|
+
"hover:bg-[var(--color-muted)]",
|
|
8328
|
+
"active:bg-[var(--color-muted)]",
|
|
8329
|
+
"transition-colors duration-100",
|
|
8330
|
+
"disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent",
|
|
8331
|
+
"focus:outline-none focus:ring-[length:var(--focus-ring-width)] focus:ring-[var(--color-ring)] focus:ring-inset",
|
|
8332
|
+
styles.button
|
|
8333
|
+
),
|
|
8334
|
+
"aria-label": "Decrease",
|
|
8335
|
+
children: /* @__PURE__ */ jsx(Minus, { className: styles.icon })
|
|
8336
|
+
}
|
|
8337
|
+
),
|
|
8338
|
+
/* @__PURE__ */ jsx(
|
|
8339
|
+
"span",
|
|
8340
|
+
{
|
|
8341
|
+
className: cn(
|
|
8342
|
+
"text-center font-medium tabular-nums",
|
|
8343
|
+
"text-[var(--color-foreground)]",
|
|
8344
|
+
"border-x-[length:var(--border-width)] border-[var(--color-border)]",
|
|
8345
|
+
"px-1 select-none",
|
|
8346
|
+
styles.text
|
|
8347
|
+
),
|
|
8348
|
+
"aria-live": "polite",
|
|
8349
|
+
"aria-atomic": "true",
|
|
8350
|
+
children: value
|
|
8351
|
+
}
|
|
8352
|
+
),
|
|
8353
|
+
/* @__PURE__ */ jsx(
|
|
8354
|
+
"button",
|
|
8355
|
+
{
|
|
8356
|
+
type: "button",
|
|
8357
|
+
onClick: handleIncrement,
|
|
8358
|
+
onMouseDown: () => !isAtMax && startLongPress(step),
|
|
8359
|
+
onMouseUp: stopLongPress,
|
|
8360
|
+
onMouseLeave: stopLongPress,
|
|
8361
|
+
onTouchStart: () => !isAtMax && startLongPress(step),
|
|
8362
|
+
onTouchEnd: stopLongPress,
|
|
8363
|
+
disabled: disabled || isAtMax,
|
|
8364
|
+
className: cn(
|
|
8365
|
+
"inline-flex items-center justify-center",
|
|
8366
|
+
"rounded-r-[var(--radius-sm)]",
|
|
8367
|
+
"text-[var(--color-foreground)]",
|
|
8368
|
+
"hover:bg-[var(--color-muted)]",
|
|
8369
|
+
"active:bg-[var(--color-muted)]",
|
|
8370
|
+
"transition-colors duration-100",
|
|
8371
|
+
"disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent",
|
|
8372
|
+
"focus:outline-none focus:ring-[length:var(--focus-ring-width)] focus:ring-[var(--color-ring)] focus:ring-inset",
|
|
8373
|
+
styles.button
|
|
8374
|
+
),
|
|
8375
|
+
"aria-label": "Increase",
|
|
8376
|
+
children: /* @__PURE__ */ jsx(Plus, { className: styles.icon })
|
|
8377
|
+
}
|
|
8378
|
+
)
|
|
8379
|
+
]
|
|
8380
|
+
}
|
|
8381
|
+
);
|
|
8382
|
+
};
|
|
8383
|
+
NumberStepper.displayName = "NumberStepper";
|
|
8384
|
+
function useSafeEventBus5() {
|
|
8385
|
+
try {
|
|
8386
|
+
return useEventBus();
|
|
8387
|
+
} catch {
|
|
8388
|
+
return { emit: () => {
|
|
8389
|
+
}, on: () => () => {
|
|
8390
|
+
}, once: () => {
|
|
8391
|
+
} };
|
|
7632
8392
|
}
|
|
8393
|
+
}
|
|
8394
|
+
var sizeStyles9 = {
|
|
8395
|
+
sm: { star: "w-4 h-4", gap: "gap-0.5" },
|
|
8396
|
+
md: { star: "w-6 h-6", gap: "gap-1" },
|
|
8397
|
+
lg: { star: "w-8 h-8", gap: "gap-1.5" }
|
|
8398
|
+
};
|
|
8399
|
+
var StarRating = ({
|
|
8400
|
+
value = 0,
|
|
8401
|
+
max = 5,
|
|
8402
|
+
readOnly = false,
|
|
8403
|
+
precision = "full",
|
|
8404
|
+
size = "md",
|
|
8405
|
+
action,
|
|
8406
|
+
actionPayload,
|
|
8407
|
+
onChange,
|
|
8408
|
+
className,
|
|
8409
|
+
label
|
|
8410
|
+
}) => {
|
|
8411
|
+
const [hoverValue, setHoverValue] = useState(null);
|
|
8412
|
+
const eventBus = useSafeEventBus5();
|
|
8413
|
+
const styles = sizeStyles9[size];
|
|
8414
|
+
const displayValue = hoverValue ?? value;
|
|
8415
|
+
const emitChange = useCallback(
|
|
8416
|
+
(newValue) => {
|
|
8417
|
+
onChange?.(newValue);
|
|
8418
|
+
if (action) {
|
|
8419
|
+
eventBus.emit(`UI:${action}`, { ...actionPayload, value: newValue });
|
|
8420
|
+
}
|
|
8421
|
+
},
|
|
8422
|
+
[onChange, action, actionPayload, eventBus]
|
|
8423
|
+
);
|
|
8424
|
+
const handleStarClick = (starIndex, isHalf) => {
|
|
8425
|
+
if (readOnly) return;
|
|
8426
|
+
const newValue = isHalf && precision === "half" ? starIndex + 0.5 : starIndex + 1;
|
|
8427
|
+
emitChange(newValue);
|
|
8428
|
+
};
|
|
8429
|
+
const handleStarHover = (starIndex, isHalf) => {
|
|
8430
|
+
if (readOnly) return;
|
|
8431
|
+
const newValue = isHalf && precision === "half" ? starIndex + 0.5 : starIndex + 1;
|
|
8432
|
+
setHoverValue(newValue);
|
|
8433
|
+
};
|
|
8434
|
+
const handleKeyDown = (e) => {
|
|
8435
|
+
if (readOnly) return;
|
|
8436
|
+
const stepSize = precision === "half" ? 0.5 : 1;
|
|
8437
|
+
if (e.key === "ArrowRight" || e.key === "ArrowUp") {
|
|
8438
|
+
e.preventDefault();
|
|
8439
|
+
emitChange(Math.min(max, value + stepSize));
|
|
8440
|
+
} else if (e.key === "ArrowLeft" || e.key === "ArrowDown") {
|
|
8441
|
+
e.preventDefault();
|
|
8442
|
+
emitChange(Math.max(0, value - stepSize));
|
|
8443
|
+
}
|
|
8444
|
+
};
|
|
7633
8445
|
return /* @__PURE__ */ jsx(
|
|
7634
|
-
|
|
8446
|
+
"div",
|
|
7635
8447
|
{
|
|
7636
|
-
className: cn(
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
8448
|
+
className: cn(
|
|
8449
|
+
"inline-flex items-center",
|
|
8450
|
+
styles.gap,
|
|
8451
|
+
!readOnly && "cursor-pointer",
|
|
8452
|
+
className
|
|
8453
|
+
),
|
|
8454
|
+
role: readOnly ? "img" : "slider",
|
|
8455
|
+
"aria-label": label ?? `Rating: ${value} out of ${max}`,
|
|
8456
|
+
"aria-valuemin": 0,
|
|
8457
|
+
"aria-valuemax": max,
|
|
8458
|
+
"aria-valuenow": value,
|
|
8459
|
+
tabIndex: readOnly ? void 0 : 0,
|
|
8460
|
+
onKeyDown: handleKeyDown,
|
|
8461
|
+
onMouseLeave: () => setHoverValue(null),
|
|
8462
|
+
children: Array.from({ length: max }, (_, i) => {
|
|
8463
|
+
const fillLevel = Math.max(0, Math.min(1, displayValue - i));
|
|
8464
|
+
const isFull = fillLevel >= 1;
|
|
8465
|
+
const isHalf = fillLevel >= 0.5 && fillLevel < 1;
|
|
7642
8466
|
return /* @__PURE__ */ jsxs(
|
|
7643
|
-
|
|
8467
|
+
"span",
|
|
7644
8468
|
{
|
|
7645
|
-
"
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
8469
|
+
className: "relative inline-block",
|
|
8470
|
+
onClick: () => handleStarClick(i, false),
|
|
8471
|
+
onMouseMove: (e) => {
|
|
8472
|
+
if (readOnly) return;
|
|
8473
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
8474
|
+
const isLeftHalf = e.clientX - rect.left < rect.width / 2;
|
|
8475
|
+
handleStarHover(i, isLeftHalf);
|
|
8476
|
+
},
|
|
7653
8477
|
children: [
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
7661
|
-
|
|
7662
|
-
|
|
7663
|
-
loading: "lazy"
|
|
7664
|
-
}
|
|
7665
|
-
) });
|
|
7666
|
-
})(),
|
|
7667
|
-
/* @__PURE__ */ jsx(Box, { className: "p-4 pb-0", children: /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
|
|
7668
|
-
/* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
|
|
7669
|
-
titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
7670
|
-
titleField?.icon && /* @__PURE__ */ jsx(Icon, { name: titleField.icon, size: "sm", className: "text-[var(--color-primary)] flex-shrink-0" }),
|
|
7671
|
-
/* @__PURE__ */ jsx(
|
|
7672
|
-
Typography,
|
|
7673
|
-
{
|
|
7674
|
-
variant: titleField?.variant === "h3" ? "h3" : "h4",
|
|
7675
|
-
className: "font-semibold truncate",
|
|
7676
|
-
children: String(titleValue)
|
|
7677
|
-
}
|
|
7678
|
-
)
|
|
7679
|
-
] }),
|
|
7680
|
-
badgeFields.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap", children: badgeFields.map((field) => {
|
|
7681
|
-
const val = getNestedValue(itemData, field.name);
|
|
7682
|
-
if (val === void 0 || val === null) return null;
|
|
7683
|
-
return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
7684
|
-
field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
|
|
7685
|
-
/* @__PURE__ */ jsx(Badge, { variant: statusVariant(String(val)), children: String(val) })
|
|
7686
|
-
] }, field.name);
|
|
7687
|
-
}) })
|
|
7688
|
-
] }),
|
|
7689
|
-
dangerActions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: dangerActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
7690
|
-
Button,
|
|
7691
|
-
{
|
|
7692
|
-
variant: "ghost",
|
|
7693
|
-
size: "sm",
|
|
7694
|
-
onClick: handleActionClick(action, itemData),
|
|
7695
|
-
"data-testid": `action-${action.event}`,
|
|
7696
|
-
className: "text-[var(--color-error)] hover:bg-[var(--color-error)]/10 px-2",
|
|
7697
|
-
children: [
|
|
7698
|
-
action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs" }),
|
|
7699
|
-
action.label
|
|
7700
|
-
]
|
|
7701
|
-
},
|
|
7702
|
-
idx
|
|
7703
|
-
)) })
|
|
7704
|
-
] }) }),
|
|
7705
|
-
bodyFields.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 flex-1", children: /* @__PURE__ */ jsx(VStack, { gap: "xs", children: bodyFields.map((field) => {
|
|
7706
|
-
const value = getNestedValue(itemData, field.name);
|
|
7707
|
-
if (value === void 0 || value === null || value === "") return null;
|
|
7708
|
-
if (field.format === "boolean") {
|
|
7709
|
-
return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
|
|
7710
|
-
/* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
7711
|
-
field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
|
|
7712
|
-
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel(field.name) })
|
|
7713
|
-
] }),
|
|
7714
|
-
/* @__PURE__ */ jsx(Badge, { variant: value ? "success" : "neutral", children: value ? t("common.yes") || "Yes" : t("common.no") || "No" })
|
|
7715
|
-
] }, field.name);
|
|
8478
|
+
/* @__PURE__ */ jsx(
|
|
8479
|
+
Star,
|
|
8480
|
+
{
|
|
8481
|
+
className: cn(
|
|
8482
|
+
styles.star,
|
|
8483
|
+
"text-[var(--color-muted)]",
|
|
8484
|
+
"transition-colors duration-100"
|
|
8485
|
+
),
|
|
8486
|
+
strokeWidth: 1.5
|
|
7716
8487
|
}
|
|
7717
|
-
|
|
7718
|
-
|
|
7719
|
-
|
|
7720
|
-
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel(field.name) })
|
|
7721
|
-
] }),
|
|
7722
|
-
/* @__PURE__ */ jsx(
|
|
7723
|
-
Typography,
|
|
7724
|
-
{
|
|
7725
|
-
variant: field.variant === "caption" ? "caption" : "small",
|
|
7726
|
-
className: "text-right truncate max-w-[60%]",
|
|
7727
|
-
children: formatValue(value, field.format)
|
|
7728
|
-
}
|
|
7729
|
-
)
|
|
7730
|
-
] }, field.name);
|
|
7731
|
-
}) }) }),
|
|
7732
|
-
primaryActions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 mt-auto border-t border-[var(--color-border)]", children: /* @__PURE__ */ jsx(HStack, { gap: "sm", className: "justify-end", children: primaryActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
7733
|
-
Button,
|
|
8488
|
+
),
|
|
8489
|
+
(isFull || isHalf) && /* @__PURE__ */ jsx(
|
|
8490
|
+
Star,
|
|
7734
8491
|
{
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
|
|
7743
|
-
}
|
|
7744
|
-
|
|
7745
|
-
|
|
8492
|
+
className: cn(
|
|
8493
|
+
styles.star,
|
|
8494
|
+
"absolute inset-0",
|
|
8495
|
+
"text-[var(--color-warning)] fill-[var(--color-warning)]",
|
|
8496
|
+
"transition-colors duration-100"
|
|
8497
|
+
),
|
|
8498
|
+
strokeWidth: 1.5,
|
|
8499
|
+
style: isHalf ? { clipPath: "inset(0 50% 0 0)" } : void 0
|
|
8500
|
+
}
|
|
8501
|
+
),
|
|
8502
|
+
!readOnly && precision === "half" && /* @__PURE__ */ jsx(
|
|
8503
|
+
"span",
|
|
8504
|
+
{
|
|
8505
|
+
className: "absolute inset-0 w-1/2",
|
|
8506
|
+
onClick: (e) => {
|
|
8507
|
+
e.stopPropagation();
|
|
8508
|
+
handleStarClick(i, true);
|
|
8509
|
+
}
|
|
8510
|
+
}
|
|
8511
|
+
)
|
|
7746
8512
|
]
|
|
7747
8513
|
},
|
|
7748
|
-
|
|
8514
|
+
i
|
|
7749
8515
|
);
|
|
7750
8516
|
})
|
|
7751
8517
|
}
|
|
7752
8518
|
);
|
|
7753
8519
|
};
|
|
7754
|
-
|
|
7755
|
-
function
|
|
8520
|
+
StarRating.displayName = "StarRating";
|
|
8521
|
+
function useSafeEventBus6() {
|
|
8522
|
+
try {
|
|
8523
|
+
return useEventBus();
|
|
8524
|
+
} catch {
|
|
8525
|
+
return { emit: () => {
|
|
8526
|
+
}, on: () => () => {
|
|
8527
|
+
}, once: () => {
|
|
8528
|
+
} };
|
|
8529
|
+
}
|
|
8530
|
+
}
|
|
8531
|
+
function formatFileSize(bytes) {
|
|
8532
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
8533
|
+
if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)}KB`;
|
|
8534
|
+
return `${Math.round(bytes / (1024 * 1024))}MB`;
|
|
8535
|
+
}
|
|
8536
|
+
var UploadDropZone = ({
|
|
8537
|
+
accept,
|
|
8538
|
+
maxSize,
|
|
8539
|
+
maxFiles = 1,
|
|
8540
|
+
label = "Drop files here or click to browse",
|
|
8541
|
+
description,
|
|
8542
|
+
disabled = false,
|
|
8543
|
+
action,
|
|
8544
|
+
actionPayload,
|
|
8545
|
+
onFiles,
|
|
8546
|
+
className
|
|
8547
|
+
}) => {
|
|
8548
|
+
const [isDragOver, setIsDragOver] = useState(false);
|
|
8549
|
+
const [error, setError] = useState(null);
|
|
8550
|
+
const inputRef = useRef(null);
|
|
8551
|
+
const eventBus = useSafeEventBus6();
|
|
8552
|
+
const defaultDescription = [
|
|
8553
|
+
accept ? `Accepted: ${accept}` : null,
|
|
8554
|
+
maxSize ? `Max size: ${formatFileSize(maxSize)}` : null,
|
|
8555
|
+
maxFiles > 1 ? `Up to ${maxFiles} files` : null
|
|
8556
|
+
].filter(Boolean).join(". ");
|
|
8557
|
+
const validateFiles = useCallback(
|
|
8558
|
+
(files) => {
|
|
8559
|
+
if (files.length > maxFiles) {
|
|
8560
|
+
return { valid: [], error: `Maximum ${maxFiles} file${maxFiles > 1 ? "s" : ""} allowed` };
|
|
8561
|
+
}
|
|
8562
|
+
if (accept) {
|
|
8563
|
+
const acceptedTypes = accept.split(",").map((t) => t.trim());
|
|
8564
|
+
const invalid = files.filter((file) => {
|
|
8565
|
+
return !acceptedTypes.some((type) => {
|
|
8566
|
+
if (type.endsWith("/*")) {
|
|
8567
|
+
return file.type.startsWith(type.replace("/*", "/"));
|
|
8568
|
+
}
|
|
8569
|
+
return file.type === type || file.name.endsWith(type);
|
|
8570
|
+
});
|
|
8571
|
+
});
|
|
8572
|
+
if (invalid.length > 0) {
|
|
8573
|
+
return { valid: [], error: `Invalid file type: ${invalid[0].name}` };
|
|
8574
|
+
}
|
|
8575
|
+
}
|
|
8576
|
+
if (maxSize) {
|
|
8577
|
+
const tooLarge = files.filter((file) => file.size > maxSize);
|
|
8578
|
+
if (tooLarge.length > 0) {
|
|
8579
|
+
return {
|
|
8580
|
+
valid: [],
|
|
8581
|
+
error: `File too large: ${tooLarge[0].name} (max ${formatFileSize(maxSize)})`
|
|
8582
|
+
};
|
|
8583
|
+
}
|
|
8584
|
+
}
|
|
8585
|
+
return { valid: files, error: null };
|
|
8586
|
+
},
|
|
8587
|
+
[accept, maxSize, maxFiles]
|
|
8588
|
+
);
|
|
8589
|
+
const handleFiles = useCallback(
|
|
8590
|
+
(files) => {
|
|
8591
|
+
const { valid, error: validationError } = validateFiles(files);
|
|
8592
|
+
setError(validationError);
|
|
8593
|
+
if (valid.length > 0) {
|
|
8594
|
+
onFiles?.(valid);
|
|
8595
|
+
if (action) {
|
|
8596
|
+
eventBus.emit(`UI:${action}`, {
|
|
8597
|
+
...actionPayload,
|
|
8598
|
+
files: valid.map((f) => ({ name: f.name, size: f.size, type: f.type }))
|
|
8599
|
+
});
|
|
8600
|
+
}
|
|
8601
|
+
}
|
|
8602
|
+
},
|
|
8603
|
+
[validateFiles, onFiles, action, actionPayload, eventBus]
|
|
8604
|
+
);
|
|
8605
|
+
const handleDragOver = (e) => {
|
|
8606
|
+
e.preventDefault();
|
|
8607
|
+
e.stopPropagation();
|
|
8608
|
+
if (!disabled) setIsDragOver(true);
|
|
8609
|
+
};
|
|
8610
|
+
const handleDragLeave = (e) => {
|
|
8611
|
+
e.preventDefault();
|
|
8612
|
+
e.stopPropagation();
|
|
8613
|
+
setIsDragOver(false);
|
|
8614
|
+
};
|
|
8615
|
+
const handleDrop = (e) => {
|
|
8616
|
+
e.preventDefault();
|
|
8617
|
+
e.stopPropagation();
|
|
8618
|
+
setIsDragOver(false);
|
|
8619
|
+
if (disabled) return;
|
|
8620
|
+
const files = Array.from(e.dataTransfer.files);
|
|
8621
|
+
handleFiles(files);
|
|
8622
|
+
};
|
|
8623
|
+
const handleClick = () => {
|
|
8624
|
+
if (!disabled) inputRef.current?.click();
|
|
8625
|
+
};
|
|
8626
|
+
const handleInputChange = (e) => {
|
|
8627
|
+
const files = Array.from(e.target.files ?? []);
|
|
8628
|
+
if (files.length > 0) handleFiles(files);
|
|
8629
|
+
e.target.value = "";
|
|
8630
|
+
};
|
|
8631
|
+
return /* @__PURE__ */ jsxs(
|
|
8632
|
+
"div",
|
|
8633
|
+
{
|
|
8634
|
+
className: cn(
|
|
8635
|
+
"relative flex flex-col items-center justify-center",
|
|
8636
|
+
"p-8 rounded-[var(--radius-sm)]",
|
|
8637
|
+
"border-2 border-dashed",
|
|
8638
|
+
"transition-colors duration-150",
|
|
8639
|
+
"cursor-pointer",
|
|
8640
|
+
isDragOver ? "border-[var(--color-primary)] bg-[var(--color-primary)] bg-opacity-5" : "border-[var(--color-border)] bg-[var(--color-surface)]",
|
|
8641
|
+
error && "border-[var(--color-error)]",
|
|
8642
|
+
disabled && "opacity-50 cursor-not-allowed",
|
|
8643
|
+
"hover:border-[var(--color-primary)] hover:bg-[var(--color-muted)]",
|
|
8644
|
+
className
|
|
8645
|
+
),
|
|
8646
|
+
onDragOver: handleDragOver,
|
|
8647
|
+
onDragLeave: handleDragLeave,
|
|
8648
|
+
onDrop: handleDrop,
|
|
8649
|
+
onClick: handleClick,
|
|
8650
|
+
role: "button",
|
|
8651
|
+
tabIndex: disabled ? -1 : 0,
|
|
8652
|
+
onKeyDown: (e) => {
|
|
8653
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
8654
|
+
e.preventDefault();
|
|
8655
|
+
handleClick();
|
|
8656
|
+
}
|
|
8657
|
+
},
|
|
8658
|
+
"aria-label": label,
|
|
8659
|
+
children: [
|
|
8660
|
+
/* @__PURE__ */ jsx(
|
|
8661
|
+
"input",
|
|
8662
|
+
{
|
|
8663
|
+
ref: inputRef,
|
|
8664
|
+
type: "file",
|
|
8665
|
+
accept,
|
|
8666
|
+
multiple: maxFiles > 1,
|
|
8667
|
+
onChange: handleInputChange,
|
|
8668
|
+
className: "hidden",
|
|
8669
|
+
disabled,
|
|
8670
|
+
"aria-hidden": "true"
|
|
8671
|
+
}
|
|
8672
|
+
),
|
|
8673
|
+
error ? /* @__PURE__ */ jsx(Icon, { icon: FileWarning, size: "lg", className: "text-[var(--color-error)] mb-2" }) : /* @__PURE__ */ jsx(Icon, { icon: Upload, size: "lg", className: "text-[var(--color-muted-foreground)] mb-2" }),
|
|
8674
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-center font-medium mb-1", children: isDragOver ? "Drop files here" : label }),
|
|
8675
|
+
error ? /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "error", className: "text-center", children: error }) : /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", className: "text-center", children: description ?? defaultDescription })
|
|
8676
|
+
]
|
|
8677
|
+
}
|
|
8678
|
+
);
|
|
8679
|
+
};
|
|
8680
|
+
UploadDropZone.displayName = "UploadDropZone";
|
|
8681
|
+
function useSafeEventBus7() {
|
|
8682
|
+
try {
|
|
8683
|
+
return useEventBus();
|
|
8684
|
+
} catch {
|
|
8685
|
+
return { emit: () => {
|
|
8686
|
+
}, on: () => () => {
|
|
8687
|
+
}, once: () => {
|
|
8688
|
+
} };
|
|
8689
|
+
}
|
|
8690
|
+
}
|
|
8691
|
+
var Lightbox = ({
|
|
8692
|
+
images,
|
|
8693
|
+
currentIndex = 0,
|
|
8694
|
+
isOpen = false,
|
|
8695
|
+
showCounter = true,
|
|
8696
|
+
closeAction,
|
|
8697
|
+
onClose,
|
|
8698
|
+
onIndexChange,
|
|
8699
|
+
className
|
|
8700
|
+
}) => {
|
|
8701
|
+
const [index, setIndex] = useState(currentIndex);
|
|
8702
|
+
const [touchStartX, setTouchStartX] = useState(null);
|
|
8703
|
+
const eventBus = useSafeEventBus7();
|
|
8704
|
+
useEffect(() => {
|
|
8705
|
+
setIndex(currentIndex);
|
|
8706
|
+
}, [currentIndex]);
|
|
8707
|
+
const handleClose = useCallback(() => {
|
|
8708
|
+
if (closeAction) {
|
|
8709
|
+
eventBus.emit(`UI:${closeAction}`, {});
|
|
8710
|
+
}
|
|
8711
|
+
onClose?.();
|
|
8712
|
+
}, [closeAction, eventBus, onClose]);
|
|
8713
|
+
const goTo = useCallback(
|
|
8714
|
+
(newIndex) => {
|
|
8715
|
+
const clamped = Math.max(0, Math.min(images.length - 1, newIndex));
|
|
8716
|
+
setIndex(clamped);
|
|
8717
|
+
onIndexChange?.(clamped);
|
|
8718
|
+
},
|
|
8719
|
+
[images.length, onIndexChange]
|
|
8720
|
+
);
|
|
8721
|
+
const goPrev = useCallback(() => goTo(index - 1), [goTo, index]);
|
|
8722
|
+
const goNext = useCallback(() => goTo(index + 1), [goTo, index]);
|
|
8723
|
+
useEffect(() => {
|
|
8724
|
+
if (!isOpen) return;
|
|
8725
|
+
const handleKeyDown = (e) => {
|
|
8726
|
+
switch (e.key) {
|
|
8727
|
+
case "Escape":
|
|
8728
|
+
handleClose();
|
|
8729
|
+
break;
|
|
8730
|
+
case "ArrowLeft":
|
|
8731
|
+
goPrev();
|
|
8732
|
+
break;
|
|
8733
|
+
case "ArrowRight":
|
|
8734
|
+
goNext();
|
|
8735
|
+
break;
|
|
8736
|
+
}
|
|
8737
|
+
};
|
|
8738
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
8739
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
8740
|
+
}, [isOpen, handleClose, goPrev, goNext]);
|
|
8741
|
+
useEffect(() => {
|
|
8742
|
+
if (isOpen) {
|
|
8743
|
+
document.body.style.overflow = "hidden";
|
|
8744
|
+
return () => {
|
|
8745
|
+
document.body.style.overflow = "";
|
|
8746
|
+
};
|
|
8747
|
+
}
|
|
8748
|
+
}, [isOpen]);
|
|
8749
|
+
if (!isOpen || images.length === 0) return null;
|
|
8750
|
+
const currentImage = images[index];
|
|
8751
|
+
const hasPrev = index > 0;
|
|
8752
|
+
const hasNext = index < images.length - 1;
|
|
8753
|
+
const handleTouchStart = (e) => {
|
|
8754
|
+
setTouchStartX(e.touches[0].clientX);
|
|
8755
|
+
};
|
|
8756
|
+
const handleTouchEnd = (e) => {
|
|
8757
|
+
if (touchStartX === null) return;
|
|
8758
|
+
const diff = e.changedTouches[0].clientX - touchStartX;
|
|
8759
|
+
const threshold = 50;
|
|
8760
|
+
if (diff > threshold && hasPrev) goPrev();
|
|
8761
|
+
if (diff < -threshold && hasNext) goNext();
|
|
8762
|
+
setTouchStartX(null);
|
|
8763
|
+
};
|
|
8764
|
+
return /* @__PURE__ */ jsxs(
|
|
8765
|
+
"div",
|
|
8766
|
+
{
|
|
8767
|
+
className: cn(
|
|
8768
|
+
"fixed inset-0 z-50 flex items-center justify-center",
|
|
8769
|
+
"bg-black bg-opacity-90",
|
|
8770
|
+
className
|
|
8771
|
+
),
|
|
8772
|
+
onClick: handleClose,
|
|
8773
|
+
role: "dialog",
|
|
8774
|
+
"aria-modal": "true",
|
|
8775
|
+
"aria-label": currentImage?.alt ?? "Image viewer",
|
|
8776
|
+
children: [
|
|
8777
|
+
/* @__PURE__ */ jsx(
|
|
8778
|
+
"button",
|
|
8779
|
+
{
|
|
8780
|
+
type: "button",
|
|
8781
|
+
onClick: (e) => {
|
|
8782
|
+
e.stopPropagation();
|
|
8783
|
+
handleClose();
|
|
8784
|
+
},
|
|
8785
|
+
className: cn(
|
|
8786
|
+
"absolute top-4 right-4 z-10",
|
|
8787
|
+
"p-2 rounded-full",
|
|
8788
|
+
"text-white bg-black bg-opacity-50",
|
|
8789
|
+
"hover:bg-opacity-70 transition-opacity",
|
|
8790
|
+
"focus:outline-none focus:ring-2 focus:ring-white"
|
|
8791
|
+
),
|
|
8792
|
+
"aria-label": "Close",
|
|
8793
|
+
children: /* @__PURE__ */ jsx(X, { className: "w-6 h-6" })
|
|
8794
|
+
}
|
|
8795
|
+
),
|
|
8796
|
+
hasPrev && images.length > 1 && /* @__PURE__ */ jsx(
|
|
8797
|
+
"button",
|
|
8798
|
+
{
|
|
8799
|
+
type: "button",
|
|
8800
|
+
onClick: (e) => {
|
|
8801
|
+
e.stopPropagation();
|
|
8802
|
+
goPrev();
|
|
8803
|
+
},
|
|
8804
|
+
className: cn(
|
|
8805
|
+
"absolute left-4 z-10",
|
|
8806
|
+
"p-2 rounded-full",
|
|
8807
|
+
"text-white bg-black bg-opacity-50",
|
|
8808
|
+
"hover:bg-opacity-70 transition-opacity",
|
|
8809
|
+
"focus:outline-none focus:ring-2 focus:ring-white"
|
|
8810
|
+
),
|
|
8811
|
+
"aria-label": "Previous image",
|
|
8812
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "w-8 h-8" })
|
|
8813
|
+
}
|
|
8814
|
+
),
|
|
8815
|
+
/* @__PURE__ */ jsx(
|
|
8816
|
+
"div",
|
|
8817
|
+
{
|
|
8818
|
+
className: "flex items-center justify-center w-full h-full p-12",
|
|
8819
|
+
onClick: (e) => e.stopPropagation(),
|
|
8820
|
+
onTouchStart: handleTouchStart,
|
|
8821
|
+
onTouchEnd: handleTouchEnd,
|
|
8822
|
+
children: currentImage && /* @__PURE__ */ jsx(
|
|
8823
|
+
"img",
|
|
8824
|
+
{
|
|
8825
|
+
src: currentImage.src,
|
|
8826
|
+
alt: currentImage.alt ?? "",
|
|
8827
|
+
className: "max-w-full max-h-full object-contain select-none",
|
|
8828
|
+
draggable: false
|
|
8829
|
+
}
|
|
8830
|
+
)
|
|
8831
|
+
}
|
|
8832
|
+
),
|
|
8833
|
+
hasNext && images.length > 1 && /* @__PURE__ */ jsx(
|
|
8834
|
+
"button",
|
|
8835
|
+
{
|
|
8836
|
+
type: "button",
|
|
8837
|
+
onClick: (e) => {
|
|
8838
|
+
e.stopPropagation();
|
|
8839
|
+
goNext();
|
|
8840
|
+
},
|
|
8841
|
+
className: cn(
|
|
8842
|
+
"absolute right-4 z-10",
|
|
8843
|
+
"p-2 rounded-full",
|
|
8844
|
+
"text-white bg-black bg-opacity-50",
|
|
8845
|
+
"hover:bg-opacity-70 transition-opacity",
|
|
8846
|
+
"focus:outline-none focus:ring-2 focus:ring-white"
|
|
8847
|
+
),
|
|
8848
|
+
"aria-label": "Next image",
|
|
8849
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "w-8 h-8" })
|
|
8850
|
+
}
|
|
8851
|
+
),
|
|
8852
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute bottom-4 left-0 right-0 text-center", children: [
|
|
8853
|
+
showCounter && images.length > 1 && /* @__PURE__ */ jsxs("div", { className: "text-white text-sm mb-1", children: [
|
|
8854
|
+
index + 1,
|
|
8855
|
+
" of ",
|
|
8856
|
+
images.length
|
|
8857
|
+
] }),
|
|
8858
|
+
currentImage?.caption && /* @__PURE__ */ jsx("div", { className: "text-white text-sm opacity-80 px-8", children: currentImage.caption })
|
|
8859
|
+
] })
|
|
8860
|
+
]
|
|
8861
|
+
}
|
|
8862
|
+
);
|
|
8863
|
+
};
|
|
8864
|
+
Lightbox.displayName = "Lightbox";
|
|
8865
|
+
function fieldLabel(key) {
|
|
7756
8866
|
return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
7757
8867
|
}
|
|
7758
|
-
function
|
|
8868
|
+
function statusVariant(value) {
|
|
7759
8869
|
const v = value.toLowerCase();
|
|
7760
8870
|
if (["active", "completed", "done", "approved", "published", "resolved", "open", "online"].includes(v)) return "success";
|
|
7761
8871
|
if (["pending", "in_progress", "in-progress", "review", "draft", "processing", "warning"].includes(v)) return "warning";
|
|
@@ -7763,17 +8873,17 @@ function statusVariant2(value) {
|
|
|
7763
8873
|
if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
|
|
7764
8874
|
return "default";
|
|
7765
8875
|
}
|
|
7766
|
-
function
|
|
8876
|
+
function formatDate(value) {
|
|
7767
8877
|
if (!value) return "";
|
|
7768
8878
|
const d = new Date(String(value));
|
|
7769
8879
|
if (isNaN(d.getTime())) return String(value);
|
|
7770
8880
|
return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
|
|
7771
8881
|
}
|
|
7772
|
-
function
|
|
8882
|
+
function formatValue(value, format) {
|
|
7773
8883
|
if (value === void 0 || value === null) return "";
|
|
7774
8884
|
switch (format) {
|
|
7775
8885
|
case "date":
|
|
7776
|
-
return
|
|
8886
|
+
return formatDate(value);
|
|
7777
8887
|
case "currency":
|
|
7778
8888
|
return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
|
|
7779
8889
|
case "number":
|
|
@@ -7786,31 +8896,81 @@ function formatValue2(value, format) {
|
|
|
7786
8896
|
return String(value);
|
|
7787
8897
|
}
|
|
7788
8898
|
}
|
|
7789
|
-
var
|
|
8899
|
+
var gapStyles5 = {
|
|
8900
|
+
none: "gap-0",
|
|
8901
|
+
sm: "gap-2",
|
|
8902
|
+
md: "gap-4",
|
|
8903
|
+
lg: "gap-6",
|
|
8904
|
+
xl: "gap-8"
|
|
8905
|
+
};
|
|
8906
|
+
var DataGrid = ({
|
|
7790
8907
|
entity,
|
|
7791
8908
|
fields: fieldsProp,
|
|
7792
8909
|
columns: columnsProp,
|
|
7793
8910
|
itemActions,
|
|
7794
|
-
|
|
7795
|
-
|
|
8911
|
+
cols,
|
|
8912
|
+
gap = "md",
|
|
8913
|
+
minCardWidth = 280,
|
|
7796
8914
|
className,
|
|
7797
8915
|
isLoading = false,
|
|
7798
|
-
error = null
|
|
8916
|
+
error = null,
|
|
8917
|
+
imageField,
|
|
8918
|
+
selectable = false,
|
|
8919
|
+
selectionEvent,
|
|
8920
|
+
infiniteScroll,
|
|
8921
|
+
loadMoreEvent,
|
|
8922
|
+
hasMore,
|
|
8923
|
+
children,
|
|
8924
|
+
pageSize = 0
|
|
7799
8925
|
}) => {
|
|
7800
8926
|
const eventBus = useEventBus();
|
|
7801
8927
|
const { t } = useTranslate();
|
|
8928
|
+
const [selectedIds, setSelectedIds] = useState(/* @__PURE__ */ new Set());
|
|
8929
|
+
const [visibleCount, setVisibleCount] = useState(pageSize || Infinity);
|
|
7802
8930
|
const fields = fieldsProp ?? columnsProp ?? [];
|
|
7803
|
-
const
|
|
8931
|
+
const allData = Array.isArray(entity) ? entity : entity ? [entity] : [];
|
|
8932
|
+
const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
|
|
8933
|
+
const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
|
|
8934
|
+
const toggleSelection = useCallback((id) => {
|
|
8935
|
+
setSelectedIds((prev) => {
|
|
8936
|
+
const next = new Set(prev);
|
|
8937
|
+
if (next.has(id)) next.delete(id);
|
|
8938
|
+
else next.add(id);
|
|
8939
|
+
if (selectionEvent) {
|
|
8940
|
+
eventBus.emit(`UI:${selectionEvent}`, { selectedIds: Array.from(next) });
|
|
8941
|
+
}
|
|
8942
|
+
return next;
|
|
8943
|
+
});
|
|
8944
|
+
}, [selectionEvent, eventBus]);
|
|
8945
|
+
const toggleAll = useCallback(() => {
|
|
8946
|
+
setSelectedIds((prev) => {
|
|
8947
|
+
const allIds2 = data.map((item, i) => item.id || String(i));
|
|
8948
|
+
const allSelected2 = allIds2.length > 0 && allIds2.every((id) => prev.has(id));
|
|
8949
|
+
const next = allSelected2 ? /* @__PURE__ */ new Set() : new Set(allIds2);
|
|
8950
|
+
if (selectionEvent) {
|
|
8951
|
+
eventBus.emit(`UI:${selectionEvent}`, { selectedIds: Array.from(next) });
|
|
8952
|
+
}
|
|
8953
|
+
return next;
|
|
8954
|
+
});
|
|
8955
|
+
}, [data, selectionEvent, eventBus]);
|
|
7804
8956
|
const titleField = fields.find((f) => f.variant === "h3" || f.variant === "h4") ?? fields[0];
|
|
7805
8957
|
const badgeFields = fields.filter((f) => f.variant === "badge" && f !== titleField);
|
|
7806
|
-
const
|
|
7807
|
-
const
|
|
7808
|
-
|
|
7809
|
-
);
|
|
8958
|
+
const bodyFields = fields.filter((f) => f !== titleField && !badgeFields.includes(f));
|
|
8959
|
+
const primaryActions = itemActions?.filter((a) => a.variant !== "danger") ?? [];
|
|
8960
|
+
const dangerActions = itemActions?.filter((a) => a.variant === "danger") ?? [];
|
|
7810
8961
|
const handleActionClick = (action, itemData) => (e) => {
|
|
7811
8962
|
e.stopPropagation();
|
|
7812
|
-
eventBus.emit(`UI:${action.event}`, { row: itemData });
|
|
8963
|
+
eventBus.emit(`UI:${action.event}`, { id: itemData.id, row: itemData });
|
|
7813
8964
|
};
|
|
8965
|
+
const gridTemplateColumns = cols ? void 0 : `repeat(auto-fit, minmax(min(${minCardWidth}px, 100%), 1fr))`;
|
|
8966
|
+
const colsClass = cols ? {
|
|
8967
|
+
1: "grid-cols-1",
|
|
8968
|
+
2: "sm:grid-cols-2",
|
|
8969
|
+
3: "sm:grid-cols-2 lg:grid-cols-3",
|
|
8970
|
+
4: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
|
|
8971
|
+
5: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5",
|
|
8972
|
+
6: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6"
|
|
8973
|
+
}[cols] : void 0;
|
|
7814
8974
|
if (isLoading) {
|
|
7815
8975
|
return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
|
|
7816
8976
|
}
|
|
@@ -7820,126 +8980,1428 @@ var DataList = ({
|
|
|
7820
8980
|
if (data.length === 0) {
|
|
7821
8981
|
return /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
|
|
7822
8982
|
}
|
|
7823
|
-
const
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
8983
|
+
const hasRenderProp = typeof children === "function";
|
|
8984
|
+
const allIds = data.map((item, i) => item.id || String(i));
|
|
8985
|
+
const allSelected = allIds.length > 0 && allIds.every((id) => selectedIds.has(id));
|
|
8986
|
+
const someSelected = selectedIds.size > 0;
|
|
8987
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
8988
|
+
selectable && someSelected && /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center px-2 py-2 bg-[var(--color-muted)] rounded-[var(--radius-sm)]", children: [
|
|
8989
|
+
/* @__PURE__ */ jsx(
|
|
8990
|
+
"input",
|
|
8991
|
+
{
|
|
8992
|
+
type: "checkbox",
|
|
8993
|
+
checked: allSelected,
|
|
8994
|
+
onChange: toggleAll,
|
|
8995
|
+
className: "w-4 h-4 accent-[var(--color-primary)]",
|
|
8996
|
+
"aria-label": "Select all"
|
|
8997
|
+
}
|
|
8998
|
+
),
|
|
8999
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "font-semibold", children: [
|
|
9000
|
+
selectedIds.size,
|
|
9001
|
+
" ",
|
|
9002
|
+
t("common.selected") || "selected"
|
|
9003
|
+
] })
|
|
9004
|
+
] }),
|
|
9005
|
+
/* @__PURE__ */ jsx(
|
|
9006
|
+
Box,
|
|
9007
|
+
{
|
|
9008
|
+
className: cn("grid", gapStyles5[gap], colsClass, className),
|
|
9009
|
+
style: gridTemplateColumns ? { gridTemplateColumns } : void 0,
|
|
9010
|
+
children: data.map((item, index) => {
|
|
9011
|
+
const itemData = item;
|
|
9012
|
+
const id = itemData.id || String(index);
|
|
9013
|
+
const isSelected = selectedIds.has(id);
|
|
9014
|
+
if (hasRenderProp) {
|
|
9015
|
+
return /* @__PURE__ */ jsx(
|
|
9016
|
+
Box,
|
|
9017
|
+
{
|
|
9018
|
+
"data-entity-row": true,
|
|
9019
|
+
className: cn(
|
|
9020
|
+
"bg-[var(--color-card)] rounded-[var(--radius-lg)]",
|
|
9021
|
+
"border border-[var(--color-border)]",
|
|
9022
|
+
"shadow-[var(--shadow-sm)] hover:shadow-[var(--shadow-hover)]",
|
|
9023
|
+
"hover:border-[var(--color-primary)] transition-all",
|
|
9024
|
+
"p-4",
|
|
9025
|
+
isSelected && "ring-2 ring-[var(--color-primary)] border-[var(--color-primary)]"
|
|
9026
|
+
),
|
|
9027
|
+
children: children(itemData, index)
|
|
9028
|
+
},
|
|
9029
|
+
id
|
|
9030
|
+
);
|
|
9031
|
+
}
|
|
9032
|
+
const titleValue = getNestedValue(itemData, titleField?.name ?? "");
|
|
9033
|
+
return /* @__PURE__ */ jsxs(
|
|
9034
|
+
Box,
|
|
9035
|
+
{
|
|
9036
|
+
"data-entity-row": true,
|
|
9037
|
+
className: cn(
|
|
9038
|
+
"bg-[var(--color-card)] rounded-[var(--radius-lg)]",
|
|
9039
|
+
"border border-[var(--color-border)]",
|
|
9040
|
+
"shadow-[var(--shadow-sm)] hover:shadow-[var(--shadow-hover)]",
|
|
9041
|
+
"hover:border-[var(--color-primary)] transition-all",
|
|
9042
|
+
"flex flex-col",
|
|
9043
|
+
isSelected && "ring-2 ring-[var(--color-primary)] border-[var(--color-primary)]"
|
|
9044
|
+
),
|
|
9045
|
+
children: [
|
|
9046
|
+
imageField && (() => {
|
|
9047
|
+
const imgUrl = getNestedValue(itemData, imageField);
|
|
9048
|
+
if (!imgUrl || typeof imgUrl !== "string") return null;
|
|
9049
|
+
return /* @__PURE__ */ jsx(Box, { className: "w-full aspect-video overflow-hidden rounded-t-[var(--radius-lg)]", children: /* @__PURE__ */ jsx(
|
|
9050
|
+
"img",
|
|
9051
|
+
{
|
|
9052
|
+
src: imgUrl,
|
|
9053
|
+
alt: titleValue !== void 0 ? String(titleValue) : "",
|
|
9054
|
+
className: "w-full h-full object-cover",
|
|
9055
|
+
loading: "lazy"
|
|
9056
|
+
}
|
|
9057
|
+
) });
|
|
9058
|
+
})(),
|
|
9059
|
+
/* @__PURE__ */ jsx(Box, { className: "p-4 pb-0", children: /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
|
|
9060
|
+
selectable && /* @__PURE__ */ jsx(
|
|
9061
|
+
"input",
|
|
9062
|
+
{
|
|
9063
|
+
type: "checkbox",
|
|
9064
|
+
checked: isSelected,
|
|
9065
|
+
onChange: () => toggleSelection(id),
|
|
9066
|
+
onClick: (e) => e.stopPropagation(),
|
|
9067
|
+
className: "w-4 h-4 mt-1 flex-shrink-0 accent-[var(--color-primary)]",
|
|
9068
|
+
"aria-label": `Select ${titleValue !== void 0 ? String(titleValue) : "item"}`
|
|
9069
|
+
}
|
|
9070
|
+
),
|
|
9071
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
|
|
9072
|
+
titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
9073
|
+
titleField?.icon && /* @__PURE__ */ jsx(Icon, { name: titleField.icon, size: "sm", className: "text-[var(--color-primary)] flex-shrink-0" }),
|
|
9074
|
+
/* @__PURE__ */ jsx(
|
|
9075
|
+
Typography,
|
|
9076
|
+
{
|
|
9077
|
+
variant: titleField?.variant === "h3" ? "h3" : "h4",
|
|
9078
|
+
className: "font-semibold truncate",
|
|
9079
|
+
children: String(titleValue)
|
|
9080
|
+
}
|
|
9081
|
+
)
|
|
9082
|
+
] }),
|
|
9083
|
+
badgeFields.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap", children: badgeFields.map((field) => {
|
|
9084
|
+
const val = getNestedValue(itemData, field.name);
|
|
9085
|
+
if (val === void 0 || val === null) return null;
|
|
9086
|
+
return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
9087
|
+
field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
|
|
9088
|
+
/* @__PURE__ */ jsx(Badge, { variant: statusVariant(String(val)), children: String(val) })
|
|
9089
|
+
] }, field.name);
|
|
9090
|
+
}) })
|
|
9091
|
+
] }),
|
|
9092
|
+
dangerActions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: dangerActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
9093
|
+
Button,
|
|
9094
|
+
{
|
|
9095
|
+
variant: "ghost",
|
|
9096
|
+
size: "sm",
|
|
9097
|
+
onClick: handleActionClick(action, itemData),
|
|
9098
|
+
"data-testid": `action-${action.event}`,
|
|
9099
|
+
className: "text-[var(--color-error)] hover:bg-[var(--color-error)]/10 px-2",
|
|
9100
|
+
children: [
|
|
9101
|
+
action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs" }),
|
|
9102
|
+
action.label
|
|
9103
|
+
]
|
|
9104
|
+
},
|
|
9105
|
+
idx
|
|
9106
|
+
)) })
|
|
9107
|
+
] }) }),
|
|
9108
|
+
bodyFields.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 flex-1", children: /* @__PURE__ */ jsx(VStack, { gap: "xs", children: bodyFields.map((field) => {
|
|
9109
|
+
const value = getNestedValue(itemData, field.name);
|
|
9110
|
+
if (value === void 0 || value === null || value === "") return null;
|
|
9111
|
+
if (field.format === "boolean") {
|
|
9112
|
+
return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
|
|
9113
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
9114
|
+
field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
|
|
9115
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel(field.name) })
|
|
9116
|
+
] }),
|
|
9117
|
+
/* @__PURE__ */ jsx(Badge, { variant: value ? "success" : "neutral", children: value ? t("common.yes") || "Yes" : t("common.no") || "No" })
|
|
9118
|
+
] }, field.name);
|
|
9119
|
+
}
|
|
9120
|
+
return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
|
|
9121
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
9122
|
+
field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
|
|
9123
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel(field.name) })
|
|
9124
|
+
] }),
|
|
9125
|
+
/* @__PURE__ */ jsx(
|
|
9126
|
+
Typography,
|
|
9127
|
+
{
|
|
9128
|
+
variant: field.variant === "caption" ? "caption" : "small",
|
|
9129
|
+
className: "text-right truncate max-w-[60%]",
|
|
9130
|
+
children: formatValue(value, field.format)
|
|
9131
|
+
}
|
|
9132
|
+
)
|
|
9133
|
+
] }, field.name);
|
|
9134
|
+
}) }) }),
|
|
9135
|
+
primaryActions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 mt-auto border-t border-[var(--color-border)]", children: /* @__PURE__ */ jsx(HStack, { gap: "sm", className: "justify-end", children: primaryActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
9136
|
+
Button,
|
|
9137
|
+
{
|
|
9138
|
+
variant: action.variant === "primary" ? "primary" : "ghost",
|
|
9139
|
+
size: "sm",
|
|
9140
|
+
onClick: handleActionClick(action, itemData),
|
|
9141
|
+
"data-testid": `action-${action.event}`,
|
|
9142
|
+
children: [
|
|
9143
|
+
action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
|
|
9144
|
+
action.label
|
|
9145
|
+
]
|
|
9146
|
+
},
|
|
9147
|
+
idx
|
|
9148
|
+
)) }) })
|
|
9149
|
+
]
|
|
9150
|
+
},
|
|
9151
|
+
id
|
|
9152
|
+
);
|
|
9153
|
+
})
|
|
9154
|
+
}
|
|
9155
|
+
),
|
|
9156
|
+
hasMoreLocal && /* @__PURE__ */ jsx(Box, { className: "flex justify-center py-3", children: /* @__PURE__ */ jsxs(
|
|
9157
|
+
Button,
|
|
9158
|
+
{
|
|
9159
|
+
variant: "ghost",
|
|
9160
|
+
size: "sm",
|
|
9161
|
+
onClick: () => setVisibleCount((prev) => prev + (pageSize || 5)),
|
|
9162
|
+
children: [
|
|
9163
|
+
/* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: "xs", className: "mr-1" }),
|
|
9164
|
+
t("common.showMore") || "Show More",
|
|
9165
|
+
" (",
|
|
9166
|
+
allData.length - visibleCount,
|
|
9167
|
+
" remaining)"
|
|
9168
|
+
]
|
|
9169
|
+
}
|
|
9170
|
+
) }),
|
|
9171
|
+
infiniteScroll && loadMoreEvent && /* @__PURE__ */ jsx(
|
|
9172
|
+
InfiniteScrollSentinel,
|
|
9173
|
+
{
|
|
9174
|
+
loadMoreEvent,
|
|
9175
|
+
isLoading,
|
|
9176
|
+
hasMore
|
|
9177
|
+
}
|
|
9178
|
+
)
|
|
9179
|
+
] });
|
|
9180
|
+
};
|
|
9181
|
+
DataGrid.displayName = "DataGrid";
|
|
9182
|
+
function fieldLabel2(key) {
|
|
9183
|
+
return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
9184
|
+
}
|
|
9185
|
+
function statusVariant2(value) {
|
|
9186
|
+
const v = value.toLowerCase();
|
|
9187
|
+
if (["active", "completed", "done", "approved", "published", "resolved", "open", "online"].includes(v)) return "success";
|
|
9188
|
+
if (["pending", "in_progress", "in-progress", "review", "draft", "processing", "warning"].includes(v)) return "warning";
|
|
9189
|
+
if (["inactive", "deleted", "rejected", "failed", "error", "blocked", "closed", "offline"].includes(v)) return "error";
|
|
9190
|
+
if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
|
|
9191
|
+
return "default";
|
|
9192
|
+
}
|
|
9193
|
+
function formatDate2(value) {
|
|
9194
|
+
if (!value) return "";
|
|
9195
|
+
const d = new Date(String(value));
|
|
9196
|
+
if (isNaN(d.getTime())) return String(value);
|
|
9197
|
+
return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
|
|
9198
|
+
}
|
|
9199
|
+
function formatValue2(value, format) {
|
|
9200
|
+
if (value === void 0 || value === null) return "";
|
|
9201
|
+
switch (format) {
|
|
9202
|
+
case "date":
|
|
9203
|
+
return formatDate2(value);
|
|
9204
|
+
case "currency":
|
|
9205
|
+
return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
|
|
9206
|
+
case "number":
|
|
9207
|
+
return typeof value === "number" ? value.toLocaleString() : String(value);
|
|
9208
|
+
case "percent":
|
|
9209
|
+
return typeof value === "number" ? `${Math.round(value)}%` : String(value);
|
|
9210
|
+
case "boolean":
|
|
9211
|
+
return value ? "Yes" : "No";
|
|
9212
|
+
default:
|
|
9213
|
+
return String(value);
|
|
9214
|
+
}
|
|
9215
|
+
}
|
|
9216
|
+
function groupData(items, field) {
|
|
9217
|
+
const groups = /* @__PURE__ */ new Map();
|
|
9218
|
+
for (const item of items) {
|
|
9219
|
+
const key = String(getNestedValue(item, field) ?? "");
|
|
9220
|
+
const group = groups.get(key);
|
|
9221
|
+
if (group) group.push(item);
|
|
9222
|
+
else groups.set(key, [item]);
|
|
9223
|
+
}
|
|
9224
|
+
return Array.from(groups.entries()).map(([label, groupItems]) => ({ label, items: groupItems }));
|
|
9225
|
+
}
|
|
9226
|
+
var DataList = ({
|
|
9227
|
+
entity,
|
|
9228
|
+
fields: fieldsProp,
|
|
9229
|
+
columns: columnsProp,
|
|
9230
|
+
itemActions,
|
|
9231
|
+
gap = "none",
|
|
9232
|
+
variant = "default",
|
|
9233
|
+
groupBy,
|
|
9234
|
+
senderField,
|
|
9235
|
+
currentUser,
|
|
9236
|
+
className,
|
|
9237
|
+
isLoading = false,
|
|
9238
|
+
error = null,
|
|
9239
|
+
// Gesture props: reorderable, swipeLeftEvent, swipeRightEvent, longPressEvent
|
|
9240
|
+
// are consumed by the compiler to wrap items in SwipeableRow/SortableList.
|
|
9241
|
+
// DataList destructures them here to prevent DOM passthrough.
|
|
9242
|
+
reorderable: _reorderable,
|
|
9243
|
+
reorderEvent: _reorderEvent,
|
|
9244
|
+
swipeLeftEvent: _swipeLeftEvent,
|
|
9245
|
+
swipeLeftActions: _swipeLeftActions,
|
|
9246
|
+
swipeRightEvent: _swipeRightEvent,
|
|
9247
|
+
swipeRightActions: _swipeRightActions,
|
|
9248
|
+
longPressEvent: _longPressEvent,
|
|
9249
|
+
infiniteScroll,
|
|
9250
|
+
loadMoreEvent,
|
|
9251
|
+
hasMore,
|
|
9252
|
+
children,
|
|
9253
|
+
pageSize = 5
|
|
9254
|
+
}) => {
|
|
9255
|
+
const eventBus = useEventBus();
|
|
9256
|
+
const { t } = useTranslate();
|
|
9257
|
+
const [visibleCount, setVisibleCount] = React69__default.useState(pageSize || Infinity);
|
|
9258
|
+
const fields = fieldsProp ?? columnsProp ?? [];
|
|
9259
|
+
const allData = Array.isArray(entity) ? entity : entity ? [entity] : [];
|
|
9260
|
+
const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
|
|
9261
|
+
const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
|
|
9262
|
+
const titleField = fields.find((f) => f.variant === "h3" || f.variant === "h4") ?? fields[0];
|
|
9263
|
+
const badgeFields = fields.filter((f) => f.variant === "badge" && f !== titleField);
|
|
9264
|
+
const progressFields = fields.filter((f) => f.variant === "progress");
|
|
9265
|
+
const bodyFields = fields.filter(
|
|
9266
|
+
(f) => f !== titleField && !badgeFields.includes(f) && !progressFields.includes(f)
|
|
9267
|
+
);
|
|
9268
|
+
const handleActionClick = (action, itemData) => (e) => {
|
|
9269
|
+
e.stopPropagation();
|
|
9270
|
+
eventBus.emit(`UI:${action.event}`, { id: itemData.id, row: itemData });
|
|
9271
|
+
};
|
|
9272
|
+
if (isLoading) {
|
|
9273
|
+
return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
|
|
9274
|
+
}
|
|
9275
|
+
if (error) {
|
|
9276
|
+
return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
|
|
9277
|
+
}
|
|
9278
|
+
if (data.length === 0) {
|
|
9279
|
+
return /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
|
|
9280
|
+
}
|
|
9281
|
+
const gapClass = {
|
|
9282
|
+
none: "",
|
|
9283
|
+
sm: "gap-1",
|
|
9284
|
+
md: "gap-2",
|
|
9285
|
+
lg: "gap-4"
|
|
9286
|
+
}[gap];
|
|
9287
|
+
const isCard = variant === "card";
|
|
9288
|
+
const isCompact = variant === "compact";
|
|
9289
|
+
const isMessage = variant === "message";
|
|
9290
|
+
if (isMessage) {
|
|
9291
|
+
const items2 = data.map((item) => item);
|
|
9292
|
+
const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
|
|
9293
|
+
const contentField = titleField?.name ?? fields[0]?.name ?? "";
|
|
9294
|
+
return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React69__default.Fragment, { children: [
|
|
9295
|
+
group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
|
|
9296
|
+
group.items.map((itemData, index) => {
|
|
9297
|
+
const id = itemData.id || `${gi}-${index}`;
|
|
9298
|
+
const sender = senderField ? String(getNestedValue(itemData, senderField) ?? "") : "";
|
|
9299
|
+
const isSent = Boolean(currentUser && sender === currentUser);
|
|
9300
|
+
const content = getNestedValue(itemData, contentField);
|
|
9301
|
+
const timestampField = fields.find((f) => f.format === "date");
|
|
9302
|
+
const timestamp = timestampField ? getNestedValue(itemData, timestampField.name) : null;
|
|
9303
|
+
return /* @__PURE__ */ jsx(
|
|
9304
|
+
Box,
|
|
9305
|
+
{
|
|
9306
|
+
className: cn(
|
|
9307
|
+
"flex px-4",
|
|
9308
|
+
isSent ? "justify-end" : "justify-start"
|
|
9309
|
+
),
|
|
9310
|
+
children: /* @__PURE__ */ jsxs(
|
|
9311
|
+
Box,
|
|
9312
|
+
{
|
|
9313
|
+
className: cn(
|
|
9314
|
+
"max-w-[75%] px-4 py-2",
|
|
9315
|
+
isSent ? "bg-[var(--color-primary)] text-[var(--color-primary-foreground)] rounded-2xl rounded-br-sm" : "bg-[var(--color-muted)] text-[var(--color-foreground)] rounded-2xl rounded-bl-sm"
|
|
9316
|
+
),
|
|
9317
|
+
children: [
|
|
9318
|
+
!isSent && senderField && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "font-semibold mb-0.5", children: sender }),
|
|
9319
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", children: content !== void 0 && content !== null ? String(content) : "" }),
|
|
9320
|
+
timestamp != null ? /* @__PURE__ */ jsx(
|
|
9321
|
+
Typography,
|
|
9322
|
+
{
|
|
9323
|
+
variant: "caption",
|
|
9324
|
+
className: cn(
|
|
9325
|
+
"mt-1 text-[0.65rem]",
|
|
9326
|
+
isSent ? "opacity-70" : "text-[var(--color-muted-foreground)]"
|
|
9327
|
+
),
|
|
9328
|
+
children: formatDate2(timestamp)
|
|
9329
|
+
}
|
|
9330
|
+
) : null
|
|
9331
|
+
]
|
|
9332
|
+
}
|
|
9333
|
+
)
|
|
9334
|
+
},
|
|
9335
|
+
id
|
|
9336
|
+
);
|
|
9337
|
+
})
|
|
9338
|
+
] }, gi)) });
|
|
9339
|
+
}
|
|
9340
|
+
const hasRenderProp = typeof children === "function";
|
|
9341
|
+
const items = data.map((item) => item);
|
|
9342
|
+
const groups = groupBy ? groupData(items, groupBy) : [{ label: "", items }];
|
|
9343
|
+
const renderItem = (itemData, index, isLast) => {
|
|
9344
|
+
if (hasRenderProp) {
|
|
9345
|
+
const id2 = itemData.id || String(index);
|
|
9346
|
+
return /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, children: [
|
|
9347
|
+
/* @__PURE__ */ jsxs(
|
|
9348
|
+
Box,
|
|
9349
|
+
{
|
|
9350
|
+
className: cn(
|
|
9351
|
+
"group flex items-center gap-4 transition-all duration-200",
|
|
9352
|
+
isCompact ? "px-4 py-2" : "px-6 py-4",
|
|
9353
|
+
"hover:bg-[var(--color-muted)]/80",
|
|
9354
|
+
!isCard && !isCompact && "rounded-[var(--radius-lg)] border border-transparent hover:border-[var(--color-border)]"
|
|
9355
|
+
),
|
|
9356
|
+
children: [
|
|
9357
|
+
/* @__PURE__ */ jsx(Box, { className: "flex-1 min-w-0", children: children(itemData, index) }),
|
|
9358
|
+
itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(
|
|
9359
|
+
HStack,
|
|
9360
|
+
{
|
|
9361
|
+
gap: "xs",
|
|
9362
|
+
className: cn(
|
|
9363
|
+
"flex-shrink-0 transition-opacity duration-200",
|
|
9364
|
+
"opacity-0 group-hover:opacity-100"
|
|
9365
|
+
),
|
|
9366
|
+
children: itemActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
9367
|
+
Button,
|
|
9368
|
+
{
|
|
9369
|
+
variant: action.variant ?? "ghost",
|
|
9370
|
+
size: "sm",
|
|
9371
|
+
onClick: handleActionClick(action, itemData),
|
|
9372
|
+
"data-testid": `action-${action.event}`,
|
|
9373
|
+
className: cn(
|
|
9374
|
+
action.variant === "danger" && "text-[var(--color-error)] hover:bg-[var(--color-error)]/10"
|
|
9375
|
+
),
|
|
9376
|
+
children: [
|
|
9377
|
+
action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
|
|
9378
|
+
action.label
|
|
9379
|
+
]
|
|
9380
|
+
},
|
|
9381
|
+
idx
|
|
9382
|
+
))
|
|
9383
|
+
}
|
|
9384
|
+
)
|
|
9385
|
+
]
|
|
9386
|
+
}
|
|
9387
|
+
),
|
|
9388
|
+
isCard && !isLast && /* @__PURE__ */ jsx(Box, { className: "mx-6 border-b border-[var(--color-border)]/40" })
|
|
9389
|
+
] }, id2);
|
|
9390
|
+
}
|
|
9391
|
+
const id = itemData.id || String(index);
|
|
9392
|
+
const titleValue = getNestedValue(itemData, titleField?.name ?? "");
|
|
9393
|
+
return /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, children: [
|
|
9394
|
+
/* @__PURE__ */ jsxs(
|
|
9395
|
+
Box,
|
|
9396
|
+
{
|
|
9397
|
+
className: cn(
|
|
9398
|
+
"group flex items-center gap-4 transition-all duration-200",
|
|
9399
|
+
isCompact ? "px-4 py-2" : "px-6 py-4",
|
|
9400
|
+
"hover:bg-[var(--color-muted)]/80",
|
|
9401
|
+
!isCard && !isCompact && "rounded-[var(--radius-lg)] border border-transparent hover:border-[var(--color-border)]"
|
|
9402
|
+
),
|
|
9403
|
+
children: [
|
|
9404
|
+
/* @__PURE__ */ jsxs(Box, { className: "flex-1 min-w-0", children: [
|
|
9405
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
9406
|
+
titleField?.icon && /* @__PURE__ */ jsx(
|
|
9407
|
+
Icon,
|
|
9408
|
+
{
|
|
9409
|
+
name: titleField.icon,
|
|
9410
|
+
size: isCompact ? "xs" : "sm",
|
|
9411
|
+
className: "text-[var(--color-primary)] flex-shrink-0"
|
|
9412
|
+
}
|
|
9413
|
+
),
|
|
9414
|
+
titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsx(
|
|
9415
|
+
Typography,
|
|
9416
|
+
{
|
|
9417
|
+
variant: titleField?.variant === "h3" ? "h3" : "h4",
|
|
9418
|
+
className: cn("font-semibold truncate flex-1", isCompact && "text-sm"),
|
|
9419
|
+
children: String(titleValue)
|
|
9420
|
+
}
|
|
9421
|
+
),
|
|
9422
|
+
badgeFields.map((field) => {
|
|
9423
|
+
const val = getNestedValue(itemData, field.name);
|
|
9424
|
+
if (val === void 0 || val === null) return null;
|
|
9425
|
+
return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center flex-shrink-0", children: [
|
|
9426
|
+
field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
|
|
9427
|
+
/* @__PURE__ */ jsx(Badge, { variant: statusVariant2(String(val)), children: String(val) })
|
|
9428
|
+
] }, field.name);
|
|
9429
|
+
})
|
|
9430
|
+
] }),
|
|
9431
|
+
bodyFields.length > 0 && !isCompact && /* @__PURE__ */ jsx(HStack, { gap: "md", className: "mt-1.5 flex-wrap", children: bodyFields.map((field) => {
|
|
9432
|
+
const value = getNestedValue(itemData, field.name);
|
|
9433
|
+
if (value === void 0 || value === null || value === "") return null;
|
|
9434
|
+
return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
9435
|
+
field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
|
|
9436
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "secondary", children: [
|
|
9437
|
+
field.label ?? fieldLabel2(field.name),
|
|
9438
|
+
":"
|
|
9439
|
+
] }),
|
|
9440
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", children: formatValue2(value, field.format) })
|
|
9441
|
+
] }, field.name);
|
|
9442
|
+
}) }),
|
|
9443
|
+
progressFields.map((field) => {
|
|
9444
|
+
const value = getNestedValue(itemData, field.name);
|
|
9445
|
+
if (typeof value !== "number") return null;
|
|
9446
|
+
return /* @__PURE__ */ jsxs(Box, { className: "mt-2 max-w-xs", children: [
|
|
9447
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center mb-1", children: [
|
|
9448
|
+
field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
|
|
9449
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
|
|
9450
|
+
] }),
|
|
9451
|
+
/* @__PURE__ */ jsx(ProgressBar, { value, max: 100 })
|
|
9452
|
+
] }, field.name);
|
|
9453
|
+
})
|
|
9454
|
+
] }),
|
|
9455
|
+
itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(
|
|
9456
|
+
HStack,
|
|
9457
|
+
{
|
|
9458
|
+
gap: "xs",
|
|
9459
|
+
className: cn(
|
|
9460
|
+
"flex-shrink-0 transition-opacity duration-200",
|
|
9461
|
+
"opacity-0 group-hover:opacity-100"
|
|
9462
|
+
),
|
|
9463
|
+
children: itemActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
9464
|
+
Button,
|
|
9465
|
+
{
|
|
9466
|
+
variant: action.variant ?? "ghost",
|
|
9467
|
+
size: "sm",
|
|
9468
|
+
onClick: handleActionClick(action, itemData),
|
|
9469
|
+
"data-testid": `action-${action.event}`,
|
|
9470
|
+
className: cn(
|
|
9471
|
+
action.variant === "danger" && "text-[var(--color-error)] hover:bg-[var(--color-error)]/10"
|
|
9472
|
+
),
|
|
9473
|
+
children: [
|
|
9474
|
+
action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
|
|
9475
|
+
action.label
|
|
9476
|
+
]
|
|
9477
|
+
},
|
|
9478
|
+
idx
|
|
9479
|
+
))
|
|
9480
|
+
}
|
|
9481
|
+
)
|
|
9482
|
+
]
|
|
9483
|
+
}
|
|
9484
|
+
),
|
|
9485
|
+
isCard && !isLast && /* @__PURE__ */ jsx(Box, { className: "mx-6 border-b border-[var(--color-border)]/40" })
|
|
9486
|
+
] }, id);
|
|
9487
|
+
};
|
|
9488
|
+
return /* @__PURE__ */ jsxs(
|
|
9489
|
+
Box,
|
|
9490
|
+
{
|
|
9491
|
+
className: cn(
|
|
9492
|
+
isCard && "bg-[var(--color-card)] rounded-[var(--radius-xl)] border border-[var(--color-border)] shadow-[var(--shadow-lg)] overflow-hidden",
|
|
9493
|
+
!isCard && gapClass,
|
|
9494
|
+
className
|
|
9495
|
+
),
|
|
9496
|
+
children: [
|
|
9497
|
+
groups.map((group, gi) => /* @__PURE__ */ jsxs(React69__default.Fragment, { children: [
|
|
9498
|
+
group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
|
|
9499
|
+
group.items.map(
|
|
9500
|
+
(itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
|
|
9501
|
+
)
|
|
9502
|
+
] }, gi)),
|
|
9503
|
+
hasMoreLocal && /* @__PURE__ */ jsx(Box, { className: "flex justify-center py-3", children: /* @__PURE__ */ jsxs(
|
|
9504
|
+
Button,
|
|
9505
|
+
{
|
|
9506
|
+
variant: "ghost",
|
|
9507
|
+
size: "sm",
|
|
9508
|
+
onClick: () => setVisibleCount((prev) => prev + (pageSize || 5)),
|
|
9509
|
+
children: [
|
|
9510
|
+
/* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: "xs", className: "mr-1" }),
|
|
9511
|
+
t("common.showMore") || "Show More",
|
|
9512
|
+
" (",
|
|
9513
|
+
allData.length - visibleCount,
|
|
9514
|
+
" remaining)"
|
|
9515
|
+
]
|
|
9516
|
+
}
|
|
9517
|
+
) }),
|
|
9518
|
+
infiniteScroll && loadMoreEvent && /* @__PURE__ */ jsx(
|
|
9519
|
+
InfiniteScrollSentinel,
|
|
9520
|
+
{
|
|
9521
|
+
loadMoreEvent,
|
|
9522
|
+
isLoading,
|
|
9523
|
+
hasMore
|
|
9524
|
+
}
|
|
9525
|
+
)
|
|
9526
|
+
]
|
|
9527
|
+
}
|
|
9528
|
+
);
|
|
9529
|
+
};
|
|
9530
|
+
DataList.displayName = "DataList";
|
|
9531
|
+
function formatValue3(value, format, max) {
|
|
9532
|
+
if (value == null) return "0";
|
|
9533
|
+
const v = typeof value === "number" ? value : value;
|
|
9534
|
+
let formatted;
|
|
9535
|
+
switch (format) {
|
|
9536
|
+
case "currency":
|
|
9537
|
+
formatted = typeof v === "number" ? `$${v.toFixed(2)}` : String(v);
|
|
9538
|
+
break;
|
|
9539
|
+
case "percent":
|
|
9540
|
+
formatted = typeof v === "number" ? `${Math.round(v)}%` : String(v);
|
|
9541
|
+
break;
|
|
9542
|
+
case "number":
|
|
9543
|
+
formatted = typeof v === "number" ? v.toLocaleString() : String(v);
|
|
9544
|
+
break;
|
|
9545
|
+
default:
|
|
9546
|
+
formatted = String(v);
|
|
9547
|
+
}
|
|
9548
|
+
if (max != null) return `${formatted} / ${max}`;
|
|
9549
|
+
return formatted;
|
|
9550
|
+
}
|
|
9551
|
+
var variantColor = {
|
|
9552
|
+
default: "text-[var(--color-foreground)]",
|
|
9553
|
+
primary: "text-[var(--color-primary)]",
|
|
9554
|
+
success: "text-[var(--color-success)]",
|
|
9555
|
+
warning: "text-[var(--color-warning)]",
|
|
9556
|
+
error: "text-[var(--color-error)]",
|
|
9557
|
+
info: "text-[var(--color-info)]"
|
|
9558
|
+
};
|
|
9559
|
+
var StatDisplay = ({
|
|
9560
|
+
label,
|
|
9561
|
+
value,
|
|
9562
|
+
max,
|
|
9563
|
+
icon: iconProp,
|
|
9564
|
+
iconBg = "bg-[var(--color-muted)]",
|
|
9565
|
+
iconColor = "text-[var(--color-foreground)]",
|
|
9566
|
+
format,
|
|
9567
|
+
size = "md",
|
|
9568
|
+
variant = "default",
|
|
9569
|
+
compact = false,
|
|
9570
|
+
className,
|
|
9571
|
+
isLoading = false,
|
|
9572
|
+
error = null
|
|
9573
|
+
}) => {
|
|
9574
|
+
const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
|
|
9575
|
+
const iconSizes2 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
|
|
9576
|
+
const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
|
|
9577
|
+
const padSizes = { sm: "p-3", md: "p-4", lg: "p-6" };
|
|
9578
|
+
const displayValue = formatValue3(value, format, max);
|
|
9579
|
+
if (error) {
|
|
9580
|
+
return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "error", children: error.message }) });
|
|
9581
|
+
}
|
|
9582
|
+
if (isLoading) {
|
|
9583
|
+
return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: "animate-pulse", children: [
|
|
9584
|
+
/* @__PURE__ */ jsx(Box, { className: "h-3 bg-[var(--color-muted)] rounded w-16" }),
|
|
9585
|
+
/* @__PURE__ */ jsx(Box, { className: "h-6 bg-[var(--color-muted)] rounded w-12" })
|
|
9586
|
+
] }) });
|
|
9587
|
+
}
|
|
9588
|
+
if (compact) {
|
|
9589
|
+
return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: cn("items-center", className), children: [
|
|
9590
|
+
ResolvedIcon && /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes2[size], iconColor) }),
|
|
9591
|
+
typeof iconProp !== "string" && iconProp,
|
|
9592
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: label }),
|
|
9593
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue })
|
|
9594
|
+
] });
|
|
9595
|
+
}
|
|
9596
|
+
return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxs(HStack, { align: "start", justify: "between", children: [
|
|
9597
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1", children: [
|
|
9598
|
+
/* @__PURE__ */ jsx(Typography, { variant: "overline", color: "secondary", children: label }),
|
|
9599
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue })
|
|
9600
|
+
] }),
|
|
9601
|
+
(ResolvedIcon || typeof iconProp !== "string" && iconProp) && /* @__PURE__ */ jsx(Box, { className: cn("p-3 rounded-[var(--radius-md)]", iconBg), children: ResolvedIcon ? /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes2[size], iconColor) }) : iconProp })
|
|
9602
|
+
] }) });
|
|
9603
|
+
};
|
|
9604
|
+
StatDisplay.displayName = "StatDisplay";
|
|
9605
|
+
var DEFAULT_THRESHOLDS = [
|
|
9606
|
+
{ value: 30, color: "var(--color-error)" },
|
|
9607
|
+
{ value: 70, color: "var(--color-warning)" },
|
|
9608
|
+
{ value: 100, color: "var(--color-success)" }
|
|
9609
|
+
];
|
|
9610
|
+
function getColorForValue(value, max, thresholds) {
|
|
9611
|
+
const percentage = value / max * 100;
|
|
9612
|
+
for (const threshold of thresholds) {
|
|
9613
|
+
if (percentage <= threshold.value) {
|
|
9614
|
+
return threshold.color;
|
|
9615
|
+
}
|
|
9616
|
+
}
|
|
9617
|
+
return thresholds[thresholds.length - 1]?.color ?? "var(--color-primary)";
|
|
9618
|
+
}
|
|
9619
|
+
var radialSizes = {
|
|
9620
|
+
sm: { size: 80, stroke: 6, fontSize: "12px" },
|
|
9621
|
+
md: { size: 120, stroke: 8, fontSize: "16px" },
|
|
9622
|
+
lg: { size: 160, stroke: 10, fontSize: "20px" }
|
|
9623
|
+
};
|
|
9624
|
+
var Meter = ({
|
|
9625
|
+
value,
|
|
9626
|
+
min = 0,
|
|
9627
|
+
max = 100,
|
|
9628
|
+
label,
|
|
9629
|
+
unit,
|
|
9630
|
+
variant = "linear",
|
|
9631
|
+
thresholds = DEFAULT_THRESHOLDS,
|
|
9632
|
+
segments = 5,
|
|
9633
|
+
showValue = true,
|
|
9634
|
+
size = "md",
|
|
9635
|
+
actions,
|
|
9636
|
+
isLoading = false,
|
|
9637
|
+
error,
|
|
9638
|
+
className
|
|
9639
|
+
}) => {
|
|
9640
|
+
const eventBus = useEventBus();
|
|
9641
|
+
const handleAction = useCallback(
|
|
9642
|
+
(action) => {
|
|
9643
|
+
if (action.event) {
|
|
9644
|
+
eventBus.emit(`UI:${action.event}`, { value });
|
|
9645
|
+
}
|
|
9646
|
+
},
|
|
9647
|
+
[eventBus, value]
|
|
9648
|
+
);
|
|
9649
|
+
const percentage = useMemo(() => {
|
|
9650
|
+
const range = max - min;
|
|
9651
|
+
if (range <= 0) return 0;
|
|
9652
|
+
return Math.min(Math.max((value - min) / range * 100, 0), 100);
|
|
9653
|
+
}, [value, min, max]);
|
|
9654
|
+
const activeColor = useMemo(
|
|
9655
|
+
() => getColorForValue(value, max, thresholds),
|
|
9656
|
+
[value, max, thresholds]
|
|
9657
|
+
);
|
|
9658
|
+
const displayValue = useMemo(() => {
|
|
9659
|
+
const formatted = Number.isInteger(value) ? value : value.toFixed(1);
|
|
9660
|
+
return unit ? `${formatted}${unit}` : `${formatted}`;
|
|
9661
|
+
}, [value, unit]);
|
|
9662
|
+
if (isLoading) {
|
|
9663
|
+
return /* @__PURE__ */ jsx(LoadingState, { message: "Loading meter...", className });
|
|
9664
|
+
}
|
|
9665
|
+
if (error) {
|
|
9666
|
+
return /* @__PURE__ */ jsx(
|
|
9667
|
+
ErrorState,
|
|
9668
|
+
{
|
|
9669
|
+
title: "Meter error",
|
|
9670
|
+
message: error.message,
|
|
9671
|
+
className
|
|
9672
|
+
}
|
|
9673
|
+
);
|
|
9674
|
+
}
|
|
9675
|
+
if (variant === "radial") {
|
|
9676
|
+
const dims = radialSizes[size];
|
|
9677
|
+
const radius = (dims.size - dims.stroke * 2) / 2;
|
|
9678
|
+
const circumference = 2 * Math.PI * radius;
|
|
9679
|
+
const offset = circumference - percentage / 100 * circumference;
|
|
9680
|
+
const center = dims.size / 2;
|
|
9681
|
+
return /* @__PURE__ */ jsx(Card, { className: cn("p-4", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
9682
|
+
label && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", weight: "medium", children: label }),
|
|
9683
|
+
/* @__PURE__ */ jsxs(Box, { className: "relative inline-flex items-center justify-center", children: [
|
|
9684
|
+
/* @__PURE__ */ jsxs(
|
|
9685
|
+
"svg",
|
|
9686
|
+
{
|
|
9687
|
+
width: dims.size,
|
|
9688
|
+
height: dims.size,
|
|
9689
|
+
viewBox: `0 0 ${dims.size} ${dims.size}`,
|
|
9690
|
+
className: "transform -rotate-90",
|
|
9691
|
+
children: [
|
|
9692
|
+
/* @__PURE__ */ jsx(
|
|
9693
|
+
"circle",
|
|
9694
|
+
{
|
|
9695
|
+
cx: center,
|
|
9696
|
+
cy: center,
|
|
9697
|
+
r: radius,
|
|
9698
|
+
fill: "none",
|
|
9699
|
+
stroke: "var(--color-muted)",
|
|
9700
|
+
strokeWidth: dims.stroke
|
|
9701
|
+
}
|
|
9702
|
+
),
|
|
9703
|
+
/* @__PURE__ */ jsx(
|
|
9704
|
+
"circle",
|
|
9705
|
+
{
|
|
9706
|
+
cx: center,
|
|
9707
|
+
cy: center,
|
|
9708
|
+
r: radius,
|
|
9709
|
+
fill: "none",
|
|
9710
|
+
stroke: activeColor,
|
|
9711
|
+
strokeWidth: dims.stroke,
|
|
9712
|
+
strokeDasharray: circumference,
|
|
9713
|
+
strokeDashoffset: offset,
|
|
9714
|
+
strokeLinecap: "round",
|
|
9715
|
+
className: "transition-all duration-500 ease-out"
|
|
9716
|
+
}
|
|
9717
|
+
)
|
|
9718
|
+
]
|
|
9719
|
+
}
|
|
9720
|
+
),
|
|
9721
|
+
showValue && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx(
|
|
9722
|
+
Typography,
|
|
9723
|
+
{
|
|
9724
|
+
variant: "h5",
|
|
9725
|
+
weight: "bold",
|
|
9726
|
+
className: "tabular-nums",
|
|
9727
|
+
style: { fontSize: dims.fontSize },
|
|
9728
|
+
children: displayValue
|
|
9729
|
+
}
|
|
9730
|
+
) })
|
|
9731
|
+
] }),
|
|
9732
|
+
actions && actions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", children: actions.map((action, idx) => /* @__PURE__ */ jsx(
|
|
9733
|
+
Badge,
|
|
9734
|
+
{
|
|
9735
|
+
variant: "default",
|
|
9736
|
+
className: "cursor-pointer hover:opacity-80 transition-opacity",
|
|
9737
|
+
onClick: () => handleAction(action),
|
|
9738
|
+
children: action.label
|
|
9739
|
+
},
|
|
9740
|
+
idx
|
|
9741
|
+
)) })
|
|
9742
|
+
] }) });
|
|
9743
|
+
}
|
|
9744
|
+
if (variant === "segmented") {
|
|
9745
|
+
const activeSegments = Math.round(percentage / 100 * segments);
|
|
9746
|
+
return /* @__PURE__ */ jsx(Card, { className: cn("p-4", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
9747
|
+
(label || showValue) && /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
|
|
9748
|
+
label && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", weight: "medium", children: label }),
|
|
9749
|
+
showValue && /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "tabular-nums", children: displayValue })
|
|
9750
|
+
] }),
|
|
9751
|
+
/* @__PURE__ */ jsx(HStack, { gap: "xs", className: "w-full", children: Array.from({ length: segments }).map((_, idx) => {
|
|
9752
|
+
const isActive = idx < activeSegments;
|
|
9753
|
+
const segColor = isActive ? getColorForValue((idx + 1) / segments * max, max, thresholds) : void 0;
|
|
9754
|
+
return /* @__PURE__ */ jsx(
|
|
9755
|
+
Box,
|
|
9756
|
+
{
|
|
9757
|
+
className: cn(
|
|
9758
|
+
"h-2 flex-1 rounded-[var(--radius-sm)] transition-all duration-300",
|
|
9759
|
+
!isActive && "bg-[var(--color-muted)]"
|
|
9760
|
+
),
|
|
9761
|
+
style: isActive ? { backgroundColor: segColor } : void 0
|
|
9762
|
+
},
|
|
9763
|
+
idx
|
|
9764
|
+
);
|
|
9765
|
+
}) }),
|
|
9766
|
+
thresholds.some((t) => t.label) && /* @__PURE__ */ jsx(HStack, { justify: "between", className: "w-full", children: thresholds.map((t, idx) => /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: t.label || "" }, idx)) })
|
|
9767
|
+
] }) });
|
|
9768
|
+
}
|
|
9769
|
+
return /* @__PURE__ */ jsx(Card, { className: cn("p-4", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
9770
|
+
(label || showValue) && /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
|
|
9771
|
+
label && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", weight: "medium", children: label }),
|
|
9772
|
+
showValue && /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "tabular-nums", children: displayValue })
|
|
9773
|
+
] }),
|
|
9774
|
+
/* @__PURE__ */ jsx(Box, { className: "w-full h-3 bg-[var(--color-muted)] rounded-[var(--radius-full)] overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
9775
|
+
Box,
|
|
9776
|
+
{
|
|
9777
|
+
className: "h-full rounded-[var(--radius-full)] transition-all duration-500 ease-out",
|
|
9778
|
+
style: {
|
|
9779
|
+
width: `${percentage}%`,
|
|
9780
|
+
backgroundColor: activeColor
|
|
9781
|
+
}
|
|
9782
|
+
}
|
|
9783
|
+
) }),
|
|
9784
|
+
/* @__PURE__ */ jsxs(HStack, { justify: "between", className: "w-full", children: [
|
|
9785
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "secondary", children: [
|
|
9786
|
+
min,
|
|
9787
|
+
unit ? ` ${unit}` : ""
|
|
9788
|
+
] }),
|
|
9789
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "secondary", children: [
|
|
9790
|
+
max,
|
|
9791
|
+
unit ? ` ${unit}` : ""
|
|
9792
|
+
] })
|
|
9793
|
+
] }),
|
|
9794
|
+
actions && actions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", children: actions.map((action, idx) => /* @__PURE__ */ jsx(
|
|
9795
|
+
Badge,
|
|
9796
|
+
{
|
|
9797
|
+
variant: "default",
|
|
9798
|
+
className: "cursor-pointer hover:opacity-80 transition-opacity",
|
|
9799
|
+
onClick: () => handleAction(action),
|
|
9800
|
+
children: action.label
|
|
9801
|
+
},
|
|
9802
|
+
idx
|
|
9803
|
+
)) })
|
|
9804
|
+
] }) });
|
|
9805
|
+
};
|
|
9806
|
+
Meter.displayName = "Meter";
|
|
9807
|
+
function useSafeEventBus8() {
|
|
9808
|
+
try {
|
|
9809
|
+
return useEventBus();
|
|
9810
|
+
} catch {
|
|
9811
|
+
return { emit: () => {
|
|
9812
|
+
}, on: () => () => {
|
|
9813
|
+
}, once: () => {
|
|
9814
|
+
} };
|
|
9815
|
+
}
|
|
9816
|
+
}
|
|
9817
|
+
var SwipeableRow = ({
|
|
9818
|
+
leftActions = [],
|
|
9819
|
+
rightActions = [],
|
|
9820
|
+
threshold = 80,
|
|
9821
|
+
children,
|
|
9822
|
+
itemData,
|
|
9823
|
+
className
|
|
9824
|
+
}) => {
|
|
9825
|
+
const eventBus = useSafeEventBus8();
|
|
9826
|
+
const [revealState, setRevealState] = useState("closed");
|
|
9827
|
+
const [offsetX, setOffsetX] = useState(0);
|
|
9828
|
+
const [isSwiping, setIsSwiping] = useState(false);
|
|
9829
|
+
const startXRef = useRef(0);
|
|
9830
|
+
const startYRef = useRef(0);
|
|
9831
|
+
const trackingRef = useRef(false);
|
|
9832
|
+
const lockedAxisRef = useRef(null);
|
|
9833
|
+
const actionsWidth = threshold;
|
|
9834
|
+
const handleActionClick = useCallback(
|
|
9835
|
+
(action) => {
|
|
9836
|
+
eventBus.emit(`UI:${action.event}`, {
|
|
9837
|
+
...action.eventPayload,
|
|
9838
|
+
row: itemData
|
|
9839
|
+
});
|
|
9840
|
+
setRevealState("closed");
|
|
9841
|
+
setOffsetX(0);
|
|
9842
|
+
},
|
|
9843
|
+
[eventBus, itemData]
|
|
9844
|
+
);
|
|
9845
|
+
const handlePointerDown = useCallback(
|
|
9846
|
+
(e) => {
|
|
9847
|
+
if (e.button !== 0) return;
|
|
9848
|
+
startXRef.current = e.clientX;
|
|
9849
|
+
startYRef.current = e.clientY;
|
|
9850
|
+
trackingRef.current = true;
|
|
9851
|
+
lockedAxisRef.current = null;
|
|
9852
|
+
setIsSwiping(false);
|
|
9853
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
9854
|
+
},
|
|
9855
|
+
[]
|
|
9856
|
+
);
|
|
9857
|
+
const handlePointerMove = useCallback(
|
|
9858
|
+
(e) => {
|
|
9859
|
+
if (!trackingRef.current) return;
|
|
9860
|
+
const dx = e.clientX - startXRef.current;
|
|
9861
|
+
const dy = e.clientY - startYRef.current;
|
|
9862
|
+
if (lockedAxisRef.current === null && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {
|
|
9863
|
+
lockedAxisRef.current = Math.abs(dx) > Math.abs(dy) ? "horizontal" : "vertical";
|
|
9864
|
+
}
|
|
9865
|
+
if (lockedAxisRef.current !== "horizontal") return;
|
|
9866
|
+
setIsSwiping(true);
|
|
9867
|
+
let newOffset = dx;
|
|
9868
|
+
if (revealState === "left") {
|
|
9869
|
+
newOffset = actionsWidth + dx;
|
|
9870
|
+
} else if (revealState === "right") {
|
|
9871
|
+
newOffset = -actionsWidth + dx;
|
|
9872
|
+
}
|
|
9873
|
+
const maxLeft = leftActions.length > 0 ? actionsWidth : 0;
|
|
9874
|
+
const maxRight = rightActions.length > 0 ? actionsWidth : 0;
|
|
9875
|
+
const clamped = Math.max(-maxRight, Math.min(maxLeft, newOffset));
|
|
9876
|
+
setOffsetX(clamped);
|
|
9877
|
+
},
|
|
9878
|
+
[revealState, actionsWidth, leftActions.length, rightActions.length]
|
|
9879
|
+
);
|
|
9880
|
+
const handlePointerUp = useCallback(
|
|
9881
|
+
() => {
|
|
9882
|
+
trackingRef.current = false;
|
|
9883
|
+
if (!isSwiping) {
|
|
9884
|
+
if (revealState !== "closed") {
|
|
9885
|
+
setRevealState("closed");
|
|
9886
|
+
setOffsetX(0);
|
|
9887
|
+
}
|
|
9888
|
+
setIsSwiping(false);
|
|
9889
|
+
return;
|
|
9890
|
+
}
|
|
9891
|
+
setIsSwiping(false);
|
|
9892
|
+
if (offsetX > threshold / 2 && leftActions.length > 0) {
|
|
9893
|
+
setRevealState("right");
|
|
9894
|
+
setOffsetX(actionsWidth);
|
|
9895
|
+
} else if (offsetX < -(threshold / 2) && rightActions.length > 0) {
|
|
9896
|
+
setRevealState("left");
|
|
9897
|
+
setOffsetX(-actionsWidth);
|
|
9898
|
+
} else {
|
|
9899
|
+
setRevealState("closed");
|
|
9900
|
+
setOffsetX(0);
|
|
9901
|
+
}
|
|
9902
|
+
},
|
|
9903
|
+
[isSwiping, offsetX, threshold, leftActions.length, rightActions.length, actionsWidth, revealState]
|
|
9904
|
+
);
|
|
9905
|
+
const handlePointerCancel = useCallback(() => {
|
|
9906
|
+
trackingRef.current = false;
|
|
9907
|
+
setIsSwiping(false);
|
|
9908
|
+
setRevealState("closed");
|
|
9909
|
+
setOffsetX(0);
|
|
9910
|
+
}, []);
|
|
9911
|
+
const renderActions = (actions, side) => {
|
|
9912
|
+
if (actions.length === 0) return null;
|
|
9913
|
+
return /* @__PURE__ */ jsx(
|
|
9914
|
+
HStack,
|
|
9915
|
+
{
|
|
9916
|
+
gap: "xs",
|
|
9917
|
+
align: "stretch",
|
|
9918
|
+
className: cn(
|
|
9919
|
+
"absolute top-0 bottom-0",
|
|
9920
|
+
side === "left" ? "left-0" : "right-0"
|
|
9921
|
+
),
|
|
9922
|
+
style: {
|
|
9923
|
+
width: `${actionsWidth}px`
|
|
9924
|
+
},
|
|
9925
|
+
children: actions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
9926
|
+
Button,
|
|
9927
|
+
{
|
|
9928
|
+
variant: action.variant ?? "secondary",
|
|
9929
|
+
size: "sm",
|
|
9930
|
+
icon: action.icon,
|
|
9931
|
+
onClick: () => handleActionClick(action),
|
|
9932
|
+
className: "flex-1 rounded-none h-full",
|
|
9933
|
+
children: [
|
|
9934
|
+
action.icon ? /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "sm" }) : null,
|
|
9935
|
+
action.label
|
|
9936
|
+
]
|
|
9937
|
+
},
|
|
9938
|
+
`${action.event}-${idx}`
|
|
9939
|
+
))
|
|
9940
|
+
}
|
|
9941
|
+
);
|
|
9942
|
+
};
|
|
9943
|
+
return /* @__PURE__ */ jsxs(
|
|
7832
9944
|
Box,
|
|
7833
9945
|
{
|
|
9946
|
+
overflow: "hidden",
|
|
9947
|
+
position: "relative",
|
|
7834
9948
|
className: cn(
|
|
7835
|
-
|
|
7836
|
-
!isCard && gapClass,
|
|
9949
|
+
"touch-pan-y",
|
|
7837
9950
|
className
|
|
7838
9951
|
),
|
|
7839
|
-
children:
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
9952
|
+
children: [
|
|
9953
|
+
renderActions(leftActions, "left"),
|
|
9954
|
+
renderActions(rightActions, "right"),
|
|
9955
|
+
/* @__PURE__ */ jsx(
|
|
9956
|
+
Box,
|
|
9957
|
+
{
|
|
9958
|
+
style: {
|
|
9959
|
+
transform: `translateX(${offsetX}px)`,
|
|
9960
|
+
transition: isSwiping ? "none" : "transform 200ms ease-out"
|
|
9961
|
+
},
|
|
9962
|
+
className: cn(
|
|
9963
|
+
"relative bg-[var(--color-surface)]",
|
|
9964
|
+
"select-none"
|
|
9965
|
+
),
|
|
9966
|
+
onPointerDown: handlePointerDown,
|
|
9967
|
+
onPointerMove: handlePointerMove,
|
|
9968
|
+
onPointerUp: handlePointerUp,
|
|
9969
|
+
onPointerCancel: handlePointerCancel,
|
|
9970
|
+
children
|
|
9971
|
+
}
|
|
9972
|
+
)
|
|
9973
|
+
]
|
|
9974
|
+
}
|
|
9975
|
+
);
|
|
9976
|
+
};
|
|
9977
|
+
SwipeableRow.displayName = "SwipeableRow";
|
|
9978
|
+
function useSafeEventBus9() {
|
|
9979
|
+
try {
|
|
9980
|
+
return useEventBus();
|
|
9981
|
+
} catch {
|
|
9982
|
+
return { emit: () => {
|
|
9983
|
+
}, on: () => () => {
|
|
9984
|
+
}, once: () => {
|
|
9985
|
+
} };
|
|
9986
|
+
}
|
|
9987
|
+
}
|
|
9988
|
+
function SortableListInner({
|
|
9989
|
+
items: initialItems,
|
|
9990
|
+
renderItem,
|
|
9991
|
+
reorderEvent,
|
|
9992
|
+
reorderPayload,
|
|
9993
|
+
dragHandlePosition = "left",
|
|
9994
|
+
className
|
|
9995
|
+
}) {
|
|
9996
|
+
const eventBus = useSafeEventBus9();
|
|
9997
|
+
const handleReorder = useCallback(
|
|
9998
|
+
(fromIndex, toIndex, item) => {
|
|
9999
|
+
eventBus.emit(`UI:${reorderEvent}`, {
|
|
10000
|
+
fromIndex,
|
|
10001
|
+
toIndex,
|
|
10002
|
+
item,
|
|
10003
|
+
...reorderPayload
|
|
10004
|
+
});
|
|
10005
|
+
},
|
|
10006
|
+
[eventBus, reorderEvent, reorderPayload]
|
|
10007
|
+
);
|
|
10008
|
+
const {
|
|
10009
|
+
items,
|
|
10010
|
+
dragIndex,
|
|
10011
|
+
dragOverIndex,
|
|
10012
|
+
isDragging,
|
|
10013
|
+
getDragHandleProps,
|
|
10014
|
+
getItemProps
|
|
10015
|
+
} = useDragReorder(initialItems, handleReorder);
|
|
10016
|
+
return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: items.map((item, index) => {
|
|
10017
|
+
const { "aria-dropeffect": ariaDropEffect, ...itemProps } = getItemProps(index);
|
|
10018
|
+
const { "aria-grabbed": ariaGrabbed, ...handleRest } = getDragHandleProps(index);
|
|
10019
|
+
const isBeingDragged = dragIndex === index;
|
|
10020
|
+
const showDropIndicator = isDragging && dragOverIndex === index && dragOverIndex !== dragIndex;
|
|
10021
|
+
const dragHandle = /* @__PURE__ */ jsx(
|
|
10022
|
+
Box,
|
|
10023
|
+
{
|
|
10024
|
+
className: cn(
|
|
10025
|
+
"flex items-center justify-center",
|
|
10026
|
+
"text-[var(--color-muted-foreground)]",
|
|
10027
|
+
"hover:text-[var(--color-foreground)]",
|
|
10028
|
+
"transition-colors duration-100",
|
|
10029
|
+
"px-1"
|
|
10030
|
+
),
|
|
10031
|
+
"aria-grabbed": ariaGrabbed,
|
|
10032
|
+
...handleRest,
|
|
10033
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "grip-vertical", size: "sm" })
|
|
10034
|
+
}
|
|
10035
|
+
);
|
|
10036
|
+
return /* @__PURE__ */ jsxs(
|
|
10037
|
+
Box,
|
|
10038
|
+
{
|
|
10039
|
+
"aria-dropeffect": ariaDropEffect,
|
|
10040
|
+
...itemProps,
|
|
10041
|
+
children: [
|
|
10042
|
+
showDropIndicator && /* @__PURE__ */ jsx(
|
|
7846
10043
|
Box,
|
|
7847
10044
|
{
|
|
10045
|
+
className: "h-0.5 bg-[var(--color-primary)] rounded-full",
|
|
10046
|
+
style: { margin: "0 8px" }
|
|
10047
|
+
}
|
|
10048
|
+
),
|
|
10049
|
+
/* @__PURE__ */ jsxs(
|
|
10050
|
+
HStack,
|
|
10051
|
+
{
|
|
10052
|
+
gap: "sm",
|
|
10053
|
+
align: "center",
|
|
7848
10054
|
className: cn(
|
|
7849
|
-
"
|
|
7850
|
-
|
|
7851
|
-
"hover:bg-[var(--color-muted)]/80",
|
|
7852
|
-
!isCard && !isCompact && "rounded-[var(--radius-lg)] border border-transparent hover:border-[var(--color-border)]"
|
|
10055
|
+
"transition-opacity duration-150",
|
|
10056
|
+
isBeingDragged && "opacity-50"
|
|
7853
10057
|
),
|
|
7854
10058
|
children: [
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
Icon,
|
|
7859
|
-
{
|
|
7860
|
-
name: titleField.icon,
|
|
7861
|
-
size: isCompact ? "xs" : "sm",
|
|
7862
|
-
className: "text-[var(--color-primary)] flex-shrink-0"
|
|
7863
|
-
}
|
|
7864
|
-
),
|
|
7865
|
-
titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsx(
|
|
7866
|
-
Typography,
|
|
7867
|
-
{
|
|
7868
|
-
variant: titleField?.variant === "h3" ? "h3" : "h4",
|
|
7869
|
-
className: cn("font-semibold truncate flex-1", isCompact && "text-sm"),
|
|
7870
|
-
children: String(titleValue)
|
|
7871
|
-
}
|
|
7872
|
-
),
|
|
7873
|
-
badgeFields.map((field) => {
|
|
7874
|
-
const val = getNestedValue(itemData, field.name);
|
|
7875
|
-
if (val === void 0 || val === null) return null;
|
|
7876
|
-
return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center flex-shrink-0", children: [
|
|
7877
|
-
field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
|
|
7878
|
-
/* @__PURE__ */ jsx(Badge, { variant: statusVariant2(String(val)), children: String(val) })
|
|
7879
|
-
] }, field.name);
|
|
7880
|
-
})
|
|
7881
|
-
] }),
|
|
7882
|
-
bodyFields.length > 0 && !isCompact && /* @__PURE__ */ jsx(HStack, { gap: "md", className: "mt-1.5 flex-wrap", children: bodyFields.map((field) => {
|
|
7883
|
-
const value = getNestedValue(itemData, field.name);
|
|
7884
|
-
if (value === void 0 || value === null || value === "") return null;
|
|
7885
|
-
return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
7886
|
-
field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
|
|
7887
|
-
/* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "secondary", children: [
|
|
7888
|
-
field.label ?? fieldLabel2(field.name),
|
|
7889
|
-
":"
|
|
7890
|
-
] }),
|
|
7891
|
-
/* @__PURE__ */ jsx(Typography, { variant: "small", children: formatValue2(value, field.format) })
|
|
7892
|
-
] }, field.name);
|
|
7893
|
-
}) }),
|
|
7894
|
-
progressFields.map((field) => {
|
|
7895
|
-
const value = getNestedValue(itemData, field.name);
|
|
7896
|
-
if (typeof value !== "number") return null;
|
|
7897
|
-
return /* @__PURE__ */ jsxs(Box, { className: "mt-2 max-w-xs", children: [
|
|
7898
|
-
/* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center mb-1", children: [
|
|
7899
|
-
field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
|
|
7900
|
-
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
|
|
7901
|
-
] }),
|
|
7902
|
-
/* @__PURE__ */ jsx(ProgressBar, { value, max: 100 })
|
|
7903
|
-
] }, field.name);
|
|
7904
|
-
})
|
|
7905
|
-
] }),
|
|
7906
|
-
itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(
|
|
7907
|
-
HStack,
|
|
7908
|
-
{
|
|
7909
|
-
gap: "xs",
|
|
7910
|
-
className: cn(
|
|
7911
|
-
"flex-shrink-0 transition-opacity duration-200",
|
|
7912
|
-
"opacity-0 group-hover:opacity-100"
|
|
7913
|
-
),
|
|
7914
|
-
children: itemActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
7915
|
-
Button,
|
|
7916
|
-
{
|
|
7917
|
-
variant: action.variant ?? "ghost",
|
|
7918
|
-
size: "sm",
|
|
7919
|
-
onClick: handleActionClick(action, itemData),
|
|
7920
|
-
"data-testid": `action-${action.event}`,
|
|
7921
|
-
className: cn(
|
|
7922
|
-
action.variant === "danger" && "text-[var(--color-error)] hover:bg-[var(--color-error)]/10"
|
|
7923
|
-
),
|
|
7924
|
-
children: [
|
|
7925
|
-
action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
|
|
7926
|
-
action.label
|
|
7927
|
-
]
|
|
7928
|
-
},
|
|
7929
|
-
idx
|
|
7930
|
-
))
|
|
7931
|
-
}
|
|
7932
|
-
)
|
|
10059
|
+
dragHandlePosition === "left" && dragHandle,
|
|
10060
|
+
/* @__PURE__ */ jsx(Box, { className: "flex-1 min-w-0", children: renderItem(item, index) }),
|
|
10061
|
+
dragHandlePosition === "right" && dragHandle
|
|
7933
10062
|
]
|
|
7934
10063
|
}
|
|
7935
|
-
)
|
|
7936
|
-
|
|
7937
|
-
|
|
7938
|
-
|
|
7939
|
-
|
|
10064
|
+
)
|
|
10065
|
+
]
|
|
10066
|
+
},
|
|
10067
|
+
index
|
|
10068
|
+
);
|
|
10069
|
+
}) });
|
|
10070
|
+
}
|
|
10071
|
+
var SortableList = SortableListInner;
|
|
10072
|
+
SortableList.displayName = "SortableList";
|
|
10073
|
+
function useSafeEventBus10() {
|
|
10074
|
+
try {
|
|
10075
|
+
return useEventBus();
|
|
10076
|
+
} catch {
|
|
10077
|
+
return { emit: () => {
|
|
10078
|
+
}, on: () => () => {
|
|
10079
|
+
}, once: () => {
|
|
10080
|
+
} };
|
|
10081
|
+
}
|
|
10082
|
+
}
|
|
10083
|
+
var Carousel = ({
|
|
10084
|
+
items,
|
|
10085
|
+
renderItem,
|
|
10086
|
+
autoPlay = false,
|
|
10087
|
+
autoPlayInterval = 5e3,
|
|
10088
|
+
showDots = true,
|
|
10089
|
+
showArrows = true,
|
|
10090
|
+
loop = false,
|
|
10091
|
+
slideChangeEvent,
|
|
10092
|
+
slideChangePayload,
|
|
10093
|
+
className
|
|
10094
|
+
}) => {
|
|
10095
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
10096
|
+
const scrollRef = useRef(null);
|
|
10097
|
+
const autoPlayRef = useRef(null);
|
|
10098
|
+
const eventBus = useSafeEventBus10();
|
|
10099
|
+
const totalSlides = items.length;
|
|
10100
|
+
const emitSlideChange = useCallback(
|
|
10101
|
+
(newIndex) => {
|
|
10102
|
+
if (slideChangeEvent) {
|
|
10103
|
+
eventBus.emit(`UI:${slideChangeEvent}`, {
|
|
10104
|
+
index: newIndex,
|
|
10105
|
+
...slideChangePayload
|
|
10106
|
+
});
|
|
10107
|
+
}
|
|
10108
|
+
},
|
|
10109
|
+
[slideChangeEvent, slideChangePayload, eventBus]
|
|
10110
|
+
);
|
|
10111
|
+
const scrollToSlide = useCallback(
|
|
10112
|
+
(index) => {
|
|
10113
|
+
const container = scrollRef.current;
|
|
10114
|
+
if (!container) return;
|
|
10115
|
+
const slideWidth = container.offsetWidth;
|
|
10116
|
+
container.scrollTo({
|
|
10117
|
+
left: slideWidth * index,
|
|
10118
|
+
behavior: "smooth"
|
|
10119
|
+
});
|
|
10120
|
+
},
|
|
10121
|
+
[]
|
|
10122
|
+
);
|
|
10123
|
+
const goToSlide = useCallback(
|
|
10124
|
+
(index) => {
|
|
10125
|
+
let targetIndex = index;
|
|
10126
|
+
if (loop) {
|
|
10127
|
+
if (targetIndex < 0) targetIndex = totalSlides - 1;
|
|
10128
|
+
if (targetIndex >= totalSlides) targetIndex = 0;
|
|
10129
|
+
} else {
|
|
10130
|
+
targetIndex = Math.max(0, Math.min(totalSlides - 1, targetIndex));
|
|
10131
|
+
}
|
|
10132
|
+
setActiveIndex(targetIndex);
|
|
10133
|
+
scrollToSlide(targetIndex);
|
|
10134
|
+
emitSlideChange(targetIndex);
|
|
10135
|
+
},
|
|
10136
|
+
[loop, totalSlides, scrollToSlide, emitSlideChange]
|
|
10137
|
+
);
|
|
10138
|
+
const goNext = useCallback(() => {
|
|
10139
|
+
goToSlide(activeIndex + 1);
|
|
10140
|
+
}, [goToSlide, activeIndex]);
|
|
10141
|
+
const goPrev = useCallback(() => {
|
|
10142
|
+
goToSlide(activeIndex - 1);
|
|
10143
|
+
}, [goToSlide, activeIndex]);
|
|
10144
|
+
const swipeHandlers = useSwipeGesture(
|
|
10145
|
+
{
|
|
10146
|
+
onSwipeLeft: goNext,
|
|
10147
|
+
onSwipeRight: goPrev
|
|
10148
|
+
},
|
|
10149
|
+
{ threshold: 40 }
|
|
7940
10150
|
);
|
|
10151
|
+
useEffect(() => {
|
|
10152
|
+
if (!autoPlay || totalSlides <= 1) return;
|
|
10153
|
+
autoPlayRef.current = setInterval(() => {
|
|
10154
|
+
setActiveIndex((prev) => {
|
|
10155
|
+
const next = loop ? (prev + 1) % totalSlides : Math.min(prev + 1, totalSlides - 1);
|
|
10156
|
+
setTimeout(() => {
|
|
10157
|
+
scrollToSlide(next);
|
|
10158
|
+
emitSlideChange(next);
|
|
10159
|
+
}, 0);
|
|
10160
|
+
return next;
|
|
10161
|
+
});
|
|
10162
|
+
}, autoPlayInterval);
|
|
10163
|
+
return () => {
|
|
10164
|
+
if (autoPlayRef.current) {
|
|
10165
|
+
clearInterval(autoPlayRef.current);
|
|
10166
|
+
autoPlayRef.current = null;
|
|
10167
|
+
}
|
|
10168
|
+
};
|
|
10169
|
+
}, [autoPlay, autoPlayInterval, loop, totalSlides, scrollToSlide, emitSlideChange]);
|
|
10170
|
+
const handleScroll = useCallback(() => {
|
|
10171
|
+
const container = scrollRef.current;
|
|
10172
|
+
if (!container) return;
|
|
10173
|
+
const slideWidth = container.offsetWidth;
|
|
10174
|
+
if (slideWidth === 0) return;
|
|
10175
|
+
const newIndex = Math.round(container.scrollLeft / slideWidth);
|
|
10176
|
+
setActiveIndex((prev) => {
|
|
10177
|
+
if (prev !== newIndex && newIndex >= 0 && newIndex < totalSlides) {
|
|
10178
|
+
return newIndex;
|
|
10179
|
+
}
|
|
10180
|
+
return prev;
|
|
10181
|
+
});
|
|
10182
|
+
}, [totalSlides]);
|
|
10183
|
+
const hasPrev = loop || activeIndex > 0;
|
|
10184
|
+
const hasNext = loop || activeIndex < totalSlides - 1;
|
|
10185
|
+
if (totalSlides === 0) return null;
|
|
10186
|
+
return /* @__PURE__ */ jsxs(Box, { position: "relative", overflow: "hidden", className: cn("w-full", className), children: [
|
|
10187
|
+
/* @__PURE__ */ jsx(
|
|
10188
|
+
Box,
|
|
10189
|
+
{
|
|
10190
|
+
ref: scrollRef,
|
|
10191
|
+
display: "flex",
|
|
10192
|
+
overflow: "auto",
|
|
10193
|
+
className: cn(
|
|
10194
|
+
"w-full",
|
|
10195
|
+
"scroll-smooth",
|
|
10196
|
+
"scrollbar-none",
|
|
10197
|
+
"[scroll-snap-type:x_mandatory]",
|
|
10198
|
+
"[&::-webkit-scrollbar]:hidden",
|
|
10199
|
+
"[-ms-overflow-style:none]"
|
|
10200
|
+
),
|
|
10201
|
+
style: {
|
|
10202
|
+
scrollSnapType: "x mandatory",
|
|
10203
|
+
WebkitOverflowScrolling: "touch"
|
|
10204
|
+
},
|
|
10205
|
+
onScroll: handleScroll,
|
|
10206
|
+
onPointerDown: swipeHandlers.onPointerDown,
|
|
10207
|
+
onPointerMove: swipeHandlers.onPointerMove,
|
|
10208
|
+
onPointerUp: swipeHandlers.onPointerUp,
|
|
10209
|
+
onPointerCancel: swipeHandlers.onPointerCancel,
|
|
10210
|
+
children: items.map((item, index) => /* @__PURE__ */ jsx(
|
|
10211
|
+
Box,
|
|
10212
|
+
{
|
|
10213
|
+
className: cn(
|
|
10214
|
+
"flex-shrink-0 w-full",
|
|
10215
|
+
"[scroll-snap-align:start]"
|
|
10216
|
+
),
|
|
10217
|
+
style: {
|
|
10218
|
+
scrollSnapAlign: "start"
|
|
10219
|
+
},
|
|
10220
|
+
children: renderItem(item, index)
|
|
10221
|
+
},
|
|
10222
|
+
index
|
|
10223
|
+
))
|
|
10224
|
+
}
|
|
10225
|
+
),
|
|
10226
|
+
showArrows && hasPrev && totalSlides > 1 && /* @__PURE__ */ jsx(
|
|
10227
|
+
Box,
|
|
10228
|
+
{
|
|
10229
|
+
position: "absolute",
|
|
10230
|
+
className: "left-2 top-1/2 -translate-y-1/2 z-10",
|
|
10231
|
+
children: /* @__PURE__ */ jsx(
|
|
10232
|
+
Button,
|
|
10233
|
+
{
|
|
10234
|
+
variant: "ghost",
|
|
10235
|
+
size: "sm",
|
|
10236
|
+
onClick: goPrev,
|
|
10237
|
+
"aria-label": "Previous slide",
|
|
10238
|
+
className: cn(
|
|
10239
|
+
"rounded-full",
|
|
10240
|
+
"bg-[var(--color-surface)]/80",
|
|
10241
|
+
"backdrop-blur-sm",
|
|
10242
|
+
"shadow-[var(--shadow-sm)]",
|
|
10243
|
+
"hover:bg-[var(--color-surface)]"
|
|
10244
|
+
),
|
|
10245
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "w-5 h-5" })
|
|
10246
|
+
}
|
|
10247
|
+
)
|
|
10248
|
+
}
|
|
10249
|
+
),
|
|
10250
|
+
showArrows && hasNext && totalSlides > 1 && /* @__PURE__ */ jsx(
|
|
10251
|
+
Box,
|
|
10252
|
+
{
|
|
10253
|
+
position: "absolute",
|
|
10254
|
+
className: "right-2 top-1/2 -translate-y-1/2 z-10",
|
|
10255
|
+
children: /* @__PURE__ */ jsx(
|
|
10256
|
+
Button,
|
|
10257
|
+
{
|
|
10258
|
+
variant: "ghost",
|
|
10259
|
+
size: "sm",
|
|
10260
|
+
onClick: goNext,
|
|
10261
|
+
"aria-label": "Next slide",
|
|
10262
|
+
className: cn(
|
|
10263
|
+
"rounded-full",
|
|
10264
|
+
"bg-[var(--color-surface)]/80",
|
|
10265
|
+
"backdrop-blur-sm",
|
|
10266
|
+
"shadow-[var(--shadow-sm)]",
|
|
10267
|
+
"hover:bg-[var(--color-surface)]"
|
|
10268
|
+
),
|
|
10269
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "w-5 h-5" })
|
|
10270
|
+
}
|
|
10271
|
+
)
|
|
10272
|
+
}
|
|
10273
|
+
),
|
|
10274
|
+
showDots && totalSlides > 1 && /* @__PURE__ */ jsx(
|
|
10275
|
+
Box,
|
|
10276
|
+
{
|
|
10277
|
+
position: "absolute",
|
|
10278
|
+
className: "bottom-3 left-0 right-0 z-10",
|
|
10279
|
+
children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", justify: "center", children: items.map((_, index) => {
|
|
10280
|
+
const isActive = index === activeIndex;
|
|
10281
|
+
return /* @__PURE__ */ jsx(
|
|
10282
|
+
Box,
|
|
10283
|
+
{
|
|
10284
|
+
className: cn(
|
|
10285
|
+
"rounded-full cursor-pointer transition-all duration-200"
|
|
10286
|
+
),
|
|
10287
|
+
style: {
|
|
10288
|
+
width: isActive ? 10 : 8,
|
|
10289
|
+
height: isActive ? 10 : 8,
|
|
10290
|
+
backgroundColor: isActive ? "var(--color-primary)" : "var(--color-muted, #d4d4d8)",
|
|
10291
|
+
opacity: isActive ? 1 : 0.6
|
|
10292
|
+
},
|
|
10293
|
+
onClick: () => goToSlide(index),
|
|
10294
|
+
role: "button",
|
|
10295
|
+
"aria-label": `Go to slide ${index + 1}`
|
|
10296
|
+
},
|
|
10297
|
+
index
|
|
10298
|
+
);
|
|
10299
|
+
}) })
|
|
10300
|
+
}
|
|
10301
|
+
)
|
|
10302
|
+
] });
|
|
7941
10303
|
};
|
|
7942
|
-
|
|
10304
|
+
Carousel.displayName = "Carousel";
|
|
10305
|
+
function useSafeEventBus11() {
|
|
10306
|
+
try {
|
|
10307
|
+
return useEventBus();
|
|
10308
|
+
} catch {
|
|
10309
|
+
return { emit: () => {
|
|
10310
|
+
}, on: () => () => {
|
|
10311
|
+
}, once: () => {
|
|
10312
|
+
} };
|
|
10313
|
+
}
|
|
10314
|
+
}
|
|
10315
|
+
var SAFETY_TIMEOUT_MS = 5e3;
|
|
10316
|
+
var PullToRefresh = ({
|
|
10317
|
+
refreshEvent,
|
|
10318
|
+
refreshPayload,
|
|
10319
|
+
threshold = 60,
|
|
10320
|
+
children,
|
|
10321
|
+
className
|
|
10322
|
+
}) => {
|
|
10323
|
+
const eventBus = useSafeEventBus11();
|
|
10324
|
+
const safetyTimerRef = useRef(null);
|
|
10325
|
+
const handleRefresh = useCallback(() => {
|
|
10326
|
+
eventBus.emit(`UI:${refreshEvent}`, refreshPayload ?? {});
|
|
10327
|
+
}, [eventBus, refreshEvent, refreshPayload]);
|
|
10328
|
+
const { pullDistance, isPulling, isRefreshing, containerProps, endRefresh } = usePullToRefresh(handleRefresh, { threshold });
|
|
10329
|
+
useEffect(() => {
|
|
10330
|
+
if (isRefreshing) {
|
|
10331
|
+
safetyTimerRef.current = setTimeout(() => {
|
|
10332
|
+
endRefresh();
|
|
10333
|
+
}, SAFETY_TIMEOUT_MS);
|
|
10334
|
+
return () => {
|
|
10335
|
+
if (safetyTimerRef.current) {
|
|
10336
|
+
clearTimeout(safetyTimerRef.current);
|
|
10337
|
+
safetyTimerRef.current = null;
|
|
10338
|
+
}
|
|
10339
|
+
};
|
|
10340
|
+
}
|
|
10341
|
+
}, [isRefreshing, endRefresh]);
|
|
10342
|
+
useEffect(() => {
|
|
10343
|
+
return () => {
|
|
10344
|
+
if (safetyTimerRef.current) {
|
|
10345
|
+
clearTimeout(safetyTimerRef.current);
|
|
10346
|
+
}
|
|
10347
|
+
};
|
|
10348
|
+
}, []);
|
|
10349
|
+
const pullProgress = Math.min(pullDistance / threshold, 1);
|
|
10350
|
+
const showIndicator = pullDistance > 0 || isRefreshing;
|
|
10351
|
+
return /* @__PURE__ */ jsxs(Box, { position: "relative", overflow: "hidden", className: cn("w-full", className), children: [
|
|
10352
|
+
/* @__PURE__ */ jsx(
|
|
10353
|
+
Box,
|
|
10354
|
+
{
|
|
10355
|
+
position: "absolute",
|
|
10356
|
+
display: "flex",
|
|
10357
|
+
className: cn(
|
|
10358
|
+
"top-0 left-0 right-0 z-10",
|
|
10359
|
+
"items-center justify-center",
|
|
10360
|
+
"transition-opacity duration-200",
|
|
10361
|
+
showIndicator ? "opacity-100" : "opacity-0"
|
|
10362
|
+
),
|
|
10363
|
+
style: {
|
|
10364
|
+
height: threshold,
|
|
10365
|
+
transform: `translateY(${showIndicator ? 0 : -threshold}px)`,
|
|
10366
|
+
pointerEvents: "none"
|
|
10367
|
+
},
|
|
10368
|
+
children: /* @__PURE__ */ jsx(
|
|
10369
|
+
Box,
|
|
10370
|
+
{
|
|
10371
|
+
className: "transition-transform duration-150",
|
|
10372
|
+
style: {
|
|
10373
|
+
transform: `scale(${isRefreshing ? 1 : pullProgress})`,
|
|
10374
|
+
opacity: isRefreshing ? 1 : pullProgress
|
|
10375
|
+
},
|
|
10376
|
+
children: /* @__PURE__ */ jsx(
|
|
10377
|
+
Spinner,
|
|
10378
|
+
{
|
|
10379
|
+
size: pullProgress >= 0.5 ? "md" : "sm",
|
|
10380
|
+
className: cn(
|
|
10381
|
+
"text-[var(--color-primary)]",
|
|
10382
|
+
isRefreshing && "animate-spin"
|
|
10383
|
+
)
|
|
10384
|
+
}
|
|
10385
|
+
)
|
|
10386
|
+
}
|
|
10387
|
+
)
|
|
10388
|
+
}
|
|
10389
|
+
),
|
|
10390
|
+
/* @__PURE__ */ jsx(
|
|
10391
|
+
Box,
|
|
10392
|
+
{
|
|
10393
|
+
fullWidth: true,
|
|
10394
|
+
className: cn(
|
|
10395
|
+
"min-h-0",
|
|
10396
|
+
isPulling && "select-none"
|
|
10397
|
+
),
|
|
10398
|
+
...containerProps,
|
|
10399
|
+
children
|
|
10400
|
+
}
|
|
10401
|
+
)
|
|
10402
|
+
] });
|
|
10403
|
+
};
|
|
10404
|
+
PullToRefresh.displayName = "PullToRefresh";
|
|
7943
10405
|
|
|
7944
10406
|
// components/organisms/types.ts
|
|
7945
10407
|
var EntityDisplayEvents = {
|
|
@@ -8368,6 +10830,7 @@ var StatCard = ({
|
|
|
8368
10830
|
// Schema-based props
|
|
8369
10831
|
entity,
|
|
8370
10832
|
metrics,
|
|
10833
|
+
sparklineData,
|
|
8371
10834
|
isLoading: externalLoading,
|
|
8372
10835
|
error: externalError
|
|
8373
10836
|
}) => {
|
|
@@ -8375,7 +10838,7 @@ var StatCard = ({
|
|
|
8375
10838
|
const labelToUse = propLabel ?? propTitle;
|
|
8376
10839
|
const eventBus = useEventBus();
|
|
8377
10840
|
const { t } = useTranslate();
|
|
8378
|
-
const handleActionClick =
|
|
10841
|
+
const handleActionClick = React69__default.useCallback(() => {
|
|
8379
10842
|
if (action?.event) {
|
|
8380
10843
|
eventBus.emit(`UI:${action.event}`, {});
|
|
8381
10844
|
}
|
|
@@ -8386,7 +10849,7 @@ var StatCard = ({
|
|
|
8386
10849
|
const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
|
|
8387
10850
|
const isLoading = externalLoading ?? false;
|
|
8388
10851
|
const error = externalError;
|
|
8389
|
-
const computeMetricValue =
|
|
10852
|
+
const computeMetricValue = React69__default.useCallback(
|
|
8390
10853
|
(metric, items) => {
|
|
8391
10854
|
if (metric.value !== void 0) {
|
|
8392
10855
|
return metric.value;
|
|
@@ -8425,7 +10888,7 @@ var StatCard = ({
|
|
|
8425
10888
|
},
|
|
8426
10889
|
[]
|
|
8427
10890
|
);
|
|
8428
|
-
const schemaStats =
|
|
10891
|
+
const schemaStats = React69__default.useMemo(() => {
|
|
8429
10892
|
if (!metrics || metrics.length === 0) return null;
|
|
8430
10893
|
return metrics.map((metric) => ({
|
|
8431
10894
|
label: metric.label,
|
|
@@ -8433,7 +10896,7 @@ var StatCard = ({
|
|
|
8433
10896
|
format: metric.format
|
|
8434
10897
|
}));
|
|
8435
10898
|
}, [metrics, data, computeMetricValue]);
|
|
8436
|
-
const calculatedTrend =
|
|
10899
|
+
const calculatedTrend = React69__default.useMemo(() => {
|
|
8437
10900
|
if (manualTrend !== void 0) return manualTrend;
|
|
8438
10901
|
if (previousValue === void 0 || currentValue === void 0)
|
|
8439
10902
|
return void 0;
|
|
@@ -8513,7 +10976,35 @@ var StatCard = ({
|
|
|
8513
10976
|
] }),
|
|
8514
10977
|
subtitle && !calculatedTrend && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: subtitle })
|
|
8515
10978
|
] }),
|
|
8516
|
-
|
|
10979
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
10980
|
+
Icon2 && /* @__PURE__ */ jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsx(Icon2, { className: cn("h-6 w-6", iconColor) }) }),
|
|
10981
|
+
sparklineData && sparklineData.length > 1 && (() => {
|
|
10982
|
+
const w = 80;
|
|
10983
|
+
const h = 32;
|
|
10984
|
+
const pad = 2;
|
|
10985
|
+
const min = Math.min(...sparklineData);
|
|
10986
|
+
const max = Math.max(...sparklineData);
|
|
10987
|
+
const range = max - min || 1;
|
|
10988
|
+
const points = sparklineData.map((v, i) => {
|
|
10989
|
+
const x = pad + i / (sparklineData.length - 1) * (w - pad * 2);
|
|
10990
|
+
const y = pad + (1 - (v - min) / range) * (h - pad * 2);
|
|
10991
|
+
return `${x},${y}`;
|
|
10992
|
+
}).join(" ");
|
|
10993
|
+
const trending = sparklineData[sparklineData.length - 1] >= sparklineData[0];
|
|
10994
|
+
const strokeColor = trending ? "var(--color-success)" : "var(--color-error)";
|
|
10995
|
+
return /* @__PURE__ */ jsx("svg", { width: w, height: h, viewBox: `0 0 ${w} ${h}`, className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
|
|
10996
|
+
"polyline",
|
|
10997
|
+
{
|
|
10998
|
+
fill: "none",
|
|
10999
|
+
stroke: strokeColor,
|
|
11000
|
+
strokeWidth: "2",
|
|
11001
|
+
strokeLinecap: "round",
|
|
11002
|
+
strokeLinejoin: "round",
|
|
11003
|
+
points
|
|
11004
|
+
}
|
|
11005
|
+
) });
|
|
11006
|
+
})()
|
|
11007
|
+
] })
|
|
8517
11008
|
] }),
|
|
8518
11009
|
action && /* @__PURE__ */ jsxs(
|
|
8519
11010
|
Button,
|
|
@@ -8561,7 +11052,7 @@ var PageHeader = ({
|
|
|
8561
11052
|
action.onClick();
|
|
8562
11053
|
}
|
|
8563
11054
|
};
|
|
8564
|
-
const
|
|
11055
|
+
const statusColors2 = {
|
|
8565
11056
|
default: "bg-[var(--color-muted)] text-[var(--color-foreground)]",
|
|
8566
11057
|
success: "bg-[var(--color-success)]/10 text-[var(--color-success)]",
|
|
8567
11058
|
warning: "bg-[var(--color-warning)]/10 text-[var(--color-warning)]",
|
|
@@ -8569,7 +11060,7 @@ var PageHeader = ({
|
|
|
8569
11060
|
info: "bg-[var(--color-info)]/10 text-[var(--color-info)]"
|
|
8570
11061
|
};
|
|
8571
11062
|
return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
|
|
8572
|
-
breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Box, { as: "nav", className: "mb-4", children: /* @__PURE__ */ jsx(Box, { as: "ol", className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, idx) => /* @__PURE__ */ jsxs(
|
|
11063
|
+
breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Box, { as: "nav", className: "mb-4", children: /* @__PURE__ */ jsx(Box, { as: "ol", className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, idx) => /* @__PURE__ */ jsxs(React69__default.Fragment, { children: [
|
|
8573
11064
|
idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
|
|
8574
11065
|
crumb.href ? /* @__PURE__ */ jsx(
|
|
8575
11066
|
"a",
|
|
@@ -8600,7 +11091,7 @@ var PageHeader = ({
|
|
|
8600
11091
|
variant: "small",
|
|
8601
11092
|
className: cn(
|
|
8602
11093
|
"px-2.5 py-1 rounded-[var(--radius-full)] text-xs font-medium",
|
|
8603
|
-
|
|
11094
|
+
statusColors2[status.variant || "default"]
|
|
8604
11095
|
),
|
|
8605
11096
|
children: status.label
|
|
8606
11097
|
}
|
|
@@ -8805,7 +11296,7 @@ var DetailPanel = ({
|
|
|
8805
11296
|
return;
|
|
8806
11297
|
}
|
|
8807
11298
|
if (action.event) {
|
|
8808
|
-
eventBus.emit(`UI:${action.event}`, { row: data2 });
|
|
11299
|
+
eventBus.emit(`UI:${action.event}`, { id: data2?.id, row: data2 });
|
|
8809
11300
|
}
|
|
8810
11301
|
if (action.onClick) {
|
|
8811
11302
|
action.onClick();
|
|
@@ -9202,7 +11693,7 @@ var Form = ({
|
|
|
9202
11693
|
const normalizedInitialData = initialData ?? {};
|
|
9203
11694
|
const resolvedEntity = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
|
|
9204
11695
|
const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
|
|
9205
|
-
const entityDerivedFields =
|
|
11696
|
+
const entityDerivedFields = React69__default.useMemo(() => {
|
|
9206
11697
|
if (fields && fields.length > 0) return void 0;
|
|
9207
11698
|
if (!resolvedEntity) return void 0;
|
|
9208
11699
|
return resolvedEntity.fields.map(
|
|
@@ -9221,14 +11712,14 @@ var Form = ({
|
|
|
9221
11712
|
const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
|
|
9222
11713
|
const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
|
|
9223
11714
|
const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
|
|
9224
|
-
const [formData, setFormData] =
|
|
11715
|
+
const [formData, setFormData] = React69__default.useState(
|
|
9225
11716
|
normalizedInitialData
|
|
9226
11717
|
);
|
|
9227
|
-
const [collapsedSections, setCollapsedSections] =
|
|
11718
|
+
const [collapsedSections, setCollapsedSections] = React69__default.useState(
|
|
9228
11719
|
/* @__PURE__ */ new Set()
|
|
9229
11720
|
);
|
|
9230
11721
|
const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
|
|
9231
|
-
const evalContext =
|
|
11722
|
+
const evalContext = React69__default.useMemo(
|
|
9232
11723
|
() => ({
|
|
9233
11724
|
formValues: formData,
|
|
9234
11725
|
globalVariables: externalContext?.globalVariables ?? {},
|
|
@@ -9237,13 +11728,13 @@ var Form = ({
|
|
|
9237
11728
|
}),
|
|
9238
11729
|
[formData, externalContext]
|
|
9239
11730
|
);
|
|
9240
|
-
|
|
11731
|
+
React69__default.useEffect(() => {
|
|
9241
11732
|
const data = initialData;
|
|
9242
11733
|
if (data && Object.keys(data).length > 0) {
|
|
9243
11734
|
setFormData(data);
|
|
9244
11735
|
}
|
|
9245
11736
|
}, [initialData]);
|
|
9246
|
-
const processCalculations =
|
|
11737
|
+
const processCalculations = React69__default.useCallback(
|
|
9247
11738
|
(changedFieldId, newFormData) => {
|
|
9248
11739
|
if (!hiddenCalculations.length) return;
|
|
9249
11740
|
const context = {
|
|
@@ -9268,7 +11759,7 @@ var Form = ({
|
|
|
9268
11759
|
},
|
|
9269
11760
|
[hiddenCalculations, externalContext, eventBus]
|
|
9270
11761
|
);
|
|
9271
|
-
const checkViolations =
|
|
11762
|
+
const checkViolations = React69__default.useCallback(
|
|
9272
11763
|
(changedFieldId, newFormData) => {
|
|
9273
11764
|
if (!violationTriggers.length) return;
|
|
9274
11765
|
const context = {
|
|
@@ -9305,7 +11796,7 @@ var Form = ({
|
|
|
9305
11796
|
processCalculations(name, newFormData);
|
|
9306
11797
|
checkViolations(name, newFormData);
|
|
9307
11798
|
};
|
|
9308
|
-
const isFieldVisible =
|
|
11799
|
+
const isFieldVisible = React69__default.useCallback(
|
|
9309
11800
|
(fieldName) => {
|
|
9310
11801
|
const condition = conditionalFields[fieldName];
|
|
9311
11802
|
if (!condition) return true;
|
|
@@ -9313,7 +11804,7 @@ var Form = ({
|
|
|
9313
11804
|
},
|
|
9314
11805
|
[conditionalFields, evalContext]
|
|
9315
11806
|
);
|
|
9316
|
-
const isSectionVisible =
|
|
11807
|
+
const isSectionVisible = React69__default.useCallback(
|
|
9317
11808
|
(section) => {
|
|
9318
11809
|
if (!section.condition) return true;
|
|
9319
11810
|
return Boolean(evaluateFormExpression(section.condition, evalContext));
|
|
@@ -9345,7 +11836,7 @@ var Form = ({
|
|
|
9345
11836
|
eventBus.emit(`UI:${onCancel}`);
|
|
9346
11837
|
}
|
|
9347
11838
|
};
|
|
9348
|
-
const renderField =
|
|
11839
|
+
const renderField = React69__default.useCallback(
|
|
9349
11840
|
(field) => {
|
|
9350
11841
|
const fieldName = field.name || field.field;
|
|
9351
11842
|
if (!fieldName) return null;
|
|
@@ -9366,7 +11857,7 @@ var Form = ({
|
|
|
9366
11857
|
[formData, isFieldVisible, relationsData, relationsLoading, isLoading]
|
|
9367
11858
|
);
|
|
9368
11859
|
const effectiveFields = entityDerivedFields ?? fields;
|
|
9369
|
-
const normalizedFields =
|
|
11860
|
+
const normalizedFields = React69__default.useMemo(() => {
|
|
9370
11861
|
if (!effectiveFields || effectiveFields.length === 0) return [];
|
|
9371
11862
|
return effectiveFields.map((field) => {
|
|
9372
11863
|
if (typeof field === "string") {
|
|
@@ -9375,7 +11866,7 @@ var Form = ({
|
|
|
9375
11866
|
return field;
|
|
9376
11867
|
});
|
|
9377
11868
|
}, [effectiveFields]);
|
|
9378
|
-
const schemaFields =
|
|
11869
|
+
const schemaFields = React69__default.useMemo(() => {
|
|
9379
11870
|
if (normalizedFields.length === 0) return null;
|
|
9380
11871
|
if (isDebugEnabled()) {
|
|
9381
11872
|
debugGroup(`Form: ${entityName || "unknown"}`);
|
|
@@ -9385,7 +11876,7 @@ var Form = ({
|
|
|
9385
11876
|
}
|
|
9386
11877
|
return normalizedFields.map(renderField).filter(Boolean);
|
|
9387
11878
|
}, [normalizedFields, renderField, entityName, conditionalFields]);
|
|
9388
|
-
const sectionElements =
|
|
11879
|
+
const sectionElements = React69__default.useMemo(() => {
|
|
9389
11880
|
if (!sections || sections.length === 0) return null;
|
|
9390
11881
|
return sections.map((section) => {
|
|
9391
11882
|
if (!isSectionVisible(section)) {
|
|
@@ -9724,7 +12215,7 @@ var CardGrid = ({
|
|
|
9724
12215
|
return;
|
|
9725
12216
|
}
|
|
9726
12217
|
if (action.event) {
|
|
9727
|
-
eventBus.emit(`UI:${action.event}`, { row: itemData });
|
|
12218
|
+
eventBus.emit(`UI:${action.event}`, { id: itemData.id, row: itemData });
|
|
9728
12219
|
}
|
|
9729
12220
|
if (action.onClick) {
|
|
9730
12221
|
action.onClick(itemData);
|
|
@@ -10236,7 +12727,7 @@ function InputPattern({
|
|
|
10236
12727
|
className
|
|
10237
12728
|
}) {
|
|
10238
12729
|
const { emit } = useEventBus();
|
|
10239
|
-
const [localValue, setLocalValue] =
|
|
12730
|
+
const [localValue, setLocalValue] = React69__default.useState(value);
|
|
10240
12731
|
const handleChange = (e) => {
|
|
10241
12732
|
setLocalValue(e.target.value);
|
|
10242
12733
|
if (onChange) {
|
|
@@ -10273,7 +12764,7 @@ function TextareaPattern({
|
|
|
10273
12764
|
className
|
|
10274
12765
|
}) {
|
|
10275
12766
|
const { emit } = useEventBus();
|
|
10276
|
-
const [localValue, setLocalValue] =
|
|
12767
|
+
const [localValue, setLocalValue] = React69__default.useState(value);
|
|
10277
12768
|
const handleChange = (e) => {
|
|
10278
12769
|
setLocalValue(e.target.value);
|
|
10279
12770
|
if (onChange) {
|
|
@@ -10304,7 +12795,7 @@ function SelectPattern({
|
|
|
10304
12795
|
className
|
|
10305
12796
|
}) {
|
|
10306
12797
|
const { emit } = useEventBus();
|
|
10307
|
-
const [localValue, setLocalValue] =
|
|
12798
|
+
const [localValue, setLocalValue] = React69__default.useState(value);
|
|
10308
12799
|
const handleChange = (e) => {
|
|
10309
12800
|
setLocalValue(e.target.value);
|
|
10310
12801
|
if (onChange) {
|
|
@@ -10333,7 +12824,7 @@ function CheckboxPattern({
|
|
|
10333
12824
|
className
|
|
10334
12825
|
}) {
|
|
10335
12826
|
const { emit } = useEventBus();
|
|
10336
|
-
const [localChecked, setLocalChecked] =
|
|
12827
|
+
const [localChecked, setLocalChecked] = React69__default.useState(checked);
|
|
10337
12828
|
const handleChange = (e) => {
|
|
10338
12829
|
setLocalChecked(e.target.checked);
|
|
10339
12830
|
if (onChange) {
|
|
@@ -10763,7 +13254,7 @@ function SuspenseConfigProvider({
|
|
|
10763
13254
|
config,
|
|
10764
13255
|
children
|
|
10765
13256
|
}) {
|
|
10766
|
-
return
|
|
13257
|
+
return React69__default.createElement(
|
|
10767
13258
|
SuspenseConfigContext.Provider,
|
|
10768
13259
|
{ value: config },
|
|
10769
13260
|
children
|
|
@@ -11016,7 +13507,7 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
|
|
|
11016
13507
|
let wrapper;
|
|
11017
13508
|
switch (slot) {
|
|
11018
13509
|
case "modal":
|
|
11019
|
-
wrapper = /* @__PURE__ */ jsx(Modal, { isOpen: true, onClose: handleDismiss, showCloseButton: true, children: /* @__PURE__ */ jsx(
|
|
13510
|
+
wrapper = /* @__PURE__ */ jsx(Modal, { isOpen: true, onClose: handleDismiss, showCloseButton: true, size: "lg", children: /* @__PURE__ */ jsx(
|
|
11020
13511
|
Box,
|
|
11021
13512
|
{
|
|
11022
13513
|
className: cn("ui-slot", `ui-slot-${slot}`, className),
|
|
@@ -11248,4 +13739,4 @@ function UISlotRenderer({
|
|
|
11248
13739
|
}
|
|
11249
13740
|
UISlotRenderer.displayName = "UISlotRenderer";
|
|
11250
13741
|
|
|
11251
|
-
export { Accordion, ActionButtons, Alert, Avatar, Badge, Box, Breadcrumb, Button, ButtonGroup, CalendarGrid, Card, Card2, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Center, ChartLegend, Checkbox, CodeBlock, ConditionalWrapper, Container, ControlButton, DPad, DataGrid, DataList, DataTable, DateRangeSelector, DayCell, DetailPanel, Divider, Drawer, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, FilterGroup, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormField, FormSectionHeader, GraphView, Grid, HStack, Heading, HealthBar, Icon, Input, InputGroup, Label, LawReferenceTooltip, LineChart, LoadingState, MapView, MarkdownContent, MasterDetail, Menu, Modal, Overlay, PageHeader, Pagination, Popover, ProgressBar, ProgressDots, QuizBlock, Radio, RelationSelect, RepeatableFormSection, ScaledDiagram, ScoreDisplay, SearchInput, Select, SidePanel, SimpleGrid, Skeleton, SlotContentRenderer, Spacer, Spinner, Sprite, Stack, StatBadge, StatCard, StateIndicator, SuspenseConfigProvider, Switch, Tabs, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Toast, Tooltip, Typography, UISlotComponent, UISlotRenderer, VStack, ViolationAlert, WizardNavigation, WizardProgress, drawSprite };
|
|
13742
|
+
export { Accordion, ActionButtons, Alert, AnimatedCounter, Avatar, Badge, Box, Breadcrumb, Button, ButtonGroup, CalendarGrid, Card, Card2, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, Center, ChartLegend, Checkbox, CodeBlock, ConditionalWrapper, ConfettiEffect, Container, ControlButton, DPad, DataGrid, DataList, DataTable, DateRangeSelector, DayCell, DetailPanel, Divider, Drawer, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, FilterGroup, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormField, FormSectionHeader, GraphView, Grid, HStack, Heading, HealthBar, Icon, InfiniteScrollSentinel, Input, InputGroup, Label, LawReferenceTooltip, Lightbox, LineChart, LoadingState, MapView, MarkdownContent, MasterDetail, Menu, Meter, Modal, NumberStepper, Overlay, PageHeader, Pagination, Popover, ProgressBar, ProgressDots, PullToRefresh, QuizBlock, Radio, RangeSlider, RelationSelect, RepeatableFormSection, ScaledDiagram, ScoreDisplay, SearchInput, Select, SidePanel, SimpleGrid, Skeleton, SlotContentRenderer, SortableList, Spacer, Spinner, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateIndicator, StatusDot, SuspenseConfigProvider, SwipeableRow, Switch, Tabs, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Toast, Tooltip, TrendIndicator, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UploadDropZone, VStack, ViolationAlert, WizardNavigation, WizardProgress, drawSprite };
|