@mcp-b/interactive-components 0.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/LICENSE +21 -0
- package/README.md +99 -0
- package/dist/code-editor-B94tewLC.js +425 -0
- package/dist/code-preview-gKk0nBKP.js +269 -0
- package/dist/components/code-editor/code-editor.d.ts +65 -0
- package/dist/components/code-editor/code-editor.js +2 -0
- package/dist/components/code-preview/code-preview.d.ts +58 -0
- package/dist/components/code-preview/code-preview.js +3 -0
- package/dist/components/interactive-editor/interactive-editor.d.ts +77 -0
- package/dist/components/interactive-editor/interactive-editor.js +3 -0
- package/dist/components/r-editor/r-editor.d.ts +68 -0
- package/dist/components/r-editor/r-editor.js +2 -0
- package/dist/components/sql-editor/sql-editor.d.ts +78 -0
- package/dist/components/sql-editor/sql-editor.js +2 -0
- package/dist/decorate-DcF3lt7P.js +9 -0
- package/dist/docs/custom-elements.json +2807 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/interactive-editor-WfTWxJGF.js +1454 -0
- package/dist/lib/runner-channel.d.ts +25 -0
- package/dist/lib/runner-channel.js +55 -0
- package/dist/lib/runner-url.d.ts +15 -0
- package/dist/lib/runner-url.js +19 -0
- package/dist/lib/transform.d.ts +2 -0
- package/dist/lib/transform.js +210 -0
- package/dist/r-editor-DwSyDo2i.js +743 -0
- package/dist/runners/ephemeral-indexeddb.js +114 -0
- package/dist/runners/pglite-runner.js +175 -0
- package/dist/runners/pyscript-runner.html +189 -0
- package/dist/runners/webr-runner.html +282 -0
- package/dist/sql-editor-CsNrjJ2_.js +968 -0
- package/dist/themes/interactive.css +79 -0
- package/dist/transform-DWhHlnkw.d.ts +53 -0
- package/dist/vite.d.ts +14 -0
- package/dist/vite.js +62 -0
- package/package.json +96 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MCP-B contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# @mcp-b/interactive-components
|
|
2
|
+
|
|
3
|
+
Interactive Lit components for browser code, SQL, R, and Python execution.
|
|
4
|
+
|
|
5
|
+
## Components
|
|
6
|
+
|
|
7
|
+
| Component | Tag | Description |
|
|
8
|
+
| -------------------------- | ------------------------------ | ----------------------------------------------------------------------- |
|
|
9
|
+
| `SigveloCodeEditor` | `<sigvelo-code-editor>` | CodeMirror 6 editor with syntax highlighting, folding, and autocomplete |
|
|
10
|
+
| `SigveloCodePreview` | `<sigvelo-code-preview>` | Sandboxed iframe preview for HTML/JS/CSS/Python output |
|
|
11
|
+
| `SigveloInteractiveEditor` | `<sigvelo-interactive-editor>` | Full playground: file explorer sidebar + editor + preview/console |
|
|
12
|
+
| `SigveloSqlEditor` | `<sigvelo-sql-editor>` | Isolated PGlite SQL editor with optional PostGIS and persistence |
|
|
13
|
+
| `SigveloREditor` | `<sigvelo-r-editor>` | Sandboxed WebR editor with plots, packages, and console output |
|
|
14
|
+
|
|
15
|
+
## Dependencies
|
|
16
|
+
|
|
17
|
+
`@mcp-b/wc-support` and `@mcp-b/web-components` are installed runtime
|
|
18
|
+
dependencies so every Lit package shares the same localization, icon, and
|
|
19
|
+
scroll-lock registries. The consuming application provides these peer
|
|
20
|
+
dependencies:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
lit >= 3.0.0
|
|
24
|
+
lit-html >= 3.0.0
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Keeping Lit external avoids loading multiple component runtimes.
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<script type="module">
|
|
33
|
+
import "@mcp-b/interactive-components/themes/interactive.css";
|
|
34
|
+
import "@mcp-b/interactive-components/components/interactive-editor/interactive-editor.js";
|
|
35
|
+
|
|
36
|
+
const editor = document.querySelector("sigvelo-interactive-editor");
|
|
37
|
+
editor.files = [
|
|
38
|
+
{ name: "index.html", content: "<h1>Hello</h1>" },
|
|
39
|
+
{ name: "main.js", content: 'console.log("hi")' },
|
|
40
|
+
];
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<sigvelo-interactive-editor entry-file="index.html" layout="vertical"></sigvelo-interactive-editor>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Runner assets
|
|
47
|
+
|
|
48
|
+
The package keeps its publish artifact small: it ships the runner entry points,
|
|
49
|
+
while PGlite, PyScript, and WebR remain normal runtime dependencies. Add the
|
|
50
|
+
provided Vite plugin to copy the runners and their engine assets into the
|
|
51
|
+
application output during development and production builds:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { defineConfig } from "vite";
|
|
55
|
+
import { interactiveRuntimeAssets } from "@mcp-b/interactive-components/vite";
|
|
56
|
+
|
|
57
|
+
export default defineConfig({
|
|
58
|
+
plugins: [...interactiveRuntimeAssets()],
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Then configure that same-origin mount before creating an editor:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { setRunnerBaseUrl } from "@mcp-b/interactive-components";
|
|
66
|
+
|
|
67
|
+
setRunnerBaseUrl(new URL("/assets/sigvelo/runners/", window.location.origin));
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The plugin preserves the required directory layout. Serve every runner response with the correct
|
|
71
|
+
MIME type and `Access-Control-Allow-Origin: *`. Python and R run in opaque
|
|
72
|
+
sandboxed frames (without `allow-same-origin`), so their runtime modules require
|
|
73
|
+
CORS. WebR also needs `blob:` in the runner document's `worker-src` Content
|
|
74
|
+
Security Policy because its trusted packaged worker is re-homed into the opaque frame. PGlite
|
|
75
|
+
runs in a module worker, so its entry point must stay on the application's
|
|
76
|
+
origin. Do not weaken the sandbox to work around a missing header or CSP rule.
|
|
77
|
+
|
|
78
|
+
## Styling
|
|
79
|
+
|
|
80
|
+
The component uses Sigvelo design tokens (`--sigvelo-*`) for all UI chrome (sidebar, buttons, console). Editor-specific tokens (`--sigvelo-interactive-editor-*`) control the code editing surface and syntax highlighting. See `src/themes/interactive.css` for the full list.
|
|
81
|
+
|
|
82
|
+
The component has no `border-radius` or `box-shadow` on its host element, so it fills its parent container flush. The parent is responsible for visual framing (border, radius, shadow).
|
|
83
|
+
|
|
84
|
+
### Customizable CSS properties
|
|
85
|
+
|
|
86
|
+
| Property | Default | Description |
|
|
87
|
+
| ---------------------------------------- | --------- | ----------------------------- |
|
|
88
|
+
| `--sigvelo-interactive-editor-height` | `480px` | Height of the editor |
|
|
89
|
+
| `--sigvelo-interactive-editor-bg` | `#f8f8f8` | Editor background |
|
|
90
|
+
| `--sigvelo-interactive-editor-gutter-bg` | `#f0f0f0` | Line number gutter background |
|
|
91
|
+
|
|
92
|
+
## Development
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pnpm dev # Build + Storybook on port 6007
|
|
96
|
+
pnpm build # Production build (tsc + CEM + Vite)
|
|
97
|
+
pnpm test # Vitest
|
|
98
|
+
pnpm storybook # Storybook only
|
|
99
|
+
```
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
import { t as __decorate } from "./decorate-DcF3lt7P.js";
|
|
2
|
+
import { css, html } from "lit";
|
|
3
|
+
import { property, query, state } from "lit/decorators.js";
|
|
4
|
+
import { SigveloElement } from "@mcp-b/wc-support/base/sigvelo-element";
|
|
5
|
+
import hostStyles from "@mcp-b/wc-support/styles/host.styles";
|
|
6
|
+
import { SigveloChangeEvent } from "@mcp-b/wc-support/events/form";
|
|
7
|
+
import { Compartment, EditorState } from "@codemirror/state";
|
|
8
|
+
import { EditorView, crosshairCursor, drawSelection, dropCursor, highlightActiveLine, highlightActiveLineGutter, keymap, lineNumbers, rectangularSelection } from "@codemirror/view";
|
|
9
|
+
import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands";
|
|
10
|
+
import { HighlightStyle, StreamLanguage, bracketMatching, defaultHighlightStyle, foldGutter, foldKeymap, indentOnInput, syntaxHighlighting } from "@codemirror/language";
|
|
11
|
+
import { tags } from "@lezer/highlight";
|
|
12
|
+
import { autocompletion, closeBrackets, closeBracketsKeymap, completionKeymap } from "@codemirror/autocomplete";
|
|
13
|
+
import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
|
|
14
|
+
import { javascript } from "@codemirror/lang-javascript";
|
|
15
|
+
import { html as html$1 } from "@codemirror/lang-html";
|
|
16
|
+
import { css as css$1 } from "@codemirror/lang-css";
|
|
17
|
+
import { python } from "@codemirror/lang-python";
|
|
18
|
+
import { r } from "@codemirror/legacy-modes/mode/r";
|
|
19
|
+
import { PostgreSQL, sql } from "@codemirror/lang-sql";
|
|
20
|
+
import { oneDark } from "@codemirror/theme-one-dark";
|
|
21
|
+
//#region src/components/code-editor/code-editor.styles.ts
|
|
22
|
+
var code_editor_styles_default = css`
|
|
23
|
+
:host {
|
|
24
|
+
display: block;
|
|
25
|
+
overflow: hidden;
|
|
26
|
+
font-family: var(
|
|
27
|
+
--sigvelo-font-mono,
|
|
28
|
+
"Fira Code",
|
|
29
|
+
"Cascadia Code",
|
|
30
|
+
"JetBrains Mono",
|
|
31
|
+
monospace
|
|
32
|
+
);
|
|
33
|
+
font-size: 13px;
|
|
34
|
+
background: var(--sigvelo-interactive-editor-bg, #f8f8f8);
|
|
35
|
+
height: 100%;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.cm-host {
|
|
39
|
+
height: 100%;
|
|
40
|
+
overflow: auto;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* CodeMirror overrides that work inside Shadow DOM */
|
|
44
|
+
.cm-host .cm-editor {
|
|
45
|
+
height: 100%;
|
|
46
|
+
outline: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.cm-host .cm-scroller {
|
|
50
|
+
font-family: inherit;
|
|
51
|
+
font-size: 13px;
|
|
52
|
+
line-height: 1.6;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.cm-host .cm-gutters {
|
|
56
|
+
border-right: none;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Fold gutter markers — rendered via CSS pseudo-elements so axe
|
|
60
|
+
doesn't flag non-text characters as inconclusive contrast. */
|
|
61
|
+
.cm-host .cm-fold-open::after,
|
|
62
|
+
.cm-host .cm-fold-closed::after {
|
|
63
|
+
display: inline-block;
|
|
64
|
+
font-size: 10px;
|
|
65
|
+
line-height: 1;
|
|
66
|
+
opacity: 0.5;
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
}
|
|
69
|
+
.cm-host .cm-fold-open::after {
|
|
70
|
+
content: "▾";
|
|
71
|
+
}
|
|
72
|
+
.cm-host .cm-fold-closed::after {
|
|
73
|
+
content: "▸";
|
|
74
|
+
}
|
|
75
|
+
`;
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/components/code-editor/code-editor.ts
|
|
78
|
+
const lightHighlight = HighlightStyle.define([
|
|
79
|
+
{
|
|
80
|
+
tag: tags.keyword,
|
|
81
|
+
color: "#cf222e"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
tag: tags.controlKeyword,
|
|
85
|
+
color: "#cf222e"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
tag: tags.moduleKeyword,
|
|
89
|
+
color: "#cf222e"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
tag: tags.operatorKeyword,
|
|
93
|
+
color: "#cf222e"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
tag: tags.definitionKeyword,
|
|
97
|
+
color: "#cf222e"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
tag: tags.operator,
|
|
101
|
+
color: "#24292f"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
tag: tags.separator,
|
|
105
|
+
color: "#24292f"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
tag: tags.punctuation,
|
|
109
|
+
color: "#24292f"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
tag: tags.bracket,
|
|
113
|
+
color: "#24292f"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
tag: tags.string,
|
|
117
|
+
color: "#0a3069"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
tag: tags.regexp,
|
|
121
|
+
color: "#0a3069"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
tag: [
|
|
125
|
+
tags.name,
|
|
126
|
+
tags.deleted,
|
|
127
|
+
tags.character
|
|
128
|
+
],
|
|
129
|
+
color: "#cf222e"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
tag: [tags.propertyName, tags.macroName],
|
|
133
|
+
color: "#0550ae"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
tag: [tags.function(tags.variableName), tags.labelName],
|
|
137
|
+
color: "#8250df"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
tag: [
|
|
141
|
+
tags.color,
|
|
142
|
+
tags.constant(tags.name),
|
|
143
|
+
tags.standard(tags.name)
|
|
144
|
+
],
|
|
145
|
+
color: "#0550ae"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
tag: [tags.definition(tags.name), tags.separator],
|
|
149
|
+
color: "#24292f"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
tag: [
|
|
153
|
+
tags.typeName,
|
|
154
|
+
tags.className,
|
|
155
|
+
tags.number,
|
|
156
|
+
tags.changed,
|
|
157
|
+
tags.annotation,
|
|
158
|
+
tags.self,
|
|
159
|
+
tags.namespace
|
|
160
|
+
],
|
|
161
|
+
color: "#953800"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
tag: tags.comment,
|
|
165
|
+
color: "#57606a",
|
|
166
|
+
fontStyle: "italic"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
tag: tags.meta,
|
|
170
|
+
color: "#57606a"
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
tag: tags.tagName,
|
|
174
|
+
color: "#116329"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
tag: tags.attributeName,
|
|
178
|
+
color: "#0550ae"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
tag: tags.attributeValue,
|
|
182
|
+
color: "#0a3069"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
tag: tags.processingInstruction,
|
|
186
|
+
color: "#57606a"
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
tag: tags.documentMeta,
|
|
190
|
+
color: "#57606a"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
tag: tags.heading,
|
|
194
|
+
color: "#24292f",
|
|
195
|
+
fontWeight: "bold"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
tag: tags.bool,
|
|
199
|
+
color: "#0550ae"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
tag: tags.atom,
|
|
203
|
+
color: "#0550ae"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
tag: tags.special(tags.variableName),
|
|
207
|
+
color: "#953800"
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
tag: tags.variableName,
|
|
211
|
+
color: "#24292f"
|
|
212
|
+
}
|
|
213
|
+
]);
|
|
214
|
+
const lightTheme = EditorView.theme({
|
|
215
|
+
"&": {
|
|
216
|
+
color: "#24292f",
|
|
217
|
+
backgroundColor: "#ffffff"
|
|
218
|
+
},
|
|
219
|
+
".cm-content": { caretColor: "#24292f" },
|
|
220
|
+
".cm-cursor": { borderLeftColor: "#24292f" },
|
|
221
|
+
"&.cm-focused .cm-selectionBackground, .cm-selectionBackground, ::selection": { backgroundColor: "#dae9fd" },
|
|
222
|
+
".cm-activeLine": { backgroundColor: "#f6f8fa" },
|
|
223
|
+
".cm-gutters": {
|
|
224
|
+
backgroundColor: "#f6f8fa",
|
|
225
|
+
color: "#636c76",
|
|
226
|
+
borderRight: "none"
|
|
227
|
+
},
|
|
228
|
+
".cm-activeLineGutter": { backgroundColor: "#eaeef2" }
|
|
229
|
+
}, { dark: false });
|
|
230
|
+
const darkTheme = EditorView.theme({
|
|
231
|
+
".cm-gutters": { color: "#9da5b4" },
|
|
232
|
+
".cm-gutterElement": { color: "#9da5b4" },
|
|
233
|
+
".ͼw": { color: "#9da5b4 !important" },
|
|
234
|
+
".ͼq": { color: "#e5c07b !important" },
|
|
235
|
+
".ͼp": { color: "#d9a2e8 !important" }
|
|
236
|
+
}, { dark: true });
|
|
237
|
+
function getLanguageExtension(lang) {
|
|
238
|
+
switch (lang) {
|
|
239
|
+
case "javascript": return javascript();
|
|
240
|
+
case "typescript": return javascript({ typescript: true });
|
|
241
|
+
case "jsx": return javascript({ jsx: true });
|
|
242
|
+
case "tsx": return javascript({
|
|
243
|
+
typescript: true,
|
|
244
|
+
jsx: true
|
|
245
|
+
});
|
|
246
|
+
case "html": return html$1();
|
|
247
|
+
case "css": return css$1();
|
|
248
|
+
case "python": return python();
|
|
249
|
+
case "r": return StreamLanguage.define(r);
|
|
250
|
+
case "sql": return sql({ dialect: PostgreSQL });
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* `<sigvelo-code-editor>`
|
|
255
|
+
*
|
|
256
|
+
* @summary A CodeMirror 6 wrapper that provides syntax-highlighted editing for
|
|
257
|
+
* a single document. Supports JavaScript, TypeScript, JSX, TSX, HTML, and CSS.
|
|
258
|
+
* Automatically detects dark mode from the `data-theme` attribute on the
|
|
259
|
+
* document root and applies the One Dark CodeMirror theme accordingly.
|
|
260
|
+
*
|
|
261
|
+
* @tag sigvelo-code-editor
|
|
262
|
+
* @status experimental
|
|
263
|
+
* @since 0.1
|
|
264
|
+
*
|
|
265
|
+
* @event sigvelo-change - Fires when the document content changes. `event.detail.value` contains the new content.
|
|
266
|
+
*/
|
|
267
|
+
var SigveloCodeEditor = class extends SigveloElement {
|
|
268
|
+
constructor(..._args) {
|
|
269
|
+
super(..._args);
|
|
270
|
+
this.value = "";
|
|
271
|
+
this.language = "javascript";
|
|
272
|
+
this.readonly = false;
|
|
273
|
+
this.editorLabel = "";
|
|
274
|
+
this._dark = false;
|
|
275
|
+
this._view = null;
|
|
276
|
+
this._langCompartment = new Compartment();
|
|
277
|
+
this._themeCompartment = new Compartment();
|
|
278
|
+
this._readonlyCompartment = new Compartment();
|
|
279
|
+
this._labelCompartment = new Compartment();
|
|
280
|
+
this._suppressExternalUpdate = false;
|
|
281
|
+
this._themeObserver = null;
|
|
282
|
+
this._systemTheme = null;
|
|
283
|
+
this._onSystemThemeChange = null;
|
|
284
|
+
}
|
|
285
|
+
static {
|
|
286
|
+
this.styles = [hostStyles, code_editor_styles_default];
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* The name exposed to assistive technology. CodeMirror renders a
|
|
290
|
+
* `role="textbox"` element, which must always be named, so an unset
|
|
291
|
+
* `editor-label` falls back to the language rather than leaving it anonymous.
|
|
292
|
+
*/
|
|
293
|
+
get accessibleLabel() {
|
|
294
|
+
return this.editorLabel || `${this.language} code editor`;
|
|
295
|
+
}
|
|
296
|
+
connectedCallback() {
|
|
297
|
+
super.connectedCallback();
|
|
298
|
+
this._dark = this._isDark();
|
|
299
|
+
this._observeTheme();
|
|
300
|
+
}
|
|
301
|
+
firstUpdated() {
|
|
302
|
+
this._createView();
|
|
303
|
+
}
|
|
304
|
+
updated(changed) {
|
|
305
|
+
if (!this._view) return;
|
|
306
|
+
const effects = [];
|
|
307
|
+
if (changed.has("language")) effects.push(this._langCompartment.reconfigure(getLanguageExtension(this.language)));
|
|
308
|
+
if (changed.has("_dark")) effects.push(this._themeCompartment.reconfigure(this._dark ? [oneDark, darkTheme] : [lightTheme, syntaxHighlighting(lightHighlight)]));
|
|
309
|
+
if (changed.has("readonly")) effects.push(this._readonlyCompartment.reconfigure(EditorState.readOnly.of(this.readonly)));
|
|
310
|
+
if (changed.has("editorLabel") || changed.has("language")) effects.push(this._labelCompartment.reconfigure(EditorView.contentAttributes.of({ "aria-label": this.accessibleLabel })));
|
|
311
|
+
if (effects.length) this._view.dispatch({ effects });
|
|
312
|
+
if (changed.has("value") && !this._suppressExternalUpdate) {
|
|
313
|
+
if (this._view.state.doc.toString() !== this.value) this._view.dispatch({ changes: {
|
|
314
|
+
from: 0,
|
|
315
|
+
to: this._view.state.doc.length,
|
|
316
|
+
insert: this.value
|
|
317
|
+
} });
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
disconnectedCallback() {
|
|
321
|
+
super.disconnectedCallback();
|
|
322
|
+
this._themeObserver?.disconnect();
|
|
323
|
+
if (this._systemTheme && this._onSystemThemeChange) this._systemTheme.removeEventListener("change", this._onSystemThemeChange);
|
|
324
|
+
this._systemTheme = null;
|
|
325
|
+
this._onSystemThemeChange = null;
|
|
326
|
+
this._view?.destroy();
|
|
327
|
+
this._view = null;
|
|
328
|
+
}
|
|
329
|
+
_isDark() {
|
|
330
|
+
const theme = document.documentElement.dataset.theme;
|
|
331
|
+
if (theme === "dark") return true;
|
|
332
|
+
if (theme === "light") return false;
|
|
333
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
334
|
+
}
|
|
335
|
+
_observeTheme() {
|
|
336
|
+
this._themeObserver = new MutationObserver(() => {
|
|
337
|
+
this._dark = this._isDark();
|
|
338
|
+
});
|
|
339
|
+
this._themeObserver.observe(document.documentElement, {
|
|
340
|
+
attributes: true,
|
|
341
|
+
attributeFilter: ["data-theme"]
|
|
342
|
+
});
|
|
343
|
+
this._systemTheme = window.matchMedia("(prefers-color-scheme: dark)");
|
|
344
|
+
this._onSystemThemeChange = () => {
|
|
345
|
+
this._dark = this._isDark();
|
|
346
|
+
};
|
|
347
|
+
this._systemTheme.addEventListener("change", this._onSystemThemeChange);
|
|
348
|
+
}
|
|
349
|
+
_createView() {
|
|
350
|
+
if (!this._host) return;
|
|
351
|
+
const editorState = EditorState.create({
|
|
352
|
+
doc: this.value,
|
|
353
|
+
extensions: [
|
|
354
|
+
lineNumbers(),
|
|
355
|
+
highlightActiveLineGutter(),
|
|
356
|
+
history(),
|
|
357
|
+
foldGutter({ markerDOM(open) {
|
|
358
|
+
const span = document.createElement("span");
|
|
359
|
+
span.setAttribute("aria-hidden", "true");
|
|
360
|
+
span.className = open ? "cm-fold-open" : "cm-fold-closed";
|
|
361
|
+
return span;
|
|
362
|
+
} }),
|
|
363
|
+
drawSelection(),
|
|
364
|
+
dropCursor(),
|
|
365
|
+
indentOnInput(),
|
|
366
|
+
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
|
367
|
+
bracketMatching(),
|
|
368
|
+
closeBrackets(),
|
|
369
|
+
autocompletion(),
|
|
370
|
+
rectangularSelection(),
|
|
371
|
+
crosshairCursor(),
|
|
372
|
+
highlightActiveLine(),
|
|
373
|
+
highlightSelectionMatches(),
|
|
374
|
+
keymap.of([
|
|
375
|
+
...closeBracketsKeymap,
|
|
376
|
+
...defaultKeymap,
|
|
377
|
+
...searchKeymap,
|
|
378
|
+
...historyKeymap,
|
|
379
|
+
...foldKeymap,
|
|
380
|
+
...completionKeymap,
|
|
381
|
+
indentWithTab
|
|
382
|
+
]),
|
|
383
|
+
this._langCompartment.of(getLanguageExtension(this.language)),
|
|
384
|
+
this._themeCompartment.of(this._dark ? [oneDark, darkTheme] : [lightTheme, syntaxHighlighting(lightHighlight)]),
|
|
385
|
+
this._readonlyCompartment.of(EditorState.readOnly.of(this.readonly)),
|
|
386
|
+
EditorView.updateListener.of((update) => {
|
|
387
|
+
if (update.docChanged) {
|
|
388
|
+
this._suppressExternalUpdate = true;
|
|
389
|
+
this.value = update.state.doc.toString();
|
|
390
|
+
this.dispatchEvent(new SigveloChangeEvent());
|
|
391
|
+
this._suppressExternalUpdate = false;
|
|
392
|
+
}
|
|
393
|
+
}),
|
|
394
|
+
this._labelCompartment.of(EditorView.contentAttributes.of({ "aria-label": this.accessibleLabel })),
|
|
395
|
+
EditorView.theme({
|
|
396
|
+
"&": { height: "100%" },
|
|
397
|
+
".cm-scroller": { overflow: "auto" }
|
|
398
|
+
})
|
|
399
|
+
]
|
|
400
|
+
});
|
|
401
|
+
this._view = new EditorView({
|
|
402
|
+
state: editorState,
|
|
403
|
+
parent: this._host,
|
|
404
|
+
root: this.shadowRoot ?? void 0
|
|
405
|
+
});
|
|
406
|
+
const scroller = this._view.scrollDOM;
|
|
407
|
+
if (scroller) scroller.tabIndex = 0;
|
|
408
|
+
}
|
|
409
|
+
/** Returns the underlying CodeMirror `EditorView`, or `null` if not yet created. */
|
|
410
|
+
getEditorView() {
|
|
411
|
+
return this._view;
|
|
412
|
+
}
|
|
413
|
+
render() {
|
|
414
|
+
return html` <div class="cm-host"></div> `;
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
__decorate([property()], SigveloCodeEditor.prototype, "value", void 0);
|
|
418
|
+
__decorate([property()], SigveloCodeEditor.prototype, "language", void 0);
|
|
419
|
+
__decorate([property({ type: Boolean })], SigveloCodeEditor.prototype, "readonly", void 0);
|
|
420
|
+
__decorate([property({ attribute: "editor-label" })], SigveloCodeEditor.prototype, "editorLabel", void 0);
|
|
421
|
+
__decorate([query(".cm-host")], SigveloCodeEditor.prototype, "_host", void 0);
|
|
422
|
+
__decorate([state()], SigveloCodeEditor.prototype, "_dark", void 0);
|
|
423
|
+
customElements.define("sigvelo-code-editor", SigveloCodeEditor);
|
|
424
|
+
//#endregion
|
|
425
|
+
export { SigveloCodeEditor as t };
|