@duskmoon-dev/el-code-engine 1.1.2 → 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.
package/dist/esm/index.js CHANGED
@@ -11,6 +11,7 @@ import { BaseElement, css } from "@duskmoon-dev/el-base";
11
11
  import { EditorView } from "@duskmoon-dev/code-engine/view";
12
12
  import { EditorState, Compartment } from "@duskmoon-dev/code-engine/state";
13
13
  import { basicSetup } from "@duskmoon-dev/code-engine/setup";
14
+ import { undo, redo } from "@duskmoon-dev/code-engine/commands";
14
15
  import * as _duskmoonTheme from "@duskmoon-dev/code-engine/theme/duskmoon";
15
16
  import * as _sunshineTheme from "@duskmoon-dev/code-engine/theme/sunshine";
16
17
  import * as _moonlightTheme from "@duskmoon-dev/code-engine/theme/moonlight";
@@ -70,6 +71,75 @@ var LANG_LOADERS = {
70
71
  lezer: langLoader(() => import("@duskmoon-dev/code-engine/lang/lezer")),
71
72
  caddyfile: langLoader(() => import("@duskmoon-dev/code-engine/lang/caddyfile"))
72
73
  };
74
+ var LANG_BADGES = {
75
+ javascript: "JS",
76
+ typescript: "TS",
77
+ python: "PY",
78
+ rust: "RS",
79
+ go: "GO",
80
+ java: "JAVA",
81
+ cpp: "C++",
82
+ html: "HTML",
83
+ css: "CSS",
84
+ json: "JSON",
85
+ markdown: "MD",
86
+ sql: "SQL",
87
+ yaml: "YAML",
88
+ xml: "XML",
89
+ php: "PHP",
90
+ elixir: "EX",
91
+ erlang: "ERL",
92
+ heex: "HEEX",
93
+ dart: "DART",
94
+ zig: "ZIG",
95
+ vue: "VUE",
96
+ angular: "NG",
97
+ sass: "SASS",
98
+ less: "LESS",
99
+ wast: "WAST",
100
+ lezer: "LEZER",
101
+ caddyfile: "CADDY",
102
+ jinja: "JINJA",
103
+ liquid: "LIQUID"
104
+ };
105
+ var LANG_NAMES = {
106
+ javascript: "JavaScript",
107
+ typescript: "TypeScript",
108
+ python: "Python",
109
+ rust: "Rust",
110
+ go: "Go",
111
+ java: "Java",
112
+ cpp: "C++",
113
+ html: "HTML",
114
+ css: "CSS",
115
+ json: "JSON",
116
+ markdown: "Markdown",
117
+ sql: "SQL",
118
+ yaml: "YAML",
119
+ xml: "XML",
120
+ php: "PHP",
121
+ elixir: "Elixir",
122
+ erlang: "Erlang",
123
+ heex: "HEEx",
124
+ dart: "Dart",
125
+ zig: "Zig",
126
+ vue: "Vue",
127
+ angular: "Angular",
128
+ sass: "Sass",
129
+ less: "Less",
130
+ wast: "WAT",
131
+ lezer: "Lezer",
132
+ caddyfile: "Caddyfile",
133
+ jinja: "Jinja",
134
+ liquid: "Liquid"
135
+ };
136
+ var ICON_UNDO = `<svg viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/></svg>`;
137
+ var ICON_REDO = `<svg viewBox="0 0 24 24"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg>`;
138
+ var ICON_WRAP = `<svg viewBox="0 0 24 24"><line x1="3" y1="6" x2="21" y2="6"/><path d="M3 12h15a3 3 0 1 1 0 6h-4"/><polyline points="16 16 14 18 16 20"/><line x1="3" y1="18" x2="10" y2="18"/></svg>`;
139
+ var ICON_COPY = `<svg viewBox="0 0 24 24"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>`;
140
+ var ICON_CHECK = `<svg viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg>`;
141
+ var ICON_FULLSCREEN = `<svg viewBox="0 0 24 24"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>`;
142
+ var ICON_EXIT_FULLSCREEN = `<svg viewBox="0 0 24 24"><polyline points="4 14 10 14 10 20"/><polyline points="20 10 14 10 14 4"/><line x1="14" y1="10" x2="21" y2="3"/><line x1="3" y1="21" x2="10" y2="14"/></svg>`;
73
143
  var styles = css`
74
144
  :host {
75
145
  display: block;
@@ -101,6 +171,129 @@ var styles = css`
101
171
  .cm-host .cm-editor.cm-focused {
102
172
  outline: none;
103
173
  }
