1
0
mirror of https://github.com/mattermost/focalboard.git synced 2025-01-26 18:48:15 +02:00

Migrating to menuWrapper to functional component

This commit is contained in:
Jesús Espino 2021-03-30 13:53:12 +02:00
parent e441c4ee91
commit 009639b1ea

View File

@ -1,75 +1,49 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React from 'react' import React, {useRef, useState, useEffect} from 'react'
import './menuWrapper.scss' import './menuWrapper.scss'
type Props = { type Props = {
children?: React.ReactNode; children?: React.ReactNode;
onToggle?: (open: boolean) => void;
isDisabled?: boolean;
stopPropagationOnToggle?: boolean; stopPropagationOnToggle?: boolean;
className?: string className?: string
disabled?: boolean disabled?: boolean
} }
type State = { const MenuWrapper = React.memo((props: Props) => {
open: boolean; const node = useRef<HTMLDivElement>(null)
} const [open, setOpen] = useState(false)
export default class MenuWrapper extends React.PureComponent<Props, State> { if (!Array.isArray(props.children) || props.children.length !== 2) {
private node: React.RefObject<HTMLDivElement> throw new Error('MenuWrapper needs exactly 2 children')
public constructor(props: Props) {
super(props)
if (!Array.isArray(props.children) || props.children.length !== 2) {
throw new Error('MenuWrapper needs exactly 2 children')
}
this.state = {
open: false,
}
this.node = React.createRef()
} }
public componentDidMount(): void { const close = (): void => {
document.addEventListener('menuItemClicked', this.close, true) setOpen(false)
document.addEventListener('click', this.closeOnBlur, true)
document.addEventListener('keyup', this.keyboardClose, true)
} }
public componentWillUnmount(): void { const closeOnBlur = (e: Event) => {
document.removeEventListener('menuItemClicked', this.close, true) if (e.target && node.current?.contains(e.target as Node)) {
document.removeEventListener('click', this.closeOnBlur, true)
document.removeEventListener('keyup', this.keyboardClose, true)
}
private keyboardClose = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
this.close()
}
if (e.key === 'Tab') {
this.closeOnBlur(e)
}
}
private closeOnBlur = (e: Event) => {
if (this.node && this.node.current && e.target && this.node.current.contains(e.target as Node)) {
return return
} }
this.close() close()
} }
public close = (): void => { const keyboardClose = (e: KeyboardEvent) => {
if (this.state.open) { if (e.key === 'Escape') {
this.setState({open: false}) close()
}
if (e.key === 'Tab') {
closeOnBlur(e)
} }
} }
private toggle = (e: React.MouseEvent<HTMLDivElement, MouseEvent>): void => { const toggle = (e: React.MouseEvent<HTMLDivElement, MouseEvent>): void => {
if (this.props.disabled) { if (props.disabled) {
return return
} }
@ -79,33 +53,43 @@ export default class MenuWrapper extends React.PureComponent<Props, State> {
* We need to refactor this so that the modal is explicitly closed on toggle, but for now I am aiming to preserve the existing logic * We need to refactor this so that the modal is explicitly closed on toggle, but for now I am aiming to preserve the existing logic
* so as to not break other things * so as to not break other things
**/ **/
if (this.props.stopPropagationOnToggle) { if (props.stopPropagationOnToggle) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
} }
const newState = !this.state.open setOpen(!open)
this.setState({open: newState})
} }
public render(): JSX.Element { useEffect(() => {
const {children} = this.props document.addEventListener('menuItemClicked', close, true)
let className = 'MenuWrapper' document.addEventListener('click', closeOnBlur, true)
if (this.props.disabled) { document.addEventListener('keyup', keyboardClose, true)
className += ' disabled' return () => {
} document.removeEventListener('menuItemClicked', close, true)
if (this.props.className) { document.removeEventListener('click', closeOnBlur, true)
className += ' ' + this.props.className document.removeEventListener('keyup', keyboardClose, true)
} }
}, [])
return ( const {children} = props
<div let className = 'MenuWrapper'
className={className} if (props.disabled) {
onClick={this.toggle} className += ' disabled'
ref={this.node}
>
{children ? Object.values(children)[0] : null}
{children && !this.props.disabled && this.state.open ? Object.values(children)[1] : null}
</div>
)
} }
} if (props.className) {
className += ' ' + props.className
}
return (
<div
className={className}
onClick={toggle}
ref={node}
>
{children ? Object.values(children)[0] : null}
{children && !props.disabled && open ? Object.values(children)[1] : null}
</div>
)
})
export default MenuWrapper