@vanduo-oss/vd3-cbun 1.0.0 → 1.2.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,1328 @@
1
+ // src/code-editor/vue.js
2
+ import { defineComponent, h, ref, onMounted, onBeforeUnmount, watch } from "vue";
3
+
4
+ // src/code-editor/tokenizer/scanner.js
5
+ function scan(source, rules) {
6
+ const tokens = [];
7
+ const n = source.length;
8
+ let i = 0;
9
+ let plainStart = -1;
10
+ const flushPlain = (end) => {
11
+ if (plainStart !== -1 && end > plainStart) {
12
+ tokens.push({ type: "plain", value: source.slice(plainStart, end) });
13
+ }
14
+ plainStart = -1;
15
+ };
16
+ while (i < n) {
17
+ let matched = false;
18
+ for (let r = 0; r < rules.length; r++) {
19
+ const rule = rules[r];
20
+ rule.re.lastIndex = i;
21
+ const m = rule.re.exec(source);
22
+ if (m && m[0].length > 0) {
23
+ flushPlain(i);
24
+ const value = m[0];
25
+ if (rule.expand) {
26
+ const sub = rule.expand(value);
27
+ for (let k = 0; k < sub.length; k++) tokens.push(sub[k]);
28
+ } else {
29
+ tokens.push({ type: rule.type, value });
30
+ }
31
+ i += value.length;
32
+ matched = true;
33
+ break;
34
+ }
35
+ }
36
+ if (!matched) {
37
+ if (plainStart === -1) plainStart = i;
38
+ i++;
39
+ }
40
+ }
41
+ flushPlain(n);
42
+ return coalesce(tokens);
43
+ }
44
+ function coalesce(tokens) {
45
+ if (tokens.length < 2) return tokens;
46
+ const out = [{ type: tokens[0].type, value: tokens[0].value }];
47
+ for (let i = 1; i < tokens.length; i++) {
48
+ const cur = tokens[i];
49
+ const prev = out[out.length - 1];
50
+ if (cur.type === prev.type) prev.value += cur.value;
51
+ else out.push({ type: cur.type, value: cur.value });
52
+ }
53
+ return out;
54
+ }
55
+ function wordRegex(words, flags) {
56
+ const sorted = [...words].sort((a, b) => b.length - a.length);
57
+ return new RegExp("(?:" + sorted.join("|") + ")\\b", (flags || "") + "y");
58
+ }
59
+
60
+ // src/code-editor/tokenizer/javascript.js
61
+ var JS_KEYWORDS = [
62
+ "break",
63
+ "case",
64
+ "catch",
65
+ "class",
66
+ "const",
67
+ "continue",
68
+ "debugger",
69
+ "default",
70
+ "delete",
71
+ "do",
72
+ "else",
73
+ "export",
74
+ "extends",
75
+ "finally",
76
+ "for",
77
+ "function",
78
+ "if",
79
+ "import",
80
+ "in",
81
+ "instanceof",
82
+ "new",
83
+ "return",
84
+ "super",
85
+ "switch",
86
+ "this",
87
+ "throw",
88
+ "try",
89
+ "typeof",
90
+ "var",
91
+ "void",
92
+ "while",
93
+ "with",
94
+ "yield",
95
+ "async",
96
+ "await",
97
+ "let",
98
+ "static",
99
+ "get",
100
+ "set",
101
+ "of",
102
+ "as",
103
+ "from"
104
+ ];
105
+ var TS_KEYWORDS = [
106
+ ...JS_KEYWORDS,
107
+ "interface",
108
+ "type",
109
+ "enum",
110
+ "implements",
111
+ "declare",
112
+ "namespace",
113
+ "readonly",
114
+ "satisfies",
115
+ "abstract",
116
+ "public",
117
+ "private",
118
+ "protected",
119
+ "keyof",
120
+ "infer",
121
+ "is",
122
+ "asserts",
123
+ "override",
124
+ "module",
125
+ "string",
126
+ "number",
127
+ "boolean",
128
+ "object",
129
+ "symbol",
130
+ "bigint",
131
+ "any",
132
+ "unknown",
133
+ "never"
134
+ ];
135
+ var BUILTINS = [
136
+ "console",
137
+ "window",
138
+ "document",
139
+ "globalThis",
140
+ "Math",
141
+ "JSON",
142
+ "Object",
143
+ "Array",
144
+ "String",
145
+ "Number",
146
+ "Boolean",
147
+ "Symbol",
148
+ "Promise",
149
+ "Map",
150
+ "Set",
151
+ "WeakMap",
152
+ "WeakSet",
153
+ "Date",
154
+ "RegExp",
155
+ "Error",
156
+ "Function",
157
+ "parseInt",
158
+ "parseFloat",
159
+ "isNaN",
160
+ "isFinite",
161
+ "require",
162
+ "module",
163
+ "exports",
164
+ "process",
165
+ "NaN",
166
+ "Infinity"
167
+ ];
168
+ function makeRules(keywords) {
169
+ return [
170
+ { type: "comment", re: /\/\/[^\n]*/y },
171
+ { type: "comment", re: /\/\*[\s\S]*?\*\//y },
172
+ { type: "string", re: /"(?:[^"\\\n]|\\.)*"?/y },
173
+ { type: "string", re: /'(?:[^'\\\n]|\\.)*'?/y },
174
+ { type: "string", re: /`(?:[^`\\]|\\.)*`?/y },
175
+ {
176
+ type: "number",
177
+ re: /0[xX][\da-fA-F_]+n?|0[bB][01_]+n?|0[oO][0-7_]+n?|(?:\d[\d_]*\.?[\d_]*|\.\d[\d_]*)(?:[eE][+-]?\d+)?n?/y
178
+ },
179
+ { type: "keyword", re: wordRegex(keywords) },
180
+ { type: "boolean", re: /(?:true|false)\b/y },
181
+ { type: "null", re: /(?:null|undefined)\b/y },
182
+ { type: "builtin", re: wordRegex(BUILTINS) },
183
+ { type: "function", re: /[A-Za-z_$][\w$]*(?=\s*\()/y },
184
+ { type: "plain", re: /[A-Za-z_$][\w$]*/y },
185
+ { type: "operator", re: /\.{3}|=>|[+\-*/%=<>!&|^~?]+/y },
186
+ { type: "punctuation", re: /[{}()[\];,.:]/y }
187
+ ];
188
+ }
189
+ var JS_RULES = makeRules(JS_KEYWORDS);
190
+ var TS_RULES = makeRules(TS_KEYWORDS);
191
+ function tokenizeJavaScript(source) {
192
+ return scan(source, JS_RULES);
193
+ }
194
+ function tokenizeTypeScript(source) {
195
+ return scan(source, TS_RULES);
196
+ }
197
+
198
+ // src/code-editor/tokenizer/html.js
199
+ function expandTag(value) {
200
+ const out = [];
201
+ const open = /^<\/?/.exec(value)[0];
202
+ out.push({ type: "punctuation", value: open });
203
+ let rest = value.slice(open.length);
204
+ const name = /^[a-zA-Z][\w:-]*/.exec(rest);
205
+ if (name) {
206
+ out.push({ type: "tag", value: name[0] });
207
+ rest = rest.slice(name[0].length);
208
+ }
209
+ if (rest) {
210
+ const inner = scan(rest, [
211
+ { type: "string", re: /"[^"]*"?|'[^']*'?/y },
212
+ { type: "operator", re: /=/y },
213
+ { type: "punctuation", re: /\/?>/y },
214
+ { type: "attribute", re: /[a-zA-Z_:@][\w:.-]*/y }
215
+ ]);
216
+ for (let i = 0; i < inner.length; i++) out.push(inner[i]);
217
+ }
218
+ return out;
219
+ }
220
+ var RULES = [
221
+ { type: "comment", re: /<!--[\s\S]*?-->/y },
222
+ { type: "meta", re: /<!\[CDATA\[[\s\S]*?\]\]>/y },
223
+ { type: "meta", re: /<!DOCTYPE[^>]*>/iy },
224
+ {
225
+ expand: expandTag,
226
+ re: /<\/?[a-zA-Z][\w:-]*(?:\s+[^\s/>"'=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+))?)*\s*\/?>/y
227
+ },
228
+ { expand: expandTag, re: /<\/?[a-zA-Z][\w:-]*/y },
229
+ { type: "meta", re: /&[a-zA-Z][a-zA-Z0-9]*;|&#\d+;|&#x[0-9a-fA-F]+;/y }
230
+ ];
231
+ function tokenizeHtml(source) {
232
+ return scan(source, RULES);
233
+ }
234
+
235
+ // src/code-editor/tokenizer/css.js
236
+ var RULES2 = [
237
+ { type: "comment", re: /\/\*[\s\S]*?\*\//y },
238
+ { type: "string", re: /"(?:[^"\\\n]|\\.)*"?|'(?:[^'\\\n]|\\.)*'?/y },
239
+ { type: "meta", re: /@[a-zA-Z-]+/y },
240
+ { type: "keyword", re: /!important\b/y },
241
+ { type: "number", re: /#[0-9a-fA-F]{3,8}\b/y },
242
+ { type: "number", re: /-?(?:\d*\.\d+|\d+)(?:%|[a-zA-Z]{1,4})?/y },
243
+ { type: "property", re: /[-a-zA-Z]+(?=\s*:)/y },
244
+ { type: "function", re: /[-a-zA-Z][\w-]*(?=\()/y },
245
+ { type: "punctuation", re: /[{}()[\];:,]/y },
246
+ { type: "operator", re: /[>+~*]/y },
247
+ // Catch-all: consume an identifier/dash run (or whitespace) in one match so
248
+ // the greedy property/function look-ahead rules run once per run, not once
249
+ // per character (keeps scanning linear).
250
+ { type: "plain", re: /[-\w$]+|\s+/y }
251
+ ];
252
+ function tokenizeCss(source) {
253
+ return scan(source, RULES2);
254
+ }
255
+
256
+ // src/code-editor/tokenizer/json.js
257
+ var RULES3 = [
258
+ { type: "property", re: /"(?:[^"\\]|\\.)*"(?=\s*:)/y },
259
+ { type: "string", re: /"(?:[^"\\]|\\.)*"?/y },
260
+ { type: "number", re: /-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/y },
261
+ { type: "boolean", re: /\b(?:true|false)\b/y },
262
+ { type: "null", re: /\bnull\b/y },
263
+ { type: "punctuation", re: /[{}[\]:,]/y }
264
+ ];
265
+ function tokenizeJson(source) {
266
+ return scan(source, RULES3);
267
+ }
268
+
269
+ // src/code-editor/tokenizer/markdown.js
270
+ var RULES4 = [
271
+ { type: "string", re: /```[\s\S]*?```|~~~[\s\S]*?~~~|`[^`\n]*`/y },
272
+ { type: "keyword", re: /^ {0,3}#{1,6} [^\n]*/my },
273
+ { type: "comment", re: /^ {0,3}>[^\n]*/my },
274
+ { type: "punctuation", re: /^ {0,3}(?:[-*+]|\d+\.)\s/my },
275
+ { type: "meta", re: /^ {0,3}(?:-{3,}|\*{3,}|_{3,})\s*$/my },
276
+ { type: "function", re: /!?\[[^\][\n]*\]\([^()\n]*\)/y },
277
+ { type: "operator", re: /\*\*[^\n]*?\*\*|__[^\n]*?__/y },
278
+ { type: "meta", re: /\*[^*\n]+?\*|_[^_\n]+?_/y }
279
+ ];
280
+ function tokenizeMarkdown(source) {
281
+ return scan(source, RULES4);
282
+ }
283
+
284
+ // src/code-editor/tokenizer/shell.js
285
+ var KEYWORDS = [
286
+ "if",
287
+ "then",
288
+ "elif",
289
+ "else",
290
+ "fi",
291
+ "for",
292
+ "while",
293
+ "until",
294
+ "do",
295
+ "done",
296
+ "case",
297
+ "esac",
298
+ "function",
299
+ "in",
300
+ "select",
301
+ "return",
302
+ "break",
303
+ "continue",
304
+ "local",
305
+ "export",
306
+ "readonly",
307
+ "declare",
308
+ "typeset",
309
+ "set",
310
+ "unset",
311
+ "shift",
312
+ "exit",
313
+ "source",
314
+ "alias"
315
+ ];
316
+ var BUILTINS2 = [
317
+ "echo",
318
+ "printf",
319
+ "read",
320
+ "cd",
321
+ "pwd",
322
+ "ls",
323
+ "cat",
324
+ "grep",
325
+ "sed",
326
+ "awk",
327
+ "cut",
328
+ "sort",
329
+ "uniq",
330
+ "head",
331
+ "tail",
332
+ "find",
333
+ "xargs",
334
+ "curl",
335
+ "wget",
336
+ "git",
337
+ "npm",
338
+ "pnpm",
339
+ "yarn",
340
+ "node",
341
+ "python",
342
+ "pip",
343
+ "docker",
344
+ "kubectl",
345
+ "make",
346
+ "chmod",
347
+ "chown",
348
+ "mkdir",
349
+ "rmdir",
350
+ "rm",
351
+ "cp",
352
+ "mv",
353
+ "touch",
354
+ "test",
355
+ "sudo",
356
+ "env",
357
+ "which",
358
+ "kill",
359
+ "ps",
360
+ "tar",
361
+ "ssh"
362
+ ];
363
+ var RULES5 = [
364
+ { type: "comment", re: /#[^\n]*/y },
365
+ { type: "string", re: /"(?:[^"\\]|\\.)*"?/y },
366
+ { type: "string", re: /'[^']*'?/y },
367
+ { type: "variable", re: /\$\{[^}\n]*\}?|\$[A-Za-z_]\w*|\$[@*#?$!0-9-]/y },
368
+ { type: "keyword", re: wordRegex(KEYWORDS) },
369
+ { type: "builtin", re: wordRegex(BUILTINS2) },
370
+ { type: "attribute", re: /(?:^|\s)-{1,2}[A-Za-z][\w-]*/y },
371
+ { type: "number", re: /\b\d+\b/y },
372
+ { type: "operator", re: /\|\||&&|[|&;<>]+/y },
373
+ { type: "punctuation", re: /[(){}[\]]/y }
374
+ ];
375
+ function tokenizeShell(source) {
376
+ return scan(source, RULES5);
377
+ }
378
+
379
+ // src/code-editor/tokenizer/python.js
380
+ var KEYWORDS2 = [
381
+ "def",
382
+ "class",
383
+ "return",
384
+ "if",
385
+ "elif",
386
+ "else",
387
+ "for",
388
+ "while",
389
+ "break",
390
+ "continue",
391
+ "pass",
392
+ "import",
393
+ "from",
394
+ "as",
395
+ "with",
396
+ "try",
397
+ "except",
398
+ "finally",
399
+ "raise",
400
+ "yield",
401
+ "lambda",
402
+ "global",
403
+ "nonlocal",
404
+ "del",
405
+ "assert",
406
+ "async",
407
+ "await",
408
+ "in",
409
+ "is",
410
+ "not",
411
+ "and",
412
+ "or",
413
+ "match",
414
+ "case"
415
+ ];
416
+ var BUILTINS3 = [
417
+ "print",
418
+ "len",
419
+ "range",
420
+ "int",
421
+ "float",
422
+ "str",
423
+ "list",
424
+ "dict",
425
+ "set",
426
+ "tuple",
427
+ "bool",
428
+ "bytes",
429
+ "type",
430
+ "isinstance",
431
+ "issubclass",
432
+ "super",
433
+ "open",
434
+ "enumerate",
435
+ "zip",
436
+ "map",
437
+ "filter",
438
+ "sorted",
439
+ "reversed",
440
+ "sum",
441
+ "min",
442
+ "max",
443
+ "abs",
444
+ "round",
445
+ "input",
446
+ "repr",
447
+ "format",
448
+ "object",
449
+ "self",
450
+ "cls",
451
+ "Exception",
452
+ "ValueError",
453
+ "TypeError",
454
+ "KeyError",
455
+ "IndexError",
456
+ "AttributeError",
457
+ "RuntimeError"
458
+ ];
459
+ var RULES6 = [
460
+ { type: "comment", re: /#[^\n]*/y },
461
+ {
462
+ type: "string",
463
+ re: /[rRbBfFuU]{0,2}(?:"""[\s\S]*?"""|'''[\s\S]*?'''|"(?:[^"\\\n]|\\.)*"?|'(?:[^'\\\n]|\\.)*'?)/y
464
+ },
465
+ { type: "meta", re: /@[A-Za-z_]\w*/y },
466
+ { type: "keyword", re: wordRegex(KEYWORDS2) },
467
+ { type: "boolean", re: /\b(?:True|False)\b/y },
468
+ { type: "null", re: /\bNone\b/y },
469
+ { type: "builtin", re: wordRegex(BUILTINS3) },
470
+ { type: "function", re: /[A-Za-z_]\w*(?=\s*\()/y },
471
+ {
472
+ type: "number",
473
+ re: /\b0[xXoObB][0-9a-fA-F_]+\b|\b\d[\d_]*(?:\.\d[\d_]*)?(?:[eE][+-]?\d+)?[jJ]?\b/y
474
+ },
475
+ { type: "operator", re: /:=|[+\-*/%=<>!&|^~@]+/y },
476
+ { type: "punctuation", re: /[()[\]{}:;,.]/y },
477
+ // Catch-all: consume an identifier run (or whitespace) in one match so the
478
+ // greedy function look-ahead rule runs once per run, not once per character.
479
+ { type: "plain", re: /\w+|\s+/y }
480
+ ];
481
+ function tokenizePython(source) {
482
+ return scan(source, RULES6);
483
+ }
484
+
485
+ // src/code-editor/tokenizer/index.js
486
+ var TOKENIZERS = {
487
+ javascript: tokenizeJavaScript,
488
+ typescript: tokenizeTypeScript,
489
+ html: tokenizeHtml,
490
+ css: tokenizeCss,
491
+ json: tokenizeJson,
492
+ markdown: tokenizeMarkdown,
493
+ shell: tokenizeShell,
494
+ python: tokenizePython
495
+ };
496
+ var LANGUAGES = Object.freeze([
497
+ "plaintext",
498
+ "javascript",
499
+ "typescript",
500
+ "html",
501
+ "css",
502
+ "json",
503
+ "markdown",
504
+ "shell",
505
+ "python"
506
+ ]);
507
+ var ALIASES = Object.freeze({
508
+ js: "javascript",
509
+ jsx: "javascript",
510
+ mjs: "javascript",
511
+ cjs: "javascript",
512
+ ts: "typescript",
513
+ tsx: "typescript",
514
+ htm: "html",
515
+ xml: "html",
516
+ vue: "html",
517
+ svg: "html",
518
+ sh: "shell",
519
+ bash: "shell",
520
+ zsh: "shell",
521
+ shellscript: "shell",
522
+ py: "python",
523
+ python3: "python",
524
+ md: "markdown",
525
+ mkd: "markdown",
526
+ json5: "json",
527
+ jsonc: "json",
528
+ text: "plaintext",
529
+ txt: "plaintext",
530
+ plain: "plaintext"
531
+ });
532
+ function resolveLanguage(language) {
533
+ const id = String(language || "plaintext").toLowerCase();
534
+ return ALIASES[id] || id;
535
+ }
536
+ function getTokenizer(language) {
537
+ return TOKENIZERS[resolveLanguage(language)] || null;
538
+ }
539
+ function tokenize(source, language) {
540
+ if (!source) return [];
541
+ const tokenizer = getTokenizer(language);
542
+ if (!tokenizer) return [{ type: "plain", value: source }];
543
+ return tokenizer(source);
544
+ }
545
+
546
+ // src/code-editor/highlight.js
547
+ var ESCAPE_RE = /[&<>"']/g;
548
+ var ESCAPE_MAP = {
549
+ "&": "&amp;",
550
+ "<": "&lt;",
551
+ ">": "&gt;",
552
+ '"': "&quot;",
553
+ "'": "&#39;"
554
+ };
555
+ function escapeHtml(str) {
556
+ return String(str).replace(ESCAPE_RE, (ch) => ESCAPE_MAP[ch]);
557
+ }
558
+ function renderTokensToHtml(tokens) {
559
+ let html = "";
560
+ for (let i = 0; i < tokens.length; i++) {
561
+ const t = tokens[i];
562
+ if (t.type === "plain") {
563
+ html += escapeHtml(t.value);
564
+ } else {
565
+ html += '<span class="vd-tk-' + t.type + '">' + escapeHtml(t.value) + "</span>";
566
+ }
567
+ }
568
+ return html;
569
+ }
570
+ function highlight(source, language) {
571
+ const html = renderTokensToHtml(tokenize(source, language));
572
+ return source.endsWith("\n") || source === "" ? html + "\n" : html;
573
+ }
574
+ function renderTokensToDom(tokens, doc) {
575
+ const frag = doc.createDocumentFragment();
576
+ for (let i = 0; i < tokens.length; i++) {
577
+ const t = tokens[i];
578
+ if (t.type === "plain") {
579
+ frag.appendChild(doc.createTextNode(t.value));
580
+ } else {
581
+ const span = doc.createElement("span");
582
+ span.className = "vd-tk-" + t.type;
583
+ span.textContent = t.value;
584
+ frag.appendChild(span);
585
+ }
586
+ }
587
+ return frag;
588
+ }
589
+
590
+ // src/code-editor/constants.js
591
+ var DEFAULT_TAB_SIZE = 2;
592
+ var MAX_HIGHLIGHT_LENGTH = 1e5;
593
+ var AUTO_CLOSE_PAIRS = Object.freeze({
594
+ "(": ")",
595
+ "[": "]",
596
+ "{": "}",
597
+ '"': '"',
598
+ "'": "'",
599
+ "`": "`"
600
+ });
601
+ var OPENERS = Object.freeze(Object.keys(AUTO_CLOSE_PAIRS));
602
+ var CLOSERS = Object.freeze([")", "]", "}", '"', "'", "`"]);
603
+ function closerFor(ch) {
604
+ return AUTO_CLOSE_PAIRS[ch];
605
+ }
606
+ function isMatchingPair(open, close) {
607
+ return AUTO_CLOSE_PAIRS[open] === close;
608
+ }
609
+
610
+ // src/code-editor/editing.js
611
+ var CLOSER_SET = new Set(CLOSERS);
612
+ var WORD = /[\w$]/;
613
+ function indentOnEnter(value, start, end, unit) {
614
+ const lineStart = value.lastIndexOf("\n", start - 1) + 1;
615
+ const leading = /^[ \t]*/.exec(value.slice(lineStart, start))[0];
616
+ const prev = value[start - 1];
617
+ const next = value[end];
618
+ const opens = prev === "{" || prev === "[" || prev === "(";
619
+ if (opens && isMatchingPair(prev, next)) {
620
+ const inner = leading + unit;
621
+ const text2 = "\n" + inner + "\n" + leading;
622
+ const caret2 = start + 1 + inner.length;
623
+ return { from: start, to: end, text: text2, selectionStart: caret2, selectionEnd: caret2 };
624
+ }
625
+ const indent = opens ? leading + unit : leading;
626
+ const text = "\n" + indent;
627
+ const caret = start + text.length;
628
+ return { from: start, to: end, text, selectionStart: caret, selectionEnd: caret };
629
+ }
630
+ function handleTab(value, start, end, unit) {
631
+ if (start !== end && value.slice(start, end).indexOf("\n") !== -1) {
632
+ const from = value.lastIndexOf("\n", start - 1) + 1;
633
+ const block = value.slice(from, end);
634
+ const indented = block.replace(/^/gm, unit);
635
+ const added = indented.length - block.length;
636
+ return {
637
+ from,
638
+ to: end,
639
+ text: indented,
640
+ selectionStart: start + unit.length,
641
+ selectionEnd: end + added
642
+ };
643
+ }
644
+ return {
645
+ from: start,
646
+ to: end,
647
+ text: unit,
648
+ selectionStart: start + unit.length,
649
+ selectionEnd: start + unit.length
650
+ };
651
+ }
652
+ function handleShiftTab(value, start, end, unit) {
653
+ const from = value.lastIndexOf("\n", start - 1) + 1;
654
+ const size = unit.length || 1;
655
+ const lines = value.slice(from, end).split("\n");
656
+ let firstRemoved = 0;
657
+ let totalRemoved = 0;
658
+ const dedented = lines.map((line, idx) => {
659
+ let remove = 0;
660
+ while (remove < size && line[remove] === " ") remove++;
661
+ if (remove === 0 && line[0] === " ") remove = 1;
662
+ if (idx === 0) firstRemoved = remove;
663
+ totalRemoved += remove;
664
+ return line.slice(remove);
665
+ }).join("\n");
666
+ return {
667
+ from,
668
+ to: end,
669
+ text: dedented,
670
+ selectionStart: Math.max(from, start - firstRemoved),
671
+ selectionEnd: Math.max(from, end - totalRemoved)
672
+ };
673
+ }
674
+ function autoClosePair(char, value, start, end) {
675
+ const closer = closerFor(char);
676
+ if (!closer) return null;
677
+ if (start !== end) {
678
+ return {
679
+ from: start,
680
+ to: end,
681
+ text: char + value.slice(start, end) + closer,
682
+ selectionStart: start + 1,
683
+ selectionEnd: end + 1
684
+ };
685
+ }
686
+ const nextChar = value[start];
687
+ if (char === closer) {
688
+ if (nextChar && WORD.test(nextChar)) return null;
689
+ const prevChar = value[start - 1];
690
+ if (prevChar && WORD.test(prevChar)) return null;
691
+ } else if (nextChar && WORD.test(nextChar)) {
692
+ return null;
693
+ }
694
+ return {
695
+ from: start,
696
+ to: end,
697
+ text: char + closer,
698
+ selectionStart: start + 1,
699
+ selectionEnd: start + 1
700
+ };
701
+ }
702
+ function skipOverCloser(char, value, start, end) {
703
+ if (start !== end || !CLOSER_SET.has(char)) return null;
704
+ if (value[start] === char) {
705
+ return { caretOnly: true, selectionStart: start + 1, selectionEnd: start + 1 };
706
+ }
707
+ return null;
708
+ }
709
+ function handleBackspacePair(value, start, end) {
710
+ if (start !== end || start === 0) return null;
711
+ const prev = value[start - 1];
712
+ const next = value[start];
713
+ if (AUTO_CLOSE_PAIRS[prev] && AUTO_CLOSE_PAIRS[prev] === next) {
714
+ return {
715
+ from: start - 1,
716
+ to: start + 1,
717
+ text: "",
718
+ selectionStart: start - 1,
719
+ selectionEnd: start - 1
720
+ };
721
+ }
722
+ return null;
723
+ }
724
+
725
+ // src/code-editor/core.js
726
+ var VD_CODE_EDITOR_VERSION = "1.0.0";
727
+ var DEFAULTS = {
728
+ value: "",
729
+ language: "plaintext",
730
+ readOnly: false,
731
+ lineNumbers: true,
732
+ tabSize: DEFAULT_TAB_SIZE,
733
+ placeholder: "",
734
+ maxLength: void 0,
735
+ wrap: false,
736
+ autoClose: true,
737
+ highlightActiveLine: true,
738
+ maxHighlightLength: MAX_HIGHLIGHT_LENGTH,
739
+ spellcheck: false,
740
+ ariaLabel: "Code editor",
741
+ copy: true
742
+ };
743
+ var RAF = typeof window !== "undefined" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : (cb) => setTimeout(cb, 16);
744
+ var CAF = typeof window !== "undefined" && window.cancelAnimationFrame ? window.cancelAnimationFrame.bind(window) : clearTimeout;
745
+ function resolveElement(element) {
746
+ if (!element) return null;
747
+ if (typeof element === "string") {
748
+ return typeof document !== "undefined" ? document.querySelector(element) : null;
749
+ }
750
+ return element;
751
+ }
752
+ function countNewlines(str, end) {
753
+ let n = 0;
754
+ const limit = end == null ? str.length : end;
755
+ for (let i = 0; i < limit; i++) {
756
+ if (str.charCodeAt(i) === 10) n++;
757
+ }
758
+ return n;
759
+ }
760
+ var VdCodeEditor = class {
761
+ constructor(options = {}) {
762
+ this._opts = Object.assign({}, DEFAULTS, options);
763
+ this._listeners = /* @__PURE__ */ Object.create(null);
764
+ this._domListeners = [];
765
+ this._raf = 0;
766
+ this._ro = null;
767
+ this._copyTimer = 0;
768
+ this._destroyed = false;
769
+ this._lineHeight = 21;
770
+ this._paddingTop = 0;
771
+ this._gutterCount = -1;
772
+ this._lastValue = this._opts.value == null ? "" : String(this._opts.value);
773
+ this.element = resolveElement(options.element);
774
+ if (this.element) this._mount();
775
+ }
776
+ // ── mounting ──────────────────────────────────────────────────────────────
777
+ _mount() {
778
+ const el = this.element;
779
+ const doc = el.ownerDocument;
780
+ const opts = this._opts;
781
+ const showGutter = opts.lineNumbers && !opts.wrap;
782
+ const showActiveLine = opts.highlightActiveLine && !opts.wrap;
783
+ el.classList.add("vd-code-editor");
784
+ el.classList.toggle("is-wrap", !!opts.wrap);
785
+ el.classList.toggle("is-readonly", !!opts.readOnly);
786
+ el.classList.toggle("has-gutter", showGutter);
787
+ el.style.setProperty("--vd-code-editor-tab-size", String(opts.tabSize));
788
+ if (showActiveLine) {
789
+ this._activeLine = doc.createElement("div");
790
+ this._activeLine.className = "vd-code-editor-active-line";
791
+ this._activeLine.setAttribute("aria-hidden", "true");
792
+ el.appendChild(this._activeLine);
793
+ }
794
+ this._pre = doc.createElement("pre");
795
+ this._pre.className = "vd-code-editor-highlight";
796
+ this._pre.setAttribute("aria-hidden", "true");
797
+ this._code = doc.createElement("code");
798
+ this._code.className = "vd-code-editor-code";
799
+ this._pre.appendChild(this._code);
800
+ el.appendChild(this._pre);
801
+ if (showGutter) {
802
+ this._gutter = doc.createElement("div");
803
+ this._gutter.className = "vd-code-editor-gutter";
804
+ this._gutter.setAttribute("aria-hidden", "true");
805
+ this._gutterLines = doc.createElement("div");
806
+ this._gutterLines.className = "vd-code-editor-gutter-lines";
807
+ this._gutter.appendChild(this._gutterLines);
808
+ el.appendChild(this._gutter);
809
+ }
810
+ const ta = doc.createElement("textarea");
811
+ ta.className = "vd-code-editor-input";
812
+ ta.value = this._lastValue;
813
+ ta.spellcheck = !!opts.spellcheck;
814
+ ta.wrap = opts.wrap ? "soft" : "off";
815
+ ta.setAttribute("autocomplete", "off");
816
+ ta.setAttribute("autocapitalize", "off");
817
+ ta.setAttribute("autocorrect", "off");
818
+ ta.setAttribute("aria-label", opts.ariaLabel || "Code editor");
819
+ ta.setAttribute("aria-multiline", "true");
820
+ if (opts.readOnly) ta.readOnly = true;
821
+ if (opts.placeholder) ta.placeholder = opts.placeholder;
822
+ if (opts.maxLength != null) ta.maxLength = opts.maxLength;
823
+ ta.style.tabSize = String(opts.tabSize);
824
+ this._pre.style.tabSize = String(opts.tabSize);
825
+ this._textarea = ta;
826
+ el.appendChild(ta);
827
+ if (opts.copy && typeof navigator !== "undefined" && navigator.clipboard) {
828
+ const btn = doc.createElement("button");
829
+ btn.type = "button";
830
+ btn.className = "vd-code-editor-copy";
831
+ btn.setAttribute("aria-label", "Copy code");
832
+ btn.textContent = "Copy";
833
+ this._copyBtn = btn;
834
+ el.appendChild(btn);
835
+ }
836
+ this._attach();
837
+ this._measure();
838
+ this._repaint();
839
+ this._syncScroll();
840
+ }
841
+ _attach() {
842
+ const ta = this._textarea;
843
+ this._listen(ta, "input", () => this._handleInput());
844
+ this._listen(ta, "scroll", () => this._syncScroll());
845
+ this._listen(ta, "keydown", (e) => this._handleKeydown(e));
846
+ this._listen(ta, "focus", (e) => this._handleFocus(e));
847
+ this._listen(ta, "blur", (e) => this._handleBlur(e));
848
+ this._listen(ta, "click", () => this._updateActiveLine());
849
+ this._listen(ta, "keyup", () => this._updateActiveLine());
850
+ this._listen(ta, "select", () => this._updateActiveLine());
851
+ if (this._copyBtn) this._listen(this._copyBtn, "click", () => this._handleCopy());
852
+ if (typeof ResizeObserver === "function") {
853
+ this._ro = new ResizeObserver(() => {
854
+ this._measure();
855
+ this._syncScroll();
856
+ });
857
+ this._ro.observe(this.element);
858
+ }
859
+ const fonts = this.element.ownerDocument.fonts;
860
+ if (fonts && fonts.ready && typeof fonts.ready.then === "function") {
861
+ fonts.ready.then(() => {
862
+ if (this._destroyed) return;
863
+ this._measure();
864
+ this._syncScroll();
865
+ });
866
+ }
867
+ }
868
+ _listen(target, type, handler) {
869
+ target.addEventListener(type, handler);
870
+ this._domListeners.push([target, type, handler]);
871
+ }
872
+ // ── rendering ─────────────────────────────────────────────────────────────
873
+ _measure() {
874
+ if (typeof getComputedStyle !== "function") return;
875
+ const cs = getComputedStyle(this._textarea);
876
+ const lh = parseFloat(cs.lineHeight);
877
+ if (Number.isFinite(lh) && lh > 0) this._lineHeight = lh;
878
+ const pt = parseFloat(cs.paddingTop);
879
+ this._paddingTop = Number.isFinite(pt) ? pt : 0;
880
+ }
881
+ _scheduleRepaint() {
882
+ if (this._raf || this._destroyed) return;
883
+ this._raf = RAF(() => {
884
+ this._raf = 0;
885
+ if (!this._destroyed) this._repaint();
886
+ });
887
+ }
888
+ _repaint() {
889
+ const value = this._textarea.value;
890
+ const doc = this.element.ownerDocument;
891
+ const trailing = value.endsWith("\n") || value === "";
892
+ if (value.length > this._opts.maxHighlightLength) {
893
+ this._code.classList.add("is-plain");
894
+ this._code.replaceChildren(doc.createTextNode(trailing ? value + "\n" : value));
895
+ } else {
896
+ this._code.classList.remove("is-plain");
897
+ const frag = renderTokensToDom(tokenize(value, this._opts.language), doc);
898
+ if (trailing) frag.appendChild(doc.createTextNode("\n"));
899
+ this._code.replaceChildren(frag);
900
+ }
901
+ this._updateGutter(value);
902
+ }
903
+ _updateGutter(value) {
904
+ if (!this._gutterLines) return;
905
+ const lines = countNewlines(value) + 1;
906
+ if (lines === this._gutterCount) return;
907
+ this._gutterCount = lines;
908
+ this.element.style.setProperty(
909
+ "--vd-code-editor-gutter-digits",
910
+ String(Math.max(2, String(lines).length))
911
+ );
912
+ let text = "1";
913
+ for (let i = 2; i <= lines; i++) text += "\n" + i;
914
+ this._gutterLines.textContent = text;
915
+ }
916
+ _syncScroll() {
917
+ const ta = this._textarea;
918
+ if (!ta) return;
919
+ const st = ta.scrollTop;
920
+ if (this._pre) {
921
+ this._pre.scrollTop = st;
922
+ this._pre.scrollLeft = ta.scrollLeft;
923
+ }
924
+ if (this._gutterLines) {
925
+ this._gutterLines.style.transform = "translateY(" + -st + "px)";
926
+ }
927
+ this._updateActiveLine();
928
+ }
929
+ _updateActiveLine() {
930
+ if (!this._activeLine) return;
931
+ const ta = this._textarea;
932
+ const line = countNewlines(ta.value, ta.selectionStart || 0);
933
+ const top = this._paddingTop + line * this._lineHeight - ta.scrollTop;
934
+ this._activeLine.style.height = this._lineHeight + "px";
935
+ this._activeLine.style.transform = "translateY(" + top + "px)";
936
+ }
937
+ // ── input + keymap ────────────────────────────────────────────────────────
938
+ _handleInput() {
939
+ this._scheduleRepaint();
940
+ this._syncScroll();
941
+ this._emitChangeIfChanged();
942
+ }
943
+ _emitChangeIfChanged() {
944
+ const v = this._textarea.value;
945
+ if (v === this._lastValue) return;
946
+ this._lastValue = v;
947
+ this._emit("change", { value: v });
948
+ }
949
+ _handleFocus(e) {
950
+ this.element.classList.add("is-focused");
951
+ this._emit("focus", e);
952
+ }
953
+ _handleBlur(e) {
954
+ this.element.classList.remove("is-focused");
955
+ this._emit("blur", e);
956
+ }
957
+ _handleKeydown(e) {
958
+ if (this._opts.readOnly || e.isComposing) return;
959
+ if (e.ctrlKey || e.metaKey || e.altKey) return;
960
+ const ta = this._textarea;
961
+ const value = ta.value;
962
+ const s = ta.selectionStart;
963
+ const en = ta.selectionEnd;
964
+ const unit = " ".repeat(this._opts.tabSize);
965
+ if (e.key === "Enter") {
966
+ e.preventDefault();
967
+ this._applyEdit(indentOnEnter(value, s, en, unit));
968
+ return;
969
+ }
970
+ if (e.key === "Tab") {
971
+ e.preventDefault();
972
+ this._applyEdit(
973
+ e.shiftKey ? handleShiftTab(value, s, en, unit) : handleTab(value, s, en, unit)
974
+ );
975
+ return;
976
+ }
977
+ if (e.key === "Backspace") {
978
+ const edit = handleBackspacePair(value, s, en);
979
+ if (edit) {
980
+ e.preventDefault();
981
+ this._applyEdit(edit);
982
+ }
983
+ return;
984
+ }
985
+ if (e.key.length === 1 && this._opts.autoClose) {
986
+ const skip = skipOverCloser(e.key, value, s, en);
987
+ if (skip) {
988
+ e.preventDefault();
989
+ ta.setSelectionRange(skip.selectionStart, skip.selectionEnd);
990
+ this._updateActiveLine();
991
+ return;
992
+ }
993
+ const auto = autoClosePair(e.key, value, s, en);
994
+ if (auto) {
995
+ e.preventDefault();
996
+ this._applyEdit(auto);
997
+ }
998
+ }
999
+ }
1000
+ // Apply an edit, preferring execCommand so the native undo stack is preserved;
1001
+ // fall back to setRangeText, then to a direct value splice (jsdom/old engines).
1002
+ _applyEdit(edit) {
1003
+ const ta = this._textarea;
1004
+ ta.setSelectionRange(edit.from, edit.to);
1005
+ let nativeInput = false;
1006
+ if (this._tryExecInsert(edit.text)) {
1007
+ nativeInput = true;
1008
+ } else if (typeof ta.setRangeText === "function") {
1009
+ ta.setRangeText(edit.text, edit.from, edit.to, "end");
1010
+ } else {
1011
+ ta.value = ta.value.slice(0, edit.from) + edit.text + ta.value.slice(edit.to);
1012
+ }
1013
+ if (edit.selectionStart != null) {
1014
+ const end = edit.selectionEnd == null ? edit.selectionStart : edit.selectionEnd;
1015
+ ta.setSelectionRange(edit.selectionStart, end);
1016
+ }
1017
+ if (nativeInput) {
1018
+ this._updateActiveLine();
1019
+ } else {
1020
+ this._handleInput();
1021
+ }
1022
+ }
1023
+ _tryExecInsert(text) {
1024
+ try {
1025
+ return typeof document !== "undefined" && typeof document.execCommand === "function" && document.execCommand("insertText", false, text);
1026
+ } catch {
1027
+ return false;
1028
+ }
1029
+ }
1030
+ _handleCopy() {
1031
+ if (this._destroyed || typeof navigator === "undefined" || !navigator.clipboard) return;
1032
+ navigator.clipboard.writeText(this._textarea.value).then(
1033
+ () => this._flashCopied(),
1034
+ () => {
1035
+ }
1036
+ );
1037
+ }
1038
+ _flashCopied() {
1039
+ if (!this._copyBtn) return;
1040
+ this._copyBtn.classList.add("is-copied");
1041
+ this._copyBtn.textContent = "Copied";
1042
+ if (this._copyTimer) clearTimeout(this._copyTimer);
1043
+ this._copyTimer = setTimeout(() => {
1044
+ this._copyTimer = 0;
1045
+ if (this._destroyed || !this._copyBtn) return;
1046
+ this._copyBtn.classList.remove("is-copied");
1047
+ this._copyBtn.textContent = "Copy";
1048
+ }, 1200);
1049
+ }
1050
+ // ── public API ────────────────────────────────────────────────────────────
1051
+ getValue() {
1052
+ return this._textarea ? this._textarea.value : this._lastValue;
1053
+ }
1054
+ setValue(next, options) {
1055
+ const silent = !!(options && options.silent);
1056
+ const v = next == null ? "" : String(next);
1057
+ if (!this._textarea) {
1058
+ this._lastValue = v;
1059
+ return this;
1060
+ }
1061
+ if (v === this._textarea.value) return this;
1062
+ this._textarea.value = v;
1063
+ if (silent) this._lastValue = v;
1064
+ this._repaint();
1065
+ this._syncScroll();
1066
+ if (!silent) this._emitChangeIfChanged();
1067
+ return this;
1068
+ }
1069
+ getSelection() {
1070
+ const ta = this._textarea;
1071
+ if (!ta) return { start: 0, end: 0, text: "" };
1072
+ return {
1073
+ start: ta.selectionStart,
1074
+ end: ta.selectionEnd,
1075
+ text: ta.value.slice(ta.selectionStart, ta.selectionEnd)
1076
+ };
1077
+ }
1078
+ setSelection(start, end) {
1079
+ if (!this._textarea) return this;
1080
+ const e = end == null ? start : end;
1081
+ this._textarea.setSelectionRange(start, e);
1082
+ this._updateActiveLine();
1083
+ return this;
1084
+ }
1085
+ insertText(text) {
1086
+ if (!this._textarea) return this;
1087
+ const ta = this._textarea;
1088
+ const str = String(text);
1089
+ this._applyEdit({
1090
+ from: ta.selectionStart,
1091
+ to: ta.selectionEnd,
1092
+ text: str,
1093
+ selectionStart: ta.selectionStart + str.length
1094
+ });
1095
+ return this;
1096
+ }
1097
+ setLanguage(language) {
1098
+ this._opts.language = language || "plaintext";
1099
+ if (this._textarea) this._repaint();
1100
+ return this;
1101
+ }
1102
+ setReadOnly(readOnly) {
1103
+ this._opts.readOnly = !!readOnly;
1104
+ if (this._textarea) this._textarea.readOnly = !!readOnly;
1105
+ if (this.element) this.element.classList.toggle("is-readonly", !!readOnly);
1106
+ return this;
1107
+ }
1108
+ setTabSize(tabSize) {
1109
+ const n = Number(tabSize) || DEFAULT_TAB_SIZE;
1110
+ this._opts.tabSize = n;
1111
+ if (this._textarea) this._textarea.style.tabSize = String(n);
1112
+ if (this._pre) this._pre.style.tabSize = String(n);
1113
+ if (this.element) this.element.style.setProperty("--vd-code-editor-tab-size", String(n));
1114
+ return this;
1115
+ }
1116
+ setPlaceholder(text) {
1117
+ this._opts.placeholder = text || "";
1118
+ if (this._textarea) this._textarea.placeholder = text || "";
1119
+ return this;
1120
+ }
1121
+ setAutoClose(autoClose) {
1122
+ this._opts.autoClose = !!autoClose;
1123
+ return this;
1124
+ }
1125
+ focus() {
1126
+ if (this._textarea) this._textarea.focus();
1127
+ return this;
1128
+ }
1129
+ blur() {
1130
+ if (this._textarea) this._textarea.blur();
1131
+ return this;
1132
+ }
1133
+ on(name, handler) {
1134
+ if (!this._listeners[name]) this._listeners[name] = [];
1135
+ this._listeners[name].push(handler);
1136
+ return this;
1137
+ }
1138
+ off(name, handler) {
1139
+ const list = this._listeners[name];
1140
+ if (!list) return this;
1141
+ const i = list.indexOf(handler);
1142
+ if (i !== -1) list.splice(i, 1);
1143
+ return this;
1144
+ }
1145
+ _emit(name, payload) {
1146
+ const list = this._listeners[name];
1147
+ if (!list) return;
1148
+ for (let i = 0; i < list.length; i++) list[i](payload);
1149
+ }
1150
+ destroy() {
1151
+ if (this._destroyed) return;
1152
+ this._destroyed = true;
1153
+ if (this._raf) CAF(this._raf);
1154
+ if (this._copyTimer) clearTimeout(this._copyTimer);
1155
+ if (this._ro) {
1156
+ this._ro.disconnect();
1157
+ this._ro = null;
1158
+ }
1159
+ for (let i = 0; i < this._domListeners.length; i++) {
1160
+ const [target, type, handler] = this._domListeners[i];
1161
+ target.removeEventListener(type, handler);
1162
+ }
1163
+ this._domListeners = [];
1164
+ if (this.element) {
1165
+ const nodes = [this._activeLine, this._pre, this._gutter, this._textarea, this._copyBtn];
1166
+ for (let i = 0; i < nodes.length; i++) {
1167
+ const n = nodes[i];
1168
+ if (n && n.parentNode === this.element) this.element.removeChild(n);
1169
+ }
1170
+ this.element.classList.remove(
1171
+ "vd-code-editor",
1172
+ "is-wrap",
1173
+ "is-readonly",
1174
+ "has-gutter",
1175
+ "is-focused"
1176
+ );
1177
+ }
1178
+ this._listeners = /* @__PURE__ */ Object.create(null);
1179
+ this._textarea = null;
1180
+ this._pre = null;
1181
+ this._code = null;
1182
+ this._gutter = null;
1183
+ this._gutterLines = null;
1184
+ this._activeLine = null;
1185
+ this._copyBtn = null;
1186
+ }
1187
+ };
1188
+
1189
+ // src/code-editor/vue.js
1190
+ var VdCodeEditor2 = defineComponent({
1191
+ name: "VdCodeEditor",
1192
+ props: {
1193
+ /** Editor contents (v-model). */
1194
+ modelValue: { type: String, default: "" },
1195
+ /** Syntax language id or alias (e.g. `js`, `python`, `plaintext`). */
1196
+ language: { type: String, default: "plaintext" },
1197
+ /** Render as a non-editable viewer (copy still works). */
1198
+ readOnly: { type: Boolean, default: false },
1199
+ /** Show the line-number gutter (ignored in wrap mode). */
1200
+ lineNumbers: { type: Boolean, default: true },
1201
+ /** Indent width, in spaces. */
1202
+ tabSize: { type: Number, default: 2 },
1203
+ /** Empty-state placeholder text. */
1204
+ placeholder: { type: String, default: "" },
1205
+ /** Native `maxlength` cap on the content. */
1206
+ maxLength: { type: Number, default: void 0 },
1207
+ /** Soft-wrap long lines (disables the gutter + active-line). */
1208
+ wrap: { type: Boolean, default: false },
1209
+ /** Auto-close brackets/quotes and step over closers. */
1210
+ autoClose: { type: Boolean, default: true },
1211
+ /** Highlight the caret's line (ignored in wrap mode). */
1212
+ highlightActiveLine: { type: Boolean, default: true },
1213
+ /** Skip highlighting above this many characters (perf guard). */
1214
+ maxHighlightLength: { type: Number, default: 1e5 },
1215
+ /** Native spellcheck on the textarea. */
1216
+ spellcheck: { type: Boolean, default: false },
1217
+ /** Show the copy-to-clipboard button (when the clipboard API exists). */
1218
+ copy: { type: Boolean, default: true },
1219
+ /** Accessible label for the textarea. */
1220
+ ariaLabel: { type: String, default: "Code editor" }
1221
+ },
1222
+ emits: ["update:modelValue", "change", "focus", "blur", "ready"],
1223
+ setup(props, { emit, expose }) {
1224
+ const el = ref(null);
1225
+ let instance = null;
1226
+ const create = () => {
1227
+ instance = new VdCodeEditor({
1228
+ element: el.value,
1229
+ value: props.modelValue,
1230
+ language: props.language,
1231
+ readOnly: props.readOnly,
1232
+ lineNumbers: props.lineNumbers,
1233
+ tabSize: props.tabSize,
1234
+ placeholder: props.placeholder,
1235
+ maxLength: props.maxLength,
1236
+ wrap: props.wrap,
1237
+ autoClose: props.autoClose,
1238
+ highlightActiveLine: props.highlightActiveLine,
1239
+ maxHighlightLength: props.maxHighlightLength,
1240
+ spellcheck: props.spellcheck,
1241
+ copy: props.copy,
1242
+ ariaLabel: props.ariaLabel
1243
+ });
1244
+ instance.on("change", (payload) => {
1245
+ emit("update:modelValue", payload.value);
1246
+ emit("change", payload.value);
1247
+ });
1248
+ instance.on("focus", (e) => emit("focus", e));
1249
+ instance.on("blur", (e) => emit("blur", e));
1250
+ emit("ready", instance);
1251
+ };
1252
+ const teardown = () => {
1253
+ if (instance) {
1254
+ instance.destroy();
1255
+ instance = null;
1256
+ }
1257
+ };
1258
+ onMounted(() => {
1259
+ if (typeof window === "undefined" || !el.value) return;
1260
+ create();
1261
+ });
1262
+ watch(
1263
+ () => props.modelValue,
1264
+ (next) => {
1265
+ if (instance && next !== instance.getValue()) instance.setValue(next, { silent: true });
1266
+ }
1267
+ );
1268
+ watch(
1269
+ () => props.language,
1270
+ (v) => instance && instance.setLanguage(v)
1271
+ );
1272
+ watch(
1273
+ () => props.readOnly,
1274
+ (v) => instance && instance.setReadOnly(v)
1275
+ );
1276
+ watch(
1277
+ () => props.tabSize,
1278
+ (v) => instance && instance.setTabSize(v)
1279
+ );
1280
+ watch(
1281
+ () => props.placeholder,
1282
+ (v) => instance && instance.setPlaceholder(v)
1283
+ );
1284
+ watch(
1285
+ () => props.autoClose,
1286
+ (v) => instance && instance.setAutoClose(v)
1287
+ );
1288
+ watch(
1289
+ () => [
1290
+ props.lineNumbers,
1291
+ props.wrap,
1292
+ props.highlightActiveLine,
1293
+ props.spellcheck,
1294
+ props.maxLength,
1295
+ props.maxHighlightLength,
1296
+ props.copy,
1297
+ props.ariaLabel
1298
+ ],
1299
+ () => {
1300
+ if (!instance) return;
1301
+ teardown();
1302
+ create();
1303
+ }
1304
+ );
1305
+ onBeforeUnmount(teardown);
1306
+ expose({
1307
+ getInstance: () => instance,
1308
+ focus: () => instance && instance.focus(),
1309
+ blur: () => instance && instance.blur(),
1310
+ getValue: () => instance ? instance.getValue() : props.modelValue,
1311
+ setValue: (value) => instance && instance.setValue(value),
1312
+ getSelection: () => instance ? instance.getSelection() : { start: 0, end: 0, text: "" },
1313
+ setSelection: (start, end) => instance && instance.setSelection(start, end),
1314
+ insertText: (text) => instance && instance.insertText(text),
1315
+ getContainer: () => el.value
1316
+ });
1317
+ return () => h("div", { ref: el, class: "vd-code-editor" });
1318
+ }
1319
+ });
1320
+ export {
1321
+ LANGUAGES,
1322
+ VD_CODE_EDITOR_VERSION,
1323
+ VdCodeEditor2 as VdCodeEditor,
1324
+ VdCodeEditor as VdCodeEditorCore,
1325
+ highlight,
1326
+ tokenize
1327
+ };
1328
+ //# sourceMappingURL=index.js.map