@pinkpixel/marzipan 1.0.7 → 1.0.9

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.
Files changed (138) hide show
  1. package/README.md +1 -1
  2. package/dist/_basePickBy-7myk7wY6.js +152 -0
  3. package/dist/_basePickBy-7myk7wY6.js.map +1 -0
  4. package/dist/_baseUniq-DVSvs9C9.js +615 -0
  5. package/dist/_baseUniq-DVSvs9C9.js.map +1 -0
  6. package/dist/arc-wOVD9GAB.js +84 -0
  7. package/dist/arc-wOVD9GAB.js.map +1 -0
  8. package/dist/architectureDiagram-VXUJARFQ-BUbrFcAV.js +4663 -0
  9. package/dist/architectureDiagram-VXUJARFQ-BUbrFcAV.js.map +1 -0
  10. package/dist/blockDiagram-VD42YOAC-jy_Bz7_a.js +2262 -0
  11. package/dist/blockDiagram-VD42YOAC-jy_Bz7_a.js.map +1 -0
  12. package/dist/c4Diagram-YG6GDRKO-zzDx0s1r.js +1581 -0
  13. package/dist/c4Diagram-YG6GDRKO-zzDx0s1r.js.map +1 -0
  14. package/dist/channel-CwQyz_h8.js +6 -0
  15. package/dist/channel-CwQyz_h8.js.map +1 -0
  16. package/dist/chunk-4BX2VUAB-BPOEnnJc.js +9 -0
  17. package/dist/chunk-4BX2VUAB-BPOEnnJc.js.map +1 -0
  18. package/dist/chunk-55IACEB6-CvbNm4Ij.js +9 -0
  19. package/dist/chunk-55IACEB6-CvbNm4Ij.js.map +1 -0
  20. package/dist/chunk-B4BG7PRW-DeY8sefa.js +1376 -0
  21. package/dist/chunk-B4BG7PRW-DeY8sefa.js.map +1 -0
  22. package/dist/chunk-DI55MBZ5-BiWs6KMl.js +1371 -0
  23. package/dist/chunk-DI55MBZ5-BiWs6KMl.js.map +1 -0
  24. package/dist/chunk-FMBD7UC4-DFfhN2XA.js +20 -0
  25. package/dist/chunk-FMBD7UC4-DFfhN2XA.js.map +1 -0
  26. package/dist/chunk-QN33PNHL-0k4tnBW4.js +20 -0
  27. package/dist/chunk-QN33PNHL-0k4tnBW4.js.map +1 -0
  28. package/dist/chunk-QZHKN3VN-Cqlx-pCX.js +16 -0
  29. package/dist/chunk-QZHKN3VN-Cqlx-pCX.js.map +1 -0
  30. package/dist/chunk-TZMSLE5B-CIL9qnEM.js +65 -0
  31. package/dist/chunk-TZMSLE5B-CIL9qnEM.js.map +1 -0
  32. package/dist/classDiagram-2ON5EDUG-DvfCZ1-0.js +17 -0
  33. package/dist/classDiagram-2ON5EDUG-DvfCZ1-0.js.map +1 -0
  34. package/dist/classDiagram-v2-WZHVMYZB-DvfCZ1-0.js +17 -0
  35. package/dist/classDiagram-v2-WZHVMYZB-DvfCZ1-0.js.map +1 -0
  36. package/dist/clone-BZ5Rkhbx.js +9 -0
  37. package/dist/clone-BZ5Rkhbx.js.map +1 -0
  38. package/dist/cose-bilkent-S5V4N54A-Doh7yBTX.js +2609 -0
  39. package/dist/cose-bilkent-S5V4N54A-Doh7yBTX.js.map +1 -0
  40. package/dist/dagre-6UL2VRFP-BFkZcVkL.js +445 -0
  41. package/dist/dagre-6UL2VRFP-BFkZcVkL.js.map +1 -0
  42. package/dist/diagram-PSM6KHXK-DyiwV-ia.js +532 -0
  43. package/dist/diagram-PSM6KHXK-DyiwV-ia.js.map +1 -0
  44. package/dist/diagram-QEK2KX5R-Dczirmo7.js +218 -0
  45. package/dist/diagram-QEK2KX5R-Dczirmo7.js.map +1 -0
  46. package/dist/diagram-S2PKOQOG-BOO6_G9V.js +143 -0
  47. package/dist/diagram-S2PKOQOG-BOO6_G9V.js.map +1 -0
  48. package/dist/erDiagram-Q2GNP2WA-Bm9LxMmY.js +842 -0
  49. package/dist/erDiagram-Q2GNP2WA-Bm9LxMmY.js.map +1 -0
  50. package/dist/favicon.png +0 -0
  51. package/dist/flowDiagram-NV44I4VS-CDsRBuXA.js +1621 -0
  52. package/dist/flowDiagram-NV44I4VS-CDsRBuXA.js.map +1 -0
  53. package/dist/ganttDiagram-LVOFAZNH-BHG15mHm.js +2506 -0
  54. package/dist/ganttDiagram-LVOFAZNH-BHG15mHm.js.map +1 -0
  55. package/dist/gitGraphDiagram-NY62KEGX-D_Oe_z5q.js +700 -0
  56. package/dist/gitGraphDiagram-NY62KEGX-D_Oe_z5q.js.map +1 -0
  57. package/dist/graph-DnSw707R.js +248 -0
  58. package/dist/graph-DnSw707R.js.map +1 -0
  59. package/dist/icons.d.ts +1 -0
  60. package/dist/icons.d.ts.map +1 -1
  61. package/dist/icons.js +6 -0
  62. package/dist/icons.js.map +1 -1
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +595 -492
  65. package/dist/index.js.map +1 -1
  66. package/dist/infoDiagram-F6ZHWCRC-BIKrEuHs.js +25 -0
  67. package/dist/infoDiagram-F6ZHWCRC-BIKrEuHs.js.map +1 -0
  68. package/dist/journeyDiagram-XKPGCS4Q-Cwx0rvbI.js +835 -0
  69. package/dist/journeyDiagram-XKPGCS4Q-Cwx0rvbI.js.map +1 -0
  70. package/dist/kanban-definition-3W4ZIXB7-DJzoU3Tr.js +720 -0
  71. package/dist/kanban-definition-3W4ZIXB7-DJzoU3Tr.js.map +1 -0
  72. package/dist/layout-mDCCYMKB.js +1325 -0
  73. package/dist/layout-mDCCYMKB.js.map +1 -0
  74. package/dist/linear-Cr_O1Zei.js +260 -0
  75. package/dist/linear-Cr_O1Zei.js.map +1 -0
  76. package/dist/logo.png +0 -0
  77. package/dist/marzipan.d.ts +28 -3
  78. package/dist/marzipan.d.ts.map +1 -1
  79. package/dist/marzipan.js +161 -64
  80. package/dist/marzipan.js.map +1 -1
  81. package/dist/mermaid.core-BwjwqwU6.js +15249 -0
  82. package/dist/mermaid.core-BwjwqwU6.js.map +1 -0
  83. package/dist/mindmap-definition-VGOIOE7T-BNBUkXyU.js +785 -0
  84. package/dist/mindmap-definition-VGOIOE7T-BNBUkXyU.js.map +1 -0
  85. package/dist/parser.d.ts +12 -1
  86. package/dist/parser.d.ts.map +1 -1
  87. package/dist/parser.js +65 -14
  88. package/dist/parser.js.map +1 -1
  89. package/dist/pieDiagram-ADFJNKIX-DgEtM4kB.js +162 -0
  90. package/dist/pieDiagram-ADFJNKIX-DgEtM4kB.js.map +1 -0
  91. package/dist/plugins/block-handles.d.ts +162 -0
  92. package/dist/plugins/block-handles.d.ts.map +1 -0
  93. package/dist/plugins/block-handles.js +355 -0
  94. package/dist/plugins/block-handles.js.map +1 -0
  95. package/dist/plugins/imagePicker.d.ts +2 -0
  96. package/dist/plugins/imagePicker.d.ts.map +1 -1
  97. package/dist/plugins/imagePicker.js +17 -15
  98. package/dist/plugins/imagePicker.js.map +1 -1
  99. package/dist/plugins/index.d.ts +8 -0
  100. package/dist/plugins/index.d.ts.map +1 -0
  101. package/dist/plugins/index.js +5 -0
  102. package/dist/plugins/index.js.map +1 -0
  103. package/dist/plugins/mermaidPlugin.js +1 -1
  104. package/dist/plugins/tableGridPlugin.d.ts +4 -2
  105. package/dist/plugins/tableGridPlugin.d.ts.map +1 -1
  106. package/dist/plugins/tableGridPlugin.js +21 -21
  107. package/dist/plugins/tableGridPlugin.js.map +1 -1
  108. package/dist/plugins/tablePlugin.d.ts +7 -1
  109. package/dist/plugins/tablePlugin.d.ts.map +1 -1
  110. package/dist/plugins/tablePlugin.js +20 -19
  111. package/dist/plugins/tablePlugin.js.map +1 -1
  112. package/dist/quadrantDiagram-AYHSOK5B-iCwbSiz2.js +1023 -0
  113. package/dist/quadrantDiagram-AYHSOK5B-iCwbSiz2.js.map +1 -0
  114. package/dist/requirementDiagram-UZGBJVZJ-CH1vdgr6.js +851 -0
  115. package/dist/requirementDiagram-UZGBJVZJ-CH1vdgr6.js.map +1 -0
  116. package/dist/sankeyDiagram-TZEHDZUN-Gl503N-l.js +811 -0
  117. package/dist/sankeyDiagram-TZEHDZUN-Gl503N-l.js.map +1 -0
  118. package/dist/sequenceDiagram-WL72ISMW-BG1sXWAR.js +2512 -0
  119. package/dist/sequenceDiagram-WL72ISMW-BG1sXWAR.js.map +1 -0
  120. package/dist/stateDiagram-FKZM4ZOC-DZEKan9V.js +264 -0
  121. package/dist/stateDiagram-FKZM4ZOC-DZEKan9V.js.map +1 -0
  122. package/dist/stateDiagram-v2-4FDKWEC3-BbM9NXKp.js +17 -0
  123. package/dist/stateDiagram-v2-4FDKWEC3-BbM9NXKp.js.map +1 -0
  124. package/dist/styles.js +2 -2
  125. package/dist/timeline-definition-IT6M3QCI-B4lGoGS8.js +796 -0
  126. package/dist/timeline-definition-IT6M3QCI-B4lGoGS8.js.map +1 -0
  127. package/dist/toolbar.d.ts +4 -1
  128. package/dist/toolbar.d.ts.map +1 -1
  129. package/dist/toolbar.js +60 -20
  130. package/dist/toolbar.js.map +1 -1
  131. package/dist/treemap-75Q7IDZK-Cx8WKL-4.js +12988 -0
  132. package/dist/treemap-75Q7IDZK-Cx8WKL-4.js.map +1 -0
  133. package/dist/xychartDiagram-PRI3JC2R-DnhFwjWO.js +1341 -0
  134. package/dist/xychartDiagram-PRI3JC2R-DnhFwjWO.js.map +1 -0
  135. package/docs/api.md +95 -48
  136. package/docs/block-handles.README.md +329 -0
  137. package/docs/types.d.ts +57 -37
  138. package/package.json +3 -2
