From 2dd8f1a8bbed642e522ef4c00d4425a8c7cc11cf Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Wed, 18 Dec 2024 16:47:39 +0100 Subject: [PATCH 1/4] Python part of `Divider` --- chartlets.js/CHANGES.md | 1 + chartlets.py/CHANGES.md | 7 +++-- chartlets.py/chartlets/components/__init__.py | 1 + chartlets.py/chartlets/components/divider.py | 29 +++++++++++++++++++ chartlets.py/demo/my_extension/my_panel_3.py | 4 +-- chartlets.py/tests/components/divider_test.py | 22 ++++++++++++++ 6 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 chartlets.py/chartlets/components/divider.py create mode 100644 chartlets.py/tests/components/divider_test.py diff --git a/chartlets.js/CHANGES.md b/chartlets.js/CHANGES.md index 7e5fd11f..5e0d1532 100644 --- a/chartlets.js/CHANGES.md +++ b/chartlets.js/CHANGES.md @@ -38,6 +38,7 @@ - using `return` object with `schema` property for callback return values * New (MUI) components + - `Divider` - `LinearProgress` - `RadioGroup` and `Radio` - `Switch` diff --git a/chartlets.py/CHANGES.md b/chartlets.py/CHANGES.md index 6dd0fc46..5bccfbfa 100644 --- a/chartlets.py/CHANGES.md +++ b/chartlets.py/CHANGES.md @@ -19,11 +19,12 @@ * Added `tooltip` property to interactive components. * New components - - `Switch` + - `Divider` - `RadioGroup` and `Radio` - - `Tabs` + - `Switch` - `Slider` - + - `Tabs` and `Tab` + ## Version 0.0.29 (from 2024/11/26) * Fixed a bug that prevents using annotations of type `dict` or `dict[str, T]`. diff --git a/chartlets.py/chartlets/components/__init__.py b/chartlets.py/chartlets/components/__init__.py index 615d95c0..ac2142de 100644 --- a/chartlets.py/chartlets/components/__init__.py +++ b/chartlets.py/chartlets/components/__init__.py @@ -3,6 +3,7 @@ from .button import IconButton from .checkbox import Checkbox from .charts.vega import VegaChart +from .divider import Divider from .progress import CircularProgress from .progress import CircularProgressWithLabel from .progress import LinearProgress diff --git a/chartlets.py/chartlets/components/divider.py b/chartlets.py/chartlets/components/divider.py new file mode 100644 index 00000000..c310499b --- /dev/null +++ b/chartlets.py/chartlets/components/divider.py @@ -0,0 +1,29 @@ +from dataclasses import dataclass + +from chartlets import Container + + +@dataclass(frozen=True) +class Divider(Container): + """The Divider component provides a thin, + unobtrusive line for grouping elements to reinforce visual hierarchy. + """ + + label: str | None = None + """The text label.""" + + orientation: str | None = None + """The orientation. Can be `horizontal` (default) or `vertical`.""" + + variant: str | None = None + """The variant. One of `fullWidth ` (default), `inset`, and `middle`.""" + + flexItem: bool | None = None + """Use the `flexItem` prop to display the divider when it's being + used in a flex container. + """ + + textAlign: str | None = None + """Use the `textAlign` prop to align elements that are + wrapped by the divider. One of `center` (default), `left`, and `right`. + """ diff --git a/chartlets.py/demo/my_extension/my_panel_3.py b/chartlets.py/demo/my_extension/my_panel_3.py index b5ca8451..2d6832da 100644 --- a/chartlets.py/demo/my_extension/my_panel_3.py +++ b/chartlets.py/demo/my_extension/my_panel_3.py @@ -1,5 +1,5 @@ from chartlets import Component, Input, State, Output -from chartlets.components import Box, Select, Checkbox, Typography +from chartlets.components import Box, Divider, Select, Checkbox, Typography from server.context import Context from server.panel import Panel @@ -50,7 +50,7 @@ def render_panel( "height": "100%", "gap": "6px", }, - children=[opaque_checkbox, color_select, info_text], + children=[opaque_checkbox, color_select, Divider(), info_text], ) diff --git a/chartlets.py/tests/components/divider_test.py b/chartlets.py/tests/components/divider_test.py new file mode 100644 index 00000000..ca877039 --- /dev/null +++ b/chartlets.py/tests/components/divider_test.py @@ -0,0 +1,22 @@ +from chartlets.components import Divider +from tests.component_test import make_base + + +class DividerTest(make_base(Divider)): + + def test_is_json_serializable(self): + self.assert_is_json_serializable( + self.cls( + textAlign="center", + variant="middle", + flexItem=True, + children=["Options"], + ), + { + "type": "Divider", + "textAlign": "center", + "variant": "middle", + "flexItem": True, + "children": ["Options"], + }, + ) From 865a69c066128d0aff8d4c3ec21a15cb25cacd7e Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Wed, 18 Dec 2024 18:03:05 +0100 Subject: [PATCH 2/4] new Divider component --- .../lib/src/plugins/mui/Divider.test.tsx | 22 +++++++++++ .../packages/lib/src/plugins/mui/Divider.tsx | 39 +++++++++++++++++++ .../packages/lib/src/plugins/mui/index.ts | 2 + chartlets.py/chartlets/components/divider.py | 3 -- chartlets.py/demo/my_extension/my_panel_3.py | 4 +- 5 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 chartlets.js/packages/lib/src/plugins/mui/Divider.test.tsx create mode 100644 chartlets.js/packages/lib/src/plugins/mui/Divider.tsx diff --git a/chartlets.js/packages/lib/src/plugins/mui/Divider.test.tsx b/chartlets.js/packages/lib/src/plugins/mui/Divider.test.tsx new file mode 100644 index 00000000..d623c025 --- /dev/null +++ b/chartlets.js/packages/lib/src/plugins/mui/Divider.test.tsx @@ -0,0 +1,22 @@ +import { describe, it, expect } from "vitest"; +import { render, screen } from "@testing-library/react"; +import type { ComponentChangeHandler } from "@/types/state/event"; +import { Divider } from "./Divider"; + +describe("Divider", () => { + it("should render the Box component", () => { + const onChange: ComponentChangeHandler = () => {}; + render( + , + ); + // to inspect rendered component, do: + // expect(document.querySelector("#bx")).toEqual({}); + expect(screen.getByText("Section 1")).not.toBeUndefined(); + }); +}); diff --git a/chartlets.js/packages/lib/src/plugins/mui/Divider.tsx b/chartlets.js/packages/lib/src/plugins/mui/Divider.tsx new file mode 100644 index 00000000..b7db544e --- /dev/null +++ b/chartlets.js/packages/lib/src/plugins/mui/Divider.tsx @@ -0,0 +1,39 @@ +import type { ElementType } from "react"; +import MuiDivider from "@mui/material/Divider"; + +import type { ComponentState, ComponentProps } from "@/index"; +import { Children } from "@/index"; + +interface DividerState extends ComponentState { + orientation?: "horizontal" | "vertical"; + variant?: "fullWidth" | "inset" | "middle"; + flexItem?: boolean; + textAlign?: "left" | "center" | "right"; + component?: ElementType; +} + +interface DividerProps extends ComponentProps, DividerState {} + +export const Divider = ({ + id, + style, + orientation, + variant, + flexItem, + textAlign, + children: nodes, + onChange, +}: DividerProps) => { + return ( + + + + ); +}; diff --git a/chartlets.js/packages/lib/src/plugins/mui/index.ts b/chartlets.js/packages/lib/src/plugins/mui/index.ts index a72f6c64..4eab3395 100644 --- a/chartlets.js/packages/lib/src/plugins/mui/index.ts +++ b/chartlets.js/packages/lib/src/plugins/mui/index.ts @@ -3,6 +3,7 @@ import { Box } from "./Box"; import { Button } from "./Button"; import { Checkbox } from "./Checkbox"; import { CircularProgress } from "./CircularProgress"; +import { Divider } from "./Divider"; import { IconButton } from "./IconButton"; import { RadioGroup } from "./RadioGroup"; import { Select } from "./Select"; @@ -18,6 +19,7 @@ export default function mui(): Plugin { ["Button", Button], ["Checkbox", Checkbox], ["CircularProgress", CircularProgress], + ["Divider", Divider], ["IconButton", IconButton], ["RadioGroup", RadioGroup], ["Select", Select], diff --git a/chartlets.py/chartlets/components/divider.py b/chartlets.py/chartlets/components/divider.py index c310499b..4ab58b32 100644 --- a/chartlets.py/chartlets/components/divider.py +++ b/chartlets.py/chartlets/components/divider.py @@ -9,9 +9,6 @@ class Divider(Container): unobtrusive line for grouping elements to reinforce visual hierarchy. """ - label: str | None = None - """The text label.""" - orientation: str | None = None """The orientation. Can be `horizontal` (default) or `vertical`.""" diff --git a/chartlets.py/demo/my_extension/my_panel_3.py b/chartlets.py/demo/my_extension/my_panel_3.py index 2d6832da..12a02863 100644 --- a/chartlets.py/demo/my_extension/my_panel_3.py +++ b/chartlets.py/demo/my_extension/my_panel_3.py @@ -42,6 +42,8 @@ def render_panel( id="info_text", children=update_info_text(ctx, dataset_id, opaque, color) ) + divider = Divider(style={"paddingTop": "10px", "paddingBottom": "10px"}) + return Box( style={ "display": "flex", @@ -50,7 +52,7 @@ def render_panel( "height": "100%", "gap": "6px", }, - children=[opaque_checkbox, color_select, Divider(), info_text], + children=[opaque_checkbox, color_select, divider, info_text], ) From 9678716d7347bbef23b2f9cbde5c5d36173c2e4e Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Wed, 18 Dec 2024 18:22:06 +0100 Subject: [PATCH 3/4] using `Literal` typing form --- chartlets.py/chartlets/components/divider.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/chartlets.py/chartlets/components/divider.py b/chartlets.py/chartlets/components/divider.py index 4ab58b32..4f70f5f1 100644 --- a/chartlets.py/chartlets/components/divider.py +++ b/chartlets.py/chartlets/components/divider.py @@ -1,26 +1,28 @@ from dataclasses import dataclass +from typing import Literal from chartlets import Container @dataclass(frozen=True) class Divider(Container): - """The Divider component provides a thin, + """The `Divider` component provides a thin, unobtrusive line for grouping elements to reinforce visual hierarchy. """ - orientation: str | None = None + orientation: Literal["horizontal", "vertical"] | None = None """The orientation. Can be `horizontal` (default) or `vertical`.""" - variant: str | None = None + variant: Literal["fullWidth", "inset", "middle"] | None = None """The variant. One of `fullWidth ` (default), `inset`, and `middle`.""" + textAlign: Literal["left", "center", "right"] | None = None + """Use the `textAlign` prop to align elements that are + wrapped by the divider. One of `left`, `center` (default), and `right`. + """ + flexItem: bool | None = None """Use the `flexItem` prop to display the divider when it's being used in a flex container. """ - textAlign: str | None = None - """Use the `textAlign` prop to align elements that are - wrapped by the divider. One of `center` (default), `left`, and `right`. - """ From 73303c2ecab53825075d82070f592276cb3d07c7 Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Tue, 14 Jan 2025 14:38:39 +0100 Subject: [PATCH 4/4] Update chartlets.js/packages/lib/src/plugins/mui/Divider.tsx Co-authored-by: b-yogesh --- chartlets.js/packages/lib/src/plugins/mui/Divider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chartlets.js/packages/lib/src/plugins/mui/Divider.tsx b/chartlets.js/packages/lib/src/plugins/mui/Divider.tsx index b7db544e..bd54cfe3 100644 --- a/chartlets.js/packages/lib/src/plugins/mui/Divider.tsx +++ b/chartlets.js/packages/lib/src/plugins/mui/Divider.tsx @@ -33,7 +33,7 @@ export const Divider = ({ flexItem={flexItem} textAlign={textAlign} > - + {nodes && nodes.length && } ); };