Skip to content

Commit 8114292

Browse files
authored
Added new Switch component (#72)
1 parent f77b23f commit 8114292

File tree

8 files changed

+120
-1
lines changed

8 files changed

+120
-1
lines changed

chartlets.js/CHANGES.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@
3737
- using `schema` instead of `type` property for callback arguments
3838
- using `return` object with `schema` property for callback return values
3939

40-
* New components
40+
* New (MUI) components
4141
- `LinearProgress`
42+
- `Switch`
4243

4344
## Version 0.0.29 (from 2024/11/26)
4445

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { describe, it, expect } from "vitest";
2+
import { render, screen, fireEvent } from "@testing-library/react";
3+
import { createChangeHandler } from "./common.test";
4+
import { Switch } from "./Switch";
5+
6+
describe("Switch", () => {
7+
it("should render the Switch component", () => {
8+
render(
9+
<Switch id="cb" type={"Switch"} label={"Click!"} onChange={() => {}} />,
10+
);
11+
// to inspect rendered component, do:
12+
// expect(document.querySelector("#cb")).toEqual({});
13+
expect(screen.getByText("Click!")).not.toBeUndefined();
14+
});
15+
16+
it("should fire 'value' property", () => {
17+
const { recordedEvents, onChange } = createChangeHandler();
18+
render(
19+
<Switch
20+
data-testid="bt"
21+
id="cb"
22+
type={"Switch"}
23+
label={"Click!"}
24+
value={false}
25+
onChange={onChange}
26+
/>,
27+
);
28+
fireEvent.click(screen.getByText("Click!"));
29+
expect(recordedEvents.length).toEqual(1);
30+
expect(recordedEvents[0]).toEqual({
31+
componentType: "Switch",
32+
id: "cb",
33+
property: "value",
34+
value: true,
35+
});
36+
});
37+
});
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { type ChangeEvent } from "react";
2+
import MuiSwitch from "@mui/material/Switch";
3+
import MuiFormControl from "@mui/material/FormControl";
4+
import MuiFormControlLabel from "@mui/material/FormControlLabel";
5+
6+
import type { ComponentState, ComponentProps } from "@/index";
7+
8+
interface SwitchState extends ComponentState {
9+
label?: string;
10+
value?: boolean | undefined;
11+
}
12+
13+
interface SwitchProps extends ComponentProps, SwitchState {}
14+
15+
export function Switch({
16+
type,
17+
id,
18+
name,
19+
value,
20+
disabled,
21+
style,
22+
label,
23+
onChange,
24+
}: SwitchProps) {
25+
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
26+
if (id) {
27+
return onChange({
28+
componentType: type,
29+
id: id,
30+
property: "value",
31+
value: event.currentTarget.checked,
32+
});
33+
}
34+
};
35+
return (
36+
<MuiFormControl variant="filled" size="small" style={style}>
37+
<MuiFormControlLabel
38+
label={label}
39+
control={
40+
<MuiSwitch
41+
id={id}
42+
name={name}
43+
checked={Boolean(value)}
44+
disabled={disabled}
45+
onChange={handleChange}
46+
/>
47+
}
48+
/>
49+
</MuiFormControl>
50+
);
51+
}

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 @@ import { Checkbox } from "./Checkbox";
55
import { CircularProgress } from "./CircularProgress";
66
import { IconButton } from "./IconButton";
77
import { Select } from "./Select";
8+
import { Switch } from "./Switch";
89
import { Typography } from "./Typography";
910

1011
export default function mui(): Plugin {
@@ -16,6 +17,7 @@ export default function mui(): Plugin {
1617
["CircularProgress", CircularProgress],
1718
["IconButton", IconButton],
1819
["Select", Select],
20+
["Switch", Switch],
1921
["Typography", Typography],
2022
],
2123
};

chartlets.py/CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
- using `schema` instead of `type` property for callback arguments
1717
- using `return` object with `schema` property for callback return values
1818

19+
* New components
20+
- `Switch`
1921

2022
## Version 0.0.29 (from 2024/11/26)
2123

chartlets.py/chartlets/components/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
from .progress import LinearProgressWithLabel
99
from .charts.vega import VegaChart
1010
from .select import Select
11+
from .switch import Switch
1112
from .typography import Typography
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from dataclasses import dataclass
2+
3+
from chartlets import Component
4+
5+
6+
@dataclass(frozen=True)
7+
class Switch(Component):
8+
"""Switches toggle the state of a single setting on or off."""
9+
10+
value: bool | None = None
11+
"""The switch value."""
12+
13+
label: str = ""
14+
"""The switch label."""
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from chartlets.components import Switch
2+
from tests.component_test import make_base
3+
4+
5+
class SwitchTest(make_base(Switch)):
6+
7+
def test_is_json_serializable(self):
8+
self.assert_is_json_serializable(
9+
self.cls(value=True, label="Auto-safe"),
10+
{"type": "Switch", "value": True, "label": "Auto-safe"},
11+
)

0 commit comments

Comments
 (0)