@alfadocs/ui-kit-debug 1.96.0 → 1.97.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. package/dist/_chunks/{address-autocomplete-DR4Xn23Z.js → address-autocomplete-DC-H-MZw.js} +2 -2
  2. package/dist/_chunks/{address-autocomplete-DR4Xn23Z.js.map → address-autocomplete-DC-H-MZw.js.map} +1 -1
  3. package/dist/_chunks/{address-fields-qxQkGwPf.js → address-fields-D5Ije0S2.js} +7 -7
  4. package/dist/_chunks/{address-fields-qxQkGwPf.js.map → address-fields-D5Ije0S2.js.map} +1 -1
  5. package/dist/_chunks/{agenda-card-BhY342MA.js → agenda-card-bRQ4j6U6.js} +2 -2
  6. package/dist/_chunks/{agenda-card-BhY342MA.js.map → agenda-card-bRQ4j6U6.js.map} +1 -1
  7. package/dist/_chunks/{agenda-tray-BmxBGEci.js → agenda-tray-CzE3E8GU.js} +2 -2
  8. package/dist/_chunks/{agenda-tray-BmxBGEci.js.map → agenda-tray-CzE3E8GU.js.map} +1 -1
  9. package/dist/_chunks/{alia-sidebar-ovRX_oti.js → alia-sidebar-B5mu44g2.js} +3 -3
  10. package/dist/_chunks/{alia-sidebar-ovRX_oti.js.map → alia-sidebar-B5mu44g2.js.map} +1 -1
  11. package/dist/_chunks/{anamnesis-summary-rows-CdRUXoaA.js → anamnesis-summary-rows-B9HqOGd7.js} +4 -4
  12. package/dist/_chunks/{anamnesis-summary-rows-CdRUXoaA.js.map → anamnesis-summary-rows-B9HqOGd7.js.map} +1 -1
  13. package/dist/_chunks/{appointment-card-Csx4544A.js → appointment-card-zPr0brha.js} +3 -3
  14. package/dist/_chunks/{appointment-card-Csx4544A.js.map → appointment-card-zPr0brha.js.map} +1 -1
  15. package/dist/_chunks/{appointment-peek-CcDCWb-F.js → appointment-peek-xFTBany4.js} +3 -3
  16. package/dist/_chunks/{appointment-peek-CcDCWb-F.js.map → appointment-peek-xFTBany4.js.map} +1 -1
  17. package/dist/_chunks/{appointment-timeline-DW6FN6u8.js → appointment-timeline-AKkVx9AN.js} +2 -2
  18. package/dist/_chunks/{appointment-timeline-DW6FN6u8.js.map → appointment-timeline-AKkVx9AN.js.map} +1 -1
  19. package/dist/_chunks/{appointment-tray-CZfXwHWz.js → appointment-tray-B8qQBW65.js} +2 -2
  20. package/dist/_chunks/{appointment-tray-CZfXwHWz.js.map → appointment-tray-B8qQBW65.js.map} +1 -1
  21. package/dist/_chunks/{aspect-ratio-DeSNzASA.js → aspect-ratio-B-6cyOpm.js} +13 -13
  22. package/dist/_chunks/aspect-ratio-B-6cyOpm.js.map +1 -0
  23. package/dist/_chunks/{autocomplete-BXMcNoa3.js → autocomplete-D10ydpgi.js} +2 -2
  24. package/dist/_chunks/{autocomplete-BXMcNoa3.js.map → autocomplete-D10ydpgi.js.map} +1 -1
  25. package/dist/_chunks/{avatar-a6042Ox2.js → avatar-BoqdWsNe.js} +2 -2
  26. package/dist/_chunks/avatar-BoqdWsNe.js.map +1 -0
  27. package/dist/_chunks/{balance-badge-cell-DcBmtijD.js → balance-badge-cell-DaZokVZY.js} +3 -3
  28. package/dist/_chunks/{balance-badge-cell-DcBmtijD.js.map → balance-badge-cell-DaZokVZY.js.map} +1 -1
  29. package/dist/_chunks/{breadcrumb-Bn29NCnf.js → breadcrumb-zxa_PNhF.js} +2 -2
  30. package/dist/_chunks/breadcrumb-zxa_PNhF.js.map +1 -0
  31. package/dist/_chunks/{calendar-CmiMS4FJ.js → calendar-DVe5eArk.js} +2 -2
  32. package/dist/_chunks/{calendar-CmiMS4FJ.js.map → calendar-DVe5eArk.js.map} +1 -1
  33. package/dist/_chunks/{calendar-appointment-editor-dialog-BOZ5wk96.js → calendar-appointment-editor-dialog-26LEMx0q.js} +12 -12
  34. package/dist/_chunks/{calendar-appointment-editor-dialog-BOZ5wk96.js.map → calendar-appointment-editor-dialog-26LEMx0q.js.map} +1 -1
  35. package/dist/_chunks/{chat-message-LRO_6Ee3.js → chat-message-CkBCAcwn.js} +2 -2
  36. package/dist/_chunks/{chat-message-LRO_6Ee3.js.map → chat-message-CkBCAcwn.js.map} +1 -1
  37. package/dist/_chunks/{city-input-CA59CjnV.js → city-input-DXipzTfZ.js} +3 -3
  38. package/dist/_chunks/{city-input-CA59CjnV.js.map → city-input-DXipzTfZ.js.map} +1 -1
  39. package/dist/_chunks/{clinical-note-card-CWHFnCmY.js → clinical-note-card--juv_ELr.js} +2 -2
  40. package/dist/_chunks/{clinical-note-card-CWHFnCmY.js.map → clinical-note-card--juv_ELr.js.map} +1 -1
  41. package/dist/_chunks/{combobox-D-gpgEDy.js → combobox-duuDRI1t.js} +2 -2
  42. package/dist/_chunks/{combobox-D-gpgEDy.js.map → combobox-duuDRI1t.js.map} +1 -1
  43. package/dist/_chunks/{command-palette-B3dVqm9D.js → command-palette-DxQBU4wH.js} +3 -3
  44. package/dist/_chunks/command-palette-DxQBU4wH.js.map +1 -0
  45. package/dist/_chunks/{contact-profile-card-jBf9U4At.js → contact-profile-card-QPUgGu-t.js} +57 -57
  46. package/dist/_chunks/contact-profile-card-QPUgGu-t.js.map +1 -0
  47. package/dist/_chunks/{copy-field-hgVSc51W.js → copy-field-BaYEDJ9f.js} +24 -24
  48. package/dist/_chunks/copy-field-BaYEDJ9f.js.map +1 -0
  49. package/dist/_chunks/{country-select-BfmX9y5i.js → country-select-CUuGOAoZ.js} +2 -2
  50. package/dist/_chunks/{country-select-BfmX9y5i.js.map → country-select-CUuGOAoZ.js.map} +1 -1
  51. package/dist/_chunks/{data-table-xUDjZS_O.js → data-table-C4UT4L9B.js} +3 -3
  52. package/dist/_chunks/{data-table-xUDjZS_O.js.map → data-table-C4UT4L9B.js.map} +1 -1
  53. package/dist/_chunks/{data-table-tabs-CcgU2lr5.js → data-table-tabs-Db7zToFD.js} +2 -2
  54. package/dist/_chunks/{data-table-tabs-CcgU2lr5.js.map → data-table-tabs-Db7zToFD.js.map} +1 -1
  55. package/dist/_chunks/{dependent-selector-CyNi7M_f.js → dependent-selector-DRN0P0Kr.js} +2 -2
  56. package/dist/_chunks/{dependent-selector-CyNi7M_f.js.map → dependent-selector-DRN0P0Kr.js.map} +1 -1
  57. package/dist/_chunks/{document-preview-DWIQryMW.js → document-preview-U8H6tnDJ.js} +2 -2
  58. package/dist/_chunks/{document-preview-DWIQryMW.js.map → document-preview-U8H6tnDJ.js.map} +1 -1
  59. package/dist/_chunks/{document-scanner-BQP0Rqrt.js → document-scanner-Bf3VUp00.js} +24 -24
  60. package/dist/_chunks/document-scanner-Bf3VUp00.js.map +1 -0
  61. package/dist/_chunks/{editable-currency-cell-renderer-BEaj2NT_.js → editable-currency-cell-renderer-BUdFMh67.js} +2 -2
  62. package/dist/_chunks/{editable-currency-cell-renderer-BEaj2NT_.js.map → editable-currency-cell-renderer-BUdFMh67.js.map} +1 -1
  63. package/dist/_chunks/{email-input-C7THAwh2.js → email-input-BEO3vonE.js} +2 -2
  64. package/dist/_chunks/{email-input-C7THAwh2.js.map → email-input-BEO3vonE.js.map} +1 -1
  65. package/dist/_chunks/{entity-summary-BJdfIsk_.js → entity-summary-B4p8zP1J.js} +2 -2
  66. package/dist/_chunks/{entity-summary-BJdfIsk_.js.map → entity-summary-B4p8zP1J.js.map} +1 -1
  67. package/dist/_chunks/{face-scheme-BmygzbZr.js → face-scheme-DdVLQ5dP.js} +3 -3
  68. package/dist/_chunks/{face-scheme-BmygzbZr.js.map → face-scheme-DdVLQ5dP.js.map} +1 -1
  69. package/dist/_chunks/{file-manager-Ba_TcfCj.js → file-manager-B4K2j7jB.js} +4 -4
  70. package/dist/_chunks/{file-manager-Ba_TcfCj.js.map → file-manager-B4K2j7jB.js.map} +1 -1
  71. package/dist/_chunks/{fiscal-code-input-BzWmNDnl.js → fiscal-code-input-BBvU7sAo.js} +2 -2
  72. package/dist/_chunks/{fiscal-code-input-BzWmNDnl.js.map → fiscal-code-input-BBvU7sAo.js.map} +1 -1
  73. package/dist/_chunks/{forgot-password-form-BCk4rGIh.js → forgot-password-form-CeTb5p-x.js} +2 -2
  74. package/dist/_chunks/{forgot-password-form-BCk4rGIh.js.map → forgot-password-form-CeTb5p-x.js.map} +1 -1
  75. package/dist/_chunks/{header-settings-C2D74i4g.js → header-settings-Df9q1uHt.js} +2 -2
  76. package/dist/_chunks/{header-settings-C2D74i4g.js.map → header-settings-Df9q1uHt.js.map} +1 -1
  77. package/dist/_chunks/{heatmap-C9tEvqEm.js → heatmap-B2Z1_kDn.js} +2 -2
  78. package/dist/_chunks/{heatmap-C9tEvqEm.js.map → heatmap-B2Z1_kDn.js.map} +1 -1
  79. package/dist/_chunks/{help-me-write-templates-BJSf24xS.js → help-me-write-templates-ra5a__Yy.js} +2 -2
  80. package/dist/_chunks/{help-me-write-templates-BJSf24xS.js.map → help-me-write-templates-ra5a__Yy.js.map} +1 -1
  81. package/dist/_chunks/{iban-input-B9L2QDHh.js → iban-input-DuTwKok5.js} +2 -2
  82. package/dist/_chunks/{iban-input-B9L2QDHh.js.map → iban-input-DuTwKok5.js.map} +1 -1
  83. package/dist/_chunks/{icon-picker-DQMG9L6M.js → icon-picker-BmU6gpZT.js} +2 -2
  84. package/dist/_chunks/{icon-picker-DQMG9L6M.js.map → icon-picker-BmU6gpZT.js.map} +1 -1
  85. package/dist/_chunks/{input-surface-iBmxVBfr.js → input-surface-BMffm2Vd.js} +4 -4
  86. package/dist/_chunks/{input-surface-iBmxVBfr.js.map → input-surface-BMffm2Vd.js.map} +1 -1
  87. package/dist/_chunks/{link-cell-renderer-OmvrkUeN.js → link-cell-renderer-DKMgD-2v.js} +4 -4
  88. package/dist/_chunks/{link-cell-renderer-OmvrkUeN.js.map → link-cell-renderer-DKMgD-2v.js.map} +1 -1
  89. package/dist/_chunks/{locale-picker-B1NAHW4U.js → locale-picker-C86h8Yt1.js} +2 -2
  90. package/dist/_chunks/{locale-picker-B1NAHW4U.js.map → locale-picker-C86h8Yt1.js.map} +1 -1
  91. package/dist/_chunks/{login-dev-card-DcfcFJrm.js → login-dev-card-D5BV5j1i.js} +4 -4
  92. package/dist/_chunks/{login-dev-card-DcfcFJrm.js.map → login-dev-card-D5BV5j1i.js.map} +1 -1
  93. package/dist/_chunks/{map-view--c9bJDRw.js → map-view-V7etHnyF.js} +2 -2
  94. package/dist/_chunks/map-view-V7etHnyF.js.map +1 -0
  95. package/dist/_chunks/{marketplace-app-shell-DDZI-uBl.js → marketplace-app-shell-D2qgIuXX.js} +4 -4
  96. package/dist/_chunks/{marketplace-app-shell-DDZI-uBl.js.map → marketplace-app-shell-D2qgIuXX.js.map} +1 -1
  97. package/dist/_chunks/{message-card-B6SduXJv.js → message-card-BzJEITml.js} +2 -2
  98. package/dist/_chunks/{message-card-B6SduXJv.js.map → message-card-BzJEITml.js.map} +1 -1
  99. package/dist/_chunks/{message-tray-18_TrLCy.js → message-tray-DiPgJbOb.js} +2 -2
  100. package/dist/_chunks/{message-tray-18_TrLCy.js.map → message-tray-DiPgJbOb.js.map} +1 -1
  101. package/dist/_chunks/{multi-select-i5MFRpXg.js → multi-select-Df3R8lv_.js} +30 -30
  102. package/dist/_chunks/multi-select-Df3R8lv_.js.map +1 -0
  103. package/dist/_chunks/{navigation-menu-DbaSlvdO.js → navigation-menu-1MrpIVkY.js} +3 -3
  104. package/dist/_chunks/navigation-menu-1MrpIVkY.js.map +1 -0
  105. package/dist/_chunks/{notes-panel-DfjF83IK.js → notes-panel-BbNLYcdv.js} +3 -3
  106. package/dist/_chunks/{notes-panel-DfjF83IK.js.map → notes-panel-BbNLYcdv.js.map} +1 -1
  107. package/dist/_chunks/{operator-hero-N_ziNGFF.js → operator-hero-BcuPTzS_.js} +2 -2
  108. package/dist/_chunks/{operator-hero-N_ziNGFF.js.map → operator-hero-BcuPTzS_.js.map} +1 -1
  109. package/dist/_chunks/{pagination-DvKGrsXu.js → pagination-C7N_NiRN.js} +2 -2
  110. package/dist/_chunks/{pagination-DvKGrsXu.js.map → pagination-C7N_NiRN.js.map} +1 -1
  111. package/dist/_chunks/{password-input-BokZ_rnT.js → password-input-SJGHFdOO.js} +2 -2
  112. package/dist/_chunks/{password-input-BokZ_rnT.js.map → password-input-SJGHFdOO.js.map} +1 -1
  113. package/dist/_chunks/{patient-details-DGHkAErB.js → patient-details-DoIOWP6j.js} +3 -3
  114. package/dist/_chunks/{patient-details-DGHkAErB.js.map → patient-details-DoIOWP6j.js.map} +1 -1
  115. package/dist/_chunks/{patient-field-row-BVK4y98C.js → patient-field-row--dCDO5oB.js} +9 -9
  116. package/dist/_chunks/{patient-field-row-BVK4y98C.js.map → patient-field-row--dCDO5oB.js.map} +1 -1
  117. package/dist/_chunks/{patient-search-CL6dtBIq.js → patient-search-DJy0IZSx.js} +2 -2
  118. package/dist/_chunks/{patient-search-CL6dtBIq.js.map → patient-search-DJy0IZSx.js.map} +1 -1
  119. package/dist/_chunks/{patient-summary-card-DXz07c2X.js → patient-summary-card-CL04aq8h.js} +3 -3
  120. package/dist/_chunks/{patient-summary-card-DXz07c2X.js.map → patient-summary-card-CL04aq8h.js.map} +1 -1
  121. package/dist/_chunks/{payment-automation-upsell-CZk6f8aK.js → payment-automation-upsell-BPF0c-5D.js} +2 -2
  122. package/dist/_chunks/{payment-automation-upsell-CZk6f8aK.js.map → payment-automation-upsell-BPF0c-5D.js.map} +1 -1
  123. package/dist/_chunks/{pdf-viewer-gAsNUsA8.js → pdf-viewer-DlceXkfW.js} +267 -286
  124. package/dist/_chunks/pdf-viewer-DlceXkfW.js.map +1 -0
  125. package/dist/_chunks/{phone-input-DJ4BN8tG.js → phone-input-BL8Sj6OG.js} +3 -3
  126. package/dist/_chunks/phone-input-BL8Sj6OG.js.map +1 -0
  127. package/dist/_chunks/{postal-code-input-CfZOnIkW.js → postal-code-input-dJdSAVkP.js} +2 -2
  128. package/dist/_chunks/{postal-code-input-CfZOnIkW.js.map → postal-code-input-dJdSAVkP.js.map} +1 -1
  129. package/dist/_chunks/{practice-profile-hero-DKmnB-M0.js → practice-profile-hero-B8vykoci.js} +2 -2
  130. package/dist/_chunks/{practice-profile-hero-DKmnB-M0.js.map → practice-profile-hero-B8vykoci.js.map} +1 -1
  131. package/dist/_chunks/{practice-results-ZOVlrb43.js → practice-results-U-5kpnJa.js} +3 -3
  132. package/dist/_chunks/{practice-results-ZOVlrb43.js.map → practice-results-U-5kpnJa.js.map} +1 -1
  133. package/dist/_chunks/{province-select-D64whw0m.js → province-select-cVOlwEc5.js} +2 -2
  134. package/dist/_chunks/{province-select-D64whw0m.js.map → province-select-cVOlwEc5.js.map} +1 -1
  135. package/dist/_chunks/{public-footer-BiPiU_lk.js → public-footer-t6gx6sjn.js} +163 -152
  136. package/dist/_chunks/public-footer-t6gx6sjn.js.map +1 -0
  137. package/dist/_chunks/{registration-form-K4j2tdLt.js → registration-form-JzzTomhd.js} +5 -5
  138. package/dist/_chunks/{registration-form-K4j2tdLt.js.map → registration-form-JzzTomhd.js.map} +1 -1
  139. package/dist/_chunks/{reserved.agent-TRbKB39d.js → reserved.agent-CB-92Vi9.js} +8 -8
  140. package/dist/_chunks/{reserved.agent-TRbKB39d.js.map → reserved.agent-CB-92Vi9.js.map} +1 -1
  141. package/dist/_chunks/{reset-password-form-C6XLV7SI.js → reset-password-form-DDdGEoIL.js} +3 -3
  142. package/dist/_chunks/{reset-password-form-C6XLV7SI.js.map → reset-password-form-DDdGEoIL.js.map} +1 -1
  143. package/dist/_chunks/{rich-text-editor-CJfT08It.js → rich-text-editor-F04przIt.js} +2 -2
  144. package/dist/_chunks/{rich-text-editor-CJfT08It.js.map → rich-text-editor-F04przIt.js.map} +1 -1
  145. package/dist/_chunks/{search-bar-mA4bPe3t.js → search-bar-CQ9_V3EJ.js} +2 -2
  146. package/dist/_chunks/{search-bar-mA4bPe3t.js.map → search-bar-CQ9_V3EJ.js.map} +1 -1
  147. package/dist/_chunks/{search-input-BAlDd05M.js → search-input-CRAMo1CA.js} +2 -2
  148. package/dist/_chunks/{search-input-BAlDd05M.js.map → search-input-CRAMo1CA.js.map} +1 -1
  149. package/dist/_chunks/{send-registration-link-form-yLSfcaPk.js → send-registration-link-form-DHCQpA4C.js} +3 -3
  150. package/dist/_chunks/{send-registration-link-form-yLSfcaPk.js.map → send-registration-link-form-DHCQpA4C.js.map} +1 -1
  151. package/dist/_chunks/{sidebar-BS24EnYd.js → sidebar-2VsPlNkZ.js} +3 -3
  152. package/dist/_chunks/sidebar-2VsPlNkZ.js.map +1 -0
  153. package/dist/_chunks/{sign-document-BiOTs1P4.js → sign-document-B5qZhthO.js} +10 -10
  154. package/dist/_chunks/sign-document-B5qZhthO.js.map +1 -0
  155. package/dist/_chunks/{signature-capture-Chqh62Pc.js → signature-capture-BJc7kfqi.js} +2 -2
  156. package/dist/_chunks/signature-capture-BJc7kfqi.js.map +1 -0
  157. package/dist/_chunks/{signature-field-Y01UB5DA.js → signature-field-DjabvRZm.js} +28 -34
  158. package/dist/_chunks/{signature-field-Y01UB5DA.js.map → signature-field-DjabvRZm.js.map} +1 -1
  159. package/dist/_chunks/{signature-request-CLtMgQKi.js → signature-request-CQ0torGq.js} +2 -2
  160. package/dist/_chunks/{signature-request-CLtMgQKi.js.map → signature-request-CQ0torGq.js.map} +1 -1
  161. package/dist/_chunks/{signed-out-frame-CRwVTCjY.js → signed-out-frame-BcQE00H1.js} +2 -2
  162. package/dist/_chunks/{signed-out-frame-CRwVTCjY.js.map → signed-out-frame-BcQE00H1.js.map} +1 -1
  163. package/dist/_chunks/{stat-Dno2ZihS.js → stat-BFKZV50y.js} +137 -117
  164. package/dist/_chunks/stat-BFKZV50y.js.map +1 -0
  165. package/dist/_chunks/{state-backed-text-input-Cgh4ms3p.js → state-backed-text-input-DVETOhSS.js} +2 -2
  166. package/dist/_chunks/{state-backed-text-input-Cgh4ms3p.js.map → state-backed-text-input-DVETOhSS.js.map} +1 -1
  167. package/dist/_chunks/{stepper-accordion-DDTSOUHc.js → stepper-accordion-CYjrmRte.js} +44 -44
  168. package/dist/_chunks/stepper-accordion-CYjrmRte.js.map +1 -0
  169. package/dist/_chunks/{task-editor-qXfMbHsy.js → task-editor-BiPGFXtB.js} +3 -3
  170. package/dist/_chunks/{task-editor-qXfMbHsy.js.map → task-editor-BiPGFXtB.js.map} +1 -1
  171. package/dist/_chunks/{text-input-CaG9ApoE.js → text-input-B6iAgCr3.js} +2 -2
  172. package/dist/_chunks/{text-input-CaG9ApoE.js.map → text-input-B6iAgCr3.js.map} +1 -1
  173. package/dist/_chunks/{timeline-B32dylRJ.js → timeline-tn5QQJdS.js} +2 -2
  174. package/dist/_chunks/{timeline-B32dylRJ.js.map → timeline-tn5QQJdS.js.map} +1 -1
  175. package/dist/_chunks/{transcript-panel-CoHHpcFg.js → transcript-panel-A781Pkzr.js} +2 -2
  176. package/dist/_chunks/{transcript-panel-CoHHpcFg.js.map → transcript-panel-A781Pkzr.js.map} +1 -1
  177. package/dist/_chunks/{use-appointment-details-read-UXXvBeGZ.js → use-appointment-details-read-BbIoPWO6.js} +5 -5
  178. package/dist/_chunks/{use-appointment-details-read-UXXvBeGZ.js.map → use-appointment-details-read-BbIoPWO6.js.map} +1 -1
  179. package/dist/_chunks/{widget-picker-B9HpT2Tb.js → widget-picker-DNYIqRT1.js} +2 -2
  180. package/dist/_chunks/{widget-picker-B9HpT2Tb.js.map → widget-picker-DNYIqRT1.js.map} +1 -1
  181. package/dist/_chunks/{workflow-map-flsvqQ3L.js → workflow-map-k-dQkpe7.js} +20 -20
  182. package/dist/_chunks/{workflow-map-flsvqQ3L.js.map → workflow-map-k-dQkpe7.js.map} +1 -1
  183. package/dist/_chunks/{workflow-status-HQ6ziE46.js → workflow-status-9wb7iWUd.js} +2 -2
  184. package/dist/_chunks/{workflow-status-HQ6ziE46.js.map → workflow-status-9wb7iWUd.js.map} +1 -1
  185. package/dist/_chunks/{workflow-webhook-action-BD-6UyOs.js → workflow-webhook-action-B_52rH7O.js} +3 -3
  186. package/dist/_chunks/{workflow-webhook-action-BD-6UyOs.js.map → workflow-webhook-action-B_52rH7O.js.map} +1 -1
  187. package/dist/agent-catalog.json +1 -1
  188. package/dist/components/_shared/input-surface.d.ts +3 -3
  189. package/dist/components/address-autocomplete/index.js +1 -1
  190. package/dist/components/address-fields/index.js +1 -1
  191. package/dist/components/agenda-card/index.js +1 -1
  192. package/dist/components/agenda-tray/index.js +1 -1
  193. package/dist/components/appointment-card/index.js +2 -2
  194. package/dist/components/appointment-details-panel/index.js +1 -1
  195. package/dist/components/appointment-peek/index.js +1 -1
  196. package/dist/components/appointment-timeline/index.js +1 -1
  197. package/dist/components/aspect-ratio/index.js +1 -1
  198. package/dist/components/autocomplete/index.js +1 -1
  199. package/dist/components/avatar/index.js +1 -1
  200. package/dist/components/booking/index.js +1 -1
  201. package/dist/components/breadcrumb/index.js +1 -1
  202. package/dist/components/calendar/index.js +1 -1
  203. package/dist/components/chat-message/index.js +1 -1
  204. package/dist/components/city-input/index.js +1 -1
  205. package/dist/components/clinical-note-card/index.js +1 -1
  206. package/dist/components/combobox/index.js +1 -1
  207. package/dist/components/command-palette/index.js +1 -1
  208. package/dist/components/contact-profile-card/index.js +1 -1
  209. package/dist/components/copy-field/index.js +1 -1
  210. package/dist/components/country-select/index.js +1 -1
  211. package/dist/components/data-table/index.js +3 -3
  212. package/dist/components/data-table-tabs/index.js +1 -1
  213. package/dist/components/dependent-selector/index.js +1 -1
  214. package/dist/components/document-preview/index.js +1 -1
  215. package/dist/components/document-scanner/index.js +1 -1
  216. package/dist/components/email-input/index.js +1 -1
  217. package/dist/components/entity-summary/index.js +1 -1
  218. package/dist/components/face-scheme/index.js +1 -1
  219. package/dist/components/file-manager/index.js +1 -1
  220. package/dist/components/fiscal-code-input/index.js +1 -1
  221. package/dist/components/header-settings/index.js +1 -1
  222. package/dist/components/heatmap/index.js +1 -1
  223. package/dist/components/iban-input/index.js +1 -1
  224. package/dist/components/icon-picker/index.js +1 -1
  225. package/dist/components/locale-picker/index.js +1 -1
  226. package/dist/components/map-view/index.js +1 -1
  227. package/dist/components/message-card/index.js +1 -1
  228. package/dist/components/message-tray/index.js +1 -1
  229. package/dist/components/multi-select/index.js +1 -1
  230. package/dist/components/navigation-menu/index.js +1 -1
  231. package/dist/components/notes-panel/index.js +1 -1
  232. package/dist/components/operator-hero/index.js +1 -1
  233. package/dist/components/pagination/index.js +1 -1
  234. package/dist/components/password-input/index.js +1 -1
  235. package/dist/components/patient-details/index.js +1 -1
  236. package/dist/components/patient-search/index.js +1 -1
  237. package/dist/components/patient-summary-card/index.js +1 -1
  238. package/dist/components/patient-table/index.js +1 -1
  239. package/dist/components/pdf-viewer/index.js +1 -1
  240. package/dist/components/pdf-viewer/pdf-viewer.d.ts.map +1 -1
  241. package/dist/components/phone-input/index.js +1 -1
  242. package/dist/components/postal-code-input/index.js +1 -1
  243. package/dist/components/practice-profile-hero/index.js +1 -1
  244. package/dist/components/practice-results/index.js +1 -1
  245. package/dist/components/province-select/index.js +1 -1
  246. package/dist/components/public-footer/index.js +1 -1
  247. package/dist/components/public-footer/public-footer.d.ts.map +1 -1
  248. package/dist/components/rich-text-editor/index.js +1 -1
  249. package/dist/components/search-bar/index.js +1 -1
  250. package/dist/components/search-input/index.js +1 -1
  251. package/dist/components/sidebar/index.js +1 -1
  252. package/dist/components/sign-document/index.js +1 -1
  253. package/dist/components/signature-capture/index.js +1 -1
  254. package/dist/components/signature-field/index.js +1 -1
  255. package/dist/components/signature-field/signature-field.d.ts.map +1 -1
  256. package/dist/components/stat/index.js +1 -1
  257. package/dist/components/stat/stat.d.ts +8 -0
  258. package/dist/components/stat/stat.d.ts.map +1 -1
  259. package/dist/components/stepper-accordion/index.js +1 -1
  260. package/dist/components/task-editor/index.js +1 -1
  261. package/dist/components/text-input/index.js +1 -1
  262. package/dist/components/timeline/index.js +1 -1
  263. package/dist/components/transcript-panel/index.js +1 -1
  264. package/dist/components/widget-picker/index.js +1 -1
  265. package/dist/components/workflow/index.js +1 -1
  266. package/dist/components/workflow-status/index.js +1 -1
  267. package/dist/core.css +1 -1
  268. package/dist/host-compat.css +13 -1
  269. package/dist/index.js +88 -88
  270. package/dist/patterns/alia-assistant/index.js +1 -1
  271. package/dist/patterns/anamnesis/index.js +1 -1
  272. package/dist/patterns/calendar/index.js +1 -1
  273. package/dist/patterns/forgot-password-form/index.js +1 -1
  274. package/dist/patterns/help-me-write-templates/index.js +1 -1
  275. package/dist/patterns/login-form/index.js +1 -1
  276. package/dist/patterns/marketplace-app-shell/index.js +1 -1
  277. package/dist/patterns/payment-automation-upsell/index.js +1 -1
  278. package/dist/patterns/registration-form/index.js +1 -1
  279. package/dist/patterns/reset-password-form/index.js +1 -1
  280. package/dist/patterns/send-registration-link-form/index.js +1 -1
  281. package/dist/patterns/signature-request/index.js +1 -1
  282. package/dist/patterns/signed-out-frame/index.js +1 -1
  283. package/dist/patterns/workflow-webhook-action/index.js +1 -1
  284. package/dist/tokens.css +1 -1
  285. package/package.json +1 -1
  286. package/dist/_chunks/aspect-ratio-DeSNzASA.js.map +0 -1
  287. package/dist/_chunks/avatar-a6042Ox2.js.map +0 -1
  288. package/dist/_chunks/breadcrumb-Bn29NCnf.js.map +0 -1
  289. package/dist/_chunks/command-palette-B3dVqm9D.js.map +0 -1
  290. package/dist/_chunks/contact-profile-card-jBf9U4At.js.map +0 -1
  291. package/dist/_chunks/copy-field-hgVSc51W.js.map +0 -1
  292. package/dist/_chunks/document-scanner-BQP0Rqrt.js.map +0 -1
  293. package/dist/_chunks/map-view--c9bJDRw.js.map +0 -1
  294. package/dist/_chunks/multi-select-i5MFRpXg.js.map +0 -1
  295. package/dist/_chunks/navigation-menu-DbaSlvdO.js.map +0 -1
  296. package/dist/_chunks/pdf-viewer-gAsNUsA8.js.map +0 -1
  297. package/dist/_chunks/phone-input-DJ4BN8tG.js.map +0 -1
  298. package/dist/_chunks/public-footer-BiPiU_lk.js.map +0 -1
  299. package/dist/_chunks/sidebar-BS24EnYd.js.map +0 -1
  300. package/dist/_chunks/sign-document-BiOTs1P4.js.map +0 -1
  301. package/dist/_chunks/signature-capture-Chqh62Pc.js.map +0 -1
  302. package/dist/_chunks/stat-Dno2ZihS.js.map +0 -1
  303. package/dist/_chunks/stepper-accordion-DDTSOUHc.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfadocs/ui-kit-debug",
