-
Notifications
You must be signed in to change notification settings - Fork 0
Add accordion component #140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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, | ||
| }); | ||
| }); | ||
| }); |
| 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> | ||
| ); | ||
| }; |
| 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.""" |
| 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], | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this mean we can have multiple children for this component? How does that look like?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the Accordion component accepts multiple children, which are rendered in the order they are provided. Additional styling can be applied via the |
||
| ) | ||
|
|
||
| return Box( | ||
| style={ | ||
| "display": "flex", | ||
| "flexDirection": "column", | ||
| "width": "100%", | ||
| "height": "100%", | ||
| }, | ||
| children=[accordion1, accordion2], | ||
| ) | ||
Uh oh!
There was an error while loading. Please reload this page.