Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ui.menu component #1076

Merged
merged 44 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
1285148
menu trigger docs
dgodinez-dh Nov 25, 2024
053221a
merge latest
dgodinez-dh Nov 26, 2024
6d6acd0
finish menu trigger doc
dgodinez-dh Nov 26, 2024
bb1d7d1
initial menu doc
dgodinez-dh Nov 26, 2024
af1e12c
menu doc
dgodinez-dh Nov 26, 2024
45ccee9
item table source
dgodinez-dh Nov 26, 2024
3b24bb2
merge latest
dgodinez-dh Dec 2, 2024
183f80d
Apply suggestions from code review
dgodinez-dh Dec 9, 2024
1fddb44
merge latest
dgodinez-dh Dec 30, 2024
ffad948
merge latest
dgodinez-dh Dec 30, 2024
854c347
remove table source example
dgodinez-dh Dec 30, 2024
865e52c
menu_trigger.py
dgodinez-dh Dec 30, 2024
82e55be
submenu_trigger
dgodinez-dh Dec 30, 2024
58ed5ea
contextual help trigger
dgodinez-dh Dec 30, 2024
44067f7
inital menu.py
dgodinez-dh Dec 30, 2024
5dc1f34
update props
dgodinez-dh Dec 31, 2024
d3c7b48
finish menu props
dgodinez-dh Dec 31, 2024
8033b58
python init
dgodinez-dh Dec 31, 2024
9e50c87
initial js
dgodinez-dh Dec 31, 2024
ec591a4
hook up js
dgodinez-dh Dec 31, 2024
872bc78
revert version change
dgodinez-dh Dec 31, 2024
cfd5b3c
update to version 101
dgodinez-dh Dec 31, 2024
29763f5
add type for elementComponentMap
dgodinez-dh Jan 3, 2025
878aec3
add export
dgodinez-dh Jan 3, 2025
a4ea0a9
unavailable items
dgodinez-dh Jan 3, 2025
6425c60
fix menutrigger docs
dgodinez-dh Jan 6, 2025
ae244f6
fix menu docs
dgodinez-dh Jan 6, 2025
210bfe1
fix selection
dgodinez-dh Jan 6, 2025
34639cf
fix todo
dgodinez-dh Jan 6, 2025
7d90a5e
merge latest
dgodinez-dh Jan 6, 2025
8d1ad2b
code clean up
dgodinez-dh Jan 6, 2025
a16d839
update snapshots
dgodinez-dh Jan 6, 2025
66be7a3
menu trigger docs clean up
dgodinez-dh Jan 6, 2025
fdf67cd
fix ts error for TabPanels
dgodinez-dh Jan 6, 2025
7dd4718
Apply suggestions from code review
dgodinez-dh Jan 10, 2025
15c9633
add line about menu trigger
dgodinez-dh Jan 10, 2025
f8bc172
updates from review
dgodinez-dh Jan 10, 2025
4177d06
fix selection type
dgodinez-dh Jan 10, 2025
919662d
remove displayName
dgodinez-dh Jan 10, 2025
754c93d
on_change
dgodinez-dh Jan 10, 2025
d716ca5
Update plugins/ui/docs/components/menu_trigger.md
dgodinez-dh Jan 10, 2025
614f5be
fix doc string
dgodinez-dh Jan 10, 2025
b59f939
Apply suggestions from code review
dgodinez-dh Jan 10, 2025
5957c41
code review update
dgodinez-dh Jan 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130,549 changes: 120,939 additions & 9,610 deletions package-lock.json

Large diffs are not rendered by default.

263 changes: 263 additions & 0 deletions plugins/ui/docs/components/menu.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
# Menu

Menus display a list of actions or options that a user can choose.

## Example

```python
from deephaven import ui


my_menu_example = ui.menu_trigger(
bmingles marked this conversation as resolved.
Show resolved Hide resolved
ui.action_button("Edit"),
ui.menu(
ui.item("Cut", key="cut"),
ui.item("Copy", key="copy"),
ui.item("Paste", key="paste"),
ui.item("Replace", key="replace"),
on_action=lambda key: print(key),
),
)
```

## Content

Menu accepts `item` elements as children, each with a `key` prop. Basic usage of `menu`, seen in the example above, shows multiple items populated with a string.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you say "Menu" do you really mean menu? Or "Menus accept / A menu accepts"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to:
A menu accepts


## Events

Use the `on_selection_change` prop as a callback to handle press events on items when `selection_mode` is either `single` or `multiple`. See Selection for more information.
dgodinez-dh marked this conversation as resolved.
Show resolved Hide resolved

Menu also supports the `on_action` callback when `selection_mode` is `none` (default).

```python
from deephaven import ui


@ui.component
def open_action_example():
action, set_action = ui.use_state()
return ui.flex(
ui.menu_trigger(
ui.action_button("Edit"),
ui.menu(
ui.item("Cut", key="cut"),
ui.item("Copy", key="copy"),
ui.item("Paste", key="paste"),
on_action=set_action,
),
),
ui.text(f"Action {action}"),
gap="size-100",
align_items="center",
)


my_open_action_example = open_action_example()
```

## Selection

Menu supports multiple selection modes. By default, selection is disabled, however this can be changed using the `selection_mode` prop. Use `default_selected_keys` to provide a default set of selected items (uncontrolled) or `selected_keys` to set the selected items (controlled). The value of the selected keys must match the key prop of the items.
dgodinez-dh marked this conversation as resolved.
Show resolved Hide resolved

