@alfadocs/ui-kit-debug 1.65.0 → 1.67.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 (264) hide show
  1. package/dist/_chunks/ai-credits-exhausted-notice-DfAgfZDF.js +287 -0
  2. package/dist/_chunks/ai-credits-exhausted-notice-DfAgfZDF.js.map +1 -0
  3. package/dist/_chunks/ai-credits-exhausted-notice.agent-DgTSTgez.js +43 -0
  4. package/dist/_chunks/ai-credits-exhausted-notice.agent-DgTSTgez.js.map +1 -0
  5. package/dist/_chunks/ai-credits-notice-DQ-r3iQU.js +191 -0
  6. package/dist/_chunks/ai-credits-notice-DQ-r3iQU.js.map +1 -0
  7. package/dist/_chunks/{ai-permission-notice-DpRmZ9Q3.js → ai-permission-notice-qsdm4Sx4.js} +2 -2
  8. package/dist/_chunks/{ai-permission-notice-DpRmZ9Q3.js.map → ai-permission-notice-qsdm4Sx4.js.map} +1 -1
  9. package/dist/_chunks/{alert-DdDpOi-P.js → alert-DjsJMGRE.js} +3 -2
  10. package/dist/_chunks/{alert-DdDpOi-P.js.map → alert-DjsJMGRE.js.map} +1 -1
  11. package/dist/_chunks/{anamnesis-summary-rows-BIfw890v.js → anamnesis-summary-rows-BQ_EokKz.js} +2 -2
  12. package/dist/_chunks/{anamnesis-summary-rows-BIfw890v.js.map → anamnesis-summary-rows-BQ_EokKz.js.map} +1 -1
  13. package/dist/_chunks/{audio-recorder-DR-u1qbl.js → audio-recorder-B11RR-rC.js} +2 -2
  14. package/dist/_chunks/{audio-recorder-DR-u1qbl.js.map → audio-recorder-B11RR-rC.js.map} +1 -1
  15. package/dist/_chunks/{auth-form-parts-Cmb41LSQ.js → auth-form-parts-DwUTH6YN.js} +2 -2
  16. package/dist/_chunks/{auth-form-parts-Cmb41LSQ.js.map → auth-form-parts-DwUTH6YN.js.map} +1 -1
  17. package/dist/_chunks/{booking-DkjatiXc.js → booking-tTVxKPQY.js} +2 -2
  18. package/dist/_chunks/{booking-DkjatiXc.js.map → booking-tTVxKPQY.js.map} +1 -1
  19. package/dist/_chunks/{calendar-workspace-Cp8yTZ1g.js → calendar-workspace-MRrzcxAy.js} +6 -6
  20. package/dist/_chunks/{calendar-workspace-Cp8yTZ1g.js.map → calendar-workspace-MRrzcxAy.js.map} +1 -1
  21. package/dist/_chunks/chart-CwmyCuWe.js +1340 -0
  22. package/dist/_chunks/chart-CwmyCuWe.js.map +1 -0
  23. package/dist/_chunks/{document-preview-B1dQm292.js → document-preview-VyQOjFVL.js} +2 -2
  24. package/dist/_chunks/{document-preview-B1dQm292.js.map → document-preview-VyQOjFVL.js.map} +1 -1
  25. package/dist/_chunks/{document-scanner-CVPVLK7z.js → document-scanner-CXH_GYh4.js} +2 -2
  26. package/dist/_chunks/{document-scanner-CVPVLK7z.js.map → document-scanner-CXH_GYh4.js.map} +1 -1
  27. package/dist/_chunks/{entity-summary-BQ9_KA8S.js → entity-summary-Bj-Wxq7Y.js} +2 -2
  28. package/dist/_chunks/{entity-summary-BQ9_KA8S.js.map → entity-summary-Bj-Wxq7Y.js.map} +1 -1
  29. package/dist/_chunks/{error-summary-DrUfuKu1.js → error-summary-PUE5Zxp9.js} +2 -2
  30. package/dist/_chunks/{error-summary-DrUfuKu1.js.map → error-summary-PUE5Zxp9.js.map} +1 -1
  31. package/dist/_chunks/{forgot-password-form-CgZkEvZy.js → forgot-password-form-CPOfRE0C.js} +4 -4
  32. package/dist/_chunks/{forgot-password-form-CgZkEvZy.js.map → forgot-password-form-CPOfRE0C.js.map} +1 -1
  33. package/dist/_chunks/{freemium-paywall-DKJHRFpp.js → freemium-paywall-6DO7noHX.js} +2 -2
  34. package/dist/_chunks/{freemium-paywall-DKJHRFpp.js.map → freemium-paywall-6DO7noHX.js.map} +1 -1
  35. package/dist/_chunks/heatmap-C1TeC7wT.js +3650 -0
  36. package/dist/_chunks/heatmap-C1TeC7wT.js.map +1 -0
  37. package/dist/_chunks/help-me-write-templates-Bw3Q58x-.js +687 -0
  38. package/dist/_chunks/help-me-write-templates-Bw3Q58x-.js.map +1 -0
  39. package/dist/_chunks/hourglass-BEAzW1wE.js +26 -0
  40. package/dist/_chunks/hourglass-BEAzW1wE.js.map +1 -0
  41. package/dist/_chunks/{login-dev-card-PnADNcI9.js → login-dev-card-A-CL3mjt.js} +3 -3
  42. package/dist/_chunks/{login-dev-card-PnADNcI9.js.map → login-dev-card-A-CL3mjt.js.map} +1 -1
  43. package/dist/_chunks/{marketplace-app-shell-C-2e4eCD.js → marketplace-app-shell-DtSX8sYb.js} +2 -2
  44. package/dist/_chunks/{marketplace-app-shell-C-2e4eCD.js.map → marketplace-app-shell-DtSX8sYb.js.map} +1 -1
  45. package/dist/_chunks/{notes-panel-uEGIL7mi.js → notes-panel-IdsmqRFC.js} +3 -3
  46. package/dist/_chunks/{notes-panel-uEGIL7mi.js.map → notes-panel-IdsmqRFC.js.map} +1 -1
  47. package/dist/_chunks/{patient-details-4P1vA9Ls.js → patient-details-C-EWQTms.js} +2 -2
  48. package/dist/_chunks/{patient-details-4P1vA9Ls.js.map → patient-details-C-EWQTms.js.map} +1 -1
  49. package/dist/_chunks/{patient-field-row-CBXhlfGD.js → patient-field-row-lY-Tb5Mo.js} +155 -176
  50. package/dist/_chunks/patient-field-row-lY-Tb5Mo.js.map +1 -0
  51. package/dist/_chunks/{patient-search-DOnDUVsl.js → patient-search-DpAKidZ5.js} +2 -2
  52. package/dist/_chunks/{patient-search-DOnDUVsl.js.map → patient-search-DpAKidZ5.js.map} +1 -1
  53. package/dist/_chunks/{patient-summary-card-CuDLo8MP.js → patient-summary-card-Bpto_VCD.js} +2 -2
  54. package/dist/_chunks/{patient-summary-card-CuDLo8MP.js.map → patient-summary-card-Bpto_VCD.js.map} +1 -1
  55. package/dist/_chunks/{payment-automation-upsell-C8MEu0t6.js → payment-automation-upsell-BQ307qEX.js} +2 -2
  56. package/dist/_chunks/{payment-automation-upsell-C8MEu0t6.js.map → payment-automation-upsell-BQ307qEX.js.map} +1 -1
  57. package/dist/_chunks/{payment-form-C3dGY7v4.js → payment-form-XKtinW8r.js} +2 -2
  58. package/dist/_chunks/{payment-form-C3dGY7v4.js.map → payment-form-XKtinW8r.js.map} +1 -1
  59. package/dist/_chunks/{pdf-viewer-DJ9VN7cu.js → pdf-viewer-BvoVMjH4.js} +2 -2
  60. package/dist/_chunks/{pdf-viewer-DJ9VN7cu.js.map → pdf-viewer-BvoVMjH4.js.map} +1 -1
  61. package/dist/_chunks/{practice-results-8h2Utpt3.js → practice-results-BrUDDMXC.js} +2 -2
  62. package/dist/_chunks/{practice-results-8h2Utpt3.js.map → practice-results-BrUDDMXC.js.map} +1 -1
  63. package/dist/_chunks/{registration-form-BQyT_kBX.js → registration-form-BxwqUZzk.js} +3 -3
  64. package/dist/_chunks/{registration-form-BQyT_kBX.js.map → registration-form-BxwqUZzk.js.map} +1 -1
  65. package/dist/_chunks/{rich-text-editor-M2gT_E7f.js → rich-text-editor-aCIoptbg.js} +1653 -1743
  66. package/dist/_chunks/{rich-text-editor-M2gT_E7f.js.map → rich-text-editor-aCIoptbg.js.map} +1 -1
  67. package/dist/_chunks/{sign-document-CY7xTXbm.js → sign-document-D1P1nUQA.js} +2 -2
  68. package/dist/_chunks/{sign-document-CY7xTXbm.js.map → sign-document-D1P1nUQA.js.map} +1 -1
  69. package/dist/_chunks/{signature-request-BMCHy2ZO.js → signature-request-3u6TvRt2.js} +2 -2
  70. package/dist/_chunks/{signature-request-BMCHy2ZO.js.map → signature-request-3u6TvRt2.js.map} +1 -1
  71. package/dist/_chunks/{task-editor-CifOznfq.js → task-editor-Bb5MMcid.js} +2 -2
  72. package/dist/_chunks/{task-editor-CifOznfq.js.map → task-editor-Bb5MMcid.js.map} +1 -1
  73. package/dist/_chunks/{tasks-panel-8nLwBw6P.js → tasks-panel-BOb57Ysw.js} +2 -2
  74. package/dist/_chunks/{tasks-panel-8nLwBw6P.js.map → tasks-panel-BOb57Ysw.js.map} +1 -1
  75. package/dist/_chunks/{use-appointment-details-read-B-FEWbQM.js → use-appointment-details-read-CVSPoP5j.js} +4 -4
  76. package/dist/_chunks/{use-appointment-details-read-B-FEWbQM.js.map → use-appointment-details-read-CVSPoP5j.js.map} +1 -1
  77. package/dist/_chunks/voice-control-panel-BJIEbDq6.js +1148 -0
  78. package/dist/_chunks/voice-control-panel-BJIEbDq6.js.map +1 -0
  79. package/dist/_chunks/{warning-stack-HYWAytZV.js → warning-stack-BdY-0bd3.js} +2 -2
  80. package/dist/_chunks/{warning-stack-HYWAytZV.js.map → warning-stack-BdY-0bd3.js.map} +1 -1
  81. package/dist/_chunks/{workflow-map-C2B2qIr1.js → workflow-map-CYbRD9ek.js} +2 -2
  82. package/dist/_chunks/{workflow-map-C2B2qIr1.js.map → workflow-map-CYbRD9ek.js.map} +1 -1
  83. package/dist/agent-catalog.json +50 -3
  84. package/dist/agent-i18n/en.json +7 -4
  85. package/dist/components/_shared/use-apex-radial-centre.d.ts +7 -4
  86. package/dist/components/_shared/use-apex-radial-centre.d.ts.map +1 -1
  87. package/dist/components/ai-credits-notice/ai-credits-exhausted-notice.agent.d.ts +4 -0
  88. package/dist/components/ai-credits-notice/ai-credits-exhausted-notice.agent.d.ts.map +1 -0
  89. package/dist/components/ai-credits-notice/ai-credits-exhausted-notice.d.ts +96 -0
  90. package/dist/components/ai-credits-notice/ai-credits-exhausted-notice.d.ts.map +1 -0
  91. package/dist/components/ai-credits-notice/ai-credits-notice.d.ts +30 -4
  92. package/dist/components/ai-credits-notice/ai-credits-notice.d.ts.map +1 -1
  93. package/dist/components/ai-credits-notice/index.d.ts +3 -0
  94. package/dist/components/ai-credits-notice/index.d.ts.map +1 -1
  95. package/dist/components/ai-credits-notice/index.js +10 -4
  96. package/dist/components/ai-credits-notice/index.js.map +1 -1
  97. package/dist/components/ai-permission-notice/index.js +1 -1
  98. package/dist/components/alert/index.js +1 -1
  99. package/dist/components/appointment-details-panel/index.js +1 -1
  100. package/dist/components/audio-recorder/index.js +1 -1
  101. package/dist/components/booking/index.js +1 -1
  102. package/dist/components/chart/index.js +1 -1
  103. package/dist/components/document-preview/index.js +1 -1
  104. package/dist/components/document-scanner/index.js +1 -1
  105. package/dist/components/entity-summary/index.js +1 -1
  106. package/dist/components/error-summary/index.js +1 -1
  107. package/dist/components/freemium-paywall/index.js +1 -1
  108. package/dist/components/heatmap/heatmap-context.d.ts +3 -0
  109. package/dist/components/heatmap/heatmap-context.d.ts.map +1 -1
  110. package/dist/components/heatmap/heatmap-disclosure.d.ts +67 -0
  111. package/dist/components/heatmap/heatmap-disclosure.d.ts.map +1 -0
  112. package/dist/components/heatmap/heatmap-format.d.ts.map +1 -1
  113. package/dist/components/heatmap/heatmap-grid.d.ts +1 -1
  114. package/dist/components/heatmap/heatmap-grid.d.ts.map +1 -1
  115. package/dist/components/heatmap/heatmap-legend.d.ts +5 -2
  116. package/dist/components/heatmap/heatmap-legend.d.ts.map +1 -1
  117. package/dist/components/heatmap/heatmap-model.d.ts +107 -15
  118. package/dist/components/heatmap/heatmap-model.d.ts.map +1 -1
  119. package/dist/components/heatmap/heatmap-table-view.d.ts +3 -2
  120. package/dist/components/heatmap/heatmap-table-view.d.ts.map +1 -1
  121. package/dist/components/heatmap/heatmap.d.ts +33 -7
  122. package/dist/components/heatmap/heatmap.d.ts.map +1 -1
  123. package/dist/components/heatmap/index.d.ts +1 -1
  124. package/dist/components/heatmap/index.d.ts.map +1 -1
  125. package/dist/components/heatmap/index.js +1 -1
  126. package/dist/components/notes-panel/index.js +1 -1
  127. package/dist/components/patient-details/index.js +1 -1
  128. package/dist/components/patient-search/index.js +1 -1
  129. package/dist/components/patient-summary-card/index.js +1 -1
  130. package/dist/components/payment-form/index.js +1 -1
  131. package/dist/components/pdf-viewer/index.js +1 -1
  132. package/dist/components/practice-results/index.js +1 -1
  133. package/dist/components/rich-text-editor/index.js +1 -1
  134. package/dist/components/rich-text-editor/rich-text-editor.d.ts.map +1 -1
  135. package/dist/components/sign-document/index.js +1 -1
  136. package/dist/components/task-editor/index.js +1 -1
  137. package/dist/components/tasks-panel/index.js +1 -1
  138. package/dist/components/voice-control-panel/index.d.ts +2 -1
  139. package/dist/components/voice-control-panel/index.d.ts.map +1 -1
  140. package/dist/components/voice-control-panel/index.js +1 -1
  141. package/dist/components/voice-control-panel/voice-control-panel.agent.d.ts.map +1 -1
  142. package/dist/components/voice-control-panel/voice-control-panel.d.ts +43 -3
  143. package/dist/components/voice-control-panel/voice-control-panel.d.ts.map +1 -1
  144. package/dist/components/warning-stack/index.js +1 -1
  145. package/dist/components/workflow/index.js +1 -1
  146. package/dist/i18n/locales/ar.d.ts +29 -12
  147. package/dist/i18n/locales/ar.d.ts.map +1 -1
  148. package/dist/i18n/locales/ar.js +29 -12
  149. package/dist/i18n/locales/ar.js.map +1 -1
  150. package/dist/i18n/locales/de.d.ts +29 -12
  151. package/dist/i18n/locales/de.d.ts.map +1 -1
  152. package/dist/i18n/locales/de.js +29 -12
  153. package/dist/i18n/locales/de.js.map +1 -1
  154. package/dist/i18n/locales/el.d.ts +29 -12
  155. package/dist/i18n/locales/el.d.ts.map +1 -1
  156. package/dist/i18n/locales/el.js +29 -12
  157. package/dist/i18n/locales/el.js.map +1 -1
  158. package/dist/i18n/locales/en.d.ts +29 -12
  159. package/dist/i18n/locales/en.d.ts.map +1 -1
  160. package/dist/i18n/locales/en.js +29 -12
  161. package/dist/i18n/locales/en.js.map +1 -1
  162. package/dist/i18n/locales/es.d.ts +29 -12
  163. package/dist/i18n/locales/es.d.ts.map +1 -1
  164. package/dist/i18n/locales/es.js +29 -12
  165. package/dist/i18n/locales/es.js.map +1 -1
  166. package/dist/i18n/locales/fr.d.ts +29 -12
  167. package/dist/i18n/locales/fr.d.ts.map +1 -1
  168. package/dist/i18n/locales/fr.js +29 -12
  169. package/dist/i18n/locales/fr.js.map +1 -1
  170. package/dist/i18n/locales/hi.d.ts +29 -12
  171. package/dist/i18n/locales/hi.d.ts.map +1 -1
  172. package/dist/i18n/locales/hi.js +29 -12
  173. package/dist/i18n/locales/hi.js.map +1 -1
  174. package/dist/i18n/locales/it.d.ts +29 -12
  175. package/dist/i18n/locales/it.d.ts.map +1 -1
  176. package/dist/i18n/locales/it.js +29 -12
  177. package/dist/i18n/locales/it.js.map +1 -1
  178. package/dist/i18n/locales/ja.d.ts +29 -12
  179. package/dist/i18n/locales/ja.d.ts.map +1 -1
  180. package/dist/i18n/locales/ja.js +29 -12
  181. package/dist/i18n/locales/ja.js.map +1 -1
  182. package/dist/i18n/locales/nl.d.ts +29 -12
  183. package/dist/i18n/locales/nl.d.ts.map +1 -1
  184. package/dist/i18n/locales/nl.js +29 -12
  185. package/dist/i18n/locales/nl.js.map +1 -1
  186. package/dist/i18n/locales/pl.d.ts +29 -12
  187. package/dist/i18n/locales/pl.d.ts.map +1 -1
  188. package/dist/i18n/locales/pl.js +29 -12
  189. package/dist/i18n/locales/pl.js.map +1 -1
  190. package/dist/i18n/locales/pt.d.ts +29 -12
  191. package/dist/i18n/locales/pt.d.ts.map +1 -1
  192. package/dist/i18n/locales/pt.js +29 -12
  193. package/dist/i18n/locales/pt.js.map +1 -1
  194. package/dist/i18n/locales/ro.d.ts +29 -12
  195. package/dist/i18n/locales/ro.d.ts.map +1 -1
  196. package/dist/i18n/locales/ro.js +29 -12
  197. package/dist/i18n/locales/ro.js.map +1 -1
  198. package/dist/i18n/locales/ru.d.ts +29 -12
  199. package/dist/i18n/locales/ru.d.ts.map +1 -1
  200. package/dist/i18n/locales/ru.js +29 -12
  201. package/dist/i18n/locales/ru.js.map +1 -1
  202. package/dist/i18n/locales/sq.d.ts +29 -12
  203. package/dist/i18n/locales/sq.d.ts.map +1 -1
  204. package/dist/i18n/locales/sq.js +29 -12
  205. package/dist/i18n/locales/sq.js.map +1 -1
  206. package/dist/i18n/locales/sv.d.ts +29 -12
  207. package/dist/i18n/locales/sv.d.ts.map +1 -1
  208. package/dist/i18n/locales/sv.js +29 -12
  209. package/dist/i18n/locales/sv.js.map +1 -1
  210. package/dist/i18n/locales/tr.d.ts +29 -12
  211. package/dist/i18n/locales/tr.d.ts.map +1 -1
  212. package/dist/i18n/locales/tr.js +29 -12
  213. package/dist/i18n/locales/tr.js.map +1 -1
  214. package/dist/i18n/locales/zh.d.ts +29 -12
  215. package/dist/i18n/locales/zh.d.ts.map +1 -1
  216. package/dist/i18n/locales/zh.js +29 -12
  217. package/dist/i18n/locales/zh.js.map +1 -1
  218. package/dist/index.js +814 -809
  219. package/dist/index.js.map +1 -1
  220. package/dist/locales/ar.json +29 -12
  221. package/dist/locales/de.json +29 -12
  222. package/dist/locales/el.json +29 -12
  223. package/dist/locales/en.json +29 -12
  224. package/dist/locales/es.json +29 -12
  225. package/dist/locales/fr.json +29 -12
  226. package/dist/locales/hi.json +29 -12
  227. package/dist/locales/it.json +29 -12
  228. package/dist/locales/ja.json +29 -12
  229. package/dist/locales/nl.json +29 -12
  230. package/dist/locales/pl.json +29 -12
  231. package/dist/locales/pt.json +29 -12
  232. package/dist/locales/ro.json +29 -12
  233. package/dist/locales/ru.json +29 -12
  234. package/dist/locales/sq.json +29 -12
  235. package/dist/locales/sv.json +29 -12
  236. package/dist/locales/tr.json +29 -12
  237. package/dist/locales/zh.json +29 -12
  238. package/dist/patterns/anamnesis/index.js +1 -1
  239. package/dist/patterns/calendar/index.js +1 -1
  240. package/dist/patterns/forgot-password-form/index.js +1 -1
  241. package/dist/patterns/help-me-write-templates/help-me-write-templates.d.ts +6 -23
  242. package/dist/patterns/help-me-write-templates/help-me-write-templates.d.ts.map +1 -1
  243. package/dist/patterns/help-me-write-templates/index.js +8 -7
  244. package/dist/patterns/help-me-write-templates/index.js.map +1 -1
  245. package/dist/patterns/login-form/index.js +1 -1
  246. package/dist/patterns/marketplace-app-shell/index.js +1 -1
  247. package/dist/patterns/payment-automation-upsell/index.js +1 -1
  248. package/dist/patterns/registration-form/index.js +1 -1
  249. package/dist/patterns/signature-request/index.js +1 -1
  250. package/dist/tokens.css +1 -1
  251. package/package.json +1 -1
  252. package/dist/_chunks/ai-credits-notice-pK9BOmEz.js +0 -90
  253. package/dist/_chunks/ai-credits-notice-pK9BOmEz.js.map +0 -1
  254. package/dist/_chunks/ai-credits-notice.agent-C9L7orrP.js +0 -17
  255. package/dist/_chunks/ai-credits-notice.agent-C9L7orrP.js.map +0 -1
  256. package/dist/_chunks/chart-CIzXxNeM.js +0 -1322
  257. package/dist/_chunks/chart-CIzXxNeM.js.map +0 -1
  258. package/dist/_chunks/heatmap-BxRHM8Et.js +0 -2865
  259. package/dist/_chunks/heatmap-BxRHM8Et.js.map +0 -1
  260. package/dist/_chunks/help-me-write-templates-DFmqnsAa.js +0 -747
  261. package/dist/_chunks/help-me-write-templates-DFmqnsAa.js.map +0 -1
  262. package/dist/_chunks/patient-field-row-CBXhlfGD.js.map +0 -1
  263. package/dist/_chunks/voice-control-panel-C0BfY23Y.js +0 -1009
  264. package/dist/_chunks/voice-control-panel-C0BfY23Y.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-control-panel-BJIEbDq6.js","sources":["../../node_modules/lucide-react/dist/esm/icons/audio-lines.mjs","../../src/components/voice-control-panel/voice-control-panel.agent.ts","../../src/components/voice-control-panel/voice-control-panel.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 [\"path\", { d: \"M2 10v3\", key: \"1fnikh\" }],\n [\"path\", { d: \"M6 6v11\", key: \"11sgs0\" }],\n [\"path\", { d: \"M10 3v18\", key: \"yhl04a\" }],\n [\"path\", { d: \"M14 8v7\", key: \"3a1oy3\" }],\n [\"path\", { d: \"M18 5v13\", key: \"123xd1\" }],\n [\"path\", { d: \"M22 10v3\", key: \"154ddg\" }]\n];\nconst AudioLines = createLucideIcon(\"audio-lines\", __iconNode);\n\nexport { __iconNode, AudioLines as default };\n//# sourceMappingURL=audio-lines.mjs.map\n","/* -------------------------------------------------------------------- */\n/* Agent adapter: VoiceControlPanel. */\n/* */\n/* The panel draws a host-driven voice session; the host owns the */\n/* microphone and the speech service. `start_listening` / `stop_listening`*/\n/* call the same `onToggle` the button calls, but only in the direction */\n/* asked, so an agent never starts by mistake. They are `capture` and */\n/* `write` (start opens the microphone). Picking a match hands the host */\n/* an id through `onCandidatePick`, which the host turns into a write on */\n/* the patient's record, so it is `phi`. The commands disclosure is a */\n/* plain `expand`. In the floating layout the panel above the pill opens */\n/* and closes (`open` / `close`, `read`): closing never stops listening. */\n/* */\n/* No state slot returns the transcript, the target line or a message: */\n/* those can carry patient data the host put there. */\n/* */\n/* AI credits: `start_listening` is gated by `aiCredits.exhausted` after */\n/* the consent check, so out of credits it shows the out-of-credits */\n/* notice instead. The notice's buy, upgrade and support buttons are */\n/* host navigation an agent never presses; it can only read the gate and */\n/* close the notice (`close_credits_notice`, `read`). */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { VoiceControlPanelHandle } from './voice-control-panel';\n\nexport const voiceControlPanelAgent: AgentAdapter<VoiceControlPanelHandle> = {\n id: 'voice-control-panel',\n capabilities: ['capture', 'pick', 'expand', 'open', 'close'],\n state: {\n status: {\n type: \"'idle' | 'starting' | 'listening' | 'paused' | 'error'\",\n descriptionKey: 'ui.agent.voiceControlPanel.state.status',\n description:\n 'Where the host voice session is: idle, starting, listening, paused or error.',\n read: (handle) => handle.getStatus(),\n },\n candidateIds: {\n type: 'string[]',\n descriptionKey: 'ui.agent.voiceControlPanel.state.candidateIds',\n description:\n 'Ids of the matches currently offered, in spoken order (option 1 first). Empty when there is nothing to choose.',\n read: (handle) => handle.getCandidateIds(),\n },\n commandsOpen: {\n type: 'boolean',\n descriptionKey: 'ui.agent.voiceControlPanel.state.commandsOpen',\n description: 'True when the voice commands list is expanded.',\n read: (handle) => handle.isCommandsOpen(),\n },\n panelOpen: {\n type: 'boolean',\n descriptionKey: 'ui.agent.voiceControlPanel.state.panelOpen',\n description:\n 'Floating layout: true when the panel above the pill is open. Always false inline.',\n read: (handle) => handle.isPanelOpen(),\n },\n creditsExhausted: {\n type: 'boolean',\n descriptionKey: 'ui.agent.voiceControlPanel.state.creditsExhausted',\n description:\n 'True when the practice is out of AI credits: every start shows the out-of-credits notice instead of listening.',\n read: (handle) => handle.isCreditsExhausted(),\n },\n creditsNoticeOpen: {\n type: 'boolean',\n descriptionKey: 'ui.agent.voiceControlPanel.state.creditsNoticeOpen',\n description:\n 'True when the out-of-credits notice is showing in the panel, in place of the controls.',\n read: (handle) => handle.isCreditsNoticeOpen(),\n },\n },\n actions: {\n start_listening: {\n safety: 'write',\n idempotent: true,\n // The host streams the patient's audio to its transcription service.\n openWorld: true,\n descriptionKey: 'ui.agent.voiceControlPanel.actions.startListening',\n description:\n 'Ask the host to start listening (it opens the microphone). Does nothing when already starting or listening, or while the panel is disabled. Without patient AI consent it shows the consent banner instead; out of AI credits (creditsExhausted) it shows the out-of-credits notice instead.',\n errors: ['Microphone permission denied', 'Speech service unavailable'],\n invoke: (handle) => {\n handle.start();\n },\n },\n stop_listening: {\n safety: 'write',\n idempotent: true,\n descriptionKey: 'ui.agent.voiceControlPanel.actions.stopListening',\n description:\n 'Ask the host to stop listening, cancel a start or end a paused session. Never gated by consent or AI credits. Does nothing when idle or stopped.',\n invoke: (handle) => {\n handle.stop();\n },\n },\n pick_candidate: {\n // The host turns the pick into a write on the patient's record (the\n // care plan adds a treatment line), so it is gated as PHI.\n safety: 'phi',\n argsType: '{ id: string }',\n argsSchema: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'One of the ids in the candidateIds state slot.',\n },\n },\n required: ['id'],\n additionalProperties: false,\n },\n descriptionKey: 'ui.agent.voiceControlPanel.actions.pickCandidate',\n description:\n 'Pick one of the offered matches by id, the same as saying its option number or pressing it. Unknown ids are ignored.',\n examples: [\n { args: { id: 'otve' }, note: 'Pick the match with id otve.' },\n ],\n invoke: (handle, args: { id: string }) => {\n handle.pickCandidate(args.id);\n },\n },\n open_commands: {\n safety: 'read',\n idempotent: true,\n descriptionKey: 'ui.agent.voiceControlPanel.actions.openCommands',\n description: 'Expand the voice commands list.',\n invoke: (handle) => {\n handle.openCommands();\n },\n },\n close_commands: {\n safety: 'read',\n idempotent: true,\n descriptionKey: 'ui.agent.voiceControlPanel.actions.closeCommands',\n description: 'Collapse the voice commands list.',\n invoke: (handle) => {\n handle.closeCommands();\n },\n },\n open_panel: {\n safety: 'read',\n idempotent: true,\n descriptionKey: 'ui.agent.voiceControlPanel.actions.openPanel',\n description:\n 'Floating layout: open the panel above the pill. Does nothing inline.',\n invoke: (handle) => {\n handle.openPanel();\n },\n },\n close_panel: {\n safety: 'read',\n idempotent: true,\n descriptionKey: 'ui.agent.voiceControlPanel.actions.closePanel',\n description:\n 'Floating layout: close the panel above the pill. Listening carries on. Does nothing inline.',\n invoke: (handle) => {\n handle.closePanel();\n },\n },\n close_credits_notice: {\n safety: 'read',\n idempotent: true,\n descriptionKey: 'ui.agent.voiceControlPanel.actions.closeCreditsNotice',\n description:\n 'Close the out-of-credits notice and go back to the controls. Credits stay out: the next start shows it again.',\n invoke: (handle) => {\n handle.closeCreditsNotice();\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'voice-control-panel',\n description: 'Marks the VoiceControlPanel root.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop on VoiceControlPanel.',\n },\n item: {\n attr: 'data-candidate-id',\n description:\n 'On each match button, the candidate id that pick_candidate takes.',\n },\n },\n};\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { cva } from 'class-variance-authority';\nimport { Trans, useTranslation } from 'react-i18next';\nimport {\n AudioLines,\n ChevronDown,\n CircleAlert,\n CircleCheck,\n Info,\n LoaderCircle,\n SlidersHorizontal,\n Square,\n TriangleAlert,\n X,\n} from 'lucide-react';\nimport {\n AiCreditsExhaustedNotice,\n AiCreditsWarning,\n type AiCreditsInfo,\n type AiCreditsNoticeProps,\n} from '../ai-credits-notice';\nimport {\n useDismissibleAiCreditsNotice,\n withAiCreditsNotice,\n} from '../ai-credits-notice/ai-credits-notice';\nimport {\n AiConsentBanner,\n type AiConsentBannerHeadingLevel,\n type AiConsentGate,\n} from '../ai-permission-notice';\nimport { AiSparkle } from '../ai-sparkle';\nimport { Badge } from '../badge';\nimport { Button, IconButton } from '../button';\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '../collapsible';\nimport { FormField } from '../form-field';\nimport { Kbd, type KbdNamedKey } from '../kbd';\nimport { List } from '../list';\nimport { LiveRegion } from '../live-region';\nimport { Select, type SelectOption } from '../select';\nimport {\n aiFabDividerClass,\n aiFabPillClass,\n aiFabSegmentVariants,\n aiFabSweepClass,\n} from '../_shared/ai-fab-pill';\nimport { composeRefs } from '../_shared/compose-refs';\nimport {\n glassEntranceClass,\n glassSurfaceClass,\n} from '../_shared/glass-surface';\nimport { publishFloatingClearance } from '../_shared/floating-clearance';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { useAiSparkle } from '../../hooks/use-ai-sparkle';\nimport { useIsomorphicLayoutEffect } from '../../hooks/use-isomorphic-layout-effect';\nimport { voiceControlPanelAgent } from './voice-control-panel.agent';\n\n/* -------------------------------------------------------------------- */\n/* VoiceControlPanel */\n/* */\n/* The kit draws the voice-control UI; the host owns the microphone and */\n/* the speech service and drives the panel through props. The same split */\n/* as RichTextEditor's `onDictate`: no audio, no network, no parsing in */\n/* the kit. The panel is compact so it can sit inline above a chart today */\n/* and move into a tool rail later: a container query stacks it in a */\n/* narrow container. */\n/* */\n/* `layout=\"floating\"` draws the same panel as a non-modal companion */\n/* above the RichTextEditor's AI pill (shared recipe in */\n/* `_shared/ai-fab-pill.ts`), fixed to a viewport corner: mic | panel. */\n/* */\n/* `aiConsent` puts every start behind the patient AI-consent gate, the */\n/* same contract, banner and resume-after-grant as RichTextEditor. */\n/* `aiCredits` puts it behind the practice's AI credits too, checked */\n/* after consent, with the shared AiCreditsExhaustedNotice. */\n/* -------------------------------------------------------------------- */\n\n/* -------------------------------------------------------------------- */\n/* Public types */\n/* -------------------------------------------------------------------- */\n\n/** Where the host's voice session is. */\nexport type VoiceControlStatus =\n | 'idle'\n | 'starting'\n | 'listening'\n | 'paused'\n | 'error';\n\n/** How a message reads: the tone decides the colour and the icon. */\nexport type VoiceControlTone = 'info' | 'success' | 'warning' | 'error';\n\n/** Generic failures the kit words itself, translated. */\nexport type VoiceControlError =\n | 'microphoneDenied'\n | 'connectionLost'\n | 'startFailed'\n | 'recordingFailed'\n | 'unsupported';\n\n/** A host message, already translated by the host. */\nexport interface VoiceControlMessage {\n tone: VoiceControlTone;\n text: string;\n /**\n * Change it to announce the same words again (the live region only speaks\n * when the message changes), e.g. a counter for \"Not recognised\" twice.\n */\n id?: string | number;\n}\n\n/** What the speech service heard. `partial` may still change. */\nexport interface VoiceControlTranscript {\n final?: string;\n partial?: string;\n}\n\n/** One dictation language the host's speech service accepts. */\nexport interface VoiceControlLanguage {\n value: string;\n label: string;\n}\n\n/** One match the user can pick by voice (\"option 1\") or by hand. */\nexport interface VoiceControlCandidate {\n id: string;\n label: string;\n detail?: string;\n}\n\n/** One voice command shown in the commands disclosure. */\nexport interface VoiceControlCommand {\n phrase: ReactNode;\n description: ReactNode;\n}\n\n/** What a press asks the host to do: start (or resume), or stop (or cancel\n * a start). */\nexport type VoiceControlToggle = 'start' | 'stop';\n\n/** Inline in the page flow, or a floating pill that opens the panel. */\nexport type VoiceControlLayout = 'inline' | 'floating';\n\n/** The viewport corner of the floating pill. Logical: mirrors in RTL. */\nexport type VoiceControlPosition = 'bottom-end' | 'bottom-start';\n\n/**\n * The practice's AI credits, as the platform keeps them (a yearly allowance\n * that expires, then welcome and bought credits that do not), plus whether\n * they have run out. See `AiCreditsInfo` for the allowance, the dates and\n * the next steps the host can offer.\n */\nexport interface VoiceControlAiCredits extends AiCreditsInfo {\n /**\n * Out of AI credits. Every way of starting shows the out-of-credits\n * notice in the panel instead of calling `onToggle`; stopping is never\n * gated. Set while a session runs or is paused, the panel stops it\n * (`onToggle('stop')`, once) and shows the notice on its own.\n */\n exhausted?: boolean;\n}\n\n/** Curated imperative handle for agent / external automation. */\nexport interface VoiceControlPanelHandle {\n getStatus: () => VoiceControlStatus;\n /** Ask the host to start (`onToggle('start')`) unless already starting\n * or listening, or disabled. Gated by `aiConsent` like a press. */\n start: () => void;\n /** Ask the host to stop, cancel a start or end a paused session\n * (`onToggle('stop')`); a no-op when idle or stopped. Never gated. */\n stop: () => void;\n getCandidateIds: () => string[];\n pickCandidate: (id: string) => void;\n isCommandsOpen: () => boolean;\n openCommands: () => void;\n closeCommands: () => void;\n /** Floating layout: whether the panel above the pill is open. Always\n * false inline. */\n isPanelOpen: () => boolean;\n /** Floating layout: open the panel (no focus move). A no-op inline. */\n openPanel: () => void;\n /** Floating layout: close the panel; listening carries on. A no-op inline. */\n closePanel: () => void;\n /** Whether `aiCredits.exhausted` is gating every start. */\n isCreditsExhausted: () => boolean;\n /** Whether the out-of-credits notice is showing. */\n isCreditsNoticeOpen: () => boolean;\n /** Close the out-of-credits notice, back to the controls. */\n closeCreditsNotice: () => void;\n}\n\nexport interface VoiceControlPanelProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'title' | 'children' | 'onToggle'\n> {\n /** Where the host's voice session is. Drives the button, dot and status. */\n status: VoiceControlStatus;\n /**\n * The start/stop button, the pill's voice segment, the shortcut and the\n * agent call this, saying which way: `'start'` when idle, paused or\n * stopped, `'stop'` when starting or listening (stop, or cancel a start).\n * Every stop is passed on, so act on the argument rather than flip your\n * own state. A host that ignores the argument keeps working.\n */\n onToggle: (next: VoiceControlToggle) => void;\n /**\n * Stops a session from starting: disables the button, the shortcut, the\n * settings and the matches. A session already starting or listening can\n * still be stopped, so the microphone is never trapped on.\n */\n disabled?: boolean;\n /** Panel title. Default: the kit's \"Voice control\". */\n title?: ReactNode;\n /** Shows a \"Beta\" badge beside the title. */\n beta?: boolean;\n /** A host notice under the title, e.g. \"Free during the beta.\" */\n betaNotice?: ReactNode;\n /** The current dictation language (a `languages` value). */\n language?: string;\n /** Dictation languages. The select shows only with two or more. */\n languages?: VoiceControlLanguage[];\n onLanguageChange?: (value: string) => void;\n /** Extra settings beside the language, e.g. the periodontal route select. */\n extraControls?: ReactNode;\n /** The bold \"where am I\" line: the field or elements voice acts on. */\n target?: ReactNode;\n /** What the speech service heard: `final` reads normal, `partial` muted. */\n transcript?: VoiceControlTranscript;\n /** A host message. The tone sets colour and icon; not every message is red. */\n message?: VoiceControlMessage | null;\n /** A generic failure, worded and translated by the kit (tone: error). */\n error?: VoiceControlError | null;\n /** Several matches to choose from, numbered as they are spoken. */\n candidates?: VoiceControlCandidate[];\n /** Host label above the matches, e.g. \"Several matches: say 'option 1'…\". */\n candidatesLabel?: string;\n onCandidatePick?: (id: string) => void;\n /** Voice commands listed in the disclosure under the panel. */\n commands?: VoiceControlCommand[];\n /** Start with the commands disclosure open. */\n defaultCommandsOpen?: boolean;\n /**\n * Keyboard shortcut the kit binds document-wide to toggle, e.g. `\"Alt+V\"`\n * (default). Modifiers: Alt, Control, Shift, Meta. `false` turns it off.\n */\n shortcut?: string | false;\n /** Opaque instance id: `data-component-id` and agent registration. */\n id?: string;\n /**\n * `inline` (default): the panel sits in the page flow, above the chart.\n * `floating`: the RichTextEditor's AI pill (mic | panel) fixed to a\n * viewport corner; the second segment opens this panel above it, non-modal.\n */\n layout?: VoiceControlLayout;\n /**\n * Floating only: the viewport corner. Default `bottom-end`; `bottom-start`\n * moves the pill away from another floating widget (a chat bubble).\n */\n position?: VoiceControlPosition;\n /** Floating only: whether the panel above the pill is open (controlled). */\n open?: boolean;\n /** Floating only: the open state when uncontrolled. Default `false`. */\n defaultOpen?: boolean;\n /**\n * Floating only: called when the panel opens or closes, by the pill, the\n * close button, Escape, or on its own for an error or a set of matches.\n */\n onOpenChange?: (open: boolean) => void;\n /**\n * Floating only: the pill's sparkle, as on the RichTextEditor's pill. It\n * plays once when the pill first shows and again when a success message\n * arrives (a write landed); never in a loop while listening. Default `true`.\n */\n aiSparkle?: boolean;\n /**\n * Patient AI-consent gate: voice sends patient audio to the host's speech\n * service. Same contract as RichTextEditor's `aiConsent`. While present and\n * not granted, every way of starting shows the `AiConsentBanner` instead of\n * calling `onToggle`; stopping is never gated. Omit for ungated behaviour.\n */\n aiConsent?: AiConsentGate;\n /**\n * Heading level for the `AiConsentBanner` title and the out-of-credits\n * notice title, which show in the same place. Default 5.\n */\n aiConsentHeadingLevel?: AiConsentBannerHeadingLevel;\n /**\n * The practice's AI credits. With `exhausted`, every way of starting (the\n * Start button, the pill's mic, the shortcut, the agent's\n * `start_listening`) shows the out-of-credits notice instead of calling\n * `onToggle`, after the consent check; stopping is never gated. Running\n * low (80% used, or `runningLow`) and `expiring` show as quiet lines in\n * the panel and never block. Omit for ungated behaviour.\n */\n aiCredits?: VoiceControlAiCredits;\n /**\n * Floating only: the `AiCreditsNotice` hover card on the pill's mic, as on\n * the RichTextEditor's AI triggers. It never takes the click: the mic\n * still starts, stops or opens a gate exactly as without it.\n */\n aiCreditsNotice?: AiCreditsNoticeProps;\n}\n\n/* -------------------------------------------------------------------- */\n/* CVA */\n/* -------------------------------------------------------------------- */\n\nconst rootVariants = cva(\n [\n // The container query lives on the root and is read by descendants only,\n // never by a flex parent of its own (see the grid below).\n 'ds:@container/voice-control',\n 'ds:block ds:w-full ds:min-w-0',\n // The edge is --surface-border-width (1px, 2px in the accessible themes),\n // at zero specificity so the nearest theme root decides it.\n 'ds:rounded-[var(--radius-lg)] ds:[:where(&)]:border-[length:var(--surface-border-width,var(--border-width-sm))]',\n 'ds:bg-[var(--card)] ds:text-[color:var(--foreground)]',\n 'ds:p-[var(--spacing-md)]',\n 'ds:print:hidden',\n ].join(' '),\n {\n variants: {\n // The border colour lives only here, never beside a base colour, so\n // the listening ring can't lose a race on stylesheet order.\n status: {\n idle: 'ds:border-[color:var(--card-border)]',\n starting: 'ds:border-[color:var(--card-border)]',\n listening: 'ds:border-[color:var(--ring)]',\n paused: 'ds:border-[color:var(--card-border)]',\n error: 'ds:border-[color:var(--card-border)]',\n },\n },\n defaultVariants: { status: 'idle' },\n },\n);\n\nconst statusDotVariants = cva(\n [\n 'ds:relative ds:inline-flex ds:size-2.5 ds:shrink-0 ds:rounded-[var(--radius-full)]',\n 'ds:forced-colors:border ds:forced-colors:border-[CanvasText]',\n ].join(' '),\n {\n variants: {\n status: {\n idle: 'ds:border ds:border-[color:var(--muted-foreground)]',\n starting: 'ds:bg-[color:var(--muted-foreground)]',\n listening: 'ds:bg-[color:var(--destructive)]',\n paused: 'ds:bg-[color:var(--warning)]',\n error: 'ds:bg-[color:var(--error)]',\n },\n },\n defaultVariants: { status: 'idle' },\n },\n);\n\nconst messageVariants = cva(\n 'ds:m-0 ds:flex ds:items-start ds:gap-[var(--spacing-xs)] type-body-sm',\n {\n variants: {\n tone: {\n info: 'ds:text-[color:var(--info-foreground)]',\n success: 'ds:text-[color:var(--success-foreground)]',\n warning: 'ds:text-[color:var(--warning-foreground)]',\n error: 'ds:text-[color:var(--error-foreground)]',\n },\n },\n defaultVariants: { tone: 'info' },\n },\n);\n\nconst focusRing =\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)] ds:forced-colors:focus-visible:outline-[CanvasText]';\n\nconst candidateButtonVariants = cva(\n [\n 'ds:flex ds:w-full ds:items-center',\n 'ds:min-h-[var(--min-target-size)] ds:rounded-[var(--radius-sm)]',\n 'ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)] ds:py-[var(--spacing-2xs)]',\n 'ds:text-start ds:text-[color:var(--foreground)] ds:cursor-pointer',\n 'ds:hover:bg-[color:var(--muted)] ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:disabled:cursor-not-allowed ds:disabled:opacity-50',\n focusRing,\n ].join(' '),\n);\n\nconst commandsTriggerVariants = cva(\n [\n 'ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]',\n 'ds:min-h-[var(--min-target-size)] ds:py-[var(--spacing-2xs)]',\n 'ds:rounded-[var(--radius-sm)] type-meta ds:text-[color:var(--muted-foreground)] ds:text-start',\n 'ds:hover:text-[color:var(--foreground)] ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n focusRing,\n ].join(' '),\n);\n\n/* ---- Floating layout ------------------------------------------------ */\n\n// The fixed cluster: the panel stacked above the pill, in one viewport\n// corner. `--z-fixed` is the kit's layer for viewport-fixed controls (the\n// FloatingActionButton's): above sticky chrome, below a modal's backdrop, so\n// an open Dialog covers the pill and the page together. The Select listbox\n// the panel opens portals to <body> on its own `--z-dropdown` layer, above\n// this one. The cluster is as wide as the open panel; its empty corner lets\n// clicks through to the page.\nconst floatingRootVariants = cva(\n [\n 'ds:fixed ds:z-[var(--z-fixed)]',\n // `--voice-control-offset` (default: the kit's corner gap) lifts the\n // cluster, for example above the page's own floating button; the\n // panel's height cap below reads the same property.\n 'ds:bottom-[calc(var(--voice-control-offset,var(--spacing-lg))+env(safe-area-inset-bottom,0px))]',\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]',\n 'ds:pointer-events-none ds:[&>*]:pointer-events-auto',\n 'ds:print:hidden',\n ].join(' '),\n {\n variants: {\n position: {\n 'bottom-end': 'ds:end-[var(--spacing-lg)] ds:items-end',\n 'bottom-start': 'ds:start-[var(--spacing-lg)] ds:items-start',\n },\n },\n defaultVariants: { position: 'bottom-end' },\n },\n);\n\n// The panel above the pill: the Help me write card's liquid glass (shared\n// recipe in `_shared/glass-surface.ts`, with its opaque fallback for the\n// accessible themes, more contrast, reduced transparency and forced\n// colours), so AI tools share one look. Compact: never wider than the\n// viewport minus the gutter on both sides, never taller than the room above\n// the pill; longer content scrolls inside. It grows out of the pill's\n// corner. `transform-origin` has no logical keywords, so the corner is\n// picked per position and direction: bottom-end is the bottom-right corner\n// in LTR and the bottom-left in RTL.\nconst floatingPanelVariants = cva(\n [\n 'ds:@container/voice-control',\n // Closed is `hidden`: never let a display utility win over it.\n 'ds:min-w-0 ds:[&[hidden]]:hidden',\n 'ds:[inline-size:min(24rem,calc(100vw-(var(--spacing-lg)*2)))]',\n 'ds:[max-block-size:calc(100dvh-var(--min-target-size)-var(--voice-control-offset,var(--spacing-lg))-var(--spacing-lg)-var(--spacing-sm)-env(safe-area-inset-bottom,0px))]',\n // On a phone the panel spans the screen, so it stops at half the height\n // (scrolling inside) and the voice cursor row above it stays in view.\n 'ds:max-sm:[max-block-size:calc(50dvh-var(--min-target-size)-var(--voice-control-offset,var(--spacing-lg))-var(--spacing-lg)-var(--spacing-sm)-env(safe-area-inset-bottom,0px))]',\n 'ds:overflow-y-auto ds:overscroll-contain',\n glassSurfaceClass,\n glassEntranceClass,\n 'ds:text-[color:var(--foreground)]',\n focusRing,\n ].join(' '),\n {\n variants: {\n position: {\n 'bottom-end': 'ds:origin-bottom-right ds:rtl:origin-bottom-left',\n 'bottom-start': 'ds:origin-bottom-left ds:rtl:origin-bottom-right',\n },\n },\n defaultVariants: { position: 'bottom-end' },\n },\n);\n\n// The pill's mic segment. While listening it carries the word \"Listening\"\n// beside the stop icon, so it widens like an extended FAB.\nconst micSegmentVariants = cva(\n 'ds:disabled:cursor-not-allowed ds:disabled:opacity-50',\n {\n variants: {\n extended: {\n true: 'ds:gap-[var(--spacing-xs)] ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-md)]',\n false: '',\n },\n },\n defaultVariants: { extended: false },\n },\n);\n\n/* -------------------------------------------------------------------- */\n/* Shortcut */\n/* -------------------------------------------------------------------- */\n\ntype ShortcutModifier = Extract<\n KbdNamedKey,\n 'Alt' | 'Control' | 'Shift' | 'Meta'\n>;\n\ninterface ParsedShortcut {\n modifiers: Set<ShortcutModifier>;\n key: string;\n /** `aria-keyshortcuts` value, e.g. `Alt+V`. */\n aria: string;\n /** Keys for the kit Kbd, e.g. `['Alt', 'V']`. */\n keys: string[];\n}\n\nconst MODIFIER_ALIASES: Record<string, ShortcutModifier> = {\n alt: 'Alt',\n option: 'Alt',\n ctrl: 'Control',\n control: 'Control',\n shift: 'Shift',\n meta: 'Meta',\n cmd: 'Meta',\n command: 'Meta',\n};\n\n/** Parse `\"Alt+V\"`-style shortcuts. Returns null for an unusable string. */\nexport function parseVoiceShortcut(shortcut: string): ParsedShortcut | null {\n const parts = shortcut\n .split('+')\n .map((part) => part.trim())\n .filter(Boolean);\n if (parts.length === 0) return null;\n const rawKey = parts[parts.length - 1];\n const modifiers = new Set<ShortcutModifier>();\n for (const part of parts.slice(0, -1)) {\n const modifier = MODIFIER_ALIASES[part.toLowerCase()];\n if (!modifier) return null;\n modifiers.add(modifier);\n }\n const key = rawKey.length === 1 ? rawKey.toUpperCase() : rawKey;\n const ordered = (['Control', 'Alt', 'Shift', 'Meta'] as const).filter((m) =>\n modifiers.has(m),\n );\n return {\n modifiers,\n key,\n aria: [...ordered, key].join('+'),\n keys: [...ordered, key],\n };\n}\n\n/** Whether a keydown matches a parsed shortcut. Letters and digits match on\n * the physical key, so Alt+V still matches on macOS, where Option+V types\n * a different character. */\nfunction matchesShortcut(event: KeyboardEvent, parsed: ParsedShortcut) {\n if (event.altKey !== parsed.modifiers.has('Alt')) return false;\n if (event.ctrlKey !== parsed.modifiers.has('Control')) return false;\n if (event.shiftKey !== parsed.modifiers.has('Shift')) return false;\n if (event.metaKey !== parsed.modifiers.has('Meta')) return false;\n const { key } = parsed;\n if (/^[A-Z]$/.test(key)) return event.code === `Key${key}`;\n if (/^[0-9]$/.test(key)) return event.code === `Digit${key}`;\n return event.key.toLowerCase() === key.toLowerCase();\n}\n\n/* -------------------------------------------------------------------- */\n/* Component */\n/* -------------------------------------------------------------------- */\n\ntype FocusTarget =\n | 'panel'\n | 'gate'\n | 'credits'\n | 'toggle'\n | 'launcher'\n | 'return';\n\n/** The shortcut as kit Kbd pills. `<Trans>` hands a placeholder component\n * `children` (null for a self-closing tag), which would switch Kbd to its\n * children path and render an empty pill, so this wrapper drops them. */\nfunction ShortcutKeys({ keys }: { keys: string[] }) {\n return <Kbd keys={keys} separator=\"plus\" size=\"sm\" />;\n}\n\nconst TONE_ICON: Record<VoiceControlTone, typeof Info> = {\n info: Info,\n success: CircleCheck,\n warning: TriangleAlert,\n error: CircleAlert,\n};\n\nconst NO_CANDIDATES: VoiceControlCandidate[] = [];\n\n// The kit's target size (44px, 48px in the accessible themes) on every\n// control in the panel, at every width: the panel is touch-first.\nconst TARGET_HEIGHT = 'ds:min-h-[var(--min-target-size)]';\nconst TARGET_SQUARE =\n 'ds:min-h-[var(--min-target-size)] ds:min-w-[var(--min-target-size)]';\n\n/** A part that already ends a sentence, in Latin, CJK or Arabic script. */\nconst SENTENCE_END = /[.!?…:。.!?؟।]$/u;\n\n/** How soon after a session ends that running out of credits still shows\n * the notice on its own. Later, it waits for the next start. */\nconst CREDITS_GRACE_MS = 10_000;\n\n/** Appended on every other announcement so a repeat still changes the\n * region's text (and is read again). Invisible, and not trimmed away. */\nconst NO_BREAK_SPACE = '\\u00a0';\n\n/**\n * VoiceControlPanel: the kit UI for a host-driven voice control session.\n * The host keeps the microphone and the speech service; the panel shows the\n * state, what was heard, where the voice acts, messages and matches, and\n * calls `onToggle` from its button and its keyboard shortcut.\n */\nexport const VoiceControlPanel = forwardRef<\n HTMLDivElement,\n VoiceControlPanelProps\n>(\n (\n {\n status,\n onToggle,\n disabled = false,\n title,\n beta = false,\n betaNotice,\n language,\n languages,\n onLanguageChange,\n extraControls,\n target,\n transcript,\n message,\n error,\n candidates = NO_CANDIDATES,\n candidatesLabel,\n onCandidatePick,\n commands,\n defaultCommandsOpen = false,\n shortcut = 'Alt+V',\n id,\n layout = 'inline',\n position = 'bottom-end',\n open,\n defaultOpen = false,\n onOpenChange,\n aiSparkle = true,\n aiConsent,\n aiConsentHeadingLevel,\n aiCredits,\n aiCreditsNotice: aiCreditsNoticeProp,\n className,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation('ui');\n const titleId = useId();\n const candidatesLabelId = useId();\n const panelId = useId();\n const [commandsOpen, setCommandsOpen] = useState(defaultCommandsOpen);\n const floating = layout === 'floating';\n\n const rootRef = useRef<HTMLDivElement>(null);\n const composedRef = useMemo(() => composeRefs(ref, rootRef), [ref]);\n const panelRef = useRef<HTMLDivElement>(null);\n const gateRef = useRef<HTMLDivElement>(null);\n const creditsRef = useRef<HTMLDivElement>(null);\n const toggleRef = useRef<HTMLButtonElement>(null);\n const launcherRef = useRef<HTMLButtonElement>(null);\n const pillRef = useRef<HTMLDivElement>(null);\n\n const parsedShortcut = useMemo(\n () => (shortcut === false ? null : parseVoiceShortcut(shortcut)),\n [shortcut],\n );\n useEffect(() => {\n if (import.meta.env.DEV && shortcut !== false && !parsedShortcut) {\n console.warn(\n `VoiceControlPanel: shortcut \"${shortcut}\" is not a valid shortcut ` +\n '(use modifiers Alt, Control, Shift, Meta and one key, e.g. \"Alt+V\"); it is off.',\n );\n }\n }, [shortcut, parsedShortcut]);\n\n /* ---- Floating panel: open state ---------------------------------- */\n const [openState, setOpenState] = useState(defaultOpen);\n const controlled = open !== undefined;\n const panelOpen = floating && (controlled ? open : openState);\n\n /* ---- AI consent gate --------------------------------------------- */\n // Hard stop, whatever the UI state: no consent, no start.\n const aiBlocked = aiConsent !== undefined && !aiConsent.granted;\n const [gateOpen, setGateOpen] = useState(false);\n const showGate = gateOpen && aiBlocked;\n // A start was gated: resume it if consent is granted from this banner.\n const resumeAfterGrantRef = useRef(false);\n // Set only by a Grant click HERE. A `granted` that flips for any other\n // reason (another patient, another tab) must not start listening.\n const grantRequestedRef = useRef(false);\n const [localGrantPending, setLocalGrantPending] = useState(false);\n const grantPending = (aiConsent?.pending ?? false) || localGrantPending;\n\n /* ---- AI credits gate (checked after consent) ---------------------- */\n const creditsBlocked = aiCredits?.exhausted === true;\n const [creditsOpen, setCreditsOpen] = useState(false);\n const showCredits = creditsOpen && creditsBlocked;\n // Set when the notice opens on its own (no focus move), so the live\n // region says why the panel changed. The ref lets the announcement join\n // a status change in the same commit (\"Not listening. You've run out…\");\n // the counter re-runs the announcer when nothing else changed.\n const creditsAnnouncePendingRef = useRef(false);\n const [creditsAnnounce, setCreditsAnnounce] = useState(0);\n // Mirrors `creditsOpen`, set at once by `openCredits` so a focus request\n // made from an effect survives until the notice renders.\n const creditsOpenRef = useRef(creditsOpen);\n creditsOpenRef.current = creditsOpen;\n // The body the gates replace: the controls, or a gate. Focus in here is\n // lost when the body swaps.\n const bodyRef = useRef<HTMLDivElement>(null);\n // Whether focus was last inside the notice: still true when the notice\n // unmounts with focus in it (no blur fires), false once focus left it.\n const noticeFocusRef = useRef(false);\n\n /* ---- Latest values for listeners, callbacks and the agent handle -- */\n const latest = useRef({\n status,\n onToggle,\n disabled,\n candidates,\n onCandidatePick,\n commandsOpen,\n aiBlocked,\n creditsBlocked,\n showCredits,\n floating,\n panelOpen,\n controlled,\n onOpenChange,\n });\n latest.current = {\n status,\n onToggle,\n disabled,\n candidates,\n onCandidatePick,\n commandsOpen,\n aiBlocked,\n creditsBlocked,\n showCredits,\n floating,\n panelOpen,\n controlled,\n onOpenChange,\n };\n\n // A focus move waits for the DOM to show its target; asking for one\n // always re-renders, so it runs now, never at some later render.\n const pendingFocusRef = useRef<FocusTarget | null>(null);\n const [, setFocusRequest] = useState(0);\n const requestFocus = useCallback((target: FocusTarget) => {\n pendingFocusRef.current = target;\n setFocusRequest((n) => n + 1);\n }, []);\n // Where focus was when a start was gated, to go back on Close.\n const gateReturnRef = useRef<HTMLElement | null>(null);\n // Consent withdrawn mid-session: the one automatic stop already sent.\n const stopSentRef = useRef(false);\n\n const setPanelOpen = useCallback((next: boolean) => {\n const now = latest.current;\n if (!now.floating || now.panelOpen === next) return;\n if (!now.controlled) setOpenState(next);\n now.onOpenChange?.(next);\n }, []);\n\n const closeGate = useCallback(() => {\n resumeAfterGrantRef.current = false;\n grantRequestedRef.current = false;\n setGateOpen(false);\n }, []);\n\n /** Where focus is now, to go back to on Close (never <body>). */\n const captureReturn = useCallback(() => {\n const focused =\n typeof document === 'undefined' ? null : document.activeElement;\n gateReturnRef.current =\n focused instanceof HTMLElement && focused !== document.body\n ? focused\n : null;\n }, []);\n\n const openGate = useCallback(() => {\n captureReturn();\n resumeAfterGrantRef.current = true;\n // Consent first: a credits notice still up gives way to the banner.\n setCreditsOpen(false);\n setGateOpen(true);\n setPanelOpen(true);\n requestFocus('gate');\n }, [captureReturn, setPanelOpen, requestFocus]);\n\n /** Whether focus sits in the body the gates replace (or is already\n * lost), so a swap must hand it on. */\n const focusInBody = useCallback(() => {\n if (typeof document === 'undefined') return false;\n const focused = document.activeElement;\n return (\n !focused ||\n focused === document.body ||\n Boolean(bodyRef.current?.contains(focused))\n );\n }, []);\n\n // Closing the notice with focus inside it sends focus to Start.\n const closeCredits = useCallback(() => {\n const inside = Boolean(\n creditsRef.current?.contains(document.activeElement),\n );\n noticeFocusRef.current = false;\n setCreditsOpen(false);\n if (inside) requestFocus('toggle');\n }, [requestFocus]);\n\n // A start met the credits gate: the notice takes the body and focus, as\n // the consent banner does. `keepReturn`: the start came through the\n // consent banner, which already holds where it was asked from.\n const openCredits = useCallback(\n (keepReturn = false) => {\n if (!keepReturn) captureReturn();\n creditsOpenRef.current = true;\n setCreditsOpen(true);\n setPanelOpen(true);\n requestFocus('credits');\n },\n [captureReturn, setPanelOpen, requestFocus],\n );\n\n // The one way in for the button, the pill's mic, the shortcut and the\n // agent: stopping (or cancelling a start) is never gated; starting is,\n // while consent is missing, then while credits are out.\n const requestToggle = useCallback(() => {\n const {\n status: now,\n disabled: off,\n aiBlocked: blocked,\n creditsBlocked: outOfCredits,\n } = latest.current;\n if (now === 'starting' || now === 'listening') {\n // Every stop reaches the host, never swallowed: it says 'stop', so a\n // repeat cannot be read as a start.\n latest.current.onToggle('stop');\n return;\n }\n if (off) return;\n if (blocked) {\n openGate();\n return;\n }\n if (outOfCredits) {\n openCredits();\n return;\n }\n latest.current.onToggle('start');\n }, [openGate, openCredits]);\n const requestToggleRef = useRef(requestToggle);\n requestToggleRef.current = requestToggle;\n\n const handleGrantConsent = useCallback(() => {\n grantRequestedRef.current = true;\n const result = aiConsent?.onGrant?.();\n if (result && typeof (result as Promise<void>).then === 'function') {\n setLocalGrantPending(true);\n Promise.resolve(result)\n .catch(() => {\n // The host shows its own failure UI (`pending`, a fresh\n // `granted: false`). This click no longer counts as the grant,\n // so a later grant from elsewhere will not start listening.\n grantRequestedRef.current = false;\n })\n .finally(() => setLocalGrantPending(false));\n }\n }, [aiConsent]);\n\n // Granted after a Grant click here: start listening, as the editor\n // resumes the action it gated. Granted any other way: close the banner.\n const prevGrantedRef = useRef(aiConsent?.granted ?? true);\n useEffect(() => {\n const wasGranted = prevGrantedRef.current;\n const nowGranted = aiConsent?.granted ?? true;\n prevGrantedRef.current = nowGranted;\n if (wasGranted || !nowGranted) return;\n const resume = resumeAfterGrantRef.current;\n const requestedHere = grantRequestedRef.current;\n resumeAfterGrantRef.current = false;\n grantRequestedRef.current = false;\n setGateOpen(false);\n if (!resume) return;\n const focusLost =\n typeof document === 'undefined' ||\n !document.activeElement ||\n document.activeElement === document.body;\n if (requestedHere) {\n const {\n status: now,\n disabled: off,\n creditsBlocked: outOfCredits,\n } = latest.current;\n if (!off && now !== 'starting' && now !== 'listening') {\n if (outOfCredits) {\n // Consent first, then credits: the resumed start meets the\n // credits gate instead of starting. Close still goes back to\n // where the start was asked from.\n openCredits(true);\n return;\n }\n latest.current.onToggle('start');\n }\n gateReturnRef.current = null;\n requestFocus('toggle');\n } else if (focusLost) {\n requestFocus('toggle');\n }\n }, [aiConsent?.granted, requestFocus, openCredits]);\n\n // Consent withdrawn (or the patient changed), or credits run out,\n // mid-session: stop, once. Paused counts: the host still holds the\n // session, and with a gate closed Resume is refused, so only this stop\n // (or the agent's) can end it.\n useEffect(() => {\n const held =\n status === 'starting' || status === 'listening' || status === 'paused';\n if (!held || !(aiBlocked || creditsBlocked)) {\n stopSentRef.current = false;\n return;\n }\n if (stopSentRef.current) return;\n stopSentRef.current = true;\n latest.current.onToggle('stop');\n }, [aiBlocked, creditsBlocked, status]);\n\n // Out of credits during a session, or within CREDITS_GRACE_MS of its\n // end (the host stopped first): once it has stopped, the notice shows\n // on its own, once per run-out, and the floating panel opens, as for an\n // error. While a session still runs, Stop stays in view. Credits that\n // load already exhausted, or run out long after the last session, wait\n // for the next start. Focus moves only if it was in the body the\n // notice replaces (the Stop the user pressed), never from the page.\n const sessionRef = useRef({ live: false, endedAt: -Infinity });\n const creditsShownRef = useRef(false);\n useEffect(() => {\n const session = sessionRef.current;\n const live =\n status === 'starting' || status === 'listening' || status === 'paused';\n if (live) {\n session.live = true;\n } else if (session.live) {\n session.live = false;\n session.endedAt = Date.now();\n }\n if (!creditsBlocked) {\n creditsShownRef.current = false;\n if (creditsOpenRef.current) {\n // Credits are back: the notice goes; focus in it goes to Start.\n if (noticeFocusRef.current && focusInBody()) requestFocus('toggle');\n noticeFocusRef.current = false;\n gateReturnRef.current = null;\n setCreditsOpen(false);\n }\n return;\n }\n if (creditsShownRef.current) return;\n if (status === 'starting' || status === 'listening') return;\n const recent =\n status === 'paused' || Date.now() - session.endedAt <= CREDITS_GRACE_MS;\n if (!recent) return;\n creditsShownRef.current = true;\n // Close goes back to Start: no earlier start's origin applies.\n gateReturnRef.current = null;\n if (focusInBody() && document.activeElement !== document.body) {\n // Focus moves with the notice, which then reads itself.\n requestFocus('credits');\n } else {\n // Focus stays on the page: the live region says what changed.\n noticeFocusRef.current = false;\n creditsAnnouncePendingRef.current = true;\n setCreditsAnnounce((n) => n + 1);\n }\n creditsOpenRef.current = true;\n setCreditsOpen(true);\n setPanelOpen(true);\n }, [creditsBlocked, status, setPanelOpen, focusInBody, requestFocus]);\n\n // Closing the floating panel closes the banner or notice inside it too.\n useEffect(() => {\n if (floating && !panelOpen && gateOpen) closeGate();\n if (floating && !panelOpen && creditsOpen) setCreditsOpen(false);\n }, [floating, panelOpen, gateOpen, closeGate, creditsOpen]);\n\n /* ---- Document-wide shortcut ------------------------------------- */\n useEffect(() => {\n if (!parsedShortcut || typeof document === 'undefined') return;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.defaultPrevented || event.repeat || event.isComposing) {\n return;\n }\n if (!matchesShortcut(event, parsedShortcut)) return;\n const { status: now, disabled: off } = latest.current;\n // Disabled stops a start, never a stop.\n if (off && now !== 'starting' && now !== 'listening') return;\n event.preventDefault();\n requestToggleRef.current();\n };\n document.addEventListener('keydown', onKeyDown);\n return () => document.removeEventListener('keydown', onKeyDown);\n }, [parsedShortcut]);\n\n /* ---- Agent handle ----------------------------------------------- */\n const handle = useMemo<VoiceControlPanelHandle>(\n () => ({\n getStatus: () => latest.current.status,\n start: () => {\n const { status: now, disabled: off } = latest.current;\n if (off || now === 'starting' || now === 'listening') return;\n // Gated like a user: without consent it shows the banner.\n requestToggleRef.current();\n },\n stop: () => {\n const { status: now } = latest.current;\n if (now !== 'starting' && now !== 'listening' && now !== 'paused') {\n return;\n }\n // Never gated, always 'stop', also for a paused session (whose\n // button would resume).\n latest.current.onToggle('stop');\n },\n getCandidateIds: () => latest.current.candidates.map((c) => c.id),\n pickCandidate: (candidateId: string) => {\n if (latest.current.disabled) return;\n if (!latest.current.candidates.some((c) => c.id === candidateId)) {\n return;\n }\n latest.current.onCandidatePick?.(candidateId);\n },\n isCommandsOpen: () => latest.current.commandsOpen,\n openCommands: () => setCommandsOpen(true),\n closeCommands: () => setCommandsOpen(false),\n isPanelOpen: () => latest.current.panelOpen,\n openPanel: () => setPanelOpen(true),\n closePanel: () => setPanelOpen(false),\n isCreditsExhausted: () => latest.current.creditsBlocked,\n isCreditsNoticeOpen: () => latest.current.showCredits,\n closeCreditsNotice: () => closeCredits(),\n }),\n [setPanelOpen, closeCredits],\n );\n useAgentRegistration(voiceControlPanelAgent, handle, id);\n\n /* ---- Strings ---------------------------------------------------- */\n const statusLabel = t(`voiceControl.status.${status}`);\n const errorText = error ? t(`voiceControl.error.${error}`) : '';\n const messageText = message?.text ?? '';\n // The id lets a host repeat the same words and still be heard.\n const messageKey = messageText\n ? `${message?.id ?? ''}\\u0000${messageText}`\n : '';\n const hasCandidates = candidates.length > 0;\n const candidatesKey = candidates.map((c) => c.id).join('\\u0000');\n const active = status === 'starting' || status === 'listening';\n\n // The label always says what pressing does. While starting, pressing\n // cancels; the spinner, aria-busy and the \"Connecting\" status carry the\n // busy state.\n const buttonLabel =\n status === 'listening'\n ? t('voiceControl.action.stop')\n : status === 'starting'\n ? t('common.cancel')\n : status === 'paused'\n ? t('voiceControl.action.resume')\n : t('voiceControl.action.start');\n\n /* ---- One live region: status, error, message, matches ------------ */\n const [announcement, setAnnouncement] = useState({ text: '', count: 0 });\n const announced = useRef({\n status,\n errorText,\n messageKey,\n candidatesKey,\n });\n useEffect(() => {\n const before = announced.current;\n const parts: string[] = [];\n if (status !== before.status) parts.push(statusLabel);\n if (errorText && errorText !== before.errorText) parts.push(errorText);\n if (messageKey && messageKey !== before.messageKey) {\n parts.push(messageText);\n }\n // A new set of matches, not only the first one.\n if (candidatesKey && candidatesKey !== before.candidatesKey) {\n parts.push(candidatesLabel || t('voiceControl.candidates'));\n }\n // The out-of-credits notice opened on its own (no focus move).\n if (creditsAnnouncePendingRef.current) {\n creditsAnnouncePendingRef.current = false;\n parts.push(t('aiCredits.title'));\n }\n announced.current = { status, errorText, messageKey, candidatesKey };\n if (parts.length > 0) {\n setAnnouncement((prev) => ({\n // A sentence break between parts gives the screen reader a pause:\n // \"Stopped. Microphone access is blocked…\". The break is a\n // translated template (Japanese ends a sentence with 。), skipped\n // when a part already ends one.\n text: parts.reduce((joined, part) =>\n SENTENCE_END.test(joined)\n ? `${joined} ${part}`\n : t('voiceControl.announcementJoin', {\n first: joined,\n next: part,\n }),\n ),\n count: prev.count + 1,\n }));\n }\n }, [\n t,\n status,\n statusLabel,\n errorText,\n messageKey,\n messageText,\n candidatesKey,\n candidatesLabel,\n creditsAnnounce,\n ]);\n\n /* ---- Floating: open on its own when the user must act ------------ */\n // A new error (the session stopped) or a new set of matches (a choice\n // is waiting) opens the panel, without moving focus.\n const attention = useRef({ error, candidatesKey });\n useEffect(() => {\n const before = attention.current;\n attention.current = { error, candidatesKey };\n if (!floating) return;\n if (\n (error && error !== before.error) ||\n (candidatesKey && candidatesKey !== before.candidatesKey)\n ) {\n setPanelOpen(true);\n }\n }, [floating, error, candidatesKey, setPanelOpen]);\n\n /* ---- Floating: clearance for scrolled-to and focused content ----- */\n // See `_shared/floating-clearance.ts`. Closed: how far the pill reaches\n // up from the viewport's bottom edge, plus a gap. Open: the panel too,\n // but never more than half the viewport, so a tall panel on a short\n // screen cannot push the cursor's whole working area off the page.\n // Layout heights (offsetHeight), so the panel's grow-in zoom does not\n // shrink the reading.\n useEffect(() => {\n const el = rootRef.current;\n if (!floating || !el) return undefined;\n const owner = {};\n const measure = () => {\n const style = window.getComputedStyle(el);\n const gap = Number.parseFloat(style.rowGap) || 0;\n const closed =\n (Number.parseFloat(style.bottom) || 0) +\n (pillRef.current?.offsetHeight ?? 0) +\n gap;\n const panel = panelRef.current;\n const panelHeight = panel && !panel.hidden ? panel.offsetHeight : 0;\n publishFloatingClearance(\n owner,\n panelHeight > 0\n ? Math.max(\n closed,\n Math.min(closed + panelHeight + gap, window.innerHeight / 2),\n )\n : closed,\n );\n };\n measure();\n const observer =\n typeof ResizeObserver === 'undefined'\n ? null\n : new ResizeObserver(measure);\n observer?.observe(el);\n window.addEventListener('resize', measure);\n return () => {\n observer?.disconnect();\n window.removeEventListener('resize', measure);\n publishFloatingClearance(owner, null);\n };\n }, [floating]);\n\n /* ---- Floating: the credits hover card on the mic ------------------ */\n // \"Don't show again\" hides it for the rest of this mount, per mode, as\n // on the RichTextEditor.\n const creditsNotice = useDismissibleAiCreditsNotice(\n floating ? aiCreditsNoticeProp : undefined,\n );\n\n /* ---- Floating: the pill's sparkle -------------------------------- */\n const sparkleOn = floating && aiSparkle;\n const {\n state: sparkleState,\n props: sparkleProps,\n land: landSparkle,\n } = useAiSparkle({ enabled: sparkleOn });\n const successKey = message?.tone === 'success' ? messageKey : '';\n const sparkledKey = useRef(successKey);\n useEffect(() => {\n if (successKey === sparkledKey.current) return;\n sparkledKey.current = successKey;\n if (sparkleOn && successKey) landSparkle();\n }, [sparkleOn, successKey, landSparkle]);\n\n /* ---- Focus after a pick ------------------------------------------ */\n // Picking a match usually makes the host clear the matches, which\n // unmounts the focused button and drops focus to <body>. Send it back to\n // the start/stop button instead. Only for a pick made on a match button.\n const restoreFocusRef = useRef(false);\n useEffect(() => {\n if (hasCandidates || !restoreFocusRef.current) return;\n restoreFocusRef.current = false;\n const focused =\n typeof document === 'undefined' ? null : document.activeElement;\n if (!focused || focused === document.body) toggleRef.current?.focus();\n }, [hasCandidates]);\n\n /* ---- Floating: Escape closes the panel ---------------------------- */\n // A native listener on the cluster: it hears keys from the pill and the\n // panel only, not from a portalled Select listbox, which closes itself.\n const closePanelRef = useRef<(refocus: boolean) => void>(() => {});\n useEffect(() => {\n const el = rootRef.current;\n if (!floating || !el) return undefined;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Escape' || event.defaultPrevented) return;\n if (!latest.current.panelOpen) return;\n event.preventDefault();\n closePanelRef.current(true);\n };\n el.addEventListener('keydown', onKeyDown);\n return () => el.removeEventListener('keydown', onKeyDown);\n }, [floating]);\n\n /* ---- Floating: a close from anywhere keeps focus on the page ------ */\n // Closed by the host (`open={false}`) while focus is inside: send it to\n // the panel segment, not to <body>. Read before the browser moves it.\n const wasOpenRef = useRef(panelOpen);\n useIsomorphicLayoutEffect(() => {\n const wasOpen = wasOpenRef.current;\n wasOpenRef.current = panelOpen;\n if (!wasOpen || panelOpen || pendingFocusRef.current) return;\n const focused = document.activeElement;\n if (focused && panelRef.current?.contains(focused)) {\n requestFocus('launcher');\n }\n }, [panelOpen, requestFocus]);\n\n /* ---- Pending focus moves (declared last: runs after the others) -- */\n // Focus moves wait for the DOM to show the target (the panel and the\n // banner mount or unhide in the same commit that asks for focus).\n useEffect(() => {\n const target = pendingFocusRef.current;\n if (!target) return;\n // Opened from an effect (a start resumed after a grant), the notice\n // shows a render later: keep the request until it does, unless the\n // credits came back in the meantime.\n if (target === 'credits' && !creditsRef.current) {\n if (!latest.current.creditsBlocked || !creditsOpenRef.current) {\n pendingFocusRef.current = null;\n }\n return;\n }\n pendingFocusRef.current = null;\n if (target === 'gate') {\n const gate = gateRef.current;\n // The banner's confirm checkbox, or the banner itself when the\n // reader may not grant (there is nothing to tick).\n const focusable =\n gate?.querySelector<HTMLElement>(\n '[role=\"checkbox\"]:not([disabled])',\n ) ??\n gate?.querySelector<HTMLElement>(\n '[data-component=\"ai-consent-banner\"]',\n );\n focusable?.focus();\n } else if (target === 'credits') {\n // The notice itself, so it is read from its title.\n creditsRef.current\n ?.querySelector<HTMLElement>(\n '[data-component=\"ai-credits-exhausted-notice\"]',\n )\n ?.focus();\n } else if (target === 'return') {\n const origin = gateReturnRef.current;\n gateReturnRef.current = null;\n // Still on the page and shown (a hidden panel has no boxes).\n if (origin?.isConnected && origin.getClientRects().length > 0) {\n origin.focus();\n } else if (latest.current.floating && !latest.current.panelOpen) {\n launcherRef.current?.focus();\n } else {\n toggleRef.current?.focus();\n }\n } else if (target === 'panel') {\n panelRef.current?.focus();\n } else if (target === 'toggle') {\n toggleRef.current?.focus();\n } else {\n launcherRef.current?.focus();\n }\n });\n\n /* ---- Settings --------------------------------------------------- */\n const languageOptions: SelectOption[] = (languages ?? []).map((l) => ({\n value: l.value,\n label: l.label,\n }));\n const showLanguage = languageOptions.length > 1;\n const hasSettings =\n showLanguage || (extraControls != null && extraControls !== false);\n\n const showTranscript =\n Boolean(transcript?.final) || Boolean(transcript?.partial);\n const busy = status === 'starting';\n\n const ToneIcon = message ? TONE_ICON[message.tone] : Info;\n\n /* ---- Pieces shared by both layouts ------------------------------ */\n // Escape and the close button send focus back where the panel was\n // opened from: the field Alt+V was pressed in (if it is still there),\n // or else the panel segment.\n const closePanel = (refocus: boolean) => {\n setPanelOpen(false);\n closeGate();\n setCreditsOpen(false);\n if (refocus) requestFocus(gateReturnRef.current ? 'return' : 'launcher');\n };\n closePanelRef.current = closePanel;\n\n const header = (\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-x-[var(--spacing-xs)] ds:gap-y-[var(--spacing-2xs)]\">\n <p\n id={titleId}\n className=\"ds:m-0 type-label ds:font-semibold ds:text-[color:var(--foreground)]\"\n >\n {title ?? t('voiceControl.title')}\n </p>\n {beta ? (\n <Badge variant=\"brand\" size=\"sm\">\n {t('voiceControl.beta')}\n </Badge>\n ) : null}\n <span className=\"ds:ms-auto ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)] type-meta ds:text-[color:var(--muted-foreground)]\">\n <span aria-hidden=\"true\" className={statusDotVariants({ status })}>\n {status === 'listening' ? (\n <span\n className={[\n 'ds:absolute ds:inset-0 ds:rounded-[var(--radius-full)]',\n 'ds:bg-[color:var(--destructive)]',\n // No pulse in the accessible themes (--accessible-off).\n 'ds:motion-safe:animate-[var(--accessible-off,recorder-pulse_1.2s_ease-out_infinite)]',\n ].join(' ')}\n />\n ) : null}\n </span>\n <span data-voice-status=\"\">{statusLabel}</span>\n </span>\n {floating ? (\n <IconButton\n intent=\"ghost\"\n size=\"md\"\n icon={<X />}\n aria-label={t('common.close')}\n onClick={() => closePanel(true)}\n className={TARGET_SQUARE}\n data-voice-close=\"\"\n />\n ) : null}\n </div>\n );\n\n const betaNoticeLine = betaNotice ? (\n <p className=\"ds:m-0 ds:flex ds:items-start ds:gap-[var(--spacing-2xs)] type-meta ds:text-[color:var(--muted-foreground)]\">\n <Info aria-hidden=\"true\" className=\"ds:mt-px ds:size-4 ds:shrink-0\" />\n <span>{betaNotice}</span>\n </p>\n ) : null;\n\n // Without consent the banner takes the body: the same banner, Grant\n // control and busy state as the RichTextEditor's gate.\n const consentGate =\n showGate && aiConsent ? (\n <div\n ref={gateRef}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n data-voice-consent=\"\"\n >\n <AiConsentBanner\n // Focus lands here when the reader may not grant (nothing to tick).\n tabIndex={-1}\n granted={aiConsent.granted}\n grantedAt={aiConsent.grantedAt}\n grantedBy={aiConsent.grantedBy}\n // No handler, no Grant control: never a dead button.\n canGrant={\n (aiConsent.canGrant ?? true) && aiConsent.onGrant !== undefined\n }\n pending={grantPending}\n onGrantConsent={handleGrantConsent}\n headingLevel={aiConsentHeadingLevel}\n />\n <div className=\"ds:flex ds:justify-end\">\n <Button\n intent=\"ghost\"\n size=\"md\"\n onClick={() => {\n closeGate();\n requestFocus('return');\n }}\n className={TARGET_HEIGHT}\n >\n {t('common.close')}\n </Button>\n </div>\n </div>\n ) : null;\n\n // Out of credits, after consent: the shared notice takes the body, with\n // the same Close as the consent banner. The panel announces it itself.\n const creditsGate =\n showCredits && !consentGate ? (\n <div\n ref={creditsRef}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n data-voice-credits=\"\"\n onFocusCapture={() => {\n noticeFocusRef.current = true;\n }}\n onBlurCapture={() => {\n noticeFocusRef.current = false;\n }}\n >\n <AiCreditsExhaustedNotice\n // Focus lands here when a start meets the gate, with the kit\n // focus ring.\n tabIndex={-1}\n className={focusRing}\n credits={aiCredits}\n headingLevel={aiConsentHeadingLevel ?? 5}\n announce=\"off\"\n />\n <div className=\"ds:flex ds:justify-end\">\n <Button\n intent=\"ghost\"\n size=\"md\"\n onClick={() => {\n closeCredits();\n requestFocus('return');\n }}\n className={TARGET_HEIGHT}\n >\n {t('common.close')}\n </Button>\n </div>\n </div>\n ) : null;\n\n // Running low, expiring, or out of credits at rest: quiet lines that\n // never block. Renders nothing when none applies.\n const creditsLines = aiCredits ? (\n <AiCreditsWarning credits={aiCredits} exhausted={creditsBlocked} />\n ) : null;\n\n const controls = (\n <>\n {/* Body: action | readout | settings. One column in a narrow\n container (the tool rail, the floating panel), three from 560px\n of panel width. */}\n <div className=\"ds:grid ds:grid-cols-1 ds:items-start ds:gap-[var(--spacing-sm)] ds:@[560px]/voice-control:grid-cols-[auto_minmax(0,1fr)_auto]\">\n <Button\n ref={toggleRef}\n intent={status === 'listening' ? 'outline' : 'primary'}\n background=\"surface\"\n size=\"md\"\n // Disabled stops a start, never a stop.\n disabled={disabled && !active}\n aria-busy={busy || undefined}\n aria-keyshortcuts={parsedShortcut?.aria}\n onClick={() => requestToggle()}\n startIcon={\n busy ? (\n <LoaderCircle className=\"ds:animate-[var(--accessible-off,spin_1s_linear_infinite)] ds:motion-reduce:animate-none\" />\n ) : status === 'listening' ? (\n <Square className=\"ds:fill-current\" />\n ) : (\n <AudioLines />\n )\n }\n className={`${TARGET_HEIGHT} ds:w-full ds:@[560px]/voice-control:w-auto`}\n data-voice-toggle=\"\"\n >\n {buttonLabel}\n </Button>\n\n <div className=\"ds:flex ds:min-w-0 ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n {target != null && target !== '' ? (\n <p className=\"ds:m-0 type-body-sm ds:font-semibold ds:[overflow-wrap:anywhere]\">\n {target}\n </p>\n ) : null}\n {showTranscript ? (\n <p\n className=\"ds:m-0 type-body-sm ds:[overflow-wrap:anywhere]\"\n data-voice-transcript=\"\"\n >\n <span className=\"ds:sr-only\">{t('voiceControl.heard')} </span>\n {transcript?.final ? (\n <span className=\"ds:text-[color:var(--foreground)]\">\n {transcript.final}\n </span>\n ) : null}\n {transcript?.final && transcript?.partial ? ' ' : null}\n {transcript?.partial ? (\n <span\n className=\"ds:italic ds:text-[color:var(--muted-foreground)]\"\n data-voice-partial=\"\"\n >\n {transcript.partial}\n </span>\n ) : null}\n </p>\n ) : status === 'listening' ? (\n // Holds the line while nothing has been heard yet, so the first\n // words do not push the panel down.\n <p\n aria-hidden=\"true\"\n className=\"ds:m-0 type-body-sm ds:min-h-[1lh]\"\n />\n ) : null}\n {error ? (\n <p className={messageVariants({ tone: 'error' })}>\n <CircleAlert\n aria-hidden=\"true\"\n className=\"ds:mt-px ds:size-4 ds:shrink-0\"\n />\n <span>{errorText}</span>\n </p>\n ) : null}\n {message && message.text ? (\n <p\n className={messageVariants({ tone: message.tone })}\n data-tone={message.tone}\n >\n <ToneIcon\n aria-hidden=\"true\"\n className=\"ds:mt-px ds:size-4 ds:shrink-0\"\n />\n <span>{message.text}</span>\n </p>\n ) : null}\n </div>\n\n {hasSettings ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:@[560px]/voice-control:flex-row ds:@[560px]/voice-control:flex-wrap ds:@[560px]/voice-control:items-end\">\n {showLanguage ? (\n // A visible, associated label (the kit FormField pattern).\n <FormField label={t('voiceControl.language')}>\n <Select\n options={languageOptions}\n value={language ?? ''}\n onValueChange={(next) => {\n if (next) onLanguageChange?.(next);\n }}\n disabled={disabled}\n />\n </FormField>\n ) : null}\n {extraControls}\n </div>\n ) : null}\n </div>\n\n {/* Matches, numbered as they are spoken (\"option 1\") */}\n {hasCandidates ? (\n <div\n role=\"group\"\n aria-labelledby={candidatesLabel ? candidatesLabelId : undefined}\n aria-label={\n candidatesLabel ? undefined : t('voiceControl.candidates')\n }\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\"\n data-voice-candidates=\"\"\n >\n {candidatesLabel ? (\n <p\n id={candidatesLabelId}\n className=\"ds:m-0 type-body-sm ds:text-[color:var(--foreground)]\"\n >\n {candidatesLabel}\n </p>\n ) : null}\n <List as=\"ol\" density=\"compact\">\n {candidates.map((candidate, index) => (\n <List.Item\n key={candidate.id}\n title={\n <button\n type=\"button\"\n disabled={disabled}\n onClick={() => {\n restoreFocusRef.current = true;\n onCandidatePick?.(candidate.id);\n }}\n className={candidateButtonVariants()}\n data-candidate-id={candidate.id}\n >\n {/* One inline run, so the accessible name keeps\n its spaces: \"Option 1: Composite filling OTVE\". */}\n <span>\n <span className=\"ds:sr-only\">\n {t('voiceControl.candidate', {\n number: index + 1,\n })}\n </span>{' '}\n <span className=\"ds:font-medium\">\n {candidate.label}\n </span>\n {candidate.detail ? (\n <>\n {' '}\n <span className=\"ds:ms-[var(--spacing-2xs)] type-meta ds:text-[color:var(--muted-foreground)]\">\n {candidate.detail}\n </span>\n </>\n ) : null}\n </span>\n </button>\n }\n />\n ))}\n </List>\n </div>\n ) : null}\n\n {/* Voice commands, titled with the shortcut */}\n {commands && commands.length > 0 ? (\n <Collapsible open={commandsOpen} onOpenChange={setCommandsOpen}>\n <CollapsibleTrigger className={commandsTriggerVariants()}>\n <ChevronDown\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:shrink-0 ds:transition-transform ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none ds:[[data-state=open]_&]:rotate-180\"\n />\n <span>\n {parsedShortcut ? (\n <Trans\n ns=\"ui\"\n i18nKey=\"voiceControl.commandsWithShortcut\"\n components={{\n shortcut: <ShortcutKeys keys={parsedShortcut.keys} />,\n }}\n />\n ) : (\n t('voiceControl.commands')\n )}\n </span>\n </CollapsibleTrigger>\n <CollapsibleContent\n aria-label={t('voiceControl.commands')}\n className=\"ds:pt-[var(--spacing-xs)]\"\n >\n <List density=\"compact\">\n {commands.map((command, index) => (\n <List.Item\n key={index}\n title={command.phrase}\n description={command.description}\n />\n ))}\n </List>\n </CollapsibleContent>\n </Collapsible>\n ) : null}\n </>\n );\n\n const content = (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {header}\n {betaNoticeLine}\n <div ref={bodyRef} className=\"ds:contents\">\n {consentGate ?? creditsGate ?? (\n <>\n {creditsLines}\n {controls}\n </>\n )}\n </div>\n </div>\n );\n\n // Always mounted, polite, and outside anything that collapses: it keeps\n // speaking while the floating panel is closed. See the docs for why\n // errors are polite.\n const liveRegion = (\n <LiveRegion politeness=\"polite\" data-voice-announcer=\"\">\n {announcement.text\n ? // Alternate a trailing no-break space so the same words said\n // twice in a row still change the region and are announced.\n `${announcement.text}${announcement.count % 2 ? NO_BREAK_SPACE : ''}`\n : ''}\n </LiveRegion>\n );\n\n if (!floating) {\n return (\n <div\n ref={composedRef}\n role=\"group\"\n aria-labelledby={titleId}\n data-component=\"voice-control-panel\"\n data-component-id={id}\n data-status={status}\n id={id}\n {...rest}\n className={rootVariants({ status, className })}\n >\n {content}\n {liveRegion}\n </div>\n );\n }\n\n /* ---- Floating layout -------------------------------------------- */\n const listening = status === 'listening';\n // The state in words on the pill, so it never rests on colour alone:\n // \"Listening\" on the red segment, \"Paused\" on the plain one (paused and\n // idle would otherwise look the same with the panel closed).\n const showWord = listening || status === 'paused';\n // The visible word must stay inside the name (WCAG 2.5.3). English\n // \"Listening\" sits in \"Stop listening\"; \"Paused\" is not in \"Resume\n // listening\", nor is a translation always, so the word then leads the\n // name through a translated template: \"Paused: Resume listening\".\n const micLabel =\n showWord &&\n !buttonLabel.toLocaleLowerCase().includes(statusLabel.toLocaleLowerCase())\n ? t('voiceControl.statusWithAction', {\n status: statusLabel,\n action: buttonLabel,\n })\n : buttonLabel;\n return (\n <div\n ref={composedRef}\n data-component=\"voice-control-panel\"\n data-component-id={id}\n data-status={status}\n data-layout=\"floating\"\n data-position={position}\n data-open={panelOpen ? '' : undefined}\n id={id}\n {...rest}\n className={floatingRootVariants({ position, className })}\n >\n {/* Non-modal: no focus trap, no backdrop; the page stays usable. */}\n <div\n ref={panelRef}\n id={panelId}\n role=\"group\"\n aria-labelledby={titleId}\n tabIndex={-1}\n hidden={!panelOpen}\n className={floatingPanelVariants({ position })}\n data-voice-panel=\"\"\n >\n {content}\n </div>\n\n {/* The RichTextEditor's AI pill: mic | panel. */}\n <div\n ref={pillRef}\n className=\"ds:relative\"\n data-ai-sparkle={sparkleProps['data-ai-sparkle']}\n >\n <div className={aiFabPillClass} data-voice-pill=\"\">\n {withAiCreditsNotice(\n <button\n type=\"button\"\n onClick={() => requestToggle()}\n disabled={(disabled && !active) || undefined}\n aria-label={micLabel}\n aria-busy={busy || undefined}\n aria-keyshortcuts={parsedShortcut?.aria}\n className={aiFabSegmentVariants({\n // The word on the red needs 7:1 in the accessible themes:\n // `labelled` holds the hover red there.\n recording: listening ? 'labelled' : false,\n className: micSegmentVariants({ extended: showWord }),\n })}\n data-voice-mic=\"\"\n >\n {busy ? (\n <LoaderCircle\n aria-hidden=\"true\"\n className=\"ds:size-5 ds:animate-[var(--accessible-off,spin_1s_linear_infinite)] ds:motion-reduce:animate-none\"\n />\n ) : listening ? (\n <Square\n aria-hidden=\"true\"\n className=\"ds:size-5 ds:fill-current\"\n />\n ) : (\n <AudioLines aria-hidden=\"true\" className=\"ds:size-5\" />\n )}\n {/* The state in words, not colour alone; see micLabel. */}\n {showWord ? (\n <span className=\"type-label ds:whitespace-nowrap\">\n {statusLabel}\n </span>\n ) : null}\n </button>,\n creditsNotice,\n // The pill sits at the foot of the viewport: the card opens up.\n 'top',\n )}\n <span aria-hidden=\"true\" className={aiFabDividerClass} />\n <button\n ref={launcherRef}\n type=\"button\"\n onClick={() => {\n if (panelOpen) {\n closePanel(false);\n } else {\n // Opened from here: Escape comes back here.\n gateReturnRef.current = null;\n setPanelOpen(true);\n requestFocus('panel');\n }\n }}\n aria-label={t('voiceControl.panelToggle')}\n aria-expanded={panelOpen}\n aria-controls={panelId}\n className={aiFabSegmentVariants({ recording: false })}\n data-voice-launcher=\"\"\n >\n {/* Fixed glyph: aria-expanded carries open or closed. */}\n <SlidersHorizontal aria-hidden=\"true\" className=\"ds:size-5\" />\n </button>\n {sparkleState ? (\n <span\n aria-hidden=\"true\"\n className={`${aiFabSweepClass} ${sparkleProps.className}`}\n />\n ) : null}\n </div>\n <AiSparkle state={sparkleState} />\n </div>\n\n {liveRegion}\n </div>\n );\n },\n);\n\nVoiceControlPanel.displayName = 'VoiceControlPanel';\n"],"names":["__iconNode","AudioLines","createLucideIcon","voiceControlPanelAgent","handle","args","rootVariants","cva","statusDotVariants","messageVariants","focusRing","candidateButtonVariants","commandsTriggerVariants","floatingRootVariants","floatingPanelVariants","glassSurfaceClass","glassEntranceClass","micSegmentVariants","MODIFIER_ALIASES","parseVoiceShortcut","shortcut","parts","part","rawKey","modifiers","modifier","key","ordered","m","matchesShortcut","event","parsed","ShortcutKeys","keys","Kbd","TONE_ICON","Info","CircleCheck","TriangleAlert","CircleAlert","NO_CANDIDATES","TARGET_HEIGHT","TARGET_SQUARE","SENTENCE_END","CREDITS_GRACE_MS","NO_BREAK_SPACE","VoiceControlPanel","forwardRef","status","onToggle","disabled","title","beta","betaNotice","language","languages","onLanguageChange","extraControls","target","transcript","message","error","candidates","candidatesLabel","onCandidatePick","commands","defaultCommandsOpen","id","layout","position","open","defaultOpen","onOpenChange","aiSparkle","aiConsent","aiConsentHeadingLevel","aiCredits","aiCreditsNoticeProp","className","rest","ref","t","useTranslation","titleId","useId","candidatesLabelId","panelId","commandsOpen","setCommandsOpen","useState","floating","rootRef","useRef","composedRef","useMemo","composeRefs","panelRef","gateRef","creditsRef","toggleRef","launcherRef","pillRef","parsedShortcut","useEffect","openState","setOpenState","controlled","panelOpen","aiBlocked","gateOpen","setGateOpen","showGate","resumeAfterGrantRef","grantRequestedRef","localGrantPending","setLocalGrantPending","grantPending","creditsBlocked","creditsOpen","setCreditsOpen","showCredits","creditsAnnouncePendingRef","creditsAnnounce","setCreditsAnnounce","creditsOpenRef","bodyRef","noticeFocusRef","latest","pendingFocusRef","setFocusRequest","requestFocus","useCallback","gateReturnRef","stopSentRef","setPanelOpen","next","now","_a","closeGate","captureReturn","focused","openGate","focusInBody","closeCredits","inside","openCredits","keepReturn","requestToggle","off","blocked","outOfCredits","requestToggleRef","handleGrantConsent","result","prevGrantedRef","wasGranted","nowGranted","resume","requestedHere","focusLost","sessionRef","creditsShownRef","session","n","onKeyDown","c","candidateId","_b","useAgentRegistration","statusLabel","errorText","messageText","messageKey","hasCandidates","candidatesKey","active","buttonLabel","announcement","setAnnouncement","announced","before","prev","joined","attention","el","owner","measure","style","gap","closed","panel","panelHeight","publishFloatingClearance","observer","creditsNotice","useDismissibleAiCreditsNotice","sparkleOn","sparkleState","sparkleProps","landSparkle","useAiSparkle","successKey","sparkledKey","restoreFocusRef","closePanelRef","wasOpenRef","useIsomorphicLayoutEffect","wasOpen","gate","focusable","origin","_c","_d","_e","_f","_g","languageOptions","l","showLanguage","hasSettings","showTranscript","busy","ToneIcon","closePanel","refocus","header","jsxs","jsx","Badge","IconButton","X","betaNoticeLine","consentGate","AiConsentBanner","Button","creditsGate","AiCreditsExhaustedNotice","creditsLines","AiCreditsWarning","controls","Fragment","LoaderCircle","Square","FormField","Select","List","candidate","index","Collapsible","CollapsibleTrigger","ChevronDown","Trans","CollapsibleContent","command","content","liveRegion","LiveRegion","listening","showWord","micLabel","aiFabPillClass","withAiCreditsNotice","aiFabSegmentVariants","aiFabDividerClass","SlidersHorizontal","aiFabSweepClass","AiSparkle"],"mappings":"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","x_google_ignoreList":[0]}
