diff --git a/examples/03-ui-components/13-custom-ui/MUISuggestionMenu.tsx b/examples/03-ui-components/13-custom-ui/MUISuggestionMenu.tsx index d677bfe15..dc1e43dbb 100644 --- a/examples/03-ui-components/13-custom-ui/MUISuggestionMenu.tsx +++ b/examples/03-ui-components/13-custom-ui/MUISuggestionMenu.tsx @@ -42,12 +42,26 @@ function MUISuggestionMenuItem( return; } - const overflow = elementOverflow( - itemRef.current, - document.querySelector( - `.MuiPaper-root:has([aria-label="suggestion-menu"])` - )! - ); + const overflow = elementOverflow(itemRef.current, () => { + if (!itemRef.current) { + return; + } + + let container: HTMLElement = itemRef.current; + + while ( + !container.classList.contains("MuiPaper-root") && + container.parentElement + ) { + container = container.parentElement; + } + + if (!container.classList.contains("MuiPaper-root")) { + return; + } + + return container; + }); if (overflow === "top") { itemRef.current.scrollIntoView(true); @@ -140,7 +154,7 @@ export function MUISuggestionMenu( diff --git a/packages/ariakit/src/style.css b/packages/ariakit/src/style.css index 213f4d5cd..881ba43fe 100644 --- a/packages/ariakit/src/style.css +++ b/packages/ariakit/src/style.css @@ -59,7 +59,8 @@ .bn-ariakit .bn-suggestion-menu { height: fit-content; - max-height: 100%; + max-height: inherit; + overflow-y: auto; } .bn-ariakit .bn-color-picker-dropdown { @@ -97,7 +98,7 @@ gap: 7px; height: fit-content; justify-items: center; - max-height: min(500px, 100%); + max-height: inherit; overflow-y: auto; padding: 20px; } diff --git a/packages/ariakit/src/suggestionMenu/SuggestionMenuItem.tsx b/packages/ariakit/src/suggestionMenu/SuggestionMenuItem.tsx index 8acf330c3..1169c7403 100644 --- a/packages/ariakit/src/suggestionMenu/SuggestionMenuItem.tsx +++ b/packages/ariakit/src/suggestionMenu/SuggestionMenuItem.tsx @@ -17,10 +17,7 @@ export const SuggestionMenuItem = forwardRef< return; } - const overflow = elementOverflow( - itemRef.current, - document.querySelector(".bn-suggestion-menu")! - ); + const overflow = elementOverflow(itemRef.current); if (overflow === "top") { itemRef.current.scrollIntoView(true); diff --git a/packages/ariakit/src/suggestionMenu/gridSuggestionMenu/GridSuggestionMenuItem.tsx b/packages/ariakit/src/suggestionMenu/gridSuggestionMenu/GridSuggestionMenuItem.tsx index 75624ede1..6db77fda6 100644 --- a/packages/ariakit/src/suggestionMenu/gridSuggestionMenu/GridSuggestionMenuItem.tsx +++ b/packages/ariakit/src/suggestionMenu/gridSuggestionMenu/GridSuggestionMenuItem.tsx @@ -17,10 +17,7 @@ export const GridSuggestionMenuItem = forwardRef< return; } - const overflow = elementOverflow( - itemRef.current, - document.querySelector(".bn-grid-suggestion-menu")! - ); + const overflow = elementOverflow(itemRef.current); if (overflow === "top") { itemRef.current.scrollIntoView(true); diff --git a/packages/mantine/src/suggestionMenu/SuggestionMenuItem.tsx b/packages/mantine/src/suggestionMenu/SuggestionMenuItem.tsx index c7db27e38..6174ff498 100644 --- a/packages/mantine/src/suggestionMenu/SuggestionMenuItem.tsx +++ b/packages/mantine/src/suggestionMenu/SuggestionMenuItem.tsx @@ -25,10 +25,7 @@ export const SuggestionMenuItem = forwardRef< return; } - const overflow = elementOverflow( - itemRef.current, - document.querySelector(".bn-suggestion-menu")! - ); + const overflow = elementOverflow(itemRef.current); if (overflow === "top") { itemRef.current.scrollIntoView(true); diff --git a/packages/mantine/src/suggestionMenu/gridSuggestionMenu/GridSuggestionMenuItem.tsx b/packages/mantine/src/suggestionMenu/gridSuggestionMenu/GridSuggestionMenuItem.tsx index a03edfd6b..ded689a9c 100644 --- a/packages/mantine/src/suggestionMenu/gridSuggestionMenu/GridSuggestionMenuItem.tsx +++ b/packages/mantine/src/suggestionMenu/gridSuggestionMenu/GridSuggestionMenuItem.tsx @@ -19,10 +19,7 @@ export const GridSuggestionMenuItem = forwardRef< return; } - const overflow = elementOverflow( - itemRef.current, - document.querySelector(".bn-grid-suggestion-menu")! - ); + const overflow = elementOverflow(itemRef.current); if (overflow === "top") { itemRef.current.scrollIntoView(true); diff --git a/packages/react/src/util/elementOverflow.ts b/packages/react/src/util/elementOverflow.ts index 2eff6bf5b..2a3136f16 100644 --- a/packages/react/src/util/elementOverflow.ts +++ b/packages/react/src/util/elementOverflow.ts @@ -1,9 +1,47 @@ -export function elementOverflow(element: HTMLElement, container: HTMLElement) { +// Default for `getContainer`, meant for use in suggestion menus. Traverses +// ancestors of the passed element until a suggestion menu root is found. +const defaultGetContainer = (element: HTMLElement) => { + let container: HTMLElement = element; + + while ( + !container.classList.contains("bn-suggestion-menu") && + !container.classList.contains("bn-grid-suggestion-menu") && + container.parentElement + ) { + container = container.parentElement; + } + + if ( + !container.classList.contains("bn-suggestion-menu") && + !container.classList.contains("bn-grid-suggestion-menu") + ) { + return; + } + + return container; +}; + +export function elementOverflow( + element: HTMLElement, + getContainer?: () => HTMLElement | undefined +) { + let container = getContainer?.(); + if (!container) { + container = defaultGetContainer(element); + } + if (!container) { + return "none"; + } + const elementRect = element.getBoundingClientRect(); - const parentRect = container.getBoundingClientRect(); + const containerRect = container.getBoundingClientRect(); + + if (!containerRect) { + return "none"; + } - const topOverflow = elementRect.top < parentRect.top; - const bottomOverflow = elementRect.bottom > parentRect.bottom; + const topOverflow = elementRect.top < containerRect.top; + const bottomOverflow = elementRect.bottom > containerRect.bottom; return topOverflow && bottomOverflow ? "both" diff --git a/packages/shadcn/src/style.css b/packages/shadcn/src/style.css index bd507e628..c54fc94d4 100644 --- a/packages/shadcn/src/style.css +++ b/packages/shadcn/src/style.css @@ -107,7 +107,8 @@ .bn-shadcn .bn-suggestion-menu { height: fit-content; - max-height: 100%; + max-height: inherit; + overflow-y: auto; } .bn-shadcn .bn-suggestion-menu-item[aria-selected="true"], @@ -123,7 +124,7 @@ gap: 7px; height: fit-content; justify-items: center; - max-height: min(500px, 100%); + max-height: inherit; overflow-y: auto; padding: 20px; } diff --git a/packages/shadcn/src/suggestionMenu/SuggestionMenuItem.tsx b/packages/shadcn/src/suggestionMenu/SuggestionMenuItem.tsx index a8800f3a5..dea07b2da 100644 --- a/packages/shadcn/src/suggestionMenu/SuggestionMenuItem.tsx +++ b/packages/shadcn/src/suggestionMenu/SuggestionMenuItem.tsx @@ -22,10 +22,7 @@ export const SuggestionMenuItem = forwardRef< return; } - const overflow = elementOverflow( - itemRef.current, - document.querySelector(".bn-suggestion-menu")! - ); + const overflow = elementOverflow(itemRef.current); if (overflow === "top") { itemRef.current.scrollIntoView(true); } else if (overflow === "bottom") { diff --git a/packages/shadcn/src/suggestionMenu/gridSuggestionMenu/GridSuggestionMenuItem.tsx b/packages/shadcn/src/suggestionMenu/gridSuggestionMenu/GridSuggestionMenuItem.tsx index 75624ede1..6db77fda6 100644 --- a/packages/shadcn/src/suggestionMenu/gridSuggestionMenu/GridSuggestionMenuItem.tsx +++ b/packages/shadcn/src/suggestionMenu/gridSuggestionMenu/GridSuggestionMenuItem.tsx @@ -17,10 +17,7 @@ export const GridSuggestionMenuItem = forwardRef< return; } - const overflow = elementOverflow( - itemRef.current, - document.querySelector(".bn-grid-suggestion-menu")! - ); + const overflow = elementOverflow(itemRef.current); if (overflow === "top") { itemRef.current.scrollIntoView(true);