```python
from deephaven import ui


@ui.component
def single_selection_example():
selected, set_selected = ui.use_state(["middle"])
return ui.flex(
ui.menu_trigger(
ui.action_button("Align"),
ui.menu(
ui.item("Left", key="left"),
ui.item("Middle", key="middle"),
ui.item("Right", key="right"),
selection_mode="single",
selected_keys=selected,
on_selection_change=set_selected,
),
),
ui.text(f"Current selection (controlled) {selected}"),
gap="size-100",
align_items="center",
)


my_single_selection_example = single_selection_example()
```

Set `selection_mode` prop to `multiple` to allow more than one selection.

```python
from deephaven import ui


@ui.component
def multiple_selection_example():
selected, set_selected = ui.use_state(["sidebar", "console"])
return ui.flex(
ui.menu_trigger(
ui.action_button("Show"),
ui.menu(
ui.item("Sidebar", key="sidebar"),
ui.item("Searchbar", key="searchbar"),
ui.item("Tools", key="tools"),
ui.item("Console", key="console"),
selection_mode="multiple",
selected_keys=selected,
on_selection_change=set_selected,
),
close_on_select=False,
),
ui.text(f"Current selection (controlled) {selected}"),
gap="size-100",
align_items="center",
)


my_multiple_selection_example = multiple_selection_example()
```

## Links

By default, interacting with an item in a Menu triggers `on_action` and optionally `on_selection_change` depending on the `selection_mode`. Alternatively, items may be links to another page or website. This can be achieved by passing the `href` prop to the `item` component. Link items in a menu are not selectable.

```python
from deephaven import ui


my_link_example = ui.menu_trigger(
ui.action_button("Links"),
ui.menu(
ui.item("Adobe", href="https://adobe.com/", target="_blank"),
ui.item("Apple", href="https://apple.com/", target="_blank"),
ui.item("Google", href="https://google.com/", target="_blank"),
ui.item("Microsoft", href="https://microsoft.com/", target="_blank"),
),
)
```

## Sections

```python
from deephaven import ui


@ui.component
def sections_example():
selected, set_selected = ui.use_state(["bold", "left"])
return (
ui.menu_trigger(
ui.action_button("Show"),
ui.menu(
ui.section(
ui.item("Bold", key="bold"),
ui.item("Underline", key="underline"),
title="Styles",
),
ui.section(
ui.item("Left", key="left"),
ui.item("Middle", key="middle"),
ui.item("Right", key="right"),
title="Align",
),
selection_mode="multiple",
selected_keys=selected,
on_selection_change=set_selected,
),
close_on_select=False,
),
)


my_sections_example = sections_example()
```

## Unavailable Items
dgodinez-dh marked this conversation as resolved.
Show resolved Hide resolved

`contextual_help_trigger` disables a menu item's action and replaces it with a popover with information on why the item is unavailable and may link users to more information elsewhere.

The `contextual_help_trigger` accepts exactly two children: the `item` which triggers opening of the `dialog` and the Dialog itself. The trigger must be the first child passed into the `contextual_help_trigger` and should be an `item`. Similar to `contextual_help`, the layout of the `dialog` is very deliberate. See [`contextual_help`](./contextual_help.md) for further explanation.

Setting the `is_unavailable` prop on the `contextual_help_trigger` makes the menu item unavailable and enables the `dialog` with contextual help, allowing for programmatic control.

Note that the `menu's` `on_action` and `on_selection_change` callbacks will not fire for items made unavailable by a `contextual_help_trigger`.

The example below illustrates how one would setup a `menu` to use `contextual_help_trigger`.
dgodinez-dh marked this conversation as resolved.
Show resolved Hide resolved

```python
from deephaven import ui


my_menu_example = ui.menu_trigger(
ui.action_button("Edit"),
ui.menu(
ui.item("Undo", key="undo"),
ui.item("Redo", key="redo"),
ui.contextual_help_trigger(
ui.item("Cut", key="cut"),
ui.dialog(
ui.heading("Cut"),
ui.content("Please select text for 'Cut' to be enabled."),
),
is_unavailable=True,
),
ui.contextual_help_trigger(
ui.item("Copy", key="copy"),
ui.dialog(
ui.heading("Copy"),
ui.content("Please select text for 'Copy' to be enabled."),
),
is_unavailable=True,
),
ui.contextual_help_trigger(
ui.item("Paste", key="paste"),
ui.dialog(ui.heading("Paste"), ui.content("You have nothing to 'Paste'.")),
bmingles marked this conversation as resolved.
Show resolved Hide resolved
),
),
)
```

## Submenus

Submenus can be created by wrapping an item and a menu in a `submenu_trigger`. The `submenu_trigger` accepts exactly two children: the `item` which triggers opening of the submenu, and the `menu` itself. Each submenu's `menu` accepts its own set of menu props, allowing you to customize its user action and selection behavior.

```python
from deephaven import ui


my_submenu_example = ui.menu_trigger(
ui.action_button("Actions"),
ui.menu(
ui.item("Cut", key="cut"),
ui.item("Copy", key="copy"),
ui.item("Paste", key="paste"),
ui.submenu_trigger(
ui.item("Share", key="share"),
ui.menu(
ui.item("Copy link", key="copy link"),
ui.submenu_trigger(
ui.item("Email", key="email"),
ui.menu(
ui.item("Email as attachment", key="attachment"),
ui.item("Email as link", key="link"),
on_action=lambda key: print(f"Email menu {key} action"),
),
),
ui.item("SMS", key="sms"),
on_action=lambda key: print(f"Share menu {key} action"),
),
),
ui.item("Delete", key="delete"),
on_action=lambda key: print(f"Root menu {key} action"),
),
)
```

## API Reference

```{eval-rst}
.. dhautofunction:: deephaven.ui.menu
```
Loading
Loading