@duskmoon-dev/el-markdown-input 0.8.1 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1189 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __returnValue = (v) => v;
3
+ function __exportSetter(name, newValue) {
4
+ this[name] = __returnValue.bind(null, newValue);
5
+ }
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: true,
11
+ configurable: true,
12
+ set: __exportSetter.bind(all, name)
13
+ });
14
+ };
15
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
16
+
17
+ // src/css.ts
18
+ import { css } from "@duskmoon-dev/el-base";
19
+ var elementStyles;
20
+ var init_css = __esm(() => {
21
+ elementStyles = css`
22
+ /* ── Custom property defaults with design-system fallbacks ─────────── */
23
+ :host {
24
+ --md-border: var(--color-outline, #d0d7de);
25
+ --md-border-focus: var(--color-primary, #0969da);
26
+ --md-bg: var(--color-surface, #ffffff);
27
+ --md-bg-toolbar: var(--color-surface-variant, #f6f8fa);
28
+ --md-bg-hover: var(--color-surface-container, #eaeef2);
29
+ --md-text: var(--color-on-surface, #1f2328);
30
+ --md-text-muted: var(--color-on-surface-variant, #656d76);
31
+ --md-accent: var(--color-primary, #0969da);
32
+ --md-radius: 6px;
33
+ --md-upload-bar: var(--color-primary, #0969da);
34
+ --md-color-warning: var(--color-warning, #d97706);
35
+ --md-color-error: var(--color-error, #dc2626);
36
+
37
+ display: block;
38
+ position: relative; /* establishes containing block for the ac-dropdown portal */
39
+ font-family: inherit;
40
+ }
41
+
42
+ :host([hidden]) {
43
+ display: none !important;
44
+ }
45
+
46
+ /* Dark-mode overrides (activated by [dark] attribute on host) */
47
+ :host([dark]) {
48
+ --md-border: #30363d;
49
+ --md-border-focus: #58a6ff;
50
+ --md-bg: #0d1117;
51
+ --md-bg-toolbar: #161b22;
52
+ --md-bg-hover: #21262d;
53
+ --md-text: #e6edf3;
54
+ --md-text-muted: #8b949e;
55
+ --md-accent: #58a6ff;
56
+ --md-upload-bar: #58a6ff;
57
+ --md-color-warning: #f59e0b;
58
+ --md-color-error: #fca5a5;
59
+ }
60
+
61
+ /* ── Editor chrome ──────────────────────────────────────────────────── */
62
+ .editor {
63
+ display: flex;
64
+ flex-direction: column;
65
+ border: 1px solid var(--md-border);
66
+ border-radius: var(--md-radius);
67
+ background: var(--md-bg);
68
+ color: var(--md-text);
69
+ overflow: hidden;
70
+ }
71
+
72
+ .editor:focus-within {
73
+ border-color: var(--md-border-focus);
74
+ outline: 2px solid var(--md-border-focus);
75
+ outline-offset: -1px;
76
+ }
77
+
78
+ /* ── Toolbar / tab bar ──────────────────────────────────────────────── */
79
+ .toolbar {
80
+ display: flex;
81
+ gap: 0;
82
+ background: var(--md-bg-toolbar);
83
+ border-bottom: 1px solid var(--md-border);
84
+ padding: 0 0.5rem;
85
+ }
86
+
87
+ .tab-btn {
88
+ padding: 0.5rem 0.875rem;
89
+ border: none;
90
+ background: transparent;
91
+ color: var(--md-text-muted);
92
+ font-family: inherit;
93
+ font-size: 0.875rem;
94
+ font-weight: 500;
95
+ cursor: pointer;
96
+ border-bottom: 2px solid transparent;
97
+ margin-bottom: -1px;
98
+ transition:
99
+ color 150ms ease,
100
+ border-color 150ms ease;
101
+ }
102
+
103
+ .tab-btn:hover {
104
+ color: var(--md-text);
105
+ background: var(--md-bg-hover);
106
+ }
107
+
108
+ .tab-btn[aria-selected='true'] {
109
+ color: var(--md-text);
110
+ border-bottom-color: var(--md-accent);
111
+ }
112
+
113
+ .tab-btn:focus-visible {
114
+ outline: 2px solid var(--md-accent);
115
+ outline-offset: -2px;
116
+ border-radius: 3px;
117
+ }
118
+
119
+ /* ── Write area (backdrop + textarea overlay) ───────────────────────── */
120
+ .write-area {
121
+ position: relative;
122
+ min-height: 12rem;
123
+ flex: 1;
124
+ }
125
+
126
+ /*
127
+ * Backdrop: renders syntax-highlighted HTML behind the transparent textarea.
128
+ * Must share IDENTICAL font metrics with the textarea to stay pixel-aligned.
129
+ */
130
+ .backdrop {
131
+ position: absolute;
132
+ inset: 0;
133
+ pointer-events: none;
134
+ /*
135
+ * Use overflow: auto (not overflow: hidden) so the backdrop reserves
136
+ * the same scrollbar gutter as the textarea when content overflows.
137
+ * Without this, the textarea scrollbar narrows its text area but the
138
+ * backdrop stays full-width — lines wrap at different points — causing
139
+ * the cursor to appear misaligned with the highlighted text.
140
+ */
141
+ overflow: auto;
142
+ scrollbar-width: none; /* Firefox */
143
+ border: none;
144
+ background: transparent;
145
+ /*
146
+ * Do NOT put white-space: pre-wrap here. The backdrop div contains a
147
+ * backdrop-content child, and the HTML template has whitespace text
148
+ * nodes (newline + indent) between them. With pre-wrap on the parent
149
+ * those text nodes render as a visible leading newline, shifting all
150
+ * content down by one line and misaligning the cursor vertically.
151
+ * pre-wrap lives on .backdrop-content instead.
152
+ */
153
+
154
+ font-family: ui-monospace, 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
155
+ font-size: 0.875rem;
156
+ line-height: 1.6;
157
+ padding: 0.75rem;
158
+ color: var(--md-text);
159
+ }
160
+
161
+ .backdrop::-webkit-scrollbar {
162
+ display: none; /* Chrome / Safari */
163
+ }
164
+
165
+ .backdrop-content {
166
+ display: block;
167
+ white-space: pre-wrap;
168
+ word-wrap: break-word;
169
+ overflow-wrap: break-word;
170
+ /* Prism token colours are injected via a separate <style id="prism-theme"> */
171
+ }
172
+
173
+ textarea {
174
+ position: relative;
175
+ display: block;
176
+ width: 100%;
177
+ min-height: 12rem;
178
+ border: none;
179
+ outline: none;
180
+ resize: vertical;
181
+ background: transparent;
182
+ color: transparent;
183
+ caret-color: var(--md-text);
184
+ box-sizing: border-box;
185
+
186
+ /* MUST match .backdrop exactly */
187
+ font-family: ui-monospace, 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
188
+ font-size: 0.875rem;
189
+ line-height: 1.6;
190
+ padding: 0.75rem;
191
+ white-space: pre-wrap;
192
+ word-wrap: break-word;
193
+ overflow-wrap: break-word;
194
+ }
195
+
196
+ textarea::placeholder {
197
+ color: var(--md-text-muted);
198
+ }
199
+
200
+ textarea:disabled {
201
+ cursor: not-allowed;
202
+ opacity: 0.6;
203
+ }
204
+
205
+ /* ── Preview panel ──────────────────────────────────────────────────── */
206
+ .preview-body {
207
+ padding: 0.75rem;
208
+ min-height: 12rem;
209
+ overflow-y: auto;
210
+ color: var(--md-text);
211
+ /* .markdown-body styles come from @duskmoon-dev/core via the element */
212
+ }
213
+
214
+ /* ── Status bar ─────────────────────────────────────────────────────── */
215
+ .status-bar {
216
+ display: flex;
217
+ align-items: center;
218
+ justify-content: space-between;
219
+ padding: 0.375rem 0.75rem;
220
+ border-top: 1px solid var(--md-border);
221
+ background: var(--md-bg-toolbar);
222
+ font-size: 0.75rem;
223
+ color: var(--md-text-muted);
224
+ gap: 0.5rem;
225
+ }
226
+
227
+ .attach-btn {
228
+ display: inline-flex;
229
+ align-items: center;
230
+ gap: 0.25rem;
231
+ padding: 0.25rem 0.5rem;
232
+ border: none;
233
+ background: transparent;
234
+ color: var(--md-text-muted);
235
+ font-family: inherit;
236
+ font-size: 0.75rem;
237
+ cursor: pointer;
238
+ border-radius: 4px;
239
+ transition:
240
+ color 150ms ease,
241
+ background 150ms ease;
242
+ }
243
+
244
+ .attach-btn:hover {
245
+ color: var(--md-text);
246
+ background: var(--md-bg-hover);
247
+ }
248
+
249
+ .attach-btn:focus-visible {
250
+ outline: 2px solid var(--md-accent);
251
+ outline-offset: 1px;
252
+ }
253
+
254
+ .status-bar-count {
255
+ margin-left: auto;
256
+ white-space: nowrap;
257
+ }
258
+
259
+ .status-bar-count .warning {
260
+ color: var(--md-color-warning);
261
+ }
262
+
263
+ .status-bar-count .error {
264
+ color: var(--md-color-error);
265
+ }
266
+
267
+ .file-input {
268
+ display: none;
269
+ }
270
+
271
+ /* ── Autocomplete dropdown ──────────────────────────────────────────── */
272
+ /*
273
+ * The dropdown is a direct child of :host (outside .editor) so it is not
274
+ * clipped by .editor's overflow: hidden. :host has position: relative which
275
+ * establishes the containing block for this absolute positioning.
276
+ */
277
+ .ac-dropdown {
278
+ position: absolute;
279
+ z-index: 100;
280
+ left: 0.75rem;
281
+ /* Align to bottom of the editor chrome; the editor fills 100% of :host height */
282
+ bottom: calc(var(--md-status-bar-height, 2rem) + 4px);
283
+ min-width: 16rem;
284
+ max-width: 28rem;
285
+ max-height: 16rem;
286
+ overflow-y: auto;
287
+ margin: 0;
288
+ padding: 0.25rem 0;
289
+ list-style: none;
290
+ background: var(--md-bg);
291
+ border: 1px solid var(--md-border);
292
+ border-radius: var(--md-radius);
293
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
294
+ }
295
+
296
+ .ac-item {
297
+ display: flex;
298
+ flex-direction: column;
299
+ padding: 0.5rem 0.75rem;
300
+ cursor: pointer;
301
+ transition: background 100ms ease;
302
+ }
303
+
304
+ .ac-item:hover,
305
+ .ac-item[aria-selected='true'] {
306
+ background: var(--md-bg-hover);
307
+ }
308
+
309
+ .ac-item-label {
310
+ font-size: 0.875rem;
311
+ color: var(--md-text);
312
+ font-weight: 500;
313
+ }
314
+
315
+ .ac-item-subtitle {
316
+ font-size: 0.75rem;
317
+ color: var(--md-text-muted);
318
+ margin-top: 1px;
319
+ }
320
+
321
+ /* ── Upload progress rows ───────────────────────────────────────────── */
322
+ .upload-list {
323
+ display: flex;
324
+ flex-direction: column;
325
+ gap: 0;
326
+ }
327
+
328
+ .upload-row {
329
+ display: flex;
330
+ align-items: center;
331
+ gap: 0.5rem;
332
+ padding: 0.375rem 0.75rem;
333
+ border-top: 1px solid var(--md-border);
334
+ background: var(--md-bg-toolbar);
335
+ font-size: 0.75rem;
336
+ color: var(--md-text-muted);
337
+ }
338
+
339
+ .upload-filename {
340
+ flex: 1;
341
+ overflow: hidden;
342
+ text-overflow: ellipsis;
343
+ white-space: nowrap;
344
+ }
345
+
346
+ .upload-bar-track {
347
+ width: 6rem;
348
+ height: 3px;
349
+ background: var(--md-border);
350
+ border-radius: 2px;
351
+ overflow: hidden;
352
+ flex-shrink: 0;
353
+ }
354
+
355
+ .upload-bar {
356
+ height: 100%;
357
+ background: var(--md-upload-bar);
358
+ border-radius: 2px;
359
+ transition: width 150ms ease;
360
+ }
361
+
362
+ .upload-error-row {
363
+ display: flex;
364
+ align-items: center;
365
+ gap: 0.5rem;
366
+ padding: 0.375rem 0.75rem;
367
+ border-top: 1px solid var(--md-border);
368
+ background: oklch(97% 0.02 25);
369
+ color: var(--md-color-error);
370
+ font-size: 0.75rem;
371
+ }
372
+
373
+ :host([dark]) .upload-error-row {
374
+ background: oklch(20% 0.03 25);
375
+ }
376
+
377
+ .upload-error-msg {
378
+ flex: 1;
379
+ overflow: hidden;
380
+ text-overflow: ellipsis;
381
+ white-space: nowrap;
382
+ }
383
+ `;
384
+ });
385
+
386
+ // src/highlight.ts
387
+ function _loadScript(src) {
388
+ return new Promise((resolve) => {
389
+ const script = document.createElement("script");
390
+ script.src = src;
391
+ script.onload = () => resolve();
392
+ script.onerror = () => resolve();
393
+ document.head.appendChild(script);
394
+ });
395
+ }
396
+ function ensurePrism() {
397
+ if (window.Prism)
398
+ return Promise.resolve();
399
+ if (_prismReady)
400
+ return _prismReady;
401
+ _prismReady = _loadScript(PRISM_CORE_URL).then(() => {
402
+ if (!window.Prism)
403
+ return;
404
+ window.Prism.manual = true;
405
+ return _loadScript(PRISM_AUTOLOADER_URL).then(() => {
406
+ if (window.Prism?.plugins?.autoloader) {
407
+ window.Prism.plugins.autoloader.languages_path = `${PRISM_BASE}/components/`;
408
+ }
409
+ });
410
+ });
411
+ return _prismReady;
412
+ }
413
+ function escapeHtml(text) {
414
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
415
+ }
416
+ function highlightMarkdown(text) {
417
+ const escaped = escapeHtml(text);
418
+ if (!window.Prism?.languages?.markdown) {
419
+ return escaped + " ";
420
+ }
421
+ try {
422
+ const highlighted = window.Prism.highlight(text, window.Prism.languages.markdown, "markdown");
423
+ return highlighted + " ";
424
+ } catch {
425
+ return escaped + " ";
426
+ }
427
+ }
428
+ function applyPrismTheme(shadowRoot, dark) {
429
+ const themeUrl = dark ? PRISM_THEME_DARK_URL : PRISM_THEME_LIGHT_URL;
430
+ let styleEl = shadowRoot.getElementById("prism-theme");
431
+ if (!styleEl) {
432
+ styleEl = document.createElement("style");
433
+ styleEl.id = "prism-theme";
434
+ shadowRoot.appendChild(styleEl);
435
+ }
436
+ const expected = `@import url("${themeUrl}");`;
437
+ if (styleEl.textContent !== expected) {
438
+ styleEl.textContent = expected;
439
+ }
440
+ }
441
+ var PRISM_BASE = "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0", PRISM_CORE_URL, PRISM_AUTOLOADER_URL, PRISM_THEME_DARK_URL, PRISM_THEME_LIGHT_URL, _prismReady = null;
442
+ var init_highlight = __esm(() => {
443
+ PRISM_CORE_URL = `${PRISM_BASE}/prism.min.js`;
444
+ PRISM_AUTOLOADER_URL = `${PRISM_BASE}/plugins/autoloader/prism-autoloader.min.js`;
445
+ PRISM_THEME_DARK_URL = `${PRISM_BASE}/themes/prism-tomorrow.min.css`;
446
+ PRISM_THEME_LIGHT_URL = `${PRISM_BASE}/themes/prism-coy.min.css`;
447
+ });
448
+
449
+ // src/upload.ts
450
+ function isAcceptedType(file) {
451
+ const type = file.type.toLowerCase();
452
+ if (ACCEPTED_MIME_PREFIXES.some((p) => type.startsWith(p)))
453
+ return true;
454
+ if (ACCEPTED_MIME_EXACT.includes(type))
455
+ return true;
456
+ const name = file.name.toLowerCase();
457
+ if (ACCEPTED_EXTENSIONS.some((ext) => name.endsWith(ext)))
458
+ return true;
459
+ return false;
460
+ }
461
+ function fileToMarkdown(file, url) {
462
+ if (file.type.startsWith("image/")) {
463
+ return `![${file.name}](${url})`;
464
+ }
465
+ return `[${file.name}](${url})`;
466
+ }
467
+ function uploadFile(file, uploadUrl, onProgress) {
468
+ return new Promise((resolve, reject) => {
469
+ const xhr = new XMLHttpRequest;
470
+ const body = new FormData;
471
+ body.append("file", file);
472
+ xhr.upload.addEventListener("progress", (e) => {
473
+ if (e.lengthComputable) {
474
+ onProgress(Math.round(e.loaded / e.total * 100));
475
+ }
476
+ });
477
+ xhr.addEventListener("load", () => {
478
+ if (xhr.status >= 200 && xhr.status < 300) {
479
+ try {
480
+ const data = JSON.parse(xhr.responseText);
481
+ if (data.url) {
482
+ resolve(data.url);
483
+ } else {
484
+ reject("Upload response missing url field");
485
+ }
486
+ } catch {
487
+ reject("Upload response is not valid JSON");
488
+ }
489
+ } else {
490
+ reject(`Upload failed with status ${xhr.status}`);
491
+ }
492
+ });
493
+ xhr.addEventListener("error", () => reject("Network error during upload"));
494
+ xhr.addEventListener("abort", () => reject("Upload aborted"));
495
+ xhr.open("POST", uploadUrl);
496
+ xhr.send(body);
497
+ });
498
+ }
499
+ var ACCEPTED_MIME_PREFIXES, ACCEPTED_MIME_EXACT, ACCEPTED_EXTENSIONS;
500
+ var init_upload = __esm(() => {
501
+ ACCEPTED_MIME_PREFIXES = ["image/"];
502
+ ACCEPTED_MIME_EXACT = ["application/pdf"];
503
+ ACCEPTED_EXTENSIONS = [".zip", ".txt", ".csv", ".json", ".md"];
504
+ });
505
+
506
+ // src/autocomplete.ts
507
+ function detectTrigger(value, cursorPos) {
508
+ let i = cursorPos - 1;
509
+ while (i >= 0) {
510
+ const ch = value[i];
511
+ if (ch === "@" || ch === "#") {
512
+ const query = value.slice(i + 1, cursorPos);
513
+ if (!/\s/.test(query)) {
514
+ const before = i > 0 ? value[i - 1] : null;
515
+ if (before === null || /[\s\n]/.test(before)) {
516
+ return { trigger: ch, query, triggerPos: i };
517
+ }
518
+ }
519
+ return null;
520
+ }
521
+ if (/[\s\n]/.test(ch)) {
522
+ return null;
523
+ }
524
+ i--;
525
+ }
526
+ return null;
527
+ }
528
+ function confirmSuggestion(value, triggerPos, cursorPos, trigger, replacement) {
529
+ const before = value.slice(0, triggerPos);
530
+ const after = value.slice(cursorPos);
531
+ const inserted = `${trigger}${replacement}`;
532
+ const newValue = before + inserted + after;
533
+ const newCursorPos = triggerPos + inserted.length;
534
+ return { newValue, newCursorPos };
535
+ }
536
+ function renderDropdown(suggestions, selectedIndex) {
537
+ if (suggestions.length === 0)
538
+ return "";
539
+ const items = suggestions.map((s, i) => {
540
+ const selected = i === selectedIndex ? ' aria-selected="true"' : ' aria-selected="false"';
541
+ const subtitle = s.subtitle ? `<span class="ac-item-subtitle">${escapeHtml2(s.subtitle)}</span>` : "";
542
+ return `<li id="ac-item-${i}" class="ac-item" role="option" data-ac-index="${i}"${selected}>
543
+ <span class="ac-item-label">${escapeHtml2(s.label)}</span>${subtitle}
544
+ </li>`;
545
+ }).join("");
546
+ return items;
547
+ }
548
+ function escapeHtml2(text) {
549
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
550
+ }
551
+
552
+ // src/status-bar.ts
553
+ function countWords(text) {
554
+ if (!text.trim())
555
+ return 0;
556
+ return text.trim().split(/\s+/).filter(Boolean).length;
557
+ }
558
+ function countColour(wordCount, maxWords) {
559
+ if (!maxWords)
560
+ return "normal";
561
+ const pct = wordCount / maxWords * 100;
562
+ if (pct >= 100)
563
+ return "error";
564
+ if (pct >= 90)
565
+ return "warning";
566
+ return "normal";
567
+ }
568
+ function renderStatusCount(wordCount, charCount, maxWords) {
569
+ const cap = maxWords ?? null;
570
+ const colour = countColour(wordCount, cap);
571
+ const colourClass = colour !== "normal" ? ` class="${colour}"` : "";
572
+ if (cap) {
573
+ return `<span${colourClass}>${wordCount} / ${cap} words · ${charCount} chars</span>`;
574
+ }
575
+ return `<span>${wordCount} words · ${charCount} chars</span>`;
576
+ }
577
+
578
+ // src/element.ts
579
+ var exports_element = {};
580
+ __export(exports_element, {
581
+ ElDmMarkdownInput: () => ElDmMarkdownInput
582
+ });
583
+ import { BaseElement } from "@duskmoon-dev/el-base";
584
+ import { css as markdownBodyCSS } from "@duskmoon-dev/core/components/markdown-body";
585
+ import { css as css2 } from "@duskmoon-dev/el-base";
586
+ function sanitizeUrl(url) {
587
+ const trimmed = url.trim();
588
+ if (!/^[a-z][a-z\d+\-.]*:/i.test(trimmed))
589
+ return trimmed;
590
+ if (/^https?:/i.test(trimmed))
591
+ return trimmed;
592
+ return "#";
593
+ }
594
+ function escapeHtmlStr(s) {
595
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
596
+ }
597
+ var coreMarkdownStyles, markdownBodySheet, ElDmMarkdownInput;
598
+ var init_element = __esm(() => {
599
+ init_css();
600
+ init_highlight();
601
+ init_upload();
602
+ coreMarkdownStyles = markdownBodyCSS.replace(/@layer\s+components\s*\{/, "").replace(/\}\s*$/, "");
603
+ markdownBodySheet = css2`
604
+ ${coreMarkdownStyles}
605
+ `;
606
+ ElDmMarkdownInput = class ElDmMarkdownInput extends BaseElement {
607
+ static formAssociated = true;
608
+ static properties = {
609
+ name: { type: String, reflect: true, default: "" },
610
+ value: { type: String, default: "" },
611
+ placeholder: { type: String, reflect: true, default: "Write markdown…" },
612
+ disabled: { type: Boolean, reflect: true },
613
+ readonly: { type: Boolean, reflect: true },
614
+ uploadUrl: { type: String, reflect: true, attribute: "upload-url" },
615
+ maxWords: { type: Number, reflect: true, attribute: "max-words" },
616
+ dark: { type: Boolean, reflect: true }
617
+ };
618
+ #internals;
619
+ #initialized = false;
620
+ #activeTab = "write";
621
+ #highlightTimer = null;
622
+ #statusTimer = null;
623
+ #textarea = null;
624
+ #backdrop = null;
625
+ #backdropContent = null;
626
+ #writeArea = null;
627
+ #previewBody = null;
628
+ #statusCount = null;
629
+ #acDropdown = null;
630
+ #uploadList = null;
631
+ #fileInput = null;
632
+ #resizeObserver = null;
633
+ #acSuggestions = [];
634
+ #acSelectedIndex = -1;
635
+ #acTriggerPos = -1;
636
+ #acTrigger = null;
637
+ #uploadIdCounter = 0;
638
+ constructor() {
639
+ super();
640
+ this.#internals = this.attachInternals();
641
+ this.attachStyles([elementStyles, markdownBodySheet]);
642
+ }
643
+ connectedCallback() {
644
+ super.connectedCallback();
645
+ const initial = this.value ?? "";
646
+ if (initial && this.#textarea) {
647
+ this.#textarea.value = initial;
648
+ this.#syncFormValue();
649
+ }
650
+ }
651
+ disconnectedCallback() {
652
+ this.#resizeObserver?.disconnect();
653
+ super.disconnectedCallback();
654
+ }
655
+ update() {
656
+ if (!this.#initialized) {
657
+ super.update();
658
+ this.#initialized = true;
659
+ this.#cacheDOMRefs();
660
+ this.#attachEventHandlers();
661
+ this.#initHighlight();
662
+ this.#updateStatusBarNow();
663
+ const initVal = this.value ?? "";
664
+ if (initVal && this.#textarea) {
665
+ this.#textarea.value = initVal;
666
+ this.#syncFormValue();
667
+ this.#scheduleHighlight();
668
+ }
669
+ return;
670
+ }
671
+ this.#patchDynamicRegions();
672
+ }
673
+ #patchDynamicRegions() {
674
+ const ta = this.#textarea;
675
+ if (!ta)
676
+ return;
677
+ const placeholder = this.placeholder ?? "Write markdown…";
678
+ ta.placeholder = placeholder;
679
+ ta.disabled = !!this.disabled;
680
+ ta.readOnly = !!this.readonly;
681
+ const attachBtn = this.shadowRoot.querySelector(".attach-btn");
682
+ if (attachBtn) {
683
+ attachBtn.disabled = ta.disabled || ta.readOnly;
684
+ }
685
+ const propVal = this.value ?? "";
686
+ if (propVal !== ta.value) {
687
+ ta.value = propVal;
688
+ this.#syncFormValue();
689
+ this.#scheduleHighlight();
690
+ }
691
+ const dark = !!this.dark;
692
+ applyPrismTheme(this.shadowRoot, dark);
693
+ this.#updateStatusBarNow();
694
+ }
695
+ render() {
696
+ const ph = this.placeholder ?? "Write markdown…";
697
+ const disabled = !!this.disabled;
698
+ const readonly = !!this.readonly;
699
+ return `
700
+ <div class="editor">
701
+ <div class="toolbar" role="tablist" aria-label="Editor mode">
702
+ <button
703
+ class="tab-btn"
704
+ data-tab="write"
705
+ role="tab"
706
+ aria-selected="true"
707
+ aria-controls="write-panel"
708
+ >Write</button>
709
+ <button
710
+ class="tab-btn"
711
+ data-tab="preview"
712
+ role="tab"
713
+ aria-selected="false"
714
+ aria-controls="preview-panel"
715
+ >Preview</button>
716
+ </div>
717
+
718
+ <div class="write-area" id="write-panel" role="tabpanel" aria-label="Markdown editor">
719
+ <div class="backdrop" aria-hidden="true">
720
+ <div class="backdrop-content"></div>
721
+ </div>
722
+ <textarea
723
+ aria-label="Markdown editor"
724
+ aria-haspopup="listbox"
725
+ aria-autocomplete="list"
726
+ aria-controls="ac-dropdown"
727
+ placeholder="${ph}"
728
+ ${disabled ? "disabled" : ""}
729
+ ${readonly ? "readonly" : ""}
730
+ spellcheck="false"
731
+ autocomplete="off"
732
+ autocorrect="off"
733
+ autocapitalize="off"
734
+ ></textarea>
735
+ </div>
736
+
737
+ <div
738
+ class="preview-body markdown-body"
739
+ id="preview-panel"
740
+ role="tabpanel"
741
+ aria-label="Markdown preview"
742
+ hidden
743
+ ></div>
744
+
745
+ <div class="status-bar">
746
+ <button class="attach-btn" type="button" aria-label="Attach files" ${disabled || readonly ? "disabled" : ""}>
747
+ &#128206; Attach files
748
+ </button>
749
+ <span class="status-bar-count" aria-live="polite"></span>
750
+ <input
751
+ type="file"
752
+ class="file-input"
753
+ multiple
754
+ accept="image/*,application/pdf,.zip,.txt,.csv,.json,.md"
755
+ aria-hidden="true"
756
+ tabindex="-1"
757
+ >
758
+ </div>
759
+
760
+ <div class="upload-list"></div>
761
+ </div>
762
+ <ul id="ac-dropdown" class="ac-dropdown" role="listbox" aria-label="Suggestions" hidden></ul>
763
+ `;
764
+ }
765
+ #cacheDOMRefs() {
766
+ this.#textarea = this.shadowRoot.querySelector("textarea");
767
+ this.#backdrop = this.shadowRoot.querySelector(".backdrop");
768
+ this.#backdropContent = this.shadowRoot.querySelector(".backdrop-content");
769
+ this.#writeArea = this.shadowRoot.querySelector(".write-area");
770
+ this.#previewBody = this.shadowRoot.querySelector(".preview-body");
771
+ this.#statusCount = this.shadowRoot.querySelector(".status-bar-count");
772
+ this.#acDropdown = this.shadowRoot.querySelector(".ac-dropdown");
773
+ this.#uploadList = this.shadowRoot.querySelector(".upload-list");
774
+ this.#fileInput = this.shadowRoot.querySelector(".file-input");
775
+ }
776
+ #attachEventHandlers() {
777
+ const ta = this.#textarea;
778
+ if (!ta)
779
+ return;
780
+ ta.addEventListener("input", () => {
781
+ this.#syncFormValue();
782
+ this.emit("change", { value: ta.value });
783
+ this.#scheduleHighlight();
784
+ this.#scheduleStatusUpdate();
785
+ this.#handleAutocompleteInput();
786
+ });
787
+ ta.addEventListener("scroll", () => {
788
+ if (this.#backdrop) {
789
+ this.#backdrop.scrollTop = ta.scrollTop;
790
+ this.#backdrop.scrollLeft = ta.scrollLeft;
791
+ }
792
+ });
793
+ ta.addEventListener("blur", () => {
794
+ setTimeout(() => {
795
+ if (!this.shadowRoot?.activeElement) {
796
+ this.#closeDropdown();
797
+ }
798
+ }, 150);
799
+ });
800
+ ta.addEventListener("keydown", (e) => {
801
+ if (this.#acSuggestions.length > 0 && !this.#acDropdown?.hidden) {
802
+ this.#handleDropdownKeydown(e);
803
+ }
804
+ if (e.ctrlKey && e.shiftKey && e.key === "P") {
805
+ e.preventDefault();
806
+ this.#switchTab(this.#activeTab === "write" ? "preview" : "write");
807
+ }
808
+ });
809
+ const writeArea = this.#writeArea;
810
+ if (writeArea) {
811
+ writeArea.addEventListener("dragover", (e) => {
812
+ e.preventDefault();
813
+ writeArea.style.opacity = "0.8";
814
+ });
815
+ writeArea.addEventListener("dragleave", () => {
816
+ writeArea.style.opacity = "";
817
+ });
818
+ writeArea.addEventListener("drop", (e) => {
819
+ e.preventDefault();
820
+ writeArea.style.opacity = "";
821
+ if (this.readonly)
822
+ return;
823
+ const files = Array.from(e.dataTransfer?.files ?? []).filter(isAcceptedType);
824
+ files.forEach((f) => this.#startUpload(f));
825
+ });
826
+ }
827
+ ta.addEventListener("paste", (e) => {
828
+ if (this.readonly)
829
+ return;
830
+ const imageFiles = Array.from(e.clipboardData?.files ?? []).filter((f) => f.type.startsWith("image/"));
831
+ if (imageFiles.length > 0) {
832
+ e.preventDefault();
833
+ imageFiles.forEach((f) => this.#startUpload(f));
834
+ }
835
+ });
836
+ const toolbar = this.shadowRoot.querySelector(".toolbar");
837
+ toolbar?.addEventListener("click", (e) => {
838
+ const btn = e.target.closest(".tab-btn");
839
+ const tab = btn?.dataset.tab;
840
+ if (tab)
841
+ this.#switchTab(tab);
842
+ });
843
+ const attachBtn = this.shadowRoot.querySelector(".attach-btn");
844
+ attachBtn?.addEventListener("click", () => this.#fileInput?.click());
845
+ this.#fileInput?.addEventListener("change", () => {
846
+ const files = Array.from(this.#fileInput?.files ?? []).filter(isAcceptedType);
847
+ files.forEach((f) => this.#startUpload(f));
848
+ if (this.#fileInput)
849
+ this.#fileInput.value = "";
850
+ });
851
+ this.#acDropdown?.addEventListener("click", (e) => {
852
+ const item = e.target.closest("[data-ac-index]");
853
+ if (item) {
854
+ const idx = parseInt(item.dataset.acIndex ?? "-1", 10);
855
+ if (idx >= 0) {
856
+ this.#acSelectedIndex = idx;
857
+ this.#confirmAutocomplete();
858
+ }
859
+ }
860
+ });
861
+ if (typeof ResizeObserver !== "undefined") {
862
+ this.#resizeObserver = new ResizeObserver(() => {
863
+ if (this.#backdrop && this.#textarea) {
864
+ this.#backdrop.style.height = `${this.#textarea.offsetHeight}px`;
865
+ }
866
+ });
867
+ this.#resizeObserver.observe(ta);
868
+ }
869
+ }
870
+ #initHighlight() {
871
+ const dark = !!this.dark;
872
+ applyPrismTheme(this.shadowRoot, dark);
873
+ ensurePrism().then(() => {
874
+ if (this.#textarea && this.#backdropContent) {
875
+ this.#backdropContent.innerHTML = highlightMarkdown(this.#textarea.value);
876
+ }
877
+ });
878
+ }
879
+ #scheduleHighlight() {
880
+ if (this.#highlightTimer !== null)
881
+ clearTimeout(this.#highlightTimer);
882
+ this.#highlightTimer = setTimeout(() => {
883
+ this.#highlightTimer = null;
884
+ if (this.#backdropContent && this.#textarea) {
885
+ this.#backdropContent.innerHTML = highlightMarkdown(this.#textarea.value);
886
+ }
887
+ if (this.#backdrop && this.#textarea) {
888
+ this.#backdrop.scrollTop = this.#textarea.scrollTop;
889
+ }
890
+ }, 60);
891
+ }
892
+ #switchTab(tab) {
893
+ if (tab === this.#activeTab)
894
+ return;
895
+ this.#activeTab = tab;
896
+ const writeBtns = this.shadowRoot.querySelectorAll(".tab-btn");
897
+ writeBtns.forEach((btn) => {
898
+ const isActive = btn.dataset.tab === tab;
899
+ btn.setAttribute("aria-selected", String(isActive));
900
+ });
901
+ if (tab === "preview") {
902
+ this.#writeArea?.setAttribute("hidden", "");
903
+ if (this.#previewBody) {
904
+ this.#previewBody.removeAttribute("hidden");
905
+ this.#previewBody.innerHTML = this.#renderMarkdown(this.#textarea?.value ?? "");
906
+ }
907
+ } else {
908
+ this.#writeArea?.removeAttribute("hidden");
909
+ this.#previewBody?.setAttribute("hidden", "");
910
+ }
911
+ }
912
+ #renderMarkdown(md) {
913
+ if (!md.trim())
914
+ return "<p></p>";
915
+ const CB_PH = "⁠CB";
916
+ const IC_PH = "⁠IC";
917
+ const codeBlocks = [];
918
+ let html = md.replace(/```(\w*)\n?([\s\S]*?)```/g, (_, lang, code) => {
919
+ const escaped = code.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
920
+ const idx = codeBlocks.push(`<pre><code class="language-${lang || "text"}">${escaped}</code></pre>`) - 1;
921
+ return `${CB_PH}${idx}${CB_PH}`;
922
+ });
923
+ const inlineCodes = [];
924
+ html = html.replace(/`([^`\n]+)`/g, (_, code) => {
925
+ const escaped = code.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
926
+ const idx = inlineCodes.push(`<code>${escaped}</code>`) - 1;
927
+ return `${IC_PH}${idx}${IC_PH}`;
928
+ });
929
+ html = html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
930
+ html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (_, alt, url) => `<img src="${sanitizeUrl(url)}" alt="${alt}">`);
931
+ html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, text, url) => `<a href="${sanitizeUrl(url)}">${text}</a>`);
932
+ html = html.replace(/^###### (.+)$/gm, "<h6>$1</h6>").replace(/^##### (.+)$/gm, "<h5>$1</h5>").replace(/^#### (.+)$/gm, "<h4>$1</h4>").replace(/^### (.+)$/gm, "<h3>$1</h3>").replace(/^## (.+)$/gm, "<h2>$1</h2>").replace(/^# (.+)$/gm, "<h1>$1</h1>");
933
+ html = html.replace(/^[-*_]{3,}$/gm, "<hr>");
934
+ html = html.replace(/^&gt; (.+)$/gm, "<blockquote>$1</blockquote>");
935
+ html = html.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>").replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>").replace(/\*(.+?)\*/g, "<em>$1</em>").replace(/___(.+?)___/g, "<strong><em>$1</em></strong>").replace(/__(.+?)__/g, "<strong>$1</strong>").replace(/_(.+?)_/g, "<em>$1</em>");
936
+ html = html.replace(/~~(.+?)~~/g, "<del>$1</del>");
937
+ html = html.replace(/^[ \t]*[-*+] (.+)$/gm, '<li data-list="ul">$1</li>');
938
+ html = html.replace(/^[ \t]*\d+\. (.+)$/gm, '<li data-list="ol">$1</li>');
939
+ html = html.replace(/(<li data-list="ul">[^\n]*<\/li>(?:\n<li data-list="ul">[^\n]*<\/li>)*)/g, (match) => "<ul>" + match.replace(/ data-list="ul"/g, "") + "</ul>");
940
+ html = html.replace(/(<li data-list="ol">[^\n]*<\/li>(?:\n<li data-list="ol">[^\n]*<\/li>)*)/g, (match) => "<ol>" + match.replace(/ data-list="ol"/g, "") + "</ol>");
941
+ const lines = html.split(`
942
+
943
+ `);
944
+ html = lines.map((block) => {
945
+ const t = block.trim();
946
+ if (!t)
947
+ return "";
948
+ if (/^<(h[1-6]|ul|ol|li|blockquote|hr|pre|img)/.test(t) || t.startsWith(CB_PH))
949
+ return t;
950
+ return `<p>${t.replace(/\n/g, "<br>")}</p>`;
951
+ }).filter(Boolean).join(`
952
+ `);
953
+ html = html.replace(new RegExp(`${CB_PH}(\\d+)${CB_PH}`, "g"), (_, i) => codeBlocks[parseInt(i, 10)] ?? "");
954
+ html = html.replace(new RegExp(`${IC_PH}(\\d+)${IC_PH}`, "g"), (_, i) => inlineCodes[parseInt(i, 10)] ?? "");
955
+ return html;
956
+ }
957
+ #syncFormValue() {
958
+ this.#internals?.setFormValue(this.#textarea?.value ?? "");
959
+ }
960
+ #startUpload(file) {
961
+ this.emit("upload-start", { file });
962
+ const id = `upload-${++this.#uploadIdCounter}`;
963
+ const uploadUrl = this.uploadUrl;
964
+ if (!uploadUrl) {
965
+ this.emit("upload-error", { file, error: "no upload-url set" });
966
+ this.#showUploadError(file, "no upload-url set");
967
+ return;
968
+ }
969
+ this.#addProgressRow(id, file.name);
970
+ uploadFile(file, uploadUrl, (pct) => {
971
+ this.#updateProgressRow(id, pct);
972
+ }).then((url) => {
973
+ this.#removeUploadRow(id);
974
+ const markdown = fileToMarkdown(file, url);
975
+ this.insertText(markdown);
976
+ this.emit("upload-done", { file, url, markdown });
977
+ }).catch((err) => {
978
+ this.#removeUploadRow(id);
979
+ const errorMsg = typeof err === "string" ? err : "Upload failed";
980
+ this.emit("upload-error", { file, error: errorMsg });
981
+ this.#showUploadError(file, errorMsg);
982
+ });
983
+ }
984
+ #addProgressRow(id, filename) {
985
+ if (!this.#uploadList)
986
+ return;
987
+ const row = document.createElement("div");
988
+ row.className = "upload-row";
989
+ row.id = id;
990
+ row.innerHTML = `
991
+ <span class="upload-filename">${escapeHtmlStr(filename)}</span>
992
+ <div class="upload-bar-track">
993
+ <div class="upload-bar" style="width: 0%"></div>
994
+ </div>
995
+ `;
996
+ this.#uploadList.appendChild(row);
997
+ }
998
+ #updateProgressRow(id, pct) {
999
+ const bar = this.#uploadList?.querySelector(`#${id} .upload-bar`);
1000
+ if (bar)
1001
+ bar.style.width = `${pct}%`;
1002
+ }
1003
+ #removeUploadRow(id) {
1004
+ this.#uploadList?.querySelector(`#${id}`)?.remove();
1005
+ }
1006
+ #showUploadError(file, message) {
1007
+ if (!this.#uploadList)
1008
+ return;
1009
+ const row = document.createElement("div");
1010
+ row.className = "upload-error-row";
1011
+ row.innerHTML = `
1012
+ <span class="upload-error-msg">${escapeHtmlStr(file.name)}: ${escapeHtmlStr(message)}</span>
1013
+ `;
1014
+ this.#uploadList.appendChild(row);
1015
+ setTimeout(() => row.remove(), 4000);
1016
+ }
1017
+ #handleAutocompleteInput() {
1018
+ const ta = this.#textarea;
1019
+ if (!ta)
1020
+ return;
1021
+ const result = detectTrigger(ta.value, ta.selectionStart ?? 0);
1022
+ if (!result) {
1023
+ this.#closeDropdown();
1024
+ return;
1025
+ }
1026
+ const { trigger, query, triggerPos } = result;
1027
+ this.#acTrigger = trigger;
1028
+ this.#acTriggerPos = triggerPos;
1029
+ const resolve = (list) => this.setSuggestions(list);
1030
+ if (trigger === "@") {
1031
+ this.emit("mention-query", { trigger, query, resolve });
1032
+ } else {
1033
+ this.emit("reference-query", { trigger, query, resolve });
1034
+ }
1035
+ }
1036
+ #handleDropdownKeydown(e) {
1037
+ const len = this.#acSuggestions.length;
1038
+ if (len === 0)
1039
+ return;
1040
+ switch (e.key) {
1041
+ case "ArrowDown":
1042
+ e.preventDefault();
1043
+ this.#acSelectedIndex = (this.#acSelectedIndex + 1) % len;
1044
+ this.#updateDropdown();
1045
+ break;
1046
+ case "ArrowUp":
1047
+ e.preventDefault();
1048
+ this.#acSelectedIndex = (this.#acSelectedIndex - 1 + len) % len;
1049
+ this.#updateDropdown();
1050
+ break;
1051
+ case "Enter":
1052
+ case "Tab":
1053
+ if (this.#acSelectedIndex >= 0) {
1054
+ e.preventDefault();
1055
+ this.#confirmAutocomplete();
1056
+ }
1057
+ break;
1058
+ case "Escape":
1059
+ this.#closeDropdown();
1060
+ break;
1061
+ }
1062
+ }
1063
+ #confirmAutocomplete() {
1064
+ const ta = this.#textarea;
1065
+ if (!ta || this.#acSelectedIndex < 0 || !this.#acTrigger)
1066
+ return;
1067
+ const suggestion = this.#acSuggestions[this.#acSelectedIndex];
1068
+ if (!suggestion)
1069
+ return;
1070
+ const { newValue, newCursorPos } = confirmSuggestion(ta.value, this.#acTriggerPos, ta.selectionStart ?? ta.value.length, this.#acTrigger, suggestion.id);
1071
+ ta.value = newValue;
1072
+ ta.setSelectionRange(newCursorPos, newCursorPos);
1073
+ this.#syncFormValue();
1074
+ this.emit("change", { value: ta.value });
1075
+ this.#scheduleHighlight();
1076
+ this.#scheduleStatusUpdate();
1077
+ this.#closeDropdown();
1078
+ }
1079
+ #closeDropdown() {
1080
+ this.#acSuggestions = [];
1081
+ this.#acSelectedIndex = -1;
1082
+ this.#acTrigger = null;
1083
+ this.#acTriggerPos = -1;
1084
+ if (this.#acDropdown) {
1085
+ this.#acDropdown.innerHTML = "";
1086
+ this.#acDropdown.hidden = true;
1087
+ }
1088
+ }
1089
+ #updateDropdown() {
1090
+ if (!this.#acDropdown)
1091
+ return;
1092
+ if (this.#acSuggestions.length === 0) {
1093
+ this.#acDropdown.hidden = true;
1094
+ this.#textarea?.removeAttribute("aria-activedescendant");
1095
+ return;
1096
+ }
1097
+ this.#acDropdown.innerHTML = renderDropdown(this.#acSuggestions, this.#acSelectedIndex);
1098
+ this.#acDropdown.hidden = false;
1099
+ if (this.#acSelectedIndex >= 0) {
1100
+ this.#textarea?.setAttribute("aria-activedescendant", `ac-item-${this.#acSelectedIndex}`);
1101
+ } else {
1102
+ this.#textarea?.removeAttribute("aria-activedescendant");
1103
+ }
1104
+ }
1105
+ #scheduleStatusUpdate() {
1106
+ if (this.#statusTimer !== null)
1107
+ clearTimeout(this.#statusTimer);
1108
+ this.#statusTimer = setTimeout(() => {
1109
+ this.#statusTimer = null;
1110
+ this.#updateStatusBarNow();
1111
+ }, 100);
1112
+ }
1113
+ #updateStatusBarNow() {
1114
+ if (!this.#statusCount)
1115
+ return;
1116
+ const text = this.#textarea?.value ?? "";
1117
+ const words = countWords(text);
1118
+ const chars = text.length;
1119
+ const maxWords = this.maxWords ?? null;
1120
+ this.#statusCount.innerHTML = renderStatusCount(words, chars, maxWords);
1121
+ }
1122
+ getValue() {
1123
+ return this.#textarea?.value ?? "";
1124
+ }
1125
+ setValue(str) {
1126
+ if (this.#textarea) {
1127
+ this.#textarea.value = str;
1128
+ this.#syncFormValue();
1129
+ this.#scheduleHighlight();
1130
+ this.#updateStatusBarNow();
1131
+ } else {
1132
+ this.value = str;
1133
+ }
1134
+ }
1135
+ insertText(str) {
1136
+ const ta = this.#textarea;
1137
+ if (!ta)
1138
+ return;
1139
+ const start = ta.selectionStart ?? ta.value.length;
1140
+ const end = ta.selectionEnd ?? ta.value.length;
1141
+ ta.value = ta.value.slice(0, start) + str + ta.value.slice(end);
1142
+ const newPos = start + str.length;
1143
+ ta.setSelectionRange(newPos, newPos);
1144
+ ta.dispatchEvent(new Event("input", { bubbles: true }));
1145
+ }
1146
+ setSuggestions(list) {
1147
+ this.#acSuggestions = list;
1148
+ this.#acSelectedIndex = list.length > 0 ? 0 : -1;
1149
+ this.#updateDropdown();
1150
+ }
1151
+ };
1152
+ });
1153
+
1154
+ // src/index.ts
1155
+ init_element();
1156
+ function register() {
1157
+ if (!customElements.get("el-dm-markdown-input")) {
1158
+ Promise.resolve().then(() => (init_element(), exports_element)).then(({ ElDmMarkdownInput: ElDmMarkdownInput2 }) => {
1159
+ customElements.define("el-dm-markdown-input", ElDmMarkdownInput2);
1160
+ });
1161
+ }
1162
+ }
1163
+ var MarkdownInputHook = {
1164
+ mounted() {
1165
+ this.el.setValue(this.el.dataset.value ?? "");
1166
+ this.el.addEventListener("change", (e) => {
1167
+ const detail = e.detail;
1168
+ this.pushEvent("content_changed", { value: detail.value });
1169
+ });
1170
+ this.el.addEventListener("upload-start", (e) => {
1171
+ const detail = e.detail;
1172
+ this.pushEvent("upload_file", { name: detail.file.name });
1173
+ });
1174
+ },
1175
+ updated() {
1176
+ const v = this.el.dataset.value;
1177
+ if (v !== undefined && v !== this.el.getValue()) {
1178
+ this.el.setValue(v);
1179
+ }
1180
+ }
1181
+ };
1182
+ export {
1183
+ register,
1184
+ MarkdownInputHook,
1185
+ ElDmMarkdownInput
1186
+ };
1187
+
1188
+ //# debugId=765ABA8108F4BB0A64756E2164756E21
1189
+ //# sourceMappingURL=index.js.map