1
- import React , { useEffect , useState } from 'react' ;
1
+ import React , { useEffect , useState , useRef } from 'react' ;
2
2
import { createPortal } from 'react-dom' ;
3
3
import Option from './option' ;
4
4
import EmptyOption from './empty-options' ;
5
5
6
+ import './menu.scss' ;
7
+
6
8
const getScrollParent = ( element ) => {
7
9
let style = getComputedStyle ( element ) ;
8
10
const excludeStaticParent = style . position === 'absolute' ;
@@ -35,29 +37,63 @@ const getMenuPosition = (selectBase) => {
35
37
return selectBase . getBoundingClientRect ( ) ;
36
38
} ;
37
39
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
+
38
51
const MenuPortal = ( { selectToggleRef, menuPortalTarget, children } ) => {
39
52
const [ position , setPosition ] = useState ( getMenuPosition ( selectToggleRef . current ) ) ;
53
+ const [ { cropSize, rootPosition, maxHeight } , setCropSize ] = useState ( { } ) ;
54
+ const menuRef = useRef ( ) ;
40
55
useEffect ( ( ) => {
56
+ setCropSize ( { maxHeight : window . innerHeight - menuRef . current . getBoundingClientRect ( ) . top - 4 } ) ;
41
57
const scrollParentElement = getScrollParent ( selectToggleRef . current ) ;
42
- const scrollListener = scrollParentElement . addEventListener ( 'scroll' , ( ) => {
58
+ const scrollHandler = function ( ) {
59
+ setCropSize ( checkScrollVisibility ( scrollParentElement , selectToggleRef . current , menuRef . current ) ) ;
43
60
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 } ) ) ;
46
65
setPosition ( getMenuPosition ( selectToggleRef . current ) ) ;
47
- } ) ;
66
+ } ;
67
+
68
+ scrollParentElement . addEventListener ( 'scroll' , scrollHandler , true ) ;
69
+ window . addEventListener ( 'resize' , resizeHandler , true ) ;
48
70
return ( ) => {
49
- window . removeEventListener ( 'resize' , resizeListener ) ;
50
- scrollParentElement . removeEventListener ( 'scroll' , scrollListener ) ;
71
+ window . removeEventListener ( 'resize' , resizeHandler , true ) ;
72
+ scrollParentElement . removeEventListener ( 'scroll' , scrollHandler , true ) ;
51
73
} ;
52
74
} , [ selectToggleRef ] ) ;
53
75
54
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
+ } ) ;
55
83
const portalDiv = (
56
84
< div
85
+ ref = { menuRef }
57
86
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
+ } }
59
95
>
60
- { children }
96
+ { cropSize < 0 ? < div style = { { position : 'relative' , top : cropSize , width : position . width } } > { sizedMenu } </ div > : sizedMenu }
61
97
</ div >
62
98
) ;
63
99
@@ -83,7 +119,7 @@ const Menu = ({
83
119
} ) => {
84
120
const filteredOptions = isSearchable ? filterOptions ( options , filterValue ) : options ;
85
121
const menuItems = (
86
- < ul className = " pf-c-select__menu" >
122
+ < ul className = { ` pf-c-select__menu${ menuIsPortal ? ' ddorg__pf4-component-mapper__select-menu-portal' : '' } ` } >
87
123
{ filteredOptions . length === 0 && (
88
124
< EmptyOption
89
125
isSearchable = { isSearchable }
0 commit comments