@@ -0,0 +1,355 @@
1
+ class r {
2
+ constructor(e, t, i = {}) {
3
+ this.editor = e, this.preview = t, this.config = {
4
+ enabled: i.enabled ?? !0,
5
+ showOnHover: i.showOnHover ?? !0,
6
+ handleOffset: i.handleOffset ?? -30,
7
+ handleSize: i.handleSize ?? 20,
8
+ colors: {
9
+ hover: i.colors?.hover ?? "rgba(59, 130, 246, 0.1)",
10
+ selected: i.colors?.selected ?? "rgba(59, 130, 246, 0.2)",
11
+ handle: i.colors?.handle ?? "rgba(59, 130, 246, 0.8)"
12
+ }
13
+ }, this.blocks = /* @__PURE__ */ new Map(), this.selectedBlockId = null, this.handleContainer = null, this.initialize();
14
+ }
15
+ /**
16
+ * Initialize the plugin
17
+ */
18
+ initialize() {
19
+ this.config.enabled && (this.createHandleContainer(), this.setupEventListeners(), this.scanBlocks());
20
+ }
21
+ /**
22
+ * Create the container for block handles
23
+ */
24
+ createHandleContainer() {
25
+ this.handleContainer = document.createElement("div"), this.handleContainer.className = "mz-block-handles", this.handleContainer.style.cssText = `
26
+ position: absolute;
27
+ top: 0;
28
+ left: 0;
29
+ width: 100%;
30
+ height: 100%;
31
+ pointer-events: none;
32
+ z-index: 10;
33
+ `, this.preview.style.position = "relative", this.preview.appendChild(this.handleContainer);
34
+ }
35
+ /**
36
+ * Set up event listeners for block interactions
37
+ */
38
+ setupEventListeners() {
39
+ this.preview.addEventListener("mousemove", this.handleMouseMove.bind(this)), this.preview.addEventListener("mouseleave", this.handleMouseLeave.bind(this)), this.preview.addEventListener("click", this.handleClick.bind(this)), document.addEventListener("keydown", this.handleKeyDown.bind(this));
40
+ }
41
+ /**
42
+ * Scan the preview for blocks and create handles
43
+ */
44
+ scanBlocks() {
45
+ if (this.blocks.clear(), !this.handleContainer) return;
46
+ this.handleContainer.innerHTML = "", this.preview.querySelectorAll("[data-block-id]").forEach((t) => {
47
+ const i = t.getAttribute("data-block-id"), s = t.getAttribute("data-block-type"), n = parseInt(t.getAttribute("data-line-start") || "0", 10), c = parseInt(t.getAttribute("data-line-end") || "0", 10);
48
+ if (!i) return;
49
+ const l = this.createHandle(i, s || "paragraph", t);
50
+ this.blocks.set(i, {
51
+ id: i,
52
+ type: s || "paragraph",
53
+ lineStart: n,
54
+ lineEnd: c,
55
+ element: t,
56
+ handleElement: l
57
+ });
58
+ });
59
+ }
60
+ /**
61
+ * Create a handle element for a block
62
+ */
63
+ createHandle(e, t, i) {
64
+ const s = document.createElement("div");
65
+ return s.className = `mz-block-handle mz-block-handle-${t}`, s.setAttribute("data-block-id", e), s.style.cssText = `
66
+ position: absolute;
67
+ width: ${this.config.handleSize}px;
68
+ height: ${this.config.handleSize}px;
69
+ left: ${this.config.handleOffset}px;
70
+ background: ${this.config.colors.handle};
71
+ border-radius: 4px;
72
+ cursor: pointer;
73
+ opacity: 0;
74
+ transition: opacity 0.2s ease;
75
+ pointer-events: auto;
76
+ display: flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ color: white;
80
+ font-size: 12px;
81
+ user-select: none;
82
+ `, s.innerHTML = this.getHandleIcon(t), s.addEventListener("click", (n) => {
83
+ n.stopPropagation(), this.selectBlock(e);
84
+ }), s.addEventListener("contextmenu", (n) => {
85
+ n.preventDefault(), n.stopPropagation(), this.showContextMenu(e, n);
86
+ }), this.handleContainer?.appendChild(s), this.updateHandlePosition(e), s;
87
+ }
88
+ /**
89
+ * Get icon for handle based on block type
90
+ */
91
+ getHandleIcon(e) {
92
+ return {
93
+ heading: "⚡",
94
+ paragraph: "¶",
95
+ "list-item": "•",
96
+ quote: '"',
97
+ "code-fence": "{",
98
+ "code-content": "{}",
99
+ hr: "―",
100
+ "table-row": "⊞",
101
+ "table-separator": "═"
102
+ }[e] || "○";
103
+ }
104
+ /**
105
+ * Update handle position based on block element position
106
+ */
107
+ updateHandlePosition(e) {
108
+ const t = this.blocks.get(e);
109
+ if (!t || !t.handleElement) return;
110
+ const i = t.element.getBoundingClientRect(), s = this.preview.getBoundingClientRect(), n = i.top - s.top + this.preview.scrollTop;
111
+ t.handleElement.style.top = `${n}px`;
112
+ }
113
+ /**
114
+ * Update all handle positions (call on scroll/resize)
115
+ */
116
+ updateAllHandlePositions() {
117
+ this.blocks.forEach((e, t) => {
118
+ this.updateHandlePosition(t);
119
+ });
120
+ }
121
+ /**
122
+ * Handle mouse move for hover effects
123
+ */
124
+ handleMouseMove(e) {
125
+ if (!this.config.showOnHover) return;
126
+ const t = e.target, i = this.findBlockElement(t);
127
+ if (i) {
128
+ const s = i.getAttribute("data-block-id");
129
+ s && (this.showHandle(s), this.highlightBlock(s, !1));
130
+ } else
131
+ this.hideAllHandles(), this.unhighlightAll();
132
+ }
133
+ /**
134
+ * Handle mouse leave event
135
+ */
136
+ handleMouseLeave() {
137
+ this.hideAllHandles(), this.unhighlightAll(!0);
138
+ }
139
+ /**
140
+ * Handle click events for block selection
141
+ */
142
+ handleClick(e) {
143
+ const t = e.target, i = this.findBlockElement(t);
144
+ if (i) {
145
+ const s = i.getAttribute("data-block-id");
146
+ s && e.shiftKey && (e.preventDefault(), this.selectBlock(s));
147
+ } else t.closest(".mz-block-handle") || this.deselectBlock();
148
+ }
149
+ /**
150
+ * Handle keyboard shortcuts
151
+ */
152
+ handleKeyDown(e) {
153
+ 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
+ }
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
+ /**
162
+ * Show a specific handle
163
+ */
164
+ showHandle(e) {
165
+ const t = this.blocks.get(e);
166
+ t?.handleElement && (t.handleElement.style.opacity = "1");
167
+ }
168
+ /**
169
+ * Hide all handles except selected
170
+ */
171
+ hideAllHandles() {
172
+ this.blocks.forEach((e) => {
173
+ e.handleElement && e.id !== this.selectedBlockId && (e.handleElement.style.opacity = "0");
174
+ });
175
+ }
176
+ /**
177
+ * Highlight a block
178
+ */
179
+ highlightBlock(e, t) {
180
+ const i = this.blocks.get(e);
181
+ if (!i) return;
182
+ const s = t ? this.config.colors.selected : this.config.colors.hover;
183
+ i.element.style.backgroundColor = s;
184
+ }
185
+ /**
186
+ * Remove highlight from all blocks
187
+ */
188
+ unhighlightAll(e = !1) {
189
+ this.blocks.forEach((t) => {
190
+ (!e || t.id !== this.selectedBlockId) && (t.element.style.backgroundColor = "");
191
+ });
192
+ }
193
+ /**
194
+ * Select a block
195
+ */
196
+ selectBlock(e) {
197
+ if (this.selectedBlockId) {
198
+ this.unhighlightAll();
199
+ const t = this.blocks.get(this.selectedBlockId);
200
+ t?.handleElement && (t.handleElement.style.opacity = "0");
201
+ }
202
+ this.selectedBlockId = e, this.highlightBlock(e, !0), this.showHandle(e), this.preview.dispatchEvent(new CustomEvent("blockSelected", {
203
+ detail: { blockId: e, block: this.blocks.get(e) }
204
+ }));
205
+ }
206
+ /**
207
+ * Deselect current block
208
+ */
209
+ deselectBlock() {
210
+ if (!this.selectedBlockId) return;
211
+ const e = this.selectedBlockId;
212
+ this.selectedBlockId = null, this.unhighlightAll(), this.hideAllHandles(), this.preview.dispatchEvent(new CustomEvent("blockDeselected", {
213
+ detail: { blockId: e }
214
+ }));
215
+ }
216
+ /**
217
+ * Copy block content to clipboard
218
+ */
219
+ async copyBlock(e) {
220
+ const t = this.blocks.get(e);
221
+ if (!t) return;
222
+ const i = this.getBlockContent(t);
223
+ try {
224
+ await navigator.clipboard.writeText(i), this.showToast("Block copied to clipboard");
225
+ } catch (s) {
226
+ console.error("Failed to copy block:", s), this.showToast("Failed to copy block", "error");
227
+ }
228
+ }
229
+ /**
230
+ * Delete a block from the editor
231
+ */
232
+ deleteBlock(e) {
233
+ const t = this.blocks.get(e);
234
+ if (!t) return;
235
+ const s = this.editor.value.split(`
236
+ `);
237
+ s.splice(t.lineStart, t.lineEnd - t.lineStart + 1), this.editor.value = s.join(`
238
+ `), this.editor.dispatchEvent(new Event("input", { bubbles: !0 })), this.deselectBlock(), this.showToast("Block deleted");
239
+ }
240
+ /**
241
+ * Get the text content of a block from the editor
242
+ */
243
+ getBlockContent(e) {
244
+ return this.editor.value.split(`
245
+ `).slice(e.lineStart, e.lineEnd + 1).join(`
246
+ `);
247
+ }
248
+ /**
249
+ * Show context menu for block actions
250
+ */
251
+ showContextMenu(e, t) {
252
+ const i = document.querySelector(".mz-block-context-menu");
253
+ i && i.remove();
254
+ const s = document.createElement("div");
255
+ s.className = "mz-block-context-menu", s.style.cssText = `
256
+ position: fixed;
257
+ top: ${t.clientY}px;
258
+ left: ${t.clientX}px;
259
+ background: white;
260
+ border: 1px solid #e0e0e0;
261
+ border-radius: 4px;
262
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
263
+ z-index: 1000;
264
+ min-width: 150px;
265
+ padding: 4px 0;
266
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
267
+ font-size: 14px;
268
+ `, [
269
+ { label: "Copy", action: () => this.copyBlock(e), icon: "📋" },
270
+ { label: "Delete", action: () => this.deleteBlock(e), icon: "🗑️" },
271
+ { label: "Select", action: () => this.selectBlock(e), icon: "✓" }
272
+ ].forEach(({ label: l, action: a, icon: d }) => {
273
+ const o = document.createElement("div");
274
+ o.className = "mz-context-menu-item", o.textContent = `${d} ${l}`, o.style.cssText = `
275
+ padding: 8px 16px;
276
+ cursor: pointer;
277
+ user-select: none;
278
+ `, o.addEventListener("mouseenter", () => {
279
+ o.style.backgroundColor = "#f5f5f5";
280
+ }), o.addEventListener("mouseleave", () => {
281
+ o.style.backgroundColor = "";
282
+ }), o.addEventListener("click", () => {
283
+ a(), s.remove();
284
+ }), s.appendChild(o);
285
+ }), document.body.appendChild(s);
286
+ const c = (l) => {
287
+ s.contains(l.target) || (s.remove(), document.removeEventListener("click", c));
288
+ };
289
+ setTimeout(() => {
290
+ document.addEventListener("click", c);
291
+ }, 0);
292
+ }
293
+ /**
294
+ * Show a toast notification
295
+ */
296
+ showToast(e, t = "success") {
297
+ const i = document.createElement("div");
298
+ i.className = "mz-toast", i.textContent = e, i.style.cssText = `
299
+ position: fixed;
300
+ bottom: 20px;
301
+ right: 20px;
302
+ background: ${t === "success" ? "#10b981" : "#ef4444"};
303
+ color: white;
304
+ padding: 12px 20px;
305
+ border-radius: 4px;
306
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
307
+ z-index: 1000;
308
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
309
+ font-size: 14px;
310
+ animation: slideIn 0.3s ease;
311
+ `, document.body.appendChild(i), setTimeout(() => {
312
+ i.style.animation = "slideOut 0.3s ease", setTimeout(() => i.remove(), 300);
313
+ }, 2e3);
314
+ }
315
+ /**
316
+ * Enable the plugin
317
+ */
318
+ enable() {
319
+ this.config.enabled = !0, this.initialize();
320
+ }
321
+ /**
322
+ * Disable the plugin
323
+ */
324
+ disable() {
325
+ this.config.enabled = !1, this.handleContainer?.remove(), this.handleContainer = null, this.blocks.clear(), this.selectedBlockId = null;
326
+ }
327
+ /**
328
+ * Refresh the plugin (rescan blocks and update positions)
329
+ */
330
+ refresh() {
331
+ this.scanBlocks();
332
+ }
333
+ /**
334
+ * Get the currently selected block
335
+ */
336
+ getSelectedBlock() {
337
+ return this.selectedBlockId && this.blocks.get(this.selectedBlockId) || null;
338
+ }
339
+ /**
340
+ * Get all blocks
341
+ */
342
+ getAllBlocks() {
343
+ return Array.from(this.blocks.values());
344
+ }
345
+ /**
346
+ * Clean up and remove the plugin
347
+ */
348
+ destroy() {
349
+ this.disable(), this.preview.removeEventListener("mousemove", this.handleMouseMove.bind(this)), this.preview.removeEventListener("mouseleave", this.handleMouseLeave.bind(this)), this.preview.removeEventListener("click", this.handleClick.bind(this)), document.removeEventListener("keydown", this.handleKeyDown.bind(this));
350
+ }
351
+ }
352
+ export {
353
+ r as BlockHandlesPlugin
354
+ };
355
+ //# sourceMappingURL=block-handles.js.map
@@ -0,0 +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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"}
@@ -2,6 +2,8 @@ export type ImagePickerOptions = {
2
2
  uploader?: (file: File) => Promise<string>;
3
3
  label?: string;
4
4
  title?: string;
5
+ placeholder?: string;
6
+ promptMessage?: string;
5
7
  };
