@almadar/ui 2.5.0 → 2.6.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.
@@ -1,14 +1,14 @@
1
- import { useTheme, useUISlots } from './chunk-YLKXEXBP.js';
2
- import { useTranslate, useQuerySingleton } from './chunk-GOZKH7QW.js';
1
+ import { useTheme, useUISlots } from './chunk-DKQN5FVU.js';
2
+ import { useTranslate, useInfiniteScroll, useQuerySingleton, useLongPress, useSwipeGesture, useDragReorder, usePullToRefresh } from './chunk-WGJIL4YR.js';
3
3
  import { useEventBus } from './chunk-YXZM3WCF.js';
4
4
  import { cn, debugGroup, debug, debugGroupEnd, getNestedValue, isDebugEnabled } from './chunk-KKCVDUK7.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, MoreHorizontal, TrendingUp, TrendingDown, Minus, ArrowLeft, Calendar, Tag, Clock, CheckCircle2, DollarSign, FileText, Package } from 'lucide-react';
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 React50 from 'react';
11
- import React50__default, { useCallback, useRef, useState, useLayoutEffect, useEffect, lazy, createContext, useMemo, useId, useContext, Suspense } from 'react';
10
+ import * as React68 from 'react';
11
+ import React68__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 = React50__default.forwardRef(
160
+ var Button = React68__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 = React50__default.forwardRef(
218
+ var Input = React68__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 = React50__default.forwardRef(
330
+ var Label = React68__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 = React50__default.forwardRef(
350
+ var Textarea = React68__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 = React50__default.forwardRef(
373
+ var Select = React68__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 = React50__default.forwardRef(
409
+ var Checkbox = React68__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 = React50__default.forwardRef(
475
+ var Card = React68__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 = React50__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
511
+ var CardHeader = React68__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
512
512
  CardHeader.displayName = "CardHeader";
513
- var CardTitle = React50__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
513
+ var CardTitle = React68__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 = React50__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
526
+ var CardContent = React68__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 = React50__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
530
+ var CardFooter = React68__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
531
531
  "div",
532
532
  {
533
533
  ref,
@@ -573,7 +573,7 @@ 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 = React50__default.forwardRef(
576
+ var Badge = React68__default.forwardRef(
577
577
  ({ className, variant = "default", size = "sm", 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" ? (() => {
@@ -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 = React50__default.forwardRef(
609
+ var Spinner = React68__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 = React50__default.forwardRef(
874
+ var Box = React68__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 = React50__default.forwardRef(
1219
+ var Radio = React68__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 = React50.forwardRef(
1323
+ var Switch = React68.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] = React50.useState(
1334
+ const [isChecked, setIsChecked] = React68.useState(
1335
1335
  checked !== void 0 ? checked : defaultChecked
1336
1336
  );
1337
- React50.useEffect(() => {
1337
+ React68.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 directionClass = direction === "horizontal" ? reverse ? "flex-row-reverse" : "flex-row" : reverse ? "flex-col-reverse" : "flex-col";
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] = React50__default.useState(false);
2009
- const timeoutRef = React50__default.useRef(null);
2010
+ const [isVisible, setIsVisible] = React68__default.useState(false);
2011
+ const timeoutRef = React68__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
- React50__default.useEffect(() => {
2020
+ React68__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 = React68__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 = React68__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 = React68__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: formatValue3,
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 = formatValue3 ? formatValue3(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] = React50.useState(value);
2268
- const [isAnimating, setIsAnimating] = React50.useState(false);
2269
- React50.useEffect(() => {
2830
+ const [displayValue, setDisplayValue] = React68.useState(value);
2831
+ const [isAnimating, setIsAnimating] = React68.useState(false);
2832
+ React68.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] = React50.useState(false);
2905
+ const [isPressed, setIsPressed] = React68.useState(false);
2343
2906
  const actualPressed = pressed ?? isPressed;
2344
- const handlePointerDown = React50.useCallback(
2907
+ const handlePointerDown = React68.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 = React50.useCallback(
2917
+ const handlePointerUp = React68.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 = React50.useCallback(
2927
+ const handlePointerLeave = React68.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 React50__default.Component {
3155
+ var ErrorBoundary = class extends React68__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 iconMap = {
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: iconMap[variant],
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 useSafeEventBus() {
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 = useSafeEventBus();
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 sizeStyles5 = {
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
- sizeStyles5[resolvedSize],
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 = React50__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx("span", { children: trigger });
4201
- const triggerElement = React50__default.cloneElement(
4777
+ const triggerChild = React68__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx("span", { children: trigger });
4778
+ const triggerElement = React68__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: "fixed inset-0 z-50 flex items-center justify-center p-4 pointer-events-none", children: /* @__PURE__ */ jsxs(
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 = React50__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
4664
- const triggerElement = React50__default.cloneElement(
5283
+ const childElement = React68__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
5284
+ const triggerElement = React68__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 iconMap2 = {
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: iconMap2[variant],
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 = React50__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
5395
- const trigger = React50__default.cloneElement(triggerElement, {
6014
+ const triggerElement = React68__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
6015
+ const trigger = React68__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(React50__default.Fragment, { children: [
6264
+ return /* @__PURE__ */ jsxs(React68__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 useSafeEventBus2() {
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 = useSafeEventBus2();
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 = React50__default.memo(
6394
+ var MarkdownContent = React68__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 = React50__default.memo(
6495
+ var CodeBlock = React68__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(Box, { className: cn("overflow-x-auto", className), children: /* @__PURE__ */ jsxs(Box, { className: "min-w-[800px]", children: [
6185
- /* @__PURE__ */ jsxs(Box, { className: "grid grid-cols-8 border-b border-[var(--color-border)]", children: [
6186
- /* @__PURE__ */ jsx(Box, { className: "p-2" }),
6187
- weekDays.map((day) => {
6188
- const isToday = day.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
6189
- const count = eventsForDayCount(day);
6190
- return /* @__PURE__ */ jsxs(
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-l border-[var(--color-border)]",
6866
+ className: "grid grid-cols-8 border-b border-[var(--color-border)]",
6194
6867
  children: [
6195
- /* @__PURE__ */ jsx(
6196
- DayCell,
6868
+ /* @__PURE__ */ jsx(Box, { className: "p-2 text-right pr-3", children: /* @__PURE__ */ jsx(
6869
+ Typography,
6197
6870
  {
6198
- date: day,
6199
- isToday,
6200
- onClick: onDayClick
6871
+ variant: "small",
6872
+ className: "text-[var(--color-muted-foreground)]",
6873
+ children: time
6201
6874
  }
6202
- ),
6203
- count > 0 && /* @__PURE__ */ jsx(Box, { className: "text-center pb-1", children: /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: count }) })
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
- day.toISOString()
6207
- );
6208
- })
6209
- ] }),
6210
- /* @__PURE__ */ jsx(Box, { className: "max-h-[500px] overflow-y-auto", children: resolvedTimeSlots.map((time) => /* @__PURE__ */ jsxs(
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] = React50.useState(/* @__PURE__ */ new Set());
6884
- const handlePress = React50.useCallback(
7543
+ const [activeDirections, setActiveDirections] = React68.useState(/* @__PURE__ */ new Set());
7544
+ const handlePress = React68.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 = React50.useCallback(
7552
+ const handleRelease = React68.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] = React50.useState(/* @__PURE__ */ new Set());
6951
- const handlePress = React50.useCallback(
7610
+ const [activeButtons, setActiveButtons] = React68.useState(/* @__PURE__ */ new Set());
7611
+ const handlePress = React68.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 = React50.useCallback(
7619
+ const handleRelease = React68.useCallback(
6960
7620
  (id) => {
6961
7621
  setActiveButtons((prev) => {
6962
7622
  const next = new Set(prev);
@@ -7545,211 +8205,939 @@ function MapView({
7545
8205
  }
7546
8206
  );
7547
8207
  }
7548
- function fieldLabel(key) {
7549
- return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
7550
- }
7551
- function statusVariant(value) {
7552
- const v = value.toLowerCase();
7553
- if (["active", "completed", "done", "approved", "published", "resolved", "open", "online"].includes(v)) return "success";
7554
- if (["pending", "in_progress", "in-progress", "review", "draft", "processing", "warning"].includes(v)) return "warning";
7555
- if (["inactive", "deleted", "rejected", "failed", "error", "blocked", "closed", "offline"].includes(v)) return "error";
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 gapStyles5 = {
7583
- none: "gap-0",
7584
- sm: "gap-2",
7585
- md: "gap-4",
7586
- lg: "gap-6",
7587
- xl: "gap-8"
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 DataGrid = ({
7590
- entity,
7591
- fields: fieldsProp,
7592
- columns: columnsProp,
7593
- itemActions,
7594
- cols,
7595
- gap = "md",
7596
- minCardWidth = 280,
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
- isLoading = false,
7599
- error = null,
7600
- imageField
8248
+ label
7601
8249
  }) => {
7602
- const eventBus = useEventBus();
7603
- const { t } = useTranslate();
7604
- const fields = fieldsProp ?? columnsProp ?? [];
7605
- const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
7606
- const titleField = fields.find((f) => f.variant === "h3" || f.variant === "h4") ?? fields[0];
7607
- const badgeFields = fields.filter((f) => f.variant === "badge" && f !== titleField);
7608
- const bodyFields = fields.filter((f) => f !== titleField && !badgeFields.includes(f));
7609
- const primaryActions = itemActions?.filter((a) => a.variant !== "danger") ?? [];
7610
- const dangerActions = itemActions?.filter((a) => a.variant === "danger") ?? [];
7611
- const handleActionClick = (action, itemData) => (e) => {
7612
- e.stopPropagation();
7613
- eventBus.emit(`UI:${action.event}`, { row: itemData });
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 gridTemplateColumns = cols ? void 0 : `repeat(auto-fit, minmax(min(${minCardWidth}px, 100%), 1fr))`;
7616
- const colsClass = cols ? {
7617
- 1: "grid-cols-1",
7618
- 2: "sm:grid-cols-2",
7619
- 3: "sm:grid-cols-2 lg:grid-cols-3",
7620
- 4: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
7621
- 5: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5",
7622
- 6: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6"
7623
- }[cols] : void 0;
7624
- if (isLoading) {
7625
- return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
7626
- }
7627
- if (error) {
7628
- return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
7629
- }
7630
- if (data.length === 0) {
7631
- return /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
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
- Box,
8446
+ "div",
7635
8447
  {
7636
- className: cn("grid", gapStyles5[gap], colsClass, className),
7637
- style: gridTemplateColumns ? { gridTemplateColumns } : void 0,
7638
- children: data.map((item, index) => {
7639
- const itemData = item;
7640
- const id = itemData.id || String(index);
7641
- const titleValue = getNestedValue(itemData, titleField?.name ?? "");
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
- Box,
8467
+ "span",
7644
8468
  {
7645
- "data-entity-row": true,
7646
- className: cn(
7647
- "bg-[var(--color-card)] rounded-[var(--radius-lg)]",
7648
- "border border-[var(--color-border)]",
7649
- "shadow-[var(--shadow-sm)] hover:shadow-[var(--shadow-hover)]",
7650
- "hover:border-[var(--color-primary)] transition-all",
7651
- "flex flex-col"
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
- imageField && (() => {
7655
- const imgUrl = getNestedValue(itemData, imageField);
7656
- if (!imgUrl || typeof imgUrl !== "string") return null;
7657
- return /* @__PURE__ */ jsx(Box, { className: "w-full aspect-video overflow-hidden rounded-t-[var(--radius-lg)]", children: /* @__PURE__ */ jsx(
7658
- "img",
7659
- {
7660
- src: imgUrl,
7661
- alt: titleValue !== void 0 ? String(titleValue) : "",
7662
- className: "w-full h-full object-cover",
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) })
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
8487
+ }
8488
+ ),
8489
+ (isFull || isHalf) && /* @__PURE__ */ jsx(
8490
+ Star,
8491
+ {
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
+ )
8512
+ ]
8513
+ },
8514
+ i
8515
+ );
8516
+ })
8517
+ }
8518
+ );
8519
+ };
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) {
8866
+ return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
8867
+ }
8868
+ function statusVariant(value) {
8869
+ const v = value.toLowerCase();
8870
+ if (["active", "completed", "done", "approved", "published", "resolved", "open", "online"].includes(v)) return "success";
8871
+ if (["pending", "in_progress", "in-progress", "review", "draft", "processing", "warning"].includes(v)) return "warning";
8872
+ if (["inactive", "deleted", "rejected", "failed", "error", "blocked", "closed", "offline"].includes(v)) return "error";
8873
+ if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
8874
+ return "default";
8875
+ }
8876
+ function formatDate(value) {
8877
+ if (!value) return "";
8878
+ const d = new Date(String(value));
8879
+ if (isNaN(d.getTime())) return String(value);
8880
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
8881
+ }
8882
+ function formatValue(value, format) {
8883
+ if (value === void 0 || value === null) return "";
8884
+ switch (format) {
8885
+ case "date":
8886
+ return formatDate(value);
8887
+ case "currency":
8888
+ return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
8889
+ case "number":
8890
+ return typeof value === "number" ? value.toLocaleString() : String(value);
8891
+ case "percent":
8892
+ return typeof value === "number" ? `${Math.round(value)}%` : String(value);
8893
+ case "boolean":
8894
+ return value ? "Yes" : "No";
8895
+ default:
8896
+ return String(value);
8897
+ }
8898
+ }
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 = ({
8907
+ entity,
8908
+ fields: fieldsProp,
8909
+ columns: columnsProp,
8910
+ itemActions,
8911
+ cols,
8912
+ gap = "md",
8913
+ minCardWidth = 280,
8914
+ className,
8915
+ isLoading = false,
8916
+ error = null,
8917
+ imageField,
8918
+ selectable = false,
8919
+ selectionEvent,
8920
+ infiniteScroll,
8921
+ loadMoreEvent,
8922
+ hasMore
8923
+ }) => {
8924
+ const eventBus = useEventBus();
8925
+ const { t } = useTranslate();
8926
+ const [selectedIds, setSelectedIds] = useState(/* @__PURE__ */ new Set());
8927
+ const fields = fieldsProp ?? columnsProp ?? [];
8928
+ const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
8929
+ const toggleSelection = useCallback((id) => {
8930
+ setSelectedIds((prev) => {
8931
+ const next = new Set(prev);
8932
+ if (next.has(id)) next.delete(id);
8933
+ else next.add(id);
8934
+ if (selectionEvent) {
8935
+ eventBus.emit(`UI:${selectionEvent}`, { selectedIds: Array.from(next) });
8936
+ }
8937
+ return next;
8938
+ });
8939
+ }, [selectionEvent, eventBus]);
8940
+ const toggleAll = useCallback(() => {
8941
+ setSelectedIds((prev) => {
8942
+ const allIds2 = data.map((item, i) => item.id || String(i));
8943
+ const allSelected2 = allIds2.length > 0 && allIds2.every((id) => prev.has(id));
8944
+ const next = allSelected2 ? /* @__PURE__ */ new Set() : new Set(allIds2);
8945
+ if (selectionEvent) {
8946
+ eventBus.emit(`UI:${selectionEvent}`, { selectedIds: Array.from(next) });
8947
+ }
8948
+ return next;
8949
+ });
8950
+ }, [data, selectionEvent, eventBus]);
8951
+ const titleField = fields.find((f) => f.variant === "h3" || f.variant === "h4") ?? fields[0];
8952
+ const badgeFields = fields.filter((f) => f.variant === "badge" && f !== titleField);
8953
+ const bodyFields = fields.filter((f) => f !== titleField && !badgeFields.includes(f));
8954
+ const primaryActions = itemActions?.filter((a) => a.variant !== "danger") ?? [];
8955
+ const dangerActions = itemActions?.filter((a) => a.variant === "danger") ?? [];
8956
+ const handleActionClick = (action, itemData) => (e) => {
8957
+ e.stopPropagation();
8958
+ eventBus.emit(`UI:${action.event}`, { row: itemData });
8959
+ };
8960
+ const gridTemplateColumns = cols ? void 0 : `repeat(auto-fit, minmax(min(${minCardWidth}px, 100%), 1fr))`;
8961
+ const colsClass = cols ? {
8962
+ 1: "grid-cols-1",
8963
+ 2: "sm:grid-cols-2",
8964
+ 3: "sm:grid-cols-2 lg:grid-cols-3",
8965
+ 4: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
8966
+ 5: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5",
8967
+ 6: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6"
8968
+ }[cols] : void 0;
8969
+ if (isLoading) {
8970
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
8971
+ }
8972
+ if (error) {
8973
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
8974
+ }
8975
+ if (data.length === 0) {
8976
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
8977
+ }
8978
+ const allIds = data.map((item, i) => item.id || String(i));
8979
+ const allSelected = allIds.length > 0 && allIds.every((id) => selectedIds.has(id));
8980
+ const someSelected = selectedIds.size > 0;
8981
+ return /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
8982
+ selectable && someSelected && /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center px-2 py-2 bg-[var(--color-muted)] rounded-[var(--radius-sm)]", children: [
8983
+ /* @__PURE__ */ jsx(
8984
+ "input",
8985
+ {
8986
+ type: "checkbox",
8987
+ checked: allSelected,
8988
+ onChange: toggleAll,
8989
+ className: "w-4 h-4 accent-[var(--color-primary)]",
8990
+ "aria-label": "Select all"
8991
+ }
8992
+ ),
8993
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "font-semibold", children: [
8994
+ selectedIds.size,
8995
+ " ",
8996
+ t("common.selected") || "selected"
8997
+ ] })
8998
+ ] }),
8999
+ /* @__PURE__ */ jsx(
9000
+ Box,
9001
+ {
9002
+ className: cn("grid", gapStyles5[gap], colsClass, className),
9003
+ style: gridTemplateColumns ? { gridTemplateColumns } : void 0,
9004
+ children: data.map((item, index) => {
9005
+ const itemData = item;
9006
+ const id = itemData.id || String(index);
9007
+ const titleValue = getNestedValue(itemData, titleField?.name ?? "");
9008
+ const isSelected = selectedIds.has(id);
9009
+ return /* @__PURE__ */ jsxs(
9010
+ Box,
9011
+ {
9012
+ "data-entity-row": true,
9013
+ className: cn(
9014
+ "bg-[var(--color-card)] rounded-[var(--radius-lg)]",
9015
+ "border border-[var(--color-border)]",
9016
+ "shadow-[var(--shadow-sm)] hover:shadow-[var(--shadow-hover)]",
9017
+ "hover:border-[var(--color-primary)] transition-all",
9018
+ "flex flex-col",
9019
+ isSelected && "ring-2 ring-[var(--color-primary)] border-[var(--color-primary)]"
9020
+ ),
9021
+ children: [
9022
+ imageField && (() => {
9023
+ const imgUrl = getNestedValue(itemData, imageField);
9024
+ if (!imgUrl || typeof imgUrl !== "string") return null;
9025
+ return /* @__PURE__ */ jsx(Box, { className: "w-full aspect-video overflow-hidden rounded-t-[var(--radius-lg)]", children: /* @__PURE__ */ jsx(
9026
+ "img",
9027
+ {
9028
+ src: imgUrl,
9029
+ alt: titleValue !== void 0 ? String(titleValue) : "",
9030
+ className: "w-full h-full object-cover",
9031
+ loading: "lazy"
9032
+ }
9033
+ ) });
9034
+ })(),
9035
+ /* @__PURE__ */ jsx(Box, { className: "p-4 pb-0", children: /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
9036
+ selectable && /* @__PURE__ */ jsx(
9037
+ "input",
9038
+ {
9039
+ type: "checkbox",
9040
+ checked: isSelected,
9041
+ onChange: () => toggleSelection(id),
9042
+ onClick: (e) => e.stopPropagation(),
9043
+ className: "w-4 h-4 mt-1 flex-shrink-0 accent-[var(--color-primary)]",
9044
+ "aria-label": `Select ${titleValue !== void 0 ? String(titleValue) : "item"}`
9045
+ }
9046
+ ),
9047
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
9048
+ titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
9049
+ titleField?.icon && /* @__PURE__ */ jsx(Icon, { name: titleField.icon, size: "sm", className: "text-[var(--color-primary)] flex-shrink-0" }),
9050
+ /* @__PURE__ */ jsx(
9051
+ Typography,
9052
+ {
9053
+ variant: titleField?.variant === "h3" ? "h3" : "h4",
9054
+ className: "font-semibold truncate",
9055
+ children: String(titleValue)
9056
+ }
9057
+ )
9058
+ ] }),
9059
+ badgeFields.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap", children: badgeFields.map((field) => {
9060
+ const val = getNestedValue(itemData, field.name);
9061
+ if (val === void 0 || val === null) return null;
9062
+ return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
9063
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
9064
+ /* @__PURE__ */ jsx(Badge, { variant: statusVariant(String(val)), children: String(val) })
9065
+ ] }, field.name);
9066
+ }) })
9067
+ ] }),
9068
+ dangerActions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: dangerActions.map((action, idx) => /* @__PURE__ */ jsxs(
9069
+ Button,
9070
+ {
9071
+ variant: "ghost",
9072
+ size: "sm",
9073
+ onClick: handleActionClick(action, itemData),
9074
+ "data-testid": `action-${action.event}`,
9075
+ className: "text-[var(--color-error)] hover:bg-[var(--color-error)]/10 px-2",
9076
+ children: [
9077
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs" }),
9078
+ action.label
9079
+ ]
9080
+ },
9081
+ idx
9082
+ )) })
9083
+ ] }) }),
9084
+ bodyFields.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 flex-1", children: /* @__PURE__ */ jsx(VStack, { gap: "xs", children: bodyFields.map((field) => {
9085
+ const value = getNestedValue(itemData, field.name);
9086
+ if (value === void 0 || value === null || value === "") return null;
9087
+ if (field.format === "boolean") {
9088
+ return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
9089
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
9090
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
9091
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel(field.name) })
9092
+ ] }),
9093
+ /* @__PURE__ */ jsx(Badge, { variant: value ? "success" : "neutral", children: value ? t("common.yes") || "Yes" : t("common.no") || "No" })
7686
9094
  ] }, field.name);
7687
- }) })
7688
- ] }),
7689
- dangerActions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: dangerActions.map((action, idx) => /* @__PURE__ */ jsxs(
9095
+ }
9096
+ return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
9097
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
9098
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
9099
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel(field.name) })
9100
+ ] }),
9101
+ /* @__PURE__ */ jsx(
9102
+ Typography,
9103
+ {
9104
+ variant: field.variant === "caption" ? "caption" : "small",
9105
+ className: "text-right truncate max-w-[60%]",
9106
+ children: formatValue(value, field.format)
9107
+ }
9108
+ )
9109
+ ] }, field.name);
9110
+ }) }) }),
9111
+ 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(
7690
9112
  Button,
7691
9113
  {
7692
- variant: "ghost",
9114
+ variant: action.variant === "primary" ? "primary" : "ghost",
7693
9115
  size: "sm",
7694
9116
  onClick: handleActionClick(action, itemData),
7695
9117
  "data-testid": `action-${action.event}`,
7696
- className: "text-[var(--color-error)] hover:bg-[var(--color-error)]/10 px-2",
7697
9118
  children: [
7698
- action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs" }),
9119
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
7699
9120
  action.label
7700
9121
  ]
7701
9122
  },
7702
9123
  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);
7716
- }
7717
- return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
7718
- /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
7719
- field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
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,
7734
- {
7735
- variant: action.variant === "primary" ? "primary" : "ghost",
7736
- size: "sm",
7737
- onClick: handleActionClick(action, itemData),
7738
- "data-testid": `action-${action.event}`,
7739
- children: [
7740
- action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
7741
- action.label
7742
- ]
7743
- },
7744
- idx
7745
- )) }) })
7746
- ]
7747
- },
7748
- id
7749
- );
7750
- })
7751
- }
7752
- );
9124
+ )) }) })
9125
+ ]
9126
+ },
9127
+ id
9128
+ );
9129
+ })
9130
+ }
9131
+ ),
9132
+ infiniteScroll && loadMoreEvent && /* @__PURE__ */ jsx(
9133
+ InfiniteScrollSentinel,
9134
+ {
9135
+ loadMoreEvent,
9136
+ isLoading,
9137
+ hasMore
9138
+ }
9139
+ )
9140
+ ] });
7753
9141
  };