174
+
175
+ /* ── Topbar ────────────────────────────────────────── */
176
+
177
+ .topbar {
178
+ display: none;
179
+ }
180
+
181
+ :host([show-topbar]) .topbar {
182
+ display: flex;
183
+ align-items: center;
184
+ justify-content: space-between;
185
+ gap: 0.5rem;
186
+ padding: 0.375rem 0.75rem;
187
+ border-bottom: 1px solid var(--dm-border, #e0e0e0);
188
+ background: var(--dm-surface-container, #f0f0f0);
189
+ font-size: 0.75rem;
190
+ color: var(--dm-on-surface, #1a1a1a);
191
+ }
192
+
193
+ .topbar-left {
194
+ display: flex;
195
+ align-items: center;
196
+ gap: 0.5rem;
197
+ min-width: 0;
198
+ }
199
+
200
+ .topbar-right {
201
+ display: flex;
202
+ align-items: center;
203
+ gap: 0.25rem;
204
+ }
205
+
206
+ .lang-badge {
207
+ padding: 0.0625rem 0.375rem;
208
+ border-radius: var(--dm-radius-sm, 0.25rem);
209
+ background: var(--dm-primary, #6750a4);
210
+ color: var(--dm-on-primary, #fff);
211
+ font-size: 0.625rem;
212
+ font-weight: 600;
213
+ text-transform: uppercase;
214
+ letter-spacing: 0.025em;
215
+ }
216
+
217
+ .topbar-title {
218
+ opacity: 0.7;
219
+ font-size: 0.6875rem;
220
+ white-space: nowrap;
221
+ overflow: hidden;
222
+ text-overflow: ellipsis;
223
+ }
224
+
225
+ .bar-btn {
226
+ display: inline-flex;
227
+ align-items: center;
228
+ justify-content: center;
229
+ width: 1.5rem;
230
+ height: 1.5rem;
231
+ padding: 0;
232
+ border: none;
233
+ border-radius: var(--dm-radius-sm, 0.25rem);
234
+ background: transparent;
235
+ color: var(--dm-on-surface-variant, #555);
236
+ font-family: inherit;
237
+ font-size: 0.75rem;
238
+ cursor: pointer;
239
+ transition:
240
+ background 0.15s,
241
+ color 0.15s;
242
+ }
243
+
244
+ .bar-btn:hover {
245
+ background: var(--dm-surface-container-high, #e0e0e0);
246
+ color: var(--dm-on-surface, #1a1a1a);
247
+ }
248
+
249
+ .bar-btn svg {
250
+ width: 14px;
251
+ height: 14px;
252
+ fill: none;
253
+ stroke: currentColor;
254
+ stroke-width: 2;
255
+ stroke-linecap: round;
256
+ stroke-linejoin: round;
257
+ }
258
+
259
+ /* ── Bottombar ─────────────────────────────────────── */
260
+
261
+ .bottombar {
262
+ display: none;
263
+ }
264
+
265
+ :host([show-bottombar]) .bottombar {
266
+ display: flex;
267
+ align-items: center;
268
+ justify-content: space-between;
269
+ padding: 0.25rem 0.75rem;
270
+ border-top: 1px solid var(--dm-border, #e0e0e0);
271
+ background: var(--dm-surface-container-high, #e0e0e0);
272
+ font-size: 0.625rem;
273
+ color: var(--dm-on-surface-variant, #555);
274
+ }
275
+
276
+ .bottombar-left,
277
+ .bottombar-right {
278
+ display: flex;
279
+ align-items: center;
280
+ gap: 0.75rem;
281
+ }
282
+
283
+ /* ── Fullscreen ────────────────────────────────────── */
284
+
285
+ :host(.fullscreen) {
286
+ position: fixed !important;
287
+ inset: 0 !important;
288
+ z-index: 9999 !important;
289
+ min-height: 100vh !important;
290
+ display: flex;
291
+ flex-direction: column;
292
+ }
293
+
294
+ :host(.fullscreen) .cm-host {
295
+ flex: 1;
296
+ }
104
297
  `;
105
298
 
106
299
  class ElDmCodeEngine extends BaseElement {
@@ -108,7 +301,10 @@ class ElDmCodeEngine extends BaseElement {
108
301
  language: { type: String, reflect: true },
109
302
  readonly: { type: Boolean, reflect: true },
110
303
  theme: { type: String, reflect: true, default: "duskmoon" },
111
- wrap: { type: Boolean, reflect: true }
304
+ wrap: { type: Boolean, reflect: true },
305
+ showTopbar: { type: Boolean, reflect: true },
306
+ showBottombar: { type: Boolean, reflect: true },
307
+ title: { type: String, reflect: true }
112
308
  };
113
309
  #editor = null;
114
310
  #pendingValue = null;
@@ -117,6 +313,11 @@ class ElDmCodeEngine extends BaseElement {
117
313
  #themeCompartment = new Compartment;
118
314
  #wrapCompartment = new Compartment;
119
315
  #langCache = new Map;
316
+ #cursorLine = 1;
317
+ #cursorCol = 1;
318
+ #lineCount = 0;
319
+ #isFullscreen = false;
320
+ #copyTimer = null;
120
321
  constructor() {
121
322
  super();
122
323
  this.attachStyles(styles);
@@ -143,7 +344,7 @@ class ElDmCodeEngine extends BaseElement {
143
344
  this.value = v;
144
345
  }
145
346
  render() {
146
- return '<div class="cm-host" part="editor"></div>';
347
+ return `${this.#renderTopbar()}<div class="cm-host" part="editor"></div>${this.#renderBottombar()}`;
147
348
  }
148
349
  update() {
149
350
  if (!this.#editor) {
@@ -153,7 +354,24 @@ class ElDmCodeEngine extends BaseElement {
153
354
  this.#applyConfig();
154
355
  }
155
356
  }
357
+ #clickHandler = (e) => {
358
+ const btn = e.target?.closest("[data-action]");
359
+ if (btn) {
360
+ const action = btn.getAttribute("data-action");
361
+ if (action)
362
+ this.#handleBarAction(action);
363
+ }
364
+ };
365
+ connectedCallback() {
366
+ super.connectedCallback();
367
+ this.shadowRoot.addEventListener("click", this.#clickHandler);
368
+ }
156
369
  disconnectedCallback() {
370
+ this.shadowRoot.removeEventListener("click", this.#clickHandler);
371
+ if (this.#copyTimer) {
372
+ clearTimeout(this.#copyTimer);
373
+ this.#copyTimer = null;
374
+ }
157
375
  if (this.#editor) {
158
376
  this.#pendingValue = this.#editor.state.doc.toString();
159
377
  this.#editor.destroy();
@@ -161,6 +379,110 @@ class ElDmCodeEngine extends BaseElement {
161
379
  }
162
380
  super.disconnectedCallback();
163
381
  }
382
+ #renderTopbar() {
383
+ const badge = this.language ? `<span class="lang-badge">${LANG_BADGES[this.language] ?? this.language.toUpperCase()}</span>` : "";
384
+ const t = this.title;
385
+ const title = t ? `<span class="topbar-title">${t}</span>` : "";
386
+ return `
387
+ <div class="topbar" part="topbar">
388
+ <slot name="topbar">
389
+ <div class="topbar-left">${badge}${title}</div>
390
+ <div class="topbar-right">
391
+ <button class="bar-btn" data-action="undo" title="Undo">${ICON_UNDO}</button>
392
+ <button class="bar-btn" data-action="redo" title="Redo">${ICON_REDO}</button>
393
+ <button class="bar-btn" data-action="wrap" title="Toggle line wrap">${ICON_WRAP}</button>
394
+ <button class="bar-btn" data-action="copy" title="Copy">${ICON_COPY}</button>
395
+ <button class="bar-btn" data-action="fullscreen" title="Toggle fullscreen">${this.#isFullscreen ? ICON_EXIT_FULLSCREEN : ICON_FULLSCREEN}</button>
396
+ </div>
397
+ </slot>
398
+ </div>
399
+ `;
400
+ }
401
+ #renderBottombar() {
402
+ const langName = this.language ? LANG_NAMES[this.language] ?? this.language : "";
403
+ return `
404
+ <div class="bottombar" part="bottombar">
405
+ <slot name="bottombar">
406
+ <div class="bottombar-left">
407
+ <span class="cursor-pos">Ln ${this.#cursorLine}, Col ${this.#cursorCol}</span>
408
+ <span class="line-count">${this.#lineCount} lines</span>
409
+ </div>
410
+ <div class="bottombar-right">
411
+ <span>UTF-8</span>
412
+ ${langName ? `<span>${langName}</span>` : ""}
413
+ </div>
414
+ </slot>
415
+ </div>
416
+ `;
417
+ }
418
+ #handleBarAction(action) {
419
+ switch (action) {
420
+ case "undo":
421
+ if (this.#editor)
422
+ undo(this.#editor);
423
+ break;
424
+ case "redo":
425
+ if (this.#editor)
426
+ redo(this.#editor);
427
+ break;
428
+ case "wrap":
429
+ this.wrap = !this.wrap;
430
+ break;
431
+ case "copy":
432
+ this.#handleCopy();
433
+ break;
434
+ case "fullscreen":
435
+ this.#toggleFullscreen();
436
+ break;
437
+ }
438
+ }
439
+ async#handleCopy() {
440
+ const value = this.value;
441
+ try {
442
+ await navigator.clipboard.writeText(value);
443
+ } catch {
444
+ return;
445
+ }
446
+ this.emit("copy", { value });
447
+ this.#showCopyFeedback();
448
+ }
449
+ #showCopyFeedback() {
450
+ const btn = this.shadowRoot?.querySelector('[data-action="copy"]');
451
+ if (!btn)
452
+ return;
453
+ if (this.#copyTimer)
454
+ clearTimeout(this.#copyTimer);
455
+ btn.innerHTML = ICON_CHECK;
456
+ btn.setAttribute("title", "Copied!");
457
+ this.#copyTimer = setTimeout(() => {
458
+ btn.innerHTML = ICON_COPY;
459
+ btn.setAttribute("title", "Copy");
460
+ this.#copyTimer = null;
461
+ }, 2000);
462
+ }
463
+ #toggleFullscreen() {
464
+ this.#isFullscreen = !this.#isFullscreen;
465
+ this.classList.toggle("fullscreen", this.#isFullscreen);
466
+ const btn = this.shadowRoot?.querySelector('[data-action="fullscreen"]');
467
+ if (btn) {
468
+ btn.innerHTML = this.#isFullscreen ? ICON_EXIT_FULLSCREEN : ICON_FULLSCREEN;
469
+ btn.setAttribute("title", this.#isFullscreen ? "Exit fullscreen" : "Toggle fullscreen");
470
+ }
471
+ this.emit("fullscreen", { active: this.#isFullscreen });
472
+ }
473
+ #updateCursorInfo(state) {
474
+ const pos = state.selection.main.head;
475
+ const line = state.doc.lineAt(pos);
476
+ this.#cursorLine = line.number;
477
+ this.#cursorCol = pos - line.from + 1;
478
+ this.#lineCount = state.doc.lines;
479
+ const cursorEl = this.shadowRoot?.querySelector(".cursor-pos");
480
+ const lineCountEl = this.shadowRoot?.querySelector(".line-count");
481
+ if (cursorEl)
482
+ cursorEl.textContent = `Ln ${this.#cursorLine}, Col ${this.#cursorCol}`;
483
+ if (lineCountEl)
484
+ lineCountEl.textContent = `${this.#lineCount} lines`;
485
+ }
164
486
  async#mountEditor() {
165
487
  const host = this.shadowRoot?.querySelector(".cm-host");
166
488
  if (!host || this.#editor)
@@ -181,6 +503,9 @@ class ElDmCodeEngine extends BaseElement {
181
503
  if (update.docChanged) {
182
504
  this.emit("input", { value: update.state.doc.toString() });
183
505
  }
506
+ if (update.docChanged || update.selectionSet) {
507
+ this.#updateCursorInfo(update.state);
508
+ }
184
509
  }),
185
510
  EditorView.domEventHandlers({
186
511
  blur: () => {
@@ -193,6 +518,7 @@ class ElDmCodeEngine extends BaseElement {
193
518
  parent: host,
194
519
  root: this.shadowRoot
195
520
  });
521
+ this.#updateCursorInfo(this.#editor.state);
196
522
  }
197
523
  async#applyConfig() {
198
524
  if (!this.#editor)
@@ -239,5 +565,5 @@ export {
239
565
  ElDmCodeEngine
240
566
  };
241
567
 
242
- //# debugId=B8FEEBB401E9A3D064756E2164756E21
568
+ //# debugId=6C8C69AE44633C3064756E2164756E21
243
569
  //# sourceMappingURL=index.js.map
@@ -2,10 +2,10 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/el-dm-code-engine.ts", "../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * DuskMoon Code Engine Element\n *\n * A lightweight code editor backed by @duskmoon-dev/code-engine (CodeMirror 6 fork).\n * Behaves like a native <input> or <textarea>: the `value` attribute sets the initial\n * content, the `value` property always reflects the current content, and the element\n * fires `input` on every change and `change` on blur.\n *\n * @element el-dm-code-engine\n *\n * @attr {string} value - Initial editor content (read once at mount, like <input>)\n * @attr {string} language - Language name for syntax highlighting (e.g. \"javascript\", \"css\")\n * @attr {boolean} readonly - Whether the editor is read-only\n * @attr {string} theme - Editor theme: \"duskmoon\" | \"sunshine\" | \"moonlight\" | \"one-dark\"\n * @attr {boolean} wrap - Enable line wrapping\n *\n * @prop {string} value - Gets or sets current editor content\n *\n * @method focus() - Focuses the editor\n * @method getValue() - Returns current editor content\n * @method setValue(value: string) - Sets editor content programmatically\n *\n * @fires input - Fired on every document change, detail: { value: string }\n * @fires change - Fired when editor loses focus, detail: { value: string }\n *\n * @csspart editor - The CodeMirror mount container\n */\n\nimport { BaseElement, css } from '@duskmoon-dev/el-base';\nimport type { Extension } from '@duskmoon-dev/code-engine';\nimport { EditorView } from '@duskmoon-dev/code-engine/view';\nimport { EditorState, Compartment } from '@duskmoon-dev/code-engine/state';\nimport { basicSetup } from '@duskmoon-dev/code-engine/setup';\n\n// ── Static theme imports (all 4 are small; avoids runtime bare-specifier issues) ──\nimport * as _duskmoonTheme from '@duskmoon-dev/code-engine/theme/duskmoon';\nimport * as _sunshineTheme from '@duskmoon-dev/code-engine/theme/sunshine';\nimport * as _moonlightTheme from '@duskmoon-dev/code-engine/theme/moonlight';\nimport * as _oneDarkTheme from '@duskmoon-dev/code-engine/theme/one-dark';\n\nfunction extractExt(mod: Record<string, unknown>): Extension {\n const v =\n mod.default ??\n Object.values(mod).find((x) => typeof x === 'function' || (x && typeof x !== 'string'));\n // Theme modules export a factory function (e.g. duskMoon(options?))\n if (typeof v === 'function') return (v as () => Extension)() as Extension;\n return (v ?? []) as Extension;\n}\n\nconst THEMES: Record<string, Extension> = {\n duskmoon: extractExt(_duskmoonTheme as unknown as Record<string, unknown>),\n sunshine: extractExt(_sunshineTheme as unknown as Record<string, unknown>),\n moonlight: extractExt(_moonlightTheme as unknown as Record<string, unknown>),\n 'one-dark': extractExt(_oneDarkTheme as unknown as Record<string, unknown>),\n};\n\n// ── Language loaders (literal import paths so bundlers can resolve them) ──\n\nfunction langLoader(\n importFn: () => Promise<Record<string, unknown>>,\n opts?: Record<string, unknown>,\n): () => Promise<Extension | null> {\n return async () => {\n const mod = await importFn();\n const factory = mod.default ?? Object.values(mod).find((v) => typeof v === 'function');\n if (typeof factory === 'function') {\n return (opts ? factory(opts) : factory()) as Extension;\n }\n return factory as Extension | null;\n };\n}\n\nconst LANG_LOADERS: Record<string, () => Promise<Extension | null>> = {\n javascript: langLoader(() => import('@duskmoon-dev/code-engine/lang/javascript')),\n typescript: langLoader(() => import('@duskmoon-dev/code-engine/lang/javascript'), {\n typescript: true,\n }),\n css: langLoader(() => import('@duskmoon-dev/code-engine/lang/css')),\n html: langLoader(() => import('@duskmoon-dev/code-engine/lang/html')),\n json: langLoader(() => import('@duskmoon-dev/code-engine/lang/json')),\n python: langLoader(() => import('@duskmoon-dev/code-engine/lang/python')),\n markdown: langLoader(() => import('@duskmoon-dev/code-engine/lang/markdown')),\n xml: langLoader(() => import('@duskmoon-dev/code-engine/lang/xml')),\n sql: langLoader(() => import('@duskmoon-dev/code-engine/lang/sql')),\n rust: langLoader(() => import('@duskmoon-dev/code-engine/lang/rust')),\n go: langLoader(() => import('@duskmoon-dev/code-engine/lang/go')),\n java: langLoader(() => import('@duskmoon-dev/code-engine/lang/java')),\n cpp: langLoader(() => import('@duskmoon-dev/code-engine/lang/cpp')),\n php: langLoader(() => import('@duskmoon-dev/code-engine/lang/php')),\n yaml: langLoader(() => import('@duskmoon-dev/code-engine/lang/yaml')),\n sass: langLoader(() => import('@duskmoon-dev/code-engine/lang/sass')),\n less: langLoader(() => import('@duskmoon-dev/code-engine/lang/less')),\n elixir: langLoader(() => import('@duskmoon-dev/code-engine/lang/elixir')),\n erlang: langLoader(() => import('@duskmoon-dev/code-engine/lang/erlang')),\n heex: langLoader(() => import('@duskmoon-dev/code-engine/lang/heex')),\n dart: langLoader(() => import('@duskmoon-dev/code-engine/lang/dart')),\n zig: langLoader(() => import('@duskmoon-dev/code-engine/lang/zig')),\n vue: langLoader(() => import('@duskmoon-dev/code-engine/lang/vue')),\n angular: langLoader(() => import('@duskmoon-dev/code-engine/lang/angular')),\n liquid: langLoader(() => import('@duskmoon-dev/code-engine/lang/liquid')),\n jinja: langLoader(() => import('@duskmoon-dev/code-engine/lang/jinja')),\n wast: langLoader(() => import('@duskmoon-dev/code-engine/lang/wast')),\n lezer: langLoader(() => import('@duskmoon-dev/code-engine/lang/lezer')),\n caddyfile: langLoader(() => import('@duskmoon-dev/code-engine/lang/caddyfile')),\n};\nexport type CodeEngineTheme = 'duskmoon' | 'sunshine' | 'moonlight' | 'one-dark';\n\nconst styles = css`\n :host {\n display: block;\n min-height: 200px;\n font-family: var(\n --dm-font-mono,\n ui-monospace,\n 'Cascadia Code',\n 'Source Code Pro',\n Menlo,\n Consolas,\n 'DejaVu Sans Mono',\n monospace\n );\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n .cm-host {\n height: 100%;\n }\n\n .cm-host .cm-editor {\n height: 100%;\n }\n\n .cm-host .cm-editor.cm-focused {\n outline: none;\n }\n`;\n\nexport class ElDmCodeEngine extends BaseElement {\n static properties = {\n language: { type: String, reflect: true },\n readonly: { type: Boolean, reflect: true },\n theme: { type: String, reflect: true, default: 'duskmoon' },\n wrap: { type: Boolean, reflect: true },\n };\n\n declare language: string;\n declare readonly: boolean;\n declare theme: CodeEngineTheme;\n declare wrap: boolean;\n\n #editor: EditorView | null = null;\n #pendingValue: string | null = null;\n\n readonly #languageCompartment = new Compartment();\n readonly #readonlyCompartment = new Compartment();\n readonly #themeCompartment = new Compartment();\n readonly #wrapCompartment = new Compartment();\n\n readonly #langCache = new Map<string, Extension | null>();\n\n constructor() {\n super();\n this.attachStyles(styles);\n }\n\n /**\n * Current editor content. Getter always returns live document text.\n * Setter updates the editor document (or queues the value if called before mount).\n */\n get value(): string {\n return (\n this.#editor?.state.doc.toString() ?? this.#pendingValue ?? this.getAttribute('value') ?? ''\n );\n }\n\n set value(v: string) {\n if (this.#editor) {\n this.#editor.dispatch({\n changes: { from: 0, to: this.#editor.state.doc.length, insert: v },\n });\n } else {\n this.#pendingValue = v;\n }\n }\n\n /** Focus the editor. */\n focus(): void {\n this.#editor?.focus();\n }\n\n /** Returns current editor content. Equivalent to reading the `value` property. */\n getValue(): string {\n return this.value;\n }\n\n /** Sets editor content programmatically. Equivalent to assigning the `value` property. */\n setValue(v: string): void {\n this.value = v;\n }\n\n protected render(): string {\n return '<div class=\"cm-host\" part=\"editor\"></div>';\n }\n\n protected update(): void {\n if (!this.#editor) {\n // First render: create the container then mount the editor.\n super.update();\n void this.#mountEditor();\n } else {\n // Editor already mounted: reconfigure via compartment transactions.\n void this.#applyConfig();\n }\n }\n\n disconnectedCallback(): void {\n // Save current content so it survives a DOM move/reconnect.\n if (this.#editor) {\n this.#pendingValue = this.#editor.state.doc.toString();\n this.#editor.destroy();\n this.#editor = null;\n }\n super.disconnectedCallback();\n }\n\n // ── Private helpers ──────────────────────────────────────────────────\n\n async #mountEditor(): Promise<void> {\n const host = this.shadowRoot?.querySelector('.cm-host');\n if (!host || this.#editor) return;\n\n const initialDoc = this.#pendingValue ?? this.getAttribute('value') ?? '';\n this.#pendingValue = null;\n\n const langExt = await this.#loadLanguage(this.language);\n\n this.#editor = new EditorView({\n state: EditorState.create({\n doc: initialDoc,\n extensions: [\n basicSetup,\n this.#languageCompartment.of(langExt ?? []),\n this.#readonlyCompartment.of(EditorState.readOnly.of(this.readonly ?? false)),\n this.#themeCompartment.of(THEMES[this.theme] ?? []),\n this.#wrapCompartment.of(this.wrap ? EditorView.lineWrapping : []),\n EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n this.emit('input', { value: update.state.doc.toString() });\n }\n }),\n EditorView.domEventHandlers({\n blur: () => {\n this.emit('change', { value: this.#editor!.state.doc.toString() });\n return false;\n },\n }),\n ],\n }),\n parent: host,\n root: this.shadowRoot,\n });\n }\n\n async #applyConfig(): Promise<void> {\n if (!this.#editor) return;\n\n const langExt = await this.#loadLanguage(this.language);\n\n this.#editor.dispatch({\n effects: [\n this.#languageCompartment.reconfigure(langExt ?? []),\n this.#readonlyCompartment.reconfigure(EditorState.readOnly.of(this.readonly ?? false)),\n this.#themeCompartment.reconfigure(THEMES[this.theme] ?? []),\n this.#wrapCompartment.reconfigure(this.wrap ? EditorView.lineWrapping : []),\n ],\n });\n }\n\n async #loadLanguage(name: string): Promise<Extension | null> {\n if (!name) return null;\n if (this.#langCache.has(name)) return this.#langCache.get(name)!;\n\n const loader = LANG_LOADERS[name];\n if (!loader) {\n this.#langCache.set(name, null);\n return null;\n }\n\n try {\n const ext = await loader();\n this.#langCache.set(name, ext);\n return ext;\n } catch {\n this.#langCache.set(name, null);\n return null;\n }\n }\n}\n",
5
+ "/**\n * DuskMoon Code Engine Element\n *\n * A lightweight code editor backed by @duskmoon-dev/code-engine (CodeMirror 6 fork).\n * Behaves like a native <input> or <textarea>: the `value` attribute sets the initial\n * content, the `value` property always reflects the current content, and the element\n * fires `input` on every change and `change` on blur.\n *\n * @element el-dm-code-engine\n *\n * @attr {string} value - Initial editor content (read once at mount, like <input>)\n * @attr {string} language - Language name for syntax highlighting (e.g. \"javascript\", \"css\")\n * @attr {boolean} readonly - Whether the editor is read-only\n * @attr {string} theme - Editor theme: \"duskmoon\" | \"sunshine\" | \"moonlight\" | \"one-dark\"\n * @attr {boolean} wrap - Enable line wrapping\n *\n * @prop {string} value - Gets or sets current editor content\n *\n * @method focus() - Focuses the editor\n * @method getValue() - Returns current editor content\n * @method setValue(value: string) - Sets editor content programmatically\n *\n * @fires input - Fired on every document change, detail: { value: string }\n * @fires change - Fired when editor loses focus, detail: { value: string }\n *\n * @csspart editor - The CodeMirror mount container\n *\n * @attr {boolean} show-topbar - Show the topbar\n * @attr {boolean} show-bottombar - Show the bottombar\n * @attr {string} title - Title shown in topbar (e.g. filename)\n *\n * @fires copy - Fired when copy button is clicked, detail: { value: string }\n * @fires fullscreen - Fired when fullscreen is toggled, detail: { active: boolean }\n *\n * @csspart topbar - The topbar container\n * @csspart bottombar - The bottombar container\n *\n * @slot topbar - Custom topbar content (replaces default)\n * @slot bottombar - Custom bottombar content (replaces default)\n */\n\nimport { BaseElement, css } from '@duskmoon-dev/el-base';\nimport type { Extension } from '@duskmoon-dev/code-engine';\nimport { EditorView } from '@duskmoon-dev/code-engine/view';\nimport { EditorState, Compartment } from '@duskmoon-dev/code-engine/state';\nimport { basicSetup } from '@duskmoon-dev/code-engine/setup';\nimport { undo, redo } from '@duskmoon-dev/code-engine/commands';\n\n// ── Static theme imports (all 4 are small; avoids runtime bare-specifier issues) ──\nimport * as _duskmoonTheme from '@duskmoon-dev/code-engine/theme/duskmoon';\nimport * as _sunshineTheme from '@duskmoon-dev/code-engine/theme/sunshine';\nimport * as _moonlightTheme from '@duskmoon-dev/code-engine/theme/moonlight';\nimport * as _oneDarkTheme from '@duskmoon-dev/code-engine/theme/one-dark';\n\nfunction extractExt(mod: Record<string, unknown>): Extension {\n const v =\n mod.default ??\n Object.values(mod).find((x) => typeof x === 'function' || (x && typeof x !== 'string'));\n // Theme modules export a factory function (e.g. duskMoon(options?))\n if (typeof v === 'function') return (v as () => Extension)() as Extension;\n return (v ?? []) as Extension;\n}\n\nconst THEMES: Record<string, Extension> = {\n duskmoon: extractExt(_duskmoonTheme as unknown as Record<string, unknown>),\n sunshine: extractExt(_sunshineTheme as unknown as Record<string, unknown>),\n moonlight: extractExt(_moonlightTheme as unknown as Record<string, unknown>),\n 'one-dark': extractExt(_oneDarkTheme as unknown as Record<string, unknown>),\n};\n\n// ── Language loaders (literal import paths so bundlers can resolve them) ──\n\nfunction langLoader(\n importFn: () => Promise<Record<string, unknown>>,\n opts?: Record<string, unknown>,\n): () => Promise<Extension | null> {\n return async () => {\n const mod = await importFn();\n const factory = mod.default ?? Object.values(mod).find((v) => typeof v === 'function');\n if (typeof factory === 'function') {\n return (opts ? factory(opts) : factory()) as Extension;\n }\n return factory as Extension | null;\n };\n}\n\nconst LANG_LOADERS: Record<string, () => Promise<Extension | null>> = {\n javascript: langLoader(() => import('@duskmoon-dev/code-engine/lang/javascript')),\n typescript: langLoader(() => import('@duskmoon-dev/code-engine/lang/javascript'), {\n typescript: true,\n }),\n css: langLoader(() => import('@duskmoon-dev/code-engine/lang/css')),\n html: langLoader(() => import('@duskmoon-dev/code-engine/lang/html')),\n json: langLoader(() => import('@duskmoon-dev/code-engine/lang/json')),\n python: langLoader(() => import('@duskmoon-dev/code-engine/lang/python')),\n markdown: langLoader(() => import('@duskmoon-dev/code-engine/lang/markdown')),\n xml: langLoader(() => import('@duskmoon-dev/code-engine/lang/xml')),\n sql: langLoader(() => import('@duskmoon-dev/code-engine/lang/sql')),\n rust: langLoader(() => import('@duskmoon-dev/code-engine/lang/rust')),\n go: langLoader(() => import('@duskmoon-dev/code-engine/lang/go')),\n java: langLoader(() => import('@duskmoon-dev/code-engine/lang/java')),\n cpp: langLoader(() => import('@duskmoon-dev/code-engine/lang/cpp')),\n php: langLoader(() => import('@duskmoon-dev/code-engine/lang/php')),\n yaml: langLoader(() => import('@duskmoon-dev/code-engine/lang/yaml')),\n sass: langLoader(() => import('@duskmoon-dev/code-engine/lang/sass')),\n less: langLoader(() => import('@duskmoon-dev/code-engine/lang/less')),\n elixir: langLoader(() => import('@duskmoon-dev/code-engine/lang/elixir')),\n erlang: langLoader(() => import('@duskmoon-dev/code-engine/lang/erlang')),\n heex: langLoader(() => import('@duskmoon-dev/code-engine/lang/heex')),\n dart: langLoader(() => import('@duskmoon-dev/code-engine/lang/dart')),\n zig: langLoader(() => import('@duskmoon-dev/code-engine/lang/zig')),\n vue: langLoader(() => import('@duskmoon-dev/code-engine/lang/vue')),\n angular: langLoader(() => import('@duskmoon-dev/code-engine/lang/angular')),\n liquid: langLoader(() => import('@duskmoon-dev/code-engine/lang/liquid')),\n jinja: langLoader(() => import('@duskmoon-dev/code-engine/lang/jinja')),\n wast: langLoader(() => import('@duskmoon-dev/code-engine/lang/wast')),\n lezer: langLoader(() => import('@duskmoon-dev/code-engine/lang/lezer')),\n caddyfile: langLoader(() => import('@duskmoon-dev/code-engine/lang/caddyfile')),\n};\n\nconst LANG_BADGES: Record<string, string> = {\n javascript: 'JS',\n typescript: 'TS',\n python: 'PY',\n rust: 'RS',\n go: 'GO',\n java: 'JAVA',\n cpp: 'C++',\n html: 'HTML',\n css: 'CSS',\n json: 'JSON',\n markdown: 'MD',\n sql: 'SQL',\n yaml: 'YAML',\n xml: 'XML',\n php: 'PHP',\n elixir: 'EX',\n erlang: 'ERL',\n heex: 'HEEX',\n dart: 'DART',\n zig: 'ZIG',\n vue: 'VUE',\n angular: 'NG',\n sass: 'SASS',\n less: 'LESS',\n wast: 'WAST',\n lezer: 'LEZER',\n caddyfile: 'CADDY',\n jinja: 'JINJA',\n liquid: 'LIQUID',\n};\n\nconst LANG_NAMES: Record<string, string> = {\n javascript: 'JavaScript',\n typescript: 'TypeScript',\n python: 'Python',\n rust: 'Rust',\n go: 'Go',\n java: 'Java',\n cpp: 'C++',\n html: 'HTML',\n css: 'CSS',\n json: 'JSON',\n markdown: 'Markdown',\n sql: 'SQL',\n yaml: 'YAML',\n xml: 'XML',\n php: 'PHP',\n elixir: 'Elixir',\n erlang: 'Erlang',\n heex: 'HEEx',\n dart: 'Dart',\n zig: 'Zig',\n vue: 'Vue',\n angular: 'Angular',\n sass: 'Sass',\n less: 'Less',\n wast: 'WAT',\n lezer: 'Lezer',\n caddyfile: 'Caddyfile',\n jinja: 'Jinja',\n liquid: 'Liquid',\n};\n\n// ── SVG Icons (14×14, stroke-based) ──\n\nconst ICON_UNDO = `<svg viewBox=\"0 0 24 24\"><polyline points=\"1 4 1 10 7 10\"/><path d=\"M3.51 15a9 9 0 1 0 2.13-9.36L1 10\"/></svg>`;\n\nconst ICON_REDO = `<svg viewBox=\"0 0 24 24\"><polyline points=\"23 4 23 10 17 10\"/><path d=\"M20.49 15a9 9 0 1 1-2.12-9.36L23 10\"/></svg>`;\n\nconst ICON_WRAP = `<svg viewBox=\"0 0 24 24\"><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"/><path d=\"M3 12h15a3 3 0 1 1 0 6h-4\"/><polyline points=\"16 16 14 18 16 20\"/><line x1=\"3\" y1=\"18\" x2=\"10\" y2=\"18\"/></svg>`;\n\nconst ICON_COPY = `<svg viewBox=\"0 0 24 24\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\"/><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"/></svg>`;\n\nconst ICON_CHECK = `<svg viewBox=\"0 0 24 24\"><polyline points=\"20 6 9 17 4 12\"/></svg>`;\n\nconst ICON_FULLSCREEN = `<svg viewBox=\"0 0 24 24\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/></svg>`;\n\nconst ICON_EXIT_FULLSCREEN = `<svg viewBox=\"0 0 24 24\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" y1=\"10\" x2=\"21\" y2=\"3\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/></svg>`;\n\nexport type CodeEngineTheme = 'duskmoon' | 'sunshine' | 'moonlight' | 'one-dark';\n\nconst styles = css`\n :host {\n display: block;\n min-height: 200px;\n font-family: var(\n --dm-font-mono,\n ui-monospace,\n 'Cascadia Code',\n 'Source Code Pro',\n Menlo,\n Consolas,\n 'DejaVu Sans Mono',\n monospace\n );\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n .cm-host {\n height: 100%;\n }\n\n .cm-host .cm-editor {\n height: 100%;\n }\n\n .cm-host .cm-editor.cm-focused {\n outline: none;\n }\n\n /* ── Topbar ────────────────────────────────────────── */\n\n .topbar {\n display: none;\n }\n\n :host([show-topbar]) .topbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n padding: 0.375rem 0.75rem;\n border-bottom: 1px solid var(--dm-border, #e0e0e0);\n background: var(--dm-surface-container, #f0f0f0);\n font-size: 0.75rem;\n color: var(--dm-on-surface, #1a1a1a);\n }\n\n .topbar-left {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n min-width: 0;\n }\n\n .topbar-right {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n }\n\n .lang-badge {\n padding: 0.0625rem 0.375rem;\n border-radius: var(--dm-radius-sm, 0.25rem);\n background: var(--dm-primary, #6750a4);\n color: var(--dm-on-primary, #fff);\n font-size: 0.625rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.025em;\n }\n\n .topbar-title {\n opacity: 0.7;\n font-size: 0.6875rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .bar-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n padding: 0;\n border: none;\n border-radius: var(--dm-radius-sm, 0.25rem);\n background: transparent;\n color: var(--dm-on-surface-variant, #555);\n font-family: inherit;\n font-size: 0.75rem;\n cursor: pointer;\n transition:\n background 0.15s,\n color 0.15s;\n }\n\n .bar-btn:hover {\n background: var(--dm-surface-container-high, #e0e0e0);\n color: var(--dm-on-surface, #1a1a1a);\n }\n\n .bar-btn svg {\n width: 14px;\n height: 14px;\n fill: none;\n stroke: currentColor;\n stroke-width: 2;\n stroke-linecap: round;\n stroke-linejoin: round;\n }\n\n /* ── Bottombar ─────────────────────────────────────── */\n\n .bottombar {\n display: none;\n }\n\n :host([show-bottombar]) .bottombar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.25rem 0.75rem;\n border-top: 1px solid var(--dm-border, #e0e0e0);\n background: var(--dm-surface-container-high, #e0e0e0);\n font-size: 0.625rem;\n color: var(--dm-on-surface-variant, #555);\n }\n\n .bottombar-left,\n .bottombar-right {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n }\n\n /* ── Fullscreen ────────────────────────────────────── */\n\n :host(.fullscreen) {\n position: fixed !important;\n inset: 0 !important;\n z-index: 9999 !important;\n min-height: 100vh !important;\n display: flex;\n flex-direction: column;\n }\n\n :host(.fullscreen) .cm-host {\n flex: 1;\n }\n`;\n\nexport class ElDmCodeEngine extends BaseElement {\n static properties = {\n language: { type: String, reflect: true },\n readonly: { type: Boolean, reflect: true },\n theme: { type: String, reflect: true, default: 'duskmoon' },\n wrap: { type: Boolean, reflect: true },\n showTopbar: { type: Boolean, reflect: true },\n showBottombar: { type: Boolean, reflect: true },\n title: { type: String, reflect: true },\n };\n\n declare language: string;\n declare readonly: boolean;\n declare theme: CodeEngineTheme;\n declare wrap: boolean;\n declare showTopbar: boolean;\n declare showBottombar: boolean;\n declare title: string;\n\n #editor: EditorView | null = null;\n #pendingValue: string | null = null;\n\n readonly #languageCompartment = new Compartment();\n readonly #readonlyCompartment = new Compartment();\n readonly #themeCompartment = new Compartment();\n readonly #wrapCompartment = new Compartment();\n\n readonly #langCache = new Map<string, Extension | null>();\n\n #cursorLine = 1;\n #cursorCol = 1;\n #lineCount = 0;\n #isFullscreen = false;\n #copyTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor() {\n super();\n this.attachStyles(styles);\n }\n\n /**\n * Current editor content. Getter always returns live document text.\n * Setter updates the editor document (or queues the value if called before mount).\n */\n get value(): string {\n return (\n this.#editor?.state.doc.toString() ?? this.#pendingValue ?? this.getAttribute('value') ?? ''\n );\n }\n\n set value(v: string) {\n if (this.#editor) {\n this.#editor.dispatch({\n changes: { from: 0, to: this.#editor.state.doc.length, insert: v },\n });\n } else {\n this.#pendingValue = v;\n }\n }\n\n /** Focus the editor. */\n focus(): void {\n this.#editor?.focus();\n }\n\n /** Returns current editor content. Equivalent to reading the `value` property. */\n getValue(): string {\n return this.value;\n }\n\n /** Sets editor content programmatically. Equivalent to assigning the `value` property. */\n setValue(v: string): void {\n this.value = v;\n }\n\n protected render(): string {\n return `${this.#renderTopbar()}<div class=\"cm-host\" part=\"editor\"></div>${this.#renderBottombar()}`;\n }\n\n protected update(): void {\n if (!this.#editor) {\n // First render: create the container then mount the editor.\n super.update();\n void this.#mountEditor();\n } else {\n // Editor already mounted: reconfigure via compartment transactions.\n void this.#applyConfig();\n }\n }\n\n #clickHandler = (e: Event) => {\n const btn = (e.target as Element)?.closest('[data-action]');\n if (btn) {\n const action = btn.getAttribute('data-action');\n if (action) this.#handleBarAction(action);\n }\n };\n\n connectedCallback(): void {\n super.connectedCallback();\n this.shadowRoot!.addEventListener('click', this.#clickHandler);\n }\n\n disconnectedCallback(): void {\n this.shadowRoot!.removeEventListener('click', this.#clickHandler);\n if (this.#copyTimer) {\n clearTimeout(this.#copyTimer);\n this.#copyTimer = null;\n }\n // Save current content so it survives a DOM move/reconnect.\n if (this.#editor) {\n this.#pendingValue = this.#editor.state.doc.toString();\n this.#editor.destroy();\n this.#editor = null;\n }\n super.disconnectedCallback();\n }\n\n // ── Bar rendering ───────────────────────────────────────────────────\n\n #renderTopbar(): string {\n const badge = this.language\n ? `<span class=\"lang-badge\">${LANG_BADGES[this.language] ?? this.language.toUpperCase()}</span>`\n : '';\n const t = (this as unknown as { title: string }).title;\n const title = t ? `<span class=\"topbar-title\">${t}</span>` : '';\n return `\n <div class=\"topbar\" part=\"topbar\">\n <slot name=\"topbar\">\n <div class=\"topbar-left\">${badge}${title}</div>\n <div class=\"topbar-right\">\n <button class=\"bar-btn\" data-action=\"undo\" title=\"Undo\">${ICON_UNDO}</button>\n <button class=\"bar-btn\" data-action=\"redo\" title=\"Redo\">${ICON_REDO}</button>\n <button class=\"bar-btn\" data-action=\"wrap\" title=\"Toggle line wrap\">${ICON_WRAP}</button>\n <button class=\"bar-btn\" data-action=\"copy\" title=\"Copy\">${ICON_COPY}</button>\n <button class=\"bar-btn\" data-action=\"fullscreen\" title=\"Toggle fullscreen\">${this.#isFullscreen ? ICON_EXIT_FULLSCREEN : ICON_FULLSCREEN}</button>\n </div>\n </slot>\n </div>\n `;\n }\n\n #renderBottombar(): string {\n const langName = this.language ? (LANG_NAMES[this.language] ?? this.language) : '';\n return `\n <div class=\"bottombar\" part=\"bottombar\">\n <slot name=\"bottombar\">\n <div class=\"bottombar-left\">\n <span class=\"cursor-pos\">Ln ${this.#cursorLine}, Col ${this.#cursorCol}</span>\n <span class=\"line-count\">${this.#lineCount} lines</span>\n </div>\n <div class=\"bottombar-right\">\n <span>UTF-8</span>\n ${langName ? `<span>${langName}</span>` : ''}\n </div>\n </slot>\n </div>\n `;\n }\n\n // ── Action handlers ─────────────────────────────────────────────────\n\n #handleBarAction(action: string): void {\n switch (action) {\n case 'undo':\n if (this.#editor) undo(this.#editor);\n break;\n case 'redo':\n if (this.#editor) redo(this.#editor);\n break;\n case 'wrap':\n this.wrap = !this.wrap;\n break;\n case 'copy':\n void this.#handleCopy();\n break;\n case 'fullscreen':\n this.#toggleFullscreen();\n break;\n }\n }\n\n async #handleCopy(): Promise<void> {\n const value = this.value;\n try {\n await navigator.clipboard.writeText(value);\n } catch {\n return; // Clipboard API unavailable or denied\n }\n this.emit('copy', { value });\n this.#showCopyFeedback();\n }\n\n #showCopyFeedback(): void {\n const btn = this.shadowRoot?.querySelector('[data-action=\"copy\"]');\n if (!btn) return;\n if (this.#copyTimer) clearTimeout(this.#copyTimer);\n btn.innerHTML = ICON_CHECK;\n btn.setAttribute('title', 'Copied!');\n this.#copyTimer = setTimeout(() => {\n btn.innerHTML = ICON_COPY;\n btn.setAttribute('title', 'Copy');\n this.#copyTimer = null;\n }, 2000);\n }\n\n #toggleFullscreen(): void {\n this.#isFullscreen = !this.#isFullscreen;\n this.classList.toggle('fullscreen', this.#isFullscreen);\n // Update fullscreen button icon\n const btn = this.shadowRoot?.querySelector('[data-action=\"fullscreen\"]');\n if (btn) {\n btn.innerHTML = this.#isFullscreen ? ICON_EXIT_FULLSCREEN : ICON_FULLSCREEN;\n btn.setAttribute('title', this.#isFullscreen ? 'Exit fullscreen' : 'Toggle fullscreen');\n }\n this.emit('fullscreen', { active: this.#isFullscreen });\n }\n\n // ── Cursor tracking ────────────────────────────────────────────────\n\n #updateCursorInfo(state: EditorState): void {\n const pos = state.selection.main.head;\n const line = state.doc.lineAt(pos);\n this.#cursorLine = line.number;\n this.#cursorCol = pos - line.from + 1;\n this.#lineCount = state.doc.lines;\n\n // Update bottombar spans directly (avoid full re-render)\n const cursorEl = this.shadowRoot?.querySelector('.cursor-pos');\n const lineCountEl = this.shadowRoot?.querySelector('.line-count');\n if (cursorEl) cursorEl.textContent = `Ln ${this.#cursorLine}, Col ${this.#cursorCol}`;\n if (lineCountEl) lineCountEl.textContent = `${this.#lineCount} lines`;\n }\n\n // ── Private helpers ──────────────────────────────────────────────────\n\n async #mountEditor(): Promise<void> {\n const host = this.shadowRoot?.querySelector('.cm-host');\n if (!host || this.#editor) return;\n\n const initialDoc = this.#pendingValue ?? this.getAttribute('value') ?? '';\n this.#pendingValue = null;\n\n const langExt = await this.#loadLanguage(this.language);\n\n this.#editor = new EditorView({\n state: EditorState.create({\n doc: initialDoc,\n extensions: [\n basicSetup,\n this.#languageCompartment.of(langExt ?? []),\n this.#readonlyCompartment.of(EditorState.readOnly.of(this.readonly ?? false)),\n this.#themeCompartment.of(THEMES[this.theme] ?? []),\n this.#wrapCompartment.of(this.wrap ? EditorView.lineWrapping : []),\n EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n this.emit('input', { value: update.state.doc.toString() });\n }\n if (update.docChanged || update.selectionSet) {\n this.#updateCursorInfo(update.state);\n }\n }),\n EditorView.domEventHandlers({\n blur: () => {\n this.emit('change', { value: this.#editor!.state.doc.toString() });\n return false;\n },\n }),\n ],\n }),\n parent: host,\n root: this.shadowRoot,\n });\n\n this.#updateCursorInfo(this.#editor.state);\n }\n\n async #applyConfig(): Promise<void> {\n if (!this.#editor) return;\n\n const langExt = await this.#loadLanguage(this.language);\n\n this.#editor.dispatch({\n effects: [\n this.#languageCompartment.reconfigure(langExt ?? []),\n this.#readonlyCompartment.reconfigure(EditorState.readOnly.of(this.readonly ?? false)),\n this.#themeCompartment.reconfigure(THEMES[this.theme] ?? []),\n this.#wrapCompartment.reconfigure(this.wrap ? EditorView.lineWrapping : []),\n ],\n });\n }\n\n async #loadLanguage(name: string): Promise<Extension | null> {\n if (!name) return null;\n if (this.#langCache.has(name)) return this.#langCache.get(name)!;\n\n const loader = LANG_LOADERS[name];\n if (!loader) {\n this.#langCache.set(name, null);\n return null;\n }\n\n try {\n const ext = await loader();\n this.#langCache.set(name, ext);\n return ext;\n } catch {\n this.#langCache.set(name, null);\n return null;\n }\n }\n}\n",
6
6
  "/**\n * @duskmoon-dev/el-code-engine\n *\n * DuskMoon Code Engine custom element — a lightweight code editor\n * backed by @duskmoon-dev/code-engine (CodeMirror 6 fork).\n */\n\nimport { ElDmCodeEngine } from './el-dm-code-engine.js';\n\nexport { ElDmCodeEngine };\nexport type { CodeEngineTheme } from './el-dm-code-engine.js';\n\n/**\n * Register the el-dm-code-engine custom element.\n *\n * @example\n * ```ts\n * import { register } from '@duskmoon-dev/el-code-engine';\n * register();\n * ```\n */\nexport function register(): void {\n if (!customElements.get('el-dm-code-engine')) {\n customElements.define('el-dm-code-engine', ElDmCodeEngine);\n }\n}\n"
7
7
  ],
8
- "mappings": "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",
9
- "debugId": "B8FEEBB401E9A3D064756E2164756E21",
8
+ "mappings": ";;;;;;;;;AAyCA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA,SAAS,UAAU,CAAC,KAAyC;AAAA,EAC3D,MAAM,IACJ,IAAI,WACJ,OAAO,OAAO,GAAG,EAAE,KAAK,CAAC,MAAM,OAAO,MAAM,cAAe,KAAK,OAAO,MAAM,QAAS;AAAA,EAExF,IAAI,OAAO,MAAM;AAAA,IAAY,OAAQ,EAAsB;AAAA,EAC3D,OAAQ,KAAK,CAAC;AAAA;AAGhB,IAAM,SAAoC;AAAA,EACxC,UAAU,WAAW,cAAoD;AAAA,EACzE,UAAU,WAAW,cAAoD;AAAA,EACzE,WAAW,WAAW,eAAqD;AAAA,EAC3E,YAAY,WAAW,aAAmD;AAC5E;AAIA,SAAS,UAAU,CACjB,UACA,MACiC;AAAA,EACjC,OAAO,YAAY;AAAA,IACjB,MAAM,MAAM,MAAM,SAAS;AAAA,IAC3B,MAAM,UAAU,IAAI,WAAW,OAAO,OAAO,GAAG,EAAE,KAAK,CAAC,MAAM,OAAO,MAAM,UAAU;AAAA,IACrF,IAAI,OAAO,YAAY,YAAY;AAAA,MACjC,OAAQ,OAAO,QAAQ,IAAI,IAAI,QAAQ;AAAA,IACzC;AAAA,IACA,OAAO;AAAA;AAAA;AAIX,IAAM,eAAgE;AAAA,EACpE,YAAY,WAAW,MAAa,mDAA4C;AAAA,EAChF,YAAY,WAAW,MAAa,qDAA8C;AAAA,IAChF,YAAY;AAAA,EACd,CAAC;AAAA,EACD,KAAK,WAAW,MAAa,4CAAqC;AAAA,EAClE,MAAM,WAAW,MAAa,6CAAsC;AAAA,EACpE,MAAM,WAAW,MAAa,6CAAsC;AAAA,EACpE,QAAQ,WAAW,MAAa,+CAAwC;AAAA,EACxE,UAAU,WAAW,MAAa,iDAA0C;AAAA,EAC5E,KAAK,WAAW,MAAa,4CAAqC;AAAA,EAClE,KAAK,WAAW,MAAa,4CAAqC;AAAA,EAClE,MAAM,WAAW,MAAa,6CAAsC;AAAA,EACpE,IAAI,WAAW,MAAa,2CAAoC;AAAA,EAChE,MAAM,WAAW,MAAa,6CAAsC;AAAA,EACpE,KAAK,WAAW,MAAa,4CAAqC;AAAA,EAClE,KAAK,WAAW,MAAa,4CAAqC;AAAA,EAClE,MAAM,WAAW,MAAa,6CAAsC;AAAA,EACpE,MAAM,WAAW,MAAa,6CAAsC;AAAA,EACpE,MAAM,WAAW,MAAa,6CAAsC;AAAA,EACpE,QAAQ,WAAW,MAAa,+CAAwC;AAAA,EACxE,QAAQ,WAAW,MAAa,+CAAwC;AAAA,EACxE,MAAM,WAAW,MAAa,6CAAsC;AAAA,EACpE,MAAM,WAAW,MAAa,6CAAsC;AAAA,EACpE,KAAK,WAAW,MAAa,4CAAqC;AAAA,EAClE,KAAK,WAAW,MAAa,4CAAqC;AAAA,EAClE,SAAS,WAAW,MAAa,gDAAyC;AAAA,EAC1E,QAAQ,WAAW,MAAa,+CAAwC;AAAA,EACxE,OAAO,WAAW,MAAa,8CAAuC;AAAA,EACtE,MAAM,WAAW,MAAa,6CAAsC;AAAA,EACpE,OAAO,WAAW,MAAa,8CAAuC;AAAA,EACtE,WAAW,WAAW,MAAa,kDAA2C;AAChF;AAEA,IAAM,cAAsC;AAAA,EAC1C,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,UAAU;AAAA,EACV,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,WAAW;AAAA,EACX,OAAO;AAAA,EACP,QAAQ;AACV;AAEA,IAAM,aAAqC;AAAA,EACzC,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,UAAU;AAAA,EACV,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,WAAW;AAAA,EACX,OAAO;AAAA,EACP,QAAQ;AACV;AAIA,IAAM,YAAY;AAElB,IAAM,YAAY;AAElB,IAAM,YAAY;AAElB,IAAM,YAAY;AAElB,IAAM,aAAa;AAEnB,IAAM,kBAAkB;AAExB,IAAM,uBAAuB;AAI7B,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4JR,MAAM,uBAAuB,YAAY;AAAA,SACvC,aAAa;AAAA,IAClB,UAAU,EAAE,MAAM,QAAQ,SAAS,KAAK;AAAA,IACxC,UAAU,EAAE,MAAM,SAAS,SAAS,KAAK;AAAA,IACzC,OAAO,EAAE,MAAM,QAAQ,SAAS,MAAM,SAAS,WAAW;AAAA,IAC1D,MAAM,EAAE,MAAM,SAAS,SAAS,KAAK;AAAA,IACrC,YAAY,EAAE,MAAM,SAAS,SAAS,KAAK;AAAA,IAC3C,eAAe,EAAE,MAAM,SAAS,SAAS,KAAK;AAAA,IAC9C,OAAO,EAAE,MAAM,QAAQ,SAAS,KAAK;AAAA,EACvC;AAAA,EAUA,UAA6B;AAAA,EAC7B,gBAA+B;AAAA,EAEtB,uBAAuB,IAAI;AAAA,EAC3B,uBAAuB,IAAI;AAAA,EAC3B,oBAAoB,IAAI;AAAA,EACxB,mBAAmB,IAAI;AAAA,EAEvB,aAAa,IAAI;AAAA,EAE1B,cAAc;AAAA,EACd,aAAa;AAAA,EACb,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,aAAmD;AAAA,EAEnD,WAAW,GAAG;AAAA,IACZ,MAAM;AAAA,IACN,KAAK,aAAa,MAAM;AAAA;AAAA,MAOtB,KAAK,GAAW;AAAA,IAClB,OACE,KAAK,SAAS,MAAM,IAAI,SAAS,KAAK,KAAK,iBAAiB,KAAK,aAAa,OAAO,KAAK;AAAA;AAAA,MAI1F,KAAK,CAAC,GAAW;AAAA,IACnB,IAAI,KAAK,SAAS;AAAA,MAChB,KAAK,QAAQ,SAAS;AAAA,QACpB,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,QAAQ,MAAM,IAAI,QAAQ,QAAQ,EAAE;AAAA,MACnE,CAAC;AAAA,IACH,EAAO;AAAA,MACL,KAAK,gBAAgB;AAAA;AAAA;AAAA,EAKzB,KAAK,GAAS;AAAA,IACZ,KAAK,SAAS,MAAM;AAAA;AAAA,EAItB,QAAQ,GAAW;AAAA,IACjB,OAAO,KAAK;AAAA;AAAA,EAId,QAAQ,CAAC,GAAiB;AAAA,IACxB,KAAK,QAAQ;AAAA;AAAA,EAGL,MAAM,GAAW;AAAA,IACzB,OAAO,GAAG,KAAK,cAAc,6CAA6C,KAAK,iBAAiB;AAAA;AAAA,EAGxF,MAAM,GAAS;AAAA,IACvB,IAAI,CAAC,KAAK,SAAS;AAAA,MAEjB,MAAM,OAAO;AAAA,MACR,KAAK,aAAa;AAAA,IACzB,EAAO;AAAA,MAEA,KAAK,aAAa;AAAA;AAAA;AAAA,EAI3B,gBAAgB,CAAC,MAAa;AAAA,IAC5B,MAAM,MAAO,EAAE,QAAoB,QAAQ,eAAe;AAAA,IAC1D,IAAI,KAAK;AAAA,MACP,MAAM,SAAS,IAAI,aAAa,aAAa;AAAA,MAC7C,IAAI;AAAA,QAAQ,KAAK,iBAAiB,MAAM;AAAA,IAC1C;AAAA;AAAA,EAGF,iBAAiB,GAAS;AAAA,IACxB,MAAM,kBAAkB;AAAA,IACxB,KAAK,WAAY,iBAAiB,SAAS,KAAK,aAAa;AAAA;AAAA,EAG/D,oBAAoB,GAAS;AAAA,IAC3B,KAAK,WAAY,oBAAoB,SAAS,KAAK,aAAa;AAAA,IAChE,IAAI,KAAK,YAAY;AAAA,MACnB,aAAa,KAAK,UAAU;AAAA,MAC5B,KAAK,aAAa;AAAA,IACpB;AAAA,IAEA,IAAI,KAAK,SAAS;AAAA,MAChB,KAAK,gBAAgB,KAAK,QAAQ,MAAM,IAAI,SAAS;AAAA,MACrD,KAAK,QAAQ,QAAQ;AAAA,MACrB,KAAK,UAAU;AAAA,IACjB;AAAA,IACA,MAAM,qBAAqB;AAAA;AAAA,EAK7B,aAAa,GAAW;AAAA,IACtB,MAAM,QAAQ,KAAK,WACf,4BAA4B,YAAY,KAAK,aAAa,KAAK,SAAS,YAAY,aACpF;AAAA,IACJ,MAAM,IAAK,KAAsC;AAAA,IACjD,MAAM,QAAQ,IAAI,8BAA8B,aAAa;AAAA,IAC7D,OAAO;AAAA;AAAA;AAAA,qCAG0B,QAAQ;AAAA;AAAA,sEAEyB;AAAA,sEACA;AAAA,kFACY;AAAA,sEACZ;AAAA,yFACmB,KAAK,gBAAgB,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnI,gBAAgB,GAAW;AAAA,IACzB,MAAM,WAAW,KAAK,WAAY,WAAW,KAAK,aAAa,KAAK,WAAY;AAAA,IAChF,OAAO;AAAA;AAAA;AAAA;AAAA,0CAI+B,KAAK,oBAAoB,KAAK;AAAA,uCACjC,KAAK;AAAA;AAAA;AAAA;AAAA,cAI9B,WAAW,SAAS,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASpD,gBAAgB,CAAC,QAAsB;AAAA,IACrC,QAAQ;AAAA,WACD;AAAA,QACH,IAAI,KAAK;AAAA,UAAS,KAAK,KAAK,OAAO;AAAA,QACnC;AAAA,WACG;AAAA,QACH,IAAI,KAAK;AAAA,UAAS,KAAK,KAAK,OAAO;AAAA,QACnC;AAAA,WACG;AAAA,QACH,KAAK,OAAO,CAAC,KAAK;AAAA,QAClB;AAAA,WACG;AAAA,QACE,KAAK,YAAY;AAAA,QACtB;AAAA,WACG;AAAA,QACH,KAAK,kBAAkB;AAAA,QACvB;AAAA;AAAA;AAAA,OAIA,WAAW,GAAkB;AAAA,IACjC,MAAM,QAAQ,KAAK;AAAA,IACnB,IAAI;AAAA,MACF,MAAM,UAAU,UAAU,UAAU,KAAK;AAAA,MACzC,MAAM;AAAA,MACN;AAAA;AAAA,IAEF,KAAK,KAAK,QAAQ,EAAE,MAAM,CAAC;AAAA,IAC3B,KAAK,kBAAkB;AAAA;AAAA,EAGzB,iBAAiB,GAAS;AAAA,IACxB,MAAM,MAAM,KAAK,YAAY,cAAc,sBAAsB;AAAA,IACjE,IAAI,CAAC;AAAA,MAAK;AAAA,IACV,IAAI,KAAK;AAAA,MAAY,aAAa,KAAK,UAAU;AAAA,IACjD,IAAI,YAAY;AAAA,IAChB,IAAI,aAAa,SAAS,SAAS;AAAA,IACnC,KAAK,aAAa,WAAW,MAAM;AAAA,MACjC,IAAI,YAAY;AAAA,MAChB,IAAI,aAAa,SAAS,MAAM;AAAA,MAChC,KAAK,aAAa;AAAA,OACjB,IAAI;AAAA;AAAA,EAGT,iBAAiB,GAAS;AAAA,IACxB,KAAK,gBAAgB,CAAC,KAAK;AAAA,IAC3B,KAAK,UAAU,OAAO,cAAc,KAAK,aAAa;AAAA,IAEtD,MAAM,MAAM,KAAK,YAAY,cAAc,4BAA4B;AAAA,IACvE,IAAI,KAAK;AAAA,MACP,IAAI,YAAY,KAAK,gBAAgB,uBAAuB;AAAA,MAC5D,IAAI,aAAa,SAAS,KAAK,gBAAgB,oBAAoB,mBAAmB;AAAA,IACxF;AAAA,IACA,KAAK,KAAK,cAAc,EAAE,QAAQ,KAAK,cAAc,CAAC;AAAA;AAAA,EAKxD,iBAAiB,CAAC,OAA0B;AAAA,IAC1C,MAAM,MAAM,MAAM,UAAU,KAAK;AAAA,IACjC,MAAM,OAAO,MAAM,IAAI,OAAO,GAAG;AAAA,IACjC,KAAK,cAAc,KAAK;AAAA,IACxB,KAAK,aAAa,MAAM,KAAK,OAAO;AAAA,IACpC,KAAK,aAAa,MAAM,IAAI;AAAA,IAG5B,MAAM,WAAW,KAAK,YAAY,cAAc,aAAa;AAAA,IAC7D,MAAM,cAAc,KAAK,YAAY,cAAc,aAAa;AAAA,IAChE,IAAI;AAAA,MAAU,SAAS,cAAc,MAAM,KAAK,oBAAoB,KAAK;AAAA,IACzE,IAAI;AAAA,MAAa,YAAY,cAAc,GAAG,KAAK;AAAA;AAAA,OAK/C,YAAY,GAAkB;AAAA,IAClC,MAAM,OAAO,KAAK,YAAY,cAAc,UAAU;AAAA,IACtD,IAAI,CAAC,QAAQ,KAAK;AAAA,MAAS;AAAA,IAE3B,MAAM,aAAa,KAAK,iBAAiB,KAAK,aAAa,OAAO,KAAK;AAAA,IACvE,KAAK,gBAAgB;AAAA,IAErB,MAAM,UAAU,MAAM,KAAK,cAAc,KAAK,QAAQ;AAAA,IAEtD,KAAK,UAAU,IAAI,WAAW;AAAA,MAC5B,OAAO,YAAY,OAAO;AAAA,QACxB,KAAK;AAAA,QACL,YAAY;AAAA,UACV;AAAA,UACA,KAAK,qBAAqB,GAAG,WAAW,CAAC,CAAC;AAAA,UAC1C,KAAK,qBAAqB,GAAG,YAAY,SAAS,GAAG,KAAK,YAAY,KAAK,CAAC;AAAA,UAC5E,KAAK,kBAAkB,GAAG,OAAO,KAAK,UAAU,CAAC,CAAC;AAAA,UAClD,KAAK,iBAAiB,GAAG,KAAK,OAAO,WAAW,eAAe,CAAC,CAAC;AAAA,UACjE,WAAW,eAAe,GAAG,CAAC,WAAW;AAAA,YACvC,IAAI,OAAO,YAAY;AAAA,cACrB,KAAK,KAAK,SAAS,EAAE,OAAO,OAAO,MAAM,IAAI,SAAS,EAAE,CAAC;AAAA,YAC3D;AAAA,YACA,IAAI,OAAO,cAAc,OAAO,cAAc;AAAA,cAC5C,KAAK,kBAAkB,OAAO,KAAK;AAAA,YACrC;AAAA,WACD;AAAA,UACD,WAAW,iBAAiB;AAAA,YAC1B,MAAM,MAAM;AAAA,cACV,KAAK,KAAK,UAAU,EAAE,OAAO,KAAK,QAAS,MAAM,IAAI,SAAS,EAAE,CAAC;AAAA,cACjE,OAAO;AAAA;AAAA,UAEX,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,MACD,QAAQ;AAAA,MACR,MAAM,KAAK;AAAA,IACb,CAAC;AAAA,IAED,KAAK,kBAAkB,KAAK,QAAQ,KAAK;AAAA;AAAA,OAGrC,YAAY,GAAkB;AAAA,IAClC,IAAI,CAAC,KAAK;AAAA,MAAS;AAAA,IAEnB,MAAM,UAAU,MAAM,KAAK,cAAc,KAAK,QAAQ;AAAA,IAEtD,KAAK,QAAQ,SAAS;AAAA,MACpB,SAAS;AAAA,QACP,KAAK,qBAAqB,YAAY,WAAW,CAAC,CAAC;AAAA,QACnD,KAAK,qBAAqB,YAAY,YAAY,SAAS,GAAG,KAAK,YAAY,KAAK,CAAC;AAAA,QACrF,KAAK,kBAAkB,YAAY,OAAO,KAAK,UAAU,CAAC,CAAC;AAAA,QAC3D,KAAK,iBAAiB,YAAY,KAAK,OAAO,WAAW,eAAe,CAAC,CAAC;AAAA,MAC5E;AAAA,IACF,CAAC;AAAA;AAAA,OAGG,aAAa,CAAC,MAAyC;AAAA,IAC3D,IAAI,CAAC;AAAA,MAAM,OAAO;AAAA,IAClB,IAAI,KAAK,WAAW,IAAI,IAAI;AAAA,MAAG,OAAO,KAAK,WAAW,IAAI,IAAI;AAAA,IAE9D,MAAM,SAAS,aAAa;AAAA,IAC5B,IAAI,CAAC,QAAQ;AAAA,MACX,KAAK,WAAW,IAAI,MAAM,IAAI;AAAA,MAC9B,OAAO;AAAA,IACT;AAAA,IAEA,IAAI;AAAA,MACF,MAAM,MAAM,MAAM,OAAO;AAAA,MACzB,KAAK,WAAW,IAAI,MAAM,GAAG;AAAA,MAC7B,OAAO;AAAA,MACP,MAAM;AAAA,MACN,KAAK,WAAW,IAAI,MAAM,IAAI;AAAA,MAC9B,OAAO;AAAA;AAAA;AAGb;;;ACxoBO,SAAS,QAAQ,GAAS;AAAA,EAC/B,IAAI,CAAC,eAAe,IAAI,mBAAmB,GAAG;AAAA,IAC5C,eAAe,OAAO,qBAAqB,cAAc;AAAA,EAC3D;AAAA;",
9
+ "debugId": "6C8C69AE44633C3064756E2164756E21",
10
10
  "names": []
11
11
  }