@alfadocs/ui-kit-debug 1.6.0 → 1.7.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/{actions-cell-renderer-BD-jruqA.js → actions-cell-renderer-ALEAGO3j.js} +6 -6
- package/dist/_chunks/{actions-cell-renderer-BD-jruqA.js.map → actions-cell-renderer-ALEAGO3j.js.map} +1 -1
- package/dist/_chunks/{agenda-tray-CYR-znfE.js → agenda-tray-BweO8pDo.js} +3 -3
- package/dist/_chunks/{agenda-tray-CYR-znfE.js.map → agenda-tray-BweO8pDo.js.map} +1 -1
- package/dist/_chunks/{ai-consent-banner-DLF6FNXv.js → ai-consent-banner-OggpS5hW.js} +2 -2
- package/dist/_chunks/{ai-consent-banner-DLF6FNXv.js.map → ai-consent-banner-OggpS5hW.js.map} +1 -1
- package/dist/_chunks/{ai-prompt-input-BgAubYKd.js → ai-prompt-input-DnbfEJnr.js} +2 -2
- package/dist/_chunks/{ai-prompt-input-BgAubYKd.js.map → ai-prompt-input-DnbfEJnr.js.map} +1 -1
- package/dist/_chunks/{alia-sidebar-Bg53-ZOT.js → alia-sidebar-BWcWZivN.js} +7 -7
- package/dist/_chunks/{alia-sidebar-Bg53-ZOT.js.map → alia-sidebar-BWcWZivN.js.map} +1 -1
- package/dist/_chunks/{anamnesis-card-BylMLHYj.js → anamnesis-card-NTi4LLzI.js} +2 -2
- package/dist/_chunks/{anamnesis-card-BylMLHYj.js.map → anamnesis-card-NTi4LLzI.js.map} +1 -1
- package/dist/_chunks/{anamnesis-summary-rows-BpYztFUv.js → anamnesis-summary-rows-F-cCmFAn.js} +7 -7
- package/dist/_chunks/{anamnesis-summary-rows-BpYztFUv.js.map → anamnesis-summary-rows-F-cCmFAn.js.map} +1 -1
- package/dist/_chunks/{appointment-timeline-DT1uFp8z.js → appointment-timeline-CMPvzlGZ.js} +4 -4
- package/dist/_chunks/{appointment-timeline-DT1uFp8z.js.map → appointment-timeline-CMPvzlGZ.js.map} +1 -1
- package/dist/_chunks/{appointment-tray-DvyVK7um.js → appointment-tray-3c_FLxXJ.js} +3 -3
- package/dist/_chunks/{appointment-tray-DvyVK7um.js.map → appointment-tray-3c_FLxXJ.js.map} +1 -1
- package/dist/_chunks/{audio-recorder-nVRN4PSK.js → audio-recorder-EWBCNIsd.js} +3 -3
- package/dist/_chunks/{audio-recorder-nVRN4PSK.js.map → audio-recorder-EWBCNIsd.js.map} +1 -1
- package/dist/_chunks/{bishop-score-BV1JAEMV.js → bishop-score-Cnu0xs-z.js} +2 -2
- package/dist/_chunks/{bishop-score-BV1JAEMV.js.map → bishop-score-Cnu0xs-z.js.map} +1 -1
- package/dist/_chunks/{bmi-calculator-CdR-RLFj.js → bmi-calculator-CcH6upht.js} +2 -2
- package/dist/_chunks/{bmi-calculator-CdR-RLFj.js.map → bmi-calculator-CcH6upht.js.map} +1 -1
- package/dist/_chunks/{booking-D84O6H2X.js → booking-CQMJUFG-.js} +5 -5
- package/dist/_chunks/{booking-D84O6H2X.js.map → booking-CQMJUFG-.js.map} +1 -1
- package/dist/_chunks/{button-group-Be_In68J.js → button-group-CaxRJsNG.js} +2 -2
- package/dist/_chunks/{button-group-Be_In68J.js.map → button-group-CaxRJsNG.js.map} +1 -1
- package/dist/_chunks/{button-BvNtqHAS.js → button-nJaPh_HC.js} +68 -38
- package/dist/_chunks/button-nJaPh_HC.js.map +1 -0
- package/dist/_chunks/{care-plan-card-CehAU7F_.js → care-plan-card-DQjVRDxO.js} +2 -2
- package/dist/_chunks/{care-plan-card-CehAU7F_.js.map → care-plan-card-DQjVRDxO.js.map} +1 -1
- package/dist/_chunks/{care-plan-entry-card-ChWRMfMw.js → care-plan-entry-card-CMpoeNkb.js} +2 -2
- package/dist/_chunks/{care-plan-entry-card-ChWRMfMw.js.map → care-plan-entry-card-CMpoeNkb.js.map} +1 -1
- package/dist/_chunks/{care-plan-header-_B0TTWT1.js → care-plan-header-CxYoq23f.js} +2 -2
- package/dist/_chunks/{care-plan-header-_B0TTWT1.js.map → care-plan-header-CxYoq23f.js.map} +1 -1
- package/dist/_chunks/{carousel.agent-pjORsMS8.js → carousel.agent-CLxdHEBP.js} +2 -2
- package/dist/_chunks/{carousel.agent-pjORsMS8.js.map → carousel.agent-CLxdHEBP.js.map} +1 -1
- package/dist/_chunks/{chart-Y-gso_Uz.js → chart-Bkr1Sh4o.js} +3 -3
- package/dist/_chunks/{chart-Y-gso_Uz.js.map → chart-Bkr1Sh4o.js.map} +1 -1
- package/dist/_chunks/{chat-input-BqI9GXQh.js → chat-input-BsB5Umpj.js} +2 -2
- package/dist/_chunks/{chat-input-BqI9GXQh.js.map → chat-input-BsB5Umpj.js.map} +1 -1
- package/dist/_chunks/{chat-message-DHNUbjXA.js → chat-message-DBQu10rs.js} +3 -3
- package/dist/_chunks/{chat-message-DHNUbjXA.js.map → chat-message-DBQu10rs.js.map} +1 -1
- package/dist/_chunks/{code-block-BONe9fJi.js → code-block-BIkpRLkl.js} +2 -2
- package/dist/_chunks/{code-block-BONe9fJi.js.map → code-block-BIkpRLkl.js.map} +1 -1
- package/dist/_chunks/{connection-status-NT8hUtYl.js → connection-status-DRZIcMqM.js} +3 -3
- package/dist/_chunks/{connection-status-NT8hUtYl.js.map → connection-status-DRZIcMqM.js.map} +1 -1
- package/dist/_chunks/{contact-profile-card-BxHiG8e6.js → contact-profile-card-CE9OJKcl.js} +2 -2
- package/dist/_chunks/{contact-profile-card-BxHiG8e6.js.map → contact-profile-card-CE9OJKcl.js.map} +1 -1
- package/dist/_chunks/{control-room-rail-DDyPDBji.js → control-room-rail-IH1eBjrK.js} +3 -3
- package/dist/_chunks/{control-room-rail-DDyPDBji.js.map → control-room-rail-IH1eBjrK.js.map} +1 -1
- package/dist/_chunks/{copy-field-B-DoMBH_.js → copy-field-fYKpl6aN.js} +2 -2
- package/dist/_chunks/{copy-field-B-DoMBH_.js.map → copy-field-fYKpl6aN.js.map} +1 -1
- package/dist/_chunks/{cycle-calculator-DJZYvNhw.js → cycle-calculator-DzgO1vzP.js} +2 -2
- package/dist/_chunks/{cycle-calculator-DJZYvNhw.js.map → cycle-calculator-DzgO1vzP.js.map} +1 -1
- package/dist/_chunks/{dashboard-grid-bd0QW2a8.js → dashboard-grid-BFtdHqfn.js} +2 -2
- package/dist/_chunks/{dashboard-grid-bd0QW2a8.js.map → dashboard-grid-BFtdHqfn.js.map} +1 -1
- package/dist/_chunks/{data-table-tabs-C8uDThT3.js → data-table-tabs-C1kRUzat.js} +3 -3
- package/dist/_chunks/{data-table-tabs-C8uDThT3.js.map → data-table-tabs-C1kRUzat.js.map} +1 -1
- package/dist/_chunks/{description-list-Ck7fKdt5.js → description-list-CjJqR8WK.js} +2 -2
- package/dist/_chunks/{description-list-Ck7fKdt5.js.map → description-list-CjJqR8WK.js.map} +1 -1
- package/dist/_chunks/{document-preview-Aae2yKvY.js → document-preview-oyx9RhCo.js} +2 -2
- package/dist/_chunks/{document-preview-Aae2yKvY.js.map → document-preview-oyx9RhCo.js.map} +1 -1
- package/dist/_chunks/{document-scanner-qNZLhH_r.js → document-scanner-C5Vrbu21.js} +2 -2
- package/dist/_chunks/{document-scanner-qNZLhH_r.js.map → document-scanner-C5Vrbu21.js.map} +1 -1
- package/dist/_chunks/{due-date-calculator-ajaQ4ya5.js → due-date-calculator-wK8Tajzz.js} +2 -2
- package/dist/_chunks/{due-date-calculator-ajaQ4ya5.js.map → due-date-calculator-wK8Tajzz.js.map} +1 -1
- package/dist/_chunks/{editable-currency-cell-renderer-DyMbSyDK.js → editable-currency-cell-renderer-DYdzKpjL.js} +3 -3
- package/dist/_chunks/{editable-currency-cell-renderer-DyMbSyDK.js.map → editable-currency-cell-renderer-DYdzKpjL.js.map} +1 -1
- package/dist/_chunks/{editor-overlay-DE-gxj9L.js → editor-overlay-DEc5yYwo.js} +2 -2
- package/dist/_chunks/{editor-overlay-DE-gxj9L.js.map → editor-overlay-DEc5yYwo.js.map} +1 -1
- package/dist/_chunks/{empty-state-Df0tM6Kn.js → empty-state-X0sVPfVo.js} +2 -2
- package/dist/_chunks/{empty-state-Df0tM6Kn.js.map → empty-state-X0sVPfVo.js.map} +1 -1
- package/dist/_chunks/{entity-summary-DBOI5di6.js → entity-summary-B_vO5Ur4.js} +3 -3
- package/dist/_chunks/{entity-summary-DBOI5di6.js.map → entity-summary-B_vO5Ur4.js.map} +1 -1
- package/dist/_chunks/{face-scheme-D7Pub04e.js → face-scheme-BfDi4YkW.js} +5 -5
- package/dist/_chunks/{face-scheme-D7Pub04e.js.map → face-scheme-BfDi4YkW.js.map} +1 -1
- package/dist/_chunks/{fetal-weight-jon6GIfQ.js → fetal-weight-Dqy0T1fP.js} +2 -2
- package/dist/_chunks/{fetal-weight-jon6GIfQ.js.map → fetal-weight-Dqy0T1fP.js.map} +1 -1
- package/dist/_chunks/{field-array-BQFX5OYi.js → field-array-BjkXZzSr.js} +3 -3
- package/dist/_chunks/{field-array-BQFX5OYi.js.map → field-array-BjkXZzSr.js.map} +1 -1
- package/dist/_chunks/{field-value-BbiDRyNh.js → field-value-DG8zaZvo.js} +4 -4
- package/dist/_chunks/{field-value-BbiDRyNh.js.map → field-value-DG8zaZvo.js.map} +1 -1
- package/dist/_chunks/{file-manager-CML_C6_h.js → file-manager-Cc_upjZX.js} +6 -6
- package/dist/_chunks/{file-manager-CML_C6_h.js.map → file-manager-Cc_upjZX.js.map} +1 -1
- package/dist/_chunks/{finished-terminal-BWNVh7Y8.js → finished-terminal-Br61Ip4e.js} +2 -2
- package/dist/_chunks/{finished-terminal-BWNVh7Y8.js.map → finished-terminal-Br61Ip4e.js.map} +1 -1
- package/dist/_chunks/{fiscal-code-input-Nx1N9r72.js → fiscal-code-input-B_nYMSEM.js} +2 -2
- package/dist/_chunks/{fiscal-code-input-Nx1N9r72.js.map → fiscal-code-input-B_nYMSEM.js.map} +1 -1
- package/dist/_chunks/{freemium-paywall-HG3pFvMp.js → freemium-paywall-DrXzYfv-.js} +2 -2
- package/dist/_chunks/{freemium-paywall-HG3pFvMp.js.map → freemium-paywall-DrXzYfv-.js.map} +1 -1
- package/dist/_chunks/{gestational-age-calculator-dEpQDWcb.js → gestational-age-calculator-C_uDAeP_.js} +2 -2
- package/dist/_chunks/{gestational-age-calculator-dEpQDWcb.js.map → gestational-age-calculator-C_uDAeP_.js.map} +1 -1
- package/dist/_chunks/{hcg-doubling-CC6TLtHd.js → hcg-doubling-BaXkJhT-.js} +2 -2
- package/dist/_chunks/{hcg-doubling-CC6TLtHd.js.map → hcg-doubling-BaXkJhT-.js.map} +1 -1
- package/dist/_chunks/{header-CimZS-J9.js → header-DUXRIPyM.js} +2 -2
- package/dist/_chunks/{header-CimZS-J9.js.map → header-DUXRIPyM.js.map} +1 -1
- package/dist/_chunks/{header-settings-C0zHLXJE.js → header-settings-CVC_davE.js} +4 -4
- package/dist/_chunks/{header-settings-C0zHLXJE.js.map → header-settings-CVC_davE.js.map} +1 -1
- package/dist/_chunks/{icon-button-9c9Gp41m.js → icon-button-DA2CAGHZ.js} +2 -2
- package/dist/_chunks/{icon-button-9c9Gp41m.js.map → icon-button-DA2CAGHZ.js.map} +1 -1
- package/dist/_chunks/{icon-button-group-DrvuWPGJ.js → icon-button-group-D6SVMteH.js} +2 -2
- package/dist/_chunks/{icon-button-group-DrvuWPGJ.js.map → icon-button-group-D6SVMteH.js.map} +1 -1
- package/dist/_chunks/{icon-picker-DXV3sDp1.js → icon-picker-ChzpCnZ-.js} +3 -3
- package/dist/_chunks/{icon-picker-DXV3sDp1.js.map → icon-picker-ChzpCnZ-.js.map} +1 -1
- package/dist/_chunks/{image-cropper-DWSnyLwW.js → image-cropper-C84NDTB7.js} +2 -2
- package/dist/_chunks/{image-cropper-DWSnyLwW.js.map → image-cropper-C84NDTB7.js.map} +1 -1
- package/dist/_chunks/{info-tip-C4mPSJbS.js → info-tip-C119cwQl.js} +2 -2
- package/dist/_chunks/{info-tip-C4mPSJbS.js.map → info-tip-C119cwQl.js.map} +1 -1
- package/dist/_chunks/{insert-result-98J1QEp7.js → insert-result-LCNTskNJ.js} +2 -2
- package/dist/_chunks/{insert-result-98J1QEp7.js.map → insert-result-LCNTskNJ.js.map} +1 -1
- package/dist/_chunks/{key-value-pair-DGkGlgCF.js → key-value-pair-BubG4fUa.js} +2 -2
- package/dist/_chunks/{key-value-pair-DGkGlgCF.js.map → key-value-pair-BubG4fUa.js.map} +1 -1
- package/dist/_chunks/{link-cell-renderer-D3IsW_2R.js → link-cell-renderer-DH4JYpKU.js} +2 -2
- package/dist/_chunks/{link-cell-renderer-D3IsW_2R.js.map → link-cell-renderer-DH4JYpKU.js.map} +1 -1
- package/dist/_chunks/{locale-picker-sI0HWgZy.js → locale-picker-BvbVjDQ-.js} +3 -3
- package/dist/_chunks/{locale-picker-sI0HWgZy.js.map → locale-picker-BvbVjDQ-.js.map} +1 -1
- package/dist/_chunks/{map-view-iwSDRW3t.js → map-view-CCAlC9IL.js} +2 -2
- package/dist/_chunks/{map-view-iwSDRW3t.js.map → map-view-CCAlC9IL.js.map} +1 -1
- package/dist/_chunks/{marketplace-app-shell-b5hN-Q0m.js → marketplace-app-shell-Chfdia7m.js} +4 -4
- package/dist/_chunks/{marketplace-app-shell-b5hN-Q0m.js.map → marketplace-app-shell-Chfdia7m.js.map} +1 -1
- package/dist/_chunks/{message-card-BCJ-Jgs6.js → message-card-D8GB4FdF.js} +3 -3
- package/dist/_chunks/{message-card-BCJ-Jgs6.js.map → message-card-D8GB4FdF.js.map} +1 -1
- package/dist/_chunks/{message-tray-DHtm_WaF.js → message-tray-CGIRQjx5.js} +4 -4
- package/dist/_chunks/{message-tray-DHtm_WaF.js.map → message-tray-CGIRQjx5.js.map} +1 -1
- package/dist/_chunks/{notes-panel-D6HKLLS-.js → notes-panel-DlnENphf.js} +3 -3
- package/dist/_chunks/{notes-panel-D6HKLLS-.js.map → notes-panel-DlnENphf.js.map} +1 -1
- package/dist/_chunks/{notification-card-CcMQn2RX.js → notification-card-CtrzoTUO.js} +3 -3
- package/dist/_chunks/{notification-card-CcMQn2RX.js.map → notification-card-CtrzoTUO.js.map} +1 -1
- package/dist/_chunks/{notification-tray-nr7dv-Q8.js → notification-tray-BiRzXHDf.js} +4 -4
- package/dist/_chunks/{notification-tray-nr7dv-Q8.js.map → notification-tray-BiRzXHDf.js.map} +1 -1
- package/dist/_chunks/{optical-prescription-DtzEqFQm.js → optical-prescription-Dj3Eh5Ok.js} +2 -2
- package/dist/_chunks/{optical-prescription-DtzEqFQm.js.map → optical-prescription-Dj3Eh5Ok.js.map} +1 -1
- package/dist/_chunks/{patient-details-rENrE_qY.js → patient-details-qnsqYBGQ.js} +5 -5
- package/dist/_chunks/{patient-details-rENrE_qY.js.map → patient-details-qnsqYBGQ.js.map} +1 -1
- package/dist/_chunks/{patient-search-NQemeJlL.js → patient-search-D5ufYoRc.js} +2 -2
- package/dist/_chunks/{patient-search-NQemeJlL.js.map → patient-search-D5ufYoRc.js.map} +1 -1
- package/dist/_chunks/{patient-summary-card-DQJgOOrA.js → patient-summary-card-CBfuDvJ5.js} +3 -3
- package/dist/_chunks/{patient-summary-card-DQJgOOrA.js.map → patient-summary-card-CBfuDvJ5.js.map} +1 -1
- package/dist/_chunks/{patient-table-BubxfOWL.js → patient-table-DwshfVsQ.js} +3 -3
- package/dist/_chunks/{patient-table-BubxfOWL.js.map → patient-table-DwshfVsQ.js.map} +1 -1
- package/dist/_chunks/{payment-automation-upsell-CnaBPt5e.js → payment-automation-upsell-BBIG7NFL.js} +2 -2
- package/dist/_chunks/{payment-automation-upsell-CnaBPt5e.js.map → payment-automation-upsell-BBIG7NFL.js.map} +1 -1
- package/dist/_chunks/{payment-request-card-CvhDzDNk.js → payment-request-card-BjjBMdsp.js} +3 -3
- package/dist/_chunks/{payment-request-card-CvhDzDNk.js.map → payment-request-card-BjjBMdsp.js.map} +1 -1
- package/dist/_chunks/{periodontal-chart-C0nNQKKK.js → periodontal-chart-BatZEFar.js} +2 -2
- package/dist/_chunks/{periodontal-chart-C0nNQKKK.js.map → periodontal-chart-BatZEFar.js.map} +1 -1
- package/dist/_chunks/{periodontal-chart-card-Bz-ebteE.js → periodontal-chart-card-BBpY_rBc.js} +2 -2
- package/dist/_chunks/{periodontal-chart-card-Bz-ebteE.js.map → periodontal-chart-card-BBpY_rBc.js.map} +1 -1
- package/dist/_chunks/{popover-Btj6N25H.js → popover-Cqcjx-Ny.js} +2 -2
- package/dist/_chunks/{popover-Btj6N25H.js.map → popover-Cqcjx-Ny.js.map} +1 -1
- package/dist/_chunks/{practice-results-CKoLD_x5.js → practice-results-BEsAdW-B.js} +719 -633
- package/dist/_chunks/practice-results-BEsAdW-B.js.map +1 -0
- package/dist/_chunks/{pregnancy-dating-DQVpFs_f.js → pregnancy-dating-BVS_9YU2.js} +2 -2
- package/dist/_chunks/{pregnancy-dating-DQVpFs_f.js.map → pregnancy-dating-BVS_9YU2.js.map} +1 -1
- package/dist/_chunks/{pregnancy-weight-gain-hm3QJALe.js → pregnancy-weight-gain-CJwbs9W-.js} +2 -2
- package/dist/_chunks/{pregnancy-weight-gain-hm3QJALe.js.map → pregnancy-weight-gain-CJwbs9W-.js.map} +1 -1
- package/dist/_chunks/{privacy-lock-SQYFRSuH.js → privacy-lock-CkAUo6Dz.js} +3 -3
- package/dist/_chunks/{privacy-lock-SQYFRSuH.js.map → privacy-lock-CkAUo6Dz.js.map} +1 -1
- package/dist/_chunks/{product-hub-panel-BjnD9pdl.js → product-hub-panel-BScCotGD.js} +3 -3
- package/dist/_chunks/{product-hub-panel-BjnD9pdl.js.map → product-hub-panel-BScCotGD.js.map} +1 -1
- package/dist/_chunks/{public-header.agent-DseNK2NQ.js → public-header.agent-kth2SdXn.js} +3 -3
- package/dist/_chunks/{public-header.agent-DseNK2NQ.js.map → public-header.agent-kth2SdXn.js.map} +1 -1
- package/dist/_chunks/{radiograph-panel.agent-CAXFgCyn.js → radiograph-panel.agent-CiHwgISa.js} +4 -4
- package/dist/_chunks/{radiograph-panel.agent-CAXFgCyn.js.map → radiograph-panel.agent-CiHwgISa.js.map} +1 -1
- package/dist/_chunks/{reviews-panel-Cd3SxJdW.js → reviews-panel-BKHEfqVQ.js} +4 -4
- package/dist/_chunks/{reviews-panel-Cd3SxJdW.js.map → reviews-panel-BKHEfqVQ.js.map} +1 -1
- package/dist/_chunks/{rich-text-editor-DGtn_4sb.js → rich-text-editor-DARnq_6N.js} +5 -5
- package/dist/_chunks/{rich-text-editor-DGtn_4sb.js.map → rich-text-editor-DARnq_6N.js.map} +1 -1
- package/dist/_chunks/{session-countdown-q4r5TlCo.js → session-countdown-QMsnRa1x.js} +2 -2
- package/dist/_chunks/{session-countdown-q4r5TlCo.js.map → session-countdown-QMsnRa1x.js.map} +1 -1
- package/dist/_chunks/{sheet-CD99CdXr.js → sheet-BSznOyJs.js} +2 -2
- package/dist/_chunks/{sheet-CD99CdXr.js.map → sheet-BSznOyJs.js.map} +1 -1
- package/dist/_chunks/{sign-in-with-alfadocs-button-_JxVRO5d.js → sign-in-with-alfadocs-button-BLe_quy5.js} +2 -2
- package/dist/_chunks/{sign-in-with-alfadocs-button-_JxVRO5d.js.map → sign-in-with-alfadocs-button-BLe_quy5.js.map} +1 -1
- package/dist/_chunks/{signature-request-C4UBfVRZ.js → signature-request-DXhpphlp.js} +4 -4
- package/dist/_chunks/{signature-request-C4UBfVRZ.js.map → signature-request-DXhpphlp.js.map} +1 -1
- package/dist/_chunks/{slot-grid-P_e9p5t5.js → slot-grid-BuZOKfcd.js} +4 -4
- package/dist/_chunks/{slot-grid-P_e9p5t5.js.map → slot-grid-BuZOKfcd.js.map} +1 -1
- package/dist/_chunks/{streaming-text-BuW7I0Zu.js → streaming-text-CvsjIQ7S.js} +2 -2
- package/dist/_chunks/{streaming-text-BuW7I0Zu.js.map → streaming-text-CvsjIQ7S.js.map} +1 -1
- package/dist/_chunks/{task-tray-BT288xoM.js → task-tray-CYG6rj2s.js} +3 -3
- package/dist/_chunks/{task-tray-BT288xoM.js.map → task-tray-CYG6rj2s.js.map} +1 -1
- package/dist/_chunks/{tasks-panel-BBkZuejF.js → tasks-panel-Do5SFp-j.js} +5 -5
- package/dist/_chunks/{tasks-panel-BBkZuejF.js.map → tasks-panel-Do5SFp-j.js.map} +1 -1
- package/dist/_chunks/{theme-toggle-Bi-CmV6M.js → theme-toggle-DuMhQNFS.js} +3 -3
- package/dist/_chunks/{theme-toggle-Bi-CmV6M.js.map → theme-toggle-DuMhQNFS.js.map} +1 -1
- package/dist/_chunks/{toast.agent-C44mtGrW.js → toast.agent-D1tdg6DS.js} +2 -2
- package/dist/_chunks/{toast.agent-C44mtGrW.js.map → toast.agent-D1tdg6DS.js.map} +1 -1
- package/dist/_chunks/{token-insert-menu-D8FgXl33.js → token-insert-menu-9Um0JinI.js} +2 -2
- package/dist/_chunks/{token-insert-menu-D8FgXl33.js.map → token-insert-menu-9Um0JinI.js.map} +1 -1
- package/dist/_chunks/{tool-rail-BF3F2Ihq.js → tool-rail-CHyUmulN.js} +2 -2
- package/dist/_chunks/{tool-rail-BF3F2Ihq.js.map → tool-rail-CHyUmulN.js.map} +1 -1
- package/dist/_chunks/{tooth-scheme-BPXE1_3N.js → tooth-scheme-WdyVymQ1.js} +3 -3
- package/dist/_chunks/{tooth-scheme-BPXE1_3N.js.map → tooth-scheme-WdyVymQ1.js.map} +1 -1
- package/dist/_chunks/{unit-converter-iDxlxKmm.js → unit-converter-BPumXMA6.js} +2 -2
- package/dist/_chunks/{unit-converter-iDxlxKmm.js.map → unit-converter-BPumXMA6.js.map} +1 -1
- package/dist/_chunks/{warning-stack-nczJf52p.js → warning-stack-DQz0Jyir.js} +3 -3
- package/dist/_chunks/{warning-stack-nczJf52p.js.map → warning-stack-DQz0Jyir.js.map} +1 -1
- package/dist/_chunks/{workflow-map-BVofnDYh.js → workflow-map-DE_ribRM.js} +5 -5
- package/dist/_chunks/{workflow-map-BVofnDYh.js.map → workflow-map-DE_ribRM.js.map} +1 -1
- package/dist/agent-catalog.json +2 -2
- package/dist/components/agenda-tray/index.js +1 -1
- package/dist/components/ai-consent-banner/index.js +1 -1
- package/dist/components/ai-prompt-input/index.js +1 -1
- package/dist/components/anamnesis-card/index.js +1 -1
- package/dist/components/appointment-card/index.js +1 -1
- package/dist/components/appointment-timeline/index.js +1 -1
- package/dist/components/audio-recorder/index.js +1 -1
- package/dist/components/bishop-score/index.js +1 -1
- package/dist/components/bmi-calculator/index.js +1 -1
- package/dist/components/booking/index.js +1 -1
- package/dist/components/button/button.d.ts +10 -0
- package/dist/components/button/button.d.ts.map +1 -1
- package/dist/components/button/index.js +2 -2
- package/dist/components/button-group/index.js +1 -1
- package/dist/components/care-plan-card/index.js +1 -1
- package/dist/components/care-plan-entry-card/index.js +1 -1
- package/dist/components/care-plan-header/index.js +1 -1
- package/dist/components/carousel/index.js +1 -1
- package/dist/components/chart/index.js +1 -1
- package/dist/components/chat-input/index.js +1 -1
- package/dist/components/chat-message/index.js +1 -1
- package/dist/components/connection-status/index.js +1 -1
- package/dist/components/contact-profile-card/index.js +1 -1
- package/dist/components/control-room-rail/index.js +1 -1
- package/dist/components/copy-field/index.js +1 -1
- package/dist/components/cycle-calculator/index.js +1 -1
- package/dist/components/dashboard-grid/index.js +1 -1
- package/dist/components/data-table/index.js +3 -3
- package/dist/components/data-table-tabs/index.js +1 -1
- package/dist/components/description-list/index.js +1 -1
- package/dist/components/document-preview/index.js +1 -1
- package/dist/components/document-scanner/index.js +1 -1
- package/dist/components/due-date-calculator/index.js +1 -1
- package/dist/components/editor-overlay/index.js +1 -1
- package/dist/components/empty-state/index.js +1 -1
- package/dist/components/entity-summary/index.js +1 -1
- package/dist/components/face-scheme/index.js +1 -1
- package/dist/components/fetal-weight/index.js +1 -1
- package/dist/components/field-array/index.js +1 -1
- package/dist/components/file-manager/index.js +1 -1
- package/dist/components/finished-terminal/index.js +1 -1
- package/dist/components/fiscal-code-input/index.js +1 -1
- package/dist/components/freemium-paywall/index.js +1 -1
- package/dist/components/gestational-age-calculator/index.js +1 -1
- package/dist/components/hcg-doubling/index.js +1 -1
- package/dist/components/header/index.js +1 -1
- package/dist/components/header-settings/index.js +1 -1
- package/dist/components/icon-button/index.js +1 -1
- package/dist/components/icon-button-group/index.js +1 -1
- package/dist/components/icon-picker/index.js +1 -1
- package/dist/components/image-cropper/index.js +1 -1
- package/dist/components/info-tip/index.js +1 -1
- package/dist/components/key-value-pair/index.js +1 -1
- package/dist/components/locale-picker/index.js +1 -1
- package/dist/components/map-view/index.js +1 -1
- package/dist/components/matrix-rain/matrix-rain.d.ts +1 -1
- package/dist/components/message-card/index.js +1 -1
- package/dist/components/message-tray/index.js +1 -1
- package/dist/components/notes-panel/index.js +1 -1
- package/dist/components/notification-card/index.js +1 -1
- package/dist/components/notification-tray/index.js +1 -1
- package/dist/components/optical-prescription/index.js +1 -1
- package/dist/components/patient-details/index.js +1 -1
- package/dist/components/patient-search/index.js +1 -1
- package/dist/components/patient-summary-card/index.js +1 -1
- package/dist/components/patient-table/index.js +1 -1
- package/dist/components/payment-card/index.js +1 -1
- package/dist/components/periodontal-chart/index.js +1 -1
- package/dist/components/periodontal-chart-card/index.js +1 -1
- package/dist/components/popover/index.js +1 -1
- package/dist/components/practice-results/index.js +1 -1
- package/dist/components/practice-results/practice-results.d.ts +47 -7
- package/dist/components/practice-results/practice-results.d.ts.map +1 -1
- package/dist/components/pregnancy-dating/index.js +1 -1
- package/dist/components/pregnancy-weight-gain/index.js +1 -1
- package/dist/components/privacy-lock/index.js +1 -1
- package/dist/components/product-hub-tray/index.js +1 -1
- package/dist/components/public-header/index.js +1 -1
- package/dist/components/public-header/public-header.d.ts +1 -1
- package/dist/components/radiograph-panel/index.js +1 -1
- package/dist/components/reviews-panel/index.js +1 -1
- package/dist/components/rich-text-editor/index.js +1 -1
- package/dist/components/session-countdown/index.js +1 -1
- package/dist/components/sheet/index.js +1 -1
- package/dist/components/sign-in-with-alfadocs-button/index.js +1 -1
- package/dist/components/slot-grid/index.js +1 -1
- package/dist/components/streaming-text/index.js +1 -1
- package/dist/components/task-tray/index.js +1 -1
- package/dist/components/tasks-panel/index.js +1 -1
- package/dist/components/theme-toggle/index.js +1 -1
- package/dist/components/toast/index.js +1 -1
- package/dist/components/token-insert-menu/index.js +1 -1
- package/dist/components/tool-rail/index.js +1 -1
- package/dist/components/tooth-scheme/index.js +1 -1
- package/dist/components/unit-converter/index.js +1 -1
- package/dist/components/warning-stack/index.js +1 -1
- package/dist/components/workflow/index.js +1 -1
- package/dist/i18n/locales/ar.d.ts +1 -0
- package/dist/i18n/locales/ar.d.ts.map +1 -1
- package/dist/i18n/locales/ar.js +2 -1
- package/dist/i18n/locales/ar.js.map +1 -1
- package/dist/i18n/locales/de.d.ts +1 -0
- package/dist/i18n/locales/de.d.ts.map +1 -1
- package/dist/i18n/locales/de.js +2 -1
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/el.d.ts +1 -0
- package/dist/i18n/locales/el.d.ts.map +1 -1
- package/dist/i18n/locales/el.js +2 -1
- package/dist/i18n/locales/el.js.map +1 -1
- package/dist/i18n/locales/en.d.ts +1 -0
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +2 -1
- package/dist/i18n/locales/en.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +1 -0
- package/dist/i18n/locales/es.d.ts.map +1 -1
- package/dist/i18n/locales/es.js +2 -1
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +1 -0
- package/dist/i18n/locales/fr.d.ts.map +1 -1
- package/dist/i18n/locales/fr.js +2 -1
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hi.d.ts +1 -0
- package/dist/i18n/locales/hi.d.ts.map +1 -1
- package/dist/i18n/locales/hi.js +2 -1
- package/dist/i18n/locales/hi.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +1 -0
- package/dist/i18n/locales/it.d.ts.map +1 -1
- package/dist/i18n/locales/it.js +2 -1
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/ja.d.ts +1 -0
- package/dist/i18n/locales/ja.d.ts.map +1 -1
- package/dist/i18n/locales/ja.js +2 -1
- package/dist/i18n/locales/ja.js.map +1 -1
- package/dist/i18n/locales/nl.d.ts +1 -0
- package/dist/i18n/locales/nl.d.ts.map +1 -1
- package/dist/i18n/locales/nl.js +2 -1
- package/dist/i18n/locales/nl.js.map +1 -1
- package/dist/i18n/locales/pl.d.ts +1 -0
- package/dist/i18n/locales/pl.d.ts.map +1 -1
- package/dist/i18n/locales/pl.js +2 -1
- package/dist/i18n/locales/pl.js.map +1 -1
- package/dist/i18n/locales/pt.d.ts +1 -0
- package/dist/i18n/locales/pt.d.ts.map +1 -1
- package/dist/i18n/locales/pt.js +2 -1
- package/dist/i18n/locales/pt.js.map +1 -1
- package/dist/i18n/locales/ro.d.ts +1 -0
- package/dist/i18n/locales/ro.d.ts.map +1 -1
- package/dist/i18n/locales/ro.js +2 -1
- package/dist/i18n/locales/ro.js.map +1 -1
- package/dist/i18n/locales/ru.d.ts +1 -0
- package/dist/i18n/locales/ru.d.ts.map +1 -1
- package/dist/i18n/locales/ru.js +2 -1
- package/dist/i18n/locales/ru.js.map +1 -1
- package/dist/i18n/locales/sq.d.ts +1 -0
- package/dist/i18n/locales/sq.d.ts.map +1 -1
- package/dist/i18n/locales/sq.js +2 -1
- package/dist/i18n/locales/sq.js.map +1 -1
- package/dist/i18n/locales/sv.d.ts +1 -0
- package/dist/i18n/locales/sv.d.ts.map +1 -1
- package/dist/i18n/locales/sv.js +2 -1
- package/dist/i18n/locales/sv.js.map +1 -1
- package/dist/i18n/locales/tr.d.ts +1 -0
- package/dist/i18n/locales/tr.d.ts.map +1 -1
- package/dist/i18n/locales/tr.js +2 -1
- package/dist/i18n/locales/tr.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +1 -0
- package/dist/i18n/locales/zh.d.ts.map +1 -1
- package/dist/i18n/locales/zh.js +2 -1
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.js +96 -96
- package/dist/locales/ar.json +2 -1
- package/dist/locales/de.json +2 -1
- package/dist/locales/el.json +2 -1
- package/dist/locales/en.json +2 -1
- package/dist/locales/es.json +2 -1
- package/dist/locales/fr.json +2 -1
- package/dist/locales/hi.json +2 -1
- package/dist/locales/it.json +2 -1
- package/dist/locales/ja.json +2 -1
- package/dist/locales/nl.json +2 -1
- package/dist/locales/pl.json +2 -1
- package/dist/locales/pt.json +2 -1
- package/dist/locales/ro.json +2 -1
- package/dist/locales/ru.json +2 -1
- package/dist/locales/sq.json +2 -1
- package/dist/locales/sv.json +2 -1
- package/dist/locales/tr.json +2 -1
- package/dist/locales/zh.json +2 -1
- package/dist/patterns/alia-assistant/index.js +1 -1
- package/dist/patterns/anamnesis/index.js +1 -1
- package/dist/patterns/marketplace-app-shell/index.js +1 -1
- package/dist/patterns/payment-automation-upsell/index.js +1 -1
- package/dist/patterns/signature-request/index.js +1 -1
- package/dist/tokens.css +1 -1
- package/package.json +1 -1
- package/dist/_chunks/button-BvNtqHAS.js.map +0 -1
- package/dist/_chunks/practice-results-CKoLD_x5.js.map +0 -1
package/dist/_chunks/{control-room-rail-DDyPDBji.js.map → control-room-rail-IH1eBjrK.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-room-rail-DDyPDBji.js","sources":["../../src/components/control-room-rail/control-room-rail.agent.ts","../../src/components/control-room-rail/control-room-context.tsx","../../src/components/control-room-rail/control-room-rail.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — ControlRoomRail. */\n/* */\n/* The product surface built on ToolRail: the docked \"Control Room\". */\n/* It claims its OWN agent identity ('control-room-rail') so an agent and */\n/* the DOM / cascade boundary can tell the Control Room apart from a bare */\n/* ToolRail. Generic rail surface only: open / close a tool's panel and */\n/* read which tool is active. State is strictly the active tool id — never */\n/* any tool's panel CONTENT (which may carry PHI). */\n/* */\n/* The descriptionKeys deliberately REUSE the existing */\n/* `ui.toolRail.agent.*` translations — no new i18n keys are coined this */\n/* pass. */\n/* */\n/* NOTE: pin / unpin / reorder favourites are intentionally NOT yet an */\n/* agent capability. Exposing them is a deferred follow-up: it needs a */\n/* closed-vocabulary capability addition (DS-maintainer approval per */\n/* src/docs/26-agent-readiness.mdx) plus its own 18-locale descriptionKeys */\n/* — neither of which this pass introduces. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { ControlRoomRailHandle } from './control-room-rail';\n\nexport const controlRoomRailAgent: AgentAdapter<ControlRoomRailHandle> = {\n id: 'control-room-rail',\n capabilities: ['open', 'close', 'select_single'],\n state: {\n activeToolId: {\n type: 'string | null',\n descriptionKey: 'ui.toolRail.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 // Pure ephemeral panel state (open) — no data loss, no external effect.\n safety: 'read',\n argsType: '{ id: string }',\n argsSchema: {\n type: 'object',\n properties: { id: { type: 'string' } },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.toolRail.agent.actions.open',\n description: \"Open the given tool's panel.\",\n examples: [{ args: { id: 'inbox' }, note: 'Open the inbox tool panel.' }],\n invoke: (handle, args: { id: string }) => {\n handle.open(args.id);\n },\n },\n close: {\n safety: 'read',\n idempotent: true,\n descriptionKey: 'ui.toolRail.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 argsSchema: {\n type: 'object',\n properties: { id: { type: ['string', 'null'] } },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.toolRail.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: 'control-room-rail',\n description: 'Marks the ControlRoomRail 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 createContext,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport type { ToolRailHandle, ToolRailTool } from '../tool-rail';\n\n/* ------------------------------------------------------------------ */\n/* Control Room context — the scope mechanism */\n/* */\n/* The DS provides the plumbing; the CONSUMER declares scope by which */\n/* API it reaches for: */\n/* - <ControlRoomProvider globalTools={…}> → `global` tools, set */\n/* once at the app shell, persist across navigation. */\n/* - useControlRoomTools([…]) → `contextual` tools, */\n/* registered per-page, swap with the open entity. */\n/* `<ControlRoomRail>` reads the merged set; `global` tools seed the */\n/* default favourites (pinned on top), `contextual` tools fall below */\n/* the divider. The rail renders the divider between the two groups. */\n/* ------------------------------------------------------------------ */\n\ninterface ControlRoomContextValue {\n globalTools: ToolRailTool[];\n contextualTools: ToolRailTool[];\n registerContextualTools: (id: string, tools: ToolRailTool[]) => void;\n unregisterContextualTools: (id: string) => void;\n // The rail registers its imperative handle here so pages can drive it\n // (e.g. open the X-ray panel when a tooth is clicked). Null until mounted.\n registerRail: (handle: ToolRailHandle | null) => void;\n openTool: (id: string) => void;\n closeTool: () => void;\n}\n\nconst ControlRoomContext = createContext<ControlRoomContextValue | null>(null);\n\nexport interface ControlRoomProviderProps {\n /**\n * Tools valid in every context (Alia, Inbox). Set once at the app shell —\n * they pin to the rail's far end and persist across navigation. Memoise\n * this array so it doesn't re-register every render.\n */\n globalTools?: ToolRailTool[];\n children: ReactNode;\n}\n\n/**\n * Holds the Control Room's global tools and the registry of per-context\n * contextual tools. Mount once at the app shell, inside the frame that also\n * renders `<ControlRoomRail>`.\n */\nexport function ControlRoomProvider({\n globalTools = [],\n children,\n}: ControlRoomProviderProps) {\n // id → that registration's contextual tools. Multiple concurrent\n // registrations merge in insertion order (rare, but composes cleanly).\n const [registry, setRegistry] = useState<Map<string, ToolRailTool[]>>(\n () => new Map(),\n );\n\n const registerContextualTools = useCallback(\n (id: string, tools: ToolRailTool[]) => {\n setRegistry((prev) => {\n const next = new Map(prev);\n next.set(id, tools);\n return next;\n });\n },\n [],\n );\n\n const unregisterContextualTools = useCallback((id: string) => {\n setRegistry((prev) => {\n if (!prev.has(id)) return prev;\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n\n const contextualTools = useMemo(\n () => Array.from(registry.values()).flat(),\n [registry],\n );\n\n // The rail's imperative handle, registered by <ControlRoomRail> on mount.\n // openTool/closeTool drive it so a page can open a panel (e.g. the X-ray\n // viewer when a tooth is clicked) without holding a ref to the rail itself.\n const railHandleRef = useRef<ToolRailHandle | null>(null);\n const registerRail = useCallback((handle: ToolRailHandle | null) => {\n railHandleRef.current = handle;\n }, []);\n const openTool = useCallback((id: string) => {\n railHandleRef.current?.setActiveTool(id);\n }, []);\n const closeTool = useCallback(() => {\n railHandleRef.current?.setActiveTool(null);\n }, []);\n\n const value = useMemo<ControlRoomContextValue>(\n () => ({\n globalTools,\n contextualTools,\n registerContextualTools,\n unregisterContextualTools,\n registerRail,\n openTool,\n closeTool,\n }),\n [\n globalTools,\n contextualTools,\n registerContextualTools,\n unregisterContextualTools,\n registerRail,\n openTool,\n closeTool,\n ],\n );\n\n return (\n <ControlRoomContext.Provider value={value}>\n {children}\n </ControlRoomContext.Provider>\n );\n}\n\n/**\n * Register this context's **contextual** tools (Notes, Appointments, the entity\n * summary). They sit below the favourites divider and unregister automatically\n * when the calling component unmounts (i.e. when you leave the context).\n *\n * Pass a **stable / memoised** array — like `useEffect` deps, a fresh array\n * every render re-registers every render. Wrap it in `useMemo`.\n *\n * No-op when rendered outside a `<ControlRoomProvider>`.\n */\nexport function useControlRoomTools(tools: ToolRailTool[]): void {\n const ctx = useContext(ControlRoomContext);\n // Depend on the STABLE register/unregister callbacks, never the whole\n // context value: the value object changes every time the registry updates\n // (which this very effect triggers), so depending on `ctx` would re-register\n // on every change — an infinite loop. The callbacks are `useCallback([])`.\n const register = ctx?.registerContextualTools;\n const unregister = ctx?.unregisterContextualTools;\n const id = useId();\n useEffect(() => {\n if (!register || !unregister) return undefined;\n register(id, tools);\n return () => unregister(id);\n }, [register, unregister, id, tools]);\n}\n\n/**\n * The merged tool set the rail consumes: contextual tools (auto-tagged\n * `scope: 'contextual'`) then globals (`scope: 'global'`). Scope is assigned\n * here by which API registered the tool — `global` seeds the Control Room's\n * default favourites (pinned on top); `contextual` falls below the divider.\n * `ControlRoomRail` re-groups by favourite membership for the final order.\n * Returns `[]` outside a provider.\n */\nexport function useControlRoomMergedTools(): ToolRailTool[] {\n const ctx = useContext(ControlRoomContext);\n return useMemo(() => {\n if (!ctx) return [];\n const contextual = ctx.contextualTools.map((tool) => ({\n ...tool,\n scope: 'contextual' as const,\n }));\n const global = ctx.globalTools.map((tool) => ({\n ...tool,\n scope: 'global' as const,\n }));\n return [...contextual, ...global];\n }, [ctx]);\n}\n\n/**\n * Imperative actions to drive the rail from a page: open a tool's panel (e.g.\n * the X-ray viewer when a tooth is clicked) or collapse it. No-ops outside a\n * `<ControlRoomProvider>`. The functions are stable across renders.\n */\nexport function useControlRoomActions(): {\n openTool: (id: string) => void;\n closeTool: () => void;\n} {\n const ctx = useContext(ControlRoomContext);\n const noop = useCallback(() => {}, []);\n return {\n openTool: ctx?.openTool ?? noop,\n closeTool: ctx?.closeTool ?? noop,\n };\n}\n\n/**\n * Internal: the rail registers its imperative handle with the provider so\n * `useControlRoomActions().openTool` can drive it. Returns the stable\n * `registerRail` callback (or a no-op outside a provider).\n */\nexport function useControlRoomRailRegister(): (\n handle: ToolRailHandle | null,\n) => void {\n const ctx = useContext(ControlRoomContext);\n const noop = useCallback((_handle: ToolRailHandle | null) => {}, []);\n return ctx?.registerRail ?? noop;\n}\n","import {\n forwardRef,\n useCallback,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Star, X } from 'lucide-react';\nimport { IconButton } from '../button/icon-button';\nimport { PanelHeaderActionsProvider } from '../panel-header/panel-header';\nimport {\n ToolRail,\n type ToolRailHandle,\n type ToolRailProps,\n type ToolRailTool,\n} from '../tool-rail';\nimport { usePersistentState } from '../../hooks/use-persistent-state';\nimport { controlRoomRailAgent } from './control-room-rail.agent';\nimport {\n useControlRoomMergedTools,\n useControlRoomRailRegister,\n} from './control-room-context';\n\n/* ------------------------------------------------------------------ */\n/* ControlRoomRail — the unified, contextual workspace rail. */\n/* */\n/* The docked right-hand \"Control Room\": the single home for the */\n/* assistant, inbox, notes, appointments and entity summaries */\n/* alongside the main work surface. One panel open at a time, */\n/* non-modal. */\n/* */\n/* It layers a FAVOURITES model over the proven ToolRail (its prior */\n/* name): favourited tools form a pinned group at the TOP of the strip */\n/* above a divider, then everything else below. The default favourites */\n/* are the host's `global` tools (Alia, Inbox) — so the rail opens with */\n/* notifications + Alia on top, the Control Room's default arrangement. */\n/* */\n/* Favouriting is DRAG-FIRST, no per-icon star: drag a tool up across */\n/* the divider to pin it (and drop it where you want in the order), */\n/* drag a favourite back down to unpin. The keyboard equivalent is */\n/* `Alt`+Arrow (crossing the divider pins / unpins, announced). The */\n/* non-drag pointer path — and the discoverable entry point — is an */\n/* add / remove control in each open tool's panel header. */\n/* */\n/* ToolRail stays favourite-agnostic: this layer maps favourite */\n/* membership onto the rail's generic `scope` grouping + (whole-strip) */\n/* `reorderable` run, reads cross-divider moves as pin / unpin, and */\n/* injects the favourite + close controls into the active panel's */\n/* PanelHeader via <PanelHeaderActionsProvider> (no separate header */\n/* row — the controls live inline-end of the panel's title row). */\n/* ------------------------------------------------------------------ */\n\n/** A Control Room tool — the rail tool descriptor, `scope`-aware. */\nexport type ControlRoomTool = ToolRailTool;\n\n/** Imperative handle — open / collapse a tool panel without the DOM. */\nexport type ControlRoomRailHandle = ToolRailHandle;\n\nexport interface ControlRoomRailProps extends Omit<\n ToolRailProps,\n | 'tools'\n | 'onReorder'\n | 'formatReorderAnnouncement'\n | 'renderToolAffordance'\n | 'renderPanelHeader'\n> {\n /**\n * Explicit tool set. Omit to read the merged global + contextual tools from\n * the nearest `<ControlRoomProvider>` (+ `useControlRoomTools`).\n */\n tools?: ControlRoomTool[];\n /**\n * Enable the favourites model: a pinned top group, drag / `Alt`+Arrow\n * reordering, and the panel-header add / remove control. Default `true`. Set\n * `false` for the legacy flat strip (tools render in the order / `scope` you\n * pass, no drag, no panel-header control).\n */\n reorderable?: boolean;\n /**\n * Controlled favourite tool ids, in pinned order. When set, the rail does not\n * persist — the host owns the value and is notified via `onFavoriteIdsChange`.\n */\n favoriteIds?: string[];\n /**\n * Uncontrolled initial favourites. Defaults to the ids of the tools the host\n * marked `scope: 'global'` (Alia, Inbox) — pinning them on top by default.\n */\n defaultFavoriteIds?: string[];\n /** Fires with the next favourites order whenever the user pins / reorders. */\n onFavoriteIdsChange?: (next: string[]) => void;\n /** localStorage key for the uncontrolled favourites. */\n persistFavoritesKey?: string;\n}\n\nexport const ControlRoomRail = forwardRef<\n ControlRoomRailHandle,\n ControlRoomRailProps\n>(function ControlRoomRail(\n {\n tools,\n railLabel,\n reorderable = true,\n favoriteIds,\n defaultFavoriteIds,\n onFavoriteIdsChange,\n persistFavoritesKey = 'ui.controlRoom.favorites',\n activeToolId,\n defaultActiveToolId = null,\n onActiveToolChange,\n ...rest\n },\n ref,\n) {\n const { t } = useTranslation();\n\n // Mirror the active tool id so the rail can build the panel-header controls\n // (favourite + close) for whichever tool is open. Controlled hosts own the\n // value via `activeToolId`; otherwise we seed from `defaultActiveToolId` and\n // track subsequent changes through the intercepted `onActiveToolChange`.\n const [activeTracked, setActiveTracked] = useState<string | null>(\n activeToolId ?? defaultActiveToolId ?? null,\n );\n const activeId = activeToolId !== undefined ? activeToolId : activeTracked;\n const handleActiveToolChange = useCallback(\n (id: string | null) => {\n if (activeToolId === undefined) setActiveTracked(id);\n onActiveToolChange?.(id);\n },\n [activeToolId, onActiveToolChange],\n );\n // Provider-driven tools when none are passed explicitly. Calling the hook\n // unconditionally is safe — it returns [] outside a provider.\n const merged = useControlRoomMergedTools();\n const resolved = tools ?? merged;\n\n const isControlled = favoriteIds !== undefined;\n // Uncontrolled favourites persist to localStorage; the lazy initial seeds\n // from the host's `global` tools on first mount only (later tool changes\n // don't re-seed — favourites are user-owned once set). When controlled, the\n // hook is disabled so it never reads or writes storage.\n const [storedFavorites, setStoredFavorites] = usePersistentState<string[]>(\n persistFavoritesKey,\n () =>\n defaultFavoriteIds ??\n resolved.filter((tl) => tl.scope === 'global').map((tl) => tl.id),\n { disabled: isControlled },\n );\n const favorites = isControlled ? favoriteIds : storedFavorites;\n\n const byId = useMemo(() => {\n const map = new Map<string, ControlRoomTool>();\n for (const tl of resolved) map.set(tl.id, tl);\n return map;\n }, [resolved]);\n\n // Favourites filtered to currently-present tools — stale ids are ignored\n // (and dropped on the next write).\n const favoriteSet = useMemo(\n () => new Set(favorites.filter((id) => byId.has(id))),\n [favorites, byId],\n );\n\n const updateFavorites = (updater: (prev: string[]) => string[]) => {\n // `updater` must be pure — it is invoked twice (once to compute the\n // reported `next`, once inside the functional setState below).\n const next = updater(favorites.filter((id) => byId.has(id)));\n // Persist via a functional update so rapid pin/reorder events compose\n // (mirrors the Sidebar's useFavorites); controlled hosts own the value.\n if (!isControlled)\n setStoredFavorites((prev) => updater(prev.filter((id) => byId.has(id))));\n onFavoriteIdsChange?.(next);\n };\n\n // Re-group into the pinned run (favourites order, tagged so ToolRail draws\n // the divider) followed by the rest. EVERY tool is `reorderable` so the rail's\n // reorder run spans the whole strip — that's what lets a drag / Alt+Arrow\n // cross the divider; `handleReorder` reads the crossing as pin / unpin.\n const railTools = useMemo<ControlRoomTool[]>(() => {\n if (!reorderable) return resolved;\n const favTools = favorites\n .filter((id) => byId.has(id))\n .map((id) => ({\n ...(byId.get(id) as ControlRoomTool),\n scope: 'global' as const,\n reorderable: true,\n }));\n const rest = resolved\n .filter((tl) => !favoriteSet.has(tl.id))\n .map((tl) => ({\n ...tl,\n scope: 'contextual' as const,\n reorderable: true,\n }));\n return [...favTools, ...rest];\n }, [reorderable, resolved, favorites, byId, favoriteSet]);\n\n // The drag / Alt+Arrow path announces through the rail's own reorder live\n // region; the panel-header button toggles outside it, so it needs its own\n // polite announcement. The zero-width-space toggle forces a re-announce of an\n // identical message (e.g. pin → unpin → pin the same tool).\n const [pinMessage, setPinMessage] = useState('');\n const pinAnnounceToggle = useRef(false);\n const announcePinChange = (label: string, willPin: boolean) => {\n const text = willPin\n ? t('controlRoom.pinnedAnnounce', {\n tool: label,\n defaultValue: 'Pinned {{tool}} to favourites',\n })\n : t('controlRoom.unpinnedAnnounce', {\n tool: label,\n defaultValue: 'Removed {{tool}} from favourites',\n });\n pinAnnounceToggle.current = !pinAnnounceToggle.current;\n setPinMessage(pinAnnounceToggle.current ? text : `${text}\\u200B`);\n };\n\n const togglePin = (id: string) => {\n announcePinChange(byId.get(id)?.label ?? id, !favoriteSet.has(id));\n updateFavorites((prev) =>\n prev.includes(id) ? prev.filter((p) => p !== id) : [...prev, id],\n );\n };\n\n // The rail fires `onReorder` with indices into `railTools` (favourites first,\n // then the rest). The divider sits at `favCount`, so the index either side of\n // it tells us whether a move is a reorder, a pin, an unpin, or a no-op.\n const handleReorder = (from: number, to: number) => {\n const movedId = railTools[from]?.id;\n if (movedId === undefined) return;\n updateFavorites((prev) => {\n const present = prev.filter((id) => byId.has(id));\n const favCount = present.length;\n const wasFav = from < favCount;\n if (wasFav) {\n // Dropped below the divider → unpin.\n if (to >= favCount) return present.filter((id) => id !== movedId);\n // Reorder within favourites (full-strip index == favourites index).\n const next = present.slice();\n next.splice(from, 1);\n next.splice(to, 0, movedId);\n return next;\n }\n // A contextual tool dropped onto / above the divider → pin at that slot.\n if (to <= favCount) {\n const next = present.slice();\n next.splice(Math.min(to, favCount), 0, movedId);\n return next;\n }\n // Contextual → contextual: that group is host-ordered, so nothing to do.\n return prev;\n });\n };\n\n // Membership-aware live-region phrasing for the rail's reorder announcer.\n const formatReorderAnnouncement = ({\n tool,\n from,\n to,\n }: {\n tool: ControlRoomTool;\n from: number;\n to: number;\n }): string => {\n const favCount = favoriteSet.size;\n const wasFav = from < favCount;\n if (wasFav && to >= favCount)\n return t('controlRoom.unpinnedAnnounce', {\n tool: tool.label,\n defaultValue: 'Removed {{tool}} from favourites',\n });\n if (!wasFav && to <= favCount)\n return t('controlRoom.pinnedAnnounce', {\n tool: tool.label,\n defaultValue: 'Pinned {{tool}} to favourites',\n });\n if (wasFav && to < favCount)\n return t('controlRoom.reorderAnnounce', {\n tool: tool.label,\n to: to + 1,\n total: favCount,\n defaultValue: '{{tool}} moved to position {{to}} of {{total}}',\n });\n // Contextual → contextual is a no-op; stay silent.\n return '';\n };\n\n // Register the rail's imperative handle with the provider (so a page's\n // useControlRoomActions().openTool can drive it) AND forward it to the\n // consumer's ref. A callback ref does both; no-op without a provider. We also\n // stash it locally so the injected close control can collapse the panel.\n const railHandleRef = useRef<ToolRailHandle | null>(null);\n const registerRail = useControlRoomRailRegister();\n const setRefs = useCallback(\n (handle: ToolRailHandle | null) => {\n railHandleRef.current = handle;\n registerRail(handle);\n if (typeof ref === 'function') ref(handle);\n else if (ref) ref.current = handle;\n },\n [registerRail, ref],\n );\n\n // The active tool's panel-header controls, injected into its PanelHeader's\n // action cluster (inline-end of the title row) via context — no separate\n // header row. When a tool is open: an icon-only favourite toggle (only when\n // reorderable; pressed state via aria-pressed + the filled star) followed by\n // a close control that collapses the panel. Nothing injected when collapsed\n // or where the panel renders no PanelHeader.\n const activeTool = activeId != null ? (byId.get(activeId) ?? null) : null;\n const injectedActions: ReactNode = activeTool ? (\n <>\n {reorderable\n ? (() => {\n const pinned = favoriteSet.has(activeTool.id);\n return (\n <IconButton\n icon={\n <Star\n aria-hidden=\"true\"\n fill={pinned ? 'currentColor' : 'none'}\n className={\n pinned ? 'ds:text-[color:var(--accent)]' : undefined\n }\n />\n }\n intent=\"ghost\"\n size=\"sm\"\n aria-pressed={pinned}\n aria-label={t('controlRoom.favorite', {\n defaultValue: 'Favourite',\n })}\n onClick={() => togglePin(activeTool.id)}\n />\n );\n })()\n : null}\n <IconButton\n icon={<X aria-hidden=\"true\" />}\n intent=\"ghost\"\n size=\"sm\"\n aria-label={t('controlRoom.close', { defaultValue: 'Close' })}\n onClick={() => railHandleRef.current?.close()}\n />\n </>\n ) : null;\n return (\n <PanelHeaderActionsProvider actions={injectedActions}>\n <ToolRail\n ref={setRefs}\n dataComponent=\"control-room-rail\"\n agentAdapter={controlRoomRailAgent}\n tools={railTools}\n activeToolId={activeToolId}\n defaultActiveToolId={defaultActiveToolId}\n onActiveToolChange={handleActiveToolChange}\n railLabel={\n railLabel ??\n t('controlRoom.railLabel', { defaultValue: 'Control room' })\n }\n onReorder={reorderable ? handleReorder : undefined}\n formatReorderAnnouncement={\n reorderable ? formatReorderAnnouncement : undefined\n }\n {...rest}\n />\n {/* Polite announcement for the panel-header pin / unpin button (the\n drag / Alt+Arrow path announces via the rail's own reorder region). */}\n {reorderable ? (\n <span role=\"status\" aria-live=\"polite\" className=\"ds:sr-only\">\n {pinMessage}\n </span>\n ) : null}\n </PanelHeaderActionsProvider>\n );\n});\n"],"names":["controlRoomRailAgent","handle","args","ControlRoomContext","createContext","ControlRoomProvider","globalTools","children","registry","setRegistry","useState","registerContextualTools","useCallback","id","tools","prev","next","unregisterContextualTools","contextualTools","useMemo","railHandleRef","useRef","registerRail","openTool","_a","closeTool","value","jsx","useControlRoomTools","ctx","useContext","register","unregister","useId","useEffect","useControlRoomMergedTools","contextual","tool","global","useControlRoomActions","noop","useControlRoomRailRegister","_handle","ControlRoomRail","forwardRef","railLabel","reorderable","favoriteIds","defaultFavoriteIds","onFavoriteIdsChange","persistFavoritesKey","activeToolId","defaultActiveToolId","onActiveToolChange","rest","ref","t","useTranslation","activeTracked","setActiveTracked","activeId","handleActiveToolChange","merged","resolved","isControlled","storedFavorites","setStoredFavorites","usePersistentState","tl","favorites","byId","map","favoriteSet","updateFavorites","updater","railTools","favTools","pinMessage","setPinMessage","pinAnnounceToggle","announcePinChange","label","willPin","text","togglePin","p","handleReorder","from","to","movedId","present","favCount","formatReorderAnnouncement","wasFav","setRefs","activeTool","injectedActions","jsxs","Fragment","pinned","IconButton","Star","X","PanelHeaderActionsProvider","ToolRail"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"control-room-rail-IH1eBjrK.js","sources":["../../src/components/control-room-rail/control-room-rail.agent.ts","../../src/components/control-room-rail/control-room-context.tsx","../../src/components/control-room-rail/control-room-rail.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — ControlRoomRail. */\n/* */\n/* The product surface built on ToolRail: the docked \"Control Room\". */\n/* It claims its OWN agent identity ('control-room-rail') so an agent and */\n/* the DOM / cascade boundary can tell the Control Room apart from a bare */\n/* ToolRail. Generic rail surface only: open / close a tool's panel and */\n/* read which tool is active. State is strictly the active tool id — never */\n/* any tool's panel CONTENT (which may carry PHI). */\n/* */\n/* The descriptionKeys deliberately REUSE the existing */\n/* `ui.toolRail.agent.*` translations — no new i18n keys are coined this */\n/* pass. */\n/* */\n/* NOTE: pin / unpin / reorder favourites are intentionally NOT yet an */\n/* agent capability. Exposing them is a deferred follow-up: it needs a */\n/* closed-vocabulary capability addition (DS-maintainer approval per */\n/* src/docs/26-agent-readiness.mdx) plus its own 18-locale descriptionKeys */\n/* — neither of which this pass introduces. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { ControlRoomRailHandle } from './control-room-rail';\n\nexport const controlRoomRailAgent: AgentAdapter<ControlRoomRailHandle> = {\n id: 'control-room-rail',\n capabilities: ['open', 'close', 'select_single'],\n state: {\n activeToolId: {\n type: 'string | null',\n descriptionKey: 'ui.toolRail.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 // Pure ephemeral panel state (open) — no data loss, no external effect.\n safety: 'read',\n argsType: '{ id: string }',\n argsSchema: {\n type: 'object',\n properties: { id: { type: 'string' } },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.toolRail.agent.actions.open',\n description: \"Open the given tool's panel.\",\n examples: [{ args: { id: 'inbox' }, note: 'Open the inbox tool panel.' }],\n invoke: (handle, args: { id: string }) => {\n handle.open(args.id);\n },\n },\n close: {\n safety: 'read',\n idempotent: true,\n descriptionKey: 'ui.toolRail.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 argsSchema: {\n type: 'object',\n properties: { id: { type: ['string', 'null'] } },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.toolRail.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: 'control-room-rail',\n description: 'Marks the ControlRoomRail 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 createContext,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport type { ToolRailHandle, ToolRailTool } from '../tool-rail';\n\n/* ------------------------------------------------------------------ */\n/* Control Room context — the scope mechanism */\n/* */\n/* The DS provides the plumbing; the CONSUMER declares scope by which */\n/* API it reaches for: */\n/* - <ControlRoomProvider globalTools={…}> → `global` tools, set */\n/* once at the app shell, persist across navigation. */\n/* - useControlRoomTools([…]) → `contextual` tools, */\n/* registered per-page, swap with the open entity. */\n/* `<ControlRoomRail>` reads the merged set; `global` tools seed the */\n/* default favourites (pinned on top), `contextual` tools fall below */\n/* the divider. The rail renders the divider between the two groups. */\n/* ------------------------------------------------------------------ */\n\ninterface ControlRoomContextValue {\n globalTools: ToolRailTool[];\n contextualTools: ToolRailTool[];\n registerContextualTools: (id: string, tools: ToolRailTool[]) => void;\n unregisterContextualTools: (id: string) => void;\n // The rail registers its imperative handle here so pages can drive it\n // (e.g. open the X-ray panel when a tooth is clicked). Null until mounted.\n registerRail: (handle: ToolRailHandle | null) => void;\n openTool: (id: string) => void;\n closeTool: () => void;\n}\n\nconst ControlRoomContext = createContext<ControlRoomContextValue | null>(null);\n\nexport interface ControlRoomProviderProps {\n /**\n * Tools valid in every context (Alia, Inbox). Set once at the app shell —\n * they pin to the rail's far end and persist across navigation. Memoise\n * this array so it doesn't re-register every render.\n */\n globalTools?: ToolRailTool[];\n children: ReactNode;\n}\n\n/**\n * Holds the Control Room's global tools and the registry of per-context\n * contextual tools. Mount once at the app shell, inside the frame that also\n * renders `<ControlRoomRail>`.\n */\nexport function ControlRoomProvider({\n globalTools = [],\n children,\n}: ControlRoomProviderProps) {\n // id → that registration's contextual tools. Multiple concurrent\n // registrations merge in insertion order (rare, but composes cleanly).\n const [registry, setRegistry] = useState<Map<string, ToolRailTool[]>>(\n () => new Map(),\n );\n\n const registerContextualTools = useCallback(\n (id: string, tools: ToolRailTool[]) => {\n setRegistry((prev) => {\n const next = new Map(prev);\n next.set(id, tools);\n return next;\n });\n },\n [],\n );\n\n const unregisterContextualTools = useCallback((id: string) => {\n setRegistry((prev) => {\n if (!prev.has(id)) return prev;\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n\n const contextualTools = useMemo(\n () => Array.from(registry.values()).flat(),\n [registry],\n );\n\n // The rail's imperative handle, registered by <ControlRoomRail> on mount.\n // openTool/closeTool drive it so a page can open a panel (e.g. the X-ray\n // viewer when a tooth is clicked) without holding a ref to the rail itself.\n const railHandleRef = useRef<ToolRailHandle | null>(null);\n const registerRail = useCallback((handle: ToolRailHandle | null) => {\n railHandleRef.current = handle;\n }, []);\n const openTool = useCallback((id: string) => {\n railHandleRef.current?.setActiveTool(id);\n }, []);\n const closeTool = useCallback(() => {\n railHandleRef.current?.setActiveTool(null);\n }, []);\n\n const value = useMemo<ControlRoomContextValue>(\n () => ({\n globalTools,\n contextualTools,\n registerContextualTools,\n unregisterContextualTools,\n registerRail,\n openTool,\n closeTool,\n }),\n [\n globalTools,\n contextualTools,\n registerContextualTools,\n unregisterContextualTools,\n registerRail,\n openTool,\n closeTool,\n ],\n );\n\n return (\n <ControlRoomContext.Provider value={value}>\n {children}\n </ControlRoomContext.Provider>\n );\n}\n\n/**\n * Register this context's **contextual** tools (Notes, Appointments, the entity\n * summary). They sit below the favourites divider and unregister automatically\n * when the calling component unmounts (i.e. when you leave the context).\n *\n * Pass a **stable / memoised** array — like `useEffect` deps, a fresh array\n * every render re-registers every render. Wrap it in `useMemo`.\n *\n * No-op when rendered outside a `<ControlRoomProvider>`.\n */\nexport function useControlRoomTools(tools: ToolRailTool[]): void {\n const ctx = useContext(ControlRoomContext);\n // Depend on the STABLE register/unregister callbacks, never the whole\n // context value: the value object changes every time the registry updates\n // (which this very effect triggers), so depending on `ctx` would re-register\n // on every change — an infinite loop. The callbacks are `useCallback([])`.\n const register = ctx?.registerContextualTools;\n const unregister = ctx?.unregisterContextualTools;\n const id = useId();\n useEffect(() => {\n if (!register || !unregister) return undefined;\n register(id, tools);\n return () => unregister(id);\n }, [register, unregister, id, tools]);\n}\n\n/**\n * The merged tool set the rail consumes: contextual tools (auto-tagged\n * `scope: 'contextual'`) then globals (`scope: 'global'`). Scope is assigned\n * here by which API registered the tool — `global` seeds the Control Room's\n * default favourites (pinned on top); `contextual` falls below the divider.\n * `ControlRoomRail` re-groups by favourite membership for the final order.\n * Returns `[]` outside a provider.\n */\nexport function useControlRoomMergedTools(): ToolRailTool[] {\n const ctx = useContext(ControlRoomContext);\n return useMemo(() => {\n if (!ctx) return [];\n const contextual = ctx.contextualTools.map((tool) => ({\n ...tool,\n scope: 'contextual' as const,\n }));\n const global = ctx.globalTools.map((tool) => ({\n ...tool,\n scope: 'global' as const,\n }));\n return [...contextual, ...global];\n }, [ctx]);\n}\n\n/**\n * Imperative actions to drive the rail from a page: open a tool's panel (e.g.\n * the X-ray viewer when a tooth is clicked) or collapse it. No-ops outside a\n * `<ControlRoomProvider>`. The functions are stable across renders.\n */\nexport function useControlRoomActions(): {\n openTool: (id: string) => void;\n closeTool: () => void;\n} {\n const ctx = useContext(ControlRoomContext);\n const noop = useCallback(() => {}, []);\n return {\n openTool: ctx?.openTool ?? noop,\n closeTool: ctx?.closeTool ?? noop,\n };\n}\n\n/**\n * Internal: the rail registers its imperative handle with the provider so\n * `useControlRoomActions().openTool` can drive it. Returns the stable\n * `registerRail` callback (or a no-op outside a provider).\n */\nexport function useControlRoomRailRegister(): (\n handle: ToolRailHandle | null,\n) => void {\n const ctx = useContext(ControlRoomContext);\n const noop = useCallback((_handle: ToolRailHandle | null) => {}, []);\n return ctx?.registerRail ?? noop;\n}\n","import {\n forwardRef,\n useCallback,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Star, X } from 'lucide-react';\nimport { IconButton } from '../button/icon-button';\nimport { PanelHeaderActionsProvider } from '../panel-header/panel-header';\nimport {\n ToolRail,\n type ToolRailHandle,\n type ToolRailProps,\n type ToolRailTool,\n} from '../tool-rail';\nimport { usePersistentState } from '../../hooks/use-persistent-state';\nimport { controlRoomRailAgent } from './control-room-rail.agent';\nimport {\n useControlRoomMergedTools,\n useControlRoomRailRegister,\n} from './control-room-context';\n\n/* ------------------------------------------------------------------ */\n/* ControlRoomRail — the unified, contextual workspace rail. */\n/* */\n/* The docked right-hand \"Control Room\": the single home for the */\n/* assistant, inbox, notes, appointments and entity summaries */\n/* alongside the main work surface. One panel open at a time, */\n/* non-modal. */\n/* */\n/* It layers a FAVOURITES model over the proven ToolRail (its prior */\n/* name): favourited tools form a pinned group at the TOP of the strip */\n/* above a divider, then everything else below. The default favourites */\n/* are the host's `global` tools (Alia, Inbox) — so the rail opens with */\n/* notifications + Alia on top, the Control Room's default arrangement. */\n/* */\n/* Favouriting is DRAG-FIRST, no per-icon star: drag a tool up across */\n/* the divider to pin it (and drop it where you want in the order), */\n/* drag a favourite back down to unpin. The keyboard equivalent is */\n/* `Alt`+Arrow (crossing the divider pins / unpins, announced). The */\n/* non-drag pointer path — and the discoverable entry point — is an */\n/* add / remove control in each open tool's panel header. */\n/* */\n/* ToolRail stays favourite-agnostic: this layer maps favourite */\n/* membership onto the rail's generic `scope` grouping + (whole-strip) */\n/* `reorderable` run, reads cross-divider moves as pin / unpin, and */\n/* injects the favourite + close controls into the active panel's */\n/* PanelHeader via <PanelHeaderActionsProvider> (no separate header */\n/* row — the controls live inline-end of the panel's title row). */\n/* ------------------------------------------------------------------ */\n\n/** A Control Room tool — the rail tool descriptor, `scope`-aware. */\nexport type ControlRoomTool = ToolRailTool;\n\n/** Imperative handle — open / collapse a tool panel without the DOM. */\nexport type ControlRoomRailHandle = ToolRailHandle;\n\nexport interface ControlRoomRailProps extends Omit<\n ToolRailProps,\n | 'tools'\n | 'onReorder'\n | 'formatReorderAnnouncement'\n | 'renderToolAffordance'\n | 'renderPanelHeader'\n> {\n /**\n * Explicit tool set. Omit to read the merged global + contextual tools from\n * the nearest `<ControlRoomProvider>` (+ `useControlRoomTools`).\n */\n tools?: ControlRoomTool[];\n /**\n * Enable the favourites model: a pinned top group, drag / `Alt`+Arrow\n * reordering, and the panel-header add / remove control. Default `true`. Set\n * `false` for the legacy flat strip (tools render in the order / `scope` you\n * pass, no drag, no panel-header control).\n */\n reorderable?: boolean;\n /**\n * Controlled favourite tool ids, in pinned order. When set, the rail does not\n * persist — the host owns the value and is notified via `onFavoriteIdsChange`.\n */\n favoriteIds?: string[];\n /**\n * Uncontrolled initial favourites. Defaults to the ids of the tools the host\n * marked `scope: 'global'` (Alia, Inbox) — pinning them on top by default.\n */\n defaultFavoriteIds?: string[];\n /** Fires with the next favourites order whenever the user pins / reorders. */\n onFavoriteIdsChange?: (next: string[]) => void;\n /** localStorage key for the uncontrolled favourites. */\n persistFavoritesKey?: string;\n}\n\nexport const ControlRoomRail = forwardRef<\n ControlRoomRailHandle,\n ControlRoomRailProps\n>(function ControlRoomRail(\n {\n tools,\n railLabel,\n reorderable = true,\n favoriteIds,\n defaultFavoriteIds,\n onFavoriteIdsChange,\n persistFavoritesKey = 'ui.controlRoom.favorites',\n activeToolId,\n defaultActiveToolId = null,\n onActiveToolChange,\n ...rest\n },\n ref,\n) {\n const { t } = useTranslation();\n\n // Mirror the active tool id so the rail can build the panel-header controls\n // (favourite + close) for whichever tool is open. Controlled hosts own the\n // value via `activeToolId`; otherwise we seed from `defaultActiveToolId` and\n // track subsequent changes through the intercepted `onActiveToolChange`.\n const [activeTracked, setActiveTracked] = useState<string | null>(\n activeToolId ?? defaultActiveToolId ?? null,\n );\n const activeId = activeToolId !== undefined ? activeToolId : activeTracked;\n const handleActiveToolChange = useCallback(\n (id: string | null) => {\n if (activeToolId === undefined) setActiveTracked(id);\n onActiveToolChange?.(id);\n },\n [activeToolId, onActiveToolChange],\n );\n // Provider-driven tools when none are passed explicitly. Calling the hook\n // unconditionally is safe — it returns [] outside a provider.\n const merged = useControlRoomMergedTools();\n const resolved = tools ?? merged;\n\n const isControlled = favoriteIds !== undefined;\n // Uncontrolled favourites persist to localStorage; the lazy initial seeds\n // from the host's `global` tools on first mount only (later tool changes\n // don't re-seed — favourites are user-owned once set). When controlled, the\n // hook is disabled so it never reads or writes storage.\n const [storedFavorites, setStoredFavorites] = usePersistentState<string[]>(\n persistFavoritesKey,\n () =>\n defaultFavoriteIds ??\n resolved.filter((tl) => tl.scope === 'global').map((tl) => tl.id),\n { disabled: isControlled },\n );\n const favorites = isControlled ? favoriteIds : storedFavorites;\n\n const byId = useMemo(() => {\n const map = new Map<string, ControlRoomTool>();\n for (const tl of resolved) map.set(tl.id, tl);\n return map;\n }, [resolved]);\n\n // Favourites filtered to currently-present tools — stale ids are ignored\n // (and dropped on the next write).\n const favoriteSet = useMemo(\n () => new Set(favorites.filter((id) => byId.has(id))),\n [favorites, byId],\n );\n\n const updateFavorites = (updater: (prev: string[]) => string[]) => {\n // `updater` must be pure — it is invoked twice (once to compute the\n // reported `next`, once inside the functional setState below).\n const next = updater(favorites.filter((id) => byId.has(id)));\n // Persist via a functional update so rapid pin/reorder events compose\n // (mirrors the Sidebar's useFavorites); controlled hosts own the value.\n if (!isControlled)\n setStoredFavorites((prev) => updater(prev.filter((id) => byId.has(id))));\n onFavoriteIdsChange?.(next);\n };\n\n // Re-group into the pinned run (favourites order, tagged so ToolRail draws\n // the divider) followed by the rest. EVERY tool is `reorderable` so the rail's\n // reorder run spans the whole strip — that's what lets a drag / Alt+Arrow\n // cross the divider; `handleReorder` reads the crossing as pin / unpin.\n const railTools = useMemo<ControlRoomTool[]>(() => {\n if (!reorderable) return resolved;\n const favTools = favorites\n .filter((id) => byId.has(id))\n .map((id) => ({\n ...(byId.get(id) as ControlRoomTool),\n scope: 'global' as const,\n reorderable: true,\n }));\n const rest = resolved\n .filter((tl) => !favoriteSet.has(tl.id))\n .map((tl) => ({\n ...tl,\n scope: 'contextual' as const,\n reorderable: true,\n }));\n return [...favTools, ...rest];\n }, [reorderable, resolved, favorites, byId, favoriteSet]);\n\n // The drag / Alt+Arrow path announces through the rail's own reorder live\n // region; the panel-header button toggles outside it, so it needs its own\n // polite announcement. The zero-width-space toggle forces a re-announce of an\n // identical message (e.g. pin → unpin → pin the same tool).\n const [pinMessage, setPinMessage] = useState('');\n const pinAnnounceToggle = useRef(false);\n const announcePinChange = (label: string, willPin: boolean) => {\n const text = willPin\n ? t('controlRoom.pinnedAnnounce', {\n tool: label,\n defaultValue: 'Pinned {{tool}} to favourites',\n })\n : t('controlRoom.unpinnedAnnounce', {\n tool: label,\n defaultValue: 'Removed {{tool}} from favourites',\n });\n pinAnnounceToggle.current = !pinAnnounceToggle.current;\n setPinMessage(pinAnnounceToggle.current ? text : `${text}\\u200B`);\n };\n\n const togglePin = (id: string) => {\n announcePinChange(byId.get(id)?.label ?? id, !favoriteSet.has(id));\n updateFavorites((prev) =>\n prev.includes(id) ? prev.filter((p) => p !== id) : [...prev, id],\n );\n };\n\n // The rail fires `onReorder` with indices into `railTools` (favourites first,\n // then the rest). The divider sits at `favCount`, so the index either side of\n // it tells us whether a move is a reorder, a pin, an unpin, or a no-op.\n const handleReorder = (from: number, to: number) => {\n const movedId = railTools[from]?.id;\n if (movedId === undefined) return;\n updateFavorites((prev) => {\n const present = prev.filter((id) => byId.has(id));\n const favCount = present.length;\n const wasFav = from < favCount;\n if (wasFav) {\n // Dropped below the divider → unpin.\n if (to >= favCount) return present.filter((id) => id !== movedId);\n // Reorder within favourites (full-strip index == favourites index).\n const next = present.slice();\n next.splice(from, 1);\n next.splice(to, 0, movedId);\n return next;\n }\n // A contextual tool dropped onto / above the divider → pin at that slot.\n if (to <= favCount) {\n const next = present.slice();\n next.splice(Math.min(to, favCount), 0, movedId);\n return next;\n }\n // Contextual → contextual: that group is host-ordered, so nothing to do.\n return prev;\n });\n };\n\n // Membership-aware live-region phrasing for the rail's reorder announcer.\n const formatReorderAnnouncement = ({\n tool,\n from,\n to,\n }: {\n tool: ControlRoomTool;\n from: number;\n to: number;\n }): string => {\n const favCount = favoriteSet.size;\n const wasFav = from < favCount;\n if (wasFav && to >= favCount)\n return t('controlRoom.unpinnedAnnounce', {\n tool: tool.label,\n defaultValue: 'Removed {{tool}} from favourites',\n });\n if (!wasFav && to <= favCount)\n return t('controlRoom.pinnedAnnounce', {\n tool: tool.label,\n defaultValue: 'Pinned {{tool}} to favourites',\n });\n if (wasFav && to < favCount)\n return t('controlRoom.reorderAnnounce', {\n tool: tool.label,\n to: to + 1,\n total: favCount,\n defaultValue: '{{tool}} moved to position {{to}} of {{total}}',\n });\n // Contextual → contextual is a no-op; stay silent.\n return '';\n };\n\n // Register the rail's imperative handle with the provider (so a page's\n // useControlRoomActions().openTool can drive it) AND forward it to the\n // consumer's ref. A callback ref does both; no-op without a provider. We also\n // stash it locally so the injected close control can collapse the panel.\n const railHandleRef = useRef<ToolRailHandle | null>(null);\n const registerRail = useControlRoomRailRegister();\n const setRefs = useCallback(\n (handle: ToolRailHandle | null) => {\n railHandleRef.current = handle;\n registerRail(handle);\n if (typeof ref === 'function') ref(handle);\n else if (ref) ref.current = handle;\n },\n [registerRail, ref],\n );\n\n // The active tool's panel-header controls, injected into its PanelHeader's\n // action cluster (inline-end of the title row) via context — no separate\n // header row. When a tool is open: an icon-only favourite toggle (only when\n // reorderable; pressed state via aria-pressed + the filled star) followed by\n // a close control that collapses the panel. Nothing injected when collapsed\n // or where the panel renders no PanelHeader.\n const activeTool = activeId != null ? (byId.get(activeId) ?? null) : null;\n const injectedActions: ReactNode = activeTool ? (\n <>\n {reorderable\n ? (() => {\n const pinned = favoriteSet.has(activeTool.id);\n return (\n <IconButton\n icon={\n <Star\n aria-hidden=\"true\"\n fill={pinned ? 'currentColor' : 'none'}\n className={\n pinned ? 'ds:text-[color:var(--accent)]' : undefined\n }\n />\n }\n intent=\"ghost\"\n size=\"sm\"\n aria-pressed={pinned}\n aria-label={t('controlRoom.favorite', {\n defaultValue: 'Favourite',\n })}\n onClick={() => togglePin(activeTool.id)}\n />\n );\n })()\n : null}\n <IconButton\n icon={<X aria-hidden=\"true\" />}\n intent=\"ghost\"\n size=\"sm\"\n aria-label={t('controlRoom.close', { defaultValue: 'Close' })}\n onClick={() => railHandleRef.current?.close()}\n />\n </>\n ) : null;\n return (\n <PanelHeaderActionsProvider actions={injectedActions}>\n <ToolRail\n ref={setRefs}\n dataComponent=\"control-room-rail\"\n agentAdapter={controlRoomRailAgent}\n tools={railTools}\n activeToolId={activeToolId}\n defaultActiveToolId={defaultActiveToolId}\n onActiveToolChange={handleActiveToolChange}\n railLabel={\n railLabel ??\n t('controlRoom.railLabel', { defaultValue: 'Control room' })\n }\n onReorder={reorderable ? handleReorder : undefined}\n formatReorderAnnouncement={\n reorderable ? formatReorderAnnouncement : undefined\n }\n {...rest}\n />\n {/* Polite announcement for the panel-header pin / unpin button (the\n drag / Alt+Arrow path announces via the rail's own reorder region). */}\n {reorderable ? (\n <span role=\"status\" aria-live=\"polite\" className=\"ds:sr-only\">\n {pinMessage}\n </span>\n ) : null}\n </PanelHeaderActionsProvider>\n );\n});\n"],"names":["controlRoomRailAgent","handle","args","ControlRoomContext","createContext","ControlRoomProvider","globalTools","children","registry","setRegistry","useState","registerContextualTools","useCallback","id","tools","prev","next","unregisterContextualTools","contextualTools","useMemo","railHandleRef","useRef","registerRail","openTool","_a","closeTool","value","jsx","useControlRoomTools","ctx","useContext","register","unregister","useId","useEffect","useControlRoomMergedTools","contextual","tool","global","useControlRoomActions","noop","useControlRoomRailRegister","_handle","ControlRoomRail","forwardRef","railLabel","reorderable","favoriteIds","defaultFavoriteIds","onFavoriteIdsChange","persistFavoritesKey","activeToolId","defaultActiveToolId","onActiveToolChange","rest","ref","t","useTranslation","activeTracked","setActiveTracked","activeId","handleActiveToolChange","merged","resolved","isControlled","storedFavorites","setStoredFavorites","usePersistentState","tl","favorites","byId","map","favoriteSet","updateFavorites","updater","railTools","favTools","pinMessage","setPinMessage","pinAnnounceToggle","announcePinChange","label","willPin","text","togglePin","p","handleReorder","from","to","movedId","present","favCount","formatReorderAnnouncement","wasFav","setRefs","activeTool","injectedActions","jsxs","Fragment","pinned","IconButton","Star","X","PanelHeaderActionsProvider","ToolRail"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { jsxs as M, jsx as o } from "react/jsx-runtime";
|
|
|
2
2
|
import { forwardRef as P, useRef as v, useState as E, useEffect as H, useCallback as z, useMemo as O } from "react";
|
|
3
3
|
import { c as u } from "./index-D2ZczOXr.js";
|
|
4
4
|
import { useTranslation as W } from "react-i18next";
|
|
5
|
-
import { B as _ } from "./button-
|
|
5
|
+
import { B as _ } from "./button-nJaPh_HC.js";
|
|
6
6
|
import { u as q } from "./registry-DvAUVLHh.js";
|
|
7
7
|
import { u as D } from "./use-copy-to-clipboard-Cyfc_dlv.js";
|
|
8
8
|
import { C as G } from "./check-DrFSN__t.js";
|
|
@@ -265,4 +265,4 @@ export {
|
|
|
265
265
|
ee as C,
|
|
266
266
|
Q as c
|
|
267
267
|
};
|
|
268
|
-
//# sourceMappingURL=copy-field-
|
|
268
|
+
//# sourceMappingURL=copy-field-fYKpl6aN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy-field-B-DoMBH_.js","sources":["../../src/components/copy-field/copy-field.agent.ts","../../src/components/copy-field/copy-field.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — CopyField. */\n/* */\n/* See `src/docs/26-agent-readiness.mdx` for the contract. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\n\n/**\n * Imperative handle for CopyField — agents can read the value and trigger a\n * programmatic copy. State stays scoped to identifiers + transient UI state;\n * never PHI (per PRS §Security).\n */\nexport interface CopyFieldHandle {\n /** Returns the read-only value currently displayed. */\n getValue: () => string;\n /** Triggers the clipboard write side-effect. */\n copy: () => Promise<boolean>;\n /** Returns true for the brief window after a successful copy. */\n isCopied: () => boolean;\n}\n\nexport const copyFieldAgent: AgentAdapter<CopyFieldHandle> = {\n id: 'copy-field',\n capabilities: ['copy'],\n state: {\n value: {\n type: 'string',\n descriptionKey: 'ui.agent.copyField.state.value',\n description: 'The value displayed in the read-only field.',\n read: (handle) => handle.getValue(),\n },\n copied: {\n type: 'boolean',\n descriptionKey: 'ui.agent.copyField.state.copied',\n description: 'True for the brief window after a successful copy.',\n read: (handle) => handle.isCopied(),\n },\n },\n actions: {\n copy: {\n // Writes the value to the system clipboard — reaches outside this UI.\n safety: 'write',\n openWorld: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the clipboard write succeeded.',\n },\n descriptionKey: 'ui.agent.copyField.actions.copy',\n description: 'Programmatically trigger the clipboard write.',\n invoke: (handle) => handle.copy(),\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'copy-field',\n description:\n 'Marks the CopyField root. The trailing button uses `aria-label` keyed off the copy / copied state.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop, when provided.',\n },\n },\n};\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Check, Copy } from 'lucide-react';\nimport { Button } from '../button/button';\nimport { useAgentRegistration } from '../../agent';\nimport { useCopyToClipboard } from '../../hooks/use-copy-to-clipboard';\nimport { copyFieldAgent, type CopyFieldHandle } from './copy-field.agent';\n\n/* ------------------------------------------------------------------ */\n/* Clipboard helper */\n/* */\n/* `navigator.clipboard.writeText` is the modern path. The fallback */\n/* covers older browsers and insecure contexts via a synthesised */\n/* textarea + `document.execCommand('copy')`. The off-screen position */\n/* uses imperative DOM `.style` assignments — those are NOT JSX inline */\n/* styles and don't violate constraint §3. */\n/* ------------------------------------------------------------------ */\n\nasync function copyToClipboard(text: string): Promise<boolean> {\n if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch {\n // fall through to legacy path\n }\n }\n if (typeof document === 'undefined') return false;\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.setAttribute('readonly', '');\n // Imperative DOM style — not a JSX inline-style violation. We use\n // `setProperty('inset-inline-start', …)` so the hidden textarea stays\n // logically off-screen in both LTR and RTL contexts.\n textarea.style.position = 'absolute';\n textarea.style.setProperty('inset-inline-start', '-9999px');\n document.body.appendChild(textarea);\n textarea.select();\n let ok = false;\n try {\n ok = document.execCommand('copy');\n } catch {\n ok = false;\n }\n document.body.removeChild(textarea);\n return ok;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA — outer wrapper */\n/* */\n/* Mirrors the shared input-surface chrome (border + halo shadow) so */\n/* CopyField sits inline next to TextInput / Combobox in forms without */\n/* visual drift. Logical paddings only. `ds:focus-within` paints the */\n/* ring when the trailing button or the embedded input receives focus. */\n/* ------------------------------------------------------------------ */\n\nconst fieldVariants = cva(\n [\n 'ds:inline-flex ds:items-stretch ds:w-full',\n 'ds:rounded-[var(--radius-sm)] ds:bg-input ds:text-foreground',\n 'ds:border ds:border-border',\n 'ds:shadow-[var(--shadow-input)]',\n 'ds:focus-within:outline-[length:var(--focus-ring-width)] ds:focus-within:outline-solid',\n 'ds:focus-within:outline-ring ds:focus-within:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-within:outline-[CanvasText]',\n 'ds:transition-[colors,box-shadow] ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:overflow-hidden',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:h-8 ds:text-[var(--font-size-sm)]',\n md: 'ds:h-[var(--min-target-size)] ds:text-[var(--font-size-base)]',\n lg: 'ds:h-12 ds:text-[var(--font-size-lg)]',\n },\n disabled: {\n true: 'ds:opacity-50 ds:cursor-not-allowed',\n false: '',\n },\n },\n defaultVariants: { size: 'md', disabled: false },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* CVA — value <input> styling */\n/* ------------------------------------------------------------------ */\n\nconst valueVariants = cva(\n [\n 'ds:flex-1 ds:min-w-0 ds:bg-transparent ds:border-0 ds:outline-none',\n 'ds:text-foreground',\n 'ds:disabled:cursor-not-allowed',\n ].join(' '),\n {\n variants: {\n intent: {\n default: '',\n // `--primary` is calibrated for foreground use (violet-500 light,\n // magenta-500 dark) — both pass AA against their input backgrounds.\n primary: 'ds:text-primary ds:font-medium',\n },\n size: {\n sm: 'ds:text-[var(--font-size-sm)]',\n md: 'ds:text-[var(--font-size-base)]',\n lg: 'ds:text-[var(--font-size-lg)]',\n },\n wrap: {\n true: 'ds:[overflow-wrap:anywhere] ds:whitespace-normal',\n false: 'ds:overflow-hidden ds:text-ellipsis ds:whitespace-nowrap',\n },\n hasStartIcon: {\n true: '',\n false: '',\n },\n },\n // Explicit pairs decide the leading padding — single ps-* per cell, so\n // there's no fight between size + hasStartIcon under Tailwind's flat\n // utility precedence.\n compoundVariants: [\n { size: 'sm', hasStartIcon: false, class: 'ds:ps-[var(--spacing-sm)]' },\n { size: 'md', hasStartIcon: false, class: 'ds:ps-[var(--spacing-sm)]' },\n { size: 'lg', hasStartIcon: false, class: 'ds:ps-[var(--spacing-md)]' },\n { size: 'sm', hasStartIcon: true, class: 'ds:ps-[var(--spacing-xs)]' },\n { size: 'md', hasStartIcon: true, class: 'ds:ps-[var(--spacing-xs)]' },\n { size: 'lg', hasStartIcon: true, class: 'ds:ps-[var(--spacing-sm)]' },\n ],\n defaultVariants: {\n intent: 'default',\n size: 'md',\n wrap: false,\n hasStartIcon: false,\n },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Leading icon slot */\n/* ------------------------------------------------------------------ */\n\nconst startIconVariants = cva(\n [\n 'ds:inline-flex ds:items-center ds:justify-center ds:shrink-0',\n 'ds:text-muted-foreground',\n 'ds:[&_svg]:size-4',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:ps-[var(--spacing-sm)]',\n md: 'ds:ps-[var(--spacing-sm)]',\n lg: 'ds:ps-[var(--spacing-md)]',\n },\n },\n defaultVariants: { size: 'md' },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Trailing button wrapper */\n/* */\n/* The button visually attaches to the field by removing its own focus */\n/* ring (the wrapper paints `focus-within`) and rounding only the */\n/* trailing inline-end corners. */\n/* ------------------------------------------------------------------ */\n\nconst copyButtonVariants = cva(\n [\n 'ds:shrink-0 ds:rounded-none',\n 'ds:focus-visible:outline-none',\n 'ds:h-full',\n 'ds:gap-[var(--spacing-xs)]',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Props */\n/* ------------------------------------------------------------------ */\n\ntype FieldSize = NonNullable<VariantProps<typeof fieldVariants>['size']>;\ntype ValueIntent = NonNullable<VariantProps<typeof valueVariants>['intent']>;\n\nexport interface CopyFieldProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'children' | 'onCopy'\n> {\n /** The value displayed in the read-only field and copied on click. */\n value: string;\n /** Field height + padding. Mirrors TextInput sizes. */\n size?: FieldSize;\n /**\n * `primary` tints the value text with `--primary` — matches the\n * link-style emphasis used by the telehealth showSession page.\n */\n intent?: ValueIntent;\n /**\n * Leading icon slot, decorative. Use `lucide-react` icons like\n * `<Link2 />` for a URL, `<KeyRound />` for a token.\n */\n startIcon?: ReactNode;\n /**\n * `false` (default) truncates long values with ellipsis on a single\n * line. `true` allows wrap with `overflow-wrap: anywhere`.\n */\n wrap?: boolean;\n /** Override the default 'Copy' button label. */\n copyLabel?: ReactNode;\n /** Override the default 'Copied' success-state label. */\n copiedLabel?: ReactNode;\n /** Milliseconds before the button reverts to its default state. Default 2000. */\n copiedDuration?: number;\n /** ARIA label for the read-only textbox. Defaults to the i18n key. */\n ariaLabel?: string;\n /** Fires once after a successful clipboard write. */\n onCopy?: (value: string) => void;\n /** Greys both the field and the button; the button doesn't fire onCopy. */\n disabled?: boolean;\n}\n\n/* ------------------------------------------------------------------ */\n/* CopyField */\n/* ------------------------------------------------------------------ */\n\nexport const CopyField = forwardRef<HTMLDivElement, CopyFieldProps>(\n (\n {\n value,\n size = 'md',\n intent = 'default',\n startIcon,\n wrap = false,\n copyLabel,\n copiedLabel,\n copiedDuration = 2000,\n ariaLabel,\n onCopy,\n disabled = false,\n className,\n id,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation();\n\n const valueRef = useRef(value);\n valueRef.current = value;\n const onCopyRef = useRef(onCopy);\n onCopyRef.current = onCopy;\n\n // Drive status + auto-reset from the shared hook. The custom `writer`\n // preserves CopyField's legacy `document.execCommand('copy')` fallback\n // for non-HTTPS / older-browser contexts.\n const { status, copy } = useCopyToClipboard({\n resetAfterMs: copiedDuration,\n writer: copyToClipboard,\n });\n const copied = status === 'copied';\n const copiedRef = useRef(false);\n copiedRef.current = copied;\n\n // i18n-aware live-region text mirrors the hook status — `copied` →\n // success message, `error` → failure message, `idle` → clear.\n const [liveRegionText, setLiveRegionText] = useState('');\n useEffect(() => {\n if (status === 'copied') {\n setLiveRegionText(t('copyField.copySuccess'));\n } else if (status === 'error') {\n setLiveRegionText(t('copyField.copyFailed'));\n } else {\n setLiveRegionText('');\n }\n }, [status, t]);\n\n const handleCopy = useCallback(async (): Promise<boolean> => {\n if (disabled) return false;\n const ok = await copy(valueRef.current);\n if (ok) onCopyRef.current?.(valueRef.current);\n return ok;\n }, [disabled, copy]);\n\n const handleButtonClick = useCallback(() => {\n void handleCopy();\n }, [handleCopy]);\n\n /* -------------------------------------------------------------- */\n /* Agent handle — read value + trigger copy + check transient state */\n /* -------------------------------------------------------------- */\n\n const agentHandle = useMemo<CopyFieldHandle>(\n () => ({\n getValue: () => valueRef.current,\n copy: () => handleCopy(),\n isCopied: () => copiedRef.current,\n }),\n [handleCopy],\n );\n useAgentRegistration(copyFieldAgent, agentHandle, id);\n\n const resolvedAriaLabel = ariaLabel ?? t('copyField.valueLabel');\n const resolvedCopyText = copyLabel ?? t('copyField.copy');\n const resolvedCopiedText = copiedLabel ?? t('copyField.copied');\n // `aria-label` must be a string; when the consumer passes a non-string\n // ReactNode for copyLabel / copiedLabel we fall back to the translated\n // default so AT users still hear a coherent name.\n const buttonAccessibleLabel = copied\n ? typeof resolvedCopiedText === 'string'\n ? resolvedCopiedText\n : t('copyField.copied')\n : typeof resolvedCopyText === 'string'\n ? resolvedCopyText\n : t('copyField.copy');\n\n return (\n <div\n ref={ref}\n className={fieldVariants({ size, disabled, className })}\n data-component=\"copy-field\"\n data-component-id={id}\n data-copied={copied ? 'true' : undefined}\n {...rest}\n >\n {startIcon ? (\n <span aria-hidden=\"true\" className={startIconVariants({ size })}>\n {startIcon}\n </span>\n ) : null}\n <input\n id={id}\n type=\"text\"\n readOnly\n value={value}\n disabled={disabled}\n aria-label={resolvedAriaLabel}\n className={valueVariants({\n intent,\n size,\n wrap,\n hasStartIcon: Boolean(startIcon),\n })}\n />\n <Button\n type=\"button\"\n intent=\"ghost\"\n size={size}\n onClick={handleButtonClick}\n disabled={disabled}\n aria-label={buttonAccessibleLabel}\n className={copyButtonVariants()}\n startIcon={\n copied ? <Check aria-hidden=\"true\" /> : <Copy aria-hidden=\"true\" />\n }\n >\n <span className=\"type-label\">\n {copied ? resolvedCopiedText : resolvedCopyText}\n </span>\n </Button>\n <span role=\"status\" aria-live=\"polite\" className=\"ds:sr-only\">\n {liveRegionText}\n </span>\n </div>\n );\n },\n);\n\nCopyField.displayName = 'CopyField';\n"],"names":["copyFieldAgent","handle","copyToClipboard","text","_a","textarea","ok","fieldVariants","cva","valueVariants","startIconVariants","copyButtonVariants","CopyField","forwardRef","value","size","intent","startIcon","wrap","copyLabel","copiedLabel","copiedDuration","ariaLabel","onCopy","disabled","className","id","rest","ref","useTranslation","valueRef","useRef","onCopyRef","status","copy","useCopyToClipboard","copied","copiedRef","liveRegionText","setLiveRegionText","useState","useEffect","handleCopy","useCallback","handleButtonClick","agentHandle","useMemo","useAgentRegistration","resolvedAriaLabel","resolvedCopyText","resolvedCopiedText","buttonAccessibleLabel","jsxs","jsx","Button","Check","Copy"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"copy-field-fYKpl6aN.js","sources":["../../src/components/copy-field/copy-field.agent.ts","../../src/components/copy-field/copy-field.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — CopyField. */\n/* */\n/* See `src/docs/26-agent-readiness.mdx` for the contract. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\n\n/**\n * Imperative handle for CopyField — agents can read the value and trigger a\n * programmatic copy. State stays scoped to identifiers + transient UI state;\n * never PHI (per PRS §Security).\n */\nexport interface CopyFieldHandle {\n /** Returns the read-only value currently displayed. */\n getValue: () => string;\n /** Triggers the clipboard write side-effect. */\n copy: () => Promise<boolean>;\n /** Returns true for the brief window after a successful copy. */\n isCopied: () => boolean;\n}\n\nexport const copyFieldAgent: AgentAdapter<CopyFieldHandle> = {\n id: 'copy-field',\n capabilities: ['copy'],\n state: {\n value: {\n type: 'string',\n descriptionKey: 'ui.agent.copyField.state.value',\n description: 'The value displayed in the read-only field.',\n read: (handle) => handle.getValue(),\n },\n copied: {\n type: 'boolean',\n descriptionKey: 'ui.agent.copyField.state.copied',\n description: 'True for the brief window after a successful copy.',\n read: (handle) => handle.isCopied(),\n },\n },\n actions: {\n copy: {\n // Writes the value to the system clipboard — reaches outside this UI.\n safety: 'write',\n openWorld: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the clipboard write succeeded.',\n },\n descriptionKey: 'ui.agent.copyField.actions.copy',\n description: 'Programmatically trigger the clipboard write.',\n invoke: (handle) => handle.copy(),\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'copy-field',\n description:\n 'Marks the CopyField root. The trailing button uses `aria-label` keyed off the copy / copied state.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop, when provided.',\n },\n },\n};\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Check, Copy } from 'lucide-react';\nimport { Button } from '../button/button';\nimport { useAgentRegistration } from '../../agent';\nimport { useCopyToClipboard } from '../../hooks/use-copy-to-clipboard';\nimport { copyFieldAgent, type CopyFieldHandle } from './copy-field.agent';\n\n/* ------------------------------------------------------------------ */\n/* Clipboard helper */\n/* */\n/* `navigator.clipboard.writeText` is the modern path. The fallback */\n/* covers older browsers and insecure contexts via a synthesised */\n/* textarea + `document.execCommand('copy')`. The off-screen position */\n/* uses imperative DOM `.style` assignments — those are NOT JSX inline */\n/* styles and don't violate constraint §3. */\n/* ------------------------------------------------------------------ */\n\nasync function copyToClipboard(text: string): Promise<boolean> {\n if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch {\n // fall through to legacy path\n }\n }\n if (typeof document === 'undefined') return false;\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.setAttribute('readonly', '');\n // Imperative DOM style — not a JSX inline-style violation. We use\n // `setProperty('inset-inline-start', …)` so the hidden textarea stays\n // logically off-screen in both LTR and RTL contexts.\n textarea.style.position = 'absolute';\n textarea.style.setProperty('inset-inline-start', '-9999px');\n document.body.appendChild(textarea);\n textarea.select();\n let ok = false;\n try {\n ok = document.execCommand('copy');\n } catch {\n ok = false;\n }\n document.body.removeChild(textarea);\n return ok;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA — outer wrapper */\n/* */\n/* Mirrors the shared input-surface chrome (border + halo shadow) so */\n/* CopyField sits inline next to TextInput / Combobox in forms without */\n/* visual drift. Logical paddings only. `ds:focus-within` paints the */\n/* ring when the trailing button or the embedded input receives focus. */\n/* ------------------------------------------------------------------ */\n\nconst fieldVariants = cva(\n [\n 'ds:inline-flex ds:items-stretch ds:w-full',\n 'ds:rounded-[var(--radius-sm)] ds:bg-input ds:text-foreground',\n 'ds:border ds:border-border',\n 'ds:shadow-[var(--shadow-input)]',\n 'ds:focus-within:outline-[length:var(--focus-ring-width)] ds:focus-within:outline-solid',\n 'ds:focus-within:outline-ring ds:focus-within:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-within:outline-[CanvasText]',\n 'ds:transition-[colors,box-shadow] ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:overflow-hidden',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:h-8 ds:text-[var(--font-size-sm)]',\n md: 'ds:h-[var(--min-target-size)] ds:text-[var(--font-size-base)]',\n lg: 'ds:h-12 ds:text-[var(--font-size-lg)]',\n },\n disabled: {\n true: 'ds:opacity-50 ds:cursor-not-allowed',\n false: '',\n },\n },\n defaultVariants: { size: 'md', disabled: false },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* CVA — value <input> styling */\n/* ------------------------------------------------------------------ */\n\nconst valueVariants = cva(\n [\n 'ds:flex-1 ds:min-w-0 ds:bg-transparent ds:border-0 ds:outline-none',\n 'ds:text-foreground',\n 'ds:disabled:cursor-not-allowed',\n ].join(' '),\n {\n variants: {\n intent: {\n default: '',\n // `--primary` is calibrated for foreground use (violet-500 light,\n // magenta-500 dark) — both pass AA against their input backgrounds.\n primary: 'ds:text-primary ds:font-medium',\n },\n size: {\n sm: 'ds:text-[var(--font-size-sm)]',\n md: 'ds:text-[var(--font-size-base)]',\n lg: 'ds:text-[var(--font-size-lg)]',\n },\n wrap: {\n true: 'ds:[overflow-wrap:anywhere] ds:whitespace-normal',\n false: 'ds:overflow-hidden ds:text-ellipsis ds:whitespace-nowrap',\n },\n hasStartIcon: {\n true: '',\n false: '',\n },\n },\n // Explicit pairs decide the leading padding — single ps-* per cell, so\n // there's no fight between size + hasStartIcon under Tailwind's flat\n // utility precedence.\n compoundVariants: [\n { size: 'sm', hasStartIcon: false, class: 'ds:ps-[var(--spacing-sm)]' },\n { size: 'md', hasStartIcon: false, class: 'ds:ps-[var(--spacing-sm)]' },\n { size: 'lg', hasStartIcon: false, class: 'ds:ps-[var(--spacing-md)]' },\n { size: 'sm', hasStartIcon: true, class: 'ds:ps-[var(--spacing-xs)]' },\n { size: 'md', hasStartIcon: true, class: 'ds:ps-[var(--spacing-xs)]' },\n { size: 'lg', hasStartIcon: true, class: 'ds:ps-[var(--spacing-sm)]' },\n ],\n defaultVariants: {\n intent: 'default',\n size: 'md',\n wrap: false,\n hasStartIcon: false,\n },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Leading icon slot */\n/* ------------------------------------------------------------------ */\n\nconst startIconVariants = cva(\n [\n 'ds:inline-flex ds:items-center ds:justify-center ds:shrink-0',\n 'ds:text-muted-foreground',\n 'ds:[&_svg]:size-4',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:ps-[var(--spacing-sm)]',\n md: 'ds:ps-[var(--spacing-sm)]',\n lg: 'ds:ps-[var(--spacing-md)]',\n },\n },\n defaultVariants: { size: 'md' },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Trailing button wrapper */\n/* */\n/* The button visually attaches to the field by removing its own focus */\n/* ring (the wrapper paints `focus-within`) and rounding only the */\n/* trailing inline-end corners. */\n/* ------------------------------------------------------------------ */\n\nconst copyButtonVariants = cva(\n [\n 'ds:shrink-0 ds:rounded-none',\n 'ds:focus-visible:outline-none',\n 'ds:h-full',\n 'ds:gap-[var(--spacing-xs)]',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Props */\n/* ------------------------------------------------------------------ */\n\ntype FieldSize = NonNullable<VariantProps<typeof fieldVariants>['size']>;\ntype ValueIntent = NonNullable<VariantProps<typeof valueVariants>['intent']>;\n\nexport interface CopyFieldProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'children' | 'onCopy'\n> {\n /** The value displayed in the read-only field and copied on click. */\n value: string;\n /** Field height + padding. Mirrors TextInput sizes. */\n size?: FieldSize;\n /**\n * `primary` tints the value text with `--primary` — matches the\n * link-style emphasis used by the telehealth showSession page.\n */\n intent?: ValueIntent;\n /**\n * Leading icon slot, decorative. Use `lucide-react` icons like\n * `<Link2 />` for a URL, `<KeyRound />` for a token.\n */\n startIcon?: ReactNode;\n /**\n * `false` (default) truncates long values with ellipsis on a single\n * line. `true` allows wrap with `overflow-wrap: anywhere`.\n */\n wrap?: boolean;\n /** Override the default 'Copy' button label. */\n copyLabel?: ReactNode;\n /** Override the default 'Copied' success-state label. */\n copiedLabel?: ReactNode;\n /** Milliseconds before the button reverts to its default state. Default 2000. */\n copiedDuration?: number;\n /** ARIA label for the read-only textbox. Defaults to the i18n key. */\n ariaLabel?: string;\n /** Fires once after a successful clipboard write. */\n onCopy?: (value: string) => void;\n /** Greys both the field and the button; the button doesn't fire onCopy. */\n disabled?: boolean;\n}\n\n/* ------------------------------------------------------------------ */\n/* CopyField */\n/* ------------------------------------------------------------------ */\n\nexport const CopyField = forwardRef<HTMLDivElement, CopyFieldProps>(\n (\n {\n value,\n size = 'md',\n intent = 'default',\n startIcon,\n wrap = false,\n copyLabel,\n copiedLabel,\n copiedDuration = 2000,\n ariaLabel,\n onCopy,\n disabled = false,\n className,\n id,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation();\n\n const valueRef = useRef(value);\n valueRef.current = value;\n const onCopyRef = useRef(onCopy);\n onCopyRef.current = onCopy;\n\n // Drive status + auto-reset from the shared hook. The custom `writer`\n // preserves CopyField's legacy `document.execCommand('copy')` fallback\n // for non-HTTPS / older-browser contexts.\n const { status, copy } = useCopyToClipboard({\n resetAfterMs: copiedDuration,\n writer: copyToClipboard,\n });\n const copied = status === 'copied';\n const copiedRef = useRef(false);\n copiedRef.current = copied;\n\n // i18n-aware live-region text mirrors the hook status — `copied` →\n // success message, `error` → failure message, `idle` → clear.\n const [liveRegionText, setLiveRegionText] = useState('');\n useEffect(() => {\n if (status === 'copied') {\n setLiveRegionText(t('copyField.copySuccess'));\n } else if (status === 'error') {\n setLiveRegionText(t('copyField.copyFailed'));\n } else {\n setLiveRegionText('');\n }\n }, [status, t]);\n\n const handleCopy = useCallback(async (): Promise<boolean> => {\n if (disabled) return false;\n const ok = await copy(valueRef.current);\n if (ok) onCopyRef.current?.(valueRef.current);\n return ok;\n }, [disabled, copy]);\n\n const handleButtonClick = useCallback(() => {\n void handleCopy();\n }, [handleCopy]);\n\n /* -------------------------------------------------------------- */\n /* Agent handle — read value + trigger copy + check transient state */\n /* -------------------------------------------------------------- */\n\n const agentHandle = useMemo<CopyFieldHandle>(\n () => ({\n getValue: () => valueRef.current,\n copy: () => handleCopy(),\n isCopied: () => copiedRef.current,\n }),\n [handleCopy],\n );\n useAgentRegistration(copyFieldAgent, agentHandle, id);\n\n const resolvedAriaLabel = ariaLabel ?? t('copyField.valueLabel');\n const resolvedCopyText = copyLabel ?? t('copyField.copy');\n const resolvedCopiedText = copiedLabel ?? t('copyField.copied');\n // `aria-label` must be a string; when the consumer passes a non-string\n // ReactNode for copyLabel / copiedLabel we fall back to the translated\n // default so AT users still hear a coherent name.\n const buttonAccessibleLabel = copied\n ? typeof resolvedCopiedText === 'string'\n ? resolvedCopiedText\n : t('copyField.copied')\n : typeof resolvedCopyText === 'string'\n ? resolvedCopyText\n : t('copyField.copy');\n\n return (\n <div\n ref={ref}\n className={fieldVariants({ size, disabled, className })}\n data-component=\"copy-field\"\n data-component-id={id}\n data-copied={copied ? 'true' : undefined}\n {...rest}\n >\n {startIcon ? (\n <span aria-hidden=\"true\" className={startIconVariants({ size })}>\n {startIcon}\n </span>\n ) : null}\n <input\n id={id}\n type=\"text\"\n readOnly\n value={value}\n disabled={disabled}\n aria-label={resolvedAriaLabel}\n className={valueVariants({\n intent,\n size,\n wrap,\n hasStartIcon: Boolean(startIcon),\n })}\n />\n <Button\n type=\"button\"\n intent=\"ghost\"\n size={size}\n onClick={handleButtonClick}\n disabled={disabled}\n aria-label={buttonAccessibleLabel}\n className={copyButtonVariants()}\n startIcon={\n copied ? <Check aria-hidden=\"true\" /> : <Copy aria-hidden=\"true\" />\n }\n >\n <span className=\"type-label\">\n {copied ? resolvedCopiedText : resolvedCopyText}\n </span>\n </Button>\n <span role=\"status\" aria-live=\"polite\" className=\"ds:sr-only\">\n {liveRegionText}\n </span>\n </div>\n );\n },\n);\n\nCopyField.displayName = 'CopyField';\n"],"names":["copyFieldAgent","handle","copyToClipboard","text","_a","textarea","ok","fieldVariants","cva","valueVariants","startIconVariants","copyButtonVariants","CopyField","forwardRef","value","size","intent","startIcon","wrap","copyLabel","copiedLabel","copiedDuration","ariaLabel","onCopy","disabled","className","id","rest","ref","useTranslation","valueRef","useRef","onCopyRef","status","copy","useCopyToClipboard","copied","copiedRef","liveRegionText","setLiveRegionText","useState","useEffect","handleCopy","useCallback","handleButtonClick","agentHandle","useMemo","useAgentRegistration","resolvedAriaLabel","resolvedCopyText","resolvedCopiedText","buttonAccessibleLabel","jsxs","jsx","Button","Check","Copy"],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@ import { D as Y } from "./date-picker-Bp64zk2p.js";
|
|
|
8
8
|
import { N as H } from "./number-input-Cgu2TtA8.js";
|
|
9
9
|
import { C as M } from "./card-DPmk26CL.js";
|
|
10
10
|
import { B as T } from "./badge-sTusUqZD.js";
|
|
11
|
-
import { I as U } from "./insert-result-
|
|
11
|
+
import { I as U } from "./insert-result-LCNTskNJ.js";
|
|
12
12
|
import { a as m, c as V } from "./date-picker-variants-pKAJfnWr.js";
|
|
13
13
|
import { C as J } from "./check-DrFSN__t.js";
|
|
14
14
|
import { H as Q } from "./heart--qCA4ffe.js";
|
|
@@ -422,4 +422,4 @@ export {
|
|
|
422
422
|
ie as L,
|
|
423
423
|
se as p
|
|
424
424
|
};
|
|
425
|
-
//# sourceMappingURL=cycle-calculator-
|
|
425
|
+
//# sourceMappingURL=cycle-calculator-DzgO1vzP.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cycle-calculator-DJZYvNhw.js","sources":["../../node_modules/lucide-react/dist/esm/icons/droplet.mjs","../../src/components/cycle-calculator/cycle-calculator.agent.ts","../../src/components/cycle-calculator/cycle.ts","../../src/components/cycle-calculator/cycle-calculator.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M12 22a7 7 0 0 0 7-7c0-2-1-3.9-3-5.5s-3.5-4-4-6.5c-.5 2.5-2 4.9-4 6.5C6 11.1 5 13 5 15a7 7 0 0 0 7 7z\",\n key: \"c7niix\"\n }\n ]\n];\nconst Droplet = createLucideIcon(\"droplet\", __iconNode);\n\nexport { __iconNode, Droplet as default };\n//# sourceMappingURL=droplet.mjs.map\n","/* -------------------------------------------------------------------- */\n/* Agent adapter — CycleCalculator. */\n/* */\n/* Menstrual-cycle predictor: takes a last-period date (+ optional cycle */\n/* and period lengths) and computes ovulation, fertile window and the */\n/* next few periods. The agent surface is the three inputs plus the */\n/* computed prediction; the handle is the curated `CycleCalculatorHandle` */\n/* (the public `ref` stays the root <div>, exactly as `slider.tsx` and */\n/* `bmi-calculator.tsx` keep theirs). */\n/* */\n/* Dates cross the boundary as local-time `yyyy-MM-dd` strings, never */\n/* `Date` objects, so nothing shifts a day under JSON/UTC serialisation. */\n/* */\n/* PHI (§7): never exposes patient identity — the slots return the */\n/* operator's own structural inputs (a date, two day counts) and the */\n/* dates derived from them, the same \"filter model\" precedent §7 sets. */\n/* See `src/docs/26-agent-readiness.mdx`. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { CycleCalculatorHandle } from './cycle-calculator';\n\n/** Shared JSON Schema fragment for a local-time calendar date. */\nconst isoDate = {\n type: 'string',\n pattern: '^\\\\d{4}-\\\\d{2}-\\\\d{2}$',\n} as const;\n\nexport const cycleCalculatorAgent: AgentAdapter<CycleCalculatorHandle> = {\n id: 'cycle-calculator',\n // set_value → the three `set_*` actions + the `inputs` state slot.\n capabilities: ['set_value'],\n state: {\n inputs: {\n type: '{ lastPeriodStart: string | null, cycleLength: number | null, periodLength: number | null }',\n descriptionKey: 'ui.agent.cycleCalculator.state.inputs',\n description:\n 'The three cycle inputs as entered — last-period start date (`yyyy-MM-dd`), average cycle length in days, and period (bleed) length in days. Null where unset.',\n read: (handle) => handle.getInputs(),\n },\n result: {\n type: '{ ovulation: string, fertileWindow: { start: string, end: string }, nextPeriod: string, periodRange: { start: string, end: string } | null, upcomingPeriods: string[] } | null',\n descriptionKey: 'ui.agent.cycleCalculator.state.result',\n description:\n 'Computed prediction — ovulation date, fertile window, next period, current bleed range and the next few period starts, all `yyyy-MM-dd`. Null until a last-period date is set.',\n read: (handle) => handle.getResult(),\n },\n },\n actions: {\n set_last_period: {\n // Drives the same local input state a user types into; nothing is\n // persisted to a record, and the value is reversible in the same UI.\n safety: 'write',\n argsType: '{ date: string | null }',\n argsSchema: {\n type: 'object',\n properties: {\n date: {\n oneOf: [\n { ...isoDate, description: 'Local calendar date, `yyyy-MM-dd`.' },\n { type: 'null' },\n ],\n description:\n 'Start date of the last period, or null to clear it. Must not be in the future.',\n },\n },\n required: ['date'],\n additionalProperties: false,\n },\n idempotent: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the date was applied.',\n },\n errors: [\n 'Returns false for an unparseable date or a date in the future — the on-screen DatePicker caps at today.',\n ],\n examples: [\n { args: { date: '2026-08-01' }, note: 'Last period started 1 August.' },\n ],\n descriptionKey: 'ui.agent.cycleCalculator.actions.setLastPeriod',\n description:\n 'Set the start date of the last period. This is the only required input — the prediction stays null without it.',\n invoke: (handle, args: { date: string | null }) =>\n handle.setLastPeriod(args.date),\n },\n set_cycle_length: {\n safety: 'write',\n argsType: '{ days: number | null }',\n argsSchema: {\n type: 'object',\n properties: {\n days: {\n oneOf: [\n { type: 'integer', minimum: 20, maximum: 45 },\n { type: 'null' },\n ],\n description:\n 'Average cycle length in days (20–45), or null to fall back to the 28-day default.',\n },\n },\n required: ['days'],\n additionalProperties: false,\n },\n idempotent: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the value was applied.',\n },\n errors: [\n 'Returns false outside 20–45 days — the same bounds the on-screen NumberInput enforces.',\n ],\n descriptionKey: 'ui.agent.cycleCalculator.actions.setCycleLength',\n description:\n 'Set the average cycle length in days. Shifts ovulation, the fertile window and every upcoming period.',\n invoke: (handle, args: { days: number | null }) =>\n handle.setCycleLength(args.days),\n },\n set_period_length: {\n safety: 'write',\n argsType: '{ days: number | null }',\n argsSchema: {\n type: 'object',\n properties: {\n days: {\n oneOf: [\n { type: 'integer', minimum: 1, maximum: 14 },\n { type: 'null' },\n ],\n description:\n 'Period (bleed) length in days (1–14), or null to omit the bleed range.',\n },\n },\n required: ['days'],\n additionalProperties: false,\n },\n idempotent: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the value was applied.',\n },\n errors: [\n 'Returns false outside 1–14 days — the same bounds the on-screen NumberInput enforces.',\n ],\n descriptionKey: 'ui.agent.cycleCalculator.actions.setPeriodLength',\n description:\n 'Set the period (bleed) length in days. Optional — it only adds the current bleed range to the result.',\n invoke: (handle, args: { days: number | null }) =>\n handle.setPeriodLength(args.days),\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'cycle-calculator',\n description: 'Marks the CycleCalculator wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the id prop. Also the registry key — without an `id` the instance does not register and only the DOM channel works.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* Menstrual-cycle prediction — pure, framework-free, unit-testable. */\n/* */\n/* Uses the standard fixed-luteal-phase model: ovulation falls ~14 days */\n/* before the next period, so on a cycle of length L ovulation is day */\n/* (L − 14). The fertile window spans the 5 days before ovulation */\n/* (sperm survival) through 1 day after (oocyte viability). */\n/* ------------------------------------------------------------------ */\n\nimport { addDays } from 'date-fns';\n\n/** Standard menstrual-cycle length. */\nexport const DEFAULT_CYCLE_LENGTH = 28;\n/** Luteal phase is biologically near-constant at ~14 days. */\nexport const LUTEAL_PHASE_DAYS = 14;\n/** Sperm survive up to ~5 days before ovulation. */\nexport const FERTILE_DAYS_BEFORE = 5;\n/** The oocyte is viable ~1 day after ovulation. */\nexport const FERTILE_DAYS_AFTER = 1;\n\nexport interface CycleInput {\n /** First day of the most recent period. */\n lastPeriodStart: Date;\n /** Average cycle length in days. Defaults to 28. */\n cycleLength?: number;\n /** Period (bleed) length in days. Optional — used for the period range. */\n periodLength?: number;\n}\n\nexport interface DateRange {\n start: Date;\n end: Date;\n}\n\nexport interface CyclePrediction {\n /** Start date of the next period. */\n nextPeriod: Date;\n /** Estimated ovulation date. */\n ovulation: Date;\n /** Fertile window (5 days before ovulation → 1 day after). */\n fertileWindow: DateRange;\n /** Start dates of the next few periods (length = `occurrences`). */\n upcomingPeriods: Date[];\n /**\n * The current period's bleed range (first day → last day), or `null` when no\n * `periodLength` was given.\n */\n periodRange: DateRange | null;\n}\n\n/**\n * Predict ovulation, the fertile window and upcoming periods from the last\n * period's start date. `occurrences` controls how many future periods to\n * list (default 3).\n */\nexport function predictCycle(\n input: CycleInput,\n occurrences = 3,\n): CyclePrediction {\n const cycle = input.cycleLength ?? DEFAULT_CYCLE_LENGTH;\n const { lastPeriodStart } = input;\n\n const ovulation = addDays(lastPeriodStart, cycle - LUTEAL_PHASE_DAYS);\n const fertileWindow: DateRange = {\n start: addDays(ovulation, -FERTILE_DAYS_BEFORE),\n end: addDays(ovulation, FERTILE_DAYS_AFTER),\n };\n const nextPeriod = addDays(lastPeriodStart, cycle);\n const upcomingPeriods = Array.from({ length: occurrences }, (_, i) =>\n addDays(lastPeriodStart, cycle * (i + 1)),\n );\n const periodRange: DateRange | null =\n input.periodLength && input.periodLength > 0\n ? {\n start: lastPeriodStart,\n end: addDays(lastPeriodStart, input.periodLength - 1),\n }\n : null;\n\n return { nextPeriod, ovulation, fertileWindow, upcomingPeriods, periodRange };\n}\n","/* ------------------------------------------------------------------ */\n/* CycleCalculator — predict ovulation, fertile window and upcoming */\n/* periods from the last period's start date. */\n/* */\n/* Maths lives in `./cycle` (pure, separately tested). */\n/* ------------------------------------------------------------------ */\n\nimport { forwardRef, useEffect, useMemo, useRef, useState } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { format, isAfter, parseISO } from 'date-fns';\nimport { Heart, Check, Droplet } from 'lucide-react';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { cycleCalculatorAgent } from './cycle-calculator.agent';\nimport { FormField } from '../form-field';\nimport { DatePicker } from '../date-picker';\nimport { NumberInput } from '../number-input';\nimport { Card } from '../card';\nimport { Badge } from '../badge';\nimport {\n InsertButton,\n type InsertPayload,\n type InsertVariant,\n type InsertMode,\n} from '../_shared/insert-result';\nimport {\n type CyclePrediction,\n predictCycle,\n DEFAULT_CYCLE_LENGTH,\n} from './cycle';\n\nconst rootVariants = cva('ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]', {\n variants: {\n width: { full: 'ds:w-full', auto: 'ds:inline-flex' },\n },\n defaultVariants: { width: 'full' },\n});\n\n/**\n * DS token NAME backing the result-card chip — the fertile window is the\n * headline fertility datum, shown on screen with the `accent` Badge variant\n * (which fills `--accent`). The card chip reuses that token so the inserted\n * PNG chip matches the on-screen fertile-window badge.\n */\nconst HIGHLIGHT_TOKEN = '--accent';\n\n/* ------------------------------------------------------------------ */\n/* Agent boundary */\n/* */\n/* Dates cross the agent boundary as local-time `yyyy-MM-dd` strings, */\n/* never `Date` objects — a Date JSON-serialises to UTC and silently */\n/* shifts the day for anyone east or west of Greenwich. */\n/* ------------------------------------------------------------------ */\n\nconst toIsoDate = (d: Date): string => format(d, 'yyyy-MM-dd');\n\nconst fromIsoDate = (iso: string): Date | null => {\n const d = parseISO(iso);\n return Number.isNaN(d.getTime()) ? null : d;\n};\n\n/** UI input bounds, mirrored by the agent handle so it can't out-type a user. */\nconst CYCLE_LENGTH_RANGE = { min: 20, max: 45 } as const;\nconst PERIOD_LENGTH_RANGE = { min: 1, max: 14 } as const;\n\nconst inRange = (\n n: number | null,\n { min, max }: { min: number; max: number },\n): boolean => n === null || (Number.isFinite(n) && n >= min && n <= max);\n\n/** `CyclePrediction` projected onto the agent boundary — ISO dates, no Dates. */\nexport interface CyclePredictionSnapshot {\n /** Estimated ovulation date, `yyyy-MM-dd`. */\n ovulation: string;\n /** Fertile window, `yyyy-MM-dd` endpoints. */\n fertileWindow: { start: string; end: string };\n /** Start of the next period, `yyyy-MM-dd`. */\n nextPeriod: string;\n /** Current period's bleed range, or null when no period length was given. */\n periodRange: { start: string; end: string } | null;\n /** Start dates of the next few periods, `yyyy-MM-dd`. */\n upcomingPeriods: string[];\n}\n\n/**\n * Curated imperative handle for agent / external automation. Reads the three\n * cycle inputs and the computed prediction, and drives the inputs the way a\n * user would. Never exposes patient identity — only structural dates and day\n * counts. Consumed by `cycle-calculator.agent.ts`; the public `ref` stays the\n * root DOM element.\n */\nexport interface CycleCalculatorHandle {\n /** Current inputs — ISO date + day counts, or null when unset. */\n getInputs: () => {\n lastPeriodStart: string | null;\n cycleLength: number | null;\n periodLength: number | null;\n };\n /** Computed prediction, or null until a last-period date is set. */\n getResult: () => CyclePredictionSnapshot | null;\n /** Set the last period's start date (`yyyy-MM-dd`, not in the future). */\n setLastPeriod: (isoDate: string | null) => boolean;\n /** Set the average cycle length in days (20–45). */\n setCycleLength: (days: number | null) => boolean;\n /** Set the period (bleed) length in days (1–14). */\n setPeriodLength: (days: number | null) => boolean;\n}\n\nexport interface CycleCalculatorProps extends VariantProps<\n typeof rootVariants\n> {\n /** Initial cycle length in days. Defaults to 28. */\n defaultCycleLength?: number;\n /** Fires whenever a prediction can be computed (and `null` when it can't). */\n onResultChange?: (result: CyclePrediction | null) => void;\n /** When provided, shows the result-action buttons that emit / copy the result. */\n onInsert?: (payload: InsertPayload) => void;\n /**\n * Which verb the result button performs. Defaults to `'insert'`.\n * Use `'copy'` in an app-shell surface (no editor to insert into) — the\n * button writes the result to the clipboard as a multi-format `ClipboardItem`.\n */\n insertVariant?: InsertVariant;\n /** `copy` variant only — fired after a successful clipboard write. */\n onCopy?: (mode: InsertMode) => void;\n /** `copy` variant only — fired if the clipboard write can't proceed. */\n onError?: (error: unknown) => void;\n /**\n * Brand wordmark printed in the inserted/copied result-card footer.\n * Omitted → no brand line (and no footer hairline); a string → that custom\n * brand; `false` → no brand line. Brand is opt-in.\n */\n insertBrand?: string | false;\n /** Opaque instance id, emitted as `data-component-id`. */\n id?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n}\n\nexport const CycleCalculator = forwardRef<HTMLDivElement, CycleCalculatorProps>(\n (\n {\n defaultCycleLength = DEFAULT_CYCLE_LENGTH,\n onResultChange,\n onInsert,\n insertVariant = 'insert',\n onCopy,\n onError,\n insertBrand,\n id,\n width,\n className,\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation();\n\n const [lastPeriod, setLastPeriod] = useState<Date | undefined>(undefined);\n const [cycleLength, setCycleLength] = useState<number | null>(\n defaultCycleLength,\n );\n const [periodLength, setPeriodLength] = useState<number | null>(null);\n\n const result = useMemo<CyclePrediction | null>(() => {\n if (!lastPeriod) return null;\n return predictCycle({\n lastPeriodStart: lastPeriod,\n cycleLength: cycleLength ?? DEFAULT_CYCLE_LENGTH,\n periodLength: periodLength ?? undefined,\n });\n }, [lastPeriod, cycleLength, periodLength]);\n\n const dateFormatter = useMemo(\n () => new Intl.DateTimeFormat(i18n.language, { dateStyle: 'medium' }),\n [i18n.language],\n );\n\n useEffect(() => {\n onResultChange?.(result);\n }, [result, onResultChange]);\n\n const today = useMemo(() => new Date(), []);\n\n /* ── Agent handle ────────────────────────────────────────────────── */\n const liveRef = useRef({ lastPeriod, cycleLength, periodLength, result });\n liveRef.current = { lastPeriod, cycleLength, periodLength, result };\n\n const agentHandle = useMemo<CycleCalculatorHandle>(\n () => ({\n getInputs: () => ({\n lastPeriodStart: liveRef.current.lastPeriod\n ? toIsoDate(liveRef.current.lastPeriod)\n : null,\n cycleLength: liveRef.current.cycleLength,\n periodLength: liveRef.current.periodLength,\n }),\n getResult: () => {\n const r = liveRef.current.result;\n if (!r) return null;\n return {\n ovulation: toIsoDate(r.ovulation),\n fertileWindow: {\n start: toIsoDate(r.fertileWindow.start),\n end: toIsoDate(r.fertileWindow.end),\n },\n nextPeriod: toIsoDate(r.nextPeriod),\n periodRange: r.periodRange\n ? {\n start: toIsoDate(r.periodRange.start),\n end: toIsoDate(r.periodRange.end),\n }\n : null,\n upcomingPeriods: r.upcomingPeriods.map(toIsoDate),\n };\n },\n setLastPeriod: (isoDate) => {\n if (isoDate === null) {\n setLastPeriod(undefined);\n return true;\n }\n const parsed = fromIsoDate(isoDate);\n // The DatePicker caps at today; the handle honours the same bound.\n if (!parsed || isAfter(parsed, new Date())) return false;\n setLastPeriod(parsed);\n return true;\n },\n setCycleLength: (days) => {\n if (!inRange(days, CYCLE_LENGTH_RANGE)) return false;\n setCycleLength(days);\n return true;\n },\n setPeriodLength: (days) => {\n if (!inRange(days, PERIOD_LENGTH_RANGE)) return false;\n setPeriodLength(days);\n return true;\n },\n }),\n [],\n );\n useAgentRegistration(cycleCalculatorAgent, agentHandle, id);\n\n const fmt = (d: Date): string => dateFormatter.format(d);\n\n return (\n <div\n ref={ref}\n data-component=\"cycle-calculator\"\n data-component-id={id}\n className={rootVariants({ width, className })}\n >\n <div className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:sm:grid-cols-2\">\n <FormField label={t('cycleCalculator.lastPeriod')}>\n <DatePicker\n value={lastPeriod}\n onChange={setLastPeriod}\n maxDate={today}\n />\n </FormField>\n <FormField\n label={t('cycleCalculator.cycleLength')}\n description={t('cycleCalculator.cycleLengthHint')}\n >\n <NumberInput\n mode=\"integer\"\n min={CYCLE_LENGTH_RANGE.min}\n max={CYCLE_LENGTH_RANGE.max}\n value={cycleLength}\n onChange={setCycleLength}\n />\n </FormField>\n <FormField\n label={t('cycleCalculator.periodLength')}\n description={t('cycleCalculator.periodLengthHint')}\n >\n <NumberInput\n mode=\"integer\"\n min={PERIOD_LENGTH_RANGE.min}\n max={PERIOD_LENGTH_RANGE.max}\n value={periodLength}\n onChange={setPeriodLength}\n />\n </FormField>\n </div>\n\n <p className=\"ds:sr-only\" role=\"status\" aria-live=\"polite\">\n {result\n ? `${t('cycleCalculator.ovulation')}: ${fmt(result.ovulation)}. ${t(\n 'cycleCalculator.nextPeriod',\n )}: ${fmt(result.nextPeriod)}.`\n : ''}\n </p>\n\n {result ? (\n <Card variant=\"elevated\">\n <Card.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <dl className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:sm:grid-cols-3\">\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-xs)] ds:text-center\">\n <dt className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.ovulation')}\n </dt>\n <dd>\n <Badge\n variant=\"success\"\n size=\"lg\"\n leading={<Check aria-hidden />}\n >\n {fmt(result.ovulation)}\n </Badge>\n </dd>\n </div>\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-xs)] ds:text-center\">\n <dt className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.fertileWindow')}\n </dt>\n <dd>\n <Badge\n variant=\"accent\"\n size=\"lg\"\n leading={<Heart aria-hidden />}\n >\n {fmt(result.fertileWindow.start)} –{' '}\n {fmt(result.fertileWindow.end)}\n </Badge>\n </dd>\n </div>\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-xs)] ds:text-center\">\n <dt className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.nextPeriod')}\n </dt>\n <dd>\n <Badge\n variant=\"error\"\n size=\"lg\"\n leading={<Droplet aria-hidden />}\n >\n {fmt(result.nextPeriod)}\n </Badge>\n </dd>\n </div>\n </dl>\n\n {result.periodRange ? (\n <div className=\"ds:flex ds:flex-col ds:items-start ds:gap-[var(--spacing-2xs)]\">\n <span className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.periodRange')}\n </span>\n <span className=\"type-body ds:text-foreground\">\n {fmt(result.periodRange.start)} –{' '}\n {fmt(result.periodRange.end)}\n </span>\n </div>\n ) : null}\n\n <div className=\"ds:flex ds:flex-col ds:items-start ds:gap-[var(--spacing-2xs)]\">\n <span className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.upcomingPeriods')}\n </span>\n <ul className=\"ds:flex ds:flex-wrap ds:gap-x-[var(--spacing-md)] ds:gap-y-[var(--spacing-2xs)]\">\n {result.upcomingPeriods.map((d) => (\n <li\n key={d.getTime()}\n className=\"type-body ds:text-foreground\"\n >\n {fmt(d)}\n </li>\n ))}\n </ul>\n </div>\n\n {insertVariant === 'copy' || onInsert ? (\n <InsertButton\n onInsert={onInsert}\n variant={insertVariant}\n onCopy={onCopy}\n onError={onError}\n card={{\n title: t('insert.title.cycle'),\n icon: 'heart',\n highlight: `${fmt(result.fertileWindow.start)} – ${fmt(\n result.fertileWindow.end,\n )}`,\n // Chip reuses the on-screen fertile-window badge's accent\n // token so the inserted PNG chip matches the screen.\n highlightToken: HIGHLIGHT_TOKEN,\n brand: insertBrand,\n fields: [\n {\n // Ovulation is a predicted date → calendar glyph (the\n // on-screen badge uses a Check tick, which ICON_GEOMETRY\n // does not carry, so the calendar reads the date meaning).\n icon: 'calendar',\n label: t('cycleCalculator.ovulation'),\n value: fmt(result.ovulation),\n },\n {\n // Fertile window → heart glyph, matching the on-screen\n // fertile-window badge's Heart icon.\n icon: 'heart',\n label: t('cycleCalculator.fertileWindow'),\n value: `${fmt(result.fertileWindow.start)} – ${fmt(\n result.fertileWindow.end,\n )}`,\n },\n {\n // Next period → droplets glyph, matching the on-screen\n // next-period badge's Droplet icon.\n icon: 'droplets',\n label: t('cycleCalculator.nextPeriod'),\n value: fmt(result.nextPeriod),\n },\n ],\n }}\n />\n ) : null}\n </Card.Body>\n </Card>\n ) : (\n <p className=\"type-body ds:text-muted-foreground\">\n {t('cycleCalculator.empty')}\n </p>\n )}\n </div>\n );\n },\n);\n\nCycleCalculator.displayName = 'CycleCalculator';\n"],"names":["__iconNode","Droplet","createLucideIcon","isoDate","cycleCalculatorAgent","handle","args","DEFAULT_CYCLE_LENGTH","LUTEAL_PHASE_DAYS","FERTILE_DAYS_AFTER","predictCycle","input","occurrences","cycle","lastPeriodStart","ovulation","addDays","fertileWindow","nextPeriod","upcomingPeriods","_","i","periodRange","rootVariants","cva","HIGHLIGHT_TOKEN","toIsoDate","d","format","fromIsoDate","iso","parseISO","CYCLE_LENGTH_RANGE","PERIOD_LENGTH_RANGE","inRange","n","min","max","CycleCalculator","forwardRef","defaultCycleLength","onResultChange","onInsert","insertVariant","onCopy","onError","insertBrand","id","width","className","ref","t","i18n","useTranslation","lastPeriod","setLastPeriod","useState","cycleLength","setCycleLength","periodLength","setPeriodLength","result","useMemo","dateFormatter","useEffect","today","liveRef","useRef","agentHandle","parsed","isAfter","days","useAgentRegistration","fmt","jsxs","jsx","FormField","DatePicker","NumberInput","Card","Badge","Check","Heart","InsertButton"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"cycle-calculator-DzgO1vzP.js","sources":["../../node_modules/lucide-react/dist/esm/icons/droplet.mjs","../../src/components/cycle-calculator/cycle-calculator.agent.ts","../../src/components/cycle-calculator/cycle.ts","../../src/components/cycle-calculator/cycle-calculator.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M12 22a7 7 0 0 0 7-7c0-2-1-3.9-3-5.5s-3.5-4-4-6.5c-.5 2.5-2 4.9-4 6.5C6 11.1 5 13 5 15a7 7 0 0 0 7 7z\",\n key: \"c7niix\"\n }\n ]\n];\nconst Droplet = createLucideIcon(\"droplet\", __iconNode);\n\nexport { __iconNode, Droplet as default };\n//# sourceMappingURL=droplet.mjs.map\n","/* -------------------------------------------------------------------- */\n/* Agent adapter — CycleCalculator. */\n/* */\n/* Menstrual-cycle predictor: takes a last-period date (+ optional cycle */\n/* and period lengths) and computes ovulation, fertile window and the */\n/* next few periods. The agent surface is the three inputs plus the */\n/* computed prediction; the handle is the curated `CycleCalculatorHandle` */\n/* (the public `ref` stays the root <div>, exactly as `slider.tsx` and */\n/* `bmi-calculator.tsx` keep theirs). */\n/* */\n/* Dates cross the boundary as local-time `yyyy-MM-dd` strings, never */\n/* `Date` objects, so nothing shifts a day under JSON/UTC serialisation. */\n/* */\n/* PHI (§7): never exposes patient identity — the slots return the */\n/* operator's own structural inputs (a date, two day counts) and the */\n/* dates derived from them, the same \"filter model\" precedent §7 sets. */\n/* See `src/docs/26-agent-readiness.mdx`. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { CycleCalculatorHandle } from './cycle-calculator';\n\n/** Shared JSON Schema fragment for a local-time calendar date. */\nconst isoDate = {\n type: 'string',\n pattern: '^\\\\d{4}-\\\\d{2}-\\\\d{2}$',\n} as const;\n\nexport const cycleCalculatorAgent: AgentAdapter<CycleCalculatorHandle> = {\n id: 'cycle-calculator',\n // set_value → the three `set_*` actions + the `inputs` state slot.\n capabilities: ['set_value'],\n state: {\n inputs: {\n type: '{ lastPeriodStart: string | null, cycleLength: number | null, periodLength: number | null }',\n descriptionKey: 'ui.agent.cycleCalculator.state.inputs',\n description:\n 'The three cycle inputs as entered — last-period start date (`yyyy-MM-dd`), average cycle length in days, and period (bleed) length in days. Null where unset.',\n read: (handle) => handle.getInputs(),\n },\n result: {\n type: '{ ovulation: string, fertileWindow: { start: string, end: string }, nextPeriod: string, periodRange: { start: string, end: string } | null, upcomingPeriods: string[] } | null',\n descriptionKey: 'ui.agent.cycleCalculator.state.result',\n description:\n 'Computed prediction — ovulation date, fertile window, next period, current bleed range and the next few period starts, all `yyyy-MM-dd`. Null until a last-period date is set.',\n read: (handle) => handle.getResult(),\n },\n },\n actions: {\n set_last_period: {\n // Drives the same local input state a user types into; nothing is\n // persisted to a record, and the value is reversible in the same UI.\n safety: 'write',\n argsType: '{ date: string | null }',\n argsSchema: {\n type: 'object',\n properties: {\n date: {\n oneOf: [\n { ...isoDate, description: 'Local calendar date, `yyyy-MM-dd`.' },\n { type: 'null' },\n ],\n description:\n 'Start date of the last period, or null to clear it. Must not be in the future.',\n },\n },\n required: ['date'],\n additionalProperties: false,\n },\n idempotent: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the date was applied.',\n },\n errors: [\n 'Returns false for an unparseable date or a date in the future — the on-screen DatePicker caps at today.',\n ],\n examples: [\n { args: { date: '2026-08-01' }, note: 'Last period started 1 August.' },\n ],\n descriptionKey: 'ui.agent.cycleCalculator.actions.setLastPeriod',\n description:\n 'Set the start date of the last period. This is the only required input — the prediction stays null without it.',\n invoke: (handle, args: { date: string | null }) =>\n handle.setLastPeriod(args.date),\n },\n set_cycle_length: {\n safety: 'write',\n argsType: '{ days: number | null }',\n argsSchema: {\n type: 'object',\n properties: {\n days: {\n oneOf: [\n { type: 'integer', minimum: 20, maximum: 45 },\n { type: 'null' },\n ],\n description:\n 'Average cycle length in days (20–45), or null to fall back to the 28-day default.',\n },\n },\n required: ['days'],\n additionalProperties: false,\n },\n idempotent: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the value was applied.',\n },\n errors: [\n 'Returns false outside 20–45 days — the same bounds the on-screen NumberInput enforces.',\n ],\n descriptionKey: 'ui.agent.cycleCalculator.actions.setCycleLength',\n description:\n 'Set the average cycle length in days. Shifts ovulation, the fertile window and every upcoming period.',\n invoke: (handle, args: { days: number | null }) =>\n handle.setCycleLength(args.days),\n },\n set_period_length: {\n safety: 'write',\n argsType: '{ days: number | null }',\n argsSchema: {\n type: 'object',\n properties: {\n days: {\n oneOf: [\n { type: 'integer', minimum: 1, maximum: 14 },\n { type: 'null' },\n ],\n description:\n 'Period (bleed) length in days (1–14), or null to omit the bleed range.',\n },\n },\n required: ['days'],\n additionalProperties: false,\n },\n idempotent: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the value was applied.',\n },\n errors: [\n 'Returns false outside 1–14 days — the same bounds the on-screen NumberInput enforces.',\n ],\n descriptionKey: 'ui.agent.cycleCalculator.actions.setPeriodLength',\n description:\n 'Set the period (bleed) length in days. Optional — it only adds the current bleed range to the result.',\n invoke: (handle, args: { days: number | null }) =>\n handle.setPeriodLength(args.days),\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'cycle-calculator',\n description: 'Marks the CycleCalculator wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the id prop. Also the registry key — without an `id` the instance does not register and only the DOM channel works.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* Menstrual-cycle prediction — pure, framework-free, unit-testable. */\n/* */\n/* Uses the standard fixed-luteal-phase model: ovulation falls ~14 days */\n/* before the next period, so on a cycle of length L ovulation is day */\n/* (L − 14). The fertile window spans the 5 days before ovulation */\n/* (sperm survival) through 1 day after (oocyte viability). */\n/* ------------------------------------------------------------------ */\n\nimport { addDays } from 'date-fns';\n\n/** Standard menstrual-cycle length. */\nexport const DEFAULT_CYCLE_LENGTH = 28;\n/** Luteal phase is biologically near-constant at ~14 days. */\nexport const LUTEAL_PHASE_DAYS = 14;\n/** Sperm survive up to ~5 days before ovulation. */\nexport const FERTILE_DAYS_BEFORE = 5;\n/** The oocyte is viable ~1 day after ovulation. */\nexport const FERTILE_DAYS_AFTER = 1;\n\nexport interface CycleInput {\n /** First day of the most recent period. */\n lastPeriodStart: Date;\n /** Average cycle length in days. Defaults to 28. */\n cycleLength?: number;\n /** Period (bleed) length in days. Optional — used for the period range. */\n periodLength?: number;\n}\n\nexport interface DateRange {\n start: Date;\n end: Date;\n}\n\nexport interface CyclePrediction {\n /** Start date of the next period. */\n nextPeriod: Date;\n /** Estimated ovulation date. */\n ovulation: Date;\n /** Fertile window (5 days before ovulation → 1 day after). */\n fertileWindow: DateRange;\n /** Start dates of the next few periods (length = `occurrences`). */\n upcomingPeriods: Date[];\n /**\n * The current period's bleed range (first day → last day), or `null` when no\n * `periodLength` was given.\n */\n periodRange: DateRange | null;\n}\n\n/**\n * Predict ovulation, the fertile window and upcoming periods from the last\n * period's start date. `occurrences` controls how many future periods to\n * list (default 3).\n */\nexport function predictCycle(\n input: CycleInput,\n occurrences = 3,\n): CyclePrediction {\n const cycle = input.cycleLength ?? DEFAULT_CYCLE_LENGTH;\n const { lastPeriodStart } = input;\n\n const ovulation = addDays(lastPeriodStart, cycle - LUTEAL_PHASE_DAYS);\n const fertileWindow: DateRange = {\n start: addDays(ovulation, -FERTILE_DAYS_BEFORE),\n end: addDays(ovulation, FERTILE_DAYS_AFTER),\n };\n const nextPeriod = addDays(lastPeriodStart, cycle);\n const upcomingPeriods = Array.from({ length: occurrences }, (_, i) =>\n addDays(lastPeriodStart, cycle * (i + 1)),\n );\n const periodRange: DateRange | null =\n input.periodLength && input.periodLength > 0\n ? {\n start: lastPeriodStart,\n end: addDays(lastPeriodStart, input.periodLength - 1),\n }\n : null;\n\n return { nextPeriod, ovulation, fertileWindow, upcomingPeriods, periodRange };\n}\n","/* ------------------------------------------------------------------ */\n/* CycleCalculator — predict ovulation, fertile window and upcoming */\n/* periods from the last period's start date. */\n/* */\n/* Maths lives in `./cycle` (pure, separately tested). */\n/* ------------------------------------------------------------------ */\n\nimport { forwardRef, useEffect, useMemo, useRef, useState } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { format, isAfter, parseISO } from 'date-fns';\nimport { Heart, Check, Droplet } from 'lucide-react';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { cycleCalculatorAgent } from './cycle-calculator.agent';\nimport { FormField } from '../form-field';\nimport { DatePicker } from '../date-picker';\nimport { NumberInput } from '../number-input';\nimport { Card } from '../card';\nimport { Badge } from '../badge';\nimport {\n InsertButton,\n type InsertPayload,\n type InsertVariant,\n type InsertMode,\n} from '../_shared/insert-result';\nimport {\n type CyclePrediction,\n predictCycle,\n DEFAULT_CYCLE_LENGTH,\n} from './cycle';\n\nconst rootVariants = cva('ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]', {\n variants: {\n width: { full: 'ds:w-full', auto: 'ds:inline-flex' },\n },\n defaultVariants: { width: 'full' },\n});\n\n/**\n * DS token NAME backing the result-card chip — the fertile window is the\n * headline fertility datum, shown on screen with the `accent` Badge variant\n * (which fills `--accent`). The card chip reuses that token so the inserted\n * PNG chip matches the on-screen fertile-window badge.\n */\nconst HIGHLIGHT_TOKEN = '--accent';\n\n/* ------------------------------------------------------------------ */\n/* Agent boundary */\n/* */\n/* Dates cross the agent boundary as local-time `yyyy-MM-dd` strings, */\n/* never `Date` objects — a Date JSON-serialises to UTC and silently */\n/* shifts the day for anyone east or west of Greenwich. */\n/* ------------------------------------------------------------------ */\n\nconst toIsoDate = (d: Date): string => format(d, 'yyyy-MM-dd');\n\nconst fromIsoDate = (iso: string): Date | null => {\n const d = parseISO(iso);\n return Number.isNaN(d.getTime()) ? null : d;\n};\n\n/** UI input bounds, mirrored by the agent handle so it can't out-type a user. */\nconst CYCLE_LENGTH_RANGE = { min: 20, max: 45 } as const;\nconst PERIOD_LENGTH_RANGE = { min: 1, max: 14 } as const;\n\nconst inRange = (\n n: number | null,\n { min, max }: { min: number; max: number },\n): boolean => n === null || (Number.isFinite(n) && n >= min && n <= max);\n\n/** `CyclePrediction` projected onto the agent boundary — ISO dates, no Dates. */\nexport interface CyclePredictionSnapshot {\n /** Estimated ovulation date, `yyyy-MM-dd`. */\n ovulation: string;\n /** Fertile window, `yyyy-MM-dd` endpoints. */\n fertileWindow: { start: string; end: string };\n /** Start of the next period, `yyyy-MM-dd`. */\n nextPeriod: string;\n /** Current period's bleed range, or null when no period length was given. */\n periodRange: { start: string; end: string } | null;\n /** Start dates of the next few periods, `yyyy-MM-dd`. */\n upcomingPeriods: string[];\n}\n\n/**\n * Curated imperative handle for agent / external automation. Reads the three\n * cycle inputs and the computed prediction, and drives the inputs the way a\n * user would. Never exposes patient identity — only structural dates and day\n * counts. Consumed by `cycle-calculator.agent.ts`; the public `ref` stays the\n * root DOM element.\n */\nexport interface CycleCalculatorHandle {\n /** Current inputs — ISO date + day counts, or null when unset. */\n getInputs: () => {\n lastPeriodStart: string | null;\n cycleLength: number | null;\n periodLength: number | null;\n };\n /** Computed prediction, or null until a last-period date is set. */\n getResult: () => CyclePredictionSnapshot | null;\n /** Set the last period's start date (`yyyy-MM-dd`, not in the future). */\n setLastPeriod: (isoDate: string | null) => boolean;\n /** Set the average cycle length in days (20–45). */\n setCycleLength: (days: number | null) => boolean;\n /** Set the period (bleed) length in days (1–14). */\n setPeriodLength: (days: number | null) => boolean;\n}\n\nexport interface CycleCalculatorProps extends VariantProps<\n typeof rootVariants\n> {\n /** Initial cycle length in days. Defaults to 28. */\n defaultCycleLength?: number;\n /** Fires whenever a prediction can be computed (and `null` when it can't). */\n onResultChange?: (result: CyclePrediction | null) => void;\n /** When provided, shows the result-action buttons that emit / copy the result. */\n onInsert?: (payload: InsertPayload) => void;\n /**\n * Which verb the result button performs. Defaults to `'insert'`.\n * Use `'copy'` in an app-shell surface (no editor to insert into) — the\n * button writes the result to the clipboard as a multi-format `ClipboardItem`.\n */\n insertVariant?: InsertVariant;\n /** `copy` variant only — fired after a successful clipboard write. */\n onCopy?: (mode: InsertMode) => void;\n /** `copy` variant only — fired if the clipboard write can't proceed. */\n onError?: (error: unknown) => void;\n /**\n * Brand wordmark printed in the inserted/copied result-card footer.\n * Omitted → no brand line (and no footer hairline); a string → that custom\n * brand; `false` → no brand line. Brand is opt-in.\n */\n insertBrand?: string | false;\n /** Opaque instance id, emitted as `data-component-id`. */\n id?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n}\n\nexport const CycleCalculator = forwardRef<HTMLDivElement, CycleCalculatorProps>(\n (\n {\n defaultCycleLength = DEFAULT_CYCLE_LENGTH,\n onResultChange,\n onInsert,\n insertVariant = 'insert',\n onCopy,\n onError,\n insertBrand,\n id,\n width,\n className,\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation();\n\n const [lastPeriod, setLastPeriod] = useState<Date | undefined>(undefined);\n const [cycleLength, setCycleLength] = useState<number | null>(\n defaultCycleLength,\n );\n const [periodLength, setPeriodLength] = useState<number | null>(null);\n\n const result = useMemo<CyclePrediction | null>(() => {\n if (!lastPeriod) return null;\n return predictCycle({\n lastPeriodStart: lastPeriod,\n cycleLength: cycleLength ?? DEFAULT_CYCLE_LENGTH,\n periodLength: periodLength ?? undefined,\n });\n }, [lastPeriod, cycleLength, periodLength]);\n\n const dateFormatter = useMemo(\n () => new Intl.DateTimeFormat(i18n.language, { dateStyle: 'medium' }),\n [i18n.language],\n );\n\n useEffect(() => {\n onResultChange?.(result);\n }, [result, onResultChange]);\n\n const today = useMemo(() => new Date(), []);\n\n /* ── Agent handle ────────────────────────────────────────────────── */\n const liveRef = useRef({ lastPeriod, cycleLength, periodLength, result });\n liveRef.current = { lastPeriod, cycleLength, periodLength, result };\n\n const agentHandle = useMemo<CycleCalculatorHandle>(\n () => ({\n getInputs: () => ({\n lastPeriodStart: liveRef.current.lastPeriod\n ? toIsoDate(liveRef.current.lastPeriod)\n : null,\n cycleLength: liveRef.current.cycleLength,\n periodLength: liveRef.current.periodLength,\n }),\n getResult: () => {\n const r = liveRef.current.result;\n if (!r) return null;\n return {\n ovulation: toIsoDate(r.ovulation),\n fertileWindow: {\n start: toIsoDate(r.fertileWindow.start),\n end: toIsoDate(r.fertileWindow.end),\n },\n nextPeriod: toIsoDate(r.nextPeriod),\n periodRange: r.periodRange\n ? {\n start: toIsoDate(r.periodRange.start),\n end: toIsoDate(r.periodRange.end),\n }\n : null,\n upcomingPeriods: r.upcomingPeriods.map(toIsoDate),\n };\n },\n setLastPeriod: (isoDate) => {\n if (isoDate === null) {\n setLastPeriod(undefined);\n return true;\n }\n const parsed = fromIsoDate(isoDate);\n // The DatePicker caps at today; the handle honours the same bound.\n if (!parsed || isAfter(parsed, new Date())) return false;\n setLastPeriod(parsed);\n return true;\n },\n setCycleLength: (days) => {\n if (!inRange(days, CYCLE_LENGTH_RANGE)) return false;\n setCycleLength(days);\n return true;\n },\n setPeriodLength: (days) => {\n if (!inRange(days, PERIOD_LENGTH_RANGE)) return false;\n setPeriodLength(days);\n return true;\n },\n }),\n [],\n );\n useAgentRegistration(cycleCalculatorAgent, agentHandle, id);\n\n const fmt = (d: Date): string => dateFormatter.format(d);\n\n return (\n <div\n ref={ref}\n data-component=\"cycle-calculator\"\n data-component-id={id}\n className={rootVariants({ width, className })}\n >\n <div className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:sm:grid-cols-2\">\n <FormField label={t('cycleCalculator.lastPeriod')}>\n <DatePicker\n value={lastPeriod}\n onChange={setLastPeriod}\n maxDate={today}\n />\n </FormField>\n <FormField\n label={t('cycleCalculator.cycleLength')}\n description={t('cycleCalculator.cycleLengthHint')}\n >\n <NumberInput\n mode=\"integer\"\n min={CYCLE_LENGTH_RANGE.min}\n max={CYCLE_LENGTH_RANGE.max}\n value={cycleLength}\n onChange={setCycleLength}\n />\n </FormField>\n <FormField\n label={t('cycleCalculator.periodLength')}\n description={t('cycleCalculator.periodLengthHint')}\n >\n <NumberInput\n mode=\"integer\"\n min={PERIOD_LENGTH_RANGE.min}\n max={PERIOD_LENGTH_RANGE.max}\n value={periodLength}\n onChange={setPeriodLength}\n />\n </FormField>\n </div>\n\n <p className=\"ds:sr-only\" role=\"status\" aria-live=\"polite\">\n {result\n ? `${t('cycleCalculator.ovulation')}: ${fmt(result.ovulation)}. ${t(\n 'cycleCalculator.nextPeriod',\n )}: ${fmt(result.nextPeriod)}.`\n : ''}\n </p>\n\n {result ? (\n <Card variant=\"elevated\">\n <Card.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <dl className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:sm:grid-cols-3\">\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-xs)] ds:text-center\">\n <dt className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.ovulation')}\n </dt>\n <dd>\n <Badge\n variant=\"success\"\n size=\"lg\"\n leading={<Check aria-hidden />}\n >\n {fmt(result.ovulation)}\n </Badge>\n </dd>\n </div>\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-xs)] ds:text-center\">\n <dt className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.fertileWindow')}\n </dt>\n <dd>\n <Badge\n variant=\"accent\"\n size=\"lg\"\n leading={<Heart aria-hidden />}\n >\n {fmt(result.fertileWindow.start)} –{' '}\n {fmt(result.fertileWindow.end)}\n </Badge>\n </dd>\n </div>\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-xs)] ds:text-center\">\n <dt className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.nextPeriod')}\n </dt>\n <dd>\n <Badge\n variant=\"error\"\n size=\"lg\"\n leading={<Droplet aria-hidden />}\n >\n {fmt(result.nextPeriod)}\n </Badge>\n </dd>\n </div>\n </dl>\n\n {result.periodRange ? (\n <div className=\"ds:flex ds:flex-col ds:items-start ds:gap-[var(--spacing-2xs)]\">\n <span className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.periodRange')}\n </span>\n <span className=\"type-body ds:text-foreground\">\n {fmt(result.periodRange.start)} –{' '}\n {fmt(result.periodRange.end)}\n </span>\n </div>\n ) : null}\n\n <div className=\"ds:flex ds:flex-col ds:items-start ds:gap-[var(--spacing-2xs)]\">\n <span className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.upcomingPeriods')}\n </span>\n <ul className=\"ds:flex ds:flex-wrap ds:gap-x-[var(--spacing-md)] ds:gap-y-[var(--spacing-2xs)]\">\n {result.upcomingPeriods.map((d) => (\n <li\n key={d.getTime()}\n className=\"type-body ds:text-foreground\"\n >\n {fmt(d)}\n </li>\n ))}\n </ul>\n </div>\n\n {insertVariant === 'copy' || onInsert ? (\n <InsertButton\n onInsert={onInsert}\n variant={insertVariant}\n onCopy={onCopy}\n onError={onError}\n card={{\n title: t('insert.title.cycle'),\n icon: 'heart',\n highlight: `${fmt(result.fertileWindow.start)} – ${fmt(\n result.fertileWindow.end,\n )}`,\n // Chip reuses the on-screen fertile-window badge's accent\n // token so the inserted PNG chip matches the screen.\n highlightToken: HIGHLIGHT_TOKEN,\n brand: insertBrand,\n fields: [\n {\n // Ovulation is a predicted date → calendar glyph (the\n // on-screen badge uses a Check tick, which ICON_GEOMETRY\n // does not carry, so the calendar reads the date meaning).\n icon: 'calendar',\n label: t('cycleCalculator.ovulation'),\n value: fmt(result.ovulation),\n },\n {\n // Fertile window → heart glyph, matching the on-screen\n // fertile-window badge's Heart icon.\n icon: 'heart',\n label: t('cycleCalculator.fertileWindow'),\n value: `${fmt(result.fertileWindow.start)} – ${fmt(\n result.fertileWindow.end,\n )}`,\n },\n {\n // Next period → droplets glyph, matching the on-screen\n // next-period badge's Droplet icon.\n icon: 'droplets',\n label: t('cycleCalculator.nextPeriod'),\n value: fmt(result.nextPeriod),\n },\n ],\n }}\n />\n ) : null}\n </Card.Body>\n </Card>\n ) : (\n <p className=\"type-body ds:text-muted-foreground\">\n {t('cycleCalculator.empty')}\n </p>\n )}\n </div>\n );\n },\n);\n\nCycleCalculator.displayName = 'CycleCalculator';\n"],"names":["__iconNode","Droplet","createLucideIcon","isoDate","cycleCalculatorAgent","handle","args","DEFAULT_CYCLE_LENGTH","LUTEAL_PHASE_DAYS","FERTILE_DAYS_AFTER","predictCycle","input","occurrences","cycle","lastPeriodStart","ovulation","addDays","fertileWindow","nextPeriod","upcomingPeriods","_","i","periodRange","rootVariants","cva","HIGHLIGHT_TOKEN","toIsoDate","d","format","fromIsoDate","iso","parseISO","CYCLE_LENGTH_RANGE","PERIOD_LENGTH_RANGE","inRange","n","min","max","CycleCalculator","forwardRef","defaultCycleLength","onResultChange","onInsert","insertVariant","onCopy","onError","insertBrand","id","width","className","ref","t","i18n","useTranslation","lastPeriod","setLastPeriod","useState","cycleLength","setCycleLength","periodLength","setPeriodLength","result","useMemo","dateFormatter","useEffect","today","liveRef","useRef","agentHandle","parsed","isAfter","days","useAgentRegistration","fmt","jsxs","jsx","FormField","DatePicker","NumberInput","Card","Badge","Check","Heart","InsertButton"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -2,7 +2,7 @@ import { jsxs as _, jsx as w } from "react/jsx-runtime";
|
|
|
2
2
|
import { forwardRef as Te, useRef as S, useMemo as L, useState as O, useCallback as D, useEffect as X, useImperativeHandle as We, useContext as $e, Children as Ie, isValidElement as Ae, Fragment as je, createContext as Fe } from "react";
|
|
3
3
|
import { c as Ge } from "./index-D2ZczOXr.js";
|
|
4
4
|
import { useTranslation as ke } from "react-i18next";
|
|
5
|
-
import { I as re } from "./icon-button-
|
|
5
|
+
import { I as re } from "./icon-button-DA2CAGHZ.js";
|
|
6
6
|
import { u as U } from "./use-isomorphic-layout-effect-BGfaCOP1.js";
|
|
7
7
|
import { u as Ke } from "./registry-DvAUVLHh.js";
|
|
8
8
|
import { P as _e } from "./plus-DzMQ_c6b.js";
|
|
@@ -688,4 +688,4 @@ export {
|
|
|
688
688
|
cr as D,
|
|
689
689
|
Oe as d
|
|
690
690
|
};
|
|
691
|
-
//# sourceMappingURL=dashboard-grid-
|
|
691
|
+
//# sourceMappingURL=dashboard-grid-BFtdHqfn.js.map
|