diff --git a/plugins/ui/DESIGN.md b/plugins/ui/DESIGN.md index fbbfd49c3..43e6ca30e 100644 --- a/plugins/ui/DESIGN.md +++ b/plugins/ui/DESIGN.md @@ -1188,6 +1188,50 @@ picker7 = ui.picker( ) ``` +###### ui.list_action_group +A group of action buttons that can be used to create a list of actions. +This component should be used within the actions prop of a `ListView` component. + +```py +def list_action_group( + *children: ActionGroupItem, + on_action: Callable[[ActionKey, Key], None] | None = None, + on_selection_change: Callable[[Selection, Key], None] | None = None, + **props: Any +) -> ListActionGroupElement: +``` + +###### Parameters +| Parameter | Type | Description | +|-------------------------|------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------| +| `*children` | `ActionGroupItem` | The actions to render within the action group. | +| `on_action` | `Callable[[ActionKey, Key], None] \| None` | Handler that is called when an item is pressed. The first argument is the key of the action, the second argument is the key of the list_view item. | +| `on_selection_change` | `Callable[[Selection, Key], None] \| None` | Handler that is called when the selection changes. The first argument is the selection, the second argument is the key of the list_view item. | +| `**props` | `Any` | Any other [ActionGroup](https://react-spectrum.adobe.com/react-spectrum/ActionGroup.html) prop. | + + + +###### ui.list_action_menu +A group of action buttons that can be used to create a list of actions. +This component should be used within the actions prop of a `ListView` component. + +```py +def list_action_menu( + *children: ActionMenuItem, + on_action: Callable[[ActionKey, Key], None] | None = None, + on_open_change: Callable[[bool, Key], None] | None = None, + **props: Any +) -> ListActionMenuElement: +``` + +###### Parameters +| Parameter | Type | Description | +|-------------------------|------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------| +| `*children` | `ActionMenuItem` | The options to render within the picker. | +| `on_action` | `Callable[[ActionKey, Key], None] \| None` | Handler that is called when an item is pressed. The first argument is the key of the action, the second argument is the key of the list_view item. | +| `on_open_change` | `Callable[[bool, Key], None] \| None` | The first argument is a boolean indicating if the menu is open, the second argument is the key of the list_view item. | +| `**props` | `Any` | Any other [ActionMenu](https://react-spectrum.adobe.com/react-spectrum/ActionMenu.html) prop. | + ###### ui.list_view A list view that can be used to create a list of items. Children should be one of two types: 1. If children are of type `ListViewItem`, they are the list items. @@ -1201,7 +1245,7 @@ ui.list_view( label_column: ColumnName | None = None, description_column: ColumnName | None = None, icon_column: ColumnName | None = None, - action_buttons: ActionButtonElement | ActionGroupElement | ActionMenuElement | None = None, + actions: ListActionGroupElement | ListActionMenuElement | None = None, default_selected_keys: Selection | None = None, selected_keys: Selection | None = None, render_empty_state: Element | None = None, @@ -1212,20 +1256,20 @@ ui.list_view( ``` ###### Parameters -| Parameter | Type | Description | -|------------------------------|----------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `*children` | `ListViewItem \| Table` | The options to render within the picker. | -| `key_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to use as item keys. Defaults to the first column. | -| `label_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to display as primary text. Defaults to the `key_column` value. | -| `description_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to display as descriptions. | -| `icon_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to map to icons. | -| `action_buttons` | `ActionButtonElement \| ActionGroupElement \| ActionMenuElement \| None` | Only valid if any `ListViewItem` children do not already have embedded buttons. The action buttons to render for all elements within the list view. The `on_*` event handlers within the passed object will be modified so that the second argument is the key for the `list_view` item that the buttons are embedded in. | -| `default_selected_keys` | `Selection \| None` | The initial selected keys in the collection (uncontrolled). | -| `selected_keys` | `Selection \| None` | The currently selected keys in the collection (controlled). | -| `render_empty_state` | `Element \| None` | Sets what the `list_view` should render when there is no content to display. | -| `on_selection_change` | `Callable[[Selection], None] \| None` | Handler that is called when the selections changes. | -| `on_change` | `Callable[[Selection], None] \| None` | Alias of `on_selection_change`. Handler that is called when the selections changes. | -| `**props` | `Any` | Any other [ListView](https://react-spectrum.adobe.com/react-spectrum/ListView.html) prop, with the exception of `items`, `dragAndDropHooks`, and `onLoadMore`. | +| Parameter | Type | Description | +|-------------------------|------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `*children` | `ListViewItem \| Table` | The options to render within the picker. | +| `key_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to use as item keys. Defaults to the first column. | +| `label_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to display as primary text. Defaults to the `key_column` value. | +| `description_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to display as descriptions. | +| `icon_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to map to icons. | +| `actions` | `ListActionGroupElement \| ListActionMenuElement \| None` | Only valid if children are of type Table. The action group or menus to render for all elements within the list view. | +| `default_selected_keys` | `Selection \| None` | The initial selected keys in the collection (uncontrolled). | +| `selected_keys` | `Selection \| None` | The currently selected keys in the collection (controlled). | +| `render_empty_state` | `Element \| None` | Sets what the `list_view` should render when there is no content to display. | +| `on_selection_change` | `Callable[[Selection], None] \| None` | Handler that is called when the selections changes. | +| `on_change` | `Callable[[Selection], None] \| None` | Alias of `on_selection_change`. Handler that is called when the selections changes. | +| `**props` | `Any` | Any other [ListView](https://react-spectrum.adobe.com/react-spectrum/ListView.html) prop, with the exception of `items`, `dragAndDropHooks`, and `onLoadMore`. | ```py @@ -1298,15 +1342,15 @@ list_view5 = ui.list_view( # Buttons can be embedded in the list view. Note key is added to the on_press handler, but is not required. -on_button_action = lambda e, key: print(f"Event {e} was emitted for list item {key}") -button = ui.action_button("Print Item", on_press=on_button_action) +on_button_action = lambda action_key, key: print(f"Action {action_key} was pressed for list item {key}") +button = ui.list_action_group("Print Item", on_action=on_button_action) list_view7 = ui.list_view( "Option 1", "Option 2", "Option 3", "Option 4", - action_buttons=button, + actions=button, ) ``` @@ -1826,6 +1870,7 @@ TransformedData = Any Stringable = str | int | float | bool PickerItem = Stringable | ItemElement Key = Stringable +ActionKey = Key Selection = Sequence[Key] ListViewItem = Stringable | ItemElement diff --git a/plugins/ui/src/deephaven/ui/components/__init__.py b/plugins/ui/src/deephaven/ui/components/__init__.py index 02d648588..f0678f892 100644 --- a/plugins/ui/src/deephaven/ui/components/__init__.py +++ b/plugins/ui/src/deephaven/ui/components/__init__.py @@ -11,6 +11,9 @@ from .picker import picker from .section import section from .item import item +from .list_view import list_view +from .list_action_group import list_action_group +from .list_action_menu import list_action_menu from . import html @@ -34,6 +37,9 @@ "icon_wrapper", "item", "illustrated_message", + "list_view", + "list_action_group", + "list_action_menu", "html", "number_field", "panel", diff --git a/plugins/ui/src/deephaven/ui/components/list_action_group.py b/plugins/ui/src/deephaven/ui/components/list_action_group.py new file mode 100644 index 000000000..c7f9840db --- /dev/null +++ b/plugins/ui/src/deephaven/ui/components/list_action_group.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +from typing import Callable, Any, Union + +from .item import ItemElement +from ..elements import BaseElement, Element +from .._internal.utils import create_props +from ..types import Stringable, Selection, Key, ActionKey + +ActionGroupItem = Union[Stringable, ItemElement] +ListActionGroupElement = Element + + +def list_action_group( + *children: ActionGroupItem, + on_action: Callable[[ActionKey, Key], None] | None = None, + on_selection_change: Callable[[Selection, Key], None] | None = None, + **props: Any, +) -> ListActionGroupElement: + """ + A group of action buttons that can be used to create a list of actions. + This component should be used within the actions prop of a `ListView` component. + + Args: + *children: The options to render within the list_action_group. + on_action: Handler that is called when an item is pressed. + The first argument is the key of the action, the second argument is the key of the list_view item. + on_selection_change: Handler that is called when the selection changes. + The first argument is the selection, the second argument is the key of the list_view item. + **props: Any other ActionGroup prop. + + Returns: + A ListActionGroup that can be used within the actions prop of a `ListView` component. + """ + children, props = create_props(locals()) + + return BaseElement("deephaven.ui.components.ListActionGroup", *children, **props) diff --git a/plugins/ui/src/deephaven/ui/components/list_action_menu.py b/plugins/ui/src/deephaven/ui/components/list_action_menu.py new file mode 100644 index 000000000..7a9eb0af5 --- /dev/null +++ b/plugins/ui/src/deephaven/ui/components/list_action_menu.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +from typing import Callable, Any, Union + + +from .item import ItemElement +from ..elements import BaseElement, Element +from .._internal.utils import create_props +from ..types import Stringable, Key, ActionKey + +ActionMenuItem = Union[Stringable, ItemElement] +ListActionMenuElement = Element + + +def list_action_menu( + *children: ActionMenuItem, + on_action: Callable[[ActionKey, Key], None] | None = None, + on_open_change: Callable[[bool, Key], None] | None = None, + **props: Any, +) -> ListActionMenuElement: + """ + A menu of action buttons that can be used to create a list of actions. + This component should be used within the actions prop of a `ListView` component. + + Args: + *children: The options to render within the list_action_menu. + on_action: Handler that is called when an item is selected. + The first argument is the key of the action, the second argument is the key of the list_view item. + on_open_change: Handler that is called when the menu is opened or closed. + The first argument is a boolean indicating if the menu is open, the second argument is the key of the list_view item. + **props: Any other ActionMenu prop. + + Returns: + A ListActionMenu that can be used within the actions prop of a `ListView` component. + """ + children, props = create_props(locals()) + + return BaseElement("deephaven.ui.components.ListActionMenu", *children, **props) diff --git a/plugins/ui/src/deephaven/ui/components/list_view.py b/plugins/ui/src/deephaven/ui/components/list_view.py new file mode 100644 index 000000000..f467ba0de --- /dev/null +++ b/plugins/ui/src/deephaven/ui/components/list_view.py @@ -0,0 +1,73 @@ +from __future__ import annotations + +from typing import Callable, Any, Union + +from deephaven.table import Table + +from .item import ItemElement +from .list_action_group import ListActionGroupElement +from .list_action_menu import ListActionMenuElement +from ..elements import BaseElement, Element +from .._internal.utils import create_props +from ..types import ColumnName, Stringable, Selection + +ListViewItem = Union[Stringable, ItemElement] +ListViewElement = Element + + +def list_view( + *children: ListViewItem | Table, + key_column: ColumnName | None = None, + label_column: ColumnName | None = None, + description_column: ColumnName | None = None, + icon_column: ColumnName | None = None, + actions: ListActionGroupElement | ListActionMenuElement | None = None, + default_selected_keys: Selection | None = None, + selected_keys: Selection | None = None, + render_empty_state: Element | None = None, + on_selection_change: Callable[[Selection], None] | None = None, + on_change: Callable[[Selection], None] | None = None, + **props: Any, +) -> ListViewElement: + """ + A list view that can be used to create a list of items. Children should be one of two types: + 1. If children are of type `ListViewItem`, they are the list items. + 2. If children are of type `Table`, the values in the table are the list items. + There can only be one child, the `Table`. + + + Args: + *children: The options to render within the list_view. + key_column: + Only valid if children are of type Table. + The column of values to use as item keys. Defaults to the first column. + label_column: + Only valid if children are of type Table. + The column of values to display as primary text. Defaults to the key_column value. + description_column: + Only valid if children are of type Table. + The column of values to display as descriptions. + icon_column: Only valid if children are of type Table. + The column of values to map to icons. + actions: + Only valid if children are of type Table. + The action group or menus to render for all elements within the list view. + default_selected_keys: + The initial selected keys in the collection (uncontrolled). + selected_keys: + The currently selected keys in the collection (controlled). + render_empty_state: + Sets what the `list_view` should render when there is no content to display. + on_selection_change: + Handler that is called when the selection changes. + on_change: + Alias of `on_selection_change`. Handler that is called when the selection changes. + **props: + Any other ListView prop, except items, dragAndDropHooks, and onLoadMore. + + Returns: + The rendered ListView. + """ + children, props = create_props(locals()) + + return BaseElement("deephaven.ui.components.ListView", *children, **props) diff --git a/plugins/ui/src/deephaven/ui/components/spectrum/action_button.py b/plugins/ui/src/deephaven/ui/components/spectrum/action_button.py index 3b322b5cf..d8d99d9b2 100644 --- a/plugins/ui/src/deephaven/ui/components/spectrum/action_button.py +++ b/plugins/ui/src/deephaven/ui/components/spectrum/action_button.py @@ -20,6 +20,8 @@ from .basic import spectrum_element from ...elements import Element +ActionButtonElement = Element + def action_button( *children: Any, @@ -86,7 +88,7 @@ def action_button( aria_details: str | None = None, UNSAFE_class_name: str | None = None, UNSAFE_style: CSSProperties | None = None, -) -> Element: +) -> ActionButtonElement: """ ActionButtons allow users to perform an action. They're used for similar, task-based options within a workflow, and are ideal for interfaces where buttons aren't meant to draw a lot of attention. Python implementation for the Adobe React Spectrum ActionButton component: https://react-spectrum.adobe.com/react-spectrum/ActionButton.html diff --git a/plugins/ui/src/deephaven/ui/types/types.py b/plugins/ui/src/deephaven/ui/types/types.py index 7962f207d..90bfd8480 100644 --- a/plugins/ui/src/deephaven/ui/types/types.py +++ b/plugins/ui/src/deephaven/ui/types/types.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, Literal, Union, List, Tuple, Callable, TypedDict +from typing import Any, Dict, Literal, Union, List, Tuple, Callable, TypedDict, Sequence from deephaven import SortDirection @@ -105,4 +105,7 @@ class RowDataValue(CellData): # Stringable is a type that is naturally convertible to a string Stringable = Union[str, int, float, bool] Key = Stringable +ActionKey = Key + Dependencies = Union[Tuple[Any], List[Any]] +Selection = Sequence[Key]