diff --git a/plugins/ui/src/deephaven/ui/components/__init__.py b/plugins/ui/src/deephaven/ui/components/__init__.py index 80fcdf5bc..2f3903fee 100644 --- a/plugins/ui/src/deephaven/ui/components/__init__.py +++ b/plugins/ui/src/deephaven/ui/components/__init__.py @@ -21,6 +21,7 @@ from .date_range_picker import date_range_picker from .dialog import dialog from .dialog_trigger import dialog_trigger +from .disclosure import disclosure from .flex import flex from .form import form from .fragment import fragment @@ -93,6 +94,7 @@ "date_range_picker", "dialog", "dialog_trigger", + "disclosure", "flex", "form", "fragment", diff --git a/plugins/ui/src/deephaven/ui/components/disclosure.py b/plugins/ui/src/deephaven/ui/components/disclosure.py new file mode 100644 index 000000000..3326b33ba --- /dev/null +++ b/plugins/ui/src/deephaven/ui/components/disclosure.py @@ -0,0 +1,185 @@ +from __future__ import annotations +from typing import Any, Callable +from .types import ( + AlignSelf, + CSSProperties, + DimensionValue, + JustifySelf, + LayoutFlex, + Position, +) +from .basic import component_element +from ..elements import Element + + +def disclosure( + title: Any, + panel: Any, + *, + is_quiet: bool | None = None, + is_disabled: bool | None = None, + is_expanded: bool | None = None, + default_expanded: bool | None = None, + on_expanded_change: Callable[[bool], None] | None = None, + flex: LayoutFlex | None = None, + flex_grow: float | None = None, + flex_shrink: float | None = None, + flex_basis: DimensionValue | None = None, + align_self: AlignSelf | None = None, + justify_self: JustifySelf | None = None, + order: int | None = None, + grid_area: str | None = None, + grid_row: str | None = None, + grid_column: str | None = None, + grid_column_start: str | None = None, + grid_column_end: str | None = None, + grid_row_start: str | None = None, + grid_row_end: str | None = None, + slot: str | None = None, + margin: DimensionValue | None = None, + margin_top: DimensionValue | None = None, + margin_bottom: DimensionValue | None = None, + margin_start: DimensionValue | None = None, + margin_end: DimensionValue | None = None, + margin_x: DimensionValue | None = None, + margin_y: DimensionValue | None = None, + width: DimensionValue | None = None, + height: DimensionValue | None = None, + min_width: DimensionValue | None = None, + min_height: DimensionValue | None = None, + max_width: DimensionValue | None = None, + max_height: DimensionValue | None = None, + position: Position | None = None, + top: DimensionValue | None = None, + bottom: DimensionValue | None = None, + left: DimensionValue | None = None, + right: DimensionValue | None = None, + start: DimensionValue | None = None, + end: DimensionValue | None = None, + z_index: int | None = None, + is_hidden: bool | None = None, + id: str | None = None, + aria_label: str | None = None, + aria_labelledby: str | None = None, + aria_describedby: str | None = None, + aria_details: str | None = None, + UNSAFE_class_name: str | None = None, + UNSAFE_style: CSSProperties | None = None, + key: str | None = None, +) -> Element: + """ + A collapsible section of content with a heading that toggles the visibility of a panel. + + Args: + title: The title of the disclosure. + panel: The content of the disclosure. + is_quiet: Whether the element is displayed with a quiet style. + is_disabled: Whether the element is disabled. + is_expanded: Whether the element is expanded (controlled). + default_expanded: Whether the element is expanded by default (uncontrolled). + on_expanded_change: Handler that is called when the element's expanded state changes. + flex: When used in a flex layout, specifies how the element will grow or shrink to fit the space available. + flex_grow: When used in a flex layout, specifies how the element will grow to fit the space available. + flex_shrink: When used in a flex layout, specifies how the element will shrink to fit the space available. + flex_basis: When used in a flex layout, specifies the initial main size of the element. + align_self: Overrides the alignItems property of a flex or grid container. + justify_self: Species how the element is justified inside a flex or grid container. + order: The layout order for the element within a flex or grid container. + grid_area: When used in a grid layout specifies, specifies the named grid area that the element should be placed in within the grid. + grid_row: When used in a grid layout, specifies the row the element should be placed in within the grid. + grid_column: When used in a grid layout, specifies the column the element should be placed in within the grid. + grid_row_start: When used in a grid layout, specifies the starting row to span within the grid. + grid_row_end: When used in a grid layout, specifies the ending row to span within the grid. + grid_column_start: When used in a grid layout, specifies the starting column to span within the grid. + grid_column_end: When used in a grid layout, specifies the ending column to span within the grid. + slot: Slot name for the element. Slows enable components to receive props from a parent component. An explicit null indicates that local props override parent props. + margin: The margin for all four sides of the element. + margin_top: The margin for the top side of the element. + margin_bottom: The margin for the bottom side of the element. + margin_start: The margin for the logical start side of the element, depending on layout direction. + margin_end: The margin for the logical end side of the element, depending on layout direction. + margin_x: The margin for the left and right sides of the element. + margin_y: The margin for the top and bottom sides of the element. + width: The width of the element. + height: The height of the element. + min_width: The minimum width of the element. + min_height: The minimum height of the element. + max_width: The maximum width of the element. + max_height: The maximum height of the element. + position: Specifies how the element is position. + top: The top position of the element. + bottom: The bottom position of the element. + left: The left position of the element. + right: The right position of the element. + start: The logical start position of the element, depending on layout direction. + end: The logical end position of the element, depending on layout direction. + z_index: The stacking order for the element + is_hidden: Hides the element. + id: The unique identifier of the element. + aria_label: Defines a string value that labels the current element. + aria_labelledby: Identifies the element (or elements) that labels the current element. + aria_describedby: Identifies the element (or elements) that describes the object. + aria_details: Identifies the element (or elements) that provide a detailed, extended description for the object. + UNSAFE_class_name: Set the CSS className for the element. Only use as a last resort. Use style props instead. + UNSAFE_style: Set the inline style for the element. Only use as a last resort. Use style props instead. + key: A unique identifier used by React to render elements in a list. + + Returns: + The rendered contextual help component. + + """ + return component_element( + "Disclosure", + title=title, + panel=panel, + is_quiet=is_quiet, + is_disabled=is_disabled, + is_expanded=is_expanded, + default_expanded=default_expanded, + on_expanded_change=on_expanded_change, + flex=flex, + flex_grow=flex_grow, + flex_shrink=flex_shrink, + flex_basis=flex_basis, + align_self=align_self, + justify_self=justify_self, + order=order, + grid_area=grid_area, + grid_row=grid_row, + grid_column=grid_column, + grid_column_start=grid_column_start, + grid_column_end=grid_column_end, + grid_row_start=grid_row_start, + grid_row_end=grid_row_end, + slot=slot, + margin=margin, + margin_top=margin_top, + margin_bottom=margin_bottom, + margin_start=margin_start, + margin_end=margin_end, + margin_x=margin_x, + margin_y=margin_y, + width=width, + height=height, + min_width=min_width, + min_height=min_height, + max_width=max_width, + max_height=max_height, + position=position, + top=top, + bottom=bottom, + left=left, + right=right, + start=start, + end=end, + z_index=z_index, + is_hidden=is_hidden, + id=id, + aria_label=aria_label, + aria_labelledby=aria_labelledby, + aria_describedby=aria_describedby, + aria_details=aria_details, + UNSAFE_class_name=UNSAFE_class_name, + UNSAFE_style=UNSAFE_style, + key=key, + ) diff --git a/plugins/ui/src/js/src/elements/Disclosure.tsx b/plugins/ui/src/js/src/elements/Disclosure.tsx new file mode 100644 index 000000000..027aaa676 --- /dev/null +++ b/plugins/ui/src/js/src/elements/Disclosure.tsx @@ -0,0 +1,36 @@ +import { + Disclosure as DHCDisclosure, + DisclosureProps as DHCDisclosureProps, + DisclosureTitle as DHCDisclosureTitle, + DisclosurePanel as DHCDisclosurePanel, +} from '@deephaven/components'; +import { isElementOfType } from '@deephaven/react-hooks'; +import { ReactNode } from 'react'; + +export type SerializedDisclosureProps = Omit & { + title: ReactNode; + panel: ReactNode; +}; + +export function Disclosure(props: DHCDisclosureProps): JSX.Element { + const { title, panel, ...otherProps } = props; + return ( + /* eslint-disable-next-line react/jsx-props-no-spreading */ + + {title != null && + (isElementOfType(title, DHCDisclosureTitle) ? ( + title + ) : ( + {title} + ))} + {panel != null && + (isElementOfType(panel, DHCDisclosurePanel) ? ( + panel + ) : ( + {panel} + ))} + + ); +} + +export default Disclosure; diff --git a/plugins/ui/src/js/src/elements/index.ts b/plugins/ui/src/js/src/elements/index.ts index 02443263d..60ef3c93b 100644 --- a/plugins/ui/src/js/src/elements/index.ts +++ b/plugins/ui/src/js/src/elements/index.ts @@ -9,6 +9,7 @@ export * from './DateField'; export * from './DatePicker'; export * from './DateRangePicker'; export * from './Dialog'; +export * from './Disclosure'; export * from './Flex'; export * from './Form'; export * from './Grid'; diff --git a/plugins/ui/src/js/src/elements/model/ElementConstants.ts b/plugins/ui/src/js/src/elements/model/ElementConstants.ts index f5e148347..dfeff6cbb 100644 --- a/plugins/ui/src/js/src/elements/model/ElementConstants.ts +++ b/plugins/ui/src/js/src/elements/model/ElementConstants.ts @@ -41,6 +41,7 @@ export const ELEMENT_NAME = { dateRangePicker: uiComponentName('DateRangePicker'), dialog: uiComponentName('Dialog'), dialogTrigger: uiComponentName('DialogTrigger'), + disclosure: uiComponentName('Disclosure'), flex: uiComponentName('Flex'), form: uiComponentName('Form'), fragment: uiComponentName('Fragment'), diff --git a/plugins/ui/src/js/src/widget/WidgetUtils.tsx b/plugins/ui/src/js/src/widget/WidgetUtils.tsx index 868fa9352..8cef731ec 100644 --- a/plugins/ui/src/js/src/widget/WidgetUtils.tsx +++ b/plugins/ui/src/js/src/widget/WidgetUtils.tsx @@ -59,6 +59,7 @@ import { DatePicker, DateRangePicker, Dialog, + Disclosure, Flex, Form, Grid, @@ -134,6 +135,7 @@ export const elementComponentMap = { [ELEMENT_NAME.dateRangePicker]: DateRangePicker, [ELEMENT_NAME.dialog]: Dialog, [ELEMENT_NAME.dialogTrigger]: DialogTrigger, + [ELEMENT_NAME.disclosure]: Disclosure, [ELEMENT_NAME.flex]: Flex, [ELEMENT_NAME.form]: Form, [ELEMENT_NAME.fragment]: React.Fragment,