1- import React , { useEffect , useState , Fragment } from 'react' ;
1+ import React , { useEffect , useState , useRef } from 'react' ;
22import { createPortal } from 'react-dom' ;
33import Option from './option' ;
4- import Input from './input' ;
54import EmptyOption from './empty-options' ;
65
6+ import './menu.scss' ;
7+
78const getScrollParent = ( element ) => {
89 let style = getComputedStyle ( element ) ;
910 const excludeStaticParent = style . position === 'absolute' ;
@@ -36,31 +37,63 @@ const getMenuPosition = (selectBase) => {
3637 return selectBase . getBoundingClientRect ( ) ;
3738} ;
3839
39- const MenuPortal = ( { selectToggleRef, menuPortalTarget, children, isSearchable } ) => {
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+
51+ const MenuPortal = ( { selectToggleRef, menuPortalTarget, children } ) => {
4052 const [ position , setPosition ] = useState ( getMenuPosition ( selectToggleRef . current ) ) ;
53+ const [ { cropSize, rootPosition, maxHeight } , setCropSize ] = useState ( { } ) ;
54+ const menuRef = useRef ( ) ;
4155 useEffect ( ( ) => {
56+ setCropSize ( { maxHeight : window . innerHeight - menuRef . current . getBoundingClientRect ( ) . top - 4 } ) ;
4257 const scrollParentElement = getScrollParent ( selectToggleRef . current ) ;
43- const scrollListener = scrollParentElement . addEventListener ( 'scroll' , ( ) => {
58+ const scrollHandler = function ( ) {
59+ setCropSize ( checkScrollVisibility ( scrollParentElement , selectToggleRef . current , menuRef . current ) ) ;
4460 setPosition ( getMenuPosition ( selectToggleRef . current ) ) ;
45- } ) ;
46- const resizeListener = window . addEventListener ( 'resize' , ( ) => {
61+ } ;
62+
63+ const resizeHandler = function ( ) {
64+ setCropSize ( ( prevSize ) => ( { ...prevSize , maxHeight : window . innerHeight - menuRef . current . getBoundingClientRect ( ) . top - 4 } ) ) ;
4765 setPosition ( getMenuPosition ( selectToggleRef . current ) ) ;
48- } ) ;
66+ } ;
67+
68+ scrollParentElement . addEventListener ( 'scroll' , scrollHandler , true ) ;
69+ window . addEventListener ( 'resize' , resizeHandler , true ) ;
4970 return ( ) => {
50- window . removeEventListener ( 'resize' , resizeListener ) ;
51- scrollParentElement . removeEventListener ( 'scroll' , scrollListener ) ;
71+ window . removeEventListener ( 'resize' , resizeHandler , true ) ;
72+ scrollParentElement . removeEventListener ( 'scroll' , scrollHandler , true ) ;
5273 } ;
5374 } , [ selectToggleRef ] ) ;
5475
55- const top = isSearchable ? position . top + position . height + 64 : position . top + position . height ;
76+ 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+ } ) ;
5683 const portalDiv = (
5784 < div
58- className = { `pf-c-select ddorg_pf4-component-mapper__select-portal-menu${
59- isSearchable ? ' ddorg_pf4-component-mapper__select-portal-menu-searchable' : ''
60- } `}
61- style = { { borderTop : '4px solid white' , zIndex : 401 , position : 'absolute' , top, left : position . left , width : position . width } }
85+ ref = { menuRef }
86+ className = "pf-c-select ddorg_pf4-component-mapper__select-portal-menu"
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+ } }
6295 >
63- { children }
96+ { cropSize < 0 ? < div style = { { position : 'relative' , top : cropSize , width : position . width } } > { sizedMenu } </ div > : sizedMenu }
6497 </ div >
6598 ) ;
6699
@@ -71,7 +104,6 @@ const Menu = ({
71104 noResultsMessage,
72105 noOptionsMessage,
73106 filterOptions,
74- inputRef,
75107 isSearchable,
76108 filterValue,
77109 options,
@@ -87,8 +119,7 @@ const Menu = ({
87119} ) => {
88120 const filteredOptions = isSearchable ? filterOptions ( options , filterValue ) : options ;
89121 const menuItems = (
90- < ul className = "pf-c-select__menu" >
91- { ! menuIsPortal && isSearchable && < Input inputRef = { inputRef } getInputProps = { getInputProps } /> }
122+ < ul className = { `pf-c-select__menu${ menuIsPortal ? ' ddorg__pf4-component-mapper__select-menu-portal' : '' } ` } >
92123 { filteredOptions . length === 0 && (
93124 < EmptyOption
94125 isSearchable = { isSearchable }
@@ -112,16 +143,9 @@ const Menu = ({
112143 ) ;
113144 if ( menuIsPortal ) {
114145 return (
115- < Fragment >
116- { isSearchable && (
117- < ul className = "pf-c-select__menu" >
118- < Input inputRef = { inputRef } getInputProps = { getInputProps } />
119- </ ul >
120- ) }
121- < MenuPortal isSearchable = { isSearchable } menuPortalTarget = { menuPortalTarget } selectToggleRef = { selectToggleRef } >
122- { menuItems }
123- </ MenuPortal >
124- </ Fragment >
146+ < MenuPortal menuPortalTarget = { menuPortalTarget } selectToggleRef = { selectToggleRef } >
147+ { menuItems }
148+ </ MenuPortal >
125149 ) ;
126150 }
127151
0 commit comments