mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-04-20 14:52:13 +00:00
resizable label/menu in popup implemented
This commit is contained in:
parent
f1a70932d8
commit
c0ea366fc4
2 changed files with 49 additions and 27 deletions
|
|
@ -15,14 +15,15 @@ class Popup extends Component {
|
||||||
this.labelBorderRightRef = React.createRef();
|
this.labelBorderRightRef = React.createRef();
|
||||||
this.labelBorderBottomRef = React.createRef();
|
this.labelBorderBottomRef = React.createRef();
|
||||||
this.labelBorderLeftRef = React.createRef();
|
this.labelBorderLeftRef = React.createRef();
|
||||||
this.menuRef = React.createRef();
|
this.menuContainerRef = React.createRef();
|
||||||
this.menuScrollRef = React.createRef();
|
this.menuScrollRef = React.createRef();
|
||||||
|
this.menuChildrenRef = React.createRef();
|
||||||
this.menuBorderTopRef = React.createRef();
|
this.menuBorderTopRef = React.createRef();
|
||||||
this.menuBorderRightRef = React.createRef();
|
this.menuBorderRightRef = React.createRef();
|
||||||
this.menuBorderBottomRef = React.createRef();
|
this.menuBorderBottomRef = React.createRef();
|
||||||
this.menuBorderLeftRef = React.createRef();
|
this.menuBorderLeftRef = React.createRef();
|
||||||
this.hiddenBorderRef = React.createRef();
|
this.hiddenBorderRef = React.createRef();
|
||||||
this.labelMutationObserver = this.createLabelMutationObserver();
|
this.popupMutationObserver = this.createPopupMutationObserver();
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
open: false
|
open: false
|
||||||
|
|
@ -39,7 +40,7 @@ class Popup extends Component {
|
||||||
window.removeEventListener('blur', this.close);
|
window.removeEventListener('blur', this.close);
|
||||||
window.removeEventListener('resize', this.close);
|
window.removeEventListener('resize', this.close);
|
||||||
window.removeEventListener('keyup', this.onKeyUp);
|
window.removeEventListener('keyup', this.onKeyUp);
|
||||||
this.labelMutationObserver.disconnect();
|
this.popupMutationObserver.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
|
|
@ -50,7 +51,7 @@ class Popup extends Component {
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
if (this.state.open && !prevState.open) {
|
if (this.state.open && !prevState.open) {
|
||||||
this.updateStyles();
|
this.updateStyles();
|
||||||
this.labelMutationObserver.observe(document.documentElement, {
|
this.popupMutationObserver.observe(document.documentElement, {
|
||||||
childList: true,
|
childList: true,
|
||||||
attributes: true,
|
attributes: true,
|
||||||
subtree: true
|
subtree: true
|
||||||
|
|
@ -59,37 +60,56 @@ class Popup extends Component {
|
||||||
this.props.onOpen();
|
this.props.onOpen();
|
||||||
}
|
}
|
||||||
} else if (!this.state.open && prevState.open) {
|
} else if (!this.state.open && prevState.open) {
|
||||||
this.labelMutationObserver.disconnect();
|
this.popupMutationObserver.disconnect();
|
||||||
if (typeof this.props.onClose === 'function') {
|
if (typeof this.props.onClose === 'function') {
|
||||||
this.props.onClose();
|
this.props.onClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createLabelMutationObserver = () => {
|
createPopupMutationObserver = () => {
|
||||||
let prevLabelRect = {};
|
let prevLabelRect = {};
|
||||||
|
let prevMenuChildrenRect = {};
|
||||||
return new MutationObserver(() => {
|
return new MutationObserver(() => {
|
||||||
if (this.state.open) {
|
if (this.state.open) {
|
||||||
const labelRect = this.labelRef.current.getBoundingClientRect();
|
const labelRect = this.labelRef.current.getBoundingClientRect();
|
||||||
|
const menuChildrenRect = this.menuChildrenRef.current.getBoundingClientRect();
|
||||||
if (labelRect.x !== prevLabelRect.x ||
|
if (labelRect.x !== prevLabelRect.x ||
|
||||||
labelRect.y !== prevLabelRect.y ||
|
labelRect.y !== prevLabelRect.y ||
|
||||||
labelRect.width !== prevLabelRect.width ||
|
labelRect.width !== prevLabelRect.width ||
|
||||||
labelRect.height !== prevLabelRect.height) {
|
labelRect.height !== prevLabelRect.height ||
|
||||||
|
menuChildrenRect.x !== prevMenuChildrenRect.x ||
|
||||||
|
menuChildrenRect.y !== prevMenuChildrenRect.y ||
|
||||||
|
menuChildrenRect.width !== prevMenuChildrenRect.width ||
|
||||||
|
menuChildrenRect.height !== prevMenuChildrenRect.height) {
|
||||||
this.updateStyles();
|
this.updateStyles();
|
||||||
}
|
}
|
||||||
|
|
||||||
prevLabelRect = labelRect;
|
prevLabelRect = labelRect;
|
||||||
|
prevMenuChildrenRect = menuChildrenRect;
|
||||||
} else {
|
} else {
|
||||||
prevLabelRect = {};
|
prevLabelRect = {};
|
||||||
|
prevMenuChildrenRect = {};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStyles = () => {
|
updateStyles = () => {
|
||||||
|
this.menuContainerRef.current.removeAttribute('style');
|
||||||
|
this.menuScrollRef.current.removeAttribute('style');
|
||||||
|
this.menuBorderTopRef.current.removeAttribute('style');
|
||||||
|
this.menuBorderRightRef.current.removeAttribute('style');
|
||||||
|
this.menuBorderBottomRef.current.removeAttribute('style');
|
||||||
|
this.menuBorderLeftRef.current.removeAttribute('style');
|
||||||
|
this.labelBorderTopRef.current.removeAttribute('style');
|
||||||
|
this.labelBorderRightRef.current.removeAttribute('style');
|
||||||
|
this.labelBorderBottomRef.current.removeAttribute('style');
|
||||||
|
this.labelBorderLeftRef.current.removeAttribute('style');
|
||||||
|
|
||||||
const menuDirections = {};
|
const menuDirections = {};
|
||||||
const bodyRect = document.body.getBoundingClientRect();
|
const bodyRect = document.body.getBoundingClientRect();
|
||||||
const menuRect = this.menuRef.current.getBoundingClientRect();
|
|
||||||
const labelRect = this.labelRef.current.getBoundingClientRect();
|
const labelRect = this.labelRef.current.getBoundingClientRect();
|
||||||
|
const menuChildredRect = this.menuChildrenRef.current.getBoundingClientRect();
|
||||||
const borderSize = parseFloat(window.getComputedStyle(this.hiddenBorderRef.current).getPropertyValue('border-top-width'));
|
const borderSize = parseFloat(window.getComputedStyle(this.hiddenBorderRef.current).getPropertyValue('border-top-width'));
|
||||||
const labelPosition = {
|
const labelPosition = {
|
||||||
left: labelRect.x - bodyRect.x,
|
left: labelRect.x - bodyRect.x,
|
||||||
|
|
@ -98,38 +118,38 @@ class Popup extends Component {
|
||||||
bottom: (bodyRect.height + bodyRect.y) - (labelRect.y + labelRect.height)
|
bottom: (bodyRect.height + bodyRect.y) - (labelRect.y + labelRect.height)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (menuRect.height <= labelPosition.bottom) {
|
if (menuChildredRect.height <= labelPosition.bottom) {
|
||||||
this.menuRef.current.style.top = `${labelPosition.top + labelRect.height}px`;
|
this.menuContainerRef.current.style.top = `${labelPosition.top + labelRect.height}px`;
|
||||||
this.menuScrollRef.current.style.maxHeight = `${labelPosition.bottom}px`;
|
this.menuScrollRef.current.style.maxHeight = `${labelPosition.bottom}px`;
|
||||||
menuDirections.bottom = true;
|
menuDirections.bottom = true;
|
||||||
} else if (menuRect.height <= labelPosition.top) {
|
} else if (menuChildredRect.height <= labelPosition.top) {
|
||||||
this.menuRef.current.style.bottom = `${labelPosition.bottom + labelRect.height}px`;
|
this.menuContainerRef.current.style.bottom = `${labelPosition.bottom + labelRect.height}px`;
|
||||||
this.menuScrollRef.current.style.maxHeight = `${labelPosition.top}px`;
|
this.menuScrollRef.current.style.maxHeight = `${labelPosition.top}px`;
|
||||||
menuDirections.top = true;
|
menuDirections.top = true;
|
||||||
} else if (labelPosition.bottom >= labelPosition.top) {
|
} else if (labelPosition.bottom >= labelPosition.top) {
|
||||||
this.menuRef.current.style.top = `${labelPosition.top + labelRect.height}px`;
|
this.menuContainerRef.current.style.top = `${labelPosition.top + labelRect.height}px`;
|
||||||
this.menuScrollRef.current.style.maxHeight = `${labelPosition.bottom}px`;
|
this.menuScrollRef.current.style.maxHeight = `${labelPosition.bottom}px`;
|
||||||
menuDirections.bottom = true;
|
menuDirections.bottom = true;
|
||||||
} else {
|
} else {
|
||||||
this.menuRef.current.style.bottom = `${labelPosition.bottom + labelRect.height}px`;
|
this.menuContainerRef.current.style.bottom = `${labelPosition.bottom + labelRect.height}px`;
|
||||||
this.menuScrollRef.current.style.maxHeight = `${labelPosition.top}px`;
|
this.menuScrollRef.current.style.maxHeight = `${labelPosition.top}px`;
|
||||||
menuDirections.top = true;
|
menuDirections.top = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (menuRect.width <= (labelPosition.right + labelRect.width)) {
|
if (menuChildredRect.width <= (labelPosition.right + labelRect.width)) {
|
||||||
this.menuRef.current.style.left = `${labelPosition.left}px`;
|
this.menuContainerRef.current.style.left = `${labelPosition.left}px`;
|
||||||
this.menuScrollRef.current.style.maxWidth = `${labelPosition.right + labelRect.width}px`;
|
this.menuScrollRef.current.style.maxWidth = `${labelPosition.right + labelRect.width}px`;
|
||||||
menuDirections.right = true;
|
menuDirections.right = true;
|
||||||
} else if (menuRect.width <= (labelPosition.left + labelRect.width)) {
|
} else if (menuChildredRect.width <= (labelPosition.left + labelRect.width)) {
|
||||||
this.menuRef.current.style.right = `${labelPosition.right}px`;
|
this.menuContainerRef.current.style.right = `${labelPosition.right}px`;
|
||||||
this.menuScrollRef.current.style.maxWidth = `${labelPosition.left + labelRect.width}px`;
|
this.menuScrollRef.current.style.maxWidth = `${labelPosition.left + labelRect.width}px`;
|
||||||
menuDirections.left = true;
|
menuDirections.left = true;
|
||||||
} else if (labelPosition.right > labelPosition.left) {
|
} else if (labelPosition.right > labelPosition.left) {
|
||||||
this.menuRef.current.style.left = `${labelPosition.left}px`;
|
this.menuContainerRef.current.style.left = `${labelPosition.left}px`;
|
||||||
this.menuScrollRef.current.style.maxWidth = `${labelPosition.right + labelRect.width}px`;
|
this.menuScrollRef.current.style.maxWidth = `${labelPosition.right + labelRect.width}px`;
|
||||||
menuDirections.right = true;
|
menuDirections.right = true;
|
||||||
} else {
|
} else {
|
||||||
this.menuRef.current.style.right = `${labelPosition.right}px`;
|
this.menuContainerRef.current.style.right = `${labelPosition.right}px`;
|
||||||
this.menuScrollRef.current.style.maxWidth = `${labelPosition.left + labelRect.width}px`;
|
this.menuScrollRef.current.style.maxWidth = `${labelPosition.left + labelRect.width}px`;
|
||||||
menuDirections.left = true;
|
menuDirections.left = true;
|
||||||
}
|
}
|
||||||
|
|
@ -157,14 +177,14 @@ class Popup extends Component {
|
||||||
this.labelBorderLeftRef.current.style.left = `${labelPosition.left}px`;
|
this.labelBorderLeftRef.current.style.left = `${labelPosition.left}px`;
|
||||||
|
|
||||||
if (menuDirections.top) {
|
if (menuDirections.top) {
|
||||||
this.labelBorderTopRef.current.style.left = `${labelPosition.left + menuRect.width}px`;
|
this.labelBorderTopRef.current.style.left = `${labelPosition.left + menuChildredRect.width}px`;
|
||||||
if (menuDirections.left) {
|
if (menuDirections.left) {
|
||||||
this.menuBorderBottomRef.current.style.right = `${labelRect.width - borderSize}px`;
|
this.menuBorderBottomRef.current.style.right = `${labelRect.width - borderSize}px`;
|
||||||
} else {
|
} else {
|
||||||
this.menuBorderBottomRef.current.style.left = `${labelRect.width - borderSize}px`;
|
this.menuBorderBottomRef.current.style.left = `${labelRect.width - borderSize}px`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.labelBorderBottomRef.current.style.left = `${labelPosition.left + menuRect.width}px`;
|
this.labelBorderBottomRef.current.style.left = `${labelPosition.left + menuChildredRect.width}px`;
|
||||||
if (menuDirections.left) {
|
if (menuDirections.left) {
|
||||||
this.menuBorderTopRef.current.style.right = `${labelRect.width - borderSize}px`;
|
this.menuBorderTopRef.current.style.right = `${labelRect.width - borderSize}px`;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -173,7 +193,7 @@ class Popup extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.menuRef.current.style.visibility = 'visible';
|
this.menuContainerRef.current.style.visibility = 'visible';
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyUp = (event) => {
|
onKeyUp = (event) => {
|
||||||
|
|
@ -206,9 +226,11 @@ class Popup extends Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal className={classnames('modal-container', this.props.className)} onClick={this.close}>
|
<Modal className={classnames('modal-container', this.props.className)} onClick={this.close}>
|
||||||
<div ref={this.menuRef} className={styles['menu-container']} onClick={this.menuContainerOnClick}>
|
<div ref={this.menuContainerRef} className={styles['menu-container']} onClick={this.menuContainerOnClick}>
|
||||||
<div ref={this.menuScrollRef} className={styles['scroll-container']}>
|
<div ref={this.menuScrollRef} className={styles['menu-scroll-container']}>
|
||||||
{children}
|
<div ref={this.menuChildrenRef}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div ref={this.menuBorderTopRef} className={classnames(styles['border'], styles['border-top'])} />
|
<div ref={this.menuBorderTopRef} className={classnames(styles['border'], styles['border-top'])} />
|
||||||
<div ref={this.menuBorderRightRef} className={classnames(styles['border'], styles['border-right'])} />
|
<div ref={this.menuBorderRightRef} className={classnames(styles['border'], styles['border-right'])} />
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
|
||||||
.scroll-container {
|
.menu-scroll-container {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue