Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions chartlets.js/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

* Added icon support for `Button`, `IconButton` and `Tabs` components.
(#124).

* Added (MUI) component `Accordion`. (#134)

## Version 0.1.7 (from 2025/12/03)

Expand Down
51 changes: 51 additions & 0 deletions chartlets.js/packages/lib/src/plugins/mui/Accordion.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2019-2026 by Brockmann Consult Development team
* Permissions are hereby granted under the terms of the MIT License:
* https://opensource.org/licenses/MIT.
*/

import { render, screen, fireEvent } from "@testing-library/react";
import { describe, expect, it } from "vitest";

import { Accordion } from "./Accordion";
import { createChangeHandler } from "@/plugins/mui/common.test";

describe("Accordion", () => {
it("should render the Accordion component", () => {
render(
<Accordion
id="acc"
type="Accordion"
label="My Accordion"
onChange={() => {}}
/>,
);

expect(screen.getByText("My Accordion")).not.toBeUndefined();
});

it("should fire 'expanded' property", () => {
const { recordedEvents, onChange } = createChangeHandler();

render(
<Accordion
id="acc"
type="Accordion"
expanded={false}
label="My Accordion"
onChange={onChange}
></Accordion>,
);

// MUI Summary renders a button element
fireEvent.click(screen.getByRole("button"));

expect(recordedEvents.length).toEqual(1);
expect(recordedEvents[0]).toEqual({
componentType: "Accordion",
id: "acc",
property: "expanded",
value: true,
});
});
});
71 changes: 71 additions & 0 deletions chartlets.js/packages/lib/src/plugins/mui/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2019-2026 by Brockmann Consult Development team
* Permissions are hereby granted under the terms of the MIT License:
* https://opensource.org/licenses/MIT.
*/

import MuiAccordion from "@mui/material/Accordion";
import MuiAccordionDetails from "@mui/material/AccordionDetails";
import MuiAccordionSummary from "@mui/material/AccordionSummary";
import MuiTypography from "@mui/material/Typography";

import type { ComponentState, ComponentProps } from "@/index";
import { Children } from "@/index";
import { Icon } from "./Icon";
import type { SyntheticEvent } from "react";

interface AccordionState extends ComponentState {
label?: string;
icon?: string;
expanded?: boolean;
disabled?: boolean;
}

interface AccordionProps extends ComponentProps, AccordionState {}

export const Accordion = ({
id,
style,
label,
icon,
expanded,
disabled,
children: nodes,
onChange,
}: AccordionProps) => {
const handleChange = (_event: SyntheticEvent, isExpanded: boolean) => {
if (id) {
onChange?.({
componentType: "Accordion",
id,
property: "expanded",
value: isExpanded,
});
}
};
return (
<div>
<MuiAccordion
id={id}
style={style}
expanded={expanded}
disabled={disabled}
onChange={handleChange}
>
<MuiAccordionSummary
expandIcon={icon ? <Icon iconName={icon} /> : undefined}
>
{label ? (
<MuiTypography component="span">{label}</MuiTypography>
) : null}
</MuiAccordionSummary>

{nodes && (
<MuiAccordionDetails>
<Children nodes={nodes} onChange={onChange} />
</MuiAccordionDetails>
)}
</MuiAccordion>
</div>
);
};
2 changes: 2 additions & 0 deletions chartlets.js/packages/lib/src/plugins/mui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

import type { Plugin } from "@/index";
import { Accordion } from "./Accordion";
import { Box } from "./Box";
import { Button } from "./Button";
import { Checkbox } from "./Checkbox";
Expand All @@ -25,6 +26,7 @@ import { Table } from "@/plugins/mui/Table";
export default function mui(): Plugin {
return {
components: [
["Accordion", Accordion],
["Box", Box],
["Button", Button],
["Checkbox", Checkbox],
Expand Down
2 changes: 2 additions & 0 deletions chartlets.py/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

* Added `size` and removed `variant` property from `IconButton`
component to align with component in chartlets.js. (#124)

* Added (MUI) component `Accordion`. (#134)

## Version 0.1.7 (from 2025/12/03)

Expand Down
1 change: 1 addition & 0 deletions chartlets.py/chartlets/components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Permissions are hereby granted under the terms of the MIT License:
# https://opensource.org/licenses/MIT.

from .accordion import Accordion
from .box import Box
from .button import Button
from .button import IconButton
Expand Down
27 changes: 27 additions & 0 deletions chartlets.py/chartlets/components/accordion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright (c) 2019-2026 by Brockmann Consult Development team
# Permissions are hereby granted under the terms of the MIT License:
# https://opensource.org/licenses/MIT.


from dataclasses import dataclass, field

from chartlets import Component

@dataclass(frozen=True)
class Accordion(Component):
"""Accordion container."""

label: str | None = None
"""Header of the accordion."""

icon: str | None = None
"""Material icon name for the expand icon (e.g. 'expand_more')."""

expanded: bool = field(default=False)
"""If set, controls whether the accordion is expanded."""

disabled: bool | None = None
"""If set, controls whether the accordion is disabled."""

children: list[Component] = field(default_factory=list)
"""Accordion content."""
2 changes: 2 additions & 0 deletions chartlets.py/demo/my_extension/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from .my_panel_6 import panel as my_panel_6
from .my_panel_7 import panel as my_panel_7
from .my_panel_8 import panel as my_panel_8
from .my_panel_9 import panel as my_panel_9


ext = Extension(__name__)
Expand All @@ -22,3 +23,4 @@
ext.add(my_panel_6)
ext.add(my_panel_7)
ext.add(my_panel_8)
ext.add(my_panel_9)
74 changes: 74 additions & 0 deletions chartlets.py/demo/my_extension/my_panel_9.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Copyright (c) 2019-2026 by Brockmann Consult Development team
# Permissions are hereby granted under the terms of the MIT License:
# https://opensource.org/licenses/MIT.


from chartlets import Component, State
from chartlets.components import (
Accordion,
Typography,
Box,
Table
)
from chartlets.components.table import TableColumn, TableRow


from server.context import Context
from server.panel import Panel


panel = Panel(__name__, title="Panel I")


# noinspection PyUnusedLocal
@panel.layout()
def render_panel(
ctx: Context,
) -> Component:
columns: list[TableColumn] = [
{"id": "id", "label": "ID", "sortDirection": "desc"},
{
"id": "firstName",
"label": "First Name",
"align": "left",
"sortDirection": "desc",
},
{"id": "lastName", "label": "Last Name", "align": "center"},
{"id": "age", "label": "Age"},
]

rows: TableRow = [
["1", "John", "Doe", 30],
["2", "Jane", "Smith", 25],
["3", "Peter", "Jones", 40],
]

table = Table(id="table", rows=rows, columns=columns, hover=True)

info_text = Typography(id="info_text", children=["This is a text."])

accordion1 = Accordion(
id="accordion1",
label="Accordion No.1",
icon="arrow_drop_down",
children=[info_text],
)

accordion2 = Accordion(
id="accordion2",
label="Accordion No.2",
icon="arrow_drop_down",
# expanded=True,
# disabled=True
children=[table],
)

return Box(
style={
"display": "flex",
"flexDirection": "column",
"width": "100%",
"height": "100%",
},
children=[accordion1, accordion2],
)