fui-material 2.7.10 → 2.7.12

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.
@@ -1009,20 +1009,22 @@ const FTableFooter = ({
1009
1009
  }
1010
1010
  );
1011
1011
  };
1012
- const active$4 = "_active_16jkc_16";
1013
- const hide = "_hide_16jkc_37";
1012
+ const entering = "_entering_dwagt_17";
1013
+ const exiting = "_exiting_dwagt_23";
1014
+ const hide = "_hide_dwagt_45";
1014
1015
  const styles$r = {
1015
- "f-dialog": "_f-dialog_16jkc_1",
1016
- "active-dialog": "_active-dialog_16jkc_16",
1017
- "f-dialog__content": "_f-dialog__content_16jkc_20",
1018
- active: active$4,
1016
+ "f-dialog": "_f-dialog_dwagt_1",
1017
+ entering,
1018
+ "f-dialog__content": "_f-dialog__content_dwagt_20",
1019
+ exiting,
1019
1020
  hide,
1020
- "f-dialog__header": "_f-dialog__header_16jkc_41",
1021
- "f-dialog__header_title": "_f-dialog__header_title_16jkc_53",
1022
- "f-dialog__header_close": "_f-dialog__header_close_16jkc_64",
1023
- "f-dialog__body": "_f-dialog__body_16jkc_79",
1024
- "f-dialog__footer": "_f-dialog__footer_16jkc_84"
1021
+ "f-dialog__header": "_f-dialog__header_dwagt_49",
1022
+ "f-dialog__header_title": "_f-dialog__header_title_dwagt_61",
1023
+ "f-dialog__header_close": "_f-dialog__header_close_dwagt_72",
1024
+ "f-dialog__body": "_f-dialog__body_dwagt_87",
1025
+ "f-dialog__footer": "_f-dialog__footer_dwagt_92"
1025
1026
  };
