weml-monaco 0.9.0 → 0.10.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/CHANGELOG.md +21 -0
- package/README.md +8 -3
- package/dist/editor.cjs +53 -14
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.d.mts +17 -1
- package/dist/editor.d.ts +17 -1
- package/dist/editor.mjs +53 -14
- package/dist/editor.mjs.map +1 -1
- package/dist/preview.cjs +19 -3
- package/dist/preview.cjs.map +1 -1
- package/dist/preview.d.mts +17 -1
- package/dist/preview.d.ts +17 -1
- package/dist/preview.mjs +19 -3
- package/dist/preview.mjs.map +1 -1
- package/dist/react.cjs +5 -0
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.mts +19 -2
- package/dist/react.d.ts +19 -2
- package/dist/react.mjs +5 -0
- package/dist/react.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,27 @@ This package shares the language logic of the VS Code extension (`weml-support`)
|
|
|
8
8
|
entries below track the port catching up with its provider changes; since the shared language
|
|
9
9
|
features, both take the same code.
|
|
10
10
|
|
|
11
|
+
## [0.10.0] — 2026-10-14
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- The preview takes the host's direction and language: `createWemlPreview(editor, { language: { dir,
|
|
15
|
+
lang } })` and `preview.setLanguage(...)`, each field over the document's own `<html dir lang>`. A
|
|
16
|
+
fragment has none — a paragraph of a right-to-left publication rendered left to right.
|
|
17
|
+
- The editor passes them on: `preview.language` (`createWemlEditor`), `setPreviewLanguage`; in
|
|
18
|
+
`<WemlEditor>` the prop is followed, as `preview.theme` is.
|
|
19
|
+
|
|
20
|
+
VS Code has no counterpart: its preview shows a file, whose own `<html dir lang>` it already
|
|
21
|
+
follows, and has no host to know a language the file does not declare.
|
|
22
|
+
|
|
23
|
+
## [0.9.1] — 2026-10-14
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- `createWemlEditor`: an editor opened after the last one on the same Monaco closed has the language
|
|
27
|
+
again — highlighting, completion, hover, diagnostics, formatting. The `weml` id outlives the
|
|
28
|
+
disposed registration (Monaco cannot unregister a language) and was taken for someone else's.
|
|
29
|
+
- The paragraph mode keeps the host's `readOnly` (`editorOptions`, the Settings view) and its
|
|
30
|
+
`readOnlyMessage`: the wrapper guard only adds its own lock, while the selection touches the wrapper.
|
|
31
|
+
|
|
11
32
|
## [0.9.0] — 2026-10-13
|
|
12
33
|
|
|
13
34
|
### Added
|
package/README.md
CHANGED
|
@@ -240,7 +240,9 @@ weml.dispose();
|
|
|
240
240
|
`.monaco-component`); the workbench colours Monaco lacks (tabs, side bar, status
|
|
241
241
|
bar) are derived from the editor's. The stylesheet is injected, and published as
|
|
242
242
|
`weml-monaco/editor.css` (`injectStyles: false` to link it).
|
|
243
|
-
- The preview renders with `weml-stylesheet`, so this entry needs it installed.
|
|
243
|
+
- The preview renders with `weml-stylesheet`, so this entry needs it installed. The host's
|
|
244
|
+
direction and language go in `preview.language` (`{ dir, lang }`, over the document's own; a
|
|
245
|
+
paragraph has none), changed with `setPreviewLanguage`.
|
|
244
246
|
|
|
245
247
|
## React
|
|
246
248
|
|
|
@@ -253,7 +255,7 @@ import { WemlEditor, type WemlEditorApi } from 'weml-monaco/react';
|
|
|
253
255
|
A thin component over `createWemlEditor` (React is an optional peer dependency,
|
|
254
256
|
`>=18`): the options are its props, `editorRef` gives the editor's API
|
|
255
257
|
(`WemlEditorApi`). Props marked `@mount` are read once — a change to one needs a
|
|
256
|
-
new `key`; `fileName`, `saving`, `saveDisabled` and `preview.
|
|
258
|
+
new `key`; `fileName`, `saving`, `saveDisabled`, `preview.theme` and `preview.language` follow their props.
|
|
257
259
|
`sidePanels` take React content (`content: node | (editor) => node`), rendered into
|
|
258
260
|
their views through portals — inside the application's context. React and react-dom
|
|
259
261
|
are optional peer dependencies (`>=18`).
|
|
@@ -345,7 +347,10 @@ preview.dispose();
|
|
|
345
347
|
It renders at once, then after a pause in typing (`delay`, 300 ms), and at once
|
|
346
348
|
again when the editor gets another model; an unchanged text is not rendered
|
|
347
349
|
twice (a whole book is not cheap). A whole document keeps its `dir` / `lang`
|
|
348
|
-
(right-to-left books render right to left).
|
|
350
|
+
(right-to-left books render right to left). A fragment has none of its own — a
|
|
351
|
+
paragraph of an Arabic publication — so the host gives them: `language: { dir:
|
|
352
|
+
'rtl', lang: 'ar-AE' }`, each field over the document's, changed later with
|
|
353
|
+
`preview.setLanguage(...)`. Blank text shows `emptyText`;
|
|
349
354
|
`transform(text)` picks what to render (e.g. without a wrapper your editor adds).
|
|
350
355
|
|
|
351
356
|
**Scroll sync**, both ways, as in the VS Code preview (and with the same code,
|
package/dist/editor.cjs
CHANGED
|
@@ -36778,12 +36778,23 @@ function createWemlPreview(editor, options = {}) {
|
|
|
36778
36778
|
content.hidden = blank;
|
|
36779
36779
|
empty.hidden = !blank;
|
|
36780
36780
|
};
|
|
36781
|
-
|
|
36781
|
+
let hostLanguage = options.language;
|
|
36782
|
+
let documentDir;
|
|
36783
|
+
let documentLang;
|
|
36784
|
+
const applyLanguage = () => {
|
|
36785
|
+
const dir = hostLanguage?.dir ?? documentDir;
|
|
36786
|
+
const lang = hostLanguage?.lang ?? documentLang;
|
|
36782
36787
|
if (dir) content.dir = dir;
|
|
36783
36788
|
else content.removeAttribute("dir");
|
|
36784
36789
|
if (lang) content.lang = lang;
|
|
36785
36790
|
else content.removeAttribute("lang");
|
|
36786
36791
|
};
|
|
36792
|
+
const setDocumentLanguage = (dir, lang) => {
|
|
36793
|
+
documentDir = dir;
|
|
36794
|
+
documentLang = lang;
|
|
36795
|
+
applyLanguage();
|
|
36796
|
+
};
|
|
36797
|
+
applyLanguage();
|
|
36787
36798
|
const rendered = () => {
|
|
36788
36799
|
anchors = void 0;
|
|
36789
36800
|
if (sync.previewWithEditor) followEditor();
|
|
@@ -36811,7 +36822,7 @@ function createWemlPreview(editor, options = {}) {
|
|
|
36811
36822
|
generation = update2.generation;
|
|
36812
36823
|
shownVersion = { model, version };
|
|
36813
36824
|
showBlank(update2.blank);
|
|
36814
|
-
|
|
36825
|
+
setDocumentLanguage(update2.blank ? void 0 : update2.dir, update2.blank ? void 0 : update2.lang);
|
|
36815
36826
|
rendered();
|
|
36816
36827
|
}
|
|
36817
36828
|
done();
|
|
@@ -36831,7 +36842,7 @@ function createWemlPreview(editor, options = {}) {
|
|
|
36831
36842
|
const blank = markup.trim() === "";
|
|
36832
36843
|
showBlank(blank);
|
|
36833
36844
|
const language = blank ? {} : (0, import_weml_stylesheet.documentLanguage)(markup);
|
|
36834
|
-
|
|
36845
|
+
setDocumentLanguage(language.dir, language.lang);
|
|
36835
36846
|
const { body, bodyLine } = splitDocument(markup);
|
|
36836
36847
|
const next = blank ? [] : splitPreviewChunks(body, firstLine + bodyLine);
|
|
36837
36848
|
chunks.apply(diffPreviewChunks(texts, next));
|
|
@@ -36933,6 +36944,11 @@ function createWemlPreview(editor, options = {}) {
|
|
|
36933
36944
|
return {
|
|
36934
36945
|
element: element2,
|
|
36935
36946
|
setTheme,
|
|
36947
|
+
setLanguage(language) {
|
|
36948
|
+
hostLanguage = language;
|
|
36949
|
+
applyLanguage();
|
|
36950
|
+
anchors = void 0;
|
|
36951
|
+
},
|
|
36936
36952
|
refresh: now,
|
|
36937
36953
|
setScrollSync(next) {
|
|
36938
36954
|
sync = scrollSyncOf(next);
|
|
@@ -38220,10 +38236,13 @@ function injectEditorStyles(doc = document) {
|
|
|
38220
38236
|
// src/editor/wrapperGuard.ts
|
|
38221
38237
|
var HIDDEN_AREAS_SOURCE = "weml-editor.wrapper";
|
|
38222
38238
|
var WRAPPER_LINE_CLASS = "weml-editor-wrapper-line";
|
|
38223
|
-
|
|
38239
|
+
var WRAPPER_MESSAGE = { value: "The `<div id>` wrapper is not part of the paragraph and cannot be edited." };
|
|
38240
|
+
function guardWrapper(m2, editor, hideWrapper, hostOptions) {
|
|
38224
38241
|
const model = editor.getModel();
|
|
38225
38242
|
if (!model) return { dispose() {
|
|
38243
|
+
}, setHostOptions() {
|
|
38226
38244
|
} };
|
|
38245
|
+
let host = hostOptions;
|
|
38227
38246
|
const disposables = [];
|
|
38228
38247
|
const touchesWrapper = (selection) => selection.startLineNumber < 2 || selection.endLineNumber > model.getLineCount() - 1;
|
|
38229
38248
|
const clampSelections = () => {
|
|
@@ -38240,15 +38259,17 @@ function guardWrapper(m2, editor, hideWrapper) {
|
|
|
38240
38259
|
})
|
|
38241
38260
|
);
|
|
38242
38261
|
};
|
|
38262
|
+
let applied;
|
|
38243
38263
|
const syncReadOnly = () => {
|
|
38244
|
-
const
|
|
38245
|
-
|
|
38264
|
+
const locked = (editor.getSelections() ?? []).some(touchesWrapper);
|
|
38265
|
+
const readOnly = host.readOnly === true || locked;
|
|
38266
|
+
const readOnlyMessage = locked && host.readOnly !== true ? WRAPPER_MESSAGE : host.readOnlyMessage;
|
|
38267
|
+
if (applied?.readOnly === readOnly && applied.readOnlyMessage === readOnlyMessage) return;
|
|
38268
|
+
applied = { readOnly, readOnlyMessage };
|
|
38269
|
+
editor.updateOptions({ readOnly, readOnlyMessage });
|
|
38246
38270
|
};
|
|
38247
38271
|
const offset = contentLineOffset("paragraph", hideWrapper);
|
|
38248
|
-
editor.updateOptions({
|
|
38249
|
-
readOnlyMessage: { value: "The `<div id>` wrapper is not part of the paragraph and cannot be edited." },
|
|
38250
|
-
lineNumbers: (lineNumber) => String(lineNumber - offset)
|
|
38251
|
-
});
|
|
38272
|
+
editor.updateOptions({ lineNumbers: (lineNumber) => String(lineNumber - offset) });
|
|
38252
38273
|
disposables.push(
|
|
38253
38274
|
editor.onDidChangeCursorSelection(() => {
|
|
38254
38275
|
if (hideWrapper) clampSelections();
|
|
@@ -38313,6 +38334,11 @@ function guardWrapper(m2, editor, hideWrapper) {
|
|
|
38313
38334
|
})
|
|
38314
38335
|
);
|
|
38315
38336
|
return {
|
|
38337
|
+
setHostOptions(options) {
|
|
38338
|
+
host = options;
|
|
38339
|
+
applied = void 0;
|
|
38340
|
+
syncReadOnly();
|
|
38341
|
+
},
|
|
38316
38342
|
dispose() {
|
|
38317
38343
|
for (const disposable of disposables) disposable.dispose();
|
|
38318
38344
|
wrapperLines.clear();
|
|
@@ -38352,6 +38378,7 @@ function jsonOptions(options) {
|
|
|
38352
38378
|
return Object.fromEntries(Object.entries(options).filter(([key, value]) => !NOT_SETTINGS.has(key) && value !== void 0 && plain(value)));
|
|
38353
38379
|
}
|
|
38354
38380
|
var sharedLanguage = /* @__PURE__ */ new WeakMap();
|
|
38381
|
+
var ownLanguageId = /* @__PURE__ */ new WeakSet();
|
|
38355
38382
|
var editorCount = 0;
|
|
38356
38383
|
function acquireLanguage(m2, options) {
|
|
38357
38384
|
if (options.language) return { registration: options.language, release() {
|
|
@@ -38361,12 +38388,13 @@ function acquireLanguage(m2, options) {
|
|
|
38361
38388
|
shared.users++;
|
|
38362
38389
|
return { registration: shared.registration, release: () => releaseShared(m2) };
|
|
38363
38390
|
}
|
|
38364
|
-
if (m2.languages.getLanguages().some((language) => language.id === "weml")) {
|
|
38391
|
+
if (!ownLanguageId.has(m2) && m2.languages.getLanguages().some((language) => language.id === "weml")) {
|
|
38365
38392
|
return { registration: { analysis: localAnalysis, formatter: localFormatter, dispose() {
|
|
38366
38393
|
} }, release() {
|
|
38367
38394
|
} };
|
|
38368
38395
|
}
|
|
38369
38396
|
const registration = options.workers ? registerWemlWorker(m2, { ...options.languageOptions, worker: options.workers.analysis, formatWorker: options.workers.format }) : registerWeml(m2, options.languageOptions);
|
|
38397
|
+
ownLanguageId.add(m2);
|
|
38370
38398
|
sharedLanguage.set(m2, { registration, users: 1 });
|
|
38371
38399
|
return { registration, release: () => releaseShared(m2) };
|
|
38372
38400
|
}
|
|
@@ -38458,7 +38486,12 @@ function createWemlEditor(m2, container, options = {}) {
|
|
|
38458
38486
|
const editorHost = element("div", { className: "wb-editor wb-part" });
|
|
38459
38487
|
const baseOptions = { ...EDITOR_OPTIONS, ...options.editorOptions };
|
|
38460
38488
|
const editor = m2.editor.create(editorHost, { ...baseOptions, ...layout.editorOptions, model });
|
|
38461
|
-
|
|
38489
|
+
const wrapperGuard = mode === "paragraph" ? guardWrapper(m2, editor, options.hideWrapper ?? false, { ...baseOptions, ...layout.editorOptions }) : void 0;
|
|
38490
|
+
if (wrapperGuard) disposables.push(wrapperGuard);
|
|
38491
|
+
const applyEditorOptions = (next) => {
|
|
38492
|
+
editor.updateOptions(next);
|
|
38493
|
+
wrapperGuard?.setHostOptions(next);
|
|
38494
|
+
};
|
|
38462
38495
|
const content = createContentApi(editor, mode, lineOffset, initialValue);
|
|
38463
38496
|
const valueListeners = /* @__PURE__ */ new Set();
|
|
38464
38497
|
const problemListeners = /* @__PURE__ */ new Set();
|
|
@@ -38732,6 +38765,7 @@ function createWemlEditor(m2, container, options = {}) {
|
|
|
38732
38765
|
const views = /* @__PURE__ */ new Map();
|
|
38733
38766
|
let previewScrollSync = options.preview?.scrollSync !== false;
|
|
38734
38767
|
let previewTheme = options.preview?.theme;
|
|
38768
|
+
let previewLanguage = options.preview?.language;
|
|
38735
38769
|
const createView = (view) => {
|
|
38736
38770
|
const host = element("div");
|
|
38737
38771
|
if (view === "problems") {
|
|
@@ -38763,6 +38797,7 @@ function createWemlEditor(m2, container, options = {}) {
|
|
|
38763
38797
|
// Cut and compared in the WEML worker when the language runs there (a file: no transform).
|
|
38764
38798
|
analysis,
|
|
38765
38799
|
theme: previewTheme,
|
|
38800
|
+
language: previewLanguage,
|
|
38766
38801
|
scrollSync: previewScrollSync,
|
|
38767
38802
|
container: host,
|
|
38768
38803
|
// A paragraph without its wrapper, from the model's second line (the scroll sync matches
|
|
@@ -38814,12 +38849,12 @@ function createWemlEditor(m2, container, options = {}) {
|
|
|
38814
38849
|
const own = Object.fromEntries(Object.entries(jsonOptions(parsed)).filter(([key, value]) => JSON.stringify(value) !== JSON.stringify(base[key])));
|
|
38815
38850
|
if (JSON.stringify(own) === JSON.stringify(layout.editorOptions ?? {})) return;
|
|
38816
38851
|
layout.editorOptions = own;
|
|
38817
|
-
|
|
38852
|
+
applyEditorOptions({ ...base, ...own });
|
|
38818
38853
|
saveLayout();
|
|
38819
38854
|
}
|
|
38820
38855
|
function resetSettings() {
|
|
38821
38856
|
layout.editorOptions = {};
|
|
38822
|
-
|
|
38857
|
+
applyEditorOptions(jsonOptions(baseOptions));
|
|
38823
38858
|
saveLayout();
|
|
38824
38859
|
views.get("settings")?.settings?.setText(settingsText());
|
|
38825
38860
|
}
|
|
@@ -39419,6 +39454,10 @@ function createWemlEditor(m2, container, options = {}) {
|
|
|
39419
39454
|
previewTheme = theme;
|
|
39420
39455
|
views.get("preview")?.preview?.setTheme(theme);
|
|
39421
39456
|
},
|
|
39457
|
+
setPreviewLanguage(language2) {
|
|
39458
|
+
previewLanguage = language2;
|
|
39459
|
+
views.get("preview")?.preview?.setLanguage(language2);
|
|
39460
|
+
},
|
|
39422
39461
|
addStatusBarItem(item, alignment = "left") {
|
|
39423
39462
|
item.classList.add("wb-status-item");
|
|
39424
39463
|
(alignment === "left" ? statusLeft : statusRight).append(item);
|