@alfadocs/ui-kit 1.4.17 → 1.5.0

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.
Files changed (80) hide show
  1. package/dist/_chunks/{care-plan-card-C83Hb9EE.js → care-plan-card-CehAU7F_.js} +2 -2
  2. package/dist/_chunks/{care-plan-entry-card-CHMPSTCz.js → care-plan-entry-card-ChWRMfMw.js} +2 -2
  3. package/dist/_chunks/{periodontal-chart-brakjj0s.js → periodontal-chart-C0nNQKKK.js} +121 -121
  4. package/dist/_chunks/tooth-data-DR8Kdnup.js +903 -0
  5. package/dist/_chunks/tooth-finding-palette-vqC-D2Ye.js +708 -0
  6. package/dist/_chunks/tooth-scheme-BPXE1_3N.js +2051 -0
  7. package/dist/agent-catalog.json +465 -21
  8. package/dist/agent-i18n/en.json +23 -6
  9. package/dist/components/care-plan-card/index.js +1 -1
  10. package/dist/components/care-plan-entry-card/index.js +1 -1
  11. package/dist/components/index.d.ts +1 -0
  12. package/dist/components/periodontal-chart/index.js +1 -1
  13. package/dist/components/tooth-finding-palette/index.d.ts +4 -0
  14. package/dist/components/tooth-finding-palette/index.js +9 -0
  15. package/dist/components/tooth-finding-palette/tooth-finding-palette.agent.d.ts +4 -0
  16. package/dist/components/tooth-finding-palette/tooth-finding-palette.d.ts +89 -0
  17. package/dist/components/tooth-scheme/index.d.ts +2 -2
  18. package/dist/components/tooth-scheme/index.js +57 -30
  19. package/dist/components/tooth-scheme/tooth-data.d.ts +279 -10
  20. package/dist/components/tooth-scheme/tooth-scheme.agent.d.ts +2 -2
  21. package/dist/components/tooth-scheme/tooth-scheme.d.ts +30 -3
  22. package/dist/i18n/locales/ar.d.ts +40 -1
  23. package/dist/i18n/locales/ar.js +41 -2
  24. package/dist/i18n/locales/de.d.ts +40 -1
  25. package/dist/i18n/locales/de.js +41 -2
  26. package/dist/i18n/locales/el.d.ts +40 -1
  27. package/dist/i18n/locales/el.js +41 -2
  28. package/dist/i18n/locales/en.d.ts +40 -1
  29. package/dist/i18n/locales/en.js +41 -2
  30. package/dist/i18n/locales/es.d.ts +40 -1
  31. package/dist/i18n/locales/es.js +41 -2
  32. package/dist/i18n/locales/fr.d.ts +40 -1
  33. package/dist/i18n/locales/fr.js +41 -2
  34. package/dist/i18n/locales/hi.d.ts +40 -1
  35. package/dist/i18n/locales/hi.js +41 -2
  36. package/dist/i18n/locales/it.d.ts +40 -1
  37. package/dist/i18n/locales/it.js +41 -2
  38. package/dist/i18n/locales/ja.d.ts +40 -1
  39. package/dist/i18n/locales/ja.js +41 -2
  40. package/dist/i18n/locales/nl.d.ts +40 -1
  41. package/dist/i18n/locales/nl.js +41 -2
  42. package/dist/i18n/locales/pl.d.ts +40 -1
  43. package/dist/i18n/locales/pl.js +41 -2
  44. package/dist/i18n/locales/pt.d.ts +40 -1
  45. package/dist/i18n/locales/pt.js +41 -2
  46. package/dist/i18n/locales/ro.d.ts +40 -1
  47. package/dist/i18n/locales/ro.js +41 -2
  48. package/dist/i18n/locales/ru.d.ts +40 -1
  49. package/dist/i18n/locales/ru.js +41 -2
  50. package/dist/i18n/locales/sq.d.ts +40 -1
  51. package/dist/i18n/locales/sq.js +41 -2
  52. package/dist/i18n/locales/sv.d.ts +40 -1
  53. package/dist/i18n/locales/sv.js +41 -2
  54. package/dist/i18n/locales/tr.d.ts +40 -1
  55. package/dist/i18n/locales/tr.js +41 -2
  56. package/dist/i18n/locales/zh.d.ts +40 -1
  57. package/dist/i18n/locales/zh.js +41 -2
  58. package/dist/index.js +448 -415
  59. package/dist/locales/ar.json +41 -2
  60. package/dist/locales/de.json +41 -2
  61. package/dist/locales/el.json +41 -2
  62. package/dist/locales/en.json +41 -2
  63. package/dist/locales/es.json +41 -2
  64. package/dist/locales/fr.json +41 -2
  65. package/dist/locales/hi.json +41 -2
  66. package/dist/locales/it.json +41 -2
  67. package/dist/locales/ja.json +41 -2
  68. package/dist/locales/nl.json +41 -2
  69. package/dist/locales/pl.json +41 -2
  70. package/dist/locales/pt.json +41 -2
  71. package/dist/locales/ro.json +41 -2
  72. package/dist/locales/ru.json +41 -2
  73. package/dist/locales/sq.json +41 -2
  74. package/dist/locales/sv.json +41 -2
  75. package/dist/locales/tr.json +41 -2
  76. package/dist/locales/zh.json +41 -2
  77. package/dist/tokens.css +1 -1
  78. package/package.json +5 -1
  79. package/dist/_chunks/tooth-data-BwuoKFf4.js +0 -660
  80. package/dist/_chunks/tooth-scheme-s0ipC0-Z.js +0 -1483
