@almadar/ui 5.30.0 → 5.31.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.
@@ -45,7 +45,6 @@ var utilities = require('@dnd-kit/utilities');
45
45
  var react = require('@xyflow/react');
46
46
  var context = require('@almadar/ui/context');
47
47
  var patterns = require('@almadar/patterns');
48
- var fiber = require('@react-three/fiber');
49
48
 
50
49
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
51
50
 
@@ -2187,6 +2186,8 @@ var init_Input = __esm({
2187
2186
  className,
2188
2187
  inputType,
2189
2188
  type: htmlType,
2189
+ label,
2190
+ helperText,
2190
2191
  error,
2191
2192
  leftIcon,
2192
2193
  rightIcon,
@@ -2242,82 +2243,95 @@ var init_Input = __esm({
2242
2243
  onClear?.();
2243
2244
  }
2244
2245
  };
2246
+ const wrapField = (field) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full", children: [
2247
+ label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm font-medium text-foreground mb-1", children: label }),
2248
+ field,
2249
+ (helperText || error) && /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("mt-1 text-xs", error ? "text-error" : "text-muted-foreground"), children: error ?? helperText })
2250
+ ] });
2245
2251
  if (type === "select") {
2246
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
2247
- resolvedLeftIcon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-muted-foreground", children: resolvedLeftIcon }),
2248
- /* @__PURE__ */ jsxRuntime.jsxs(
2249
- "select",
2252
+ return wrapField(
2253
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
2254
+ resolvedLeftIcon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-muted-foreground", children: resolvedLeftIcon }),
2255
+ /* @__PURE__ */ jsxRuntime.jsxs(
2256
+ "select",
2257
+ {
2258
+ ref,
2259
+ value,
2260
+ onChange: handleChange,
2261
+ className: cn(baseClassName, "appearance-none pr-10", className),
2262
+ ...props,
2263
+ children: [
2264
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: t("form.selectPlaceholder", { label: "" }) }),
2265
+ options?.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
2266
+ ]
2267
+ }
2268
+ ),
2269
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "chevron-down", className: "h-icon-default w-icon-default" }) })
2270
+ ] })
2271
+ );
2272
+ }
2273
+ if (type === "textarea") {
2274
+ return wrapField(
2275
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
2276
+ "textarea",
2250
2277
  {
2251
2278
  ref,
2252
2279
  value,
2253
2280
  onChange: handleChange,
2254
- className: cn(baseClassName, "appearance-none pr-10", className),
2255
- ...props,
2256
- children: [
2257
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: t("form.selectPlaceholder", { label: "" }) }),
2258
- options?.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
2259
- ]
2281
+ rows: rows2,
2282
+ className: baseClassName,
2283
+ ...props
2260
2284
  }
2261
- ),
2262
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "chevron-down", className: "h-icon-default w-icon-default" }) })
2263
- ] });
2264
- }
2265
- if (type === "textarea") {
2266
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
2267
- "textarea",
2268
- {
2269
- ref,
2270
- value,
2271
- onChange: handleChange,
2272
- rows: rows2,
2273
- className: baseClassName,
2274
- ...props
2275
- }
2276
- ) });
2285
+ ) })
2286
+ );
2277
2287
  }
2278
2288
  if (type === "checkbox") {
2279
- return /* @__PURE__ */ jsxRuntime.jsx(
2280
- "input",
2281
- {
2282
- ref,
2283
- type: "checkbox",
2284
- checked: props.checked,
2285
- onChange: handleChange,
2286
- className: cn(
2287
- "h-icon-default w-icon-default rounded-sm",
2288
- "border-border",
2289
- "text-primary focus:ring-ring",
2290
- "disabled:opacity-50 disabled:cursor-not-allowed",
2291
- className
2292
- ),
2293
- ...props
2294
- }
2289
+ return wrapField(
2290
+ /* @__PURE__ */ jsxRuntime.jsx(
2291
+ "input",
2292
+ {
2293
+ ref,
2294
+ type: "checkbox",
2295
+ checked: props.checked,
2296
+ onChange: handleChange,
2297
+ className: cn(
2298
+ "h-icon-default w-icon-default rounded-sm",
2299
+ "border-border",
2300
+ "text-primary focus:ring-ring",
2301
+ "disabled:opacity-50 disabled:cursor-not-allowed",
2302
+ className
2303
+ ),
2304
+ ...props
2305
+ }
2306
+ )
2295
2307
  );
2296
2308
  }
2297
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
2298
- resolvedLeftIcon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-muted-foreground", children: resolvedLeftIcon }),
2299
- /* @__PURE__ */ jsxRuntime.jsx(
2300
- "input",
2301
- {
2302
- ref,
2303
- type,
2304
- value,
2305
- onChange: handleChange,
2306
- className: baseClassName,
2307
- ...props
2308
- }
2309
- ),
2310
- showClearButton && /* @__PURE__ */ jsxRuntime.jsx(
2311
- "button",
2312
- {
2313
- type: "button",
2314
- onClick: handleClear,
2315
- className: "absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground hover:text-foreground",
2316
- children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "x", className: "h-icon-default w-icon-default" })
2317
- }
2318
- ),
2319
- rightIcon && !showClearButton && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground", children: resolveIconNode(rightIcon, iconCls) })
2320
- ] });
2309
+ return wrapField(
2310
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
2311
+ resolvedLeftIcon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-muted-foreground", children: resolvedLeftIcon }),
2312
+ /* @__PURE__ */ jsxRuntime.jsx(
2313
+ "input",
2314
+ {
2315
+ ref,
2316
+ type,
2317
+ value,
2318
+ onChange: handleChange,
2319
+ className: baseClassName,
2320
+ ...props
2321
+ }
2322
+ ),
2323
+ showClearButton && /* @__PURE__ */ jsxRuntime.jsx(
2324
+ "button",
2325
+ {
2326
+ type: "button",
2327
+ onClick: handleClear,
2328
+ className: "absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground hover:text-foreground",
2329
+ children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "x", className: "h-icon-default w-icon-default" })
2330
+ }
2331
+ ),
2332
+ rightIcon && !showClearButton && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground", children: resolveIconNode(rightIcon, iconCls) })
2333
+ ] })
2334
+ );
2321
2335
  }
2322
2336
  );
2323
2337
  exports.Input.displayName = "Input";
@@ -2388,6 +2402,190 @@ var init_Textarea = __esm({
2388
2402
  exports.Textarea.displayName = "Textarea";
2389
2403
  }
2390
2404
  });
