@notectl/core 2.2.1 → 2.2.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 +2 -0
- package/dist/chunks/AlignmentPlugin-h6sx-yIf.mjs +2 -0
- package/dist/chunks/AlignmentPlugin-h6sx-yIf.mjs.map +1 -0
- package/dist/chunks/AttrRegistry-DcDVyzLm.mjs +2 -0
- package/dist/chunks/AttrRegistry-DcDVyzLm.mjs.map +1 -0
- package/dist/chunks/AttributedMarkCommands-D4W2Jgpj.mjs +2 -0
- package/dist/chunks/AttributedMarkCommands-D4W2Jgpj.mjs.map +1 -0
- package/dist/chunks/BidiIsolationPlugin-Bm3h9J15.mjs +2 -0
- package/dist/chunks/BidiIsolationPlugin-Bm3h9J15.mjs.map +1 -0
- package/dist/chunks/BlockInsertion-6rR9tIGP.mjs +2 -0
- package/dist/chunks/BlockInsertion-6rR9tIGP.mjs.map +1 -0
- package/dist/chunks/BlockTypePickerRegistry-BTET9jM-.mjs +2 -0
- package/dist/chunks/BlockTypePickerRegistry-BTET9jM-.mjs.map +1 -0
- package/dist/chunks/BlockquotePlugin-CxrCA0vY.mjs +2 -0
- package/dist/chunks/BlockquotePlugin-CxrCA0vY.mjs.map +1 -0
- package/dist/chunks/CaretNavigationPlugin-Bb7W_FMg.mjs +2 -0
- package/dist/chunks/CaretNavigationPlugin-Bb7W_FMg.mjs.map +1 -0
- package/dist/chunks/CodeBlockPlugin-CcB0WaIz.mjs +2 -0
- package/dist/chunks/CodeBlockPlugin-CcB0WaIz.mjs.map +1 -0
- package/dist/chunks/ColorGrid-CXRdpP_n.mjs +2 -0
- package/dist/chunks/ColorGrid-CXRdpP_n.mjs.map +1 -0
- package/dist/chunks/ColorPickerPopup-C_74bqid.mjs +2 -0
- package/dist/chunks/ColorPickerPopup-C_74bqid.mjs.map +1 -0
- package/dist/chunks/ColorValidation-DAijTjG9.mjs +2 -0
- package/dist/chunks/ColorValidation-DAijTjG9.mjs.map +1 -0
- package/dist/chunks/Commands-BIIpx_Zd.mjs +2 -0
- package/dist/chunks/Commands-BIIpx_Zd.mjs.map +1 -0
- package/dist/chunks/Decoration-ZeyVfwJB.mjs +2 -0
- package/dist/chunks/Decoration-ZeyVfwJB.mjs.map +1 -0
- package/dist/chunks/DirectionDetection-C7XE0nxW.mjs +2 -0
- package/dist/chunks/DirectionDetection-C7XE0nxW.mjs.map +1 -0
- package/dist/chunks/DirectionIcons-Bbawl9ei.mjs +2 -0
- package/dist/chunks/DirectionIcons-Bbawl9ei.mjs.map +1 -0
- package/dist/chunks/Document-r7vLOAGA.mjs +2 -0
- package/dist/chunks/Document-r7vLOAGA.mjs.map +1 -0
- package/dist/chunks/DocumentParser-CcTSeT1B.mjs +2 -0
- package/dist/chunks/DocumentParser-CcTSeT1B.mjs.map +1 -0
- package/dist/chunks/DomUtils-Bf7JLFlx.mjs +2 -0
- package/dist/chunks/DomUtils-Bf7JLFlx.mjs.map +1 -0
- package/dist/chunks/FontPlugin-1VYDwETg.mjs +2 -0
- package/dist/chunks/FontPlugin-1VYDwETg.mjs.map +1 -0
- package/dist/chunks/FontSizePlugin-L1uDVsKY.mjs +2 -0
- package/dist/chunks/FontSizePlugin-L1uDVsKY.mjs.map +1 -0
- package/dist/chunks/FormulaPlugin-66Cc9sH2.mjs +2 -0
- package/dist/chunks/FormulaPlugin-66Cc9sH2.mjs.map +1 -0
- package/dist/chunks/GapCursorNavigation-ycNzuQVH.mjs +2 -0
- package/dist/chunks/GapCursorNavigation-ycNzuQVH.mjs.map +1 -0
- package/dist/chunks/GapCursorPlugin-B29ieXel.mjs +2 -0
- package/dist/chunks/GapCursorPlugin-B29ieXel.mjs.map +1 -0
- package/dist/chunks/HTMLUtils-C6B4UT00.mjs +2 -0
- package/dist/chunks/HTMLUtils-C6B4UT00.mjs.map +1 -0
- package/dist/chunks/HardBreakPlugin-9DOyCyyM.mjs +2 -0
- package/dist/chunks/HardBreakPlugin-9DOyCyyM.mjs.map +1 -0
- package/dist/chunks/HeadingPlugin-SICF6Tm0.mjs +2 -0
- package/dist/chunks/HeadingPlugin-SICF6Tm0.mjs.map +1 -0
- package/dist/chunks/HighlightPlugin-B3b_qe68.mjs +2 -0
- package/dist/chunks/HighlightPlugin-B3b_qe68.mjs.map +1 -0
- package/dist/chunks/HorizontalRulePlugin-BrFlrpmb.mjs +2 -0
- package/dist/chunks/HorizontalRulePlugin-BrFlrpmb.mjs.map +1 -0
- package/dist/chunks/ImagePlugin-eRVtFFou.mjs +2 -0
- package/dist/chunks/ImagePlugin-eRVtFFou.mjs.map +1 -0
- package/dist/chunks/InlineCodePlugin-Cj1EZ3x2.mjs +2 -0
- package/dist/chunks/InlineCodePlugin-Cj1EZ3x2.mjs.map +1 -0
- package/dist/chunks/InlineStyleMarkSpec-4R6DC7ij.mjs +2 -0
- package/dist/chunks/InlineStyleMarkSpec-4R6DC7ij.mjs.map +1 -0
- package/dist/chunks/KeyboardNav-D0my3wuy.mjs +2 -0
- package/dist/chunks/KeyboardNav-D0my3wuy.mjs.map +1 -0
- package/dist/chunks/LinkPlugin-B_ysjORS.mjs +2 -0
- package/dist/chunks/LinkPlugin-B_ysjORS.mjs.map +1 -0
- package/dist/chunks/ListPlugin-C0BV8CnQ.mjs +2 -0
- package/dist/chunks/ListPlugin-C0BV8CnQ.mjs.map +1 -0
- package/dist/chunks/NavigationQueries-Bt4zZ17v.mjs +2 -0
- package/dist/chunks/NavigationQueries-Bt4zZ17v.mjs.map +1 -0
- package/dist/chunks/NodeResolver-ChgLF_IP.mjs +2 -0
- package/dist/chunks/NodeResolver-ChgLF_IP.mjs.map +1 -0
- package/dist/chunks/NodeSelectionCommands-Dj4VxLdD.mjs +2 -0
- package/dist/chunks/NodeSelectionCommands-Dj4VxLdD.mjs.map +1 -0
- package/dist/chunks/NodeSpecPatching-B_yLknTl.mjs +2 -0
- package/dist/chunks/NodeSpecPatching-B_yLknTl.mjs.map +1 -0
- package/dist/chunks/Platform-ByobkiCc.mjs +2 -0
- package/dist/chunks/Platform-ByobkiCc.mjs.map +1 -0
- package/dist/chunks/PluginHelpers-D4quRJ5a.mjs +2 -0
- package/dist/chunks/PluginHelpers-D4quRJ5a.mjs.map +1 -0
- package/dist/chunks/PopupKeyboardPatterns-tUrT9TyV.mjs +2 -0
- package/dist/chunks/PopupKeyboardPatterns-tUrT9TyV.mjs.map +1 -0
- package/dist/chunks/PopupManager-CyOfZUab.mjs +2 -0
- package/dist/chunks/PopupManager-CyOfZUab.mjs.map +1 -0
- package/dist/chunks/PopupPositioning-DtUrY9bh.mjs +2 -0
- package/dist/chunks/PopupPositioning-DtUrY9bh.mjs.map +1 -0
- package/dist/chunks/PrintPlugin-CXDFFzWB.mjs +2 -0
- package/dist/chunks/PrintPlugin-CXDFFzWB.mjs.map +1 -0
- package/dist/chunks/PrintTypes-WdtgSj74.mjs +2 -0
- package/dist/chunks/PrintTypes-WdtgSj74.mjs.map +1 -0
- package/dist/chunks/RangeIterator-o8v3msQe.mjs +2 -0
- package/dist/chunks/RangeIterator-o8v3msQe.mjs.map +1 -0
- package/dist/chunks/Selection-HYoVFpAx.mjs +2 -0
- package/dist/chunks/Selection-HYoVFpAx.mjs.map +1 -0
- package/dist/chunks/SelectionSync-BSHIw1EE.mjs +2 -0
- package/dist/chunks/SelectionSync-BSHIw1EE.mjs.map +1 -0
- package/dist/chunks/ShortcutFormatting-TwiufqeV.mjs +2 -0
- package/dist/chunks/ShortcutFormatting-TwiufqeV.mjs.map +1 -0
- package/dist/chunks/SimpleMark-Bdqjcz0G.mjs +2 -0
- package/dist/chunks/SimpleMark-Bdqjcz0G.mjs.map +1 -0
- package/dist/chunks/SmartPastePlugin-BhkoH03E.mjs +2 -0
- package/dist/chunks/SmartPastePlugin-BhkoH03E.mjs.map +1 -0
- package/dist/chunks/StrikethroughPlugin-DRuwEZhu.mjs +2 -0
- package/dist/chunks/StrikethroughPlugin-DRuwEZhu.mjs.map +1 -0
- package/dist/chunks/StyleRuntime-BAutwDZT.mjs +2 -0
- package/dist/chunks/StyleRuntime-BAutwDZT.mjs.map +1 -0
- package/dist/chunks/SuperSubPlugin-IZ_x8GS-.mjs +2 -0
- package/dist/chunks/SuperSubPlugin-IZ_x8GS-.mjs.map +1 -0
- package/dist/chunks/SyntaxTokenTypes-BUCOMtL8.mjs +2 -0
- package/dist/chunks/SyntaxTokenTypes-BUCOMtL8.mjs.map +1 -0
- package/dist/chunks/TablePlugin-CRp4qSZE.mjs +2 -0
- package/dist/chunks/TablePlugin-CRp4qSZE.mjs.map +1 -0
- package/dist/chunks/TextColorPlugin-CViEiYZk.mjs +2 -0
- package/dist/chunks/TextColorPlugin-CViEiYZk.mjs.map +1 -0
- package/dist/chunks/TextDirectionAutoPlugin-CzWJjrvG.mjs +2 -0
- package/dist/chunks/TextDirectionAutoPlugin-CzWJjrvG.mjs.map +1 -0
- package/dist/chunks/TextDirectionPlugin-CQGkaS2s.mjs +2 -0
- package/dist/chunks/TextDirectionPlugin-CQGkaS2s.mjs.map +1 -0
- package/dist/chunks/TextDirectionService-OFOU6r_s.mjs +2 -0
- package/dist/chunks/TextDirectionService-OFOU6r_s.mjs.map +1 -0
- package/dist/chunks/TextFormattingPlugin-CpyZgtLi.mjs +2 -0
- package/dist/chunks/TextFormattingPlugin-CpyZgtLi.mjs.map +1 -0
- package/dist/chunks/ToolbarPlugin-B5UUc6dY.mjs +2 -0
- package/dist/chunks/ToolbarPlugin-B5UUc6dY.mjs.map +1 -0
- package/dist/chunks/TypeBrands-Ch9856Gb.mjs +2 -0
- package/dist/chunks/TypeBrands-Ch9856Gb.mjs.map +1 -0
- package/dist/chunks/TypedKeys-CA4bfw9O.mjs +2 -0
- package/dist/chunks/TypedKeys-CA4bfw9O.mjs.map +1 -0
- package/dist/chunks/VideoPlugin-mXIDODzC.mjs +2 -0
- package/dist/chunks/VideoPlugin-mXIDODzC.mjs.map +1 -0
- package/dist/chunks/WordBoundary-DxeMBRyP.mjs +2 -0
- package/dist/chunks/WordBoundary-DxeMBRyP.mjs.map +1 -0
- package/dist/chunks/XmlDetector-D7TQpw-e.mjs +2 -0
- package/dist/chunks/XmlDetector-D7TQpw-e.mjs.map +1 -0
- package/dist/chunks/XmlPatterns-RN32-0ob.mjs +2 -0
- package/dist/chunks/XmlPatterns-RN32-0ob.mjs.map +1 -0
- package/dist/chunks/XmlSupport-BYiRwlkK.mjs +2 -0
- package/dist/chunks/XmlSupport-BYiRwlkK.mjs.map +1 -0
- package/dist/chunks/ar--Isa9OHJ.mjs +2 -0
- package/dist/chunks/ar--Isa9OHJ.mjs.map +1 -0
- package/dist/chunks/ar--O0A9OTR.mjs +2 -0
- package/dist/chunks/ar--O0A9OTR.mjs.map +1 -0
- package/dist/chunks/ar-0g2bmXTn.mjs +2 -0
- package/dist/chunks/ar-0g2bmXTn.mjs.map +1 -0
- package/dist/chunks/ar-4b8e2YSc.mjs +2 -0
- package/dist/chunks/ar-4b8e2YSc.mjs.map +1 -0
- package/dist/chunks/ar-B03uY4xr.mjs +2 -0
- package/dist/chunks/ar-B03uY4xr.mjs.map +1 -0
- package/dist/chunks/ar-BAfInw85.mjs +2 -0
- package/dist/chunks/ar-BAfInw85.mjs.map +1 -0
- package/dist/chunks/ar-BRX5E_Pw.mjs +2 -0
- package/dist/chunks/ar-BRX5E_Pw.mjs.map +1 -0
- package/dist/chunks/ar-BTShmP2E.mjs +2 -0
- package/dist/chunks/ar-BTShmP2E.mjs.map +1 -0
- package/dist/chunks/ar-BWOue6jG.mjs +2 -0
- package/dist/chunks/ar-BWOue6jG.mjs.map +1 -0
- package/dist/chunks/ar-Bdmunk5h.mjs +2 -0
- package/dist/chunks/ar-Bdmunk5h.mjs.map +1 -0
- package/dist/chunks/ar-BwaoCUVN.mjs +2 -0
- package/dist/chunks/ar-BwaoCUVN.mjs.map +1 -0
- package/dist/chunks/ar-BzqAYGER.mjs +2 -0
- package/dist/chunks/ar-BzqAYGER.mjs.map +1 -0
- package/dist/chunks/ar-C9lO1jsY.mjs +2 -0
- package/dist/chunks/ar-C9lO1jsY.mjs.map +1 -0
- package/dist/chunks/ar-CMXjVzFx.mjs +2 -0
- package/dist/chunks/ar-CMXjVzFx.mjs.map +1 -0
- package/dist/chunks/ar-CR6UdFL9.mjs +2 -0
- package/dist/chunks/ar-CR6UdFL9.mjs.map +1 -0
- package/dist/chunks/ar-CrOb0jL2.mjs +2 -0
- package/dist/chunks/ar-CrOb0jL2.mjs.map +1 -0
- package/dist/chunks/ar-Ctrv6cIi.mjs +2 -0
- package/dist/chunks/ar-Ctrv6cIi.mjs.map +1 -0
- package/dist/chunks/ar-Cy_77yRf.mjs +2 -0
- package/dist/chunks/ar-Cy_77yRf.mjs.map +1 -0
- package/dist/chunks/ar-D1jFXqLJ.mjs +2 -0
- package/dist/chunks/ar-D1jFXqLJ.mjs.map +1 -0
- package/dist/chunks/ar-DahJwMI9.mjs +2 -0
- package/dist/chunks/ar-DahJwMI9.mjs.map +1 -0
- package/dist/chunks/ar-Dcl3kgtd.mjs +2 -0
- package/dist/chunks/ar-Dcl3kgtd.mjs.map +1 -0
- package/dist/chunks/ar-Dx2lO0Nm.mjs +2 -0
- package/dist/chunks/ar-Dx2lO0Nm.mjs.map +1 -0
- package/dist/chunks/ar-NV_puwI2.mjs +2 -0
- package/dist/chunks/ar-NV_puwI2.mjs.map +1 -0
- package/dist/chunks/ar-Uzo1Azdw.mjs +2 -0
- package/dist/chunks/ar-Uzo1Azdw.mjs.map +1 -0
- package/dist/chunks/ar-XmSFrtmd.mjs +2 -0
- package/dist/chunks/ar-XmSFrtmd.mjs.map +1 -0
- package/dist/chunks/ar-jbplYWkC.mjs +2 -0
- package/dist/chunks/ar-jbplYWkC.mjs.map +1 -0
- package/dist/chunks/ar-sGZ-oZqB.mjs +2 -0
- package/dist/chunks/ar-sGZ-oZqB.mjs.map +1 -0
- package/dist/chunks/color-picker-C9B2rYw-.mjs +2 -0
- package/dist/chunks/color-picker-C9B2rYw-.mjs.map +1 -0
- package/dist/chunks/de-B8-w9gPi.mjs +2 -0
- package/dist/chunks/de-B8-w9gPi.mjs.map +1 -0
- package/dist/chunks/de-B9zSHWqY.mjs +2 -0
- package/dist/chunks/de-B9zSHWqY.mjs.map +1 -0
- package/dist/chunks/de-BX4y4PlH.mjs +2 -0
- package/dist/chunks/de-BX4y4PlH.mjs.map +1 -0
- package/dist/chunks/de-BXQBXxFJ.mjs +2 -0
- package/dist/chunks/de-BXQBXxFJ.mjs.map +1 -0
- package/dist/chunks/de-BcPntcnr.mjs +2 -0
- package/dist/chunks/de-BcPntcnr.mjs.map +1 -0
- package/dist/chunks/de-BdD3DpUB.mjs +2 -0
- package/dist/chunks/de-BdD3DpUB.mjs.map +1 -0
- package/dist/chunks/de-Bwxlcuee.mjs +2 -0
- package/dist/chunks/de-Bwxlcuee.mjs.map +1 -0
- package/dist/chunks/de-BxQIt_1Y.mjs +2 -0
- package/dist/chunks/de-BxQIt_1Y.mjs.map +1 -0
- package/dist/chunks/de-C--bRmjW.mjs +2 -0
- package/dist/chunks/de-C--bRmjW.mjs.map +1 -0
- package/dist/chunks/de-C-Yf378-.mjs +2 -0
- package/dist/chunks/de-C-Yf378-.mjs.map +1 -0
- package/dist/chunks/de-C7uehgMu.mjs +2 -0
- package/dist/chunks/de-C7uehgMu.mjs.map +1 -0
- package/dist/chunks/de-C9ZhDqPi.mjs +2 -0
- package/dist/chunks/de-C9ZhDqPi.mjs.map +1 -0
- package/dist/chunks/de-CHcv_Vmf.mjs +2 -0
- package/dist/chunks/de-CHcv_Vmf.mjs.map +1 -0
- package/dist/chunks/de-CTzAMkXC.mjs +2 -0
- package/dist/chunks/de-CTzAMkXC.mjs.map +1 -0
- package/dist/chunks/de-CaeEIyzV.mjs +2 -0
- package/dist/chunks/de-CaeEIyzV.mjs.map +1 -0
- package/dist/chunks/de-DHs9i4af.mjs +2 -0
- package/dist/chunks/de-DHs9i4af.mjs.map +1 -0
- package/dist/chunks/de-DN-e6G5A.mjs +2 -0
- package/dist/chunks/de-DN-e6G5A.mjs.map +1 -0
- package/dist/chunks/de-DViI26lG.mjs +2 -0
- package/dist/chunks/de-DViI26lG.mjs.map +1 -0
- package/dist/chunks/de-DY3obIAF.mjs +2 -0
- package/dist/chunks/de-DY3obIAF.mjs.map +1 -0
- package/dist/chunks/de-DcMhfRBu.mjs +2 -0
- package/dist/chunks/de-DcMhfRBu.mjs.map +1 -0
- package/dist/chunks/de-DiPz7abS.mjs +2 -0
- package/dist/chunks/de-DiPz7abS.mjs.map +1 -0
- package/dist/chunks/de-Dl4QFHMa.mjs +2 -0
- package/dist/chunks/de-Dl4QFHMa.mjs.map +1 -0
- package/dist/chunks/de-JhGflzS5.mjs +2 -0
- package/dist/chunks/de-JhGflzS5.mjs.map +1 -0
- package/dist/chunks/de-XCCpWyg0.mjs +2 -0
- package/dist/chunks/de-XCCpWyg0.mjs.map +1 -0
- package/dist/chunks/de-e6J6nvAD.mjs +2 -0
- package/dist/chunks/de-e6J6nvAD.mjs.map +1 -0
- package/dist/chunks/de-i95F9SDy.mjs +2 -0
- package/dist/chunks/de-i95F9SDy.mjs.map +1 -0
- package/dist/chunks/de-uKR7koQe.mjs +2 -0
- package/dist/chunks/de-uKR7koQe.mjs.map +1 -0
- package/dist/chunks/es-B0Za939C.mjs +2 -0
- package/dist/chunks/es-B0Za939C.mjs.map +1 -0
- package/dist/chunks/es-B8K3Yvf3.mjs +2 -0
- package/dist/chunks/es-B8K3Yvf3.mjs.map +1 -0
- package/dist/chunks/es-BIXm2Coj.mjs +2 -0
- package/dist/chunks/es-BIXm2Coj.mjs.map +1 -0
- package/dist/chunks/es-BJHF95J_.mjs +2 -0
- package/dist/chunks/es-BJHF95J_.mjs.map +1 -0
- package/dist/chunks/es-BMm9kqjC.mjs +2 -0
- package/dist/chunks/es-BMm9kqjC.mjs.map +1 -0
- package/dist/chunks/es-BQweZX6P.mjs +2 -0
- package/dist/chunks/es-BQweZX6P.mjs.map +1 -0
- package/dist/chunks/es-BdpTTRuX.mjs +2 -0
- package/dist/chunks/es-BdpTTRuX.mjs.map +1 -0
- package/dist/chunks/es-Bv7bDbMp.mjs +2 -0
- package/dist/chunks/es-Bv7bDbMp.mjs.map +1 -0
- package/dist/chunks/es-C7uVqFYr.mjs +2 -0
- package/dist/chunks/es-C7uVqFYr.mjs.map +1 -0
- package/dist/chunks/es-CCQFu1t1.mjs +2 -0
- package/dist/chunks/es-CCQFu1t1.mjs.map +1 -0
- package/dist/chunks/es-CM55WeEN.mjs +2 -0
- package/dist/chunks/es-CM55WeEN.mjs.map +1 -0
- package/dist/chunks/es-CUKJujcb.mjs +2 -0
- package/dist/chunks/es-CUKJujcb.mjs.map +1 -0
- package/dist/chunks/es-CXuMz87y.mjs +2 -0
- package/dist/chunks/es-CXuMz87y.mjs.map +1 -0
- package/dist/chunks/es-CgMfhkJJ.mjs +2 -0
- package/dist/chunks/es-CgMfhkJJ.mjs.map +1 -0
- package/dist/chunks/es-CtOtKQCP.mjs +2 -0
- package/dist/chunks/es-CtOtKQCP.mjs.map +1 -0
- package/dist/chunks/es-DD01rZ6N.mjs +2 -0
- package/dist/chunks/es-DD01rZ6N.mjs.map +1 -0
- package/dist/chunks/es-DDoqchUq.mjs +2 -0
- package/dist/chunks/es-DDoqchUq.mjs.map +1 -0
- package/dist/chunks/es-DFUVd7eO.mjs +2 -0
- package/dist/chunks/es-DFUVd7eO.mjs.map +1 -0
- package/dist/chunks/es-DFokqQst.mjs +2 -0
- package/dist/chunks/es-DFokqQst.mjs.map +1 -0
- package/dist/chunks/es-DHxdoEzR.mjs +2 -0
- package/dist/chunks/es-DHxdoEzR.mjs.map +1 -0
- package/dist/chunks/es-DehVGwQ8.mjs +2 -0
- package/dist/chunks/es-DehVGwQ8.mjs.map +1 -0
- package/dist/chunks/es-DrJyl38L.mjs +2 -0
- package/dist/chunks/es-DrJyl38L.mjs.map +1 -0
- package/dist/chunks/es-fTW0TkYV.mjs +2 -0
- package/dist/chunks/es-fTW0TkYV.mjs.map +1 -0
- package/dist/chunks/es-kfKiqpyD.mjs +2 -0
- package/dist/chunks/es-kfKiqpyD.mjs.map +1 -0
- package/dist/chunks/es-nRLq7bgP.mjs +2 -0
- package/dist/chunks/es-nRLq7bgP.mjs.map +1 -0
- package/dist/chunks/es-paXY7HFt.mjs +2 -0
- package/dist/chunks/es-paXY7HFt.mjs.map +1 -0
- package/dist/chunks/es-xuahrvJN.mjs +2 -0
- package/dist/chunks/es-xuahrvJN.mjs.map +1 -0
- package/dist/chunks/fonts-DQC6Uj4r.mjs +2 -0
- package/dist/chunks/fonts-DQC6Uj4r.mjs.map +1 -0
- package/dist/chunks/fr-0qEo3bRP.mjs +2 -0
- package/dist/chunks/fr-0qEo3bRP.mjs.map +1 -0
- package/dist/chunks/fr-5HkMazAf.mjs +2 -0
- package/dist/chunks/fr-5HkMazAf.mjs.map +1 -0
- package/dist/chunks/fr-B9pBLaVx.mjs +2 -0
- package/dist/chunks/fr-B9pBLaVx.mjs.map +1 -0
- package/dist/chunks/fr-BRXUnq3R.mjs +2 -0
- package/dist/chunks/fr-BRXUnq3R.mjs.map +1 -0
- package/dist/chunks/fr-BSUKEtTk.mjs +2 -0
- package/dist/chunks/fr-BSUKEtTk.mjs.map +1 -0
- package/dist/chunks/fr-BaXKyPmX.mjs +2 -0
- package/dist/chunks/fr-BaXKyPmX.mjs.map +1 -0
- package/dist/chunks/fr-BeRlON1t.mjs +2 -0
- package/dist/chunks/fr-BeRlON1t.mjs.map +1 -0
- package/dist/chunks/fr-Bg937iAy.mjs +2 -0
- package/dist/chunks/fr-Bg937iAy.mjs.map +1 -0
- package/dist/chunks/fr-BwWrFThE.mjs +2 -0
- package/dist/chunks/fr-BwWrFThE.mjs.map +1 -0
- package/dist/chunks/fr-C3EKRThN.mjs +2 -0
- package/dist/chunks/fr-C3EKRThN.mjs.map +1 -0
- package/dist/chunks/fr-CKjH6tJI.mjs +2 -0
- package/dist/chunks/fr-CKjH6tJI.mjs.map +1 -0
- package/dist/chunks/fr-CQs0-pNX.mjs +2 -0
- package/dist/chunks/fr-CQs0-pNX.mjs.map +1 -0
- package/dist/chunks/fr-C_2i5Ono.mjs +2 -0
- package/dist/chunks/fr-C_2i5Ono.mjs.map +1 -0
- package/dist/chunks/fr-CfhyYN-t.mjs +2 -0
- package/dist/chunks/fr-CfhyYN-t.mjs.map +1 -0
- package/dist/chunks/fr-D0MDdoir.mjs +2 -0
- package/dist/chunks/fr-D0MDdoir.mjs.map +1 -0
- package/dist/chunks/fr-D5ulA3Z6.mjs +2 -0
- package/dist/chunks/fr-D5ulA3Z6.mjs.map +1 -0
- package/dist/chunks/fr-DEZ_oxzS.mjs +2 -0
- package/dist/chunks/fr-DEZ_oxzS.mjs.map +1 -0
- package/dist/chunks/fr-DciSEykY.mjs +2 -0
- package/dist/chunks/fr-DciSEykY.mjs.map +1 -0
- package/dist/chunks/fr-DiDhVhyV.mjs +2 -0
- package/dist/chunks/fr-DiDhVhyV.mjs.map +1 -0
- package/dist/chunks/fr-DjMZ-3K5.mjs +2 -0
- package/dist/chunks/fr-DjMZ-3K5.mjs.map +1 -0
- package/dist/chunks/fr-DtzIu6tU.mjs +2 -0
- package/dist/chunks/fr-DtzIu6tU.mjs.map +1 -0
- package/dist/chunks/fr-F2ZrfVaF.mjs +2 -0
- package/dist/chunks/fr-F2ZrfVaF.mjs.map +1 -0
- package/dist/chunks/fr-KXmbys88.mjs +2 -0
- package/dist/chunks/fr-KXmbys88.mjs.map +1 -0
- package/dist/chunks/fr-SbpHNrQ-.mjs +2 -0
- package/dist/chunks/fr-SbpHNrQ-.mjs.map +1 -0
- package/dist/chunks/fr-ZsRdLuys.mjs +2 -0
- package/dist/chunks/fr-ZsRdLuys.mjs.map +1 -0
- package/dist/chunks/fr-eC0UdAPu.mjs +2 -0
- package/dist/chunks/fr-eC0UdAPu.mjs.map +1 -0
- package/dist/chunks/fr-fshsDD66.mjs +2 -0
- package/dist/chunks/fr-fshsDD66.mjs.map +1 -0
- package/dist/chunks/full-CHkwduuY.mjs +2 -0
- package/dist/chunks/full-CHkwduuY.mjs.map +1 -0
- package/dist/chunks/hi-4CiAKVjT.mjs +2 -0
- package/dist/chunks/hi-4CiAKVjT.mjs.map +1 -0
- package/dist/chunks/hi-B-ZuX4aN.mjs +2 -0
- package/dist/chunks/hi-B-ZuX4aN.mjs.map +1 -0
- package/dist/chunks/hi-B2YB3Bo4.mjs +2 -0
- package/dist/chunks/hi-B2YB3Bo4.mjs.map +1 -0
- package/dist/chunks/hi-B2uhiPCN.mjs +2 -0
- package/dist/chunks/hi-B2uhiPCN.mjs.map +1 -0
- package/dist/chunks/hi-B5cl8TWK.mjs +2 -0
- package/dist/chunks/hi-B5cl8TWK.mjs.map +1 -0
- package/dist/chunks/hi-BNJIGWQQ.mjs +2 -0
- package/dist/chunks/hi-BNJIGWQQ.mjs.map +1 -0
- package/dist/chunks/hi-BOMkDPqC.mjs +2 -0
- package/dist/chunks/hi-BOMkDPqC.mjs.map +1 -0
- package/dist/chunks/hi-Bl-yeeOI.mjs +2 -0
- package/dist/chunks/hi-Bl-yeeOI.mjs.map +1 -0
- package/dist/chunks/hi-Bu799xIO.mjs +2 -0
- package/dist/chunks/hi-Bu799xIO.mjs.map +1 -0
- package/dist/chunks/hi-By8YwVIX.mjs +2 -0
- package/dist/chunks/hi-By8YwVIX.mjs.map +1 -0
- package/dist/chunks/hi-BzbMD_cP.mjs +2 -0
- package/dist/chunks/hi-BzbMD_cP.mjs.map +1 -0
- package/dist/chunks/hi-C2jEsf8v.mjs +2 -0
- package/dist/chunks/hi-C2jEsf8v.mjs.map +1 -0
- package/dist/chunks/hi-C9fvG91d.mjs +2 -0
- package/dist/chunks/hi-C9fvG91d.mjs.map +1 -0
- package/dist/chunks/hi-CTWubxLY.mjs +2 -0
- package/dist/chunks/hi-CTWubxLY.mjs.map +1 -0
- package/dist/chunks/hi-CoclKAUM.mjs +2 -0
- package/dist/chunks/hi-CoclKAUM.mjs.map +1 -0
- package/dist/chunks/hi-CrmakMVj.mjs +2 -0
- package/dist/chunks/hi-CrmakMVj.mjs.map +1 -0
- package/dist/chunks/hi-DWX6k5ZD.mjs +2 -0
- package/dist/chunks/hi-DWX6k5ZD.mjs.map +1 -0
- package/dist/chunks/hi-DY55FuDK.mjs +2 -0
- package/dist/chunks/hi-DY55FuDK.mjs.map +1 -0
- package/dist/chunks/hi-DsdXcOB6.mjs +2 -0
- package/dist/chunks/hi-DsdXcOB6.mjs.map +1 -0
- package/dist/chunks/hi-Dt89SxNy.mjs +2 -0
- package/dist/chunks/hi-Dt89SxNy.mjs.map +1 -0
- package/dist/chunks/hi-J8ErB5nB.mjs +2 -0
- package/dist/chunks/hi-J8ErB5nB.mjs.map +1 -0
- package/dist/chunks/hi-L6pJxZam.mjs +2 -0
- package/dist/chunks/hi-L6pJxZam.mjs.map +1 -0
- package/dist/chunks/hi-SECtQQzq.mjs +2 -0
- package/dist/chunks/hi-SECtQQzq.mjs.map +1 -0
- package/dist/chunks/hi-aH9HZG23.mjs +2 -0
- package/dist/chunks/hi-aH9HZG23.mjs.map +1 -0
- package/dist/chunks/hi-j3TDLMYd.mjs +2 -0
- package/dist/chunks/hi-j3TDLMYd.mjs.map +1 -0
- package/dist/chunks/hi-l6DA-aOw.mjs +2 -0
- package/dist/chunks/hi-l6DA-aOw.mjs.map +1 -0
- package/dist/chunks/hi-uACJUw53.mjs +2 -0
- package/dist/chunks/hi-uACJUw53.mjs.map +1 -0
- package/dist/chunks/minimal-D5v-raei.mjs +2 -0
- package/dist/chunks/minimal-D5v-raei.mjs.map +1 -0
- package/dist/chunks/pt-5VeuNDd2.mjs +2 -0
- package/dist/chunks/pt-5VeuNDd2.mjs.map +1 -0
- package/dist/chunks/pt-BCXgUDiU.mjs +2 -0
- package/dist/chunks/pt-BCXgUDiU.mjs.map +1 -0
- package/dist/chunks/pt-BDam9cDu.mjs +2 -0
- package/dist/chunks/pt-BDam9cDu.mjs.map +1 -0
- package/dist/chunks/pt-Bb908r0n.mjs +2 -0
- package/dist/chunks/pt-Bb908r0n.mjs.map +1 -0
- package/dist/chunks/pt-BkpVtod-.mjs +2 -0
- package/dist/chunks/pt-BkpVtod-.mjs.map +1 -0
- package/dist/chunks/pt-BlFAJZo7.mjs +2 -0
- package/dist/chunks/pt-BlFAJZo7.mjs.map +1 -0
- package/dist/chunks/pt-Bu7Mbz67.mjs +2 -0
- package/dist/chunks/pt-Bu7Mbz67.mjs.map +1 -0
- package/dist/chunks/pt-C8sOyw0V.mjs +2 -0
- package/dist/chunks/pt-C8sOyw0V.mjs.map +1 -0
- package/dist/chunks/pt-CEUgbrii.mjs +2 -0
- package/dist/chunks/pt-CEUgbrii.mjs.map +1 -0
- package/dist/chunks/pt-CMrFpUWS.mjs +2 -0
- package/dist/chunks/pt-CMrFpUWS.mjs.map +1 -0
- package/dist/chunks/pt-CMx2wPPY.mjs +2 -0
- package/dist/chunks/pt-CMx2wPPY.mjs.map +1 -0
- package/dist/chunks/pt-CR4j8gtE.mjs +2 -0
- package/dist/chunks/pt-CR4j8gtE.mjs.map +1 -0
- package/dist/chunks/pt-Cc4zysaT.mjs +2 -0
- package/dist/chunks/pt-Cc4zysaT.mjs.map +1 -0
- package/dist/chunks/pt-Cv6q7x5x.mjs +2 -0
- package/dist/chunks/pt-Cv6q7x5x.mjs.map +1 -0
- package/dist/chunks/pt-DFKJVh7k.mjs +2 -0
- package/dist/chunks/pt-DFKJVh7k.mjs.map +1 -0
- package/dist/chunks/pt-DYMyMgKQ.mjs +2 -0
- package/dist/chunks/pt-DYMyMgKQ.mjs.map +1 -0
- package/dist/chunks/pt-D__tcM2T.mjs +2 -0
- package/dist/chunks/pt-D__tcM2T.mjs.map +1 -0
- package/dist/chunks/pt-Dg2ctkug.mjs +2 -0
- package/dist/chunks/pt-Dg2ctkug.mjs.map +1 -0
- package/dist/chunks/pt-DgfMoLWR.mjs +2 -0
- package/dist/chunks/pt-DgfMoLWR.mjs.map +1 -0
- package/dist/chunks/pt-DmN9u3NX.mjs +2 -0
- package/dist/chunks/pt-DmN9u3NX.mjs.map +1 -0
- package/dist/chunks/pt-GqLw5tN0.mjs +2 -0
- package/dist/chunks/pt-GqLw5tN0.mjs.map +1 -0
- package/dist/chunks/pt-Hy-0Xnnc.mjs +2 -0
- package/dist/chunks/pt-Hy-0Xnnc.mjs.map +1 -0
- package/dist/chunks/pt-OXa_IR4Q.mjs +2 -0
- package/dist/chunks/pt-OXa_IR4Q.mjs.map +1 -0
- package/dist/chunks/pt-UPF7DBlz.mjs +2 -0
- package/dist/chunks/pt-UPF7DBlz.mjs.map +1 -0
- package/dist/chunks/pt-_qxIe7zX.mjs +2 -0
- package/dist/chunks/pt-_qxIe7zX.mjs.map +1 -0
- package/dist/chunks/pt-paXY7HFt.mjs +2 -0
- package/dist/chunks/pt-paXY7HFt.mjs.map +1 -0
- package/dist/chunks/pt-zMHcNGPk.mjs +2 -0
- package/dist/chunks/pt-zMHcNGPk.mjs.map +1 -0
- package/dist/chunks/ru-4g_qsaLr.mjs +2 -0
- package/dist/chunks/ru-4g_qsaLr.mjs.map +1 -0
- package/dist/chunks/ru-B1m8J9dl.mjs +2 -0
- package/dist/chunks/ru-B1m8J9dl.mjs.map +1 -0
- package/dist/chunks/ru-BFpEOrVp.mjs +2 -0
- package/dist/chunks/ru-BFpEOrVp.mjs.map +1 -0
- package/dist/chunks/ru-BNPUT-3S.mjs +2 -0
- package/dist/chunks/ru-BNPUT-3S.mjs.map +1 -0
- package/dist/chunks/ru-BotG0MFT.mjs +2 -0
- package/dist/chunks/ru-BotG0MFT.mjs.map +1 -0
- package/dist/chunks/ru-BxySx7an.mjs +2 -0
- package/dist/chunks/ru-BxySx7an.mjs.map +1 -0
- package/dist/chunks/ru-C-APN_dm.mjs +2 -0
- package/dist/chunks/ru-C-APN_dm.mjs.map +1 -0
- package/dist/chunks/ru-C9yFslEG.mjs +2 -0
- package/dist/chunks/ru-C9yFslEG.mjs.map +1 -0
- package/dist/chunks/ru-CkG_bpfo.mjs +2 -0
- package/dist/chunks/ru-CkG_bpfo.mjs.map +1 -0
- package/dist/chunks/ru-Cs8KCNyq.mjs +2 -0
- package/dist/chunks/ru-Cs8KCNyq.mjs.map +1 -0
- package/dist/chunks/ru-CvDl-yEd.mjs +2 -0
- package/dist/chunks/ru-CvDl-yEd.mjs.map +1 -0
- package/dist/chunks/ru-CwyPz2Va.mjs +2 -0
- package/dist/chunks/ru-CwyPz2Va.mjs.map +1 -0
- package/dist/chunks/ru-D53d-_UB.mjs +2 -0
- package/dist/chunks/ru-D53d-_UB.mjs.map +1 -0
- package/dist/chunks/ru-DJMpeuey.mjs +2 -0
- package/dist/chunks/ru-DJMpeuey.mjs.map +1 -0
- package/dist/chunks/ru-DSRv3_Rg.mjs +2 -0
- package/dist/chunks/ru-DSRv3_Rg.mjs.map +1 -0
- package/dist/chunks/ru-DV-lgEtM.mjs +2 -0
- package/dist/chunks/ru-DV-lgEtM.mjs.map +1 -0
- package/dist/chunks/ru-DiwQV30V.mjs +2 -0
- package/dist/chunks/ru-DiwQV30V.mjs.map +1 -0
- package/dist/chunks/ru-DkW9XZFy.mjs +2 -0
- package/dist/chunks/ru-DkW9XZFy.mjs.map +1 -0
- package/dist/chunks/ru-DyCTlhjg.mjs +2 -0
- package/dist/chunks/ru-DyCTlhjg.mjs.map +1 -0
- package/dist/chunks/ru-QGX8lOTs.mjs +2 -0
- package/dist/chunks/ru-QGX8lOTs.mjs.map +1 -0
- package/dist/chunks/ru-QcTo2yoL.mjs +2 -0
- package/dist/chunks/ru-QcTo2yoL.mjs.map +1 -0
- package/dist/chunks/ru-Y11wuxOB.mjs +2 -0
- package/dist/chunks/ru-Y11wuxOB.mjs.map +1 -0
- package/dist/chunks/ru-Yngw7nFP.mjs +2 -0
- package/dist/chunks/ru-Yngw7nFP.mjs.map +1 -0
- package/dist/chunks/ru-d68SZpEe.mjs +2 -0
- package/dist/chunks/ru-d68SZpEe.mjs.map +1 -0
- package/dist/chunks/ru-k7o3Qks3.mjs +2 -0
- package/dist/chunks/ru-k7o3Qks3.mjs.map +1 -0
- package/dist/chunks/ru-l73diFXn.mjs +2 -0
- package/dist/chunks/ru-l73diFXn.mjs.map +1 -0
- package/dist/chunks/ru-q8kz-237.mjs +2 -0
- package/dist/chunks/ru-q8kz-237.mjs.map +1 -0
- package/dist/chunks/src-gVRDR_79.mjs +2 -0
- package/dist/chunks/src-gVRDR_79.mjs.map +1 -0
- package/dist/chunks/zh-BGYJXxVl.mjs +2 -0
- package/dist/chunks/zh-BGYJXxVl.mjs.map +1 -0
- package/dist/chunks/zh-BP97XjlS.mjs +2 -0
- package/dist/chunks/zh-BP97XjlS.mjs.map +1 -0
- package/dist/chunks/zh-BQ73oqxc.mjs +2 -0
- package/dist/chunks/zh-BQ73oqxc.mjs.map +1 -0
- package/dist/chunks/zh-BQqf3wJZ.mjs +2 -0
- package/dist/chunks/zh-BQqf3wJZ.mjs.map +1 -0
- package/dist/chunks/zh-Baxh6v0j.mjs +2 -0
- package/dist/chunks/zh-Baxh6v0j.mjs.map +1 -0
- package/dist/chunks/zh-BjoyjClN.mjs +2 -0
- package/dist/chunks/zh-BjoyjClN.mjs.map +1 -0
- package/dist/chunks/zh-BvuAbM2S.mjs +2 -0
- package/dist/chunks/zh-BvuAbM2S.mjs.map +1 -0
- package/dist/chunks/zh-C-wHnDo5.mjs +2 -0
- package/dist/chunks/zh-C-wHnDo5.mjs.map +1 -0
- package/dist/chunks/zh-C7iCgCRP.mjs +2 -0
- package/dist/chunks/zh-C7iCgCRP.mjs.map +1 -0
- package/dist/chunks/zh-CRsDvfPR.mjs +2 -0
- package/dist/chunks/zh-CRsDvfPR.mjs.map +1 -0
- package/dist/chunks/zh-CWGAPVei.mjs +2 -0
- package/dist/chunks/zh-CWGAPVei.mjs.map +1 -0
- package/dist/chunks/zh-CWIzJcXi.mjs +2 -0
- package/dist/chunks/zh-CWIzJcXi.mjs.map +1 -0
- package/dist/chunks/zh-CYV-db-K.mjs +2 -0
- package/dist/chunks/zh-CYV-db-K.mjs.map +1 -0
- package/dist/chunks/zh-CnW44JEw.mjs +2 -0
- package/dist/chunks/zh-CnW44JEw.mjs.map +1 -0
- package/dist/chunks/zh-D1HSmSOf.mjs +2 -0
- package/dist/chunks/zh-D1HSmSOf.mjs.map +1 -0
- package/dist/chunks/zh-DWN1Jqn3.mjs +2 -0
- package/dist/chunks/zh-DWN1Jqn3.mjs.map +1 -0
- package/dist/chunks/zh-DYD476c5.mjs +2 -0
- package/dist/chunks/zh-DYD476c5.mjs.map +1 -0
- package/dist/chunks/zh-DdzgYD7k.mjs +2 -0
- package/dist/chunks/zh-DdzgYD7k.mjs.map +1 -0
- package/dist/chunks/zh-DeZP08HI.mjs +2 -0
- package/dist/chunks/zh-DeZP08HI.mjs.map +1 -0
- package/dist/chunks/zh-DgSmvLyw.mjs +2 -0
- package/dist/chunks/zh-DgSmvLyw.mjs.map +1 -0
- package/dist/chunks/zh-DlVfQn4z.mjs +2 -0
- package/dist/chunks/zh-DlVfQn4z.mjs.map +1 -0
- package/dist/chunks/zh-DuucmOns.mjs +2 -0
- package/dist/chunks/zh-DuucmOns.mjs.map +1 -0
- package/dist/chunks/zh-Oj-qSUEp.mjs +2 -0
- package/dist/chunks/zh-Oj-qSUEp.mjs.map +1 -0
- package/dist/chunks/zh-YfuE_m2y.mjs +2 -0
- package/dist/chunks/zh-YfuE_m2y.mjs.map +1 -0
- package/dist/chunks/zh-dGSDBBzb.mjs +2 -0
- package/dist/chunks/zh-dGSDBBzb.mjs.map +1 -0
- package/dist/chunks/zh-ikm3rSTR.mjs +2 -0
- package/dist/chunks/zh-ikm3rSTR.mjs.map +1 -0
- package/dist/chunks/zh-oZl1P_p0.mjs +2 -0
- package/dist/chunks/zh-oZl1P_p0.mjs.map +1 -0
- package/dist/commands/BlockInsertion.d.ts +49 -2
- package/dist/commands/BlockInsertion.d.ts.map +1 -1
- package/dist/commands/Commands.d.ts.map +1 -1
- package/dist/commands/NodeSelectionCommands.d.ts +10 -2
- package/dist/commands/NodeSelectionCommands.d.ts.map +1 -1
- package/dist/editor/styles/list.d.ts +1 -1
- package/dist/editor/styles/list.d.ts.map +1 -1
- package/dist/fonts.mjs +1 -1
- package/dist/full.mjs +1 -1
- package/dist/html.mjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/input/KeyDescriptor.d.ts +40 -0
- package/dist/input/KeyDescriptor.d.ts.map +1 -0
- package/dist/input/KeyboardHandler.d.ts +17 -5
- package/dist/input/KeyboardHandler.d.ts.map +1 -1
- package/dist/input/PasteHTMLHandler.d.ts.map +1 -1
- package/dist/input/PasteRichBlockHandler.d.ts +22 -3
- package/dist/input/PasteRichBlockHandler.d.ts.map +1 -1
- package/dist/model/Document.d.ts +2 -2
- package/dist/model/Document.d.ts.map +1 -1
- package/dist/notectl-core.mjs +1 -1
- package/dist/notectl-core.umd.js +1 -1
- package/dist/notectl-core.umd.js.map +1 -1
- package/dist/plugins/alignment.mjs +1 -1
- package/dist/plugins/bidi-isolation.mjs +1 -1
- package/dist/plugins/blockquote.mjs +1 -1
- package/dist/plugins/caret-navigation.mjs +1 -1
- package/dist/plugins/code-block.mjs +1 -1
- package/dist/plugins/font-size.mjs +1 -1
- package/dist/plugins/font.mjs +1 -1
- package/dist/plugins/formula/DisplayMathNodeSpec.d.ts.map +1 -1
- package/dist/plugins/formula/FormulaCommands.d.ts +14 -0
- package/dist/plugins/formula/FormulaCommands.d.ts.map +1 -1
- package/dist/plugins/formula/FormulaEditorMount.d.ts.map +1 -1
- package/dist/plugins/formula/FormulaLocale.d.ts +7 -1
- package/dist/plugins/formula/FormulaLocale.d.ts.map +1 -1
- package/dist/plugins/formula/FormulaPasteInterceptor.d.ts +12 -3
- package/dist/plugins/formula/FormulaPasteInterceptor.d.ts.map +1 -1
- package/dist/plugins/formula/FormulaSerialization.d.ts +17 -0
- package/dist/plugins/formula/FormulaSerialization.d.ts.map +1 -0
- package/dist/plugins/formula/FormulaStyles.d.ts +1 -1
- package/dist/plugins/formula/FormulaStyles.d.ts.map +1 -1
- package/dist/plugins/formula/InlineMathNodeSpec.d.ts.map +1 -1
- package/dist/plugins/formula/locales/ar.d.ts.map +1 -1
- package/dist/plugins/formula/locales/de.d.ts.map +1 -1
- package/dist/plugins/formula/locales/es.d.ts.map +1 -1
- package/dist/plugins/formula/locales/fr.d.ts.map +1 -1
- package/dist/plugins/formula/locales/hi.d.ts.map +1 -1
- package/dist/plugins/formula/locales/pt.d.ts.map +1 -1
- package/dist/plugins/formula/locales/ru.d.ts.map +1 -1
- package/dist/plugins/formula/locales/zh.d.ts.map +1 -1
- package/dist/plugins/formula/math-field/MathPalette.d.ts.map +1 -1
- package/dist/plugins/formula/math-field/MathPaletteData.d.ts +7 -1
- package/dist/plugins/formula/math-field/MathPaletteData.d.ts.map +1 -1
- package/dist/plugins/formula/mathml/MathMLDocument.d.ts +13 -0
- package/dist/plugins/formula/mathml/MathMLDocument.d.ts.map +1 -1
- package/dist/plugins/formula.mjs +1 -1
- package/dist/plugins/gap-cursor.mjs +1 -1
- package/dist/plugins/hard-break.mjs +1 -1
- package/dist/plugins/heading.mjs +1 -1
- package/dist/plugins/highlight.mjs +1 -1
- package/dist/plugins/horizontal-rule.mjs +1 -1
- package/dist/plugins/image.mjs +1 -1
- package/dist/plugins/inline-code.mjs +1 -1
- package/dist/plugins/language.mjs +1 -1
- package/dist/plugins/link.mjs +1 -1
- package/dist/plugins/list/ListCommands.d.ts +16 -3
- package/dist/plugins/list/ListCommands.d.ts.map +1 -1
- package/dist/plugins/list/ListLocale.d.ts +6 -0
- package/dist/plugins/list/ListLocale.d.ts.map +1 -1
- package/dist/plugins/list/ListMarker.d.ts +14 -0
- package/dist/plugins/list/ListMarker.d.ts.map +1 -0
- package/dist/plugins/list/ListPlugin.d.ts.map +1 -1
- package/dist/plugins/list/locales/ar.d.ts.map +1 -1
- package/dist/plugins/list/locales/de.d.ts.map +1 -1
- package/dist/plugins/list/locales/es.d.ts.map +1 -1
- package/dist/plugins/list/locales/fr.d.ts.map +1 -1
- package/dist/plugins/list/locales/hi.d.ts.map +1 -1
- package/dist/plugins/list/locales/pt.d.ts.map +1 -1
- package/dist/plugins/list/locales/ru.d.ts.map +1 -1
- package/dist/plugins/list/locales/zh.d.ts.map +1 -1
- package/dist/plugins/list.mjs +1 -1
- package/dist/plugins/print.mjs +1 -1
- package/dist/plugins/shared.mjs +1 -1
- package/dist/plugins/smart-paste.mjs +1 -1
- package/dist/plugins/strikethrough.mjs +1 -1
- package/dist/plugins/super-sub.mjs +1 -1
- package/dist/plugins/table/TableCommands.d.ts.map +1 -1
- package/dist/plugins/table.mjs +1 -1
- package/dist/plugins/text-color.mjs +1 -1
- package/dist/plugins/text-direction-auto.mjs +1 -1
- package/dist/plugins/text-direction.mjs +1 -1
- package/dist/plugins/text-formatting.mjs +1 -1
- package/dist/plugins/toolbar/ToolbarPopupController.d.ts.map +1 -1
- package/dist/plugins/toolbar.mjs +1 -1
- package/dist/plugins/video/VideoCommands.d.ts.map +1 -1
- package/dist/plugins/video.mjs +1 -1
- package/dist/presets/full.mjs +1 -1
- package/dist/presets/minimal.mjs +1 -1
- package/dist/presets.mjs +1 -1
- package/dist/state/InlineContentOps.d.ts +5 -3
- package/dist/state/InlineContentOps.d.ts.map +1 -1
- package/dist/state/StepInversion.d.ts.map +1 -1
- package/dist/state/StepMaps.d.ts.map +1 -1
- package/dist/state/Steps.d.ts +20 -3
- package/dist/state/Steps.d.ts.map +1 -1
- package/dist/state/TransactionBuilder.d.ts +3 -3
- package/dist/state/TransactionBuilder.d.ts.map +1 -1
- package/dist/test/TestUtils.d.ts +2 -0
- package/dist/test/TestUtils.d.ts.map +1 -1
- package/dist/view/SelectionSync.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/chunks/AlignmentPlugin-BLzRjrUl.mjs +0 -2
- package/dist/chunks/AlignmentPlugin-BLzRjrUl.mjs.map +0 -1
- package/dist/chunks/AttrRegistry-CRnXTPha.mjs +0 -2
- package/dist/chunks/AttrRegistry-CRnXTPha.mjs.map +0 -1
- package/dist/chunks/AttributedMarkCommands-CxhdUsuE.mjs +0 -2
- package/dist/chunks/AttributedMarkCommands-CxhdUsuE.mjs.map +0 -1
- package/dist/chunks/BidiIsolationPlugin-DNPXe5ga.mjs +0 -2
- package/dist/chunks/BidiIsolationPlugin-DNPXe5ga.mjs.map +0 -1
- package/dist/chunks/BlockInsertion-C7jFEeYB.mjs +0 -2
- package/dist/chunks/BlockInsertion-C7jFEeYB.mjs.map +0 -1
- package/dist/chunks/BlockTypePickerRegistry-U4uY7-lN.mjs +0 -2
- package/dist/chunks/BlockTypePickerRegistry-U4uY7-lN.mjs.map +0 -1
- package/dist/chunks/BlockquotePlugin-YgXcV4mT.mjs +0 -2
- package/dist/chunks/BlockquotePlugin-YgXcV4mT.mjs.map +0 -1
- package/dist/chunks/CaretNavigationPlugin-P6OYaTSq.mjs +0 -2
- package/dist/chunks/CaretNavigationPlugin-P6OYaTSq.mjs.map +0 -1
- package/dist/chunks/CodeBlockPlugin-ChPv3Edf.mjs +0 -2
- package/dist/chunks/CodeBlockPlugin-ChPv3Edf.mjs.map +0 -1
- package/dist/chunks/ColorGrid-D5-teEjD.mjs +0 -2
- package/dist/chunks/ColorGrid-D5-teEjD.mjs.map +0 -1
- package/dist/chunks/ColorPickerPopup-_Gp09pdx.mjs +0 -2
- package/dist/chunks/ColorPickerPopup-_Gp09pdx.mjs.map +0 -1
- package/dist/chunks/ColorValidation-okAvytHQ.mjs +0 -2
- package/dist/chunks/ColorValidation-okAvytHQ.mjs.map +0 -1
- package/dist/chunks/CommandHelpers-NV80Ff1G.mjs +0 -2
- package/dist/chunks/CommandHelpers-NV80Ff1G.mjs.map +0 -1
- package/dist/chunks/Commands-ixGhPiRG.mjs +0 -2
- package/dist/chunks/Commands-ixGhPiRG.mjs.map +0 -1
- package/dist/chunks/Decoration-DZK7hrL1.mjs +0 -2
- package/dist/chunks/Decoration-DZK7hrL1.mjs.map +0 -1
- package/dist/chunks/DirectionDetection-7HmMUZrx.mjs +0 -2
- package/dist/chunks/DirectionDetection-7HmMUZrx.mjs.map +0 -1
- package/dist/chunks/DirectionIcons-DhRvPVoz.mjs +0 -2
- package/dist/chunks/DirectionIcons-DhRvPVoz.mjs.map +0 -1
- package/dist/chunks/Document-znhIcvM9.mjs +0 -2
- package/dist/chunks/Document-znhIcvM9.mjs.map +0 -1
- package/dist/chunks/DocumentParser-DCjOW3us.mjs +0 -2
- package/dist/chunks/DocumentParser-DCjOW3us.mjs.map +0 -1
- package/dist/chunks/DomUtils-RKbAVBQz.mjs +0 -2
- package/dist/chunks/DomUtils-RKbAVBQz.mjs.map +0 -1
- package/dist/chunks/FontPlugin-COYtG1Uo.mjs +0 -2
- package/dist/chunks/FontPlugin-COYtG1Uo.mjs.map +0 -1
- package/dist/chunks/FontSizePlugin-CLcfdTm3.mjs +0 -2
- package/dist/chunks/FontSizePlugin-CLcfdTm3.mjs.map +0 -1
- package/dist/chunks/FormulaPlugin-DphHU4Rn.mjs +0 -2
- package/dist/chunks/FormulaPlugin-DphHU4Rn.mjs.map +0 -1
- package/dist/chunks/GapCursorNavigation-Bkuu_Ek8.mjs +0 -2
- package/dist/chunks/GapCursorNavigation-Bkuu_Ek8.mjs.map +0 -1
- package/dist/chunks/GapCursorPlugin-CRDmQEi1.mjs +0 -2
- package/dist/chunks/GapCursorPlugin-CRDmQEi1.mjs.map +0 -1
- package/dist/chunks/HTMLUtils-brwcaufP.mjs +0 -2
- package/dist/chunks/HTMLUtils-brwcaufP.mjs.map +0 -1
- package/dist/chunks/HardBreakPlugin-Cr6dMQ-H.mjs +0 -2
- package/dist/chunks/HardBreakPlugin-Cr6dMQ-H.mjs.map +0 -1
- package/dist/chunks/HeadingPlugin-3NL4ARPp.mjs +0 -2
- package/dist/chunks/HeadingPlugin-3NL4ARPp.mjs.map +0 -1
- package/dist/chunks/HighlightPlugin-dHxnAuoW.mjs +0 -2
- package/dist/chunks/HighlightPlugin-dHxnAuoW.mjs.map +0 -1
- package/dist/chunks/HorizontalRulePlugin-BYPaI4TR.mjs +0 -2
- package/dist/chunks/HorizontalRulePlugin-BYPaI4TR.mjs.map +0 -1
- package/dist/chunks/ImagePlugin-kgokm-a1.mjs +0 -2
- package/dist/chunks/ImagePlugin-kgokm-a1.mjs.map +0 -1
- package/dist/chunks/InlineCodePlugin-Bl1jyDwk.mjs +0 -2
- package/dist/chunks/InlineCodePlugin-Bl1jyDwk.mjs.map +0 -1
- package/dist/chunks/InlineStyleMarkSpec-Cc-b1tlm.mjs +0 -2
- package/dist/chunks/InlineStyleMarkSpec-Cc-b1tlm.mjs.map +0 -1
- package/dist/chunks/KeyboardNav-DZXdTg-_.mjs +0 -2
- package/dist/chunks/KeyboardNav-DZXdTg-_.mjs.map +0 -1
- package/dist/chunks/LinkPlugin-Dmcfo3On.mjs +0 -2
- package/dist/chunks/LinkPlugin-Dmcfo3On.mjs.map +0 -1
- package/dist/chunks/ListPlugin-Ch-5CsFc.mjs +0 -2
- package/dist/chunks/ListPlugin-Ch-5CsFc.mjs.map +0 -1
- package/dist/chunks/NavigationQueries-3zTaNBlp.mjs +0 -2
- package/dist/chunks/NavigationQueries-3zTaNBlp.mjs.map +0 -1
- package/dist/chunks/NodeResolver-BplmzA7c.mjs +0 -2
- package/dist/chunks/NodeResolver-BplmzA7c.mjs.map +0 -1
- package/dist/chunks/NodeSelectionCommands-dUmbRoZ2.mjs +0 -2
- package/dist/chunks/NodeSelectionCommands-dUmbRoZ2.mjs.map +0 -1
- package/dist/chunks/NodeSpecPatching-DToX09gc.mjs +0 -2
- package/dist/chunks/NodeSpecPatching-DToX09gc.mjs.map +0 -1
- package/dist/chunks/Platform-wPvKFB9m.mjs +0 -2
- package/dist/chunks/Platform-wPvKFB9m.mjs.map +0 -1
- package/dist/chunks/PluginHelpers-C3aCCGfX.mjs +0 -2
- package/dist/chunks/PluginHelpers-C3aCCGfX.mjs.map +0 -1
- package/dist/chunks/PopupKeyboardPatterns-ZdAQB78m.mjs +0 -2
- package/dist/chunks/PopupKeyboardPatterns-ZdAQB78m.mjs.map +0 -1
- package/dist/chunks/PopupManager-DsT1uRWi.mjs +0 -2
- package/dist/chunks/PopupManager-DsT1uRWi.mjs.map +0 -1
- package/dist/chunks/PopupPositioning-BEnz90Oh.mjs +0 -2
- package/dist/chunks/PopupPositioning-BEnz90Oh.mjs.map +0 -1
- package/dist/chunks/PrintPlugin-Bq-Z14K1.mjs +0 -2
- package/dist/chunks/PrintPlugin-Bq-Z14K1.mjs.map +0 -1
- package/dist/chunks/PrintTypes-DA0Cc--M.mjs +0 -2
- package/dist/chunks/PrintTypes-DA0Cc--M.mjs.map +0 -1
- package/dist/chunks/RangeIterator-Cl4_k8cx.mjs +0 -2
- package/dist/chunks/RangeIterator-Cl4_k8cx.mjs.map +0 -1
- package/dist/chunks/Selection-aeiSsvhe.mjs +0 -2
- package/dist/chunks/Selection-aeiSsvhe.mjs.map +0 -1
- package/dist/chunks/SelectionSync-DCJpNFat.mjs +0 -2
- package/dist/chunks/SelectionSync-DCJpNFat.mjs.map +0 -1
- package/dist/chunks/ShortcutFormatting-DZK70CN9.mjs +0 -2
- package/dist/chunks/ShortcutFormatting-DZK70CN9.mjs.map +0 -1
- package/dist/chunks/SimpleMark-CezTJnXh.mjs +0 -2
- package/dist/chunks/SimpleMark-CezTJnXh.mjs.map +0 -1
- package/dist/chunks/SmartPastePlugin-DlApY6Vw.mjs +0 -2
- package/dist/chunks/SmartPastePlugin-DlApY6Vw.mjs.map +0 -1
- package/dist/chunks/StrikethroughPlugin-BuFDABvz.mjs +0 -2
- package/dist/chunks/StrikethroughPlugin-BuFDABvz.mjs.map +0 -1
- package/dist/chunks/StyleRuntime-Bwde5icB.mjs +0 -2
- package/dist/chunks/StyleRuntime-Bwde5icB.mjs.map +0 -1
- package/dist/chunks/SuperSubPlugin-CiLJ7i4s.mjs +0 -2
- package/dist/chunks/SuperSubPlugin-CiLJ7i4s.mjs.map +0 -1
- package/dist/chunks/SyntaxTokenTypes-C9dGwufi.mjs +0 -2
- package/dist/chunks/SyntaxTokenTypes-C9dGwufi.mjs.map +0 -1
- package/dist/chunks/TablePlugin-5ru-y-YX.mjs +0 -2
- package/dist/chunks/TablePlugin-5ru-y-YX.mjs.map +0 -1
- package/dist/chunks/TextColorPlugin-Vz-Nz8aH.mjs +0 -2
- package/dist/chunks/TextColorPlugin-Vz-Nz8aH.mjs.map +0 -1
- package/dist/chunks/TextDirectionAutoPlugin-Behl6KMe.mjs +0 -2
- package/dist/chunks/TextDirectionAutoPlugin-Behl6KMe.mjs.map +0 -1
- package/dist/chunks/TextDirectionPlugin-C3h1n-aA.mjs +0 -2
- package/dist/chunks/TextDirectionPlugin-C3h1n-aA.mjs.map +0 -1
- package/dist/chunks/TextDirectionService-DRfeQnF6.mjs +0 -2
- package/dist/chunks/TextDirectionService-DRfeQnF6.mjs.map +0 -1
- package/dist/chunks/TextFormattingPlugin-D_nRMeBn.mjs +0 -2
- package/dist/chunks/TextFormattingPlugin-D_nRMeBn.mjs.map +0 -1
- package/dist/chunks/ToolbarPlugin-CSMSgjPM.mjs +0 -2
- package/dist/chunks/ToolbarPlugin-CSMSgjPM.mjs.map +0 -1
- package/dist/chunks/TypeBrands-BZDKMjR-.mjs +0 -2
- package/dist/chunks/TypeBrands-BZDKMjR-.mjs.map +0 -1
- package/dist/chunks/TypedKeys-E3jOGByL.mjs +0 -2
- package/dist/chunks/TypedKeys-E3jOGByL.mjs.map +0 -1
- package/dist/chunks/VideoPlugin-BUCGIYXr.mjs +0 -2
- package/dist/chunks/VideoPlugin-BUCGIYXr.mjs.map +0 -1
- package/dist/chunks/WordBoundary-CYDAtEks.mjs +0 -2
- package/dist/chunks/WordBoundary-CYDAtEks.mjs.map +0 -1
- package/dist/chunks/XmlDetector-DxBGXqua.mjs +0 -2
- package/dist/chunks/XmlDetector-DxBGXqua.mjs.map +0 -1
- package/dist/chunks/XmlPatterns-BiHS8w3k.mjs +0 -2
- package/dist/chunks/XmlPatterns-BiHS8w3k.mjs.map +0 -1
- package/dist/chunks/XmlSupport-B_F65M8G.mjs +0 -2
- package/dist/chunks/XmlSupport-B_F65M8G.mjs.map +0 -1
- package/dist/chunks/ar-B38MlRRN.mjs +0 -2
- package/dist/chunks/ar-B38MlRRN.mjs.map +0 -1
- package/dist/chunks/ar-BIeE0C5A.mjs +0 -2
- package/dist/chunks/ar-BIeE0C5A.mjs.map +0 -1
- package/dist/chunks/ar-BK0rFxF_.mjs +0 -2
- package/dist/chunks/ar-BK0rFxF_.mjs.map +0 -1
- package/dist/chunks/ar-BK4O36ep.mjs +0 -2
- package/dist/chunks/ar-BK4O36ep.mjs.map +0 -1
- package/dist/chunks/ar-BNUWuZe3.mjs +0 -2
- package/dist/chunks/ar-BNUWuZe3.mjs.map +0 -1
- package/dist/chunks/ar-BSXH8acw.mjs +0 -2
- package/dist/chunks/ar-BSXH8acw.mjs.map +0 -1
- package/dist/chunks/ar-BY8yNlGe.mjs +0 -2
- package/dist/chunks/ar-BY8yNlGe.mjs.map +0 -1
- package/dist/chunks/ar-BgHkduPE.mjs +0 -2
- package/dist/chunks/ar-BgHkduPE.mjs.map +0 -1
- package/dist/chunks/ar-BnfWtLhK.mjs +0 -2
- package/dist/chunks/ar-BnfWtLhK.mjs.map +0 -1
- package/dist/chunks/ar-BwCPhCf6.mjs +0 -2
- package/dist/chunks/ar-BwCPhCf6.mjs.map +0 -1
- package/dist/chunks/ar-Bymjd9Z_.mjs +0 -2
- package/dist/chunks/ar-Bymjd9Z_.mjs.map +0 -1
- package/dist/chunks/ar-CKPpdJ7F.mjs +0 -2
- package/dist/chunks/ar-CKPpdJ7F.mjs.map +0 -1
- package/dist/chunks/ar-C_ir5Uf4.mjs +0 -2
- package/dist/chunks/ar-C_ir5Uf4.mjs.map +0 -1
- package/dist/chunks/ar-CkE6GDVA.mjs +0 -2
- package/dist/chunks/ar-CkE6GDVA.mjs.map +0 -1
- package/dist/chunks/ar-ClgA1KQM.mjs +0 -2
- package/dist/chunks/ar-ClgA1KQM.mjs.map +0 -1
- package/dist/chunks/ar-Cm1DOK74.mjs +0 -2
- package/dist/chunks/ar-Cm1DOK74.mjs.map +0 -1
- package/dist/chunks/ar-CseGhQtS.mjs +0 -2
- package/dist/chunks/ar-CseGhQtS.mjs.map +0 -1
- package/dist/chunks/ar-D0bqkviV.mjs +0 -2
- package/dist/chunks/ar-D0bqkviV.mjs.map +0 -1
- package/dist/chunks/ar-D5d185g0.mjs +0 -2
- package/dist/chunks/ar-D5d185g0.mjs.map +0 -1
- package/dist/chunks/ar-DSwUyX47.mjs +0 -2
- package/dist/chunks/ar-DSwUyX47.mjs.map +0 -1
- package/dist/chunks/ar-DfSNWZX7.mjs +0 -2
- package/dist/chunks/ar-DfSNWZX7.mjs.map +0 -1
- package/dist/chunks/ar-Dghtfs46.mjs +0 -2
- package/dist/chunks/ar-Dghtfs46.mjs.map +0 -1
- package/dist/chunks/ar-DvNKBrJd.mjs +0 -2
- package/dist/chunks/ar-DvNKBrJd.mjs.map +0 -1
- package/dist/chunks/ar-KNULRI8r.mjs +0 -2
- package/dist/chunks/ar-KNULRI8r.mjs.map +0 -1
- package/dist/chunks/ar-NtGRavHz.mjs +0 -2
- package/dist/chunks/ar-NtGRavHz.mjs.map +0 -1
- package/dist/chunks/ar-Y9KjJLX8.mjs +0 -2
- package/dist/chunks/ar-Y9KjJLX8.mjs.map +0 -1
- package/dist/chunks/ar-odM5gkvw.mjs +0 -2
- package/dist/chunks/ar-odM5gkvw.mjs.map +0 -1
- package/dist/chunks/color-picker-C89H4SVX.mjs +0 -2
- package/dist/chunks/color-picker-C89H4SVX.mjs.map +0 -1
- package/dist/chunks/de-B1TXiyll.mjs +0 -2
- package/dist/chunks/de-B1TXiyll.mjs.map +0 -1
- package/dist/chunks/de-BDRaxLyi.mjs +0 -2
- package/dist/chunks/de-BDRaxLyi.mjs.map +0 -1
- package/dist/chunks/de-BGOpZ8Ls.mjs +0 -2
- package/dist/chunks/de-BGOpZ8Ls.mjs.map +0 -1
- package/dist/chunks/de-BfZ5qXWz.mjs +0 -2
- package/dist/chunks/de-BfZ5qXWz.mjs.map +0 -1
- package/dist/chunks/de-BibufNIa.mjs +0 -2
- package/dist/chunks/de-BibufNIa.mjs.map +0 -1
- package/dist/chunks/de-BkZqCmzL.mjs +0 -2
- package/dist/chunks/de-BkZqCmzL.mjs.map +0 -1
- package/dist/chunks/de-BzRd2oyR.mjs +0 -2
- package/dist/chunks/de-BzRd2oyR.mjs.map +0 -1
- package/dist/chunks/de-C4gnHDmk.mjs +0 -2
- package/dist/chunks/de-C4gnHDmk.mjs.map +0 -1
- package/dist/chunks/de-C4iw9SEp.mjs +0 -2
- package/dist/chunks/de-C4iw9SEp.mjs.map +0 -1
- package/dist/chunks/de-CLWzcDoW.mjs +0 -2
- package/dist/chunks/de-CLWzcDoW.mjs.map +0 -1
- package/dist/chunks/de-Cbv0otYM.mjs +0 -2
- package/dist/chunks/de-Cbv0otYM.mjs.map +0 -1
- package/dist/chunks/de-Cinp7zmo.mjs +0 -2
- package/dist/chunks/de-Cinp7zmo.mjs.map +0 -1
- package/dist/chunks/de-CvnyjI_X.mjs +0 -2
- package/dist/chunks/de-CvnyjI_X.mjs.map +0 -1
- package/dist/chunks/de-DCx3Shj3.mjs +0 -2
- package/dist/chunks/de-DCx3Shj3.mjs.map +0 -1
- package/dist/chunks/de-Dav2GzjV.mjs +0 -2
- package/dist/chunks/de-Dav2GzjV.mjs.map +0 -1
- package/dist/chunks/de-Dc7GRbWc.mjs +0 -2
- package/dist/chunks/de-Dc7GRbWc.mjs.map +0 -1
- package/dist/chunks/de-DdntlpT3.mjs +0 -2
- package/dist/chunks/de-DdntlpT3.mjs.map +0 -1
- package/dist/chunks/de-DefykdF-.mjs +0 -2
- package/dist/chunks/de-DefykdF-.mjs.map +0 -1
- package/dist/chunks/de-DfQQIP8Y.mjs +0 -2
- package/dist/chunks/de-DfQQIP8Y.mjs.map +0 -1
- package/dist/chunks/de-DkcKDkbA.mjs +0 -2
- package/dist/chunks/de-DkcKDkbA.mjs.map +0 -1
- package/dist/chunks/de-DqGfLfeV.mjs +0 -2
- package/dist/chunks/de-DqGfLfeV.mjs.map +0 -1
- package/dist/chunks/de-DudqIJho.mjs +0 -2
- package/dist/chunks/de-DudqIJho.mjs.map +0 -1
- package/dist/chunks/de-LCXA2xWj.mjs +0 -2
- package/dist/chunks/de-LCXA2xWj.mjs.map +0 -1
- package/dist/chunks/de-YygmrxGp.mjs +0 -2
- package/dist/chunks/de-YygmrxGp.mjs.map +0 -1
- package/dist/chunks/de-asI3UlFG.mjs +0 -2
- package/dist/chunks/de-asI3UlFG.mjs.map +0 -1
- package/dist/chunks/de-kvMvD3AJ.mjs +0 -2
- package/dist/chunks/de-kvMvD3AJ.mjs.map +0 -1
- package/dist/chunks/de-pnfTnS03.mjs +0 -2
- package/dist/chunks/de-pnfTnS03.mjs.map +0 -1
- package/dist/chunks/es-4tbAR0If.mjs +0 -2
- package/dist/chunks/es-4tbAR0If.mjs.map +0 -1
- package/dist/chunks/es-B9z2Xwj0.mjs +0 -2
- package/dist/chunks/es-B9z2Xwj0.mjs.map +0 -1
- package/dist/chunks/es-BJxjRQSg.mjs +0 -2
- package/dist/chunks/es-BJxjRQSg.mjs.map +0 -1
- package/dist/chunks/es-BSyxBRjn.mjs +0 -2
- package/dist/chunks/es-BSyxBRjn.mjs.map +0 -1
- package/dist/chunks/es-Bcpq2xfU.mjs +0 -2
- package/dist/chunks/es-Bcpq2xfU.mjs.map +0 -1
- package/dist/chunks/es-BhUjc8mO.mjs +0 -2
- package/dist/chunks/es-BhUjc8mO.mjs.map +0 -1
- package/dist/chunks/es-Bm7hoJSI.mjs +0 -2
- package/dist/chunks/es-Bm7hoJSI.mjs.map +0 -1
- package/dist/chunks/es-C0E-lFIC.mjs +0 -2
- package/dist/chunks/es-C0E-lFIC.mjs.map +0 -1
- package/dist/chunks/es-C2wBBQ7N.mjs +0 -2
- package/dist/chunks/es-C2wBBQ7N.mjs.map +0 -1
- package/dist/chunks/es-C9vhYpfP.mjs +0 -2
- package/dist/chunks/es-C9vhYpfP.mjs.map +0 -1
- package/dist/chunks/es-Cgslt0Hp.mjs +0 -2
- package/dist/chunks/es-Cgslt0Hp.mjs.map +0 -1
- package/dist/chunks/es-CksXDFxg.mjs +0 -2
- package/dist/chunks/es-CksXDFxg.mjs.map +0 -1
- package/dist/chunks/es-CnQUZlfY.mjs +0 -2
- package/dist/chunks/es-CnQUZlfY.mjs.map +0 -1
- package/dist/chunks/es-CrRNOn2Q.mjs +0 -2
- package/dist/chunks/es-CrRNOn2Q.mjs.map +0 -1
- package/dist/chunks/es-D0427MIH.mjs +0 -2
- package/dist/chunks/es-D0427MIH.mjs.map +0 -1
- package/dist/chunks/es-D19xfXus.mjs +0 -2
- package/dist/chunks/es-D19xfXus.mjs.map +0 -1
- package/dist/chunks/es-Dk6lCcOt.mjs +0 -2
- package/dist/chunks/es-Dk6lCcOt.mjs.map +0 -1
- package/dist/chunks/es-Dls_xPCW.mjs +0 -2
- package/dist/chunks/es-Dls_xPCW.mjs.map +0 -1
- package/dist/chunks/es-DrcsyDvI.mjs +0 -2
- package/dist/chunks/es-DrcsyDvI.mjs.map +0 -1
- package/dist/chunks/es-DwKejbO9.mjs +0 -2
- package/dist/chunks/es-DwKejbO9.mjs.map +0 -1
- package/dist/chunks/es-NcrWuNe1.mjs +0 -2
- package/dist/chunks/es-NcrWuNe1.mjs.map +0 -1
- package/dist/chunks/es-RaZerssd.mjs +0 -2
- package/dist/chunks/es-RaZerssd.mjs.map +0 -1
- package/dist/chunks/es-TIjHCFNF.mjs +0 -2
- package/dist/chunks/es-TIjHCFNF.mjs.map +0 -1
- package/dist/chunks/es-eZcDkBb-.mjs +0 -2
- package/dist/chunks/es-eZcDkBb-.mjs.map +0 -1
- package/dist/chunks/es-j_-KW9-4.mjs +0 -2
- package/dist/chunks/es-j_-KW9-4.mjs.map +0 -1
- package/dist/chunks/es-kGLwn8EB.mjs +0 -2
- package/dist/chunks/es-kGLwn8EB.mjs.map +0 -1
- package/dist/chunks/es-qQRDC0Ge.mjs +0 -2
- package/dist/chunks/es-qQRDC0Ge.mjs.map +0 -1
- package/dist/chunks/fonts-ZXAIMT3b.mjs +0 -2
- package/dist/chunks/fonts-ZXAIMT3b.mjs.map +0 -1
- package/dist/chunks/fr-B27zAq0X.mjs +0 -2
- package/dist/chunks/fr-B27zAq0X.mjs.map +0 -1
- package/dist/chunks/fr-BEd3ZHO4.mjs +0 -2
- package/dist/chunks/fr-BEd3ZHO4.mjs.map +0 -1
- package/dist/chunks/fr-BHXLpdaH.mjs +0 -2
- package/dist/chunks/fr-BHXLpdaH.mjs.map +0 -1
- package/dist/chunks/fr-BKu4eU3V.mjs +0 -2
- package/dist/chunks/fr-BKu4eU3V.mjs.map +0 -1
- package/dist/chunks/fr-BUrUZ5UQ.mjs +0 -2
- package/dist/chunks/fr-BUrUZ5UQ.mjs.map +0 -1
- package/dist/chunks/fr-BlqlUQ3b.mjs +0 -2
- package/dist/chunks/fr-BlqlUQ3b.mjs.map +0 -1
- package/dist/chunks/fr-BruEqDw1.mjs +0 -2
- package/dist/chunks/fr-BruEqDw1.mjs.map +0 -1
- package/dist/chunks/fr-BwuuFBkA.mjs +0 -2
- package/dist/chunks/fr-BwuuFBkA.mjs.map +0 -1
- package/dist/chunks/fr-C2lLh5Ti.mjs +0 -2
- package/dist/chunks/fr-C2lLh5Ti.mjs.map +0 -1
- package/dist/chunks/fr-C7N2_AlK.mjs +0 -2
- package/dist/chunks/fr-C7N2_AlK.mjs.map +0 -1
- package/dist/chunks/fr-COfd6sLW.mjs +0 -2
- package/dist/chunks/fr-COfd6sLW.mjs.map +0 -1
- package/dist/chunks/fr-COx4cSxc.mjs +0 -2
- package/dist/chunks/fr-COx4cSxc.mjs.map +0 -1
- package/dist/chunks/fr-CX37XjPO.mjs +0 -2
- package/dist/chunks/fr-CX37XjPO.mjs.map +0 -1
- package/dist/chunks/fr-CYn6fMiH.mjs +0 -2
- package/dist/chunks/fr-CYn6fMiH.mjs.map +0 -1
- package/dist/chunks/fr-CbsiyDEa.mjs +0 -2
- package/dist/chunks/fr-CbsiyDEa.mjs.map +0 -1
- package/dist/chunks/fr-CcZiELJY.mjs +0 -2
- package/dist/chunks/fr-CcZiELJY.mjs.map +0 -1
- package/dist/chunks/fr-CeHzUPVT.mjs +0 -2
- package/dist/chunks/fr-CeHzUPVT.mjs.map +0 -1
- package/dist/chunks/fr-Cv73J4QZ.mjs +0 -2
- package/dist/chunks/fr-Cv73J4QZ.mjs.map +0 -1
- package/dist/chunks/fr-DDLuorz7.mjs +0 -2
- package/dist/chunks/fr-DDLuorz7.mjs.map +0 -1
- package/dist/chunks/fr-DMA4CAyo.mjs +0 -2
- package/dist/chunks/fr-DMA4CAyo.mjs.map +0 -1
- package/dist/chunks/fr-DNJuGtO1.mjs +0 -2
- package/dist/chunks/fr-DNJuGtO1.mjs.map +0 -1
- package/dist/chunks/fr-DQOE8O6_.mjs +0 -2
- package/dist/chunks/fr-DQOE8O6_.mjs.map +0 -1
- package/dist/chunks/fr-DXjOwGew.mjs +0 -2
- package/dist/chunks/fr-DXjOwGew.mjs.map +0 -1
- package/dist/chunks/fr-DilrEvE_.mjs +0 -2
- package/dist/chunks/fr-DilrEvE_.mjs.map +0 -1
- package/dist/chunks/fr-P7iY3ntE.mjs +0 -2
- package/dist/chunks/fr-P7iY3ntE.mjs.map +0 -1
- package/dist/chunks/fr-ViUNGo_J.mjs +0 -2
- package/dist/chunks/fr-ViUNGo_J.mjs.map +0 -1
- package/dist/chunks/fr-gdIyLcGC.mjs +0 -2
- package/dist/chunks/fr-gdIyLcGC.mjs.map +0 -1
- package/dist/chunks/full-h88Sb2MR.mjs +0 -2
- package/dist/chunks/full-h88Sb2MR.mjs.map +0 -1
- package/dist/chunks/hi-BC82Jxjl.mjs +0 -2
- package/dist/chunks/hi-BC82Jxjl.mjs.map +0 -1
- package/dist/chunks/hi-BCTarnem.mjs +0 -2
- package/dist/chunks/hi-BCTarnem.mjs.map +0 -1
- package/dist/chunks/hi-BMStjhJF.mjs +0 -2
- package/dist/chunks/hi-BMStjhJF.mjs.map +0 -1
- package/dist/chunks/hi-BQ2Fyx7t.mjs +0 -2
- package/dist/chunks/hi-BQ2Fyx7t.mjs.map +0 -1
- package/dist/chunks/hi-Bg4-z2Os.mjs +0 -2
- package/dist/chunks/hi-Bg4-z2Os.mjs.map +0 -1
- package/dist/chunks/hi-BgqI_gOH.mjs +0 -2
- package/dist/chunks/hi-BgqI_gOH.mjs.map +0 -1
- package/dist/chunks/hi-CEPSeUBX.mjs +0 -2
- package/dist/chunks/hi-CEPSeUBX.mjs.map +0 -1
- package/dist/chunks/hi-CRaZj5Uo.mjs +0 -2
- package/dist/chunks/hi-CRaZj5Uo.mjs.map +0 -1
- package/dist/chunks/hi-CT0uK1Me.mjs +0 -2
- package/dist/chunks/hi-CT0uK1Me.mjs.map +0 -1
- package/dist/chunks/hi-CnIpMd8L.mjs +0 -2
- package/dist/chunks/hi-CnIpMd8L.mjs.map +0 -1
- package/dist/chunks/hi-CnSv0JhL.mjs +0 -2
- package/dist/chunks/hi-CnSv0JhL.mjs.map +0 -1
- package/dist/chunks/hi-DLLBZu67.mjs +0 -2
- package/dist/chunks/hi-DLLBZu67.mjs.map +0 -1
- package/dist/chunks/hi-DMg_aiSR.mjs +0 -2
- package/dist/chunks/hi-DMg_aiSR.mjs.map +0 -1
- package/dist/chunks/hi-DWwLzOX5.mjs +0 -2
- package/dist/chunks/hi-DWwLzOX5.mjs.map +0 -1
- package/dist/chunks/hi-D_4Xi4Nv.mjs +0 -2
- package/dist/chunks/hi-D_4Xi4Nv.mjs.map +0 -1
- package/dist/chunks/hi-D_Jtykmj.mjs +0 -2
- package/dist/chunks/hi-D_Jtykmj.mjs.map +0 -1
- package/dist/chunks/hi-Da5pRz8E.mjs +0 -2
- package/dist/chunks/hi-Da5pRz8E.mjs.map +0 -1
- package/dist/chunks/hi-DqL20WmM.mjs +0 -2
- package/dist/chunks/hi-DqL20WmM.mjs.map +0 -1
- package/dist/chunks/hi-DwQopxRg.mjs +0 -2
- package/dist/chunks/hi-DwQopxRg.mjs.map +0 -1
- package/dist/chunks/hi-IuMohSSw.mjs +0 -2
- package/dist/chunks/hi-IuMohSSw.mjs.map +0 -1
- package/dist/chunks/hi-PUX7dDPm.mjs +0 -2
- package/dist/chunks/hi-PUX7dDPm.mjs.map +0 -1
- package/dist/chunks/hi-RmfZAmwT.mjs +0 -2
- package/dist/chunks/hi-RmfZAmwT.mjs.map +0 -1
- package/dist/chunks/hi-UIBrTEVu.mjs +0 -2
- package/dist/chunks/hi-UIBrTEVu.mjs.map +0 -1
- package/dist/chunks/hi-_SjWnfeh.mjs +0 -2
- package/dist/chunks/hi-_SjWnfeh.mjs.map +0 -1
- package/dist/chunks/hi-dV2GZgH_.mjs +0 -2
- package/dist/chunks/hi-dV2GZgH_.mjs.map +0 -1
- package/dist/chunks/hi-ehh5oKz3.mjs +0 -2
- package/dist/chunks/hi-ehh5oKz3.mjs.map +0 -1
- package/dist/chunks/hi-yXnRBFJK.mjs +0 -2
- package/dist/chunks/hi-yXnRBFJK.mjs.map +0 -1
- package/dist/chunks/minimal-a40NeBQ_.mjs +0 -2
- package/dist/chunks/minimal-a40NeBQ_.mjs.map +0 -1
- package/dist/chunks/pt-2a8Oto6x.mjs +0 -2
- package/dist/chunks/pt-2a8Oto6x.mjs.map +0 -1
- package/dist/chunks/pt-ALzIyTiI.mjs +0 -2
- package/dist/chunks/pt-ALzIyTiI.mjs.map +0 -1
- package/dist/chunks/pt-B2hMlTc6.mjs +0 -2
- package/dist/chunks/pt-B2hMlTc6.mjs.map +0 -1
- package/dist/chunks/pt-BCIkSb0w.mjs +0 -2
- package/dist/chunks/pt-BCIkSb0w.mjs.map +0 -1
- package/dist/chunks/pt-BFotmq5x.mjs +0 -2
- package/dist/chunks/pt-BFotmq5x.mjs.map +0 -1
- package/dist/chunks/pt-BM7OScX6.mjs +0 -2
- package/dist/chunks/pt-BM7OScX6.mjs.map +0 -1
- package/dist/chunks/pt-BM7zXWxW.mjs +0 -2
- package/dist/chunks/pt-BM7zXWxW.mjs.map +0 -1
- package/dist/chunks/pt-BchCuzFq.mjs +0 -2
- package/dist/chunks/pt-BchCuzFq.mjs.map +0 -1
- package/dist/chunks/pt-BmcHFWoR.mjs +0 -2
- package/dist/chunks/pt-BmcHFWoR.mjs.map +0 -1
- package/dist/chunks/pt-C53W99RV.mjs +0 -2
- package/dist/chunks/pt-C53W99RV.mjs.map +0 -1
- package/dist/chunks/pt-CORQy8qv.mjs +0 -2
- package/dist/chunks/pt-CORQy8qv.mjs.map +0 -1
- package/dist/chunks/pt-CUPKr943.mjs +0 -2
- package/dist/chunks/pt-CUPKr943.mjs.map +0 -1
- package/dist/chunks/pt-CYkKDsLa.mjs +0 -2
- package/dist/chunks/pt-CYkKDsLa.mjs.map +0 -1
- package/dist/chunks/pt-Cd_SXHKt.mjs +0 -2
- package/dist/chunks/pt-Cd_SXHKt.mjs.map +0 -1
- package/dist/chunks/pt-CjN3Oq-6.mjs +0 -2
- package/dist/chunks/pt-CjN3Oq-6.mjs.map +0 -1
- package/dist/chunks/pt-CrKrgktr.mjs +0 -2
- package/dist/chunks/pt-CrKrgktr.mjs.map +0 -1
- package/dist/chunks/pt-Crmbkj0e.mjs +0 -2
- package/dist/chunks/pt-Crmbkj0e.mjs.map +0 -1
- package/dist/chunks/pt-D19IWOM_.mjs +0 -2
- package/dist/chunks/pt-D19IWOM_.mjs.map +0 -1
- package/dist/chunks/pt-D6zY7l2E.mjs +0 -2
- package/dist/chunks/pt-D6zY7l2E.mjs.map +0 -1
- package/dist/chunks/pt-DA5hufLZ.mjs +0 -2
- package/dist/chunks/pt-DA5hufLZ.mjs.map +0 -1
- package/dist/chunks/pt-DEfBqu-c.mjs +0 -2
- package/dist/chunks/pt-DEfBqu-c.mjs.map +0 -1
- package/dist/chunks/pt-DG3rw6nK.mjs +0 -2
- package/dist/chunks/pt-DG3rw6nK.mjs.map +0 -1
- package/dist/chunks/pt-DRoAHNZi.mjs +0 -2
- package/dist/chunks/pt-DRoAHNZi.mjs.map +0 -1
- package/dist/chunks/pt-Eml9QiUL.mjs +0 -2
- package/dist/chunks/pt-Eml9QiUL.mjs.map +0 -1
- package/dist/chunks/pt-Haa3wVmA.mjs +0 -2
- package/dist/chunks/pt-Haa3wVmA.mjs.map +0 -1
- package/dist/chunks/pt-aj7zOxTg.mjs +0 -2
- package/dist/chunks/pt-aj7zOxTg.mjs.map +0 -1
- package/dist/chunks/pt-l6dTmkQk.mjs +0 -2
- package/dist/chunks/pt-l6dTmkQk.mjs.map +0 -1
- package/dist/chunks/ru--JPEpdcJ.mjs +0 -2
- package/dist/chunks/ru--JPEpdcJ.mjs.map +0 -1
- package/dist/chunks/ru-B76ORyqe.mjs +0 -2
- package/dist/chunks/ru-B76ORyqe.mjs.map +0 -1
- package/dist/chunks/ru-BDQ62WuE.mjs +0 -2
- package/dist/chunks/ru-BDQ62WuE.mjs.map +0 -1
- package/dist/chunks/ru-BQ6W3lwr.mjs +0 -2
- package/dist/chunks/ru-BQ6W3lwr.mjs.map +0 -1
- package/dist/chunks/ru-BQpaitci.mjs +0 -2
- package/dist/chunks/ru-BQpaitci.mjs.map +0 -1
- package/dist/chunks/ru-Bm9VwJLu.mjs +0 -2
- package/dist/chunks/ru-Bm9VwJLu.mjs.map +0 -1
- package/dist/chunks/ru-BnNdik6i.mjs +0 -2
- package/dist/chunks/ru-BnNdik6i.mjs.map +0 -1
- package/dist/chunks/ru-Bo4am8cd.mjs +0 -2
- package/dist/chunks/ru-Bo4am8cd.mjs.map +0 -1
- package/dist/chunks/ru-C1k56xWQ.mjs +0 -2
- package/dist/chunks/ru-C1k56xWQ.mjs.map +0 -1
- package/dist/chunks/ru-C4rnSQlI.mjs +0 -2
- package/dist/chunks/ru-C4rnSQlI.mjs.map +0 -1
- package/dist/chunks/ru-CKM3t1sv.mjs +0 -2
- package/dist/chunks/ru-CKM3t1sv.mjs.map +0 -1
- package/dist/chunks/ru-CO6eCsxU.mjs +0 -2
- package/dist/chunks/ru-CO6eCsxU.mjs.map +0 -1
- package/dist/chunks/ru-CTaYpQ9_.mjs +0 -2
- package/dist/chunks/ru-CTaYpQ9_.mjs.map +0 -1
- package/dist/chunks/ru-CdY8d80t.mjs +0 -2
- package/dist/chunks/ru-CdY8d80t.mjs.map +0 -1
- package/dist/chunks/ru-CsDtaWRd.mjs +0 -2
- package/dist/chunks/ru-CsDtaWRd.mjs.map +0 -1
- package/dist/chunks/ru-Cy_4nn8h.mjs +0 -2
- package/dist/chunks/ru-Cy_4nn8h.mjs.map +0 -1
- package/dist/chunks/ru-DACtjNuJ.mjs +0 -2
- package/dist/chunks/ru-DACtjNuJ.mjs.map +0 -1
- package/dist/chunks/ru-DN6yN_w9.mjs +0 -2
- package/dist/chunks/ru-DN6yN_w9.mjs.map +0 -1
- package/dist/chunks/ru-DThFtd76.mjs +0 -2
- package/dist/chunks/ru-DThFtd76.mjs.map +0 -1
- package/dist/chunks/ru-Dd_P7hP7.mjs +0 -2
- package/dist/chunks/ru-Dd_P7hP7.mjs.map +0 -1
- package/dist/chunks/ru-Dhuxwzwy.mjs +0 -2
- package/dist/chunks/ru-Dhuxwzwy.mjs.map +0 -1
- package/dist/chunks/ru-Dn6UDGIG.mjs +0 -2
- package/dist/chunks/ru-Dn6UDGIG.mjs.map +0 -1
- package/dist/chunks/ru-DojHc5wu.mjs +0 -2
- package/dist/chunks/ru-DojHc5wu.mjs.map +0 -1
- package/dist/chunks/ru-DyWzWBjV.mjs +0 -2
- package/dist/chunks/ru-DyWzWBjV.mjs.map +0 -1
- package/dist/chunks/ru-NBxCkjlP.mjs +0 -2
- package/dist/chunks/ru-NBxCkjlP.mjs.map +0 -1
- package/dist/chunks/ru-_MQaVHam.mjs +0 -2
- package/dist/chunks/ru-_MQaVHam.mjs.map +0 -1
- package/dist/chunks/ru-wv17PPrd.mjs +0 -2
- package/dist/chunks/ru-wv17PPrd.mjs.map +0 -1
- package/dist/chunks/src-ooaZ_Egu.mjs +0 -2
- package/dist/chunks/src-ooaZ_Egu.mjs.map +0 -1
- package/dist/chunks/zh-2-Y3Limy.mjs +0 -2
- package/dist/chunks/zh-2-Y3Limy.mjs.map +0 -1
- package/dist/chunks/zh-B02VPMqX.mjs +0 -2
- package/dist/chunks/zh-B02VPMqX.mjs.map +0 -1
- package/dist/chunks/zh-BYjLBWWN.mjs +0 -2
- package/dist/chunks/zh-BYjLBWWN.mjs.map +0 -1
- package/dist/chunks/zh-Bt2ZdHcS.mjs +0 -2
- package/dist/chunks/zh-Bt2ZdHcS.mjs.map +0 -1
- package/dist/chunks/zh-BuN_C4o-.mjs +0 -2
- package/dist/chunks/zh-BuN_C4o-.mjs.map +0 -1
- package/dist/chunks/zh-CA3BDj0Y.mjs +0 -2
- package/dist/chunks/zh-CA3BDj0Y.mjs.map +0 -1
- package/dist/chunks/zh-CHuGP7RS.mjs +0 -2
- package/dist/chunks/zh-CHuGP7RS.mjs.map +0 -1
- package/dist/chunks/zh-CIPsF5P8.mjs +0 -2
- package/dist/chunks/zh-CIPsF5P8.mjs.map +0 -1
- package/dist/chunks/zh-C_YS18re.mjs +0 -2
- package/dist/chunks/zh-C_YS18re.mjs.map +0 -1
- package/dist/chunks/zh-CfMPFWUg.mjs +0 -2
- package/dist/chunks/zh-CfMPFWUg.mjs.map +0 -1
- package/dist/chunks/zh-CfjCcBIB.mjs +0 -2
- package/dist/chunks/zh-CfjCcBIB.mjs.map +0 -1
- package/dist/chunks/zh-CqQph809.mjs +0 -2
- package/dist/chunks/zh-CqQph809.mjs.map +0 -1
- package/dist/chunks/zh-Cxe42GC5.mjs +0 -2
- package/dist/chunks/zh-Cxe42GC5.mjs.map +0 -1
- package/dist/chunks/zh-CyMU2cTf.mjs +0 -2
- package/dist/chunks/zh-CyMU2cTf.mjs.map +0 -1
- package/dist/chunks/zh-Cynz1sBa.mjs +0 -2
- package/dist/chunks/zh-Cynz1sBa.mjs.map +0 -1
- package/dist/chunks/zh-DRKs6Q0a.mjs +0 -2
- package/dist/chunks/zh-DRKs6Q0a.mjs.map +0 -1
- package/dist/chunks/zh-DTuIJjx6.mjs +0 -2
- package/dist/chunks/zh-DTuIJjx6.mjs.map +0 -1
- package/dist/chunks/zh-DTz9l6mp.mjs +0 -2
- package/dist/chunks/zh-DTz9l6mp.mjs.map +0 -1
- package/dist/chunks/zh-DZwjiJmn.mjs +0 -2
- package/dist/chunks/zh-DZwjiJmn.mjs.map +0 -1
- package/dist/chunks/zh-D_VJDQl4.mjs +0 -2
- package/dist/chunks/zh-D_VJDQl4.mjs.map +0 -1
- package/dist/chunks/zh-Dt20Om7Z.mjs +0 -2
- package/dist/chunks/zh-Dt20Om7Z.mjs.map +0 -1
- package/dist/chunks/zh-SgsZ9f-W.mjs +0 -2
- package/dist/chunks/zh-SgsZ9f-W.mjs.map +0 -1
- package/dist/chunks/zh-XR7Ls7m-.mjs +0 -2
- package/dist/chunks/zh-XR7Ls7m-.mjs.map +0 -1
- package/dist/chunks/zh-aXPI9lKF.mjs +0 -2
- package/dist/chunks/zh-aXPI9lKF.mjs.map +0 -1
- package/dist/chunks/zh-cLXIKkZQ.mjs +0 -2
- package/dist/chunks/zh-cLXIKkZQ.mjs.map +0 -1
- package/dist/chunks/zh-cZUtN871.mjs +0 -2
- package/dist/chunks/zh-cZUtN871.mjs.map +0 -1
- package/dist/chunks/zh-hcdnCGUp.mjs +0 -2
- package/dist/chunks/zh-hcdnCGUp.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"VideoPlugin-BUCGIYXr.mjs","names":[],"sources":["../../src/plugins/video/VideoProviders.ts","../../src/plugins/video/VideoTypes.ts","../../src/plugins/video/VideoCommands.ts","../../src/plugins/video/VideoPopup.ts","../../src/plugins/video/VideoEditOverlay.ts","../../src/plugins/video/VideoEmbedPrompt.ts","../../src/plugins/video/VideoLocale.ts","../../src/plugins/video/VideoViewHelpers.ts","../../src/plugins/video/VideoNodeSpec.ts","../../src/plugins/video/VideoFacade.ts","../../src/plugins/video/VideoResize.ts","../../src/plugins/video/VideoSelectionToolbar.ts","../../src/plugins/video/VideoNodeView.ts","../../src/plugins/video/VideoPasteInterceptor.ts","../../src/plugins/video/VideoPopupStyles.ts","../../src/plugins/video/VideoSanitizeHook.ts","../../src/plugins/video/VideoStyles.ts","../../src/plugins/video/VideoPlugin.ts"],"sourcesContent":["/**\n * Dependency-free video provider registry.\n *\n * Every embed is derived from pure client-side parsing of the user-supplied URL.\n * No oEmbed, no provider SDK, no runtime network call — a hard project constraint.\n *\n * A provider knows three things:\n * - which incoming hostnames it recognizes (`hostnames`),\n * - how to extract a video id (+ optional privacy hash) from such a URL (`parse`),\n * - how to build the canonical embed/watch/thumbnail URLs from that id.\n *\n * The `embedHostnames` set is the load-bearing security boundary: it is the exact\n * set of hosts a video `<iframe src>` may point at. The sanitize host-allowlist\n * (see `VideoPlugin`) is built from the union of every provider's `embedHostnames`,\n * so adding a provider keeps the allowlist in sync automatically.\n */\n\n/** A parsed reference to a hosted video. */\nexport interface VideoMatch {\n\treadonly provider: string;\n\treadonly videoId: string;\n\t/** Privacy hash for unlisted videos (Vimeo). */\n\treadonly hash?: string;\n}\n\n/** Options influencing embed-URL construction. */\nexport interface EmbedUrlOptions {\n\t/** Use the privacy-enhanced host/params (youtube-nocookie, Vimeo `dnt`). */\n\treadonly privacy: boolean;\n\t/**\n\t * Start playback immediately. Only ever set in response to an explicit user\n\t * gesture (the facade Play button), never on load — so this can never be an\n\t * autoplay-on-load (WCAG F93) violation.\n\t */\n\treadonly autoplay: boolean;\n}\n\n/**\n * A video provider. Recognizing a new service is a single object: declare its\n * hostnames, a `parse` that pulls the id out of a URL, and the URL builders.\n */\nexport interface VideoProvider {\n\t/** Stable identifier persisted in the node (`youtube` | `vimeo` | ...). */\n\treadonly id: string;\n\t/** Human-readable provider name for UI surfaces. */\n\treadonly label: string;\n\t/** Exact hostnames recognized when parsing an incoming watch/share URL. */\n\treadonly hostnames: readonly string[];\n\t/** Exact hostnames permitted as an embed `<iframe src>` (sanitize allowlist). */\n\treadonly embedHostnames: readonly string[];\n\t/** Extracts the video id (and optional hash) from a host-matched URL. */\n\tparse(url: URL): { readonly videoId: string; readonly hash?: string } | null;\n\t/** Builds the embed `<iframe src>` for the match. */\n\tbuildEmbedUrl(match: VideoMatch, options: EmbedUrlOptions): string;\n\t/** Builds the canonical public watch URL (facade link + HTML export). */\n\tbuildWatchUrl(match: VideoMatch): string;\n\t/**\n\t * Builds a deterministic thumbnail URL, if the provider exposes one without an\n\t * API call. Absent (or returning undefined) means the facade uses a local\n\t * placeholder. Loading a provider thumbnail is itself a third-party request,\n\t * so it is opt-in (`useProviderThumbnail`), never the default.\n\t */\n\tthumbnailUrl?(match: VideoMatch): string | undefined;\n}\n\n// --- ID shape validators ---\n\nconst YOUTUBE_ID = /^[A-Za-z0-9_-]{11}$/;\nconst VIMEO_ID = /^\\d+$/;\nconst VIMEO_HASH = /^[A-Za-z0-9]+$/;\nconst DAILYMOTION_ID = /^[A-Za-z0-9]+$/;\n\n/** Reads the first non-empty path segment after a given marker segment. */\nfunction segmentAfter(segments: readonly string[], marker: string): string | undefined {\n\tconst index: number = segments.indexOf(marker);\n\tif (index === -1) return undefined;\n\treturn segments[index + 1];\n}\n\n// --- YouTube ---\n\nconst YOUTUBE: VideoProvider = {\n\tid: 'youtube',\n\tlabel: 'YouTube',\n\thostnames: [\n\t\t'youtube.com',\n\t\t'www.youtube.com',\n\t\t'm.youtube.com',\n\t\t'music.youtube.com',\n\t\t'youtu.be',\n\t\t'youtube-nocookie.com',\n\t\t'www.youtube-nocookie.com',\n\t],\n\tembedHostnames: [\n\t\t'www.youtube-nocookie.com',\n\t\t'youtube-nocookie.com',\n\t\t'www.youtube.com',\n\t\t'youtube.com',\n\t],\n\tparse(url: URL): { readonly videoId: string } | null {\n\t\tconst host: string = url.hostname.toLowerCase();\n\t\tconst segments: string[] = url.pathname.split('/').filter(Boolean);\n\n\t\t// youtu.be/<id>\n\t\tif (host === 'youtu.be') {\n\t\t\tconst id: string | undefined = segments[0];\n\t\t\treturn id && YOUTUBE_ID.test(id) ? { videoId: id } : null;\n\t\t}\n\n\t\t// /watch?v=<id>\n\t\tconst queryId: string | null = url.searchParams.get('v');\n\t\tif (queryId && YOUTUBE_ID.test(queryId)) return { videoId: queryId };\n\n\t\t// /embed/<id>, /shorts/<id>, /live/<id>, /v/<id>\n\t\tfor (const marker of ['embed', 'shorts', 'live', 'v']) {\n\t\t\tconst id: string | undefined = segmentAfter(segments, marker);\n\t\t\tif (id && YOUTUBE_ID.test(id)) return { videoId: id };\n\t\t}\n\t\treturn null;\n\t},\n\tbuildEmbedUrl(match: VideoMatch, options: EmbedUrlOptions): string {\n\t\tconst host: string = options.privacy ? 'www.youtube-nocookie.com' : 'www.youtube.com';\n\t\tconst params: string = buildQuery({\n\t\t\trel: '0',\n\t\t\t...(options.autoplay ? { autoplay: '1' } : {}),\n\t\t});\n\t\treturn `https://${host}/embed/${match.videoId}${params}`;\n\t},\n\tbuildWatchUrl(match: VideoMatch): string {\n\t\treturn `https://www.youtube.com/watch?v=${match.videoId}`;\n\t},\n\tthumbnailUrl(match: VideoMatch): string {\n\t\treturn `https://i.ytimg.com/vi/${match.videoId}/hqdefault.jpg`;\n\t},\n};\n\n// --- Vimeo ---\n\nconst VIMEO: VideoProvider = {\n\tid: 'vimeo',\n\tlabel: 'Vimeo',\n\thostnames: ['vimeo.com', 'www.vimeo.com', 'player.vimeo.com'],\n\tembedHostnames: ['player.vimeo.com'],\n\tparse(url: URL): { readonly videoId: string; readonly hash?: string } | null {\n\t\tconst segments: string[] = url.pathname.split('/').filter(Boolean);\n\n\t\t// player.vimeo.com/video/<id>?h=<hash>\n\t\tconst playerId: string | undefined = segmentAfter(segments, 'video');\n\t\tif (playerId && VIMEO_ID.test(playerId)) {\n\t\t\treturn withVimeoHash(playerId, url, undefined);\n\t\t}\n\n\t\t// vimeo.com/<id>, vimeo.com/<id>/<hash>, vimeo.com/channels/<name>/<id>\n\t\tconst numeric: string | undefined = segments.find((s) => VIMEO_ID.test(s));\n\t\tif (numeric) {\n\t\t\tconst index: number = segments.indexOf(numeric);\n\t\t\tconst pathHash: string | undefined = segments[index + 1];\n\t\t\treturn withVimeoHash(numeric, url, pathHash);\n\t\t}\n\t\treturn null;\n\t},\n\tbuildEmbedUrl(match: VideoMatch, options: EmbedUrlOptions): string {\n\t\tconst params: string = buildQuery({\n\t\t\t...(match.hash ? { h: match.hash } : {}),\n\t\t\t...(options.privacy ? { dnt: '1' } : {}),\n\t\t\t...(options.autoplay ? { autoplay: '1' } : {}),\n\t\t});\n\t\treturn `https://player.vimeo.com/video/${match.videoId}${params}`;\n\t},\n\tbuildWatchUrl(match: VideoMatch): string {\n\t\tconst base = `https://vimeo.com/${match.videoId}`;\n\t\treturn match.hash ? `${base}/${match.hash}` : base;\n\t},\n};\n\n/** Validates an optional Vimeo hash (query `h=` takes precedence over a path segment). */\nfunction withVimeoHash(\n\tvideoId: string,\n\turl: URL,\n\tpathHash: string | undefined,\n): { readonly videoId: string; readonly hash?: string } {\n\tconst queryHash: string | null = url.searchParams.get('h');\n\tconst candidate: string | undefined = queryHash ?? pathHash;\n\tif (candidate && VIMEO_HASH.test(candidate)) {\n\t\treturn { videoId, hash: candidate };\n\t}\n\treturn { videoId };\n}\n\n// --- Dailymotion ---\n\nconst DAILYMOTION: VideoProvider = {\n\tid: 'dailymotion',\n\tlabel: 'Dailymotion',\n\thostnames: ['dailymotion.com', 'www.dailymotion.com', 'geo.dailymotion.com', 'dai.ly'],\n\tembedHostnames: ['www.dailymotion.com', 'geo.dailymotion.com'],\n\tparse(url: URL): { readonly videoId: string } | null {\n\t\tconst host: string = url.hostname.toLowerCase();\n\t\tconst segments: string[] = url.pathname.split('/').filter(Boolean);\n\n\t\t// dai.ly/<id>\n\t\tif (host === 'dai.ly') {\n\t\t\tconst id: string | undefined = segments[0];\n\t\t\treturn id && DAILYMOTION_ID.test(id) ? { videoId: id } : null;\n\t\t}\n\n\t\t// /video/<id> or /embed/video/<id>\n\t\tconst id: string | undefined = segmentAfter(segments, 'video');\n\t\tif (id && DAILYMOTION_ID.test(id)) return { videoId: id };\n\t\treturn null;\n\t},\n\tbuildEmbedUrl(match: VideoMatch, options: EmbedUrlOptions): string {\n\t\tconst params: string = buildQuery(options.autoplay ? { autoplay: '1' } : {});\n\t\treturn `https://www.dailymotion.com/embed/video/${match.videoId}${params}`;\n\t},\n\tbuildWatchUrl(match: VideoMatch): string {\n\t\treturn `https://www.dailymotion.com/video/${match.videoId}`;\n\t},\n\tthumbnailUrl(match: VideoMatch): string {\n\t\treturn `https://www.dailymotion.com/thumbnail/video/${match.videoId}`;\n\t},\n};\n\n/** The default provider registry: YouTube, Vimeo, Dailymotion. */\nexport const DEFAULT_VIDEO_PROVIDERS: readonly VideoProvider[] = [YOUTUBE, VIMEO, DAILYMOTION];\n\n// --- URL parsing entry point ---\n\n/**\n * Parses a user-supplied URL into a {@link VideoMatch} against the given providers.\n * Returns null when the URL is malformed, not `https`/`http`, or matches no\n * provider — the caller then falls back to a plain link (never a blind embed).\n *\n * Host matching is exact set-membership, never substring: this is what rejects\n * look-alikes such as `evilyoutube.com`, `youtube.com.evil.com`, and the\n * `https://youtube.com@evil.com` userinfo trick (whose real host is `evil.com`).\n */\nexport function parseVideoUrl(\n\trawUrl: string,\n\tproviders: readonly VideoProvider[] = DEFAULT_VIDEO_PROVIDERS,\n): VideoMatch | null {\n\tconst url: URL | null = safeParseUrl(rawUrl);\n\tif (!url) return null;\n\tif (url.protocol !== 'https:' && url.protocol !== 'http:') return null;\n\n\tconst host: string = url.hostname.toLowerCase();\n\tfor (const provider of providers) {\n\t\tif (!provider.hostnames.includes(host)) continue;\n\t\tconst result = provider.parse(url);\n\t\tif (result) {\n\t\t\treturn {\n\t\t\t\tprovider: provider.id,\n\t\t\t\tvideoId: result.videoId,\n\t\t\t\t...(result.hash ? { hash: result.hash } : {}),\n\t\t\t};\n\t\t}\n\t}\n\treturn null;\n}\n\n/** Looks up a provider by id. */\nexport function findProvider(\n\tproviderId: string,\n\tproviders: readonly VideoProvider[] = DEFAULT_VIDEO_PROVIDERS,\n): VideoProvider | undefined {\n\treturn providers.find((p) => p.id === providerId);\n}\n\n/** Builds the embed `<iframe src>` for a match, or null when the provider is unknown. */\nexport function buildEmbedUrlForMatch(\n\tmatch: VideoMatch,\n\tproviders: readonly VideoProvider[],\n\toptions: EmbedUrlOptions,\n): string | null {\n\tconst provider: VideoProvider | undefined = findProvider(match.provider, providers);\n\treturn provider ? provider.buildEmbedUrl(match, options) : null;\n}\n\n/** Builds the canonical public watch URL for a match, or null when unknown. */\nexport function buildWatchUrlForMatch(\n\tmatch: VideoMatch,\n\tproviders: readonly VideoProvider[],\n): string | null {\n\tconst provider: VideoProvider | undefined = findProvider(match.provider, providers);\n\treturn provider ? provider.buildWatchUrl(match) : null;\n}\n\n/** Builds a deterministic thumbnail URL for a match, or undefined when unavailable. */\nexport function buildThumbnailForMatch(\n\tmatch: VideoMatch,\n\tproviders: readonly VideoProvider[],\n): string | undefined {\n\tconst provider: VideoProvider | undefined = findProvider(match.provider, providers);\n\treturn provider?.thumbnailUrl?.(match);\n}\n\n/** Returns the human-readable provider label, falling back to the raw id. */\nexport function providerLabel(\n\tproviderId: string,\n\tproviders: readonly VideoProvider[] = DEFAULT_VIDEO_PROVIDERS,\n): string {\n\treturn findProvider(providerId, providers)?.label ?? providerId;\n}\n\n/**\n * Builds the exact set of hostnames permitted as a video embed `<iframe src>`,\n * unioned across all providers. Used by the sanitize host-allowlist hook.\n */\nexport function collectEmbedHostnames(\n\tproviders: readonly VideoProvider[] = DEFAULT_VIDEO_PROVIDERS,\n): ReadonlySet<string> {\n\tconst hosts = new Set<string>();\n\tfor (const provider of providers) {\n\t\tfor (const host of provider.embedHostnames) hosts.add(host.toLowerCase());\n\t}\n\treturn hosts;\n}\n\n/**\n * True when `src` is a safe video embed URL: an `https:` URL whose hostname is an\n * exact member of the embed allowlist. Used both to validate iframes on import\n * and to reject anything that does not provably point at a known provider.\n */\nexport function isAllowedEmbedSrc(src: string, allowedHosts: ReadonlySet<string>): boolean {\n\tconst url: URL | null = safeParseUrl(src);\n\tif (!url) return false;\n\tif (url.protocol !== 'https:') return false;\n\treturn allowedHosts.has(url.hostname.toLowerCase());\n}\n\n/** Parses a URL, returning null instead of throwing on malformed input. */\nfunction safeParseUrl(raw: string): URL | null {\n\ttry {\n\t\treturn new URL(raw.trim());\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** Builds a query string (`?a=1&b=2`) from defined entries, or '' when empty. */\nfunction buildQuery(params: Record<string, string>): string {\n\tconst entries: [string, string][] = Object.entries(params);\n\tif (entries.length === 0) return '';\n\tconst query: string = entries\n\t\t.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)\n\t\t.join('&');\n\treturn `?${query}`;\n}\n","/**\n * Video plugin types, configuration, and defaults.\n */\n\nimport { DEFAULT_VIDEO_PROVIDERS, type VideoProvider } from './VideoProviders.js';\n\n// --- Video Attributes ---\n\n/** Logical alignment of a video block within the content column. */\nexport type VideoAlign = 'start' | 'center' | 'end';\n\n/**\n * Structured video node attributes. The node never stores raw `<iframe>` HTML;\n * the live iframe is constructed at view time from `provider` + `videoId`. This\n * is the privacy and security keystone (see `ARCHITECTURE.md` / issue #142).\n */\nexport interface VideoAttrs {\n\t/** Provider id, e.g. `youtube` | `vimeo` | `dailymotion`. */\n\treadonly provider: string;\n\t/** Provider-validated video id. */\n\treadonly videoId: string;\n\t/** Privacy hash for unlisted videos (Vimeo). */\n\treadonly hash?: string;\n\t/** CSS aspect ratio, e.g. `16/9`; height always follows width from this. */\n\treadonly aspectRatio: string;\n\t/** Responsive width as a percentage of the content column. */\n\treadonly widthPercent: number;\n\t/** Logical alignment. */\n\treadonly align: VideoAlign;\n\t/**\n\t * Accessible name describing the video content (iframe `title`, figure label).\n\t * Required for a non-empty, descriptive accessible name (WCAG SC 4.1.2).\n\t */\n\treadonly title: string;\n\t/** Optional visible caption rendered as `<figcaption>`. */\n\treadonly caption?: string;\n\t/** Use privacy-enhanced host/params (nocookie / dnt). */\n\treadonly privacy: boolean;\n}\n\n// --- Keyboard Bindings ---\n\n/**\n * Configurable keyboard bindings for video 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 VideoKeymap {\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_VIDEO_KEYMAP: Readonly<Record<keyof VideoKeymap, 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\nimport type { VideoLocale } from './VideoLocale.js';\n\nexport interface VideoPluginConfig {\n\t/** Declarative provider registry. Default: YouTube, Vimeo, Dailymotion. */\n\treadonly providers: readonly VideoProvider[];\n\t/** Use the privacy-first facade (click-to-load). @default true */\n\treadonly facade: boolean;\n\t/**\n\t * Load the provider thumbnail in the facade. A provider thumbnail is itself a\n\t * third-party request, so it is off by default to preserve the\n\t * zero-contact-before-consent guarantee. @default false\n\t */\n\treadonly useProviderThumbnail: boolean;\n\t/** Use privacy-enhanced host/params (nocookie / dnt). @default true */\n\treadonly privacy: boolean;\n\t/** Aspect ratios offered in the editing UI. */\n\treadonly allowedAspectRatios: readonly string[];\n\t/** Default aspect ratio for newly inserted videos. */\n\treadonly defaultAspectRatio: string;\n\t/** Default responsive width (percent of content column). @default 100 */\n\treadonly defaultWidthPercent: number;\n\t/** Minimum responsive width (percent). @default 25 */\n\treadonly minWidthPercent: number;\n\t/** Percent to grow/shrink per small resize step. @default 10 */\n\treadonly widthStep: number;\n\t/** Percent to grow/shrink per large resize step. @default 25 */\n\treadonly widthStepLarge: number;\n\t/** Whether videos are resizable. @default true */\n\treadonly resizable: boolean;\n\t/** Customize keyboard bindings for video resize actions. */\n\treadonly keymap?: VideoKeymap;\n\t/** Locale override for user-facing strings. */\n\treadonly locale?: VideoLocale;\n}\n\nexport const DEFAULT_VIDEO_CONFIG: VideoPluginConfig = {\n\tproviders: DEFAULT_VIDEO_PROVIDERS,\n\tfacade: true,\n\tuseProviderThumbnail: false,\n\tprivacy: true,\n\tallowedAspectRatios: ['16/9', '4/3', '1/1', '9/16'],\n\tdefaultAspectRatio: '16/9',\n\tdefaultWidthPercent: 100,\n\tminWidthPercent: 25,\n\twidthStep: 10,\n\twidthStepLarge: 25,\n\tresizable: true,\n};\n\n// --- Shared constants ---\n\n/** Node type name for the video block. */\nexport const VIDEO_TYPE = 'video';\n\n/** Maximum responsive width (percent of content column). */\nexport const MAX_WIDTH_PERCENT = 100;\n\n// --- Value validators (CSS-injection-safe; values may come from imported HTML) ---\n\n/** A safe `<number>/<number>` ratio, e.g. `16/9` or `2.39 / 1`. */\nconst ASPECT_RATIO_PATTERN = /^\\d+(?:\\.\\d+)?\\s*\\/\\s*\\d+(?:\\.\\d+)?$/;\n\n/**\n * Validates an aspect-ratio string before it is used as a CSS value. Returns the\n * normalized ratio (`16 / 9`) when it is a safe `<num>/<num>` form, otherwise the\n * configured default. This is the guard that prevents CSS injection from an\n * imported `data-video-ratio` attribute.\n */\nexport function sanitizeAspectRatio(value: string | undefined, config: VideoPluginConfig): string {\n\tif (!value || !ASPECT_RATIO_PATTERN.test(value.trim())) return config.defaultAspectRatio;\n\tconst [w, h] = value.split('/');\n\treturn `${w?.trim()} / ${h?.trim()}`;\n}\n\n/** Clamps a responsive width percentage to `[minWidthPercent, 100]` and rounds it. */\nexport function clampWidthPercent(value: number, config: VideoPluginConfig): number {\n\tif (!Number.isFinite(value)) return config.defaultWidthPercent;\n\treturn Math.max(config.minWidthPercent, Math.min(MAX_WIDTH_PERCENT, Math.round(value)));\n}\n\n/** A video id shape shared by all built-in providers (alphanumeric, `_`, `-`). */\nconst SAFE_VIDEO_ID = /^[A-Za-z0-9_-]+$/;\n\n/** True when a video id is well-formed enough to build a clean embed URL. */\nexport function isSafeVideoId(value: string): boolean {\n\treturn value.length > 0 && value.length <= 64 && SAFE_VIDEO_ID.test(value);\n}\n\n/**\n * Normalizes a block's raw attributes into a fully-formed {@link VideoAttrs},\n * applying defaults and validating the ratio/width. Shared by the NodeSpec\n * renderer and the NodeView so both read attributes identically.\n */\nexport function normalizeVideoAttrs(\n\tattrs: Partial<VideoAttrs> | undefined,\n\tconfig: VideoPluginConfig,\n): VideoAttrs {\n\treturn {\n\t\tprovider: attrs?.provider ?? '',\n\t\tvideoId: attrs?.videoId ?? '',\n\t\t...(attrs?.hash ? { hash: attrs.hash } : {}),\n\t\taspectRatio: sanitizeAspectRatio(attrs?.aspectRatio, config),\n\t\twidthPercent: clampWidthPercent(attrs?.widthPercent ?? config.defaultWidthPercent, config),\n\t\talign: attrs?.align ?? 'center',\n\t\ttitle: attrs?.title ?? '',\n\t\t...(attrs?.caption ? { caption: attrs.caption } : {}),\n\t\tprivacy: attrs?.privacy ?? config.privacy,\n\t};\n}\n","/**\n * Video plugin commands: insert (root + table cell), source/caption/align/resize\n * updates, paste-to-embed replacement, and removal. Every content operation builds\n * an invertible transaction, so undo/redo works automatically. Mirrors the image\n * plugin's command shape for nested-context support.\n */\n\nimport { deleteNodeSelection } from '../../commands/NodeSelectionCommands.js';\nimport type { BlockAttrs, BlockNode } from '../../model/Document.js';\nimport {\n\tcreateBlockNode,\n\tgetBlockChildren,\n\tgetBlockText,\n\tisBlockNode,\n} from '../../model/Document.js';\nimport { createNodeSelection, isGapCursor, isNodeSelection } 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 VideoMatch, parseVideoUrl } from './VideoProviders.js';\nimport {\n\tVIDEO_TYPE,\n\ttype VideoAlign,\n\ttype VideoAttrs,\n\ttype VideoPluginConfig,\n\tclampWidthPercent,\n\tsanitizeAspectRatio,\n} from './VideoTypes.js';\n\n/** A contiguous text range, used to replace a pasted URL with an embed. */\nexport interface VideoTextRange {\n\treadonly blockId: BlockId;\n\treadonly start: number;\n\treadonly end: number;\n}\n\n/** Validated fields from the insert/edit form. */\nexport interface VideoEditInput {\n\treadonly url: string;\n\treadonly title: string;\n\treadonly caption: string;\n\treadonly aspectRatio: string;\n}\n\n/**\n * Builds full video attributes from validated form input, parsing the URL into a\n * provider/id (and hash). Returns null when the URL matches no provider.\n */\nexport function buildVideoAttrsFromForm(\n\tinput: VideoEditInput,\n\tconfig: VideoPluginConfig,\n): VideoAttrs | null {\n\tconst match: VideoMatch | null = parseVideoUrl(input.url, config.providers);\n\tif (!match) return null;\n\treturn {\n\t\tprovider: match.provider,\n\t\tvideoId: match.videoId,\n\t\t...(match.hash ? { hash: match.hash } : {}),\n\t\taspectRatio: sanitizeAspectRatio(input.aspectRatio, config),\n\t\twidthPercent: config.defaultWidthPercent,\n\t\talign: 'center',\n\t\ttitle: input.title,\n\t\t...(input.caption ? { caption: input.caption } : {}),\n\t\tprivacy: config.privacy,\n\t};\n}\n\n/** Converts structured video attributes into a plain block-attrs object. */\nfunction toBlockAttrs(attrs: VideoAttrs): BlockAttrs {\n\treturn {\n\t\tprovider: attrs.provider,\n\t\tvideoId: attrs.videoId,\n\t\taspectRatio: attrs.aspectRatio,\n\t\twidthPercent: attrs.widthPercent,\n\t\talign: attrs.align,\n\t\ttitle: attrs.title,\n\t\tprivacy: attrs.privacy,\n\t\t...(attrs.hash ? { hash: attrs.hash } : {}),\n\t\t...(attrs.caption ? { caption: attrs.caption } : {}),\n\t};\n}\n\n/** Copies block attributes into a mutable object, omitting the given keys. */\nfunction omitAttrs(\n\tattrs: BlockAttrs | undefined,\n\tkeys: readonly string[],\n): Record<string, string | number | boolean> {\n\tconst out: Record<string, string | number | boolean> = {};\n\tfor (const [key, value] of Object.entries(attrs ?? {})) {\n\t\tif (!keys.includes(key)) out[key] = value;\n\t}\n\treturn out;\n}\n\n/** Returns the currently selected video block and its node path, or null. */\nfunction selectedVideo(state: EditorState): { block: BlockNode; path: BlockId[] } | null {\n\tconst sel = state.selection;\n\tif (!isNodeSelection(sel)) return null;\n\tconst block: BlockNode | undefined = state.getBlock(sel.nodeId);\n\tif (!block || block.type !== VIDEO_TYPE) return null;\n\tconst path: BlockId[] | undefined = state.getNodePath(sel.nodeId);\n\tif (!path) return null;\n\treturn { block, path };\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\tconst path: BlockId[] | undefined = state.getNodePath(bid);\n\tif (!path) return undefined;\n\tfor (const id of path) {\n\t\tif (state.getBlock(id)?.type === 'table_cell') return id;\n\t}\n\treturn undefined;\n}\n\n// --- Insertion ---\n\n/**\n * Inserts a video block. Inside a table cell the video becomes the cell's child;\n * otherwise it is inserted after the anchor block at document root.\n */\nexport function insertVideo(context: PluginContext, attrs: VideoAttrs): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\tif (isGapCursor(sel)) return false;\n\n\tconst blockAttrs: BlockAttrs = toBlockAttrs(attrs);\n\tconst anchorBlockId: BlockId = isNodeSelection(sel) ? sel.nodeId : sel.anchor.blockId;\n\n\tconst cellId: BlockId | undefined = findTableCellAncestor(state, anchorBlockId);\n\tif (cellId) return insertVideoIntoCell(state, context, cellId, blockAttrs);\n\treturn insertVideoAtRoot(state, context, anchorBlockId, blockAttrs);\n}\n\n/** Inserts a video at document root after the anchor block, with a trailing paragraph. */\nfunction insertVideoAtRoot(\n\tstate: EditorState,\n\tcontext: PluginContext,\n\tanchorBlockId: BlockId,\n\tblockAttrs: BlockAttrs,\n): boolean {\n\tconst blockIndex: number = state.doc.children.findIndex((b) => b.id === anchorBlockId);\n\tif (blockIndex === -1) return false;\n\n\tconst videoBlock: BlockNode = createBlockNode(nodeType(VIDEO_TYPE), [], undefined, blockAttrs);\n\tconst trailingParagraph: BlockNode = createBlockNode(nodeType('paragraph'));\n\n\tconst tr = state\n\t\t.transaction('command')\n\t\t.insertNode([], blockIndex + 1, videoBlock)\n\t\t.insertNode([], blockIndex + 2, trailingParagraph)\n\t\t.setSelection(createNodeSelection(videoBlock.id, []))\n\t\t.build();\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Inserts a video as the sole content of a table cell. */\nfunction insertVideoIntoCell(\n\tstate: EditorState,\n\tcontext: PluginContext,\n\tcellId: BlockId,\n\tblockAttrs: BlockAttrs,\n): boolean {\n\tconst cellPath: BlockId[] | undefined = state.getNodePath(cellId);\n\tconst cell: BlockNode | undefined = state.getBlock(cellId);\n\tif (!cellPath || !cell) return false;\n\n\tconst videoBlock: BlockNode = createBlockNode(nodeType(VIDEO_TYPE), [], undefined, blockAttrs);\n\tconst builder = state.transaction('command');\n\n\tconst blockChildren: readonly BlockNode[] = getBlockChildren(cell);\n\tfor (let i = blockChildren.length - 1; i >= 0; i--) {\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) builder.removeNode(cellPath, rawIndex);\n\t}\n\n\tbuilder.insertNode(cellPath, 0, videoBlock);\n\tbuilder.setSelection(createNodeSelection(videoBlock.id, [...cellPath, videoBlock.id]));\n\tcontext.dispatch(builder.build());\n\treturn true;\n}\n\n/**\n * Replaces a pasted URL (the given text range) with a video embed in a single\n * transaction. When the range is the block's entire content, the empty paragraph\n * is replaced outright; otherwise the video is inserted after it. Used by the\n * ask-first paste flow.\n */\nexport function insertVideoReplacingRange(\n\tcontext: PluginContext,\n\trange: VideoTextRange,\n\tattrs: VideoAttrs,\n): boolean {\n\tconst state = context.getState();\n\tconst block: BlockNode | undefined = state.getBlock(range.blockId);\n\tif (!block) return false;\n\tconst loc = locateBlock(state, range.blockId);\n\tif (!loc) return false;\n\n\tconst remaining: number = Math.max(0, getBlockText(block).length - (range.end - range.start));\n\tconst replaceWhole: boolean = remaining === 0 && block.type === 'paragraph';\n\tconst videoBlock: BlockNode = createBlockNode(\n\t\tnodeType(VIDEO_TYPE),\n\t\t[],\n\t\tundefined,\n\t\ttoBlockAttrs(attrs),\n\t);\n\tconst selectionPath: BlockId[] =\n\t\tloc.parentPath.length === 0 ? [] : [...loc.parentPath, videoBlock.id];\n\n\tconst builder = state.transaction('command');\n\tif (replaceWhole) {\n\t\tbuilder.removeNode(loc.parentPath, loc.index);\n\t\tbuilder.insertNode(loc.parentPath, loc.index, videoBlock);\n\t\t// Keep something editable after a root-level embed that is now the last block.\n\t\tif (loc.parentPath.length === 0 && loc.index >= state.doc.children.length - 1) {\n\t\t\tbuilder.insertNode([], loc.index + 1, createBlockNode(nodeType('paragraph')));\n\t\t}\n\t} else {\n\t\tbuilder.deleteTextAt(range.blockId, range.start, range.end);\n\t\tbuilder.insertNode(loc.parentPath, loc.index + 1, videoBlock);\n\t}\n\tbuilder.setSelection(createNodeSelection(videoBlock.id, selectionPath));\n\tcontext.dispatch(builder.build());\n\treturn true;\n}\n\n/** Locates a block's parent path and its raw index within that parent. */\nfunction locateBlock(\n\tstate: EditorState,\n\tblockId: BlockId,\n): { parentPath: BlockId[]; index: number } | null {\n\tconst path: BlockId[] | undefined = state.getNodePath(blockId);\n\tif (!path || path.length === 0) return null;\n\n\tif (path.length === 1) {\n\t\tconst index: number = state.doc.children.findIndex((b) => b.id === blockId);\n\t\treturn index === -1 ? null : { parentPath: [], index };\n\t}\n\n\tconst parentId: BlockId | undefined = path[path.length - 2];\n\tconst parent: BlockNode | undefined = parentId ? state.getBlock(parentId) : undefined;\n\tif (!parent) return null;\n\tconst index: number = parent.children.findIndex((c) => isBlockNode(c) && c.id === blockId);\n\treturn index === -1 ? null : { parentPath: path.slice(0, -1), index };\n}\n\n// --- Attribute updates (operate on the selected video) ---\n\n/** Merges attributes onto the selected video, replacing the full attr set. */\nfunction applyVideoAttrs(context: PluginContext, attrs: BlockAttrs): boolean {\n\tconst state = context.getState();\n\tconst selected = selectedVideo(state);\n\tif (!selected) return false;\n\tcontext.dispatch(state.transaction('command').setNodeAttr(selected.path, attrs).build());\n\treturn true;\n}\n\n/** Updates the selected video's provider/id/hash (and privacy) from a parsed URL. */\nexport function setVideoSource(\n\tcontext: PluginContext,\n\tmatch: VideoMatch,\n\tprivacy: boolean,\n): boolean {\n\tconst selected = selectedVideo(context.getState());\n\tif (!selected) return false;\n\tconst next: Record<string, string | number | boolean> = omitAttrs(selected.block.attrs, ['hash']);\n\tnext.provider = match.provider;\n\tnext.videoId = match.videoId;\n\tnext.privacy = privacy;\n\tif (match.hash) next.hash = match.hash;\n\treturn applyVideoAttrs(context, next);\n}\n\n/** Sets the alignment of the selected video. */\nexport function setVideoAlign(context: PluginContext, align: VideoAlign): boolean {\n\tconst selected = selectedVideo(context.getState());\n\tif (!selected) return false;\n\treturn applyVideoAttrs(context, { ...(selected.block.attrs ?? {}), align });\n}\n\n/** Sets (or clears) the caption of the selected video. */\nexport function setVideoCaption(context: PluginContext, caption: string): boolean {\n\tconst selected = selectedVideo(context.getState());\n\tif (!selected) return false;\n\tconst next: Record<string, string | number | boolean> = omitAttrs(selected.block.attrs, [\n\t\t'caption',\n\t]);\n\tif (caption.trim()) next.caption = caption.trim();\n\treturn applyVideoAttrs(context, next);\n}\n\n/** Sets the accessible title of the selected video. */\nexport function setVideoTitle(context: PluginContext, title: string): boolean {\n\tconst selected = selectedVideo(context.getState());\n\tif (!selected) return false;\n\treturn applyVideoAttrs(context, { ...(selected.block.attrs ?? {}), title });\n}\n\n/** Sets the aspect ratio of the selected video. */\nexport function setVideoAspectRatio(context: PluginContext, aspectRatio: string): boolean {\n\tconst selected = selectedVideo(context.getState());\n\tif (!selected) return false;\n\treturn applyVideoAttrs(context, { ...(selected.block.attrs ?? {}), aspectRatio });\n}\n\n/**\n * Applies a full edit (URL, title, caption, aspect ratio) to the selected video\n * in a single undoable transaction. Returns false when nothing is selected or the\n * URL matches no provider.\n */\nexport function applyVideoEdit(\n\tcontext: PluginContext,\n\tinput: VideoEditInput,\n\tconfig: VideoPluginConfig,\n): boolean {\n\tconst selected = selectedVideo(context.getState());\n\tif (!selected) return false;\n\tconst match: VideoMatch | null = parseVideoUrl(input.url, config.providers);\n\tif (!match) return false;\n\n\tconst next: Record<string, string | number | boolean> = omitAttrs(selected.block.attrs, [\n\t\t'hash',\n\t\t'caption',\n\t]);\n\tnext.provider = match.provider;\n\tnext.videoId = match.videoId;\n\tnext.title = input.title;\n\tnext.aspectRatio = sanitizeAspectRatio(input.aspectRatio, config);\n\tif (match.hash) next.hash = match.hash;\n\tif (input.caption.trim()) next.caption = input.caption.trim();\n\treturn applyVideoAttrs(context, next);\n}\n\n/** Resizes the selected video by a width-percentage delta. */\nexport function resizeVideoByDelta(\n\tcontext: PluginContext,\n\tdelta: number,\n\tconfig: VideoPluginConfig,\n): boolean {\n\tconst selected = selectedVideo(context.getState());\n\tif (!selected) return false;\n\tconst current: number =\n\t\t(selected.block.attrs?.widthPercent as number | undefined) ?? config.defaultWidthPercent;\n\tconst next: number = clampWidthPercent(current + delta, config);\n\tif (next === current) return false;\n\treturn applyVideoAttrs(context, { ...(selected.block.attrs ?? {}), widthPercent: next });\n}\n\n/** Resets the selected video to the default responsive width. */\nexport function resetVideoSize(context: PluginContext, config: VideoPluginConfig): boolean {\n\tconst selected = selectedVideo(context.getState());\n\tif (!selected) return false;\n\treturn applyVideoAttrs(context, {\n\t\t...(selected.block.attrs ?? {}),\n\t\twidthPercent: config.defaultWidthPercent,\n\t});\n}\n\n/** Removes the currently selected video block. */\nexport function removeVideo(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tconst selected = selectedVideo(state);\n\tif (!selected) return false;\n\tconst tr = deleteNodeSelection(state, createNodeSelection(selected.block.id, selected.path));\n\tif (!tr) return false;\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Returns the selected video's current width percentage, or null. */\nexport function selectedVideoWidthPercent(\n\tstate: EditorState,\n\tconfig: VideoPluginConfig,\n): number | null {\n\tconst selected = selectedVideo(state);\n\tif (!selected) return null;\n\treturn (selected.block.attrs?.widthPercent as number | undefined) ?? config.defaultWidthPercent;\n}\n\n/** Registers the non-UI video commands (removal). Insert/resize are wired by the plugin. */\nexport function registerVideoCommands(context: PluginContext): void {\n\tcontext.registerCommand('removeVideo', () => removeVideo(context));\n}\n","/**\n * Shared insert/edit form for videos: URL, accessible title (required), optional\n * caption, and aspect ratio. Used both by the toolbar insert popup and the\n * on-selection edit panel.\n *\n * Accessibility: every field has a programmatic label, the title field is\n * `aria-required` and blocks submission until filled (the iframe accessible name\n * is a Level A requirement), and validation errors are surfaced through a\n * `role=\"alert\"` live region plus focus management.\n */\n\nimport type { VideoLocale } from './VideoLocale.js';\nimport { parseVideoUrl } from './VideoProviders.js';\nimport type { VideoPluginConfig } from './VideoTypes.js';\n\n/** Initial field values when editing an existing video. */\nexport interface VideoFormInitial {\n\treadonly url?: string;\n\treadonly title?: string;\n\treadonly caption?: string;\n\treadonly aspectRatio?: string;\n}\n\n/** Validated form output passed to the submit handler. */\nexport interface VideoFormValues {\n\treadonly url: string;\n\treadonly title: string;\n\treadonly caption: string;\n\treadonly aspectRatio: string;\n}\n\nexport interface VideoFormOptions {\n\treadonly mode: 'insert' | 'edit';\n\treadonly initial?: VideoFormInitial;\n\treadonly config: VideoPluginConfig;\n\treadonly locale: VideoLocale;\n\t/** Applies the change. The form has already validated URL + title. */\n\treadonly onSubmit: (values: VideoFormValues) => void;\n\treadonly onClose: () => void;\n}\n\nlet formIdCounter = 0;\n\n/** Returns a process-unique element id for label/aria associations. */\nfunction nextFieldId(prefix: string): string {\n\tformIdCounter += 1;\n\treturn `${prefix}-${formIdCounter}`;\n}\n\n/** Builds a labeled text field; returns the input element. */\nfunction appendField(\n\tcontainer: HTMLElement,\n\toptions: {\n\t\tlabel: string;\n\t\tariaLabel: string;\n\t\tplaceholder: string;\n\t\tvalue: string;\n\t\ttype: 'url' | 'text';\n\t\trequired?: boolean;\n\t\thint?: string;\n\t\tdescribedBy?: string;\n\t},\n): HTMLInputElement {\n\tconst id = nextFieldId('notectl-video-field');\n\tconst wrapper: HTMLDivElement = document.createElement('div');\n\twrapper.className = 'notectl-video-popup__field';\n\n\tconst label: HTMLLabelElement = document.createElement('label');\n\tlabel.className = 'notectl-video-popup__label';\n\tlabel.setAttribute('for', id);\n\tlabel.textContent = options.label;\n\twrapper.appendChild(label);\n\n\tconst input: HTMLInputElement = document.createElement('input');\n\tinput.id = id;\n\tinput.type = options.type;\n\tinput.value = options.value;\n\tinput.placeholder = options.placeholder;\n\tinput.className = 'notectl-video-popup__input';\n\tinput.setAttribute('aria-label', options.ariaLabel);\n\tif (options.required) input.setAttribute('aria-required', 'true');\n\n\tconst describedByIds: string[] = [];\n\tif (options.hint) {\n\t\tconst hintId = `${id}-hint`;\n\t\tconst hint: HTMLParagraphElement = document.createElement('p');\n\t\thint.id = hintId;\n\t\thint.className = 'notectl-video-popup__hint';\n\t\thint.textContent = options.hint;\n\t\twrapper.appendChild(hint);\n\t\tdescribedByIds.push(hintId);\n\t}\n\tif (options.describedBy) describedByIds.push(options.describedBy);\n\tif (describedByIds.length > 0) input.setAttribute('aria-describedby', describedByIds.join(' '));\n\n\twrapper.insertBefore(input, wrapper.children[1] ?? null);\n\tcontainer.appendChild(wrapper);\n\treturn input;\n}\n\n/** Builds the labeled aspect-ratio select. */\nfunction appendAspectRatioField(\n\tcontainer: HTMLElement,\n\tconfig: VideoPluginConfig,\n\tlocale: VideoLocale,\n\tvalue: string,\n): HTMLSelectElement {\n\tconst id = nextFieldId('notectl-video-field');\n\tconst wrapper: HTMLDivElement = document.createElement('div');\n\twrapper.className = 'notectl-video-popup__field';\n\n\tconst label: HTMLLabelElement = document.createElement('label');\n\tlabel.className = 'notectl-video-popup__label';\n\tlabel.setAttribute('for', id);\n\tlabel.textContent = locale.aspectRatioLabel;\n\twrapper.appendChild(label);\n\n\tconst select: HTMLSelectElement = document.createElement('select');\n\tselect.id = id;\n\tselect.className = 'notectl-video-popup__select';\n\tselect.setAttribute('aria-label', locale.aspectRatioAria);\n\n\tconst ratios: readonly string[] = config.allowedAspectRatios.includes(value)\n\t\t? config.allowedAspectRatios\n\t\t: [value, ...config.allowedAspectRatios];\n\tfor (const ratio of ratios) {\n\t\tconst option: HTMLOptionElement = document.createElement('option');\n\t\toption.value = ratio;\n\t\toption.textContent = ratio;\n\t\tif (ratio === value) option.selected = true;\n\t\tselect.appendChild(option);\n\t}\n\twrapper.appendChild(select);\n\tcontainer.appendChild(wrapper);\n\treturn select;\n}\n\n/** Renders the video insert/edit form into the given container. */\nexport function renderVideoForm(container: HTMLElement, options: VideoFormOptions): void {\n\tconst { config, locale, initial, mode } = options;\n\tcontainer.classList.add('notectl-video-popup');\n\n\tconst errorId = nextFieldId('notectl-video-error');\n\tconst error: HTMLParagraphElement = document.createElement('p');\n\terror.id = errorId;\n\terror.className = 'notectl-video-popup__error';\n\terror.setAttribute('role', 'alert');\n\n\tconst urlInput: HTMLInputElement = appendField(container, {\n\t\tlabel: locale.urlLabel,\n\t\tariaLabel: locale.urlAria,\n\t\tplaceholder: locale.urlPlaceholder,\n\t\tvalue: initial?.url ?? '',\n\t\ttype: 'url',\n\t\trequired: true,\n\t\tdescribedBy: errorId,\n\t});\n\tconst titleInput: HTMLInputElement = appendField(container, {\n\t\tlabel: locale.titleLabel,\n\t\tariaLabel: locale.titleAria,\n\t\tplaceholder: locale.titlePlaceholder,\n\t\tvalue: initial?.title ?? '',\n\t\ttype: 'text',\n\t\trequired: true,\n\t\thint: locale.titleHint,\n\t});\n\tconst captionInput: HTMLInputElement = appendField(container, {\n\t\tlabel: locale.captionLabel,\n\t\tariaLabel: locale.captionAria,\n\t\tplaceholder: locale.captionPlaceholder,\n\t\tvalue: initial?.caption ?? '',\n\t\ttype: 'text',\n\t});\n\tconst ratioSelect: HTMLSelectElement = appendAspectRatioField(\n\t\tcontainer,\n\t\tconfig,\n\t\tlocale,\n\t\tinitial?.aspectRatio ?? config.defaultAspectRatio,\n\t);\n\n\tcontainer.appendChild(error);\n\n\tconst actions: HTMLDivElement = document.createElement('div');\n\tactions.className = 'notectl-video-popup__actions';\n\n\tconst cancelBtn: HTMLButtonElement = document.createElement('button');\n\tcancelBtn.type = 'button';\n\tcancelBtn.className = 'notectl-video-popup__cancel';\n\tcancelBtn.textContent = locale.cancelButton;\n\n\tconst submitBtn: HTMLButtonElement = document.createElement('button');\n\tsubmitBtn.type = 'button';\n\tsubmitBtn.className = 'notectl-video-popup__submit';\n\tsubmitBtn.textContent = mode === 'edit' ? locale.updateButton : locale.insertButton;\n\tsubmitBtn.setAttribute('aria-label', mode === 'edit' ? locale.updateAria : locale.insertAria);\n\n\tactions.append(cancelBtn, submitBtn);\n\tcontainer.appendChild(actions);\n\n\tconst showError = (message: string, field: HTMLElement): void => {\n\t\terror.textContent = message;\n\t\tfield.focus();\n\t};\n\n\tconst submit = (): void => {\n\t\tconst url: string = urlInput.value.trim();\n\t\tif (!parseVideoUrl(url, config.providers)) {\n\t\t\tshowError(locale.invalidUrl, urlInput);\n\t\t\treturn;\n\t\t}\n\t\tconst title: string = titleInput.value.trim();\n\t\tif (!title) {\n\t\t\tshowError(locale.titleRequired, titleInput);\n\t\t\treturn;\n\t\t}\n\t\terror.textContent = '';\n\t\toptions.onSubmit({\n\t\t\turl,\n\t\t\ttitle,\n\t\t\tcaption: captionInput.value.trim(),\n\t\t\taspectRatio: ratioSelect.value,\n\t\t});\n\t\toptions.onClose();\n\t};\n\n\tcancelBtn.addEventListener('mousedown', (e: MouseEvent) => e.preventDefault());\n\tcancelBtn.addEventListener('click', (e: MouseEvent) => {\n\t\te.preventDefault();\n\t\toptions.onClose();\n\t});\n\tsubmitBtn.addEventListener('mousedown', (e: MouseEvent) => e.preventDefault());\n\tsubmitBtn.addEventListener('click', (e: MouseEvent) => {\n\t\te.preventDefault();\n\t\tsubmit();\n\t});\n\n\tfor (const input of [urlInput, titleInput, captionInput]) {\n\t\tinput.addEventListener('keydown', (e: KeyboardEvent) => {\n\t\t\tif (e.key === 'Enter') {\n\t\t\t\te.preventDefault();\n\t\t\t\tsubmit();\n\t\t\t}\n\t\t});\n\t}\n\n\trequestAnimationFrame(() => urlInput.focus());\n}\n","/**\n * Floating panel for inserting and editing videos, hosting the shared video form\n * outside the editable/reconciled DOM. Mirrors `FormulaOverlay`: a focusable\n * dialog positioned at the caret (insert) or the video's bounding rect (edit),\n * promoted to the browser top layer so it escapes host-page stacking contexts.\n */\n\nimport { isNodeSelection } from '../../model/Selection.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport type { PluginContext } from '../Plugin.js';\nimport { promoteToTopLayer } from '../shared/PopupPositioning.js';\nimport {\n\ttype VideoEditInput,\n\ttype VideoTextRange,\n\tapplyVideoEdit,\n\tbuildVideoAttrsFromForm,\n\tinsertVideo,\n\tinsertVideoReplacingRange,\n} from './VideoCommands.js';\nimport type { VideoLocale } from './VideoLocale.js';\nimport { type VideoFormInitial, renderVideoForm } from './VideoPopup.js';\nimport { buildWatchUrlForMatch } from './VideoProviders.js';\nimport {\n\tVIDEO_TYPE,\n\ttype VideoAttrs,\n\ttype VideoPluginConfig,\n\tnormalizeVideoAttrs,\n} from './VideoTypes.js';\n\nconst PANEL_MARGIN = 8;\n\nexport class VideoEditOverlay {\n\tprivate panel: HTMLElement | null = null;\n\tprivate outsideHandler: ((e: MouseEvent) => void) | null = null;\n\n\tconstructor(\n\t\tprivate readonly context: PluginContext,\n\t\tprivate readonly config: VideoPluginConfig,\n\t\tprivate readonly locale: VideoLocale,\n\t) {}\n\n\t/** Whether the overlay is currently open. */\n\tget isOpen(): boolean {\n\t\treturn this.panel !== null;\n\t}\n\n\t/** Opens the insert form at the caret. */\n\topenInsert(): void {\n\t\tif (this.context.isReadOnly()) return;\n\t\tthis.open({\n\t\t\trect: caretRect(),\n\t\t\tmode: 'insert',\n\t\t\tlabel: this.locale.insertDialogLabel,\n\t\t\tonSubmit: (input: VideoEditInput) => {\n\t\t\t\tconst attrs: VideoAttrs | null = buildVideoAttrsFromForm(input, this.config);\n\t\t\t\tif (attrs) insertVideo(this.context, attrs);\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Opens the insert form pre-filled with a pasted URL; on submit the URL text\n\t * range is replaced with the embed (ask-first paste flow). Cancelling leaves the\n\t * URL as plain text.\n\t */\n\topenInsertReplacingRange(range: VideoTextRange, prefillUrl: string): void {\n\t\tif (this.context.isReadOnly()) return;\n\t\tthis.open({\n\t\t\trect: caretRect(),\n\t\t\tmode: 'insert',\n\t\t\tlabel: this.locale.insertDialogLabel,\n\t\t\tinitial: { url: prefillUrl },\n\t\t\tonSubmit: (input: VideoEditInput) => {\n\t\t\t\tconst attrs: VideoAttrs | null = buildVideoAttrsFromForm(input, this.config);\n\t\t\t\tif (attrs) insertVideoReplacingRange(this.context, range, attrs);\n\t\t\t},\n\t\t});\n\t}\n\n\t/** Opens the edit form for the currently selected video, pre-filled. */\n\topenEditForSelected(): void {\n\t\tif (this.context.isReadOnly()) return;\n\t\tconst state = this.context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return;\n\t\tconst block = state.getBlock(sel.nodeId);\n\t\tif (!block || block.type !== VIDEO_TYPE) return;\n\n\t\tconst attrs: VideoAttrs = normalizeVideoAttrs(block.attrs, this.config);\n\t\tconst url: string =\n\t\t\tbuildWatchUrlForMatch(\n\t\t\t\t{\n\t\t\t\t\tprovider: attrs.provider,\n\t\t\t\t\tvideoId: attrs.videoId,\n\t\t\t\t\t...(attrs.hash ? { hash: attrs.hash } : {}),\n\t\t\t\t},\n\t\t\t\tthis.config.providers,\n\t\t\t) ?? '';\n\t\tconst initial: VideoFormInitial = {\n\t\t\turl,\n\t\t\ttitle: attrs.title,\n\t\t\tcaption: attrs.caption ?? '',\n\t\t\taspectRatio: attrs.aspectRatio,\n\t\t};\n\n\t\tthis.open({\n\t\t\trect: this.videoRect(sel.nodeId),\n\t\t\tmode: 'edit',\n\t\t\tlabel: this.locale.editDialogLabel,\n\t\t\tinitial,\n\t\t\tonSubmit: (input: VideoEditInput) => {\n\t\t\t\tapplyVideoEdit(this.context, input, this.config);\n\t\t\t},\n\t\t});\n\t}\n\n\t/** Closes the overlay, optionally returning focus to the editor. */\n\tclose(returnFocus: boolean): void {\n\t\tif (!this.panel) return;\n\t\tif (this.outsideHandler) {\n\t\t\tdocument.removeEventListener('mousedown', this.outsideHandler, true);\n\t\t\tthis.outsideHandler = null;\n\t\t}\n\t\tthis.panel.remove();\n\t\tthis.panel = null;\n\t\tif (returnFocus) this.context.getContainer().focus();\n\t}\n\n\tprivate open(config: {\n\t\trect: DOMRect | null;\n\t\tmode: 'insert' | 'edit';\n\t\tlabel: string;\n\t\tinitial?: VideoFormInitial;\n\t\tonSubmit: (input: VideoEditInput) => void;\n\t}): void {\n\t\tthis.close(false);\n\t\tconst panel: HTMLDivElement = document.createElement('div');\n\t\tpanel.className = 'notectl-video-overlay';\n\t\tpanel.setAttribute('role', 'dialog');\n\t\tpanel.setAttribute('aria-modal', 'false');\n\t\tpanel.setAttribute('aria-label', config.label);\n\t\tthis.panel = panel;\n\n\t\trenderVideoForm(panel, {\n\t\t\tmode: config.mode,\n\t\t\tinitial: config.initial,\n\t\t\tconfig: this.config,\n\t\t\tlocale: this.locale,\n\t\t\tonSubmit: config.onSubmit,\n\t\t\tonClose: () => this.close(true),\n\t\t});\n\n\t\tpanel.addEventListener('keydown', (e: KeyboardEvent) => {\n\t\t\tif (e.key === 'Escape') {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tthis.close(true);\n\t\t\t}\n\t\t});\n\n\t\tthis.context.getPluginContainer('top').appendChild(panel);\n\t\tpromoteToTopLayer(panel);\n\t\tpositionPanel(panel, config.rect);\n\t\tthis.installOutsideHandler();\n\t}\n\n\tprivate videoRect(nodeId: BlockId): DOMRect | null {\n\t\tconst el: Element | null = this.context\n\t\t\t.getContainer()\n\t\t\t.querySelector(`[data-block-id=\"${nodeId}\"]`);\n\t\treturn el ? el.getBoundingClientRect() : null;\n\t}\n\n\tprivate installOutsideHandler(): void {\n\t\tconst handler = (e: MouseEvent): void => {\n\t\t\tif (this.panel && !e.composedPath().includes(this.panel)) {\n\t\t\t\tthis.close(false);\n\t\t\t}\n\t\t};\n\t\tthis.outsideHandler = handler;\n\t\trequestAnimationFrame(() => {\n\t\t\tif (this.outsideHandler) document.addEventListener('mousedown', handler, true);\n\t\t});\n\t}\n}\n\n/** Returns the bounding rect of the current DOM selection caret, if any. */\nfunction caretRect(): DOMRect | null {\n\tconst selection: Selection | null = window.getSelection();\n\tif (!selection || selection.rangeCount === 0) return null;\n\tconst rect: DOMRect = selection.getRangeAt(0).getBoundingClientRect();\n\tif (rect.width === 0 && rect.height === 0 && rect.top === 0 && rect.left === 0) return null;\n\treturn rect;\n}\n\n/** Positions the panel below the anchor rect, clamped to the viewport. */\nfunction positionPanel(panel: HTMLElement, rect: DOMRect | null): void {\n\tconst anchorTop: number = rect ? rect.bottom : window.innerHeight / 3;\n\tconst anchorLeft: number = rect ? rect.left : window.innerWidth / 3;\n\tconst width: number = panel.offsetWidth || 320;\n\tconst maxLeft: number = window.innerWidth - width - PANEL_MARGIN;\n\tconst left: number = Math.max(PANEL_MARGIN, Math.min(anchorLeft, maxLeft));\n\tconst maxTop: number = window.innerHeight - panel.offsetHeight - PANEL_MARGIN;\n\tconst top: number = Math.min(anchorTop + PANEL_MARGIN, Math.max(PANEL_MARGIN, maxTop));\n\tpanel.style.left = `${Math.round(left)}px`;\n\tpanel.style.top = `${Math.round(top)}px`;\n}\n","/**\n * The ask-first paste affordance: a small, keyboard-operable popover shown after\n * a video URL is pasted. It offers to turn the link into an embed rather than\n * silently rewriting the content under the caret (which is disorienting for\n * assistive-technology users). The change is announced separately via aria-live.\n */\n\nimport { promoteToTopLayer } from '../shared/PopupPositioning.js';\nimport type { VideoLocale } from './VideoLocale.js';\n\nconst PROMPT_MARGIN = 8;\n\nexport interface EmbedPromptController {\n\tclose(): void;\n}\n\nexport interface EmbedPromptOptions {\n\t/** Shadow-DOM container the popover mounts into (registered styles apply). */\n\treadonly container: HTMLElement;\n\t/** Anchor rect (the pasted URL / caret); centered in the viewport when null. */\n\treadonly rect: DOMRect | null;\n\treadonly locale: VideoLocale;\n\t/** Invoked when the user accepts the embed. */\n\treadonly onEmbed: () => void;\n\t/** Invoked when the user keeps the link (dismiss / Escape / outside click). */\n\treadonly onDismiss: () => void;\n}\n\n/** Shows the embed prompt and returns a controller to close it programmatically. */\nexport function showEmbedPrompt(options: EmbedPromptOptions): EmbedPromptController {\n\tconst { locale } = options;\n\tconst popover: HTMLDivElement = document.createElement('div');\n\tpopover.className = 'notectl-video-embed-prompt';\n\tpopover.setAttribute('role', 'dialog');\n\tpopover.setAttribute('aria-label', locale.embedPrompt);\n\n\tconst text: HTMLSpanElement = document.createElement('span');\n\ttext.className = 'notectl-video-embed-prompt__text';\n\ttext.textContent = locale.embedPrompt;\n\n\tconst embedBtn: HTMLButtonElement = document.createElement('button');\n\tembedBtn.type = 'button';\n\tembedBtn.className = 'notectl-video-embed-prompt__embed';\n\tembedBtn.textContent = locale.embedConfirm;\n\n\tconst dismissBtn: HTMLButtonElement = document.createElement('button');\n\tdismissBtn.type = 'button';\n\tdismissBtn.className = 'notectl-video-embed-prompt__dismiss';\n\tdismissBtn.textContent = locale.embedDismiss;\n\n\tpopover.append(text, embedBtn, dismissBtn);\n\n\tlet outsideHandler: ((e: MouseEvent) => void) | null = null;\n\tlet closed = false;\n\n\tconst close = (): void => {\n\t\tif (closed) return;\n\t\tclosed = true;\n\t\tif (outsideHandler) {\n\t\t\tdocument.removeEventListener('mousedown', outsideHandler, true);\n\t\t\toutsideHandler = null;\n\t\t}\n\t\tpopover.remove();\n\t};\n\n\tconst finish = (action: () => void): void => {\n\t\tclose();\n\t\taction();\n\t};\n\n\tembedBtn.addEventListener('mousedown', (e: MouseEvent) => e.preventDefault());\n\tembedBtn.addEventListener('click', (e: MouseEvent) => {\n\t\te.preventDefault();\n\t\tfinish(options.onEmbed);\n\t});\n\tdismissBtn.addEventListener('mousedown', (e: MouseEvent) => e.preventDefault());\n\tdismissBtn.addEventListener('click', (e: MouseEvent) => {\n\t\te.preventDefault();\n\t\tfinish(options.onDismiss);\n\t});\n\tpopover.addEventListener('keydown', (e: KeyboardEvent) => {\n\t\tif (e.key === 'Escape') {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tfinish(options.onDismiss);\n\t\t}\n\t});\n\n\toptions.container.appendChild(popover);\n\tpromoteToTopLayer(popover);\n\tpositionPrompt(popover, options.rect);\n\n\toutsideHandler = (e: MouseEvent): void => {\n\t\tif (!e.composedPath().includes(popover)) finish(options.onDismiss);\n\t};\n\trequestAnimationFrame(() => {\n\t\tif (outsideHandler) document.addEventListener('mousedown', outsideHandler, true);\n\t\t// Move focus to the primary action so keyboard and screen-reader users can\n\t\t// act immediately; the aria-live announcement explains the choice.\n\t\tembedBtn.focus();\n\t});\n\n\treturn { close };\n}\n\n/** Positions the prompt just below the anchor rect, clamped to the viewport. */\nfunction positionPrompt(popover: HTMLElement, rect: DOMRect | null): void {\n\tconst anchorTop: number = rect ? rect.bottom : window.innerHeight / 3;\n\tconst anchorLeft: number = rect ? rect.left : window.innerWidth / 3;\n\tconst width: number = popover.offsetWidth || 240;\n\tconst maxLeft: number = window.innerWidth - width - PROMPT_MARGIN;\n\tconst left: number = Math.max(PROMPT_MARGIN, Math.min(anchorLeft, maxLeft));\n\tconst maxTop: number = window.innerHeight - popover.offsetHeight - PROMPT_MARGIN;\n\tconst top: number = Math.min(anchorTop + PROMPT_MARGIN, Math.max(PROMPT_MARGIN, maxTop));\n\tpopover.style.left = `${Math.round(left)}px`;\n\tpopover.style.top = `${Math.round(top)}px`;\n}\n","/** Locale interface and default English locale for the VideoPlugin. */\n\nimport { type LocaleModuleMap, loadLocaleModule } from '../shared/LocaleLoader.js';\n\n// --- Locale Interface ---\n\nexport interface VideoLocale {\n\t// Toolbar\n\treadonly insertVideo: string;\n\treadonly insertVideoTooltip: string;\n\n\t// Insert / edit popup — fields\n\treadonly urlLabel: string;\n\treadonly urlPlaceholder: string;\n\treadonly urlAria: string;\n\treadonly titleLabel: string;\n\treadonly titlePlaceholder: string;\n\treadonly titleAria: string;\n\treadonly titleHint: string;\n\treadonly captionLabel: string;\n\treadonly captionPlaceholder: string;\n\treadonly captionAria: string;\n\treadonly aspectRatioLabel: string;\n\treadonly aspectRatioAria: string;\n\n\t// Popup — actions and dialog labels\n\treadonly insertButton: string;\n\treadonly insertAria: string;\n\treadonly updateButton: string;\n\treadonly updateAria: string;\n\treadonly cancelButton: string;\n\treadonly insertDialogLabel: string;\n\treadonly editDialogLabel: string;\n\n\t// Popup — validation\n\treadonly invalidUrl: string;\n\treadonly titleRequired: string;\n\n\t// Facade (click-to-load)\n\treadonly play: (title: string) => string;\n\treadonly loading: string;\n\treadonly providerBadge: (provider: string) => string;\n\treadonly closePlayer: string;\n\n\t// Figure / NodeView accessible name\n\treadonly videoAria: (provider: string, title: string) => string;\n\n\t// Selection + resize announcements\n\treadonly videoSelected: string;\n\treadonly videoSelectedWithTitle: (title: string) => string;\n\treadonly resizeHint: (shrink: string, grow: string) => string;\n\treadonly keyboardResizeHint: (shrink: string, grow: string) => string;\n\treadonly videoResized: (percent: number) => string;\n\treadonly resetToDefaultSize: string;\n\n\t// Player enter / exit\n\treadonly enteredPlayer: (title: string) => string;\n\treadonly exitedPlayer: string;\n\n\t// On-selection edit toolbar\n\treadonly videoOptions: string;\n\treadonly editVideo: string;\n\treadonly alignStart: string;\n\treadonly alignCenter: string;\n\treadonly alignEnd: string;\n\treadonly deleteVideo: string;\n\n\t// Ask-first paste affordance\n\treadonly embedPrompt: string;\n\treadonly embedConfirm: string;\n\treadonly embedDismiss: string;\n\treadonly embedOfferAnnounce: (provider: string) => string;\n\treadonly embeddedAnnounce: string;\n}\n\n// --- Default English Locale ---\n\nexport const VIDEO_LOCALE_EN: VideoLocale = {\n\tinsertVideo: 'Insert Video',\n\tinsertVideoTooltip: 'Insert Video',\n\n\turlLabel: 'Video URL',\n\turlPlaceholder: 'https://www.youtube.com/watch?v=...',\n\turlAria: 'Video URL',\n\ttitleLabel: 'Title',\n\ttitlePlaceholder: 'Describe the video',\n\ttitleAria: 'Video title',\n\ttitleHint: 'Describes the video for screen readers. Required.',\n\tcaptionLabel: 'Caption',\n\tcaptionPlaceholder: 'Optional visible caption',\n\tcaptionAria: 'Video caption',\n\taspectRatioLabel: 'Aspect ratio',\n\taspectRatioAria: 'Video aspect ratio',\n\n\tinsertButton: 'Insert',\n\tinsertAria: 'Insert video',\n\tupdateButton: 'Update',\n\tupdateAria: 'Update video',\n\tcancelButton: 'Cancel',\n\tinsertDialogLabel: 'Insert video',\n\teditDialogLabel: 'Edit video',\n\n\tinvalidUrl: 'Enter a YouTube, Vimeo, or Dailymotion video URL.',\n\ttitleRequired: 'Enter a title so screen readers can describe the video.',\n\n\tplay: (title: string) => (title ? `Play video: ${title}` : 'Play video'),\n\tloading: 'Loading video...',\n\tproviderBadge: (provider: string) => `${provider} video`,\n\tclosePlayer: 'Close video player',\n\n\tvideoAria: (provider: string, title: string) =>\n\t\ttitle ? `${provider} video: ${title}` : `${provider} video`,\n\n\tvideoSelected: 'Video selected.',\n\tvideoSelectedWithTitle: (title: string) => `Video selected: ${title}.`,\n\tresizeHint: (shrink: string, grow: string) => `${shrink} / ${grow} to resize.`,\n\tkeyboardResizeHint: (shrink: string, grow: string) => `${shrink} / ${grow} to resize`,\n\tvideoResized: (percent: number) => `Video resized to ${percent} percent width.`,\n\tresetToDefaultSize: 'Video reset to full width.',\n\n\tenteredPlayer: (title: string) =>\n\t\ttitle\n\t\t\t? `Playing ${title}. Press Escape to return to the document.`\n\t\t\t: 'Playing video. Press Escape to return to the document.',\n\texitedPlayer: 'Returned to the document.',\n\n\tvideoOptions: 'Video options',\n\teditVideo: 'Edit video',\n\talignStart: 'Align left',\n\talignCenter: 'Align center',\n\talignEnd: 'Align right',\n\tdeleteVideo: 'Delete video',\n\n\tembedPrompt: 'Embed this video?',\n\tembedConfirm: 'Embed',\n\tembedDismiss: 'Keep as link',\n\tembedOfferAnnounce: (provider: string) =>\n\t\t`${provider} link pasted. Press Embed to turn it into a video, or continue editing to keep it as a link.`,\n\tembeddedAnnounce: 'Video embedded.',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: LocaleModuleMap<VideoLocale> = import.meta.glob<{\n\tdefault: VideoLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadVideoLocale(lang: string): Promise<VideoLocale> {\n\treturn loadLocaleModule(localeModules, lang, VIDEO_LOCALE_EN);\n}\n","/**\n * Shared DOM helpers for the video figure shell, used by both the NodeSpec\n * `toDOM` (static fallback) and the interactive `VideoNodeView`. Keeping the\n * structure, class names, and sizing in one place keeps the two renderers in\n * sync so reconciliation never thrashes.\n */\n\nimport { setStyleProperty } from '../../style/StyleRuntime.js';\nimport type { VideoAlign } from './VideoTypes.js';\n\n/** Logical alignment → figure modifier class. */\nexport const VIDEO_ALIGNMENT_CLASSES: Readonly<Record<VideoAlign, string>> = {\n\tstart: 'notectl-video--start',\n\tcenter: 'notectl-video--center',\n\tend: 'notectl-video--end',\n};\n\n/** Replaces the alignment modifier class on a video figure. */\nexport function applyVideoAlignment(figure: HTMLElement, align: VideoAlign): void {\n\tfor (const cls of Object.values(VIDEO_ALIGNMENT_CLASSES)) figure.classList.remove(cls);\n\tconst next: string = VIDEO_ALIGNMENT_CLASSES[align] ?? VIDEO_ALIGNMENT_CLASSES.center;\n\tfigure.classList.add(next);\n}\n\n/**\n * Applies responsive sizing to the video frame: a validated `aspect-ratio`\n * (height always follows width, so the embed can never be distorted) and a width\n * as a percentage of the content column. Both values must be pre-validated by the\n * caller (`sanitizeAspectRatio` / `clampWidthPercent`).\n */\nexport function applyVideoFrameSizing(\n\tframe: HTMLElement,\n\taspectRatio: string,\n\twidthPercent: number,\n): void {\n\tsetStyleProperty(frame, 'aspect-ratio', aspectRatio);\n\tsetStyleProperty(frame, 'width', `${widthPercent}%`);\n}\n","/**\n * NodeSpec for the `video` block: a void, selectable embed.\n *\n * The node stores structured attributes, never raw `<iframe>` HTML. The live\n * iframe is built only at view time (see `VideoNodeView`). Serialization uses a\n * privacy-preserving, progressive-enhancement `<figure>`:\n *\n * - In a notectl renderer, `data-video-*` lets the plugin upgrade the figure to\n * facade then iframe.\n * - In a \"dumb\" context (email, plain HTML), it degrades to a labeled link (and\n * an opt-in thumbnail), contacting no third party on load. The privacy promise\n * therefore holds outside the editor too — a plain `<iframe>` export would\n * leak it on every page that renders the export.\n *\n * `parseHTML` reconstructs the node from `data-video-*`, and additionally tolerates\n * a known-provider embed `<iframe>` on import (host-validated by the sanitize hook).\n */\n\nimport { escapeAttr, escapeHTML } from '../../model/HTMLUtils.js';\nimport type { NodeSpec } from '../../model/NodeSpec.js';\nimport { createBlockElement } from '../../view/DomUtils.js';\nimport type { VideoLocale } from './VideoLocale.js';\nimport {\n\ttype VideoMatch,\n\tbuildThumbnailForMatch,\n\tbuildWatchUrlForMatch,\n\tfindProvider,\n\tparseVideoUrl,\n\tproviderLabel,\n} from './VideoProviders.js';\nimport {\n\ttype VideoAlign,\n\ttype VideoAttrs,\n\ttype VideoPluginConfig,\n\tclampWidthPercent,\n\tisSafeVideoId,\n\tnormalizeVideoAttrs,\n\tsanitizeAspectRatio,\n} from './VideoTypes.js';\nimport { applyVideoAlignment, applyVideoFrameSizing } from './VideoViewHelpers.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface NodeAttrRegistry {\n\t\tvideo: {\n\t\t\tprovider: string;\n\t\t\tvideoId: string;\n\t\t\thash?: string;\n\t\t\taspectRatio: string;\n\t\t\twidthPercent: number;\n\t\t\talign: VideoAlign;\n\t\t\ttitle: string;\n\t\t\tcaption?: string;\n\t\t\tprivacy: boolean;\n\t\t};\n\t}\n}\n\nconst VIDEO_HASH_PATTERN = /^[A-Za-z0-9]+$/;\n/** Parse rules run above the image plugin's generic `figure` rule (default 50). */\nconst VIDEO_PARSE_PRIORITY = 60;\n\n/** Builds a {@link VideoMatch} from node attributes. */\nfunction matchFromAttrs(attrs: VideoAttrs): VideoMatch {\n\treturn {\n\t\tprovider: attrs.provider,\n\t\tvideoId: attrs.videoId,\n\t\t...(attrs.hash ? { hash: attrs.hash } : {}),\n\t};\n}\n\n/**\n * Creates the `video` NodeSpec, closing over the plugin config so URL building\n * and provider lookups stay declarative and dependency-free.\n */\nexport function createVideoNodeSpec(\n\tconfig: VideoPluginConfig,\n\tlocale: VideoLocale,\n): NodeSpec<'video'> {\n\tconst providers = config.providers;\n\n\treturn {\n\t\ttype: 'video',\n\t\tgroup: 'block',\n\t\tisVoid: true,\n\t\tselectable: true,\n\t\tattrs: {\n\t\t\tprovider: { default: '' },\n\t\t\tvideoId: { default: '' },\n\t\t\thash: { default: '' },\n\t\t\taspectRatio: { default: config.defaultAspectRatio },\n\t\t\twidthPercent: { default: config.defaultWidthPercent },\n\t\t\talign: { default: 'center' },\n\t\t\ttitle: { default: '' },\n\t\t\tcaption: { default: '' },\n\t\t\tprivacy: { default: config.privacy },\n\t\t},\n\n\t\ttoDOM(node) {\n\t\t\tconst attrs: VideoAttrs = normalizeVideoAttrs(node.attrs as Partial<VideoAttrs>, config);\n\t\t\tconst figure: HTMLElement = createBlockElement('figure', node.id);\n\t\t\tfigure.className = 'notectl-video';\n\t\t\tfigure.setAttribute('data-void', 'true');\n\t\t\tfigure.setAttribute('data-selectable', 'true');\n\t\t\tfigure.setAttribute('data-video-provider', attrs.provider);\n\t\t\tfigure.setAttribute('data-video-id', attrs.videoId);\n\t\t\tif (attrs.hash) figure.setAttribute('data-video-hash', attrs.hash);\n\t\t\tapplyVideoAlignment(figure, attrs.align);\n\t\t\tfigure.setAttribute(\n\t\t\t\t'aria-label',\n\t\t\t\tlocale.videoAria(providerLabel(attrs.provider, providers), attrs.title),\n\t\t\t);\n\n\t\t\tconst frame: HTMLDivElement = document.createElement('div');\n\t\t\tframe.className = 'notectl-video__frame';\n\t\t\tapplyVideoFrameSizing(frame, attrs.aspectRatio, attrs.widthPercent);\n\n\t\t\t// Static, accessible fallback: a labeled link to the public watch URL.\n\t\t\t// The interactive facade is layered on by VideoNodeView when present.\n\t\t\tconst watchUrl: string | null = buildWatchUrlForMatch(matchFromAttrs(attrs), providers);\n\t\t\tif (watchUrl) {\n\t\t\t\tconst link: HTMLAnchorElement = document.createElement('a');\n\t\t\t\tlink.className = 'notectl-video__fallback-link';\n\t\t\t\tlink.href = watchUrl;\n\t\t\t\tlink.rel = 'noopener noreferrer';\n\t\t\t\tlink.textContent = attrs.title || watchUrl;\n\t\t\t\tframe.appendChild(link);\n\t\t\t}\n\t\t\tfigure.appendChild(frame);\n\n\t\t\tif (attrs.caption) {\n\t\t\t\tconst figcaption: HTMLElement = document.createElement('figcaption');\n\t\t\t\tfigcaption.className = 'notectl-video__caption';\n\t\t\t\tfigcaption.textContent = attrs.caption;\n\t\t\t\tfigure.appendChild(figcaption);\n\t\t\t}\n\t\t\treturn figure;\n\t\t},\n\n\t\ttoHTML(node) {\n\t\t\tconst attrs: VideoAttrs = normalizeVideoAttrs(node.attrs as Partial<VideoAttrs>, config);\n\t\t\tconst match: VideoMatch = matchFromAttrs(attrs);\n\t\t\tconst watchUrl: string | null = buildWatchUrlForMatch(match, providers);\n\n\t\t\tconst dataAttrs: string[] = [\n\t\t\t\t`data-video-provider=\"${escapeAttr(attrs.provider)}\"`,\n\t\t\t\t`data-video-id=\"${escapeAttr(attrs.videoId)}\"`,\n\t\t\t\t`data-video-ratio=\"${escapeAttr(attrs.aspectRatio)}\"`,\n\t\t\t\t`data-video-width=\"${attrs.widthPercent}\"`,\n\t\t\t\t`data-video-privacy=\"${attrs.privacy ? 'true' : 'false'}\"`,\n\t\t\t];\n\t\t\tif (attrs.hash) dataAttrs.push(`data-video-hash=\"${escapeAttr(attrs.hash)}\"`);\n\t\t\tif (attrs.title) dataAttrs.push(`data-video-title=\"${escapeAttr(attrs.title)}\"`);\n\n\t\t\tconst thumbnail: string | undefined = config.useProviderThumbnail\n\t\t\t\t? buildThumbnailForMatch(match, providers)\n\t\t\t\t: undefined;\n\t\t\tconst linkInner: string = thumbnail\n\t\t\t\t? `<img src=\"${escapeAttr(thumbnail)}\" alt=\"\">`\n\t\t\t\t: escapeHTML(attrs.title || watchUrl || '');\n\t\t\tconst body: string = watchUrl\n\t\t\t\t? `<a href=\"${escapeAttr(watchUrl)}\" rel=\"noopener noreferrer\">${linkInner}</a>`\n\t\t\t\t: linkInner;\n\t\t\tconst caption: string = attrs.caption\n\t\t\t\t? `<figcaption>${escapeHTML(attrs.caption)}</figcaption>`\n\t\t\t\t: '';\n\n\t\t\treturn `<figure ${dataAttrs.join(' ')}>${body}${caption}</figure>`;\n\t\t},\n\n\t\tparseHTML: [\n\t\t\t{\n\t\t\t\ttag: 'figure',\n\t\t\t\tpriority: VIDEO_PARSE_PRIORITY,\n\t\t\t\tgetAttrs: (el: HTMLElement) => parseVideoFigure(el, config),\n\t\t\t},\n\t\t\t{\n\t\t\t\ttag: 'iframe',\n\t\t\t\tpriority: VIDEO_PARSE_PRIORITY,\n\t\t\t\tgetAttrs: (el: HTMLElement) => parseVideoIframe(el, config),\n\t\t\t},\n\t\t],\n\n\t\t// Tags/attrs needed for the figure export round-trip plus tolerant iframe\n\t\t// import. The iframe host is additionally validated by the sanitize hook;\n\t\t// declaring `iframe` here only lets DOMPurify keep it long enough for that\n\t\t// hook and the parse rule to run. `data-video-*` pass via ALLOW_DATA_ATTR.\n\t\tsanitize: {\n\t\t\ttags: ['figure', 'figcaption', 'a', 'img', 'iframe'],\n\t\t\tattrs: [\n\t\t\t\t'href',\n\t\t\t\t'rel',\n\t\t\t\t'src',\n\t\t\t\t'alt',\n\t\t\t\t'title',\n\t\t\t\t'allow',\n\t\t\t\t'allowfullscreen',\n\t\t\t\t'referrerpolicy',\n\t\t\t\t'loading',\n\t\t\t\t'width',\n\t\t\t\t'height',\n\t\t\t\t'frameborder',\n\t\t\t\t'class',\n\t\t\t\t'style',\n\t\t\t],\n\t\t},\n\t};\n}\n\n/** Reconstructs video attributes from a `data-video-*` figure, or false. */\nfunction parseVideoFigure(\n\tel: HTMLElement,\n\tconfig: VideoPluginConfig,\n): Record<string, string | number | boolean> | false {\n\tconst provider: string | null = el.getAttribute('data-video-provider');\n\tconst videoId: string | null = el.getAttribute('data-video-id');\n\tif (!provider || !videoId) return false;\n\tif (!isSafeVideoId(videoId)) return false;\n\tif (!findProvider(provider, config.providers)) return false;\n\n\tconst title: string =\n\t\tel.getAttribute('data-video-title') ??\n\t\tel.querySelector('a')?.textContent?.trim() ??\n\t\tel.getAttribute('aria-label') ??\n\t\t'';\n\tconst caption: string = el.querySelector('figcaption')?.textContent?.trim() ?? '';\n\tconst widthAttr: string | null = el.getAttribute('data-video-width');\n\n\tconst attrs: Record<string, string | number | boolean> = {\n\t\tprovider,\n\t\tvideoId,\n\t\taspectRatio: sanitizeAspectRatio(el.getAttribute('data-video-ratio') ?? undefined, config),\n\t\twidthPercent: clampWidthPercent(\n\t\t\twidthAttr ? Number.parseFloat(widthAttr) : config.defaultWidthPercent,\n\t\t\tconfig,\n\t\t),\n\t\talign: 'center',\n\t\ttitle,\n\t\tprivacy: el.getAttribute('data-video-privacy') !== 'false',\n\t};\n\tconst hash: string | null = el.getAttribute('data-video-hash');\n\tif (hash && VIDEO_HASH_PATTERN.test(hash)) attrs.hash = hash;\n\tif (caption) attrs.caption = caption;\n\treturn attrs;\n}\n\n/** Reconstructs video attributes from a known-provider embed `<iframe>`, or false. */\nfunction parseVideoIframe(\n\tel: HTMLElement,\n\tconfig: VideoPluginConfig,\n): Record<string, string | number | boolean> | false {\n\tconst src: string = el.getAttribute('src') ?? '';\n\tconst match: VideoMatch | null = parseVideoUrl(src, config.providers);\n\tif (!match || !isSafeVideoId(match.videoId)) return false;\n\n\tconst attrs: Record<string, string | number | boolean> = {\n\t\tprovider: match.provider,\n\t\tvideoId: match.videoId,\n\t\taspectRatio: ratioFromIframeDimensions(el, config),\n\t\twidthPercent: config.defaultWidthPercent,\n\t\talign: 'center',\n\t\ttitle: el.getAttribute('title') ?? '',\n\t\tprivacy: config.privacy,\n\t};\n\tif (match.hash) attrs.hash = match.hash;\n\treturn attrs;\n}\n\n/** Derives a validated aspect ratio from an iframe's width/height, else the default. */\nfunction ratioFromIframeDimensions(el: HTMLElement, config: VideoPluginConfig): string {\n\tconst width: number = Number.parseFloat(el.getAttribute('width') ?? '');\n\tconst height: number = Number.parseFloat(el.getAttribute('height') ?? '');\n\tif (Number.isFinite(width) && Number.isFinite(height) && width > 0 && height > 0) {\n\t\treturn sanitizeAspectRatio(`${width}/${height}`, config);\n\t}\n\treturn config.defaultAspectRatio;\n}\n","/**\n * Privacy-first facade (click-to-load) for the video NodeView.\n *\n * Until the user activates the embed there is NO iframe in the DOM and zero\n * contact with the provider — the GDPR / Schrems II safe default. Activation,\n * playback, and exit are pure view state: they never dispatch a transaction, so\n * \"play\" never enters the undo stack.\n *\n * The iframe is built with `createElement` + `setAttribute` (never from an HTML\n * string), so no attacker-controllable markup is ever passed through `innerHTML`.\n * Autoplay is only ever requested in response to the explicit facade click, and\n * is suppressed under `prefers-reduced-motion` — so it can never be an\n * autoplay-on-load (WCAG F93) violation.\n */\n\nimport { setStyleProperty } from '../../style/StyleRuntime.js';\nimport type { VideoLocale } from './VideoLocale.js';\nimport { buildEmbedUrlForMatch, buildThumbnailForMatch, providerLabel } from './VideoProviders.js';\nimport type { VideoMatch } from './VideoProviders.js';\nimport type { VideoAttrs, VideoPluginConfig } from './VideoTypes.js';\n\nconst PLAY_ICON =\n\t'<svg viewBox=\"0 0 68 48\" width=\"48\" height=\"34\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M66.5 7.7c-.8-2.9-2.5-5.4-5.4-6.2C55.8.1 34 0 34 0S12.2.1 6.9 1.5C4 2.3 2.3 4.8 1.5 7.7.1 13 0 24 0 24s.1 11 1.5 16.3c.8 2.9 2.5 5.4 5.4 6.2C12.2 47.9 34 48 34 48s21.8-.1 27.1-1.5c2.9-.8 4.6-3.3 5.4-6.2C67.9 35 68 24 68 24s-.1-11-1.5-16.3z\" fill=\"currentColor\"/><path d=\"M45 24 27 14v20z\" fill=\"#fff\"/></svg>';\n\nconst CLOSE_ICON =\n\t'<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M19 6.4 17.6 5 12 10.6 6.4 5 5 6.4 10.6 12 5 17.6 6.4 19 12 13.4 17.6 19 19 17.6 13.4 12z\" fill=\"currentColor\"/></svg>';\n\n/** True when the user prefers reduced motion (guarded for non-browser test envs). */\nfunction prefersReducedMotion(): boolean {\n\treturn window.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false;\n}\n\n/** Builds the embed iframe for the given attributes via DOM APIs (never innerHTML). */\nfunction buildPlayerIframe(\n\tattrs: VideoAttrs,\n\tconfig: VideoPluginConfig,\n\tlocale: VideoLocale,\n): HTMLIFrameElement {\n\tconst match: VideoMatch = {\n\t\tprovider: attrs.provider,\n\t\tvideoId: attrs.videoId,\n\t\t...(attrs.hash ? { hash: attrs.hash } : {}),\n\t};\n\tconst src: string =\n\t\tbuildEmbedUrlForMatch(match, config.providers, {\n\t\t\tprivacy: attrs.privacy,\n\t\t\tautoplay: !prefersReducedMotion(),\n\t\t}) ?? '';\n\n\tconst iframe: HTMLIFrameElement = document.createElement('iframe');\n\tiframe.className = 'notectl-video__iframe';\n\tiframe.setAttribute('src', src);\n\t// A non-empty, descriptive iframe name is a Level A requirement (SC 4.1.2).\n\tiframe.setAttribute(\n\t\t'title',\n\t\tattrs.title || locale.providerBadge(providerLabel(attrs.provider, config.providers)),\n\t);\n\tiframe.setAttribute('allow', 'autoplay; fullscreen; picture-in-picture; encrypted-media');\n\tiframe.setAttribute('allowfullscreen', 'true');\n\tiframe.setAttribute('referrerpolicy', 'no-referrer');\n\tiframe.setAttribute('loading', 'lazy');\n\tiframe.setAttribute('frameborder', '0');\n\treturn iframe;\n}\n\n/**\n * Owns the facade ↔ player lifecycle for a single video frame. Construction\n * renders the facade; `activate()` swaps in the iframe; `deactivate()` restores\n * the facade. All transitions are view-only.\n */\nexport class VideoFacadeController {\n\tprivate readonly frame: HTMLElement;\n\tprivate readonly getAttrs: () => VideoAttrs;\n\tprivate readonly config: VideoPluginConfig;\n\tprivate readonly locale: VideoLocale;\n\tprivate readonly announce: (text: string) => void;\n\n\tprivate facadeButton: HTMLButtonElement | null = null;\n\tprivate player: HTMLElement | null = null;\n\tprivate iframe: HTMLIFrameElement | null = null;\n\tprivate escapeHandler: ((e: KeyboardEvent) => void) | null = null;\n\t/** Snapshot of the embed-relevant attributes currently rendered. */\n\tprivate renderedKey = '';\n\n\tconstructor(options: {\n\t\tframe: HTMLElement;\n\t\tgetAttrs: () => VideoAttrs;\n\t\tconfig: VideoPluginConfig;\n\t\tlocale: VideoLocale;\n\t\tannounce: (text: string) => void;\n\t}) {\n\t\tthis.frame = options.frame;\n\t\tthis.getAttrs = options.getAttrs;\n\t\tthis.config = options.config;\n\t\tthis.locale = options.locale;\n\t\tthis.announce = options.announce;\n\t\tthis.renderFacade();\n\t}\n\n\t/** Whether the player iframe is currently mounted. */\n\tget isActive(): boolean {\n\t\treturn this.player !== null;\n\t}\n\n\t/** Embed-relevant attribute snapshot; a change means facade/iframe must refresh. */\n\tprivate facadeKey(attrs: VideoAttrs): string {\n\t\treturn [\n\t\t\tattrs.provider,\n\t\t\tattrs.videoId,\n\t\t\tattrs.hash ?? '',\n\t\t\tattrs.privacy,\n\t\t\tattrs.title,\n\t\t\tthis.config.useProviderThumbnail,\n\t\t].join('|');\n\t}\n\n\t/** (Re)builds the facade play button and poster from current attributes. */\n\trenderFacade(): void {\n\t\tthis.facadeButton?.remove();\n\t\tconst attrs: VideoAttrs = this.getAttrs();\n\t\tthis.renderedKey = this.facadeKey(attrs);\n\n\t\tconst button: HTMLButtonElement = document.createElement('button');\n\t\tbutton.type = 'button';\n\t\tbutton.className = 'notectl-video__facade';\n\t\tbutton.setAttribute('aria-label', this.locale.play(attrs.title));\n\n\t\tconst poster: HTMLSpanElement = document.createElement('span');\n\t\tposter.className = 'notectl-video__poster';\n\t\tposter.setAttribute('aria-hidden', 'true');\n\t\tif (this.config.useProviderThumbnail) {\n\t\t\tconst thumbnail: string | undefined = buildThumbnailForMatch(\n\t\t\t\t{ provider: attrs.provider, videoId: attrs.videoId },\n\t\t\t\tthis.config.providers,\n\t\t\t);\n\t\t\tif (thumbnail) setStyleProperty(poster, 'background-image', `url(\"${thumbnail}\")`);\n\t\t}\n\n\t\tconst icon: HTMLSpanElement = document.createElement('span');\n\t\ticon.className = 'notectl-video__play-icon';\n\t\ticon.setAttribute('aria-hidden', 'true');\n\t\ticon.innerHTML = PLAY_ICON;\n\n\t\tconst badge: HTMLSpanElement = document.createElement('span');\n\t\tbadge.className = 'notectl-video__badge';\n\t\tbadge.setAttribute('aria-hidden', 'true');\n\t\tbadge.textContent = this.locale.providerBadge(\n\t\t\tproviderLabel(attrs.provider, this.config.providers),\n\t\t);\n\n\t\tbutton.append(poster, icon, badge);\n\t\t// Stop selection mousedown so pressing Play plays instead of node-selecting;\n\t\t// clicking the surrounding frame still selects the node.\n\t\tbutton.addEventListener('mousedown', (e: MouseEvent) => e.stopPropagation());\n\t\tbutton.addEventListener('click', (e: MouseEvent) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tthis.activate();\n\t\t});\n\n\t\tthis.facadeButton = button;\n\t\tthis.frame.insertBefore(button, this.frame.firstChild);\n\t}\n\n\t/**\n\t * Refreshes after an attribute change. Re-renders the facade label/poster, or\n\t * rebuilds the active iframe when the embed source changed. No-ops when nothing\n\t * relevant changed, so unrelated state updates never steal focus from the facade.\n\t */\n\tupdate(): void {\n\t\tconst attrs: VideoAttrs = this.getAttrs();\n\t\tconst key: string = this.facadeKey(attrs);\n\t\tif (key === this.renderedKey) return;\n\t\tthis.renderedKey = key;\n\n\t\tif (this.isActive && this.iframe) {\n\t\t\tconst next: HTMLIFrameElement = buildPlayerIframe(attrs, this.config, this.locale);\n\t\t\tthis.iframe.replaceWith(next);\n\t\t\tthis.iframe = next;\n\t\t\treturn;\n\t\t}\n\t\tthis.renderFacade();\n\t}\n\n\t/** Builds the iframe, moves focus into the player, and announces the change. */\n\tactivate(): void {\n\t\tif (this.isActive || !this.facadeButton) return;\n\t\tconst attrs: VideoAttrs = this.getAttrs();\n\n\t\tconst player: HTMLDivElement = document.createElement('div');\n\t\tplayer.className = 'notectl-video__player';\n\n\t\tconst exit: HTMLButtonElement = document.createElement('button');\n\t\texit.type = 'button';\n\t\texit.className = 'notectl-video__exit';\n\t\texit.setAttribute('aria-label', this.locale.closePlayer);\n\t\texit.innerHTML = CLOSE_ICON;\n\t\texit.addEventListener('mousedown', (e: MouseEvent) => e.stopPropagation());\n\t\texit.addEventListener('click', (e: MouseEvent) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tthis.deactivate(true);\n\t\t});\n\n\t\tconst iframe: HTMLIFrameElement = buildPlayerIframe(attrs, this.config, this.locale);\n\n\t\t// Exit button precedes the iframe so Shift+Tab out of the player reaches a\n\t\t// reliable, same-document return control (the cross-origin iframe can swallow\n\t\t// Escape once focus is inside it).\n\t\tplayer.append(exit, iframe);\n\t\tthis.facadeButton.remove();\n\t\tthis.facadeButton = null;\n\t\tthis.frame.insertBefore(player, this.frame.firstChild);\n\t\tthis.player = player;\n\t\tthis.iframe = iframe;\n\n\t\tthis.escapeHandler = (e: KeyboardEvent): void => {\n\t\t\tif (e.key !== 'Escape') return;\n\t\t\te.stopPropagation();\n\t\t\tthis.deactivate(true);\n\t\t};\n\t\tthis.frame.addEventListener('keydown', this.escapeHandler);\n\n\t\tiframe.focus();\n\t\tthis.announce(this.locale.enteredPlayer(attrs.title));\n\t}\n\n\t/** Tears down the iframe and restores the facade. */\n\tdeactivate(returnFocus: boolean): void {\n\t\tif (!this.player) return;\n\t\tif (this.escapeHandler) {\n\t\t\tthis.frame.removeEventListener('keydown', this.escapeHandler);\n\t\t\tthis.escapeHandler = null;\n\t\t}\n\t\tthis.player.remove();\n\t\tthis.player = null;\n\t\tthis.iframe = null;\n\t\tthis.renderFacade();\n\t\tif (returnFocus) this.facadeButton?.focus();\n\t\tthis.announce(this.locale.exitedPlayer);\n\t}\n\n\t/** Removes all DOM and listeners. */\n\tdestroy(): void {\n\t\tif (this.escapeHandler) {\n\t\t\tthis.frame.removeEventListener('keydown', this.escapeHandler);\n\t\t\tthis.escapeHandler = null;\n\t\t}\n\t\tthis.player?.remove();\n\t\tthis.player = null;\n\t\tthis.iframe = null;\n\t\tthis.facadeButton?.remove();\n\t\tthis.facadeButton = null;\n\t}\n}\n","/**\n * Pointer resize overlay for a selected video.\n *\n * Because the embed's aspect ratio is locked (height always follows width), only\n * the responsive width percentage changes — so the overlay exposes two side\n * handles rather than four corners, which communicates \"resize width\" honestly.\n * The handles are decorative (`aria-hidden`): keyboard resize is provided by the\n * plugin's shortcuts with live-region announcements, the accessible path.\n */\n\nimport { getStyleNonceForNode } from '../../style/StyleRuntime.js';\n\ntype SideHandle = 'w' | 'e';\n\nconst HANDLES: readonly SideHandle[] = ['w', 'e'];\n/** +1 means dragging right grows width; -1 means dragging left grows it. */\nconst HANDLE_X_SIGN: Readonly<Record<SideHandle, 1 | -1>> = { w: -1, e: 1 };\n\n/** Callbacks the overlay uses to read geometry and commit changes. */\nexport interface VideoResizeCallbacks {\n\treadonly minPercent: number;\n\tgetWidthPercent(): number;\n\t/** Width of the 100%-reference container (the figure / content column). */\n\tgetReferenceWidth(): number;\n\tisRtl(): boolean;\n\t/** Applies a width live during drag (no transaction). */\n\tapplyLiveWidth(percent: number): void;\n\t/** Commits the final width as an undoable transaction. */\n\tcommit(percent: number): void;\n\t/** Formats a percentage for the live size indicator. */\n\tformatPercent(percent: number): string;\n}\n\nlet activeCursorStyle: HTMLStyleElement | null = null;\n\n/** Forces an `ew-resize` cursor document-wide during a drag and disables selection. */\nfunction setGlobalResizeCursor(referenceNode: Node): void {\n\tclearGlobalResizeCursor();\n\tactiveCursorStyle = document.createElement('style');\n\tconst nonce: string | undefined = getStyleNonceForNode(referenceNode);\n\tif (nonce) activeCursorStyle.setAttribute('nonce', nonce);\n\tactiveCursorStyle.textContent = '*{cursor:ew-resize!important;user-select:none!important}';\n\tdocument.head.appendChild(activeCursorStyle);\n}\n\nfunction clearGlobalResizeCursor(): void {\n\tactiveCursorStyle?.remove();\n\tactiveCursorStyle = null;\n}\n\n/** A mounted resize overlay with a teardown handle. */\nexport interface VideoResizeOverlay {\n\treadonly element: HTMLElement;\n\tdestroy(): void;\n}\n\n/**\n * Builds the resize overlay (two side handles + live size indicator + optional\n * keyboard hint) and wires pointer dragging. Returns the element to append and a\n * `destroy` that detaches global listeners.\n */\nexport function createVideoResizeOverlay(\n\tcallbacks: VideoResizeCallbacks,\n\tkeyboardHint: string,\n): VideoResizeOverlay {\n\tconst overlay: HTMLDivElement = document.createElement('div');\n\toverlay.className = 'notectl-video__resize-overlay';\n\toverlay.setAttribute('data-notectl-no-print', '');\n\n\tconst indicator: HTMLDivElement = document.createElement('div');\n\tindicator.className = 'notectl-video__size-indicator';\n\toverlay.appendChild(indicator);\n\n\tlet detachMove: (() => void) | null = null;\n\n\tfor (const position of HANDLES) {\n\t\tconst handle: HTMLDivElement = document.createElement('div');\n\t\thandle.className = `notectl-video__resize-handle notectl-video__resize-handle--${position}`;\n\t\thandle.setAttribute('aria-hidden', 'true');\n\t\tattachHandle(handle, position, overlay, indicator, callbacks, (fn) => {\n\t\t\tdetachMove = fn;\n\t\t});\n\t\toverlay.appendChild(handle);\n\t}\n\n\tif (keyboardHint) {\n\t\tconst hint: HTMLDivElement = document.createElement('div');\n\t\thint.className = 'notectl-video__keyboard-hint';\n\t\thint.setAttribute('aria-hidden', 'true');\n\t\thint.textContent = keyboardHint;\n\t\toverlay.appendChild(hint);\n\t}\n\n\treturn {\n\t\telement: overlay,\n\t\tdestroy(): void {\n\t\t\tdetachMove?.();\n\t\t\tclearGlobalResizeCursor();\n\t\t},\n\t};\n}\n\n/** Wires a single side handle's pointer drag. */\nfunction attachHandle(\n\thandle: HTMLElement,\n\tposition: SideHandle,\n\toverlay: HTMLElement,\n\tindicator: HTMLElement,\n\tcallbacks: VideoResizeCallbacks,\n\tregisterDetach: (fn: () => void) => void,\n): void {\n\tlet startX = 0;\n\tlet startPercent = 0;\n\tlet referenceWidth = 0;\n\tlet currentPercent = 0;\n\tlet xSign: 1 | -1 = HANDLE_X_SIGN[position];\n\n\tconst onPointerMove = (e: PointerEvent): void => {\n\t\tconst deltaPx: number = (e.clientX - startX) * xSign;\n\t\tconst deltaPercent: number = referenceWidth > 0 ? (deltaPx / referenceWidth) * 100 : 0;\n\t\tcurrentPercent = clamp(startPercent + deltaPercent, callbacks.minPercent);\n\t\tcallbacks.applyLiveWidth(currentPercent);\n\t\tindicator.textContent = callbacks.formatPercent(Math.round(currentPercent));\n\t};\n\n\tconst onPointerUp = (e: PointerEvent): void => {\n\t\tdocument.removeEventListener('pointermove', onPointerMove);\n\t\tdocument.removeEventListener('pointerup', onPointerUp);\n\t\toverlay.classList.remove('notectl-video__resize-overlay--active');\n\t\tindicator.classList.remove('notectl-video__size-indicator--visible');\n\t\tclearGlobalResizeCursor();\n\t\tcallbacks.commit(Math.round(currentPercent));\n\t\t(e.target as HTMLElement | null)?.releasePointerCapture?.(e.pointerId);\n\t};\n\n\tregisterDetach(() => {\n\t\tdocument.removeEventListener('pointermove', onPointerMove);\n\t\tdocument.removeEventListener('pointerup', onPointerUp);\n\t});\n\n\thandle.addEventListener('pointerdown', (e: PointerEvent) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tstartX = e.clientX;\n\t\tstartPercent = callbacks.getWidthPercent();\n\t\tcurrentPercent = startPercent;\n\t\treferenceWidth = callbacks.getReferenceWidth();\n\t\txSign = callbacks.isRtl() ? (-HANDLE_X_SIGN[position] as 1 | -1) : HANDLE_X_SIGN[position];\n\n\t\toverlay.classList.add('notectl-video__resize-overlay--active');\n\t\tindicator.textContent = callbacks.formatPercent(Math.round(startPercent));\n\t\tindicator.classList.add('notectl-video__size-indicator--visible');\n\t\tsetGlobalResizeCursor(overlay);\n\n\t\t(e.target as HTMLElement).setPointerCapture(e.pointerId);\n\t\tdocument.addEventListener('pointermove', onPointerMove);\n\t\tdocument.addEventListener('pointerup', onPointerUp);\n\t});\n}\n\n/** Clamps a percentage to `[min, 100]`. */\nfunction clamp(value: number, min: number): number {\n\treturn Math.max(min, Math.min(100, value));\n}\n","/**\n * Floating toolbar shown when a video is selected: edit, align, and delete. All\n * controls are real `<button>`s with localized accessible names, grouped in a\n * `role=\"toolbar\"`. Pointer interaction never disturbs the node selection\n * (mousedown is suppressed), so the toolbar stays usable while the video is held.\n */\n\nimport type { VideoLocale } from './VideoLocale.js';\nimport type { VideoAlign } from './VideoTypes.js';\n\n/** Context-bound actions the toolbar invokes. */\nexport interface VideoToolbarActions {\n\tedit(): void;\n\talign(align: VideoAlign): void;\n\tremove(): void;\n}\n\nexport interface VideoSelectionToolbar {\n\treadonly element: HTMLElement;\n\tupdate(align: VideoAlign): void;\n\tdestroy(): void;\n}\n\nconst ICONS = {\n\tedit: '<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a1 1 0 0 0 0-1.41l-2.34-2.34a1 1 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z\" fill=\"currentColor\"/></svg>',\n\talignStart:\n\t\t'<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M3 4h18v2H3V4zm0 7h12v2H3v-2zm0 7h18v2H3v-2zm0-3.5h12v-2H3v2z\" fill=\"currentColor\"/></svg>',\n\talignCenter:\n\t\t'<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M3 4h18v2H3V4zm3 7h12v2H6v-2zm-3 7h18v2H3v-2zm3-3.5h12v-2H6v2z\" fill=\"currentColor\"/></svg>',\n\talignEnd:\n\t\t'<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M3 4h18v2H3V4zm6 7h12v2H9v-2zm-6 7h18v2H3v-2zm6-3.5h12v-2H9v2z\" fill=\"currentColor\"/></svg>',\n\tremove:\n\t\t'<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M6 19a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z\" fill=\"currentColor\"/></svg>',\n} as const;\n\n/** Builds a toolbar button, suppressing the selection-clearing mousedown. */\nfunction button(label: string, icon: string, onActivate: () => void): HTMLButtonElement {\n\tconst btn: HTMLButtonElement = document.createElement('button');\n\tbtn.type = 'button';\n\tbtn.className = 'notectl-video__tool';\n\tbtn.setAttribute('aria-label', label);\n\tbtn.title = label;\n\tbtn.innerHTML = icon;\n\tbtn.addEventListener('mousedown', (e: MouseEvent) => e.preventDefault());\n\tbtn.addEventListener('click', (e: MouseEvent) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tonActivate();\n\t});\n\treturn btn;\n}\n\n/** Creates the on-selection video toolbar. */\nexport function createVideoSelectionToolbar(options: {\n\tlocale: VideoLocale;\n\tactions: VideoToolbarActions;\n\tinitialAlign: VideoAlign;\n}): VideoSelectionToolbar {\n\tconst { locale, actions } = options;\n\n\tconst toolbar: HTMLDivElement = document.createElement('div');\n\ttoolbar.className = 'notectl-video__toolbar';\n\ttoolbar.setAttribute('role', 'toolbar');\n\ttoolbar.setAttribute('aria-label', locale.videoOptions);\n\ttoolbar.setAttribute('data-notectl-no-print', '');\n\ttoolbar.addEventListener('mousedown', (e: MouseEvent) => e.stopPropagation());\n\n\tconst editBtn: HTMLButtonElement = button(locale.editVideo, ICONS.edit, () => actions.edit());\n\n\tconst alignButtons: Readonly<Record<VideoAlign, HTMLButtonElement>> = {\n\t\tstart: button(locale.alignStart, ICONS.alignStart, () => actions.align('start')),\n\t\tcenter: button(locale.alignCenter, ICONS.alignCenter, () => actions.align('center')),\n\t\tend: button(locale.alignEnd, ICONS.alignEnd, () => actions.align('end')),\n\t};\n\n\tconst removeBtn: HTMLButtonElement = button(locale.deleteVideo, ICONS.remove, () =>\n\t\tactions.remove(),\n\t);\n\n\tconst separator = (): HTMLSpanElement => {\n\t\tconst sep: HTMLSpanElement = document.createElement('span');\n\t\tsep.className = 'notectl-video__tool-separator';\n\t\tsep.setAttribute('aria-hidden', 'true');\n\t\treturn sep;\n\t};\n\n\ttoolbar.append(\n\t\teditBtn,\n\t\tseparator(),\n\t\talignButtons.start,\n\t\talignButtons.center,\n\t\talignButtons.end,\n\t\tseparator(),\n\t\tremoveBtn,\n\t);\n\n\tconst update = (align: VideoAlign): void => {\n\t\tfor (const key of ['start', 'center', 'end'] as const) {\n\t\t\tconst active: boolean = key === align;\n\t\t\talignButtons[key].classList.toggle('notectl-video__tool--active', active);\n\t\t\talignButtons[key].setAttribute('aria-pressed', active ? 'true' : 'false');\n\t\t}\n\t};\n\tupdate(options.initialAlign);\n\n\treturn {\n\t\telement: toolbar,\n\t\tupdate,\n\t\tdestroy(): void {\n\t\t\ttoolbar.remove();\n\t\t},\n\t};\n}\n","/**\n * NodeView factory for video blocks.\n *\n * Renders a `<figure>` with a responsive, ratio-locked frame, layers the\n * click-to-load facade on top, manages the selection state and the pointer\n * resize overlay, and keeps everything in sync with attribute updates. The live\n * iframe lifecycle lives entirely in {@link VideoFacadeController}.\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 { setStyleProperty } from '../../style/StyleRuntime.js';\nimport type { NodeView, NodeViewFactory } from '../../view/NodeView.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { VideoFacadeController } from './VideoFacade.js';\nimport type { VideoLocale } from './VideoLocale.js';\nimport { providerLabel } from './VideoProviders.js';\nimport { type VideoResizeOverlay, createVideoResizeOverlay } from './VideoResize.js';\nimport {\n\ttype VideoSelectionToolbar,\n\ttype VideoToolbarActions,\n\tcreateVideoSelectionToolbar,\n} from './VideoSelectionToolbar.js';\nimport {\n\ttype VideoAttrs,\n\ttype VideoKeymap,\n\ttype VideoPluginConfig,\n\tnormalizeVideoAttrs,\n} from './VideoTypes.js';\nimport { applyVideoAlignment, applyVideoFrameSizing } from './VideoViewHelpers.js';\n\n/** Dependencies the factory closes over (the NodeView API itself is fixed). */\nexport interface VideoNodeViewOptions {\n\treadonly config: VideoPluginConfig;\n\treadonly locale: VideoLocale;\n\treadonly resolvedKeymap: Readonly<Record<keyof VideoKeymap, string | null>>;\n\treadonly announce: (text: string) => void;\n\t/** Context-bound edit/align/remove actions for the on-selection toolbar. */\n\treadonly actions: VideoToolbarActions;\n}\n\n/** Builds the visual keyboard-resize hint from the resolved keymap. */\nfunction buildKeyboardHint(\n\tresolvedKeymap: Readonly<Record<keyof VideoKeymap, string | null>>,\n\tlocale: VideoLocale,\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 video blocks. */\nexport function createVideoNodeViewFactory(options: VideoNodeViewOptions): NodeViewFactory {\n\tconst { config, locale, resolvedKeymap, announce, actions } = options;\n\n\treturn (\n\t\tnode: BlockNode,\n\t\tgetState: () => EditorState,\n\t\tdispatch: (tr: Transaction) => void,\n\t): NodeView => {\n\t\tconst figure: HTMLElement = document.createElement('figure');\n\t\tfigure.className = 'notectl-video';\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 frame: HTMLDivElement = document.createElement('div');\n\t\tframe.className = 'notectl-video__frame';\n\t\tfigure.appendChild(frame);\n\n\t\tlet currentNodeId: BlockId = node.id;\n\t\tlet currentAttrs: VideoAttrs = normalizeVideoAttrs(node.attrs as Partial<VideoAttrs>, config);\n\t\tlet captionEl: HTMLElement | null = null;\n\t\tlet resizeOverlay: VideoResizeOverlay | null = null;\n\t\tlet toolbar: VideoSelectionToolbar | null = null;\n\n\t\tconst facade = new VideoFacadeController({\n\t\t\tframe,\n\t\t\tgetAttrs: () => currentAttrs,\n\t\t\tconfig,\n\t\t\tlocale,\n\t\t\tannounce,\n\t\t});\n\n\t\tfunction updateCaption(caption: string | undefined): void {\n\t\t\tif (caption) {\n\t\t\t\tif (!captionEl) {\n\t\t\t\t\tcaptionEl = document.createElement('figcaption');\n\t\t\t\t\tcaptionEl.className = 'notectl-video__caption';\n\t\t\t\t\tfigure.appendChild(captionEl);\n\t\t\t\t}\n\t\t\t\tif (captionEl.textContent !== caption) captionEl.textContent = caption;\n\t\t\t} else if (captionEl) {\n\t\t\t\tcaptionEl.remove();\n\t\t\t\tcaptionEl = null;\n\t\t\t}\n\t\t}\n\n\t\tfunction applyAttrs(n: BlockNode): void {\n\t\t\tcurrentAttrs = normalizeVideoAttrs(n.attrs as Partial<VideoAttrs>, config);\n\t\t\tapplyVideoFrameSizing(frame, currentAttrs.aspectRatio, currentAttrs.widthPercent);\n\t\t\tapplyVideoAlignment(figure, currentAttrs.align);\n\t\t\tfigure.setAttribute(\n\t\t\t\t'aria-label',\n\t\t\t\tlocale.videoAria(\n\t\t\t\t\tproviderLabel(currentAttrs.provider, config.providers),\n\t\t\t\t\tcurrentAttrs.title,\n\t\t\t\t),\n\t\t\t);\n\t\t\tupdateCaption(currentAttrs.caption);\n\t\t\tfacade.update();\n\t\t\ttoolbar?.update(currentAttrs.align);\n\t\t}\n\n\t\tapplyAttrs(node);\n\n\t\tfunction commitWidth(percent: number): void {\n\t\t\tconst state: EditorState = getState();\n\t\t\tconst block: BlockNode | undefined = state.getBlock(currentNodeId);\n\t\t\tif (!block) return;\n\t\t\tconst path: BlockId[] | undefined = state.getNodePath(currentNodeId);\n\t\t\tif (!path) return;\n\t\t\tconst merged: BlockAttrs = { ...(block.attrs ?? {}), widthPercent: percent };\n\t\t\tdispatch(state.transaction('command').setNodeAttr(path, merged).build());\n\t\t}\n\n\t\tfunction createOverlay(): void {\n\t\t\tif (!config.resizable || resizeOverlay) return;\n\t\t\tresizeOverlay = createVideoResizeOverlay(\n\t\t\t\t{\n\t\t\t\t\tminPercent: config.minWidthPercent,\n\t\t\t\t\tgetWidthPercent: () => currentAttrs.widthPercent,\n\t\t\t\t\tgetReferenceWidth: () => figure.clientWidth || frame.clientWidth,\n\t\t\t\t\tisRtl: () => getTextDirection(figure) === 'rtl',\n\t\t\t\t\tapplyLiveWidth: (p: number) => setStyleProperty(frame, 'width', `${p}%`),\n\t\t\t\t\tcommit: (p: number) => commitWidth(p),\n\t\t\t\t\tformatPercent: (p: number) => `${p}%`,\n\t\t\t\t},\n\t\t\t\tbuildKeyboardHint(resolvedKeymap, locale),\n\t\t\t);\n\t\t\tframe.appendChild(resizeOverlay.element);\n\t\t}\n\n\t\tfunction removeOverlay(): void {\n\t\t\tif (!resizeOverlay) return;\n\t\t\tresizeOverlay.destroy();\n\t\t\tresizeOverlay.element.remove();\n\t\t\tresizeOverlay = null;\n\t\t}\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 !== 'video') 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-video--selected');\n\t\t\t\tcreateOverlay();\n\t\t\t\tif (!toolbar) {\n\t\t\t\t\ttoolbar = createVideoSelectionToolbar({\n\t\t\t\t\t\tlocale,\n\t\t\t\t\t\tactions,\n\t\t\t\t\t\tinitialAlign: currentAttrs.align,\n\t\t\t\t\t});\n\t\t\t\t\tfigure.appendChild(toolbar.element);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tdeselectNode(): void {\n\t\t\t\tfigure.classList.remove('notectl-video--selected');\n\t\t\t\tremoveOverlay();\n\t\t\t\ttoolbar?.destroy();\n\t\t\t\ttoolbar = null;\n\t\t\t},\n\n\t\t\tdestroy(): void {\n\t\t\t\tremoveOverlay();\n\t\t\t\ttoolbar?.destroy();\n\t\t\t\ttoolbar = null;\n\t\t\t\tfacade.destroy();\n\t\t\t},\n\t\t};\n\t};\n}\n","/**\n * Ask-first paste-to-embed interceptor.\n *\n * Runs on the RAW clipboard text/html before the editor's own sanitize pass (the\n * paste pipeline invokes interceptors first). When the sole clipboard content is\n * a known-provider video URL — or a standalone embed `<iframe>` — it claims the\n * paste, inserts the URL as plain text, and hands the inserted range to `onOffer`\n * so the plugin can show the \"Embed this video?\" affordance. Nothing is embedded\n * silently; the user opts in. Anything else passes through to default handling.\n */\n\nimport type { PasteInterceptor } from '../../model/PasteInterceptor.js';\nimport { createCollapsedSelection, isCollapsed, isTextSelection } from '../../model/Selection.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport type { VideoTextRange } from './VideoCommands.js';\nimport {\n\ttype VideoMatch,\n\ttype VideoProvider,\n\tbuildWatchUrlForMatch,\n\tparseVideoUrl,\n} from './VideoProviders.js';\n\n/** Parses untrusted clipboard HTML into an INERT fragment (no resource loads). */\nfunction parseFragment(html: string): DocumentFragment {\n\tconst template: HTMLTemplateElement = document.createElement('template');\n\ttemplate.innerHTML = html;\n\treturn template.content;\n}\n\n/** Returns the `src` of a standalone embed iframe (only content besides whitespace), else null. */\nfunction standaloneIframeSrc(html: string): string | null {\n\tif (!html) return null;\n\tconst fragment: DocumentFragment = parseFragment(html);\n\tconst iframe: HTMLIFrameElement | null = fragment.querySelector('iframe');\n\tif (!iframe) return null;\n\tconst clone: DocumentFragment = fragment.cloneNode(true) as DocumentFragment;\n\tfor (const el of Array.from(clone.querySelectorAll('iframe'))) el.remove();\n\tif ((clone.textContent ?? '').trim() !== '') return null;\n\treturn iframe.getAttribute('src');\n}\n\n/** Detects a sole-clipboard video paste, returning the text to insert and the match. */\nfunction extractVideoPaste(\n\tplainText: string,\n\thtml: string,\n\tproviders: readonly VideoProvider[],\n): { url: string; match: VideoMatch } | null {\n\tconst text: string = plainText.trim();\n\t// A bare URL has no internal whitespace; this enforces \"sole clipboard content\".\n\tif (text && !/\\s/.test(text)) {\n\t\tconst match: VideoMatch | null = parseVideoUrl(text, providers);\n\t\tif (match) return { url: text, match };\n\t}\n\n\tconst iframeSrc: string | null = standaloneIframeSrc(html);\n\tif (iframeSrc) {\n\t\tconst match: VideoMatch | null = parseVideoUrl(iframeSrc, providers);\n\t\tif (match) {\n\t\t\t// Insert the friendly public watch URL as the placeholder text, not the\n\t\t\t// raw embed URL.\n\t\t\treturn { url: buildWatchUrlForMatch(match, providers) ?? iframeSrc, match };\n\t\t}\n\t}\n\treturn null;\n}\n\n/** Creates the ask-first video paste interceptor. */\nexport function createVideoPasteInterceptor(options: {\n\tproviders: readonly VideoProvider[];\n\tonOffer: (range: VideoTextRange, match: VideoMatch) => void;\n}): PasteInterceptor {\n\treturn (plainText: string, html: string, state: EditorState): Transaction | null => {\n\t\tconst result = extractVideoPaste(plainText, html, options.providers);\n\t\tif (!result) return null;\n\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel) || !isCollapsed(sel)) return null;\n\n\t\tconst blockId = sel.anchor.blockId;\n\t\tconst start: number = sel.anchor.offset;\n\t\tconst end: number = start + result.url.length;\n\n\t\tconst tr: Transaction = state\n\t\t\t.transaction('paste')\n\t\t\t.insertText(blockId, start, result.url, [])\n\t\t\t.setSelection(createCollapsedSelection(blockId, end))\n\t\t\t.build();\n\n\t\t// The transaction applies before the deferred affordance reads the DOM.\n\t\toptions.onOffer({ blockId, start, end }, result.match);\n\t\treturn tr;\n\t};\n}\n","/** Styles for the video insert/edit overlay panel and its form. */\nexport const VIDEO_POPUP_CSS = `\n.notectl-video-overlay {\n\tposition: fixed;\n\tz-index: 1000;\n\tbox-sizing: border-box;\n\tmin-width: 300px;\n\tmax-width: 92vw;\n\tpadding: 12px;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 8px;\n\tbackground: var(--notectl-surface-overlay);\n\tcolor: var(--notectl-fg);\n\tbox-shadow: 0 6px 24px var(--notectl-shadow);\n}\n\n.notectl-video-popup {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 10px;\n}\n\n.notectl-video-popup__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.notectl-video-popup__label {\n\tfont-size: 12px;\n\tfont-weight: 600;\n\tcolor: var(--notectl-fg-muted);\n}\n\n.notectl-video-popup__input,\n.notectl-video-popup__select {\n\twidth: 100%;\n\tpadding: 6px 8px;\n\tbox-sizing: border-box;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tbackground: var(--notectl-surface-raised);\n\tcolor: var(--notectl-fg);\n\tfont: inherit;\n}\n\n.notectl-video-popup__input:focus-visible,\n.notectl-video-popup__select:focus-visible {\n\toutline: 2px solid var(--notectl-primary);\n\toutline-offset: 1px;\n}\n\n.notectl-video-popup__hint {\n\tmargin: 0;\n\tfont-size: 11px;\n\tcolor: var(--notectl-fg-muted);\n}\n\n.notectl-video-popup__error:not(:empty) {\n\tmargin: 0;\n\tpadding: 6px 8px;\n\tborder-radius: 4px;\n\tbackground: var(--notectl-danger-muted);\n\tcolor: var(--notectl-danger);\n\tfont-size: 12px;\n}\n\n.notectl-video-popup__actions {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tgap: 8px;\n\tmargin-top: 2px;\n}\n\n.notectl-video-popup__cancel,\n.notectl-video-popup__submit {\n\tpadding: 7px 14px;\n\tcursor: pointer;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tbackground: var(--notectl-surface-raised);\n\tcolor: var(--notectl-fg);\n\tfont: inherit;\n}\n\n.notectl-video-popup__submit {\n\tborder-color: var(--notectl-primary);\n\tbackground: var(--notectl-primary);\n\tcolor: var(--notectl-primary-fg);\n\tfont-weight: 600;\n}\n\n.notectl-video-popup__cancel:focus-visible,\n.notectl-video-popup__submit:focus-visible {\n\toutline: 2px solid var(--notectl-primary);\n\toutline-offset: 2px;\n}\n\n/* Ask-first paste affordance */\n.notectl-video-embed-prompt {\n\tposition: fixed;\n\tz-index: 1000;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 6px 8px 6px 12px;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 8px;\n\tbackground: var(--notectl-surface-overlay);\n\tcolor: var(--notectl-fg);\n\tbox-shadow: 0 4px 16px var(--notectl-shadow);\n\tfont-size: 13px;\n}\n\n.notectl-video-embed-prompt__text {\n\tmargin-inline-end: 4px;\n}\n\n.notectl-video-embed-prompt__embed,\n.notectl-video-embed-prompt__dismiss {\n\tpadding: 4px 10px;\n\tcursor: pointer;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tbackground: var(--notectl-surface-raised);\n\tcolor: var(--notectl-fg);\n\tfont: inherit;\n}\n\n.notectl-video-embed-prompt__embed {\n\tborder-color: var(--notectl-primary);\n\tbackground: var(--notectl-primary);\n\tcolor: var(--notectl-primary-fg);\n\tfont-weight: 600;\n}\n\n.notectl-video-embed-prompt__embed:focus-visible,\n.notectl-video-embed-prompt__dismiss:focus-visible {\n\toutline: 2px solid var(--notectl-primary);\n\toutline-offset: 2px;\n}\n\n@media (forced-colors: active) {\n\t.notectl-video-overlay,\n\t.notectl-video-embed-prompt {\n\t\tborder: 1px solid CanvasText;\n\t}\n\t.notectl-video-popup__submit,\n\t.notectl-video-embed-prompt__embed {\n\t\tborder: 1px solid ButtonText;\n\t}\n}\n`;\n","/**\n * Global DOMPurify host-allowlist hook for video iframes.\n *\n * Every notectl sanitize sink (paste, document parse, serialize) calls the same\n * `DOMPurify` singleton, so a single `uponSanitizeElement` hook covers all three.\n * For each `<iframe>` it rejects `srcdoc` and any `src` that is not an `https:`\n * URL whose hostname is an EXACT member of the provider embed allowlist — the\n * load-bearing check that defeats look-alikes (`evilyoutube.com`,\n * `youtube.com.evil.com`, the `https://youtube.com@evil.com` userinfo trick).\n * `ALLOWED_URI_REGEXP` cannot express host rules, so this hook is mandatory.\n *\n * The hook is global per DOMPurify instance, so installs are reference-counted:\n * the hook is added once and removed only when the last video plugin is destroyed,\n * preventing leakage across editor instances and tests.\n */\n\nimport DOMPurify from 'dompurify';\nimport { isAllowedEmbedSrc } from './VideoProviders.js';\n\nlet refCount = 0;\nconst allowedHosts = new Set<string>();\nlet hook: ((node: Node) => void) | null = null;\n\n/**\n * Installs (or re-uses) the iframe host-allowlist hook, merging in the given\n * embed hostnames. Pair every call with {@link uninstallVideoIframeHook}.\n */\nexport function installVideoIframeHook(hosts: ReadonlySet<string>): void {\n\tfor (const host of hosts) allowedHosts.add(host);\n\trefCount += 1;\n\tif (hook) return;\n\n\thook = (node: Node): void => {\n\t\tif (node.nodeName.toLowerCase() !== 'iframe') return;\n\t\tconst el = node as Element;\n\t\t// An iframe with srcdoc renders attacker-controlled markup; never allow it.\n\t\tif (el.hasAttribute('srcdoc')) {\n\t\t\tel.parentNode?.removeChild(el);\n\t\t\treturn;\n\t\t}\n\t\tconst src: string = el.getAttribute('src') ?? '';\n\t\tif (!isAllowedEmbedSrc(src, allowedHosts)) {\n\t\t\tel.parentNode?.removeChild(el);\n\t\t}\n\t};\n\tDOMPurify.addHook('uponSanitizeElement', hook);\n}\n\n/** Removes the hook when the last installer is gone (reference-counted). */\nexport function uninstallVideoIframeHook(): void {\n\trefCount = Math.max(0, refCount - 1);\n\tif (refCount > 0 || !hook) return;\n\tDOMPurify.removeHook('uponSanitizeElement');\n\thook = null;\n\tallowedHosts.clear();\n}\n","/** Video block styles: responsive frame, facade, player, resize, toolbar, caption. */\nexport const VIDEO_CSS = `\n.notectl-video {\n\tmargin: 12px 0;\n\tposition: relative;\n\tuser-select: none;\n}\n\n.notectl-video--center { text-align: center; }\n.notectl-video--start { text-align: start; }\n.notectl-video--end { text-align: end; }\n\n.notectl-video__frame {\n\tdisplay: inline-block;\n\tposition: relative;\n\twidth: 100%;\n\tmax-width: 100%;\n\tvertical-align: top;\n\toverflow: hidden;\n\tborder-radius: 8px;\n\tbackground: #000;\n\ttext-align: start;\n}\n\n/* Facade (click-to-load) */\n.notectl-video__facade {\n\tposition: absolute;\n\tinset: 0;\n\twidth: 100%;\n\theight: 100%;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: 0;\n\tborder: 0;\n\tcursor: pointer;\n\tbackground: #14181c;\n\tcolor: #fff;\n}\n\n.notectl-video__facade:focus-visible {\n\toutline: 3px solid var(--notectl-primary);\n\toutline-offset: -3px;\n}\n\n.notectl-video__poster {\n\tposition: absolute;\n\tinset: 0;\n\tbackground-size: cover;\n\tbackground-position: center;\n\tbackground-repeat: no-repeat;\n}\n\n.notectl-video__poster::after {\n\tcontent: \"\";\n\tposition: absolute;\n\tinset: 0;\n\tbackground: rgba(0, 0, 0, 0.25);\n}\n\n.notectl-video__play-icon {\n\tposition: relative;\n\tz-index: 1;\n\tdisplay: inline-flex;\n\tfilter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.5));\n\ttransition: transform 0.12s ease;\n}\n\n.notectl-video__facade:hover .notectl-video__play-icon {\n\ttransform: scale(1.08);\n}\n\n.notectl-video__badge {\n\tposition: absolute;\n\tz-index: 1;\n\tbottom: 8px;\n\tinset-inline-start: 8px;\n\tpadding: 2px 6px;\n\tborder-radius: 4px;\n\tbackground: rgba(0, 0, 0, 0.65);\n\tcolor: #fff;\n\tfont-size: 12px;\n\tfont-weight: 600;\n}\n\n/* Player (activated iframe + exit control) */\n.notectl-video__player {\n\tposition: absolute;\n\tinset: 0;\n}\n\n.notectl-video__iframe {\n\tposition: absolute;\n\tinset: 0;\n\twidth: 100%;\n\theight: 100%;\n\tborder: 0;\n\tdisplay: block;\n}\n\n.notectl-video__exit {\n\tposition: absolute;\n\tz-index: 2;\n\ttop: 6px;\n\tinset-inline-end: 6px;\n\twidth: 28px;\n\theight: 28px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tborder: 0;\n\tborder-radius: 50%;\n\tcursor: pointer;\n\tbackground: rgba(0, 0, 0, 0.65);\n\tcolor: #fff;\n}\n\n.notectl-video__exit:focus-visible {\n\toutline: 2px solid #fff;\n\toutline-offset: 2px;\n}\n\n/* Static fallback link (no-JS / export rehydration) */\n.notectl-video__fallback-link {\n\tposition: absolute;\n\tinset: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: 8px;\n\tcolor: #fff;\n\ttext-decoration: underline;\n\ttext-align: center;\n}\n\n/* Caption */\n.notectl-video__caption {\n\tmargin-top: 6px;\n\tfont-size: 13px;\n\tcolor: var(--notectl-fg-muted);\n\ttext-align: center;\n}\n\n/* Selection */\n.notectl-video--selected .notectl-video__frame {\n\toutline: 2px solid var(--notectl-primary);\n\toutline-offset: 2px;\n}\n\n/* Resize overlay + side handles */\n.notectl-video__resize-overlay {\n\tposition: absolute;\n\tinset: 0;\n\tpointer-events: none;\n}\n\n.notectl-video__resize-handle {\n\tposition: absolute;\n\ttop: 50%;\n\ttransform: translateY(-50%);\n\twidth: 8px;\n\theight: 44px;\n\tmax-height: 60%;\n\tborder: 2px solid var(--notectl-primary);\n\tborder-radius: 6px;\n\tbackground: var(--notectl-surface-raised);\n\tpointer-events: all;\n\tcursor: ew-resize;\n\tz-index: 2;\n}\n\n.notectl-video__resize-handle--w { inset-inline-start: -5px; }\n.notectl-video__resize-handle--e { inset-inline-end: -5px; }\n\n.notectl-video__size-indicator {\n\tposition: absolute;\n\tbottom: -28px;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n\tpadding: 2px 8px;\n\tborder-radius: 4px;\n\tbackground: var(--notectl-tooltip-bg);\n\tcolor: var(--notectl-tooltip-fg);\n\tfont-size: 11px;\n\tfont-weight: 500;\n\twhite-space: nowrap;\n\tpointer-events: none;\n\topacity: 0;\n\ttransition: opacity 0.15s;\n\tz-index: 3;\n}\n\n.notectl-video__size-indicator--visible { opacity: 1; }\n\n.notectl-video__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-video--selected .notectl-video__keyboard-hint { display: block; }\n.notectl-video__resize-overlay--active ~ .notectl-video__keyboard-hint,\n.notectl-video__resize-overlay--active .notectl-video__keyboard-hint { display: none; }\n\n/* On-selection toolbar */\n.notectl-video__toolbar {\n\tposition: absolute;\n\ttop: -44px;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 2px;\n\tpadding: 2px;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 6px;\n\tbackground: var(--notectl-surface-overlay);\n\tbox-shadow: 0 2px 8px var(--notectl-shadow);\n\tz-index: 10;\n}\n\n.notectl-video__tool {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 28px;\n\theight: 28px;\n\tborder: none;\n\tborder-radius: 4px;\n\tbackground: transparent;\n\tcursor: pointer;\n\tcolor: var(--notectl-fg);\n}\n\n.notectl-video__tool:hover { background: var(--notectl-hover-bg); }\n\n.notectl-video__tool--active {\n\tbackground: var(--notectl-active-bg);\n\tcolor: var(--notectl-primary);\n}\n\n.notectl-video__tool:focus-visible {\n\toutline: 2px solid var(--notectl-primary);\n\toutline-offset: 1px;\n}\n\n.notectl-video__tool svg { width: 16px; height: 16px; }\n\n.notectl-video__tool-separator {\n\twidth: 1px;\n\theight: 18px;\n\tmargin: 0 2px;\n\tbackground: var(--notectl-border);\n}\n\n@media (prefers-reduced-motion: reduce) {\n\t.notectl-video__play-icon,\n\t.notectl-video__size-indicator {\n\t\ttransition: none;\n\t}\n}\n\n@media (forced-colors: active) {\n\t.notectl-video__frame { outline: 1px solid CanvasText; }\n\t.notectl-video__facade { border: 1px solid ButtonText; }\n\t.notectl-video__play-icon { forced-color-adjust: none; }\n\t.notectl-video__resize-handle { background: ButtonFace; border-color: ButtonText; }\n\t.notectl-video--selected .notectl-video__frame { outline: 2px solid Highlight; }\n}\n`;\n","/**\n * VideoPlugin: dependency-free, accessibility-first video embeds for notectl.\n *\n * Embeds are produced entirely by client-side URL parsing (no oEmbed, no provider\n * SDK). The node stores structured data, never raw iframe HTML; the live iframe is\n * built only at view time behind a privacy-first click-to-load facade. A global\n * DOMPurify host-allowlist hook guards every sanitize sink against untrusted\n * iframes on import.\n */\n\nimport { type BlockNode, getBlockText } from '../../model/Document.js';\nimport type { Keymap } from '../../model/Keymap.js';\nimport { isNodeSelection } from '../../model/Selection.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport {\n\ttype VideoTextRange,\n\tregisterVideoCommands,\n\tremoveVideo,\n\tresetVideoSize,\n\tresizeVideoByDelta,\n\tselectedVideoWidthPercent,\n\tsetVideoAlign,\n} from './VideoCommands.js';\nimport { VideoEditOverlay } from './VideoEditOverlay.js';\nimport { type EmbedPromptController, showEmbedPrompt } from './VideoEmbedPrompt.js';\nimport { VIDEO_LOCALE_EN, type VideoLocale, loadVideoLocale } from './VideoLocale.js';\nimport { createVideoNodeSpec } from './VideoNodeSpec.js';\nimport { createVideoNodeViewFactory } from './VideoNodeView.js';\nimport { createVideoPasteInterceptor } from './VideoPasteInterceptor.js';\nimport { VIDEO_POPUP_CSS } from './VideoPopupStyles.js';\nimport { type VideoMatch, collectEmbedHostnames, providerLabel } from './VideoProviders.js';\nimport { installVideoIframeHook, uninstallVideoIframeHook } from './VideoSanitizeHook.js';\nimport { VIDEO_CSS } from './VideoStyles.js';\nimport {\n\tDEFAULT_VIDEO_CONFIG,\n\tDEFAULT_VIDEO_KEYMAP,\n\tVIDEO_TYPE,\n\ttype VideoKeymap,\n\ttype VideoPluginConfig,\n} from './VideoTypes.js';\n\nconst VIDEO_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2zm6 4.5v7l6-3.5-6-3.5z\" fill=\"currentColor\"/></svg>';\n\nexport class VideoPlugin implements Plugin {\n\treadonly id = 'video';\n\treadonly name = 'Video';\n\treadonly priority = 47;\n\n\tprivate readonly config: VideoPluginConfig;\n\tprivate readonly resolvedKeymap: Readonly<Record<keyof VideoKeymap, string | null>>;\n\tprivate context: PluginContext | null = null;\n\tprivate locale: VideoLocale = VIDEO_LOCALE_EN;\n\tprivate overlay: VideoEditOverlay | null = null;\n\tprivate embedPrompt: EmbedPromptController | null = null;\n\n\tconstructor(config?: Partial<VideoPluginConfig>) {\n\t\tthis.config = { ...DEFAULT_VIDEO_CONFIG, ...config };\n\t\tthis.resolvedKeymap = { ...DEFAULT_VIDEO_KEYMAP, ...config?.keymap };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.context = context;\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tVIDEO_LOCALE_EN,\n\t\t\tloadVideoLocale,\n\t\t);\n\n\t\tcontext.registerStyleSheet(VIDEO_CSS);\n\t\tcontext.registerStyleSheet(VIDEO_POPUP_CSS);\n\t\tinstallVideoIframeHook(collectEmbedHostnames(this.config.providers));\n\n\t\tcontext.registerNodeSpec(createVideoNodeSpec(this.config, this.locale));\n\t\tthis.overlay = new VideoEditOverlay(context, this.config, this.locale);\n\t\tthis.registerNodeView(context);\n\n\t\tregisterVideoCommands(context);\n\t\tthis.registerInsertCommand(context);\n\t\tthis.registerResizeCommands(context);\n\t\tthis.registerResizeKeymaps(context);\n\t\tthis.registerPasteInterceptor(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tdestroy(): void {\n\t\tuninstallVideoIframeHook();\n\t\tthis.embedPrompt?.close();\n\t\tthis.embedPrompt = null;\n\t\tthis.overlay?.close(false);\n\t\tthis.overlay = null;\n\t\tthis.context = null;\n\t}\n\n\tonStateChange(oldState: EditorState, newState: EditorState, _tr: Transaction): void {\n\t\tif (!this.context) return;\n\t\tif (!this.isVideoSelected(oldState) && this.isVideoSelected(newState)) {\n\t\t\tthis.announceVideoSelection(newState);\n\t\t}\n\t}\n\n\tprivate registerNodeView(context: PluginContext): void {\n\t\tcontext.registerNodeView(\n\t\t\tVIDEO_TYPE,\n\t\t\tcreateVideoNodeViewFactory({\n\t\t\t\tconfig: this.config,\n\t\t\t\tlocale: this.locale,\n\t\t\t\tresolvedKeymap: this.resolvedKeymap,\n\t\t\t\tannounce: (text: string) => context.announce(text),\n\t\t\t\tactions: {\n\t\t\t\t\tedit: () => this.overlay?.openEditForSelected(),\n\t\t\t\t\talign: (align) => setVideoAlign(context, align),\n\t\t\t\t\tremove: () => removeVideo(context),\n\t\t\t\t},\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate registerInsertCommand(context: PluginContext): void {\n\t\t// Context-aware: edit the selected video, otherwise open the insert form.\n\t\tcontext.registerCommand('insertVideo', () => {\n\t\t\tif (this.isVideoSelected(context.getState())) this.overlay?.openEditForSelected();\n\t\t\telse this.overlay?.openInsert();\n\t\t\treturn true;\n\t\t});\n\t}\n\n\tprivate registerResizeCommands(context: PluginContext): void {\n\t\tconst step: number = this.config.widthStep;\n\t\tconst stepLarge: number = this.config.widthStepLarge;\n\t\tconst resize = (delta: number): boolean => {\n\t\t\tconst ok: boolean = resizeVideoByDelta(context, delta, this.config);\n\t\t\tif (ok) this.announceCurrentSize(context);\n\t\t\treturn ok;\n\t\t};\n\n\t\tcontext.registerCommand('resizeVideoGrow', () => resize(step));\n\t\tcontext.registerCommand('resizeVideoShrink', () => resize(-step));\n\t\tcontext.registerCommand('resizeVideoGrowLarge', () => resize(stepLarge));\n\t\tcontext.registerCommand('resizeVideoShrinkLarge', () => resize(-stepLarge));\n\t\tcontext.registerCommand('resetVideoSize', () => {\n\t\t\tconst ok: boolean = resetVideoSize(context, this.config);\n\t\t\tif (ok) context.announce(this.locale.resetToDefaultSize);\n\t\t\treturn ok;\n\t\t});\n\t}\n\n\tprivate registerResizeKeymaps(context: PluginContext): void {\n\t\tconst commands: Record<keyof VideoKeymap, string> = {\n\t\t\tgrowWidth: 'resizeVideoGrow',\n\t\t\tshrinkWidth: 'resizeVideoShrink',\n\t\t\tgrowWidthLarge: 'resizeVideoGrowLarge',\n\t\t\tshrinkWidthLarge: 'resizeVideoShrinkLarge',\n\t\t\tresetSize: 'resetVideoSize',\n\t\t};\n\t\tconst bindings: Record<string, () => boolean> = {};\n\t\tfor (const [slot, commandName] of Object.entries(commands)) {\n\t\t\tconst binding: string | null = this.resolvedKeymap[slot as keyof VideoKeymap] ?? null;\n\t\t\tif (binding) bindings[binding] = () => context.executeCommand(commandName);\n\t\t}\n\t\tif (Object.keys(bindings).length > 0) context.registerKeymap(bindings as Keymap);\n\t}\n\n\tprivate registerPasteInterceptor(context: PluginContext): void {\n\t\t// Priority below smart-paste (50) so a sole video URL is claimed first.\n\t\tcontext.registerPasteInterceptor(\n\t\t\tcreateVideoPasteInterceptor({\n\t\t\t\tproviders: this.config.providers,\n\t\t\t\tonOffer: (range: VideoTextRange, match: VideoMatch) => this.offerEmbed(range, match),\n\t\t\t}),\n\t\t\t{ name: 'video', priority: 40 },\n\t\t);\n\t}\n\n\t/** Shows the ask-first affordance after a video URL was pasted as text. */\n\tprivate offerEmbed(range: VideoTextRange, match: VideoMatch): void {\n\t\tif (!this.context) return;\n\t\tconst context = this.context;\n\t\tconst name: string = providerLabel(match.provider, this.config.providers);\n\t\tthis.embedPrompt?.close();\n\n\t\t// Defer so the pasted URL is in the DOM and the caret rect is available.\n\t\trequestAnimationFrame(() => {\n\t\t\tcontext.announce(this.locale.embedOfferAnnounce(name));\n\t\t\tconst prefillUrl: string = readRangeText(context.getState(), range);\n\t\t\tthis.embedPrompt = showEmbedPrompt({\n\t\t\t\tcontainer: context.getPluginContainer('top'),\n\t\t\t\trect: caretRect(),\n\t\t\t\tlocale: this.locale,\n\t\t\t\tonEmbed: () => {\n\t\t\t\t\tthis.embedPrompt = null;\n\t\t\t\t\tthis.overlay?.openInsertReplacingRange(range, prefillUrl);\n\t\t\t\t},\n\t\t\t\tonDismiss: () => {\n\t\t\t\t\tthis.embedPrompt = null;\n\t\t\t\t\tcontext.getContainer().focus();\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'video',\n\t\t\tgroup: 'insert',\n\t\t\ticon: VIDEO_ICON,\n\t\t\tlabel: this.locale.insertVideo,\n\t\t\ttooltip: this.locale.insertVideoTooltip,\n\t\t\tcommand: 'insertVideo',\n\t\t});\n\t}\n\n\tprivate isVideoSelected(state: EditorState): boolean {\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return false;\n\t\treturn state.getBlock(sel.nodeId)?.type === VIDEO_TYPE;\n\t}\n\n\tprivate announceVideoSelection(state: EditorState): void {\n\t\tif (!this.context) return;\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return;\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.nodeId);\n\t\tif (!block || block.type !== VIDEO_TYPE) return;\n\n\t\tconst title: string = (block.attrs?.title as string | undefined) ?? '';\n\t\tconst parts: string[] = [\n\t\t\ttitle ? this.locale.videoSelectedWithTitle(title) : this.locale.videoSelected,\n\t\t];\n\t\tconst shrink: string | null = this.resolvedKeymap.shrinkWidth ?? null;\n\t\tconst grow: string | null = this.resolvedKeymap.growWidth ?? null;\n\t\tif (shrink && grow) {\n\t\t\tparts.push(this.locale.resizeHint(formatShortcut(shrink), formatShortcut(grow)));\n\t\t}\n\t\tthis.context.announce(parts.join(' '));\n\t}\n\n\tprivate announceCurrentSize(context: PluginContext): void {\n\t\tconst percent: number | null = selectedVideoWidthPercent(context.getState(), this.config);\n\t\tif (percent !== null) context.announce(this.locale.videoResized(percent));\n\t}\n}\n\n/** Returns the current text occupying a range (the pasted URL), clamped to bounds. */\nfunction readRangeText(state: EditorState, range: VideoTextRange): string {\n\tconst block: BlockNode | undefined = state.getBlock(range.blockId);\n\tif (!block) return '';\n\tconst text: string = getBlockText(block);\n\treturn text.slice(range.start, Math.min(range.end, text.length));\n}\n\n/** Returns the current selection caret rect, or null. */\nfunction caretRect(): DOMRect | null {\n\tconst selection: Selection | null = window.getSelection();\n\tif (!selection || selection.rangeCount === 0) return null;\n\tconst rect: DOMRect = selection.getRangeAt(0).getBoundingClientRect();\n\tif (rect.width === 0 && rect.height === 0 && rect.top === 0 && rect.left === 0) return null;\n\treturn rect;\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{f as n,g as e}from"./Document-znhIcvM9.mjs";var t="undefined"!=typeof Intl&&"Segmenter"in Intl?new Intl.Segmenter(void 0,{granularity:"grapheme"}):null;function r(n,e){if(e>=n.length||0===n.length)return 0;if(t){for(const r of t.segment(n)){const n=r.index+r.segment.length;if(n>e)return n-e}return 0}return 1}function i(n,e){if(e<=0||0===n.length)return 0;if(t){let r=1;for(const i of t.segment(n)){if(i.index+i.segment.length>=e){r=i.segment.length;break}r=i.segment.length}return r}return 1}function f(n,t){let r=t-1;for(;r>=0;){const t=e(n,r);if(!t||"inline"===t.kind)break;if(!/\s/.test(t.char))break;r--}if(r>=0&&"inline"===e(n,r)?.kind)return r;for(;r>=0;){const t=e(n,r);if(!t||"inline"===t.kind)break;if(/\s/.test(t.char))break;r--}return r+1}function s(t,r){const i=n(t);let f=r;for(;f<i;){const n=e(t,f);if(!n||"inline"===n.kind)break;if(/\s/.test(n.char))break;f++}if(f===r&&f<i&&"inline"===e(t,f)?.kind)return f+1;for(;f<i;){const n=e(t,f);if(!n||"inline"===n.kind)break;if(!/\s/.test(n.char))break;f++}return f}export{i,s as n,r,f as t};
|
|
2
|
-
//# sourceMappingURL=WordBoundary-CYDAtEks.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WordBoundary-CYDAtEks.mjs","names":[],"sources":["../../src/model/GraphemeUtils.ts","../../src/model/WordBoundary.ts"],"sourcesContent":["/**\n * Grapheme-cluster utilities for correct character navigation.\n *\n * Uses `Intl.Segmenter` (with `granularity: 'grapheme'`) to correctly\n * handle multi-code-unit characters such as emoji, ZWJ sequences, and\n * combining characters. Falls back to +1/-1 when `Intl.Segmenter` is\n * not available.\n */\n\nconst SEGMENTER_SUPPORTED: boolean = typeof Intl !== 'undefined' && 'Segmenter' in Intl;\nconst SEGMENTER: Intl.Segmenter | null = SEGMENTER_SUPPORTED\n\t? new Intl.Segmenter(undefined, { granularity: 'grapheme' })\n\t: null;\n\n/**\n * Returns the number of UTF-16 code units to advance from `offset` to the next\n * grapheme-cluster boundary. Returns 0 if `offset` is at or past the end.\n *\n * Callers normally pass an offset that already sits on a cluster boundary, in\n * which case this is the full width of the cluster starting at `offset`. When\n * `offset` lands inside a cluster, the remaining units up to that cluster's end\n * are returned so navigation snaps forward to the next boundary (rather than\n * skipping the rest of the current cluster).\n */\nexport function nextGraphemeSize(text: string, offset: number): number {\n\tif (offset >= text.length || text.length === 0) return 0;\n\n\tif (SEGMENTER) {\n\t\tfor (const segment of SEGMENTER.segment(text)) {\n\t\t\tconst end: number = segment.index + segment.segment.length;\n\t\t\tif (end > offset) {\n\t\t\t\treturn end - offset;\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\treturn 1;\n}\n\n/**\n * Returns the number of UTF-16 code units in the grapheme cluster\n * immediately before `offset`. Returns 0 if `offset` is 0 or the\n * string is empty.\n */\nexport function prevGraphemeSize(text: string, offset: number): number {\n\tif (offset <= 0 || text.length === 0) return 0;\n\n\tif (SEGMENTER) {\n\t\tlet lastSize = 1;\n\t\tfor (const segment of SEGMENTER.segment(text)) {\n\t\t\tif (segment.index + segment.segment.length >= offset) {\n\t\t\t\tlastSize = segment.segment.length;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tlastSize = segment.segment.length;\n\t\t}\n\t\treturn lastSize;\n\t}\n\n\treturn 1;\n}\n","/**\n * Word boundary detection for delete-word and word-movement commands.\n * InlineNodes act as word boundaries.\n */\n\nimport { type BlockNode, getBlockLength, getContentAtOffset } from './Document.js';\n\n/**\n * Finds the word boundary backward from the given offset.\n * InlineNodes act as word boundaries.\n */\nexport function findWordBoundaryBackward(block: BlockNode, offset: number): number {\n\tlet pos = offset - 1;\n\t// Skip trailing whitespace\n\twhile (pos >= 0) {\n\t\tconst content = getContentAtOffset(block, pos);\n\t\tif (!content || content.kind === 'inline') break;\n\t\tif (!/\\s/.test(content.char)) break;\n\t\tpos--;\n\t}\n\t// If at InlineNode, delete just it (treat as word boundary)\n\tif (pos >= 0) {\n\t\tconst content = getContentAtOffset(block, pos);\n\t\tif (content?.kind === 'inline') return pos;\n\t}\n\t// Skip word characters until whitespace or InlineNode\n\twhile (pos >= 0) {\n\t\tconst content = getContentAtOffset(block, pos);\n\t\tif (!content || content.kind === 'inline') break;\n\t\tif (/\\s/.test(content.char)) break;\n\t\tpos--;\n\t}\n\treturn pos + 1;\n}\n\n/**\n * Finds the word boundary forward from the given offset.\n * InlineNodes act as word boundaries.\n */\nexport function findWordBoundaryForward(block: BlockNode, offset: number): number {\n\tconst len = getBlockLength(block);\n\tlet pos = offset;\n\t// Skip word characters first\n\twhile (pos < len) {\n\t\tconst content = getContentAtOffset(block, pos);\n\t\tif (!content || content.kind === 'inline') break;\n\t\tif (/\\s/.test(content.char)) break;\n\t\tpos++;\n\t}\n\t// If at InlineNode and haven't moved, delete just the InlineNode\n\tif (pos === offset && pos < len) {\n\t\tconst content = getContentAtOffset(block, pos);\n\t\tif (content?.kind === 'inline') return pos + 1;\n\t}\n\t// Skip trailing whitespace\n\twhile (pos < len) {\n\t\tconst content = getContentAtOffset(block, pos);\n\t\tif (!content || content.kind === 'inline') break;\n\t\tif (!/\\s/.test(content.char)) break;\n\t\tpos++;\n\t}\n\treturn pos;\n}\n"],"mappings":"mDAUA,IAAM,EAD+C,oBAAT,MAAwB,cAAe,KAEhF,IAAI,KAAK,eAAU,EAAW,CAAE,YAAa,aAC7C,KAYH,SAAgB,EAAiB,EAAc,GAC9C,GAAI,GAAU,EAAK,QAA0B,IAAhB,EAAK,OAAc,OAAO,EAEvD,GAAI,EAAW,CACd,IAAK,MAAM,KAAW,EAAU,QAAQ,GAAO,CAC9C,MAAM,EAAc,EAAQ,MAAQ,EAAQ,QAAQ,OACpD,GAAI,EAAM,EACT,OAAO,EAAM,EAGf,OAAO,EAGR,OAAO,EAQR,SAAgB,EAAiB,EAAc,GAC9C,GAAI,GAAU,GAAqB,IAAhB,EAAK,OAAc,OAAO,EAE7C,GAAI,EAAW,CACd,IAAI,EAAW,EACf,IAAK,MAAM,KAAW,EAAU,QAAQ,GAAO,CAC9C,GAAI,EAAQ,MAAQ,EAAQ,QAAQ,QAAU,EAAQ,CACrD,EAAW,EAAQ,QAAQ,OAC3B,MAED,EAAW,EAAQ,QAAQ,OAE5B,OAAO,EAGR,OAAO,ECjDR,SAAgB,EAAyB,EAAkB,GAC1D,IAAI,EAAM,EAAS,EAEnB,KAAO,GAAO,GAAG,CAChB,MAAM,EAAU,EAAmB,EAAO,GAC1C,IAAK,GAA4B,WAAjB,EAAQ,KAAmB,MAC3C,IAAK,KAAK,KAAK,EAAQ,MAAO,MAC9B,IAGD,GAAI,GAAO,GAEY,WADN,EAAmB,EAAO,IAC7B,KAAmB,OAAO,EAGxC,KAAO,GAAO,GAAG,CAChB,MAAM,EAAU,EAAmB,EAAO,GAC1C,IAAK,GAA4B,WAAjB,EAAQ,KAAmB,MAC3C,GAAI,KAAK,KAAK,EAAQ,MAAO,MAC7B,IAED,OAAO,EAAM,EAOd,SAAgB,EAAwB,EAAkB,GACzD,MAAM,EAAM,EAAe,GAC3B,IAAI,EAAM,EAEV,KAAO,EAAM,GAAK,CACjB,MAAM,EAAU,EAAmB,EAAO,GAC1C,IAAK,GAA4B,WAAjB,EAAQ,KAAmB,MAC3C,GAAI,KAAK,KAAK,EAAQ,MAAO,MAC7B,IAGD,GAAI,IAAQ,GAAU,EAAM,GAEL,WADN,EAAmB,EAAO,IAC7B,KAAmB,OAAO,EAAM,EAG9C,KAAO,EAAM,GAAK,CACjB,MAAM,EAAU,EAAmB,EAAO,GAC1C,IAAK,GAA4B,WAAjB,EAAQ,KAAmB,MAC3C,IAAK,KAAK,KAAK,EAAQ,MAAO,MAC9B,IAED,OAAO"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{n as t}from"./TypedKeys-E3jOGByL.mjs";import{n,t as e}from"./XmlPatterns-BiHS8w3k.mjs";var s=new t("languageRegistry");function*o(t,n){let e=0;for(;e<t.length;){let s=!1;for(const o of n.patterns){o.pattern.lastIndex=e;const n=o.pattern.exec(t);if(n&&n.index===e&&n[0].length>0){const t=n[0].length;yield{type:o.type,from:e,to:e+t},e+=t,s=!0;break}}s||e++}}var r={keyword:1,function:.9,type:1,annotation:1.5,property:1.2,tag:1.5,attribute:1.5,constant:.8,string:.4,number:.4,boolean:.6,null:.6,regex:.8,comment:.3,operator:.1,punctuation:.1},i=1.5;function a(t,n,e=r){const s=t.length;if(0===s)return{totalBytes:0,nonWhitespaceBytes:0,recognizedBytes:0,unknownBytes:0,tokenCount:0,weightedScore:0};const i=e.punctuation??0;let a=0,c=0,u=0;for(const r of o(t,n)){const t=r.to-r.from;a+=t,u++,c+=t*(e[r.type]??i)}return{totalBytes:s,nonWhitespaceBytes:l(t),recognizedBytes:a,unknownBytes:s-a,tokenCount:u,weightedScore:c}}function l(t){let n=0;for(let e=0;e<t.length;e++){const s=t.charCodeAt(e);32!==s&&9!==s&&10!==s&&13!==s&&n++}return n}function c(t){if(0===t.nonWhitespaceBytes)return 0;return n=.7*(t.recognizedBytes/t.nonWhitespaceBytes)+.3*(t.weightedScore/t.nonWhitespaceBytes/1.5),Math.max(0,Math.min(1,n));var n}var u=class{id;constructor(t,n={}){this.language=t,this.options=n,this.id=t.name}detect(t){const n=this.options.maxLength??1e5;if(t.length>n)return null;const e=t.trim(),s=this.options.minLines??2;if(e.split("\n").filter(t=>t.trim().length>0).length<s)return null;const o=c(a(e,this.language,this.options.weights)),r=this.matchesAnySignature(e)?this.options.signatureBonus??.3:0,i=Math.min(1,o+r);return i<(this.options.minConfidence??.35)?null:{language:this.language.name,formattedText:e,confidence:i}}matchesAnySignature(t){const n=this.options.signatures??[];for(const e of n)if(e.test(t))return!0;return!1}},h=class{id="json";detect(t){const n=t.trim();if(!n.startsWith("{")&&!n.startsWith("["))return null;try{const t=JSON.parse(n);if("object"!=typeof t||null===t)return null;const e=JSON.stringify(t,null,2);return e.length<=5?null:{language:"json",formattedText:e,confidence:.9}}catch{return null}}},g=/^(<\?[\s\S]*?\?>\s*)+/,f=new RegExp(`^<${n}${e}\\/?>`),p=new RegExp(["<\\?[^?]*\\?>","\x3c!--[\\s\\S]*?--\x3e","<!\\[CDATA\\[[\\s\\S]*?\\]\\]>",`<\\/(${n})>`,`<(${n})${e}\\/>`,`<(${n})${e}>`].join("|"),"g"),m=new RegExp(`<\\/${n}>\\s*$`),d=class{id="xml";detect(t){const n=t.trim();if(!n.startsWith("<"))return null;const e=n.replace(g,"");if(!f.test(e))return null;if(!this.isWellFormed(n))return null;const s=this.formatXml(n);return s.length<=10?null:{language:"xml",formattedText:s,confidence:.85}}isWellFormed(t){const n=[];let e=!1;p.lastIndex=0;let s=p.exec(t);for(;s;){const o=s[1],r=s[2],i=s[3];if(o){if(0===n.length||n[n.length-1]!==o)return!1;n.pop(),e=!0}else r?e=!0:i&&(n.push(i),e=!0);s=p.exec(t)}return e&&0===n.length}formatXml(t){const n=this.splitIntoTokens(t),e=[];let s=0;for(const o of n){const t=y[x(o)];"decrease"===t&&(s=Math.max(0,s-1)),e.push(" ".repeat(2*s)+o),"increase"===t&&s++}return e.join("\n")}splitIntoTokens(t){return t.replace(/>\s*</g,">\n<").split("\n").map(t=>t.trim()).filter(t=>t.length>0)}},y={pi:"none",comment:"none",cdata:"none",closing:"decrease",selfClosing:"none",inline:"none",opening:"increase",text:"none"};function x(t){return t.startsWith("<?")?"pi":t.startsWith("\x3c!--")?"comment":t.startsWith("<![CDATA[")?"cdata":t.startsWith("</")?"closing":t.endsWith("/>")?"selfClosing":t.startsWith("<")&&m.test(t)?"inline":t.startsWith("<")?"opening":"text"}export{r as a,o as c,c as i,s as l,h as n,i as o,u as r,a as s,d as t};
|
|
2
|
-
//# sourceMappingURL=XmlDetector-DxBGXqua.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"XmlDetector-DxBGXqua.mjs","names":[],"sources":["../../src/plugins/language/LanguageTypes.ts","../../src/plugins/code-block/highlighter/TokenIteration.ts","../../src/plugins/smart-paste/detectors/TokenStats.ts","../../src/plugins/smart-paste/detectors/DetectionScorer.ts","../../src/plugins/smart-paste/detectors/LexerDetector.ts","../../src/plugins/smart-paste/detectors/JsonDetector.ts","../../src/plugins/smart-paste/detectors/XmlDetector.ts"],"sourcesContent":["/**\n * Unified language support types for programming language registration.\n *\n * Bundles syntax highlighting and paste detection into a single\n * registration unit so that all artifacts for one language live together.\n */\n\nimport { ServiceKey } from '../Plugin.js';\nimport type { LanguageDefinition } from '../code-block/highlighter/TokenizerTypes.js';\nimport type { ContentDetector } from '../smart-paste/SmartPasteTypes.js';\n\n/**\n * Unified language support bundle grouping all artifacts for one\n * programming language: syntax highlighting, paste detection, and\n * (optionally) code formatting.\n *\n * Pass to `LanguageRegistryService.register()` to make a language\n * available across all participating plugins in a single call.\n */\nexport interface LanguageSupport {\n\t/** Canonical lowercase identifier (e.g. `'java'`, `'python'`). */\n\treadonly id: string;\n\n\t/** Human-readable name shown in the language picker (e.g. `'Java'`). */\n\treadonly displayName: string;\n\n\t/** Alternative names accepted as aliases (e.g. `['py', 'py3']`). */\n\treadonly aliases?: readonly string[];\n\n\t/** Syntax highlighting token patterns for the RegexTokenizer. */\n\treadonly highlighting?: LanguageDefinition;\n\n\t/** Smart-paste detector for auto-detecting this language in pasted text. */\n\treadonly detection?: ContentDetector;\n\n\t/**\n\t * Code formatter for reformatting code block content on demand.\n\t * @experimental Not yet consumed by any built-in plugin.\n\t */\n\treadonly formatter?: CodeFormatter;\n}\n\n/**\n * Formatter that can reformat source code.\n * @experimental Reserved for future use.\n */\nexport interface CodeFormatter {\n\tformat(code: string): string | Promise<string>;\n}\n\n/** Service for registering and querying language support bundles. */\nexport interface LanguageRegistryService {\n\t/** Registers a language bundle. Re-registering the same `id` overwrites. */\n\tregister(support: LanguageSupport): void;\n\n\t/**\n\t * Subscribes to language registrations with replay semantics.\n\t * The listener is immediately called for all already-registered\n\t * bundles, then called for each future registration.\n\t */\n\tonRegister(listener: LanguageRegistryListener): void;\n\n\t/** Returns the bundle for the given language id, or `undefined`. */\n\tget(id: string): LanguageSupport | undefined;\n\n\t/** Returns all registered language support bundles. */\n\tgetAll(): readonly LanguageSupport[];\n}\n\n/** Internal listener type for registry change notifications. */\nexport type LanguageRegistryListener = (support: LanguageSupport) => void;\n\nexport const LANGUAGE_REGISTRY_SERVICE_KEY = new ServiceKey<LanguageRegistryService>(\n\t'languageRegistry',\n);\n","/**\n * Shared low-level iteration over tokenized regions of source code.\n *\n * Used by both the `RegexTokenizer` (for syntax highlighting) and the\n * smart-paste `LexerDetector` (for language detection) so both consumers\n * see exactly the same tokenization for a given language definition.\n */\n\nimport type { LanguageDefinition } from './TokenizerTypes.js';\n\n/** A successfully matched token region produced by `iterateTokens`. */\nexport interface IteratedToken {\n\treadonly type: string;\n\treadonly from: number;\n\treadonly to: number;\n}\n\n/**\n * Iterates tokens of `code` according to the language's sticky-regex patterns.\n *\n * Walks left-to-right; at each position emits the first matching pattern's\n * token and advances past it. Positions where no pattern matches are silently\n * skipped one byte at a time and never appear in the output — a consumer\n * that needs unknown-byte counts can derive them from `code.length` minus the\n * sum of yielded token widths.\n */\nexport function* iterateTokens(\n\tcode: string,\n\tlanguage: LanguageDefinition,\n): Generator<IteratedToken> {\n\tlet pos = 0;\n\twhile (pos < code.length) {\n\t\tlet matched = false;\n\t\tfor (const pattern of language.patterns) {\n\t\t\tpattern.pattern.lastIndex = pos;\n\t\t\tconst match: RegExpExecArray | null = pattern.pattern.exec(code);\n\t\t\tif (match && match.index === pos && match[0].length > 0) {\n\t\t\t\tconst len: number = match[0].length;\n\t\t\t\tyield { type: pattern.type, from: pos, to: pos + len };\n\t\t\t\tpos += len;\n\t\t\t\tmatched = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!matched) {\n\t\t\tpos++;\n\t\t}\n\t}\n}\n","/**\n * Tokenization statistics used by the lexer-based content detector to\n * derive a calibrated, discriminative confidence score per language.\n *\n * The same `LanguageDefinition` that powers syntax highlighting is run\n * over the candidate text, and the token stream is reduced to four\n * aggregate measures: how much of the input was recognized, how many\n * tokens were emitted, and the relevance-weighted byte score that\n * favours language-specific tokens (keywords, decorators, tags) over\n * universal ones (punctuation, operators).\n */\n\nimport { iterateTokens } from '../../code-block/highlighter/TokenIteration.js';\nimport type { LanguageDefinition } from '../../code-block/highlighter/TokenizerTypes.js';\n\n/**\n * Per-token-type relevance weights.\n *\n * Higher weights indicate a matched token of that type contributes more\n * evidence that the input is in the corresponding language. Tokens that\n * appear in many languages (punctuation, operators) are weighted low;\n * tokens whose patterns encode language-specific identifiers (keywords,\n * annotations, tags) are weighted high.\n */\nexport type RelevanceWeights = Readonly<Record<string, number>>;\n\n/**\n * Default relevance weights spanning the canonical syntax token types.\n * Values were chosen so that keyword-rich code (typical for general\n * programming languages) and tag/attribute-rich code (markup) reach\n * scores comparable to one another while pure punctuation falls off.\n */\nexport const DEFAULT_RELEVANCE_WEIGHTS: RelevanceWeights = {\n\tkeyword: 1.0,\n\tfunction: 0.9,\n\ttype: 1.0,\n\tannotation: 1.5,\n\tproperty: 1.2,\n\ttag: 1.5,\n\tattribute: 1.5,\n\tconstant: 0.8,\n\tstring: 0.4,\n\tnumber: 0.4,\n\tboolean: 0.6,\n\tnull: 0.6,\n\tregex: 0.8,\n\tcomment: 0.3,\n\toperator: 0.1,\n\tpunctuation: 0.1,\n};\n\n/**\n * Maximum value present in `DEFAULT_RELEVANCE_WEIGHTS`.\n * Used as the normalization upper bound when computing density —\n * a stream consisting entirely of maximally-weighted tokens has\n * density 1.0.\n */\nexport const MAX_RELEVANCE_WEIGHT = 1.5;\n\n/** Aggregate statistics describing one tokenization pass. */\nexport interface TokenStats {\n\treadonly totalBytes: number;\n\treadonly nonWhitespaceBytes: number;\n\treadonly recognizedBytes: number;\n\treadonly unknownBytes: number;\n\treadonly tokenCount: number;\n\treadonly weightedScore: number;\n}\n\n/**\n * Tokenizes `code` with `language` and returns aggregate statistics\n * suitable for confidence scoring across competing language candidates.\n *\n * Whitespace is counted separately from `unknownBytes` so the scorer can\n * normalize against the meaningful (non-whitespace) input length without\n * unfairly penalizing indentation or vertical spacing.\n */\nexport function computeTokenStats(\n\tcode: string,\n\tlanguage: LanguageDefinition,\n\tweights: RelevanceWeights = DEFAULT_RELEVANCE_WEIGHTS,\n): TokenStats {\n\tconst totalBytes: number = code.length;\n\tif (totalBytes === 0) {\n\t\treturn {\n\t\t\ttotalBytes: 0,\n\t\t\tnonWhitespaceBytes: 0,\n\t\t\trecognizedBytes: 0,\n\t\t\tunknownBytes: 0,\n\t\t\ttokenCount: 0,\n\t\t\tweightedScore: 0,\n\t\t};\n\t}\n\n\tconst fallbackWeight: number = weights.punctuation ?? 0;\n\n\tlet recognizedBytes = 0;\n\tlet weightedScore = 0;\n\tlet tokenCount = 0;\n\n\tfor (const token of iterateTokens(code, language)) {\n\t\tconst len: number = token.to - token.from;\n\t\trecognizedBytes += len;\n\t\ttokenCount++;\n\t\tconst weight: number = weights[token.type] ?? fallbackWeight;\n\t\tweightedScore += len * weight;\n\t}\n\n\tconst nonWhitespaceBytes: number = countNonWhitespaceBytes(code);\n\n\treturn {\n\t\ttotalBytes,\n\t\tnonWhitespaceBytes,\n\t\trecognizedBytes,\n\t\tunknownBytes: totalBytes - recognizedBytes,\n\t\ttokenCount,\n\t\tweightedScore,\n\t};\n}\n\nfunction countNonWhitespaceBytes(text: string): number {\n\tlet count = 0;\n\tfor (let i = 0; i < text.length; i++) {\n\t\tconst c: number = text.charCodeAt(i);\n\t\tif (c !== 32 && c !== 9 && c !== 10 && c !== 13) count++;\n\t}\n\treturn count;\n}\n","/**\n * Pure scoring function that maps tokenization statistics to a\n * discriminative confidence value in `[0, 1]`.\n *\n * The score combines two independent signals:\n * - **Coverage** — fraction of input bytes recognized by the language's\n * patterns. Low coverage means many bytes fell through with no rule\n * matching, which is strong evidence the text is not in this language.\n * - **Density** — average per-byte weight of recognized tokens, normalized\n * against the maximum possible weight. High density means the recognized\n * tokens are themselves discriminative (keywords, annotations) rather\n * than universally-shared syntax (punctuation, operators).\n *\n * Coverage and density are equally weighted: a language that recognizes\n * lots of low-information punctuation is no more credible than one that\n * recognizes a few highly-specific keywords surrounded by unknown bytes,\n * and only the union of both signals sums to high confidence.\n */\n\nimport { MAX_RELEVANCE_WEIGHT, type TokenStats } from './TokenStats.js';\n\n/**\n * Weight of the byte-coverage signal in the combined confidence.\n *\n * Coverage dominates because failure to recognize most non-whitespace\n * bytes is the strongest evidence that the input is not in this language.\n * Relevance is a secondary refinement: among languages with comparable\n * coverage, the one whose recognized tokens are more discriminative\n * (keywords / annotations / tags rather than punctuation) wins.\n */\nconst COVERAGE_WEIGHT = 0.7;\n/** Weight of the relevance-density signal in the combined confidence. */\nconst RELEVANCE_WEIGHT = 0.3;\n\n/**\n * Maps tokenization statistics to a confidence value in `[0, 1]`.\n *\n * Both axes normalize against `nonWhitespaceBytes` so the score scales\n * linearly with the size of the meaningful input and is unaffected by\n * indentation:\n *\n * - **Coverage** = recognized bytes / non-whitespace bytes. Measures how\n * *much* of the meaningful input the lexer matched.\n * - **Relevance** = weighted score / non-whitespace bytes / max weight.\n * Measures how *rich* the matched tokens are on average — a sparse run\n * of keywords amid mostly-unknown text scores low here even though the\n * recognized bytes alone would look high-weight.\n */\nexport function scoreFromStats(stats: TokenStats): number {\n\tif (stats.nonWhitespaceBytes === 0) return 0;\n\n\tconst coverage: number = stats.recognizedBytes / stats.nonWhitespaceBytes;\n\tconst relevance: number = stats.weightedScore / stats.nonWhitespaceBytes / MAX_RELEVANCE_WEIGHT;\n\n\treturn clamp01(COVERAGE_WEIGHT * coverage + RELEVANCE_WEIGHT * relevance);\n}\n\nfunction clamp01(value: number): number {\n\treturn Math.max(0, Math.min(1, value));\n}\n","/**\n * Generic, lexer-driven content detector.\n *\n * Re-uses the `LanguageDefinition` from the syntax highlighter as the\n * authoritative grammar for detection — anything the highlighter learns\n * to tokenize, the detector learns to recognize, with no parallel\n * heuristic to maintain.\n *\n * Detection strategy:\n * 1. **Lexer probe** — tokenize the candidate text with the language's\n * patterns. Coverage and weighted density jointly form a calibrated\n * confidence in `[0, 1]` (see `DetectionScorer`).\n * 2. **Smoking-gun signatures** — when present, language-specific regexes\n * that confirm a plausible interpretation. A signature match adds a\n * fixed bonus to the lexer-derived confidence (capped at 1.0); without\n * signatures the lexer score stands on its own.\n *\n * Signatures must be definitionally specific to the target language —\n * patterns that are syntactically impossible in any competing language\n * the detector will be matched against. They are intentionally additive,\n * not gating: a signature on a near-zero lexer score still produces a\n * low overall confidence and is rejected by the minimum threshold.\n */\n\nimport type { LanguageDefinition } from '../../code-block/highlighter/TokenizerTypes.js';\nimport type { ContentDetector, DetectionResult } from '../SmartPasteTypes.js';\nimport { scoreFromStats } from './DetectionScorer.js';\nimport { type RelevanceWeights, type TokenStats, computeTokenStats } from './TokenStats.js';\n\n/** Configuration options for the lexer-based content detector. */\nexport interface LexerDetectorOptions {\n\t/** Minimum number of non-empty lines required before detection runs. */\n\treadonly minLines?: number;\n\n\t/** Maximum input length analyzed (DoS guard). */\n\treadonly maxLength?: number;\n\n\t/** Minimum confidence value required to accept the detection. */\n\treadonly minConfidence?: number;\n\n\t/**\n\t * Language-specific \"smoking-gun\" patterns. If any pattern matches,\n\t * `signatureBonus` is added to the lexer-derived confidence (capped\n\t * at 1.0). Patterns must be effectively impossible in any competing\n\t * language the detector will be matched against.\n\t */\n\treadonly signatures?: readonly RegExp[];\n\n\t/** Confidence bonus added on signature match. Defaults to `0.3`. */\n\treadonly signatureBonus?: number;\n\n\t/** Custom per-token-type relevance weights. Defaults to the canonical set. */\n\treadonly weights?: RelevanceWeights;\n}\n\nconst DEFAULT_MIN_LINES = 2;\nconst DEFAULT_MAX_LENGTH = 100_000;\nconst DEFAULT_MIN_CONFIDENCE = 0.35;\nconst DEFAULT_SIGNATURE_BONUS = 0.3;\n\n/**\n * Content detector that classifies pasted text using the same\n * `LanguageDefinition` employed for syntax highlighting.\n */\nexport class LexerDetector implements ContentDetector {\n\treadonly id: string;\n\n\tconstructor(\n\t\tprivate readonly language: LanguageDefinition,\n\t\tprivate readonly options: LexerDetectorOptions = {},\n\t) {\n\t\tthis.id = language.name;\n\t}\n\n\tdetect(text: string): DetectionResult | null {\n\t\tconst maxLength: number = this.options.maxLength ?? DEFAULT_MAX_LENGTH;\n\t\tif (text.length > maxLength) return null;\n\n\t\tconst trimmed: string = text.trim();\n\t\tconst minLines: number = this.options.minLines ?? DEFAULT_MIN_LINES;\n\t\tconst lines: string[] = trimmed.split('\\n').filter((l: string) => l.trim().length > 0);\n\t\tif (lines.length < minLines) return null;\n\n\t\tconst stats: TokenStats = computeTokenStats(trimmed, this.language, this.options.weights);\n\t\tconst lexerConfidence: number = scoreFromStats(stats);\n\n\t\tconst bonus: number = this.matchesAnySignature(trimmed)\n\t\t\t? (this.options.signatureBonus ?? DEFAULT_SIGNATURE_BONUS)\n\t\t\t: 0;\n\t\tconst confidence: number = Math.min(1, lexerConfidence + bonus);\n\n\t\tconst minConfidence: number = this.options.minConfidence ?? DEFAULT_MIN_CONFIDENCE;\n\t\tif (confidence < minConfidence) return null;\n\n\t\treturn { language: this.language.name, formattedText: trimmed, confidence };\n\t}\n\n\tprivate matchesAnySignature(text: string): boolean {\n\t\tconst signatures: readonly RegExp[] = this.options.signatures ?? [];\n\t\tfor (const signature of signatures) {\n\t\t\tif (signature.test(text)) return true;\n\t\t}\n\t\treturn false;\n\t}\n}\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"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"XmlPatterns-BiHS8w3k.mjs","names":[],"sources":["../../src/plugins/shared/XmlPatterns.ts"],"sourcesContent":["/**\n * Shared XML regex pattern fragments used by XmlDetector and XML language definition.\n *\n * Based on XML 1.0 spec Name production (simplified to ASCII + common extensions).\n */\n\n/** XML tag name pattern (string fragment for RegExp construction). */\nexport const XML_TAG_NAME = '[a-zA-Z_][\\\\w:.-]*';\n\n/** Optional attributes pattern (string fragment for RegExp construction). */\nexport const XML_ATTRS = '(?:\\\\s(?:[^>\"\\']|\"[^\"]*\"|\\'[^\\']*\\')*)?';\n"],"mappings":"AAOA,IAAa,EAAe,qBAGf,EAAY"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{n as t,r as e,t as n}from"./XmlDetector-DxBGXqua.mjs";import{n as a}from"./XmlPatterns-BiHS8w3k.mjs";var s={name:"java",aliases:[],patterns:[{type:"comment",pattern:/\/\*[\s\S]*?\*\//y},{type:"comment",pattern:/\/\/[^\n]*/y},{type:"string",pattern:/"""[\s\S]*?"""/y},{type:"string",pattern:/"(?:[^"\\]|\\.)*"/y},{type:"string",pattern:/'(?:[^'\\]|\\.)*'/y},{type:"annotation",pattern:/@[a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*/y},{type:"keyword",pattern:new RegExp(`(?:${["abstract","assert","boolean","break","byte","case","catch","char","class","const","continue","default","do","double","else","enum","exports","extends","final","finally","float","for","goto","if","implements","import","instanceof","int","interface","long","module","native","new","non-sealed","open","opens","package","permits","private","protected","provides","public","record","requires","return","sealed","short","static","strictfp","super","switch","synchronized","this","throw","throws","to","transient","transitive","try","uses","var","void","volatile","when","while","with","yield"].join("|")})\\b`,"y")},{type:"boolean",pattern:/(?:true|false)\b/y},{type:"null",pattern:/null\b/y},{type:"number",pattern:/0[xX][\da-fA-F](?:_*[\da-fA-F])*[lL]?/y},{type:"number",pattern:/0[bB][01](?:_*[01])*[lL]?/y},{type:"number",pattern:/\d(?:_*\d)*(?:\.(?:\d(?:_*\d)*)?)?(?:[eE][+-]?\d(?:_*\d)*)?[fFdDlL]?/y},{type:"function",pattern:/[a-zA-Z_]\w*(?=\s*\()/y},{type:"operator",pattern:/(?:>>>=?|>>=?|<<=?|->|::|\+\+|--|&&|\|\||[+\-*/%&|^~!=<>]=?|\?|:)/y},{type:"punctuation",pattern:/[{}[\]();.,]/y}]},r={id:"java",displayName:"Java",highlighting:s,detection:new e(s,{signatures:[/^[ \t]*package\s+[\w.]+\s*;/m,/^[ \t]*import\s+(?:static\s+)?[\w.]+(?:\.\*)?\s*;/m,/\bSystem\s*\.\s*(?:out|err)\s*\.\s*\w+\s*\(/,/\bpublic\s+static\s+void\s+main\s*\(\s*String\s*\[\s*\]/]})},p={name:"json",aliases:["jsonc"],patterns:[{type:"property",pattern:/"(?:[^"\\]|\\.)*"(?=\s*:)/y},{type:"string",pattern:/"(?:[^"\\]|\\.)*"/y},{type:"number",pattern:/-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/y},{type:"boolean",pattern:/(?:true|false)\b/y},{type:"null",pattern:/null\b/y},{type:"punctuation",pattern:/[{}[\]:,]/y}]},i={id:"json",displayName:"JSON",aliases:["jsonc"],highlighting:p,detection:new t},o={name:"typescript",aliases:["ts","tsx"],patterns:[{type:"comment",pattern:/\/\*[\s\S]*?\*\//y},{type:"comment",pattern:/\/\/[^\n]*/y},{type:"string",pattern:/`(?:[^`\\$]|\\.|\$(?!\{)|\$\{[^}]*\})*`/y},{type:"string",pattern:/"(?:[^"\\]|\\.)*"/y},{type:"string",pattern:/'(?:[^'\\]|\\.)*'/y},{type:"annotation",pattern:/@[a-zA-Z_$][\w$]*(?:\.[a-zA-Z_$][\w$]*)*/y},{type:"keyword",pattern:new RegExp(`(?:${["abstract","any","as","asserts","async","await","bigint","boolean","break","case","catch","class","const","constructor","continue","debugger","declare","default","delete","do","else","enum","export","extends","finally","for","from","function","get","global","if","implements","import","in","infer","instanceof","interface","is","keyof","let","module","namespace","never","new","number","object","of","out","override","package","private","protected","public","readonly","require","return","satisfies","set","static","string","super","switch","symbol","this","throw","try","type","typeof","unique","unknown","using","var","void","while","with","yield"].join("|")})\\b`,"y")},{type:"boolean",pattern:/(?:true|false)\b/y},{type:"null",pattern:/(?:null|undefined)\b/y},{type:"number",pattern:/0[xX][\da-fA-F](?:_*[\da-fA-F])*n?/y},{type:"number",pattern:/0[bB][01](?:_*[01])*n?/y},{type:"number",pattern:/0[oO][0-7](?:_*[0-7])*n?/y},{type:"number",pattern:/\d(?:_*\d)*(?:\.(?:\d(?:_*\d)*)?)?(?:[eE][+-]?\d(?:_*\d)*)?n?/y},{type:"function",pattern:/[a-zA-Z_$][\w$]*(?=\s*\()/y},{type:"operator",pattern:/(?:>>>=?|>>=?|<<=?|\*\*=?|\?\?=?|\|\|=?|&&=?|===?|!==?|=>|\?\.|\.\.\.|\+\+|--|[+\-*/%&|^~!=<>]=?|\?|:)/y},{type:"punctuation",pattern:/[{}[\]();.,]/y}]},y={id:"typescript",displayName:"TypeScript",aliases:["ts","tsx"],highlighting:o,detection:new e(o,{signatures:[/^[ \t]*import\b[^;\n]*?\bfrom\s+['"]/m,/^[ \t]*(?:export\s+)?type\s+\w+(?:\s*<[^=>]*>)?\s*=/m,/^[ \t]*declare\s+(?:const|let|var|function|class|namespace|module|global)\b/m,/[\w$\])]\??\s*:\s*(?:string|number|boolean|void|any|unknown|never|bigint|symbol|object|null|undefined)\b/,/^[ \t]*export\s+(?:default\s+|const\s+|let\s+|var\s+|function\s+|async\s+function\b|class\s+|interface\s+|enum\s+|namespace\s+|abstract\s+class\b|\*\s+from\b|\{)/m]})},l={name:"xml",aliases:["html","xhtml","svg","xsl"],patterns:[{type:"comment",pattern:/<!--[\s\S]*?-->/y},{type:"keyword",pattern:/<!\[CDATA\[[\s\S]*?\]\]>/y},{type:"keyword",pattern:/<\?[\s\S]*?\?>/y},{type:"tag",pattern:new RegExp(`<\\/${a}`,"y")},{type:"tag",pattern:new RegExp(`<${a}`,"y")},{type:"punctuation",pattern:/\/>|>|=/y},{type:"attribute",pattern:new RegExp(`${a}(?=\\s*=)`,"y")},{type:"string",pattern:/"[^"]*"/y},{type:"string",pattern:/'[^']*'/y}]},c={id:"xml",displayName:"XML",aliases:["html","xhtml","svg","xsl"],highlighting:l,detection:new n};export{i as a,s as c,o as i,l as n,p as o,y as r,r as s,c as t};
|
|
2
|
-
//# sourceMappingURL=XmlSupport-B_F65M8G.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"XmlSupport-B_F65M8G.mjs","names":[],"sources":["../../src/plugins/code-block/highlighter/languages/java.ts","../../src/plugins/language/bundles/JavaSupport.ts","../../src/plugins/code-block/highlighter/languages/json.ts","../../src/plugins/language/bundles/JsonSupport.ts","../../src/plugins/code-block/highlighter/languages/typescript.ts","../../src/plugins/language/bundles/TypeScriptSupport.ts","../../src/plugins/code-block/highlighter/languages/xml.ts","../../src/plugins/language/bundles/XmlSupport.ts"],"sourcesContent":["/**\n * Java language definition for regex-based syntax highlighting.\n *\n * Covers Java 21 syntax including sealed classes, records, pattern matching,\n * modules, text blocks, and switch expressions.\n *\n * Token type mapping:\n * - `comment` - line `//`, block, and Javadoc comments\n * - `string` - double-quoted strings, text blocks, char literals\n * - `annotation` - annotations `@Name`, `@java.lang.Override`\n * - `keyword` - Java 21 keywords (including contextual: sealed, record, var, yield, when)\n * - `boolean` - `true`, `false`\n * - `null` - `null`\n * - `number` - decimal, hex, binary, float, scientific, with underscores\n * - `function` - method/function names (identifier followed by `(`)\n * - `operator` - all Java operators including `->`, `::`, `>>>=`\n * - `punctuation` - delimiters `{}[]();.,`\n */\n\nimport type { LanguageDefinition } from '../TokenizerTypes.js';\n\nconst JAVA_KEYWORDS: readonly string[] = [\n\t'abstract',\n\t'assert',\n\t'boolean',\n\t'break',\n\t'byte',\n\t'case',\n\t'catch',\n\t'char',\n\t'class',\n\t'const',\n\t'continue',\n\t'default',\n\t'do',\n\t'double',\n\t'else',\n\t'enum',\n\t'exports',\n\t'extends',\n\t'final',\n\t'finally',\n\t'float',\n\t'for',\n\t'goto',\n\t'if',\n\t'implements',\n\t'import',\n\t'instanceof',\n\t'int',\n\t'interface',\n\t'long',\n\t'module',\n\t'native',\n\t'new',\n\t'non-sealed',\n\t'open',\n\t'opens',\n\t'package',\n\t'permits',\n\t'private',\n\t'protected',\n\t'provides',\n\t'public',\n\t'record',\n\t'requires',\n\t'return',\n\t'sealed',\n\t'short',\n\t'static',\n\t'strictfp',\n\t'super',\n\t'switch',\n\t'synchronized',\n\t'this',\n\t'throw',\n\t'throws',\n\t'to',\n\t'transient',\n\t'transitive',\n\t'try',\n\t'uses',\n\t'var',\n\t'void',\n\t'volatile',\n\t'when',\n\t'while',\n\t'with',\n\t'yield',\n];\n\nconst KEYWORD_PATTERN: RegExp = new RegExp(`(?:${JAVA_KEYWORDS.join('|')})\\\\b`, 'y');\n\nexport const JAVA_LANGUAGE: LanguageDefinition = {\n\tname: 'java',\n\taliases: [],\n\tpatterns: [\n\t\t// 1. Block/Javadoc comments — before `/` operator\n\t\t{ type: 'comment', pattern: /\\/\\*[\\s\\S]*?\\*\\//y },\n\t\t// 2. Line comments — before `/` operator\n\t\t{ type: 'comment', pattern: /\\/\\/[^\\n]*/y },\n\t\t// 3. Text blocks `\"\"\"...\"\"\"` — before empty string `\"\"`\n\t\t{ type: 'string', pattern: /\"\"\"[\\s\\S]*?\"\"\"/y },\n\t\t// 4. Double-quoted strings — escape-aware\n\t\t{ type: 'string', pattern: /\"(?:[^\"\\\\]|\\\\.)*\"/y },\n\t\t// 5. Char literals — escape-aware\n\t\t{ type: 'string', pattern: /'(?:[^'\\\\]|\\\\.)*'/y },\n\t\t// 6. Annotations — before operators (captures `@`)\n\t\t{ type: 'annotation', pattern: /@[a-zA-Z_]\\w*(?:\\.[a-zA-Z_]\\w*)*/y },\n\t\t// 7. Keywords — before functions (`if(` = keyword, not function)\n\t\t{ type: 'keyword', pattern: KEYWORD_PATTERN },\n\t\t// 8. Booleans\n\t\t{ type: 'boolean', pattern: /(?:true|false)\\b/y },\n\t\t// 9. Null\n\t\t{ type: 'null', pattern: /null\\b/y },\n\t\t// 10. Hex numbers — before decimal (both can start with `0`)\n\t\t{ type: 'number', pattern: /0[xX][\\da-fA-F](?:_*[\\da-fA-F])*[lL]?/y },\n\t\t// 11. Binary numbers — before decimal\n\t\t{ type: 'number', pattern: /0[bB][01](?:_*[01])*[lL]?/y },\n\t\t// 12. Decimal/float/scientific numbers — with underscore and suffix support\n\t\t{\n\t\t\ttype: 'number',\n\t\t\tpattern: /\\d(?:_*\\d)*(?:\\.(?:\\d(?:_*\\d)*)?)?(?:[eE][+-]?\\d(?:_*\\d)*)?[fFdDlL]?/y,\n\t\t},\n\t\t// 13. Function/method names — identifier followed by `(`\n\t\t{ type: 'function', pattern: /[a-zA-Z_]\\w*(?=\\s*\\()/y },\n\t\t// 14. Operators\n\t\t{\n\t\t\ttype: 'operator',\n\t\t\tpattern: /(?:>>>=?|>>=?|<<=?|->|::|\\+\\+|--|&&|\\|\\||[+\\-*/%&|^~!=<>]=?|\\?|:)/y,\n\t\t},\n\t\t// 15. Punctuation — catch-all delimiters\n\t\t{ type: 'punctuation', pattern: /[{}[\\]();.,]/y },\n\t],\n};\n","/**\n * Built-in Java language support bundle.\n * Includes syntax highlighting (Java 21) and lexer-based smart-paste detection.\n *\n * Detection re-uses the same `JAVA_LANGUAGE` token definition that powers\n * highlighting — see `LexerDetector` for the algorithm. Smoking-gun\n * signatures encode constructs that are syntactically impossible outside\n * Java: dotted-path imports terminated by `;`, file-leading `package`\n * declarations, the canonical `main(String[] args)` entry point, and\n * `System.out` / `System.err` calls.\n */\n\nimport { JAVA_LANGUAGE } from '../../code-block/highlighter/languages/java.js';\nimport { LexerDetector } from '../../smart-paste/detectors/LexerDetector.js';\nimport type { LanguageSupport } from '../LanguageTypes.js';\n\nconst JAVA_SIGNATURES: readonly RegExp[] = [\n\t/^[ \\t]*package\\s+[\\w.]+\\s*;/m,\n\t/^[ \\t]*import\\s+(?:static\\s+)?[\\w.]+(?:\\.\\*)?\\s*;/m,\n\t/\\bSystem\\s*\\.\\s*(?:out|err)\\s*\\.\\s*\\w+\\s*\\(/,\n\t/\\bpublic\\s+static\\s+void\\s+main\\s*\\(\\s*String\\s*\\[\\s*\\]/,\n];\n\nexport const JAVA_SUPPORT: LanguageSupport = {\n\tid: 'java',\n\tdisplayName: 'Java',\n\thighlighting: JAVA_LANGUAGE,\n\tdetection: new LexerDetector(JAVA_LANGUAGE, { signatures: JAVA_SIGNATURES }),\n};\n","/**\n * JSON language definition for regex-based syntax highlighting.\n */\n\nimport type { LanguageDefinition } from '../TokenizerTypes.js';\n\nexport const JSON_LANGUAGE: LanguageDefinition = {\n\tname: 'json',\n\taliases: ['jsonc'],\n\tpatterns: [\n\t\t{ type: 'property', pattern: /\"(?:[^\"\\\\]|\\\\.)*\"(?=\\s*:)/y },\n\t\t{ type: 'string', pattern: /\"(?:[^\"\\\\]|\\\\.)*\"/y },\n\t\t{ type: 'number', pattern: /-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?/y },\n\t\t{ type: 'boolean', pattern: /(?:true|false)\\b/y },\n\t\t{ type: 'null', pattern: /null\\b/y },\n\t\t{ type: 'punctuation', pattern: /[{}[\\]:,]/y },\n\t],\n};\n","/**\n * Built-in JSON language support bundle.\n * Includes syntax highlighting and smart-paste detection.\n */\n\nimport { JSON_LANGUAGE } from '../../code-block/highlighter/languages/json.js';\nimport { JsonDetector } from '../../smart-paste/detectors/JsonDetector.js';\nimport type { LanguageSupport } from '../LanguageTypes.js';\n\nexport const JSON_SUPPORT: LanguageSupport = {\n\tid: 'json',\n\tdisplayName: 'JSON',\n\taliases: ['jsonc'],\n\thighlighting: JSON_LANGUAGE,\n\tdetection: new JsonDetector(),\n};\n","/**\n * TypeScript language definition for regex-based syntax highlighting.\n *\n * Covers modern TypeScript syntax including interfaces, type aliases, enums,\n * generics, decorators, async/await, optional chaining, nullish coalescing,\n * template literals, and JSX-friendly punctuation.\n *\n * Token type mapping:\n * - `comment` - line `//`, block, and JSDoc comments\n * - `string` - double/single-quoted strings, template literals\n * - `annotation` - decorators `@Name`, `@module.Name`\n * - `keyword` - JS/TS keywords (control flow, declarations, modifiers)\n * - `boolean` - `true`, `false`\n * - `null` - `null`, `undefined`\n * - `number` - decimal, hex, octal, binary, BigInt, scientific, with separators\n * - `function` - function/method names (identifier followed by `(` or `<...>(`)\n * - `operator` - all TS operators including `=>`, `??`, `?.`, `**`, `>>>=`\n * - `punctuation` - delimiters `{}[]();.,`\n *\n * Aliases: `ts`, `tsx`.\n */\n\nimport type { LanguageDefinition } from '../TokenizerTypes.js';\n\nconst TYPESCRIPT_KEYWORDS: readonly string[] = [\n\t'abstract',\n\t'any',\n\t'as',\n\t'asserts',\n\t'async',\n\t'await',\n\t'bigint',\n\t'boolean',\n\t'break',\n\t'case',\n\t'catch',\n\t'class',\n\t'const',\n\t'constructor',\n\t'continue',\n\t'debugger',\n\t'declare',\n\t'default',\n\t'delete',\n\t'do',\n\t'else',\n\t'enum',\n\t'export',\n\t'extends',\n\t'finally',\n\t'for',\n\t'from',\n\t'function',\n\t'get',\n\t'global',\n\t'if',\n\t'implements',\n\t'import',\n\t'in',\n\t'infer',\n\t'instanceof',\n\t'interface',\n\t'is',\n\t'keyof',\n\t'let',\n\t'module',\n\t'namespace',\n\t'never',\n\t'new',\n\t'number',\n\t'object',\n\t'of',\n\t'out',\n\t'override',\n\t'package',\n\t'private',\n\t'protected',\n\t'public',\n\t'readonly',\n\t'require',\n\t'return',\n\t'satisfies',\n\t'set',\n\t'static',\n\t'string',\n\t'super',\n\t'switch',\n\t'symbol',\n\t'this',\n\t'throw',\n\t'try',\n\t'type',\n\t'typeof',\n\t'unique',\n\t'unknown',\n\t'using',\n\t'var',\n\t'void',\n\t'while',\n\t'with',\n\t'yield',\n];\n\nconst KEYWORD_PATTERN: RegExp = new RegExp(`(?:${TYPESCRIPT_KEYWORDS.join('|')})\\\\b`, 'y');\n\nexport const TYPESCRIPT_LANGUAGE: LanguageDefinition = {\n\tname: 'typescript',\n\taliases: ['ts', 'tsx'],\n\tpatterns: [\n\t\t// 1. Block/JSDoc comments — before `/` operator\n\t\t{ type: 'comment', pattern: /\\/\\*[\\s\\S]*?\\*\\//y },\n\t\t// 2. Line comments — before `/` operator\n\t\t{ type: 'comment', pattern: /\\/\\/[^\\n]*/y },\n\t\t// 3. Template literals (no nested ${} parsing) — escape-aware\n\t\t{ type: 'string', pattern: /`(?:[^`\\\\$]|\\\\.|\\$(?!\\{)|\\$\\{[^}]*\\})*`/y },\n\t\t// 4. Double-quoted strings — escape-aware\n\t\t{ type: 'string', pattern: /\"(?:[^\"\\\\]|\\\\.)*\"/y },\n\t\t// 5. Single-quoted strings — escape-aware\n\t\t{ type: 'string', pattern: /'(?:[^'\\\\]|\\\\.)*'/y },\n\t\t// 6. Decorators — before operators\n\t\t{ type: 'annotation', pattern: /@[a-zA-Z_$][\\w$]*(?:\\.[a-zA-Z_$][\\w$]*)*/y },\n\t\t// 7. Keywords — before functions (`if(` = keyword, not function)\n\t\t{ type: 'keyword', pattern: KEYWORD_PATTERN },\n\t\t// 8. Booleans\n\t\t{ type: 'boolean', pattern: /(?:true|false)\\b/y },\n\t\t// 9. Null/undefined\n\t\t{ type: 'null', pattern: /(?:null|undefined)\\b/y },\n\t\t// 10. Hex numbers (with optional BigInt suffix) — before decimal\n\t\t{ type: 'number', pattern: /0[xX][\\da-fA-F](?:_*[\\da-fA-F])*n?/y },\n\t\t// 11. Binary numbers — before decimal\n\t\t{ type: 'number', pattern: /0[bB][01](?:_*[01])*n?/y },\n\t\t// 12. Octal numbers — before decimal\n\t\t{ type: 'number', pattern: /0[oO][0-7](?:_*[0-7])*n?/y },\n\t\t// 13. Decimal/float/scientific/BigInt — with numeric separator support\n\t\t{\n\t\t\ttype: 'number',\n\t\t\tpattern: /\\d(?:_*\\d)*(?:\\.(?:\\d(?:_*\\d)*)?)?(?:[eE][+-]?\\d(?:_*\\d)*)?n?/y,\n\t\t},\n\t\t// 14. Function/method names — identifier followed by `(`\n\t\t{ type: 'function', pattern: /[a-zA-Z_$][\\w$]*(?=\\s*\\()/y },\n\t\t// 15. Operators — longer alternatives first (alternation picks first match, not longest)\n\t\t{\n\t\t\ttype: 'operator',\n\t\t\tpattern:\n\t\t\t\t/(?:>>>=?|>>=?|<<=?|\\*\\*=?|\\?\\?=?|\\|\\|=?|&&=?|===?|!==?|=>|\\?\\.|\\.\\.\\.|\\+\\+|--|[+\\-*/%&|^~!=<>]=?|\\?|:)/y,\n\t\t},\n\t\t// 16. Punctuation — catch-all delimiters\n\t\t{ type: 'punctuation', pattern: /[{}[\\]();.,]/y },\n\t],\n};\n","/**\n * Built-in TypeScript language support bundle.\n * Includes syntax highlighting (modern TS) and lexer-based smart-paste detection.\n *\n * Aliases `ts` and `tsx` are accepted for the language picker and code-block fences.\n *\n * Detection re-uses the same `TYPESCRIPT_LANGUAGE` token definition that\n * powers highlighting — see `LexerDetector` for the algorithm. Smoking-gun\n * signatures encode constructs that are syntactically impossible in Java:\n * `import … from '…'`, `type X = …` aliases, `declare …` ambients,\n * `: <lowercase-primitive>` type annotations, and the `export` statement\n * starter for declarations.\n */\n\nimport { TYPESCRIPT_LANGUAGE } from '../../code-block/highlighter/languages/typescript.js';\nimport { LexerDetector } from '../../smart-paste/detectors/LexerDetector.js';\nimport type { LanguageSupport } from '../LanguageTypes.js';\n\nconst TYPESCRIPT_SIGNATURES: readonly RegExp[] = [\n\t/^[ \\t]*import\\b[^;\\n]*?\\bfrom\\s+['\"]/m,\n\t/^[ \\t]*(?:export\\s+)?type\\s+\\w+(?:\\s*<[^=>]*>)?\\s*=/m,\n\t/^[ \\t]*declare\\s+(?:const|let|var|function|class|namespace|module|global)\\b/m,\n\t/[\\w$\\])]\\??\\s*:\\s*(?:string|number|boolean|void|any|unknown|never|bigint|symbol|object|null|undefined)\\b/,\n\t/^[ \\t]*export\\s+(?:default\\s+|const\\s+|let\\s+|var\\s+|function\\s+|async\\s+function\\b|class\\s+|interface\\s+|enum\\s+|namespace\\s+|abstract\\s+class\\b|\\*\\s+from\\b|\\{)/m,\n];\n\nexport const TYPESCRIPT_SUPPORT: LanguageSupport = {\n\tid: 'typescript',\n\tdisplayName: 'TypeScript',\n\taliases: ['ts', 'tsx'],\n\thighlighting: TYPESCRIPT_LANGUAGE,\n\tdetection: new LexerDetector(TYPESCRIPT_LANGUAGE, { signatures: TYPESCRIPT_SIGNATURES }),\n};\n","/**\n * XML language definition for regex-based syntax highlighting.\n *\n * Token type mapping:\n * - `comment` — XML comments `<!-- ... -->`\n * - `keyword` — processing instructions, CDATA sections\n * - `tag` — tag names (consumed with `<`/`</` prefix)\n * - `attribute` — attribute names (identifier followed by `=`)\n * - `string` — attribute values (double or single quoted)\n * - `punctuation` — delimiters `/>`, `>`, `=`\n *\n * Tag names are combined with their `<` or `</` prefix into a single `tag` token\n * to prevent text content between tags from being incorrectly highlighted.\n */\n\nimport { XML_TAG_NAME } from '../../../shared/XmlPatterns.js';\nimport type { LanguageDefinition } from '../TokenizerTypes.js';\n\nexport const XML_LANGUAGE: LanguageDefinition = {\n\tname: 'xml',\n\taliases: ['html', 'xhtml', 'svg', 'xsl'],\n\tpatterns: [\n\t\t{ type: 'comment', pattern: /<!--[\\s\\S]*?-->/y },\n\t\t{ type: 'keyword', pattern: /<!\\[CDATA\\[[\\s\\S]*?\\]\\]>/y },\n\t\t{ type: 'keyword', pattern: /<\\?[\\s\\S]*?\\?>/y },\n\t\t{ type: 'tag', pattern: new RegExp(`<\\\\/${XML_TAG_NAME}`, 'y') },\n\t\t{ type: 'tag', pattern: new RegExp(`<${XML_TAG_NAME}`, 'y') },\n\t\t{ type: 'punctuation', pattern: /\\/>|>|=/y },\n\t\t{ type: 'attribute', pattern: new RegExp(`${XML_TAG_NAME}(?=\\\\s*=)`, 'y') },\n\t\t{ type: 'string', pattern: /\"[^\"]*\"/y },\n\t\t{ type: 'string', pattern: /'[^']*'/y },\n\t],\n};\n","/**\n * Built-in XML language support bundle.\n * Includes syntax highlighting and smart-paste detection.\n */\n\nimport { XML_LANGUAGE } from '../../code-block/highlighter/languages/xml.js';\nimport { XmlDetector } from '../../smart-paste/detectors/XmlDetector.js';\nimport type { LanguageSupport } from '../LanguageTypes.js';\n\nexport const XML_SUPPORT: LanguageSupport = {\n\tid: 'xml',\n\tdisplayName: 'XML',\n\taliases: ['html', 'xhtml', 'svg', 'xsl'],\n\thighlighting: XML_LANGUAGE,\n\tdetection: new XmlDetector(),\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ar-B38MlRRN.mjs","names":[],"sources":["../../src/plugins/text-formatting/locales/ar.ts"],"sourcesContent":["import type { TextFormattingLocale } from '../TextFormattingLocale.js';\n\nconst locale: TextFormattingLocale = {\n\tboldLabel: 'غامق',\n\titalicLabel: 'مائل',\n\tunderlineLabel: 'تحته خط',\n};\n\nexport default locale;\n"],"mappings":"AAEA,IAAM,EAA+B,CACpC,UAAW,OACX,YAAa,OACb,eAAgB"}
|