x-ui-design 0.8.88 → 0.8.90

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.
@@ -2,4 +2,10 @@ import { RuleType } from '../types';
2
2
  export declare const parseValue: (value: RuleType) => RuleType;
3
3
  export declare function createArray(length: number): number[];
4
4
  export declare function clsx(...args: RuleType[]): string;
5
- export declare function getScrollParent(el: HTMLElement | null, includeSelf?: boolean): HTMLElement | null;
5
+ export declare function getElementParentDetails(el: HTMLElement | null, includeSelf?: boolean): {
6
+ relativePosition: {
7
+ left: number;
8
+ top: number;
9
+ };
10
+ scrollableParents: HTMLElement | null;
11
+ };
@@ -6,9 +6,9 @@ type TPopupPosition = {
6
6
  targetRef: RefObject<HTMLDivElement | null>;
7
7
  popupRef: RefObject<HTMLDivElement | null>;
8
8
  placement?: Placement;
9
- inBody: boolean;
9
+ popupContainer?: HTMLElement | null;
10
10
  };
11
- export declare const usePopupPosition: ({ open, setOpen, inBody, popupRef, targetRef, placement }: TPopupPosition) => {
11
+ export declare const usePopupPosition: ({ open, setOpen, popupRef, targetRef, placement, popupContainer, }: TPopupPosition) => {
12
12
  _placement: Placement;
13
13
  popupStyle: CSSProperties;
14
14
  };
package/dist/index.esm.js CHANGED
@@ -1624,19 +1624,43 @@ function clsx(...args) {
1624
1624
  return [];
1625
1625
  }).filter(Boolean).join(' ');
1626
1626
  }
