Skip to content

Commit

Permalink
docs: add docs for menu and useContextMenu (#13209)
Browse files Browse the repository at this point in the history
* docs(menu): add docs

* docs(useContextMenu): add docs

* docs(useContextMenu): clarify that react refs can also be passed

* docs(useContextMenu): update live demo meta

* docs(menu): add live demo meta

---------

Co-authored-by: Andrea N. Cardona <cardona.n.andrea@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
3 people committed Feb 24, 2023
1 parent d791865 commit 495cfe3
Show file tree
Hide file tree
Showing 6 changed files with 281 additions and 6 deletions.
6 changes: 1 addition & 5 deletions packages/react/src/components/ContextMenu/docs/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@
variants={[
{
label: 'Default',
variant: 'experimental-unstable-menu-contextmenu--context-menu'
variant: 'experimental-unstable-usecontextmenu--use-context-menu'
},
{
label: 'Multiple Groups',
variant: 'experimental-unstable-menu-contextmenu--multiple-groups'
}
]}
/>
65 changes: 65 additions & 0 deletions packages/react/src/components/ContextMenu/useContextMenu.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { ArgsTable, Canvas, Story } from '@storybook/addon-docs';

# useContextMenu

[Source code](https://github.com/carbon-design-system/carbon/tree/main/packages/react/src/components/Menu)

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Overview](#overview)
- [Component API](#component-api)
- [Feedback](#feedback)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Overview

The `useContextMenu` hook is meant to be used in conjunction with `Menu` (see this [component's documentation](http://localhost:3000/?path=/docs/experimental-unstable-menu--playground) for more details). It provides an easy way to generate the necessary props for `Menu`.

By default, it will listen to the `contextmenu` event on `document`. In most cases you'll want to restrict a context menu to a certain element or group of elements only. You can pass that element as the argument for `useContextMenu`.

```jsx
function SomeComponent() {
const el = useRef(null);
const menuProps = useContextMenu(el);

return (
<>
<div ref={el}>
</div>

<Menu {...menuProps}>
<MenuItem label="Cut" />
<MenuItem label="Copy" />
<MenuItem label="Paste" />
</Menu>
</>
);
}
```

Be aware that the following props are not set by `useContextMenu` and can therefore be configured by the user:
- className
- label
- size
- target

## Component API

```js
// returns an object with 'x', 'y', 'open' and 'onClose' set accordingly intended
// to be passed as pros to the <Menu> component.
const menuProps = useContextMenu(
// the DOM element or react ref the "contextmenu" event should be attached to.
// defaults to document.
trigger,
);
```

## Feedback

Help us improve this component by providing feedback, asking questions on Slack,
or updating this file on
[GitHub](https://github.com/carbon-design-system/carbon/edit/main/packages/react/src/components/ContextMenu/useContextMenu.mdx).
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,27 @@
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';
import React, { useRef } from 'react';
import { action } from '@storybook/addon-actions';

import { usePrefix } from '../../internal/usePrefix';
import CodeSnippet from '../CodeSnippet';
import UnorderedList from '../UnorderedList';
import ListItem from '../ListItem';

import { Menu, MenuItem, MenuItemDivider, MenuItemRadioGroup } from '../Menu';

import { useContextMenu } from './';
import mdx from './useContextMenu.mdx';

export default {
title: 'Experimental/unstable__useContextMenu',
component: useContextMenu,
parameters: {
docs: {
page: mdx,
},
},
};

const Text = () => (
Expand Down Expand Up @@ -88,3 +95,29 @@ export const _useContextMenu = () => {
</>
);
};

export const SpecificElement = () => {
const prefix = usePrefix();

const el = useRef(null);
const menuProps = useContextMenu(el);

return (
<>
<div
ref={el}
style={{
cursor: 'context-menu',
display: 'inline',
padding: '0.5rem 1rem',
backgroundColor: `var(--${prefix}-layer-01)`,
}}>
Right click this element
</div>
<Menu {...menuProps}>
<MenuItem label="Edit" />
<MenuItem label="Delete" kind="danger" />
</Menu>
</>
);
};
162 changes: 162 additions & 0 deletions packages/react/src/components/Menu/Menu.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { ArgsTable, Canvas, Story } from '@storybook/addon-docs';

# Menu

[Source code](https://github.com/carbon-design-system/carbon/tree/main/packages/react/src/components/Menu)

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Overview](#overview)
- [Positioning](#positioning)
- [Subcomponents](#subcomponents)
- [MenuItem](#menuitem)
- [MenuItemDivider](#menuitemdivider)
- [MenuItemGroup](#menuitemgroup)
- [MenuItemSelectable](#menuitemselectable)
- [MenuItemRadioGroup](#menuitemradiogroup)
- [Context menu (right-click menu)](#context-menu-right-click-menu)
- [Component API](#component-api)
- [Feedback](#feedback)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Overview

`Menu` is a versatile component that can be used in a variety of situations. It implements the [menu design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menubar/) defined in the ARIA Authoring Practices Guide (APG).

The `Menu` component's `children` must be a collection of any of these subcomponents:
- [MenuItem](#menuitem)
- [MenuItemDivider](#menuitemdivider)
- [MenuItemGroup](#menuitemgroup)
- [MenuItemSelectable](#menuitemselectable)
- [MenuItemRadioGroup](#menuitemradiogroup)

## Positioning

You must provide a reference point for the `Menu` to position itself at. The props `x` and `y` either accept a single number each or an array of two numbers.

The latter option is used to specify the trigger boundaries. For example, Carbon uses this for the [OverflowMenuV2](http://localhost:3000/?path=/story/experimental-unstable-overflowmenuv2--overflow-menu-v-2) where it passes `[x, x + width]` and `[y, y + height]` of the trigger button. This way, the `Menu` is able to automatically determine its ideal position on the screen (which side to open at and in which direction) while always staying visually attached to the trigger.
Each `MenuItem` that has `children` and therfore a submenu uses the same approach under the hood to correctly position the submenu.

## Subcomponents

### MenuItem

A `MenuItem` renders a basic menu item with a label an optionally a shortcut hint (_note: the component only renders this hint and doesn't actually register the shortcut in the browser_). Each `MenuItem` can be clicked unless it's marked as `disabled`. If it triggers a destructive action, you can pass it `kind="danger"` to highlight it specially on hover and focus.

```jsx
<Menu>
<MenuItem label="Copy" shortcut="⌘C" />
<MenuItem label="Paste" shortcut="⌘V" disabled />
<MenuItem label="Delete" kind="danger" />
</Menu>
```
In order to render a submenu, you can pass any of the above mentioned subcomponents as `children` of a `MenuItem`.
```jsx
<Menu>
<MenuItem label="Open" />
<MenuItem label="Save" />
<MenuItem label="Import">
<MenuItem label="Image">
<MenuItem label="Movie">
<MenuItem label="Text">
</MenuItem>
</Menu>
```

### MenuItemDivider

The `MenuItemDivider` renders a thin dividing line, visually separating menu items. Use this to enhance grouping of related items.

```jsx
<Menu>
<MenuItem label="Cut" />
<MenuItem label="Copy" />
<MenuItem label="Paste" />
<MenuItemDivider />
<MenuItem label="Delete" kind="danger" />
</Menu>
```

### MenuItemGroup

You can logically group multiple menu items by wrapping them inside a `MenuItemGroup`. This doesn't affect the visual rendering but can tremendously improve the experience for assistive technology users. You'll always want to use a `MenuItemGroup` if you have multiple [`MenuItemSelectable`](#menuitemselectable) that are relatd to each other.

### MenuItemSelectable

`MenuItemSelectable` is a checkbox in a menu context. Each `MenuItemSelectable` can be checked and unchecked unrelated to other items. If multiple items are related to each other, you'll want to wrap them in a `MenuItemGroup` for improved accessibility.

```jsx
<Menu>
<MenuItemGroup label="Font style">
<MenuItemSelectable label="Bold" selected />
<MenuItemSelectable label="Italic" />
</MenuItemGroup>
</Menu>
```

### MenuItemRadioGroup
`MenuItemRadioGroup` is a radio button group in a menu context. Only one item can be selected at a time. The component automatically wraps itself in a `MenuItemGroup`, so you won't have to nest it manually.

```jsx
<Menu>
<MenuItemRadioGroup
label="Font family"
items={[
'Sans',
'Serif',
'Mono',
]}
selectedItem="Sans"
/>
<MenuItemDivider />
<MenuItemRadioGroup
label="Text decoration"
items={[
'None',
'Overline',
'Line-through',
'Underline',
]}
selectedItem="None"
/>
</Menu>
```

The `items` prop is designed to accept arbitrary items to best match your data structure. If you pass your items as anything that doesn't support `.toString()` out of the box, you'll need to pass a custom `itemToString` function that will be used for rendering the labels.

```jsx
const items = [
{ weight: 100, label: 'Thin' },
{ weight: 200, label: 'Extralight' },
{ weight: 300, label: 'Light' },
{ weight: 400, label: 'Regular' },
{ weight: 500, label: 'Medium' },
{ weight: 600, label: 'Semibold' },
{ weight: 700, label: 'Bold' },
];

<MenuItemRadioGroup
label="Font weight"
items={items}
selectedItem={items[3]}
itemToString={(item) => item.label}
/>
```

## Context menu (right-click menu)

The `Menu` component is suited to be used as a context menu for complex web applications. To make this easy, Carbon provides a [`useContextMenu`](http://localhost:3000/?path=/story/experimental-unstable-usecontextmenu--use-context-menu) react hook. Please refer to the [hook's documentation](http://localhost:3000/?path=/docs/experimental-unstable-usecontextmenu--use-context-menu) for more details.

## Component API

<ArgsTable />

## Feedback

Help us improve this component by providing feedback, asking questions on Slack,
or updating this file on
[GitHub](https://github.com/carbon-design-system/carbon/edit/main/packages/react/src/components/Menu/Menu.mdx).
6 changes: 6 additions & 0 deletions packages/react/src/components/Menu/Menu.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
MenuItemRadioGroup,
MenuItemDivider,
} from './';
import mdx from './Menu.mdx';

export default {
title: 'Experimental/unstable__Menu',
Expand All @@ -27,6 +28,11 @@ export default {
MenuItemRadioGroup,
MenuItemDivider,
},
parameters: {
docs: {
page: mdx,
},
},
};

export const Playground = (args) => {
Expand Down
13 changes: 13 additions & 0 deletions packages/react/src/components/Menu/docs/overview.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Live demo

<StorybookDemo
themeSelector
tall
url="https://react.carbondesignsystem.com"
variants={[
{
label: 'Default',
variant: 'experimental-unstable-menu--playground'
},
]}
/>

0 comments on commit 495cfe3

Please sign in to comment.