odontogram 0.0.1 → 0.1.2
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/index.d.mts +35 -0
- package/dist/index.mjs +297 -0
- package/package.json +48 -100
- package/readme.md +140 -0
- package/src/index.ts +2 -0
- package/src/og-odontogram.ts +109 -0
- package/src/og-tooth.ts +76 -0
- package/src/stories/Layout.stories.ts +64 -0
- package/src/stories/Odontogram.stories.ts +68 -0
- package/LICENSE +0 -21
- package/README.md +0 -299
- package/cdn/components/button/button.d.ts +0 -25
- package/cdn/components/button/button.d.ts.map +0 -1
- package/cdn/components/button/button.js +0 -598
- package/cdn/components/button/button.styles.d.ts +0 -3
- package/cdn/components/button/button.styles.d.ts.map +0 -1
- package/cdn/components/button/index.d.ts +0 -2
- package/cdn/components/button/index.d.ts.map +0 -1
- package/cdn/components/button/index.js +0 -2
- package/cdn/components/index.d.ts +0 -2
- package/cdn/components/index.d.ts.map +0 -1
- package/cdn/components/index.js +0 -1
- package/cdn/index.d.ts +0 -2
- package/cdn/index.d.ts.map +0 -1
- package/cdn/index.js +0 -1
- package/cdn/loader.js +0 -118
- package/custom-elements.json +0 -152
- package/dist/components/button/button.d.ts +0 -25
- package/dist/components/button/button.d.ts.map +0 -1
- package/dist/components/button/button.js +0 -47
- package/dist/components/button/button.js.map +0 -1
- package/dist/components/button/button.styles.d.ts +0 -3
- package/dist/components/button/button.styles.d.ts.map +0 -1
- package/dist/components/button/button.styles.js +0 -43
- package/dist/components/button/button.styles.js.map +0 -1
- package/dist/components/button/index.d.ts +0 -2
- package/dist/components/button/index.d.ts.map +0 -1
- package/dist/components/button/index.js +0 -3
- package/dist/components/button/index.js.map +0 -1
- package/dist/components/index.d.ts +0 -2
- package/dist/components/index.d.ts.map +0 -1
- package/dist/components/index.js +0 -2
- package/dist/components/index.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +0 -1
- package/react/MyButton.d.ts +0 -90
- package/react/MyButton.js +0 -32
- package/react/index.d.ts +0 -1
- package/react/index.js +0 -1
- package/react/react-utils.js +0 -67
- package/types/custom-element-jsx.d.ts +0 -236
- package/types/custom-element-svelte.d.ts +0 -70
- package/types/custom-element-vuejs.d.ts +0 -40
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as lit from "lit";
|
|
2
|
+
import { LitElement } from "lit";
|
|
3
|
+
|
|
4
|
+
//#region src/og-tooth.d.ts
|
|
5
|
+
interface ToothSurfaces {
|
|
6
|
+
vestibular: boolean;
|
|
7
|
+
distal: boolean;
|
|
8
|
+
palatine: boolean;
|
|
9
|
+
mesial: boolean;
|
|
10
|
+
occlusal: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare class OgTooth extends LitElement {
|
|
13
|
+
toothId: string;
|
|
14
|
+
colorClick: string;
|
|
15
|
+
selections: ToothSurfaces;
|
|
16
|
+
private _toggle;
|
|
17
|
+
render(): lit.TemplateResult<1>;
|
|
18
|
+
static styles: lit.CSSResult;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/og-odontogram.d.ts
|
|
22
|
+
type PatientMode = 'adult' | 'baby' | 'old';
|
|
23
|
+
declare class OgDontogram extends LitElement {
|
|
24
|
+
mode: PatientMode;
|
|
25
|
+
chartData: Record<string, ToothSurfaces>;
|
|
26
|
+
private teethState;
|
|
27
|
+
private layouts;
|
|
28
|
+
willUpdate(changedProperties: Map<string, any>): void;
|
|
29
|
+
private _updateState;
|
|
30
|
+
renderTooth(id: number): lit.TemplateResult<1>;
|
|
31
|
+
render(): lit.TemplateResult<1>;
|
|
32
|
+
static styles: lit.CSSResult;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { OgDontogram, OgTooth, PatientMode, ToothSurfaces };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { LitElement, css, html } from "lit";
|
|
2
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
3
|
+
|
|
4
|
+
//#region \0@oxc-project+runtime@0.114.0/helpers/decorate.js
|
|
5
|
+
function __decorate(decorators, target, key, desc) {
|
|
6
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
7
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
8
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
9
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/og-tooth.ts
|
|
14
|
+
let OgTooth = class OgTooth extends LitElement {
|
|
15
|
+
constructor(..._args) {
|
|
16
|
+
super(..._args);
|
|
17
|
+
this.toothId = "";
|
|
18
|
+
this.colorClick = "#ff6961";
|
|
19
|
+
this.selections = {
|
|
20
|
+
vestibular: false,
|
|
21
|
+
distal: false,
|
|
22
|
+
palatine: false,
|
|
23
|
+
mesial: false,
|
|
24
|
+
occlusal: false
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
_toggle(surface, clickFn, unclickFn) {
|
|
28
|
+
const isSelected = !this.selections[surface];
|
|
29
|
+
this.selections = {
|
|
30
|
+
...this.selections,
|
|
31
|
+
[surface]: isSelected
|
|
32
|
+
};
|
|
33
|
+
const eventName = isSelected ? clickFn : unclickFn;
|
|
34
|
+
this.dispatchEvent(new CustomEvent(eventName, {
|
|
35
|
+
detail: {
|
|
36
|
+
toothId: this.toothId,
|
|
37
|
+
surface,
|
|
38
|
+
state: isSelected
|
|
39
|
+
},
|
|
40
|
+
bubbles: true,
|
|
41
|
+
composed: true
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
render() {
|
|
45
|
+
return html`
|
|
46
|
+
<div class="tooth-container">
|
|
47
|
+
<span class="label">${this.toothId}</span>
|
|
48
|
+
<div class="tooth-relative">
|
|
49
|
+
<div class="surface top ${this.selections.vestibular ? "selected" : ""}"
|
|
50
|
+
@click=${() => this._toggle("vestibular", "vestibularC", "vestibularU")}></div>
|
|
51
|
+
|
|
52
|
+
<div class="surface left ${this.selections.distal ? "selected" : ""}"
|
|
53
|
+
@click=${() => this._toggle("distal", "distalC", "distalU")}></div>
|
|
54
|
+
|
|
55
|
+
<div class="surface bottom ${this.selections.palatine ? "selected" : ""}"
|
|
56
|
+
@click=${() => this._toggle("palatine", "palatineC", "palatineU")}></div>
|
|
57
|
+
|
|
58
|
+
<div class="surface right ${this.selections.mesial ? "selected" : ""}"
|
|
59
|
+
@click=${() => this._toggle("mesial", "mesialC", "mesialU")}></div>
|
|
60
|
+
|
|
61
|
+
<div class="surface center ${this.selections.occlusal ? "selected" : ""}"
|
|
62
|
+
@click=${() => this._toggle("occlusal", "occlusalC", "occlusalU")}></div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
`;
|
|
66
|
+
}
|
|
67
|
+
static {
|
|
68
|
+
this.styles = css`
|
|
69
|
+
.tooth-container { display: flex; flex-direction: column; align-items: center; width: 50px; }
|
|
70
|
+
.label { font-size: 12px; margin-bottom: 5px; font-weight: bold; color: #333; }
|
|
71
|
+
.tooth-relative { position: relative; width: 44px; height: 44px; background: #eee; }
|
|
72
|
+
.surface {
|
|
73
|
+
position: absolute; width: 20px; height: 20px; outline: 2px solid #000;
|
|
74
|
+
background-color: #fff; cursor: pointer; box-sizing: border-box; transition: background-color 0.2s;
|
|
75
|
+
}
|
|
76
|
+
.selected { background-color: var(--click-color, #ff6961) !important; }
|
|
77
|
+
.top { top: 0; left: 0; border-top-left-radius: 100%; }
|
|
78
|
+
.left { bottom: 0; left: 0; border-bottom-left-radius: 100%; }
|
|
79
|
+
.bottom { bottom: 0; right: 0; border-bottom-right-radius: 100%; }
|
|
80
|
+
.right { top: 0; right: 0; border-top-right-radius: 100%; }
|
|
81
|
+
.center { top: 25%; right: 25%; border-radius: 50%; z-index: 2; }
|
|
82
|
+
`;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
__decorate([property({ type: String })], OgTooth.prototype, "toothId", void 0);
|
|
86
|
+
__decorate([property({ type: String })], OgTooth.prototype, "colorClick", void 0);
|
|
87
|
+
__decorate([property({ type: Object })], OgTooth.prototype, "selections", void 0);
|
|
88
|
+
OgTooth = __decorate([customElement("og-tooth")], OgTooth);
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/og-odontogram.ts
|
|
92
|
+
let OgDontogram = class OgDontogram extends LitElement {
|
|
93
|
+
constructor(..._args) {
|
|
94
|
+
super(..._args);
|
|
95
|
+
this.mode = "adult";
|
|
96
|
+
this.chartData = {};
|
|
97
|
+
this.teethState = {};
|
|
98
|
+
this.layouts = {
|
|
99
|
+
adult: {
|
|
100
|
+
upperRight: [
|
|
101
|
+
18,
|
|
102
|
+
17,
|
|
103
|
+
16,
|
|
104
|
+
15,
|
|
105
|
+
14,
|
|
106
|
+
13,
|
|
107
|
+
12,
|
|
108
|
+
11
|
|
109
|
+
],
|
|
110
|
+
upperLeft: [
|
|
111
|
+
21,
|
|
112
|
+
22,
|
|
113
|
+
23,
|
|
114
|
+
24,
|
|
115
|
+
25,
|
|
116
|
+
26,
|
|
117
|
+
27,
|
|
118
|
+
28
|
|
119
|
+
],
|
|
120
|
+
lowerRight: [
|
|
121
|
+
48,
|
|
122
|
+
47,
|
|
123
|
+
46,
|
|
124
|
+
45,
|
|
125
|
+
44,
|
|
126
|
+
43,
|
|
127
|
+
42,
|
|
128
|
+
41
|
|
129
|
+
],
|
|
130
|
+
lowerLeft: [
|
|
131
|
+
31,
|
|
132
|
+
32,
|
|
133
|
+
33,
|
|
134
|
+
34,
|
|
135
|
+
35,
|
|
136
|
+
36,
|
|
137
|
+
37,
|
|
138
|
+
38
|
|
139
|
+
]
|
|
140
|
+
},
|
|
141
|
+
baby: {
|
|
142
|
+
upperRight: [
|
|
143
|
+
55,
|
|
144
|
+
54,
|
|
145
|
+
53,
|
|
146
|
+
52,
|
|
147
|
+
51
|
|
148
|
+
],
|
|
149
|
+
upperLeft: [
|
|
150
|
+
61,
|
|
151
|
+
62,
|
|
152
|
+
63,
|
|
153
|
+
64,
|
|
154
|
+
65
|
|
155
|
+
],
|
|
156
|
+
lowerRight: [
|
|
157
|
+
85,
|
|
158
|
+
84,
|
|
159
|
+
83,
|
|
160
|
+
82,
|
|
161
|
+
81
|
|
162
|
+
],
|
|
163
|
+
lowerLeft: [
|
|
164
|
+
71,
|
|
165
|
+
72,
|
|
166
|
+
73,
|
|
167
|
+
74,
|
|
168
|
+
75
|
|
169
|
+
]
|
|
170
|
+
},
|
|
171
|
+
old: {
|
|
172
|
+
upperRight: [
|
|
173
|
+
17,
|
|
174
|
+
16,
|
|
175
|
+
15,
|
|
176
|
+
14,
|
|
177
|
+
13,
|
|
178
|
+
12,
|
|
179
|
+
11
|
|
180
|
+
],
|
|
181
|
+
upperLeft: [
|
|
182
|
+
21,
|
|
183
|
+
22,
|
|
184
|
+
23,
|
|
185
|
+
24,
|
|
186
|
+
25,
|
|
187
|
+
26,
|
|
188
|
+
27
|
|
189
|
+
],
|
|
190
|
+
lowerRight: [
|
|
191
|
+
47,
|
|
192
|
+
46,
|
|
193
|
+
45,
|
|
194
|
+
44,
|
|
195
|
+
43,
|
|
196
|
+
42,
|
|
197
|
+
41
|
|
198
|
+
],
|
|
199
|
+
lowerLeft: [
|
|
200
|
+
31,
|
|
201
|
+
32,
|
|
202
|
+
33,
|
|
203
|
+
34,
|
|
204
|
+
35,
|
|
205
|
+
36,
|
|
206
|
+
37
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
willUpdate(changedProperties) {
|
|
212
|
+
if (changedProperties.has("chartData")) this.teethState = { ...this.chartData };
|
|
213
|
+
}
|
|
214
|
+
_updateState(id, region, value) {
|
|
215
|
+
const toothId = id.toString();
|
|
216
|
+
const newState = { ...this.teethState };
|
|
217
|
+
if (!newState[toothId]) newState[toothId] = {
|
|
218
|
+
vestibular: false,
|
|
219
|
+
distal: false,
|
|
220
|
+
palatine: false,
|
|
221
|
+
mesial: false,
|
|
222
|
+
occlusal: false
|
|
223
|
+
};
|
|
224
|
+
newState[toothId] = {
|
|
225
|
+
...newState[toothId],
|
|
226
|
+
[region]: value
|
|
227
|
+
};
|
|
228
|
+
this.teethState = newState;
|
|
229
|
+
this.dispatchEvent(new CustomEvent("odontogram-change", {
|
|
230
|
+
detail: {
|
|
231
|
+
data: this.teethState,
|
|
232
|
+
mode: this.mode
|
|
233
|
+
},
|
|
234
|
+
bubbles: true,
|
|
235
|
+
composed: true
|
|
236
|
+
}));
|
|
237
|
+
}
|
|
238
|
+
renderTooth(id) {
|
|
239
|
+
const state = this.teethState[id.toString()] || {
|
|
240
|
+
vestibular: false,
|
|
241
|
+
distal: false,
|
|
242
|
+
palatine: false,
|
|
243
|
+
mesial: false,
|
|
244
|
+
occlusal: false
|
|
245
|
+
};
|
|
246
|
+
return html`
|
|
247
|
+
<og-tooth
|
|
248
|
+
.toothId=${id.toString()}
|
|
249
|
+
.selections=${state}
|
|
250
|
+
@vestibularC=${() => this._updateState(id, "vestibular", true)}
|
|
251
|
+
@vestibularU=${() => this._updateState(id, "vestibular", false)}
|
|
252
|
+
@distalC=${() => this._updateState(id, "distal", true)}
|
|
253
|
+
@distalU=${() => this._updateState(id, "distal", false)}
|
|
254
|
+
@palatineC=${() => this._updateState(id, "palatine", true)}
|
|
255
|
+
@palatineU=${() => this._updateState(id, "palatine", false)}
|
|
256
|
+
@mesialC=${() => this._updateState(id, "mesial", true)}
|
|
257
|
+
@mesialU=${() => this._updateState(id, "mesial", false)}
|
|
258
|
+
@occlusalC=${() => this._updateState(id, "occlusal", true)}
|
|
259
|
+
@occlusalU=${() => this._updateState(id, "occlusal", false)}
|
|
260
|
+
></og-tooth>
|
|
261
|
+
`;
|
|
262
|
+
}
|
|
263
|
+
render() {
|
|
264
|
+
const layout = this.layouts[this.mode] || this.layouts.adult;
|
|
265
|
+
return html`
|
|
266
|
+
<div class="odontogram-wrapper mode-${this.mode}">
|
|
267
|
+
<div class="arch">
|
|
268
|
+
<div class="quadrant">${layout.upperRight.map((id) => this.renderTooth(id))}</div>
|
|
269
|
+
<div class="quadrant">${layout.upperLeft.map((id) => this.renderTooth(id))}</div>
|
|
270
|
+
</div>
|
|
271
|
+
<div class="arch">
|
|
272
|
+
<div class="quadrant">${layout.lowerRight.map((id) => this.renderTooth(id))}</div>
|
|
273
|
+
<div class="quadrant">${layout.lowerLeft.map((id) => this.renderTooth(id))}</div>
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
`;
|
|
277
|
+
}
|
|
278
|
+
static {
|
|
279
|
+
this.styles = css`
|
|
280
|
+
:host { display: block; padding: 20px; }
|
|
281
|
+
.odontogram-wrapper { display: flex; flex-direction: column; gap: 40px; align-items: center; }
|
|
282
|
+
.arch { display: flex; gap: 40px; }
|
|
283
|
+
.quadrant { display: flex; gap: 4px; }
|
|
284
|
+
|
|
285
|
+
/* You can add specific colors or spacing per mode if you want */
|
|
286
|
+
.mode-baby { gap: 20px; }
|
|
287
|
+
.mode-baby og-tooth { transform: scale(0.9); }
|
|
288
|
+
`;
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
__decorate([property({ type: String })], OgDontogram.prototype, "mode", void 0);
|
|
292
|
+
__decorate([property({ type: Object })], OgDontogram.prototype, "chartData", void 0);
|
|
293
|
+
__decorate([state()], OgDontogram.prototype, "teethState", void 0);
|
|
294
|
+
OgDontogram = __decorate([customElement("og-dontogram")], OgDontogram);
|
|
295
|
+
|
|
296
|
+
//#endregion
|
|
297
|
+
export { OgDontogram, OgTooth };
|
package/package.json
CHANGED
|
@@ -1,120 +1,68 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "odontogram",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "A lightweight, interactive web component odontogram built with Lit.",
|
|
5
|
+
"main": "./dist/index.mjs",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.mts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.mts",
|
|
11
|
+
"import": "./dist/index.mjs"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
18
|
+
"sideEffects": [
|
|
19
|
+
"**/*.js",
|
|
20
|
+
"**/*.ts"
|
|
21
|
+
],
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"lit": "^3.0.0"
|
|
24
|
+
},
|
|
6
25
|
"license": "MIT",
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
7
29
|
"keywords": [
|
|
8
30
|
"odontogram",
|
|
9
31
|
"react",
|
|
10
32
|
"dental-chart"
|
|
11
33
|
],
|
|
12
|
-
"publishConfig": {
|
|
13
|
-
"access": "public"
|
|
14
|
-
},
|
|
15
34
|
"repository": {
|
|
16
35
|
"type": "git",
|
|
17
36
|
"url": "https://github.com/biomathcode/odontogram"
|
|
18
37
|
},
|
|
19
|
-
"main": "dist/index.js",
|
|
20
38
|
"type": "module",
|
|
21
39
|
"scripts": {
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"test": "web-test-runner --group default",
|
|
27
|
-
"build": "tsc && npm run analyze && npm run build:kitchen-sink",
|
|
28
|
-
"build:cdn": "npx cross-env BUILD_TARGET=cdn vite build && npm run analyze",
|
|
29
|
-
"build:html": "npx cross-env BUILD_TARGET=html vite build",
|
|
30
|
-
"build:react": "npx cross-env BUILD_TARGET=react vite build && npx rimraf -rf ./public/react/html",
|
|
31
|
-
"build:kitchen-sink": "npx rimraf ./public && npm run build:cdn && npm run build:html && npm run build:react",
|
|
32
|
-
"build:watch": "concurrently -k -r \"tsc --watch\" \"npx cross-env BUILD_TARGET=cdn vite build --watch\"",
|
|
33
|
-
"new": "plop",
|
|
34
|
-
"deploy": "npm run build && npm publish",
|
|
35
|
-
"format": "npm run format:eslint && npm run format:prettier",
|
|
36
|
-
"format:eslint": "npx eslint --fix",
|
|
37
|
-
"format:prettier": "npx prettier . --write",
|
|
38
|
-
"lint": "wctools validate && npm run lint:eslint && npm run lint:prettier",
|
|
39
|
-
"lint:eslint": "npx eslint",
|
|
40
|
-
"lint:prettier": "npx prettier . --check",
|
|
41
|
-
"prepare": "husky && npx playwright install-deps",
|
|
40
|
+
"dev": "vite",
|
|
41
|
+
"build": "tsdown",
|
|
42
|
+
"build:vite": "tsc && vite build",
|
|
43
|
+
"preview": "vite preview",
|
|
42
44
|
"storybook": "storybook dev -p 6006",
|
|
43
|
-
"build-storybook": "storybook build"
|
|
45
|
+
"build-storybook": "storybook build",
|
|
46
|
+
"deploy-storybook": "gh-pages -d storybook-static"
|
|
44
47
|
},
|
|
45
48
|
"dependencies": {
|
|
46
|
-
"
|
|
47
|
-
"lit": "^3.2.1",
|
|
48
|
-
"wc-dox": "^1.3.5"
|
|
49
|
+
"lit": "^3.3.1"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
|
-
"@
|
|
52
|
-
"@
|
|
53
|
-
"@
|
|
54
|
-
"@
|
|
55
|
-
"@
|
|
56
|
-
"@playwright
|
|
57
|
-
"@
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
"@wc-toolkit/jsx-types": "^1.5.2",
|
|
68
|
-
"@wc-toolkit/lazy-loader": "^1.0.1",
|
|
69
|
-
"@wc-toolkit/module-path-resolver": "^1.0.0",
|
|
70
|
-
"@wc-toolkit/react-wrappers": "^1.1.1",
|
|
71
|
-
"@wc-toolkit/storybook-helpers": "^10.0.0",
|
|
72
|
-
"@wc-toolkit/type-parser": "^1.2.0",
|
|
73
|
-
"@wc-toolkit/wctools": "^0.0.18",
|
|
74
|
-
"@web/dev-server-esbuild": "^1.0.4",
|
|
75
|
-
"@web/test-runner": "^0.20.2",
|
|
76
|
-
"@web/test-runner-commands": "^0.9.0",
|
|
77
|
-
"@web/test-runner-playwright": "^0.11.1",
|
|
78
|
-
"concurrently": "^9.1.0",
|
|
79
|
-
"custom-element-svelte-integration": "^1.1.2",
|
|
80
|
-
"custom-element-vuejs-integration": "^1.3.3",
|
|
81
|
-
"custom-elements-manifest-deprecator": "^1.1.1",
|
|
82
|
-
"eslint": "^9.16.0",
|
|
83
|
-
"eslint-config-prettier": "^9.1.0",
|
|
84
|
-
"eslint-plugin-lit": "^1.15.0",
|
|
85
|
-
"eslint-plugin-lit-a11y": "^5.1.1",
|
|
86
|
-
"eslint-plugin-require-extensions": "^0.1.3",
|
|
87
|
-
"eslint-plugin-storybook": "^10.1.11",
|
|
88
|
-
"glob": "^11.0.0",
|
|
89
|
-
"globals": "^15.13.0",
|
|
90
|
-
"husky": "^9.0.11",
|
|
91
|
-
"lint-staged": "^15.2.7",
|
|
92
|
-
"plop": "^4.0.1",
|
|
93
|
-
"prettier": "^3.3.2",
|
|
94
|
-
"rollup-plugin-summary": "^3.0.0",
|
|
95
|
-
"storybook": "^10.1.11",
|
|
96
|
-
"typescript": "^5.5.3",
|
|
97
|
-
"typescript-eslint": "^8.17.0",
|
|
98
|
-
"vite": "^7.3.0",
|
|
99
|
-
"vite-plugin-dts": "^4.5.4"
|
|
100
|
-
},
|
|
101
|
-
"lint-staged": {
|
|
102
|
-
"*.js": "eslint --cache --fix",
|
|
103
|
-
"*.format:prettier": "prettier --write"
|
|
104
|
-
},
|
|
105
|
-
"files": [
|
|
106
|
-
"cdn",
|
|
107
|
-
"eslint",
|
|
108
|
-
"dist",
|
|
109
|
-
"react",
|
|
110
|
-
"types",
|
|
111
|
-
"index.d.ts",
|
|
112
|
-
"index.js",
|
|
113
|
-
"package.json",
|
|
114
|
-
"custom-elements.json",
|
|
115
|
-
"vscode.css-custom-data.json",
|
|
116
|
-
"vscode.html-custom-data.json",
|
|
117
|
-
"web-types.json"
|
|
118
|
-
],
|
|
119
|
-
"customElements": "custom-elements.json"
|
|
52
|
+
"@chromatic-com/storybook": "^5.0.1",
|
|
53
|
+
"@storybook/addon-a11y": "^10.2.13",
|
|
54
|
+
"@storybook/addon-docs": "^10.2.13",
|
|
55
|
+
"@storybook/addon-vitest": "^10.2.13",
|
|
56
|
+
"@storybook/web-components-vite": "^10.2.13",
|
|
57
|
+
"@vitest/browser-playwright": "^4.0.18",
|
|
58
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
59
|
+
"gh-pages": "^6.3.0",
|
|
60
|
+
"playwright": "^1.58.2",
|
|
61
|
+
"storybook": "^10.2.13",
|
|
62
|
+
"tsdown": "0.21.0-beta.2",
|
|
63
|
+
"typescript": "~5.9.3",
|
|
64
|
+
"vite": "^7.3.1",
|
|
65
|
+
"vite-plugin-dts": "^4.5.4",
|
|
66
|
+
"vitest": "^4.0.18"
|
|
67
|
+
}
|
|
120
68
|
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# 🦷 Og-odontogram
|
|
2
|
+
|
|
3
|
+
A lightweight, interactive, and highly customizable **Web Component Ogdontogram** built with [Lit](https://lit.dev/). Perfect for dental software, patient records, and educational tools.
|
|
4
|
+
|
|
5
|
+
## ✨ Features
|
|
6
|
+
|
|
7
|
+
* **Zero Framework Dependency**: Works with React, Vue, Angular, or plain HTML.
|
|
8
|
+
* **Multi-Mode Support**: Toggle between `adult` (32 teeth), `baby` (20 primary teeth), and `old` (geriatric) layouts.
|
|
9
|
+
* **Interactive Regions**: Supports 5 surfaces per tooth: Vestibular, Distal, Palatine, Mesial, and Occlusal.
|
|
10
|
+
* **JSON Powered**: Export and rehydrate the entire chart state via a simple JSON object.
|
|
11
|
+
* **CSS Theming**: Customize selection colors using CSS variables.
|
|
12
|
+
* **Open-WC Compliant**: Shipped as unoptimized ESM for maximum bundler compatibility.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 📦 Installation
|
|
17
|
+
|
|
18
|
+
Install via NPM:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install odontogram
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🚀 Quick Start
|
|
28
|
+
|
|
29
|
+
### Plain HTML / Vanilla JS
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<script type="module">
|
|
33
|
+
import 'odontogram';
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<og-odontogram id="my-chart" mode="adult"></og-odontogram>
|
|
37
|
+
|
|
38
|
+
<script>
|
|
39
|
+
const chart = document.getElementById('my-chart');
|
|
40
|
+
|
|
41
|
+
// Listen for changes
|
|
42
|
+
chart.addEventListener('oodontogram-change', (e) => {
|
|
43
|
+
console.log('New State:', e.detail.data);
|
|
44
|
+
});
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### React / Next.js
|
|
50
|
+
|
|
51
|
+
```jsx
|
|
52
|
+
import 'oodontogram';
|
|
53
|
+
|
|
54
|
+
function App() {
|
|
55
|
+
return (
|
|
56
|
+
<og-odontogram
|
|
57
|
+
mode="baby"
|
|
58
|
+
onoodontogram-change={(e) => console.log(e.detail.data)}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 🛠 API & Configuration
|
|
68
|
+
|
|
69
|
+
### Properties
|
|
70
|
+
|
|
71
|
+
| Property | Type | Default | Description |
|
|
72
|
+
| ----------- | -------- | --------- | ---------------------------------------- |
|
|
73
|
+
| `mode` | `string` | `'adult'` | Patient type: `adult`, `baby`, or `old`. |
|
|
74
|
+
| `chartData` | `object` | `{}` | Initial state to pre-fill the chart. |
|
|
75
|
+
|
|
76
|
+
### Custom Events
|
|
77
|
+
|
|
78
|
+
| Event | Detail | Description |
|
|
79
|
+
| -------------------- | --------------------------- | ------------------------------------------ |
|
|
80
|
+
| `oodontogram-change` | `{ data: {}, mode: string}` | Fired whenever a tooth surface is toggled. |
|
|
81
|
+
|
|
82
|
+
### CSS Variables
|
|
83
|
+
|
|
84
|
+
Customize the look of the selected regions:
|
|
85
|
+
|
|
86
|
+
```css
|
|
87
|
+
og-odontogram {
|
|
88
|
+
--click-color: #ff6961; /* The color of selected surfaces */
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 📊 Data Structure
|
|
96
|
+
|
|
97
|
+
The component exports a clean JSON structure representing the "history" or "state" of the teeth.
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"16": {
|
|
102
|
+
"vestibular": true,
|
|
103
|
+
"distal": false,
|
|
104
|
+
"palatine": false,
|
|
105
|
+
"mesial": true,
|
|
106
|
+
"occlusal": true
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 🎨 Storybook (Development & Demo)
|
|
115
|
+
|
|
116
|
+
We use Storybook to showcase all modes and test interactivity. You can see the "Adult", "Pediatric", and "Senior" layouts in isolation.
|
|
117
|
+
|
|
118
|
+
To run Storybook locally:
|
|
119
|
+
|
|
120
|
+
1. Clone the repo.
|
|
121
|
+
2. `npm install`
|
|
122
|
+
3. `npm run storybook`
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 🏗 Developing
|
|
127
|
+
|
|
128
|
+
If you want to contribute or build from source:
|
|
129
|
+
|
|
130
|
+
* **Build for Production**: `npm run build` (uses `tsdown` to generate `.mjs` and `.d.mts`).
|
|
131
|
+
* **Test**: `npm run test` (uses Vitest + Playwright for browser testing).
|
|
132
|
+
* **Lint**: `npm run lint`.
|
|
133
|
+
|
|
134
|
+
## 📄 License
|
|
135
|
+
|
|
136
|
+
MIT © [Biomathcode](https://github.com/biomathcode)
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
**Would you like me to help you set up a GitHub Action to automatically publish this to NPM whenever you create a new release?**
|
package/src/index.ts
ADDED