tosijs-ui 1.6.22 → 1.7.0-beta.1
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/CHANGELOG.md +98 -2
- package/bin/make-icon-data.js +0 -0
- package/dist/code-editor-cm.d.ts +48 -0
- package/dist/code-editor-cm.js +243 -0
- package/dist/code-editor.d.ts +65 -9
- package/dist/code-editor.js +270 -75
- package/dist/doc-system/site/bundle-guard.d.ts +50 -0
- package/dist/doc-system/site/bundle-guard.js +111 -0
- package/dist/doc-system/site/check-examples.js +11 -3
- package/dist/doc-system/site/dev-server.js +49 -11
- package/dist/doc-system/site/epub.js +28 -9
- package/dist/doc-system/site/make-llms-txt.js +17 -1
- package/dist/doc-system/site/orchestrator.js +43 -12
- package/dist/iife.js +160 -109
- package/dist/iife.js.map +36 -8
- package/dist/live-example/code-transform.d.ts +39 -0
- package/dist/live-example/code-transform.js +305 -4
- package/dist/live-example/component.d.ts +10 -0
- package/dist/live-example/component.js +276 -14
- package/dist/live-example/execution.d.ts +16 -0
- package/dist/live-example/execution.js +29 -8
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/llms.txt +9 -2
- package/package.json +18 -4
- package/tls/create-dev-certs.sh +25 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,90 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.7.0-beta.1
|
|
4
|
+
|
|
5
|
+
**A beta, published under npm's `beta` tag** — `latest` stays on 1.6.x. A prerelease is not
|
|
6
|
+
matched by `^1.6.x` (or by `^1.7.0`), so nobody is auto-upgraded into the editor swap; you get
|
|
7
|
+
this only by asking for it:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
npm i tosijs-ui@beta # or tosijs-ui@1.7.0-beta.1
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The code editor moved from **ACE to [CodeMirror 6](https://codemirror.net/)**, `tjs`
|
|
14
|
+
became a first-class editing mode with runtime-value autocomplete, and the doc-site
|
|
15
|
+
builder gained the hooks that unblock the tosijs 2.0 TJS port.
|
|
16
|
+
|
|
17
|
+
**Known cost, deliberate for now.** `dist/iife.js` carries CodeMirror (bun's IIFE format cannot
|
|
18
|
+
code-split), and generated doc pages hide the body until hydration — so on a cheap phone the
|
|
19
|
+
blank-screen window is ~4.5s vs ~3.7s without the editor. The fix is to pre-render the page
|
|
20
|
+
chrome so hydration is additive and the gate can go (then the bundle gates *editing*, not
|
|
21
|
+
*reading*); that's the next doc-system release, not this one. Measurements in `TODO.md`.
|
|
22
|
+
|
|
23
|
+
### Breaking
|
|
24
|
+
|
|
25
|
+
`<tosi-code>` (ACE → CodeMirror 6). Each removed member now **warns once and no-ops**
|
|
26
|
+
rather than failing silently, but they are gone:
|
|
27
|
+
|
|
28
|
+
| removed | replacement |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| `theme` attribute | style the editor with `--code-bg` / `--text-color` |
|
|
31
|
+
| `options` property (ACE-shaped) | configure via `editor` (a CodeMirror `EditorView`) |
|
|
32
|
+
| `ace` getter | there is no ACE global; use `editor` |
|
|
33
|
+
| `editor.session.getUndoManager()` | `undo()` / `redo()` / `canUndo()` / `canRedo()` |
|
|
34
|
+
|
|
35
|
+
**`editor` changed type in place** — it was an ACE `Editor`, it is now a CodeMirror
|
|
36
|
+
[`EditorView`](https://codemirror.net/docs/ref/#view.EditorView). A grep for the
|
|
37
|
+
removed names will not catch this; any code reaching into `editor` needs revisiting.
|
|
38
|
+
|
|
39
|
+
Unchanged: `value`, `original` / `showDiff()`, `mode`, `disabled`.
|
|
40
|
+
|
|
41
|
+
**Semver stance (deliberate, not an oversight).** This library breaks in minors before 2.0 —
|
|
42
|
+
**`2.0` is reserved for the tjs-native rewrite**, not for this. So `^1.6.x` resolves `1.7.0` and
|
|
43
|
+
existing consumers pick this up on their next install.
|
|
44
|
+
|
|
45
|
+
**If you use `<tosi-code>`, pin `~1.6` and upgrade deliberately.** Everything else in the library
|
|
46
|
+
is untouched, so a consumer of (say) `<tosi-rating>` can take 1.7 without changes — but note it
|
|
47
|
+
now installs 12 `@codemirror/*` runtime dependencies where the library previously had none.
|
|
48
|
+
|
|
49
|
+
The trap to know about: **`editor` changed type in place** and no shim can catch it. The removed
|
|
50
|
+
`theme` / `options` / `ace` members warn once and no-op, but `el.editor` still exists — it is
|
|
51
|
+
simply a CodeMirror `EditorView` now, so `el.editor.session.*` is a runtime `TypeError`. A grep
|
|
52
|
+
for the removed names will not find it.
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
|
|
56
|
+
- `<tosi-code>` gained a `change` event (`event.detail.value`), `undo()` / `redo()` /
|
|
57
|
+
`canUndo()` / `canRedo()`, and `tjs` / `ajs` modes.
|
|
58
|
+
- **Runtime-value autocomplete** in `tjs` mode: set `tjsAutocomplete` and completion
|
|
59
|
+
suggests the *real members of live values* — including tosijs proxy members that no
|
|
60
|
+
static analysis can see. Live examples wire their own executed scope into it, so
|
|
61
|
+
`const { app } = tosi(…)` gives real `app.` / `app.items.` completions.
|
|
62
|
+
- Inline **WebAssembly** live examples (tjs `wasm {}` blocks).
|
|
63
|
+
- `buildSite`: `libraryBuild` and `generateCssPreload` hooks, for projects whose
|
|
64
|
+
library sources are native `.tjs` (this is what the tosijs 2.0 TJS port needs).
|
|
65
|
+
**These actually shipped in 1.6.21** — they are listed here only because they landed on this
|
|
66
|
+
branch first. Nothing needs 1.7 to use them.
|
|
67
|
+
|
|
68
|
+
### Changed
|
|
69
|
+
|
|
70
|
+
- **`dist/iife.js` is ~384KB gzipped, up from ~120KB.** Bun's IIFE format cannot
|
|
71
|
+
code-split, so CodeMirror is inlined there. (Under a bundler/ESM it stays a lazy
|
|
72
|
+
chunk — a page with no `<tosi-code>` doesn't load it.) This is deliberate: the
|
|
73
|
+
in-page editor and its save-to-source flow are the point of the doc-system, so the
|
|
74
|
+
IIFE carries the editor.
|
|
75
|
+
- The library now has runtime `dependencies` (12 `@codemirror/*` packages) where it
|
|
76
|
+
previously had none. They can't be optional peers: the tjs CodeMirror extension must
|
|
77
|
+
share this exact `@codemirror/state` instance or it silently no-ops.
|
|
78
|
+
- `tjs-lang` peer: `^0.8.7` → `^0.9.1`.
|
|
79
|
+
|
|
80
|
+
### Fixed
|
|
81
|
+
|
|
82
|
+
- `showDiff()` rendered nothing. Giving `<tosi-code>` its own `content` displaced the
|
|
83
|
+
default `<slot>` that used to project the light-DOM diff overlay, so the overlay was
|
|
84
|
+
invisible (0×0) while `showingDiff` still reported `true`. It now renders inside the
|
|
85
|
+
shadow root. This is the review step of the doc-system's edit-and-save-to-source
|
|
86
|
+
flow, so a blank diff meant saving changes you never saw.
|
|
87
|
+
|
|
3
88
|
## 1.6.22
|
|
4
89
|
|
|
5
90
|
### Fixed
|
|
@@ -33,8 +118,19 @@
|
|
|
33
118
|
|
|
34
119
|
## 1.6.21
|
|
35
120
|
|
|
36
|
-
|
|
37
|
-
|
|
121
|
+
### Fixed
|
|
122
|
+
|
|
123
|
+
- Doc-system nav-toggle in `routing: 'memory'` mode drove the *outer* doc-browser
|
|
124
|
+
instance instead of its own (now scoped per-instance).
|
|
125
|
+
|
|
126
|
+
### Added
|
|
127
|
+
|
|
128
|
+
- `buildSite` `libraryBuild` + `generateCssPreload` hooks (also in 1.7.0 above), so a
|
|
129
|
+
project whose library source is native `.tjs` can build through the doc-site pipeline.
|
|
130
|
+
|
|
131
|
+
### Changed
|
|
132
|
+
|
|
133
|
+
- `tjs-lang` peer: `^0.8.7` → `^0.9.0`.
|
|
38
134
|
|
|
39
135
|
## 1.6.20
|
|
40
136
|
|
package/bin/make-icon-data.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { EditorView } from '@codemirror/view';
|
|
2
|
+
import { Extension } from '@codemirror/state';
|
|
3
|
+
/** Map a `<tosi-code mode>` value to a CodeMirror language extension. */
|
|
4
|
+
export declare function languageForMode(mode: string): Extension;
|
|
5
|
+
/** Runtime-introspection hooks for tjs autocomplete (all optional). */
|
|
6
|
+
export interface TjsAutocompleteConfig {
|
|
7
|
+
getMetadata?: () => Record<string, unknown> | undefined;
|
|
8
|
+
getImports?: () => Record<string, Record<string, unknown>> | undefined;
|
|
9
|
+
getLiveBindings?: () => Record<string, unknown> | undefined;
|
|
10
|
+
getMembers?: (path: string) => Promise<unknown[] | undefined>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Lazy-load tjs-lang's CodeMirror language + completion bundle. Returns a single
|
|
14
|
+
* CodeMirror `Extension` (tjs language, forbidden-keyword highlighting, theme, and
|
|
15
|
+
* `tjsCompletionSource`-driven autocomplete) suitable for `setLanguageExtension()`,
|
|
16
|
+
* or `null` when tjs-lang (an optional peer) isn't installed or its editor build
|
|
17
|
+
* lacks `tjsEditorExtension`. The dynamic import keeps it out of the bundle until a
|
|
18
|
+
* tjs editor actually mounts.
|
|
19
|
+
*/
|
|
20
|
+
export declare function loadTjsExtension(autocomplete?: TjsAutocompleteConfig): Promise<Extension | null>;
|
|
21
|
+
export interface CmHandle {
|
|
22
|
+
view: EditorView;
|
|
23
|
+
getValue(): string;
|
|
24
|
+
setValue(text: string): void;
|
|
25
|
+
setMode(mode: string): void;
|
|
26
|
+
/** Swap the language compartment wholesale (e.g. an async-loaded tjs bundle). */
|
|
27
|
+
setLanguageExtension(ext: Extension): void;
|
|
28
|
+
setReadOnly(readOnly: boolean): void;
|
|
29
|
+
undo(): void;
|
|
30
|
+
redo(): void;
|
|
31
|
+
canUndo(): boolean;
|
|
32
|
+
canRedo(): boolean;
|
|
33
|
+
focus(): void;
|
|
34
|
+
refresh(): void;
|
|
35
|
+
destroy(): void;
|
|
36
|
+
}
|
|
37
|
+
export interface CmOptions {
|
|
38
|
+
value?: string;
|
|
39
|
+
mode?: string;
|
|
40
|
+
readOnly?: boolean;
|
|
41
|
+
/** additional language-adjacent extensions (e.g. a tjs language + autocomplete) */
|
|
42
|
+
languageExtension?: Extension;
|
|
43
|
+
onChange?: (value: string) => void;
|
|
44
|
+
/** style-injection root — pass the host's ShadowRoot when mounted in shadow DOM */
|
|
45
|
+
root?: Document | ShadowRoot;
|
|
46
|
+
}
|
|
47
|
+
/** Create a CodeMirror editor mounted in `parent`, returning an editor-agnostic handle. */
|
|
48
|
+
export declare function createCmEditor(parent: HTMLElement, opts?: CmOptions): CmHandle;
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/*
|
|
2
|
+
CodeMirror 6 editor factory — the "heavy" module.
|
|
3
|
+
|
|
4
|
+
`code-editor.ts` imports this **dynamically** (on first `<tosi-code>` connect), so
|
|
5
|
+
CodeMirror only enters a consumer's bundle as a separate lazy chunk when the editor
|
|
6
|
+
is actually used — mirroring the way the old ACE build loaded from a CDN on first
|
|
7
|
+
use. No `<tosi-code>` in the page → no CodeMirror.
|
|
8
|
+
|
|
9
|
+
Languages here are the always-available set (js/ts/css/html/markdown). First-class
|
|
10
|
+
tjs (highlighting + runtime-value autocomplete via tjs-lang's editors/codemirror) is
|
|
11
|
+
layered in separately and only when tjs-lang is installed.
|
|
12
|
+
*/
|
|
13
|
+
import { EditorView, keymap, lineNumbers, highlightActiveLineGutter, highlightSpecialChars, drawSelection, dropCursor, rectangularSelection, crosshairCursor, highlightActiveLine, } from '@codemirror/view';
|
|
14
|
+
import { EditorState, Compartment } from '@codemirror/state';
|
|
15
|
+
import { indentWithTab, history, defaultKeymap, historyKeymap, undo, redo, undoDepth, redoDepth, } from '@codemirror/commands';
|
|
16
|
+
import { indentUnit, foldGutter, foldKeymap, indentOnInput, syntaxHighlighting, defaultHighlightStyle, bracketMatching, } from '@codemirror/language';
|
|
17
|
+
import { closeBrackets, closeBracketsKeymap, autocompletion, completionKeymap, } from '@codemirror/autocomplete';
|
|
18
|
+
import { searchKeymap, highlightSelectionMatches } from '@codemirror/search';
|
|
19
|
+
import { lintKeymap } from '@codemirror/lint';
|
|
20
|
+
import { javascript } from '@codemirror/lang-javascript';
|
|
21
|
+
import { css } from '@codemirror/lang-css';
|
|
22
|
+
import { html } from '@codemirror/lang-html';
|
|
23
|
+
import { markdown } from '@codemirror/lang-markdown';
|
|
24
|
+
import { oneDarkHighlightStyle } from '@codemirror/theme-one-dark';
|
|
25
|
+
// The doc-system flips dark mode with a `darkmode` class on <body> (which inverts
|
|
26
|
+
// the luminance of --code-bg / --text-color, so the editor SURFACE adapts for
|
|
27
|
+
// free). Only CM's syntax-token colors need swapping: the light defaultHighlightStyle
|
|
28
|
+
// washes out on a dark surface, so use oneDark's brighter palette in dark mode.
|
|
29
|
+
const isDarkMode = () => typeof document !== 'undefined' &&
|
|
30
|
+
!!document.body &&
|
|
31
|
+
document.body.classList.contains('darkmode');
|
|
32
|
+
const highlightFor = (dark) => dark
|
|
33
|
+
? syntaxHighlighting(oneDarkHighlightStyle)
|
|
34
|
+
: syntaxHighlighting(defaultHighlightStyle, { fallback: true });
|
|
35
|
+
/** Map a `<tosi-code mode>` value to a CodeMirror language extension. */
|
|
36
|
+
export function languageForMode(mode) {
|
|
37
|
+
switch (mode) {
|
|
38
|
+
case 'js':
|
|
39
|
+
case 'javascript':
|
|
40
|
+
return javascript();
|
|
41
|
+
case 'ts':
|
|
42
|
+
case 'typescript':
|
|
43
|
+
// tjs highlights as TypeScript here (the sync default). First-class tjs — the
|
|
44
|
+
// tjs-lang language + autocomplete — is layered on asynchronously via
|
|
45
|
+
// `loadTjsExtension()` + `setLanguageExtension()`, since it lazy-loads the
|
|
46
|
+
// (optional) tjs-lang editor build; this keeps `mode="tjs"` readable meanwhile.
|
|
47
|
+
// falls through
|
|
48
|
+
case 'tjs':
|
|
49
|
+
case 'ajs':
|
|
50
|
+
return javascript({ typescript: true });
|
|
51
|
+
case 'css':
|
|
52
|
+
return css();
|
|
53
|
+
case 'html':
|
|
54
|
+
return html();
|
|
55
|
+
case 'md':
|
|
56
|
+
case 'markdown':
|
|
57
|
+
return markdown();
|
|
58
|
+
default:
|
|
59
|
+
return javascript();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// The language compartment carries the language AND its completion source, so
|
|
63
|
+
// exactly ONE `autocompletion()` is ever active: standard modes use CM's built-in
|
|
64
|
+
// (language-provided) completions here, while the tjs bundle brings its own
|
|
65
|
+
// `autocompletion({ override: [tjsCompletionSource] })`. (This is why the base
|
|
66
|
+
// extension set below does NOT include `autocompletion()`.)
|
|
67
|
+
function standardLanguageBundle(mode) {
|
|
68
|
+
return [languageForMode(mode), autocompletion()];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Lazy-load tjs-lang's CodeMirror language + completion bundle. Returns a single
|
|
72
|
+
* CodeMirror `Extension` (tjs language, forbidden-keyword highlighting, theme, and
|
|
73
|
+
* `tjsCompletionSource`-driven autocomplete) suitable for `setLanguageExtension()`,
|
|
74
|
+
* or `null` when tjs-lang (an optional peer) isn't installed or its editor build
|
|
75
|
+
* lacks `tjsEditorExtension`. The dynamic import keeps it out of the bundle until a
|
|
76
|
+
* tjs editor actually mounts.
|
|
77
|
+
*/
|
|
78
|
+
export async function loadTjsExtension(autocomplete = {}) {
|
|
79
|
+
try {
|
|
80
|
+
const mod = (await import('tjs-lang/editors/codemirror'));
|
|
81
|
+
if (typeof mod.tjsEditorExtension === 'function') {
|
|
82
|
+
return mod.tjsEditorExtension({ typescript: true, autocomplete });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// tjs-lang absent or editor build unavailable — caller keeps TS highlighting.
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
// A minimal theme so the editor has a real surface instead of showing whatever is
|
|
91
|
+
// behind it. It's applied as a CodeMirror theme (not shadow-DOM CSS) so it beats
|
|
92
|
+
// CM's injected base styles. Colors come from the doc-system theme vars
|
|
93
|
+
// (`--code-bg` / `--text-color`, which pierce the shadow root and adapt to dark
|
|
94
|
+
// mode) with sensible standalone fallbacks.
|
|
95
|
+
const editorTheme = EditorView.theme({
|
|
96
|
+
'&': {
|
|
97
|
+
height: '100%',
|
|
98
|
+
backgroundColor: 'var(--code-bg, var(--input-bg, #fdfdfd))',
|
|
99
|
+
color: 'var(--text-color, #222)',
|
|
100
|
+
},
|
|
101
|
+
'.cm-scroller': {
|
|
102
|
+
fontFamily: "Menlo, Monaco, Consolas, 'Courier New', monospace",
|
|
103
|
+
},
|
|
104
|
+
'.cm-gutters': {
|
|
105
|
+
backgroundColor: 'var(--code-bg, var(--input-bg, #fdfdfd))',
|
|
106
|
+
color: 'var(--text-color, #888)',
|
|
107
|
+
border: 'none',
|
|
108
|
+
},
|
|
109
|
+
'.cm-activeLine': { backgroundColor: 'transparent' },
|
|
110
|
+
'.cm-activeLineGutter': { backgroundColor: 'transparent' },
|
|
111
|
+
});
|
|
112
|
+
// A basicSetup-equivalent without a hard-coded color theme, so the host page's CSS
|
|
113
|
+
// (and dark mode) controls the palette. Line-wrapping mirrors the old ACE `wrap:true`.
|
|
114
|
+
function baseExtensions() {
|
|
115
|
+
return [
|
|
116
|
+
editorTheme,
|
|
117
|
+
lineNumbers(),
|
|
118
|
+
highlightActiveLineGutter(),
|
|
119
|
+
highlightSpecialChars(),
|
|
120
|
+
history(),
|
|
121
|
+
foldGutter(),
|
|
122
|
+
drawSelection(),
|
|
123
|
+
dropCursor(),
|
|
124
|
+
EditorState.allowMultipleSelections.of(true),
|
|
125
|
+
indentOnInput(),
|
|
126
|
+
indentUnit.of(' '),
|
|
127
|
+
EditorState.tabSize.of(2),
|
|
128
|
+
// syntax highlighting is applied per-instance via a compartment (dark-mode aware)
|
|
129
|
+
bracketMatching(),
|
|
130
|
+
closeBrackets(),
|
|
131
|
+
// NB: autocompletion() lives in the language compartment (see
|
|
132
|
+
// standardLanguageBundle) so tjs's own completion source never doubles up.
|
|
133
|
+
rectangularSelection(),
|
|
134
|
+
crosshairCursor(),
|
|
135
|
+
highlightActiveLine(),
|
|
136
|
+
highlightSelectionMatches(),
|
|
137
|
+
EditorView.lineWrapping,
|
|
138
|
+
keymap.of([
|
|
139
|
+
indentWithTab,
|
|
140
|
+
...closeBracketsKeymap,
|
|
141
|
+
...defaultKeymap,
|
|
142
|
+
...searchKeymap,
|
|
143
|
+
...historyKeymap,
|
|
144
|
+
...foldKeymap,
|
|
145
|
+
...completionKeymap,
|
|
146
|
+
...lintKeymap,
|
|
147
|
+
]),
|
|
148
|
+
];
|
|
149
|
+
}
|
|
150
|
+
const darkListeners = new Set();
|
|
151
|
+
let darkObserver;
|
|
152
|
+
function watchDarkMode(listener) {
|
|
153
|
+
darkListeners.add(listener);
|
|
154
|
+
if (darkObserver === undefined &&
|
|
155
|
+
typeof MutationObserver !== 'undefined' &&
|
|
156
|
+
typeof document !== 'undefined' &&
|
|
157
|
+
document.body) {
|
|
158
|
+
darkObserver = new MutationObserver(() => {
|
|
159
|
+
for (const l of darkListeners)
|
|
160
|
+
l();
|
|
161
|
+
});
|
|
162
|
+
darkObserver.observe(document.body, {
|
|
163
|
+
attributes: true,
|
|
164
|
+
attributeFilter: ['class'],
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return () => {
|
|
168
|
+
darkListeners.delete(listener);
|
|
169
|
+
if (darkListeners.size === 0) {
|
|
170
|
+
darkObserver?.disconnect();
|
|
171
|
+
darkObserver = undefined;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/** Create a CodeMirror editor mounted in `parent`, returning an editor-agnostic handle. */
|
|
176
|
+
export function createCmEditor(parent, opts = {}) {
|
|
177
|
+
const language = new Compartment();
|
|
178
|
+
const readonly = new Compartment();
|
|
179
|
+
const highlight = new Compartment();
|
|
180
|
+
const langExt = opts.languageExtension ?? standardLanguageBundle(opts.mode ?? 'javascript');
|
|
181
|
+
const view = new EditorView({
|
|
182
|
+
parent,
|
|
183
|
+
root: opts.root,
|
|
184
|
+
state: EditorState.create({
|
|
185
|
+
doc: opts.value ?? '',
|
|
186
|
+
extensions: [
|
|
187
|
+
baseExtensions(),
|
|
188
|
+
highlight.of(highlightFor(isDarkMode())),
|
|
189
|
+
language.of(langExt),
|
|
190
|
+
readonly.of(EditorState.readOnly.of(!!opts.readOnly)),
|
|
191
|
+
EditorView.updateListener.of((u) => {
|
|
192
|
+
if (u.docChanged && opts.onChange)
|
|
193
|
+
opts.onChange(u.state.doc.toString());
|
|
194
|
+
}),
|
|
195
|
+
],
|
|
196
|
+
}),
|
|
197
|
+
});
|
|
198
|
+
// Re-apply the right highlight palette when the doc-system toggles dark mode
|
|
199
|
+
// (it flips the `darkmode` class on <body>).
|
|
200
|
+
let dark = isDarkMode();
|
|
201
|
+
const unwatchDark = watchDarkMode(() => {
|
|
202
|
+
const nowDark = isDarkMode();
|
|
203
|
+
if (nowDark !== dark) {
|
|
204
|
+
dark = nowDark;
|
|
205
|
+
view.dispatch({ effects: highlight.reconfigure(highlightFor(dark)) });
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
const handle = {
|
|
209
|
+
view,
|
|
210
|
+
getValue: () => view.state.doc.toString(),
|
|
211
|
+
setValue(text) {
|
|
212
|
+
if (view.state.doc.toString() === text)
|
|
213
|
+
return;
|
|
214
|
+
view.dispatch({
|
|
215
|
+
changes: { from: 0, to: view.state.doc.length, insert: text },
|
|
216
|
+
});
|
|
217
|
+
},
|
|
218
|
+
setMode(mode) {
|
|
219
|
+
view.dispatch({
|
|
220
|
+
effects: language.reconfigure(standardLanguageBundle(mode)),
|
|
221
|
+
});
|
|
222
|
+
},
|
|
223
|
+
setLanguageExtension(ext) {
|
|
224
|
+
view.dispatch({ effects: language.reconfigure(ext) });
|
|
225
|
+
},
|
|
226
|
+
setReadOnly(ro) {
|
|
227
|
+
view.dispatch({
|
|
228
|
+
effects: readonly.reconfigure(EditorState.readOnly.of(ro)),
|
|
229
|
+
});
|
|
230
|
+
},
|
|
231
|
+
undo: () => void undo(view),
|
|
232
|
+
redo: () => void redo(view),
|
|
233
|
+
canUndo: () => undoDepth(view.state) > 0,
|
|
234
|
+
canRedo: () => redoDepth(view.state) > 0,
|
|
235
|
+
focus: () => view.focus(),
|
|
236
|
+
refresh: () => view.requestMeasure(),
|
|
237
|
+
destroy: () => {
|
|
238
|
+
unwatchDark();
|
|
239
|
+
view.destroy();
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
return handle;
|
|
243
|
+
}
|
package/dist/code-editor.d.ts
CHANGED
|
@@ -1,27 +1,58 @@
|
|
|
1
|
-
import { Component as WebComponent, ElementCreator } from 'tosijs';
|
|
2
|
-
|
|
1
|
+
import { Component as WebComponent, ElementCreator, PartsMap } from 'tosijs';
|
|
2
|
+
import type { CmHandle, TjsAutocompleteConfig } from './code-editor-cm';
|
|
3
|
+
export type { TjsAutocompleteConfig } from './code-editor-cm';
|
|
4
|
+
interface CodeEditorParts extends PartsMap {
|
|
5
|
+
host: HTMLDivElement;
|
|
6
|
+
diffHost: HTMLDivElement;
|
|
7
|
+
}
|
|
8
|
+
export declare class CodeEditor extends WebComponent<CodeEditorParts> {
|
|
3
9
|
static preferredTagName: string;
|
|
4
10
|
private source;
|
|
11
|
+
private _handle;
|
|
12
|
+
private _loadPromise;
|
|
13
|
+
private _loadGeneration;
|
|
14
|
+
private _appliedMode;
|
|
15
|
+
private _appliedDisabled;
|
|
16
|
+
private _tjsAutocomplete;
|
|
17
|
+
/**
|
|
18
|
+
* Runtime-introspection hooks for tjs autocomplete (`getLiveBindings` /
|
|
19
|
+
* `getMembers`) — lets completion suggest the REAL members of live values (e.g.
|
|
20
|
+
* a tosijs proxy or a DOM element) that static analysis can't see. Only used in
|
|
21
|
+
* tjs mode; setting it re-applies the tjs extension so it takes effect live.
|
|
22
|
+
*/
|
|
23
|
+
get tjsAutocomplete(): TjsAutocompleteConfig | undefined;
|
|
24
|
+
set tjsAutocomplete(config: TjsAutocompleteConfig | undefined);
|
|
5
25
|
get value(): string;
|
|
6
26
|
set value(text: string);
|
|
7
27
|
private _original;
|
|
8
28
|
get original(): string;
|
|
9
29
|
set original(text: string);
|
|
10
30
|
private diffOverlay;
|
|
31
|
+
private _partsHydrated;
|
|
32
|
+
private _pendingDiff;
|
|
33
|
+
private get partsReady();
|
|
11
34
|
get showingDiff(): boolean;
|
|
12
35
|
showDiff(on: boolean): void;
|
|
13
36
|
static initAttributes: {
|
|
14
37
|
mode: string;
|
|
15
|
-
theme: string;
|
|
16
38
|
disabled: boolean;
|
|
17
39
|
};
|
|
18
40
|
role: string;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
41
|
+
/** The underlying CodeMirror EditorView (undefined until loaded). */
|
|
42
|
+
get editor(): CmHandle['view'] | undefined;
|
|
43
|
+
/** @deprecated Removed in 1.7 — CodeMirror themes via `--code-bg`/`--text-color`. */
|
|
44
|
+
get theme(): string;
|
|
45
|
+
set theme(_: string);
|
|
46
|
+
/** @deprecated Removed in 1.7 — ACE-shaped options have no CodeMirror equivalent. */
|
|
47
|
+
get options(): Record<string, unknown>;
|
|
48
|
+
set options(_: Record<string, unknown>);
|
|
49
|
+
/** @deprecated Removed in 1.7 — there is no ACE global; use `editor` (an EditorView). */
|
|
50
|
+
get ace(): undefined;
|
|
51
|
+
undo(): void;
|
|
52
|
+
redo(): void;
|
|
53
|
+
canUndo(): boolean;
|
|
54
|
+
canRedo(): boolean;
|
|
55
|
+
content: () => HTMLDivElement[];
|
|
25
56
|
static shadowStyleSpec: {
|
|
26
57
|
':host': {
|
|
27
58
|
display: string;
|
|
@@ -29,9 +60,34 @@ export declare class CodeEditor extends WebComponent {
|
|
|
29
60
|
width: string;
|
|
30
61
|
height: string;
|
|
31
62
|
};
|
|
63
|
+
'[part="host"]': {
|
|
64
|
+
height: string;
|
|
65
|
+
};
|
|
66
|
+
'[part="diffHost"]': {
|
|
67
|
+
position: string;
|
|
68
|
+
inset: string;
|
|
69
|
+
zIndex: string;
|
|
70
|
+
overflow: string;
|
|
71
|
+
background: string;
|
|
72
|
+
};
|
|
73
|
+
'.cm-editor': {
|
|
74
|
+
height: string;
|
|
75
|
+
};
|
|
76
|
+
'.cm-scroller': {
|
|
77
|
+
outline: string;
|
|
78
|
+
fontFamily: string;
|
|
79
|
+
};
|
|
32
80
|
};
|
|
33
81
|
onResize(): void;
|
|
34
82
|
connectedCallback(): void;
|
|
83
|
+
disconnectedCallback(): void;
|
|
84
|
+
private isTjsMode;
|
|
85
|
+
/**
|
|
86
|
+
* When in tjs mode, lazily upgrade the editor to tjs-lang's CodeMirror language +
|
|
87
|
+
* autocomplete. No-op (keeps TS highlighting) if not tjs, if tjs-lang isn't
|
|
88
|
+
* installed, or if the mode/handle changed before the async load resolved.
|
|
89
|
+
*/
|
|
90
|
+
private applyTjsExtension;
|
|
35
91
|
render(): void;
|
|
36
92
|
}
|
|
37
93
|
export declare const codeEditor: ElementCreator<CodeEditor>;
|