2405
+ function flatOptions(opts, groups) {
2406
+ const flat = opts ?? [];
2407
+ const grp = (groups ?? []).flatMap((g) => g.options);
2408
+ return [...flat, ...grp];
2409
+ }
2410
+ function NativeSelect({
2411
+ className,
2412
+ options,
2413
+ groups,
2414
+ placeholder,
2415
+ error,
2416
+ onChange,
2417
+ value,
2418
+ ...props
2419
+ }) {
2420
+ const eventBus = useEventBus();
2421
+ const handleChange = (e) => {
2422
+ if (typeof onChange === "string") {
2423
+ eventBus.emit(`UI:${onChange}`, { value: e.target.value });
2424
+ } else {
2425
+ onChange?.(e.target.value);
2426
+ }
2427
+ };
2428
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
2429
+ /* @__PURE__ */ jsxRuntime.jsxs(
2430
+ "select",
2431
+ {
2432
+ onChange: handleChange,
2433
+ value,
2434
+ className: cn(
2435
+ "block w-full border-[length:var(--border-width)] shadow-sm appearance-none",
2436
+ "px-3 py-2 pr-10 text-sm text-foreground font-medium",
2437
+ "bg-card",
2438
+ "focus:outline-none focus:ring-2 focus:ring-offset-0 focus:ring-ring",
2439
+ "disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
2440
+ error ? "border-error focus:border-error" : "border-border focus:border-primary",
2441
+ className
2442
+ ),
2443
+ ...props,
2444
+ children: [
2445
+ placeholder && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: placeholder }),
2446
+ options?.map((option) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value)),
2447
+ groups?.map((group) => /* @__PURE__ */ jsxRuntime.jsx("optgroup", { label: group.label, children: group.options.map((option) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value)) }, group.label))
2448
+ ]
2449
+ }
2450
+ ),
2451
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "chevron-down", className: "h-icon-default w-icon-default text-foreground" }) })
2452
+ ] });
2453
+ }
2454
+ function RichSelect({
2455
+ className,
2456
+ options,
2457
+ groups,
2458
+ placeholder,
2459
+ error,
2460
+ onChange,
2461
+ value,
2462
+ multiple,
2463
+ searchable,
2464
+ clearable,
2465
+ disabled
2466
+ }) {
2467
+ const eventBus = useEventBus();
2468
+ const [open, setOpen] = React74.useState(false);
2469
+ const [search, setSearch] = React74.useState("");
2470
+ const containerRef = React74.useRef(null);
2471
+ const selected = multiple ? Array.isArray(value) ? value : value ? [value] : [] : value ? [value] : [];
2472
+ const all = flatOptions(options, groups);
2473
+ const filtered = searchable && search ? all.filter((o) => o.label.toLowerCase().includes(search.toLowerCase())) : all;
2474
+ const toggle = (optValue) => {
2475
+ let next;
2476
+ if (multiple) {
2477
+ next = selected.includes(optValue) ? selected.filter((v) => v !== optValue) : [...selected, optValue];
2478
+ } else {
2479
+ next = optValue;
2480
+ setOpen(false);
2481
+ }
2482
+ if (typeof onChange === "string") {
2483
+ eventBus.emit(`UI:${onChange}`, { value: next });
2484
+ } else {
2485
+ onChange?.(next);
2486
+ }
2487
+ };
2488
+ const clear = (e) => {
2489
+ e.stopPropagation();
2490
+ const next = multiple ? [] : "";
2491
+ if (typeof onChange === "string") {
2492
+ eventBus.emit(`UI:${onChange}`, { value: next });
2493
+ } else {
2494
+ onChange?.(next);
2495
+ }
2496
+ };
2497
+ React74.useEffect(() => {
2498
+ const handler = (e) => {
2499
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
2500
+ setOpen(false);
2501
+ setSearch("");
2502
+ }
2503
+ };
2504
+ document.addEventListener("mousedown", handler);
2505
+ return () => document.removeEventListener("mousedown", handler);
2506
+ }, []);
2507
+ const displayLabel = selected.length === 0 ? placeholder ?? "" : multiple ? `${selected.length} selected` : all.find((o) => o.value === selected[0])?.label ?? selected[0];
2508
+ const hasValue = selected.length > 0;
2509
+ const renderOptions = (opts) => opts.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
2510
+ "button",
2511
+ {
2512
+ type: "button",
2513
+ disabled: opt.disabled,
2514
+ onClick: () => !opt.disabled && toggle(opt.value),
2515
+ className: cn(
2516
+ "w-full flex items-center justify-between px-3 py-1.5 text-sm text-start",
2517
+ "hover:bg-muted transition-colors",
2518
+ "disabled:opacity-50 disabled:cursor-not-allowed",
2519
+ selected.includes(opt.value) && "text-primary font-medium"
2520
+ ),
2521
+ children: [
2522
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: opt.label }),
2523
+ selected.includes(opt.value) && /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "check", className: "h-icon-default w-icon-default" })
2524
+ ]
2525
+ },
2526
+ opt.value
2527
+ ));
2528
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: cn("relative w-full", className), children: [
2529
+ /* @__PURE__ */ jsxRuntime.jsx(
2530
+ "button",
2531
+ {
2532
+ type: "button",
2533
+ disabled,
2534
+ onClick: () => !disabled && setOpen((o) => !o),
2535
+ className: cn(
2536
+ "block w-full border-[length:var(--border-width)] shadow-sm",
2537
+ "px-3 py-2 pr-10 text-sm text-start font-medium",
2538
+ "bg-card rounded-sm",
2539
+ "focus:outline-none focus:ring-2 focus:ring-offset-0 focus:ring-ring",
2540
+ "disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
2541
+ error ? "border-error focus:border-error" : "border-border focus:border-primary",
2542
+ !hasValue && "text-muted-foreground"
2543
+ ),
2544
+ children: displayLabel
2545
+ }
2546
+ ),
2547
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center gap-1 pointer-events-none", children: [
2548
+ clearable && hasValue && /* @__PURE__ */ jsxRuntime.jsx(
2549
+ "button",
2550
+ {
2551
+ type: "button",
2552
+ onClick: clear,
2553
+ className: "pointer-events-auto text-muted-foreground hover:text-foreground",
2554
+ children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "x", className: "h-icon-default w-icon-default" })
2555
+ }
2556
+ ),
2557
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "chevron-down", className: "h-icon-default w-icon-default text-foreground" })
2558
+ ] }),
2559
+ open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(
2560
+ "absolute z-50 mt-1 w-full",
2561
+ "bg-card border-[length:var(--border-width)] border-border",
2562
+ "rounded-sm shadow-elevation-popover py-1 max-h-60 overflow-y-auto"
2563
+ ), children: [
2564
+ searchable && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 pb-1 border-b border-border", children: /* @__PURE__ */ jsxRuntime.jsx(
2565
+ "input",
2566
+ {
2567
+ autoFocus: true,
2568
+ type: "text",
2569
+ value: search,
2570
+ onChange: (e) => setSearch(e.target.value),
2571
+ placeholder: "Search\u2026",
2572
+ className: cn(
2573
+ "w-full px-2 py-1 text-sm bg-transparent",
2574
+ "focus:outline-none text-foreground placeholder:text-muted-foreground"
2575
+ )
2576
+ }
2577
+ ) }),
2578
+ groups && groups.length > 0 ? groups.map((g) => {
2579
+ const groupFiltered = searchable && search ? g.options.filter((o) => o.label.toLowerCase().includes(search.toLowerCase())) : g.options;
2580
+ if (groupFiltered.length === 0) return null;
2581
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2582
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-1 text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: g.label }),
2583
+ renderOptions(groupFiltered)
2584
+ ] }, g.label);
2585
+ }) : renderOptions(filtered)
2586
+ ] })
2587
+ ] });
2588
+ }
2391
2589
  exports.Select = void 0;
