@alfadocs/ui-kit 0.1.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.
Files changed (217) hide show
  1. package/dist/_chunks/{agenda-card-Bld47Eul.js → agenda-card-DXOgg8IX.js} +3 -3
  2. package/dist/_chunks/{agenda-card-Bld47Eul.js.map → agenda-card-DXOgg8IX.js.map} +1 -1
  3. package/dist/_chunks/{agenda-tray-D86cNIJ0.js → agenda-tray-DEO8XL8V.js} +4 -4
  4. package/dist/_chunks/{agenda-tray-D86cNIJ0.js.map → agenda-tray-DEO8XL8V.js.map} +1 -1
  5. package/dist/_chunks/{ai-prompt-input-CdYwt2VP.js → ai-prompt-input-8IShJ-GX.js} +3 -3
  6. package/dist/_chunks/{ai-prompt-input-CdYwt2VP.js.map → ai-prompt-input-8IShJ-GX.js.map} +1 -1
  7. package/dist/_chunks/{audio-recorder-D2UEBF9B.js → audio-recorder-BvisG0Wt.js} +4 -4
  8. package/dist/_chunks/{audio-recorder-D2UEBF9B.js.map → audio-recorder-BvisG0Wt.js.map} +1 -1
  9. package/dist/_chunks/{autocomplete.agent-Bi6CiRKa.js → autocomplete.agent-BmrpzsfW.js} +2 -2
  10. package/dist/_chunks/autocomplete.agent-BmrpzsfW.js.map +1 -0
  11. package/dist/_chunks/{avatar-BAhxbDEu.js → avatar-DTQY5qIZ.js} +16 -16
  12. package/dist/_chunks/avatar-DTQY5qIZ.js.map +1 -0
  13. package/dist/_chunks/{badge-zDghajh8.js → badge-BbbBRweN.js} +2 -2
  14. package/dist/_chunks/badge-BbbBRweN.js.map +1 -0
  15. package/dist/_chunks/{balance-cell-renderer-BGyvZWjB.js → balance-cell-renderer-DjR0rPS6.js} +7 -7
  16. package/dist/_chunks/{balance-cell-renderer-BGyvZWjB.js.map → balance-cell-renderer-DjR0rPS6.js.map} +1 -1
  17. package/dist/_chunks/{button-DmiGFnNA.js → button-7dTew-IV.js} +4 -4
  18. package/dist/_chunks/button-7dTew-IV.js.map +1 -0
  19. package/dist/_chunks/{chat-container-Co8HpB64.js → chat-container-ChdJTH0J.js} +2 -2
  20. package/dist/_chunks/{chat-container-Co8HpB64.js.map → chat-container-ChdJTH0J.js.map} +1 -1
  21. package/dist/_chunks/{chat-input-3rstZhHR.js → chat-input-C-B4snVJ.js} +2 -2
  22. package/dist/_chunks/{chat-input-3rstZhHR.js.map → chat-input-C-B4snVJ.js.map} +1 -1
  23. package/dist/_chunks/{chat-message-dDMVSYBs.js → chat-message-cFNbQYRH.js} +3 -3
  24. package/dist/_chunks/{chat-message-dDMVSYBs.js.map → chat-message-cFNbQYRH.js.map} +1 -1
  25. package/dist/_chunks/{color-picker-OKKF3Dww.js → color-picker-DkMFcK2m.js} +74 -74
  26. package/dist/_chunks/color-picker-DkMFcK2m.js.map +1 -0
  27. package/dist/_chunks/{combobox.agent-CfeB-IZ1.js → combobox.agent-9w6W1Jct.js} +20 -20
  28. package/dist/_chunks/combobox.agent-9w6W1Jct.js.map +1 -0
  29. package/dist/_chunks/{command-palette.agent-XLfSGHCL.js → command-palette.agent-Dg7jhOIc.js} +2 -2
  30. package/dist/_chunks/command-palette.agent-Dg7jhOIc.js.map +1 -0
  31. package/dist/_chunks/{date-picker-DXx8oSJb.js → date-picker-0WQ98ZC0.js} +2 -2
  32. package/dist/_chunks/{date-picker-DXx8oSJb.js.map → date-picker-0WQ98ZC0.js.map} +1 -1
  33. package/dist/_chunks/{date-range-picker-C3CbY__H.js → date-range-picker-CtwEwoyr.js} +2 -2
  34. package/dist/_chunks/{date-range-picker-C3CbY__H.js.map → date-range-picker-CtwEwoyr.js.map} +1 -1
  35. package/dist/_chunks/{date-time-picker-Bn3FPeAc.js → date-time-picker-Df3OJ2_C.js} +6 -6
  36. package/dist/_chunks/date-time-picker-Df3OJ2_C.js.map +1 -0
  37. package/dist/_chunks/{description-list-B1CL3RTG.js → description-list-Bk3p71qY.js} +2 -2
  38. package/dist/_chunks/{description-list-B1CL3RTG.js.map → description-list-Bk3p71qY.js.map} +1 -1
  39. package/dist/_chunks/{dialog.agent-D9WeIWi2.js → dialog.agent-CtMkDinJ.js} +2 -2
  40. package/dist/_chunks/{dialog.agent-D9WeIWi2.js.map → dialog.agent-CtMkDinJ.js.map} +1 -1
  41. package/dist/_chunks/{empty-state-DV96gCnp.js → empty-state-DPUnQp0A.js} +2 -2
  42. package/dist/_chunks/{empty-state-DV96gCnp.js.map → empty-state-DPUnQp0A.js.map} +1 -1
  43. package/dist/_chunks/{file-upload.agent-DYFnqdxw.js → file-upload.agent-DVMxMeDA.js} +3 -3
  44. package/dist/_chunks/file-upload.agent-DVMxMeDA.js.map +1 -0
  45. package/dist/_chunks/{floating-action-button-RigP2E7o.js → floating-action-button-DjRhFQdd.js} +4 -4
  46. package/dist/_chunks/floating-action-button-DjRhFQdd.js.map +1 -0
  47. package/dist/_chunks/{freemium-paywall-D0GiUFOe.js → freemium-paywall-CCsX3GhK.js} +3 -3
  48. package/dist/_chunks/{freemium-paywall-D0GiUFOe.js.map → freemium-paywall-CCsX3GhK.js.map} +1 -1
  49. package/dist/_chunks/{header-CW2oRd5H.js → header-CVQxeLc_.js} +2 -2
  50. package/dist/_chunks/{header-CW2oRd5H.js.map → header-CVQxeLc_.js.map} +1 -1
  51. package/dist/_chunks/{icon-button-C482ii4y.js → icon-button-SWpSs9S6.js} +2 -2
  52. package/dist/_chunks/{icon-button-C482ii4y.js.map → icon-button-SWpSs9S6.js.map} +1 -1
  53. package/dist/_chunks/{key-value-pair-DDhSYdDL.js → key-value-pair-Cm-pSE6k.js} +2 -2
  54. package/dist/_chunks/{key-value-pair-DDhSYdDL.js.map → key-value-pair-Cm-pSE6k.js.map} +1 -1
  55. package/dist/_chunks/{leo-sidebar-gXXcGPKk.js → leo-sidebar-SqGAp1vx.js} +9 -9
  56. package/dist/_chunks/{leo-sidebar-gXXcGPKk.js.map → leo-sidebar-SqGAp1vx.js.map} +1 -1
  57. package/dist/_chunks/{message-card-DID3cXUW.js → message-card-B0oGrI3i.js} +4 -4
  58. package/dist/_chunks/{message-card-DID3cXUW.js.map → message-card-B0oGrI3i.js.map} +1 -1
  59. package/dist/_chunks/{message-tray-CVMLBnVp.js → message-tray-DZ6oZ0cs.js} +4 -4
  60. package/dist/_chunks/{message-tray-CVMLBnVp.js.map → message-tray-DZ6oZ0cs.js.map} +1 -1
  61. package/dist/_chunks/{multi-select.agent-BUKYZJfp.js → multi-select.agent-BDEVGMmW.js} +19 -19
  62. package/dist/_chunks/multi-select.agent-BDEVGMmW.js.map +1 -0
  63. package/dist/_chunks/{notification-card-BZ33fq8H.js → notification-card-C73GqjHH.js} +3 -3
  64. package/dist/_chunks/{notification-card-BZ33fq8H.js.map → notification-card-C73GqjHH.js.map} +1 -1
  65. package/dist/_chunks/{notification-tray-CnEd7B2q.js → notification-tray-a8a_nut-.js} +4 -4
  66. package/dist/_chunks/{notification-tray-CnEd7B2q.js.map → notification-tray-a8a_nut-.js.map} +1 -1
  67. package/dist/_chunks/{number-input-D7rSa_ef.js → number-input-DFQtl5K2.js} +4 -4
  68. package/dist/_chunks/number-input-DFQtl5K2.js.map +1 -0
  69. package/dist/_chunks/{otp-input-C9R9sC74.js → otp-input-C2FdizHh.js} +14 -14
  70. package/dist/_chunks/otp-input-C2FdizHh.js.map +1 -0
  71. package/dist/_chunks/{pagination.agent-D75FB6XP.js → pagination.agent-sxokDphY.js} +15 -15
  72. package/dist/_chunks/pagination.agent-sxokDphY.js.map +1 -0
  73. package/dist/_chunks/{patient-shell-CGsmI5LJ.js → patient-shell-B4vKnuOf.js} +4 -4
  74. package/dist/_chunks/{patient-shell-CGsmI5LJ.js.map → patient-shell-B4vKnuOf.js.map} +1 -1
  75. package/dist/_chunks/{payment-form-l3j-gA-t.js → payment-form-175AzK-1.js} +20 -20
  76. package/dist/_chunks/payment-form-175AzK-1.js.map +1 -0
  77. package/dist/_chunks/{phone-input-ZWa_FU4R.js → phone-input-BavVyXxZ.js} +39 -39
  78. package/dist/_chunks/phone-input-BavVyXxZ.js.map +1 -0
  79. package/dist/_chunks/{popover-CMr1pTPO.js → popover-BWgOopjI.js} +3 -3
  80. package/dist/_chunks/popover-BWgOopjI.js.map +1 -0
  81. package/dist/_chunks/{privacy-lock-DdpkKNM2.js → privacy-lock-DWL7m_VT.js} +10 -11
  82. package/dist/_chunks/{privacy-lock-DdpkKNM2.js.map → privacy-lock-DWL7m_VT.js.map} +1 -1
  83. package/dist/_chunks/{react-day-picker-d0MHsyCj.js → react-day-picker-C04L_28V.js} +5 -5
  84. package/dist/_chunks/{react-day-picker-d0MHsyCj.js.map → react-day-picker-C04L_28V.js.map} +1 -1
  85. package/dist/_chunks/{rich-text-editor.agent-C1_E7_7t.js → rich-text-editor.agent-COSb5_2D.js} +4 -4
  86. package/dist/_chunks/rich-text-editor.agent-COSb5_2D.js.map +1 -0
  87. package/dist/_chunks/{select-DbxWF3O_.js → select-CQxhOXVE.js} +7 -7
  88. package/dist/_chunks/select-CQxhOXVE.js.map +1 -0
  89. package/dist/_chunks/{sheet-DyWqluiS.js → sheet-CKsuHuHB.js} +2 -2
  90. package/dist/_chunks/{sheet-DyWqluiS.js.map → sheet-CKsuHuHB.js.map} +1 -1
  91. package/dist/_chunks/{sidebar-B52iGGNV.js → sidebar-CiEpSH9e.js} +6 -6
  92. package/dist/_chunks/sidebar-CiEpSH9e.js.map +1 -0
  93. package/dist/_chunks/{sign-in-with-alfadocs-button-BU7MP5Hg.js → sign-in-with-alfadocs-button-BDErAgG2.js} +2 -2
  94. package/dist/_chunks/{sign-in-with-alfadocs-button-BU7MP5Hg.js.map → sign-in-with-alfadocs-button-BDErAgG2.js.map} +1 -1
  95. package/dist/_chunks/{signature-capture.agent-4htVctJ2.js → signature-capture.agent-C38VPXxg.js} +19 -19
  96. package/dist/_chunks/signature-capture.agent-C38VPXxg.js.map +1 -0
  97. package/dist/_chunks/{slider-n8JWpJvT.js → slider-BVBlOW_l.js} +2 -2
  98. package/dist/_chunks/slider-BVBlOW_l.js.map +1 -0
  99. package/dist/_chunks/{slot-grid-BRAkqChA.js → slot-grid-B4WvLEwT.js} +55 -55
  100. package/dist/_chunks/slot-grid-B4WvLEwT.js.map +1 -0
  101. package/dist/_chunks/{sparkline.agent-BLY1IMyW.js → sparkline.agent-C_xp3NRB.js} +2 -2
  102. package/dist/_chunks/{sparkline.agent-BLY1IMyW.js.map → sparkline.agent-C_xp3NRB.js.map} +1 -1
  103. package/dist/_chunks/{stepper-calendar-vtWwa2bY.js → stepper-calendar-BZUJpj8i.js} +6 -6
  104. package/dist/_chunks/stepper-calendar-BZUJpj8i.js.map +1 -0
  105. package/dist/_chunks/{tabs.agent-BDUlyPbJ.js → tabs.agent-sQAHxebC.js} +5 -5
  106. package/dist/_chunks/tabs.agent-sQAHxebC.js.map +1 -0
  107. package/dist/_chunks/{task-tray-BnpiodZ4.js → task-tray-CWvVxWM0.js} +3 -3
  108. package/dist/_chunks/{task-tray-BnpiodZ4.js.map → task-tray-CWvVxWM0.js.map} +1 -1
  109. package/dist/_chunks/{text-area-BqbruBWx.js → text-area-iPDv7Nah.js} +10 -10
  110. package/dist/_chunks/text-area-iPDv7Nah.js.map +1 -0
  111. package/dist/_chunks/{theme-toggle-BHKMiORD.js → theme-toggle-CEaPghpm.js} +2 -2
  112. package/dist/_chunks/{theme-toggle-BHKMiORD.js.map → theme-toggle-CEaPghpm.js.map} +1 -1
  113. package/dist/_chunks/{time-picker-DbpAmPux.js → time-picker-Crc87DU3.js} +67 -67
  114. package/dist/_chunks/time-picker-Crc87DU3.js.map +1 -0
  115. package/dist/_chunks/{timeline-vjsUeuq1.js → timeline-Ym2DRmtu.js} +2 -2
  116. package/dist/_chunks/{timeline-vjsUeuq1.js.map → timeline-Ym2DRmtu.js.map} +1 -1
  117. package/dist/_chunks/{toast-DllSITLf.js → toast-DoMNrzwm.js} +2 -2
  118. package/dist/_chunks/{toast-DllSITLf.js.map → toast-DoMNrzwm.js.map} +1 -1
  119. package/dist/_chunks/{tooth-scheme.agent-BRqxWa1D.js → tooth-scheme.agent-BlDyu-Gx.js} +2 -2
  120. package/dist/_chunks/{tooth-scheme.agent-BRqxWa1D.js.map → tooth-scheme.agent-BlDyu-Gx.js.map} +1 -1
  121. package/dist/_chunks/{warning-stack-B9N9yWet.js → warning-stack-5KROOw9M.js} +2 -2
  122. package/dist/_chunks/{warning-stack-B9N9yWet.js.map → warning-stack-5KROOw9M.js.map} +1 -1
  123. package/dist/_chunks/{workflow-map-gBhL_Wrs.js → workflow-map-D4sjYv2d.js} +6 -6
  124. package/dist/_chunks/{workflow-map-gBhL_Wrs.js.map → workflow-map-D4sjYv2d.js.map} +1 -1
  125. package/dist/agent-catalog.json +1 -1
  126. package/dist/components/agenda-card/index.js +1 -1
  127. package/dist/components/agenda-tray/index.js +1 -1
  128. package/dist/components/ai-prompt-input/index.js +1 -1
  129. package/dist/components/audio-recorder/index.js +1 -1
  130. package/dist/components/autocomplete/index.js +1 -1
  131. package/dist/components/avatar/index.js +1 -1
  132. package/dist/components/badge/index.js +1 -1
  133. package/dist/components/button/index.js +2 -2
  134. package/dist/components/chat-container/index.js +1 -1
  135. package/dist/components/chat-input/index.js +1 -1
  136. package/dist/components/chat-message/index.js +1 -1
  137. package/dist/components/color-picker/index.js +1 -1
  138. package/dist/components/combobox/index.js +1 -1
  139. package/dist/components/command-palette/index.js +1 -1
  140. package/dist/components/data-table/index.js +1 -1
  141. package/dist/components/date-picker/index.js +1 -1
  142. package/dist/components/date-range-picker/index.js +1 -1
  143. package/dist/components/date-time-picker/index.js +1 -1
  144. package/dist/components/description-list/index.js +1 -1
  145. package/dist/components/dialog/index.js +1 -1
  146. package/dist/components/empty-state/index.js +1 -1
  147. package/dist/components/file-upload/index.js +1 -1
  148. package/dist/components/floating-action-button/index.js +1 -1
  149. package/dist/components/freemium-paywall/index.js +1 -1
  150. package/dist/components/header/index.js +1 -1
  151. package/dist/components/icon-button/index.js +1 -1
  152. package/dist/components/key-value-pair/index.js +1 -1
  153. package/dist/components/message-card/index.js +1 -1
  154. package/dist/components/message-tray/index.js +1 -1
  155. package/dist/components/multi-select/index.js +1 -1
  156. package/dist/components/notification-card/index.js +1 -1
  157. package/dist/components/notification-tray/index.js +1 -1
  158. package/dist/components/number-input/index.js +1 -1
  159. package/dist/components/otp-input/index.js +1 -1
  160. package/dist/components/pagination/index.js +1 -1
  161. package/dist/components/payment-form/index.js +1 -1
  162. package/dist/components/phone-input/index.js +1 -1
  163. package/dist/components/popover/index.js +1 -1
  164. package/dist/components/privacy-lock/index.js +1 -1
  165. package/dist/components/privacy-lock/privacy-lock.d.ts.map +1 -1
  166. package/dist/components/rich-text-editor/index.js +1 -1
  167. package/dist/components/select/index.js +1 -1
  168. package/dist/components/sheet/index.js +1 -1
  169. package/dist/components/sidebar/index.js +1 -1
  170. package/dist/components/sign-in-with-alfadocs-button/index.js +1 -1
  171. package/dist/components/signature-capture/index.js +1 -1
  172. package/dist/components/slider/index.js +1 -1
  173. package/dist/components/slot-grid/index.js +1 -1
  174. package/dist/components/sparkline/index.js +1 -1
  175. package/dist/components/stepper-calendar/index.js +1 -1
  176. package/dist/components/tabs/index.js +1 -1
  177. package/dist/components/task-tray/index.js +1 -1
  178. package/dist/components/text-area/index.js +1 -1
  179. package/dist/components/theme-toggle/index.js +1 -1
  180. package/dist/components/time-picker/index.js +1 -1
  181. package/dist/components/timeline/index.js +1 -1
  182. package/dist/components/toast/index.js +1 -1
  183. package/dist/components/tooth-scheme/index.js +1 -1
  184. package/dist/components/warning-stack/index.js +1 -1
  185. package/dist/components/workflow/index.js +1 -1
  186. package/dist/index.js +61 -61
  187. package/dist/patterns/leo-assistant/index.js +1 -1
  188. package/dist/patterns/patient-shell/index.js +1 -1
  189. package/dist/tokens.css +1 -1
  190. package/package.json +1 -1
  191. package/dist/_chunks/autocomplete.agent-Bi6CiRKa.js.map +0 -1
  192. package/dist/_chunks/avatar-BAhxbDEu.js.map +0 -1
  193. package/dist/_chunks/badge-zDghajh8.js.map +0 -1
  194. package/dist/_chunks/button-DmiGFnNA.js.map +0 -1
  195. package/dist/_chunks/color-picker-OKKF3Dww.js.map +0 -1
  196. package/dist/_chunks/combobox.agent-CfeB-IZ1.js.map +0 -1
  197. package/dist/_chunks/command-palette.agent-XLfSGHCL.js.map +0 -1
  198. package/dist/_chunks/date-time-picker-Bn3FPeAc.js.map +0 -1
  199. package/dist/_chunks/file-upload.agent-DYFnqdxw.js.map +0 -1
  200. package/dist/_chunks/floating-action-button-RigP2E7o.js.map +0 -1
  201. package/dist/_chunks/multi-select.agent-BUKYZJfp.js.map +0 -1
  202. package/dist/_chunks/number-input-D7rSa_ef.js.map +0 -1
  203. package/dist/_chunks/otp-input-C9R9sC74.js.map +0 -1
  204. package/dist/_chunks/pagination.agent-D75FB6XP.js.map +0 -1
  205. package/dist/_chunks/payment-form-l3j-gA-t.js.map +0 -1
  206. package/dist/_chunks/phone-input-ZWa_FU4R.js.map +0 -1
  207. package/dist/_chunks/popover-CMr1pTPO.js.map +0 -1
  208. package/dist/_chunks/rich-text-editor.agent-C1_E7_7t.js.map +0 -1
  209. package/dist/_chunks/select-DbxWF3O_.js.map +0 -1
  210. package/dist/_chunks/sidebar-B52iGGNV.js.map +0 -1
  211. package/dist/_chunks/signature-capture.agent-4htVctJ2.js.map +0 -1
  212. package/dist/_chunks/slider-n8JWpJvT.js.map +0 -1
  213. package/dist/_chunks/slot-grid-BRAkqChA.js.map +0 -1
  214. package/dist/_chunks/stepper-calendar-vtWwa2bY.js.map +0 -1
  215. package/dist/_chunks/tabs.agent-BDUlyPbJ.js.map +0 -1
  216. package/dist/_chunks/text-area-BqbruBWx.js.map +0 -1
  217. package/dist/_chunks/time-picker-DbpAmPux.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"tooth-scheme.agent-BRqxWa1D.js","sources":["../../src/components/tooth-scheme/tooth-data.ts","../../src/components/tooth-scheme/tooth-scheme.tsx","../../src/components/tooth-scheme/tooth-scheme.agent.ts"],"sourcesContent":["/* ------------------------------------------------------------------ */\n/* ToothScheme — data model + lookup tables. */\n/* */\n/* FDI ISO 3950 is the canonical internal id. This module exposes */\n/* conversion tables to Universal (ADA) and a simplified Palmer-style */\n/* quadrant+position string so consuming UIs can toggle numbering. */\n/* */\n/* Why simplified Palmer? True Palmer notation uses quadrant bracket */\n/* glyphs (\"⌐\", \"¬\", \"L\", \"J\") that do not render reliably in every */\n/* browser/font combination. We emit a readable `UR3` / `LL6` form */\n/* instead and document the deviation in the component MDX. */\n/* ------------------------------------------------------------------ */\n\n/* ------------------------------------------------------------------ */\n/* Core types */\n/* ------------------------------------------------------------------ */\n\nexport type FdiId = string; // '11'–'48' permanent, '51'–'85' primary\n\nexport type Dentition = 'permanent' | 'primary' | 'mixed';\nexport type Numbering = 'fdi' | 'universal' | 'palmer';\nexport type ToothMode = 'interactive' | 'display';\nexport type Surface = 'mesial' | 'distal' | 'occlusal' | 'buccal' | 'lingual';\nexport type ToothCondition =\n | 'caries'\n | 'filled'\n | 'crowned'\n | 'missing'\n | 'implant'\n | 'rootCanal';\n\nexport interface ToothState {\n conditions: ToothCondition[];\n surfaces: Surface[];\n notes?: string;\n}\n\nexport type ToothChart = Record<FdiId, ToothState>;\n\nexport type Anatomy = 'incisor' | 'canine' | 'premolar' | 'molar';\nexport type Arch = 'upper' | 'lower';\nexport type Side = 'right' | 'left'; // patient's side (NOT viewer's)\nexport type Quadrant = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;\n\nexport interface ToothMeta {\n fdi: FdiId;\n /** '1'–'32' for permanent, 'A'–'T' for primary. */\n universal: string;\n /** Simplified Palmer quadrant-and-position string, e.g. 'UR3', 'LL6'. */\n palmer: string;\n quadrant: Quadrant;\n /** 1–8 (permanent) or 1–5 (primary), counted from the midline outward. */\n positionInQuadrant: number;\n anatomy: Anatomy;\n arch: Arch;\n side: Side;\n dentition: 'permanent' | 'primary';\n}\n\n/* ------------------------------------------------------------------ */\n/* Layout orders */\n/* */\n/* Layout reads from the viewer's perspective, top-left to bottom- */\n/* right. The chart is FIXED in clinical convention: the patient's */\n/* right side sits on the viewer's left, regardless of document `dir`. */\n/* ------------------------------------------------------------------ */\n\n/**\n * 32 permanent teeth in visual layout order:\n * upper row: 18..11 (patient upper-right, outermost → midline), then 21..28 (upper-left, midline → outermost)\n * lower row: 48..41 (patient lower-right, outermost → midline), then 31..38 (lower-left, midline → outermost)\n */\nexport const PERMANENT_TEETH: FdiId[] = [\n // upper\n '18', '17', '16', '15', '14', '13', '12', '11',\n '21', '22', '23', '24', '25', '26', '27', '28',\n // lower\n '48', '47', '46', '45', '44', '43', '42', '41',\n '31', '32', '33', '34', '35', '36', '37', '38',\n];\n\n/**\n * 20 primary teeth in visual layout order:\n * upper row: 55..51 (upper-right outermost → midline), then 61..65\n * lower row: 85..81, then 71..75\n */\nexport const PRIMARY_TEETH: FdiId[] = [\n // upper\n '55', '54', '53', '52', '51',\n '61', '62', '63', '64', '65',\n // lower\n '85', '84', '83', '82', '81',\n '71', '72', '73', '74', '75',\n];\n\n/* ------------------------------------------------------------------ */\n/* Anatomy by position */\n/* ------------------------------------------------------------------ */\n\nfunction permanentAnatomy(positionInQuadrant: number): Anatomy {\n if (positionInQuadrant <= 2) return 'incisor';\n if (positionInQuadrant === 3) return 'canine';\n if (positionInQuadrant <= 5) return 'premolar';\n return 'molar';\n}\n\nfunction primaryAnatomy(positionInQuadrant: number): Anatomy {\n if (positionInQuadrant <= 2) return 'incisor';\n if (positionInQuadrant === 3) return 'canine';\n // Primary dentition has no premolars — positions 4 & 5 are molars.\n return 'molar';\n}\n\n/* ------------------------------------------------------------------ */\n/* Palmer helper */\n/* ------------------------------------------------------------------ */\n\nfunction palmerCode(quadrant: Quadrant, position: number): string {\n // Permanent: 1=UR, 2=UL, 3=LL, 4=LR. Primary: 5=UR, 6=UL, 7=LL, 8=LR.\n // Mapping is identical within each dentition ring; the number is what\n // changes, so we fold 5→1, 6→2, 7→3, 8→4 to derive the quadrant code.\n const normalised = ((quadrant - 1) % 4) + 1;\n const code =\n normalised === 1 ? 'UR'\n : normalised === 2 ? 'UL'\n : normalised === 3 ? 'LL'\n : 'LR';\n return `${code}${position}`;\n}\n\n/* ------------------------------------------------------------------ */\n/* Universal (ADA) conversion */\n/* */\n/* Permanent — Universal numbers 1..32 run clockwise from the */\n/* patient's upper-right 3rd molar (FDI 18 = Universal 1), across */\n/* the upper arch (18→11 = 1→8, 21→28 = 9→16), then down the left */\n/* lower arch (38→31 = 17→24) and across the right lower (41→48 = */\n/* 25→32). */\n/* */\n/* Primary — Universal letters A..T walk the same path: */\n/* 55→51 = A→E, 61→65 = F→J, 75→71 = K→O, 81→85 = P→T. */\n/* ------------------------------------------------------------------ */\n\nfunction permanentUniversal(quadrant: Quadrant, position: number): string {\n switch (quadrant) {\n case 1:\n // 18→1, 17→2, …, 11→8\n return String(1 + (8 - position));\n case 2:\n // 21→9, 22→10, …, 28→16\n return String(8 + position);\n case 3:\n // 38→17, 37→18, …, 31→24\n return String(17 + (8 - position));\n case 4:\n // 41→25, 42→26, …, 48→32\n return String(24 + position);\n default:\n return '';\n }\n}\n\nfunction primaryUniversal(quadrant: Quadrant, position: number): string {\n const letters = 'ABCDEFGHIJKLMNOPQRST';\n let index = -1;\n switch (quadrant) {\n case 5:\n // 55→A, 54→B, 53→C, 52→D, 51→E\n index = 0 + (5 - position);\n break;\n case 6:\n // 61→F, 62→G, 63→H, 64→I, 65→J\n index = 5 + (position - 1);\n break;\n case 7:\n // 75→K, 74→L, 73→M, 72→N, 71→O\n index = 10 + (5 - position);\n break;\n case 8:\n // 81→P, 82→Q, 83→R, 84→S, 85→T\n index = 15 + (position - 1);\n break;\n default:\n index = -1;\n }\n return index >= 0 ? letters[index] : '';\n}\n\n/* ------------------------------------------------------------------ */\n/* Meta builder */\n/* ------------------------------------------------------------------ */\n\nfunction buildMeta(fdi: FdiId): ToothMeta {\n const quadrant = Number(fdi[0]) as Quadrant;\n const position = Number(fdi[1]);\n const isPrimary = quadrant >= 5;\n const anatomy = isPrimary ? primaryAnatomy(position) : permanentAnatomy(position);\n const arch: Arch = quadrant === 1 || quadrant === 2 || quadrant === 5 || quadrant === 6 ? 'upper' : 'lower';\n const side: Side = quadrant === 1 || quadrant === 4 || quadrant === 5 || quadrant === 8 ? 'right' : 'left';\n const universal = isPrimary ? primaryUniversal(quadrant, position) : permanentUniversal(quadrant, position);\n const palmer = palmerCode(quadrant, position);\n return {\n fdi,\n universal,\n palmer,\n quadrant,\n positionInQuadrant: position,\n anatomy,\n arch,\n side,\n dentition: isPrimary ? 'primary' : 'permanent',\n };\n}\n\nexport const FDI_TO_META: Record<FdiId, ToothMeta> = [\n ...PERMANENT_TEETH,\n ...PRIMARY_TEETH,\n].reduce<Record<FdiId, ToothMeta>>((acc, fdi) => {\n acc[fdi] = buildMeta(fdi);\n return acc;\n}, {});\n\nexport const FDI_TO_UNIVERSAL: Record<FdiId, string> = Object.fromEntries(\n Object.entries(FDI_TO_META).map(([fdi, meta]) => [fdi, meta.universal]),\n);\n\nexport const FDI_TO_PALMER: Record<FdiId, string> = Object.fromEntries(\n Object.entries(FDI_TO_META).map(([fdi, meta]) => [fdi, meta.palmer]),\n);\n\n/* ------------------------------------------------------------------ */\n/* Condition → token + pattern */\n/* */\n/* Every condition carries BOTH a colour AND a fill pattern so */\n/* colour-blind clinicians can distinguish states in the SVG (and in */\n/* black-and-white prints) — colour is never the sole channel. */\n/* ------------------------------------------------------------------ */\n\n/** CSS variable name (without the leading `var(...)`) that drives a condition's colour. */\nexport const CONDITION_TOKENS: Record<ToothCondition, string> = {\n caries: '--destructive',\n filled: '--info',\n crowned: '--warning',\n missing: '--muted-foreground',\n implant: '--accent',\n rootCanal: '--primary',\n};\n\n/**\n * Convenience: the `fill=\"var(--destructive)\"` string ready to paste onto\n * an SVG attribute. Kept in sync with `CONDITION_TOKENS`.\n */\nexport const CONDITION_COLORS: Record<ToothCondition, string> = {\n caries: 'var(--destructive)',\n filled: 'var(--info)',\n crowned: 'var(--warning)',\n missing: 'var(--muted-foreground)',\n implant: 'var(--accent)',\n rootCanal: 'var(--primary)',\n};\n\n/** SVG `<pattern>` ids declared in `<defs>`. `missing` renders an X glyph instead of a pattern. */\nexport const CONDITION_PATTERNS: Record<ToothCondition, string> = {\n caries: 'tooth-scheme-pattern-diagonal',\n filled: 'tooth-scheme-pattern-dots',\n crowned: 'tooth-scheme-pattern-crosshatch',\n missing: 'tooth-scheme-pattern-blank',\n implant: 'tooth-scheme-pattern-vertical',\n rootCanal: 'tooth-scheme-pattern-horizontal',\n};\n\n/* ------------------------------------------------------------------ */\n/* SVG shape paths — one per anatomy class */\n/* */\n/* Artistry is deliberately minimal for this first pass: each tooth is */\n/* a rounded rectangle with a small anatomy cue (cusp notch for */\n/* molars, pointed tip for canines, narrower body for incisors). The */\n/* shapes accept a `translate(x, y)` on the enclosing `<g>` and draw */\n/* within a 30×50 bounding box (22×50 for incisors). */\n/* ------------------------------------------------------------------ */\n\nexport interface ToothShape {\n /** Visual width inside the enclosing `<g>`. */\n width: number;\n /** Visual height inside the enclosing `<g>`. */\n height: number;\n /** SVG `d` attribute for the crown outline. */\n path: string;\n /** Optional inner decorative path (occlusal surface on molars, etc.). */\n innerPath?: string;\n}\n\nexport const TOOTH_SHAPES: Record<Anatomy, ToothShape> = {\n incisor: {\n width: 22,\n height: 50,\n // Narrow rounded rectangle — slightly wider at the occlusal/biting edge.\n path: 'M4 4 C4 2 6 0 8 0 L14 0 C16 0 18 2 18 4 L20 44 C20 47 18 50 14 50 L8 50 C4 50 2 47 2 44 Z',\n },\n canine: {\n width: 26,\n height: 50,\n // Pointed cusp at the bottom — canines present a single prominent cusp.\n path: 'M4 4 C4 2 6 0 8 0 L18 0 C20 0 22 2 22 4 L24 40 L13 50 L2 40 Z',\n },\n premolar: {\n width: 28,\n height: 50,\n // Wider rounded rectangle with a subtle horizontal notch hinting at two cusps.\n path: 'M4 4 C4 2 6 0 8 0 L20 0 C22 0 24 2 24 4 L26 44 C26 47 24 50 20 50 L8 50 C4 50 2 47 2 44 Z',\n innerPath: 'M6 34 L22 34',\n },\n molar: {\n width: 32,\n height: 50,\n // Widest rounded rectangle with a cross-notch hinting at the occlusal fissure pattern.\n path: 'M4 4 C4 2 6 0 8 0 L24 0 C26 0 28 2 28 4 L30 44 C30 47 28 50 24 50 L8 50 C4 50 2 47 2 44 Z',\n innerPath: 'M6 32 L26 32 M16 22 L16 42',\n },\n};\n\n/* ------------------------------------------------------------------ */\n/* Viewport layout helpers */\n/* ------------------------------------------------------------------ */\n\nexport const TOOTH_GAP = 4;\nexport const TOOTH_ROW_GAP = 24;\nexport const TOOTH_HIT_PAD = 4;\n\nexport interface PositionedTooth {\n fdi: FdiId;\n meta: ToothMeta;\n shape: ToothShape;\n x: number;\n y: number;\n}\n\n/**\n * Produce the positioned list of teeth for a given dentition. The layout\n * is a two-row grid reading viewer-left-to-right across the upper arch,\n * then viewer-left-to-right across the lower arch. Clinical convention\n * is preserved: the patient's right sits on the viewer's left in both\n * arches, regardless of document direction.\n */\nexport function layoutTeeth(dentition: Dentition): {\n teeth: PositionedTooth[];\n width: number;\n height: number;\n} {\n const ids: FdiId[] =\n dentition === 'primary'\n ? PRIMARY_TEETH\n : dentition === 'mixed'\n ? [...PERMANENT_TEETH, ...PRIMARY_TEETH]\n : PERMANENT_TEETH;\n\n // Upper / lower partition is inferred from meta.arch.\n const upper: FdiId[] = [];\n const lower: FdiId[] = [];\n for (const id of ids) {\n const meta = FDI_TO_META[id];\n if (meta.arch === 'upper') upper.push(id);\n else lower.push(id);\n }\n\n const rowHeight = 50;\n const maxPerRow = Math.max(upper.length, lower.length);\n\n // Centre each row on the widest one.\n function positionRow(row: FdiId[], yOffset: number): PositionedTooth[] {\n const rowWidth = row.reduce((acc, id) => {\n const shape = TOOTH_SHAPES[FDI_TO_META[id].anatomy];\n return acc + shape.width + TOOTH_GAP;\n }, 0);\n const fullRowWidth = row.length > 0 ? rowWidth - TOOTH_GAP : 0;\n\n const maxRowWidth = (function computeMax(): number {\n const bigger = upper.length >= lower.length ? upper : lower;\n const biggerWidth = bigger.reduce((acc, id) => {\n const shape = TOOTH_SHAPES[FDI_TO_META[id].anatomy];\n return acc + shape.width + TOOTH_GAP;\n }, 0);\n return biggerWidth - TOOTH_GAP;\n })();\n\n const startX = (maxRowWidth - fullRowWidth) / 2;\n let cursor = startX;\n return row.map((id) => {\n const meta = FDI_TO_META[id];\n const shape = TOOTH_SHAPES[meta.anatomy];\n const tooth: PositionedTooth = {\n fdi: id,\n meta,\n shape,\n x: cursor,\n y: yOffset,\n };\n cursor += shape.width + TOOTH_GAP;\n return tooth;\n });\n }\n\n const upperRow = positionRow(upper, 0);\n const lowerRow = positionRow(lower, rowHeight + TOOTH_ROW_GAP);\n\n // Compute the true content width / height for the viewBox.\n const maxRowWidth = Math.max(\n upperRow.reduce((acc, t) => Math.max(acc, t.x + t.shape.width), 0),\n lowerRow.reduce((acc, t) => Math.max(acc, t.x + t.shape.width), 0),\n );\n\n // Fall back to a reasonable default if a row is empty.\n const width = maxRowWidth > 0 ? maxRowWidth : maxPerRow * 30;\n const height = rowHeight * 2 + TOOTH_ROW_GAP;\n\n return { teeth: [...upperRow, ...lowerRow], width, height };\n}\n\n/* ------------------------------------------------------------------ */\n/* Labels by numbering */\n/* ------------------------------------------------------------------ */\n\nexport function labelFor(id: FdiId, numbering: Numbering): string {\n switch (numbering) {\n case 'universal':\n return FDI_TO_UNIVERSAL[id] ?? id;\n case 'palmer':\n return FDI_TO_PALMER[id] ?? id;\n case 'fdi':\n default:\n return id;\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Chart helpers */\n/* ------------------------------------------------------------------ */\n\nexport function emptyChart(): ToothChart {\n return {};\n}\n\nexport function chartFromConditions(\n conditions: Partial<Record<FdiId, ToothCondition[]>>,\n): ToothChart {\n const chart: ToothChart = {};\n for (const [id, list] of Object.entries(conditions)) {\n if (!list || list.length === 0) continue;\n chart[id] = { conditions: list, surfaces: [] };\n }\n return chart;\n}\n","/* ------------------------------------------------------------------ */\n/* ToothScheme — in-house SVG dental chart. */\n/* */\n/* - The ONLY Domain-Specific component without a third-party engine. */\n/* No DentalChart.js, no toothchart, no canvas — `src/docs/08-third- */\n/* party.mdx §Dental chart` flags every candidate as rejected (jQuery */\n/* dependency, abandoned, poor a11y), so we draw SVG ourselves. */\n/* */\n/* - Colour-not-alone: each `ToothCondition` has a translated label, a */\n/* token colour AND a `<pattern>` fill. Pattern ids live in */\n/* `CONDITION_PATTERNS`; the six `<pattern>` nodes live once per */\n/* mounted chart inside a single `<defs>` block. */\n/* */\n/* - Chart orientation is FIXED to clinical convention: the patient's */\n/* right side sits on the viewer's left in both upper and lower */\n/* arches, regardless of document `dir`. RTL mirrors the surrounding */\n/* chrome (labels, controls) but NEVER the anatomy — a mirrored */\n/* chart would invert every diagnosis recorded against it. */\n/* */\n/* TODO: */\n/* - SVG artistry is deliberately minimal (rounded-rect crowns with */\n/* anatomy cues). A future pass should replace each `<path>` with */\n/* a clinically-correct crown outline from the dental design team. */\n/* - Surface selection sub-control (mesial / distal / occlusal / …) */\n/* is stubbed via the data model only; the interactive surface */\n/* picker will land in a follow-up. */\n/* - Condition editing is a single-step cycle on Space/Enter — good */\n/* enough for demos and stories; a richer picker belongs in a */\n/* popover and will reuse Radix Popover when it's wired in. */\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n} from 'react';\nimport * as RadixTooltip from '@radix-ui/react-tooltip';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\n\nimport {\n CONDITION_COLORS,\n CONDITION_PATTERNS,\n CONDITION_TOKENS,\n FDI_TO_META,\n PERMANENT_TEETH,\n PRIMARY_TEETH,\n TOOTH_HIT_PAD,\n chartFromConditions,\n labelFor,\n layoutTeeth,\n type Dentition,\n type FdiId,\n type Numbering,\n type ToothChart,\n type ToothCondition,\n type ToothMode,\n type ToothState,\n} from './tooth-data';\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport interface ToothSchemeProps {\n /** Which teeth to render. Default `'permanent'`. */\n dentition?: Dentition;\n /** Numbering system shown on each tooth label. Default `'fdi'`. */\n numbering?: Numbering;\n /** `'interactive'` enables selection + keyboard nav; `'display'` is read-only. Default `'interactive'`. */\n mode?: ToothMode;\n /** Controlled chart state — the full `Record<FdiId, ToothState>`. */\n value?: ToothChart;\n /** Uncontrolled initial chart state. */\n defaultValue?: ToothChart;\n /** Fired whenever the chart changes — always emits FDI ids. */\n onChange?: (next: ToothChart) => void;\n /** Fired when a tooth is focused or clicked. */\n onSelect?: (toothId: FdiId) => void;\n /** Shortcut for pre-populating conditions: `{ '16': ['caries'], '36': ['filled'] }`. */\n conditions?: Partial<Record<FdiId, ToothCondition[]>>;\n /** Accessible label override for the chart region. */\n ariaLabel?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n}\n\nexport interface ToothSchemeHandle {\n /** Programmatically focus a tooth by FDI id. */\n focusTooth: (id: FdiId) => void;\n /** Read the current chart state. */\n getChart: () => ToothChart;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst rootVariants = cva(\n [\n 'ds:tooth-scheme-alfadocs',\n 'ds:inline-flex ds:flex-col',\n 'ds:gap-[var(--spacing-sm)]',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n ].join(' '),\n);\n\nconst svgVariants = cva(\n [\n 'ds:block ds:max-w-full ds:h-auto',\n 'ds:text-[var(--foreground)]',\n ].join(' '),\n);\n\n// `group` here is load-bearing — the focus-ring <rect> below uses\n// `group-focus-visible:opacity-100` to appear when the parent <g> takes\n// focus. Without this class the selector never fires and keyboard users\n// see no focus indicator (a11y-critical-fixes.mdx).\nconst toothGroupVariants = cva(\n [\n 'ds:group ds:cursor-pointer',\n 'ds:focus:outline-none',\n 'ds:transition-[fill,stroke,opacity] ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n ].join(' '),\n);\n\nconst legendVariants = cva(\n [\n 'ds:flex ds:flex-wrap ds:items-center',\n 'ds:gap-[var(--spacing-sm)]',\n 'type-meta ds:text-[var(--muted-foreground)]',\n ].join(' '),\n);\n\nconst legendItemVariants = cva(\n [\n 'ds:inline-flex ds:items-center',\n 'ds:gap-[var(--spacing-xs)]',\n ].join(' '),\n);\n\nconst legendSwatchVariants = cva(\n [\n 'ds:inline-block',\n 'ds:inline-size-[0.75rem] ds:block-size-[0.75rem]',\n 'ds:rounded-[var(--radius-xs)]',\n 'ds:border ds:border-[color:var(--border)]',\n ].join(' '),\n);\n\nconst liveRegionVariants = cva(\n [\n 'ds:sr-only',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nfunction isControlled(props: Pick<ToothSchemeProps, 'value'>): boolean {\n return props.value !== undefined;\n}\n\nfunction emptyState(): ToothState {\n return { conditions: [], surfaces: [] };\n}\n\nfunction cycleCondition(current: ToothCondition[] | undefined): ToothCondition[] {\n if (!current || current.length === 0) return ['caries'];\n return [];\n}\n\nfunction sanitiseIdSuffix(raw: string): string {\n return raw.replace(/[^a-zA-Z0-9-_]/g, '');\n}\n\n/* ------------------------------------------------------------------ */\n/* Patterns <defs> */\n/* ------------------------------------------------------------------ */\n\ninterface PatternDefsProps {\n idPrefix: string;\n}\n\nfunction PatternDefs({ idPrefix }: PatternDefsProps): JSX.Element {\n // We namespace pattern ids per-instance so multiple ToothScheme charts\n // on a page don't collide. References inside the component use\n // `${idPrefix}-${CONDITION_PATTERNS[condition]}`.\n const pid = (id: string): string => `${idPrefix}-${id}`;\n return (\n <defs>\n <pattern\n id={pid(CONDITION_PATTERNS.caries)}\n patternUnits=\"userSpaceOnUse\"\n width=\"6\"\n height=\"6\"\n patternTransform=\"rotate(45)\"\n >\n <line\n x1=\"0\"\n y1=\"0\"\n x2=\"0\"\n y2=\"6\"\n stroke={CONDITION_COLORS.caries}\n strokeWidth=\"2\"\n />\n </pattern>\n <pattern\n id={pid(CONDITION_PATTERNS.filled)}\n patternUnits=\"userSpaceOnUse\"\n width=\"5\"\n height=\"5\"\n >\n <circle cx=\"2.5\" cy=\"2.5\" r=\"1\" fill={CONDITION_COLORS.filled} />\n </pattern>\n <pattern\n id={pid(CONDITION_PATTERNS.crowned)}\n patternUnits=\"userSpaceOnUse\"\n width=\"6\"\n height=\"6\"\n >\n <path\n d=\"M0 0 L6 6 M6 0 L0 6\"\n stroke={CONDITION_COLORS.crowned}\n strokeWidth=\"1\"\n />\n </pattern>\n <pattern\n id={pid(CONDITION_PATTERNS.implant)}\n patternUnits=\"userSpaceOnUse\"\n width=\"4\"\n height=\"4\"\n >\n <line\n x1=\"1\"\n y1=\"0\"\n x2=\"1\"\n y2=\"4\"\n stroke={CONDITION_COLORS.implant}\n strokeWidth=\"1\"\n />\n </pattern>\n <pattern\n id={pid(CONDITION_PATTERNS.rootCanal)}\n patternUnits=\"userSpaceOnUse\"\n width=\"4\"\n height=\"4\"\n >\n <line\n x1=\"0\"\n y1=\"1\"\n x2=\"4\"\n y2=\"1\"\n stroke={CONDITION_COLORS.rootCanal}\n strokeWidth=\"1\"\n />\n </pattern>\n {/* `missing` does not need a pattern — the renderer draws an X glyph. */}\n </defs>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Legend */\n/* ------------------------------------------------------------------ */\n\nconst ALL_CONDITIONS: ToothCondition[] = [\n 'caries',\n 'filled',\n 'crowned',\n 'missing',\n 'implant',\n 'rootCanal',\n];\n\ninterface LegendProps {\n idPrefix: string;\n}\n\nfunction Legend({ idPrefix: _idPrefix }: LegendProps): JSX.Element {\n const { t } = useTranslation();\n return (\n <ul\n className={legendVariants()}\n data-testid=\"tooth-scheme-legend\"\n aria-label={t('toothScheme.legendLabel')}\n >\n {ALL_CONDITIONS.map((condition) => (\n <li key={condition} className={legendItemVariants()}>\n <span\n className={legendSwatchVariants()}\n aria-hidden=\"true\"\n data-condition={condition}\n data-token={CONDITION_TOKENS[condition]}\n data-testid={`tooth-scheme-legend-swatch-${condition}`}\n />\n <span>{t(`toothScheme.condition.${condition}`)}</span>\n </li>\n ))}\n </ul>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport const ToothScheme = forwardRef<ToothSchemeHandle, ToothSchemeProps>(\n (\n {\n dentition = 'permanent',\n numbering = 'fdi',\n mode = 'interactive',\n value,\n defaultValue,\n onChange,\n onSelect,\n conditions,\n ariaLabel,\n className,\n },\n ref,\n ) => {\n const { t } = useTranslation();\n\n const rawId = useId();\n const idPrefix = useMemo(\n () => `ts-${sanitiseIdSuffix(rawId)}`,\n [rawId],\n );\n\n // Chart state — controlled / uncontrolled.\n const [internalChart, setInternalChart] = useState<ToothChart>(() => {\n if (value !== undefined) return value;\n if (defaultValue !== undefined) return defaultValue;\n if (conditions) return chartFromConditions(conditions);\n return {};\n });\n\n const chart: ToothChart = isControlled({ value }) ? (value as ToothChart) : internalChart;\n\n // Keep uncontrolled chart in sync when `conditions` shortcut updates.\n useEffect(() => {\n if (isControlled({ value })) return;\n if (conditions === undefined) return;\n setInternalChart(chartFromConditions(conditions));\n // Intentionally depend on a stable key — swapping the entire prop\n // snapshot is the consumer's signal to reset.\n }, [conditions, value]);\n\n // Layout.\n const layout = useMemo(() => layoutTeeth(dentition), [dentition]);\n const visibleIds = useMemo(\n () => layout.teeth.map((t) => t.fdi),\n [layout],\n );\n\n // Roving tabindex: which tooth owns `tabindex=\"0\"`.\n const firstId: FdiId | undefined = visibleIds[0];\n const [focusedId, setFocusedId] = useState<FdiId | undefined>(firstId);\n useEffect(() => {\n if (!focusedId || !visibleIds.includes(focusedId)) {\n setFocusedId(firstId);\n }\n }, [firstId, focusedId, visibleIds]);\n\n // Live-region announcement text.\n const [announcement, setAnnouncement] = useState<string>('');\n\n const svgRef = useRef<SVGSVGElement>(null);\n\n const commitChart = useCallback(\n (next: ToothChart) => {\n if (!isControlled({ value })) {\n setInternalChart(next);\n }\n onChange?.(next);\n },\n [onChange, value],\n );\n\n const focusToothById = useCallback((id: FdiId) => {\n const svg = svgRef.current;\n if (!svg) return;\n const node = svg.querySelector<SVGGElement>(`g[data-fdi=\"${id}\"]`);\n if (node) {\n node.focus();\n setFocusedId(id);\n }\n }, []);\n\n useImperativeHandle(\n ref,\n (): ToothSchemeHandle => ({\n focusTooth: (id: FdiId) => {\n focusToothById(id);\n },\n getChart: () => chart,\n }),\n [chart, focusToothById],\n );\n\n /* ------------------------------------------------------------- */\n /* Keyboard navigation */\n /* ------------------------------------------------------------- */\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<SVGGElement>, id: FdiId) => {\n if (mode !== 'interactive') return;\n const meta = FDI_TO_META[id];\n if (!meta) return;\n\n // Resolve the ordered list of visible ids for Left/Right.\n const order = visibleIds;\n const currentIndex = order.indexOf(id);\n\n switch (event.key) {\n case 'ArrowRight': {\n event.preventDefault();\n const nextIndex = Math.min(order.length - 1, currentIndex + 1);\n focusToothById(order[nextIndex]);\n return;\n }\n case 'ArrowLeft': {\n event.preventDefault();\n const nextIndex = Math.max(0, currentIndex - 1);\n focusToothById(order[nextIndex]);\n return;\n }\n case 'ArrowUp':\n case 'ArrowDown': {\n event.preventDefault();\n // Map to the opposing arch, same FDI position where possible.\n // Permanent: 1 ↔ 4, 2 ↔ 3. Primary: 5 ↔ 8, 6 ↔ 7.\n const quadrantMap: Record<number, number> = {\n 1: 4,\n 4: 1,\n 2: 3,\n 3: 2,\n 5: 8,\n 8: 5,\n 6: 7,\n 7: 6,\n };\n const targetQuadrant = quadrantMap[meta.quadrant];\n if (!targetQuadrant) return;\n const candidate = `${targetQuadrant}${meta.positionInQuadrant}`;\n if (order.includes(candidate)) {\n focusToothById(candidate);\n }\n return;\n }\n case 'Home': {\n event.preventDefault();\n // First tooth in the same quadrant (visible).\n const inQuadrant = order.filter(\n (other) => FDI_TO_META[other].quadrant === meta.quadrant,\n );\n if (inQuadrant.length > 0) {\n focusToothById(inQuadrant[0]);\n }\n return;\n }\n case 'End': {\n event.preventDefault();\n const inQuadrant = order.filter(\n (other) => FDI_TO_META[other].quadrant === meta.quadrant,\n );\n if (inQuadrant.length > 0) {\n focusToothById(inQuadrant[inQuadrant.length - 1]);\n }\n return;\n }\n case ' ':\n case 'Enter': {\n event.preventDefault();\n const prev = chart[id]?.conditions;\n const nextConditions = cycleCondition(prev);\n const next: ToothChart = { ...chart };\n if (nextConditions.length === 0) {\n delete next[id];\n setAnnouncement(t('toothScheme.deselected', { id }));\n } else {\n next[id] = {\n ...(chart[id] ?? emptyState()),\n conditions: nextConditions,\n };\n setAnnouncement(\n t('toothScheme.selected', {\n id,\n conditions: nextConditions\n .map((c) => t(`toothScheme.condition.${c}`))\n .join(', '),\n }),\n );\n }\n commitChart(next);\n onSelect?.(id);\n return;\n }\n default:\n return;\n }\n },\n [chart, commitChart, focusToothById, mode, onSelect, t, visibleIds],\n );\n\n const handleClick = useCallback(\n (id: FdiId) => {\n if (mode !== 'interactive') return;\n setFocusedId(id);\n const prev = chart[id]?.conditions;\n const nextConditions = cycleCondition(prev);\n const next: ToothChart = { ...chart };\n if (nextConditions.length === 0) {\n delete next[id];\n setAnnouncement(t('toothScheme.deselected', { id }));\n } else {\n next[id] = {\n ...(chart[id] ?? emptyState()),\n conditions: nextConditions,\n };\n setAnnouncement(\n t('toothScheme.selected', {\n id,\n conditions: nextConditions\n .map((c) => t(`toothScheme.condition.${c}`))\n .join(', '),\n }),\n );\n }\n commitChart(next);\n onSelect?.(id);\n },\n [chart, commitChart, mode, onSelect, t],\n );\n\n /* ------------------------------------------------------------- */\n /* Rendering */\n /* ------------------------------------------------------------- */\n\n const viewBoxWidth = layout.width + 4; // small padding for stroke\n const viewBoxHeight = layout.height + 4;\n\n const regionLabel = ariaLabel ?? t('toothScheme.ariaLabel');\n\n return (\n <RadixTooltip.Provider delayDuration={200}>\n <div\n role=\"region\"\n aria-label={regionLabel}\n className={[rootVariants(), className].filter(Boolean).join(' ')}\n data-component=\"tooth-scheme\"\n data-testid=\"tooth-scheme-root\"\n data-dentition={dentition}\n data-numbering={numbering}\n data-mode={mode}\n >\n <svg\n ref={svgRef}\n viewBox={`0 0 ${viewBoxWidth} ${viewBoxHeight}`}\n className={svgVariants()}\n role=\"group\"\n aria-label={regionLabel}\n data-testid=\"tooth-scheme-svg\"\n focusable=\"false\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <PatternDefs idPrefix={idPrefix} />\n\n {layout.teeth.map((tooth) => {\n const state = chart[tooth.fdi];\n const primaryCondition: ToothCondition | undefined =\n state?.conditions?.[0];\n\n const anatomyLabel = t(\n `toothScheme.anatomy.${tooth.meta.anatomy}`,\n );\n const conditionSuffix = primaryCondition\n ? `, ${t(`toothScheme.condition.${primaryCondition}`)}`\n : '';\n const label = t('toothScheme.toothLabel', {\n id: labelFor(tooth.fdi, numbering),\n anatomy: anatomyLabel,\n conditionSuffix,\n });\n\n const tabIndex =\n mode === 'interactive'\n ? tooth.fdi === focusedId\n ? 0\n : -1\n : undefined;\n\n const fillColour: string =\n primaryCondition && primaryCondition !== 'missing'\n ? `url(#${idPrefix}-${CONDITION_PATTERNS[primaryCondition]})`\n : 'var(--muted)';\n\n const strokeColour: string =\n primaryCondition && primaryCondition !== 'missing'\n ? CONDITION_COLORS[primaryCondition]\n : 'var(--border)';\n\n const tooltipContent = primaryCondition\n ? `${anatomyLabel} · ${t(`toothScheme.condition.${primaryCondition}`)}`\n : anatomyLabel;\n\n const labelText = labelFor(tooth.fdi, numbering);\n\n return (\n <RadixTooltip.Root key={tooth.fdi}>\n <RadixTooltip.Trigger asChild>\n <g\n data-fdi={tooth.fdi}\n data-anatomy={tooth.meta.anatomy}\n data-arch={tooth.meta.arch}\n data-side={tooth.meta.side}\n data-quadrant={tooth.meta.quadrant}\n data-condition={primaryCondition ?? 'none'}\n data-testid={`tooth-${tooth.fdi}`}\n transform={`translate(${tooth.x}, ${tooth.y})`}\n tabIndex={tabIndex}\n role={mode === 'interactive' ? 'button' : undefined}\n aria-label={label}\n aria-pressed={\n mode === 'interactive'\n ? (primaryCondition !== undefined)\n : undefined\n }\n className={toothGroupVariants()}\n onClick={\n mode === 'interactive'\n ? () => handleClick(tooth.fdi)\n : undefined\n }\n onFocus={() => setFocusedId(tooth.fdi)}\n onKeyDown={(event) => handleKeyDown(event, tooth.fdi)}\n >\n {/* Invisible ≥44px hit target (WCAG 2.5.5). */}\n <rect\n x={-TOOTH_HIT_PAD}\n y={-TOOTH_HIT_PAD}\n width={tooth.shape.width + TOOTH_HIT_PAD * 2}\n height={tooth.shape.height + TOOTH_HIT_PAD * 2}\n fill=\"transparent\"\n />\n {/* Crown outline. */}\n <path\n d={tooth.shape.path}\n fill={fillColour}\n stroke={strokeColour}\n strokeWidth=\"1.5\"\n vectorEffect=\"non-scaling-stroke\"\n />\n {tooth.shape.innerPath ? (\n <path\n d={tooth.shape.innerPath}\n fill=\"none\"\n stroke=\"var(--muted-foreground)\"\n strokeWidth=\"0.75\"\n vectorEffect=\"non-scaling-stroke\"\n />\n ) : null}\n {/* Focus ring — drawn as a rect so it tracks the hit\n area. `group` on the parent <g> makes this\n group-focus-visible selector fire when a keyboard\n user focuses the tooth. In forced-colors mode the\n ring falls back to `CanvasText` so it stays visible\n when `var(--ring)` is remapped. */}\n <rect\n x={-TOOTH_HIT_PAD}\n y={-TOOTH_HIT_PAD}\n width={tooth.shape.width + TOOTH_HIT_PAD * 2}\n height={tooth.shape.height + TOOTH_HIT_PAD * 2}\n fill=\"none\"\n stroke=\"var(--ring)\"\n strokeWidth=\"var(--focus-ring-width)\"\n className={[\n 'ds:opacity-0',\n 'ds:group-focus-visible:opacity-100',\n 'ds:forced-colors:stroke-[CanvasText]',\n ].join(' ')}\n data-testid={`tooth-${tooth.fdi}-focus-ring`}\n pointerEvents=\"none\"\n rx=\"4\"\n />\n {/* Missing-tooth X glyph. */}\n {primaryCondition === 'missing' ? (\n <path\n d={`M2 2 L${tooth.shape.width - 2} ${tooth.shape.height - 2} M${tooth.shape.width - 2} 2 L2 ${tooth.shape.height - 2}`}\n stroke={CONDITION_COLORS.missing}\n strokeWidth=\"2\"\n fill=\"none\"\n />\n ) : null}\n {/* Tooth number label — sits below (upper arch) or above (lower) the crown. */}\n <text\n x={tooth.shape.width / 2}\n y={\n tooth.meta.arch === 'upper'\n ? tooth.shape.height + 12\n : -4\n }\n textAnchor=\"middle\"\n fontSize=\"10\"\n fill=\"var(--muted-foreground)\"\n className=\"ds:select-none\"\n aria-hidden=\"true\"\n >\n {labelText}\n </text>\n </g>\n </RadixTooltip.Trigger>\n <RadixTooltip.Portal>\n <RadixTooltip.Content\n side=\"top\"\n sideOffset={6}\n className=\"ds:z-[var(--z-tooltip)] ds:rounded-[var(--radius-sm)] ds:bg-[var(--foreground)] ds:text-[var(--background)] ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)] ds:pt-[calc(var(--spacing-xs)/2)] ds:pb-[calc(var(--spacing-xs)/2)] ds:text-[var(--font-size-xs)]\"\n >\n {tooltipContent}\n <RadixTooltip.Arrow className=\"ds:fill-[var(--foreground)]\" />\n </RadixTooltip.Content>\n </RadixTooltip.Portal>\n </RadixTooltip.Root>\n );\n })}\n </svg>\n\n <Legend idPrefix={idPrefix} />\n\n <div\n className={liveRegionVariants()}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n data-testid=\"tooth-scheme-live\"\n >\n {announcement}\n </div>\n </div>\n </RadixTooltip.Provider>\n );\n },\n);\n\nToothScheme.displayName = 'ToothScheme';\n\n/* ------------------------------------------------------------------ */\n/* Re-exports */\n/* ------------------------------------------------------------------ */\n\nexport {\n rootVariants as toothSchemeVariants,\n PERMANENT_TEETH,\n PRIMARY_TEETH,\n};\nexport type {\n Dentition,\n FdiId,\n Numbering,\n ToothChart,\n ToothCondition,\n ToothMode,\n ToothState,\n} from './tooth-data';\n","import type { AgentAdapter } from '../../agent/types';\nimport type { ToothSchemeHandle } from './tooth-scheme';\n\nexport const toothSchemeAgent: AgentAdapter<ToothSchemeHandle> = {\n id: 'tooth-scheme',\n capabilities: ['pick'],\n state: {\n chart: {\n type: 'object',\n description: 'Current dental chart state — tooth conditions keyed by FDI id.',\n read: (handle) => handle.getChart(),\n },\n },\n actions: {\n focus_tooth: {\n safety: 'read',\n argsType: '{ id: FdiId }',\n description: 'Move focus to a specific tooth by FDI id.',\n invoke: (handle, args: { id: Parameters<ToothSchemeHandle['focusTooth']>[0] }) => {\n handle.focusTooth(args.id);\n },\n },\n },\n domHooks: {\n root: { attr: 'data-component', value: 'tooth-scheme' },\n item: {\n attr: 'data-fdi',\n description: 'Each rendered tooth `<g>` carries its FDI id as `data-fdi`. Tests still use `data-testid=\"tooth-<fdi>\"` separately.',\n },\n },\n};\n"],"names":["PERMANENT_TEETH","PRIMARY_TEETH","permanentAnatomy","positionInQuadrant","primaryAnatomy","palmerCode","quadrant","position","normalised","permanentUniversal","primaryUniversal","letters","index","buildMeta","fdi","isPrimary","anatomy","arch","side","universal","palmer","FDI_TO_META","acc","FDI_TO_UNIVERSAL","meta","FDI_TO_PALMER","CONDITION_TOKENS","CONDITION_COLORS","CONDITION_PATTERNS","TOOTH_SHAPES","TOOTH_GAP","TOOTH_ROW_GAP","TOOTH_HIT_PAD","layoutTeeth","dentition","ids","upper","lower","id","rowHeight","maxPerRow","positionRow","row","yOffset","rowWidth","shape","fullRowWidth","cursor","tooth","upperRow","lowerRow","maxRowWidth","t","width","height","labelFor","numbering","emptyChart","chartFromConditions","conditions","chart","list","rootVariants","cva","svgVariants","toothGroupVariants","legendVariants","legendItemVariants","legendSwatchVariants","liveRegionVariants","isControlled","props","emptyState","cycleCondition","current","sanitiseIdSuffix","raw","PatternDefs","idPrefix","pid","jsx","ALL_CONDITIONS","Legend","_idPrefix","useTranslation","condition","ToothScheme","forwardRef","mode","value","defaultValue","onChange","onSelect","ariaLabel","className","ref","rawId","useId","useMemo","internalChart","setInternalChart","useState","useEffect","layout","visibleIds","firstId","focusedId","setFocusedId","announcement","setAnnouncement","svgRef","useRef","commitChart","useCallback","next","focusToothById","svg","node","useImperativeHandle","handleKeyDown","event","order","currentIndex","nextIndex","targetQuadrant","candidate","inQuadrant","other","prev","_a","nextConditions","c","handleClick","viewBoxWidth","viewBoxHeight","regionLabel","RadixTooltip","jsxs","state","primaryCondition","anatomyLabel","conditionSuffix","label","tabIndex","fillColour","strokeColour","tooltipContent","labelText","toothSchemeAgent","handle","args"],"mappings":"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"}
