analytica-frontend-lib 1.6.76 → 1.6.78
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 +4 -5
- package/dist/AccessReportModal/index.js.map +1 -1
- package/dist/AccessReportModal/index.mjs +3 -4
- package/dist/AccessibilityWidget/index.js +4 -5
- package/dist/AccessibilityWidget/index.js.map +1 -1
- package/dist/AccessibilityWidget/index.mjs +3 -4
- package/dist/Accordation/index.js +4 -4
- package/dist/Accordation/index.mjs +3 -3
- package/dist/ActivitiesHistory/index.js +48 -49
- package/dist/ActivitiesHistory/index.js.map +1 -1
- package/dist/ActivitiesHistory/index.mjs +47 -48
- package/dist/ActivityCardQuestionBanks/index.d.ts.map +1 -1
- package/dist/ActivityCardQuestionBanks/index.js +48 -49
- package/dist/ActivityCardQuestionBanks/index.js.map +1 -1
- package/dist/ActivityCardQuestionBanks/index.mjs +47 -48
- package/dist/ActivityCardQuestionPreview/index.js +48 -49
- package/dist/ActivityCardQuestionPreview/index.js.map +1 -1
- package/dist/ActivityCardQuestionPreview/index.mjs +47 -48
- package/dist/ActivityCreate/ActivityCreateContent/index.js +48 -49
- package/dist/ActivityCreate/ActivityCreateContent/index.js.map +1 -1
- package/dist/ActivityCreate/ActivityCreateContent/index.mjs +47 -48
- package/dist/ActivityCreate/index.js +48 -49
- package/dist/ActivityCreate/index.js.map +1 -1
- package/dist/ActivityCreate/index.mjs +47 -48
- package/dist/ActivityDetails/index.js +48 -49
- package/dist/ActivityDetails/index.js.map +1 -1
- package/dist/ActivityDetails/index.mjs +47 -48
- package/dist/ActivityFilters/index.js +48 -49
- package/dist/ActivityFilters/index.js.map +1 -1
- package/dist/ActivityFilters/index.mjs +47 -48
- package/dist/ActivityPageLayout/index.js +48 -49
- package/dist/ActivityPageLayout/index.js.map +1 -1
- package/dist/ActivityPageLayout/index.mjs +47 -48
- package/dist/ActivityPreview/index.js +48 -49
- package/dist/ActivityPreview/index.js.map +1 -1
- package/dist/ActivityPreview/index.mjs +47 -48
- package/dist/AlertDialog/index.d.ts.map +1 -1
- package/dist/AlertDialog/index.js +3 -3
- package/dist/AlertDialog/index.mjs +2 -2
- package/dist/AlertManager/index.js +48 -49
- package/dist/AlertManager/index.js.map +1 -1
- package/dist/AlertManager/index.mjs +47 -48
- package/dist/AlertManagerView/index.js +4 -5
- package/dist/AlertManagerView/index.js.map +1 -1
- package/dist/AlertManagerView/index.mjs +3 -4
- package/dist/AnnouncementModal/index.js +4 -5
- package/dist/AnnouncementModal/index.js.map +1 -1
- package/dist/AnnouncementModal/index.mjs +3 -4
- package/dist/AnnouncementsGate/index.js +5 -6
- package/dist/AnnouncementsGate/index.js.map +1 -1
- package/dist/AnnouncementsGate/index.mjs +4 -5
- package/dist/AnswerKeyModal/index.js +4 -5
- package/dist/AnswerKeyModal/index.js.map +1 -1
- package/dist/AnswerKeyModal/index.mjs +3 -4
- package/dist/AppHeader/index.js +8 -9
- package/dist/AppHeader/index.js.map +1 -1
- package/dist/AppHeader/index.mjs +7 -8
- package/dist/CalendarCard/index.js +6 -7
- package/dist/CalendarCard/index.js.map +1 -1
- package/dist/CalendarCard/index.mjs +5 -6
- package/dist/Card/index.d.ts.map +1 -1
- package/dist/Card/index.js +3 -3
- package/dist/Card/index.mjs +2 -2
- package/dist/Chat/index.js +4 -5
- package/dist/Chat/index.js.map +1 -1
- package/dist/Chat/index.mjs +3 -4
- package/dist/Chatbot/index.js +4 -5
- package/dist/Chatbot/index.js.map +1 -1
- package/dist/Chatbot/index.mjs +3 -4
- package/dist/CheckBoxGroup/index.js +48 -49
- package/dist/CheckBoxGroup/index.js.map +1 -1
- package/dist/CheckBoxGroup/index.mjs +47 -48
- package/dist/ComparatorChart/ComparatorView/index.js +4 -5
- package/dist/ComparatorChart/ComparatorView/index.js.map +1 -1
- package/dist/ComparatorChart/ComparatorView/index.mjs +3 -4
- package/dist/CorrectActivityModal/index.js +9 -10
- package/dist/CorrectActivityModal/index.js.map +1 -1
- package/dist/CorrectActivityModal/index.mjs +8 -9
- package/dist/DownloadButton/index.js +6 -7
- package/dist/DownloadButton/index.js.map +1 -1
- package/dist/DownloadButton/index.mjs +5 -6
- package/dist/DownloadModal/index.js +4 -5
- package/dist/DownloadModal/index.js.map +1 -1
- package/dist/DownloadModal/index.mjs +3 -4
- package/dist/DropdownMenu/index.js +4 -5
- package/dist/DropdownMenu/index.js.map +1 -1
- package/dist/DropdownMenu/index.mjs +3 -4
- package/dist/EnemClassroomStartModal/index.js +8 -9
- package/dist/EnemClassroomStartModal/index.js.map +1 -1
- package/dist/EnemClassroomStartModal/index.mjs +7 -8
- package/dist/EnemMoment/index.js +110 -94
- package/dist/EnemMoment/index.js.map +1 -1
- package/dist/EnemMoment/index.mjs +74 -58
- package/dist/EnemMoment/index.mjs.map +1 -1
- package/dist/EnemMomentStudentModal/index.js +62 -63
- package/dist/EnemMomentStudentModal/index.js.map +1 -1
- package/dist/EnemMomentStudentModal/index.mjs +48 -49
- package/dist/EnemMomentStudentModal/index.mjs.map +1 -1
- package/dist/EssayThemePicker/index.js +3 -3
- package/dist/EssayThemePicker/index.mjs +2 -2
- package/dist/ExamDetailsLayout/ExamDetailsPage/index.js +48 -49
- package/dist/ExamDetailsLayout/ExamDetailsPage/index.js.map +1 -1
- package/dist/ExamDetailsLayout/ExamDetailsPage/index.mjs +47 -48
- package/dist/ExamPageLayout/index.js +48 -49
- package/dist/ExamPageLayout/index.js.map +1 -1
- package/dist/ExamPageLayout/index.mjs +47 -48
- package/dist/Forum/index.js +6 -7
- package/dist/Forum/index.js.map +1 -1
- package/dist/Forum/index.mjs +5 -6
- package/dist/IconButton/index.js +2 -2
- package/dist/IconButton/index.mjs +1 -1
- package/dist/LessonCardPreview/index.js +48 -49
- package/dist/LessonCardPreview/index.js.map +1 -1
- package/dist/LessonCardPreview/index.mjs +47 -48
- package/dist/LessonMediaSections/index.js +48 -49
- package/dist/LessonMediaSections/index.js.map +1 -1
- package/dist/LessonMediaSections/index.mjs +47 -48
- package/dist/LessonsCatalog/index.js +48 -49
- package/dist/LessonsCatalog/index.js.map +1 -1
- package/dist/LessonsCatalog/index.mjs +47 -48
- package/dist/Modal/index.d.ts +11 -1
- package/dist/Modal/index.d.ts.map +1 -1
- package/dist/Modal/index.js +3 -4
- package/dist/Modal/index.js.map +1 -1
- package/dist/Modal/index.mjs +2 -3
- package/dist/MultiCheckSelect/index.js +5 -6
- package/dist/MultiCheckSelect/index.js.map +1 -1
- package/dist/MultiCheckSelect/index.mjs +4 -5
- package/dist/NotificationCard/index.js +6 -7
- package/dist/NotificationCard/index.js.map +1 -1
- package/dist/NotificationCard/index.mjs +5 -6
- package/dist/PerformanceReportModal/index.js +4 -5
- package/dist/PerformanceReportModal/index.js.map +1 -1
- package/dist/PerformanceReportModal/index.mjs +3 -4
- package/dist/PrintableUsersTable/index.js +48 -49
- package/dist/PrintableUsersTable/index.js.map +1 -1
- package/dist/PrintableUsersTable/index.mjs +47 -48
- package/dist/ProgressModal/index.js +4 -5
- package/dist/ProgressModal/index.js.map +1 -1
- package/dist/ProgressModal/index.mjs +3 -4
- package/dist/QuestionsPerformanceCard/index.js +49 -50
- package/dist/QuestionsPerformanceCard/index.js.map +1 -1
- package/dist/QuestionsPerformanceCard/index.mjs +48 -49
- package/dist/Quiz/QuizResult/index.js +4 -4
- package/dist/Quiz/QuizResult/index.mjs +3 -3
- package/dist/Quiz/index.d.ts.map +1 -1
- package/dist/Quiz/index.js +8 -9
- package/dist/Quiz/index.js.map +1 -1
- package/dist/Quiz/index.mjs +7 -8
- package/dist/QuizTimer/index.d.ts +12 -0
- package/dist/QuizTimer/index.d.ts.map +1 -1
- package/dist/QuizTimer/index.js +4 -2
- package/dist/QuizTimer/index.js.map +1 -1
- package/dist/QuizTimer/index.mjs +4 -2
- package/dist/RecommendedLessonCreate/index.js +48 -49
- package/dist/RecommendedLessonCreate/index.js.map +1 -1
- package/dist/RecommendedLessonCreate/index.mjs +47 -48
- package/dist/RecommendedLessonDetails/index.js +11 -12
- package/dist/RecommendedLessonDetails/index.js.map +1 -1
- package/dist/RecommendedLessonDetails/index.mjs +10 -11
- package/dist/RecommendedLessonsHistory/index.js +48 -49
- package/dist/RecommendedLessonsHistory/index.js.map +1 -1
- package/dist/RecommendedLessonsHistory/index.mjs +47 -48
- package/dist/ReportDetailModal/index.js +5 -6
- package/dist/ReportDetailModal/index.js.map +1 -1
- package/dist/ReportDetailModal/index.mjs +4 -5
- package/dist/RichEditor/index.js +6 -7
- package/dist/RichEditor/index.js.map +1 -1
- package/dist/RichEditor/index.mjs +5 -6
- package/dist/{RichEditorCore-62NIM7PC.js → RichEditorCore-6OT3VNJR.js} +15 -16
- package/dist/RichEditorCore-6OT3VNJR.js.map +1 -0
- package/dist/{RichEditorCore-CCO3SSSU.mjs → RichEditorCore-IF6JQHEO.mjs} +6 -7
- package/dist/{RichEditorCore-CCO3SSSU.mjs.map → RichEditorCore-IF6JQHEO.mjs.map} +1 -1
- package/dist/Search/index.js +5 -6
- package/dist/Search/index.js.map +1 -1
- package/dist/Search/index.mjs +4 -5
- package/dist/SendActivityModal/SendActivityModal.js +48 -49
- package/dist/SendActivityModal/SendActivityModal.js.map +1 -1
- package/dist/SendActivityModal/SendActivityModal.mjs +47 -48
- package/dist/SendActivityModal/index.js +48 -49
- package/dist/SendActivityModal/index.js.map +1 -1
- package/dist/SendActivityModal/index.mjs +47 -48
- package/dist/SendLessonModal/index.js +48 -49
- package/dist/SendLessonModal/index.js.map +1 -1
- package/dist/SendLessonModal/index.mjs +47 -48
- package/dist/SimulatedPerformance/SimulatedPerformanceView/index.js +48 -49
- package/dist/SimulatedPerformance/SimulatedPerformanceView/index.js.map +1 -1
- package/dist/SimulatedPerformance/SimulatedPerformanceView/index.mjs +47 -48
- package/dist/SimulatedPerformance/useSimulatedPerformance/index.js +6 -7
- package/dist/SimulatedPerformance/useSimulatedPerformance/index.js.map +1 -1
- package/dist/SimulatedPerformance/useSimulatedPerformance/index.mjs +5 -6
- package/dist/SimulatedStudentSimulationsModal/index.js +8 -9
- package/dist/SimulatedStudentSimulationsModal/index.js.map +1 -1
- package/dist/SimulatedStudentSimulationsModal/index.mjs +7 -8
- package/dist/SimulationSummaryCards/index.js +5 -5
- package/dist/SimulationSummaryCards/index.mjs +4 -4
- package/dist/SimulationsPage/index.js +48 -49
- package/dist/SimulationsPage/index.js.map +1 -1
- package/dist/SimulationsPage/index.mjs +47 -48
- package/dist/StudentLessonProgressModal/index.js +6 -7
- package/dist/StudentLessonProgressModal/index.js.map +1 -1
- package/dist/StudentLessonProgressModal/index.mjs +5 -6
- package/dist/StudentPerformanceDetailsModal/index.js +9 -10
- package/dist/StudentPerformanceDetailsModal/index.js.map +1 -1
- package/dist/StudentPerformanceDetailsModal/index.mjs +8 -9
- package/dist/Support/TicketModal/index.js +4 -5
- package/dist/Support/TicketModal/index.js.map +1 -1
- package/dist/Support/TicketModal/index.mjs +3 -4
- package/dist/Support/index.js +5 -6
- package/dist/Support/index.js.map +1 -1
- package/dist/Support/index.mjs +4 -5
- package/dist/TableProvider/index.js +48 -49
- package/dist/TableProvider/index.js.map +1 -1
- package/dist/TableProvider/index.mjs +47 -48
- package/dist/UnifiedDraftModelPage/index.js +48 -49
- package/dist/UnifiedDraftModelPage/index.js.map +1 -1
- package/dist/UnifiedDraftModelPage/index.mjs +47 -48
- package/dist/UnifiedHistoryPage/index.js +48 -49
- package/dist/UnifiedHistoryPage/index.js.map +1 -1
- package/dist/UnifiedHistoryPage/index.mjs +47 -48
- package/dist/VideoPlayer/index.js +7 -8
- package/dist/VideoPlayer/index.js.map +1 -1
- package/dist/VideoPlayer/index.mjs +6 -7
- package/dist/Whiteboard/index.js +4 -5
- package/dist/Whiteboard/index.js.map +1 -1
- package/dist/Whiteboard/index.mjs +3 -4
- package/dist/{chunk-EVBQNVQW.mjs → chunk-233FSBU7.mjs} +5 -5
- package/dist/{chunk-JU63EMZM.js → chunk-24DQFREC.js} +3 -3
- package/dist/{chunk-JU63EMZM.js.map → chunk-24DQFREC.js.map} +1 -1
- package/dist/{chunk-QFXSQKW3.mjs → chunk-254EBPMW.mjs} +22 -22
- package/dist/{chunk-QFXSQKW3.mjs.map → chunk-254EBPMW.mjs.map} +1 -1
- package/dist/{chunk-SFQVZ4KQ.js → chunk-2ETPIOCD.js} +3 -3
- package/dist/{chunk-SFQVZ4KQ.js.map → chunk-2ETPIOCD.js.map} +1 -1
- package/dist/{chunk-RCNIBRZY.js → chunk-2VTJ2PKF.js} +10 -10
- package/dist/{chunk-RCNIBRZY.js.map → chunk-2VTJ2PKF.js.map} +1 -1
- package/dist/{chunk-B35D5S4G.js → chunk-2ZMGNCMI.js} +6 -6
- package/dist/{chunk-B35D5S4G.js.map → chunk-2ZMGNCMI.js.map} +1 -1
- package/dist/{chunk-QEPKR6ZF.js → chunk-3KSRDIS2.js} +20 -20
- package/dist/{chunk-QEPKR6ZF.js.map → chunk-3KSRDIS2.js.map} +1 -1
- package/dist/{chunk-MUCV5ZWZ.mjs → chunk-3YF7H577.mjs} +15 -9
- package/dist/chunk-3YF7H577.mjs.map +1 -0
- package/dist/{chunk-MADPP2PW.mjs → chunk-3ZSI2KI5.mjs} +2 -2
- package/dist/{chunk-2W7PTFXS.mjs → chunk-42XKJV56.mjs} +2 -2
- package/dist/{chunk-M6TC6XRQ.mjs → chunk-55ESXRRM.mjs} +2 -2
- package/dist/{chunk-4MURAKPC.mjs → chunk-5DJVOLVX.mjs} +3 -3
- package/dist/{chunk-YVT7CT3G.mjs → chunk-5P6CBDZ6.mjs} +2 -2
- package/dist/{chunk-BHKTJCFD.js → chunk-5QUP5HKB.js} +3 -3
- package/dist/{chunk-BHKTJCFD.js.map → chunk-5QUP5HKB.js.map} +1 -1
- package/dist/{chunk-SFEU7BMY.mjs → chunk-5SFNRXZB.mjs} +2 -2
- package/dist/{chunk-6ALEXGAN.js → chunk-6U4AI5SE.js} +6 -6
- package/dist/{chunk-6ALEXGAN.js.map → chunk-6U4AI5SE.js.map} +1 -1
- package/dist/{chunk-KYY4U5SN.mjs → chunk-6Z5W5J44.mjs} +3 -3
- package/dist/{chunk-XOKBMLW3.js → chunk-7IGUYLSF.js} +3 -3
- package/dist/{chunk-XOKBMLW3.js.map → chunk-7IGUYLSF.js.map} +1 -1
- package/dist/{chunk-GVYGPJH3.mjs → chunk-AU5M2766.mjs} +2 -2
- package/dist/{chunk-2VODGC76.js → chunk-AVEMHDN2.js} +66 -44
- package/dist/chunk-AVEMHDN2.js.map +1 -0
- package/dist/{chunk-HIIOADV4.js → chunk-AZSRKBYS.js} +63 -71
- package/dist/chunk-AZSRKBYS.js.map +1 -0
- package/dist/{chunk-CY2VKNCB.js → chunk-BQIBVC6X.js} +5 -5
- package/dist/{chunk-CY2VKNCB.js.map → chunk-BQIBVC6X.js.map} +1 -1
- package/dist/{chunk-M77TQ5JJ.mjs → chunk-BU32E6BR.mjs} +4 -6
- package/dist/{chunk-M77TQ5JJ.mjs.map → chunk-BU32E6BR.mjs.map} +1 -1
- package/dist/{chunk-5CQVDUDO.js → chunk-BUNF5POU.js} +5 -5
- package/dist/{chunk-5CQVDUDO.js.map → chunk-BUNF5POU.js.map} +1 -1
- package/dist/{chunk-Z6UN4ZPW.mjs → chunk-BVHVYC7Q.mjs} +4 -4
- package/dist/{chunk-WJENEFDG.js → chunk-CAFVLHDV.js} +3 -3
- package/dist/{chunk-WJENEFDG.js.map → chunk-CAFVLHDV.js.map} +1 -1
- package/dist/{chunk-BVUPM6EY.js → chunk-CAQ2Q3ON.js} +2 -2
- package/dist/chunk-CAQ2Q3ON.js.map +1 -0
- package/dist/{chunk-QMPOGLAR.js → chunk-CIASXVWX.js} +3 -3
- package/dist/{chunk-QMPOGLAR.js.map → chunk-CIASXVWX.js.map} +1 -1
- package/dist/{chunk-APKEYUJ3.js → chunk-CIQLC2ZZ.js} +3 -3
- package/dist/{chunk-APKEYUJ3.js.map → chunk-CIQLC2ZZ.js.map} +1 -1
- package/dist/{chunk-36XPNLGQ.js → chunk-CW3FCWR4.js} +16 -16
- package/dist/{chunk-36XPNLGQ.js.map → chunk-CW3FCWR4.js.map} +1 -1
- package/dist/{chunk-J5VEAJN5.mjs → chunk-CWVUGZNK.mjs} +2 -2
- package/dist/{chunk-BCMDP6GK.mjs → chunk-DV3N2K3Y.mjs} +4 -4
- package/dist/{chunk-PP7SEERV.mjs → chunk-DXYSEBK3.mjs} +9 -3
- package/dist/chunk-DXYSEBK3.mjs.map +1 -0
- package/dist/{chunk-754M6HQ5.js → chunk-EJN4OP3D.js} +5 -5
- package/dist/{chunk-754M6HQ5.js.map → chunk-EJN4OP3D.js.map} +1 -1
- package/dist/{chunk-3IM2SBPO.js → chunk-F5K3HMKT.js} +4 -4
- package/dist/{chunk-3IM2SBPO.js.map → chunk-F5K3HMKT.js.map} +1 -1
- package/dist/{chunk-WMDSGVZ7.mjs → chunk-GCGSAS2Z.mjs} +48 -63
- package/dist/chunk-GCGSAS2Z.mjs.map +1 -0
- package/dist/{chunk-EXHGEJ4P.mjs → chunk-GKARHTZ2.mjs} +2 -2
- package/dist/{chunk-2VDCEEXB.js → chunk-GNKFBVW4.js} +3 -3
- package/dist/{chunk-2VDCEEXB.js.map → chunk-GNKFBVW4.js.map} +1 -1
- package/dist/{chunk-CDLOMECB.js → chunk-GTBPMNTJ.js} +3 -3
- package/dist/{chunk-CDLOMECB.js.map → chunk-GTBPMNTJ.js.map} +1 -1
- package/dist/{chunk-YQKAASWM.js → chunk-GXXDSBN2.js} +10 -4
- package/dist/chunk-GXXDSBN2.js.map +1 -0
- package/dist/{chunk-FASVPU6N.js → chunk-H3F4OCXC.js} +10 -10
- package/dist/{chunk-FASVPU6N.js.map → chunk-H3F4OCXC.js.map} +1 -1
- package/dist/{chunk-JCFN6KRS.mjs → chunk-HGWDB73S.mjs} +2 -2
- package/dist/{chunk-JXXMO7PY.mjs → chunk-HN5RW4C3.mjs} +3 -3
- package/dist/{chunk-I2A4EQPH.mjs → chunk-HQ2GXFK5.mjs} +6 -6
- package/dist/{chunk-BIPC6F6D.js → chunk-IDJ37MOU.js} +115 -115
- package/dist/{chunk-BIPC6F6D.js.map → chunk-IDJ37MOU.js.map} +1 -1
- package/dist/{chunk-TBJLNIOY.mjs → chunk-JBLYYTHN.mjs} +2 -2
- package/dist/{chunk-G4NK66PM.js → chunk-JTWXQ267.js} +24 -18
- package/dist/chunk-JTWXQ267.js.map +1 -0
- package/dist/{chunk-V6IC74KH.js → chunk-JXGLDRDC.js} +34 -34
- package/dist/{chunk-V6IC74KH.js.map → chunk-JXGLDRDC.js.map} +1 -1
- package/dist/{chunk-DDFIRQI5.mjs → chunk-K3E5VEBF.mjs} +56 -34
- package/dist/chunk-K3E5VEBF.mjs.map +1 -0
- package/dist/{chunk-MSBEWG26.js → chunk-K5O2IOI4.js} +8 -8
- package/dist/{chunk-MSBEWG26.js.map → chunk-K5O2IOI4.js.map} +1 -1
- package/dist/{chunk-SB5YGKXR.js → chunk-KBMLGQ5J.js} +49 -64
- package/dist/chunk-KBMLGQ5J.js.map +1 -0
- package/dist/chunk-KCZEKV7M.mjs +81 -0
- package/dist/chunk-KCZEKV7M.mjs.map +1 -0
- package/dist/{chunk-GRSN76BV.mjs → chunk-KH2R4STU.mjs} +3 -3
- package/dist/{chunk-7DQM34JT.js → chunk-KHYSXYPO.js} +23 -23
- package/dist/{chunk-7DQM34JT.js.map → chunk-KHYSXYPO.js.map} +1 -1
- package/dist/{chunk-V2YHMPRR.js → chunk-KJHBQQYJ.js} +5 -5
- package/dist/{chunk-V2YHMPRR.js.map → chunk-KJHBQQYJ.js.map} +1 -1
- package/dist/{chunk-ZF5NMQJZ.mjs → chunk-KUKLN3CK.mjs} +4 -4
- package/dist/{chunk-6AYB7CZH.js → chunk-KZQVGSR2.js} +2 -2
- package/dist/{chunk-6AYB7CZH.js.map → chunk-KZQVGSR2.js.map} +1 -1
- package/dist/{chunk-UAKRBNW2.mjs → chunk-L4T76OKM.mjs} +2 -2
- package/dist/{chunk-AUCXJ7LG.js → chunk-M3LQH7Y7.js} +3 -3
- package/dist/{chunk-AUCXJ7LG.js.map → chunk-M3LQH7Y7.js.map} +1 -1
- package/dist/{chunk-FQNJJH7F.js → chunk-MCXRKD56.js} +13 -13
- package/dist/{chunk-FQNJJH7F.js.map → chunk-MCXRKD56.js.map} +1 -1
- package/dist/{chunk-PY5WCBKN.mjs → chunk-MERKXOSI.mjs} +4 -4
- package/dist/{chunk-D3YDZF2G.js → chunk-N472HQPZ.js} +3 -3
- package/dist/{chunk-D3YDZF2G.js.map → chunk-N472HQPZ.js.map} +1 -1
- package/dist/{chunk-UPMYCGXR.js → chunk-N4K4X34Z.js} +4 -4
- package/dist/{chunk-UPMYCGXR.js.map → chunk-N4K4X34Z.js.map} +1 -1
- package/dist/{chunk-RU43UMEH.js → chunk-NFCNAFUK.js} +3 -3
- package/dist/{chunk-RU43UMEH.js.map → chunk-NFCNAFUK.js.map} +1 -1
- package/dist/{chunk-APCB5HWT.mjs → chunk-NLSDZJRR.mjs} +3 -3
- package/dist/{chunk-EWYIXCNF.mjs → chunk-NLUTNCLH.mjs} +5 -5
- package/dist/{chunk-OP4Q2KDS.mjs → chunk-NMKKMY5P.mjs} +2 -2
- package/dist/{chunk-WDPFO4II.mjs → chunk-NMPK336K.mjs} +2 -2
- package/dist/{chunk-X6BZ5IEV.mjs → chunk-NU7O6YKR.mjs} +2 -2
- package/dist/{chunk-ZABDSRX3.js → chunk-NUZ5K3CB.js} +4 -4
- package/dist/{chunk-ZABDSRX3.js.map → chunk-NUZ5K3CB.js.map} +1 -1
- package/dist/{chunk-N5ZGFYLA.js → chunk-NZX3BA62.js} +3 -3
- package/dist/{chunk-N5ZGFYLA.js.map → chunk-NZX3BA62.js.map} +1 -1
- package/dist/{chunk-2TLSEAL2.js → chunk-O4TRDWXJ.js} +3 -3
- package/dist/{chunk-2TLSEAL2.js.map → chunk-O4TRDWXJ.js.map} +1 -1
- package/dist/{chunk-CBI5F4ME.mjs → chunk-OMSSA4NO.mjs} +2 -2
- package/dist/{chunk-YGEEWLGJ.js → chunk-PKKXCX5B.js} +3 -3
- package/dist/{chunk-YGEEWLGJ.js.map → chunk-PKKXCX5B.js.map} +1 -1
- package/dist/{chunk-GYHD6QEA.mjs → chunk-PQGQ3EH5.mjs} +2 -2
- package/dist/{chunk-3LN5GQAC.js → chunk-Q6UIUYNF.js} +6 -8
- package/dist/chunk-Q6UIUYNF.js.map +1 -0
- package/dist/chunk-QLWBGM7H.js +81 -0
- package/dist/chunk-QLWBGM7H.js.map +1 -0
- package/dist/{chunk-IF5GW6ID.js → chunk-QZ5DCDZ2.js} +6 -6
- package/dist/{chunk-IF5GW6ID.js.map → chunk-QZ5DCDZ2.js.map} +1 -1
- package/dist/{chunk-LSUCENYD.mjs → chunk-RBKGHUSR.mjs} +2 -2
- package/dist/{chunk-PIZTI5SJ.js → chunk-RMCZ7C2C.js} +3 -3
- package/dist/{chunk-PIZTI5SJ.js.map → chunk-RMCZ7C2C.js.map} +1 -1
- package/dist/{chunk-LGQNMQOT.mjs → chunk-ROS5XGTQ.mjs} +2 -2
- package/dist/chunk-ROS5XGTQ.mjs.map +1 -0
- package/dist/{chunk-TEUERRDG.mjs → chunk-RV45XVXE.mjs} +2 -2
- package/dist/{chunk-FW6ZI2MC.mjs → chunk-UAFSWXN5.mjs} +2 -2
- package/dist/{chunk-QUGKQYAJ.mjs → chunk-ULVFVLFE.mjs} +4 -6
- package/dist/{chunk-QUGKQYAJ.mjs.map → chunk-ULVFVLFE.mjs.map} +1 -1
- package/dist/{chunk-ANLL2EIX.mjs → chunk-UWCGTH3U.mjs} +2 -2
- package/dist/{chunk-6R2LEEEP.mjs → chunk-UZF2D2GG.mjs} +2 -2
- package/dist/{chunk-62L3PMYE.mjs → chunk-V3OVMHZD.mjs} +2 -2
- package/dist/{chunk-UDITT3N3.mjs → chunk-V6ELDZ2B.mjs} +2 -2
- package/dist/{chunk-G7NUCBD3.js → chunk-VDPV24JJ.js} +3 -3
- package/dist/{chunk-G7NUCBD3.js.map → chunk-VDPV24JJ.js.map} +1 -1
- package/dist/{chunk-IJQOTS5O.mjs → chunk-VJUS3GC4.mjs} +2 -2
- package/dist/{chunk-ZUPP7R2K.js → chunk-W7BBVDBI.js} +17 -3
- package/dist/chunk-W7BBVDBI.js.map +1 -0
- package/dist/{chunk-EHQDQ5RV.js → chunk-XARMPXRN.js} +10 -12
- package/dist/chunk-XARMPXRN.js.map +1 -0
- package/dist/{chunk-MQEAEU6G.mjs → chunk-XGMRYNER.mjs} +2 -2
- package/dist/{chunk-MMQMVVD6.mjs → chunk-XLTD5J74.mjs} +3 -3
- package/dist/{chunk-L3ST5GUJ.js → chunk-XQUK7R7L.js} +17 -17
- package/dist/{chunk-L3ST5GUJ.js.map → chunk-XQUK7R7L.js.map} +1 -1
- package/dist/{chunk-OMBUOOMD.mjs → chunk-XYT542WD.mjs} +2 -2
- package/dist/{chunk-IZNABVXE.js → chunk-Y4IGIWP4.js} +3 -3
- package/dist/{chunk-IZNABVXE.js.map → chunk-Y4IGIWP4.js.map} +1 -1
- package/dist/{chunk-COWOGT7U.mjs → chunk-YZWFDSTC.mjs} +2 -2
- package/dist/{chunk-M2FN7CNS.mjs → chunk-Z4L2DWMX.mjs} +17 -3
- package/dist/chunk-Z4L2DWMX.mjs.map +1 -0
- package/dist/chunk-Z75J66LL.mjs +149 -0
- package/dist/chunk-Z75J66LL.mjs.map +1 -0
- package/dist/{chunk-CWIJ7RXR.js → chunk-ZHUFICW3.js} +3 -3
- package/dist/{chunk-CWIJ7RXR.js.map → chunk-ZHUFICW3.js.map} +1 -1
- package/dist/{chunk-Q5XGBTOY.js → chunk-ZNITTMV5.js} +3 -3
- package/dist/{chunk-Q5XGBTOY.js.map → chunk-ZNITTMV5.js.map} +1 -1
- package/dist/components/EnemMoment/HeaderFilters.d.ts +12 -1
- package/dist/components/EnemMoment/HeaderFilters.d.ts.map +1 -1
- package/dist/components/EnemMoment/types.d.ts +10 -1
- package/dist/components/EnemMoment/types.d.ts.map +1 -1
- package/dist/hooks/useAppContent/index.js +48 -49
- package/dist/hooks/useAppContent/index.js.map +1 -1
- package/dist/hooks/useAppContent/index.mjs +47 -48
- package/dist/hooks/useResizableColumns.d.ts +20 -9
- package/dist/hooks/useResizableColumns.d.ts.map +1 -1
- package/dist/hooks/useScreen/index.js +2 -2
- package/dist/hooks/useScreen/index.mjs +1 -1
- package/dist/index.js +48 -49
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +47 -48
- package/dist/store/layoutPreferencesStore.d.ts +12 -24
- package/dist/store/layoutPreferencesStore.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/RichEditorCore-62NIM7PC.js.map +0 -1
- package/dist/chunk-2EDRPEYL.mjs +0 -157
- package/dist/chunk-2EDRPEYL.mjs.map +0 -1
- package/dist/chunk-2VODGC76.js.map +0 -1
- package/dist/chunk-3LN5GQAC.js.map +0 -1
- package/dist/chunk-BVUPM6EY.js.map +0 -1
- package/dist/chunk-CH6BWMSQ.js +0 -17
- package/dist/chunk-CH6BWMSQ.js.map +0 -1
- package/dist/chunk-DDFIRQI5.mjs.map +0 -1
- package/dist/chunk-EHQDQ5RV.js.map +0 -1
- package/dist/chunk-G4NK66PM.js.map +0 -1
- package/dist/chunk-HIIOADV4.js.map +0 -1
- package/dist/chunk-JSH3BQZ7.mjs +0 -17
- package/dist/chunk-JSH3BQZ7.mjs.map +0 -1
- package/dist/chunk-LGQNMQOT.mjs.map +0 -1
- package/dist/chunk-LMDAF6LA.mjs +0 -51
- package/dist/chunk-LMDAF6LA.mjs.map +0 -1
- package/dist/chunk-M2FN7CNS.mjs.map +0 -1
- package/dist/chunk-MUCV5ZWZ.mjs.map +0 -1
- package/dist/chunk-PJOBOBNJ.js +0 -51
- package/dist/chunk-PJOBOBNJ.js.map +0 -1
- package/dist/chunk-PP7SEERV.mjs.map +0 -1
- package/dist/chunk-SB5YGKXR.js.map +0 -1
- package/dist/chunk-WMDSGVZ7.mjs.map +0 -1
- package/dist/chunk-YQKAASWM.js.map +0 -1
- package/dist/chunk-ZUPP7R2K.js.map +0 -1
- /package/dist/{chunk-EVBQNVQW.mjs.map → chunk-233FSBU7.mjs.map} +0 -0
- /package/dist/{chunk-MADPP2PW.mjs.map → chunk-3ZSI2KI5.mjs.map} +0 -0
- /package/dist/{chunk-2W7PTFXS.mjs.map → chunk-42XKJV56.mjs.map} +0 -0
- /package/dist/{chunk-M6TC6XRQ.mjs.map → chunk-55ESXRRM.mjs.map} +0 -0
- /package/dist/{chunk-4MURAKPC.mjs.map → chunk-5DJVOLVX.mjs.map} +0 -0
- /package/dist/{chunk-YVT7CT3G.mjs.map → chunk-5P6CBDZ6.mjs.map} +0 -0
- /package/dist/{chunk-SFEU7BMY.mjs.map → chunk-5SFNRXZB.mjs.map} +0 -0
- /package/dist/{chunk-KYY4U5SN.mjs.map → chunk-6Z5W5J44.mjs.map} +0 -0
- /package/dist/{chunk-GVYGPJH3.mjs.map → chunk-AU5M2766.mjs.map} +0 -0
- /package/dist/{chunk-Z6UN4ZPW.mjs.map → chunk-BVHVYC7Q.mjs.map} +0 -0
- /package/dist/{chunk-J5VEAJN5.mjs.map → chunk-CWVUGZNK.mjs.map} +0 -0
- /package/dist/{chunk-BCMDP6GK.mjs.map → chunk-DV3N2K3Y.mjs.map} +0 -0
- /package/dist/{chunk-EXHGEJ4P.mjs.map → chunk-GKARHTZ2.mjs.map} +0 -0
- /package/dist/{chunk-JCFN6KRS.mjs.map → chunk-HGWDB73S.mjs.map} +0 -0
- /package/dist/{chunk-JXXMO7PY.mjs.map → chunk-HN5RW4C3.mjs.map} +0 -0
- /package/dist/{chunk-I2A4EQPH.mjs.map → chunk-HQ2GXFK5.mjs.map} +0 -0
- /package/dist/{chunk-TBJLNIOY.mjs.map → chunk-JBLYYTHN.mjs.map} +0 -0
- /package/dist/{chunk-GRSN76BV.mjs.map → chunk-KH2R4STU.mjs.map} +0 -0
- /package/dist/{chunk-ZF5NMQJZ.mjs.map → chunk-KUKLN3CK.mjs.map} +0 -0
- /package/dist/{chunk-UAKRBNW2.mjs.map → chunk-L4T76OKM.mjs.map} +0 -0
- /package/dist/{chunk-PY5WCBKN.mjs.map → chunk-MERKXOSI.mjs.map} +0 -0
- /package/dist/{chunk-APCB5HWT.mjs.map → chunk-NLSDZJRR.mjs.map} +0 -0
- /package/dist/{chunk-EWYIXCNF.mjs.map → chunk-NLUTNCLH.mjs.map} +0 -0
- /package/dist/{chunk-OP4Q2KDS.mjs.map → chunk-NMKKMY5P.mjs.map} +0 -0
- /package/dist/{chunk-WDPFO4II.mjs.map → chunk-NMPK336K.mjs.map} +0 -0
- /package/dist/{chunk-X6BZ5IEV.mjs.map → chunk-NU7O6YKR.mjs.map} +0 -0
- /package/dist/{chunk-CBI5F4ME.mjs.map → chunk-OMSSA4NO.mjs.map} +0 -0
- /package/dist/{chunk-GYHD6QEA.mjs.map → chunk-PQGQ3EH5.mjs.map} +0 -0
- /package/dist/{chunk-LSUCENYD.mjs.map → chunk-RBKGHUSR.mjs.map} +0 -0
- /package/dist/{chunk-TEUERRDG.mjs.map → chunk-RV45XVXE.mjs.map} +0 -0
- /package/dist/{chunk-FW6ZI2MC.mjs.map → chunk-UAFSWXN5.mjs.map} +0 -0
- /package/dist/{chunk-ANLL2EIX.mjs.map → chunk-UWCGTH3U.mjs.map} +0 -0
- /package/dist/{chunk-6R2LEEEP.mjs.map → chunk-UZF2D2GG.mjs.map} +0 -0
- /package/dist/{chunk-62L3PMYE.mjs.map → chunk-V3OVMHZD.mjs.map} +0 -0
- /package/dist/{chunk-UDITT3N3.mjs.map → chunk-V6ELDZ2B.mjs.map} +0 -0
- /package/dist/{chunk-IJQOTS5O.mjs.map → chunk-VJUS3GC4.mjs.map} +0 -0
- /package/dist/{chunk-MQEAEU6G.mjs.map → chunk-XGMRYNER.mjs.map} +0 -0
- /package/dist/{chunk-MMQMVVD6.mjs.map → chunk-XLTD5J74.mjs.map} +0 -0
- /package/dist/{chunk-OMBUOOMD.mjs.map → chunk-XYT542WD.mjs.map} +0 -0
- /package/dist/{chunk-COWOGT7U.mjs.map → chunk-YZWFDSTC.mjs.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Quiz/Quiz.tsx"],"sourcesContent":["import { BookOpenIcon } from '@phosphor-icons/react/dist/csr/BookOpen';\nimport { CaretLeftIcon } from '@phosphor-icons/react/dist/csr/CaretLeft';\nimport { CaretRightIcon } from '@phosphor-icons/react/dist/csr/CaretRight';\nimport { SquaresFourIcon } from '@phosphor-icons/react/dist/csr/SquaresFour';\nimport { HeaderAlternative } from '../Alternative/Alternative';\nimport Button from '../Button/Button';\nimport IconButton from '../IconButton/IconButton';\nimport {\n forwardRef,\n ReactNode,\n useEffect,\n useRef,\n useState,\n ComponentType,\n} from 'react';\nimport {\n useQuizStore,\n QUESTION_TYPE,\n QUIZ_TYPE,\n AI_CORRECTION_STATUS,\n CORRECTION_SOURCE,\n} from './useQuizStore';\nimport CorrectionSourceTag from './CorrectionSourceTag';\nimport { resolveCorrectionText } from './correction.utils';\nimport { QuizVariant } from './Quiz.types';\nimport { AlertDialog } from '../AlertDialog/AlertDialog';\nimport Modal from '../Modal/Modal';\n\nimport Select, {\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '../Select/Select';\nimport { cn } from '../../utils/utils';\nimport {\n QuizAlternative,\n QuizConnectDots,\n QuizDissertative,\n QuizFill,\n QuizImageQuestion,\n QuizMultipleChoice,\n QuizTrueOrFalse,\n} from './QuizContent';\nimport { CardStatus } from '../Card/Card';\nimport Text from '../Text/Text';\nimport HtmlMathRenderer from '../HtmlMathRenderer/HtmlMathRenderer';\nimport {\n formatExamInfo,\n getQuestionA11yIds,\n shouldShowExamInfo,\n} from './Quiz.utils';\nimport QuizTimer from '../QuizTimer/QuizTimer';\nimport { useMobile } from '../../hooks/useMobile';\n\n// Função para obter configuração do tipo de quiz\nexport const getQuizTypeConfig = (type: QUIZ_TYPE) => {\n // Configuração centralizada para cada tipo de quiz\n const QUIZ_TYPE_CONFIG = {\n [QUIZ_TYPE.SIMULADO]: {\n label: 'Simulado',\n article: 'o',\n preposition: 'do',\n },\n [QUIZ_TYPE.QUESTIONARIO]: {\n label: 'Questionário',\n article: 'o',\n preposition: 'do',\n },\n [QUIZ_TYPE.ATIVIDADE]: {\n label: 'Atividade',\n article: 'a',\n preposition: 'da',\n },\n [QUIZ_TYPE.AULA_RECOMENDADA]: {\n label: 'Aula recomendada',\n article: 'a',\n preposition: 'da',\n },\n } as const;\n\n const config = QUIZ_TYPE_CONFIG[type];\n return config || QUIZ_TYPE_CONFIG[QUIZ_TYPE.SIMULADO]; // fallback para simulado\n};\n\n// Função para obter o label do tipo\nexport const getTypeLabel = (type: QUIZ_TYPE) => {\n return getQuizTypeConfig(type).label;\n};\n\n// Função para obter o artigo (o/a)\nexport const getQuizArticle = (type: QUIZ_TYPE) => {\n return getQuizTypeConfig(type).article;\n};\n\n// Função para obter a preposição (do/da)\nexport const getQuizPreposition = (type: QUIZ_TYPE) => {\n return getQuizTypeConfig(type).preposition;\n};\n\n// Função para gerar título de conclusão\nexport const getCompletionTitle = (type: QUIZ_TYPE) => {\n const config = getQuizTypeConfig(type);\n return `Você concluiu ${config.article} ${config.label.toLowerCase()}!`;\n};\n\n// Função para gerar o rótulo do botão de retorno no modal de conclusão\nexport const getGoBackButtonLabel = (type: QUIZ_TYPE): string => {\n if (type === QUIZ_TYPE.SIMULADO) return 'Ir para simulados';\n if (type === QUIZ_TYPE.QUESTIONARIO) return 'Ir para aulas';\n if (type === QUIZ_TYPE.ATIVIDADE) return 'Ir para atividades';\n if (type === QUIZ_TYPE.AULA_RECOMENDADA) return 'Ir para aulas recomendadas';\n return 'Ir para simulados';\n};\n\n// Função para gerar texto de confirmação de saída\nexport const getExitConfirmationText = (type: QUIZ_TYPE) => {\n const config = getQuizTypeConfig(type);\n // QUESTIONARIO não tem rascunho: ao sair, as respostas são perdidas.\n // Demais tipos (SIMULADO, ATIVIDADE, AULA_RECOMENDADA e fallback) salvam o\n // progresso, então o aluno pode continuar depois de onde parou.\n if (type === QUIZ_TYPE.QUESTIONARIO) {\n return `Se você sair ${config.preposition} ${config.label.toLowerCase()} agora, todas as respostas serão perdidas.`;\n }\n return `Se você sair ${config.preposition} ${config.label.toLowerCase()} agora, poderá continuar de onde parou depois.`;\n};\n\n// Função para gerar texto de confirmação de finalização\nexport const getFinishConfirmationText = (type: QUIZ_TYPE) => {\n const config = getQuizTypeConfig(type);\n return `Tem certeza que deseja finalizar ${config.article} ${config.label.toLowerCase()}?`;\n};\n\nconst Quiz = forwardRef<\n HTMLDivElement,\n { children: ReactNode; className?: string; variant?: 'result' | 'default' }\n>(({ children, className, variant = QuizVariant.DEFAULT, ...props }, ref) => {\n const { setVariant } = useQuizStore();\n\n useEffect(() => {\n setVariant(variant as QuizVariant);\n }, [variant, setVariant]);\n\n return (\n <div ref={ref} className={cn('flex flex-col', className)} {...props}>\n {children}\n </div>\n );\n});\n\nconst QuizTitle = forwardRef<\n HTMLDivElement,\n { className?: string; onBack?: () => void; showTimer?: boolean }\n>(({ className, onBack, showTimer = false, ...props }, ref) => {\n const {\n quiz,\n currentQuestionIndex,\n getTotalQuestions,\n getQuizTitle,\n isStarted,\n } = useQuizStore();\n\n const [showExitConfirmation, setShowExitConfirmation] = useState(false);\n\n const totalQuestions = getTotalQuestions();\n const quizTitle = getQuizTitle();\n\n const handleBackClick = () => {\n if (isStarted) {\n setShowExitConfirmation(true);\n } else {\n actionOnBack();\n }\n };\n\n const handleConfirmExit = () => {\n setShowExitConfirmation(false);\n actionOnBack();\n };\n\n const actionOnBack = () => {\n if (onBack) {\n onBack();\n } else {\n globalThis.history.back();\n }\n };\n\n const handleCancelExit = () => {\n setShowExitConfirmation(false);\n };\n\n return (\n <>\n <div\n ref={ref}\n /*\n * Três colunas em vez de `justify-between`: as laterais são `1fr`\n * iguais, então o título fica centralizado na tela mesmo com o voltar\n * e o cronômetro tendo larguras diferentes. Com flex ele era empurrado\n * para a direita junto do cronômetro.\n */\n className={cn(\n 'grid grid-cols-[1fr_auto_1fr] items-center gap-2 relative p-2',\n className\n )}\n {...props}\n >\n <IconButton\n icon={<CaretLeftIcon size={24} />}\n size=\"md\"\n aria-label=\"Voltar\"\n onClick={handleBackClick}\n className=\"justify-self-start\"\n />\n <span className=\"flex flex-col gap-2 text-center\">\n <Text size=\"md\" weight=\"bold\" color=\"text-text-950\">\n {quizTitle}\n </Text>\n <Text size=\"xs\" color=\"text-text-600\">\n {totalQuestions > 0\n ? `${currentQuestionIndex + 1} de ${totalQuestions}`\n : '0 de 0'}\n </Text>\n </span>\n <div className=\"justify-self-end\">{showTimer && <QuizTimer />}</div>\n </div>\n\n <AlertDialog\n isOpen={showExitConfirmation}\n onChangeOpen={setShowExitConfirmation}\n title=\"Deseja sair?\"\n description={getExitConfirmationText(quiz?.type || QUIZ_TYPE.SIMULADO)}\n cancelButtonLabel=\"Voltar e revisar\"\n submitButtonLabel=\"Sair Mesmo Assim\"\n onSubmit={handleConfirmExit}\n onCancel={handleCancelExit}\n />\n </>\n );\n});\n\nconst QuizHeader = () => {\n const { getCurrentQuestion, getQuestionIndex, quiz, currentQuestionIndex } =\n useQuizStore();\n const currentQuestion = getCurrentQuestion();\n const titleRef = useRef<HTMLHeadingElement>(null);\n const previousIndexRef = useRef(currentQuestionIndex);\n\n // After \"Próxima\"/\"Anterior\" focus would stay on the footer button and the\n // new question would go unannounced. Moving it to the heading makes the\n // screen reader read it, and the next Tab lands on the answer controls.\n // The first render is skipped so opening the quiz does not steal focus.\n useEffect(() => {\n if (previousIndexRef.current === currentQuestionIndex) return;\n previousIndexRef.current = currentQuestionIndex;\n titleRef.current?.focus();\n }, [currentQuestionIndex]);\n let currentId =\n currentQuestion && 'questionId' in currentQuestion\n ? (currentQuestion.questionId as string)\n : currentQuestion?.id;\n const questionIndex = getQuestionIndex(currentId!);\n\n const questionNumber = currentQuestion\n ? `Questão ${questionIndex.toString().padStart(2, '0')}`\n : 'Questão';\n\n const showExamInfo = shouldShowExamInfo(quiz);\n const examInfo = showExamInfo\n ? formatExamInfo(currentQuestion?.examBoard, currentQuestion?.examYear)\n : '';\n\n const title = examInfo ? `${questionNumber} ${examInfo}` : questionNumber;\n\n const { titleId, statementId } = getQuestionA11yIds(currentQuestion?.id);\n\n return (\n <HeaderAlternative\n titleId={titleId}\n contentId={statementId}\n titleRef={titleRef}\n title={title}\n subTitle={currentQuestion?.knowledgeMatrix?.[0]?.topic?.name ?? ''}\n content={currentQuestion?.statement ?? ''}\n />\n );\n};\n\nconst QuizContent = ({ paddingBottom }: { paddingBottom?: string }) => {\n const { getCurrentQuestion } = useQuizStore();\n const { isMobile } = useMobile();\n const currentQuestion = getCurrentQuestion();\n\n // `QuizFooter` is `position: fixed`, so it sits on top of the content instead\n // of taking space in the flow — without room reserved here, the last\n // alternative ends up underneath it and unreadable. The bar is taller on a\n // phone, where its controls stack into two rows.\n const contentPaddingBottom = paddingBottom ?? (isMobile ? 'pb-32' : 'pb-24');\n const questionComponents: Record<\n string,\n ComponentType<QuizVariantInterface>\n > = {\n [QUESTION_TYPE.ALTERNATIVA]: QuizAlternative,\n [QUESTION_TYPE.MULTIPLA_ESCOLHA]: QuizMultipleChoice,\n [QUESTION_TYPE.DISSERTATIVA]: QuizDissertative,\n [QUESTION_TYPE.VERDADEIRO_FALSO]: QuizTrueOrFalse,\n [QUESTION_TYPE.RELACIONAR]: QuizConnectDots,\n [QUESTION_TYPE.PREENCHER_LACUNAS]: QuizFill,\n [QUESTION_TYPE.IMAGEM]: QuizImageQuestion,\n };\n\n const QuestionComponent = currentQuestion\n ? questionComponents[currentQuestion.questionType]\n : null;\n\n if (!QuestionComponent) {\n return (\n <Text size=\"md\" weight=\"medium\" className=\"text-text-950 text-md\">\n Tipo de questão não suportado\n </Text>\n );\n }\n\n // The teacher's comment is no longer echoed here: in the result variant it\n // lives behind the \"Ver comentário\" button in the footer, so it is not shown\n // twice on the same screen.\n return <QuestionComponent paddingBottom={contentPaddingBottom} />;\n};\n\ninterface QuizVariantInterface {\n paddingBottom?: string;\n}\n\nconst QuizQuestionList = ({\n filterType = 'all',\n onQuestionClick,\n}: {\n filterType?: string;\n onQuestionClick?: () => void;\n} = {}) => {\n const {\n getQuestionsGroupedBySubject,\n goToQuestion,\n getQuestionStatusFromUserAnswers,\n getQuestionIndex,\n quiz,\n } = useQuizStore();\n\n const showExamInfo = shouldShowExamInfo(quiz);\n\n const groupedQuestions = getQuestionsGroupedBySubject();\n const getQuestionStatus = (questionId: string) => {\n return getQuestionStatusFromUserAnswers(questionId);\n };\n const filteredGroupedQuestions = Object.entries(groupedQuestions).reduce(\n (acc, [subjectId, questions]) => {\n const filteredQuestions = questions.filter((question) => {\n const status = getQuestionStatus(question.id);\n switch (filterType) {\n case 'answered':\n return status === 'answered';\n case 'unanswered':\n return status === 'unanswered' || status === 'skipped';\n default:\n return true;\n }\n });\n\n if (filteredQuestions.length > 0) {\n acc[subjectId] = filteredQuestions;\n }\n\n return acc;\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n {} as { [key: string]: any[] }\n );\n\n const getStatusLabel = (status: string) => {\n switch (status) {\n case 'answered':\n return 'Respondida';\n case 'skipped':\n return 'Em branco';\n default:\n return 'Em branco';\n }\n };\n return (\n <div className=\"space-y-6 px-4 h-full\">\n {Object.entries(filteredGroupedQuestions).length == 0 && (\n <div className=\"flex items-center justify-center text-gray-500 py-8 h-full\">\n <p className=\"text-lg\">Nenhum resultado</p>\n </div>\n )}\n {Object.entries(filteredGroupedQuestions).map(\n ([subjectId, questions]) => (\n <section key={subjectId} className=\"flex flex-col gap-2\">\n <span className=\"pt-6 pb-4 flex flex-row gap-2\">\n <div className=\"bg-primary-500 p-1 rounded-sm flex items-center justify-center\">\n <BookOpenIcon size={17} className=\"text-white\" />\n </div>\n <p className=\"text-text-800 font-bold text-lg\">\n {questions?.[0]?.knowledgeMatrix?.[0]?.subject?.name ??\n 'Sem componente curricular'}\n </p>\n </span>\n\n <ul className=\"flex flex-col gap-2\">\n {questions.map((question) => {\n const status = getQuestionStatus(question.id);\n const questionNumber = getQuestionIndex(question.id);\n const examInfo = showExamInfo\n ? formatExamInfo(question.examBoard, question.examYear)\n : '';\n const questionTitle = `Questão ${questionNumber.toString().padStart(2, '0')}`;\n const header = examInfo\n ? `${questionTitle} ${examInfo}`\n : questionTitle;\n return (\n <CardStatus\n key={question.id}\n header={header}\n label={getStatusLabel(status)}\n onClick={() => {\n goToQuestion(questionNumber - 1);\n onQuestionClick?.();\n }}\n />\n );\n })}\n </ul>\n </section>\n )\n )}\n </div>\n );\n};\n\n/**\n * Shared layout for the quiz result modals (generic result, all-correct and\n * all-incorrect questionnaire variants): a centered image, a title and a\n * footer with action buttons.\n */\nconst QuizResultModal = ({\n isOpen,\n onClose,\n image,\n showImagePlaceholder = true,\n title,\n description,\n footer,\n}: {\n isOpen: boolean;\n onClose: () => void;\n image?: ReactNode;\n showImagePlaceholder?: boolean;\n title: ReactNode;\n description: ReactNode;\n footer: ReactNode;\n}) => (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title=\"\"\n closeOnEscape={false}\n hideCloseButton\n size={'md'}\n >\n <div className=\"flex flex-col w-full h-full items-center justify-center gap-4\">\n {image ? (\n <div className=\"w-[282px] h-auto\">{image}</div>\n ) : (\n showImagePlaceholder && (\n <div className=\"w-[282px] h-[200px] bg-gray-100 rounded-md flex items-center justify-center\">\n <Text as=\"span\" size=\"sm\" color=\"text-gray-500\">\n Imagem de resultado\n </Text>\n </div>\n )\n )}\n <div className=\"flex flex-col gap-2 text-center\">\n <Text as=\"h2\" size=\"lg\" weight=\"bold\">\n {title}\n </Text>\n {description}\n </div>\n {footer}\n </div>\n </Modal>\n);\n\n/**\n * Correction of the question currently on screen, resolved once.\n *\n * A dissertativa may have been graded by the AI. The teacher's text wins when it\n * exists, the AI's stands otherwise; the two are never merged — the backend\n * keeps them in separate columns precisely so a review does not destroy the\n * original verdict — and `correctionSource` says which one is on screen.\n *\n * It lives here, and not inline in `QuizFooter`, because both the footer (for\n * the modal body and title) and `QuizReviewActions` (for the buttons) need the\n * same four values, and deriving them twice would be two chances to disagree.\n *\n * @returns The effective comment plus the fields the tag and the title read\n */\nconst useCurrentCorrection = () => {\n const { getCurrentQuestion, getQuestionResultByQuestionId } = useQuizStore();\n\n const currentQuestion = getCurrentQuestion();\n const result = currentQuestion\n ? getQuestionResultByQuestionId(currentQuestion.id)\n : null;\n\n return {\n comment: resolveCorrectionText({ ...result }),\n correctionSource: result?.correctionSource,\n aiCorrectionStatus: result?.aiCorrectionStatus,\n };\n};\n\n/**\n * Title for the per-question feedback modal, phrased for whoever wrote it.\n *\n * Calling an AI correction \"Comentário do professor\" would be a lie the tag\n * inside the modal immediately contradicts, so both are derived from the same\n * `correctionSource`.\n *\n * @param correctionSource - Who produced the correction on display\n * @returns The modal title\n */\nconst getCorrectionModalTitle = (\n correctionSource?: CORRECTION_SOURCE | null\n): string => {\n if (correctionSource === CORRECTION_SOURCE.IA) {\n return 'Correção por IA';\n }\n\n if (correctionSource === CORRECTION_SOURCE.IA_PROFESSOR) {\n return 'Correção revisada pelo professor';\n }\n\n return 'Comentário do professor';\n};\n\n/**\n * The review bar's question-scoped actions: see the resolution, see the correction.\n *\n * Split out of `QuizFooter` because the two bars do different jobs — the\n * `default` one navigates between questions, this one reads a question already\n * graded — and because the four conditions the correction needs pushed the\n * footer past the cognitive-complexity limit while sitting in the middle of\n * unrelated navigation markup.\n *\n * @param props - Callbacks that open the footer's modals\n * @returns JSX element\n */\nconst QuizReviewActions = ({\n onOpenResolution,\n onOpenComment,\n className,\n}: {\n onOpenResolution: () => void;\n onOpenComment: () => void;\n readonly className?: string;\n}) => {\n const { getCurrentQuestion } = useQuizStore();\n const { comment, correctionSource, aiCorrectionStatus } =\n useCurrentCorrection();\n\n const currentQuestion = getCurrentQuestion();\n const hasResolution = Boolean(currentQuestion?.solutionExplanation);\n const isAiCorrecting = aiCorrectionStatus === AI_CORRECTION_STATUS.PENDING;\n const commentLabel =\n correctionSource === CORRECTION_SOURCE.IA\n ? 'Ver correção da IA'\n : 'Ver comentário';\n\n return (\n <div className={className}>\n {hasResolution && (\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"large\"\n onClick={onOpenResolution}\n >\n Ver resolução\n </Button>\n )}\n {comment && (\n <Button\n variant=\"outline\"\n action=\"primary\"\n size=\"large\"\n onClick={onOpenComment}\n >\n {commentLabel}\n </Button>\n )}\n {/* Sem comentário ainda, mas a IA está corrigindo: o aluno acaba de\n entregar e chegou aqui antes do feedback existir. Dizer que está a\n caminho é melhor do que não mostrar nada. */}\n {!comment && isAiCorrecting && (\n <CorrectionSourceTag\n aiCorrectionStatus={aiCorrectionStatus}\n className=\"self-center\"\n />\n )}\n </div>\n );\n};\n\n/**\n * What the completion modal shows instead of the score.\n *\n * Some exams are not corrected on the spot — the in-classroom ENEM simulation\n * is graded later — so telling the student how many they got right would be\n * wrong. With this set, finishing opens a modal with only this content and\n * one button.\n */\nexport interface QuizCompletionOverride {\n title: ReactNode;\n description: ReactNode;\n buttonLabel: string;\n onConfirm: () => void;\n}\n\nconst QuizFooter = forwardRef<\n HTMLDivElement,\n {\n className?: string;\n onGoToSimulated?: () => void;\n onDetailResult?: () => void;\n handleFinishSimulated?: () => void;\n onGoToNextModule?: () => void;\n onRepeat?: () => void;\n onTryLater?: () => void;\n resultImageComponent?: ReactNode;\n resultIncorrectImageComponent?: ReactNode;\n /** Replaces the score modal; see `QuizCompletionOverride`. */\n completionOverride?: QuizCompletionOverride;\n }\n>(\n (\n {\n className,\n onGoToSimulated,\n onDetailResult,\n handleFinishSimulated,\n onGoToNextModule,\n onRepeat,\n onTryLater,\n resultImageComponent,\n resultIncorrectImageComponent,\n completionOverride,\n ...props\n },\n ref\n ) => {\n const {\n quiz,\n currentQuestionIndex,\n getTotalQuestions,\n goToNextQuestion,\n goToPreviousQuestion,\n getUnansweredQuestionsFromUserAnswers,\n getCurrentAnswer,\n skipQuestion,\n skipCurrentQuestionIfUnanswered,\n getCurrentQuestion,\n getQuestionStatusFromUserAnswers,\n variant,\n getQuestionResultStatistics,\n } = useQuizStore();\n\n // The review bar carries four controls. Below ~500px they no longer fit on\n // one line, so the actions and the pagination stack into two centred rows.\n const { isMobile } = useMobile();\n\n const totalQuestions = getTotalQuestions();\n const isFirstQuestion = currentQuestionIndex === 0;\n const isLastQuestion = currentQuestionIndex === totalQuestions - 1;\n const currentAnswer = getCurrentAnswer();\n const currentQuestion = getCurrentQuestion();\n const {\n comment: teacherComment,\n correctionSource,\n aiCorrectionStatus,\n } = useCurrentCorrection();\n const isCurrentQuestionSkipped = currentQuestion\n ? getQuestionStatusFromUserAnswers(currentQuestion.id) === 'skipped'\n : false;\n // Sistema unificado de controle de modais\n const [activeModal, setActiveModal] = useState<string | null>(null);\n const [filterType, setFilterType] = useState<string>('all');\n\n // Funções para controlar modais\n const openModal = (modalName: string) => setActiveModal(modalName);\n const closeModal = () => setActiveModal(null);\n const isModalOpen = (modalName: string) => activeModal === modalName;\n const unansweredQuestions = getUnansweredQuestionsFromUserAnswers();\n const allQuestions = getTotalQuestions();\n const stats = getQuestionResultStatistics();\n const correctAnswers = stats?.correctAnswers;\n const quizType = quiz?.type || QUIZ_TYPE.SIMULADO;\n const quizTypeLabel = getTypeLabel(quizType);\n // Real subtopic name, used to label the questionnaire completion modals.\n // The backend always populates the question knowledge matrix, so this is\n // available as soon as the quiz is loaded.\n const moduleName =\n quiz?.questions?.[0]?.knowledgeMatrix?.[0]?.subtopic?.name;\n\n // Submits the answers and opens the correct result modal. Statistics must\n // be read AFTER handleFinishSimulated, which is what populates\n // questionsResult in the store (the render-time values are still empty).\n const submitAndOpenResultModal = async () => {\n if (handleFinishSimulated) {\n await Promise.resolve(handleFinishSimulated());\n }\n\n if (completionOverride) {\n openModal('modalCompletionOverride');\n return;\n }\n\n const latestStats = getQuestionResultStatistics();\n const latestCorrect = latestStats?.correctAnswers;\n const latestTotal = latestStats?.totalAnswered;\n\n if (\n quizType === QUIZ_TYPE.QUESTIONARIO &&\n typeof latestCorrect === 'number' &&\n typeof latestTotal === 'number' &&\n latestCorrect === latestTotal\n ) {\n openModal('modalQuestionnaireAllCorrect');\n return;\n }\n\n if (\n quizType === QUIZ_TYPE.QUESTIONARIO &&\n typeof latestCorrect === 'number' &&\n latestCorrect === 0\n ) {\n openModal('modalQuestionnaireAllIncorrect');\n return;\n }\n\n openModal('modalResult');\n };\n\n const handleFinishQuiz = async () => {\n // Marca a questão atual como pulada se não foi respondida\n skipCurrentQuestionIfUnanswered();\n\n if (unansweredQuestions.length > 0) {\n openModal('alertDialog');\n return;\n }\n\n try {\n await submitAndOpenResultModal();\n } catch (err) {\n console.error('handleFinishSimulated failed:', err);\n }\n };\n\n const handleAlertSubmit = async () => {\n try {\n await submitAndOpenResultModal();\n } catch (err) {\n console.error('handleFinishSimulated failed:', err);\n closeModal();\n }\n };\n\n return (\n <>\n <footer\n ref={ref}\n className={cn(\n 'w-full px-2 bg-background lg:max-w-[1000px] not-lg:max-w-[calc(100vw-32px)] border-t border-border-50 fixed bottom-0 min-h-[80px] flex flex-row justify-between items-center',\n className\n )}\n {...props}\n >\n {variant === 'default' ? (\n <>\n <div className=\"flex flex-row items-center gap-1\">\n <IconButton\n icon={<SquaresFourIcon size={24} className=\"text-text-950\" />}\n size=\"md\"\n onClick={() => openModal('modalNavigate')}\n />\n\n {isFirstQuestion ? (\n <Button\n variant=\"outline\"\n size=\"small\"\n onClick={() => {\n skipQuestion();\n goToNextQuestion();\n }}\n >\n Pular\n </Button>\n ) : (\n <Button\n size=\"medium\"\n variant=\"link\"\n action=\"primary\"\n iconLeft={<CaretLeftIcon size={18} />}\n onClick={() => {\n goToPreviousQuestion();\n }}\n >\n Voltar\n </Button>\n )}\n </div>\n\n {!isFirstQuestion && !isLastQuestion && (\n <Button\n size=\"small\"\n variant=\"outline\"\n action=\"primary\"\n onClick={() => {\n skipQuestion();\n goToNextQuestion();\n }}\n >\n Pular\n </Button>\n )}\n\n {isLastQuestion ? (\n <Button\n size=\"medium\"\n variant=\"solid\"\n action=\"primary\"\n onClick={handleFinishQuiz}\n >\n Finalizar\n </Button>\n ) : (\n <Button\n size=\"medium\"\n variant=\"link\"\n action=\"primary\"\n iconRight={<CaretRightIcon size={18} />}\n disabled={!currentAnswer && !isCurrentQuestionSkipped}\n onClick={() => {\n goToNextQuestion();\n }}\n >\n Avançar\n </Button>\n )}\n </>\n ) : (\n <div\n className={cn(\n 'flex w-full items-center gap-2',\n isMobile ? 'flex-col py-2' : 'flex-row'\n )}\n >\n <QuizReviewActions\n className={cn(\n 'flex flex-row items-center gap-2',\n isMobile && 'justify-center'\n )}\n onOpenResolution={() => openModal('modalResolution')}\n onOpenComment={() => openModal('modalTeacherComment')}\n />\n {/* On a wide bar the pagination sits at the far end, away from the\n actions that act on the question being read; stacked, it is\n centred under them. */}\n <div\n className={cn(\n 'flex flex-row items-center gap-2',\n isMobile ? 'justify-center' : 'flex-1 justify-end'\n )}\n >\n <Button\n variant=\"outline\"\n action=\"primary\"\n size=\"medium\"\n aria-label=\"Questão anterior\"\n disabled={isFirstQuestion}\n onClick={goToPreviousQuestion}\n >\n <CaretLeftIcon size={18} />\n </Button>\n <Button\n variant=\"outline\"\n action=\"primary\"\n size=\"medium\"\n aria-label=\"Próxima questão\"\n disabled={isLastQuestion}\n onClick={goToNextQuestion}\n >\n <CaretRightIcon size={18} />\n </Button>\n </div>\n </div>\n )}\n </footer>\n\n <AlertDialog\n isOpen={isModalOpen('alertDialog')}\n onChangeOpen={(open) =>\n open ? openModal('alertDialog') : closeModal()\n }\n title={`Finalizar ${quizTypeLabel.toLowerCase()}?`}\n description={\n unansweredQuestions.length > 0\n ? `Você deixou as questões ${unansweredQuestions.join(', ')} sem resposta. Finalizar agora pode impactar seu desempenho.`\n : getFinishConfirmationText(quizType)\n }\n cancelButtonLabel=\"Voltar e revisar\"\n submitButtonLabel=\"Finalizar Mesmo Assim\"\n onSubmit={handleAlertSubmit}\n />\n\n <QuizResultModal\n isOpen={isModalOpen('modalResult')}\n onClose={closeModal}\n image={resultImageComponent}\n title={getCompletionTitle(quizType)}\n description={\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n Você acertou {correctAnswers ?? '--'} de {allQuestions} questões.\n </Text>\n }\n footer={\n <div className=\"px-6 flex flex-row items-center gap-2 w-full\">\n <Button\n variant=\"outline\"\n className=\"w-full\"\n size=\"small\"\n onClick={onGoToSimulated}\n >\n {getGoBackButtonLabel(quizType)}\n </Button>\n\n <Button className=\"w-full\" onClick={onDetailResult}>\n Detalhar resultado\n </Button>\n </div>\n }\n />\n\n {completionOverride && (\n <QuizResultModal\n isOpen={isModalOpen('modalCompletionOverride')}\n onClose={closeModal}\n image={resultImageComponent}\n title={completionOverride.title}\n description={\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n {completionOverride.description}\n </Text>\n }\n footer={\n <div className=\"px-6 flex flex-row items-center w-full\">\n <Button\n className=\"w-full\"\n onClick={completionOverride.onConfirm}\n data-testid=\"quiz-completion-override-confirm\"\n >\n {completionOverride.buttonLabel}\n </Button>\n </div>\n }\n />\n )}\n\n <Modal\n isOpen={isModalOpen('modalNavigate')}\n onClose={closeModal}\n title=\"Questões\"\n size={'lg'}\n >\n <div className=\"flex flex-col w-full not-lg:h-[calc(100vh-200px)] lg:max-h-[687px] lg:h-[687px]\">\n <div className=\"flex flex-row justify-between items-center py-6 pt-6 pb-4 border-b border-border-200 flex-shrink-0\">\n <p className=\"text-text-950 font-bold text-lg\">Filtrar por</p>\n <span className=\"max-w-[266px]\">\n <Select value={filterType} onValueChange={setFilterType}>\n <SelectTrigger\n variant=\"rounded\"\n className=\"max-w-[266px] min-w-[160px]\"\n >\n <SelectValue placeholder=\"Selecione uma opção\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">Todas</SelectItem>\n <SelectItem value=\"unanswered\">Em branco</SelectItem>\n <SelectItem value=\"answered\">Respondidas</SelectItem>\n </SelectContent>\n </Select>\n </span>\n </div>\n\n <div className=\"flex flex-col gap-2 flex-1 min-h-0 overflow-y-auto\">\n <QuizQuestionList\n filterType={filterType}\n onQuestionClick={closeModal}\n />\n </div>\n </div>\n </Modal>\n\n <Modal\n isOpen={isModalOpen('modalResolution')}\n onClose={closeModal}\n title=\"Resolução\"\n size={'lg'}\n >\n <HtmlMathRenderer\n content={currentQuestion?.solutionExplanation || ''}\n className=\"text-text-950 text-base\"\n />\n </Modal>\n\n <Modal\n isOpen={isModalOpen('modalTeacherComment')}\n onClose={closeModal}\n title={getCorrectionModalTitle(correctionSource)}\n size={'lg'}\n >\n {/* A tag fica dentro do modal, junto do texto: é ela que diz se o que\n está sendo lido saiu da IA, do professor, ou da IA revisada por\n ele. Sem isso o título sozinho teria que carregar essa informação\n em toda variação. */}\n <CorrectionSourceTag\n correctionSource={correctionSource}\n aiCorrectionStatus={aiCorrectionStatus}\n className=\"mb-3\"\n />\n {/* Plain text on purpose: the teacher writes this in a bare textarea,\n so running it through the HTML/LaTeX renderer would change what\n they typed. `whitespace-pre-wrap` keeps their line breaks. The AI\n feedback is plain text for the same reason. */}\n <Text\n size=\"md\"\n className=\"text-text-950 whitespace-pre-wrap break-words\"\n >\n {teacherComment}\n </Text>\n </Modal>\n\n <QuizResultModal\n isOpen={isModalOpen('modalQuestionnaireAllCorrect')}\n onClose={closeModal}\n image={resultImageComponent}\n title=\"🎉 Parabéns!\"\n description={\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n {moduleName\n ? `Você concluiu o módulo ${moduleName}.`\n : 'Você concluiu o questionário!'}\n </Text>\n }\n footer={\n <div className=\"px-6 flex flex-row items-center gap-2 w-full\">\n <Button className=\"w-full\" onClick={onGoToNextModule}>\n {getGoBackButtonLabel(quizType)}\n </Button>\n </div>\n }\n />\n\n <QuizResultModal\n isOpen={isModalOpen('modalQuestionnaireAllIncorrect')}\n onClose={closeModal}\n image={resultIncorrectImageComponent}\n showImagePlaceholder={false}\n title=\"😕 Não foi dessa vez...\"\n description={\n <>\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n Você tirou 0 no questionário, mas não se preocupe! Isso é apenas\n uma oportunidade de aprendizado.\n </Text>\n\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n Que tal tentar novamente para melhorar sua nota? Estamos aqui\n para te ajudar a entender o conteúdo e evoluir.\n </Text>\n\n {quiz?.canRetry && (\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n Clique em Repetir Questionário e mostre do que você é capaz!\n 💪\n </Text>\n )}\n </>\n }\n footer={\n <div className=\"flex flex-row justify-center items-center gap-2 w-full\">\n {quiz?.canRetry && (\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"small\"\n className=\"w-auto\"\n onClick={() => {\n closeModal();\n openModal('alertDialogTryLater');\n }}\n >\n Tentar depois\n </Button>\n )}\n\n <Button\n variant=\"outline\"\n size=\"small\"\n className=\"w-auto\"\n onClick={onDetailResult}\n >\n Detalhar resultado\n </Button>\n\n {quiz?.canRetry ? (\n <Button className=\"w-auto\" size=\"small\" onClick={onRepeat}>\n Repetir questionário\n </Button>\n ) : (\n <Button\n className=\"w-auto\"\n size=\"small\"\n onClick={onGoToSimulated}\n >\n {getGoBackButtonLabel(quizType)}\n </Button>\n )}\n </div>\n }\n />\n\n <AlertDialog\n isOpen={isModalOpen('alertDialogTryLater')}\n onChangeOpen={(open) =>\n open ? openModal('alertDialogTryLater') : closeModal()\n }\n title=\"Tentar depois?\"\n description={\n 'Você optou por refazer o questionário mais tarde.\\n\\nLembre-se: enquanto não refazer o questionário, sua nota permanecerá 0 no sistema.'\n }\n cancelButtonLabel=\"Repetir questionário\"\n submitButtonLabel=\"Tentar depois\"\n onSubmit={() => {\n onTryLater?.();\n closeModal();\n }}\n onCancel={() => {\n onRepeat?.();\n closeModal();\n }}\n />\n </>\n );\n }\n);\n\nexport {\n QuizTitle,\n Quiz,\n QuizHeader,\n QuizContent,\n QuizFooter,\n QuizQuestionList,\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-EHQDQ5RV.js","../src/components/Chatbot/Chatbot.tsx","../src/components/Chatbot/ChatbotFab.tsx","../src/components/Chatbot/ChatbotPanel.tsx","../src/components/Chatbot/ChatbotMessageList.tsx","../src/components/Chatbot/ChatbotMessage.tsx","../src/components/Chatbot/ChatbotContentRenderer.tsx","../src/components/Chatbot/ChatbotTypingIndicator.tsx","../src/components/Chatbot/ChatbotInput.tsx","../src/components/Chatbot/ChatbotConversationList.tsx"],"names":["jsx","useRef"],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-EHQDQ5RV.js","sourcesContent":[null,"import { useEffect, useRef } from 'react';\nimport ChatbotFab from './ChatbotFab';\nimport ChatbotPanel from './ChatbotPanel';\nimport ChatbotMessageList from './ChatbotMessageList';\nimport ChatbotInput from './ChatbotInput';\nimport ChatbotConversationList from './ChatbotConversationList';\nimport { createUseChatbot } from '../../hooks/useChatbot';\nimport type {\n ChatbotApiClient,\n ChatbotCurrentContext,\n ChatbotUser,\n} from '../../types/chatbot';\n\n/**\n * Props for the root Chatbot component\n */\nexport interface ChatbotProps {\n /** API client that wraps REST calls — produced by the host app */\n apiClient: ChatbotApiClient;\n /** Authenticated user (used only for UI decoration today) */\n user: ChatbotUser;\n /** Optional context sent with every outgoing message */\n currentContext?: ChatbotCurrentContext;\n /** Extra tailwind classes on the FAB */\n fabClassName?: string;\n /** Extra tailwind classes on the panel */\n panelClassName?: string;\n}\n\n/**\n * Analytica student chatbot — floating assistant available in the\n * authenticated area. Composes the Fab + Panel and owns no state of its\n * own: the `useChatbot` hook (bound to the provided `apiClient`) keeps\n * everything in one place.\n *\n * Host apps should render this inside the layout so the FAB is reachable\n * from every page. `currentContext` is a hint (activityId, questionId,\n * lessonId) produced by the host to enrich the AI prompt — it flows\n * untouched to the backend.\n */\nexport default function Chatbot({\n apiClient,\n user,\n currentContext,\n fabClassName,\n panelClassName,\n}: Readonly<ChatbotProps>) {\n // Keep the latest apiClient in a ref — any `apiClient` prop swap (e.g.,\n // after re-auth with a new token-bound client) is seen by the hook on\n // its next call without tearing down internal state.\n const apiClientRef = useRef(apiClient);\n apiClientRef.current = apiClient;\n\n // Bind the factory exactly once, passing a getter so the hook resolves\n // `apiClientRef.current` fresh on every call instead of snapshotting\n // whatever client we saw on first mount.\n const boundHookRef = useRef<ReturnType<typeof createUseChatbot> | null>(null);\n boundHookRef.current ??= createUseChatbot(() => apiClientRef.current);\n const useBoundChatbot = boundHookRef.current;\n const {\n isOpen,\n isSending,\n isLoadingHistory,\n isLoadingMessages,\n errorMessage,\n conversations,\n activeConversationId,\n messages,\n togglePanel,\n closePanel,\n selectConversation,\n startNewConversation,\n sendMessage,\n deleteConversation,\n } = useBoundChatbot();\n\n const firstName = user.name?.trim().split(/\\s+/)[0];\n const emptyHint = firstName\n ? `Olá, ${firstName}! Como posso ajudar nos seus estudos?`\n : 'Comece a conversa enviando uma pergunta.';\n\n const handleSend = (text: string): void => {\n sendMessage(text, currentContext).catch(() => undefined);\n };\n\n const fabRef = useRef<HTMLButtonElement>(null);\n const wasOpenRef = useRef(false);\n\n /**\n * Returns focus to the FAB when the panel closes.\n *\n * The panel restores focus on its own (`useModalFocus` remembers whoever\n * opened it), but when that was the FAB the remembered node is gone — the FAB\n * is unmounted while the panel is open, and the hook only restores focus to an\n * element still on the page, so focus would be left on the `<body>`.\n *\n * The `<body>` guard keeps any other opener intact: if something else still\n * holds the focus the hook already handled it, and this effect stays out of\n * the way.\n */\n useEffect(() => {\n if (isOpen) {\n wasOpenRef.current = true;\n return;\n }\n\n if (!wasOpenRef.current) return;\n wasOpenRef.current = false;\n\n const active = document.activeElement;\n if (!active || active === document.body) {\n fabRef.current?.focus();\n }\n }, [isOpen]);\n\n return (\n <>\n {!isOpen && (\n <ChatbotFab\n ref={fabRef}\n onClick={togglePanel}\n isOpen={isOpen}\n className={fabClassName}\n />\n )}\n <ChatbotPanel\n isOpen={isOpen}\n onClose={closePanel}\n onStartNew={startNewConversation}\n className={panelClassName}\n errorMessage={errorMessage}\n historySlot={\n <ChatbotConversationList\n conversations={conversations}\n activeConversationId={activeConversationId}\n isLoading={isLoadingHistory}\n onSelect={selectConversation}\n onDelete={deleteConversation}\n onStartNew={startNewConversation}\n />\n }\n messagesSlot={\n <ChatbotMessageList\n messages={messages}\n isSending={isSending}\n isLoading={isLoadingMessages}\n emptyHint={emptyHint}\n />\n }\n inputSlot={<ChatbotInput onSend={handleSend} disabled={isSending} />}\n />\n </>\n );\n}\n","import { forwardRef } from 'react';\nimport { ChatCircleDotsIcon } from '@phosphor-icons/react';\nimport Button from '../Button/Button';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\n\n/**\n * Props for the floating action button that opens the chatbot panel\n */\nexport interface ChatbotFabProps {\n /** Click handler — opens or toggles the panel */\n onClick: () => void;\n /** Whether the panel is currently open (drives aria + styling) */\n isOpen?: boolean;\n /** Optional unread count badge */\n unreadCount?: number;\n /** Extra tailwind classes */\n className?: string;\n}\n\n/**\n * Circular floating action button anchored bottom-right of the viewport.\n * Uses `fixed` so it sits on top of page scroll.\n *\n * The ref lands on the `<button>`: the FAB is unmounted while the panel is\n * open, so `Chatbot` is the one that returns focus to it on close and needs to\n * reach the freshly remounted node.\n */\nconst ChatbotFab = forwardRef<HTMLButtonElement, ChatbotFabProps>(\n ({ onClick, isOpen = false, unreadCount = 0, className }, ref) => {\n const noun =\n unreadCount === 1 ? 'mensagem não lida' : 'mensagens não lidas';\n let badgeLabel: string;\n if (unreadCount > 9) {\n badgeLabel = 'Mais de 9 mensagens não lidas';\n } else {\n badgeLabel = `${unreadCount} ${noun}`;\n }\n\n const baseAriaLabel = isOpen\n ? 'Fechar assistente'\n : 'Abrir assistente de estudos';\n const ariaLabel =\n unreadCount > 0 ? `${baseAriaLabel} (${badgeLabel})` : baseAriaLabel;\n\n return (\n <Button\n ref={ref}\n variant=\"raw\"\n onClick={onClick}\n aria-label={ariaLabel}\n aria-expanded={isOpen}\n className={cn(\n 'fixed bottom-6 right-6 z-40',\n 'flex h-14 w-14 items-center justify-center rounded-full',\n 'bg-primary-500 text-white shadow-lg',\n 'transition-all hover:bg-primary-600 active:scale-95',\n 'focus:outline-none focus:ring-2 focus:ring-primary-300',\n className\n )}\n >\n <ChatCircleDotsIcon size={26} weight=\"fill\" />\n {unreadCount > 0 && (\n <Text\n as=\"span\"\n size=\"xs\"\n weight=\"bold\"\n color=\"text-white\"\n data-testid=\"chatbot-fab-badge\"\n aria-live=\"polite\"\n aria-label={badgeLabel}\n className=\"absolute -top-1 -right-1 flex h-5 min-w-5 items-center justify-center rounded-full bg-error-500 px-1\"\n >\n {unreadCount > 9 ? '9+' : unreadCount}\n </Text>\n )}\n </Button>\n );\n }\n);\n\nChatbotFab.displayName = 'ChatbotFab';\n\nexport default ChatbotFab;\n","import { useEffect, useRef, useState, type ReactNode } from 'react';\nimport {\n CaretUpIcon,\n ListIcon,\n MinusIcon,\n PlusIcon,\n RobotIcon,\n XIcon,\n} from '@phosphor-icons/react';\nimport Text from '../Text/Text';\nimport IconButton from '../IconButton/IconButton';\nimport { cn } from '../../utils/utils';\nimport { useModalFocus } from '../../hooks/useModalFocus';\nimport { useEscapeToClose } from '../../hooks/useEscapeToClose';\n\nconst HEADER_ICON_BUTTON_CLASSES =\n '!text-white hover:!bg-white/15 hover:!text-white focus-visible:!ring-white/60';\n\n/**\n * Props for the chatbot panel shell\n */\nexport interface ChatbotPanelProps {\n isOpen: boolean;\n onClose: () => void;\n onStartNew: () => void;\n /** Conversation list passed as a node so the panel stays layout-only */\n historySlot: ReactNode;\n /** Messages list passed as a node (allows easy swap during tests) */\n messagesSlot: ReactNode;\n /** Input area slot (auto-resize textarea + send button) */\n inputSlot: ReactNode;\n /** Optional error banner (string shown above the input) */\n errorMessage?: string | null;\n className?: string;\n}\n\n/**\n * Fixed drawer-like panel anchored to the bottom-right of the screen.\n * Splits into optional history sidebar + main conversation area. The\n * panel is purely presentational — state lives in the `useChatbot` hook.\n */\nexport default function ChatbotPanel({\n isOpen,\n onClose,\n onStartNew,\n historySlot,\n messagesSlot,\n inputSlot,\n errorMessage,\n className,\n}: Readonly<ChatbotPanelProps>) {\n const [showHistory, setShowHistory] = useState(false);\n const [isMinimized, setIsMinimized] = useState(false);\n const dialogRef = useRef<HTMLDialogElement>(null);\n const previousErrorRef = useRef<string | null | undefined>(errorMessage);\n\n // Reset the minimized state every time the panel is reopened so the\n // user always lands on the full conversation view.\n useEffect(() => {\n if (isOpen) {\n setIsMinimized(false);\n }\n }, [isOpen]);\n\n // Auto-expand on new errors so the role=\"alert\" banner is mounted and\n // announced by screen readers. Without this, a failed send while\n // minimized would be silent — the body (including the alert node) is\n // unmounted in the minimized state. Compare against the previous value\n // (not just truthy/falsy) so a distinct truthy error arriving after the\n // user minimized also re-expands and re-announces.\n useEffect(() => {\n const previous = previousErrorRef.current;\n if (errorMessage && errorMessage !== previous) {\n setIsMinimized(false);\n }\n previousErrorRef.current = errorMessage;\n }, [errorMessage]);\n\n /**\n * Foco e navegação pelos hooks compartilhados, os mesmos do `Modal` e do\n * `AlertDialog`: `useModalFocus` leva o foco pro diálogo ao abrir, prende Tab\n * e Shift+Tab lá dentro, torna o resto da página `inert` (um `<dialog open>`\n * sem `showModal()` não tem top layer, então nada impedia o cursor virtual do\n * leitor de tela de passear pela página atrás) e devolve o foco a quem abriu.\n *\n * `useEscapeToClose` respeita um Escape já tratado, então fechar um popover\n * de dentro do painel não fecha o painel junto.\n */\n useModalFocus(isOpen, dialogRef);\n useEscapeToClose(isOpen, onClose);\n\n if (!isOpen) return null;\n\n return (\n <dialog\n ref={dialogRef}\n open\n // Requisito do `useModalFocus`: o foco inicial vai pro próprio diálogo,\n // pro leitor anunciar \"Assistente de estudos, diálogo\" antes dos\n // controles do header.\n tabIndex={-1}\n // `open` sem `showModal()` não marca o diálogo como modal; quem prende a\n // navegação é o `inert` do hook, e este atributo é o que conta isso ao\n // leitor de tela. Mesmo par usado no `Modal` e no `AlertDialog`.\n aria-modal=\"true\"\n aria-label=\"Assistente de estudos\"\n // Height uses an inline style instead of a Tailwind arbitrary\n // class so host apps don't need to add an `@source` directive\n // for Tailwind v4 to pick up an otherwise uncommon utility.\n style={\n isMinimized ? undefined : { height: 'min(720px, calc(100vh - 3rem))' }\n }\n className={cn(\n // `<dialog open>` comes with `margin: auto` by default; `m-0`\n // resets that so the `fixed` positioning below pins the panel\n // to the bottom-right as intended. The panel sits at the same\n // bottom-right corner as the FAB (the FAB is hidden while the\n // panel is open to avoid stacking).\n 'fixed bottom-6 right-6 z-40 m-0',\n // Responsive sizing: fills small viewports without overflowing,\n // yet caps at the intended desktop footprint on larger screens.\n // The panel widens when the history sidebar is visible so the\n // main chat column keeps enough horizontal room for messages.\n 'flex w-[calc(100vw-3rem)] flex-col overflow-hidden rounded-2xl p-0',\n showHistory\n ? 'max-w-[620px] sm:max-w-[640px]'\n : 'max-w-[400px] sm:max-w-[420px]',\n 'border border-background-200 bg-background shadow-2xl',\n className\n )}\n >\n <div className=\"flex items-center justify-between gap-2 bg-primary-500 px-4 py-3 text-white\">\n <div className=\"flex min-w-0 items-center gap-3\">\n <div\n aria-hidden=\"true\"\n className=\"flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-full bg-white/15 text-white\"\n >\n <RobotIcon size={20} weight=\"fill\" />\n </div>\n <div className=\"flex min-w-0 flex-col\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"truncate leading-tight text-white\"\n >\n Assistente de estudos\n </Text>\n <Text size=\"2xs\" className=\"truncate leading-tight text-white/80\">\n Tire dúvidas enquanto estuda\n </Text>\n </div>\n </div>\n <div className=\"flex items-center gap-1\">\n {!isMinimized && (\n <>\n <IconButton\n size=\"sm\"\n aria-label={\n showHistory ? 'Ocultar histórico' : 'Mostrar histórico'\n }\n onClick={() => setShowHistory((v) => !v)}\n icon={<ListIcon size={18} />}\n className={HEADER_ICON_BUTTON_CLASSES}\n />\n <IconButton\n size=\"sm\"\n aria-label=\"Nova conversa\"\n onClick={onStartNew}\n icon={<PlusIcon size={18} />}\n className={HEADER_ICON_BUTTON_CLASSES}\n />\n </>\n )}\n <IconButton\n size=\"sm\"\n aria-label={\n isMinimized ? 'Expandir assistente' : 'Minimizar assistente'\n }\n aria-expanded={!isMinimized}\n onClick={() => setIsMinimized((v) => !v)}\n icon={\n isMinimized ? <CaretUpIcon size={18} /> : <MinusIcon size={18} />\n }\n className={HEADER_ICON_BUTTON_CLASSES}\n />\n <IconButton\n size=\"sm\"\n aria-label=\"Fechar assistente\"\n onClick={onClose}\n icon={<XIcon size={18} />}\n className={HEADER_ICON_BUTTON_CLASSES}\n />\n </div>\n </div>\n\n {!isMinimized && (\n <div className=\"flex flex-1 overflow-hidden border-t border-background-200\">\n {showHistory && (\n <div className=\"w-44 shrink-0 border-r border-background-200\">\n {historySlot}\n </div>\n )}\n <div className=\"flex flex-1 flex-col\">\n {messagesSlot}\n {errorMessage && (\n <div\n role=\"alert\"\n aria-live=\"assertive\"\n className=\"border-t border-error-200 bg-error-50 px-3 py-2\"\n >\n <Text size=\"xs\" className=\"text-error-700\">\n {errorMessage}\n </Text>\n </div>\n )}\n {inputSlot}\n </div>\n </div>\n )}\n </dialog>\n );\n}\n","import { useEffect, useRef } from 'react';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\nimport ChatbotMessage from './ChatbotMessage';\nimport ChatbotTypingIndicator from './ChatbotTypingIndicator';\nimport type { ChatbotMessage as ChatbotMessageType } from '../../types/chatbot';\n\n/**\n * Props for the scrollable list of messages\n */\nexport interface ChatbotMessageListProps {\n messages: ChatbotMessageType[];\n isSending?: boolean;\n isLoading?: boolean;\n emptyHint?: string;\n className?: string;\n}\n\n/**\n * Vertical list of messages with auto-scroll to bottom on new items.\n */\nexport default function ChatbotMessageList({\n messages,\n isSending = false,\n isLoading = false,\n emptyHint = 'Comece a conversa enviando uma pergunta.',\n className,\n}: Readonly<ChatbotMessageListProps>) {\n const bottomRef = useRef<HTMLDivElement>(null);\n const didMountRef = useRef(false);\n\n useEffect(() => {\n // Skip the scroll on initial render — otherwise scrollIntoView could\n // yank the page viewport before the panel is visible. Only auto-scroll\n // on subsequent updates (new message, typing indicator changes).\n if (!didMountRef.current) {\n didMountRef.current = true;\n return;\n }\n if (bottomRef.current) {\n bottomRef.current.scrollIntoView({ behavior: 'smooth', block: 'end' });\n }\n }, [messages.length, isSending]);\n\n const showEmpty = !isLoading && messages.length === 0 && !isSending;\n\n return (\n <div\n role=\"log\"\n aria-live=\"polite\"\n aria-relevant=\"additions\"\n className={cn(\n 'flex-1 overflow-y-auto p-4 space-y-3',\n 'bg-background-50',\n className\n )}\n >\n {showEmpty && (\n <div className=\"flex h-full items-center justify-center\">\n <Text size=\"sm\" className=\"text-center text-text-400\">\n {emptyHint}\n </Text>\n </div>\n )}\n {messages.map((msg) => (\n <ChatbotMessage key={msg.id} message={msg} />\n ))}\n {isSending && (\n <div className=\"flex justify-start\">\n <ChatbotTypingIndicator />\n </div>\n )}\n <div ref={bottomRef} />\n </div>\n );\n}\n","import { RobotIcon, UserIcon } from '@phosphor-icons/react';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\nimport ChatbotContentRenderer from './ChatbotContentRenderer';\nimport {\n CHATBOT_MESSAGE_ROLES,\n type ChatbotMessage as ChatbotMessageType,\n} from '../../types/chatbot';\n\n/**\n * Props for a single message bubble\n */\nexport interface ChatbotMessageProps {\n message: ChatbotMessageType;\n className?: string;\n /** Optional classes forwarded to the assistant markdown renderer. */\n contentClassName?: string;\n}\n\n/**\n * Format a timestamp using pt-BR locale (hour and minute only)\n */\nfunction formatTimestamp(value: Date | string): string {\n const date = value instanceof Date ? value : new Date(value);\n if (Number.isNaN(date.getTime())) return '';\n return date.toLocaleTimeString('pt-BR', {\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n\n/**\n * Individual chat bubble. User messages are aligned to the right with a\n * primary background; assistant messages sit on the left in a neutral\n * background and pass through markdown / LaTeX renderers.\n */\nexport default function ChatbotMessage({\n message,\n className,\n contentClassName,\n}: Readonly<ChatbotMessageProps>) {\n const isUser = message.role === CHATBOT_MESSAGE_ROLES.USER;\n return (\n <div\n className={cn(\n 'flex w-full gap-2',\n isUser ? 'justify-end' : 'justify-start',\n className\n )}\n >\n {!isUser && (\n <div\n role=\"img\"\n aria-label=\"Mensagem do assistente\"\n className=\"flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-primary-100 text-primary-600\"\n >\n <RobotIcon size={18} weight=\"fill\" aria-hidden=\"true\" />\n </div>\n )}\n <div\n className={cn(\n 'max-w-[80%] px-4 py-2',\n isUser\n ? 'rounded-2xl rounded-br-md bg-background-200 text-text-900'\n : 'rounded-2xl rounded-bl-md bg-background-100 text-text-900'\n )}\n >\n {isUser ? (\n <Text size=\"sm\" className=\"whitespace-pre-wrap break-words\">\n {message.content}\n </Text>\n ) : (\n <ChatbotContentRenderer\n content={message.content}\n className={contentClassName}\n />\n )}\n <Text size=\"2xs\" className=\"mt-1 block text-right text-text-700\">\n {formatTimestamp(message.createdAt)}\n </Text>\n </div>\n {isUser && (\n <div\n role=\"img\"\n aria-label=\"Sua mensagem\"\n className=\"flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-primary-500 text-white\"\n >\n <UserIcon size={18} weight=\"fill\" aria-hidden=\"true\" />\n </div>\n )}\n </div>\n );\n}\n","import ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport HtmlMathRenderer from '../HtmlMathRenderer/HtmlMathRenderer';\nimport { containsMath } from '../HtmlMathRenderer/utils';\nimport { cn } from '../../utils/utils';\n\n/**\n * Props for the assistant content renderer\n */\nexport interface ChatbotContentRendererProps {\n content: string;\n className?: string;\n}\n\n/**\n * Unambiguous math detection: only treats content as math when there is a\n * `$$...$$` display block, an explicit LaTeX block\n * (`\\begin{...}...\\end{...}`), or an inline `$...$` whose inner content\n * contains an unmistakably mathematical character (backslash / caret /\n * underscore / curly brace). This avoids false positives on prose that\n * contains currency like \"R$ 20\" or \"por $20 e o livro $ 5\".\n *\n * Instead of `matchAll` with a lazy regex (which would greedily consume\n * adjacent `$`s left-to-right and could miss a valid formula following a\n * currency span on the same line, e.g. \"Preço R$ 20 e a fórmula $x^2+1$\"),\n * we collect every `$` index and probe all pairs — detection is O(N²) in\n * the worst case but N here is the count of `$` on a single line, so in\n * practice it remains linear on realistic input.\n */\nconst MATH_CHAR_PATTERN = /[\\\\^_{}]/;\n\n/**\n * Collect every unescaped `$` index in the content.\n */\nfunction collectDollarIndices(content: string): number[] {\n const result: number[] = [];\n for (let i = 0; i < content.length; i++) {\n if (content[i] === '$' && content[i - 1] !== '\\\\') {\n result.push(i);\n }\n }\n return result;\n}\n\n/**\n * Return true if any `$...$` pair spanning a single line contains a\n * math-only character.\n */\nfunction hasInlineMathSpan(content: string, indices: number[]): boolean {\n for (let i = 0; i < indices.length; i++) {\n for (let j = i + 1; j < indices.length; j++) {\n const inner = content.slice(indices[i] + 1, indices[j]);\n if (inner.includes('\\n')) break;\n if (MATH_CHAR_PATTERN.test(inner)) return true;\n }\n }\n return false;\n}\n\nfunction looksLikeMath(content: string): boolean {\n if (!containsMath(content)) return false;\n if (/\\$\\$[\\s\\S]+?\\$\\$/.test(content)) return true;\n if (/\\\\begin\\{[^}]+\\}[\\s\\S]+?\\\\end\\{[^}]+\\}/.test(content)) return true;\n return hasInlineMathSpan(content, collectDollarIndices(content));\n}\n\n/**\n * Renders a markdown string safely. When the content contains inline LaTeX\n * ($...$ or $$...$$) we fallback to `HtmlMathRenderer`, which already\n * supports math. For plain markdown we use `react-markdown` with GFM\n * (tables, task lists, strikethrough) and no raw HTML — escape by default.\n */\nexport default function ChatbotContentRenderer({\n content,\n className,\n}: Readonly<ChatbotContentRendererProps>) {\n if (looksLikeMath(content)) {\n return (\n <HtmlMathRenderer\n content={content}\n className={cn('whitespace-pre-wrap break-words', className)}\n />\n );\n }\n\n return (\n <div\n className={cn(\n 'prose prose-sm max-w-none break-words',\n // tighten prose defaults so the bubble feels compact\n '[&>*:first-child]:mt-0 [&>*:last-child]:mb-0',\n className\n )}\n >\n {/*\n SECURITY: do NOT add `rehype-raw` or any raw-HTML plugin to\n `rehypePlugins` here. Chatbot content is untrusted (LLM output) and\n must be escaped by react-markdown's default sanitization. Enabling\n raw HTML would reintroduce an XSS vector — any change requires an\n explicit security review and a dedicated sanitization pipeline.\n */}\n <ReactMarkdown remarkPlugins={[remarkGfm]}>{content}</ReactMarkdown>\n </div>\n );\n}\n","import Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\n\n/**\n * Props for the typing indicator shown while the assistant is generating\n * a reply.\n */\nexport interface ChatbotTypingIndicatorProps {\n className?: string;\n}\n\n/**\n * Three animated dots signalling \"assistant is typing\".\n * Implemented in pure Tailwind — no additional dependencies.\n */\nexport default function ChatbotTypingIndicator({\n className,\n}: Readonly<ChatbotTypingIndicatorProps>) {\n return (\n <output\n aria-label=\"Assistente digitando\"\n className={cn(\n 'inline-flex items-center gap-1 rounded-2xl rounded-bl-md bg-background-100 px-4 py-3',\n className\n )}\n >\n <Text\n as=\"span\"\n className=\"h-2 w-2 animate-bounce rounded-full bg-text-400 [animation-delay:-0.3s]\"\n />\n <Text\n as=\"span\"\n className=\"h-2 w-2 animate-bounce rounded-full bg-text-400 [animation-delay:-0.15s]\"\n />\n <Text\n as=\"span\"\n className=\"h-2 w-2 animate-bounce rounded-full bg-text-400\"\n />\n </output>\n );\n}\n","import { useCallback, useState, type KeyboardEvent } from 'react';\nimport { PaperPlaneTiltIcon } from '@phosphor-icons/react';\nimport Button from '../Button/Button';\nimport TextArea from '../TextArea/TextArea';\nimport { cn } from '../../utils/utils';\n\nconst MIN_HEIGHT = 40;\nconst MAX_HEIGHT = 120;\n\n/**\n * Props for the chatbot text input\n */\nexport interface ChatbotInputProps {\n onSend: (text: string) => void;\n disabled?: boolean;\n placeholder?: string;\n className?: string;\n}\n\n/**\n * Auto-resizing textarea + send button. Enter sends, Shift+Enter creates a\n * new line, as is standard for chat UIs.\n *\n * Uses the library's `<TextArea>` component (design-system compliant)\n * with its built-in `autoResize` — no manual DOM height manipulation.\n */\nexport default function ChatbotInput({\n onSend,\n disabled = false,\n placeholder = 'Pergunte ao assistente...',\n className,\n}: Readonly<ChatbotInputProps>) {\n const [value, setValue] = useState('');\n\n const submit = useCallback(() => {\n const trimmed = value.trim();\n if (!trimmed || disabled) return;\n onSend(trimmed);\n setValue('');\n }, [disabled, onSend, value]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n // Ignore Enter while an IME composition is in progress (e.g. typing\n // Japanese/Chinese), otherwise confirming the composition would\n // submit the message prematurely.\n if (e.nativeEvent.isComposing) return;\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n submit();\n }\n },\n [submit]\n );\n\n const isSendDisabled = disabled || value.trim().length === 0;\n\n return (\n <div\n className={cn(\n 'flex items-center gap-2 border-t border-background-200 bg-background p-3',\n className\n )}\n >\n {/* `TextArea` wraps its <textarea> in a flex column, so `flex-1`\n needs to live on this outer wrapper — passing it via\n `className` would only affect the inner element. */}\n <div className=\"flex-1 min-w-0\">\n <TextArea\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n autoResize\n minHeight={MIN_HEIGHT}\n aria-label=\"Mensagem para o assistente\"\n className=\"w-full\"\n style={{ maxHeight: MAX_HEIGHT, overflowY: 'auto' }}\n />\n </div>\n {/* Use the library's `<Button>` with `variant=\"raw\"` (same pattern\n as `ChatbotFab`) so the send action goes through the shared\n component. `raw` keeps custom sizing/shape without inheriting\n the default solid/outline/link classes. */}\n <Button\n variant=\"raw\"\n type=\"button\"\n onClick={submit}\n disabled={isSendDisabled}\n aria-label=\"Enviar mensagem\"\n className={cn(\n 'flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full',\n 'bg-primary-500 text-white transition-colors',\n 'hover:bg-primary-600',\n 'disabled:bg-background-200 disabled:text-text-500 disabled:cursor-not-allowed',\n 'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-300'\n )}\n >\n <PaperPlaneTiltIcon size={20} weight=\"fill\" />\n </Button>\n </div>\n );\n}\n","import { TrashIcon, PlusIcon } from '@phosphor-icons/react';\nimport Text from '../Text/Text';\nimport Button from '../Button/Button';\nimport IconButton from '../IconButton/IconButton';\nimport EmptyState from '../EmptyState/EmptyState';\nimport { SkeletonText } from '../Skeleton/Skeleton';\nimport { cn } from '../../utils/utils';\nimport type { ChatbotConversation } from '../../types/chatbot';\n\n/**\n * Props for the list of past chatbot conversations\n */\nexport interface ChatbotConversationListProps {\n conversations: ChatbotConversation[];\n activeConversationId: string | null;\n isLoading?: boolean;\n onSelect: (id: string) => void;\n onDelete: (id: string) => void;\n onStartNew: () => void;\n className?: string;\n}\n\n/**\n * Format the conversation timestamp in pt-BR using the short day/month\n * form (e.g. \"17/04\"), which is enough to disambiguate conversations in\n * the sidebar without overflowing the row.\n */\nfunction formatDate(value: Date | string): string {\n const d = value instanceof Date ? value : new Date(value);\n if (Number.isNaN(d.getTime())) return '';\n return d.toLocaleDateString('pt-BR', {\n day: '2-digit',\n month: '2-digit',\n });\n}\n\n/**\n * Sidebar-like drawer listing the student's past conversations. Clicking\n * a row activates it; the trash icon calls `onDelete` — the actual\n * confirmation flow (modal, toast-undo, etc.) is delegated to the\n * consumer so behaviour can be customized per host app.\n */\nexport default function ChatbotConversationList({\n conversations,\n activeConversationId,\n isLoading = false,\n onSelect,\n onDelete,\n onStartNew,\n className,\n}: Readonly<ChatbotConversationListProps>) {\n return (\n <div\n className={cn(\n 'flex h-full flex-col border-r border-background-200 bg-background',\n className\n )}\n >\n <div className=\"p-3\">\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"small\"\n onClick={onStartNew}\n iconLeft={<PlusIcon size={14} />}\n className=\"w-full\"\n >\n Nova conversa\n </Button>\n </div>\n\n <div className=\"flex-1 overflow-y-auto px-2 pb-2\">{renderBody()}</div>\n </div>\n );\n\n function renderBody() {\n if (isLoading) {\n return (\n <div className=\"space-y-2 px-2\">\n <SkeletonText />\n <SkeletonText />\n <SkeletonText />\n </div>\n );\n }\n\n if (conversations.length === 0) {\n return (\n <div className=\"mt-4\">\n <EmptyState\n title=\"Sem conversas ainda\"\n description=\"Comece sua primeira conversa com o assistente.\"\n />\n </div>\n );\n }\n\n return (\n <ul className=\"space-y-1\">\n {conversations.map((c) => {\n const isActive = c.id === activeConversationId;\n return (\n <li key={c.id}>\n <div\n className={cn(\n 'group flex items-start gap-2 rounded-md px-2 py-2 transition-colors',\n isActive ? 'bg-primary-50' : 'hover:bg-background-100'\n )}\n >\n <Button\n variant=\"raw\"\n onClick={() => onSelect(c.id)}\n className=\"flex-1 text-left\"\n >\n <Text\n size=\"sm\"\n weight=\"semibold\"\n className=\"truncate text-text-900\"\n >\n {c.title || 'Conversa sem título'}\n </Text>\n <Text size=\"2xs\" className=\"text-text-400\">\n {formatDate(c.lastMessageAt)}\n </Text>\n </Button>\n <IconButton\n size=\"sm\"\n aria-label={`Excluir conversa ${c.title || ''}`.trim()}\n onClick={() => onDelete(c.id)}\n icon={<TrashIcon size={14} />}\n />\n </div>\n </li>\n );\n })}\n </ul>\n );\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-G4NK66PM.js","../src/components/Modal/Modal.tsx","../src/components/ReadingFluencyIcons/MicIconReadingFluency.tsx","../src/components/ReadingFluencyIcons/MicOffIconReadingFluency.tsx","../src/components/ReadingFluencyIcons/StopIconReadingFluency.tsx","../src/components/ReadingFluencyIcons/PlayIconReadingFluency.tsx","../src/components/ReadingFluencyIcons/PauseIconReadingFluency.tsx","../src/components/ReadingFluencyIcons/VoiceIconReadingFluency.tsx","../src/components/ReadingFluencyIcons/CloseIconReadingFluency.tsx","../src/components/CloseButtonReadingFluency/CloseButtonReadingFluency.tsx","../src/hooks/useMicrophonePermission.ts","../src/hooks/useBodyScrollLock.ts"],"names":["jsx","jsxs"],"mappings":"AAAA;AACE;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACE;AACA;AACA;AACF,sDAA4B;AAC5B;AACE;AACA;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACA;AC5BA;AAGE;AACA;AACA;AACA;AACA;AAAA,8BACK;AACP,qDAAsB;AD4BtB;AACA;AElBI,+CAAA;AAbG,IAAM,sBAAA,EAAqD,CAAC;AAAA,EACjE,KAAA,EAAO,EAAA;AAAA,EACP;AACF,CAAA,EAAA,mBACE,6BAAA;AAAA,EAAC,KAAA;AAAA,EAAA;AAAA,IACC,KAAA,EAAM,4BAAA;AAAA,IACN,KAAA,EAAO,IAAA;AAAA,IACP,MAAA,EAAQ,IAAA;AAAA,IACR,OAAA,EAAQ,WAAA;AAAA,IACR,IAAA,EAAK,MAAA;AAAA,IACL,SAAA;AAAA,IACA,aAAA,EAAY,MAAA;AAAA,IAEZ,QAAA,kBAAA,6BAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,CAAA,EAAE,k0CAAA;AAAA,QACF,IAAA,EAAK;AAAA,MAAA;AAAA,IACP;AAAA,EAAA;AACF,CAAA;AAEF,qBAAA,CAAsB,YAAA,EAAc,uBAAA;AFqCpC;AACA;AG5CI;AAbG,IAAM,yBAAA,EAAwD,CAAC;AAAA,EACpE,KAAA,EAAO,EAAA;AAAA,EACP;AACF,CAAA,EAAA,mBACEA,6BAAAA;AAAA,EAAC,KAAA;AAAA,EAAA;AAAA,IACC,KAAA,EAAM,4BAAA;AAAA,IACN,KAAA,EAAO,IAAA;AAAA,IACP,MAAA,EAAQ,IAAA;AAAA,IACR,OAAA,EAAQ,WAAA;AAAA,IACR,IAAA,EAAK,MAAA;AAAA,IACL,SAAA;AAAA,IACA,aAAA,EAAY,MAAA;AAAA,IAEZ,QAAA,kBAAAA,6BAAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,CAAA,EAAE,w8DAAA;AAAA,QACF,IAAA,EAAK;AAAA,MAAA;AAAA,IACP;AAAA,EAAA;AACF,CAAA;AAEF,wBAAA,CAAyB,YAAA,EAAc,0BAAA;AH+DvC;AACA;AItEI;AAbG,IAAM,uBAAA,EAAsD,CAAC;AAAA,EAClE,KAAA,EAAO,EAAA;AAAA,EACP;AACF,CAAA,EAAA,mBACEA,6BAAAA;AAAA,EAAC,KAAA;AAAA,EAAA;AAAA,IACC,KAAA,EAAM,4BAAA;AAAA,IACN,KAAA,EAAO,IAAA;AAAA,IACP,MAAA,EAAQ,IAAA;AAAA,IACR,OAAA,EAAQ,WAAA;AAAA,IACR,IAAA,EAAK,MAAA;AAAA,IACL,SAAA;AAAA,IACA,aAAA,EAAY,MAAA;AAAA,IAEZ,QAAA,kBAAAA,6BAAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,CAAA,EAAE,6nBAAA;AAAA,QACF,IAAA,EAAK;AAAA,MAAA;AAAA,IACP;AAAA,EAAA;AACF,CAAA;AAEF,sBAAA,CAAuB,YAAA,EAAc,wBAAA;AJyFrC;AACA;AKhGI;AAbG,IAAM,uBAAA,EAAsD,CAAC;AAAA,EAClE,KAAA,EAAO,EAAA;AAAA,EACP;AACF,CAAA,EAAA,mBACEA,6BAAAA;AAAA,EAAC,KAAA;AAAA,EAAA;AAAA,IACC,KAAA,EAAM,4BAAA;AAAA,IACN,KAAA,EAAO,IAAA;AAAA,IACP,MAAA,EAAQ,IAAA;AAAA,IACR,OAAA,EAAQ,eAAA;AAAA,IACR,IAAA,EAAK,MAAA;AAAA,IACL,SAAA;AAAA,IACA,aAAA,EAAY,MAAA;AAAA,IAEZ,QAAA,kBAAAA,6BAAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,CAAA,EAAE,sqCAAA;AAAA,QACF,IAAA,EAAK,SAAA;AAAA,QACL,MAAA,EAAO,SAAA;AAAA,QACP,WAAA,EAAa,CAAA;AAAA,QACb,cAAA,EAAe,OAAA;AAAA,QACf,aAAA,EAAc;AAAA,MAAA;AAAA,IAChB;AAAA,EAAA;AACF,CAAA;AAEF,sBAAA,CAAuB,YAAA,EAAc,wBAAA;ALmHrC;AACA;AMlJA;AAwBM;AAhBC,IAAM,wBAAA,EAAuD,CAAC;AAAA,EACnE,KAAA,EAAO,EAAA;AAAA,EACP;AACF,CAAA,EAAA,GAAM;AAEJ,EAAA,MAAM,OAAA,EAAS,CAAA,2BAAA,EAA8B,0BAAA,CAAM,CAAE,UAAA,CAAW,GAAA,EAAK,EAAE,CAAC,CAAA,CAAA;AAEtE,EAAA;AAAC,IAAA;AAAA,IAAA;AACO,MAAA;AACC,MAAA;AACC,MAAA;AACA,MAAA;AACH,MAAA;AACL,MAAA;AACY,MAAA;AAEZ,MAAA;AAAA,wBAAA;AAAC,UAAA;AAAA,UAAA;AACK,YAAA;AACM,YAAA;AACR,YAAA;AACA,YAAA;AACI,YAAA;AACC,YAAA;AACF,YAAA;AAEL,YAAA;AAA2B,8BAAA;AACnB,8BAAA;AAA6oC,YAAA;AAAA,UAAA;AACvpC,QAAA;AACAA,wBAAAA;AAAC,UAAA;AAAA,UAAA;AACG,YAAA;AACG,YAAA;AAAA,UAAA;AACP,QAAA;AACAA,wBAAAA;AAAC,UAAA;AAAA,UAAA;AACG,YAAA;AACG,YAAA;AACe,YAAA;AAAA,UAAA;AACtB,QAAA;AAAA,MAAA;AAAA,IAAA;AACF,EAAA;AAEJ;AACsC;ANyJqC;AACA;AO5LzE;AAJmE;AACnE,EAAA;AACA,EAAA;AAEAC;AAAC,EAAA;AAAA,EAAA;AACO,IAAA;AACS,IAAA;AAC2B,IAAA;AAClC,IAAA;AACH,IAAA;AACL,IAAA;AACY,IAAA;AAEZ,IAAA;AAAAD,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AACAA,sBAAAA;AAAC,QAAA;AAAA,QAAA;AACG,UAAA;AACG,UAAA;AAAA,QAAA;AACP,MAAA;AAAA,IAAA;AAAA,EAAA;AACF;AAEoC;APkPqC;AACA;AQxU5C;AAkCzB;AAhB+D;AAC5D,EAAA;AACP,EAAA;AACI;AAEgE,EAAA;AAElEC,EAAAA;AAAC,IAAA;AAAA,IAAA;AACO,MAAA;AACC,MAAA;AACC,MAAA;AACA,MAAA;AACH,MAAA;AACL,MAAA;AACY,MAAA;AAEZ,MAAA;AAIE,wBAAA;AAAAD,0BAAAA;AAAC,YAAA;AAAA,YAAA;AACG,cAAA;AACG,cAAA;AACE,cAAA;AACM,cAAA;AACE,cAAA;AAAA,YAAA;AACjB,UAAA;AAEAA,0BAAAA;AAAC,YAAA;AAAA,YAAA;AACG,cAAA;AACG,cAAA;AAAA,YAAA;AACP,UAAA;AACF,QAAA;AAIEC,wBAAAA;AAAC,UAAA;AAAA,UAAA;AACK,YAAA;AACF,YAAA;AACA,YAAA;AACI,YAAA;AACC,YAAA;AACK,YAAA;AACc,YAAA;AAE1B,YAAA;AAAiC,8BAAA;AACjCD,8BAAAA;AAAC,gBAAA;AAAA,gBAAA;AACI,kBAAA;AACE,kBAAA;AACE,kBAAA;AACA,kBAAA;AAAA,gBAAA;AACT,cAAA;AACiB,8BAAA;AACgB,8BAAA;AACJ,8BAAA;AAC7BA,8BAAAA;AAAC,gBAAA;AAAA,gBAAA;AACM,kBAAA;AACE,kBAAA;AAAA,gBAAA;AACT,cAAA;AACAA,8BAAAA;AAAC,gBAAA;AAAA,gBAAA;AACM,kBAAA;AACD,kBAAA;AACG,kBAAA;AAAA,gBAAA;AACT,cAAA;AACAA,8BAAAA;AAAC,gBAAA;AAAA,gBAAA;AACI,kBAAA;AACE,kBAAA;AACE,kBAAA;AACA,kBAAA;AAAA,gBAAA;AACT,cAAA;AACiB,8BAAA;AACgB,8BAAA;AACJ,8BAAA;AAC7BA,8BAAAA;AAAC,gBAAA;AAAA,gBAAA;AACM,kBAAA;AACE,kBAAA;AAAA,gBAAA;AACT,cAAA;AACAA,8BAAAA;AAAC,gBAAA;AAAA,gBAAA;AACM,kBAAA;AACD,kBAAA;AACG,kBAAA;AAAA,gBAAA;AACT,cAAA;AACAA,8BAAAA;AAAC,gBAAA;AAAA,gBAAA;AACM,kBAAA;AACF,kBAAA;AACC,kBAAA;AACG,kBAAA;AAAA,gBAAA;AACT,cAAA;AAAA,YAAA;AAAA,UAAA;AAEJ,QAAA;AAAA,MAAA;AAAA,IAAA;AACF,EAAA;AAEJ;AACsC;ARkVqC;AACA;ASlc1B;AA6D3C;AA7BJ;AAQuC;AAKrC,EAAA;AACa,IAAA;AACX,IAAA;AACO,IAAA;AACmB,IAAA;AACvB,IAAA;AAILA,EAAAA;AAAC,IAAA;AAAA,IAAA;AACC,MAAA;AACA,MAAA;AACY,MAAA;AACyB,MAAA;AACjC,MAAA;AAE2B,MAAA;AAAU,IAAA;AAC3C,EAAA;AAEJ;AACwC;ATyZmC;AACA;AU1d1B;AAoCwB;AACI,EAAA;AAE3D,EAAA;AAC6C,IAAA;AACrB,IAAA;AACb,MAAA;AACvB,MAAA;AACF,IAAA;AAIwB,IAAA;AACC,IAAA;AACL,MAAA;AAClB,MAAA;AACF,IAAA;AAEa,IAAA;AAC6B,IAAA;AAEpB,IAAA;AACd,MAAA;AACR,IAAA;AAIoB,IAAA;AACH,MAAA;AACA,MAAA;AACuC,MAAA;AAEE,MAAA;AAE3C,IAAA;AACmB,MAAA;AAC/B,IAAA;AAEU,IAAA;AACF,MAAA;AAC6B,MAAA;AACxC,IAAA;AACG,EAAA;AAE6C,EAAA;AACW,IAAA;AACrB,IAAA;AACb,MAAA;AAChB,MAAA;AACT,IAAA;AACI,IAAA;AACgE,MAAA;AAChB,MAAA;AAC/B,MAAA;AACZ,MAAA;AACO,IAAA;AAO+C,MAAA;AAG7C,MAAA;AAEwB,MAAA;AACjC,MAAA;AACT,IAAA;AACG,EAAA;AAEE,EAAA;AACL,IAAA;AACsB,IAAA;AACE,IAAA;AACqB,IAAA;AAC7C,IAAA;AACF,EAAA;AACF;AVka2E;AACA;AWvhBjD;AAaG;AAEb;AACO;AACI;AAEH;AAGyB,EAAA;AAER,EAAA;AACI,EAAA;AAEZ,EAAA;AAGP,EAAA;AAKsB,IAAA;AAEgB,IAAA;AAEhB,IAAA;AAC/B,IAAA;AACW,IAAA;AAAA;AAAA;AAAA;AAIC,aAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA;AAMQ,IAAA;AACnC,EAAA;AACF;AAE0B;AACO,EAAA;AACI,EAAA;AAEyB,EAAA;AAC/C,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;AXuf2E;AACA;AC/X3D;AAtKK;AACf,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACN;AAsFe;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;AACH;AACM,EAAA;AAC0B,EAAA;AAEC,EAAA;AACzB,EAAA;AACO,EAAA;AAEX,EAAA;AAEiB,EAAA;AAEnC,EAAA;AAEyB,EAAA;AACN,EAAA;AACnB,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AAIsC,EAAA;AAGN,EAAA;AACd,oBAAA;AACA,IAAA;AACuD,MAAA;AACvE,IAAA;AACF,EAAA;AAG4B,EAAA;AAET,IAAA;AACZ,MAAA;AAAA,MAAA;AACM,QAAA;AACK,QAAA;AACC,QAAA;AACM,QAAA;AACN,QAAA;AACP,QAAA;AAGJ,QAAA;AAAe,0BAAA;AAEV,YAAA;AAAA,YAAA;AACU,cAAA;AAEM,cAAA;AACL,cAAA;AACC,cAAA;AAEM,cAAA;AAAA,YAAA;AAGvB,UAAA;AAGe,0BAAA;AAGI,YAAA;AACZ,cAAA;AAAA,cAAA;AACM,gBAAA;AACY,gBAAA;AACP,gBAAA;AAAA,cAAA;AAEd,YAAA;AAIFA,4BAAAA;AAAC,cAAA;AAAA,cAAA;AACK,gBAAA;AACC,gBAAA;AACK,gBAAA;AAET,gBAAA;AAAA,cAAA;AACH,YAAA;AAIEA,YAAAA;AAAC,cAAA;AAAA,cAAA;AACM,gBAAA;AACK,gBAAA;AAET,gBAAA;AAAA,cAAA;AACH,YAAA;AAKe,YAAA;AACL,cAAA;AACoC,gBAAA;AACN,gBAAA;AAClB,gBAAA;AACqB,gBAAA;AAC9B,gBAAA;AAELA,kBAAAA;AAAC,oBAAA;AAAA,oBAAA;AACS,sBAAA;AACD,sBAAA;AACF,sBAAA;AACK,sBAAA;AACD,sBAAA;AAEO,sBAAA;AAAA,oBAAA;AAClB,kBAAA;AAEJ,gBAAA;AAEEA,gBAAAA;AAAC,kBAAA;AAAA,kBAAA;AAC2B,oBAAA;AAChB,oBAAA;AACK,oBAAA;AACT,oBAAA;AACA,oBAAA;AAAA,kBAAA;AACR,gBAAA;AAED,cAAA;AAEDA,cAAAA;AAAC,gBAAA;AAAA,gBAAA;AACS,kBAAA;AACD,kBAAA;AACF,kBAAA;AACK,kBAAA;AACD,kBAAA;AAEO,kBAAA;AAAA,gBAAA;AAClB,cAAA;AAEJ,YAAA;AAEJ,UAAA;AAAA,QAAA;AAAA,MAAA;AAEJ,IAAA;AAEJ,EAAA;AAIiB,EAAA;AACZ,IAAA;AAAA,IAAA;AACM,MAAA;AACK,MAAA;AACC,MAAA;AACM,MAAA;AACN,MAAA;AACP,MAAA;AAGJ,MAAA;AAAe,wBAAA;AACc,0BAAA;AAIzBA,UAAAA;AAAC,YAAA;AAAA,YAAA;AACU,cAAA;AAkBM,cAAA;AACL,cAAA;AACC,cAAA;AAEM,cAAA;AAAA,YAAA;AACnB,UAAA;AAEJ,QAAA;AAIEA,QAAAA;AAAC,UAAA;AAAA,UAAA;AACY,YAAA;AACT,cAAA;AACA,cAAA;AACF,YAAA;AAEAA,YAAAA;AAAC,cAAA;AAAA,cAAA;AACY,gBAAA;AACT,kBAAA;AAEE,kCAAA;AACJ,gBAAA;AAEC,gBAAA;AAAA,cAAA;AACH,YAAA;AAAA,UAAA;AACF,QAAA;AAKe,QAAA;AAA2C,MAAA;AAAA,IAAA;AAGhE,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;AACiB,EAAA;AACjB,EAAA;AAEhB,EAAA;AAEmB,EAAA;AAEb,EAAA;AACR,IAAA;AACN,IAAA;AACE,EAAA;AAEO,EAAA;AAGS,IAAA;AACtB,oBAAA;AACpB,EAAA;AAEmC,EAAA;AACG,IAAA;AACjB,oBAAA;AACrB,EAAA;AAEmD,EAAA;AAC7B,EAAA;AACO,EAAA;AAEX,EAAA;AAGD,EAAA;AACZ,IAAA;AAAA,IAAA;AACM,MAAA;AAIK,MAAA;AACN,MAAA;AACa,MAAA;AACN,MAAA;AACD,MAAA;AAGV,MAAA;AAAe,wBAAA;AACG,0BAAA;AAIhBA,0BAAAA;AAAC,YAAA;AAAA,YAAA;AACM,cAAA;AACD,cAAA;AACM,cAAA;AACC,cAAA;AAAA,YAAA;AACb,UAAA;AAEgB,0BAAA;AAGlB,QAAA;AAGe,wBAAA;AACgB,0BAAA;AAId,0BAAA;AAGO,4BAAA;AAIA,4BAAA;AAMtB,UAAA;AAEAA,0BAAAA;AAAC,YAAA;AAAA,YAAA;AACS,cAAA;AACH,cAAA;AACK,cAAA;AACD,cAAA;AACV,cAAA;AAAA,YAAA;AAED,UAAA;AAEAA,0BAAAA;AAAC,YAAA;AAAA,YAAA;AACS,cAAA;AACH,cAAA;AACI,cAAA;AACV,cAAA;AAAA,YAAA;AAED,UAAA;AAGAA,0BAAAA;AAAC,YAAA;AAAA,YAAA;AACM,cAAA;AACI,cAAA;AACD,cAAA;AACE,cAAA;AAEM,cAAA;AAEhB,YAAA;AACF,UAAA;AACF,QAAA;AAAA,MAAA;AAAA,IAAA;AAEJ,EAAA;AAEJ;AAEE;AAmCiC;AACjC,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACgB,EAAA;AACR,EAAA;AAC4B;AACd,EAAA;AAC0B,EAAA;AAEC,EAAA;AACzB,EAAA;AACO,EAAA;AAEX,EAAA;AAGH,EAAA;AACZ,IAAA;AAAA,IAAA;AACM,MAAA;AAEK,MAAA;AACN,MAAA;AACa,MAAA;AACN,MAAA;AACD,MAAA;AAGV,MAAA;AAAe,wBAAA;AACG,0BAAA;AAIA,0BAAA;AAGlB,QAAA;AAGe,wBAAA;AACbA,0BAAAA;AAAC,YAAA;AAAA,YAAA;AACK,cAAA;AACC,cAAA;AACK,cAAA;AAET,cAAA;AAAA,YAAA;AACH,UAAA;AAEAA,0BAAAA;AAAC,YAAA;AAAA,YAAA;AACS,cAAA;AACH,cAAA;AACK,cAAA;AACD,cAAA;AACV,cAAA;AAAA,YAAA;AAED,UAAA;AAEAA,0BAAAA;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;AACS,EAAA;AACR,EAAA;AACvB,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;AACE,EAAA;AACA,EAAA;AACN,EAAA;AAC8B,EAAA;AAGpB,EAAA;AAEH,EAAA;AACzB,EAAA;AACO,EAAA;AAGf,EAAA;AACuB,IAAA;AACb,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;AAOU,sBAAA;AACjB,IAAA;AACF,EAAA;AAE6D,EAAA;AACpC,IAAA;AACoC,IAAA;AACJ,IAAA;AACN,IAAA;AACK,IAAA;AACtB,IAAA;AAClC,EAAA;AAEoB,EAAA;AAE6C,EAAA;AAGhD,EAAA;AACZ,IAAA;AAAA,IAAA;AACM,MAAA;AAEK,MAAA;AACN,MAAA;AACO,MAAA;AACA,MAAA;AACD,MAAA;AAGV,MAAA;AAAe,wBAAA;AACG,0BAAA;AAKhBA,0BAAAA;AAAC,YAAA;AAAA,YAAA;AACW,cAAA;AACE,cAAA;AAGV,cAAA;AAAC,gBAAA;AAAA,gBAAA;AAEiB,kBAAA;AACN,kBAAA;AAAA,gBAAA;AAFL,gBAAA;AAIR,cAAA;AAAA,YAAA;AACH,UAAA;AAGe,0BAAA;AACbA,4BAAAA;AAAC,cAAA;AAAA,cAAA;AACM,gBAAA;AACA,gBAAA;AACG,gBAAA;AAE2B,gBAAA;AAGH,gBAAA;AAEjB,gBAAA;AACK,kBAAA;AACF,kBAAA;AAClB,gBAAA;AAEY,gBAAA;AAAW,cAAA;AACzB,YAAA;AAEAA,4BAAAA;AAAC,cAAA;AAAA,cAAA;AACM,gBAAA;AACI,gBAAA;AACE,gBAAA;AACwB,gBAAA;AAC3B,gBAAA;AACE,gBAAA;AAGP,gBAAA;AAEiC,cAAA;AAEtC,YAAA;AAEAA,4BAAAA;AAAC,cAAA;AAAA,cAAA;AACM,gBAAA;AACI,gBAAA;AACE,gBAAA;AACH,gBAAA;AACE,gBAAA;AAEVA,gBAAAA;AAAC,kBAAA;AAAA,kBAAA;AACW,oBAAA;AACqB,oBAAA;AAAA,kBAAA;AACjC,gBAAA;AAAA,cAAA;AACF,YAAA;AAEgB,4BAAA;AAGlB,UAAA;AACF,QAAA;AAGe,wBAAA;AACbA,0BAAAA;AAAC,YAAA;AAAA,YAAA;AACS,cAAA;AACH,cAAA;AACK,cAAA;AACD,cAAA;AACV,cAAA;AAAA,YAAA;AAED,UAAA;AAEqC,0BAAA;AAGvC,QAAA;AAAA,MAAA;AAAA,IAAA;AAEJ,EAAA;AAEJ;AAEE;AAkCkC;AAClC,EAAA;AACA,EAAA;AACQ,EAAA;AACM,EAAA;AACE,EAAA;AACL,EAAA;AAC0B;AACf,EAAA;AAC0B,EAAA;AAEC,EAAA;AACzB,EAAA;AACO,EAAA;AAEX,EAAA;AAGH,EAAA;AACZ,IAAA;AAAA,IAAA;AACM,MAAA;AAEK,MAAA;AACN,MAAA;AACa,MAAA;AACN,MAAA;AACD,MAAA;AAEK,MAAA;AACG,wBAAA;AAIhBA,wBAAAA;AAAC,UAAA;AAAA,UAAA;AACM,YAAA;AACD,YAAA;AACM,YAAA;AACC,YAAA;AAAA,UAAA;AACb,QAAA;AAEe,wBAAA;AACbA,0BAAAA;AAAC,YAAA;AAAA,YAAA;AACK,cAAA;AACC,cAAA;AACK,cAAA;AAET,cAAA;AAAA,YAAA;AACH,UAAA;AACAA,0BAAAA;AAAC,YAAA;AAAA,YAAA;AACM,cAAA;AACK,cAAA;AAET,cAAA;AAAA,YAAA;AACH,UAAA;AACF,QAAA;AACF,MAAA;AAAA,IAAA;AAEJ,EAAA;AAEJ;AACyC;ADiMkC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-G4NK66PM.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\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}: ModalProps) => {\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 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 const dialogResetClasses = 'p-0 m-0 border-none outline-none static';\n const modalClasses = cn(\n baseClasses,\n sizeClasses,\n dialogResetClasses,\n className\n );\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={titleId}\n aria-modal=\"true\"\n open\n >\n {/* Header simples com XIcon */}\n <div className=\"flex justify-end p-6 pb-0\">\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=\"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 aria-label=\"Fechar modal\"\n >\n <XIcon size={18} />\n </button>\n )}\n </div>\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 size=\"lg\"\n className=\"font-semibold text-text-950 text-center\"\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 </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={titleId}\n aria-modal=\"true\"\n open\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-6\">\n <h2 id={titleId} className=\"text-lg font-semibold text-text-950\">\n {title}\n </h2>\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 * Exceção deliberada ao contrato do print.css, que manda pôr\n * `data-print-hide` no CONTAINER e não no botão: aqui o container\n * é o header, e ele carrega o <h2> do título, que É conteúdo do\n * relatório. Marcá-lo apagaria o título junto. A razão do contrato\n * — colapsar o espaçamento do flex — não se aplica: o header usa\n * `justify-between`, sem `gap`, então o título simplesmente ocupa\n * a linha sozinho.\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=\"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 aria-label=\"Fechar modal\"\n >\n <XIcon size={18} />\n </button>\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 </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","import type { FC } from 'react';\nimport type { ReadingFluencyIconProps } from './types';\n\n/**\n * Microfone (ligado) — tema Reading Fluency. Cor marrom `#604903` (fixa da arte).\n * `aria-hidden` por ser decorativo; quem usa em botão deve prover o rótulo.\n */\nexport const MicIconReadingFluency: FC<ReadingFluencyIconProps> = ({\n size = 24,\n className,\n}) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n className={className}\n aria-hidden=\"true\"\n >\n <path\n d=\"M19.0899 9.64246C19.2722 9.12736 19.8996 8.87431 20.3966 9.09265C21.0667 9.38732 21.0012 10.0389 20.9688 10.6317C20.902 11.8547 20.6668 12.9383 20.1905 14.0663C19.8435 14.8412 19.4182 15.5484 18.8468 16.1815C17.3308 17.8298 15.2311 18.8217 12.9952 18.9471L13.0011 20.2665C13.0021 20.5743 13.0211 20.8906 12.9669 21.1962C12.9158 21.6151 12.4185 22.0384 11.9796 21.996C10.9121 21.8926 11.0195 20.9985 11.0206 20.3046L11.0235 18.955C6.82821 18.5619 3.81573 15.9926 3.14951 11.745C3.07466 11.2676 2.95457 10.2389 3.04502 9.78601C3.07111 9.6531 3.12649 9.52768 3.20713 9.41883C3.38516 9.17631 3.6094 9.06793 3.89658 9.02136C4.04493 9.0039 4.19567 9.02105 4.33603 9.07215C4.61331 9.16908 4.83184 9.38643 4.93076 9.66297C5.03905 9.96346 4.99607 10.5347 5.03037 10.8768C5.15593 12.1285 5.5318 13.3453 6.254 14.3856C8.21912 17.2126 12.5465 17.6029 15.505 16.2762C17.7033 15.2904 18.876 12.9902 18.9737 10.66C19.0011 10.3277 18.9782 9.95865 19.0899 9.64246ZM11.6446 2.02136C13.3014 1.8719 15.0753 2.55335 16.0636 3.90711C17.3039 5.60658 16.9297 7.57787 16.9933 9.51258C17.094 12.5795 15.5804 14.6964 12.4269 14.9735C11.0254 15.0315 9.70841 14.768 8.61631 13.829C7.65801 13.0048 7.11544 11.7587 7.04014 10.5096C6.99793 9.80921 7.02898 9.06921 7.02061 8.36316C6.99942 6.57705 6.92635 5.08207 8.18369 3.62488C9.06989 2.59789 10.3004 2.10617 11.6446 2.02136Z\"\n fill=\"#604903\"\n />\n </svg>\n);\nMicIconReadingFluency.displayName = 'MicIconReadingFluency';\n","import type { FC } from 'react';\nimport type { ReadingFluencyIconProps } from './types';\n\n/**\n * Microfone desligado — tema Reading Fluency. Cor marrom `#604903` (fixa da arte).\n * `aria-hidden` por ser decorativo; quem usa em botão deve prover o rótulo.\n */\nexport const MicOffIconReadingFluency: FC<ReadingFluencyIconProps> = ({\n size = 24,\n className,\n}) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n className={className}\n aria-hidden=\"true\"\n >\n <path\n d=\"M2.92138 2.00096C3.51243 1.97398 3.79735 2.38941 4.18114 2.77342L5.24071 3.83787L6.43603 5.03221C6.65214 5.24803 6.95078 5.53088 7.14013 5.75877C7.41612 4.73636 7.69377 4.07412 8.47899 3.31639C10.3488 1.51221 13.8942 1.57682 15.686 3.45994C16.928 4.74071 17.0078 6.30724 16.9936 7.9658C16.9725 10.4436 17.2409 12.039 15.2905 13.9053C15.4504 14.0281 15.7475 14.3379 15.897 14.4892C16.2051 14.7986 16.5109 15.1115 16.813 15.4267C18.1001 14.1651 18.7625 12.8312 18.9448 11.0283C19.0123 10.3609 18.8665 9.42655 19.5864 9.09959C19.8254 8.99225 20.0977 8.98518 20.3423 9.07908C20.5949 9.17395 20.7975 9.3682 20.9038 9.61619C21.022 9.89823 20.9779 10.3016 20.9614 10.6054C20.8956 11.8206 20.6659 12.8698 20.2183 13.999C19.8981 14.6879 19.5623 15.3325 19.0698 15.9189C18.8077 16.231 18.5097 16.5316 18.2339 16.8369C18.4118 16.9867 18.6925 17.2869 18.8696 17.4648L20.06 18.6582L21.1362 19.7285C21.6674 20.2521 22.3111 20.706 21.8325 21.541C21.6184 21.9356 20.8757 22.1607 20.5151 21.8642C19.9124 21.3681 19.3263 20.7287 18.7759 20.1748L15.3921 16.792L7.33251 8.7324L4.19774 5.59861C3.58409 4.98783 2.96253 4.37668 2.35497 3.75975C2.18785 3.59003 2.05404 3.38354 2.01317 3.14451C1.9702 2.89156 2.0312 2.63133 2.18212 2.42381C2.37884 2.15194 2.60825 2.05338 2.92138 2.00096ZM4.17724 9.09861C4.35579 9.08613 4.56672 9.14867 4.72313 9.2324C5.3088 9.54598 5.20095 10.4279 5.24853 11.0058C5.29609 11.546 5.39785 12.08 5.55224 12.5986C6.34419 15.2155 8.29261 16.6266 10.8843 16.9746C11.3668 17.0394 12.0198 16.9345 12.4526 17.1758C12.6687 17.2964 12.8225 17.4863 12.8872 17.7304C12.9826 18.0903 12.9844 20.6384 12.938 21.0605C12.9203 21.2214 12.8826 21.3792 12.8032 21.5205C12.6402 21.8103 12.3689 21.9179 12.0708 21.998C11.8022 22.0146 11.5208 21.9284 11.3276 21.7314C11.1975 21.5978 11.1064 21.4285 11.0659 21.2441C11.0016 20.9629 11.0318 19.3686 11.0308 18.9804C9.4007 18.7722 8.13113 18.4599 6.73388 17.4775C4.4657 15.8888 3.33397 13.1768 3.29052 10.415C3.27955 9.71664 3.39629 9.22846 4.17724 9.09861Z\"\n fill=\"#604903\"\n />\n </svg>\n);\nMicOffIconReadingFluency.displayName = 'MicOffIconReadingFluency';\n","import type { FC } from 'react';\nimport type { ReadingFluencyIconProps } from './types';\n\n/**\n * Parar (quadrado arredondado) — tema Reading Fluency. Cor marrom `#604903` (fixa da\n * arte). `aria-hidden` por ser decorativo; quem usa em botão deve prover o rótulo.\n */\nexport const StopIconReadingFluency: FC<ReadingFluencyIconProps> = ({\n size = 24,\n className,\n}) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n className={className}\n aria-hidden=\"true\"\n >\n <path\n d=\"M9.19373 3.02192C9.23924 3.01968 9.28477 3.01795 9.3303 3.01669C10.3859 2.98615 11.5022 3.00736 12.5695 3.00486C14.1845 3.02035 15.7972 2.94773 17.3862 3.2905C20.5781 3.97907 20.9146 6.66832 20.9808 9.41075C20.9978 10.5335 21.003 11.6565 20.996 12.7793C20.9942 14.8218 21.144 17.7223 19.7633 19.3629C18.5786 20.7708 16.5405 20.9308 14.8126 20.9714C13.7196 21.0046 12.4391 21.0064 11.3323 20.9895C9.21141 20.9573 6.22451 21.2041 4.55526 19.6974C3.28925 18.5546 3.06985 16.632 3.02355 15.0153C2.99244 13.9292 2.99703 12.6416 3.00958 11.5439C3.03437 9.37514 2.76331 6.22534 4.32955 4.52291C5.55279 3.19327 7.51307 3.08323 9.19373 3.02192Z\"\n fill=\"#604903\"\n />\n </svg>\n);\nStopIconReadingFluency.displayName = 'StopIconReadingFluency';\n","import type { FC } from 'react';\nimport type { ReadingFluencyIconProps } from './types';\n\n/**\n * Reproduzir (triângulo dourado com contorno creme) — tema Reading Fluency. Cores fixas\n * da arte (`#F9CB3B` + `#FDEFC4`). `aria-hidden`; quem usa em botão dá o rótulo.\n */\nexport const PlayIconReadingFluency: FC<ReadingFluencyIconProps> = ({\n size = 30,\n className,\n}) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0.5 0.5 29 29\"\n fill=\"none\"\n className={className}\n aria-hidden=\"true\"\n >\n <path\n d=\"M9.69336 3.00977C10.4688 2.9555 11.2352 3.14459 11.7656 3.30371C12.3241 3.47126 12.8823 3.69117 13.2188 3.81738L13.2266 3.81934L13.2334 3.82227C16.6576 5.1362 19.8422 7.04365 22.6582 9.45996L23.2168 9.94922L23.2227 9.95508C23.672 10.3617 24.7284 11.2995 25.2793 12.2227L25.2871 12.2354L25.2939 12.2471C26.0279 13.5184 26.1156 14.9454 25.8896 16.1572L25.8408 16.3965C25.4502 18.1299 24.2837 19.1044 23.6602 19.6924C22.0107 21.2479 20.2264 22.4993 18.4365 23.6328L18.4248 23.6406C16.5421 24.8144 14.5418 25.7695 12.46 26.4893L12.4512 26.4932L12.4414 26.4961C12.05 26.6272 11.243 26.9066 10.4883 26.9756L10.4893 26.9766C10.4871 26.9768 10.4846 26.9764 10.4824 26.9766C10.4811 26.9767 10.4798 26.9774 10.4785 26.9775L10.4775 26.9766C9.01305 27.1114 7.57551 26.6212 6.48535 25.6455L6.48145 25.6416C6.03578 25.2405 5.5503 24.6967 5.20605 24.0059C4.77418 23.1392 4.5478 21.9412 4.41113 21.0146C4.26294 20.0099 4.17714 18.9939 4.12598 18.332L4.12695 18.3311C3.87395 15.2113 4.00141 12.0703 4.50684 8.98438L4.50781 8.97559C4.58505 8.51619 4.69474 7.82631 4.87891 7.15918C5.05634 6.51655 5.3614 5.66072 5.96387 4.95801C6.91568 3.8481 8.10898 3.14206 9.66699 3.01172L9.67969 3.01074L9.69336 3.00977Z\"\n fill=\"#F9CB3B\"\n stroke=\"#FDEFC4\"\n strokeWidth={4}\n strokeLinejoin=\"round\"\n strokeLinecap=\"round\"\n />\n </svg>\n);\nPlayIconReadingFluency.displayName = 'PlayIconReadingFluency';\n","import { useId, type FC } from 'react';\nimport type { ReadingFluencyIconProps } from './types';\n\n/**\n * Pausar (duas barras douradas com contorno creme) — tema Reading Fluency. Cores fixas da\n * arte (`#F9CB3B` + `#FDEFC4`). O contorno usa um `mask` com id único (via\n * `useId`) pra não colidir entre instâncias. `aria-hidden`; rótulo vem de quem usa.\n */\nexport const PauseIconReadingFluency: FC<ReadingFluencyIconProps> = ({\n size = 30,\n className,\n}) => {\n // id único (sem \":\") pra o `mask` não colidir entre instâncias.\n const maskId = `reading-fluency-pause-mask-${useId().replaceAll(':', '')}`;\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0.5 0.5 29 29\"\n fill=\"none\"\n className={className}\n aria-hidden=\"true\"\n >\n <mask\n id={maskId}\n maskUnits=\"userSpaceOnUse\"\n x=\"0\"\n y=\"0\"\n width=\"30\"\n height=\"30\"\n fill=\"black\"\n >\n <rect fill=\"white\" x=\"0\" y=\"0\" width=\"30\" height=\"30\" />\n <path d=\"M8.35951 5.00949C10.6501 4.92814 12.3849 5.36738 12.9894 8.00754C13.2835 9.29259 13.3368 10.3731 13.4113 11.6814C13.5344 13.9646 13.5298 16.2541 13.3986 18.5368C13.3042 20.1586 13.2249 22.3488 12.2462 23.6999C11.5928 24.6021 10.6951 24.8378 9.67397 24.9607L9.52846 24.9695C8.38167 25.0352 6.67349 25.0771 5.79701 24.1872C4.54564 22.9165 4.64406 20.6255 4.56361 18.9236C4.53395 18.2957 4.52973 17.6529 4.51967 17.0271C4.48697 15.2495 4.49579 13.4711 4.54701 11.6941C4.59757 9.94732 4.49372 7.37338 5.64467 5.96848C6.31209 5.15389 7.40284 5.06041 8.35951 5.00949ZM21.1007 5.0007C22.1707 4.98962 23.5125 5.03762 24.2951 5.88742C25.4067 7.09483 25.3923 9.49503 25.4406 11.0954C25.4652 11.9549 25.4827 12.8147 25.4943 13.6745C25.5093 15.3472 25.4933 17.0201 25.4464 18.6921C25.4358 19.0755 25.4267 19.4585 25.4083 19.8464C25.3317 21.464 25.2498 23.707 23.7111 24.57C22.9844 24.9773 21.9663 24.9964 21.1583 24.9997C17.4651 25.012 16.8859 22.9575 16.6652 19.5163L16.5587 17.6726C16.4634 15.5104 16.4845 13.3439 16.6222 11.1843C16.7381 9.26399 16.7736 6.61625 18.5665 5.54758C19.2935 5.11439 20.0571 5.05304 20.8693 5.00754C20.9463 5.0036 21.0236 5.00123 21.1007 5.0007Z\" />\n </mask>\n <path\n d=\"M8.35951 5.00949C10.6501 4.92814 12.3849 5.36738 12.9894 8.00754C13.2835 9.29259 13.3368 10.3731 13.4113 11.6814C13.5344 13.9646 13.5298 16.2541 13.3986 18.5368C13.3042 20.1586 13.2249 22.3488 12.2462 23.6999C11.5928 24.6021 10.6951 24.8378 9.67397 24.9607L9.52846 24.9695C8.38167 25.0352 6.67349 25.0771 5.79701 24.1872C4.54564 22.9165 4.64406 20.6255 4.56361 18.9236C4.53395 18.2957 4.52973 17.6529 4.51967 17.0271C4.48697 15.2495 4.49579 13.4711 4.54701 11.6941C4.59757 9.94732 4.49372 7.37338 5.64467 5.96848C6.31209 5.15389 7.40284 5.06041 8.35951 5.00949ZM21.1007 5.0007C22.1707 4.98962 23.5125 5.03762 24.2951 5.88742C25.4067 7.09483 25.3923 9.49503 25.4406 11.0954C25.4652 11.9549 25.4827 12.8147 25.4943 13.6745C25.5093 15.3472 25.4933 17.0201 25.4464 18.6921C25.4358 19.0755 25.4267 19.4585 25.4083 19.8464C25.3317 21.464 25.2498 23.707 23.7111 24.57C22.9844 24.9773 21.9663 24.9964 21.1583 24.9997C17.4651 25.012 16.8859 22.9575 16.6652 19.5163L16.5587 17.6726C16.4634 15.5104 16.4845 13.3439 16.6222 11.1843C16.7381 9.26399 16.7736 6.61625 18.5665 5.54758C19.2935 5.11439 20.0571 5.05304 20.8693 5.00754C20.9463 5.0036 21.0236 5.00123 21.1007 5.0007Z\"\n fill=\"#F9CB3B\"\n />\n <path\n d=\"M8.35951 5.00949L8.21753 1.01201L8.18221 1.01327L8.14692 1.01514L8.35951 5.00949ZM12.9894 8.00754L16.8885 7.11501L16.8885 7.11478L12.9894 8.00754ZM13.4113 11.6814L17.4055 11.4659L17.4048 11.4542L13.4113 11.6814ZM13.3986 18.5368L17.3918 18.7693L17.392 18.7665L13.3986 18.5368ZM12.2462 23.6999L9.00678 21.3534L9.00675 21.3535L12.2462 23.6999ZM9.67397 24.9607L9.91514 28.9534L10.0338 28.9462L10.1519 28.932L9.67397 24.9607ZM9.52846 24.9695L9.75736 28.9629L9.76963 28.9622L9.52846 24.9695ZM5.79701 24.1872L2.94698 26.9939L2.94725 26.9942L5.79701 24.1872ZM4.56361 18.9236L0.568071 19.1123L0.568074 19.1124L4.56361 18.9236ZM4.51967 17.0271L8.51916 16.9628L8.51899 16.9535L4.51967 17.0271ZM4.54701 11.6941L0.548687 11.5783L0.548673 11.5788L4.54701 11.6941ZM5.64467 5.96848L2.55059 3.43339L2.55043 3.43358L5.64467 5.96848ZM21.1007 5.0007L21.1283 9.00063L21.1422 9.00049L21.1007 5.0007ZM24.2951 5.88742L27.2377 3.17806L27.2374 3.17775L24.2951 5.88742ZM25.4406 11.0954L29.4389 10.9808L29.4387 10.9748L25.4406 11.0954ZM25.4943 13.6745L29.4941 13.6385L29.494 13.6297L29.4939 13.6208L25.4943 13.6745ZM25.4464 18.6921L21.448 18.58L21.448 18.5811L25.4464 18.6921ZM25.4083 19.8464L29.4039 20.0357L29.4039 20.0356L25.4083 19.8464ZM23.7111 24.57L25.6668 28.0593L25.6678 28.0588L23.7111 24.57ZM21.1583 24.9997L21.1716 28.9997L21.175 28.9997L21.1583 24.9997ZM16.6652 19.5163L12.6718 19.7469L12.6726 19.7596L12.6734 19.7724L16.6652 19.5163ZM16.5587 17.6726L12.5626 17.8487L12.5638 17.8759L12.5654 17.9031L16.5587 17.6726ZM16.6222 11.1843L20.6141 11.4389L20.6149 11.4253L16.6222 11.1843ZM18.5665 5.54758L16.5189 2.11144L16.5185 2.11164L18.5665 5.54758ZM20.8693 5.00754L20.6652 1.01275L20.6554 1.01325L20.6455 1.0138L20.8693 5.00754ZM8.35951 5.00949L8.50149 9.00697C8.94628 8.99117 9.22481 9.00718 9.3955 9.0317C9.55838 9.0551 9.52798 9.07337 9.40598 9.00749C9.34262 8.97327 9.26944 8.92423 9.19718 8.85964C9.12479 8.79494 9.07279 8.73203 9.0397 8.68403C8.97479 8.58986 9.02531 8.61646 9.0903 8.9003L12.9894 8.00754L16.8885 7.11478C16.3936 4.95326 15.2449 3.06872 13.2075 1.96841C11.4302 1.0086 9.51614 0.965889 8.21753 1.01201L8.35951 5.00949ZM12.9894 8.00754L9.09024 8.90006C9.29709 9.8037 9.34041 10.5495 9.41773 11.9086L13.4113 11.6814L17.4048 11.4542C17.3333 10.1967 17.27 8.78147 16.8885 7.11501L12.9894 8.00754ZM13.4113 11.6814L9.41708 11.8968C9.53222 14.0312 9.52795 16.1721 9.40517 18.3072L13.3986 18.5368L17.392 18.7665C17.5317 16.3361 17.5367 13.8981 17.4055 11.4659L13.4113 11.6814ZM13.3986 18.5368L9.40533 18.3044C9.35312 19.2015 9.31895 19.9024 9.20896 20.5591C9.09438 21.2432 8.96301 21.4139 9.00678 21.3534L12.2462 23.6999L15.4857 26.0464C16.5081 24.6349 16.9057 23.0348 17.0991 21.8806C17.297 20.699 17.3496 19.4939 17.3918 18.7693L13.3986 18.5368ZM12.2462 23.6999L9.00675 21.3535C9.05447 21.2876 9.13219 21.2004 9.24072 21.1151C9.34795 21.0309 9.44718 20.9783 9.51396 20.9495C9.57485 20.9233 9.59274 20.9237 9.5378 20.936C9.4793 20.9492 9.37659 20.9676 9.19607 20.9893L9.67397 24.9607L10.1519 28.932C11.4584 28.7748 13.8144 28.3538 15.4857 26.0464L12.2462 23.6999ZM9.67397 24.9607L9.43279 20.9679L9.28729 20.9767L9.52846 24.9695L9.76963 28.9622L9.91514 28.9534L9.67397 24.9607ZM9.52846 24.9695L9.29956 20.976C9.04041 20.9909 8.81068 21.0006 8.59362 21.0001C8.37479 20.9996 8.21316 20.9885 8.1008 20.9732C7.98264 20.9571 7.98675 20.9453 8.07044 20.9787C8.16047 21.0146 8.39471 21.1244 8.64678 21.3803L5.79701 24.1872L2.94725 26.9942C4.29917 28.3667 5.99551 28.7604 7.02194 28.9001C8.11462 29.0489 9.16195 28.997 9.75736 28.9629L9.52846 24.9695ZM5.79701 24.1872L8.64704 21.3806C8.89881 21.6362 8.79101 21.7497 8.69682 21.1228C8.65569 20.849 8.62918 20.5201 8.61013 20.1029C8.60069 19.896 8.59383 19.6876 8.58625 19.4556C8.57899 19.2334 8.57083 18.9817 8.55915 18.7347L4.56361 18.9236L0.568074 19.1124C0.59464 19.6745 0.603352 21.0982 0.785607 22.3114C0.975172 23.5732 1.44384 25.4675 2.94698 26.9939L5.79701 24.1872ZM4.56361 18.9236L8.55916 18.7348C8.53335 18.1885 8.53007 17.6422 8.51915 16.9628L4.51967 17.0271L0.520185 17.0913C0.529381 17.6636 0.534558 18.403 0.568071 19.1123L4.56361 18.9236ZM4.51967 17.0271L8.51899 16.9535C8.48744 15.2382 8.49596 13.5228 8.54535 11.8093L4.54701 11.6941L0.548673 11.5788C0.49562 13.4195 0.486505 15.2609 0.520345 17.1006L4.51967 17.0271ZM4.54701 11.6941L8.54534 11.8098C8.5772 10.7088 8.55922 9.97709 8.65482 9.17865C8.75348 8.35476 8.90321 8.30281 8.7389 8.50337L5.64467 5.96848L2.55043 3.43358C1.23518 5.03905 0.861363 6.97652 0.711566 8.2275C0.55872 9.50395 0.567376 10.9326 0.548687 11.5783L4.54701 11.6941ZM5.64467 5.96848L8.73875 8.50356C8.58231 8.69449 8.4044 8.83555 8.24345 8.93019C8.09194 9.01928 7.98263 9.05158 7.95983 9.05789C7.94005 9.06336 7.97197 9.05289 8.08608 9.03966C8.20329 9.02608 8.3476 9.01579 8.5721 9.00384L8.35951 5.00949L8.14692 1.01514C7.47816 1.05074 4.49577 1.05928 2.55059 3.43339L5.64467 5.96848ZM21.1007 5.0007L21.1422 9.00049C21.3776 8.99805 21.5594 8.99992 21.7166 9.00876C21.8739 9.01761 21.9614 9.0313 21.9984 9.03892C22.0358 9.04664 21.9742 9.03864 21.8553 8.98034C21.7269 8.91736 21.538 8.79829 21.3527 8.5971L24.2951 5.88742L27.2374 3.17775C26.0751 1.91561 24.6472 1.41666 23.6129 1.20354C22.595 0.99378 21.6228 0.995078 21.0593 1.00092L21.1007 5.0007ZM24.2951 5.88742L21.3524 8.59679C21.1841 8.41405 21.1558 8.29532 21.186 8.37664C21.2156 8.45654 21.2653 8.63086 21.3101 8.93224C21.4076 9.58849 21.4143 10.2837 21.4424 11.2161L25.4406 11.0954L29.4387 10.9748C29.4186 10.3068 29.4083 9.00167 29.2231 7.75587C29.0491 6.58552 28.628 4.68808 27.2377 3.17806L24.2951 5.88742ZM25.4406 11.0954L21.4422 11.21C21.4662 12.0476 21.4833 12.8869 21.4946 13.7282L25.4943 13.6745L29.4939 13.6208C29.4821 12.7424 29.4642 11.8623 29.4389 10.9808L25.4406 11.0954ZM25.4943 13.6745L21.4944 13.7105C21.509 15.3336 21.4935 16.9571 21.448 18.58L25.4464 18.6921L29.4449 18.8042C29.4931 17.083 29.5096 15.3608 29.4941 13.6385L25.4943 13.6745ZM25.4464 18.6921L21.448 18.5811C21.4367 18.9878 21.4288 19.3191 21.4128 19.6572L25.4083 19.8464L29.4039 20.0356C29.4246 19.5979 29.4349 19.1631 29.4449 18.8031L25.4464 18.6921ZM25.4083 19.8464L21.4128 19.6571C21.3924 20.0876 21.3768 20.4307 21.3448 20.7705C21.3133 21.105 21.2736 21.3402 21.2324 21.5014C21.135 21.8828 21.1547 21.4176 21.7544 21.0813L23.7111 24.57L25.6678 28.0588C27.8061 26.8595 28.6362 24.8412 28.9836 23.481C29.326 22.1403 29.3704 20.7425 29.4039 20.0357L25.4083 19.8464ZM23.7111 24.57L21.7554 21.0807C21.9055 20.9966 22.0115 20.9649 22.0367 20.9578C22.0625 20.9506 22.0444 20.9578 21.9665 20.9676C21.89 20.9772 21.7844 20.9858 21.6395 20.9915C21.4931 20.9972 21.3365 20.999 21.1417 20.9998L21.1583 24.9997L21.175 28.9997C21.5753 28.998 22.251 28.9947 22.9639 28.9051C23.6593 28.8178 24.6687 28.6187 25.6668 28.0593L23.7111 24.57ZM21.1583 24.9997L21.1451 20.9997C20.566 21.0017 20.4158 20.9177 20.4905 20.9493C20.6318 21.0092 20.8151 21.1518 20.9282 21.3199C20.999 21.4251 20.9366 21.3873 20.8544 20.9989C20.772 20.609 20.7086 20.0646 20.657 19.2602L16.6652 19.5163L12.6734 19.7724C12.7775 21.3953 12.9746 23.83 14.291 25.7862C15.9393 28.2357 18.5546 29.0084 21.1716 28.9997L21.1583 24.9997ZM16.6652 19.5163L20.6585 19.2858L20.5521 17.442L16.5587 17.6726L12.5654 17.9031L12.6718 19.7469L16.6652 19.5163ZM16.5587 17.6726L20.5549 17.4964C20.4659 15.4776 20.4855 13.4548 20.6141 11.4389L16.6222 11.1843L12.6303 10.9297C12.4834 13.233 12.461 15.5433 12.5626 17.8487L16.5587 17.6726ZM16.6222 11.1843L20.6149 11.4253C20.6486 10.8683 20.6661 10.4577 20.707 9.99853C20.7459 9.56208 20.7952 9.23053 20.8559 8.97634C20.9917 8.4084 21.057 8.71981 20.6146 8.98351L18.5665 5.54758L16.5185 2.11164C14.2832 3.44402 13.4343 5.61363 13.0751 7.11681C12.7251 8.58124 12.6762 10.1691 12.6295 10.9433L16.6222 11.1843ZM18.5665 5.54758L20.6142 8.98371C20.5 9.05175 20.4177 9.06486 20.4558 9.0574C20.4837 9.05193 20.5422 9.04236 20.6511 9.03191C20.7645 9.02104 20.8978 9.01221 21.093 9.00128L20.8693 5.00754L20.6455 1.0138C19.8717 1.05715 18.1832 1.11964 16.5189 2.11144L18.5665 5.54758ZM20.8693 5.00754L21.0734 9.00233C21.0962 9.00116 21.1144 9.0007 21.1283 9.00061L21.1007 5.0007L21.0731 1.0008C20.9328 1.00176 20.7965 1.00604 20.6652 1.01275L20.8693 5.00754Z\"\n fill=\"#FDEFC4\"\n mask={`url(#${maskId})`}\n />\n </svg>\n );\n};\nPauseIconReadingFluency.displayName = 'PauseIconReadingFluency';\n","import type { FC } from 'react';\nimport type { ReadingFluencyIconProps } from './types';\n\n/**\n * Ícone de voz — passarinho Reading Fluency + ondas sonoras (ilustração multicolor, cores\n * fixas da arte). viewBox nativo 61×50 (não é quadrado): `size` define a LARGURA\n * e a altura sai proporcional; sem `size`, usa o tamanho nativo. Prefira dimensionar\n * por `className` (ex.: `h-full w-full`) — o viewBox preserva a proporção.\n * `aria-hidden` por ser decorativo; quem usa em botão deve prover o rótulo.\n */\nexport const VoiceIconReadingFluency: FC<ReadingFluencyIconProps> = ({\n size,\n className,\n}) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size ?? 61}\n height={size != null ? (size * 50) / 61 : 50}\n viewBox=\"0 0 61 50\"\n fill=\"none\"\n className={className}\n aria-hidden=\"true\"\n >\n <path\n d=\"M5.89958 11.0353C5.36925 9.39292 5.46146 5.2114 7.31148 4.38714C8.83221 3.71028 10.6106 8.56901 10.6024 9.56426C10.7431 9.91306 10.8001 10.1116 10.8951 10.4702C11.6865 10.7351 11.5683 11.6757 12.1608 11.8734C12.2664 11.3525 12.5066 9.88954 12.9531 9.62142C13.3623 7.56723 18.6693 4.18722 18.2897 7.90361C18.2066 8.71521 16.7618 10.9438 16.3177 11.6823C16.3047 11.6897 16.2912 11.697 16.2781 11.7044C16.2126 11.9791 16.0587 12.2842 15.9196 12.5298C15.0803 14.0115 14.4109 15.7585 14.5935 17.5096C13.9343 18.0849 12.1336 19.8053 11.6808 20.4719C11.3486 20.523 11.0145 20.5608 10.6795 20.5849C9.24711 20.6788 7.7871 20.1425 6.88473 18.982C6.67675 18.7148 6.43281 18.5793 6.41377 18.2225C5.82456 17.5439 5.66506 15.9093 7.00576 16.171C7.30467 16.2294 8.07822 16.5892 8.17307 16.8913C8.55448 16.9374 9.02883 17.2243 9.3772 17.4119C9.41743 17.3324 9.48578 17.1321 9.52079 17.0396C7.86606 15.6009 6.20837 13.2781 5.89958 11.0353ZM9.37816 17.4148C9.77375 17.6756 10.9896 18.2284 11.4333 18.2678C11.1755 18.0348 9.93269 17.3217 9.52232 17.0433C9.48728 17.1359 9.41837 17.3355 9.37816 17.4148ZM10.8943 10.4708C11.1467 11.6766 11.8103 14.7203 12.4008 15.7172L12.4799 15.7437C12.4638 15.5665 12.439 15.4452 12.3981 15.2721C12.1441 14.1973 12.0306 12.9691 12.1594 11.8732C11.5672 11.6754 11.6854 10.7358 10.8943 10.4708Z\"\n fill=\"#F2C63A\"\n />\n <path\n d=\"M5.89816 11.037C5.36767 9.39482 5.45956 5.21281 7.30989 4.38864C8.83091 3.71116 10.6093 8.5717 10.6006 9.56592C9.92562 10.5549 9.73674 12.6533 9.65742 13.836C7.74025 12.7144 7.49431 12.3699 5.89816 11.037Z\"\n fill=\"#30A34D\"\n />\n <path\n d=\"M12.9514 9.62322C13.3597 7.56898 18.6692 4.18769 18.2889 7.90547C18.2059 8.71724 16.7601 10.946 16.3164 11.6841C16.3033 11.6915 16.2901 11.6989 16.277 11.7063C15.4067 11.8016 14.445 12.6386 13.8166 13.1892C13.2694 11.7843 13.1261 11.1044 12.9514 9.62322Z\"\n fill=\"#326FC3\"\n />\n <path\n d=\"M6.41244 18.224C5.82281 17.5457 5.66258 15.9101 7.00374 16.1719C7.30256 16.2301 8.07691 16.5903 8.1711 16.8927C8.19085 17.3908 8.47107 18.2886 8.61778 18.8012C7.75783 18.7811 7.19159 18.5547 6.41244 18.224Z\"\n fill=\"#326FC3\"\n />\n <path\n d=\"M21.9013 12.2457C28.7536 10.4097 32.7867 13.2996 35.9036 18.8556C34.2692 20.4976 33.3412 23.961 33.7014 27.8574C34.1881 33.1218 36.84 37.1808 39.6237 36.9235C39.8707 36.9006 40.1096 36.8425 40.341 36.7556C39.31 40.7146 36.0917 43.4284 30.6476 44.8872C21.231 47.4104 11.9723 44.353 10.1892 33.8562C8.40605 23.3592 12.4847 14.7689 21.9013 12.2457Z\"\n fill=\"#30A34D\"\n />\n <path\n d=\"M20.1394 16.5047C24.7935 13.0145 31.4084 13.7302 34.7735 16.9147C35.1847 17.4974 35.5778 18.1238 35.9582 18.7891C34.2869 20.4061 33.3337 23.9075 33.6982 27.8508C34.1848 33.115 36.836 37.174 39.6196 36.9172C39.9469 36.8869 40.2605 36.7954 40.5601 36.654C40.5579 36.6631 40.5575 36.6726 40.5553 36.6816C36.3785 41.7088 29.4955 44.717 23.76 41.8492C18.3293 39.1336 16.4171 34.408 15.9158 31.2891C15.3061 27.4959 16.3161 19.372 20.1394 16.5047Z\"\n fill=\"#FEFEFE\"\n />\n <path\n d=\"M33.7926 26.8947C33.3406 25.1789 32.9294 23.8729 33.0648 22.0871C33.2268 19.9517 33.5639 18.936 34.6203 18.4262C35.9538 17.7827 38.105 17.1253 40.4071 18.4263C42.7092 19.7272 43.5262 22.9862 43.5262 25.1778C43.5262 27.1493 43.0549 30.6309 41.7132 28.859C41.169 28.1403 39.8684 27.8894 39.2212 28.0658C38.1561 28.3561 36.4652 28.9222 35.5473 28.7106C34.6294 28.4989 34.1011 28.0661 33.7926 26.8947Z\"\n fill=\"#414345\"\n />\n <path\n d=\"M34.3395 31.2139C35.4206 32.9759 36.3404 33.7131 37.1362 33.6873C39.5658 33.6087 39.8675 32.1382 42.3903 33.7994C41.9769 35.1235 42.0371 36.1015 40.7039 36.88C39.9968 37.2906 39.1563 37.363 38.3714 37.0809C36.6985 36.4688 35.1347 34.2329 34.3395 31.2139Z\"\n fill=\"#414345\"\n />\n <path\n d=\"M21.7834 24.0741C21.4056 22.7086 19.9271 20.7491 21.8142 20.3618C22.4902 20.223 23.1423 20.2085 23.8286 20.1765C25.56 19.9154 27.1508 19.9787 28.685 20.9431C30.9397 22.3605 31.5333 26.0731 30.2316 28.3226C29.7824 29.0988 28.7778 29.9327 27.8788 30.0096C27.8905 30.2143 27.982 30.3881 27.9328 30.6162C27.615 32.0909 25.665 32.5194 24.3996 32.29C23.5938 32.1439 22.6186 31.6772 22.8115 30.6936C22.9304 30.0875 23.5578 29.7112 24.0269 29.4072C23.0094 28.9732 21.6768 28.3704 21.2312 27.2565C20.7708 26.1055 21.3942 25.0944 21.7834 24.0741Z\"\n fill=\"#F2C63A\"\n />\n <path\n d=\"M26.1501 21.6541C26.596 21.5411 27.0656 21.5741 27.4918 21.7483C28.2517 22.0552 28.7944 22.7794 29.11 23.524C29.5437 24.5482 29.5578 25.7059 29.1494 26.7411C28.8269 27.5388 28.3981 27.9267 27.6522 28.2503C24.0318 29.049 22.9479 22.6523 26.1501 21.6541Z\"\n fill=\"#F05229\"\n />\n <path\n d=\"M26.0933 22.0685C29.016 21.3408 30.2031 26.6081 27.6336 27.8345C24.5972 28.4993 23.5183 23.3784 26.0933 22.0685Z\"\n fill=\"#070706\"\n />\n <path\n d=\"M27.1529 22.6617C27.5375 22.4874 27.9886 22.6568 28.1689 23.0432C28.3493 23.4296 28.1929 23.8917 27.8167 24.084C27.5654 24.2125 27.2654 24.1927 27.0328 24.0322C26.8001 23.8717 26.6713 23.5958 26.6963 23.3113C26.7212 23.0267 26.8959 22.7781 27.1529 22.6617Z\"\n fill=\"#FEFEFE\"\n />\n <path\n d=\"M22.3181 30.3049C23.9963 29.2449 26.117 28.3714 27.8852 29.7839C27.9718 30.0597 28.1587 30.2655 28.1686 30.5948C28.2326 32.7231 25.6662 33.9903 23.8265 34.1184C22.655 34.1999 21.1377 33.9021 21.0685 32.4892C21.0259 31.6185 21.7697 30.8846 22.3181 30.3049Z\"\n fill=\"#EF99A4\"\n />\n <path\n d=\"M35.4161 19.0845C36.6781 18.4283 38.0635 18.4166 39.3945 18.8412C39.9208 19.0092 40.3002 19.3 40.0868 19.8906C39.7412 20.2316 39.5839 20.0824 39.188 19.9615C38.7547 19.8291 38.2168 19.5584 37.76 19.5497C37.1002 19.5371 36.4057 19.9081 35.7571 19.9489C35.3143 19.8113 35.3863 19.4616 35.4161 19.0845Z\"\n fill=\"#696B6C\"\n />\n <path\n d=\"M48.4316 33.4614C48.6691 33.4699 48.997 33.5192 49.3125 33.7173L49.4473 33.812L49.4492 33.814C51.4905 35.4228 53.4968 37.1332 55.4727 38.7671C55.6675 38.9282 56.1486 39.2886 56.5127 39.6587C56.7037 39.8529 56.9119 40.0967 57.0684 40.3804C57.2057 40.6297 57.3276 40.9566 57.3232 41.3325L57.3135 41.4976C57.2179 42.3597 56.5375 42.8668 56.3682 43.02L56.1416 43.2251L55.8398 43.2681C55.2121 43.3581 54.6974 43.2644 54.2236 42.9839C54.0192 42.8628 53.8446 42.7199 53.7041 42.5991C53.5378 42.4562 53.4455 42.3699 53.2812 42.2329V42.2319C51.2601 40.5443 49.1115 38.851 47.0986 37.063C46.5724 36.5955 46.1646 35.9554 46.3408 35.1606C46.4148 34.8277 46.5774 34.5562 46.7295 34.3511C46.8823 34.1452 47.0633 33.954 47.2275 33.7896L47.4697 33.5483L47.8086 33.5044C47.9183 33.4904 48.1746 33.4523 48.4316 33.4614ZM47.7158 34.7261C47.6529 34.7955 47.5949 34.8637 47.5439 34.9312C47.5956 34.8628 47.6537 34.7934 47.7178 34.7231C47.717 34.724 47.7166 34.7252 47.7158 34.7261ZM58.4102 24.5317C58.8057 24.5266 59.2495 24.6016 59.6475 24.8589C60.0109 25.094 60.2606 25.433 60.4053 25.8247L60.4609 25.9966L60.4619 25.9976C60.6131 26.5363 60.5806 27.0735 60.2832 27.5503C60.0329 27.9511 59.651 28.2019 59.4228 28.3491L59.2471 28.4624L59.04 28.4956C57.6624 28.7179 56.243 28.8544 54.8525 28.979C53.4512 29.1046 52.0848 29.2179 50.7607 29.394C50.5168 29.4265 49.9037 29.5159 49.3076 29.5337C49.0119 29.5425 48.6721 29.5355 48.3584 29.48C48.1032 29.4348 47.5966 29.3158 47.2666 28.8853C46.907 28.4157 46.6189 27.8103 46.7715 27.1206C46.9137 26.4791 47.3824 26.0455 47.7812 25.7534L47.9775 25.6099L48.2168 25.5728C50.1283 25.2724 52.3605 25.1249 54.1953 24.9038L54.2129 24.9009L54.2295 24.8999C55.4754 24.7925 57.0045 24.5503 58.4092 24.5317H58.4102ZM47.7598 27.7173C47.7715 27.7617 47.7877 27.8067 47.8066 27.853C47.7877 27.8067 47.7716 27.7617 47.7598 27.7173ZM47.7314 27.5493C47.7319 27.5561 47.7328 27.563 47.7334 27.5698C47.7294 27.5264 47.7292 27.4838 47.7324 27.4419L47.7314 27.5493ZM48.3721 26.5601C48.3287 26.5919 48.2873 26.6241 48.248 26.6558C48.2873 26.6241 48.3287 26.5928 48.3721 26.561C48.5788 26.5285 48.788 26.4972 48.999 26.4683C48.788 26.4972 48.5788 26.5276 48.3721 26.5601ZM51.4746 26.189C52.0779 26.1297 52.6813 26.0705 53.2754 26.0093C52.6814 26.0708 52.0779 26.1297 51.4746 26.189ZM52.3516 11.1099C53.0202 11.109 53.6049 11.4715 53.9531 11.8521C54.3187 12.2501 54.4484 12.7482 54.4326 13.1909C54.4233 13.4527 54.3228 13.6799 54.2773 13.7788C54.215 13.9143 54.1342 14.0573 54.0498 14.1978C53.8793 14.4813 53.6471 14.824 53.3818 15.1948C52.8484 15.9403 52.1374 16.8614 51.4082 17.7759C49.9654 19.5852 48.3732 21.4657 47.8857 21.9497L47.6357 22.1978L47.2861 22.2349C47.1824 22.2458 47.0279 22.2613 46.8623 22.2612C46.5509 22.2612 46.2388 22.1842 45.9707 22.0669C45.7061 21.951 45.4048 21.7608 45.1768 21.4702C44.8756 21.0862 44.748 20.6596 44.7695 20.1929L44.793 20.0073C44.8282 19.8306 44.8932 19.6848 44.9287 19.6079C44.9922 19.4705 45.0738 19.3245 45.1602 19.1812C45.3346 18.8918 45.5721 18.542 45.8428 18.1646C46.387 17.4057 47.1104 16.4707 47.8486 15.5474C49.304 13.7271 50.9086 11.8384 51.3564 11.4087L51.6025 11.1724L51.9414 11.1362C52.04 11.1256 52.1901 11.109 52.3516 11.1089V11.1099ZM45.8545 19.9927C45.8439 20.0142 45.8339 20.0346 45.8252 20.0542C45.8338 20.0346 45.8439 20.0143 45.8545 19.9927ZM46.0068 19.7153C45.9585 19.7961 45.9172 19.87 45.8828 19.936C45.9172 19.87 45.9585 19.7961 46.0068 19.7153ZM53.2168 12.5288C53.2364 12.5501 53.2546 12.5722 53.2715 12.5952C53.2546 12.5721 53.2365 12.5493 53.2168 12.5278C53.1913 12.4999 53.1635 12.4731 53.1348 12.4468C53.1637 12.4733 53.1911 12.5007 53.2168 12.5288ZM51.8496 12.3354C51.8357 12.3504 51.8223 12.3672 51.8076 12.3833C51.9105 12.2712 51.9919 12.185 52.0488 12.1304L51.8496 12.3354ZM52.7041 12.1782C52.6493 12.1573 52.5932 12.1413 52.5371 12.1294C52.5933 12.1412 52.6493 12.1574 52.7041 12.1782ZM52.5117 12.1245C52.4983 12.122 52.4851 12.1185 52.4717 12.1167L52.4502 12.1147C52.4707 12.1171 52.4912 12.1207 52.5117 12.1245ZM47.7363 27.5903C47.739 27.6132 47.7415 27.6364 47.7461 27.6597C47.7493 27.6759 47.7536 27.692 47.7578 27.7085C47.7475 27.6684 47.7408 27.629 47.7363 27.5903Z\"\n fill=\"#D1F0DB\"\n />\n </svg>\n);\nVoiceIconReadingFluency.displayName = 'VoiceIconReadingFluency';\n","import { useId, type FC } from 'react';\nimport type { ReadingFluencyIconProps } from './types';\n\n/**\n * Fechar (X creme num disco rosa com contorno creme) — tema Reading Fluency.\n * Cores fixas da arte (`#EA909A` + `#FDEFC4` + `#FBF0CE`), como no resto da\n * família. `aria-hidden`; quem usa em botão dá o rótulo — ver\n * `CloseButtonReadingFluency`.\n *\n * O disco visível ocupa 29 dos 37 do box: a arte fica 1u acima do centro\n * vertical (centro em y=17,5) pra abrir espaço pra sombra, que desce 1u. Como o\n * borrão da sombra alcança ~y=39, a barra de baixo dela é cortada pelo box de\n * 37 — a 5%/10% de preto isso é imperceptível, e alargar o box encolheria a\n * arte, então fica como a designer entregou.\n *\n * O `filter` da sombra usa id único (via `useId`) pra não colidir entre\n * instâncias — mesmo cuidado do `PauseIconReadingFluency`.\n */\nexport const CloseIconReadingFluency: FC<ReadingFluencyIconProps> = ({\n size = 37,\n className,\n}) => {\n // id único (sem \":\") pra o `filter` não colidir entre instâncias.\n const filterId = `reading-fluency-close-shadow-${useId().replaceAll(':', '')}`;\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0 0 37 37\"\n fill=\"none\"\n className={className}\n aria-hidden=\"true\"\n >\n <g filter={`url(#${filterId})`}>\n {/* Disco rosa com contorno creme. `strokeLinejoin` arredondado porque o\n path traz micro-segmentos quase degenerados do Figma (`V4.50145`,\n `V30.4614`) que viram farpas com o `miter` default. */}\n <path\n d=\"M18.3393 4.50145C18.6632 4.49328 19.0833 4.525 19.2309 4.53075C19.3571 4.53565 19.6589 4.53951 19.896 4.55809C20.512 4.60634 21.1133 4.70917 21.6665 4.82372C23.9818 5.30311 26.0685 6.30892 27.8286 7.98582L27.8296 7.9868C28.0478 8.19497 28.3029 8.50457 28.3628 8.57176L28.5171 8.73973C28.5904 8.82056 28.6752 8.91638 28.7407 8.99754C29.1275 9.47701 29.4543 9.99376 29.729 10.4731C29.9749 10.8961 30.197 11.3329 30.393 11.7807L30.5805 12.2319L30.5844 12.2427L30.6919 12.5347C31.2127 14.0062 31.4554 15.6151 31.4936 17.0884C31.5837 20.5692 30.5961 24.3495 27.8491 27.0073C26.0096 28.7872 23.6491 29.8392 21.2397 30.2593L21.2329 30.2612L21.226 30.2622C20.4284 30.3935 19.6221 30.4649 18.8139 30.48C18.5571 30.5059 18.3011 30.4988 18.1469 30.4917C18.0386 30.4866 17.9315 30.4796 17.8452 30.4741C17.7517 30.4682 17.6873 30.4644 17.6372 30.4624V30.4614C15.516 30.3925 13.4409 29.826 11.5796 28.8071L11.5727 28.8042L11.5669 28.8003C7.8651 26.7266 5.89682 22.9161 5.56003 18.9487C5.2757 15.599 5.96732 11.7362 8.35104 8.90868L8.35397 8.90575C10.2531 6.66533 12.8945 5.18306 15.7964 4.72801V4.72704C16.2826 4.64864 16.8342 4.57081 17.393 4.54442C17.7615 4.52704 17.9272 4.53156 18.1655 4.51024L18.1928 4.50829C18.2419 4.50479 18.2907 4.50359 18.3393 4.50243V4.50145Z\"\n fill=\"#EA909A\"\n stroke=\"#FDEFC4\"\n strokeWidth={3}\n strokeLinejoin=\"round\"\n />\n {/* Glifo X (10×10, centrado em ~18,1 / 17,1). */}\n <path\n d=\"M18.1454 15.3852C18.1993 15.3141 18.2759 15.234 18.3387 15.1706L20.1715 13.3386C20.4228 13.0873 20.9998 12.4544 21.2762 12.2963C22.0778 11.8376 23.1941 12.4592 23.1404 13.4209C23.1094 13.9774 22.8929 14.1713 22.5218 14.5401L21.937 15.1227C21.2706 15.7874 20.5934 16.4821 19.9169 17.1332L21.9604 19.1703L22.5612 19.7688C22.8649 20.0719 23.0725 20.2298 23.1299 20.6766C23.1757 21.0212 23.0813 21.3699 22.8677 21.6444C22.6253 21.9541 22.3339 22.0783 21.957 22.1262C21.9307 22.1273 21.9237 22.1458 21.8894 22.1418C21.6884 22.1179 21.3947 22.0724 21.2299 21.9462C20.8246 21.6362 20.4882 21.228 20.1169 20.8779C19.4629 20.217 18.7929 19.5668 18.1454 18.9046C17.9687 19.1005 17.7217 19.3346 17.5308 19.5258L16.3611 20.6955L15.6407 21.4168C15.2888 21.7686 15.0409 22.0827 14.5141 22.1267C13.6999 22.1944 13.0203 21.4341 13.1678 20.6329C13.2635 20.1137 13.7235 19.7838 14.085 19.4216L15.6099 17.8969C15.8251 17.6821 16.1838 17.3474 16.3736 17.1301C16.1813 16.929 15.9385 16.7023 15.7366 16.5008L14.2443 15.0104C13.9882 14.7549 13.5494 14.3713 13.3597 14.0876C12.8052 13.2582 13.3802 12.2545 14.305 12.1533C15.0134 12.128 15.178 12.3901 15.645 12.8586L16.5126 13.7277L17.5884 14.8014C17.729 14.9419 18.0421 15.2401 18.1454 15.3852Z\"\n fill=\"#FBF0CE\"\n />\n </g>\n <defs>\n {/* \"Drop Shadow/200\" da arte: duas sombras empilhadas (5% e 10% de\n #0C0C0D), ambas dy=1 / blur 2. */}\n <filter\n id={filterId}\n x=\"-0.857773\"\n y=\"-0.857758\"\n width=\"38\"\n height=\"38\"\n filterUnits=\"userSpaceOnUse\"\n colorInterpolationFilters=\"sRGB\"\n >\n <feFlood floodOpacity=\"0\" result=\"BackgroundImageFix\" />\n <feColorMatrix\n in=\"SourceAlpha\"\n type=\"matrix\"\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"\n result=\"hardAlpha\"\n />\n <feOffset dy=\"1\" />\n <feGaussianBlur stdDeviation=\"2\" />\n <feComposite in2=\"hardAlpha\" operator=\"out\" />\n <feColorMatrix\n type=\"matrix\"\n values=\"0 0 0 0 0.0470588 0 0 0 0 0.0470588 0 0 0 0 0.0509804 0 0 0 0.05 0\"\n />\n <feBlend\n mode=\"normal\"\n in2=\"BackgroundImageFix\"\n result=\"effect1_dropShadow\"\n />\n <feColorMatrix\n in=\"SourceAlpha\"\n type=\"matrix\"\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"\n result=\"hardAlpha\"\n />\n <feOffset dy=\"1\" />\n <feGaussianBlur stdDeviation=\"2\" />\n <feComposite in2=\"hardAlpha\" operator=\"out\" />\n <feColorMatrix\n type=\"matrix\"\n values=\"0 0 0 0 0.0470588 0 0 0 0 0.0470588 0 0 0 0 0.0509804 0 0 0 0.1 0\"\n />\n <feBlend\n mode=\"normal\"\n in2=\"effect1_dropShadow\"\n result=\"effect2_dropShadow\"\n />\n <feBlend\n mode=\"normal\"\n in=\"SourceGraphic\"\n in2=\"effect2_dropShadow\"\n result=\"shape\"\n />\n </filter>\n </defs>\n </svg>\n );\n};\nCloseIconReadingFluency.displayName = 'CloseIconReadingFluency';\n","import { ButtonHTMLAttributes, forwardRef } from 'react';\nimport { cn } from '../../utils/utils';\nimport { CloseIconReadingFluency } from '../ReadingFluencyIcons';\n\nexport interface CloseButtonReadingFluencyProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Lado do ícone em pixels. Default: 37 (tamanho nativo da arte). */\n iconSize?: number;\n /** Classes extras (posicionamento fica com quem usa). */\n className?: string;\n}\n\n/**\n * Botão de fechar do tema Reading Fluency: alvo clicável de no mínimo 42×42\n * envolvendo o `CloseIconReadingFluency` (disco visível de ~29px no box de 37).\n *\n * Substitui a composição antiga `ButtonReadingFluency variant=\"icon\"` + `XIcon`\n * do phosphor, que montava o disco em CSS (`bg-error-500`, borda `primary-200`,\n * glifo 14px). Aquele caminho dependia de `--color-error-500`, que **o tema\n * papole light não define** — o rosa da arte não saía. Aqui as cores vêm do\n * próprio SVG, como no resto da família de ícones.\n *\n * `aria-label` já vem com \"Fechar\" (o ícone é decorativo); passe outro pra\n * sobrescrever. O alvo é um **mínimo** de 42×42 — preserva o toque do botão\n * anterior com o disco menor e cresce junto se `iconSize` passar de 42, em vez\n * de deixar o ícone estourar a área clicável.\n *\n * Estados: a spec só entregou o `default`, então hover/pressed usam realce e\n * recuo neutros (brilho + escala), que funcionam sobre o header verde e sobre o\n * corpo branco sem inventar cor nova. Foco reaproveita o `secondary-600` que o\n * resto dos botões Reading Fluency já usa.\n */\nconst BASE_CLASSES =\n 'inline-flex min-h-[42px] min-w-[42px] shrink-0 cursor-pointer items-center justify-center rounded-full ' +\n 'transition-[transform,filter] duration-100 ' +\n 'hover:brightness-105 ' +\n 'active:scale-95 ' +\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-secondary-600 ' +\n 'disabled:cursor-not-allowed disabled:opacity-40 ' +\n 'disabled:hover:brightness-100 disabled:active:scale-100';\n\nexport const CloseButtonReadingFluency = forwardRef<\n HTMLButtonElement,\n CloseButtonReadingFluencyProps\n>(\n (\n {\n iconSize = 37,\n className,\n type = 'button',\n 'aria-label': ariaLabel = 'Fechar',\n ...props\n },\n ref\n ) => (\n <button\n ref={ref}\n type={type}\n aria-label={ariaLabel}\n className={cn(BASE_CLASSES, className)}\n {...props}\n >\n <CloseIconReadingFluency size={iconSize} />\n </button>\n )\n);\nCloseButtonReadingFluency.displayName = 'CloseButtonReadingFluency';\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 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-HIIOADV4.js","../src/components/AlertDialog/AlertDialog.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-HIIOADV4.js","sourcesContent":[null,"import {\n forwardRef,\n HTMLAttributes,\n useEffect,\n useId,\n useRef,\n MouseEvent,\n KeyboardEvent,\n} from 'react';\nimport Button from '../Button/Button';\nimport { useModalFocus } from '../../hooks/useModalFocus';\nimport { cn } from '../../utils/utils';\n\n/**\n * Lookup table for size classes\n */\nconst SIZE_CLASSES = {\n 'extra-small': 'w-screen max-w-[324px]',\n small: 'w-screen max-w-[378px]',\n medium: 'w-screen max-w-[459px]',\n large: 'w-screen max-w-[578px]',\n 'extra-large': 'w-screen max-w-[912px]',\n} as const;\n\ninterface AlertDialogProps extends HTMLAttributes<HTMLDialogElement> {\n /** Title of the alert dialog */\n title: string;\n /** Whether the alert dialog is open (controlled mode) */\n isOpen: boolean;\n /** Function called when the alert dialog is opened or closed (controlled mode) */\n onChangeOpen: (open: boolean) => void;\n /** Whether clicking the backdrop should close the alert dialog */\n closeOnBackdropClick?: boolean;\n /** Whether pressing Escape should close the alert dialog */\n closeOnEscape?: boolean;\n /** Additional CSS classes for the alert dialog content */\n className?: string;\n /** Function called when submit button is clicked */\n onSubmit?: (value?: unknown) => void;\n /** Value to pass to onSubmit function */\n submitValue?: unknown;\n /** Function called when cancel button is clicked */\n onCancel?: (value?: unknown) => void;\n /** Value to pass to onCancel function */\n cancelValue?: unknown;\n /** Description of the alert dialog */\n description: string;\n /** Label of the cancel button */\n cancelButtonLabel?: string;\n /** Label of the submit button */\n submitButtonLabel?: string;\n /** Size of the alert dialog */\n size?: 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large';\n /** Action type for the submit button (controls color/style). Defaults to 'negative' (destructive) */\n submitAction?: 'primary' | 'secondary' | 'positive' | 'negative';\n}\n\nconst AlertDialog = forwardRef<HTMLDialogElement, AlertDialogProps>(\n (\n {\n description,\n cancelButtonLabel = 'Cancelar',\n submitButtonLabel = 'Deletar',\n title,\n isOpen,\n closeOnBackdropClick = true,\n closeOnEscape = true,\n className = '',\n onSubmit,\n onChangeOpen,\n submitValue,\n onCancel,\n cancelValue,\n size = 'medium',\n submitAction = 'negative',\n ...props\n },\n ref\n ) => {\n const dialogRef = useRef<HTMLDialogElement>(null);\n\n /**\n * Ids por instância. Fixos, dois diálogos abertos ao mesmo tempo — ou um\n * diálogo convivendo com qualquer outro elemento da página que use o mesmo\n * id — fariam o `aria-labelledby` apontar para o nó errado, e o leitor de\n * tela anunciaria o título do outro.\n */\n const titleId = useId();\n const descriptionId = useId();\n\n /**\n * Leva o foco pro diálogo ao abrir, prende o Tab lá dentro e devolve o foco\n * a quem o abriu ao fechar. Sem isto o foco ficava no botão que está ATRÁS\n * do backdrop: o leitor de tela seguia lendo a página de trás, sem nunca\n * anunciar que um diálogo abriu, e o Tab passeava pelo conteúdo bloqueado.\n *\n * É o mesmo hook que o `Modal` usa — o `AlertDialog` é que tinha ficado de\n * fora quando o foco foi resolvido lá.\n */\n useModalFocus(isOpen, dialogRef);\n\n /**\n * O nó é preciso aqui (para o foco) e também no `ref` do consumidor, que\n * segue sendo encaminhado como antes.\n */\n const setDialogRef = (node: HTMLDialogElement | null) => {\n dialogRef.current = node;\n\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n (ref as { current: HTMLDialogElement | null }).current = node;\n }\n };\n\n // Handle escape key\n useEffect(() => {\n if (!isOpen || !closeOnEscape) return;\n\n const handleEscape = (event: globalThis.KeyboardEvent) => {\n if (event.key === 'Escape') {\n onChangeOpen(false);\n }\n };\n\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }, [isOpen, closeOnEscape]);\n\n // Prevent body scroll when modal is open\n useEffect(() => {\n if (isOpen) {\n document.body.style.overflow = 'hidden';\n } else {\n document.body.style.overflow = 'unset';\n }\n\n return () => {\n document.body.style.overflow = 'unset';\n };\n }, [isOpen]);\n\n const handleBackdropClick = (event: MouseEvent<HTMLDivElement>) => {\n if (event.target === event.currentTarget && closeOnBackdropClick) {\n onChangeOpen(false);\n }\n };\n\n const handleBackdropKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Escape' && closeOnEscape) {\n onChangeOpen(false);\n }\n };\n\n const handleSubmit = () => {\n onChangeOpen(false);\n onSubmit?.(submitValue);\n };\n\n const handleCancel = () => {\n onChangeOpen(false);\n onCancel?.(cancelValue);\n };\n\n const sizeClasses = SIZE_CLASSES[size];\n\n return (\n <>\n {/* Alert Dialog Overlay */}\n {isOpen && (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm\"\n onClick={handleBackdropClick}\n onKeyDown={handleBackdropKeyDown}\n data-testid=\"alert-dialog-overlay\"\n >\n {/* Alert Dialog Content */}\n <dialog\n ref={setDialogRef}\n // `<dialog>` em vez de `role=\"dialog\"`: o papel vem do elemento,\n // que é o que garante o tratamento correto em qualquer\n // navegador/leitor. Mesmo padrão do `Modal`.\n //\n // `open` (e não `showModal()`) porque o backdrop é nosso; em\n // troca, o navegador não gerencia foco — quem faz isso é o\n // `useModalFocus` acima, e é dele o requisito do `tabIndex={-1}`:\n // o foco inicial vai pro próprio diálogo, não pro primeiro botão,\n // para o leitor anunciar título e descrição antes das ações.\n open\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={descriptionId}\n tabIndex={-1}\n className={cn(\n // `static` anula o `position: absolute` que o navegador aplica\n // a `<dialog>`; sem isso ele escapa da centralização do\n // backdrop. As demais regras do UA (padding, borda, fundo) já\n // são sobrescritas pelas classes abaixo.\n 'static bg-background border border-border-100 rounded-lg shadow-lg p-6 m-3',\n sizeClasses,\n className\n )}\n {...props}\n >\n <h2\n id={titleId}\n className=\"pb-3 text-xl font-semibold text-text-950\"\n >\n {title}\n </h2>\n <p id={descriptionId} className=\"text-text-700 text-sm\">\n {description}\n </p>\n\n <div className=\"flex flex-row items-center justify-end pt-4 gap-3\">\n <Button variant=\"outline\" size=\"small\" onClick={handleCancel}>\n {cancelButtonLabel}\n </Button>\n\n <Button\n variant=\"solid\"\n size=\"small\"\n action={submitAction}\n onClick={handleSubmit}\n >\n {submitButtonLabel}\n </Button>\n </div>\n </dialog>\n </div>\n )}\n </>\n );\n }\n);\n\nAlertDialog.displayName = 'AlertDialog';\n\nexport { AlertDialog };\n"]}
|
package/dist/chunk-JSH3BQZ7.mjs
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
// src/hooks/useEscapeToClose.ts
|
|
2
|
-
import { useEffect } from "react";
|
|
3
|
-
var useEscapeToClose = (enabled, onClose) => {
|
|
4
|
-
useEffect(() => {
|
|
5
|
-
if (!enabled) return;
|
|
6
|
-
const handleEscape = (event) => {
|
|
7
|
-
if (event.key === "Escape" && !event.defaultPrevented) onClose();
|
|
8
|
-
};
|
|
9
|
-
document.addEventListener("keydown", handleEscape);
|
|
10
|
-
return () => document.removeEventListener("keydown", handleEscape);
|
|
11
|
-
}, [enabled, onClose]);
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export {
|
|
15
|
-
useEscapeToClose
|
|
16
|
-
};
|
|
17
|
-
//# sourceMappingURL=chunk-JSH3BQZ7.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useEscapeToClose.ts"],"sourcesContent":["import { useEffect } from 'react';\n\n/**\n * Fecha um overlay (modal/dialog) ao pressionar Escape enquanto ele está aberto.\n *\n * Compartilhado pelos modais da lib pra evitar duplicar o mesmo `keydown`\n * listener em cada componente.\n *\n * @param enabled - Liga o listener. Normalmente `isOpen && closeOnEscape`.\n * @param onClose - Chamado quando o Escape é pressionado.\n */\nexport const useEscapeToClose = (enabled: boolean, onClose: () => void) => {\n useEffect(() => {\n if (!enabled) return;\n\n const handleEscape = (event: globalThis.KeyboardEvent) => {\n // A popup inside the overlay (Select, DropdownMenu...) that already\n // handled this Escape marks it with preventDefault: only the popup\n // closes, the overlay stays open.\n if (event.key === 'Escape' && !event.defaultPrevented) onClose();\n };\n\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }, [enabled, onClose]);\n};\n"],"mappings":";AAAA,SAAS,iBAAiB;AAWnB,IAAM,mBAAmB,CAAC,SAAkB,YAAwB;AACzE,YAAU,MAAM;AACd,QAAI,CAAC,QAAS;AAEd,UAAM,eAAe,CAAC,UAAoC;AAIxD,UAAI,MAAM,QAAQ,YAAY,CAAC,MAAM,iBAAkB,SAAQ;AAAA,IACjE;AAEA,aAAS,iBAAiB,WAAW,YAAY;AACjD,WAAO,MAAM,SAAS,oBAAoB,WAAW,YAAY;AAAA,EACnE,GAAG,CAAC,SAAS,OAAO,CAAC;AACvB;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/IconButton/IconButton.tsx"],"sourcesContent":["import { ButtonHTMLAttributes, ReactNode, forwardRef } from 'react';\nimport { cn } from '../../utils/utils';\n\n/**\n * IconButton component props interface\n */\nexport type IconButtonProps = {\n /** Ícone a ser exibido no botão */\n icon: ReactNode;\n /** Tamanho do botão */\n size?: 'sm' | 'md';\n /** Estado de seleção/ativo do botão - permanece ativo até ser clicado novamente ou outro botão ser ativado */\n active?: boolean;\n /** Additional CSS classes to apply */\n className?: string;\n} & ButtonHTMLAttributes<HTMLButtonElement>;\n\n/**\n * IconButton component for Analytica Ensino platforms\n *\n * Um botão compacto apenas com ícone, ideal para menus dropdown,\n * barras de ferramentas e ações secundárias.\n * Oferece dois tamanhos com estilo consistente.\n * Estado ativo permanece até ser clicado novamente ou outro botão ser ativado.\n * Suporta forwardRef para acesso programático ao elemento DOM.\n *\n * @param icon - O ícone a ser exibido no botão\n * @param size - Tamanho do botão (sm, md)\n * @param active - Estado ativo/selecionado do botão\n * @param className - Classes CSS adicionais\n * @param props - Todos os outros atributos HTML padrão de button\n * @returns Um elemento button compacto estilizado apenas com ícone\n *\n * @example\n * ```tsx\n * <IconButton\n * icon={<MoreVerticalIcon />}\n * size=\"sm\"\n * onClick={() => openMenu()}\n * />\n * ```\n *\n * @example\n * ```tsx\n * // Botão ativo em uma barra de ferramentas - permanece ativo até outro clique\n * <IconButton\n * icon={<BoldIcon />}\n * active={isBold}\n * onClick={toggleBold}\n * />\n * ```\n *\n * @example\n * ```tsx\n * // Usando ref para controle programático\n * const buttonRef = useRef<HTMLButtonElement>(null);\n *\n * <IconButton\n * ref={buttonRef}\n * icon={<EditIcon />}\n * size=\"md\"\n * onClick={() => startEditing()}\n * />\n * ```\n */\nconst IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(\n (\n { icon, size = 'md', active = false, className = '', disabled, ...props },\n ref\n ) => {\n // Classes base para todos os estados\n const baseClasses = [\n 'inline-flex',\n 'items-center',\n 'justify-center',\n 'rounded-lg',\n 'font-medium',\n 'bg-transparent',\n 'text-text-950',\n 'cursor-pointer',\n 'hover:bg-primary-600',\n 'hover:text-text',\n 'focus-visible:outline-none',\n 'focus-visible:ring-2',\n 'focus-visible:ring-offset-0',\n 'focus-visible:ring-indicator-info',\n 'disabled:opacity-50',\n 'disabled:cursor-not-allowed',\n 'disabled:pointer-events-none',\n ];\n\n // Classes de tamanho\n const sizeClasses = {\n sm: ['w-6', 'h-6', 'text-sm'],\n md: ['w-10', 'h-10', 'text-base'],\n };\n\n // Classes de estado ativo\n const activeClasses = active\n ? ['!bg-primary-50', '!text-primary-950', 'hover:!bg-primary-100']\n : [];\n\n const allClasses = [\n ...baseClasses,\n ...sizeClasses[size],\n ...activeClasses,\n ].join(' ');\n\n // Garantir acessibilidade com aria-label padrão\n const ariaLabel = props['aria-label'] ?? 'Botão de ação';\n\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cn(allClasses, className)}\n disabled={disabled}\n aria-pressed={active}\n aria-label={ariaLabel}\n {...props}\n >\n <span className=\"flex items-center justify-center\">{icon}</span>\n </button>\n );\n }\n);\n\nIconButton.displayName = 'IconButton';\n\nexport default IconButton;\n"],"mappings":";;;;;AAAA,SAA0C,kBAAkB;AAyHpD;AAxDR,IAAM,aAAa;AAAA,EACjB,CACE,EAAE,MAAM,OAAO,MAAM,SAAS,OAAO,YAAY,IAAI,UAAU,GAAG,MAAM,GACxE,QACG;AAEH,UAAM,cAAc;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAGA,UAAM,cAAc;AAAA,MAClB,IAAI,CAAC,OAAO,OAAO,SAAS;AAAA,MAC5B,IAAI,CAAC,QAAQ,QAAQ,WAAW;AAAA,IAClC;AAGA,UAAM,gBAAgB,SAClB,CAAC,kBAAkB,qBAAqB,uBAAuB,IAC/D,CAAC;AAEL,UAAM,aAAa;AAAA,MACjB,GAAG;AAAA,MACH,GAAG,YAAY,IAAI;AAAA,MACnB,GAAG;AAAA,IACL,EAAE,KAAK,GAAG;AAGV,UAAM,YAAY,MAAM,YAAY,KAAK;AAEzC,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL,WAAW,GAAG,YAAY,SAAS;AAAA,QACnC;AAAA,QACA,gBAAc;AAAA,QACd,cAAY;AAAA,QACX,GAAG;AAAA,QAEJ,8BAAC,UAAK,WAAU,oCAAoC,gBAAK;AAAA;AAAA,IAC3D;AAAA,EAEJ;AACF;AAEA,WAAW,cAAc;AAEzB,IAAO,qBAAQ;","names":[]}
|