@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
@@ -3427,6 +3427,8 @@ var init_Input = __esm({
3427
3427
  className,
3428
3428
  inputType,
3429
3429
  type: htmlType,
3430
+ label,
3431
+ helperText,
3430
3432
  error,
3431
3433
  leftIcon,
3432
3434
  rightIcon,
@@ -3482,82 +3484,95 @@ var init_Input = __esm({
3482
3484
  onClear?.();
3483
3485
  }
3484
3486
  };
3487
+ const wrapField = (field) => /* @__PURE__ */ jsxs("div", { className: "w-full", children: [
3488
+ label && /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-foreground mb-1", children: label }),
3489
+ field,
3490
+ (helperText || error) && /* @__PURE__ */ jsx("p", { className: cn("mt-1 text-xs", error ? "text-error" : "text-muted-foreground"), children: error ?? helperText })
3491
+ ] });
3485
3492
  if (type === "select") {
3486
- return /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
3487
- resolvedLeftIcon && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-muted-foreground", children: resolvedLeftIcon }),
3488
- /* @__PURE__ */ jsxs(
3489
- "select",
3493
+ return wrapField(
3494
+ /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
3495
+ resolvedLeftIcon && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-muted-foreground", children: resolvedLeftIcon }),
3496
+ /* @__PURE__ */ jsxs(
3497
+ "select",
3498
+ {
3499
+ ref,
3500
+ value,
3501
+ onChange: handleChange,
3502
+ className: cn(baseClassName, "appearance-none pr-10", className),
3503
+ ...props,
3504
+ children: [
3505
+ /* @__PURE__ */ jsx("option", { value: "", children: t("form.selectPlaceholder", { label: "" }) }),
3506
+ options?.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
3507
+ ]
3508
+ }
3509
+ ),
3510
+ /* @__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" }) })
3511
+ ] })
3512
+ );
3513
+ }
3514
+ if (type === "textarea") {
3515
+ return wrapField(
3516
+ /* @__PURE__ */ jsx("div", { className: "relative w-full", children: /* @__PURE__ */ jsx(
3517
+ "textarea",
3490
3518
  {
3491
3519
  ref,
3492
3520
  value,
3493
3521
  onChange: handleChange,
3494
- className: cn(baseClassName, "appearance-none pr-10", className),
3495
- ...props,
3496
- children: [
3497
- /* @__PURE__ */ jsx("option", { value: "", children: t("form.selectPlaceholder", { label: "" }) }),
3498
- options?.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
3499
- ]
3522
+ rows: rows2,
3523
+ className: baseClassName,
3524
+ ...props
3500
3525
  }
3501
- ),
3502
- /* @__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" }) })
3503
- ] });
3504
- }
3505
- if (type === "textarea") {
3506
- return /* @__PURE__ */ jsx("div", { className: "relative w-full", children: /* @__PURE__ */ jsx(
3507
- "textarea",
3508
- {
3509
- ref,
3510
- value,
3511
- onChange: handleChange,
3512
- rows: rows2,
3513
- className: baseClassName,
3514
- ...props
3515
- }
3516
- ) });
3526
+ ) })
3527
+ );
3517
3528
  }
3518
3529
  if (type === "checkbox") {
3519
- return /* @__PURE__ */ jsx(
3520
- "input",
3521
- {
3522
- ref,
3523
- type: "checkbox",
3524
- checked: props.checked,
3525
- onChange: handleChange,
3526
- className: cn(
3527
- "h-icon-default w-icon-default rounded-sm",
3528
- "border-border",
3529
- "text-primary focus:ring-ring",
3530
- "disabled:opacity-50 disabled:cursor-not-allowed",
3531
- className
3532
- ),
3533
- ...props
3534
- }
3530
+ return wrapField(
3531
+ /* @__PURE__ */ jsx(
3532
+ "input",
3533
+ {
3534
+ ref,
3535
+ type: "checkbox",
3536
+ checked: props.checked,
3537
+ onChange: handleChange,
3538
+ className: cn(
3539
+ "h-icon-default w-icon-default rounded-sm",
3540
+ "border-border",
3541
+ "text-primary focus:ring-ring",
3542
+ "disabled:opacity-50 disabled:cursor-not-allowed",
3543
+ className
3544
+ ),
3545
+ ...props
3546
+ }
3547
+ )
3535
3548
  );
3536
3549
  }
3537
- return /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
3538
- resolvedLeftIcon && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-muted-foreground", children: resolvedLeftIcon }),
3539
- /* @__PURE__ */ jsx(
3540
- "input",
3541
- {
3542
- ref,
3543
- type,
3544
- value,
3545
- onChange: handleChange,
3546
- className: baseClassName,
3547
- ...props
3548
- }
3549
- ),
3550
- showClearButton && /* @__PURE__ */ jsx(
3551
- "button",
3552
- {
3553
- type: "button",
3554
- onClick: handleClear,
3555
- className: "absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground hover:text-foreground",
3556
- children: /* @__PURE__ */ jsx(Icon, { name: "x", className: "h-icon-default w-icon-default" })
3557
- }
3558
- ),
3559
- rightIcon && !showClearButton && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground", children: resolveIconNode(rightIcon, iconCls) })
3560
- ] });
3550
+ return wrapField(
3551
+ /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
3552
+ resolvedLeftIcon && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-muted-foreground", children: resolvedLeftIcon }),
3553
+ /* @__PURE__ */ jsx(
3554
+ "input",
3555
+ {
3556
+ ref,
3557
+ type,
3558
+ value,
3559
+ onChange: handleChange,
3560
+ className: baseClassName,
3561
+ ...props
3562
+ }
3563
+ ),
3564
+ showClearButton && /* @__PURE__ */ jsx(
3565
+ "button",
3566
+ {
3567
+ type: "button",
3568
+ onClick: handleClear,
3569
+ className: "absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground hover:text-foreground",
3570
+ children: /* @__PURE__ */ jsx(Icon, { name: "x", className: "h-icon-default w-icon-default" })
3571
+ }
3572
+ ),
3573
+ rightIcon && !showClearButton && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground", children: resolveIconNode(rightIcon, iconCls) })
3574
+ ] })
3575
+ );
3561
3576
  }
3562
3577
  );
3563
3578
  Input.displayName = "Input";
@@ -3628,6 +3643,190 @@ var init_Textarea = __esm({
3628
3643
  Textarea.displayName = "Textarea";
3629
3644
  }
3630
3645
  });
