@meowdown/core 0.83.0 → 0.83.2

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/dist/index.js CHANGED
@@ -72,6 +72,39 @@ function getIsComposing() {
72
72
  return isComposing || compositionEndedAt > 0 && Date.now() - compositionEndedAt <= COMPOSITION_TAIL_MS;
73
73
  }
74
74
 
75
+ // src/utils/guard-plugin.ts
76
+ /**
77
+ * Wrap an `appendTransaction` so that a throw is reported with `reportError`
78
+ * and appends nothing. Otherwise the whole dispatch fails, and text the
79
+ * browser already inserted never reaches the editor state.
80
+ */
81
+ function guardAppendTransaction(appendTransaction) {
82
+ return (transactions, oldState, newState) => {
83
+ try {
84
+ return appendTransaction(transactions, oldState, newState);
85
+ } catch (error) {
86
+ reportError(error);
87
+ return null;
88
+ }
89
+ };
90
+ }
91
+ /**
92
+ * Wrap a `decorations` prop so that a throw is reported with `reportError` and
93
+ * draws no decorations. ProseMirror reads decorations in the middle of a view
94
+ * update and in `EditorView.destroy`, where a throw leaves the view half
95
+ * updated.
96
+ */
97
+ function guardDecorations(decorations) {
98
+ return (state) => {
99
+ try {
100
+ return decorations(state);
101
+ } catch (error) {
102
+ reportError(error);
103
+ return null;
104
+ }
105
+ };
106
+ }
107
+
75
108
  // src/utils/input-modality.ts
