From ba8200e638bd4847453faae8bf6cd8aeb6d99e50 Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Wed, 11 Dec 2024 18:14:51 +0100 Subject: [PATCH 1/3] new Tooltip component (as property) --- chartlets.js/CHANGES.md | 4 +- .../packages/lib/src/plugins/mui/Button.tsx | 29 ++++++++------ .../packages/lib/src/plugins/mui/Checkbox.tsx | 32 ++++++++------- .../lib/src/plugins/mui/IconButton.tsx | 26 +++++++----- .../packages/lib/src/plugins/mui/Select.tsx | 40 ++++++++++--------- .../lib/src/plugins/mui/Tooltip.test.tsx | 16 ++++++++ .../packages/lib/src/plugins/mui/Tooltip.tsx | 11 +++++ .../packages/lib/src/types/state/component.ts | 1 + 8 files changed, 102 insertions(+), 57 deletions(-) create mode 100644 chartlets.js/packages/lib/src/plugins/mui/Tooltip.test.tsx create mode 100644 chartlets.js/packages/lib/src/plugins/mui/Tooltip.tsx diff --git a/chartlets.js/CHANGES.md b/chartlets.js/CHANGES.md index 72883035..f577a746 100644 --- a/chartlets.js/CHANGES.md +++ b/chartlets.js/CHANGES.md @@ -37,9 +37,11 @@ - using `schema` instead of `type` property for callback arguments - using `return` object with `schema` property for callback return values -* New components +* New (MUI) components - `LinearProgress` +* Supporting `tooltip` property for interactive MUI components. + ## Version 0.0.29 (from 2024/11/26) * Resolved warnings that appeared when using Vega charts. diff --git a/chartlets.js/packages/lib/src/plugins/mui/Button.tsx b/chartlets.js/packages/lib/src/plugins/mui/Button.tsx index 4c68263a..5e639270 100644 --- a/chartlets.js/packages/lib/src/plugins/mui/Button.tsx +++ b/chartlets.js/packages/lib/src/plugins/mui/Button.tsx @@ -3,6 +3,7 @@ import MuiButton from "@mui/material/Button"; import MuiIcon from "@mui/material/Icon"; import type { ComponentState, ComponentProps } from "@/index"; +import { Tooltip } from "./Tooltip"; interface ButtonState extends ComponentState { text?: string; @@ -45,18 +46,20 @@ export function Button({ } }; return ( - {startIcon}} - endIcon={endIcon && {endIcon}} - onClick={handleClick} - > - {text} - + + {startIcon}} + endIcon={endIcon && {endIcon}} + onClick={handleClick} + > + {text} + + ); } diff --git a/chartlets.js/packages/lib/src/plugins/mui/Checkbox.tsx b/chartlets.js/packages/lib/src/plugins/mui/Checkbox.tsx index 7133a7d4..7457cc66 100644 --- a/chartlets.js/packages/lib/src/plugins/mui/Checkbox.tsx +++ b/chartlets.js/packages/lib/src/plugins/mui/Checkbox.tsx @@ -4,6 +4,7 @@ import MuiFormControl from "@mui/material/FormControl"; import MuiFormControlLabel from "@mui/material/FormControlLabel"; import type { ComponentState, ComponentProps } from "@/index"; +import { Tooltip } from "@mui/material"; interface CheckboxState extends ComponentState { label?: string; @@ -19,6 +20,7 @@ export function Checkbox({ value, disabled, style, + tooltip, label, onChange, }: CheckboxProps) { @@ -33,19 +35,21 @@ export function Checkbox({ } }; return ( - - - } - /> - + + + + } + /> + + ); } diff --git a/chartlets.js/packages/lib/src/plugins/mui/IconButton.tsx b/chartlets.js/packages/lib/src/plugins/mui/IconButton.tsx index 55887b9c..ef76e966 100644 --- a/chartlets.js/packages/lib/src/plugins/mui/IconButton.tsx +++ b/chartlets.js/packages/lib/src/plugins/mui/IconButton.tsx @@ -3,6 +3,7 @@ import MuiIconButton from "@mui/material/IconButton"; import MuiIcon from "@mui/material/Icon"; import type { ComponentState, ComponentProps } from "@/index"; +import { Tooltip } from "./Tooltip"; interface IconButtonState extends ComponentState { icon?: string; @@ -24,6 +25,7 @@ export function IconButton({ id, name, style, + tooltip, color, icon, size, @@ -41,16 +43,18 @@ export function IconButton({ } }; return ( - - {icon} - + + + {icon} + + ); } diff --git a/chartlets.js/packages/lib/src/plugins/mui/Select.tsx b/chartlets.js/packages/lib/src/plugins/mui/Select.tsx index 3fe51100..1cae59fd 100644 --- a/chartlets.js/packages/lib/src/plugins/mui/Select.tsx +++ b/chartlets.js/packages/lib/src/plugins/mui/Select.tsx @@ -5,6 +5,7 @@ import MuiSelect, { type SelectChangeEvent } from "@mui/material/Select"; import type { ComponentState, ComponentProps } from "@/index"; import { isString } from "@/utils/isString"; +import { Tooltip } from "./Tooltip"; export type SelectOption = | string @@ -27,6 +28,7 @@ export function Select({ options, disabled, style, + tooltip, label, onChange, }: SelectProps) { @@ -45,24 +47,26 @@ export function Select({ } }; return ( - - {label && {label}} - - {Array.isArray(options) && - options.map(normalizeSelectOption).map(([value, text], index) => ( - - {text} - - ))} - - + + + {label && {label}} + + {Array.isArray(options) && + options.map(normalizeSelectOption).map(([value, text], index) => ( + + {text} + + ))} + + + ); } diff --git a/chartlets.js/packages/lib/src/plugins/mui/Tooltip.test.tsx b/chartlets.js/packages/lib/src/plugins/mui/Tooltip.test.tsx new file mode 100644 index 00000000..a4c0f421 --- /dev/null +++ b/chartlets.js/packages/lib/src/plugins/mui/Tooltip.test.tsx @@ -0,0 +1,16 @@ +import { describe, it, expect } from "vitest"; +import { render, screen } from "@testing-library/react"; +import { Tooltip } from "./Tooltip"; + +describe("Tooltip", () => { + it("should render its child component", () => { + render( + + + , + ); + // to inspect rendered component, do: + // expect(document.querySelector("#typo")).toEqual({}); + expect(screen.getByText("Click Me")).not.toBeUndefined(); + }); +}); diff --git a/chartlets.js/packages/lib/src/plugins/mui/Tooltip.tsx b/chartlets.js/packages/lib/src/plugins/mui/Tooltip.tsx new file mode 100644 index 00000000..310db270 --- /dev/null +++ b/chartlets.js/packages/lib/src/plugins/mui/Tooltip.tsx @@ -0,0 +1,11 @@ +import MuiTooltip from "@mui/material/Tooltip"; +import type { ReactElement } from "react"; + +interface TooltipProps { + title?: string; + children: ReactElement; +} + +export function Tooltip({ title, children }: TooltipProps) { + return title ? {children} : children; +} diff --git a/chartlets.js/packages/lib/src/types/state/component.ts b/chartlets.js/packages/lib/src/types/state/component.ts index e2e5a2ca..5bb5033c 100644 --- a/chartlets.js/packages/lib/src/types/state/component.ts +++ b/chartlets.js/packages/lib/src/types/state/component.ts @@ -23,6 +23,7 @@ export interface ComponentState { disabled?: boolean; label?: string; color?: string; + tooltip?: string; } export interface ContainerState extends ComponentState { From beb059ee2d7f712e60432ab2596179a47500fc1b Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Thu, 12 Dec 2024 08:29:22 +0100 Subject: [PATCH 2/3] Added `tooltip` component property --- chartlets.py/CHANGES.md | 1 + chartlets.py/chartlets/components/button.py | 8 ++++++++ chartlets.py/chartlets/components/checkbox.py | 4 ++++ chartlets.py/chartlets/components/select.py | 4 ++++ 4 files changed, 17 insertions(+) diff --git a/chartlets.py/CHANGES.md b/chartlets.py/CHANGES.md index 776fb51c..c0825c68 100644 --- a/chartlets.py/CHANGES.md +++ b/chartlets.py/CHANGES.md @@ -16,6 +16,7 @@ - using `schema` instead of `type` property for callback arguments - using `return` object with `schema` property for callback return values +* Added `tooltip` property to interactive components. ## Version 0.0.29 (from 2024/11/26) diff --git a/chartlets.py/chartlets/components/button.py b/chartlets.py/chartlets/components/button.py index 2a34ea81..c8e2cb4c 100644 --- a/chartlets.py/chartlets/components/button.py +++ b/chartlets.py/chartlets/components/button.py @@ -28,6 +28,10 @@ class Button(Component): One "contained" | "outlined" | "text". Defaults to "text". """ + tooltip: str | None = None + """Tooltip title. Optional.""" + + @dataclass(frozen=True) class IconButton(Component): @@ -50,3 +54,7 @@ class IconButton(Component): """The button variant. One "contained" | "outlined" | "text". Defaults to "text". """ + + tooltip: str | None = None + """Tooltip title. Optional.""" + diff --git a/chartlets.py/chartlets/components/checkbox.py b/chartlets.py/chartlets/components/checkbox.py index a56bd84d..8b7e76b3 100644 --- a/chartlets.py/chartlets/components/checkbox.py +++ b/chartlets.py/chartlets/components/checkbox.py @@ -13,3 +13,7 @@ class Checkbox(Component): label: str = "" """The checkbox label.""" + + tooltip: str | None = None + """Tooltip title. Optional.""" + diff --git a/chartlets.py/chartlets/components/select.py b/chartlets.py/chartlets/components/select.py index 19404b33..916fbee4 100644 --- a/chartlets.py/chartlets/components/select.py +++ b/chartlets.py/chartlets/components/select.py @@ -17,3 +17,7 @@ class Select(Component): """The options given as a list of number or text values or a list of (value, label) pairs. """ + + tooltip: str | None = None + """Tooltip title. Optional.""" + From c709f53fe8342d2922227f4e112a75b123d7a17f Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Thu, 12 Dec 2024 08:34:48 +0100 Subject: [PATCH 3/3] added tooltips to demo --- chartlets.py/demo/my_extension/my_panel_1.py | 1 + chartlets.py/demo/my_extension/my_panel_2.py | 1 + chartlets.py/demo/my_extension/my_panel_3.py | 2 ++ 3 files changed, 4 insertions(+) diff --git a/chartlets.py/demo/my_extension/my_panel_1.py b/chartlets.py/demo/my_extension/my_panel_1.py index 81189d44..f27c242e 100644 --- a/chartlets.py/demo/my_extension/my_panel_1.py +++ b/chartlets.py/demo/my_extension/my_panel_1.py @@ -22,6 +22,7 @@ def render_panel(ctx: Context) -> Component: label="Dataset", options=[(i, f"DS #{i + 1}") for i in range(len(ctx.datasets))], style={"flexGrow": 0, "minWidth": 120}, + tooltip="Select the test dataset to be used" ) control_group = Box( style={ diff --git a/chartlets.py/demo/my_extension/my_panel_2.py b/chartlets.py/demo/my_extension/my_panel_2.py index d6fb2b2d..56f53bf5 100644 --- a/chartlets.py/demo/my_extension/my_panel_2.py +++ b/chartlets.py/demo/my_extension/my_panel_2.py @@ -28,6 +28,7 @@ def render_panel( label="Variable", options=[(v, v) for v in variable_names], style={"flexGrow": 0, "minWidth": 120}, + tooltip="Select the variable of the test dataset to be used" ) control_group = Box( style={ diff --git a/chartlets.py/demo/my_extension/my_panel_3.py b/chartlets.py/demo/my_extension/my_panel_3.py index 01adc445..b5ca8451 100644 --- a/chartlets.py/demo/my_extension/my_panel_3.py +++ b/chartlets.py/demo/my_extension/my_panel_3.py @@ -26,6 +26,7 @@ def render_panel( id="opaque", value=opaque, label="Opaque", + tooltip="Select whether the color is opaque" ) color_select = Select( @@ -34,6 +35,7 @@ def render_panel( label="Color", options=COLORS, style={"flexGrow": 0, "minWidth": 80}, + tooltip="Select color" ) info_text = Typography(