Skip to content

Commit ad8def6

Browse files
committed
Merge branch 'main' into clarasb-132-update_VegaChart
2 parents 98e9ef2 + e295ef8 commit ad8def6

12 files changed

Lines changed: 321 additions & 24 deletions

File tree

chartlets.js/CHANGES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,16 @@
99
- `vitest: ^3.2.4`
1010

1111
* Added icon support for `Button`, `IconButton` and `Tabs` components.
12+
(#124).
13+
14+
* Added (MUI) component `Accordion`. (#41, #134)
1215
(#124)
1316

1417
* Adjusted `VegaChart` component, due to `react-vega` upgrade
1518
from v7 to v8. (#132)
1619

20+
* Fixed handling of `style` prop in `Tabs` component and added prop
21+
`iconPosition`. (#135, #136)
1722

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (c) 2019-2026 by Brockmann Consult Development team
3+
* Permissions are hereby granted under the terms of the MIT License:
4+
* https://opensource.org/licenses/MIT.
5+
*/
6+
7+
import { render, screen, fireEvent } from "@testing-library/react";
8+
import { describe, expect, it } from "vitest";
9+
10+
import { Accordion } from "./Accordion";
11+
import { createChangeHandler } from "@/plugins/mui/common.test";
12+
13+
describe("Accordion", () => {
14+
it("should render the Accordion component", () => {
15+
render(
16+
<Accordion
17+
id="acc"
18+
type="Accordion"
19+
label="My Accordion"
20+
onChange={() => {}}
21+
/>,
22+
);
23+
24+
expect(screen.getByText("My Accordion")).not.toBeUndefined();
25+
});
26+
27+
it("should fire 'expanded' property", () => {
28+
const { recordedEvents, onChange } = createChangeHandler();
29+
30+
render(
31+
<Accordion
32+
id="acc"
33+
type="Accordion"
34+
expanded={false}
35+
label="My Accordion"
36+
onChange={onChange}
37+
></Accordion>,
38+
);
39+
40+
// MUI Summary renders a button element
41+
fireEvent.click(screen.getByRole("button"));
42+
43+
expect(recordedEvents.length).toEqual(1);
44+
expect(recordedEvents[0]).toEqual({
45+
componentType: "Accordion",
46+
id: "acc",
47+
property: "expanded",
48+
value: true,
49+
});
50+
});
51+
});
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (c) 2019-2026 by Brockmann Consult Development team
3+
* Permissions are hereby granted under the terms of the MIT License:
4+
* https://opensource.org/licenses/MIT.
5+
*/
6+
7+
import MuiAccordion from "@mui/material/Accordion";
8+
import MuiAccordionDetails from "@mui/material/AccordionDetails";
9+
import MuiAccordionSummary from "@mui/material/AccordionSummary";
10+
import MuiTypography from "@mui/material/Typography";
11+
12+
import type { ComponentState, ComponentProps } from "@/index";
13+
import { Children } from "@/index";
14+
import { Icon } from "./Icon";
15+
import type { SyntheticEvent } from "react";
16+
17+
interface AccordionState extends ComponentState {
18+
label?: string;
19+
icon?: string;
20+
expanded?: boolean;
21+
disabled?: boolean;
22+
}
23+
24+
interface AccordionProps extends ComponentProps, AccordionState {}
25+
26+
export const Accordion = ({
27+
id,
28+
style,
29+
label,
30+
icon,
31+
expanded,
32+
disabled,
33+
children: nodes,
34+
onChange,
35+
}: AccordionProps) => {
36+
const handleChange = (_event: SyntheticEvent, isExpanded: boolean) => {
37+
if (id) {
38+
onChange?.({
39+
componentType: "Accordion",
40+
id,
41+
property: "expanded",
42+
value: isExpanded,
43+
});
44+
}
45+
};
46+
return (
47+
<div>
48+
<MuiAccordion
49+
id={id}
50+
style={style}
51+
expanded={expanded}
52+
disabled={disabled}
53+
onChange={handleChange}
54+
>
55+
<MuiAccordionSummary
56+
expandIcon={icon ? <Icon iconName={icon} /> : undefined}
57+
>
58+
{label ? (
59+
<MuiTypography component="span">{label}</MuiTypography>
60+
) : null}
61+
</MuiAccordionSummary>
62+
63+
{nodes && (
64+
<MuiAccordionDetails>
65+
<Children nodes={nodes} onChange={onChange} />
66+
</MuiAccordionDetails>
67+
)}
68+
</MuiAccordion>
69+
</div>
70+
);
71+
};

chartlets.js/packages/lib/src/plugins/mui/Tabs.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ import { Icon } from "./Icon";
1515
import { isString } from "@/utils/isString";
1616
import { isComponentState } from "@/types/state/component";
1717

18-
interface TabState {
18+
interface TabState extends ComponentState {
1919
type: "Tab";
2020
label?: string;
2121
icon?: string;
22+
iconPosition?: "bottom" | "end" | "start" | "top";
2223
disabled?: boolean;
2324
children?: ComponentProps[];
2425
}
@@ -50,20 +51,22 @@ export function Tabs({
5051
}
5152
};
5253
return (
53-
<MuiBox sx={{ width: "100%" }}>
54+
<MuiBox sx={{ width: "100%" }} style={style}>
5455
<MuiBox sx={{ borderBottom: 1, borderColor: "divider" }}>
55-
<MuiTabs id={id} style={style} value={value} onChange={handleChange}>
56+
<MuiTabs id={id} value={value} onChange={handleChange}>
5657
{tabItems?.map((tab, index) => {
5758
const tabState = isComponentState(tab)
5859
? (tab as TabState)
5960
: undefined;
6061
return (
6162
<MuiTab
6263
key={index}
64+
style={tabState?.style}
6365
label={tabState ? tabState.label : isString(tab) ? tab : ""}
6466
icon={
6567
tabState && tabState.icon && <Icon iconName={tabState.icon} />
6668
}
69+
iconPosition={tabState?.iconPosition}
6770
disabled={disabled || (tabState && tabState.disabled)}
6871
/>
6972
);
@@ -78,7 +81,7 @@ export function Tabs({
7881
key={index}
7982
type={type}
8083
onChange={onChange}
81-
children={tabState?.children ?? undefined}
84+
children={tabState?.children}
8285
/>
8386
)
8487
);

chartlets.js/packages/lib/src/plugins/mui/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
import type { Plugin } from "@/index";
8+
import { Accordion } from "./Accordion";
89
import { Box } from "./Box";
910
import { Button } from "./Button";
1011
import { Checkbox } from "./Checkbox";
@@ -25,6 +26,7 @@ import { Table } from "@/plugins/mui/Table";
2526
export default function mui(): Plugin {
2627
return {
2728
components: [
29+
["Accordion", Accordion],
2830
["Box", Box],
2931
["Button", Button],
3032
["Checkbox", Checkbox],

chartlets.py/CHANGES.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
* Added `size` and removed `variant` property from `IconButton`
44
component to align with component in chartlets.js. (#124)
55

6+
* Added (MUI) component `Accordion`. (#41, #134)
7+
8+
* Added `iconPosition` to `Tabs` Component. (#135, #136)
9+
610
* Updated dependencies
7-
- `altair>=6.0.0,<7.0.0` (#132)
11+
- `altair>=6.0.0,<7.0.0` (#132)
812

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

@@ -17,10 +21,10 @@
1721

1822
## Version 0.1.5 (from 2025/03/21)
1923

20-
* Add `multiple` property for `Select` component to enable the
24+
* Added `multiple` property for `Select` component to enable the selection
2125
of multiple elements.
2226

23-
* Add support for `Python 3.13`
27+
* Added support for `Python 3.13`
2428

2529

2630
## Version 0.1.4 (from 2025/03/06)

chartlets.py/chartlets/components/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# Permissions are hereby granted under the terms of the MIT License:
33
# https://opensource.org/licenses/MIT.
44

5+
from .accordion import Accordion
56
from .box import Box
67
from .button import Button
78
from .button import IconButton
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright (c) 2019-2026 by Brockmann Consult Development team
2+
# Permissions are hereby granted under the terms of the MIT License:
3+
# https://opensource.org/licenses/MIT.
4+
5+
6+
from dataclasses import dataclass, field
7+
8+
from chartlets import Component
9+
10+
@dataclass(frozen=True)
11+
class Accordion(Component):
12+
"""Accordion container."""
13+
14+
label: str | None = None
15+
"""Header of the accordion."""
16+
17+
icon: str | None = None
18+
"""Material icon name for the expand icon (e.g. 'expand_more')."""
19+
20+
expanded: bool = field(default=False)
21+
"""If set, controls whether the accordion is expanded."""
22+
23+
disabled: bool | None = None
24+
"""If set, controls whether the accordion is disabled."""
25+
26+
children: list[Component] = field(default_factory=list)
27+
"""Accordion content."""

chartlets.py/chartlets/components/tabs.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ class Tab(Component):
1616
icon: str | None = None
1717
"""The tab icon's name."""
1818

19+
iconPosition: str | None = None
20+
""" The position of the icon relative to the label.
21+
One of "bottom" | "end" | "start" | "top".
22+
Defaults to "top".
23+
"""
24+
1925
label: str | None = None
2026
"""The tab label."""
2127

chartlets.py/demo/my_extension/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from .my_panel_6 import panel as my_panel_6
1212
from .my_panel_7 import panel as my_panel_7
1313
from .my_panel_8 import panel as my_panel_8
14+
from .my_panel_9 import panel as my_panel_9
1415

1516

1617
ext = Extension(__name__)
@@ -22,3 +23,4 @@
2223
ext.add(my_panel_6)
2324
ext.add(my_panel_7)
2425
ext.add(my_panel_8)
26+
ext.add(my_panel_9)

0 commit comments

Comments
 (0)