@cubud/wen 1.0.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.
@@ -0,0 +1,1007 @@
1
+ // src/wen-core.js
2
+ import { Editor } from "https://esm.sh/@tiptap/core@2.2.4";
3
+ import StarterKit from "https://esm.sh/@tiptap/starter-kit@2.2.4";
4
+ import { Markdown } from "https://esm.sh/tiptap-markdown@0.8.9";
5
+ import Link from "https://esm.sh/@tiptap/extension-link@2.2.4";
6
+ import Image from "https://esm.sh/@tiptap/extension-image@2.2.4";
7
+ import CodeBlockLowlight from "https://esm.sh/@tiptap/extension-code-block-lowlight@2.2.4";
8
+ import { createLowlight, common } from "https://esm.sh/lowlight@3.1.0";
9
+ import Table from "https://esm.sh/@tiptap/extension-table@2.2.4";
10
+ import TableRow from "https://esm.sh/@tiptap/extension-table-row@2.2.4";
11
+ import TableHeader from "https://esm.sh/@tiptap/extension-table-header@2.2.4";
12
+ import TableCell from "https://esm.sh/@tiptap/extension-table-cell@2.2.4";
13
+ import TaskList from "https://esm.sh/@tiptap/extension-task-list@2.2.4";
14
+ import TaskItem from "https://esm.sh/@tiptap/extension-task-item@2.2.4";
15
+ import { Extension } from "https://esm.sh/@tiptap/core@2.2.4";
16
+ import { Plugin, PluginKey } from "https://esm.sh/@tiptap/pm@2.2.4/state";
17
+ import { Decoration, DecorationSet } from "https://esm.sh/@tiptap/pm@2.2.4/view";
18
+
19
+ // src/wen-utils.js
20
+ import DOMPurify from "https://esm.sh/dompurify@3.1.6";
21
+ function escapeHtml(value) {
22
+ return String(value ?? "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
23
+ }
24
+ function sanitizeHtml(dirty) {
25
+ return DOMPurify.sanitize(dirty);
26
+ }
27
+
28
+ // src/wen-core.js
29
+ var lowlight = createLowlight(common);
30
+ var GitHubAlerts = Extension.create({
31
+ name: "githubAlerts",
32
+ addProseMirrorPlugins() {
33
+ return [
34
+ new Plugin({
35
+ key: new PluginKey("githubAlerts"),
36
+ props: {
37
+ decorations(state) {
38
+ const decorations = [];
39
+ const { doc } = state;
40
+ doc.descendants((node, pos) => {
41
+ if (node.type.name === "blockquote") {
42
+ const firstChild = node.firstChild;
43
+ if (firstChild && firstChild.type.name === "paragraph") {
44
+ const text = firstChild.textContent;
45
+ const match = text.match(/^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]/i);
46
+ if (match) {
47
+ const type = match[1].toLowerCase();
48
+ decorations.push(
49
+ Decoration.node(pos, pos + node.nodeSize, {
50
+ class: `wen-github-alert wen-github-alert-${type}`
51
+ })
52
+ );
53
+ const startPos = pos + 2;
54
+ const endPos = startPos + match[0].length;
55
+ decorations.push(
56
+ Decoration.inline(startPos, endPos, {
57
+ class: `wen-github-alert-badge wen-github-alert-badge-${type}`
58
+ })
59
+ );
60
+ }
61
+ }
62
+ }
63
+ });
64
+ return DecorationSet.create(doc, decorations);
65
+ }
66
+ }
67
+ })
68
+ ];
69
+ }
70
+ });
71
+ var WenSmartBlocks = CodeBlockLowlight.extend({
72
+ addOptions() {
73
+ return { ...this.parent?.(), blockViews: {}, lowlight };
74
+ },
75
+ addNodeView() {
76
+ return ({ node, getPos, editor }) => {
77
+ const lang = node.attrs.language;
78
+ const ViewClass = this.options.blockViews[lang];
79
+ if (ViewClass) return new ViewClass(node, getPos, editor);
80
+ const dom = document.createElement("pre");
81
+ const contentDOM = document.createElement("code");
82
+ if (lang) contentDOM.className = `language-${lang}`;
83
+ dom.appendChild(contentDOM);
84
+ return { dom, contentDOM };
85
+ };
86
+ }
87
+ });
88
+ var WenEditor = class _WenEditor {
89
+ constructor(options) {
90
+ this.container = options.element;
91
+ this.blockViews = options.blockViews || {};
92
+ this.useFrontmatter = options.useFrontmatter !== false;
93
+ this.useNativeComponents = options.useNativeComponents !== false;
94
+ this.unsafe = options.unsafe === true;
95
+ this.wrapper = document.createElement("div");
96
+ this.wrapper.className = "wen-editor-wrapper";
97
+ this.toolbar = document.createElement("div");
98
+ this.toolbar.className = "wen-toolbar";
99
+ this.editorNode = document.createElement("div");
100
+ this.wrapper.appendChild(this.toolbar);
101
+ this.wrapper.appendChild(this.editorNode);
102
+ this.container.appendChild(this.wrapper);
103
+ const processedMarkdown = this.importMarkdown(options.initialMarkdown || "");
104
+ this.editor = new Editor({
105
+ element: this.editorNode,
106
+ extensions: [
107
+ StarterKit.configure({ codeBlock: false }),
108
+ WenSmartBlocks.configure({ blockViews: this.blockViews }),
109
+ GitHubAlerts,
110
+ Markdown,
111
+ Image,
112
+ Link.configure({ openOnClick: false }),
113
+ Table.configure({ resizable: true, HTMLAttributes: { class: "wen-table" } }),
114
+ TableRow,
115
+ TableHeader,
116
+ TableCell,
117
+ TaskList,
118
+ TaskItem.configure({ nested: true })
119
+ ],
120
+ content: processedMarkdown,
121
+ editorProps: { attributes: { class: "wen-editor-root" } },
122
+ onTransaction: () => this.updateToolbarStates()
123
+ });
124
+ this.editor.wenEditorInstance = this;
125
+ this.buildToolbar();
126
+ }
127
+ importMarkdown(md) {
128
+ let processed = md;
129
+ if (this.useFrontmatter) {
130
+ processed = processed.replace(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/, "```yaml\n$1\n```\n\n");
131
+ }
132
+ if (this.useNativeComponents) {
133
+ const tokens = processed.split(/(^```[\s\S]*?^```\r?\n?)/m);
134
+ for (let i = 0; i < tokens.length; i++) {
135
+ if (i % 2 === 0) {
136
+ let chunk = tokens[i];
137
+ const openCloseRegex = /^[ \t]*<([a-zA-Z0-9-]+)[^>]*>[\s\S]*?<\/\1>[ \t]*/gm;
138
+ chunk = chunk.replace(openCloseRegex, (match) => "\n```component\n" + match.trim() + "\n```\n");
139
+ const selfCloseRegex = /^[ \t]*<([a-zA-Z0-9-]+)[^>]*\/>[ \t]*/gm;
140
+ chunk = chunk.replace(selfCloseRegex, (match) => "\n```component\n" + match.trim() + "\n```\n");
141
+ tokens[i] = chunk;
142
+ }
143
+ }
144
+ processed = tokens.join("");
145
+ }
146
+ return processed;
147
+ }
148
+ loadContent(md) {
149
+ const processed = this.importMarkdown(md);
150
+ this.editor.commands.setContent(processed);
151
+ }
152
+ exportMarkdown() {
153
+ let md = this.editor.storage.markdown.getMarkdown();
154
+ if (this.useFrontmatter) {
155
+ md = md.replace(/^```yaml\r?\n([\s\S]*?)\r?\n```\r?\n?/, "---\n$1\n---\n");
156
+ }
157
+ if (this.useNativeComponents) {
158
+ const unwrapRegex = /```component\r?\n([ \t]*<(?:[a-zA-Z0-9-]+)[\s\S]*?>)[ \t]*\r?\n```\r?\n?/gm;
159
+ md = md.replace(unwrapRegex, "$1\n");
160
+ }
161
+ return md;
162
+ }
163
+ downloadMarkdown(filename = "wen-document.md") {
164
+ const md = this.exportMarkdown();
165
+ const blob = new Blob([md], { type: "text/markdown;charset=utf-8" });
166
+ const url = URL.createObjectURL(blob);
167
+ const link = document.createElement("a");
168
+ link.href = url;
169
+ link.download = filename;
170
+ document.body.appendChild(link);
171
+ link.click();
172
+ document.body.removeChild(link);
173
+ URL.revokeObjectURL(url);
174
+ }
175
+ buildToolbar() {
176
+ const createBtn = (label, action, isActiveCheck = null, isDisabledCheck = null) => {
177
+ const btn = document.createElement("button");
178
+ btn.className = "wen-toolbar-btn";
179
+ btn.innerHTML = label;
180
+ btn.addEventListener("click", () => {
181
+ action();
182
+ this.editor.view.focus();
183
+ });
184
+ if (isActiveCheck) btn.isActiveCheck = isActiveCheck;
185
+ if (isDisabledCheck) btn.isDisabledCheck = isDisabledCheck;
186
+ this.toolbar.appendChild(btn);
187
+ return btn;
188
+ };
189
+ const addDivider = () => {
190
+ const div = document.createElement("div");
191
+ div.className = "wen-toolbar-divider";
192
+ this.toolbar.appendChild(div);
193
+ };
194
+ createBtn("<b>B</b>", () => this.editor.chain().focus().toggleBold().run(), () => this.editor.isActive("bold"));
195
+ createBtn("<i>I</i>", () => this.editor.chain().focus().toggleItalic().run(), () => this.editor.isActive("italic"));
196
+ createBtn("<s>S</s>", () => this.editor.chain().focus().toggleStrike().run(), () => this.editor.isActive("strike"));
197
+ addDivider();
198
+ createBtn("\xB6 Text", () => this.editor.chain().focus().setParagraph().run(), () => this.editor.isActive("paragraph"));
199
+ createBtn("H1", () => this.editor.chain().focus().toggleHeading({ level: 1 }).run(), () => this.editor.isActive("heading", { level: 1 }));
200
+ createBtn("H2", () => this.editor.chain().focus().toggleHeading({ level: 2 }).run(), () => this.editor.isActive("heading", { level: 2 }));
201
+ createBtn("H3", () => this.editor.chain().focus().toggleHeading({ level: 3 }).run(), () => this.editor.isActive("heading", { level: 3 }));
202
+ createBtn("H4", () => this.editor.chain().focus().toggleHeading({ level: 4 }).run(), () => this.editor.isActive("heading", { level: 4 }));
203
+ addDivider();
204
+ createBtn("\u2022 List", () => this.editor.chain().focus().toggleBulletList().run(), () => this.editor.isActive("bulletList"));
205
+ createBtn("1. List", () => this.editor.chain().focus().toggleOrderedList().run(), () => this.editor.isActive("orderedList"));
206
+ createBtn("\u2611\uFE0F Task", () => this.editor.chain().focus().toggleTaskList().run(), () => this.editor.isActive("taskList"));
207
+ createBtn('" Quote', () => this.editor.chain().focus().toggleBlockquote().run(), () => this.editor.isActive("blockquote"));
208
+ createBtn("\u{1F4E2} Alert", () => {
209
+ this.editor.chain().focus().insertContent("<blockquote><p>[!NOTE]<br>Your message here...</p></blockquote>").run();
210
+ });
211
+ addDivider();
212
+ createBtn("\u{1F517} Link", () => {
213
+ const previousUrl = this.editor.getAttributes("link").href;
214
+ this.showModal("Insert Link", "URL", previousUrl, (url) => {
215
+ if (url === null) return;
216
+ if (url === "") this.editor.chain().focus().extendMarkRange("link").unsetLink().run();
217
+ else this.editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
218
+ });
219
+ }, () => this.editor.isActive("link"));
220
+ createBtn("\u{1F5BC}\uFE0F Image", () => {
221
+ const attrs = this.editor.getAttributes("image");
222
+ const previousUrl = attrs.src || "";
223
+ this.showModal(previousUrl ? "Edit Image" : "Insert Image", "Image URL", previousUrl, (url) => {
224
+ if (url) {
225
+ this.editor.chain().focus().setImage({ src: url }).run();
226
+ }
227
+ });
228
+ }, () => this.editor.isActive("image"));
229
+ addDivider();
230
+ createBtn("\u{1F4CA} Table", () => this.editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run());
231
+ createBtn("+ Row", () => this.editor.chain().focus().addRowAfter().run(), null, () => !this.editor.can().addRowAfter());
232
+ createBtn("+ Col", () => this.editor.chain().focus().addColumnAfter().run(), null, () => !this.editor.can().addColumnAfter());
233
+ createBtn("- Row", () => this.editor.chain().focus().deleteRow().run(), null, () => !this.editor.can().deleteRow());
234
+ createBtn("- Col", () => this.editor.chain().focus().deleteColumn().run(), null, () => !this.editor.can().deleteColumn());
235
+ createBtn("x Table", () => this.editor.chain().focus().deleteTable().run(), null, () => !this.editor.can().deleteTable());
236
+ addDivider();
237
+ createBtn("\u{1F4BE} Save", () => {
238
+ this.downloadMarkdown("wen-document.md");
239
+ });
240
+ }
241
+ updateToolbarStates() {
242
+ this.toolbar.querySelectorAll(".wen-toolbar-btn").forEach((btn) => {
243
+ if (btn.isActiveCheck) {
244
+ if (btn.isActiveCheck()) btn.classList.add("is-active");
245
+ else btn.classList.remove("is-active");
246
+ }
247
+ if (btn.isDisabledCheck) {
248
+ btn.disabled = btn.isDisabledCheck();
249
+ }
250
+ });
251
+ }
252
+ showModal(title, inputPlaceholder, initialValue, callback) {
253
+ const overlay = document.createElement("div");
254
+ overlay.className = "wen-modal-overlay";
255
+ overlay.innerHTML = `
256
+ <div class="wen-modal">
257
+ <strong>${escapeHtml(title)}</strong>
258
+ <input type="text" placeholder="${escapeHtml(inputPlaceholder)}" value="${escapeHtml(initialValue || "")}" />
259
+ <div class="wen-modal-actions">
260
+ <button class="wen-modal-cancel">Cancel</button>
261
+ <button class="wen-modal-submit">Save</button>
262
+ </div>
263
+ </div>
264
+ `;
265
+ document.body.appendChild(overlay);
266
+ const input = overlay.querySelector("input");
267
+ input.focus();
268
+ const close = (value) => {
269
+ document.body.removeChild(overlay);
270
+ callback(value);
271
+ };
272
+ overlay.querySelector(".wen-modal-cancel").addEventListener("click", () => close(null));
273
+ overlay.querySelector(".wen-modal-submit").addEventListener("click", () => close(input.value));
274
+ input.addEventListener("keydown", (e) => {
275
+ if (e.key === "Enter") close(input.value);
276
+ if (e.key === "Escape") close(null);
277
+ });
278
+ }
279
+ showRichModal(title, initialMarkdown, callback) {
280
+ const overlay = document.createElement("div");
281
+ overlay.className = "wen-rich-modal-overlay";
282
+ overlay.innerHTML = `
283
+ <div class="wen-rich-modal">
284
+ <div class="wen-rich-modal-header">
285
+ <strong>Editing Content: &lt;${escapeHtml(title)}&gt;</strong>
286
+ <div>
287
+ <button class="wen-modal-cancel">Cancel</button>
288
+ <button class="wen-modal-submit">Save Changes</button>
289
+ </div>
290
+ </div>
291
+ <div class="wen-rich-modal-body" id="modal-editor-container"></div>
292
+ </div>
293
+ `;
294
+ document.body.appendChild(overlay);
295
+ const modalEditor = new _WenEditor({
296
+ element: overlay.querySelector("#modal-editor-container"),
297
+ blockViews: this.blockViews,
298
+ // Inherit all our rich UI blocks
299
+ useFrontmatter: false,
300
+ // Sub-components don't need YAML frontmatter
301
+ useNativeComponents: this.useNativeComponents,
302
+ unsafe: this.unsafe,
303
+ // Inherit the trust setting into recursive editors
304
+ initialMarkdown
305
+ });
306
+ const close = (save) => {
307
+ const finalMd = save ? modalEditor.exportMarkdown() : null;
308
+ modalEditor.editor.destroy();
309
+ document.body.removeChild(overlay);
310
+ if (save) callback(finalMd);
311
+ };
312
+ overlay.querySelector(".wen-modal-cancel").addEventListener("click", () => close(false));
313
+ overlay.querySelector(".wen-modal-submit").addEventListener("click", () => close(true));
314
+ }
315
+ };
316
+
317
+ // src/wen-yaml.js
318
+ import yaml from "https://esm.sh/js-yaml@4.1.0";
319
+ var WenYamlView = class {
320
+ constructor(node, getPos, editor) {
321
+ this.node = node;
322
+ this.getPos = getPos;
323
+ this.editor = editor;
324
+ this.dom = document.createElement("div");
325
+ this.dom.className = "wen-yaml-block";
326
+ this.dom.contentEditable = "false";
327
+ this.dom.innerHTML = `
328
+ <div class="wen-yaml-header">
329
+ <span class="wen-yaml-title">\u{1F5C2}\uFE0F Properties</span>
330
+ <button class="wen-yaml-toggle-btn" data-state="visual">View Raw</button>
331
+ </div>
332
+ <div class="wen-yaml-visual-container">
333
+ <div class="wen-yaml-view-visual active"></div>
334
+ <div class="wen-yaml-fade"></div>
335
+ <button class="wen-yaml-expand-btn">\u25BC Show More</button>
336
+ </div>
337
+ <div class="wen-yaml-view-raw"><textarea class="wen-yaml-raw-input"></textarea></div>
338
+ <div class="wen-yaml-error-state hidden"><span class="wen-yaml-error-msg"></span></div>
339
+ `;
340
+ const toggleBtn = this.dom.querySelector(".wen-yaml-toggle-btn");
341
+ const visualContainer = this.dom.querySelector(".wen-yaml-visual-container");
342
+ const visualView = this.dom.querySelector(".wen-yaml-view-visual");
343
+ const expandBtn = this.dom.querySelector(".wen-yaml-expand-btn");
344
+ const rawView = this.dom.querySelector(".wen-yaml-view-raw");
345
+ const rawInput = this.dom.querySelector(".wen-yaml-raw-input");
346
+ const errorState = this.dom.querySelector(".wen-yaml-error-state");
347
+ const errorMsg = this.dom.querySelector(".wen-yaml-error-msg");
348
+ rawInput.value = this.node.textContent;
349
+ let isUpdatingFromUI = false;
350
+ let isExpanded = false;
351
+ const checkHeight = () => {
352
+ if (visualView.scrollHeight > 220) {
353
+ visualContainer.classList.add("needs-collapse");
354
+ visualContainer.classList.toggle("is-collapsed", !isExpanded);
355
+ } else {
356
+ visualContainer.classList.remove("needs-collapse", "is-collapsed");
357
+ }
358
+ };
359
+ expandBtn.addEventListener("click", () => {
360
+ isExpanded = !isExpanded;
361
+ visualContainer.classList.toggle("is-collapsed", !isExpanded);
362
+ expandBtn.innerText = isExpanded ? "\u25B2 Show Less" : "\u25BC Show More";
363
+ });
364
+ const updateTipTapState = (newRawYaml) => {
365
+ if (newRawYaml === this.node.textContent) return;
366
+ if (typeof this.getPos === "function") {
367
+ const tr = this.editor.state.tr;
368
+ const start = this.getPos() + 1;
369
+ const end = start + this.node.nodeSize - 2;
370
+ if (newRawYaml) tr.replaceWith(start, end, this.editor.schema.text(newRawYaml));
371
+ else tr.delete(start, end);
372
+ this.editor.view.dispatch(tr);
373
+ }
374
+ };
375
+ const castValue = (str) => {
376
+ if (str === "true") return true;
377
+ if (str === "false") return false;
378
+ if (str === "null") return null;
379
+ if (!isNaN(str) && str.trim() !== "") return Number(str);
380
+ return str;
381
+ };
382
+ const scrapeNode = (container) => {
383
+ if (container.classList.contains("wen-type-object")) {
384
+ const obj = {};
385
+ container.querySelectorAll(":scope > .wen-row-list > .wen-row").forEach((row) => {
386
+ const k = row.querySelector(":scope > .wen-row-top > .wen-key-wrap > .wen-key").value.trim();
387
+ const valContainer = row.querySelector(":scope > .wen-row-top > .wen-val-wrap > div") || row.querySelector(":scope > .wen-complex-wrap > div");
388
+ if (k && valContainer) obj[k] = scrapeNode(valContainer);
389
+ });
390
+ return obj;
391
+ }
392
+ if (container.classList.contains("wen-type-array")) {
393
+ const arr = [];
394
+ container.querySelectorAll(":scope > .wen-array-list > .wen-array-item").forEach((item) => {
395
+ const valContainer = item.querySelector(":scope > .wen-row-top > .wen-val-wrap > div") || item.querySelector(":scope > .wen-complex-wrap > div");
396
+ if (valContainer) arr.push(scrapeNode(valContainer));
397
+ });
398
+ return arr;
399
+ }
400
+ if (container.classList.contains("wen-type-primitive")) {
401
+ return castValue(container.querySelector(".wen-val").value);
402
+ }
403
+ return "";
404
+ };
405
+ const sync = () => {
406
+ const newData = scrapeNode(visualView.firstElementChild);
407
+ const newYaml = Object.keys(newData).length ? yaml.dump(newData) : "";
408
+ rawInput.value = newYaml;
409
+ isUpdatingFromUI = true;
410
+ updateTipTapState(newYaml);
411
+ isUpdatingFromUI = false;
412
+ checkHeight();
413
+ };
414
+ const buildUI = (data) => {
415
+ const createPrimitive = (val) => {
416
+ const wrapper = document.createElement("div");
417
+ wrapper.className = "wen-type-primitive";
418
+ wrapper.innerHTML = `
419
+ <textarea class="wen-val" rows="1" placeholder="Empty value...">${escapeHtml(val !== null && val !== void 0 ? val : "")}</textarea>
420
+ <div class="wen-type-controls">
421
+ <button class="wen-make-obj" title="Add Section">\u{1F4C2}</button>
422
+ <button class="wen-make-arr" title="Add List">\u{1F4CB}</button>
423
+ </div>
424
+ `;
425
+ const textarea = wrapper.querySelector(".wen-val");
426
+ const resize = () => {
427
+ textarea.style.height = "auto";
428
+ textarea.style.height = textarea.scrollHeight + "px";
429
+ };
430
+ textarea.addEventListener("input", () => {
431
+ resize();
432
+ sync();
433
+ });
434
+ setTimeout(resize, 0);
435
+ const handleComplexSwap = (newElement) => {
436
+ const row = wrapper.closest(".wen-row") || wrapper.closest(".wen-array-item");
437
+ if (row) {
438
+ row.classList.add("has-complex");
439
+ row.querySelector(".wen-complex-wrap").appendChild(newElement);
440
+ wrapper.remove();
441
+ } else {
442
+ wrapper.replaceWith(newElement);
443
+ }
444
+ sync();
445
+ };
446
+ wrapper.querySelector(".wen-make-obj").addEventListener("click", () => handleComplexSwap(createObject({ "": "" })));
447
+ wrapper.querySelector(".wen-make-arr").addEventListener("click", () => handleComplexSwap(createArray([""])));
448
+ return wrapper;
449
+ };
450
+ const createArray = (arr) => {
451
+ const wrapper = document.createElement("div");
452
+ wrapper.className = "wen-type-array";
453
+ const list = document.createElement("div");
454
+ list.className = "wen-array-list";
455
+ const addItem = (val) => {
456
+ const isComplex = typeof val === "object" && val !== null;
457
+ const item = document.createElement("div");
458
+ item.className = `wen-array-item ${isComplex ? "has-complex" : ""}`;
459
+ item.innerHTML = `
460
+ <div class="wen-row-top">
461
+ <span class="wen-bullet">-</span>
462
+ <div class="wen-val-wrap"></div>
463
+ <button class="wen-btn-delete" title="Remove Item">\xD7</button>
464
+ </div>
465
+ <div class="wen-complex-wrap"></div>
466
+ `;
467
+ const targetWrap = isComplex ? item.querySelector(".wen-complex-wrap") : item.querySelector(".wen-val-wrap");
468
+ targetWrap.appendChild(isComplex ? Array.isArray(val) ? createArray(val) : createObject(val) : createPrimitive(val));
469
+ item.querySelector(".wen-btn-delete").addEventListener("click", () => {
470
+ item.remove();
471
+ sync();
472
+ });
473
+ list.appendChild(item);
474
+ };
475
+ arr.forEach(addItem);
476
+ const addBtn = document.createElement("button");
477
+ addBtn.className = "wen-btn-add";
478
+ addBtn.innerText = "+ Add list item";
479
+ addBtn.addEventListener("click", () => {
480
+ addItem("");
481
+ sync();
482
+ });
483
+ wrapper.appendChild(list);
484
+ wrapper.appendChild(addBtn);
485
+ return wrapper;
486
+ };
487
+ const createObject = (obj) => {
488
+ const wrapper = document.createElement("div");
489
+ wrapper.className = "wen-type-object";
490
+ const rowList = document.createElement("div");
491
+ rowList.className = "wen-row-list";
492
+ const addRow = (k, v) => {
493
+ const isComplex = typeof v === "object" && v !== null;
494
+ const row = document.createElement("div");
495
+ row.className = `wen-row ${isComplex ? "has-complex" : ""}`;
496
+ row.innerHTML = `
497
+ <div class="wen-row-top">
498
+ <div class="wen-key-wrap"><input type="text" class="wen-key" value="${escapeHtml(k)}" placeholder="Label..." /><span class="wen-colon">:</span></div>
499
+ <div class="wen-val-wrap"></div>
500
+ <button class="wen-btn-delete" title="Remove Property">\xD7</button>
501
+ </div>
502
+ <div class="wen-complex-wrap"></div>
503
+ `;
504
+ const targetWrap = isComplex ? row.querySelector(".wen-complex-wrap") : row.querySelector(".wen-val-wrap");
505
+ targetWrap.appendChild(isComplex ? Array.isArray(v) ? createArray(v) : createObject(v) : createPrimitive(v));
506
+ row.querySelector(".wen-key").addEventListener("input", sync);
507
+ row.querySelector(".wen-btn-delete").addEventListener("click", () => {
508
+ row.remove();
509
+ sync();
510
+ });
511
+ rowList.appendChild(row);
512
+ };
513
+ Object.keys(obj).forEach((k) => addRow(k, obj[k]));
514
+ const addBtn = document.createElement("button");
515
+ addBtn.className = "wen-btn-add";
516
+ addBtn.innerText = "+ Add property";
517
+ addBtn.addEventListener("click", () => {
518
+ addRow("", "");
519
+ sync();
520
+ });
521
+ wrapper.appendChild(rowList);
522
+ wrapper.appendChild(addBtn);
523
+ return wrapper;
524
+ };
525
+ return createObject(data);
526
+ };
527
+ const renderVisualGrid = () => {
528
+ visualView.innerHTML = "";
529
+ let dataObj = {};
530
+ try {
531
+ dataObj = yaml.load(rawInput.value) || {};
532
+ errorState.classList.remove("active");
533
+ } catch (err) {
534
+ errorMsg.innerText = "YAML Error: " + err.message;
535
+ errorState.classList.add("active");
536
+ return;
537
+ }
538
+ if (typeof dataObj !== "object" || dataObj === null || Array.isArray(dataObj)) dataObj = { "": dataObj };
539
+ visualView.appendChild(buildUI(dataObj));
540
+ setTimeout(checkHeight, 0);
541
+ };
542
+ toggleBtn.addEventListener("click", () => {
543
+ const isVisual = toggleBtn.getAttribute("data-state") === "visual";
544
+ if (isVisual) {
545
+ visualContainer.style.display = "none";
546
+ rawView.classList.add("active");
547
+ toggleBtn.setAttribute("data-state", "raw");
548
+ toggleBtn.innerText = "View UI";
549
+ } else {
550
+ renderVisualGrid();
551
+ if (!errorState.classList.contains("active")) {
552
+ rawView.classList.remove("active");
553
+ visualContainer.style.display = "block";
554
+ toggleBtn.setAttribute("data-state", "visual");
555
+ toggleBtn.innerText = "View Raw";
556
+ }
557
+ }
558
+ });
559
+ rawInput.addEventListener("input", () => {
560
+ updateTipTapState(rawInput.value);
561
+ });
562
+ renderVisualGrid();
563
+ this.update = (updatedNode) => {
564
+ if (updatedNode.type.name !== "codeBlock" || updatedNode.attrs.language !== "yaml") return false;
565
+ if (this.node.textContent !== updatedNode.textContent) {
566
+ this.node = updatedNode;
567
+ rawInput.value = this.node.textContent;
568
+ if (!isUpdatingFromUI) {
569
+ renderVisualGrid();
570
+ }
571
+ }
572
+ return true;
573
+ };
574
+ this.stopEvent = () => true;
575
+ }
576
+ };
577
+
578
+ // src/wen-component.js
579
+ import { marked } from "https://esm.sh/marked@12.0.1";
580
+ var WenComponentView = class {
581
+ constructor(node, getPos, editor) {
582
+ this.node = node;
583
+ this.getPos = getPos;
584
+ this.editor = editor;
585
+ this.dom = document.createElement("div");
586
+ this.dom.className = "wen-component-block";
587
+ this.dom.contentEditable = "false";
588
+ this.dom.innerHTML = `
589
+ <div class="wen-component-header">
590
+ <span class="wen-component-title">\u{1F9E9} Component Wireframe</span>
591
+ <button class="wen-component-toggle-btn" data-state="visual">View Raw XML</button>
592
+ </div>
593
+ <div class="wen-component-view-visual active"></div>
594
+ <div class="wen-component-view-raw"><textarea class="wen-component-raw-input"></textarea></div>
595
+ `;
596
+ const toggleBtn = this.dom.querySelector(".wen-component-toggle-btn");
597
+ const visualView = this.dom.querySelector(".wen-component-view-visual");
598
+ const rawView = this.dom.querySelector(".wen-component-view-raw");
599
+ const rawInput = this.dom.querySelector(".wen-component-raw-input");
600
+ rawInput.value = this.node.textContent;
601
+ let isUpdatingFromUI = false;
602
+ const updateTipTapState = (newRawContent) => {
603
+ if (newRawContent === this.node.textContent) return;
604
+ if (typeof this.getPos === "function") {
605
+ const tr = this.editor.state.tr;
606
+ const start = this.getPos() + 1;
607
+ const end = start + this.node.nodeSize - 2;
608
+ if (newRawContent) tr.replaceWith(start, end, this.editor.schema.text(newRawContent));
609
+ else tr.delete(start, end);
610
+ this.editor.view.dispatch(tr);
611
+ }
612
+ };
613
+ const renderVisualWireframe = () => {
614
+ visualView.innerHTML = "";
615
+ const unsafe = this.editor.wenEditorInstance?.unsafe === true;
616
+ let rawCode = rawInput.value.trim();
617
+ rawCode = rawCode.replace(/^```[a-zA-Z0-9-]*\r?\n/, "").replace(/\r?\n```$/, "").trim();
618
+ const componentRegex = /^<([a-zA-Z0-9-]+)\s*([^>]*?)(?:(?:>([\s\S]*)<\/\1>)|(?:\/?>))$/;
619
+ const match = rawCode.match(componentRegex);
620
+ if (!match) {
621
+ visualView.innerHTML = `<div class="wen-component-error">Syntax Error: Cannot parse component structure.</div>`;
622
+ return;
623
+ }
624
+ let currentTagName = match[1];
625
+ let attributesStr = match[2].trim();
626
+ let currentInner = match[3];
627
+ let isSelfClosing = currentInner === void 0 && rawCode.endsWith("/>");
628
+ let currentAttributes = [];
629
+ const attrRegex = /([a-zA-Z0-9_]+)=(?:'([^']*)'|"([^"]*)"|\{([^}]*)\})/g;
630
+ let attrMatch;
631
+ while ((attrMatch = attrRegex.exec(attributesStr)) !== null) {
632
+ currentAttributes.push({ name: attrMatch[1], value: attrMatch[2] || attrMatch[3] || attrMatch[4] || "" });
633
+ }
634
+ const syncState = () => {
635
+ const attrsStr = currentAttributes.map((a) => `${a.name}="${a.value}"`).join(" ");
636
+ const space = attrsStr ? " " + attrsStr : "";
637
+ let newRaw = isSelfClosing ? `<${currentTagName}${space} />` : `<${currentTagName}${space}>
638
+ ${currentInner}
639
+ </${currentTagName}>`;
640
+ rawInput.value = newRaw;
641
+ isUpdatingFromUI = true;
642
+ updateTipTapState(newRaw);
643
+ isUpdatingFromUI = false;
644
+ };
645
+ const wireframe = document.createElement("div");
646
+ wireframe.className = "wen-wireframe";
647
+ const header = document.createElement("div");
648
+ header.className = "wen-wireframe-header";
649
+ header.innerHTML = `<strong>${currentTagName}</strong> ${isSelfClosing ? "<em>(Self-Closing)</em>" : ""}`;
650
+ wireframe.appendChild(header);
651
+ if (currentAttributes.length > 0) {
652
+ const propsContainer = document.createElement("div");
653
+ propsContainer.className = "wen-wireframe-props";
654
+ currentAttributes.forEach((attr, idx) => {
655
+ const prop = document.createElement("span");
656
+ prop.className = "wen-wireframe-prop";
657
+ prop.innerHTML = `<span class="wen-prop-key">${attr.name}</span> = `;
658
+ const input = document.createElement("input");
659
+ input.type = "text";
660
+ input.className = "wen-prop-val-input";
661
+ input.value = attr.value;
662
+ input.addEventListener("input", (e) => {
663
+ currentAttributes[idx].value = e.target.value;
664
+ syncState();
665
+ });
666
+ prop.appendChild(input);
667
+ propsContainer.appendChild(prop);
668
+ });
669
+ wireframe.appendChild(propsContainer);
670
+ }
671
+ if (!isSelfClosing) {
672
+ const contentContainer = document.createElement("div");
673
+ contentContainer.className = "wen-wireframe-content";
674
+ let previewHTML = "<em>Empty content</em>";
675
+ if ((currentInner || "").trim()) {
676
+ try {
677
+ const doc = new DOMParser().parseFromString(currentInner, "text/html");
678
+ const parseNode = (n) => {
679
+ if (n.nodeType === 1) {
680
+ const name = n.localName;
681
+ if (n.hasChildNodes() && n.childNodes.length > 0) {
682
+ return `<div class="wen-preview-tag">&lt;${name}&gt;</div>
683
+ ${parseChildren(n.childNodes)}
684
+ <div class="wen-preview-tag">&lt;/${name}&gt;</div>
685
+ `;
686
+ } else {
687
+ return `<div class="wen-preview-tag">&lt;${name}/&gt;</div>
688
+ `;
689
+ }
690
+ } else if (n.nodeType === 3) {
691
+ const text = n.textContent.replace(/^ +/gm, "");
692
+ if (!text.trim()) return "";
693
+ return `<div class="wen-preview-md">${marked.parse(text)}</div>`;
694
+ }
695
+ return "";
696
+ };
697
+ const parseChildren = (children) => {
698
+ let raw = "";
699
+ for (let i = 0; i < children.length; i++) {
700
+ raw += parseNode(children[i]);
701
+ }
702
+ return raw;
703
+ };
704
+ const parsed = parseChildren(doc.body.childNodes);
705
+ if (parsed.trim()) previewHTML = parsed;
706
+ } catch (e) {
707
+ previewHTML = "<em>Preview unavailable</em>";
708
+ }
709
+ }
710
+ const safePreview = unsafe ? previewHTML : sanitizeHtml(previewHTML);
711
+ contentContainer.innerHTML = `
712
+ <div class="wen-wireframe-preview-box">
713
+ <div class="wen-wireframe-preview">${safePreview}</div>
714
+ </div>
715
+ <button class="wen-wireframe-edit-btn">\u270F\uFE0F Edit in WYSIWYG</button>
716
+ `;
717
+ const outdent = (str) => {
718
+ if (!str) return "";
719
+ const lines = str.split("\n");
720
+ let minIndent = Infinity;
721
+ lines.forEach((line) => {
722
+ if (line.trim().length > 0) {
723
+ const match2 = line.match(/^[ \t]*/);
724
+ if (match2) {
725
+ const indent = match2[0].length;
726
+ if (indent < minIndent) minIndent = indent;
727
+ }
728
+ }
729
+ });
730
+ if (minIndent === Infinity || minIndent === 0) return str;
731
+ return lines.map((line) => line.trim().length === 0 ? line : line.substring(minIndent)).join("\n");
732
+ };
733
+ contentContainer.querySelector(".wen-wireframe-edit-btn").addEventListener("click", () => {
734
+ const cleanMarkdown = outdent(currentInner || "");
735
+ this.editor.wenEditorInstance.showRichModal(currentTagName, cleanMarkdown, (newMd) => {
736
+ currentInner = "\n" + newMd + "\n";
737
+ syncState();
738
+ renderVisualWireframe();
739
+ });
740
+ });
741
+ wireframe.appendChild(contentContainer);
742
+ }
743
+ visualView.appendChild(wireframe);
744
+ };
745
+ toggleBtn.addEventListener("click", () => {
746
+ const isVisual = toggleBtn.getAttribute("data-state") === "visual";
747
+ if (isVisual) {
748
+ visualView.classList.remove("active");
749
+ rawView.classList.add("active");
750
+ toggleBtn.setAttribute("data-state", "raw");
751
+ toggleBtn.innerText = "View UI";
752
+ } else {
753
+ renderVisualWireframe();
754
+ rawView.classList.remove("active");
755
+ visualView.classList.add("active");
756
+ toggleBtn.setAttribute("data-state", "visual");
757
+ toggleBtn.innerText = "View Raw XML";
758
+ }
759
+ });
760
+ rawInput.addEventListener("input", () => {
761
+ isUpdatingFromUI = true;
762
+ updateTipTapState(rawInput.value);
763
+ isUpdatingFromUI = false;
764
+ });
765
+ renderVisualWireframe();
766
+ this.update = (updatedNode) => {
767
+ if (updatedNode.type.name !== "codeBlock" || !["xml", "component", "jsx"].includes(updatedNode.attrs.language)) return false;
768
+ if (this.node.textContent !== updatedNode.textContent) {
769
+ this.node = updatedNode;
770
+ rawInput.value = this.node.textContent;
771
+ if (!isUpdatingFromUI) renderVisualWireframe();
772
+ }
773
+ return true;
774
+ };
775
+ this.stopEvent = () => true;
776
+ }
777
+ };
778
+
779
+ // src/wen-mermaid.js
780
+ import mermaid from "https://esm.sh/mermaid@10.9.1";
781
+ mermaid.initialize({
782
+ startOnLoad: false,
783
+ theme: "neutral",
784
+ securityLevel: "strict"
785
+ });
786
+ var WenMermaidView = class {
787
+ constructor(node, getPos, editor) {
788
+ this.node = node;
789
+ this.getPos = getPos;
790
+ this.editor = editor;
791
+ this.id = "mermaid-" + Math.random().toString(36).substr(2, 9);
792
+ this.dom = document.createElement("div");
793
+ this.dom.className = "wen-mermaid-block";
794
+ this.dom.contentEditable = "false";
795
+ this.dom.innerHTML = `
796
+ <div class="wen-mermaid-header">
797
+ <span class="wen-mermaid-title">\u{1F9DC}\u200D\u2640\uFE0F Mermaid Diagram</span>
798
+ <button class="wen-mermaid-toggle-btn" data-state="visual">Edit Chart</button>
799
+ </div>
800
+ <div class="wen-mermaid-view-visual active"></div>
801
+ <div class="wen-mermaid-view-raw"><textarea class="wen-mermaid-raw-input"></textarea></div>
802
+ `;
803
+ const toggleBtn = this.dom.querySelector(".wen-mermaid-toggle-btn");
804
+ const visualView = this.dom.querySelector(".wen-mermaid-view-visual");
805
+ const rawView = this.dom.querySelector(".wen-mermaid-view-raw");
806
+ const rawInput = this.dom.querySelector(".wen-mermaid-raw-input");
807
+ rawInput.value = this.node.textContent;
808
+ let isUpdatingFromUI = false;
809
+ const updateTipTapState = (newRawContent) => {
810
+ if (newRawContent === this.node.textContent) return;
811
+ if (typeof this.getPos === "function") {
812
+ const tr = this.editor.state.tr;
813
+ const start = this.getPos() + 1;
814
+ const end = start + this.node.nodeSize - 2;
815
+ if (newRawContent) tr.replaceWith(start, end, this.editor.schema.text(newRawContent));
816
+ else tr.delete(start, end);
817
+ this.editor.view.dispatch(tr);
818
+ }
819
+ };
820
+ const renderVisualDiagram = async () => {
821
+ visualView.innerHTML = "";
822
+ const code = rawInput.value.trim();
823
+ if (!code) {
824
+ visualView.innerHTML = `<div class="wen-mermaid-empty">Empty diagram</div>`;
825
+ return;
826
+ }
827
+ try {
828
+ const unsafe = this.editor.wenEditorInstance?.unsafe === true;
829
+ mermaid.initialize({ startOnLoad: false, theme: "neutral", securityLevel: unsafe ? "loose" : "strict" });
830
+ const { svg } = await mermaid.render(this.id, code);
831
+ visualView.innerHTML = svg;
832
+ } catch (err) {
833
+ visualView.innerHTML = `<div class="wen-mermaid-error"><strong>Syntax Error:</strong><br/>${escapeHtml(err.message)}</div>`;
834
+ const garbage = document.getElementById(this.id);
835
+ if (garbage) garbage.remove();
836
+ }
837
+ };
838
+ toggleBtn.addEventListener("click", () => {
839
+ const isVisual = toggleBtn.getAttribute("data-state") === "visual";
840
+ if (isVisual) {
841
+ visualView.classList.remove("active");
842
+ rawView.classList.add("active");
843
+ toggleBtn.setAttribute("data-state", "raw");
844
+ toggleBtn.innerText = "View Chart";
845
+ } else {
846
+ renderVisualDiagram();
847
+ rawView.classList.remove("active");
848
+ visualView.classList.add("active");
849
+ toggleBtn.setAttribute("data-state", "visual");
850
+ toggleBtn.innerText = "Edit Chart";
851
+ }
852
+ });
853
+ rawInput.addEventListener("input", () => {
854
+ isUpdatingFromUI = true;
855
+ updateTipTapState(rawInput.value);
856
+ isUpdatingFromUI = false;
857
+ });
858
+ renderVisualDiagram();
859
+ this.update = (updatedNode) => {
860
+ if (updatedNode.type.name !== "codeBlock" || updatedNode.attrs.language !== "mermaid") return false;
861
+ if (this.node.textContent !== updatedNode.textContent) {
862
+ this.node = updatedNode;
863
+ rawInput.value = this.node.textContent;
864
+ if (!isUpdatingFromUI) {
865
+ renderVisualDiagram();
866
+ }
867
+ }
868
+ return true;
869
+ };
870
+ this.stopEvent = () => true;
871
+ }
872
+ };
873
+
874
+ // src/wen-chart.js
875
+ import frappe from "https://esm.sh/frappe-charts@1.6.2";
876
+ var Chart = frappe.Chart || frappe;
877
+ var WenChartView = class {
878
+ constructor(node, getPos, editor) {
879
+ this.node = node;
880
+ this.getPos = getPos;
881
+ this.editor = editor;
882
+ this.dom = document.createElement("div");
883
+ this.dom.className = "wen-chart-block";
884
+ this.dom.contentEditable = "false";
885
+ this.dom.innerHTML = `
886
+ <div class="wen-chart-header">
887
+ <span class="wen-chart-title">\u{1F4CA} Frappe Chart</span>
888
+ <button class="wen-chart-toggle-btn" data-state="visual">Edit Data</button>
889
+ </div>
890
+ <div class="wen-chart-view-visual active">
891
+ <div class="frappe-container"></div>
892
+ </div>
893
+ <div class="wen-chart-view-raw"><textarea class="wen-chart-raw-input"></textarea></div>
894
+ `;
895
+ const toggleBtn = this.dom.querySelector(".wen-chart-toggle-btn");
896
+ const visualView = this.dom.querySelector(".wen-chart-view-visual");
897
+ const chartContainer = this.dom.querySelector(".frappe-container");
898
+ const rawView = this.dom.querySelector(".wen-chart-view-raw");
899
+ const rawInput = this.dom.querySelector(".wen-chart-raw-input");
900
+ rawInput.value = this.node.textContent;
901
+ let isUpdatingFromUI = false;
902
+ let chartInstance = null;
903
+ const updateTipTapState = (newRawContent) => {
904
+ if (newRawContent === this.node.textContent) return;
905
+ if (typeof this.getPos === "function") {
906
+ const tr = this.editor.state.tr;
907
+ const start = this.getPos() + 1;
908
+ const end = start + this.node.nodeSize - 2;
909
+ if (newRawContent) tr.replaceWith(start, end, this.editor.schema.text(newRawContent));
910
+ else tr.delete(start, end);
911
+ this.editor.view.dispatch(tr);
912
+ }
913
+ };
914
+ const parseMicroFormat = (text) => {
915
+ const lines = text.trim().split("\n");
916
+ let type = "bar";
917
+ let title = "";
918
+ let dataStartIndex = 0;
919
+ for (let i = 0; i < lines.length; i++) {
920
+ const line = lines[i].trim();
921
+ if (line === "---") {
922
+ dataStartIndex = i + 1;
923
+ break;
924
+ }
925
+ if (line.toLowerCase().startsWith("type:")) type = line.split(":")[1].trim();
926
+ if (line.toLowerCase().startsWith("title:")) title = line.split(":")[1].trim();
927
+ }
928
+ if (dataStartIndex === 0) dataStartIndex = 0;
929
+ const headers = lines[dataStartIndex].split(",").map((s) => s.trim());
930
+ const labels = [];
931
+ const datasets = headers.slice(1).map((name) => ({ name, values: [] }));
932
+ for (let i = dataStartIndex + 1; i < lines.length; i++) {
933
+ if (!lines[i].trim()) continue;
934
+ const cols = lines[i].split(",").map((s) => s.trim());
935
+ labels.push(cols[0]);
936
+ cols.slice(1).forEach((val, idx) => {
937
+ if (datasets[idx]) datasets[idx].values.push(Number(val) || 0);
938
+ });
939
+ }
940
+ return { title, type, data: { labels, datasets } };
941
+ };
942
+ const renderChart = () => {
943
+ try {
944
+ const config = parseMicroFormat(rawInput.value);
945
+ chartContainer.innerHTML = "";
946
+ chartInstance = new Chart(chartContainer, {
947
+ title: config.title,
948
+ data: config.data,
949
+ type: config.type,
950
+ height: 250,
951
+ colors: ["#8250df", "#0d9488", "#cf222e", "#bf8700"]
952
+ // Default categorical palette
953
+ });
954
+ let errorMsg = visualView.querySelector(".wen-chart-error");
955
+ if (errorMsg) errorMsg.remove();
956
+ chartContainer.style.display = "block";
957
+ } catch (err) {
958
+ chartContainer.style.display = "none";
959
+ let errorMsg = visualView.querySelector(".wen-chart-error");
960
+ if (!errorMsg) {
961
+ errorMsg = document.createElement("div");
962
+ errorMsg.className = "wen-chart-error";
963
+ visualView.appendChild(errorMsg);
964
+ }
965
+ errorMsg.innerHTML = `<strong>Data Parsing Error:</strong><br/>Ensure you have a header row and valid numbers.`;
966
+ }
967
+ };
968
+ toggleBtn.addEventListener("click", () => {
969
+ const isVisual = toggleBtn.getAttribute("data-state") === "visual";
970
+ if (isVisual) {
971
+ visualView.classList.remove("active");
972
+ rawView.classList.add("active");
973
+ toggleBtn.setAttribute("data-state", "raw");
974
+ toggleBtn.innerText = "View Chart";
975
+ } else {
976
+ renderChart();
977
+ rawView.classList.remove("active");
978
+ visualView.classList.add("active");
979
+ toggleBtn.setAttribute("data-state", "visual");
980
+ toggleBtn.innerText = "Edit Data";
981
+ }
982
+ });
983
+ rawInput.addEventListener("input", () => {
984
+ isUpdatingFromUI = true;
985
+ updateTipTapState(rawInput.value);
986
+ isUpdatingFromUI = false;
987
+ });
988
+ renderChart();
989
+ this.update = (updatedNode) => {
990
+ if (updatedNode.type.name !== "codeBlock" || updatedNode.attrs.language !== "chart") return false;
991
+ if (this.node.textContent !== updatedNode.textContent) {
992
+ this.node = updatedNode;
993
+ rawInput.value = this.node.textContent;
994
+ if (!isUpdatingFromUI) renderChart();
995
+ }
996
+ return true;
997
+ };
998
+ this.stopEvent = () => true;
999
+ }
1000
+ };
1001
+ export {
1002
+ WenChartView,
1003
+ WenComponentView,
1004
+ WenEditor,
1005
+ WenMermaidView,
1006
+ WenYamlView
1007
+ };