@@ -0,0 +1,708 @@
1
+ import { jsxs as w, jsx as a } from "react/jsx-runtime";
2
+ import { forwardRef as yt, useMemo as F, useRef as X, useState as xt, useCallback as O, useImperativeHandle as wt } from "react";
3
+ import { c as I } from "./index-D2ZczOXr.js";
4
+ import { useTranslation as kt } from "react-i18next";
5
+ import { u as tt } from "./use-controllable-state-BiY4xTzM.js";
6
+ import { u as St } from "./registry-DvAUVLHh.js";
7
+ import { E as Tt, u as Ft, U as It, f as _t, z as At, q as Ct, t as Nt, Y as Rt, A as Et, C as Pt, s as Mt, k as et } from "./tooth-data-DR8Kdnup.js";
8
+ const st = {
9
+ type: "string",
10
+ description: "Finding id — either a built-in condition (the enum on tooth-scheme's set_finding: caries, filled, crowned, rootCanal, implant, …) or a practice-defined id supplied through the conditionRegistry prop. Read the live list from the `tools` state slot rather than guessing."
11
+ }, Vt = {
12
+ planned: !0,
13
+ executed: !0
14
+ }, jt = {
15
+ enum: Object.keys(Vt),
16
+ description: "Execution status the next charted finding takes — 'planned' (proposed treatment) or 'executed' (work already carried out)."
17
+ }, Dt = {
18
+ id: "tooth-finding-palette",
19
+ // select_single — exactly one finding tool is armed at a time (or none);
20
+ // set_value — the planned/executed status is a second, separate choice.
21
+ // `pick` covers `focus_tool`, which moves the roving tab stop WITHOUT
22
+ // arming — the same shape as tooth-scheme's `focus_tooth` and
23
+ // face-scheme's `focus_zone`, both of which sit under `pick`.
24
+ capabilities: ["pick", "select_single", "set_value"],
25
+ state: {
26
+ activeFinding: {
27
+ type: "string | null",
28
+ descriptionKey: "ui.agent.toothFindingPalette.state.activeFinding",
29
+ description: "Id of the armed finding tool, or null when no tool is selected. Identifies a finding TYPE — never a patient, and never a charted finding.",
30
+ read: (s) => s.getValue()
31
+ },
32
+ status: {
33
+ type: "string",
34
+ descriptionKey: "ui.agent.toothFindingPalette.state.status",
35
+ description: "Execution status the next charted finding takes — 'planned' or 'executed'.",
36
+ read: (s) => s.getStatus()
37
+ },
38
+ tools: {
39
+ type: "string[]",
40
+ descriptionKey: "ui.agent.toothFindingPalette.state.tools",
41
+ description: "Every finding id the palette currently offers, in render order — built-ins plus any practice-defined ids. The authoritative vocabulary for select_finding.",
42
+ read: (s) => s.getTools()
43
+ }
44
+ },
45
+ actions: {
46
+ select_finding: {
47
+ // Arming a tool persists nothing — PRS 26 §3 puts selection and view
48
+ // state under `read`, and 20 of the 23 shipped `select_*` actions
49
+ // agree. `write` would make an agent prompt before picking up a
50
+ // paintbrush.
51
+ safety: "read",
52
+ argsType: "{ condition: ConditionId }",
53
+ argsSchema: {
54
+ type: "object",
55
+ properties: { condition: st },
56
+ required: ["condition"]
57
+ },
58
+ idempotent: !0,
59
+ descriptionKey: "ui.agent.toothFindingPalette.actions.selectFinding",
60
+ description: "Arm a finding tool, so the next tooth (or surface, or root) picked on the paired dental chart records that finding.",
61
+ examples: [
62
+ {
63
+ args: { condition: "caries" },
64
+ note: "Arm the caries tool before marking a decayed surface."
65
+ }
66
+ ],
67
+ errors: [
68
+ `The condition is not among the palette's tools — read the "tools" state slot for the live list.`
69
+ ],
70
+ invoke: (s, o) => {
71
+ s.setValue(o.condition);
72
+ }
73
+ },
74
+ clear_selection: {
75
+ // Disarms the palette. Nothing charted is lost and nothing persists —
76
+ // `read`, matching `clear_selection` on data-table, file-manager
77
+ // and list.
78
+ safety: "read",
79
+ idempotent: !0,
80
+ descriptionKey: "ui.agent.toothFindingPalette.actions.clearSelection",
81
+ description: "Disarm the palette so clicks on the chart stop recording a finding. Charted findings are untouched.",
82
+ invoke: (s) => {
83
+ s.clear();
84
+ }
85
+ },
86
+ set_status: {
87
+ safety: "write",
88
+ argsType: "{ status: SymbolStatus }",
89
+ argsSchema: {
90
+ type: "object",
91
+ properties: { status: jt },
92
+ required: ["status"]
93
+ },
94
+ idempotent: !0,
95
+ descriptionKey: "ui.agent.toothFindingPalette.actions.setStatus",
96
+ description: "Choose whether the next charted finding is recorded as planned or executed.",
97
+ examples: [
98
+ {
99
+ args: { status: "executed" },
100
+ note: "Record the next finding as work already carried out."
101
+ }
102
+ ],
103
+ invoke: (s, o) => {
104
+ s.setStatus(o.status);
105
+ }
106
+ },
107
+ focus_tool: {
108
+ safety: "read",
109
+ argsType: "{ condition: ConditionId }",
110
+ argsSchema: {
111
+ type: "object",
112
+ properties: { condition: st },
113
+ required: ["condition"]
114
+ },
115
+ idempotent: !0,
116
+ descriptionKey: "ui.agent.toothFindingPalette.actions.focusTool",
117
+ description: "Move keyboard focus to a tool without arming it — relocates the toolbar's single roving tab stop.",
118
+ invoke: (s, o) => {
119
+ s.focusTool(o.condition);
120
+ }
121
+ }
122
+ },
123
+ domHooks: {
124
+ root: {
125
+ attr: "data-component",
126
+ value: "tooth-finding-palette",
127
+ description: "Marks the palette toolbar wrapper."
128
+ },
129
+ instanceId: {
130
+ attr: "data-component-id",
131
+ sourceProp: "id",
132
+ description: "Sourced from the id prop. Required to address a specific palette from the agent."
133
+ },
134
+ item: {
135
+ attr: "data-condition",
136
+ description: 'Each tool button emits its finding id as data-condition, and the armed tool also carries data-active="true". Group wrappers carry data-group with the group id; the planned/executed pills carry data-status.'
137
+ }
138
+ }
139
+ }, it = [
140
+ // What a check-up records and what fills it back in.
141
+ { id: "decay", conditions: ["caries", "filled", "medication"] },
142
+ // Everything that replaces or covers the crown.
143
+ {
144
+ id: "prosthetics",
145
+ conditions: [
146
+ "crowned",
147
+ "temporaryCrown",
148
+ "bridge",
149
+ "stub",
150
+ "implant",
151
+ "implantExtraction"
152
+ ]
153
+ },
154
+ // Work inside the root.
155
+ { id: "endodontics", conditions: ["rootCanal", "pin", "rootAmputation"] },
156
+ // Work on the tissue around the tooth.
157
+ {
158
+ id: "periodontics",
159
+ conditions: ["periodontalSurgery", "mucogingivalSurgery", "curettage"]
160
+ },
161
+ // Flank-mounted appliance fittings.
162
+ { id: "orthodontics", conditions: ["anchorage", "hook", "attachment"] },
163
+ // The tooth's own status, plus the diagnostic marker.
164
+ { id: "diagnosis", conditions: ["missing", "destroyed", "xray"] }
165
+ ], Lt = "custom", at = ["planned", "executed"], Ot = "16", zt = I(
166
+ [
167
+ "ds:flex ds:text-[var(--foreground)]",
168
+ "ds:focus:outline-none",
169
+ "ds:aria-disabled:opacity-60"
170
+ ].join(" "),
171
+ {
172
+ variants: {
173
+ orientation: {
174
+ horizontal: "ds:flex-row ds:flex-wrap ds:items-start",
175
+ vertical: "ds:flex-col ds:items-stretch"
176
+ },
177
+ size: {
178
+ sm: "ds:gap-[var(--spacing-sm)]",
179
+ md: "ds:gap-[var(--spacing-md)]",
180
+ lg: "ds:gap-[var(--spacing-lg)]"
181
+ }
182
+ },
183
+ defaultVariants: { orientation: "horizontal", size: "md" }
184
+ }
185
+ ), ot = I(
186
+ ["ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:min-w-0"].join(" ")
187
+ ), nt = I(
188
+ ["type-eyebrow ds:text-[color:var(--muted-foreground)]"].join(" ")
189
+ ), rt = I(["ds:flex"].join(" "), {
190
+ variants: {
191
+ orientation: {
192
+ horizontal: "ds:flex-row ds:flex-wrap ds:items-stretch",
193
+ vertical: "ds:flex-col ds:items-stretch"
194
+ },
195
+ size: {
196
+ sm: "ds:gap-[var(--spacing-xs)]",
197
+ md: "ds:gap-[var(--spacing-xs)]",
198
+ lg: "ds:gap-[var(--spacing-sm)]"
199
+ }
200
+ },
201
+ defaultVariants: { orientation: "horizontal", size: "md" }
202
+ }), Kt = I(
203
+ [
204
+ // `min-w-0` (and NOT `shrink-0`): a wrapped row wraps first and only then
205
+ // shrinks the tiles on a line, so a long CJK label truncates inside its own
206
+ // tile instead of pushing the toolbar wider than its frame.
207
+ "ds:relative ds:inline-flex ds:items-center ds:min-w-0",
208
+ "ds:gap-[var(--spacing-xs)] ds:text-start",
209
+ "ds:rounded-[var(--radius-md)] ds:border-2 ds:cursor-pointer",
210
+ "ds:min-h-[var(--min-target-size)]",
211
+ "ds:transition-colors ds:duration-[var(--animation-duration)]",
212
+ "ds:motion-reduce:transition-none",
213
+ "ds:focus:outline-none",
214
+ "ds:focus-visible:outline-[length:var(--focus-ring-width)]",
215
+ "ds:focus-visible:outline-solid ds:focus-visible:outline-[var(--ring)]",
216
+ "ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]",
217
+ "ds:forced-colors:border-[ButtonBorder]",
218
+ "ds:forced-colors:focus-visible:outline-[CanvasText]",
219
+ "ds:disabled:opacity-50 ds:disabled:cursor-not-allowed"
220
+ ].join(" "),
221
+ {
222
+ variants: {
223
+ selected: {
224
+ true: [
225
+ "ds:border-[var(--primary)]",
226
+ "ds:bg-[color-mix(in_srgb,var(--primary)_12%,var(--card))]",
227
+ "ds:font-semibold",
228
+ "ds:forced-colors:border-[Highlight]"
229
+ ].join(" "),
230
+ false: [
231
+ "ds:border-[var(--border)] ds:bg-[var(--card)] ds:font-normal",
232
+ "ds:hover:bg-[color-mix(in_srgb,var(--accent)_10%,var(--card))]"
233
+ ].join(" ")
234
+ },
235
+ size: {
236
+ sm: "type-meta ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-sm)] ds:py-[var(--spacing-xs)]",
237
+ md: "type-body-sm ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-sm)] ds:py-[var(--spacing-xs)]",
238
+ lg: "type-body ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-md)] ds:py-[var(--spacing-sm)]"
239
+ },
240
+ orientation: {
241
+ horizontal: "",
242
+ vertical: "ds:w-full ds:justify-start"
243
+ }
244
+ },
245
+ defaultVariants: { selected: !1, size: "md", orientation: "horizontal" }
246
+ }
247
+ ), Ut = I(
248
+ [
249
+ "ds:inline-flex ds:items-center ds:shrink-0",
250
+ "ds:gap-[var(--spacing-xs)] ds:text-start ds:whitespace-nowrap",
251
+ "ds:rounded-[var(--radius-md)] ds:border-2 ds:cursor-pointer",
252
+ "ds:min-h-[var(--min-target-size)]",
253
+ "ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]",
254
+ "ds:transition-colors ds:duration-[var(--animation-duration)]",
255
+ "ds:motion-reduce:transition-none",
256
+ "ds:focus:outline-none",
257
+ "ds:focus-visible:outline-[length:var(--focus-ring-width)]",
258
+ "ds:focus-visible:outline-solid ds:focus-visible:outline-[var(--ring)]",
259
+ "ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]",
260
+ "ds:forced-colors:border-[ButtonBorder]",
261
+ "ds:forced-colors:focus-visible:outline-[CanvasText]",
262
+ "ds:disabled:opacity-50 ds:disabled:cursor-not-allowed"
263
+ ].join(" "),
264
+ {
265
+ variants: {
266
+ selected: {
267
+ true: [
268
+ "ds:border-[var(--primary)]",
269
+ "ds:bg-[color-mix(in_srgb,var(--primary)_12%,var(--card))]",
270
+ "ds:font-semibold",
271
+ "ds:forced-colors:border-[Highlight]"
272
+ ].join(" "),
273
+ false: [
274
+ "ds:border-[var(--border)] ds:bg-[var(--card)] ds:font-normal",
275
+ "ds:hover:bg-[color-mix(in_srgb,var(--accent)_10%,var(--card))]"
276
+ ].join(" ")
277
+ },
278
+ size: {
279
+ sm: "type-meta ds:py-[var(--spacing-xs)]",
280
+ md: "type-body-sm ds:py-[var(--spacing-xs)]",
281
+ lg: "type-body ds:py-[var(--spacing-sm)]"
282
+ }
283
+ },
284
+ defaultVariants: { selected: !1, size: "md" }
285
+ }
286
+ ), Ht = {
287
+ sm: { w: 18, h: 31 },
288
+ md: { w: 22, h: 38 },
289
+ lg: { w: 28, h: 48 }
290
+ };
291
+ function $t({
292
+ glyph: s,
293
+ colour: o,
294
+ cx: d,
295
+ cy: l,
296
+ testId: g
297
+ }) {
298
+ const r = 9 + s.length * 5;
299
+ return /* @__PURE__ */ w(
300
+ "g",
301
+ {
302
+ transform: `translate(${d - r / 2}, ${l - 7})`,
303
+ "data-testid": g,
304
+ pointerEvents: "none",
305
+ "aria-hidden": "true",
306
+ children: [
307
+ /* @__PURE__ */ a(
308
+ "rect",
309
+ {
310
+ width: r,
311
+ height: 14,
312
+ rx: "3.5",
313
+ fill: "var(--card)",
314
+ stroke: o,
315
+ strokeWidth: "1.5"
316
+ }
317
+ ),
318
+ /* @__PURE__ */ a(
319
+ "text",
320
+ {
321
+ x: r / 2,
322
+ y: 10,
323
+ textAnchor: "middle",
324
+ fontSize: "9",
325
+ fontWeight: "600",
326
+ fill: "var(--foreground)",
327
+ className: "ds:select-none",
328
+ children: s
329
+ }
330
+ )
331
+ ]
332
+ }
333
+ );
334
+ }
335
+ function Bt({
336
+ condition: s,
337
+ assetBaseUrl: o,
338
+ registry: d,
339
+ size: l
340
+ }) {
341
+ const g = _t[Ot], r = At(s, d), f = s === "missing", b = Ct(s, d), y = !r && !f && Nt(s, "side", d), _ = 36 * 0.9, k = 62 * 0.9, E = (36 - _) / 2, u = (62 - k) / 2, { w: c, h: z } = Ht[l];
342
+ return /* @__PURE__ */ w(
343
+ "svg",
344
+ {
345
+ width: c,
346
+ height: z,
347
+ viewBox: "0 0 36 62",
348
+ "aria-hidden": "true",
349
+ className: "ds:block ds:shrink-0",
350
+ "data-testid": `tooth-finding-palette-symbol-${s}`,
351
+ children: [
352
+ /* @__PURE__ */ a(
353
+ "image",
354
+ {
355
+ href: Rt(g, o),
356
+ x: E,
357
+ y: u,
358
+ width: _,
359
+ height: k,
360
+ preserveAspectRatio: "xMidYMid meet",
361
+ opacity: f ? 0.25 : 1
362
+ }
363
+ ),
364
+ r ? /* @__PURE__ */ a(
365
+ "image",
366
+ {
367
+ href: Et(g, o, r),
368
+ x: E,
369
+ y: u,
370
+ width: _,
371
+ height: k,
372
+ preserveAspectRatio: "xMidYMid meet"
373
+ }
374
+ ) : null,
375
+ y ? /* @__PURE__ */ a(
376
+ "rect",
377
+ {
378
+ x: 3,
379
+ y: 2,
380
+ width: 30,
381
+ height: 58,
382
+ fill: "none",
383
+ stroke: b,
384
+ strokeWidth: 2,
385
+ strokeDasharray: s === "filled" ? "4 2" : void 0,
386
+ rx: 6
387
+ }
388
+ ) : null,
389
+ f ? /* @__PURE__ */ a(
390
+ "path",
391
+ {
392
+ d: "M7 9 L29 53 M29 9 L7 53",
393
+ stroke: Pt.missing,
394
+ strokeWidth: 2,
395
+ fill: "none"
396
+ }
397
+ ) : null,
398
+ !r && !y && !f ? /* @__PURE__ */ a(
399
+ $t,
400
+ {
401
+ glyph: Mt(s, d),
402
+ colour: b,
403
+ cx: 18,
404
+ cy: 31,
405
+ testId: `tooth-finding-palette-glyph-${s}`
406
+ }
407
+ ) : null
408
+ ]
409
+ }
410
+ );
411
+ }
412
+ function Gt({ status: s }) {
413
+ return /* @__PURE__ */ a(
414
+ "svg",
415
+ {
416
+ width: "14",
417
+ height: "14",
418
+ viewBox: "0 0 14 14",
419
+ "aria-hidden": "true",
420
+ className: "ds:block ds:shrink-0",
421
+ children: /* @__PURE__ */ a(
422
+ "circle",
423
+ {
424
+ cx: 7,
425
+ cy: 7,
426
+ r: 5,
427
+ fill: s === "executed" ? et.executed : "var(--card)",
428
+ stroke: et[s],
429
+ strokeWidth: 1.75
430
+ }
431
+ )
432
+ }
433
+ );
434
+ }
435
+ function G(s, o = !1) {
436
+ const d = /* @__PURE__ */ new Set();
437
+ return s.map((l) => ({
438
+ id: l.id,
439
+ label: l.label,
440
+ synthetic: o,
441
+ conditions: l.conditions.filter((g) => d.has(g) ? !1 : (d.add(g), !0))
442
+ })).filter((l) => l.conditions.length > 0);
443
+ }
444
+ const qt = yt(function({
445
+ id: o,
446
+ value: d,
447
+ defaultValue: l,
448
+ onChange: g,
449
+ conditions: r,
450
+ groups: f,
451
+ conditionRegistry: b,
452
+ showStatus: y = !1,
453
+ status: _,
454
+ defaultStatus: k = "planned",
455
+ onStatusChange: E,
456
+ size: u = "md",
457
+ orientation: c = "horizontal",
458
+ assetBaseUrl: z = "/toothscheme/teeth",
459
+ disabled: S = !1,
460
+ disabledConditions: q,
461
+ ariaLabel: dt,
462
+ showGroupLabels: W = !0,
463
+ className: lt,
464
+ "aria-label": ct,
465
+ "aria-labelledby": Y,
466
+ ...ut
467
+ }, pt) {
468
+ const { t: x } = kt(), [gt, A] = tt({
469
+ value: d,
470
+ defaultValue: l ?? null,
471
+ onChange: g
472
+ }), h = gt ?? null, [ht, K] = tt({
473
+ value: _,
474
+ defaultValue: k,
475
+ onChange: E
476
+ }), P = ht ?? k, C = F(() => {
477
+ if (f) return G(f);
478
+ if (r) return G([{ id: "all", conditions: r }], !0);
479
+ const t = (b ?? []).map((i) => i.id).filter((i) => !Tt(i)), e = t.length > 0 ? [
480
+ ...it,
481
+ { id: Lt, conditions: t }
482
+ ] : it;
483
+ return G(e);
484
+ }, [f, r, b]), Z = F(
485
+ () => new Set(q ?? []),
486
+ [q]
487
+ ), J = F(
488
+ () => C.flatMap((t) => t.conditions),
489
+ [C]
490
+ ), n = F(() => {
491
+ const t = C.flatMap(
492
+ (e) => e.conditions.map((i) => ({
493
+ kind: "tool",
494
+ key: `tool:${i}`,
495
+ condition: i,
496
+ disabled: S || Z.has(i)
497
+ }))
498
+ );
499
+ return y ? [
500
+ ...t,
501
+ ...at.map((e) => ({
502
+ kind: "status",
503
+ key: `status:${e}`,
504
+ status: e,
505
+ disabled: S
506
+ }))
507
+ ] : t;
508
+ }, [C, Z, S, y]), M = X([]);
509
+ M.current.length = n.length;
510
+ const [U, H] = xt(null), N = F(() => {
511
+ if (n.length === 0) return -1;
512
+ const t = n.findIndex((e) => !e.disabled);
513
+ if (t === -1) return -1;
514
+ if (U !== null) {
515
+ const e = Math.min(Math.max(U, 0), n.length - 1);
516
+ return n[e].disabled ? t : e;
517
+ }
518
+ if (h !== null) {
519
+ const e = n.findIndex(
520
+ (i) => i.kind === "tool" && i.condition === h
521
+ );
522
+ if (e !== -1 && !n[e].disabled) return e;
523
+ }
524
+ return t;
525
+ }, [n, U, h]), $ = X(null), Q = O(
526
+ () => typeof window < "u" && $.current !== null && window.getComputedStyle($.current).direction === "rtl",
527
+ []
528
+ ), V = O((t) => {
529
+ var e;
530
+ H(t), (e = M.current[t]) == null || e.focus();
531
+ }, []), ft = O(
532
+ (t) => {
533
+ const e = n.length;
534
+ if (e === 0) return;
535
+ const i = Q(), m = c === "vertical" ? "ArrowDown" : i ? "ArrowLeft" : "ArrowRight", R = c === "vertical" ? "ArrowUp" : i ? "ArrowRight" : "ArrowLeft", D = N === -1 ? 0 : N;
536
+ let p = null, T = 1;
537
+ if (t.key === m ? p = (D + 1) % e : t.key === R ? (p = (D - 1 + e) % e, T = -1) : t.key === "Home" ? p = 0 : t.key === "End" && (p = e - 1, T = -1), p === null) return;
538
+ t.preventDefault();
539
+ let v = p;
540
+ for (let L = 0; L < e && n[v].disabled; L += 1)
541
+ v = (v + T + e) % e;
542
+ V(v);
543
+ },
544
+ [n, c, Q, N, V]
545
+ ), mt = O(
546
+ (t) => {
547
+ A(h === t ? null : t);
548
+ },
549
+ [h, A]
550
+ ), B = F(
551
+ () => ({
552
+ getValue: () => h,
553
+ setValue: (t) => A(t),
554
+ clear: () => A(null),
555
+ getStatus: () => P,
556
+ setStatus: (t) => K(t),
557
+ getTools: () => [...J],
558
+ focusTool: (t) => {
559
+ const e = n.findIndex(
560
+ (i) => i.kind === "tool" && i.condition === t
561
+ );
562
+ e !== -1 && V(e);
563
+ }
564
+ }),
565
+ [h, P, n, J, A, K, V]
566
+ );
567
+ wt(pt, () => B, [B]), St(Dt, B, o);
568
+ const vt = dt ?? ct ?? x("toothFindingPalette.ariaLabel"), bt = (t) => t.label ?? x(`toothFindingPalette.group.${t.id}`, { defaultValue: t.id });
569
+ let j = 0;
570
+ return /* @__PURE__ */ w(
571
+ "div",
572
+ {
573
+ ...ut,
574
+ ref: $,
575
+ role: "toolbar",
576
+ "aria-orientation": c,
577
+ "aria-label": Y ? void 0 : vt,
578
+ "aria-labelledby": Y,
579
+ "aria-disabled": S || void 0,
580
+ "data-component": "tooth-finding-palette",
581
+ "data-component-id": o,
582
+ "data-orientation": c,
583
+ "data-size": u,
584
+ "data-active": h ?? void 0,
585
+ "data-status": y ? P : void 0,
586
+ "data-testid": "tooth-finding-palette",
587
+ id: o,
588
+ onKeyDown: ft,
589
+ className: [zt({ orientation: c, size: u }), lt].filter(Boolean).join(" "),
590
+ children: [
591
+ n.length === 0 ? /* @__PURE__ */ a("p", { className: "type-body-sm ds:text-[color:var(--muted-foreground)] ds:m-0", children: x("toothFindingPalette.empty") }) : null,
592
+ C.map((t) => {
593
+ const e = bt(t);
594
+ return /* @__PURE__ */ w(
595
+ "div",
596
+ {
597
+ role: t.synthetic ? void 0 : "group",
598
+ "aria-label": t.synthetic ? void 0 : e,
599
+ "data-group": t.id,
600
+ "data-testid": `tooth-finding-palette-group-${t.id}`,
601
+ className: ot(),
602
+ children: [
603
+ W && !t.synthetic ? (
604
+ // Sighted-only: the group already carries `heading` as its
605
+ // accessible name, so exposing the text again would announce
606
+ // the group twice.
607
+ /* @__PURE__ */ a("span", { "aria-hidden": "true", className: nt(), children: e })
608
+ ) : null,
609
+ /* @__PURE__ */ a("div", { className: rt({ orientation: c, size: u }), children: t.conditions.map((i) => {
610
+ const m = j;
611
+ j += 1;
612
+ const R = n[m], D = (R == null ? void 0 : R.disabled) ?? S, p = Ft(i, b), T = p.kind === "key" ? x(p.key) : p.text, v = h === i;
613
+ return /* @__PURE__ */ w(
614
+ "button",
615
+ {
616
+ type: "button",
617
+ ref: (L) => {
618
+ M.current[m] = L;
619
+ },
620
+ disabled: D,
621
+ "aria-pressed": v,
622
+ tabIndex: m === N ? 0 : -1,
623
+ "data-condition": i,
624
+ "data-active": v ? "true" : void 0,
625
+ "data-testid": `tooth-finding-palette-tool-${i}`,
626
+ title: T,
627
+ onFocus: () => H(m),
628
+ onClick: () => mt(i),
629
+ className: Kt({
630
+ selected: v,
631
+ size: u,
632
+ orientation: c
633
+ }),
634
+ children: [
635
+ /* @__PURE__ */ a(
636
+ Bt,
637
+ {
638
+ condition: i,
639
+ assetBaseUrl: z,
640
+ registry: b,
641
+ size: u
642
+ }
643
+ ),
644
+ /* @__PURE__ */ a("span", { className: "ds:truncate ds:min-w-0", children: T })
645
+ ]
646
+ },
647
+ i
648
+ );
649
+ }) })
650
+ ]
651
+ },
652
+ t.id
653
+ );
654
+ }),
655
+ y ? /* @__PURE__ */ w(
656
+ "div",
657
+ {
658
+ role: "group",
659
+ "aria-label": x("toothFindingPalette.statusLabel"),
660
+ "data-group": "status",
661
+ "data-testid": "tooth-finding-palette-status-group",
662
+ className: ot(),
663
+ children: [
664
+ W ? /* @__PURE__ */ a("span", { "aria-hidden": "true", className: nt(), children: x("toothFindingPalette.statusLabel") }) : null,
665
+ /* @__PURE__ */ a("div", { className: rt({ orientation: c, size: u }), children: at.map((t) => {
666
+ const e = j;
667
+ j += 1;
668
+ const i = P === t;
669
+ return /* @__PURE__ */ w(
670
+ "button",
671
+ {
672
+ type: "button",
673
+ ref: (m) => {
674
+ M.current[e] = m;
675
+ },
676
+ disabled: S,
677
+ "aria-pressed": i,
678
+ tabIndex: e === N ? 0 : -1,
679
+ "data-status": t,
680
+ "data-active": i ? "true" : void 0,
681
+ "data-testid": `tooth-finding-palette-status-${t}`,
682
+ onFocus: () => H(e),
683
+ onClick: () => K(t),
684
+ className: Ut({ selected: i, size: u }),
685
+ children: [
686
+ /* @__PURE__ */ a(Gt, { status: t }),
687
+ /* @__PURE__ */ a("span", { children: x(It(t)) })
688
+ ]
689
+ },
690
+ t
691
+ );
692
+ }) })
693
+ ]
694
+ }
695
+ ) : null
696
+ ]
697
+ }
698
+ );
699
+ });
700
+ qt.displayName = "ToothFindingPalette";
701
+ export {
702
+ Lt as C,
703
+ it as D,
704
+ qt as T,
705
+ zt as a,
706
+ Dt as t
707
+ };
708
+ //# sourceMappingURL=tooth-finding-palette-vqC-D2Ye.js.map