7754
9142
  DataGrid.displayName = "DataGrid";
7755
9143
  function fieldLabel2(key) {
@@ -7786,6 +9174,16 @@ function formatValue2(value, format) {
7786
9174
  return String(value);
7787
9175
  }
7788
9176
  }
9177
+ function groupData(items, field) {
9178
+ const groups = /* @__PURE__ */ new Map();
9179
+ for (const item of items) {
9180
+ const key = String(getNestedValue(item, field) ?? "");
9181
+ const group = groups.get(key);
9182
+ if (group) group.push(item);
9183
+ else groups.set(key, [item]);
9184
+ }
9185
+ return Array.from(groups.entries()).map(([label, groupItems]) => ({ label, items: groupItems }));
9186
+ }
7789
9187
  var DataList = ({
7790
9188
  entity,
7791
9189
  fields: fieldsProp,
@@ -7793,9 +9191,25 @@ var DataList = ({
7793
9191
  itemActions,
7794
9192
  gap = "none",
7795
9193
  variant = "default",
9194
+ groupBy,
9195
+ senderField,
9196
+ currentUser,
7796
9197
  className,
7797
9198
  isLoading = false,
7798
- error = null
9199
+ error = null,
9200
+ // Gesture props: reorderable, swipeLeftEvent, swipeRightEvent, longPressEvent
9201
+ // are consumed by the compiler to wrap items in SwipeableRow/SortableList.
9202
+ // DataList destructures them here to prevent DOM passthrough.
9203
+ reorderable: _reorderable,
9204
+ reorderEvent: _reorderEvent,
9205
+ swipeLeftEvent: _swipeLeftEvent,
9206
+ swipeLeftActions: _swipeLeftActions,
9207
+ swipeRightEvent: _swipeRightEvent,
9208
+ swipeRightActions: _swipeRightActions,
9209
+ longPressEvent: _longPressEvent,
9210
+ infiniteScroll,
9211
+ loadMoreEvent,
9212
+ hasMore
7799
9213
  }) => {
7800
9214
  const eventBus = useEventBus();
7801
9215
  const { t } = useTranslate();
@@ -7828,118 +9242,783 @@ var DataList = ({
7828
9242
  }[gap];
7829
9243
  const isCard = variant === "card";
7830
9244
  const isCompact = variant === "compact";
7831
- return /* @__PURE__ */ jsx(
9245
+ const isMessage = variant === "message";
9246
+ if (isMessage) {
9247
+ const items2 = data.map((item) => item);
9248
+ const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
9249
+ const contentField = titleField?.name ?? fields[0]?.name ?? "";
9250
+ return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React68__default.Fragment, { children: [
9251
+ group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
9252
+ group.items.map((itemData, index) => {
9253
+ const id = itemData.id || `${gi}-${index}`;
9254
+ const sender = senderField ? String(getNestedValue(itemData, senderField) ?? "") : "";
9255
+ const isSent = Boolean(currentUser && sender === currentUser);
9256
+ const content = getNestedValue(itemData, contentField);
9257
+ const timestampField = fields.find((f) => f.format === "date");
9258
+ const timestamp = timestampField ? getNestedValue(itemData, timestampField.name) : null;
9259
+ return /* @__PURE__ */ jsx(
9260
+ Box,
9261
+ {
9262
+ className: cn(
9263
+ "flex px-4",
9264
+ isSent ? "justify-end" : "justify-start"
9265
+ ),
9266
+ children: /* @__PURE__ */ jsxs(
9267
+ Box,
9268
+ {
9269
+ className: cn(
9270
+ "max-w-[75%] px-4 py-2",
9271
+ 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"
9272
+ ),
9273
+ children: [
9274
+ !isSent && senderField && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "font-semibold mb-0.5", children: sender }),
9275
+ /* @__PURE__ */ jsx(Typography, { variant: "body", children: content !== void 0 && content !== null ? String(content) : "" }),
9276
+ timestamp != null ? /* @__PURE__ */ jsx(
9277
+ Typography,
9278
+ {
9279
+ variant: "caption",
9280
+ className: cn(
9281
+ "mt-1 text-[0.65rem]",
9282
+ isSent ? "opacity-70" : "text-[var(--color-muted-foreground)]"
9283
+ ),
9284
+ children: formatDate2(timestamp)
9285
+ }
9286
+ ) : null
9287
+ ]
9288
+ }
9289
+ )
9290
+ },
9291
+ id
9292
+ );
9293
+ })
9294
+ ] }, gi)) });
9295
+ }
9296
+ const items = data.map((item) => item);
9297
+ const groups = groupBy ? groupData(items, groupBy) : [{ label: "", items }];
9298
+ const renderItem = (itemData, index, isLast) => {
9299
+ const id = itemData.id || String(index);
9300
+ const titleValue = getNestedValue(itemData, titleField?.name ?? "");
9301
+ return /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, children: [
9302
+ /* @__PURE__ */ jsxs(
9303
+ Box,
9304
+ {
9305
+ className: cn(
9306
+ "group flex items-center gap-4 transition-all duration-200",
9307
+ isCompact ? "px-4 py-2" : "px-6 py-4",
9308
+ "hover:bg-[var(--color-muted)]/80",
9309
+ !isCard && !isCompact && "rounded-[var(--radius-lg)] border border-transparent hover:border-[var(--color-border)]"
9310
+ ),
9311
+ children: [
9312
+ /* @__PURE__ */ jsxs(Box, { className: "flex-1 min-w-0", children: [
9313
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
9314
+ titleField?.icon && /* @__PURE__ */ jsx(
9315
+ Icon,
9316
+ {
9317
+ name: titleField.icon,
9318
+ size: isCompact ? "xs" : "sm",
9319
+ className: "text-[var(--color-primary)] flex-shrink-0"
9320
+ }
9321
+ ),
9322
+ titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsx(
9323
+ Typography,
9324
+ {
9325
+ variant: titleField?.variant === "h3" ? "h3" : "h4",
9326
+ className: cn("font-semibold truncate flex-1", isCompact && "text-sm"),
9327
+ children: String(titleValue)
9328
+ }
9329
+ ),
9330
+ badgeFields.map((field) => {
9331
+ const val = getNestedValue(itemData, field.name);
9332
+ if (val === void 0 || val === null) return null;
9333
+ return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center flex-shrink-0", children: [
9334
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
9335
+ /* @__PURE__ */ jsx(Badge, { variant: statusVariant2(String(val)), children: String(val) })
9336
+ ] }, field.name);
9337
+ })
9338
+ ] }),
9339
+ bodyFields.length > 0 && !isCompact && /* @__PURE__ */ jsx(HStack, { gap: "md", className: "mt-1.5 flex-wrap", children: bodyFields.map((field) => {
9340
+ const value = getNestedValue(itemData, field.name);
9341
+ if (value === void 0 || value === null || value === "") return null;
9342
+ return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
9343
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
9344
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "secondary", children: [
9345
+ field.label ?? fieldLabel2(field.name),
9346
+ ":"
9347
+ ] }),
9348
+ /* @__PURE__ */ jsx(Typography, { variant: "small", children: formatValue2(value, field.format) })
9349
+ ] }, field.name);
9350
+ }) }),
9351
+ progressFields.map((field) => {
9352
+ const value = getNestedValue(itemData, field.name);
9353
+ if (typeof value !== "number") return null;
9354
+ return /* @__PURE__ */ jsxs(Box, { className: "mt-2 max-w-xs", children: [
9355
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center mb-1", children: [
9356
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
9357
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
9358
+ ] }),
9359
+ /* @__PURE__ */ jsx(ProgressBar, { value, max: 100 })
9360
+ ] }, field.name);
9361
+ })
9362
+ ] }),
9363
+ itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(
9364
+ HStack,
9365
+ {
9366
+ gap: "xs",
9367
+ className: cn(
9368
+ "flex-shrink-0 transition-opacity duration-200",
9369
+ "opacity-0 group-hover:opacity-100"
9370
+ ),
9371
+ children: itemActions.map((action, idx) => /* @__PURE__ */ jsxs(
9372
+ Button,
9373
+ {
9374
+ variant: action.variant ?? "ghost",
9375
+ size: "sm",
9376
+ onClick: handleActionClick(action, itemData),
9377
+ "data-testid": `action-${action.event}`,
9378
+ className: cn(
9379
+ action.variant === "danger" && "text-[var(--color-error)] hover:bg-[var(--color-error)]/10"
9380
+ ),
9381
+ children: [
9382
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
9383
+ action.label
9384
+ ]
9385
+ },
9386
+ idx
9387
+ ))
9388
+ }
9389
+ )
9390
+ ]
9391
+ }
9392
+ ),
9393
+ isCard && !isLast && /* @__PURE__ */ jsx(Box, { className: "mx-6 border-b border-[var(--color-border)]/40" })
9394
+ ] }, id);
9395
+ };
9396
+ return /* @__PURE__ */ jsxs(
9397
+ Box,
9398
+ {
9399
+ className: cn(
9400
+ isCard && "bg-[var(--color-card)] rounded-[var(--radius-xl)] border border-[var(--color-border)] shadow-[var(--shadow-lg)] overflow-hidden",
9401
+ !isCard && gapClass,
9402
+ className
9403
+ ),
9404
+ children: [
9405
+ groups.map((group, gi) => /* @__PURE__ */ jsxs(React68__default.Fragment, { children: [
9406
+ group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
9407
+ group.items.map(
9408
+ (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
9409
+ )
9410
+ ] }, gi)),
9411
+ infiniteScroll && loadMoreEvent && /* @__PURE__ */ jsx(
9412
+ InfiniteScrollSentinel,
9413
+ {
9414
+ loadMoreEvent,
9415
+ isLoading,
9416
+ hasMore
9417
+ }
9418
+ )
9419
+ ]
9420
+ }
9421
+ );
9422
+ };
9423
+ DataList.displayName = "DataList";
9424
+ function useSafeEventBus8() {
9425
+ try {
9426
+ return useEventBus();
9427
+ } catch {
9428
+ return { emit: () => {
9429
+ }, on: () => () => {
9430
+ }, once: () => {
9431
+ } };
9432
+ }
9433
+ }
9434
+ var SwipeableRow = ({
9435
+ leftActions = [],
9436
+ rightActions = [],
9437
+ threshold = 80,
9438
+ children,
9439
+ itemData,
9440
+ className
9441
+ }) => {
9442
+ const eventBus = useSafeEventBus8();
9443
+ const [revealState, setRevealState] = useState("closed");
9444
+ const [offsetX, setOffsetX] = useState(0);
9445
+ const [isSwiping, setIsSwiping] = useState(false);
9446
+ const startXRef = useRef(0);
9447
+ const startYRef = useRef(0);
9448
+ const trackingRef = useRef(false);
9449
+ const lockedAxisRef = useRef(null);
9450
+ const actionsWidth = threshold;
9451
+ const handleActionClick = useCallback(
9452
+ (action) => {
9453
+ eventBus.emit(`UI:${action.event}`, {
9454
+ ...action.eventPayload,
9455
+ row: itemData
9456
+ });
9457
+ setRevealState("closed");
9458
+ setOffsetX(0);
9459
+ },
9460
+ [eventBus, itemData]
9461
+ );
9462
+ const handlePointerDown = useCallback(
9463
+ (e) => {
9464
+ if (e.button !== 0) return;
9465
+ startXRef.current = e.clientX;
9466
+ startYRef.current = e.clientY;
9467
+ trackingRef.current = true;
9468
+ lockedAxisRef.current = null;
9469
+ setIsSwiping(false);
9470
+ e.currentTarget.setPointerCapture(e.pointerId);
9471
+ },
9472
+ []
9473
+ );
9474
+ const handlePointerMove = useCallback(
9475
+ (e) => {
9476
+ if (!trackingRef.current) return;
9477
+ const dx = e.clientX - startXRef.current;
9478
+ const dy = e.clientY - startYRef.current;
9479
+ if (lockedAxisRef.current === null && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {
9480
+ lockedAxisRef.current = Math.abs(dx) > Math.abs(dy) ? "horizontal" : "vertical";
9481
+ }
9482
+ if (lockedAxisRef.current !== "horizontal") return;
9483
+ setIsSwiping(true);
9484
+ let newOffset = dx;
9485
+ if (revealState === "left") {
9486
+ newOffset = actionsWidth + dx;
9487
+ } else if (revealState === "right") {
9488
+ newOffset = -actionsWidth + dx;
9489
+ }
9490
+ const maxLeft = leftActions.length > 0 ? actionsWidth : 0;
9491
+ const maxRight = rightActions.length > 0 ? actionsWidth : 0;
9492
+ const clamped = Math.max(-maxRight, Math.min(maxLeft, newOffset));
9493
+ setOffsetX(clamped);
9494
+ },
9495
+ [revealState, actionsWidth, leftActions.length, rightActions.length]
9496
+ );
9497
+ const handlePointerUp = useCallback(
9498
+ () => {
9499
+ trackingRef.current = false;
9500
+ if (!isSwiping) {
9501
+ if (revealState !== "closed") {
9502
+ setRevealState("closed");
9503
+ setOffsetX(0);
9504
+ }
9505
+ setIsSwiping(false);
9506
+ return;
9507
+ }
9508
+ setIsSwiping(false);
9509
+ if (offsetX > threshold / 2 && leftActions.length > 0) {
9510
+ setRevealState("right");
9511
+ setOffsetX(actionsWidth);
9512
+ } else if (offsetX < -(threshold / 2) && rightActions.length > 0) {
9513
+ setRevealState("left");
9514
+ setOffsetX(-actionsWidth);
9515
+ } else {
9516
+ setRevealState("closed");
9517
+ setOffsetX(0);
9518
+ }
9519
+ },
9520
+ [isSwiping, offsetX, threshold, leftActions.length, rightActions.length, actionsWidth, revealState]
9521
+ );
9522
+ const handlePointerCancel = useCallback(() => {
9523
+ trackingRef.current = false;
9524
+ setIsSwiping(false);
9525
+ setRevealState("closed");
9526
+ setOffsetX(0);
9527
+ }, []);
9528
+ const renderActions = (actions, side) => {
9529
+ if (actions.length === 0) return null;
9530
+ return /* @__PURE__ */ jsx(
9531
+ HStack,
9532
+ {
9533
+ gap: "xs",
9534
+ align: "stretch",
9535
+ className: cn(
9536
+ "absolute top-0 bottom-0",
9537
+ side === "left" ? "left-0" : "right-0"
9538
+ ),
9539
+ style: {
9540
+ width: `${actionsWidth}px`
9541
+ },
9542
+ children: actions.map((action, idx) => /* @__PURE__ */ jsxs(
9543
+ Button,
9544
+ {
9545
+ variant: action.variant ?? "secondary",
9546
+ size: "sm",
9547
+ icon: action.icon,
9548
+ onClick: () => handleActionClick(action),
9549
+ className: "flex-1 rounded-none h-full",
9550
+ children: [
9551
+ action.icon ? /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "sm" }) : null,
9552
+ action.label
9553
+ ]
9554
+ },
9555
+ `${action.event}-${idx}`
9556
+ ))
9557
+ }
9558
+ );
9559
+ };
9560
+ return /* @__PURE__ */ jsxs(
7832
9561
  Box,
7833
9562
  {
9563
+ overflow: "hidden",
9564
+ position: "relative",
7834
9565
  className: cn(
7835
- isCard && "bg-[var(--color-card)] rounded-[var(--radius-xl)] border border-[var(--color-border)] shadow-[var(--shadow-lg)] overflow-hidden",
7836
- !isCard && gapClass,
9566
+ "touch-pan-y",
7837
9567
  className
7838
9568
  ),
7839
- children: data.map((item, index) => {
7840
- const itemData = item;
7841
- const id = itemData.id || String(index);
7842
- const titleValue = getNestedValue(itemData, titleField?.name ?? "");
7843
- const isLast = index === data.length - 1;
7844
- return /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, children: [
7845
- /* @__PURE__ */ jsxs(
9569
+ children: [
9570
+ renderActions(leftActions, "left"),
9571
+ renderActions(rightActions, "right"),
9572
+ /* @__PURE__ */ jsx(
9573
+ Box,
9574
+ {
9575
+ style: {
9576
+ transform: `translateX(${offsetX}px)`,
9577
+ transition: isSwiping ? "none" : "transform 200ms ease-out"
9578
+ },
9579
+ className: cn(
9580
+ "relative bg-[var(--color-surface)]",
9581
+ "select-none"
9582
+ ),
9583
+ onPointerDown: handlePointerDown,
9584
+ onPointerMove: handlePointerMove,
9585
+ onPointerUp: handlePointerUp,
9586
+ onPointerCancel: handlePointerCancel,
9587
+ children
9588
+ }
9589
+ )
9590
+ ]
9591
+ }
9592
+ );
9593
+ };
9594
+ SwipeableRow.displayName = "SwipeableRow";
9595
+ function useSafeEventBus9() {
9596
+ try {
9597
+ return useEventBus();
9598
+ } catch {
9599
+ return { emit: () => {
9600
+ }, on: () => () => {
9601
+ }, once: () => {
9602
+ } };
9603
+ }
9604
+ }
9605
+ function SortableListInner({
9606
+ items: initialItems,
9607
+ renderItem,
9608
+ reorderEvent,
9609
+ reorderPayload,
9610
+ dragHandlePosition = "left",
9611
+ className
9612
+ }) {
9613
+ const eventBus = useSafeEventBus9();
9614
+ const handleReorder = useCallback(
9615
+ (fromIndex, toIndex, item) => {
9616
+ eventBus.emit(`UI:${reorderEvent}`, {
9617
+ fromIndex,
9618
+ toIndex,
9619
+ item,
9620
+ ...reorderPayload
9621
+ });
9622
+ },
9623
+ [eventBus, reorderEvent, reorderPayload]
9624
+ );
9625
+ const {
9626
+ items,
9627
+ dragIndex,
9628
+ dragOverIndex,
9629
+ isDragging,
9630
+ getDragHandleProps,
9631
+ getItemProps
9632
+ } = useDragReorder(initialItems, handleReorder);
9633
+ return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: items.map((item, index) => {
9634
+ const { "aria-dropeffect": ariaDropEffect, ...itemProps } = getItemProps(index);
9635
+ const { "aria-grabbed": ariaGrabbed, ...handleRest } = getDragHandleProps(index);
9636
+ const isBeingDragged = dragIndex === index;
9637
+ const showDropIndicator = isDragging && dragOverIndex === index && dragOverIndex !== dragIndex;
9638
+ const dragHandle = /* @__PURE__ */ jsx(
9639
+ Box,
9640
+ {
9641
+ className: cn(
9642
+ "flex items-center justify-center",
9643
+ "text-[var(--color-muted-foreground)]",
9644
+ "hover:text-[var(--color-foreground)]",
9645
+ "transition-colors duration-100",
9646
+ "px-1"
9647
+ ),
9648
+ "aria-grabbed": ariaGrabbed,
9649
+ ...handleRest,
9650
+ children: /* @__PURE__ */ jsx(Icon, { name: "grip-vertical", size: "sm" })
9651
+ }
9652
+ );
9653
+ return /* @__PURE__ */ jsxs(
9654
+ Box,
9655
+ {
9656
+ "aria-dropeffect": ariaDropEffect,
9657
+ ...itemProps,
9658
+ children: [
9659
+ showDropIndicator && /* @__PURE__ */ jsx(
7846
9660
  Box,
7847
9661
  {
9662
+ className: "h-0.5 bg-[var(--color-primary)] rounded-full",
9663
+ style: { margin: "0 8px" }
9664
+ }
9665
+ ),
9666
+ /* @__PURE__ */ jsxs(
9667
+ HStack,
9668
+ {
9669
+ gap: "sm",
9670
+ align: "center",
7848
9671
  className: cn(
7849
- "group flex items-center gap-4 transition-all duration-200",
7850
- isCompact ? "px-4 py-2" : "px-6 py-4",
7851
- "hover:bg-[var(--color-muted)]/80",
7852
- !isCard && !isCompact && "rounded-[var(--radius-lg)] border border-transparent hover:border-[var(--color-border)]"
9672
+ "transition-opacity duration-150",
9673
+ isBeingDragged && "opacity-50"
7853
9674
  ),
7854
9675
  children: [
7855
- /* @__PURE__ */ jsxs(Box, { className: "flex-1 min-w-0", children: [
7856
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
7857
- titleField?.icon && /* @__PURE__ */ jsx(
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
- )
9676
+ dragHandlePosition === "left" && dragHandle,
9677
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 min-w-0", children: renderItem(item, index) }),
9678
+ dragHandlePosition === "right" && dragHandle
7933
9679
  ]
7934
9680
  }
7935
- ),
7936
- isCard && !isLast && /* @__PURE__ */ jsx(Box, { className: "mx-6 border-b border-[var(--color-border)]/40" })
7937
- ] }, id);
7938
- })
7939
- }
9681
+ )
9682
+ ]
9683
+ },
9684
+ index
9685
+ );
9686
+ }) });
9687
+ }
9688
+ var SortableList = SortableListInner;
9689
+ SortableList.displayName = "SortableList";
9690
+ function useSafeEventBus10() {
9691
+ try {
9692
+ return useEventBus();
9693
+ } catch {
9694
+ return { emit: () => {
9695
+ }, on: () => () => {
9696
+ }, once: () => {
9697
+ } };
9698
+ }
9699
+ }
9700
+ var Carousel = ({
9701
+ items,
9702
+ renderItem,
9703
+ autoPlay = false,
9704
+ autoPlayInterval = 5e3,
9705
+ showDots = true,
9706
+ showArrows = true,
9707
+ loop = false,
9708
+ slideChangeEvent,
9709
+ slideChangePayload,
9710
+ className
9711
+ }) => {
9712
+ const [activeIndex, setActiveIndex] = useState(0);
9713
+ const scrollRef = useRef(null);
9714
+ const autoPlayRef = useRef(null);
9715
+ const eventBus = useSafeEventBus10();
9716
+ const totalSlides = items.length;
9717
+ const emitSlideChange = useCallback(
9718
+ (newIndex) => {
9719
+ if (slideChangeEvent) {
9720
+ eventBus.emit(`UI:${slideChangeEvent}`, {
9721
+ index: newIndex,
9722
+ ...slideChangePayload
9723
+ });
9724
+ }
9725
+ },
9726
+ [slideChangeEvent, slideChangePayload, eventBus]
9727
+ );
9728
+ const scrollToSlide = useCallback(
9729
+ (index) => {
9730
+ const container = scrollRef.current;
9731
+ if (!container) return;
9732
+ const slideWidth = container.offsetWidth;
9733
+ container.scrollTo({
9734
+ left: slideWidth * index,
9735
+ behavior: "smooth"
9736
+ });
9737
+ },
9738
+ []
9739
+ );
9740
+ const goToSlide = useCallback(
9741
+ (index) => {
9742
+ let targetIndex = index;
9743
+ if (loop) {
9744
+ if (targetIndex < 0) targetIndex = totalSlides - 1;
9745
+ if (targetIndex >= totalSlides) targetIndex = 0;
9746
+ } else {
9747
+ targetIndex = Math.max(0, Math.min(totalSlides - 1, targetIndex));
9748
+ }
9749
+ setActiveIndex(targetIndex);
9750
+ scrollToSlide(targetIndex);
9751
+ emitSlideChange(targetIndex);
9752
+ },
9753
+ [loop, totalSlides, scrollToSlide, emitSlideChange]
9754
+ );
9755
+ const goNext = useCallback(() => {
9756
+ goToSlide(activeIndex + 1);
9757
+ }, [goToSlide, activeIndex]);
9758
+ const goPrev = useCallback(() => {
9759
+ goToSlide(activeIndex - 1);
9760
+ }, [goToSlide, activeIndex]);
9761
+ const swipeHandlers = useSwipeGesture(
9762
+ {
9763
+ onSwipeLeft: goNext,
9764
+ onSwipeRight: goPrev
9765
+ },
9766
+ { threshold: 40 }
7940
9767
  );
9768
+ useEffect(() => {
9769
+ if (!autoPlay || totalSlides <= 1) return;
9770
+ autoPlayRef.current = setInterval(() => {
9771
+ setActiveIndex((prev) => {
9772
+ const next = loop ? (prev + 1) % totalSlides : Math.min(prev + 1, totalSlides - 1);
9773
+ setTimeout(() => {
9774
+ scrollToSlide(next);
9775
+ emitSlideChange(next);
9776
+ }, 0);
9777
+ return next;
9778
+ });
9779
+ }, autoPlayInterval);
9780
+ return () => {
9781
+ if (autoPlayRef.current) {
9782
+ clearInterval(autoPlayRef.current);
9783
+ autoPlayRef.current = null;
9784
+ }
9785
+ };
9786
+ }, [autoPlay, autoPlayInterval, loop, totalSlides, scrollToSlide, emitSlideChange]);
9787
+ const handleScroll = useCallback(() => {
9788
+ const container = scrollRef.current;
9789
+ if (!container) return;
9790
+ const slideWidth = container.offsetWidth;
9791
+ if (slideWidth === 0) return;
9792
+ const newIndex = Math.round(container.scrollLeft / slideWidth);
9793
+ setActiveIndex((prev) => {
9794
+ if (prev !== newIndex && newIndex >= 0 && newIndex < totalSlides) {
9795
+ return newIndex;
9796
+ }
9797
+ return prev;
9798
+ });
9799
+ }, [totalSlides]);
9800
+ const hasPrev = loop || activeIndex > 0;
9801
+ const hasNext = loop || activeIndex < totalSlides - 1;
9802
+ if (totalSlides === 0) return null;
9803
+ return /* @__PURE__ */ jsxs(Box, { position: "relative", overflow: "hidden", className: cn("w-full", className), children: [
9804
+ /* @__PURE__ */ jsx(
9805
+ Box,
9806
+ {
9807
+ ref: scrollRef,
9808
+ display: "flex",
9809
+ overflow: "auto",
9810
+ className: cn(
9811
+ "w-full",
9812
+ "scroll-smooth",
9813
+ "scrollbar-none",
9814
+ "[scroll-snap-type:x_mandatory]",
9815
+ "[&::-webkit-scrollbar]:hidden",
9816
+ "[-ms-overflow-style:none]"
9817
+ ),
9818
+ style: {
9819
+ scrollSnapType: "x mandatory",
9820
+ WebkitOverflowScrolling: "touch"
9821
+ },
9822
+ onScroll: handleScroll,
9823
+ onPointerDown: swipeHandlers.onPointerDown,
9824
+ onPointerMove: swipeHandlers.onPointerMove,
9825
+ onPointerUp: swipeHandlers.onPointerUp,
9826
+ onPointerCancel: swipeHandlers.onPointerCancel,
9827
+ children: items.map((item, index) => /* @__PURE__ */ jsx(
9828
+ Box,
9829
+ {
9830
+ className: cn(
9831
+ "flex-shrink-0 w-full",
9832
+ "[scroll-snap-align:start]"
9833
+ ),
9834
+ style: {
9835
+ scrollSnapAlign: "start"
9836
+ },
9837
+ children: renderItem(item, index)
9838
+ },
9839
+ index
9840
+ ))
9841
+ }
9842
+ ),
9843
+ showArrows && hasPrev && totalSlides > 1 && /* @__PURE__ */ jsx(
9844
+ Box,
9845
+ {
9846
+ position: "absolute",
9847
+ className: "left-2 top-1/2 -translate-y-1/2 z-10",
9848
+ children: /* @__PURE__ */ jsx(
9849
+ Button,
9850
+ {
9851
+ variant: "ghost",
9852
+ size: "sm",
9853
+ onClick: goPrev,
9854
+ "aria-label": "Previous slide",
9855
+ className: cn(
9856
+ "rounded-full",
9857
+ "bg-[var(--color-surface)]/80",
9858
+ "backdrop-blur-sm",
9859
+ "shadow-[var(--shadow-sm)]",
9860
+ "hover:bg-[var(--color-surface)]"
9861
+ ),
9862
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "w-5 h-5" })
9863
+ }
9864
+ )
9865
+ }
9866
+ ),
9867
+ showArrows && hasNext && totalSlides > 1 && /* @__PURE__ */ jsx(
9868
+ Box,
9869
+ {
9870
+ position: "absolute",
9871
+ className: "right-2 top-1/2 -translate-y-1/2 z-10",
9872
+ children: /* @__PURE__ */ jsx(
9873
+ Button,
9874
+ {
9875
+ variant: "ghost",
9876
+ size: "sm",
9877
+ onClick: goNext,
9878
+ "aria-label": "Next slide",
9879
+ className: cn(
9880
+ "rounded-full",
9881
+ "bg-[var(--color-surface)]/80",
9882
+ "backdrop-blur-sm",
9883
+ "shadow-[var(--shadow-sm)]",
9884
+ "hover:bg-[var(--color-surface)]"
9885
+ ),
9886
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "w-5 h-5" })
9887
+ }
9888
+ )
9889
+ }
9890
+ ),
9891
+ showDots && totalSlides > 1 && /* @__PURE__ */ jsx(
9892
+ Box,
9893
+ {
9894
+ position: "absolute",
9895
+ className: "bottom-3 left-0 right-0 z-10",
9896
+ children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", justify: "center", children: items.map((_, index) => {
9897
+ const isActive = index === activeIndex;
9898
+ return /* @__PURE__ */ jsx(
9899
+ Box,
9900
+ {
9901
+ className: cn(
9902
+ "rounded-full cursor-pointer transition-all duration-200"
9903
+ ),
9904
+ style: {
9905
+ width: isActive ? 10 : 8,
9906
+ height: isActive ? 10 : 8,
9907
+ backgroundColor: isActive ? "var(--color-primary)" : "var(--color-muted, #d4d4d8)",
9908
+ opacity: isActive ? 1 : 0.6
9909
+ },
9910
+ onClick: () => goToSlide(index),
9911
+ role: "button",
9912
+ "aria-label": `Go to slide ${index + 1}`
9913
+ },
9914
+ index
9915
+ );
9916
+ }) })
9917
+ }
9918
+ )
9919
+ ] });
7941
9920
  };
