1- import React , { useEffect , useState } from 'react' ;
1+ import React , { useEffect , useState , useRef } from 'react' ;
22import { createPortal } from 'react-dom' ;
33import Option from './option' ;
44import EmptyOption from './empty-options' ;
55
6+ import './menu.scss' ;
7+
68const getScrollParent = ( element ) => {
79 let style = getComputedStyle ( element ) ;
810 const excludeStaticParent = style . position === 'absolute' ;
@@ -35,29 +37,63 @@ const getMenuPosition = (selectBase) => {
3537 return selectBase . getBoundingClientRect ( ) ;
3638} ;
3739
40+ const checkScrollVisibility = ( scrollableParent , selectRoot , menuRoot ) => {
41+ const parentProportions = scrollableParent . getBoundingClientRect ( ) ;
42+ const rootProportions = selectRoot . getBoundingClientRect ( ) ;
43+ const menuProportions = menuRoot . getBoundingClientRect ( ) ;
44+ return {
45+ rootPosition : parentProportions . y ,
46+ cropSize : rootProportions . y + rootProportions . height - parentProportions . y ,
47+ maxHeight : window . innerHeight - menuProportions . top + 1
48+ } ;
49+ } ;
50+
3851const MenuPortal = ( { selectToggleRef, menuPortalTarget, children } ) => {
3952 const [ position , setPosition ] = useState ( getMenuPosition ( selectToggleRef . current ) ) ;
53+ const [ { cropSize, rootPosition, maxHeight } , setCropSize ] = useState ( { } ) ;
54+ const menuRef = useRef ( ) ;
4055 useEffect ( ( ) => {
56+ setCropSize ( { maxHeight : window . innerHeight - menuRef . current . getBoundingClientRect ( ) . top - 4 } ) ;
4157 const scrollParentElement = getScrollParent ( selectToggleRef . current ) ;
42- const scrollListener = scrollParentElement . addEventListener ( 'scroll' , ( ) => {
58+ const scrollHandler = function ( ) {
59+ setCropSize ( checkScrollVisibility ( scrollParentElement , selectToggleRef . current , menuRef . current ) ) ;
4360 setPosition ( getMenuPosition ( selectToggleRef . current ) ) ;
44- } ) ;
45- const resizeListener = window . addEventListener ( 'resize' , ( ) => {
61+ } ;
62+
63+ const resizeHandler = function ( ) {
64+ setCropSize ( ( prevSize ) => ( { ...prevSize , maxHeight : window . innerHeight - menuRef . current . getBoundingClientRect ( ) . top - 4 } ) ) ;
4665 setPosition ( getMenuPosition ( selectToggleRef . current ) ) ;
47- } ) ;
66+ } ;
67+
68+ scrollParentElement . addEventListener ( 'scroll' , scrollHandler , true ) ;
69+ window . addEventListener ( 'resize' , resizeHandler , true ) ;
4870 return ( ) => {
49- window . removeEventListener ( 'resize' , resizeListener ) ;
50- scrollParentElement . removeEventListener ( 'scroll' , scrollListener ) ;
71+ window . removeEventListener ( 'resize' , resizeHandler , true ) ;
72+ scrollParentElement . removeEventListener ( 'scroll' , scrollHandler , true ) ;
5173 } ;
5274 } , [ selectToggleRef ] ) ;
5375
5476 const top = position . top + position . height ;
77+ const sizedMenu = React . cloneElement ( children , {
78+ style : {
79+ maxHeight : cropSize < 0 ? maxHeight + cropSize : maxHeight ,
80+ overflow : 'auto'
81+ }
82+ } ) ;
5583 const portalDiv = (
5684 < div
85+ ref = { menuRef }
5786 className = "pf-c-select ddorg_pf4-component-mapper__select-portal-menu"
58- style = { { borderTop : '4px solid white' , zIndex : 401 , position : 'absolute' , top, left : position . left , width : position . width } }
87+ style = { {
88+ zIndex : 401 ,
89+ position : 'absolute' ,
90+ top : cropSize < 0 ? rootPosition : top ,
91+ left : position . left ,
92+ width : position . width ,
93+ overflow : 'hidden'
94+ } }
5995 >
60- { children }
96+ { cropSize < 0 ? < div style = { { position : 'relative' , top : cropSize , width : position . width } } > { sizedMenu } </ div > : sizedMenu }
6197 </ div >
6298 ) ;
6399
@@ -83,7 +119,7 @@ const Menu = ({
83119} ) => {
84120 const filteredOptions = isSearchable ? filterOptions ( options , filterValue ) : options ;
85121 const menuItems = (
86- < ul className = " pf-c-select__menu" >
122+ < ul className = { ` pf-c-select__menu${ menuIsPortal ? ' ddorg__pf4-component-mapper__select-menu-portal' : '' } ` } >
87123 { filteredOptions . length === 0 && (
88124 < EmptyOption
89125 isSearchable = { isSearchable }
0 commit comments