1027
+ let openDialogsCount = 0;
1026
1028
  const FDialog = ({
1027
1029
  openAndClose,
1028
1030
  closeButtonBackPage,
@@ -1033,22 +1035,55 @@ const FDialog = ({
1033
1035
  st,
1034
1036
  width = "lg"
1035
1037
  }) => {
1038
+ const [isMounted, setIsMounted] = useState(openAndClose);
1039
+ const [isClosing, setIsClosing] = useState(false);
1036
1040
  useEffect(() => {
1037
- if (!openAndClose) return;
1038
- const dialogCount = document.querySelectorAll(".active-dialog").length;
1039
- if (dialogCount > 0) {
1040
- document.body.classList.add("open-dialog");
1041
- } else {
1042
- document.body.classList.remove("open-dialog");
1041
+ if (openAndClose) {
1042
+ setIsMounted(true);
1043
+ setIsClosing(false);
1044
+ } else if (isMounted) {
1045
+ setIsClosing(true);
1043
1046
  }
1044
- return () => {
1045
- const updatedCount = document.querySelectorAll(".active-dialog").length;
1046
- if (updatedCount === 0) {
1047
- document.body.classList.remove("open-dialog");
1048
- }
1049
- };
1050
1047
  }, [openAndClose]);
1051
- if (!openAndClose) return null;
1048
+ const handleAnimationEnd = (e) => {
1049
+ if (isClosing && e.target === e.currentTarget) {
1050
+ setIsMounted(false);
1051
+ setIsClosing(false);
1052
+ }
1053
+ };
1054
+ useEffect(() => {
1055
+ if (isClosing) {
1056
+ const timer = setTimeout(() => {
1057
+ setIsMounted(false);
1058
+ setIsClosing(false);
1059
+ }, 300);
1060
+ return () => clearTimeout(timer);
1061
+ }
1062
+ }, [isClosing]);
1063
+ useEffect(() => {
1064
+ if (isMounted && !isClosing) {
1065
+ openDialogsCount += 1;
1066
+ document.body.classList.add("open-dialog");
1067
+ return () => {
1068
+ openDialogsCount = Math.max(0, openDialogsCount - 1);
1069
+ if (openDialogsCount === 0) {
1070
+ document.body.classList.remove("open-dialog");
1071
+ }
1072
+ };
1073
+ }
1074
+ }, [isMounted, isClosing]);
1075
+ const handleKeyDown = useCallback((e) => {
1076
+ if (e.key === "Escape" && openAndClose && !isClosing) {
1077
+ closeButtonBackPage == null ? void 0 : closeButtonBackPage(false);
1078
+ }
1079
+ }, [openAndClose, isClosing, closeButtonBackPage]);
1080
+ useEffect(() => {
1081
+ if (isMounted && !isClosing) {
1082
+ window.addEventListener("keydown", handleKeyDown);
1083
+ return () => window.removeEventListener("keydown", handleKeyDown);
1084
+ }
1085
+ }, [isMounted, isClosing, handleKeyDown]);
1086
+ if (!isMounted) return null;
1052
1087
  const widthStyles = {
1053
1088
  xs: "50vw",
1054
1089
  md: "65vw",
@@ -1057,22 +1092,28 @@ const FDialog = ({
1057
1092
  adaptive: "fit-content"
1058
1093
  };
1059
1094
  const contentWidth = widthStyles[width];
1095
+ const animationClass = isClosing ? styles$r["exiting"] : styles$r["entering"];
1060
1096
  return ReactDOM.createPortal(
1061
1097
  /* @__PURE__ */ jsx(
1062
1098
  "div",
1063
1099
  {
1064
1100
  id,
1065
1101
  style: st,
1066
- className: `${styles$r["f-dialog"]} ${openAndClose ? styles$r["active-dialog"] : ""} ${className || ""}`,
1067
- onClick: () => closeButtonBackPage == null ? void 0 : closeButtonBackPage(false),
1102
+ className: `${styles$r["f-dialog"]} ${animationClass} ${className || ""}`,
1103
+ onMouseDown: (e) => {
1104
+ if (e.target === e.currentTarget) {
1105
+ closeButtonBackPage == null ? void 0 : closeButtonBackPage(false);
1106
+ }
1107
+ },
1108
+ onAnimationEnd: handleAnimationEnd,
1068
1109
  children: /* @__PURE__ */ jsx(
1069
1110
  "div",
1070
1111
  {
1071
- className: `${styles$r["f-dialog__content"]} ${openAndClose ? styles$r["active"] : ""} ${hide2 ? styles$r["hide"] : ""}`,
1112
+ className: `${styles$r["f-dialog__content"]} ${hide2 ? styles$r["hide"] : ""}`,
1072
1113
  style: {
1073
1114
  width: contentWidth
1074
1115
  },
1075
- onClick: (e) => e.stopPropagation(),
1116
+ onMouseDown: (e) => e.stopPropagation(),
1076
1117
  children
1077
1118
  }
1078
1119
  )
@@ -3446,24 +3487,24 @@ const FTooltip = ({
3446
3487
  tooltipElement && createPortal(tooltipElement, document.body)
3447
3488
  ] });
3448
3489
  };
3449
- const rotate = "_rotate_fq6h3_43";
3450
- const focused = "_focused_fq6h3_94";
3451
- const selected = "_selected_fq6h3_97";
3490
+ const rotate = "_rotate_1kvw2_38";
3491
+ const focused = "_focused_1kvw2_87";
3492
+ const selected = "_selected_1kvw2_90";
3452
3493
  const styles$6 = {
3453
- "f-search-select": "_f-search-select_fq6h3_3",
3454
- "f-select-native-hidden": "_f-select-native-hidden_fq6h3_8",
3455
- "f-select-actions": "_f-select-actions_fq6h3_25",
3456
- "f-select-icon": "_f-select-icon_fq6h3_34",
3494
+ "f-search-select": "_f-search-select_1kvw2_3",
3495
+ "f-select-native-hidden": "_f-select-native-hidden_1kvw2_9",
3496
+ "f-select-actions": "_f-select-actions_1kvw2_20",
3497
+ "f-select-icon": "_f-select-icon_1kvw2_29",
3457
3498
  rotate,
3458
- "f-select-dropdown": "_f-select-dropdown_fq6h3_48",
3459
- "f-select-list": "_f-select-list_fq6h3_62",
3460
- "f-select-option": "_f-select-option_fq6h3_81",
3499
+ "f-select-dropdown": "_f-select-dropdown_1kvw2_43",
3500
+ "f-select-list": "_f-select-list_1kvw2_54",
3501
+ "f-select-option": "_f-select-option_1kvw2_75",
3461
3502
  focused,
3462
3503
  selected,
3463
- "f-select-create": "_f-select-create_fq6h3_102",
3464
- "f-select-no-results": "_f-select-no-results_fq6h3_108",
3465
- "f-select-highlight": "_f-select-highlight_fq6h3_128",
3466
- "has-icons": "_has-icons_fq6h3_135"
3504
+ "f-select-create": "_f-select-create_1kvw2_95",
3505
+ "f-select-no-results": "_f-select-no-results_1kvw2_101",
3506
+ "f-select-highlight": "_f-select-highlight_1kvw2_121",
3507
+ "has-icons": "_has-icons_1kvw2_128"
3467
3508
  };
3468
3509
  const ChevronIcon = ({ className }) => /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: /* @__PURE__ */ jsx("polyline", { points: "6 9 12 15 18 9" }) });
3469
3510
  const CloseIcon = () => /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
@@ -3525,7 +3566,11 @@ const FSearchableSelect = forwardRef(
3525
3566
  const [searchQuery, setSearchQuery] = useState("");
3526
3567
  const [highlightedIndex, setHighlightedIndex] = useState(0);
3527
3568
  const [isTyping, setIsTyping] = useState(false);
3569
+ const [dropdownStyle, setDropdownStyle] = useState({});
3570
+ const [listMaxHeight, setListMaxHeight] = useState(300);
3528
3571
  const containerRef = useRef(null);
3572
+ const controlRef = useRef(null);
3573
+ const dropdownRef = useRef(null);
3529
3574
  const visibleInputRef = useRef(null);
3530
3575
  const listRef = useRef(null);
3531
3576
  const lastValueRef = useRef(restProps.value !== void 0 ? String(restProps.value) : "");
@@ -3543,11 +3588,48 @@ const FSearchableSelect = forwardRef(
3543
3588
  return;
3544
3589
  }
3545
3590
  setIsTyping(true);
3546
- const timeoutId = setTimeout(() => {
3547
- setIsTyping(false);
3548
- }, 1e3);
3591
+ const timeoutId = setTimeout(() => setIsTyping(false), 1e3);
3549
3592
  return () => clearTimeout(timeoutId);
3550
3593
  }, [searchQuery, isOpen]);
3594
+ const updateDropdownPosition = () => {
3595
+ if (!controlRef.current || !isOpen) return;
3596
+ const rect = controlRef.current.getBoundingClientRect();
3597
+ const viewportHeight = window.innerHeight;
3598
+ const spaceBelow = viewportHeight - rect.bottom;
3599
+ const spaceAbove = rect.top;
3600
+ let top, bottom, maxHeight;
3601
+ const gap = 4;
3602
+ if (spaceBelow < 250 && spaceAbove > spaceBelow) {
3603
+ bottom = viewportHeight - rect.top + gap;
3604
+ top = "auto";
3605
+ maxHeight = Math.min(spaceAbove - 20, 350);
3606
+ } else {
3607
+ top = rect.bottom + gap;
3608
+ bottom = "auto";
3609
+ maxHeight = Math.min(spaceBelow - 20, 350);
3610
+ }
3611
+ setDropdownStyle({
3612
+ position: "fixed",
3613
+ top,
3614
+ bottom,
3615
+ left: rect.left,
3616
+ width: rect.width,
3617
+ zIndex: 999999
3618
+ // Поверх модалок
3619
+ });
3620
+ setListMaxHeight(maxHeight);
3621
+ };
3622
+ useLayoutEffect(() => {
3623
+ if (isOpen) {
3624
+ updateDropdownPosition();
3625
+ window.addEventListener("scroll", updateDropdownPosition, true);
3626
+ window.addEventListener("resize", updateDropdownPosition);
3627
+ }
3628
+ return () => {
3629
+ window.removeEventListener("scroll", updateDropdownPosition, true);
3630
+ window.removeEventListener("resize", updateDropdownPosition);
3631
+ };
3632
+ }, [isOpen]);
3551
3633
  const deferredQuery = useDeferredValue(searchQuery);
3552
3634
  const filteredOptions = useMemo(() => {
3553
3635
  if (!isOpen) return options;
@@ -3567,6 +3649,14 @@ const FSearchableSelect = forwardRef(
3567
3649
  }
3568
3650
  return list;
3569
3651
  }, [filteredOptions, showCreateOption, deferredQuery]);
3652
+ useEffect(() => {
3653
+ if (isOpen && listRef.current) {
3654
+ const activeItem = listRef.current.children[highlightedIndex];
3655
+ if (activeItem) {
3656
+ activeItem.scrollIntoView({ block: "nearest" });
3657
+ }
3658
+ }
3659
+ }, [highlightedIndex, isOpen]);
3570
3660
  const triggerChange = (newValue) => {
3571
3661
  lastValueRef.current = newValue;
3572
3662
  if (restProps.onChange) {
@@ -3591,7 +3681,10 @@ const FSearchableSelect = forwardRef(
3591
3681
  };
3592
3682
  useEffect(() => {
3593
3683
  const handleClickOutside = (event) => {
3594
- if (containerRef.current && !containerRef.current.contains(event.target)) {
3684
+ var _a, _b;
3685
+ const isClickInContainer = (_a = containerRef.current) == null ? void 0 : _a.contains(event.target);
3686
+ const isClickInDropdown = (_b = dropdownRef.current) == null ? void 0 : _b.contains(event.target);
3687
+ if (!isClickInContainer && !isClickInDropdown) {
3595
3688
  setIsOpen(false);
3596
3689
  const effectiveValue = restProps.value !== void 0 ? String(restProps.value) : lastValueRef.current;
3597
3690
  if (effectiveValue) {
@@ -3669,7 +3762,7 @@ const FSearchableSelect = forwardRef(
3669
3762
  "aria-hidden": "true"
3670
3763
  }
3671
3764
  ),
3672
- /* @__PURE__ */ jsxs("div", { className: `f-form-element__control ${load ? "is-loading" : ""}`, children: [
3765
+ /* @__PURE__ */ jsxs("div", { ref: controlRef, className: `f-form-element__control ${load ? "is-loading" : ""}`, children: [
3673
3766
  /* @__PURE__ */ jsx(
3674
3767
  "input",
3675
3768
  {
@@ -3713,29 +3806,48 @@ const FSearchableSelect = forwardRef(
3713
3806
  /* @__PURE__ */ jsx("div", { className: `${styles$6["f-select-icon"]} ${isOpen ? styles$6["rotate"] : ""}`, children: /* @__PURE__ */ jsx(ChevronIcon, {}) })
3714
3807
  ] })
3715
3808
  ] }),
3716
- isOpen && !disabled2 && !load && /* @__PURE__ */ jsx("div", { className: styles$6["f-select-dropdown"], children: /* @__PURE__ */ jsx("ul", { ref: listRef, className: styles$6["f-select-list"], children: isTyping ? /* @__PURE__ */ jsx("li", { className: styles$6["f-select-no-results"], children: "Ожидается окончание ввода..." }) : renderList.length === 0 ? /* @__PURE__ */ jsx("li", { className: styles$6["f-select-no-results"], children: allowCreate ? "Нет данных" : "Совпадений не найдено" }) : renderList.map((option, index) => /* @__PURE__ */ jsx(
3717
- "li",
3718
- {
3719
- className: `
3809
+ isOpen && !disabled2 && !load && typeof document !== "undefined" && createPortal(
3810
+ /* @__PURE__ */ jsx(
3811
+ "div",
3812
+ {
3813
+ className: styles$6["f-select-dropdown"],
3814
+ style: dropdownStyle,
3815
+ ref: dropdownRef,
3816
+ children: /* @__PURE__ */ jsx(
3817
+ "ul",
3818
+ {
3819
+ ref: listRef,
3820
+ className: styles$6["f-select-list"],
3821
+ style: { maxHeight: `${listMaxHeight}px` },
3822
+ children: isTyping ? /* @__PURE__ */ jsx("li", { className: styles$6["f-select-no-results"], children: "Ожидается окончание ввода..." }) : renderList.length === 0 ? /* @__PURE__ */ jsx("li", { className: styles$6["f-select-no-results"], children: allowCreate ? "Нет данных" : "Совпадений не найдено" }) : renderList.map((option, index) => /* @__PURE__ */ jsx(
3823
+ "li",
3824
+ {
3825
+ className: `
3720
3826
  ${styles$6["f-select-option"]}
3721
3827
  ${option.isNew ? styles$6["f-select-create"] : ""}
3722
3828
  ${index === highlightedIndex ? styles$6["focused"] : ""}
3723
3829
  ${currentValStr === option.value ? styles$6["selected"] : ""}
3724
3830
  `,
3725
- onMouseDown: (e) => e.preventDefault(),
3726
- onClick: (e) => {
3727
- e.stopPropagation();
3728
- handleSelect(option);
3729
- },
3730
- onMouseEnter: () => setHighlightedIndex(index),
3731
- children: /* @__PURE__ */ jsxs("div", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: [
3732
- option.isNew && /* @__PURE__ */ jsx("span", { style: { marginRight: 4 }, children: /* @__PURE__ */ jsx(PlusIcon, {}) }),
3733
- /* @__PURE__ */ jsx(HighlightedText, { text: option.label, highlight: deferredQuery }),
3734
- option.isNew && /* @__PURE__ */ jsx("span", { style: { opacity: 0.6, fontSize: "0.85em", marginLeft: 6 }, children: "(Создать)" })
3735
- ] })
3736
- },
3737
- option.value + index
3738
- )) }) }),
3831
+ onMouseDown: (e) => e.preventDefault(),
3832
+ onClick: (e) => {
3833
+ e.stopPropagation();
3834
+ handleSelect(option);
3835
+ },
3836
+ onMouseEnter: () => setHighlightedIndex(index),
3837
+ children: /* @__PURE__ */ jsxs("div", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: [
3838
+ option.isNew && /* @__PURE__ */ jsx("span", { style: { marginRight: 4 }, children: /* @__PURE__ */ jsx(PlusIcon, {}) }),
3839
+ /* @__PURE__ */ jsx(HighlightedText, { text: option.label, highlight: deferredQuery }),
3840
+ option.isNew && /* @__PURE__ */ jsx("span", { style: { opacity: 0.6, fontSize: "0.85em", marginLeft: 6 }, children: "(Создать)" })
3841
+ ] })
3842
+ },
3843
+ option.value + index
3844
+ ))
3845
+ }
3846
+ )
3847
+ }
3848
+ ),
3849
+ document.body
3850
+ ),
3739
3851
  helpText && /* @__PURE__ */ jsx(
3740
3852
  "p",
3741
3853
  {