formanitor 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BpeChartWidget-HATASHAC.mjs +7 -0
- package/dist/BpeChartWidget-HATASHAC.mjs.map +1 -0
- package/dist/BpeChartWidget-VZRH7M7L.cjs +28 -0
- package/dist/BpeChartWidget-VZRH7M7L.cjs.map +1 -0
- package/dist/{DateTimeWidget-3AUBZYYK.mjs → DateTimeWidget-KRX4O6OD.mjs} +5 -4
- package/dist/DateTimeWidget-KRX4O6OD.mjs.map +1 -0
- package/dist/{DateTimeWidget-OS7ER5F6.cjs → DateTimeWidget-RJ7SATVA.cjs} +6 -5
- package/dist/DateTimeWidget-RJ7SATVA.cjs.map +1 -0
- package/dist/{DateWidget-KCTE6N5G.mjs → DateWidget-JEKDKPNS.mjs} +4 -3
- package/dist/DateWidget-JEKDKPNS.mjs.map +1 -0
- package/dist/{DateWidget-UNLX544Z.cjs → DateWidget-T7IQUWEA.cjs} +8 -7
- package/dist/DateWidget-T7IQUWEA.cjs.map +1 -0
- package/dist/DentalChartWidget-LYLOFWZU.cjs +21 -0
- package/dist/DentalChartWidget-LYLOFWZU.cjs.map +1 -0
- package/dist/DentalChartWidget-P2YPKAMO.mjs +8 -0
- package/dist/DentalChartWidget-P2YPKAMO.mjs.map +1 -0
- package/dist/{EditableTable-VQ72UEFF.cjs → EditableTable-OW5LC6OC.cjs} +6 -5
- package/dist/EditableTable-OW5LC6OC.cjs.map +1 -0
- package/dist/{EditableTable-XFCPKSUY.mjs → EditableTable-VZ66IXYI.mjs} +5 -4
- package/dist/EditableTable-VZ66IXYI.mjs.map +1 -0
- package/dist/ExtraOralExamWidget-JVKJ4ZWC.mjs +438 -0
- package/dist/ExtraOralExamWidget-JVKJ4ZWC.mjs.map +1 -0
- package/dist/ExtraOralExamWidget-ZIOSKMIO.cjs +440 -0
- package/dist/ExtraOralExamWidget-ZIOSKMIO.cjs.map +1 -0
- package/dist/{FollowupWidget-MAYTHM2E.cjs → FollowupWidget-2STSJSDY.cjs} +8 -7
- package/dist/FollowupWidget-2STSJSDY.cjs.map +1 -0
- package/dist/{FollowupWidget-BFZ6P2JE.mjs → FollowupWidget-GCGPWZVY.mjs} +4 -3
- package/dist/FollowupWidget-GCGPWZVY.mjs.map +1 -0
- package/dist/{OBGPathwayWidget-X67XKRIH.mjs → OBGPathwayWidget-QJNWUIEM.mjs} +4 -3
- package/dist/OBGPathwayWidget-QJNWUIEM.mjs.map +1 -0
- package/dist/{OBGPathwayWidget-XGN3HEWS.cjs → OBGPathwayWidget-YRU36UL7.cjs} +13 -12
- package/dist/OBGPathwayWidget-YRU36UL7.cjs.map +1 -0
- package/dist/{ObstetricHistoryWidget-Z4VAXH3E.mjs → ObstetricHistoryWidget-EW6JLNQ7.mjs} +4 -3
- package/dist/ObstetricHistoryWidget-EW6JLNQ7.mjs.map +1 -0
- package/dist/{ObstetricHistoryWidget-RP7NY4PV.cjs → ObstetricHistoryWidget-OOWCVFRB.cjs} +10 -9
- package/dist/ObstetricHistoryWidget-OOWCVFRB.cjs.map +1 -0
- package/dist/PregnancyStatusWidget-QTTVFBOE.cjs +96 -0
- package/dist/PregnancyStatusWidget-QTTVFBOE.cjs.map +1 -0
- package/dist/PregnancyStatusWidget-U2BEJGBJ.mjs +94 -0
- package/dist/PregnancyStatusWidget-U2BEJGBJ.mjs.map +1 -0
- package/dist/{SuggestionTextareaWidget-DY6M5JPO.cjs → SuggestionTextareaWidget-FWRZ46MV.cjs} +5 -5
- package/dist/{SuggestionTextareaWidget-DY6M5JPO.cjs.map → SuggestionTextareaWidget-FWRZ46MV.cjs.map} +1 -1
- package/dist/{SuggestionTextareaWidget-GQTWCFBG.mjs → SuggestionTextareaWidget-UNL3FZRI.mjs} +3 -3
- package/dist/{SuggestionTextareaWidget-GQTWCFBG.mjs.map → SuggestionTextareaWidget-UNL3FZRI.mjs.map} +1 -1
- package/dist/TreatmentPlanWidget-665HLKYV.mjs +317 -0
- package/dist/TreatmentPlanWidget-665HLKYV.mjs.map +1 -0
- package/dist/TreatmentPlanWidget-TATWSPLY.cjs +319 -0
- package/dist/TreatmentPlanWidget-TATWSPLY.cjs.map +1 -0
- package/dist/{chunk-4PMNVBJD.mjs → chunk-2OMQV2ZB.mjs} +4 -3
- package/dist/chunk-2OMQV2ZB.mjs.map +1 -0
- package/dist/chunk-5RT3S67O.cjs +30 -0
- package/dist/chunk-5RT3S67O.cjs.map +1 -0
- package/dist/chunk-6YUVILN5.mjs +42 -0
- package/dist/chunk-6YUVILN5.mjs.map +1 -0
- package/dist/{chunk-YEFM2ERQ.cjs → chunk-7OQFO6TM.cjs} +8 -7
- package/dist/chunk-7OQFO6TM.cjs.map +1 -0
- package/dist/chunk-BBD3Y37O.cjs +220 -0
- package/dist/chunk-BBD3Y37O.cjs.map +1 -0
- package/dist/chunk-EJ7MKHER.mjs +45 -0
- package/dist/chunk-EJ7MKHER.mjs.map +1 -0
- package/dist/{chunk-XN2QLBLT.mjs → chunk-G6Y4UJPN.mjs} +5 -4
- package/dist/chunk-G6Y4UJPN.mjs.map +1 -0
- package/dist/{chunk-AZSAPO2V.cjs → chunk-HXY3IX3G.cjs} +3 -44
- package/dist/chunk-HXY3IX3G.cjs.map +1 -0
- package/dist/{chunk-BMNY7F6H.mjs → chunk-JM7WNDNT.mjs} +4 -21
- package/dist/chunk-JM7WNDNT.mjs.map +1 -0
- package/dist/chunk-MQHZ7HD2.mjs +215 -0
- package/dist/chunk-MQHZ7HD2.mjs.map +1 -0
- package/dist/{chunk-ML47UEDU.cjs → chunk-O4FSJPU3.cjs} +2 -27
- package/dist/chunk-O4FSJPU3.cjs.map +1 -0
- package/dist/chunk-Q66LXMRR.mjs +28 -0
- package/dist/chunk-Q66LXMRR.mjs.map +1 -0
- package/dist/chunk-RILRMRXB.cjs +50 -0
- package/dist/chunk-RILRMRXB.cjs.map +1 -0
- package/dist/chunk-SQ2KNAUD.cjs +64 -0
- package/dist/chunk-SQ2KNAUD.cjs.map +1 -0
- package/dist/{chunk-TVFUWRTE.cjs → chunk-TCQQUJCL.cjs} +5 -4
- package/dist/chunk-TCQQUJCL.cjs.map +1 -0
- package/dist/chunk-UKSP3B3W.mjs +600 -0
- package/dist/chunk-UKSP3B3W.mjs.map +1 -0
- package/dist/chunk-X4AJCTON.cjs +607 -0
- package/dist/chunk-X4AJCTON.cjs.map +1 -0
- package/dist/chunk-ZZX3IG2T.mjs +25 -0
- package/dist/chunk-ZZX3IG2T.mjs.map +1 -0
- package/dist/index.cjs +107 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -3
- package/dist/index.d.ts +69 -3
- package/dist/index.mjs +73 -43
- package/dist/index.mjs.map +1 -1
- package/dist/read-only-table.d.cts +1 -1
- package/dist/read-only-table.d.ts +1 -1
- package/dist/smart.d.cts +1 -1
- package/dist/smart.d.ts +1 -1
- package/dist/{types-CYtJk8H9.d.ts → types-BbOnd5IN.d.cts} +53 -3
- package/dist/{types-CYtJk8H9.d.cts → types-BbOnd5IN.d.ts} +53 -3
- package/package.json +1 -1
- package/dist/DateTimeWidget-3AUBZYYK.mjs.map +0 -1
- package/dist/DateTimeWidget-OS7ER5F6.cjs.map +0 -1
- package/dist/DateWidget-KCTE6N5G.mjs.map +0 -1
- package/dist/DateWidget-UNLX544Z.cjs.map +0 -1
- package/dist/EditableTable-VQ72UEFF.cjs.map +0 -1
- package/dist/EditableTable-XFCPKSUY.mjs.map +0 -1
- package/dist/FollowupWidget-BFZ6P2JE.mjs.map +0 -1
- package/dist/FollowupWidget-MAYTHM2E.cjs.map +0 -1
- package/dist/OBGPathwayWidget-X67XKRIH.mjs.map +0 -1
- package/dist/OBGPathwayWidget-XGN3HEWS.cjs.map +0 -1
- package/dist/ObstetricHistoryWidget-RP7NY4PV.cjs.map +0 -1
- package/dist/ObstetricHistoryWidget-Z4VAXH3E.mjs.map +0 -1
- package/dist/chunk-4HDMR2LX.mjs +0 -69
- package/dist/chunk-4HDMR2LX.mjs.map +0 -1
- package/dist/chunk-4PMNVBJD.mjs.map +0 -1
- package/dist/chunk-AZSAPO2V.cjs.map +0 -1
- package/dist/chunk-BMNY7F6H.mjs.map +0 -1
- package/dist/chunk-ML47UEDU.cjs.map +0 -1
- package/dist/chunk-TVFUWRTE.cjs.map +0 -1
- package/dist/chunk-XN2QLBLT.mjs.map +0 -1
- package/dist/chunk-YEFM2ERQ.cjs.map +0 -1
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkPHADAQSH_cjs = require('./chunk-PHADAQSH.cjs');
|
|
4
|
+
var chunkRILRMRXB_cjs = require('./chunk-RILRMRXB.cjs');
|
|
5
|
+
var chunkO3VQBPEW_cjs = require('./chunk-O3VQBPEW.cjs');
|
|
6
|
+
var chunkTB33A4PD_cjs = require('./chunk-TB33A4PD.cjs');
|
|
7
|
+
var chunkFHHISVCH_cjs = require('./chunk-FHHISVCH.cjs');
|
|
8
|
+
var react = require('react');
|
|
9
|
+
var lucideReact = require('lucide-react');
|
|
10
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
11
|
+
|
|
12
|
+
// src/core/dentalChart.ts
|
|
13
|
+
var CONDITION_CONFIG = {
|
|
14
|
+
cavity: { label: "Cavity", color: "#ef4444" },
|
|
15
|
+
filled: { label: "Filled", color: "#3b82f6" },
|
|
16
|
+
crown: { label: "Crown", color: "#f59e0b" },
|
|
17
|
+
missing: { label: "Missing", color: "#9ca3af" },
|
|
18
|
+
root_canal: { label: "Root Canal (RCT)", color: "#a855f7" },
|
|
19
|
+
bridge: { label: "Bridge", color: "#f97316" },
|
|
20
|
+
implant: { label: "Implant", color: "#14b8a6" },
|
|
21
|
+
fractured: { label: "Fractured", color: "#eab308" },
|
|
22
|
+
impacted: { label: "Impacted", color: "#6366f1" }
|
|
23
|
+
};
|
|
24
|
+
var ALL_CONDITIONS = Object.keys(CONDITION_CONFIG);
|
|
25
|
+
var QUADRANTS = {
|
|
26
|
+
upperRight: [11, 12, 13, 14, 15, 16, 17, 18],
|
|
27
|
+
upperLeft: [21, 22, 23, 24, 25, 26, 27, 28],
|
|
28
|
+
lowerLeft: [31, 32, 33, 34, 35, 36, 37, 38],
|
|
29
|
+
lowerRight: [41, 42, 43, 44, 45, 46, 47, 48]
|
|
30
|
+
};
|
|
31
|
+
var TOOTH_NAMES = {
|
|
32
|
+
11: "UR Central Incisor",
|
|
33
|
+
12: "UR Lateral Incisor",
|
|
34
|
+
13: "UR Canine",
|
|
35
|
+
14: "UR 1st Premolar",
|
|
36
|
+
15: "UR 2nd Premolar",
|
|
37
|
+
16: "UR 1st Molar",
|
|
38
|
+
17: "UR 2nd Molar",
|
|
39
|
+
18: "UR 3rd Molar",
|
|
40
|
+
21: "UL Central Incisor",
|
|
41
|
+
22: "UL Lateral Incisor",
|
|
42
|
+
23: "UL Canine",
|
|
43
|
+
24: "UL 1st Premolar",
|
|
44
|
+
25: "UL 2nd Premolar",
|
|
45
|
+
26: "UL 1st Molar",
|
|
46
|
+
27: "UL 2nd Molar",
|
|
47
|
+
28: "UL 3rd Molar",
|
|
48
|
+
31: "LL Central Incisor",
|
|
49
|
+
32: "LL Lateral Incisor",
|
|
50
|
+
33: "LL Canine",
|
|
51
|
+
34: "LL 1st Premolar",
|
|
52
|
+
35: "LL 2nd Premolar",
|
|
53
|
+
36: "LL 1st Molar",
|
|
54
|
+
37: "LL 2nd Molar",
|
|
55
|
+
38: "LL 3rd Molar",
|
|
56
|
+
41: "LR Central Incisor",
|
|
57
|
+
42: "LR Lateral Incisor",
|
|
58
|
+
43: "LR Canine",
|
|
59
|
+
44: "LR 1st Premolar",
|
|
60
|
+
45: "LR 2nd Premolar",
|
|
61
|
+
46: "LR 1st Molar",
|
|
62
|
+
47: "LR 2nd Molar",
|
|
63
|
+
48: "LR 3rd Molar"
|
|
64
|
+
};
|
|
65
|
+
function toothLabel(id) {
|
|
66
|
+
return TOOTH_NAMES[id] ?? `Tooth ${id}`;
|
|
67
|
+
}
|
|
68
|
+
var SURFACE_CONDITIONS = ["cavity", "filled", "fractured"];
|
|
69
|
+
var ANTERIOR_TEETH = /* @__PURE__ */ new Set([13, 12, 11, 21, 22, 23, 43, 42, 41, 31, 32, 33]);
|
|
70
|
+
function getToothSurfaces(id) {
|
|
71
|
+
const isUpper = id >= 11 && id <= 28;
|
|
72
|
+
const isAnterior = ANTERIOR_TEETH.has(id);
|
|
73
|
+
return [
|
|
74
|
+
"Buccal",
|
|
75
|
+
"Mesial",
|
|
76
|
+
"Distal",
|
|
77
|
+
isAnterior ? "Incisal" : "Occlusal",
|
|
78
|
+
isUpper ? "Palatal" : "Lingual"
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
function normalizeDentalChart(value) {
|
|
82
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
83
|
+
const v = value;
|
|
84
|
+
if (v.teeth && typeof v.teeth === "object" && !Array.isArray(v.teeth)) {
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return { teeth: {} };
|
|
89
|
+
}
|
|
90
|
+
function ToothEditor({
|
|
91
|
+
id,
|
|
92
|
+
entry,
|
|
93
|
+
onChange
|
|
94
|
+
}) {
|
|
95
|
+
const conditions = entry?.conditions ?? [];
|
|
96
|
+
const surfaces = entry?.surfaces ?? {};
|
|
97
|
+
const notes = entry?.notes ?? "";
|
|
98
|
+
const availableSurfaces = getToothSurfaces(id);
|
|
99
|
+
const buildEntry = (nextConditions, nextSurfaces, nextNotes) => ({
|
|
100
|
+
conditions: nextConditions,
|
|
101
|
+
surfaces: Object.keys(nextSurfaces).length ? nextSurfaces : void 0,
|
|
102
|
+
notes: nextNotes || void 0
|
|
103
|
+
});
|
|
104
|
+
const toggle = (c) => {
|
|
105
|
+
const isActive = conditions.includes(c);
|
|
106
|
+
const nextConditions = isActive ? conditions.filter((x) => x !== c) : [...conditions, c];
|
|
107
|
+
const nextSurfaces = { ...surfaces };
|
|
108
|
+
if (isActive) delete nextSurfaces[c];
|
|
109
|
+
onChange(buildEntry(nextConditions, nextSurfaces, notes));
|
|
110
|
+
};
|
|
111
|
+
const toggleSurface = (c, surface) => {
|
|
112
|
+
const current = surfaces[c] ?? [];
|
|
113
|
+
const next = current.includes(surface) ? current.filter((s) => s !== surface) : [...current, surface];
|
|
114
|
+
const nextSurfaces = { ...surfaces, [c]: next.length ? next : [] };
|
|
115
|
+
onChange(buildEntry(conditions, nextSurfaces, notes));
|
|
116
|
+
};
|
|
117
|
+
const updateNotes = (v) => onChange(buildEntry(conditions, surfaces, v));
|
|
118
|
+
const activeSurfaceConditions = SURFACE_CONDITIONS.filter(
|
|
119
|
+
(c) => conditions.includes(c)
|
|
120
|
+
);
|
|
121
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
122
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
123
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
124
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs font-semibold text-foreground", children: [
|
|
125
|
+
"Tooth ",
|
|
126
|
+
id
|
|
127
|
+
] }),
|
|
128
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-muted-foreground", children: toothLabel(id) })
|
|
129
|
+
] }),
|
|
130
|
+
conditions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
131
|
+
"button",
|
|
132
|
+
{
|
|
133
|
+
type: "button",
|
|
134
|
+
onClick: () => onChange({ conditions: [] }),
|
|
135
|
+
className: "flex shrink-0 items-center gap-1 text-[10px] text-destructive hover:underline",
|
|
136
|
+
children: [
|
|
137
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3 w-3" }),
|
|
138
|
+
"Clear"
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
)
|
|
142
|
+
] }),
|
|
143
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5", children: ALL_CONDITIONS.map((c) => {
|
|
144
|
+
const cfg = CONDITION_CONFIG[c];
|
|
145
|
+
const active = conditions.includes(c);
|
|
146
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
147
|
+
"button",
|
|
148
|
+
{
|
|
149
|
+
type: "button",
|
|
150
|
+
onClick: () => toggle(c),
|
|
151
|
+
className: chunkFHHISVCH_cjs.cn(
|
|
152
|
+
"rounded-full border px-2.5 py-0.5 text-[10px] font-medium transition-all",
|
|
153
|
+
active ? "text-white" : "border-border bg-background text-muted-foreground hover:border-gray-400"
|
|
154
|
+
),
|
|
155
|
+
style: active ? { backgroundColor: cfg.color, borderColor: cfg.color } : void 0,
|
|
156
|
+
children: cfg.label
|
|
157
|
+
},
|
|
158
|
+
c
|
|
159
|
+
);
|
|
160
|
+
}) }),
|
|
161
|
+
activeSurfaceConditions.map((c) => {
|
|
162
|
+
const cfg = CONDITION_CONFIG[c];
|
|
163
|
+
const selected = surfaces[c] ?? [];
|
|
164
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
165
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
166
|
+
"p",
|
|
167
|
+
{
|
|
168
|
+
className: "text-[10px] font-semibold uppercase tracking-wide",
|
|
169
|
+
style: { color: cfg.color },
|
|
170
|
+
children: [
|
|
171
|
+
cfg.label,
|
|
172
|
+
" \u2014 surfaces"
|
|
173
|
+
]
|
|
174
|
+
}
|
|
175
|
+
),
|
|
176
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", children: availableSurfaces.map((surface) => {
|
|
177
|
+
const on = selected.includes(surface);
|
|
178
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
179
|
+
"button",
|
|
180
|
+
{
|
|
181
|
+
type: "button",
|
|
182
|
+
onClick: () => toggleSurface(c, surface),
|
|
183
|
+
className: chunkFHHISVCH_cjs.cn(
|
|
184
|
+
"rounded border px-2 py-0.5 text-[10px] font-medium transition-all",
|
|
185
|
+
on ? "text-white" : "border-border bg-background text-muted-foreground hover:border-gray-400"
|
|
186
|
+
),
|
|
187
|
+
style: on ? { backgroundColor: cfg.color, borderColor: cfg.color } : void 0,
|
|
188
|
+
children: surface
|
|
189
|
+
},
|
|
190
|
+
surface
|
|
191
|
+
);
|
|
192
|
+
}) })
|
|
193
|
+
] }, c);
|
|
194
|
+
}),
|
|
195
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
196
|
+
chunkPHADAQSH_cjs.Textarea,
|
|
197
|
+
{
|
|
198
|
+
value: notes,
|
|
199
|
+
onChange: (e) => updateNotes(e.target.value),
|
|
200
|
+
placeholder: "Notes for this tooth\u2026",
|
|
201
|
+
className: "h-16 resize-none text-xs"
|
|
202
|
+
}
|
|
203
|
+
)
|
|
204
|
+
] });
|
|
205
|
+
}
|
|
206
|
+
function ToothButton({
|
|
207
|
+
id,
|
|
208
|
+
entry,
|
|
209
|
+
isUpper,
|
|
210
|
+
onChange
|
|
211
|
+
}) {
|
|
212
|
+
const conditions = entry?.conditions ?? [];
|
|
213
|
+
const isMissing = conditions.includes("missing");
|
|
214
|
+
const primary = isMissing ? "missing" : conditions[0] ?? null;
|
|
215
|
+
const primaryColor = primary ? CONDITION_CONFIG[primary].color : null;
|
|
216
|
+
const multiCount = conditions.length > 1 ? conditions.length : null;
|
|
217
|
+
const boxStyle = {
|
|
218
|
+
position: "relative",
|
|
219
|
+
width: 46,
|
|
220
|
+
height: 58,
|
|
221
|
+
flexShrink: 0,
|
|
222
|
+
display: "flex",
|
|
223
|
+
flexDirection: "column",
|
|
224
|
+
borderRadius: 6,
|
|
225
|
+
border: "1px solid",
|
|
226
|
+
borderColor: !isMissing && primaryColor ? primaryColor : isMissing ? "#d1d5db" : "#e5e7eb",
|
|
227
|
+
backgroundColor: isMissing ? "#f3f4f6" : "#ffffff",
|
|
228
|
+
cursor: "pointer",
|
|
229
|
+
userSelect: "none",
|
|
230
|
+
outline: "none",
|
|
231
|
+
transition: "box-shadow 0.15s"
|
|
232
|
+
};
|
|
233
|
+
const numberStyle = {
|
|
234
|
+
flex: 1,
|
|
235
|
+
display: "flex",
|
|
236
|
+
alignItems: "center",
|
|
237
|
+
justifyContent: "center",
|
|
238
|
+
fontSize: 11,
|
|
239
|
+
fontWeight: 700,
|
|
240
|
+
color: isMissing ? "#9ca3af" : "#374151",
|
|
241
|
+
lineHeight: 1
|
|
242
|
+
};
|
|
243
|
+
const stripStyle = (rounded) => ({
|
|
244
|
+
height: 10,
|
|
245
|
+
flexShrink: 0,
|
|
246
|
+
borderRadius: rounded === "bottom" ? "0 0 5px 5px" : "5px 5px 0 0",
|
|
247
|
+
backgroundColor: !isMissing && primaryColor ? primaryColor : "transparent"
|
|
248
|
+
});
|
|
249
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(chunkRILRMRXB_cjs.Popover, { children: [
|
|
250
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkRILRMRXB_cjs.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
251
|
+
"button",
|
|
252
|
+
{
|
|
253
|
+
type: "button",
|
|
254
|
+
title: toothLabel(id),
|
|
255
|
+
style: boxStyle,
|
|
256
|
+
className: "hover:ring-2 hover:ring-primary/30 focus:ring-2 focus:ring-primary/40",
|
|
257
|
+
children: [
|
|
258
|
+
isUpper ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
259
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: numberStyle, children: isMissing ? "\u2715" : id }),
|
|
260
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: stripStyle("bottom") })
|
|
261
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
262
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: stripStyle("top") }),
|
|
263
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: numberStyle, children: isMissing ? "\u2715" : id })
|
|
264
|
+
] }),
|
|
265
|
+
multiCount && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1.5 -right-1.5 z-10 flex h-3.5 w-3.5 items-center justify-center rounded-full bg-primary text-[7px] font-bold text-primary-foreground", children: multiCount })
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
) }),
|
|
269
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkRILRMRXB_cjs.PopoverContent, { className: "w-72 p-3", side: isUpper ? "top" : "bottom", align: "center", sideOffset: 6, children: /* @__PURE__ */ jsxRuntime.jsx(ToothEditor, { id, entry, onChange }) })
|
|
270
|
+
] });
|
|
271
|
+
}
|
|
272
|
+
var ANTERIOR_IDS = /* @__PURE__ */ new Set([13, 12, 11, 21, 22, 23, 43, 42, 41, 31, 32, 33]);
|
|
273
|
+
function buildSurfaceColorMap(entry) {
|
|
274
|
+
if (!entry?.surfaces) return {};
|
|
275
|
+
const map = {};
|
|
276
|
+
for (const cond of SURFACE_CONDITIONS) {
|
|
277
|
+
const surfs = entry.surfaces[cond];
|
|
278
|
+
if (!surfs?.length) continue;
|
|
279
|
+
const color = CONDITION_CONFIG[cond]?.color;
|
|
280
|
+
if (!color) continue;
|
|
281
|
+
for (const s of surfs) map[s] = color;
|
|
282
|
+
}
|
|
283
|
+
return map;
|
|
284
|
+
}
|
|
285
|
+
function ToothDiagram({ id, entry }) {
|
|
286
|
+
const colorMap = buildSurfaceColorMap(entry);
|
|
287
|
+
const hasSurfaces = Object.keys(colorMap).length > 0;
|
|
288
|
+
const isUpper = id >= 11 && id <= 28;
|
|
289
|
+
const bottomLabel = isUpper ? "Palatal" : "Lingual";
|
|
290
|
+
const centerLabel = ANTERIOR_IDS.has(id) ? "Incisal" : "Occlusal";
|
|
291
|
+
const S = 46;
|
|
292
|
+
const I = 11;
|
|
293
|
+
const segments = [
|
|
294
|
+
{ key: "Buccal", d: `M0,0 L${S},0 L${S - I},${I} L${I},${I}Z` },
|
|
295
|
+
{ key: "Mesial", d: `M0,0 L0,${S} L${I},${S - I} L${I},${I}Z` },
|
|
296
|
+
{ key: "Distal", d: `M${S},0 L${S},${S} L${S - I},${S - I} L${S - I},${I}Z` },
|
|
297
|
+
{ key: bottomLabel, d: `M0,${S} L${S},${S} L${S - I},${S - I} L${I},${S - I}Z` },
|
|
298
|
+
{ key: centerLabel, d: `M${I},${I} L${S - I},${I} L${S - I},${S - I} L${I},${S - I}Z` }
|
|
299
|
+
];
|
|
300
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
301
|
+
"svg",
|
|
302
|
+
{
|
|
303
|
+
width: S,
|
|
304
|
+
height: S,
|
|
305
|
+
viewBox: `0 0 ${S} ${S}`,
|
|
306
|
+
style: { flexShrink: 0, opacity: hasSurfaces ? 1 : 0.3 },
|
|
307
|
+
children: segments.map(({ key, d }) => {
|
|
308
|
+
const color = colorMap[key];
|
|
309
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
310
|
+
"path",
|
|
311
|
+
{
|
|
312
|
+
d,
|
|
313
|
+
fill: color ?? "#f1f5f9",
|
|
314
|
+
stroke: color ? color : "#cbd5e1",
|
|
315
|
+
strokeWidth: "1",
|
|
316
|
+
strokeLinejoin: "round"
|
|
317
|
+
},
|
|
318
|
+
key
|
|
319
|
+
);
|
|
320
|
+
})
|
|
321
|
+
}
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
function ArchRow({
|
|
325
|
+
teeth: toothIds,
|
|
326
|
+
isUpper,
|
|
327
|
+
data,
|
|
328
|
+
onChange,
|
|
329
|
+
reverseOrder = false
|
|
330
|
+
}) {
|
|
331
|
+
const ordered = reverseOrder ? [...toothIds].reverse() : toothIds;
|
|
332
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1", children: ordered.map((id) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
|
|
333
|
+
isUpper && /* @__PURE__ */ jsxRuntime.jsx(ToothDiagram, { id, entry: data[String(id)] }),
|
|
334
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
335
|
+
ToothButton,
|
|
336
|
+
{
|
|
337
|
+
id,
|
|
338
|
+
entry: data[String(id)],
|
|
339
|
+
isUpper,
|
|
340
|
+
onChange: (entry) => onChange(id, entry)
|
|
341
|
+
}
|
|
342
|
+
),
|
|
343
|
+
!isUpper && /* @__PURE__ */ jsxRuntime.jsx(ToothDiagram, { id, entry: data[String(id)] })
|
|
344
|
+
] }, id)) });
|
|
345
|
+
}
|
|
346
|
+
function ChartLegend() {
|
|
347
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-x-4 gap-y-1.5", children: ALL_CONDITIONS.map((c) => {
|
|
348
|
+
const cfg = CONDITION_CONFIG[c];
|
|
349
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
350
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-2.5 w-2.5 shrink-0 rounded-full", style: { backgroundColor: cfg.color } }),
|
|
351
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: cfg.label })
|
|
352
|
+
] }, c);
|
|
353
|
+
}) });
|
|
354
|
+
}
|
|
355
|
+
var DentalChartWidget = ({ fieldId }) => {
|
|
356
|
+
const { value, setValue, setTouched, disabled } = chunkTB33A4PD_cjs.useField(fieldId);
|
|
357
|
+
const data = normalizeDentalChart(value);
|
|
358
|
+
const teeth = data.teeth;
|
|
359
|
+
const handleToothChange = react.useCallback(
|
|
360
|
+
(id, entry) => {
|
|
361
|
+
const next = { ...teeth };
|
|
362
|
+
if (entry.conditions.length === 0 && !entry.notes) {
|
|
363
|
+
delete next[String(id)];
|
|
364
|
+
} else {
|
|
365
|
+
next[String(id)] = entry;
|
|
366
|
+
}
|
|
367
|
+
setValue({ teeth: next });
|
|
368
|
+
setTouched();
|
|
369
|
+
},
|
|
370
|
+
[teeth, setValue, setTouched]
|
|
371
|
+
);
|
|
372
|
+
const markedCount = Object.keys(teeth).length;
|
|
373
|
+
if (disabled) {
|
|
374
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DentalChartDisplay, { data });
|
|
375
|
+
}
|
|
376
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-border/60 bg-card shadow-sm", children: [
|
|
377
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-b border-border/60 px-4 py-3", children: [
|
|
378
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
379
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Intra Oral Examination \u2013 Dental Chart" }),
|
|
380
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-0.5 text-[11px] text-muted-foreground", children: [
|
|
381
|
+
"Click any tooth to mark conditions",
|
|
382
|
+
markedCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-1 font-medium text-foreground", children: [
|
|
383
|
+
"\xB7 ",
|
|
384
|
+
markedCount,
|
|
385
|
+
" ",
|
|
386
|
+
markedCount !== 1 ? "teeth" : "tooth",
|
|
387
|
+
" marked"
|
|
388
|
+
] })
|
|
389
|
+
] })
|
|
390
|
+
] }),
|
|
391
|
+
markedCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
392
|
+
chunkO3VQBPEW_cjs.Button,
|
|
393
|
+
{
|
|
394
|
+
type: "button",
|
|
395
|
+
variant: "ghost",
|
|
396
|
+
size: "sm",
|
|
397
|
+
onClick: () => {
|
|
398
|
+
setValue({ teeth: {} });
|
|
399
|
+
setTouched();
|
|
400
|
+
},
|
|
401
|
+
className: "h-7 gap-1 text-xs text-destructive hover:text-destructive",
|
|
402
|
+
children: [
|
|
403
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3" }),
|
|
404
|
+
"Clear all"
|
|
405
|
+
]
|
|
406
|
+
}
|
|
407
|
+
)
|
|
408
|
+
] }),
|
|
409
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto px-4 py-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0", children: [
|
|
410
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex", children: [
|
|
411
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
412
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: "UR" }),
|
|
413
|
+
/* @__PURE__ */ jsxRuntime.jsx(ArchRow, { teeth: QUADRANTS.upperRight, isUpper: true, data: teeth, onChange: handleToothChange, reverseOrder: true })
|
|
414
|
+
] }),
|
|
415
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-2 h-[58px] w-px bg-border" }),
|
|
416
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
417
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: "UL" }),
|
|
418
|
+
/* @__PURE__ */ jsxRuntime.jsx(ArchRow, { teeth: QUADRANTS.upperLeft, isUpper: true, data: teeth, onChange: handleToothChange })
|
|
419
|
+
] })
|
|
420
|
+
] }),
|
|
421
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-2 flex w-full items-center gap-2", children: [
|
|
422
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-border" }),
|
|
423
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: "Occlusal" }),
|
|
424
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-border" })
|
|
425
|
+
] }),
|
|
426
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex", children: [
|
|
427
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
428
|
+
/* @__PURE__ */ jsxRuntime.jsx(ArchRow, { teeth: QUADRANTS.lowerRight, isUpper: false, data: teeth, onChange: handleToothChange, reverseOrder: true }),
|
|
429
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: "LR" })
|
|
430
|
+
] }),
|
|
431
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-2 h-[58px] w-px bg-border" }),
|
|
432
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
433
|
+
/* @__PURE__ */ jsxRuntime.jsx(ArchRow, { teeth: QUADRANTS.lowerLeft, isUpper: false, data: teeth, onChange: handleToothChange }),
|
|
434
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: "LL" })
|
|
435
|
+
] })
|
|
436
|
+
] })
|
|
437
|
+
] }) }) }),
|
|
438
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-border/60 px-4 py-3", children: [
|
|
439
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Legend" }),
|
|
440
|
+
/* @__PURE__ */ jsxRuntime.jsx(ChartLegend, {})
|
|
441
|
+
] })
|
|
442
|
+
] });
|
|
443
|
+
};
|
|
444
|
+
function DentalChartDisplay({ data }) {
|
|
445
|
+
const teeth = data.teeth ?? {};
|
|
446
|
+
const markedCount = Object.keys(teeth).length;
|
|
447
|
+
if (markedCount === 0) {
|
|
448
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl border border-border/60 bg-card px-4 py-8 text-center text-sm text-muted-foreground shadow-sm", children: "No dental findings recorded" });
|
|
449
|
+
}
|
|
450
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DentalChartReadOnly, { data });
|
|
451
|
+
}
|
|
452
|
+
function DentalChartReadOnly({
|
|
453
|
+
data,
|
|
454
|
+
className
|
|
455
|
+
}) {
|
|
456
|
+
const teeth = data.teeth ?? {};
|
|
457
|
+
const markedCount = Object.keys(teeth).length;
|
|
458
|
+
const usedConditions = new Set(
|
|
459
|
+
Object.values(teeth).flatMap((e) => e.conditions ?? [])
|
|
460
|
+
);
|
|
461
|
+
const toothNotes = Object.entries(teeth).filter(([, e]) => e.notes).map(([id, e]) => ({ id: Number(id), label: toothLabel(Number(id)), notes: e.notes }));
|
|
462
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkFHHISVCH_cjs.cn("rounded-xl border border-border/60 bg-card shadow-sm", className), children: [
|
|
463
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between border-b border-border/60 px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
464
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Intra Oral Examination \u2013 Dental Chart" }),
|
|
465
|
+
markedCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-0.5 text-[11px] text-muted-foreground", children: [
|
|
466
|
+
markedCount,
|
|
467
|
+
" ",
|
|
468
|
+
markedCount !== 1 ? "teeth" : "tooth",
|
|
469
|
+
" marked"
|
|
470
|
+
] })
|
|
471
|
+
] }) }),
|
|
472
|
+
markedCount === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-8 text-center text-sm text-muted-foreground", children: "No dental findings recorded" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
473
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto px-4 py-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0", children: [
|
|
474
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex", children: [
|
|
475
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
476
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: "UR" }),
|
|
477
|
+
/* @__PURE__ */ jsxRuntime.jsx(ReadOnlyArchRow, { teeth: QUADRANTS.upperRight, isUpper: true, data: teeth, reverseOrder: true })
|
|
478
|
+
] }),
|
|
479
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-2 h-[58px] w-px bg-border" }),
|
|
480
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
481
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: "UL" }),
|
|
482
|
+
/* @__PURE__ */ jsxRuntime.jsx(ReadOnlyArchRow, { teeth: QUADRANTS.upperLeft, isUpper: true, data: teeth })
|
|
483
|
+
] })
|
|
484
|
+
] }),
|
|
485
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-2 flex w-full items-center gap-2", children: [
|
|
486
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-border" }),
|
|
487
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: "Occlusal" }),
|
|
488
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-border" })
|
|
489
|
+
] }),
|
|
490
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex", children: [
|
|
491
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
492
|
+
/* @__PURE__ */ jsxRuntime.jsx(ReadOnlyArchRow, { teeth: QUADRANTS.lowerRight, isUpper: false, data: teeth, reverseOrder: true }),
|
|
493
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: "LR" })
|
|
494
|
+
] }),
|
|
495
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-2 h-[58px] w-px bg-border" }),
|
|
496
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
497
|
+
/* @__PURE__ */ jsxRuntime.jsx(ReadOnlyArchRow, { teeth: QUADRANTS.lowerLeft, isUpper: false, data: teeth }),
|
|
498
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: "LL" })
|
|
499
|
+
] })
|
|
500
|
+
] })
|
|
501
|
+
] }) }) }),
|
|
502
|
+
usedConditions.size > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-border/60 px-4 py-3", children: [
|
|
503
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Legend" }),
|
|
504
|
+
/* @__PURE__ */ jsxRuntime.jsx(ReadOnlyLegend, { usedConditions })
|
|
505
|
+
] }),
|
|
506
|
+
toothNotes.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-border/60 px-4 py-3", children: [
|
|
507
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Tooth Notes" }),
|
|
508
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: toothNotes.map(({ id, label, notes }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 text-xs", children: [
|
|
509
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 font-medium text-foreground", children: id }),
|
|
510
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
|
|
511
|
+
label,
|
|
512
|
+
":"
|
|
513
|
+
] }),
|
|
514
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground", children: notes })
|
|
515
|
+
] }, id)) })
|
|
516
|
+
] })
|
|
517
|
+
] })
|
|
518
|
+
] });
|
|
519
|
+
}
|
|
520
|
+
function ReadOnlyTooth({
|
|
521
|
+
id,
|
|
522
|
+
entry,
|
|
523
|
+
isUpper
|
|
524
|
+
}) {
|
|
525
|
+
const conditions = entry?.conditions ?? [];
|
|
526
|
+
const isMissing = conditions.includes("missing");
|
|
527
|
+
const primary = isMissing ? "missing" : conditions[0] ?? null;
|
|
528
|
+
const primaryColor = primary ? CONDITION_CONFIG[primary].color : null;
|
|
529
|
+
const multiCount = conditions.length > 1 ? conditions.length : null;
|
|
530
|
+
const tooltipParts = [
|
|
531
|
+
`Tooth ${id}: ${toothLabel(id)}`,
|
|
532
|
+
conditions.length > 0 ? conditions.map((c) => CONDITION_CONFIG[c]?.label ?? c).join(", ") : "Healthy",
|
|
533
|
+
entry?.notes ? `Notes: ${entry.notes}` : null
|
|
534
|
+
].filter(Boolean);
|
|
535
|
+
const boxStyle = {
|
|
536
|
+
position: "relative",
|
|
537
|
+
width: 46,
|
|
538
|
+
height: 58,
|
|
539
|
+
flexShrink: 0,
|
|
540
|
+
display: "flex",
|
|
541
|
+
flexDirection: "column",
|
|
542
|
+
borderRadius: 6,
|
|
543
|
+
border: "1px solid",
|
|
544
|
+
borderColor: !isMissing && primaryColor ? primaryColor : isMissing ? "#d1d5db" : "#e5e7eb",
|
|
545
|
+
backgroundColor: isMissing ? "#f3f4f6" : "#ffffff",
|
|
546
|
+
userSelect: "none"
|
|
547
|
+
};
|
|
548
|
+
const numberStyle = {
|
|
549
|
+
flex: 1,
|
|
550
|
+
display: "flex",
|
|
551
|
+
alignItems: "center",
|
|
552
|
+
justifyContent: "center",
|
|
553
|
+
fontSize: 11,
|
|
554
|
+
fontWeight: 700,
|
|
555
|
+
color: isMissing ? "#9ca3af" : "#374151",
|
|
556
|
+
lineHeight: 1
|
|
557
|
+
};
|
|
558
|
+
const stripStyle = (rounded) => ({
|
|
559
|
+
height: 10,
|
|
560
|
+
flexShrink: 0,
|
|
561
|
+
borderRadius: rounded === "bottom" ? "0 0 5px 5px" : "5px 5px 0 0",
|
|
562
|
+
backgroundColor: !isMissing && primaryColor ? primaryColor : "transparent"
|
|
563
|
+
});
|
|
564
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { title: tooltipParts.join("\n"), style: boxStyle, children: [
|
|
565
|
+
isUpper ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
566
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: numberStyle, children: isMissing ? "\u2715" : id }),
|
|
567
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: stripStyle("bottom") })
|
|
568
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
569
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: stripStyle("top") }),
|
|
570
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: numberStyle, children: isMissing ? "\u2715" : id })
|
|
571
|
+
] }),
|
|
572
|
+
multiCount && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1.5 -right-1.5 z-10 flex h-3.5 w-3.5 items-center justify-center rounded-full bg-primary text-[7px] font-bold text-primary-foreground", children: multiCount })
|
|
573
|
+
] });
|
|
574
|
+
}
|
|
575
|
+
function ReadOnlyArchRow({
|
|
576
|
+
teeth: toothIds,
|
|
577
|
+
isUpper,
|
|
578
|
+
data,
|
|
579
|
+
reverseOrder = false
|
|
580
|
+
}) {
|
|
581
|
+
const ordered = reverseOrder ? [...toothIds].reverse() : toothIds;
|
|
582
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1", children: ordered.map((id) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
|
|
583
|
+
isUpper && /* @__PURE__ */ jsxRuntime.jsx(ToothDiagram, { id, entry: data[String(id)] }),
|
|
584
|
+
/* @__PURE__ */ jsxRuntime.jsx(ReadOnlyTooth, { id, entry: data[String(id)], isUpper }),
|
|
585
|
+
!isUpper && /* @__PURE__ */ jsxRuntime.jsx(ToothDiagram, { id, entry: data[String(id)] })
|
|
586
|
+
] }, id)) });
|
|
587
|
+
}
|
|
588
|
+
function ReadOnlyLegend({ usedConditions }) {
|
|
589
|
+
const active = ALL_CONDITIONS.filter((c) => usedConditions.has(c));
|
|
590
|
+
if (active.length === 0) return null;
|
|
591
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-x-4 gap-y-1.5", children: active.map((c) => {
|
|
592
|
+
const cfg = CONDITION_CONFIG[c];
|
|
593
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
594
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-2.5 w-2.5 shrink-0 rounded-full", style: { backgroundColor: cfg.color } }),
|
|
595
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: cfg.label })
|
|
596
|
+
] }, c);
|
|
597
|
+
}) });
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
exports.CONDITION_CONFIG = CONDITION_CONFIG;
|
|
601
|
+
exports.DentalChartReadOnly = DentalChartReadOnly;
|
|
602
|
+
exports.DentalChartWidget = DentalChartWidget;
|
|
603
|
+
exports.QUADRANTS = QUADRANTS;
|
|
604
|
+
exports.normalizeDentalChart = normalizeDentalChart;
|
|
605
|
+
exports.toothLabel = toothLabel;
|
|
606
|
+
//# sourceMappingURL=chunk-X4AJCTON.cjs.map
|
|
607
|
+
//# sourceMappingURL=chunk-X4AJCTON.cjs.map
|