76
109
  const KEYBOARD_MODALITY_KEYS = /* @__PURE__ */ new Set([
77
110
  "ArrowLeft",
@@ -555,7 +588,7 @@ function getUnitEdge(range, oldPos, newPos, isPointer) {
555
588
  function createCaretSnapPlugin(marks) {
556
589
  return new Plugin({
557
590
  key: new PluginKey("atom-mark-caret-snap"),
558
- appendTransaction: (transactions, oldState, newState) => {
591
+ appendTransaction: guardAppendTransaction((transactions, oldState, newState) => {
559
592
  if (getIsComposing()) return null;
560
593
  const markNames = getActiveMarkNames(marks, newState);
561
594
  if (markNames.length === 0) return null;
@@ -575,14 +608,14 @@ function createCaretSnapPlugin(marks) {
575
608
  const isPointer = hasPointerSelectionTransaction(transactions);
576
609
  const head = getUnitEdge(range, oldState.selection.head, selection.head, isPointer);
577
610
  return newState.tr.setSelection(TextSelection.create(newState.doc, head));
578
- }
611
+ })
579
612
  });
580
613
  }
581
614
  const SELECTED_CLASS = "md-atom-selected";
582
615
  function createSelectionPlugin(marks) {
583
616
  return new Plugin({
584
617
  key: new PluginKey("atom-mark-selection"),
585
- props: { decorations: (state) => {
618
+ props: { decorations: guardDecorations((state) => {
586
619
  const markNames = getActiveMarkNames(marks, state);
587
620
  if (markNames.length === 0) return;
588
621
  if (isNodeSelection(state.selection)) return;
@@ -595,7 +628,7 @@ function createSelectionPlugin(marks) {
595
628
  if (node.marks.some((mark) => markNames.includes(mark.type.name))) decorations.push(Decoration.inline(pos, pos + node.nodeSize, { class: SELECTED_CLASS }));
596
629
  });
597
630
  return DecorationSet.create(state.doc, decorations);
598
- } }
631
+ }) }
599
632
  });
600
633
  }
601
634
  /**
@@ -696,7 +729,7 @@ function isSingleParagraph(state) {
696
729
  function defineSingleParagraph() {
697
730
  return withPriority$1(definePlugin(new Plugin({
698
731
  key: singleParagraphPluginKey,
699
- appendTransaction(transactions, _oldState, state) {
732
+ appendTransaction: guardAppendTransaction((transactions, _oldState, state) => {
700
733
  if (!isSingleParagraph(state)) return;
701
734
  if (!transactions.some((transaction) => transaction.docChanged)) return;
702
735
  const markdown = docToParagraphMarkdown(state.doc);
@@ -705,7 +738,7 @@ function defineSingleParagraph() {
705
738
  const position = Math.min(state.selection.head, doc.content.size - 1);
706
739
  const transaction = state.tr.replaceWith(0, state.doc.content.size, doc.content);
707
740
  return transaction.setSelection(TextSelection.create(transaction.doc, Math.max(1, position)));
708
- }
741
+ })
709
742
  })), Priority$1.highest);
710
743
  }
711
744
 
@@ -2424,6 +2457,45 @@ function formatFileSize(bytes) {
2424
2457
  return `${value < 9.95 ? Math.round(value * 10) / 10 : Math.round(value)} ${unit}`;
2425
2458
  }
2426
2459
 
2460
+ // src/utils/guard-mark-view.ts
2461
+ /**
2462
+ * Wrap a mark view constructor so that a throw from it, or from the view's
2463
+ * `update` or `destroy`, is reported with `reportError` instead of leaving
2464
+ * ProseMirror's view tree half updated. A constructor that throws gets a bare
2465
+ * `<span>`, which keeps the mark's source text editable.
2466
+ */
2467
+ function guardMarkView(constructor) {
2468
+ return (mark, view, inline) => {
2469
+ let markView;
2470
+ try {
2471
+ markView = constructor(mark, view, inline);
2472
+ } catch (error) {
2473
+ reportError(error);
2474
+ return { dom: document.createElement("span") };
2475
+ }
2476
+ return {
2477
+ dom: markView.dom,
2478
+ contentDOM: markView.contentDOM,
2479
+ ignoreMutation: markView.ignoreMutation?.bind(markView),
2480
+ update: (next) => {
2481
+ try {
2482
+ return markView.update?.(next) ?? false;
2483
+ } catch (error) {
2484
+ reportError(error);
2485
+ return false;
2486
+ }
2487
+ },
2488
+ destroy: () => {
2489
+ try {
2490
+ markView.destroy?.();
2491
+ } catch (error) {
2492
+ reportError(error);
2493
+ }
2494
+ }
2495
+ };
2496
+ };
2497
+ }
2498
+
2427
2499
  // src/extensions/file-view.ts
2428
2500
  /**
2429
2501
  * `data-file-kind` values by file extension, for host CSS theming.
@@ -2574,16 +2646,16 @@ var FileMarkView = class {
2574
2646
  function defineFileView(getOptions) {
2575
2647
  return defineMarkView({
2576
2648
  name: "mdFile",
2577
- constructor: (mark, view) => new FileMarkView(mark, getOptions?.(view.state))
2649
+ constructor: guardMarkView((mark, view) => new FileMarkView(mark, getOptions?.(view.state)))
2578
2650
  });
2579
2651
  }
2580
2652
 
2581
2653
  // src/extensions/find.ts
2582
- const revealActiveMatch = new Plugin({ props: { decorations: (state) => {
2654
+ const revealActiveMatch = new Plugin({ props: { decorations: guardDecorations((state) => {
2583
2655
  const { from, to, empty } = state.selection;
2584
2656
  if (empty || getSearchStatus$1(state).active === 0) return;
2585
2657
  return DecorationSet.create(state.doc, [Decoration.inline(from, to, { class: "show" })]);
2586
- } } });
2658
+ }) } });
2587
2659
  /**
2588
2660
  * Find over the editor's text. `setSearchQuery` highlights every match and
2589
2661
  * selects the first one at or after the caret; `findNext` and `findPrev` walk
@@ -3058,7 +3130,7 @@ const beforeInputKey = new PluginKey("meowdown-hidden-run-beforeinput");
3058
3130
  function createSnapPlugin() {
3059
3131
  return new Plugin({
3060
3132
  key: snapKey,
3061
- appendTransaction: (transactions, oldState, newState) => {
3133
+ appendTransaction: guardAppendTransaction((transactions, oldState, newState) => {
3062
3134
  if (getIsComposing()) return null;
3063
3135
  if (getMarkMode(newState) !== "hide") return null;
3064
3136
  const selection = newState.selection;
@@ -3075,7 +3147,7 @@ function createSnapPlugin() {
3075
3147
  const anchor = selection.anchor === selection.from ? from : to;
3076
3148
  const head = selection.head === selection.from ? from : to;
3077
3149
  return newState.tr.setSelection(TextSelection.create(newState.doc, anchor, head));
3078
- }
3150
+ })
3079
3151
  });
3080
3152
  }
3081
3153
  const relocateEnterSplit = (state, dispatch) => {
@@ -3727,7 +3799,7 @@ var ImageMarkView = class {
3727
3799
  function defineImage(getOptions) {
3728
3800
  return defineMarkView({
3729
3801
  name: "mdImage",
3730
- constructor: (mark, view) => new ImageMarkView(mark, view, getOptions?.(view.state) ?? {})
3802
+ constructor: guardMarkView((mark, view) => new ImageMarkView(mark, view, getOptions?.(view.state) ?? {}))
3731
3803
  });
3732
3804
  }
3733
3805
 
@@ -4769,7 +4841,7 @@ function createInlineMarkPlugin(getOptions) {
4769
4841
  };
4770
4842
  }
4771
4843
  },
4772
- appendTransaction(transactions, oldState, newState) {
4844
+ appendTransaction: guardAppendTransaction((transactions, oldState, newState) => {
4773
4845
  for (const tr of transactions) if (tr.getMeta(META_KEY)) return null;
4774
4846
  const restyle = transactions.some((transaction) => transaction.getMeta(RESTYLE_KEY));
4775
4847
  if (!(restyle || transactions.some((transaction) => {
@@ -4790,9 +4862,13 @@ function createInlineMarkPlugin(getOptions) {
4790
4862
  tr.setMeta(META_KEY, true);
4791
4863
  tr.setMeta("addToHistory", false);
4792
4864
  return tr;
4793
- },
4865
+ }),
4794
4866
  view(view) {
4795
- view.dispatch(triggerInlineMarks(view.state));
4867
+ try {
4868
+ view.dispatch(triggerInlineMarks(view.state));
4869
+ } catch (error) {
4870
+ reportError(error);
4871
+ }
4796
4872
  const controller = new AbortController();
4797
4873
  const flush = (currentView) => {
4798
4874
  if (currentView.isDestroyed) return;
@@ -6047,10 +6123,10 @@ function defineMeowdownList() {
6047
6123
  function createMarkModePlugin(getMode) {
6048
6124
  return new Plugin({ props: {
6049
6125
  attributes: (state) => ({ "data-mark-mode": getMode(state) }),
6050
- decorations: (state) => {
6126
+ decorations: guardDecorations((state) => {
6051
6127
  const mode = getMode(state);
6052
6128
  return mode === "focus" || mode === "hide" ? computeRevealDecorations(state, mode) : void 0;
6053
- }
6129
+ })
6054
6130
  } });
6055
6131
  }
6056
6132
  function findRevealablePack($pos, mode, direction) {
@@ -6195,7 +6271,7 @@ var MathMarkView = class {
6195
6271
  function defineMath() {
6196
6272
  return defineMarkView({
6197
6273
  name: "mdMath",
6198
- constructor: (mark, view) => new MathMarkView(mark, view)
6274
+ constructor: guardMarkView((mark, view) => new MathMarkView(mark, view))
6199
6275
  });
6200
6276
  }
6201
6277
 
@@ -6292,7 +6368,7 @@ function unionOfChangedRanges(transactions) {
6292
6368
  function createTableAlignSyncPlugin() {
6293
6369
  return new Plugin({
6294
6370
  key: new PluginKey("table-align-sync"),
6295
- appendTransaction(transactions, _oldState, newState) {
6371
+ appendTransaction: guardAppendTransaction((transactions, _oldState, newState) => {
6296
6372
  if (!transactions.some((transaction) => transaction.docChanged)) return;
6297
6373
  const range = unionOfChangedRanges(transactions);
6298
6374
  if (!range) return;
@@ -6307,7 +6383,7 @@ function createTableAlignSyncPlugin() {
6307
6383
  return false;
6308
6384
  });
6309
6385
  return tr?.docChanged ? tr : void 0;
6310
- }
6386
+ })
6311
6387
  });
6312
6388
  }
6313
6389
  function defineTableAlignSync() {
@@ -6564,11 +6640,11 @@ const pendingReplacementPlugin = new Plugin({
6564
6640
  return value;
6565
6641
  }
6566
6642
  },
6567
- props: { decorations: (state) => {
6643
+ props: { decorations: guardDecorations((state) => {
6568
6644
  const pending = getPendingReplacement(state);
6569
6645
  if (!pending || pending.from >= pending.to) return null;
6570
6646
  return DecorationSet.create(state.doc, [Decoration.inline(pending.from, pending.to, { class: "md-pending-replacement" })]);
6571
- } }
6647
+ }) }
6572
6648
  });
6573
6649
  function startPendingReplacement(options) {
6574
6650
  return (state, dispatch) => {
@@ -6672,16 +6748,20 @@ function definePendingReplacementHandler(handler) {
6672
6748
  const prev = pendingReplacementKey.getState(prevState);
6673
6749
  const next = pendingReplacementKey.getState(view.state);
6674
6750
  if (!next || prev === next) return;
6675
- if (next.pending) {
6676
- if (next.pending !== prev?.pending) handler({
6677
- type: "update",
6678
- pending: next.pending
6751
+ try {
6752
+ if (next.pending) {
6753
+ if (next.pending !== prev?.pending) handler({
6754
+ type: "update",
6755
+ pending: next.pending
6756
+ });
6757
+ } else if (next.ended && next.ended !== prev?.ended) handler({
6758
+ type: "ended",
6759
+ pending: next.ended.pending,
6760
+ outcome: next.ended.outcome
6679
6761
  });
6680
- } else if (next.ended && next.ended !== prev?.ended) handler({
6681
- type: "ended",
6682
- pending: next.ended.pending,
6683
- outcome: next.ended.outcome
6684
- });
6762
+ } catch (error) {
6763
+ reportError(error);
6764
+ }
6685
6765
  } }) }));
6686
6766
  }
6687
6767
 
@@ -7238,7 +7318,7 @@ function createWikilinkMarkView() {
7238
7318
  function defineWikilink() {
7239
7319
  return defineMarkView({
7240
7320
  name: "mdWikilink",
7241
- constructor: createWikilinkMarkView()
7321
+ constructor: guardMarkView(createWikilinkMarkView())
7242
7322
  });
7243
7323
  }
7244
7324
 
package/dist/style.css CHANGED
@@ -894,9 +894,13 @@
894
894
  --meowdown-mermaid-surface: color-mix(in srgb,
895
895
  var(--meowdown-mermaid-fg) 3%,
896
896
  var(--meowdown-mermaid-bg));
897
+ --meowdown-mermaid-surface-alt: color-mix(in srgb,
898
+ var(--meowdown-mermaid-fg) 8%,
899
+ var(--meowdown-mermaid-bg));
897
900
  --meowdown-mermaid-border: color-mix(in srgb,
898
901
  var(--meowdown-mermaid-fg) 20%,
899
902
  var(--meowdown-mermaid-bg));
903
+ --meowdown-mermaid-critical: var(--meowdown-danger);
900
904
  --meowdown-mermaid-error: var(--meowdown-danger);
901
905
  --meowdown-image-loading-bg: light-dark(oklch(96.7% 0 0), oklch(27.4% .005 286));
902
906
  --meowdown-image-radius: .5rem;
@@ -1205,13 +1209,32 @@
1205
1209
  }
1206
1210
 
1207
1211
  .ProseMirror .prosemirror-flat-list[data-list-kind="task"] {
1208
- transition: opacity .2s;
1212
+ transition: color .2s;
1209
1213
 
1210
1214
  &[data-list-checked] {
1211
- opacity: .5;
1215
+ color: color-mix(in srgb, currentColor 50%, transparent);
1212
1216
 
1213
1217
  & .prosemirror-flat-list[data-list-kind="task"][data-list-checked] {
1214
- opacity: 1;
1218
+ color: inherit;
1219
+ }
1220
+
1221
+ & :is(.md-link, .md-link-uri, .md-link-title) {
1222
+ color: color-mix(in srgb, var(--meowdown-accent) 50%, transparent);
1223
+ }
1224
+
1225
+ & .md-tag {
1226
+ background: color-mix(in oklab, var(--meowdown-accent) 5%, transparent);
1227
+ color: color-mix(in srgb,
1228
+ color-mix(in oklab, var(--meowdown-accent) 80%, var(--meowdown-heading)) 50%,
1229
+ transparent);
1230
+ }
1231
+
1232
+ & .md-mark {
1233
+ color: color-mix(in srgb, var(--meowdown-mark) 50%, transparent);
1234
+ }
1235
+
1236
+ & .list-marker input[type="checkbox"] {
1237
+ border-color: color-mix(in srgb, var(--meowdown-muted) 50%, transparent);
1215
1238
  }
1216
1239
  }
1217
1240
 
@@ -1234,8 +1257,8 @@
1234
1257
  transition: background-color .15s, border-color .15s;
1235
1258
 
1236
1259
  &:checked {
1237
- background-color: var(--meowdown-accent);
1238
- background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
1260
+ background-color: color-mix(in srgb, var(--meowdown-accent) 50%, transparent);
1261
+ background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' fill-opacity='0.5' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
1239
1262
  border-color: #0000;
1240
1263
  }
1241
1264
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meowdown/core",
3
3
  "type": "module",
4
- "version": "0.83.0",
4
+ "version": "0.83.2",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -27,7 +27,7 @@
27
27
  "@lezer/highlight": "^1.2.5",
28
28
  "@meowdown/embed": "0.3.1",
29
29
  "@meowdown/markdown": "0.78.0",
30
- "@ocavue/utils": "^1.9.0",
30
+ "@ocavue/utils": "^1.11.0",
31
31
  "@post-embed/exporter": "^0.5.0",
32
32
  "@post-embed/schema": "^0.5.2",
33
33
  "@post-embed/types": "^0.5.0",