@pinkpixel/marzipan 1.0.9 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -1
- package/dist/{_basePickBy-7myk7wY6.js → _basePickBy-CBhXlrs3.js} +3 -3
- package/dist/{_basePickBy-7myk7wY6.js.map → _basePickBy-CBhXlrs3.js.map} +1 -1
- package/dist/{_baseUniq-DVSvs9C9.js → _baseUniq-BnlNEqx5.js} +2 -2
- package/dist/{_baseUniq-DVSvs9C9.js.map → _baseUniq-BnlNEqx5.js.map} +1 -1
- package/dist/actions/core/formats.d.ts.map +1 -1
- package/dist/actions/core/formats.js +5 -0
- package/dist/actions/core/formats.js.map +1 -1
- package/dist/actions/index.d.ts +4 -0
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +20 -0
- package/dist/actions/index.js.map +1 -1
- package/dist/{arc-CfMWIGxd.js → arc-DKfQKN_X.js} +2 -2
- package/dist/{arc-CfMWIGxd.js.map → arc-DKfQKN_X.js.map} +1 -1
- package/dist/{architectureDiagram-VXUJARFQ-BUbrFcAV.js → architectureDiagram-VXUJARFQ-DyTB8Kgd.js} +5 -5
- package/dist/{architectureDiagram-VXUJARFQ-BUbrFcAV.js.map → architectureDiagram-VXUJARFQ-DyTB8Kgd.js.map} +1 -1
- package/dist/{blockDiagram-VD42YOAC-jy_Bz7_a.js → blockDiagram-VD42YOAC-BCYA47jf.js} +7 -12
- package/dist/{blockDiagram-VD42YOAC-jy_Bz7_a.js.map → blockDiagram-VD42YOAC-BCYA47jf.js.map} +1 -1
- package/dist/{c4Diagram-YG6GDRKO-D-ENeA7h.js → c4Diagram-YG6GDRKO-ChtfMRpM.js} +3 -3
- package/dist/{c4Diagram-YG6GDRKO-D-ENeA7h.js.map → c4Diagram-YG6GDRKO-ChtfMRpM.js.map} +1 -1
- package/dist/channel-XZzkxuXg.js +6 -0
- package/dist/{channel-BCTxewZI.js.map → channel-XZzkxuXg.js.map} +1 -1
- package/dist/{chunk-4BX2VUAB-BPOEnnJc.js → chunk-4BX2VUAB-Cx8HPvOf.js} +2 -2
- package/dist/{chunk-4BX2VUAB-BPOEnnJc.js.map → chunk-4BX2VUAB-Cx8HPvOf.js.map} +1 -1
- package/dist/{chunk-55IACEB6-CvbNm4Ij.js → chunk-55IACEB6-DGQSbiTY.js} +2 -2
- package/dist/{chunk-55IACEB6-CvbNm4Ij.js.map → chunk-55IACEB6-DGQSbiTY.js.map} +1 -1
- package/dist/{chunk-B4BG7PRW-C_qWbbk6.js → chunk-B4BG7PRW-CY260R4Q.js} +5 -5
- package/dist/{chunk-B4BG7PRW-C_qWbbk6.js.map → chunk-B4BG7PRW-CY260R4Q.js.map} +1 -1
- package/dist/{chunk-DI55MBZ5-BiWs6KMl.js → chunk-DI55MBZ5-B4h9UrCS.js} +4 -4
- package/dist/{chunk-DI55MBZ5-BiWs6KMl.js.map → chunk-DI55MBZ5-B4h9UrCS.js.map} +1 -1
- package/dist/{chunk-FMBD7UC4-B9NJjOBf.js → chunk-FMBD7UC4-BrVGjj-q.js} +2 -2
- package/dist/{chunk-FMBD7UC4-B9NJjOBf.js.map → chunk-FMBD7UC4-BrVGjj-q.js.map} +1 -1
- package/dist/{chunk-QN33PNHL-0k4tnBW4.js → chunk-QN33PNHL-DZm-2bJu.js} +2 -2
- package/dist/{chunk-QN33PNHL-0k4tnBW4.js.map → chunk-QN33PNHL-DZm-2bJu.js.map} +1 -1
- package/dist/{chunk-QZHKN3VN-Cqlx-pCX.js → chunk-QZHKN3VN-Hi_p5q2K.js} +2 -2
- package/dist/{chunk-QZHKN3VN-Cqlx-pCX.js.map → chunk-QZHKN3VN-Hi_p5q2K.js.map} +1 -1
- package/dist/{chunk-TZMSLE5B-CIL9qnEM.js → chunk-TZMSLE5B-CIZlLW3r.js} +2 -2
- package/dist/{chunk-TZMSLE5B-CIL9qnEM.js.map → chunk-TZMSLE5B-CIZlLW3r.js.map} +1 -1
- package/dist/{classDiagram-2ON5EDUG-Cg641kit.js → classDiagram-2ON5EDUG-QSrTDjZ0.js} +3 -3
- package/dist/{classDiagram-2ON5EDUG-Cg641kit.js.map → classDiagram-2ON5EDUG-QSrTDjZ0.js.map} +1 -1
- package/dist/{classDiagram-2ON5EDUG-DvfCZ1-0.js → classDiagram-v2-WZHVMYZB-QSrTDjZ0.js} +3 -3
- package/dist/{classDiagram-v2-WZHVMYZB-Cg641kit.js.map → classDiagram-v2-WZHVMYZB-QSrTDjZ0.js.map} +1 -1
- package/dist/clone-B6rhP1DC.js +9 -0
- package/dist/{clone-BZ5Rkhbx.js.map → clone-B6rhP1DC.js.map} +1 -1
- package/dist/{cose-bilkent-S5V4N54A-DIb5rck_.js → cose-bilkent-S5V4N54A-Cz05oWQ-.js} +3 -3
- package/dist/{cose-bilkent-S5V4N54A-DIb5rck_.js.map → cose-bilkent-S5V4N54A-Cz05oWQ-.js.map} +1 -1
- package/dist/{cytoscape.esm-DfdJODL8.js → cytoscape.esm-Cvf3sx9F.js} +16 -47
- package/dist/{cytoscape.esm-DfdJODL8.js.map → cytoscape.esm-Cvf3sx9F.js.map} +1 -1
- package/dist/{dagre-6UL2VRFP-BFkZcVkL.js → dagre-6UL2VRFP-24cZIDCv.js} +7 -7
- package/dist/{dagre-6UL2VRFP-BFkZcVkL.js.map → dagre-6UL2VRFP-24cZIDCv.js.map} +1 -1
- package/dist/defaultLocale-BgPVtth8.js +172 -0
- package/dist/defaultLocale-BgPVtth8.js.map +1 -0
- package/dist/{diagram-PSM6KHXK-DyiwV-ia.js → diagram-PSM6KHXK-hMkwALkg.js} +7 -7
- package/dist/{diagram-PSM6KHXK-DyiwV-ia.js.map → diagram-PSM6KHXK-hMkwALkg.js.map} +1 -1
- package/dist/{diagram-QEK2KX5R-DxjNZqZ_.js → diagram-QEK2KX5R-DN407_qN.js} +4 -4
- package/dist/{diagram-QEK2KX5R-DxjNZqZ_.js.map → diagram-QEK2KX5R-DN407_qN.js.map} +1 -1
- package/dist/{diagram-S2PKOQOG-CCX3j4vi.js → diagram-S2PKOQOG-DYfbxKMk.js} +4 -4
- package/dist/{diagram-S2PKOQOG-BOO6_G9V.js.map → diagram-S2PKOQOG-DYfbxKMk.js.map} +1 -1
- package/dist/{erDiagram-Q2GNP2WA-Bm9LxMmY.js → erDiagram-Q2GNP2WA-CyzD1x2b.js} +5 -5
- package/dist/{erDiagram-Q2GNP2WA-Bm9LxMmY.js.map → erDiagram-Q2GNP2WA-CyzD1x2b.js.map} +1 -1
- package/dist/{flowDiagram-NV44I4VS-CDsRBuXA.js → flowDiagram-NV44I4VS-BHrJSYHv.js} +6 -6
- package/dist/{flowDiagram-NV44I4VS-CDsRBuXA.js.map → flowDiagram-NV44I4VS-BHrJSYHv.js.map} +1 -1
- package/dist/ganttDiagram-JELNMOA3-DibD3FLu.js +2671 -0
- package/dist/ganttDiagram-JELNMOA3-DibD3FLu.js.map +1 -0
- package/dist/{gitGraphDiagram-NY62KEGX-BgmbSTgN.js → gitGraphDiagram-V2S2FVAM-BlXeU9uI.js} +5 -5
- package/dist/gitGraphDiagram-V2S2FVAM-BlXeU9uI.js.map +1 -0
- package/dist/{graph-CSVEP8oS.js → graph-BN01VVM9.js} +3 -3
- package/dist/{graph-CSVEP8oS.js.map → graph-BN01VVM9.js.map} +1 -1
- package/dist/index-DjXgvYA3.js +36 -0
- package/dist/index-DjXgvYA3.js.map +1 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +357 -303
- package/dist/index.js.map +1 -1
- package/dist/{infoDiagram-F6ZHWCRC-BIKrEuHs.js → infoDiagram-HS3SLOUP-Dqf1wtMF.js} +3 -3
- package/dist/{infoDiagram-F6ZHWCRC-BIKrEuHs.js.map → infoDiagram-HS3SLOUP-Dqf1wtMF.js.map} +1 -1
- package/dist/{journeyDiagram-XKPGCS4Q-B5P7hkT-.js → journeyDiagram-XKPGCS4Q-DCJl6fPA.js} +5 -5
- package/dist/{journeyDiagram-XKPGCS4Q-B5P7hkT-.js.map → journeyDiagram-XKPGCS4Q-DCJl6fPA.js.map} +1 -1
- package/dist/{kanban-definition-3W4ZIXB7-DJzoU3Tr.js → kanban-definition-3W4ZIXB7-C4uKwcnd.js} +3 -3
- package/dist/{kanban-definition-3W4ZIXB7-CLtnd0xR.js.map → kanban-definition-3W4ZIXB7-C4uKwcnd.js.map} +1 -1
- package/dist/{layout-CdTiJocX.js → layout-DPZm-_SA.js} +33 -22
- package/dist/layout-DPZm-_SA.js.map +1 -0
- package/dist/{linear-Cr_O1Zei.js → linear-DgKHAz_i.js} +3 -3
- package/dist/{linear-BhblBDrV.js.map → linear-DgKHAz_i.js.map} +1 -1
- package/dist/marzipan.d.ts.map +1 -1
- package/dist/marzipan.js +9 -5
- package/dist/marzipan.js.map +1 -1
- package/dist/{mermaid.core-DENutRS8.js → mermaid.core-KR6iXUBd.js} +430 -415
- package/dist/{mermaid.core-BwjwqwU6.js.map → mermaid.core-KR6iXUBd.js.map} +1 -1
- package/dist/{mindmap-definition-VGOIOE7T-BNBUkXyU.js → mindmap-definition-VGOIOE7T-DDKBtjHc.js} +4 -4
- package/dist/{mindmap-definition-VGOIOE7T-BNBUkXyU.js.map → mindmap-definition-VGOIOE7T-DDKBtjHc.js.map} +1 -1
- package/dist/{ordinal-DfAQgscy.js → ordinal-B6-f3MAq.js} +2 -2
- package/dist/{ordinal-DfAQgscy.js.map → ordinal-B6-f3MAq.js.map} +1 -1
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +0 -4
- package/dist/parser.js.map +1 -1
- package/dist/{pieDiagram-ADFJNKIX-BND3UUQ-.js → pieDiagram-ADFJNKIX-hp1Z1x8W.js} +6 -6
- package/dist/{pieDiagram-ADFJNKIX-BND3UUQ-.js.map → pieDiagram-ADFJNKIX-hp1Z1x8W.js.map} +1 -1
- package/dist/plugins/accentSwatchPlugin.d.ts.map +1 -1
- package/dist/plugins/accentSwatchPlugin.js +33 -33
- package/dist/plugins/accentSwatchPlugin.js.map +1 -1
- package/dist/plugins/block-handles.d.ts +24 -9
- package/dist/plugins/block-handles.d.ts.map +1 -1
- package/dist/plugins/block-handles.js +102 -78
- package/dist/plugins/block-handles.js.map +1 -1
- package/dist/plugins/imageManagerPlugin.js.map +1 -1
- package/dist/plugins/index.d.ts +16 -0
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +29 -2
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/mermaidPlugin.js +1 -1
- package/dist/plugins/tableGridPlugin.d.ts.map +1 -1
- package/dist/plugins/tableGridPlugin.js +23 -23
- package/dist/plugins/tableGridPlugin.js.map +1 -1
- package/dist/{quadrantDiagram-AYHSOK5B-iCwbSiz2.js → quadrantDiagram-AYHSOK5B-B9wjnoWH.js} +3 -3
- package/dist/{quadrantDiagram-AYHSOK5B-CnLHbrEF.js.map → quadrantDiagram-AYHSOK5B-B9wjnoWH.js.map} +1 -1
- package/dist/{requirementDiagram-UZGBJVZJ-CH1vdgr6.js → requirementDiagram-UZGBJVZJ-CAYg9pNG.js} +4 -4
- package/dist/{requirementDiagram-UZGBJVZJ-CH1vdgr6.js.map → requirementDiagram-UZGBJVZJ-CAYg9pNG.js.map} +1 -1
- package/dist/{sankeyDiagram-TZEHDZUN-CV5-bwv8.js → sankeyDiagram-TZEHDZUN-Dbi0-ImG.js} +3 -3
- package/dist/{sankeyDiagram-TZEHDZUN-CV5-bwv8.js.map → sankeyDiagram-TZEHDZUN-Dbi0-ImG.js.map} +1 -1
- package/dist/{sequenceDiagram-WL72ISMW-Cq1otbHU.js → sequenceDiagram-WL72ISMW-CgnGVPN0.js} +4 -4
- package/dist/{sequenceDiagram-WL72ISMW-BG1sXWAR.js.map → sequenceDiagram-WL72ISMW-CgnGVPN0.js.map} +1 -1
- package/dist/{stateDiagram-FKZM4ZOC-BJ5UwskL.js → stateDiagram-FKZM4ZOC-BnrHMBt-.js} +5 -5
- package/dist/{stateDiagram-FKZM4ZOC-BJ5UwskL.js.map → stateDiagram-FKZM4ZOC-BnrHMBt-.js.map} +1 -1
- package/dist/{stateDiagram-v2-4FDKWEC3-BbM9NXKp.js → stateDiagram-v2-4FDKWEC3-CvQCssRZ.js} +3 -3
- package/dist/{stateDiagram-v2-4FDKWEC3-BbM9NXKp.js.map → stateDiagram-v2-4FDKWEC3-CvQCssRZ.js.map} +1 -1
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +25 -21
- package/dist/styles.js.map +1 -1
- package/dist/themes.d.ts +6 -0
- package/dist/themes.d.ts.map +1 -1
- package/dist/themes.js +2 -0
- package/dist/themes.js.map +1 -1
- package/dist/{timeline-definition-IT6M3QCI-B4lGoGS8.js → timeline-definition-IT6M3QCI-C9po0EuD.js} +3 -3
- package/dist/{timeline-definition-IT6M3QCI-CqPEUsh4.js.map → timeline-definition-IT6M3QCI-C9po0EuD.js.map} +1 -1
- package/dist/treemap-GDKQZRPO-DUJ_UgsM.js +17929 -0
- package/dist/treemap-GDKQZRPO-DUJ_UgsM.js.map +1 -0
- package/dist/{xychartDiagram-PRI3JC2R-C3_IO4Rm.js → xychartDiagram-PRI3JC2R-Daz1URdd.js} +4 -4
- package/dist/{xychartDiagram-PRI3JC2R-C3_IO4Rm.js.map → xychartDiagram-PRI3JC2R-Daz1URdd.js.map} +1 -1
- package/docs/.vitepress/config.ts +77 -0
- package/docs/README.md +3 -1
- package/docs/TABLE_OF_CONTENTS.md +1 -0
- package/docs/api.md +42 -2
- package/docs/{block-handles.README.md → block-handles.md} +2 -6
- package/docs/index.md +95 -0
- package/docs/plugins.md +24 -0
- package/docs/public/favicon.png +0 -0
- package/docs/public/logo.png +0 -0
- package/docs/types.d.ts +1 -1
- package/docs/types.md +150 -0
- package/package.json +11 -4
- package/dist/_basePickBy-BXyyc71p.js +0 -152
- package/dist/_basePickBy-BXyyc71p.js.map +0 -1
- package/dist/_baseUniq-Dde5pUWM.js +0 -615
- package/dist/_baseUniq-Dde5pUWM.js.map +0 -1
- package/dist/arc-wOVD9GAB.js +0 -84
- package/dist/arc-wOVD9GAB.js.map +0 -1
- package/dist/architectureDiagram-VXUJARFQ-Bb4i7x-6.js +0 -4663
- package/dist/architectureDiagram-VXUJARFQ-Bb4i7x-6.js.map +0 -1
- package/dist/blockDiagram-VD42YOAC-ldSoJhgA.js +0 -2262
- package/dist/blockDiagram-VD42YOAC-ldSoJhgA.js.map +0 -1
- package/dist/c4Diagram-YG6GDRKO-zzDx0s1r.js +0 -1581
- package/dist/c4Diagram-YG6GDRKO-zzDx0s1r.js.map +0 -1
- package/dist/channel-BCTxewZI.js +0 -6
- package/dist/channel-CwQyz_h8.js +0 -6
- package/dist/channel-CwQyz_h8.js.map +0 -1
- package/dist/chunk-4BX2VUAB-Cfh_4i4X.js +0 -9
- package/dist/chunk-4BX2VUAB-Cfh_4i4X.js.map +0 -1
- package/dist/chunk-55IACEB6-DNOIVRvW.js +0 -9
- package/dist/chunk-55IACEB6-DNOIVRvW.js.map +0 -1
- package/dist/chunk-B4BG7PRW-DeY8sefa.js +0 -1376
- package/dist/chunk-B4BG7PRW-DeY8sefa.js.map +0 -1
- package/dist/chunk-DI55MBZ5-D_yXJA03.js +0 -1371
- package/dist/chunk-DI55MBZ5-D_yXJA03.js.map +0 -1
- package/dist/chunk-FMBD7UC4-DFfhN2XA.js +0 -20
- package/dist/chunk-FMBD7UC4-DFfhN2XA.js.map +0 -1
- package/dist/chunk-QN33PNHL-CVrLUVsI.js +0 -20
- package/dist/chunk-QN33PNHL-CVrLUVsI.js.map +0 -1
- package/dist/chunk-QZHKN3VN-FvAf_VJR.js +0 -16
- package/dist/chunk-QZHKN3VN-FvAf_VJR.js.map +0 -1
- package/dist/chunk-TZMSLE5B-DxYTPD3t.js +0 -65
- package/dist/chunk-TZMSLE5B-DxYTPD3t.js.map +0 -1
- package/dist/classDiagram-2ON5EDUG-DvfCZ1-0.js.map +0 -1
- package/dist/classDiagram-v2-WZHVMYZB-Cg641kit.js +0 -17
- package/dist/classDiagram-v2-WZHVMYZB-DvfCZ1-0.js +0 -17
- package/dist/classDiagram-v2-WZHVMYZB-DvfCZ1-0.js.map +0 -1
- package/dist/clone-BZ5Rkhbx.js +0 -9
- package/dist/clone-D062_nJ-.js +0 -9
- package/dist/clone-D062_nJ-.js.map +0 -1
- package/dist/cose-bilkent-S5V4N54A-Doh7yBTX.js +0 -2609
- package/dist/cose-bilkent-S5V4N54A-Doh7yBTX.js.map +0 -1
- package/dist/dagre-6UL2VRFP-CZKadRq9.js +0 -445
- package/dist/dagre-6UL2VRFP-CZKadRq9.js.map +0 -1
- package/dist/defaultLocale-D7EN2tov.js +0 -172
- package/dist/defaultLocale-D7EN2tov.js.map +0 -1
- package/dist/diagram-PSM6KHXK-VDtnZynV.js +0 -532
- package/dist/diagram-PSM6KHXK-VDtnZynV.js.map +0 -1
- package/dist/diagram-QEK2KX5R-Dczirmo7.js +0 -218
- package/dist/diagram-QEK2KX5R-Dczirmo7.js.map +0 -1
- package/dist/diagram-S2PKOQOG-BOO6_G9V.js +0 -143
- package/dist/diagram-S2PKOQOG-CCX3j4vi.js.map +0 -1
- package/dist/erDiagram-Q2GNP2WA-nwmrf6lJ.js +0 -842
- package/dist/erDiagram-Q2GNP2WA-nwmrf6lJ.js.map +0 -1
- package/dist/flowDiagram-NV44I4VS-DQEdMlRX.js +0 -1621
- package/dist/flowDiagram-NV44I4VS-DQEdMlRX.js.map +0 -1
- package/dist/ganttDiagram-LVOFAZNH-BHG15mHm.js +0 -2506
- package/dist/ganttDiagram-LVOFAZNH-BHG15mHm.js.map +0 -1
- package/dist/ganttDiagram-LVOFAZNH-WMiy-Gep.js +0 -2506
- package/dist/ganttDiagram-LVOFAZNH-WMiy-Gep.js.map +0 -1
- package/dist/gitGraphDiagram-NY62KEGX-BgmbSTgN.js.map +0 -1
- package/dist/gitGraphDiagram-NY62KEGX-D_Oe_z5q.js +0 -700
- package/dist/gitGraphDiagram-NY62KEGX-D_Oe_z5q.js.map +0 -1
- package/dist/graph-DnSw707R.js +0 -248
- package/dist/graph-DnSw707R.js.map +0 -1
- package/dist/infoDiagram-F6ZHWCRC-BzTgHHGF.js +0 -25
- package/dist/infoDiagram-F6ZHWCRC-BzTgHHGF.js.map +0 -1
- package/dist/journeyDiagram-XKPGCS4Q-Cwx0rvbI.js +0 -835
- package/dist/journeyDiagram-XKPGCS4Q-Cwx0rvbI.js.map +0 -1
- package/dist/kanban-definition-3W4ZIXB7-CLtnd0xR.js +0 -720
- package/dist/kanban-definition-3W4ZIXB7-DJzoU3Tr.js.map +0 -1
- package/dist/layout-CdTiJocX.js.map +0 -1
- package/dist/layout-mDCCYMKB.js +0 -1325
- package/dist/layout-mDCCYMKB.js.map +0 -1
- package/dist/linear-BhblBDrV.js +0 -260
- package/dist/linear-Cr_O1Zei.js.map +0 -1
- package/dist/mermaid.core-BwjwqwU6.js +0 -15249
- package/dist/mermaid.core-DENutRS8.js.map +0 -1
- package/dist/mindmap-definition-VGOIOE7T-BXBE9eta.js +0 -785
- package/dist/mindmap-definition-VGOIOE7T-BXBE9eta.js.map +0 -1
- package/dist/pieDiagram-ADFJNKIX-DgEtM4kB.js +0 -162
- package/dist/pieDiagram-ADFJNKIX-DgEtM4kB.js.map +0 -1
- package/dist/quadrantDiagram-AYHSOK5B-CnLHbrEF.js +0 -1023
- package/dist/quadrantDiagram-AYHSOK5B-iCwbSiz2.js.map +0 -1
- package/dist/requirementDiagram-UZGBJVZJ-caC7K17a.js +0 -851
- package/dist/requirementDiagram-UZGBJVZJ-caC7K17a.js.map +0 -1
- package/dist/sankeyDiagram-TZEHDZUN-Gl503N-l.js +0 -811
- package/dist/sankeyDiagram-TZEHDZUN-Gl503N-l.js.map +0 -1
- package/dist/sequenceDiagram-WL72ISMW-BG1sXWAR.js +0 -2512
- package/dist/sequenceDiagram-WL72ISMW-Cq1otbHU.js.map +0 -1
- package/dist/stateDiagram-FKZM4ZOC-DZEKan9V.js +0 -264
- package/dist/stateDiagram-FKZM4ZOC-DZEKan9V.js.map +0 -1
- package/dist/stateDiagram-v2-4FDKWEC3-H1gqsSsO.js +0 -17
- package/dist/stateDiagram-v2-4FDKWEC3-H1gqsSsO.js.map +0 -1
- package/dist/timeline-definition-IT6M3QCI-B4lGoGS8.js.map +0 -1
- package/dist/timeline-definition-IT6M3QCI-CqPEUsh4.js +0 -796
- package/dist/treemap-75Q7IDZK-Cx8WKL-4.js +0 -12988
- package/dist/treemap-75Q7IDZK-Cx8WKL-4.js.map +0 -1
- package/dist/treemap-75Q7IDZK-DmPg5GN7.js +0 -12988
- package/dist/treemap-75Q7IDZK-DmPg5GN7.js.map +0 -1
- package/dist/xychartDiagram-PRI3JC2R-DnhFwjWO.js +0 -1341
- package/dist/xychartDiagram-PRI3JC2R-DnhFwjWO.js.map +0 -1
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
class r {
|
|
2
|
-
constructor(e, t,
|
|
2
|
+
constructor(e, t, n = {}) {
|
|
3
3
|
this.editor = e, this.preview = t, this.config = {
|
|
4
|
-
enabled:
|
|
5
|
-
showOnHover:
|
|
6
|
-
handleOffset:
|
|
7
|
-
handleSize:
|
|
4
|
+
enabled: n.enabled ?? !0,
|
|
5
|
+
showOnHover: n.showOnHover ?? !0,
|
|
6
|
+
handleOffset: n.handleOffset ?? 4,
|
|
7
|
+
handleSize: n.handleSize ?? 20,
|
|
8
8
|
colors: {
|
|
9
|
-
hover:
|
|
10
|
-
selected:
|
|
11
|
-
handle:
|
|
9
|
+
hover: n.colors?.hover ?? "rgba(59, 130, 246, 0.1)",
|
|
10
|
+
selected: n.colors?.selected ?? "rgba(59, 130, 246, 0.2)",
|
|
11
|
+
handle: n.colors?.handle ?? "rgba(59, 130, 246, 0.8)"
|
|
12
12
|
}
|
|
13
|
-
}, this.blocks = /* @__PURE__ */ new Map(), this.selectedBlockId = null, this.handleContainer = null, this.initialize();
|
|
13
|
+
}, this.blocks = /* @__PURE__ */ new Map(), this.selectedBlockId = null, this.handleContainer = null, this._boundMouseMove = this.handleMouseMove.bind(this), this._boundMouseLeave = this.handleMouseLeave.bind(this), this._boundClick = this.handleClick.bind(this), this._boundKeyDown = this.handleKeyDown.bind(this), this.initialize();
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* Initialize the plugin
|
|
@@ -19,7 +19,9 @@ class r {
|
|
|
19
19
|
this.config.enabled && (this.createHandleContainer(), this.setupEventListeners(), this.scanBlocks());
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
|
-
* Create the container for block handles
|
|
22
|
+
* Create the container for block handles.
|
|
23
|
+
* Appended to the wrapper (parent of preview) so it sits above the textarea
|
|
24
|
+
* and is not subject to the preview's pointer-events: none rule.
|
|
23
25
|
*/
|
|
24
26
|
createHandleContainer() {
|
|
25
27
|
this.handleContainer = document.createElement("div"), this.handleContainer.className = "mz-block-handles", this.handleContainer.style.cssText = `
|
|
@@ -29,14 +31,18 @@ class r {
|
|
|
29
31
|
width: 100%;
|
|
30
32
|
height: 100%;
|
|
31
33
|
pointer-events: none;
|
|
32
|
-
z-index:
|
|
33
|
-
|
|
34
|
+
z-index: 2;
|
|
35
|
+
`;
|
|
36
|
+
const e = this.preview.parentElement;
|
|
37
|
+
e && e.appendChild(this.handleContainer);
|
|
34
38
|
}
|
|
35
39
|
/**
|
|
36
|
-
* Set up event listeners for block interactions
|
|
40
|
+
* Set up event listeners for block interactions.
|
|
41
|
+
* We listen on both the textarea (normal mode) and the preview (preview mode),
|
|
42
|
+
* since in preview mode the textarea is display:none and the preview has pointer-events:auto.
|
|
37
43
|
*/
|
|
38
44
|
setupEventListeners() {
|
|
39
|
-
this.
|
|
45
|
+
this.editor.addEventListener("mousemove", this._boundMouseMove), this.editor.addEventListener("mouseleave", this._boundMouseLeave), this.editor.addEventListener("click", this._boundClick), this.preview.addEventListener("mousemove", this._boundMouseMove), this.preview.addEventListener("mouseleave", this._boundMouseLeave), this.preview.addEventListener("click", this._boundClick), document.addEventListener("keydown", this._boundKeyDown);
|
|
40
46
|
}
|
|
41
47
|
/**
|
|
42
48
|
* Scan the preview for blocks and create handles
|
|
@@ -44,25 +50,25 @@ class r {
|
|
|
44
50
|
scanBlocks() {
|
|
45
51
|
if (this.blocks.clear(), !this.handleContainer) return;
|
|
46
52
|
this.handleContainer.innerHTML = "", this.preview.querySelectorAll("[data-block-id]").forEach((t) => {
|
|
47
|
-
const i =
|
|
53
|
+
const n = t, i = n.getAttribute("data-block-id"), s = n.getAttribute("data-block-type"), c = parseInt(n.getAttribute("data-line-start") || "0", 10), l = parseInt(n.getAttribute("data-line-end") || "0", 10);
|
|
48
54
|
if (!i) return;
|
|
49
|
-
const
|
|
55
|
+
const a = this.createHandle(i, s || "paragraph");
|
|
50
56
|
this.blocks.set(i, {
|
|
51
57
|
id: i,
|
|
52
58
|
type: s || "paragraph",
|
|
53
|
-
lineStart:
|
|
54
|
-
lineEnd:
|
|
55
|
-
element:
|
|
56
|
-
handleElement:
|
|
59
|
+
lineStart: c,
|
|
60
|
+
lineEnd: l,
|
|
61
|
+
element: n,
|
|
62
|
+
handleElement: a
|
|
57
63
|
});
|
|
58
64
|
});
|
|
59
65
|
}
|
|
60
66
|
/**
|
|
61
67
|
* Create a handle element for a block
|
|
62
68
|
*/
|
|
63
|
-
createHandle(e, t
|
|
64
|
-
const
|
|
65
|
-
return
|
|
69
|
+
createHandle(e, t) {
|
|
70
|
+
const n = document.createElement("div");
|
|
71
|
+
return n.className = `mz-block-handle mz-block-handle-${t}`, n.setAttribute("data-block-id", e), n.style.cssText = `
|
|
66
72
|
position: absolute;
|
|
67
73
|
width: ${this.config.handleSize}px;
|
|
68
74
|
height: ${this.config.handleSize}px;
|
|
@@ -72,18 +78,18 @@ class r {
|
|
|
72
78
|
cursor: pointer;
|
|
73
79
|
opacity: 0;
|
|
74
80
|
transition: opacity 0.2s ease;
|
|
75
|
-
pointer-events:
|
|
81
|
+
pointer-events: none;
|
|
76
82
|
display: flex;
|
|
77
83
|
align-items: center;
|
|
78
84
|
justify-content: center;
|
|
79
85
|
color: white;
|
|
80
86
|
font-size: 12px;
|
|
81
87
|
user-select: none;
|
|
82
|
-
`,
|
|
83
|
-
|
|
84
|
-
}),
|
|
85
|
-
|
|
86
|
-
}), this.handleContainer?.appendChild(
|
|
88
|
+
`, n.innerHTML = this.getHandleIcon(t), n.addEventListener("click", (i) => {
|
|
89
|
+
i.stopPropagation(), this.selectBlock(e);
|
|
90
|
+
}), n.addEventListener("contextmenu", (i) => {
|
|
91
|
+
i.preventDefault(), i.stopPropagation(), this.showContextMenu(e, i);
|
|
92
|
+
}), this.handleContainer?.appendChild(n), this.updateHandlePosition(e), n;
|
|
87
93
|
}
|
|
88
94
|
/**
|
|
89
95
|
* Get icon for handle based on block type
|
|
@@ -102,13 +108,14 @@ class r {
|
|
|
102
108
|
}[e] || "○";
|
|
103
109
|
}
|
|
104
110
|
/**
|
|
105
|
-
* Update handle position based on block element position
|
|
111
|
+
* Update handle position based on block element position.
|
|
112
|
+
* Uses viewport-relative coordinates so scrolling is automatically accounted for.
|
|
106
113
|
*/
|
|
107
114
|
updateHandlePosition(e) {
|
|
108
115
|
const t = this.blocks.get(e);
|
|
109
116
|
if (!t || !t.handleElement) return;
|
|
110
|
-
const
|
|
111
|
-
t.handleElement.style.top = `${
|
|
117
|
+
const n = t.element.getBoundingClientRect(), i = this.preview.getBoundingClientRect(), s = n.top - i.top;
|
|
118
|
+
t.handleElement.style.top = `${s}px`;
|
|
112
119
|
}
|
|
113
120
|
/**
|
|
114
121
|
* Update all handle positions (call on scroll/resize)
|
|
@@ -119,16 +126,33 @@ class r {
|
|
|
119
126
|
});
|
|
120
127
|
}
|
|
121
128
|
/**
|
|
122
|
-
*
|
|
129
|
+
* Find the preview block element at a given viewport position.
|
|
130
|
+
* Extends the hit rect to the left by handleOffset + handleSize so the
|
|
131
|
+
* mouse can reach the handle without triggering a hide.
|
|
132
|
+
*/
|
|
133
|
+
findBlockAtPoint(e, t) {
|
|
134
|
+
const n = this.config.handleOffset + this.config.handleSize;
|
|
135
|
+
for (const i of this.blocks.values()) {
|
|
136
|
+
const s = i.element.getBoundingClientRect();
|
|
137
|
+
if (e >= s.left - n && e <= s.right && t >= s.top && t <= s.bottom)
|
|
138
|
+
return i.element;
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Handle mouse move for hover effects.
|
|
144
|
+
* Listens on both the textarea (normal mode) and the preview (preview mode).
|
|
123
145
|
*/
|
|
124
146
|
handleMouseMove(e) {
|
|
125
147
|
if (!this.config.showOnHover) return;
|
|
126
|
-
const t = e.
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
148
|
+
const t = document.elementFromPoint(e.clientX, e.clientY);
|
|
149
|
+
if (t && t.closest?.(".mz-block-handle")) return;
|
|
150
|
+
const n = this.findBlockAtPoint(e.clientX, e.clientY);
|
|
151
|
+
if (n) {
|
|
152
|
+
const i = n.getAttribute("data-block-id");
|
|
153
|
+
i && (this.showHandle(i), i !== this.selectedBlockId && this.highlightBlock(i, !1));
|
|
130
154
|
} else
|
|
131
|
-
this.hideAllHandles(), this.unhighlightAll();
|
|
155
|
+
this.hideAllHandles(), this.unhighlightAll(!0);
|
|
132
156
|
}
|
|
133
157
|
/**
|
|
134
158
|
* Handle mouse leave event
|
|
@@ -137,14 +161,20 @@ class r {
|
|
|
137
161
|
this.hideAllHandles(), this.unhighlightAll(!0);
|
|
138
162
|
}
|
|
139
163
|
/**
|
|
140
|
-
* Handle click events for block selection
|
|
164
|
+
* Handle click events for block selection.
|
|
165
|
+
* Clicks anywhere in the left handle-zone (the padding area left of block text)
|
|
166
|
+
* select the block — no shift key required. Shift+click anywhere on the block
|
|
167
|
+
* also selects it. Clicking in normal text area deselects.
|
|
141
168
|
*/
|
|
142
169
|
handleClick(e) {
|
|
143
|
-
const t = e.
|
|
144
|
-
if (
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
170
|
+
const t = this.findBlockAtPoint(e.clientX, e.clientY);
|
|
171
|
+
if (t) {
|
|
172
|
+
const n = t.getAttribute("data-block-id");
|
|
173
|
+
if (n) {
|
|
174
|
+
const i = t.getBoundingClientRect();
|
|
175
|
+
e.clientX < i.left || e.shiftKey ? (e.preventDefault(), this.selectBlock(n)) : this.selectedBlockId && this.deselectBlock();
|
|
176
|
+
}
|
|
177
|
+
} else e.target.closest?.(".mz-block-handle") || this.deselectBlock();
|
|
148
178
|
}
|
|
149
179
|
/**
|
|
150
180
|
* Handle keyboard shortcuts
|
|
@@ -152,35 +182,29 @@ class r {
|
|
|
152
182
|
handleKeyDown(e) {
|
|
153
183
|
this.selectedBlockId && ((e.ctrlKey || e.metaKey) && e.key === "c" && !this.editor.selectionStart && (e.preventDefault(), this.copyBlock(this.selectedBlockId)), (e.key === "Delete" || e.key === "Backspace") && !this.editor.selectionStart && (e.preventDefault(), this.deleteBlock(this.selectedBlockId)), e.key === "Escape" && this.deselectBlock());
|
|
154
184
|
}
|
|
155
|
-
/**
|
|
156
|
-
* Find the block element from any child element
|
|
157
|
-
*/
|
|
158
|
-
findBlockElement(e) {
|
|
159
|
-
return e ? e.hasAttribute("data-block-id") ? e : e.closest("[data-block-id]") : null;
|
|
160
|
-
}
|
|
161
185
|
/**
|
|
162
186
|
* Show a specific handle
|
|
163
187
|
*/
|
|
164
188
|
showHandle(e) {
|
|
165
189
|
const t = this.blocks.get(e);
|
|
166
|
-
t?.handleElement && (t.handleElement.style.opacity = "1");
|
|
190
|
+
t?.handleElement && (t.handleElement.style.opacity = "1", t.handleElement.style.pointerEvents = "auto");
|
|
167
191
|
}
|
|
168
192
|
/**
|
|
169
193
|
* Hide all handles except selected
|
|
170
194
|
*/
|
|
171
195
|
hideAllHandles() {
|
|
172
196
|
this.blocks.forEach((e) => {
|
|
173
|
-
e.handleElement && e.id !== this.selectedBlockId && (e.handleElement.style.opacity = "0");
|
|
197
|
+
e.handleElement && e.id !== this.selectedBlockId && (e.handleElement.style.opacity = "0", e.handleElement.style.pointerEvents = "none");
|
|
174
198
|
});
|
|
175
199
|
}
|
|
176
200
|
/**
|
|
177
201
|
* Highlight a block
|
|
178
202
|
*/
|
|
179
203
|
highlightBlock(e, t) {
|
|
180
|
-
const
|
|
181
|
-
if (!
|
|
182
|
-
const
|
|
183
|
-
|
|
204
|
+
const n = this.blocks.get(e);
|
|
205
|
+
if (!n) return;
|
|
206
|
+
const i = t ? this.config.colors.selected : this.config.colors.hover;
|
|
207
|
+
n.element.style.backgroundColor = i ?? "";
|
|
184
208
|
}
|
|
185
209
|
/**
|
|
186
210
|
* Remove highlight from all blocks
|
|
@@ -197,7 +221,7 @@ class r {
|
|
|
197
221
|
if (this.selectedBlockId) {
|
|
198
222
|
this.unhighlightAll();
|
|
199
223
|
const t = this.blocks.get(this.selectedBlockId);
|
|
200
|
-
t?.handleElement && (t.handleElement.style.opacity = "0");
|
|
224
|
+
t?.handleElement && (t.handleElement.style.opacity = "0", t.handleElement.style.pointerEvents = "none");
|
|
201
225
|
}
|
|
202
226
|
this.selectedBlockId = e, this.highlightBlock(e, !0), this.showHandle(e), this.preview.dispatchEvent(new CustomEvent("blockSelected", {
|
|
203
227
|
detail: { blockId: e, block: this.blocks.get(e) }
|
|
@@ -219,11 +243,11 @@ class r {
|
|
|
219
243
|
async copyBlock(e) {
|
|
220
244
|
const t = this.blocks.get(e);
|
|
221
245
|
if (!t) return;
|
|
222
|
-
const
|
|
246
|
+
const n = this.getBlockContent(t);
|
|
223
247
|
try {
|
|
224
|
-
await navigator.clipboard.writeText(
|
|
225
|
-
} catch (
|
|
226
|
-
console.error("Failed to copy block:",
|
|
248
|
+
await navigator.clipboard.writeText(n), this.showToast("Block copied to clipboard");
|
|
249
|
+
} catch (i) {
|
|
250
|
+
console.error("Failed to copy block:", i), this.showToast("Failed to copy block", "error");
|
|
227
251
|
}
|
|
228
252
|
}
|
|
229
253
|
/**
|
|
@@ -232,9 +256,9 @@ class r {
|
|
|
232
256
|
deleteBlock(e) {
|
|
233
257
|
const t = this.blocks.get(e);
|
|
234
258
|
if (!t) return;
|
|
235
|
-
const
|
|
259
|
+
const i = this.editor.value.split(`
|
|
236
260
|
`);
|
|
237
|
-
|
|
261
|
+
i.splice(t.lineStart, t.lineEnd - t.lineStart + 1), this.editor.value = i.join(`
|
|
238
262
|
`), this.editor.dispatchEvent(new Event("input", { bubbles: !0 })), this.deselectBlock(), this.showToast("Block deleted");
|
|
239
263
|
}
|
|
240
264
|
/**
|
|
@@ -249,10 +273,10 @@ class r {
|
|
|
249
273
|
* Show context menu for block actions
|
|
250
274
|
*/
|
|
251
275
|
showContextMenu(e, t) {
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
const
|
|
255
|
-
|
|
276
|
+
const n = document.querySelector(".mz-block-context-menu");
|
|
277
|
+
n && n.remove();
|
|
278
|
+
const i = document.createElement("div");
|
|
279
|
+
i.className = "mz-block-context-menu", i.style.cssText = `
|
|
256
280
|
position: fixed;
|
|
257
281
|
top: ${t.clientY}px;
|
|
258
282
|
left: ${t.clientX}px;
|
|
@@ -280,11 +304,11 @@ class r {
|
|
|
280
304
|
}), o.addEventListener("mouseleave", () => {
|
|
281
305
|
o.style.backgroundColor = "";
|
|
282
306
|
}), o.addEventListener("click", () => {
|
|
283
|
-
a(),
|
|
284
|
-
}),
|
|
285
|
-
}), document.body.appendChild(
|
|
307
|
+
a(), i.remove();
|
|
308
|
+
}), i.appendChild(o);
|
|
309
|
+
}), document.body.appendChild(i);
|
|
286
310
|
const c = (l) => {
|
|
287
|
-
|
|
311
|
+
i.contains(l.target) || (i.remove(), document.removeEventListener("click", c));
|
|
288
312
|
};
|
|
289
313
|
setTimeout(() => {
|
|
290
314
|
document.addEventListener("click", c);
|
|
@@ -294,8 +318,8 @@ class r {
|
|
|
294
318
|
* Show a toast notification
|
|
295
319
|
*/
|
|
296
320
|
showToast(e, t = "success") {
|
|
297
|
-
const
|
|
298
|
-
|
|
321
|
+
const n = document.createElement("div");
|
|
322
|
+
n.className = "mz-toast", n.textContent = e, n.style.cssText = `
|
|
299
323
|
position: fixed;
|
|
300
324
|
bottom: 20px;
|
|
301
325
|
right: 20px;
|
|
@@ -308,21 +332,21 @@ class r {
|
|
|
308
332
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
309
333
|
font-size: 14px;
|
|
310
334
|
animation: slideIn 0.3s ease;
|
|
311
|
-
`, document.body.appendChild(
|
|
312
|
-
|
|
335
|
+
`, document.body.appendChild(n), setTimeout(() => {
|
|
336
|
+
n.style.animation = "slideOut 0.3s ease", setTimeout(() => n.remove(), 300);
|
|
313
337
|
}, 2e3);
|
|
314
338
|
}
|
|
315
339
|
/**
|
|
316
340
|
* Enable the plugin
|
|
317
341
|
*/
|
|
318
342
|
enable() {
|
|
319
|
-
this.config.enabled = !0, this.initialize();
|
|
343
|
+
this.config.enabled || (this.config.enabled = !0, this.initialize());
|
|
320
344
|
}
|
|
321
345
|
/**
|
|
322
346
|
* Disable the plugin
|
|
323
347
|
*/
|
|
324
348
|
disable() {
|
|
325
|
-
this.config.enabled = !1, this.handleContainer?.remove(), this.handleContainer = null, this.blocks.clear(), this.selectedBlockId = null;
|
|
349
|
+
this.config.enabled = !1, this.handleContainer?.remove(), this.handleContainer = null, this.blocks.clear(), this.selectedBlockId = null, this.editor.removeEventListener("mousemove", this._boundMouseMove), this.editor.removeEventListener("mouseleave", this._boundMouseLeave), this.editor.removeEventListener("click", this._boundClick), this.preview.removeEventListener("mousemove", this._boundMouseMove), this.preview.removeEventListener("mouseleave", this._boundMouseLeave), this.preview.removeEventListener("click", this._boundClick), document.removeEventListener("keydown", this._boundKeyDown);
|
|
326
350
|
}
|
|
327
351
|
/**
|
|
328
352
|
* Refresh the plugin (rescan blocks and update positions)
|
|
@@ -346,7 +370,7 @@ class r {
|
|
|
346
370
|
* Clean up and remove the plugin
|
|
347
371
|
*/
|
|
348
372
|
destroy() {
|
|
349
|
-
this.disable()
|
|
373
|
+
this.disable();
|
|
350
374
|
}
|
|
351
375
|
}
|
|
352
376
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-handles.js","sources":["../../src/plugins/block-handles.ts"],"sourcesContent":["// @ts-nocheck\n/**\n * Block Handles Plugin\n * \n * Provides interactive handles on the left side of markdown blocks in the preview overlay.\n * Handles appear on hover and provide quick actions for block manipulation.\n * \n * Features:\n * - Hover to show handles\n * - Click to select blocks\n * - Copy block content\n * - Delete blocks\n * - Visual feedback for selected blocks\n */\n\nexport interface BlockHandle {\n id: string;\n type: string;\n lineStart: number;\n lineEnd: number;\n element: HTMLElement;\n handleElement: HTMLElement | null;\n}\n\nexport interface BlockHandlesConfig {\n enabled?: boolean;\n showOnHover?: boolean;\n handleOffset?: number;\n handleSize?: number;\n colors?: {\n hover?: string;\n selected?: string;\n handle?: string;\n };\n}\n\nexport class BlockHandlesPlugin {\n private editor: HTMLTextAreaElement;\n private preview: HTMLElement;\n private config: Required<BlockHandlesConfig>;\n private blocks: Map<string, BlockHandle>;\n private selectedBlockId: string | null;\n private handleContainer: HTMLElement | null;\n\n constructor(editor: HTMLTextAreaElement, preview: HTMLElement, config: BlockHandlesConfig = {}) {\n this.editor = editor;\n this.preview = preview;\n this.config = {\n enabled: config.enabled ?? true,\n showOnHover: config.showOnHover ?? true,\n handleOffset: config.handleOffset ?? -30,\n handleSize: config.handleSize ?? 20,\n colors: {\n hover: config.colors?.hover ?? 'rgba(59, 130, 246, 0.1)',\n selected: config.colors?.selected ?? 'rgba(59, 130, 246, 0.2)',\n handle: config.colors?.handle ?? 'rgba(59, 130, 246, 0.8)',\n },\n };\n this.blocks = new Map();\n this.selectedBlockId = null;\n this.handleContainer = null;\n\n this.initialize();\n }\n\n /**\n * Initialize the plugin\n */\n private initialize(): void {\n if (!this.config.enabled) return;\n\n // Create handle container\n this.createHandleContainer();\n\n // Set up event listeners\n this.setupEventListeners();\n\n // Initial scan for blocks\n this.scanBlocks();\n }\n\n /**\n * Create the container for block handles\n */\n private createHandleContainer(): void {\n this.handleContainer = document.createElement('div');\n this.handleContainer.className = 'mz-block-handles';\n this.handleContainer.style.cssText = `\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 10;\n `;\n this.preview.style.position = 'relative';\n this.preview.appendChild(this.handleContainer);\n }\n\n /**\n * Set up event listeners for block interactions\n */\n private setupEventListeners(): void {\n // Mouse move for hover effects\n this.preview.addEventListener('mousemove', this.handleMouseMove.bind(this));\n this.preview.addEventListener('mouseleave', this.handleMouseLeave.bind(this));\n\n // Click for selection\n this.preview.addEventListener('click', this.handleClick.bind(this));\n\n // Keyboard shortcuts\n document.addEventListener('keydown', this.handleKeyDown.bind(this));\n }\n\n /**\n * Scan the preview for blocks and create handles\n */\n public scanBlocks(): void {\n this.blocks.clear();\n \n if (!this.handleContainer) return;\n\n // Clear existing handles\n this.handleContainer.innerHTML = '';\n\n // Find all elements with block metadata\n const blockElements = this.preview.querySelectorAll('[data-block-id]');\n \n blockElements.forEach((element: HTMLElement) => {\n const blockId = element.getAttribute('data-block-id');\n const blockType = element.getAttribute('data-block-type');\n const lineStart = parseInt(element.getAttribute('data-line-start') || '0', 10);\n const lineEnd = parseInt(element.getAttribute('data-line-end') || '0', 10);\n\n if (!blockId) return;\n\n // Create handle for this block\n const handle = this.createHandle(blockId, blockType || 'paragraph', element);\n\n this.blocks.set(blockId, {\n id: blockId,\n type: blockType || 'paragraph',\n lineStart,\n lineEnd,\n element,\n handleElement: handle,\n });\n });\n }\n\n /**\n * Create a handle element for a block\n */\n private createHandle(blockId: string, blockType: string, blockElement: HTMLElement): HTMLElement {\n const handle = document.createElement('div');\n handle.className = `mz-block-handle mz-block-handle-${blockType}`;\n handle.setAttribute('data-block-id', blockId);\n handle.style.cssText = `\n position: absolute;\n width: ${this.config.handleSize}px;\n height: ${this.config.handleSize}px;\n left: ${this.config.handleOffset}px;\n background: ${this.config.colors.handle};\n border-radius: 4px;\n cursor: pointer;\n opacity: 0;\n transition: opacity 0.2s ease;\n pointer-events: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-size: 12px;\n user-select: none;\n `;\n\n // Add icon based on block type\n handle.innerHTML = this.getHandleIcon(blockType);\n\n // Handle click events\n handle.addEventListener('click', (e) => {\n e.stopPropagation();\n this.selectBlock(blockId);\n });\n\n // Show context menu on right click\n handle.addEventListener('contextmenu', (e) => {\n e.preventDefault();\n e.stopPropagation();\n this.showContextMenu(blockId, e);\n });\n\n this.handleContainer?.appendChild(handle);\n this.updateHandlePosition(blockId);\n\n return handle;\n }\n\n /**\n * Get icon for handle based on block type\n */\n private getHandleIcon(blockType: string): string {\n const icons: Record<string, string> = {\n heading: '⚡',\n paragraph: '¶',\n 'list-item': '•',\n quote: '\"',\n 'code-fence': '{',\n 'code-content': '{}',\n hr: '―',\n 'table-row': '⊞',\n 'table-separator': '═',\n };\n return icons[blockType] || '○';\n }\n\n /**\n * Update handle position based on block element position\n */\n private updateHandlePosition(blockId: string): void {\n const block = this.blocks.get(blockId);\n if (!block || !block.handleElement) return;\n\n const blockRect = block.element.getBoundingClientRect();\n const previewRect = this.preview.getBoundingClientRect();\n\n const top = blockRect.top - previewRect.top + this.preview.scrollTop;\n \n block.handleElement.style.top = `${top}px`;\n }\n\n /**\n * Update all handle positions (call on scroll/resize)\n */\n public updateAllHandlePositions(): void {\n this.blocks.forEach((block, blockId) => {\n this.updateHandlePosition(blockId);\n });\n }\n\n /**\n * Handle mouse move for hover effects\n */\n private handleMouseMove(e: MouseEvent): void {\n if (!this.config.showOnHover) return;\n\n const target = e.target as HTMLElement;\n const blockElement = this.findBlockElement(target);\n\n if (blockElement) {\n const blockId = blockElement.getAttribute('data-block-id');\n if (blockId) {\n this.showHandle(blockId);\n this.highlightBlock(blockId, false);\n }\n } else {\n this.hideAllHandles();\n this.unhighlightAll();\n }\n }\n\n /**\n * Handle mouse leave event\n */\n private handleMouseLeave(): void {\n this.hideAllHandles();\n this.unhighlightAll(true);\n }\n\n /**\n * Handle click events for block selection\n */\n private handleClick(e: MouseEvent): void {\n const target = e.target as HTMLElement;\n const blockElement = this.findBlockElement(target);\n\n if (blockElement) {\n const blockId = blockElement.getAttribute('data-block-id');\n if (blockId && e.shiftKey) {\n e.preventDefault();\n this.selectBlock(blockId);\n }\n } else if (!target.closest('.mz-block-handle')) {\n // Click outside blocks and handles - deselect\n this.deselectBlock();\n }\n }\n\n /**\n * Handle keyboard shortcuts\n */\n private handleKeyDown(e: KeyboardEvent): void {\n if (!this.selectedBlockId) return;\n\n // Copy block (Ctrl/Cmd + C when block is selected)\n if ((e.ctrlKey || e.metaKey) && e.key === 'c' && !this.editor.selectionStart) {\n e.preventDefault();\n this.copyBlock(this.selectedBlockId);\n }\n\n // Delete block (Delete or Backspace when block is selected)\n if ((e.key === 'Delete' || e.key === 'Backspace') && !this.editor.selectionStart) {\n e.preventDefault();\n this.deleteBlock(this.selectedBlockId);\n }\n\n // Escape to deselect\n if (e.key === 'Escape') {\n this.deselectBlock();\n }\n }\n\n /**\n * Find the block element from any child element\n */\n private findBlockElement(element: HTMLElement | null): HTMLElement | null {\n if (!element) return null;\n \n // Check if element itself is a block\n if (element.hasAttribute('data-block-id')) {\n return element;\n }\n\n // Look up the tree for a block element\n return element.closest('[data-block-id]') as HTMLElement | null;\n }\n\n /**\n * Show a specific handle\n */\n private showHandle(blockId: string): void {\n const block = this.blocks.get(blockId);\n if (block?.handleElement) {\n block.handleElement.style.opacity = '1';\n }\n }\n\n /**\n * Hide all handles except selected\n */\n private hideAllHandles(): void {\n this.blocks.forEach((block) => {\n if (block.handleElement && block.id !== this.selectedBlockId) {\n block.handleElement.style.opacity = '0';\n }\n });\n }\n\n /**\n * Highlight a block\n */\n private highlightBlock(blockId: string, selected: boolean): void {\n const block = this.blocks.get(blockId);\n if (!block) return;\n\n const color = selected ? this.config.colors.selected : this.config.colors.hover;\n block.element.style.backgroundColor = color;\n }\n\n /**\n * Remove highlight from all blocks\n */\n private unhighlightAll(keepSelected: boolean = false): void {\n this.blocks.forEach((block) => {\n if (!keepSelected || block.id !== this.selectedBlockId) {\n block.element.style.backgroundColor = '';\n }\n });\n }\n\n /**\n * Select a block\n */\n private selectBlock(blockId: string): void {\n // Deselect previous block\n if (this.selectedBlockId) {\n this.unhighlightAll();\n const prevBlock = this.blocks.get(this.selectedBlockId);\n if (prevBlock?.handleElement) {\n prevBlock.handleElement.style.opacity = '0';\n }\n }\n\n // Select new block\n this.selectedBlockId = blockId;\n this.highlightBlock(blockId, true);\n this.showHandle(blockId);\n\n // Dispatch selection event\n this.preview.dispatchEvent(new CustomEvent('blockSelected', {\n detail: { blockId, block: this.blocks.get(blockId) },\n }));\n }\n\n /**\n * Deselect current block\n */\n private deselectBlock(): void {\n if (!this.selectedBlockId) return;\n\n const blockId = this.selectedBlockId;\n this.selectedBlockId = null;\n this.unhighlightAll();\n this.hideAllHandles();\n\n // Dispatch deselection event\n this.preview.dispatchEvent(new CustomEvent('blockDeselected', {\n detail: { blockId },\n }));\n }\n\n /**\n * Copy block content to clipboard\n */\n private async copyBlock(blockId: string): Promise<void> {\n const block = this.blocks.get(blockId);\n if (!block) return;\n\n const content = this.getBlockContent(block);\n \n try {\n await navigator.clipboard.writeText(content);\n this.showToast('Block copied to clipboard');\n } catch (err) {\n console.error('Failed to copy block:', err);\n this.showToast('Failed to copy block', 'error');\n }\n }\n\n /**\n * Delete a block from the editor\n */\n private deleteBlock(blockId: string): void {\n const block = this.blocks.get(blockId);\n if (!block) return;\n\n const content = this.editor.value;\n const lines = content.split('\\n');\n\n // Remove lines for this block\n lines.splice(block.lineStart, block.lineEnd - block.lineStart + 1);\n\n // Update editor\n this.editor.value = lines.join('\\n');\n \n // Trigger input event to update preview\n this.editor.dispatchEvent(new Event('input', { bubbles: true }));\n\n // Deselect and rescan\n this.deselectBlock();\n this.showToast('Block deleted');\n }\n\n /**\n * Get the text content of a block from the editor\n */\n private getBlockContent(block: BlockHandle): string {\n const content = this.editor.value;\n const lines = content.split('\\n');\n \n return lines\n .slice(block.lineStart, block.lineEnd + 1)\n .join('\\n');\n }\n\n /**\n * Show context menu for block actions\n */\n private showContextMenu(blockId: string, e: MouseEvent): void {\n // Remove existing context menu if any\n const existingMenu = document.querySelector('.mz-block-context-menu');\n if (existingMenu) {\n existingMenu.remove();\n }\n\n const menu = document.createElement('div');\n menu.className = 'mz-block-context-menu';\n menu.style.cssText = `\n position: fixed;\n top: ${e.clientY}px;\n left: ${e.clientX}px;\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n z-index: 1000;\n min-width: 150px;\n padding: 4px 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n `;\n\n const actions = [\n { label: 'Copy', action: () => this.copyBlock(blockId), icon: '📋' },\n { label: 'Delete', action: () => this.deleteBlock(blockId), icon: '🗑️' },\n { label: 'Select', action: () => this.selectBlock(blockId), icon: '✓' },\n ];\n\n actions.forEach(({ label, action, icon }) => {\n const item = document.createElement('div');\n item.className = 'mz-context-menu-item';\n item.textContent = `${icon} ${label}`;\n item.style.cssText = `\n padding: 8px 16px;\n cursor: pointer;\n user-select: none;\n `;\n\n item.addEventListener('mouseenter', () => {\n item.style.backgroundColor = '#f5f5f5';\n });\n\n item.addEventListener('mouseleave', () => {\n item.style.backgroundColor = '';\n });\n\n item.addEventListener('click', () => {\n action();\n menu.remove();\n });\n\n menu.appendChild(item);\n });\n\n document.body.appendChild(menu);\n\n // Close menu on click outside\n const closeMenu = (e: MouseEvent) => {\n if (!menu.contains(e.target as Node)) {\n menu.remove();\n document.removeEventListener('click', closeMenu);\n }\n };\n\n setTimeout(() => {\n document.addEventListener('click', closeMenu);\n }, 0);\n }\n\n /**\n * Show a toast notification\n */\n private showToast(message: string, type: 'success' | 'error' = 'success'): void {\n const toast = document.createElement('div');\n toast.className = 'mz-toast';\n toast.textContent = message;\n toast.style.cssText = `\n position: fixed;\n bottom: 20px;\n right: 20px;\n background: ${type === 'success' ? '#10b981' : '#ef4444'};\n color: white;\n padding: 12px 20px;\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n z-index: 1000;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n animation: slideIn 0.3s ease;\n `;\n\n document.body.appendChild(toast);\n\n setTimeout(() => {\n toast.style.animation = 'slideOut 0.3s ease';\n setTimeout(() => toast.remove(), 300);\n }, 2000);\n }\n\n /**\n * Enable the plugin\n */\n public enable(): void {\n this.config.enabled = true;\n this.initialize();\n }\n\n /**\n * Disable the plugin\n */\n public disable(): void {\n this.config.enabled = false;\n this.handleContainer?.remove();\n this.handleContainer = null;\n this.blocks.clear();\n this.selectedBlockId = null;\n }\n\n /**\n * Refresh the plugin (rescan blocks and update positions)\n */\n public refresh(): void {\n this.scanBlocks();\n }\n\n /**\n * Get the currently selected block\n */\n public getSelectedBlock(): BlockHandle | null {\n return this.selectedBlockId ? this.blocks.get(this.selectedBlockId) || null : null;\n }\n\n /**\n * Get all blocks\n */\n public getAllBlocks(): BlockHandle[] {\n return Array.from(this.blocks.values());\n }\n\n /**\n * Clean up and remove the plugin\n */\n public destroy(): void {\n this.disable();\n this.preview.removeEventListener('mousemove', this.handleMouseMove.bind(this));\n this.preview.removeEventListener('mouseleave', this.handleMouseLeave.bind(this));\n this.preview.removeEventListener('click', this.handleClick.bind(this));\n document.removeEventListener('keydown', this.handleKeyDown.bind(this));\n }\n}\n"],"names":["BlockHandlesPlugin","editor","preview","config","element","blockId","blockType","lineStart","lineEnd","handle","blockElement","e","block","blockRect","previewRect","top","target","selected","color","keepSelected","prevBlock","content","err","lines","existingMenu","menu","label","action","icon","item","closeMenu","message","type","toast"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"block-handles.js","sources":["../../src/plugins/block-handles.ts"],"sourcesContent":["/**\n * Block Handles Plugin\n * \n * Provides interactive handles on the left side of markdown blocks in the preview overlay.\n * Handles appear on hover and provide quick actions for block manipulation.\n * \n * Features:\n * - Hover to show handles\n * - Click to select blocks\n * - Copy block content\n * - Delete blocks\n * - Visual feedback for selected blocks\n */\n\nexport interface BlockHandle {\n id: string;\n type: string;\n lineStart: number;\n lineEnd: number;\n element: HTMLElement;\n handleElement: HTMLElement | null;\n}\n\nexport interface BlockHandlesConfig {\n enabled?: boolean;\n showOnHover?: boolean;\n handleOffset?: number;\n handleSize?: number;\n colors?: {\n hover?: string;\n selected?: string;\n handle?: string;\n };\n}\n\nexport class BlockHandlesPlugin {\n private editor: HTMLTextAreaElement;\n private preview: HTMLElement;\n private config: Required<BlockHandlesConfig>;\n private blocks: Map<string, BlockHandle>;\n private selectedBlockId: string | null;\n private handleContainer: HTMLElement | null;\n\n // Stored bound handlers for proper cleanup\n private _boundMouseMove: (e: MouseEvent) => void;\n private _boundMouseLeave: () => void;\n private _boundClick: (e: MouseEvent) => void;\n private _boundKeyDown: (e: KeyboardEvent) => void;\n\n constructor(editor: HTMLTextAreaElement, preview: HTMLElement, config: BlockHandlesConfig = {}) {\n this.editor = editor;\n this.preview = preview;\n this.config = {\n enabled: config.enabled ?? true,\n showOnHover: config.showOnHover ?? true,\n handleOffset: config.handleOffset ?? 4,\n handleSize: config.handleSize ?? 20,\n colors: {\n hover: config.colors?.hover ?? 'rgba(59, 130, 246, 0.1)',\n selected: config.colors?.selected ?? 'rgba(59, 130, 246, 0.2)',\n handle: config.colors?.handle ?? 'rgba(59, 130, 246, 0.8)',\n },\n };\n this.blocks = new Map();\n this.selectedBlockId = null;\n this.handleContainer = null;\n\n // Bind handlers once for consistent add/remove\n this._boundMouseMove = this.handleMouseMove.bind(this);\n this._boundMouseLeave = this.handleMouseLeave.bind(this);\n this._boundClick = this.handleClick.bind(this);\n this._boundKeyDown = this.handleKeyDown.bind(this);\n\n this.initialize();\n }\n\n /**\n * Initialize the plugin\n */\n private initialize(): void {\n if (!this.config.enabled) return;\n\n // Create handle container\n this.createHandleContainer();\n\n // Set up event listeners\n this.setupEventListeners();\n\n // Initial scan for blocks\n this.scanBlocks();\n }\n\n /**\n * Create the container for block handles.\n * Appended to the wrapper (parent of preview) so it sits above the textarea\n * and is not subject to the preview's pointer-events: none rule.\n */\n private createHandleContainer(): void {\n this.handleContainer = document.createElement('div');\n this.handleContainer.className = 'mz-block-handles';\n this.handleContainer.style.cssText = `\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 2;\n `;\n // Attach to the wrapper (preview's parent), not the preview itself.\n // The preview has pointer-events: none which would prevent any interaction.\n const wrapper = this.preview.parentElement;\n if (wrapper) {\n wrapper.appendChild(this.handleContainer);\n }\n }\n\n /**\n * Set up event listeners for block interactions.\n * We listen on both the textarea (normal mode) and the preview (preview mode),\n * since in preview mode the textarea is display:none and the preview has pointer-events:auto.\n */\n private setupEventListeners(): void {\n // Normal overlay mode: textarea receives pointer events\n this.editor.addEventListener('mousemove', this._boundMouseMove);\n this.editor.addEventListener('mouseleave', this._boundMouseLeave);\n this.editor.addEventListener('click', this._boundClick);\n\n // Preview mode: preview has pointer-events:auto, textarea is display:none\n this.preview.addEventListener('mousemove', this._boundMouseMove);\n this.preview.addEventListener('mouseleave', this._boundMouseLeave);\n this.preview.addEventListener('click', this._boundClick);\n\n // Keyboard shortcuts\n document.addEventListener('keydown', this._boundKeyDown);\n }\n\n /**\n * Scan the preview for blocks and create handles\n */\n public scanBlocks(): void {\n this.blocks.clear();\n \n if (!this.handleContainer) return;\n\n // Clear existing handles\n this.handleContainer.innerHTML = '';\n\n // Find all elements with block metadata\n const blockElements = this.preview.querySelectorAll('[data-block-id]');\n \n blockElements.forEach((element) => {\n const el = element as HTMLElement;\n const blockId = el.getAttribute('data-block-id');\n const blockType = el.getAttribute('data-block-type');\n const lineStart = parseInt(el.getAttribute('data-line-start') || '0', 10);\n const lineEnd = parseInt(el.getAttribute('data-line-end') || '0', 10);\n\n if (!blockId) return;\n\n // Create handle for this block\n const handle = this.createHandle(blockId, blockType || 'paragraph');\n\n this.blocks.set(blockId, {\n id: blockId,\n type: blockType || 'paragraph',\n lineStart,\n lineEnd,\n element: el,\n handleElement: handle,\n });\n });\n }\n\n /**\n * Create a handle element for a block\n */\n private createHandle(blockId: string, blockType: string): HTMLElement {\n const handle = document.createElement('div');\n handle.className = `mz-block-handle mz-block-handle-${blockType}`;\n handle.setAttribute('data-block-id', blockId);\n handle.style.cssText = `\n position: absolute;\n width: ${this.config.handleSize}px;\n height: ${this.config.handleSize}px;\n left: ${this.config.handleOffset}px;\n background: ${this.config.colors.handle};\n border-radius: 4px;\n cursor: pointer;\n opacity: 0;\n transition: opacity 0.2s ease;\n pointer-events: none;\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-size: 12px;\n user-select: none;\n `;\n\n // Add icon based on block type\n handle.innerHTML = this.getHandleIcon(blockType);\n\n // Handle click events\n handle.addEventListener('click', (e) => {\n e.stopPropagation();\n this.selectBlock(blockId);\n });\n\n // Show context menu on right click\n handle.addEventListener('contextmenu', (e) => {\n e.preventDefault();\n e.stopPropagation();\n this.showContextMenu(blockId, e);\n });\n\n this.handleContainer?.appendChild(handle);\n this.updateHandlePosition(blockId);\n\n return handle;\n }\n\n /**\n * Get icon for handle based on block type\n */\n private getHandleIcon(blockType: string): string {\n const icons: Record<string, string> = {\n heading: '⚡',\n paragraph: '¶',\n 'list-item': '•',\n quote: '\"',\n 'code-fence': '{',\n 'code-content': '{}',\n hr: '―',\n 'table-row': '⊞',\n 'table-separator': '═',\n };\n return icons[blockType] || '○';\n }\n\n /**\n * Update handle position based on block element position.\n * Uses viewport-relative coordinates so scrolling is automatically accounted for.\n */\n private updateHandlePosition(blockId: string): void {\n const block = this.blocks.get(blockId);\n if (!block || !block.handleElement) return;\n\n const blockRect = block.element.getBoundingClientRect();\n const previewRect = this.preview.getBoundingClientRect();\n\n // blockRect.top and previewRect.top are both viewport-relative,\n // so their difference gives the offset within the visible preview area.\n const top = blockRect.top - previewRect.top;\n\n block.handleElement.style.top = `${top}px`;\n }\n\n /**\n * Update all handle positions (call on scroll/resize)\n */\n public updateAllHandlePositions(): void {\n this.blocks.forEach((_block, blockId) => {\n this.updateHandlePosition(blockId);\n });\n }\n\n /**\n * Find the preview block element at a given viewport position.\n * Extends the hit rect to the left by handleOffset + handleSize so the\n * mouse can reach the handle without triggering a hide.\n */\n private findBlockAtPoint(clientX: number, clientY: number): HTMLElement | null {\n const handleReach = this.config.handleOffset + this.config.handleSize;\n for (const block of this.blocks.values()) {\n const rect = block.element.getBoundingClientRect();\n if (clientX >= rect.left - handleReach && clientX <= rect.right &&\n clientY >= rect.top && clientY <= rect.bottom) {\n return block.element;\n }\n }\n return null;\n }\n\n /**\n * Handle mouse move for hover effects.\n * Listens on both the textarea (normal mode) and the preview (preview mode).\n */\n private handleMouseMove(e: MouseEvent): void {\n if (!this.config.showOnHover) return;\n\n // If the element actually under the cursor is a handle, keep it visible\n const elementUnder = document.elementFromPoint(e.clientX, e.clientY);\n if (elementUnder && (elementUnder as HTMLElement).closest?.('.mz-block-handle')) return;\n\n const blockElement = this.findBlockAtPoint(e.clientX, e.clientY);\n\n if (blockElement) {\n const blockId = blockElement.getAttribute('data-block-id');\n if (blockId) {\n this.showHandle(blockId);\n // Don't replace selected-color with hover-color on the selected block\n if (blockId !== this.selectedBlockId) {\n this.highlightBlock(blockId, false);\n }\n }\n } else {\n this.hideAllHandles();\n this.unhighlightAll(true); // keep selected block highlighted\n }\n }\n\n /**\n * Handle mouse leave event\n */\n private handleMouseLeave(): void {\n this.hideAllHandles();\n this.unhighlightAll(true);\n }\n\n /**\n * Handle click events for block selection.\n * Clicks anywhere in the left handle-zone (the padding area left of block text)\n * select the block — no shift key required. Shift+click anywhere on the block\n * also selects it. Clicking in normal text area deselects.\n */\n private handleClick(e: MouseEvent): void {\n const blockElement = this.findBlockAtPoint(e.clientX, e.clientY);\n\n if (blockElement) {\n const blockId = blockElement.getAttribute('data-block-id');\n if (blockId) {\n const blockRect = blockElement.getBoundingClientRect();\n // A click in the handle zone (left of where text starts) or shift+click selects\n const inHandleZone = e.clientX < blockRect.left;\n if (inHandleZone || e.shiftKey) {\n e.preventDefault();\n this.selectBlock(blockId);\n } else {\n // Normal click inside block text — deselect if something was selected\n if (this.selectedBlockId) this.deselectBlock();\n }\n }\n } else if (!(e.target as HTMLElement).closest?.('.mz-block-handle')) {\n // Click outside all blocks — deselect\n this.deselectBlock();\n }\n }\n\n /**\n * Handle keyboard shortcuts\n */\n private handleKeyDown(e: KeyboardEvent): void {\n if (!this.selectedBlockId) return;\n\n // Copy block (Ctrl/Cmd + C when block is selected)\n if ((e.ctrlKey || e.metaKey) && e.key === 'c' && !this.editor.selectionStart) {\n e.preventDefault();\n this.copyBlock(this.selectedBlockId);\n }\n\n // Delete block (Delete or Backspace when block is selected)\n if ((e.key === 'Delete' || e.key === 'Backspace') && !this.editor.selectionStart) {\n e.preventDefault();\n this.deleteBlock(this.selectedBlockId);\n }\n\n // Escape to deselect\n if (e.key === 'Escape') {\n this.deselectBlock();\n }\n }\n\n /**\n * Show a specific handle\n */\n private showHandle(blockId: string): void {\n const block = this.blocks.get(blockId);\n if (block?.handleElement) {\n block.handleElement.style.opacity = '1';\n block.handleElement.style.pointerEvents = 'auto';\n }\n }\n\n /**\n * Hide all handles except selected\n */\n private hideAllHandles(): void {\n this.blocks.forEach((block) => {\n if (block.handleElement && block.id !== this.selectedBlockId) {\n block.handleElement.style.opacity = '0';\n block.handleElement.style.pointerEvents = 'none';\n }\n });\n }\n\n /**\n * Highlight a block\n */\n private highlightBlock(blockId: string, selected: boolean): void {\n const block = this.blocks.get(blockId);\n if (!block) return;\n\n const color = selected ? this.config.colors.selected : this.config.colors.hover;\n block.element.style.backgroundColor = color ?? '';\n }\n\n /**\n * Remove highlight from all blocks\n */\n private unhighlightAll(keepSelected: boolean = false): void {\n this.blocks.forEach((block) => {\n if (!keepSelected || block.id !== this.selectedBlockId) {\n block.element.style.backgroundColor = '';\n }\n });\n }\n\n /**\n * Select a block\n */\n private selectBlock(blockId: string): void {\n // Deselect previous block\n if (this.selectedBlockId) {\n this.unhighlightAll();\n const prevBlock = this.blocks.get(this.selectedBlockId);\n if (prevBlock?.handleElement) {\n prevBlock.handleElement.style.opacity = '0';\n prevBlock.handleElement.style.pointerEvents = 'none';\n }\n }\n\n // Select new block\n this.selectedBlockId = blockId;\n this.highlightBlock(blockId, true);\n this.showHandle(blockId);\n\n // Dispatch selection event\n this.preview.dispatchEvent(new CustomEvent('blockSelected', {\n detail: { blockId, block: this.blocks.get(blockId) },\n }));\n }\n\n /**\n * Deselect current block\n */\n private deselectBlock(): void {\n if (!this.selectedBlockId) return;\n\n const blockId = this.selectedBlockId;\n this.selectedBlockId = null;\n this.unhighlightAll();\n this.hideAllHandles();\n\n // Dispatch deselection event\n this.preview.dispatchEvent(new CustomEvent('blockDeselected', {\n detail: { blockId },\n }));\n }\n\n /**\n * Copy block content to clipboard\n */\n private async copyBlock(blockId: string): Promise<void> {\n const block = this.blocks.get(blockId);\n if (!block) return;\n\n const content = this.getBlockContent(block);\n \n try {\n await navigator.clipboard.writeText(content);\n this.showToast('Block copied to clipboard');\n } catch (err) {\n console.error('Failed to copy block:', err);\n this.showToast('Failed to copy block', 'error');\n }\n }\n\n /**\n * Delete a block from the editor\n */\n private deleteBlock(blockId: string): void {\n const block = this.blocks.get(blockId);\n if (!block) return;\n\n const content = this.editor.value;\n const lines = content.split('\\n');\n\n // Remove lines for this block\n lines.splice(block.lineStart, block.lineEnd - block.lineStart + 1);\n\n // Update editor\n this.editor.value = lines.join('\\n');\n \n // Trigger input event to update preview\n this.editor.dispatchEvent(new Event('input', { bubbles: true }));\n\n // Deselect and rescan\n this.deselectBlock();\n this.showToast('Block deleted');\n }\n\n /**\n * Get the text content of a block from the editor\n */\n private getBlockContent(block: BlockHandle): string {\n const content = this.editor.value;\n const lines = content.split('\\n');\n \n return lines\n .slice(block.lineStart, block.lineEnd + 1)\n .join('\\n');\n }\n\n /**\n * Show context menu for block actions\n */\n private showContextMenu(blockId: string, e: MouseEvent): void {\n // Remove existing context menu if any\n const existingMenu = document.querySelector('.mz-block-context-menu');\n if (existingMenu) {\n existingMenu.remove();\n }\n\n const menu = document.createElement('div');\n menu.className = 'mz-block-context-menu';\n menu.style.cssText = `\n position: fixed;\n top: ${e.clientY}px;\n left: ${e.clientX}px;\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n z-index: 1000;\n min-width: 150px;\n padding: 4px 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n `;\n\n const actions = [\n { label: 'Copy', action: () => this.copyBlock(blockId), icon: '📋' },\n { label: 'Delete', action: () => this.deleteBlock(blockId), icon: '🗑️' },\n { label: 'Select', action: () => this.selectBlock(blockId), icon: '✓' },\n ];\n\n actions.forEach(({ label, action, icon }) => {\n const item = document.createElement('div');\n item.className = 'mz-context-menu-item';\n item.textContent = `${icon} ${label}`;\n item.style.cssText = `\n padding: 8px 16px;\n cursor: pointer;\n user-select: none;\n `;\n\n item.addEventListener('mouseenter', () => {\n item.style.backgroundColor = '#f5f5f5';\n });\n\n item.addEventListener('mouseleave', () => {\n item.style.backgroundColor = '';\n });\n\n item.addEventListener('click', () => {\n action();\n menu.remove();\n });\n\n menu.appendChild(item);\n });\n\n document.body.appendChild(menu);\n\n // Close menu on click outside\n const closeMenu = (e: MouseEvent) => {\n if (!menu.contains(e.target as Node)) {\n menu.remove();\n document.removeEventListener('click', closeMenu);\n }\n };\n\n setTimeout(() => {\n document.addEventListener('click', closeMenu);\n }, 0);\n }\n\n /**\n * Show a toast notification\n */\n private showToast(message: string, type: 'success' | 'error' = 'success'): void {\n const toast = document.createElement('div');\n toast.className = 'mz-toast';\n toast.textContent = message;\n toast.style.cssText = `\n position: fixed;\n bottom: 20px;\n right: 20px;\n background: ${type === 'success' ? '#10b981' : '#ef4444'};\n color: white;\n padding: 12px 20px;\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n z-index: 1000;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n animation: slideIn 0.3s ease;\n `;\n\n document.body.appendChild(toast);\n\n setTimeout(() => {\n toast.style.animation = 'slideOut 0.3s ease';\n setTimeout(() => toast.remove(), 300);\n }, 2000);\n }\n\n /**\n * Enable the plugin\n */\n public enable(): void {\n if (this.config.enabled) return; // Already enabled\n this.config.enabled = true;\n this.initialize();\n }\n\n /**\n * Disable the plugin\n */\n public disable(): void {\n this.config.enabled = false;\n this.handleContainer?.remove();\n this.handleContainer = null;\n this.blocks.clear();\n this.selectedBlockId = null;\n // Remove event listeners from both textarea and preview\n this.editor.removeEventListener('mousemove', this._boundMouseMove);\n this.editor.removeEventListener('mouseleave', this._boundMouseLeave);\n this.editor.removeEventListener('click', this._boundClick);\n this.preview.removeEventListener('mousemove', this._boundMouseMove);\n this.preview.removeEventListener('mouseleave', this._boundMouseLeave);\n this.preview.removeEventListener('click', this._boundClick);\n document.removeEventListener('keydown', this._boundKeyDown);\n }\n\n /**\n * Refresh the plugin (rescan blocks and update positions)\n */\n public refresh(): void {\n this.scanBlocks();\n }\n\n /**\n * Get the currently selected block\n */\n public getSelectedBlock(): BlockHandle | null {\n return this.selectedBlockId ? this.blocks.get(this.selectedBlockId) || null : null;\n }\n\n /**\n * Get all blocks\n */\n public getAllBlocks(): BlockHandle[] {\n return Array.from(this.blocks.values());\n }\n\n /**\n * Clean up and remove the plugin\n */\n public destroy(): void {\n this.disable();\n }\n}\n"],"names":["BlockHandlesPlugin","editor","preview","config","wrapper","element","el","blockId","blockType","lineStart","lineEnd","handle","e","block","blockRect","previewRect","top","_block","clientX","clientY","handleReach","rect","elementUnder","blockElement","selected","color","keepSelected","prevBlock","content","err","lines","existingMenu","menu","label","action","icon","item","closeMenu","message","type","toast"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imageManagerPlugin.js","sources":["../../src/plugins/imageManagerPlugin.ts"],"sourcesContent":["// plugins/imageManagerPlugin.ts` — recents, upload, URL add, drag-drop, paste\n// =====================================================\n// Persists “recents” in `localStorage` (data-URLs for small files ≤ default 1 MB).\n// Optional `uploader(file) => Promise<string>` to store remotely and return a URL.\n// Drag files onto the editor, or paste images from clipboard—instant preview and insert.\n// Tiny panel with thumbnails; click to insert; remove/clear as needed.\n\ntype MzEditor = {\n container: HTMLElement;\n textarea: HTMLTextAreaElement;\n updatePreview: () => void;\n};\n\ntype RecentImage = { url: string; name: string; createdAt: number; persistent: boolean };\n\nconst LS_KEY = 'marzipan.images';\n\nfunction insertAtCursor(editor: MzEditor, text: string) {\n const ta = editor.textarea;\n const s = ta.selectionStart ?? 0, e = ta.selectionEnd ?? 0;\n ta.setRangeText(text, s, e, 'end');\n editor.updatePreview();\n ta.focus();\n}\n\nfunction loadRecents(): RecentImage[] {\n try { return JSON.parse(localStorage.getItem(LS_KEY) || '[]'); }\n catch { return []; }\n}\nfunction saveRecents(list: RecentImage[]) {\n try { localStorage.setItem(LS_KEY, JSON.stringify(list.slice(0, 50))); } catch {}\n}\n\nasync function fileToDataURL(file: File): Promise<string> {\n const fr = new FileReader();\n return new Promise((res, rej) => {\n fr.onerror = () => rej(fr.error);\n fr.onload = () => res(String(fr.result));\n fr.readAsDataURL(file);\n });\n}\n\nexport function imageManagerPlugin(opts?: {\n label?: string; // toolbar label\n title?: string; // tooltip\n maxRecent?: number; // default 24\n persistThresholdBytes?: number; // default 1 MiB\n uploader?: (file: File) => Promise<string>; // optional remote upload\n onInsert?: (url: string) => string; // transform URL before insert\n}) {\n const label = opts?.label ?? '🗂️';\n const title = opts?.title ?? 'Images';\n const maxRecent = Math.max(1, opts?.maxRecent ?? 24);\n const threshold = opts?.persistThresholdBytes ?? (1 * 1024 * 1024);\n\n return (editor: MzEditor) => {\n const bar = editor.container.querySelector('.marzipan-toolbar') as HTMLElement ?? editor.container;\n\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'mz-btn mz-btn-imagemgr';\n btn.title = title;\n btn.textContent = label;\n\n let panel: HTMLElement | null = null;\n let recents: RecentImage[] = loadRecents();\n\n function closePanel() {\n panel?.remove(); panel = null;\n document.removeEventListener('click', outsideClose, true);\n window.removeEventListener('resize', closePanel);\n window.removeEventListener('scroll', closePanel, true);\n }\n function outsideClose(e: MouseEvent) {\n if (!panel) return;\n if (e.target instanceof Node && (panel.contains(e.target) || btn.contains(e.target))) return;\n closePanel();\n }\n\n function renderGrid(root: HTMLElement) {\n const grid = root.querySelector('.mz-im-grid') as HTMLElement;\n grid.innerHTML = '';\n recents.slice(0, maxRecent).forEach((img, idx) => {\n const card = document.createElement('div');\n card.className = 'mz-im-card';\n\n const image = document.createElement('img');\n image.decoding = 'async';\n image.loading = 'lazy';\n image.src = img.url;\n image.alt = img.name;\n\n const row = document.createElement('div');\n row.className = 'mz-im-actions';\n\n const insertBtn = document.createElement('button');\n insertBtn.type = 'button';\n insertBtn.textContent = 'Insert';\n insertBtn.onclick = () => {\n const url = opts?.onInsert ? opts.onInsert(img.url) : img.url;\n insertAtCursor(editor, ``);\n closePanel();\n };\n\n const delBtn = document.createElement('button');\n delBtn.type = 'button';\n delBtn.textContent = '✕';\n delBtn.title = 'Remove from recents';\n delBtn.onclick = () => {\n recents.splice(idx, 1);\n saveRecents(recents);\n renderGrid(root);\n };\n\n row.append(insertBtn, delBtn);\n card.append(image, row);\n grid.appendChild(card);\n });\n }\n\n async function addFromFile(file: File) {\n try {\n let url: string;\n if (opts?.uploader) {\n url = await opts.uploader(file);\n } else if (file.size <= threshold) {\n url = await fileToDataURL(file); // persist across reload\n } else {\n url = URL.createObjectURL(file); // session-only\n }\n const item: RecentImage = { url, name: file.name, createdAt: Date.now(), persistent: !url.startsWith('blob:') };\n recents = [item, ...recents.filter(r => r.url !== url)];\n saveRecents(recents);\n if (panel) renderGrid(panel);\n const finalUrl = opts?.onInsert ? opts.onInsert(url) : url;\n insertAtCursor(editor, ``);\n } catch (e) {\n console.error('Image add failed:', e);\n alert('Could not add image.');\n }\n }\n\n async function addFromUrl(url: string, name = 'image') {\n const item: RecentImage = { url, name, createdAt: Date.now(), persistent: true };\n recents = [item, ...recents.filter(r => r.url !== url)];\n saveRecents(recents);\n if (panel) renderGrid(panel);\n const finalUrl = opts?.onInsert ? opts.onInsert(url) : url;\n insertAtCursor(editor, ``);\n }\n\n function openPanel() {\n if (panel) { closePanel(); return; }\n\n panel = document.createElement('div');\n panel.className = 'mz-pop mz-im-panel';\n panel.innerHTML = `\n <div class=\"mz-im-row\">\n <input class=\"mz-im-url\" type=\"url\" placeholder=\"https://example.com/image.png\" />\n <button class=\"mz-im-addurl\" type=\"button\">Add URL</button>\n <input class=\"mz-im-file\" type=\"file\" accept=\"image/*\" hidden />\n <button class=\"mz-im-upload\" type=\"button\">Upload</button>\n <button class=\"mz-im-clear\" type=\"button\" title=\"Clear recents\">Clear</button>\n </div>\n <div class=\"mz-im-drop\">Drop images here, or paste into the editor.</div>\n <div class=\"mz-im-grid\"></div>\n `;\n document.body.appendChild(panel);\n\n // position panel\n const br = btn.getBoundingClientRect();\n panel.style.left = `${Math.round(window.scrollX + br.left)}px`;\n panel.style.top = `${Math.round(window.scrollY + br.bottom + 6)}px`;\n\n // Wire buttons\n const urlIn = panel.querySelector('.mz-im-url') as HTMLInputElement;\n const addUrl = panel.querySelector('.mz-im-addurl') as HTMLButtonElement;\n const fileIn = panel.querySelector('.mz-im-file') as HTMLInputElement;\n const upBtn = panel.querySelector('.mz-im-upload') as HTMLButtonElement;\n const clrBtn = panel.querySelector('.mz-im-clear') as HTMLButtonElement;\n const drop = panel.querySelector('.mz-im-drop') as HTMLElement;\n\n addUrl.onclick = () => {\n const val = urlIn.value.trim();\n if (!val) return;\n addFromUrl(val);\n urlIn.value = '';\n };\n\n upBtn.onclick = () => fileIn.click();\n fileIn.onchange = () => { const f = fileIn.files?.[0]; if (f) addFromFile(f); };\n\n clrBtn.onclick = () => {\n if (confirm('Clear recent images?')) {\n recents = [];\n saveRecents(recents);\n renderGrid(panel!);\n }\n };\n\n // Drag & drop\n ;['dragenter','dragover'].forEach(ev =>\n drop.addEventListener(ev, e => { e.preventDefault(); drop.classList.add('on'); })\n );\n ;['dragleave','drop'].forEach(ev =>\n drop.addEventListener(ev, e => { e.preventDefault(); drop.classList.remove('on'); })\n );\n drop.addEventListener('drop', (e: DragEvent) => {\n const files = e.dataTransfer?.files;\n if (!files || !files.length) return;\n Array.from(files).forEach(addFromFile);\n });\n\n // Render\n renderGrid(panel);\n\n // Close management\n setTimeout(() => {\n document.addEventListener('click', outsideClose, true);\n window.addEventListener('resize', closePanel);\n window.addEventListener('scroll', closePanel, true);\n }, 0);\n }\n\n // Paste support (into the editor textarea)\n editor.textarea.addEventListener('paste', (e: ClipboardEvent) => {\n const item = e.clipboardData?.items && Array.from(e.clipboardData.items)\n .find(i => i.kind === 'file' && i.type.startsWith('image/'));\n if (!item) return;\n const file = item.getAsFile();\n if (file) {\n e.preventDefault();\n addFromFile(file);\n }\n });\n\n // Drag & drop onto the editor container\n editor.container.addEventListener('dragover', e => {\n if (Array.from(e.dataTransfer?.items || []).some(i => i.kind === 'file')) e.preventDefault();\n });\n editor.container.addEventListener('drop', (e: DragEvent) => {\n const files = e.dataTransfer?.files;\n if (!files || !files.length) return;\n e.preventDefault();\n Array.from(files).forEach(addFromFile);\n });\n\n btn.onclick = openPanel;\n bar.appendChild(btn);\n };\n}\n\n// Minimal styles (inject once in your app)\nexport const imageManagerStyles = `\n.mz-im-panel { width: 440px; max-width: calc(100vw - 24px); }\n.mz-im-row { display: grid; grid-template-columns: 1fr auto auto auto; gap: 6px; margin-bottom: 8px; }\n.mz-im-row input[type=\"url\"] {\n background: var(--mz-ip-bg, #0f1216); color: var(--mz-ip-fg, #e7e7e7);\n border: 1px solid var(--mz-ip-bd, #2b2f36); border-radius: 8px; padding: 6px 8px;\n}\n.mz-im-row button {\n padding: 6px 10px; border-radius: 8px; border: 1px solid var(--mz-bd, #2b2f36);\n background: var(--mz-btn-bg, #1a1e24); color: var(--mz-btn-fg, #e7e7e7); cursor: pointer;\n}\n.mz-im-drop {\n border: 1px dashed var(--mz-drop-bd, #3b4350); border-radius: 8px;\n padding: 10px; text-align: center; font-size: 12px; margin-bottom: 8px;\n background: var(--mz-drop-bg, #0e1116);\n}\n.mz-im-drop.on { background: var(--mz-drop-on, #172033); }\n.mz-im-grid {\n display: grid; grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));\n gap: 8px; max-height: 320px; overflow: auto; padding: 2px;\n}\n.mz-im-card { border: 1px solid var(--mz-card-bd, #2b2f36); border-radius: 8px; overflow: hidden;\n background: var(--mz-card-bg, #12151a); display: flex; flex-direction: column; }\n.mz-im-card img { width: 100%; height: 82px; object-fit: cover; display: block; }\n.mz-im-actions { display: flex; gap: 6px; padding: 6px; justify-content: space-between; }\n.mz-im-actions button {\n flex: 1; padding: 4px 6px; border-radius: 6px; border: 1px solid var(--mz-bd, #2b2f36);\n background: var(--mz-btn2-bg, #1b2027); color: var(--mz-btn2-fg, #e7e7e7); cursor: pointer; font-size: 12px;\n}\n`;"],"names":["LS_KEY","insertAtCursor","editor","text","ta","s","e","loadRecents","saveRecents","list","fileToDataURL","file","fr","res","rej","imageManagerPlugin","opts","label","title","maxRecent","threshold","bar","btn","panel","recents","closePanel","outsideClose","renderGrid","root","grid","img","idx","card","image","row","insertBtn","url","delBtn","addFromFile","r","finalUrl","addFromUrl","name","openPanel","br","urlIn","addUrl","fileIn","upBtn","clrBtn","drop","val","f","ev","files","item","i","imageManagerStyles"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"imageManagerPlugin.js","sources":["../../src/plugins/imageManagerPlugin.ts"],"sourcesContent":["// plugins/imageManagerPlugin.ts` — recents, upload, URL add, drag-drop, paste\n// =====================================================\n// Persists “recents” in `localStorage` (data-URLs for small files ≤ default 1 MB).\n// Optional `uploader(file) => Promise<string>` to store remotely and return a URL.\n// Drag files onto the editor, or paste images from clipboard—instant preview and insert.\n// Tiny panel with thumbnails; click to insert; remove/clear as needed.\n\ntype MzEditor = {\n container: HTMLElement;\n textarea: HTMLTextAreaElement;\n updatePreview: () => void;\n};\n\ntype RecentImage = { url: string; name: string; createdAt: number; persistent: boolean };\n\nconst LS_KEY = 'marzipan.images';\n\nfunction insertAtCursor(editor: MzEditor, text: string) {\n const ta = editor.textarea;\n const s = ta.selectionStart ?? 0, e = ta.selectionEnd ?? 0;\n ta.setRangeText(text, s, e, 'end');\n editor.updatePreview();\n ta.focus();\n}\n\nfunction loadRecents(): RecentImage[] {\n try { return JSON.parse(localStorage.getItem(LS_KEY) || '[]'); }\n catch { return []; }\n}\nfunction saveRecents(list: RecentImage[]) {\n try { localStorage.setItem(LS_KEY, JSON.stringify(list.slice(0, 50))); } catch { /* localStorage not available */ }\n}\n\nasync function fileToDataURL(file: File): Promise<string> {\n const fr = new FileReader();\n return new Promise((res, rej) => {\n fr.onerror = () => rej(fr.error);\n fr.onload = () => res(String(fr.result));\n fr.readAsDataURL(file);\n });\n}\n\nexport function imageManagerPlugin(opts?: {\n label?: string; // toolbar label\n title?: string; // tooltip\n maxRecent?: number; // default 24\n persistThresholdBytes?: number; // default 1 MiB\n uploader?: (file: File) => Promise<string>; // optional remote upload\n onInsert?: (url: string) => string; // transform URL before insert\n}) {\n const label = opts?.label ?? '🗂️';\n const title = opts?.title ?? 'Images';\n const maxRecent = Math.max(1, opts?.maxRecent ?? 24);\n const threshold = opts?.persistThresholdBytes ?? (1 * 1024 * 1024);\n\n return (editor: MzEditor) => {\n const bar = editor.container.querySelector('.marzipan-toolbar') as HTMLElement ?? editor.container;\n\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'mz-btn mz-btn-imagemgr';\n btn.title = title;\n btn.textContent = label;\n\n let panel: HTMLElement | null = null;\n let recents: RecentImage[] = loadRecents();\n\n function closePanel() {\n panel?.remove(); panel = null;\n document.removeEventListener('click', outsideClose, true);\n window.removeEventListener('resize', closePanel);\n window.removeEventListener('scroll', closePanel, true);\n }\n function outsideClose(e: MouseEvent) {\n if (!panel) return;\n if (e.target instanceof Node && (panel.contains(e.target) || btn.contains(e.target))) return;\n closePanel();\n }\n\n function renderGrid(root: HTMLElement) {\n const grid = root.querySelector('.mz-im-grid') as HTMLElement;\n grid.innerHTML = '';\n recents.slice(0, maxRecent).forEach((img, idx) => {\n const card = document.createElement('div');\n card.className = 'mz-im-card';\n\n const image = document.createElement('img');\n image.decoding = 'async';\n image.loading = 'lazy';\n image.src = img.url;\n image.alt = img.name;\n\n const row = document.createElement('div');\n row.className = 'mz-im-actions';\n\n const insertBtn = document.createElement('button');\n insertBtn.type = 'button';\n insertBtn.textContent = 'Insert';\n insertBtn.onclick = () => {\n const url = opts?.onInsert ? opts.onInsert(img.url) : img.url;\n insertAtCursor(editor, ``);\n closePanel();\n };\n\n const delBtn = document.createElement('button');\n delBtn.type = 'button';\n delBtn.textContent = '✕';\n delBtn.title = 'Remove from recents';\n delBtn.onclick = () => {\n recents.splice(idx, 1);\n saveRecents(recents);\n renderGrid(root);\n };\n\n row.append(insertBtn, delBtn);\n card.append(image, row);\n grid.appendChild(card);\n });\n }\n\n async function addFromFile(file: File) {\n try {\n let url: string;\n if (opts?.uploader) {\n url = await opts.uploader(file);\n } else if (file.size <= threshold) {\n url = await fileToDataURL(file); // persist across reload\n } else {\n url = URL.createObjectURL(file); // session-only\n }\n const item: RecentImage = { url, name: file.name, createdAt: Date.now(), persistent: !url.startsWith('blob:') };\n recents = [item, ...recents.filter(r => r.url !== url)];\n saveRecents(recents);\n if (panel) renderGrid(panel);\n const finalUrl = opts?.onInsert ? opts.onInsert(url) : url;\n insertAtCursor(editor, ``);\n } catch (e) {\n console.error('Image add failed:', e);\n alert('Could not add image.');\n }\n }\n\n async function addFromUrl(url: string, name = 'image') {\n const item: RecentImage = { url, name, createdAt: Date.now(), persistent: true };\n recents = [item, ...recents.filter(r => r.url !== url)];\n saveRecents(recents);\n if (panel) renderGrid(panel);\n const finalUrl = opts?.onInsert ? opts.onInsert(url) : url;\n insertAtCursor(editor, ``);\n }\n\n function openPanel() {\n if (panel) { closePanel(); return; }\n\n panel = document.createElement('div');\n panel.className = 'mz-pop mz-im-panel';\n panel.innerHTML = `\n <div class=\"mz-im-row\">\n <input class=\"mz-im-url\" type=\"url\" placeholder=\"https://example.com/image.png\" />\n <button class=\"mz-im-addurl\" type=\"button\">Add URL</button>\n <input class=\"mz-im-file\" type=\"file\" accept=\"image/*\" hidden />\n <button class=\"mz-im-upload\" type=\"button\">Upload</button>\n <button class=\"mz-im-clear\" type=\"button\" title=\"Clear recents\">Clear</button>\n </div>\n <div class=\"mz-im-drop\">Drop images here, or paste into the editor.</div>\n <div class=\"mz-im-grid\"></div>\n `;\n document.body.appendChild(panel);\n\n // position panel\n const br = btn.getBoundingClientRect();\n panel.style.left = `${Math.round(window.scrollX + br.left)}px`;\n panel.style.top = `${Math.round(window.scrollY + br.bottom + 6)}px`;\n\n // Wire buttons\n const urlIn = panel.querySelector('.mz-im-url') as HTMLInputElement;\n const addUrl = panel.querySelector('.mz-im-addurl') as HTMLButtonElement;\n const fileIn = panel.querySelector('.mz-im-file') as HTMLInputElement;\n const upBtn = panel.querySelector('.mz-im-upload') as HTMLButtonElement;\n const clrBtn = panel.querySelector('.mz-im-clear') as HTMLButtonElement;\n const drop = panel.querySelector('.mz-im-drop') as HTMLElement;\n\n addUrl.onclick = () => {\n const val = urlIn.value.trim();\n if (!val) return;\n addFromUrl(val);\n urlIn.value = '';\n };\n\n upBtn.onclick = () => fileIn.click();\n fileIn.onchange = () => { const f = fileIn.files?.[0]; if (f) addFromFile(f); };\n\n clrBtn.onclick = () => {\n if (confirm('Clear recent images?')) {\n recents = [];\n saveRecents(recents);\n renderGrid(panel!);\n }\n };\n\n // Drag & drop\n ;['dragenter','dragover'].forEach(ev =>\n drop.addEventListener(ev, e => { e.preventDefault(); drop.classList.add('on'); })\n );\n ;['dragleave','drop'].forEach(ev =>\n drop.addEventListener(ev, e => { e.preventDefault(); drop.classList.remove('on'); })\n );\n drop.addEventListener('drop', (e: DragEvent) => {\n const files = e.dataTransfer?.files;\n if (!files || !files.length) return;\n Array.from(files).forEach(addFromFile);\n });\n\n // Render\n renderGrid(panel);\n\n // Close management\n setTimeout(() => {\n document.addEventListener('click', outsideClose, true);\n window.addEventListener('resize', closePanel);\n window.addEventListener('scroll', closePanel, true);\n }, 0);\n }\n\n // Paste support (into the editor textarea)\n editor.textarea.addEventListener('paste', (e: ClipboardEvent) => {\n const item = e.clipboardData?.items && Array.from(e.clipboardData.items)\n .find(i => i.kind === 'file' && i.type.startsWith('image/'));\n if (!item) return;\n const file = item.getAsFile();\n if (file) {\n e.preventDefault();\n addFromFile(file);\n }\n });\n\n // Drag & drop onto the editor container\n editor.container.addEventListener('dragover', e => {\n if (Array.from(e.dataTransfer?.items || []).some(i => i.kind === 'file')) e.preventDefault();\n });\n editor.container.addEventListener('drop', (e: DragEvent) => {\n const files = e.dataTransfer?.files;\n if (!files || !files.length) return;\n e.preventDefault();\n Array.from(files).forEach(addFromFile);\n });\n\n btn.onclick = openPanel;\n bar.appendChild(btn);\n };\n}\n\n// Minimal styles (inject once in your app)\nexport const imageManagerStyles = `\n.mz-im-panel { width: 440px; max-width: calc(100vw - 24px); }\n.mz-im-row { display: grid; grid-template-columns: 1fr auto auto auto; gap: 6px; margin-bottom: 8px; }\n.mz-im-row input[type=\"url\"] {\n background: var(--mz-ip-bg, #0f1216); color: var(--mz-ip-fg, #e7e7e7);\n border: 1px solid var(--mz-ip-bd, #2b2f36); border-radius: 8px; padding: 6px 8px;\n}\n.mz-im-row button {\n padding: 6px 10px; border-radius: 8px; border: 1px solid var(--mz-bd, #2b2f36);\n background: var(--mz-btn-bg, #1a1e24); color: var(--mz-btn-fg, #e7e7e7); cursor: pointer;\n}\n.mz-im-drop {\n border: 1px dashed var(--mz-drop-bd, #3b4350); border-radius: 8px;\n padding: 10px; text-align: center; font-size: 12px; margin-bottom: 8px;\n background: var(--mz-drop-bg, #0e1116);\n}\n.mz-im-drop.on { background: var(--mz-drop-on, #172033); }\n.mz-im-grid {\n display: grid; grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));\n gap: 8px; max-height: 320px; overflow: auto; padding: 2px;\n}\n.mz-im-card { border: 1px solid var(--mz-card-bd, #2b2f36); border-radius: 8px; overflow: hidden;\n background: var(--mz-card-bg, #12151a); display: flex; flex-direction: column; }\n.mz-im-card img { width: 100%; height: 82px; object-fit: cover; display: block; }\n.mz-im-actions { display: flex; gap: 6px; padding: 6px; justify-content: space-between; }\n.mz-im-actions button {\n flex: 1; padding: 4px 6px; border-radius: 6px; border: 1px solid var(--mz-bd, #2b2f36);\n background: var(--mz-btn2-bg, #1b2027); color: var(--mz-btn2-fg, #e7e7e7); cursor: pointer; font-size: 12px;\n}\n`;"],"names":["LS_KEY","insertAtCursor","editor","text","ta","s","e","loadRecents","saveRecents","list","fileToDataURL","file","fr","res","rej","imageManagerPlugin","opts","label","title","maxRecent","threshold","bar","btn","panel","recents","closePanel","outsideClose","renderGrid","root","grid","img","idx","card","image","row","insertBtn","url","delBtn","addFromFile","r","finalUrl","addFromUrl","name","openPanel","br","urlIn","addUrl","fileIn","upBtn","clrBtn","drop","val","f","ev","files","item","i","imageManagerStyles"],"mappings":"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"}
|
package/dist/plugins/index.d.ts
CHANGED
|
@@ -5,4 +5,20 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { BlockHandlesPlugin } from './block-handles';
|
|
7
7
|
export type { BlockHandle, BlockHandlesConfig } from './block-handles';
|
|
8
|
+
export { accentSwatchPlugin, accentSwatchStyles } from './accentSwatchPlugin';
|
|
9
|
+
export { imageManagerPlugin, imageManagerStyles } from './imageManagerPlugin';
|
|
10
|
+
export { imagePickerPlugin } from './imagePickerPlugin';
|
|
11
|
+
export type { ImagePickerOptions } from './imagePicker';
|
|
12
|
+
export { mermaidPlugin } from './mermaidPlugin';
|
|
13
|
+
export { mermaidExternalPlugin } from './mermaidExternal';
|
|
14
|
+
export { tablePlugin } from './tablePlugin';
|
|
15
|
+
export type { TablePluginOptions } from './tablePlugin';
|
|
16
|
+
export { tableGridPlugin, tableGridStyles } from './tableGridPlugin';
|
|
17
|
+
export type { TableGridPluginOptions } from './tableGridPlugin';
|
|
18
|
+
export { tableGeneratorPlugin } from './tableGenerator';
|
|
19
|
+
export { tinyHighlightPlugin, tinyHighlightStyles } from './tinyHighlight';
|
|
20
|
+
export type { MarzipanLike } from './tinyHighlight';
|
|
21
|
+
export { buildTableMarkdown, resolvePositiveInteger } from './utils/table';
|
|
22
|
+
export { imagePickerPlugin as coreImagePickerPlugin } from './imagePicker';
|
|
23
|
+
export type { ImagePickerOptions as CoreImagePickerOptions } from './imagePicker';
|
|
8
24
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"AACA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"AACA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAGvE,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAG9E,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGxD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACrE,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAGxD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAC3E,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAG3E,OAAO,EAAE,iBAAiB,IAAI,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3E,YAAY,EAAE,kBAAkB,IAAI,sBAAsB,EAAE,MAAM,eAAe,CAAC"}
|