1
+ {"version":3,"file":"tooth-scheme.agent-BlDyu-Gx.js","sources":["../../src/components/tooth-scheme/tooth-data.ts","../../src/components/tooth-scheme/tooth-scheme.tsx","../../src/components/tooth-scheme/tooth-scheme.agent.ts"],"sourcesContent":["/* ------------------------------------------------------------------ */\n/* ToothScheme — data model + lookup tables. */\n/* */\n/* FDI ISO 3950 is the canonical internal id. This module exposes */\n/* conversion tables to Universal (ADA) and a simplified Palmer-style */\n/* quadrant+position string so consuming UIs can toggle numbering. */\n/* */\n/* Why simplified Palmer? True Palmer notation uses quadrant bracket */\n/* glyphs (\"⌐\", \"¬\", \"L\", \"J\") that do not render reliably in every */\n/* browser/font combination. We emit a readable `UR3` / `LL6` form */\n/* instead and document the deviation in the component MDX. */\n/* ------------------------------------------------------------------ */\n\n/* ------------------------------------------------------------------ */\n/* Core types */\n/* ------------------------------------------------------------------ */\n\nexport type FdiId = string; // '11'–'48' permanent, '51'–'85' primary\n\nexport type Dentition = 'permanent' | 'primary' | 'mixed';\nexport type Numbering = 'fdi' | 'universal' | 'palmer';\nexport type ToothMode = 'interactive' | 'display';\nexport type Surface = 'mesial' | 'distal' | 'occlusal' | 'buccal' | 'lingual';\nexport type ToothCondition =\n | 'caries'\n | 'filled'\n | 'crowned'\n | 'missing'\n | 'implant'\n | 'rootCanal';\n\nexport interface ToothState {\n conditions: ToothCondition[];\n surfaces: Surface[];\n notes?: string;\n}\n\nexport type ToothChart = Record<FdiId, ToothState>;\n\nexport type Anatomy = 'incisor' | 'canine' | 'premolar' | 'molar';\nexport type Arch = 'upper' | 'lower';\nexport type Side = 'right' | 'left'; // patient's side (NOT viewer's)\nexport type Quadrant = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;\n\nexport interface ToothMeta {\n fdi: FdiId;\n /** '1'–'32' for permanent, 'A'–'T' for primary. */\n universal: string;\n /** Simplified Palmer quadrant-and-position string, e.g. 'UR3', 'LL6'. */\n palmer: string;\n quadrant: Quadrant;\n /** 1–8 (permanent) or 1–5 (primary), counted from the midline outward. */\n positionInQuadrant: number;\n anatomy: Anatomy;\n arch: Arch;\n side: Side;\n dentition: 'permanent' | 'primary';\n}\n\n/* ------------------------------------------------------------------ */\n/* Layout orders */\n/* */\n/* Layout reads from the viewer's perspective, top-left to bottom- */\n/* right. The chart is FIXED in clinical convention: the patient's */\n/* right side sits on the viewer's left, regardless of document `dir`. */\n/* ------------------------------------------------------------------ */\n\n/**\n * 32 permanent teeth in visual layout order:\n * upper row: 18..11 (patient upper-right, outermost → midline), then 21..28 (upper-left, midline → outermost)\n * lower row: 48..41 (patient lower-right, outermost → midline), then 31..38 (lower-left, midline → outermost)\n */\nexport const PERMANENT_TEETH: FdiId[] = [\n // upper\n '18', '17', '16', '15', '14', '13', '12', '11',\n '21', '22', '23', '24', '25', '26', '27', '28',\n // lower\n '48', '47', '46', '45', '44', '43', '42', '41',\n '31', '32', '33', '34', '35', '36', '37', '38',\n];\n\n/**\n * 20 primary teeth in visual layout order:\n * upper row: 55..51 (upper-right outermost → midline), then 61..65\n * lower row: 85..81, then 71..75\n */\nexport const PRIMARY_TEETH: FdiId[] = [\n // upper\n '55', '54', '53', '52', '51',\n '61', '62', '63', '64', '65',\n // lower\n '85', '84', '83', '82', '81',\n '71', '72', '73', '74', '75',\n];\n\n/* ------------------------------------------------------------------ */\n/* Anatomy by position */\n/* ------------------------------------------------------------------ */\n\nfunction permanentAnatomy(positionInQuadrant: number): Anatomy {\n if (positionInQuadrant <= 2) return 'incisor';\n if (positionInQuadrant === 3) return 'canine';\n if (positionInQuadrant <= 5) return 'premolar';\n return 'molar';\n}\n\nfunction primaryAnatomy(positionInQuadrant: number): Anatomy {\n if (positionInQuadrant <= 2) return 'incisor';\n if (positionInQuadrant === 3) return 'canine';\n // Primary dentition has no premolars — positions 4 & 5 are molars.\n return 'molar';\n}\n\n/* ------------------------------------------------------------------ */\n/* Palmer helper */\n/* ------------------------------------------------------------------ */\n\nfunction palmerCode(quadrant: Quadrant, position: number): string {\n // Permanent: 1=UR, 2=UL, 3=LL, 4=LR. Primary: 5=UR, 6=UL, 7=LL, 8=LR.\n // Mapping is identical within each dentition ring; the number is what\n // changes, so we fold 5→1, 6→2, 7→3, 8→4 to derive the quadrant code.\n const normalised = ((quadrant - 1) % 4) + 1;\n const code =\n normalised === 1 ? 'UR'\n : normalised === 2 ? 'UL'\n : normalised === 3 ? 'LL'\n : 'LR';\n return `${code}${position}`;\n}\n\n/* ------------------------------------------------------------------ */\n/* Universal (ADA) conversion */\n/* */\n/* Permanent — Universal numbers 1..32 run clockwise from the */\n/* patient's upper-right 3rd molar (FDI 18 = Universal 1), across */\n/* the upper arch (18→11 = 1→8, 21→28 = 9→16), then down the left */\n/* lower arch (38→31 = 17→24) and across the right lower (41→48 = */\n/* 25→32). */\n/* */\n/* Primary — Universal letters A..T walk the same path: */\n/* 55→51 = A→E, 61→65 = F→J, 75→71 = K→O, 81→85 = P→T. */\n/* ------------------------------------------------------------------ */\n\nfunction permanentUniversal(quadrant: Quadrant, position: number): string {\n switch (quadrant) {\n case 1:\n // 18→1, 17→2, …, 11→8\n return String(1 + (8 - position));\n case 2:\n // 21→9, 22→10, …, 28→16\n return String(8 + position);\n case 3:\n // 38→17, 37→18, …, 31→24\n return String(17 + (8 - position));\n case 4:\n // 41→25, 42→26, …, 48→32\n return String(24 + position);\n default:\n return '';\n }\n}\n\nfunction primaryUniversal(quadrant: Quadrant, position: number): string {\n const letters = 'ABCDEFGHIJKLMNOPQRST';\n let index = -1;\n switch (quadrant) {\n case 5:\n // 55→A, 54→B, 53→C, 52→D, 51→E\n index = 0 + (5 - position);\n break;\n case 6:\n // 61→F, 62→G, 63→H, 64→I, 65→J\n index = 5 + (position - 1);\n break;\n case 7:\n // 75→K, 74→L, 73→M, 72→N, 71→O\n index = 10 + (5 - position);\n break;\n case 8:\n // 81→P, 82→Q, 83→R, 84→S, 85→T\n index = 15 + (position - 1);\n break;\n default:\n index = -1;\n }\n return index >= 0 ? letters[index] : '';\n}\n\n/* ------------------------------------------------------------------ */\n/* Meta builder */\n/* ------------------------------------------------------------------ */\n\nfunction buildMeta(fdi: FdiId): ToothMeta {\n const quadrant = Number(fdi[0]) as Quadrant;\n const position = Number(fdi[1]);\n const isPrimary = quadrant >= 5;\n const anatomy = isPrimary ? primaryAnatomy(position) : permanentAnatomy(position);\n const arch: Arch = quadrant === 1 || quadrant === 2 || quadrant === 5 || quadrant === 6 ? 'upper' : 'lower';\n const side: Side = quadrant === 1 || quadrant === 4 || quadrant === 5 || quadrant === 8 ? 'right' : 'left';\n const universal = isPrimary ? primaryUniversal(quadrant, position) : permanentUniversal(quadrant, position);\n const palmer = palmerCode(quadrant, position);\n return {\n fdi,\n universal,\n palmer,\n quadrant,\n positionInQuadrant: position,\n anatomy,\n arch,\n side,\n dentition: isPrimary ? 'primary' : 'permanent',\n };\n}\n\nexport const FDI_TO_META: Record<FdiId, ToothMeta> = [\n ...PERMANENT_TEETH,\n ...PRIMARY_TEETH,\n].reduce<Record<FdiId, ToothMeta>>((acc, fdi) => {\n acc[fdi] = buildMeta(fdi);\n return acc;\n}, {});\n\nexport const FDI_TO_UNIVERSAL: Record<FdiId, string> = Object.fromEntries(\n Object.entries(FDI_TO_META).map(([fdi, meta]) => [fdi, meta.universal]),\n);\n\nexport const FDI_TO_PALMER: Record<FdiId, string> = Object.fromEntries(\n Object.entries(FDI_TO_META).map(([fdi, meta]) => [fdi, meta.palmer]),\n);\n\n/* ------------------------------------------------------------------ */\n/* Condition → token + pattern */\n/* */\n/* Every condition carries BOTH a colour AND a fill pattern so */\n/* colour-blind clinicians can distinguish states in the SVG (and in */\n/* black-and-white prints) — colour is never the sole channel. */\n/* ------------------------------------------------------------------ */\n\n/** CSS variable name (without the leading `var(...)`) that drives a condition's colour. */\nexport const CONDITION_TOKENS: Record<ToothCondition, string> = {\n caries: '--destructive',\n filled: '--info',\n crowned: '--warning',\n missing: '--muted-foreground',\n implant: '--accent',\n rootCanal: '--primary',\n};\n\n/**\n * Convenience: the `fill=\"var(--destructive)\"` string ready to paste onto\n * an SVG attribute. Kept in sync with `CONDITION_TOKENS`.\n */\nexport const CONDITION_COLORS: Record<ToothCondition, string> = {\n caries: 'var(--destructive)',\n filled: 'var(--info)',\n crowned: 'var(--warning)',\n missing: 'var(--muted-foreground)',\n implant: 'var(--accent)',\n rootCanal: 'var(--primary)',\n};\n\n/** SVG `<pattern>` ids declared in `<defs>`. `missing` renders an X glyph instead of a pattern. */\nexport const CONDITION_PATTERNS: Record<ToothCondition, string> = {\n caries: 'tooth-scheme-pattern-diagonal',\n filled: 'tooth-scheme-pattern-dots',\n crowned: 'tooth-scheme-pattern-crosshatch',\n missing: 'tooth-scheme-pattern-blank',\n implant: 'tooth-scheme-pattern-vertical',\n rootCanal: 'tooth-scheme-pattern-horizontal',\n};\n\n/* ------------------------------------------------------------------ */\n/* SVG shape paths — one per anatomy class */\n/* */\n/* Artistry is deliberately minimal for this first pass: each tooth is */\n/* a rounded rectangle with a small anatomy cue (cusp notch for */\n/* molars, pointed tip for canines, narrower body for incisors). The */\n/* shapes accept a `translate(x, y)` on the enclosing `<g>` and draw */\n/* within a 30×50 bounding box (22×50 for incisors). */\n/* ------------------------------------------------------------------ */\n\nexport interface ToothShape {\n /** Visual width inside the enclosing `<g>`. */\n width: number;\n /** Visual height inside the enclosing `<g>`. */\n height: number;\n /** SVG `d` attribute for the crown outline. */\n path: string;\n /** Optional inner decorative path (occlusal surface on molars, etc.). */\n innerPath?: string;\n}\n\nexport const TOOTH_SHAPES: Record<Anatomy, ToothShape> = {\n incisor: {\n width: 22,\n height: 50,\n // Narrow rounded rectangle — slightly wider at the occlusal/biting edge.\n path: 'M4 4 C4 2 6 0 8 0 L14 0 C16 0 18 2 18 4 L20 44 C20 47 18 50 14 50 L8 50 C4 50 2 47 2 44 Z',\n },\n canine: {\n width: 26,\n height: 50,\n // Pointed cusp at the bottom — canines present a single prominent cusp.\n path: 'M4 4 C4 2 6 0 8 0 L18 0 C20 0 22 2 22 4 L24 40 L13 50 L2 40 Z',\n },\n premolar: {\n width: 28,\n height: 50,\n // Wider rounded rectangle with a subtle horizontal notch hinting at two cusps.\n path: 'M4 4 C4 2 6 0 8 0 L20 0 C22 0 24 2 24 4 L26 44 C26 47 24 50 20 50 L8 50 C4 50 2 47 2 44 Z',\n innerPath: 'M6 34 L22 34',\n },\n molar: {\n width: 32,\n height: 50,\n // Widest rounded rectangle with a cross-notch hinting at the occlusal fissure pattern.\n path: 'M4 4 C4 2 6 0 8 0 L24 0 C26 0 28 2 28 4 L30 44 C30 47 28 50 24 50 L8 50 C4 50 2 47 2 44 Z',\n innerPath: 'M6 32 L26 32 M16 22 L16 42',\n },\n};\n\n/* ------------------------------------------------------------------ */\n/* Viewport layout helpers */\n/* ------------------------------------------------------------------ */\n\nexport const TOOTH_GAP = 4;\nexport const TOOTH_ROW_GAP = 24;\nexport const TOOTH_HIT_PAD = 4;\n\nexport interface PositionedTooth {\n fdi: FdiId;\n meta: ToothMeta;\n shape: ToothShape;\n x: number;\n y: number;\n}\n\n/**\n * Produce the positioned list of teeth for a given dentition. The layout\n * is a two-row grid reading viewer-left-to-right across the upper arch,\n * then viewer-left-to-right across the lower arch. Clinical convention\n * is preserved: the patient's right sits on the viewer's left in both\n * arches, regardless of document direction.\n */\nexport function layoutTeeth(dentition: Dentition): {\n teeth: PositionedTooth[];\n width: number;\n height: number;\n} {\n const ids: FdiId[] =\n dentition === 'primary'\n ? PRIMARY_TEETH\n : dentition === 'mixed'\n ? [...PERMANENT_TEETH, ...PRIMARY_TEETH]\n : PERMANENT_TEETH;\n\n // Upper / lower partition is inferred from meta.arch.\n const upper: FdiId[] = [];\n const lower: FdiId[] = [];\n for (const id of ids) {\n const meta = FDI_TO_META[id];\n if (meta.arch === 'upper') upper.push(id);\n else lower.push(id);\n }\n\n const rowHeight = 50;\n const maxPerRow = Math.max(upper.length, lower.length);\n\n // Centre each row on the widest one.\n function positionRow(row: FdiId[], yOffset: number): PositionedTooth[] {\n const rowWidth = row.reduce((acc, id) => {\n const shape = TOOTH_SHAPES[FDI_TO_META[id].anatomy];\n return acc + shape.width + TOOTH_GAP;\n }, 0);\n const fullRowWidth = row.length > 0 ? rowWidth - TOOTH_GAP : 0;\n\n const maxRowWidth = (function computeMax(): number {\n const bigger = upper.length >= lower.length ? upper : lower;\n const biggerWidth = bigger.reduce((acc, id) => {\n const shape = TOOTH_SHAPES[FDI_TO_META[id].anatomy];\n return acc + shape.width + TOOTH_GAP;\n }, 0);\n return biggerWidth - TOOTH_GAP;\n })();\n\n const startX = (maxRowWidth - fullRowWidth) / 2;\n let cursor = startX;\n return row.map((id) => {\n const meta = FDI_TO_META[id];\n const shape = TOOTH_SHAPES[meta.anatomy];\n const tooth: PositionedTooth = {\n fdi: id,\n meta,\n shape,\n x: cursor,\n y: yOffset,\n };\n cursor += shape.width + TOOTH_GAP;\n return tooth;\n });\n }\n\n const upperRow = positionRow(upper, 0);\n const lowerRow = positionRow(lower, rowHeight + TOOTH_ROW_GAP);\n\n // Compute the true content width / height for the viewBox.\n const maxRowWidth = Math.max(\n upperRow.reduce((acc, t) => Math.max(acc, t.x + t.shape.width), 0),\n lowerRow.reduce((acc, t) => Math.max(acc, t.x + t.shape.width), 0),\n );\n\n // Fall back to a reasonable default if a row is empty.\n const width = maxRowWidth > 0 ? maxRowWidth : maxPerRow * 30;\n const height = rowHeight * 2 + TOOTH_ROW_GAP;\n\n return { teeth: [...upperRow, ...lowerRow], width, height };\n}\n\n/* ------------------------------------------------------------------ */\n/* Labels by numbering */\n/* ------------------------------------------------------------------ */\n\nexport function labelFor(id: FdiId, numbering: Numbering): string {\n switch (numbering) {\n case 'universal':\n return FDI_TO_UNIVERSAL[id] ?? id;\n case 'palmer':\n return FDI_TO_PALMER[id] ?? id;\n case 'fdi':\n default:\n return id;\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Chart helpers */\n/* ------------------------------------------------------------------ */\n\nexport function emptyChart(): ToothChart {\n return {};\n}\n\nexport function chartFromConditions(\n conditions: Partial<Record<FdiId, ToothCondition[]>>,\n): ToothChart {\n const chart: ToothChart = {};\n for (const [id, list] of Object.entries(conditions)) {\n if (!list || list.length === 0) continue;\n chart[id] = { conditions: list, surfaces: [] };\n }\n return chart;\n}\n","/* ------------------------------------------------------------------ */\n/* ToothScheme — in-house SVG dental chart. */\n/* */\n/* - The ONLY Domain-Specific component without a third-party engine. */\n/* No DentalChart.js, no toothchart, no canvas — `src/docs/08-third- */\n/* party.mdx §Dental chart` flags every candidate as rejected (jQuery */\n/* dependency, abandoned, poor a11y), so we draw SVG ourselves. */\n/* */\n/* - Colour-not-alone: each `ToothCondition` has a translated label, a */\n/* token colour AND a `<pattern>` fill. Pattern ids live in */\n/* `CONDITION_PATTERNS`; the six `<pattern>` nodes live once per */\n/* mounted chart inside a single `<defs>` block. */\n/* */\n/* - Chart orientation is FIXED to clinical convention: the patient's */\n/* right side sits on the viewer's left in both upper and lower */\n/* arches, regardless of document `dir`. RTL mirrors the surrounding */\n/* chrome (labels, controls) but NEVER the anatomy — a mirrored */\n/* chart would invert every diagnosis recorded against it. */\n/* */\n/* TODO: */\n/* - SVG artistry is deliberately minimal (rounded-rect crowns with */\n/* anatomy cues). A future pass should replace each `<path>` with */\n/* a clinically-correct crown outline from the dental design team. */\n/* - Surface selection sub-control (mesial / distal / occlusal / …) */\n/* is stubbed via the data model only; the interactive surface */\n/* picker will land in a follow-up. */\n/* - Condition editing is a single-step cycle on Space/Enter — good */\n/* enough for demos and stories; a richer picker belongs in a */\n/* popover and will reuse Radix Popover when it's wired in. */\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n} from 'react';\nimport * as RadixTooltip from '@radix-ui/react-tooltip';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\n\nimport {\n CONDITION_COLORS,\n CONDITION_PATTERNS,\n CONDITION_TOKENS,\n FDI_TO_META,\n PERMANENT_TEETH,\n PRIMARY_TEETH,\n TOOTH_HIT_PAD,\n chartFromConditions,\n labelFor,\n layoutTeeth,\n type Dentition,\n type FdiId,\n type Numbering,\n type ToothChart,\n type ToothCondition,\n type ToothMode,\n type ToothState,\n} from './tooth-data';\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport interface ToothSchemeProps {\n /** Which teeth to render. Default `'permanent'`. */\n dentition?: Dentition;\n /** Numbering system shown on each tooth label. Default `'fdi'`. */\n numbering?: Numbering;\n /** `'interactive'` enables selection + keyboard nav; `'display'` is read-only. Default `'interactive'`. */\n mode?: ToothMode;\n /** Controlled chart state — the full `Record<FdiId, ToothState>`. */\n value?: ToothChart;\n /** Uncontrolled initial chart state. */\n defaultValue?: ToothChart;\n /** Fired whenever the chart changes — always emits FDI ids. */\n onChange?: (next: ToothChart) => void;\n /** Fired when a tooth is focused or clicked. */\n onSelect?: (toothId: FdiId) => void;\n /** Shortcut for pre-populating conditions: `{ '16': ['caries'], '36': ['filled'] }`. */\n conditions?: Partial<Record<FdiId, ToothCondition[]>>;\n /** Accessible label override for the chart region. */\n ariaLabel?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n}\n\nexport interface ToothSchemeHandle {\n /** Programmatically focus a tooth by FDI id. */\n focusTooth: (id: FdiId) => void;\n /** Read the current chart state. */\n getChart: () => ToothChart;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst rootVariants = cva(\n [\n 'ds:tooth-scheme-alfadocs',\n 'ds:inline-flex ds:flex-col',\n 'ds:gap-[var(--spacing-sm)]',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n ].join(' '),\n);\n\nconst svgVariants = cva(\n [\n 'ds:block ds:max-w-full ds:h-auto',\n 'ds:text-[var(--foreground)]',\n ].join(' '),\n);\n\n// `group` here is load-bearing — the focus-ring <rect> below uses\n// `group-focus-visible:opacity-100` to appear when the parent <g> takes\n// focus. Without this class the selector never fires and keyboard users\n// see no focus indicator (a11y-critical-fixes.mdx).\nconst toothGroupVariants = cva(\n [\n 'ds:group ds:cursor-pointer',\n 'ds:focus:outline-none',\n 'ds:transition-[fill,stroke,opacity] ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n ].join(' '),\n);\n\nconst legendVariants = cva(\n [\n 'ds:flex ds:flex-wrap ds:items-center',\n 'ds:gap-[var(--spacing-sm)]',\n 'type-meta ds:text-[var(--muted-foreground)]',\n ].join(' '),\n);\n\nconst legendItemVariants = cva(\n [\n 'ds:inline-flex ds:items-center',\n 'ds:gap-[var(--spacing-xs)]',\n ].join(' '),\n);\n\nconst legendSwatchVariants = cva(\n [\n 'ds:inline-block',\n 'ds:inline-size-[0.75rem] ds:block-size-[0.75rem]',\n 'ds:rounded-[var(--radius-xs)]',\n 'ds:border ds:border-[color:var(--border)]',\n ].join(' '),\n);\n\nconst liveRegionVariants = cva(\n [\n 'ds:sr-only',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nfunction isControlled(props: Pick<ToothSchemeProps, 'value'>): boolean {\n return props.value !== undefined;\n}\n\nfunction emptyState(): ToothState {\n return { conditions: [], surfaces: [] };\n}\n\nfunction cycleCondition(current: ToothCondition[] | undefined): ToothCondition[] {\n if (!current || current.length === 0) return ['caries'];\n return [];\n}\n\nfunction sanitiseIdSuffix(raw: string): string {\n return raw.replace(/[^a-zA-Z0-9-_]/g, '');\n}\n\n/* ------------------------------------------------------------------ */\n/* Patterns <defs> */\n/* ------------------------------------------------------------------ */\n\ninterface PatternDefsProps {\n idPrefix: string;\n}\n\nfunction PatternDefs({ idPrefix }: PatternDefsProps): JSX.Element {\n // We namespace pattern ids per-instance so multiple ToothScheme charts\n // on a page don't collide. References inside the component use\n // `${idPrefix}-${CONDITION_PATTERNS[condition]}`.\n const pid = (id: string): string => `${idPrefix}-${id}`;\n return (\n <defs>\n <pattern\n id={pid(CONDITION_PATTERNS.caries)}\n patternUnits=\"userSpaceOnUse\"\n width=\"6\"\n height=\"6\"\n patternTransform=\"rotate(45)\"\n >\n <line\n x1=\"0\"\n y1=\"0\"\n x2=\"0\"\n y2=\"6\"\n stroke={CONDITION_COLORS.caries}\n strokeWidth=\"2\"\n />\n </pattern>\n <pattern\n id={pid(CONDITION_PATTERNS.filled)}\n patternUnits=\"userSpaceOnUse\"\n width=\"5\"\n height=\"5\"\n >\n <circle cx=\"2.5\" cy=\"2.5\" r=\"1\" fill={CONDITION_COLORS.filled} />\n </pattern>\n <pattern\n id={pid(CONDITION_PATTERNS.crowned)}\n patternUnits=\"userSpaceOnUse\"\n width=\"6\"\n height=\"6\"\n >\n <path\n d=\"M0 0 L6 6 M6 0 L0 6\"\n stroke={CONDITION_COLORS.crowned}\n strokeWidth=\"1\"\n />\n </pattern>\n <pattern\n id={pid(CONDITION_PATTERNS.implant)}\n patternUnits=\"userSpaceOnUse\"\n width=\"4\"\n height=\"4\"\n >\n <line\n x1=\"1\"\n y1=\"0\"\n x2=\"1\"\n y2=\"4\"\n stroke={CONDITION_COLORS.implant}\n strokeWidth=\"1\"\n />\n </pattern>\n <pattern\n id={pid(CONDITION_PATTERNS.rootCanal)}\n patternUnits=\"userSpaceOnUse\"\n width=\"4\"\n height=\"4\"\n >\n <line\n x1=\"0\"\n y1=\"1\"\n x2=\"4\"\n y2=\"1\"\n stroke={CONDITION_COLORS.rootCanal}\n strokeWidth=\"1\"\n />\n </pattern>\n {/* `missing` does not need a pattern — the renderer draws an X glyph. */}\n </defs>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Legend */\n/* ------------------------------------------------------------------ */\n\nconst ALL_CONDITIONS: ToothCondition[] = [\n 'caries',\n 'filled',\n 'crowned',\n 'missing',\n 'implant',\n 'rootCanal',\n];\n\ninterface LegendProps {\n idPrefix: string;\n}\n\nfunction Legend({ idPrefix: _idPrefix }: LegendProps): JSX.Element {\n const { t } = useTranslation();\n return (\n <ul\n className={legendVariants()}\n data-testid=\"tooth-scheme-legend\"\n aria-label={t('toothScheme.legendLabel')}\n >\n {ALL_CONDITIONS.map((condition) => (\n <li key={condition} className={legendItemVariants()}>\n <span\n className={legendSwatchVariants()}\n aria-hidden=\"true\"\n data-condition={condition}\n data-token={CONDITION_TOKENS[condition]}\n data-testid={`tooth-scheme-legend-swatch-${condition}`}\n />\n <span>{t(`toothScheme.condition.${condition}`)}</span>\n </li>\n ))}\n </ul>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport const ToothScheme = forwardRef<ToothSchemeHandle, ToothSchemeProps>(\n (\n {\n dentition = 'permanent',\n numbering = 'fdi',\n mode = 'interactive',\n value,\n defaultValue,\n onChange,\n onSelect,\n conditions,\n ariaLabel,\n className,\n },\n ref,\n ) => {\n const { t } = useTranslation();\n\n const rawId = useId();\n const idPrefix = useMemo(\n () => `ts-${sanitiseIdSuffix(rawId)}`,\n [rawId],\n );\n\n // Chart state — controlled / uncontrolled.\n const [internalChart, setInternalChart] = useState<ToothChart>(() => {\n if (value !== undefined) return value;\n if (defaultValue !== undefined) return defaultValue;\n if (conditions) return chartFromConditions(conditions);\n return {};\n });\n\n const chart: ToothChart = isControlled({ value }) ? (value as ToothChart) : internalChart;\n\n // Keep uncontrolled chart in sync when `conditions` shortcut updates.\n useEffect(() => {\n if (isControlled({ value })) return;\n if (conditions === undefined) return;\n setInternalChart(chartFromConditions(conditions));\n // Intentionally depend on a stable key — swapping the entire prop\n // snapshot is the consumer's signal to reset.\n }, [conditions, value]);\n\n // Layout.\n const layout = useMemo(() => layoutTeeth(dentition), [dentition]);\n const visibleIds = useMemo(\n () => layout.teeth.map((t) => t.fdi),\n [layout],\n );\n\n // Roving tabindex: which tooth owns `tabindex=\"0\"`.\n const firstId: FdiId | undefined = visibleIds[0];\n const [focusedId, setFocusedId] = useState<FdiId | undefined>(firstId);\n useEffect(() => {\n if (!focusedId || !visibleIds.includes(focusedId)) {\n setFocusedId(firstId);\n }\n }, [firstId, focusedId, visibleIds]);\n\n // Live-region announcement text.\n const [announcement, setAnnouncement] = useState<string>('');\n\n const svgRef = useRef<SVGSVGElement>(null);\n\n const commitChart = useCallback(\n (next: ToothChart) => {\n if (!isControlled({ value })) {\n setInternalChart(next);\n }\n onChange?.(next);\n },\n [onChange, value],\n );\n\n const focusToothById = useCallback((id: FdiId) => {\n const svg = svgRef.current;\n if (!svg) return;\n const node = svg.querySelector<SVGGElement>(`g[data-fdi=\"${id}\"]`);\n if (node) {\n node.focus();\n setFocusedId(id);\n }\n }, []);\n\n useImperativeHandle(\n ref,\n (): ToothSchemeHandle => ({\n focusTooth: (id: FdiId) => {\n focusToothById(id);\n },\n getChart: () => chart,\n }),\n [chart, focusToothById],\n );\n\n /* ------------------------------------------------------------- */\n /* Keyboard navigation */\n /* ------------------------------------------------------------- */\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<SVGGElement>, id: FdiId) => {\n if (mode !== 'interactive') return;\n const meta = FDI_TO_META[id];\n if (!meta) return;\n\n // Resolve the ordered list of visible ids for Left/Right.\n const order = visibleIds;\n const currentIndex = order.indexOf(id);\n\n switch (event.key) {\n case 'ArrowRight': {\n event.preventDefault();\n const nextIndex = Math.min(order.length - 1, currentIndex + 1);\n focusToothById(order[nextIndex]);\n return;\n }\n case 'ArrowLeft': {\n event.preventDefault();\n const nextIndex = Math.max(0, currentIndex - 1);\n focusToothById(order[nextIndex]);\n return;\n }\n case 'ArrowUp':\n case 'ArrowDown': {\n event.preventDefault();\n // Map to the opposing arch, same FDI position where possible.\n // Permanent: 1 ↔ 4, 2 ↔ 3. Primary: 5 ↔ 8, 6 ↔ 7.\n const quadrantMap: Record<number, number> = {\n 1: 4,\n 4: 1,\n 2: 3,\n 3: 2,\n 5: 8,\n 8: 5,\n 6: 7,\n 7: 6,\n };\n const targetQuadrant = quadrantMap[meta.quadrant];\n if (!targetQuadrant) return;\n const candidate = `${targetQuadrant}${meta.positionInQuadrant}`;\n if (order.includes(candidate)) {\n focusToothById(candidate);\n }\n return;\n }\n case 'Home': {\n event.preventDefault();\n // First tooth in the same quadrant (visible).\n const inQuadrant = order.filter(\n (other) => FDI_TO_META[other].quadrant === meta.quadrant,\n );\n if (inQuadrant.length > 0) {\n focusToothById(inQuadrant[0]);\n }\n return;\n }\n case 'End': {\n event.preventDefault();\n const inQuadrant = order.filter(\n (other) => FDI_TO_META[other].quadrant === meta.quadrant,\n );\n if (inQuadrant.length > 0) {\n focusToothById(inQuadrant[inQuadrant.length - 1]);\n }\n return;\n }\n case ' ':\n case 'Enter': {\n event.preventDefault();\n const prev = chart[id]?.conditions;\n const nextConditions = cycleCondition(prev);\n const next: ToothChart = { ...chart };\n if (nextConditions.length === 0) {\n delete next[id];\n setAnnouncement(t('toothScheme.deselected', { id }));\n } else {\n next[id] = {\n ...(chart[id] ?? emptyState()),\n conditions: nextConditions,\n };\n setAnnouncement(\n t('toothScheme.selected', {\n id,\n conditions: nextConditions\n .map((c) => t(`toothScheme.condition.${c}`))\n .join(', '),\n }),\n );\n }\n commitChart(next);\n onSelect?.(id);\n return;\n }\n default:\n return;\n }\n },\n [chart, commitChart, focusToothById, mode, onSelect, t, visibleIds],\n );\n\n const handleClick = useCallback(\n (id: FdiId) => {\n if (mode !== 'interactive') return;\n setFocusedId(id);\n const prev = chart[id]?.conditions;\n const nextConditions = cycleCondition(prev);\n const next: ToothChart = { ...chart };\n if (nextConditions.length === 0) {\n delete next[id];\n setAnnouncement(t('toothScheme.deselected', { id }));\n } else {\n next[id] = {\n ...(chart[id] ?? emptyState()),\n conditions: nextConditions,\n };\n setAnnouncement(\n t('toothScheme.selected', {\n id,\n conditions: nextConditions\n .map((c) => t(`toothScheme.condition.${c}`))\n .join(', '),\n }),\n );\n }\n commitChart(next);\n onSelect?.(id);\n },\n [chart, commitChart, mode, onSelect, t],\n );\n\n /* ------------------------------------------------------------- */\n /* Rendering */\n /* ------------------------------------------------------------- */\n\n const viewBoxWidth = layout.width + 4; // small padding for stroke\n const viewBoxHeight = layout.height + 4;\n\n const regionLabel = ariaLabel ?? t('toothScheme.ariaLabel');\n\n return (\n <RadixTooltip.Provider delayDuration={200}>\n <div\n role=\"region\"\n aria-label={regionLabel}\n className={[rootVariants(), className].filter(Boolean).join(' ')}\n data-component=\"tooth-scheme\"\n data-testid=\"tooth-scheme-root\"\n data-dentition={dentition}\n data-numbering={numbering}\n data-mode={mode}\n >\n <svg\n ref={svgRef}\n viewBox={`0 0 ${viewBoxWidth} ${viewBoxHeight}`}\n className={svgVariants()}\n role=\"group\"\n aria-label={regionLabel}\n data-testid=\"tooth-scheme-svg\"\n focusable=\"false\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <PatternDefs idPrefix={idPrefix} />\n\n {layout.teeth.map((tooth) => {\n const state = chart[tooth.fdi];\n const primaryCondition: ToothCondition | undefined =\n state?.conditions?.[0];\n\n const anatomyLabel = t(\n `toothScheme.anatomy.${tooth.meta.anatomy}`,\n );\n const conditionSuffix = primaryCondition\n ? `, ${t(`toothScheme.condition.${primaryCondition}`)}`\n : '';\n const label = t('toothScheme.toothLabel', {\n id: labelFor(tooth.fdi, numbering),\n anatomy: anatomyLabel,\n conditionSuffix,\n });\n\n const tabIndex =\n mode === 'interactive'\n ? tooth.fdi === focusedId\n ? 0\n : -1\n : undefined;\n\n const fillColour: string =\n primaryCondition && primaryCondition !== 'missing'\n ? `url(#${idPrefix}-${CONDITION_PATTERNS[primaryCondition]})`\n : 'var(--muted)';\n\n const strokeColour: string =\n primaryCondition && primaryCondition !== 'missing'\n ? CONDITION_COLORS[primaryCondition]\n : 'var(--border)';\n\n const tooltipContent = primaryCondition\n ? `${anatomyLabel} · ${t(`toothScheme.condition.${primaryCondition}`)}`\n : anatomyLabel;\n\n const labelText = labelFor(tooth.fdi, numbering);\n\n return (\n <RadixTooltip.Root key={tooth.fdi}>\n <RadixTooltip.Trigger asChild>\n <g\n data-fdi={tooth.fdi}\n data-anatomy={tooth.meta.anatomy}\n data-arch={tooth.meta.arch}\n data-side={tooth.meta.side}\n data-quadrant={tooth.meta.quadrant}\n data-condition={primaryCondition ?? 'none'}\n data-testid={`tooth-${tooth.fdi}`}\n transform={`translate(${tooth.x}, ${tooth.y})`}\n tabIndex={tabIndex}\n role={mode === 'interactive' ? 'button' : undefined}\n aria-label={label}\n aria-pressed={\n mode === 'interactive'\n ? (primaryCondition !== undefined)\n : undefined\n }\n className={toothGroupVariants()}\n onClick={\n mode === 'interactive'\n ? () => handleClick(tooth.fdi)\n : undefined\n }\n onFocus={() => setFocusedId(tooth.fdi)}\n onKeyDown={(event) => handleKeyDown(event, tooth.fdi)}\n >\n {/* Invisible ≥44px hit target (WCAG 2.5.5). */}\n <rect\n x={-TOOTH_HIT_PAD}\n y={-TOOTH_HIT_PAD}\n width={tooth.shape.width + TOOTH_HIT_PAD * 2}\n height={tooth.shape.height + TOOTH_HIT_PAD * 2}\n fill=\"transparent\"\n />\n {/* Crown outline. */}\n <path\n d={tooth.shape.path}\n fill={fillColour}\n stroke={strokeColour}\n strokeWidth=\"1.5\"\n vectorEffect=\"non-scaling-stroke\"\n />\n {tooth.shape.innerPath ? (\n <path\n d={tooth.shape.innerPath}\n fill=\"none\"\n stroke=\"var(--muted-foreground)\"\n strokeWidth=\"0.75\"\n vectorEffect=\"non-scaling-stroke\"\n />\n ) : null}\n {/* Focus ring — drawn as a rect so it tracks the hit\n area. `group` on the parent <g> makes this\n group-focus-visible selector fire when a keyboard\n user focuses the tooth. In forced-colors mode the\n ring falls back to `CanvasText` so it stays visible\n when `var(--ring)` is remapped. */}\n <rect\n x={-TOOTH_HIT_PAD}\n y={-TOOTH_HIT_PAD}\n width={tooth.shape.width + TOOTH_HIT_PAD * 2}\n height={tooth.shape.height + TOOTH_HIT_PAD * 2}\n fill=\"none\"\n stroke=\"var(--ring)\"\n strokeWidth=\"var(--focus-ring-width)\"\n className={[\n 'ds:opacity-0',\n 'ds:group-focus-visible:opacity-100',\n 'ds:forced-colors:stroke-[CanvasText]',\n ].join(' ')}\n data-testid={`tooth-${tooth.fdi}-focus-ring`}\n pointerEvents=\"none\"\n rx=\"4\"\n />\n {/* Missing-tooth X glyph. */}\n {primaryCondition === 'missing' ? (\n <path\n d={`M2 2 L${tooth.shape.width - 2} ${tooth.shape.height - 2} M${tooth.shape.width - 2} 2 L2 ${tooth.shape.height - 2}`}\n stroke={CONDITION_COLORS.missing}\n strokeWidth=\"2\"\n fill=\"none\"\n />\n ) : null}\n {/* Tooth number label — sits below (upper arch) or above (lower) the crown. */}\n <text\n x={tooth.shape.width / 2}\n y={\n tooth.meta.arch === 'upper'\n ? tooth.shape.height + 12\n : -4\n }\n textAnchor=\"middle\"\n fontSize=\"10\"\n fill=\"var(--muted-foreground)\"\n className=\"ds:select-none\"\n aria-hidden=\"true\"\n >\n {labelText}\n </text>\n </g>\n </RadixTooltip.Trigger>\n <RadixTooltip.Portal>\n <RadixTooltip.Content\n side=\"top\"\n sideOffset={6}\n className=\"ds:z-[var(--z-tooltip)] ds:rounded-[var(--radius-sm)] ds:bg-[var(--foreground)] ds:text-[var(--background)] ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)] ds:pt-[calc(var(--spacing-xs)/2)] ds:pb-[calc(var(--spacing-xs)/2)] ds:text-[length:var(--font-size-xs)]\"\n >\n {tooltipContent}\n <RadixTooltip.Arrow className=\"ds:fill-[var(--foreground)]\" />\n </RadixTooltip.Content>\n </RadixTooltip.Portal>\n </RadixTooltip.Root>\n );\n })}\n </svg>\n\n <Legend idPrefix={idPrefix} />\n\n <div\n className={liveRegionVariants()}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n data-testid=\"tooth-scheme-live\"\n >\n {announcement}\n </div>\n </div>\n </RadixTooltip.Provider>\n );\n },\n);\n\nToothScheme.displayName = 'ToothScheme';\n\n/* ------------------------------------------------------------------ */\n/* Re-exports */\n/* ------------------------------------------------------------------ */\n\nexport {\n rootVariants as toothSchemeVariants,\n PERMANENT_TEETH,\n PRIMARY_TEETH,\n};\nexport type {\n Dentition,\n FdiId,\n Numbering,\n ToothChart,\n ToothCondition,\n ToothMode,\n ToothState,\n} from './tooth-data';\n","import type { AgentAdapter } from '../../agent/types';\nimport type { ToothSchemeHandle } from './tooth-scheme';\n\nexport const toothSchemeAgent: AgentAdapter<ToothSchemeHandle> = {\n id: 'tooth-scheme',\n capabilities: ['pick'],\n state: {\n chart: {\n type: 'object',\n description: 'Current dental chart state — tooth conditions keyed by FDI id.',\n read: (handle) => handle.getChart(),\n },\n },\n actions: {\n focus_tooth: {\n safety: 'read',\n argsType: '{ id: FdiId }',\n description: 'Move focus to a specific tooth by FDI id.',\n invoke: (handle, args: { id: Parameters<ToothSchemeHandle['focusTooth']>[0] }) => {\n handle.focusTooth(args.id);\n },\n },\n },\n domHooks: {\n root: { attr: 'data-component', value: 'tooth-scheme' },\n item: {\n attr: 'data-fdi',\n description: 'Each rendered tooth `<g>` carries its FDI id as `data-fdi`. Tests still use `data-testid=\"tooth-<fdi>\"` separately.',\n },\n },\n};\n"],"names":["PERMANENT_TEETH","PRIMARY_TEETH","permanentAnatomy","positionInQuadrant","primaryAnatomy","palmerCode","quadrant","position","normalised","permanentUniversal","primaryUniversal","letters","index","buildMeta","fdi","isPrimary","anatomy","arch","side","universal","palmer","FDI_TO_META","acc","FDI_TO_UNIVERSAL","meta","FDI_TO_PALMER","CONDITION_TOKENS","CONDITION_COLORS","CONDITION_PATTERNS","TOOTH_SHAPES","TOOTH_GAP","TOOTH_ROW_GAP","TOOTH_HIT_PAD","layoutTeeth","dentition","ids","upper","lower","id","rowHeight","maxPerRow","positionRow","row","yOffset","rowWidth","shape","fullRowWidth","cursor","tooth","upperRow","lowerRow","maxRowWidth","t","width","height","labelFor","numbering","emptyChart","chartFromConditions","conditions","chart","list","rootVariants","cva","svgVariants","toothGroupVariants","legendVariants","legendItemVariants","legendSwatchVariants","liveRegionVariants","isControlled","props","emptyState","cycleCondition","current","sanitiseIdSuffix","raw","PatternDefs","idPrefix","pid","jsx","ALL_CONDITIONS","Legend","_idPrefix","useTranslation","condition","ToothScheme","forwardRef","mode","value","defaultValue","onChange","onSelect","ariaLabel","className","ref","rawId","useId","useMemo","internalChart","setInternalChart","useState","useEffect","layout","visibleIds","firstId","focusedId","setFocusedId","announcement","setAnnouncement","svgRef","useRef","commitChart","useCallback","next","focusToothById","svg","node","useImperativeHandle","handleKeyDown","event","order","currentIndex","nextIndex","targetQuadrant","candidate","inQuadrant","other","prev","_a","nextConditions","c","handleClick","viewBoxWidth","viewBoxHeight","regionLabel","RadixTooltip","jsxs","state","primaryCondition","anatomyLabel","conditionSuffix","label","tabIndex","fillColour","strokeColour","tooltipContent","labelText","toothSchemeAgent","handle","args"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { forwardRef as M, useId as N, useState as O, useRef as y, useEffect as V
3
3
  import { c as W } from "./index-D2ZczOXr.js";
4
4
  import { useTranslation as q } from "react-i18next";
5
5
  import { A as u } from "./alert-ETrF7Q8J.js";
6
- import { B as F } from "./button-DmiGFnNA.js";
6
+ import { B as F } from "./button-7dTew-IV.js";
7
7
  import { C as H } from "./chevron-down-BX_NP2Yh.js";
8
8
  const L = W(
9
9
  [
@@ -176,4 +176,4 @@ P.displayName = "WarningStack";
176
176
  export {
177
177
  P as W
178
178
  };
179
- //# sourceMappingURL=warning-stack-B9N9yWet.js.map
179
+ //# sourceMappingURL=warning-stack-5KROOw9M.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"warning-stack-B9N9yWet.js","sources":["../../src/components/warning-stack/warning-stack.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { ChevronDown } from 'lucide-react';\nimport { Alert, type AlertProps } from '../alert/alert';\nimport { Button } from '../button/button';\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface WarningStackItem {\n id: string;\n variant?: AlertProps['variant'];\n title: ReactNode;\n description?: ReactNode;\n icon?: ReactNode;\n actions?: ReactNode;\n dismissible?: boolean;\n}\n\nconst stackVariants = cva(\n [\n 'ds:flex ds:flex-col',\n 'ds:rounded-[var(--radius-lg)]',\n 'ds:bg-[color:var(--card)] ds:text-[color:var(--card-foreground)]',\n 'ds:shadow-[var(--shadow-card)]',\n 'ds:p-[var(--spacing-md)]',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:gap-[var(--spacing-sm)]',\n md: 'ds:gap-[var(--spacing-md)]',\n },\n // `stretch: true` fills the parent layout cell — mirrors the `stretch`\n // prop on `Card` so a WarningStack rendered next to a Card in a grid\n // row ends up at matching height.\n stretch: {\n true: 'ds:h-full ds:self-stretch',\n false: '',\n },\n },\n defaultVariants: {\n size: 'md',\n stretch: false,\n },\n },\n);\n\nconst listVariants = cva('ds:flex ds:flex-col', {\n variants: {\n size: {\n sm: 'ds:gap-[var(--spacing-sm)]',\n md: 'ds:gap-[var(--spacing-md)]',\n },\n },\n defaultVariants: { size: 'md' },\n});\n\nconst TOGGLE_CLASSES = [\n 'inline-flex items-center gap-[var(--spacing-xs)] self-start',\n].join(' ');\n\nexport interface WarningStackProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'role' | 'title'>,\n VariantProps<typeof stackVariants> {\n /** Items rendered inside the stack. */\n items: WarningStackItem[];\n /** Fill the parent layout cell — use in a dashboard grid row so the\n * stack ends up with matching height to sibling Cards. */\n stretch?: boolean;\n /** Visible title rendered as an `<h2>` above the stack. Also labels the\n * region for assistive tech. When omitted, the region is labelled via a\n * visually hidden heading using `ariaLabel` (or the default \"Warnings\"). */\n title?: ReactNode;\n /** Optional short description rendered under the title. */\n description?: ReactNode;\n /** Cap on visible items before a \"Show N more\" toggle appears. */\n maxVisible?: number;\n /** Whether the stack starts collapsed when items exceed `maxVisible`. */\n defaultCollapsed?: boolean;\n /** Fires when a dismissible item's close control is activated. */\n onDismiss?: (item: WarningStackItem) => void;\n /** Accessible label for the region when `title` is not set. */\n ariaLabel?: string;\n /** Optional node rendered when the stack has zero items. */\n emptyState?: ReactNode;\n}\n\n/* ------------------------------------------------------------------ */\n/* Root */\n/* ------------------------------------------------------------------ */\n\nexport const WarningStack = forwardRef<HTMLDivElement, WarningStackProps>(\n (\n {\n items,\n title,\n description,\n maxVisible,\n defaultCollapsed = true,\n onDismiss,\n size = 'md',\n stretch = false,\n ariaLabel,\n emptyState,\n className,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation();\n const labelId = useId();\n const listId = useId();\n\n const overflow = maxVisible !== undefined && items.length > maxVisible;\n const [collapsed, setCollapsed] = useState(defaultCollapsed);\n\n // Live-region announces the count when items change.\n const liveRef = useRef<HTMLDivElement>(null);\n const lastCountRef = useRef<number>(items.length);\n\n useEffect(() => {\n if (!liveRef.current) return;\n const prev = lastCountRef.current;\n const next = items.length;\n if (prev !== next) {\n liveRef.current.textContent = t('ui.warningStack.countChanged', {\n count: next,\n defaultValue: '{{count}} warnings to review',\n });\n }\n lastCountRef.current = next;\n }, [items.length, t]);\n\n const visible = useMemo(() => {\n if (!overflow || !collapsed) return items;\n return items.slice(0, maxVisible);\n }, [items, overflow, collapsed, maxVisible]);\n\n const hiddenCount = overflow ? items.length - (maxVisible ?? 0) : 0;\n\n const handleDismiss = useCallback(\n (item: WarningStackItem) => (open: boolean) => {\n if (!open) onDismiss?.(item);\n },\n [onDismiss],\n );\n\n const toggle = useCallback(() => setCollapsed((c) => !c), []);\n\n const regionLabel = ariaLabel ?? t('ui.warningStack.regionLabel', 'Warnings');\n\n // Title block: a visible header when `title` is provided; otherwise a\n // visually hidden heading so the region still has a programmatic name.\n // A `<div>` rather than `<header>` wrapper keeps the `<header>` element's\n // implicit banner role from leaking out of the region.\n const header = title ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-3xs)]\">\n <h2\n id={labelId}\n className=\"ds:text-start type-title-section ds:text-[var(--foreground)]\"\n >\n {title}\n </h2>\n {description ? (\n <p className=\"ds:text-start type-body-sm ds:text-[var(--muted-foreground)]\">\n {description}\n </p>\n ) : null}\n </div>\n ) : (\n <h2 id={labelId} className=\"ds:sr-only\">\n {regionLabel}\n </h2>\n );\n\n if (items.length === 0) {\n if (!emptyState) return null;\n return (\n <section\n ref={ref}\n role=\"region\"\n aria-labelledby={labelId}\n className={[stackVariants({ size, stretch }), className].filter(Boolean).join(' ')}\n {...rest}\n >\n {header}\n {emptyState}\n </section>\n );\n }\n\n return (\n <section\n ref={ref}\n role=\"region\"\n aria-labelledby={labelId}\n className={[stackVariants({ size, stretch }), className].filter(Boolean).join(' ')}\n {...rest}\n >\n {header}\n <div\n ref={liveRef}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"ds:sr-only\"\n />\n <ul\n id={listId}\n className={listVariants({ size })}\n aria-label={t('ui.warningStack.listLabel', 'Warning list')}\n >\n {visible.map((item) => {\n const variant = item.variant ?? 'warning';\n return (\n <li key={item.id}>\n <Alert\n variant={variant}\n dismissible={item.dismissible}\n icon={item.icon}\n onOpenChange={handleDismiss(item)}\n >\n {/* `as=\"h3\"` keeps a clean heading ladder — the stack's\n h2 labels the region, then each item's h3 rises from it. */}\n <Alert.Title as=\"h3\">{item.title}</Alert.Title>\n {item.description ? (\n <Alert.Description>{item.description}</Alert.Description>\n ) : null}\n {item.actions ? <Alert.Action>{item.actions}</Alert.Action> : null}\n </Alert>\n </li>\n );\n })}\n </ul>\n\n {overflow ? (\n <Button\n type=\"button\"\n intent=\"link\"\n size=\"sm\"\n aria-expanded={!collapsed}\n aria-controls={listId}\n onClick={toggle}\n className={TOGGLE_CLASSES}\n >\n <ChevronDown\n aria-hidden=\"true\"\n className={[\n 'ds:size-4 ds:transition-transform ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n collapsed ? '' : 'ds:rotate-180',\n ].join(' ')}\n />\n {collapsed\n ? t('ui.warningStack.showMore', {\n count: hiddenCount,\n defaultValue: 'Show {{count}} more warnings',\n })\n : t('ui.warningStack.showLess', 'Show less')}\n </Button>\n ) : null}\n </section>\n );\n },\n);\n\nWarningStack.displayName = 'WarningStack';\n"],"names":["stackVariants","cva","listVariants","TOGGLE_CLASSES","WarningStack","forwardRef","items","title","description","maxVisible","defaultCollapsed","onDismiss","size","stretch","ariaLabel","emptyState","className","rest","ref","t","useTranslation","labelId","useId","listId","overflow","collapsed","setCollapsed","useState","liveRef","useRef","lastCountRef","useEffect","prev","next","visible","useMemo","hiddenCount","handleDismiss","useCallback","item","open","toggle","c","regionLabel","header","jsxs","jsx","variant","Alert","Button","ChevronDown"],"mappings":"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"}
1
+ {"version":3,"file":"warning-stack-5KROOw9M.js","sources":["../../src/components/warning-stack/warning-stack.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { ChevronDown } from 'lucide-react';\nimport { Alert, type AlertProps } from '../alert/alert';\nimport { Button } from '../button/button';\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface WarningStackItem {\n id: string;\n variant?: AlertProps['variant'];\n title: ReactNode;\n description?: ReactNode;\n icon?: ReactNode;\n actions?: ReactNode;\n dismissible?: boolean;\n}\n\nconst stackVariants = cva(\n [\n 'ds:flex ds:flex-col',\n 'ds:rounded-[var(--radius-lg)]',\n 'ds:bg-[color:var(--card)] ds:text-[color:var(--card-foreground)]',\n 'ds:shadow-[var(--shadow-card)]',\n 'ds:p-[var(--spacing-md)]',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:gap-[var(--spacing-sm)]',\n md: 'ds:gap-[var(--spacing-md)]',\n },\n // `stretch: true` fills the parent layout cell — mirrors the `stretch`\n // prop on `Card` so a WarningStack rendered next to a Card in a grid\n // row ends up at matching height.\n stretch: {\n true: 'ds:h-full ds:self-stretch',\n false: '',\n },\n },\n defaultVariants: {\n size: 'md',\n stretch: false,\n },\n },\n);\n\nconst listVariants = cva('ds:flex ds:flex-col', {\n variants: {\n size: {\n sm: 'ds:gap-[var(--spacing-sm)]',\n md: 'ds:gap-[var(--spacing-md)]',\n },\n },\n defaultVariants: { size: 'md' },\n});\n\nconst TOGGLE_CLASSES = [\n 'inline-flex items-center gap-[var(--spacing-xs)] self-start',\n].join(' ');\n\nexport interface WarningStackProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'role' | 'title'>,\n VariantProps<typeof stackVariants> {\n /** Items rendered inside the stack. */\n items: WarningStackItem[];\n /** Fill the parent layout cell — use in a dashboard grid row so the\n * stack ends up with matching height to sibling Cards. */\n stretch?: boolean;\n /** Visible title rendered as an `<h2>` above the stack. Also labels the\n * region for assistive tech. When omitted, the region is labelled via a\n * visually hidden heading using `ariaLabel` (or the default \"Warnings\"). */\n title?: ReactNode;\n /** Optional short description rendered under the title. */\n description?: ReactNode;\n /** Cap on visible items before a \"Show N more\" toggle appears. */\n maxVisible?: number;\n /** Whether the stack starts collapsed when items exceed `maxVisible`. */\n defaultCollapsed?: boolean;\n /** Fires when a dismissible item's close control is activated. */\n onDismiss?: (item: WarningStackItem) => void;\n /** Accessible label for the region when `title` is not set. */\n ariaLabel?: string;\n /** Optional node rendered when the stack has zero items. */\n emptyState?: ReactNode;\n}\n\n/* ------------------------------------------------------------------ */\n/* Root */\n/* ------------------------------------------------------------------ */\n\nexport const WarningStack = forwardRef<HTMLDivElement, WarningStackProps>(\n (\n {\n items,\n title,\n description,\n maxVisible,\n defaultCollapsed = true,\n onDismiss,\n size = 'md',\n stretch = false,\n ariaLabel,\n emptyState,\n className,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation();\n const labelId = useId();\n const listId = useId();\n\n const overflow = maxVisible !== undefined && items.length > maxVisible;\n const [collapsed, setCollapsed] = useState(defaultCollapsed);\n\n // Live-region announces the count when items change.\n const liveRef = useRef<HTMLDivElement>(null);\n const lastCountRef = useRef<number>(items.length);\n\n useEffect(() => {\n if (!liveRef.current) return;\n const prev = lastCountRef.current;\n const next = items.length;\n if (prev !== next) {\n liveRef.current.textContent = t('ui.warningStack.countChanged', {\n count: next,\n defaultValue: '{{count}} warnings to review',\n });\n }\n lastCountRef.current = next;\n }, [items.length, t]);\n\n const visible = useMemo(() => {\n if (!overflow || !collapsed) return items;\n return items.slice(0, maxVisible);\n }, [items, overflow, collapsed, maxVisible]);\n\n const hiddenCount = overflow ? items.length - (maxVisible ?? 0) : 0;\n\n const handleDismiss = useCallback(\n (item: WarningStackItem) => (open: boolean) => {\n if (!open) onDismiss?.(item);\n },\n [onDismiss],\n );\n\n const toggle = useCallback(() => setCollapsed((c) => !c), []);\n\n const regionLabel = ariaLabel ?? t('ui.warningStack.regionLabel', 'Warnings');\n\n // Title block: a visible header when `title` is provided; otherwise a\n // visually hidden heading so the region still has a programmatic name.\n // A `<div>` rather than `<header>` wrapper keeps the `<header>` element's\n // implicit banner role from leaking out of the region.\n const header = title ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-3xs)]\">\n <h2\n id={labelId}\n className=\"ds:text-start type-title-section ds:text-[var(--foreground)]\"\n >\n {title}\n </h2>\n {description ? (\n <p className=\"ds:text-start type-body-sm ds:text-[var(--muted-foreground)]\">\n {description}\n </p>\n ) : null}\n </div>\n ) : (\n <h2 id={labelId} className=\"ds:sr-only\">\n {regionLabel}\n </h2>\n );\n\n if (items.length === 0) {\n if (!emptyState) return null;\n return (\n <section\n ref={ref}\n role=\"region\"\n aria-labelledby={labelId}\n className={[stackVariants({ size, stretch }), className].filter(Boolean).join(' ')}\n {...rest}\n >\n {header}\n {emptyState}\n </section>\n );\n }\n\n return (\n <section\n ref={ref}\n role=\"region\"\n aria-labelledby={labelId}\n className={[stackVariants({ size, stretch }), className].filter(Boolean).join(' ')}\n {...rest}\n >\n {header}\n <div\n ref={liveRef}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"ds:sr-only\"\n />\n <ul\n id={listId}\n className={listVariants({ size })}\n aria-label={t('ui.warningStack.listLabel', 'Warning list')}\n >\n {visible.map((item) => {\n const variant = item.variant ?? 'warning';\n return (\n <li key={item.id}>\n <Alert\n variant={variant}\n dismissible={item.dismissible}\n icon={item.icon}\n onOpenChange={handleDismiss(item)}\n >\n {/* `as=\"h3\"` keeps a clean heading ladder — the stack's\n h2 labels the region, then each item's h3 rises from it. */}\n <Alert.Title as=\"h3\">{item.title}</Alert.Title>\n {item.description ? (\n <Alert.Description>{item.description}</Alert.Description>\n ) : null}\n {item.actions ? <Alert.Action>{item.actions}</Alert.Action> : null}\n </Alert>\n </li>\n );\n })}\n </ul>\n\n {overflow ? (\n <Button\n type=\"button\"\n intent=\"link\"\n size=\"sm\"\n aria-expanded={!collapsed}\n aria-controls={listId}\n onClick={toggle}\n className={TOGGLE_CLASSES}\n >\n <ChevronDown\n aria-hidden=\"true\"\n className={[\n 'ds:size-4 ds:transition-transform ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n collapsed ? '' : 'ds:rotate-180',\n ].join(' ')}\n />\n {collapsed\n ? t('ui.warningStack.showMore', {\n count: hiddenCount,\n defaultValue: 'Show {{count}} more warnings',\n })\n : t('ui.warningStack.showLess', 'Show less')}\n </Button>\n ) : null}\n </section>\n );\n },\n);\n\nWarningStack.displayName = 'WarningStack';\n"],"names":["stackVariants","cva","listVariants","TOGGLE_CLASSES","WarningStack","forwardRef","items","title","description","maxVisible","defaultCollapsed","onDismiss","size","stretch","ariaLabel","emptyState","className","rest","ref","t","useTranslation","labelId","useId","listId","overflow","collapsed","setCollapsed","useState","liveRef","useRef","lastCountRef","useEffect","prev","next","visible","useMemo","hiddenCount","handleDismiss","useCallback","item","open","toggle","c","regionLabel","header","jsxs","jsx","variant","Alert","Button","ChevronDown"],"mappings":"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"}
@@ -3,16 +3,16 @@ import { forwardRef as P, useMemo as V, useRef as B, useCallback as K, useEffect
3
3
  import { c as L } from "./index-D2ZczOXr.js";
4
4
  import { useTranslation as z } from "react-i18next";
5
5
  import { C as _ } from "./card-DeItIBcV.js";
6
- import { B as pe } from "./badge-zDghajh8.js";
7
- import { K as G } from "./key-value-pair-DDhSYdDL.js";
6
+ import { B as pe } from "./badge-BbbBRweN.js";
7
+ import { K as G } from "./key-value-pair-Cm-pSE6k.js";
8
8
  import { T as he } from "./timestamp-DmSt92P1.js";
9
- import { I as M } from "./icon-button-C482ii4y.js";
9
+ import { I as M } from "./icon-button-SWpSs9S6.js";
10
10
  import { c as C } from "./createLucideIcon-CrFbzy84.js";
11
11
  import { C as ve } from "./circle-BkqTgYmt.js";
12
12
  import { A as W } from "./alert-ETrF7Q8J.js";
13
- import { B as we } from "./button-DmiGFnNA.js";
13
+ import { B as we } from "./button-7dTew-IV.js";
14
14
  import { D as N } from "./dropdown-menu-BnVUeVG3.js";
15
- import { E as T } from "./empty-state-DV96gCnp.js";
15
+ import { E as T } from "./empty-state-DPUnQp0A.js";
16
16
  import { P as ee } from "./plus-CYKNmfuA.js";
17
17
  import { G as te } from "./globe-BkEFMNSg.js";
18
18
  import { S as se } from "./square-check-big-Jr-0202D.js";
@@ -1334,4 +1334,4 @@ export {
1334
1334
  Y as r,
1335
1335
  D as w
1336
1336
  };
1337
- //# sourceMappingURL=workflow-map-gBhL_Wrs.js.map
1337
+ //# sourceMappingURL=workflow-map-D4sjYv2d.js.map