2392
2590
  var init_Select = __esm({
2393
2591
  "components/core/atoms/Select.tsx"() {
@@ -2395,47 +2593,12 @@ var init_Select = __esm({
2395
2593
  init_Icon();
2396
2594
  init_useEventBus();
2397
2595
  exports.Select = React74__namespace.default.forwardRef(
2398
- ({ className, options, placeholder, error, onChange, ...props }, ref) => {
2399
- const eventBus = useEventBus();
2400
- const handleChange = (e) => {
2401
- if (typeof onChange === "string") {
2402
- eventBus.emit(`UI:${onChange}`, { value: e.target.value });
2403
- } else {
2404
- onChange?.(e);
2405
- }
2406
- };
2407
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
2408
- /* @__PURE__ */ jsxRuntime.jsxs(
2409
- "select",
2410
- {
2411
- ref,
2412
- onChange: handleChange,
2413
- className: cn(
2414
- "block w-full border-[length:var(--border-width)] shadow-sm appearance-none",
2415
- "px-3 py-2 pr-10 text-sm text-foreground font-medium",
2416
- "bg-card",
2417
- "focus:outline-none focus:ring-2 focus:ring-offset-0 focus:ring-ring",
2418
- "disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
2419
- error ? "border-error focus:border-error" : "border-border focus:border-primary",
2420
- className
2421
- ),
2422
- ...props,
2423
- children: [
2424
- placeholder && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: placeholder }),
2425
- options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
2426
- "option",
2427
- {
2428
- value: option.value,
2429
- disabled: option.disabled,
2430
- children: option.label
2431
- },
2432
- option.value
2433
- ))
2434
- ]
2435
- }
2436
- ),
2437
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "chevron-down", className: "h-icon-default w-icon-default text-foreground" }) })
2438
- ] });
2596
+ (props, _ref) => {
2597
+ const { multiple, searchable, clearable } = props;
2598
+ if (multiple || searchable || clearable) {
2599
+ return /* @__PURE__ */ jsxRuntime.jsx(RichSelect, { ...props });
2600
+ }
2601
+ return /* @__PURE__ */ jsxRuntime.jsx(NativeSelect, { ...props });
2439
2602
  }
2440
2603
  );
2441
2604
  exports.Select.displayName = "Select";
@@ -2489,11 +2652,54 @@ var init_Checkbox = __esm({
2489
2652
  exports.Checkbox.displayName = "Checkbox";
2490
2653
  }
2491
2654
  });
2655
+ var sizeStyles2; exports.Spinner = void 0;
2656
+ var init_Spinner = __esm({
2657
+ "components/core/atoms/Spinner.tsx"() {
2658
+ init_cn();
2659
+ init_Icon();
2660
+ sizeStyles2 = {
2661
+ xs: "h-3 w-3",
2662
+ sm: "h-icon-default w-icon-default",
2663
+ md: "h-6 w-6",
2664
+ lg: "h-8 w-8"
2665
+ };
2666
+ exports.Spinner = React74__namespace.default.forwardRef(
2667
+ ({ className, size = "md", overlay, ...props }, ref) => {
2668
+ if (overlay) {
2669
+ return /* @__PURE__ */ jsxRuntime.jsx(
2670
+ "div",
2671
+ {
2672
+ ref,
2673
+ className: cn(
2674
+ "absolute inset-0 z-10 flex items-center justify-center",
2675
+ "bg-background/60 backdrop-blur-sm",
2676
+ className
2677
+ ),
2678
+ ...props,
2679
+ children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "loader", className: cn("animate-spin text-foreground", sizeStyles2[size]) })
2680
+ }
2681
+ );
2682
+ }
2683
+ return /* @__PURE__ */ jsxRuntime.jsx(
2684
+ "div",
2685
+ {
2686
+ ref,
2687
+ className: cn("text-foreground", className),
2688
+ ...props,
2689
+ children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "loader", className: cn("animate-spin", sizeStyles2[size]) })
2690
+ }
2691
+ );
2692
+ }
2693
+ );
2694
+ exports.Spinner.displayName = "Spinner";
2695
+ }
2696
+ });
2492
2697
  var variantStyles2, paddingStyles, shadowStyles, lookStyles; exports.Card = void 0; exports.CardHeader = void 0; exports.CardTitle = void 0; exports.CardContent = void 0; exports.CardBody = void 0; exports.CardFooter = void 0;
