1
0
mirror of https://github.com/mattermost/focalboard.git synced 2025-07-12 23:50:27 +02:00

Fix hover menu behavior on ViewHeader component (#2662)

This commit is contained in:
Jesús Espino
2022-03-29 13:59:28 +02:00
committed by GitHub
parent c58eee4d85
commit a53ff91033
3 changed files with 30 additions and 49 deletions

View File

@ -253,23 +253,29 @@ const ViewMenu = (props: Props) => {
/>))} />))}
<BoardPermissionGate permissions={[Permission.ManageBoardProperties]}> <BoardPermissionGate permissions={[Permission.ManageBoardProperties]}>
<Menu.Separator/> <Menu.Separator/>
</BoardPermissionGate>
{!props.readonly && {!props.readonly &&
<BoardPermissionGate permissions={[Permission.ManageBoardProperties]}>
<Menu.Text <Menu.Text
id='__duplicateView' id='__duplicateView'
name={duplicateViewText} name={duplicateViewText}
icon={<DuplicateIcon/>} icon={<DuplicateIcon/>}
onClick={handleDuplicateView} onClick={handleDuplicateView}
/> />
</BoardPermissionGate>
} }
{!props.readonly && views.length > 1 && {!props.readonly && views.length > 1 &&
<BoardPermissionGate permissions={[Permission.ManageBoardProperties]}>
<Menu.Text <Menu.Text
id='__deleteView' id='__deleteView'
name={deleteViewText} name={deleteViewText}
icon={<DeleteIcon/>} icon={<DeleteIcon/>}
onClick={handleDeleteView} onClick={handleDeleteView}
/> />
</BoardPermissionGate>
} }
{!props.readonly && {!props.readonly &&
<BoardPermissionGate permissions={[Permission.ManageBoardProperties]}>
<Menu.SubMenu <Menu.SubMenu
id='__addView' id='__addView'
name={addViewText} name={addViewText}
@ -300,8 +306,8 @@ const ViewMenu = (props: Props) => {
onClick={handleAddViewCalendar} onClick={handleAddViewCalendar}
/> />
</Menu.SubMenu> </Menu.SubMenu>
}
</BoardPermissionGate> </BoardPermissionGate>
}
</Menu> </Menu>
) )
} }

View File

@ -6,7 +6,7 @@ import SeparatorOption from './separatorOption'
import SwitchOption from './switchOption' import SwitchOption from './switchOption'
import TextOption from './textOption' import TextOption from './textOption'
import ColorOption from './colorOption' import ColorOption from './colorOption'
import SubMenuOption from './subMenuOption' import SubMenuOption, {HoveringContext} from './subMenuOption'
import LabelOption from './labelOption' import LabelOption from './labelOption'
import './menu.scss' import './menu.scss'
@ -27,7 +27,7 @@ export default class Menu extends React.PureComponent<Props> {
static Label = LabelOption static Label = LabelOption
public state = { public state = {
hoveringIdx: -1, hovering: null,
} }
public render(): JSX.Element { public render(): JSX.Element {
@ -36,16 +36,14 @@ export default class Menu extends React.PureComponent<Props> {
<div className={'Menu noselect ' + (position || 'bottom')}> <div className={'Menu noselect ' + (position || 'bottom')}>
<div className='menu-contents'> <div className='menu-contents'>
<div className='menu-options'> <div className='menu-options'>
{React.Children.map(children, (child, i) => { {React.Children.map(children, (child) => (
return addChildMenuItem({ <div
child, onMouseEnter={() => this.setState({hovering: child})}
onMouseEnter: () => >
this.setState({ <HoveringContext.Provider value={child == this.state.hovering}>
hoveringIdx: i, {child}
}), </HoveringContext.Provider>
isHovering: () => i === this.state.hoveringIdx, </div>))}
})
})}
</div> </div>
<div className='menu-spacer hideOnWidescreen'/> <div className='menu-spacer hideOnWidescreen'/>
@ -67,28 +65,3 @@ export default class Menu extends React.PureComponent<Props> {
// No need to do anything, as click bubbled up to MenuWrapper, which closes // No need to do anything, as click bubbled up to MenuWrapper, which closes
} }
} }
function addChildMenuItem(props: {child: React.ReactNode, onMouseEnter: () => void, isHovering: () => boolean}): JSX.Element | null {
const {child, onMouseEnter, isHovering} = props
if (child !== null) {
if (React.isValidElement(child)) {
const castedChild = child as React.ReactElement
return (
<div
onMouseEnter={onMouseEnter}
>
{castedChild.type === SubMenuOption ? (
<castedChild.type
{...castedChild.props}
isHovering={isHovering}
/>
) : (
<castedChild.type {...castedChild.props}/>
)}
</div>
)
}
}
return (null)
}

View File

@ -1,6 +1,6 @@
// 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, {useEffect, useState} from 'react' import React, {useEffect, useState, useContext} from 'react'
import SubmenuTriangleIcon from '../icons/submenuTriangle' import SubmenuTriangleIcon from '../icons/submenuTriangle'
@ -8,25 +8,27 @@ import Menu from '.'
import './subMenuOption.scss' import './subMenuOption.scss'
export const HoveringContext = React.createContext(false)
type SubMenuOptionProps = { type SubMenuOptionProps = {
id: string id: string
name: string name: string
position?: 'bottom' | 'top' | 'left' | 'left-bottom' position?: 'bottom' | 'top' | 'left' | 'left-bottom'
icon?: React.ReactNode icon?: React.ReactNode
children: React.ReactNode children: React.ReactNode
isHovering?: boolean
} }
function SubMenuOption(props: SubMenuOptionProps): JSX.Element { function SubMenuOption(props: SubMenuOptionProps): JSX.Element {
const [isOpen, setIsOpen] = useState(false) const [isOpen, setIsOpen] = useState(false)
const isHovering = useContext(HoveringContext)
const openLeftClass = props.position === 'left' || props.position === 'left-bottom' ? ' open-left' : '' const openLeftClass = props.position === 'left' || props.position === 'left-bottom' ? ' open-left' : ''
useEffect(() => { useEffect(() => {
if (props.isHovering !== undefined) { if (isHovering !== undefined) {
setIsOpen(props.isHovering) setIsOpen(isHovering)
} }
}, [props.isHovering]) }, [isHovering])
return ( return (
<div <div