@almadar/ui 5.29.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.
Files changed (37) hide show
  1. package/dist/avl/index.cjs +933 -6749
  2. package/dist/avl/index.js +934 -6750
  3. package/dist/components/core/atoms/Card.d.ts +2 -0
  4. package/dist/components/core/atoms/Input.d.ts +2 -0
  5. package/dist/components/core/atoms/Select.d.ts +18 -6
  6. package/dist/components/core/atoms/Spinner.d.ts +2 -0
  7. package/dist/components/core/atoms/index.d.ts +1 -1
  8. package/dist/components/core/molecules/DocumentViewer.d.ts +0 -2
  9. package/dist/components/core/molecules/Header.d.ts +0 -4
  10. package/dist/components/core/molecules/JsonTreeEditor.d.ts +3 -8
  11. package/dist/components/core/molecules/Menu.d.ts +4 -0
  12. package/dist/components/core/molecules/Navigation.d.ts +0 -2
  13. package/dist/components/core/molecules/PageHeader.d.ts +0 -2
  14. package/dist/components/core/molecules/PropertyInspector.d.ts +8 -1
  15. package/dist/components/core/molecules/index.d.ts +1 -1
  16. package/dist/components/core/organisms/index.d.ts +0 -1
  17. package/dist/components/core/templates/index.d.ts +0 -3
  18. package/dist/components/game/molecules/index.d.ts +0 -1
  19. package/dist/components/game/molecules/three/index.cjs +27 -2
  20. package/dist/components/game/molecules/three/index.js +27 -2
  21. package/dist/components/game/molecules/three/patterns.d.ts +20 -0
  22. package/dist/components/game/organisms/TraitSlot.d.ts +3 -1
  23. package/dist/components/game/organisms/types/isometric.d.ts +2 -0
  24. package/dist/components/index.cjs +1198 -1062
  25. package/dist/components/index.js +1201 -1064
  26. package/dist/docs/index.cjs +205 -172
  27. package/dist/docs/index.d.cts +4 -0
  28. package/dist/docs/index.js +146 -113
  29. package/dist/marketing/index.cjs +91 -54
  30. package/dist/marketing/index.d.cts +2 -0
  31. package/dist/marketing/index.js +58 -21
  32. package/dist/providers/index.cjs +563 -275
  33. package/dist/providers/index.js +563 -275
  34. package/dist/renderer/pattern-resolver.d.ts +2 -5
  35. package/dist/runtime/index.cjs +563 -275
  36. package/dist/runtime/index.js +563 -275
  37. package/package.json +16 -2
@@ -3163,6 +3163,8 @@ var init_Input = __esm({
3163
3163
  className,
3164
3164
  inputType,
3165
3165
  type: htmlType,
3166
+ label,
3167
+ helperText,
3166
3168
  error,
3167
3169
  leftIcon,
3168
3170
  rightIcon,
@@ -3218,82 +3220,95 @@ var init_Input = __esm({
3218
3220
  onClear?.();
3219
3221
  }
3220
3222
  };
3223
+ const wrapField = (field) => /* @__PURE__ */ jsxs("div", { className: "w-full", children: [
3224
+ label && /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-foreground mb-1", children: label }),
3225
+ field,
3226
+ (helperText || error) && /* @__PURE__ */ jsx("p", { className: cn("mt-1 text-xs", error ? "text-error" : "text-muted-foreground"), children: error ?? helperText })
3227
+ ] });
3221
3228
  if (type === "select") {
3222
- return /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
3223
- resolvedLeftIcon && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-muted-foreground", children: resolvedLeftIcon }),
3224
- /* @__PURE__ */ jsxs(
3225
- "select",
3229
+ return wrapField(
3230
+ /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
3231
+ resolvedLeftIcon && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-muted-foreground", children: resolvedLeftIcon }),
3232
+ /* @__PURE__ */ jsxs(
3233
+ "select",
3234
+ {
3235
+ ref,
3236
+ value,
3237
+ onChange: handleChange,
3238
+ className: cn(baseClassName, "appearance-none pr-10", className),
3239
+ ...props,
3240
+ children: [
3241
+ /* @__PURE__ */ jsx("option", { value: "", children: t("form.selectPlaceholder", { label: "" }) }),
3242
+ options?.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
3243
+ ]
3244
+ }
3245
+ ),
3246
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-muted-foreground", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-down", className: "h-icon-default w-icon-default" }) })
3247
+ ] })
3248
+ );
3249
+ }
3250
+ if (type === "textarea") {
3251
+ return wrapField(
3252
+ /* @__PURE__ */ jsx("div", { className: "relative w-full", children: /* @__PURE__ */ jsx(
3253
+ "textarea",
3226
3254
  {
3227
3255
  ref,
3228
3256
  value,
3229
3257
  onChange: handleChange,
3230
- className: cn(baseClassName, "appearance-none pr-10", className),
3231
- ...props,
3232
- children: [
3233
- /* @__PURE__ */ jsx("option", { value: "", children: t("form.selectPlaceholder", { label: "" }) }),
3234
- options?.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
3235
- ]
3258
+ rows: rows2,
3259
+ className: baseClassName,
3260
+ ...props
3236
3261
  }
3237
- ),
3238
- /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-muted-foreground", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-down", className: "h-icon-default w-icon-default" }) })
3239
- ] });
3240
- }
3241
- if (type === "textarea") {
3242
- return /* @__PURE__ */ jsx("div", { className: "relative w-full", children: /* @__PURE__ */ jsx(
3243
- "textarea",
3244
- {
3245
- ref,
3246
- value,
3247
- onChange: handleChange,
3248
- rows: rows2,
3249
- className: baseClassName,
3250
- ...props
3251
- }
3252
- ) });
3262
+ ) })
3263
+ );
3253
3264
  }
