Skip to content

Commit 85d26a0

Browse files
committed
fix: types issues
1 parent 09db4b0 commit 85d26a0

8 files changed

Lines changed: 152 additions & 170 deletions

File tree

biome.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,16 @@
5757
"noConsoleLog": {
5858
"fix": "none",
5959
"level": "warn"
60-
}
60+
},
61+
"noExplicitAny": "off"
6162
},
6263
"correctness": {
6364
"useImportExtensions": "off",
6465
"noUndeclaredDependencies": "off",
65-
"noUnusedVariables": "info",
66-
"noNodejsModules": "off"
66+
"noUnusedVariables": "off",
67+
"noNodejsModules": "off",
68+
"noUndeclaredVariables": "off",
69+
"noUnusedFunctionParameters": "off"
6770
}
6871
}
6972
},

package.json

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@
44
"version": "0.2.1",
55
"author": "Pratik Sharma <sharma.pratik2016@gmail.com>",
66
"license": "MIT",
7-
"keywords": [
8-
"odontogram",
9-
"react",
10-
"dental-chart"
11-
],
7+
"keywords": ["odontogram", "react", "dental-chart"],
128
"publishConfig": {
139
"access": "public"
1410
},
@@ -38,9 +34,7 @@
3834
"import": "./dist/index.mjs"
3935
}
4036
},
41-
"files": [
42-
"dist"
43-
],
37+
"files": ["dist"],
4438
"config": {
4539
"commitizen": {
4640
"path": "./node_modules/@ryansonshine/cz-conventional-changelog"

src/Odontogram.tsx

Lines changed: 81 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
import "./styles.css";
2-
import { useCallback, useRef, useState } from "react";
3-
import { teethPaths } from "./data";
2+
import {
3+
type CSSProperties,
4+
type FC,
5+
type KeyboardEvent,
6+
type MouseEvent,
7+
type ReactNode,
8+
useCallback,
9+
useRef,
10+
useState,
11+
} from "react";
412
import { OdontogramTooltip } from "./Tooltip";
13+
import { teethPaths } from "./data";
514

615
type Placement =
716
| "top"
@@ -17,6 +26,23 @@ type Placement =
1726
| "left-start"
1827
| "left-end";
1928

29+
const placements: Record<
30+
Placement,
31+
(toothBox: DOMRect, margin: number) => { x: number; y: number }
32+
> = {
33+
top: (t, m) => ({ x: t.left + t.width / 2, y: t.top - m }),
34+
"top-start": (t, m) => ({ x: t.left, y: t.top - m }),
35+
"top-end": (t, m) => ({ x: t.right, y: t.top - m }),
36+
bottom: (t, m) => ({ x: t.left + t.width / 2, y: t.bottom + m }),
37+
"bottom-start": (t, m) => ({ x: t.left, y: t.bottom + m }),
38+
"bottom-end": (t, m) => ({ x: t.right, y: t.bottom + m }),
39+
left: (t, m) => ({ x: t.left - m, y: t.top + t.height / 2 }),
40+
"left-start": (t, m) => ({ x: t.left - m, y: t.top }),
41+
"left-end": (t, m) => ({ x: t.left - m, y: t.bottom }),
42+
right: (t, m) => ({ x: t.right + m, y: t.top + t.height / 2 }),
43+
"right-start": (t, m) => ({ x: t.right + m, y: t.top }),
44+
"right-end": (t, m) => ({ x: t.right + m, y: t.bottom }),
45+
};
2046

2147
export interface TeethProps {
2248
name: string;
@@ -25,9 +51,9 @@ export interface TeethProps {
2551
lineHighlightPath: string | string[];
2652
selected?: boolean;
2753
onClick?: (name: string) => void;
28-
onKeyDown?: (e: React.KeyboardEvent<SVGGElement>, name: string) => void;
29-
children?: React.ReactNode;
30-
onHover?: (name: string, event: React.MouseEvent, placement?: Placement) => void;
54+
onKeyDown?: (e: KeyboardEvent<SVGGElement>, name: string) => void;
55+
children?: ReactNode;
56+
onHover?: (name: string, event: MouseEvent, placement?: Placement) => void;
3157
onLeave?: () => void;
3258
}
3359

@@ -57,8 +83,6 @@ export interface OdontogramProps {
5783
};
5884
showTooltip?: boolean;
5985
showHalf?: "upper" | "lower" | "full";
60-
61-
6286
}
6387

6488
export function convertFDIToNotation(
@@ -151,7 +175,6 @@ export const Teeth = ({
151175
onKeyDown={(e) => onKeyDown?.(e, name)}
152176
onMouseMove={(e) => onHover?.(name, e)}
153177
onMouseLeave={onLeave}
154-
role="button"
155178
aria-pressed={selected}
156179
aria-label={`Tooth ${name}`}
157180
style={{
@@ -170,9 +193,9 @@ export const Teeth = ({
170193
/>
171194
<path fill="currentColor" d={shadowPath} />
172195
{Array.isArray(lineHighlightPath) ? (
173-
lineHighlightPath.map((d, i) => (
196+
lineHighlightPath.map((d) => (
174197
<path
175-
key={i}
198+
key={`${d}`}
176199
stroke="currentColor"
177200
strokeLinecap="round"
178201
strokeLinejoin="round"
@@ -190,7 +213,7 @@ export const Teeth = ({
190213
</g>
191214
);
192215

193-
export const Odontogram: React.FC<OdontogramProps> = ({
216+
export const Odontogram: FC<OdontogramProps> = ({
194217
defaultSelected = [],
195218
onChange,
196219
className = "",
@@ -201,8 +224,7 @@ export const Odontogram: React.FC<OdontogramProps> = ({
201224
margin: 10,
202225
},
203226
showTooltip = true,
204-
showHalf = 'full',
205-
227+
showHalf = "full",
206228
}) => {
207229
const themeColors =
208230
theme === "dark"
@@ -222,7 +244,7 @@ export const Odontogram: React.FC<OdontogramProps> = ({
222244
);
223245

224246
const svgRef = useRef<SVGSVGElement>(null);
225-
const tooltipRef = useRef<HTMLDivElement>(null);
247+
const _tooltipRef = useRef<HTMLDivElement>(null);
226248

227249
const [tooltipData, setTooltipData] = useState<{
228250
active: boolean;
@@ -270,10 +292,30 @@ export const Odontogram: React.FC<OdontogramProps> = ({
270292
label: string;
271293
position: { x: number; y: number };
272294
}> = [
273-
{ name: "first", transform: "", label: "Upper Right", position: { x: 100, y: 30 } },
274-
{ name: "second", transform: "scale(-1, 1) translate(-409, 0)", label: "Upper Left", position: { x: 309, y: 30 } },
275-
{ name: "third", transform: "scale(1, -1) translate(0, -694)", label: "Lower Right", position: { x: 100, y: 664 } },
276-
{ name: "fourth", transform: "scale(-1, -1) translate(-409, -694)", label: "Lower Left", position: { x: 309, y: 664 } },
295+
{
296+
name: "first",
297+
transform: "",
298+
label: "Upper Right",
299+
position: { x: 100, y: 30 },
300+
},
301+
{
302+
name: "second",
303+
transform: "scale(-1, 1) translate(-409, 0)",
304+
label: "Upper Left",
305+
position: { x: 309, y: 30 },
306+
},
307+
{
308+
name: "third",
309+
transform: "scale(1, -1) translate(0, -694)",
310+
label: "Lower Right",
311+
position: { x: 100, y: 664 },
312+
},
313+
{
314+
name: "fourth",
315+
transform: "scale(-1, -1) translate(-409, -694)",
316+
label: "Lower Left",
317+
position: { x: 309, y: 664 },
318+
},
277319
];
278320

279321
let visibleQuadrants = quadrants;
@@ -283,98 +325,45 @@ export const Odontogram: React.FC<OdontogramProps> = ({
283325
visibleQuadrants = quadrants.slice(2);
284326
}
285327

286-
287-
288328
const handleHover = (
289329
name: string,
290330
e: React.MouseEvent,
291-
placement: Placement = "right" // default
331+
placement: Placement = "right", // default
292332
) => {
293333
const target = e.currentTarget as SVGGElement;
294334
const path = target.querySelector("path");
295335

296-
if (!path || !svgRef.current) return;
336+
if (!(path && svgRef.current)) {
337+
return;
338+
}
297339

298340
const toothBox = path.getBoundingClientRect();
299341
const svgBox = svgRef.current.getBoundingClientRect();
300342

301343
const margin = tooltip?.margin || 10; // distance between tooth and tooltip
302344

303345
// Compute tooltip position just above or below depending on space
304-
let x = toothBox.left
305-
let y = toothBox.top
306-
307-
switch (placement) {
308-
case "top":
309-
x = toothBox.left + toothBox.width / 2;
310-
y = toothBox.top - margin;
311-
break;
312-
case "top-start":
313-
x = toothBox.left;
314-
y = toothBox.top - margin;
315-
break;
316-
case "top-end":
317-
x = toothBox.right;
318-
y = toothBox.top - margin;
319-
break;
320-
case "bottom":
321-
x = toothBox.left + toothBox.width / 2;
322-
y = toothBox.bottom + margin;
323-
break;
324-
case "bottom-start":
325-
x = toothBox.left;
326-
y = toothBox.bottom + margin;
327-
break;
328-
case "bottom-end":
329-
x = toothBox.right;
330-
y = toothBox.bottom + margin;
331-
break;
332-
case "left":
333-
x = toothBox.left - margin;
334-
y = toothBox.top + toothBox.height / 2;
335-
break;
336-
case "left-start":
337-
x = toothBox.left - margin;
338-
y = toothBox.top;
339-
break;
340-
case "left-end":
341-
x = toothBox.left - margin;
342-
y = toothBox.bottom;
343-
break;
344-
case "right":
345-
x = toothBox.right + margin;
346-
y = toothBox.top + toothBox.height / 2;
347-
break;
348-
case "right-start":
349-
x = toothBox.right + margin;
350-
y = toothBox.top;
351-
break;
352-
case "right-end":
353-
x = toothBox.right + margin;
354-
y = toothBox.bottom;
355-
break;
356-
}
357346

347+
const { x, y } =
348+
placements[placement]?.(toothBox, margin) ??
349+
placements.right(toothBox, margin);
358350

359-
// If tooltip would go above svg, place it below instead
360-
if (y < svgBox.top) {
361-
y = toothBox.bottom + margin;
362-
}
351+
const safeY = y < svgBox.top ? toothBox.bottom + margin : y;
363352

364353
setTooltipData({
365354
active: true,
366-
position: { x, y },
355+
position: { x, y: safeY },
367356
payload: {
368357
id: name,
369358
notations: getToothNotations(name),
370-
type: teethPaths.find((t) => t.name === name.replace("teeth-", "").slice(1))
371-
?.type ?? "Unknown",
359+
type:
360+
teethPaths.find((t) => t.name === name.replace("teeth-", "").slice(1))
361+
?.type ?? "Unknown",
372362
},
373363
});
374364
};
375365
const handleLeave = () => setTooltipData((p) => ({ ...p, active: false }));
376366

377-
378367
const renderTeeth = (prefix: string) =>
379368
teethPaths.map((tooth) => {
380369
const id = `${prefix}${tooth.name}`;
@@ -396,14 +385,13 @@ export const Odontogram: React.FC<OdontogramProps> = ({
396385
);
397386
});
398387

399-
400388
const finalColors = { ...themeColors, ...mapToCssVars(colors) };
401389

402390
return (
403391
<div
404392
className={`Odontogram ${theme === "dark" ? "dark-theme" : ""}`}
405393
style={{
406-
...(finalColors as React.CSSProperties),
394+
...(finalColors as CSSProperties),
407395
width: "100%",
408396
maxWidth: 300,
409397
margin: "0 auto",
@@ -417,7 +405,13 @@ export const Odontogram: React.FC<OdontogramProps> = ({
417405
ref={svgRef}
418406
xmlns="http://www.w3.org/2000/svg"
419407
fill="none"
420-
viewBox={showHalf === "full" ? "0 0 409 694" : showHalf === 'upper' ? "0 0 409 347" : "0 200 409 694"}
408+
viewBox={
409+
showHalf === "full"
410+
? "0 0 409 694"
411+
: showHalf === "upper"
412+
? "0 0 409 347"
413+
: "0 200 409 694"
414+
}
421415
className="Odontogram"
422416
style={{
423417
width: "100%",
@@ -426,11 +420,10 @@ export const Odontogram: React.FC<OdontogramProps> = ({
426420
touchAction: "manipulation",
427421
}}
428422
>
429-
423+
<title>Odontogram</title>
430424
{visibleQuadrants.map(({ name, transform, label, position }, index) => (
431425
<g key={name} name={name} transform={transform}>
432426
{renderTeeth(`teeth-${index + 1}`)}
433-
434427
</g>
435428
))}
436429
</svg>

0 commit comments

Comments
 (0)