@simple-mark/codemirror 0.3.4 → 0.3.5
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/index.d.ts +8 -2
- package/index.js +85 -16
- package/package.json +3 -3
package/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EditorState, Extension, Facet, StateCommand } from "@codemirror/state";
|
|
2
2
|
import { DecorationSet, EditorView, ViewPlugin, ViewUpdate } from "@codemirror/view";
|
|
3
|
-
import {
|
|
3
|
+
import { ResolvedLineLook, Theme } from "@simple-mark/model";
|
|
4
4
|
//#region packages/codemirror/src/links.d.ts
|
|
5
5
|
/** What to open: a web address, or a path as written (an image, another document, …). */
|
|
6
6
|
interface LinkTarget {
|
|
@@ -40,7 +40,7 @@ export declare function previews(): Extension;
|
|
|
40
40
|
/** The theme the editor draws with. */
|
|
41
41
|
export declare const markdownTheme: Facet<Theme, Theme>;
|
|
42
42
|
/** A look as an inline CSS declaration list. */
|
|
43
|
-
export declare function lookCss(look:
|
|
43
|
+
export declare function lookCss(look: ResolvedLineLook, theme: Theme): string;
|
|
44
44
|
declare class MarkdownDecorations {
|
|
45
45
|
decorations: DecorationSet;
|
|
46
46
|
private theme;
|
|
@@ -49,6 +49,12 @@ declare class MarkdownDecorations {
|
|
|
49
49
|
constructor(view: EditorView);
|
|
50
50
|
update(update: ViewUpdate): void;
|
|
51
51
|
private build;
|
|
52
|
+
/**
|
|
53
|
+
* One element behind each run of neighbouring spans with the same background (inline code
|
|
54
|
+
* with its backticks), so the background has rounded corners only at its ends. The spans
|
|
55
|
+
* themselves draw no background. Being longer, a box wraps the spans' elements.
|
|
56
|
+
*/
|
|
57
|
+
private backgroundBoxes;
|
|
52
58
|
/** Draws runs of wide characters exactly two columns each, so table pipes line up. */
|
|
53
59
|
private wideRuns;
|
|
54
60
|
private lineDecoration;
|
package/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
|
|
|
2
2
|
import { commonmarkLanguage, markdown } from "@codemirror/lang-markdown";
|
|
3
3
|
import { EditorState, Facet, Prec, StateEffect, StateField } from "@codemirror/state";
|
|
4
4
|
import { Decoration, EditorView, ViewPlugin, WidgetType, hoverTooltip, keymap, showTooltip } from "@codemirror/view";
|
|
5
|
-
import { cellAt, charWidth, defaultTheme, headingAnchors, linkAt, linkKind, markdownExtensions, markdownStyles, mathSource, parseTable, previewBlocks, renderTable, resolveLineLook, resolveLook, rowLine } from "@simple-mark/model";
|
|
5
|
+
import { STROKES, cellAt, charWidth, defaultTheme, headingAnchors, linkAt, linkKind, markdownExtensions, markdownStyles, mathSource, parseTable, previewBlocks, renderTable, resolveLineLook, resolveLook, rowLine } from "@simple-mark/model";
|
|
6
6
|
import { ensureSyntaxTree, syntaxTree } from "@codemirror/language";
|
|
7
7
|
//#region packages/codemirror/src/image-resolver.ts
|
|
8
8
|
/** The URLs a resolver gives for `src`, in order; undefined while the host is still loading. */
|
|
@@ -129,12 +129,26 @@ function lookCss(look, theme) {
|
|
|
129
129
|
if (look.monospace !== void 0) css.push(`font-family: ${look.monospace ? theme.monospaceFamily : theme.fontFamily}`);
|
|
130
130
|
if (look.color !== void 0) css.push(`color: ${look.color}`);
|
|
131
131
|
if (look.background !== void 0) css.push(`background-color: ${look.background}`);
|
|
132
|
+
if (look.radius !== void 0) css.push(`border-radius: ${look.radius}em`);
|
|
132
133
|
if (look.strike !== void 0 || look.underline !== void 0) {
|
|
133
134
|
const lines = [look.strike && "line-through", look.underline && "underline"].filter(Boolean);
|
|
134
135
|
css.push(`text-decoration: ${lines.join(" ") || "none"}`);
|
|
135
136
|
}
|
|
137
|
+
const em = (size) => `${size / (look.fontScale ?? 1)}em`;
|
|
136
138
|
if (look.lineBackground !== void 0) css.push(`background-color: ${look.lineBackground}`);
|
|
137
|
-
if (look.
|
|
139
|
+
if (look.radiusTop || look.radiusBottom) {
|
|
140
|
+
const [top, bottom] = [em(look.radiusTop ?? 0), em(look.radiusBottom ?? 0)];
|
|
141
|
+
css.push(`border-radius: ${top} ${top} ${bottom} ${bottom}`);
|
|
142
|
+
}
|
|
143
|
+
const shadows = [];
|
|
144
|
+
if (look.borderLeft !== void 0) shadows.push(`inset ${em(STROKES.bar)} 0 0 ${look.borderLeft}`);
|
|
145
|
+
if (look.borderBottom !== void 0) shadows.push(`inset 0 -${em(STROKES.border)} 0 ${look.borderBottom}`);
|
|
146
|
+
if (shadows.length) css.push(`box-shadow: ${shadows.join(", ")}`);
|
|
147
|
+
if (look.rule !== void 0) {
|
|
148
|
+
const half = em(STROKES.rule / 2);
|
|
149
|
+
css.push(`background-image: linear-gradient(transparent calc(50% - ${half}), ${look.rule} 0, ${look.rule} calc(50% + ${half}), transparent 0)`);
|
|
150
|
+
}
|
|
151
|
+
if (look.indent !== void 0) css.push(`padding-left: ${em(look.indent)}`);
|
|
138
152
|
return css.join("; ");
|
|
139
153
|
}
|
|
140
154
|
const fontChecks = /* @__PURE__ */ new Map();
|
|
@@ -186,32 +200,86 @@ var MarkdownDecorations = class {
|
|
|
186
200
|
const { doc } = view.state;
|
|
187
201
|
const { from, to } = view.viewport;
|
|
188
202
|
const { blocks, spans } = markdownStyles(syntaxTree(view.state), from, to);
|
|
203
|
+
/** Block styles of each line, and the styles whose block starts or ends there. */
|
|
189
204
|
const lines = /* @__PURE__ */ new Map();
|
|
190
205
|
for (const block of blocks) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
206
|
+
let blockEnd = block.to;
|
|
207
|
+
if (blockEnd > block.from && doc.lineAt(blockEnd).from === blockEnd) blockEnd--;
|
|
208
|
+
const firstLine = doc.lineAt(block.from).from;
|
|
209
|
+
const lastLine = doc.lineAt(blockEnd).from;
|
|
210
|
+
for (let pos = Math.max(block.from, from), end = Math.min(blockEnd, to); pos <= end;) {
|
|
195
211
|
const line = doc.lineAt(pos);
|
|
196
|
-
let
|
|
197
|
-
if (!
|
|
198
|
-
|
|
212
|
+
let entry = lines.get(line.from);
|
|
213
|
+
if (!entry) lines.set(line.from, entry = {
|
|
214
|
+
styles: /* @__PURE__ */ new Set(),
|
|
215
|
+
first: /* @__PURE__ */ new Set(),
|
|
216
|
+
last: /* @__PURE__ */ new Set()
|
|
217
|
+
});
|
|
218
|
+
entry.styles.add(block.style);
|
|
219
|
+
if (line.from === firstLine) entry.first.add(block.style);
|
|
220
|
+
if (line.from === lastLine) entry.last.add(block.style);
|
|
199
221
|
pos = line.to + 1;
|
|
200
222
|
}
|
|
201
223
|
}
|
|
202
224
|
const ranges = [];
|
|
203
|
-
for (const [lineFrom,
|
|
225
|
+
for (const [lineFrom, entry] of lines) ranges.push(this.lineDecoration(entry).range(lineFrom));
|
|
226
|
+
for (const box of this.backgroundBoxes(spans)) ranges.push(box);
|
|
204
227
|
for (const span of spans) ranges.push(this.markDecoration(span.styles).range(span.from, span.to));
|
|
205
|
-
for (const [lineFrom, styles] of lines) {
|
|
228
|
+
for (const [lineFrom, { styles }] of lines) {
|
|
206
229
|
const line = doc.lineAt(lineFrom);
|
|
207
230
|
if (line.length && [...styles].some((s) => /^h[1-6]$/.test(s))) ranges.push(headingText.range(line.from, line.to));
|
|
208
231
|
}
|
|
209
232
|
if (this.fixWide) {
|
|
210
233
|
const cursorLines = new Set(view.state.selection.ranges.map((r) => doc.lineAt(r.head).from));
|
|
211
|
-
for (const [lineFrom, styles] of lines) if (styles.has("table") && !cursorLines.has(lineFrom)) this.wideRuns(doc.lineAt(lineFrom), ranges);
|
|
234
|
+
for (const [lineFrom, { styles }] of lines) if (styles.has("table") && !cursorLines.has(lineFrom)) this.wideRuns(doc.lineAt(lineFrom), ranges);
|
|
212
235
|
}
|
|
213
236
|
return Decoration.set(ranges, true);
|
|
214
237
|
}
|
|
238
|
+
/**
|
|
239
|
+
* One element behind each run of neighbouring spans with the same background (inline code
|
|
240
|
+
* with its backticks), so the background has rounded corners only at its ends. The spans
|
|
241
|
+
* themselves draw no background. Being longer, a box wraps the spans' elements.
|
|
242
|
+
*/
|
|
243
|
+
backgroundBoxes(spans) {
|
|
244
|
+
const boxes = [];
|
|
245
|
+
let open = null;
|
|
246
|
+
const flush = () => {
|
|
247
|
+
if (!open) return;
|
|
248
|
+
const { background, radius, monospace } = open.look;
|
|
249
|
+
const look = {
|
|
250
|
+
background,
|
|
251
|
+
...radius !== void 0 ? { radius } : {},
|
|
252
|
+
...monospace !== void 0 ? { monospace } : {}
|
|
253
|
+
};
|
|
254
|
+
const key = `box:${JSON.stringify(look)}`;
|
|
255
|
+
let deco = this.cache.get(key);
|
|
256
|
+
if (!deco) {
|
|
257
|
+
const css = `${lookCss(look, this.theme)}; line-height: 0; -webkit-box-decoration-break: clone; box-decoration-break: clone`;
|
|
258
|
+
deco = Decoration.mark({
|
|
259
|
+
class: "sm-box",
|
|
260
|
+
attributes: { style: css }
|
|
261
|
+
});
|
|
262
|
+
this.cache.set(key, deco);
|
|
263
|
+
}
|
|
264
|
+
boxes.push(deco.range(open.from, open.to));
|
|
265
|
+
open = null;
|
|
266
|
+
};
|
|
267
|
+
for (const span of spans) {
|
|
268
|
+
const look = resolveLook([], span.styles, this.theme);
|
|
269
|
+
if (look.background === void 0) flush();
|
|
270
|
+
else if (open && open.to === span.from && open.look.background === look.background) open.to = span.to;
|
|
271
|
+
else {
|
|
272
|
+
flush();
|
|
273
|
+
open = {
|
|
274
|
+
from: span.from,
|
|
275
|
+
to: span.to,
|
|
276
|
+
look
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
flush();
|
|
281
|
+
return boxes;
|
|
282
|
+
}
|
|
215
283
|
/** Draws runs of wide characters exactly two columns each, so table pipes line up. */
|
|
216
284
|
wideRuns(line, ranges) {
|
|
217
285
|
let start = -1;
|
|
@@ -241,13 +309,14 @@ var MarkdownDecorations = class {
|
|
|
241
309
|
}
|
|
242
310
|
flush(i);
|
|
243
311
|
}
|
|
244
|
-
lineDecoration(
|
|
245
|
-
const
|
|
312
|
+
lineDecoration(entry) {
|
|
313
|
+
const styles = [...entry.styles].sort();
|
|
314
|
+
const key = `line:${styles.join(" ")}|${[...entry.first].sort().join(" ")}|${[...entry.last].sort().join(" ")}`;
|
|
246
315
|
let deco = this.cache.get(key);
|
|
247
316
|
if (!deco) {
|
|
248
317
|
deco = Decoration.line({
|
|
249
318
|
class: styles.map((s) => `sm-line-${s}`).join(" "),
|
|
250
|
-
attributes: { style: lookCss(resolveLineLook(styles, this.theme), this.theme) }
|
|
319
|
+
attributes: { style: lookCss(resolveLineLook(styles, this.theme, entry), this.theme) }
|
|
251
320
|
});
|
|
252
321
|
this.cache.set(key, deco);
|
|
253
322
|
}
|
|
@@ -258,7 +327,7 @@ var MarkdownDecorations = class {
|
|
|
258
327
|
let deco = this.cache.get(key);
|
|
259
328
|
if (!deco) {
|
|
260
329
|
const linked = styles.includes("link") || styles.includes("url");
|
|
261
|
-
const look = resolveLook([], styles, this.theme);
|
|
330
|
+
const { background: _background, radius: _radius, ...look } = resolveLook([], styles, this.theme);
|
|
262
331
|
const keepLine = look.monospace !== void 0 || look.fontScale !== void 0;
|
|
263
332
|
deco = Decoration.mark({
|
|
264
333
|
class: styles.map((s) => `sm-${s}`).join(" "),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simple-mark/codemirror",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "CodeMirror 6 editor that styles Markdown without hiding its syntax.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@codemirror/state": "^6.7.6",
|
|
29
29
|
"@codemirror/view": "^6.43.15",
|
|
30
30
|
"@lezer/common": "^1.5.3",
|
|
31
|
-
"@simple-mark/math": "^0.3.
|
|
32
|
-
"@simple-mark/model": "^0.3.
|
|
31
|
+
"@simple-mark/math": "^0.3.5",
|
|
32
|
+
"@simple-mark/model": "^0.3.5"
|
|
33
33
|
}
|
|
34
34
|
}
|