3254
3265
  if (type === "checkbox") {
3255
- return /* @__PURE__ */ jsx(
3256
- "input",
3257
- {
3258
- ref,
3259
- type: "checkbox",
3260
- checked: props.checked,
3261
- onChange: handleChange,
3262
- className: cn(
3263
- "h-icon-default w-icon-default rounded-sm",
3264
- "border-border",
3265
- "text-primary focus:ring-ring",
3266
- "disabled:opacity-50 disabled:cursor-not-allowed",
3267
- className
3268
- ),
3269
- ...props
3270
- }
3266
+ return wrapField(
3267
+ /* @__PURE__ */ jsx(
3268
+ "input",
3269
+ {
3270
+ ref,
3271
+ type: "checkbox",
3272
+ checked: props.checked,
3273
+ onChange: handleChange,
3274
+ className: cn(
3275
+ "h-icon-default w-icon-default rounded-sm",
3276
+ "border-border",
3277
+ "text-primary focus:ring-ring",
3278
+ "disabled:opacity-50 disabled:cursor-not-allowed",
3279
+ className
3280
+ ),
3281
+ ...props
3282
+ }
3283
+ )
3271
3284
  );
3272
3285
  }
3273
- return /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
3274
- resolvedLeftIcon && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-muted-foreground", children: resolvedLeftIcon }),
3275
- /* @__PURE__ */ jsx(
3276
- "input",
3277
- {
3278
- ref,
3279
- type,
3280
- value,
3281
- onChange: handleChange,
3282
- className: baseClassName,
3283
- ...props
3284
- }
3285
- ),
3286
- showClearButton && /* @__PURE__ */ jsx(
3287
- "button",
3288
- {
3289
- type: "button",
3290
- onClick: handleClear,
3291
- className: "absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground hover:text-foreground",
3292
- children: /* @__PURE__ */ jsx(Icon, { name: "x", className: "h-icon-default w-icon-default" })
3293
- }
3294
- ),
3295
- rightIcon && !showClearButton && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground", children: resolveIconNode(rightIcon, iconCls) })
3296
- ] });
3286
+ return wrapField(
3287
+ /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
3288
+ resolvedLeftIcon && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-muted-foreground", children: resolvedLeftIcon }),
3289
+ /* @__PURE__ */ jsx(
3290
+ "input",
3291
+ {
3292
+ ref,
3293
+ type,
3294
+ value,
3295
+ onChange: handleChange,
3296
+ className: baseClassName,
3297
+ ...props
3298
+ }
3299
+ ),
3300
+ showClearButton && /* @__PURE__ */ jsx(
3301
+ "button",
3302
+ {
3303
+ type: "button",
3304
+ onClick: handleClear,
3305
+ className: "absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground hover:text-foreground",
3306
+ children: /* @__PURE__ */ jsx(Icon, { name: "x", className: "h-icon-default w-icon-default" })
3307
+ }
3308
+ ),
3309
+ rightIcon && !showClearButton && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground", children: resolveIconNode(rightIcon, iconCls) })
3310
+ ] })
3311
+ );
3297
3312
  }
3298
3313
  );
3299
3314
  Input.displayName = "Input";
@@ -3364,6 +3379,190 @@ var init_Textarea = __esm({
3364
3379
  Textarea.displayName = "Textarea";
3365
3380
  }
3366
3381
  });
3382
+ function flatOptions(opts, groups) {
3383
+ const flat = opts ?? [];
3384
+ const grp = (groups ?? []).flatMap((g) => g.options);
3385
+ return [...flat, ...grp];
3386
+ }
3387
+ function NativeSelect({
3388
+ className,
3389
+ options,
3390
+ groups,
3391
+ placeholder,
3392
+ error,
3393
+ onChange,
3394
+ value,
3395
+ ...props
3396
+ }) {
3397
+ const eventBus = useEventBus();
3398
+ const handleChange = (e) => {
3399
+ if (typeof onChange === "string") {
3400
+ eventBus.emit(`UI:${onChange}`, { value: e.target.value });
3401
+ } else {
3402
+ onChange?.(e.target.value);
3403
+ }
3404
+ };
3405
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
3406
+ /* @__PURE__ */ jsxs(
3407
+ "select",
3408
+ {
3409
+ onChange: handleChange,
3410
+ value,
3411
+ className: cn(
3412
+ "block w-full border-[length:var(--border-width)] shadow-sm appearance-none",
3413
+ "px-3 py-2 pr-10 text-sm text-foreground font-medium",
3414
+ "bg-card",
3415
+ "focus:outline-none focus:ring-2 focus:ring-offset-0 focus:ring-ring",
3416
+ "disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
3417
+ error ? "border-error focus:border-error" : "border-border focus:border-primary",
3418
+ className
3419
+ ),
3420
+ ...props,
3421
+ children: [
3422
+ placeholder && /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }),
3423
+ options?.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value)),
3424
+ groups?.map((group) => /* @__PURE__ */ jsx("optgroup", { label: group.label, children: group.options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value)) }, group.label))
3425
+ ]
3426
+ }
3427
+ ),
3428
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-down", className: "h-icon-default w-icon-default text-foreground" }) })
3429
+ ] });
3430
+ }
3431
+ function RichSelect({
3432
+ className,
3433
+ options,
3434
+ groups,
3435
+ placeholder,
3436
+ error,
3437
+ onChange,
3438
+ value,
3439
+ multiple,
3440
+ searchable,
3441
+ clearable,
3442
+ disabled
3443
+ }) {
3444
+ const eventBus = useEventBus();
3445
+ const [open, setOpen] = useState(false);
3446
+ const [search, setSearch] = useState("");
3447
+ const containerRef = useRef(null);
3448
+ const selected = multiple ? Array.isArray(value) ? value : value ? [value] : [] : value ? [value] : [];
3449
+ const all = flatOptions(options, groups);
3450
+ const filtered = searchable && search ? all.filter((o) => o.label.toLowerCase().includes(search.toLowerCase())) : all;
3451
+ const toggle = (optValue) => {
3452
+ let next;
3453
+ if (multiple) {
3454
+ next = selected.includes(optValue) ? selected.filter((v) => v !== optValue) : [...selected, optValue];
3455
+ } else {
3456
+ next = optValue;
3457
+ setOpen(false);
3458
+ }
3459
+ if (typeof onChange === "string") {
3460
+ eventBus.emit(`UI:${onChange}`, { value: next });
3461
+ } else {
3462
+ onChange?.(next);
3463
+ }
3464
+ };
3465
+ const clear = (e) => {
3466
+ e.stopPropagation();
3467
+ const next = multiple ? [] : "";
3468
+ if (typeof onChange === "string") {
3469
+ eventBus.emit(`UI:${onChange}`, { value: next });
3470
+ } else {
3471
+ onChange?.(next);
3472
+ }
3473
+ };
3474
+ useEffect(() => {
3475
+ const handler = (e) => {
3476
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
3477
+ setOpen(false);
3478
+ setSearch("");
3479
+ }
3480
+ };
3481
+ document.addEventListener("mousedown", handler);
3482
+ return () => document.removeEventListener("mousedown", handler);
3483
+ }, []);
3484
+ const displayLabel = selected.length === 0 ? placeholder ?? "" : multiple ? `${selected.length} selected` : all.find((o) => o.value === selected[0])?.label ?? selected[0];
3485
+ const hasValue = selected.length > 0;
3486
+ const renderOptions = (opts) => opts.map((opt) => /* @__PURE__ */ jsxs(
3487
+ "button",
3488
+ {
3489
+ type: "button",
3490
+ disabled: opt.disabled,
3491
+ onClick: () => !opt.disabled && toggle(opt.value),
3492
+ className: cn(
3493
+ "w-full flex items-center justify-between px-3 py-1.5 text-sm text-start",
3494
+ "hover:bg-muted transition-colors",
3495
+ "disabled:opacity-50 disabled:cursor-not-allowed",
3496
+ selected.includes(opt.value) && "text-primary font-medium"
3497
+ ),
3498
+ children: [
3499
+ /* @__PURE__ */ jsx("span", { children: opt.label }),
3500
+ selected.includes(opt.value) && /* @__PURE__ */ jsx(Icon, { name: "check", className: "h-icon-default w-icon-default" })
3501
+ ]
3502
+ },
3503
+ opt.value
3504
+ ));
3505
+ return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: cn("relative w-full", className), children: [
3506
+ /* @__PURE__ */ jsx(
3507
+ "button",
3508
+ {
3509
+ type: "button",
3510
+ disabled,
3511
+ onClick: () => !disabled && setOpen((o) => !o),
3512
+ className: cn(
3513
+ "block w-full border-[length:var(--border-width)] shadow-sm",
3514
+ "px-3 py-2 pr-10 text-sm text-start font-medium",
3515
+ "bg-card rounded-sm",
3516
+ "focus:outline-none focus:ring-2 focus:ring-offset-0 focus:ring-ring",
3517
+ "disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
3518
+ error ? "border-error focus:border-error" : "border-border focus:border-primary",
3519
+ !hasValue && "text-muted-foreground"
3520
+ ),
3521
+ children: displayLabel
3522
+ }
3523
+ ),
3524
+ /* @__PURE__ */ jsxs("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center gap-1 pointer-events-none", children: [
3525
+ clearable && hasValue && /* @__PURE__ */ jsx(
3526
+ "button",
3527
+ {
3528
+ type: "button",
3529
+ onClick: clear,
3530
+ className: "pointer-events-auto text-muted-foreground hover:text-foreground",
3531
+ children: /* @__PURE__ */ jsx(Icon, { name: "x", className: "h-icon-default w-icon-default" })
3532
+ }
3533
+ ),
3534
+ /* @__PURE__ */ jsx(Icon, { name: "chevron-down", className: "h-icon-default w-icon-default text-foreground" })
3535
+ ] }),
3536
+ open && /* @__PURE__ */ jsxs("div", { className: cn(
3537
+ "absolute z-50 mt-1 w-full",
3538
+ "bg-card border-[length:var(--border-width)] border-border",
3539
+ "rounded-sm shadow-elevation-popover py-1 max-h-60 overflow-y-auto"
3540
+ ), children: [
3541
+ searchable && /* @__PURE__ */ jsx("div", { className: "px-2 pb-1 border-b border-border", children: /* @__PURE__ */ jsx(
3542
+ "input",
3543
+ {
3544
+ autoFocus: true,
3545
+ type: "text",
3546
+ value: search,
3547
+ onChange: (e) => setSearch(e.target.value),
3548
+ placeholder: "Search\u2026",
3549
+ className: cn(
3550
+ "w-full px-2 py-1 text-sm bg-transparent",
3551
+ "focus:outline-none text-foreground placeholder:text-muted-foreground"
3552
+ )
3553
+ }
3554
+ ) }),
3555
+ groups && groups.length > 0 ? groups.map((g) => {
3556
+ const groupFiltered = searchable && search ? g.options.filter((o) => o.label.toLowerCase().includes(search.toLowerCase())) : g.options;
3557
+ if (groupFiltered.length === 0) return null;
3558
+ return /* @__PURE__ */ jsxs("div", { children: [
3559
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-1 text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: g.label }),
3560
+ renderOptions(groupFiltered)
3561
+ ] }, g.label);
3562
+ }) : renderOptions(filtered)
3563
+ ] })
3564
+ ] });
3565
+ }
3367
3566
  var Select;
