analytica-frontend-lib 1.7.21 → 1.7.23
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/AccessReportModal/index.js +3 -3
- package/dist/AccessReportModal/index.mjs +2 -2
- package/dist/ActivitiesHistory/index.js +49 -49
- package/dist/ActivitiesHistory/index.mjs +48 -48
- package/dist/ActivityCardQuestionBanks/index.js +49 -49
- package/dist/ActivityCardQuestionBanks/index.mjs +48 -48
- package/dist/ActivityCardQuestionPreview/index.js +49 -49
- package/dist/ActivityCardQuestionPreview/index.mjs +48 -48
- package/dist/ActivityCreate/ActivityCreateContent/index.js +49 -49
- package/dist/ActivityCreate/ActivityCreateContent/index.mjs +48 -48
- package/dist/ActivityCreate/index.js +49 -49
- package/dist/ActivityCreate/index.mjs +48 -48
- package/dist/ActivityDetails/index.js +49 -49
- package/dist/ActivityDetails/index.mjs +48 -48
- package/dist/ActivityFilters/index.js +49 -49
- package/dist/ActivityFilters/index.mjs +48 -48
- package/dist/ActivityPageLayout/index.js +49 -49
- package/dist/ActivityPageLayout/index.mjs +48 -48
- package/dist/ActivityPreview/index.js +49 -49
- package/dist/ActivityPreview/index.mjs +48 -48
- package/dist/AlertManager/index.js +49 -49
- package/dist/AlertManager/index.mjs +48 -48
- package/dist/AlertManagerView/index.js +3 -3
- package/dist/AlertManagerView/index.mjs +2 -2
- package/dist/AnnouncementModal/index.js +3 -3
- package/dist/AnnouncementModal/index.mjs +2 -2
- package/dist/AnnouncementsGate/index.js +4 -4
- package/dist/AnnouncementsGate/index.mjs +3 -3
- package/dist/AnswerKeyModal/index.js +3 -3
- package/dist/AnswerKeyModal/index.mjs +2 -2
- package/dist/AppHeader/index.js +6 -6
- package/dist/AppHeader/index.mjs +5 -5
- package/dist/CalendarCard/index.js +4 -4
- package/dist/CalendarCard/index.mjs +3 -3
- package/dist/Chat/index.js +3 -3
- package/dist/Chat/index.mjs +2 -2
- package/dist/CheckBox/index.d.ts.map +1 -1
- package/dist/CheckBox/index.js +2 -2
- package/dist/CheckBox/index.mjs +1 -1
- package/dist/CheckBoxGroup/index.js +49 -49
- package/dist/CheckBoxGroup/index.mjs +48 -48
- package/dist/ComparatorChart/ComparatorView/index.js +3 -3
- package/dist/ComparatorChart/ComparatorView/index.mjs +2 -2
- package/dist/CorrectActivityModal/index.js +7 -7
- package/dist/CorrectActivityModal/index.mjs +6 -6
- package/dist/DownloadButton/index.js +4 -4
- package/dist/DownloadButton/index.mjs +3 -3
- package/dist/DownloadModal/index.js +3 -3
- package/dist/DownloadModal/index.mjs +2 -2
- package/dist/DropdownMenu/index.js +3 -3
- package/dist/DropdownMenu/index.mjs +2 -2
- package/dist/EnemClassroomStartModal/index.d.ts.map +1 -1
- package/dist/EnemClassroomStartModal/index.js +7 -7
- package/dist/EnemClassroomStartModal/index.mjs +6 -6
- package/dist/EnemMoment/index.js +57 -57
- package/dist/EnemMoment/index.mjs +51 -51
- package/dist/EnemMomentStudentModal/index.js +50 -50
- package/dist/EnemMomentStudentModal/index.mjs +48 -48
- package/dist/ExamDetailsLayout/ExamDetailsPage/index.js +49 -49
- package/dist/ExamDetailsLayout/ExamDetailsPage/index.mjs +48 -48
- package/dist/ExamPageLayout/index.js +49 -49
- package/dist/ExamPageLayout/index.mjs +48 -48
- package/dist/Forum/index.js +5 -5
- package/dist/Forum/index.mjs +4 -4
- package/dist/KnowledgePerformanceCard/index.js +51 -51
- package/dist/KnowledgePerformanceCard/index.mjs +50 -50
- package/dist/LessonCardPreview/index.js +49 -49
- package/dist/LessonCardPreview/index.mjs +48 -48
- package/dist/LessonMediaSections/index.js +49 -49
- package/dist/LessonMediaSections/index.mjs +48 -48
- package/dist/LessonsCatalog/index.js +49 -49
- package/dist/LessonsCatalog/index.mjs +48 -48
- package/dist/Modal/index.d.ts.map +1 -1
- package/dist/Modal/index.js +2 -2
- package/dist/Modal/index.mjs +1 -1
- package/dist/MultiCheckSelect/index.js +5 -5
- package/dist/MultiCheckSelect/index.mjs +4 -4
- package/dist/MultiSearchSelect/index.js +3 -3
- package/dist/MultiSearchSelect/index.mjs +2 -2
- package/dist/MultipleChoice/index.js +3 -3
- package/dist/MultipleChoice/index.mjs +2 -2
- package/dist/NotificationCard/index.js +4 -4
- package/dist/NotificationCard/index.mjs +3 -3
- package/dist/PerformanceReportModal/index.js +3 -3
- package/dist/PerformanceReportModal/index.mjs +2 -2
- package/dist/PrintableUsersTable/index.js +49 -49
- package/dist/PrintableUsersTable/index.mjs +48 -48
- package/dist/ProgressModal/index.js +3 -3
- package/dist/ProgressModal/index.mjs +2 -2
- package/dist/QuestionsPerformanceCard/index.js +50 -50
- package/dist/QuestionsPerformanceCard/index.mjs +49 -49
- package/dist/Quiz/index.js +6 -6
- package/dist/Quiz/index.mjs +5 -5
- package/dist/RecommendedLessonCreate/index.js +49 -49
- package/dist/RecommendedLessonCreate/index.mjs +48 -48
- package/dist/RecommendedLessonDetails/index.js +7 -7
- package/dist/RecommendedLessonDetails/index.mjs +6 -6
- package/dist/RecommendedLessonsHistory/index.js +49 -49
- package/dist/RecommendedLessonsHistory/index.mjs +48 -48
- package/dist/ReportDetailModal/index.js +4 -4
- package/dist/ReportDetailModal/index.mjs +3 -3
- package/dist/RichEditor/index.js +5 -5
- package/dist/RichEditor/index.mjs +4 -4
- package/dist/{RichEditorCore-6MTYSSKS.mjs → RichEditorCore-2S5YUAOI.mjs} +5 -5
- package/dist/{RichEditorCore-KDARBEK4.js → RichEditorCore-N7A2445B.js} +16 -16
- package/dist/{RichEditorCore-KDARBEK4.js.map → RichEditorCore-N7A2445B.js.map} +1 -1
- package/dist/Search/index.js +4 -4
- package/dist/Search/index.mjs +3 -3
- package/dist/SendActivityModal/SendActivityModal.js +49 -49
- package/dist/SendActivityModal/SendActivityModal.mjs +48 -48
- package/dist/SendActivityModal/index.js +49 -49
- package/dist/SendActivityModal/index.mjs +48 -48
- package/dist/SendLessonModal/index.js +49 -49
- package/dist/SendLessonModal/index.mjs +48 -48
- package/dist/SimulatedPerformance/SimulatedPerformanceView/index.js +49 -49
- package/dist/SimulatedPerformance/SimulatedPerformanceView/index.mjs +48 -48
- package/dist/SimulatedPerformance/useSimulatedPerformance/index.js +5 -5
- package/dist/SimulatedPerformance/useSimulatedPerformance/index.mjs +4 -4
- package/dist/SimulatedStudentSimulationsModal/index.js +6 -6
- package/dist/SimulatedStudentSimulationsModal/index.mjs +5 -5
- package/dist/SimulationsPage/index.js +49 -49
- package/dist/SimulationsPage/index.mjs +48 -48
- package/dist/StudentLessonProgressModal/index.js +3 -3
- package/dist/StudentLessonProgressModal/index.mjs +2 -2
- package/dist/StudentPerformanceDetailsModal/index.js +5 -5
- package/dist/StudentPerformanceDetailsModal/index.mjs +4 -4
- package/dist/Support/TicketModal/index.js +3 -3
- package/dist/Support/TicketModal/index.mjs +2 -2
- package/dist/Support/index.js +4 -4
- package/dist/Support/index.mjs +3 -3
- package/dist/SupportChatComposer/index.js +3 -3
- package/dist/SupportChatComposer/index.mjs +2 -2
- package/dist/SupportChatEvent/index.js +3 -3
- package/dist/SupportChatEvent/index.mjs +2 -2
- package/dist/SupportChatMessage/index.js +3 -3
- package/dist/SupportChatMessage/index.mjs +2 -2
- package/dist/SupportChatWidget/index.js +3 -3
- package/dist/SupportChatWidget/index.mjs +2 -2
- package/dist/SupportConcludeModal/index.js +4 -4
- package/dist/SupportConcludeModal/index.mjs +3 -3
- package/dist/SupportConversationHeader/index.js +4 -4
- package/dist/SupportConversationHeader/index.mjs +3 -3
- package/dist/SupportConversationMessages/index.js +5 -5
- package/dist/SupportConversationMessages/index.mjs +4 -4
- package/dist/SupportTicketConversation/index.js +12 -12
- package/dist/SupportTicketConversation/index.mjs +11 -11
- package/dist/TableProvider/index.js +49 -49
- package/dist/TableProvider/index.mjs +48 -48
- package/dist/UnifiedDraftModelPage/index.js +49 -49
- package/dist/UnifiedDraftModelPage/index.mjs +48 -48
- package/dist/UnifiedHistoryPage/index.js +49 -49
- package/dist/UnifiedHistoryPage/index.mjs +48 -48
- package/dist/VideoPlayer/index.js +5 -5
- package/dist/VideoPlayer/index.mjs +4 -4
- package/dist/Whiteboard/index.js +3 -3
- package/dist/Whiteboard/index.mjs +2 -2
- package/dist/{chunk-B6QOBHZM.mjs → chunk-24BEZK43.mjs} +2 -2
- package/dist/{chunk-CYSODZGX.js → chunk-27Y6V3GM.js} +169 -66
- package/dist/chunk-27Y6V3GM.js.map +1 -0
- package/dist/{chunk-OQTXTDSK.mjs → chunk-2OJ3QSLU.mjs} +3 -3
- package/dist/{chunk-VDUO65VK.mjs → chunk-3EGJJDIM.mjs} +2 -2
- package/dist/{chunk-VDUO65VK.mjs.map → chunk-3EGJJDIM.mjs.map} +1 -1
- package/dist/{chunk-4OUBPEVS.mjs → chunk-3HKLGNUE.mjs} +3 -3
- package/dist/{chunk-YA7XLH7D.js → chunk-3MFACEZ2.js} +3 -3
- package/dist/{chunk-YA7XLH7D.js.map → chunk-3MFACEZ2.js.map} +1 -1
- package/dist/{chunk-IHBWJM4C.mjs → chunk-3Q7RJKUP.mjs} +2 -2
- package/dist/{chunk-PY6WD6SB.mjs → chunk-3WRB4WCD.mjs} +4 -4
- package/dist/{chunk-4RHCBMMP.js → chunk-46VHAL4S.js} +3 -3
- package/dist/{chunk-4RHCBMMP.js.map → chunk-46VHAL4S.js.map} +1 -1
- package/dist/{chunk-POT3ALY3.js → chunk-5DINXU6W.js} +1 -1
- package/dist/{chunk-POT3ALY3.js.map → chunk-5DINXU6W.js.map} +1 -1
- package/dist/{chunk-L52NFNFK.mjs → chunk-5VC4BK65.mjs} +3 -3
- package/dist/{chunk-B67RLIUM.js → chunk-72D7G6YQ.js} +3 -3
- package/dist/{chunk-B67RLIUM.js.map → chunk-72D7G6YQ.js.map} +1 -1
- package/dist/{chunk-C65DG2RI.mjs → chunk-7FSBWUOM.mjs} +2 -2
- package/dist/{chunk-QWMFWYII.js → chunk-7IZNLARX.js} +3 -3
- package/dist/{chunk-QWMFWYII.js.map → chunk-7IZNLARX.js.map} +1 -1
- package/dist/{chunk-ZCBT2BUZ.js → chunk-7RFHXFFV.js} +13 -13
- package/dist/{chunk-ZCBT2BUZ.js.map → chunk-7RFHXFFV.js.map} +1 -1
- package/dist/{chunk-EMWX6IKP.js → chunk-7VJP5D26.js} +13 -13
- package/dist/{chunk-EMWX6IKP.js.map → chunk-7VJP5D26.js.map} +1 -1
- package/dist/{chunk-HCQJR5CE.mjs → chunk-7ZWEBNFB.mjs} +2 -2
- package/dist/{chunk-3RHNJUXU.mjs → chunk-ACSEJOW6.mjs} +2 -2
- package/dist/{chunk-WQZHUW7C.mjs → chunk-ANFHLSDB.mjs} +3 -3
- package/dist/{chunk-H6NQOLQY.mjs → chunk-ANFLWCVD.mjs} +2 -2
- package/dist/{chunk-BKBDQXZX.js → chunk-AOYPUZRO.js} +3 -3
- package/dist/{chunk-BKBDQXZX.js.map → chunk-AOYPUZRO.js.map} +1 -1
- package/dist/{chunk-5WS6IENQ.mjs → chunk-AU2HLQDJ.mjs} +2 -2
- package/dist/{chunk-P6FX3NT6.mjs → chunk-AZGDHAP5.mjs} +2 -2
- package/dist/{chunk-NCGO7FPB.js → chunk-AZKNYREH.js} +8 -8
- package/dist/{chunk-NCGO7FPB.js.map → chunk-AZKNYREH.js.map} +1 -1
- package/dist/{chunk-R6MTPYYW.js → chunk-AZTBNERQ.js} +3 -3
- package/dist/{chunk-R6MTPYYW.js.map → chunk-AZTBNERQ.js.map} +1 -1
- package/dist/{chunk-NPB2JTYC.mjs → chunk-BO3QVQ37.mjs} +4 -4
- package/dist/{chunk-2WI4Q2I2.mjs → chunk-BPMWRFSI.mjs} +4 -4
- package/dist/{chunk-TEW33GLR.mjs → chunk-BXN3VO6I.mjs} +2 -2
- package/dist/{chunk-7ZB3YHF2.mjs → chunk-C6LC5LD5.mjs} +1 -1
- package/dist/{chunk-7ZB3YHF2.mjs.map → chunk-C6LC5LD5.mjs.map} +1 -1
- package/dist/{chunk-5HONWYQA.js → chunk-C7ILTLT5.js} +3 -3
- package/dist/{chunk-5HONWYQA.js.map → chunk-C7ILTLT5.js.map} +1 -1
- package/dist/{chunk-OES54VU6.mjs → chunk-CFV2OZ3P.mjs} +116 -13
- package/dist/chunk-CFV2OZ3P.mjs.map +1 -0
- package/dist/{chunk-4OVIHZ3I.js → chunk-CGXWWPEA.js} +6 -6
- package/dist/{chunk-4OVIHZ3I.js.map → chunk-CGXWWPEA.js.map} +1 -1
- package/dist/{chunk-MNU45FM3.js → chunk-COT4KW3H.js} +2 -2
- package/dist/{chunk-MNU45FM3.js.map → chunk-COT4KW3H.js.map} +1 -1
- package/dist/{chunk-JDQUXG75.js → chunk-CVDNCU6L.js} +3 -3
- package/dist/{chunk-JDQUXG75.js.map → chunk-CVDNCU6L.js.map} +1 -1
- package/dist/{chunk-HBZHWSMZ.mjs → chunk-D46PJSQ7.mjs} +13 -13
- package/dist/{chunk-ARYIJ4RU.js → chunk-DDORKDQO.js} +3 -3
- package/dist/{chunk-ARYIJ4RU.js.map → chunk-DDORKDQO.js.map} +1 -1
- package/dist/{chunk-7YQTDJFA.js → chunk-DKXSR2V3.js} +3 -3
- package/dist/{chunk-7YQTDJFA.js.map → chunk-DKXSR2V3.js.map} +1 -1
- package/dist/{chunk-I6EAPPBL.mjs → chunk-DZMYIOKZ.mjs} +5 -5
- package/dist/{chunk-SKM7NFPY.js → chunk-EPXAFJVW.js} +6 -6
- package/dist/{chunk-SKM7NFPY.js.map → chunk-EPXAFJVW.js.map} +1 -1
- package/dist/{chunk-AYYMS23L.js → chunk-ESIQ2GB4.js} +7 -7
- package/dist/{chunk-AYYMS23L.js.map → chunk-ESIQ2GB4.js.map} +1 -1
- package/dist/{chunk-NU2WNYOD.js → chunk-EW7HGUFV.js} +87 -87
- package/dist/{chunk-NU2WNYOD.js.map → chunk-EW7HGUFV.js.map} +1 -1
- package/dist/{chunk-I4QGQMXI.mjs → chunk-EXYXZFNK.mjs} +2 -2
- package/dist/{chunk-RBJAO57A.js → chunk-FAAR4XC5.js} +3 -3
- package/dist/{chunk-RBJAO57A.js.map → chunk-FAAR4XC5.js.map} +1 -1
- package/dist/{chunk-N2VNE3ON.js → chunk-FDTDJDZI.js} +13 -13
- package/dist/{chunk-N2VNE3ON.js.map → chunk-FDTDJDZI.js.map} +1 -1
- package/dist/{chunk-SU5Q64TW.mjs → chunk-FVCTKS33.mjs} +6 -5
- package/dist/chunk-FVCTKS33.mjs.map +1 -0
- package/dist/{chunk-AVHZHWI3.js → chunk-GBIFSFWJ.js} +15 -15
- package/dist/{chunk-AVHZHWI3.js.map → chunk-GBIFSFWJ.js.map} +1 -1
- package/dist/{chunk-KSUPPAKH.js → chunk-GIQSHTB5.js} +9 -9
- package/dist/{chunk-KSUPPAKH.js.map → chunk-GIQSHTB5.js.map} +1 -1
- package/dist/{chunk-4QBKD4JN.js → chunk-GUUJYGXF.js} +3 -3
- package/dist/{chunk-4QBKD4JN.js.map → chunk-GUUJYGXF.js.map} +1 -1
- package/dist/{chunk-M4O46VDY.mjs → chunk-GX2PKLN2.mjs} +2 -2
- package/dist/{chunk-5BUTINIM.mjs → chunk-HLVLSWKD.mjs} +3 -3
- package/dist/{chunk-FU23WOTY.js → chunk-HSV5VZ4Z.js} +6 -6
- package/dist/{chunk-FU23WOTY.js.map → chunk-HSV5VZ4Z.js.map} +1 -1
- package/dist/{chunk-MMS2ELDK.mjs → chunk-IIQCS3A2.mjs} +2 -2
- package/dist/{chunk-NKWLCZUZ.mjs → chunk-JGGUMHM6.mjs} +2 -2
- package/dist/{chunk-HT2GREFH.js → chunk-JLD46DL7.js} +11 -11
- package/dist/{chunk-HT2GREFH.js.map → chunk-JLD46DL7.js.map} +1 -1
- package/dist/{chunk-NVL5TKWD.mjs → chunk-JYFLOQYT.mjs} +2 -2
- package/dist/{chunk-DWGDEUEW.mjs → chunk-KG563P7F.mjs} +5 -5
- package/dist/{chunk-TCIC5556.mjs → chunk-KH4TEDGD.mjs} +2 -2
- package/dist/{chunk-23PAYKWB.js → chunk-KM27ZDHZ.js} +2 -2
- package/dist/{chunk-23PAYKWB.js.map → chunk-KM27ZDHZ.js.map} +1 -1
- package/dist/{chunk-XZUMD3CB.mjs → chunk-LODDYDTP.mjs} +2 -2
- package/dist/{chunk-XZUMD3CB.mjs.map → chunk-LODDYDTP.mjs.map} +1 -1
- package/dist/{chunk-E6CGJBID.mjs → chunk-LUHKMY56.mjs} +2 -2
- package/dist/{chunk-TVLEUNKE.mjs → chunk-LZP5VZCO.mjs} +2 -2
- package/dist/{chunk-EHNEBXS7.mjs → chunk-M6DXZ2FM.mjs} +2 -2
- package/dist/{chunk-B4C5DWAP.mjs → chunk-MMMJDO75.mjs} +2 -2
- package/dist/{chunk-AFCWMJQO.js → chunk-MOUPNP53.js} +3 -3
- package/dist/{chunk-AFCWMJQO.js.map → chunk-MOUPNP53.js.map} +1 -1
- package/dist/{chunk-36KFIZ43.js → chunk-MYPUZ6EG.js} +3 -3
- package/dist/{chunk-36KFIZ43.js.map → chunk-MYPUZ6EG.js.map} +1 -1
- package/dist/{chunk-6JHIKIPA.js → chunk-NUGLTWEA.js} +23 -23
- package/dist/{chunk-6JHIKIPA.js.map → chunk-NUGLTWEA.js.map} +1 -1
- package/dist/{chunk-KWXOYHYK.mjs → chunk-P7MORXSE.mjs} +2 -2
- package/dist/{chunk-YG4IZ5Q3.mjs → chunk-Q2OSEROT.mjs} +2 -2
- package/dist/{chunk-L5SXG6T6.mjs → chunk-QQKOHKO2.mjs} +3 -3
- package/dist/{chunk-SADSJ2MV.js → chunk-QVGUYPXO.js} +3 -3
- package/dist/{chunk-SADSJ2MV.js.map → chunk-QVGUYPXO.js.map} +1 -1
- package/dist/{chunk-K45PTE7F.mjs → chunk-RBKQXT73.mjs} +4 -4
- package/dist/{chunk-JZFISWTP.js → chunk-RIN2IN7E.js} +2 -2
- package/dist/{chunk-JZFISWTP.js.map → chunk-RIN2IN7E.js.map} +1 -1
- package/dist/{chunk-BXLAOYAG.mjs → chunk-RIUVPTG7.mjs} +2 -2
- package/dist/{chunk-QVB54LBS.mjs → chunk-RNZGX6MX.mjs} +3 -3
- package/dist/{chunk-VSVLIRO2.js → chunk-RXEU77VN.js} +15 -15
- package/dist/{chunk-VSVLIRO2.js.map → chunk-RXEU77VN.js.map} +1 -1
- package/dist/{chunk-ZRIYCU2V.js → chunk-S2BZPPAI.js} +5 -5
- package/dist/{chunk-ZRIYCU2V.js.map → chunk-S2BZPPAI.js.map} +1 -1
- package/dist/{chunk-MES2BP4T.mjs → chunk-SGL5IUCV.mjs} +2 -2
- package/dist/{chunk-7LS5UQCQ.mjs → chunk-STKUPDHG.mjs} +2 -2
- package/dist/{chunk-PPYCCT2K.js → chunk-SWDVSCQJ.js} +9 -8
- package/dist/chunk-SWDVSCQJ.js.map +1 -0
- package/dist/{chunk-JCA76TCX.mjs → chunk-SZKLJOTN.mjs} +2 -2
- package/dist/{chunk-F5WR6XZZ.js → chunk-T73HPYF2.js} +3 -3
- package/dist/{chunk-F5WR6XZZ.js.map → chunk-T73HPYF2.js.map} +1 -1
- package/dist/{chunk-ZB6HDDE4.js → chunk-TQO37PVW.js} +14 -14
- package/dist/{chunk-ZB6HDDE4.js.map → chunk-TQO37PVW.js.map} +1 -1
- package/dist/{chunk-VKQ5AJDT.mjs → chunk-UENZQF2Y.mjs} +2 -2
- package/dist/{chunk-DCG7EUBC.js → chunk-UWLW5YVB.js} +6 -6
- package/dist/{chunk-DCG7EUBC.js.map → chunk-UWLW5YVB.js.map} +1 -1
- package/dist/{chunk-37AJ2GVO.mjs → chunk-UXJIZDXQ.mjs} +2 -2
- package/dist/{chunk-PLLPFCN3.js → chunk-UXMDPRAI.js} +14 -14
- package/dist/{chunk-PLLPFCN3.js.map → chunk-UXMDPRAI.js.map} +1 -1
- package/dist/{chunk-7BOTKRY6.mjs → chunk-V55DG5B4.mjs} +2 -2
- package/dist/{chunk-YRTIDZTN.js → chunk-VHEDMUAW.js} +4 -4
- package/dist/{chunk-YRTIDZTN.js.map → chunk-VHEDMUAW.js.map} +1 -1
- package/dist/{chunk-4RD55E4R.js → chunk-VWLWSO4J.js} +3 -3
- package/dist/{chunk-4RD55E4R.js.map → chunk-VWLWSO4J.js.map} +1 -1
- package/dist/{chunk-VJQIKFMG.mjs → chunk-W3CWEZDB.mjs} +3 -3
- package/dist/{chunk-JM6SLU7D.js → chunk-W7NNH4VY.js} +6 -6
- package/dist/{chunk-JM6SLU7D.js.map → chunk-W7NNH4VY.js.map} +1 -1
- package/dist/{chunk-VQ7MSYIH.js → chunk-WUN5NHZE.js} +4 -4
- package/dist/{chunk-VQ7MSYIH.js.map → chunk-WUN5NHZE.js.map} +1 -1
- package/dist/{chunk-AAU7ABJN.js → chunk-WWTRSQ3X.js} +3 -3
- package/dist/{chunk-AAU7ABJN.js.map → chunk-WWTRSQ3X.js.map} +1 -1
- package/dist/{chunk-BR6D2TGF.js → chunk-WZOA2PVJ.js} +3 -3
- package/dist/{chunk-BR6D2TGF.js.map → chunk-WZOA2PVJ.js.map} +1 -1
- package/dist/{chunk-TZKR5Z4J.mjs → chunk-XJF2F36N.mjs} +2 -2
- package/dist/{chunk-P6ACVNQK.mjs → chunk-YD2XBEKO.mjs} +2 -2
- package/dist/{chunk-LMXWIPGR.js → chunk-YWPLHFAK.js} +3 -3
- package/dist/{chunk-LMXWIPGR.js.map → chunk-YWPLHFAK.js.map} +1 -1
- package/dist/{chunk-DCEWWHV5.mjs → chunk-Z3HGYPH7.mjs} +2 -2
- package/dist/{chunk-Q3PKW6TH.js → chunk-ZCV3HWI2.js} +6 -6
- package/dist/{chunk-Q3PKW6TH.js.map → chunk-ZCV3HWI2.js.map} +1 -1
- package/dist/{chunk-OSA3YVDZ.mjs → chunk-ZF46DCAC.mjs} +2 -2
- package/dist/{chunk-5T6IDXSB.js → chunk-ZO2GA23I.js} +3 -3
- package/dist/{chunk-5T6IDXSB.js.map → chunk-ZO2GA23I.js.map} +1 -1
- package/dist/{chunk-ZN3763VZ.js → chunk-ZQLW4EJB.js} +9 -9
- package/dist/{chunk-ZN3763VZ.js.map → chunk-ZQLW4EJB.js.map} +1 -1
- package/dist/{chunk-CM5R4SPF.js → chunk-ZQQJTO6T.js} +3 -3
- package/dist/{chunk-CM5R4SPF.js.map → chunk-ZQQJTO6T.js.map} +1 -1
- package/dist/{chunk-SEL4QDCO.js → chunk-ZSXSAE3D.js} +3 -3
- package/dist/{chunk-SEL4QDCO.js.map → chunk-ZSXSAE3D.js.map} +1 -1
- package/dist/components/SupportChatWidget/guestSupportChatAdapter.d.ts +6 -1
- package/dist/components/SupportChatWidget/guestSupportChatAdapter.d.ts.map +1 -1
- package/dist/hooks/useAppContent/index.js +49 -49
- package/dist/hooks/useAppContent/index.mjs +48 -48
- package/dist/hooks/useSupportChat.d.ts +2 -0
- package/dist/hooks/useSupportChat.d.ts.map +1 -1
- package/dist/index.js +49 -49
- package/dist/index.mjs +48 -48
- package/dist/types/supportChat/index.d.ts +14 -0
- package/dist/types/supportChat/index.d.ts.map +1 -1
- package/dist/types/supportChat/index.js +2 -2
- package/dist/types/supportChat/index.mjs +1 -1
- package/dist/types/supportChat.d.ts +14 -0
- package/dist/types/supportChat.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-CYSODZGX.js.map +0 -1
- package/dist/chunk-OES54VU6.mjs.map +0 -1
- package/dist/chunk-PPYCCT2K.js.map +0 -1
- package/dist/chunk-SU5Q64TW.mjs.map +0 -1
- /package/dist/{RichEditorCore-6MTYSSKS.mjs.map → RichEditorCore-2S5YUAOI.mjs.map} +0 -0
- /package/dist/{chunk-B6QOBHZM.mjs.map → chunk-24BEZK43.mjs.map} +0 -0
- /package/dist/{chunk-OQTXTDSK.mjs.map → chunk-2OJ3QSLU.mjs.map} +0 -0
- /package/dist/{chunk-4OUBPEVS.mjs.map → chunk-3HKLGNUE.mjs.map} +0 -0
- /package/dist/{chunk-IHBWJM4C.mjs.map → chunk-3Q7RJKUP.mjs.map} +0 -0
- /package/dist/{chunk-PY6WD6SB.mjs.map → chunk-3WRB4WCD.mjs.map} +0 -0
- /package/dist/{chunk-L52NFNFK.mjs.map → chunk-5VC4BK65.mjs.map} +0 -0
- /package/dist/{chunk-C65DG2RI.mjs.map → chunk-7FSBWUOM.mjs.map} +0 -0
- /package/dist/{chunk-HCQJR5CE.mjs.map → chunk-7ZWEBNFB.mjs.map} +0 -0
- /package/dist/{chunk-3RHNJUXU.mjs.map → chunk-ACSEJOW6.mjs.map} +0 -0
- /package/dist/{chunk-WQZHUW7C.mjs.map → chunk-ANFHLSDB.mjs.map} +0 -0
- /package/dist/{chunk-H6NQOLQY.mjs.map → chunk-ANFLWCVD.mjs.map} +0 -0
- /package/dist/{chunk-5WS6IENQ.mjs.map → chunk-AU2HLQDJ.mjs.map} +0 -0
- /package/dist/{chunk-P6FX3NT6.mjs.map → chunk-AZGDHAP5.mjs.map} +0 -0
- /package/dist/{chunk-NPB2JTYC.mjs.map → chunk-BO3QVQ37.mjs.map} +0 -0
- /package/dist/{chunk-2WI4Q2I2.mjs.map → chunk-BPMWRFSI.mjs.map} +0 -0
- /package/dist/{chunk-TEW33GLR.mjs.map → chunk-BXN3VO6I.mjs.map} +0 -0
- /package/dist/{chunk-HBZHWSMZ.mjs.map → chunk-D46PJSQ7.mjs.map} +0 -0
- /package/dist/{chunk-I6EAPPBL.mjs.map → chunk-DZMYIOKZ.mjs.map} +0 -0
- /package/dist/{chunk-I4QGQMXI.mjs.map → chunk-EXYXZFNK.mjs.map} +0 -0
- /package/dist/{chunk-M4O46VDY.mjs.map → chunk-GX2PKLN2.mjs.map} +0 -0
- /package/dist/{chunk-5BUTINIM.mjs.map → chunk-HLVLSWKD.mjs.map} +0 -0
- /package/dist/{chunk-MMS2ELDK.mjs.map → chunk-IIQCS3A2.mjs.map} +0 -0
- /package/dist/{chunk-NKWLCZUZ.mjs.map → chunk-JGGUMHM6.mjs.map} +0 -0
- /package/dist/{chunk-NVL5TKWD.mjs.map → chunk-JYFLOQYT.mjs.map} +0 -0
- /package/dist/{chunk-DWGDEUEW.mjs.map → chunk-KG563P7F.mjs.map} +0 -0
- /package/dist/{chunk-TCIC5556.mjs.map → chunk-KH4TEDGD.mjs.map} +0 -0
- /package/dist/{chunk-E6CGJBID.mjs.map → chunk-LUHKMY56.mjs.map} +0 -0
- /package/dist/{chunk-TVLEUNKE.mjs.map → chunk-LZP5VZCO.mjs.map} +0 -0
- /package/dist/{chunk-EHNEBXS7.mjs.map → chunk-M6DXZ2FM.mjs.map} +0 -0
- /package/dist/{chunk-B4C5DWAP.mjs.map → chunk-MMMJDO75.mjs.map} +0 -0
- /package/dist/{chunk-KWXOYHYK.mjs.map → chunk-P7MORXSE.mjs.map} +0 -0
- /package/dist/{chunk-YG4IZ5Q3.mjs.map → chunk-Q2OSEROT.mjs.map} +0 -0
- /package/dist/{chunk-L5SXG6T6.mjs.map → chunk-QQKOHKO2.mjs.map} +0 -0
- /package/dist/{chunk-K45PTE7F.mjs.map → chunk-RBKQXT73.mjs.map} +0 -0
- /package/dist/{chunk-BXLAOYAG.mjs.map → chunk-RIUVPTG7.mjs.map} +0 -0
- /package/dist/{chunk-QVB54LBS.mjs.map → chunk-RNZGX6MX.mjs.map} +0 -0
- /package/dist/{chunk-MES2BP4T.mjs.map → chunk-SGL5IUCV.mjs.map} +0 -0
- /package/dist/{chunk-7LS5UQCQ.mjs.map → chunk-STKUPDHG.mjs.map} +0 -0
- /package/dist/{chunk-JCA76TCX.mjs.map → chunk-SZKLJOTN.mjs.map} +0 -0
- /package/dist/{chunk-VKQ5AJDT.mjs.map → chunk-UENZQF2Y.mjs.map} +0 -0
- /package/dist/{chunk-37AJ2GVO.mjs.map → chunk-UXJIZDXQ.mjs.map} +0 -0
- /package/dist/{chunk-7BOTKRY6.mjs.map → chunk-V55DG5B4.mjs.map} +0 -0
- /package/dist/{chunk-VJQIKFMG.mjs.map → chunk-W3CWEZDB.mjs.map} +0 -0
- /package/dist/{chunk-TZKR5Z4J.mjs.map → chunk-XJF2F36N.mjs.map} +0 -0
- /package/dist/{chunk-P6ACVNQK.mjs.map → chunk-YD2XBEKO.mjs.map} +0 -0
- /package/dist/{chunk-DCEWWHV5.mjs.map → chunk-Z3HGYPH7.mjs.map} +0 -0
- /package/dist/{chunk-OSA3YVDZ.mjs.map → chunk-ZF46DCAC.mjs.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-23PAYKWB.js","../src/components/Modal/Modal.tsx","../src/hooks/useMicrophonePermission.ts","../src/hooks/useBodyScrollLock.ts"],"names":["useState"],"mappings":"AAAA;AACE;AACA;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACE;AACA;AACA;AACA;AACF,sDAA4B;AAC5B;AACE;AACA;AACA;AACF,sDAA4B;AAC5B;AACE;AACA;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACA;ACnCA;AAGE;AACA;AACA;AACA;AACA;AAAA,8BACK;AACP,qDAAsB;ADmCtB;AACA;AE5CA;AAoCO,SAAS,uBAAA,CAAA,EAAyD;AACvE,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,EAAA,EAAI,6BAAA,UAA+C,CAAA;AAE3E,EAAA,8BAAA,CAAU,EAAA,GAAM;AACd,IAAA,MAAM,IAAA,EAAM,OAAO,UAAA,IAAc,YAAA,EAAc,UAAA,EAAY,KAAA,CAAA;AAC3D,IAAA,GAAA,CAAI,iBAAC,GAAA,2BAAK,YAAA,6BAAc,cAAA,EAAc;AACpC,MAAA,SAAA,CAAU,aAAa,CAAA;AACvB,MAAA,MAAA;AAAA,IACF;AAIA,IAAA,MAAM,YAAA,EAAc,GAAA,CAAI,WAAA;AACxB,IAAA,GAAA,CAAI,iBAAC,WAAA,6BAAa,OAAA,EAAO;AACvB,MAAA,SAAA,CAAU,QAAQ,CAAA;AAClB,MAAA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,OAAA,EAAS,IAAA;AACb,IAAA,IAAI,WAAA,EAAsC,IAAA;AAE1C,IAAA,MAAM,cAAA,EAAgB;AAAA,MACpB,IAAA,EAAM;AAAA,IACR,CAAA;AAEA,IAAA,WAAA,CACG,KAAA,CAAM,aAAa,CAAA,CACnB,IAAA,CAAK,CAAC,MAAA,EAAA,GAAW;AAChB,MAAA,GAAA,CAAI,CAAC,MAAA,EAAQ,MAAA;AACb,MAAA,WAAA,EAAa,MAAA;AACb,MAAA,SAAA,CAAU,MAAA,CAAO,KAAmC,CAAA;AACpD,MAAA,MAAA,CAAO,SAAA,EAAW,CAAA,EAAA,GAChB,SAAA,CAAU,MAAA,CAAO,KAAmC,CAAA;AAAA,IACxD,CAAC,CAAA,CACA,KAAA,CAAM,CAAA,EAAA,GAAM;AACX,MAAA,GAAA,CAAI,MAAA,EAAQ,SAAA,CAAU,QAAQ,CAAA;AAAA,IAChC,CAAC,CAAA;AAEH,IAAA,OAAO,CAAA,EAAA,GAAM;AACX,MAAA,OAAA,EAAS,KAAA;AACT,MAAA,GAAA,CAAI,UAAA,EAAY,UAAA,CAAW,SAAA,EAAW,IAAA;AAAA,IACxC,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,CAAC,CAAA;AAEL,EAAA,MAAM,kBAAA,EAAoB,gCAAA,MAAY,CAAA,EAAA,GAAY;AAChD,IAAA,MAAM,IAAA,EAAM,OAAO,UAAA,IAAc,YAAA,EAAc,UAAA,EAAY,KAAA,CAAA;AAC3D,IAAA,GAAA,CAAI,iBAAC,GAAA,6BAAK,YAAA,6BAAc,cAAA,EAAc;AACpC,MAAA,SAAA,CAAU,aAAa,CAAA;AACvB,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,EAAS,MAAM,GAAA,CAAI,YAAA,CAAa,YAAA,CAAa,EAAE,KAAA,EAAO,KAAK,CAAC,CAAA;AAClE,MAAA,MAAA,CAAO,SAAA,CAAU,CAAA,CAAE,OAAA,CAAQ,CAAC,KAAA,EAAA,GAAU,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA;AAClD,MAAA,SAAA,CAAU,SAAS,CAAA;AACnB,MAAA,OAAO,IAAA;AAAA,IACT,EAAA,MAAA,CAAS,KAAA,EAAO;AAOd,MAAA,MAAM,UAAA,kBAAa,KAAA,6BAA0C,MAAA;AAC7D,MAAA,MAAM,SAAA,EACJ,UAAA,IAAc,kBAAA,GACd,UAAA,IAAc,gBAAA,GACd,UAAA,IAAc,uBAAA;AAChB,MAAA,SAAA,CAAU,SAAA,EAAW,SAAA,EAAW,QAAQ,CAAA;AACxC,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF,CAAA,EAAG,CAAC,CAAC,CAAA;AAEL,EAAA,OAAO;AAAA,IACL,MAAA;AAAA,IACA,SAAA,EAAW,OAAA,IAAW,SAAA;AAAA,IACtB,WAAA,EAAa,OAAA,IAAW,aAAA;AAAA,IACxB,SAAA,EAAW,OAAA,IAAW,SAAA,GAAY,OAAA,IAAW,QAAA;AAAA,IAC7C;AAAA,EACF,CAAA;AACF;AFZA;AACA;AGzGA;AAaA,IAAM,qBAAA,EAAuB,yBAAA;AAE7B,IAAI,UAAA,EAAY,CAAA;AAChB,IAAI,iBAAA,EAAmB,EAAA;AACvB,IAAI,qBAAA,EAAuB,EAAA;AAE3B,IAAM,UAAA,EAAY,CAAA,EAAA,GAAM;AAEtB,EAAA,MAAM,eAAA,EACJ,MAAA,CAAO,WAAA,EAAa,QAAA,CAAS,eAAA,CAAgB,WAAA;AAE/C,EAAA,iBAAA,EAAmB,QAAA,CAAS,IAAA,CAAK,KAAA,CAAM,QAAA;AACvC,EAAA,qBAAA,EAAuB,QAAA,CAAS,IAAA,CAAK,KAAA,CAAM,YAAA;AAE3C,EAAA,QAAA,CAAS,IAAA,CAAK,KAAA,CAAM,SAAA,EAAW,QAAA;AAG/B,EAAA,GAAA,CAAI,eAAA,EAAiB,CAAA,EAAG;AAItB,IAAA,MAAM,oBAAA,EACJ,MAAA,CAAO,UAAA,CAAW,MAAA,CAAO,gBAAA,CAAiB,QAAA,CAAS,IAAI,CAAA,CAAE,YAAY,EAAA,GACrE,CAAA;AACF,IAAA,QAAA,CAAS,IAAA,CAAK,KAAA,CAAM,aAAA,EAAe,CAAA,EAAA;AAEV,IAAA;AACZ,IAAA;AACW,IAAA;AAAA;AAAA;AAAA;AAIC,aAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA;AAMQ,IAAA;AACnC,EAAA;AACF;AAE0B;AACO,EAAA;AACI,EAAA;AAEV,EAAA;AACZ,EAAA;AACI,IAAA;AACjB,EAAA;AACF;AAKsD;AACpC,EAAA;AACD,IAAA;AAEkB,IAAA;AAClB,IAAA;AAEA,IAAA;AACE,MAAA;AACoB,MAAA;AACnC,IAAA;AACS,EAAA;AACb;AHyEwC;AACA;AC0FxB;AAjNK;AACf,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACN;AAgGe;AACb,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACO,EAAA;AACK,EAAA;AACI,EAAA;AAChB,EAAA;AACkB,EAAA;AACR,EAAA;AACV,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACmB,EAAA;AACnB,EAAA;AACA,EAAA;AACgB;AACM,EAAA;AAC0B,EAAA;AAMA,EAAA;AAErB,EAAA;AACH,EAAA;AACS,EAAA;AAEb,EAAA;AAEiB,EAAA;AAEnC,EAAA;AAOyB,EAAA;AAMA,EAAA;AAQzB,EAAA;AACmB,EAAA;AACnB,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AASE,EAAA;AAIA,EAAA;AAG8B,EAAA;AACd,oBAAA;AACA,IAAA;AACW,MAAA;AAC3B,IAAA;AACF,EAAA;AAG4B,EAAA;AAEnB,IAAA;AACF,MAAA;AAAA,MAAA;AACM,QAAA;AACK,QAAA;AACC,QAAA;AACM,QAAA;AACC,QAAA;AACP,QAAA;AACP,QAAA;AAGJ,QAAA;AAAK,0BAAA;AAGD,YAAA;AACG,cAAA;AAAA,cAAA;AACM,gBAAA;AACY,gBAAA;AACP,gBAAA;AAAA,cAAA;AAEd,YAAA;AAIF,4BAAA;AAAC,cAAA;AAAA,cAAA;AACK,gBAAA;AACwC,gBAAA;AACvB,kBAAA;AACrB,gBAAA;AAIU,gBAAA;AACL,gBAAA;AACK,gBAAA;AAET,gBAAA;AAAA,cAAA;AACH,YAAA;AAIE,YAAA;AAAC,cAAA;AAAA,cAAA;AACM,gBAAA;AACK,gBAAA;AAET,gBAAA;AAAA,cAAA;AACH,YAAA;AAKA,YAAA;AACU,cAAA;AACa,gBAAA;AACN,gBAAA;AACK,gBAAA;AACP,gBAAA;AACF,gBAAA;AAEL,kBAAA;AAAC,oBAAA;AAAA,oBAAA;AACS,sBAAA;AACD,sBAAA;AACF,sBAAA;AACK,sBAAA;AACD,sBAAA;AAER,sBAAA;AAAe,oBAAA;AAClB,kBAAA;AAEJ,gBAAA;AAEE,gBAAA;AAAC,kBAAA;AAAA,kBAAA;AACM,oBAAA;AACK,oBAAA;AACK,oBAAA;AACT,oBAAA;AACA,oBAAA;AAAA,kBAAA;AACR,gBAAA;AAED,cAAA;AACY,cAAA;AACZ,gBAAA;AAAA,gBAAA;AACS,kBAAA;AACD,kBAAA;AACF,kBAAA;AACK,kBAAA;AACD,kBAAA;AAER,kBAAA;AAAe,gBAAA;AAClB,cAAA;AAEJ,YAAA;AAEJ,UAAA;AAIE,UAAA;AAAC,YAAA;AAAA,YAAA;AACU,cAAA;AAEM,cAAA;AACJ,cAAA;AACA,cAAA;AAEX,cAAA;AAAiB,YAAA;AACnB,UAAA;AAAA,QAAA;AAAA,MAAA;AAGN,IAAA;AAEJ,EAAA;AAIO,EAAA;AACF,IAAA;AAAA,IAAA;AACM,MAAA;AACK,MAAA;AACC,MAAA;AACoB,MAAA;AACb,MAAA;AACP,MAAA;AACP,MAAA;AAGJ,MAAA;AAAK,wBAAA;AAEA,UAAA;AAAA,UAAA;AACK,YAAA;AACW,YAAA;AACM,cAAA;AACrB,YAAA;AAIU,YAAA;AACC,YAAA;AACT,cAAA;AAAA;AAAA;AAAA;AAIoB,cAAA;AACtB,YAAA;AAEC,YAAA;AAAA,UAAA;AACH,QAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUM,0BAAA;AAEV,QAAA;AAIE,QAAA;AAAC,UAAA;AAAA,UAAA;AACY,YAAA;AACT,cAAA;AACA,cAAA;AACF,YAAA;AAEA,YAAA;AAAC,cAAA;AAAA,cAAA;AACY,gBAAA;AACT,kBAAA;AACkB,kCAAA;AAEpB,gBAAA;AAEC,gBAAA;AAAA,cAAA;AACH,YAAA;AAAA,UAAA;AACF,QAAA;AAKC,QAAA;AAKD,QAAA;AAAC,UAAA;AAAA,UAAA;AACU,YAAA;AAgBM,YAAA;AACJ,YAAA;AACA,YAAA;AAEX,YAAA;AAAiB,UAAA;AACnB,QAAA;AAAA,MAAA;AAAA,IAAA;AAGN,EAAA;AAEJ;AAEe;AAqD2B;AACxC,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACgB,EAAA;AACR,EAAA;AACR,EAAA;AACW,EAAA;AACgC;AACrB,EAAA;AAC0B,EAAA;AACX,EAAA;AACHA,EAAAA;AAEF,EAAA;AAEK,EAAA;AAEL,EAAA;AACF,IAAA;AACN,IAAA;AACE,EAAA;AAEO,EAAA;AAGT,IAAA;AACJ,oBAAA;AACpB,EAAA;AAEmC,EAAA;AACG,IAAA;AACjB,oBAAA;AACrB,EAAA;AAEyB,EAAA;AACH,EAAA;AACO,EAAA;AAEX,EAAA;AAGX,EAAA;AACF,IAAA;AAAA,IAAA;AACM,MAAA;AAIK,MAAA;AACN,MAAA;AACa,MAAA;AACN,MAAA;AACD,MAAA;AAGV,MAAA;AAAK,wBAAA;AACG,0BAAA;AAIN,0BAAA;AAAC,YAAA;AAAA,YAAA;AACM,cAAA;AACD,cAAA;AACM,cAAA;AACC,cAAA;AAAA,YAAA;AACb,UAAA;AAEM,0BAAA;AAGR,QAAA;AAGK,wBAAA;AACF,0BAAA;AAII,0BAAA;AAGE,4BAAA;AAIA,4BAAA;AAMP,UAAA;AAEA,0BAAA;AAAC,YAAA;AAAA,YAAA;AACS,cAAA;AACH,cAAA;AACK,cAAA;AACD,cAAA;AACV,cAAA;AAAA,YAAA;AAED,UAAA;AAEA,0BAAA;AAAC,YAAA;AAAA,YAAA;AACS,cAAA;AACH,cAAA;AACI,cAAA;AACV,cAAA;AAAA,YAAA;AAED,UAAA;AAGA,0BAAA;AAAC,YAAA;AAAA,YAAA;AACM,cAAA;AACI,cAAA;AACD,cAAA;AACE,cAAA;AAEV,cAAA;AAEA,YAAA;AACF,UAAA;AACF,QAAA;AAAA,MAAA;AAAA,IAAA;AAEJ,EAAA;AAEJ;AACiC;AAoCE;AACjC,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACgB,EAAA;AACR,EAAA;AAC4B;AACd,EAAA;AAC0B,EAAA;AAErB,EAAA;AACH,EAAA;AACO,EAAA;AAEX,EAAA;AAGb,EAAA;AACF,IAAA;AAAA,IAAA;AACM,MAAA;AAEK,MAAA;AACN,MAAA;AACa,MAAA;AACN,MAAA;AACD,MAAA;AAGV,MAAA;AAAK,wBAAA;AACG,0BAAA;AAIA,0BAAA;AAGR,QAAA;AAGK,wBAAA;AACH,0BAAA;AAAC,YAAA;AAAA,YAAA;AACK,cAAA;AACC,cAAA;AACK,cAAA;AAET,cAAA;AAAA,YAAA;AACH,UAAA;AAEA,0BAAA;AAAC,YAAA;AAAA,YAAA;AACS,cAAA;AACH,cAAA;AACK,cAAA;AACD,cAAA;AACV,cAAA;AAAA,YAAA;AAED,UAAA;AAEA,0BAAA;AAAC,YAAA;AAAA,YAAA;AACS,cAAA;AACH,cAAA;AACI,cAAA;AACV,cAAA;AAAA,YAAA;AAED,UAAA;AACF,QAAA;AAAA,MAAA;AAAA,IAAA;AAEJ,EAAA;AAEJ;AACwC;AA8BX;AAC3B,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAAI,EAAA;AAC1E;AAEwD;AAClB,EAAA;AACI,EAAA;AACR,EAAA;AACO,EAAA;AACT,EAAA;AACM,EAAA;AACtC;AAgB0C;AACxC,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACgB,EAAA;AAC2B;AACK,EAAA;AACF,EAAA;AACZA,EAAAA;AACIA,EAAAA;AACNA,EAAAA;AACEA,EAAAA;AAGC,EAAA;AAER,EAAA;AACH,EAAA;AACO,EAAA;AAGf,EAAA;AACa,IAAA;AACH,MAAA;AACtB,MAAA;AACF,IAAA;AACmC,IAAA;AACnB,IAAA;AACoB,IAAA;AAC9B,EAAA;AAEQ,EAAA;AAED,IAAA;AACO,MAAA;AACF,MAAA;AAClB,IAAA;AACS,EAAA;AAEc,EAAA;AACA,IAAA;AACX,IAAA;AACG,IAAA;AACD,MAAA;AACM,MAAA;AACb,IAAA;AAMU,sBAAA;AAEjB,IAAA;AACF,EAAA;AAE6D,EAAA;AACpC,IAAA;AACQ,IAAA;AACE,IAAA;AACG,IAAA;AACF,IAAA;AACF,IAAA;AAClC,EAAA;AAEoB,EAAA;AAEa,EAAA;AAG1B,EAAA;AACF,IAAA;AAAA,IAAA;AACM,MAAA;AAEK,MAAA;AACN,MAAA;AACO,MAAA;AACA,MAAA;AACD,MAAA;AAGV,MAAA;AAAK,wBAAA;AACG,0BAAA;AAKN,0BAAA;AAAC,YAAA;AAAA,YAAA;AACW,cAAA;AACE,cAAA;AAEX,cAAA;AACE,gBAAA;AAAA,gBAAA;AAEiB,kBAAA;AACN,kBAAA;AAAA,gBAAA;AAFL,gBAAA;AAIR,cAAA;AAAA,YAAA;AACH,UAAA;AAGK,0BAAA;AACH,4BAAA;AAAC,cAAA;AAAA,cAAA;AACM,gBAAA;AACA,gBAAA;AACG,gBAAA;AAEN,gBAAA;AAGA,gBAAA;AAEa,gBAAA;AACK,kBAAA;AACF,kBAAA;AAClB,gBAAA;AAEA,gBAAA;AAAuB,cAAA;AACzB,YAAA;AAEA,4BAAA;AAAC,cAAA;AAAA,cAAA;AACM,gBAAA;AACI,gBAAA;AACE,gBAAA;AACC,gBAAA;AACJ,gBAAA;AACE,gBAAA;AAGR,gBAAA;AAEkC,cAAA;AAEtC,YAAA;AAEA,4BAAA;AAAC,cAAA;AAAA,cAAA;AACM,gBAAA;AACI,gBAAA;AACE,gBAAA;AACH,gBAAA;AACE,gBAAA;AAEV,gBAAA;AAAC,kBAAA;AAAA,kBAAA;AACW,oBAAA;AACS,oBAAA;AAAY,kBAAA;AACjC,gBAAA;AAAA,cAAA;AACF,YAAA;AAEC,4BAAA;AAGH,UAAA;AACF,QAAA;AAGK,wBAAA;AACH,0BAAA;AAAC,YAAA;AAAA,YAAA;AACS,cAAA;AACH,cAAA;AACK,cAAA;AACD,cAAA;AACV,cAAA;AAAA,YAAA;AAED,UAAA;AAEC,0BAAA;AAGH,QAAA;AAAA,MAAA;AAAA,IAAA;AAEJ,EAAA;AAEJ;AACiC;AAmCG;AAClC,EAAA;AACA,EAAA;AACQ,EAAA;AACM,EAAA;AACE,EAAA;AACL,EAAA;AAC0B;AACf,EAAA;AAC0B,EAAA;AAErB,EAAA;AACH,EAAA;AACO,EAAA;AAEX,EAAA;AAGb,EAAA;AACF,IAAA;AAAA,IAAA;AACM,MAAA;AAEK,MAAA;AACN,MAAA;AACa,MAAA;AACN,MAAA;AACD,MAAA;AAET,MAAA;AACO,wBAAA;AAIN,wBAAA;AAAC,UAAA;AAAA,UAAA;AACM,YAAA;AACD,YAAA;AACM,YAAA;AACC,YAAA;AAAA,UAAA;AACb,QAAA;AAEK,wBAAA;AACH,0BAAA;AAAC,YAAA;AAAA,YAAA;AACK,cAAA;AACC,cAAA;AACK,cAAA;AAET,cAAA;AAAA,YAAA;AACH,UAAA;AACA,0BAAA;AAAC,YAAA;AAAA,YAAA;AACM,cAAA;AACK,cAAA;AAET,cAAA;AAAA,YAAA;AACH,UAAA;AACF,QAAA;AACF,MAAA;AAAA,IAAA;AAEJ,EAAA;AAEJ;AAC2B;ADzRa;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-23PAYKWB.js","sourcesContent":[null,"import {\n ReactNode,\n MouseEvent,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport { XIcon } from '@phosphor-icons/react/dist/csr/X';\nimport {\n MicIconReadingFluency,\n MicOffIconReadingFluency,\n PlayIconReadingFluency,\n PauseIconReadingFluency,\n} from '../ReadingFluencyIcons';\nimport { cn } from '../../utils/utils';\nimport Button, { ButtonReadingFluency } from '../Button/Button';\nimport { CloseButtonReadingFluency } from '../CloseButtonReadingFluency/CloseButtonReadingFluency';\nimport readingFluencyBird from '../../assets/img/readingFluencyBird.png';\nimport { readingFluencyFallback } from '../../assets/fallbacks/readingFluencyFallback';\nimport { useMicrophonePermission } from '../../hooks/useMicrophonePermission';\nimport { useEscapeToClose } from '../../hooks/useEscapeToClose';\nimport { useBodyScrollLock } from '../../hooks/useBodyScrollLock';\nimport { useModalFocus } from '../../hooks/useModalFocus';\nimport {\n isYouTubeUrl,\n getYouTubeVideoId,\n getYouTubeEmbedUrl,\n} from './utils/videoUtils';\nimport Text from '../Text/Text';\n\n/**\n * Lookup table for size classes\n */\nconst SIZE_CLASSES = {\n xs: 'max-w-[360px]',\n sm: 'max-w-[420px]',\n md: 'max-w-[510px]',\n lg: 'max-w-[640px]',\n xl: 'max-w-[970px]',\n} as const;\n\n/**\n * Modal component props interface\n */\ntype ModalProps = {\n contentClassName?: string;\n /** Whether the modal is open */\n isOpen: boolean;\n /** Function to close the modal */\n onClose: () => void;\n /**\n * Modal title. Aceita string OU ReactNode pra permitir elementos inline\n * (ex: botão de voltar + label). Como é renderizado dentro de <h2>,\n * quando ReactNode use APENAS phrasing content (`<span>`, `<button>`,\n * ícones) — nunca `<div>` ou `<p>`.\n */\n title: ReactNode;\n /** Modal description/content */\n children?: ReactNode;\n /** Size of the modal */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** Additional CSS classes for the modal content */\n className?: string;\n /** Whether pressing Escape should close the modal */\n closeOnEscape?: boolean;\n /** Footer content (typically buttons) */\n footer?: ReactNode;\n /** Hide the close button */\n hideCloseButton?: boolean;\n /** Modal variant */\n variant?: 'default' | 'activity';\n /** Description for activity variant */\n description?: string;\n /** Image URL for activity variant */\n image?: string;\n /** Alt text for activity image (leave empty for decorative images) */\n imageAlt?: string;\n /** Action link for activity variant */\n actionLink?: string;\n /** Action button label for activity variant */\n actionLabel?: string;\n /**\n * Called when the action button is clicked, before the link opens.\n *\n * Lets the caller record the click — the notification center uses it to mark a\n * notice as read when the reader follows its \"Ver mais\" link. Optional and\n * side-effect free when omitted: the link still opens either way.\n */\n onActionClick?: () => void;\n /**\n * Id of the element that names the dialog. Overrides the built-in `<h2>`\n * title — use it when the visible title lives inside `children`.\n */\n labelledBy?: string;\n /**\n * Id of the element that describes the dialog, read by screen readers right\n * after the title when the dialog receives focus.\n */\n describedBy?: string;\n};\n\n/**\n * Modal component for Analytica Ensino platforms\n *\n * A flexible modal component with multiple size variants and customizable behavior.\n *\n * @param isOpen - Whether the modal is currently open\n * @param onClose - Callback function called when the modal should be closed\n * @param title - The title displayed at the top of the modal\n * @param children - The main content of the modal\n * @param size - The size variant (xs, sm, md, lg, xl)\n * @param className - Additional CSS classes for the modal content\n * @param closeOnEscape - Whether pressing Escape closes the modal (default: true)\n * @param footer - Footer content, typically action buttons\n * @param hideCloseButton - Whether to hide the X close button (default: false)\n * @returns A modal overlay with content\n *\n * @example\n * ```tsx\n * <Modal\n * isOpen={isModalOpen}\n * onClose={() => setIsModalOpen(false)}\n * title=\"Invite your team\"\n * size=\"md\"\n * footer={\n * <div className=\"flex gap-3\">\n * <Button variant=\"outline\" onClick={() => setIsModalOpen(false)}>Cancel</Button>\n * <Button variant=\"solid\" onClick={handleExplore}>Explore</Button>\n * </div>\n * }\n * >\n * Elevate user interactions with our versatile modals.\n * </Modal>\n * ```\n */\nconst Modal = ({\n isOpen,\n onClose,\n title,\n children,\n size = 'md',\n className = '',\n closeOnEscape = true,\n footer,\n hideCloseButton = false,\n variant = 'default',\n description,\n image,\n imageAlt,\n actionLink,\n actionLabel,\n onActionClick,\n contentClassName = '',\n labelledBy,\n describedBy,\n}: ModalProps) => {\n const titleId = useId();\n const dialogRef = useRef<HTMLDialogElement>(null);\n /**\n * O título é quem recebe o foco na abertura (ver `useModalFocus`). Guardado\n * como `HTMLElement` porque as duas montagens o renderizam com tags\n * diferentes — `<h2>` na default, `<Text>` (um `<p>`) na activity.\n */\n const titleRef = useRef<HTMLElement | null>(null);\n\n useEscapeToClose(isOpen && closeOnEscape, onClose);\n useBodyScrollLock(isOpen);\n useModalFocus(isOpen, dialogRef, titleRef);\n\n if (!isOpen) return null;\n\n const sizeClasses = SIZE_CLASSES[size];\n const baseClasses =\n 'bg-secondary-50 rounded-3xl shadow-hard-shadow-2 border border-border-100 w-full mx-4 max-h-[calc(100dvh-2rem)] flex flex-col overflow-hidden';\n // Reset dialog default styles to prevent positioning issues.\n //\n // `relative` (antes era `static`) segue anulando o `position: absolute` que o\n // navegador aplica ao <dialog> aberto — sem isso ele escapa da centralização\n // do backdrop — e agora também ancora o botão de fechar, que é o ÚLTIMO do\n // DOM nas duas montagens e volta ao topo à direita pelo CSS.\n const dialogResetClasses = 'm-0 border-none outline-none relative';\n /**\n * Espaço acima do conteúdo na montagem activity: 24px de padding, mais os\n * 26px do botão quando ele aparece. É o que o header do X reservava antes de\n * ele virar `absolute`.\n */\n const activityTopPadding = hideCloseButton ? 'pt-6' : 'pt-12.5';\n /**\n * Padding do diálogo. Na montagem activity o X não tem mais um header pra\n * ocupar, então o espaço acima vira padding do PRÓPRIO diálogo — fora da área\n * que rola, pro conteúdo não passar por baixo do X quando ele transborda.\n * `px-0`/`pb-0` no lugar de `p-0` pra não disputar com o `pt-*`.\n */\n const dialogPaddingClasses =\n variant === 'activity' ? cn('px-0 pb-0', activityTopPadding) : 'p-0';\n const modalClasses = cn(\n baseClasses,\n sizeClasses,\n dialogResetClasses,\n dialogPaddingClasses,\n className\n );\n\n /**\n * Classes do botão de fechar. Ele é o último elemento do DOM nas duas\n * montagens — pro leitor de tela percorrer título → conteúdo → ações e só\n * então chegar nele — e volta ao canto superior direito por `absolute`. As\n * coordenadas reproduzem onde ele estava: 24px do topo e da direita.\n */\n const closeButtonClasses =\n 'absolute right-6 top-6 p-1 text-text-500 hover:text-text-700 hover:bg-background-50 rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-indicator-info focus:ring-offset-2';\n\n // Normalize URLs missing protocol\n const normalizeUrl = (href: string) =>\n /^https?:\\/\\//i.test(href) ? href : `https://${href}`;\n\n // Handle action link click\n const handleActionClick = () => {\n onActionClick?.();\n if (actionLink) {\n window.open(normalizeUrl(actionLink), '_blank', 'noopener,noreferrer');\n }\n };\n\n // Activity variant rendering\n if (variant === 'activity') {\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs border-none p-0 m-0 w-full cursor-default\">\n <dialog\n ref={dialogRef}\n tabIndex={-1}\n className={modalClasses}\n aria-labelledby={labelledBy ?? titleId}\n aria-describedby={describedBy}\n aria-modal=\"true\"\n open\n >\n {/* Conteúdo centralizado */}\n <div className=\"flex flex-col items-center px-6 pb-6 gap-5 flex-1 min-h-0 overflow-y-auto\">\n {/* Imagem ilustrativa */}\n {image && (\n <div className=\"flex justify-center\">\n <img\n src={image}\n alt={imageAlt ?? ''}\n className=\"w-[122px] h-[122px] object-contain\"\n />\n </div>\n )}\n\n {/* Título */}\n <Text\n id={titleId}\n ref={(node: HTMLParagraphElement | null) => {\n titleRef.current = node;\n }}\n // Alvo do foco inicial (`useModalFocus`), e não um controle:\n // recebe foco por código, fica fora do ciclo de Tab e não mostra\n // anel.\n tabIndex={-1}\n size=\"lg\"\n className=\"font-semibold text-text-950 text-center focus:outline-none\"\n >\n {title}\n </Text>\n\n {/* Descrição */}\n {description && (\n <Text\n size=\"sm\"\n className=\"text-text-400 text-center max-w-md leading-[21px]\"\n >\n {description}\n </Text>\n )}\n\n {/* Ação: Botão ou Vídeo Embedado */}\n {actionLink && (\n <div className=\"w-full\">\n {(() => {\n const normalized = normalizeUrl(actionLink);\n const isYT = isYouTubeUrl(normalized);\n if (!isYT) return null;\n const id = getYouTubeVideoId(normalized);\n if (!id) {\n return (\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"large\"\n className=\"w-full\"\n onClick={handleActionClick}\n >\n {actionLabel || 'Iniciar Atividade'}\n </Button>\n );\n }\n return (\n <iframe\n src={getYouTubeEmbedUrl(id)}\n className=\"w-full aspect-video rounded-lg\"\n allowFullScreen\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\"\n title=\"Vídeo YouTube\"\n />\n );\n })()}\n {!isYouTubeUrl(normalizeUrl(actionLink)) && (\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"large\"\n className=\"w-full\"\n onClick={handleActionClick}\n >\n {actionLabel || 'Iniciar Atividade'}\n </Button>\n )}\n </div>\n )}\n </div>\n\n {/* Fechar: ÚLTIMO no DOM — ver `closeButtonClasses` */}\n {!hideCloseButton && (\n <button\n onClick={onClose}\n // Ver a nota sobre `data-print-hide` na montagem default abaixo.\n data-print-hide\n className={closeButtonClasses}\n aria-label=\"Fechar modal\"\n >\n <XIcon size={18} />\n </button>\n )}\n </dialog>\n </div>\n );\n }\n\n // Default variant rendering\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs border-none p-0 m-0 w-full cursor-default\">\n <dialog\n ref={dialogRef}\n tabIndex={-1}\n className={modalClasses}\n aria-labelledby={labelledBy ?? titleId}\n aria-describedby={describedBy}\n aria-modal=\"true\"\n open\n >\n {/* Header — só o título: o X é o último do DOM, lá embaixo */}\n <div className=\"flex items-center justify-between px-6 py-6\">\n {title ? (\n <h2\n id={titleId}\n ref={(node) => {\n titleRef.current = node;\n }}\n // Alvo do foco inicial (`useModalFocus`), e não um controle:\n // recebe foco por código, fica fora do ciclo de Tab e não mostra\n // anel.\n tabIndex={-1}\n className={cn(\n 'text-lg font-semibold text-text-950 focus:outline-none',\n // Reserva a faixa do X, que era um irmão no `justify-between` e\n // agora flutua por cima do header: sem isso um título longo\n // passaria por baixo dele.\n !hideCloseButton && 'pr-8'\n )}\n >\n {title}\n </h2>\n ) : (\n // Keeps the header height when the title lives in `children`,\n // without leaving an empty heading in the accessibility tree.\n //\n // A altura é a do X (18px do ícone + 2x4px do `p-1`), que ocupava\n // esta linha e hoje flutua por cima dela: sem reservá-la, um modal\n // sem título próprio encolheria e o botão encostaria no conteúdo.\n // Com título não é preciso — a linha do `text-lg` (28px) já é mais\n // alta que o botão, como antes.\n <span className={cn('block', !hideCloseButton && 'h-6.5')} />\n )}\n </div>\n\n {/* Content */}\n {children && (\n <div\n className={cn(\n 'px-6 pb-6 flex-1 min-h-0 overflow-y-auto',\n contentClassName\n )}\n >\n <div\n className={cn(\n 'text-text-500 font-normal text-sm leading-6',\n contentClassName?.includes('flex') &&\n 'flex flex-col flex-1 min-h-0'\n )}\n >\n {children}\n </div>\n </div>\n )}\n\n {/* Footer */}\n {footer && (\n <div className=\"flex justify-end gap-3 px-6 pb-6\">{footer}</div>\n )}\n\n {/* Fechar: ÚLTIMO no DOM — ver `closeButtonClasses` */}\n {!hideCloseButton && (\n <button\n onClick={onClose}\n /*\n * O X não sai no PDF. Quando este modal é a região de impressão\n * (`js-print-region` + `body.printing-modal`), o print.css revela\n * o <dialog> INTEIRO — o botão mora dentro dele e nada mais o\n * esconderia.\n *\n * O atributo vai no próprio botão, e não num container, como manda\n * o contrato do print.css: ele É o elemento inteiro a esconder.\n * A razão do contrato — colapsar junto o espaçamento do flex — não\n * se aplica, porque o botão está fora do fluxo (`absolute`) e não\n * ocupa espaço nenhum para colapsar.\n *\n * Inerte fora de `@media print`, e só surte efeito em quem importa\n * `analytica-frontend-lib/print.css`.\n */\n data-print-hide\n className={closeButtonClasses}\n aria-label=\"Fechar modal\"\n >\n <XIcon size={18} />\n </button>\n )}\n </dialog>\n </div>\n );\n};\n\nexport default Modal;\n\n// ======================================================================\n// MicPermissionModalReadingFluency — modal Reading Fluency de permissão de microfone\n// ======================================================================\n\ntype MicPermissionModalReadingFluencyProps = {\n /**\n * Controla a abertura (modo controlado). **Se omitido**, o modal entra em modo\n * gerenciado: usa `useMicrophonePermission` e se abre sozinho quando o\n * microfone ainda não foi concedido.\n */\n isOpen?: boolean;\n /** Fecha o modal (X e Esc). No modo gerenciado, apenas dispensa na sessão. */\n onClose?: () => void;\n /**\n * Chamado após o botão \"Habilitar permissões\" (o prompt do navegador já é\n * disparado internamente). Recebe se a permissão foi concedida.\n */\n onEnable?: (granted: boolean) => void;\n /** Ação do link \"Configurar depois\". */\n onConfigureLater?: () => void;\n /** Ação da barra \"Saiba mais sobre como cuidamos dos dados\". */\n onLearnMore?: () => void;\n /** Fecha ao pressionar Esc (default: true). */\n closeOnEscape?: boolean;\n /** Título (default: \"Por que pedimos acesso ao microfone\"). */\n title?: string;\n /** Texto explicativo (default: o texto da arte). */\n description?: ReactNode;\n /**\n * Fonte da imagem do passarinho. Default: o PNG Reading Fluency empacotado na lib.\n * Passe uma URL pelo cliente caso o asset da lib não seja resolvido no bundle.\n */\n imageSrc?: string;\n};\n\n/**\n * Modal Reading Fluency que pede permissão de uso do microfone.\n *\n * Header verde (`secondary-500`) com o passarinho + ícone de microfone e o botão\n * de fechar (`ButtonReadingFluency variant=\"icon\"`); corpo branco com título, texto e as\n * ações (`ButtonReadingFluency` solid \"Habilitar permissões\" + link \"Configurar depois\");\n * barra inferior verde-clara com o link \"Saiba mais...\".\n *\n * Modo **gerenciado** (sem `isOpen`): usa `useMicrophonePermission` — abre\n * sozinho quando o microfone não foi concedido, \"Habilitar permissões\" dispara o\n * prompt do navegador e \"Configurar depois\" apenas dispensa na sessão (como não\n * persiste, ao recarregar a página volta a pedir). Passando `isOpen`, vira\n * controlado (o `onEnable` ainda dispara o prompt do navegador).\n *\n * Observação: os tokens de cor/spacing são uma leitura da arte — ajustar na story.\n */\nconst MicPermissionModalReadingFluency = ({\n isOpen,\n onClose,\n onEnable,\n onConfigureLater,\n onLearnMore,\n closeOnEscape = true,\n title = 'Por que pedimos acesso ao microfone',\n description,\n imageSrc = readingFluencyBird,\n}: MicPermissionModalReadingFluencyProps) => {\n const titleId = useId();\n const dialogRef = useRef<HTMLDialogElement>(null);\n const { shouldAsk, requestPermission } = useMicrophonePermission();\n const [dismissed, setDismissed] = useState(false);\n\n const isControlled = isOpen !== undefined;\n // Gerenciado: abre quando falta permissão e não foi dispensado nesta sessão.\n const open = isControlled ? isOpen : shouldAsk && !dismissed;\n\n const handleClose = useCallback(() => {\n if (isControlled) onClose?.();\n else setDismissed(true);\n }, [isControlled, onClose]);\n\n const handleEnable = async () => {\n // Dispara o prompt nativo do navegador. No modo gerenciado, se conceder, o\n // `shouldAsk` vira false e o modal fecha sozinho.\n const granted = await requestPermission();\n onEnable?.(granted);\n };\n\n const handleConfigureLater = () => {\n if (!isControlled) setDismissed(true);\n onConfigureLater?.();\n };\n\n useEscapeToClose(open && closeOnEscape, handleClose);\n useBodyScrollLock(open);\n useModalFocus(open, dialogRef);\n\n if (!open) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs p-4\">\n <dialog\n ref={dialogRef}\n // `tabIndex={-1}` é requisito do `useModalFocus`: o foco inicial vai\n // pro próprio diálogo, pro leitor anunciar título e texto antes das\n // ações.\n tabIndex={-1}\n open\n aria-labelledby={titleId}\n aria-modal=\"true\"\n className=\"font-quicksand static m-0 w-full max-w-[420px] overflow-hidden rounded-3xl border-none p-0 shadow-hard-shadow-2\"\n >\n {/* Header verde */}\n <div className=\"relative flex items-center justify-center gap-3 bg-secondary-500 px-6 pt-8 pb-10\">\n <span className=\"absolute right-4 top-4\">\n <CloseButtonReadingFluency onClick={handleClose} />\n </span>\n\n <img\n src={imageSrc}\n alt=\"Reading Fluency\"\n className=\"h-14 w-auto select-none\"\n draggable={false}\n />\n\n <span className=\"flex size-14 items-center justify-center rounded-full bg-background\">\n <MicIconReadingFluency size={28} />\n </span>\n </div>\n\n {/* Corpo (padding 24) */}\n <div className=\"flex flex-col items-center gap-4 bg-background p-6 text-center\">\n <Text size=\"lg\" id={titleId} className=\"font-bold text-secondary-900\">\n {title}\n </Text>\n\n <div className=\"flex flex-col gap-3 text-[14px] font-medium text-text-600\">\n {description ?? (\n <>\n <Text size=\"sm\">\n Usamos o microfone para gravar a leitura da criança e avaliar\n sua fluência leitora ao longo do tempo.\n </Text>\n <Text size=\"sm\">\n As gravações ficam armazenadas com segurança e são usadas\n apenas para esse fim.\n </Text>\n </>\n )}\n </div>\n\n <ButtonReadingFluency\n variant=\"solid\"\n size=\"medium\"\n className=\"mt-2\"\n onClick={handleEnable}\n >\n Habilitar permissões\n </ButtonReadingFluency>\n\n <ButtonReadingFluency\n variant=\"link\"\n size=\"medium\"\n onClick={handleConfigureLater}\n >\n Configurar depois\n </ButtonReadingFluency>\n\n {/* Barra \"Saiba mais\": botão arredondado, inset pelo padding do corpo */}\n <Button\n type=\"button\"\n onClick={onLearnMore}\n variant=\"raw\"\n className=\"w-full cursor-pointer rounded-xl bg-secondary-100 px-4 py-4 text-center\"\n >\n <span className=\"text-[14px] font-medium text-secondary-700 underline\">\n Saiba mais sobre como cuidamos dos dados\n </span>\n </Button>\n </div>\n </dialog>\n </div>\n );\n};\nMicPermissionModalReadingFluency.displayName =\n 'MicPermissionModalReadingFluency';\n\nexport { MicPermissionModalReadingFluency };\nexport type { MicPermissionModalReadingFluencyProps };\n\n// ======================================================================\n// MicOffModalReadingFluency — modal Reading Fluency de \"microfone parece desligado\"\n// ======================================================================\n\ntype MicOffModalReadingFluencyProps = {\n /** Se o modal está aberto. */\n isOpen: boolean;\n /** Fecha o modal (X e Esc). */\n onClose: () => void;\n /** Ação do botão \"Tentar ler de novo\". */\n onRetry?: () => void;\n /** Ação do link \"Pedir ajuda a um adulto\". */\n onAskAdult?: () => void;\n /** Fecha ao pressionar Esc (default: true). */\n closeOnEscape?: boolean;\n /** Título (default: \"Parece que o microfone está desligado\"). */\n title?: string;\n};\n\n/**\n * Modal Reading Fluency exibido quando o microfone parece desligado/mudo durante a\n * leitura. Header verde com o ícone de microfone cortado + botão de fechar;\n * corpo branco com o título (uppercase) e as ações \"Tentar ler de novo\"\n * (`ButtonReadingFluency` solid) e \"Pedir ajuda a um adulto\" (`ButtonReadingFluency` link).\n *\n * É um modal controlado (o app decide quando abrir — ex.: ao detectar que não\n * há áudio durante a gravação).\n *\n * Observação: os tokens de cor/spacing são uma leitura da arte — ajustar na story.\n */\nconst MicOffModalReadingFluency = ({\n isOpen,\n onClose,\n onRetry,\n onAskAdult,\n closeOnEscape = true,\n title = 'Parece que o microfone está desligado',\n}: MicOffModalReadingFluencyProps) => {\n const titleId = useId();\n const dialogRef = useRef<HTMLDialogElement>(null);\n\n useEscapeToClose(isOpen && closeOnEscape, onClose);\n useBodyScrollLock(isOpen);\n useModalFocus(isOpen, dialogRef);\n\n if (!isOpen) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs p-4\">\n <dialog\n ref={dialogRef}\n // Ver a nota sobre `tabIndex={-1}` no MicPermissionModalReadingFluency.\n tabIndex={-1}\n open\n aria-labelledby={titleId}\n aria-modal=\"true\"\n className=\"font-quicksand static m-0 w-full max-w-[420px] overflow-hidden rounded-3xl border-none p-0 shadow-hard-shadow-2\"\n >\n {/* Header verde */}\n <div className=\"relative flex items-center justify-center bg-secondary-500 px-6 pt-10 pb-10\">\n <span className=\"absolute right-4 top-4\">\n <CloseButtonReadingFluency onClick={onClose} />\n </span>\n\n <span className=\"flex size-20 items-center justify-center rounded-full bg-background shadow-hard-shadow-2\">\n <MicOffIconReadingFluency size={40} />\n </span>\n </div>\n\n {/* Corpo (padding 24) */}\n <div className=\"flex flex-col items-center gap-4 bg-background p-6 text-center\">\n <Text\n id={titleId}\n size=\"lg\"\n className=\"font-bold uppercase text-secondary-900\"\n >\n {title}\n </Text>\n\n <ButtonReadingFluency\n variant=\"solid\"\n size=\"medium\"\n className=\"mt-2\"\n onClick={onRetry}\n >\n Tentar ler de novo\n </ButtonReadingFluency>\n\n <ButtonReadingFluency\n variant=\"link\"\n size=\"medium\"\n onClick={onAskAdult}\n >\n Pedir ajuda a um adulto\n </ButtonReadingFluency>\n </div>\n </dialog>\n </div>\n );\n};\nMicOffModalReadingFluency.displayName = 'MicOffModalReadingFluency';\n\nexport { MicOffModalReadingFluency };\nexport type { MicOffModalReadingFluencyProps };\n\n// ======================================================================\n// AudioPlaybackModalReadingFluency — modal Reading Fluency para ouvir a gravação\n// ======================================================================\n\ntype AudioPlaybackModalReadingFluencyProps = {\n /** Se o modal está aberto. */\n isOpen: boolean;\n /** Fecha o modal (X e Esc). */\n onClose: () => void;\n /**\n * A gravação a tocar: uma **URL** (string, ex.: blob URL) **ou** um\n * **arquivo/blob** (`File`/`Blob` — ex.: o blob do `AudioRecorderReadingFluency`).\n * Quando é `File`/`Blob`, vira um object URL same-origin internamente\n * (criado/revogado pelo componente).\n */\n src?: string | File | Blob;\n /** Ação do botão \"Pronto!\". */\n onConfirm?: () => void;\n /** Ação do link \"Quero ler de novo\". */\n onRetry?: () => void;\n /** Fecha ao pressionar Esc (default: true). */\n closeOnEscape?: boolean;\n};\n\n// Alturas (px) das barras da waveform — decorativa (não reflete o áudio real).\nconst PAPOLE_WAVEFORM_BARS = [\n 12, 20, 32, 16, 40, 24, 52, 28, 44, 60, 44, 28, 52, 24, 40, 16, 32, 20, 12,\n];\n\nconst formatPlaybackTime = (seconds: number): string => {\n const safe = Number.isFinite(seconds) ? Math.max(0, seconds) : 0;\n const pad = (n: number) => n.toString().padStart(2, '0');\n const h = Math.floor(safe / 3600);\n const m = Math.floor((safe % 3600) / 60);\n const s = Math.floor(safe % 60);\n return `${pad(h)}:${pad(m)}:${pad(s)}`;\n};\n\n/**\n * Modal Reading Fluency para o aluno ouvir a própria gravação. Header verde com uma\n * waveform decorativa e um player simples (play/pause + barra de progresso +\n * tempo) + botão de fechar; corpo branco com \"Pronto!\" (`ButtonReadingFluency` solid) e\n * \"Quero ler de novo\" (`ButtonReadingFluency` link).\n *\n * A gravação entra por `src`, que aceita **URL** (string) **ou** **File/Blob**\n * (ex.: o blob do `AudioRecorderReadingFluency`, convertido em object URL internamente).\n *\n * Controlado: o app decide quando abrir (ex.: após finalizar a gravação).\n *\n * Observação: waveform é decorativa (não analisa o áudio) e os tokens de\n * cor/spacing são uma leitura da arte — ajustar na story.\n */\nconst AudioPlaybackModalReadingFluency = ({\n isOpen,\n onClose,\n src,\n onConfirm,\n onRetry,\n closeOnEscape = true,\n}: AudioPlaybackModalReadingFluencyProps) => {\n const dialogRef = useRef<HTMLDialogElement>(null);\n const audioRef = useRef<HTMLAudioElement>(null);\n const [isPlaying, setIsPlaying] = useState(false);\n const [currentTime, setCurrentTime] = useState(0);\n const [duration, setDuration] = useState(0);\n const [objectUrl, setObjectUrl] = useState<string | undefined>(undefined);\n\n // String → usa direto; File/Blob → usa o object URL criado no efeito abaixo.\n const resolvedSrc = typeof src === 'string' ? src : objectUrl;\n\n useEscapeToClose(isOpen && closeOnEscape, onClose);\n useBodyScrollLock(isOpen);\n useModalFocus(isOpen, dialogRef);\n\n // `src` File/Blob → object URL same-origin (criado/revogado aqui).\n useEffect(() => {\n if (!src || typeof src === 'string') {\n setObjectUrl(undefined);\n return;\n }\n const url = URL.createObjectURL(src);\n setObjectUrl(url);\n return () => URL.revokeObjectURL(url);\n }, [src]);\n\n useEffect(() => {\n // Reseta o player ao fechar (o <audio> desmonta com o modal).\n if (!isOpen) {\n setIsPlaying(false);\n setCurrentTime(0);\n }\n }, [isOpen]);\n\n const togglePlay = () => {\n const audio = audioRef.current;\n if (!audio) return;\n if (isPlaying) {\n audio.pause();\n setIsPlaying(false);\n } else {\n // Só marca como tocando depois que o play() resolve. Se rejeitar\n // (AbortError ao pausar antes de iniciar, fonte inválida, etc.) mantém\n // false pra UI nunca indicar reprodução ativa numa falha.\n audio\n .play()\n ?.then(() => setIsPlaying(true))\n .catch(() => setIsPlaying(false));\n }\n };\n\n const handleSeek = (event: MouseEvent<HTMLButtonElement>) => {\n const audio = audioRef.current;\n if (!audio || !Number.isFinite(duration) || duration <= 0) return;\n const rect = event.currentTarget.getBoundingClientRect();\n const ratio = (event.clientX - rect.left) / rect.width;\n audio.currentTime = Math.min(Math.max(ratio, 0), 1) * duration;\n setCurrentTime(audio.currentTime);\n };\n\n if (!isOpen) return null;\n\n const progress = duration > 0 ? (currentTime / duration) * 100 : 0;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs p-4\">\n <dialog\n ref={dialogRef}\n // Ver a nota sobre `tabIndex={-1}` no MicPermissionModalReadingFluency.\n tabIndex={-1}\n open\n aria-label=\"Ouvir gravação\"\n aria-modal=\"true\"\n className=\"font-quicksand static m-0 w-full max-w-[420px] overflow-hidden rounded-3xl border-none p-0 shadow-hard-shadow-2\"\n >\n {/* Header verde: waveform + player */}\n <div className=\"relative flex flex-col gap-5 bg-secondary-500 px-6 pt-8 pb-6\">\n <span className=\"absolute right-4 top-4\">\n <CloseButtonReadingFluency onClick={onClose} />\n </span>\n\n {/* Waveform (decorativa) */}\n <div\n className=\"flex h-16 items-center justify-center gap-1\"\n aria-hidden=\"true\"\n >\n {PAPOLE_WAVEFORM_BARS.map((height, index) => (\n <span\n key={index}\n style={{ height }}\n className=\"w-1 rounded-full bg-error-400\"\n />\n ))}\n </div>\n\n {/* Player */}\n <div className=\"flex items-center gap-3\">\n <audio\n ref={audioRef}\n src={resolvedSrc}\n preload=\"metadata\"\n onTimeUpdate={() =>\n setCurrentTime(audioRef.current?.currentTime ?? 0)\n }\n onLoadedMetadata={() =>\n setDuration(audioRef.current?.duration ?? 0)\n }\n onEnded={() => {\n setIsPlaying(false);\n setCurrentTime(0);\n }}\n >\n <track kind=\"captions\" />\n </audio>\n\n <Button\n type=\"button\"\n onClick={togglePlay}\n disabled={!resolvedSrc}\n aria-label={isPlaying ? 'Pausar' : 'Reproduzir'}\n variant=\"raw\"\n className=\"flex flex-shrink-0 items-center justify-center disabled:cursor-not-allowed disabled:opacity-40\"\n >\n {isPlaying ? (\n <PauseIconReadingFluency size={36} />\n ) : (\n <PlayIconReadingFluency size={36} />\n )}\n </Button>\n\n <Button\n type=\"button\"\n onClick={handleSeek}\n aria-label=\"Barra de progresso\"\n variant=\"raw\"\n className=\"h-2 flex-1 overflow-hidden rounded-full bg-background\"\n >\n <span\n className=\"block h-full rounded-full bg-primary-500 transition-[width] duration-100\"\n style={{ width: `${progress}%` }}\n />\n </Button>\n\n <span className=\"flex-shrink-0 text-sm font-medium text-primary\">\n {formatPlaybackTime(currentTime)}\n </span>\n </div>\n </div>\n\n {/* Corpo (padding 24) */}\n <div className=\"flex flex-col items-center gap-4 bg-background p-6 text-center\">\n <ButtonReadingFluency\n variant=\"solid\"\n size=\"medium\"\n className=\"w-full\"\n onClick={onConfirm}\n >\n Pronto!\n </ButtonReadingFluency>\n\n <ButtonReadingFluency variant=\"link\" size=\"medium\" onClick={onRetry}>\n Quero ler de novo\n </ButtonReadingFluency>\n </div>\n </dialog>\n </div>\n );\n};\nAudioPlaybackModalReadingFluency.displayName =\n 'AudioPlaybackModalReadingFluency';\n\nexport { AudioPlaybackModalReadingFluency };\nexport type { AudioPlaybackModalReadingFluencyProps };\n\n// ======================================================================\n// SuccessModalReadingFluency — modal Reading Fluency de feedback positivo\n// ======================================================================\n\ntype SuccessModalReadingFluencyProps = {\n /** Se o modal está aberto. */\n isOpen: boolean;\n /** Fecha o modal (X e Esc). */\n onClose: () => void;\n /** Título (ex.: \"Incrível!\"). */\n title?: string;\n /** Frase de reforço (ex.: \"Você leu muito bem!\"). */\n description?: string;\n /** Fecha ao pressionar Esc (default: true). */\n closeOnEscape?: boolean;\n /**\n * Fonte da imagem de comemoração. Default: a imagem de fallback genérica\n * empacotada na lib. Passe uma URL pelo cliente (ex.: a imagem configurada pela\n * instituição via `useReadingFluencyAsset`) para sobrescrever.\n */\n imageSrc?: string;\n};\n\n/**\n * Modal Reading Fluency de comemoração/feedback positivo: card branco com o passarinho,\n * um título grande e uma frase de reforço, e o botão de fechar. Sem header verde\n * e sem ações — o aluno fecha no X (ou Esc). Título/descrição são configuráveis\n * pra reaproveitar em outros feedbacks.\n */\nconst SuccessModalReadingFluency = ({\n isOpen,\n onClose,\n title = 'Incrível!',\n description = 'Você leu muito bem!',\n closeOnEscape = true,\n imageSrc = readingFluencyFallback,\n}: SuccessModalReadingFluencyProps) => {\n const titleId = useId();\n const dialogRef = useRef<HTMLDialogElement>(null);\n\n useEscapeToClose(isOpen && closeOnEscape, onClose);\n useBodyScrollLock(isOpen);\n useModalFocus(isOpen, dialogRef);\n\n if (!isOpen) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs p-4\">\n <dialog\n ref={dialogRef}\n // Ver a nota sobre `tabIndex={-1}` no MicPermissionModalReadingFluency.\n tabIndex={-1}\n open\n aria-labelledby={titleId}\n aria-modal=\"true\"\n className=\"font-quicksand static m-0 w-full max-w-[380px] overflow-hidden rounded-3xl border-none bg-background p-0 shadow-hard-shadow-2\"\n >\n <div className=\"relative flex flex-col items-center gap-4 p-8 text-center\">\n <span className=\"absolute right-4 top-4\">\n <CloseButtonReadingFluency onClick={onClose} />\n </span>\n\n <img\n src={imageSrc}\n alt=\"Reading Fluency\"\n className=\"h-[172px] w-[252px] select-none object-contain\"\n draggable={false}\n />\n\n <div className=\"flex flex-col items-center gap-1\">\n <Text\n id={titleId}\n size=\"3xl\"\n className=\"font-bold uppercase text-secondary-900\"\n >\n {title}\n </Text>\n <Text\n size=\"sm\"\n className=\"font-semibold uppercase tracking-wide text-text-500\"\n >\n {description}\n </Text>\n </div>\n </div>\n </dialog>\n </div>\n );\n};\nSuccessModalReadingFluency.displayName = 'SuccessModalReadingFluency';\n\nexport { SuccessModalReadingFluency };\nexport type { SuccessModalReadingFluencyProps };\n","/* eslint-disable no-undef -- tipos/globais do DOM (PermissionDescriptor, PermissionStatus, navigator) são verificados pelo TypeScript */\nimport { useCallback, useEffect, useState } from 'react';\n\nexport type MicrophonePermissionStatus =\n | 'checking'\n | 'granted'\n | 'denied'\n | 'prompt'\n | 'unsupported';\n\nexport interface UseMicrophonePermissionReturn {\n /** Estado atual da permissão de microfone. */\n status: MicrophonePermissionStatus;\n /** Já concedeu o acesso. */\n isGranted: boolean;\n /** O navegador suporta captura de áudio (`getUserMedia`). */\n isSupported: boolean;\n /**\n * Ainda não concedeu (precisa perguntar) — `true` em `prompt`/`denied`.\n * Use para decidir se abre o modal de permissão.\n */\n shouldAsk: boolean;\n /**\n * Dispara o prompt do navegador (via `getUserMedia`). Encerra as tracks logo\n * após (só queríamos a permissão). Retorna `true` se foi concedida.\n */\n requestPermission: () => Promise<boolean>;\n}\n\n/**\n * Encapsula a lógica de permissão de microfone do navegador:\n * - consulta o estado (Permissions API) e reage a mudanças;\n * - `requestPermission()` abre o prompt nativo (`getUserMedia`).\n *\n * Não persiste nada: ao recarregar a página o estado é reconsultado — então um\n * \"configurar depois\" (que não concede) volta a pedir no próximo carregamento.\n */\nexport function useMicrophonePermission(): UseMicrophonePermissionReturn {\n const [status, setStatus] = useState<MicrophonePermissionStatus>('checking');\n\n useEffect(() => {\n const nav = typeof navigator !== 'undefined' ? navigator : undefined;\n if (!nav?.mediaDevices?.getUserMedia) {\n setStatus('unsupported');\n return;\n }\n\n // Nem todos os navegadores suportam a Permissions API para consultar 'microphone'\n // (ex.: Safari). Nesses casos assumimos 'prompt' (precisa perguntar).\n const permissions = nav.permissions;\n if (!permissions?.query) {\n setStatus('prompt');\n return;\n }\n\n let active = true;\n let permStatus: PermissionStatus | null = null;\n\n const micDescriptor = {\n name: 'microphone',\n } as unknown as PermissionDescriptor;\n\n permissions\n .query(micDescriptor)\n .then((result) => {\n if (!active) return;\n permStatus = result;\n setStatus(result.state as MicrophonePermissionStatus);\n result.onchange = () =>\n setStatus(result.state as MicrophonePermissionStatus);\n })\n .catch(() => {\n if (active) setStatus('prompt');\n });\n\n return () => {\n active = false;\n if (permStatus) permStatus.onchange = null;\n };\n }, []);\n\n const requestPermission = useCallback(async () => {\n const nav = typeof navigator !== 'undefined' ? navigator : undefined;\n if (!nav?.mediaDevices?.getUserMedia) {\n setStatus('unsupported');\n return false;\n }\n try {\n const stream = await nav.mediaDevices.getUserMedia({ audio: true });\n stream.getTracks().forEach((track) => track.stop());\n setStatus('granted');\n return true;\n } catch (error) {\n // getUserMedia rejeita com uma DOMException cujo `name` diz o motivo. Só é\n // rejeição de permissão de fato em NotAllowedError/SecurityError (e o\n // legado PermissionDeniedError) → 'denied'. Falhas de hardware\n // (NotFoundError sem mic, NotReadableError mic ocupado) ou transitórias\n // (AbortError) NÃO são negação: voltam pro fallback 'prompt' pra permitir\n // nova tentativa, sem travar o usuário num falso 'denied'.\n const errorName = (error as { name?: unknown } | undefined)?.name;\n const isDenial =\n errorName === 'NotAllowedError' ||\n errorName === 'SecurityError' ||\n errorName === 'PermissionDeniedError';\n setStatus(isDenial ? 'denied' : 'prompt');\n return false;\n }\n }, []);\n\n return {\n status,\n isGranted: status === 'granted',\n isSupported: status !== 'unsupported',\n shouldAsk: status === 'prompt' || status === 'denied',\n requestPermission,\n };\n}\n","import { useEffect } from 'react';\n\n/**\n * Trava o scroll do `body` enquanto um modal está aberto, com contagem de\n * referências compartilhada entre TODOS os modais da lib.\n *\n * O primeiro modal a travar salva os estilos originais do `body`, aplica\n * `overflow: hidden`, compensa o sumiço da scrollbar com `padding-right` e cria\n * um overlay (`#modal-scrollbar-overlay`) cobrindo essa faixa com a cor do\n * backdrop. Modais abertos ao mesmo tempo apenas incrementam o contador; só\n * quando o ÚLTIMO fecha os estilos originais são restaurados — assim fechar um\n * modal não devolve o scroll do body enquanto outro continua aberto.\n */\nconst SCROLLBAR_OVERLAY_ID = 'modal-scrollbar-overlay';\n\nlet lockCount = 0;\nlet originalOverflow = '';\nlet originalPaddingRight = '';\n\nconst applyLock = () => {\n // Mede a scrollbar antes de esconder o overflow.\n const scrollbarWidth =\n window.innerWidth - document.documentElement.clientWidth;\n\n originalOverflow = document.body.style.overflow;\n originalPaddingRight = document.body.style.paddingRight;\n\n document.body.style.overflow = 'hidden';\n\n // Compensa a scrollbar que some pra não deslocar o layout.\n if (scrollbarWidth > 0) {\n // Soma à padding-right JÁ existente (inline ou de folha de estilo) em vez de\n // substituí-la — senão o espaçamento original do body seria descartado. O\n // valor inline original fica salvo em `originalPaddingRight` pra restaurar.\n const currentPaddingRight =\n Number.parseFloat(window.getComputedStyle(document.body).paddingRight) ||\n 0;\n document.body.style.paddingRight = `${currentPaddingRight + scrollbarWidth}px`;\n\n const overlay = document.createElement('div');\n overlay.id = SCROLLBAR_OVERLAY_ID;\n overlay.style.cssText = `\n position: fixed;\n top: 0;\n right: 0;\n width: ${scrollbarWidth}px;\n height: 100vh;\n background-color: rgb(0 0 0 / 0.6);\n z-index: 40;\n pointer-events: none;\n `;\n document.body.appendChild(overlay);\n }\n};\n\nconst releaseLock = () => {\n document.body.style.overflow = originalOverflow;\n document.body.style.paddingRight = originalPaddingRight;\n\n const overlay = document.getElementById(SCROLLBAR_OVERLAY_ID);\n if (overlay) {\n overlay.remove();\n }\n};\n\n/**\n * @param locked - Trava o scroll enquanto `true`. Normalmente `isOpen`.\n */\nexport const useBodyScrollLock = (locked: boolean) => {\n useEffect(() => {\n if (!locked) return;\n\n if (lockCount === 0) applyLock();\n lockCount += 1;\n\n return () => {\n lockCount -= 1;\n if (lockCount === 0) releaseLock();\n };\n }, [locked]);\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-KM27ZDHZ.js","../src/components/Modal/Modal.tsx","../src/hooks/useMicrophonePermission.ts","../src/hooks/useBodyScrollLock.ts"],"names":["useState"],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-KM27ZDHZ.js","sourcesContent":[null,"import {\n ReactNode,\n MouseEvent,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport { XIcon } from '@phosphor-icons/react/dist/csr/X';\nimport {\n MicIconReadingFluency,\n MicOffIconReadingFluency,\n PlayIconReadingFluency,\n PauseIconReadingFluency,\n} from '../ReadingFluencyIcons';\nimport { cn } from '../../utils/utils';\nimport Button, { ButtonReadingFluency } from '../Button/Button';\nimport { CloseButtonReadingFluency } from '../CloseButtonReadingFluency/CloseButtonReadingFluency';\nimport readingFluencyBird from '../../assets/img/readingFluencyBird.png';\nimport { readingFluencyFallback } from '../../assets/fallbacks/readingFluencyFallback';\nimport { useMicrophonePermission } from '../../hooks/useMicrophonePermission';\nimport { useEscapeToClose } from '../../hooks/useEscapeToClose';\nimport { useBodyScrollLock } from '../../hooks/useBodyScrollLock';\nimport { useModalFocus } from '../../hooks/useModalFocus';\nimport {\n isYouTubeUrl,\n getYouTubeVideoId,\n getYouTubeEmbedUrl,\n} from './utils/videoUtils';\nimport Text from '../Text/Text';\n\n/**\n * Lookup table for size classes\n */\nconst SIZE_CLASSES = {\n xs: 'max-w-[360px]',\n sm: 'max-w-[420px]',\n md: 'max-w-[510px]',\n lg: 'max-w-[640px]',\n xl: 'max-w-[970px]',\n} as const;\n\n/**\n * Modal component props interface\n */\ntype ModalProps = {\n contentClassName?: string;\n /** Whether the modal is open */\n isOpen: boolean;\n /** Function to close the modal */\n onClose: () => void;\n /**\n * Modal title. Aceita string OU ReactNode pra permitir elementos inline\n * (ex: botão de voltar + label). Como é renderizado dentro de <h2>,\n * quando ReactNode use APENAS phrasing content (`<span>`, `<button>`,\n * ícones) — nunca `<div>` ou `<p>`.\n */\n title: ReactNode;\n /** Modal description/content */\n children?: ReactNode;\n /** Size of the modal */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** Additional CSS classes for the modal content */\n className?: string;\n /** Whether pressing Escape should close the modal */\n closeOnEscape?: boolean;\n /** Footer content (typically buttons) */\n footer?: ReactNode;\n /** Hide the close button */\n hideCloseButton?: boolean;\n /** Modal variant */\n variant?: 'default' | 'activity';\n /** Description for activity variant */\n description?: string;\n /** Image URL for activity variant */\n image?: string;\n /** Alt text for activity image (leave empty for decorative images) */\n imageAlt?: string;\n /** Action link for activity variant */\n actionLink?: string;\n /** Action button label for activity variant */\n actionLabel?: string;\n /**\n * Called when the action button is clicked, before the link opens.\n *\n * Lets the caller record the click — the notification center uses it to mark a\n * notice as read when the reader follows its \"Ver mais\" link. Optional and\n * side-effect free when omitted: the link still opens either way.\n */\n onActionClick?: () => void;\n /**\n * Id of the element that names the dialog. Overrides the built-in `<h2>`\n * title — use it when the visible title lives inside `children`.\n */\n labelledBy?: string;\n /**\n * Id of the element that describes the dialog, read by screen readers right\n * after the title when the dialog receives focus.\n */\n describedBy?: string;\n};\n\n/**\n * Modal component for Analytica Ensino platforms\n *\n * A flexible modal component with multiple size variants and customizable behavior.\n *\n * @param isOpen - Whether the modal is currently open\n * @param onClose - Callback function called when the modal should be closed\n * @param title - The title displayed at the top of the modal\n * @param children - The main content of the modal\n * @param size - The size variant (xs, sm, md, lg, xl)\n * @param className - Additional CSS classes for the modal content\n * @param closeOnEscape - Whether pressing Escape closes the modal (default: true)\n * @param footer - Footer content, typically action buttons\n * @param hideCloseButton - Whether to hide the X close button (default: false)\n * @returns A modal overlay with content\n *\n * @example\n * ```tsx\n * <Modal\n * isOpen={isModalOpen}\n * onClose={() => setIsModalOpen(false)}\n * title=\"Invite your team\"\n * size=\"md\"\n * footer={\n * <div className=\"flex gap-3\">\n * <Button variant=\"outline\" onClick={() => setIsModalOpen(false)}>Cancel</Button>\n * <Button variant=\"solid\" onClick={handleExplore}>Explore</Button>\n * </div>\n * }\n * >\n * Elevate user interactions with our versatile modals.\n * </Modal>\n * ```\n */\nconst Modal = ({\n isOpen,\n onClose,\n title,\n children,\n size = 'md',\n className = '',\n closeOnEscape = true,\n footer,\n hideCloseButton = false,\n variant = 'default',\n description,\n image,\n imageAlt,\n actionLink,\n actionLabel,\n onActionClick,\n contentClassName = '',\n labelledBy,\n describedBy,\n}: ModalProps) => {\n const titleId = useId();\n const dialogRef = useRef<HTMLDialogElement>(null);\n /**\n * O título é quem recebe o foco na abertura (ver `useModalFocus`). Guardado\n * como `HTMLElement` porque as duas montagens o renderizam com tags\n * diferentes — `<h2>` na default, `<Text>` (um `<p>`) na activity.\n */\n const titleRef = useRef<HTMLElement | null>(null);\n\n useEscapeToClose(isOpen && closeOnEscape, onClose);\n useBodyScrollLock(isOpen);\n useModalFocus(isOpen, dialogRef, titleRef);\n\n if (!isOpen) return null;\n\n const sizeClasses = SIZE_CLASSES[size];\n /*\n * `overflow-clip`, not `overflow-hidden`: both cut the content at the\n * rounded border, but a `hidden` box can still be scrolled by the browser.\n * Focusing something positioned outside it (an `sr-only` input) scrolled\n * the panel itself and pushed title, body and footer out of view (AE-3237).\n * Scrolling belongs to the body below, never to the panel.\n */\n const baseClasses =\n 'bg-secondary-50 rounded-3xl shadow-hard-shadow-2 border border-border-100 w-full mx-4 max-h-[calc(100dvh-2rem)] flex flex-col overflow-clip';\n // Reset dialog default styles to prevent positioning issues.\n //\n // `relative` (antes era `static`) segue anulando o `position: absolute` que o\n // navegador aplica ao <dialog> aberto — sem isso ele escapa da centralização\n // do backdrop — e agora também ancora o botão de fechar, que é o ÚLTIMO do\n // DOM nas duas montagens e volta ao topo à direita pelo CSS.\n const dialogResetClasses = 'm-0 border-none outline-none relative';\n /**\n * Espaço acima do conteúdo na montagem activity: 24px de padding, mais os\n * 26px do botão quando ele aparece. É o que o header do X reservava antes de\n * ele virar `absolute`.\n */\n const activityTopPadding = hideCloseButton ? 'pt-6' : 'pt-12.5';\n /**\n * Padding do diálogo. Na montagem activity o X não tem mais um header pra\n * ocupar, então o espaço acima vira padding do PRÓPRIO diálogo — fora da área\n * que rola, pro conteúdo não passar por baixo do X quando ele transborda.\n * `px-0`/`pb-0` no lugar de `p-0` pra não disputar com o `pt-*`.\n */\n const dialogPaddingClasses =\n variant === 'activity' ? cn('px-0 pb-0', activityTopPadding) : 'p-0';\n const modalClasses = cn(\n baseClasses,\n sizeClasses,\n dialogResetClasses,\n dialogPaddingClasses,\n className\n );\n\n /**\n * Classes do botão de fechar. Ele é o último elemento do DOM nas duas\n * montagens — pro leitor de tela percorrer título → conteúdo → ações e só\n * então chegar nele — e volta ao canto superior direito por `absolute`. As\n * coordenadas reproduzem onde ele estava: 24px do topo e da direita.\n */\n const closeButtonClasses =\n 'absolute right-6 top-6 p-1 text-text-500 hover:text-text-700 hover:bg-background-50 rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-indicator-info focus:ring-offset-2';\n\n // Normalize URLs missing protocol\n const normalizeUrl = (href: string) =>\n /^https?:\\/\\//i.test(href) ? href : `https://${href}`;\n\n // Handle action link click\n const handleActionClick = () => {\n onActionClick?.();\n if (actionLink) {\n window.open(normalizeUrl(actionLink), '_blank', 'noopener,noreferrer');\n }\n };\n\n // Activity variant rendering\n if (variant === 'activity') {\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs border-none p-0 m-0 w-full cursor-default\">\n <dialog\n ref={dialogRef}\n tabIndex={-1}\n className={modalClasses}\n aria-labelledby={labelledBy ?? titleId}\n aria-describedby={describedBy}\n aria-modal=\"true\"\n open\n >\n {/* Conteúdo centralizado */}\n <div className=\"flex flex-col items-center px-6 pb-6 gap-5 flex-1 min-h-0 overflow-y-auto\">\n {/* Imagem ilustrativa */}\n {image && (\n <div className=\"flex justify-center\">\n <img\n src={image}\n alt={imageAlt ?? ''}\n className=\"w-[122px] h-[122px] object-contain\"\n />\n </div>\n )}\n\n {/* Título */}\n <Text\n id={titleId}\n ref={(node: HTMLParagraphElement | null) => {\n titleRef.current = node;\n }}\n // Alvo do foco inicial (`useModalFocus`), e não um controle:\n // recebe foco por código, fica fora do ciclo de Tab e não mostra\n // anel.\n tabIndex={-1}\n size=\"lg\"\n className=\"font-semibold text-text-950 text-center focus:outline-none\"\n >\n {title}\n </Text>\n\n {/* Descrição */}\n {description && (\n <Text\n size=\"sm\"\n className=\"text-text-400 text-center max-w-md leading-[21px]\"\n >\n {description}\n </Text>\n )}\n\n {/* Ação: Botão ou Vídeo Embedado */}\n {actionLink && (\n <div className=\"w-full\">\n {(() => {\n const normalized = normalizeUrl(actionLink);\n const isYT = isYouTubeUrl(normalized);\n if (!isYT) return null;\n const id = getYouTubeVideoId(normalized);\n if (!id) {\n return (\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"large\"\n className=\"w-full\"\n onClick={handleActionClick}\n >\n {actionLabel || 'Iniciar Atividade'}\n </Button>\n );\n }\n return (\n <iframe\n src={getYouTubeEmbedUrl(id)}\n className=\"w-full aspect-video rounded-lg\"\n allowFullScreen\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\"\n title=\"Vídeo YouTube\"\n />\n );\n })()}\n {!isYouTubeUrl(normalizeUrl(actionLink)) && (\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"large\"\n className=\"w-full\"\n onClick={handleActionClick}\n >\n {actionLabel || 'Iniciar Atividade'}\n </Button>\n )}\n </div>\n )}\n </div>\n\n {/* Fechar: ÚLTIMO no DOM — ver `closeButtonClasses` */}\n {!hideCloseButton && (\n <button\n onClick={onClose}\n // Ver a nota sobre `data-print-hide` na montagem default abaixo.\n data-print-hide\n className={closeButtonClasses}\n aria-label=\"Fechar modal\"\n >\n <XIcon size={18} />\n </button>\n )}\n </dialog>\n </div>\n );\n }\n\n // Default variant rendering\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs border-none p-0 m-0 w-full cursor-default\">\n <dialog\n ref={dialogRef}\n tabIndex={-1}\n className={modalClasses}\n aria-labelledby={labelledBy ?? titleId}\n aria-describedby={describedBy}\n aria-modal=\"true\"\n open\n >\n {/* Header — só o título: o X é o último do DOM, lá embaixo */}\n <div className=\"flex items-center justify-between px-6 py-6\">\n {title ? (\n <h2\n id={titleId}\n ref={(node) => {\n titleRef.current = node;\n }}\n // Alvo do foco inicial (`useModalFocus`), e não um controle:\n // recebe foco por código, fica fora do ciclo de Tab e não mostra\n // anel.\n tabIndex={-1}\n className={cn(\n 'text-lg font-semibold text-text-950 focus:outline-none',\n // Reserva a faixa do X, que era um irmão no `justify-between` e\n // agora flutua por cima do header: sem isso um título longo\n // passaria por baixo dele.\n !hideCloseButton && 'pr-8'\n )}\n >\n {title}\n </h2>\n ) : (\n // Keeps the header height when the title lives in `children`,\n // without leaving an empty heading in the accessibility tree.\n //\n // A altura é a do X (18px do ícone + 2x4px do `p-1`), que ocupava\n // esta linha e hoje flutua por cima dela: sem reservá-la, um modal\n // sem título próprio encolheria e o botão encostaria no conteúdo.\n // Com título não é preciso — a linha do `text-lg` (28px) já é mais\n // alta que o botão, como antes.\n <span className={cn('block', !hideCloseButton && 'h-6.5')} />\n )}\n </div>\n\n {/* Content */}\n {children && (\n <div\n className={cn(\n 'px-6 pb-6 flex-1 min-h-0 overflow-y-auto',\n contentClassName\n )}\n >\n <div\n className={cn(\n 'text-text-500 font-normal text-sm leading-6',\n contentClassName?.includes('flex') &&\n 'flex flex-col flex-1 min-h-0'\n )}\n >\n {children}\n </div>\n </div>\n )}\n\n {/* Footer */}\n {footer && (\n <div className=\"flex justify-end gap-3 px-6 pb-6\">{footer}</div>\n )}\n\n {/* Fechar: ÚLTIMO no DOM — ver `closeButtonClasses` */}\n {!hideCloseButton && (\n <button\n onClick={onClose}\n /*\n * O X não sai no PDF. Quando este modal é a região de impressão\n * (`js-print-region` + `body.printing-modal`), o print.css revela\n * o <dialog> INTEIRO — o botão mora dentro dele e nada mais o\n * esconderia.\n *\n * O atributo vai no próprio botão, e não num container, como manda\n * o contrato do print.css: ele É o elemento inteiro a esconder.\n * A razão do contrato — colapsar junto o espaçamento do flex — não\n * se aplica, porque o botão está fora do fluxo (`absolute`) e não\n * ocupa espaço nenhum para colapsar.\n *\n * Inerte fora de `@media print`, e só surte efeito em quem importa\n * `analytica-frontend-lib/print.css`.\n */\n data-print-hide\n className={closeButtonClasses}\n aria-label=\"Fechar modal\"\n >\n <XIcon size={18} />\n </button>\n )}\n </dialog>\n </div>\n );\n};\n\nexport default Modal;\n\n// ======================================================================\n// MicPermissionModalReadingFluency — modal Reading Fluency de permissão de microfone\n// ======================================================================\n\ntype MicPermissionModalReadingFluencyProps = {\n /**\n * Controla a abertura (modo controlado). **Se omitido**, o modal entra em modo\n * gerenciado: usa `useMicrophonePermission` e se abre sozinho quando o\n * microfone ainda não foi concedido.\n */\n isOpen?: boolean;\n /** Fecha o modal (X e Esc). No modo gerenciado, apenas dispensa na sessão. */\n onClose?: () => void;\n /**\n * Chamado após o botão \"Habilitar permissões\" (o prompt do navegador já é\n * disparado internamente). Recebe se a permissão foi concedida.\n */\n onEnable?: (granted: boolean) => void;\n /** Ação do link \"Configurar depois\". */\n onConfigureLater?: () => void;\n /** Ação da barra \"Saiba mais sobre como cuidamos dos dados\". */\n onLearnMore?: () => void;\n /** Fecha ao pressionar Esc (default: true). */\n closeOnEscape?: boolean;\n /** Título (default: \"Por que pedimos acesso ao microfone\"). */\n title?: string;\n /** Texto explicativo (default: o texto da arte). */\n description?: ReactNode;\n /**\n * Fonte da imagem do passarinho. Default: o PNG Reading Fluency empacotado na lib.\n * Passe uma URL pelo cliente caso o asset da lib não seja resolvido no bundle.\n */\n imageSrc?: string;\n};\n\n/**\n * Modal Reading Fluency que pede permissão de uso do microfone.\n *\n * Header verde (`secondary-500`) com o passarinho + ícone de microfone e o botão\n * de fechar (`ButtonReadingFluency variant=\"icon\"`); corpo branco com título, texto e as\n * ações (`ButtonReadingFluency` solid \"Habilitar permissões\" + link \"Configurar depois\");\n * barra inferior verde-clara com o link \"Saiba mais...\".\n *\n * Modo **gerenciado** (sem `isOpen`): usa `useMicrophonePermission` — abre\n * sozinho quando o microfone não foi concedido, \"Habilitar permissões\" dispara o\n * prompt do navegador e \"Configurar depois\" apenas dispensa na sessão (como não\n * persiste, ao recarregar a página volta a pedir). Passando `isOpen`, vira\n * controlado (o `onEnable` ainda dispara o prompt do navegador).\n *\n * Observação: os tokens de cor/spacing são uma leitura da arte — ajustar na story.\n */\nconst MicPermissionModalReadingFluency = ({\n isOpen,\n onClose,\n onEnable,\n onConfigureLater,\n onLearnMore,\n closeOnEscape = true,\n title = 'Por que pedimos acesso ao microfone',\n description,\n imageSrc = readingFluencyBird,\n}: MicPermissionModalReadingFluencyProps) => {\n const titleId = useId();\n const dialogRef = useRef<HTMLDialogElement>(null);\n const { shouldAsk, requestPermission } = useMicrophonePermission();\n const [dismissed, setDismissed] = useState(false);\n\n const isControlled = isOpen !== undefined;\n // Gerenciado: abre quando falta permissão e não foi dispensado nesta sessão.\n const open = isControlled ? isOpen : shouldAsk && !dismissed;\n\n const handleClose = useCallback(() => {\n if (isControlled) onClose?.();\n else setDismissed(true);\n }, [isControlled, onClose]);\n\n const handleEnable = async () => {\n // Dispara o prompt nativo do navegador. No modo gerenciado, se conceder, o\n // `shouldAsk` vira false e o modal fecha sozinho.\n const granted = await requestPermission();\n onEnable?.(granted);\n };\n\n const handleConfigureLater = () => {\n if (!isControlled) setDismissed(true);\n onConfigureLater?.();\n };\n\n useEscapeToClose(open && closeOnEscape, handleClose);\n useBodyScrollLock(open);\n useModalFocus(open, dialogRef);\n\n if (!open) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs p-4\">\n <dialog\n ref={dialogRef}\n // `tabIndex={-1}` é requisito do `useModalFocus`: o foco inicial vai\n // pro próprio diálogo, pro leitor anunciar título e texto antes das\n // ações.\n tabIndex={-1}\n open\n aria-labelledby={titleId}\n aria-modal=\"true\"\n className=\"font-quicksand static m-0 w-full max-w-[420px] overflow-hidden rounded-3xl border-none p-0 shadow-hard-shadow-2\"\n >\n {/* Header verde */}\n <div className=\"relative flex items-center justify-center gap-3 bg-secondary-500 px-6 pt-8 pb-10\">\n <span className=\"absolute right-4 top-4\">\n <CloseButtonReadingFluency onClick={handleClose} />\n </span>\n\n <img\n src={imageSrc}\n alt=\"Reading Fluency\"\n className=\"h-14 w-auto select-none\"\n draggable={false}\n />\n\n <span className=\"flex size-14 items-center justify-center rounded-full bg-background\">\n <MicIconReadingFluency size={28} />\n </span>\n </div>\n\n {/* Corpo (padding 24) */}\n <div className=\"flex flex-col items-center gap-4 bg-background p-6 text-center\">\n <Text size=\"lg\" id={titleId} className=\"font-bold text-secondary-900\">\n {title}\n </Text>\n\n <div className=\"flex flex-col gap-3 text-[14px] font-medium text-text-600\">\n {description ?? (\n <>\n <Text size=\"sm\">\n Usamos o microfone para gravar a leitura da criança e avaliar\n sua fluência leitora ao longo do tempo.\n </Text>\n <Text size=\"sm\">\n As gravações ficam armazenadas com segurança e são usadas\n apenas para esse fim.\n </Text>\n </>\n )}\n </div>\n\n <ButtonReadingFluency\n variant=\"solid\"\n size=\"medium\"\n className=\"mt-2\"\n onClick={handleEnable}\n >\n Habilitar permissões\n </ButtonReadingFluency>\n\n <ButtonReadingFluency\n variant=\"link\"\n size=\"medium\"\n onClick={handleConfigureLater}\n >\n Configurar depois\n </ButtonReadingFluency>\n\n {/* Barra \"Saiba mais\": botão arredondado, inset pelo padding do corpo */}\n <Button\n type=\"button\"\n onClick={onLearnMore}\n variant=\"raw\"\n className=\"w-full cursor-pointer rounded-xl bg-secondary-100 px-4 py-4 text-center\"\n >\n <span className=\"text-[14px] font-medium text-secondary-700 underline\">\n Saiba mais sobre como cuidamos dos dados\n </span>\n </Button>\n </div>\n </dialog>\n </div>\n );\n};\nMicPermissionModalReadingFluency.displayName =\n 'MicPermissionModalReadingFluency';\n\nexport { MicPermissionModalReadingFluency };\nexport type { MicPermissionModalReadingFluencyProps };\n\n// ======================================================================\n// MicOffModalReadingFluency — modal Reading Fluency de \"microfone parece desligado\"\n// ======================================================================\n\ntype MicOffModalReadingFluencyProps = {\n /** Se o modal está aberto. */\n isOpen: boolean;\n /** Fecha o modal (X e Esc). */\n onClose: () => void;\n /** Ação do botão \"Tentar ler de novo\". */\n onRetry?: () => void;\n /** Ação do link \"Pedir ajuda a um adulto\". */\n onAskAdult?: () => void;\n /** Fecha ao pressionar Esc (default: true). */\n closeOnEscape?: boolean;\n /** Título (default: \"Parece que o microfone está desligado\"). */\n title?: string;\n};\n\n/**\n * Modal Reading Fluency exibido quando o microfone parece desligado/mudo durante a\n * leitura. Header verde com o ícone de microfone cortado + botão de fechar;\n * corpo branco com o título (uppercase) e as ações \"Tentar ler de novo\"\n * (`ButtonReadingFluency` solid) e \"Pedir ajuda a um adulto\" (`ButtonReadingFluency` link).\n *\n * É um modal controlado (o app decide quando abrir — ex.: ao detectar que não\n * há áudio durante a gravação).\n *\n * Observação: os tokens de cor/spacing são uma leitura da arte — ajustar na story.\n */\nconst MicOffModalReadingFluency = ({\n isOpen,\n onClose,\n onRetry,\n onAskAdult,\n closeOnEscape = true,\n title = 'Parece que o microfone está desligado',\n}: MicOffModalReadingFluencyProps) => {\n const titleId = useId();\n const dialogRef = useRef<HTMLDialogElement>(null);\n\n useEscapeToClose(isOpen && closeOnEscape, onClose);\n useBodyScrollLock(isOpen);\n useModalFocus(isOpen, dialogRef);\n\n if (!isOpen) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs p-4\">\n <dialog\n ref={dialogRef}\n // Ver a nota sobre `tabIndex={-1}` no MicPermissionModalReadingFluency.\n tabIndex={-1}\n open\n aria-labelledby={titleId}\n aria-modal=\"true\"\n className=\"font-quicksand static m-0 w-full max-w-[420px] overflow-hidden rounded-3xl border-none p-0 shadow-hard-shadow-2\"\n >\n {/* Header verde */}\n <div className=\"relative flex items-center justify-center bg-secondary-500 px-6 pt-10 pb-10\">\n <span className=\"absolute right-4 top-4\">\n <CloseButtonReadingFluency onClick={onClose} />\n </span>\n\n <span className=\"flex size-20 items-center justify-center rounded-full bg-background shadow-hard-shadow-2\">\n <MicOffIconReadingFluency size={40} />\n </span>\n </div>\n\n {/* Corpo (padding 24) */}\n <div className=\"flex flex-col items-center gap-4 bg-background p-6 text-center\">\n <Text\n id={titleId}\n size=\"lg\"\n className=\"font-bold uppercase text-secondary-900\"\n >\n {title}\n </Text>\n\n <ButtonReadingFluency\n variant=\"solid\"\n size=\"medium\"\n className=\"mt-2\"\n onClick={onRetry}\n >\n Tentar ler de novo\n </ButtonReadingFluency>\n\n <ButtonReadingFluency\n variant=\"link\"\n size=\"medium\"\n onClick={onAskAdult}\n >\n Pedir ajuda a um adulto\n </ButtonReadingFluency>\n </div>\n </dialog>\n </div>\n );\n};\nMicOffModalReadingFluency.displayName = 'MicOffModalReadingFluency';\n\nexport { MicOffModalReadingFluency };\nexport type { MicOffModalReadingFluencyProps };\n\n// ======================================================================\n// AudioPlaybackModalReadingFluency — modal Reading Fluency para ouvir a gravação\n// ======================================================================\n\ntype AudioPlaybackModalReadingFluencyProps = {\n /** Se o modal está aberto. */\n isOpen: boolean;\n /** Fecha o modal (X e Esc). */\n onClose: () => void;\n /**\n * A gravação a tocar: uma **URL** (string, ex.: blob URL) **ou** um\n * **arquivo/blob** (`File`/`Blob` — ex.: o blob do `AudioRecorderReadingFluency`).\n * Quando é `File`/`Blob`, vira um object URL same-origin internamente\n * (criado/revogado pelo componente).\n */\n src?: string | File | Blob;\n /** Ação do botão \"Pronto!\". */\n onConfirm?: () => void;\n /** Ação do link \"Quero ler de novo\". */\n onRetry?: () => void;\n /** Fecha ao pressionar Esc (default: true). */\n closeOnEscape?: boolean;\n};\n\n// Alturas (px) das barras da waveform — decorativa (não reflete o áudio real).\nconst PAPOLE_WAVEFORM_BARS = [\n 12, 20, 32, 16, 40, 24, 52, 28, 44, 60, 44, 28, 52, 24, 40, 16, 32, 20, 12,\n];\n\nconst formatPlaybackTime = (seconds: number): string => {\n const safe = Number.isFinite(seconds) ? Math.max(0, seconds) : 0;\n const pad = (n: number) => n.toString().padStart(2, '0');\n const h = Math.floor(safe / 3600);\n const m = Math.floor((safe % 3600) / 60);\n const s = Math.floor(safe % 60);\n return `${pad(h)}:${pad(m)}:${pad(s)}`;\n};\n\n/**\n * Modal Reading Fluency para o aluno ouvir a própria gravação. Header verde com uma\n * waveform decorativa e um player simples (play/pause + barra de progresso +\n * tempo) + botão de fechar; corpo branco com \"Pronto!\" (`ButtonReadingFluency` solid) e\n * \"Quero ler de novo\" (`ButtonReadingFluency` link).\n *\n * A gravação entra por `src`, que aceita **URL** (string) **ou** **File/Blob**\n * (ex.: o blob do `AudioRecorderReadingFluency`, convertido em object URL internamente).\n *\n * Controlado: o app decide quando abrir (ex.: após finalizar a gravação).\n *\n * Observação: waveform é decorativa (não analisa o áudio) e os tokens de\n * cor/spacing são uma leitura da arte — ajustar na story.\n */\nconst AudioPlaybackModalReadingFluency = ({\n isOpen,\n onClose,\n src,\n onConfirm,\n onRetry,\n closeOnEscape = true,\n}: AudioPlaybackModalReadingFluencyProps) => {\n const dialogRef = useRef<HTMLDialogElement>(null);\n const audioRef = useRef<HTMLAudioElement>(null);\n const [isPlaying, setIsPlaying] = useState(false);\n const [currentTime, setCurrentTime] = useState(0);\n const [duration, setDuration] = useState(0);\n const [objectUrl, setObjectUrl] = useState<string | undefined>(undefined);\n\n // String → usa direto; File/Blob → usa o object URL criado no efeito abaixo.\n const resolvedSrc = typeof src === 'string' ? src : objectUrl;\n\n useEscapeToClose(isOpen && closeOnEscape, onClose);\n useBodyScrollLock(isOpen);\n useModalFocus(isOpen, dialogRef);\n\n // `src` File/Blob → object URL same-origin (criado/revogado aqui).\n useEffect(() => {\n if (!src || typeof src === 'string') {\n setObjectUrl(undefined);\n return;\n }\n const url = URL.createObjectURL(src);\n setObjectUrl(url);\n return () => URL.revokeObjectURL(url);\n }, [src]);\n\n useEffect(() => {\n // Reseta o player ao fechar (o <audio> desmonta com o modal).\n if (!isOpen) {\n setIsPlaying(false);\n setCurrentTime(0);\n }\n }, [isOpen]);\n\n const togglePlay = () => {\n const audio = audioRef.current;\n if (!audio) return;\n if (isPlaying) {\n audio.pause();\n setIsPlaying(false);\n } else {\n // Só marca como tocando depois que o play() resolve. Se rejeitar\n // (AbortError ao pausar antes de iniciar, fonte inválida, etc.) mantém\n // false pra UI nunca indicar reprodução ativa numa falha.\n audio\n .play()\n ?.then(() => setIsPlaying(true))\n .catch(() => setIsPlaying(false));\n }\n };\n\n const handleSeek = (event: MouseEvent<HTMLButtonElement>) => {\n const audio = audioRef.current;\n if (!audio || !Number.isFinite(duration) || duration <= 0) return;\n const rect = event.currentTarget.getBoundingClientRect();\n const ratio = (event.clientX - rect.left) / rect.width;\n audio.currentTime = Math.min(Math.max(ratio, 0), 1) * duration;\n setCurrentTime(audio.currentTime);\n };\n\n if (!isOpen) return null;\n\n const progress = duration > 0 ? (currentTime / duration) * 100 : 0;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs p-4\">\n <dialog\n ref={dialogRef}\n // Ver a nota sobre `tabIndex={-1}` no MicPermissionModalReadingFluency.\n tabIndex={-1}\n open\n aria-label=\"Ouvir gravação\"\n aria-modal=\"true\"\n className=\"font-quicksand static m-0 w-full max-w-[420px] overflow-hidden rounded-3xl border-none p-0 shadow-hard-shadow-2\"\n >\n {/* Header verde: waveform + player */}\n <div className=\"relative flex flex-col gap-5 bg-secondary-500 px-6 pt-8 pb-6\">\n <span className=\"absolute right-4 top-4\">\n <CloseButtonReadingFluency onClick={onClose} />\n </span>\n\n {/* Waveform (decorativa) */}\n <div\n className=\"flex h-16 items-center justify-center gap-1\"\n aria-hidden=\"true\"\n >\n {PAPOLE_WAVEFORM_BARS.map((height, index) => (\n <span\n key={index}\n style={{ height }}\n className=\"w-1 rounded-full bg-error-400\"\n />\n ))}\n </div>\n\n {/* Player */}\n <div className=\"flex items-center gap-3\">\n <audio\n ref={audioRef}\n src={resolvedSrc}\n preload=\"metadata\"\n onTimeUpdate={() =>\n setCurrentTime(audioRef.current?.currentTime ?? 0)\n }\n onLoadedMetadata={() =>\n setDuration(audioRef.current?.duration ?? 0)\n }\n onEnded={() => {\n setIsPlaying(false);\n setCurrentTime(0);\n }}\n >\n <track kind=\"captions\" />\n </audio>\n\n <Button\n type=\"button\"\n onClick={togglePlay}\n disabled={!resolvedSrc}\n aria-label={isPlaying ? 'Pausar' : 'Reproduzir'}\n variant=\"raw\"\n className=\"flex flex-shrink-0 items-center justify-center disabled:cursor-not-allowed disabled:opacity-40\"\n >\n {isPlaying ? (\n <PauseIconReadingFluency size={36} />\n ) : (\n <PlayIconReadingFluency size={36} />\n )}\n </Button>\n\n <Button\n type=\"button\"\n onClick={handleSeek}\n aria-label=\"Barra de progresso\"\n variant=\"raw\"\n className=\"h-2 flex-1 overflow-hidden rounded-full bg-background\"\n >\n <span\n className=\"block h-full rounded-full bg-primary-500 transition-[width] duration-100\"\n style={{ width: `${progress}%` }}\n />\n </Button>\n\n <span className=\"flex-shrink-0 text-sm font-medium text-primary\">\n {formatPlaybackTime(currentTime)}\n </span>\n </div>\n </div>\n\n {/* Corpo (padding 24) */}\n <div className=\"flex flex-col items-center gap-4 bg-background p-6 text-center\">\n <ButtonReadingFluency\n variant=\"solid\"\n size=\"medium\"\n className=\"w-full\"\n onClick={onConfirm}\n >\n Pronto!\n </ButtonReadingFluency>\n\n <ButtonReadingFluency variant=\"link\" size=\"medium\" onClick={onRetry}>\n Quero ler de novo\n </ButtonReadingFluency>\n </div>\n </dialog>\n </div>\n );\n};\nAudioPlaybackModalReadingFluency.displayName =\n 'AudioPlaybackModalReadingFluency';\n\nexport { AudioPlaybackModalReadingFluency };\nexport type { AudioPlaybackModalReadingFluencyProps };\n\n// ======================================================================\n// SuccessModalReadingFluency — modal Reading Fluency de feedback positivo\n// ======================================================================\n\ntype SuccessModalReadingFluencyProps = {\n /** Se o modal está aberto. */\n isOpen: boolean;\n /** Fecha o modal (X e Esc). */\n onClose: () => void;\n /** Título (ex.: \"Incrível!\"). */\n title?: string;\n /** Frase de reforço (ex.: \"Você leu muito bem!\"). */\n description?: string;\n /** Fecha ao pressionar Esc (default: true). */\n closeOnEscape?: boolean;\n /**\n * Fonte da imagem de comemoração. Default: a imagem de fallback genérica\n * empacotada na lib. Passe uma URL pelo cliente (ex.: a imagem configurada pela\n * instituição via `useReadingFluencyAsset`) para sobrescrever.\n */\n imageSrc?: string;\n};\n\n/**\n * Modal Reading Fluency de comemoração/feedback positivo: card branco com o passarinho,\n * um título grande e uma frase de reforço, e o botão de fechar. Sem header verde\n * e sem ações — o aluno fecha no X (ou Esc). Título/descrição são configuráveis\n * pra reaproveitar em outros feedbacks.\n */\nconst SuccessModalReadingFluency = ({\n isOpen,\n onClose,\n title = 'Incrível!',\n description = 'Você leu muito bem!',\n closeOnEscape = true,\n imageSrc = readingFluencyFallback,\n}: SuccessModalReadingFluencyProps) => {\n const titleId = useId();\n const dialogRef = useRef<HTMLDialogElement>(null);\n\n useEscapeToClose(isOpen && closeOnEscape, onClose);\n useBodyScrollLock(isOpen);\n useModalFocus(isOpen, dialogRef);\n\n if (!isOpen) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs p-4\">\n <dialog\n ref={dialogRef}\n // Ver a nota sobre `tabIndex={-1}` no MicPermissionModalReadingFluency.\n tabIndex={-1}\n open\n aria-labelledby={titleId}\n aria-modal=\"true\"\n className=\"font-quicksand static m-0 w-full max-w-[380px] overflow-hidden rounded-3xl border-none bg-background p-0 shadow-hard-shadow-2\"\n >\n <div className=\"relative flex flex-col items-center gap-4 p-8 text-center\">\n <span className=\"absolute right-4 top-4\">\n <CloseButtonReadingFluency onClick={onClose} />\n </span>\n\n <img\n src={imageSrc}\n alt=\"Reading Fluency\"\n className=\"h-[172px] w-[252px] select-none object-contain\"\n draggable={false}\n />\n\n <div className=\"flex flex-col items-center gap-1\">\n <Text\n id={titleId}\n size=\"3xl\"\n className=\"font-bold uppercase text-secondary-900\"\n >\n {title}\n </Text>\n <Text\n size=\"sm\"\n className=\"font-semibold uppercase tracking-wide text-text-500\"\n >\n {description}\n </Text>\n </div>\n </div>\n </dialog>\n </div>\n );\n};\nSuccessModalReadingFluency.displayName = 'SuccessModalReadingFluency';\n\nexport { SuccessModalReadingFluency };\nexport type { SuccessModalReadingFluencyProps };\n","/* eslint-disable no-undef -- tipos/globais do DOM (PermissionDescriptor, PermissionStatus, navigator) são verificados pelo TypeScript */\nimport { useCallback, useEffect, useState } from 'react';\n\nexport type MicrophonePermissionStatus =\n | 'checking'\n | 'granted'\n | 'denied'\n | 'prompt'\n | 'unsupported';\n\nexport interface UseMicrophonePermissionReturn {\n /** Estado atual da permissão de microfone. */\n status: MicrophonePermissionStatus;\n /** Já concedeu o acesso. */\n isGranted: boolean;\n /** O navegador suporta captura de áudio (`getUserMedia`). */\n isSupported: boolean;\n /**\n * Ainda não concedeu (precisa perguntar) — `true` em `prompt`/`denied`.\n * Use para decidir se abre o modal de permissão.\n */\n shouldAsk: boolean;\n /**\n * Dispara o prompt do navegador (via `getUserMedia`). Encerra as tracks logo\n * após (só queríamos a permissão). Retorna `true` se foi concedida.\n */\n requestPermission: () => Promise<boolean>;\n}\n\n/**\n * Encapsula a lógica de permissão de microfone do navegador:\n * - consulta o estado (Permissions API) e reage a mudanças;\n * - `requestPermission()` abre o prompt nativo (`getUserMedia`).\n *\n * Não persiste nada: ao recarregar a página o estado é reconsultado — então um\n * \"configurar depois\" (que não concede) volta a pedir no próximo carregamento.\n */\nexport function useMicrophonePermission(): UseMicrophonePermissionReturn {\n const [status, setStatus] = useState<MicrophonePermissionStatus>('checking');\n\n useEffect(() => {\n const nav = typeof navigator !== 'undefined' ? navigator : undefined;\n if (!nav?.mediaDevices?.getUserMedia) {\n setStatus('unsupported');\n return;\n }\n\n // Nem todos os navegadores suportam a Permissions API para consultar 'microphone'\n // (ex.: Safari). Nesses casos assumimos 'prompt' (precisa perguntar).\n const permissions = nav.permissions;\n if (!permissions?.query) {\n setStatus('prompt');\n return;\n }\n\n let active = true;\n let permStatus: PermissionStatus | null = null;\n\n const micDescriptor = {\n name: 'microphone',\n } as unknown as PermissionDescriptor;\n\n permissions\n .query(micDescriptor)\n .then((result) => {\n if (!active) return;\n permStatus = result;\n setStatus(result.state as MicrophonePermissionStatus);\n result.onchange = () =>\n setStatus(result.state as MicrophonePermissionStatus);\n })\n .catch(() => {\n if (active) setStatus('prompt');\n });\n\n return () => {\n active = false;\n if (permStatus) permStatus.onchange = null;\n };\n }, []);\n\n const requestPermission = useCallback(async () => {\n const nav = typeof navigator !== 'undefined' ? navigator : undefined;\n if (!nav?.mediaDevices?.getUserMedia) {\n setStatus('unsupported');\n return false;\n }\n try {\n const stream = await nav.mediaDevices.getUserMedia({ audio: true });\n stream.getTracks().forEach((track) => track.stop());\n setStatus('granted');\n return true;\n } catch (error) {\n // getUserMedia rejeita com uma DOMException cujo `name` diz o motivo. Só é\n // rejeição de permissão de fato em NotAllowedError/SecurityError (e o\n // legado PermissionDeniedError) → 'denied'. Falhas de hardware\n // (NotFoundError sem mic, NotReadableError mic ocupado) ou transitórias\n // (AbortError) NÃO são negação: voltam pro fallback 'prompt' pra permitir\n // nova tentativa, sem travar o usuário num falso 'denied'.\n const errorName = (error as { name?: unknown } | undefined)?.name;\n const isDenial =\n errorName === 'NotAllowedError' ||\n errorName === 'SecurityError' ||\n errorName === 'PermissionDeniedError';\n setStatus(isDenial ? 'denied' : 'prompt');\n return false;\n }\n }, []);\n\n return {\n status,\n isGranted: status === 'granted',\n isSupported: status !== 'unsupported',\n shouldAsk: status === 'prompt' || status === 'denied',\n requestPermission,\n };\n}\n","import { useEffect } from 'react';\n\n/**\n * Trava o scroll do `body` enquanto um modal está aberto, com contagem de\n * referências compartilhada entre TODOS os modais da lib.\n *\n * O primeiro modal a travar salva os estilos originais do `body`, aplica\n * `overflow: hidden`, compensa o sumiço da scrollbar com `padding-right` e cria\n * um overlay (`#modal-scrollbar-overlay`) cobrindo essa faixa com a cor do\n * backdrop. Modais abertos ao mesmo tempo apenas incrementam o contador; só\n * quando o ÚLTIMO fecha os estilos originais são restaurados — assim fechar um\n * modal não devolve o scroll do body enquanto outro continua aberto.\n */\nconst SCROLLBAR_OVERLAY_ID = 'modal-scrollbar-overlay';\n\nlet lockCount = 0;\nlet originalOverflow = '';\nlet originalPaddingRight = '';\n\nconst applyLock = () => {\n // Mede a scrollbar antes de esconder o overflow.\n const scrollbarWidth =\n window.innerWidth - document.documentElement.clientWidth;\n\n originalOverflow = document.body.style.overflow;\n originalPaddingRight = document.body.style.paddingRight;\n\n document.body.style.overflow = 'hidden';\n\n // Compensa a scrollbar que some pra não deslocar o layout.\n if (scrollbarWidth > 0) {\n // Soma à padding-right JÁ existente (inline ou de folha de estilo) em vez de\n // substituí-la — senão o espaçamento original do body seria descartado. O\n // valor inline original fica salvo em `originalPaddingRight` pra restaurar.\n const currentPaddingRight =\n Number.parseFloat(window.getComputedStyle(document.body).paddingRight) ||\n 0;\n document.body.style.paddingRight = `${currentPaddingRight + scrollbarWidth}px`;\n\n const overlay = document.createElement('div');\n overlay.id = SCROLLBAR_OVERLAY_ID;\n overlay.style.cssText = `\n position: fixed;\n top: 0;\n right: 0;\n width: ${scrollbarWidth}px;\n height: 100vh;\n background-color: rgb(0 0 0 / 0.6);\n z-index: 40;\n pointer-events: none;\n `;\n document.body.appendChild(overlay);\n }\n};\n\nconst releaseLock = () => {\n document.body.style.overflow = originalOverflow;\n document.body.style.paddingRight = originalPaddingRight;\n\n const overlay = document.getElementById(SCROLLBAR_OVERLAY_ID);\n if (overlay) {\n overlay.remove();\n }\n};\n\n/**\n * @param locked - Trava o scroll enquanto `true`. Normalmente `isOpen`.\n */\nexport const useBodyScrollLock = (locked: boolean) => {\n useEffect(() => {\n if (!locked) return;\n\n if (lockCount === 0) applyLock();\n lockCount += 1;\n\n return () => {\n lockCount -= 1;\n if (lockCount === 0) releaseLock();\n };\n }, [locked]);\n};\n"]}
|
|
@@ -190,7 +190,7 @@ var Modal = ({
|
|
|
190
190
|
useModalFocus(isOpen, dialogRef, titleRef);
|
|
191
191
|
if (!isOpen) return null;
|
|
192
192
|
const sizeClasses = SIZE_CLASSES[size];
|
|
193
|
-
const baseClasses = "bg-secondary-50 rounded-3xl shadow-hard-shadow-2 border border-border-100 w-full mx-4 max-h-[calc(100dvh-2rem)] flex flex-col overflow-
|
|
193
|
+
const baseClasses = "bg-secondary-50 rounded-3xl shadow-hard-shadow-2 border border-border-100 w-full mx-4 max-h-[calc(100dvh-2rem)] flex flex-col overflow-clip";
|
|
194
194
|
const dialogResetClasses = "m-0 border-none outline-none relative";
|
|
195
195
|
const activityTopPadding = hideCloseButton ? "pt-6" : "pt-12.5";
|
|
196
196
|
const dialogPaddingClasses = variant === "activity" ? cn("px-0 pb-0", activityTopPadding) : "p-0";
|
|
@@ -784,4 +784,4 @@ export {
|
|
|
784
784
|
AudioPlaybackModalReadingFluency,
|
|
785
785
|
SuccessModalReadingFluency
|
|
786
786
|
};
|
|
787
|
-
//# sourceMappingURL=chunk-
|
|
787
|
+
//# sourceMappingURL=chunk-LODDYDTP.mjs.map
|