@alfadocs/ui-kit-debug 0.48.0 → 0.50.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.
- package/dist/_chunks/{address-autocomplete-CSjMrBvu.js → address-autocomplete-CT-9AOli.js} +2 -2
- package/dist/_chunks/{address-autocomplete-CSjMrBvu.js.map → address-autocomplete-CT-9AOli.js.map} +1 -1
- package/dist/_chunks/{ai-consent-banner-DO5ingMq.js → ai-consent-banner-F2md5JD3.js} +2 -2
- package/dist/_chunks/{ai-consent-banner-DO5ingMq.js.map → ai-consent-banner-F2md5JD3.js.map} +1 -1
- package/dist/_chunks/{ai-tools-rail-CxYG04cw.js → ai-tools-rail-CYLWrRmm.js} +6 -6
- package/dist/_chunks/ai-tools-rail-CYLWrRmm.js.map +1 -0
- package/dist/_chunks/{alert-ywPR59NE.js → alert-CUTxnym2.js} +56 -35
- package/dist/_chunks/alert-CUTxnym2.js.map +1 -0
- package/dist/_chunks/antenatal-schedule-timeline-CdiqkF05.js +413 -0
- package/dist/_chunks/antenatal-schedule-timeline-CdiqkF05.js.map +1 -0
- package/dist/_chunks/{ar-DEz65ZJW.js → ar-C68WKG5a.js} +2 -2
- package/dist/_chunks/{ar-DEz65ZJW.js.map → ar-C68WKG5a.js.map} +1 -1
- package/dist/_chunks/{audio-recorder-DC-v9YFW.js → audio-recorder-DVJXV7_k.js} +2 -2
- package/dist/_chunks/{audio-recorder-DC-v9YFW.js.map → audio-recorder-DVJXV7_k.js.map} +1 -1
- package/dist/_chunks/bishop-score-2MzAz8NE.js +185 -0
- package/dist/_chunks/bishop-score-2MzAz8NE.js.map +1 -0
- package/dist/_chunks/{booking-WV2GSru5.js → booking-DljH0JkS.js} +5 -5
- package/dist/_chunks/{booking-WV2GSru5.js.map → booking-DljH0JkS.js.map} +1 -1
- package/dist/_chunks/circle-arrow-up-CC_85SuH.js +16 -0
- package/dist/_chunks/circle-arrow-up-CC_85SuH.js.map +1 -0
- package/dist/_chunks/cycle-calculator-oOkj5wlB.js +252 -0
- package/dist/_chunks/cycle-calculator-oOkj5wlB.js.map +1 -0
- package/dist/_chunks/{date-picker-Bq7xhMA-.js → date-picker-BfHblqwA.js} +2 -2
- package/dist/_chunks/{date-picker-Bq7xhMA-.js.map → date-picker-BfHblqwA.js.map} +1 -1
- package/dist/_chunks/{date-picker-variants-DLi1Va_e.js → date-picker-variants-CXEAx3O_.js} +22 -22
- package/dist/_chunks/{date-picker-variants-DLi1Va_e.js.map → date-picker-variants-CXEAx3O_.js.map} +1 -1
- package/dist/_chunks/{date-range-picker-DcXuI9y7.js → date-range-picker-hcAMs1wO.js} +3 -3
- package/dist/_chunks/{date-range-picker-DcXuI9y7.js.map → date-range-picker-hcAMs1wO.js.map} +1 -1
- package/dist/_chunks/{date-time-picker-RimumeLR.js → date-time-picker-H-3Pwqlb.js} +9 -9
- package/dist/_chunks/{date-time-picker-RimumeLR.js.map → date-time-picker-H-3Pwqlb.js.map} +1 -1
- package/dist/_chunks/{de-bTBGdjPS.js → de-DK4A9_a8.js} +2 -2
- package/dist/_chunks/{de-bTBGdjPS.js.map → de-DK4A9_a8.js.map} +1 -1
- package/dist/_chunks/{document-scanner-BqLsGs4Y.js → document-scanner-Cxqvq7GR.js} +2 -2
- package/dist/_chunks/{document-scanner-BqLsGs4Y.js.map → document-scanner-Cxqvq7GR.js.map} +1 -1
- package/dist/_chunks/due-date-calculator-DykajWzh.js +256 -0
- package/dist/_chunks/due-date-calculator-DykajWzh.js.map +1 -0
- package/dist/_chunks/{editable-currency-cell-renderer-CLil9B29.js → editable-currency-cell-renderer-Bh48OHRv.js} +2 -2
- package/dist/_chunks/{editable-currency-cell-renderer-CLil9B29.js.map → editable-currency-cell-renderer-Bh48OHRv.js.map} +1 -1
- package/dist/_chunks/{el-BWG5RXxa.js → el-B29HXhG5.js} +2 -2
- package/dist/_chunks/{el-BWG5RXxa.js.map → el-B29HXhG5.js.map} +1 -1
- package/dist/_chunks/{es-DfO_G435.js → es-BOwPVwWn.js} +2 -2
- package/dist/_chunks/{es-DfO_G435.js.map → es-BOwPVwWn.js.map} +1 -1
- package/dist/_chunks/fetal-weight-Da-B4P4k.js +122 -0
- package/dist/_chunks/fetal-weight-Da-B4P4k.js.map +1 -0
- package/dist/_chunks/{fr-BTn24bs8.js → fr-DoDBtn0T.js} +2 -2
- package/dist/_chunks/{fr-BTn24bs8.js.map → fr-DoDBtn0T.js.map} +1 -1
- package/dist/_chunks/{freemium-paywall-DzpD63WY.js → freemium-paywall-BWaLWje-.js} +2 -2
- package/dist/_chunks/{freemium-paywall-DzpD63WY.js.map → freemium-paywall-BWaLWje-.js.map} +1 -1
- package/dist/_chunks/gestational-age-calculator-Bc55hq6t.js +311 -0
- package/dist/_chunks/gestational-age-calculator-Bc55hq6t.js.map +1 -0
- package/dist/_chunks/hcg-doubling-DAnpbale.js +170 -0
- package/dist/_chunks/hcg-doubling-DAnpbale.js.map +1 -0
- package/dist/_chunks/{hi-Dj3oYd84.js → hi-DGByrKby.js} +2 -2
- package/dist/_chunks/{hi-Dj3oYd84.js.map → hi-DGByrKby.js.map} +1 -1
- package/dist/_chunks/{isSameWeek-HfxKk6Lz.js → isSameWeek-B1odL2vR.js} +2 -2
- package/dist/_chunks/{isSameWeek-HfxKk6Lz.js.map → isSameWeek-B1odL2vR.js.map} +1 -1
- package/dist/_chunks/{it-Y85ofIQQ.js → it-B16rEecm.js} +3 -3
- package/dist/_chunks/{it-Y85ofIQQ.js.map → it-B16rEecm.js.map} +1 -1
- package/dist/_chunks/{ja-CQ7J6YoA.js → ja-B0viOgft.js} +2 -2
- package/dist/_chunks/{ja-CQ7J6YoA.js.map → ja-B0viOgft.js.map} +1 -1
- package/dist/_chunks/{marketplace-app-shell-Gfsf78ge.js → marketplace-app-shell-UKSLx9K_.js} +3 -3
- package/dist/_chunks/{marketplace-app-shell-Gfsf78ge.js.map → marketplace-app-shell-UKSLx9K_.js.map} +1 -1
- package/dist/_chunks/{nl-D9kHCmp3.js → nl-cBxEX2QU.js} +2 -2
- package/dist/_chunks/{nl-D9kHCmp3.js.map → nl-cBxEX2QU.js.map} +1 -1
- package/dist/_chunks/{patient-search-CocVcGJ3.js → patient-search-BJOmTmDA.js} +2 -2
- package/dist/_chunks/{patient-search-CocVcGJ3.js.map → patient-search-BJOmTmDA.js.map} +1 -1
- package/dist/_chunks/{patient-shell-CnT4L8gn.js → patient-shell-DUmhXnFq.js} +2 -2
- package/dist/_chunks/{patient-shell-CnT4L8gn.js.map → patient-shell-DUmhXnFq.js.map} +1 -1
- package/dist/_chunks/{payment-form-BNTx4876.js → payment-form-xmeCkxas.js} +2 -2
- package/dist/_chunks/{payment-form-BNTx4876.js.map → payment-form-xmeCkxas.js.map} +1 -1
- package/dist/_chunks/{pdf-viewer-G8SU6Azw.js → pdf-viewer-q1D3Uion.js} +2 -2
- package/dist/_chunks/{pdf-viewer-G8SU6Azw.js.map → pdf-viewer-q1D3Uion.js.map} +1 -1
- package/dist/_chunks/{pl-B3Smqpkr.js → pl-DtS08ioY.js} +3 -3
- package/dist/_chunks/{pl-B3Smqpkr.js.map → pl-DtS08ioY.js.map} +1 -1
- package/dist/_chunks/{practice-results-BFL_mcDW.js → practice-results-Cq1y8JFD.js} +2 -2
- package/dist/_chunks/{practice-results-BFL_mcDW.js.map → practice-results-Cq1y8JFD.js.map} +1 -1
- package/dist/_chunks/pregnancy-dating-48Gfvod1.js +421 -0
- package/dist/_chunks/pregnancy-dating-48Gfvod1.js.map +1 -0
- package/dist/_chunks/pregnancy-weight-gain-CCGrvarh.js +322 -0
- package/dist/_chunks/pregnancy-weight-gain-CCGrvarh.js.map +1 -0
- package/dist/_chunks/product-hub-panel-CkfZBA3t.js +620 -0
- package/dist/_chunks/product-hub-panel-CkfZBA3t.js.map +1 -0
- package/dist/_chunks/{pt-D3J-1c_7.js → pt-yFXs1VvH.js} +2 -2
- package/dist/_chunks/{pt-D3J-1c_7.js.map → pt-yFXs1VvH.js.map} +1 -1
- package/dist/_chunks/{ro-BKAbbEA3.js → ro-DsCzSrzR.js} +2 -2
- package/dist/_chunks/{ro-BKAbbEA3.js.map → ro-DsCzSrzR.js.map} +1 -1
- package/dist/_chunks/{ru-BeG8f0Ep.js → ru-DgDxL0pc.js} +3 -3
- package/dist/_chunks/{ru-BeG8f0Ep.js.map → ru-DgDxL0pc.js.map} +1 -1
- package/dist/_chunks/{sidebar-_vJXI9rB.js → sidebar-h78cTNLh.js} +440 -338
- package/dist/_chunks/sidebar-h78cTNLh.js.map +1 -0
- package/dist/_chunks/{sign-document-DPI2pY9V.js → sign-document-CZkAf28g.js} +2 -2
- package/dist/_chunks/{sign-document-DPI2pY9V.js.map → sign-document-CZkAf28g.js.map} +1 -1
- package/dist/_chunks/{sq-_hRPaeUy.js → sq-DHlCYN67.js} +2 -2
- package/dist/_chunks/{sq-_hRPaeUy.js.map → sq-DHlCYN67.js.map} +1 -1
- package/dist/_chunks/subDays-Bs00akhK.js +8 -0
- package/dist/_chunks/{subDays-Dv7q9S7u.js.map → subDays-Bs00akhK.js.map} +1 -1
- package/dist/_chunks/{sv-g009fSpe.js → sv-O0QaQs_s.js} +2 -2
- package/dist/_chunks/{sv-g009fSpe.js.map → sv-O0QaQs_s.js.map} +1 -1
- package/dist/_chunks/{tr-OKUOuhMW.js → tr-BmNDRuio.js} +2 -2
- package/dist/_chunks/{tr-OKUOuhMW.js.map → tr-BmNDRuio.js.map} +1 -1
- package/dist/_chunks/warning-stack-CXfoAT-_.js +220 -0
- package/dist/_chunks/warning-stack-CXfoAT-_.js.map +1 -0
- package/dist/_chunks/{workflow-map-ZXw-zsZ8.js → workflow-map-DzX_LI4y.js} +2 -2
- package/dist/_chunks/{workflow-map-ZXw-zsZ8.js.map → workflow-map-DzX_LI4y.js.map} +1 -1
- package/dist/_chunks/{zh-CN-De4zwEhx.js → zh-CN-CgVJZEzz.js} +3 -3
- package/dist/_chunks/{zh-CN-De4zwEhx.js.map → zh-CN-CgVJZEzz.js.map} +1 -1
- package/dist/agent-catalog.json +44 -1
- package/dist/components/_shared/antenatal-schedule-timeline.d.ts +18 -0
- package/dist/components/_shared/antenatal-schedule-timeline.d.ts.map +1 -0
- package/dist/components/_shared/antenatal-schedule.d.ts +68 -0
- package/dist/components/_shared/antenatal-schedule.d.ts.map +1 -0
- package/dist/components/_shared/index.d.ts +3 -0
- package/dist/components/_shared/index.d.ts.map +1 -1
- package/dist/components/_shared/obstetrics.d.ts +138 -0
- package/dist/components/_shared/obstetrics.d.ts.map +1 -0
- package/dist/components/address-autocomplete/index.js +1 -1
- package/dist/components/ai-consent-banner/index.js +1 -1
- package/dist/components/ai-tools-rail/ai-tools-rail.d.ts.map +1 -1
- package/dist/components/ai-tools-rail/index.js +1 -1
- package/dist/components/alert/alert.d.ts +2 -2
- package/dist/components/alert/alert.d.ts.map +1 -1
- package/dist/components/alert/index.js +1 -1
- package/dist/components/audio-recorder/index.js +1 -1
- package/dist/components/bishop-score/bishop-score.d.ts +27 -0
- package/dist/components/bishop-score/bishop-score.d.ts.map +1 -0
- package/dist/components/bishop-score/bishop.d.ts +30 -0
- package/dist/components/bishop-score/bishop.d.ts.map +1 -0
- package/dist/components/bishop-score/index.d.ts +4 -0
- package/dist/components/bishop-score/index.d.ts.map +1 -0
- package/dist/components/bishop-score/index.js +10 -0
- package/dist/components/bishop-score/index.js.map +1 -0
- package/dist/components/booking/index.js +1 -1
- package/dist/components/cycle-calculator/cycle-calculator.d.ts.map +1 -1
- package/dist/components/cycle-calculator/cycle.d.ts +5 -0
- package/dist/components/cycle-calculator/cycle.d.ts.map +1 -1
- package/dist/components/cycle-calculator/index.js +1 -1
- package/dist/components/data-table/index.js +1 -1
- package/dist/components/date-picker/index.js +1 -1
- package/dist/components/date-range-picker/index.js +1 -1
- package/dist/components/date-time-picker/index.js +1 -1
- package/dist/components/document-scanner/index.js +1 -1
- package/dist/components/due-date-calculator/due-date-calculator.d.ts +19 -1
- package/dist/components/due-date-calculator/due-date-calculator.d.ts.map +1 -1
- package/dist/components/due-date-calculator/gestation.d.ts +1 -59
- package/dist/components/due-date-calculator/gestation.d.ts.map +1 -1
- package/dist/components/due-date-calculator/index.d.ts +1 -1
- package/dist/components/due-date-calculator/index.d.ts.map +1 -1
- package/dist/components/due-date-calculator/index.js +16 -10
- package/dist/components/fetal-weight/efw.d.ts +25 -0
- package/dist/components/fetal-weight/efw.d.ts.map +1 -0
- package/dist/components/fetal-weight/fetal-weight.d.ts +27 -0
- package/dist/components/fetal-weight/fetal-weight.d.ts.map +1 -0
- package/dist/components/fetal-weight/index.d.ts +4 -0
- package/dist/components/fetal-weight/index.d.ts.map +1 -0
- package/dist/components/fetal-weight/index.js +6 -0
- package/dist/components/fetal-weight/index.js.map +1 -0
- package/dist/components/freemium-paywall/index.js +1 -1
- package/dist/components/gestational-age-calculator/gestational-age-calculator.d.ts +32 -1
- package/dist/components/gestational-age-calculator/gestational-age-calculator.d.ts.map +1 -1
- package/dist/components/gestational-age-calculator/index.js +1 -1
- package/dist/components/hcg-doubling/hcg-doubling.d.ts +31 -0
- package/dist/components/hcg-doubling/hcg-doubling.d.ts.map +1 -0
- package/dist/components/hcg-doubling/hcg.d.ts +33 -0
- package/dist/components/hcg-doubling/hcg.d.ts.map +1 -0
- package/dist/components/hcg-doubling/index.d.ts +4 -0
- package/dist/components/hcg-doubling/index.d.ts.map +1 -0
- package/dist/components/hcg-doubling/index.js +7 -0
- package/dist/components/hcg-doubling/index.js.map +1 -0
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/patient-search/index.js +1 -1
- package/dist/components/payment-form/index.js +1 -1
- package/dist/components/pdf-viewer/index.js +1 -1
- package/dist/components/practice-results/index.js +1 -1
- package/dist/components/pregnancy-dating/index.d.ts +3 -0
- package/dist/components/pregnancy-dating/index.d.ts.map +1 -0
- package/dist/components/pregnancy-dating/index.js +5 -0
- package/dist/components/pregnancy-dating/index.js.map +1 -0
- package/dist/components/pregnancy-dating/pregnancy-dating.d.ts +60 -0
- package/dist/components/pregnancy-dating/pregnancy-dating.d.ts.map +1 -0
- package/dist/components/pregnancy-weight-gain/index.js +1 -1
- package/dist/components/pregnancy-weight-gain/pregnancy-weight-gain.d.ts +7 -0
- package/dist/components/pregnancy-weight-gain/pregnancy-weight-gain.d.ts.map +1 -1
- package/dist/components/pregnancy-weight-gain/weight-gain.d.ts +33 -8
- package/dist/components/pregnancy-weight-gain/weight-gain.d.ts.map +1 -1
- package/dist/components/product-hub-tray/index.d.ts +8 -0
- package/dist/components/product-hub-tray/index.d.ts.map +1 -0
- package/dist/components/product-hub-tray/index.js +10 -0
- package/dist/components/product-hub-tray/index.js.map +1 -0
- package/dist/components/product-hub-tray/product-hub-panel.agent.d.ts +4 -0
- package/dist/components/product-hub-tray/product-hub-panel.agent.d.ts.map +1 -0
- package/dist/components/product-hub-tray/product-hub-panel.d.ts +54 -0
- package/dist/components/product-hub-tray/product-hub-panel.d.ts.map +1 -0
- package/dist/components/product-hub-tray/product-hub-tray.agent.d.ts +4 -0
- package/dist/components/product-hub-tray/product-hub-tray.agent.d.ts.map +1 -0
- package/dist/components/product-hub-tray/product-hub-tray.d.ts +115 -0
- package/dist/components/product-hub-tray/product-hub-tray.d.ts.map +1 -0
- package/dist/components/sidebar/index.d.ts +2 -2
- package/dist/components/sidebar/index.d.ts.map +1 -1
- package/dist/components/sidebar/index.js +12 -11
- package/dist/components/sidebar/sidebar.d.ts +14 -1
- package/dist/components/sidebar/sidebar.d.ts.map +1 -1
- package/dist/components/sign-document/index.js +1 -1
- package/dist/components/warning-stack/index.js +1 -1
- package/dist/components/warning-stack/warning-stack.d.ts.map +1 -1
- package/dist/components/workflow/index.js +1 -1
- package/dist/i18n/locales/ar.d.ts +262 -1
- package/dist/i18n/locales/ar.d.ts.map +1 -1
- package/dist/i18n/locales/ar.js +261 -2
- package/dist/i18n/locales/ar.js.map +1 -1
- package/dist/i18n/locales/de.d.ts +262 -1
- package/dist/i18n/locales/de.d.ts.map +1 -1
- package/dist/i18n/locales/de.js +261 -2
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/el.d.ts +262 -1
- package/dist/i18n/locales/el.d.ts.map +1 -1
- package/dist/i18n/locales/el.js +261 -2
- package/dist/i18n/locales/el.js.map +1 -1
- package/dist/i18n/locales/en.d.ts +262 -1
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +261 -2
- package/dist/i18n/locales/en.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +262 -1
- package/dist/i18n/locales/es.d.ts.map +1 -1
- package/dist/i18n/locales/es.js +261 -2
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +262 -1
- package/dist/i18n/locales/fr.d.ts.map +1 -1
- package/dist/i18n/locales/fr.js +261 -2
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hi.d.ts +262 -1
- package/dist/i18n/locales/hi.d.ts.map +1 -1
- package/dist/i18n/locales/hi.js +261 -2
- package/dist/i18n/locales/hi.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +262 -1
- package/dist/i18n/locales/it.d.ts.map +1 -1
- package/dist/i18n/locales/it.js +261 -2
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/ja.d.ts +262 -1
- package/dist/i18n/locales/ja.d.ts.map +1 -1
- package/dist/i18n/locales/ja.js +261 -2
- package/dist/i18n/locales/ja.js.map +1 -1
- package/dist/i18n/locales/nl.d.ts +262 -1
- package/dist/i18n/locales/nl.d.ts.map +1 -1
- package/dist/i18n/locales/nl.js +261 -2
- package/dist/i18n/locales/nl.js.map +1 -1
- package/dist/i18n/locales/pl.d.ts +262 -1
- package/dist/i18n/locales/pl.d.ts.map +1 -1
- package/dist/i18n/locales/pl.js +261 -2
- package/dist/i18n/locales/pl.js.map +1 -1
- package/dist/i18n/locales/pt.d.ts +262 -1
- package/dist/i18n/locales/pt.d.ts.map +1 -1
- package/dist/i18n/locales/pt.js +261 -2
- package/dist/i18n/locales/pt.js.map +1 -1
- package/dist/i18n/locales/ro.d.ts +262 -1
- package/dist/i18n/locales/ro.d.ts.map +1 -1
- package/dist/i18n/locales/ro.js +261 -2
- package/dist/i18n/locales/ro.js.map +1 -1
- package/dist/i18n/locales/ru.d.ts +262 -1
- package/dist/i18n/locales/ru.d.ts.map +1 -1
- package/dist/i18n/locales/ru.js +261 -2
- package/dist/i18n/locales/ru.js.map +1 -1
- package/dist/i18n/locales/sq.d.ts +262 -1
- package/dist/i18n/locales/sq.d.ts.map +1 -1
- package/dist/i18n/locales/sq.js +261 -2
- package/dist/i18n/locales/sq.js.map +1 -1
- package/dist/i18n/locales/sv.d.ts +262 -1
- package/dist/i18n/locales/sv.d.ts.map +1 -1
- package/dist/i18n/locales/sv.js +261 -2
- package/dist/i18n/locales/sv.js.map +1 -1
- package/dist/i18n/locales/tr.d.ts +262 -1
- package/dist/i18n/locales/tr.d.ts.map +1 -1
- package/dist/i18n/locales/tr.js +261 -2
- package/dist/i18n/locales/tr.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +262 -1
- package/dist/i18n/locales/zh.d.ts.map +1 -1
- package/dist/i18n/locales/zh.js +261 -2
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.js +661 -632
- package/dist/index.js.map +1 -1
- package/dist/locales/ar.json +263 -2
- package/dist/locales/de.json +263 -2
- package/dist/locales/el.json +263 -2
- package/dist/locales/en.json +263 -2
- package/dist/locales/es.json +263 -2
- package/dist/locales/fr.json +263 -2
- package/dist/locales/hi.json +263 -2
- package/dist/locales/it.json +263 -2
- package/dist/locales/ja.json +263 -2
- package/dist/locales/nl.json +263 -2
- package/dist/locales/pl.json +263 -2
- package/dist/locales/pt.json +263 -2
- package/dist/locales/ro.json +263 -2
- package/dist/locales/ru.json +263 -2
- package/dist/locales/sq.json +263 -2
- package/dist/locales/sv.json +263 -2
- package/dist/locales/tr.json +263 -2
- package/dist/locales/zh.json +263 -2
- package/dist/patterns/marketplace-app-shell/index.js +1 -1
- package/dist/patterns/patient-shell/index.js +1 -1
- package/dist/tokens.css +1 -1
- package/package.json +21 -1
- package/dist/_chunks/ai-tools-rail-CxYG04cw.js.map +0 -1
- package/dist/_chunks/alert-ywPR59NE.js.map +0 -1
- package/dist/_chunks/cycle-calculator-DYvGm_m1.js +0 -211
- package/dist/_chunks/cycle-calculator-DYvGm_m1.js.map +0 -1
- package/dist/_chunks/due-date-calculator-BXd3ANj7.js +0 -216
- package/dist/_chunks/due-date-calculator-BXd3ANj7.js.map +0 -1
- package/dist/_chunks/gestation-mWF4AXea.js +0 -50
- package/dist/_chunks/gestation-mWF4AXea.js.map +0 -1
- package/dist/_chunks/gestational-age-calculator-Crj6FgZw.js +0 -203
- package/dist/_chunks/gestational-age-calculator-Crj6FgZw.js.map +0 -1
- package/dist/_chunks/pregnancy-weight-gain-C7dK89jE.js +0 -246
- package/dist/_chunks/pregnancy-weight-gain-C7dK89jE.js.map +0 -1
- package/dist/_chunks/sidebar-_vJXI9rB.js.map +0 -1
- package/dist/_chunks/subDays-Dv7q9S7u.js +0 -8
- package/dist/_chunks/warning-stack-DNR3-IbP.js +0 -180
- package/dist/_chunks/warning-stack-DNR3-IbP.js.map +0 -1
|
@@ -58,7 +58,7 @@ const $e = O(
|
|
|
58
58
|
].join(" ")
|
|
59
59
|
), Le = O(
|
|
60
60
|
[
|
|
61
|
-
"ds:flex ds:flex-col ds:gap-[var(--spacing-
|
|
61
|
+
"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]",
|
|
62
62
|
"ds:ps-3 ds:pe-3 ds:py-2 ds:rounded-[var(--radius-sm)]",
|
|
63
63
|
"ds:cursor-pointer ds:select-none ds:text-foreground",
|
|
64
64
|
"ds:text-start",
|
|
@@ -355,4 +355,4 @@ export {
|
|
|
355
355
|
ze as A,
|
|
356
356
|
oe as p
|
|
357
357
|
};
|
|
358
|
-
//# sourceMappingURL=address-autocomplete-
|
|
358
|
+
//# sourceMappingURL=address-autocomplete-CT-9AOli.js.map
|
package/dist/_chunks/{address-autocomplete-CSjMrBvu.js.map → address-autocomplete-CT-9AOli.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"address-autocomplete-CSjMrBvu.js","sources":["../../src/components/address-autocomplete/parse-address.ts","../../src/components/address-autocomplete/address-autocomplete.tsx"],"sourcesContent":["/* ------------------------------------------------------------------ */\n/* parse-address — pure mapper from Google address components to the */\n/* kit's StructuredAddress shape. */\n/* */\n/* Kept dependency-free and side-effect-free so it can be unit-tested */\n/* in isolation (no Google SDK, no DOM) and reused by the mock-mode */\n/* story/test fixtures. Accepts the loosened component shape produced */\n/* by BOTH the new Places API (`Place.addressComponents` → */\n/* `{ longText, shortText, types }`) and the classic Geocoder/ */\n/* PlacesService shape (`{ long_name, short_name, types }`) so the */\n/* component can fall back without re-shaping upstream. */\n/* ------------------------------------------------------------------ */\n\n/**\n * Structured, app-friendly address. Field semantics match the AlfaDocs\n * Italian patient-address model: `province` is the 2-letter IT province\n * code (UPPERCASED) and `country` is the ISO 3166-1 alpha-2 code\n * (lowercased), matching how the platform stores them.\n */\nexport interface StructuredAddress {\n /** Street line — route, with the street number joined when present. */\n street: string;\n /** Town / city (locality, falling back to postal_town / admin level 3). */\n city: string;\n /** Postal / ZIP code. */\n postcode: string;\n /** Province — admin level 2 short code, UPPERCASED (e.g. \"MI\", \"RM\"). */\n province: string;\n /** Country — ISO alpha-2, lowercased (e.g. \"it\", \"gb\"). */\n country: string;\n /** Google's human-readable formatted address (whole line). */\n formatted: string;\n}\n\n/**\n * Loosened address-component shape accepted by {@link parseAddressComponents}.\n * Mirrors both Places-API (`longText`/`shortText`) and classic Geocoder\n * (`long_name`/`short_name`) field names so either source parses without a\n * pre-pass. `types` is required; the text fields are individually optional.\n */\nexport interface RawAddressComponent {\n types: string[];\n longText?: string | null;\n shortText?: string | null;\n long_name?: string | null;\n short_name?: string | null;\n}\n\nfunction longTextOf(component: RawAddressComponent): string {\n return component.longText ?? component.long_name ?? '';\n}\n\nfunction shortTextOf(component: RawAddressComponent): string {\n return component.shortText ?? component.short_name ?? longTextOf(component);\n}\n\nfunction findByType(\n components: readonly RawAddressComponent[],\n type: string,\n): RawAddressComponent | undefined {\n return components.find((component) => component.types.includes(type));\n}\n\n/**\n * Maps an array of Google address components to a {@link StructuredAddress}.\n *\n * Pure: no SDK calls, no DOM, no I/O. `formatted` is passed through from the\n * caller (Google's `formattedAddress` / `formatted_address`) because it is\n * not derivable from the component list.\n *\n * Mapping rules:\n * - `street` = `route`, prefixed with `street_number` when present\n * (e.g. \"Via Roma 12\"). Either part alone is used if the\n * other is missing.\n * - `city` = `locality`, falling back to `postal_town`, then\n * `administrative_area_level_3`.\n * - `postcode` = `postal_code`.\n * - `province` = `administrative_area_level_2` SHORT text, UPPERCASED.\n * - `country` = `country` SHORT text (ISO alpha-2), lowercased.\n */\nexport function parseAddressComponents(\n components: readonly RawAddressComponent[],\n formatted = '',\n): StructuredAddress {\n const route = findByType(components, 'route');\n const streetNumber = findByType(components, 'street_number');\n const locality = findByType(components, 'locality');\n const postalTown = findByType(components, 'postal_town');\n const adminLevel3 = findByType(components, 'administrative_area_level_3');\n const postalCode = findByType(components, 'postal_code');\n const adminLevel2 = findByType(components, 'administrative_area_level_2');\n const country = findByType(components, 'country');\n\n const routeText = route ? longTextOf(route) : '';\n const numberText = streetNumber ? longTextOf(streetNumber) : '';\n const street = [routeText, numberText].filter(Boolean).join(' ').trim();\n\n const cityComponent = locality ?? postalTown ?? adminLevel3;\n const city = cityComponent ? longTextOf(cityComponent) : '';\n\n const postcode = postalCode ? longTextOf(postalCode) : '';\n\n const province = adminLevel2 ? shortTextOf(adminLevel2).toUpperCase() : '';\n\n const countryCode = country ? shortTextOf(country).toLowerCase() : '';\n\n return {\n street,\n city,\n postcode,\n province,\n country: countryCode,\n formatted,\n };\n}\n","/// <reference types=\"google.maps\" />\n/* ------------------------------------------------------------------ */\n/* AddressAutocomplete — single-line address field with Google Places */\n/* suggestions, surfaced as an accessible combobox + listbox. */\n/* */\n/* - Wraps the Google Maps JS API on demand via the library's */\n/* `APIProvider`; the consumer supplies `apiKey` (never cached by the */\n/* kit, same contract as MapView). NO `<Map>` is rendered — only the */\n/* `places` library is loaded via `useMapsLibrary(\"places\")`. */\n/* - NO consent gate (unlike MapView): the consumer guarantees consent */\n/* upstream before mounting this field. */\n/* - Prefers the NEW Places API */\n/* (`AutocompleteSuggestion.fetchAutocompleteSuggestions` for */\n/* predictions + `Place.fetchFields([\"addressComponents\", …])` for */\n/* details). Falls back to the classic `AutocompleteService` + */\n/* `PlacesService` when the new classes are unavailable in the loaded */\n/* SDK version. */\n/* - NO-KEY / no-library fallback: when `apiKey` is absent (and no */\n/* `getSuggestions` injector is given), renders a plain themed text */\n/* input so the field never hard-fails. */\n/* - MOCK mode: pass `getSuggestions` to drive the listbox from a */\n/* static list (each carrying a pre-parsed `StructuredAddress`) — no */\n/* real Google call. Used by stories/tests. */\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type FocusEvent,\n type ForwardedRef,\n type KeyboardEvent,\n type ReactNode,\n} from 'react';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { APIProvider, useMapsLibrary } from '@vis.gl/react-google-maps';\nimport { MapPin } from 'lucide-react';\nimport { useFormField } from '../form-field/form-field-context';\nimport { composeRefs } from '../_shared/compose-refs';\nimport { useControllableState } from '../../hooks/use-controllable-state';\nimport { useDebouncedCallback } from '../_shared/use-debounced-callback';\nimport {\n INPUT_SURFACE_CHROME,\n INPUT_SURFACE_HEIGHT,\n INPUT_SURFACE_TEXT,\n INPUT_SURFACE_TONE,\n} from '../_shared/input-surface';\nimport {\n parseAddressComponents,\n type StructuredAddress,\n type RawAddressComponent,\n} from './parse-address';\n\nexport type { StructuredAddress, RawAddressComponent };\n\n/* ------------------------------------------------------------------ */\n/* Suggestion shape */\n/* ------------------------------------------------------------------ */\n\n/**\n * A single address suggestion surfaced in the listbox.\n *\n * `placeId` keys the row and (in real Google mode) is used to fetch full\n * details on selection. In MOCK mode the suggestion carries a pre-parsed\n * `address` so selection resolves without any network call.\n */\nexport interface AddressSuggestion {\n /** Stable id — the Google place id, or any unique string in mock mode. */\n placeId: string;\n /** Primary line shown in the row (e.g. \"Via Roma 12\"). */\n primaryText: string;\n /** Secondary line shown muted under the primary (e.g. \"Milan, Italy\"). */\n secondaryText?: string;\n /**\n * Pre-parsed structured address. Required in MOCK mode (so selection can\n * resolve without Google). In real Google mode this is omitted and the\n * details are fetched on selection.\n */\n address?: StructuredAddress;\n}\n\n/**\n * Test/story injector. Given the current query it returns the suggestions\n * to show. Each returned suggestion MUST carry a pre-parsed `address` so\n * selection resolves without a real Google call.\n */\nexport type GetSuggestions = (\n query: string,\n) => AddressSuggestion[] | Promise<AddressSuggestion[]>;\n\n/* ------------------------------------------------------------------ */\n/* Props */\n/* ------------------------------------------------------------------ */\n\nexport interface AddressAutocompleteProps {\n /**\n * Google Maps JS API key. Consumer-owned; never cached by the kit. When\n * absent (and no `getSuggestions` injector is given) the field degrades\n * to a plain free-text input with no suggestions.\n */\n apiKey?: string;\n /** Controlled text value of the input. */\n value?: string;\n /** Fires on every keystroke with the new input text. */\n onValueChange?: (value: string) => void;\n /** Uncontrolled initial text. Ignored once `value` is set. */\n defaultValue?: string;\n /**\n * Fires when the user picks a suggestion, with the parsed structured\n * address. In real Google mode the details are fetched first, so this\n * is async relative to the click.\n */\n onSelect?: (address: StructuredAddress) => void;\n /**\n * Test-only / mock injector. When provided, the listbox is driven from\n * its return value instead of a real Google call — even when `apiKey` is\n * also set (the injector wins, so stories/tests are deterministic).\n */\n getSuggestions?: GetSuggestions;\n /**\n * Restrict predictions to these CLDR region codes (e.g. `['it']`).\n * Real-Google mode only.\n */\n regionCodes?: string[];\n /** Visible label is owned by a wrapping FormField; this is a fallback name. */\n 'aria-label'?: string;\n /** Placeholder text. Falls back to the translated default. */\n placeholder?: string;\n /** Debounce before firing a suggestion fetch. Default 250ms. */\n debounceMs?: number;\n disabled?: boolean;\n required?: boolean;\n readOnly?: boolean;\n name?: string;\n /** Field id. Falls back to FormField context id. */\n id?: string;\n size?: 'sm' | 'md' | 'lg';\n tone?: 'default' | 'error';\n className?: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst wrapperVariants = cva(\n ['ds:flex ds:w-full ds:items-center', INPUT_SURFACE_CHROME].join(' '),\n {\n variants: {\n size: {\n sm: `${INPUT_SURFACE_HEIGHT.sm} ${INPUT_SURFACE_TEXT.sm}`,\n md: `${INPUT_SURFACE_HEIGHT.md} ${INPUT_SURFACE_TEXT.md}`,\n lg: `${INPUT_SURFACE_HEIGHT.lg} ${INPUT_SURFACE_TEXT.lg}`,\n },\n tone: INPUT_SURFACE_TONE,\n },\n defaultVariants: { size: 'md', tone: 'default' },\n },\n);\n\nconst inputVariants = cva(\n [\n 'ds:flex-1 ds:min-w-0 ds:ps-3 ds:pe-3 ds:bg-transparent ds:text-foreground',\n 'ds:placeholder:text-muted-foreground',\n 'ds:outline-none ds:focus:outline-none ds:focus-visible:outline-none',\n 'ds:disabled:cursor-not-allowed ds:read-only:cursor-default',\n ].join(' '),\n);\n\nconst adornmentClasses =\n 'ds:inline-flex ds:items-center ds:shrink-0 ds:ps-3 ds:text-muted-foreground ds:[&_svg]:size-4';\n\nconst listboxVariants = cva(\n [\n 'ds:absolute ds:z-[var(--z-dropdown)] ds:mt-[var(--spacing-2xs)] ds:w-full',\n 'ds:overflow-auto ds:max-h-[18rem]',\n 'ds:rounded-[var(--radius-sm)] ds:border ds:border-border ds:bg-background',\n 'ds:shadow-[var(--shadow-md)] ds:p-[var(--spacing-xs)]',\n ].join(' '),\n);\n\nconst optionVariants = cva(\n [\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-3xs)]',\n 'ds:ps-3 ds:pe-3 ds:py-2 ds:rounded-[var(--radius-sm)]',\n 'ds:cursor-pointer ds:select-none ds:text-foreground',\n 'ds:text-start',\n 'ds:data-[active=true]:bg-primary ds:data-[active=true]:text-primary-foreground',\n 'ds:hover:bg-muted ds:data-[active=true]:hover:bg-primary',\n ].join(' '),\n);\n\nconst messageClasses =\n 'ds:ps-3 ds:pe-3 ds:py-2 type-body-sm ds:text-muted-foreground';\n\n/* ------------------------------------------------------------------ */\n/* Inner: real Google Places engine. */\n/* */\n/* `useMapsLibrary(\"places\")` only resolves inside an APIProvider tree, */\n/* so this inner component is mounted by the outer wrapper only when an */\n/* apiKey is present and no mock injector is supplied. It owns no UI — */\n/* it renders the shared `<AddressCombobox>` with a `getSuggestions` / */\n/* `resolveSelection` pair wired to the loaded SDK. */\n/* ------------------------------------------------------------------ */\n\ninterface GoogleEngineProps extends Omit<AddressAutocompleteProps, 'apiKey'> {\n forwardedRef: ForwardedRef<HTMLInputElement>;\n}\n\nfunction GooglePlacesEngine({\n forwardedRef,\n regionCodes,\n onSelect,\n ...rest\n}: GoogleEngineProps): ReactNode {\n const places = useMapsLibrary('places');\n // A fresh session token groups the query + selection phases for billing.\n // Reset after each selection so the next lookup starts a new session.\n const sessionTokenRef =\n useRef<google.maps.places.AutocompleteSessionToken | null>(null);\n\n const supportsNewApi = Boolean(\n places &&\n 'AutocompleteSuggestion' in places &&\n 'Place' in places &&\n 'AutocompleteSessionToken' in places,\n );\n\n const getSuggestions = useCallback<GetSuggestions>(\n async (query) => {\n if (!places || query.trim().length === 0) return [];\n\n if (supportsNewApi) {\n if (!sessionTokenRef.current) {\n sessionTokenRef.current = new places.AutocompleteSessionToken();\n }\n const { suggestions } =\n await places.AutocompleteSuggestion.fetchAutocompleteSuggestions({\n input: query,\n sessionToken: sessionTokenRef.current,\n includedRegionCodes: regionCodes,\n });\n return suggestions\n .map((suggestion): AddressSuggestion | null => {\n const prediction = suggestion.placePrediction;\n if (!prediction) return null;\n return {\n placeId: prediction.placeId,\n primaryText: prediction.mainText?.text ?? prediction.text.text,\n secondaryText: prediction.secondaryText?.text,\n };\n })\n .filter((value): value is AddressSuggestion => value !== null);\n }\n\n // Classic fallback — AutocompleteService.getPlacePredictions.\n const ServiceCtor = (\n places as unknown as {\n AutocompleteService?: new () => google.maps.places.AutocompleteService;\n }\n ).AutocompleteService;\n if (!ServiceCtor) return [];\n const service = new ServiceCtor();\n const response = await service.getPlacePredictions({ input: query });\n return response.predictions.map((prediction) => ({\n placeId: prediction.place_id,\n primaryText:\n prediction.structured_formatting?.main_text ?? prediction.description,\n secondaryText: prediction.structured_formatting?.secondary_text,\n }));\n },\n [places, supportsNewApi, regionCodes],\n );\n\n const resolveSelection = useCallback(\n async (\n suggestion: AddressSuggestion,\n ): Promise<StructuredAddress | null> => {\n if (suggestion.address) return suggestion.address;\n if (!places) return null;\n\n if (supportsNewApi) {\n const place = new places.Place({ id: suggestion.placeId });\n const { place: filled } = await place.fetchFields({\n fields: ['addressComponents', 'formattedAddress'],\n });\n // End the billing session once details are fetched.\n sessionTokenRef.current = null;\n const components = (filled.addressComponents ??\n []) as unknown as RawAddressComponent[];\n return parseAddressComponents(\n components,\n filled.formattedAddress ?? '',\n );\n }\n\n // Classic fallback — PlacesService.getDetails. Requires a DOM node to\n // host the service (an offscreen div suffices; nothing is rendered).\n const ServiceCtor = (\n places as unknown as {\n PlacesService?: new (\n container: HTMLElement,\n ) => google.maps.places.PlacesService;\n }\n ).PlacesService;\n if (!ServiceCtor) return null;\n const service = new ServiceCtor(document.createElement('div'));\n return new Promise<StructuredAddress | null>((resolve) => {\n service.getDetails(\n {\n placeId: suggestion.placeId,\n fields: ['address_components', 'formatted_address'],\n },\n (result) => {\n if (!result) {\n resolve(null);\n return;\n }\n const components = (result.address_components ??\n []) as unknown as RawAddressComponent[];\n resolve(\n parseAddressComponents(\n components,\n result.formatted_address ?? '',\n ),\n );\n },\n );\n });\n },\n [places, supportsNewApi],\n );\n\n return (\n <AddressCombobox\n {...rest}\n forwardedRef={forwardedRef}\n getSuggestions={getSuggestions}\n resolveSelection={resolveSelection}\n onSelect={onSelect}\n />\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Inner: the accessible combobox itself. */\n/* */\n/* Implements the WAI-ARIA 1.2 combobox pattern (text input + listbox */\n/* popup, `aria-activedescendant`). Shared by mock mode, no-key mode, */\n/* and the Google engine — only the `getSuggestions` / `resolveSelection`*/\n/* pair differs. */\n/* ------------------------------------------------------------------ */\n\ninterface AddressComboboxProps extends Omit<\n AddressAutocompleteProps,\n 'apiKey' | 'getSuggestions'\n> {\n forwardedRef?: ForwardedRef<HTMLInputElement>;\n getSuggestions?: GetSuggestions;\n resolveSelection?: (\n suggestion: AddressSuggestion,\n ) => Promise<StructuredAddress | null>;\n}\n\nfunction AddressCombobox({\n forwardedRef,\n value,\n defaultValue,\n onValueChange,\n onSelect,\n getSuggestions,\n resolveSelection,\n placeholder,\n debounceMs = 250,\n disabled,\n required,\n readOnly,\n name,\n id,\n size = 'md',\n tone = 'default',\n className,\n 'aria-label': ariaLabel,\n}: AddressComboboxProps): ReactNode {\n const { t } = useTranslation();\n const ctx = useFormField();\n\n // Internal node ref — used for focus() after selection and for the\n // listbox-contains check on blur. Composed with the consumer's\n // forwardRef onto the rendered <input>.\n const inputRef = useRef<HTMLInputElement | null>(null);\n const setInputRef = useMemo(\n () => composeRefs(forwardedRef, inputRef),\n [forwardedRef],\n );\n\n const reactId = useId();\n const idPrefix = id ?? ctx.id ?? reactId;\n const listId = `${idPrefix}-listbox`;\n const liveId = `${idPrefix}-live`;\n const optionId = (placeId: string) => `${idPrefix}-opt-${placeId}`;\n\n const effectiveDisabled = Boolean(ctx.disabled || disabled);\n const effectiveRequired = Boolean(ctx.required || required);\n const effectiveInvalid = ctx.invalid;\n const effectiveTone: 'default' | 'error' = effectiveInvalid ? 'error' : tone;\n const describedBy = ctx.describedBy || undefined;\n\n const [currentValueRaw, commitValue] = useControllableState<string>({\n value,\n defaultValue: defaultValue ?? '',\n onChange: onValueChange,\n });\n const currentValue = currentValueRaw ?? '';\n\n const [open, setOpen] = useState(false);\n const [suggestions, setSuggestions] = useState<AddressSuggestion[]>([]);\n const [loading, setLoading] = useState(false);\n const [activeIndex, setActiveIndex] = useState(-1);\n\n const composingRef = useRef(false);\n const latestQueryRef = useRef('');\n\n const resolvedPlaceholder =\n placeholder ?? t('inputs.addressAutocomplete.placeholder');\n\n const runFetch = useCallback(\n (query: string) => {\n if (!getSuggestions || effectiveDisabled || readOnly) return;\n if (composingRef.current) return;\n latestQueryRef.current = query;\n setLoading(true);\n Promise.resolve(getSuggestions(query))\n .then((results) => {\n // Drop stale responses — only the latest query may render.\n if (latestQueryRef.current !== query) return;\n setSuggestions(results);\n setActiveIndex(-1);\n setLoading(false);\n })\n .catch(() => {\n if (latestQueryRef.current !== query) return;\n setSuggestions([]);\n setLoading(false);\n });\n },\n [getSuggestions, effectiveDisabled, readOnly],\n );\n\n const debouncedFetch = useDebouncedCallback(runFetch, debounceMs);\n\n useEffect(() => () => debouncedFetch.cancel(), [debouncedFetch]);\n\n const handleInputChange = (next: string) => {\n commitValue(next);\n if (effectiveDisabled || readOnly) return;\n if (!open) setOpen(true);\n if (composingRef.current) return;\n debouncedFetch(next);\n };\n\n const handleSelect = useCallback(\n (suggestion: AddressSuggestion) => {\n commitValue(suggestion.primaryText);\n setOpen(false);\n setActiveIndex(-1);\n setSuggestions([]);\n latestQueryRef.current = suggestion.primaryText;\n if (resolveSelection) {\n Promise.resolve(resolveSelection(suggestion))\n .then((address) => {\n if (address) onSelect?.(address);\n })\n .catch(() => {\n /* selection details failed — leave the typed text in place */\n });\n } else if (suggestion.address) {\n onSelect?.(suggestion.address);\n }\n inputRef.current?.focus();\n },\n [commitValue, resolveSelection, onSelect, inputRef],\n );\n\n // Whether the listbox popup is actually displayed (mirrors `aria-expanded`\n // on the input). Derived here — above the keyboard handler — so an expanded\n // listbox can swallow Enter instead of letting it submit a surrounding\n // <form>.\n const showEmpty =\n open &&\n !loading &&\n currentValue.trim().length > 0 &&\n suggestions.length === 0 &&\n Boolean(getSuggestions);\n const hasOptions = suggestions.length > 0;\n const listboxOpen = open && (hasOptions || showEmpty || loading);\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.nativeEvent.isComposing) return;\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n if (!open) {\n setOpen(true);\n if (currentValue) debouncedFetch(currentValue);\n return;\n }\n if (suggestions.length === 0) return;\n setActiveIndex((index) => (index + 1) % suggestions.length);\n return;\n }\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n if (suggestions.length === 0) return;\n setActiveIndex((index) =>\n index <= 0 ? suggestions.length - 1 : index - 1,\n );\n return;\n }\n if (event.key === 'Enter') {\n // While the listbox is expanded, swallow Enter so it never submits the\n // surrounding <form>. Accept the highlighted option if there is one;\n // otherwise keep the typed text (blur / Escape dismiss the listbox).\n if (listboxOpen) {\n event.preventDefault();\n if (activeIndex >= 0 && suggestions[activeIndex]) {\n handleSelect(suggestions[activeIndex]);\n }\n }\n return;\n }\n if (event.key === 'Escape') {\n if (open) {\n event.preventDefault();\n setOpen(false);\n setActiveIndex(-1);\n }\n }\n };\n\n const handleFocus = () => {\n if (effectiveDisabled || readOnly) return;\n if (currentValue) {\n setOpen(true);\n debouncedFetch(currentValue);\n }\n };\n\n const handleBlur = (event: FocusEvent<HTMLInputElement>) => {\n // Keep open when focus moves into the listbox (pointer-down on an option).\n const next = event.relatedTarget as Node | null;\n if (next && listRef.current?.contains(next)) return;\n setOpen(false);\n setActiveIndex(-1);\n };\n\n const listRef = useRef<HTMLUListElement | null>(null);\n\n const activeDescendant =\n open && activeIndex >= 0 && suggestions[activeIndex]\n ? optionId(suggestions[activeIndex].placeId)\n : undefined;\n\n const liveMessage = loading\n ? t('inputs.addressAutocomplete.loading')\n : open && currentValue.trim().length > 0\n ? t('inputs.addressAutocomplete.results', { count: suggestions.length })\n : '';\n\n return (\n <div\n className=\"ds:relative ds:w-full\"\n data-component=\"address-autocomplete\"\n data-component-id={id}\n >\n <div\n className={wrapperVariants({ size, tone: effectiveTone, className })}\n data-disabled={effectiveDisabled || undefined}\n >\n <span aria-hidden=\"true\" className={adornmentClasses}>\n <MapPin />\n </span>\n <input\n ref={setInputRef}\n id={idPrefix}\n name={name}\n type=\"text\"\n autoComplete=\"off\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={listboxOpen}\n aria-controls={listboxOpen ? listId : undefined}\n aria-activedescendant={activeDescendant}\n aria-describedby={describedBy}\n aria-invalid={effectiveInvalid || undefined}\n aria-label={ariaLabel ?? t('inputs.addressAutocomplete.ariaLabel')}\n placeholder={resolvedPlaceholder}\n value={currentValue}\n disabled={effectiveDisabled}\n required={effectiveRequired}\n readOnly={readOnly}\n onChange={(event) => handleInputChange(event.target.value)}\n onKeyDown={handleKeyDown}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onCompositionStart={() => {\n composingRef.current = true;\n }}\n onCompositionEnd={(event) => {\n composingRef.current = false;\n debouncedFetch(event.currentTarget.value);\n }}\n className={inputVariants()}\n />\n </div>\n {listboxOpen ? (\n <ul\n ref={listRef}\n id={listId}\n role=\"listbox\"\n aria-label={ariaLabel ?? t('inputs.addressAutocomplete.listLabel')}\n className={listboxVariants()}\n >\n {hasOptions\n ? suggestions.map((suggestion, index) => (\n <li\n key={suggestion.placeId}\n id={optionId(suggestion.placeId)}\n role=\"option\"\n aria-selected={index === activeIndex}\n data-active={index === activeIndex || undefined}\n // Pointer-down (not click) so selection runs before the\n // input's blur closes the listbox.\n onMouseDown={(event) => {\n event.preventDefault();\n handleSelect(suggestion);\n }}\n onMouseEnter={() => setActiveIndex(index)}\n className={optionVariants()}\n >\n <span className=\"ds:truncate\">{suggestion.primaryText}</span>\n {suggestion.secondaryText ? (\n <span className=\"type-meta ds:text-muted-foreground ds:data-[active=true]:text-primary-foreground ds:truncate\">\n {suggestion.secondaryText}\n </span>\n ) : null}\n </li>\n ))\n : null}\n {!hasOptions && loading ? (\n <li role=\"presentation\" className={messageClasses}>\n {t('inputs.addressAutocomplete.loading')}\n </li>\n ) : null}\n {!hasOptions && !loading && showEmpty ? (\n <li role=\"presentation\" className={messageClasses}>\n {t('inputs.addressAutocomplete.noResults')}\n </li>\n ) : null}\n </ul>\n ) : null}\n <span\n id={liveId}\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"ds:sr-only\"\n >\n {liveMessage}\n </span>\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Public component */\n/* ------------------------------------------------------------------ */\n\nexport const AddressAutocomplete = forwardRef<\n HTMLInputElement,\n AddressAutocompleteProps\n>(function AddressAutocomplete({ apiKey, getSuggestions, ...rest }, ref) {\n const { i18n } = useTranslation();\n\n // MOCK mode wins whenever a `getSuggestions` injector is supplied — even if\n // an apiKey is also present — so stories/tests stay deterministic and never\n // hit the network. The mock injector already carries pre-parsed addresses,\n // so selection resolves straight from the suggestion.\n if (getSuggestions) {\n return (\n <AddressCombobox\n {...rest}\n forwardedRef={ref}\n getSuggestions={getSuggestions}\n resolveSelection={resolveMockSelection}\n />\n );\n }\n\n // NO-KEY fallback — plain free-text input, no suggestions, never fails.\n if (!apiKey) {\n return <AddressCombobox {...rest} forwardedRef={ref} />;\n }\n\n return (\n <APIProvider apiKey={apiKey} language={i18n.language}>\n <GooglePlacesEngine {...rest} forwardedRef={ref} />\n </APIProvider>\n );\n});\nAddressAutocomplete.displayName = 'AddressAutocomplete';\n\n// Module-scoped so the mock branch passes a stable function identity.\nasync function resolveMockSelection(\n suggestion: AddressSuggestion,\n): Promise<StructuredAddress | null> {\n return suggestion.address ?? null;\n}\n"],"names":["longTextOf","component","shortTextOf","findByType","components","type","parseAddressComponents","formatted","route","streetNumber","locality","postalTown","adminLevel3","postalCode","adminLevel2","country","routeText","numberText","street","cityComponent","city","postcode","province","countryCode","wrapperVariants","cva","INPUT_SURFACE_CHROME","INPUT_SURFACE_HEIGHT","INPUT_SURFACE_TEXT","INPUT_SURFACE_TONE","inputVariants","adornmentClasses","listboxVariants","optionVariants","messageClasses","GooglePlacesEngine","forwardedRef","regionCodes","onSelect","rest","places","useMapsLibrary","sessionTokenRef","useRef","supportsNewApi","getSuggestions","useCallback","query","suggestions","suggestion","prediction","_a","_b","value","ServiceCtor","resolveSelection","place","filled","service","resolve","result","jsx","AddressCombobox","defaultValue","onValueChange","placeholder","debounceMs","disabled","required","readOnly","name","id","size","tone","className","ariaLabel","t","useTranslation","ctx","useFormField","inputRef","setInputRef","useMemo","composeRefs","reactId","useId","idPrefix","listId","liveId","optionId","placeId","effectiveDisabled","effectiveRequired","effectiveInvalid","effectiveTone","describedBy","currentValueRaw","commitValue","useControllableState","currentValue","open","setOpen","useState","setSuggestions","loading","setLoading","activeIndex","setActiveIndex","composingRef","latestQueryRef","resolvedPlaceholder","runFetch","results","debouncedFetch","useDebouncedCallback","useEffect","handleInputChange","next","handleSelect","address","showEmpty","hasOptions","listboxOpen","handleKeyDown","event","index","handleFocus","handleBlur","listRef","activeDescendant","liveMessage","jsxs","MapPin","AddressAutocomplete","forwardRef","apiKey","ref","i18n","resolveMockSelection","APIProvider"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"address-autocomplete-CT-9AOli.js","sources":["../../src/components/address-autocomplete/parse-address.ts","../../src/components/address-autocomplete/address-autocomplete.tsx"],"sourcesContent":["/* ------------------------------------------------------------------ */\n/* parse-address — pure mapper from Google address components to the */\n/* kit's StructuredAddress shape. */\n/* */\n/* Kept dependency-free and side-effect-free so it can be unit-tested */\n/* in isolation (no Google SDK, no DOM) and reused by the mock-mode */\n/* story/test fixtures. Accepts the loosened component shape produced */\n/* by BOTH the new Places API (`Place.addressComponents` → */\n/* `{ longText, shortText, types }`) and the classic Geocoder/ */\n/* PlacesService shape (`{ long_name, short_name, types }`) so the */\n/* component can fall back without re-shaping upstream. */\n/* ------------------------------------------------------------------ */\n\n/**\n * Structured, app-friendly address. Field semantics match the AlfaDocs\n * Italian patient-address model: `province` is the 2-letter IT province\n * code (UPPERCASED) and `country` is the ISO 3166-1 alpha-2 code\n * (lowercased), matching how the platform stores them.\n */\nexport interface StructuredAddress {\n /** Street line — route, with the street number joined when present. */\n street: string;\n /** Town / city (locality, falling back to postal_town / admin level 3). */\n city: string;\n /** Postal / ZIP code. */\n postcode: string;\n /** Province — admin level 2 short code, UPPERCASED (e.g. \"MI\", \"RM\"). */\n province: string;\n /** Country — ISO alpha-2, lowercased (e.g. \"it\", \"gb\"). */\n country: string;\n /** Google's human-readable formatted address (whole line). */\n formatted: string;\n}\n\n/**\n * Loosened address-component shape accepted by {@link parseAddressComponents}.\n * Mirrors both Places-API (`longText`/`shortText`) and classic Geocoder\n * (`long_name`/`short_name`) field names so either source parses without a\n * pre-pass. `types` is required; the text fields are individually optional.\n */\nexport interface RawAddressComponent {\n types: string[];\n longText?: string | null;\n shortText?: string | null;\n long_name?: string | null;\n short_name?: string | null;\n}\n\nfunction longTextOf(component: RawAddressComponent): string {\n return component.longText ?? component.long_name ?? '';\n}\n\nfunction shortTextOf(component: RawAddressComponent): string {\n return component.shortText ?? component.short_name ?? longTextOf(component);\n}\n\nfunction findByType(\n components: readonly RawAddressComponent[],\n type: string,\n): RawAddressComponent | undefined {\n return components.find((component) => component.types.includes(type));\n}\n\n/**\n * Maps an array of Google address components to a {@link StructuredAddress}.\n *\n * Pure: no SDK calls, no DOM, no I/O. `formatted` is passed through from the\n * caller (Google's `formattedAddress` / `formatted_address`) because it is\n * not derivable from the component list.\n *\n * Mapping rules:\n * - `street` = `route`, prefixed with `street_number` when present\n * (e.g. \"Via Roma 12\"). Either part alone is used if the\n * other is missing.\n * - `city` = `locality`, falling back to `postal_town`, then\n * `administrative_area_level_3`.\n * - `postcode` = `postal_code`.\n * - `province` = `administrative_area_level_2` SHORT text, UPPERCASED.\n * - `country` = `country` SHORT text (ISO alpha-2), lowercased.\n */\nexport function parseAddressComponents(\n components: readonly RawAddressComponent[],\n formatted = '',\n): StructuredAddress {\n const route = findByType(components, 'route');\n const streetNumber = findByType(components, 'street_number');\n const locality = findByType(components, 'locality');\n const postalTown = findByType(components, 'postal_town');\n const adminLevel3 = findByType(components, 'administrative_area_level_3');\n const postalCode = findByType(components, 'postal_code');\n const adminLevel2 = findByType(components, 'administrative_area_level_2');\n const country = findByType(components, 'country');\n\n const routeText = route ? longTextOf(route) : '';\n const numberText = streetNumber ? longTextOf(streetNumber) : '';\n const street = [routeText, numberText].filter(Boolean).join(' ').trim();\n\n const cityComponent = locality ?? postalTown ?? adminLevel3;\n const city = cityComponent ? longTextOf(cityComponent) : '';\n\n const postcode = postalCode ? longTextOf(postalCode) : '';\n\n const province = adminLevel2 ? shortTextOf(adminLevel2).toUpperCase() : '';\n\n const countryCode = country ? shortTextOf(country).toLowerCase() : '';\n\n return {\n street,\n city,\n postcode,\n province,\n country: countryCode,\n formatted,\n };\n}\n","/// <reference types=\"google.maps\" />\n/* ------------------------------------------------------------------ */\n/* AddressAutocomplete — single-line address field with Google Places */\n/* suggestions, surfaced as an accessible combobox + listbox. */\n/* */\n/* - Wraps the Google Maps JS API on demand via the library's */\n/* `APIProvider`; the consumer supplies `apiKey` (never cached by the */\n/* kit, same contract as MapView). NO `<Map>` is rendered — only the */\n/* `places` library is loaded via `useMapsLibrary(\"places\")`. */\n/* - NO consent gate (unlike MapView): the consumer guarantees consent */\n/* upstream before mounting this field. */\n/* - Prefers the NEW Places API */\n/* (`AutocompleteSuggestion.fetchAutocompleteSuggestions` for */\n/* predictions + `Place.fetchFields([\"addressComponents\", …])` for */\n/* details). Falls back to the classic `AutocompleteService` + */\n/* `PlacesService` when the new classes are unavailable in the loaded */\n/* SDK version. */\n/* - NO-KEY / no-library fallback: when `apiKey` is absent (and no */\n/* `getSuggestions` injector is given), renders a plain themed text */\n/* input so the field never hard-fails. */\n/* - MOCK mode: pass `getSuggestions` to drive the listbox from a */\n/* static list (each carrying a pre-parsed `StructuredAddress`) — no */\n/* real Google call. Used by stories/tests. */\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type FocusEvent,\n type ForwardedRef,\n type KeyboardEvent,\n type ReactNode,\n} from 'react';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { APIProvider, useMapsLibrary } from '@vis.gl/react-google-maps';\nimport { MapPin } from 'lucide-react';\nimport { useFormField } from '../form-field/form-field-context';\nimport { composeRefs } from '../_shared/compose-refs';\nimport { useControllableState } from '../../hooks/use-controllable-state';\nimport { useDebouncedCallback } from '../_shared/use-debounced-callback';\nimport {\n INPUT_SURFACE_CHROME,\n INPUT_SURFACE_HEIGHT,\n INPUT_SURFACE_TEXT,\n INPUT_SURFACE_TONE,\n} from '../_shared/input-surface';\nimport {\n parseAddressComponents,\n type StructuredAddress,\n type RawAddressComponent,\n} from './parse-address';\n\nexport type { StructuredAddress, RawAddressComponent };\n\n/* ------------------------------------------------------------------ */\n/* Suggestion shape */\n/* ------------------------------------------------------------------ */\n\n/**\n * A single address suggestion surfaced in the listbox.\n *\n * `placeId` keys the row and (in real Google mode) is used to fetch full\n * details on selection. In MOCK mode the suggestion carries a pre-parsed\n * `address` so selection resolves without any network call.\n */\nexport interface AddressSuggestion {\n /** Stable id — the Google place id, or any unique string in mock mode. */\n placeId: string;\n /** Primary line shown in the row (e.g. \"Via Roma 12\"). */\n primaryText: string;\n /** Secondary line shown muted under the primary (e.g. \"Milan, Italy\"). */\n secondaryText?: string;\n /**\n * Pre-parsed structured address. Required in MOCK mode (so selection can\n * resolve without Google). In real Google mode this is omitted and the\n * details are fetched on selection.\n */\n address?: StructuredAddress;\n}\n\n/**\n * Test/story injector. Given the current query it returns the suggestions\n * to show. Each returned suggestion MUST carry a pre-parsed `address` so\n * selection resolves without a real Google call.\n */\nexport type GetSuggestions = (\n query: string,\n) => AddressSuggestion[] | Promise<AddressSuggestion[]>;\n\n/* ------------------------------------------------------------------ */\n/* Props */\n/* ------------------------------------------------------------------ */\n\nexport interface AddressAutocompleteProps {\n /**\n * Google Maps JS API key. Consumer-owned; never cached by the kit. When\n * absent (and no `getSuggestions` injector is given) the field degrades\n * to a plain free-text input with no suggestions.\n */\n apiKey?: string;\n /** Controlled text value of the input. */\n value?: string;\n /** Fires on every keystroke with the new input text. */\n onValueChange?: (value: string) => void;\n /** Uncontrolled initial text. Ignored once `value` is set. */\n defaultValue?: string;\n /**\n * Fires when the user picks a suggestion, with the parsed structured\n * address. In real Google mode the details are fetched first, so this\n * is async relative to the click.\n */\n onSelect?: (address: StructuredAddress) => void;\n /**\n * Test-only / mock injector. When provided, the listbox is driven from\n * its return value instead of a real Google call — even when `apiKey` is\n * also set (the injector wins, so stories/tests are deterministic).\n */\n getSuggestions?: GetSuggestions;\n /**\n * Restrict predictions to these CLDR region codes (e.g. `['it']`).\n * Real-Google mode only.\n */\n regionCodes?: string[];\n /** Visible label is owned by a wrapping FormField; this is a fallback name. */\n 'aria-label'?: string;\n /** Placeholder text. Falls back to the translated default. */\n placeholder?: string;\n /** Debounce before firing a suggestion fetch. Default 250ms. */\n debounceMs?: number;\n disabled?: boolean;\n required?: boolean;\n readOnly?: boolean;\n name?: string;\n /** Field id. Falls back to FormField context id. */\n id?: string;\n size?: 'sm' | 'md' | 'lg';\n tone?: 'default' | 'error';\n className?: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst wrapperVariants = cva(\n ['ds:flex ds:w-full ds:items-center', INPUT_SURFACE_CHROME].join(' '),\n {\n variants: {\n size: {\n sm: `${INPUT_SURFACE_HEIGHT.sm} ${INPUT_SURFACE_TEXT.sm}`,\n md: `${INPUT_SURFACE_HEIGHT.md} ${INPUT_SURFACE_TEXT.md}`,\n lg: `${INPUT_SURFACE_HEIGHT.lg} ${INPUT_SURFACE_TEXT.lg}`,\n },\n tone: INPUT_SURFACE_TONE,\n },\n defaultVariants: { size: 'md', tone: 'default' },\n },\n);\n\nconst inputVariants = cva(\n [\n 'ds:flex-1 ds:min-w-0 ds:ps-3 ds:pe-3 ds:bg-transparent ds:text-foreground',\n 'ds:placeholder:text-muted-foreground',\n 'ds:outline-none ds:focus:outline-none ds:focus-visible:outline-none',\n 'ds:disabled:cursor-not-allowed ds:read-only:cursor-default',\n ].join(' '),\n);\n\nconst adornmentClasses =\n 'ds:inline-flex ds:items-center ds:shrink-0 ds:ps-3 ds:text-muted-foreground ds:[&_svg]:size-4';\n\nconst listboxVariants = cva(\n [\n 'ds:absolute ds:z-[var(--z-dropdown)] ds:mt-[var(--spacing-2xs)] ds:w-full',\n 'ds:overflow-auto ds:max-h-[18rem]',\n 'ds:rounded-[var(--radius-sm)] ds:border ds:border-border ds:bg-background',\n 'ds:shadow-[var(--shadow-md)] ds:p-[var(--spacing-xs)]',\n ].join(' '),\n);\n\nconst optionVariants = cva(\n [\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]',\n 'ds:ps-3 ds:pe-3 ds:py-2 ds:rounded-[var(--radius-sm)]',\n 'ds:cursor-pointer ds:select-none ds:text-foreground',\n 'ds:text-start',\n 'ds:data-[active=true]:bg-primary ds:data-[active=true]:text-primary-foreground',\n 'ds:hover:bg-muted ds:data-[active=true]:hover:bg-primary',\n ].join(' '),\n);\n\nconst messageClasses =\n 'ds:ps-3 ds:pe-3 ds:py-2 type-body-sm ds:text-muted-foreground';\n\n/* ------------------------------------------------------------------ */\n/* Inner: real Google Places engine. */\n/* */\n/* `useMapsLibrary(\"places\")` only resolves inside an APIProvider tree, */\n/* so this inner component is mounted by the outer wrapper only when an */\n/* apiKey is present and no mock injector is supplied. It owns no UI — */\n/* it renders the shared `<AddressCombobox>` with a `getSuggestions` / */\n/* `resolveSelection` pair wired to the loaded SDK. */\n/* ------------------------------------------------------------------ */\n\ninterface GoogleEngineProps extends Omit<AddressAutocompleteProps, 'apiKey'> {\n forwardedRef: ForwardedRef<HTMLInputElement>;\n}\n\nfunction GooglePlacesEngine({\n forwardedRef,\n regionCodes,\n onSelect,\n ...rest\n}: GoogleEngineProps): ReactNode {\n const places = useMapsLibrary('places');\n // A fresh session token groups the query + selection phases for billing.\n // Reset after each selection so the next lookup starts a new session.\n const sessionTokenRef =\n useRef<google.maps.places.AutocompleteSessionToken | null>(null);\n\n const supportsNewApi = Boolean(\n places &&\n 'AutocompleteSuggestion' in places &&\n 'Place' in places &&\n 'AutocompleteSessionToken' in places,\n );\n\n const getSuggestions = useCallback<GetSuggestions>(\n async (query) => {\n if (!places || query.trim().length === 0) return [];\n\n if (supportsNewApi) {\n if (!sessionTokenRef.current) {\n sessionTokenRef.current = new places.AutocompleteSessionToken();\n }\n const { suggestions } =\n await places.AutocompleteSuggestion.fetchAutocompleteSuggestions({\n input: query,\n sessionToken: sessionTokenRef.current,\n includedRegionCodes: regionCodes,\n });\n return suggestions\n .map((suggestion): AddressSuggestion | null => {\n const prediction = suggestion.placePrediction;\n if (!prediction) return null;\n return {\n placeId: prediction.placeId,\n primaryText: prediction.mainText?.text ?? prediction.text.text,\n secondaryText: prediction.secondaryText?.text,\n };\n })\n .filter((value): value is AddressSuggestion => value !== null);\n }\n\n // Classic fallback — AutocompleteService.getPlacePredictions.\n const ServiceCtor = (\n places as unknown as {\n AutocompleteService?: new () => google.maps.places.AutocompleteService;\n }\n ).AutocompleteService;\n if (!ServiceCtor) return [];\n const service = new ServiceCtor();\n const response = await service.getPlacePredictions({ input: query });\n return response.predictions.map((prediction) => ({\n placeId: prediction.place_id,\n primaryText:\n prediction.structured_formatting?.main_text ?? prediction.description,\n secondaryText: prediction.structured_formatting?.secondary_text,\n }));\n },\n [places, supportsNewApi, regionCodes],\n );\n\n const resolveSelection = useCallback(\n async (\n suggestion: AddressSuggestion,\n ): Promise<StructuredAddress | null> => {\n if (suggestion.address) return suggestion.address;\n if (!places) return null;\n\n if (supportsNewApi) {\n const place = new places.Place({ id: suggestion.placeId });\n const { place: filled } = await place.fetchFields({\n fields: ['addressComponents', 'formattedAddress'],\n });\n // End the billing session once details are fetched.\n sessionTokenRef.current = null;\n const components = (filled.addressComponents ??\n []) as unknown as RawAddressComponent[];\n return parseAddressComponents(\n components,\n filled.formattedAddress ?? '',\n );\n }\n\n // Classic fallback — PlacesService.getDetails. Requires a DOM node to\n // host the service (an offscreen div suffices; nothing is rendered).\n const ServiceCtor = (\n places as unknown as {\n PlacesService?: new (\n container: HTMLElement,\n ) => google.maps.places.PlacesService;\n }\n ).PlacesService;\n if (!ServiceCtor) return null;\n const service = new ServiceCtor(document.createElement('div'));\n return new Promise<StructuredAddress | null>((resolve) => {\n service.getDetails(\n {\n placeId: suggestion.placeId,\n fields: ['address_components', 'formatted_address'],\n },\n (result) => {\n if (!result) {\n resolve(null);\n return;\n }\n const components = (result.address_components ??\n []) as unknown as RawAddressComponent[];\n resolve(\n parseAddressComponents(\n components,\n result.formatted_address ?? '',\n ),\n );\n },\n );\n });\n },\n [places, supportsNewApi],\n );\n\n return (\n <AddressCombobox\n {...rest}\n forwardedRef={forwardedRef}\n getSuggestions={getSuggestions}\n resolveSelection={resolveSelection}\n onSelect={onSelect}\n />\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Inner: the accessible combobox itself. */\n/* */\n/* Implements the WAI-ARIA 1.2 combobox pattern (text input + listbox */\n/* popup, `aria-activedescendant`). Shared by mock mode, no-key mode, */\n/* and the Google engine — only the `getSuggestions` / `resolveSelection`*/\n/* pair differs. */\n/* ------------------------------------------------------------------ */\n\ninterface AddressComboboxProps extends Omit<\n AddressAutocompleteProps,\n 'apiKey' | 'getSuggestions'\n> {\n forwardedRef?: ForwardedRef<HTMLInputElement>;\n getSuggestions?: GetSuggestions;\n resolveSelection?: (\n suggestion: AddressSuggestion,\n ) => Promise<StructuredAddress | null>;\n}\n\nfunction AddressCombobox({\n forwardedRef,\n value,\n defaultValue,\n onValueChange,\n onSelect,\n getSuggestions,\n resolveSelection,\n placeholder,\n debounceMs = 250,\n disabled,\n required,\n readOnly,\n name,\n id,\n size = 'md',\n tone = 'default',\n className,\n 'aria-label': ariaLabel,\n}: AddressComboboxProps): ReactNode {\n const { t } = useTranslation();\n const ctx = useFormField();\n\n // Internal node ref — used for focus() after selection and for the\n // listbox-contains check on blur. Composed with the consumer's\n // forwardRef onto the rendered <input>.\n const inputRef = useRef<HTMLInputElement | null>(null);\n const setInputRef = useMemo(\n () => composeRefs(forwardedRef, inputRef),\n [forwardedRef],\n );\n\n const reactId = useId();\n const idPrefix = id ?? ctx.id ?? reactId;\n const listId = `${idPrefix}-listbox`;\n const liveId = `${idPrefix}-live`;\n const optionId = (placeId: string) => `${idPrefix}-opt-${placeId}`;\n\n const effectiveDisabled = Boolean(ctx.disabled || disabled);\n const effectiveRequired = Boolean(ctx.required || required);\n const effectiveInvalid = ctx.invalid;\n const effectiveTone: 'default' | 'error' = effectiveInvalid ? 'error' : tone;\n const describedBy = ctx.describedBy || undefined;\n\n const [currentValueRaw, commitValue] = useControllableState<string>({\n value,\n defaultValue: defaultValue ?? '',\n onChange: onValueChange,\n });\n const currentValue = currentValueRaw ?? '';\n\n const [open, setOpen] = useState(false);\n const [suggestions, setSuggestions] = useState<AddressSuggestion[]>([]);\n const [loading, setLoading] = useState(false);\n const [activeIndex, setActiveIndex] = useState(-1);\n\n const composingRef = useRef(false);\n const latestQueryRef = useRef('');\n\n const resolvedPlaceholder =\n placeholder ?? t('inputs.addressAutocomplete.placeholder');\n\n const runFetch = useCallback(\n (query: string) => {\n if (!getSuggestions || effectiveDisabled || readOnly) return;\n if (composingRef.current) return;\n latestQueryRef.current = query;\n setLoading(true);\n Promise.resolve(getSuggestions(query))\n .then((results) => {\n // Drop stale responses — only the latest query may render.\n if (latestQueryRef.current !== query) return;\n setSuggestions(results);\n setActiveIndex(-1);\n setLoading(false);\n })\n .catch(() => {\n if (latestQueryRef.current !== query) return;\n setSuggestions([]);\n setLoading(false);\n });\n },\n [getSuggestions, effectiveDisabled, readOnly],\n );\n\n const debouncedFetch = useDebouncedCallback(runFetch, debounceMs);\n\n useEffect(() => () => debouncedFetch.cancel(), [debouncedFetch]);\n\n const handleInputChange = (next: string) => {\n commitValue(next);\n if (effectiveDisabled || readOnly) return;\n if (!open) setOpen(true);\n if (composingRef.current) return;\n debouncedFetch(next);\n };\n\n const handleSelect = useCallback(\n (suggestion: AddressSuggestion) => {\n commitValue(suggestion.primaryText);\n setOpen(false);\n setActiveIndex(-1);\n setSuggestions([]);\n latestQueryRef.current = suggestion.primaryText;\n if (resolveSelection) {\n Promise.resolve(resolveSelection(suggestion))\n .then((address) => {\n if (address) onSelect?.(address);\n })\n .catch(() => {\n /* selection details failed — leave the typed text in place */\n });\n } else if (suggestion.address) {\n onSelect?.(suggestion.address);\n }\n inputRef.current?.focus();\n },\n [commitValue, resolveSelection, onSelect, inputRef],\n );\n\n // Whether the listbox popup is actually displayed (mirrors `aria-expanded`\n // on the input). Derived here — above the keyboard handler — so an expanded\n // listbox can swallow Enter instead of letting it submit a surrounding\n // <form>.\n const showEmpty =\n open &&\n !loading &&\n currentValue.trim().length > 0 &&\n suggestions.length === 0 &&\n Boolean(getSuggestions);\n const hasOptions = suggestions.length > 0;\n const listboxOpen = open && (hasOptions || showEmpty || loading);\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.nativeEvent.isComposing) return;\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n if (!open) {\n setOpen(true);\n if (currentValue) debouncedFetch(currentValue);\n return;\n }\n if (suggestions.length === 0) return;\n setActiveIndex((index) => (index + 1) % suggestions.length);\n return;\n }\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n if (suggestions.length === 0) return;\n setActiveIndex((index) =>\n index <= 0 ? suggestions.length - 1 : index - 1,\n );\n return;\n }\n if (event.key === 'Enter') {\n // While the listbox is expanded, swallow Enter so it never submits the\n // surrounding <form>. Accept the highlighted option if there is one;\n // otherwise keep the typed text (blur / Escape dismiss the listbox).\n if (listboxOpen) {\n event.preventDefault();\n if (activeIndex >= 0 && suggestions[activeIndex]) {\n handleSelect(suggestions[activeIndex]);\n }\n }\n return;\n }\n if (event.key === 'Escape') {\n if (open) {\n event.preventDefault();\n setOpen(false);\n setActiveIndex(-1);\n }\n }\n };\n\n const handleFocus = () => {\n if (effectiveDisabled || readOnly) return;\n if (currentValue) {\n setOpen(true);\n debouncedFetch(currentValue);\n }\n };\n\n const handleBlur = (event: FocusEvent<HTMLInputElement>) => {\n // Keep open when focus moves into the listbox (pointer-down on an option).\n const next = event.relatedTarget as Node | null;\n if (next && listRef.current?.contains(next)) return;\n setOpen(false);\n setActiveIndex(-1);\n };\n\n const listRef = useRef<HTMLUListElement | null>(null);\n\n const activeDescendant =\n open && activeIndex >= 0 && suggestions[activeIndex]\n ? optionId(suggestions[activeIndex].placeId)\n : undefined;\n\n const liveMessage = loading\n ? t('inputs.addressAutocomplete.loading')\n : open && currentValue.trim().length > 0\n ? t('inputs.addressAutocomplete.results', { count: suggestions.length })\n : '';\n\n return (\n <div\n className=\"ds:relative ds:w-full\"\n data-component=\"address-autocomplete\"\n data-component-id={id}\n >\n <div\n className={wrapperVariants({ size, tone: effectiveTone, className })}\n data-disabled={effectiveDisabled || undefined}\n >\n <span aria-hidden=\"true\" className={adornmentClasses}>\n <MapPin />\n </span>\n <input\n ref={setInputRef}\n id={idPrefix}\n name={name}\n type=\"text\"\n autoComplete=\"off\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={listboxOpen}\n aria-controls={listboxOpen ? listId : undefined}\n aria-activedescendant={activeDescendant}\n aria-describedby={describedBy}\n aria-invalid={effectiveInvalid || undefined}\n aria-label={ariaLabel ?? t('inputs.addressAutocomplete.ariaLabel')}\n placeholder={resolvedPlaceholder}\n value={currentValue}\n disabled={effectiveDisabled}\n required={effectiveRequired}\n readOnly={readOnly}\n onChange={(event) => handleInputChange(event.target.value)}\n onKeyDown={handleKeyDown}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onCompositionStart={() => {\n composingRef.current = true;\n }}\n onCompositionEnd={(event) => {\n composingRef.current = false;\n debouncedFetch(event.currentTarget.value);\n }}\n className={inputVariants()}\n />\n </div>\n {listboxOpen ? (\n <ul\n ref={listRef}\n id={listId}\n role=\"listbox\"\n aria-label={ariaLabel ?? t('inputs.addressAutocomplete.listLabel')}\n className={listboxVariants()}\n >\n {hasOptions\n ? suggestions.map((suggestion, index) => (\n <li\n key={suggestion.placeId}\n id={optionId(suggestion.placeId)}\n role=\"option\"\n aria-selected={index === activeIndex}\n data-active={index === activeIndex || undefined}\n // Pointer-down (not click) so selection runs before the\n // input's blur closes the listbox.\n onMouseDown={(event) => {\n event.preventDefault();\n handleSelect(suggestion);\n }}\n onMouseEnter={() => setActiveIndex(index)}\n className={optionVariants()}\n >\n <span className=\"ds:truncate\">{suggestion.primaryText}</span>\n {suggestion.secondaryText ? (\n <span className=\"type-meta ds:text-muted-foreground ds:data-[active=true]:text-primary-foreground ds:truncate\">\n {suggestion.secondaryText}\n </span>\n ) : null}\n </li>\n ))\n : null}\n {!hasOptions && loading ? (\n <li role=\"presentation\" className={messageClasses}>\n {t('inputs.addressAutocomplete.loading')}\n </li>\n ) : null}\n {!hasOptions && !loading && showEmpty ? (\n <li role=\"presentation\" className={messageClasses}>\n {t('inputs.addressAutocomplete.noResults')}\n </li>\n ) : null}\n </ul>\n ) : null}\n <span\n id={liveId}\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"ds:sr-only\"\n >\n {liveMessage}\n </span>\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Public component */\n/* ------------------------------------------------------------------ */\n\nexport const AddressAutocomplete = forwardRef<\n HTMLInputElement,\n AddressAutocompleteProps\n>(function AddressAutocomplete({ apiKey, getSuggestions, ...rest }, ref) {\n const { i18n } = useTranslation();\n\n // MOCK mode wins whenever a `getSuggestions` injector is supplied — even if\n // an apiKey is also present — so stories/tests stay deterministic and never\n // hit the network. The mock injector already carries pre-parsed addresses,\n // so selection resolves straight from the suggestion.\n if (getSuggestions) {\n return (\n <AddressCombobox\n {...rest}\n forwardedRef={ref}\n getSuggestions={getSuggestions}\n resolveSelection={resolveMockSelection}\n />\n );\n }\n\n // NO-KEY fallback — plain free-text input, no suggestions, never fails.\n if (!apiKey) {\n return <AddressCombobox {...rest} forwardedRef={ref} />;\n }\n\n return (\n <APIProvider apiKey={apiKey} language={i18n.language}>\n <GooglePlacesEngine {...rest} forwardedRef={ref} />\n </APIProvider>\n );\n});\nAddressAutocomplete.displayName = 'AddressAutocomplete';\n\n// Module-scoped so the mock branch passes a stable function identity.\nasync function resolveMockSelection(\n suggestion: AddressSuggestion,\n): Promise<StructuredAddress | null> {\n return suggestion.address ?? null;\n}\n"],"names":["longTextOf","component","shortTextOf","findByType","components","type","parseAddressComponents","formatted","route","streetNumber","locality","postalTown","adminLevel3","postalCode","adminLevel2","country","routeText","numberText","street","cityComponent","city","postcode","province","countryCode","wrapperVariants","cva","INPUT_SURFACE_CHROME","INPUT_SURFACE_HEIGHT","INPUT_SURFACE_TEXT","INPUT_SURFACE_TONE","inputVariants","adornmentClasses","listboxVariants","optionVariants","messageClasses","GooglePlacesEngine","forwardedRef","regionCodes","onSelect","rest","places","useMapsLibrary","sessionTokenRef","useRef","supportsNewApi","getSuggestions","useCallback","query","suggestions","suggestion","prediction","_a","_b","value","ServiceCtor","resolveSelection","place","filled","service","resolve","result","jsx","AddressCombobox","defaultValue","onValueChange","placeholder","debounceMs","disabled","required","readOnly","name","id","size","tone","className","ariaLabel","t","useTranslation","ctx","useFormField","inputRef","setInputRef","useMemo","composeRefs","reactId","useId","idPrefix","listId","liveId","optionId","placeId","effectiveDisabled","effectiveRequired","effectiveInvalid","effectiveTone","describedBy","currentValueRaw","commitValue","useControllableState","currentValue","open","setOpen","useState","setSuggestions","loading","setLoading","activeIndex","setActiveIndex","composingRef","latestQueryRef","resolvedPlaceholder","runFetch","results","debouncedFetch","useDebouncedCallback","useEffect","handleInputChange","next","handleSelect","address","showEmpty","hasOptions","listboxOpen","handleKeyDown","event","index","handleFocus","handleBlur","listRef","activeDescendant","liveMessage","jsxs","MapPin","AddressAutocomplete","forwardRef","apiKey","ref","i18n","resolveMockSelection","APIProvider"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { jsxs as r, jsx as n } from "react/jsx-runtime";
|
|
|
2
2
|
import { forwardRef as N, useState as k, useRef as q, useMemo as I } from "react";
|
|
3
3
|
import { c as L } from "./index-D2ZczOXr.js";
|
|
4
4
|
import { useTranslation as R } from "react-i18next";
|
|
5
|
-
import { A as d } from "./alert-
|
|
5
|
+
import { A as d } from "./alert-CUTxnym2.js";
|
|
6
6
|
import { B as w } from "./badge-zsf5i5bH.js";
|
|
7
7
|
import { B as T } from "./button-DD_0Xdmr.js";
|
|
8
8
|
import { C as V } from "./checkbox-DRcOdmXv.js";
|
|
@@ -166,4 +166,4 @@ export {
|
|
|
166
166
|
P as A,
|
|
167
167
|
K as a
|
|
168
168
|
};
|
|
169
|
-
//# sourceMappingURL=ai-consent-banner-
|
|
169
|
+
//# sourceMappingURL=ai-consent-banner-F2md5JD3.js.map
|
package/dist/_chunks/{ai-consent-banner-DO5ingMq.js.map → ai-consent-banner-F2md5JD3.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-consent-banner-DO5ingMq.js","sources":["../../src/components/ai-consent-banner/ai-consent-banner.agent.ts","../../src/components/ai-consent-banner/ai-consent-banner.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — AiConsentBanner. */\n/* */\n/* Read-only structural surface: the current consent state and whether */\n/* the grant affordance is armed. Identifiers / structural state ONLY — */\n/* never the grantee's name or any PHI. The real consent gate lives */\n/* server-side; this adapter does not expose a grant action so an agent */\n/* cannot consent on a user's behalf. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { AiConsentBannerHandle } from './ai-consent-banner';\n\nexport const aiConsentBannerAgent: AgentAdapter<AiConsentBannerHandle> = {\n id: 'ai-consent-banner',\n capabilities: [],\n state: {\n consentState: {\n type: \"'granted' | 'required' | 'pending'\",\n descriptionKey: 'ui.agent.aiConsentBanner.state.consentState',\n description:\n 'Current consent state. Structural only — never the grantee identity.',\n read: (handle) => handle.getState(),\n },\n armed: {\n type: 'boolean',\n descriptionKey: 'ui.agent.aiConsentBanner.state.armed',\n description:\n 'Whether the consent confirmation checkbox is ticked (required state only).',\n read: (handle) => handle.isArmed(),\n },\n },\n actions: {},\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'ai-consent-banner',\n description: 'Marks the AiConsentBanner root region.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the id prop. Required to address a specific banner from the agent.',\n },\n },\n};\n","import {\n forwardRef,\n useMemo,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Alert } from '../alert/alert';\nimport { Badge } from '../badge/badge';\nimport { Button } from '../button/button';\nimport { Checkbox } from '../checkbox/checkbox';\nimport { Spinner } from '../spinner/spinner';\nimport { Timestamp } from '../timestamp/timestamp';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { aiConsentBannerAgent } from './ai-consent-banner.agent';\n\n/* -------------------------------------------------------------------- */\n/* AiConsentBanner */\n/* */\n/* Presentational AI-consent gate surfaced above an AI-assisted surface */\n/* (e.g. Alfascribe consultation transcription). The SERVER owns the */\n/* real gate — this component only reflects the consent record and lets */\n/* the operator initiate a grant; it never enforces access itself. */\n/* */\n/* Three states drive the Alert variant + body: */\n/* - granted → success Alert with a Badge + when/who it was granted. */\n/* - required → info Alert with a Checkbox-gated Grant Button. */\n/* - pending → info Alert in a disabled, Spinner-busy state while the */\n/* server persists the grant. */\n/* */\n/* All visible text flows through useTranslation('ui') against the */\n/* `aiConsentBanner.*` namespace. */\n/* -------------------------------------------------------------------- */\n\n/* -------------------------------------------------------------------- */\n/* CVA — root */\n/* -------------------------------------------------------------------- */\n\nconst rootVariants = cva('ds:w-full ds:text-[color:var(--foreground)]', {\n variants: {\n state: {\n granted: '',\n required: '',\n pending: '',\n },\n },\n defaultVariants: {\n state: 'required',\n },\n});\n\n/* -------------------------------------------------------------------- */\n/* State derivation */\n/* -------------------------------------------------------------------- */\n\nexport type AiConsentState = NonNullable<\n VariantProps<typeof rootVariants>['state']\n>;\n\n/** Pending wins over granted/required so the busy state is never masked. */\nfunction deriveState(granted: boolean, pending: boolean): AiConsentState {\n if (pending) return 'pending';\n return granted ? 'granted' : 'required';\n}\n\n/* -------------------------------------------------------------------- */\n/* Public types */\n/* -------------------------------------------------------------------- */\n\n/** Agent-readiness curated handle. Exposes the structural consent state only. */\nexport interface AiConsentBannerHandle {\n /** Current derived state: 'granted' | 'required' | 'pending'. */\n getState: () => AiConsentState;\n /** Whether the Grant affordance is currently armed (checkbox ticked). */\n isArmed: () => boolean;\n}\n\nexport interface AiConsentBannerProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'aria-label' | 'children' | 'role'\n> {\n /**\n * Stable instance id. Surfaced on the root as `data-component-id` so an\n * agent / MCP UI bridge can address this specific banner. Mirrored to the\n * real DOM `id`.\n */\n id?: string;\n /** Whether consent has already been granted. Server-sourced. */\n granted: boolean;\n /**\n * When consent was granted — ISO-8601 string, ms-epoch, or Date. Rendered\n * via `Timestamp` in the granted state.\n */\n grantedAt?: string | number | Date;\n /** Who granted consent (operator display name / role). Granted state only. */\n grantedBy?: string;\n /**\n * Whether the current user is allowed to grant consent. When `false`, the\n * required-state Grant affordance is hidden and a not-allowed note shows.\n * Default `true`.\n */\n canGrant?: boolean;\n /** The grant is being persisted server-side — shows the busy Spinner state. */\n pending?: boolean;\n /** Fired when the operator confirms the consent grant. */\n onGrantConsent?: () => void;\n /** Override the region's accessible name. */\n 'aria-label'?: string;\n}\n\n/* -------------------------------------------------------------------- */\n/* Component */\n/* -------------------------------------------------------------------- */\n\nexport const AiConsentBanner = forwardRef<HTMLDivElement, AiConsentBannerProps>(\n (\n {\n id,\n granted,\n grantedAt,\n grantedBy,\n canGrant = true,\n pending = false,\n onGrantConsent,\n 'aria-label': ariaLabel,\n className,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation();\n const state = deriveState(granted, pending);\n\n // Local arm switch — the required state gates the Grant Button behind an\n // explicit \"I understand\" checkbox so consent is never one mis-click away.\n const [armed, setArmed] = useState(false);\n\n const armedRef = useRef(armed);\n armedRef.current = armed;\n\n const handle = useMemo<AiConsentBannerHandle>(\n () => ({\n getState: () => deriveState(granted, pending),\n isArmed: () => armedRef.current,\n }),\n [granted, pending],\n );\n useAgentRegistration(aiConsentBannerAgent, handle, id);\n\n const resolvedAriaLabel =\n ariaLabel ?? t('aiConsentBanner.regionLabel', 'AI assistance consent');\n\n // Alert variant per state: granted → success, required/pending → info.\n const alertVariant = state === 'granted' ? 'success' : 'info';\n\n let body: React.ReactNode;\n if (state === 'granted') {\n body = (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]\">\n <Badge variant=\"success\">\n {t('aiConsentBanner.badge.granted', 'Consent granted')}\n </Badge>\n {grantedAt !== undefined ? (\n <span className=\"type-body-sm ds:text-[color:var(--muted-foreground)]\">\n {t('aiConsentBanner.grantedAtPrefix', 'Granted')}{' '}\n <Timestamp value={grantedAt} format=\"relative\" shape=\"inline\" />\n </span>\n ) : null}\n </div>\n {grantedBy ? (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('aiConsentBanner.grantedBy', {\n name: grantedBy,\n defaultValue: 'By {{name}}',\n })}\n </p>\n ) : null}\n </div>\n );\n } else if (state === 'pending') {\n body = (\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n <Spinner\n size=\"sm\"\n label={t('aiConsentBanner.pendingLabel', 'Saving consent…')}\n />\n <span className=\"type-body-sm ds:text-[color:var(--muted-foreground)]\">\n {t('aiConsentBanner.pendingLabel', 'Saving consent…')}\n </span>\n </div>\n );\n } else {\n // required\n body = canGrant ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <Checkbox\n checked={armed}\n onCheckedChange={(next) => setArmed(next === true)}\n label={t(\n 'aiConsentBanner.confirmLabel',\n 'I confirm consent has been obtained for AI assistance.',\n )}\n />\n <Alert.Action>\n <Button\n intent=\"primary\"\n size=\"sm\"\n disabled={!armed}\n onClick={onGrantConsent}\n >\n {t('aiConsentBanner.grantButton', 'Grant consent')}\n </Button>\n </Alert.Action>\n </div>\n ) : (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t(\n 'aiConsentBanner.notAllowed',\n 'You do not have permission to grant AI assistance consent.',\n )}\n </p>\n );\n }\n\n return (\n <div\n ref={ref}\n role=\"region\"\n aria-label={resolvedAriaLabel}\n aria-busy={state === 'pending' ? true : undefined}\n data-component=\"ai-consent-banner\"\n data-component-id={id}\n data-state={state}\n id={id}\n className={rootVariants({ state, className })}\n {...rest}\n >\n <Alert\n variant={alertVariant}\n icon={state === 'pending' ? null : undefined}\n >\n <Alert.Title>\n {t('aiConsentBanner.title', 'AI assistance consent')}\n </Alert.Title>\n <Alert.Description>\n {state === 'granted'\n ? t(\n 'aiConsentBanner.description.granted',\n 'AI assistance is enabled for this record.',\n )\n : t(\n 'aiConsentBanner.description.required',\n 'AI assistance requires recorded consent before it can run.',\n )}\n </Alert.Description>\n {body}\n </Alert>\n </div>\n );\n },\n);\n\nAiConsentBanner.displayName = 'AiConsentBanner';\n"],"names":["aiConsentBannerAgent","handle","rootVariants","cva","deriveState","granted","pending","AiConsentBanner","forwardRef","id","grantedAt","grantedBy","canGrant","onGrantConsent","ariaLabel","className","rest","ref","t","useTranslation","state","armed","setArmed","useState","armedRef","useRef","useMemo","useAgentRegistration","resolvedAriaLabel","alertVariant","body","jsxs","jsx","Badge","Timestamp","Spinner","Checkbox","next","Alert","Button"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ai-consent-banner-F2md5JD3.js","sources":["../../src/components/ai-consent-banner/ai-consent-banner.agent.ts","../../src/components/ai-consent-banner/ai-consent-banner.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — AiConsentBanner. */\n/* */\n/* Read-only structural surface: the current consent state and whether */\n/* the grant affordance is armed. Identifiers / structural state ONLY — */\n/* never the grantee's name or any PHI. The real consent gate lives */\n/* server-side; this adapter does not expose a grant action so an agent */\n/* cannot consent on a user's behalf. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { AiConsentBannerHandle } from './ai-consent-banner';\n\nexport const aiConsentBannerAgent: AgentAdapter<AiConsentBannerHandle> = {\n id: 'ai-consent-banner',\n capabilities: [],\n state: {\n consentState: {\n type: \"'granted' | 'required' | 'pending'\",\n descriptionKey: 'ui.agent.aiConsentBanner.state.consentState',\n description:\n 'Current consent state. Structural only — never the grantee identity.',\n read: (handle) => handle.getState(),\n },\n armed: {\n type: 'boolean',\n descriptionKey: 'ui.agent.aiConsentBanner.state.armed',\n description:\n 'Whether the consent confirmation checkbox is ticked (required state only).',\n read: (handle) => handle.isArmed(),\n },\n },\n actions: {},\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'ai-consent-banner',\n description: 'Marks the AiConsentBanner root region.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the id prop. Required to address a specific banner from the agent.',\n },\n },\n};\n","import {\n forwardRef,\n useMemo,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Alert } from '../alert/alert';\nimport { Badge } from '../badge/badge';\nimport { Button } from '../button/button';\nimport { Checkbox } from '../checkbox/checkbox';\nimport { Spinner } from '../spinner/spinner';\nimport { Timestamp } from '../timestamp/timestamp';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { aiConsentBannerAgent } from './ai-consent-banner.agent';\n\n/* -------------------------------------------------------------------- */\n/* AiConsentBanner */\n/* */\n/* Presentational AI-consent gate surfaced above an AI-assisted surface */\n/* (e.g. Alfascribe consultation transcription). The SERVER owns the */\n/* real gate — this component only reflects the consent record and lets */\n/* the operator initiate a grant; it never enforces access itself. */\n/* */\n/* Three states drive the Alert variant + body: */\n/* - granted → success Alert with a Badge + when/who it was granted. */\n/* - required → info Alert with a Checkbox-gated Grant Button. */\n/* - pending → info Alert in a disabled, Spinner-busy state while the */\n/* server persists the grant. */\n/* */\n/* All visible text flows through useTranslation('ui') against the */\n/* `aiConsentBanner.*` namespace. */\n/* -------------------------------------------------------------------- */\n\n/* -------------------------------------------------------------------- */\n/* CVA — root */\n/* -------------------------------------------------------------------- */\n\nconst rootVariants = cva('ds:w-full ds:text-[color:var(--foreground)]', {\n variants: {\n state: {\n granted: '',\n required: '',\n pending: '',\n },\n },\n defaultVariants: {\n state: 'required',\n },\n});\n\n/* -------------------------------------------------------------------- */\n/* State derivation */\n/* -------------------------------------------------------------------- */\n\nexport type AiConsentState = NonNullable<\n VariantProps<typeof rootVariants>['state']\n>;\n\n/** Pending wins over granted/required so the busy state is never masked. */\nfunction deriveState(granted: boolean, pending: boolean): AiConsentState {\n if (pending) return 'pending';\n return granted ? 'granted' : 'required';\n}\n\n/* -------------------------------------------------------------------- */\n/* Public types */\n/* -------------------------------------------------------------------- */\n\n/** Agent-readiness curated handle. Exposes the structural consent state only. */\nexport interface AiConsentBannerHandle {\n /** Current derived state: 'granted' | 'required' | 'pending'. */\n getState: () => AiConsentState;\n /** Whether the Grant affordance is currently armed (checkbox ticked). */\n isArmed: () => boolean;\n}\n\nexport interface AiConsentBannerProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'aria-label' | 'children' | 'role'\n> {\n /**\n * Stable instance id. Surfaced on the root as `data-component-id` so an\n * agent / MCP UI bridge can address this specific banner. Mirrored to the\n * real DOM `id`.\n */\n id?: string;\n /** Whether consent has already been granted. Server-sourced. */\n granted: boolean;\n /**\n * When consent was granted — ISO-8601 string, ms-epoch, or Date. Rendered\n * via `Timestamp` in the granted state.\n */\n grantedAt?: string | number | Date;\n /** Who granted consent (operator display name / role). Granted state only. */\n grantedBy?: string;\n /**\n * Whether the current user is allowed to grant consent. When `false`, the\n * required-state Grant affordance is hidden and a not-allowed note shows.\n * Default `true`.\n */\n canGrant?: boolean;\n /** The grant is being persisted server-side — shows the busy Spinner state. */\n pending?: boolean;\n /** Fired when the operator confirms the consent grant. */\n onGrantConsent?: () => void;\n /** Override the region's accessible name. */\n 'aria-label'?: string;\n}\n\n/* -------------------------------------------------------------------- */\n/* Component */\n/* -------------------------------------------------------------------- */\n\nexport const AiConsentBanner = forwardRef<HTMLDivElement, AiConsentBannerProps>(\n (\n {\n id,\n granted,\n grantedAt,\n grantedBy,\n canGrant = true,\n pending = false,\n onGrantConsent,\n 'aria-label': ariaLabel,\n className,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation();\n const state = deriveState(granted, pending);\n\n // Local arm switch — the required state gates the Grant Button behind an\n // explicit \"I understand\" checkbox so consent is never one mis-click away.\n const [armed, setArmed] = useState(false);\n\n const armedRef = useRef(armed);\n armedRef.current = armed;\n\n const handle = useMemo<AiConsentBannerHandle>(\n () => ({\n getState: () => deriveState(granted, pending),\n isArmed: () => armedRef.current,\n }),\n [granted, pending],\n );\n useAgentRegistration(aiConsentBannerAgent, handle, id);\n\n const resolvedAriaLabel =\n ariaLabel ?? t('aiConsentBanner.regionLabel', 'AI assistance consent');\n\n // Alert variant per state: granted → success, required/pending → info.\n const alertVariant = state === 'granted' ? 'success' : 'info';\n\n let body: React.ReactNode;\n if (state === 'granted') {\n body = (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]\">\n <Badge variant=\"success\">\n {t('aiConsentBanner.badge.granted', 'Consent granted')}\n </Badge>\n {grantedAt !== undefined ? (\n <span className=\"type-body-sm ds:text-[color:var(--muted-foreground)]\">\n {t('aiConsentBanner.grantedAtPrefix', 'Granted')}{' '}\n <Timestamp value={grantedAt} format=\"relative\" shape=\"inline\" />\n </span>\n ) : null}\n </div>\n {grantedBy ? (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t('aiConsentBanner.grantedBy', {\n name: grantedBy,\n defaultValue: 'By {{name}}',\n })}\n </p>\n ) : null}\n </div>\n );\n } else if (state === 'pending') {\n body = (\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n <Spinner\n size=\"sm\"\n label={t('aiConsentBanner.pendingLabel', 'Saving consent…')}\n />\n <span className=\"type-body-sm ds:text-[color:var(--muted-foreground)]\">\n {t('aiConsentBanner.pendingLabel', 'Saving consent…')}\n </span>\n </div>\n );\n } else {\n // required\n body = canGrant ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <Checkbox\n checked={armed}\n onCheckedChange={(next) => setArmed(next === true)}\n label={t(\n 'aiConsentBanner.confirmLabel',\n 'I confirm consent has been obtained for AI assistance.',\n )}\n />\n <Alert.Action>\n <Button\n intent=\"primary\"\n size=\"sm\"\n disabled={!armed}\n onClick={onGrantConsent}\n >\n {t('aiConsentBanner.grantButton', 'Grant consent')}\n </Button>\n </Alert.Action>\n </div>\n ) : (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t(\n 'aiConsentBanner.notAllowed',\n 'You do not have permission to grant AI assistance consent.',\n )}\n </p>\n );\n }\n\n return (\n <div\n ref={ref}\n role=\"region\"\n aria-label={resolvedAriaLabel}\n aria-busy={state === 'pending' ? true : undefined}\n data-component=\"ai-consent-banner\"\n data-component-id={id}\n data-state={state}\n id={id}\n className={rootVariants({ state, className })}\n {...rest}\n >\n <Alert\n variant={alertVariant}\n icon={state === 'pending' ? null : undefined}\n >\n <Alert.Title>\n {t('aiConsentBanner.title', 'AI assistance consent')}\n </Alert.Title>\n <Alert.Description>\n {state === 'granted'\n ? t(\n 'aiConsentBanner.description.granted',\n 'AI assistance is enabled for this record.',\n )\n : t(\n 'aiConsentBanner.description.required',\n 'AI assistance requires recorded consent before it can run.',\n )}\n </Alert.Description>\n {body}\n </Alert>\n </div>\n );\n },\n);\n\nAiConsentBanner.displayName = 'AiConsentBanner';\n"],"names":["aiConsentBannerAgent","handle","rootVariants","cva","deriveState","granted","pending","AiConsentBanner","forwardRef","id","grantedAt","grantedBy","canGrant","onGrantConsent","ariaLabel","className","rest","ref","t","useTranslation","state","armed","setArmed","useState","armedRef","useRef","useMemo","useAgentRegistration","resolvedAriaLabel","alertVariant","body","jsxs","jsx","Badge","Timestamp","Spinner","Checkbox","next","Alert","Button"],"mappings":"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"}
|
|
@@ -63,7 +63,7 @@ const te = {
|
|
|
63
63
|
description: "Stable tool id emitted on each strip IconButton. The active icon also carries data-active set to its id."
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
}, se = "ds:[inline-size:3rem]", ne = "ds:[inline-size:22rem]", ie = b(
|
|
66
|
+
}, se = "ds:[inline-size:3rem]", ne = "ds:[inline-size:var(--ai-tools-rail-panel-inline-size,22rem)]", ie = b(
|
|
67
67
|
["ds:flex ds:shrink-0 ds:h-full", "ds:bg-[var(--background)]"].join(" "),
|
|
68
68
|
{
|
|
69
69
|
variants: {
|
|
@@ -115,8 +115,8 @@ const ce = M(
|
|
|
115
115
|
defaultActiveToolId: L = null,
|
|
116
116
|
onActiveToolChange: B,
|
|
117
117
|
side: R = "end",
|
|
118
|
-
railLabel:
|
|
119
|
-
className:
|
|
118
|
+
railLabel: z,
|
|
119
|
+
className: H
|
|
120
120
|
}, _) => {
|
|
121
121
|
var E;
|
|
122
122
|
const { t: m } = Q(), [F, l] = $({
|
|
@@ -196,7 +196,7 @@ const ce = M(
|
|
|
196
196
|
"data-component": "ai-tools-rail",
|
|
197
197
|
"data-component-id": n,
|
|
198
198
|
"data-side": R,
|
|
199
|
-
className: [ie({ side: R }),
|
|
199
|
+
className: [ie({ side: R }), H].filter(Boolean).join(" "),
|
|
200
200
|
children: [
|
|
201
201
|
p ? /* @__PURE__ */ f(
|
|
202
202
|
"aside",
|
|
@@ -220,7 +220,7 @@ const ce = M(
|
|
|
220
220
|
{
|
|
221
221
|
role: "toolbar",
|
|
222
222
|
"aria-orientation": "vertical",
|
|
223
|
-
"aria-label":
|
|
223
|
+
"aria-label": z ?? m("aiToolsRail.railLabel", { defaultValue: "AI tools" }),
|
|
224
224
|
className: oe(),
|
|
225
225
|
onKeyDown: W,
|
|
226
226
|
children: a.map((e, t) => {
|
|
@@ -277,4 +277,4 @@ export {
|
|
|
277
277
|
ce as A,
|
|
278
278
|
te as a
|
|
279
279
|
};
|
|
280
|
-
//# sourceMappingURL=ai-tools-rail-
|
|
280
|
+
//# sourceMappingURL=ai-tools-rail-CYLWrRmm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-tools-rail-CYLWrRmm.js","sources":["../../src/components/ai-tools-rail/ai-tools-rail.agent.ts","../../src/components/ai-tools-rail/ai-tools-rail.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — AiToolsRail. */\n/* */\n/* Rail-level surface: open / close a tool's panel and read which tool */\n/* is active. State is strictly the active tool id — never any tool's */\n/* panel CONTENT (which may carry PHI). Tool ids + badge counts are */\n/* supplied by the host via props, not derived from panel bodies. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { AiToolsRailHandle } from './ai-tools-rail';\n\nexport const aiToolsRailAgent: AgentAdapter<AiToolsRailHandle> = {\n id: 'ai-tools-rail',\n capabilities: ['open', 'close', 'select_single'],\n state: {\n activeToolId: {\n type: 'string | null',\n descriptionKey: 'ui.aiToolsRail.agent.state.activeToolId',\n description:\n 'Id of the tool whose panel is currently open, or null when the rail is collapsed to its strip. No panel content is ever exposed.',\n read: (handle) => handle.getActiveToolId(),\n },\n },\n actions: {\n open: {\n safety: 'read',\n argsType: '{ id: string }',\n descriptionKey: 'ui.aiToolsRail.agent.actions.open',\n description: \"Open the given tool's panel.\",\n invoke: (handle, args: { id: string }) => {\n handle.open(args.id);\n },\n },\n close: {\n safety: 'read',\n descriptionKey: 'ui.aiToolsRail.agent.actions.close',\n description: 'Collapse the rail to its strip (no active tool).',\n invoke: (handle) => {\n handle.close();\n },\n },\n select_tool: {\n safety: 'read',\n argsType: '{ id: string | null }',\n descriptionKey: 'ui.aiToolsRail.agent.actions.selectTool',\n description:\n 'Set the active tool by id (opens its panel), or pass null to collapse.',\n invoke: (handle, args: { id: string | null }) => {\n handle.setActiveTool(args.id);\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'ai-tools-rail',\n description: 'Marks the AiToolsRail wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the id prop. Required to address a specific rail from the agent.',\n },\n item: {\n attr: 'data-tool-id',\n description:\n 'Stable tool id emitted on each strip IconButton. The active icon also carries data-active set to its id.',\n },\n },\n};\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { IconButton } from '../button/icon-button';\nimport { ScrollArea } from '../scroll-area/scroll-area';\nimport { TooltipProvider } from '../tooltip/tooltip';\nimport { useControllableState } from '../../hooks/use-controllable-state';\nimport { useIsomorphicLayoutEffect } from '../../hooks/use-isomorphic-layout-effect';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { aiToolsRailAgent } from './ai-tools-rail.agent';\n\n/* ------------------------------------------------------------------ */\n/* Tokenised widths */\n/* */\n/* Fixed + tokenised so the rail stays constraint-compliant — no */\n/* prop-driven inline styles. Bare `[inline-size:…]` is NOT a */\n/* recognised utility under the `ds:` prefix; it must carry the */\n/* prefix or Tailwind emits no rule. Consumers needing a different */\n/* size wrap the rail and override via CSS. */\n/* ------------------------------------------------------------------ */\nconst RAIL_WIDTH = 'ds:[inline-size:3rem]';\n// Panel width rides a consumer-overridable custom property (set\n// `--ai-tools-rail-panel-inline-size` on the rail or a wrapper) so\n// content-heavy tools (e.g. an inbox feed) can widen their panel\n// without inline styles. Defaults to the 22rem tray-family width.\nconst PANEL_WIDTH =\n 'ds:[inline-size:var(--ai-tools-rail-panel-inline-size,22rem)]';\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport interface AiToolsRailTool {\n /** Stable tool id — used in `data-active`, the imperative handle, and\n * to label the open panel region. */\n id: string;\n /** Accessible name for the strip icon + tooltip, and the open panel's\n * region label. Never rendered as visible body text. */\n label: string;\n /** lucide-react glyph (rendered `aria-hidden` inside the IconButton). */\n icon: ReactNode;\n /** Panel body for this tool. Rendered inline-start of the strip when\n * `side='end'` (mirrored for `'start'`). The consumer composes it. */\n panel: ReactNode;\n /** Optional unseen / notification count shown on the strip icon. */\n badgeCount?: number;\n /** When true the icon is non-interactive and skipped by roving focus. */\n disabled?: boolean;\n}\n\n/**\n * Curated imperative handle for AiToolsRail. Exposed as the forwardRef\n * target so a future agent / MCP UI bridge can drive the rail without\n * touching the DOM. See `ai-tools-rail.agent.ts`.\n *\n * State surfaced here is strictly identifiers + counts — never any\n * tool's panel content (which may carry PHI).\n */\nexport interface AiToolsRailHandle {\n /** Currently-active tool id, or null when collapsed to strip-only. */\n getActiveToolId: () => string | null;\n /** Activate a tool by id (opens its panel), or null to collapse. */\n setActiveTool: (id: string | null) => void;\n /** Activate a tool by id (opens its panel). */\n open: (id: string) => void;\n /** Collapse to strip-only (no active tool). */\n close: () => void;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA — `side` drives the dock edge + which shadow faces main content */\n/* ------------------------------------------------------------------ */\n\nconst railVariants = cva(\n ['ds:flex ds:shrink-0 ds:h-full', 'ds:bg-[var(--background)]'].join(' '),\n {\n variants: {\n side: {\n // Strip docks inline-end; the panel mounts inline-start of it\n // (flex-row, panel rendered first). Shadow faces the main area.\n end: 'ds:flex-row ds:shadow-[var(--shadow-chrome-start)]',\n // Strip docks inline-start; the panel mounts inline-end of it.\n start: 'ds:flex-row-reverse ds:shadow-[var(--shadow-chrome-end)]',\n },\n },\n defaultVariants: { side: 'end' },\n },\n);\n\nconst stripVariants = cva(\n [\n 'ds:flex ds:shrink-0 ds:flex-col ds:items-center',\n 'ds:pt-[var(--spacing-md)] ds:pb-[var(--spacing-md)]',\n 'ds:gap-[var(--spacing-xs)]',\n RAIL_WIDTH,\n ].join(' '),\n);\n\nconst panelVariants = cva(\n [\n 'ds:flex ds:min-h-0 ds:flex-col ds:h-full',\n 'ds:bg-[var(--background)]',\n PANEL_WIDTH,\n ].join(' '),\n);\n\n// Hand-rolled overlay count chip — mirrors the AliaSidebar / MessageTray\n// badge markup. A <Badge> would re-introduce its own landmark/role; the\n// strip icon already carries the count in its accessible name, so this\n// span is purely decorative (`aria-hidden`).\nconst badgeVariants = cva(\n [\n 'ds:absolute ds:-top-[var(--spacing-xs)] ds:-end-[var(--spacing-xs)]',\n 'ds:inline-flex ds:items-center ds:justify-center',\n 'ds:min-w-[calc(var(--spacing-md)+var(--spacing-xs))]',\n 'ds:h-[calc(var(--spacing-md)+var(--spacing-xs))]',\n 'ds:ps-[calc(var(--spacing-xs)/1.5)] ds:pe-[calc(var(--spacing-xs)/1.5)]',\n 'ds:rounded-[var(--radius-full)]',\n 'ds:bg-[color:var(--destructive)] ds:text-[color:var(--destructive-foreground)]',\n 'ds:text-[length:var(--font-size-xs)] ds:font-semibold ds:leading-none',\n 'ds:pointer-events-none ds:select-none',\n 'ds:forced-colors:outline ds:forced-colors:outline-1 ds:forced-colors:outline-[CanvasText]',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Props */\n/* ------------------------------------------------------------------ */\n\nexport interface AiToolsRailProps extends VariantProps<typeof railVariants> {\n /** Stable instance id, surfaced on the root as `data-component-id`. */\n id?: string;\n /** The tools shown as icons on the strip. */\n tools: AiToolsRailTool[];\n /** Controlled active tool id (null = collapsed / strip-only). */\n activeToolId?: string | null;\n /** Uncontrolled initial active tool id (default null). */\n defaultActiveToolId?: string | null;\n /** Fires whenever the active tool changes (incl. → null on collapse). */\n onActiveToolChange?: (id: string | null) => void;\n /** Which edge the rail docks to. Default `'end'` (inline-end). */\n side?: 'start' | 'end';\n /** Accessible label for the toolbar strip. */\n railLabel?: string;\n className?: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nfunction formatBadgeCount(count: number, overflowLabel: string): string {\n return count > 99 ? overflowLabel : String(count);\n}\n\n/* ------------------------------------------------------------------ */\n/* Root */\n/* ------------------------------------------------------------------ */\n\nexport const AiToolsRail = forwardRef<AiToolsRailHandle, AiToolsRailProps>(\n (\n {\n id,\n tools,\n activeToolId,\n defaultActiveToolId = null,\n onActiveToolChange,\n side = 'end',\n railLabel,\n className,\n },\n ref,\n ) => {\n const { t } = useTranslation();\n\n // Controlled / uncontrolled bridge — the same hook MessageTray uses.\n const [activeRaw, setActiveRaw] = useControllableState<string | null>({\n value: activeToolId,\n defaultValue: defaultActiveToolId,\n onChange: onActiveToolChange,\n });\n const activeId = activeRaw ?? null;\n\n // Roving-tabindex bookkeeping for the vertical toolbar strip.\n const buttonsRef = useRef<Array<HTMLButtonElement | null>>([]);\n const panelRef = useRef<HTMLElement | null>(null);\n const [focusIndex, setFocusIndex] = useState(0);\n // Distinguishes keyboard activation (auto-focus into the panel) from\n // pointer activation (focus stays on the icon — less jarring).\n const activatedByKeyboardRef = useRef(false);\n // Set on Enter/Space keydown, read by the click handler that follows,\n // cleared on keyup — so a subsequent mouse click never inherits it.\n const keyboardActivateRef = useRef(false);\n\n const activeIndex = useMemo(\n () => tools.findIndex((tl) => tl.id === activeId),\n [tools, activeId],\n );\n const activeTool = activeIndex >= 0 ? tools[activeIndex] : null;\n\n // First non-disabled index — the resting roving stop when none active.\n const firstEnabledIndex = useMemo(\n () => tools.findIndex((tl) => !tl.disabled),\n [tools],\n );\n\n // The roving tab stop: the active icon when a tool is open, else the\n // index the user last focused, else the first enabled icon.\n const rovingIndex =\n activeIndex >= 0\n ? activeIndex\n : focusIndex >= 0 && !tools[focusIndex]?.disabled\n ? focusIndex\n : firstEnabledIndex;\n\n const selectTool = useCallback(\n (toolId: string, fromKeyboard: boolean) => {\n const tool = tools.find((tl) => tl.id === toolId);\n if (!tool || tool.disabled) return;\n activatedByKeyboardRef.current = fromKeyboard;\n // Clicking / activating the active tool collapses to strip-only.\n setActiveRaw(activeId === toolId ? null : toolId);\n },\n [tools, activeId, setActiveRaw],\n );\n\n /* ---- Roving arrow-key navigation (vertical toolbar) ----------- */\n const handleStripKeyDown = useCallback(\n (event: ReactKeyboardEvent<HTMLDivElement>) => {\n const count = tools.length;\n if (count === 0) return;\n\n let next: number | null = null;\n if (event.key === 'ArrowDown') next = (rovingIndex + 1) % count;\n else if (event.key === 'ArrowUp')\n next = (rovingIndex - 1 + count) % count;\n else if (event.key === 'Home') next = 0;\n else if (event.key === 'End') next = count - 1;\n if (next === null) return;\n\n // Skip disabled icons in the travel direction.\n const goingBack = event.key === 'ArrowUp' || event.key === 'End';\n let candidate = next;\n let attempts = 0;\n while (attempts < count && tools[candidate]?.disabled) {\n candidate = goingBack\n ? (candidate - 1 + count) % count\n : (candidate + 1) % count;\n attempts += 1;\n }\n if (tools[candidate]?.disabled) return;\n\n event.preventDefault();\n setFocusIndex(candidate);\n buttonsRef.current[candidate]?.focus();\n },\n [tools, rovingIndex],\n );\n\n /* ---- Esc collapses + returns focus to the active tool's icon -- */\n // Attached imperatively via the root ref (not a JSX onKeyDown on the\n // static container) so the Escape shortcut works from anywhere inside the\n // open panel without an interaction handler on a non-interactive element.\n const rootRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n const node = rootRef.current;\n if (!node) return undefined;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n if (activeIndex < 0) return;\n event.preventDefault();\n const returnIndex = activeIndex;\n setActiveRaw(null);\n setFocusIndex(returnIndex);\n // Defer until after the panel unmounts so focus lands cleanly.\n requestAnimationFrame(() => {\n buttonsRef.current[returnIndex]?.focus();\n });\n };\n node.addEventListener('keydown', onKeyDown);\n return () => node.removeEventListener('keydown', onKeyDown);\n }, [activeIndex, setActiveRaw]);\n\n /* ---- Move focus into the panel when opened by keyboard -------- */\n useIsomorphicLayoutEffect(() => {\n if (activeTool && activatedByKeyboardRef.current) {\n panelRef.current?.focus();\n }\n activatedByKeyboardRef.current = false;\n }, [activeTool]);\n\n /* ---- Curated imperative handle for agent integration ---------- */\n const activeIdRef = useRef<string | null>(activeId);\n activeIdRef.current = activeId;\n\n const handle = useMemo<AiToolsRailHandle>(\n () => ({\n getActiveToolId: () => activeIdRef.current,\n setActiveTool: (toolId) => {\n activatedByKeyboardRef.current = false;\n setActiveRaw(toolId);\n },\n open: (toolId) => {\n const tool = tools.find((tl) => tl.id === toolId);\n if (!tool || tool.disabled) return;\n activatedByKeyboardRef.current = false;\n setActiveRaw(toolId);\n },\n close: () => {\n activatedByKeyboardRef.current = false;\n setActiveRaw(null);\n },\n }),\n [tools, setActiveRaw],\n );\n\n useImperativeHandle(ref, () => handle, [handle]);\n useAgentRegistration(aiToolsRailAgent, handle, id);\n\n const overflowLabel = t('aiToolsRail.badgeCountOverflow', {\n defaultValue: '99+',\n });\n\n return (\n <div\n ref={rootRef}\n data-component=\"ai-tools-rail\"\n data-component-id={id}\n data-side={side}\n className={[railVariants({ side }), className]\n .filter(Boolean)\n .join(' ')}\n >\n {/* The OPEN panel is the single complementary landmark, named by\n the active tool. Rendered only while a tool is active so two\n unnamed regions never coexist. */}\n {activeTool ? (\n <aside\n ref={panelRef}\n tabIndex={-1}\n aria-label={t('aiToolsRail.panelLabel', {\n tool: activeTool.label,\n defaultValue: '{{tool}} panel',\n })}\n data-ai-tools-rail-state=\"expanded\"\n data-active-tool={activeTool.id}\n className={[panelVariants(), 'ds:focus-visible:outline-none'].join(\n ' ',\n )}\n >\n <ScrollArea orientation=\"vertical\" className=\"ds:flex-1 ds:min-h-0\">\n {activeTool.panel}\n </ScrollArea>\n </aside>\n ) : null}\n\n {/* The 3rem icon strip — a vertical toolbar with roving tabindex.\n Self-contained TooltipProvider so consumers needn't mount one;\n Radix providers compose, so a host-level provider still works. */}\n <TooltipProvider>\n <div\n role=\"toolbar\"\n aria-orientation=\"vertical\"\n aria-label={\n railLabel ??\n t('aiToolsRail.railLabel', { defaultValue: 'AI tools' })\n }\n className={stripVariants()}\n onKeyDown={handleStripKeyDown}\n >\n {tools.map((tool, index) => {\n const isActive = tool.id === activeId;\n const showBadge =\n typeof tool.badgeCount === 'number' && tool.badgeCount > 0;\n // Fold the count into the accessible name so SR users hear it\n // without relying on the decorative chip.\n const accessibleName = showBadge\n ? t('aiToolsRail.toolWithCount', {\n tool: tool.label,\n count: tool.badgeCount,\n defaultValue: '{{tool}}, {{count}} updates',\n })\n : tool.label;\n return (\n <div key={tool.id} className=\"ds:relative\">\n <IconButton\n ref={(el) => {\n buttonsRef.current[index] = el;\n }}\n icon={tool.icon}\n tooltip={tool.label}\n aria-label={accessibleName}\n intent=\"ghost\"\n size=\"sm\"\n disabled={tool.disabled}\n aria-pressed={isActive}\n aria-expanded={isActive}\n data-active={isActive ? tool.id : undefined}\n data-tool-id={tool.id}\n tabIndex={index === rovingIndex ? 0 : -1}\n onFocus={() => {\n if (!tool.disabled) setFocusIndex(index);\n }}\n onClick={() =>\n selectTool(tool.id, keyboardActivateRef.current)\n }\n onKeyDown={(event) => {\n // Enter/Space activate via the native button's click,\n // which fires AFTER this keydown. Flag the upcoming\n // click as keyboard-driven so focus moves into the\n // panel; reset on keyup so a later mouse click doesn't\n // inherit the flag.\n if (event.key === 'Enter' || event.key === ' ') {\n keyboardActivateRef.current = true;\n }\n }}\n onKeyUp={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n keyboardActivateRef.current = false;\n }\n }}\n />\n {showBadge ? (\n <span aria-hidden=\"true\" className={badgeVariants()}>\n {formatBadgeCount(\n tool.badgeCount as number,\n overflowLabel,\n )}\n </span>\n ) : null}\n </div>\n );\n })}\n </div>\n </TooltipProvider>\n </div>\n );\n },\n);\n\nAiToolsRail.displayName = 'AiToolsRail';\n"],"names":["aiToolsRailAgent","handle","args","RAIL_WIDTH","PANEL_WIDTH","railVariants","cva","stripVariants","panelVariants","badgeVariants","formatBadgeCount","count","overflowLabel","AiToolsRail","forwardRef","id","tools","activeToolId","defaultActiveToolId","onActiveToolChange","side","railLabel","className","ref","t","useTranslation","activeRaw","setActiveRaw","useControllableState","activeId","buttonsRef","useRef","panelRef","focusIndex","setFocusIndex","useState","activatedByKeyboardRef","keyboardActivateRef","activeIndex","useMemo","tl","activeTool","firstEnabledIndex","rovingIndex","_a","selectTool","useCallback","toolId","fromKeyboard","tool","handleStripKeyDown","event","next","goingBack","candidate","attempts","_b","_c","rootRef","useEffect","node","onKeyDown","returnIndex","useIsomorphicLayoutEffect","activeIdRef","useImperativeHandle","useAgentRegistration","jsxs","jsx","ScrollArea","TooltipProvider","index","isActive","showBadge","accessibleName","IconButton","el"],"mappings":"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"}
|