@dragunio/fe-libs 0.1.3 → 0.1.4

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/index.js CHANGED
@@ -439,6 +439,7 @@ function Drawer({ open, onClose, title, footer, side = "right", width = 400, ful
439
439
 
440
440
  // packages/form-controls/src/index.tsx
441
441
  var import_react6 = require("react");
442
+ var import_react_dom2 = require("react-dom");
442
443
  var import_jsx_runtime7 = require("react/jsx-runtime");
443
444
  function getFieldError(error, errorMessage) {
444
445
  if (errorMessage !== void 0 && errorMessage !== null) return errorMessage;
@@ -524,13 +525,30 @@ var Selection = (0, import_react6.forwardRef)(function Selection2({ className, l
524
525
  const [query, setQuery] = (0, import_react6.useState)("");
525
526
  const [activeIndex, setActiveIndex] = (0, import_react6.useState)(0);
526
527
  const rootRef = (0, import_react6.useRef)(null);
528
+ const menuRef = (0, import_react6.useRef)(null);
529
+ const [menuPosition, setMenuPosition] = (0, import_react6.useState)(null);
527
530
  (0, import_react6.useEffect)(() => {
528
531
  const close = (event) => {
529
- if (!rootRef.current?.contains(event.target)) setOpen(false);
532
+ const target = event.target;
533
+ if (!rootRef.current?.contains(target) && !menuRef.current?.contains(target)) setOpen(false);
530
534
  };
531
535
  document.addEventListener("mousedown", close);
532
536
  return () => document.removeEventListener("mousedown", close);
533
537
  }, []);
538
+ (0, import_react6.useLayoutEffect)(() => {
539
+ if (!open) return;
540
+ const updateMenuPosition = () => {
541
+ const rect = rootRef.current?.getBoundingClientRect();
542
+ if (rect) setMenuPosition({ top: rect.bottom + 7, left: rect.left, width: rect.width });
543
+ };
544
+ updateMenuPosition();
545
+ window.addEventListener("resize", updateMenuPosition);
546
+ document.addEventListener("scroll", updateMenuPosition, true);
547
+ return () => {
548
+ window.removeEventListener("resize", updateMenuPosition);
549
+ document.removeEventListener("scroll", updateMenuPosition, true);
550
+ };
551
+ }, [open]);
534
552
  const filteredOptions = options.filter((option) => !query || (option.searchText ?? (typeof option.label === "string" ? option.label : String(option.value))).toLowerCase().includes(query.toLowerCase()));
535
553
  const commit = (next) => {
536
554
  if (!isControlled) setInternalValue(next);
@@ -582,7 +600,7 @@ var Selection = (0, import_react6.forwardRef)(function Selection2({ className, l
582
600
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "fe-selection__actions", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "fe-selection__chevron", "aria-hidden": "true" }) })
583
601
  ] }),
584
602
  clearable && selectedOptions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "fe-selection__clear", "aria-label": "Clear selection", onClick: clear }),
585
- open && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { id: listboxId, className: "fe-selection__menu", role: "listbox", "aria-multiselectable": multiple || void 0, children: [
603
+ open && menuPosition && (0, import_react_dom2.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { ref: menuRef, id: listboxId, className: "fe-selection__menu", style: { position: "fixed", top: menuPosition.top, left: menuPosition.left, width: menuPosition.width }, role: "listbox", "aria-multiselectable": multiple || void 0, children: [
586
604
  searchable && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "fe-selection__search", children: [
587
605
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-hidden": "true", children: "\u2315" }),
588
606
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { autoFocus: true, value: query, onChange: (event) => {
@@ -597,7 +615,7 @@ var Selection = (0, import_react6.forwardRef)(function Selection2({ className, l
597
615
  isSelected && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "fe-selection__check", "aria-hidden": "true", children: "\u2713" })
598
616
  ] }, String(option.value));
599
617
  }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "fe-selection__empty", children: "No matching options" }) })
600
- ] })
618
+ ] }), document.body)
601
619
  ] }),
602
620
  helperText && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "fe-selection__helper", children: helperText })
603
621
  ] });
