@rufous/ui 0.2.67 → 0.2.68

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.
package/dist/main.cjs CHANGED
@@ -3540,6 +3540,7 @@ DateRangeField.displayName = "DateRangeField";
3540
3540
 
3541
3541
  // lib/TextFields/Autocomplete.tsx
3542
3542
  var import_react21 = __toESM(require("react"), 1);
3543
+ var import_react_dom2 = __toESM(require("react-dom"), 1);
3543
3544
  var ChevronDownIcon = () => /* @__PURE__ */ import_react21.default.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react21.default.createElement("polyline", { points: "6 9 12 15 18 9" }));
3544
3545
  var CloseSmIcon = ({ size = 16 }) => /* @__PURE__ */ import_react21.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round" }, /* @__PURE__ */ import_react21.default.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), /* @__PURE__ */ import_react21.default.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" }));
3545
3546
  var CheckIcon = () => /* @__PURE__ */ import_react21.default.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react21.default.createElement("polyline", { points: "20 6 9 17 4 12" }));
@@ -3593,11 +3594,21 @@ function AutocompleteInner(props, _ref) {
3593
3594
  const [open, setOpen] = (0, import_react21.useState)(false);
3594
3595
  const [inputStr, setInputStr] = (0, import_react21.useState)("");
3595
3596
  const [focusedIdx, setFocusedIdx] = (0, import_react21.useState)(-1);
3597
+ const [popupStyle, setPopupStyle] = (0, import_react21.useState)({});
3596
3598
  const containerRef = (0, import_react21.useRef)(null);
3597
3599
  const inputRef = (0, import_react21.useRef)(null);
3598
3600
  const listRef = (0, import_react21.useRef)(null);
3599
3601
  const inputId = (0, import_react21.useRef)(`rf-ac-${Math.random().toString(36).slice(2, 9)}`).current;
3600
3602
  const sxClass = useSx(sx);
3603
+ const calcPopupStyle = (0, import_react21.useCallback)(() => {
3604
+ if (!containerRef.current) return;
3605
+ const rect = containerRef.current.getBoundingClientRect();
3606
+ setPopupStyle({
3607
+ top: rect.bottom + 4,
3608
+ left: rect.left,
3609
+ width: rect.width
3610
+ });
3611
+ }, []);
3601
3612
  const activeInput = controlledInput !== void 0 ? controlledInput : inputStr;
3602
3613
  const selectedValues = multiple ? Array.isArray(value) ? value : [] : value != null ? [value] : [];
3603
3614
  const isEqual = (0, import_react21.useCallback)(
@@ -3631,12 +3642,13 @@ function AutocompleteInner(props, _ref) {
3631
3642
  filtered.forEach((opt, i) => flatEntries.push({ kind: "option", option: opt, flatIdx: i }));
3632
3643
  }
3633
3644
  const selectableOptions = flatEntries.filter((e) => e.kind === "option");
3634
- const openPopup = () => {
3645
+ const openPopup = (0, import_react21.useCallback)(() => {
3635
3646
  if (disabled) return;
3647
+ calcPopupStyle();
3636
3648
  setOpen(true);
3637
3649
  setFocusedIdx(-1);
3638
3650
  onOpen?.();
3639
- };
3651
+ }, [disabled, calcPopupStyle, onOpen]);
3640
3652
  const closePopup = (0, import_react21.useCallback)(() => {
3641
3653
  setOpen(false);
3642
3654
  setFocusedIdx(-1);
@@ -3648,14 +3660,20 @@ function AutocompleteInner(props, _ref) {
3648
3660
  }, [freeSolo, multiple, value, onInputChange, onClose]);
3649
3661
  (0, import_react21.useEffect)(() => {
3650
3662
  if (!open) return;
3651
- const handler = (e) => {
3663
+ const handleOutside = (e) => {
3652
3664
  if (containerRef.current && !containerRef.current.contains(e.target)) {
3653
3665
  closePopup();
3654
3666
  }
3655
3667
  };
3656
- document.addEventListener("mousedown", handler);
3657
- return () => document.removeEventListener("mousedown", handler);
3658
- }, [open, closePopup]);
3668
+ document.addEventListener("mousedown", handleOutside);
3669
+ window.addEventListener("scroll", calcPopupStyle, true);
3670
+ window.addEventListener("resize", calcPopupStyle);
3671
+ return () => {
3672
+ document.removeEventListener("mousedown", handleOutside);
3673
+ window.removeEventListener("scroll", calcPopupStyle, true);
3674
+ window.removeEventListener("resize", calcPopupStyle);
3675
+ };
3676
+ }, [open, closePopup, calcPopupStyle]);
3659
3677
  (0, import_react21.useEffect)(() => {
3660
3678
  if (controlledInput !== void 0) return;
3661
3679
  if (!multiple) {
@@ -3840,34 +3858,37 @@ function AutocompleteInner(props, _ref) {
3840
3858
  },
3841
3859
  /* @__PURE__ */ import_react21.default.createElement(ChevronDownIcon, null)
3842
3860
  ))
3843
- ), helperText && /* @__PURE__ */ import_react21.default.createElement("div", { className: `rf-text-field__helper-text${error ? " rf-text-field__helper-text--error" : ""}` }, helperText), open && !disabled && /* @__PURE__ */ import_react21.default.createElement("div", { className: "rf-autocomplete__popup", role: "presentation" }, loading ? /* @__PURE__ */ import_react21.default.createElement("div", { className: "rf-autocomplete__loading" }, /* @__PURE__ */ import_react21.default.createElement("span", { className: "rf-ac-spinner" }), loadingText) : flatEntries.length === 0 ? /* @__PURE__ */ import_react21.default.createElement("div", { className: "rf-autocomplete__no-options" }, noOptionsText) : /* @__PURE__ */ import_react21.default.createElement("ul", { ref: listRef, className: "rf-autocomplete__listbox", role: "listbox" }, groupBy ? (
3844
- // Grouped render
3845
- (() => {
3846
- const rendered = [];
3847
- let groupItems = [];
3848
- let currentGroup = "";
3849
- flatEntries.forEach((entry, ei) => {
3850
- if (entry.kind === "group") {
3851
- if (groupItems.length > 0) {
3861
+ ), helperText && /* @__PURE__ */ import_react21.default.createElement("div", { className: `rf-text-field__helper-text${error ? " rf-text-field__helper-text--error" : ""}` }, helperText), open && !disabled && import_react_dom2.default.createPortal(
3862
+ /* @__PURE__ */ import_react21.default.createElement("div", { className: "rf-autocomplete__popup", role: "presentation", style: popupStyle }, loading ? /* @__PURE__ */ import_react21.default.createElement("div", { className: "rf-autocomplete__loading" }, /* @__PURE__ */ import_react21.default.createElement("span", { className: "rf-ac-spinner" }), loadingText) : flatEntries.length === 0 ? /* @__PURE__ */ import_react21.default.createElement("div", { className: "rf-autocomplete__no-options" }, noOptionsText) : /* @__PURE__ */ import_react21.default.createElement("ul", { ref: listRef, className: "rf-autocomplete__listbox", role: "listbox" }, groupBy ? (
3863
+ // Grouped render
3864
+ (() => {
3865
+ const rendered = [];
3866
+ let groupItems = [];
3867
+ let currentGroup = "";
3868
+ flatEntries.forEach((entry, ei) => {
3869
+ if (entry.kind === "group") {
3870
+ if (groupItems.length > 0) {
3871
+ rendered.push(
3872
+ /* @__PURE__ */ import_react21.default.createElement("li", { key: `g-${currentGroup}`, role: "presentation" }, /* @__PURE__ */ import_react21.default.createElement("div", { className: "rf-autocomplete__group-header" }, currentGroup), /* @__PURE__ */ import_react21.default.createElement("ul", { className: "rf-autocomplete__group-items", role: "group" }, groupItems))
3873
+ );
3874
+ groupItems = [];
3875
+ }
3876
+ currentGroup = entry.label;
3877
+ } else {
3878
+ const { option, flatIdx } = entry;
3879
+ groupItems.push(renderOptionItem(option, flatIdx));
3880
+ }
3881
+ if (ei === flatEntries.length - 1 && groupItems.length > 0) {
3852
3882
  rendered.push(
3853
3883
  /* @__PURE__ */ import_react21.default.createElement("li", { key: `g-${currentGroup}`, role: "presentation" }, /* @__PURE__ */ import_react21.default.createElement("div", { className: "rf-autocomplete__group-header" }, currentGroup), /* @__PURE__ */ import_react21.default.createElement("ul", { className: "rf-autocomplete__group-items", role: "group" }, groupItems))
3854
3884
  );
3855
- groupItems = [];
3856
3885
  }
3857
- currentGroup = entry.label;
3858
- } else {
3859
- const { option, flatIdx } = entry;
3860
- groupItems.push(renderOptionItem(option, flatIdx));
3861
- }
3862
- if (ei === flatEntries.length - 1 && groupItems.length > 0) {
3863
- rendered.push(
3864
- /* @__PURE__ */ import_react21.default.createElement("li", { key: `g-${currentGroup}`, role: "presentation" }, /* @__PURE__ */ import_react21.default.createElement("div", { className: "rf-autocomplete__group-header" }, currentGroup), /* @__PURE__ */ import_react21.default.createElement("ul", { className: "rf-autocomplete__group-items", role: "group" }, groupItems))
3865
- );
3866
- }
3867
- });
3868
- return rendered;
3869
- })()
3870
- ) : selectableOptions.map(({ option, flatIdx }) => renderOptionItem(option, flatIdx)))));
3886
+ });
3887
+ return rendered;
3888
+ })()
3889
+ ) : selectableOptions.map(({ option, flatIdx }) => renderOptionItem(option, flatIdx)))),
3890
+ document.body
3891
+ ));
3871
3892
  function renderOptionItem(option, flatIdx) {
3872
3893
  const selected = isSelected(option);
3873
3894
  const focused = focusedIdx === flatIdx;
@@ -4558,6 +4579,7 @@ function DataGrid({
4558
4579
 
4559
4580
  // lib/Select/Select.tsx
4560
4581
  var import_react23 = __toESM(require("react"), 1);
4582
+ var import_react_dom3 = __toESM(require("react-dom"), 1);
4561
4583
  var ChevronDownIcon2 = () => /* @__PURE__ */ import_react23.default.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react23.default.createElement("polyline", { points: "6 9 12 15 18 9" }));
4562
4584
  var CheckIcon2 = () => /* @__PURE__ */ import_react23.default.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react23.default.createElement("polyline", { points: "20 6 9 17 4 12" }));
4563
4585
  function normaliseOptions(options) {
@@ -4584,10 +4606,20 @@ var Select = import_react23.default.forwardRef(function Select2(props, ref) {
4584
4606
  } = props;
4585
4607
  const [open, setOpen] = (0, import_react23.useState)(false);
4586
4608
  const [focusedIdx, setFocusedIdx] = (0, import_react23.useState)(-1);
4609
+ const [popupStyle, setPopupStyle] = (0, import_react23.useState)({});
4587
4610
  const containerRef = (0, import_react23.useRef)(null);
4588
4611
  const listRef = (0, import_react23.useRef)(null);
4589
4612
  const inputId = (0, import_react23.useRef)(`rf-sel-${Math.random().toString(36).slice(2, 9)}`).current;
4590
4613
  const sxClass = useSx(sx);
4614
+ const calcPopupStyle = (0, import_react23.useCallback)(() => {
4615
+ if (!containerRef.current) return;
4616
+ const rect = containerRef.current.getBoundingClientRect();
4617
+ setPopupStyle({
4618
+ top: rect.bottom + 4,
4619
+ left: rect.left,
4620
+ width: rect.width
4621
+ });
4622
+ }, []);
4591
4623
  const options = normaliseOptions(rawOptions);
4592
4624
  const selectedValues = multiple ? Array.isArray(value) ? value : value != null ? [value] : [] : value != null ? [value] : [];
4593
4625
  const isSelected = (0, import_react23.useCallback)(
@@ -4599,9 +4631,10 @@ var Select = import_react23.default.forwardRef(function Select2(props, ref) {
4599
4631
  const isFloating = Boolean(open || hasValue);
4600
4632
  const openPopup = (0, import_react23.useCallback)(() => {
4601
4633
  if (disabled) return;
4634
+ calcPopupStyle();
4602
4635
  setOpen(true);
4603
4636
  setFocusedIdx(-1);
4604
- }, [disabled]);
4637
+ }, [disabled, calcPopupStyle]);
4605
4638
  const closePopup = (0, import_react23.useCallback)(() => {
4606
4639
  setOpen(false);
4607
4640
  setFocusedIdx(-1);
@@ -4612,14 +4645,20 @@ var Select = import_react23.default.forwardRef(function Select2(props, ref) {
4612
4645
  }, [open, openPopup, closePopup]);
4613
4646
  (0, import_react23.useEffect)(() => {
4614
4647
  if (!open) return;
4615
- const handler = (e) => {
4648
+ const handleOutside = (e) => {
4616
4649
  if (containerRef.current && !containerRef.current.contains(e.target)) {
4617
4650
  closePopup();
4618
4651
  }
4619
4652
  };
4620
- document.addEventListener("mousedown", handler);
4621
- return () => document.removeEventListener("mousedown", handler);
4622
- }, [open, closePopup]);
4653
+ document.addEventListener("mousedown", handleOutside);
4654
+ window.addEventListener("scroll", calcPopupStyle, true);
4655
+ window.addEventListener("resize", calcPopupStyle);
4656
+ return () => {
4657
+ document.removeEventListener("mousedown", handleOutside);
4658
+ window.removeEventListener("scroll", calcPopupStyle, true);
4659
+ window.removeEventListener("resize", calcPopupStyle);
4660
+ };
4661
+ }, [open, closePopup, calcPopupStyle]);
4623
4662
  const selectOption = (0, import_react23.useCallback)((opt) => {
4624
4663
  if (opt.disabled) return;
4625
4664
  if (multiple) {
@@ -4738,32 +4777,35 @@ var Select = import_react23.default.forwardRef(function Select2(props, ref) {
4738
4777
  /* @__PURE__ */ import_react23.default.createElement("div", { className: "rf-select__arrow", "aria-hidden": "true" }, /* @__PURE__ */ import_react23.default.createElement(ChevronDownIcon2, null))
4739
4778
  ),
4740
4779
  helperText && /* @__PURE__ */ import_react23.default.createElement("div", { className: `rf-text-field__helper-text${error ? " rf-text-field__helper-text--error" : ""}` }, helperText),
4741
- open && !disabled && /* @__PURE__ */ import_react23.default.createElement("div", { className: "rf-select__popup", role: "presentation" }, /* @__PURE__ */ import_react23.default.createElement("ul", { ref: listRef, className: "rf-select__listbox", role: "listbox", "aria-multiselectable": multiple }, options.map((opt, idx) => {
4742
- const selected = isSelected(opt.value);
4743
- const focused = focusedIdx === idx;
4744
- return /* @__PURE__ */ import_react23.default.createElement(
4745
- "li",
4746
- {
4747
- key: opt.value,
4748
- "data-idx": idx,
4749
- role: "option",
4750
- "aria-selected": selected,
4751
- "aria-disabled": opt.disabled,
4752
- className: [
4753
- "rf-select__option",
4754
- selected ? "rf-select__option--selected" : "",
4755
- focused ? "rf-select__option--focused" : "",
4756
- opt.disabled ? "rf-select__option--disabled" : ""
4757
- ].filter(Boolean).join(" "),
4758
- onMouseEnter: () => setFocusedIdx(idx),
4759
- onMouseLeave: () => setFocusedIdx(-1),
4760
- onMouseDown: (e) => e.preventDefault(),
4761
- onClick: () => selectOption(opt)
4762
- },
4763
- /* @__PURE__ */ import_react23.default.createElement("span", { className: "rf-select__option-label" }, opt.label),
4764
- /* @__PURE__ */ import_react23.default.createElement("span", { className: "rf-select__option-check", "aria-hidden": "true" }, /* @__PURE__ */ import_react23.default.createElement(CheckIcon2, null))
4765
- );
4766
- })))
4780
+ open && !disabled && import_react_dom3.default.createPortal(
4781
+ /* @__PURE__ */ import_react23.default.createElement("div", { className: "rf-select__popup", role: "presentation", style: popupStyle }, /* @__PURE__ */ import_react23.default.createElement("ul", { ref: listRef, className: "rf-select__listbox", role: "listbox", "aria-multiselectable": multiple }, options.map((opt, idx) => {
4782
+ const selected = isSelected(opt.value);
4783
+ const focused = focusedIdx === idx;
4784
+ return /* @__PURE__ */ import_react23.default.createElement(
4785
+ "li",
4786
+ {
4787
+ key: opt.value,
4788
+ "data-idx": idx,
4789
+ role: "option",
4790
+ "aria-selected": selected,
4791
+ "aria-disabled": opt.disabled,
4792
+ className: [
4793
+ "rf-select__option",
4794
+ selected ? "rf-select__option--selected" : "",
4795
+ focused ? "rf-select__option--focused" : "",
4796
+ opt.disabled ? "rf-select__option--disabled" : ""
4797
+ ].filter(Boolean).join(" "),
4798
+ onMouseEnter: () => setFocusedIdx(idx),
4799
+ onMouseLeave: () => setFocusedIdx(-1),
4800
+ onMouseDown: (e) => e.preventDefault(),
4801
+ onClick: () => selectOption(opt)
4802
+ },
4803
+ /* @__PURE__ */ import_react23.default.createElement("span", { className: "rf-select__option-label" }, opt.label),
4804
+ /* @__PURE__ */ import_react23.default.createElement("span", { className: "rf-select__option-check", "aria-hidden": "true" }, /* @__PURE__ */ import_react23.default.createElement(CheckIcon2, null))
4805
+ );
4806
+ }))),
4807
+ document.body
4808
+ )
4767
4809
  );
4768
4810
  });
4769
4811
  Select.displayName = "Select";
@@ -5921,7 +5963,7 @@ Skeleton.displayName = "Skeleton";
5921
5963
 
5922
5964
  // lib/Tooltip/Tooltip.tsx
5923
5965
  var import_react35 = __toESM(require("react"), 1);
5924
- var import_react_dom2 = __toESM(require("react-dom"), 1);
5966
+ var import_react_dom4 = __toESM(require("react-dom"), 1);
5925
5967
  var GAP = 8;
5926
5968
  function computePosition(anchor, tooltip, placement) {
5927
5969
  const { top: aTop, left: aLeft, width: aW, height: aH } = anchor;
@@ -6140,7 +6182,7 @@ var Tooltip = ({
6140
6182
  ...childProps
6141
6183
  },
6142
6184
  import_react35.default.cloneElement(children)
6143
- ), import_react_dom2.default.createPortal(tooltipElement, document.body));
6185
+ ), import_react_dom4.default.createPortal(tooltipElement, document.body));
6144
6186
  };
6145
6187
  Tooltip.displayName = "Tooltip";
6146
6188
 
@@ -7027,7 +7069,7 @@ Stepper.displayName = "Stepper";
7027
7069
 
7028
7070
  // lib/Menu/Menu.tsx
7029
7071
  var import_react40 = __toESM(require("react"), 1);
7030
- var import_react_dom3 = __toESM(require("react-dom"), 1);
7072
+ var import_react_dom5 = __toESM(require("react-dom"), 1);
7031
7073
  var MenuDivider = () => /* @__PURE__ */ import_react40.default.createElement("hr", { className: "rf-menu-divider", "aria-hidden": "true" });
7032
7074
  MenuDivider.displayName = "MenuDivider";
7033
7075
  var MenuItem = ({
@@ -7180,13 +7222,13 @@ var Menu = ({
7180
7222
  },
7181
7223
  children
7182
7224
  ));
7183
- return import_react_dom3.default.createPortal(portal, document.body);
7225
+ return import_react_dom5.default.createPortal(portal, document.body);
7184
7226
  };
7185
7227
  Menu.displayName = "Menu";
7186
7228
 
7187
7229
  // lib/Drawer/Drawer.tsx
7188
7230
  var import_react41 = __toESM(require("react"), 1);
7189
- var import_react_dom4 = __toESM(require("react-dom"), 1);
7231
+ var import_react_dom6 = __toESM(require("react-dom"), 1);
7190
7232
  var Drawer = ({
7191
7233
  open,
7192
7234
  onClose,
@@ -7286,7 +7328,7 @@ var Drawer = ({
7286
7328
  },
7287
7329
  children
7288
7330
  ));
7289
- return import_react_dom4.default.createPortal(
7331
+ return import_react_dom6.default.createPortal(
7290
7332
  /* @__PURE__ */ import_react41.default.createElement("div", { className: rootClasses, style }, drawerContent),
7291
7333
  document.body
7292
7334
  );
@@ -7295,7 +7337,7 @@ Drawer.displayName = "Drawer";
7295
7337
 
7296
7338
  // lib/Snackbar/Snackbar.tsx
7297
7339
  var import_react42 = __toESM(require("react"), 1);
7298
- var import_react_dom5 = __toESM(require("react-dom"), 1);
7340
+ var import_react_dom7 = __toESM(require("react-dom"), 1);
7299
7341
  var SEVERITY_ICONS = {
7300
7342
  success: "\u2713",
7301
7343
  error: "\u2715",
@@ -7400,7 +7442,7 @@ var Snackbar = ({
7400
7442
  "\u2715"
7401
7443
  )
7402
7444
  ));
7403
- return import_react_dom5.default.createPortal(snackbarEl, document.body);
7445
+ return import_react_dom7.default.createPortal(snackbarEl, document.body);
7404
7446
  };
7405
7447
  Snackbar.displayName = "Snackbar";
7406
7448
 
@@ -7454,7 +7496,7 @@ Link.displayName = "Link";
7454
7496
 
7455
7497
  // lib/Popper/Popper.tsx
7456
7498
  var import_react44 = __toESM(require("react"), 1);
7457
- var import_react_dom6 = __toESM(require("react-dom"), 1);
7499
+ var import_react_dom8 = __toESM(require("react-dom"), 1);
7458
7500
  function computePopperPosition(anchorRect, popperRect, placement, offset2 = [0, 8]) {
7459
7501
  const [skid, dist] = offset2;
7460
7502
  let top = 0;
@@ -7597,13 +7639,13 @@ var Popper = ({
7597
7639
  if (disablePortal) {
7598
7640
  return /* @__PURE__ */ import_react44.default.createElement(import_react44.default.Fragment, null, popper);
7599
7641
  }
7600
- return import_react_dom6.default.createPortal(popper, document.body);
7642
+ return import_react_dom8.default.createPortal(popper, document.body);
7601
7643
  };
7602
7644
  Popper.displayName = "Popper";
7603
7645
 
7604
7646
  // lib/Popover/Popover.tsx
7605
7647
  var import_react45 = __toESM(require("react"), 1);
7606
- var import_react_dom7 = __toESM(require("react-dom"), 1);
7648
+ var import_react_dom9 = __toESM(require("react-dom"), 1);
7607
7649
  function getPoint(rect, v, h) {
7608
7650
  const x = h === "left" ? rect.left : h === "center" ? rect.left + rect.width / 2 : rect.right;
7609
7651
  const y = v === "top" ? rect.top : v === "center" ? rect.top + rect.height / 2 : rect.bottom;
@@ -7706,7 +7748,7 @@ var Popover = ({
7706
7748
  if (disablePortal) {
7707
7749
  return /* @__PURE__ */ import_react45.default.createElement("div", { className: `${rootClasses} rf-popover-inline`, style }, content);
7708
7750
  }
7709
- return import_react_dom7.default.createPortal(
7751
+ return import_react_dom9.default.createPortal(
7710
7752
  /* @__PURE__ */ import_react45.default.createElement("div", { className: rootClasses, style }, content),
7711
7753
  document.body
7712
7754
  );
@@ -8357,7 +8399,7 @@ PhoneField.displayName = "PhoneField";
8357
8399
 
8358
8400
  // lib/RufousTextEditor/RufousTextEditor.tsx
8359
8401
  var import_react59 = __toESM(require("react"), 1);
8360
- var import_react_dom14 = require("react-dom");
8402
+ var import_react_dom16 = require("react-dom");
8361
8403
  var import_react60 = require("@tiptap/react");
8362
8404
  var import_starter_kit = __toESM(require("@tiptap/starter-kit"), 1);
8363
8405
  var import_extension_placeholder = __toESM(require("@tiptap/extension-placeholder"), 1);
@@ -8479,7 +8521,7 @@ function createMentionSuggestion(users) {
8479
8521
 
8480
8522
  // lib/RufousTextEditor/Toolbar.tsx
8481
8523
  var import_react55 = __toESM(require("react"), 1);
8482
- var import_react_dom10 = require("react-dom");
8524
+ var import_react_dom12 = require("react-dom");
8483
8525
 
8484
8526
  // lib/RufousTextEditor/TextToSpeech.tsx
8485
8527
  var import_react51 = __toESM(require("react"), 1);
@@ -8792,7 +8834,7 @@ var SpeechToText_default = SpeechToText;
8792
8834
 
8793
8835
  // lib/RufousTextEditor/AICommands.tsx
8794
8836
  var import_react53 = __toESM(require("react"), 1);
8795
- var import_react_dom8 = require("react-dom");
8837
+ var import_react_dom10 = require("react-dom");
8796
8838
  var AI_COMMANDS = [
8797
8839
  { id: "improve", label: "Improve writing", prompt: "Improve the following text to make it clearer, more engaging, and well-structured. Return only the improved text, no explanations." },
8798
8840
  { id: "shorter", label: "Make shorter", prompt: "Make the following text shorter and more concise while keeping the key points. Return only the shortened text, no explanations." },
@@ -8949,7 +8991,7 @@ var AICommands = ({ editor, onAICommand }) => {
8949
8991
  onClick: () => handleCommandSelect(cmd)
8950
8992
  },
8951
8993
  cmd.label
8952
- ))), /* @__PURE__ */ import_react53.default.createElement("div", { className: "ai-commands-hint" }, editor.state.selection.empty ? "Will apply to all text" : "Will apply to selected text"))), showModal && (0, import_react_dom8.createPortal)(
8994
+ ))), /* @__PURE__ */ import_react53.default.createElement("div", { className: "ai-commands-hint" }, editor.state.selection.empty ? "Will apply to all text" : "Will apply to selected text"))), showModal && (0, import_react_dom10.createPortal)(
8953
8995
  /* @__PURE__ */ import_react53.default.createElement("div", { className: "ai-modal-overlay", onMouseDown: handleCancel }, /* @__PURE__ */ import_react53.default.createElement("div", { className: "ai-modal", onMouseDown: (e) => e.stopPropagation() }, /* @__PURE__ */ import_react53.default.createElement("div", { className: "ai-modal-header" }, /* @__PURE__ */ import_react53.default.createElement("span", { className: "ai-modal-title" }, "AI Assistant"), /* @__PURE__ */ import_react53.default.createElement("button", { className: "ai-modal-close", onClick: handleCancel }, "\xD7")), /* @__PURE__ */ import_react53.default.createElement("div", { className: "ai-modal-prompt-section" }, /* @__PURE__ */ import_react53.default.createElement("label", { className: "ai-modal-label" }, "Prompt"), /* @__PURE__ */ import_react53.default.createElement("div", { className: "ai-modal-prompt-row" }, /* @__PURE__ */ import_react53.default.createElement(
8954
8996
  "textarea",
8955
8997
  {
@@ -9000,7 +9042,7 @@ var AICommands_default = AICommands;
9000
9042
 
9001
9043
  // lib/RufousTextEditor/TranslateModal.tsx
9002
9044
  var import_react54 = __toESM(require("react"), 1);
9003
- var import_react_dom9 = require("react-dom");
9045
+ var import_react_dom11 = require("react-dom");
9004
9046
  var LANGUAGES = [
9005
9047
  { code: "af", name: "Afrikaans" },
9006
9048
  { code: "sq", name: "Albanian" },
@@ -9191,7 +9233,7 @@ var TranslateModal = ({ editor, onClose, onTranslate, initialSource, initialTarg
9191
9233
  setTranslating(false);
9192
9234
  }
9193
9235
  };
9194
- return (0, import_react_dom9.createPortal)(
9236
+ return (0, import_react_dom11.createPortal)(
9195
9237
  /* @__PURE__ */ import_react54.default.createElement("div", { className: "modal-overlay", onClick: onClose }, /* @__PURE__ */ import_react54.default.createElement("div", { className: "modal-content translate-modal", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ import_react54.default.createElement("div", { className: "modal-header" }, /* @__PURE__ */ import_react54.default.createElement("h3", null, "Translate options"), /* @__PURE__ */ import_react54.default.createElement("button", { className: "modal-close", onClick: onClose }, "\xD7")), /* @__PURE__ */ import_react54.default.createElement("div", { className: "modal-body" }, /* @__PURE__ */ import_react54.default.createElement("div", { className: "translate-columns" }, /* @__PURE__ */ import_react54.default.createElement("div", { className: "translate-col" }, /* @__PURE__ */ import_react54.default.createElement("div", { className: "translate-filter" }, /* @__PURE__ */ import_react54.default.createElement(
9196
9238
  "input",
9197
9239
  {
@@ -10101,7 +10143,7 @@ var Dropdown = ({ trigger, children, className = "", keepOpen = false }) => {
10101
10143
  },
10102
10144
  trigger.label,
10103
10145
  /* @__PURE__ */ import_react55.default.createElement("span", { className: "dropdown-arrow" }, "\u25BE")
10104
- ), open && (0, import_react_dom10.createPortal)(
10146
+ ), open && (0, import_react_dom12.createPortal)(
10105
10147
  /* @__PURE__ */ import_react55.default.createElement("div", { className: "rf-rte-wrapper rf-rte-dropdown-portal" }, /* @__PURE__ */ import_react55.default.createElement("div", { ref: menuRef, className: "dropdown-menu dropdown-menu-fixed", onClick: keepOpen ? void 0 : () => setOpen(false) }, typeof children === "function" ? children(() => setOpen(false)) : children)),
10106
10148
  document.body
10107
10149
  ));
@@ -11004,7 +11046,7 @@ var Toolbar_default = Toolbar;
11004
11046
 
11005
11047
  // lib/RufousTextEditor/ImageToolbar.tsx
11006
11048
  var import_react56 = __toESM(require("react"), 1);
11007
- var import_react_dom11 = require("react-dom");
11049
+ var import_react_dom13 = require("react-dom");
11008
11050
  var ALIGNMENTS = [
11009
11051
  { value: "left", label: "Left", icon: "\u2630" },
11010
11052
  { value: "center", label: "Center", icon: "\u2261" },
@@ -11176,7 +11218,7 @@ var ImageToolbar = ({ editor }) => {
11176
11218
  }, [editor]);
11177
11219
  const node = editor?.state.selection.node;
11178
11220
  const isImage = node && node.type.name === "image";
11179
- if (!editor || !isImage || !pos) return showModal ? (0, import_react_dom11.createPortal)(
11221
+ if (!editor || !isImage || !pos) return showModal ? (0, import_react_dom13.createPortal)(
11180
11222
  /* @__PURE__ */ import_react56.default.createElement(ImagePropertiesModal, { editor, node, onClose: () => setShowModal(false) }),
11181
11223
  document.body
11182
11224
  ) : null;
@@ -11253,7 +11295,7 @@ var ImageToolbar = ({ editor }) => {
11253
11295
  );
11254
11296
  setShowVAlign(false);
11255
11297
  };
11256
- return (0, import_react_dom11.createPortal)(
11298
+ return (0, import_react_dom13.createPortal)(
11257
11299
  /* @__PURE__ */ import_react56.default.createElement(import_react56.default.Fragment, null, /* @__PURE__ */ import_react56.default.createElement(
11258
11300
  "div",
11259
11301
  {
@@ -11284,7 +11326,7 @@ var ImageToolbar_default = ImageToolbar;
11284
11326
 
11285
11327
  // lib/RufousTextEditor/VideoToolbar.tsx
11286
11328
  var import_react57 = __toESM(require("react"), 1);
11287
- var import_react_dom12 = require("react-dom");
11329
+ var import_react_dom14 = require("react-dom");
11288
11330
  var ALIGNMENTS2 = [
11289
11331
  { value: "left", label: "Left", icon: "\u2630" },
11290
11332
  { value: "center", label: "Center", icon: "\u2261" },
@@ -11430,7 +11472,7 @@ var VideoToolbar = ({ editor }) => {
11430
11472
  const node = editor?.state.selection.node;
11431
11473
  const isVideo = node && VIDEO_TYPES.includes(node.type.name);
11432
11474
  const nodeType = node?.type.name;
11433
- if (!editor || !isVideo || !pos) return showModal ? (0, import_react_dom12.createPortal)(
11475
+ if (!editor || !isVideo || !pos) return showModal ? (0, import_react_dom14.createPortal)(
11434
11476
  /* @__PURE__ */ import_react57.default.createElement(VideoPropertiesModal, { editor, node, nodeType, onClose: () => setShowModal(false) }),
11435
11477
  document.body
11436
11478
  ) : null;
@@ -11477,7 +11519,7 @@ var VideoToolbar = ({ editor }) => {
11477
11519
  })
11478
11520
  );
11479
11521
  };
11480
- return (0, import_react_dom12.createPortal)(
11522
+ return (0, import_react_dom14.createPortal)(
11481
11523
  /* @__PURE__ */ import_react57.default.createElement(import_react57.default.Fragment, null, /* @__PURE__ */ import_react57.default.createElement(
11482
11524
  "div",
11483
11525
  {
@@ -11525,7 +11567,7 @@ var VideoToolbar_default = VideoToolbar;
11525
11567
 
11526
11568
  // lib/RufousTextEditor/TableToolbar.tsx
11527
11569
  var import_react58 = __toESM(require("react"), 1);
11528
- var import_react_dom13 = require("react-dom");
11570
+ var import_react_dom15 = require("react-dom");
11529
11571
  var IconAddRowBefore = () => /* @__PURE__ */ import_react58.default.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ import_react58.default.createElement("path", { d: "M20 3H4c-.55 0-1 .45-1 1v16c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zm-1 8H5V5h14v6zm0 8H5v-6h14v6z" }), /* @__PURE__ */ import_react58.default.createElement("path", { d: "M9 6h2v1.5h1.5v2H11V11H9V9.5H7.5v-2H9z" }));
11530
11572
  var IconAddRowAfter = () => /* @__PURE__ */ import_react58.default.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ import_react58.default.createElement("path", { d: "M20 3H4c-.55 0-1 .45-1 1v16c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zm-1 8H5V5h14v6zm0 8H5v-6h14v6z" }), /* @__PURE__ */ import_react58.default.createElement("path", { d: "M9 14h2v1.5h1.5v2H11V19H9v-1.5H7.5v-2H9z" }));
11531
11573
  var IconAddColBefore = () => /* @__PURE__ */ import_react58.default.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ import_react58.default.createElement("path", { d: "M20 3H4c-.55 0-1 .45-1 1v16c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zm-9 16H5V5h6v14zm8 0h-6V5h6v14z" }), /* @__PURE__ */ import_react58.default.createElement("path", { d: "M6 10h1.5v2H6v1.5H4v-2h1.5V10H4V8h2z", transform: "translate(2,1)" }));
@@ -11582,7 +11624,7 @@ var TableToolbar = ({ editor }) => {
11582
11624
  const canMerge = editor.can().mergeCells();
11583
11625
  const canSplit = editor.can().splitCell();
11584
11626
  const prevent = (e) => e.preventDefault();
11585
- return (0, import_react_dom13.createPortal)(
11627
+ return (0, import_react_dom15.createPortal)(
11586
11628
  /* @__PURE__ */ import_react58.default.createElement(
11587
11629
  "div",
11588
11630
  {
@@ -12271,7 +12313,7 @@ var RufousTextEditor = ({
12271
12313
  },
12272
12314
  "\u201C Quote"
12273
12315
  )
12274
- ), /* @__PURE__ */ import_react59.default.createElement("div", { className: "status-bar" }, /* @__PURE__ */ import_react59.default.createElement("div", { className: "status-bar-left" }, onSaveProp && /* @__PURE__ */ import_react59.default.createElement("button", { onClick: handleSave, className: "status-btn save-btn" }, "Save"), onExportProp && /* @__PURE__ */ import_react59.default.createElement("button", { onClick: handleExport, className: "status-btn export-btn" }, "Export")), /* @__PURE__ */ import_react59.default.createElement("div", { className: "status-bar-right" }, saveStatus && /* @__PURE__ */ import_react59.default.createElement("span", { className: "save-status" }, saveStatus), editor && /* @__PURE__ */ import_react59.default.createElement(import_react59.default.Fragment, null, /* @__PURE__ */ import_react59.default.createElement("span", { className: "word-count" }, "CHARS: ", editor.storage.characterCount?.characters?.() ?? editor.getText().length), /* @__PURE__ */ import_react59.default.createElement("span", { className: "word-count" }, "WORDS: ", editor.storage.characterCount?.words?.() ?? editor.getText().split(/\s+/).filter(Boolean).length)))), linkModalOpen && (0, import_react_dom14.createPortal)(
12316
+ ), /* @__PURE__ */ import_react59.default.createElement("div", { className: "status-bar" }, /* @__PURE__ */ import_react59.default.createElement("div", { className: "status-bar-left" }, onSaveProp && /* @__PURE__ */ import_react59.default.createElement("button", { onClick: handleSave, className: "status-btn save-btn" }, "Save"), onExportProp && /* @__PURE__ */ import_react59.default.createElement("button", { onClick: handleExport, className: "status-btn export-btn" }, "Export")), /* @__PURE__ */ import_react59.default.createElement("div", { className: "status-bar-right" }, saveStatus && /* @__PURE__ */ import_react59.default.createElement("span", { className: "save-status" }, saveStatus), editor && /* @__PURE__ */ import_react59.default.createElement(import_react59.default.Fragment, null, /* @__PURE__ */ import_react59.default.createElement("span", { className: "word-count" }, "CHARS: ", editor.storage.characterCount?.characters?.() ?? editor.getText().length), /* @__PURE__ */ import_react59.default.createElement("span", { className: "word-count" }, "WORDS: ", editor.storage.characterCount?.words?.() ?? editor.getText().split(/\s+/).filter(Boolean).length)))), linkModalOpen && (0, import_react_dom16.createPortal)(
12275
12317
  /* @__PURE__ */ import_react59.default.createElement("div", { className: "link-modal-overlay", onClick: handleLinkCancel }, /* @__PURE__ */ import_react59.default.createElement("div", { className: "link-modal", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ import_react59.default.createElement("div", { className: "link-modal-body" }, /* @__PURE__ */ import_react59.default.createElement("div", { className: "link-modal-field" }, /* @__PURE__ */ import_react59.default.createElement("label", { className: "link-modal-label" }, "URL"), /* @__PURE__ */ import_react59.default.createElement(
12276
12318
  "input",
12277
12319
  {
@@ -12316,7 +12358,7 @@ var RufousTextEditor = ({
12316
12358
  )),
12317
12359
  helperText && /* @__PURE__ */ import_react59.default.createElement("div", { className: `rf-rte-helper-text ${error ? "rf-rte-helper-error" : ""}` }, helperText)
12318
12360
  );
12319
- return isFullscreen ? (0, import_react_dom14.createPortal)(wrapperJsx, document.body) : wrapperJsx;
12361
+ return isFullscreen ? (0, import_react_dom16.createPortal)(wrapperJsx, document.body) : wrapperJsx;
12320
12362
  };
12321
12363
  var RufousTextContent = ({ content, className, style, sx }) => {
12322
12364
  const sxClass = useSx(sx);
package/dist/main.css CHANGED
@@ -75,6 +75,13 @@
75
75
  z-index: 2000;
76
76
  backdrop-filter: blur(2px);
77
77
  }
78
+ .MuiPopover-root,
79
+ .MuiMenu-root,
80
+ .MuiAutocomplete-popper,
81
+ .MuiTooltip-popper,
82
+ .MuiModal-root:not(.dialog-overlay) {
83
+ z-index: 2100 !important;
84
+ }
78
85
  .dialog-container {
79
86
  background: var(--surface-color);
80
87
  color: var(--text-color);
@@ -2235,12 +2242,9 @@ pre {
2235
2242
  flex-shrink: 0;
2236
2243
  }
2237
2244
  .rf-autocomplete__popup {
2238
- position: absolute;
2239
- top: calc(100% + 4px);
2240
- left: 0;
2241
- right: 0;
2242
- z-index: 1400;
2243
- background: #ffffff;
2245
+ position: fixed;
2246
+ z-index: 2100;
2247
+ background: var(--surface-color, #ffffff);
2244
2248
  border-radius: 8px;
2245
2249
  box-shadow:
2246
2250
  0 4px 6px rgba(0, 0, 0, 0.06),
@@ -2489,11 +2493,8 @@ pre {
2489
2493
  margin-top: 17px;
2490
2494
  }
2491
2495
  .rf-select__popup {
2492
- position: absolute;
2493
- top: calc(100% + 4px);
2494
- left: 0;
2495
- right: 0;
2496
- z-index: 1400;
2496
+ position: fixed;
2497
+ z-index: 2100;
2497
2498
  background: var(--surface-color, #ffffff);
2498
2499
  border-radius: 8px;
2499
2500
  box-shadow:
package/dist/main.js CHANGED
@@ -3388,6 +3388,7 @@ import React72, {
3388
3388
  useEffect as useEffect6,
3389
3389
  useCallback as useCallback2
3390
3390
  } from "react";
3391
+ import ReactDOM from "react-dom";
3391
3392
  var ChevronDownIcon = () => /* @__PURE__ */ React72.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React72.createElement("polyline", { points: "6 9 12 15 18 9" }));
3392
3393
  var CloseSmIcon = ({ size = 16 }) => /* @__PURE__ */ React72.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round" }, /* @__PURE__ */ React72.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), /* @__PURE__ */ React72.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" }));
3393
3394
  var CheckIcon = () => /* @__PURE__ */ React72.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React72.createElement("polyline", { points: "20 6 9 17 4 12" }));
@@ -3441,11 +3442,21 @@ function AutocompleteInner(props, _ref) {
3441
3442
  const [open, setOpen] = useState7(false);
3442
3443
  const [inputStr, setInputStr] = useState7("");
3443
3444
  const [focusedIdx, setFocusedIdx] = useState7(-1);
3445
+ const [popupStyle, setPopupStyle] = useState7({});
3444
3446
  const containerRef = useRef6(null);
3445
3447
  const inputRef = useRef6(null);
3446
3448
  const listRef = useRef6(null);
3447
3449
  const inputId = useRef6(`rf-ac-${Math.random().toString(36).slice(2, 9)}`).current;
3448
3450
  const sxClass = useSx(sx);
3451
+ const calcPopupStyle = useCallback2(() => {
3452
+ if (!containerRef.current) return;
3453
+ const rect = containerRef.current.getBoundingClientRect();
3454
+ setPopupStyle({
3455
+ top: rect.bottom + 4,
3456
+ left: rect.left,
3457
+ width: rect.width
3458
+ });
3459
+ }, []);
3449
3460
  const activeInput = controlledInput !== void 0 ? controlledInput : inputStr;
3450
3461
  const selectedValues = multiple ? Array.isArray(value) ? value : [] : value != null ? [value] : [];
3451
3462
  const isEqual = useCallback2(
@@ -3479,12 +3490,13 @@ function AutocompleteInner(props, _ref) {
3479
3490
  filtered.forEach((opt, i) => flatEntries.push({ kind: "option", option: opt, flatIdx: i }));
3480
3491
  }
3481
3492
  const selectableOptions = flatEntries.filter((e) => e.kind === "option");
3482
- const openPopup = () => {
3493
+ const openPopup = useCallback2(() => {
3483
3494
  if (disabled) return;
3495
+ calcPopupStyle();
3484
3496
  setOpen(true);
3485
3497
  setFocusedIdx(-1);
3486
3498
  onOpen?.();
3487
- };
3499
+ }, [disabled, calcPopupStyle, onOpen]);
3488
3500
  const closePopup = useCallback2(() => {
3489
3501
  setOpen(false);
3490
3502
  setFocusedIdx(-1);
@@ -3496,14 +3508,20 @@ function AutocompleteInner(props, _ref) {
3496
3508
  }, [freeSolo, multiple, value, onInputChange, onClose]);
3497
3509
  useEffect6(() => {
3498
3510
  if (!open) return;
3499
- const handler = (e) => {
3511
+ const handleOutside = (e) => {
3500
3512
  if (containerRef.current && !containerRef.current.contains(e.target)) {
3501
3513
  closePopup();
3502
3514
  }
3503
3515
  };
3504
- document.addEventListener("mousedown", handler);
3505
- return () => document.removeEventListener("mousedown", handler);
3506
- }, [open, closePopup]);
3516
+ document.addEventListener("mousedown", handleOutside);
3517
+ window.addEventListener("scroll", calcPopupStyle, true);
3518
+ window.addEventListener("resize", calcPopupStyle);
3519
+ return () => {
3520
+ document.removeEventListener("mousedown", handleOutside);
3521
+ window.removeEventListener("scroll", calcPopupStyle, true);
3522
+ window.removeEventListener("resize", calcPopupStyle);
3523
+ };
3524
+ }, [open, closePopup, calcPopupStyle]);
3507
3525
  useEffect6(() => {
3508
3526
  if (controlledInput !== void 0) return;
3509
3527
  if (!multiple) {
@@ -3688,34 +3706,37 @@ function AutocompleteInner(props, _ref) {
3688
3706
  },
3689
3707
  /* @__PURE__ */ React72.createElement(ChevronDownIcon, null)
3690
3708
  ))
3691
- ), helperText && /* @__PURE__ */ React72.createElement("div", { className: `rf-text-field__helper-text${error ? " rf-text-field__helper-text--error" : ""}` }, helperText), open && !disabled && /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__popup", role: "presentation" }, loading ? /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__loading" }, /* @__PURE__ */ React72.createElement("span", { className: "rf-ac-spinner" }), loadingText) : flatEntries.length === 0 ? /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__no-options" }, noOptionsText) : /* @__PURE__ */ React72.createElement("ul", { ref: listRef, className: "rf-autocomplete__listbox", role: "listbox" }, groupBy ? (
3692
- // Grouped render
3693
- (() => {
3694
- const rendered = [];
3695
- let groupItems = [];
3696
- let currentGroup = "";
3697
- flatEntries.forEach((entry, ei) => {
3698
- if (entry.kind === "group") {
3699
- if (groupItems.length > 0) {
3709
+ ), helperText && /* @__PURE__ */ React72.createElement("div", { className: `rf-text-field__helper-text${error ? " rf-text-field__helper-text--error" : ""}` }, helperText), open && !disabled && ReactDOM.createPortal(
3710
+ /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__popup", role: "presentation", style: popupStyle }, loading ? /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__loading" }, /* @__PURE__ */ React72.createElement("span", { className: "rf-ac-spinner" }), loadingText) : flatEntries.length === 0 ? /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__no-options" }, noOptionsText) : /* @__PURE__ */ React72.createElement("ul", { ref: listRef, className: "rf-autocomplete__listbox", role: "listbox" }, groupBy ? (
3711
+ // Grouped render
3712
+ (() => {
3713
+ const rendered = [];
3714
+ let groupItems = [];
3715
+ let currentGroup = "";
3716
+ flatEntries.forEach((entry, ei) => {
3717
+ if (entry.kind === "group") {
3718
+ if (groupItems.length > 0) {
3719
+ rendered.push(
3720
+ /* @__PURE__ */ React72.createElement("li", { key: `g-${currentGroup}`, role: "presentation" }, /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__group-header" }, currentGroup), /* @__PURE__ */ React72.createElement("ul", { className: "rf-autocomplete__group-items", role: "group" }, groupItems))
3721
+ );
3722
+ groupItems = [];
3723
+ }
3724
+ currentGroup = entry.label;
3725
+ } else {
3726
+ const { option, flatIdx } = entry;
3727
+ groupItems.push(renderOptionItem(option, flatIdx));
3728
+ }
3729
+ if (ei === flatEntries.length - 1 && groupItems.length > 0) {
3700
3730
  rendered.push(
3701
3731
  /* @__PURE__ */ React72.createElement("li", { key: `g-${currentGroup}`, role: "presentation" }, /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__group-header" }, currentGroup), /* @__PURE__ */ React72.createElement("ul", { className: "rf-autocomplete__group-items", role: "group" }, groupItems))
3702
3732
  );
3703
- groupItems = [];
3704
3733
  }
3705
- currentGroup = entry.label;
3706
- } else {
3707
- const { option, flatIdx } = entry;
3708
- groupItems.push(renderOptionItem(option, flatIdx));
3709
- }
3710
- if (ei === flatEntries.length - 1 && groupItems.length > 0) {
3711
- rendered.push(
3712
- /* @__PURE__ */ React72.createElement("li", { key: `g-${currentGroup}`, role: "presentation" }, /* @__PURE__ */ React72.createElement("div", { className: "rf-autocomplete__group-header" }, currentGroup), /* @__PURE__ */ React72.createElement("ul", { className: "rf-autocomplete__group-items", role: "group" }, groupItems))
3713
- );
3714
- }
3715
- });
3716
- return rendered;
3717
- })()
3718
- ) : selectableOptions.map(({ option, flatIdx }) => renderOptionItem(option, flatIdx)))));
3734
+ });
3735
+ return rendered;
3736
+ })()
3737
+ ) : selectableOptions.map(({ option, flatIdx }) => renderOptionItem(option, flatIdx)))),
3738
+ document.body
3739
+ ));
3719
3740
  function renderOptionItem(option, flatIdx) {
3720
3741
  const selected = isSelected(option);
3721
3742
  const focused = focusedIdx === flatIdx;
@@ -4428,6 +4449,7 @@ import React75, {
4428
4449
  useEffect as useEffect8,
4429
4450
  useCallback as useCallback3
4430
4451
  } from "react";
4452
+ import ReactDOM2 from "react-dom";
4431
4453
  var ChevronDownIcon2 = () => /* @__PURE__ */ React75.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React75.createElement("polyline", { points: "6 9 12 15 18 9" }));
4432
4454
  var CheckIcon2 = () => /* @__PURE__ */ React75.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React75.createElement("polyline", { points: "20 6 9 17 4 12" }));
4433
4455
  function normaliseOptions(options) {
@@ -4454,10 +4476,20 @@ var Select = React75.forwardRef(function Select2(props, ref) {
4454
4476
  } = props;
4455
4477
  const [open, setOpen] = useState9(false);
4456
4478
  const [focusedIdx, setFocusedIdx] = useState9(-1);
4479
+ const [popupStyle, setPopupStyle] = useState9({});
4457
4480
  const containerRef = useRef9(null);
4458
4481
  const listRef = useRef9(null);
4459
4482
  const inputId = useRef9(`rf-sel-${Math.random().toString(36).slice(2, 9)}`).current;
4460
4483
  const sxClass = useSx(sx);
4484
+ const calcPopupStyle = useCallback3(() => {
4485
+ if (!containerRef.current) return;
4486
+ const rect = containerRef.current.getBoundingClientRect();
4487
+ setPopupStyle({
4488
+ top: rect.bottom + 4,
4489
+ left: rect.left,
4490
+ width: rect.width
4491
+ });
4492
+ }, []);
4461
4493
  const options = normaliseOptions(rawOptions);
4462
4494
  const selectedValues = multiple ? Array.isArray(value) ? value : value != null ? [value] : [] : value != null ? [value] : [];
4463
4495
  const isSelected = useCallback3(
@@ -4469,9 +4501,10 @@ var Select = React75.forwardRef(function Select2(props, ref) {
4469
4501
  const isFloating = Boolean(open || hasValue);
4470
4502
  const openPopup = useCallback3(() => {
4471
4503
  if (disabled) return;
4504
+ calcPopupStyle();
4472
4505
  setOpen(true);
4473
4506
  setFocusedIdx(-1);
4474
- }, [disabled]);
4507
+ }, [disabled, calcPopupStyle]);
4475
4508
  const closePopup = useCallback3(() => {
4476
4509
  setOpen(false);
4477
4510
  setFocusedIdx(-1);
@@ -4482,14 +4515,20 @@ var Select = React75.forwardRef(function Select2(props, ref) {
4482
4515
  }, [open, openPopup, closePopup]);
4483
4516
  useEffect8(() => {
4484
4517
  if (!open) return;
4485
- const handler = (e) => {
4518
+ const handleOutside = (e) => {
4486
4519
  if (containerRef.current && !containerRef.current.contains(e.target)) {
4487
4520
  closePopup();
4488
4521
  }
4489
4522
  };
4490
- document.addEventListener("mousedown", handler);
4491
- return () => document.removeEventListener("mousedown", handler);
4492
- }, [open, closePopup]);
4523
+ document.addEventListener("mousedown", handleOutside);
4524
+ window.addEventListener("scroll", calcPopupStyle, true);
4525
+ window.addEventListener("resize", calcPopupStyle);
4526
+ return () => {
4527
+ document.removeEventListener("mousedown", handleOutside);
4528
+ window.removeEventListener("scroll", calcPopupStyle, true);
4529
+ window.removeEventListener("resize", calcPopupStyle);
4530
+ };
4531
+ }, [open, closePopup, calcPopupStyle]);
4493
4532
  const selectOption = useCallback3((opt) => {
4494
4533
  if (opt.disabled) return;
4495
4534
  if (multiple) {
@@ -4608,32 +4647,35 @@ var Select = React75.forwardRef(function Select2(props, ref) {
4608
4647
  /* @__PURE__ */ React75.createElement("div", { className: "rf-select__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React75.createElement(ChevronDownIcon2, null))
4609
4648
  ),
4610
4649
  helperText && /* @__PURE__ */ React75.createElement("div", { className: `rf-text-field__helper-text${error ? " rf-text-field__helper-text--error" : ""}` }, helperText),
4611
- open && !disabled && /* @__PURE__ */ React75.createElement("div", { className: "rf-select__popup", role: "presentation" }, /* @__PURE__ */ React75.createElement("ul", { ref: listRef, className: "rf-select__listbox", role: "listbox", "aria-multiselectable": multiple }, options.map((opt, idx) => {
4612
- const selected = isSelected(opt.value);
4613
- const focused = focusedIdx === idx;
4614
- return /* @__PURE__ */ React75.createElement(
4615
- "li",
4616
- {
4617
- key: opt.value,
4618
- "data-idx": idx,
4619
- role: "option",
4620
- "aria-selected": selected,
4621
- "aria-disabled": opt.disabled,
4622
- className: [
4623
- "rf-select__option",
4624
- selected ? "rf-select__option--selected" : "",
4625
- focused ? "rf-select__option--focused" : "",
4626
- opt.disabled ? "rf-select__option--disabled" : ""
4627
- ].filter(Boolean).join(" "),
4628
- onMouseEnter: () => setFocusedIdx(idx),
4629
- onMouseLeave: () => setFocusedIdx(-1),
4630
- onMouseDown: (e) => e.preventDefault(),
4631
- onClick: () => selectOption(opt)
4632
- },
4633
- /* @__PURE__ */ React75.createElement("span", { className: "rf-select__option-label" }, opt.label),
4634
- /* @__PURE__ */ React75.createElement("span", { className: "rf-select__option-check", "aria-hidden": "true" }, /* @__PURE__ */ React75.createElement(CheckIcon2, null))
4635
- );
4636
- })))
4650
+ open && !disabled && ReactDOM2.createPortal(
4651
+ /* @__PURE__ */ React75.createElement("div", { className: "rf-select__popup", role: "presentation", style: popupStyle }, /* @__PURE__ */ React75.createElement("ul", { ref: listRef, className: "rf-select__listbox", role: "listbox", "aria-multiselectable": multiple }, options.map((opt, idx) => {
4652
+ const selected = isSelected(opt.value);
4653
+ const focused = focusedIdx === idx;
4654
+ return /* @__PURE__ */ React75.createElement(
4655
+ "li",
4656
+ {
4657
+ key: opt.value,
4658
+ "data-idx": idx,
4659
+ role: "option",
4660
+ "aria-selected": selected,
4661
+ "aria-disabled": opt.disabled,
4662
+ className: [
4663
+ "rf-select__option",
4664
+ selected ? "rf-select__option--selected" : "",
4665
+ focused ? "rf-select__option--focused" : "",
4666
+ opt.disabled ? "rf-select__option--disabled" : ""
4667
+ ].filter(Boolean).join(" "),
4668
+ onMouseEnter: () => setFocusedIdx(idx),
4669
+ onMouseLeave: () => setFocusedIdx(-1),
4670
+ onMouseDown: (e) => e.preventDefault(),
4671
+ onClick: () => selectOption(opt)
4672
+ },
4673
+ /* @__PURE__ */ React75.createElement("span", { className: "rf-select__option-label" }, opt.label),
4674
+ /* @__PURE__ */ React75.createElement("span", { className: "rf-select__option-check", "aria-hidden": "true" }, /* @__PURE__ */ React75.createElement(CheckIcon2, null))
4675
+ );
4676
+ }))),
4677
+ document.body
4678
+ )
4637
4679
  );
4638
4680
  });
4639
4681
  Select.displayName = "Select";
@@ -5807,7 +5849,7 @@ import React87, {
5807
5849
  useRef as useRef14,
5808
5850
  useState as useState13
5809
5851
  } from "react";
5810
- import ReactDOM from "react-dom";
5852
+ import ReactDOM3 from "react-dom";
5811
5853
  var GAP = 8;
5812
5854
  function computePosition(anchor, tooltip, placement) {
5813
5855
  const { top: aTop, left: aLeft, width: aW, height: aH } = anchor;
@@ -6026,7 +6068,7 @@ var Tooltip = ({
6026
6068
  ...childProps
6027
6069
  },
6028
6070
  React87.cloneElement(children)
6029
- ), ReactDOM.createPortal(tooltipElement, document.body));
6071
+ ), ReactDOM3.createPortal(tooltipElement, document.body));
6030
6072
  };
6031
6073
  Tooltip.displayName = "Tooltip";
6032
6074
 
@@ -6932,7 +6974,7 @@ import React97, {
6932
6974
  useRef as useRef16,
6933
6975
  useState as useState17
6934
6976
  } from "react";
6935
- import ReactDOM2 from "react-dom";
6977
+ import ReactDOM4 from "react-dom";
6936
6978
  var MenuDivider = () => /* @__PURE__ */ React97.createElement("hr", { className: "rf-menu-divider", "aria-hidden": "true" });
6937
6979
  MenuDivider.displayName = "MenuDivider";
6938
6980
  var MenuItem = ({
@@ -7085,7 +7127,7 @@ var Menu = ({
7085
7127
  },
7086
7128
  children
7087
7129
  ));
7088
- return ReactDOM2.createPortal(portal, document.body);
7130
+ return ReactDOM4.createPortal(portal, document.body);
7089
7131
  };
7090
7132
  Menu.displayName = "Menu";
7091
7133
 
@@ -7094,7 +7136,7 @@ import React98, {
7094
7136
  useEffect as useEffect13,
7095
7137
  useState as useState18
7096
7138
  } from "react";
7097
- import ReactDOM3 from "react-dom";
7139
+ import ReactDOM5 from "react-dom";
7098
7140
  var Drawer = ({
7099
7141
  open,
7100
7142
  onClose,
@@ -7194,7 +7236,7 @@ var Drawer = ({
7194
7236
  },
7195
7237
  children
7196
7238
  ));
7197
- return ReactDOM3.createPortal(
7239
+ return ReactDOM5.createPortal(
7198
7240
  /* @__PURE__ */ React98.createElement("div", { className: rootClasses, style }, drawerContent),
7199
7241
  document.body
7200
7242
  );
@@ -7208,7 +7250,7 @@ import React99, {
7208
7250
  useRef as useRef17,
7209
7251
  useState as useState19
7210
7252
  } from "react";
7211
- import ReactDOM4 from "react-dom";
7253
+ import ReactDOM6 from "react-dom";
7212
7254
  var SEVERITY_ICONS = {
7213
7255
  success: "\u2713",
7214
7256
  error: "\u2715",
@@ -7313,7 +7355,7 @@ var Snackbar = ({
7313
7355
  "\u2715"
7314
7356
  )
7315
7357
  ));
7316
- return ReactDOM4.createPortal(snackbarEl, document.body);
7358
+ return ReactDOM6.createPortal(snackbarEl, document.body);
7317
7359
  };
7318
7360
  Snackbar.displayName = "Snackbar";
7319
7361
 
@@ -7372,7 +7414,7 @@ import React101, {
7372
7414
  useRef as useRef18,
7373
7415
  useState as useState20
7374
7416
  } from "react";
7375
- import ReactDOM5 from "react-dom";
7417
+ import ReactDOM7 from "react-dom";
7376
7418
  function computePopperPosition(anchorRect, popperRect, placement, offset2 = [0, 8]) {
7377
7419
  const [skid, dist] = offset2;
7378
7420
  let top = 0;
@@ -7515,7 +7557,7 @@ var Popper = ({
7515
7557
  if (disablePortal) {
7516
7558
  return /* @__PURE__ */ React101.createElement(React101.Fragment, null, popper);
7517
7559
  }
7518
- return ReactDOM5.createPortal(popper, document.body);
7560
+ return ReactDOM7.createPortal(popper, document.body);
7519
7561
  };
7520
7562
  Popper.displayName = "Popper";
7521
7563
 
@@ -7526,7 +7568,7 @@ import React102, {
7526
7568
  useRef as useRef19,
7527
7569
  useState as useState21
7528
7570
  } from "react";
7529
- import ReactDOM6 from "react-dom";
7571
+ import ReactDOM8 from "react-dom";
7530
7572
  function getPoint(rect, v, h) {
7531
7573
  const x = h === "left" ? rect.left : h === "center" ? rect.left + rect.width / 2 : rect.right;
7532
7574
  const y = v === "top" ? rect.top : v === "center" ? rect.top + rect.height / 2 : rect.bottom;
@@ -7629,7 +7671,7 @@ var Popover = ({
7629
7671
  if (disablePortal) {
7630
7672
  return /* @__PURE__ */ React102.createElement("div", { className: `${rootClasses} rf-popover-inline`, style }, content);
7631
7673
  }
7632
- return ReactDOM6.createPortal(
7674
+ return ReactDOM8.createPortal(
7633
7675
  /* @__PURE__ */ React102.createElement("div", { className: rootClasses, style }, content),
7634
7676
  document.body
7635
7677
  );
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rufous/ui",
3
3
  "private": false,
4
- "version": "0.2.67",
4
+ "version": "0.2.68",
5
5
  "type": "module",
6
6
  "description": "Experimental: A lightweight React UI component library (Beta)",
7
7
  "style": "./dist/main.css",