3
- "version": "1.96.0",
3
+ "version": "1.97.0",
4
4
  "type": "module",
5
5
  "description": "AlfaDocs shared design system — tokens, components, patterns, and translations for platform, booking, and alfascribe. (debug build — identical runtime to @alfadocs/ui-kit, ships source maps for symbolication).",
6
6
  "license": "BUSL-1.1",
@@ -1 +0,0 @@
1
- {"version":3,"file":"aspect-ratio-DeSNzASA.js","sources":["../../src/components/aspect-ratio/aspect-ratio.tsx"],"sourcesContent":["import {\n forwardRef,\n type HTMLAttributes,\n type ReactNode,\n type CSSProperties,\n} from 'react';\nimport { Root as RadixAspectRatio } from '@radix-ui/react-aspect-ratio';\nimport { cva } from 'class-variance-authority';\n\nexport { RadixAspectRatio as AspectRatioPrimitive };\n\ntype PresetRatio = '1:1' | '4:3' | '16:9' | '3:2' | '21:9';\ntype FitValue = 'cover' | 'contain' | 'fill' | 'scale-down' | 'none';\n\nconst aspectRatioVariants = cva(\n [\n 'ds:relative ds:inline-size-full ds:overflow-hidden',\n 'ds:[&>*]:absolute ds:[&>*]:inset-0 ds:[&>*]:inline-size-full ds:[&>*]:block-size-full',\n 'ds:[&>*]:[object-position:var(--ar-object-position,center)]',\n ],\n {\n variants: {\n ratio: {\n '1:1': 'ds:aspect-[1/1] ar-1x1',\n '4:3': 'ds:aspect-[4/3] ar-4x3',\n '16:9': 'ds:aspect-[16/9] ar-16x9',\n '3:2': 'ds:aspect-[3/2] ar-3x2',\n '21:9': 'ds:aspect-[21/9] ar-21x9',\n } satisfies Record<PresetRatio, string>,\n fit: {\n cover: 'ds:[&>*]:object-cover',\n contain: 'ds:[&>*]:object-contain',\n fill: 'ds:[&>*]:object-fill',\n 'scale-down': 'ds:[&>*]:object-scale-down',\n none: 'ds:[&>*]:object-none',\n } satisfies Record<FitValue, string>,\n },\n defaultVariants: {\n ratio: '16:9',\n fit: 'cover',\n },\n },\n);\n\nexport interface AspectRatioProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'children'\n> {\n /** Preset ratio or numeric escape hatch (e.g. 2.35 for cinema). */\n ratio?: PresetRatio | number;\n /** object-fit applied to the direct child element. */\n fit?: FitValue;\n /** Forwarded to the child via `--ar-object-position` CSS variable. */\n objectPosition?: string;\n children: ReactNode;\n}\n\nexport const AspectRatio = forwardRef<HTMLDivElement, AspectRatioProps>(\n (\n { ratio, fit, objectPosition, className, style, children, ...rest },\n ref,\n ) => {\n const isNumericRatio = typeof ratio === 'number';\n // When a numeric ratio is passed we drive the layout via the inline\n // `aspectRatio` style. We must also pass `ratio: null` to CVA so the\n // preset (default `'16:9'`) is suppressed — `undefined` would fall back\n // to defaultVariants and apply the 16:9 utility, conflicting with the\n // numeric value.\n const presetRatio: PresetRatio | null | undefined = isNumericRatio\n ? null\n : (ratio as PresetRatio | undefined);\n\n // Sanctioned inline styles (constraint §4 exceptions):\n // 1. `aspectRatio` — numeric ratio escape hatch has no Tailwind equivalent\n // 2. `--ar-object-position` — CSS custom property forwarded to the child via var()\n // Radix Root is NOT used as the render element: it uses padding-top + physical\n // properties (top/right/bottom/left) which violate constraints §3 and §4.\n const computedStyle:\n | (CSSProperties & Record<string, string | number>)\n | undefined =\n isNumericRatio || objectPosition || style\n ? {\n ...style,\n ...(isNumericRatio ? { aspectRatio: ratio } : {}),\n ...(objectPosition\n ? { '--ar-object-position': objectPosition }\n : {}),\n }\n : undefined;\n\n return (\n <div\n ref={ref}\n data-component=\"aspect-ratio\"\n className={aspectRatioVariants({ ratio: presetRatio, fit, className })}\n // eslint-disable-next-line react/forbid-dom-props -- dynamic aspectRatio + --ar-object-position CSS variable, no static equivalent\n style={computedStyle}\n {...rest}\n >\n {children}\n </div>\n );\n },\n);\n\nAspectRatio.displayName = 'AspectRatio';\n"],"names":["aspectRatioVariants","cva","AspectRatio","forwardRef","ratio","fit","objectPosition","className","style","children","rest","ref","isNumericRatio","presetRatio","computedStyle","jsx"],"mappings":";;;;AAcA,MAAMA,IAAsBC;AAAA,EAC1B;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAEF;AAAA,IACE,UAAU;AAAA,MACR,OAAO;AAAA,QACL,OAAO;AAAA,QACP,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,QAAQ;AAAA,MAAA;AAAA,MAEV,KAAK;AAAA,QACH,OAAO;AAAA,QACP,SAAS;AAAA,QACT,MAAM;AAAA,QACN,cAAc;AAAA,QACd,MAAM;AAAA,MAAA;AAAA,IACR;AAAA,IAEF,iBAAiB;AAAA,MACf,OAAO;AAAA,MACP,KAAK;AAAA,IAAA;AAAA,EACP;AAEJ,GAeaC,IAAcC;AAAA,EACzB,CACE,EAAE,OAAAC,GAAO,KAAAC,GAAK,gBAAAC,GAAgB,WAAAC,GAAW,OAAAC,GAAO,UAAAC,GAAU,GAAGC,EAAA,GAC7DC,MACG;AACH,UAAMC,IAAiB,OAAOR,KAAU,UAMlCS,IAA8CD,IAChD,OACCR,GAOCU,IAGJF,KAAkBN,KAAkBE,IAChC;AAAA,MACE,GAAGA;AAAA,MACH,GAAII,IAAiB,EAAE,aAAaR,EAAA,IAAU,CAAA;AAAA,MAC9C,GAAIE,IACA,EAAE,wBAAwBA,MAC1B,CAAA;AAAA,IAAC,IAEP;AAEN,WACE,gBAAAS;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAAJ;AAAA,QACA,kBAAe;AAAA,QACf,WAAWX,EAAoB,EAAE,OAAOa,GAAa,KAAAR,GAAK,WAAAE,GAAW;AAAA,QAErE,OAAOO;AAAA,QACN,GAAGJ;AAAA,QAEH,UAAAD;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEAP,EAAY,cAAc;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"avatar-a6042Ox2.js","sources":["../../src/components/avatar/avatar.tsx"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useRef,\n useState,\n type HTMLAttributes,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { composeRefs } from '../_shared/compose-refs';\nimport { useIsomorphicLayoutEffect } from '../../hooks/use-isomorphic-layout-effect';\n\n// ── Hash ──────────────────────────────────────────────────────────────────────\n\n/** djb2 hash — fast, unsigned 32-bit, stable across calls. */\nfunction djb2(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) + hash) ^ str.charCodeAt(i);\n hash = hash >>> 0; // coerce to unsigned 32-bit integer\n }\n return hash;\n}\n\n/**\n * 16 brand hues. All reach ≥ 4.5 : 1 against the initials text: white\n * (var(--primary-foreground)) in the light themes and --color-grey-50 in\n * both dark themes, which pin --primary-foreground to navy. The lowest pair\n * is blue-300 with grey-50, at 4.60 : 1. Spans four distinct hue families\n * for good visual distribution.\n *\n * Index | Token | Contrast | Visual character\n * 0 | --color-violet-500 | 4.74 : 1 | bright violet\n * 1 | --color-violet-600 | 5.53 : 1 | medium violet\n * 2 | --color-violet-700 | 7.29 : 1 | dark violet\n * 3 | --color-violet-800 | 9.57 : 1 | deep violet\n * 4 | --color-violet-900 | 12.06 : 1 | midnight violet\n * 5 | --color-purple-700 | 5.21 : 1 | medium purple\n * 6 | --color-purple-800 | 7.52 : 1 | dark purple\n * 7 | --color-purple-900 | 10.40 : 1 | deep purple\n * 8 | --color-magenta-700 | 6.01 : 1 | vivid magenta\n * 9 | --color-magenta-800 | 8.05 : 1 | dark magenta\n * 10 | --color-magenta-900 | 11.20 : 1 | deep magenta\n * 11 | --color-blue-300 | 4.64 : 1 | slate / steel blue\n * 12 | --color-blue-400 | 6.95 : 1 | medium slate\n * 13 | --color-blue-500 | 13.00 : 1 | deep navy\n * 14 | --color-blue-700 | 17.82 : 1 | midnight navy\n * 15 | --color-grey-900 | 5.78 : 1 | warm charcoal\n */\nconst INITIALS_BG_CLASSES = [\n 'ds:bg-[var(--color-violet-500)]',\n 'ds:bg-[var(--color-violet-600)]',\n 'ds:bg-[var(--color-violet-700)]',\n 'ds:bg-[var(--color-violet-800)]',\n 'ds:bg-[var(--color-violet-900)]',\n 'ds:bg-[var(--color-purple-700)]',\n 'ds:bg-[var(--color-purple-800)]',\n 'ds:bg-[var(--color-purple-900)]',\n 'ds:bg-[var(--color-magenta-700)]',\n 'ds:bg-[var(--color-magenta-800)]',\n 'ds:bg-[var(--color-magenta-900)]',\n 'ds:bg-[var(--color-blue-300)]',\n 'ds:bg-[var(--color-blue-400)]',\n 'ds:bg-[var(--color-blue-500)]',\n 'ds:bg-[var(--color-blue-700)]',\n 'ds:bg-[var(--color-grey-900)]',\n] as const;\n\n/** Deterministically maps a name string to one of 16 brand-hue Tailwind classes. Same name always produces the same class. */\nexport function nameToColorClass(name: string): string {\n return INITIALS_BG_CLASSES[djb2(name) % INITIALS_BG_CLASSES.length];\n}\n\n/**\n * Extracts 1–2 uppercase initials:\n * - Single-word name: first two characters (\"John\" → \"JO\")\n * - Multi-word name: first char of first word + first char of last word (\"John Doe\" → \"JD\")\n * - Parenthesised or bracketed parts and words with no letter are skipped\n * (\"Lucy Danvers (daughter)\" → \"LD\"), unless nothing else is left.\n */\nexport function getInitials(name: string): string {\n const toWords = (text: string) =>\n text\n .trim()\n .split(/\\s+/)\n .map((word) => word.replace(/^[^\\p{L}\\p{N}]+|[^\\p{L}\\p{N}]+$/gu, ''))\n .filter((word) => /\\p{L}/u.test(word));\n const outside = toWords(name.replace(/\\([^)]*\\)|\\[[^\\]]*\\]/g, ' '));\n const words = outside.length > 0 ? outside : toWords(name);\n if (words.length === 0) return '';\n if (words.length === 1) return words[0].slice(0, 2).toUpperCase();\n return (words[0][0] + words[words.length - 1][0]).toUpperCase();\n}\n\n// ── CVA ───────────────────────────────────────────────────────────────────────\n\nconst avatarVariants = cva(\n [\n 'ds:relative ds:inline-flex ds:shrink-0 ds:select-none ds:items-center ds:justify-center ds:overflow-hidden',\n // Focus ring — uses design-system tokens so theme overrides (accessible: 3px) apply automatically.\n // The ring renders when Avatar is placed inside a focusable ancestor (e.g. a <button>).\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-ring',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n ].join(' '),\n {\n variants: {\n size: {\n // text-[var(--font-size-xs)] = 0.75rem (12px) — smallest available token\n xs: 'ds:size-6 ds:text-[length:var(--font-size-xs)] ds:font-semibold ds:leading-none',\n sm: 'ds:size-8 ds:text-[length:var(--font-size-xs)] ds:font-semibold ds:leading-none',\n md: 'ds:size-10 ds:text-[length:var(--font-size-xs)] ds:font-semibold ds:leading-none',\n lg: 'ds:size-12 ds:text-[length:var(--font-size-sm)] ds:font-semibold ds:leading-none',\n xl: 'ds:size-16 ds:text-[length:var(--font-size-base)] ds:font-semibold ds:leading-none',\n // 2xl / 3xl are hero / display crops (operator cards, practice-\n // profile pages). They token-reference `--avatar-size-*` so\n // consumer themes can override the dimensions per-context, and\n // `--avatar-text-size-*` so initials scale proportionally to\n // the circle (otherwise --font-size-base at 192px reads as a\n // tiny letter in a vast disc).\n // Their initials size is a compound variant below: it depends on\n // the ratio, and two text-size classes on one element would leave\n // the winner to stylesheet order.\n '2xl':\n 'ds:size-[var(--avatar-size-2xl)] ds:font-semibold ds:leading-none',\n '3xl':\n 'ds:size-[var(--avatar-size-3xl)] ds:font-semibold ds:leading-none',\n },\n // HTP-6712. `rounded` is the photo shape for practices and\n // professionals: a rounded rectangle whose corner scales with the\n // size (compound variants below), so a 40px photo does not read as\n // a circle and a 192px one matches the card corners.\n shape: {\n circle: 'ds:rounded-[var(--radius-full)]',\n rounded: '',\n },\n // The size sets the height; a non-square ratio derives the width\n // from it. A 192px practice photo becomes 256 x 192, a 128px\n // professional one 96 x 128, so a hero keeps its height. Pair a\n // non-square ratio with `shape=\"rounded\"`: a circle stretched to 4:3\n // is a pill.\n ratio: {\n '1:1': '',\n '4:3': 'ds:w-auto ds:aspect-[4/3]',\n '3:4': 'ds:w-auto ds:aspect-[3/4]',\n },\n },\n compoundVariants: [\n {\n shape: 'rounded',\n size: ['xs', 'sm'],\n className: 'ds:rounded-[var(--radius-sm)]',\n },\n {\n shape: 'rounded',\n size: ['md', 'lg', 'xl'],\n className: 'ds:rounded-[var(--radius-md)]',\n },\n {\n // The card radius, as on the white boxes the big photos sit in.\n shape: 'rounded',\n size: ['2xl', '3xl'],\n className: 'ds:rounded-[var(--radius-lg)]',\n },\n // Display initials. A 3:4 box is a quarter narrower than its\n // height, so they scale down with it: two wide or CJK initials\n // still fit.\n {\n size: '2xl',\n ratio: ['1:1', '4:3'],\n className: 'ds:text-[length:var(--avatar-text-size-2xl)]',\n },\n {\n size: '3xl',\n ratio: ['1:1', '4:3'],\n className: 'ds:text-[length:var(--avatar-text-size-3xl)]',\n },\n {\n size: '2xl',\n ratio: '3:4',\n className: 'ds:text-[length:calc(var(--avatar-text-size-2xl)*0.75)]',\n },\n {\n size: '3xl',\n ratio: '3:4',\n className: 'ds:text-[length:calc(var(--avatar-text-size-3xl)*0.75)]',\n },\n ],\n defaultVariants: { size: 'md', shape: 'circle', ratio: '1:1' },\n },\n);\n\n// The photo always fills and crops (object-fit: cover). A portrait (3:4)\n// crops towards the top so a face is not cut; a 216 x 360 photo in a 3:4\n// box loses 14px at the top and 58px at the bottom. Everything else crops\n// from the centre: square logos lose their top and bottom in 4:3.\nconst imageVariants = cva(\n 'ds:absolute ds:inset-0 ds:size-full ds:object-cover',\n {\n variants: {\n ratio: {\n '1:1': '',\n '4:3': '',\n '3:4': 'ds:object-[50%_20%]',\n },\n },\n defaultVariants: { ratio: '1:1' },\n },\n);\n\n// ── Props ─────────────────────────────────────────────────────────────────────\n\nexport interface AvatarProps\n extends\n Omit<HTMLAttributes<HTMLSpanElement>, 'color'>,\n VariantProps<typeof avatarVariants> {\n /** Image source URL. When provided and loads successfully, the image is displayed. */\n src?: string;\n /**\n * Text alternative written on the photo's `<img>`, so it is there in the\n * first HTML and for image search and crawlers that do not read ARIA. Pass\n * the name of the person or place in the photo. While the photo shows, this\n * text is the accessible name: the `<img>` is the one image assistive\n * technology meets, and the wrapper drops its own `role=\"img\"` and\n * `aria-label` so nothing is announced twice. If the photo fails to load, or\n * while only initials show, the wrapper keeps `role=\"img\"` labelled with\n * `name`.\n *\n * Leave it out and the `<img>` stays decorative (`alt=\"\"`), as before.\n * An empty string means the same. Added in 1.91.0.\n */\n alt?: string;\n /** Display name — drives initials extraction and deterministic background colour. */\n name?: string;\n /**\n * Override the auto-generated background with any CSS colour string\n * (e.g. `\"var(--color-violet-700)\"`).\n * Applied via a CSS custom property so no `style` attribute is added to the JSX element.\n * Caller is responsible for WCAG AA contrast (≥4.5:1) against white text.\n */\n color?: string;\n}\n\n// ── Component ─────────────────────────────────────────────────────────────────\n\nexport const Avatar = forwardRef<HTMLSpanElement, AvatarProps>(\n ({ src, alt, name, color, size, shape, ratio, className, ...props }, ref) => {\n const { t } = useTranslation('ui');\n\n const innerRef = useRef<HTMLSpanElement>(null);\n const composedRef = composeRefs(ref, innerRef);\n\n // Track only image errors. The image renders immediately as an overlay;\n // before it loads the browser paints nothing (transparent), showing the\n // background colour + initials behind it. On error we remove the img and\n // the initials/fallback remain permanently visible.\n const [imgError, setImgError] = useState(false);\n\n // Reset error flag whenever src changes\n useEffect(() => {\n setImgError(false);\n }, [src]);\n\n // Apply color override via CSS custom property — avoids style={{…}} on JSX.\n // Mirrors the pattern used by the Progress component for imperative CSS property injection.\n useIsomorphicLayoutEffect(() => {\n const el = innerRef.current;\n if (!el) return;\n if (color) {\n el.style.setProperty('--avatar-color-override', color);\n } else {\n el.style.removeProperty('--avatar-color-override');\n }\n }, [color]);\n\n // Image is \"active\" when provided and not errored\n const imgActive = !!src && !imgError;\n\n // Initials and fallback icon are shown when no usable image\n const showInitials = !imgActive && !!name;\n const showIcon = !imgActive && !name;\n\n // Background — always rendered (serves as loading placeholder when image is fetching)\n const fallbackBgClass = color\n ? 'ds:bg-[var(--avatar-color-override)]'\n : name\n ? nameToColorClass(name)\n : 'ds:bg-muted';\n\n // Always light text against brand hues / color override; muted-foreground\n // for icon. Both dark themes pin `--primary-foreground` to navy, which is\n // illegible on the swatches, so `--avatar-initials-foreground` re-points\n // to near-white `--color-grey-50` there.\n const contentColorClass =\n color || name\n ? 'ds:text-[var(--avatar-initials-foreground,var(--primary-foreground))]'\n : 'ds:text-muted-foreground';\n\n const rootClassName = avatarVariants({\n size,\n shape,\n ratio,\n className: [fallbackBgClass, contentColorClass, className]\n .filter(Boolean)\n .join(' '),\n });\n\n // Accessible label — name takes priority, then the localised placeholder\n const ariaLabel = name ?? t('avatar.placeholder', 'User avatar');\n\n // A photo with its own alt text is the image; the wrapper steps back.\n const altOnPhoto = imgActive && !!alt;\n\n return (\n <span\n ref={composedRef}\n role={altOnPhoto ? undefined : 'img'}\n aria-label={altOnPhoto ? undefined : ariaLabel}\n data-component=\"avatar\"\n className={rootClassName}\n {...props}\n >\n {/* Initials — rendered behind the image; visible while image is loading\n or permanently when no src / src errors */}\n {(showInitials || imgActive) && !!name && (\n <span aria-hidden=\"true\">{getInitials(name)}</span>\n )}\n\n {/* Fallback icon — shown when neither image nor name is available */}\n {showIcon && (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n className=\"ds:size-[58%] ds:fill-current\"\n >\n <path d=\"M12 12c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm0 2c-3.33 0-10 1.67-10 5v2h20v-2c0-3.33-6.67-5-10-5z\" />\n </svg>\n )}\n\n {/* Image — absolutely positioned overlay. Renders transparently until the\n browser paints the decoded pixels, then covers the initials behind it.\n Removed from DOM on error so initials remain permanently visible. */}\n {imgActive && (\n <img\n src={src}\n alt={alt ?? ''}\n aria-hidden={alt ? undefined : 'true'}\n className={imageVariants({ ratio })}\n onError={() => setImgError(true)}\n />\n )}\n </span>\n );\n },\n);\n\nAvatar.displayName = 'Avatar';\n"],"names":["djb2","str","hash","i","INITIALS_BG_CLASSES","nameToColorClass","name","getInitials","toWords","text","word","outside","words","avatarVariants","cva","imageVariants","Avatar","forwardRef","src","alt","color","size","shape","ratio","className","props","ref","t","useTranslation","innerRef","useRef","composedRef","composeRefs","imgError","setImgError","useState","useEffect","useIsomorphicLayoutEffect","el","imgActive","showInitials","showIcon","fallbackBgClass","rootClassName","ariaLabel","altOnPhoto","jsxs","jsx"],"mappings":";;;;;;AAeA,SAASA,EAAKC,GAAqB;AACjC,MAAIC,IAAO;AACX,WAASC,IAAI,GAAGA,IAAIF,EAAI,QAAQE;AAC9B,IAAAD,KAASA,KAAQ,KAAKA,IAAQD,EAAI,WAAWE,CAAC,GAC9CD,IAAOA,MAAS;AAElB,SAAOA;AACT;AA2BA,MAAME,IAAsB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,SAASC,EAAiBC,GAAsB;AACrD,SAAOF,EAAoBJ,EAAKM,CAAI,IAAIF,EAAoB,MAAM;AACpE;AASO,SAASG,EAAYD,GAAsB;AAChD,QAAME,IAAU,CAACC,MACfA,EACG,OACA,MAAM,KAAK,EACX,IAAI,CAACC,MAASA,EAAK,QAAQ,qCAAqC,EAAE,CAAC,EACnE,OAAO,CAACA,MAAS,WAAA,UAAA,GAAA,EAAS,KAAKA,CAAI,CAAC,GACnCC,IAAUH,EAAQF,EAAK,QAAQ,yBAAyB,GAAG,CAAC,GAC5DM,IAAQD,EAAQ,SAAS,IAAIA,IAAUH,EAAQF,CAAI;AACzD,SAAIM,EAAM,WAAW,IAAU,KAC3BA,EAAM,WAAW,IAAUA,EAAM,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,YAAA,KAC5CA,EAAM,CAAC,EAAE,CAAC,IAAIA,EAAMA,EAAM,SAAS,CAAC,EAAE,CAAC,GAAG,YAAA;AACpD;AAIA,MAAMC,IAAiBC;AAAA,EACrB;AAAA,IACE;AAAA;AAAA;AAAA,IAGA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AAAA,EACV;AAAA,IACE,UAAU;AAAA,MACR,MAAM;AAAA;AAAA,QAEJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAUJ,OACE;AAAA,QACF,OACE;AAAA,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAMJ,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOX,OAAO;AAAA,QACL,OAAO;AAAA,QACP,OAAO;AAAA,QACP,OAAO;AAAA,MAAA;AAAA,IACT;AAAA,IAEF,kBAAkB;AAAA,MAChB;AAAA,QACE,OAAO;AAAA,QACP,MAAM,CAAC,MAAM,IAAI;AAAA,QACjB,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,OAAO;AAAA,QACP,MAAM,CAAC,MAAM,MAAM,IAAI;AAAA,QACvB,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA;AAAA,QAEE,OAAO;AAAA,QACP,MAAM,CAAC,OAAO,KAAK;AAAA,QACnB,WAAW;AAAA,MAAA;AAAA;AAAA;AAAA;AAAA,MAKb;AAAA,QACE,MAAM;AAAA,QACN,OAAO,CAAC,OAAO,KAAK;AAAA,QACpB,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,MAAM;AAAA,QACN,OAAO,CAAC,OAAO,KAAK;AAAA,QACpB,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,WAAW;AAAA,MAAA;AAAA,IACb;AAAA,IAEF,iBAAiB,EAAE,MAAM,MAAM,OAAO,UAAU,OAAO,MAAA;AAAA,EAAM;AAEjE,GAMMC,IAAgBD;AAAA,EACpB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,OAAO;AAAA,QACL,OAAO;AAAA,QACP,OAAO;AAAA,QACP,OAAO;AAAA,MAAA;AAAA,IACT;AAAA,IAEF,iBAAiB,EAAE,OAAO,MAAA;AAAA,EAAM;AAEpC,GAqCaE,IAASC;AAAA,EACpB,CAAC,EAAE,KAAAC,GAAK,KAAAC,GAAK,MAAAb,GAAM,OAAAc,GAAO,MAAAC,GAAM,OAAAC,GAAO,OAAAC,GAAO,WAAAC,GAAW,GAAGC,EAAA,GAASC,MAAQ;AAC3E,UAAM,EAAE,GAAAC,EAAA,IAAMC,EAAe,IAAI,GAE3BC,IAAWC,EAAwB,IAAI,GACvCC,IAAcC,EAAYN,GAAKG,CAAQ,GAMvC,CAACI,GAAUC,CAAW,IAAIC,EAAS,EAAK;AAG9C,IAAAC,EAAU,MAAM;AACd,MAAAF,EAAY,EAAK;AAAA,IACnB,GAAG,CAAChB,CAAG,CAAC,GAIRmB,EAA0B,MAAM;AAC9B,YAAMC,IAAKT,EAAS;AACpB,MAAKS,MACDlB,IACFkB,EAAG,MAAM,YAAY,2BAA2BlB,CAAK,IAErDkB,EAAG,MAAM,eAAe,yBAAyB;AAAA,IAErD,GAAG,CAAClB,CAAK,CAAC;AAGV,UAAMmB,IAAY,CAAC,CAACrB,KAAO,CAACe,GAGtBO,IAAe,CAACD,KAAa,CAAC,CAACjC,GAC/BmC,IAAW,CAACF,KAAa,CAACjC,GAG1BoC,IAAkBtB,IACpB,yCACAd,IACED,EAAiBC,CAAI,IACrB,eAWAqC,IAAgB9B,EAAe;AAAA,MACnC,MAAAQ;AAAA,MACA,OAAAC;AAAA,MACA,OAAAC;AAAA,MACA,WAAW,CAACmB,GARZtB,KAASd,IACL,0EACA,4BAM4CkB,CAAS,EACtD,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,IAAA,CACZ,GAGKoB,IAAYtC,KAAQqB,EAAE,sBAAsB,aAAa,GAGzDkB,IAAaN,KAAa,CAAC,CAACpB;AAElC,WACE,gBAAA2B;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAKf;AAAA,QACL,MAAMc,IAAa,SAAY;AAAA,QAC/B,cAAYA,IAAa,SAAYD;AAAA,QACrC,kBAAe;AAAA,QACf,WAAWD;AAAA,QACV,GAAGlB;AAAA,QAIF,UAAA;AAAA,WAAAe,KAAgBD,MAAc,CAAC,CAACjC,KAChC,gBAAAyC,EAAC,UAAK,eAAY,QAAQ,UAAAxC,EAAYD,CAAI,EAAA,CAAE;AAAA,UAI7CmC,KACC,gBAAAM;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,eAAY;AAAA,cACZ,SAAQ;AAAA,cACR,WAAU;AAAA,cAEV,UAAA,gBAAAA,EAAC,QAAA,EAAK,GAAE,mHAAA,CAAmH;AAAA,YAAA;AAAA,UAAA;AAAA,UAO9HR,KACC,gBAAAQ;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,KAAA7B;AAAA,cACA,KAAKC,KAAO;AAAA,cACZ,eAAaA,IAAM,SAAY;AAAA,cAC/B,WAAWJ,EAAc,EAAE,OAAAQ,GAAO;AAAA,cAClC,SAAS,MAAMW,EAAY,EAAI;AAAA,YAAA;AAAA,UAAA;AAAA,QACjC;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEAlB,EAAO,cAAc;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"breadcrumb-Bn29NCnf.js","sources":["../../src/components/breadcrumb/breadcrumb.agent.ts","../../src/components/breadcrumb/breadcrumb.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — Breadcrumb. */\n/* */\n/* Breadcrumb is a navigation trail. Items expose their stable route id */\n/* + href ONLY — labels can contain patient names or other PHI and MUST */\n/* NOT be exposed on `data-*` or in adapter state (see PRS §26 §6.1). */\n/* */\n/* See `src/docs/26-agent-readiness.mdx` for the full contract. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { BreadcrumbHandle } from './breadcrumb';\n\nexport interface BreadcrumbAgentItem {\n id: string;\n href?: string;\n}\n\nexport const breadcrumbAgent: AgentAdapter<BreadcrumbHandle> = {\n id: 'breadcrumb',\n capabilities: ['navigate'],\n state: {\n items: {\n type: 'Array<{ id: string, href?: string }>',\n descriptionKey: 'ui.agent.breadcrumb.state.items',\n description:\n 'Ordered list of crumb ids + hrefs in display order. Labels are intentionally excluded — they may contain PHI.',\n read: (handle) => handle.getItems(),\n },\n },\n actions: {\n navigate_to: {\n safety: 'read',\n argsType: '{ id: string }',\n argsSchema: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'Stable opaque crumb id (from getItems).',\n },\n },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.breadcrumb.actions.navigateTo',\n description:\n 'Activate the crumb with the given id — equivalent to clicking the link.',\n examples: [\n { args: { id: '/patients' }, note: 'Navigate to the patients crumb.' },\n ],\n invoke: (handle, args: { id: string }) => {\n handle.navigateTo(args.id);\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'breadcrumb',\n description: 'Marks the Breadcrumb root `<nav>`.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n item: {\n attr: 'data-crumb-id',\n description:\n 'Stable opaque id of a crumb. Labels are NEVER carried in data-* — they may contain PHI.',\n },\n },\n};\n","import {\n Children,\n cloneElement,\n createContext,\n forwardRef,\n isValidElement,\n useContext,\n useImperativeHandle,\n useMemo,\n useRef,\n type AnchorHTMLAttributes,\n type ComponentPropsWithoutRef,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport * as DropdownMenu from '@radix-ui/react-dropdown-menu';\nimport { Slot } from '@radix-ui/react-slot';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { ChevronRight, Ellipsis } from 'lucide-react';\nimport { MENU_ROW_HIGHLIGHT } from '../_shared/menu-row';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { breadcrumbAgent } from './breadcrumb.agent';\n\n/* -------------------------------------------------------------------- */\n/* Context — shares separator variant between siblings */\n/* -------------------------------------------------------------------- */\n\ntype SeparatorVariant = 'chevron' | 'slash';\n\ninterface BreadcrumbContextValue {\n separator: SeparatorVariant;\n}\n\nconst BreadcrumbContext = createContext<BreadcrumbContextValue>({\n separator: 'chevron',\n});\n\n/* -------------------------------------------------------------------- */\n/* Root — <nav aria-label> wrapper + truncation engine */\n/* -------------------------------------------------------------------- */\n\nexport interface BreadcrumbProps extends Omit<\n ComponentPropsWithoutRef<'nav'>,\n 'id'\n> {\n /** Override the default `aria-label` (falls back to translated `ui.navigation.breadcrumb.label`). */\n 'aria-label'?: string;\n /** Separator glyph between items. @default 'chevron' */\n separator?: SeparatorVariant;\n /** Maximum number of visible crumbs before collapsing. @default 4 */\n maxItems?: number;\n /** Items kept visible at the start. @default 1 */\n itemsBeforeCollapse?: number;\n /** Items kept visible at the end. @default 1 */\n itemsAfterCollapse?: number;\n /** If true, disables collapse behaviour. */\n disableCollapse?: boolean;\n /**\n * Consumer-supplied instance id, surfaced as `data-component-id` so an\n * agent / UI bridge can address this instance.\n */\n id?: string;\n}\n\n/**\n * Imperative handle for agent-readiness.\n *\n * Items expose their stable id (`BreadcrumbItem` `id` prop, falling back\n * to the `BreadcrumbLink` href) and href — never their visible label,\n * which may contain PHI (see PRS §26 §6.1).\n */\nexport interface BreadcrumbHandle {\n getItems: () => Array<{ id: string; href?: string }>;\n navigateTo: (id: string) => void;\n}\n\nconst Breadcrumb = forwardRef<HTMLElement, BreadcrumbProps>(\n (\n {\n children,\n className,\n 'aria-label': ariaLabel,\n separator = 'chevron',\n maxItems = 4,\n itemsBeforeCollapse = 1,\n itemsAfterCollapse = 1,\n disableCollapse = false,\n id,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation('ui');\n\n const items = useMemo(() => extractAgentItems(children), [children]);\n\n const handle = useMemo<BreadcrumbHandle>(\n () => ({\n getItems: () => items,\n navigateTo: (targetId: string) => {\n const hit = items.find((i) => i.id === targetId);\n if (!hit?.href) return;\n if (typeof window === 'undefined') return;\n // Same allow-list as the BreadcrumbLink renderer — never honour\n // `javascript:` / `data:` URLs.\n const trimmed = hit.href.trim();\n if (/^\\s*javascript:/i.test(trimmed)) return;\n window.location.assign(trimmed);\n },\n }),\n [items],\n );\n const innerRef = useRef<HTMLElement>(null);\n useImperativeHandle(ref, () => innerRef.current as HTMLElement, []);\n useAgentRegistration(breadcrumbAgent, handle, id);\n\n return (\n <BreadcrumbContext.Provider value={{ separator }}>\n <nav\n ref={innerRef}\n id={id}\n aria-label={ariaLabel ?? t('navigation.breadcrumb.label')}\n data-component=\"breadcrumb\"\n data-component-id={id}\n className={className}\n {...rest}\n >\n <BreadcrumbList\n maxItems={maxItems}\n itemsBeforeCollapse={itemsBeforeCollapse}\n itemsAfterCollapse={itemsAfterCollapse}\n disableCollapse={disableCollapse}\n >\n {children}\n </BreadcrumbList>\n </nav>\n </BreadcrumbContext.Provider>\n );\n },\n);\nBreadcrumb.displayName = 'Breadcrumb';\n\n/**\n * Walks the Breadcrumb children to collect `{ id, href }` for the agent\n * handle. The id is taken from the BreadcrumbItem's `id` prop, falling\n * back to the inner BreadcrumbLink's href (or an index string as a last\n * resort). Labels are never read — they may contain PHI.\n */\nfunction extractAgentItems(\n children: ReactNode,\n): Array<{ id: string; href?: string }> {\n const out: Array<{ id: string; href?: string }> = [];\n let index = 0;\n Children.forEach(children, (child) => {\n if (!isValidElement(child)) return;\n // Only collect Items. Anything else (separators, custom wrappers) is\n // skipped — the agent contract addresses crumbs, not chrome.\n if (child.type !== BreadcrumbItem) return;\n const itemProps = child.props as BreadcrumbItemProps & {\n id?: string;\n children?: ReactNode;\n };\n let href: string | undefined;\n Children.forEach(itemProps.children, (grandchild) => {\n if (href) return;\n if (!isValidElement(grandchild)) return;\n if (grandchild.type !== BreadcrumbLink) return;\n const linkProps = grandchild.props as BreadcrumbLinkProps;\n if (typeof linkProps.href === 'string') href = linkProps.href;\n });\n const id = itemProps.id ?? href ?? String(index);\n out.push({ id, href });\n index += 1;\n });\n return out;\n}\n\n/* -------------------------------------------------------------------- */\n/* List — walks its children, injects separators & ellipsis */\n/* -------------------------------------------------------------------- */\n\nconst listClasses = [\n 'ds:flex ds:flex-wrap ds:items-center',\n 'ds:gap-[var(--spacing-xs)]',\n 'ds:text-[var(--font-size-sm)] ds:text-[var(--muted-foreground)]',\n 'ds:ps-0 ds:m-0',\n 'ds:list-none',\n].join(' ');\n\nexport interface BreadcrumbListProps extends ComponentPropsWithoutRef<'ol'> {\n maxItems?: number;\n itemsBeforeCollapse?: number;\n itemsAfterCollapse?: number;\n disableCollapse?: boolean;\n}\n\nconst BreadcrumbList = forwardRef<HTMLOListElement, BreadcrumbListProps>(\n (\n {\n children,\n className,\n maxItems = 4,\n itemsBeforeCollapse = 1,\n itemsAfterCollapse = 1,\n disableCollapse = false,\n ...rest\n },\n ref,\n ) => {\n const arr = Children.toArray(children).filter((c) =>\n isValidElement(c),\n ) as ReactElement[];\n const total = arr.length;\n\n const shouldCollapse =\n !disableCollapse &&\n total > maxItems &&\n itemsBeforeCollapse + itemsAfterCollapse < total;\n\n // `isCurrent` only goes to components (BreadcrumbItem or a host wrapper\n // that takes it). A plain DOM child such as an `<li>` would pass it to\n // the DOM and React would warn about an unknown prop.\n const renderItem = (child: ReactElement, isLast: boolean, key: string) =>\n typeof child.type === 'string'\n ? cloneElement(child, { key })\n : cloneElement(child, {\n isCurrent: (child.props as BreadcrumbItemProps).isCurrent ?? isLast,\n key,\n } as Partial<BreadcrumbItemProps>);\n\n const renderSeparatorIf = (condition: boolean, key: string) =>\n condition ? <BreadcrumbSeparator key={key} /> : null;\n\n const nodes: ReactNode[] = [];\n if (!shouldCollapse) {\n arr.forEach((child, i) => {\n const isLast = i === total - 1;\n nodes.push(renderItem(child, isLast, `item-${i}`));\n nodes.push(renderSeparatorIf(!isLast, `sep-${i}`));\n });\n } else {\n const before = arr.slice(0, itemsBeforeCollapse);\n const after = arr.slice(total - itemsAfterCollapse);\n const hidden = arr.slice(itemsBeforeCollapse, total - itemsAfterCollapse);\n\n before.forEach((child, i) => {\n nodes.push(renderItem(child, false, `b-${i}`));\n nodes.push(renderSeparatorIf(true, `b-sep-${i}`));\n });\n\n nodes.push(\n <BreadcrumbItem key=\"ellipsis\">\n <BreadcrumbEllipsis hiddenItems={hidden} />\n </BreadcrumbItem>,\n );\n nodes.push(renderSeparatorIf(true, 'ellipsis-sep'));\n\n after.forEach((child, i) => {\n const isLast = i === after.length - 1;\n nodes.push(renderItem(child, isLast, `a-${i}`));\n nodes.push(renderSeparatorIf(!isLast, `a-sep-${i}`));\n });\n }\n\n return (\n <ol\n ref={ref}\n className={[listClasses, className].filter(Boolean).join(' ')}\n {...rest}\n >\n {nodes}\n </ol>\n );\n },\n);\nBreadcrumbList.displayName = 'BreadcrumbList';\n\n/* -------------------------------------------------------------------- */\n/* Item — <li> marks current when `isCurrent` */\n/* -------------------------------------------------------------------- */\n\nconst itemClasses = [\n 'ds:inline-flex ds:flex-wrap ds:items-center',\n 'ds:[min-inline-size:0] ds:[max-inline-size:100%]',\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:py-[var(--spacing-xs)]',\n].join(' ');\n\nexport interface BreadcrumbItemProps extends ComponentPropsWithoutRef<'li'> {\n /** Set automatically by `BreadcrumbList` on the final item. */\n isCurrent?: boolean;\n}\n\nconst BreadcrumbItem = forwardRef<HTMLLIElement, BreadcrumbItemProps>(\n ({ children, className, isCurrent = false, id, ...rest }, ref) => {\n // Derive an agent crumb id: explicit `id` prop, else the inner link's\n // href. Labels are never used — they may contain PHI (PRS §26 §6.1).\n let derived: string | undefined = id;\n if (!derived) {\n Children.forEach(children, (child) => {\n if (derived) return;\n if (!isValidElement(child)) return;\n if (child.type !== BreadcrumbLink) return;\n const linkProps = child.props as BreadcrumbLinkProps;\n if (typeof linkProps.href === 'string') derived = linkProps.href;\n });\n }\n return (\n <li\n ref={ref}\n id={id}\n data-crumb-id={derived}\n className={[itemClasses, className].filter(Boolean).join(' ')}\n {...rest}\n >\n {Children.map(children, (child) =>\n isValidElement(child) &&\n (child.type === BreadcrumbLink ||\n (child.props as { _link?: boolean })?._link)\n ? cloneElement(child as ReactElement<BreadcrumbLinkProps>, {\n isCurrent,\n })\n : child,\n )}\n </li>\n );\n },\n);\nBreadcrumbItem.displayName = 'BreadcrumbItem';\n\n/* -------------------------------------------------------------------- */\n/* Link — renders <a>, or plain text when current */\n/* -------------------------------------------------------------------- */\n\nconst linkClasses = [\n 'ds:inline-flex ds:items-center',\n 'ds:[max-inline-size:16rem]',\n 'ds:overflow-hidden ds:text-ellipsis ds:whitespace-nowrap',\n 'ds:break-normal',\n 'ds:text-[var(--muted-foreground)] ds:no-underline',\n 'ds:hover:text-[var(--foreground)] ds:hover:underline',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:min-h-[var(--min-target-size)] ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)]',\n].join(' ');\n\nconst currentClasses = [\n 'ds:inline-flex ds:items-center',\n 'ds:[max-inline-size:16rem]',\n 'ds:overflow-hidden ds:text-ellipsis ds:whitespace-nowrap',\n 'ds:break-normal',\n 'ds:text-[var(--foreground)] ds:font-[var(--font-weight-semibold)]',\n 'ds:min-h-[var(--min-target-size)] ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)]',\n].join(' ');\n\nexport interface BreadcrumbLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n /** Use Radix `Slot` so consumers can pass a router link. */\n asChild?: boolean;\n /** Set by the parent Item when this is the current page. */\n isCurrent?: boolean;\n}\n\nconst BreadcrumbLink = forwardRef<HTMLAnchorElement, BreadcrumbLinkProps>(\n (\n { asChild = false, isCurrent = false, className, children, ...rest },\n ref,\n ) => {\n const { t } = useTranslation('ui');\n\n if (isCurrent) {\n return (\n <span\n aria-current=\"page\"\n aria-label={\n (rest['aria-label'] as string | undefined) ??\n t('navigation.breadcrumb.current')\n }\n className={[currentClasses, className].filter(Boolean).join(' ')}\n >\n {children}\n </span>\n );\n }\n\n if (asChild) {\n return (\n <Slot\n ref={ref}\n className={[linkClasses, className].filter(Boolean).join(' ')}\n {...rest}\n >\n {children}\n </Slot>\n );\n }\n\n return (\n <a\n ref={ref}\n className={[linkClasses, className].filter(Boolean).join(' ')}\n {...rest}\n >\n {children}\n </a>\n );\n },\n);\nBreadcrumbLink.displayName = 'BreadcrumbLink';\n\n/* -------------------------------------------------------------------- */\n/* Separator */\n/* -------------------------------------------------------------------- */\n\nconst separatorVariants = cva(\n [\n 'ds:inline-flex ds:items-center ds:justify-center',\n 'ds:text-[var(--muted-foreground)]',\n 'ds:ms-[var(--spacing-xs)] ds:me-[var(--spacing-xs)]',\n 'ds:select-none',\n ].join(' '),\n {\n variants: {\n variant: {\n chevron: '',\n slash: '',\n },\n },\n defaultVariants: { variant: 'chevron' },\n },\n);\n\nexport interface BreadcrumbSeparatorProps\n extends\n Omit<ComponentPropsWithoutRef<'li'>, 'children'>,\n VariantProps<typeof separatorVariants> {\n children?: ReactNode;\n}\n\nconst BreadcrumbSeparator = forwardRef<HTMLLIElement, BreadcrumbSeparatorProps>(\n ({ className, variant, children, ...rest }, ref) => {\n const ctx = useContext(BreadcrumbContext);\n const resolved = variant ?? ctx.separator;\n const defaultGlyph =\n resolved === 'slash' ? (\n <span aria-hidden=\"true\">/</span>\n ) : (\n <ChevronRight\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:rtl:-scale-x-100\"\n />\n );\n return (\n <li\n ref={ref}\n aria-hidden=\"true\"\n role=\"presentation\"\n className={separatorVariants({ variant: resolved, className })}\n {...rest}\n >\n {children ?? defaultGlyph}\n </li>\n );\n },\n);\nBreadcrumbSeparator.displayName = 'BreadcrumbSeparator';\n\n/* -------------------------------------------------------------------- */\n/* Ellipsis — opens a Radix DropdownMenu with hidden crumbs */\n/* -------------------------------------------------------------------- */\n\nconst ellipsisTriggerClasses = [\n 'ds:inline-flex ds:items-center ds:justify-center',\n 'ds:min-w-[var(--min-target-size)] ds:min-h-[var(--min-target-size)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:text-[var(--muted-foreground)]',\n 'ds:hover:text-[var(--foreground)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n].join(' ');\n\nconst ellipsisContentClasses = [\n 'ds:z-[var(--z-dropdown)] ds:min-w-[12rem] ds:overflow-hidden',\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-[var(--border)]',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:shadow-[var(--shadow-lg)]',\n 'ds:p-[var(--spacing-xs)]',\n 'ds:animate-in ds:fade-in ds:zoom-in-95 ds:motion-reduce:animate-none',\n].join(' ');\n\nconst ellipsisItemClasses = [\n 'ds:flex ds:items-center',\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:text-[var(--foreground)] ds:cursor-pointer ds:select-none',\n MENU_ROW_HIGHLIGHT.highlighted,\n 'ds:outline-none',\n].join(' ');\n\nexport interface BreadcrumbEllipsisProps extends ComponentPropsWithoutRef<'button'> {\n /** Hidden crumb elements rendered inside the dropdown menu. */\n hiddenItems?: ReactElement[];\n}\n\nconst BreadcrumbEllipsis = forwardRef<\n HTMLButtonElement,\n BreadcrumbEllipsisProps\n>(({ className, hiddenItems = [], ...rest }, ref) => {\n const { t } = useTranslation('ui');\n const showPath = t('navigation.breadcrumb.showPath');\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n ref={ref}\n type=\"button\"\n aria-label={showPath}\n className={[ellipsisTriggerClasses, className]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n <Ellipsis aria-hidden=\"true\" className=\"ds:size-4\" />\n <span className=\"ds:sr-only\">{showPath}</span>\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className={ellipsisContentClasses}\n align=\"start\"\n sideOffset={6}\n >\n {hiddenItems.map((item, i) => {\n // Extract the anchor inside the hidden BreadcrumbItem (if any)\n const linkChild = extractLink(item);\n return (\n <DropdownMenu.Item\n key={`hidden-${i}`}\n asChild\n className={ellipsisItemClasses}\n >\n {linkChild ?? <span>{item}</span>}\n </DropdownMenu.Item>\n );\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n );\n});\nBreadcrumbEllipsis.displayName = 'BreadcrumbEllipsis';\n\n/**\n * Walks a `BreadcrumbItem` to find the first child whose type is\n * `BreadcrumbLink` and returns the link rendered as a plain `<a>` so the\n * dropdown item can adopt its navigational behaviour.\n */\nfunction extractLink(item: ReactElement): ReactElement | null {\n let found: ReactElement | null = null;\n const itemChildren = (item.props as { children?: ReactNode }).children;\n Children.forEach(itemChildren, (child) => {\n if (found) return;\n if (!isValidElement(child)) return;\n if (child.type === BreadcrumbLink) {\n const linkProps = child.props as BreadcrumbLinkProps & {\n children?: ReactNode;\n };\n const href =\n typeof linkProps.href === 'string' ? linkProps.href : undefined;\n const safeHref = href && /^\\s*javascript:/i.test(href) ? undefined : href;\n found = (\n <a\n href={safeHref}\n onClick={\n linkProps.onClick as AnchorHTMLAttributes<HTMLAnchorElement>['onClick']\n }\n >\n {linkProps.children}\n </a>\n );\n }\n });\n return found;\n}\n\nexport {\n Breadcrumb,\n BreadcrumbList,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbSeparator,\n BreadcrumbEllipsis,\n};\n"],"names":["breadcrumbAgent","handle","args","BreadcrumbContext","createContext","Breadcrumb","forwardRef","children","className","ariaLabel","separator","maxItems","itemsBeforeCollapse","itemsAfterCollapse","disableCollapse","id","rest","ref","t","useTranslation","items","useMemo","extractAgentItems","targetId","hit","i","trimmed","innerRef","useRef","useImperativeHandle","useAgentRegistration","jsx","BreadcrumbList","out","index","Children","child","isValidElement","BreadcrumbItem","itemProps","href","grandchild","BreadcrumbLink","linkProps","listClasses","arr","total","shouldCollapse","renderItem","isLast","key","cloneElement","renderSeparatorIf","condition","BreadcrumbSeparator","nodes","before","after","hidden","BreadcrumbEllipsis","itemClasses","isCurrent","derived","_a","linkClasses","currentClasses","asChild","Slot","separatorVariants","cva","variant","ctx","useContext","resolved","defaultGlyph","ChevronRight","ellipsisTriggerClasses","ellipsisContentClasses","ellipsisItemClasses","MENU_ROW_HIGHLIGHT","hiddenItems","showPath","jsxs","DropdownMenu","Ellipsis","item","linkChild","extractLink","found","itemChildren","safeHref"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"command-palette-B3dVqm9D.js","sources":["../../src/components/command-palette/command-palette.agent.ts","../../src/components/command-palette/command-palette.tsx"],"sourcesContent":["import type { AgentAdapter } from '../../agent/types';\nimport type { CommandPaletteHandle } from './command-palette';\n\nexport const commandPaletteAgent: AgentAdapter<CommandPaletteHandle> = {\n id: 'command-palette',\n // The curated handle exposes open/close + the filter query only. Running a\n // highlighted command is internal to the dialog (not on the handle), so no\n // 'submit'/'pick' capability is claimed here.\n capabilities: ['open', 'close', 'filter'],\n state: {\n query: {\n type: 'string',\n descriptionKey: 'ui.agent.commandPalette.state.query',\n description: 'Current filter query in the command palette input.',\n read: (handle) => handle.getQuery(),\n },\n isOpen: {\n type: 'boolean',\n descriptionKey: 'ui.agent.commandPalette.state.isOpen',\n description: 'True when the palette is visible.',\n read: (handle) => handle.getIsOpen(),\n },\n },\n actions: {\n open: {\n safety: 'read',\n idempotent: true,\n descriptionKey: 'ui.agent.commandPalette.actions.open',\n description: 'Open the command palette.',\n invoke: (handle) => {\n handle.open();\n },\n },\n close: {\n safety: 'read',\n idempotent: true,\n descriptionKey: 'ui.agent.commandPalette.actions.close',\n description: 'Close the command palette.',\n invoke: (handle) => {\n handle.close();\n },\n },\n apply_filter: {\n safety: 'read',\n argsType: '{ query: string }',\n argsSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Filter text matched against command labels.',\n },\n },\n required: ['query'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.commandPalette.actions.applyFilter',\n description: 'Set the filter query.',\n invoke: (handle, args: { query: string }) => {\n handle.setQuery(args.query);\n },\n },\n },\n domHooks: {\n root: { attr: 'data-component', value: 'command-palette' },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n item: {\n attr: 'data-command-id',\n description: 'Each command item emits its key as data-command-id.',\n },\n },\n};\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type ElementRef,\n type ReactNode,\n} from 'react';\nimport { Command as CommandPrimitive, defaultFilter } from 'cmdk';\nimport * as RadixDialog from '@radix-ui/react-dialog';\nimport { useTranslation } from 'react-i18next';\nimport { Search } from 'lucide-react';\nimport { MENU_ROW_HIGHLIGHT } from '../_shared/menu-row';\nimport { useAgentRegistration } from '../../agent';\nimport { commandPaletteAgent } from './command-palette.agent';\n\n/* -------------------------------------------------------------------- */\n/* Types */\n/* -------------------------------------------------------------------- */\n\nexport interface Command {\n id: string;\n label: string;\n group: string;\n keywords?: string[];\n shortcut?: string;\n onSelect: () => void;\n /** Optional leading icon. */\n icon?: ReactNode;\n}\n\n/* -------------------------------------------------------------------- */\n/* Diacritic-insensitive normaliser */\n/* -------------------------------------------------------------------- */\n\nfunction normalise(value: string): string {\n return value\n .normalize('NFD')\n .replace(/\\p{Diacritic}/gu, '')\n .toLowerCase();\n}\n\nexport const diacriticInsensitiveFilter = (\n value: string,\n search: string,\n keywords?: string[],\n) =>\n defaultFilter(normalise(value), normalise(search), keywords?.map(normalise));\n\n/* -------------------------------------------------------------------- */\n/* Recents (localStorage, SSR-safe) */\n/* -------------------------------------------------------------------- */\n\nconst RECENTS_KEY = 'ui.cmdk.recents';\nconst MAX_RECENTS = 5;\n\nfunction readRecents(): string[] {\n if (typeof window === 'undefined') return [];\n try {\n const raw = window.localStorage.getItem(RECENTS_KEY);\n if (!raw) return [];\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed)\n ? parsed.slice(0, MAX_RECENTS).filter((v) => typeof v === 'string')\n : [];\n } catch {\n return [];\n }\n}\n\nfunction writeRecents(ids: string[]) {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(\n RECENTS_KEY,\n JSON.stringify(ids.slice(0, MAX_RECENTS)),\n );\n } catch {\n /* noop */\n }\n}\n\n/* -------------------------------------------------------------------- */\n/* useCommandPalette — Cmd/Ctrl+K hook */\n/* -------------------------------------------------------------------- */\n\nexport function useCommandPalette() {\n const [open, setOpen] = useState(false);\n\n useEffect(() => {\n function handler(event: KeyboardEvent) {\n // Cmd/Ctrl+K must work even from inside inputs; check the\n // modifier first and bail on edit-context only for plain keys.\n const isMeta = event.metaKey || event.ctrlKey;\n if (isMeta && event.key === 'k') {\n event.preventDefault();\n setOpen((v) => !v);\n return;\n }\n\n const target = event.target as HTMLElement | null;\n const tag = target?.tagName.toLowerCase();\n const isEditable =\n tag === 'input' || tag === 'textarea' || target?.isContentEditable;\n if (isEditable && !(open && event.key === 'Escape')) return;\n }\n document.addEventListener('keydown', handler);\n return () => document.removeEventListener('keydown', handler);\n }, [open]);\n\n return { open, setOpen };\n}\n\n/* -------------------------------------------------------------------- */\n/* Primitives (forwardRef wrappers around cmdk + dialog chrome) */\n/* -------------------------------------------------------------------- */\n\nconst rootClasses = [\n 'ds:flex ds:h-full ds:w-full ds:flex-col ds:overflow-hidden',\n 'ds:rounded-[var(--radius-md)]',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n].join(' ');\n\nexport type CommandPaletteRootProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive\n>;\n\n// Curated agent-readiness handle — see command-palette.agent.ts.\nexport interface CommandPaletteHandle {\n getQuery: () => string;\n getIsOpen: () => boolean;\n open: () => void;\n close: () => void;\n setQuery: (query: string) => void;\n}\n\nconst CommandPalette = forwardRef<\n ElementRef<typeof CommandPrimitive>,\n CommandPaletteRootProps\n>(({ className, filter = diacriticInsensitiveFilter, id, ...rest }, ref) => (\n <CommandPrimitive\n ref={ref}\n filter={filter}\n className={[rootClasses, className].filter(Boolean).join(' ')}\n data-component=\"command-palette\"\n data-component-id={id}\n {...rest}\n />\n));\nCommandPalette.displayName = 'CommandPalette';\n\n/* -------------------------------------------------------------------- */\n/* Input */\n/* -------------------------------------------------------------------- */\n\nconst inputWrapClasses = [\n 'ds:flex ds:items-center',\n 'ds:border-block-end ds:border-[var(--border)]',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-sm)]',\n].join(' ');\n\nconst inputClasses = [\n 'ds:flex ds:w-full ds:bg-transparent',\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:text-[var(--font-size-base)] ds:text-[var(--foreground)]',\n 'ds:placeholder:text-[var(--muted-foreground)]',\n 'ds:outline-none',\n 'ds:disabled:cursor-not-allowed ds:disabled:opacity-50',\n 'ds:border-0',\n].join(' ');\n\nexport type CommandInputProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive.Input\n>;\n\nconst CommandInput = forwardRef<\n ElementRef<typeof CommandPrimitive.Input>,\n CommandInputProps\n>(({ className, placeholder, ...rest }, ref) => {\n const { t } = useTranslation('ui');\n return (\n <div className={inputWrapClasses}>\n <Search\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:me-2 ds:text-[var(--muted-foreground)]\"\n />\n <CommandPrimitive.Input\n ref={ref}\n placeholder={\n placeholder ??\n t('navigation.cmdk.placeholder', 'Type a command or search\\u2026')\n }\n className={[inputClasses, className].filter(Boolean).join(' ')}\n {...rest}\n />\n </div>\n );\n});\nCommandInput.displayName = 'CommandInput';\n\n/* -------------------------------------------------------------------- */\n/* List / Empty / Group / Item / Separator */\n/* -------------------------------------------------------------------- */\n\nconst CommandList = forwardRef<\n ElementRef<typeof CommandPrimitive.List>,\n ComponentPropsWithoutRef<typeof CommandPrimitive.List>\n>(({ className, ...rest }, ref) => (\n <CommandPrimitive.List\n ref={ref}\n className={[\n 'ds:max-h-[20rem] ds:overflow-y-auto',\n 'ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)]',\n 'ds:py-[var(--spacing-xs)]',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n />\n));\nCommandList.displayName = 'CommandList';\n\nconst CommandEmpty = forwardRef<\n ElementRef<typeof CommandPrimitive.Empty>,\n ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>\n>(({ className, children, ...rest }, ref) => {\n const { t } = useTranslation('ui');\n return (\n <CommandPrimitive.Empty\n ref={ref}\n className={[\n 'ds:py-[var(--spacing-lg)] ds:text-center',\n 'type-body-sm ds:text-[var(--muted-foreground)]',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n {children ?? t('navigation.cmdk.empty', 'No results found')}\n </CommandPrimitive.Empty>\n );\n});\nCommandEmpty.displayName = 'CommandEmpty';\n\nconst CommandGroup = forwardRef<\n ElementRef<typeof CommandPrimitive.Group>,\n ComponentPropsWithoutRef<typeof CommandPrimitive.Group>\n>(({ className, heading, ...rest }, ref) => (\n <CommandPrimitive.Group\n ref={ref}\n heading={heading}\n className={[\n 'ds:overflow-hidden',\n 'ds:text-[var(--foreground)]',\n 'ds:[&_[cmdk-group-heading]]:ps-[var(--spacing-sm)]',\n 'ds:[&_[cmdk-group-heading]]:pe-[var(--spacing-sm)]',\n 'ds:[&_[cmdk-group-heading]]:py-[var(--spacing-xs)]',\n 'ds:[&_[cmdk-group-heading]]:type-eyebrow',\n 'ds:[&_[cmdk-group-heading]]:text-[var(--muted-foreground)]',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n />\n));\nCommandGroup.displayName = 'CommandGroup';\n\nconst itemClasses = [\n 'ds:relative ds:flex ds:items-center',\n 'ds:gap-[var(--spacing-sm)]',\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n 'ds:text-[var(--font-size-sm)] ds:text-[var(--foreground)]',\n 'ds:cursor-pointer ds:select-none ds:outline-none',\n MENU_ROW_HIGHLIGHT.selected,\n 'ds:data-[disabled=true]:pointer-events-none ds:data-[disabled=true]:opacity-50',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n].join(' ');\n\nexport type CommandItemProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive.Item\n>;\n\nconst CommandItem = forwardRef<\n ElementRef<typeof CommandPrimitive.Item>,\n CommandItemProps\n>(({ className, ...rest }, ref) => (\n <CommandPrimitive.Item\n ref={ref}\n className={[itemClasses, className].filter(Boolean).join(' ')}\n {...rest}\n />\n));\nCommandItem.displayName = 'CommandItem';\n\nconst CommandSeparator = forwardRef<\n ElementRef<typeof CommandPrimitive.Separator>,\n ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>\n>(({ className, ...rest }, ref) => (\n <CommandPrimitive.Separator\n ref={ref}\n className={[\n 'ds:-ms-[var(--spacing-xs)] ds:-me-[var(--spacing-xs)]',\n 'ds:my-[var(--spacing-xs)]',\n 'ds:h-px ds:bg-[var(--border)]',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n />\n));\nCommandSeparator.displayName = 'CommandSeparator';\n\nexport type CommandShortcutProps = ComponentPropsWithoutRef<'kbd'>;\n\nconst CommandShortcut = forwardRef<HTMLElement, CommandShortcutProps>(\n ({ className, children, ...rest }, ref) => (\n <kbd\n ref={ref}\n className={[\n 'ds:ms-auto',\n 'ds:inline-flex ds:items-center',\n 'ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)]',\n 'ds:h-5 ds:rounded-[var(--radius-sm)]',\n 'ds:bg-[var(--muted)]/20 ds:text-[var(--muted-foreground)]',\n 'ds:text-[length:var(--font-size-xs)] ds:font-[var(--font-weight-medium)]',\n // On the lit row the chip matches the row fill, so an inset ring\n // keeps it a key cap.\n 'ds:group-data-[selected=true]/menu-row:ring-[length:var(--border-width-sm)] ds:group-data-[selected=true]/menu-row:ring-inset',\n 'ds:group-data-[selected=true]/menu-row:ring-[color:var(--accent-foreground)]',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n {children}\n </kbd>\n ),\n);\nCommandShortcut.displayName = 'CommandShortcut';\n\n/* -------------------------------------------------------------------- */\n/* Highlight helper */\n/* -------------------------------------------------------------------- */\n\n/**\n * Returns React nodes that wrap the matching segments of `label` in `<mark>`.\n * Diacritic-insensitive. No `dangerouslySetInnerHTML`.\n */\nexport function highlightMatch(label: string, query: string): ReactNode {\n if (!query) return label;\n const norm = normalise(label);\n const normQ = normalise(query);\n const idx = norm.indexOf(normQ);\n if (idx === -1) return label;\n // Walk the original label using character-by-character correspondence with the\n // normalised string. Since normalise may drop diacritics, we use index mapping.\n const before = label.slice(0, idx);\n const match = label.slice(idx, idx + normQ.length);\n const after = label.slice(idx + normQ.length);\n return (\n <>\n {before}\n <mark className=\"ds:bg-[var(--accent)]/20 ds:text-inherit ds:rounded-[var(--radius-sm)] ds:px-[0.125em] ds:group-data-[selected=true]/menu-row:bg-transparent ds:group-data-[selected=true]/menu-row:underline\">\n {match}\n </mark>\n {after}\n </>\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* CommandPaletteDialog — Dialog shell + commands-as-data API */\n/* -------------------------------------------------------------------- */\n\nexport interface CommandPaletteDialogProps {\n /** Controlled open state. */\n open: boolean;\n /** Fires when the dialog opens/closes. */\n onOpenChange: (open: boolean) => void;\n /** Commands to display. */\n commands: Command[];\n /** Extra content rendered above the input (optional). */\n header?: ReactNode;\n /** Stable id for agent registration / DOM addressing. */\n id?: string;\n}\n\nconst overlayClasses = [\n 'ds:fixed ds:inset-0 ds:z-[var(--z-modal-backdrop)]',\n 'ds:bg-[var(--background)]/70 ds:backdrop-blur-sm',\n 'ds:data-[state=open]:animate-in ds:data-[state=closed]:animate-out',\n 'ds:data-[state=open]:fade-in ds:data-[state=closed]:fade-out',\n 'ds:motion-reduce:animate-none',\n].join(' ');\n\nconst dialogContentClasses = [\n 'ds:fixed ds:z-[var(--z-modal)]',\n // Logical-inset arbitrary-value positioning: `inset-inline-start-1/2`\n // isn't a real Tailwind class (the generator maps fractions only to\n // `start-*`), so use `start-1/2` for horizontal and `top-*` for the\n // top offset — matching the working Dialog component.\n 'ds:top-[12vh] ds:start-1/2 ds:-translate-x-1/2 ds:rtl:translate-x-1/2',\n 'ds:w-[92vw] ds:max-w-[var(--dialog-width-lg)]',\n 'ds:rounded-[var(--radius-lg)]',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:shadow-[var(--shadow-xl)]',\n 'ds:border ds:border-[var(--border)]',\n 'ds:data-[state=open]:animate-in ds:data-[state=closed]:animate-out',\n 'ds:data-[state=open]:zoom-in-95 ds:data-[state=closed]:zoom-out-95',\n 'ds:motion-reduce:animate-none',\n 'ds:focus:outline-none',\n].join(' ');\n\nconst VisuallyHidden = ({ children }: { children: ReactNode }) => (\n <span className=\"ds:sr-only\">{children}</span>\n);\n\nfunction CommandPaletteDialog({\n open,\n onOpenChange,\n commands,\n header,\n id,\n}: CommandPaletteDialogProps) {\n const { t } = useTranslation('ui');\n const [search, setSearch] = useState('');\n const [recents, setRecents] = useState<string[]>(readRecents);\n\n useEffect(() => {\n if (!open) setSearch('');\n }, [open]);\n\n // Agent handle — refs mirror state for fresh reads from the memoized handle.\n const openRef = useRef(open);\n useEffect(() => {\n openRef.current = open;\n }, [open]);\n const searchRef = useRef(search);\n useEffect(() => {\n searchRef.current = search;\n }, [search]);\n const onOpenChangeRef = useRef(onOpenChange);\n useEffect(() => {\n onOpenChangeRef.current = onOpenChange;\n }, [onOpenChange]);\n\n const agentHandle = useMemo<CommandPaletteHandle>(\n () => ({\n getQuery: () => searchRef.current,\n getIsOpen: () => openRef.current,\n open: () => onOpenChangeRef.current(true),\n close: () => onOpenChangeRef.current(false),\n setQuery: (query) => setSearch(query),\n }),\n [],\n );\n useAgentRegistration(commandPaletteAgent, agentHandle, id);\n\n const grouped = useMemo(() => {\n const byGroup = new Map<string, Command[]>();\n commands.forEach((c) => {\n const list = byGroup.get(c.group) ?? [];\n list.push(c);\n byGroup.set(c.group, list);\n });\n return byGroup;\n }, [commands]);\n\n const recentCommands = useMemo(() => {\n if (search) return [];\n const byId = new Map(commands.map((c) => [c.id, c]));\n return recents.map((id) => byId.get(id)).filter(Boolean) as Command[];\n }, [commands, recents, search]);\n\n const runCommand = useCallback(\n (cmd: Command) => {\n onOpenChange(false);\n const next = [cmd.id, ...recents.filter((id) => id !== cmd.id)].slice(\n 0,\n MAX_RECENTS,\n );\n setRecents(next);\n writeRecents(next);\n // Defer so Dialog unmount doesn't swallow the callback\n setTimeout(() => cmd.onSelect(), 0);\n },\n [recents, onOpenChange],\n );\n\n const clearRecents = useCallback(() => {\n setRecents([]);\n writeRecents([]);\n }, []);\n\n return (\n <RadixDialog.Root open={open} onOpenChange={onOpenChange}>\n <RadixDialog.Portal>\n <RadixDialog.Overlay\n data-component=\"command-palette-overlay\"\n className={overlayClasses}\n />\n <RadixDialog.Content\n data-component=\"command-palette-dialog\"\n className={dialogContentClasses}\n aria-label={t('navigation.cmdk.title', 'Command palette')}\n >\n <RadixDialog.Title asChild>\n <VisuallyHidden>\n {t('navigation.cmdk.title', 'Command palette')}\n </VisuallyHidden>\n </RadixDialog.Title>\n <RadixDialog.Description asChild>\n <VisuallyHidden>\n {t(\n 'navigation.cmdk.description',\n 'Search for commands, pages, and actions',\n )}\n </VisuallyHidden>\n </RadixDialog.Description>\n <CommandPalette\n id={id}\n label={t('navigation.cmdk.title', 'Command palette')}\n >\n {header}\n <CommandInput value={search} onValueChange={setSearch} />\n <CommandList label={t('navigation.cmdk.title', 'Command palette')}>\n <CommandEmpty />\n {recentCommands.length > 0 ? (\n <>\n <CommandGroup\n heading={t('navigation.cmdk.recents', 'Recent')}\n >\n {recentCommands.map((cmd) => (\n <CommandItem\n key={`recent-${cmd.id}`}\n value={`recent-${cmd.label}`}\n data-command-id={cmd.id}\n onSelect={() => runCommand(cmd)}\n >\n {cmd.icon ? (\n <span aria-hidden=\"true\">{cmd.icon}</span>\n ) : null}\n <span>{cmd.label}</span>\n {cmd.shortcut ? (\n <CommandShortcut>{cmd.shortcut}</CommandShortcut>\n ) : null}\n </CommandItem>\n ))}\n <CommandItem\n value=\"__clear-recents\"\n onSelect={clearRecents}\n >\n <span>\n {t(\n 'navigation.cmdk.clearRecents',\n 'Clear recent commands',\n )}\n </span>\n </CommandItem>\n </CommandGroup>\n <CommandSeparator />\n </>\n ) : null}\n {Array.from(grouped.entries()).map(([group, list]) => (\n <CommandGroup key={group} heading={group}>\n {list.map((cmd) => (\n <CommandItem\n key={cmd.id}\n value={cmd.label}\n data-command-id={cmd.id}\n keywords={cmd.keywords}\n onSelect={() => runCommand(cmd)}\n >\n {cmd.icon ? (\n <span aria-hidden=\"true\">{cmd.icon}</span>\n ) : null}\n <span>{highlightMatch(cmd.label, search)}</span>\n {cmd.shortcut ? (\n <CommandShortcut>{cmd.shortcut}</CommandShortcut>\n ) : null}\n </CommandItem>\n ))}\n </CommandGroup>\n ))}\n </CommandList>\n </CommandPalette>\n </RadixDialog.Content>\n </RadixDialog.Portal>\n </RadixDialog.Root>\n );\n}\n\nexport {\n CommandPalette,\n CommandPaletteDialog,\n CommandInput,\n CommandList,\n CommandGroup,\n CommandItem,\n CommandEmpty,\n CommandSeparator,\n CommandShortcut,\n};\n"],"names":["commandPaletteAgent","handle","args","normalise","value","diacriticInsensitiveFilter","search","keywords","defaultFilter","RECENTS_KEY","MAX_RECENTS","readRecents","raw","parsed","v","writeRecents","ids","useCommandPalette","open","setOpen","useState","useEffect","handler","event","target","tag","rootClasses","CommandPalette","forwardRef","className","filter","id","rest","ref","jsx","CommandPrimitive","inputWrapClasses","inputClasses","CommandInput","placeholder","t","useTranslation","jsxs","Search","CommandList","CommandEmpty","children","CommandGroup","heading","itemClasses","MENU_ROW_HIGHLIGHT","CommandItem","CommandSeparator","CommandShortcut","highlightMatch","label","query","norm","normQ","idx","before","match","after","Fragment","overlayClasses","dialogContentClasses","VisuallyHidden","CommandPaletteDialog","onOpenChange","commands","header","setSearch","recents","setRecents","openRef","useRef","searchRef","onOpenChangeRef","agentHandle","useMemo","useAgentRegistration","grouped","byGroup","list","recentCommands","byId","runCommand","useCallback","cmd","next","clearRecents","RadixDialog","group"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"contact-profile-card-jBf9U4At.js","sources":["../../node_modules/lucide-react/dist/esm/icons/banknote.mjs","../../src/components/contact-profile-card/contact-profile-card.agent.ts","../../src/components/contact-profile-card/contact-profile-card.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"20\", height: \"12\", x: \"2\", y: \"6\", rx: \"2\", key: \"9lu3g6\" }],\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"2\", key: \"1c9p78\" }],\n [\"path\", { d: \"M6 12h.01M18 12h.01\", key: \"113zkx\" }]\n];\nconst Banknote = createLucideIcon(\"banknote\", __iconNode);\n\nexport { __iconNode, Banknote as default };\n//# sourceMappingURL=banknote.mjs.map\n","import type { AgentAdapter } from '../../agent/types';\nimport type { ContactProfileCardHandle } from './contact-profile-card';\n\n/* -------------------------------------------------------------------- */\n/* Agent adapter — ContactProfileCard */\n/* */\n/* Read-only adapter. Surfaces the rendered profession field so an */\n/* agent / MCP runtime can resolve \"what kind of practice is this?\" */\n/* without re-parsing the DOM. No actions yet — the card is a passive */\n/* presentation surface; navigation lives on the consumer's page. */\n/* -------------------------------------------------------------------- */\n\nexport const contactProfileCardAgent: AgentAdapter<ContactProfileCardHandle> = {\n id: 'contact-profile-card',\n // Passive presentation surface — only exposes the rendered profession for\n // introspection. No interactive capability is backed by the handle.\n capabilities: [],\n state: {\n profession: {\n type: 'string',\n descriptionKey: 'ui.agent.contactProfileCard.state.profession',\n description:\n 'Profession string the card is currently rendering — undefined when the consumer omitted it.',\n read: (handle) => handle.getProfession(),\n },\n },\n actions: {},\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'contact-profile-card',\n description: 'Marks the ContactProfileCard root region.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","import {\n forwardRef,\n useId,\n useMemo,\n type ComponentPropsWithoutRef,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport {\n Banknote,\n ExternalLink,\n Globe,\n Heart,\n Languages as LanguagesIcon,\n Mail,\n MapPin,\n MessageCircle,\n Phone,\n ShieldCheck,\n Stethoscope,\n type LucideIcon,\n} from 'lucide-react';\nimport { Badge } from '../badge/badge';\nimport { Card } from '../card/card';\nimport { KeyValueList, KeyValuePair } from '../key-value-pair/key-value-pair';\nimport { Link } from '../link/link';\nimport { formatPriceOrFree } from '../_shared/format-price';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { contactProfileCardAgent } from './contact-profile-card.agent';\n\n/* -------------------------------------------------------------------- */\n/* ContactProfileCard */\n/* */\n/* Replaces the bespoke \"Profilo\" / \"Practice info\" cards that every */\n/* AlfaDocs surface composes by hand (booking-website PracticeInfoCard, */\n/* alfascribe operator pages, builders docs example, …). Composes Card */\n/* + KeyValueList + KeyValuePair so the labels share a column (no */\n/* zigzag values) and every row uses the same lucide icon family. */\n/* */\n/* The component is intentionally opinionated: every field is optional, */\n/* but the ORDER, ICONS, and LABELS are owned by the kit. Consumers */\n/* pass the data; the kit owns the visual + i18n. */\n/* */\n/* All visible text flows through `useTranslation('ui')` against the */\n/* `contactProfileCard.*` namespace. */\n/* -------------------------------------------------------------------- */\n\n/* -------------------------------------------------------------------- */\n/* CVA */\n/* -------------------------------------------------------------------- */\n\n// Override the KVP icon colour at the card root so every inner row's\n// leading glyph paints with `--accent` (brand magenta/violet) instead\n// of the default `--muted-foreground`. The ContactProfileCard is a\n// marketing surface — muted icons read as disabled against the\n// otherwise saturated card chrome. Scoped via CSS custom property so\n// only this card's icons shift; standalone KVPs elsewhere keep\n// `--muted-foreground`.\nconst rootVariants = cva(\n 'ds:w-full ds:text-[color:var(--foreground)] ds:[--key-value-pair-icon-color:var(--accent)]',\n {\n variants: {\n // Matches the kit's other `surface` props (Booking, ReviewsPanel).\n // The card itself renders `<Card variant=\"elevated\">` so the\n // `surface=\"flat\"` opt-out is rare — most consumers want the\n // boundary.\n surface: {\n flat: '',\n elevated: '',\n },\n },\n defaultVariants: { surface: 'elevated' },\n },\n);\n\n/* -------------------------------------------------------------------- */\n/* Public types */\n/* -------------------------------------------------------------------- */\n\nexport interface ContactProfileCardAddress {\n /** Display text — already formatted by the consumer (street, postcode, city). */\n line: string;\n /** Optional lat/lng — drives the static-map link + the embedded thumbnail. */\n lat?: number;\n lng?: number;\n}\n\nexport interface ContactProfileCardHandle {\n /** Resolved consumer-supplied data — useful for agent introspection. */\n getProfession: () => string | undefined;\n}\n\nexport interface ContactProfileCardProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'aria-label' | 'children' | 'children'\n> {\n /**\n * Override the localised \"Profilo\" / \"Profile\" heading. Most\n * consumers leave this unset.\n */\n heading?: string;\n /**\n * Free-text intro paragraph rendered above the data rows (e.g.\n * the practice's `bookingDescription` field). When omitted, the\n * card jumps straight into the data rows.\n */\n description?: string;\n\n /* ----- Identity rows ----- */\n\n /** Street + postcode + city, with optional lat/lng for the map link. */\n address?: ContactProfileCardAddress;\n /** Phone number, displayed as-is. Compiled into a `tel:` link. */\n phone?: string;\n /**\n * WhatsApp number — digits only (no `+`, no spaces). Compiled into\n * a `https://wa.me/<number>` link with an optional pre-filled message.\n */\n whatsappNumber?: string;\n /** Optional pre-filled WhatsApp message. Consumer-localised. */\n whatsappMessage?: string;\n /** Public-facing email. Compiled into a `mailto:` link. */\n email?: string;\n /**\n * Practice website. An address without a scheme (`www.example.it`) is\n * linked over `https://`; anything but a web address shows as text.\n */\n website?: string;\n\n /* ----- Embedded map thumbnail ----- */\n\n /**\n * Google Maps Static API key. When provided alongside `address.lat`\n * and `address.lng`, renders a static-map thumbnail at the top of\n * the card — a single one-shot `<img>` fetch, no JS SDK boot, no\n * consent gate needed (the same pattern PracticeResults uses).\n *\n * Without it (or without coords), the card renders info rows only —\n * the address row's \"Open in Google Maps\" link is still emitted as\n * a real `<a>` so the spatial cue isn't lost.\n *\n * Additive — existing consumers that don't pass this prop see the\n * same render as before.\n */\n googleMapsApiKey?: string;\n /**\n * Zoom level for the embedded map thumbnail. Default `14` —\n * neighbourhood-level, shows the pin in context. Ignored when the\n * thumbnail isn't rendered.\n */\n mapZoom?: number;\n\n /* ----- Profile metadata ----- */\n\n /**\n * ISO 639-1 language codes the practice speaks. Rendered as\n * `<Badge variant=\"neutral\">` chips. Each code is auto-resolved\n * into the active locale's native language name via the kit's\n * built-in `languages.<iso>` i18n bundle (18 ISO codes × 18\n * locales). For example `languages={['it', 'en']}` with\n * `i18n.language === 'it'` renders \"Italiano\" + \"Inglese\".\n *\n * Unknown / unbundled codes fall back to the uppercase ISO code\n * (`'xyz'` → `'XYZ'`). To override a specific label — regional\n * dialect, brand-voice variant, codes the kit doesn't ship — pass\n * `languageLabels`.\n */\n languages?: string[];\n /**\n * Override map from ISO code → display label, applied on top of\n * the kit's i18n auto-resolution. Only set when you need a\n * consumer-specific label for a code — the typical case is\n * regional dialect / brand-voice variants / non-ISO codes.\n *\n * Resolution order: `languageLabels[code]` > `t('languages.<code>')`\n * > `code.toUpperCase()`.\n */\n languageLabels?: Record<string, string>;\n /**\n * Insurance / convention strings (consumer-supplied, free text).\n * Rendered as `<Badge variant=\"info\">` chips.\n */\n insurances?: string[];\n /**\n * First-visit price in the smallest currency unit (cents / centesimi).\n * Formatted via `Intl.NumberFormat`; `0` renders the translated word\n * \"Free\". Omit when the consumer doesn't want to show the price.\n */\n firstVisitPriceCents?: number;\n /** ISO-4217 currency code for the price formatter. Defaults to `EUR`. */\n currencyCode?: string;\n /** Profession line — single value or already-joined comma list. */\n profession?: string;\n /** Show the \"expert for anxious patients\" row when true. */\n specializedInFearPatients?: boolean;\n\n /* ----- Telemetry hooks ----- */\n\n /**\n * Fires when the patient clicks the phone link. The kit emits a\n * `track('practice_profile_card_phone_click')` event before\n * invoking this — gate consumer-side analytics on the same event\n * to avoid duplicate fires.\n */\n onPhoneClick?: () => void;\n /** Fires when the patient clicks the WhatsApp link. */\n onWhatsAppClick?: () => void;\n /** Fires when the patient clicks the static-map link. */\n onMapClick?: () => void;\n /** Fires when the patient clicks the email mailto link. */\n onEmailClick?: () => void;\n\n /* ----- Slots ----- */\n\n /**\n * Rendered above the heading — e.g. a `<Avatar>` for the operator\n * variant, or a coloured chip strip. Optional.\n */\n headerSlot?: ReactNode;\n /**\n * Render an arbitrary map widget at the top of the card chrome —\n * replaces the built-in static `<img>` thumbnail that\n * `googleMapsApiKey` would otherwise produce. Use this when you\n * want an interactive map inside the card boundary instead of a\n * fixed image:\n *\n * <ContactProfileCard\n * mapSlot={\n * <PracticeMap practice={practice} googleMapsApiKey={key} />\n * }\n * …\n * />\n *\n * When both `mapSlot` and `googleMapsApiKey` are provided, the slot\n * wins (explicit > implicit). When neither is provided, no map area\n * renders. The slot is unstyled — pass through any container chrome\n * the consumer wants (e.g. a fixed height wrapper). The kit\n * positions it where the static thumbnail would have lived.\n */\n mapSlot?: ReactNode;\n /**\n * Rendered at the end of the card body, below the rows. Use for\n * a \"Book now\" `<Button>` or a \"View full profile\" link.\n */\n footerSlot?: ReactNode;\n\n /* ----- Styling ----- */\n\n /**\n * `'elevated'` (default) wraps the card in `<Card variant=\"elevated\">`\n * for a defined surface — what most consumers want when the card\n * stands alone on a page. `'flat'` drops the Card chrome so the\n * content sits naked — use when an outer card / sheet already\n * provides the boundary (e.g. embedded inside a `<Sheet>` or a\n * parent `<Card.Body>`).\n */\n surface?: 'flat' | 'elevated';\n\n /* ----- a11y ----- */\n\n /** Override the default region aria-label. */\n 'aria-label'?: string;\n /** Agent-readiness consumer id, surfaced as `data-component-id`. */\n id?: string;\n}\n\n/* -------------------------------------------------------------------- */\n/* Helpers */\n/* -------------------------------------------------------------------- */\n\n/** Strip everything except digits + leading `+` for `tel:` URLs. */\nfunction normalisePhone(raw: string): string {\n return raw.replace(/[^\\d+]/g, '');\n}\n\n/** Build the WhatsApp `wa.me` URL. Number must already be digits-only. */\nfunction buildWhatsAppHref(number: string, message?: string): string {\n const base = `https://wa.me/${number}`;\n if (!message) return base;\n return `${base}?text=${encodeURIComponent(message)}`;\n}\n\n/**\n * The website as a link address, or undefined when it is not a web\n * address. Practices often save `www.example.it`, which a link would\n * resolve against the current page, and the field is practice-written,\n * so a `javascript:` value must never become a link.\n */\nfunction websiteHref(website: string): string | undefined {\n const value = website.trim();\n const href = /^[a-z][a-z0-9+.-]*:/i.test(value) ? value : `https://${value}`;\n try {\n const { protocol } = new URL(href);\n return protocol === 'http:' || protocol === 'https:' ? href : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Google Maps search query — works without an API key. */\nfunction buildMapHref(address: ContactProfileCardAddress): string {\n const q = encodeURIComponent(address.line);\n return `https://www.google.com/maps/search/?api=1&query=${q}`;\n}\n\n/* -------------------------------------------------------------------- */\n/* MapThumbStrip — embedded Google Static Maps image */\n/* */\n/* Full-width strip rendered at the top of the card when the consumer */\n/* supplies both `address.lat`/`lng` and `googleMapsApiKey`. Same */\n/* one-shot `<img>` strategy as PracticeResults' StaticMapThumb (no JS */\n/* SDK boot → no consent gate needed), but full-card-width instead of */\n/* a 12rem aside. */\n/* -------------------------------------------------------------------- */\n\ninterface MapThumbStripProps {\n apiKey: string;\n center: { lat: number; lng: number };\n zoom: number;\n altText: string;\n}\n\n/**\n * Resolve the kit's `--map-marker-color` token to a six-character hex\n * string (no leading `#`) for Google Static Maps' `markers=color:` URL\n * parameter, which requires a literal hex value at fetch time.\n *\n * SSR-safe: when `document` is undefined we fall back to the kit's\n * brand violet. Same helper as PracticeResults — keep in sync if you\n * touch one.\n */\nfunction getStaticMapMarkerHex(): string {\n if (typeof document === 'undefined') return '4945a3';\n const raw = getComputedStyle(document.documentElement)\n .getPropertyValue('--map-marker-color')\n .trim();\n const match = /^#?([0-9a-fA-F]{6})$/.exec(raw);\n return match ? match[1] : '4945a3';\n}\n\nfunction MapThumbStrip({ apiKey, center, zoom, altText }: MapThumbStripProps) {\n // 640×192 keeps the asset under Google's 1MP free tier at scale=2\n // (1280×384 actual) and matches the strip's 12rem height at a\n // ~3.33:1 aspect ratio. Marker colour resolves from the kit's\n // `--map-marker-color` token at runtime so the value still lives\n // in `src/tokens/**` per the closed-palette constraint.\n const markerHex = getStaticMapMarkerHex();\n const src =\n `https://maps.googleapis.com/maps/api/staticmap` +\n `?center=${center.lat},${center.lng}` +\n `&zoom=${zoom}` +\n `&size=640x192&scale=2` +\n `&markers=color:0x${markerHex}%7C${center.lat},${center.lng}` +\n `&key=${encodeURIComponent(apiKey)}`;\n return (\n <img\n src={src}\n alt={altText}\n loading=\"lazy\"\n decoding=\"async\"\n width={640}\n height={192}\n className=\"ds:block ds:inline-size-full ds:block-size-[12rem] ds:[object-fit:cover] ds:rounded-[var(--radius-md)]\"\n />\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* Component */\n/* -------------------------------------------------------------------- */\n\nexport const ContactProfileCard = forwardRef<\n HTMLDivElement,\n ContactProfileCardProps\n>(\n (\n {\n heading,\n description,\n address,\n phone,\n whatsappNumber,\n whatsappMessage,\n email,\n website,\n languages,\n languageLabels,\n insurances,\n firstVisitPriceCents,\n currencyCode = 'EUR',\n profession,\n specializedInFearPatients,\n googleMapsApiKey,\n mapZoom = 14,\n onPhoneClick,\n onWhatsAppClick,\n onMapClick,\n onEmailClick,\n headerSlot,\n footerSlot,\n mapSlot,\n surface = 'elevated',\n 'aria-label': ariaLabel,\n id,\n className,\n ...rest\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation('ui');\n const headingId = useId();\n const locale = i18n.language ?? 'en';\n\n const resolvedHeading = heading ?? t('contactProfileCard.heading');\n const resolvedAriaLabel = ariaLabel ?? resolvedHeading;\n\n const formattedPrice = useMemo(() => {\n if (firstVisitPriceCents == null) return undefined;\n // 0 is a free first visit: the chip reads \"Free\", not \"€0.00\".\n return formatPriceOrFree(\n firstVisitPriceCents,\n currencyCode,\n locale,\n t('common.freeOfCharge'),\n );\n }, [firstVisitPriceCents, currencyCode, locale, t]);\n\n // Compose the rows in display order. Each `row` carries the icon +\n // localised label + the rendered value. Skipping a field is just\n // omitting the row — `KeyValueList` collapses the subgrid cleanly.\n const rows: Array<{\n key: string;\n icon: ReactElement;\n label: string;\n value: ReactNode;\n }> = [];\n\n if (address) {\n rows.push({\n key: 'address',\n icon: <MapPin aria-hidden=\"true\" />,\n label: t('contactProfileCard.label.address'),\n value: (\n <span className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <span dir=\"auto\">{address.line}</span>\n {address.lat != null && address.lng != null ? (\n <Link\n href={buildMapHref(address)}\n external\n intent=\"default\"\n onClick={onMapClick}\n >\n {t('contactProfileCard.openInGoogleMaps')}\n </Link>\n ) : null}\n </span>\n ),\n });\n }\n\n if (phone) {\n rows.push({\n key: 'phone',\n icon: <Phone aria-hidden=\"true\" />,\n label: t('contactProfileCard.label.phone'),\n value: (\n <Link\n href={`tel:${normalisePhone(phone)}`}\n intent=\"default\"\n onClick={onPhoneClick}\n >\n <bdi dir=\"ltr\">{phone}</bdi>\n </Link>\n ),\n });\n }\n\n if (whatsappNumber) {\n rows.push({\n key: 'whatsapp',\n icon: <MessageCircle aria-hidden=\"true\" />,\n label: t('contactProfileCard.label.whatsapp'),\n value: (\n <Link\n href={buildWhatsAppHref(whatsappNumber, whatsappMessage)}\n external\n intent=\"default\"\n onClick={onWhatsAppClick}\n >\n <bdi dir=\"ltr\">{whatsappNumber}</bdi>\n </Link>\n ),\n });\n }\n\n if (email) {\n rows.push({\n key: 'email',\n icon: <Mail aria-hidden=\"true\" />,\n label: t('contactProfileCard.label.email'),\n value: (\n <Link\n href={`mailto:${email}`}\n intent=\"default\"\n onClick={onEmailClick}\n >\n <bdi dir=\"ltr\">{email}</bdi>\n </Link>\n ),\n });\n }\n\n if (website) {\n const href = websiteHref(website);\n rows.push({\n key: 'website',\n icon: <Globe aria-hidden=\"true\" />,\n label: t('contactProfileCard.label.website'),\n value: href ? (\n <Link href={href} external intent=\"default\">\n <bdi dir=\"ltr\">{website}</bdi>\n </Link>\n ) : (\n <bdi dir=\"ltr\">{website}</bdi>\n ),\n });\n }\n\n if (languages && languages.length > 0) {\n // Resolution order, highest to lowest:\n // 1. consumer `languageLabels` override — for regional dialects,\n // brand-voice variants, or codes the kit doesn't ship.\n // 2. kit i18n bundle (`languages.<iso>`) — auto-resolves the 18\n // ISO codes the kit ships into the active locale's native\n // language name. Retires consumer-side ISO→label plumbing.\n // 3. uppercase fallback for unknown codes that the consumer\n // didn't override.\n const resolveLabel = (code: string): string => {\n if (languageLabels?.[code]) return languageLabels[code];\n const key = `languages.${code}`;\n if (i18n.exists(key)) return t(key);\n return code.toUpperCase();\n };\n rows.push({\n key: 'languages',\n icon: <LanguagesIcon aria-hidden=\"true\" />,\n label: t('contactProfileCard.label.languages'),\n value: (\n <span className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-2xs)]\">\n {languages.map((code) => (\n <Badge key={code} variant=\"neutral\">\n {resolveLabel(code)}\n </Badge>\n ))}\n </span>\n ),\n });\n }\n\n if (insurances && insurances.length > 0) {\n rows.push({\n key: 'insurances',\n icon: <ShieldCheck aria-hidden=\"true\" />,\n label: t('contactProfileCard.label.insurances'),\n value: (\n <span className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-2xs)]\">\n {insurances.map((ins) => (\n <Badge key={ins} variant=\"info\">\n {ins}\n </Badge>\n ))}\n </span>\n ),\n });\n }\n\n if (formattedPrice) {\n // The one figure on this card a patient compares between\n // practices, so it gets a chip. The chip starts in the value\n // column with every other row's value (the subgrid aligns them),\n // not pinned to the row's end, where it read as out of line.\n // `accentSoft`, not `brand`. The languages and insurance rows on\n // this card are tonal chips (`neutral` and `info`), so a solid\n // `brand` fill would read as a different class of object rather\n // than the same family. `accentSoft` is the same tonal recipe in\n // the most distinct hue on the card, so the price still leads.\n // `lg` because `md` sets the label at the smallest step of the\n // ramp, and `.theme-accessible` cannot lift it — the one figure\n // patients compare should not be the smallest text on the card.\n rows.push({\n key: 'firstVisitPrice',\n icon: <Banknote aria-hidden=\"true\" />,\n label: t('contactProfileCard.label.firstVisitPrice'),\n value: (\n <Badge variant=\"accentSoft\" size=\"lg\">\n {formattedPrice}\n </Badge>\n ),\n });\n }\n\n if (specializedInFearPatients) {\n rows.push({\n key: 'expertForAnxiousPatients',\n icon: <Heart aria-hidden=\"true\" />,\n label: t('contactProfileCard.label.expertForAnxiousPatients'),\n value: t('contactProfileCard.value.yesShort'),\n });\n }\n\n if (profession) {\n rows.push({\n key: 'profession',\n icon: <Stethoscope aria-hidden=\"true\" />,\n label: t('contactProfileCard.label.profession'),\n value: profession,\n });\n }\n\n // Imperative handle for agent integrations.\n useAgentRegistration(\n contactProfileCardAgent,\n { getProfession: () => profession },\n id,\n );\n\n // Embedded static-map thumbnail. Renders only when the consumer\n // supplies BOTH a usable lat/lng pair AND a `googleMapsApiKey`.\n // The d.ts-promised behaviour; without a key the strip is silently\n // omitted and the address row's \"Open in Google Maps\" link still\n // emits as the spatial-cue fallback.\n const showMapThumb =\n !!googleMapsApiKey &&\n address?.lat !== undefined &&\n address?.lng !== undefined;\n const mapThumb = showMapThumb ? (\n <MapThumbStrip\n apiKey={googleMapsApiKey!}\n center={{ lat: address!.lat!, lng: address!.lng! }}\n zoom={mapZoom}\n altText={t('contactProfileCard.map.alt', {\n address: address!.line,\n defaultValue: 'Map showing {{address}}',\n })}\n />\n ) : null;\n\n // Map area: explicit consumer slot wins over the implicit\n // googleMapsApiKey-driven static thumbnail. 0.33.4 introduces the\n // slot so consumers can embed an interactive <MapView> /\n // <PracticeMap> wrapper inside the card chrome instead of the\n // fixed static <img>. When neither is set the area renders as\n // nothing. 0.33.6 moves the area from above the heading to below\n // the data rows — the map reads as the spatial closer (\"here it\n // is on the map\") rather than a stylised hero, and any CTA in\n // footerSlot still lands at the very bottom.\n const mapArea = mapSlot ?? mapThumb;\n\n const body = (\n <>\n {description ? (\n <p dir=\"auto\" className=\"type-body-sm ds:m-0 ds:whitespace-pre-line\">\n {description}\n </p>\n ) : null}\n {rows.length > 0 ? (\n <KeyValueList rowGap=\"md\">\n {rows.map((row) => (\n <KeyValuePair\n key={row.key}\n icon={row.icon}\n label={row.label}\n value={row.value}\n />\n ))}\n </KeyValueList>\n ) : null}\n {mapArea}\n {footerSlot}\n </>\n );\n\n // `surface=\"flat\"` skips the Card wrapper — the consumer is\n // already inside a Card / Sheet and doesn't want a double border.\n const inner = (\n <>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {headerSlot}\n <h2\n id={headingId}\n className=\"type-title-card ds:m-0 ds:text-[color:var(--foreground)]\"\n >\n {resolvedHeading}\n </h2>\n </div>\n {body}\n </>\n );\n\n return (\n <div\n ref={ref}\n role=\"region\"\n aria-label={resolvedAriaLabel}\n aria-labelledby={headingId}\n data-component=\"contact-profile-card\"\n data-component-id={id}\n id={id}\n className={rootVariants({ surface, className })}\n {...rest}\n >\n {surface === 'elevated' ? (\n <Card variant=\"elevated\">\n <Card.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n {inner}\n </Card.Body>\n </Card>\n ) : (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n {inner}\n </div>\n )}\n </div>\n );\n },\n);\n\nContactProfileCard.displayName = 'ContactProfileCard';\n\n// Helper export so consumers can mirror the kit's row order if they\n// need to compose a partial alternative (rare).\nexport const CONTACT_PROFILE_CARD_ROW_KEYS = [\n 'address',\n 'phone',\n 'whatsapp',\n 'email',\n 'website',\n 'languages',\n 'insurances',\n 'firstVisitPrice',\n 'expertForAnxiousPatients',\n 'profession',\n] as const;\n\n// Defensive icon export so consumers can render the same glyph\n// outside the card if they need it for consistency.\nexport const CONTACT_PROFILE_CARD_ROW_ICONS: Record<\n (typeof CONTACT_PROFILE_CARD_ROW_KEYS)[number],\n LucideIcon\n> = {\n address: MapPin,\n phone: Phone,\n whatsapp: MessageCircle,\n email: Mail,\n website: Globe,\n languages: LanguagesIcon,\n insurances: ShieldCheck,\n firstVisitPrice: Banknote,\n expertForAnxiousPatients: Heart,\n profession: Stethoscope,\n};\n\n// Re-exports of the rootVariants type for downstream typing.\nexport type ContactProfileCardSurface = NonNullable<\n VariantProps<typeof rootVariants>['surface']\n>;\n\n// ExternalLink is exported by lucide-react and used elsewhere in the\n// kit; re-exporting here so consumers don't have to add it as a\n// peer-dep import for icon parity in their own UIs.\nexport { ExternalLink };\n"],"names":["__iconNode","Banknote","createLucideIcon","contactProfileCardAgent","handle","rootVariants","cva","normalisePhone","raw","buildWhatsAppHref","number","message","base","websiteHref","website","value","href","protocol","buildMapHref","address","getStaticMapMarkerHex","match","MapThumbStrip","apiKey","center","zoom","altText","markerHex","src","jsx","ContactProfileCard","forwardRef","heading","description","phone","whatsappNumber","whatsappMessage","email","languages","languageLabels","insurances","firstVisitPriceCents","currencyCode","profession","specializedInFearPatients","googleMapsApiKey","mapZoom","onPhoneClick","onWhatsAppClick","onMapClick","onEmailClick","headerSlot","footerSlot","mapSlot","surface","ariaLabel","id","className","rest","ref","t","i18n","useTranslation","headingId","useId","locale","resolvedHeading","resolvedAriaLabel","formattedPrice","useMemo","formatPriceOrFree","rows","MapPin","jsxs","Link","Phone","MessageCircle","Mail","Globe","resolveLabel","code","key","LanguagesIcon","Badge","ShieldCheck","ins","Heart","Stethoscope","useAgentRegistration","mapThumb","mapArea","body","Fragment","KeyValueList","row","KeyValuePair","inner","Card","CONTACT_PROFILE_CARD_ROW_KEYS","CONTACT_PROFILE_CARD_ROW_ICONS"],"mappings":"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","x_google_ignoreList":[0]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"copy-field-hgVSc51W.js","sources":["../../src/components/copy-field/copy-field.agent.ts","../../src/components/copy-field/copy-field.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — CopyField. */\n/* */\n/* See `src/docs/26-agent-readiness.mdx` for the contract. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\n\n/**\n * Imperative handle for CopyField — agents can read the value and trigger a\n * programmatic copy. State stays scoped to identifiers + transient UI state;\n * never PHI (per PRS §Security).\n */\nexport interface CopyFieldHandle {\n /** Returns the read-only value currently displayed. */\n getValue: () => string;\n /** Triggers the clipboard write side-effect. */\n copy: () => Promise<boolean>;\n /** Returns true for the brief window after a successful copy. */\n isCopied: () => boolean;\n}\n\nexport const copyFieldAgent: AgentAdapter<CopyFieldHandle> = {\n id: 'copy-field',\n capabilities: ['copy'],\n state: {\n value: {\n type: 'string',\n descriptionKey: 'ui.agent.copyField.state.value',\n description: 'The value displayed in the read-only field.',\n read: (handle) => handle.getValue(),\n },\n copied: {\n type: 'boolean',\n descriptionKey: 'ui.agent.copyField.state.copied',\n description: 'True for the brief window after a successful copy.',\n read: (handle) => handle.isCopied(),\n },\n },\n actions: {\n copy: {\n // Writes the value to the system clipboard — reaches outside this UI.\n safety: 'write',\n openWorld: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the clipboard write succeeded.',\n },\n descriptionKey: 'ui.agent.copyField.actions.copy',\n description: 'Programmatically trigger the clipboard write.',\n invoke: (handle) => handle.copy(),\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'copy-field',\n description:\n 'Marks the CopyField root. The trailing button uses `aria-label` keyed off the copy / copied state.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop, when provided.',\n },\n },\n};\n","import {\n forwardRef,\n useCallback,\n useEffect,\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 { Check, Copy } from 'lucide-react';\nimport { Button } from '../button/button';\nimport { useAgentRegistration } from '../../agent';\nimport { useCopyToClipboard } from '../../hooks/use-copy-to-clipboard';\nimport { copyFieldAgent, type CopyFieldHandle } from './copy-field.agent';\n\n/* ------------------------------------------------------------------ */\n/* Clipboard helper */\n/* */\n/* `navigator.clipboard.writeText` is the modern path. The fallback */\n/* covers older browsers and insecure contexts via a synthesised */\n/* textarea + `document.execCommand('copy')`. The off-screen position */\n/* uses imperative DOM `.style` assignments — those are NOT JSX inline */\n/* styles and don't violate constraint §3. */\n/* ------------------------------------------------------------------ */\n\nasync function copyToClipboard(text: string): Promise<boolean> {\n if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch {\n // fall through to legacy path\n }\n }\n if (typeof document === 'undefined') return false;\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.setAttribute('readonly', '');\n // Imperative DOM style — not a JSX inline-style violation. We use\n // `setProperty('inset-inline-start', …)` so the hidden textarea stays\n // logically off-screen in both LTR and RTL contexts.\n textarea.style.position = 'absolute';\n textarea.style.setProperty('inset-inline-start', '-9999px');\n document.body.appendChild(textarea);\n textarea.select();\n let ok = false;\n try {\n ok = document.execCommand('copy');\n } catch {\n ok = false;\n }\n document.body.removeChild(textarea);\n return ok;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA — outer wrapper */\n/* */\n/* Mirrors the shared input-surface chrome (border + halo shadow) so */\n/* CopyField sits inline next to TextInput / Combobox in forms without */\n/* visual drift. Logical paddings only. `ds:focus-within` paints the */\n/* ring when the trailing button or the embedded input receives focus. */\n/* ------------------------------------------------------------------ */\n\nconst fieldVariants = cva(\n [\n 'ds:inline-flex ds:items-stretch ds:w-full',\n 'ds:rounded-[var(--radius-sm)] ds:bg-input ds:text-foreground',\n 'ds:border ds:border-[color:var(--control-border)]',\n 'ds:shadow-[var(--shadow-input)]',\n 'ds:focus-within:outline-[length:var(--focus-ring-width)] ds:focus-within:outline-solid',\n 'ds:focus-within:outline-ring ds:focus-within:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-within:outline-[CanvasText]',\n 'ds:transition-[colors,box-shadow] ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:overflow-hidden',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:h-8 ds:text-[var(--font-size-sm)]',\n md: 'ds:h-[var(--min-target-size)] ds:text-[var(--font-size-base)]',\n lg: 'ds:h-12 ds:text-[var(--font-size-lg)]',\n },\n disabled: {\n true: 'ds:opacity-50 ds:cursor-not-allowed',\n false: '',\n },\n },\n defaultVariants: { size: 'md', disabled: false },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* CVA — value <input> styling */\n/* ------------------------------------------------------------------ */\n\nconst valueVariants = cva(\n [\n 'ds:flex-1 ds:min-w-0 ds:bg-transparent ds:border-0 ds:outline-none',\n 'ds:text-foreground',\n 'ds:disabled:cursor-not-allowed',\n ].join(' '),\n {\n variants: {\n intent: {\n default: '',\n // `--primary` is calibrated for foreground use (violet-500 light,\n // magenta-500 dark) — both pass AA against their input backgrounds.\n primary: 'ds:text-primary ds:font-medium',\n },\n size: {\n sm: 'ds:text-[var(--font-size-sm)]',\n md: 'ds:text-[var(--font-size-base)]',\n lg: 'ds:text-[var(--font-size-lg)]',\n },\n wrap: {\n true: 'ds:[overflow-wrap:anywhere] ds:whitespace-normal',\n false: 'ds:overflow-hidden ds:text-ellipsis ds:whitespace-nowrap',\n },\n hasStartIcon: {\n true: '',\n false: '',\n },\n },\n // Explicit pairs decide the leading padding — single ps-* per cell, so\n // there's no fight between size + hasStartIcon under Tailwind's flat\n // utility precedence.\n compoundVariants: [\n { size: 'sm', hasStartIcon: false, class: 'ds:ps-[var(--spacing-sm)]' },\n { size: 'md', hasStartIcon: false, class: 'ds:ps-[var(--spacing-sm)]' },\n { size: 'lg', hasStartIcon: false, class: 'ds:ps-[var(--spacing-md)]' },\n { size: 'sm', hasStartIcon: true, class: 'ds:ps-[var(--spacing-xs)]' },\n { size: 'md', hasStartIcon: true, class: 'ds:ps-[var(--spacing-xs)]' },\n { size: 'lg', hasStartIcon: true, class: 'ds:ps-[var(--spacing-sm)]' },\n ],\n defaultVariants: {\n intent: 'default',\n size: 'md',\n wrap: false,\n hasStartIcon: false,\n },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Leading icon slot */\n/* ------------------------------------------------------------------ */\n\nconst startIconVariants = cva(\n [\n 'ds:inline-flex ds:items-center ds:justify-center ds:shrink-0',\n 'ds:text-muted-foreground',\n 'ds:[&_svg]:size-4',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:ps-[var(--spacing-sm)]',\n md: 'ds:ps-[var(--spacing-sm)]',\n lg: 'ds:ps-[var(--spacing-md)]',\n },\n },\n defaultVariants: { size: 'md' },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Trailing button wrapper */\n/* */\n/* The button visually attaches to the field by removing its own focus */\n/* ring (the wrapper paints `focus-within`) and rounding only the */\n/* trailing inline-end corners. */\n/* ------------------------------------------------------------------ */\n\nconst copyButtonVariants = cva(\n [\n 'ds:shrink-0 ds:rounded-none',\n 'ds:focus-visible:outline-none',\n 'ds:h-full',\n 'ds:gap-[var(--spacing-xs)]',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Props */\n/* ------------------------------------------------------------------ */\n\ntype FieldSize = NonNullable<VariantProps<typeof fieldVariants>['size']>;\ntype ValueIntent = NonNullable<VariantProps<typeof valueVariants>['intent']>;\n\nexport interface CopyFieldProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'children' | 'onCopy'\n> {\n /** The value displayed in the read-only field and copied on click. */\n value: string;\n /** Field height + padding. Mirrors TextInput sizes. */\n size?: FieldSize;\n /**\n * `primary` tints the value text with `--primary` — matches the\n * link-style emphasis used by the telehealth showSession page.\n */\n intent?: ValueIntent;\n /**\n * Leading icon slot, decorative. Use `lucide-react` icons like\n * `<Link2 />` for a URL, `<KeyRound />` for a token.\n */\n startIcon?: ReactNode;\n /**\n * `false` (default) truncates long values with ellipsis on a single\n * line. `true` allows wrap with `overflow-wrap: anywhere`.\n */\n wrap?: boolean;\n /** Override the default 'Copy' button label. */\n copyLabel?: ReactNode;\n /** Override the default 'Copied' success-state label. */\n copiedLabel?: ReactNode;\n /** Milliseconds before the button reverts to its default state. Default 2000. */\n copiedDuration?: number;\n /** ARIA label for the read-only textbox. Defaults to the i18n key. */\n ariaLabel?: string;\n /** Fires once after a successful clipboard write. */\n onCopy?: (value: string) => void;\n /** Greys both the field and the button; the button doesn't fire onCopy. */\n disabled?: boolean;\n}\n\n/* ------------------------------------------------------------------ */\n/* CopyField */\n/* ------------------------------------------------------------------ */\n\nexport const CopyField = forwardRef<HTMLDivElement, CopyFieldProps>(\n (\n {\n value,\n size = 'md',\n intent = 'default',\n startIcon,\n wrap = false,\n copyLabel,\n copiedLabel,\n copiedDuration = 2000,\n ariaLabel,\n onCopy,\n disabled = false,\n className,\n id,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation('ui');\n\n const valueRef = useRef(value);\n valueRef.current = value;\n const onCopyRef = useRef(onCopy);\n onCopyRef.current = onCopy;\n\n // Drive status + auto-reset from the shared hook. The custom `writer`\n // preserves CopyField's legacy `document.execCommand('copy')` fallback\n // for non-HTTPS / older-browser contexts.\n const { status, copy } = useCopyToClipboard({\n resetAfterMs: copiedDuration,\n writer: copyToClipboard,\n });\n const copied = status === 'copied';\n const copiedRef = useRef(false);\n copiedRef.current = copied;\n\n // i18n-aware live-region text mirrors the hook status — `copied` →\n // success message, `error` → failure message, `idle` → clear.\n const [liveRegionText, setLiveRegionText] = useState('');\n useEffect(() => {\n if (status === 'copied') {\n setLiveRegionText(t('copyField.copySuccess'));\n } else if (status === 'error') {\n setLiveRegionText(t('copyField.copyFailed'));\n } else {\n setLiveRegionText('');\n }\n }, [status, t]);\n\n const handleCopy = useCallback(async (): Promise<boolean> => {\n if (disabled) return false;\n const ok = await copy(valueRef.current);\n if (ok) onCopyRef.current?.(valueRef.current);\n return ok;\n }, [disabled, copy]);\n\n const handleButtonClick = useCallback(() => {\n void handleCopy();\n }, [handleCopy]);\n\n /* -------------------------------------------------------------- */\n /* Agent handle — read value + trigger copy + check transient state */\n /* -------------------------------------------------------------- */\n\n const agentHandle = useMemo<CopyFieldHandle>(\n () => ({\n getValue: () => valueRef.current,\n copy: () => handleCopy(),\n isCopied: () => copiedRef.current,\n }),\n [handleCopy],\n );\n useAgentRegistration(copyFieldAgent, agentHandle, id);\n\n const resolvedAriaLabel = ariaLabel ?? t('copyField.valueLabel');\n const resolvedCopyText = copyLabel ?? t('copyField.copy');\n const resolvedCopiedText = copiedLabel ?? t('copyField.copied');\n // `aria-label` must be a string; when the consumer passes a non-string\n // ReactNode for copyLabel / copiedLabel we fall back to the translated\n // default so AT users still hear a coherent name.\n const buttonAccessibleLabel = copied\n ? typeof resolvedCopiedText === 'string'\n ? resolvedCopiedText\n : t('copyField.copied')\n : typeof resolvedCopyText === 'string'\n ? resolvedCopyText\n : t('copyField.copy');\n\n return (\n <div\n ref={ref}\n className={fieldVariants({ size, disabled, className })}\n data-component=\"copy-field\"\n data-component-id={id}\n data-copied={copied ? 'true' : undefined}\n {...rest}\n >\n {startIcon ? (\n <span aria-hidden=\"true\" className={startIconVariants({ size })}>\n {startIcon}\n </span>\n ) : null}\n <input\n id={id}\n type=\"text\"\n readOnly\n value={value}\n disabled={disabled}\n aria-label={resolvedAriaLabel}\n className={valueVariants({\n intent,\n size,\n wrap,\n hasStartIcon: Boolean(startIcon),\n })}\n />\n <Button\n type=\"button\"\n intent=\"ghost\"\n size={size}\n onClick={handleButtonClick}\n disabled={disabled}\n aria-label={buttonAccessibleLabel}\n className={copyButtonVariants()}\n startIcon={\n copied ? <Check aria-hidden=\"true\" /> : <Copy aria-hidden=\"true\" />\n }\n >\n <span className=\"type-label\">\n {copied ? resolvedCopiedText : resolvedCopyText}\n </span>\n </Button>\n <span role=\"status\" aria-live=\"polite\" className=\"ds:sr-only\">\n {liveRegionText}\n </span>\n </div>\n );\n },\n);\n\nCopyField.displayName = 'CopyField';\n"],"names":["copyFieldAgent","handle","copyToClipboard","text","_a","textarea","ok","fieldVariants","cva","valueVariants","startIconVariants","copyButtonVariants","CopyField","forwardRef","value","size","intent","startIcon","wrap","copyLabel","copiedLabel","copiedDuration","ariaLabel","onCopy","disabled","className","id","rest","ref","useTranslation","valueRef","useRef","onCopyRef","status","copy","useCopyToClipboard","copied","copiedRef","liveRegionText","setLiveRegionText","useState","useEffect","handleCopy","useCallback","handleButtonClick","agentHandle","useMemo","useAgentRegistration","resolvedAriaLabel","resolvedCopyText","resolvedCopiedText","buttonAccessibleLabel","jsxs","jsx","Button","Check","Copy"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"document-scanner-BQP0Rqrt.js","sources":["../../src/components/document-scanner/document-scanner.agent.ts","../../src/components/document-scanner/document-scanner.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — DocumentScanner. */\n/* */\n/* State exposes only structural lifecycle info — never the captured */\n/* image bytes (PHI). Actions drive the camera + capture flow. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { DocumentScannerHandle } from './document-scanner';\n\nexport const documentScannerAgent: AgentAdapter<DocumentScannerHandle> = {\n id: 'document-scanner',\n capabilities: ['capture', 'submit'],\n state: {\n hasCapture: {\n type: 'boolean',\n descriptionKey: 'documentScanner.agent.state.hasCapture',\n description: 'True when a captured or uploaded image is available.',\n read: (handle) => handle.hasCapture(),\n },\n phase: {\n type: 'string',\n descriptionKey: 'documentScanner.agent.state.phase',\n description:\n \"Lifecycle phase: 'idle' | 'requesting' | 'streaming' | 'captured' | 'error'.\",\n read: (handle) => handle.getPhase(),\n },\n },\n actions: {\n start_camera: {\n safety: 'write',\n idempotent: true,\n descriptionKey: 'documentScanner.agent.actions.startCamera',\n description: 'Request camera permission and begin the live viewfinder.',\n errors: [\n 'permission-denied',\n 'no-camera',\n 'not-readable',\n 'insecure-context',\n ],\n invoke: (handle) => handle.startCamera(),\n },\n capture: {\n safety: 'write',\n descriptionKey: 'documentScanner.agent.actions.capture',\n description: 'Freeze the current viewfinder frame as a captured image.',\n errors: ['capture-failed'],\n invoke: (handle) => handle.capture(),\n },\n submit: {\n safety: 'write',\n descriptionKey: 'documentScanner.agent.actions.confirm',\n description: 'Confirm the current capture, emitting it via onConfirm.',\n invoke: (handle) => {\n handle.confirm();\n },\n },\n retake: {\n safety: 'destructive',\n descriptionKey: 'documentScanner.agent.actions.retake',\n description:\n 'Discard the current capture and return to the capture path.',\n invoke: (handle) => {\n handle.retake();\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'document-scanner',\n description: 'Marks the DocumentScanner wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* DocumentScanner — patient check-in ID-document capture. */\n/* */\n/* - Native MediaDevices: a live <video autoplay playsinline muted> */\n/* viewfinder via getUserMedia({ video: { facingMode } }), an */\n/* offscreen <canvas> for the freeze-frame / crop draw, and an <img> */\n/* for the captured preview. No third-party dependency for capture. */\n/* - Upload fallback: the existing kit FileUpload (variant='button') */\n/* handles accept / maxSize / reject and is ALWAYS reachable — even */\n/* on a hard camera error it is the recovery path (per HTP-5113). */\n/* - Lifecycle: the camera starts only on an explicit user gesture and */\n/* every MediaStreamTrack is stopped on unmount, on capture, on */\n/* error, on Escape, and on document visibilitychange→hidden so the */\n/* camera LED is released (privacy + battery). Mirrors */\n/* audio-recorder's teardown pattern. */\n/* - Confirm payload: { dataUrl, blob, source, width, height, mimeType, */\n/* byteSize, capturedAt (ISO-8601), sha256 }. sha256 is the */\n/* SubtleCrypto digest of the encoded bytes — tamper-evident for */\n/* audit, matching signature-capture. Document-only: no selfie, no */\n/* liveness, no OCR / MRZ / auto-crop (out of scope, would need a */\n/* separate 08-third-party dependency). */\n/* - Security: no fetch / XHR / localStorage / sessionStorage / globals */\n/* in this file — the captured ID document is PHI and the consumer */\n/* owns persistence + the \"already on file → skip\" decision. */\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Camera, RotateCcw, Check, LoaderCircle } from 'lucide-react';\nimport { Button } from '../button';\nimport { Alert } from '../alert';\nimport { FileUpload, type FileUploadRejection } from '../file-upload';\nimport { useControllableState } from '../../hooks/use-controllable-state';\nimport { useAgentRegistration } from '../../agent';\nimport { documentScannerAgent } from './document-scanner.agent';\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport type DocumentScannerSource = 'camera' | 'upload';\n\nexport interface DocumentCapture {\n /** Data URL of the captured / uploaded image (encoded to `mimeType`). */\n dataUrl: string;\n /** Encoded bytes as a Blob — the consumer persists this. */\n blob: Blob;\n /** Where the image came from. */\n source: DocumentScannerSource;\n /** Intrinsic pixel width of the encoded image. */\n width: number;\n /** Intrinsic pixel height of the encoded image. */\n height: number;\n /** MIME of the encoded image. */\n mimeType: string;\n /** Encoded byte size. */\n byteSize: number;\n /** ISO-8601 UTC timestamp for when the capture was confirmed. */\n capturedAt: string;\n /** Hex-encoded SHA-256 digest of the encoded bytes. */\n sha256: string;\n}\n\nexport type DocumentScannerErrorKind =\n | 'permission-denied'\n | 'no-camera'\n | 'not-readable'\n | 'insecure-context'\n | 'capture-failed'\n | 'file-invalid-type'\n | 'file-too-large';\n\nexport interface DocumentScannerError {\n kind: DocumentScannerErrorKind;\n}\n\nexport type DocumentType = 'tessera-sanitaria' | 'cie' | 'id-card' | 'generic';\n\nexport type DocumentScannerPhase =\n | 'idle'\n | 'requesting'\n | 'streaming'\n | 'captured'\n | 'error';\n\n/** Curated imperative handle for agent / external automation. */\nexport interface DocumentScannerHandle {\n /** True when a captured or uploaded image is held. */\n hasCapture: () => boolean;\n /** Current lifecycle phase. */\n getPhase: () => DocumentScannerPhase;\n /** Request the camera and begin the viewfinder. */\n startCamera: () => Promise<void> | void;\n /** Freeze the current viewfinder frame. */\n capture: () => Promise<void> | void;\n /** Confirm the current capture, firing `onConfirm`. */\n confirm: () => void;\n /** Discard the current capture and return to the capture path. */\n retake: () => void;\n}\n\nexport interface DocumentScannerProps {\n /** Opaque instance id — emitted as `data-component-id` for the agent registry. */\n id?: string;\n /** Controlled captured-image value. When defined the component is controlled. */\n value?: DocumentCapture | null;\n /** Initial captured image for uncontrolled use; seeds the `captured` preview. */\n defaultValue?: DocumentCapture | null;\n /** Fired when the user confirms a captured or uploaded image. */\n onConfirm?: (capture: DocumentCapture) => void;\n /** Fired when the user discards the current capture to retake / re-upload. */\n onRetake?: () => void;\n /** Fired on a permission / hardware / decode failure (telemetry). */\n onError?: (error: DocumentScannerError) => void;\n /** Drives the overlay frame aspect ratio + the translated hint copy. */\n documentType?: DocumentType;\n /** Camera-vs-upload strategy. `auto` falls back to upload on camera failure. */\n captureMode?: 'auto' | 'camera-only' | 'upload-only';\n /** react-dropzone accept map for the upload fallback. */\n accept?: Record<string, string[]>;\n /** Max upload byte size. Defaults to 10MB. */\n maxSize?: number;\n /** Camera to request. Defaults to the rear (`environment`) camera. */\n facingMode?: 'environment' | 'user';\n /** MIME of the encoded capture. */\n outputType?: 'image/jpeg' | 'image/webp' | 'image/png';\n /** 0..1 quality for lossy `outputType`. Ignored for image/png. */\n outputQuality?: number;\n /** Crop the confirmed image to the overlay frame rect. */\n cropToFrame?: boolean;\n /** Disable all controls and skip the camera request. */\n disabled?: boolean;\n /** Accessible label for the component's group region. */\n ariaLabel?: string;\n /** Extra classes merged onto the outermost wrapper. */\n className?: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst rootVariants = cva(\n [\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-md)]',\n 'ds:rounded-[var(--radius-md)] ds:[:where(&)]:border-[length:var(--surface-border-width,var(--border-width-sm))] ds:border-[color:var(--card-border)]',\n 'ds:shadow-[var(--shadow-card)]',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:p-[var(--spacing-md)]',\n 'ds:aria-disabled:opacity-[var(--opacity-50)] ds:aria-disabled:cursor-not-allowed',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:[max-inline-size:20rem]',\n md: 'ds:[max-inline-size:28rem]',\n lg: 'ds:[max-inline-size:36rem]',\n },\n },\n defaultVariants: { size: 'md' },\n },\n);\n\n// The viewport is a positioned, neutral surface that holds the <video> /\n// <img> and the (absolutely-positioned, aria-hidden) frame overlay. The\n// document aspect ratio drives the box shape so the frame matches the card.\nconst viewportVariants = cva(\n [\n 'ds:relative ds:block ds:inline-size-full ds:overflow-hidden',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:bg-[var(--muted)]',\n ].join(' '),\n {\n variants: {\n // ID-1 cards (Tessera Sanitaria / CIE / id-card) are ~1.586:1; the\n // generic frame is a slightly squarer neutral card.\n frame: {\n 'tessera-sanitaria': 'ds:aspect-[1.586/1]',\n cie: 'ds:aspect-[1.586/1]',\n 'id-card': 'ds:aspect-[1.586/1]',\n generic: 'ds:aspect-[1.4/1]',\n },\n },\n defaultVariants: { frame: 'tessera-sanitaria' },\n },\n);\n\nconst mediaVariants = cva(\n [\n 'ds:absolute ds:inset-0 ds:block',\n 'ds:inline-size-full ds:block-size-full',\n 'ds:object-cover',\n ].join(' '),\n);\n\n// The alignment frame sits over arbitrary live video. It is a\n// high-contrast neutral stroke (var(--background) = white on light /\n// near-black on dark) backed by a tokenised scrim — NEVER the magenta\n// accent (fails AA over an unknown image). Decorative → aria-hidden.\nconst frameOverlayVariants = cva(\n [\n 'ds:pointer-events-none ds:absolute',\n 'ds:inset-[12%]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:border-2 ds:border-[color:var(--background)]',\n 'ds:shadow-[0_0_0_100vmax_color-mix(in_srgb,var(--foreground)_45%,transparent)]',\n ].join(' '),\n);\n\nconst cornerVariants = cva(\n [\n 'ds:pointer-events-none ds:absolute ds:size-6',\n 'ds:border-[color:var(--background)]',\n ].join(' '),\n);\n\nconst controlBarVariants = cva(\n [\n // Phone: actions stack full-width; sm+: a wrapping row.\n 'ds:flex ds:flex-col ds:items-stretch ds:gap-[var(--spacing-sm)]',\n 'ds:sm:flex-row ds:sm:flex-wrap ds:sm:items-center',\n ].join(' '),\n);\n\nconst hintVariants = cva(\n ['type-body-sm ds:text-center', 'ds:text-[var(--muted-foreground)]'].join(\n ' ',\n ),\n);\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nfunction toHex(bytes: Uint8Array): string {\n let out = '';\n for (let i = 0; i < bytes.length; i += 1) {\n out += bytes[i].toString(16).padStart(2, '0');\n }\n return out;\n}\n\nasync function sha256Hex(buffer: ArrayBuffer): Promise<string> {\n const g = globalThis as { crypto?: Crypto };\n if (g.crypto?.subtle) {\n // Copy into a fresh ArrayBuffer so the BufferSource is never a\n // SharedArrayBuffer (SubtleCrypto's narrowing rejects the latter).\n const copy = new Uint8Array(buffer.byteLength);\n copy.set(new Uint8Array(buffer));\n const digest = await g.crypto.subtle.digest('SHA-256', copy.buffer);\n return toHex(new Uint8Array(digest));\n }\n // No subtle crypto (older test env) — return empty so the rest of the\n // payload is still usable. Tests stub crypto.subtle.\n return '';\n}\n\n/** Map a getUserMedia rejection (a DOMException) to our error kind. */\nfunction classifyMediaError(err: unknown): DocumentScannerErrorKind {\n const name = err instanceof Error ? err.name : '';\n if (name === 'NotAllowedError' || name === 'SecurityError') {\n return 'permission-denied';\n }\n if (name === 'NotFoundError' || name === 'OverconstrainedError') {\n return 'no-camera';\n }\n if (name === 'NotReadableError' || name === 'AbortError') {\n return 'not-readable';\n }\n return 'capture-failed';\n}\n\n/** True when getUserMedia is actually reachable (HTTPS / localhost + API). */\nfunction mediaDevicesAvailable(): boolean {\n return (\n typeof navigator !== 'undefined' &&\n typeof navigator.mediaDevices !== 'undefined' &&\n typeof navigator.mediaDevices.getUserMedia === 'function'\n );\n}\n\nconst HINT_KEY: Record<DocumentType, string> = {\n 'tessera-sanitaria': 'documentScanner.hint.tesseraSanitaria',\n cie: 'documentScanner.hint.cie',\n 'id-card': 'documentScanner.hint.idCard',\n generic: 'documentScanner.hint.generic',\n};\n\nconst ERROR_KEY: Record<DocumentScannerErrorKind, string> = {\n 'permission-denied': 'documentScanner.error.permissionDenied',\n 'no-camera': 'documentScanner.error.noCamera',\n 'not-readable': 'documentScanner.error.notReadable',\n 'insecure-context': 'documentScanner.error.insecureContext',\n 'capture-failed': 'documentScanner.error.captureFailed',\n 'file-invalid-type': 'documentScanner.error.fileInvalidType',\n 'file-too-large': 'documentScanner.error.fileTooLarge',\n};\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\ntype SizeVariant = NonNullable<VariantProps<typeof rootVariants>['size']>;\n\ninterface DocumentScannerInternalProps extends DocumentScannerProps {\n /** Visual size variant (exposed via Controls). */\n size?: SizeVariant;\n}\n\nexport const DocumentScanner = forwardRef<\n DocumentScannerHandle,\n DocumentScannerInternalProps\n>(\n (\n {\n id,\n value,\n defaultValue = null,\n onConfirm,\n onRetake,\n onError,\n documentType = 'tessera-sanitaria',\n captureMode = 'auto',\n accept = {\n 'image/jpeg': ['.jpg', '.jpeg'],\n 'image/png': ['.png'],\n 'image/webp': ['.webp'],\n },\n maxSize = 10 * 1024 * 1024,\n facingMode = 'environment',\n outputType = 'image/jpeg',\n outputQuality = 0.92,\n cropToFrame = true,\n disabled = false,\n size = 'md',\n ariaLabel,\n className,\n },\n ref,\n ) => {\n const { t } = useTranslation('ui');\n const rawId = useId();\n const hintId = `ds-${rawId.replace(/[^a-zA-Z0-9-_]/g, '')}-hint`;\n\n // Controlled / uncontrolled captured value. `value` defined → controlled.\n const [capture, setCapture] = useControllableState<DocumentCapture | null>({\n value,\n defaultValue,\n });\n\n // Whether the captured value was seeded by `defaultValue` (already on\n // file) — drives the \"Already on file\" badge + Retake-only chrome.\n const seededRef = useRef<boolean>(defaultValue != null || value != null);\n\n const [phase, setPhase] = useState<DocumentScannerPhase>(\n defaultValue != null || value != null ? 'captured' : 'idle',\n );\n const [errorKind, setErrorKind] = useState<DocumentScannerErrorKind | null>(\n null,\n );\n const [streamReady, setStreamReady] = useState(false);\n // True while an uploaded image is being decoded (distinct from the\n // camera-permission `requesting` so the live region announces the right\n // \"Processing image\" copy).\n const [decoding, setDecoding] = useState(false);\n\n const videoRef = useRef<HTMLVideoElement>(null);\n const viewportRef = useRef<HTMLDivElement>(null);\n const streamRef = useRef<MediaStream | null>(null);\n const unmountedRef = useRef(false);\n\n const confirmBtnRef = useRef<HTMLButtonElement>(null);\n const shutterBtnRef = useRef<HTMLButtonElement>(null);\n const useCameraBtnRef = useRef<HTMLButtonElement>(null);\n const recoveryRef = useRef<HTMLButtonElement>(null);\n\n // Latest callbacks via refs so the async media path never closes over\n // a stale prop.\n const onErrorRef = useRef(onError);\n const onConfirmRef = useRef(onConfirm);\n const onRetakeRef = useRef(onRetake);\n useEffect(() => {\n onErrorRef.current = onError;\n onConfirmRef.current = onConfirm;\n onRetakeRef.current = onRetake;\n }, [onError, onConfirm, onRetake]);\n\n const isControlled = value !== undefined;\n const isUploadOnly = captureMode === 'upload-only';\n\n /* ---- Stream teardown — the single most important privacy path ---- */\n const stopStream = useCallback(() => {\n const held = streamRef.current;\n if (held) {\n held.getTracks().forEach((track) => track.stop());\n }\n streamRef.current = null;\n const video = videoRef.current;\n if (video) {\n // Detach so the element releases its reference to the (now-stopped)\n // stream and the browser drops the camera indicator.\n video.srcObject = null;\n }\n setStreamReady(false);\n }, []);\n\n const reportError = useCallback((kind: DocumentScannerErrorKind) => {\n setErrorKind(kind);\n setPhase('error');\n onErrorRef.current?.({ kind });\n }, []);\n\n /* ---- Start the camera — user gesture only, never auto on mount ---- */\n const startCamera = useCallback(async () => {\n if (disabled || isUploadOnly) return;\n if (!mediaDevicesAvailable()) {\n // No mediaDevices → insecure context (non-HTTPS) or unsupported.\n reportError('insecure-context');\n return;\n }\n setErrorKind(null);\n setPhase('requesting');\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n video: { facingMode },\n audio: false,\n });\n // Guard against an unmount between the permission prompt and\n // resolution — otherwise the freshly-acquired track leaks and the\n // camera LED stays live.\n if (unmountedRef.current) {\n stream.getTracks().forEach((track) => track.stop());\n return;\n }\n streamRef.current = stream;\n const video = videoRef.current;\n if (video) {\n try {\n video.srcObject = stream;\n } catch {\n // Some environments reject a non-native MediaStream on\n // srcObject; the stream is still held + torn down correctly.\n }\n // iOS Safari needs an explicit play() after attaching.\n const playResult = video.play?.();\n if (playResult && typeof playResult.catch === 'function') {\n playResult.catch(() => {\n /* autoplay can reject silently in some browsers; the\n loadedmetadata handler still enables the shutter */\n });\n }\n }\n setPhase('streaming');\n } catch (err: unknown) {\n stopStream();\n reportError(classifyMediaError(err));\n }\n }, [disabled, isUploadOnly, facingMode, stopStream, reportError]);\n\n /* ---- Shutter enablement: gate on the video actually playing ---- */\n const handleVideoReady = useCallback(() => {\n const video = videoRef.current;\n if (!video) return;\n // HAVE_CURRENT_DATA (2) means at least one frame is decodable.\n if (video.readyState >= 2) {\n setStreamReady(true);\n }\n }, []);\n\n /* ---- Poll readiness on entering streaming ---- */\n // The loadedmetadata / canplay events can fire before React attaches the\n // listeners (the metadata may already be decoded by the time the stream\n // is swapped onto the element). A short poll closes that race so the\n // shutter reliably enables.\n useEffect(() => {\n if (phase !== 'streaming') return undefined;\n handleVideoReady();\n const interval = window.setInterval(handleVideoReady, 100);\n const stopAfter = window.setTimeout(\n () => window.clearInterval(interval),\n 4000,\n );\n return () => {\n window.clearInterval(interval);\n window.clearTimeout(stopAfter);\n };\n }, [phase, handleVideoReady]);\n\n /* ---- Capture: freeze the current frame onto a canvas ---- */\n const capturePhoto = useCallback(async () => {\n const video = videoRef.current;\n if (!video || video.readyState < 2) {\n reportError('capture-failed');\n return;\n }\n const vw = video.videoWidth || video.clientWidth;\n const vh = video.videoHeight || video.clientHeight;\n if (vw === 0 || vh === 0) {\n reportError('capture-failed');\n return;\n }\n\n // Crop region in source-video pixel space. The overlay frame is\n // inset 12% on each edge of the viewport; mirror that onto the\n // source so the cropped image is the document, not the whole frame.\n let sx = 0;\n let sy = 0;\n let sw = vw;\n let sh = vh;\n if (cropToFrame) {\n const insetX = vw * 0.12;\n const insetY = vh * 0.12;\n sx = insetX;\n sy = insetY;\n sw = vw - insetX * 2;\n sh = vh - insetY * 2;\n }\n\n const canvas = document.createElement('canvas');\n canvas.width = Math.max(1, Math.round(sw));\n canvas.height = Math.max(1, Math.round(sh));\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n reportError('capture-failed');\n return;\n }\n try {\n ctx.drawImage(video, sx, sy, sw, sh, 0, 0, canvas.width, canvas.height);\n } catch {\n // A video element with no decoded frame throws InvalidStateError in\n // some browsers — surface it as a capture failure rather than crash.\n reportError('capture-failed');\n return;\n }\n\n // Release the camera as soon as the frame is frozen — we no longer\n // need the live stream and the LED should go dark immediately.\n stopStream();\n\n const blob = await new Promise<Blob | null>((resolve) => {\n if (typeof canvas.toBlob === 'function') {\n canvas.toBlob(\n (b) => resolve(b),\n outputType,\n outputType === 'image/png' ? undefined : outputQuality,\n );\n } else {\n resolve(null);\n }\n });\n if (!blob) {\n reportError('capture-failed');\n return;\n }\n const dataUrl = canvas.toDataURL(\n outputType,\n outputType === 'image/png' ? undefined : outputQuality,\n );\n const arrayBuffer = await blob.arrayBuffer();\n const sha256 = await sha256Hex(arrayBuffer);\n\n seededRef.current = false;\n const next: DocumentCapture = {\n dataUrl,\n blob,\n source: 'camera',\n width: canvas.width,\n height: canvas.height,\n mimeType: outputType,\n byteSize: blob.size,\n capturedAt: new Date().toISOString(),\n sha256,\n };\n setCapture(next);\n setPhase('captured');\n }, [\n cropToFrame,\n outputType,\n outputQuality,\n stopStream,\n reportError,\n setCapture,\n ]);\n\n /* ---- Upload fallback → decode an image File into a capture ---- */\n const handleUploadDrop = useCallback(\n async (accepted: File[]) => {\n const file = accepted[0];\n if (!file) return;\n setDecoding(true);\n try {\n const objectUrl = URL.createObjectURL(file);\n const dimensions = await new Promise<{ w: number; h: number }>(\n (resolve, reject) => {\n const img = new Image();\n img.onload = () =>\n resolve({ w: img.naturalWidth, h: img.naturalHeight });\n img.onerror = () => reject(new Error('decode-failed'));\n img.src = objectUrl;\n },\n ).finally(() => {\n // The object URL is only needed to read intrinsic dimensions;\n // the persisted payload carries a data URL instead.\n URL.revokeObjectURL(objectUrl);\n });\n\n const dataUrl = await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(String(reader.result));\n reader.onerror = () => reject(new Error('read-failed'));\n reader.readAsDataURL(file);\n });\n\n const arrayBuffer = await file.arrayBuffer();\n const sha256 = await sha256Hex(arrayBuffer);\n\n seededRef.current = false;\n setErrorKind(null);\n setCapture({\n dataUrl,\n blob: file,\n source: 'upload',\n width: dimensions.w,\n height: dimensions.h,\n mimeType: file.type || outputType,\n byteSize: file.size,\n capturedAt: new Date().toISOString(),\n sha256,\n });\n setPhase('captured');\n } catch {\n reportError('capture-failed');\n } finally {\n setDecoding(false);\n }\n },\n [outputType, reportError, setCapture],\n );\n\n const handleUploadReject = useCallback(\n (rejections: FileUploadRejection[]) => {\n // FileUpload's reason enum is wider than our two error kinds. The\n // dropzone is locked to a single image (maxFiles:1, multiple:false),\n // so 'too-many-files' / 'file-too-small' are unreachable here; both\n // size/type problems fold into the matching inline message and\n // default to invalid-type for anything else.\n const reason = rejections[0]?.reason;\n const kind: DocumentScannerErrorKind =\n reason === 'file-too-large' ? 'file-too-large' : 'file-invalid-type';\n reportError(kind);\n },\n [reportError],\n );\n\n /* ---- Confirm / Retake ---- */\n const confirm = useCallback(() => {\n if (!capture) return;\n onConfirmRef.current?.(capture);\n }, [capture]);\n\n // Set when a user-initiated transition back to idle should move focus to\n // the Use-camera button (Retake). Distinguishes retake-to-idle from the\n // initial idle mount, so focus is never stolen on first paint.\n const focusUseCameraRef = useRef(false);\n\n const retake = useCallback(() => {\n // Controlled mode: retake is advisory only. The consumer owns `value`,\n // so we must NOT clear the capture, flip seededRef, or force a local\n // phase — doing so would race the controlled-value sync effect (which\n // re-asserts `captured` while value is still set), dropping the\n // \"already on file\" badge and surfacing a stray Confirm for an\n // already-persisted image. Emit onRetake and let the value drive phase.\n if (isControlled) {\n onRetakeRef.current?.();\n return;\n }\n seededRef.current = false;\n focusUseCameraRef.current = true;\n setCapture(null);\n setErrorKind(null);\n setDecoding(false);\n setPhase('idle');\n onRetakeRef.current?.();\n }, [isControlled, setCapture]);\n\n /* ---- Focus management on phase transitions ---- */\n useEffect(() => {\n if (phase === 'captured' && !seededRef.current) {\n // Land the keyboard / SR user on the next logical action.\n confirmBtnRef.current?.focus();\n } else if (phase === 'error') {\n recoveryRef.current?.focus();\n } else if (phase === 'idle' && focusUseCameraRef.current) {\n // After a Retake, return focus to the capture entry point. Never on\n // the initial idle mount (the flag is only set by retake()).\n focusUseCameraRef.current = false;\n useCameraBtnRef.current?.focus();\n }\n }, [phase]);\n\n /* ---- Escape from streaming returns to idle and stops the stream ---- */\n useEffect(() => {\n if (phase !== 'streaming') return undefined;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n stopStream();\n setPhase('idle');\n }\n };\n document.addEventListener('keydown', onKeyDown);\n return () => document.removeEventListener('keydown', onKeyDown);\n }, [phase, stopStream]);\n\n /* ---- Release the camera when the tab is hidden ---- */\n useEffect(() => {\n const onVisibility = () => {\n if (document.visibilityState === 'hidden' && streamRef.current) {\n stopStream();\n setPhase('idle');\n }\n };\n document.addEventListener('visibilitychange', onVisibility);\n return () =>\n document.removeEventListener('visibilitychange', onVisibility);\n }, [stopStream]);\n\n /* ---- Unmount cleanup: release the camera if still held ---- */\n useEffect(() => {\n return () => {\n unmountedRef.current = true;\n const held = streamRef.current;\n if (held) held.getTracks().forEach((track) => track.stop());\n streamRef.current = null;\n };\n }, []);\n\n /* ---- Sync controlled value → phase ---- */\n useEffect(() => {\n if (!isControlled) return;\n if (value != null) {\n setPhase('captured');\n } else if (phase === 'captured') {\n setPhase('idle');\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value, isControlled]);\n\n /* ---- Imperative handle + agent registration ---- */\n const agentHandle = useMemo<DocumentScannerHandle>(\n () => ({\n hasCapture: () => capture != null,\n getPhase: () => phase,\n startCamera: () => startCamera(),\n capture: () => capturePhoto(),\n confirm: () => confirm(),\n retake: () => retake(),\n }),\n [capture, phase, startCamera, capturePhoto, confirm, retake],\n );\n useImperativeHandle(ref, () => agentHandle, [agentHandle]);\n useAgentRegistration(documentScannerAgent, agentHandle, id);\n\n /* ---- Derived strings ---- */\n const regionLabel = ariaLabel ?? t('documentScanner.regionLabel');\n const hintText = t(HINT_KEY[documentType]);\n const maxSizeMb = Math.round(maxSize / (1024 * 1024));\n\n const statusText = (() => {\n if (decoding) return t('documentScanner.state.uploading');\n switch (phase) {\n case 'idle':\n return t('documentScanner.state.idle');\n case 'requesting':\n return t('documentScanner.state.requesting');\n case 'streaming':\n return t('documentScanner.state.streaming');\n case 'captured':\n return t('documentScanner.state.captured');\n case 'error':\n return errorKind\n ? t(ERROR_KEY[errorKind], { maxSizeMb })\n : t('documentScanner.error.captureFailed');\n }\n })();\n\n // A camera retry only makes sense for a hardware/permission failure —\n // not for upload-side rejections or an insecure (non-HTTPS) context.\n const canRetryCamera =\n !isUploadOnly &&\n errorKind !== 'file-invalid-type' &&\n errorKind !== 'file-too-large' &&\n errorKind !== 'insecure-context';\n\n // The upload affordance is always reachable: shown in idle/error for\n // auto + camera-only, primary in upload-only, and the recovery path on\n // any hard camera error.\n const showUploadFallback =\n !disabled &&\n (captureMode === 'auto' ||\n captureMode === 'upload-only' ||\n phase === 'error');\n\n const uploadAffordance = (\n <FileUpload\n variant=\"button\"\n accept={accept}\n maxSize={maxSize}\n multiple={false}\n maxFiles={1}\n disabled={disabled}\n showPreview={false}\n onDrop={(acceptedFiles) => {\n void handleUploadDrop(acceptedFiles);\n }}\n onReject={handleUploadReject}\n />\n );\n\n /* ---- Render ---- */\n const showViewport =\n phase === 'idle' ||\n phase === 'requesting' ||\n phase === 'streaming' ||\n phase === 'error';\n\n return (\n <div\n role=\"group\"\n aria-label={regionLabel}\n aria-disabled={disabled || undefined}\n className={[rootVariants({ size }), className]\n .filter(Boolean)\n .join(' ')}\n data-component=\"document-scanner\"\n data-component-id={id}\n data-phase={phase}\n >\n {/* Polite live region — announces every phase change to SR users. */}\n <span\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"ds:sr-only\"\n data-testid=\"document-scanner-live\"\n >\n {statusText}\n </span>\n\n {phase === 'captured' && capture ? (\n /* ---- Captured preview ---- */\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <div className={viewportVariants({ frame: documentType })}>\n <img\n src={capture.dataUrl}\n alt={t('documentScanner.previewAlt')}\n className={mediaVariants()}\n data-testid=\"document-scanner-preview\"\n />\n {seededRef.current ? (\n <span className=\"ds:absolute ds:top-[var(--spacing-sm)] ds:start-[var(--spacing-sm)] ds:rounded-[var(--radius-full)] ds:border ds:border-[color:color-mix(in_srgb,var(--foreground)_15%,transparent)] ds:bg-[var(--primary)] ds:text-[var(--primary-foreground)] ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:py-[var(--spacing-2xs)] type-meta\">\n {t('documentScanner.onFileBadge')}\n </span>\n ) : null}\n </div>\n <div className={controlBarVariants()}>\n <Button\n intent=\"secondary\"\n size=\"md\"\n // Button's md variant is h-10 (40px) with no min-target\n // compensation — pin to --min-target-size (44/48px) to clear\n // WCAG 2.5.5, matching SignatureCapture's action buttons.\n className=\"ds:[min-block-size:var(--min-target-size)] ds:[min-inline-size:var(--min-target-size)]\"\n startIcon={<RotateCcw aria-hidden=\"true\" />}\n onClick={retake}\n disabled={disabled}\n >\n {t('documentScanner.retake')}\n </Button>\n {/* Seeded \"already on file\" images need no Confirm — they are\n already persisted; the only action is Retake. */}\n {seededRef.current ? null : (\n <Button\n ref={confirmBtnRef}\n intent=\"primary\"\n size=\"md\"\n className=\"ds:[min-block-size:var(--min-target-size)] ds:[min-inline-size:var(--min-target-size)]\"\n startIcon={<Check aria-hidden=\"true\" />}\n onClick={confirm}\n disabled={disabled || capture == null}\n >\n {t('documentScanner.confirm')}\n </Button>\n )}\n </div>\n </div>\n ) : null}\n\n {showViewport ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n {/* Viewport — only meaningful while streaming/requesting; in\n idle/error it is a neutral placeholder behind the controls. */}\n {!isUploadOnly && phase !== 'error' ? (\n <div\n ref={viewportRef}\n className={viewportVariants({ frame: documentType })}\n aria-busy={phase === 'requesting' || undefined}\n >\n <video\n ref={videoRef}\n autoPlay\n playsInline\n muted\n aria-label={t('documentScanner.videoLabel')}\n className={mediaVariants()}\n onLoadedMetadata={handleVideoReady}\n onCanPlay={handleVideoReady}\n data-testid=\"document-scanner-video\"\n />\n {phase === 'requesting' ? (\n <div className=\"ds:absolute ds:inset-0 ds:flex ds:items-center ds:justify-center ds:bg-[color-mix(in_srgb,var(--foreground)_20%,transparent)]\">\n <LoaderCircle\n aria-hidden=\"true\"\n className=\"ds:size-8 ds:animate-spin ds:text-[var(--background)] ds:motion-reduce:animate-none\"\n />\n </div>\n ) : null}\n {/* Decorative alignment frame + corner guides. */}\n <div\n aria-hidden=\"true\"\n className={frameOverlayVariants()}\n data-testid=\"document-scanner-frame\"\n >\n <span\n className={[\n cornerVariants(),\n 'ds:top-0 ds:start-0 ds:border-t-2 ds:border-s-2 ds:rounded-ss-[var(--radius-sm)]',\n ].join(' ')}\n />\n <span\n className={[\n cornerVariants(),\n 'ds:top-0 ds:end-0 ds:border-t-2 ds:border-e-2 ds:rounded-se-[var(--radius-sm)]',\n ].join(' ')}\n />\n <span\n className={[\n cornerVariants(),\n 'ds:bottom-0 ds:start-0 ds:border-b-2 ds:border-s-2 ds:rounded-es-[var(--radius-sm)]',\n ].join(' ')}\n />\n <span\n className={[\n cornerVariants(),\n 'ds:bottom-0 ds:end-0 ds:border-b-2 ds:border-e-2 ds:rounded-ee-[var(--radius-sm)]',\n ].join(' ')}\n />\n </div>\n </div>\n ) : null}\n\n {phase === 'streaming' ? (\n <p id={hintId} className={hintVariants()}>\n {hintText}\n </p>\n ) : null}\n\n {/* Error block — Alert pattern with the upload recovery path. */}\n {phase === 'error' && errorKind ? (\n <Alert variant=\"error\" live=\"assertive\">\n <Alert.Description>\n {t(ERROR_KEY[errorKind], { maxSizeMb })}\n </Alert.Description>\n <Alert.Action>\n {/* The camera-retry button is the focus target on a\n hardware/permission error; for upload-side or\n insecure-context errors there is nothing to retry and\n the upload affordance is the recovery path. */}\n {canRetryCamera ? (\n <Button\n ref={recoveryRef}\n intent=\"secondary\"\n size=\"sm\"\n onClick={() => {\n void startCamera();\n }}\n disabled={disabled}\n >\n {t('documentScanner.retry')}\n </Button>\n ) : null}\n {showUploadFallback ? uploadAffordance : null}\n </Alert.Action>\n </Alert>\n ) : null}\n\n {/* Primary control bar (no hard error). */}\n {phase !== 'error' ? (\n <div className={controlBarVariants()}>\n {phase === 'streaming' ? (\n <Button\n ref={shutterBtnRef}\n intent=\"primary\"\n size=\"lg\"\n startIcon={<Camera aria-hidden=\"true\" />}\n onClick={() => {\n void capturePhoto();\n }}\n disabled={disabled || !streamReady}\n aria-describedby={hintId}\n aria-label={t('documentScanner.capture')}\n >\n {t('documentScanner.capture')}\n </Button>\n ) : null}\n\n {(phase === 'idle' || phase === 'requesting') &&\n !isUploadOnly ? (\n <Button\n ref={useCameraBtnRef}\n intent=\"primary\"\n size=\"md\"\n className=\"ds:[min-block-size:var(--min-target-size)] ds:[min-inline-size:var(--min-target-size)]\"\n loading={phase === 'requesting'}\n startIcon={<Camera aria-hidden=\"true\" />}\n onClick={() => {\n void startCamera();\n }}\n disabled={disabled}\n >\n {t('documentScanner.useCamera')}\n </Button>\n ) : null}\n\n {decoding ? (\n <span className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)] type-body-sm ds:text-[var(--muted-foreground)]\">\n <LoaderCircle\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:animate-spin ds:motion-reduce:animate-none\"\n />\n {t('documentScanner.state.uploading')}\n </span>\n ) : showUploadFallback && phase !== 'streaming' ? (\n uploadAffordance\n ) : null}\n\n {/* In streaming, upload stays reachable as a low-emphasis\n fallback below the shutter. */}\n {phase === 'streaming' && captureMode !== 'camera-only'\n ? uploadAffordance\n : null}\n </div>\n ) : null}\n </div>\n ) : null}\n </div>\n );\n },\n);\n\nDocumentScanner.displayName = 'DocumentScanner';\n\nexport {\n rootVariants as documentScannerRootVariants,\n viewportVariants as documentScannerViewportVariants,\n};\n"],"names":["documentScannerAgent","handle","rootVariants","cva","viewportVariants","mediaVariants","frameOverlayVariants","cornerVariants","controlBarVariants","hintVariants","toHex","bytes","out","i","sha256Hex","buffer","g","_a","copy","digest","classifyMediaError","err","name","mediaDevicesAvailable","HINT_KEY","ERROR_KEY","DocumentScanner","forwardRef","id","value","defaultValue","onConfirm","onRetake","onError","documentType","captureMode","accept","maxSize","facingMode","outputType","outputQuality","cropToFrame","disabled","size","ariaLabel","className","ref","t","useTranslation","hintId","useId","capture","setCapture","useControllableState","seededRef","useRef","phase","setPhase","useState","errorKind","setErrorKind","streamReady","setStreamReady","decoding","setDecoding","videoRef","viewportRef","streamRef","unmountedRef","confirmBtnRef","shutterBtnRef","useCameraBtnRef","recoveryRef","onErrorRef","onConfirmRef","onRetakeRef","useEffect","isControlled","isUploadOnly","stopStream","useCallback","held","track","video","reportError","kind","startCamera","stream","playResult","handleVideoReady","interval","stopAfter","capturePhoto","vw","vh","sx","sy","sw","sh","insetX","insetY","canvas","ctx","blob","resolve","b","dataUrl","arrayBuffer","sha256","next","handleUploadDrop","accepted","file","objectUrl","dimensions","reject","img","reader","handleUploadReject","rejections","confirm","focusUseCameraRef","retake","_b","_c","onKeyDown","event","onVisibility","agentHandle","useMemo","useImperativeHandle","useAgentRegistration","regionLabel","hintText","maxSizeMb","statusText","canRetryCamera","showUploadFallback","uploadAffordance","jsx","FileUpload","acceptedFiles","showViewport","jsxs","Button","RotateCcw","Check","LoaderCircle","Alert","Camera"],"mappings":";;;;;;;;;;;;;AAUO,MAAMA,KAA4D;AAAA,EACvE,IAAI;AAAA,EACJ,cAAc,CAAC,WAAW,QAAQ;AAAA,EAClC,OAAO;AAAA,IACL,YAAY;AAAA,MACV,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,MAAM,CAACC,MAAWA,EAAO,WAAA;AAAA,IAAW;AAAA,IAEtC,OAAO;AAAA,MACL,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,MAAM,CAACA,MAAWA,EAAO,SAAA;AAAA,IAAS;AAAA,EACpC;AAAA,EAEF,SAAS;AAAA,IACP,cAAc;AAAA,MACZ,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,QAAQ,CAACA,MAAWA,EAAO,YAAA;AAAA,IAAY;AAAA,IAEzC,SAAS;AAAA,MACP,QAAQ;AAAA,MACR,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,QAAQ,CAAC,gBAAgB;AAAA,MACzB,QAAQ,CAACA,MAAWA,EAAO,QAAA;AAAA,IAAQ;AAAA,IAErC,QAAQ;AAAA,MACN,QAAQ;AAAA,MACR,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,QAAQ,CAACA,MAAW;AAClB,QAAAA,EAAO,QAAA;AAAA,MACT;AAAA,IAAA;AAAA,IAEF,QAAQ;AAAA,MACN,QAAQ;AAAA,MACR,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,QAAQ,CAACA,MAAW;AAClB,QAAAA,EAAO,OAAA;AAAA,MACT;AAAA,IAAA;AAAA,EACF;AAAA,EAEF,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IAAA;AAAA,IAEf,YAAY;AAAA,MACV,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,aAAa;AAAA,IAAA;AAAA,EACf;AAEJ,GCyEMC,KAAeC;AAAA,EACnB;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AAAA,EACV;AAAA,IACE,UAAU;AAAA,MACR,MAAM;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MAAA;AAAA,IACN;AAAA,IAEF,iBAAiB,EAAE,MAAM,KAAA;AAAA,EAAK;AAElC,GAKMC,KAAmBD;AAAA,EACvB;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AAAA,EACV;AAAA,IACE,UAAU;AAAA;AAAA;AAAA,MAGR,OAAO;AAAA,QACL,qBAAqB;AAAA,QACrB,KAAK;AAAA,QACL,WAAW;AAAA,QACX,SAAS;AAAA,MAAA;AAAA,IACX;AAAA,IAEF,iBAAiB,EAAE,OAAO,oBAAA;AAAA,EAAoB;AAElD,GAEME,KAAgBF;AAAA,EACpB;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ,GAMMG,KAAuBH;AAAA,EAC3B;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ,GAEMI,IAAiBJ;AAAA,EACrB;AAAA,IACE;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ,GAEMK,KAAqBL;AAAA,EACzB;AAAA;AAAA,IAEE;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ,GAEMM,KAAeN;AAAA,EACnB,CAAC,+BAA+B,mCAAmC,EAAE;AAAA,IACnE;AAAA,EAAA;AAEJ;AAMA,SAASO,GAAMC,GAA2B;AACxC,MAAIC,IAAM;AACV,WAASC,IAAI,GAAGA,IAAIF,EAAM,QAAQE,KAAK;AACrC,IAAAD,KAAOD,EAAME,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAE9C,SAAOD;AACT;AAEA,eAAeE,GAAUC,GAAsC;;AAC7D,QAAMC,IAAI;AACV,OAAIC,IAAAD,EAAE,WAAF,QAAAC,EAAU,QAAQ;AAGpB,UAAMC,IAAO,IAAI,WAAWH,EAAO,UAAU;AAC7C,IAAAG,EAAK,IAAI,IAAI,WAAWH,CAAM,CAAC;AAC/B,UAAMI,IAAS,MAAMH,EAAE,OAAO,OAAO,OAAO,WAAWE,EAAK,MAAM;AAClE,WAAOR,GAAM,IAAI,WAAWS,CAAM,CAAC;AAAA,EACrC;AAGA,SAAO;AACT;AAGA,SAASC,GAAmBC,GAAwC;AAClE,QAAMC,IAAOD,aAAe,QAAQA,EAAI,OAAO;AAC/C,SAAIC,MAAS,qBAAqBA,MAAS,kBAClC,sBAELA,MAAS,mBAAmBA,MAAS,yBAChC,cAELA,MAAS,sBAAsBA,MAAS,eACnC,iBAEF;AACT;AAGA,SAASC,KAAiC;AACxC,SACE,OAAO,YAAc,OACrB,OAAO,UAAU,eAAiB,OAClC,OAAO,UAAU,aAAa,gBAAiB;AAEnD;AAEA,MAAMC,KAAyC;AAAA,EAC7C,qBAAqB;AAAA,EACrB,KAAK;AAAA,EACL,WAAW;AAAA,EACX,SAAS;AACX,GAEMC,KAAsD;AAAA,EAC1D,qBAAqB;AAAA,EACrB,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,kBAAkB;AACpB,GAaaC,KAAkBC;AAAA,EAI7B,CACE;AAAA,IACE,IAAAC;AAAA,IACA,OAAAC;AAAA,IACA,cAAAC,IAAe;AAAA,IACf,WAAAC;AAAA,IACA,UAAAC;AAAA,IACA,SAAAC;AAAA,IACA,cAAAC,IAAe;AAAA,IACf,aAAAC,IAAc;AAAA,IACd,QAAAC,KAAS;AAAA,MACP,cAAc,CAAC,QAAQ,OAAO;AAAA,MAC9B,aAAa,CAAC,MAAM;AAAA,MACpB,cAAc,CAAC,OAAO;AAAA,IAAA;AAAA,IAExB,SAAAC,KAAU,KAAK,OAAO;AAAA,IACtB,YAAAC,KAAa;AAAA,IACb,YAAAC,IAAa;AAAA,IACb,eAAAC,IAAgB;AAAA,IAChB,aAAAC,KAAc;AAAA,IACd,UAAAC,IAAW;AAAA,IACX,MAAAC,KAAO;AAAA,IACP,WAAAC;AAAA,IACA,WAAAC;AAAA,EAAA,GAEFC,OACG;AACH,UAAM,EAAE,GAAAC,EAAA,IAAMC,GAAe,IAAI,GAE3BC,KAAS,MADDC,GAAA,EACa,QAAQ,mBAAmB,EAAE,CAAC,SAGnD,CAACC,GAASC,CAAU,IAAIC,GAA6C;AAAA,MACzE,OAAAxB;AAAA,MACA,cAAAC;AAAA,IAAA,CACD,GAIKwB,IAAYC,EAAgBzB,KAAgB,QAAQD,KAAS,IAAI,GAEjE,CAAC2B,GAAOC,CAAQ,IAAIC;AAAA,MACxB5B,KAAgB,QAAQD,KAAS,OAAO,aAAa;AAAA,IAAA,GAEjD,CAAC8B,GAAWC,CAAY,IAAIF;AAAA,MAChC;AAAA,IAAA,GAEI,CAACG,IAAaC,EAAc,IAAIJ,EAAS,EAAK,GAI9C,CAACK,IAAUC,CAAW,IAAIN,EAAS,EAAK,GAExCO,IAAWV,EAAyB,IAAI,GACxCW,KAAcX,EAAuB,IAAI,GACzCY,IAAYZ,EAA2B,IAAI,GAC3Ca,KAAeb,EAAO,EAAK,GAE3Bc,KAAgBd,EAA0B,IAAI,GAC9Ce,KAAgBf,EAA0B,IAAI,GAC9CgB,KAAkBhB,EAA0B,IAAI,GAChDiB,KAAcjB,EAA0B,IAAI,GAI5CkB,IAAalB,EAAOtB,CAAO,GAC3ByC,IAAenB,EAAOxB,CAAS,GAC/B4C,IAAcpB,EAAOvB,CAAQ;AACnC,IAAA4C,EAAU,MAAM;AACd,MAAAH,EAAW,UAAUxC,GACrByC,EAAa,UAAU3C,GACvB4C,EAAY,UAAU3C;AAAA,IACxB,GAAG,CAACC,GAASF,GAAWC,CAAQ,CAAC;AAEjC,UAAM6C,IAAehD,MAAU,QACzBiD,IAAe3C,MAAgB,eAG/B4C,IAAaC,EAAY,MAAM;AACnC,YAAMC,IAAOd,EAAU;AACvB,MAAIc,KACFA,EAAK,YAAY,QAAQ,CAACC,MAAUA,EAAM,MAAM,GAElDf,EAAU,UAAU;AACpB,YAAMgB,IAAQlB,EAAS;AACvB,MAAIkB,MAGFA,EAAM,YAAY,OAEpBrB,GAAe,EAAK;AAAA,IACtB,GAAG,CAAA,CAAE,GAECsB,IAAcJ,EAAY,CAACK,MAAmC;;AAClE,MAAAzB,EAAayB,CAAI,GACjB5B,EAAS,OAAO,IAChBxC,IAAAwD,EAAW,YAAX,QAAAxD,EAAA,KAAAwD,GAAqB,EAAE,MAAAY;IACzB,GAAG,CAAA,CAAE,GAGCC,IAAcN,EAAY,YAAY;;AAC1C,UAAI,EAAAtC,KAAYoC,IAChB;AAAA,YAAI,CAACvD,MAAyB;AAE5B,UAAA6D,EAAY,kBAAkB;AAC9B;AAAA,QACF;AACA,QAAAxB,EAAa,IAAI,GACjBH,EAAS,YAAY;AACrB,YAAI;AACF,gBAAM8B,IAAS,MAAM,UAAU,aAAa,aAAa;AAAA,YACvD,OAAO,EAAE,YAAAjD,GAAA;AAAA,YACT,OAAO;AAAA,UAAA,CACR;AAID,cAAI8B,GAAa,SAAS;AACxB,YAAAmB,EAAO,YAAY,QAAQ,CAACL,MAAUA,EAAM,MAAM;AAClD;AAAA,UACF;AACA,UAAAf,EAAU,UAAUoB;AACpB,gBAAMJ,IAAQlB,EAAS;AACvB,cAAIkB,GAAO;AACT,gBAAI;AACF,cAAAA,EAAM,YAAYI;AAAA,YACpB,QAAQ;AAAA,YAGR;AAEA,kBAAMC,KAAavE,IAAAkE,EAAM,SAAN,gBAAAlE,EAAA,KAAAkE;AACnB,YAAIK,KAAc,OAAOA,EAAW,SAAU,cAC5CA,EAAW,MAAM,MAAM;AAAA,YAGvB,CAAC;AAAA,UAEL;AACA,UAAA/B,EAAS,WAAW;AAAA,QACtB,SAASpC,GAAc;AACrB,UAAA0D,EAAA,GACAK,EAAYhE,GAAmBC,CAAG,CAAC;AAAA,QACrC;AAAA;AAAA,IACF,GAAG,CAACqB,GAAUoC,GAAcxC,IAAYyC,GAAYK,CAAW,CAAC,GAG1DK,IAAmBT,EAAY,MAAM;AACzC,YAAMG,IAAQlB,EAAS;AACvB,MAAKkB,KAEDA,EAAM,cAAc,KACtBrB,GAAe,EAAI;AAAA,IAEvB,GAAG,CAAA,CAAE;AAOL,IAAAc,EAAU,MAAM;AACd,UAAIpB,MAAU,YAAa;AAC3B,MAAAiC,EAAA;AACA,YAAMC,IAAW,OAAO,YAAYD,GAAkB,GAAG,GACnDE,IAAY,OAAO;AAAA,QACvB,MAAM,OAAO,cAAcD,CAAQ;AAAA,QACnC;AAAA,MAAA;AAEF,aAAO,MAAM;AACX,eAAO,cAAcA,CAAQ,GAC7B,OAAO,aAAaC,CAAS;AAAA,MAC/B;AAAA,IACF,GAAG,CAACnC,GAAOiC,CAAgB,CAAC;AAG5B,UAAMG,IAAeZ,EAAY,YAAY;AAC3C,YAAMG,IAAQlB,EAAS;AACvB,UAAI,CAACkB,KAASA,EAAM,aAAa,GAAG;AAClC,QAAAC,EAAY,gBAAgB;AAC5B;AAAA,MACF;AACA,YAAMS,IAAKV,EAAM,cAAcA,EAAM,aAC/BW,IAAKX,EAAM,eAAeA,EAAM;AACtC,UAAIU,MAAO,KAAKC,MAAO,GAAG;AACxB,QAAAV,EAAY,gBAAgB;AAC5B;AAAA,MACF;AAKA,UAAIW,IAAK,GACLC,IAAK,GACLC,IAAKJ,GACLK,IAAKJ;AACT,UAAIrD,IAAa;AACf,cAAM0D,IAASN,IAAK,MACdO,IAASN,IAAK;AACpB,QAAAC,IAAKI,GACLH,IAAKI,GACLH,IAAKJ,IAAKM,IAAS,GACnBD,IAAKJ,IAAKM,IAAS;AAAA,MACrB;AAEA,YAAMC,IAAS,SAAS,cAAc,QAAQ;AAC9C,MAAAA,EAAO,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAMJ,CAAE,CAAC,GACzCI,EAAO,SAAS,KAAK,IAAI,GAAG,KAAK,MAAMH,CAAE,CAAC;AAC1C,YAAMI,IAAMD,EAAO,WAAW,IAAI;AAClC,UAAI,CAACC,GAAK;AACR,QAAAlB,EAAY,gBAAgB;AAC5B;AAAA,MACF;AACA,UAAI;AACF,QAAAkB,EAAI,UAAUnB,GAAOY,GAAIC,GAAIC,GAAIC,GAAI,GAAG,GAAGG,EAAO,OAAOA,EAAO,MAAM;AAAA,MACxE,QAAQ;AAGN,QAAAjB,EAAY,gBAAgB;AAC5B;AAAA,MACF;AAIA,MAAAL,EAAA;AAEA,YAAMwB,IAAO,MAAM,IAAI,QAAqB,CAACC,MAAY;AACvD,QAAI,OAAOH,EAAO,UAAW,aAC3BA,EAAO;AAAA,UACL,CAACI,MAAMD,EAAQC,CAAC;AAAA,UAChBlE;AAAA,UACAA,MAAe,cAAc,SAAYC;AAAA,QAAA,IAG3CgE,EAAQ,IAAI;AAAA,MAEhB,CAAC;AACD,UAAI,CAACD,GAAM;AACT,QAAAnB,EAAY,gBAAgB;AAC5B;AAAA,MACF;AACA,YAAMsB,KAAUL,EAAO;AAAA,QACrB9D;AAAA,QACAA,MAAe,cAAc,SAAYC;AAAA,MAAA,GAErCmE,KAAc,MAAMJ,EAAK,YAAA,GACzBK,KAAS,MAAM9F,GAAU6F,EAAW;AAE1C,MAAArD,EAAU,UAAU;AACpB,YAAMuD,KAAwB;AAAA,QAC5B,SAAAH;AAAA,QACA,MAAAH;AAAA,QACA,QAAQ;AAAA,QACR,OAAOF,EAAO;AAAA,QACd,QAAQA,EAAO;AAAA,QACf,UAAU9D;AAAA,QACV,UAAUgE,EAAK;AAAA,QACf,aAAY,oBAAI,KAAA,GAAO,YAAA;AAAA,QACvB,QAAAK;AAAA,MAAA;AAEF,MAAAxD,EAAWyD,EAAI,GACfpD,EAAS,UAAU;AAAA,IACrB,GAAG;AAAA,MACDhB;AAAA,MACAF;AAAA,MACAC;AAAA,MACAuC;AAAA,MACAK;AAAA,MACAhC;AAAA,IAAA,CACD,GAGK0D,KAAmB9B;AAAA,MACvB,OAAO+B,MAAqB;AAC1B,cAAMC,IAAOD,EAAS,CAAC;AACvB,YAAKC,GACL;AAAA,UAAAhD,EAAY,EAAI;AAChB,cAAI;AACF,kBAAMiD,IAAY,IAAI,gBAAgBD,CAAI,GACpCE,IAAa,MAAM,IAAI;AAAA,cAC3B,CAACV,GAASW,MAAW;AACnB,sBAAMC,IAAM,IAAI,MAAA;AAChB,gBAAAA,EAAI,SAAS,MACXZ,EAAQ,EAAE,GAAGY,EAAI,cAAc,GAAGA,EAAI,eAAe,GACvDA,EAAI,UAAU,MAAMD,EAAO,IAAI,MAAM,eAAe,CAAC,GACrDC,EAAI,MAAMH;AAAA,cACZ;AAAA,YAAA,EACA,QAAQ,MAAM;AAGd,kBAAI,gBAAgBA,CAAS;AAAA,YAC/B,CAAC,GAEKP,IAAU,MAAM,IAAI,QAAgB,CAACF,GAASW,MAAW;AAC7D,oBAAME,IAAS,IAAI,WAAA;AACnB,cAAAA,EAAO,SAAS,MAAMb,EAAQ,OAAOa,EAAO,MAAM,CAAC,GACnDA,EAAO,UAAU,MAAMF,EAAO,IAAI,MAAM,aAAa,CAAC,GACtDE,EAAO,cAAcL,CAAI;AAAA,YAC3B,CAAC,GAEKL,IAAc,MAAMK,EAAK,YAAA,GACzBJ,IAAS,MAAM9F,GAAU6F,CAAW;AAE1C,YAAArD,EAAU,UAAU,IACpBM,EAAa,IAAI,GACjBR,EAAW;AAAA,cACT,SAAAsD;AAAA,cACA,MAAMM;AAAA,cACN,QAAQ;AAAA,cACR,OAAOE,EAAW;AAAA,cAClB,QAAQA,EAAW;AAAA,cACnB,UAAUF,EAAK,QAAQzE;AAAA,cACvB,UAAUyE,EAAK;AAAA,cACf,aAAY,oBAAI,KAAA,GAAO,YAAA;AAAA,cACvB,QAAAJ;AAAA,YAAA,CACD,GACDnD,EAAS,UAAU;AAAA,UACrB,QAAQ;AACN,YAAA2B,EAAY,gBAAgB;AAAA,UAC9B,UAAA;AACE,YAAApB,EAAY,EAAK;AAAA,UACnB;AAAA;AAAA,MACF;AAAA,MACA,CAACzB,GAAY6C,GAAahC,CAAU;AAAA,IAAA,GAGhCkE,KAAqBtC;AAAA,MACzB,CAACuC,MAAsC;;AAOrC,cAAMlC,MADSpE,IAAAsG,EAAW,CAAC,MAAZ,gBAAAtG,EAAe,YAEjB,mBAAmB,mBAAmB;AACnD,QAAAmE,EAAYC,CAAI;AAAA,MAClB;AAAA,MACA,CAACD,CAAW;AAAA,IAAA,GAIRoC,IAAUxC,EAAY,MAAM;;AAChC,MAAK7B,OACLlC,IAAAyD,EAAa,YAAb,QAAAzD,EAAA,KAAAyD,GAAuBvB;AAAA,IACzB,GAAG,CAACA,CAAO,CAAC,GAKNsE,KAAoBlE,EAAO,EAAK,GAEhCmE,KAAS1C,EAAY,MAAM;;AAO/B,UAAIH,GAAc;AAChB,SAAA5D,IAAA0D,EAAY,YAAZ,QAAA1D,EAAA,KAAA0D;AACA;AAAA,MACF;AACA,MAAArB,EAAU,UAAU,IACpBmE,GAAkB,UAAU,IAC5BrE,EAAW,IAAI,GACfQ,EAAa,IAAI,GACjBI,EAAY,EAAK,GACjBP,EAAS,MAAM,IACfkE,IAAAhD,EAAY,YAAZ,QAAAgD,EAAA,KAAAhD;AAAA,IACF,GAAG,CAACE,GAAczB,CAAU,CAAC;AAG7B,IAAAwB,EAAU,MAAM;;AACd,MAAIpB,MAAU,cAAc,CAACF,EAAU,WAErCrC,IAAAoD,GAAc,YAAd,QAAApD,EAAuB,UACduC,MAAU,WACnBmE,IAAAnD,GAAY,YAAZ,QAAAmD,EAAqB,UACZnE,MAAU,UAAUiE,GAAkB,YAG/CA,GAAkB,UAAU,KAC5BG,IAAArD,GAAgB,YAAhB,QAAAqD,EAAyB;AAAA,IAE7B,GAAG,CAACpE,CAAK,CAAC,GAGVoB,EAAU,MAAM;AACd,UAAIpB,MAAU,YAAa;AAC3B,YAAMqE,IAAY,CAACC,MAAyB;AAC1C,QAAIA,EAAM,QAAQ,aAChB/C,EAAA,GACAtB,EAAS,MAAM;AAAA,MAEnB;AACA,sBAAS,iBAAiB,WAAWoE,CAAS,GACvC,MAAM,SAAS,oBAAoB,WAAWA,CAAS;AAAA,IAChE,GAAG,CAACrE,GAAOuB,CAAU,CAAC,GAGtBH,EAAU,MAAM;AACd,YAAMmD,IAAe,MAAM;AACzB,QAAI,SAAS,oBAAoB,YAAY5D,EAAU,YACrDY,EAAA,GACAtB,EAAS,MAAM;AAAA,MAEnB;AACA,sBAAS,iBAAiB,oBAAoBsE,CAAY,GACnD,MACL,SAAS,oBAAoB,oBAAoBA,CAAY;AAAA,IACjE,GAAG,CAAChD,CAAU,CAAC,GAGfH,EAAU,MACD,MAAM;AACX,MAAAR,GAAa,UAAU;AACvB,YAAMa,IAAOd,EAAU;AACvB,MAAIc,OAAW,UAAA,EAAY,QAAQ,CAACC,MAAUA,EAAM,MAAM,GAC1Df,EAAU,UAAU;AAAA,IACtB,GACC,CAAA,CAAE,GAGLS,EAAU,MAAM;AACd,MAAKC,MACDhD,KAAS,OACX4B,EAAS,UAAU,IACVD,MAAU,cACnBC,EAAS,MAAM;AAAA,IAGnB,GAAG,CAAC5B,GAAOgD,CAAY,CAAC;AAGxB,UAAMmD,KAAcC;AAAA,MAClB,OAAO;AAAA,QACL,YAAY,MAAM9E,KAAW;AAAA,QAC7B,UAAU,MAAMK;AAAA,QAChB,aAAa,MAAM8B,EAAA;AAAA,QACnB,SAAS,MAAMM,EAAA;AAAA,QACf,SAAS,MAAM4B,EAAA;AAAA,QACf,QAAQ,MAAME,GAAA;AAAA,MAAO;AAAA,MAEvB,CAACvE,GAASK,GAAO8B,GAAaM,GAAc4B,GAASE,EAAM;AAAA,IAAA;AAE7D,IAAAQ,GAAoBpF,IAAK,MAAMkF,IAAa,CAACA,EAAW,CAAC,GACzDG,GAAqBnI,IAAsBgI,IAAapG,CAAE;AAG1D,UAAMwG,KAAcxF,MAAaG,EAAE,6BAA6B,GAC1DsF,KAAWtF,EAAEvB,GAASU,CAAY,CAAC,GACnCoG,KAAY,KAAK,MAAMjG,MAAW,OAAO,KAAK,GAE9CkG,MAAc,MAAM;AACxB,UAAIxE,GAAU,QAAOhB,EAAE,iCAAiC;AACxD,cAAQS,GAAA;AAAA,QACN,KAAK;AACH,iBAAOT,EAAE,4BAA4B;AAAA,QACvC,KAAK;AACH,iBAAOA,EAAE,kCAAkC;AAAA,QAC7C,KAAK;AACH,iBAAOA,EAAE,iCAAiC;AAAA,QAC5C,KAAK;AACH,iBAAOA,EAAE,gCAAgC;AAAA,QAC3C,KAAK;AACH,iBAAOY,IACHZ,EAAEtB,GAAUkC,CAAS,GAAG,EAAE,WAAA2E,GAAA,CAAW,IACrCvF,EAAE,qCAAqC;AAAA,MAAA;AAAA,IAEjD,GAAA,GAIMyF,KACJ,CAAC1D,KACDnB,MAAc,uBACdA,MAAc,oBACdA,MAAc,oBAKV8E,KACJ,CAAC/F,MACAP,MAAgB,UACfA,MAAgB,iBAChBqB,MAAU,UAERkF,KACJ,gBAAAC;AAAA,MAACC;AAAA,MAAA;AAAA,QACC,SAAQ;AAAA,QACR,QAAAxG;AAAA,QACA,SAAAC;AAAA,QACA,UAAU;AAAA,QACV,UAAU;AAAA,QACV,UAAAK;AAAA,QACA,aAAa;AAAA,QACb,QAAQ,CAACmG,MAAkB;AACzB,UAAK/B,GAAiB+B,CAAa;AAAA,QACrC;AAAA,QACA,UAAUvB;AAAA,MAAA;AAAA,IAAA,GAKRwB,KACJtF,MAAU,UACVA,MAAU,gBACVA,MAAU,eACVA,MAAU;AAEZ,WACE,gBAAAuF;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAYX;AAAA,QACZ,iBAAe1F,KAAY;AAAA,QAC3B,WAAW,CAACxC,GAAa,EAAE,MAAAyC,IAAM,GAAGE,EAAS,EAC1C,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,QACX,kBAAe;AAAA,QACf,qBAAmBjB;AAAA,QACnB,cAAY4B;AAAA,QAGZ,UAAA;AAAA,UAAA,gBAAAmF;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,aAAU;AAAA,cACV,eAAY;AAAA,cACZ,WAAU;AAAA,cACV,eAAY;AAAA,cAEX,UAAAJ;AAAA,YAAA;AAAA,UAAA;AAAA,UAGF/E,MAAU,cAAcL;AAAA;AAAA,YAEvB,gBAAA4F,EAAC,OAAA,EAAI,WAAU,kDACb,UAAA;AAAA,cAAA,gBAAAA,EAAC,SAAI,WAAW3I,GAAiB,EAAE,OAAO8B,GAAc,GACtD,UAAA;AAAA,gBAAA,gBAAAyG;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,KAAKxF,EAAQ;AAAA,oBACb,KAAKJ,EAAE,4BAA4B;AAAA,oBACnC,WAAW1C,GAAA;AAAA,oBACX,eAAY;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAEbiD,EAAU,UACT,gBAAAqF,EAAC,QAAA,EAAK,WAAU,4UACb,UAAA5F,EAAE,6BAA6B,EAAA,CAClC,IACE;AAAA,cAAA,GACN;AAAA,cACA,gBAAAgG,EAAC,OAAA,EAAI,WAAWvI,GAAA,GACd,UAAA;AAAA,gBAAA,gBAAAmI;AAAA,kBAACK;AAAA,kBAAA;AAAA,oBACC,QAAO;AAAA,oBACP,MAAK;AAAA,oBAIL,WAAU;AAAA,oBACV,WAAW,gBAAAL,EAACM,IAAA,EAAU,eAAY,OAAA,CAAO;AAAA,oBACzC,SAASvB;AAAA,oBACT,UAAAhF;AAAA,oBAEC,YAAE,wBAAwB;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAI5BY,EAAU,UAAU,OACnB,gBAAAqF;AAAA,kBAACK;AAAA,kBAAA;AAAA,oBACC,KAAK3E;AAAA,oBACL,QAAO;AAAA,oBACP,MAAK;AAAA,oBACL,WAAU;AAAA,oBACV,WAAW,gBAAAsE,EAACO,IAAA,EAAM,eAAY,OAAA,CAAO;AAAA,oBACrC,SAAS1B;AAAA,oBACT,UAAU9E,KAAYS,KAAW;AAAA,oBAEhC,YAAE,yBAAyB;AAAA,kBAAA;AAAA,gBAAA;AAAA,cAC9B,EAAA,CAEJ;AAAA,YAAA,EAAA,CACF;AAAA,cACE;AAAA,UAEH2F,KACC,gBAAAC,EAAC,OAAA,EAAI,WAAU,kDAGZ,UAAA;AAAA,YAAA,CAACjE,KAAgBtB,MAAU,UAC1B,gBAAAuF;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,KAAK7E;AAAA,gBACL,WAAW9D,GAAiB,EAAE,OAAO8B,GAAc;AAAA,gBACnD,aAAWsB,MAAU,gBAAgB;AAAA,gBAErC,UAAA;AAAA,kBAAA,gBAAAmF;AAAA,oBAAC;AAAA,oBAAA;AAAA,sBACC,KAAK1E;AAAA,sBACL,UAAQ;AAAA,sBACR,aAAW;AAAA,sBACX,OAAK;AAAA,sBACL,cAAYlB,EAAE,4BAA4B;AAAA,sBAC1C,WAAW1C,GAAA;AAAA,sBACX,kBAAkBoF;AAAA,sBAClB,WAAWA;AAAA,sBACX,eAAY;AAAA,oBAAA;AAAA,kBAAA;AAAA,kBAEbjC,MAAU,eACT,gBAAAmF,EAAC,OAAA,EAAI,WAAU,iIACb,UAAA,gBAAAA;AAAA,oBAACQ;AAAA,oBAAA;AAAA,sBACC,eAAY;AAAA,sBACZ,WAAU;AAAA,oBAAA;AAAA,kBAAA,GAEd,IACE;AAAA,kBAEJ,gBAAAJ;AAAA,oBAAC;AAAA,oBAAA;AAAA,sBACC,eAAY;AAAA,sBACZ,WAAWzI,GAAA;AAAA,sBACX,eAAY;AAAA,sBAEZ,UAAA;AAAA,wBAAA,gBAAAqI;AAAA,0BAAC;AAAA,0BAAA;AAAA,4BACC,WAAW;AAAA,8BACTpI,EAAA;AAAA,8BACA;AAAA,4BAAA,EACA,KAAK,GAAG;AAAA,0BAAA;AAAA,wBAAA;AAAA,wBAEZ,gBAAAoI;AAAA,0BAAC;AAAA,0BAAA;AAAA,4BACC,WAAW;AAAA,8BACTpI,EAAA;AAAA,8BACA;AAAA,4BAAA,EACA,KAAK,GAAG;AAAA,0BAAA;AAAA,wBAAA;AAAA,wBAEZ,gBAAAoI;AAAA,0BAAC;AAAA,0BAAA;AAAA,4BACC,WAAW;AAAA,8BACTpI,EAAA;AAAA,8BACA;AAAA,4BAAA,EACA,KAAK,GAAG;AAAA,0BAAA;AAAA,wBAAA;AAAA,wBAEZ,gBAAAoI;AAAA,0BAAC;AAAA,0BAAA;AAAA,4BACC,WAAW;AAAA,8BACTpI,EAAA;AAAA,8BACA;AAAA,4BAAA,EACA,KAAK,GAAG;AAAA,0BAAA;AAAA,wBAAA;AAAA,sBACZ;AAAA,oBAAA;AAAA,kBAAA;AAAA,gBACF;AAAA,cAAA;AAAA,YAAA,IAEA;AAAA,YAEHiD,MAAU,cACT,gBAAAmF,EAAC,KAAA,EAAE,IAAI1F,IAAQ,WAAWxC,GAAA,GACvB,UAAA4H,GAAA,CACH,IACE;AAAA,YAGH7E,MAAU,WAAWG,IACpB,gBAAAoF,EAACK,MAAM,SAAQ,SAAQ,MAAK,aAC1B,UAAA;AAAA,cAAA,gBAAAT,EAACS,GAAM,aAAN,EACE,UAAArG,EAAEtB,GAAUkC,CAAS,GAAG,EAAE,WAAA2E,GAAA,CAAW,EAAA,CACxC;AAAA,cACA,gBAAAS,EAACK,GAAM,QAAN,EAKE,UAAA;AAAA,gBAAAZ,KACC,gBAAAG;AAAA,kBAACK;AAAA,kBAAA;AAAA,oBACC,KAAKxE;AAAA,oBACL,QAAO;AAAA,oBACP,MAAK;AAAA,oBACL,SAAS,MAAM;AACb,sBAAKc,EAAA;AAAA,oBACP;AAAA,oBACA,UAAA5C;AAAA,oBAEC,YAAE,uBAAuB;AAAA,kBAAA;AAAA,gBAAA,IAE1B;AAAA,gBACH+F,KAAqBC,KAAmB;AAAA,cAAA,EAAA,CAC3C;AAAA,YAAA,EAAA,CACF,IACE;AAAA,YAGHlF,MAAU,UACT,gBAAAuF,EAAC,OAAA,EAAI,WAAWvI,MACb,UAAA;AAAA,cAAAgD,MAAU,cACT,gBAAAmF;AAAA,gBAACK;AAAA,gBAAA;AAAA,kBACC,KAAK1E;AAAA,kBACL,QAAO;AAAA,kBACP,MAAK;AAAA,kBACL,WAAW,gBAAAqE,EAACU,IAAA,EAAO,eAAY,OAAA,CAAO;AAAA,kBACtC,SAAS,MAAM;AACb,oBAAKzD,EAAA;AAAA,kBACP;AAAA,kBACA,UAAUlD,KAAY,CAACmB;AAAA,kBACvB,oBAAkBZ;AAAA,kBAClB,cAAYF,EAAE,yBAAyB;AAAA,kBAEtC,YAAE,yBAAyB;AAAA,gBAAA;AAAA,cAAA,IAE5B;AAAA,eAEFS,MAAU,UAAUA,MAAU,iBAChC,CAACsB,IACC,gBAAA6D;AAAA,gBAACK;AAAA,gBAAA;AAAA,kBACC,KAAKzE;AAAA,kBACL,QAAO;AAAA,kBACP,MAAK;AAAA,kBACL,WAAU;AAAA,kBACV,SAASf,MAAU;AAAA,kBACnB,WAAW,gBAAAmF,EAACU,IAAA,EAAO,eAAY,OAAA,CAAO;AAAA,kBACtC,SAAS,MAAM;AACb,oBAAK/D,EAAA;AAAA,kBACP;AAAA,kBACA,UAAA5C;AAAA,kBAEC,YAAE,2BAA2B;AAAA,gBAAA;AAAA,cAAA,IAE9B;AAAA,cAEHqB,KACC,gBAAAgF,EAAC,QAAA,EAAK,WAAU,4GACd,UAAA;AAAA,gBAAA,gBAAAJ;AAAA,kBAACQ;AAAA,kBAAA;AAAA,oBACC,eAAY;AAAA,oBACZ,WAAU;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAEXpG,EAAE,iCAAiC;AAAA,cAAA,EAAA,CACtC,IACE0F,MAAsBjF,MAAU,cAClCkF,KACE;AAAA,cAIHlF,MAAU,eAAerB,MAAgB,gBACtCuG,KACA;AAAA,YAAA,EAAA,CACN,IACE;AAAA,UAAA,EAAA,CACN,IACE;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGV;AACF;AAEAhH,GAAgB,cAAc;"}