3646
+ function flatOptions(opts, groups) {
3647
+ const flat = opts ?? [];
3648
+ const grp = (groups ?? []).flatMap((g) => g.options);
3649
+ return [...flat, ...grp];
3650
+ }
3651
+ function NativeSelect({
3652
+ className,
3653
+ options,
3654
+ groups,
3655
+ placeholder,
3656
+ error,
3657
+ onChange,
3658
+ value,
3659
+ ...props
3660
+ }) {
3661
+ const eventBus = useEventBus();
3662
+ const handleChange = (e) => {
3663
+ if (typeof onChange === "string") {
3664
+ eventBus.emit(`UI:${onChange}`, { value: e.target.value });
3665
+ } else {
3666
+ onChange?.(e.target.value);
3667
+ }
3668
+ };
3669
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
3670
+ /* @__PURE__ */ jsxs(
3671
+ "select",
3672
+ {
3673
+ onChange: handleChange,
3674
+ value,
3675
+ className: cn(
3676
+ "block w-full border-[length:var(--border-width)] shadow-sm appearance-none",
3677
+ "px-3 py-2 pr-10 text-sm text-foreground font-medium",
3678
+ "bg-card",
3679
+ "focus:outline-none focus:ring-2 focus:ring-offset-0 focus:ring-ring",
3680
+ "disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
3681
+ error ? "border-error focus:border-error" : "border-border focus:border-primary",
3682
+ className
3683
+ ),
3684
+ ...props,
3685
+ children: [
3686
+ placeholder && /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }),
3687
+ options?.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value)),
3688
+ 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))
3689
+ ]
3690
+ }
3691
+ ),
3692
+ /* @__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" }) })
3693
+ ] });
3694
+ }
3695
+ function RichSelect({
3696
+ className,
3697
+ options,
3698
+ groups,
3699
+ placeholder,
3700
+ error,
3701
+ onChange,
3702
+ value,
3703
+ multiple,
3704
+ searchable,
3705
+ clearable,
3706
+ disabled
3707
+ }) {
3708
+ const eventBus = useEventBus();
3709
+ const [open, setOpen] = useState(false);
3710
+ const [search, setSearch] = useState("");
3711
+ const containerRef = useRef(null);
3712
+ const selected = multiple ? Array.isArray(value) ? value : value ? [value] : [] : value ? [value] : [];
3713
+ const all = flatOptions(options, groups);
3714
+ const filtered = searchable && search ? all.filter((o) => o.label.toLowerCase().includes(search.toLowerCase())) : all;
3715
+ const toggle = (optValue) => {
3716
+ let next;
3717
+ if (multiple) {
3718
+ next = selected.includes(optValue) ? selected.filter((v) => v !== optValue) : [...selected, optValue];
3719
+ } else {
3720
+ next = optValue;
3721
+ setOpen(false);
3722
+ }
3723
+ if (typeof onChange === "string") {
3724
+ eventBus.emit(`UI:${onChange}`, { value: next });
3725
+ } else {
3726
+ onChange?.(next);
3727
+ }
3728
+ };
3729
+ const clear = (e) => {
3730
+ e.stopPropagation();
3731
+ const next = multiple ? [] : "";
3732
+ if (typeof onChange === "string") {
3733
+ eventBus.emit(`UI:${onChange}`, { value: next });
3734
+ } else {
3735
+ onChange?.(next);
3736
+ }
3737
+ };
3738
+ useEffect(() => {
3739
+ const handler = (e) => {
3740
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
3741
+ setOpen(false);
3742
+ setSearch("");
3743
+ }
3744
+ };
3745
+ document.addEventListener("mousedown", handler);
3746
+ return () => document.removeEventListener("mousedown", handler);
3747
+ }, []);
3748
+ const displayLabel = selected.length === 0 ? placeholder ?? "" : multiple ? `${selected.length} selected` : all.find((o) => o.value === selected[0])?.label ?? selected[0];
3749
+ const hasValue = selected.length > 0;
3750
+ const renderOptions = (opts) => opts.map((opt) => /* @__PURE__ */ jsxs(
3751
+ "button",
3752
+ {
3753
+ type: "button",
3754
+ disabled: opt.disabled,
3755
+ onClick: () => !opt.disabled && toggle(opt.value),
3756
+ className: cn(
3757
+ "w-full flex items-center justify-between px-3 py-1.5 text-sm text-start",
3758
+ "hover:bg-muted transition-colors",
3759
+ "disabled:opacity-50 disabled:cursor-not-allowed",
3760
+ selected.includes(opt.value) && "text-primary font-medium"
3761
+ ),
3762
+ children: [
3763
+ /* @__PURE__ */ jsx("span", { children: opt.label }),
3764
+ selected.includes(opt.value) && /* @__PURE__ */ jsx(Icon, { name: "check", className: "h-icon-default w-icon-default" })
3765
+ ]
3766
+ },
3767
+ opt.value
3768
+ ));
3769
+ return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: cn("relative w-full", className), children: [
3770
+ /* @__PURE__ */ jsx(
3771
+ "button",
3772
+ {
3773
+ type: "button",
3774
+ disabled,
3775
+ onClick: () => !disabled && setOpen((o) => !o),
3776
+ className: cn(
3777
+ "block w-full border-[length:var(--border-width)] shadow-sm",
3778
+ "px-3 py-2 pr-10 text-sm text-start font-medium",
3779
+ "bg-card rounded-sm",
3780
+ "focus:outline-none focus:ring-2 focus:ring-offset-0 focus:ring-ring",
3781
+ "disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
3782
+ error ? "border-error focus:border-error" : "border-border focus:border-primary",
3783
+ !hasValue && "text-muted-foreground"
3784
+ ),
3785
+ children: displayLabel
3786
+ }
3787
+ ),
3788
+ /* @__PURE__ */ jsxs("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center gap-1 pointer-events-none", children: [
3789
+ clearable && hasValue && /* @__PURE__ */ jsx(
3790
+ "button",
3791
+ {
3792
+ type: "button",
3793
+ onClick: clear,
3794
+ className: "pointer-events-auto text-muted-foreground hover:text-foreground",
3795
+ children: /* @__PURE__ */ jsx(Icon, { name: "x", className: "h-icon-default w-icon-default" })
3796
+ }
3797
+ ),
3798
+ /* @__PURE__ */ jsx(Icon, { name: "chevron-down", className: "h-icon-default w-icon-default text-foreground" })
3799
+ ] }),
3800
+ open && /* @__PURE__ */ jsxs("div", { className: cn(
3801
+ "absolute z-50 mt-1 w-full",
3802
+ "bg-card border-[length:var(--border-width)] border-border",
3803
+ "rounded-sm shadow-elevation-popover py-1 max-h-60 overflow-y-auto"
3804
+ ), children: [
3805
+ searchable && /* @__PURE__ */ jsx("div", { className: "px-2 pb-1 border-b border-border", children: /* @__PURE__ */ jsx(
3806
+ "input",
3807
+ {
3808
+ autoFocus: true,
3809
+ type: "text",
3810
+ value: search,
3811
+ onChange: (e) => setSearch(e.target.value),
3812
+ placeholder: "Search\u2026",
3813
+ className: cn(
3814
+ "w-full px-2 py-1 text-sm bg-transparent",
3815
+ "focus:outline-none text-foreground placeholder:text-muted-foreground"
3816
+ )
3817
+ }
3818
+ ) }),
3819
+ groups && groups.length > 0 ? groups.map((g) => {
3820
+ const groupFiltered = searchable && search ? g.options.filter((o) => o.label.toLowerCase().includes(search.toLowerCase())) : g.options;
3821
+ if (groupFiltered.length === 0) return null;
3822
+ return /* @__PURE__ */ jsxs("div", { children: [
3823
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-1 text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: g.label }),
3824
+ renderOptions(groupFiltered)
3825
+ ] }, g.label);
3826
+ }) : renderOptions(filtered)
3827
+ ] })
3828
+ ] });
3829
+ }
3631
3830
  var Select;