3368
3567
  var init_Select = __esm({
3369
3568
  "components/core/atoms/Select.tsx"() {
@@ -3371,47 +3570,12 @@ var init_Select = __esm({
3371
3570
  init_Icon();
3372
3571
  init_useEventBus();
3373
3572
  Select = React79__default.forwardRef(
3374
- ({ className, options, placeholder, error, onChange, ...props }, ref) => {
3375
- const eventBus = useEventBus();
3376
- const handleChange = (e) => {
3377
- if (typeof onChange === "string") {
3378
- eventBus.emit(`UI:${onChange}`, { value: e.target.value });
3379
- } else {
3380
- onChange?.(e);
3381
- }
3382
- };
3383
- return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
3384
- /* @__PURE__ */ jsxs(
3385
- "select",
3386
- {
3387
- ref,
3388
- onChange: handleChange,
3389
- className: cn(
3390
- "block w-full border-[length:var(--border-width)] shadow-sm appearance-none",
3391
- "px-3 py-2 pr-10 text-sm text-foreground font-medium",
3392
- "bg-card",
3393
- "focus:outline-none focus:ring-2 focus:ring-offset-0 focus:ring-ring",
3394
- "disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
3395
- error ? "border-error focus:border-error" : "border-border focus:border-primary",
3396
- className
3397
- ),
3398
- ...props,
3399
- children: [
3400
- placeholder && /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }),
3401
- options.map((option) => /* @__PURE__ */ jsx(
3402
- "option",
3403
- {
3404
- value: option.value,
3405
- disabled: option.disabled,
3406
- children: option.label
3407
- },
3408
- option.value
3409
- ))
3410
- ]
3411
- }
3412
- ),
3413
- /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-down", className: "h-icon-default w-icon-default text-foreground" }) })
3414
- ] });
3573
+ (props, _ref) => {
3574
+ const { multiple, searchable, clearable } = props;
3575
+ if (multiple || searchable || clearable) {
3576
+ return /* @__PURE__ */ jsx(RichSelect, { ...props });
3577
+ }
3578
+ return /* @__PURE__ */ jsx(NativeSelect, { ...props });
3415
3579
  }
3416
3580
  );
3417
3581
  Select.displayName = "Select";
@@ -3465,11 +3629,54 @@ var init_Checkbox = __esm({
3465
3629
  Checkbox.displayName = "Checkbox";
3466
3630
  }
3467
3631
  });
3632
+ var sizeStyles3, Spinner;
3633
+ var init_Spinner = __esm({
3634
+ "components/core/atoms/Spinner.tsx"() {
3635
+ init_cn();
3636
+ init_Icon();
3637
+ sizeStyles3 = {
3638
+ xs: "h-3 w-3",
3639
+ sm: "h-icon-default w-icon-default",
3640
+ md: "h-6 w-6",
3641
+ lg: "h-8 w-8"
3642
+ };
3643
+ Spinner = React79__default.forwardRef(
3644
+ ({ className, size = "md", overlay, ...props }, ref) => {
3645
+ if (overlay) {
3646
+ return /* @__PURE__ */ jsx(
3647
+ "div",
3648
+ {
3649
+ ref,
3650
+ className: cn(
3651
+ "absolute inset-0 z-10 flex items-center justify-center",
3652
+ "bg-background/60 backdrop-blur-sm",
3653
+ className
3654
+ ),
3655
+ ...props,
3656
+ children: /* @__PURE__ */ jsx(Icon, { name: "loader", className: cn("animate-spin text-foreground", sizeStyles3[size]) })
3657
+ }
3658
+ );
3659
+ }
3660
+ return /* @__PURE__ */ jsx(
3661
+ "div",
3662
+ {
3663
+ ref,
3664
+ className: cn("text-foreground", className),
3665
+ ...props,
3666
+ children: /* @__PURE__ */ jsx(Icon, { name: "loader", className: cn("animate-spin", sizeStyles3[size]) })
3667
+ }
3668
+ );
3669
+ }
3670
+ );
3671
+ Spinner.displayName = "Spinner";
3672
+ }
3673
+ });
3468
3674
  var variantStyles4, paddingStyles2, shadowStyles2, lookStyles2, Card, CardHeader, CardTitle, CardContent, CardBody, CardFooter;