@@ -3,7 +3,7 @@ import { forwardRef as dn, useId as P, useState as y, useEffect as f, useMemo as
3
3
  import { c as cn } from "./index-D2ZczOXr.js";
4
4
  import { useTranslation as ln } from "react-i18next";
5
5
  import { u as un } from "./use-isomorphic-layout-effect-BGfaCOP1.js";
6
- import { A as C } from "./alert-DdDpOi-P.js";
6
+ import { A as C } from "./alert-DjsJMGRE.js";
7
7
  import { B as fn } from "./button-D-MQxsA_.js";
8
8
  import { I as mn } from "./icon-button-C_1TgRiK.js";
9
9
  import { X as gn } from "./x-B5YnXwCz.js";
@@ -270,4 +270,4 @@ Nn.displayName = "WarningStack";
270
270
  export {
271
271
  Nn as W
272
272
  };
273
- //# sourceMappingURL=warning-stack-HYWAytZV.js.map
273
+ //# sourceMappingURL=warning-stack-BdY-0bd3.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"warning-stack-HYWAytZV.js","sources":["../../src/components/warning-stack/warning-stack.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n type MutableRefObject,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { ChevronDown, X } from 'lucide-react';\nimport { useIsomorphicLayoutEffect } from '../../hooks/use-isomorphic-layout-effect';\nimport { Alert, type AlertProps } from '../alert/alert';\nimport { Button } from '../button/button';\nimport { IconButton } from '../button/icon-button';\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface WarningStackItem {\n id: string;\n variant?: AlertProps['variant'];\n title: ReactNode;\n description?: ReactNode;\n icon?: ReactNode;\n actions?: ReactNode;\n dismissible?: boolean;\n}\n\n/** Empty-collapse fold phases (no-`emptyState` path only). See the fold\n * state machine in the component body. */\ntype FoldPhase = 'open' | 'settling' | 'closing' | 'closed';\n\nconst stackVariants = cva(\n [\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-md)]',\n 'ds:rounded-[var(--radius-lg)]',\n 'ds:bg-[color:var(--card)] ds:text-[color:var(--card-foreground)]',\n 'ds:shadow-[var(--shadow-card)]',\n 'ds:[:where(&)]:border-[length:var(--surface-border-width,var(--border-width-sm))] ds:border-[color:var(--card-border)]',\n 'ds:p-[var(--spacing-md)]',\n ].join(' '),\n {\n variants: {\n // `stretch: true` fills the parent layout cell — mirrors the `stretch`\n // prop on `Card` so a WarningStack rendered next to a Card in a grid\n // row ends up at matching height.\n stretch: {\n true: 'ds:h-full ds:self-stretch',\n false: '',\n },\n },\n defaultVariants: {\n stretch: false,\n },\n },\n);\n\n// Single column by default; two columns once the stack itself is wide\n// enough (container query — viewport width lies when the stack sits in\n// a narrow grid cell). A trailing odd item spans both columns so the\n// grid never ends on a half-width hole, which also keeps a lone item\n// full-width exactly as before.\n// 768px, not the `@3xl` rem alias: container-query `rem` resolves against the\n// host's root font-size, so a non-16px root silently moves the threshold.\nconst LIST_CLASSES = [\n 'ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)]',\n 'ds:@[768px]/warning-stack:grid-cols-2',\n 'ds:@[768px]/warning-stack:[&>li:nth-child(odd):last-child]:col-span-full',\n].join(' ');\n\nconst TOGGLE_CLASSES = [\n 'ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)] ds:self-start',\n].join(' ');\n\n/* ------------------------------------------------------------------ */\n/* Empty-collapse animation */\n/* */\n/* When the stack empties (every notice dismissed) and no `emptyState` */\n/* is supplied, the whole region folds away instead of leaving a hole. */\n/* The grid `1fr → 0fr` track is the only CSS-only way to animate to/ */\n/* from `height: auto`; JS-measured `max-height` is barred by the */\n/* no-inline-styles constraint. The outer wrapper owns the height */\n/* track; the inner wrapper owns the cross-fade + overflow clip. */\n/* ------------------------------------------------------------------ */\n\n/** Floor for how long the folding region stays mounted after it empties, so a\n * screen reader can voice the cleared count even when `--animation-duration`\n * is 0ms (accessible themes). The region is already visually collapsed, so\n * this window is imperceptible. */\nconst MIN_FOLD_UNMOUNT_MS = 250;\n\n/** Reads `--animation-duration` (ms) so the unmount timer matches the\n * CSS transition. Falls back to 200ms when it can't be resolved. */\nfunction readAnimationDurationMs(): number {\n if (typeof window === 'undefined') return 200;\n const raw = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue('--animation-duration');\n const trimmed = raw.trim();\n const n = parseFloat(trimmed);\n if (!Number.isFinite(n)) return 200;\n return trimmed.endsWith('ms') ? n : n * 1000;\n}\n\n/** Outer height-collapse track. Always a grid so the `grid-template-rows`\n * transition has a stable from/to; only the row size flips. */\nfunction collapseTrackClass(collapsed: boolean, stretch: boolean): string {\n return [\n 'ds:grid ds:transition-[grid-template-rows]',\n 'ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n collapsed ? 'ds:grid-rows-[0fr]' : 'ds:grid-rows-[1fr]',\n stretch ? 'ds:h-full ds:self-stretch' : '',\n ]\n .filter(Boolean)\n .join(' ');\n}\n\n/** Inner cross-fade layer. `min-h-0` lets the grid item shrink below its\n * content; `overflow-hidden` (only while animating) clips the fold so the\n * card's resting drop-shadow isn't clipped at rest. */\nfunction collapseInnerClass(collapsed: boolean, closing: boolean): string {\n return [\n 'ds:min-h-0',\n 'ds:transition-opacity ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n collapsed ? 'ds:opacity-0 ds:overflow-hidden' : 'ds:opacity-100',\n closing ? 'ds:pointer-events-none' : '',\n ]\n .filter(Boolean)\n .join(' ');\n}\n\nexport interface WarningStackProps\n extends\n Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'role' | 'title'>,\n VariantProps<typeof stackVariants> {\n /** Items rendered inside the stack. */\n items: WarningStackItem[];\n /** Fill the parent layout cell — use in a dashboard grid row so the\n * stack ends up with matching height to sibling Cards. */\n stretch?: boolean;\n /** Visible title rendered as an `<h2>` above the stack. Also labels the\n * region for assistive tech. When omitted, the region is labelled via a\n * visually hidden heading using `ariaLabel` (or the default \"Warnings\"). */\n title?: ReactNode;\n /** Optional short description rendered under the title. */\n description?: ReactNode;\n /** Cap on visible items before a \"Show N more\" toggle appears. Defaults to\n * `2`; pass a larger number (or `Infinity`) to show more before collapsing. */\n maxVisible?: number;\n /** Whether the stack starts collapsed when items exceed `maxVisible`. */\n defaultCollapsed?: boolean;\n /** Fires when a dismissible item's close control is activated. */\n onDismiss?: (item: WarningStackItem) => void;\n /** Whether the whole-stack close control is shown at the header's inline-end.\n * Defaults to `true` — the tray is closable. Set `false` for stacks that\n * carry notices which must not be bulk-cleared (e.g. hard compliance blocks). */\n closable?: boolean;\n /** Fires when the whole-stack close control is activated, after every\n * currently-visible notice has been dismissed (folding the region away).\n * Optional — the fold happens internally regardless; supply this only to\n * mirror the bulk dismissal into the consumer's own store. */\n onDismissAll?: () => void;\n /** Accessible label for the whole-stack close control. Defaults to the\n * localised \"Dismiss all notices\". */\n dismissAllLabel?: string;\n /** Accessible label for the region when `title` is not set. */\n ariaLabel?: string;\n /** Optional node rendered when the stack has zero items. */\n emptyState?: ReactNode;\n}\n\n/* ------------------------------------------------------------------ */\n/* Root */\n/* ------------------------------------------------------------------ */\n\nexport const WarningStack = forwardRef<HTMLDivElement, WarningStackProps>(\n (\n {\n items,\n title,\n description,\n maxVisible = 2,\n defaultCollapsed = true,\n onDismiss,\n closable = true,\n onDismissAll,\n dismissAllLabel,\n stretch = false,\n ariaLabel,\n emptyState,\n className,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation('ui');\n const labelId = useId();\n const listId = useId();\n\n // Track dismissed ids internally so the <li> unmounts even when the\n // consumer doesn't mirror dismissal into `items` — otherwise the list\n // keeps a ghost entry (and the two-column grid a blank cell). Pruned\n // when an id leaves `items`, so a re-pushed item renders again.\n const [dismissedIds, setDismissedIds] = useState<ReadonlySet<string>>(\n () => new Set(),\n );\n useEffect(() => {\n setDismissedIds((prev) => {\n if (prev.size === 0) return prev;\n const ids = new Set(items.map((item) => item.id));\n const next = new Set([...prev].filter((id) => ids.has(id)));\n return next.size === prev.size ? prev : next;\n });\n }, [items]);\n\n const liveItems = useMemo(\n () => items.filter((item) => !dismissedIds.has(item.id)),\n [items, dismissedIds],\n );\n\n const overflow = maxVisible !== undefined && liveItems.length > maxVisible;\n const [collapsed, setCollapsed] = useState(defaultCollapsed);\n\n // Live-region announces the count when items change.\n const liveRef = useRef<HTMLDivElement>(null);\n const lastCountRef = useRef<number>(liveItems.length);\n\n useEffect(() => {\n if (!liveRef.current) return;\n const prev = lastCountRef.current;\n const next = liveItems.length;\n if (prev !== next) {\n liveRef.current.textContent = t('warningStack.countChanged', {\n count: next,\n defaultValue: '{{count}} warnings to review',\n });\n }\n lastCountRef.current = next;\n }, [liveItems.length, t]);\n\n const visible = useMemo(() => {\n if (!overflow || !collapsed) return liveItems;\n return liveItems.slice(0, maxVisible);\n }, [liveItems, overflow, collapsed, maxVisible]);\n\n const hiddenCount = overflow ? liveItems.length - (maxVisible ?? 0) : 0;\n\n /* ----- Empty-collapse phase ------------------------------------- */\n const hasItems = liveItems.length > 0;\n const hasEmptyState = emptyState != null;\n // There is something to show whenever a live notice remains, or an\n // empty state has been supplied to fill the region in its place.\n const present = hasItems || hasEmptyState;\n\n // Only the no-`emptyState` path animates the fold. It runs in two beats\n // so the height transition has a stable start: a CSS transition can't\n // interpolate when the element's content changes in the same commit as\n // the track flip, so `settling` first re-renders the emptied region at\n // full height (track still open), then `closing` flips the track to 0fr\n // on the next frame — now the browser animates from a real height.\n // open → settling → closing → closed (unmounted, until a notice lands)\n const [phase, setPhase] = useState<FoldPhase>(present ? 'open' : 'closed');\n // Drives the expand-in when a notice lands after the region had folded.\n const [entering, setEntering] = useState(false);\n\n useIsomorphicLayoutEffect(() => {\n if (present) {\n if (phase !== 'open') {\n // Replay the expand only when re-appearing from a collapsed state.\n if (phase === 'closing' || phase === 'closed') setEntering(true);\n setPhase('open');\n }\n } else if (phase === 'open') {\n setPhase('settling');\n }\n }, [present, phase]);\n\n // settling → closing: flip the track shut one frame after the emptied\n // region has painted at full height, so the collapse actually animates.\n useEffect(() => {\n if (phase !== 'settling') return;\n const raf = window.requestAnimationFrame(() => setPhase('closing'));\n return () => window.cancelAnimationFrame(raf);\n }, [phase]);\n\n // closing → closed: unmount once the collapse transition has run. The\n // delay is floored so the polite live region (which lives in this subtree)\n // survives long enough for assistive tech to voice the cleared count\n // before the node is removed — otherwise an accessible theme, where\n // `--animation-duration` is 0ms, would unmount in the same frame and\n // swallow the announcement. The region is already collapsed to zero\n // height by then, so the extra mounted time is invisible.\n useEffect(() => {\n if (phase !== 'closing') return;\n const delay = Math.max(readAnimationDurationMs(), MIN_FOLD_UNMOUNT_MS);\n const id = window.setTimeout(() => setPhase('closed'), delay);\n return () => window.clearTimeout(id);\n }, [phase]);\n\n // Expand-in: clear the collapsed start-state on the next frame so the\n // grid track animates open instead of snapping to full height.\n useEffect(() => {\n if (!entering) return;\n const raf = window.requestAnimationFrame(() => setEntering(false));\n return () => window.cancelAnimationFrame(raf);\n }, [entering]);\n\n const closing = phase === 'closing';\n const animCollapsed = closing || entering;\n const mounted = present || phase === 'settling' || phase === 'closing';\n\n // Focus hand-off: dismissing unmounts the focused close button, which\n // would otherwise drop focus to <body> (WCAG 2.4.3). Aim for the\n // dismiss control now occupying the same list position (the next\n // item), else the last remaining one, else the region itself.\n const sectionRef = useRef<HTMLElement | null>(null);\n const setSectionRef = useCallback(\n (node: HTMLElement | null) => {\n sectionRef.current = node;\n if (typeof ref === 'function') {\n ref(node as HTMLDivElement | null);\n } else if (ref) {\n (ref as MutableRefObject<HTMLDivElement | null>).current =\n node as HTMLDivElement | null;\n }\n },\n [ref],\n );\n const pendingFocusIndexRef = useRef<number | null>(null);\n // No dependency array on purpose: this runs after every render but is\n // gated by `pendingFocusIndexRef`, which is only non-null on the render\n // that immediately follows a dismissal. Don't \"fix\" it to `[liveItems]`.\n useEffect(() => {\n if (pendingFocusIndexRef.current === null) return;\n const index = pendingFocusIndexRef.current;\n pendingFocusIndexRef.current = null;\n const section = sectionRef.current;\n if (!section) return;\n const dismissControls = Array.from(\n section.querySelectorAll<HTMLButtonElement>('[data-alert-dismiss]'),\n );\n const target =\n dismissControls[Math.min(index, dismissControls.length - 1)];\n if (target) target.focus();\n // Last notice gone: only land focus on the region if it survives the\n // dismissal (an emptyState keeps it mounted). When the stack folds\n // away entirely there is no stable target here — the consumer owns\n // re-homing focus (see the dashboard pattern) and the live region\n // announces the cleared count.\n else if (hasEmptyState) section.focus();\n });\n\n const handleDismiss = useCallback(\n (item: WarningStackItem, index: number) => (open: boolean) => {\n if (open) return;\n pendingFocusIndexRef.current = index;\n setDismissedIds((prev) => new Set(prev).add(item.id));\n onDismiss?.(item);\n },\n [onDismiss],\n );\n\n // Whole-stack close: dismiss every currently-visible notice in one go,\n // which empties `liveItems` and folds the region away. Focus re-homing on\n // the fold is the consumer's responsibility (same as the last-item case) —\n // there's no surviving in-component target once the header unmounts.\n const handleDismissAll = useCallback(() => {\n setDismissedIds((prev) => {\n const next = new Set(prev);\n for (const item of liveItems) next.add(item.id);\n return next;\n });\n onDismissAll?.();\n }, [liveItems, onDismissAll]);\n\n const toggle = useCallback(() => setCollapsed((c) => !c), []);\n\n const regionLabel = ariaLabel ?? t('warningStack.regionLabel', 'Warnings');\n\n // Title block: a visible header when `title` is provided; otherwise a\n // visually hidden heading so the region still has a programmatic name.\n // A `<div>` rather than `<header>` wrapper keeps the `<header>` element's\n // implicit banner role from leaking out of the region. The whole-stack\n // close control (when enabled) sits at the inline-end of this row.\n const titleBlock = title ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <h2\n id={labelId}\n className=\"ds:text-start type-title-section ds:text-[var(--foreground)]\"\n >\n {title}\n </h2>\n {description ? (\n <p className=\"ds:text-start type-body-sm ds:text-[var(--muted-foreground)]\">\n {description}\n </p>\n ) : null}\n </div>\n ) : (\n <h2 id={labelId} className=\"ds:sr-only\">\n {regionLabel}\n </h2>\n );\n\n const showStackClose = closable && hasItems;\n const header = showStackClose ? (\n <div className=\"ds:flex ds:items-start ds:justify-between ds:gap-[var(--spacing-sm)]\">\n {titleBlock}\n <IconButton\n type=\"button\"\n icon={<X aria-hidden=\"true\" />}\n intent=\"ghost\"\n size=\"sm\"\n aria-label={\n dismissAllLabel ??\n t('warningStack.dismissAll', 'Dismiss all notices')\n }\n onClick={handleDismissAll}\n // Pull flush to the card's inline-end padding edge, and never let\n // the button compress when the title wraps.\n className=\"ds:-me-[var(--spacing-2xs)] ds:shrink-0\"\n />\n </div>\n ) : (\n titleBlock\n );\n\n // Fully folded away (or cold-start empty with no emptyState): render\n // nothing. Matches the long-standing \"empty + no emptyState → null\"\n // contract, now reached via the fold-out animation rather than instantly.\n if (!mounted) return null;\n\n return (\n // Outer: height-collapse track. Carries the bounding marker so it is\n // the cascade-reset boundary even mid-fold.\n <div\n data-component=\"warning-stack\"\n className={collapseTrackClass(animCollapsed, stretch)}\n >\n {/* Inner: cross-fade + overflow clip while folding. */}\n <div className={collapseInnerClass(animCollapsed, closing)}>\n <section\n ref={setSectionRef}\n aria-labelledby={labelId}\n // Programmatically focusable so a surviving region can take the\n // last dismissal's focus (see the focus hand-off above).\n tabIndex={-1}\n className={[stackVariants({ stretch }), className]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n {header}\n {/* The live region announces the count as it changes. Omitted in\n emptyState mode, where the empty state itself communicates. */}\n {!hasEmptyState ? (\n <div\n ref={liveRef}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"ds:sr-only\"\n />\n ) : null}\n {hasItems ? (\n <>\n {/* Container-type lives on this wrapper (never on the flex\n section itself) so the list can query its own inline size. */}\n <div className=\"ds:@container/warning-stack\">\n <ul\n id={listId}\n className={LIST_CLASSES}\n // Neutral wording — the list mixes warnings with info\n // notices and promo offers.\n aria-label={t('warningStack.listLabel', 'Notices')}\n >\n {visible.map((item, index) => {\n const variant = item.variant ?? 'warning';\n return (\n // `data-warning-id` is the per-notice agent hook: it\n // makes one warning addressable in the DOM, and its\n // dismiss control is the nested `[data-alert-dismiss]`.\n <li key={item.id} data-warning-id={item.id}>\n <Alert\n variant={variant}\n dismissible={item.dismissible}\n icon={item.icon}\n onOpenChange={handleDismiss(item, index)}\n // Compact: clamp title/description so a notice stays\n // a predictable height — keeps the tray tight and\n // side-by-side cards even.\n clamp\n // Fill the row so side-by-side alerts equalise height.\n className=\"ds:h-full\"\n >\n {/* `as=\"h3\"` keeps a clean heading ladder — the\n stack's h2 labels the region, then each item's\n h3 rises from it. */}\n <Alert.Title as=\"h3\">{item.title}</Alert.Title>\n {item.description ? (\n <Alert.Description>\n {item.description}\n </Alert.Description>\n ) : null}\n {item.actions ? (\n <Alert.Action>{item.actions}</Alert.Action>\n ) : null}\n </Alert>\n </li>\n );\n })}\n </ul>\n </div>\n\n {overflow ? (\n <Button\n type=\"button\"\n intent=\"link\"\n size=\"sm\"\n aria-expanded={!collapsed}\n aria-controls={listId}\n onClick={toggle}\n className={TOGGLE_CLASSES}\n >\n <ChevronDown\n aria-hidden=\"true\"\n className={[\n 'ds:size-4 ds:transition-transform ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n collapsed ? '' : 'ds:rotate-180',\n ].join(' ')}\n />\n {collapsed\n ? t('warningStack.showMore', {\n count: hiddenCount,\n defaultValue: 'Show {{count}} more warnings',\n })\n : t('warningStack.showLess', 'Show less')}\n </Button>\n ) : null}\n </>\n ) : (\n emptyState\n )}\n </section>\n </div>\n </div>\n );\n },\n);\n\nWarningStack.displayName = 'WarningStack';\n"],"names":["stackVariants","cva","LIST_CLASSES","TOGGLE_CLASSES","MIN_FOLD_UNMOUNT_MS","readAnimationDurationMs","trimmed","n","collapseTrackClass","collapsed","stretch","collapseInnerClass","closing","WarningStack","forwardRef","items","title","description","maxVisible","defaultCollapsed","onDismiss","closable","onDismissAll","dismissAllLabel","ariaLabel","emptyState","className","rest","ref","t","useTranslation","labelId","useId","listId","dismissedIds","setDismissedIds","useState","useEffect","prev","ids","item","next","id","liveItems","useMemo","overflow","setCollapsed","liveRef","useRef","lastCountRef","visible","hiddenCount","hasItems","hasEmptyState","present","phase","setPhase","entering","setEntering","useIsomorphicLayoutEffect","raf","delay","animCollapsed","mounted","sectionRef","setSectionRef","useCallback","node","pendingFocusIndexRef","index","section","dismissControls","target","handleDismiss","open","handleDismissAll","toggle","c","regionLabel","titleBlock","jsxs","jsx","header","IconButton","X","Fragment","variant","Alert","Button","ChevronDown"],"mappings":"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"}
1
+ {"version":3,"file":"warning-stack-BdY-0bd3.js","sources":["../../src/components/warning-stack/warning-stack.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n type MutableRefObject,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { ChevronDown, X } from 'lucide-react';\nimport { useIsomorphicLayoutEffect } from '../../hooks/use-isomorphic-layout-effect';\nimport { Alert, type AlertProps } from '../alert/alert';\nimport { Button } from '../button/button';\nimport { IconButton } from '../button/icon-button';\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface WarningStackItem {\n id: string;\n variant?: AlertProps['variant'];\n title: ReactNode;\n description?: ReactNode;\n icon?: ReactNode;\n actions?: ReactNode;\n dismissible?: boolean;\n}\n\n/** Empty-collapse fold phases (no-`emptyState` path only). See the fold\n * state machine in the component body. */\ntype FoldPhase = 'open' | 'settling' | 'closing' | 'closed';\n\nconst stackVariants = cva(\n [\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-md)]',\n 'ds:rounded-[var(--radius-lg)]',\n 'ds:bg-[color:var(--card)] ds:text-[color:var(--card-foreground)]',\n 'ds:shadow-[var(--shadow-card)]',\n 'ds:[:where(&)]:border-[length:var(--surface-border-width,var(--border-width-sm))] ds:border-[color:var(--card-border)]',\n 'ds:p-[var(--spacing-md)]',\n ].join(' '),\n {\n variants: {\n // `stretch: true` fills the parent layout cell — mirrors the `stretch`\n // prop on `Card` so a WarningStack rendered next to a Card in a grid\n // row ends up at matching height.\n stretch: {\n true: 'ds:h-full ds:self-stretch',\n false: '',\n },\n },\n defaultVariants: {\n stretch: false,\n },\n },\n);\n\n// Single column by default; two columns once the stack itself is wide\n// enough (container query — viewport width lies when the stack sits in\n// a narrow grid cell). A trailing odd item spans both columns so the\n// grid never ends on a half-width hole, which also keeps a lone item\n// full-width exactly as before.\n// 768px, not the `@3xl` rem alias: container-query `rem` resolves against the\n// host's root font-size, so a non-16px root silently moves the threshold.\nconst LIST_CLASSES = [\n 'ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)]',\n 'ds:@[768px]/warning-stack:grid-cols-2',\n 'ds:@[768px]/warning-stack:[&>li:nth-child(odd):last-child]:col-span-full',\n].join(' ');\n\nconst TOGGLE_CLASSES = [\n 'ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)] ds:self-start',\n].join(' ');\n\n/* ------------------------------------------------------------------ */\n/* Empty-collapse animation */\n/* */\n/* When the stack empties (every notice dismissed) and no `emptyState` */\n/* is supplied, the whole region folds away instead of leaving a hole. */\n/* The grid `1fr → 0fr` track is the only CSS-only way to animate to/ */\n/* from `height: auto`; JS-measured `max-height` is barred by the */\n/* no-inline-styles constraint. The outer wrapper owns the height */\n/* track; the inner wrapper owns the cross-fade + overflow clip. */\n/* ------------------------------------------------------------------ */\n\n/** Floor for how long the folding region stays mounted after it empties, so a\n * screen reader can voice the cleared count even when `--animation-duration`\n * is 0ms (accessible themes). The region is already visually collapsed, so\n * this window is imperceptible. */\nconst MIN_FOLD_UNMOUNT_MS = 250;\n\n/** Reads `--animation-duration` (ms) so the unmount timer matches the\n * CSS transition. Falls back to 200ms when it can't be resolved. */\nfunction readAnimationDurationMs(): number {\n if (typeof window === 'undefined') return 200;\n const raw = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue('--animation-duration');\n const trimmed = raw.trim();\n const n = parseFloat(trimmed);\n if (!Number.isFinite(n)) return 200;\n return trimmed.endsWith('ms') ? n : n * 1000;\n}\n\n/** Outer height-collapse track. Always a grid so the `grid-template-rows`\n * transition has a stable from/to; only the row size flips. */\nfunction collapseTrackClass(collapsed: boolean, stretch: boolean): string {\n return [\n 'ds:grid ds:transition-[grid-template-rows]',\n 'ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n collapsed ? 'ds:grid-rows-[0fr]' : 'ds:grid-rows-[1fr]',\n stretch ? 'ds:h-full ds:self-stretch' : '',\n ]\n .filter(Boolean)\n .join(' ');\n}\n\n/** Inner cross-fade layer. `min-h-0` lets the grid item shrink below its\n * content; `overflow-hidden` (only while animating) clips the fold so the\n * card's resting drop-shadow isn't clipped at rest. */\nfunction collapseInnerClass(collapsed: boolean, closing: boolean): string {\n return [\n 'ds:min-h-0',\n 'ds:transition-opacity ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n collapsed ? 'ds:opacity-0 ds:overflow-hidden' : 'ds:opacity-100',\n closing ? 'ds:pointer-events-none' : '',\n ]\n .filter(Boolean)\n .join(' ');\n}\n\nexport interface WarningStackProps\n extends\n Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'role' | 'title'>,\n VariantProps<typeof stackVariants> {\n /** Items rendered inside the stack. */\n items: WarningStackItem[];\n /** Fill the parent layout cell — use in a dashboard grid row so the\n * stack ends up with matching height to sibling Cards. */\n stretch?: boolean;\n /** Visible title rendered as an `<h2>` above the stack. Also labels the\n * region for assistive tech. When omitted, the region is labelled via a\n * visually hidden heading using `ariaLabel` (or the default \"Warnings\"). */\n title?: ReactNode;\n /** Optional short description rendered under the title. */\n description?: ReactNode;\n /** Cap on visible items before a \"Show N more\" toggle appears. Defaults to\n * `2`; pass a larger number (or `Infinity`) to show more before collapsing. */\n maxVisible?: number;\n /** Whether the stack starts collapsed when items exceed `maxVisible`. */\n defaultCollapsed?: boolean;\n /** Fires when a dismissible item's close control is activated. */\n onDismiss?: (item: WarningStackItem) => void;\n /** Whether the whole-stack close control is shown at the header's inline-end.\n * Defaults to `true` — the tray is closable. Set `false` for stacks that\n * carry notices which must not be bulk-cleared (e.g. hard compliance blocks). */\n closable?: boolean;\n /** Fires when the whole-stack close control is activated, after every\n * currently-visible notice has been dismissed (folding the region away).\n * Optional — the fold happens internally regardless; supply this only to\n * mirror the bulk dismissal into the consumer's own store. */\n onDismissAll?: () => void;\n /** Accessible label for the whole-stack close control. Defaults to the\n * localised \"Dismiss all notices\". */\n dismissAllLabel?: string;\n /** Accessible label for the region when `title` is not set. */\n ariaLabel?: string;\n /** Optional node rendered when the stack has zero items. */\n emptyState?: ReactNode;\n}\n\n/* ------------------------------------------------------------------ */\n/* Root */\n/* ------------------------------------------------------------------ */\n\nexport const WarningStack = forwardRef<HTMLDivElement, WarningStackProps>(\n (\n {\n items,\n title,\n description,\n maxVisible = 2,\n defaultCollapsed = true,\n onDismiss,\n closable = true,\n onDismissAll,\n dismissAllLabel,\n stretch = false,\n ariaLabel,\n emptyState,\n className,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation('ui');\n const labelId = useId();\n const listId = useId();\n\n // Track dismissed ids internally so the <li> unmounts even when the\n // consumer doesn't mirror dismissal into `items` — otherwise the list\n // keeps a ghost entry (and the two-column grid a blank cell). Pruned\n // when an id leaves `items`, so a re-pushed item renders again.\n const [dismissedIds, setDismissedIds] = useState<ReadonlySet<string>>(\n () => new Set(),\n );\n useEffect(() => {\n setDismissedIds((prev) => {\n if (prev.size === 0) return prev;\n const ids = new Set(items.map((item) => item.id));\n const next = new Set([...prev].filter((id) => ids.has(id)));\n return next.size === prev.size ? prev : next;\n });\n }, [items]);\n\n const liveItems = useMemo(\n () => items.filter((item) => !dismissedIds.has(item.id)),\n [items, dismissedIds],\n );\n\n const overflow = maxVisible !== undefined && liveItems.length > maxVisible;\n const [collapsed, setCollapsed] = useState(defaultCollapsed);\n\n // Live-region announces the count when items change.\n const liveRef = useRef<HTMLDivElement>(null);\n const lastCountRef = useRef<number>(liveItems.length);\n\n useEffect(() => {\n if (!liveRef.current) return;\n const prev = lastCountRef.current;\n const next = liveItems.length;\n if (prev !== next) {\n liveRef.current.textContent = t('warningStack.countChanged', {\n count: next,\n defaultValue: '{{count}} warnings to review',\n });\n }\n lastCountRef.current = next;\n }, [liveItems.length, t]);\n\n const visible = useMemo(() => {\n if (!overflow || !collapsed) return liveItems;\n return liveItems.slice(0, maxVisible);\n }, [liveItems, overflow, collapsed, maxVisible]);\n\n const hiddenCount = overflow ? liveItems.length - (maxVisible ?? 0) : 0;\n\n /* ----- Empty-collapse phase ------------------------------------- */\n const hasItems = liveItems.length > 0;\n const hasEmptyState = emptyState != null;\n // There is something to show whenever a live notice remains, or an\n // empty state has been supplied to fill the region in its place.\n const present = hasItems || hasEmptyState;\n\n // Only the no-`emptyState` path animates the fold. It runs in two beats\n // so the height transition has a stable start: a CSS transition can't\n // interpolate when the element's content changes in the same commit as\n // the track flip, so `settling` first re-renders the emptied region at\n // full height (track still open), then `closing` flips the track to 0fr\n // on the next frame — now the browser animates from a real height.\n // open → settling → closing → closed (unmounted, until a notice lands)\n const [phase, setPhase] = useState<FoldPhase>(present ? 'open' : 'closed');\n // Drives the expand-in when a notice lands after the region had folded.\n const [entering, setEntering] = useState(false);\n\n useIsomorphicLayoutEffect(() => {\n if (present) {\n if (phase !== 'open') {\n // Replay the expand only when re-appearing from a collapsed state.\n if (phase === 'closing' || phase === 'closed') setEntering(true);\n setPhase('open');\n }\n } else if (phase === 'open') {\n setPhase('settling');\n }\n }, [present, phase]);\n\n // settling → closing: flip the track shut one frame after the emptied\n // region has painted at full height, so the collapse actually animates.\n useEffect(() => {\n if (phase !== 'settling') return;\n const raf = window.requestAnimationFrame(() => setPhase('closing'));\n return () => window.cancelAnimationFrame(raf);\n }, [phase]);\n\n // closing → closed: unmount once the collapse transition has run. The\n // delay is floored so the polite live region (which lives in this subtree)\n // survives long enough for assistive tech to voice the cleared count\n // before the node is removed — otherwise an accessible theme, where\n // `--animation-duration` is 0ms, would unmount in the same frame and\n // swallow the announcement. The region is already collapsed to zero\n // height by then, so the extra mounted time is invisible.\n useEffect(() => {\n if (phase !== 'closing') return;\n const delay = Math.max(readAnimationDurationMs(), MIN_FOLD_UNMOUNT_MS);\n const id = window.setTimeout(() => setPhase('closed'), delay);\n return () => window.clearTimeout(id);\n }, [phase]);\n\n // Expand-in: clear the collapsed start-state on the next frame so the\n // grid track animates open instead of snapping to full height.\n useEffect(() => {\n if (!entering) return;\n const raf = window.requestAnimationFrame(() => setEntering(false));\n return () => window.cancelAnimationFrame(raf);\n }, [entering]);\n\n const closing = phase === 'closing';\n const animCollapsed = closing || entering;\n const mounted = present || phase === 'settling' || phase === 'closing';\n\n // Focus hand-off: dismissing unmounts the focused close button, which\n // would otherwise drop focus to <body> (WCAG 2.4.3). Aim for the\n // dismiss control now occupying the same list position (the next\n // item), else the last remaining one, else the region itself.\n const sectionRef = useRef<HTMLElement | null>(null);\n const setSectionRef = useCallback(\n (node: HTMLElement | null) => {\n sectionRef.current = node;\n if (typeof ref === 'function') {\n ref(node as HTMLDivElement | null);\n } else if (ref) {\n (ref as MutableRefObject<HTMLDivElement | null>).current =\n node as HTMLDivElement | null;\n }\n },\n [ref],\n );\n const pendingFocusIndexRef = useRef<number | null>(null);\n // No dependency array on purpose: this runs after every render but is\n // gated by `pendingFocusIndexRef`, which is only non-null on the render\n // that immediately follows a dismissal. Don't \"fix\" it to `[liveItems]`.\n useEffect(() => {\n if (pendingFocusIndexRef.current === null) return;\n const index = pendingFocusIndexRef.current;\n pendingFocusIndexRef.current = null;\n const section = sectionRef.current;\n if (!section) return;\n const dismissControls = Array.from(\n section.querySelectorAll<HTMLButtonElement>('[data-alert-dismiss]'),\n );\n const target =\n dismissControls[Math.min(index, dismissControls.length - 1)];\n if (target) target.focus();\n // Last notice gone: only land focus on the region if it survives the\n // dismissal (an emptyState keeps it mounted). When the stack folds\n // away entirely there is no stable target here — the consumer owns\n // re-homing focus (see the dashboard pattern) and the live region\n // announces the cleared count.\n else if (hasEmptyState) section.focus();\n });\n\n const handleDismiss = useCallback(\n (item: WarningStackItem, index: number) => (open: boolean) => {\n if (open) return;\n pendingFocusIndexRef.current = index;\n setDismissedIds((prev) => new Set(prev).add(item.id));\n onDismiss?.(item);\n },\n [onDismiss],\n );\n\n // Whole-stack close: dismiss every currently-visible notice in one go,\n // which empties `liveItems` and folds the region away. Focus re-homing on\n // the fold is the consumer's responsibility (same as the last-item case) —\n // there's no surviving in-component target once the header unmounts.\n const handleDismissAll = useCallback(() => {\n setDismissedIds((prev) => {\n const next = new Set(prev);\n for (const item of liveItems) next.add(item.id);\n return next;\n });\n onDismissAll?.();\n }, [liveItems, onDismissAll]);\n\n const toggle = useCallback(() => setCollapsed((c) => !c), []);\n\n const regionLabel = ariaLabel ?? t('warningStack.regionLabel', 'Warnings');\n\n // Title block: a visible header when `title` is provided; otherwise a\n // visually hidden heading so the region still has a programmatic name.\n // A `<div>` rather than `<header>` wrapper keeps the `<header>` element's\n // implicit banner role from leaking out of the region. The whole-stack\n // close control (when enabled) sits at the inline-end of this row.\n const titleBlock = title ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <h2\n id={labelId}\n className=\"ds:text-start type-title-section ds:text-[var(--foreground)]\"\n >\n {title}\n </h2>\n {description ? (\n <p className=\"ds:text-start type-body-sm ds:text-[var(--muted-foreground)]\">\n {description}\n </p>\n ) : null}\n </div>\n ) : (\n <h2 id={labelId} className=\"ds:sr-only\">\n {regionLabel}\n </h2>\n );\n\n const showStackClose = closable && hasItems;\n const header = showStackClose ? (\n <div className=\"ds:flex ds:items-start ds:justify-between ds:gap-[var(--spacing-sm)]\">\n {titleBlock}\n <IconButton\n type=\"button\"\n icon={<X aria-hidden=\"true\" />}\n intent=\"ghost\"\n size=\"sm\"\n aria-label={\n dismissAllLabel ??\n t('warningStack.dismissAll', 'Dismiss all notices')\n }\n onClick={handleDismissAll}\n // Pull flush to the card's inline-end padding edge, and never let\n // the button compress when the title wraps.\n className=\"ds:-me-[var(--spacing-2xs)] ds:shrink-0\"\n />\n </div>\n ) : (\n titleBlock\n );\n\n // Fully folded away (or cold-start empty with no emptyState): render\n // nothing. Matches the long-standing \"empty + no emptyState → null\"\n // contract, now reached via the fold-out animation rather than instantly.\n if (!mounted) return null;\n\n return (\n // Outer: height-collapse track. Carries the bounding marker so it is\n // the cascade-reset boundary even mid-fold.\n <div\n data-component=\"warning-stack\"\n className={collapseTrackClass(animCollapsed, stretch)}\n >\n {/* Inner: cross-fade + overflow clip while folding. */}\n <div className={collapseInnerClass(animCollapsed, closing)}>\n <section\n ref={setSectionRef}\n aria-labelledby={labelId}\n // Programmatically focusable so a surviving region can take the\n // last dismissal's focus (see the focus hand-off above).\n tabIndex={-1}\n className={[stackVariants({ stretch }), className]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n {header}\n {/* The live region announces the count as it changes. Omitted in\n emptyState mode, where the empty state itself communicates. */}\n {!hasEmptyState ? (\n <div\n ref={liveRef}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"ds:sr-only\"\n />\n ) : null}\n {hasItems ? (\n <>\n {/* Container-type lives on this wrapper (never on the flex\n section itself) so the list can query its own inline size. */}\n <div className=\"ds:@container/warning-stack\">\n <ul\n id={listId}\n className={LIST_CLASSES}\n // Neutral wording — the list mixes warnings with info\n // notices and promo offers.\n aria-label={t('warningStack.listLabel', 'Notices')}\n >\n {visible.map((item, index) => {\n const variant = item.variant ?? 'warning';\n return (\n // `data-warning-id` is the per-notice agent hook: it\n // makes one warning addressable in the DOM, and its\n // dismiss control is the nested `[data-alert-dismiss]`.\n <li key={item.id} data-warning-id={item.id}>\n <Alert\n variant={variant}\n dismissible={item.dismissible}\n icon={item.icon}\n onOpenChange={handleDismiss(item, index)}\n // Compact: clamp title/description so a notice stays\n // a predictable height — keeps the tray tight and\n // side-by-side cards even.\n clamp\n // Fill the row so side-by-side alerts equalise height.\n className=\"ds:h-full\"\n >\n {/* `as=\"h3\"` keeps a clean heading ladder — the\n stack's h2 labels the region, then each item's\n h3 rises from it. */}\n <Alert.Title as=\"h3\">{item.title}</Alert.Title>\n {item.description ? (\n <Alert.Description>\n {item.description}\n </Alert.Description>\n ) : null}\n {item.actions ? (\n <Alert.Action>{item.actions}</Alert.Action>\n ) : null}\n </Alert>\n </li>\n );\n })}\n </ul>\n </div>\n\n {overflow ? (\n <Button\n type=\"button\"\n intent=\"link\"\n size=\"sm\"\n aria-expanded={!collapsed}\n aria-controls={listId}\n onClick={toggle}\n className={TOGGLE_CLASSES}\n >\n <ChevronDown\n aria-hidden=\"true\"\n className={[\n 'ds:size-4 ds:transition-transform ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n collapsed ? '' : 'ds:rotate-180',\n ].join(' ')}\n />\n {collapsed\n ? t('warningStack.showMore', {\n count: hiddenCount,\n defaultValue: 'Show {{count}} more warnings',\n })\n : t('warningStack.showLess', 'Show less')}\n </Button>\n ) : null}\n </>\n ) : (\n emptyState\n )}\n </section>\n </div>\n </div>\n );\n },\n);\n\nWarningStack.displayName = 'WarningStack';\n"],"names":["stackVariants","cva","LIST_CLASSES","TOGGLE_CLASSES","MIN_FOLD_UNMOUNT_MS","readAnimationDurationMs","trimmed","n","collapseTrackClass","collapsed","stretch","collapseInnerClass","closing","WarningStack","forwardRef","items","title","description","maxVisible","defaultCollapsed","onDismiss","closable","onDismissAll","dismissAllLabel","ariaLabel","emptyState","className","rest","ref","t","useTranslation","labelId","useId","listId","dismissedIds","setDismissedIds","useState","useEffect","prev","ids","item","next","id","liveItems","useMemo","overflow","setCollapsed","liveRef","useRef","lastCountRef","visible","hiddenCount","hasItems","hasEmptyState","present","phase","setPhase","entering","setEntering","useIsomorphicLayoutEffect","raf","delay","animCollapsed","mounted","sectionRef","setSectionRef","useCallback","node","pendingFocusIndexRef","index","section","dismissControls","target","handleDismiss","open","handleDismissAll","toggle","c","regionLabel","titleBlock","jsxs","jsx","header","IconButton","X","Fragment","variant","Alert","Button","ChevronDown"],"mappings":"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"}
@@ -13,7 +13,7 @@ import { T as ae } from "./trash-2-uumy3fy1.js";
13
13
  import { C as Ne } from "./circle-dashed-CUj6o2cA.js";
14
14
  import { C as Ce } from "./circle-j7oZoouK.js";
15
15
  import { u as _e } from "./registry-DvAUVLHh.js";
16
- import { A as V } from "./alert-DdDpOi-P.js";
16
+ import { A as V } from "./alert-DjsJMGRE.js";
17
17
  import { B as Se } from "./button-D-MQxsA_.js";
18
18
  import { D as N } from "./dropdown-menu-D1we7oAY.js";
19
19
  import { E } from "./empty-state-pL1qum99.js";
@@ -1321,4 +1321,4 @@ export {
1321
1321
  ee as r,
1322
1322
  D as w
1323
1323
  };
1324
- //# sourceMappingURL=workflow-map-C2B2qIr1.js.map
1324
+ //# sourceMappingURL=workflow-map-CYbRD9ek.js.map