3632
3831
  var init_Select = __esm({
3633
3832
  "components/core/atoms/Select.tsx"() {
@@ -3635,47 +3834,12 @@ var init_Select = __esm({
3635
3834
  init_Icon();
3636
3835
  init_useEventBus();
3637
3836
  Select = React80__default.forwardRef(
3638
- ({ className, options, placeholder, error, onChange, ...props }, ref) => {
3639
- const eventBus = useEventBus();
3640
- const handleChange = (e) => {
3641
- if (typeof onChange === "string") {
3642
- eventBus.emit(`UI:${onChange}`, { value: e.target.value });
3643
- } else {
3644
- onChange?.(e);
3645
- }
3646
- };
3647
- return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
3648
- /* @__PURE__ */ jsxs(
3649
- "select",
3650
- {
3651
- ref,
3652
- onChange: handleChange,
3653
- className: cn(
3654
- "block w-full border-[length:var(--border-width)] shadow-sm appearance-none",
3655
- "px-3 py-2 pr-10 text-sm text-foreground font-medium",
3656
- "bg-card",
3657
- "focus:outline-none focus:ring-2 focus:ring-offset-0 focus:ring-ring",
3658
- "disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
3659
- error ? "border-error focus:border-error" : "border-border focus:border-primary",
3660
- className
3661
- ),
3662
- ...props,
3663
- children: [
3664
- placeholder && /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }),
3665
- options.map((option) => /* @__PURE__ */ jsx(
3666
- "option",
3667
- {
3668
- value: option.value,
3669
- disabled: option.disabled,
3670
- children: option.label
3671
- },
3672
- option.value
3673
- ))
3674
- ]
3675
- }
3676
- ),
3677
- /* @__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" }) })
3678
- ] });
3837
+ (props, _ref) => {
3838
+ const { multiple, searchable, clearable } = props;
3839
+ if (multiple || searchable || clearable) {
3840
+ return /* @__PURE__ */ jsx(RichSelect, { ...props });
3841
+ }
3842
+ return /* @__PURE__ */ jsx(NativeSelect, { ...props });
3679
3843
  }
3680
3844
  );
3681
3845
  Select.displayName = "Select";
@@ -3729,11 +3893,54 @@ var init_Checkbox = __esm({
3729
3893
  Checkbox.displayName = "Checkbox";
3730
3894
  }
3731
3895
  });
3896
+ var sizeStyles3, Spinner;
3897
+ var init_Spinner = __esm({
3898
+ "components/core/atoms/Spinner.tsx"() {
3899
+ init_cn();
3900
+ init_Icon();
3901
+ sizeStyles3 = {
3902
+ xs: "h-3 w-3",
3903
+ sm: "h-icon-default w-icon-default",
3904
+ md: "h-6 w-6",
3905
+ lg: "h-8 w-8"
3906
+ };
3907
+ Spinner = React80__default.forwardRef(
3908
+ ({ className, size = "md", overlay, ...props }, ref) => {
3909
+ if (overlay) {
3910
+ return /* @__PURE__ */ jsx(
3911
+ "div",
3912
+ {
3913
+ ref,
3914
+ className: cn(
3915
+ "absolute inset-0 z-10 flex items-center justify-center",
3916
+ "bg-background/60 backdrop-blur-sm",
3917
+ className
3918
+ ),
3919
+ ...props,
3920
+ children: /* @__PURE__ */ jsx(Icon, { name: "loader", className: cn("animate-spin text-foreground", sizeStyles3[size]) })
3921
+ }
3922
+ );
3923
+ }
3924
+ return /* @__PURE__ */ jsx(
3925
+ "div",
3926
+ {
3927
+ ref,
3928
+ className: cn("text-foreground", className),
3929
+ ...props,
3930
+ children: /* @__PURE__ */ jsx(Icon, { name: "loader", className: cn("animate-spin", sizeStyles3[size]) })
3931
+ }
3932
+ );
3933
+ }
3934
+ );
3935
+ Spinner.displayName = "Spinner";
3936
+ }
3937
+ });
3732
3938
  var variantStyles4, paddingStyles2, shadowStyles2, lookStyles2, Card, CardHeader, CardTitle, CardContent, CardBody, CardFooter;
3733
3939
  var init_Card = __esm({
3734
3940
  "components/core/atoms/Card.tsx"() {
3735
3941
  init_cn();
3736
3942
  init_useEventBus();
3943
+ init_Spinner();
3737
3944
  variantStyles4 = {
3738
3945
  default: [
3739
3946
  "bg-card",
@@ -3798,6 +4005,7 @@ var init_Card = __esm({
3798
4005
  look = "elevated",
3799
4006
  children,
3800
4007
  action,
4008
+ loading,
3801
4009
  onClick,
3802
4010
  ...props
3803
4011
  }, ref) => {
@@ -3811,7 +4019,7 @@ var init_Card = __esm({
3811
4019
  {
3812
4020
  ref,
3813
4021
  className: cn(
3814
- "rounded-container",
4022
+ "rounded-container relative",
3815
4023
  "transition-all duration-[var(--transition-normal)]",
3816
4024
  variantStyles4[variant],
3817
4025
  paddingStyles2[padding],
@@ -3822,6 +4030,7 @@ var init_Card = __esm({
3822
4030
  onClick: handleClick,
3823
4031
  ...props,
3824
4032
  children: [
4033
+ loading && /* @__PURE__ */ jsx(Spinner, { overlay: true, size: "md" }),
3825
4034
  (title || subtitle) && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
3826
4035
  title && /* @__PURE__ */ jsx("h3", { className: "text-lg text-card-foreground font-bold", children: title }),
3827
4036
  subtitle && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1", children: subtitle })
@@ -3863,7 +4072,7 @@ var init_Card = __esm({
3863
4072
  CardFooter.displayName = "CardFooter";
3864
4073
  }
3865
4074
  });
3866
- var variantStyles5, sizeStyles3, iconSizes, FilterPill;
4075
+ var variantStyles5, sizeStyles4, iconSizes, FilterPill;
3867
4076
  var init_FilterPill = __esm({
3868
4077
  "components/core/atoms/FilterPill.tsx"() {
3869
4078
  init_cn();
@@ -3897,7 +4106,7 @@ var init_FilterPill = __esm({
3897
4106
  "border-[length:var(--border-width-thin)] border-border"
3898
4107
  ].join(" ")
3899
4108
  };
3900
- sizeStyles3 = {
4109
+ sizeStyles4 = {
3901
4110
  sm: "px-2 py-0.5 text-xs",
3902
4111
  md: "px-2.5 py-1 text-sm",
3903
4112
  lg: "px-3 py-1.5 text-base"
@@ -3941,7 +4150,7 @@ var init_FilterPill = __esm({
3941
4150
  className: cn(
3942
4151
  "inline-flex items-center gap-1 font-bold rounded-pill",
3943
4152
  variantStyles5[variant],
3944
- sizeStyles3[size],
4153
+ sizeStyles4[size],
3945
4154
  (onClick || clickEvent) && "cursor-pointer",
3946
4155
  className
3947
4156
  ),
@@ -3973,33 +4182,6 @@ var init_FilterPill = __esm({
3973
4182
  FilterPill.displayName = "FilterPill";
3974
4183
  }
3975
4184
  });
3976
- var sizeStyles4, Spinner;
3977
- var init_Spinner = __esm({
3978
- "components/core/atoms/Spinner.tsx"() {
3979
- init_cn();
3980
- init_Icon();
3981
- sizeStyles4 = {
3982
- xs: "h-3 w-3",
3983
- sm: "h-icon-default w-icon-default",
3984
- md: "h-6 w-6",
3985
- lg: "h-8 w-8"
3986
- };
3987
- Spinner = React80__default.forwardRef(
3988
- ({ className, size = "md", ...props }, ref) => {
3989
- return /* @__PURE__ */ jsx(
3990
- "div",
3991
- {
3992
- ref,
3993
- className: cn("text-foreground", className),
3994
- ...props,
3995
- children: /* @__PURE__ */ jsx(Icon, { name: "loader", className: cn("animate-spin", sizeStyles4[size]) })
3996
- }
3997
- );
3998
- }
3999
- );
4000
- Spinner.displayName = "Spinner";
4001
- }
4002
- });
4003
4185
  function generateInitials(name) {
4004
4186
  const parts = name.trim().split(/\s+/);
4005
4187
  if (parts.length === 1) {
@@ -16466,30 +16648,30 @@ var init_BranchingLogicBuilder = __esm({
16466
16648
  if (!sourceQuestion?.optionValues) return [];
16467
16649
  return sourceQuestion.optionValues.map((v) => ({ value: v, label: v }));
16468
16650
  }, [sourceQuestion]);
16469
- const handleSource = (e) => {
16470
- onChange({ ...rule, sourceQuestionId: e.target.value });
16651
+ const handleSource = (v) => {
16652
+ onChange({ ...rule, sourceQuestionId: v });
16471
16653
  };
16472
- const handleOperator = (e) => {
16473
- const next = e.target.value;
16654
+ const handleOperator = (v) => {
16655
+ const next = v;
16474
16656
  const nextValue = next === "in" && !Array.isArray(rule.value) ? rule.value ? [rule.value] : [] : next !== "in" && Array.isArray(rule.value) ? rule.value[0] ?? "" : rule.value;
16475
16657
  onChange({ ...rule, operator: next, value: nextValue });
16476
16658
  };
16477
16659
  const handleScalarValue = (e) => {
16478
16660
  onChange({ ...rule, value: e.target.value });
16479
16661
  };
16480
- const handleAddChip = (e) => {
16481
- const v = e.target.value;
16482
- if (!v) return;
16662
+ const handleAddChip = (v) => {
16663
+ const val = v;
16664
+ if (!val) return;
16483
16665
  const current = Array.isArray(rule.value) ? rule.value : [];
16484
- if (current.includes(v)) return;
16485
- onChange({ ...rule, value: [...current, v] });
16666
+ if (current.includes(val)) return;
16667
+ onChange({ ...rule, value: [...current, val] });
16486
16668
  };
16487
16669
  const handleRemoveChip = (chip) => {
16488
16670
  const current = Array.isArray(rule.value) ? rule.value : [];
16489
16671
  onChange({ ...rule, value: current.filter((c) => c !== chip) });
16490
16672
  };
16491
- const handleTarget = (e) => {
16492
- onChange({ ...rule, targetQuestionId: e.target.value });
16673
+ const handleTarget = (v) => {
16674
+ onChange({ ...rule, targetQuestionId: v });
16493
16675
  };
16494
16676
  const isMulti = rule.operator === "in";
16495
16677
  const chips = Array.isArray(rule.value) ? rule.value : [];
@@ -16570,7 +16752,7 @@ var init_BranchingLogicBuilder = __esm({
16570
16752
  options: valueOptions,
16571
16753
  value: scalarValue,
16572
16754
  placeholder: t("branchingLogic.selectValue"),
16573
- onChange: (e) => onChange({ ...rule, value: e.target.value }),
16755
+ onChange: (v) => onChange({ ...rule, value: v }),
16574
16756
  disabled: readOnly
16575
16757
  }
16576
16758
  ) : /* @__PURE__ */ jsx(
@@ -19002,7 +19184,7 @@ var init_Pagination = __esm({
19002
19184
  Select,
19003
19185
  {
19004
19186
  value: String(pageSize),
19005
- onChange: (e) => handlePageSizeChange(Number(e.target.value)),
19187
+ onChange: (v) => handlePageSizeChange(Number(v)),
19006
19188
  options: pageSizeOptions.map((size) => ({
19007
19189
  value: String(size),
19008
19190
  label: String(size)
@@ -21928,7 +22110,84 @@ var init_DashboardLayout = __esm({
21928
22110
  NavLinkBottom.displayName = "NavLinkBottom";
21929
22111
  }
21930
22112
  });
21931
- var Menu;
22113
+ function computeMenuStyle(position, triggerRect) {
22114
+ const isTop = position.startsWith("top");
22115
+ const isRight = position.endsWith("right") || position.endsWith("end");
22116
+ if (isTop) {
22117
+ return {
22118
+ top: triggerRect.top - MENU_GAP,
22119
+ transform: "translateY(-100%)",
22120
+ ...isRight ? { right: window.innerWidth - triggerRect.right } : { left: triggerRect.left }
22121
+ };
22122
+ }
22123
+ return {
22124
+ top: triggerRect.bottom + MENU_GAP,
22125
+ ...isRight ? { right: window.innerWidth - triggerRect.right } : { left: triggerRect.left }
22126
+ };
22127
+ }
22128
+ function SubMenu({
22129
+ items,
22130
+ itemRef,
22131
+ direction,
22132
+ eventBus
22133
+ }) {
22134
+ const [rect, setRect] = useState(null);
22135
+ useEffect(() => {
22136
+ if (itemRef) {
22137
+ setRect(itemRef.getBoundingClientRect());
22138
+ }
22139
+ }, [itemRef]);
22140
+ if (!rect) return null;
22141
+ const isRtl = direction === "rtl";
22142
+ const style = {
22143
+ top: rect.top,
22144
+ ...isRtl ? { right: window.innerWidth - rect.left } : { left: rect.right }
22145
+ };
22146
+ const panel = /* @__PURE__ */ jsx(
22147
+ "div",
22148
+ {
22149
+ className: cn("fixed z-50", menuContainerStyles),
22150
+ style,
22151
+ children: items.map((item, index) => {
22152
+ const isDivider = item.id === "divider" || item.label === "divider";
22153
+ const itemId = item.id ?? `item-${item.label.toLowerCase().replace(/\s+/g, "-")}-${index}`;
22154
+ const isDanger = item.variant === "danger";
22155
+ if (isDivider) {
22156
+ return /* @__PURE__ */ jsx(Divider, { className: "my-1" }, `divider-${index}`);
22157
+ }
22158
+ return /* @__PURE__ */ jsxs(
22159
+ Box,
22160
+ {
22161
+ as: "button",
22162
+ onClick: () => {
22163
+ if (item.disabled) return;
22164
+ if (item.event) eventBus.emit(`UI:${item.event}`, { itemId, label: item.label });
22165
+ item.onClick?.();
22166
+ },
22167
+ "aria-disabled": item.disabled || void 0,
22168
+ "data-testid": item.event ? `action-${item.event}` : void 0,
22169
+ className: cn(
22170
+ "w-full flex items-center gap-3 px-4 py-2 text-start",
22171
+ "text-sm transition-colors",
22172
+ "hover:bg-muted focus:outline-none focus:bg-muted",
22173
+ "disabled:opacity-50 disabled:cursor-not-allowed",
22174
+ item.disabled && "cursor-not-allowed",
22175
+ isDanger && "text-error hover:bg-error/10"
22176
+ ),
22177
+ children: [
22178
+ 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" })),
22179
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: cn("flex-1", isDanger && "text-red-600"), children: item.label }),
22180
+ item.badge !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-auto text-xs font-medium", children: item.badge })
22181
+ ]
22182
+ },
22183
+ itemId
22184
+ );
22185
+ })
22186
+ }
22187
+ );
22188
+ return typeof document !== "undefined" ? createPortal(panel, document.body) : panel;
22189
+ }
22190
+ var MENU_GAP, menuContainerStyles, Menu;
21932
22191
  var init_Menu = __esm({
21933
22192
  "components/core/molecules/Menu.tsx"() {
21934
22193
  "use client";
@@ -21939,16 +22198,27 @@ var init_Menu = __esm({
21939
22198
  init_Badge();
21940
22199
  init_cn();
21941
22200
  init_useEventBus();
22201
+ MENU_GAP = 4;
22202
+ menuContainerStyles = cn(
22203
+ "bg-card",
22204
+ "border-[length:var(--border-width)] border-border",
22205
+ "shadow-elevation-popover",
22206
+ "rounded-sm",
22207
+ "min-w-0 sm:min-w-[200px] max-w-[calc(100vw-1rem)] py-1"
22208
+ );
21942
22209
  Menu = ({
21943
22210
  trigger,
21944
22211
  items,
21945
22212
  position = "bottom-left",
21946
- className
22213
+ className,
22214
+ header,
22215
+ footer
21947
22216
  }) => {
21948
22217
  const eventBus = useEventBus();
21949
- const { t, direction } = useTranslate();
22218
+ const { direction } = useTranslate();
21950
22219
  const [isOpen, setIsOpen] = useState(false);
21951
22220
  const [activeSubMenu, setActiveSubMenu] = useState(null);
22221
+ const [activeSubMenuRef, setActiveSubMenuRef] = useState(null);
21952
22222
  const [triggerRect, setTriggerRect] = useState(null);
21953
22223
  const triggerRef = useRef(null);
21954
22224
  const menuRef = useRef(null);
@@ -21963,13 +22233,14 @@ var init_Menu = __esm({
21963
22233
  }
21964
22234
  setIsOpen(!isOpen);
21965
22235
  setActiveSubMenu(null);
22236
+ setActiveSubMenuRef(null);
21966
22237
  };
21967
- const handleItemClick = (item) => {
22238
+ const handleItemClick = (item, itemId) => {
21968
22239
  if (item.disabled) return;
21969
22240
  if (item.subMenu && item.subMenu.length > 0) {
21970
- setActiveSubMenu(item.id ?? null);
22241
+ setActiveSubMenu(itemId);
21971
22242
  } else {
21972
- if (item.event) eventBus.emit(`UI:${item.event}`, { itemId: item.id, label: item.label });
22243
+ if (item.event) eventBus.emit(`UI:${item.event}`, { itemId, label: item.label });
21973
22244
  item.onClick?.();
21974
22245
  setIsOpen(false);
21975
22246
  }
@@ -21984,22 +22255,12 @@ var init_Menu = __esm({
21984
22255
  if (isOpen && menuRef.current && !menuRef.current.contains(e.target) && triggerRef.current && !triggerRef.current.contains(e.target)) {
21985
22256
  setIsOpen(false);
21986
22257
  setActiveSubMenu(null);
22258
+ setActiveSubMenuRef(null);
21987
22259
  }
21988
22260
  };
21989
22261
  document.addEventListener("mousedown", handleClickOutside);
21990
22262
  return () => document.removeEventListener("mousedown", handleClickOutside);
21991
22263
  }, [isOpen]);
21992
- const positionClasses = {
21993
- "top-left": "bottom-full left-0 mb-2",
21994
- "top-right": "bottom-full right-0 mb-2",
21995
- "bottom-left": "top-full left-0 mt-2",
21996
- "bottom-right": "top-full right-0 mt-2",
21997
- // Aliases for pattern compatibility
21998
- "top-start": "bottom-full left-0 mb-2",
21999
- "top-end": "bottom-full right-0 mb-2",
22000
- "bottom-start": "top-full left-0 mt-2",
22001
- "bottom-end": "top-full right-0 mt-2"
22002
- };
22003
22264
  const rtlMirror = {
22004
22265
  "top-left": "top-right",
22005
22266
  "top-right": "top-left",
@@ -22011,7 +22272,6 @@ var init_Menu = __esm({
22011
22272
  "bottom-end": "bottom-start"
22012
22273
  };
22013
22274
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
22014
- const subMenuSideClass = direction === "rtl" ? "right-full mr-2" : "left-full ml-2";
22015
22275
  const triggerChild = React80__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
22016
22276
  const triggerElement = React80__default.cloneElement(
22017
22277
  triggerChild,
@@ -22020,94 +22280,87 @@ var init_Menu = __esm({
22020
22280
  onClick: handleToggle
22021
22281
  }
22022
22282
  );
22023
- const menuContainerStyles = cn(
22024
- "bg-card",
22025
- "border-[length:var(--border-width)] border-border",
22026
- "shadow-elevation-popover",
22027
- "rounded-sm",
22028
- "min-w-0 sm:min-w-[200px] max-w-[calc(100vw-1rem)] py-1"
22029
- );
22030
- const renderMenuItem = (item, hasSubMenu, index) => {
22283
+ const renderMenuItems = (menuItems) => menuItems.map((item, index) => {
22284
+ const isDivider = item.id === "divider" || item.label === "divider";
22031
22285
  const itemId = item.id ?? `item-${item.label.toLowerCase().replace(/\s+/g, "-")}-${index}`;
22286
+ const hasSubMenu = !!(item.subMenu && item.subMenu.length > 0);
22032
22287
  const isDanger = item.variant === "danger";
22033
- return /* @__PURE__ */ jsx(
22034
- Box,
22035
- {
22036
- as: "button",
22037
- onClick: () => !item.disabled && handleItemClick({ ...item, id: itemId }),
22038
- "aria-disabled": item.disabled || void 0,
22039
- onMouseEnter: () => hasSubMenu && setActiveSubMenu(itemId),
22040
- "data-testid": item.event ? `action-${item.event}` : void 0,
22041
- className: cn(
22042
- "w-full flex items-center justify-between gap-3 px-4 py-2 text-start",
22043
- "text-sm transition-colors",
22044
- "hover:bg-muted",
22045
- "focus:outline-none focus:bg-muted",
22046
- "disabled:opacity-50 disabled:cursor-not-allowed",
22047
- item.disabled && "cursor-not-allowed",
22048
- isDanger && "text-error hover:bg-error/10"
22049
- ),
22050
- children: /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-3 flex-1 min-w-0", children: [
22051
- 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" })),
22052
- /* @__PURE__ */ jsx(
22053
- Typography,
22054
- {
22055
- variant: "small",
22056
- className: cn("flex-1", isDanger && "text-red-600"),
22057
- children: item.label
22288
+ if (isDivider) {
22289
+ return /* @__PURE__ */ jsx(Divider, { className: "my-1" }, `divider-${index}`);
22290
+ }
22291
+ return /* @__PURE__ */ jsxs(Box, { children: [
22292
+ /* @__PURE__ */ jsx(
22293
+ Box,
22294
+ {
22295
+ as: "button",
22296
+ onClick: () => handleItemClick({ ...item, id: itemId }, itemId),
22297
+ "aria-disabled": item.disabled || void 0,
22298
+ onMouseEnter: (e) => {
22299
+ if (hasSubMenu) {
22300
+ setActiveSubMenu(itemId);
22301
+ setActiveSubMenuRef(e.currentTarget);
22058
22302
  }
22303
+ },
22304
+ "data-testid": item.event ? `action-${item.event}` : void 0,
22305
+ className: cn(
22306
+ "w-full flex items-center justify-between gap-3 px-4 py-2 text-start",
22307
+ "text-sm transition-colors",
22308
+ "hover:bg-muted",
22309
+ "focus:outline-none focus:bg-muted",
22310
+ "disabled:opacity-50 disabled:cursor-not-allowed",
22311
+ item.disabled && "cursor-not-allowed",
22312
+ isDanger && "text-error hover:bg-error/10"
22059
22313
  ),
22060
- item.badge !== void 0 && /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: item.badge }),
22061
- hasSubMenu && /* @__PURE__ */ jsx(Icon, { name: direction === "rtl" ? "chevron-left" : "chevron-right", size: "sm", className: "flex-shrink-0" })
22062
- ] })
22063
- },
22064
- itemId
22065
- );
22066
- };
22067
- const renderMenuItems = (menuItems) => {
22068
- return menuItems.map((item, index) => {
22069
- const hasSubMenu = item.subMenu && item.subMenu.length > 0;
22070
- const isDivider = item.id === "divider" || item.label === "divider";
22071
- const itemId = item.id ?? `item-${item.label.toLowerCase().replace(/\s+/g, "-")}-${index}`;
22072
- if (isDivider) {
22073
- return /* @__PURE__ */ jsx(Divider, { className: "my-1" }, `divider-${index}`);
22074
- }
22075
- return /* @__PURE__ */ jsxs(Box, { children: [
22076
- renderMenuItem(item, !!hasSubMenu, index),
22077
- hasSubMenu && activeSubMenu === itemId && item.subMenu && /* @__PURE__ */ jsx(
22078
- Box,
22079
- {
22080
- className: cn(
22081
- "absolute top-0 z-50",
22082
- subMenuSideClass,
22083
- menuContainerStyles
22314
+ children: /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-3 flex-1 min-w-0", children: [
22315
+ 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" })),
22316
+ /* @__PURE__ */ jsx(
22317
+ Typography,
22318
+ {
22319
+ variant: "small",
22320
+ className: cn("flex-1", isDanger && "text-red-600"),
22321
+ children: item.label
22322
+ }
22084
22323
  ),
22085
- children: renderMenuItems(item.subMenu)
22086
- }
22087
- )
22088
- ] }, itemId);
22089
- });
22090
- };
22091
- return /* @__PURE__ */ jsxs(Box, { className: "relative", children: [
22324
+ item.badge !== void 0 && /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: item.badge }),
22325
+ hasSubMenu && /* @__PURE__ */ jsx(
22326
+ Icon,
22327
+ {
22328
+ name: direction === "rtl" ? "chevron-left" : "chevron-right",
22329
+ size: "sm",
22330
+ className: "flex-shrink-0"
22331
+ }
22332
+ )
22333
+ ] })
22334
+ }
22335
+ ),
22336
+ hasSubMenu && activeSubMenu === itemId && item.subMenu && /* @__PURE__ */ jsx(
22337
+ SubMenu,
22338
+ {
22339
+ items: item.subMenu,
22340
+ itemRef: activeSubMenuRef,
22341
+ direction,
22342
+ eventBus
22343
+ }
22344
+ )
22345
+ ] }, itemId);
22346
+ });
22347
+ const panel = isOpen && triggerRect ? /* @__PURE__ */ jsxs(
22348
+ "div",
22349
+ {
22350
+ ref: menuRef,
22351
+ className: cn("fixed z-50", menuContainerStyles, className),
22352
+ style: computeMenuStyle(effectivePosition, triggerRect),
22353
+ role: "menu",
22354
+ children: [
22355
+ header && /* @__PURE__ */ jsx("div", { className: "px-4 py-2 border-b border-border", children: header }),
22356
+ renderMenuItems(items),
22357
+ footer && /* @__PURE__ */ jsx("div", { className: "px-4 py-2 border-t border-border", children: footer })
22358
+ ]
22359
+ }
22360
+ ) : null;
22361
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
22092
22362
  triggerElement,
22093
- isOpen && triggerRect && /* @__PURE__ */ jsx(
22094
- Box,
22095
- {
22096
- ref: menuRef,
22097
- className: cn(
22098
- "absolute z-50",
22099
- menuContainerStyles,
22100
- positionClasses[effectivePosition],
22101
- className
22102
- ),
22103
- style: {
22104
- left: effectivePosition.includes("left") ? 0 : "auto",
22105
- right: effectivePosition.includes("right") ? 0 : "auto"
22106
- },
22107
- role: "menu",
22108
- children: renderMenuItems(items)
22109
- }
22110
- )
22363
+ panel && typeof document !== "undefined" ? createPortal(panel, document.body) : panel
22111
22364
  ] });
22112
22365
  };
22113
22366
  Menu.displayName = "Menu";
@@ -23861,7 +24114,7 @@ var init_FilterGroup = __esm({
23861
24114
  Select,
23862
24115
  {
23863
24116
  value: selectedValues[filter.field] || "all",
23864
- onChange: (e) => handleFilterSelect(filter.field, e.target.value),
24117
+ onChange: (v) => handleFilterSelect(filter.field, v),
23865
24118
  options: [
23866
24119
  { value: "all", label: t("filterGroup.all") },
23867
24120
  ...filter.options?.map((opt) => ({
@@ -23944,7 +24197,7 @@ var init_FilterGroup = __esm({
23944
24197
  Select,
23945
24198
  {
23946
24199
  value: selectedValues[filter.field] || "all",
23947
- onChange: (e) => handleFilterSelect(filter.field, e.target.value),
24200
+ onChange: (v) => handleFilterSelect(filter.field, v),
23948
24201
  options: [
23949
24202
  { value: "all", label: t("filterGroup.allOf", { label: filter.label }) },
23950
24203
  ...filter.options?.map((opt) => ({
@@ -24062,7 +24315,7 @@ var init_FilterGroup = __esm({
24062
24315
  Select,
24063
24316
  {
24064
24317
  value: selectedValues[filter.field] || "all",
24065
- onChange: (e) => handleFilterSelect(filter.field, e.target.value),
24318
+ onChange: (v) => handleFilterSelect(filter.field, v),
24066
24319
  options: [
24067
24320
  { value: "all", label: t("filterGroup.all") },
24068
24321
  ...filter.options?.map((opt) => ({
@@ -28244,13 +28497,13 @@ var init_MapView = __esm({
28244
28497
  shadowSize: [41, 41]
28245
28498
  });
28246
28499
  L.Marker.prototype.options.icon = defaultIcon;
28247
- const { useEffect: useEffect71, useRef: useRef66, useCallback: useCallback112, useState: useState99 } = React80__default;
28500
+ const { useEffect: useEffect72, useRef: useRef67, useCallback: useCallback112, useState: useState100 } = React80__default;
28248
28501
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
28249
28502
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
28250
28503
  function MapUpdater({ centerLat, centerLng, zoom }) {
28251
28504
  const map = useMap();
28252
- const prevRef = useRef66({ centerLat, centerLng, zoom });
28253
- useEffect71(() => {
28505
+ const prevRef = useRef67({ centerLat, centerLng, zoom });
28506
+ useEffect72(() => {
28254
28507
  const prev = prevRef.current;
28255
28508
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
28256
28509
  map.setView([centerLat, centerLng], zoom);
@@ -28261,7 +28514,7 @@ var init_MapView = __esm({
28261
28514
  }
28262
28515
  function MapClickHandler({ onMapClick }) {
28263
28516
  const map = useMap();
28264
- useEffect71(() => {
28517
+ useEffect72(() => {
28265
28518
  if (!onMapClick) return;
28266
28519
  const handler = (e) => {
28267
28520
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -28289,7 +28542,7 @@ var init_MapView = __esm({
28289
28542
  showAttribution = true
28290
28543
  }) {
28291
28544
  const eventBus = useEventBus2();
28292
- const [clickedPosition, setClickedPosition] = useState99(null);
28545
+ const [clickedPosition, setClickedPosition] = useState100(null);
28293
28546
  const handleMapClick = useCallback112((lat, lng) => {
28294
28547
  if (showClickedPin) {
28295
28548
  setClickedPosition({ lat, lng });
@@ -33725,8 +33978,8 @@ var init_VersionDiff = __esm({
33725
33978
  return { added, removed };
33726
33979
  }, [diff]);
33727
33980
  const handleBeforeChange = useCallback(
33728
- (e) => {
33729
- const id = e.target.value;
33981
+ (v) => {
33982
+ const id = v;
33730
33983
  setInternalBefore(id);
33731
33984
  onSelectBefore?.(id);
33732
33985
  if (selectBeforeEvent) eventBus.emit(`UI:${selectBeforeEvent}`, { id });
@@ -33734,8 +33987,8 @@ var init_VersionDiff = __esm({
33734
33987
  [onSelectBefore, selectBeforeEvent, eventBus]
33735
33988
  );
33736
33989
  const handleAfterChange = useCallback(
33737
- (e) => {
33738
- const id = e.target.value;
33990
+ (v) => {
33991
+ const id = v;
33739
33992
  setInternalAfter(id);
33740
33993
  onSelectAfter?.(id);
33741
33994
  if (selectAfterEvent) eventBus.emit(`UI:${selectAfterEvent}`, { id });
@@ -36513,7 +36766,6 @@ var init_DocumentViewer = __esm({
36513
36766
  showPrint = false,
36514
36767
  actions,
36515
36768
  documents,
36516
- entity,
36517
36769
  isLoading = false,
36518
36770
  error,
36519
36771
  className
@@ -38362,11 +38614,11 @@ function RuleEditor({
38362
38614
  className
38363
38615
  }) {
38364
38616
  const { t } = useTranslate();
38365
- const handleWhenChange = useCallback((e) => {
38366
- onChange({ ...rule, whenEvent: e.target.value });
38617
+ const handleWhenChange = useCallback((v) => {
38618
+ onChange({ ...rule, whenEvent: v });
38367
38619
  }, [rule, onChange]);
38368
- const handleThenChange = useCallback((e) => {
38369
- onChange({ ...rule, thenAction: e.target.value });
38620
+ const handleThenChange = useCallback((v) => {
38621
+ onChange({ ...rule, thenAction: v });
38370
38622
  }, [rule, onChange]);
38371
38623
  return /* @__PURE__ */ jsxs(HStack, { className: cn("items-center p-2 rounded-lg bg-muted/50 border border-border", className), gap: "sm", children: [
38372
38624
  /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-primary font-bold whitespace-nowrap", children: t("eventHandler.when") }),
@@ -39442,7 +39694,7 @@ var init_Form = __esm({
39442
39694
  ...commonProps,
39443
39695
  options,
39444
39696
  value: String(currentValue),
39445
- onChange: (e) => handleChange(fieldName, e.target.value),
39697
+ onChange: (v) => handleChange(fieldName, v),
39446
39698
  placeholder: field.placeholder || `Select ${label}...`
39447
39699
  }
39448
39700
  );
@@ -43309,7 +43561,7 @@ function TraitSlot({
43309
43561
  size = "md",
43310
43562
  showTooltip = true,
43311
43563
  categoryColors,
43312
- tooltipFrameUrl,
43564
+ tooltipFrameUrl = "",
43313
43565
  className,
43314
43566
  feedback,
43315
43567
  onItemDrop,
@@ -46210,18 +46462,32 @@ var init_WorldMapTemplate = __esm({
46210
46462
  }
46211
46463
  });
46212
46464
  function lazyThree(name, loader) {
46213
- const Lazy = React80__default.lazy(() => loader().then((m) => ({ default: m[name] })));
46465
+ const Lazy = React80__default.lazy(
46466
+ () => loader().then((m) => {
46467
+ const Resolved = m[name];
46468
+ if (!Resolved) {
46469
+ throw new Error(
46470
+ `[@almadar/ui] 3D component "${name}" was not found in the three subpath bundle.`
46471
+ );
46472
+ }
46473
+ return { default: Resolved };
46474
+ })
46475
+ );
46214
46476
  function ThreeWrapper(props) {
46215
46477
  return React80__default.createElement(
46216
- React80__default.Suspense,
46217
- { fallback: null },
46218
- React80__default.createElement(Lazy, props)
46478
+ ThreeBoundary,
46479
+ { name },
46480
+ React80__default.createElement(
46481
+ React80__default.Suspense,
46482
+ { fallback: null },
46483
+ React80__default.createElement(Lazy, props)
46484
+ )
46219
46485
  );
46220
46486
  }
46221
46487
  ThreeWrapper.displayName = `Lazy(${name})`;
46222
46488
  return ThreeWrapper;
46223
46489
  }
46224
- var FeatureRenderer, GameCanvas3D, GameCanvas3DBattleTemplate, GameCanvas3DCastleTemplate, GameCanvas3DWorldMapTemplate, COMPONENT_REGISTRY;
46490
+ var ThreeBoundary, FeatureRenderer, GameCanvas3D, GameCanvas3DBattleTemplate, GameCanvas3DCastleTemplate, GameCanvas3DWorldMapTemplate, COMPONENT_REGISTRY;
46225
46491
  var init_component_registry_generated = __esm({
46226
46492
  "components/core/organisms/component-registry.generated.ts"() {
46227
46493
  init_AboutPageTemplate();
@@ -46507,6 +46773,28 @@ var init_component_registry_generated = __esm({
46507
46773
  init_WorldMapBoard();
46508
46774
  init_WorldMapTemplate();
46509
46775
  init_XPBar();
46776
+ ThreeBoundary = class extends React80__default.Component {
46777
+ constructor() {
46778
+ super(...arguments);
46779
+ __publicField(this, "state", { failed: false });
46780
+ }
46781
+ static getDerivedStateFromError() {
46782
+ return { failed: true };
46783
+ }
46784
+ render() {
46785
+ if (this.state.failed) {
46786
+ return React80__default.createElement(
46787
+ "div",
46788
+ {
46789
+ "data-testid": "three-unavailable",
46790
+ style: { padding: 16, fontSize: 13, lineHeight: 1.5, opacity: 0.7 }
46791
+ },
46792
+ `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.`
46793
+ );
46794
+ }
46795
+ return this.props.children;
46796
+ }
46797
+ };
46510
46798
  FeatureRenderer = lazyThree("FeatureRenderer", () => import('@almadar/ui/components/molecules/game/three'));
46511
46799
  GameCanvas3D = lazyThree("GameCanvas3D", () => import('@almadar/ui/components/molecules/game/three'));
46512
46800
  GameCanvas3DBattleTemplate = lazyThree("GameCanvas3DBattleTemplate", () => import('@almadar/ui/components/molecules/game/three'));