@simple-mark/codemirror 0.3.2 → 0.3.4

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.
Files changed (3) hide show
  1. package/index.d.ts +10 -3
  2. package/index.js +32 -11
  3. package/package.json +3 -3
package/index.d.ts CHANGED
@@ -22,11 +22,15 @@ export declare function links(): Extension;
22
22
  //#region packages/codemirror/src/image-resolver.d.ts
23
23
  /**
24
24
  * Turns a path as written in the document into a URL to load, or several to try in order
25
- * (the first that loads is shown), or null if it can't be loaded.
25
+ * (the first that loads is shown), or null if it can't be loaded. `undefined` means the host
26
+ * doesn't know yet (its file is still loading): the editor shows that it is loading, and the
27
+ * host calls `refreshImages` once it knows.
26
28
  */
27
- type ImageResolver = (src: string) => string | readonly string[] | null;
29
+ type ImageResolver = (src: string) => string | readonly string[] | null | undefined;
28
30
  /** How image (and file) paths are resolved; by default they are used as written. */
29
31
  export declare const imageResolver: Facet<ImageResolver, ImageResolver>;
32
+ /** Resolves the images again, e.g. when files the resolver was waiting for have loaded. */
33
+ export declare function refreshImages(view: EditorView): void;
30
34
  //#endregion
31
35
  //#region packages/codemirror/src/previews.d.ts
32
36
  /** Image and math previews; the source text always stays visible. */
