@grandbazar/ui-baza 1.2.8 → 1.2.10

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.cjs CHANGED
@@ -1684,7 +1684,7 @@ function DropdownMenuProvider({ children }) {
1684
1684
  portalPlacement,
1685
1685
  setPortalPlacement
1686
1686
  },
1687
- children: typeof children === "function" ? children({ isOpen, setIsOpen, portalPlacement }) : children
1687
+ children: typeof children === "function" ? children({ isOpen, setIsOpen, portalPlacement, triggerRef }) : children
1688
1688
  }
1689
1689
  );
1690
1690
  }
@@ -1810,38 +1810,6 @@ function handleDropdownMouseLeave(event, { ignoreRelatedTargetRef, setIsOpen })
1810
1810
  setIsOpen(false);
1811
1811
  }
1812
1812
 
1813
- function usePortalHandlersByEventTrigger() {
1814
- const { triggerRef, setIsOpen } = useDropdownMenuContext();
1815
- const handlePortalBlur = React.useCallback(
1816
- (event) => {
1817
- const relatedTarget = event.relatedTarget;
1818
- if (!(relatedTarget instanceof Node)) {
1819
- setIsOpen(false);
1820
- return;
1821
- }
1822
- if (event.currentTarget.contains(relatedTarget) || triggerRef.current?.contains(relatedTarget)) {
1823
- return;
1824
- }
1825
- setIsOpen(false);
1826
- },
1827
- [setIsOpen, triggerRef]
1828
- );
1829
- const portalHandlersByEvent = React.useMemo(
1830
- () => ({
1831
- click: {},
1832
- hover: {
1833
- onMouseLeave: (event) => handleDropdownMouseLeave(event, {
1834
- ignoreRelatedTargetRef: triggerRef,
1835
- setIsOpen
1836
- }),
1837
- onBlur: handlePortalBlur
1838
- }
1839
- }),
1840
- [handlePortalBlur, setIsOpen, triggerRef]
1841
- );
1842
- return portalHandlersByEvent;
1843
- }
1844
-
1845
1813
  const getAdjustedAlign = ({
1846
1814
  align,
1847
1815
  translateAxis,
@@ -1934,42 +1902,131 @@ function getAdjustedPlacement({
1934
1902
  return { position: adjustedPosition, align: adjustedAlign };
1935
1903
  }
1936
1904
 
1937
- function usePortalPosition({ align, position, offset, portalWidth, portalHeight }) {
1905
+ function syncPortalPosition({
1906
+ align,
1907
+ position,
1908
+ offset,
1909
+ portalWidth,
1910
+ portalHeight,
1911
+ triggerRect,
1912
+ setPortalPlacement,
1913
+ setPortalPosition,
1914
+ scrollContainer
1915
+ }) {
1916
+ const isWindowScrollContainer = !scrollContainer;
1917
+ const scrollCoords = {
1918
+ x: isWindowScrollContainer ? window.scrollX : scrollContainer.scrollLeft,
1919
+ y: isWindowScrollContainer ? window.scrollY : scrollContainer.scrollTop
1920
+ };
1921
+ const viewportPosition = {
1922
+ left: scrollCoords.x,
1923
+ right: scrollCoords.x + (isWindowScrollContainer ? window.innerWidth : scrollContainer.clientWidth),
1924
+ top: scrollCoords.y,
1925
+ bottom: scrollCoords.y + (isWindowScrollContainer ? window.innerHeight : scrollContainer.clientHeight)
1926
+ };
1927
+ const { position: adjustedPosition, align: adjustedAlign } = getAdjustedPlacement({
1928
+ align,
1929
+ position,
1930
+ viewportPosition,
1931
+ portalWidth,
1932
+ portalHeight,
1933
+ scrollCoords,
1934
+ triggerRect
1935
+ });
1936
+ setPortalPlacement({ position: adjustedPosition, align: adjustedAlign });
1937
+ const newPortalPosition = getPortalPosition({
1938
+ align: adjustedAlign,
1939
+ position: adjustedPosition,
1940
+ offset,
1941
+ triggerRect,
1942
+ scrollCoords
1943
+ });
1944
+ setPortalPosition(newPortalPosition);
1945
+ }
1946
+
1947
+ function usePortalHandlersByEventTrigger() {
1948
+ const { triggerRef, setIsOpen } = useDropdownMenuContext();
1949
+ const handlePortalBlur = React.useCallback(
1950
+ (event) => {
1951
+ const relatedTarget = event.relatedTarget;
1952
+ if (!(relatedTarget instanceof Node)) {
1953
+ setIsOpen(false);
1954
+ return;
1955
+ }
1956
+ if (event.currentTarget.contains(relatedTarget) || triggerRef.current?.contains(relatedTarget)) {
1957
+ return;
1958
+ }
1959
+ setIsOpen(false);
1960
+ },
1961
+ [setIsOpen, triggerRef]
1962
+ );
1963
+ const portalHandlersByEvent = React.useMemo(
1964
+ () => ({
1965
+ click: {},
1966
+ hover: {
1967
+ onMouseLeave: (event) => handleDropdownMouseLeave(event, {
1968
+ ignoreRelatedTargetRef: triggerRef,
1969
+ setIsOpen
1970
+ }),
1971
+ onBlur: handlePortalBlur
1972
+ }
1973
+ }),
1974
+ [handlePortalBlur, setIsOpen, triggerRef]
1975
+ );
1976
+ return portalHandlersByEvent;
1977
+ }
1978
+
1979
+ function usePortalPosition({
1980
+ align,
1981
+ position,
1982
+ offset,
1983
+ portalWidth,
1984
+ portalHeight,
1985
+ scrollContainerRef
1986
+ }) {
1938
1987
  const { isOpen, triggerRef, setPortalPlacement } = useDropdownMenuContext();
1939
1988
  const [portalPosition, setPortalPosition] = React.useState();
1940
1989
  React.useEffect(() => {
1941
- if (isOpen && triggerRef.current) {
1942
- const triggerRect = triggerRef.current.getBoundingClientRect();
1943
- const scrollCoords = {
1944
- x: window.scrollX,
1945
- y: window.scrollY
1946
- };
1947
- const viewportPosition = {
1948
- left: scrollCoords.x,
1949
- right: scrollCoords.x + window.innerWidth,
1950
- top: scrollCoords.y,
1951
- bottom: scrollCoords.y + window.innerHeight
1990
+ if (!isOpen || !triggerRef.current) {
1991
+ return;
1992
+ }
1993
+ const triggerRect = triggerRef.current.getBoundingClientRect();
1994
+ const scrollContainer = scrollContainerRef?.current;
1995
+ if (scrollContainer) {
1996
+ const containerRect = scrollContainer.getBoundingClientRect();
1997
+ const normalizedTriggerRect = {
1998
+ ...triggerRect,
1999
+ x: triggerRect.x - containerRect.left - scrollContainer.clientLeft,
2000
+ y: triggerRect.y - containerRect.top - scrollContainer.clientTop,
2001
+ top: triggerRect.top - containerRect.top - scrollContainer.clientTop,
2002
+ right: triggerRect.right - containerRect.left - scrollContainer.clientLeft,
2003
+ bottom: triggerRect.bottom - containerRect.top - scrollContainer.clientTop,
2004
+ left: triggerRect.left - containerRect.left - scrollContainer.clientLeft
1952
2005
  };
1953
- const { position: adjustedPosition, align: adjustedAlign } = getAdjustedPlacement({
2006
+ syncPortalPosition({
1954
2007
  align,
1955
2008
  position,
1956
- viewportPosition,
2009
+ offset,
1957
2010
  portalWidth,
1958
2011
  portalHeight,
1959
- scrollCoords,
1960
- triggerRect
1961
- });
1962
- setPortalPlacement({ position: adjustedPosition, align: adjustedAlign });
1963
- const newPortalPosition = getPortalPosition({
1964
- align: adjustedAlign,
1965
- position: adjustedPosition,
1966
- offset,
1967
- triggerRect,
1968
- scrollCoords
2012
+ triggerRect: normalizedTriggerRect,
2013
+ setPortalPlacement,
2014
+ setPortalPosition,
2015
+ scrollContainer
1969
2016
  });
1970
- setPortalPosition(newPortalPosition);
2017
+ return;
1971
2018
  }
1972
- }, [align, isOpen, offset, portalHeight, portalWidth, position, setPortalPlacement, triggerRef]);
2019
+ syncPortalPosition({
2020
+ align,
2021
+ position,
2022
+ offset,
2023
+ portalWidth,
2024
+ portalHeight,
2025
+ triggerRect,
2026
+ setPortalPlacement,
2027
+ setPortalPosition
2028
+ });
2029
+ }, [align, isOpen, offset, portalHeight, portalWidth, position, scrollContainerRef, setPortalPlacement, triggerRef]);
1973
2030
  return portalPosition;
1974
2031
  }
1975
2032
 
@@ -2011,12 +2068,14 @@ const styles$g = {
2011
2068
  function DropdownPortal({
2012
2069
  children,
2013
2070
  className,
2071
+ style,
2014
2072
  align = "start",
2015
2073
  position = "bottom",
2016
2074
  isNested,
2017
2075
  offset = DROPDOWN_PORTAL_DEFAULT_OFFSET,
2018
2076
  maxWidth,
2019
- maxHeight
2077
+ maxHeight,
2078
+ scrollContainerRef
2020
2079
  }) {
2021
2080
  const { portalRef, triggerEvent, isOpen } = useDropdownMenuContext();
2022
2081
  const handlersByTrigger = usePortalHandlersByEventTrigger();
@@ -2025,7 +2084,8 @@ function DropdownPortal({
2025
2084
  position,
2026
2085
  offset,
2027
2086
  ...maxWidth && { portalWidth: maxWidth + offset },
2028
- ...maxHeight && { portalHeight: maxHeight + offset }
2087
+ ...maxHeight && { portalHeight: maxHeight + offset },
2088
+ scrollContainerRef
2029
2089
  });
2030
2090
  if (!isOpen || !portalPosition) {
2031
2091
  return null;
@@ -2037,7 +2097,8 @@ function DropdownPortal({
2037
2097
  style: {
2038
2098
  ...portalPosition,
2039
2099
  ...maxWidth && { "--dropdown-portal-max-width": `${maxWidth + offset}px` },
2040
- ...maxHeight && { "--dropdown-portal-max-height": `${maxHeight + offset}px` }
2100
+ ...maxHeight && { "--dropdown-portal-max-height": `${maxHeight + offset}px` },
2101
+ ...style
2041
2102
  },
2042
2103
  ref: portalRef,
2043
2104
  className: classNames(styles$g.dropdownPortal, className),
@@ -2046,7 +2107,7 @@ function DropdownPortal({
2046
2107
  children
2047
2108
  }
2048
2109
  ),
2049
- document.body
2110
+ scrollContainerRef?.current ?? document.body
2050
2111
  );
2051
2112
  }
2052
2113
 
@@ -2725,8 +2786,15 @@ function Tag({ children, className, size = "md", mode = "primary", disabled, ...
2725
2786
  );
2726
2787
  }
2727
2788
 
2728
- const tooltipContent = "_tooltipContent_1267q_2";
2729
- const tooltipTitle = "_tooltipTitle_1267q_96";
2789
+ const TOOLTIP_CONTENT_ARROW = {
2790
+ width: 16,
2791
+ height: 8,
2792
+ offsetInline: 12,
2793
+ offsetBlock: 10
2794
+ };
2795
+
2796
+ const tooltipContent = "_tooltipContent_ww0bo_2";
2797
+ const tooltipTitle = "_tooltipTitle_ww0bo_92";
2730
2798
  const styles = {
2731
2799
  tooltipContent: tooltipContent,
2732
2800
  tooltipTitle: tooltipTitle
@@ -2739,7 +2807,6 @@ function TooltipContent({
2739
2807
  description,
2740
2808
  arrowAlign,
2741
2809
  arrowPosition,
2742
- arrowOffset,
2743
2810
  ...props
2744
2811
  }) {
2745
2812
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -2749,11 +2816,11 @@ function TooltipContent({
2749
2816
  role: role ?? "tooltip",
2750
2817
  "data-align": arrowAlign,
2751
2818
  "data-position": arrowPosition,
2752
- ...arrowOffset && {
2753
- style: {
2754
- "--tooltip-content-arrow-offset-inline": `${arrowOffset.inline}px`,
2755
- "--tooltip-content-arrow-offset-block": `${arrowOffset.block}px`
2756
- }
2819
+ style: {
2820
+ "--tooltip-content-arrow-width": `${TOOLTIP_CONTENT_ARROW.width}px`,
2821
+ "--tooltip-content-arrow-height": `${TOOLTIP_CONTENT_ARROW.height}px`,
2822
+ "--tooltip-content-arrow-offset-inline": `${TOOLTIP_CONTENT_ARROW.offsetInline}px`,
2823
+ "--tooltip-content-arrow-offset-block": `${TOOLTIP_CONTENT_ARROW.offsetBlock}px`
2757
2824
  },
2758
2825
  ...props,
2759
2826
  children: [
@@ -2764,7 +2831,24 @@ function TooltipContent({
2764
2831
  );
2765
2832
  }
2766
2833
 
2767
- const TOOLTIP_OFFSET = 8;
2834
+ function getCenteredPortalShiftStyle({
2835
+ portalPlacement,
2836
+ triggerRef
2837
+ }) {
2838
+ const triggerRect = triggerRef.current?.getBoundingClientRect();
2839
+ if (!triggerRect || !portalPlacement || portalPlacement.align === "center") {
2840
+ return {};
2841
+ }
2842
+ const isHorizontal = portalPlacement.position === "top" || portalPlacement.position === "bottom";
2843
+ const triggerHalfSize = isHorizontal ? triggerRect.width / 2 : triggerRect.height / 2;
2844
+ const arrowOffset = (isHorizontal ? TOOLTIP_CONTENT_ARROW.offsetInline : TOOLTIP_CONTENT_ARROW.offsetBlock) + TOOLTIP_CONTENT_ARROW.height * Math.SQRT2 / 2;
2845
+ const shift = portalPlacement.align === "start" ? triggerHalfSize - arrowOffset : arrowOffset - triggerHalfSize;
2846
+ const shiftPx = `${Number(shift.toFixed(3))}px`;
2847
+ if (isHorizontal) {
2848
+ return { marginLeft: shiftPx };
2849
+ }
2850
+ return { marginTop: shiftPx };
2851
+ }
2768
2852
 
2769
2853
  function TooltipRoot({
2770
2854
  children,
@@ -2774,18 +2858,24 @@ function TooltipRoot({
2774
2858
  maxWidth,
2775
2859
  maxHeight,
2776
2860
  withoutArrow = false,
2861
+ scrollContainerRef,
2862
+ centerArrowToTrigger = true,
2777
2863
  ...tooltipContentProps
2778
2864
  }) {
2779
- return /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu.Root, { children: ({ portalPlacement }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2865
+ return /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu.Root, { children: ({ portalPlacement, triggerRef }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2780
2866
  /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu.Trigger, { asChild: true, triggerEvent, children }),
2781
2867
  /* @__PURE__ */ jsxRuntime.jsx(
2782
2868
  DropdownMenu.Portal,
2783
2869
  {
2784
2870
  align,
2785
2871
  position,
2786
- offset: TOOLTIP_OFFSET,
2872
+ offset: TOOLTIP_CONTENT_ARROW.height,
2787
2873
  maxWidth,
2788
2874
  maxHeight,
2875
+ scrollContainerRef,
2876
+ style: {
2877
+ ...!withoutArrow && centerArrowToTrigger && getCenteredPortalShiftStyle({ portalPlacement, triggerRef })
2878
+ },
2789
2879
  children: /* @__PURE__ */ jsxRuntime.jsx(
2790
2880
  TooltipContent,
2791
2881
  {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ComponentProps } from 'react';
2
+ import { CSSProperties } from 'react';
2
3
  import { default as default_2 } from 'react';
3
4
  import { Dispatch } from 'react';
4
5
  import { IconGoogle } from './logos';
@@ -190,7 +191,7 @@ export declare namespace DropdownMenu {
190
191
  var Portal: typeof DropdownPortal;
191
192
  }
192
193
 
193
- declare function DropdownPortal({ children, className, align, position, isNested, offset, maxWidth, maxHeight, }: TDropdownPortalProps): ReactPortal | null;
194
+ declare function DropdownPortal({ children, className, style, align, position, isNested, offset, maxWidth, maxHeight, scrollContainerRef, }: TDropdownPortalProps): ReactPortal | null;
194
195
 
195
196
  declare function DropdownRoot({ children }: TDropdownRootProps): JSX.Element;
196
197
 
@@ -664,16 +665,18 @@ declare type TDropdownMenuContextValue = {
664
665
  declare type TDropdownPortalProps = {
665
666
  children: React.ReactNode;
666
667
  className?: string;
668
+ style?: CSSProperties;
667
669
  align?: TArrayElement<typeof DROPDOWN_PORTAL_ALIGN_LIST>;
668
670
  position?: TArrayElement<typeof DROPDOWN_PORTAL_POSITION_LIST>;
669
671
  isNested?: boolean;
670
672
  offset?: number;
671
673
  maxWidth?: number;
672
674
  maxHeight?: number;
675
+ scrollContainerRef?: React.RefObject<HTMLElement | null>;
673
676
  };
674
677
 
675
678
  declare type TDropdownRootProps = {
676
- children: React.ReactNode | ((context: Pick<TDropdownMenuContextValue, 'isOpen' | 'setIsOpen' | 'portalPlacement'>) => React.ReactNode);
679
+ children: React.ReactNode | ((context: Pick<TDropdownMenuContextValue, 'isOpen' | 'setIsOpen' | 'portalPlacement' | 'triggerRef'>) => React.ReactNode);
677
680
  };
678
681
 
679
682
  declare type TDropdownTriggerProps = TAsChildProps<React.HTMLAttributes<HTMLButtonElement>> & {
@@ -726,7 +729,8 @@ declare type TLocale = TArrayElement<typeof LOCALES>;
726
729
  * @param triggerEvent - Trigger behavior (hover, click)
727
730
  * @param maxWidth - Max width of the tooltip content in pixels (required for horizontal flip)
728
731
  * @param maxHeight - Max height of the tooltip content in pixels (required for vertical flip)
729
- * @param arrowOffset - Arrow offset in pixels for inline and block axes
732
+ * @param scrollContainerRef - Optional scroll container used as portal mount node and positioning boundary
733
+ * @param centerArrowToTrigger - Automatically shifts portal to keep arrow at trigger center for start/end align
730
734
  * @param withoutArrow - Hide tooltip arrow
731
735
  *
732
736
  * @example
@@ -740,9 +744,9 @@ export declare namespace Tooltip {
740
744
  var Content: typeof TooltipContent;
741
745
  }
742
746
 
743
- declare function TooltipContent({ className, role, title, description, arrowAlign, arrowPosition, arrowOffset, ...props }: TTooltipContentProps): JSX.Element;
747
+ declare function TooltipContent({ className, role, title, description, arrowAlign, arrowPosition, ...props }: TTooltipContentProps): JSX.Element;
744
748
 
745
- declare function TooltipRoot({ children, align, position, triggerEvent, maxWidth, maxHeight, withoutArrow, ...tooltipContentProps }: TTooltipRootProps): JSX.Element;
749
+ declare function TooltipRoot({ children, align, position, triggerEvent, maxWidth, maxHeight, withoutArrow, scrollContainerRef, centerArrowToTrigger, ...tooltipContentProps }: TTooltipRootProps): JSX.Element;
746
750
 
747
751
  declare type TPaginationItemProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
748
752
  size?: TArrayElement<typeof PAGINATION_SIZES>;
@@ -868,20 +872,12 @@ declare type TTooltipContentProps = Omit<React.HTMLAttributes<HTMLDivElement>, '
868
872
  description?: string;
869
873
  arrowAlign?: TArrayElement<typeof DROPDOWN_PORTAL_ALIGN_LIST>;
870
874
  arrowPosition?: TArrayElement<typeof DROPDOWN_PORTAL_POSITION_LIST>;
871
- arrowOffset?: {
872
- inline: number;
873
- block: number;
874
- };
875
875
  };
876
876
 
877
- declare type TTooltipRootProps = Omit<React.ComponentProps<typeof TooltipContent>, 'arrowAlign' | 'arrowPosition'> & {
878
- children: React.ReactNode;
877
+ declare type TTooltipRootProps = Omit<React.ComponentProps<typeof TooltipContent>, 'arrowAlign' | 'arrowPosition'> & Pick<React.ComponentProps<typeof DropdownMenu.Portal>, 'align' | 'position' | 'maxWidth' | 'maxHeight' | 'scrollContainerRef' | 'children'> & {
879
878
  triggerEvent?: TArrayElement<typeof DROPDOWN_TRIGGER_EVENT_LIST>;
880
- align?: TArrayElement<typeof DROPDOWN_PORTAL_ALIGN_LIST>;
881
- position?: TArrayElement<typeof DROPDOWN_PORTAL_POSITION_LIST>;
882
- maxWidth?: number;
883
- maxHeight?: number;
884
879
  withoutArrow?: boolean;
880
+ centerArrowToTrigger?: boolean;
885
881
  };
886
882
 
887
883
  declare type TWithRef<TProps, TElement = HTMLElement> = TProps & {
package/dist/index.js CHANGED
@@ -1680,7 +1680,7 @@ function DropdownMenuProvider({ children }) {
1680
1680
  portalPlacement,
1681
1681
  setPortalPlacement
1682
1682
  },
1683
- children: typeof children === "function" ? children({ isOpen, setIsOpen, portalPlacement }) : children
1683
+ children: typeof children === "function" ? children({ isOpen, setIsOpen, portalPlacement, triggerRef }) : children
1684
1684
  }
1685
1685
  );
1686
1686
  }
@@ -1806,38 +1806,6 @@ function handleDropdownMouseLeave(event, { ignoreRelatedTargetRef, setIsOpen })
1806
1806
  setIsOpen(false);
1807
1807
  }
1808
1808
 
1809
- function usePortalHandlersByEventTrigger() {
1810
- const { triggerRef, setIsOpen } = useDropdownMenuContext();
1811
- const handlePortalBlur = useCallback(
1812
- (event) => {
1813
- const relatedTarget = event.relatedTarget;
1814
- if (!(relatedTarget instanceof Node)) {
1815
- setIsOpen(false);
1816
- return;
1817
- }
1818
- if (event.currentTarget.contains(relatedTarget) || triggerRef.current?.contains(relatedTarget)) {
1819
- return;
1820
- }
1821
- setIsOpen(false);
1822
- },
1823
- [setIsOpen, triggerRef]
1824
- );
1825
- const portalHandlersByEvent = useMemo(
1826
- () => ({
1827
- click: {},
1828
- hover: {
1829
- onMouseLeave: (event) => handleDropdownMouseLeave(event, {
1830
- ignoreRelatedTargetRef: triggerRef,
1831
- setIsOpen
1832
- }),
1833
- onBlur: handlePortalBlur
1834
- }
1835
- }),
1836
- [handlePortalBlur, setIsOpen, triggerRef]
1837
- );
1838
- return portalHandlersByEvent;
1839
- }
1840
-
1841
1809
  const getAdjustedAlign = ({
1842
1810
  align,
1843
1811
  translateAxis,
@@ -1930,42 +1898,131 @@ function getAdjustedPlacement({
1930
1898
  return { position: adjustedPosition, align: adjustedAlign };
1931
1899
  }
1932
1900
 
1933
- function usePortalPosition({ align, position, offset, portalWidth, portalHeight }) {
1901
+ function syncPortalPosition({
1902
+ align,
1903
+ position,
1904
+ offset,
1905
+ portalWidth,
1906
+ portalHeight,
1907
+ triggerRect,
1908
+ setPortalPlacement,
1909
+ setPortalPosition,
1910
+ scrollContainer
1911
+ }) {
1912
+ const isWindowScrollContainer = !scrollContainer;
1913
+ const scrollCoords = {
1914
+ x: isWindowScrollContainer ? window.scrollX : scrollContainer.scrollLeft,
1915
+ y: isWindowScrollContainer ? window.scrollY : scrollContainer.scrollTop
1916
+ };
1917
+ const viewportPosition = {
1918
+ left: scrollCoords.x,
1919
+ right: scrollCoords.x + (isWindowScrollContainer ? window.innerWidth : scrollContainer.clientWidth),
1920
+ top: scrollCoords.y,
1921
+ bottom: scrollCoords.y + (isWindowScrollContainer ? window.innerHeight : scrollContainer.clientHeight)
1922
+ };
1923
+ const { position: adjustedPosition, align: adjustedAlign } = getAdjustedPlacement({
1924
+ align,
1925
+ position,
1926
+ viewportPosition,
1927
+ portalWidth,
1928
+ portalHeight,
1929
+ scrollCoords,
1930
+ triggerRect
1931
+ });
1932
+ setPortalPlacement({ position: adjustedPosition, align: adjustedAlign });
1933
+ const newPortalPosition = getPortalPosition({
1934
+ align: adjustedAlign,
1935
+ position: adjustedPosition,
1936
+ offset,
1937
+ triggerRect,
1938
+ scrollCoords
1939
+ });
1940
+ setPortalPosition(newPortalPosition);
1941
+ }
1942
+
1943
+ function usePortalHandlersByEventTrigger() {
1944
+ const { triggerRef, setIsOpen } = useDropdownMenuContext();
1945
+ const handlePortalBlur = useCallback(
1946
+ (event) => {
1947
+ const relatedTarget = event.relatedTarget;
1948
+ if (!(relatedTarget instanceof Node)) {
1949
+ setIsOpen(false);
1950
+ return;
1951
+ }
1952
+ if (event.currentTarget.contains(relatedTarget) || triggerRef.current?.contains(relatedTarget)) {
1953
+ return;
1954
+ }
1955
+ setIsOpen(false);
1956
+ },
1957
+ [setIsOpen, triggerRef]
1958
+ );
1959
+ const portalHandlersByEvent = useMemo(
1960
+ () => ({
1961
+ click: {},
1962
+ hover: {
1963
+ onMouseLeave: (event) => handleDropdownMouseLeave(event, {
1964
+ ignoreRelatedTargetRef: triggerRef,
1965
+ setIsOpen
1966
+ }),
1967
+ onBlur: handlePortalBlur
1968
+ }
1969
+ }),
1970
+ [handlePortalBlur, setIsOpen, triggerRef]
1971
+ );
1972
+ return portalHandlersByEvent;
1973
+ }
1974
+
1975
+ function usePortalPosition({
1976
+ align,
1977
+ position,
1978
+ offset,
1979
+ portalWidth,
1980
+ portalHeight,
1981
+ scrollContainerRef
1982
+ }) {
1934
1983
  const { isOpen, triggerRef, setPortalPlacement } = useDropdownMenuContext();
1935
1984
  const [portalPosition, setPortalPosition] = useState();
1936
1985
  useEffect(() => {
1937
- if (isOpen && triggerRef.current) {
1938
- const triggerRect = triggerRef.current.getBoundingClientRect();
1939
- const scrollCoords = {
1940
- x: window.scrollX,
1941
- y: window.scrollY
1942
- };
1943
- const viewportPosition = {
1944
- left: scrollCoords.x,
1945
- right: scrollCoords.x + window.innerWidth,
1946
- top: scrollCoords.y,
1947
- bottom: scrollCoords.y + window.innerHeight
1986
+ if (!isOpen || !triggerRef.current) {
1987
+ return;
1988
+ }
1989
+ const triggerRect = triggerRef.current.getBoundingClientRect();
1990
+ const scrollContainer = scrollContainerRef?.current;
1991
+ if (scrollContainer) {
1992
+ const containerRect = scrollContainer.getBoundingClientRect();
1993
+ const normalizedTriggerRect = {
1994
+ ...triggerRect,
1995
+ x: triggerRect.x - containerRect.left - scrollContainer.clientLeft,
1996
+ y: triggerRect.y - containerRect.top - scrollContainer.clientTop,
1997
+ top: triggerRect.top - containerRect.top - scrollContainer.clientTop,
1998
+ right: triggerRect.right - containerRect.left - scrollContainer.clientLeft,
1999
+ bottom: triggerRect.bottom - containerRect.top - scrollContainer.clientTop,
2000
+ left: triggerRect.left - containerRect.left - scrollContainer.clientLeft
1948
2001
  };
1949
- const { position: adjustedPosition, align: adjustedAlign } = getAdjustedPlacement({
2002
+ syncPortalPosition({
1950
2003
  align,
1951
2004
  position,
1952
- viewportPosition,
2005
+ offset,
1953
2006
  portalWidth,
1954
2007
  portalHeight,
1955
- scrollCoords,
1956
- triggerRect
1957
- });
1958
- setPortalPlacement({ position: adjustedPosition, align: adjustedAlign });
1959
- const newPortalPosition = getPortalPosition({
1960
- align: adjustedAlign,
1961
- position: adjustedPosition,
1962
- offset,
1963
- triggerRect,
1964
- scrollCoords
2008
+ triggerRect: normalizedTriggerRect,
2009
+ setPortalPlacement,
2010
+ setPortalPosition,
2011
+ scrollContainer
1965
2012
  });
1966
- setPortalPosition(newPortalPosition);
2013
+ return;
1967
2014
  }
1968
- }, [align, isOpen, offset, portalHeight, portalWidth, position, setPortalPlacement, triggerRef]);
2015
+ syncPortalPosition({
2016
+ align,
2017
+ position,
2018
+ offset,
2019
+ portalWidth,
2020
+ portalHeight,
2021
+ triggerRect,
2022
+ setPortalPlacement,
2023
+ setPortalPosition
2024
+ });
2025
+ }, [align, isOpen, offset, portalHeight, portalWidth, position, scrollContainerRef, setPortalPlacement, triggerRef]);
1969
2026
  return portalPosition;
1970
2027
  }
1971
2028
 
@@ -2007,12 +2064,14 @@ const styles$g = {
2007
2064
  function DropdownPortal({
2008
2065
  children,
2009
2066
  className,
2067
+ style,
2010
2068
  align = "start",
2011
2069
  position = "bottom",
2012
2070
  isNested,
2013
2071
  offset = DROPDOWN_PORTAL_DEFAULT_OFFSET,
2014
2072
  maxWidth,
2015
- maxHeight
2073
+ maxHeight,
2074
+ scrollContainerRef
2016
2075
  }) {
2017
2076
  const { portalRef, triggerEvent, isOpen } = useDropdownMenuContext();
2018
2077
  const handlersByTrigger = usePortalHandlersByEventTrigger();
@@ -2021,7 +2080,8 @@ function DropdownPortal({
2021
2080
  position,
2022
2081
  offset,
2023
2082
  ...maxWidth && { portalWidth: maxWidth + offset },
2024
- ...maxHeight && { portalHeight: maxHeight + offset }
2083
+ ...maxHeight && { portalHeight: maxHeight + offset },
2084
+ scrollContainerRef
2025
2085
  });
2026
2086
  if (!isOpen || !portalPosition) {
2027
2087
  return null;
@@ -2033,7 +2093,8 @@ function DropdownPortal({
2033
2093
  style: {
2034
2094
  ...portalPosition,
2035
2095
  ...maxWidth && { "--dropdown-portal-max-width": `${maxWidth + offset}px` },
2036
- ...maxHeight && { "--dropdown-portal-max-height": `${maxHeight + offset}px` }
2096
+ ...maxHeight && { "--dropdown-portal-max-height": `${maxHeight + offset}px` },
2097
+ ...style
2037
2098
  },
2038
2099
  ref: portalRef,
2039
2100
  className: classNames(styles$g.dropdownPortal, className),
@@ -2042,7 +2103,7 @@ function DropdownPortal({
2042
2103
  children
2043
2104
  }
2044
2105
  ),
2045
- document.body
2106
+ scrollContainerRef?.current ?? document.body
2046
2107
  );
2047
2108
  }
2048
2109
 
@@ -2721,8 +2782,15 @@ function Tag({ children, className, size = "md", mode = "primary", disabled, ...
2721
2782
  );
2722
2783
  }
2723
2784
 
2724
- const tooltipContent = "_tooltipContent_1267q_2";
2725
- const tooltipTitle = "_tooltipTitle_1267q_96";
2785
+ const TOOLTIP_CONTENT_ARROW = {
2786
+ width: 16,
2787
+ height: 8,
2788
+ offsetInline: 12,
2789
+ offsetBlock: 10
2790
+ };
2791
+
2792
+ const tooltipContent = "_tooltipContent_ww0bo_2";
2793
+ const tooltipTitle = "_tooltipTitle_ww0bo_92";
2726
2794
  const styles = {
2727
2795
  tooltipContent: tooltipContent,
2728
2796
  tooltipTitle: tooltipTitle
@@ -2735,7 +2803,6 @@ function TooltipContent({
2735
2803
  description,
2736
2804
  arrowAlign,
2737
2805
  arrowPosition,
2738
- arrowOffset,
2739
2806
  ...props
2740
2807
  }) {
2741
2808
  return /* @__PURE__ */ jsxs(
@@ -2745,11 +2812,11 @@ function TooltipContent({
2745
2812
  role: role ?? "tooltip",
2746
2813
  "data-align": arrowAlign,
2747
2814
  "data-position": arrowPosition,
2748
- ...arrowOffset && {
2749
- style: {
2750
- "--tooltip-content-arrow-offset-inline": `${arrowOffset.inline}px`,
2751
- "--tooltip-content-arrow-offset-block": `${arrowOffset.block}px`
2752
- }
2815
+ style: {
2816
+ "--tooltip-content-arrow-width": `${TOOLTIP_CONTENT_ARROW.width}px`,
2817
+ "--tooltip-content-arrow-height": `${TOOLTIP_CONTENT_ARROW.height}px`,
2818
+ "--tooltip-content-arrow-offset-inline": `${TOOLTIP_CONTENT_ARROW.offsetInline}px`,
2819
+ "--tooltip-content-arrow-offset-block": `${TOOLTIP_CONTENT_ARROW.offsetBlock}px`
2753
2820
  },
2754
2821
  ...props,
2755
2822
  children: [
@@ -2760,7 +2827,24 @@ function TooltipContent({
2760
2827
  );
2761
2828
  }
2762
2829
 
2763
- const TOOLTIP_OFFSET = 8;
2830
+ function getCenteredPortalShiftStyle({
2831
+ portalPlacement,
2832
+ triggerRef
2833
+ }) {
2834
+ const triggerRect = triggerRef.current?.getBoundingClientRect();
2835
+ if (!triggerRect || !portalPlacement || portalPlacement.align === "center") {
2836
+ return {};
2837
+ }
2838
+ const isHorizontal = portalPlacement.position === "top" || portalPlacement.position === "bottom";
2839
+ const triggerHalfSize = isHorizontal ? triggerRect.width / 2 : triggerRect.height / 2;
2840
+ const arrowOffset = (isHorizontal ? TOOLTIP_CONTENT_ARROW.offsetInline : TOOLTIP_CONTENT_ARROW.offsetBlock) + TOOLTIP_CONTENT_ARROW.height * Math.SQRT2 / 2;
2841
+ const shift = portalPlacement.align === "start" ? triggerHalfSize - arrowOffset : arrowOffset - triggerHalfSize;
2842
+ const shiftPx = `${Number(shift.toFixed(3))}px`;
2843
+ if (isHorizontal) {
2844
+ return { marginLeft: shiftPx };
2845
+ }
2846
+ return { marginTop: shiftPx };
2847
+ }
2764
2848
 
2765
2849
  function TooltipRoot({
2766
2850
  children,
@@ -2770,18 +2854,24 @@ function TooltipRoot({
2770
2854
  maxWidth,
2771
2855
  maxHeight,
2772
2856
  withoutArrow = false,
2857
+ scrollContainerRef,
2858
+ centerArrowToTrigger = true,
2773
2859
  ...tooltipContentProps
2774
2860
  }) {
2775
- return /* @__PURE__ */ jsx(DropdownMenu.Root, { children: ({ portalPlacement }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
2861
+ return /* @__PURE__ */ jsx(DropdownMenu.Root, { children: ({ portalPlacement, triggerRef }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
2776
2862
  /* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, triggerEvent, children }),
2777
2863
  /* @__PURE__ */ jsx(
2778
2864
  DropdownMenu.Portal,
2779
2865
  {
2780
2866
  align,
2781
2867
  position,
2782
- offset: TOOLTIP_OFFSET,
2868
+ offset: TOOLTIP_CONTENT_ARROW.height,
2783
2869
  maxWidth,
2784
2870
  maxHeight,
2871
+ scrollContainerRef,
2872
+ style: {
2873
+ ...!withoutArrow && centerArrowToTrigger && getCenteredPortalShiftStyle({ portalPlacement, triggerRef })
2874
+ },
2785
2875
  children: /* @__PURE__ */ jsx(
2786
2876
  TooltipContent,
2787
2877
  {
package/dist/style.css CHANGED
@@ -1863,13 +1863,9 @@ textarea {
1863
1863
  }
1864
1864
  }
1865
1865
  @layer ui_baza_components {
1866
- ._tooltipContent_1267q_2 {
1867
- --tooltip-content-arrow-width: 16px;
1868
- --tooltip-content-arrow-height: 8px;
1866
+ ._tooltipContent_ww0bo_2 {
1869
1867
  --tooltip-content-arrow-square-side: calc(var(--tooltip-content-arrow-height) * sqrt(2));
1870
1868
  --tooltip-content-arrow-border-radius: 2px;
1871
- --tooltip-content-arrow-offset-inline: var(--space-xl);
1872
- --tooltip-content-arrow-offset-block: var(--space-lg);
1873
1869
 
1874
1870
  display: flex;
1875
1871
  position: relative;
@@ -1957,7 +1953,7 @@ textarea {
1957
1953
  }
1958
1954
  }
1959
1955
 
1960
- ._tooltipTitle_1267q_96 {
1956
+ ._tooltipTitle_ww0bo_92 {
1961
1957
  font-weight: var(--font-weight-medium);
1962
1958
  font-size: var(--size-md);
1963
1959
  line-height: var(--line-height-lg);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grandbazar/ui-baza",
3
- "version": "1.2.8",
3
+ "version": "1.2.10",
4
4
  "description": "A lightweight and modular UI kit for building modern, accessible web interfaces. Designed for flexibility, scalability, and developer happiness.",
5
5
  "repository": {
6
6
  "type": "git",