2493
2698
  var init_Card = __esm({
2494
2699
  "components/core/atoms/Card.tsx"() {
2495
2700
  init_cn();
2496
2701
  init_useEventBus();
2702
+ init_Spinner();
2497
2703
  variantStyles2 = {
2498
2704
  default: [
2499
2705
  "bg-card",
@@ -2558,6 +2764,7 @@ var init_Card = __esm({
2558
2764
  look = "elevated",
2559
2765
  children,
2560
2766
  action,
2767
+ loading,
2561
2768
  onClick,
2562
2769
  ...props
2563
2770
  }, ref) => {
@@ -2571,7 +2778,7 @@ var init_Card = __esm({
2571
2778
  {
2572
2779
  ref,
2573
2780
  className: cn(
2574
- "rounded-container",
2781
+ "rounded-container relative",
2575
2782
  "transition-all duration-[var(--transition-normal)]",
2576
2783
  variantStyles2[variant],
2577
2784
  paddingStyles[padding],
@@ -2582,6 +2789,7 @@ var init_Card = __esm({
2582
2789
  onClick: handleClick,
2583
2790
  ...props,
2584
2791
  children: [
2792
+ loading && /* @__PURE__ */ jsxRuntime.jsx(exports.Spinner, { overlay: true, size: "md" }),
2585
2793
  (title || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4", children: [
2586
2794
  title && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg text-card-foreground font-bold", children: title }),
2587
2795
  subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mt-1", children: subtitle })
@@ -2623,7 +2831,7 @@ var init_Card = __esm({
2623
2831
  exports.CardFooter.displayName = "CardFooter";
2624
2832
  }
2625
2833
  });
2626
- var variantStyles3, sizeStyles2; exports.Badge = void 0;
2834
+ var variantStyles3, sizeStyles3; exports.Badge = void 0;
2627
2835
  var init_Badge = __esm({
2628
2836
  "components/core/atoms/Badge.tsx"() {
2629
2837
  init_cn();
@@ -2660,7 +2868,7 @@ var init_Badge = __esm({
2660
2868
  "border-[length:var(--border-width-thin)] border-border"
2661
2869
  ].join(" ")
2662
2870
  };
2663
- sizeStyles2 = {
2871
+ sizeStyles3 = {
2664
2872
  sm: "px-2 py-0.5 text-xs",
2665
2873
  md: "px-2.5 py-1 text-sm",
2666
2874
  lg: "px-3 py-1.5 text-base"
@@ -2680,7 +2888,7 @@ var init_Badge = __esm({
2680
2888
  className: cn(
2681
2889
  "inline-flex items-center gap-1 font-bold rounded-sm",
2682
2890
  variantStyles3[variant],
2683
- sizeStyles2[size],
2891
+ sizeStyles3[size],
2684
2892
  onRemove && "pr-1",
2685
2893
  className
2686
2894
  ),
@@ -2714,7 +2922,7 @@ var init_Badge = __esm({
2714
2922
  exports.Badge.displayName = "Badge";
2715
2923
  }
2716
2924
  });
2717
- var variantStyles4, sizeStyles3, iconSizes; exports.FilterPill = void 0;
2925
+ var variantStyles4, sizeStyles4, iconSizes; exports.FilterPill = void 0;
2718
2926
  var init_FilterPill = __esm({
2719
2927
  "components/core/atoms/FilterPill.tsx"() {
2720
2928
  init_cn();
@@ -2748,7 +2956,7 @@ var init_FilterPill = __esm({
2748
2956
  "border-[length:var(--border-width-thin)] border-border"
2749
2957
  ].join(" ")
2750
2958
  };
2751
- sizeStyles3 = {
2959
+ sizeStyles4 = {
2752
2960
  sm: "px-2 py-0.5 text-xs",
2753
2961
  md: "px-2.5 py-1 text-sm",
2754
2962
  lg: "px-3 py-1.5 text-base"
@@ -2792,7 +3000,7 @@ var init_FilterPill = __esm({
2792
3000
  className: cn(
2793
3001
  "inline-flex items-center gap-1 font-bold rounded-pill",
2794
3002
  variantStyles4[variant],
2795
- sizeStyles3[size],
3003
+ sizeStyles4[size],
2796
3004
  (onClick || clickEvent) && "cursor-pointer",
2797
3005
  className
2798
3006
  ),
@@ -2824,33 +3032,6 @@ var init_FilterPill = __esm({
2824
3032
  exports.FilterPill.displayName = "FilterPill";
2825
3033
  }
2826
3034
  });
2827
- var sizeStyles4; exports.Spinner = void 0;
2828
- var init_Spinner = __esm({
2829
- "components/core/atoms/Spinner.tsx"() {
2830
- init_cn();
2831
- init_Icon();
2832
- sizeStyles4 = {
2833
- xs: "h-3 w-3",
2834
- sm: "h-icon-default w-icon-default",
2835
- md: "h-6 w-6",
2836
- lg: "h-8 w-8"
2837
- };
2838
- exports.Spinner = React74__namespace.default.forwardRef(
2839
- ({ className, size = "md", ...props }, ref) => {
2840
- return /* @__PURE__ */ jsxRuntime.jsx(
2841
- "div",
2842
- {
2843
- ref,
2844
- className: cn("text-foreground", className),
2845
- ...props,
2846
- children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "loader", className: cn("animate-spin", sizeStyles4[size]) })
2847
- }
2848
- );
2849
- }
2850
- );
2851
- exports.Spinner.displayName = "Spinner";
2852
- }
2853
- });
2854
3035
  function generateInitials(name) {
2855
3036
  const parts = name.trim().split(/\s+/);
2856
3037
  if (parts.length === 1) {
@@ -15072,30 +15253,30 @@ var init_BranchingLogicBuilder = __esm({
15072
15253
  if (!sourceQuestion?.optionValues) return [];
15073
15254
  return sourceQuestion.optionValues.map((v) => ({ value: v, label: v }));
15074
15255
  }, [sourceQuestion]);
15075
- const handleSource = (e) => {
15076
- onChange({ ...rule, sourceQuestionId: e.target.value });
15256
+ const handleSource = (v) => {
15257
+ onChange({ ...rule, sourceQuestionId: v });
15077
15258
  };
15078
- const handleOperator = (e) => {
15079
- const next = e.target.value;
15259
+ const handleOperator = (v) => {
15260
+ const next = v;
15080
15261
  const nextValue = next === "in" && !Array.isArray(rule.value) ? rule.value ? [rule.value] : [] : next !== "in" && Array.isArray(rule.value) ? rule.value[0] ?? "" : rule.value;
15081
15262
  onChange({ ...rule, operator: next, value: nextValue });
15082
15263
  };
15083
15264
  const handleScalarValue = (e) => {
15084
15265
  onChange({ ...rule, value: e.target.value });
15085
15266
  };
15086
- const handleAddChip = (e) => {
15087
- const v = e.target.value;
15088
- if (!v) return;
15267
+ const handleAddChip = (v) => {
15268
+ const val = v;
15269
+ if (!val) return;
15089
15270
  const current = Array.isArray(rule.value) ? rule.value : [];
15090
- if (current.includes(v)) return;
15091
- onChange({ ...rule, value: [...current, v] });
15271
+ if (current.includes(val)) return;
15272
+ onChange({ ...rule, value: [...current, val] });
15092
15273
  };
15093
15274
  const handleRemoveChip = (chip) => {
15094
15275
  const current = Array.isArray(rule.value) ? rule.value : [];
15095
15276
  onChange({ ...rule, value: current.filter((c) => c !== chip) });
15096
15277
  };
15097
- const handleTarget = (e) => {
15098
- onChange({ ...rule, targetQuestionId: e.target.value });
15278
+ const handleTarget = (v) => {
15279
+ onChange({ ...rule, targetQuestionId: v });
15099
15280
  };
15100
15281
  const isMulti = rule.operator === "in";
15101
15282
  const chips = Array.isArray(rule.value) ? rule.value : [];
@@ -15176,7 +15357,7 @@ var init_BranchingLogicBuilder = __esm({
15176
15357
  options: valueOptions,
15177
15358
  value: scalarValue,
15178
15359
  placeholder: t("branchingLogic.selectValue"),
15179
- onChange: (e) => onChange({ ...rule, value: e.target.value }),
15360
+ onChange: (v) => onChange({ ...rule, value: v }),
15180
15361
  disabled: readOnly
15181
15362
  }
15182
15363
  ) : /* @__PURE__ */ jsxRuntime.jsx(
@@ -17608,7 +17789,7 @@ var init_Pagination = __esm({
17608
17789
  exports.Select,
17609
17790
  {
17610
17791
  value: String(pageSize),
17611
- onChange: (e) => handlePageSizeChange(Number(e.target.value)),
17792
+ onChange: (v) => handlePageSizeChange(Number(v)),
17612
17793
  options: pageSizeOptions.map((size) => ({
17613
17794
  value: String(size),
17614
17795
  label: String(size)
@@ -20862,7 +21043,9 @@ var init_Menu = __esm({
20862
21043
  trigger,
20863
21044
  items,
20864
21045
  position = "bottom-left",
20865
- className
21046
+ className,
21047
+ header,
21048
+ footer
20866
21049
  }) => {
20867
21050
  const eventBus = useEventBus();
20868
21051
  const { direction } = hooks.useTranslate();
@@ -20994,14 +21177,18 @@ var init_Menu = __esm({
20994
21177
  )
20995
21178
  ] }, itemId);
20996
21179
  });
20997
- const panel = isOpen && triggerRect ? /* @__PURE__ */ jsxRuntime.jsx(
21180
+ const panel = isOpen && triggerRect ? /* @__PURE__ */ jsxRuntime.jsxs(
20998
21181
  "div",
20999
21182
  {
21000
21183
  ref: menuRef,
21001
21184
  className: cn("fixed z-50", menuContainerStyles, className),
21002
21185
  style: computeMenuStyle(effectivePosition, triggerRect),
21003
21186
  role: "menu",
21004
- children: renderMenuItems(items)
21187
+ children: [
21188
+ header && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-2 border-b border-border", children: header }),
21189
+ renderMenuItems(items),
21190
+ footer && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-2 border-t border-border", children: footer })
21191
+ ]
21005
21192
  }
21006
21193
  ) : null;
21007
21194
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -22416,11 +22603,15 @@ function KindSelect({
22416
22603
  function ValueNode({
22417
22604
  value,
22418
22605
  onChange,
22419
- depth
22606
+ depth,
22607
+ readonly
22420
22608
  }) {
22421
22609
  const kind = kindOf(value);
22422
22610
  if (kind === "object" || kind === "array") {
22423
- return /* @__PURE__ */ jsxRuntime.jsx(ContainerNode, { value, onChange, depth });
22611
+ return /* @__PURE__ */ jsxRuntime.jsx(ContainerNode, { value, onChange, depth, readonly });
22612
+ }
22613
+ if (readonly) {
22614
+ return /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", className: "font-mono text-foreground", children: value === null ? "null" : String(value) });
22424
22615
  }
22425
22616
  return /* @__PURE__ */ jsxRuntime.jsx(ScalarControl, { value, onChange });
22426
22617
  }
@@ -22432,15 +22623,19 @@ function Row({
22432
22623
  onValue,
22433
22624
  onRenameKey,
22434
22625
  onChangeKind,
22435
- onRemove
22626
+ onRemove,
22627
+ readonly
22436
22628
  }) {
22437
22629
  const [keyDraft, setKeyDraft] = React74__namespace.default.useState(rowKey);
22438
22630
  React74__namespace.default.useEffect(() => setKeyDraft(rowKey), [rowKey]);
22439
22631
  const container = isObj(value) || isArr(value);
22440
22632
  return /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "none", className: "group w-max min-w-full", children: [
22441
22633
  /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", align: "center", className: "py-0.5 w-max", children: [
22442
- /* @__PURE__ */ jsxRuntime.jsx(KindSelect, { kind: kindOf(value), onChange: onChangeKind }),
22443
- isArrayItem ? /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", color: "muted", className: "w-6 shrink-0 font-mono", children: rowKey }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-20 shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
22634
+ readonly ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
22635
+ "h-6 rounded-sm bg-muted text-muted-foreground text-[10px] font-mono px-1 flex items-center",
22636
+ "border-[length:var(--border-width-thin)] border-border"
22637
+ ), children: TYPE_LABEL[kindOf(value)] }) : /* @__PURE__ */ jsxRuntime.jsx(KindSelect, { kind: kindOf(value), onChange: onChangeKind }),
22638
+ isArrayItem ? /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", color: "muted", className: "w-6 shrink-0 font-mono", children: rowKey }) : readonly ? /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", color: "muted", className: "w-20 shrink-0 font-mono truncate", children: rowKey }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-20 shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
22444
22639
  exports.Input,
22445
22640
  {
22446
22641
  inputType: "text",
@@ -22453,8 +22648,8 @@ function Row({
22453
22648
  className: "font-mono"
22454
22649
  }
22455
22650
  ) }),
22456
- !container && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-48 shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(ValueNode, { value, onChange: onValue, depth: depth + 1 }) }),
22457
- /* @__PURE__ */ jsxRuntime.jsx(
22651
+ !container && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-48 shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(ValueNode, { value, onChange: onValue, depth: depth + 1, readonly }) }),
22652
+ !readonly && /* @__PURE__ */ jsxRuntime.jsx(
22458
22653
  exports.Button,
22459
22654
  {
22460
22655
  variant: "ghost",
@@ -22466,13 +22661,14 @@ function Row({
22466
22661
  }
22467
22662
  )
22468
22663
  ] }),
22469
- container && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pl-2", children: /* @__PURE__ */ jsxRuntime.jsx(ValueNode, { value, onChange: onValue, depth: depth + 1 }) })
22664
+ container && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pl-2", children: /* @__PURE__ */ jsxRuntime.jsx(ValueNode, { value, onChange: onValue, depth: depth + 1, readonly }) })
22470
22665
  ] });
22471
22666
  }
22472
22667
  function ContainerNode({
22473
22668
  value,
22474
22669
  onChange,
22475
- depth
22670
+ depth,
22671
+ readonly
22476
22672
  }) {
22477
22673
  const [open, setOpen] = React74__namespace.default.useState(depth < 2);
22478
22674
  const array = isArr(value);
@@ -22545,11 +22741,12 @@ function ContainerNode({
22545
22741
  onValue: (next) => array ? setArrValue(idx, next) : setObjValue(k, next),
22546
22742
  onRenameKey: (nk) => renameKey(k, nk),
22547
22743
  onChangeKind: (kind) => array ? changeArrKind(idx, kind) : changeObjKind(k, kind),
22548
- onRemove: () => array ? removeArrIdx(idx) : removeObjKey(k)
22744
+ onRemove: () => array ? removeArrIdx(idx) : removeObjKey(k),
22745
+ readonly
22549
22746
  },
22550
22747
  array ? idx : k
22551
22748
  )),
22552
- /* @__PURE__ */ jsxRuntime.jsx(
22749
+ !readonly && /* @__PURE__ */ jsxRuntime.jsx(
22553
22750
  exports.Button,
22554
22751
  {
22555
22752
  variant: "ghost",
@@ -22587,9 +22784,9 @@ var init_JsonTreeEditor = __esm({
22587
22784
  null: "\u2014"
22588
22785
  };
22589
22786
  KIND_OPTIONS = ["string", "number", "boolean", "object", "array"];
22590
- exports.JsonTreeEditor = ({ value, onChange, className }) => {
22787
+ exports.JsonTreeEditor = ({ value, onChange, className, readonly }) => {
22591
22788
  const root = value ?? "";
22592
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full overflow-x-auto rounded-sm bg-card/40 p-2 border-[length:var(--border-width-thin)] border-border", className), children: /* @__PURE__ */ jsxRuntime.jsx(ValueNode, { value: root, onChange, depth: 0 }) });
22789
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full overflow-x-auto rounded-sm bg-card/40 p-2 border-[length:var(--border-width-thin)] border-border", className), children: /* @__PURE__ */ jsxRuntime.jsx(ValueNode, { value: root, onChange, depth: 0, readonly }) });
22593
22790
  };
22594
22791
  }
22595
22792
  });
@@ -23082,7 +23279,7 @@ function FieldControl({
23082
23279
  {
23083
23280
  options: decl.values.map((v) => ({ value: v, label: v })),
23084
23281
  value: typeof value === "string" ? value : "",
23085
- onChange: (e) => onChange(name, e.target.value)
23282
+ onChange: (v) => onChange(name, v)
23086
23283
  }
23087
23284
  );
23088
23285
  } else if (decl.type === "number") {
@@ -23234,7 +23431,7 @@ var init_NodeSlotEditor = __esm({
23234
23431
  {
23235
23432
  options,
23236
23433
  value: type,
23237
- onChange: (e) => emit(e.target.value, props)
23434
+ onChange: (v) => emit(v, props)
23238
23435
  }
23239
23436
  ),
23240
23437
  type !== "" && /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "none", className: "pl-1", children: [
@@ -23688,7 +23885,7 @@ var init_FilterGroup = __esm({
23688
23885
  exports.Select,
23689
23886
  {
23690
23887
  value: selectedValues[filter.field] || "all",
23691
- onChange: (e) => handleFilterSelect(filter.field, e.target.value),
23888
+ onChange: (v) => handleFilterSelect(filter.field, v),
23692
23889
  options: [
23693
23890
  { value: "all", label: t("filterGroup.all") },
23694
23891
  ...filter.options?.map((opt) => ({
@@ -23771,7 +23968,7 @@ var init_FilterGroup = __esm({
23771
23968
  exports.Select,
23772
23969
  {
23773
23970
  value: selectedValues[filter.field] || "all",
23774
- onChange: (e) => handleFilterSelect(filter.field, e.target.value),
23971
+ onChange: (v) => handleFilterSelect(filter.field, v),
23775
23972
  options: [
23776
23973
  { value: "all", label: t("filterGroup.allOf", { label: filter.label }) },
23777
23974
  ...filter.options?.map((opt) => ({
@@ -23889,7 +24086,7 @@ var init_FilterGroup = __esm({
23889
24086
  exports.Select,
23890
24087
  {
23891
24088
  value: selectedValues[filter.field] || "all",
23892
- onChange: (e) => handleFilterSelect(filter.field, e.target.value),
24089
+ onChange: (v) => handleFilterSelect(filter.field, v),
23893
24090
  options: [
23894
24091
  { value: "all", label: t("filterGroup.all") },
23895
24092
  ...filter.options?.map((opt) => ({
@@ -28607,13 +28804,13 @@ var init_MapView = __esm({
28607
28804
  shadowSize: [41, 41]
28608
28805
  });
28609
28806
  L.Marker.prototype.options.icon = defaultIcon;
28610
- const { useEffect: useEffect71, useRef: useRef68, useCallback: useCallback114, useState: useState100 } = React74__namespace.default;
28807
+ const { useEffect: useEffect72, useRef: useRef69, useCallback: useCallback114, useState: useState101 } = React74__namespace.default;
28611
28808
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
28612
28809
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
28613
28810
  function MapUpdater({ centerLat, centerLng, zoom }) {
28614
28811
  const map = useMap();
28615
- const prevRef = useRef68({ centerLat, centerLng, zoom });
28616
- useEffect71(() => {
28812
+ const prevRef = useRef69({ centerLat, centerLng, zoom });
28813
+ useEffect72(() => {
28617
28814
  const prev = prevRef.current;
28618
28815
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
28619
28816
  map.setView([centerLat, centerLng], zoom);
@@ -28624,7 +28821,7 @@ var init_MapView = __esm({
28624
28821
  }
28625
28822
  function MapClickHandler({ onMapClick }) {
28626
28823
  const map = useMap();
28627
- useEffect71(() => {
28824
+ useEffect72(() => {
28628
28825
  if (!onMapClick) return;
28629
28826
  const handler = (e) => {
28630
28827
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -28652,7 +28849,7 @@ var init_MapView = __esm({
28652
28849
  showAttribution = true
28653
28850
  }) {
28654
28851
  const eventBus = useEventBus2();
28655
- const [clickedPosition, setClickedPosition] = useState100(null);
28852
+ const [clickedPosition, setClickedPosition] = useState101(null);
28656
28853
  const handleMapClick = useCallback114((lat, lng) => {
28657
28854
  if (showClickedPin) {
28658
28855
  setClickedPosition({ lat, lng });
@@ -34088,8 +34285,8 @@ var init_VersionDiff = __esm({
34088
34285
  return { added, removed };
34089
34286
  }, [diff]);
34090
34287
  const handleBeforeChange = React74.useCallback(
34091
- (e) => {
34092
- const id = e.target.value;
34288
+ (v) => {
34289
+ const id = v;
34093
34290
  setInternalBefore(id);
34094
34291
  onSelectBefore?.(id);
34095
34292
  if (selectBeforeEvent) eventBus.emit(`UI:${selectBeforeEvent}`, { id });
@@ -34097,8 +34294,8 @@ var init_VersionDiff = __esm({
34097
34294
  [onSelectBefore, selectBeforeEvent, eventBus]
34098
34295
  );
34099
34296
  const handleAfterChange = React74.useCallback(
34100
- (e) => {
34101
- const id = e.target.value;
34297
+ (v) => {
34298
+ const id = v;
34102
34299
  setInternalAfter(id);
34103
34300
  onSelectAfter?.(id);
34104
34301
  if (selectAfterEvent) eventBus.emit(`UI:${selectAfterEvent}`, { id });
@@ -38944,11 +39141,11 @@ function RuleEditor({
38944
39141
  className
38945
39142
  }) {
38946
39143
  const { t } = hooks.useTranslate();
38947
- const handleWhenChange = React74.useCallback((e) => {
38948
- onChange({ ...rule, whenEvent: e.target.value });
39144
+ const handleWhenChange = React74.useCallback((v) => {
39145
+ onChange({ ...rule, whenEvent: v });
38949
39146
  }, [rule, onChange]);
38950
- const handleThenChange = React74.useCallback((e) => {
38951
- onChange({ ...rule, thenAction: e.target.value });
39147
+ const handleThenChange = React74.useCallback((v) => {
39148
+ onChange({ ...rule, thenAction: v });
38952
39149
  }, [rule, onChange]);
38953
39150
  return /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { className: cn("items-center p-2 rounded-lg bg-muted/50 border border-border", className), gap: "sm", children: [
38954
39151
  /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", className: "text-primary font-bold whitespace-nowrap", children: t("eventHandler.when") }),
@@ -40024,7 +40221,7 @@ var init_Form = __esm({
40024
40221
  ...commonProps,
40025
40222
  options,
40026
40223
  value: String(currentValue2),
40027
- onChange: (e) => handleChange(fieldName, e.target.value),
40224
+ onChange: (v) => handleChange(fieldName, v),
40028
40225
  placeholder: field.placeholder || `Select ${label}...`
40029
40226
  }
40030
40227
  );
@@ -47263,18 +47460,32 @@ var init_XPBar = __esm({
47263
47460
  }
47264
47461
  });
47265
47462
  function lazyThree(name, loader) {
47266
- const Lazy = React74__namespace.default.lazy(() => loader().then((m) => ({ default: m[name] })));
47463
+ const Lazy = React74__namespace.default.lazy(
47464
+ () => loader().then((m) => {
47465
+ const Resolved = m[name];
47466
+ if (!Resolved) {
47467
+ throw new Error(
47468
+ `[@almadar/ui] 3D component "${name}" was not found in the three subpath bundle.`
47469
+ );
47470
+ }
47471
+ return { default: Resolved };
47472
+ })
47473
+ );
47267
47474
  function ThreeWrapper(props) {
47268
47475
  return React74__namespace.default.createElement(
47269
- React74__namespace.default.Suspense,
47270
- { fallback: null },
47271
- React74__namespace.default.createElement(Lazy, props)
47476
+ ThreeBoundary,
47477
+ { name },
47478
+ React74__namespace.default.createElement(
47479
+ React74__namespace.default.Suspense,
47480
+ { fallback: null },
47481
+ React74__namespace.default.createElement(Lazy, props)
47482
+ )
47272
47483
  );
47273
47484
  }
47274
47485
  ThreeWrapper.displayName = `Lazy(${name})`;
47275
47486
  return ThreeWrapper;
47276
47487
  }
47277
- var FeatureRenderer, GameCanvas3D, GameCanvas3DBattleTemplate, GameCanvas3DCastleTemplate, GameCanvas3DWorldMapTemplate, COMPONENT_REGISTRY;
47488
+ var ThreeBoundary, FeatureRenderer, GameCanvas3D, GameCanvas3DBattleTemplate, GameCanvas3DCastleTemplate, GameCanvas3DWorldMapTemplate, COMPONENT_REGISTRY;
47278
47489
  var init_component_registry_generated = __esm({
47279
47490
  "components/core/organisms/component-registry.generated.ts"() {
47280
47491
  init_AboutPageTemplate();
@@ -47560,6 +47771,28 @@ var init_component_registry_generated = __esm({
47560
47771
  init_WorldMapBoard();
47561
47772
  init_WorldMapTemplate();
47562
47773
  init_XPBar();
47774
+ ThreeBoundary = class extends React74__namespace.default.Component {
47775
+ constructor() {
47776
+ super(...arguments);
47777
+ __publicField(this, "state", { failed: false });
47778
+ }
47779
+ static getDerivedStateFromError() {
47780
+ return { failed: true };
47781
+ }
47782
+ render() {
47783
+ if (this.state.failed) {
47784
+ return React74__namespace.default.createElement(
47785
+ "div",
47786
+ {
47787
+ "data-testid": "three-unavailable",
47788
+ style: { padding: 16, fontSize: 13, lineHeight: 1.5, opacity: 0.7 }
47789
+ },
47790
+ `3D pattern "${this.props.name}" requires three.js. Install the optional peers three + @react-three/fiber + @react-three/drei (matching the host React major) to render it.`
47791
+ );
47792
+ }
47793
+ return this.props.children;
47794
+ }
47795
+ };
47563
47796
  FeatureRenderer = lazyThree("FeatureRenderer", () => import('@almadar/ui/components/molecules/game/three'));
47564
47797
  GameCanvas3D = lazyThree("GameCanvas3D", () => import('@almadar/ui/components/molecules/game/three'));
47565
47798
  GameCanvas3DBattleTemplate = lazyThree("GameCanvas3DBattleTemplate", () => import('@almadar/ui/components/molecules/game/three'));
@@ -49842,195 +50075,6 @@ init_StepFlowOrganism();
49842
50075
  init_ShowcaseOrganism();
49843
50076
  init_TeamOrganism();
49844
50077
  init_CaseStudyOrganism();
49845
- var DEFAULT_FEATURE_CONFIGS = {
49846
- tree: { color: 2263842, height: 1.5, scale: 1, geometry: "tree" },
49847
- rock: { color: 8421504, height: 0.5, scale: 0.8, geometry: "rock" },
49848
- bush: { color: 3329330, height: 0.4, scale: 0.6, geometry: "bush" },
49849
- house: { color: 9127187, height: 1.2, scale: 1.2, geometry: "house" },
49850
- tower: { color: 6908265, height: 2.5, scale: 1, geometry: "tower" },
49851
- wall: { color: 8421504, height: 1, scale: 1, geometry: "wall" },
49852
- mountain: { color: 5597999, height: 2, scale: 1.5, geometry: "mountain" },
49853
- hill: { color: 7048739, height: 0.8, scale: 1.2, geometry: "hill" },
49854
- water: { color: 4491468, height: 0.1, scale: 1, geometry: "water" },
49855
- chest: { color: 16766720, height: 0.3, scale: 0.4, geometry: "chest" },
49856
- sign: { color: 9127187, height: 0.8, scale: 0.3, geometry: "sign" },
49857
- portal: { color: 10040012, height: 1.5, scale: 1, geometry: "portal" }
49858
- };
49859
- function TreeFeature({ height, color }) {
49860
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
49861
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.3, 0], children: [
49862
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.08, 0.1, height * 0.6, 6] }),
49863
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 9127187 })
49864
- ] }),
49865
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.7, 0], children: [
49866
- /* @__PURE__ */ jsxRuntime.jsx("coneGeometry", { args: [0.4, height * 0.5, 8] }),
49867
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
49868
- ] }),
49869
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.9, 0], children: [
49870
- /* @__PURE__ */ jsxRuntime.jsx("coneGeometry", { args: [0.3, height * 0.4, 8] }),
49871
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
49872
- ] }),
49873
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 1.05, 0], children: [
49874
- /* @__PURE__ */ jsxRuntime.jsx("coneGeometry", { args: [0.15, height * 0.25, 8] }),
49875
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
49876
- ] })
49877
- ] });
49878
- }
49879
- function RockFeature({ height, color }) {
49880
- return /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.4, 0], children: [
49881
- /* @__PURE__ */ jsxRuntime.jsx("dodecahedronGeometry", { args: [height * 0.5, 0] }),
49882
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color, roughness: 0.9 })
49883
- ] });
49884
- }
49885
- function BushFeature({ height, color }) {
49886
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
49887
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.3, 0], children: [
49888
- /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [height * 0.4, 8, 8] }),
49889
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
49890
- ] }),
49891
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0.1, height * 0.4, 0.1], children: [
49892
- /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [height * 0.25, 8, 8] }),
49893
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
49894
- ] })
49895
- ] });
49896
- }
49897
- function HouseFeature({ height, color }) {
49898
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
49899
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.4, 0], children: [
49900
- /* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.8, height * 0.8, 0.8] }),
49901
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 13808780 })
49902
- ] }),
49903
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.9, 0], children: [
49904
- /* @__PURE__ */ jsxRuntime.jsx("coneGeometry", { args: [0.6, height * 0.4, 4] }),
49905
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
49906
- ] }),
49907
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.25, 0.41], children: [
49908
- /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.25, height * 0.5] }),
49909
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 4863784 })
49910
- ] })
49911
- ] });
49912
- }
49913
- function TowerFeature({ height, color }) {
49914
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
49915
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.5, 0], children: [
49916
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.35, height, 8] }),
49917
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
49918
- ] }),
49919
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height + 0.05, 0], children: [
49920
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.35, 0.35, 0.1, 8] }),
49921
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
49922
- ] })
49923
- ] });
49924
- }
49925
- function ChestFeature({ height, color }) {
49926
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
49927
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.5, 0], children: [
49928
- /* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.3, height, 0.2] }),
49929
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color, metalness: 0.6, roughness: 0.3 })
49930
- ] }),
49931
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height + 0.05, 0], children: [
49932
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.15, 0.15, 0.3, 8, 1, false, 0, Math.PI] }),
49933
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color, metalness: 0.6, roughness: 0.3 })
49934
- ] })
49935
- ] });
49936
- }
49937
- function DefaultFeature({ height, color }) {
49938
- return /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, height * 0.5, 0], children: [
49939
- /* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.5, height, 0.5] }),
49940
- /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
49941
- ] });
49942
- }
49943
- function FeatureVisual({
49944
- feature,
49945
- position,
49946
- isSelected,
49947
- onClick,
49948
- onHover
49949
- }) {
49950
- const config = DEFAULT_FEATURE_CONFIGS[feature.type] || {
49951
- color: 8947848,
49952
- height: 0.5,
49953
- scale: 1,
49954
- geometry: "default"
49955
- };
49956
- const color = feature.color ? parseInt(feature.color.replace("#", ""), 16) : config.color;
49957
- const renderGeometry = () => {
49958
- switch (config.geometry) {
49959
- case "tree":
49960
- return /* @__PURE__ */ jsxRuntime.jsx(TreeFeature, { height: config.height, color });
49961
- case "rock":
49962
- return /* @__PURE__ */ jsxRuntime.jsx(RockFeature, { height: config.height, color });
49963
- case "bush":
49964
- return /* @__PURE__ */ jsxRuntime.jsx(BushFeature, { height: config.height, color });
49965
- case "house":
49966
- return /* @__PURE__ */ jsxRuntime.jsx(HouseFeature, { height: config.height, color });
49967
- case "tower":
49968
- return /* @__PURE__ */ jsxRuntime.jsx(TowerFeature, { height: config.height, color });
49969
- case "chest":
49970
- return /* @__PURE__ */ jsxRuntime.jsx(ChestFeature, { height: config.height, color });
49971
- default:
49972
- return /* @__PURE__ */ jsxRuntime.jsx(DefaultFeature, { height: config.height, color });
49973
- }
49974
- };
49975
- return /* @__PURE__ */ jsxRuntime.jsxs(
49976
- "group",
49977
- {
49978
- position,
49979
- scale: config.scale,
49980
- onClick,
49981
- onPointerEnter: () => onHover(true),
49982
- onPointerLeave: () => onHover(false),
49983
- userData: { type: "feature", featureId: feature.id, featureType: feature.type },
49984
- children: [
49985
- isSelected && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
49986
- /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
49987
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
49988
- ] }),
49989
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.01, 0], rotation: [-Math.PI / 2, 0, 0], children: [
49990
- /* @__PURE__ */ jsxRuntime.jsx("circleGeometry", { args: [0.35, 16] }),
49991
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#000000", transparent: true, opacity: 0.2 })
49992
- ] }),
49993
- renderGeometry()
49994
- ]
49995
- }
49996
- );
49997
- }
49998
- function FeatureGroup({
49999
- features,
50000
- cellSize = 1,
50001
- offsetX = 0,
50002
- offsetZ = 0,
50003
- onFeatureClick,
50004
- onFeatureHover,
50005
- selectedFeatureIds = []
50006
- }) {
50007
- return /* @__PURE__ */ jsxRuntime.jsx("group", { children: features.map((feature) => {
50008
- const x = (feature.x - offsetX) * cellSize;
50009
- const z = ((feature.z ?? feature.y ?? 0) - offsetZ) * cellSize;
50010
- const y = (feature.elevation ?? 0) * 0.1;
50011
- const isSelected = feature.id ? selectedFeatureIds.includes(feature.id) : false;
50012
- return /* @__PURE__ */ jsxRuntime.jsx(
50013
- FeatureVisual,
50014
- {
50015
- feature,
50016
- position: [x, y, z],
50017
- isSelected,
50018
- onClick: () => onFeatureClick?.(feature),
50019
- onHover: (hovered) => onFeatureHover?.(hovered ? feature : null)
50020
- },
50021
- feature.id ?? `feature-${feature.x}-${feature.y}`
50022
- );
50023
- }) });
50024
- }
50025
- function FeatureRenderer2(props) {
50026
- const insideCanvas = React74.useContext(fiber.context) != null;
50027
- if (insideCanvas) return /* @__PURE__ */ jsxRuntime.jsx(FeatureGroup, { ...props });
50028
- return /* @__PURE__ */ jsxRuntime.jsxs(fiber.Canvas, { camera: { position: [4, 4, 6], fov: 50 }, style: { width: "100%", height: 360 }, children: [
50029
- /* @__PURE__ */ jsxRuntime.jsx("ambientLight", { intensity: 0.6 }),
50030
- /* @__PURE__ */ jsxRuntime.jsx("directionalLight", { position: [5, 8, 5], intensity: 0.8 }),
50031
- /* @__PURE__ */ jsxRuntime.jsx(FeatureGroup, { ...props })
50032
- ] });
50033
- }
50034
50078
 
50035
50079
  // components/core/templates/index.ts
50036
50080
  init_DashboardLayout();
@@ -50090,7 +50134,6 @@ exports.EnemyPlate = EnemyPlate;
50090
50134
  exports.EventHandlerBoard = EventHandlerBoard;
50091
50135
  exports.EventLog = EventLog;
50092
50136
  exports.FEATURE_TYPES = FEATURE_TYPES;
50093
- exports.FeatureRenderer = FeatureRenderer2;
50094
50137
  exports.GameAudioProvider = GameAudioProvider;
50095
50138
  exports.GameAudioToggle = GameAudioToggle;
50096
50139
  exports.GameCanvas2D = GameCanvas2D;