6
8
  export declare function imagePickerPlugin(opts?: ImagePickerOptions): (editor: any) => void;
7
9
  //# sourceMappingURL=imagePicker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"imagePicker.d.ts","sourceRoot":"","sources":["../../src/plugins/imagePicker.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAUF,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,kBAAuB,IAIrD,QAAQ,GAAG,UAuCpB"}
1
+ {"version":3,"file":"imagePicker.d.ts","sourceRoot":"","sources":["../../src/plugins/imagePicker.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAUF,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,kBAAuB,IAIrD,QAAQ,GAAG,UA4CpB"}
@@ -1,16 +1,18 @@
1
- function s(e, l) {
2
- const t = e.textarea, n = t.selectionStart ?? 0, r = t.selectionEnd ?? 0;
3
- t.setRangeText(l, n, r, "end"), e.updatePreview?.(), t.focus();
1
+ function m(e, r) {
2
+ const t = e.textarea, n = t.selectionStart ?? 0, l = t.selectionEnd ?? 0;
3
+ t.setRangeText(r, n, l, "end"), e.updatePreview?.(), t.focus();
4
4
  }
5
- function m(e = {}) {
6
- const l = e.label ?? "🖼️", t = e.title ?? "Insert image";
5
+ function f(e = {}) {
6
+ const r = e.label ?? "🖼️", t = e.title ?? "Insert image";
7
7
  return (n) => {
8
- const r = n.container?.querySelector?.(".marzipan-toolbar") ?? n.container, a = document.createElement("button");
9
- a.type = "button", a.title = t, a.className = "mz-btn mz-btn-image", a.textContent = l, a.onclick = async () => {
10
- const i = prompt('Paste an image URL, or type "upload" to pick a file:');
8
+ const l = n.container?.querySelector?.(".marzipan-toolbar") ?? n.container, a = document.createElement("button");
9
+ a.type = "button", a.title = t, a.className = "mz-btn mz-btn-image", a.textContent = r, a.onclick = async () => {
10
+ const p = e.promptMessage ?? 'Paste an image URL, or type "upload" to pick a file:', d = e.placeholder ?? "", u = prompt(p, d);
11
+ if (!u) return;
12
+ const i = u.trim();
11
13
  if (!i) return;
12
14
  if (i.toLowerCase() !== "upload") {
13
- s(n, `![alt text](${i})`);
15
+ m(n, `![alt text](${i})`);
14
16
  return;
15
17
  }
16
18
  const c = document.createElement("input");
@@ -18,16 +20,16 @@ function m(e = {}) {
18
20
  const o = c.files?.[0];
19
21
  if (o)
20
22
  try {
21
- const u = e.uploader ? await e.uploader(o) : URL.createObjectURL(o);
22
- s(n, `![${o.name}](${u})`);
23
- } catch (u) {
24
- console.error("Image upload failed:", u), alert("Image upload failed.");
23
+ const s = e.uploader ? await e.uploader(o) : URL.createObjectURL(o);
24
+ m(n, `![${o.name}](${s})`);
25
+ } catch (s) {
26
+ console.error("Image upload failed:", s), alert("Image upload failed.");
25
27
  }
26
28
  }, c.click();
27
- }, r?.appendChild(a);
29
+ }, l?.appendChild(a);
28
30
  };
29
31
  }
30
32
  export {
31
- m as imagePickerPlugin
33
+ f as imagePickerPlugin
32
34
  };
33
35
  //# sourceMappingURL=imagePicker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"imagePicker.js","sources":["../../src/plugins/imagePicker.ts"],"sourcesContent":["// plugins/imagePicker.ts\n// Adds a toolbar button to insert images. Supports URL or file -> blob URL.\n// Optional uploader(file) => Promise<string> to persist and return a real URL.\n\nexport type ImagePickerOptions = {\n uploader?: (file: File) => Promise<string>;\n label?: string; // button label or emoji\n title?: string; // tooltip\n};\n\nfunction insertAtCursor(editor: any, text: string) {\n const ta = editor.textarea as HTMLTextAreaElement;\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\nexport function imagePickerPlugin(opts: ImagePickerOptions = {}) {\n const label = opts.label ?? '🖼️';\n const title = opts.title ?? 'Insert image';\n\n return (editor: any) => {\n // Find or create a toolbar container\n const bar = editor.container?.querySelector?.('.marzipan-toolbar') as HTMLElement\n ?? editor.container;\n\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.title = title;\n btn.className = 'mz-btn mz-btn-image';\n btn.textContent = label;\n\n btn.onclick = async () => {\n const mode = prompt('Paste an image URL, or type \"upload\" to pick a file:');\n if (!mode) return;\n\n if (mode.toLowerCase() !== 'upload') {\n insertAtCursor(editor, `![alt text](${mode})`);\n return;\n }\n\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = 'image/*';\n input.onchange = async () => {\n const file = input.files?.[0];\n if (!file) return;\n try {\n const url = opts.uploader ? await opts.uploader(file) : URL.createObjectURL(file);\n insertAtCursor(editor, `![${file.name}](${url})`);\n } catch (e) {\n console.error('Image upload failed:', e);\n alert('Image upload failed.');\n }\n };\n input.click();\n };\n\n bar?.appendChild(btn);\n };\n}"],"names":["insertAtCursor","editor","text","ta","s","e","imagePickerPlugin","opts","label","title","bar","btn","mode","input","file","url"],"mappings":"AAUA,SAASA,EAAeC,GAAaC,GAAc;AACjD,QAAMC,IAAKF,EAAO,UACZG,IAAID,EAAG,kBAAkB,GAAGE,IAAIF,EAAG,gBAAgB;AACzD,EAAAA,EAAG,aAAaD,GAAME,GAAGC,GAAG,KAAK,GACjCJ,EAAO,gBAAA,GACPE,EAAG,MAAA;AACL;AAEO,SAASG,EAAkBC,IAA2B,IAAI;AAC/D,QAAMC,IAAQD,EAAK,SAAS,OACtBE,IAAQF,EAAK,SAAS;AAE5B,SAAO,CAACN,MAAgB;AAEtB,UAAMS,IAAMT,EAAO,WAAW,gBAAgB,mBAAmB,KAC5DA,EAAO,WAENU,IAAM,SAAS,cAAc,QAAQ;AAC3C,IAAAA,EAAI,OAAO,UACXA,EAAI,QAAQF,GACZE,EAAI,YAAY,uBAChBA,EAAI,cAAcH,GAElBG,EAAI,UAAU,YAAY;AACxB,YAAMC,IAAO,OAAO,sDAAsD;AAC1E,UAAI,CAACA,EAAM;AAEX,UAAIA,EAAK,YAAA,MAAkB,UAAU;AACnC,QAAAZ,EAAeC,GAAQ,eAAeW,CAAI,GAAG;AAC7C;AAAA,MACF;AAEA,YAAMC,IAAQ,SAAS,cAAc,OAAO;AAC5C,MAAAA,EAAM,OAAO,QACbA,EAAM,SAAS,WACfA,EAAM,WAAW,YAAY;AAC3B,cAAMC,IAAOD,EAAM,QAAQ,CAAC;AAC5B,YAAKC;AACL,cAAI;AACF,kBAAMC,IAAMR,EAAK,WAAW,MAAMA,EAAK,SAASO,CAAI,IAAI,IAAI,gBAAgBA,CAAI;AAChF,YAAAd,EAAeC,GAAQ,KAAKa,EAAK,IAAI,KAAKC,CAAG,GAAG;AAAA,UAClD,SAASV,GAAG;AACV,oBAAQ,MAAM,wBAAwBA,CAAC,GACvC,MAAM,sBAAsB;AAAA,UAC9B;AAAA,MACF,GACAQ,EAAM,MAAA;AAAA,IACR,GAEAH,GAAK,YAAYC,CAAG;AAAA,EACtB;AACF;"}
1
+ {"version":3,"file":"imagePicker.js","sources":["../../src/plugins/imagePicker.ts"],"sourcesContent":["// plugins/imagePicker.ts\n// Adds a toolbar button to insert images. Supports URL or file -> blob URL.\n// Optional uploader(file) => Promise<string> to persist and return a real URL.\n\nexport type ImagePickerOptions = {\n uploader?: (file: File) => Promise<string>;\n label?: string; // button label or emoji\n title?: string; // tooltip\n placeholder?: string; // default value for prompt\n promptMessage?: string; // custom prompt message\n};\n\nfunction insertAtCursor(editor: any, text: string) {\n const ta = editor.textarea as HTMLTextAreaElement;\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\nexport function imagePickerPlugin(opts: ImagePickerOptions = {}) {\n const label = opts.label ?? '🖼️';\n const title = opts.title ?? 'Insert image';\n\n return (editor: any) => {\n // Find or create a toolbar container\n const bar = editor.container?.querySelector?.('.marzipan-toolbar') as HTMLElement\n ?? editor.container;\n\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.title = title;\n btn.className = 'mz-btn mz-btn-image';\n btn.textContent = label;\n\n btn.onclick = async () => {\n const promptMessage = opts.promptMessage ?? 'Paste an image URL, or type \"upload\" to pick a file:';\n const initialValue = opts.placeholder ?? '';\n const mode = prompt(promptMessage, initialValue);\n if (!mode) return;\n\n const normalized = mode.trim();\n if (!normalized) return;\n\n if (normalized.toLowerCase() !== 'upload') {\n insertAtCursor(editor, `![alt text](${normalized})`);\n return;\n }\n\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = 'image/*';\n input.onchange = async () => {\n const file = input.files?.[0];\n if (!file) return;\n try {\n const url = opts.uploader ? await opts.uploader(file) : URL.createObjectURL(file);\n insertAtCursor(editor, `![${file.name}](${url})`);\n } catch (e) {\n console.error('Image upload failed:', e);\n alert('Image upload failed.');\n }\n };\n input.click();\n };\n\n bar?.appendChild(btn);\n };\n}\n"],"names":["insertAtCursor","editor","text","ta","s","e","imagePickerPlugin","opts","label","title","bar","btn","promptMessage","initialValue","mode","normalized","input","file","url"],"mappings":"AAYA,SAASA,EAAeC,GAAaC,GAAc;AACjD,QAAMC,IAAKF,EAAO,UACZG,IAAID,EAAG,kBAAkB,GAAGE,IAAIF,EAAG,gBAAgB;AACzD,EAAAA,EAAG,aAAaD,GAAME,GAAGC,GAAG,KAAK,GACjCJ,EAAO,gBAAA,GACPE,EAAG,MAAA;AACL;AAEO,SAASG,EAAkBC,IAA2B,IAAI;AAC/D,QAAMC,IAAQD,EAAK,SAAS,OACtBE,IAAQF,EAAK,SAAS;AAE5B,SAAO,CAACN,MAAgB;AAEtB,UAAMS,IAAMT,EAAO,WAAW,gBAAgB,mBAAmB,KAC5DA,EAAO,WAENU,IAAM,SAAS,cAAc,QAAQ;AAC3C,IAAAA,EAAI,OAAO,UACXA,EAAI,QAAQF,GACZE,EAAI,YAAY,uBAChBA,EAAI,cAAcH,GAElBG,EAAI,UAAU,YAAY;AACxB,YAAMC,IAAgBL,EAAK,iBAAiB,wDACtCM,IAAeN,EAAK,eAAe,IACnCO,IAAO,OAAOF,GAAeC,CAAY;AAC/C,UAAI,CAACC,EAAM;AAEX,YAAMC,IAAaD,EAAK,KAAA;AACxB,UAAI,CAACC,EAAY;AAEjB,UAAIA,EAAW,YAAA,MAAkB,UAAU;AACzC,QAAAf,EAAeC,GAAQ,eAAec,CAAU,GAAG;AACnD;AAAA,MACF;AAEA,YAAMC,IAAQ,SAAS,cAAc,OAAO;AAC5C,MAAAA,EAAM,OAAO,QACbA,EAAM,SAAS,WACfA,EAAM,WAAW,YAAY;AAC3B,cAAMC,IAAOD,EAAM,QAAQ,CAAC;AAC5B,YAAKC;AACL,cAAI;AACF,kBAAMC,IAAMX,EAAK,WAAW,MAAMA,EAAK,SAASU,CAAI,IAAI,IAAI,gBAAgBA,CAAI;AAChF,YAAAjB,EAAeC,GAAQ,KAAKgB,EAAK,IAAI,KAAKC,CAAG,GAAG;AAAA,UAClD,SAASb,GAAG;AACV,oBAAQ,MAAM,wBAAwBA,CAAC,GACvC,MAAM,sBAAsB;AAAA,UAC9B;AAAA,MACF,GACAW,EAAM,MAAA;AAAA,IACR,GAEAN,GAAK,YAAYC,CAAG;AAAA,EACtB;AACF;"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Marzipan Plugins
3
+ *
4
+ * Collection of plugins that extend Marzipan's functionality.
5
+ */
6
+ export { BlockHandlesPlugin } from './block-handles';
7
+ export type { BlockHandle, BlockHandlesConfig } from './block-handles';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,5 @@
1
+ import { BlockHandlesPlugin as e } from "./block-handles.js";
2
+ export {
3
+ e as BlockHandlesPlugin
4
+ };
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -4,7 +4,7 @@ function u(s) {
4
4
  const m = async (t) => {
5
5
  const n = t.querySelectorAll("pre code.language-mermaid");
6
6
  if (!n.length) return;
7
- const l = await import("../mermaid.core-DENutRS8.js").then((a) => a.bD);
7
+ const l = await import("../mermaid.core-BwjwqwU6.js").then((a) => a.bD);
8
8
  r ?? (r = l.default), r.initialize({
9
9
  startOnLoad: !1,
10
10
  theme: document.documentElement.classList.contains("dark") ? "dark" : "default",
@@ -3,12 +3,14 @@ type MzEditor = {
3
3
  textarea: HTMLTextAreaElement;
4
4
  updatePreview: () => void;
5
5
  };
6
- export declare function tableGridPlugin(opts?: {
6
+ export interface TableGridPluginOptions {
7
7
  maxRows?: number;
8
+ maxColumns?: number;
8
9
  maxCols?: number;
9
10
  label?: string;
10
11
  title?: string;
11
- }): (editor: MzEditor) => void;
12
+ }
13
+ export declare function tableGridPlugin(opts?: TableGridPluginOptions): (editor: MzEditor) => void;
12
14
  export declare const tableGridStyles = "\n.mz-pop {\n position: absolute; z-index: 9999; user-select: none;\n background: var(--mz-pop-bg, #111); color: var(--mz-pop-fg, #eee);\n border: 1px solid var(--mz-pop-bd, #333); border-radius: 10px;\n box-shadow: 0 8px 24px rgba(0,0,0,.35); padding: 10px;\n}\n.mz-tablegrid {\n display: grid; grid-template-rows: repeat(var(--r), 16px);\n grid-template-columns: repeat(var(--c), 16px);\n gap: 4px; margin: 4px;\n}\n.mz-tablegrid .mz-cell {\n width: 16px; height: 16px; border-radius: 4px;\n background: var(--mz-cell-bg, #1d1f23); border: 1px solid var(--mz-cell-bd, #2b2f36);\n}\n.mz-tablegrid .mz-cell.sel {\n background: var(--mz-cell-sel-bg, #2f6feb); border-color: var(--mz-cell-sel-bd, #3b82f6);\n}\n.mz-tablegrid-status { font-size: 12px; opacity: .8; padding: 6px 4px 2px; text-align: center; }\n.mz-btn { cursor: pointer; }\n";
13
15
  export {};
14
16
  //# sourceMappingURL=tableGridPlugin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tableGridPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/tableGridPlugin.ts"],"names":[],"mappings":"AAKA,KAAK,QAAQ,GAAG;IACd,SAAS,EAAE,WAAW,CAAC;IACvB,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAWF,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,IAMS,QAAQ,QAAQ,UAiFzB;AAGD,eAAO,MAAM,eAAe,o1BAqB3B,CAAC"}
1
+ {"version":3,"file":"tableGridPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/tableGridPlugin.ts"],"names":[],"mappings":"AAKA,KAAK,QAAQ,GAAG;IACd,SAAS,EAAE,WAAW,CAAC;IACvB,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAWD,wBAAgB,eAAe,CAAC,IAAI,GAAE,sBAA2B,IAMvD,QAAQ,QAAQ,UAiFzB;AAGD,eAAO,MAAM,eAAe,o1BAqB3B,CAAC"}
@@ -1,23 +1,23 @@
1
1
  import { b as h } from "../table-DMIy93NJ.js";
2
- function y(r, i) {
3
- const o = r.textarea, m = o.selectionStart ?? 0, p = o.selectionEnd ?? 0;
4
- o.setRangeText(i, m, p, "end"), r.updatePreview(), o.focus();
2
+ function C(n, i) {
3
+ const o = n.textarea, m = o.selectionStart ?? 0, p = o.selectionEnd ?? 0;
4
+ o.setRangeText(i, m, p, "end"), n.updatePreview(), o.focus();
5
5
  }
6
- function E(r) {
7
- const i = Math.max(1, r?.maxRows ?? 10), o = Math.max(1, r?.maxCols ?? 10), m = r?.label ?? "▦", p = r?.title ?? "Insert table";
6
+ function E(n = {}) {
7
+ const i = Math.max(1, n.maxRows ?? 10), o = Math.max(1, n.maxColumns ?? n.maxCols ?? 10), m = n.label ?? "▦", p = n.title ?? "Insert table";
8
8
  return (u) => {
9
- const z = u.container.querySelector(".marzipan-toolbar") ?? u.container, n = document.createElement("button");
10
- n.type = "button", n.className = "mz-btn mz-btn-tablegrid", n.title = p, n.textContent = m;
9
+ const z = u.container.querySelector(".marzipan-toolbar") ?? u.container, r = document.createElement("button");
10
+ r.type = "button", r.className = "mz-btn mz-btn-tablegrid", r.title = p, r.textContent = m;
11
11
  let e = null;
12
- function a() {
13
- e?.remove(), e = null, document.removeEventListener("click", g, !0), window.removeEventListener("resize", a), window.removeEventListener("scroll", a, !0);
12
+ function l() {
13
+ e?.remove(), e = null, document.removeEventListener("click", g, !0), window.removeEventListener("resize", l), window.removeEventListener("scroll", l, !0);
14
14
  }
15
15
  function g(t) {
16
- e && (t.target instanceof Node && (e.contains(t.target) || n.contains(t.target)) || a());
16
+ e && (t.target instanceof Node && (e.contains(t.target) || r.contains(t.target)) || l());
17
17
  }
18
18
  function v() {
19
19
  if (e) {
20
- a();
20
+ l();
21
21
  return;
22
22
  }
23
23
  e = document.createElement("div"), e.className = "mz-pop mz-tablegrid-pop";
@@ -25,27 +25,27 @@ function E(r) {
25
25
  t.className = "mz-tablegrid", t.style.setProperty("--r", String(i)), t.style.setProperty("--c", String(o));
26
26
  const d = document.createElement("div");
27
27
  d.className = "mz-tablegrid-status", d.textContent = "0 × 0";
28
- for (let l = 1; l <= i; l++)
28
+ for (let a = 1; a <= i; a++)
29
29
  for (let s = 1; s <= o; s++) {
30
30
  const c = document.createElement("div");
31
- c.className = "mz-cell", c.dataset.r = String(l), c.dataset.c = String(s), c.onmouseenter = () => {
32
- d.textContent = `${l} × ${s}`, t.querySelectorAll(".mz-cell").forEach((b) => {
31
+ c.className = "mz-cell", c.dataset.r = String(a), c.dataset.c = String(s), c.onmouseenter = () => {
32
+ d.textContent = `${a} × ${s}`, t.querySelectorAll(".mz-cell").forEach((b) => {
33
33
  const f = Number(b.dataset.r), w = Number(b.dataset.c);
34
- b.classList.toggle("sel", f <= l && w <= s);
34
+ b.classList.toggle("sel", f <= a && w <= s);
35
35
  });
36
36
  }, c.onclick = () => {
37
- y(u, `
38
- ${h(l, s)}
39
- `), a();
37
+ C(u, `
38
+ ${h(a, s)}
39
+ `), l();
40
40
  }, t.appendChild(c);
41
41
  }
42
42
  e.appendChild(t), e.appendChild(d), document.body.appendChild(e);
43
- const x = n.getBoundingClientRect();
43
+ const x = r.getBoundingClientRect();
44
44
  e.style.left = `${Math.round(window.scrollX + x.left)}px`, e.style.top = `${Math.round(window.scrollY + x.bottom + 6)}px`, setTimeout(() => {
45
- document.addEventListener("click", g, !0), window.addEventListener("resize", a), window.addEventListener("scroll", a, !0);
45
+ document.addEventListener("click", g, !0), window.addEventListener("resize", l), window.addEventListener("scroll", l, !0);
46
46
  }, 0);
47
47
  }
48
- n.onclick = v, z.appendChild(n);
48
+ r.onclick = v, z.appendChild(r);
49
49
  };
50
50
  }
51
51
  const k = `