1627
- function getScrollParent(el, includeSelf = false) {
1628
- if (!el) return null;
1627
+ function getElementParentDetails(el, includeSelf = false) {
1628
+ if (!el) {
1629
+ return {
1630
+ relativePosition: {
1631
+ left: 0,
1632
+ top: 0
1633
+ },
1634
+ scrollableParents: null
1635
+ };
1636
+ }
1629
1637
  let current = includeSelf ? el : el.parentElement;
1638
+ const relativePosition = {
1639
+ left: 0,
1640
+ top: 0
1641
+ };
1630
1642
  while (current) {
1631
1643
  const style = getComputedStyle(current);
1632
1644
  const canScroll = ['auto', 'scroll'].includes(style.overflowY) || ['auto', 'scroll'].includes(style.overflowX);
1645
+ if (current.style.position === 'relative') {
1646
+ relativePosition.left += current.offsetLeft;
1647
+ relativePosition.top += current.offsetTop;
1648
+ }
1633
1649
  if (canScroll) {
1634
- current.style.position = 'relative';
1635
- return current;
1650
+ return {
1651
+ relativePosition,
1652
+ scrollableParents: current
1653
+ };
1636
1654
  }
1637
1655
  current = current.parentElement;
1638
1656
  }
1639
- return document.scrollingElement;
1657
+ return {
1658
+ relativePosition: {
1659
+ left: 0,
1660
+ top: 0
1661
+ },
1662
+ scrollableParents: document.scrollingElement
1663
+ };
1640
1664
  }
1641
1665
 
1642
1666
  function flattenChildren(children) {
@@ -2598,100 +2622,135 @@ const OFFSET = 12;
2598
2622
  const usePopupPosition = ({
2599
2623
  open,
2600
2624
  setOpen,
2601
- inBody,
2602
2625
  popupRef,
2603
2626
  targetRef,
2604
- placement
2627
+ placement,
2628
+ popupContainer
2605
2629
  }) => {
2606
2630
  const [_placement, _setPlacement] = useState(placement ?? "bottomLeft");
2607
2631
  const [popupPosition, setPopupPosition] = useState({});
2632
+ const inBody = useMemo(() => popupContainer?.tagName === 'BODY', [popupContainer]);
2608
2633
  const calculatePosition = useCallback(e => {
2609
2634
  const container = targetRef.current?.getBoundingClientRect();
2610
2635
  if (!container) {
2611
2636
  return;
2612
2637
  }
2613
- const scrollableParents = getScrollParent(targetRef.current, true);
2614
- const scrollSameTarget = e?.target === scrollableParents;
2615
- if (!inBody) {
2616
- const hidePopupFromTop = Math.round((targetRef.current?.offsetTop || 0) - (scrollableParents?.scrollTop || 0) + container?.height);
2617
- const hidePopupFromBottom = Math.round((targetRef.current?.offsetTop || 0) - (scrollableParents?.offsetHeight || 0) - (scrollableParents?.scrollTop || 0) + container?.height);
2618
- const spaceAboveFromTop = hidePopupFromTop - Math.round((popupRef.current?.clientHeight || 0) + container?.height + OFFSET);
2619
- const spaceAboveFromBottom = -Math.round((popupRef.current?.clientHeight || 0) + container?.height - OFFSET);
2620
- if (spaceAboveFromBottom <= hidePopupFromBottom) {
2621
- _setPlacement(_placement.replace('bottom', 'top'));
2638
+ const {
2639
+ scrollableParents,
2640
+ relativePosition
2641
+ } = getElementParentDetails(targetRef.current, true);
2642
+ const _containsElement = scrollableParents?.contains(popupContainer) && popupContainer !== scrollableParents;
2643
+ const positions = !popupContainer ? {
2644
+ top: (targetRef.current?.offsetTop || 0) + OFFSET,
2645
+ left: targetRef.current?.offsetLeft || 0
2646
+ } : _containsElement ? {
2647
+ top: (targetRef.current?.clientLeft || 0) + (targetRef.current?.offsetTop || 0) + OFFSET,
2648
+ left: (targetRef.current?.clientLeft || 0) + (targetRef.current?.offsetLeft || 0)
2649
+ } : inBody ? {
2650
+ top: container.top,
2651
+ left: container.left - (targetRef.current?.clientWidth || 0) / 2
2652
+ } : {
2653
+ top: (relativePosition.top || 0) + (targetRef.current?.offsetTop || 0) - (scrollableParents?.offsetTop || 0) + OFFSET,
2654
+ left: relativePosition.left + (targetRef.current?.offsetLeft || 0) - (targetRef.current?.clientWidth || 0) / 2
2655
+ };
2656
+ if (!inBody && popupRef.current) {
2657
+ const popupRect = popupRef.current.getBoundingClientRect();
2658
+ const availableSpace = {
2659
+ top: container.top - (popupRect.height + OFFSET),
2660
+ bottom: (scrollableParents?.clientHeight || 0) - (container.bottom + popupRect.height + OFFSET),
2661
+ left: container.left - (popupRect.width + OFFSET),
2662
+ right: (scrollableParents?.clientWidth || 0) - (container.right + popupRect.width + OFFSET)
2663
+ };
2664
+ let newPlacement = _placement;
2665
+ if (availableSpace.bottom < 0 && availableSpace.top > 0) {
2666
+ newPlacement = newPlacement.replace('bottom', 'top');
2667
+ }
2668
+ if (availableSpace.top < 0 && availableSpace.bottom > 0) {
2669
+ newPlacement = newPlacement.replace('top', 'bottom');
2622
2670
  }
2623
- if (spaceAboveFromTop <= 0) {
2624
- _setPlacement(_placement.replace('top', 'bottom'));
2671
+ if (availableSpace.left < 0 && availableSpace.right > 0) {
2672
+ newPlacement = newPlacement.replace('Right', 'Left');
2625
2673
  }
2674
+ if (availableSpace.right < 0 && availableSpace.left > 0) {
2675
+ newPlacement = newPlacement.replace('Left', 'Right');
2676
+ }
2677
+ _setPlacement(newPlacement);
2626
2678
  }
2627
- if (scrollSameTarget && inBody) {
2679
+ if (e?.target === scrollableParents && inBody) {
2628
2680
  setOpen(false);
2629
2681
  setPopupPosition({});
2630
2682
  return;
2631
2683
  }
2632
2684
  const _calculation = () => {
2633
- const _placementBottom = !_placement.includes('bottom') ? 0 : (inBody ? (targetRef.current?.offsetTop || 0) + (targetRef.current?.clientHeight || 0) - (scrollableParents?.scrollTop || 0) + (scrollableParents?.offsetTop || 0) : (targetRef.current?.offsetTop || 0) + (targetRef.current?.clientHeight || 0)) + OFFSET;
2634
- const _placementTop = !_placement.includes('top') ? 0 : (inBody ? (targetRef.current?.offsetTop || 0) - (popupRef.current?.clientHeight || 0) - (scrollableParents?.scrollTop || 0) + (scrollableParents?.offsetTop || 0) : (targetRef.current?.offsetTop || 0) - (popupRef.current?.clientHeight || 0)) - OFFSET;
2635
- const _positionLeft = inBody ? container.left : targetRef.current?.offsetLeft || 0;
2636
2685
  switch (_placement) {
2637
2686
  case "bottom":
2638
2687
  setPopupPosition({
2639
- top: _placementBottom,
2640
- left: _positionLeft + (container.width || 0) / 2 - (popupRef.current?.offsetWidth || 0) / 2
2688
+ top: positions.top + container.height,
2689
+ left: positions.left + (container.width || 0) / 2 - (popupRef.current?.offsetWidth || 0) / 2
2641
2690
  });
2642
2691
  break;
2643
2692
  case "bottomLeft":
2644
2693
  setPopupPosition({
2645
- top: _placementBottom,
2646
- left: _positionLeft
2694
+ top: positions.top + container.height,
2695
+ left: positions.left
2647
2696
  });
2648
2697
  break;
2649
2698
  case "bottomRight":
2650
2699
  setPopupPosition({
2651
- top: _placementBottom,
2652
- left: _positionLeft + (container.width || 0) - (popupRef.current?.offsetWidth || 0)
2700
+ top: positions.top + container.height,
2701
+ left: positions.left + (container.width || 0) - (popupRef.current?.offsetWidth || 0)
2653
2702
  });
2654
2703
  break;
2655
2704
  case "top":
2656
2705
  setPopupPosition({
2657
- top: _placementTop,
2658
- left: _positionLeft + (container.width || 0) / 2 - (popupRef.current?.offsetWidth || 0) / 2
2706
+ top: positions.top - (popupRef.current?.clientHeight || 0) - OFFSET * 2,
2707
+ left: positions.left + (container.width || 0) / 2 - (popupRef.current?.offsetWidth || 0) / 2
2659
2708
  });
2660
2709
  break;
2661
2710
  case "topLeft":
2662
2711
  setPopupPosition({
2663
- top: _placementTop,
2664
- left: _positionLeft
2712
+ top: positions.top - (popupRef.current?.clientHeight || 0) - OFFSET * 2,
2713
+ left: positions.left
2665
2714
  });
2666
2715
  break;
2667
2716
  case "topRight":
2668
2717
  setPopupPosition({
2669
- top: _placementTop,
2670
- left: _positionLeft + (container.width || 0) - (popupRef.current?.offsetWidth || 0)
2718
+ top: positions.top - (popupRef.current?.clientHeight || 0) - OFFSET * 2,
2719
+ left: positions.left + (container.width || 0) - (popupRef.current?.offsetWidth || 0)
2671
2720
  });
2672
2721
  break;
2673
2722
  }
2674
2723
  };
2675
2724
  _calculation();
2676
- }, [targetRef, popupRef, inBody, _placement, setOpen]);
2725
+ }, [targetRef, popupRef, popupContainer, inBody, _placement, setOpen]);
2677
2726
  useEffect(() => {
2678
2727
  if (!open) {
2679
2728
  return;
2680
2729
  }
2681
- calculatePosition(undefined);
2730
+ const setPositionRelative = position => {
2731
+ scrollableParents.style.position = position;
2732
+ if (popupContainer) {
2733
+ popupContainer.style.position = position;
2734
+ }
2735
+ };
2682
2736
  const controller = new AbortController();
2683
2737
  const options = {
2684
2738
  passive: true,
2685
2739
  signal: controller.signal
2686
2740
  };
2687
- const scrollableParents = getScrollParent(targetRef.current, true);
2741
+ const {
2742
+ scrollableParents
2743
+ } = getElementParentDetails(targetRef.current, true);
2688
2744
  scrollableParents?.addEventListener("scroll", calculatePosition, options);
2745
+ setPositionRelative('relative');
2746
+ calculatePosition();
2689
2747
  document.body.addEventListener("scroll", calculatePosition, options);
2690
2748
  document.body.addEventListener("resize", calculatePosition, options);
2691
2749
  return () => {
2692
2750
  controller.abort();
2751
+ setPositionRelative('unset');
2693
2752
  };
2694
- }, [inBody, open, targetRef, calculatePosition]);
2753
+ }, [open, targetRef, popupContainer, inBody, calculatePosition]);
2695
2754
  return {
2696
2755
  _placement,
2697
2756
  popupStyle: {
@@ -2765,7 +2824,7 @@ const DatePicker = ({
2765
2824
  placement,
2766
2825
  open: isOpen,
2767
2826
  setOpen: setIsOpen,
2768
- inBody: getPopupContainer?.(targetRef.current)?.tagName === 'BODY'
2827
+ popupContainer: getPopupContainer?.(targetRef.current)
2769
2828
  });
2770
2829
  useEffect(() => {
2771
2830
  const _date = value || defaultValue;
@@ -3100,7 +3159,7 @@ const RangePicker = ({
3100
3159
  placement,
3101
3160
  open: isOpen,
3102
3161
  setOpen: setIsOpen,
3103
- inBody: getPopupContainer?.(targetRef.current)?.tagName === 'BODY'
3162
+ popupContainer: getPopupContainer?.(targetRef.current)
3104
3163
  });
3105
3164
  const localeMonths = locale?.shortMonths || Array.from({
3106
3165
  length: 12
@@ -3420,7 +3479,7 @@ const TimePicker = ({
3420
3479
  placement,
3421
3480
  targetRef,
3422
3481
  setOpen: setOpen,
3423
- inBody: getPopupContainer?.(targetRef.current)?.tagName === 'BODY'
3482
+ popupContainer: getPopupContainer?.(targetRef.current)
3424
3483
  });
3425
3484
  useEffect(() => {
3426
3485
  setInnerValue(propValue || defaultValue ? new Date(propValue || defaultValue) : null);
@@ -5398,7 +5457,7 @@ const Dropdown = ({
5398
5457
  popupRef,
5399
5458
  placement,
5400
5459
  setOpen,
5401
- inBody: getPopupContainer?.(targetRef.current)?.tagName === 'BODY'
5460
+ popupContainer: getPopupContainer?.(targetRef.current)
5402
5461
  });
5403
5462
  useEffect(() => {
5404
5463
  if (isControlled) {
@@ -5534,7 +5593,7 @@ var Dropdown$1 = /*#__PURE__*/Object.freeze({
5534
5593
  default: Dropdown
5535
5594
  });
5536
5595
 
5537
- var css_248z$1 = ".xUi-popover-wrapper-content{cursor:pointer;max-width:fit-content;width:-webkit-fill-available}.xUi-popover{background:var(--xui-background-color);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.15);padding:8px 12px;width:max-content;z-index:1000}.xUi-popover-title{padding:4px}.xUi-popover-inner{color:var(--xui-text-color);font-size:14px}";
5596
+ var css_248z$1 = ".xUi-popover-wrapper-content{cursor:pointer;max-height:fit-content;max-width:fit-content;width:-webkit-fill-available}.xUi-popover{background:var(--xui-background-color);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.15);padding:8px 12px;width:max-content;z-index:1000}.xUi-popover-title{padding:4px}.xUi-popover-inner{color:var(--xui-text-color);font-size:14px}";
5538
5597
  styleInject(css_248z$1);
5539
5598
 
5540
5599
  const Popover = ({
@@ -5567,7 +5626,7 @@ const Popover = ({
5567
5626
  placement,
5568
5627
  open: isOpen,
5569
5628
  setOpen: setInnerOpen,
5570
- inBody: getPopupContainer?.(targetRef.current)?.tagName === 'BODY'
5629
+ popupContainer: getPopupContainer?.(targetRef.current)
5571
5630
  });
5572
5631
  useEffect(() => {
5573
5632
  const handleClickOutside = e => {