@@ -899,7 +917,7 @@ var Skeleton = Object.assign(SkeletonBase, {
899
917
 
900
918
  // packages/modal/src/index.tsx
901
919
  var import_react9 = require("react");
902
- var import_react_dom2 = require("react-dom");
920
+ var import_react_dom3 = require("react-dom");
903
921
  var import_jsx_runtime12 = require("react/jsx-runtime");
904
922
  function Modal({
905
923
  open,
@@ -929,7 +947,7 @@ function Modal({
929
947
  }, [onClose, open]);
930
948
  if (!open || typeof document === "undefined") return null;
931
949
  const hasFooter = footer || actions.length > 0;
932
- return (0, import_react_dom2.createPortal)(
950
+ return (0, import_react_dom3.createPortal)(
933
951
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "fe-modal-backdrop", role: "presentation", onMouseDown: (event) => {
934
952
  if (event.target === event.currentTarget && closeOnBackdropClick) onClose();
935
953
  }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
package/dist/index.mjs CHANGED
@@ -389,9 +389,11 @@ import {
389
389
  forwardRef as forwardRef3,
390
390
  useEffect as useEffect3,
391
391
  useId,
392
+ useLayoutEffect,
392
393
  useRef as useRef2,
393
394
  useState as useState3
394
395
  } from "react";
396
+ import { createPortal as createPortal2 } from "react-dom";
395
397
  import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
396
398
  function getFieldError(error, errorMessage) {
397
399
  if (errorMessage !== void 0 && errorMessage !== null) return errorMessage;
@@ -477,13 +479,30 @@ var Selection = forwardRef3(function Selection2({ className, label, helperText,
477
479
  const [query, setQuery] = useState3("");
478
480
  const [activeIndex, setActiveIndex] = useState3(0);
479
481
  const rootRef = useRef2(null);
482
+ const menuRef = useRef2(null);
483
+ const [menuPosition, setMenuPosition] = useState3(null);
480
484
  useEffect3(() => {
481
485
  const close = (event) => {
482
- if (!rootRef.current?.contains(event.target)) setOpen(false);
486
+ const target = event.target;
487
+ if (!rootRef.current?.contains(target) && !menuRef.current?.contains(target)) setOpen(false);
483
488
  };
484
489
  document.addEventListener("mousedown", close);
485
490
  return () => document.removeEventListener("mousedown", close);
486
491
  }, []);
492
+ useLayoutEffect(() => {
493
+ if (!open) return;
494
+ const updateMenuPosition = () => {
495
+ const rect = rootRef.current?.getBoundingClientRect();
496
+ if (rect) setMenuPosition({ top: rect.bottom + 7, left: rect.left, width: rect.width });
497
+ };
498
+ updateMenuPosition();
499
+ window.addEventListener("resize", updateMenuPosition);
500
+ document.addEventListener("scroll", updateMenuPosition, true);
501
+ return () => {
502
+ window.removeEventListener("resize", updateMenuPosition);
503
+ document.removeEventListener("scroll", updateMenuPosition, true);
504
+ };
505
+ }, [open]);
487
506
  const filteredOptions = options.filter((option) => !query || (option.searchText ?? (typeof option.label === "string" ? option.label : String(option.value))).toLowerCase().includes(query.toLowerCase()));
488
507
  const commit = (next) => {
489
508
  if (!isControlled) setInternalValue(next);
@@ -535,7 +554,7 @@ var Selection = forwardRef3(function Selection2({ className, label, helperText,
535
554
  /* @__PURE__ */ jsx7("span", { className: "fe-selection__actions", children: /* @__PURE__ */ jsx7("span", { className: "fe-selection__chevron", "aria-hidden": "true" }) })
536
555
  ] }),
537
556
  clearable && selectedOptions.length > 0 && /* @__PURE__ */ jsx7("button", { type: "button", className: "fe-selection__clear", "aria-label": "Clear selection", onClick: clear }),
538
- open && /* @__PURE__ */ jsxs7("div", { id: listboxId, className: "fe-selection__menu", role: "listbox", "aria-multiselectable": multiple || void 0, children: [
557
+ open && menuPosition && createPortal2(/* @__PURE__ */ jsxs7("div", { ref: menuRef, id: listboxId, className: "fe-selection__menu", style: { position: "fixed", top: menuPosition.top, left: menuPosition.left, width: menuPosition.width }, role: "listbox", "aria-multiselectable": multiple || void 0, children: [
539
558
  searchable && /* @__PURE__ */ jsxs7("div", { className: "fe-selection__search", children: [
540
559
  /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\u2315" }),
541
560
  /* @__PURE__ */ jsx7("input", { autoFocus: true, value: query, onChange: (event) => {
@@ -550,7 +569,7 @@ var Selection = forwardRef3(function Selection2({ className, label, helperText,
550
569
  isSelected && /* @__PURE__ */ jsx7("span", { className: "fe-selection__check", "aria-hidden": "true", children: "\u2713" })
551
570
  ] }, String(option.value));
552
571
  }) : /* @__PURE__ */ jsx7("p", { className: "fe-selection__empty", children: "No matching options" }) })
553
- ] })
572
+ ] }), document.body)
554
573
  ] }),
555
574
  helperText && /* @__PURE__ */ jsx7("span", { className: "fe-selection__helper", children: helperText })
556
575
  ] });
@@ -852,7 +871,7 @@ var Skeleton = Object.assign(SkeletonBase, {
852
871
 
853
872
  // packages/modal/src/index.tsx
854
873
  import { useEffect as useEffect4, useId as useId4, useRef as useRef3 } from "react";
855
- import { createPortal as createPortal2 } from "react-dom";
874
+ import { createPortal as createPortal3 } from "react-dom";
856
875
  import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
857
876
  function Modal({
858
877
  open,
@@ -882,7 +901,7 @@ function Modal({
882
901
  }, [onClose, open]);
883
902
  if (!open || typeof document === "undefined") return null;
884
903
  const hasFooter = footer || actions.length > 0;
885
- return createPortal2(
904
+ return createPortal3(
886
905
  /* @__PURE__ */ jsx12("div", { className: "fe-modal-backdrop", role: "presentation", onMouseDown: (event) => {
887
906
  if (event.target === event.currentTarget && closeOnBackdropClick) onClose();
888
907
  }, children: /* @__PURE__ */ jsxs11(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dragunio/fe-libs",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Reusable React components, icons, and table primitives.",
5
5
  "license": "MIT",
6
6
  "repository": {