@notectl/core 2.0.1 → 2.0.3
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/README.md +258 -121
- package/dist/chunks/AlignmentPlugin-CIkPaP2h.mjs +2 -0
- package/dist/chunks/AlignmentPlugin-CIkPaP2h.mjs.map +1 -0
- package/dist/chunks/AttrRegistry-B1iBFcKO.mjs +2 -0
- package/dist/chunks/AttrRegistry-B1iBFcKO.mjs.map +1 -0
- package/dist/chunks/AttributedMarkCommands-Cmet1IuC.mjs +2 -0
- package/dist/chunks/AttributedMarkCommands-Cmet1IuC.mjs.map +1 -0
- package/dist/chunks/BlockInsertion-DTIE2BiH.mjs +2 -0
- package/dist/chunks/BlockInsertion-DTIE2BiH.mjs.map +1 -0
- package/dist/chunks/BlockTypePickerRegistry-U4uY7-lN.mjs +2 -0
- package/dist/chunks/BlockTypePickerRegistry-U4uY7-lN.mjs.map +1 -0
- package/dist/chunks/BlockquotePlugin-DmbnFmNj.mjs +2 -0
- package/dist/chunks/BlockquotePlugin-DmbnFmNj.mjs.map +1 -0
- package/dist/chunks/CaretNavigationPlugin-4EaHvYXR.mjs +2 -0
- package/dist/chunks/CaretNavigationPlugin-4EaHvYXR.mjs.map +1 -0
- package/dist/chunks/CodeBlockPlugin-BP3XaOGj.mjs +2 -0
- package/dist/chunks/CodeBlockPlugin-BP3XaOGj.mjs.map +1 -0
- package/dist/chunks/ColorGrid-taTKtdsm.mjs +2 -0
- package/dist/chunks/ColorGrid-taTKtdsm.mjs.map +1 -0
- package/dist/chunks/ColorPickerPopup-JJQ-gMBN.mjs +2 -0
- package/dist/chunks/ColorPickerPopup-JJQ-gMBN.mjs.map +1 -0
- package/dist/chunks/ColorValidation-3viVw_tK.mjs +2 -0
- package/dist/chunks/ColorValidation-3viVw_tK.mjs.map +1 -0
- package/dist/chunks/CommandHelpers-D0LIFM4O.mjs +2 -0
- package/dist/chunks/CommandHelpers-D0LIFM4O.mjs.map +1 -0
- package/dist/chunks/Commands-DJSVqp7b.mjs +2 -0
- package/dist/chunks/Commands-DJSVqp7b.mjs.map +1 -0
- package/dist/chunks/Decoration-6dhb8k3b.mjs +2 -0
- package/dist/chunks/Decoration-6dhb8k3b.mjs.map +1 -0
- package/dist/chunks/Document-CkQLx84k.mjs +2 -0
- package/dist/chunks/Document-CkQLx84k.mjs.map +1 -0
- package/dist/chunks/DocumentParser-QJUmtPp9.mjs +2 -0
- package/dist/chunks/DocumentParser-QJUmtPp9.mjs.map +1 -0
- package/dist/chunks/DocumentSerializer-bwcxM9WV.mjs +2 -0
- package/dist/chunks/DocumentSerializer-bwcxM9WV.mjs.map +1 -0
- package/dist/chunks/DomUtils-BkyCg-OO.mjs +2 -0
- package/dist/chunks/DomUtils-BkyCg-OO.mjs.map +1 -0
- package/dist/chunks/FontPlugin-Cz4qEYGh.mjs +2 -0
- package/dist/chunks/FontPlugin-Cz4qEYGh.mjs.map +1 -0
- package/dist/chunks/FontSizePlugin-D1WtDqrH.mjs +2 -0
- package/dist/chunks/FontSizePlugin-D1WtDqrH.mjs.map +1 -0
- package/dist/chunks/GapCursorNavigation-CKKq42kA.mjs +2 -0
- package/dist/chunks/GapCursorNavigation-CKKq42kA.mjs.map +1 -0
- package/dist/chunks/GapCursorPlugin-0CyOaciK.mjs +2 -0
- package/dist/chunks/GapCursorPlugin-0CyOaciK.mjs.map +1 -0
- package/dist/chunks/HTMLUtils-BLwp5G4f.mjs +2 -0
- package/dist/chunks/HTMLUtils-BLwp5G4f.mjs.map +1 -0
- package/dist/chunks/HardBreakPlugin-BOz-L53p.mjs +2 -0
- package/dist/chunks/HardBreakPlugin-BOz-L53p.mjs.map +1 -0
- package/dist/chunks/HeadingPlugin-C1F-5Ail.mjs +2 -0
- package/dist/chunks/HeadingPlugin-C1F-5Ail.mjs.map +1 -0
- package/dist/chunks/HighlightPlugin-LYARYuDC.mjs +2 -0
- package/dist/chunks/HighlightPlugin-LYARYuDC.mjs.map +1 -0
- package/dist/chunks/HorizontalRulePlugin-fmdbzWDQ.mjs +2 -0
- package/dist/chunks/HorizontalRulePlugin-fmdbzWDQ.mjs.map +1 -0
- package/dist/chunks/ImagePlugin-CrfnT1sD.mjs +2 -0
- package/dist/chunks/ImagePlugin-CrfnT1sD.mjs.map +1 -0
- package/dist/chunks/KeyboardNav-BZIHDPDV.mjs +2 -0
- package/dist/chunks/KeyboardNav-BZIHDPDV.mjs.map +1 -0
- package/dist/chunks/LinkPlugin-DzFJLnfQ.mjs +2 -0
- package/dist/chunks/LinkPlugin-DzFJLnfQ.mjs.map +1 -0
- package/dist/chunks/ListPlugin-C_Rcz3bV.mjs +2 -0
- package/dist/chunks/ListPlugin-C_Rcz3bV.mjs.map +1 -0
- package/dist/chunks/NavigationQueries-CgYPG6oY.mjs +2 -0
- package/dist/chunks/NavigationQueries-CgYPG6oY.mjs.map +1 -0
- package/dist/chunks/NodeResolver-CCA8UVRr.mjs +2 -0
- package/dist/chunks/NodeResolver-CCA8UVRr.mjs.map +1 -0
- package/dist/chunks/NodeSelectionCommands-CE_73CxF.mjs +2 -0
- package/dist/chunks/NodeSelectionCommands-CE_73CxF.mjs.map +1 -0
- package/dist/chunks/Platform-D9TRT4Mn.mjs +2 -0
- package/dist/chunks/Platform-D9TRT4Mn.mjs.map +1 -0
- package/dist/chunks/PluginHelpers-DLKHJWJn.mjs +2 -0
- package/dist/chunks/PluginHelpers-DLKHJWJn.mjs.map +1 -0
- package/dist/chunks/PopupManager-RWOaksC0.mjs +2 -0
- package/dist/chunks/PopupManager-RWOaksC0.mjs.map +1 -0
- package/dist/chunks/PopupPositioning-a1ADYSmx.mjs +2 -0
- package/dist/chunks/PopupPositioning-a1ADYSmx.mjs.map +1 -0
- package/dist/chunks/PrintPlugin-CwbEz3eP.mjs +2 -0
- package/dist/chunks/PrintPlugin-CwbEz3eP.mjs.map +1 -0
- package/dist/chunks/PrintTypes-B2DXeAEG.mjs +2 -0
- package/dist/chunks/PrintTypes-B2DXeAEG.mjs.map +1 -0
- package/dist/chunks/Selection-B14e7gd0.mjs +2 -0
- package/dist/chunks/Selection-B14e7gd0.mjs.map +1 -0
- package/dist/chunks/ShortcutFormatting-DQPMvupx.mjs +2 -0
- package/dist/chunks/ShortcutFormatting-DQPMvupx.mjs.map +1 -0
- package/dist/chunks/SmartPastePlugin-CXqJ0CPO.mjs +2 -0
- package/dist/chunks/SmartPastePlugin-CXqJ0CPO.mjs.map +1 -0
- package/dist/chunks/StrikethroughPlugin-CRl69jm3.mjs +2 -0
- package/dist/chunks/StrikethroughPlugin-CRl69jm3.mjs.map +1 -0
- package/dist/chunks/StyleRuntime-0yPPJK9H.mjs +2 -0
- package/dist/chunks/StyleRuntime-0yPPJK9H.mjs.map +1 -0
- package/dist/chunks/SuperSubPlugin-CAnaTJVm.mjs +2 -0
- package/dist/chunks/SuperSubPlugin-CAnaTJVm.mjs.map +1 -0
- package/dist/chunks/TablePlugin-D_7bgrqm.mjs +2 -0
- package/dist/chunks/TablePlugin-D_7bgrqm.mjs.map +1 -0
- package/dist/chunks/TextColorPlugin-Dfhvl1qG.mjs +2 -0
- package/dist/chunks/TextColorPlugin-Dfhvl1qG.mjs.map +1 -0
- package/dist/chunks/TextDirectionCorePlugin-CyKw-C8X.mjs +2 -0
- package/dist/chunks/TextDirectionCorePlugin-CyKw-C8X.mjs.map +1 -0
- package/dist/chunks/TextDirectionLocale-rlU1yNly.mjs +2 -0
- package/dist/chunks/TextDirectionLocale-rlU1yNly.mjs.map +1 -0
- package/dist/chunks/TextFormattingPlugin-xtQczzCs.mjs +2 -0
- package/dist/chunks/TextFormattingPlugin-xtQczzCs.mjs.map +1 -0
- package/dist/chunks/ToolbarPlugin-BFEniyH-.mjs +2 -0
- package/dist/chunks/ToolbarPlugin-BFEniyH-.mjs.map +1 -0
- package/dist/chunks/TypeBrands-BQR8dEYU.mjs +2 -0
- package/dist/chunks/TypeBrands-BQR8dEYU.mjs.map +1 -0
- package/dist/chunks/WordBoundary-iZXLMFyk.mjs +2 -0
- package/dist/chunks/WordBoundary-iZXLMFyk.mjs.map +1 -0
- package/dist/chunks/XmlPatterns-Ub8I1jdE.mjs +2 -0
- package/dist/chunks/XmlPatterns-Ub8I1jdE.mjs.map +1 -0
- package/dist/chunks/ar-3-z4mZhh.mjs +2 -0
- package/dist/chunks/ar-3-z4mZhh.mjs.map +1 -0
- package/dist/chunks/ar-B-l6wR4D.mjs +2 -0
- package/dist/chunks/ar-B-l6wR4D.mjs.map +1 -0
- package/dist/chunks/ar-B3NByR5H.mjs +2 -0
- package/dist/chunks/ar-B3NByR5H.mjs.map +1 -0
- package/dist/chunks/ar-BRvm4F78.mjs +2 -0
- package/dist/chunks/ar-BRvm4F78.mjs.map +1 -0
- package/dist/chunks/ar-BUMXujtS.mjs +2 -0
- package/dist/chunks/ar-BUMXujtS.mjs.map +1 -0
- package/dist/chunks/ar-BhVHv8Lx.mjs +2 -0
- package/dist/chunks/ar-BhVHv8Lx.mjs.map +1 -0
- package/dist/chunks/ar-BhwRD9Cg.mjs +2 -0
- package/dist/chunks/ar-BhwRD9Cg.mjs.map +1 -0
- package/dist/chunks/ar-Bm8ORJ3H.mjs +2 -0
- package/dist/chunks/ar-Bm8ORJ3H.mjs.map +1 -0
- package/dist/chunks/ar-BpxuRQB2.mjs +2 -0
- package/dist/chunks/ar-BpxuRQB2.mjs.map +1 -0
- package/dist/chunks/ar-CA0-ysCj.mjs +2 -0
- package/dist/chunks/ar-CA0-ysCj.mjs.map +1 -0
- package/dist/chunks/ar-CAkFpIju.mjs +2 -0
- package/dist/chunks/ar-CAkFpIju.mjs.map +1 -0
- package/dist/chunks/ar-CU6qxyFp.mjs +2 -0
- package/dist/chunks/ar-CU6qxyFp.mjs.map +1 -0
- package/dist/chunks/ar-CXcTrZVc.mjs +2 -0
- package/dist/chunks/ar-CXcTrZVc.mjs.map +1 -0
- package/dist/chunks/ar-CeO_osWz.mjs +2 -0
- package/dist/chunks/ar-CeO_osWz.mjs.map +1 -0
- package/dist/chunks/ar-CxRSPJDE.mjs +2 -0
- package/dist/chunks/ar-CxRSPJDE.mjs.map +1 -0
- package/dist/chunks/ar-DHes6Igy.mjs +2 -0
- package/dist/chunks/ar-DHes6Igy.mjs.map +1 -0
- package/dist/chunks/ar-DN1aHdqb.mjs +2 -0
- package/dist/chunks/ar-DN1aHdqb.mjs.map +1 -0
- package/dist/chunks/ar-DNzmHN3q.mjs +2 -0
- package/dist/chunks/ar-DNzmHN3q.mjs.map +1 -0
- package/dist/chunks/ar-DVdWier2.mjs +2 -0
- package/dist/chunks/ar-DVdWier2.mjs.map +1 -0
- package/dist/chunks/ar-G_ADWoCx.mjs +2 -0
- package/dist/chunks/ar-G_ADWoCx.mjs.map +1 -0
- package/dist/chunks/ar-KAaQxKMo.mjs +2 -0
- package/dist/chunks/ar-KAaQxKMo.mjs.map +1 -0
- package/dist/chunks/ar-MHdV5PAO.mjs +2 -0
- package/dist/chunks/ar-MHdV5PAO.mjs.map +1 -0
- package/dist/chunks/ar-S2VfgLMv.mjs +2 -0
- package/dist/chunks/ar-S2VfgLMv.mjs.map +1 -0
- package/dist/chunks/color-picker-DumtHdqh.mjs +2 -0
- package/dist/chunks/color-picker-DumtHdqh.mjs.map +1 -0
- package/dist/chunks/de-0x8V-vch.mjs +2 -0
- package/dist/chunks/de-0x8V-vch.mjs.map +1 -0
- package/dist/chunks/de-B5xIP9en.mjs +2 -0
- package/dist/chunks/de-B5xIP9en.mjs.map +1 -0
- package/dist/chunks/de-BBohFIqw.mjs +2 -0
- package/dist/chunks/de-BBohFIqw.mjs.map +1 -0
- package/dist/chunks/de-BWPmC-2S.mjs +2 -0
- package/dist/chunks/de-BWPmC-2S.mjs.map +1 -0
- package/dist/chunks/de-Bo1kM9rb.mjs +2 -0
- package/dist/chunks/de-Bo1kM9rb.mjs.map +1 -0
- package/dist/chunks/de-BqzR2XMP.mjs +2 -0
- package/dist/chunks/de-BqzR2XMP.mjs.map +1 -0
- package/dist/chunks/de-CIZibvOC.mjs +2 -0
- package/dist/chunks/de-CIZibvOC.mjs.map +1 -0
- package/dist/chunks/de-CLToQn0o.mjs +2 -0
- package/dist/chunks/de-CLToQn0o.mjs.map +1 -0
- package/dist/chunks/de-CNoAAJul.mjs +2 -0
- package/dist/chunks/de-CNoAAJul.mjs.map +1 -0
- package/dist/chunks/de-CPb7rgkk.mjs +2 -0
- package/dist/chunks/de-CPb7rgkk.mjs.map +1 -0
- package/dist/chunks/de-CdmBKVDW.mjs +2 -0
- package/dist/chunks/de-CdmBKVDW.mjs.map +1 -0
- package/dist/chunks/de-DDgeyWgp.mjs +2 -0
- package/dist/chunks/de-DDgeyWgp.mjs.map +1 -0
- package/dist/chunks/de-DGXQ4OiR.mjs +2 -0
- package/dist/chunks/de-DGXQ4OiR.mjs.map +1 -0
- package/dist/chunks/de-DJbvKl4E.mjs +2 -0
- package/dist/chunks/de-DJbvKl4E.mjs.map +1 -0
- package/dist/chunks/de-DKNvYM_G.mjs +2 -0
- package/dist/chunks/de-DKNvYM_G.mjs.map +1 -0
- package/dist/chunks/de-DOHm_P4A.mjs +2 -0
- package/dist/chunks/de-DOHm_P4A.mjs.map +1 -0
- package/dist/chunks/de-DTMX75rn.mjs +2 -0
- package/dist/chunks/de-DTMX75rn.mjs.map +1 -0
- package/dist/chunks/de-DfkQds5F.mjs +2 -0
- package/dist/chunks/de-DfkQds5F.mjs.map +1 -0
- package/dist/chunks/de-TEQW-F4t.mjs +2 -0
- package/dist/chunks/de-TEQW-F4t.mjs.map +1 -0
- package/dist/chunks/de-WzdZ_NJ6.mjs +2 -0
- package/dist/chunks/de-WzdZ_NJ6.mjs.map +1 -0
- package/dist/chunks/de-_vqVfXeo.mjs +2 -0
- package/dist/chunks/de-_vqVfXeo.mjs.map +1 -0
- package/dist/chunks/de-gR6jt-sS.mjs +2 -0
- package/dist/chunks/de-gR6jt-sS.mjs.map +1 -0
- package/dist/chunks/de-qOBFRCGL.mjs +2 -0
- package/dist/chunks/de-qOBFRCGL.mjs.map +1 -0
- package/dist/chunks/es-1udUsTJd.mjs +2 -0
- package/dist/chunks/es-1udUsTJd.mjs.map +1 -0
- package/dist/chunks/es-3H7h0_G5.mjs +2 -0
- package/dist/chunks/es-3H7h0_G5.mjs.map +1 -0
- package/dist/chunks/es-4-5iRK0M.mjs +2 -0
- package/dist/chunks/es-4-5iRK0M.mjs.map +1 -0
- package/dist/chunks/es-89LD3TlT.mjs +2 -0
- package/dist/chunks/es-89LD3TlT.mjs.map +1 -0
- package/dist/chunks/es-B2KFVoHa.mjs +2 -0
- package/dist/chunks/es-B2KFVoHa.mjs.map +1 -0
- package/dist/chunks/es-BUP1scLX.mjs +2 -0
- package/dist/chunks/es-BUP1scLX.mjs.map +1 -0
- package/dist/chunks/es-Bhhj-yh0.mjs +2 -0
- package/dist/chunks/es-Bhhj-yh0.mjs.map +1 -0
- package/dist/chunks/es-Bo0NTtQH.mjs +2 -0
- package/dist/chunks/es-Bo0NTtQH.mjs.map +1 -0
- package/dist/chunks/es-Bovw7l2W.mjs +2 -0
- package/dist/chunks/es-Bovw7l2W.mjs.map +1 -0
- package/dist/chunks/es-C7xAs1yn.mjs +2 -0
- package/dist/chunks/es-C7xAs1yn.mjs.map +1 -0
- package/dist/chunks/es-CIdF7MzV.mjs +2 -0
- package/dist/chunks/es-CIdF7MzV.mjs.map +1 -0
- package/dist/chunks/es-CPit7Z6w.mjs +2 -0
- package/dist/chunks/es-CPit7Z6w.mjs.map +1 -0
- package/dist/chunks/es-CQzgvQI6.mjs +2 -0
- package/dist/chunks/es-CQzgvQI6.mjs.map +1 -0
- package/dist/chunks/es-CSteuqi5.mjs +2 -0
- package/dist/chunks/es-CSteuqi5.mjs.map +1 -0
- package/dist/chunks/es-ClJxqhu_.mjs +2 -0
- package/dist/chunks/es-ClJxqhu_.mjs.map +1 -0
- package/dist/chunks/es-CrmqYoVh.mjs +2 -0
- package/dist/chunks/es-CrmqYoVh.mjs.map +1 -0
- package/dist/chunks/es-CwRwLkfr.mjs +2 -0
- package/dist/chunks/es-CwRwLkfr.mjs.map +1 -0
- package/dist/chunks/es-D7DRGnkZ.mjs +2 -0
- package/dist/chunks/es-D7DRGnkZ.mjs.map +1 -0
- package/dist/chunks/es-DET1uMu-.mjs +2 -0
- package/dist/chunks/es-DET1uMu-.mjs.map +1 -0
- package/dist/chunks/es-Dj83hJxy.mjs +2 -0
- package/dist/chunks/es-Dj83hJxy.mjs.map +1 -0
- package/dist/chunks/es-DwYWucI6.mjs +2 -0
- package/dist/chunks/es-DwYWucI6.mjs.map +1 -0
- package/dist/chunks/es-DwrcpThR.mjs +2 -0
- package/dist/chunks/es-DwrcpThR.mjs.map +1 -0
- package/dist/chunks/es-z7xjgDdk.mjs +2 -0
- package/dist/chunks/es-z7xjgDdk.mjs.map +1 -0
- package/dist/chunks/fonts-CG5ZnGux.mjs +2 -0
- package/dist/chunks/fonts-CG5ZnGux.mjs.map +1 -0
- package/dist/chunks/fr-B73tOEzO.mjs +2 -0
- package/dist/chunks/fr-B73tOEzO.mjs.map +1 -0
- package/dist/chunks/fr-BEbsFEkX.mjs +2 -0
- package/dist/chunks/fr-BEbsFEkX.mjs.map +1 -0
- package/dist/chunks/fr-BFCaEBSV.mjs +2 -0
- package/dist/chunks/fr-BFCaEBSV.mjs.map +1 -0
- package/dist/chunks/fr-BJ69XrDO.mjs +2 -0
- package/dist/chunks/fr-BJ69XrDO.mjs.map +1 -0
- package/dist/chunks/fr-BdQ_-Iwg.mjs +2 -0
- package/dist/chunks/fr-BdQ_-Iwg.mjs.map +1 -0
- package/dist/chunks/fr-BhnuBA0i.mjs +2 -0
- package/dist/chunks/fr-BhnuBA0i.mjs.map +1 -0
- package/dist/chunks/fr-BiLmpXZ9.mjs +2 -0
- package/dist/chunks/fr-BiLmpXZ9.mjs.map +1 -0
- package/dist/chunks/fr-C1Pak7kS.mjs +2 -0
- package/dist/chunks/fr-C1Pak7kS.mjs.map +1 -0
- package/dist/chunks/fr-CFDoFELm.mjs +2 -0
- package/dist/chunks/fr-CFDoFELm.mjs.map +1 -0
- package/dist/chunks/fr-CmsH8BnY.mjs +2 -0
- package/dist/chunks/fr-CmsH8BnY.mjs.map +1 -0
- package/dist/chunks/fr-Cz2qWiuV.mjs +2 -0
- package/dist/chunks/fr-Cz2qWiuV.mjs.map +1 -0
- package/dist/chunks/fr-CzTPuD1P.mjs +2 -0
- package/dist/chunks/fr-CzTPuD1P.mjs.map +1 -0
- package/dist/chunks/fr-D1LQMsjB.mjs +2 -0
- package/dist/chunks/fr-D1LQMsjB.mjs.map +1 -0
- package/dist/chunks/fr-D84mXQrZ.mjs +2 -0
- package/dist/chunks/fr-D84mXQrZ.mjs.map +1 -0
- package/dist/chunks/fr-DX7z_ld0.mjs +2 -0
- package/dist/chunks/fr-DX7z_ld0.mjs.map +1 -0
- package/dist/chunks/fr-DXkQUerf.mjs +2 -0
- package/dist/chunks/fr-DXkQUerf.mjs.map +1 -0
- package/dist/chunks/fr-Di5gv5P8.mjs +2 -0
- package/dist/chunks/fr-Di5gv5P8.mjs.map +1 -0
- package/dist/chunks/fr-Dq5MrVWd.mjs +2 -0
- package/dist/chunks/fr-Dq5MrVWd.mjs.map +1 -0
- package/dist/chunks/fr-DtfEjLSL.mjs +2 -0
- package/dist/chunks/fr-DtfEjLSL.mjs.map +1 -0
- package/dist/chunks/fr-DvW-dpp3.mjs +2 -0
- package/dist/chunks/fr-DvW-dpp3.mjs.map +1 -0
- package/dist/chunks/fr-UJFNrn-V.mjs +2 -0
- package/dist/chunks/fr-UJFNrn-V.mjs.map +1 -0
- package/dist/chunks/fr-hK8X-sM6.mjs +2 -0
- package/dist/chunks/fr-hK8X-sM6.mjs.map +1 -0
- package/dist/chunks/fr-uuOSXj4L.mjs +2 -0
- package/dist/chunks/fr-uuOSXj4L.mjs.map +1 -0
- package/dist/chunks/full-216JgIG1.mjs +2 -0
- package/dist/chunks/full-216JgIG1.mjs.map +1 -0
- package/dist/chunks/hi-B2kXjElO.mjs +2 -0
- package/dist/chunks/hi-B2kXjElO.mjs.map +1 -0
- package/dist/chunks/hi-B2mEQ5gX.mjs +2 -0
- package/dist/chunks/hi-B2mEQ5gX.mjs.map +1 -0
- package/dist/chunks/hi-B61lTO2W.mjs +2 -0
- package/dist/chunks/hi-B61lTO2W.mjs.map +1 -0
- package/dist/chunks/hi-BD5HrbxU.mjs +2 -0
- package/dist/chunks/hi-BD5HrbxU.mjs.map +1 -0
- package/dist/chunks/hi-BHTvSWXw.mjs +2 -0
- package/dist/chunks/hi-BHTvSWXw.mjs.map +1 -0
- package/dist/chunks/hi-BYyaOBqY.mjs +2 -0
- package/dist/chunks/hi-BYyaOBqY.mjs.map +1 -0
- package/dist/chunks/hi-Bhlbz5gX.mjs +2 -0
- package/dist/chunks/hi-Bhlbz5gX.mjs.map +1 -0
- package/dist/chunks/hi-BniuSk3L.mjs +2 -0
- package/dist/chunks/hi-BniuSk3L.mjs.map +1 -0
- package/dist/chunks/hi-CBODdhOq.mjs +2 -0
- package/dist/chunks/hi-CBODdhOq.mjs.map +1 -0
- package/dist/chunks/hi-CKWQCooT.mjs +2 -0
- package/dist/chunks/hi-CKWQCooT.mjs.map +1 -0
- package/dist/chunks/hi-CkoruGVs.mjs +2 -0
- package/dist/chunks/hi-CkoruGVs.mjs.map +1 -0
- package/dist/chunks/hi-D6Ge3Lp5.mjs +2 -0
- package/dist/chunks/hi-D6Ge3Lp5.mjs.map +1 -0
- package/dist/chunks/hi-DEreeBFj.mjs +2 -0
- package/dist/chunks/hi-DEreeBFj.mjs.map +1 -0
- package/dist/chunks/hi-Dj4JW-9k.mjs +2 -0
- package/dist/chunks/hi-Dj4JW-9k.mjs.map +1 -0
- package/dist/chunks/hi-DkP4pHSX.mjs +2 -0
- package/dist/chunks/hi-DkP4pHSX.mjs.map +1 -0
- package/dist/chunks/hi-DknCX8Nx.mjs +2 -0
- package/dist/chunks/hi-DknCX8Nx.mjs.map +1 -0
- package/dist/chunks/hi-Dm1KJQQ5.mjs +2 -0
- package/dist/chunks/hi-Dm1KJQQ5.mjs.map +1 -0
- package/dist/chunks/hi-Dx-LTWg-.mjs +2 -0
- package/dist/chunks/hi-Dx-LTWg-.mjs.map +1 -0
- package/dist/chunks/hi-RDoZtwMm.mjs +2 -0
- package/dist/chunks/hi-RDoZtwMm.mjs.map +1 -0
- package/dist/chunks/hi-Tq9eDRk7.mjs +2 -0
- package/dist/chunks/hi-Tq9eDRk7.mjs.map +1 -0
- package/dist/chunks/hi-_vJ_Eo4p.mjs +2 -0
- package/dist/chunks/hi-_vJ_Eo4p.mjs.map +1 -0
- package/dist/chunks/hi-l8E-czFm.mjs +2 -0
- package/dist/chunks/hi-l8E-czFm.mjs.map +1 -0
- package/dist/chunks/hi-ydmPh3HB.mjs +2 -0
- package/dist/chunks/hi-ydmPh3HB.mjs.map +1 -0
- package/dist/chunks/minimal-D-QxXO1C.mjs +2 -0
- package/dist/chunks/minimal-D-QxXO1C.mjs.map +1 -0
- package/dist/chunks/pt-B4NUSLW8.mjs +2 -0
- package/dist/chunks/pt-B4NUSLW8.mjs.map +1 -0
- package/dist/chunks/pt-B8VKEboV.mjs +2 -0
- package/dist/chunks/pt-B8VKEboV.mjs.map +1 -0
- package/dist/chunks/pt-BMDKykEi.mjs +2 -0
- package/dist/chunks/pt-BMDKykEi.mjs.map +1 -0
- package/dist/chunks/pt-BmWE3xXF.mjs +2 -0
- package/dist/chunks/pt-BmWE3xXF.mjs.map +1 -0
- package/dist/chunks/pt-CJWKE1SW.mjs +2 -0
- package/dist/chunks/pt-CJWKE1SW.mjs.map +1 -0
- package/dist/chunks/pt-CKETXoPa.mjs +2 -0
- package/dist/chunks/pt-CKETXoPa.mjs.map +1 -0
- package/dist/chunks/pt-CKRs16QH.mjs +2 -0
- package/dist/chunks/pt-CKRs16QH.mjs.map +1 -0
- package/dist/chunks/pt-Cb-1GHq4.mjs +2 -0
- package/dist/chunks/pt-Cb-1GHq4.mjs.map +1 -0
- package/dist/chunks/pt-CgpU74p4.mjs +2 -0
- package/dist/chunks/pt-CgpU74p4.mjs.map +1 -0
- package/dist/chunks/pt-CtOdAphq.mjs +2 -0
- package/dist/chunks/pt-CtOdAphq.mjs.map +1 -0
- package/dist/chunks/pt-CzaPFMSx.mjs +2 -0
- package/dist/chunks/pt-CzaPFMSx.mjs.map +1 -0
- package/dist/chunks/pt-DGuLcW0m.mjs +2 -0
- package/dist/chunks/pt-DGuLcW0m.mjs.map +1 -0
- package/dist/chunks/pt-DHzSXzlf.mjs +2 -0
- package/dist/chunks/pt-DHzSXzlf.mjs.map +1 -0
- package/dist/chunks/pt-DWDdBfLk.mjs +2 -0
- package/dist/chunks/pt-DWDdBfLk.mjs.map +1 -0
- package/dist/chunks/pt-DZ6Liq_x.mjs +2 -0
- package/dist/chunks/pt-DZ6Liq_x.mjs.map +1 -0
- package/dist/chunks/pt-D_MD7MJu.mjs +2 -0
- package/dist/chunks/pt-D_MD7MJu.mjs.map +1 -0
- package/dist/chunks/pt-DgaY_yNG.mjs +2 -0
- package/dist/chunks/pt-DgaY_yNG.mjs.map +1 -0
- package/dist/chunks/pt-DgzgCxdH.mjs +2 -0
- package/dist/chunks/pt-DgzgCxdH.mjs.map +1 -0
- package/dist/chunks/pt-Dh7nUcAM.mjs +2 -0
- package/dist/chunks/pt-Dh7nUcAM.mjs.map +1 -0
- package/dist/chunks/pt-P914L5AX.mjs +2 -0
- package/dist/chunks/pt-P914L5AX.mjs.map +1 -0
- package/dist/chunks/pt-XT1vsWZj.mjs +2 -0
- package/dist/chunks/pt-XT1vsWZj.mjs.map +1 -0
- package/dist/chunks/pt-jJ0XXSVz.mjs +2 -0
- package/dist/chunks/pt-jJ0XXSVz.mjs.map +1 -0
- package/dist/chunks/pt-tuOLwYkM.mjs +2 -0
- package/dist/chunks/pt-tuOLwYkM.mjs.map +1 -0
- package/dist/chunks/rolldown-runtime-B8Ku5yk6.mjs +1 -0
- package/dist/chunks/ru-7m8CMM17.mjs +2 -0
- package/dist/chunks/ru-7m8CMM17.mjs.map +1 -0
- package/dist/chunks/ru-9Qh1fR-K.mjs +2 -0
- package/dist/chunks/ru-9Qh1fR-K.mjs.map +1 -0
- package/dist/chunks/ru-B5gK8OLp.mjs +2 -0
- package/dist/chunks/ru-B5gK8OLp.mjs.map +1 -0
- package/dist/chunks/ru-BRNN6ldH.mjs +2 -0
- package/dist/chunks/ru-BRNN6ldH.mjs.map +1 -0
- package/dist/chunks/ru-BiyE9o-D.mjs +2 -0
- package/dist/chunks/ru-BiyE9o-D.mjs.map +1 -0
- package/dist/chunks/ru-BpGTIPbv.mjs +2 -0
- package/dist/chunks/ru-BpGTIPbv.mjs.map +1 -0
- package/dist/chunks/ru-CAzMaI4y.mjs +2 -0
- package/dist/chunks/ru-CAzMaI4y.mjs.map +1 -0
- package/dist/chunks/ru-COo6HpcD.mjs +2 -0
- package/dist/chunks/ru-COo6HpcD.mjs.map +1 -0
- package/dist/chunks/ru-CgEOZsUs.mjs +2 -0
- package/dist/chunks/ru-CgEOZsUs.mjs.map +1 -0
- package/dist/chunks/ru-CptzezhV.mjs +2 -0
- package/dist/chunks/ru-CptzezhV.mjs.map +1 -0
- package/dist/chunks/ru-Ct0qNMLS.mjs +2 -0
- package/dist/chunks/ru-Ct0qNMLS.mjs.map +1 -0
- package/dist/chunks/ru-Ct2IrzbA.mjs +2 -0
- package/dist/chunks/ru-Ct2IrzbA.mjs.map +1 -0
- package/dist/chunks/ru-CyHnlWLN.mjs +2 -0
- package/dist/chunks/ru-CyHnlWLN.mjs.map +1 -0
- package/dist/chunks/ru-DF0vhzeC.mjs +2 -0
- package/dist/chunks/ru-DF0vhzeC.mjs.map +1 -0
- package/dist/chunks/ru-DH6rsOWL.mjs +2 -0
- package/dist/chunks/ru-DH6rsOWL.mjs.map +1 -0
- package/dist/chunks/ru-DHH8k6G8.mjs +2 -0
- package/dist/chunks/ru-DHH8k6G8.mjs.map +1 -0
- package/dist/chunks/ru-GVReqjM4.mjs +2 -0
- package/dist/chunks/ru-GVReqjM4.mjs.map +1 -0
- package/dist/chunks/ru-IzloX5CY.mjs +2 -0
- package/dist/chunks/ru-IzloX5CY.mjs.map +1 -0
- package/dist/chunks/ru-ZrzXB0f6.mjs +2 -0
- package/dist/chunks/ru-ZrzXB0f6.mjs.map +1 -0
- package/dist/chunks/ru-asRKygvE.mjs +2 -0
- package/dist/chunks/ru-asRKygvE.mjs.map +1 -0
- package/dist/chunks/ru-m19l8nRA.mjs +2 -0
- package/dist/chunks/ru-m19l8nRA.mjs.map +1 -0
- package/dist/chunks/ru-vfQ5Xaz4.mjs +2 -0
- package/dist/chunks/ru-vfQ5Xaz4.mjs.map +1 -0
- package/dist/chunks/ru-wVOlNily.mjs +2 -0
- package/dist/chunks/ru-wVOlNily.mjs.map +1 -0
- package/dist/chunks/shared-DxmfXZH7.mjs +2 -0
- package/dist/chunks/shared-DxmfXZH7.mjs.map +1 -0
- package/dist/chunks/src-DFXIsulM.mjs +2 -0
- package/dist/chunks/src-DFXIsulM.mjs.map +1 -0
- package/dist/chunks/text-direction-advanced-B5JuIs0P.mjs +2 -0
- package/dist/chunks/text-direction-advanced-B5JuIs0P.mjs.map +1 -0
- package/dist/chunks/zh-0uhsRxfq.mjs +2 -0
- package/dist/chunks/zh-0uhsRxfq.mjs.map +1 -0
- package/dist/chunks/zh-1BrLr5Wk.mjs +2 -0
- package/dist/chunks/zh-1BrLr5Wk.mjs.map +1 -0
- package/dist/chunks/zh-BNHeXa_M.mjs +2 -0
- package/dist/chunks/zh-BNHeXa_M.mjs.map +1 -0
- package/dist/chunks/zh-BOpBzSX3.mjs +2 -0
- package/dist/chunks/zh-BOpBzSX3.mjs.map +1 -0
- package/dist/chunks/zh-BV2uDDGf.mjs +2 -0
- package/dist/chunks/zh-BV2uDDGf.mjs.map +1 -0
- package/dist/chunks/zh-BkoPteNb.mjs +2 -0
- package/dist/chunks/zh-BkoPteNb.mjs.map +1 -0
- package/dist/chunks/zh-C2z0g7OC.mjs +2 -0
- package/dist/chunks/zh-C2z0g7OC.mjs.map +1 -0
- package/dist/chunks/zh-CeJw45yo.mjs +2 -0
- package/dist/chunks/zh-CeJw45yo.mjs.map +1 -0
- package/dist/chunks/zh-CwVkxL4q.mjs +2 -0
- package/dist/chunks/zh-CwVkxL4q.mjs.map +1 -0
- package/dist/chunks/zh-Cy7mujpx.mjs +2 -0
- package/dist/chunks/zh-Cy7mujpx.mjs.map +1 -0
- package/dist/chunks/zh-D-P00ENX.mjs +2 -0
- package/dist/chunks/zh-D-P00ENX.mjs.map +1 -0
- package/dist/chunks/zh-D5d-NAuv.mjs +2 -0
- package/dist/chunks/zh-D5d-NAuv.mjs.map +1 -0
- package/dist/chunks/zh-D6gTQA2W.mjs +2 -0
- package/dist/chunks/zh-D6gTQA2W.mjs.map +1 -0
- package/dist/chunks/zh-DLwq4e4-.mjs +2 -0
- package/dist/chunks/zh-DLwq4e4-.mjs.map +1 -0
- package/dist/chunks/zh-D_Yb8Eg6.mjs +2 -0
- package/dist/chunks/zh-D_Yb8Eg6.mjs.map +1 -0
- package/dist/chunks/zh-DaNHqNDY.mjs +2 -0
- package/dist/chunks/zh-DaNHqNDY.mjs.map +1 -0
- package/dist/chunks/zh-De7-Y4O5.mjs +2 -0
- package/dist/chunks/zh-De7-Y4O5.mjs.map +1 -0
- package/dist/chunks/zh-Dj7kHEcp.mjs +2 -0
- package/dist/chunks/zh-Dj7kHEcp.mjs.map +1 -0
- package/dist/chunks/zh-Dl0oVWiK.mjs +2 -0
- package/dist/chunks/zh-Dl0oVWiK.mjs.map +1 -0
- package/dist/chunks/zh-Do0plBjM.mjs +2 -0
- package/dist/chunks/zh-Do0plBjM.mjs.map +1 -0
- package/dist/chunks/zh-Q0aDk5UA.mjs +2 -0
- package/dist/chunks/zh-Q0aDk5UA.mjs.map +1 -0
- package/dist/chunks/zh-eSgs8mzc.mjs +2 -0
- package/dist/chunks/zh-eSgs8mzc.mjs.map +1 -0
- package/dist/chunks/zh-giWyGMSZ.mjs +2 -0
- package/dist/chunks/zh-giWyGMSZ.mjs.map +1 -0
- package/dist/commands/BlockInsertion.d.ts.map +1 -1
- package/dist/commands/CommandHelpers.d.ts +13 -2
- package/dist/commands/CommandHelpers.d.ts.map +1 -1
- package/dist/commands/NodeSelectionCommands.d.ts +3 -8
- package/dist/commands/NodeSelectionCommands.d.ts.map +1 -1
- package/dist/editor/ContentSerializer.d.ts.map +1 -1
- package/dist/editor/EditorConfig.d.ts +50 -0
- package/dist/editor/EditorConfig.d.ts.map +1 -0
- package/dist/editor/EditorConfigController.d.ts +1 -1
- package/dist/editor/EditorConfigController.d.ts.map +1 -1
- package/dist/editor/EditorDOM.d.ts.map +1 -1
- package/dist/editor/EditorInitializer.d.ts +37 -0
- package/dist/editor/EditorInitializer.d.ts.map +1 -0
- package/dist/editor/EditorLifecycleCoordinator.d.ts +6 -1
- package/dist/editor/EditorLifecycleCoordinator.d.ts.map +1 -1
- package/dist/editor/NotectlEditor.d.ts +13 -51
- package/dist/editor/NotectlEditor.d.ts.map +1 -1
- package/dist/editor/PluginBootstrapper.d.ts +1 -1
- package/dist/editor/PluginBootstrapper.d.ts.map +1 -1
- package/dist/fonts.mjs +1 -2
- package/dist/full.mjs +1 -2
- package/dist/html.mjs +1 -2
- package/dist/input/ClipboardHandler.d.ts +5 -0
- package/dist/input/ClipboardHandler.d.ts.map +1 -1
- package/dist/input/HTMLParser.d.ts +9 -5
- package/dist/input/HTMLParser.d.ts.map +1 -1
- package/dist/input/InputHandler.d.ts +1 -0
- package/dist/input/InputHandler.d.ts.map +1 -1
- package/dist/input/PasteHTMLHandler.d.ts +25 -0
- package/dist/input/PasteHTMLHandler.d.ts.map +1 -0
- package/dist/input/PasteHandler.d.ts +2 -27
- package/dist/input/PasteHandler.d.ts.map +1 -1
- package/dist/input/PasteRichBlockHandler.d.ts +23 -0
- package/dist/input/PasteRichBlockHandler.d.ts.map +1 -0
- package/dist/input/SelectionDocument.d.ts +10 -0
- package/dist/input/SelectionDocument.d.ts.map +1 -0
- package/dist/model/RichBlockData.d.ts +12 -2
- package/dist/model/RichBlockData.d.ts.map +1 -1
- package/dist/notectl-core.mjs +1 -2
- package/dist/notectl-core.umd.js +2 -2
- package/dist/notectl-core.umd.js.map +1 -1
- package/dist/plugins/PluginContextFactory.d.ts +73 -0
- package/dist/plugins/PluginContextFactory.d.ts.map +1 -0
- package/dist/plugins/PluginManager.d.ts +5 -0
- package/dist/plugins/PluginManager.d.ts.map +1 -1
- package/dist/plugins/alignment.mjs +1 -2
- package/dist/plugins/blockquote.mjs +1 -2
- package/dist/plugins/caret-navigation.mjs +1 -2
- package/dist/plugins/code-block.mjs +1 -2
- package/dist/plugins/font-size.mjs +1 -2
- package/dist/plugins/font.mjs +1 -2
- package/dist/plugins/gap-cursor.mjs +1 -2
- package/dist/plugins/hard-break.mjs +1 -2
- package/dist/plugins/heading.mjs +1 -2
- package/dist/plugins/highlight.mjs +1 -2
- package/dist/plugins/horizontal-rule.mjs +1 -2
- package/dist/plugins/image/ImageCommands.d.ts.map +1 -1
- package/dist/plugins/image.mjs +1 -2
- package/dist/plugins/link.mjs +1 -2
- package/dist/plugins/list.mjs +1 -2
- package/dist/plugins/print/PrintContentPreparer.d.ts.map +1 -1
- package/dist/plugins/print.mjs +1 -2
- package/dist/plugins/shared/PopupManager.d.ts.map +1 -1
- package/dist/plugins/shared.mjs +1 -2
- package/dist/plugins/smart-paste.mjs +1 -2
- package/dist/plugins/strikethrough.mjs +1 -2
- package/dist/plugins/super-sub.mjs +1 -2
- package/dist/plugins/table/TableCommands.d.ts +1 -0
- package/dist/plugins/table/TableCommands.d.ts.map +1 -1
- package/dist/plugins/table/TableContextMenu.d.ts.map +1 -1
- package/dist/plugins/table/TableSelection.d.ts.map +1 -1
- package/dist/plugins/table.mjs +1 -2
- package/dist/plugins/text-color.mjs +1 -2
- package/dist/plugins/text-direction-advanced.mjs +1 -2
- package/dist/plugins/text-direction.mjs +1 -2
- package/dist/plugins/text-formatting.mjs +1 -2
- package/dist/plugins/toolbar/ToolbarOverflowController.d.ts +2 -0
- package/dist/plugins/toolbar/ToolbarOverflowController.d.ts.map +1 -1
- package/dist/plugins/toolbar.mjs +1 -2
- package/dist/presets/full.mjs +1 -2
- package/dist/presets/minimal.mjs +1 -2
- package/dist/presets.mjs +1 -2
- package/dist/state/StepInversion.d.ts.map +1 -1
- package/dist/view/EditorView.d.ts +8 -58
- package/dist/view/EditorView.d.ts.map +1 -1
- package/dist/view/EditorViewEvents.d.ts +54 -0
- package/dist/view/EditorViewEvents.d.ts.map +1 -0
- package/dist/view/EditorViewNavigation.d.ts +47 -0
- package/dist/view/EditorViewNavigation.d.ts.map +1 -0
- package/dist/view/SelectionSync.d.ts.map +1 -1
- package/package.json +5 -5
- package/dist/chunks/AttrRegistry-Ckj9eCHj.mjs +0 -2
- package/dist/chunks/AttrRegistry-Ckj9eCHj.mjs.map +0 -1
- package/dist/chunks/AttributedMarkCommands-x7h4Xy7V.mjs +0 -2
- package/dist/chunks/AttributedMarkCommands-x7h4Xy7V.mjs.map +0 -1
- package/dist/chunks/BlockInsertion-zPxm6oa_.mjs +0 -2
- package/dist/chunks/BlockInsertion-zPxm6oa_.mjs.map +0 -1
- package/dist/chunks/BlockTypePickerRegistry-DcSE6IXB.mjs +0 -2
- package/dist/chunks/BlockTypePickerRegistry-DcSE6IXB.mjs.map +0 -1
- package/dist/chunks/ColorGrid-CpkbKfXg.mjs +0 -2
- package/dist/chunks/ColorGrid-CpkbKfXg.mjs.map +0 -1
- package/dist/chunks/ColorPickerPopup-CDUvkgcK.mjs +0 -2
- package/dist/chunks/ColorPickerPopup-CDUvkgcK.mjs.map +0 -1
- package/dist/chunks/ColorValidation-DCSKq9B2.mjs +0 -2
- package/dist/chunks/ColorValidation-DCSKq9B2.mjs.map +0 -1
- package/dist/chunks/Commands-DwXBBVGR.mjs +0 -2
- package/dist/chunks/Commands-DwXBBVGR.mjs.map +0 -1
- package/dist/chunks/Decoration-D49mFXrH.mjs +0 -2
- package/dist/chunks/Decoration-D49mFXrH.mjs.map +0 -1
- package/dist/chunks/Document-HC8s50qJ.mjs +0 -2
- package/dist/chunks/Document-HC8s50qJ.mjs.map +0 -1
- package/dist/chunks/DocumentParser-w70-Axud.mjs +0 -2
- package/dist/chunks/DocumentParser-w70-Axud.mjs.map +0 -1
- package/dist/chunks/DomUtils-CznMAZZg.mjs +0 -2
- package/dist/chunks/DomUtils-CznMAZZg.mjs.map +0 -1
- package/dist/chunks/HTMLUtils-Cxy99Ak2.mjs +0 -2
- package/dist/chunks/HTMLUtils-Cxy99Ak2.mjs.map +0 -1
- package/dist/chunks/HeadingPlugin-B-LF-AMM.mjs +0 -2
- package/dist/chunks/HeadingPlugin-B-LF-AMM.mjs.map +0 -1
- package/dist/chunks/KeyboardNav-DsYhKKuV.mjs +0 -2
- package/dist/chunks/KeyboardNav-DsYhKKuV.mjs.map +0 -1
- package/dist/chunks/MarkCommands-CTuVDqnn.mjs +0 -2
- package/dist/chunks/MarkCommands-CTuVDqnn.mjs.map +0 -1
- package/dist/chunks/NavigationQueries-DCOv4Ca5.mjs +0 -2
- package/dist/chunks/NavigationQueries-DCOv4Ca5.mjs.map +0 -1
- package/dist/chunks/NotectlEditor-DBBJkPCW.mjs +0 -3
- package/dist/chunks/NotectlEditor-DBBJkPCW.mjs.map +0 -1
- package/dist/chunks/Platform-CU6itXZo.mjs +0 -2
- package/dist/chunks/Platform-CU6itXZo.mjs.map +0 -1
- package/dist/chunks/PluginHelpers-CdPR0MuT.mjs +0 -2
- package/dist/chunks/PluginHelpers-CdPR0MuT.mjs.map +0 -1
- package/dist/chunks/PopupManager-Du3dYnsJ.mjs +0 -2
- package/dist/chunks/PopupManager-Du3dYnsJ.mjs.map +0 -1
- package/dist/chunks/PopupPositioning-DtvqMSop.mjs +0 -2
- package/dist/chunks/PopupPositioning-DtvqMSop.mjs.map +0 -1
- package/dist/chunks/PrintTypes-DukwDSWS.mjs +0 -2
- package/dist/chunks/PrintTypes-DukwDSWS.mjs.map +0 -1
- package/dist/chunks/RangeIterator-CprUbOWv.mjs +0 -2
- package/dist/chunks/RangeIterator-CprUbOWv.mjs.map +0 -1
- package/dist/chunks/Selection-DhbizDM4.mjs +0 -2
- package/dist/chunks/Selection-DhbizDM4.mjs.map +0 -1
- package/dist/chunks/SelectionTransactions-DB3YDIEa.mjs +0 -2
- package/dist/chunks/SelectionTransactions-DB3YDIEa.mjs.map +0 -1
- package/dist/chunks/ShortcutFormatting-BLKS0Gys.mjs +0 -2
- package/dist/chunks/ShortcutFormatting-BLKS0Gys.mjs.map +0 -1
- package/dist/chunks/StyleRuntime-BmsLoEa8.mjs +0 -2
- package/dist/chunks/StyleRuntime-BmsLoEa8.mjs.map +0 -1
- package/dist/chunks/TextDirectionLocale-BraFI9JF.mjs +0 -2
- package/dist/chunks/TextDirectionLocale-BraFI9JF.mjs.map +0 -1
- package/dist/chunks/TypeBrands-Bp_Z_o5Y.mjs +0 -2
- package/dist/chunks/TypeBrands-Bp_Z_o5Y.mjs.map +0 -1
- package/dist/chunks/XmlPatterns-DxQXGjP8.mjs +0 -2
- package/dist/chunks/XmlPatterns-DxQXGjP8.mjs.map +0 -1
- package/dist/chunks/ar-B93SPJT7.mjs +0 -2
- package/dist/chunks/ar-B93SPJT7.mjs.map +0 -1
- package/dist/chunks/ar-BAmGa08u.mjs +0 -2
- package/dist/chunks/ar-BAmGa08u.mjs.map +0 -1
- package/dist/chunks/ar-BYNFEVLc.mjs +0 -2
- package/dist/chunks/ar-BYNFEVLc.mjs.map +0 -1
- package/dist/chunks/ar-Bnc7y8BP.mjs +0 -2
- package/dist/chunks/ar-Bnc7y8BP.mjs.map +0 -1
- package/dist/chunks/ar-Bp3rDZky.mjs +0 -2
- package/dist/chunks/ar-Bp3rDZky.mjs.map +0 -1
- package/dist/chunks/ar-BtOQ7lro.mjs +0 -2
- package/dist/chunks/ar-BtOQ7lro.mjs.map +0 -1
- package/dist/chunks/ar-C5JEHhw9.mjs +0 -2
- package/dist/chunks/ar-C5JEHhw9.mjs.map +0 -1
- package/dist/chunks/ar-CL3QL0tw.mjs +0 -2
- package/dist/chunks/ar-CL3QL0tw.mjs.map +0 -1
- package/dist/chunks/ar-CYtG-XlN.mjs +0 -2
- package/dist/chunks/ar-CYtG-XlN.mjs.map +0 -1
- package/dist/chunks/ar-CzVj8p__.mjs +0 -2
- package/dist/chunks/ar-CzVj8p__.mjs.map +0 -1
- package/dist/chunks/ar-D7PS3e2g.mjs +0 -2
- package/dist/chunks/ar-D7PS3e2g.mjs.map +0 -1
- package/dist/chunks/ar-D8adM2Uy.mjs +0 -2
- package/dist/chunks/ar-D8adM2Uy.mjs.map +0 -1
- package/dist/chunks/ar-D9jyShaB.mjs +0 -2
- package/dist/chunks/ar-D9jyShaB.mjs.map +0 -1
- package/dist/chunks/ar-DR6OA3ZO.mjs +0 -2
- package/dist/chunks/ar-DR6OA3ZO.mjs.map +0 -1
- package/dist/chunks/ar-Deibepjm.mjs +0 -2
- package/dist/chunks/ar-Deibepjm.mjs.map +0 -1
- package/dist/chunks/ar-Dlb5riUN.mjs +0 -2
- package/dist/chunks/ar-Dlb5riUN.mjs.map +0 -1
- package/dist/chunks/ar-DmmxE2W7.mjs +0 -2
- package/dist/chunks/ar-DmmxE2W7.mjs.map +0 -1
- package/dist/chunks/ar-Ds6Z2Gzf.mjs +0 -2
- package/dist/chunks/ar-Ds6Z2Gzf.mjs.map +0 -1
- package/dist/chunks/ar-DtIHQ8nU.mjs +0 -2
- package/dist/chunks/ar-DtIHQ8nU.mjs.map +0 -1
- package/dist/chunks/ar-J8B-on-0.mjs +0 -2
- package/dist/chunks/ar-J8B-on-0.mjs.map +0 -1
- package/dist/chunks/ar-b6VdnxAs.mjs +0 -2
- package/dist/chunks/ar-b6VdnxAs.mjs.map +0 -1
- package/dist/chunks/ar-iU02mRe5.mjs +0 -2
- package/dist/chunks/ar-iU02mRe5.mjs.map +0 -1
- package/dist/chunks/ar-mSCYQYnL.mjs +0 -2
- package/dist/chunks/ar-mSCYQYnL.mjs.map +0 -1
- package/dist/chunks/color-picker-Byjl_xr9.mjs +0 -2
- package/dist/chunks/color-picker-Byjl_xr9.mjs.map +0 -1
- package/dist/chunks/de-8aCC5jBM.mjs +0 -2
- package/dist/chunks/de-8aCC5jBM.mjs.map +0 -1
- package/dist/chunks/de-B4y4ndUw.mjs +0 -2
- package/dist/chunks/de-B4y4ndUw.mjs.map +0 -1
- package/dist/chunks/de-B5fcZ0FQ.mjs +0 -2
- package/dist/chunks/de-B5fcZ0FQ.mjs.map +0 -1
- package/dist/chunks/de-BT9VmwoJ.mjs +0 -2
- package/dist/chunks/de-BT9VmwoJ.mjs.map +0 -1
- package/dist/chunks/de-BZWSyJTG.mjs +0 -2
- package/dist/chunks/de-BZWSyJTG.mjs.map +0 -1
- package/dist/chunks/de-CFD_Wgik.mjs +0 -2
- package/dist/chunks/de-CFD_Wgik.mjs.map +0 -1
- package/dist/chunks/de-CLYtb6kD.mjs +0 -2
- package/dist/chunks/de-CLYtb6kD.mjs.map +0 -1
- package/dist/chunks/de-CP5v-98M.mjs +0 -2
- package/dist/chunks/de-CP5v-98M.mjs.map +0 -1
- package/dist/chunks/de-CYJ6uWno.mjs +0 -2
- package/dist/chunks/de-CYJ6uWno.mjs.map +0 -1
- package/dist/chunks/de-ChcKkF7A.mjs +0 -2
- package/dist/chunks/de-ChcKkF7A.mjs.map +0 -1
- package/dist/chunks/de-CicoU066.mjs +0 -2
- package/dist/chunks/de-CicoU066.mjs.map +0 -1
- package/dist/chunks/de-CjLAdBt2.mjs +0 -2
- package/dist/chunks/de-CjLAdBt2.mjs.map +0 -1
- package/dist/chunks/de-CtFvAXwF.mjs +0 -2
- package/dist/chunks/de-CtFvAXwF.mjs.map +0 -1
- package/dist/chunks/de-D1OAXtxJ.mjs +0 -2
- package/dist/chunks/de-D1OAXtxJ.mjs.map +0 -1
- package/dist/chunks/de-DBbzCQrm.mjs +0 -2
- package/dist/chunks/de-DBbzCQrm.mjs.map +0 -1
- package/dist/chunks/de-DOLwx_M7.mjs +0 -2
- package/dist/chunks/de-DOLwx_M7.mjs.map +0 -1
- package/dist/chunks/de-De2miMxo.mjs +0 -2
- package/dist/chunks/de-De2miMxo.mjs.map +0 -1
- package/dist/chunks/de-OTfhhinm.mjs +0 -2
- package/dist/chunks/de-OTfhhinm.mjs.map +0 -1
- package/dist/chunks/de-PZ9-LlBp.mjs +0 -2
- package/dist/chunks/de-PZ9-LlBp.mjs.map +0 -1
- package/dist/chunks/de-UREymH-5.mjs +0 -2
- package/dist/chunks/de-UREymH-5.mjs.map +0 -1
- package/dist/chunks/de-chYdoK9q.mjs +0 -2
- package/dist/chunks/de-chYdoK9q.mjs.map +0 -1
- package/dist/chunks/de-fXvs5vQT.mjs +0 -2
- package/dist/chunks/de-fXvs5vQT.mjs.map +0 -1
- package/dist/chunks/de-xJh5C_pk.mjs +0 -2
- package/dist/chunks/de-xJh5C_pk.mjs.map +0 -1
- package/dist/chunks/es-B9UhsaEI.mjs +0 -2
- package/dist/chunks/es-B9UhsaEI.mjs.map +0 -1
- package/dist/chunks/es-BHGwPgrP.mjs +0 -2
- package/dist/chunks/es-BHGwPgrP.mjs.map +0 -1
- package/dist/chunks/es-BTqy_aQ4.mjs +0 -2
- package/dist/chunks/es-BTqy_aQ4.mjs.map +0 -1
- package/dist/chunks/es-BbGOZGS_.mjs +0 -2
- package/dist/chunks/es-BbGOZGS_.mjs.map +0 -1
- package/dist/chunks/es-BjPsub0k.mjs +0 -2
- package/dist/chunks/es-BjPsub0k.mjs.map +0 -1
- package/dist/chunks/es-Bk0bRDFE.mjs +0 -2
- package/dist/chunks/es-Bk0bRDFE.mjs.map +0 -1
- package/dist/chunks/es-BkS6DsrM.mjs +0 -2
- package/dist/chunks/es-BkS6DsrM.mjs.map +0 -1
- package/dist/chunks/es-BzEpr4Bk.mjs +0 -2
- package/dist/chunks/es-BzEpr4Bk.mjs.map +0 -1
- package/dist/chunks/es-C2lnWyA0.mjs +0 -2
- package/dist/chunks/es-C2lnWyA0.mjs.map +0 -1
- package/dist/chunks/es-C7e35Muh.mjs +0 -2
- package/dist/chunks/es-C7e35Muh.mjs.map +0 -1
- package/dist/chunks/es-CBk43isB.mjs +0 -2
- package/dist/chunks/es-CBk43isB.mjs.map +0 -1
- package/dist/chunks/es-CE8t9fuM.mjs +0 -2
- package/dist/chunks/es-CE8t9fuM.mjs.map +0 -1
- package/dist/chunks/es-CFjzqIbS.mjs +0 -2
- package/dist/chunks/es-CFjzqIbS.mjs.map +0 -1
- package/dist/chunks/es-Ce-AEYxc.mjs +0 -2
- package/dist/chunks/es-Ce-AEYxc.mjs.map +0 -1
- package/dist/chunks/es-Co4AJr8Y.mjs +0 -2
- package/dist/chunks/es-Co4AJr8Y.mjs.map +0 -1
- package/dist/chunks/es-Cu5_OA4X.mjs +0 -2
- package/dist/chunks/es-Cu5_OA4X.mjs.map +0 -1
- package/dist/chunks/es-Cud6JXHf.mjs +0 -2
- package/dist/chunks/es-Cud6JXHf.mjs.map +0 -1
- package/dist/chunks/es-D-II7LZC.mjs +0 -2
- package/dist/chunks/es-D-II7LZC.mjs.map +0 -1
- package/dist/chunks/es-DBBSeOaD.mjs +0 -2
- package/dist/chunks/es-DBBSeOaD.mjs.map +0 -1
- package/dist/chunks/es-DCwjeUUu.mjs +0 -2
- package/dist/chunks/es-DCwjeUUu.mjs.map +0 -1
- package/dist/chunks/es-DvgH3-WZ.mjs +0 -2
- package/dist/chunks/es-DvgH3-WZ.mjs.map +0 -1
- package/dist/chunks/es-MgguVgIs.mjs +0 -2
- package/dist/chunks/es-MgguVgIs.mjs.map +0 -1
- package/dist/chunks/es-yXjjcxgb.mjs +0 -2
- package/dist/chunks/es-yXjjcxgb.mjs.map +0 -1
- package/dist/chunks/fr-B-_yKIAY.mjs +0 -2
- package/dist/chunks/fr-B-_yKIAY.mjs.map +0 -1
- package/dist/chunks/fr-BGyF2ym0.mjs +0 -2
- package/dist/chunks/fr-BGyF2ym0.mjs.map +0 -1
- package/dist/chunks/fr-BoRJ3B2-.mjs +0 -2
- package/dist/chunks/fr-BoRJ3B2-.mjs.map +0 -1
- package/dist/chunks/fr-BrKk4SPg.mjs +0 -2
- package/dist/chunks/fr-BrKk4SPg.mjs.map +0 -1
- package/dist/chunks/fr-C-y09LKg.mjs +0 -2
- package/dist/chunks/fr-C-y09LKg.mjs.map +0 -1
- package/dist/chunks/fr-C1W7jyd6.mjs +0 -2
- package/dist/chunks/fr-C1W7jyd6.mjs.map +0 -1
- package/dist/chunks/fr-C8CtmWBj.mjs +0 -2
- package/dist/chunks/fr-C8CtmWBj.mjs.map +0 -1
- package/dist/chunks/fr-C9oiPW0k.mjs +0 -2
- package/dist/chunks/fr-C9oiPW0k.mjs.map +0 -1
- package/dist/chunks/fr-CEkk4UyZ.mjs +0 -2
- package/dist/chunks/fr-CEkk4UyZ.mjs.map +0 -1
- package/dist/chunks/fr-Ccaetiwi.mjs +0 -2
- package/dist/chunks/fr-Ccaetiwi.mjs.map +0 -1
- package/dist/chunks/fr-Ccku5KzA.mjs +0 -2
- package/dist/chunks/fr-Ccku5KzA.mjs.map +0 -1
- package/dist/chunks/fr-CfUg1FxU.mjs +0 -2
- package/dist/chunks/fr-CfUg1FxU.mjs.map +0 -1
- package/dist/chunks/fr-DDkBcjmO.mjs +0 -2
- package/dist/chunks/fr-DDkBcjmO.mjs.map +0 -1
- package/dist/chunks/fr-DNwLChcm.mjs +0 -2
- package/dist/chunks/fr-DNwLChcm.mjs.map +0 -1
- package/dist/chunks/fr-DvneSjCf.mjs +0 -2
- package/dist/chunks/fr-DvneSjCf.mjs.map +0 -1
- package/dist/chunks/fr-Dx4Qqimj.mjs +0 -2
- package/dist/chunks/fr-Dx4Qqimj.mjs.map +0 -1
- package/dist/chunks/fr-RHXmueoO.mjs +0 -2
- package/dist/chunks/fr-RHXmueoO.mjs.map +0 -1
- package/dist/chunks/fr-VdiCNF4J.mjs +0 -2
- package/dist/chunks/fr-VdiCNF4J.mjs.map +0 -1
- package/dist/chunks/fr-Wiobfk5s.mjs +0 -2
- package/dist/chunks/fr-Wiobfk5s.mjs.map +0 -1
- package/dist/chunks/fr-YMiDtWuG.mjs +0 -2
- package/dist/chunks/fr-YMiDtWuG.mjs.map +0 -1
- package/dist/chunks/fr-_Oxf0k66.mjs +0 -2
- package/dist/chunks/fr-_Oxf0k66.mjs.map +0 -1
- package/dist/chunks/fr-gurfH-7T.mjs +0 -2
- package/dist/chunks/fr-gurfH-7T.mjs.map +0 -1
- package/dist/chunks/fr-zP7EjxDL.mjs +0 -2
- package/dist/chunks/fr-zP7EjxDL.mjs.map +0 -1
- package/dist/chunks/hi-B2W8pFqK.mjs +0 -2
- package/dist/chunks/hi-B2W8pFqK.mjs.map +0 -1
- package/dist/chunks/hi-B2m69ZCq.mjs +0 -2
- package/dist/chunks/hi-B2m69ZCq.mjs.map +0 -1
- package/dist/chunks/hi-BMIt3y_-.mjs +0 -2
- package/dist/chunks/hi-BMIt3y_-.mjs.map +0 -1
- package/dist/chunks/hi-BdtVhAzs.mjs +0 -2
- package/dist/chunks/hi-BdtVhAzs.mjs.map +0 -1
- package/dist/chunks/hi-BmkfaZpg.mjs +0 -2
- package/dist/chunks/hi-BmkfaZpg.mjs.map +0 -1
- package/dist/chunks/hi-C-l_R2SO.mjs +0 -2
- package/dist/chunks/hi-C-l_R2SO.mjs.map +0 -1
- package/dist/chunks/hi-C1LhM-oY.mjs +0 -2
- package/dist/chunks/hi-C1LhM-oY.mjs.map +0 -1
- package/dist/chunks/hi-CGEbGI1l.mjs +0 -2
- package/dist/chunks/hi-CGEbGI1l.mjs.map +0 -1
- package/dist/chunks/hi-CPuhj7IA.mjs +0 -2
- package/dist/chunks/hi-CPuhj7IA.mjs.map +0 -1
- package/dist/chunks/hi-CT5WERqi.mjs +0 -2
- package/dist/chunks/hi-CT5WERqi.mjs.map +0 -1
- package/dist/chunks/hi-CbLPPQ0b.mjs +0 -2
- package/dist/chunks/hi-CbLPPQ0b.mjs.map +0 -1
- package/dist/chunks/hi-ClvEtEKe.mjs +0 -2
- package/dist/chunks/hi-ClvEtEKe.mjs.map +0 -1
- package/dist/chunks/hi-CpBWHmYH.mjs +0 -2
- package/dist/chunks/hi-CpBWHmYH.mjs.map +0 -1
- package/dist/chunks/hi-DAfl8nU_.mjs +0 -2
- package/dist/chunks/hi-DAfl8nU_.mjs.map +0 -1
- package/dist/chunks/hi-DVof3w0y.mjs +0 -2
- package/dist/chunks/hi-DVof3w0y.mjs.map +0 -1
- package/dist/chunks/hi-DtlvSQkD.mjs +0 -2
- package/dist/chunks/hi-DtlvSQkD.mjs.map +0 -1
- package/dist/chunks/hi-FH3CAJuR.mjs +0 -2
- package/dist/chunks/hi-FH3CAJuR.mjs.map +0 -1
- package/dist/chunks/hi-Ga9h9a_1.mjs +0 -2
- package/dist/chunks/hi-Ga9h9a_1.mjs.map +0 -1
- package/dist/chunks/hi-Zc17M1T-.mjs +0 -2
- package/dist/chunks/hi-Zc17M1T-.mjs.map +0 -1
- package/dist/chunks/hi-g7i0bmig.mjs +0 -2
- package/dist/chunks/hi-g7i0bmig.mjs.map +0 -1
- package/dist/chunks/hi-js2P6byR.mjs +0 -2
- package/dist/chunks/hi-js2P6byR.mjs.map +0 -1
- package/dist/chunks/hi-ntUsOspQ.mjs +0 -2
- package/dist/chunks/hi-ntUsOspQ.mjs.map +0 -1
- package/dist/chunks/hi-yxAcR3w6.mjs +0 -2
- package/dist/chunks/hi-yxAcR3w6.mjs.map +0 -1
- package/dist/chunks/index-CVwf0cdH.mjs +0 -2
- package/dist/chunks/index-CVwf0cdH.mjs.map +0 -1
- package/dist/chunks/index-D3BZFsAD.mjs +0 -2
- package/dist/chunks/index-D3BZFsAD.mjs.map +0 -1
- package/dist/chunks/pt--IiroJQw.mjs +0 -2
- package/dist/chunks/pt--IiroJQw.mjs.map +0 -1
- package/dist/chunks/pt-BF72W8M5.mjs +0 -2
- package/dist/chunks/pt-BF72W8M5.mjs.map +0 -1
- package/dist/chunks/pt-BX_t4luI.mjs +0 -2
- package/dist/chunks/pt-BX_t4luI.mjs.map +0 -1
- package/dist/chunks/pt-B_XJ2s9X.mjs +0 -2
- package/dist/chunks/pt-B_XJ2s9X.mjs.map +0 -1
- package/dist/chunks/pt-C-Vp7Rxj.mjs +0 -2
- package/dist/chunks/pt-C-Vp7Rxj.mjs.map +0 -1
- package/dist/chunks/pt-CD2aCZXf.mjs +0 -2
- package/dist/chunks/pt-CD2aCZXf.mjs.map +0 -1
- package/dist/chunks/pt-CFjzqIbS.mjs +0 -2
- package/dist/chunks/pt-CFjzqIbS.mjs.map +0 -1
- package/dist/chunks/pt-CHjmBegF.mjs +0 -2
- package/dist/chunks/pt-CHjmBegF.mjs.map +0 -1
- package/dist/chunks/pt-CQRzEocL.mjs +0 -2
- package/dist/chunks/pt-CQRzEocL.mjs.map +0 -1
- package/dist/chunks/pt-Cem2WxUk.mjs +0 -2
- package/dist/chunks/pt-Cem2WxUk.mjs.map +0 -1
- package/dist/chunks/pt-D6kdF3fH.mjs +0 -2
- package/dist/chunks/pt-D6kdF3fH.mjs.map +0 -1
- package/dist/chunks/pt-DJfJVeY8.mjs +0 -2
- package/dist/chunks/pt-DJfJVeY8.mjs.map +0 -1
- package/dist/chunks/pt-DfB-IaYi.mjs +0 -2
- package/dist/chunks/pt-DfB-IaYi.mjs.map +0 -1
- package/dist/chunks/pt-DlNdH9pu.mjs +0 -2
- package/dist/chunks/pt-DlNdH9pu.mjs.map +0 -1
- package/dist/chunks/pt-DrJ0-8Yo.mjs +0 -2
- package/dist/chunks/pt-DrJ0-8Yo.mjs.map +0 -1
- package/dist/chunks/pt-DsBJpgpe.mjs +0 -2
- package/dist/chunks/pt-DsBJpgpe.mjs.map +0 -1
- package/dist/chunks/pt-DwdSYJzC.mjs +0 -2
- package/dist/chunks/pt-DwdSYJzC.mjs.map +0 -1
- package/dist/chunks/pt-Dx9UkZ3j.mjs +0 -2
- package/dist/chunks/pt-Dx9UkZ3j.mjs.map +0 -1
- package/dist/chunks/pt-K0BUlM9X.mjs +0 -2
- package/dist/chunks/pt-K0BUlM9X.mjs.map +0 -1
- package/dist/chunks/pt-TuA3_GDM.mjs +0 -2
- package/dist/chunks/pt-TuA3_GDM.mjs.map +0 -1
- package/dist/chunks/pt-cN6r-f7f.mjs +0 -2
- package/dist/chunks/pt-cN6r-f7f.mjs.map +0 -1
- package/dist/chunks/pt-uNGpVM3D.mjs +0 -2
- package/dist/chunks/pt-uNGpVM3D.mjs.map +0 -1
- package/dist/chunks/pt-v1E9u-Jx.mjs +0 -2
- package/dist/chunks/pt-v1E9u-Jx.mjs.map +0 -1
- package/dist/chunks/ru-0h51zrqE.mjs +0 -2
- package/dist/chunks/ru-0h51zrqE.mjs.map +0 -1
- package/dist/chunks/ru-4S8w6UN_.mjs +0 -2
- package/dist/chunks/ru-4S8w6UN_.mjs.map +0 -1
- package/dist/chunks/ru-B0cRw90L.mjs +0 -2
- package/dist/chunks/ru-B0cRw90L.mjs.map +0 -1
- package/dist/chunks/ru-B3O7WXNM.mjs +0 -2
- package/dist/chunks/ru-B3O7WXNM.mjs.map +0 -1
- package/dist/chunks/ru-B6zVAzvI.mjs +0 -2
- package/dist/chunks/ru-B6zVAzvI.mjs.map +0 -1
- package/dist/chunks/ru-B8teJin_.mjs +0 -2
- package/dist/chunks/ru-B8teJin_.mjs.map +0 -1
- package/dist/chunks/ru-BCriPw-8.mjs +0 -2
- package/dist/chunks/ru-BCriPw-8.mjs.map +0 -1
- package/dist/chunks/ru-BNOU16E5.mjs +0 -2
- package/dist/chunks/ru-BNOU16E5.mjs.map +0 -1
- package/dist/chunks/ru-BO6BIS5W.mjs +0 -2
- package/dist/chunks/ru-BO6BIS5W.mjs.map +0 -1
- package/dist/chunks/ru-Bdy1lLuc.mjs +0 -2
- package/dist/chunks/ru-Bdy1lLuc.mjs.map +0 -1
- package/dist/chunks/ru-BgBctNVm.mjs +0 -2
- package/dist/chunks/ru-BgBctNVm.mjs.map +0 -1
- package/dist/chunks/ru-CNLx7T3O.mjs +0 -2
- package/dist/chunks/ru-CNLx7T3O.mjs.map +0 -1
- package/dist/chunks/ru-CVSCT776.mjs +0 -2
- package/dist/chunks/ru-CVSCT776.mjs.map +0 -1
- package/dist/chunks/ru-CZvkdGnf.mjs +0 -2
- package/dist/chunks/ru-CZvkdGnf.mjs.map +0 -1
- package/dist/chunks/ru-CegMPuML.mjs +0 -2
- package/dist/chunks/ru-CegMPuML.mjs.map +0 -1
- package/dist/chunks/ru-CiLrD2Nz.mjs +0 -2
- package/dist/chunks/ru-CiLrD2Nz.mjs.map +0 -1
- package/dist/chunks/ru-ClEM6OKY.mjs +0 -2
- package/dist/chunks/ru-ClEM6OKY.mjs.map +0 -1
- package/dist/chunks/ru-CrbxCeQf.mjs +0 -2
- package/dist/chunks/ru-CrbxCeQf.mjs.map +0 -1
- package/dist/chunks/ru-D3j2x2xu.mjs +0 -2
- package/dist/chunks/ru-D3j2x2xu.mjs.map +0 -1
- package/dist/chunks/ru-DdHqb4Mh.mjs +0 -2
- package/dist/chunks/ru-DdHqb4Mh.mjs.map +0 -1
- package/dist/chunks/ru-DjgNdOdJ.mjs +0 -2
- package/dist/chunks/ru-DjgNdOdJ.mjs.map +0 -1
- package/dist/chunks/ru-Tzd5N37W.mjs +0 -2
- package/dist/chunks/ru-Tzd5N37W.mjs.map +0 -1
- package/dist/chunks/ru-XKNCzkR2.mjs +0 -2
- package/dist/chunks/ru-XKNCzkR2.mjs.map +0 -1
- package/dist/chunks/zh--oNSMazK.mjs +0 -2
- package/dist/chunks/zh--oNSMazK.mjs.map +0 -1
- package/dist/chunks/zh-BfeWdPIz.mjs +0 -2
- package/dist/chunks/zh-BfeWdPIz.mjs.map +0 -1
- package/dist/chunks/zh-BnOxGKxF.mjs +0 -2
- package/dist/chunks/zh-BnOxGKxF.mjs.map +0 -1
- package/dist/chunks/zh-BqMtE-jN.mjs +0 -2
- package/dist/chunks/zh-BqMtE-jN.mjs.map +0 -1
- package/dist/chunks/zh-C3aI7A2o.mjs +0 -2
- package/dist/chunks/zh-C3aI7A2o.mjs.map +0 -1
- package/dist/chunks/zh-C6YALJZt.mjs +0 -2
- package/dist/chunks/zh-C6YALJZt.mjs.map +0 -1
- package/dist/chunks/zh-CWdTbUOP.mjs +0 -2
- package/dist/chunks/zh-CWdTbUOP.mjs.map +0 -1
- package/dist/chunks/zh-CY01pMD4.mjs +0 -2
- package/dist/chunks/zh-CY01pMD4.mjs.map +0 -1
- package/dist/chunks/zh-Cmt7n9FY.mjs +0 -2
- package/dist/chunks/zh-Cmt7n9FY.mjs.map +0 -1
- package/dist/chunks/zh-CpP2kee3.mjs +0 -2
- package/dist/chunks/zh-CpP2kee3.mjs.map +0 -1
- package/dist/chunks/zh-Cpbg4evx.mjs +0 -2
- package/dist/chunks/zh-Cpbg4evx.mjs.map +0 -1
- package/dist/chunks/zh-Cqb55JWa.mjs +0 -2
- package/dist/chunks/zh-Cqb55JWa.mjs.map +0 -1
- package/dist/chunks/zh-DCQZ6gss.mjs +0 -2
- package/dist/chunks/zh-DCQZ6gss.mjs.map +0 -1
- package/dist/chunks/zh-DG2CNTUU.mjs +0 -2
- package/dist/chunks/zh-DG2CNTUU.mjs.map +0 -1
- package/dist/chunks/zh-DTiTJbzz.mjs +0 -2
- package/dist/chunks/zh-DTiTJbzz.mjs.map +0 -1
- package/dist/chunks/zh-Da1z6qbB.mjs +0 -2
- package/dist/chunks/zh-Da1z6qbB.mjs.map +0 -1
- package/dist/chunks/zh-Di3WqY4_.mjs +0 -2
- package/dist/chunks/zh-Di3WqY4_.mjs.map +0 -1
- package/dist/chunks/zh-DlBt06Pr.mjs +0 -2
- package/dist/chunks/zh-DlBt06Pr.mjs.map +0 -1
- package/dist/chunks/zh-Dt-wVrNr.mjs +0 -2
- package/dist/chunks/zh-Dt-wVrNr.mjs.map +0 -1
- package/dist/chunks/zh-ND6vW2M-.mjs +0 -2
- package/dist/chunks/zh-ND6vW2M-.mjs.map +0 -1
- package/dist/chunks/zh-Yd3GNsa0.mjs +0 -2
- package/dist/chunks/zh-Yd3GNsa0.mjs.map +0 -1
- package/dist/chunks/zh-lhynyH6Q.mjs +0 -2
- package/dist/chunks/zh-lhynyH6Q.mjs.map +0 -1
- package/dist/chunks/zh-v9NmlEIN.mjs +0 -2
- package/dist/chunks/zh-v9NmlEIN.mjs.map +0 -1
- package/dist/fonts.mjs.map +0 -1
- package/dist/full.mjs.map +0 -1
- package/dist/html.mjs.map +0 -1
- package/dist/notectl-core.mjs.map +0 -1
- package/dist/plugins/alignment.mjs.map +0 -1
- package/dist/plugins/blockquote.mjs.map +0 -1
- package/dist/plugins/caret-navigation.mjs.map +0 -1
- package/dist/plugins/code-block.mjs.map +0 -1
- package/dist/plugins/font-size.mjs.map +0 -1
- package/dist/plugins/font.mjs.map +0 -1
- package/dist/plugins/gap-cursor.mjs.map +0 -1
- package/dist/plugins/hard-break.mjs.map +0 -1
- package/dist/plugins/heading.mjs.map +0 -1
- package/dist/plugins/highlight.mjs.map +0 -1
- package/dist/plugins/horizontal-rule.mjs.map +0 -1
- package/dist/plugins/image.mjs.map +0 -1
- package/dist/plugins/link.mjs.map +0 -1
- package/dist/plugins/list.mjs.map +0 -1
- package/dist/plugins/print.mjs.map +0 -1
- package/dist/plugins/shared.mjs.map +0 -1
- package/dist/plugins/smart-paste.mjs.map +0 -1
- package/dist/plugins/strikethrough.mjs.map +0 -1
- package/dist/plugins/super-sub.mjs.map +0 -1
- package/dist/plugins/table.mjs.map +0 -1
- package/dist/plugins/text-color.mjs.map +0 -1
- package/dist/plugins/text-direction-advanced.mjs.map +0 -1
- package/dist/plugins/text-direction.mjs.map +0 -1
- package/dist/plugins/text-formatting.mjs.map +0 -1
- package/dist/plugins/toolbar.mjs.map +0 -1
- package/dist/presets/full.mjs.map +0 -1
- package/dist/presets/minimal.mjs.map +0 -1
- package/dist/presets.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"image.mjs","sources":["../../src/plugins/image/ImageCommands.ts","../../src/plugins/image/ImageLocale.ts","../../src/plugins/image/ImageNodeView.ts","../../src/plugins/image/ImageUpload.ts","../../src/plugins/image/ImagePlugin.ts","../../src/editor/styles/image.ts","../../src/plugins/image/ImagePopup.ts"],"sourcesContent":["/**\n * Image plugin commands: insert, remove, and attribute updates.\n * Supports both root-level and nested contexts (e.g. images inside table cells).\n */\n\nimport type { BlockAttrs, BlockNode } from '../../model/Document.js';\nimport { createBlockNode, getBlockChildren, isBlockNode } from '../../model/Document.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateNodeSelection,\n\tisGapCursor,\n\tisNodeSelection,\n} from '../../model/Selection.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport { nodeType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { PluginContext } from '../Plugin.js';\nimport type { ImageAttrs } from './ImageUpload.js';\n\n/**\n * Inserts an image block. When the cursor is inside a table cell,\n * the image is inserted as a child of the cell. Otherwise it is\n * inserted after the current block at document root.\n */\nexport function insertImage(\n\tcontext: PluginContext,\n\tattrs: Partial<ImageAttrs> & { readonly src: string },\n): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\n\tconst imageAttrs: BlockAttrs = {\n\t\tsrc: attrs.src,\n\t\talt: attrs.alt ?? '',\n\t\talign: attrs.align ?? 'center',\n\t\t...(attrs.width !== undefined ? { width: attrs.width } : {}),\n\t\t...(attrs.height !== undefined ? { height: attrs.height } : {}),\n\t};\n\n\tif (isGapCursor(sel)) return false;\n\n\tconst anchorBlockId: BlockId = isNodeSelection(sel) ? sel.nodeId : sel.anchor.blockId;\n\n\t// Check if we're inside a table cell\n\tconst cellId: BlockId | undefined = findTableCellAncestor(state, anchorBlockId);\n\tif (cellId) {\n\t\treturn insertImageIntoCell(state, context, cellId, imageAttrs);\n\t}\n\n\treturn insertImageAtRoot(state, context, anchorBlockId, imageAttrs);\n}\n\n/** Finds a table_cell ancestor for the given block (or the block itself). */\nfunction findTableCellAncestor(state: EditorState, bid: BlockId): BlockId | undefined {\n\tconst block: BlockNode | undefined = state.getBlock(bid);\n\tif (block?.type === 'table_cell') return bid;\n\n\tconst path: BlockId[] | undefined = state.getNodePath(bid);\n\tif (!path) return undefined;\n\n\tfor (const id of path) {\n\t\tconst node: BlockNode | undefined = state.getBlock(id);\n\t\tif (node?.type === 'table_cell') return id;\n\t}\n\treturn undefined;\n}\n\n/** Inserts an image at document root after the anchor block. */\nfunction insertImageAtRoot(\n\tstate: EditorState,\n\tcontext: PluginContext,\n\tanchorBlockId: BlockId,\n\timageAttrs: BlockAttrs,\n): boolean {\n\tconst blockIndex: number = state.doc.children.findIndex((b) => b.id === anchorBlockId);\n\tif (blockIndex === -1) return false;\n\n\tconst imageBlock: BlockNode = createBlockNode(nodeType('image'), [], undefined, imageAttrs);\n\tconst newParagraph: BlockNode = createBlockNode(nodeType('paragraph'));\n\n\tconst tr = state\n\t\t.transaction('command')\n\t\t.insertNode([], blockIndex + 1, imageBlock)\n\t\t.insertNode([], blockIndex + 2, newParagraph)\n\t\t.setSelection(createNodeSelection(imageBlock.id, []))\n\t\t.build();\n\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Inserts an image as a child of a table cell. */\nfunction insertImageIntoCell(\n\tstate: EditorState,\n\tcontext: PluginContext,\n\tcellId: BlockId,\n\timageAttrs: BlockAttrs,\n): boolean {\n\tconst cellPath: BlockId[] | undefined = state.getNodePath(cellId);\n\tif (!cellPath) return false;\n\n\tconst imageBlock: BlockNode = createBlockNode(nodeType('image'), [], undefined, imageAttrs);\n\n\t// Remove existing block children first (if any)\n\tconst cell: BlockNode | undefined = state.getBlock(cellId);\n\tif (!cell) return false;\n\n\tconst builder = state.transaction('command');\n\tconst blockChildren: readonly BlockNode[] = getBlockChildren(cell);\n\tfor (let i = blockChildren.length - 1; i >= 0; i--) {\n\t\t// Find the raw index in children array\n\t\tconst rawIndex: number = cell.children.findIndex(\n\t\t\t(c) => isBlockNode(c) && c.id === blockChildren[i]?.id,\n\t\t);\n\t\tif (rawIndex !== -1) {\n\t\t\tbuilder.removeNode(cellPath, rawIndex);\n\t\t}\n\t}\n\n\t// Insert image at index 0 (before any text nodes)\n\tbuilder.insertNode(cellPath, 0, imageBlock);\n\tbuilder.setSelection(createNodeSelection(imageBlock.id, [...cellPath, imageBlock.id]));\n\n\tcontext.dispatch(builder.build());\n\treturn true;\n}\n\n/** Removes the currently selected image block (works for nested images too). */\nexport function removeImage(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\tif (!isNodeSelection(sel)) return false;\n\n\tconst block: BlockNode | undefined = state.getBlock(sel.nodeId);\n\tif (!block || block.type !== 'image') return false;\n\n\tconst nodePath: BlockId[] | undefined = state.getNodePath(sel.nodeId);\n\tif (!nodePath || nodePath.length === 0) return false;\n\n\t// parentPath = all IDs except the last (the image itself)\n\tconst parentPath: BlockId[] = nodePath.slice(0, -1);\n\n\t// Find the index of the image in its parent's children\n\tlet parent: BlockNode | { readonly children: readonly BlockNode[] } | undefined;\n\tif (parentPath.length === 0) {\n\t\tparent = state.doc;\n\t} else {\n\t\tconst parentId: BlockId | undefined = parentPath[parentPath.length - 1];\n\t\tparent = parentId ? state.getBlock(parentId) : undefined;\n\t}\n\tif (!parent) return false;\n\n\tconst imageIndex: number = parent.children.findIndex(\n\t\t(c) => isBlockNode(c) && c.id === sel.nodeId,\n\t);\n\tif (imageIndex === -1) return false;\n\n\t// Determine where to place the cursor after removal\n\tconst selectionTarget: BlockId | undefined = findSelectionTargetAfterRemoval(\n\t\tstate,\n\t\tparentPath,\n\t\tsel.nodeId,\n\t);\n\tif (!selectionTarget) return false;\n\n\tconst tr = state\n\t\t.transaction('command')\n\t\t.removeNode(parentPath, imageIndex)\n\t\t.setSelection(createCollapsedSelection(selectionTarget, 0))\n\t\t.build();\n\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Finds a suitable block to select after removing an image. */\nfunction findSelectionTargetAfterRemoval(\n\tstate: EditorState,\n\tparentPath: readonly BlockId[],\n\tremovedId: BlockId,\n): BlockId | undefined {\n\tif (parentPath.length === 0) {\n\t\t// Root level: select adjacent block\n\t\tconst rootChildren: readonly BlockNode[] = state.doc.children;\n\t\tconst idx: number = rootChildren.findIndex((b) => b.id === removedId);\n\t\tconst adjacent: BlockNode | undefined = rootChildren[idx + 1] ?? rootChildren[idx - 1];\n\t\treturn adjacent?.id;\n\t}\n\n\t// Nested (e.g. inside table cell): select the cell itself\n\tconst cellId: BlockId | undefined = parentPath[parentPath.length - 1];\n\treturn cellId;\n}\n\n/** Updates attributes on the currently selected image block. */\nexport function setImageAttr(context: PluginContext, attrs: Partial<ImageAttrs>): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\tif (!isNodeSelection(sel)) return false;\n\n\tconst block: BlockNode | undefined = state.getBlock(sel.nodeId);\n\tif (!block || block.type !== 'image') return false;\n\n\tconst path: BlockId[] | undefined = state.getNodePath(sel.nodeId);\n\tif (!path) return false;\n\n\tconst merged: BlockAttrs = { ...(block.attrs ?? {}), ...attrs };\n\tconst tr = state.transaction('command').setNodeAttr(path, merged).build();\n\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Minimum image width in pixels (shared with NodeView). */\nexport const MIN_IMAGE_WIDTH = 50;\n\n/**\n * Resizes the currently selected image by a pixel delta, preserving aspect ratio.\n * Returns false if no image is selected or the image has no width/height attributes.\n */\nexport function resizeImageByDelta(\n\tcontext: PluginContext,\n\tdelta: number,\n\tmaxWidth: number,\n): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\tif (!isNodeSelection(sel)) return false;\n\n\tconst block: BlockNode | undefined = state.getBlock(sel.nodeId);\n\tif (!block || block.type !== 'image') return false;\n\n\tconst currentWidth: number | undefined = block.attrs?.width as number | undefined;\n\tconst currentHeight: number | undefined = block.attrs?.height as number | undefined;\n\tif (currentWidth === undefined || currentHeight === undefined) return false;\n\n\tconst aspectRatio: number = currentHeight > 0 ? currentWidth / currentHeight : 1;\n\tconst clampedWidth: number = Math.max(MIN_IMAGE_WIDTH, Math.min(maxWidth, currentWidth + delta));\n\tconst newHeight: number = Math.round(clampedWidth / aspectRatio);\n\n\tif (clampedWidth === currentWidth && newHeight === currentHeight) return false;\n\n\treturn setImageAttr(context, { width: clampedWidth, height: newHeight });\n}\n\n/** Resets the currently selected image to its natural size by removing width/height. */\nexport function resetImageSize(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\tif (!isNodeSelection(sel)) return false;\n\n\tconst block: BlockNode | undefined = state.getBlock(sel.nodeId);\n\tif (!block || block.type !== 'image') return false;\n\n\tconst path: BlockId[] | undefined = state.getNodePath(sel.nodeId);\n\tif (!path) return false;\n\n\tconst attrs: BlockAttrs = { ...(block.attrs ?? {}) };\n\tconst cleaned: BlockAttrs = Object.fromEntries(\n\t\tObject.entries(attrs).filter(([k]) => k !== 'width' && k !== 'height'),\n\t);\n\n\tconst tr = state.transaction('command').setNodeAttr(path, cleaned).build();\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Registers all image commands on the plugin context. */\nexport function registerImageCommands(context: PluginContext): void {\n\tcontext.registerCommand('insertImage', () => {\n\t\treturn insertImage(context, { src: '' });\n\t});\n\n\tcontext.registerCommand('removeImage', () => {\n\t\treturn removeImage(context);\n\t});\n}\n","/** Locale interface and default English locale for the ImagePlugin. */\n\n// --- Locale Interface ---\n\nexport interface ImageLocale {\n\treadonly insertImage: string;\n\treadonly insertImageTooltip: string;\n\treadonly uploadFromComputer: string;\n\treadonly uploadAria: string;\n\treadonly separator: string;\n\treadonly urlPlaceholder: string;\n\treadonly urlAria: string;\n\treadonly insertButton: string;\n\treadonly insertAria: string;\n\treadonly imageAria: (alt: string, width?: number, height?: number) => string;\n\treadonly resetToNaturalSize: string;\n\treadonly uploadFailed: string;\n\treadonly uploading: string;\n\treadonly resizeHandleLabel: (position: string) => string;\n\treadonly imageSelected: string;\n\treadonly altTextPrefix: string;\n\treadonly imageSizeAnnounce: (w: number, h: number) => string;\n\treadonly resizeHint: (shrink: string, grow: string) => string;\n\treadonly imageResized: (w: number, h: number) => string;\n\treadonly keyboardResizeHint: (shrink: string, grow: string) => string;\n}\n\n// --- Default English Locale ---\n\nexport const IMAGE_LOCALE_EN: ImageLocale = {\n\tinsertImage: 'Insert Image',\n\tinsertImageTooltip: 'Insert Image',\n\tuploadFromComputer: 'Upload from computer',\n\tuploadAria: 'Upload image from computer',\n\tseparator: 'or',\n\turlPlaceholder: 'https://...',\n\turlAria: 'Image URL',\n\tinsertButton: 'Insert',\n\tinsertAria: 'Insert image',\n\timageAria: (alt: string, width?: number, height?: number) => {\n\t\tconst parts: string[] = [alt || 'Image'];\n\t\tif (width !== undefined && height !== undefined) {\n\t\t\tparts.push(`${width} by ${height} pixels`);\n\t\t}\n\t\treturn parts.join(', ');\n\t},\n\tresetToNaturalSize: 'Image reset to natural size.',\n\tuploadFailed: 'Upload failed.',\n\tuploading: 'Uploading...',\n\tresizeHandleLabel: (position: string) => `Resize ${position}`,\n\timageSelected: 'Image selected.',\n\taltTextPrefix: 'Alt text: ',\n\timageSizeAnnounce: (w: number, h: number) => `Size: ${w} by ${h} pixels.`,\n\tresizeHint: (shrink: string, grow: string) => `${shrink} / ${grow} to resize.`,\n\timageResized: (w: number, h: number) => `Image resized to ${w} by ${h} pixels.`,\n\tkeyboardResizeHint: (shrink: string, grow: string) => `${shrink} / ${grow} to resize`,\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: Record<string, () => Promise<{ default: ImageLocale }>> = import.meta.glob<{\n\tdefault: ImageLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadImageLocale(lang: string): Promise<ImageLocale> {\n\tif (lang === 'en') return IMAGE_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return IMAGE_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn IMAGE_LOCALE_EN;\n\t}\n}\n","/**\n * NodeView factory for image blocks.\n * Renders <figure> with <img>, handles selection state, upload overlay,\n * resize with 4 corner handles + live size indicator, and a keyboard-hint\n * showing resize shortcuts when the image is selected.\n */\n\nimport type { BlockAttrs, BlockNode } from '../../model/Document.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport { getTextDirection } from '../../platform/Platform.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport {\n\tgetStyleNonceForNode,\n\tsetStyleProperties,\n\tsetStyleProperty,\n} from '../../style/StyleRuntime.js';\nimport type { NodeView, NodeViewFactory } from '../../view/NodeView.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { IMAGE_LOCALE_EN, type ImageLocale } from './ImageLocale.js';\nimport type { ImageKeymap, ImagePluginConfig, UploadState } from './ImageUpload.js';\n\nconst ALIGNMENT_CLASSES: Record<string, string> = {\n\tstart: 'notectl-image--start',\n\tcenter: 'notectl-image--center',\n\tend: 'notectl-image--end',\n};\n\nconst MIN_IMAGE_WIDTH = 50;\n\ntype HandlePosition = 'nw' | 'ne' | 'sw' | 'se';\n\nconst HANDLE_CURSORS: Readonly<Record<HandlePosition, string>> = {\n\tnw: 'nwse-resize',\n\tne: 'nesw-resize',\n\tsw: 'nesw-resize',\n\tse: 'nwse-resize',\n};\n\n/** +1 means dragging right increases width; -1 means dragging left does. */\nconst HANDLE_X_SIGN: Readonly<Record<HandlePosition, 1 | -1>> = {\n\tnw: -1,\n\tne: 1,\n\tsw: -1,\n\tse: 1,\n};\n\nconst HANDLE_POSITIONS_LTR: Readonly<Record<HandlePosition, string>> = {\n\tnw: 'top-left',\n\tne: 'top-right',\n\tsw: 'bottom-left',\n\tse: 'bottom-right',\n};\n\nconst HANDLE_POSITIONS_RTL: Readonly<Record<HandlePosition, string>> = {\n\tnw: 'top-right',\n\tne: 'top-left',\n\tsw: 'bottom-right',\n\tse: 'bottom-left',\n};\n\nconst RTL_CURSOR_MAP: Readonly<Record<HandlePosition, string>> = {\n\tnw: 'nesw-resize',\n\tne: 'nwse-resize',\n\tsw: 'nwse-resize',\n\tse: 'nesw-resize',\n};\n\n/** Returns the direction-aware ARIA label for a resize handle. */\nexport function getHandleLabel(\n\tposition: HandlePosition,\n\tisRtl: boolean,\n\tlocale: ImageLocale = IMAGE_LOCALE_EN,\n): string {\n\tconst positionName: string = (isRtl ? HANDLE_POSITIONS_RTL : HANDLE_POSITIONS_LTR)[position];\n\treturn locale.resizeHandleLabel(positionName);\n}\n\n/** Returns the X-sign for resize drag, flipped in RTL. */\nexport function getResizeXSign(position: HandlePosition, isRtl: boolean): 1 | -1 {\n\tconst sign: 1 | -1 = HANDLE_X_SIGN[position];\n\treturn isRtl ? (-sign as 1 | -1) : sign;\n}\n\n// --- Global cursor override during resize ---\n\nlet activeCursorStyle: HTMLStyleElement | null = null;\n\nfunction setGlobalResizeCursor(cursor: string, referenceNode?: Node): void {\n\tclearGlobalResizeCursor();\n\tactiveCursorStyle = document.createElement('style');\n\tconst nonce = referenceNode ? getStyleNonceForNode(referenceNode) : undefined;\n\tif (nonce) {\n\t\tactiveCursorStyle.setAttribute('nonce', nonce);\n\t}\n\tactiveCursorStyle.textContent = `*{cursor:${cursor}!important;user-select:none!important}`;\n\tdocument.head.appendChild(activeCursorStyle);\n}\n\nfunction clearGlobalResizeCursor(): void {\n\tif (activeCursorStyle) {\n\t\tactiveCursorStyle.remove();\n\t\tactiveCursorStyle = null;\n\t}\n}\n\n/** Builds the keyboard-hint text from the resolved keymap. */\nfunction buildKeyboardHintText(\n\tresolvedKeymap: Readonly<Record<keyof ImageKeymap, string | null>>,\n\tlocale: ImageLocale,\n): string {\n\tconst shrink: string | null = resolvedKeymap.shrinkWidth ?? null;\n\tconst grow: string | null = resolvedKeymap.growWidth ?? null;\n\tif (!shrink || !grow) return '';\n\treturn locale.keyboardResizeHint(formatShortcut(shrink), formatShortcut(grow));\n}\n\n/** Creates a NodeViewFactory for image blocks. */\nexport function createImageNodeViewFactory(\n\tconfig: ImagePluginConfig,\n\tuploadStates: Map<BlockId, UploadState>,\n\tresolvedKeymap?: Readonly<Record<keyof ImageKeymap, string | null>>,\n\tlocale: ImageLocale = IMAGE_LOCALE_EN,\n): NodeViewFactory {\n\treturn (\n\t\tnode: BlockNode,\n\t\tgetState: () => EditorState,\n\t\tdispatch: (tr: Transaction) => void,\n\t): NodeView => {\n\t\t// --- DOM Construction ---\n\t\tconst figure: HTMLElement = document.createElement('figure');\n\t\tfigure.className = 'notectl-image';\n\t\tfigure.setAttribute('data-block-id', node.id);\n\t\tfigure.setAttribute('data-void', 'true');\n\t\tfigure.setAttribute('data-selectable', 'true');\n\n\t\tconst container: HTMLDivElement = document.createElement('div');\n\t\tcontainer.className = 'notectl-image__container';\n\n\t\tconst img: HTMLImageElement = document.createElement('img');\n\t\timg.className = 'notectl-image__img';\n\t\timg.draggable = false;\n\n\t\tconst overlay: HTMLDivElement = document.createElement('div');\n\t\toverlay.className = 'notectl-image__overlay';\n\n\t\tcontainer.appendChild(img);\n\t\tcontainer.appendChild(overlay);\n\t\tfigure.appendChild(container);\n\n\t\tlet currentNodeId: BlockId = node.id;\n\t\tlet resizeOverlay: HTMLDivElement | null = null;\n\n\t\t// --- ARIA Label ---\n\n\t\tfunction updateAriaLabel(n: BlockNode): void {\n\t\t\tconst alt: string = (n.attrs?.alt as string | undefined) ?? '';\n\t\t\tconst width: number | undefined = n.attrs?.width as number | undefined;\n\t\t\tconst height: number | undefined = n.attrs?.height as number | undefined;\n\t\t\tfigure.setAttribute('aria-label', locale.imageAria(alt, width, height));\n\t\t}\n\n\t\t// --- Attribute Application ---\n\n\t\tfunction applyAttrs(n: BlockNode): void {\n\t\t\tconst src: string = (n.attrs?.src as string | undefined) ?? '';\n\t\t\tconst alt: string = (n.attrs?.alt as string | undefined) ?? '';\n\t\t\tconst width: number | undefined = n.attrs?.width as number | undefined;\n\t\t\tconst height: number | undefined = n.attrs?.height as number | undefined;\n\t\t\tconst align: string = (n.attrs?.align as string | undefined) ?? 'center';\n\n\t\t\t// Only update src when it changes to avoid re-triggering load events\n\t\t\tif (img.src !== src) img.src = src;\n\t\t\timg.alt = alt;\n\n\t\t\tif (width !== undefined) {\n\t\t\t\tsetStyleProperty(img, 'width', `${width}px`);\n\t\t\t} else {\n\t\t\t\tsetStyleProperty(img, 'width', '');\n\t\t\t}\n\t\t\tif (height !== undefined) {\n\t\t\t\tsetStyleProperty(img, 'height', `${height}px`);\n\t\t\t} else {\n\t\t\t\tsetStyleProperty(img, 'height', '');\n\t\t\t}\n\n\t\t\tfor (const cls of Object.values(ALIGNMENT_CLASSES)) {\n\t\t\t\tfigure.classList.remove(cls);\n\t\t\t}\n\t\t\tconst alignClass: string | undefined = ALIGNMENT_CLASSES[align];\n\t\t\tif (alignClass) {\n\t\t\t\tfigure.classList.add(alignClass);\n\t\t\t}\n\n\t\t\tconst uploadState: UploadState = uploadStates.get(n.id) ?? 'idle';\n\t\t\tconst isUploading: boolean = uploadState === 'uploading';\n\t\t\toverlay.classList.toggle('notectl-image__overlay--uploading', isUploading);\n\t\t\toverlay.classList.toggle('notectl-image__overlay--error', uploadState === 'error');\n\n\t\t\tif (isUploading) {\n\t\t\t\toverlay.textContent = locale.uploading;\n\t\t\t} else if (uploadState === 'error') {\n\t\t\t\toverlay.textContent = locale.uploadFailed;\n\t\t\t} else {\n\t\t\t\toverlay.textContent = '';\n\t\t\t}\n\n\t\t\tif (isUploading) {\n\t\t\t\tfigure.setAttribute('aria-busy', 'true');\n\t\t\t} else {\n\t\t\t\tfigure.removeAttribute('aria-busy');\n\t\t\t}\n\n\t\t\tupdateAriaLabel(n);\n\t\t}\n\n\t\tapplyAttrs(node);\n\n\t\t// --- Commit natural dimensions on first load ---\n\n\t\tlet dimensionsCommitted = false;\n\n\t\timg.addEventListener('load', () => {\n\t\t\tif (dimensionsCommitted) return;\n\n\t\t\tconst state: EditorState = getState();\n\t\t\tconst block: BlockNode | undefined = state.getBlock(currentNodeId);\n\t\t\tif (!block || block.type !== 'image') return;\n\n\t\t\tconst hasWidth: boolean = block.attrs?.width !== undefined;\n\t\t\tconst hasHeight: boolean = block.attrs?.height !== undefined;\n\t\t\tif (hasWidth && hasHeight) {\n\t\t\t\tdimensionsCommitted = true;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst naturalW: number = img.naturalWidth;\n\t\t\tconst naturalH: number = img.naturalHeight;\n\t\t\tif (naturalW === 0 || naturalH === 0) return;\n\n\t\t\tconst clampedW: number = Math.min(naturalW, config.maxWidth);\n\t\t\tconst ratio: number = naturalW > 0 ? naturalH / naturalW : 1;\n\t\t\tconst clampedH: number = Math.round(clampedW * ratio);\n\n\t\t\tconst path: BlockId[] | undefined = state.getNodePath(currentNodeId);\n\t\t\tif (!path) return;\n\n\t\t\tconst merged: BlockAttrs = {\n\t\t\t\t...(block.attrs ?? {}),\n\t\t\t\twidth: clampedW,\n\t\t\t\theight: clampedH,\n\t\t\t};\n\n\t\t\tconst tr: Transaction = state.transaction('command').setNodeAttr(path, merged).build();\n\t\t\tdispatch(tr);\n\t\t\tdimensionsCommitted = true;\n\t\t});\n\n\t\t// --- Resize Logic ---\n\n\t\tfunction clampWidth(width: number): number {\n\t\t\treturn Math.max(MIN_IMAGE_WIDTH, Math.min(config.maxWidth, width));\n\t\t}\n\n\t\tfunction commitResize(nodeId: BlockId, width: number, height: number): void {\n\t\t\tconst state: EditorState = getState();\n\t\t\tconst block: BlockNode | undefined = state.getBlock(nodeId);\n\t\t\tif (!block) return;\n\n\t\t\tconst prevWidth: number | undefined = block.attrs?.width as number | undefined;\n\t\t\tconst prevHeight: number | undefined = block.attrs?.height as number | undefined;\n\t\t\tif (prevWidth === width && prevHeight === height) return;\n\n\t\t\tconst path: BlockId[] | undefined = state.getNodePath(nodeId);\n\t\t\tif (!path) return;\n\n\t\t\tconst merged: BlockAttrs = {\n\t\t\t\t...(block.attrs ?? {}),\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t};\n\n\t\t\tconst tr: Transaction = state.transaction('command').setNodeAttr(path, merged).build();\n\t\t\tdispatch(tr);\n\t\t}\n\n\t\tfunction attachHandleListeners(\n\t\t\thandle: HTMLDivElement,\n\t\t\tposition: HandlePosition,\n\t\t\tnodeId: BlockId,\n\t\t\tsizeIndicator: HTMLDivElement,\n\t\t): void {\n\t\t\tlet startX = 0;\n\t\t\tlet startWidth = 0;\n\t\t\tlet aspectRatio = 1;\n\t\t\tlet xSign: 1 | -1 = HANDLE_X_SIGN[position];\n\n\t\t\tconst onPointerMove = (e: PointerEvent): void => {\n\t\t\t\tconst deltaX: number = e.clientX - startX;\n\t\t\t\tconst newWidth: number = clampWidth(startWidth + deltaX * xSign);\n\t\t\t\tconst newHeight: number = Math.round(newWidth / aspectRatio);\n\n\t\t\t\tsetStyleProperties(img, {\n\t\t\t\t\twidth: `${newWidth}px`,\n\t\t\t\t\theight: `${newHeight}px`,\n\t\t\t\t});\n\n\t\t\t\tsizeIndicator.textContent = `${Math.round(newWidth)} \\u00D7 ${newHeight}`;\n\t\t\t};\n\n\t\t\tconst onPointerUp = (e: PointerEvent): void => {\n\t\t\t\tdocument.removeEventListener('pointermove', onPointerMove);\n\t\t\t\tdocument.removeEventListener('pointerup', onPointerUp);\n\n\t\t\t\tfigure.classList.remove('notectl-image--resizing');\n\t\t\t\tsizeIndicator.classList.remove('notectl-image__size-indicator--visible');\n\t\t\t\tclearGlobalResizeCursor();\n\n\t\t\t\tconst finalWidth: number = Math.round(img.getBoundingClientRect().width);\n\t\t\t\tconst finalHeight: number = Math.round(finalWidth / aspectRatio);\n\n\t\t\t\tcommitResize(nodeId, finalWidth, finalHeight);\n\n\t\t\t\t(e.target as HTMLElement | null)?.releasePointerCapture?.(e.pointerId);\n\t\t\t};\n\n\t\t\thandle.addEventListener('pointerdown', (e: PointerEvent) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\n\t\t\t\tconst isRtl: boolean = getTextDirection(figure) === 'rtl';\n\t\t\t\txSign = getResizeXSign(position, isRtl);\n\n\t\t\t\tstartX = e.clientX;\n\t\t\t\tstartWidth = img.getBoundingClientRect().width;\n\t\t\t\tconst imgHeight: number = img.getBoundingClientRect().height;\n\t\t\t\taspectRatio = imgHeight > 0 ? startWidth / imgHeight : 1;\n\n\t\t\t\tfigure.classList.add('notectl-image--resizing');\n\t\t\t\tsizeIndicator.textContent = `${Math.round(startWidth)} \\u00D7 ${Math.round(imgHeight)}`;\n\t\t\t\tsizeIndicator.classList.add('notectl-image__size-indicator--visible');\n\t\t\t\tconst cursor: string = isRtl ? RTL_CURSOR_MAP[position] : HANDLE_CURSORS[position];\n\t\t\t\tsetGlobalResizeCursor(cursor, figure);\n\n\t\t\t\t(e.target as HTMLElement).setPointerCapture(e.pointerId);\n\t\t\t\tdocument.addEventListener('pointermove', onPointerMove);\n\t\t\t\tdocument.addEventListener('pointerup', onPointerUp);\n\t\t\t});\n\t\t}\n\n\t\tfunction createResizeOverlay(nodeId: BlockId): void {\n\t\t\tif (!config.resizable || resizeOverlay) return;\n\n\t\t\tresizeOverlay = document.createElement('div');\n\t\t\tresizeOverlay.className = 'notectl-image__resize-overlay';\n\t\t\tresizeOverlay.setAttribute('data-notectl-no-print', '');\n\n\t\t\tconst sizeIndicator: HTMLDivElement = document.createElement('div');\n\t\t\tsizeIndicator.className = 'notectl-image__size-indicator';\n\t\t\tresizeOverlay.appendChild(sizeIndicator);\n\n\t\t\tconst isRtl: boolean = getTextDirection(figure) === 'rtl';\n\t\t\tconst positions: readonly HandlePosition[] = ['nw', 'ne', 'sw', 'se'];\n\t\t\tfor (const pos of positions) {\n\t\t\t\tconst handle: HTMLDivElement = document.createElement('div');\n\t\t\t\thandle.className = `notectl-image__resize-handle notectl-image__resize-handle--${pos}`;\n\t\t\t\thandle.setAttribute('role', 'separator');\n\t\t\t\thandle.setAttribute('aria-label', getHandleLabel(pos, isRtl, locale));\n\t\t\t\tattachHandleListeners(handle, pos, nodeId, sizeIndicator);\n\t\t\t\tresizeOverlay.appendChild(handle);\n\t\t\t}\n\n\t\t\t// Keyboard hint (hidden from screenreaders, visual only)\n\t\t\tif (resolvedKeymap) {\n\t\t\t\tconst hintText: string = buildKeyboardHintText(resolvedKeymap, locale);\n\t\t\t\tif (hintText) {\n\t\t\t\t\tconst hint: HTMLDivElement = document.createElement('div');\n\t\t\t\t\thint.className = 'notectl-image__keyboard-hint';\n\t\t\t\t\thint.setAttribute('aria-hidden', 'true');\n\t\t\t\t\thint.textContent = hintText;\n\t\t\t\t\tresizeOverlay.appendChild(hint);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcontainer.appendChild(resizeOverlay);\n\t\t}\n\n\t\tfunction removeResizeOverlay(): void {\n\t\t\tclearGlobalResizeCursor();\n\t\t\tif (resizeOverlay) {\n\t\t\t\tresizeOverlay.remove();\n\t\t\t\tresizeOverlay = null;\n\t\t\t}\n\t\t}\n\n\t\t// --- NodeView Interface ---\n\n\t\treturn {\n\t\t\tdom: figure,\n\t\t\tcontentDOM: null,\n\n\t\t\tupdate(updatedNode: BlockNode): boolean {\n\t\t\t\tif (updatedNode.type !== 'image') return false;\n\t\t\t\tcurrentNodeId = updatedNode.id;\n\t\t\t\tfigure.setAttribute('data-block-id', updatedNode.id);\n\t\t\t\tapplyAttrs(updatedNode);\n\t\t\t\treturn true;\n\t\t\t},\n\n\t\t\tselectNode(): void {\n\t\t\t\tfigure.classList.add('notectl-image--selected');\n\t\t\t\tcreateResizeOverlay(currentNodeId);\n\t\t\t},\n\n\t\t\tdeselectNode(): void {\n\t\t\t\tfigure.classList.remove('notectl-image--selected');\n\t\t\t\tremoveResizeOverlay();\n\t\t\t},\n\n\t\t\tdestroy(): void {\n\t\t\t\tremoveResizeOverlay();\n\t\t\t\t// Do NOT revoke blob URLs here — the URL may still be referenced\n\t\t\t\t// by the clipboard (cut/paste) or undo history. Blob URLs are\n\t\t\t\t// automatically released when the document is unloaded.\n\t\t\t},\n\t\t};\n\t};\n}\n","/**\n * Image plugin types, configuration, and service key.\n */\n\nimport { ServiceKey } from '../Plugin.js';\nimport type { ImageLocale } from './ImageLocale.js';\n\n// --- Image Attributes ---\n\nexport interface ImageAttrs {\n\treadonly src: string;\n\treadonly alt: string;\n\treadonly width?: number;\n\treadonly height?: number;\n\treadonly align: 'start' | 'center' | 'end';\n}\n\n// --- Upload Types ---\n\nexport interface ImageUploadResult {\n\treadonly url: string;\n\treadonly width?: number;\n\treadonly height?: number;\n}\n\nexport interface ImageUploadService {\n\tupload(file: File): Promise<ImageUploadResult>;\n}\n\nexport const IMAGE_UPLOAD_SERVICE = new ServiceKey<ImageUploadService>('image:upload');\n\nexport type UploadState = 'idle' | 'uploading' | 'complete' | 'error';\n\n// --- Keyboard Bindings ---\n\n/**\n * Configurable keyboard bindings for image resize actions.\n * Omit a slot to use the default; set to `null` to disable the binding.\n *\n * Key descriptor format: `'Mod-Shift-ArrowRight'`, etc.\n * `Mod` resolves to Cmd on macOS, Ctrl on Windows/Linux.\n */\nexport interface ImageKeymap {\n\treadonly growWidth?: string | null;\n\treadonly shrinkWidth?: string | null;\n\treadonly growWidthLarge?: string | null;\n\treadonly shrinkWidthLarge?: string | null;\n\treadonly resetSize?: string | null;\n}\n\nexport const DEFAULT_IMAGE_KEYMAP: Readonly<Record<keyof ImageKeymap, string>> = {\n\tgrowWidth: 'Mod-Shift-ArrowRight',\n\tshrinkWidth: 'Mod-Shift-ArrowLeft',\n\tgrowWidthLarge: 'Mod-Shift-Alt-ArrowRight',\n\tshrinkWidthLarge: 'Mod-Shift-Alt-ArrowLeft',\n\tresetSize: 'Mod-Shift-0',\n};\n\n// --- Configuration ---\n\nexport interface ImagePluginConfig {\n\treadonly maxWidth: number;\n\treadonly maxFileSize: number;\n\treadonly acceptedTypes: readonly string[];\n\treadonly resizable: boolean;\n\t/** Pixels to grow/shrink per small resize step. @default 10 */\n\treadonly resizeStep?: number;\n\t/** Pixels to grow/shrink per large resize step. @default 50 */\n\treadonly resizeStepLarge?: number;\n\t/** Customize keyboard bindings for image resize actions. */\n\treadonly keymap?: ImageKeymap;\n\t/** Locale override for user-facing strings. */\n\treadonly locale?: ImageLocale;\n}\n\nexport const DEFAULT_IMAGE_CONFIG: ImagePluginConfig = {\n\tmaxWidth: 800,\n\tmaxFileSize: 10 * 1024 * 1024,\n\tacceptedTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/svg+xml'],\n\tresizable: true,\n\tresizeStep: 10,\n\tresizeStepLarge: 50,\n};\n","/**\n * ImagePlugin: registers an image void block type with NodeSpec,\n * NodeView, commands, file handler, toolbar button, and accessible\n * keyboard resize with screenreader announcements.\n */\n\nimport { IMAGE_CSS } from '../../editor/styles/image.js';\nimport type { BlockAttrs, BlockNode } from '../../model/Document.js';\nimport { escapeHTML } from '../../model/HTMLUtils.js';\nimport { isNodeSelection } from '../../model/Selection.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport { setStyleProperty } from '../../style/StyleRuntime.js';\nimport { createBlockElement } from '../../view/DomUtils.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport {\n\tinsertImage,\n\tregisterImageCommands,\n\tresetImageSize,\n\tresizeImageByDelta,\n} from './ImageCommands.js';\nimport { IMAGE_LOCALE_EN, type ImageLocale, loadImageLocale } from './ImageLocale.js';\nimport { createImageNodeViewFactory } from './ImageNodeView.js';\nimport { renderImagePopup } from './ImagePopup.js';\nimport {\n\tDEFAULT_IMAGE_CONFIG,\n\tDEFAULT_IMAGE_KEYMAP,\n\tIMAGE_UPLOAD_SERVICE,\n\ttype ImageKeymap,\n\ttype ImagePluginConfig,\n\ttype UploadState,\n} from './ImageUpload.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface NodeAttrRegistry {\n\t\timage: {\n\t\t\tsrc: string;\n\t\t\talt: string;\n\t\t\twidth?: number;\n\t\t\theight?: number;\n\t\t\talign: 'start' | 'center' | 'end';\n\t\t};\n\t}\n}\n\n// --- Plugin ---\n\nexport class ImagePlugin implements Plugin {\n\treadonly id = 'image';\n\treadonly name = 'Image';\n\treadonly priority = 45;\n\n\tprivate readonly config: ImagePluginConfig;\n\tprivate readonly resolvedKeymap: Readonly<Record<keyof ImageKeymap, string | null>>;\n\tprivate readonly uploadStates = new Map<BlockId, UploadState>();\n\tprivate readonly blobUrls = new Set<string>();\n\tprivate context: PluginContext | null = null;\n\tprivate locale!: ImageLocale;\n\n\tconstructor(config?: Partial<ImagePluginConfig>) {\n\t\tthis.config = { ...DEFAULT_IMAGE_CONFIG, ...config };\n\t\tthis.resolvedKeymap = { ...DEFAULT_IMAGE_KEYMAP, ...config?.keymap };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tIMAGE_LOCALE_EN,\n\t\t\tloadImageLocale,\n\t\t);\n\t\tcontext.registerStyleSheet(IMAGE_CSS);\n\t\tthis.context = context;\n\t\tthis.registerNodeSpec(context);\n\t\tthis.registerNodeView(context);\n\t\tregisterImageCommands(context);\n\t\tthis.registerResizeCommands(context);\n\t\tthis.registerResizeKeymaps(context);\n\t\tthis.registerFileHandler(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tdestroy(): void {\n\t\tfor (const url of this.blobUrls) {\n\t\t\tURL.revokeObjectURL(url);\n\t\t}\n\t\tthis.blobUrls.clear();\n\t\tthis.uploadStates.clear();\n\t\tthis.context = null;\n\t}\n\n\tonStateChange(oldState: EditorState, newState: EditorState, _tr: Transaction): void {\n\t\tif (!this.context) return;\n\n\t\t// Clean up upload states for removed blocks (searches full tree)\n\t\tfor (const id of this.uploadStates.keys()) {\n\t\t\tif (!newState.getBlock(id)) {\n\t\t\t\tthis.uploadStates.delete(id);\n\t\t\t}\n\t\t}\n\n\t\t// Announce image selection for screenreaders\n\t\tconst oldIsImage: boolean = this.isImageSelected(oldState);\n\t\tconst nowIsImage: boolean = this.isImageSelected(newState);\n\n\t\tif (!oldIsImage && nowIsImage) {\n\t\t\tthis.announceImageSelection(newState);\n\t\t}\n\t}\n\n\tprivate registerNodeSpec(context: PluginContext): void {\n\t\tconst locale = this.locale;\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'image',\n\t\t\tgroup: 'block',\n\t\t\tisVoid: true,\n\t\t\tselectable: true,\n\t\t\tattrs: {\n\t\t\t\tsrc: { default: '' },\n\t\t\t\talt: { default: '' },\n\t\t\t\talign: { default: 'center' },\n\t\t\t},\n\t\t\ttoDOM(node) {\n\t\t\t\tconst figure = createBlockElement('figure', node.id);\n\t\t\t\tfigure.className = 'notectl-image';\n\t\t\t\tfigure.setAttribute('data-void', 'true');\n\t\t\t\tfigure.setAttribute('data-selectable', 'true');\n\n\t\t\t\tconst imgContainer: HTMLDivElement = document.createElement('div');\n\t\t\t\timgContainer.className = 'notectl-image__container';\n\n\t\t\t\tconst alt: string = (node.attrs?.alt as string | undefined) ?? '';\n\t\t\t\tconst width: number | undefined = node.attrs?.width as number | undefined;\n\t\t\t\tconst height: number | undefined = node.attrs?.height as number | undefined;\n\n\t\t\t\tconst img: HTMLImageElement = document.createElement('img');\n\t\t\t\timg.className = 'notectl-image__img';\n\t\t\t\timg.src = (node.attrs?.src as string | undefined) ?? '';\n\t\t\t\timg.alt = alt;\n\t\t\t\timg.draggable = false;\n\n\t\t\t\tif (width !== undefined) setStyleProperty(img, 'width', `${width}px`);\n\t\t\t\tif (height !== undefined) setStyleProperty(img, 'height', `${height}px`);\n\n\t\t\t\tconst align: string = (node.attrs?.align as string | undefined) ?? 'center';\n\t\t\t\tconst alignClass: string | undefined = {\n\t\t\t\t\tstart: 'notectl-image--start',\n\t\t\t\t\tcenter: 'notectl-image--center',\n\t\t\t\t\tend: 'notectl-image--end',\n\t\t\t\t}[align];\n\t\t\t\tif (alignClass) figure.classList.add(alignClass);\n\n\t\t\t\tfigure.setAttribute('aria-label', locale.imageAria(alt, width, height));\n\n\t\t\t\timgContainer.appendChild(img);\n\t\t\t\tfigure.appendChild(imgContainer);\n\t\t\t\treturn figure;\n\t\t\t},\n\t\t\ttoHTML(node) {\n\t\t\t\tconst src: string = escapeHTML((node.attrs?.src as string | undefined) ?? '');\n\t\t\t\tconst alt: string = escapeHTML((node.attrs?.alt as string | undefined) ?? '');\n\t\t\t\tconst width: number | undefined = node.attrs?.width as number | undefined;\n\t\t\t\tconst height: number | undefined = node.attrs?.height as number | undefined;\n\n\t\t\t\tconst sizeAttrs: string =\n\t\t\t\t\t(width !== undefined ? ` width=\"${width}\"` : '') +\n\t\t\t\t\t(height !== undefined ? ` height=\"${height}\"` : '');\n\n\t\t\t\t// Alignment is handled by the serializer's alignment injection,\n\t\t\t\t// which works in both inline-style and CSS-class modes.\n\t\t\t\treturn `<figure><img src=\"${src}\" alt=\"${alt}\"${sizeAttrs}></figure>`;\n\t\t\t},\n\t\t\tparseHTML: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'figure',\n\t\t\t\t\tgetAttrs(el) {\n\t\t\t\t\t\tconst img: HTMLImageElement | null = el.querySelector('img');\n\t\t\t\t\t\tif (!img) return false;\n\t\t\t\t\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\t\t\t\t\tsrc: img.getAttribute('src') ?? '',\n\t\t\t\t\t\t\talt: img.getAttribute('alt') ?? '',\n\t\t\t\t\t\t\talign: 'center',\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst width: string | null = img.getAttribute('width');\n\t\t\t\t\t\tconst height: string | null = img.getAttribute('height');\n\t\t\t\t\t\tif (width) attrs.width = Number.parseInt(width, 10);\n\t\t\t\t\t\tif (height) attrs.height = Number.parseInt(height, 10);\n\n\t\t\t\t\t\t// Check inline style first, then class names (new + legacy)\n\t\t\t\t\t\tconst textAlign: string = el.style?.textAlign ?? '';\n\t\t\t\t\t\tif (textAlign === 'start' || textAlign === 'end' || textAlign === 'center') {\n\t\t\t\t\t\t\tattrs.align = textAlign;\n\t\t\t\t\t\t} else if (textAlign === 'left') {\n\t\t\t\t\t\t\tattrs.align = 'start';\n\t\t\t\t\t\t} else if (textAlign === 'right') {\n\t\t\t\t\t\t\tattrs.align = 'end';\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\tel.classList.contains('notectl-align-start') ||\n\t\t\t\t\t\t\tel.classList.contains('notectl-align-left') ||\n\t\t\t\t\t\t\tel.classList.contains('notectl-image--start') ||\n\t\t\t\t\t\t\tel.classList.contains('notectl-image--left')\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tattrs.align = 'start';\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\tel.classList.contains('notectl-align-end') ||\n\t\t\t\t\t\t\tel.classList.contains('notectl-align-right') ||\n\t\t\t\t\t\t\tel.classList.contains('notectl-image--end') ||\n\t\t\t\t\t\t\tel.classList.contains('notectl-image--right')\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tattrs.align = 'end';\n\t\t\t\t\t\t} else if (el.classList.contains('notectl-align-center')) {\n\t\t\t\t\t\t\tattrs.align = 'center';\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn attrs;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttag: 'img',\n\t\t\t\t\tgetAttrs(el) {\n\t\t\t\t\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\t\t\t\t\tsrc: el.getAttribute('src') ?? '',\n\t\t\t\t\t\t\talt: el.getAttribute('alt') ?? '',\n\t\t\t\t\t\t\talign: 'center',\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst width: string | null = el.getAttribute('width');\n\t\t\t\t\t\tconst height: string | null = el.getAttribute('height');\n\t\t\t\t\t\tif (width) attrs.width = Number.parseInt(width, 10);\n\t\t\t\t\t\tif (height) attrs.height = Number.parseInt(height, 10);\n\t\t\t\t\t\treturn attrs;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsanitize: {\n\t\t\t\ttags: ['figure', 'img'],\n\t\t\t\tattrs: ['src', 'alt', 'width', 'height', 'class', 'style'],\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate registerNodeView(context: PluginContext): void {\n\t\tcontext.registerNodeView(\n\t\t\t'image',\n\t\t\tcreateImageNodeViewFactory(this.config, this.uploadStates, this.resolvedKeymap, this.locale),\n\t\t);\n\t}\n\n\tprivate registerResizeCommands(context: PluginContext): void {\n\t\tconst step: number = this.config.resizeStep ?? 10;\n\t\tconst stepLarge: number = this.config.resizeStepLarge ?? 50;\n\t\tconst maxWidth: number = this.config.maxWidth;\n\n\t\tcontext.registerCommand('resizeImageGrow', () => {\n\t\t\tconst result: boolean = resizeImageByDelta(context, step, maxWidth);\n\t\t\tif (result) this.announceCurrentSize(context);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('resizeImageShrink', () => {\n\t\t\tconst result: boolean = resizeImageByDelta(context, -step, maxWidth);\n\t\t\tif (result) this.announceCurrentSize(context);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('resizeImageGrowLarge', () => {\n\t\t\tconst result: boolean = resizeImageByDelta(context, stepLarge, maxWidth);\n\t\t\tif (result) this.announceCurrentSize(context);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('resizeImageShrinkLarge', () => {\n\t\t\tconst result: boolean = resizeImageByDelta(context, -stepLarge, maxWidth);\n\t\t\tif (result) this.announceCurrentSize(context);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('resetImageSize', () => {\n\t\t\tconst result: boolean = resetImageSize(context);\n\t\t\tif (result) context.announce(this.locale.resetToNaturalSize);\n\t\t\treturn result;\n\t\t});\n\t}\n\n\tprivate registerResizeKeymaps(context: PluginContext): void {\n\t\tconst bindings: Record<string, () => boolean> = {};\n\t\tconst commands: Record<keyof ImageKeymap, string> = {\n\t\t\tgrowWidth: 'resizeImageGrow',\n\t\t\tshrinkWidth: 'resizeImageShrink',\n\t\t\tgrowWidthLarge: 'resizeImageGrowLarge',\n\t\t\tshrinkWidthLarge: 'resizeImageShrinkLarge',\n\t\t\tresetSize: 'resetImageSize',\n\t\t};\n\n\t\tfor (const [slot, commandName] of Object.entries(commands)) {\n\t\t\tconst binding: string | null = this.resolvedKeymap[slot as keyof ImageKeymap] ?? null;\n\t\t\tif (binding) {\n\t\t\t\tbindings[binding] = () => context.executeCommand(commandName);\n\t\t\t}\n\t\t}\n\n\t\tif (Object.keys(bindings).length > 0) {\n\t\t\tcontext.registerKeymap(bindings);\n\t\t}\n\t}\n\n\tprivate registerFileHandler(context: PluginContext): void {\n\t\tcontext.registerFileHandler('image/*', async (file, _position) => {\n\t\t\tif (!this.isAcceptedType(file.type)) return false;\n\t\t\tthis.handleFileInsert(context, file);\n\t\t\treturn true;\n\t\t});\n\t}\n\n\tprivate handleFileInsert(context: PluginContext, file: File): void {\n\t\tif (file.size > this.config.maxFileSize) return;\n\n\t\tconst blobUrl: string = URL.createObjectURL(file);\n\t\tthis.blobUrls.add(blobUrl);\n\n\t\tconst inserted: boolean = insertImage(context, { src: blobUrl });\n\t\tif (!inserted) {\n\t\t\tURL.revokeObjectURL(blobUrl);\n\t\t\tthis.blobUrls.delete(blobUrl);\n\t\t\treturn;\n\t\t}\n\n\t\t// Find the newly inserted image block\n\t\tconst state: EditorState = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return;\n\t\tconst imageBlockId: BlockId = sel.nodeId;\n\n\t\tthis.uploadStates.set(imageBlockId, 'uploading');\n\n\t\t// Upload if service is registered\n\t\tconst uploadService = context.getService(IMAGE_UPLOAD_SERVICE);\n\t\tif (uploadService) {\n\t\t\tthis.uploadFile(context, file, imageBlockId, blobUrl);\n\t\t} else {\n\t\t\tthis.uploadStates.set(imageBlockId, 'complete');\n\t\t}\n\t}\n\n\tprivate async uploadFile(\n\t\tcontext: PluginContext,\n\t\tfile: File,\n\t\timageBlockId: BlockId,\n\t\tblobUrl: string,\n\t): Promise<void> {\n\t\tconst uploadService = context.getService(IMAGE_UPLOAD_SERVICE);\n\t\tif (!uploadService) return;\n\n\t\ttry {\n\t\t\tconst result = await uploadService.upload(file);\n\t\t\tthis.uploadStates.set(imageBlockId, 'complete');\n\n\t\t\t// Replace blob URL with uploaded URL\n\t\t\tconst state: EditorState = context.getState();\n\t\t\tconst block: BlockNode | undefined = state.getBlock(imageBlockId);\n\t\t\tif (!block) return;\n\n\t\t\tconst path: BlockId[] | undefined = state.getNodePath(imageBlockId);\n\t\t\tif (!path) return;\n\n\t\t\tconst merged: BlockAttrs = {\n\t\t\t\t...(block.attrs ?? {}),\n\t\t\t\tsrc: result.url,\n\t\t\t\t...(result.width !== undefined ? { width: result.width } : {}),\n\t\t\t\t...(result.height !== undefined ? { height: result.height } : {}),\n\t\t\t};\n\n\t\t\tconst tr: Transaction = state.transaction('command').setNodeAttr(path, merged).build();\n\t\t\tcontext.dispatch(tr);\n\n\t\t\t// Clean up blob URL\n\t\t\tURL.revokeObjectURL(blobUrl);\n\t\t\tthis.blobUrls.delete(blobUrl);\n\t\t} catch {\n\t\t\tthis.uploadStates.set(imageBlockId, 'error');\n\t\t\tcontext.announce(this.locale.uploadFailed);\n\t\t}\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst icon =\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\"/></svg>';\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'image',\n\t\t\tgroup: 'insert',\n\t\t\ticon,\n\t\t\tlabel: this.locale.insertImage,\n\t\t\ttooltip: this.locale.insertImageTooltip,\n\t\t\tcommand: 'insertImage',\n\t\t\tpopupType: 'custom',\n\t\t\trenderPopup: (container, ctx, onClose) => {\n\t\t\t\trenderImagePopup(container, ctx, {\n\t\t\t\t\tacceptedTypes: this.config.acceptedTypes,\n\t\t\t\t\tlocale: this.locale,\n\t\t\t\t\tonFileInsert: (c, file) => this.handleFileInsert(c, file),\n\t\t\t\t\tonClose,\n\t\t\t\t});\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate isAcceptedType(mimeType: string): boolean {\n\t\treturn this.config.acceptedTypes.some(\n\t\t\t(accepted) =>\n\t\t\t\taccepted === mimeType ||\n\t\t\t\t(accepted.endsWith('/*') && mimeType.startsWith(accepted.slice(0, -1))),\n\t\t);\n\t}\n\n\tprivate isImageSelected(state: EditorState): boolean {\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return false;\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.nodeId);\n\t\treturn block?.type === 'image';\n\t}\n\n\tprivate announceImageSelection(state: EditorState): void {\n\t\tif (!this.context) return;\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.nodeId);\n\t\tif (!block || block.type !== 'image') return;\n\n\t\tconst alt: string = (block.attrs?.alt as string | undefined) ?? '';\n\t\tconst width: number | undefined = block.attrs?.width as number | undefined;\n\t\tconst height: number | undefined = block.attrs?.height as number | undefined;\n\n\t\tconst parts: string[] = [this.locale.imageSelected];\n\t\tif (alt) parts.push(`${this.locale.altTextPrefix}${alt}.`);\n\t\tif (width !== undefined && height !== undefined) {\n\t\t\tparts.push(this.locale.imageSizeAnnounce(width, height));\n\t\t}\n\n\t\tconst shrinkKey: string | null = this.resolvedKeymap.shrinkWidth ?? null;\n\t\tconst growKey: string | null = this.resolvedKeymap.growWidth ?? null;\n\t\tif (shrinkKey && growKey) {\n\t\t\tparts.push(this.locale.resizeHint(formatShortcut(shrinkKey), formatShortcut(growKey)));\n\t\t}\n\n\t\tthis.context.announce(parts.join(' '));\n\t}\n\n\tprivate announceCurrentSize(context: PluginContext): void {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.nodeId);\n\t\tif (!block || block.type !== 'image') return;\n\n\t\tconst width: number | undefined = block.attrs?.width as number | undefined;\n\t\tconst height: number | undefined = block.attrs?.height as number | undefined;\n\t\tif (width !== undefined && height !== undefined) {\n\t\t\tcontext.announce(this.locale.imageResized(width, height));\n\t\t}\n\t}\n}\n","/** Image styles — display, alignment, resize handles, upload overlay. */\nexport const IMAGE_CSS = `\n/* Image */\n.notectl-image {\n\tmargin: 8px 0;\n\tuser-select: none;\n\tline-height: 0;\n}\n\n.notectl-image--center {\n\ttext-align: center;\n}\n\n.notectl-image--start {\n\ttext-align: start;\n}\n\n.notectl-image--end {\n\ttext-align: end;\n}\n\n.notectl-image__container {\n\tdisplay: inline-block;\n\tposition: relative;\n\tline-height: 0;\n}\n\n.notectl-image__img {\n\tdisplay: block;\n\tmax-width: 100%;\n\tborder-radius: 4px;\n}\n\n.notectl-image--selected .notectl-image__container {\n\toutline: 2px solid var(--notectl-primary);\n\toutline-offset: 2px;\n\tborder-radius: 6px;\n}\n\n/* Alignment toolbar (appears on image selection) */\n.notectl-image__align-toolbar {\n\tdisplay: flex;\n\tgap: 2px;\n\tposition: absolute;\n\ttop: -36px;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n\tbackground: var(--notectl-surface-overlay);\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 6px;\n\tpadding: 2px;\n\tbox-shadow: 0 2px 8px var(--notectl-shadow);\n\tz-index: 10;\n}\n\n.notectl-image__align-btn {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 28px;\n\theight: 28px;\n\tborder: none;\n\tbackground: transparent;\n\tborder-radius: 4px;\n\tcursor: pointer;\n\tcolor: var(--notectl-fg);\n}\n\n.notectl-image__align-btn:hover {\n\tbackground: var(--notectl-hover-bg);\n}\n\n.notectl-image__align-btn--active {\n\tbackground: var(--notectl-active-bg);\n\tcolor: var(--notectl-primary-fg);\n}\n\n.notectl-image__align-btn svg {\n\twidth: 16px;\n\theight: 16px;\n\tfill: currentColor;\n}\n\n/* Upload overlay */\n.notectl-image__overlay {\n\tposition: absolute;\n\tinset: 0;\n\tdisplay: none;\n\talign-items: center;\n\tjustify-content: center;\n\tbackground: rgba(255, 255, 255, 0.8);\n\tborder-radius: 4px;\n\tfont-size: 13px;\n\tcolor: var(--notectl-fg-muted);\n}\n\n.notectl-image__overlay--uploading {\n\tdisplay: flex;\n}\n\n.notectl-image__overlay--error {\n\tdisplay: flex;\n\tbackground: var(--notectl-danger-muted);\n\tcolor: var(--notectl-danger);\n}\n\n/* Resize overlay + handles */\n.notectl-image__resize-overlay {\n\tposition: absolute;\n\tinset: 0;\n\tpointer-events: none;\n}\n\n.notectl-image__resize-handle {\n\tposition: absolute;\n\twidth: 10px;\n\theight: 10px;\n\tbackground: var(--notectl-bg);\n\tborder: 2px solid var(--notectl-primary);\n\tborder-radius: 50%;\n\tpointer-events: all;\n\tz-index: 2;\n\ttransition: transform 0.1s, background 0.1s;\n}\n\n.notectl-image__resize-handle:hover {\n\tbackground: var(--notectl-primary);\n\ttransform: scale(1.3);\n}\n\n.notectl-image--resizing .notectl-image__resize-handle {\n\tbackground: var(--notectl-primary);\n}\n\n.notectl-image__resize-handle--nw {\n\ttop: -5px;\n\tinset-inline-start: -5px;\n\tcursor: nwse-resize;\n}\n\n.notectl-image__resize-handle--ne {\n\ttop: -5px;\n\tinset-inline-end: -5px;\n\tcursor: nesw-resize;\n}\n\n.notectl-image__resize-handle--sw {\n\tbottom: -5px;\n\tinset-inline-start: -5px;\n\tcursor: nesw-resize;\n}\n\n.notectl-image__resize-handle--se {\n\tbottom: -5px;\n\tinset-inline-end: -5px;\n\tcursor: nwse-resize;\n}\n\n/* RTL cursor overrides — flip diagonal cursors when in RTL context */\n[dir=\"rtl\"] .notectl-image__resize-handle--nw {\n\tcursor: nesw-resize;\n}\n\n[dir=\"rtl\"] .notectl-image__resize-handle--ne {\n\tcursor: nwse-resize;\n}\n\n[dir=\"rtl\"] .notectl-image__resize-handle--sw {\n\tcursor: nwse-resize;\n}\n\n[dir=\"rtl\"] .notectl-image__resize-handle--se {\n\tcursor: nesw-resize;\n}\n\n/* Size indicator tooltip */\n.notectl-image__size-indicator {\n\tposition: absolute;\n\tbottom: -28px;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n\tpadding: 2px 8px;\n\tbackground: var(--notectl-tooltip-bg);\n\tcolor: var(--notectl-tooltip-fg);\n\tfont-size: 11px;\n\tfont-weight: 500;\n\tborder-radius: 4px;\n\twhite-space: nowrap;\n\tpointer-events: none;\n\topacity: 0;\n\ttransition: opacity 0.15s;\n\tz-index: 3;\n}\n\n.notectl-image__size-indicator--visible {\n\topacity: 1;\n}\n\n/* Keyboard resize hint (shown on selection, hidden during drag) */\n.notectl-image__keyboard-hint {\n\tdisplay: none;\n\tposition: absolute;\n\tbottom: -28px;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n\tpadding: 2px 8px;\n\tfont-size: 11px;\n\tcolor: var(--notectl-fg-muted);\n\twhite-space: nowrap;\n\tpointer-events: none;\n\tz-index: 3;\n}\n\n.notectl-image--selected .notectl-image__keyboard-hint {\n\tdisplay: block;\n}\n\n.notectl-image--resizing .notectl-image__keyboard-hint {\n\tdisplay: none;\n}\n\n/* Resizing feedback */\n.notectl-image--resizing .notectl-image__img {\n\topacity: 0.85;\n}\n`;\n","/**\n * Renders the image insert popup with file upload and URL input,\n * following the same pattern as FontSizePopup.\n */\n\nimport { setStyleProperty, setStyleText } from '../../style/StyleRuntime.js';\nimport type { PluginContext } from '../Plugin.js';\nimport { insertImage } from './ImageCommands.js';\nimport type { ImageLocale } from './ImageLocale.js';\n\n// --- Config ---\n\nexport interface ImagePopupConfig {\n\treadonly acceptedTypes: readonly string[];\n\treadonly locale: ImageLocale;\n\treadonly onFileInsert: (context: PluginContext, file: File) => void;\n\treadonly onClose: () => void;\n}\n\n// --- Public Entry Point ---\n\n/** Builds the image insert popup DOM inside the given container. */\nexport function renderImagePopup(\n\tcontainer: HTMLElement,\n\tcontext: PluginContext,\n\tconfig: ImagePopupConfig,\n): void {\n\tsetStyleProperty(container, 'padding', '8px');\n\tsetStyleProperty(container, 'minWidth', '240px');\n\n\tappendFileUploadSection(container, context, config);\n\tappendSeparator(container, config.locale);\n\tappendUrlSection(container, context, config);\n}\n\n// --- File Upload Section ---\n\nfunction appendFileUploadSection(\n\tcontainer: HTMLElement,\n\tcontext: PluginContext,\n\tconfig: ImagePopupConfig,\n): void {\n\tconst fileInput: HTMLInputElement = document.createElement('input');\n\tfileInput.type = 'file';\n\tfileInput.accept = config.acceptedTypes.join(',');\n\tsetStyleText(fileInput, 'position:absolute;width:0;height:0;overflow:hidden;opacity:0;');\n\n\tconst uploadBtn: HTMLButtonElement = document.createElement('button');\n\tuploadBtn.type = 'button';\n\tuploadBtn.textContent = config.locale.uploadFromComputer;\n\tuploadBtn.setAttribute('aria-label', config.locale.uploadAria);\n\tsetStyleText(\n\t\tuploadBtn,\n\t\t'display:block;width:100%;padding:8px 12px;cursor:pointer;' +\n\t\t\t'text-align:center;box-sizing:border-box;' +\n\t\t\t'border:1px solid var(--notectl-border);border-radius:4px;' +\n\t\t\t'background:var(--notectl-surface-raised);color:var(--notectl-fg);',\n\t);\n\n\tuploadBtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tfileInput.click();\n\t});\n\n\tfileInput.addEventListener('change', () => {\n\t\tconst file: File | undefined = fileInput.files?.[0];\n\t\tif (file) {\n\t\t\tconfig.onFileInsert(context, file);\n\t\t\tconfig.onClose();\n\t\t\tcontext.getContainer().focus();\n\t\t}\n\t});\n\n\tcontainer.appendChild(fileInput);\n\tcontainer.appendChild(uploadBtn);\n}\n\n// --- Separator ---\n\nfunction appendSeparator(container: HTMLElement, locale: ImageLocale): void {\n\tconst separator: HTMLDivElement = document.createElement('div');\n\tsetStyleText(\n\t\tseparator,\n\t\t'display:flex;align-items:center;margin:8px 0;' +\n\t\t\t'color:var(--notectl-fg-muted);font-size:12px;',\n\t);\n\n\tconst line1: HTMLSpanElement = document.createElement('span');\n\tsetStyleText(line1, 'flex:1;height:1px;background:var(--notectl-border);');\n\n\tconst orText: HTMLSpanElement = document.createElement('span');\n\torText.textContent = locale.separator;\n\tsetStyleText(orText, 'padding:0 8px;');\n\n\tconst line2: HTMLSpanElement = document.createElement('span');\n\tsetStyleText(line2, 'flex:1;height:1px;background:var(--notectl-border);');\n\n\tseparator.appendChild(line1);\n\tseparator.appendChild(orText);\n\tseparator.appendChild(line2);\n\tcontainer.appendChild(separator);\n}\n\n// --- URL Input Section ---\n\nfunction appendUrlSection(\n\tcontainer: HTMLElement,\n\tcontext: PluginContext,\n\tconfig: ImagePopupConfig,\n): void {\n\tconst urlInput: HTMLInputElement = document.createElement('input');\n\turlInput.type = 'url';\n\turlInput.placeholder = config.locale.urlPlaceholder;\n\turlInput.setAttribute('aria-label', config.locale.urlAria);\n\tsetStyleText(\n\t\turlInput,\n\t\t'width:100%;padding:6px 8px;box-sizing:border-box;' +\n\t\t\t'border:1px solid var(--notectl-border);border-radius:4px;' +\n\t\t\t'background:var(--notectl-bg);color:var(--notectl-fg);',\n\t);\n\n\tconst insertBtn: HTMLButtonElement = document.createElement('button');\n\tinsertBtn.type = 'button';\n\tinsertBtn.textContent = config.locale.insertButton;\n\tinsertBtn.setAttribute('aria-label', config.locale.insertAria);\n\tsetStyleText(\n\t\tinsertBtn,\n\t\t'width:100%;padding:8px 12px;margin-top:4px;cursor:pointer;' +\n\t\t\t'border:1px solid var(--notectl-border);border-radius:4px;' +\n\t\t\t'background:var(--notectl-surface-raised);color:var(--notectl-fg);',\n\t);\n\n\tconst applyUrl = (): void => {\n\t\tconst src: string = urlInput.value.trim();\n\t\tif (src) {\n\t\t\tinsertImage(context, { src });\n\t\t\tconfig.onClose();\n\t\t\tcontext.getContainer().focus();\n\t\t}\n\t};\n\n\tinsertBtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tapplyUrl();\n\t});\n\n\turlInput.addEventListener('keydown', (e: KeyboardEvent) => {\n\t\tif (e.key === 'Enter') {\n\t\t\te.preventDefault();\n\t\t\tapplyUrl();\n\t\t}\n\t});\n\n\tcontainer.appendChild(urlInput);\n\tcontainer.appendChild(insertBtn);\n\n\trequestAnimationFrame(() => urlInput.focus());\n}\n"],"names":["insertImage","context","attrs","state","getState","sel","selection","imageAttrs","src","alt","align","width","height","isGapCursor","anchorBlockId","isNodeSelection","nodeId","anchor","blockId","cellId","bid","block","getBlock","type","path","getNodePath","id","node","findTableCellAncestor","cellPath","imageBlock","createBlockNode","nodeType","cell","builder","transaction","blockChildren","getBlockChildren","i","length","rawIndex","children","findIndex","c","isBlockNode","removeNode","insertNode","setSelection","createNodeSelection","dispatch","build","insertImageIntoCell","blockIndex","doc","b","newParagraph","tr","insertImageAtRoot","resizeImageByDelta","delta","maxWidth","currentWidth","currentHeight","aspectRatio","clampedWidth","Math","max","min","newHeight","round","merged","setNodeAttr","setImageAttr","IMAGE_LOCALE_EN","insertImageTooltip","uploadFromComputer","uploadAria","separator","urlPlaceholder","urlAria","insertButton","insertAria","imageAria","parts","push","join","resetToNaturalSize","uploadFailed","uploading","resizeHandleLabel","position","imageSelected","altTextPrefix","imageSizeAnnounce","w","h","resizeHint","shrink","grow","imageResized","keyboardResizeHint","localeModules","assign","import","async","loadImageLocale","lang","loader","default","ALIGNMENT_CLASSES","start","center","end","HANDLE_CURSORS","nw","ne","sw","se","HANDLE_X_SIGN","HANDLE_POSITIONS_LTR","HANDLE_POSITIONS_RTL","RTL_CURSOR_MAP","getHandleLabel","isRtl","locale","positionName","activeCursorStyle","clearGlobalResizeCursor","remove","createImageNodeViewFactory","config","uploadStates","resolvedKeymap","figure","document","createElement","className","setAttribute","container","img","draggable","overlay","appendChild","currentNodeId","resizeOverlay","applyAttrs","n","setStyleProperty","cls","Object","values","classList","alignClass","add","uploadState","get","isUploading","toggle","textContent","removeAttribute","updateAriaLabel","dimensionsCommitted","attachHandleListeners","handle","sizeIndicator","startX","startWidth","xSign","onPointerMove","e","deltaX","clientX","newWidth","setStyleProperties","onPointerUp","removeEventListener","finalWidth","getBoundingClientRect","finalHeight","prevWidth","prevHeight","commitResize","target","releasePointerCapture","pointerId","addEventListener","preventDefault","stopPropagation","getTextDirection","sign","getResizeXSign","imgHeight","cursor","referenceNode","nonce","getStyleNonceForNode","head","setGlobalResizeCursor","setPointerCapture","removeResizeOverlay","hasWidth","hasHeight","naturalW","naturalWidth","naturalH","naturalHeight","clampedW","ratio","clampedH","dom","contentDOM","update","updatedNode","selectNode","resizable","positions","pos","hintText","shrinkWidth","growWidth","formatShortcut","buildKeyboardHintText","hint","createResizeOverlay","deselectNode","destroy","IMAGE_UPLOAD_SERVICE","ServiceKey","DEFAULT_IMAGE_KEYMAP","growWidthLarge","shrinkWidthLarge","resetSize","DEFAULT_IMAGE_CONFIG","maxFileSize","acceptedTypes","resizeStep","resizeStepLarge","ImagePlugin","name","priority","Map","blobUrls","Set","constructor","this","keymap","init","resolveLocale","registerStyleSheet","registerNodeSpec","registerNodeView","registerCommand","nodePath","parentPath","slice","parent","parentId","imageIndex","selectionTarget","removedId","rootChildren","idx","adjacent","findSelectionTargetAfterRemoval","createCollapsedSelection","removeImage","registerImageCommands","registerResizeCommands","registerResizeKeymaps","registerFileHandler","registerToolbarItem","url","URL","revokeObjectURL","clear","onStateChange","oldState","newState","_tr","keys","delete","oldIsImage","isImageSelected","nowIsImage","announceImageSelection","group","isVoid","selectable","toDOM","createBlockElement","imgContainer","toHTML","escapeHTML","parseHTML","tag","getAttrs","el","querySelector","getAttribute","Number","parseInt","textAlign","style","contains","sanitize","tags","step","stepLarge","result","announceCurrentSize","cleaned","fromEntries","entries","filter","k","resetImageSize","announce","bindings","commands","slot","commandName","binding","executeCommand","registerKeymap","file","_position","isAcceptedType","handleFileInsert","size","blobUrl","createObjectURL","imageBlockId","set","getService","uploadFile","uploadService","upload","icon","label","tooltip","command","popupType","renderPopup","ctx","onClose","fileInput","accept","setStyleText","uploadBtn","click","files","onFileInsert","getContainer","focus","appendFileUploadSection","line1","orText","line2","appendSeparator","urlInput","placeholder","insertBtn","applyUrl","value","trim","key","requestAnimationFrame","appendUrlSection","renderImagePopup","mimeType","some","accepted","endsWith","startsWith","shrinkKey","growKey"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"link.mjs","sources":["../../src/plugins/link/LinkLocale.ts","../../src/plugins/link/LinkPlugin.ts"],"sourcesContent":["/**\n * Locale interface and default English locale for the LinkPlugin.\n */\n\n// --- Locale Interface ---\n\nexport interface LinkLocale {\n\treadonly label: string;\n\treadonly tooltip: (shortcut: string) => string;\n\treadonly removeLink: string;\n\treadonly removeLinkAria: string;\n\treadonly urlPlaceholder: string;\n\treadonly urlAria: string;\n\treadonly apply: string;\n\treadonly applyAria: string;\n}\n\n// --- Default English Locale ---\n\nexport const LINK_LOCALE_EN: LinkLocale = {\n\tlabel: 'Link',\n\ttooltip: (shortcut: string) => `Insert Link (${shortcut})`,\n\tremoveLink: 'Remove Link',\n\tremoveLinkAria: 'Remove link',\n\turlPlaceholder: 'https://...',\n\turlAria: 'Link URL',\n\tapply: 'Apply',\n\tapplyAria: 'Apply link',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: Record<string, () => Promise<{ default: LinkLocale }>> = import.meta.glob<{\n\tdefault: LinkLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadLinkLocale(lang: string): Promise<LinkLocale> {\n\tif (lang === 'en') return LINK_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return LINK_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn LINK_LOCALE_EN;\n\t}\n}\n","/**\n * LinkPlugin: registers a link mark type with href attribute,\n * toggle command, keyboard shortcut (Mod-K), and toolbar button\n * with a URL input popup.\n */\n\nimport {\n\tapplyAttributedMark,\n\tisAttributedMarkActive,\n\tremoveAttributedMark,\n} from '../../commands/AttributedMarkCommands.js';\nimport { hasMark } from '../../model/Document.js';\nimport { escapeHTML } from '../../model/HTMLUtils.js';\nimport { isCollapsed, isTextSelection } from '../../model/Selection.js';\nimport { markType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { LINK_LOCALE_EN, type LinkLocale, loadLinkLocale } from './LinkLocale.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\tlink: { href: string };\n\t}\n}\n\n// --- Configuration ---\n\nexport interface LinkConfig {\n\t/** Whether to add rel=\"noopener noreferrer\" and target=\"_blank\" by default. */\n\treadonly openInNewTab: boolean;\n\treadonly locale?: LinkLocale;\n}\n\nconst DEFAULT_CONFIG: LinkConfig = {\n\topenInNewTab: true,\n};\n\n// --- Plugin ---\n\nexport class LinkPlugin implements Plugin {\n\treadonly id = 'link';\n\treadonly name = 'Link';\n\treadonly priority = 25;\n\n\tprivate readonly config: LinkConfig;\n\tprivate locale!: LinkLocale;\n\n\tconstructor(config?: Partial<LinkConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(context, this.config.locale, LINK_LOCALE_EN, loadLinkLocale);\n\t\tthis.registerMarkSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymap(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tprivate registerMarkSpec(context: PluginContext): void {\n\t\tconst openInNewTab = this.config.openInNewTab;\n\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: 'link',\n\t\t\trank: 10,\n\t\t\tattrs: {\n\t\t\t\thref: { default: '' },\n\t\t\t},\n\t\t\ttoDOM(mark) {\n\t\t\t\tconst a = document.createElement('a');\n\t\t\t\tconst href = mark.attrs?.href ?? '';\n\t\t\t\ta.setAttribute('href', href);\n\t\t\t\tif (openInNewTab) {\n\t\t\t\t\ta.setAttribute('target', '_blank');\n\t\t\t\t\ta.setAttribute('rel', 'noopener noreferrer');\n\t\t\t\t}\n\t\t\t\treturn a;\n\t\t\t},\n\t\t\ttoHTMLString: (mark, content) => {\n\t\t\t\tconst href: string = escapeHTML(String(mark.attrs?.href ?? ''));\n\t\t\t\tif (openInNewTab) {\n\t\t\t\t\treturn `<a href=\"${href}\" target=\"_blank\" rel=\"noopener noreferrer\">${content}</a>`;\n\t\t\t\t}\n\t\t\t\treturn `<a href=\"${href}\">${content}</a>`;\n\t\t\t},\n\t\t\tparseHTML: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'a',\n\t\t\t\t\tgetAttrs: (el) => {\n\t\t\t\t\t\tconst href: string = el.getAttribute('href') ?? '';\n\t\t\t\t\t\treturn { href };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsanitize: { tags: ['a'], attrs: ['href', 'target', 'rel'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('toggleLink', () => {\n\t\t\tconst state = context.getState();\n\t\t\treturn this.toggleLink(context, state);\n\t\t});\n\n\t\tcontext.registerCommand('setLink', () => {\n\t\t\t// setLink is called by the popup after URL input\n\t\t\t// The actual URL is set via the popup's custom render\n\t\t\treturn false;\n\t\t});\n\n\t\tcontext.registerCommand('removeLink', () => {\n\t\t\tconst state = context.getState();\n\t\t\treturn this.removeLink(context, state);\n\t\t});\n\t}\n\n\tprivate registerKeymap(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Mod-K': () => context.executeCommand('toggleLink'),\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst icon =\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z\"/></svg>';\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'link',\n\t\t\tgroup: 'insert',\n\t\t\ticon,\n\t\t\tlabel: this.locale.label,\n\t\t\ttooltip: this.locale.tooltip(formatShortcut('Mod-K')),\n\t\t\tcommand: 'toggleLink',\n\t\t\tpopupType: 'custom',\n\t\t\trenderPopup: (container, ctx, onClose) => {\n\t\t\t\tthis.renderLinkPopup(container, ctx, onClose);\n\t\t\t},\n\t\t\tisActive: (state) => this.isLinkActive(state),\n\t\t\tisEnabled: (state) => !isCollapsed(state.selection),\n\t\t});\n\t}\n\n\tprivate isLinkActive(state: EditorState): boolean {\n\t\treturn isAttributedMarkActive(state, 'link');\n\t}\n\n\tprivate toggleLink(context: PluginContext, state: EditorState): boolean {\n\t\tif (this.isLinkActive(state)) {\n\t\t\treturn this.removeLink(context, state);\n\t\t}\n\t\t// Adding links requires the toolbar popup for URL input\n\t\treturn false;\n\t}\n\n\tprivate addLink(context: PluginContext, state: EditorState, href: string): boolean {\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\t\tif (isCollapsed(sel)) return false;\n\n\t\tconst mark = { type: markType('link'), attrs: { href } };\n\t\tconst tr = applyAttributedMark(state, mark);\n\t\tif (!tr) return false;\n\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate removeLink(context: PluginContext, state: EditorState): boolean {\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\t// Remove link from entire link span around cursor (plugin-specific extent scan)\n\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!block) return false;\n\n\t\t\tconst textChildren: { pos: number; end: number; hasLink: boolean }[] = [];\n\t\t\tlet pos = 0;\n\t\t\tfor (const child of block.children) {\n\t\t\t\tif (!('text' in child)) continue;\n\t\t\t\tconst end = pos + child.text.length;\n\t\t\t\ttextChildren.push({ pos, end, hasLink: hasMark(child.marks, markType('link')) });\n\t\t\t\tpos = end;\n\t\t\t}\n\n\t\t\tconst cursorIdx = textChildren.findIndex(\n\t\t\t\t(c) => sel.anchor.offset >= c.pos && sel.anchor.offset <= c.end,\n\t\t\t);\n\t\t\tconst cursorEntry = cursorIdx >= 0 ? textChildren[cursorIdx] : undefined;\n\t\t\tif (cursorIdx === -1 || !cursorEntry?.hasLink) return false;\n\n\t\t\tlet startIdx = cursorIdx;\n\t\t\twhile (startIdx > 0 && textChildren[startIdx - 1]?.hasLink) {\n\t\t\t\tstartIdx--;\n\t\t\t}\n\n\t\t\tlet endIdx = cursorIdx;\n\t\t\twhile (endIdx < textChildren.length - 1 && textChildren[endIdx + 1]?.hasLink) {\n\t\t\t\tendIdx++;\n\t\t\t}\n\n\t\t\tconst startEntry = textChildren[startIdx];\n\t\t\tconst endEntry = textChildren[endIdx];\n\t\t\tif (!startEntry || !endEntry) return false;\n\n\t\t\tconst linkStart = startEntry.pos;\n\t\t\tconst linkEnd = endEntry.end;\n\n\t\t\tconst builder = state.transaction('command');\n\t\t\tbuilder.removeMark(sel.anchor.blockId, linkStart, linkEnd, { type: markType('link') });\n\t\t\tbuilder.setSelection(sel);\n\t\t\tcontext.dispatch(builder.build());\n\t\t\treturn true;\n\t\t}\n\n\t\t// Range selection: delegate to shared helper\n\t\tconst tr = removeAttributedMark(state, markType('link'));\n\t\tif (!tr) return false;\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate renderLinkPopup(\n\t\tcontainer: HTMLElement,\n\t\tcontext: PluginContext,\n\t\tonClose: () => void,\n\t): void {\n\t\tcontainer.classList.add('notectl-link-popup');\n\n\t\tconst state = context.getState();\n\t\tconst isActive = this.isLinkActive(state);\n\n\t\tif (isActive) {\n\t\t\t// Show remove link button\n\t\t\tconst removeBtn = document.createElement('button');\n\t\t\tremoveBtn.type = 'button';\n\t\t\tremoveBtn.className = 'notectl-link-popup__button';\n\t\t\tremoveBtn.textContent = this.locale.removeLink;\n\t\t\tremoveBtn.setAttribute('aria-label', this.locale.removeLinkAria);\n\t\t\tremoveBtn.addEventListener('mousedown', (e) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tcontext.executeCommand('removeLink');\n\t\t\t\tonClose();\n\t\t\t\tcontext.getContainer().focus();\n\t\t\t});\n\t\t\tcontainer.appendChild(removeBtn);\n\t\t} else {\n\t\t\t// Show URL input\n\t\t\tconst input = document.createElement('input');\n\t\t\tinput.type = 'url';\n\t\t\tinput.className = 'notectl-link-popup__input';\n\t\t\tinput.placeholder = this.locale.urlPlaceholder;\n\t\t\tinput.setAttribute('aria-label', this.locale.urlAria);\n\n\t\t\tconst applyBtn = document.createElement('button');\n\t\t\tapplyBtn.type = 'button';\n\t\t\tapplyBtn.className = 'notectl-link-popup__button notectl-link-popup__button--apply';\n\t\t\tapplyBtn.textContent = this.locale.apply;\n\t\t\tapplyBtn.setAttribute('aria-label', this.locale.applyAria);\n\n\t\t\tconst applyLink = (): void => {\n\t\t\t\tconst href = input.value.trim();\n\t\t\t\tif (href) {\n\t\t\t\t\tthis.addLink(context, context.getState(), href);\n\t\t\t\t\tonClose();\n\t\t\t\t\tcontext.getContainer().focus();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tapplyBtn.addEventListener('mousedown', (e) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tapplyLink();\n\t\t\t});\n\n\t\t\tinput.addEventListener('keydown', (e) => {\n\t\t\t\tif (e.key === 'Enter') {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tapplyLink();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tcontainer.appendChild(input);\n\t\t\tcontainer.appendChild(applyBtn);\n\n\t\t\t// Auto-focus input\n\t\t\trequestAnimationFrame(() => input.focus());\n\t\t}\n\t}\n}\n"],"names":["LINK_LOCALE_EN","label","tooltip","shortcut","removeLink","removeLinkAria","urlPlaceholder","urlAria","apply","applyAria","localeModules","assign","import","async","loadLinkLocale","lang","loader","default","DEFAULT_CONFIG","openInNewTab","LinkPlugin","id","name","priority","config","locale","constructor","this","init","context","resolveLocale","registerMarkSpec","registerCommands","registerKeymap","registerToolbarItem","type","rank","attrs","href","toDOM","mark","a","document","createElement","setAttribute","toHTMLString","content","escapeHTML","String","parseHTML","tag","getAttrs","el","getAttribute","sanitize","tags","registerCommand","state","getState","toggleLink","executeCommand","group","icon","formatShortcut","command","popupType","renderPopup","container","ctx","onClose","renderLinkPopup","isActive","isLinkActive","isEnabled","isCollapsed","selection","isAttributedMarkActive","addLink","sel","isTextSelection","markType","tr","applyAttributedMark","dispatch","block","getBlock","anchor","blockId","textChildren","pos","child","children","end","text","length","push","hasLink","hasMark","marks","cursorIdx","findIndex","c","offset","cursorEntry","startIdx","endIdx","startEntry","endEntry","linkStart","linkEnd","builder","transaction","removeMark","setSelection","build","removeAttributedMark","classList","add","removeBtn","className","textContent","addEventListener","e","preventDefault","stopPropagation","getContainer","focus","appendChild","input","placeholder","applyBtn","applyLink","value","trim","key","requestAnimationFrame"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"list.mjs","sources":["../../src/editor/styles/list.ts","../../src/plugins/list/ListLocale.ts","../../src/plugins/list/ListPlugin.ts"],"sourcesContent":["/** Width of the list marker / checkbox area in pixels. */\nexport const LIST_MARKER_WIDTH = 24;\n\n/** List styles — bullet, ordered, checklist items. */\nexport const LIST_CSS = `\n/* List Wrappers — suppress native markers, we use ::before pseudo-elements */\n.notectl-list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Ordered List — each <ol> wrapper resets the counter */\n.notectl-list--ordered {\n\tcounter-reset: notectl-ordered;\n}\n\n/* List Items */\n.notectl-list-item {\n\tmargin: 0;\n\tpadding: 2px 0;\n\tpadding-inline-start: ${LIST_MARKER_WIDTH}px;\n\tmin-height: 1.6em;\n\tposition: relative;\n}\n\n.notectl-list-item::before {\n\tposition: absolute;\n\tinset-inline-start: 0;\n\tdisplay: inline-block;\n\twidth: ${LIST_MARKER_WIDTH}px;\n\ttext-align: center;\n}\n\n/* Bullet List */\n.notectl-list-item--bullet::before {\n\tcontent: '\\\\2022';\n\tcolor: var(--notectl-fg);\n}\n\n/* Ordered List — counter increment per item */\n.notectl-list-item--ordered {\n\tcounter-increment: notectl-ordered;\n}\n\n.notectl-list-item--ordered::before {\n\tcontent: counter(notectl-ordered) '.';\n\tcolor: var(--notectl-fg);\n\tfont-size: 14px;\n}\n\n/* Checklist */\n.notectl-list-item--checklist::before {\n\tcontent: '\\\\2610';\n\tfont-size: 16px;\n\tcolor: var(--notectl-fg-muted);\n\tcursor: pointer;\n}\n\n.notectl-list-item--checklist[data-checked=\"true\"]::before {\n\tcontent: '\\\\2611';\n\tcolor: var(--notectl-success);\n}\n\n.notectl-list-item--checklist[data-checked=\"true\"] {\n\tcolor: var(--notectl-fg-muted);\n\ttext-decoration: line-through;\n}\n`;\n","/**\n * Locale interface and default English locale for the ListPlugin.\n */\n\n// --- Locale Interface ---\n\nexport interface ListLocale {\n\treadonly bulletList: string;\n\treadonly numberedList: string;\n\treadonly checklist: string;\n}\n\n// --- Default English Locale ---\n\nexport const LIST_LOCALE_EN: ListLocale = {\n\tbulletList: 'Bullet List',\n\tnumberedList: 'Numbered List',\n\tchecklist: 'Checklist',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: Record<string, () => Promise<{ default: ListLocale }>> = import.meta.glob<{\n\tdefault: ListLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadListLocale(lang: string): Promise<ListLocale> {\n\tif (lang === 'en') return LIST_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return LIST_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn LIST_LOCALE_EN;\n\t}\n}\n","/**\n * ListPlugin: registers ordered, unordered, and checklist block types\n * with NodeSpecs, toggle commands, indent/outdent (Tab/Shift-Tab),\n * input rules, and toolbar buttons.\n *\n * List items are modeled as flat blocks with a `listType` and `indent` attribute,\n * allowing simple nesting representation without deep tree structures.\n */\n\nimport { LIST_CSS, LIST_MARKER_WIDTH } from '../../editor/styles/list.js';\nimport { isNodeOfType } from '../../model/AttrRegistry.js';\nimport { generateBlockId, getBlockText } from '../../model/Document.js';\nimport { createCollapsedSelection, isCollapsed, isTextSelection } from '../../model/Selection.js';\nimport { type BlockId, blockId, nodeType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport { setStyleProperty } from '../../style/StyleRuntime.js';\nimport { createBlockElement } from '../../view/DomUtils.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport { LIST_LOCALE_EN, type ListLocale, loadListLocale } from './ListLocale.js';\n\n// --- Attribute Registry Augmentation ---\n\nexport type ListType = 'bullet' | 'ordered' | 'checklist';\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface NodeAttrRegistry {\n\t\tlist_item: { listType: ListType; indent: number; checked: boolean };\n\t}\n}\n\n// --- Configuration ---\n\nexport interface ListConfig {\n\t/** Which list types to enable. Defaults to all. */\n\treadonly types: readonly ListType[];\n\t/** Maximum indent depth. Defaults to 4. */\n\treadonly maxIndent: number;\n\t/**\n\t * When true, checklist checkboxes remain interactive even in read-only mode.\n\t * Defaults to false (checkboxes are fully read-only).\n\t */\n\treadonly interactiveCheckboxes?: boolean;\n\treadonly locale?: ListLocale;\n}\n\nconst DEFAULT_CONFIG: ListConfig = {\n\ttypes: ['bullet', 'ordered', 'checklist'],\n\tmaxIndent: 4,\n};\n\n// --- List Type Metadata ---\n\ninterface ListTypeDefinition {\n\treadonly type: ListType;\n\treadonly icon: string;\n\treadonly inputPattern: RegExp;\n\treadonly inputPrefix: string;\n}\n\nconst BULLET_LIST_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z\"/></svg>';\nconst NUMBERED_LIST_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z\"/></svg>';\nconst CHECKLIST_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M22 7h-9v2h9V7zm0 8h-9v2h9v-2zM5.54 11L2 7.46l1.41-1.41 2.12 2.12 4.24-4.24 1.41 1.41L5.54 11zm0 8L2 15.46l1.41-1.41 2.12 2.12 4.24-4.24 1.41 1.41L5.54 19z\"/></svg>';\n\nconst LIST_TYPE_DEFINITIONS: readonly ListTypeDefinition[] = [\n\t{\n\t\ttype: 'bullet',\n\t\ticon: BULLET_LIST_ICON,\n\t\tinputPattern: /^[-*] $/,\n\t\tinputPrefix: '- ',\n\t},\n\t{\n\t\ttype: 'ordered',\n\t\ticon: NUMBERED_LIST_ICON,\n\t\tinputPattern: /^\\d+\\. $/,\n\t\tinputPrefix: '1. ',\n\t},\n\t{\n\t\ttype: 'checklist',\n\t\ticon: CHECKLIST_ICON,\n\t\tinputPattern: /^\\[[ x]] $/,\n\t\tinputPrefix: '[ ] ',\n\t},\n];\n\n// --- Plugin ---\n\nexport class ListPlugin implements Plugin {\n\treadonly id = 'list';\n\treadonly name = 'List';\n\treadonly priority = 35;\n\n\tprivate readonly config: ListConfig;\n\tprivate locale!: ListLocale;\n\tprivate context: PluginContext | null = null;\n\tprivate checkboxClickHandler: ((e: MouseEvent) => void) | null = null;\n\n\tconstructor(config?: Partial<ListConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.context = context;\n\t\tthis.locale = await resolveLocale(context, this.config.locale, LIST_LOCALE_EN, loadListLocale);\n\t\tcontext.registerStyleSheet(LIST_CSS);\n\t\tthis.registerNodeSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymaps(context);\n\t\tthis.registerInputRules(context);\n\t\tthis.registerToolbarItems(context);\n\t\tthis.registerCheckboxClickHandler(context);\n\t}\n\n\tdestroy(): void {\n\t\tif (this.checkboxClickHandler && this.context) {\n\t\t\tconst container: HTMLElement = this.context.getContainer();\n\t\t\tcontainer.removeEventListener('mousedown', this.checkboxClickHandler);\n\t\t}\n\t\tthis.checkboxClickHandler = null;\n\t\tthis.context = null;\n\t}\n\n\tprivate registerNodeSpec(context: PluginContext): void {\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'list_item',\n\t\t\tgroup: 'block',\n\t\t\tcontent: { allow: ['text'] },\n\t\t\tattrs: {\n\t\t\t\tlistType: { default: 'bullet' },\n\t\t\t\tindent: { default: 0 },\n\t\t\t\tchecked: { default: false },\n\t\t\t},\n\t\t\ttoDOM(node) {\n\t\t\t\tconst listType = node.attrs?.listType ?? 'bullet';\n\t\t\t\tconst indent = node.attrs?.indent ?? 0;\n\t\t\t\tconst checked = node.attrs?.checked ?? false;\n\n\t\t\t\tconst li = createBlockElement('li', node.id);\n\t\t\t\tli.setAttribute('role', 'listitem');\n\t\t\t\tli.setAttribute('data-list-type', listType);\n\t\t\t\tli.setAttribute('data-indent', String(indent));\n\t\t\t\tli.className = `notectl-list-item notectl-list-item--${listType}`;\n\n\t\t\t\tif (indent > 0) {\n\t\t\t\t\tsetStyleProperty(li, 'marginLeft', `${indent * LIST_MARKER_WIDTH}px`);\n\t\t\t\t}\n\n\t\t\t\tif (listType === 'checklist') {\n\t\t\t\t\tli.setAttribute('data-checked', String(checked));\n\t\t\t\t\tli.setAttribute('aria-checked', String(checked));\n\t\t\t\t}\n\t\t\t\tli.setAttribute('aria-level', String(indent + 1));\n\n\t\t\t\treturn li;\n\t\t\t},\n\t\t\twrapper(node) {\n\t\t\t\tconst listType = node.attrs?.listType ?? 'bullet';\n\t\t\t\tconst tag = listType === 'ordered' ? 'ol' : 'ul';\n\t\t\t\treturn {\n\t\t\t\t\ttag,\n\t\t\t\t\tkey: `list-${listType}`,\n\t\t\t\t\tclassName: `notectl-list notectl-list--${listType}`,\n\t\t\t\t\tattrs: { role: 'list' },\n\t\t\t\t};\n\t\t\t},\n\t\t\ttoHTML(node, content) {\n\t\t\t\tconst listType: string = (node.attrs?.listType as string) ?? 'bullet';\n\t\t\t\tconst checked: boolean = (node.attrs?.checked as boolean) ?? false;\n\n\t\t\t\tif (listType === 'checklist') {\n\t\t\t\t\tconst checkedAttr: string = checked ? ' checked' : '';\n\t\t\t\t\tconst ariaChecked: string = String(checked);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t`<li role=\"checkbox\" aria-checked=\"${ariaChecked}\">` +\n\t\t\t\t\t\t`<input type=\"checkbox\" disabled${checkedAttr}>` +\n\t\t\t\t\t\t`${content || '<br>'}</li>`\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn `<li>${content || '<br>'}</li>`;\n\t\t\t},\n\t\t\tparseHTML: [{ tag: 'li' }],\n\t\t\tsanitize: {\n\t\t\t\ttags: ['ul', 'ol', 'li', 'input'],\n\t\t\t\tattrs: ['type', 'disabled', 'checked', 'role', 'aria-checked'],\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tconst enabledTypes = this.getEnabledTypes();\n\n\t\tfor (const def of enabledTypes) {\n\t\t\tcontext.registerCommand(`toggleList:${def.type}`, () => {\n\t\t\t\treturn this.toggleList(context, def.type);\n\t\t\t});\n\t\t}\n\n\t\tcontext.registerCommand('indentListItem', () => {\n\t\t\treturn this.indent(context);\n\t\t});\n\n\t\tcontext.registerCommand('outdentListItem', () => {\n\t\t\treturn this.outdent(context);\n\t\t});\n\n\t\tif (this.config.types.includes('checklist')) {\n\t\t\tcontext.registerCommand('toggleChecklistItem', () => this.toggleChecked(context), {\n\t\t\t\treadonlyAllowed: true,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate registerKeymaps(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\tEnter: () => this.handleEnter(context),\n\t\t\tBackspace: () => this.handleBackspace(context),\n\t\t\tTab: () => this.indent(context),\n\t\t\t'Shift-Tab': () => this.outdent(context),\n\t\t});\n\t}\n\n\tprivate registerInputRules(context: PluginContext): void {\n\t\tconst enabledTypes = this.getEnabledTypes();\n\n\t\tfor (const def of enabledTypes) {\n\t\t\tcontext.registerInputRule({\n\t\t\t\tpattern: def.inputPattern,\n\t\t\t\thandler: (state, match, start, _end) => {\n\t\t\t\t\tconst sel = state.selection;\n\t\t\t\t\tif (!isTextSelection(sel)) return null;\n\t\t\t\t\tif (!isCollapsed(sel)) return null;\n\n\t\t\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\t\t\tif (!block || block.type !== 'paragraph') return null;\n\n\t\t\t\t\tconst matchStr = match[0] ?? '';\n\t\t\t\t\tconst matchLen = matchStr.length;\n\t\t\t\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\t\t\t\tlistType: def.type,\n\t\t\t\t\t\tindent: 0,\n\t\t\t\t\t};\n\t\t\t\t\tif (def.type === 'checklist') {\n\t\t\t\t\t\tattrs.checked = matchStr.includes('[x]');\n\t\t\t\t\t}\n\n\t\t\t\t\treturn state\n\t\t\t\t\t\t.transaction('input')\n\t\t\t\t\t\t.deleteTextAt(sel.anchor.blockId, start, start + matchLen)\n\t\t\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('list_item'), attrs)\n\t\t\t\t\t\t.setSelection(createCollapsedSelection(sel.anchor.blockId, 0))\n\t\t\t\t\t\t.build();\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate getListLabel(type: ListType): string {\n\t\tconst labels: Record<ListType, string> = {\n\t\t\tbullet: this.locale.bulletList,\n\t\t\tordered: this.locale.numberedList,\n\t\t\tchecklist: this.locale.checklist,\n\t\t};\n\t\treturn labels[type];\n\t}\n\n\tprivate registerToolbarItems(context: PluginContext): void {\n\t\tconst enabledTypes = this.getEnabledTypes();\n\n\t\tfor (const def of enabledTypes) {\n\t\t\tcontext.registerToolbarItem({\n\t\t\t\tid: `list-${def.type}`,\n\t\t\t\tgroup: 'block',\n\t\t\t\ticon: def.icon,\n\t\t\t\tlabel: this.getListLabel(def.type),\n\t\t\t\tcommand: `toggleList:${def.type}`,\n\t\t\t\tisActive: (state) => this.isListActive(state, def.type),\n\t\t\t});\n\t\t}\n\t}\n\n\t// --- Command Implementations ---\n\n\tprivate toggleList(context: PluginContext, listType: ListType): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return false;\n\n\t\t// If already this list type, convert back to paragraph\n\t\tif (block.type === 'list_item' && block.attrs?.listType === listType) {\n\t\t\tconst tr = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('paragraph'))\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Convert to list item\n\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\tlistType,\n\t\t\tindent: isNodeOfType(block, 'list_item') ? block.attrs.indent : 0,\n\t\t};\n\t\tif (listType === 'checklist') {\n\t\t\tattrs.checked = false;\n\t\t}\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setBlockType(sel.anchor.blockId, nodeType('list_item'), attrs)\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate indent(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tif (!isTextSelection(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\tif (!block || !isNodeOfType(block, 'list_item')) return false;\n\n\t\tif (block.attrs.indent >= this.config.maxIndent) return false;\n\n\t\treturn this.setIndent(context, state, block.attrs.indent + 1);\n\t}\n\n\tprivate outdent(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tif (!isTextSelection(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\tif (!block || !isNodeOfType(block, 'list_item')) return false;\n\n\t\tif (block.attrs.indent <= 0) return false;\n\n\t\treturn this.setIndent(context, state, block.attrs.indent - 1);\n\t}\n\n\tprivate setIndent(context: PluginContext, state: EditorState, indent: number): boolean {\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return false;\n\n\t\tconst attrs = { ...block.attrs, indent } as Record<string, string | number | boolean>;\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setBlockType(sel.anchor.blockId, nodeType('list_item'), attrs)\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate toggleChecked(context: PluginContext, targetId?: BlockId): boolean {\n\t\tif (context.isReadOnly() && !this.config.interactiveCheckboxes) return false;\n\n\t\tconst state = context.getState();\n\t\tconst bid: BlockId | null =\n\t\t\ttargetId ?? (!isTextSelection(state.selection) ? null : state.selection.anchor.blockId);\n\t\tif (!bid) return false;\n\n\t\tconst block = state.getBlock(bid);\n\t\tif (!block || block.type !== 'list_item' || block.attrs?.listType !== 'checklist') {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst checked: boolean = !block.attrs?.checked;\n\t\tconst attrs = { ...block.attrs, checked } as Record<string, string | number | boolean>;\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setBlockType(bid, nodeType('list_item'), attrs)\n\t\t\t.setSelection(state.selection)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Handles Backspace at the start of a list item.\n\t * Converts the list item back to a paragraph, preserving text.\n\t */\n\tprivate handleBackspace(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'list_item') return false;\n\t\tif (sel.anchor.offset !== 0) return false;\n\n\t\tconst tr = state\n\t\t\t.transaction('input')\n\t\t\t.setBlockType(sel.anchor.blockId, nodeType('paragraph'))\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Handles Enter inside a list item.\n\t * Empty item → exit list (convert to paragraph).\n\t * Non-empty item → split and create a new list item with the same type.\n\t */\n\tprivate handleEnter(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'list_item') return false;\n\n\t\tconst text = getBlockText(block);\n\n\t\tif (text === '') {\n\t\t\t// Empty list item → convert to paragraph (exit list)\n\t\t\tconst tr = state\n\t\t\t\t.transaction('input')\n\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('paragraph'))\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Non-empty → split block and set new block to same list type\n\t\tconst newBlockId = generateBlockId();\n\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\tlistType: isNodeOfType(block, 'list_item') ? block.attrs.listType : 'bullet',\n\t\t\tindent: isNodeOfType(block, 'list_item') ? block.attrs.indent : 0,\n\t\t};\n\t\tif (attrs.listType === 'checklist') {\n\t\t\tattrs.checked = false;\n\t\t}\n\n\t\tconst tr = state\n\t\t\t.transaction('input')\n\t\t\t.splitBlock(sel.anchor.blockId, sel.anchor.offset, newBlockId)\n\t\t\t.setBlockType(newBlockId, nodeType('list_item'), attrs)\n\t\t\t.setSelection(createCollapsedSelection(newBlockId, 0))\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t// --- Checkbox Click Handling ---\n\n\tprivate registerCheckboxClickHandler(context: PluginContext): void {\n\t\tif (!this.config.types.includes('checklist')) return;\n\n\t\tthis.checkboxClickHandler = (e: MouseEvent) => {\n\t\t\tif (context.isReadOnly() && !this.config.interactiveCheckboxes) return;\n\n\t\t\tconst target: EventTarget | null = e.target;\n\t\t\tif (!(target instanceof HTMLElement)) return;\n\n\t\t\tconst li: HTMLElement | null = target.closest('.notectl-list-item--checklist');\n\t\t\tif (!li) return;\n\n\t\t\tconst rect: DOMRect = li.getBoundingClientRect();\n\t\t\tconst isRtl: boolean = getComputedStyle(li).direction === 'rtl';\n\t\t\tconst markerDistance: number = isRtl ? rect.right - e.clientX : e.clientX - rect.left;\n\t\t\tif (markerDistance >= LIST_MARKER_WIDTH) return;\n\n\t\t\te.preventDefault();\n\n\t\t\tconst bid: string | null = li.getAttribute('data-block-id');\n\t\t\tif (!bid) return;\n\n\t\t\tthis.toggleChecked(context, blockId(bid));\n\t\t};\n\n\t\tconst container: HTMLElement = context.getContainer();\n\t\tcontainer.addEventListener('mousedown', this.checkboxClickHandler);\n\t}\n\n\t// --- Helpers ---\n\n\tprivate isListActive(state: EditorState, listType: ListType): boolean {\n\t\tif (!isTextSelection(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\treturn block?.type === 'list_item' && block.attrs?.listType === listType;\n\t}\n\n\tprivate getEnabledTypes(): readonly ListTypeDefinition[] {\n\t\treturn LIST_TYPE_DEFINITIONS.filter((def) => this.config.types.includes(def.type));\n\t}\n}\n"],"names":["LIST_LOCALE_EN","bulletList","numberedList","checklist","localeModules","assign","import","async","loadListLocale","lang","loader","default","DEFAULT_CONFIG","types","maxIndent","LIST_TYPE_DEFINITIONS","type","icon","inputPattern","inputPrefix","ListPlugin","id","name","priority","config","locale","context","checkboxClickHandler","constructor","this","init","resolveLocale","registerStyleSheet","registerNodeSpec","registerCommands","registerKeymaps","registerInputRules","registerToolbarItems","registerCheckboxClickHandler","destroy","getContainer","removeEventListener","group","content","allow","attrs","listType","indent","checked","toDOM","node","li","createBlockElement","setAttribute","String","className","setStyleProperty","wrapper","tag","key","role","toHTML","checkedAttr","parseHTML","sanitize","tags","enabledTypes","getEnabledTypes","def","registerCommand","toggleList","outdent","includes","toggleChecked","readonlyAllowed","registerKeymap","Enter","handleEnter","Backspace","handleBackspace","Tab","registerInputRule","pattern","handler","state","match","start","_end","sel","selection","isTextSelection","isCollapsed","block","getBlock","anchor","blockId","matchStr","matchLen","length","transaction","deleteTextAt","setBlockType","nodeType","setSelection","createCollapsedSelection","build","getListLabel","bullet","ordered","registerToolbarItem","label","command","isActive","isListActive","getState","tr","dispatch","isNodeOfType","setIndent","targetId","isReadOnly","interactiveCheckboxes","bid","offset","getBlockText","newBlockId","generateBlockId","splitBlock","e","target","HTMLElement","closest","rect","getBoundingClientRect","getComputedStyle","direction","right","clientX","left","preventDefault","getAttribute","addEventListener","filter"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"print.mjs","sources":["../../src/plugins/print/PrintLocale.ts","../../src/plugins/print/PrintContentPreparer.ts","../../src/plugins/print/PrintPlugin.ts","../../src/plugins/print/PrintServiceImpl.ts","../../src/plugins/print/PrintStyleCollector.ts"],"sourcesContent":["/** Locale interface and default English locale for the PrintPlugin. */\n\n// --- Locale Interface ---\n\nexport interface PrintLocale {\n\treadonly label: string;\n\treadonly tooltip: (shortcut: string) => string;\n\treadonly printingAnnouncement: string;\n}\n\n// --- Default English Locale ---\n\nexport const PRINT_LOCALE_EN: PrintLocale = {\n\tlabel: 'Print',\n\ttooltip: (shortcut: string) => `Print (${shortcut})`,\n\tprintingAnnouncement: 'Printing',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: Record<string, () => Promise<{ default: PrintLocale }>> = import.meta.glob<{\n\tdefault: PrintLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadPrintLocale(lang: string): Promise<PrintLocale> {\n\tif (lang === 'en') return PRINT_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return PRINT_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn PRINT_LOCALE_EN;\n\t}\n}\n","/**\n * Prepares editor content for print output.\n * Clones the DOM, sanitizes interactive attributes, applies block filters,\n * and inserts header/footer elements.\n */\n\nimport { setStyleProperties } from '../../style/StyleRuntime.js';\nimport type { PrintOptions } from './PrintTypes.js';\n\n/** Deep-clones the .notectl-content element from the editor container. */\nexport function cloneContent(container: HTMLElement): HTMLElement {\n\tconst content: HTMLElement | null = container.querySelector('.notectl-content');\n\tconst source: HTMLElement = content ?? container;\n\treturn source.cloneNode(true) as HTMLElement;\n}\n\n/** Sanitizes the cloned content for print: removes interactive attributes and selection styling. */\nexport function sanitize(clone: HTMLElement): void {\n\t// Remove contenteditable from the root\n\tclone.removeAttribute('contenteditable');\n\n\t// Remove selection-related CSS classes\n\tconst selectionClasses: readonly string[] = ['notectl-node-selected', 'notectl-content--empty'];\n\tfor (const cls of selectionClasses) {\n\t\tclone.classList.remove(cls);\n\t\tfor (const el of clone.querySelectorAll(`.${cls}`)) {\n\t\t\tel.classList.remove(cls);\n\t\t}\n\t}\n\n\t// Remove data-placeholder to avoid showing placeholder in print\n\tclone.removeAttribute('data-placeholder');\n}\n\n/** Removes excluded block types and applies page-break-before to configured block types. */\nexport function applyBlockFilters(clone: HTMLElement, options: PrintOptions): void {\n\tif (options.excludeBlockTypes) {\n\t\tfor (const type of options.excludeBlockTypes) {\n\t\t\tconst elements: NodeListOf<Element> = clone.querySelectorAll(`[data-block-type=\"${type}\"]`);\n\t\t\tfor (const el of elements) {\n\t\t\t\tel.remove();\n\t\t\t}\n\t\t}\n\t}\n\n\tif (options.pageBreakBefore) {\n\t\tfor (const type of options.pageBreakBefore) {\n\t\t\tconst elements: NodeListOf<Element> = clone.querySelectorAll(`[data-block-type=\"${type}\"]`);\n\t\t\tfor (const el of elements) {\n\t\t\t\tsetStyleProperties(el as HTMLElement, {\n\t\t\t\t\tbreakBefore: 'page',\n\t\t\t\t\tpageBreakBefore: 'always',\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** Resolves a header/footer value to an HTML string. */\nfunction resolveContent(value: string | (() => string)): string {\n\treturn typeof value === 'function' ? value() : value;\n}\n\n/** Inserts header and footer elements into the cloned content. */\nexport function insertHeaderFooter(clone: HTMLElement, options: PrintOptions): void {\n\tif (options.header) {\n\t\tconst headerEl: HTMLDivElement = document.createElement('div');\n\t\theaderEl.className = 'notectl-print-header';\n\t\theaderEl.innerHTML = resolveContent(options.header);\n\t\tclone.insertBefore(headerEl, clone.firstChild);\n\t}\n\n\tif (options.footer) {\n\t\tconst footerEl: HTMLDivElement = document.createElement('div');\n\t\tfooterEl.className = 'notectl-print-footer';\n\t\tfooterEl.innerHTML = resolveContent(options.footer);\n\t\tclone.appendChild(footerEl);\n\t}\n}\n\n/** Orchestrates all content preparation steps. Returns a ready-to-print DOM element. */\nexport function prepare(container: HTMLElement, options: PrintOptions): HTMLElement {\n\tconst clone: HTMLElement = cloneContent(container);\n\tsanitize(clone);\n\tapplyBlockFilters(clone, options);\n\tinsertHeaderFooter(clone, options);\n\treturn clone;\n}\n","/**\n * PrintPlugin: provides print functionality for the notectl editor.\n * Registers a command, keymap, toolbar item, and exposes a PrintService.\n * Orchestrator only — delegates all logic to PrintServiceImpl, PrintStyleCollector,\n * and PrintContentPreparer.\n */\n\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { PRINT_LOCALE_EN, type PrintLocale, loadPrintLocale } from './PrintLocale.js';\nimport { createPrintService } from './PrintServiceImpl.js';\nimport type { PrintOptions, PrintPluginConfig, PrintService } from './PrintTypes.js';\nimport { PRINT_SERVICE_KEY } from './PrintTypes.js';\n\nconst PRINT_ICON: string =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\">' +\n\t'<path d=\"M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3' +\n\t' 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z\"/>' +\n\t'</svg>';\n\n/** No-op fallback service for environments without ShadowRoot. */\nconst NOOP_SERVICE: PrintService = {\n\tprint(): void {},\n\ttoHTML(): string {\n\t\treturn '';\n\t},\n};\n\nexport class PrintPlugin implements Plugin {\n\treadonly id = 'print';\n\treadonly name = 'Print';\n\n\tprivate readonly config: PrintPluginConfig;\n\tprivate service: PrintService | null = null;\n\tprivate locale!: PrintLocale;\n\n\tconstructor(config?: PrintPluginConfig) {\n\t\tthis.config = config ?? {};\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tPRINT_LOCALE_EN,\n\t\t\tloadPrintLocale,\n\t\t);\n\t\tconst container: HTMLElement = context.getContainer();\n\t\tconst rootNode: Node = container.getRootNode();\n\n\t\tif (rootNode instanceof ShadowRoot) {\n\t\t\tconst host: HTMLElement = rootNode.host as HTMLElement;\n\t\t\tconst eventBus = context.getEventBus();\n\t\t\tthis.service = createPrintService(rootNode, host, container, eventBus);\n\t\t} else {\n\t\t\tthis.service = NOOP_SERVICE;\n\t\t}\n\n\t\tcontext.registerService(PRINT_SERVICE_KEY, this.service);\n\n\t\tconst defaults: PrintOptions = this.config.defaults ?? {};\n\t\tconst service: PrintService = this.service;\n\n\t\tconst printLocale = this.locale;\n\t\tcontext.registerCommand('print', () => {\n\t\t\tcontext.announce(printLocale.printingAnnouncement);\n\t\t\tservice.print(defaults);\n\t\t\treturn true;\n\t\t});\n\n\t\tconst keyBinding: string = this.config.keyBinding ?? 'Mod-P';\n\t\tcontext.registerKeymap({\n\t\t\t[keyBinding]: () => {\n\t\t\t\tcontext.executeCommand('print');\n\t\t\t\treturn true;\n\t\t\t},\n\t\t});\n\n\t\tif (this.config.showToolbarItem !== false) {\n\t\t\tconst shortcut: string = formatShortcut(keyBinding);\n\t\t\tcontext.registerToolbarItem({\n\t\t\t\tid: 'print',\n\t\t\t\tgroup: 'actions',\n\t\t\t\tlabel: this.locale.label,\n\t\t\t\ttooltip: this.locale.tooltip(shortcut),\n\t\t\t\ticon: PRINT_ICON,\n\t\t\t\tcommand: 'print',\n\t\t\t});\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\tthis.service = null;\n\t}\n}\n","/**\n * PrintService implementation.\n * Handles the synchronous print flow: event emission, style collection,\n * content preparation, iframe creation, and cleanup.\n */\n\nimport { setStyleText } from '../../style/StyleRuntime.js';\nimport type { PluginEventBus } from '../Plugin.js';\nimport { prepare } from './PrintContentPreparer.js';\nimport { collectAll } from './PrintStyleCollector.js';\nimport {\n\tAFTER_PRINT,\n\ttype AfterPrintEvent,\n\tBEFORE_PRINT,\n\ttype BeforePrintEvent,\n\ttype PrintOptions,\n\ttype PrintService,\n} from './PrintTypes.js';\n\n/** Escapes HTML special characters in a plain-text string. */\nfunction escapeHTML(text: string): string {\n\treturn text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n}\n\n/** Builds a complete HTML document string from CSS, body content, and title. */\nexport function buildHTMLDocument(\n\tcss: string,\n\tcontent: string,\n\ttitle: string,\n\tlang = 'en',\n): string {\n\tconst safeTitle: string = escapeHTML(title);\n\treturn [\n\t\t'<!DOCTYPE html>',\n\t\t`<html lang=\"${lang}\">`,\n\t\t'<head>',\n\t\t`<meta charset=\"utf-8\">`,\n\t\t`<title>${safeTitle}</title>`,\n\t\t`<style>${css}</style>`,\n\t\t'</head>',\n\t\t`<body>${content}</body>`,\n\t\t'</html>',\n\t].join('\\n');\n}\n\n/** Creates and returns the PrintService implementation. */\nexport function createPrintService(\n\tshadowRoot: ShadowRoot,\n\thost: HTMLElement,\n\tcontainer: HTMLElement,\n\teventBus: PluginEventBus,\n): PrintService {\n\tfunction mergeOptions(options?: PrintOptions): PrintOptions {\n\t\treturn options ?? {};\n\t}\n\n\tfunction executePrint(options: PrintOptions): string | null {\n\t\t// 1. Emit BEFORE_PRINT — listeners can mutate options or cancel\n\t\tconst beforeEvent: BeforePrintEvent = {\n\t\t\toptions,\n\t\t\tcancelled: false,\n\t\t};\n\t\teventBus.emit(BEFORE_PRINT, beforeEvent);\n\n\t\tif (beforeEvent.cancelled) return null;\n\n\t\tconst finalOptions: PrintOptions = beforeEvent.options;\n\n\t\t// 2. Collect styles\n\t\tconst css: string = collectAll(shadowRoot, host, finalOptions);\n\n\t\t// 3. Prepare content\n\t\tconst clone: HTMLElement = prepare(container, finalOptions);\n\t\tconst contentHTML: string = clone.outerHTML;\n\n\t\t// 4. Build HTML document\n\t\tconst title: string = finalOptions.title ?? '';\n\t\tconst lang: string =\n\t\t\thost.closest('[lang]')?.getAttribute('lang') ?? (document.documentElement.lang || 'en');\n\t\tconst html: string = buildHTMLDocument(css, contentHTML, title, lang);\n\n\t\t// 5. Emit AFTER_PRINT\n\t\tconst afterEvent: AfterPrintEvent = { html };\n\t\teventBus.emit(AFTER_PRINT, afterEvent);\n\n\t\treturn html;\n\t}\n\n\treturn {\n\t\tprint(options?: PrintOptions): void {\n\t\t\tconst resolved: PrintOptions = mergeOptions(options);\n\t\t\tconst html: string | null = executePrint(resolved);\n\t\t\tif (!html) return;\n\n\t\t\t// Create hidden iframe\n\t\t\tconst iframe: HTMLIFrameElement = document.createElement('iframe');\n\t\t\tsetStyleText(iframe, 'position:fixed;left:-9999px;width:0;height:0;border:none');\n\t\t\tdocument.body.appendChild(iframe);\n\n\t\t\tconst iframeDoc: Document | null = iframe.contentDocument;\n\t\t\tif (!iframeDoc) {\n\t\t\t\tdocument.body.removeChild(iframe);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tiframeDoc.open();\n\t\t\tiframeDoc.write(html);\n\t\t\tiframeDoc.close();\n\n\t\t\tconst cleanup = (): void => {\n\t\t\t\tiframe.remove();\n\t\t\t};\n\n\t\t\t// Defer cleanup until print dialog closes\n\t\t\tif (iframe.contentWindow) {\n\t\t\t\tiframe.contentWindow.addEventListener('afterprint', cleanup, { once: true });\n\t\t\t\tiframe.contentWindow.print();\n\t\t\t} else {\n\t\t\t\tcleanup();\n\t\t\t}\n\t\t},\n\n\t\ttoHTML(options?: PrintOptions): string {\n\t\t\tconst resolved: PrintOptions = mergeOptions(options);\n\t\t\treturn executePrint(resolved) ?? '';\n\t\t},\n\t};\n}\n","/**\n * Collects and aggregates CSS for print output.\n * Extracts adopted stylesheets, snapshots theme tokens, and generates print-specific CSS.\n */\n\nimport {\n\tPAPER_MARGIN_HORIZONTAL_PX,\n\tPAPER_MARGIN_TOP_PX,\n\tgetPaperCSSSize,\n} from '../../model/PaperSize.js';\nimport type { PrintOptions } from './PrintTypes.js';\n\n/** Extracts CSS text from all adopted stylesheets on a ShadowRoot. */\nexport function extractAdoptedStyles(shadowRoot: ShadowRoot): string {\n\tconst parts: string[] = [];\n\tfor (const sheet of shadowRoot.adoptedStyleSheets) {\n\t\tfor (const rule of sheet.cssRules) {\n\t\t\tparts.push(rule.cssText);\n\t\t}\n\t}\n\treturn parts.join('\\n');\n}\n\n/** Snapshots --notectl-* CSS custom properties from the host element into a :root block. */\nexport function snapshotThemeTokens(host: HTMLElement): string {\n\tconst computed: CSSStyleDeclaration = getComputedStyle(host);\n\tconst tokens: string[] = [];\n\n\tfor (let i = 0; i < computed.length; i++) {\n\t\tconst prop: string = computed[i] ?? '';\n\t\tif (prop.startsWith('--notectl-')) {\n\t\t\tconst value: string = computed.getPropertyValue(prop).trim();\n\t\t\tif (value) {\n\t\t\t\ttokens.push(` ${prop}: ${value};`);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (tokens.length === 0) return '';\n\treturn `:root {\\n${tokens.join('\\n')}\\n}`;\n}\n\n/**\n * Snapshots computed typography from the host element into a `body` rule.\n * In the editor, typography is inherited from `:host` (shadow DOM).\n * The print iframe is a regular document where `:host` doesn't match,\n * so we must apply the same font/line-height explicitly.\n */\nexport function snapshotTypography(host: HTMLElement): string {\n\tconst computed: CSSStyleDeclaration = getComputedStyle(host);\n\tconst props: string[] = [\n\t\t'font-family',\n\t\t'font-size',\n\t\t'font-weight',\n\t\t'line-height',\n\t\t'letter-spacing',\n\t\t'word-spacing',\n\t\t'color',\n\t];\n\tconst rules: string[] = [' margin: 0;'];\n\tfor (const prop of props) {\n\t\tconst value: string = computed.getPropertyValue(prop).trim();\n\t\tif (value) {\n\t\t\trules.push(` ${prop}: ${value};`);\n\t\t}\n\t}\n\treturn `body {\\n${rules.join('\\n')}\\n}`;\n}\n\n/** Generates print-specific CSS rules based on PrintOptions. */\nexport function generatePrintCSS(options: PrintOptions): string {\n\tconst parts: string[] = [];\n\n\t// @page rule\n\tconst pageProps: string[] = [];\n\tif (options.margin) {\n\t\tpageProps.push(` margin: ${options.margin};`);\n\t} else if (options.paperSize) {\n\t\t// WYSIWYG: zero @page margin so body = full paper width;\n\t\t// document margins are applied as content padding below.\n\t\tpageProps.push(' margin: 0;');\n\t}\n\tif (options.paperSize || options.orientation) {\n\t\tconst sizeKeyword: string = options.paperSize ? getPaperCSSSize(options.paperSize) : 'A4';\n\t\tconst sizeParts: string[] = [sizeKeyword];\n\t\tif (options.orientation) {\n\t\t\tsizeParts.push(options.orientation);\n\t\t}\n\t\tpageProps.push(` size: ${sizeParts.join(' ')};`);\n\t}\n\tif (pageProps.length > 0) {\n\t\tparts.push(`@page {\\n${pageProps.join('\\n')}\\n}`);\n\t}\n\n\t// WYSIWYG: apply paper-mode document margins to print content\n\tif (options.paperSize) {\n\t\tparts.push(\n\t\t\t`.notectl-content { padding: ${PAPER_MARGIN_TOP_PX}px ${PAPER_MARGIN_HORIZONTAL_PX}px !important; }`,\n\t\t);\n\t}\n\n\t// Print media rules\n\tconst printRules: string[] = [];\n\n\t// Hide non-printable elements\n\tprintRules.push('[data-notectl-no-print] { display: none !important; }');\n\n\t// Code blocks: preserve background, force wrapping\n\tprintRules.push(\n\t\t'.notectl-code-block { white-space: pre-wrap !important; ' +\n\t\t\t'word-break: break-all !important; page-break-inside: avoid; }',\n\t);\n\n\t// Images: avoid page breaks\n\tprintRules.push('img { page-break-inside: avoid; }');\n\n\t// Tables: avoid page breaks\n\tprintRules.push('.notectl-table { break-inside: avoid; }');\n\n\t// Preserve background colors and images in print output (WYSIWYG default).\n\t// Only omitted when the consumer explicitly opts out via printBackground: false.\n\tif (options.printBackground !== false) {\n\t\tprintRules.push(\n\t\t\t'* { -webkit-print-color-adjust: exact !important; ' +\n\t\t\t\t'print-color-adjust: exact !important; }',\n\t\t);\n\t}\n\n\tparts.push(`@media print {\\n ${printRules.join('\\n ')}\\n}`);\n\n\treturn parts.join('\\n\\n');\n}\n\n/** Collects all CSS needed for print: adopted styles, theme tokens, print CSS, and custom CSS. */\nexport function collectAll(\n\tshadowRoot: ShadowRoot,\n\thost: HTMLElement,\n\toptions: PrintOptions,\n): string {\n\tconst parts: string[] = [];\n\n\tconst adopted: string = extractAdoptedStyles(shadowRoot);\n\tif (adopted) parts.push(adopted);\n\n\tconst theme: string = snapshotThemeTokens(host);\n\tif (theme) parts.push(theme);\n\n\t// WYSIWYG: snapshot host typography so the print iframe matches the editor.\n\t// In the editor, .notectl-content inherits font from :host (shadow DOM).\n\t// The print iframe is a regular document where :host doesn't apply.\n\tparts.push(snapshotTypography(host));\n\n\tconst printCSS: string = generatePrintCSS(options);\n\tif (printCSS) parts.push(printCSS);\n\n\tif (options.customCSS) {\n\t\tparts.push(options.customCSS);\n\t}\n\n\treturn parts.join('\\n\\n');\n}\n"],"names":["PRINT_LOCALE_EN","label","tooltip","shortcut","printingAnnouncement","localeModules","assign","import","async","loadPrintLocale","lang","loader","default","resolveContent","value","NOOP_SERVICE","print","toHTML","PrintPlugin","id","name","config","service","locale","constructor","this","init","context","resolveLocale","container","getContainer","rootNode","getRootNode","ShadowRoot","host","eventBus","getEventBus","shadowRoot","mergeOptions","options","executePrint","beforeEvent","cancelled","emit","BEFORE_PRINT","finalOptions","html","css","content","title","replace","join","buildHTMLDocument","parts","adopted","sheet","adoptedStyleSheets","rule","cssRules","push","cssText","extractAdoptedStyles","theme","computed","getComputedStyle","tokens","i","length","prop","startsWith","getPropertyValue","trim","snapshotThemeTokens","props","rules","snapshotTypography","printCSS","pageProps","margin","paperSize","orientation","sizeParts","getPaperCSSSize","PAPER_MARGIN_TOP_PX","PAPER_MARGIN_HORIZONTAL_PX","printRules","printBackground","generatePrintCSS","customCSS","collectAll","clone","querySelector","cloneNode","cloneContent","removeAttribute","selectionClasses","cls","classList","remove","el","querySelectorAll","sanitize","excludeBlockTypes","type","elements","pageBreakBefore","setStyleProperties","breakBefore","applyBlockFilters","header","headerEl","document","createElement","className","innerHTML","insertBefore","firstChild","footer","footerEl","appendChild","insertHeaderFooter","prepare","outerHTML","closest","getAttribute","documentElement","afterEvent","AFTER_PRINT","iframe","setStyleText","body","iframeDoc","contentDocument","removeChild","open","write","close","cleanup","contentWindow","addEventListener","once","createPrintService","registerService","PRINT_SERVICE_KEY","defaults","printLocale","registerCommand","announce","keyBinding","registerKeymap","executeCommand","showToolbarItem","formatShortcut","registerToolbarItem","group","icon","command","destroy"],"mappings":"+QAYO,MAAMA,EAA+B,CAC3CC,MAAO,QACPC,QAAUC,GAAqB,UAAUA,KACzCC,qBAAsB,YAKjBC,wBAAyEC,OAAA,CAAA,kBAAA,IAAAC,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,+BAI/EC,eAAsBC,EAAgBC,GACrC,GAAa,OAATA,EAAe,OAAOV,EAC1B,MAAMW,EAASN,EAAc,aAAaK,QAC1C,IAAKC,EAAQ,OAAOX,EACpB,IAEC,aADkBW,KACPC,OACZ,CAAA,MACC,OAAOZ,CACR,CACD,CCyBA,SAASa,EAAeC,GACvB,MAAwB,mBAAVA,EAAuBA,IAAUA,CAChD,CC9CA,MAOMC,EAA6B,CAClC,KAAAC,GAAe,EACfC,OAAA,IACQ,IAIF,MAAMC,EACHC,GAAK,QACLC,KAAO,QAECC,OACTC,QAA+B,KAC/BC,OAER,WAAAC,CAAYH,GACXI,KAAKJ,OAASA,GAAU,CAAA,CACzB,CAEA,UAAMK,CAAKC,GACVF,KAAKF,aAAeK,EACnBD,EACAF,KAAKJ,OAAOE,OACZvB,EACAS,GAED,MAAMoB,EAAyBF,EAAQG,eACjCC,EAAiBF,EAAUG,cAEjC,GAAID,aAAoBE,WAAY,CACnC,MAAMC,EAAoBH,EAASG,KAC7BC,EAAWR,EAAQS,cACzBX,KAAKH,QCRD,SACNe,EACAH,EACAL,EACAM,GAEA,SAASG,EAAaC,GACrB,OAAOA,GAAW,CAAA,CACnB,CAEA,SAASC,EAAaD,GAErB,MAAME,EAAgC,CACrCF,UACAG,WAAW,GAIZ,GAFAP,EAASQ,KAAKC,EAAcH,GAExBA,EAAYC,UAAW,OAAO,KAElC,MAAMG,EAA6BJ,EAAYF,QAazCO,EAtDD,SACNC,EACAC,EACAC,EACAvC,EAAO,MAGP,MAAO,CACN,kBACA,eAAeA,MACf,SACA,yBACA,UANoCuC,EAVzBC,QAAQ,KAAM,SAASA,QAAQ,KAAM,QAAQA,QAAQ,KAAM,kBAiBtE,UAAUH,YACV,UACA,SAASC,WACT,WACCG,KAAK,KACR,CAoCuBC,CCuDhB,SACNf,EACAH,EACAK,GAEA,MAAMc,EAAkB,GAElBC,EAhIA,SAA8BjB,GACpC,MAAMgB,EAAkB,GACxB,IAAA,MAAWE,KAASlB,EAAWmB,mBAC9B,IAAA,MAAWC,KAAQF,EAAMG,SACxBL,EAAMM,KAAKF,EAAKG,SAGlB,OAAOP,EAAMF,KAAK,KACnB,CAwHyBU,CAAqBxB,GACzCiB,GAASD,EAAMM,KAAKL,GAExB,MAAMQ,EAxHA,SAA6B5B,GACnC,MAAM6B,EAAgCC,iBAAiB9B,GACjD+B,EAAmB,GAEzB,IAAA,IAASC,EAAI,EAAGA,EAAIH,EAASI,OAAQD,IAAK,CACzC,MAAME,EAAeL,EAASG,IAAM,GACpC,GAAIE,EAAKC,WAAW,cAAe,CAClC,MAAMvD,EAAgBiD,EAASO,iBAAiBF,GAAMG,OAClDzD,GACHmD,EAAON,KAAK,KAAKS,MAAStD,KAE5B,CACD,CAEA,OAAsB,IAAlBmD,EAAOE,OAAqB,GACzB,YAAYF,EAAOd,KAAK,UAChC,CAwGuBqB,CAAoBtC,GACtC4B,GAAOT,EAAMM,KAAKG,GAKtBT,EAAMM,KAtGA,SAA4BzB,GAClC,MAAM6B,EAAgCC,iBAAiB9B,GACjDuC,EAAkB,CACvB,cACA,YACA,cACA,cACA,iBACA,eACA,SAEKC,EAAkB,CAAC,gBACzB,IAAA,MAAWN,KAAQK,EAAO,CACzB,MAAM3D,EAAgBiD,EAASO,iBAAiBF,GAAMG,OAClDzD,GACH4D,EAAMf,KAAK,KAAKS,MAAStD,KAE3B,CACA,MAAO,WAAW4D,EAAMvB,KAAK,UAC9B,CAmFYwB,CAAmBzC,IAE9B,MAAM0C,EAlFA,SAA0BrC,GAChC,MAAMc,EAAkB,GAGlBwB,EAAsB,GAQ5B,GAPItC,EAAQuC,OACXD,EAAUlB,KAAK,aAAapB,EAAQuC,WAC1BvC,EAAQwC,WAGlBF,EAAUlB,KAAK,gBAEZpB,EAAQwC,WAAaxC,EAAQyC,YAAa,CAC7C,MACMC,EAAsB,CADA1C,EAAQwC,UAAYG,EAAgB3C,EAAQwC,WAAa,MAEjFxC,EAAQyC,aACXC,EAAUtB,KAAKpB,EAAQyC,aAExBH,EAAUlB,KAAK,WAAWsB,EAAU9B,KAAK,QAC1C,CACI0B,EAAUV,OAAS,GACtBd,EAAMM,KAAK,YAAYkB,EAAU1B,KAAK,YAInCZ,EAAQwC,WACX1B,EAAMM,KACL,+BAA+BwB,OAAyBC,qBAK1D,MAAMC,EAAuB,GA4B7B,OAzBAA,EAAW1B,KAAK,yDAGhB0B,EAAW1B,KACV,yHAKD0B,EAAW1B,KAAK,qCAGhB0B,EAAW1B,KAAK,4CAIgB,IAA5BpB,EAAQ+C,iBACXD,EAAW1B,KACV,6FAKFN,EAAMM,KAAK,qBAAqB0B,EAAWlC,KAAK,cAEzCE,EAAMF,KAAK,OACnB,CAqB0BoC,CAAiBhD,GAO1C,OANIqC,GAAUvB,EAAMM,KAAKiB,GAErBrC,EAAQiD,WACXnC,EAAMM,KAAKpB,EAAQiD,WAGbnC,EAAMF,KAAK,OACnB,CD3FsBsC,CAAWpD,EAAYH,EAAMW,GFY5C,SAAiBhB,EAAwBU,GAC/C,MAAMmD,EAxEA,SAAsB7D,GAG5B,OAFoCA,EAAU8D,cAAc,qBACrB9D,GACzB+D,WAAU,EACzB,CAoE4BC,CAAahE,GAIxC,OArEM,SAAkB6D,GAExBA,EAAMI,gBAAgB,mBAGtB,MAAMC,EAAsC,CAAC,wBAAyB,0BACtE,IAAA,MAAWC,KAAOD,EAAkB,CACnCL,EAAMO,UAAUC,OAAOF,GACvB,IAAA,MAAWG,KAAMT,EAAMU,iBAAiB,IAAIJ,KAC3CG,EAAGF,UAAUC,OAAOF,EAEtB,CAGAN,EAAMI,gBAAgB,mBACvB,CAmDCO,CAASX,GAhDH,SAA2BA,EAAoBnD,GACrD,GAAIA,EAAQ+D,kBACX,IAAA,MAAWC,KAAQhE,EAAQ+D,kBAAmB,CAC7C,MAAME,EAAgCd,EAAMU,iBAAiB,qBAAqBG,OAClF,IAAA,MAAWJ,KAAMK,EAChBL,EAAGD,QAEL,CAGD,GAAI3D,EAAQkE,gBACX,IAAA,MAAWF,KAAQhE,EAAQkE,gBAAiB,CAC3C,MAAMD,EAAgCd,EAAMU,iBAAiB,qBAAqBG,OAClF,IAAA,MAAWJ,KAAMK,EAChBE,EAAmBP,EAAmB,CACrCQ,YAAa,OACbF,gBAAiB,UAGpB,CAEF,CA4BCG,CAAkBlB,EAAOnD,GApBnB,SAA4BmD,EAAoBnD,GACtD,GAAIA,EAAQsE,OAAQ,CACnB,MAAMC,EAA2BC,SAASC,cAAc,OACxDF,EAASG,UAAY,uBACrBH,EAASI,UAAYrG,EAAe0B,EAAQsE,QAC5CnB,EAAMyB,aAAaL,EAAUpB,EAAM0B,WACpC,CAEA,GAAI7E,EAAQ8E,OAAQ,CACnB,MAAMC,EAA2BP,SAASC,cAAc,OACxDM,EAASL,UAAY,uBACrBK,EAASJ,UAAYrG,EAAe0B,EAAQ8E,QAC5C3B,EAAM6B,YAAYD,EACnB,CACD,CAOCE,CAAmB9B,EAAOnD,GACnBmD,CACR,CEf6B+B,CAAQ5F,EAAWgB,GACZ6E,UAGZ7E,EAAaI,OAAS,GAE3Cf,EAAKyF,QAAQ,WAAWC,aAAa,UAAYb,SAASc,gBAAgBnH,MAAQ,OAI7EoH,EAA8B,CAAEhF,QAGtC,OAFAX,EAASQ,KAAKoF,EAAaD,GAEpBhF,CACR,CAEA,MAAO,CACN,KAAA9B,CAAMuB,GACL,MACMO,EAAsBN,EADGF,EAAaC,IAE5C,IAAKO,EAAM,OAGX,MAAMkF,EAA4BjB,SAASC,cAAc,UACzDiB,EAAaD,EAAQ,4DACrBjB,SAASmB,KAAKX,YAAYS,GAE1B,MAAMG,EAA6BH,EAAOI,gBAC1C,IAAKD,EAEJ,YADApB,SAASmB,KAAKG,YAAYL,GAI3BG,EAAUG,OACVH,EAAUI,MAAMzF,GAChBqF,EAAUK,QAEV,MAAMC,EAAU,KACfT,EAAO9B,UAIJ8B,EAAOU,eACVV,EAAOU,cAAcC,iBAAiB,aAAcF,EAAS,CAAEG,MAAM,IACrEZ,EAAOU,cAAc1H,SAErByH,GAEF,EAEAxH,OAAOsB,GAECC,EADwBF,EAAaC,KACX,GAGpC,CDzEkBsG,CAAmB9G,EAAUG,EAAML,EAAWM,EAC9D,MACCV,KAAKH,QAAUP,EAGhBY,EAAQmH,gBAAgBC,EAAmBtH,KAAKH,SAEhD,MAAM0H,EAAyBvH,KAAKJ,OAAO2H,UAAY,CAAA,EACjD1H,EAAwBG,KAAKH,QAE7B2H,EAAcxH,KAAKF,OACzBI,EAAQuH,gBAAgB,QAAS,KAChCvH,EAAQwH,SAASF,EAAY7I,sBAC7BkB,EAAQN,MAAMgI,IACP,IAGR,MAAMI,EAAqB3H,KAAKJ,OAAO+H,YAAc,QAQrD,GAPAzH,EAAQ0H,eAAe,CACtBD,CAACA,GAAa,KACbzH,EAAQ2H,eAAe,UAChB,MAI2B,IAAhC7H,KAAKJ,OAAOkI,gBAA2B,CAC1C,MAAMpJ,EAAmBqJ,EAAeJ,GACxCzH,EAAQ8H,oBAAoB,CAC3BtI,GAAI,QACJuI,MAAO,UACPzJ,MAAOwB,KAAKF,OAAOtB,MACnBC,QAASuB,KAAKF,OAAOrB,QAAQC,GAC7BwJ,KAtEH,sPAuEGC,QAAS,SAEX,CACD,CAEA,OAAAC,GACCpI,KAAKH,QAAU,IAChB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"shared.mjs","sources":["../../src/plugins/shared/PopupKeyboardPatterns.ts"],"sourcesContent":["/**\n * Pure functions that attach WAI-ARIA keyboard patterns to popup containers.\n * Supports menu, listbox, and grid navigation patterns.\n * Delegates to shared keyboard navigation helpers.\n */\n\nimport { applyRovingTabindex, findNextDropdownItem, navigateGrid } from './KeyboardNav.js';\n\n// --- Types ---\n\nexport interface MenuKeyboardConfig {\n\treadonly container: HTMLElement;\n\treadonly itemSelector: string;\n\treadonly onActivate: (item: HTMLElement) => void;\n\treadonly onClose: () => void;\n\treadonly getActiveElement: () => Element | null;\n}\n\nexport interface ListboxKeyboardConfig {\n\treadonly container: HTMLElement;\n\treadonly itemSelector: string;\n\treadonly onSelect: (item: HTMLElement) => void;\n\treadonly onClose: () => void;\n}\n\nexport interface GridKeyboardConfig {\n\treadonly container: HTMLElement;\n\treadonly cellSelector: string;\n\treadonly columns: number;\n\treadonly totalCells: number;\n\treadonly onSelect: (cell: HTMLElement) => void;\n\treadonly onClose: () => void;\n\treadonly onNavigate?: (index: number) => void;\n}\n\n// --- Constants ---\n\nconst GRID_NAV_KEYS: ReadonlySet<string> = new Set([\n\t'ArrowUp',\n\t'ArrowDown',\n\t'ArrowLeft',\n\t'ArrowRight',\n]);\n\n// --- Menu Keyboard ---\n\n/**\n * Attaches menu keyboard navigation (ArrowUp/Down, Enter/Space, Home/End, Escape).\n * Returns a cleanup function that removes the event listener.\n */\nexport function attachMenuKeyboard(config: MenuKeyboardConfig): () => void {\n\tlet focusedIndex = 0;\n\n\tconst handler = (e: KeyboardEvent): void => {\n\t\te.stopPropagation();\n\t\tconst items: HTMLElement[] = Array.from(\n\t\t\tconfig.container.querySelectorAll(config.itemSelector),\n\t\t) as HTMLElement[];\n\t\tif (items.length === 0) return;\n\n\t\tswitch (e.key) {\n\t\t\tcase 'Escape': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconfig.onClose();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'ArrowDown': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = findNextDropdownItem(items, focusedIndex, 1);\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'ArrowUp': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = findNextDropdownItem(items, focusedIndex, -1);\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst item: HTMLElement | undefined = items[focusedIndex];\n\t\t\t\tif (item) config.onActivate(item);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'Home': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = 0;\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'End': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = items.length - 1;\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\n\tconfig.container.addEventListener('keydown', handler);\n\treturn () => config.container.removeEventListener('keydown', handler);\n}\n\n// --- Listbox Keyboard ---\n\n/**\n * Attaches listbox keyboard navigation (ArrowUp/Down, Enter/Space, Escape).\n * Returns a cleanup function.\n */\nexport function attachListboxKeyboard(config: ListboxKeyboardConfig): () => void {\n\tlet focusedIndex = 0;\n\n\tconst handler = (e: KeyboardEvent): void => {\n\t\tconst items: HTMLElement[] = Array.from(\n\t\t\tconfig.container.querySelectorAll(config.itemSelector),\n\t\t) as HTMLElement[];\n\t\tif (items.length === 0) return;\n\n\t\tswitch (e.key) {\n\t\t\tcase 'Escape': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconfig.onClose();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'ArrowDown': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = findNextDropdownItem(items, focusedIndex, 1);\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'ArrowUp': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = findNextDropdownItem(items, focusedIndex, -1);\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst item: HTMLElement | undefined = items[focusedIndex];\n\t\t\t\tif (item) config.onSelect(item);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\n\tconfig.container.addEventListener('keydown', handler);\n\treturn () => config.container.removeEventListener('keydown', handler);\n}\n\n// --- Grid Keyboard ---\n\n/**\n * Attaches grid keyboard navigation (2D arrows, Home/End per row, Enter/Space, Escape).\n * Returns a cleanup function.\n */\nexport function attachGridKeyboard(config: GridKeyboardConfig): () => void {\n\tlet focusedIndex = 0;\n\tconst columns: number = config.columns;\n\tconst totalCells: number = config.totalCells;\n\tconst totalRows: number = Math.ceil(totalCells / columns);\n\n\tconst handler = (e: KeyboardEvent): void => {\n\t\tconst cells: HTMLElement[] = Array.from(\n\t\t\tconfig.container.querySelectorAll(config.cellSelector),\n\t\t) as HTMLElement[];\n\t\tif (cells.length === 0) return;\n\n\t\tif (e.key === 'Escape') {\n\t\t\te.preventDefault();\n\t\t\tconfig.onClose();\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.key === 'Enter' || e.key === ' ') {\n\t\t\te.preventDefault();\n\t\t\tconst cell: HTMLElement | undefined = cells[focusedIndex];\n\t\t\tif (cell) config.onSelect(cell);\n\t\t\treturn;\n\t\t}\n\n\t\tif (GRID_NAV_KEYS.has(e.key)) {\n\t\t\te.preventDefault();\n\t\t\tconst currentRow: number = Math.floor(focusedIndex / columns) + 1;\n\t\t\tconst currentCol: number = (focusedIndex % columns) + 1;\n\n\t\t\tconst [newRow, newCol] = navigateGrid(\n\t\t\t\tcurrentRow,\n\t\t\t\tcurrentCol,\n\t\t\t\ttotalRows,\n\t\t\t\tcolumns,\n\t\t\t\te.key as 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight',\n\t\t\t);\n\n\t\t\tlet newIdx: number = (newRow - 1) * columns + (newCol - 1);\n\t\t\tif (newIdx >= totalCells) {\n\t\t\t\tnewIdx = totalCells - 1;\n\t\t\t}\n\n\t\t\tfocusedIndex = newIdx;\n\t\t\tapplyRovingTabindex(cells as HTMLButtonElement[], focusedIndex);\n\t\t\tcells[focusedIndex]?.focus();\n\t\t\tconfig.onNavigate?.(focusedIndex);\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.key === 'Home' || e.key === 'End') {\n\t\t\te.preventDefault();\n\t\t\tconst currentRow: number = Math.floor(focusedIndex / columns);\n\t\t\tconst rowStart: number = currentRow * columns;\n\t\t\tconst rowEnd: number = Math.min(rowStart + columns - 1, totalCells - 1);\n\n\t\t\tfocusedIndex = e.key === 'Home' ? rowStart : rowEnd;\n\t\t\tapplyRovingTabindex(cells as HTMLButtonElement[], focusedIndex);\n\t\t\tcells[focusedIndex]?.focus();\n\t\t\tconfig.onNavigate?.(focusedIndex);\n\t\t}\n\t};\n\n\tconfig.container.addEventListener('keydown', handler);\n\treturn () => config.container.removeEventListener('keydown', handler);\n}\n"],"names":["GRID_NAV_KEYS","Set","attachMenuKeyboard","config","focusedIndex","handler","e","stopPropagation","items","Array","from","container","querySelectorAll","itemSelector","length","key","preventDefault","onClose","findNextDropdownItem","applyRovingTabindex","focus","item","onActivate","addEventListener","removeEventListener","attachListboxKeyboard","onSelect","attachGridKeyboard","columns","totalCells","totalRows","Math","ceil","cells","cellSelector","cell","has","currentRow","floor","currentCol","newRow","newCol","navigateGrid","newIdx","onNavigate","rowStart","rowEnd","min"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"smart-paste.mjs","sources":["../../src/plugins/smart-paste/SmartPasteLocale.ts","../../src/plugins/smart-paste/SmartPasteTypes.ts","../../src/plugins/smart-paste/detectors/JsonDetector.ts","../../src/plugins/smart-paste/detectors/XmlDetector.ts","../../src/plugins/smart-paste/SmartPastePlugin.ts"],"sourcesContent":["/** Locale interface and default English locale for the SmartPastePlugin. */\n\nexport interface SmartPasteLocale {\n\treadonly detectedAsCodeBlock: (language: string) => string;\n}\n\nexport const SMART_PASTE_LOCALE_EN: SmartPasteLocale = {\n\tdetectedAsCodeBlock: (language: string) =>\n\t\t`Pasted as ${language} code block with syntax highlighting.`,\n};\n\nconst localeModules: Record<string, () => Promise<{ default: SmartPasteLocale }>> =\n\timport.meta.glob<{ default: SmartPasteLocale }>('./locales/*.ts', { eager: false });\n\nexport async function loadSmartPasteLocale(lang: string): Promise<SmartPasteLocale> {\n\tif (lang === 'en') return SMART_PASTE_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return SMART_PASTE_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn SMART_PASTE_LOCALE_EN;\n\t}\n}\n","/**\n * Types for the smart paste plugin — content detection and formatting.\n */\n\nimport { ServiceKey } from '../Plugin.js';\nimport type { SmartPasteLocale } from './SmartPasteLocale.js';\n\n/** Result of detecting structured content in pasted text. */\nexport interface DetectionResult {\n\treadonly language: string;\n\treadonly formattedText: string;\n\treadonly confidence: number;\n}\n\n/** Interface for content detectors that identify and format pasted text. */\nexport interface ContentDetector {\n\treadonly id: string;\n\tdetect(text: string): DetectionResult | null;\n}\n\n/** Configuration for the SmartPastePlugin. */\nexport interface SmartPasteConfig {\n\treadonly detectors?: readonly ContentDetector[];\n\treadonly locale?: SmartPasteLocale;\n}\n\n/** Public service for registering additional content detectors at runtime. */\nexport interface SmartPasteService {\n\tregisterDetector(detector: ContentDetector): void;\n}\n\nexport const SMART_PASTE_SERVICE_KEY = new ServiceKey<SmartPasteService>('smartPaste');\n","/**\n * JSON content detector — validates and formats JSON for code block insertion.\n */\n\nimport type { ContentDetector, DetectionResult } from '../SmartPasteTypes.js';\n\n/** Minimum length for formatted JSON to be considered meaningful. */\nconst MIN_FORMATTED_LENGTH = 5;\n\n/** Confidence score for valid JSON detected via JSON.parse. */\nconst JSON_CONFIDENCE = 0.9;\n\nexport class JsonDetector implements ContentDetector {\n\treadonly id = 'json';\n\n\tdetect(text: string): DetectionResult | null {\n\t\tconst trimmed: string = text.trim();\n\t\tif (!trimmed.startsWith('{') && !trimmed.startsWith('[')) return null;\n\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(trimmed);\n\t\t\tif (typeof parsed !== 'object' || parsed === null) return null;\n\n\t\t\tconst formatted: string = JSON.stringify(parsed, null, 2);\n\t\t\tif (formatted.length <= MIN_FORMATTED_LENGTH) return null;\n\n\t\t\treturn { language: 'json', formattedText: formatted, confidence: JSON_CONFIDENCE };\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n}\n","/**\n * XML content detector — validates and formats XML for code block insertion.\n */\n\nimport { XML_ATTRS, XML_TAG_NAME } from '../../shared/XmlPatterns.js';\nimport type { ContentDetector, DetectionResult } from '../SmartPasteTypes.js';\n\n/** Minimum length for formatted XML to be considered meaningful. */\nconst MIN_FORMATTED_LENGTH = 10;\n\n/** Confidence score for valid XML detected via structural analysis. */\nconst XML_CONFIDENCE = 0.85;\n\n/** Matches any leading processing instructions like <?xml ...?> or <?xml-stylesheet ...?> */\nconst LEADING_PIS_PATTERN = /^(<\\?[\\s\\S]*?\\?>\\s*)+/;\n\n/** Matches an opening tag like <root> or <ns:tag attr=\"val\"> */\nconst OPENING_TAG_PATTERN = new RegExp(`^<${XML_TAG_NAME}${XML_ATTRS}\\\\/?>`);\n\n// --- Well-formedness regex (decomposed for readability) ---\n\nconst PI_FRAGMENT = '<\\\\?[^?]*\\\\?>';\nconst COMMENT_FRAGMENT = '<!--[\\\\s\\\\S]*?-->';\nconst CDATA_FRAGMENT = '<!\\\\[CDATA\\\\[[\\\\s\\\\S]*?\\\\]\\\\]>';\nconst CLOSING_TAG_FRAGMENT = `<\\\\/(${XML_TAG_NAME})>`;\nconst SELF_CLOSING_TAG_FRAGMENT = `<(${XML_TAG_NAME})${XML_ATTRS}\\\\/>`;\nconst OPENING_TAG_FRAGMENT = `<(${XML_TAG_NAME})${XML_ATTRS}>`;\n\nconst WELL_FORMED_TAG_PATTERN = new RegExp(\n\t[\n\t\tPI_FRAGMENT,\n\t\tCOMMENT_FRAGMENT,\n\t\tCDATA_FRAGMENT,\n\t\tCLOSING_TAG_FRAGMENT,\n\t\tSELF_CLOSING_TAG_FRAGMENT,\n\t\tOPENING_TAG_FRAGMENT,\n\t].join('|'),\n\t'g',\n);\n\n/** Matches an inline element where open + close tag appear on the same token. */\nconst INLINE_ELEMENT_PATTERN = new RegExp(`<\\\\/${XML_TAG_NAME}>\\\\s*$`);\n\n/**\n * Detects well-formed XML content and formats it with proper indentation.\n *\n * Detection strategy:\n * 1. Text must start with `<` (after trimming)\n * 2. Must begin with an XML declaration, processing instruction, or opening tag\n * 3. All opened tags must be properly closed (basic well-formedness check)\n * 4. Must contain at least one tag pair or self-closing tag\n */\nexport class XmlDetector implements ContentDetector {\n\treadonly id = 'xml';\n\n\tdetect(text: string): DetectionResult | null {\n\t\tconst trimmed: string = text.trim();\n\t\tif (!trimmed.startsWith('<')) return null;\n\n\t\t// Quick structural check: strip leading PIs, then must start with an opening tag\n\t\tconst remainder: string = trimmed.replace(LEADING_PIS_PATTERN, '');\n\t\tif (!OPENING_TAG_PATTERN.test(remainder)) return null;\n\n\t\t// Validate well-formedness via tag balancing\n\t\tif (!this.isWellFormed(trimmed)) return null;\n\n\t\tconst formatted: string = this.formatXml(trimmed);\n\t\tif (formatted.length <= MIN_FORMATTED_LENGTH) return null;\n\n\t\treturn { language: 'xml', formattedText: formatted, confidence: XML_CONFIDENCE };\n\t}\n\n\t/**\n\t * Checks basic XML well-formedness by verifying that all opened tags\n\t * are properly closed in the correct nesting order.\n\t */\n\tprivate isWellFormed(xml: string): boolean {\n\t\tconst tagStack: string[] = [];\n\t\tlet foundTag = false;\n\n\t\t// Reset lastIndex — RegExp with 'g' flag is stateful\n\t\tWELL_FORMED_TAG_PATTERN.lastIndex = 0;\n\t\tlet match: RegExpExecArray | null = WELL_FORMED_TAG_PATTERN.exec(xml);\n\n\t\twhile (match) {\n\t\t\tconst closingTag: string | undefined = match[1];\n\t\t\tconst selfClosingTag: string | undefined = match[2];\n\t\t\tconst openingTag: string | undefined = match[3];\n\n\t\t\tif (closingTag) {\n\t\t\t\tif (tagStack.length === 0 || tagStack[tagStack.length - 1] !== closingTag) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\ttagStack.pop();\n\t\t\t\tfoundTag = true;\n\t\t\t} else if (selfClosingTag) {\n\t\t\t\tfoundTag = true;\n\t\t\t} else if (openingTag) {\n\t\t\t\ttagStack.push(openingTag);\n\t\t\t\tfoundTag = true;\n\t\t\t}\n\n\t\t\tmatch = WELL_FORMED_TAG_PATTERN.exec(xml);\n\t\t}\n\n\t\treturn foundTag && tagStack.length === 0;\n\t}\n\n\t/**\n\t * Formats XML with consistent 2-space indentation.\n\t */\n\tprivate formatXml(xml: string): string {\n\t\tconst tokens: string[] = this.splitIntoTokens(xml);\n\t\tconst parts: string[] = [];\n\t\tlet indent = 0;\n\t\tconst INDENT_STEP = 2;\n\n\t\tfor (const token of tokens) {\n\t\t\tconst kind: XmlTokenKind = classifyXmlToken(token);\n\t\t\tconst indentChange: IndentChange = INDENT_BEHAVIOR[kind];\n\n\t\t\tif (indentChange === 'decrease') {\n\t\t\t\tindent = Math.max(0, indent - 1);\n\t\t\t}\n\n\t\t\tparts.push(' '.repeat(indent * INDENT_STEP) + token);\n\n\t\t\tif (indentChange === 'increase') {\n\t\t\t\tindent++;\n\t\t\t}\n\t\t}\n\n\t\treturn parts.join('\\n');\n\t}\n\n\t/** Splits XML into line-level tokens by breaking between adjacent tags. */\n\tprivate splitIntoTokens(xml: string): string[] {\n\t\treturn xml\n\t\t\t.replace(/>\\s*</g, '>\\n<')\n\t\t\t.split('\\n')\n\t\t\t.map((line: string) => line.trim())\n\t\t\t.filter((line: string) => line.length > 0);\n\t}\n}\n\n// --- Token Classification ---\n\ntype XmlTokenKind =\n\t| 'pi'\n\t| 'comment'\n\t| 'cdata'\n\t| 'closing'\n\t| 'selfClosing'\n\t| 'inline'\n\t| 'opening'\n\t| 'text';\ntype IndentChange = 'increase' | 'decrease' | 'none';\n\nconst INDENT_BEHAVIOR: Readonly<Record<XmlTokenKind, IndentChange>> = {\n\tpi: 'none',\n\tcomment: 'none',\n\tcdata: 'none',\n\tclosing: 'decrease',\n\tselfClosing: 'none',\n\tinline: 'none',\n\topening: 'increase',\n\ttext: 'none',\n};\n\nfunction classifyXmlToken(token: string): XmlTokenKind {\n\tif (token.startsWith('<?')) return 'pi';\n\tif (token.startsWith('<!--')) return 'comment';\n\tif (token.startsWith('<![CDATA[')) return 'cdata';\n\tif (token.startsWith('</')) return 'closing';\n\tif (token.endsWith('/>')) return 'selfClosing';\n\tif (token.startsWith('<') && INLINE_ELEMENT_PATTERN.test(token)) return 'inline';\n\tif (token.startsWith('<')) return 'opening';\n\treturn 'text';\n}\n","/**\n * SmartPastePlugin: detects structured content in clipboard text\n * and inserts it as formatted code blocks with syntax highlighting.\n */\n\nimport { insertBlockAfterAnchor, resolveAnchorBlockId } from '../../commands/BlockInsertion.js';\nimport { addDeleteSelectionSteps } from '../../commands/Commands.js';\nimport {\n\ttype BlockNode,\n\tcreateBlockNode,\n\tcreateTextNode,\n\tgenerateBlockId,\n} from '../../model/Document.js';\nimport { createCollapsedSelection, isCollapsed, isTextSelection } from '../../model/Selection.js';\nimport type { BlockId, NodeTypeName } from '../../model/TypeBrands.js';\nimport { nodeType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport type { PasteInterceptor, Plugin, PluginContext } from '../Plugin.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport {\n\tSMART_PASTE_LOCALE_EN,\n\ttype SmartPasteLocale,\n\tloadSmartPasteLocale,\n} from './SmartPasteLocale.js';\nimport type { ContentDetector, DetectionResult, SmartPasteConfig } from './SmartPasteTypes.js';\nimport { SMART_PASTE_SERVICE_KEY } from './SmartPasteTypes.js';\nimport { JsonDetector } from './detectors/JsonDetector.js';\nimport { XmlDetector } from './detectors/XmlDetector.js';\n\nexport class SmartPastePlugin implements Plugin {\n\treadonly id = 'smart-paste';\n\treadonly name = 'Smart Paste';\n\treadonly dependencies = ['code-block'] as const;\n\n\tprivate readonly config: SmartPasteConfig;\n\tprivate readonly detectors: ContentDetector[] = [];\n\tprivate context: PluginContext | null = null;\n\tprivate locale: SmartPasteLocale = SMART_PASTE_LOCALE_EN;\n\n\tconstructor(config?: Partial<SmartPasteConfig>) {\n\t\tthis.config = { ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.context = context;\n\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tSMART_PASTE_LOCALE_EN,\n\t\t\tloadSmartPasteLocale,\n\t\t);\n\n\t\t// Register built-in detectors\n\t\tthis.detectors.push(new JsonDetector());\n\t\tthis.detectors.push(new XmlDetector());\n\n\t\t// Register config-provided detectors\n\t\tif (this.config.detectors) {\n\t\t\tfor (const detector of this.config.detectors) {\n\t\t\t\tthis.detectors.push(detector);\n\t\t\t}\n\t\t}\n\n\t\t// Register paste interceptor\n\t\tcontext.registerPasteInterceptor(this.handlePaste, { name: 'smart-paste', priority: 50 });\n\n\t\t// Register service for external detector registration\n\t\tcontext.registerService(SMART_PASTE_SERVICE_KEY, {\n\t\t\tregisterDetector: (detector: ContentDetector) => {\n\t\t\t\tthis.detectors.push(detector);\n\t\t\t},\n\t\t});\n\t}\n\n\tdestroy(): void {\n\t\tthis.context = null;\n\t\tthis.detectors.length = 0;\n\t}\n\n\t// --- Paste Interceptor ---\n\n\tprivate readonly handlePaste: PasteInterceptor = (\n\t\tplainText: string,\n\t\t_html: string,\n\t\tstate: EditorState,\n\t): Transaction | null => {\n\t\t// Don't create nested code blocks\n\t\tif (this.isCursorInCodeBlock(state)) return null;\n\n\t\t// Run all detectors and pick the highest confidence result\n\t\tconst detection: DetectionResult | null = this.detectContent(plainText);\n\t\tif (!detection) return null;\n\n\t\tconst tr: Transaction | null = this.buildCodeBlockTransaction(state, detection);\n\t\tif (tr && this.context) {\n\t\t\tthis.context.announce(this.locale.detectedAsCodeBlock(detection.language));\n\t\t}\n\t\treturn tr;\n\t};\n\n\tprivate detectContent(text: string): DetectionResult | null {\n\t\tlet best: DetectionResult | null = null;\n\n\t\tfor (const detector of this.detectors) {\n\t\t\tconst result: DetectionResult | null = detector.detect(text);\n\t\t\tif (result && (best === null || result.confidence > best.confidence)) {\n\t\t\t\tbest = result;\n\t\t\t}\n\t\t}\n\n\t\treturn best;\n\t}\n\n\tprivate isCursorInCodeBlock(state: EditorState): boolean {\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.anchor.blockId);\n\t\treturn block?.type === 'code_block';\n\t}\n\n\tprivate buildCodeBlockTransaction(\n\t\tstate: EditorState,\n\t\tdetection: DetectionResult,\n\t): Transaction | null {\n\t\tconst sel = state.selection;\n\t\tconst builder = state.transaction('paste');\n\n\t\t// Delete selection if range-selected\n\t\tlet anchorBlockId: BlockId;\n\t\tif (isTextSelection(sel) && !isCollapsed(sel)) {\n\t\t\tconst landingId: BlockId | undefined = addDeleteSelectionSteps(state, builder);\n\t\t\tanchorBlockId = landingId ?? sel.anchor.blockId;\n\t\t} else {\n\t\t\tanchorBlockId = resolveAnchorBlockId(sel);\n\t\t}\n\n\t\t// Create the code block node\n\t\tconst newBlockId: BlockId = generateBlockId();\n\t\tconst codeBlock: BlockNode = createBlockNode(\n\t\t\tnodeType('code_block') as NodeTypeName,\n\t\t\t[createTextNode(detection.formattedText)],\n\t\t\tnewBlockId,\n\t\t\t{ language: detection.language, backgroundColor: '' },\n\t\t);\n\n\t\t// Insert at cursor (handles cell vs root, empty anchor removal)\n\t\tconst inserted: boolean = insertBlockAfterAnchor(\n\t\t\tstate,\n\t\t\tbuilder,\n\t\t\tanchorBlockId,\n\t\t\tcodeBlock,\n\t\t\tsel,\n\t\t\tthis.context?.getSchemaRegistry(),\n\t\t);\n\t\tif (!inserted) return null;\n\n\t\tbuilder.setSelection(createCollapsedSelection(newBlockId, detection.formattedText.length));\n\n\t\treturn builder.build();\n\t}\n}\n"],"names":["SMART_PASTE_LOCALE_EN","detectedAsCodeBlock","language","localeModules","assign","import","async","loadSmartPasteLocale","lang","loader","default","SMART_PASTE_SERVICE_KEY","ServiceKey","JsonDetector","id","detect","text","trimmed","trim","startsWith","parsed","JSON","parse","formatted","stringify","length","formattedText","confidence","LEADING_PIS_PATTERN","OPENING_TAG_PATTERN","RegExp","XML_TAG_NAME","XML_ATTRS","WELL_FORMED_TAG_PATTERN","join","INLINE_ELEMENT_PATTERN","XmlDetector","remainder","replace","test","this","isWellFormed","formatXml","xml","tagStack","foundTag","lastIndex","match","exec","closingTag","selfClosingTag","openingTag","pop","push","tokens","splitIntoTokens","parts","indent","token","kind","classifyXmlToken","indentChange","INDENT_BEHAVIOR","Math","max","repeat","split","map","line","filter","pi","comment","cdata","closing","selfClosing","inline","opening","endsWith","SmartPastePlugin","name","dependencies","config","detectors","context","locale","constructor","init","resolveLocale","detector","registerPasteInterceptor","handlePaste","priority","registerService","registerDetector","destroy","plainText","_html","state","isCursorInCodeBlock","detection","detectContent","tr","buildCodeBlockTransaction","announce","best","result","sel","selection","isTextSelection","block","getBlock","anchor","blockId","type","builder","transaction","anchorBlockId","isCollapsed","addDeleteSelectionSteps","resolveAnchorBlockId","newBlockId","generateBlockId","codeBlock","createBlockNode","nodeType","createTextNode","backgroundColor","insertBlockAfterAnchor","getSchemaRegistry","setSelection","createCollapsedSelection","build"],"mappings":"yaAMO,MAAMA,EAA0C,CACtDC,oBAAsBC,GACrB,aAAaA,0CAGTC,wBACLC,OAAA,CAAA,kBAAA,IAAAC,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,+BAEDC,eAAsBC,EAAqBC,GAC1C,GAAa,OAATA,EAAe,OAAOR,EAC1B,MAAMS,EAASN,EAAc,aAAaK,QAC1C,IAAKC,EAAQ,OAAOT,EACpB,IAEC,aADkBS,KACPC,OACZ,CAAA,MACC,OAAOV,CACR,CACD,CCOO,MAAMW,EAA0B,IAAIC,EAA8B,cCnBlE,MAAMC,EACHC,GAAK,OAEd,MAAAC,CAAOC,GACN,MAAMC,EAAkBD,EAAKE,OAC7B,IAAKD,EAAQE,WAAW,OAASF,EAAQE,WAAW,KAAM,OAAO,KAEjE,IACC,MAAMC,EAAkBC,KAAKC,MAAML,GACnC,GAAsB,iBAAXG,GAAkC,OAAXA,EAAiB,OAAO,KAE1D,MAAMG,EAAoBF,KAAKG,UAAUJ,EAAQ,KAAM,GACvD,OAAIG,EAAUE,QAjBY,EAiB2B,KAE9C,CAAEvB,SAAU,OAAQwB,cAAeH,EAAWI,WAhBhC,GAiBtB,CAAA,MACC,OAAO,IACR,CACD,ECtBD,MAMMC,EAAsB,wBAGtBC,EAAsB,IAAIC,OAAO,KAAKC,IAAeC,UAWrDC,EAA0B,IAAIH,OACnC,CARmB,gBACK,0BACF,iCACM,QAAQC,MACH,KAAKA,KAAgBC,QAC1B,KAAKD,KAAgBC,MAU/CE,KAAK,KACP,KAIKC,EAAyB,IAAIL,OAAO,OAAOC,WAW1C,MAAMK,EACHtB,GAAK,MAEd,MAAAC,CAAOC,GACN,MAAMC,EAAkBD,EAAKE,OAC7B,IAAKD,EAAQE,WAAW,KAAM,OAAO,KAGrC,MAAMkB,EAAoBpB,EAAQqB,QAAQV,EAAqB,IAC/D,IAAKC,EAAoBU,KAAKF,GAAY,OAAO,KAGjD,IAAKG,KAAKC,aAAaxB,GAAU,OAAO,KAExC,MAAMM,EAAoBiB,KAAKE,UAAUzB,GACzC,OAAIM,EAAUE,QA3Da,GA2D0B,KAE9C,CAAEvB,SAAU,MAAOwB,cAAeH,EAAWI,WA1D/B,IA2DtB,CAMQ,YAAAc,CAAaE,GACpB,MAAMC,EAAqB,GAC3B,IAAIC,GAAW,EAGfZ,EAAwBa,UAAY,EACpC,IAAIC,EAAgCd,EAAwBe,KAAKL,GAEjE,KAAOI,GAAO,CACb,MAAME,EAAiCF,EAAM,GACvCG,EAAqCH,EAAM,GAC3CI,EAAiCJ,EAAM,GAE7C,GAAIE,EAAY,CACf,GAAwB,IAApBL,EAASnB,QAAgBmB,EAASA,EAASnB,OAAS,KAAOwB,EAC9D,OAAO,EAERL,EAASQ,MACTP,GAAW,CACZ,MAAWK,EACVL,GAAW,EACDM,IACVP,EAASS,KAAKF,GACdN,GAAW,GAGZE,EAAQd,EAAwBe,KAAKL,EACtC,CAEA,OAAOE,GAAgC,IAApBD,EAASnB,MAC7B,CAKQ,SAAAiB,CAAUC,GACjB,MAAMW,EAAmBd,KAAKe,gBAAgBZ,GACxCa,EAAkB,GACxB,IAAIC,EAAS,EAGb,IAAA,MAAWC,KAASJ,EAAQ,CAC3B,MAAMK,EAAqBC,EAAiBF,GACtCG,EAA6BC,EAAgBH,GAE9B,aAAjBE,IACHJ,EAASM,KAAKC,IAAI,EAAGP,EAAS,IAG/BD,EAAMH,KAAK,IAAIY,OAVI,EAUGR,GAAwBC,GAEzB,aAAjBG,GACHJ,GAEF,CAEA,OAAOD,EAAMtB,KAAK,KACnB,CAGQ,eAAAqB,CAAgBZ,GACvB,OAAOA,EACLL,QAAQ,SAAU,QAClB4B,MAAM,MACNC,IAAKC,GAAiBA,EAAKlD,QAC3BmD,OAAQD,GAAiBA,EAAK3C,OAAS,EAC1C,EAgBD,MAAMqC,EAAgE,CACrEQ,GAAI,OACJC,QAAS,OACTC,MAAO,OACPC,QAAS,WACTC,YAAa,OACbC,OAAQ,OACRC,QAAS,WACT5D,KAAM,QAGP,SAAS4C,EAAiBF,GACzB,OAAIA,EAAMvC,WAAW,MAAc,KAC/BuC,EAAMvC,WAAW,WAAgB,UACjCuC,EAAMvC,WAAW,aAAqB,QACtCuC,EAAMvC,WAAW,MAAc,UAC/BuC,EAAMmB,SAAS,MAAc,cAC7BnB,EAAMvC,WAAW,MAAQgB,EAAuBI,KAAKmB,GAAe,SACpEA,EAAMvC,WAAW,KAAa,UAC3B,MACR,CCpJO,MAAM2D,EACHhE,GAAK,cACLiE,KAAO,cACPC,aAAe,CAAC,cAERC,OACAC,UAA+B,GACxCC,QAAgC,KAChCC,OAA2BpF,EAEnC,WAAAqF,CAAYJ,GACXzC,KAAKyC,OAAS,IAAKA,EACpB,CAEA,UAAMK,CAAKH,GAeV,GAdA3C,KAAK2C,QAAUA,EAEf3C,KAAK4C,aAAeG,EACnBJ,EACA3C,KAAKyC,OAAOG,OACZpF,EACAO,GAIDiC,KAAK0C,UAAU7B,KAAK,IAAIxC,GACxB2B,KAAK0C,UAAU7B,KAAK,IAAIjB,GAGpBI,KAAKyC,OAAOC,UACf,IAAA,MAAWM,KAAYhD,KAAKyC,OAAOC,UAClC1C,KAAK0C,UAAU7B,KAAKmC,GAKtBL,EAAQM,yBAAyBjD,KAAKkD,YAAa,CAAEX,KAAM,cAAeY,SAAU,KAGpFR,EAAQS,gBAAgBjF,EAAyB,CAChDkF,iBAAmBL,IAClBhD,KAAK0C,UAAU7B,KAAKmC,KAGvB,CAEA,OAAAM,GACCtD,KAAK2C,QAAU,KACf3C,KAAK0C,UAAUzD,OAAS,CACzB,CAIiBiE,YAAgC,CAChDK,EACAC,EACAC,KAGA,GAAIzD,KAAK0D,oBAAoBD,GAAQ,OAAO,KAG5C,MAAME,EAAoC3D,KAAK4D,cAAcL,GAC7D,IAAKI,EAAW,OAAO,KAEvB,MAAME,EAAyB7D,KAAK8D,0BAA0BL,EAAOE,GAIrE,OAHIE,GAAM7D,KAAK2C,SACd3C,KAAK2C,QAAQoB,SAAS/D,KAAK4C,OAAOnF,oBAAoBkG,EAAUjG,WAE1DmG,GAGA,aAAAD,CAAcpF,GACrB,IAAIwF,EAA+B,KAEnC,IAAA,MAAWhB,KAAYhD,KAAK0C,UAAW,CACtC,MAAMuB,EAAiCjB,EAASzE,OAAOC,GACnDyF,IAAoB,OAATD,GAAiBC,EAAO9E,WAAa6E,EAAK7E,cACxD6E,EAAOC,EAET,CAEA,OAAOD,CACR,CAEQ,mBAAAN,CAAoBD,GAC3B,MAAMS,EAAMT,EAAMU,UAClB,IAAKC,EAAgBF,GAAM,OAAO,EAElC,MAAMG,EAA+BZ,EAAMa,SAASJ,EAAIK,OAAOC,SAC/D,MAAuB,eAAhBH,GAAOI,IACf,CAEQ,yBAAAX,CACPL,EACAE,GAEA,MAAMO,EAAMT,EAAMU,UACZO,EAAUjB,EAAMkB,YAAY,SAGlC,IAAIC,EAGHA,EAFGR,EAAgBF,KAASW,EAAYX,GACDY,EAAwBrB,EAAOiB,IACzCR,EAAIK,OAAOC,QAExBO,EAAqBb,GAItC,MAAMc,EAAsBC,IACtBC,EAAuBC,EAC5BC,EAAS,cACT,CAACC,EAAe1B,EAAUzE,gBAC1B8F,EACA,CAAEtH,SAAUiG,EAAUjG,SAAU4H,gBAAiB,KAYlD,OAR0BC,EACzB9B,EACAiB,EACAE,EACAM,EACAhB,EACAlE,KAAK2C,SAAS6C,sBAIfd,EAAQe,aAAaC,EAAyBV,EAAYrB,EAAUzE,cAAcD,SAE3EyF,EAAQiB,SAJO,IAKvB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"strikethrough.mjs","sources":["../../src/plugins/strikethrough/StrikethroughLocale.ts","../../src/plugins/strikethrough/StrikethroughPlugin.ts"],"sourcesContent":["/**\n * Locale interface and default English locale for the StrikethroughPlugin.\n */\n\n// --- Locale Interface ---\n\nexport interface StrikethroughLocale {\n\treadonly label: string;\n\treadonly tooltip: (shortcut: string) => string;\n}\n\n// --- Default English Locale ---\n\nexport const STRIKETHROUGH_LOCALE_EN: StrikethroughLocale = {\n\tlabel: 'Strikethrough',\n\ttooltip: (shortcut: string) => `Strikethrough (${shortcut})`,\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: Record<string, () => Promise<{ default: StrikethroughLocale }>> =\n\timport.meta.glob<{ default: StrikethroughLocale }>('./locales/*.ts', { eager: false });\n\nexport async function loadStrikethroughLocale(lang: string): Promise<StrikethroughLocale> {\n\tif (lang === 'en') return STRIKETHROUGH_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return STRIKETHROUGH_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn STRIKETHROUGH_LOCALE_EN;\n\t}\n}\n","/**\n * StrikethroughPlugin: registers a strikethrough inline mark with MarkSpec,\n * toggle command, keyboard shortcut (Mod-Shift-X), and a toolbar button.\n */\n\nimport { isMarkActive, toggleMark } from '../../commands/Commands.js';\nimport { markType } from '../../model/TypeBrands.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport {\n\tSTRIKETHROUGH_LOCALE_EN,\n\ttype StrikethroughLocale,\n\tloadStrikethroughLocale,\n} from './StrikethroughLocale.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\tstrikethrough: Record<string, never>;\n\t}\n}\n\n// --- Configuration ---\n\nexport interface StrikethroughConfig {\n\treadonly locale?: StrikethroughLocale;\n}\n\nconst DEFAULT_CONFIG: StrikethroughConfig = {};\n\n// --- Plugin ---\n\nexport class StrikethroughPlugin implements Plugin {\n\treadonly id = 'strikethrough';\n\treadonly name = 'Strikethrough';\n\treadonly priority = 22;\n\n\tprivate readonly config: StrikethroughConfig;\n\tprivate locale!: StrikethroughLocale;\n\n\tconstructor(config?: Partial<StrikethroughConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tSTRIKETHROUGH_LOCALE_EN,\n\t\t\tloadStrikethroughLocale,\n\t\t);\n\t\tthis.registerMarkSpec(context);\n\t\tthis.registerCommand(context);\n\t\tthis.registerKeymap(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tprivate registerMarkSpec(context: PluginContext): void {\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: 'strikethrough',\n\t\t\trank: 3,\n\t\t\ttoDOM() {\n\t\t\t\treturn document.createElement('s');\n\t\t\t},\n\t\t\ttoHTMLString: (_mark, content) => `<s>${content}</s>`,\n\t\t\tparseHTML: [\n\t\t\t\t{ tag: 's' },\n\t\t\t\t{ tag: 'strike' },\n\t\t\t\t{ tag: 'del' },\n\t\t\t\t{\n\t\t\t\t\ttag: 'span',\n\t\t\t\t\tgetAttrs: (el: HTMLElement) => {\n\t\t\t\t\t\treturn el.style.textDecoration.includes('line-through') ? {} : false;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsanitize: { tags: ['s'] },\n\t\t});\n\t}\n\n\tprivate registerCommand(context: PluginContext): void {\n\t\tcontext.registerCommand('toggleStrikethrough', () => {\n\t\t\tconst tr = toggleMark(context.getState(), markType('strikethrough'));\n\t\t\tif (tr) {\n\t\t\t\tcontext.dispatch(tr);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\t}\n\n\tprivate registerKeymap(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Mod-Shift-X': () => context.executeCommand('toggleStrikethrough'),\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst icon =\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M10 19h4v-3h-4v3zM5 4v3h5v3h4V7h5V4H5zM3 14h18v-2H3v2z\"/></svg>';\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'strikethrough',\n\t\t\tgroup: 'format',\n\t\t\ticon,\n\t\t\tlabel: this.locale.label,\n\t\t\ttooltip: this.locale.tooltip(formatShortcut('Mod-Shift-X')),\n\t\t\tcommand: 'toggleStrikethrough',\n\t\t\tisActive: (state) => isMarkActive(state, markType('strikethrough')),\n\t\t});\n\t}\n}\n"],"names":["STRIKETHROUGH_LOCALE_EN","label","tooltip","shortcut","localeModules","assign","import","async","loadStrikethroughLocale","lang","loader","default","DEFAULT_CONFIG","StrikethroughPlugin","id","name","priority","config","locale","constructor","this","init","context","resolveLocale","registerMarkSpec","registerCommand","registerKeymap","registerToolbarItem","type","rank","toDOM","document","createElement","toHTMLString","_mark","content","parseHTML","tag","getAttrs","el","style","textDecoration","includes","sanitize","tags","tr","toggleMark","getState","markType","dispatch","executeCommand","group","icon","formatShortcut","command","isActive","state","isMarkActive"],"mappings":"4OAaO,MAAMA,EAA+C,CAC3DC,MAAO,gBACPC,QAAUC,GAAqB,kBAAkBA,MAK5CC,wBACLC,OAAA,CAAA,kBAAA,IAAAC,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,+BAEDC,eAAsBC,EAAwBC,GAC7C,GAAa,OAATA,EAAe,OAAOT,EAC1B,MAAMU,EAASN,EAAc,aAAaK,QAC1C,IAAKC,EAAQ,OAAOV,EACpB,IAEC,aADkBU,KACPC,OACZ,CAAA,MACC,OAAOX,CACR,CACD,CCHA,MAAMY,EAAsC,CAAA,EAIrC,MAAMC,EACHC,GAAK,gBACLC,KAAO,gBACPC,SAAW,GAEHC,OACTC,OAER,WAAAC,CAAYF,GACXG,KAAKH,OAAS,IAAKL,KAAmBK,EACvC,CAEA,UAAMI,CAAKC,GACVF,KAAKF,aAAeK,EACnBD,EACAF,KAAKH,OAAOC,OACZlB,EACAQ,GAEDY,KAAKI,iBAAiBF,GACtBF,KAAKK,gBAAgBH,GACrBF,KAAKM,eAAeJ,GACpBF,KAAKO,oBAAoBL,EAC1B,CAEQ,gBAAAE,CAAiBF,GACxBA,EAAQE,iBAAiB,CACxBI,KAAM,gBACNC,KAAM,EACNC,MAAA,IACQC,SAASC,cAAc,KAE/BC,aAAc,CAACC,EAAOC,IAAY,MAAMA,QACxCC,UAAW,CACV,CAAEC,IAAK,KACP,CAAEA,IAAK,UACP,CAAEA,IAAK,OACP,CACCA,IAAK,OACLC,SAAWC,KACHA,EAAGC,MAAMC,eAAeC,SAAS,iBAAkB,CAAA,IAI7DC,SAAU,CAAEC,KAAM,CAAC,OAErB,CAEQ,eAAAnB,CAAgBH,GACvBA,EAAQG,gBAAgB,sBAAuB,KAC9C,MAAMoB,EAAKC,EAAWxB,EAAQyB,WAAYC,EAAS,kBACnD,QAAIH,IACHvB,EAAQ2B,SAASJ,IACV,IAIV,CAEQ,cAAAnB,CAAeJ,GACtBA,EAAQI,eAAe,CACtB,cAAe,IAAMJ,EAAQ4B,eAAe,wBAE9C,CAEQ,mBAAAvB,CAAoBL,GAI3BA,EAAQK,oBAAoB,CAC3Bb,GAAI,gBACJqC,MAAO,SACPC,KALA,uIAMAnD,MAAOmB,KAAKF,OAAOjB,MACnBC,QAASkB,KAAKF,OAAOhB,QAAQmD,EAAe,gBAC5CC,QAAS,sBACTC,SAAWC,GAAUC,EAAaD,EAAOR,EAAS,mBAEpD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"super-sub.mjs","sources":["../../src/plugins/super-sub/SuperSubLocale.ts","../../src/plugins/super-sub/SuperSubPlugin.ts"],"sourcesContent":["/**\n * Locale interface and default English locale for the SuperSubPlugin.\n */\n\n// --- Locale Interface ---\n\nexport interface SuperSubLocale {\n\treadonly superscriptLabel: string;\n\treadonly superscriptTooltip: (shortcut: string) => string;\n\treadonly subscriptLabel: string;\n\treadonly subscriptTooltip: (shortcut: string) => string;\n}\n\n// --- Default English Locale ---\n\nexport const SUPER_SUB_LOCALE_EN: SuperSubLocale = {\n\tsuperscriptLabel: 'Superscript',\n\tsuperscriptTooltip: (shortcut: string) => `Superscript (${shortcut})`,\n\tsubscriptLabel: 'Subscript',\n\tsubscriptTooltip: (shortcut: string) => `Subscript (${shortcut})`,\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: Record<string, () => Promise<{ default: SuperSubLocale }>> = import.meta.glob<{\n\tdefault: SuperSubLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadSuperSubLocale(lang: string): Promise<SuperSubLocale> {\n\tif (lang === 'en') return SUPER_SUB_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return SUPER_SUB_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn SUPER_SUB_LOCALE_EN;\n\t}\n}\n","/**\n * SuperSubPlugin: registers superscript and subscript inline marks with\n * MarkSpecs, toggle commands, keyboard shortcuts, toolbar buttons, and\n * a middleware that enforces mutual exclusivity between the two marks.\n *\n * Data-driven — each mark type is defined declaratively and all\n * registrations are derived from the same definition table.\n */\n\nimport { isMarkActive, toggleMark } from '../../commands/Commands.js';\nimport type { Mark } from '../../model/Document.js';\nimport type { ParseRule } from '../../model/ParseRule.js';\nimport type { SanitizeConfig } from '../../model/SanitizeConfig.js';\nimport { markType as mkType } from '../../model/TypeBrands.js';\nimport type { RemoveMarkStep, Step } from '../../state/Transaction.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { resolveLocale, toCommandName } from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { SUPER_SUB_LOCALE_EN, type SuperSubLocale, loadSuperSubLocale } from './SuperSubLocale.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\tsuperscript: Record<string, never>;\n\t\tsubscript: Record<string, never>;\n\t}\n}\n\n// --- Configuration ---\n\n/** Controls toolbar button visibility per mark. */\nexport interface SuperSubToolbarConfig {\n\treadonly superscript?: boolean;\n\treadonly subscript?: boolean;\n}\n\n/** Controls which marks are enabled and which toolbar buttons are shown. */\nexport interface SuperSubConfig {\n\treadonly superscript: boolean;\n\treadonly subscript: boolean;\n\treadonly toolbar?: SuperSubToolbarConfig;\n\treadonly locale?: SuperSubLocale;\n}\n\nconst DEFAULT_CONFIG: SuperSubConfig = {\n\tsuperscript: true,\n\tsubscript: true,\n};\n\n// --- Mark Definitions ---\n\ninterface MarkDefinition {\n\treadonly type: 'superscript' | 'subscript';\n\treadonly opposite: 'superscript' | 'subscript';\n\treadonly configKey: keyof Omit<SuperSubConfig, 'toolbar' | 'locale'>;\n\treadonly rank: number;\n\treadonly tag: string;\n\treadonly icon: string;\n\treadonly keyBinding: string;\n\treadonly toHTMLString: (content: string) => string;\n\treadonly parseHTML: readonly ParseRule[];\n\treadonly sanitize: SanitizeConfig;\n}\n\nconst SUPERSCRIPT_ICON: string = [\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">',\n\t'<path d=\"M16 7.41L11.41 12 16 16.59 14.59 18l-6-6 6-6z\"',\n\t' fill=\"none\"/>',\n\t'<path d=\"M9.64 7.64c.23-.5.36-1.05.36-1.64',\n\t' 0-2.21-1.79-4-4-4H2v14h4.36c2.34 0 4.24-1.9',\n\t' 4.24-4.24 0-1.6-.89-2.99-2.2-3.71zM4.5 4.5H6c.83',\n\t' 0 1.5.67 1.5 1.5S6.83 7.5 6 7.5H4.5v-3zm2 9H4.5v-3H6.5c.83',\n\t' 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z\" fill=\"none\"/>',\n\t'<path d=\"M15.97 3.84c0-.47.19-.91.53-1.21.34-.31.8-.49',\n\t' 1.3-.49.5 0 .95.18 1.28.48.32.3.5.7.51 1.15h1.59c-.02',\n\t'-.96-.43-1.83-1.13-2.42C19.36.77 18.45.44 17.5.44c-.88',\n\t' 0-1.74.28-2.39.8-.67.53-1.06 1.28-1.06 2.1 0 .76.34',\n\t' 1.47.93 1.97.59.49 1.41.84 2.32 1.15.7.24 1.26.5 1.62.8.35.3.53.64.53',\n\t' 1.02 0 .48-.2.93-.55 1.24-.36.3-.84.48-1.37.48-.55 0-1.04-.2-1.39-.54',\n\t'-.34-.33-.53-.8-.53-1.32h-1.58c.01 1.02.43 1.95 1.16 2.57.72.62 1.67.96',\n\t' 2.67.96.92 0 1.81-.3 2.46-.84.67-.56 1.04-1.33 1.04-2.18 0-.81-.36-1.56',\n\t'-.99-2.08-.62-.51-1.48-.88-2.43-1.2-.67-.23-1.2-.47-1.52-.75-.32-.27-.46',\n\t'-.59-.46-.94z\"/>',\n\t'<path d=\"M5.88 20h2.66l3.4-5.42L15.3 20h2.67l-4.73-7.38',\n\t' 4.37-6.62h-2.6l-3.07 4.98L8.92 6h-2.6l4.26 6.58z\"/>',\n\t'</svg>',\n].join('');\n\nconst SUBSCRIPT_ICON: string = [\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">',\n\t'<path d=\"M15.97 16.84c0-.47.19-.91.53-1.21.34-.31.8-.49',\n\t' 1.3-.49.5 0 .95.18 1.28.48.32.3.5.7.51 1.15h1.59c-.02',\n\t'-.96-.43-1.83-1.13-2.42-.7-.58-1.61-.91-2.56-.91-.88',\n\t' 0-1.74.28-2.39.8-.67.53-1.06 1.28-1.06 2.1 0 .76.34',\n\t' 1.47.93 1.97.59.49 1.41.84 2.32 1.15.7.24 1.26.5 1.62.8.35.3.53.64.53',\n\t' 1.02 0 .48-.2.93-.55 1.24-.36.3-.84.48-1.37.48-.55 0-1.04-.2-1.39-.54',\n\t'-.34-.33-.53-.8-.53-1.32h-1.58c.01 1.02.43 1.95 1.16 2.57.72.62 1.67.96',\n\t' 2.67.96.92 0 1.81-.3 2.46-.84.67-.56 1.04-1.33 1.04-2.18 0-.81-.36-1.56',\n\t'-.99-2.08-.62-.51-1.48-.88-2.43-1.2-.67-.23-1.2-.47-1.52-.75-.32-.27-.46',\n\t'-.59-.46-.94z\"/>',\n\t'<path d=\"M5.88 18h2.66l3.4-5.42L15.3 18h2.67l-4.73-7.38',\n\t' 4.37-6.62h-2.6l-3.07 4.98L8.92 4h-2.6l4.26 6.58z\"/>',\n\t'</svg>',\n].join('');\n\nconst MARK_DEFINITIONS: readonly MarkDefinition[] = [\n\t{\n\t\ttype: 'superscript',\n\t\topposite: 'subscript',\n\t\tconfigKey: 'superscript',\n\t\trank: 4,\n\t\ttag: 'sup',\n\t\ticon: SUPERSCRIPT_ICON,\n\t\tkeyBinding: 'Mod-.',\n\t\ttoHTMLString: (content) => `<sup>${content}</sup>`,\n\t\tparseHTML: [{ tag: 'sup' }],\n\t\tsanitize: { tags: ['sup'] },\n\t},\n\t{\n\t\ttype: 'subscript',\n\t\topposite: 'superscript',\n\t\tconfigKey: 'subscript',\n\t\trank: 4,\n\t\ttag: 'sub',\n\t\ticon: SUBSCRIPT_ICON,\n\t\tkeyBinding: 'Mod-,',\n\t\ttoHTMLString: (content) => `<sub>${content}</sub>`,\n\t\tparseHTML: [{ tag: 'sub' }],\n\t\tsanitize: { tags: ['sub'] },\n\t},\n];\n\n// --- Plugin ---\n\nexport class SuperSubPlugin implements Plugin {\n\treadonly id = 'super-sub';\n\treadonly name = 'Superscript & Subscript';\n\treadonly priority = 23;\n\n\tprivate readonly config: SuperSubConfig;\n\tprivate locale!: SuperSubLocale;\n\n\tconstructor(config?: Partial<SuperSubConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tSUPER_SUB_LOCALE_EN,\n\t\t\tloadSuperSubLocale,\n\t\t);\n\n\t\tconst enabledMarks: MarkDefinition[] = MARK_DEFINITIONS.filter(\n\t\t\t(def) => this.config[def.configKey],\n\t\t);\n\n\t\tfor (const def of enabledMarks) {\n\t\t\tthis.registerMark(context, def);\n\t\t}\n\n\t\tthis.registerKeymaps(context, enabledMarks);\n\t\tthis.registerExclusivityMiddleware(context, enabledMarks);\n\t\tthis.registerDisabledToolbarItems(context);\n\t}\n\n\tprivate registerMark(context: PluginContext, def: MarkDefinition): void {\n\t\tconst commandName: string = toCommandName(def.type);\n\t\tconst toolbarVisible: boolean = this.isToolbarVisible(def.configKey);\n\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: def.type,\n\t\t\trank: def.rank,\n\t\t\ttoDOM() {\n\t\t\t\treturn document.createElement(def.tag);\n\t\t\t},\n\t\t\ttoHTMLString: (_mark, content) => def.toHTMLString(content),\n\t\t\tparseHTML: def.parseHTML,\n\t\t\tsanitize: def.sanitize,\n\t\t});\n\n\t\tcontext.registerCommand(commandName, () => {\n\t\t\tconst tr = toggleMark(context.getState(), mkType(def.type));\n\t\t\tif (tr) {\n\t\t\t\tcontext.dispatch(tr);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\n\t\tif (toolbarVisible) {\n\t\t\tconst label: string =\n\t\t\t\tdef.type === 'superscript' ? this.locale.superscriptLabel : this.locale.subscriptLabel;\n\t\t\tconst tooltip: string =\n\t\t\t\tdef.type === 'superscript'\n\t\t\t\t\t? this.locale.superscriptTooltip(formatShortcut(def.keyBinding))\n\t\t\t\t\t: this.locale.subscriptTooltip(formatShortcut(def.keyBinding));\n\t\t\tcontext.registerToolbarItem({\n\t\t\t\tid: def.type,\n\t\t\t\tgroup: 'format',\n\t\t\t\ticon: def.icon,\n\t\t\t\tlabel,\n\t\t\t\ttooltip,\n\t\t\t\tcommand: commandName,\n\t\t\t\tisActive: (state) => isMarkActive(state, mkType(def.type)),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate registerKeymaps(context: PluginContext, marks: readonly MarkDefinition[]): void {\n\t\tconst keymap: Record<string, () => boolean> = {};\n\t\tfor (const def of marks) {\n\t\t\tconst commandName: string = toCommandName(def.type);\n\t\t\tkeymap[def.keyBinding] = () => context.executeCommand(commandName);\n\t\t}\n\t\tif (Object.keys(keymap).length > 0) {\n\t\t\tcontext.registerKeymap(keymap);\n\t\t}\n\t}\n\n\t/**\n\t * Ensures superscript and subscript are mutually exclusive.\n\t * When an addMark step for one type is found, a removeMark step\n\t * for the opposite type is injected. For stored marks, the opposite\n\t * mark is filtered out.\n\t */\n\tprivate registerExclusivityMiddleware(\n\t\tcontext: PluginContext,\n\t\tenabledMarks: readonly MarkDefinition[],\n\t): void {\n\t\tconst bothEnabled: boolean =\n\t\t\tenabledMarks.some((d) => d.type === 'superscript') &&\n\t\t\tenabledMarks.some((d) => d.type === 'subscript');\n\n\t\tif (!bothEnabled) return;\n\n\t\tcontext.registerMiddleware(\n\t\t\t(tr, _state, next) => {\n\t\t\t\tlet patched = false;\n\n\t\t\t\t// Handle addMark steps: inject removeMark for the opposite type\n\t\t\t\tconst patchedSteps: Step[] = [];\n\t\t\t\tfor (const step of tr.steps) {\n\t\t\t\t\tif (step.type !== 'addMark') {\n\t\t\t\t\t\tpatchedSteps.push(step);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst markName: string = step.mark.type;\n\t\t\t\t\tconst def: MarkDefinition | undefined = MARK_DEFINITIONS.find((d) => d.type === markName);\n\t\t\t\t\tif (!def) {\n\t\t\t\t\t\tpatchedSteps.push(step);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tpatched = true;\n\t\t\t\t\tconst removeStep: RemoveMarkStep = {\n\t\t\t\t\t\ttype: 'removeMark',\n\t\t\t\t\t\tblockId: step.blockId,\n\t\t\t\t\t\tfrom: step.from,\n\t\t\t\t\t\tto: step.to,\n\t\t\t\t\t\tmark: { type: mkType(def.opposite) },\n\t\t\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t\t\t};\n\t\t\t\t\tpatchedSteps.push(removeStep, step);\n\t\t\t\t}\n\n\t\t\t\t// Handle stored marks: remove the opposite mark\n\t\t\t\tlet storedMarksAfter: readonly Mark[] | null = tr.storedMarksAfter;\n\t\t\t\tif (storedMarksAfter) {\n\t\t\t\t\tconst hasSup: boolean = storedMarksAfter.some((m) => m.type === 'superscript');\n\t\t\t\t\tconst hasSub: boolean = storedMarksAfter.some((m) => m.type === 'subscript');\n\n\t\t\t\t\tif (hasSup && hasSub) {\n\t\t\t\t\t\t// Keep the one that was most recently added (last in array)\n\t\t\t\t\t\tconst lastSupIdx: number = storedMarksAfter.findLastIndex(\n\t\t\t\t\t\t\t(m) => m.type === 'superscript',\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst lastSubIdx: number = storedMarksAfter.findLastIndex(\n\t\t\t\t\t\t\t(m) => m.type === 'subscript',\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst removeType: string = lastSupIdx > lastSubIdx ? 'subscript' : 'superscript';\n\n\t\t\t\t\t\tstoredMarksAfter = storedMarksAfter.filter((m) => m.type !== removeType);\n\t\t\t\t\t\tpatched = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tnext(patched ? { ...tr, steps: patchedSteps, storedMarksAfter } : tr);\n\t\t\t},\n\t\t\t{ name: 'super-sub:exclusivity' },\n\t\t);\n\t}\n\n\t/**\n\t * Registers disabled toolbar buttons for marks whose feature is disabled\n\t * but whose toolbar button is explicitly requested.\n\t */\n\tprivate registerDisabledToolbarItems(context: PluginContext): void {\n\t\tif (!this.config.toolbar) return;\n\n\t\tfor (const def of MARK_DEFINITIONS) {\n\t\t\tconst featureEnabled: boolean = this.config[def.configKey];\n\t\t\tconst toolbarVisible: boolean = this.config.toolbar[def.configKey] ?? true;\n\n\t\t\tif (!featureEnabled && toolbarVisible) {\n\t\t\t\tconst label: string =\n\t\t\t\t\tdef.type === 'superscript' ? this.locale.superscriptLabel : this.locale.subscriptLabel;\n\t\t\t\tcontext.registerToolbarItem({\n\t\t\t\t\tid: def.type,\n\t\t\t\t\tgroup: 'format',\n\t\t\t\t\ticon: def.icon,\n\t\t\t\t\tlabel,\n\t\t\t\t\tcommand: toCommandName(def.type),\n\t\t\t\t\tisEnabled: () => false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate isToolbarVisible(configKey: keyof Omit<SuperSubConfig, 'toolbar' | 'locale'>): boolean {\n\t\tif (!this.config.toolbar) return true;\n\t\treturn this.config.toolbar[configKey] ?? true;\n\t}\n}\n"],"names":["SUPER_SUB_LOCALE_EN","superscriptLabel","superscriptTooltip","shortcut","subscriptLabel","subscriptTooltip","localeModules","assign","import","async","loadSuperSubLocale","lang","loader","default","DEFAULT_CONFIG","superscript","subscript","MARK_DEFINITIONS","type","opposite","configKey","rank","tag","icon","join","keyBinding","toHTMLString","content","parseHTML","sanitize","tags","SuperSubPlugin","id","name","priority","config","locale","constructor","this","init","context","resolveLocale","enabledMarks","filter","def","registerMark","registerKeymaps","registerExclusivityMiddleware","registerDisabledToolbarItems","commandName","toCommandName","toolbarVisible","isToolbarVisible","registerMarkSpec","toDOM","document","createElement","_mark","registerCommand","tr","toggleMark","getState","mkType","dispatch","label","tooltip","formatShortcut","registerToolbarItem","group","command","isActive","state","isMarkActive","marks","keymap","executeCommand","Object","keys","length","registerKeymap","some","d","registerMiddleware","_state","next","patched","patchedSteps","step","steps","push","markName","mark","find","removeStep","blockId","from","to","path","storedMarksAfter","hasSup","m","hasSub","removeType","findLastIndex","toolbar","featureEnabled","isEnabled"],"mappings":"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"}
|