7942
- DataList.displayName = "DataList";
9921
+ Carousel.displayName = "Carousel";
9922
+ function useSafeEventBus11() {
9923
+ try {
9924
+ return useEventBus();
9925
+ } catch {
9926
+ return { emit: () => {
9927
+ }, on: () => () => {
9928
+ }, once: () => {
9929
+ } };
9930
+ }
9931
+ }
9932
+ var SAFETY_TIMEOUT_MS = 5e3;
9933
+ var PullToRefresh = ({
9934
+ refreshEvent,
9935
+ refreshPayload,
9936
+ threshold = 60,
9937
+ children,
9938
+ className
9939
+ }) => {
9940
+ const eventBus = useSafeEventBus11();
9941
+ const safetyTimerRef = useRef(null);
9942
+ const handleRefresh = useCallback(() => {
9943
+ eventBus.emit(`UI:${refreshEvent}`, refreshPayload ?? {});
9944
+ }, [eventBus, refreshEvent, refreshPayload]);
9945
+ const { pullDistance, isPulling, isRefreshing, containerProps, endRefresh } = usePullToRefresh(handleRefresh, { threshold });
9946
+ useEffect(() => {
9947
+ if (isRefreshing) {
9948
+ safetyTimerRef.current = setTimeout(() => {
9949
+ endRefresh();
9950
+ }, SAFETY_TIMEOUT_MS);
9951
+ return () => {
9952
+ if (safetyTimerRef.current) {
9953
+ clearTimeout(safetyTimerRef.current);
9954
+ safetyTimerRef.current = null;
9955
+ }
9956
+ };
9957
+ }
9958
+ }, [isRefreshing, endRefresh]);
9959
+ useEffect(() => {
9960
+ return () => {
9961
+ if (safetyTimerRef.current) {
9962
+ clearTimeout(safetyTimerRef.current);
9963
+ }
9964
+ };
9965
+ }, []);
9966
+ const pullProgress = Math.min(pullDistance / threshold, 1);
9967
+ const showIndicator = pullDistance > 0 || isRefreshing;
9968
+ return /* @__PURE__ */ jsxs(Box, { position: "relative", overflow: "hidden", className: cn("w-full", className), children: [
9969
+ /* @__PURE__ */ jsx(
9970
+ Box,
9971
+ {
9972
+ position: "absolute",
9973
+ display: "flex",
9974
+ className: cn(
9975
+ "top-0 left-0 right-0 z-10",
9976
+ "items-center justify-center",
9977
+ "transition-opacity duration-200",
9978
+ showIndicator ? "opacity-100" : "opacity-0"
9979
+ ),
9980
+ style: {
9981
+ height: threshold,
9982
+ transform: `translateY(${showIndicator ? 0 : -threshold}px)`,
9983
+ pointerEvents: "none"
9984
+ },
9985
+ children: /* @__PURE__ */ jsx(
9986
+ Box,
9987
+ {
9988
+ className: "transition-transform duration-150",
9989
+ style: {
9990
+ transform: `scale(${isRefreshing ? 1 : pullProgress})`,
9991
+ opacity: isRefreshing ? 1 : pullProgress
9992
+ },
9993
+ children: /* @__PURE__ */ jsx(
9994
+ Spinner,
9995
+ {
9996
+ size: pullProgress >= 0.5 ? "md" : "sm",
9997
+ className: cn(
9998
+ "text-[var(--color-primary)]",
9999
+ isRefreshing && "animate-spin"
10000
+ )
10001
+ }
10002
+ )
10003
+ }
10004
+ )
10005
+ }
10006
+ ),
10007
+ /* @__PURE__ */ jsx(
10008
+ Box,
10009
+ {
10010
+ fullWidth: true,
10011
+ className: cn(
10012
+ "min-h-0",
10013
+ isPulling && "select-none"
10014
+ ),
10015
+ ...containerProps,
10016
+ children
10017
+ }
10018
+ )
10019
+ ] });
10020
+ };
10021
+ PullToRefresh.displayName = "PullToRefresh";
7943
10022
 
