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:
parent
e441c4ee91
commit
009639b1ea
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user