@@ -84,7 +88,10 @@ export interface EditorOptions {
84
88
  theme?: Theme;
85
89
  /** Line ending to read and write ("\n", "\r\n"); by default the one `doc` uses. */
86
90
  lineSeparator?: string;
87
- /** Turns an image path from the document into a URL to load (default: as written). */
91
+ /**
92
+ * Turns an image path from the document into a URL to load (default: as written). Return
93
+ * undefined while the file is still loading, and call `refreshImages(view)` when it has.
94
+ */
88
95
  resolveImage?: ImageResolver;
89
96
  /**
90
97
  * Opens a followed link (Ctrl/Cmd+Click) or a clicked image preview. Default: web addresses
package/index.js CHANGED
@@ -5,18 +5,24 @@ import { Decoration, EditorView, ViewPlugin, WidgetType, hoverTooltip, keymap, s
5
5
  import { 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
- /** The URLs a resolver gives for `src`, in order. */
8
+ /** The URLs a resolver gives for `src`, in order; undefined while the host is still loading. */
9
9
  function resolvedUrls(resolve, src) {
10
10
  const result = resolve(src);
11
- return result === null ? [] : typeof result === "string" ? [result] : [...result];
11
+ return result === void 0 ? void 0 : result === null ? [] : typeof result === "string" ? [result] : [...result];
12
12
  }
13
13
  /** How image (and file) paths are resolved; by default they are used as written. */
14
14
  const imageResolver = Facet.define({ combine: (values) => values[0] ?? ((src) => src) });
15
+ /** Asks the editor to resolve its images again. */
16
+ const imagesChanged = StateEffect.define();
17
+ /** Resolves the images again, e.g. when files the resolver was waiting for have loaded. */
18
+ function refreshImages(view) {
19
+ view.dispatch({ effects: imagesChanged.of(null) });
20
+ }
15
21
  //#endregion
16
22
  //#region packages/codemirror/src/links.ts
17
23
  /** In a browser: web addresses and paths (resolved like images) open in a new tab. */
18
24
  const openInBrowser = (target, view) => {
19
- const url = target.kind === "web" ? target.url : resolvedUrls(view.state.facet(imageResolver), target.url)[0];
25
+ const url = target.kind === "web" ? target.url : resolvedUrls(view.state.facet(imageResolver), target.url)?.[0];
20
26
  if (url) window.open(url, "_blank", "noopener,noreferrer");
21
27
  };
22
28
  /** How links are opened. */
@@ -252,10 +258,12 @@ var MarkdownDecorations = class {
252
258
  let deco = this.cache.get(key);
253
259
  if (!deco) {
254
260
  const linked = styles.includes("link") || styles.includes("url");
261
+ const look = resolveLook([], styles, this.theme);
262
+ const keepLine = look.monospace !== void 0 || look.fontScale !== void 0;
255
263
  deco = Decoration.mark({
256
264
  class: styles.map((s) => `sm-${s}`).join(" "),
257
265
  attributes: {
258
- style: lookCss(resolveLook([], styles, this.theme), this.theme),
266
+ style: lookCss(look, this.theme) + (keepLine ? "; line-height: 0" : ""),
259
267
  ...linked ? { title: `${followKeyName}+Click to open` } : {}
260
268
  }
261
269
  });
@@ -620,9 +628,10 @@ const heightHints = StateField.define({
620
628
  },
621
629
  provide: (field) => EditorView.decorations.from(field)
622
630
  });
631
+ const hintTheme = EditorView.baseTheme({ ".sm-height-hint + .cm-widgetBuffer": { verticalAlign: "top" } });
623
632
  /** Better height estimates for headings and wrapping lines that are not drawn yet. */
624
633
  function lineHeightHints() {
625
- return heightHints;
634
+ return [heightHints, hintTheme];
626
635
  }
627
636
  //#endregion
628
637
  //#region packages/codemirror/src/previews.ts
@@ -684,7 +693,15 @@ function imageRef(image, resolve) {
684
693
  alt: image.alt,
685
694
  problem: `No definition for ${image.raw}`
686
695
  };
687
- const [src, ...fallbacks] = resolvedUrls(resolve, image.src);
696
+ const urls = resolvedUrls(resolve, image.src);
697
+ if (urls === void 0) return {
698
+ raw: image.raw,
699
+ src: null,
700
+ alt: image.alt,
701
+ problem: `Loading ${image.raw}…`,
702
+ loading: true
703
+ };
704
+ const [src, ...fallbacks] = urls;
688
705
  if (src === void 0) return {
689
706
  raw: image.raw,
690
707
  src: null,
@@ -729,14 +746,14 @@ var ImageWidget = class extends WidgetType {
729
746
  if (--waiting === 0) rememberHeight(view, this.key, dom);
730
747
  };
731
748
  for (const image of this.images) {
732
- const problem = (text) => {
749
+ const problem = (text, className = "sm-image-error") => {
733
750
  const span = document.createElement("span");
734
- span.className = "sm-image-error";
751
+ span.className = className;
735
752
  span.textContent = text;
736
753
  return span;
737
754
  };
738
755
  if (image.src === null) {
739
- dom.appendChild(problem(image.problem ?? `Can't load ${image.raw}`));
756
+ dom.appendChild(problem(image.problem ?? `Can't load ${image.raw}`, image.loading ? "sm-image-loading" : "sm-image-error"));
740
757
  continue;
741
758
  }
742
759
  waiting++;
@@ -798,7 +815,7 @@ function blockPreviews(state) {
798
815
  const blockPreviewField = StateField.define({
799
816
  create: blockPreviews,
800
817
  update(previews, tr) {
801
- return tr.docChanged || syntaxTree(tr.state) !== syntaxTree(tr.startState) || tr.state.facet(imageResolver) !== tr.startState.facet(imageResolver) || tr.effects.some((effect) => effect.is(refreshEstimates)) ? blockPreviews(tr.state) : previews;
818
+ return tr.docChanged || syntaxTree(tr.state) !== syntaxTree(tr.startState) || tr.state.facet(imageResolver) !== tr.startState.facet(imageResolver) || tr.effects.some((effect) => effect.is(refreshEstimates) || effect.is(imagesChanged)) ? blockPreviews(tr.state) : previews;
802
819
  },
803
820
  provide: (field) => EditorView.decorations.from(field)
804
821
  });
@@ -860,6 +877,10 @@ const previewTheme = EditorView.theme({
860
877
  color: "#cf222e",
861
878
  fontSize: "0.9em"
862
879
  },
880
+ ".sm-image-loading": {
881
+ color: "#818b98",
882
+ fontSize: "0.9em"
883
+ },
863
884
  ".sm-math-preview": {
864
885
  textAlign: "center",
865
886
  padding: previewSpacing,
@@ -1140,4 +1161,4 @@ function createEditor(parent, options = {}) {
1140
1161
  });
1141
1162
  }
1142
1163
  //#endregion
1143
- export { createEditor, followLink, imageResolver, insertRowBelow, keepLineSeparator, linkOpener, links, lookCss, markdownDecorations, markdownTheme, nextCell, previews, previousCell, simpleMark, tableEditing };
1164
+ export { createEditor, followLink, imageResolver, insertRowBelow, keepLineSeparator, linkOpener, links, lookCss, markdownDecorations, markdownTheme, nextCell, previews, previousCell, refreshImages, simpleMark, tableEditing };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simple-mark/codemirror",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
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.2",
32
- "@simple-mark/model": "^0.3.2"
31
+ "@simple-mark/math": "^0.3.4",
32
+ "@simple-mark/model": "^0.3.4"
33
33
  }
34
34
  }