main

mattermost/focalboard

Last updated at: 28/12/2023 01:42

menu.tsx

TLDR

The provided file is a TypeScript file that contains the implementation of the Menu component. It is a pure component that renders a menu with different options and styles based on the props passed to it.

Classes

Menu

The Menu class is a React component that renders a menu with different options. It accepts the following props:

  • children (React.ReactNode): The options to be rendered inside the menu.
  • position (optional, string): The position of the menu. It can be 'top', 'bottom', 'left', 'right', or 'auto'.
  • fixed (optional, boolean): If set to true, the menu will use a fixed position.
  • parentRef (optional, React.RefObject): A reference to the parent element.

The Menu class provides the following static members:

  • Color: A component for rendering a color option.
  • SubMenu: A component for rendering a submenu option.
  • Switch: A component for rendering a switch option.
  • Separator: A component for rendering a separator option.
  • Text: A component for rendering a text option.
  • TextInput: A component for rendering a text input option.
  • Label: A component for rendering a label option.

The Menu class also defines an internal state with the following properties:

  • hovering: The currently hovering child option.
  • menuStyle: The style to apply to the menu.

The Menu class renders a <div> element with the class "Menu" that contains the menu options and a cancel option. The style and position of the menu are determined by the props and the parent element reference.

END

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {CSSProperties} from 'react'

import SeparatorOption from './separatorOption'
import SwitchOption from './switchOption'
import TextOption from './textOption'
import ColorOption from './colorOption'
import SubMenuOption, {HoveringContext} from './subMenuOption'
import LabelOption from './labelOption'

import './menu.scss'
import textInputOption from './textInputOption'
import MenuUtil from './menuUtil'

type Props = {
    children: React.ReactNode
    position?: 'top' | 'bottom' | 'left' | 'right' | 'auto'
    fixed?: boolean
    parentRef?: React.RefObject<any>
}

export default class Menu extends React.PureComponent<Props> {
    static Color = ColorOption
    static SubMenu = SubMenuOption
    static Switch = SwitchOption
    static Separator = SeparatorOption
    static Text = TextOption
    static TextInput = textInputOption
    static Label = LabelOption

    menuRef: React.RefObject<HTMLDivElement>

    constructor(props: Props) {
        super(props)

        this.menuRef = React.createRef<HTMLDivElement>()
    }

    public state = {
        hovering: null,
        menuStyle: {},
    }

    public render(): JSX.Element {
        const {position, fixed, children} = this.props

        let style: CSSProperties = {}
        if (this.props.parentRef) {
            const forceBottom = position ? ['bottom', 'left', 'right'].includes(position) : false
            style = MenuUtil.openUp(this.props.parentRef, forceBottom).style
        }

        return (
            <div
                className={`Menu noselect ${position || 'bottom'} ${fixed ? ' fixed' : ''}`}
                style={style}
                ref={this.menuRef}
            >
                <div className='menu-contents'>
                    <div className='menu-options'>
                        {React.Children.map(children, (child) => (
                            <div
                                onMouseEnter={() => this.setState({hovering: child})}
                            >
                                <HoveringContext.Provider value={child === this.state.hovering}>
                                    {child}
                                </HoveringContext.Provider>
                            </div>))}
                    </div>

                    <div className='menu-spacer hideOnWidescreen'/>

                    <div className='menu-options hideOnWidescreen'>
                        <Menu.Text
                            id='menu-cancel'
                            name={'Cancel'}
                            className='menu-cancel'
                            onClick={this.onCancel}
                        />
                    </div>
                </div>
            </div>
        )
    }

    private onCancel = () => {
        // No need to do anything, as click bubbled up to MenuWrapper, which closes
    }
}