UNPKG

nishant-design-system

Version:
176 lines (159 loc) 4.31 kB
// @flow strict import * as React from 'react'; import {classify} from '../../utils/classify'; import type {IconType} from '../Icon/Icon'; import {MenuOptionButton} from './MenuOptionButton'; import css from './Menu.module.css'; type ClassNames = $ReadOnly<{ wrapper?: string, option?: string, groupTitle?: string, optionTextContainer?: string, optionTextLabel?: string, }>; export type MenuOption = { key: string, label?: string, secondaryLabel?: string, customComponent?: React.Node, iconLeft?: string, iconLeftType?: IconType, iconRight?: string, iconRightType?: IconType, disabled?: boolean, optionSize?: MenuSizeTypes, optionVariant?: MenuOptionsVariant, }; // Render first available option set export type BaseMenuProps = { onSelect?: (option: MenuOption) => mixed, selectedOption?: ?MenuOption, optionsVariant?: MenuOptionsVariant, selectedKeys?: Array<string>, classNames?: ClassNames, size?: MenuSizeTypes, width?: string, menuDisabled?: boolean, isFluid?: boolean, }; export type MenuOptionTypes = { options?: Array<MenuOption>, composeOptions?: Array<Array<MenuOption>>, groupTitleOptions?: Array<MenuGroupTitleOption>, }; export type MenuSizeTypes = 'medium' | 'small'; export type MenuOptionsVariant = 'checkbox' | 'radio' | 'normal'; export type MenuGroupTitleOption = { groupTitle?: React.Node, options?: Array<MenuOption>, showLineDivider?: boolean, }; export type MenuProps = { ...BaseMenuProps, ...MenuOptionTypes, }; const RenderOption = ({ options, composeOptions, groupTitleOptions, classNames, ...restProps }: MenuProps): React.Node => { if (options && Array.isArray(options) && options.length) { return ( <> {options.map((option) => ( <React.Fragment key={option.key}> <MenuOptionButton option={option} classNames={classNames} {...restProps} /> </React.Fragment> ))} </> ); } if ( composeOptions && Array.isArray(composeOptions) && composeOptions.length ) { return ( <> {composeOptions.map((composeMenuOptions, index) => ( // eslint-disable-next-line react/no-array-index-key <span className={css.menuDivider} key={index}> {composeMenuOptions.map((option) => ( <React.Fragment key={option.key}> <MenuOptionButton option={option} classNames={classNames} {...restProps} /> </React.Fragment> ))} </span> ))} </> ); } if ( groupTitleOptions && Array.isArray(groupTitleOptions) && groupTitleOptions.length ) { return ( <> {groupTitleOptions.map((optionsGroup, index) => ( // eslint-disable-next-line react/no-array-index-key <React.Fragment key={index}> {!!optionsGroup.groupTitle && ( <div className={classify( css.groupTitleWrapper, classNames?.groupTitle, )} > {optionsGroup.groupTitle} </div> )} {optionsGroup.options?.map((option) => ( <React.Fragment key={option.key}> <MenuOptionButton option={option} classNames={classNames} {...restProps} /> </React.Fragment> ))} </React.Fragment> ))} </> ); } return <></>; }; export const Menu: React$AbstractComponent<MenuProps, HTMLDivElement> = React.forwardRef<MenuProps, HTMLDivElement>( (props: MenuProps, ref): React.Node => { const {classNames, size = 'medium', width, isFluid = true} = props; return ( <div className={classify( css.menuCard, { [css.fluid]: isFluid, [css.medium]: size === 'medium', [css.small]: size === 'small', }, classNames?.wrapper, )} style={{width}} ref={ref} > <RenderOption {...props} /> </div> ); }, );