@neo4j-ndl/react 4.16.7 → 4.16.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/color-picker/ColorPicker.js +3 -1
- package/lib/cjs/color-picker/ColorPicker.js.map +1 -1
- package/lib/cjs/color-picker/stories/color-picker-dialog.story.js +40 -0
- package/lib/cjs/color-picker/stories/color-picker-dialog.story.js.map +1 -0
- package/lib/cjs/color-picker/stories/color-picker-popover.story.js +32 -0
- package/lib/cjs/color-picker/stories/color-picker-popover.story.js.map +1 -0
- package/lib/cjs/color-picker/stories/index.js +9 -1
- package/lib/cjs/color-picker/stories/index.js.map +1 -1
- package/lib/cjs/popover/use-popover.js +1 -1
- package/lib/cjs/popover/use-popover.js.map +1 -1
- package/lib/cjs/select/Select.js +2 -0
- package/lib/cjs/select/Select.js.map +1 -1
- package/lib/esm/color-picker/ColorPicker.js +3 -1
- package/lib/esm/color-picker/ColorPicker.js.map +1 -1
- package/lib/esm/color-picker/stories/color-picker-dialog.story.js +38 -0
- package/lib/esm/color-picker/stories/color-picker-dialog.story.js.map +1 -0
- package/lib/esm/color-picker/stories/color-picker-popover.story.js +30 -0
- package/lib/esm/color-picker/stories/color-picker-popover.story.js.map +1 -0
- package/lib/esm/color-picker/stories/index.js +6 -0
- package/lib/esm/color-picker/stories/index.js.map +1 -1
- package/lib/esm/popover/use-popover.js +1 -1
- package/lib/esm/popover/use-popover.js.map +1 -1
- package/lib/esm/select/Select.js +2 -0
- package/lib/esm/select/Select.js.map +1 -1
- package/lib/types/color-picker/ColorPicker.d.ts +4 -0
- package/lib/types/color-picker/ColorPicker.d.ts.map +1 -1
- package/lib/types/color-picker/stories/color-picker-dialog.story.d.ts +24 -0
- package/lib/types/color-picker/stories/color-picker-dialog.story.d.ts.map +1 -0
- package/lib/types/color-picker/stories/color-picker-popover.story.d.ts +24 -0
- package/lib/types/color-picker/stories/color-picker-popover.story.d.ts.map +1 -0
- package/lib/types/color-picker/stories/index.d.ts +4 -0
- package/lib/types/color-picker/stories/index.d.ts.map +1 -1
- package/lib/types/select/Select.d.ts.map +1 -1
- package/package.json +5 -2
- package/skills/ndl-react/SKILL.md +152 -0
- package/skills/ndl-react/components/accordion.md +386 -0
- package/skills/ndl-react/components/ai/code-preview.md +128 -0
- package/skills/ndl-react/components/ai/file-tag.md +90 -0
- package/skills/ndl-react/components/ai/image-tag.md +91 -0
- package/skills/ndl-react/components/ai/more-files.md +73 -0
- package/skills/ndl-react/components/ai/presence.md +54 -0
- package/skills/ndl-react/components/ai/preview.md +498 -0
- package/skills/ndl-react/components/ai/prompt.md +362 -0
- package/skills/ndl-react/components/ai/reasoning.md +95 -0
- package/skills/ndl-react/components/ai/response.md +1109 -0
- package/skills/ndl-react/components/ai/suggestion.md +84 -0
- package/skills/ndl-react/components/ai/thinking.md +43 -0
- package/skills/ndl-react/components/ai/tool-call.md +43 -0
- package/skills/ndl-react/components/ai/user-bubble.md +187 -0
- package/skills/ndl-react/components/avatar.md +169 -0
- package/skills/ndl-react/components/banner.md +225 -0
- package/skills/ndl-react/components/box.md +39 -0
- package/skills/ndl-react/components/breadcrumbs.md +245 -0
- package/skills/ndl-react/components/checkbox.md +269 -0
- package/skills/ndl-react/components/clean-icon-button.md +294 -0
- package/skills/ndl-react/components/clipboard-button.md +154 -0
- package/skills/ndl-react/components/code-block.md +276 -0
- package/skills/ndl-react/components/code.md +68 -0
- package/skills/ndl-react/components/color-picker.md +131 -0
- package/skills/ndl-react/components/conditional-wrap.md +46 -0
- package/skills/ndl-react/components/data-grid.md +3121 -0
- package/skills/ndl-react/components/date-picker.md +652 -0
- package/skills/ndl-react/components/dialog.md +485 -0
- package/skills/ndl-react/components/dismissible-tag.md +136 -0
- package/skills/ndl-react/components/divider.md +96 -0
- package/skills/ndl-react/components/drawer.md +543 -0
- package/skills/ndl-react/components/dropdown-button.md +161 -0
- package/skills/ndl-react/components/dropzone.md +371 -0
- package/skills/ndl-react/components/filled-button.md +26 -0
- package/skills/ndl-react/components/flex.md +82 -0
- package/skills/ndl-react/components/graph-label.md +167 -0
- package/skills/ndl-react/components/icon-button-array.md +187 -0
- package/skills/ndl-react/components/icon-button.md +193 -0
- package/skills/ndl-react/components/inline-edit.md +209 -0
- package/skills/ndl-react/components/kbd.md +63 -0
- package/skills/ndl-react/components/loading-bar.md +43 -0
- package/skills/ndl-react/components/loading-spinner.md +57 -0
- package/skills/ndl-react/components/logo.md +57 -0
- package/skills/ndl-react/components/menu.md +993 -0
- package/skills/ndl-react/components/modal.md +27 -0
- package/skills/ndl-react/components/next/tree-view.md +966 -0
- package/skills/ndl-react/components/outlined-button.md +26 -0
- package/skills/ndl-react/components/popover.md +283 -0
- package/skills/ndl-react/components/progress-bar.md +70 -0
- package/skills/ndl-react/components/radio.md +150 -0
- package/skills/ndl-react/components/read-only-tag.md +96 -0
- package/skills/ndl-react/components/segmented-control.md +200 -0
- package/skills/ndl-react/components/select-icon-button.md +183 -0
- package/skills/ndl-react/components/select.md +530 -0
- package/skills/ndl-react/components/selectable-tag.md +203 -0
- package/skills/ndl-react/components/side-navigation.md +652 -0
- package/skills/ndl-react/components/skeleton.md +274 -0
- package/skills/ndl-react/components/slider.md +308 -0
- package/skills/ndl-react/components/spotlight.md +796 -0
- package/skills/ndl-react/components/status-indicator.md +57 -0
- package/skills/ndl-react/components/status-label.md +132 -0
- package/skills/ndl-react/components/switch.md +167 -0
- package/skills/ndl-react/components/tabs.md +433 -0
- package/skills/ndl-react/components/tag.md +91 -0
- package/skills/ndl-react/components/text-area.md +178 -0
- package/skills/ndl-react/components/text-button.md +25 -0
- package/skills/ndl-react/components/text-input.md +475 -0
- package/skills/ndl-react/components/text-link.md +119 -0
- package/skills/ndl-react/components/time-picker.md +137 -0
- package/skills/ndl-react/components/timezone-picker.md +496 -0
- package/skills/ndl-react/components/tooltip.md +478 -0
- package/skills/ndl-react/components/tree-view.md +545 -0
- package/skills/ndl-react/components/typography.md +72 -0
- package/skills/ndl-react/components/wizard.md +152 -0
|
@@ -0,0 +1,993 @@
|
|
|
1
|
+
# Menu
|
|
2
|
+
|
|
3
|
+
Import: `import { Menu } from '@neo4j-ndl/react'`
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
### Menu
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Required | Default | Description |
|
|
10
|
+
|------|------|----------|---------|-------------|
|
|
11
|
+
| `anchorRef` | `RefObject<HTMLElement \| null>` | | | Anchor element ref for positioning |
|
|
12
|
+
| `as` | `ElementType<any, keyof IntrinsicElements>` | | | An override of the default HTML tag of the root of the component. Can also be another React component. |
|
|
13
|
+
| `children` | `ReactNode` | | | Content displayed inside the menu |
|
|
14
|
+
| `description` | `ReactNode` | | | Optional description for nested trigger rendering |
|
|
15
|
+
| `icon` | `ReactNode` | | | Optional icon for nested trigger rendering |
|
|
16
|
+
| `isDisabled` | `boolean` | | | Whether the menu trigger is disabled |
|
|
17
|
+
| `isOpen` | `boolean` | | | Whether the menu is open or closed (uncontrolled when omitted) |
|
|
18
|
+
| `isPortaled` | `boolean` | | `true` | Whether the menu should be wrapped in a floating portal |
|
|
19
|
+
| `isRoot` | `boolean` | | | Whether the menu is a root menu instance. This is set internally by the component based on nesting |
|
|
20
|
+
| `minWidth` | `number` | | | Minimum width in pixels for the menu component |
|
|
21
|
+
| `onClose` | `((event: Event, closeReason: { type: "backdropClick" \| "itemClick" \| "escapeKeyDown" \| "focusOut"; id?: string; }) => void) \| undefined` | | | Callback function that is called when the menu closes |
|
|
22
|
+
| `placement` | `'bottom-end-bottom-start' \| 'bottom-end-top-end' \| 'bottom-middle-top-middle' \| 'bottom-start-bottom-end' \| 'bottom-start-top-start' \| 'middle-end-middle-start' \| 'middle-start-middle-end' \| 'top-end-bottom-end' \| 'top-end-top-start' \| 'top-middle-bottom-middle' \| 'top-start-bottom-start' \| 'top-start-top-end'` | | | The placement of the floating element is determined by two sets of words. The first set of words specifies the point on the anchor element where the floating element will be attached. The second set of coordinates specifies the point on the floating element that will attach to the anchor element. |
|
|
23
|
+
| `portalTarget` | `HTMLElement \| null` | | | Portal target element (defaults to `document.body`) |
|
|
24
|
+
| `ref` | `any` | | | A ref to apply to the root element. |
|
|
25
|
+
| `strategy` | `'absolute' \| 'fixed'` | | | Positioning strategy used by Floating UI |
|
|
26
|
+
| `title` | `string` | | | Optional title for nested trigger rendering |
|
|
27
|
+
|
|
28
|
+
`isRoot` is determined internally by checking for a parent context menu. If no parent exists, the component renders as the root menu; otherwise, a nested menu item trigger is rendered. When `isRoot` is `false`, the `title`, `description`, `icon`, and `isDisabled` props are forwarded to the nested menu item trigger component.
|
|
29
|
+
|
|
30
|
+
The `placement` prop defaults to `bottom-start` when it is the root menu and `right-start` when it is a nested menu item trigger.
|
|
31
|
+
|
|
32
|
+
The `strategy` prop is set to `fixed` when the context menu is inside a `Dialog` otherwise it is set to `absolute`.
|
|
33
|
+
|
|
34
|
+
### Menu.CategoryItem
|
|
35
|
+
|
|
36
|
+
| Prop | Type | Required | Default | Description |
|
|
37
|
+
|------|------|----------|---------|-------------|
|
|
38
|
+
| `as` | `ElementType<any, keyof IntrinsicElements>` | | | An override of the default HTML tag of the root of the component. Can also be another React component. |
|
|
39
|
+
| `children` | `ReactNode` | | | Content displayed inside the category item component |
|
|
40
|
+
| `ref` | `any` | | | A ref to apply to the root element. |
|
|
41
|
+
|
|
42
|
+
### Menu.Divider
|
|
43
|
+
|
|
44
|
+
| Prop | Type | Required | Default | Description |
|
|
45
|
+
|------|------|----------|---------|-------------|
|
|
46
|
+
| `as` | `ElementType<any, keyof IntrinsicElements>` | | | An override of the default HTML tag of the root of the component. Can also be another React component. |
|
|
47
|
+
| `orientation` | `'horizontal' \| 'vertical'` | | `horizontal` | |
|
|
48
|
+
| `ref` | `any` | | | A ref to apply to the root element. |
|
|
49
|
+
|
|
50
|
+
### Menu.Group
|
|
51
|
+
|
|
52
|
+
| Prop | Type | Required | Default | Description |
|
|
53
|
+
|------|------|----------|---------|-------------|
|
|
54
|
+
| `children` | `ReactNode` | | | Content displayed inside the group. |
|
|
55
|
+
| `ref` | `Ref<HTMLDivElement>` | | | A ref to apply to the root element. |
|
|
56
|
+
|
|
57
|
+
### Menu.Item
|
|
58
|
+
|
|
59
|
+
| Prop | Type | Required | Default | Description |
|
|
60
|
+
|------|------|----------|---------|-------------|
|
|
61
|
+
| `as` | `ElementType<any, keyof IntrinsicElements>` | | | An override of the default HTML tag of the root of the component. Can also be another React component. |
|
|
62
|
+
| `children` | `ReactNode` | | | Content displayed inside the menu item component |
|
|
63
|
+
| `description` | `ReactNode` | | | Supporting text below title |
|
|
64
|
+
| `id` | `string` | | | Unique identifier for the menu item |
|
|
65
|
+
| `isDisabled` | `boolean` | | | Whether the menu item is disabled |
|
|
66
|
+
| `leadingVisual` | `ReactNode` | | | Leading icon for the menu item component |
|
|
67
|
+
| `onClick` | `(event: MouseEvent<HTMLButtonElement, MouseEvent>) => void` | | | Callback function that is called when the menu item is clicked and it closes the menu tree |
|
|
68
|
+
| `onFocus` | `(event: FocusEvent<HTMLButtonElement, Element>) => void` | | | Callback function that is called when the menu item is focused |
|
|
69
|
+
| `ref` | `any` | | | A ref to apply to the root element. |
|
|
70
|
+
| `title` | `ReactNode` | ✅ | | Title of the menu item component |
|
|
71
|
+
| `trailingContent` | `ReactNode` | | | |
|
|
72
|
+
|
|
73
|
+
### Menu.Items
|
|
74
|
+
|
|
75
|
+
| Prop | Type | Required | Default | Description |
|
|
76
|
+
|------|------|----------|---------|-------------|
|
|
77
|
+
| `as` | `ElementType<any, keyof IntrinsicElements>` | | | An override of the default HTML tag of the root of the component. Can also be another React component. |
|
|
78
|
+
| `children` | `ReactNode` | | | Content displayed inside the menu items component |
|
|
79
|
+
| `ref` | `any` | | | A ref to apply to the root element. |
|
|
80
|
+
|
|
81
|
+
### Menu.RadioItem
|
|
82
|
+
|
|
83
|
+
| Prop | Type | Required | Default | Description |
|
|
84
|
+
|------|------|----------|---------|-------------|
|
|
85
|
+
| `as` | `ElementType<any, keyof IntrinsicElements>` | | | An override of the default HTML tag of the root of the component. Can also be another React component. |
|
|
86
|
+
| `children` | `ReactNode` | | | Content displayed inside the menu item component |
|
|
87
|
+
| `description` | `ReactNode` | | | Supporting text below title |
|
|
88
|
+
| `id` | `string` | | | Unique identifier for the menu item |
|
|
89
|
+
| `isChecked` | `boolean` | | `false` | Whether the radio item is checked. Marks the item as aria-checked. |
|
|
90
|
+
| `isDisabled` | `boolean` | | | Whether the menu item is disabled |
|
|
91
|
+
| `leadingVisual` | `ReactNode` | | | Leading icon for the menu item component |
|
|
92
|
+
| `onClick` | `(event: MouseEvent<HTMLButtonElement, MouseEvent>) => void` | | | Callback function that is called when the menu item is clicked and it closes the menu tree |
|
|
93
|
+
| `onFocus` | `(event: FocusEvent<HTMLButtonElement, Element>) => void` | | | Callback function that is called when the menu item is focused |
|
|
94
|
+
| `ref` | `any` | | | A ref to apply to the root element. |
|
|
95
|
+
| `title` | `ReactNode` | ✅ | | Title of the menu item component |
|
|
96
|
+
| `trailingContent` | `ReactNode` | | | |
|
|
97
|
+
|
|
98
|
+
## Accessibility
|
|
99
|
+
|
|
100
|
+
## Keyboard interactions
|
|
101
|
+
|
|
102
|
+
Implements the keyboard interactions defined in the [WAI-ARIA menu pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menu/).
|
|
103
|
+
|
|
104
|
+
| Key | Description |
|
|
105
|
+
|-----|-------------|
|
|
106
|
+
| `ArrowDown` | Moves focus to the next menu item |
|
|
107
|
+
| `ArrowUp` | Moves focus to the previous menu item |
|
|
108
|
+
| `ArrowRight` | Opens a submenu when focus is on a nested menu item |
|
|
109
|
+
| `ArrowLeft` | Closes the current submenu and returns focus to the parent item |
|
|
110
|
+
| `Enter` | Activates the focused menu item |
|
|
111
|
+
| `Space` | Activates the focused menu item |
|
|
112
|
+
| `Tab` | Closes the menu and moves focus to the next focusable element on the page |
|
|
113
|
+
| `Shift + Tab` | Closes the menu and moves focus to the previous focusable element on the page |
|
|
114
|
+
| `Escape` | Closes the menu and returns focus to the trigger |
|
|
115
|
+
| Type-ahead | Typing a character moves focus to the next item starting with that character |
|
|
116
|
+
|
|
117
|
+
## WAI-ARIA roles and attributes
|
|
118
|
+
|
|
119
|
+
The Menu component follows the [WAI-ARIA menu pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menu/).
|
|
120
|
+
|
|
121
|
+
- The menu container has `role="menu"`
|
|
122
|
+
- Menu items have `role="menuitem"`
|
|
123
|
+
- `Menu.RadioItem` has `role="menuitemradio"` and `aria-checked`
|
|
124
|
+
- `Menu.Group` has `role="group"`
|
|
125
|
+
- Nested menu triggers have `role="menuitem"` and manage `aria-expanded` internally
|
|
126
|
+
- When the menu opens, focus moves to the first item. When it closes, focus returns to the trigger
|
|
127
|
+
- The menu closes when focus leaves the menu area
|
|
128
|
+
|
|
129
|
+
## Implementation guidelines
|
|
130
|
+
|
|
131
|
+
- If using a button as a trigger, set `aria-haspopup="menu"` and `aria-expanded` on the trigger button
|
|
132
|
+
- When mixing `Menu.RadioItem` with regular items, use `Menu.Group` to separate them. This creates the correct grouping semantics for assistive technologies.
|
|
133
|
+
- Only one `Menu.RadioItem` within a group should have `isChecked` set to `true` at a time
|
|
134
|
+
- Ensure menu items have descriptive `title` values. These are used for both the visible label and the type-ahead search.
|
|
135
|
+
- `role="menu"` only allows children with roles `menuitem`, `menuitemradio`, `menuitemcheckbox`, `group`, or `separator`. The built-in sub-components handle this automatically, but custom content passed without a valid role will break the menu semantics for assistive technologies
|
|
136
|
+
|
|
137
|
+
### Related WCAG criteria
|
|
138
|
+
|
|
139
|
+
- [2.1.1 Keyboard](https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html) (A): All menu items and submenus are fully operable via keyboard
|
|
140
|
+
- [2.4.3 Focus Order](https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html) (A): Focus is managed automatically — first item on open, trigger on close
|
|
141
|
+
- [4.1.2 Name, Role, Value](https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html) (A): Roles (`menu`, `menuitem`, `menuitemradio`, `group`), states (`aria-checked`, `aria-expanded`), and accessible names are set automatically by the component
|
|
142
|
+
|
|
143
|
+
## Examples
|
|
144
|
+
|
|
145
|
+
### Default
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
149
|
+
|
|
150
|
+
import { FilledButton, Menu } from '@neo4j-ndl/react';
|
|
151
|
+
import { useRef, useState } from 'react';
|
|
152
|
+
|
|
153
|
+
const Component = () => {
|
|
154
|
+
const anchorEl = useRef<HTMLButtonElement | null>(null);
|
|
155
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<>
|
|
159
|
+
<Menu
|
|
160
|
+
isOpen={isOpen}
|
|
161
|
+
anchorRef={anchorEl}
|
|
162
|
+
onClose={(_event, _data) => {
|
|
163
|
+
setIsOpen(false);
|
|
164
|
+
}}
|
|
165
|
+
htmlAttributes={{ id: 'default-menu' }}
|
|
166
|
+
>
|
|
167
|
+
<Menu.Item
|
|
168
|
+
title="Action 1"
|
|
169
|
+
onClick={() => {
|
|
170
|
+
alert('Action1');
|
|
171
|
+
setIsOpen(false);
|
|
172
|
+
}}
|
|
173
|
+
/>
|
|
174
|
+
<Menu.Item
|
|
175
|
+
title="Action 2"
|
|
176
|
+
onClick={() => {
|
|
177
|
+
alert('Action2');
|
|
178
|
+
setIsOpen(false);
|
|
179
|
+
}}
|
|
180
|
+
/>
|
|
181
|
+
<Menu.Item
|
|
182
|
+
title="Action 3"
|
|
183
|
+
description="Action 3 is disabled"
|
|
184
|
+
isDisabled={true}
|
|
185
|
+
onClick={() => {
|
|
186
|
+
alert('Action3');
|
|
187
|
+
setIsOpen(false);
|
|
188
|
+
}}
|
|
189
|
+
/>
|
|
190
|
+
<Menu.Item
|
|
191
|
+
title="Action 4"
|
|
192
|
+
description="Action 4 is awesome"
|
|
193
|
+
onClick={() => {
|
|
194
|
+
alert('Action4');
|
|
195
|
+
setIsOpen(false);
|
|
196
|
+
}}
|
|
197
|
+
/>
|
|
198
|
+
</Menu>
|
|
199
|
+
|
|
200
|
+
<FilledButton
|
|
201
|
+
onClick={() => setIsOpen(true)}
|
|
202
|
+
ref={anchorEl}
|
|
203
|
+
aria-haspopup="menu"
|
|
204
|
+
aria-expanded={isOpen}
|
|
205
|
+
>
|
|
206
|
+
Open Menu
|
|
207
|
+
</FilledButton>
|
|
208
|
+
</>
|
|
209
|
+
);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
export default Component;
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Custom Items
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
219
|
+
|
|
220
|
+
import { FilledButton, Menu, Typography } from '@neo4j-ndl/react';
|
|
221
|
+
import { Square2StackIconOutline } from '@neo4j-ndl/react/icons';
|
|
222
|
+
import { useRef, useState } from 'react';
|
|
223
|
+
|
|
224
|
+
const Component = () => {
|
|
225
|
+
const anchorEl = useRef<HTMLButtonElement | null>(null);
|
|
226
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
<>
|
|
230
|
+
<Menu
|
|
231
|
+
isOpen={isOpen}
|
|
232
|
+
anchorRef={anchorEl}
|
|
233
|
+
placement="bottom-start-top-start"
|
|
234
|
+
onClose={(_event, _data) => {
|
|
235
|
+
setIsOpen(false);
|
|
236
|
+
}}
|
|
237
|
+
htmlAttributes={{ id: 'custom-items-menu' }}
|
|
238
|
+
>
|
|
239
|
+
<Menu.Item
|
|
240
|
+
title={
|
|
241
|
+
<Typography variant="display">This can be any element</Typography>
|
|
242
|
+
}
|
|
243
|
+
/>
|
|
244
|
+
<Menu.Item title="Danger action 1" className="n-text-danger-text" />
|
|
245
|
+
<Menu.Item
|
|
246
|
+
title="Danger action 2"
|
|
247
|
+
className="n-text-danger-text"
|
|
248
|
+
leadingVisual={
|
|
249
|
+
<Square2StackIconOutline className="n-text-danger-icon" />
|
|
250
|
+
}
|
|
251
|
+
/>
|
|
252
|
+
<Menu title="More actions" description="Some additional actions">
|
|
253
|
+
<Menu.Item
|
|
254
|
+
title="Danger action 3"
|
|
255
|
+
className="n-text-danger-text"
|
|
256
|
+
isDisabled={true}
|
|
257
|
+
/>
|
|
258
|
+
<Menu.Item title="Danger action 4" className="n-text-danger-text" />
|
|
259
|
+
</Menu>
|
|
260
|
+
</Menu>
|
|
261
|
+
<FilledButton
|
|
262
|
+
onClick={() => setIsOpen(true)}
|
|
263
|
+
ref={anchorEl}
|
|
264
|
+
aria-haspopup="menu"
|
|
265
|
+
aria-expanded={isOpen}
|
|
266
|
+
>
|
|
267
|
+
Open Menu (set with custom placement)
|
|
268
|
+
</FilledButton>
|
|
269
|
+
</>
|
|
270
|
+
);
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
export default Component;
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### In Dialog
|
|
277
|
+
|
|
278
|
+
```tsx
|
|
279
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
280
|
+
|
|
281
|
+
import { Dialog, FilledButton, Menu } from '@neo4j-ndl/react';
|
|
282
|
+
import { Square2StackIconOutline } from '@neo4j-ndl/react/icons';
|
|
283
|
+
import { useRef, useState } from 'react';
|
|
284
|
+
|
|
285
|
+
const Component = () => {
|
|
286
|
+
const anchorEl = useRef<HTMLButtonElement | null>(null);
|
|
287
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
288
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
289
|
+
|
|
290
|
+
const handleClick = () => setIsModalOpen((prev) => !prev);
|
|
291
|
+
const handleClose = () => setIsModalOpen(false);
|
|
292
|
+
const handleMenuClick = () => setIsOpen((prev) => !prev);
|
|
293
|
+
|
|
294
|
+
return (
|
|
295
|
+
<>
|
|
296
|
+
<div className="n-flex n-justify-center">
|
|
297
|
+
<FilledButton onClick={handleClick}>Open Dialog</FilledButton>
|
|
298
|
+
</div>
|
|
299
|
+
<Dialog
|
|
300
|
+
htmlAttributes={{ id: 'modal-root' }}
|
|
301
|
+
isOpen={isModalOpen}
|
|
302
|
+
onClose={handleClose}
|
|
303
|
+
>
|
|
304
|
+
<div className="n-flex n-justify-center">
|
|
305
|
+
<FilledButton
|
|
306
|
+
onClick={handleMenuClick}
|
|
307
|
+
ref={anchorEl}
|
|
308
|
+
aria-haspopup="menu"
|
|
309
|
+
aria-expanded={isOpen}
|
|
310
|
+
>
|
|
311
|
+
Open Menu
|
|
312
|
+
</FilledButton>
|
|
313
|
+
</div>
|
|
314
|
+
<Menu
|
|
315
|
+
isOpen={isOpen}
|
|
316
|
+
anchorRef={anchorEl}
|
|
317
|
+
onClose={(event, _data) => {
|
|
318
|
+
setIsOpen(false);
|
|
319
|
+
event?.preventDefault();
|
|
320
|
+
event?.stopPropagation();
|
|
321
|
+
}}
|
|
322
|
+
portalTarget={document.getElementById('modal-root')}
|
|
323
|
+
htmlAttributes={{ id: 'dialog-menu' }}
|
|
324
|
+
>
|
|
325
|
+
<Menu.Item title="Undo" onClick={() => alert('Undo')} />
|
|
326
|
+
<Menu.Item title="Redo" isDisabled />
|
|
327
|
+
<Menu.Item title="Cut" description="Copy and remove" />
|
|
328
|
+
<Menu
|
|
329
|
+
title="Copy as"
|
|
330
|
+
description="Copying as something"
|
|
331
|
+
icon={<Square2StackIconOutline />}
|
|
332
|
+
>
|
|
333
|
+
<Menu.Item title="Text" />
|
|
334
|
+
<Menu.Item title="Video" />
|
|
335
|
+
<Menu title="Image">
|
|
336
|
+
<Menu.Item title=".png" />
|
|
337
|
+
<Menu.Item title=".jpg" />
|
|
338
|
+
<Menu.Item title=".svg" />
|
|
339
|
+
<Menu.Item title=".gif" />
|
|
340
|
+
</Menu>
|
|
341
|
+
<Menu.Item title="Audio" />
|
|
342
|
+
<Menu title="Share">
|
|
343
|
+
<Menu.Item title="Mail" />
|
|
344
|
+
<Menu.Item title="Instagram" />
|
|
345
|
+
</Menu>
|
|
346
|
+
</Menu>
|
|
347
|
+
</Menu>
|
|
348
|
+
</Dialog>
|
|
349
|
+
</>
|
|
350
|
+
);
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
export default Component;
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### In Popover
|
|
357
|
+
|
|
358
|
+
```tsx
|
|
359
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
360
|
+
|
|
361
|
+
import { FilledButton, Menu, Popover } from '@neo4j-ndl/react';
|
|
362
|
+
import { useRef, useState } from 'react';
|
|
363
|
+
|
|
364
|
+
const Component = () => {
|
|
365
|
+
const anchorEl = useRef<HTMLButtonElement | null>(null);
|
|
366
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
367
|
+
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
|
368
|
+
|
|
369
|
+
return (
|
|
370
|
+
<>
|
|
371
|
+
<Menu
|
|
372
|
+
isOpen={isOpen}
|
|
373
|
+
anchorRef={anchorEl}
|
|
374
|
+
onClose={(_event, _data) => {
|
|
375
|
+
setIsOpen(false);
|
|
376
|
+
}}
|
|
377
|
+
htmlAttributes={{ id: 'popover-menu' }}
|
|
378
|
+
>
|
|
379
|
+
<Menu.Item title="Action 1" onClick={() => alert('Action1')} />
|
|
380
|
+
<Menu.Item title="Action 2" onClick={() => alert('Action2')} />
|
|
381
|
+
<Menu.Item
|
|
382
|
+
title="Action 3"
|
|
383
|
+
description="Action 3 is disabled"
|
|
384
|
+
isDisabled={true}
|
|
385
|
+
onClick={() => alert('Action3')}
|
|
386
|
+
/>
|
|
387
|
+
<Menu.Item
|
|
388
|
+
title="Action 4"
|
|
389
|
+
description="Action 4 is awesome"
|
|
390
|
+
onClick={() => alert('Action4')}
|
|
391
|
+
/>
|
|
392
|
+
</Menu>
|
|
393
|
+
|
|
394
|
+
<Popover isOpen={isPopoverOpen}>
|
|
395
|
+
<Popover.Trigger>
|
|
396
|
+
<FilledButton onClick={() => setIsPopoverOpen(!isPopoverOpen)}>
|
|
397
|
+
{isPopoverOpen ? 'Close' : 'Open'} Popover
|
|
398
|
+
</FilledButton>
|
|
399
|
+
</Popover.Trigger>
|
|
400
|
+
<Popover.Content style={{ height: 150, overflow: 'auto', width: 400 }}>
|
|
401
|
+
<>
|
|
402
|
+
<p>
|
|
403
|
+
Scroll me to the bottom to open menu Lorem ipsum dolor sit amet,
|
|
404
|
+
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
|
|
405
|
+
labore et dolore magna aliqua. Ut enim ad minim veniam, quis
|
|
406
|
+
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
|
407
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate
|
|
408
|
+
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
|
409
|
+
occaecat cupidatat non proident, sunt in culpa qui officia
|
|
410
|
+
deserunt mollit anim id est laborum.
|
|
411
|
+
</p>
|
|
412
|
+
<FilledButton
|
|
413
|
+
onClick={() => setIsOpen(true)}
|
|
414
|
+
ref={anchorEl}
|
|
415
|
+
aria-haspopup="menu"
|
|
416
|
+
aria-expanded={isOpen}
|
|
417
|
+
>
|
|
418
|
+
Open Context Menu
|
|
419
|
+
</FilledButton>
|
|
420
|
+
</>
|
|
421
|
+
</Popover.Content>
|
|
422
|
+
</Popover>
|
|
423
|
+
</>
|
|
424
|
+
);
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
export default Component;
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Nested
|
|
431
|
+
|
|
432
|
+
```tsx
|
|
433
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
434
|
+
|
|
435
|
+
import { FilledButton, Menu } from '@neo4j-ndl/react';
|
|
436
|
+
import { Square2StackIconOutline } from '@neo4j-ndl/react/icons';
|
|
437
|
+
import { useRef, useState } from 'react';
|
|
438
|
+
|
|
439
|
+
const Component = () => {
|
|
440
|
+
const anchorEl = useRef<HTMLButtonElement | null>(null);
|
|
441
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
442
|
+
|
|
443
|
+
return (
|
|
444
|
+
<>
|
|
445
|
+
<Menu
|
|
446
|
+
isOpen={isOpen}
|
|
447
|
+
anchorRef={anchorEl}
|
|
448
|
+
onClose={(_event, _data) => {
|
|
449
|
+
setIsOpen(false);
|
|
450
|
+
}}
|
|
451
|
+
htmlAttributes={{ id: 'nested-menu' }}
|
|
452
|
+
>
|
|
453
|
+
<Menu.Item title="Undo" onClick={() => alert('Undo')} />
|
|
454
|
+
<Menu.Item title="Redo" isDisabled />
|
|
455
|
+
<Menu.Item title="Cut" description="Copy and remove" />
|
|
456
|
+
<Menu
|
|
457
|
+
title="Copy as"
|
|
458
|
+
description="Copying as something"
|
|
459
|
+
icon={<Square2StackIconOutline />}
|
|
460
|
+
>
|
|
461
|
+
<Menu.Item title="Text" />
|
|
462
|
+
<Menu.Item title="Video" />
|
|
463
|
+
<Menu title="Image">
|
|
464
|
+
<Menu.Item title=".png" />
|
|
465
|
+
<Menu.Item title=".jpg" />
|
|
466
|
+
<Menu.Item title=".svg" />
|
|
467
|
+
<Menu.Item title=".gif" />
|
|
468
|
+
</Menu>
|
|
469
|
+
<Menu.Item title="Audio" />
|
|
470
|
+
</Menu>
|
|
471
|
+
<Menu title="Share">
|
|
472
|
+
<Menu.Item title="Mail" />
|
|
473
|
+
<Menu.Item title="Instagram" />
|
|
474
|
+
</Menu>
|
|
475
|
+
</Menu>
|
|
476
|
+
<FilledButton
|
|
477
|
+
onClick={() => setIsOpen(true)}
|
|
478
|
+
ref={anchorEl}
|
|
479
|
+
aria-haspopup="menu"
|
|
480
|
+
aria-expanded={isOpen}
|
|
481
|
+
>
|
|
482
|
+
Open Menu
|
|
483
|
+
</FilledButton>
|
|
484
|
+
</>
|
|
485
|
+
);
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
export default Component;
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### Placements
|
|
492
|
+
|
|
493
|
+
```tsx
|
|
494
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
495
|
+
|
|
496
|
+
import { FilledButton, Menu } from '@neo4j-ndl/react';
|
|
497
|
+
import { useRef, useState } from 'react';
|
|
498
|
+
|
|
499
|
+
const Component = () => {
|
|
500
|
+
const anchorEl = useRef<HTMLButtonElement | null>(null);
|
|
501
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
502
|
+
|
|
503
|
+
return (
|
|
504
|
+
<>
|
|
505
|
+
<Menu
|
|
506
|
+
isOpen={isOpen}
|
|
507
|
+
anchorRef={anchorEl}
|
|
508
|
+
placement="middle-end-middle-start"
|
|
509
|
+
onClose={(_event, _data) => {
|
|
510
|
+
setIsOpen(false);
|
|
511
|
+
}}
|
|
512
|
+
htmlAttributes={{ id: 'placements-menu' }}
|
|
513
|
+
>
|
|
514
|
+
<Menu.Item
|
|
515
|
+
title="Action 1"
|
|
516
|
+
onClick={() => {
|
|
517
|
+
alert('Action1');
|
|
518
|
+
setIsOpen(false);
|
|
519
|
+
}}
|
|
520
|
+
/>
|
|
521
|
+
<Menu.Item
|
|
522
|
+
title="Action 2"
|
|
523
|
+
onClick={() => {
|
|
524
|
+
alert('Action2');
|
|
525
|
+
setIsOpen(false);
|
|
526
|
+
}}
|
|
527
|
+
/>
|
|
528
|
+
<Menu.Item
|
|
529
|
+
title="Action 3"
|
|
530
|
+
description="Action 3 is disabled"
|
|
531
|
+
isDisabled={true}
|
|
532
|
+
onClick={() => {
|
|
533
|
+
alert('Action3');
|
|
534
|
+
setIsOpen(false);
|
|
535
|
+
}}
|
|
536
|
+
/>
|
|
537
|
+
<Menu.Item
|
|
538
|
+
title="Action 4"
|
|
539
|
+
description="Action 4 is awesome"
|
|
540
|
+
onClick={() => {
|
|
541
|
+
alert('Action4');
|
|
542
|
+
setIsOpen(false);
|
|
543
|
+
}}
|
|
544
|
+
/>
|
|
545
|
+
<Menu.Item
|
|
546
|
+
id="action_5"
|
|
547
|
+
title="Action 5"
|
|
548
|
+
description="Action 5 does not close the menu"
|
|
549
|
+
/>
|
|
550
|
+
</Menu>
|
|
551
|
+
|
|
552
|
+
<FilledButton
|
|
553
|
+
onClick={() => setIsOpen(true)}
|
|
554
|
+
ref={anchorEl}
|
|
555
|
+
aria-haspopup="menu"
|
|
556
|
+
aria-expanded={isOpen}
|
|
557
|
+
>
|
|
558
|
+
Open Menu
|
|
559
|
+
</FilledButton>
|
|
560
|
+
</>
|
|
561
|
+
);
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
export default Component;
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
### Radio And Normal
|
|
568
|
+
|
|
569
|
+
```tsx
|
|
570
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
571
|
+
|
|
572
|
+
import { DropdownButton, Menu, Typography } from '@neo4j-ndl/react';
|
|
573
|
+
import { useRef, useState } from 'react';
|
|
574
|
+
|
|
575
|
+
const Component = () => {
|
|
576
|
+
const anchorEl = useRef<HTMLButtonElement | null>(null);
|
|
577
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
578
|
+
const [selectedOption, setSelectedOption] = useState<string | null>(
|
|
579
|
+
'option-1',
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
return (
|
|
583
|
+
<>
|
|
584
|
+
<Menu
|
|
585
|
+
isOpen={isOpen}
|
|
586
|
+
anchorRef={anchorEl}
|
|
587
|
+
onClose={(_event, _data) => {
|
|
588
|
+
setIsOpen(false);
|
|
589
|
+
}}
|
|
590
|
+
htmlAttributes={{ id: 'radio-and-normal-menu' }}
|
|
591
|
+
>
|
|
592
|
+
<Menu.Group>
|
|
593
|
+
<Menu.RadioItem
|
|
594
|
+
title="Option 1"
|
|
595
|
+
isChecked={selectedOption === 'option-1'}
|
|
596
|
+
onClick={() => {
|
|
597
|
+
setSelectedOption('option-1');
|
|
598
|
+
}}
|
|
599
|
+
/>
|
|
600
|
+
<Menu.RadioItem
|
|
601
|
+
title="Option 2"
|
|
602
|
+
isChecked={selectedOption === 'option-2'}
|
|
603
|
+
onClick={() => {
|
|
604
|
+
setSelectedOption('option-2');
|
|
605
|
+
}}
|
|
606
|
+
/>
|
|
607
|
+
</Menu.Group>
|
|
608
|
+
<Menu.Divider />
|
|
609
|
+
<Menu.Group>
|
|
610
|
+
<Menu.Item
|
|
611
|
+
title="Action 1"
|
|
612
|
+
onClick={() => {
|
|
613
|
+
alert('Action 1');
|
|
614
|
+
}}
|
|
615
|
+
/>
|
|
616
|
+
<Menu.Item
|
|
617
|
+
title="Action 2"
|
|
618
|
+
onClick={() => {
|
|
619
|
+
alert('Action 2');
|
|
620
|
+
}}
|
|
621
|
+
/>
|
|
622
|
+
</Menu.Group>
|
|
623
|
+
</Menu>
|
|
624
|
+
<div className="n-flex n-flex-col n-gap-token-4 n-items-center">
|
|
625
|
+
<Typography variant="body-medium">
|
|
626
|
+
Selected option: <strong>{selectedOption}</strong>
|
|
627
|
+
</Typography>
|
|
628
|
+
<DropdownButton
|
|
629
|
+
isOpen={isOpen}
|
|
630
|
+
onClick={() => setIsOpen(true)}
|
|
631
|
+
ref={anchorEl}
|
|
632
|
+
aria-haspopup="menu"
|
|
633
|
+
>
|
|
634
|
+
Open menu
|
|
635
|
+
</DropdownButton>
|
|
636
|
+
</div>
|
|
637
|
+
</>
|
|
638
|
+
);
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
export default Component;
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
### Radio Items
|
|
645
|
+
|
|
646
|
+
```tsx
|
|
647
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
648
|
+
|
|
649
|
+
import { DropdownButton, Kbd, Menu, Typography } from '@neo4j-ndl/react';
|
|
650
|
+
import { MoonIconOutline, SunIconOutline } from '@neo4j-ndl/react/icons';
|
|
651
|
+
import { useRef, useState } from 'react';
|
|
652
|
+
|
|
653
|
+
const Component = () => {
|
|
654
|
+
const anchorEl = useRef<HTMLButtonElement | null>(null);
|
|
655
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
656
|
+
const [selectedOption, setSelectedOption] = useState<string | null>(
|
|
657
|
+
'option-1',
|
|
658
|
+
);
|
|
659
|
+
|
|
660
|
+
return (
|
|
661
|
+
<>
|
|
662
|
+
<Menu
|
|
663
|
+
isOpen={isOpen}
|
|
664
|
+
anchorRef={anchorEl}
|
|
665
|
+
onClose={(_event, _data) => {
|
|
666
|
+
setIsOpen(false);
|
|
667
|
+
}}
|
|
668
|
+
htmlAttributes={{ id: 'radio-items-menu' }}
|
|
669
|
+
>
|
|
670
|
+
<Menu.RadioItem
|
|
671
|
+
title="Option 1"
|
|
672
|
+
leadingVisual={<SunIconOutline />}
|
|
673
|
+
isChecked={selectedOption === 'option-1'}
|
|
674
|
+
onClick={() => {
|
|
675
|
+
setSelectedOption('option-1');
|
|
676
|
+
}}
|
|
677
|
+
/>
|
|
678
|
+
<Menu.RadioItem
|
|
679
|
+
title="Option 2"
|
|
680
|
+
leadingVisual={<MoonIconOutline />}
|
|
681
|
+
isChecked={selectedOption === 'option-2'}
|
|
682
|
+
onClick={() => {
|
|
683
|
+
setSelectedOption('option-2');
|
|
684
|
+
}}
|
|
685
|
+
/>
|
|
686
|
+
<Menu.RadioItem
|
|
687
|
+
title="Option 3"
|
|
688
|
+
description="Option 3 has a description"
|
|
689
|
+
isChecked={selectedOption === 'option-3'}
|
|
690
|
+
onClick={() => {
|
|
691
|
+
setSelectedOption('option-3');
|
|
692
|
+
}}
|
|
693
|
+
/>
|
|
694
|
+
<Menu.RadioItem
|
|
695
|
+
title="Option 4"
|
|
696
|
+
trailingContent={<Kbd keys={['A']} />}
|
|
697
|
+
isChecked={selectedOption === 'option-4'}
|
|
698
|
+
onClick={() => {
|
|
699
|
+
setSelectedOption('option-4');
|
|
700
|
+
}}
|
|
701
|
+
/>
|
|
702
|
+
</Menu>
|
|
703
|
+
<div className="n-flex n-flex-col n-gap-token-4 n-items-center">
|
|
704
|
+
<Typography variant="body-medium">
|
|
705
|
+
Selected option: <strong>{selectedOption}</strong>
|
|
706
|
+
</Typography>
|
|
707
|
+
<DropdownButton
|
|
708
|
+
isOpen={isOpen}
|
|
709
|
+
onClick={() => setIsOpen(true)}
|
|
710
|
+
ref={anchorEl}
|
|
711
|
+
aria-haspopup="menu"
|
|
712
|
+
>
|
|
713
|
+
Open menu
|
|
714
|
+
</DropdownButton>
|
|
715
|
+
</div>
|
|
716
|
+
</>
|
|
717
|
+
);
|
|
718
|
+
};
|
|
719
|
+
|
|
720
|
+
export default Component;
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
### With Category
|
|
724
|
+
|
|
725
|
+
```tsx
|
|
726
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
727
|
+
|
|
728
|
+
import { FilledButton, Menu } from '@neo4j-ndl/react';
|
|
729
|
+
import { useRef, useState } from 'react';
|
|
730
|
+
|
|
731
|
+
const Component = () => {
|
|
732
|
+
const anchorEl = useRef<HTMLButtonElement | null>(null);
|
|
733
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
734
|
+
|
|
735
|
+
return (
|
|
736
|
+
<>
|
|
737
|
+
<Menu
|
|
738
|
+
isOpen={isOpen}
|
|
739
|
+
anchorRef={anchorEl}
|
|
740
|
+
onClose={(_event, _data) => {
|
|
741
|
+
setIsOpen(false);
|
|
742
|
+
}}
|
|
743
|
+
htmlAttributes={{ id: 'category-menu' }}
|
|
744
|
+
>
|
|
745
|
+
<Menu.Group>
|
|
746
|
+
<Menu.CategoryItem>Category 1</Menu.CategoryItem>
|
|
747
|
+
<Menu.Item title="Action 1" onClick={() => alert('Action1')} />
|
|
748
|
+
<Menu.Item title="Action 2" onClick={() => alert('Action2')} />
|
|
749
|
+
</Menu.Group>
|
|
750
|
+
<Menu.Divider />
|
|
751
|
+
<Menu.Group>
|
|
752
|
+
<Menu.Item
|
|
753
|
+
title="Action 3"
|
|
754
|
+
description="Action 3 is disabled"
|
|
755
|
+
isDisabled={true}
|
|
756
|
+
onClick={() => alert('Action3')}
|
|
757
|
+
/>
|
|
758
|
+
<Menu.Item
|
|
759
|
+
title="Action 4"
|
|
760
|
+
description="Action 4 is awesome"
|
|
761
|
+
onClick={() => alert('Action4')}
|
|
762
|
+
/>
|
|
763
|
+
</Menu.Group>
|
|
764
|
+
</Menu>
|
|
765
|
+
<FilledButton
|
|
766
|
+
onClick={() => setIsOpen(true)}
|
|
767
|
+
ref={anchorEl}
|
|
768
|
+
aria-haspopup="menu"
|
|
769
|
+
aria-expanded={isOpen}
|
|
770
|
+
>
|
|
771
|
+
Open Menu
|
|
772
|
+
</FilledButton>
|
|
773
|
+
</>
|
|
774
|
+
);
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
export default Component;
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
### With Disabled Item
|
|
781
|
+
|
|
782
|
+
```tsx
|
|
783
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
784
|
+
|
|
785
|
+
import { FilledButton, Menu } from '@neo4j-ndl/react';
|
|
786
|
+
import { useRef, useState } from 'react';
|
|
787
|
+
|
|
788
|
+
const Component = () => {
|
|
789
|
+
const anchorEl = useRef<HTMLButtonElement | null>(null);
|
|
790
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
791
|
+
|
|
792
|
+
return (
|
|
793
|
+
<>
|
|
794
|
+
<Menu
|
|
795
|
+
isOpen={isOpen}
|
|
796
|
+
anchorRef={anchorEl}
|
|
797
|
+
onClose={(_event, _data) => {
|
|
798
|
+
setIsOpen(false);
|
|
799
|
+
}}
|
|
800
|
+
htmlAttributes={{ id: 'disabled-item-menu' }}
|
|
801
|
+
>
|
|
802
|
+
<Menu.Item
|
|
803
|
+
title="Action 1"
|
|
804
|
+
description="Action 1 is disabled"
|
|
805
|
+
isDisabled={true}
|
|
806
|
+
/>
|
|
807
|
+
<Menu.Item title="Action 2" onClick={() => alert('Action2')} />
|
|
808
|
+
</Menu>
|
|
809
|
+
<FilledButton
|
|
810
|
+
onClick={() => setIsOpen(true)}
|
|
811
|
+
ref={anchorEl}
|
|
812
|
+
aria-haspopup="menu"
|
|
813
|
+
aria-expanded={isOpen}
|
|
814
|
+
>
|
|
815
|
+
Open Menu
|
|
816
|
+
</FilledButton>
|
|
817
|
+
</>
|
|
818
|
+
);
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
export default Component;
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
### With Divider
|
|
825
|
+
|
|
826
|
+
```tsx
|
|
827
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
828
|
+
|
|
829
|
+
import { FilledButton, Menu } from '@neo4j-ndl/react';
|
|
830
|
+
import { useRef, useState } from 'react';
|
|
831
|
+
|
|
832
|
+
const Component = () => {
|
|
833
|
+
const anchorEl = useRef<HTMLButtonElement | null>(null);
|
|
834
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
835
|
+
|
|
836
|
+
return (
|
|
837
|
+
<>
|
|
838
|
+
<Menu
|
|
839
|
+
isOpen={isOpen}
|
|
840
|
+
anchorRef={anchorEl}
|
|
841
|
+
onClose={(_event, _data) => {
|
|
842
|
+
setIsOpen(false);
|
|
843
|
+
}}
|
|
844
|
+
htmlAttributes={{ id: 'divider-menu' }}
|
|
845
|
+
>
|
|
846
|
+
<Menu.Item title="Action 1" />
|
|
847
|
+
<Menu.Divider />
|
|
848
|
+
<Menu.Item title="Action 2" />
|
|
849
|
+
<Menu.Divider />
|
|
850
|
+
<Menu.Item title="Action 3" />
|
|
851
|
+
<Menu.Divider />
|
|
852
|
+
<Menu.Item title="Action 4" />
|
|
853
|
+
</Menu>
|
|
854
|
+
<FilledButton
|
|
855
|
+
onClick={() => setIsOpen(true)}
|
|
856
|
+
ref={anchorEl}
|
|
857
|
+
aria-haspopup="menu"
|
|
858
|
+
aria-expanded={isOpen}
|
|
859
|
+
>
|
|
860
|
+
Open Menu
|
|
861
|
+
</FilledButton>
|
|
862
|
+
</>
|
|
863
|
+
);
|
|
864
|
+
};
|
|
865
|
+
|
|
866
|
+
export default Component;
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
### With Icon
|
|
870
|
+
|
|
871
|
+
```tsx
|
|
872
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
873
|
+
|
|
874
|
+
import { FilledButton, Menu } from '@neo4j-ndl/react';
|
|
875
|
+
import { PhotoIconOutline, PlusIconOutline } from '@neo4j-ndl/react/icons';
|
|
876
|
+
import { useRef, useState } from 'react';
|
|
877
|
+
|
|
878
|
+
const Component = () => {
|
|
879
|
+
const anchorEl = useRef<HTMLButtonElement | null>(null);
|
|
880
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
881
|
+
|
|
882
|
+
return (
|
|
883
|
+
<>
|
|
884
|
+
<Menu
|
|
885
|
+
isOpen={isOpen}
|
|
886
|
+
anchorRef={anchorEl}
|
|
887
|
+
onClose={(_event, _data) => {
|
|
888
|
+
setIsOpen(false);
|
|
889
|
+
}}
|
|
890
|
+
htmlAttributes={{ id: 'icon-menu' }}
|
|
891
|
+
>
|
|
892
|
+
<Menu.Item
|
|
893
|
+
leadingVisual={<PlusIconOutline />}
|
|
894
|
+
title="Action 1"
|
|
895
|
+
onClick={() => alert('Action1')}
|
|
896
|
+
/>
|
|
897
|
+
<Menu.Item
|
|
898
|
+
leadingVisual={<PlusIconOutline />}
|
|
899
|
+
title="Action 2"
|
|
900
|
+
onClick={() => alert('Action2')}
|
|
901
|
+
/>
|
|
902
|
+
<Menu.Item
|
|
903
|
+
leadingVisual={<PlusIconOutline />}
|
|
904
|
+
title="Action 3"
|
|
905
|
+
description="Action 3 is disabled"
|
|
906
|
+
isDisabled={true}
|
|
907
|
+
onClick={() => alert('Action3')}
|
|
908
|
+
/>
|
|
909
|
+
<Menu
|
|
910
|
+
title="Action 3.1"
|
|
911
|
+
description="Action with sub menu"
|
|
912
|
+
icon={<PlusIconOutline />}
|
|
913
|
+
>
|
|
914
|
+
<Menu.Item title="Text" />
|
|
915
|
+
<Menu.Item title="Video" />
|
|
916
|
+
<Menu title="Image" icon={<PhotoIconOutline />}>
|
|
917
|
+
<Menu.Item title=".png" />
|
|
918
|
+
<Menu.Item title=".jpg" />
|
|
919
|
+
</Menu>
|
|
920
|
+
<Menu.Item title="Audio" />
|
|
921
|
+
</Menu>
|
|
922
|
+
<Menu.Item
|
|
923
|
+
leadingVisual={<PlusIconOutline />}
|
|
924
|
+
title="Action 4"
|
|
925
|
+
description="Action 4 is awesome"
|
|
926
|
+
onClick={() => alert('Action4')}
|
|
927
|
+
/>
|
|
928
|
+
</Menu>
|
|
929
|
+
<FilledButton
|
|
930
|
+
onClick={() => setIsOpen(true)}
|
|
931
|
+
ref={anchorEl}
|
|
932
|
+
aria-haspopup="menu"
|
|
933
|
+
aria-expanded={isOpen}
|
|
934
|
+
>
|
|
935
|
+
Open Menu
|
|
936
|
+
</FilledButton>
|
|
937
|
+
</>
|
|
938
|
+
);
|
|
939
|
+
};
|
|
940
|
+
|
|
941
|
+
export default Component;
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
### With Keyboard Shortcuts
|
|
945
|
+
|
|
946
|
+
```tsx
|
|
947
|
+
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
|
|
948
|
+
|
|
949
|
+
import { FilledButton, Kbd, Menu } from '@neo4j-ndl/react';
|
|
950
|
+
import { PlusIconOutline } from '@neo4j-ndl/react/icons';
|
|
951
|
+
import { useRef, useState } from 'react';
|
|
952
|
+
|
|
953
|
+
const Component = () => {
|
|
954
|
+
const anchorEl = useRef<HTMLButtonElement | null>(null);
|
|
955
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
956
|
+
|
|
957
|
+
return (
|
|
958
|
+
<>
|
|
959
|
+
<Menu
|
|
960
|
+
isOpen={isOpen}
|
|
961
|
+
anchorRef={anchorEl}
|
|
962
|
+
onClose={(_event, _data) => {
|
|
963
|
+
setIsOpen(false);
|
|
964
|
+
}}
|
|
965
|
+
htmlAttributes={{ id: 'keyboard-shortcuts-menu' }}
|
|
966
|
+
>
|
|
967
|
+
<Menu.Item
|
|
968
|
+
leadingVisual={<PlusIconOutline />}
|
|
969
|
+
title="Action 1"
|
|
970
|
+
onClick={() => alert('Action1')}
|
|
971
|
+
/>
|
|
972
|
+
<Menu.Item
|
|
973
|
+
leadingVisual={<PlusIconOutline />}
|
|
974
|
+
trailingContent={<Kbd keys={['A', ['B']]} />}
|
|
975
|
+
title="Action 2"
|
|
976
|
+
description="Action 4 has a keyboard shortcut"
|
|
977
|
+
onClick={() => alert('Action4')}
|
|
978
|
+
/>
|
|
979
|
+
</Menu>
|
|
980
|
+
<FilledButton
|
|
981
|
+
onClick={() => setIsOpen(true)}
|
|
982
|
+
ref={anchorEl}
|
|
983
|
+
aria-haspopup="menu"
|
|
984
|
+
aria-expanded={isOpen}
|
|
985
|
+
>
|
|
986
|
+
Open Menu
|
|
987
|
+
</FilledButton>
|
|
988
|
+
</>
|
|
989
|
+
);
|
|
990
|
+
};
|
|
991
|
+
|
|
992
|
+
export default Component;
|
|
993
|
+
```
|