Skip to content

Commit e7c047e

Browse files
committed
fix(pf4): add scroll menu and crop menu features
1 parent 37bb475 commit e7c047e

File tree

3 files changed

+56
-11
lines changed

3 files changed

+56
-11
lines changed

packages/pf4-component-mapper/demo/demo-schemas/select-schema.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,5 +164,6 @@ const selectSchema = {
164164
};
165165

166166
export default {
167-
...selectSchema
167+
...selectSchema,
168+
fields: [selectSchema.fields[0]]
168169
};

packages/pf4-component-mapper/src/common/select/menu.js

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import React, { useEffect, useState } from 'react';
1+
import React, { useEffect, useState, useRef } from 'react';
22
import { createPortal } from 'react-dom';
33
import Option from './option';
44
import EmptyOption from './empty-options';
55

6+
import './menu.scss';
7+
68
const 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+
3851
const 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}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.pf-c-select__menu.ddorg__pf4-component-mapper__select-menu-portal {
2+
margin-top: 2px;
3+
position: relative;
4+
width: calc(100% - 2px);
5+
min-width: calc(100% - 2px);
6+
left: 1px;
7+
border-bottom: 1px solid #ddd;
8+
}

0 commit comments

Comments
 (0)