11import React , { Component , createRef } from 'react' ;
2+ import { createPortal } from 'react-dom' ;
23import PropTypes from 'prop-types' ;
34
45import Icon from '../../../common/icon/icon' ;
56import ViewColumnsTogglerListElement from './view.columns.toggler.list.element' ;
67import { columnsLabels } from '../../sub.items.module' ;
78import { createCssClassNames } from '../../../common/helpers/css.class.names' ;
89
9- const { Translator } = window ;
10-
11- const DEFAULT_PANEL_HEIGHT = 450 ;
10+ const { document, Translator, Popper } = window ;
1211
1312export default class ViewColumnsTogglerComponent extends Component {
1413 constructor ( props ) {
@@ -22,76 +21,75 @@ export default class ViewColumnsTogglerComponent extends Component {
2221
2322 this . state = {
2423 isOpen : false ,
25- buttonBottomDocumentOffset : null ,
26- panelHeight : null ,
2724 } ;
2825 }
2926
3027 componentDidMount ( ) {
3128 document . addEventListener ( 'click' , this . hidePanel , false ) ;
3229
33- this . setState ( ( ) => ( {
34- buttonBottomDocumentOffset : this . getBtnBottomDocumentOffset ( ) ,
35- } ) ) ;
36- }
37-
38- componentDidUpdate ( ) {
39- const { isOpen, panelHeight } = this . state ;
40-
41- if ( isOpen && panelHeight === null ) {
42- this . setState ( {
43- panelHeight : this . _refPanel . current . offsetHeight ,
44- } ) ;
45- }
30+ this . popperInstance = new Popper . createPopper ( this . _refTogglerButton . current , this . _refPanel . current , {
31+ placement : 'bottom-end' ,
32+ modifiers : [
33+ {
34+ name : 'flip' ,
35+ enabled : true ,
36+ options : {
37+ fallbackPlacements : [ 'top-end' ] ,
38+ boundary : document . body ,
39+ } ,
40+ } ,
41+ {
42+ name : 'offset' ,
43+ options : {
44+ offset : [ 0 , 12 ] ,
45+ } ,
46+ } ,
47+ ] ,
48+ } ) ;
4649 }
4750
4851 componentWillUnmount ( ) {
4952 document . removeEventListener ( 'click' , this . hidePanel ) ;
50- }
5153
52- getBtnBottomDocumentOffset ( ) {
53- const buttonTopOffset = this . _refTogglerButton . current . getBoundingClientRect ( ) . top ;
54-
55- return window . innerHeight - buttonTopOffset ;
54+ this . popperInstance . destroy ( ) ;
5655 }
5756
5857 hidePanel ( { target } ) {
5958 if ( ! this . state . isOpen ) {
6059 return ;
6160 }
6261
63- const isClickInsideToggler = target . closest ( '.c-view-columns-toggler' ) ;
62+ const isClickInsideToggler = this . _refTogglerButton . current . contains ( target ) ;
63+ const isClickInsidePopup = this . _refPanel . current . contains ( target ) ;
6464
65- if ( ! isClickInsideToggler ) {
65+ if ( ! isClickInsideToggler && ! isClickInsidePopup ) {
6666 this . setState ( ( ) => ( {
6767 isOpen : false ,
6868 } ) ) ;
6969 }
7070 }
7171
7272 togglePanel ( ) {
73- this . setState ( ( state ) => ( {
74- buttonBottomDocumentOffset : this . getBtnBottomDocumentOffset ( ) ,
75- isOpen : ! state . isOpen ,
76- } ) ) ;
73+ this . setState (
74+ ( state ) => ( {
75+ isOpen : ! state . isOpen ,
76+ } ) ,
77+ ( ) => {
78+ this . popperInstance . update ( ) ;
79+ } ,
80+ ) ;
7781 }
7882
7983 renderPanel ( ) {
80- if ( ! this . state . isOpen ) {
81- return null ;
82- }
83-
8484 const { columnsVisibility, toggleColumnVisibility } = this . props ;
85- const { buttonBottomDocumentOffset, panelHeight : measuredPanelHeight } = this . state ;
86- const panelHeight = measuredPanelHeight ?? DEFAULT_PANEL_HEIGHT ;
87- const showAboveBtn = buttonBottomDocumentOffset < panelHeight ;
85+ const { isOpen } = this . state ;
8886 const className = createCssClassNames ( {
8987 'ibexa-popup-menu' : true ,
9088 'c-view-columns-toggler__panel' : true ,
91- 'c-view-columns-toggler__panel--above-btn ' : showAboveBtn ,
89+ 'c-view-columns-toggler__panel--hidden ' : ! isOpen ,
9290 } ) ;
9391
94- return (
92+ return createPortal (
9593 < ul className = { className } ref = { this . _refPanel } >
9694 { Object . entries ( columnsVisibility ) . map ( ( [ columnKey , isColumnVisible ] ) => {
9795 const label = columnsLabels [ columnKey ] ;
@@ -106,7 +104,8 @@ export default class ViewColumnsTogglerComponent extends Component {
106104 />
107105 ) ;
108106 } ) }
109- </ ul >
107+ </ ul > ,
108+ document . body ,
110109 ) ;
111110 }
112111
0 commit comments