7944
10023
  // components/organisms/types.ts
7945
10024
  var EntityDisplayEvents = {
@@ -8368,6 +10447,7 @@ var StatCard = ({
8368
10447
  // Schema-based props
8369
10448
  entity,
8370
10449
  metrics,
10450
+ sparklineData,
8371
10451
  isLoading: externalLoading,
8372
10452
  error: externalError
8373
10453
  }) => {
@@ -8375,7 +10455,7 @@ var StatCard = ({
8375
10455
  const labelToUse = propLabel ?? propTitle;
8376
10456
  const eventBus = useEventBus();
8377
10457
  const { t } = useTranslate();
8378
- const handleActionClick = React50__default.useCallback(() => {
10458
+ const handleActionClick = React68__default.useCallback(() => {
8379
10459
  if (action?.event) {
8380
10460
  eventBus.emit(`UI:${action.event}`, {});
8381
10461
  }
@@ -8386,7 +10466,7 @@ var StatCard = ({
8386
10466
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
8387
10467
  const isLoading = externalLoading ?? false;
8388
10468
  const error = externalError;
8389
- const computeMetricValue = React50__default.useCallback(
10469
+ const computeMetricValue = React68__default.useCallback(
8390
10470
  (metric, items) => {
8391
10471
  if (metric.value !== void 0) {
8392
10472
  return metric.value;
@@ -8425,7 +10505,7 @@ var StatCard = ({
8425
10505
  },
8426
10506
  []
8427
10507
  );
8428
- const schemaStats = React50__default.useMemo(() => {
10508
+ const schemaStats = React68__default.useMemo(() => {
8429
10509
  if (!metrics || metrics.length === 0) return null;
8430
10510
  return metrics.map((metric) => ({
8431
10511
  label: metric.label,
@@ -8433,7 +10513,7 @@ var StatCard = ({
8433
10513
  format: metric.format
8434
10514
  }));
8435
10515
  }, [metrics, data, computeMetricValue]);
8436
- const calculatedTrend = React50__default.useMemo(() => {
10516
+ const calculatedTrend = React68__default.useMemo(() => {
8437
10517
  if (manualTrend !== void 0) return manualTrend;
8438
10518
  if (previousValue === void 0 || currentValue === void 0)
8439
10519
  return void 0;
@@ -8513,7 +10593,35 @@ var StatCard = ({
8513
10593
  ] }),
8514
10594
  subtitle && !calculatedTrend && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: subtitle })
8515
10595
  ] }),
8516
- Icon2 && /* @__PURE__ */ jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsx(Icon2, { className: cn("h-6 w-6", iconColor) }) })
10596
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
10597
+ Icon2 && /* @__PURE__ */ jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsx(Icon2, { className: cn("h-6 w-6", iconColor) }) }),
10598
+ sparklineData && sparklineData.length > 1 && (() => {
10599
+ const w = 80;
10600
+ const h = 32;
10601
+ const pad = 2;
10602
+ const min = Math.min(...sparklineData);
10603
+ const max = Math.max(...sparklineData);
10604
+ const range = max - min || 1;
10605
+ const points = sparklineData.map((v, i) => {
10606
+ const x = pad + i / (sparklineData.length - 1) * (w - pad * 2);
10607
+ const y = pad + (1 - (v - min) / range) * (h - pad * 2);
10608
+ return `${x},${y}`;
10609
+ }).join(" ");
10610
+ const trending = sparklineData[sparklineData.length - 1] >= sparklineData[0];
10611
+ const strokeColor = trending ? "var(--color-success)" : "var(--color-error)";
10612
+ return /* @__PURE__ */ jsx("svg", { width: w, height: h, viewBox: `0 0 ${w} ${h}`, className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
10613
+ "polyline",
10614
+ {
10615
+ fill: "none",
10616
+ stroke: strokeColor,
10617
+ strokeWidth: "2",
10618
+ strokeLinecap: "round",
10619
+ strokeLinejoin: "round",
10620
+ points
10621
+ }
10622
+ ) });
10623
+ })()
10624
+ ] })
8517
10625
  ] }),
8518
10626
  action && /* @__PURE__ */ jsxs(
8519
10627
  Button,
@@ -8561,7 +10669,7 @@ var PageHeader = ({
8561
10669
  action.onClick();
8562
10670
  }
8563
10671
  };
8564
- const statusColors = {
10672
+ const statusColors2 = {
8565
10673
  default: "bg-[var(--color-muted)] text-[var(--color-foreground)]",
8566
10674
  success: "bg-[var(--color-success)]/10 text-[var(--color-success)]",
8567
10675
  warning: "bg-[var(--color-warning)]/10 text-[var(--color-warning)]",
@@ -8569,7 +10677,7 @@ var PageHeader = ({
8569
10677
  info: "bg-[var(--color-info)]/10 text-[var(--color-info)]"
8570
10678
  };
8571
10679
  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(React50__default.Fragment, { children: [
10680
+ 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(React68__default.Fragment, { children: [
8573
10681
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
8574
10682
  crumb.href ? /* @__PURE__ */ jsx(
8575
10683
  "a",
@@ -8600,7 +10708,7 @@ var PageHeader = ({
8600
10708
  variant: "small",
8601
10709
  className: cn(
8602
10710
  "px-2.5 py-1 rounded-[var(--radius-full)] text-xs font-medium",
8603
- statusColors[status.variant || "default"]
10711
+ statusColors2[status.variant || "default"]
8604
10712
  ),
8605
10713
  children: status.label
8606
10714
  }
@@ -9202,7 +11310,7 @@ var Form = ({
9202
11310
  const normalizedInitialData = initialData ?? {};
9203
11311
  const resolvedEntity = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
9204
11312
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
9205
- const entityDerivedFields = React50__default.useMemo(() => {
11313
+ const entityDerivedFields = React68__default.useMemo(() => {
9206
11314
  if (fields && fields.length > 0) return void 0;
9207
11315
  if (!resolvedEntity) return void 0;
9208
11316
  return resolvedEntity.fields.map(
@@ -9221,14 +11329,14 @@ var Form = ({
9221
11329
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
9222
11330
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
9223
11331
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
9224
- const [formData, setFormData] = React50__default.useState(
11332
+ const [formData, setFormData] = React68__default.useState(
9225
11333
  normalizedInitialData
9226
11334
  );
9227
- const [collapsedSections, setCollapsedSections] = React50__default.useState(
11335
+ const [collapsedSections, setCollapsedSections] = React68__default.useState(
9228
11336
  /* @__PURE__ */ new Set()
9229
11337
  );
9230
11338
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
9231
- const evalContext = React50__default.useMemo(
11339
+ const evalContext = React68__default.useMemo(
9232
11340
  () => ({
9233
11341
  formValues: formData,
9234
11342
  globalVariables: externalContext?.globalVariables ?? {},
@@ -9237,13 +11345,13 @@ var Form = ({
9237
11345
  }),
9238
11346
  [formData, externalContext]
9239
11347
  );
9240
- React50__default.useEffect(() => {
11348
+ React68__default.useEffect(() => {
9241
11349
  const data = initialData;
9242
11350
  if (data && Object.keys(data).length > 0) {
9243
11351
  setFormData(data);
9244
11352
  }
9245
11353
  }, [initialData]);
9246
- const processCalculations = React50__default.useCallback(
11354
+ const processCalculations = React68__default.useCallback(
9247
11355
  (changedFieldId, newFormData) => {
9248
11356
  if (!hiddenCalculations.length) return;
9249
11357
  const context = {
@@ -9268,7 +11376,7 @@ var Form = ({
9268
11376
  },
9269
11377
  [hiddenCalculations, externalContext, eventBus]
9270
11378
  );
9271
- const checkViolations = React50__default.useCallback(
11379
+ const checkViolations = React68__default.useCallback(
9272
11380
  (changedFieldId, newFormData) => {
9273
11381
  if (!violationTriggers.length) return;
9274
11382
  const context = {
@@ -9305,7 +11413,7 @@ var Form = ({
9305
11413
  processCalculations(name, newFormData);
9306
11414
  checkViolations(name, newFormData);
9307
11415
  };
9308
- const isFieldVisible = React50__default.useCallback(
11416
+ const isFieldVisible = React68__default.useCallback(
9309
11417
  (fieldName) => {
9310
11418
  const condition = conditionalFields[fieldName];
9311
11419
  if (!condition) return true;
@@ -9313,7 +11421,7 @@ var Form = ({
9313
11421
  },
9314
11422
  [conditionalFields, evalContext]
9315
11423
  );
9316
- const isSectionVisible = React50__default.useCallback(
11424
+ const isSectionVisible = React68__default.useCallback(
9317
11425
  (section) => {
9318
11426
  if (!section.condition) return true;
9319
11427
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -9345,7 +11453,7 @@ var Form = ({
9345
11453
  eventBus.emit(`UI:${onCancel}`);
9346
11454
  }
9347
11455
  };
9348
- const renderField = React50__default.useCallback(
11456
+ const renderField = React68__default.useCallback(
9349
11457
  (field) => {
9350
11458
  const fieldName = field.name || field.field;
9351
11459
  if (!fieldName) return null;
@@ -9366,7 +11474,7 @@ var Form = ({
9366
11474
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
9367
11475
  );
9368
11476
  const effectiveFields = entityDerivedFields ?? fields;
9369
- const normalizedFields = React50__default.useMemo(() => {
11477
+ const normalizedFields = React68__default.useMemo(() => {
9370
11478
  if (!effectiveFields || effectiveFields.length === 0) return [];
9371
11479
  return effectiveFields.map((field) => {
9372
11480
  if (typeof field === "string") {
@@ -9375,7 +11483,7 @@ var Form = ({
9375
11483
  return field;
9376
11484
  });
9377
11485
  }, [effectiveFields]);
9378
- const schemaFields = React50__default.useMemo(() => {
11486
+ const schemaFields = React68__default.useMemo(() => {
9379
11487
  if (normalizedFields.length === 0) return null;
9380
11488
  if (isDebugEnabled()) {
9381
11489
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -9385,7 +11493,7 @@ var Form = ({
9385
11493
  }
9386
11494
  return normalizedFields.map(renderField).filter(Boolean);
9387
11495
  }, [normalizedFields, renderField, entityName, conditionalFields]);
9388
- const sectionElements = React50__default.useMemo(() => {
11496
+ const sectionElements = React68__default.useMemo(() => {
9389
11497
  if (!sections || sections.length === 0) return null;
9390
11498
  return sections.map((section) => {
9391
11499
  if (!isSectionVisible(section)) {
@@ -10236,7 +12344,7 @@ function InputPattern({
10236
12344
  className
10237
12345
  }) {
10238
12346
  const { emit } = useEventBus();
10239
- const [localValue, setLocalValue] = React50__default.useState(value);
12347
+ const [localValue, setLocalValue] = React68__default.useState(value);
10240
12348
  const handleChange = (e) => {
10241
12349
  setLocalValue(e.target.value);
10242
12350
  if (onChange) {
@@ -10273,7 +12381,7 @@ function TextareaPattern({
10273
12381
  className
10274
12382
  }) {
10275
12383
  const { emit } = useEventBus();
10276
- const [localValue, setLocalValue] = React50__default.useState(value);
12384
+ const [localValue, setLocalValue] = React68__default.useState(value);
10277
12385
  const handleChange = (e) => {
10278
12386
  setLocalValue(e.target.value);
10279
12387
  if (onChange) {
@@ -10304,7 +12412,7 @@ function SelectPattern({
10304
12412
  className
10305
12413
  }) {
10306
12414
  const { emit } = useEventBus();
10307
- const [localValue, setLocalValue] = React50__default.useState(value);
12415
+ const [localValue, setLocalValue] = React68__default.useState(value);
10308
12416
  const handleChange = (e) => {
10309
12417
  setLocalValue(e.target.value);
10310
12418
  if (onChange) {
@@ -10333,7 +12441,7 @@ function CheckboxPattern({
10333
12441
  className
10334
12442
  }) {
10335
12443
  const { emit } = useEventBus();
10336
- const [localChecked, setLocalChecked] = React50__default.useState(checked);
12444
+ const [localChecked, setLocalChecked] = React68__default.useState(checked);
10337
12445
  const handleChange = (e) => {
10338
12446
  setLocalChecked(e.target.checked);
10339
12447
  if (onChange) {
@@ -10763,7 +12871,7 @@ function SuspenseConfigProvider({
10763
12871
  config,
10764
12872
  children
10765
12873
  }) {
10766
- return React50__default.createElement(
12874
+ return React68__default.createElement(
10767
12875
  SuspenseConfigContext.Provider,
10768
12876
  { value: config },
10769
12877
  children
@@ -11248,4 +13356,4 @@ function UISlotRenderer({
11248
13356
  }
11249
13357
  UISlotRenderer.displayName = "UISlotRenderer";
11250
13358
 
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 };
13359
+ 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, 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, 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 };