Migrate Menu component from useStyles to useDefinition
Split monolithic MenuDefinition (17 classNames) into 9 per-sub-component definitions (Menu, MenuListBox, MenuAutocomplete, MenuAutocompleteListbox, MenuItem, MenuListBoxItem, MenuSection, MenuSeparator, MenuEmptyState). MenuItem color prop uses dataAttribute with default in propDefs. Defaults for placement, virtualized, selectionMode moved to propDefs. Signed-off-by: Johan Persson <johanopersson@gmail.com>
This commit is contained in:
+100
-81
@@ -1481,57 +1481,59 @@ export const MenuAutocompleteListbox: (
|
||||
) => JSX_2.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface MenuAutocompleteListBoxProps<T>
|
||||
extends ListBoxProps<T>,
|
||||
Omit<ListBoxProps<T>, 'children'> {
|
||||
// (undocumented)
|
||||
maxHeight?: string;
|
||||
// (undocumented)
|
||||
maxWidth?: string;
|
||||
// (undocumented)
|
||||
export type MenuAutocompleteListBoxOwnProps = {
|
||||
placeholder?: string;
|
||||
// (undocumented)
|
||||
placement?: PopoverProps_2['placement'];
|
||||
// (undocumented)
|
||||
selectionMode?: ListBoxProps<object>['selectionMode'];
|
||||
virtualized?: boolean;
|
||||
}
|
||||
maxWidth?: string;
|
||||
maxHeight?: string;
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export interface MenuAutocompleteListBoxProps<T>
|
||||
extends MenuAutocompleteListBoxOwnProps,
|
||||
Omit<ListBoxProps<T>, keyof MenuAutocompleteListBoxOwnProps> {}
|
||||
|
||||
// @public (undocumented)
|
||||
export type MenuAutocompleteOwnProps = {
|
||||
placeholder?: string;
|
||||
placement?: PopoverProps_2['placement'];
|
||||
virtualized?: boolean;
|
||||
maxWidth?: string;
|
||||
maxHeight?: string;
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export interface MenuAutocompleteProps<T>
|
||||
extends MenuProps_2<T>,
|
||||
Omit<MenuProps_2<T>, 'children'> {
|
||||
// (undocumented)
|
||||
maxHeight?: string;
|
||||
// (undocumented)
|
||||
maxWidth?: string;
|
||||
// (undocumented)
|
||||
placeholder?: string;
|
||||
// (undocumented)
|
||||
placement?: PopoverProps_2['placement'];
|
||||
// (undocumented)
|
||||
virtualized?: boolean;
|
||||
}
|
||||
extends MenuAutocompleteOwnProps,
|
||||
Omit<MenuProps_2<T>, keyof MenuAutocompleteOwnProps> {}
|
||||
|
||||
// @public
|
||||
export const MenuDefinition: {
|
||||
readonly styles: {
|
||||
readonly [key: string]: string;
|
||||
};
|
||||
readonly classNames: {
|
||||
readonly root: 'bui-Menu';
|
||||
readonly popover: 'bui-MenuPopover';
|
||||
readonly root: 'bui-MenuPopover';
|
||||
readonly inner: 'bui-MenuInner';
|
||||
readonly content: 'bui-MenuContent';
|
||||
readonly section: 'bui-MenuSection';
|
||||
readonly sectionHeader: 'bui-MenuSectionHeader';
|
||||
readonly item: 'bui-MenuItem';
|
||||
readonly itemListBox: 'bui-MenuItemListBox';
|
||||
readonly itemListBoxCheck: 'bui-MenuItemListBoxCheck';
|
||||
readonly itemWrapper: 'bui-MenuItemWrapper';
|
||||
readonly itemContent: 'bui-MenuItemContent';
|
||||
readonly itemArrow: 'bui-MenuItemArrow';
|
||||
readonly separator: 'bui-MenuSeparator';
|
||||
readonly searchField: 'bui-MenuSearchField';
|
||||
readonly searchFieldInput: 'bui-MenuSearchFieldInput';
|
||||
readonly searchFieldClear: 'bui-MenuSearchFieldClear';
|
||||
readonly emptyState: 'bui-MenuEmptyState';
|
||||
};
|
||||
readonly propDefs: {
|
||||
readonly placement: {
|
||||
readonly default: 'bottom start';
|
||||
};
|
||||
readonly virtualized: {
|
||||
readonly default: false;
|
||||
};
|
||||
readonly maxWidth: {};
|
||||
readonly maxHeight: {};
|
||||
readonly style: {};
|
||||
readonly className: {};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1539,16 +1541,18 @@ export const MenuDefinition: {
|
||||
export const MenuItem: (props: MenuItemProps) => JSX_2.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface MenuItemProps
|
||||
extends MenuItemProps_2,
|
||||
Omit<MenuItemProps_2, 'children'> {
|
||||
// (undocumented)
|
||||
children: React.ReactNode;
|
||||
// (undocumented)
|
||||
color?: 'primary' | 'danger';
|
||||
// (undocumented)
|
||||
export type MenuItemOwnProps = {
|
||||
iconStart?: React.ReactNode;
|
||||
}
|
||||
children: React.ReactNode;
|
||||
color?: 'primary' | 'danger';
|
||||
href?: MenuItemProps_2['href'];
|
||||
className?: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export interface MenuItemProps
|
||||
extends MenuItemOwnProps,
|
||||
Omit<MenuItemProps_2, keyof MenuItemOwnProps> {}
|
||||
|
||||
// @public (undocumented)
|
||||
export const MenuListBox: (props: MenuListBoxProps<object>) => JSX_2.Element;
|
||||
@@ -1557,59 +1561,74 @@ export const MenuListBox: (props: MenuListBoxProps<object>) => JSX_2.Element;
|
||||
export const MenuListBoxItem: (props: MenuListBoxItemProps) => JSX_2.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface MenuListBoxItemProps
|
||||
extends ListBoxItemProps,
|
||||
Omit<ListBoxItemProps, 'children'> {
|
||||
// (undocumented)
|
||||
export type MenuListBoxItemOwnProps = {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
className?: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export interface MenuListBoxItemProps
|
||||
extends MenuListBoxItemOwnProps,
|
||||
Omit<ListBoxItemProps, keyof MenuListBoxItemOwnProps> {}
|
||||
|
||||
// @public (undocumented)
|
||||
export type MenuListBoxOwnProps = {
|
||||
placement?: PopoverProps_2['placement'];
|
||||
selectionMode?: ListBoxProps<object>['selectionMode'];
|
||||
virtualized?: boolean;
|
||||
maxWidth?: string;
|
||||
maxHeight?: string;
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export interface MenuListBoxProps<T>
|
||||
extends ListBoxProps<T>,
|
||||
Omit<ListBoxProps<T>, 'children'> {
|
||||
// (undocumented)
|
||||
maxHeight?: string;
|
||||
// (undocumented)
|
||||
maxWidth?: string;
|
||||
// (undocumented)
|
||||
extends MenuListBoxOwnProps,
|
||||
Omit<ListBoxProps<T>, keyof MenuListBoxOwnProps> {}
|
||||
|
||||
// @public (undocumented)
|
||||
export type MenuOwnProps = {
|
||||
placement?: PopoverProps_2['placement'];
|
||||
// (undocumented)
|
||||
virtualized?: boolean;
|
||||
}
|
||||
maxWidth?: string;
|
||||
maxHeight?: string;
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export interface MenuProps<T>
|
||||
extends MenuProps_2<T>,
|
||||
Omit<MenuProps_2<T>, 'children'> {
|
||||
// (undocumented)
|
||||
maxHeight?: string;
|
||||
// (undocumented)
|
||||
maxWidth?: string;
|
||||
// (undocumented)
|
||||
placement?: PopoverProps_2['placement'];
|
||||
// (undocumented)
|
||||
virtualized?: boolean;
|
||||
}
|
||||
extends MenuOwnProps,
|
||||
Omit<MenuProps_2<T>, keyof MenuOwnProps> {}
|
||||
|
||||
// @public (undocumented)
|
||||
export const MenuSection: (props: MenuSectionProps<object>) => JSX_2.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface MenuSectionProps<T>
|
||||
extends MenuSectionProps_2<T>,
|
||||
Omit<MenuSectionProps_2<T>, 'children'> {
|
||||
// (undocumented)
|
||||
children: React.ReactNode;
|
||||
// (undocumented)
|
||||
export type MenuSectionOwnProps = {
|
||||
title: string;
|
||||
}
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export interface MenuSectionProps<T>
|
||||
extends MenuSectionOwnProps,
|
||||
Omit<MenuSectionProps_2<T>, keyof MenuSectionOwnProps> {}
|
||||
|
||||
// @public (undocumented)
|
||||
export const MenuSeparator: (props: MenuSeparatorProps) => JSX_2.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface MenuSeparatorProps extends SeparatorProps {}
|
||||
export type MenuSeparatorOwnProps = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export interface MenuSeparatorProps
|
||||
extends MenuSeparatorOwnProps,
|
||||
Omit<SeparatorProps, keyof MenuSeparatorOwnProps> {}
|
||||
|
||||
// @public (undocumented)
|
||||
export const MenuTrigger: (props: MenuTriggerProps) => JSX_2.Element;
|
||||
|
||||
@@ -33,8 +33,18 @@ import {
|
||||
Virtualizer,
|
||||
ListLayout,
|
||||
} from 'react-aria-components';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
import { MenuDefinition } from './definition';
|
||||
import { useDefinition } from '../../hooks/useDefinition';
|
||||
import {
|
||||
MenuDefinition,
|
||||
MenuListBoxDefinition,
|
||||
MenuAutocompleteDefinition,
|
||||
MenuAutocompleteListboxDefinition,
|
||||
MenuItemDefinition,
|
||||
MenuListBoxItemDefinition,
|
||||
MenuSectionDefinition,
|
||||
MenuSeparatorDefinition,
|
||||
MenuEmptyStateDefinition,
|
||||
} from './definition';
|
||||
import type {
|
||||
MenuTriggerProps,
|
||||
SubmenuTriggerProps,
|
||||
@@ -56,8 +66,6 @@ import {
|
||||
isInternalLink,
|
||||
createRoutingRegistration,
|
||||
} from '../InternalLinkProvider';
|
||||
import styles from './Menu.module.css';
|
||||
import clsx from 'clsx';
|
||||
import { Box } from '../Box';
|
||||
import { BgReset } from '../../hooks/useBg';
|
||||
|
||||
@@ -68,13 +76,9 @@ const { RoutingProvider, useRoutingRegistrationEffect } =
|
||||
const rowHeight = 32;
|
||||
|
||||
const MenuEmptyState = () => {
|
||||
const { classNames } = useStyles(MenuDefinition);
|
||||
const { ownProps } = useDefinition(MenuEmptyStateDefinition, {});
|
||||
|
||||
return (
|
||||
<div className={clsx(classNames.emptyState, styles[classNames.emptyState])}>
|
||||
No results found.
|
||||
</div>
|
||||
);
|
||||
return <div className={ownProps.classes.root}>No results found.</div>;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
@@ -89,43 +93,26 @@ export const SubmenuTrigger = (props: SubmenuTriggerProps) => {
|
||||
|
||||
/** @public */
|
||||
export const Menu = (props: MenuProps<object>) => {
|
||||
const { classNames, cleanedProps } = useStyles(MenuDefinition, props);
|
||||
const {
|
||||
className,
|
||||
placement = 'bottom start',
|
||||
virtualized = false,
|
||||
maxWidth,
|
||||
maxHeight,
|
||||
style,
|
||||
...rest
|
||||
} = cleanedProps;
|
||||
const { ownProps, restProps } = useDefinition(MenuDefinition, props);
|
||||
const { classes, placement, virtualized, maxWidth, maxHeight, style } =
|
||||
ownProps;
|
||||
|
||||
let newMaxWidth = maxWidth || (virtualized ? '260px' : 'undefined');
|
||||
|
||||
const menuContent = (
|
||||
<RAMenu
|
||||
className={clsx(classNames.content, styles[classNames.content])}
|
||||
className={classes.content}
|
||||
renderEmptyState={() => <MenuEmptyState />}
|
||||
style={{ width: newMaxWidth, maxHeight, ...style }}
|
||||
{...rest}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<RoutingProvider>
|
||||
<RAPopover
|
||||
className={clsx(
|
||||
classNames.popover,
|
||||
styles[classNames.popover],
|
||||
className,
|
||||
)}
|
||||
placement={placement}
|
||||
>
|
||||
<RAPopover className={classes.root} placement={placement}>
|
||||
<BgReset>
|
||||
<Box
|
||||
bg="neutral"
|
||||
className={clsx(classNames.inner, styles[classNames.inner])}
|
||||
>
|
||||
<Box bg="neutral" className={classes.inner}>
|
||||
{virtualized ? (
|
||||
<Virtualizer
|
||||
layout={ListLayout}
|
||||
@@ -147,42 +134,31 @@ export const Menu = (props: MenuProps<object>) => {
|
||||
|
||||
/** @public */
|
||||
export const MenuListBox = (props: MenuListBoxProps<object>) => {
|
||||
const { classNames, cleanedProps } = useStyles(MenuDefinition, props);
|
||||
const { ownProps, restProps } = useDefinition(MenuListBoxDefinition, props);
|
||||
const {
|
||||
className,
|
||||
selectionMode = 'single',
|
||||
placement = 'bottom start',
|
||||
virtualized = false,
|
||||
classes,
|
||||
selectionMode,
|
||||
placement,
|
||||
virtualized,
|
||||
maxWidth,
|
||||
maxHeight,
|
||||
style,
|
||||
...rest
|
||||
} = cleanedProps;
|
||||
} = ownProps;
|
||||
let newMaxWidth = maxWidth || (virtualized ? '260px' : 'undefined');
|
||||
|
||||
const listBoxContent = (
|
||||
<RAListBox
|
||||
className={clsx(classNames.content, styles[classNames.content])}
|
||||
className={classes.content}
|
||||
selectionMode={selectionMode}
|
||||
style={{ width: newMaxWidth, maxHeight, ...style }}
|
||||
{...rest}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<RAPopover
|
||||
className={clsx(
|
||||
classNames.popover,
|
||||
styles[classNames.popover],
|
||||
className,
|
||||
)}
|
||||
placement={placement}
|
||||
>
|
||||
<RAPopover className={classes.root} placement={placement}>
|
||||
<BgReset>
|
||||
<Box
|
||||
bg="neutral"
|
||||
className={clsx(classNames.inner, styles[classNames.inner])}
|
||||
>
|
||||
<Box bg="neutral" className={classes.inner}>
|
||||
{virtualized ? (
|
||||
<Virtualizer
|
||||
layout={ListLayout}
|
||||
@@ -203,64 +179,46 @@ export const MenuListBox = (props: MenuListBoxProps<object>) => {
|
||||
|
||||
/** @public */
|
||||
export const MenuAutocomplete = (props: MenuAutocompleteProps<object>) => {
|
||||
const { classNames, cleanedProps } = useStyles(MenuDefinition, props);
|
||||
const { ownProps, restProps } = useDefinition(
|
||||
MenuAutocompleteDefinition,
|
||||
props,
|
||||
);
|
||||
const {
|
||||
className,
|
||||
placement = 'bottom start',
|
||||
virtualized = false,
|
||||
classes,
|
||||
placement,
|
||||
virtualized,
|
||||
maxWidth,
|
||||
maxHeight,
|
||||
style,
|
||||
...rest
|
||||
} = cleanedProps;
|
||||
placeholder,
|
||||
} = ownProps;
|
||||
const { contains } = useFilter({ sensitivity: 'base' });
|
||||
let newMaxWidth = maxWidth || (virtualized ? '260px' : 'undefined');
|
||||
|
||||
const menuContent = (
|
||||
<RAMenu
|
||||
className={clsx(classNames.content, styles[classNames.content])}
|
||||
className={classes.content}
|
||||
renderEmptyState={() => <MenuEmptyState />}
|
||||
style={{ width: newMaxWidth, maxHeight, ...style }}
|
||||
{...rest}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<RoutingProvider>
|
||||
<RAPopover
|
||||
className={clsx(
|
||||
classNames.popover,
|
||||
styles[classNames.popover],
|
||||
className,
|
||||
)}
|
||||
placement={placement}
|
||||
>
|
||||
<RAPopover className={classes.root} placement={placement}>
|
||||
<BgReset>
|
||||
<Box
|
||||
bg="neutral"
|
||||
className={clsx(classNames.inner, styles[classNames.inner])}
|
||||
>
|
||||
<Box bg="neutral" className={classes.inner}>
|
||||
<RAAutocomplete filter={contains}>
|
||||
<RASearchField
|
||||
className={clsx(
|
||||
classNames.searchField,
|
||||
styles[classNames.searchField],
|
||||
)}
|
||||
aria-label={props.placeholder || 'Search'}
|
||||
className={classes.searchField}
|
||||
aria-label={placeholder || 'Search'}
|
||||
>
|
||||
<RAInput
|
||||
className={clsx(
|
||||
classNames.searchFieldInput,
|
||||
styles[classNames.searchFieldInput],
|
||||
)}
|
||||
placeholder={props.placeholder || 'Search...'}
|
||||
className={classes.searchFieldInput}
|
||||
placeholder={placeholder || 'Search...'}
|
||||
/>
|
||||
<RAButton
|
||||
className={clsx(
|
||||
classNames.searchFieldClear,
|
||||
styles[classNames.searchFieldClear],
|
||||
)}
|
||||
>
|
||||
<RAButton className={classes.searchFieldClear}>
|
||||
<RiCloseCircleLine />
|
||||
</RAButton>
|
||||
</RASearchField>
|
||||
@@ -288,65 +246,47 @@ export const MenuAutocomplete = (props: MenuAutocompleteProps<object>) => {
|
||||
export const MenuAutocompleteListbox = (
|
||||
props: MenuAutocompleteListBoxProps<object>,
|
||||
) => {
|
||||
const { classNames, cleanedProps } = useStyles(MenuDefinition, props);
|
||||
const { ownProps, restProps } = useDefinition(
|
||||
MenuAutocompleteListboxDefinition,
|
||||
props,
|
||||
);
|
||||
const {
|
||||
className,
|
||||
selectionMode = 'single',
|
||||
placement = 'bottom start',
|
||||
virtualized = false,
|
||||
classes,
|
||||
selectionMode,
|
||||
placement,
|
||||
virtualized,
|
||||
maxWidth,
|
||||
maxHeight,
|
||||
style,
|
||||
...rest
|
||||
} = cleanedProps;
|
||||
placeholder,
|
||||
} = ownProps;
|
||||
const { contains } = useFilter({ sensitivity: 'base' });
|
||||
let newMaxWidth = maxWidth || (virtualized ? '260px' : 'undefined');
|
||||
|
||||
const listBoxContent = (
|
||||
<RAListBox
|
||||
className={clsx(classNames.content, styles[classNames.content])}
|
||||
className={classes.content}
|
||||
renderEmptyState={() => <MenuEmptyState />}
|
||||
selectionMode={selectionMode}
|
||||
style={{ width: newMaxWidth, maxHeight, ...style }}
|
||||
{...rest}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<RAPopover
|
||||
className={clsx(
|
||||
classNames.popover,
|
||||
styles[classNames.popover],
|
||||
className,
|
||||
)}
|
||||
placement={placement}
|
||||
>
|
||||
<RAPopover className={classes.root} placement={placement}>
|
||||
<BgReset>
|
||||
<Box
|
||||
bg="neutral"
|
||||
className={clsx(classNames.inner, styles[classNames.inner])}
|
||||
>
|
||||
<Box bg="neutral" className={classes.inner}>
|
||||
<RAAutocomplete filter={contains}>
|
||||
<RASearchField
|
||||
className={clsx(
|
||||
classNames.searchField,
|
||||
styles[classNames.searchField],
|
||||
)}
|
||||
aria-label={props.placeholder || 'Search'}
|
||||
className={classes.searchField}
|
||||
aria-label={placeholder || 'Search'}
|
||||
>
|
||||
<RAInput
|
||||
className={clsx(
|
||||
classNames.searchFieldInput,
|
||||
styles[classNames.searchFieldInput],
|
||||
)}
|
||||
placeholder={props.placeholder || 'Search...'}
|
||||
className={classes.searchFieldInput}
|
||||
placeholder={placeholder || 'Search...'}
|
||||
/>
|
||||
<RAButton
|
||||
className={clsx(
|
||||
classNames.searchFieldClear,
|
||||
styles[classNames.searchFieldClear],
|
||||
)}
|
||||
>
|
||||
<RAButton className={classes.searchFieldClear}>
|
||||
<RiCloseCircleLine />
|
||||
</RAButton>
|
||||
</RASearchField>
|
||||
@@ -371,15 +311,11 @@ export const MenuAutocompleteListbox = (
|
||||
|
||||
/** @public */
|
||||
export const MenuItem = (props: MenuItemProps) => {
|
||||
const { classNames, cleanedProps } = useStyles(MenuDefinition, props);
|
||||
const {
|
||||
className,
|
||||
iconStart,
|
||||
color = 'primary',
|
||||
children,
|
||||
href,
|
||||
...rest
|
||||
} = cleanedProps;
|
||||
const { ownProps, restProps, dataAttributes } = useDefinition(
|
||||
MenuItemDefinition,
|
||||
props,
|
||||
);
|
||||
const { classes, iconStart, children, href } = ownProps;
|
||||
|
||||
useRoutingRegistrationEffect(href);
|
||||
|
||||
@@ -387,30 +323,18 @@ export const MenuItem = (props: MenuItemProps) => {
|
||||
if (href && !isInternalLink(href)) {
|
||||
return (
|
||||
<RAMenuItem
|
||||
className={clsx(classNames.item, styles[classNames.item], className)}
|
||||
data-color={color}
|
||||
className={classes.root}
|
||||
{...dataAttributes}
|
||||
textValue={typeof children === 'string' ? children : undefined}
|
||||
onAction={() => window.open(href, '_blank', 'noopener,noreferrer')}
|
||||
{...rest}
|
||||
{...restProps}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
classNames.itemWrapper,
|
||||
styles[classNames.itemWrapper],
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
classNames.itemContent,
|
||||
styles[classNames.itemContent],
|
||||
)}
|
||||
>
|
||||
<div className={classes.itemWrapper}>
|
||||
<div className={classes.itemContent}>
|
||||
{iconStart}
|
||||
{children}
|
||||
</div>
|
||||
<div
|
||||
className={clsx(classNames.itemArrow, styles[classNames.itemArrow])}
|
||||
>
|
||||
<div className={classes.itemArrow}>
|
||||
<RiArrowRightSLine />
|
||||
</div>
|
||||
</div>
|
||||
@@ -420,27 +344,18 @@ export const MenuItem = (props: MenuItemProps) => {
|
||||
|
||||
return (
|
||||
<RAMenuItem
|
||||
className={clsx(classNames.item, styles[classNames.item], className)}
|
||||
data-color={color}
|
||||
className={classes.root}
|
||||
{...dataAttributes}
|
||||
href={href}
|
||||
textValue={typeof children === 'string' ? children : undefined}
|
||||
{...rest}
|
||||
{...restProps}
|
||||
>
|
||||
<div
|
||||
className={clsx(classNames.itemWrapper, styles[classNames.itemWrapper])}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
classNames.itemContent,
|
||||
styles[classNames.itemContent],
|
||||
)}
|
||||
>
|
||||
<div className={classes.itemWrapper}>
|
||||
<div className={classes.itemContent}>
|
||||
{iconStart}
|
||||
{children}
|
||||
</div>
|
||||
<div
|
||||
className={clsx(classNames.itemArrow, styles[classNames.itemArrow])}
|
||||
>
|
||||
<div className={classes.itemArrow}>
|
||||
<RiArrowRightSLine />
|
||||
</div>
|
||||
</div>
|
||||
@@ -450,36 +365,21 @@ export const MenuItem = (props: MenuItemProps) => {
|
||||
|
||||
/** @public */
|
||||
export const MenuListBoxItem = (props: MenuListBoxItemProps) => {
|
||||
const { classNames, cleanedProps } = useStyles(MenuDefinition, props);
|
||||
const { children, className, ...rest } = cleanedProps;
|
||||
const { ownProps, restProps } = useDefinition(
|
||||
MenuListBoxItemDefinition,
|
||||
props,
|
||||
);
|
||||
const { classes, children } = ownProps;
|
||||
|
||||
return (
|
||||
<RAListBoxItem
|
||||
textValue={
|
||||
typeof props.children === 'string' ? props.children : undefined
|
||||
}
|
||||
className={clsx(
|
||||
classNames.itemListBox,
|
||||
styles[classNames.itemListBox],
|
||||
className,
|
||||
)}
|
||||
{...rest}
|
||||
textValue={typeof children === 'string' ? children : undefined}
|
||||
className={classes.root}
|
||||
{...restProps}
|
||||
>
|
||||
<div
|
||||
className={clsx(classNames.itemWrapper, styles[classNames.itemWrapper])}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
classNames.itemContent,
|
||||
styles[classNames.itemContent],
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
classNames.itemListBoxCheck,
|
||||
styles[classNames.itemListBoxCheck],
|
||||
)}
|
||||
>
|
||||
<div className={classes.itemWrapper}>
|
||||
<div className={classes.itemContent}>
|
||||
<div className={classes.check}>
|
||||
<RiCheckLine />
|
||||
</div>
|
||||
{children}
|
||||
@@ -491,26 +391,12 @@ export const MenuListBoxItem = (props: MenuListBoxItemProps) => {
|
||||
|
||||
/** @public */
|
||||
export const MenuSection = (props: MenuSectionProps<object>) => {
|
||||
const { classNames, cleanedProps } = useStyles(MenuDefinition, props);
|
||||
const { children, className, title, ...rest } = cleanedProps;
|
||||
const { ownProps, restProps } = useDefinition(MenuSectionDefinition, props);
|
||||
const { classes, children, title } = ownProps;
|
||||
|
||||
return (
|
||||
<RAMenuSection
|
||||
className={clsx(
|
||||
classNames.section,
|
||||
styles[classNames.section],
|
||||
className,
|
||||
)}
|
||||
{...rest}
|
||||
>
|
||||
<RAMenuHeader
|
||||
className={clsx(
|
||||
classNames.sectionHeader,
|
||||
styles[classNames.sectionHeader],
|
||||
)}
|
||||
>
|
||||
{title}
|
||||
</RAMenuHeader>
|
||||
<RAMenuSection className={classes.root} {...restProps}>
|
||||
<RAMenuHeader className={classes.header}>{title}</RAMenuHeader>
|
||||
{children}
|
||||
</RAMenuSection>
|
||||
);
|
||||
@@ -518,17 +404,7 @@ export const MenuSection = (props: MenuSectionProps<object>) => {
|
||||
|
||||
/** @public */
|
||||
export const MenuSeparator = (props: MenuSeparatorProps) => {
|
||||
const { classNames, cleanedProps } = useStyles(MenuDefinition, props);
|
||||
const { className, ...rest } = cleanedProps;
|
||||
const { ownProps, restProps } = useDefinition(MenuSeparatorDefinition, props);
|
||||
|
||||
return (
|
||||
<RAMenuSeparator
|
||||
className={clsx(
|
||||
classNames.separator,
|
||||
styles[classNames.separator],
|
||||
className,
|
||||
)}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
return <RAMenuSeparator className={ownProps.classes.root} {...restProps} />;
|
||||
};
|
||||
|
||||
@@ -14,30 +14,172 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { ComponentDefinition } from '../../types';
|
||||
import { defineComponent } from '../../hooks/useDefinition';
|
||||
import type {
|
||||
MenuOwnProps,
|
||||
MenuListBoxOwnProps,
|
||||
MenuAutocompleteOwnProps,
|
||||
MenuAutocompleteListBoxOwnProps,
|
||||
MenuItemOwnProps,
|
||||
MenuListBoxItemOwnProps,
|
||||
MenuSectionOwnProps,
|
||||
MenuSeparatorOwnProps,
|
||||
} from './types';
|
||||
import styles from './Menu.module.css';
|
||||
|
||||
/**
|
||||
* Component definition for Menu
|
||||
* @public
|
||||
*/
|
||||
export const MenuDefinition = {
|
||||
export const MenuDefinition = defineComponent<MenuOwnProps>()({
|
||||
styles,
|
||||
classNames: {
|
||||
root: 'bui-Menu',
|
||||
popover: 'bui-MenuPopover',
|
||||
root: 'bui-MenuPopover',
|
||||
inner: 'bui-MenuInner',
|
||||
content: 'bui-MenuContent',
|
||||
section: 'bui-MenuSection',
|
||||
sectionHeader: 'bui-MenuSectionHeader',
|
||||
item: 'bui-MenuItem',
|
||||
itemListBox: 'bui-MenuItemListBox',
|
||||
itemListBoxCheck: 'bui-MenuItemListBoxCheck',
|
||||
},
|
||||
propDefs: {
|
||||
placement: { default: 'bottom start' },
|
||||
virtualized: { default: false },
|
||||
maxWidth: {},
|
||||
maxHeight: {},
|
||||
style: {},
|
||||
className: {},
|
||||
},
|
||||
});
|
||||
|
||||
/** @internal */
|
||||
export const MenuListBoxDefinition = defineComponent<MenuListBoxOwnProps>()({
|
||||
styles,
|
||||
classNames: {
|
||||
root: 'bui-MenuPopover',
|
||||
inner: 'bui-MenuInner',
|
||||
content: 'bui-MenuContent',
|
||||
},
|
||||
propDefs: {
|
||||
placement: { default: 'bottom start' },
|
||||
selectionMode: { default: 'single' },
|
||||
virtualized: { default: false },
|
||||
maxWidth: {},
|
||||
maxHeight: {},
|
||||
style: {},
|
||||
className: {},
|
||||
},
|
||||
});
|
||||
|
||||
/** @internal */
|
||||
export const MenuAutocompleteDefinition =
|
||||
defineComponent<MenuAutocompleteOwnProps>()({
|
||||
styles,
|
||||
classNames: {
|
||||
root: 'bui-MenuPopover',
|
||||
inner: 'bui-MenuInner',
|
||||
content: 'bui-MenuContent',
|
||||
searchField: 'bui-MenuSearchField',
|
||||
searchFieldInput: 'bui-MenuSearchFieldInput',
|
||||
searchFieldClear: 'bui-MenuSearchFieldClear',
|
||||
},
|
||||
propDefs: {
|
||||
placeholder: {},
|
||||
placement: { default: 'bottom start' },
|
||||
virtualized: { default: false },
|
||||
maxWidth: {},
|
||||
maxHeight: {},
|
||||
style: {},
|
||||
className: {},
|
||||
},
|
||||
});
|
||||
|
||||
/** @internal */
|
||||
export const MenuAutocompleteListboxDefinition =
|
||||
defineComponent<MenuAutocompleteListBoxOwnProps>()({
|
||||
styles,
|
||||
classNames: {
|
||||
root: 'bui-MenuPopover',
|
||||
inner: 'bui-MenuInner',
|
||||
content: 'bui-MenuContent',
|
||||
searchField: 'bui-MenuSearchField',
|
||||
searchFieldInput: 'bui-MenuSearchFieldInput',
|
||||
searchFieldClear: 'bui-MenuSearchFieldClear',
|
||||
},
|
||||
propDefs: {
|
||||
placeholder: {},
|
||||
placement: { default: 'bottom start' },
|
||||
selectionMode: { default: 'single' },
|
||||
virtualized: { default: false },
|
||||
maxWidth: {},
|
||||
maxHeight: {},
|
||||
style: {},
|
||||
className: {},
|
||||
},
|
||||
});
|
||||
|
||||
/** @internal */
|
||||
export const MenuItemDefinition = defineComponent<MenuItemOwnProps>()({
|
||||
styles,
|
||||
classNames: {
|
||||
root: 'bui-MenuItem',
|
||||
itemWrapper: 'bui-MenuItemWrapper',
|
||||
itemContent: 'bui-MenuItemContent',
|
||||
itemArrow: 'bui-MenuItemArrow',
|
||||
separator: 'bui-MenuSeparator',
|
||||
searchField: 'bui-MenuSearchField',
|
||||
searchFieldInput: 'bui-MenuSearchFieldInput',
|
||||
searchFieldClear: 'bui-MenuSearchFieldClear',
|
||||
emptyState: 'bui-MenuEmptyState',
|
||||
},
|
||||
} as const satisfies ComponentDefinition;
|
||||
propDefs: {
|
||||
iconStart: {},
|
||||
children: {},
|
||||
color: { dataAttribute: true, default: 'primary' },
|
||||
href: {},
|
||||
className: {},
|
||||
},
|
||||
});
|
||||
|
||||
/** @internal */
|
||||
export const MenuListBoxItemDefinition =
|
||||
defineComponent<MenuListBoxItemOwnProps>()({
|
||||
styles,
|
||||
classNames: {
|
||||
root: 'bui-MenuItemListBox',
|
||||
itemWrapper: 'bui-MenuItemWrapper',
|
||||
itemContent: 'bui-MenuItemContent',
|
||||
check: 'bui-MenuItemListBoxCheck',
|
||||
},
|
||||
propDefs: {
|
||||
children: {},
|
||||
className: {},
|
||||
},
|
||||
});
|
||||
|
||||
/** @internal */
|
||||
export const MenuSectionDefinition = defineComponent<MenuSectionOwnProps>()({
|
||||
styles,
|
||||
classNames: {
|
||||
root: 'bui-MenuSection',
|
||||
header: 'bui-MenuSectionHeader',
|
||||
},
|
||||
propDefs: {
|
||||
title: {},
|
||||
children: {},
|
||||
className: {},
|
||||
},
|
||||
});
|
||||
|
||||
/** @internal */
|
||||
export const MenuSeparatorDefinition = defineComponent<MenuSeparatorOwnProps>()(
|
||||
{
|
||||
styles,
|
||||
classNames: {
|
||||
root: 'bui-MenuSeparator',
|
||||
},
|
||||
propDefs: {
|
||||
className: {},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
/** @internal */
|
||||
export const MenuEmptyStateDefinition = defineComponent<{}>()({
|
||||
styles,
|
||||
classNames: {
|
||||
root: 'bui-MenuEmptyState',
|
||||
},
|
||||
propDefs: {},
|
||||
});
|
||||
|
||||
@@ -31,11 +31,19 @@ export type {
|
||||
MenuTriggerProps,
|
||||
SubmenuTriggerProps,
|
||||
MenuProps,
|
||||
MenuOwnProps,
|
||||
MenuListBoxProps,
|
||||
MenuListBoxOwnProps,
|
||||
MenuAutocompleteProps,
|
||||
MenuAutocompleteOwnProps,
|
||||
MenuAutocompleteListBoxProps,
|
||||
MenuAutocompleteListBoxOwnProps,
|
||||
MenuItemProps,
|
||||
MenuItemOwnProps,
|
||||
MenuListBoxItemProps,
|
||||
MenuListBoxItemOwnProps,
|
||||
MenuSectionProps,
|
||||
MenuSectionOwnProps,
|
||||
MenuSeparatorProps,
|
||||
MenuSeparatorOwnProps,
|
||||
} from './types';
|
||||
|
||||
@@ -33,70 +33,112 @@ export interface MenuTriggerProps extends RAMenuTriggerProps {}
|
||||
export interface SubmenuTriggerProps extends RAMenuSubmenuTriggerProps {}
|
||||
|
||||
/** @public */
|
||||
export interface MenuProps<T>
|
||||
extends RAMenuProps<T>,
|
||||
Omit<RAMenuProps<T>, 'children'> {
|
||||
export type MenuOwnProps = {
|
||||
placement?: RAPopoverProps['placement'];
|
||||
virtualized?: boolean;
|
||||
maxWidth?: string;
|
||||
maxHeight?: string;
|
||||
}
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export interface MenuProps<T>
|
||||
extends MenuOwnProps,
|
||||
Omit<RAMenuProps<T>, keyof MenuOwnProps> {}
|
||||
|
||||
/** @public */
|
||||
export type MenuListBoxOwnProps = {
|
||||
placement?: RAPopoverProps['placement'];
|
||||
selectionMode?: RAListBoxProps<object>['selectionMode'];
|
||||
virtualized?: boolean;
|
||||
maxWidth?: string;
|
||||
maxHeight?: string;
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export interface MenuListBoxProps<T>
|
||||
extends RAListBoxProps<T>,
|
||||
Omit<RAListBoxProps<T>, 'children'> {
|
||||
extends MenuListBoxOwnProps,
|
||||
Omit<RAListBoxProps<T>, keyof MenuListBoxOwnProps> {}
|
||||
|
||||
/** @public */
|
||||
export type MenuAutocompleteOwnProps = {
|
||||
placeholder?: string;
|
||||
placement?: RAPopoverProps['placement'];
|
||||
virtualized?: boolean;
|
||||
maxWidth?: string;
|
||||
maxHeight?: string;
|
||||
}
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export interface MenuAutocompleteProps<T>
|
||||
extends RAMenuProps<T>,
|
||||
Omit<RAMenuProps<T>, 'children'> {
|
||||
extends MenuAutocompleteOwnProps,
|
||||
Omit<RAMenuProps<T>, keyof MenuAutocompleteOwnProps> {}
|
||||
|
||||
/** @public */
|
||||
export type MenuAutocompleteListBoxOwnProps = {
|
||||
placeholder?: string;
|
||||
placement?: RAPopoverProps['placement'];
|
||||
selectionMode?: RAListBoxProps<object>['selectionMode'];
|
||||
virtualized?: boolean;
|
||||
maxWidth?: string;
|
||||
maxHeight?: string;
|
||||
}
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export interface MenuAutocompleteListBoxProps<T>
|
||||
extends RAListBoxProps<T>,
|
||||
Omit<RAListBoxProps<T>, 'children'> {
|
||||
placeholder?: string;
|
||||
placement?: RAPopoverProps['placement'];
|
||||
virtualized?: boolean;
|
||||
maxWidth?: string;
|
||||
maxHeight?: string;
|
||||
}
|
||||
extends MenuAutocompleteListBoxOwnProps,
|
||||
Omit<RAListBoxProps<T>, keyof MenuAutocompleteListBoxOwnProps> {}
|
||||
|
||||
/** @public */
|
||||
export interface MenuItemProps
|
||||
extends RAMenuItemProps,
|
||||
Omit<RAMenuItemProps, 'children'> {
|
||||
export type MenuItemOwnProps = {
|
||||
iconStart?: React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
color?: 'primary' | 'danger';
|
||||
}
|
||||
href?: RAMenuItemProps['href'];
|
||||
className?: string;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export interface MenuItemProps
|
||||
extends MenuItemOwnProps,
|
||||
Omit<RAMenuItemProps, keyof MenuItemOwnProps> {}
|
||||
|
||||
/** @public */
|
||||
export type MenuListBoxItemOwnProps = {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export interface MenuListBoxItemProps
|
||||
extends RAListBoxItemProps,
|
||||
Omit<RAListBoxItemProps, 'children'> {
|
||||
extends MenuListBoxItemOwnProps,
|
||||
Omit<RAListBoxItemProps, keyof MenuListBoxItemOwnProps> {}
|
||||
|
||||
/** @public */
|
||||
export type MenuSectionOwnProps = {
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
className?: string;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export interface MenuSectionProps<T>
|
||||
extends RAMenuSectionProps<T>,
|
||||
Omit<RAMenuSectionProps<T>, 'children'> {
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
extends MenuSectionOwnProps,
|
||||
Omit<RAMenuSectionProps<T>, keyof MenuSectionOwnProps> {}
|
||||
|
||||
/** @public */
|
||||
export interface MenuSeparatorProps extends RAMenuSeparatorProps {}
|
||||
export type MenuSeparatorOwnProps = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export interface MenuSeparatorProps
|
||||
extends MenuSeparatorOwnProps,
|
||||
Omit<RAMenuSeparatorProps, keyof MenuSeparatorOwnProps> {}
|
||||
|
||||
Reference in New Issue
Block a user