@simple-mark/codemirror 0.3.3 → 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 +27 -9
  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. */
@@ -687,7 +693,15 @@ function imageRef(image, resolve) {
687
693
  alt: image.alt,
688
694
  problem: `No definition for ${image.raw}`
689
695
  };
690
- 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;
691
705
  if (src === void 0) return {
692
706
  raw: image.raw,
693
707
  src: null,
@@ -732,14 +746,14 @@ var ImageWidget = class extends WidgetType {
732
746
  if (--waiting === 0) rememberHeight(view, this.key, dom);
733
747
  };
734
748
  for (const image of this.images) {
735
- const problem = (text) => {
749
+ const problem = (text, className = "sm-image-error") => {
736
750
  const span = document.createElement("span");
737
- span.className = "sm-image-error";
751
+ span.className = className;
738
752
  span.textContent = text;
739
753
  return span;
740
754
  };
741
755
  if (image.src === null) {
742
- 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"));
743
757
  continue;
744
758
  }
745
759
  waiting++;
@@ -801,7 +815,7 @@ function blockPreviews(state) {
801
815
  const blockPreviewField = StateField.define({
802
816
  create: blockPreviews,
803
817
  update(previews, tr) {
804
- 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;
805
819
  },
806
820
  provide: (field) => EditorView.decorations.from(field)
807
821
  });
@@ -863,6 +877,10 @@ const previewTheme = EditorView.theme({
863
877
  color: "#cf222e",
864
878
  fontSize: "0.9em"
865
879
  },
880
+ ".sm-image-loading": {
881
+ color: "#818b98",
882
+ fontSize: "0.9em"
883
+ },
866
884
  ".sm-math-preview": {
867
885
  textAlign: "center",
868
886
  padding: previewSpacing,
@@ -1143,4 +1161,4 @@ function createEditor(parent, options = {}) {
1143
1161
  });
1144
1162
  }
1145
1163
  //#endregion
1146
- 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.3",
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.3",
32
- "@simple-mark/model": "^0.3.3"
31
+ "@simple-mark/math": "^0.3.4",
32
+ "@simple-mark/model": "^0.3.4"
33
33
  }
34
34
  }