diff --git a/.changeset/wicked-dancers-end.md b/.changeset/wicked-dancers-end.md new file mode 100644 index 00000000000..1efa6fe3c9b --- /dev/null +++ b/.changeset/wicked-dancers-end.md @@ -0,0 +1,18 @@ +--- +'braid-design-system': minor +--- + +--- +updated: + - MenuRenderer +--- + +**MenuRenderer:** Add `small` size. + +Introduce a new `small` size for the `MenuRenderer` component. +This is available via the `size` prop, which supports the existing `standard` (default) and `small`. + +**EXAMPLE USAGE:** +```jsx + +``` diff --git a/packages/braid-design-system/src/lib/components/MenuItem/MenuItem.screenshots.tsx b/packages/braid-design-system/src/lib/components/MenuItem/MenuItem.screenshots.tsx index 467f40407e1..c1bafd4f1de 100644 --- a/packages/braid-design-system/src/lib/components/MenuItem/MenuItem.screenshots.tsx +++ b/packages/braid-design-system/src/lib/components/MenuItem/MenuItem.screenshots.tsx @@ -14,6 +14,7 @@ import { Menu } from '../MenuRenderer/MenuRenderer'; const defaultProps = { offsetSpace: 'none', align: 'left', + size: 'standard', width: 'content', highlightIndex: -1, open: true, diff --git a/packages/braid-design-system/src/lib/components/MenuItem/useMenuItem.tsx b/packages/braid-design-system/src/lib/components/MenuItem/useMenuItem.tsx index 3bfb8e1ae77..320c6309fc2 100644 --- a/packages/braid-design-system/src/lib/components/MenuItem/useMenuItem.tsx +++ b/packages/braid-design-system/src/lib/components/MenuItem/useMenuItem.tsx @@ -11,7 +11,6 @@ import React, { import type { BadgeProps } from '../Badge/Badge'; import { type BoxProps, Box } from '../Box/Box'; import { Text } from '../Text/Text'; -import { touchableText } from '../../css/typography.css'; import { normalizeKey } from '../private/normalizeKey'; import { MenuRendererItemContext } from '../MenuRenderer/MenuRendererItemContext'; import { type Action, actionTypes } from '../MenuRenderer/MenuRenderer.actions'; @@ -25,6 +24,7 @@ import { MenuRendererContext } from '../MenuRenderer/MenuRendererContext'; import { useBraidTheme } from '../BraidProvider/BraidThemeContext'; import { iconSlotSpace } from '../private/iconSlotSpace'; import { badgeSlotSpace } from '../private/badgeSlotSpace'; +import { virtualTouchable } from '../private/touchable/virtualTouchable.css'; const { MENU_ITEM_UP, @@ -37,8 +37,6 @@ const { MENU_ITEM_HOVER, } = actionTypes; -const menuItemChildrenSize = 'standard'; - type MenuItemTone = 'critical' | undefined; export interface UseMenuItemProps { @@ -58,10 +56,11 @@ export function useMenuItem({ id, ...restProps }: UseMenuItemProps) { + const menuRendererContext = useContext(MenuRendererContext); const menuRendererItemContext = useContext(MenuRendererItemContext); assert( - menuRendererItemContext !== null, + menuRendererContext !== null && menuRendererItemContext !== null, `${displayName} must be rendered as an immediate child of a menu. See the documentation for correct usage: https://seek-oss.github.io/braid-design-system/components/MenuItem`, ); @@ -69,6 +68,7 @@ export function useMenuItem({ throw new Error(`${displayName} element rendered outside menu context`); } + const { size } = menuRendererContext; const { isHighlighted, index, dispatch, focusTrigger } = menuRendererItemContext; const menuItemRef = useRef(null); @@ -155,11 +155,14 @@ export function useMenuItem({ background: isHighlighted ? hoverBackground : undefined, className: [ styles.menuItem, - touchableText[menuItemChildrenSize], + size === 'small' ? virtualTouchable : undefined, atoms({ - display: 'block', + display: 'flex', + alignItems: 'center', width: 'full', - paddingX: 'small', + paddingX: size === 'standard' ? 'small' : 'small', // todo - with 'small' size - small or xsmall? + paddingY: size === 'standard' ? undefined : 'xsmall', + height: size === 'standard' ? 'touchable' : undefined, cursor: 'pointer', textAlign: 'left', outline: 'none', @@ -200,25 +203,18 @@ function MenuItemChildren({ `MenuItem badge prop can only be an instance of Badge. e.g. New}>`, ); - let leftSlot: ReactNode = null; + const { size, reserveIconSpace } = menuRendererContext; - if (!formElement) { - if (icon) { - leftSlot = ( - - {icon} - - ); - } else if (menuRendererContext.reserveIconSpace) { - leftSlot = ( - - ); - } - } + const leftSlot = + !formElement && (icon || reserveIconSpace) ? ( + + {icon || ( + +   + + )} + + ) : null; return ( @@ -234,8 +230,7 @@ function MenuItemChildren({ ) : null} diff --git a/packages/braid-design-system/src/lib/components/MenuItemCheckbox/MenuItemCheckbox.screenshots.tsx b/packages/braid-design-system/src/lib/components/MenuItemCheckbox/MenuItemCheckbox.screenshots.tsx index dd16b6cd5d1..dedd0cd2058 100644 --- a/packages/braid-design-system/src/lib/components/MenuItemCheckbox/MenuItemCheckbox.screenshots.tsx +++ b/packages/braid-design-system/src/lib/components/MenuItemCheckbox/MenuItemCheckbox.screenshots.tsx @@ -6,6 +6,7 @@ import { Menu } from '../MenuRenderer/MenuRenderer'; const defaultProps = { offsetSpace: 'none', align: 'left', + size: 'standard', width: 'content', highlightIndex: -1, open: true, diff --git a/packages/braid-design-system/src/lib/components/MenuItemDivider/MenuItemDivider.screenshots.tsx b/packages/braid-design-system/src/lib/components/MenuItemDivider/MenuItemDivider.screenshots.tsx index b6a7f88fc1d..09958a36faf 100644 --- a/packages/braid-design-system/src/lib/components/MenuItemDivider/MenuItemDivider.screenshots.tsx +++ b/packages/braid-design-system/src/lib/components/MenuItemDivider/MenuItemDivider.screenshots.tsx @@ -6,6 +6,7 @@ import { Menu } from '../MenuRenderer/MenuRenderer'; const defaultProps = { offsetSpace: 'none', align: 'left', + size: 'standard', width: 'content', highlightIndex: -1, open: true, diff --git a/packages/braid-design-system/src/lib/components/MenuItemDivider/MenuItemDivider.tsx b/packages/braid-design-system/src/lib/components/MenuItemDivider/MenuItemDivider.tsx index 275cedc1b43..bd1683bd282 100644 --- a/packages/braid-design-system/src/lib/components/MenuItemDivider/MenuItemDivider.tsx +++ b/packages/braid-design-system/src/lib/components/MenuItemDivider/MenuItemDivider.tsx @@ -3,6 +3,7 @@ import React, { useContext } from 'react'; import { Box } from '../Box/Box'; import { Divider } from '../Divider/Divider'; import { MenuRendererContext } from '../MenuRenderer/MenuRendererContext'; +import { menuYPadding } from '../MenuRenderer/MenuRenderer.css'; export const MenuItemDivider = () => { assert( @@ -11,7 +12,7 @@ export const MenuItemDivider = () => { ); return ( - + ); diff --git a/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.css.ts b/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.css.ts index d9dd10770f5..5176d72e584 100644 --- a/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.css.ts +++ b/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.css.ts @@ -7,6 +7,8 @@ import { import { calc } from '@vanilla-extract/css-utils'; import { vars } from '../../themes/vars.css'; +export const menuYPadding = 'xxsmall'; + export const backdrop = style({ width: '100vw', height: '100vh', @@ -48,5 +50,8 @@ export const width = styleVariants({ small, medium, large }, (w) => [ ]); export const menuHeightLimit = style({ - maxHeight: calc(vars.touchableSize).multiply(9.5).toString(), + maxHeight: calc(vars.touchableSize) + .multiply(9.5) + .add(calc(vars.space[menuYPadding]).multiply(2)) + .toString(), }); diff --git a/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.docs.tsx b/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.docs.tsx index 8a45b76dcfc..b207984c8e8 100644 --- a/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.docs.tsx +++ b/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.docs.tsx @@ -173,6 +173,62 @@ const docs: ComponentDocs = { , ), }, + { + label: 'Sizes', + description: ( + + You can customise the size of the menu via the size{' '} + prop, which accepts either standard or{' '} + small. When using a small trigger + element, it is recommended to use the small size for + menu. + + ), + Example: () => + source( + + + ( + + + Standard trigger{' '} + + + + )} + > + {}}>Button + Link + + + + ( + + + Small trigger{' '} + + + + )} + > + {}}>Button + Link + + + , + ), + }, { label: 'Width', description: ( diff --git a/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.screenshots.tsx b/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.screenshots.tsx index 8220212bd79..10eda9ca281 100644 --- a/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.screenshots.tsx +++ b/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.screenshots.tsx @@ -18,6 +18,7 @@ import { calc } from '@vanilla-extract/css-utils'; const defaultProps = { offsetSpace: 'none', align: 'left', + size: 'standard', width: 'content', highlightIndex: -1, open: true, diff --git a/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.tsx b/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.tsx index 17adb7412be..828408195bb 100644 --- a/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.tsx +++ b/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.tsx @@ -26,6 +26,7 @@ import buildDataAttributes, { import * as styles from './MenuRenderer.css'; import { BraidPortal } from '../BraidPortal/BraidPortal'; import { assignInlineVars } from '@vanilla-extract/dynamic'; +import type { MenuSize } from './MenuRendererTypes'; interface TriggerProps { 'aria-haspopup': boolean; @@ -51,6 +52,7 @@ export interface MenuRendererProps { trigger: (props: TriggerProps, state: TriggerState) => ReactNode; align?: 'left' | 'right'; offsetSpace?: ResponsiveSpace; + size?: MenuSize; width?: keyof typeof styles.width | 'content'; placement?: 'top' | 'bottom'; onOpen?: () => void; @@ -118,6 +120,7 @@ export const MenuRenderer = ({ onOpen, onClose, trigger, + size = 'standard', width = 'content', align = 'left', offsetSpace = 'none', @@ -344,6 +347,7 @@ export const MenuRenderer = ({ ; align: NonNullable; + size: NonNullable; width: NonNullable; placement: NonNullable; reserveIconSpace: NonNullable; @@ -399,6 +404,7 @@ interface MenuProps { export function Menu({ offsetSpace, align, + size, width, placement, children, @@ -419,7 +425,7 @@ export function Menu({ }); return ( - + - - + + {Children.map(children, (item, i) => { if (isDivider(item)) { dividerCount++; diff --git a/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRendererContext.ts b/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRendererContext.ts index 0863dafe3c8..23652c85e66 100644 --- a/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRendererContext.ts +++ b/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRendererContext.ts @@ -1,6 +1,8 @@ import { createContext } from 'react'; +import type { MenuSize } from './MenuRendererTypes'; interface MenuRendererValues { + size: MenuSize; reserveIconSpace: boolean; } diff --git a/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRendererTypes.ts b/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRendererTypes.ts new file mode 100644 index 00000000000..9eefd4ebfa3 --- /dev/null +++ b/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRendererTypes.ts @@ -0,0 +1,2 @@ +// todo - move to existing file +export type MenuSize = 'standard' | 'small'; diff --git a/packages/braid-design-system/src/lib/components/OverflowMenu/OverflowMenu.tsx b/packages/braid-design-system/src/lib/components/OverflowMenu/OverflowMenu.tsx index 2384676f89d..124bc694b70 100644 --- a/packages/braid-design-system/src/lib/components/OverflowMenu/OverflowMenu.tsx +++ b/packages/braid-design-system/src/lib/components/OverflowMenu/OverflowMenu.tsx @@ -9,7 +9,10 @@ import { Box } from '../Box/Box'; import * as styles from './OverflowMenu.css'; export interface OverflowMenuProps - extends Omit { + extends Omit< + MenuRendererProps, + 'size' | 'trigger' | 'align' | 'offsetSpace' + > { label: string; id?: string; } diff --git a/packages/generate-component-docs/src/__snapshots__/contract.test.ts.snap b/packages/generate-component-docs/src/__snapshots__/contract.test.ts.snap index b475df0574a..a318e88abe4 100644 --- a/packages/generate-component-docs/src/__snapshots__/contract.test.ts.snap +++ b/packages/generate-component-docs/src/__snapshots__/contract.test.ts.snap @@ -7418,6 +7418,9 @@ exports[`MenuRenderer 1`] = ` | "bottom" | "top" reserveIconSpace?: boolean + size?: + | "small" + | "standard" trigger: (props: TriggerProps, state: TriggerState) => ReactNode width?: | "content"