3469
3675
  var init_Card = __esm({
3470
3676
  "components/core/atoms/Card.tsx"() {
3471
3677
  init_cn();
3472
3678
  init_useEventBus();
3679
+ init_Spinner();
3473
3680
  variantStyles4 = {
3474
3681
  default: [
3475
3682
  "bg-card",
@@ -3534,6 +3741,7 @@ var init_Card = __esm({
3534
3741
  look = "elevated",
3535
3742
  children,
3536
3743
  action,
3744
+ loading,
3537
3745
  onClick,
3538
3746
  ...props
3539
3747
  }, ref) => {
@@ -3547,7 +3755,7 @@ var init_Card = __esm({
3547
3755
  {
3548
3756
  ref,
3549
3757
  className: cn(
3550
- "rounded-container",
3758
+ "rounded-container relative",
3551
3759
  "transition-all duration-[var(--transition-normal)]",
3552
3760
  variantStyles4[variant],
3553
3761
  paddingStyles2[padding],
@@ -3558,6 +3766,7 @@ var init_Card = __esm({
3558
3766
  onClick: handleClick,
3559
3767
  ...props,
3560
3768
  children: [
3769
+ loading && /* @__PURE__ */ jsx(Spinner, { overlay: true, size: "md" }),
3561
3770
  (title || subtitle) && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
3562
3771
  title && /* @__PURE__ */ jsx("h3", { className: "text-lg text-card-foreground font-bold", children: title }),
3563
3772
  subtitle && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1", children: subtitle })
@@ -3599,7 +3808,7 @@ var init_Card = __esm({
3599
3808
  CardFooter.displayName = "CardFooter";
3600
3809
  }
3601
3810
  });
3602
- var variantStyles5, sizeStyles3, iconSizes, FilterPill;
3811
+ var variantStyles5, sizeStyles4, iconSizes, FilterPill;
3603
3812
  var init_FilterPill = __esm({
3604
3813
  "components/core/atoms/FilterPill.tsx"() {
3605
3814
  init_cn();
@@ -3633,7 +3842,7 @@ var init_FilterPill = __esm({
3633
3842
  "border-[length:var(--border-width-thin)] border-border"
3634
3843
  ].join(" ")
3635
3844
  };
3636
- sizeStyles3 = {
3845
+ sizeStyles4 = {
3637
3846
  sm: "px-2 py-0.5 text-xs",
3638
3847
  md: "px-2.5 py-1 text-sm",
3639
3848
  lg: "px-3 py-1.5 text-base"
@@ -3677,7 +3886,7 @@ var init_FilterPill = __esm({
3677
3886
  className: cn(
3678
3887
  "inline-flex items-center gap-1 font-bold rounded-pill",
3679
3888
  variantStyles5[variant],
3680
- sizeStyles3[size],
3889
+ sizeStyles4[size],
3681
3890
  (onClick || clickEvent) && "cursor-pointer",
3682
3891
  className
3683
3892
  ),
@@ -3709,33 +3918,6 @@ var init_FilterPill = __esm({
3709
3918
  FilterPill.displayName = "FilterPill";
3710
3919
  }
3711
3920
  });
3712
- var sizeStyles4, Spinner;
3713
- var init_Spinner = __esm({
3714
- "components/core/atoms/Spinner.tsx"() {
3715
- init_cn();
3716
- init_Icon();
3717
- sizeStyles4 = {
3718
- xs: "h-3 w-3",
3719
- sm: "h-icon-default w-icon-default",
3720
- md: "h-6 w-6",
3721
- lg: "h-8 w-8"
3722
- };
3723
- Spinner = React79__default.forwardRef(
3724
- ({ className, size = "md", ...props }, ref) => {
3725
- return /* @__PURE__ */ jsx(
3726
- "div",
3727
- {
3728
- ref,
3729
- className: cn("text-foreground", className),
3730
- ...props,
3731
- children: /* @__PURE__ */ jsx(Icon, { name: "loader", className: cn("animate-spin", sizeStyles4[size]) })
3732
- }
3733
- );
3734
- }
3735
- );
3736
- Spinner.displayName = "Spinner";
3737
- }
3738
- });
3739
3921
  function generateInitials(name) {
3740
3922
  const parts = name.trim().split(/\s+/);
3741
3923
  if (parts.length === 1) {
@@ -16033,30 +16215,30 @@ var init_BranchingLogicBuilder = __esm({
16033
16215
  if (!sourceQuestion?.optionValues) return [];
16034
16216
  return sourceQuestion.optionValues.map((v) => ({ value: v, label: v }));
16035
16217
  }, [sourceQuestion]);
16036
- const handleSource = (e) => {
16037
- onChange({ ...rule, sourceQuestionId: e.target.value });
16218
+ const handleSource = (v) => {
16219
+ onChange({ ...rule, sourceQuestionId: v });
16038
16220
  };
16039
- const handleOperator = (e) => {
16040
- const next = e.target.value;
16221
+ const handleOperator = (v) => {
16222
+ const next = v;
16041
16223
  const nextValue = next === "in" && !Array.isArray(rule.value) ? rule.value ? [rule.value] : [] : next !== "in" && Array.isArray(rule.value) ? rule.value[0] ?? "" : rule.value;
16042
16224
  onChange({ ...rule, operator: next, value: nextValue });
16043
16225
  };
16044
16226
  const handleScalarValue = (e) => {
16045
16227
  onChange({ ...rule, value: e.target.value });
16046
16228
  };
16047
- const handleAddChip = (e) => {
16048
- const v = e.target.value;
16049
- if (!v) return;
16229
+ const handleAddChip = (v) => {
16230
+ const val = v;
16231
+ if (!val) return;
16050
16232
  const current = Array.isArray(rule.value) ? rule.value : [];
16051
- if (current.includes(v)) return;
16052
- onChange({ ...rule, value: [...current, v] });
16233
+ if (current.includes(val)) return;
16234
+ onChange({ ...rule, value: [...current, val] });
16053
16235
  };
16054
16236
  const handleRemoveChip = (chip) => {
16055
16237
  const current = Array.isArray(rule.value) ? rule.value : [];
16056
16238
  onChange({ ...rule, value: current.filter((c) => c !== chip) });
16057
16239
  };
16058
- const handleTarget = (e) => {
16059
- onChange({ ...rule, targetQuestionId: e.target.value });
16240
+ const handleTarget = (v) => {
16241
+ onChange({ ...rule, targetQuestionId: v });
16060
16242
  };
16061
16243
  const isMulti = rule.operator === "in";
16062
16244
  const chips = Array.isArray(rule.value) ? rule.value : [];
@@ -16137,7 +16319,7 @@ var init_BranchingLogicBuilder = __esm({
16137
16319
  options: valueOptions,
16138
16320
  value: scalarValue,
16139
16321
  placeholder: t("branchingLogic.selectValue"),
16140
- onChange: (e) => onChange({ ...rule, value: e.target.value }),
16322
+ onChange: (v) => onChange({ ...rule, value: v }),
16141
16323
  disabled: readOnly
16142
16324
  }
16143
16325
  ) : /* @__PURE__ */ jsx(
@@ -18569,7 +18751,7 @@ var init_Pagination = __esm({
18569
18751
  Select,
18570
18752
  {
18571
18753
  value: String(pageSize),
18572
- onChange: (e) => handlePageSizeChange(Number(e.target.value)),
18754
+ onChange: (v) => handlePageSizeChange(Number(v)),
18573
18755
  options: pageSizeOptions.map((size) => ({
18574
18756
  value: String(size),
18575
18757
  label: String(size)
@@ -21495,7 +21677,84 @@ var init_DashboardLayout = __esm({
21495
21677
  NavLinkBottom.displayName = "NavLinkBottom";
21496
21678
  }
21497
21679
  });
21498
- var Menu;
21680
+ function computeMenuStyle(position, triggerRect) {
21681
+ const isTop = position.startsWith("top");
21682
+ const isRight = position.endsWith("right") || position.endsWith("end");
21683
+ if (isTop) {
21684
+ return {
21685
+ top: triggerRect.top - MENU_GAP,
21686
+ transform: "translateY(-100%)",
21687
+ ...isRight ? { right: window.innerWidth - triggerRect.right } : { left: triggerRect.left }
21688
+ };
21689
+ }
21690
+ return {
21691
+ top: triggerRect.bottom + MENU_GAP,
21692
+ ...isRight ? { right: window.innerWidth - triggerRect.right } : { left: triggerRect.left }
21693
+ };
21694
+ }
21695
+ function SubMenu({
21696
+ items,
21697
+ itemRef,
21698
+ direction,
21699
+ eventBus
21700
+ }) {
21701
+ const [rect, setRect] = useState(null);
21702
+ useEffect(() => {
21703
+ if (itemRef) {
21704
+ setRect(itemRef.getBoundingClientRect());
21705
+ }
21706
+ }, [itemRef]);
21707
+ if (!rect) return null;
21708
+ const isRtl = direction === "rtl";
21709
+ const style = {
21710
+ top: rect.top,
21711
+ ...isRtl ? { right: window.innerWidth - rect.left } : { left: rect.right }
21712
+ };
21713
+ const panel = /* @__PURE__ */ jsx(
21714
+ "div",
21715
+ {
21716
+ className: cn("fixed z-50", menuContainerStyles),
21717
+ style,
21718
+ children: items.map((item, index) => {
21719
+ const isDivider = item.id === "divider" || item.label === "divider";
21720
+ const itemId = item.id ?? `item-${item.label.toLowerCase().replace(/\s+/g, "-")}-${index}`;
21721
+ const isDanger = item.variant === "danger";
21722
+ if (isDivider) {
21723
+ return /* @__PURE__ */ jsx(Divider, { className: "my-1" }, `divider-${index}`);
21724
+ }
21725
+ return /* @__PURE__ */ jsxs(
21726
+ Box,
21727
+ {
21728
+ as: "button",
21729
+ onClick: () => {
21730
+ if (item.disabled) return;
21731
+ if (item.event) eventBus.emit(`UI:${item.event}`, { itemId, label: item.label });
21732
+ item.onClick?.();
21733
+ },
21734
+ "aria-disabled": item.disabled || void 0,
21735
+ "data-testid": item.event ? `action-${item.event}` : void 0,
21736
+ className: cn(
21737
+ "w-full flex items-center gap-3 px-4 py-2 text-start",
21738
+ "text-sm transition-colors",
21739
+ "hover:bg-muted focus:outline-none focus:bg-muted",
21740
+ "disabled:opacity-50 disabled:cursor-not-allowed",
21741
+ item.disabled && "cursor-not-allowed",
21742
+ isDanger && "text-error hover:bg-error/10"
21743
+ ),
21744
+ children: [
21745
+ item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: item.icon, size: "sm", className: "flex-shrink-0" }) : /* @__PURE__ */ jsx(Icon, { icon: item.icon, size: "sm", className: "flex-shrink-0" })),
21746
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: cn("flex-1", isDanger && "text-red-600"), children: item.label }),
21747
+ item.badge !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-auto text-xs font-medium", children: item.badge })
21748
+ ]
21749
+ },
21750
+ itemId
21751
+ );
21752
+ })
21753
+ }
21754
+ );
21755
+ return typeof document !== "undefined" ? createPortal(panel, document.body) : panel;
21756
+ }
21757
+ var MENU_GAP, menuContainerStyles, Menu;
21499
21758
  var init_Menu = __esm({
21500
21759
  "components/core/molecules/Menu.tsx"() {
21501
21760
  "use client";
@@ -21506,16 +21765,27 @@ var init_Menu = __esm({
21506
21765
  init_Badge();
21507
21766
  init_cn();
21508
21767
  init_useEventBus();
21768
+ MENU_GAP = 4;
21769
+ menuContainerStyles = cn(
21770
+ "bg-card",
21771
+ "border-[length:var(--border-width)] border-border",
21772
+ "shadow-elevation-popover",
21773
+ "rounded-sm",
21774
+ "min-w-0 sm:min-w-[200px] max-w-[calc(100vw-1rem)] py-1"
21775
+ );
21509
21776
  Menu = ({
21510
21777
  trigger,
21511
21778
  items,
21512
21779
  position = "bottom-left",
21513
- className
21780
+ className,
21781
+ header,
21782
+ footer
21514
21783
  }) => {
21515
21784
  const eventBus = useEventBus();
21516
- const { t, direction } = useTranslate();
21785
+ const { direction } = useTranslate();
21517
21786
  const [isOpen, setIsOpen] = useState(false);
21518
21787
  const [activeSubMenu, setActiveSubMenu] = useState(null);
21788
+ const [activeSubMenuRef, setActiveSubMenuRef] = useState(null);
21519
21789
  const [triggerRect, setTriggerRect] = useState(null);
21520
21790
  const triggerRef = useRef(null);
21521
21791
  const menuRef = useRef(null);
@@ -21530,13 +21800,14 @@ var init_Menu = __esm({
21530
21800
  }
21531
21801
  setIsOpen(!isOpen);
21532
21802
  setActiveSubMenu(null);
21803
+ setActiveSubMenuRef(null);
21533
21804
  };
21534
- const handleItemClick = (item) => {
21805
+ const handleItemClick = (item, itemId) => {
21535
21806
  if (item.disabled) return;
21536
21807
  if (item.subMenu && item.subMenu.length > 0) {
21537
- setActiveSubMenu(item.id ?? null);
21808
+ setActiveSubMenu(itemId);
21538
21809
  } else {
21539
- if (item.event) eventBus.emit(`UI:${item.event}`, { itemId: item.id, label: item.label });
21810
+ if (item.event) eventBus.emit(`UI:${item.event}`, { itemId, label: item.label });
21540
21811
  item.onClick?.();
21541
21812
  setIsOpen(false);
21542
21813
  }
@@ -21551,22 +21822,12 @@ var init_Menu = __esm({
21551
21822
  if (isOpen && menuRef.current && !menuRef.current.contains(e.target) && triggerRef.current && !triggerRef.current.contains(e.target)) {
21552
21823
  setIsOpen(false);
21553
21824
  setActiveSubMenu(null);
21825
+ setActiveSubMenuRef(null);
21554
21826
  }
21555
21827
  };
21556
21828
  document.addEventListener("mousedown", handleClickOutside);
21557
21829
  return () => document.removeEventListener("mousedown", handleClickOutside);
21558
21830
  }, [isOpen]);
21559
- const positionClasses = {
21560
- "top-left": "bottom-full left-0 mb-2",
21561
- "top-right": "bottom-full right-0 mb-2",
21562
- "bottom-left": "top-full left-0 mt-2",
21563
- "bottom-right": "top-full right-0 mt-2",
21564
- // Aliases for pattern compatibility
21565
- "top-start": "bottom-full left-0 mb-2",
21566
- "top-end": "bottom-full right-0 mb-2",
21567
- "bottom-start": "top-full left-0 mt-2",
21568
- "bottom-end": "top-full right-0 mt-2"
21569
- };
21570
21831
  const rtlMirror = {
21571
21832
  "top-left": "top-right",
21572
21833
  "top-right": "top-left",
@@ -21578,7 +21839,6 @@ var init_Menu = __esm({
21578
21839
  "bottom-end": "bottom-start"
21579
21840
  };
21580
21841
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
21581
- const subMenuSideClass = direction === "rtl" ? "right-full mr-2" : "left-full ml-2";
21582
21842
  const triggerChild = React79__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
21583
21843
  const triggerElement = React79__default.cloneElement(
21584
21844
  triggerChild,
@@ -21587,94 +21847,87 @@ var init_Menu = __esm({
21587
21847
  onClick: handleToggle
21588
21848
  }
21589
21849
  );
21590
- const menuContainerStyles = cn(
21591
- "bg-card",
21592
- "border-[length:var(--border-width)] border-border",
21593
- "shadow-elevation-popover",
21594
- "rounded-sm",
21595
- "min-w-0 sm:min-w-[200px] max-w-[calc(100vw-1rem)] py-1"
21596
- );
21597
- const renderMenuItem = (item, hasSubMenu, index) => {
21850
+ const renderMenuItems = (menuItems) => menuItems.map((item, index) => {
21851
+ const isDivider = item.id === "divider" || item.label === "divider";
21598
21852
  const itemId = item.id ?? `item-${item.label.toLowerCase().replace(/\s+/g, "-")}-${index}`;
21853
+ const hasSubMenu = !!(item.subMenu && item.subMenu.length > 0);
21599
21854
  const isDanger = item.variant === "danger";
21600
- return /* @__PURE__ */ jsx(
21601
- Box,
21602
- {
21603
- as: "button",
21604
- onClick: () => !item.disabled && handleItemClick({ ...item, id: itemId }),
21605
- "aria-disabled": item.disabled || void 0,
21606
- onMouseEnter: () => hasSubMenu && setActiveSubMenu(itemId),
21607
- "data-testid": item.event ? `action-${item.event}` : void 0,
21608
- className: cn(
21609
- "w-full flex items-center justify-between gap-3 px-4 py-2 text-start",
21610
- "text-sm transition-colors",
21611
- "hover:bg-muted",
21612
- "focus:outline-none focus:bg-muted",
21613
- "disabled:opacity-50 disabled:cursor-not-allowed",
21614
- item.disabled && "cursor-not-allowed",
21615
- isDanger && "text-error hover:bg-error/10"
21616
- ),
21617
- children: /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-3 flex-1 min-w-0", children: [
21618
- item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: item.icon, size: "sm", className: "flex-shrink-0" }) : /* @__PURE__ */ jsx(Icon, { icon: item.icon, size: "sm", className: "flex-shrink-0" })),
21619
- /* @__PURE__ */ jsx(
21620
- Typography,
21621
- {
21622
- variant: "small",
21623
- className: cn("flex-1", isDanger && "text-red-600"),
21624
- children: item.label
21855
+ if (isDivider) {
21856
+ return /* @__PURE__ */ jsx(Divider, { className: "my-1" }, `divider-${index}`);
21857
+ }
21858
+ return /* @__PURE__ */ jsxs(Box, { children: [
21859
+ /* @__PURE__ */ jsx(
21860
+ Box,
21861
+ {
21862
+ as: "button",
21863
+ onClick: () => handleItemClick({ ...item, id: itemId }, itemId),
21864
+ "aria-disabled": item.disabled || void 0,
21865
+ onMouseEnter: (e) => {
21866
+ if (hasSubMenu) {
21867
+ setActiveSubMenu(itemId);
21868
+ setActiveSubMenuRef(e.currentTarget);
21625
21869
  }
21870
+ },
21871
+ "data-testid": item.event ? `action-${item.event}` : void 0,
21872
+ className: cn(
21873
+ "w-full flex items-center justify-between gap-3 px-4 py-2 text-start",
21874
+ "text-sm transition-colors",
21875
+ "hover:bg-muted",
21876
+ "focus:outline-none focus:bg-muted",
21877
+ "disabled:opacity-50 disabled:cursor-not-allowed",
21878
+ item.disabled && "cursor-not-allowed",
21879
+ isDanger && "text-error hover:bg-error/10"
21626
21880
  ),
21627
- item.badge !== void 0 && /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: item.badge }),
21628
- hasSubMenu && /* @__PURE__ */ jsx(Icon, { name: direction === "rtl" ? "chevron-left" : "chevron-right", size: "sm", className: "flex-shrink-0" })
21629
- ] })
21630
- },
21631
- itemId
21632
- );
21633
- };
21634
- const renderMenuItems = (menuItems) => {
21635
- return menuItems.map((item, index) => {
21636
- const hasSubMenu = item.subMenu && item.subMenu.length > 0;
21637
- const isDivider = item.id === "divider" || item.label === "divider";
21638
- const itemId = item.id ?? `item-${item.label.toLowerCase().replace(/\s+/g, "-")}-${index}`;
21639
- if (isDivider) {
21640
- return /* @__PURE__ */ jsx(Divider, { className: "my-1" }, `divider-${index}`);
21641
- }
21642
- return /* @__PURE__ */ jsxs(Box, { children: [
21643
- renderMenuItem(item, !!hasSubMenu, index),
21644
- hasSubMenu && activeSubMenu === itemId && item.subMenu && /* @__PURE__ */ jsx(
21645
- Box,
21646
- {
21647
- className: cn(
21648
- "absolute top-0 z-50",
21649
- subMenuSideClass,
21650
- menuContainerStyles
21881
+ children: /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-3 flex-1 min-w-0", children: [
21882
+ item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: item.icon, size: "sm", className: "flex-shrink-0" }) : /* @__PURE__ */ jsx(Icon, { icon: item.icon, size: "sm", className: "flex-shrink-0" })),
21883
+ /* @__PURE__ */ jsx(
21884
+ Typography,
21885
+ {
21886
+ variant: "small",
21887
+ className: cn("flex-1", isDanger && "text-red-600"),
21888
+ children: item.label
21889
+ }
21651
21890
  ),
21652
- children: renderMenuItems(item.subMenu)
21653
- }
21654
- )
21655
- ] }, itemId);
21656
- });
21657
- };
21658
- return /* @__PURE__ */ jsxs(Box, { className: "relative", children: [
21891
+ item.badge !== void 0 && /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: item.badge }),
21892
+ hasSubMenu && /* @__PURE__ */ jsx(
21893
+ Icon,
21894
+ {
21895
+ name: direction === "rtl" ? "chevron-left" : "chevron-right",
21896
+ size: "sm",
21897
+ className: "flex-shrink-0"
21898
+ }
21899
+ )
21900
+ ] })
21901
+ }
21902
+ ),
21903
+ hasSubMenu && activeSubMenu === itemId && item.subMenu && /* @__PURE__ */ jsx(
21904
+ SubMenu,
21905
+ {
21906
+ items: item.subMenu,
21907
+ itemRef: activeSubMenuRef,
21908
+ direction,
21909
+ eventBus
21910
+ }
21911
+ )
21912
+ ] }, itemId);
21913
+ });
21914
+ const panel = isOpen && triggerRect ? /* @__PURE__ */ jsxs(
21915
+ "div",
21916
+ {
21917
+ ref: menuRef,
21918
+ className: cn("fixed z-50", menuContainerStyles, className),
21919
+ style: computeMenuStyle(effectivePosition, triggerRect),
21920
+ role: "menu",
21921
+ children: [
21922
+ header && /* @__PURE__ */ jsx("div", { className: "px-4 py-2 border-b border-border", children: header }),
21923
+ renderMenuItems(items),
21924
+ footer && /* @__PURE__ */ jsx("div", { className: "px-4 py-2 border-t border-border", children: footer })
21925
+ ]
21926
+ }
21927
+ ) : null;
21928
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
21659
21929
  triggerElement,
21660
- isOpen && triggerRect && /* @__PURE__ */ jsx(
21661
- Box,
21662
- {
21663
- ref: menuRef,
21664
- className: cn(
21665
- "absolute z-50",
21666
- menuContainerStyles,
21667
- positionClasses[effectivePosition],
21668
- className
21669
- ),
21670
- style: {
21671
- left: effectivePosition.includes("left") ? 0 : "auto",
21672
- right: effectivePosition.includes("right") ? 0 : "auto"
21673
- },
21674
- role: "menu",
21675
- children: renderMenuItems(items)
21676
- }
21677
- )
21930
+ panel && typeof document !== "undefined" ? createPortal(panel, document.body) : panel
21678
21931
  ] });
21679
21932
  };
21680
21933
  Menu.displayName = "Menu";
@@ -23428,7 +23681,7 @@ var init_FilterGroup = __esm({
23428
23681
  Select,
23429
23682
  {
23430
23683
  value: selectedValues[filter.field] || "all",
23431
- onChange: (e) => handleFilterSelect(filter.field, e.target.value),
23684
+ onChange: (v) => handleFilterSelect(filter.field, v),
23432
23685
  options: [
23433
23686
  { value: "all", label: t("filterGroup.all") },
23434
23687
  ...filter.options?.map((opt) => ({
@@ -23511,7 +23764,7 @@ var init_FilterGroup = __esm({
23511
23764
  Select,
23512
23765
  {
23513
23766
  value: selectedValues[filter.field] || "all",
23514
- onChange: (e) => handleFilterSelect(filter.field, e.target.value),
23767
+ onChange: (v) => handleFilterSelect(filter.field, v),
23515
23768
  options: [
23516
23769
  { value: "all", label: t("filterGroup.allOf", { label: filter.label }) },
23517
23770
  ...filter.options?.map((opt) => ({
@@ -23629,7 +23882,7 @@ var init_FilterGroup = __esm({
23629
23882
  Select,
23630
23883
  {
23631
23884
  value: selectedValues[filter.field] || "all",
23632
- onChange: (e) => handleFilterSelect(filter.field, e.target.value),
23885
+ onChange: (v) => handleFilterSelect(filter.field, v),
23633
23886
  options: [
23634
23887
  { value: "all", label: t("filterGroup.all") },
23635
23888
  ...filter.options?.map((opt) => ({
@@ -27811,13 +28064,13 @@ var init_MapView = __esm({
27811
28064
  shadowSize: [41, 41]
27812
28065
  });
27813
28066
  L.Marker.prototype.options.icon = defaultIcon;
27814
- const { useEffect: useEffect72, useRef: useRef66, useCallback: useCallback112, useState: useState102 } = React79__default;
28067
+ const { useEffect: useEffect73, useRef: useRef67, useCallback: useCallback112, useState: useState103 } = React79__default;
27815
28068
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
27816
28069
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
27817
28070
  function MapUpdater({ centerLat, centerLng, zoom }) {
27818
28071
  const map = useMap();
27819
- const prevRef = useRef66({ centerLat, centerLng, zoom });
27820
- useEffect72(() => {
28072
+ const prevRef = useRef67({ centerLat, centerLng, zoom });
28073
+ useEffect73(() => {
27821
28074
  const prev = prevRef.current;
27822
28075
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
27823
28076
  map.setView([centerLat, centerLng], zoom);
@@ -27828,7 +28081,7 @@ var init_MapView = __esm({
27828
28081
  }
27829
28082
  function MapClickHandler({ onMapClick }) {
27830
28083
  const map = useMap();
27831
- useEffect72(() => {
28084
+ useEffect73(() => {
27832
28085
  if (!onMapClick) return;
27833
28086
  const handler = (e) => {
27834
28087
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -27856,7 +28109,7 @@ var init_MapView = __esm({
27856
28109
  showAttribution = true
27857
28110
  }) {
27858
28111
  const eventBus = useEventBus3();
27859
- const [clickedPosition, setClickedPosition] = useState102(null);
28112
+ const [clickedPosition, setClickedPosition] = useState103(null);
27860
28113
  const handleMapClick = useCallback112((lat, lng) => {
27861
28114
  if (showClickedPin) {
27862
28115
  setClickedPosition({ lat, lng });
@@ -33292,8 +33545,8 @@ var init_VersionDiff = __esm({
33292
33545
  return { added, removed };
33293
33546
  }, [diff]);
33294
33547
  const handleBeforeChange = useCallback(
33295
- (e) => {
33296
- const id = e.target.value;
33548
+ (v) => {
33549
+ const id = v;
33297
33550
  setInternalBefore(id);
33298
33551
  onSelectBefore?.(id);
33299
33552
  if (selectBeforeEvent) eventBus.emit(`UI:${selectBeforeEvent}`, { id });
@@ -33301,8 +33554,8 @@ var init_VersionDiff = __esm({
33301
33554
  [onSelectBefore, selectBeforeEvent, eventBus]
33302
33555
  );
33303
33556
  const handleAfterChange = useCallback(
33304
- (e) => {
33305
- const id = e.target.value;
33557
+ (v) => {
33558
+ const id = v;
33306
33559
  setInternalAfter(id);
33307
33560
  onSelectAfter?.(id);
33308
33561
  if (selectAfterEvent) eventBus.emit(`UI:${selectAfterEvent}`, { id });
@@ -36080,7 +36333,6 @@ var init_DocumentViewer = __esm({
36080
36333
  showPrint = false,
36081
36334
  actions,
36082
36335
  documents,
36083
- entity,
36084
36336
  isLoading = false,
36085
36337
  error,
36086
36338
  className
@@ -37929,11 +38181,11 @@ function RuleEditor({
37929
38181
  className
37930
38182
  }) {
37931
38183
  const { t } = useTranslate();
37932
- const handleWhenChange = useCallback((e) => {
37933
- onChange({ ...rule, whenEvent: e.target.value });
38184
+ const handleWhenChange = useCallback((v) => {
38185
+ onChange({ ...rule, whenEvent: v });
37934
38186
  }, [rule, onChange]);
37935
- const handleThenChange = useCallback((e) => {
37936
- onChange({ ...rule, thenAction: e.target.value });
38187
+ const handleThenChange = useCallback((v) => {
38188
+ onChange({ ...rule, thenAction: v });
37937
38189
  }, [rule, onChange]);
37938
38190
  return /* @__PURE__ */ jsxs(HStack, { className: cn("items-center p-2 rounded-lg bg-muted/50 border border-border", className), gap: "sm", children: [
37939
38191
  /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-primary font-bold whitespace-nowrap", children: t("eventHandler.when") }),
@@ -39009,7 +39261,7 @@ var init_Form = __esm({
39009
39261
  ...commonProps,
39010
39262
  options,
39011
39263
  value: String(currentValue),
39012
- onChange: (e) => handleChange(fieldName, e.target.value),
39264
+ onChange: (v) => handleChange(fieldName, v),
39013
39265
  placeholder: field.placeholder || `Select ${label}...`
39014
39266
  }
39015
39267
  );
@@ -42895,7 +43147,7 @@ function TraitSlot({
42895
43147
  size = "md",
42896
43148
  showTooltip = true,
42897
43149
  categoryColors,
42898
- tooltipFrameUrl,
43150
+ tooltipFrameUrl = "",
42899
43151
  className,
42900
43152
  feedback,
42901
43153
  onItemDrop,
@@ -45796,18 +46048,32 @@ var init_WorldMapTemplate = __esm({
45796
46048
  }
45797
46049
  });
45798
46050
  function lazyThree(name, loader) {
45799
- const Lazy = React79__default.lazy(() => loader().then((m) => ({ default: m[name] })));
46051
+ const Lazy = React79__default.lazy(
46052
+ () => loader().then((m) => {
46053
+ const Resolved = m[name];
46054
+ if (!Resolved) {
46055
+ throw new Error(
46056
+ `[@almadar/ui] 3D component "${name}" was not found in the three subpath bundle.`
46057
+ );
46058
+ }
46059
+ return { default: Resolved };
46060
+ })
46061
+ );
45800
46062
  function ThreeWrapper(props) {
45801
46063
  return React79__default.createElement(
45802
- React79__default.Suspense,
45803
- { fallback: null },
45804
- React79__default.createElement(Lazy, props)
46064
+ ThreeBoundary,
46065
+ { name },
46066
+ React79__default.createElement(
46067
+ React79__default.Suspense,
46068
+ { fallback: null },
46069
+ React79__default.createElement(Lazy, props)
46070
+ )
45805
46071
  );
45806
46072
  }
45807
46073
  ThreeWrapper.displayName = `Lazy(${name})`;
45808
46074
  return ThreeWrapper;
45809
46075
  }
45810
- var FeatureRenderer, GameCanvas3D, GameCanvas3DBattleTemplate, GameCanvas3DCastleTemplate, GameCanvas3DWorldMapTemplate, COMPONENT_REGISTRY;
46076
+ var ThreeBoundary, FeatureRenderer, GameCanvas3D, GameCanvas3DBattleTemplate, GameCanvas3DCastleTemplate, GameCanvas3DWorldMapTemplate, COMPONENT_REGISTRY;
45811
46077
  var init_component_registry_generated = __esm({
45812
46078
  "components/core/organisms/component-registry.generated.ts"() {
45813
46079
  init_AboutPageTemplate();
@@ -46093,6 +46359,28 @@ var init_component_registry_generated = __esm({
46093
46359
  init_WorldMapBoard();
46094
46360
  init_WorldMapTemplate();
46095
46361
  init_XPBar();
46362
+ ThreeBoundary = class extends React79__default.Component {
46363
+ constructor() {
46364
+ super(...arguments);
46365
+ __publicField(this, "state", { failed: false });
46366
+ }
46367
+ static getDerivedStateFromError() {
46368
+ return { failed: true };
46369
+ }
46370
+ render() {
46371
+ if (this.state.failed) {
46372
+ return React79__default.createElement(
46373
+ "div",
46374
+ {
46375
+ "data-testid": "three-unavailable",
46376
+ style: { padding: 16, fontSize: 13, lineHeight: 1.5, opacity: 0.7 }
46377
+ },
46378
+ `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.`
46379
+ );
46380
+ }
46381
+ return this.props.children;
46382
+ }
46383
+ };
46096
46384
  FeatureRenderer = lazyThree("FeatureRenderer", () => import('@almadar/ui/components/molecules/game/three'));
46097
46385
  GameCanvas3D = lazyThree("GameCanvas3D", () => import('@almadar/ui/components/molecules/game/three'));
46098
46386
  GameCanvas3DBattleTemplate = lazyThree("GameCanvas3DBattleTemplate", () => import('@almadar/ui/components/molecules/game/three'));