Skip to content

Commit c7bb9fc

Browse files
committed
fix: added maxTeeth prop to showcase baby teeths
1 parent 44261e9 commit c7bb9fc

4 files changed

Lines changed: 205 additions & 39 deletions

File tree

src/Odontogram.tsx

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -113,19 +113,21 @@ export const Odontogram: FC<OdontogramProps> = ({
113113
showTooltip = true,
114114
showHalf = "full",
115115
name,
116+
maxTeeth = 8,
117+
116118
}) => {
117119
const themeColors =
118120
theme === "dark"
119121
? {
120-
"--dark-blue": "#aab6ff",
121-
"--base-blue": "#d0d5f6",
122-
"--light-blue": "#5361e6",
123-
}
122+
"--dark-blue": "#aab6ff",
123+
"--base-blue": "#d0d5f6",
124+
"--light-blue": "#5361e6",
125+
}
124126
: {
125-
"--dark-blue": "#3e5edc",
126-
"--base-blue": "#8a98be",
127-
"--light-blue": "#c6ccf8",
128-
};
127+
"--dark-blue": "#3e5edc",
128+
"--base-blue": "#8a98be",
129+
"--light-blue": "#c6ccf8",
130+
};
129131

130132
const [selected, setSelected] = useState<Set<string>>(
131133
new Set(defaultSelected)
@@ -180,31 +182,31 @@ export const Odontogram: FC<OdontogramProps> = ({
180182
label: string;
181183
position: { x: number; y: number };
182184
}> = [
183-
{
184-
name: "first",
185-
transform: "",
186-
label: "Upper Right",
187-
position: { x: 100, y: 30 },
188-
},
189-
{
190-
name: "second",
191-
transform: "scale(-1, 1) translate(-409, 0)",
192-
label: "Upper Left",
193-
position: { x: 309, y: 30 },
194-
},
195-
{
196-
name: "third",
197-
transform: "scale(1, -1) translate(0, -694)",
198-
label: "Lower Right",
199-
position: { x: 100, y: 664 },
200-
},
201-
{
202-
name: "fourth",
203-
transform: "scale(-1, -1) translate(-409, -694)",
204-
label: "Lower Left",
205-
position: { x: 309, y: 664 },
206-
},
207-
];
185+
{
186+
name: "first",
187+
transform: "",
188+
label: "Upper Right",
189+
position: { x: 100, y: 30 },
190+
},
191+
{
192+
name: "second",
193+
transform: "scale(-1, 1) translate(-409, 0)",
194+
label: "Upper Left",
195+
position: { x: 309, y: 30 },
196+
},
197+
{
198+
name: "third",
199+
transform: "scale(1, -1) translate(0, -694)",
200+
label: "Lower Right",
201+
position: { x: 100, y: 664 },
202+
},
203+
{
204+
name: "fourth",
205+
transform: "scale(-1, -1) translate(-409, -694)",
206+
label: "Lower Left",
207+
position: { x: 309, y: 664 },
208+
},
209+
];
208210

209211
let visibleQuadrants = quadrants;
210212
if (showHalf === "upper") {
@@ -251,11 +253,15 @@ export const Odontogram: FC<OdontogramProps> = ({
251253
});
252254
};
253255
const handleLeave = () => setTooltipData((p) => ({ ...p, active: false }));
256+
const renderTeeth = (prefix: string, maxTeeth?: number) => {
257+
// FIXED: use slice() instead of splice()
258+
const filteredTeeth = maxTeeth
259+
? teethPaths.slice(0, maxTeeth)
260+
: teethPaths;
254261

255-
const renderTeeth = (prefix: string) =>
256-
teethPaths.map((tooth) => {
262+
return filteredTeeth.map((tooth) => {
257263
const id = `${prefix}${tooth.name}`;
258-
const displayName = convertFDIToNotation(id, notation ?? "FDI"); // 🆕
264+
const displayName = convertFDIToNotation(id, notation ?? "FDI");
259265

260266
return (
261267
<Teeth
@@ -272,6 +278,7 @@ export const Odontogram: FC<OdontogramProps> = ({
272278
</Teeth>
273279
);
274280
});
281+
};
275282

276283
const finalColors = { ...themeColors, ...mapToCssVars(colors) };
277284

@@ -305,8 +312,8 @@ export const Odontogram: FC<OdontogramProps> = ({
305312
showHalf === "full"
306313
? "0 0 409 694"
307314
: showHalf === "upper"
308-
? "0 0 409 347"
309-
: "0 347 409 347"
315+
? "0 0 409 347"
316+
: "0 347 409 347"
310317
}
311318
className="Odontogram"
312319
style={{
@@ -325,7 +332,7 @@ export const Odontogram: FC<OdontogramProps> = ({
325332
name={name}
326333
transform={transform}
327334
>
328-
{renderTeeth(`teeth-${index + 1}`)}
335+
{renderTeeth(`teeth-${index + 1}`, maxTeeth)}
329336
</g>
330337
))}
331338
</svg>

src/data.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,4 @@ export const teethPaths = [
9595
],
9696
},
9797
];
98+

src/stories/zBaby.stories.tsx

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import { useState } from "react";
2+
import type { Meta, StoryFn } from "@storybook/react-webpack5";
3+
import Odontogram, { getToothNotations } from "..";
4+
import { ToothDetail } from "../type";
5+
import { teethPaths } from "../data";
6+
7+
export default {
8+
title: "Components/Baby Teeth ",
9+
component: Odontogram,
10+
parameters: {
11+
layout: "centered",
12+
backgrounds: {
13+
default: "light",
14+
values: [
15+
{ name: "light", value: "#f5f5f5" },
16+
{ name: "dark", value: "#0b0d1a" },
17+
],
18+
},
19+
},
20+
argTypes: {
21+
name: {
22+
control: "text",
23+
},
24+
theme: {
25+
control: "radio",
26+
options: ["light", "dark"],
27+
},
28+
notation: {
29+
control: "radio",
30+
options: ["FDI", "Universal", "Palmer"],
31+
},
32+
colors: {
33+
control: "object",
34+
},
35+
onChange: { action: "changed" },
36+
maxTeeth: {
37+
control: 'number',
38+
options: [8, 4]
39+
}
40+
},
41+
} as Meta<typeof Odontogram>;
42+
43+
const Template: StoryFn<typeof Odontogram> = (args) => {
44+
const [selected, setSelected] = useState<ToothDetail[]>(
45+
args.defaultSelected?.map((id) => ({
46+
id,
47+
notations: getToothNotations(id),
48+
type:
49+
teethPaths.find((t) => t.name === id.replace("teeth-", ""))?.type ??
50+
"Unknown",
51+
})) ?? []
52+
);
53+
54+
const handleSubmit = (e: React.FormEvent) => {
55+
e.preventDefault();
56+
alert("Form submitted:\n" + JSON.stringify({ teeth: selected }, null, 2));
57+
};
58+
59+
return (
60+
<form
61+
style={{ display: "flex", flexDirection: "column", gap: 20 }}
62+
onSubmit={handleSubmit}
63+
>
64+
<Odontogram {...args} onChange={setSelected} />
65+
66+
<button
67+
type="submit"
68+
style={{
69+
padding: "10px 20px",
70+
background: "#4f46e5",
71+
color: "white",
72+
border: "none",
73+
borderRadius: 6,
74+
cursor: "pointer",
75+
}}
76+
>
77+
Submit Form
78+
</button>
79+
80+
<pre
81+
style={{
82+
marginTop: 20,
83+
padding: 10,
84+
background: "#eaeaea",
85+
borderRadius: 6,
86+
fontSize: 14,
87+
}}
88+
>
89+
{JSON.stringify({ teeth: selected }, null, 2)}
90+
</pre>
91+
</form>
92+
);
93+
};
94+
95+
export const Form = Template.bind({});
96+
Form.args = {
97+
theme: "light",
98+
colors: {},
99+
defaultSelected: ["teeth-11", "teeth-12", "teeth-22"],
100+
maxTeeth: 5
101+
};
102+
103+
const PureUncontrolledFormTemplate: StoryFn<typeof Odontogram> = (args) => {
104+
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
105+
e.preventDefault();
106+
107+
const formData = new FormData(e.currentTarget);
108+
const teethJson = formData.get("teeth") as string;
109+
110+
alert("Form submitted:\n" + teethJson);
111+
};
112+
113+
return (
114+
<form
115+
style={{ display: "flex", flexDirection: "column", gap: 20 }}
116+
onSubmit={handleSubmit}
117+
>
118+
<Odontogram {...args} />
119+
120+
<button
121+
type="submit"
122+
style={{
123+
padding: "10px 20px",
124+
background: "#4f46e5",
125+
color: "white",
126+
border: "none",
127+
borderRadius: 6,
128+
cursor: "pointer",
129+
}}
130+
>
131+
Submit Form
132+
</button>
133+
134+
<pre
135+
style={{
136+
marginTop: 20,
137+
padding: 10,
138+
background: "#eaeaea",
139+
borderRadius: 6,
140+
fontSize: 14,
141+
}}
142+
>
143+
{`FormData.teeth = (filled after submitting)`}
144+
</pre>
145+
</form>
146+
);
147+
};
148+
149+
export const PureUncontrolledForm = PureUncontrolledFormTemplate.bind({});
150+
PureUncontrolledForm.args = {
151+
name: "teeth",
152+
theme: "light",
153+
colors: {},
154+
defaultSelected: ["teeth-11", "teeth-12"],
155+
maxTeeth: 5
156+
};

src/type.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,6 @@ export interface OdontogramProps {
5454
};
5555
showTooltip?: boolean;
5656
showHalf?: "upper" | "lower" | "full";
57+
maxTeeth?: number;
58+
5759
}

0 commit comments

Comments
 (0)