@meowdown/core 0.82.0 → 0.83.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/dist/index.js CHANGED
@@ -49,7 +49,7 @@ import { normalizeIdentifier } from "micromark-util-normalize-identifier";
49
49
  import { bulletListInputRule, createDedentListCommand, createIndentListCommand, createListInputRuleHandler, createListRenderingPlugin, createSafariInputMethodWorkaroundPlugin, createSplitListCommand, createToggleCollapsedCommand, defaultAttributesGetter, deleteCommand, enterCommand, findCheckboxInListItem, handleListMarkerMouseDown, joinCollapsedListBackward, joinListElements, joinListUp, listToDOM, orderedListInputRule, protectCollapsed, taskListInputRule, unwrapListSlice } from "prosemirror-flat-list";
50
50
  import { defineTableCellSpec, defineTableCommands, defineTableDropIndicator, defineTableEditingPlugin, defineTableHeaderCellSpec, defineTableRowSpec, defineTableSpec, deleteTable, isCellSelection } from "@prosekit/extensions/table";
51
51
 
52
- //#region src/utils/composition.ts
52
+ // src/utils/composition.ts
53
53
  const COMPOSITION_TAIL_MS = 50;
54
54
  let compositionEndedAt = -1;
55
55
  let isComposing = false;
@@ -72,8 +72,7 @@ function getIsComposing() {
72
72
  return isComposing || compositionEndedAt > 0 && Date.now() - compositionEndedAt <= COMPOSITION_TAIL_MS;
73
73
  }
74
74
 
75
- //#endregion
76
- //#region src/utils/input-modality.ts
75
+ // src/utils/input-modality.ts
77
76
  const KEYBOARD_MODALITY_KEYS = /* @__PURE__ */ new Set([
78
77
  "ArrowLeft",
79
78
  "ArrowRight",
@@ -146,8 +145,7 @@ function onIsTouchInputChange(listener) {
146
145
  };
147
146
  }
148
147
 
149
- //#endregion
150
- //#region src/utils/transaction.ts
148
+ // src/utils/transaction.ts
151
149
  /**
152
150
  * Whether any of the given transactions are selection transactions directly caused by mouse or touch input.
153
151
  */
@@ -155,8 +153,7 @@ function hasPointerSelectionTransaction(transactions) {
155
153
  return getIsPointerSelection() && transactions.some((tr) => tr.selectionSet && !tr.docChanged);
156
154
  }
157
155
 
158
- //#endregion
159
- //#region src/extensions/editor-config-getter.ts
156
+ // src/extensions/editor-config-getter.ts
160
157
  const defaultConfig = Object.freeze({});
161
158
  const configKey = new PluginKey("meowdown-editor-config");
162
159
  /**
@@ -166,8 +163,7 @@ function getEditorConfig(state) {
166
163
  return configKey.getState(state)?.config ?? defaultConfig;
167
164
  }
168
165
 
169
- //#endregion
170
- //#region src/extensions/mark-mode-config.ts
166
+ // src/extensions/mark-mode-config.ts
171
167
  /**
172
168
  * The active mark mode, defaulting to focus when no configuration is provided.
173
169
  */
@@ -175,8 +171,7 @@ function getMarkMode(state) {
175
171
  return getEditorConfig(state).markMode ?? "focus";
176
172
  }
177
173
 
178
- //#endregion
179
- //#region src/extensions/mark-names.ts
174
+ // src/extensions/mark-names.ts
180
175
  function isMarkOfType(mark, name) {
181
176
  return mark.type.name === name;
182
177
  }
@@ -200,8 +195,7 @@ const ATOM_SOURCE_MARK_NAMES = [
200
195
  "mdFile"
201
196
  ];
202
197
 
203
- //#endregion
204
- //#region src/extensions/hidden-run.ts
198
+ // src/extensions/hidden-run.ts
205
199
  function getCharMarks(state, pos) {
206
200
  if (pos < 0 || pos + 1 > state.doc.content.size) return;
207
201
  const $pos = state.doc.resolve(pos);
@@ -341,8 +335,7 @@ function getUnitMarkerRuns(state, charPos) {
341
335
  return runs;
342
336
  }
343
337
 
344
- //#endregion
345
- //#region src/extensions/mark-range.ts
338
+ // src/extensions/mark-range.ts
346
339
  /**
347
340
  * Returns the resolved position, or `undefined` when it falls outside the
348
341
  * document or in a place that carries no inline marks: marks describe inline
@@ -425,8 +418,7 @@ function getMarkRangeStrictlyAround(state, pos, markNames) {
425
418
  }
426
419
  }
427
420
 
428
- //#endregion
429
- //#region src/extensions/atom-mark-navigation.ts
421
+ // src/extensions/atom-mark-navigation.ts
430
422
  function getActiveMarkNames(marks, state) {
431
423
  const mode = getMarkMode(state);
432
424
  const result = [];
@@ -624,14 +616,12 @@ function defineAtomMarkNavigation({ marks }) {
624
616
  }), Priority$1.high), definePlugin(createCaretSnapPlugin(marks)), definePlugin(createSelectionPlugin(marks)));
625
617
  }
626
618
 
627
- //#endregion
628
- //#region src/extensions/node-names.ts
619
+ // src/extensions/node-names.ts
629
620
  function isNodeOfType(node, name) {
630
621
  return node.type.name === name;
631
622
  }
632
623
 
633
- //#endregion
634
- //#region src/extensions/backspace-empty-first-block.ts
624
+ // src/extensions/backspace-empty-first-block.ts
635
625
  /**
636
626
  * Claim Backspace only when the selection is an empty caret in an empty
637
627
  * paragraph that is the document's first block and has a block after it.
@@ -662,8 +652,7 @@ function defineBackspaceEmptyFirstBlock(enabled) {
662
652
  } }), Priority$1.lowest);
663
653
  }
664
654
 
665
- //#endregion
666
- //#region src/converters/paragraph.ts
655
+ // src/converters/paragraph.ts
667
656
  /**
668
657
  * Build one paragraph without interpreting block-opening Markdown.
669
658
  */
@@ -689,8 +678,7 @@ function docToParagraphMarkdown(doc) {
689
678
  return paragraphs.join("\n").replaceAll(/\n[ \t]*\n+/g, "\n");
690
679
  }
691
680
 
692
- //#endregion
693
- //#region src/extensions/single-paragraph.ts
681
+ // src/extensions/single-paragraph.ts
694
682
  const singleParagraphPluginKey = new PluginKey("single-paragraph");
695
683
  /**
696
684
  * Whether the editor holds one paragraph of inline Markdown (the
@@ -721,8 +709,7 @@ function defineSingleParagraph() {
721
709
  })), Priority$1.highest);
722
710
  }
723
711
 
724
- //#endregion
725
- //#region src/extensions/block-rule.ts
712
+ // src/extensions/block-rule.ts
726
713
  /**
727
714
  * An input rule whose match turns the textblock into, or wraps it in, a block
728
715
  * node. In a single paragraph the match is left as typed text: there is no
@@ -747,14 +734,12 @@ function defineBlockEnterRule(options) {
747
734
  });
748
735
  }
749
736
 
750
- //#endregion
751
- //#region src/extensions/blockquote.ts
737
+ // src/extensions/blockquote.ts
752
738
  function defineMeowdownBlockquote() {
753
739
  return union(defineBlockquoteSpec(), defineBlockquoteCommands(), defineBlockquoteKeymap(), defineBlockInputRule(blockquoteInputRule.regex, createWrappingInputRuleHandler(blockquoteInputRule)));
754
740
  }
755
741
 
756
- //#endregion
757
- //#region src/extensions/bullet-after-heading.ts
742
+ // src/extensions/bullet-after-heading.ts
758
743
  /**
759
744
  * Claim Enter only when the selection is an empty caret at the very end of the
760
745
  * document's first heading (the note's title line). Every other Enter (a later
@@ -788,8 +773,7 @@ function defineBulletAfterHeading(enabled) {
788
773
  } }), Priority$1.high);
789
774
  }
790
775
 
791
- //#endregion
792
- //#region src/extensions/click-below.ts
776
+ // src/extensions/click-below.ts
793
777
  const clickBelowKey = new PluginKey("meowdown-click-below");
794
778
  function acceptsCaretAtEnd(node) {
795
779
  return node.isTextblock && !node.type.spec.code;
@@ -827,8 +811,7 @@ function defineClickBelow() {
827
811
  }));
828
812
  }
829
813
 
830
- //#endregion
831
- //#region src/converters/html-to-md.ts
814
+ // src/converters/html-to-md.ts
832
815
  /**
833
816
  * Convert a `<mark>` element into a `highlight` node. There is no built-in
834
817
  * `hast-util-to-mdast` handler for `<mark>`, so without this the highlight is
@@ -974,8 +957,7 @@ function htmlToMarkdown(html, parser) {
974
957
  return processor.stringify(processor.runSync(hast));
975
958
  }
976
959
 
977
- //#endregion
978
- //#region src/utils/parse-integer.ts
960
+ // src/utils/parse-integer.ts
979
961
  function parseInteger(raw) {
980
962
  if (raw == null) return void 0;
981
963
  const value = Number.parseInt(raw, 10);
@@ -986,8 +968,7 @@ function parsePositiveInteger(raw) {
986
968
  return value != null && value > 0 ? value : void 0;
987
969
  }
988
970
 
989
- //#endregion
990
- //#region src/extensions/inline-runs.ts
971
+ // src/extensions/inline-runs.ts
991
972
  function findAtomMark(marks) {
992
973
  return marks.find((mark) => isMarkOfTypes(mark, ATOM_MARK_NAMES));
993
974
  }
@@ -1029,8 +1010,7 @@ function groupInlineRuns(textblock) {
1029
1010
  return runs;
1030
1011
  }
1031
1012
 
1032
- //#endregion
1033
- //#region src/extensions/clipboard/semantic-inline.ts
1013
+ // src/extensions/clipboard/semantic-inline.ts
1034
1014
  const SEMANTIC_TAGS = {
1035
1015
  mdStrong: "strong",
1036
1016
  mdEm: "em",
@@ -1134,8 +1114,7 @@ function atomUnitToDOM(atom, sourceText) {
1134
1114
  }
1135
1115
  }
1136
1116
 
1137
- //#endregion
1138
- //#region src/extensions/heading.ts
1117
+ // src/extensions/heading.ts
1139
1118
  /**
1140
1119
  * Merge `whitespace: 'pre'` onto the base heading spec. A multi-line setext
1141
1120
  * heading keeps a soft line break as a literal `\n`; without `whitespace: 'pre'`
@@ -1222,8 +1201,7 @@ function defineHeading() {
1222
1201
  return union(defineHeadingSpec(), defineHeadingWhitespace(), defineSetextUnderlineAttr(), defineHeadingClosingHashesAttr(), defineBlockInputRule(headingInputRule.regex, createTextBlockInputRuleHandler(headingInputRule)), defineHeadingCommands(), defineHeadingKeymap());
1223
1202
  }
1224
1203
 
1225
- //#endregion
1226
- //#region src/extensions/paragraph.ts
1204
+ // src/extensions/paragraph.ts
1227
1205
  function defineMeowdownParagraphSpec() {
1228
1206
  return defineNodeSpec({
1229
1207
  name: "paragraph",
@@ -1252,8 +1230,7 @@ function defineMeowdownParagraph() {
1252
1230
  return union(withPriority$1(defineMeowdownParagraphSpec(), Priority$1.highest), defineParagraphCommands(), defineParagraphKeymap());
1253
1231
  }
1254
1232
 
1255
- //#endregion
1256
- //#region src/extensions/clipboard/clipboard-serializer.ts
1233
+ // src/extensions/clipboard/clipboard-serializer.ts
1257
1234
  function withSemanticTextblocks(nodes) {
1258
1235
  return {
1259
1236
  ...nodes,
@@ -1297,8 +1274,7 @@ function getSemanticDOMSerializer(schema) {
1297
1274
  return serializer;
1298
1275
  }
1299
1276
 
1300
- //#endregion
1301
- //#region src/extensions/html-paste.ts
1277
+ // src/extensions/html-paste.ts
1302
1278
  const htmlPasteKey = new PluginKey("meowdown-html-paste");
1303
1279
  /**
1304
1280
  * meowdown's own clipboard HTML, which must skip the markdown conversion and
@@ -1422,8 +1398,7 @@ function defineHTMLPaste() {
1422
1398
  }));
1423
1399
  }
1424
1400
 
1425
- //#endregion
1426
- //#region src/extensions/clipboard/clipboard-parser.ts
1401
+ // src/extensions/clipboard/clipboard-parser.ts
1427
1402
  /**
1428
1403
  * The clipboard parser: schema rules plus the `data-md` rules that restore a
1429
1404
  * textblock's source text from meowdown's own clipboard HTML. Registered as
@@ -1446,8 +1421,7 @@ function defineClipboardParser() {
1446
1421
  });
1447
1422
  }
1448
1423
 
1449
- //#endregion
1450
- //#region src/extensions/clipboard/plain-paste.ts
1424
+ // src/extensions/clipboard/plain-paste.ts
1451
1425
  /**
1452
1426
  * Parse pasted plain text as markdown: `- [ ] task`, `# heading`, fenced code
1453
1427
  * and the other block constructs become real nodes, while inline syntax stays
@@ -1504,8 +1478,7 @@ function definePlainTextPaste() {
1504
1478
  }));
1505
1479
  }
1506
1480
 
1507
- //#endregion
1508
- //#region src/converters/pm-to-ast.ts
1481
+ // src/converters/pm-to-ast.ts
1509
1482
  /**
1510
1483
  * Read persisted block data. Editor marks do not add Markdown delimiters.
1511
1484
  */
@@ -1513,6 +1486,7 @@ function docToAst(node) {
1513
1486
  if (isNodeOfType(node, "doc")) return {
1514
1487
  type: "document",
1515
1488
  frontmatter: node.attrs.frontmatter ?? void 0,
1489
+ frontmatterTight: node.attrs.frontmatterTight ? true : void 0,
1516
1490
  children: readBlocks(node)
1517
1491
  };
1518
1492
  if (isNodeOfType(node, "tableRow")) return readTableRow(node);
@@ -1642,8 +1616,7 @@ function readTableCell(node) {
1642
1616
  };
1643
1617
  }
1644
1618
 
1645
- //#endregion
1646
- //#region src/converters/pm-to-md.ts
1619
+ // src/converters/pm-to-md.ts
1647
1620
  /**
1648
1621
  * Convert persisted editor content to Markdown through the shared block serializer.
1649
1622
  */
@@ -1651,8 +1624,7 @@ function docToMarkdown(node, options = {}) {
1651
1624
  return serializeMarkdownAst(docToAst(node), options);
1652
1625
  }
1653
1626
 
1654
- //#endregion
1655
- //#region src/utils/top-level-block-boundary.ts
1627
+ // src/utils/top-level-block-boundary.ts
1656
1628
  function isAtTopLevelBlockStart($pos) {
1657
1629
  if ($pos.depth === 0) return true;
1658
1630
  if ($pos.parentOffset !== 0) return false;
@@ -1666,8 +1638,7 @@ function isAtTopLevelBlockEnd($pos) {
1666
1638
  return true;
1667
1639
  }
1668
1640
 
1669
- //#endregion
1670
- //#region src/extensions/clipboard/plain-text.ts
1641
+ // src/extensions/clipboard/plain-text.ts
1671
1642
  /**
1672
1643
  * Serialize a slice to Markdown. A block whose content start is not selected is
1673
1644
  * flattened so its opening markers are not synthesized. Incomplete fenced code
@@ -1783,8 +1754,7 @@ function filterTextblock(textblock) {
1783
1754
  return textblock.copy(Fragment.from(parts));
1784
1755
  }
1785
1756
 
1786
- //#endregion
1787
- //#region src/extensions/clipboard/clipboard.ts
1757
+ // src/extensions/clipboard/clipboard.ts
1788
1758
  /**
1789
1759
  * The clipboard pipeline: semantic HTML with `data-md` round-trip attributes
1790
1760
  * plus a markdown-shaped `text/plain` on copy; the matching `data-md` parser,
@@ -1795,8 +1765,7 @@ function defineClipboard() {
1795
1765
  return union(defineSemanticClipboardSerializer(), definePlainTextSerializer(), defineClipboardParser(), defineHTMLPaste(), definePlainTextPaste());
1796
1766
  }
1797
1767
 
1798
- //#endregion
1799
- //#region src/extensions/code-block-highlight.ts
1768
+ // src/extensions/code-block-highlight.ts
1800
1769
  const supportCache = /* @__PURE__ */ new Map();
1801
1770
  const parserCache = /* @__PURE__ */ new Map();
1802
1771
  const LANGUAGE_ALIASES = { math: "latex" };
@@ -1876,8 +1845,7 @@ function getCodeTokens(code, language) {
1876
1845
  return loadLanguageSupport(trimmed).then((loaded) => loaded ? tokenize(code, loaded) : []);
1877
1846
  }
1878
1847
 
1879
- //#endregion
1880
- //#region src/extensions/code-block-exit.ts
1848
+ // src/extensions/code-block-exit.ts
1881
1849
  /**
1882
1850
  * With the caret at the end of a code block, move it into the block below when
1883
1851
  * that block is an empty paragraph, and into a new default block otherwise.
@@ -1908,8 +1876,7 @@ function defineCodeBlockExitKeymap() {
1908
1876
  return defineKeymap({ "Mod-Enter": exitCodeBlockAtEnd });
1909
1877
  }
1910
1878
 
1911
- //#endregion
1912
- //#region src/extensions/code-block.ts
1879
+ // src/extensions/code-block.ts
1913
1880
  function defineFenceStyleAttr() {
1914
1881
  return defineNodeAttr({
1915
1882
  type: "codeBlock",
@@ -1934,6 +1901,29 @@ function defineFenceLengthAttr() {
1934
1901
  }
1935
1902
  });
1936
1903
  }
1904
+ /**
1905
+ * Re-declare the code block `toDOM` with a `data-code-block` root attribute.
1906
+ */
1907
+ function defineCodeBlockDOM() {
1908
+ return defineNodeSpec({
1909
+ name: "codeBlock",
1910
+ toDOM: (node) => {
1911
+ const { language } = node.attrs;
1912
+ return [
1913
+ "pre",
1914
+ {
1915
+ "data-code-block": "",
1916
+ "data-language": language || void 0
1917
+ },
1918
+ [
1919
+ "code",
1920
+ { class: language ? `language-${language}` : void 0 },
1921
+ 0
1922
+ ]
1923
+ ];
1924
+ }
1925
+ });
1926
+ }
1937
1927
  function getTildeFenceAttrs(match) {
1938
1928
  return {
1939
1929
  language: match[1] || "",
@@ -1963,11 +1953,10 @@ function defineDollarFenceEnterRule() {
1963
1953
  });
1964
1954
  }
1965
1955
  function defineCodeBlock() {
1966
- return union(defineCodeBlockSpec(), defineCodeBlockKeymap(), defineCodeBlockCommands(), defineBlockInputRule(codeBlockInputRule.regex, createTextBlockInputRuleHandler(codeBlockInputRule)), defineBlockEnterRule(codeBlockEnterRule), defineFenceStyleAttr(), defineFenceLengthAttr(), defineBlockInputRule(tildeFenceInputRule.regex, createTextBlockInputRuleHandler(tildeFenceInputRule)), defineTildeFenceEnterRule(), defineDollarFenceEnterRule(), defineCodeBlockExitKeymap());
1956
+ return union(defineCodeBlockSpec(), defineCodeBlockDOM(), defineCodeBlockKeymap(), defineCodeBlockCommands(), defineBlockInputRule(codeBlockInputRule.regex, createTextBlockInputRuleHandler(codeBlockInputRule)), defineBlockEnterRule(codeBlockEnterRule), defineFenceStyleAttr(), defineFenceLengthAttr(), defineBlockInputRule(tildeFenceInputRule.regex, createTextBlockInputRuleHandler(tildeFenceInputRule)), defineTildeFenceEnterRule(), defineDollarFenceEnterRule(), defineCodeBlockExitKeymap());
1967
1957
  }
1968
1958
 
1969
- //#endregion
1970
- //#region src/extensions/commands.ts
1959
+ // src/extensions/commands.ts
1971
1960
  function selectText(anchor, head) {
1972
1961
  return (state, dispatch) => {
1973
1962
  if (dispatch) {
@@ -2052,8 +2041,7 @@ function defineEditorCommands() {
2052
2041
  });
2053
2042
  }
2054
2043
 
2055
- //#endregion
2056
- //#region src/extensions/cross-editor-drag.ts
2044
+ // src/extensions/cross-editor-drag.ts
2057
2045
  function deleteDraggedContent(view, dragging) {
2058
2046
  const tr = view.state.tr;
2059
2047
  if (dragging.node) {
@@ -2100,8 +2088,7 @@ function defineCrossEditorDrag() {
2100
2088
  return definePlugin(createCrossEditorDragPlugin());
2101
2089
  }
2102
2090
 
2103
- //#endregion
2104
- //#region src/extensions/editor-config.ts
2091
+ // src/extensions/editor-config.ts
2105
2092
  var ConfigController = class {
2106
2093
  constructor(config) {
2107
2094
  this.config = config;
@@ -2158,16 +2145,14 @@ function defineEditorConfig(initialConfig) {
2158
2145
  }));
2159
2146
  }
2160
2147
 
2161
- //#endregion
2162
- //#region src/extensions/paste.ts
2148
+ // src/extensions/paste.ts
2163
2149
  function getPastedText(event, slice) {
2164
2150
  const fromClipboard = event.clipboardData?.getData("text/plain");
2165
2151
  if (fromClipboard) return fromClipboard;
2166
2152
  return slice.content.textBetween(0, slice.content.size, "\n");
2167
2153
  }
2168
2154
 
2169
- //#endregion
2170
- //#region src/extensions/embed-paste.ts
2155
+ // src/extensions/embed-paste.ts
2171
2156
  const embedPasteKey = new PluginKey("meowdown-embed-paste");
2172
2157
  function detectEmbedUrl(text) {
2173
2158
  const trimmed = text.trim();
@@ -2203,8 +2188,7 @@ function defineEmbedPaste(enabled) {
2203
2188
  }));
2204
2189
  }
2205
2190
 
2206
- //#endregion
2207
- //#region src/extensions/escape-collapse.ts
2191
+ // src/extensions/escape-collapse.ts
2208
2192
  /**
2209
2193
  * Collapses a non-empty selection to a caret at its head. Leaves an empty
2210
2194
  * selection alone so Escape can serve whoever binds it next.
@@ -2224,8 +2208,7 @@ function defineEscapeCollapse() {
2224
2208
  return withPriority$1(defineKeymap({ Escape: collapseSelection }), Priority$1.low);
2225
2209
  }
2226
2210
 
2227
- //#endregion
2228
- //#region src/extensions/exit-boundary.ts
2211
+ // src/extensions/exit-boundary.ts
2229
2212
  const exitBoundaryKey = new PluginKey("meowdown-exit-boundary");
2230
2213
  function canMoveBlockwise(state, direction) {
2231
2214
  const { $anchor, $head } = state.selection;
@@ -2266,8 +2249,7 @@ function defineExitBoundaryHandler(getExitBoundaryHandler) {
2266
2249
  return withPriority$1(definePlugin(createExitBoundaryPlugin(getExitBoundaryHandler)), Priority$1.low);
2267
2250
  }
2268
2251
 
2269
- //#endregion
2270
- //#region src/utils/is-mod-event.ts
2252
+ // src/utils/is-mod-event.ts
2271
2253
  /**
2272
2254
  * Whether the platform's mod key is held on `event`: `Command` on Apple, `Ctrl` elsewhere.
2273
2255
  */
@@ -2275,8 +2257,7 @@ function isModEvent(event) {
2275
2257
  return isApple ? event.metaKey : event.ctrlKey;
2276
2258
  }
2277
2259
 
2278
- //#endregion
2279
- //#region src/extensions/file-click.ts
2260
+ // src/extensions/file-click.ts
2280
2261
  const fileClickKey = new PluginKey("meowdown-file-click");
2281
2262
  function findFileAt(state, pos) {
2282
2263
  const range = getMarkRangeAt(state, pos, "mdFile");
@@ -2317,8 +2298,7 @@ function defineFileClickHandler(getOnClick) {
2317
2298
  }));
2318
2299
  }
2319
2300
 
2320
- //#endregion
2321
- //#region src/extensions/file-paste.ts
2301
+ // src/extensions/file-paste.ts
2322
2302
  const filePasteKey = new PluginKey("file-paste");
2323
2303
  const IMAGE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
2324
2304
  "avif",
@@ -2421,8 +2401,7 @@ function defineFilePaste(getOptions) {
2421
2401
  return withPriority$1(definePlugin(createFilePastePlugin(getOptions)), Priority$1.high);
2422
2402
  }
2423
2403
 
2424
- //#endregion
2425
- //#region src/utils/format-file-size.ts
2404
+ // src/utils/format-file-size.ts
2426
2405
  const UNITS = [
2427
2406
  "KB",
2428
2407
  "MB",
@@ -2445,8 +2424,7 @@ function formatFileSize(bytes) {
2445
2424
  return `${value < 9.95 ? Math.round(value * 10) / 10 : Math.round(value)} ${unit}`;
2446
2425
  }
2447
2426
 
2448
- //#endregion
2449
- //#region src/extensions/file-view.ts
2427
+ // src/extensions/file-view.ts
2450
2428
  /**
2451
2429
  * `data-file-kind` values by file extension, for host CSS theming.
2452
2430
  */
@@ -2600,8 +2578,7 @@ function defineFileView(getOptions) {
2600
2578
  });
2601
2579
  }
2602
2580
 
2603
- //#endregion
2604
- //#region src/extensions/find.ts
2581
+ // src/extensions/find.ts
2605
2582
  const revealActiveMatch = new Plugin({ props: { decorations: (state) => {
2606
2583
  const { from, to, empty } = state.selection;
2607
2584
  if (empty || getSearchStatus$1(state).active === 0) return;
@@ -2617,8 +2594,7 @@ function defineFind() {
2617
2594
  return union(defineSearchQuery(), defineSearchCommands(), definePlugin(revealActiveMatch));
2618
2595
  }
2619
2596
 
2620
- //#endregion
2621
- //#region src/extensions/get-link-unit-at.ts
2597
+ // src/extensions/get-link-unit-at.ts
2622
2598
  /**
2623
2599
  * The last text run carrying `markName` inside `range`. "Last" so a linked
2624
2600
  * image's inner url/title (which comes first) never shadows the link's own.
@@ -2712,8 +2688,7 @@ function getLinkUnitAt(state, pos) {
2712
2688
  }
2713
2689
  }
2714
2690
 
2715
- //#endregion
2716
- //#region src/extensions/image-click.ts
2691
+ // src/extensions/image-click.ts
2717
2692
  const imageClickKey = new PluginKey("meowdown-image-click");
2718
2693
  /**
2719
2694
  * The image preview wrapper around `target`, or nothing when the wrapper holds
@@ -2850,8 +2825,7 @@ function defineImageClickHandler(getOnClick) {
2850
2825
  }));
2851
2826
  }
2852
2827
 
2853
- //#endregion
2854
- //#region src/extensions/mark-click.ts
2828
+ // src/extensions/mark-click.ts
2855
2829
  /**
2856
2830
  * Shared click plumbing for text-backed marks (wikilinks, Markdown links, tags):
2857
2831
  * a click anywhere on the rendered mark fires `onClick`.
@@ -2872,8 +2846,7 @@ function defineMarkClickHandler(config) {
2872
2846
  }));
2873
2847
  }
2874
2848
 
2875
- //#endregion
2876
- //#region src/extensions/tag-click.ts
2849
+ // src/extensions/tag-click.ts
2877
2850
  const tagClickKey = new PluginKey("meowdown-tag-click");
2878
2851
  /**
2879
2852
  * The tag covering `pos`, found via the `mdTag` run. The tag name is read from
@@ -2914,8 +2887,7 @@ function defineTagClickHandler(getOnClick) {
2914
2887
  });
2915
2888
  }
2916
2889
 
2917
- //#endregion
2918
- //#region src/extensions/wikilink-click.ts
2890
+ // src/extensions/wikilink-click.ts
2919
2891
  const wikilinkClickKey = new PluginKey("meowdown-wikilink-click");
2920
2892
  /**
2921
2893
  * Exported for tests.
@@ -2966,8 +2938,7 @@ function defineWikilinkClickHandler(getOnClick) {
2966
2938
  });
2967
2939
  }
2968
2940
 
2969
- //#endregion
2970
- //#region src/extensions/follow-link.ts
2941
+ // src/extensions/follow-link.ts
2971
2942
  const followLinkKey = new PluginKey("meowdown-follow-link");
2972
2943
  function createFollowLinkPlugin(getHandlers) {
2973
2944
  return new Plugin({
@@ -3059,27 +3030,29 @@ function defineFollowLinkHandler(getHandlers) {
3059
3030
  return withPriority$1(definePlugin(createFollowLinkPlugin(getHandlers)), Priority$1.high);
3060
3031
  }
3061
3032
 
3062
- //#endregion
3063
- //#region src/extensions/frontmatter.ts
3033
+ // src/extensions/frontmatter.ts
3064
3034
  /**
3065
- * Stores YAML frontmatter as a non-rendered attribute on the root `doc` node.
3035
+ * Stores YAML frontmatter as a non-rendered attribute on the root `doc` node,
3036
+ * plus whether the first block starts right under its closing fence.
3066
3037
  */
3067
3038
  function defineDocFrontmatterAttr() {
3068
- return defineNodeAttr({
3039
+ return union(defineNodeAttr({
3069
3040
  type: "doc",
3070
3041
  attr: "frontmatter",
3071
3042
  default: null
3072
- });
3043
+ }), defineNodeAttr({
3044
+ type: "doc",
3045
+ attr: "frontmatterTight",
3046
+ default: false
3047
+ }));
3073
3048
  }
3074
3049
 
3075
- //#endregion
3076
- //#region src/utils/execute-command.ts
3050
+ // src/utils/execute-command.ts
3077
3051
  function executeCommand(view, command) {
3078
3052
  return command(view.state, view.dispatch, view);
3079
3053
  }
3080
3054
 
3081
- //#endregion
3082
- //#region src/extensions/hidden-run-caret.ts
3055
+ // src/extensions/hidden-run-caret.ts
3083
3056
  const snapKey = new PluginKey("meowdown-hidden-run-snap");
3084
3057
  const beforeInputKey = new PluginKey("meowdown-hidden-run-beforeinput");
3085
3058
  function createSnapPlugin() {
@@ -3155,8 +3128,7 @@ function defineHiddenRunCaret() {
3155
3128
  }), Priority$1.highest));
3156
3129
  }
3157
3130
 
3158
- //#endregion
3159
- //#region src/extensions/horizontal-rule.ts
3131
+ // src/extensions/horizontal-rule.ts
3160
3132
  function defineHorizontalRuleMarkerAttr() {
3161
3133
  return defineNodeAttr({
3162
3134
  type: "horizontalRule",
@@ -3170,8 +3142,7 @@ function defineMeowdownHorizontalRule() {
3170
3142
  return union(defineHorizontalRuleSpec(), defineHorizontalRuleCommands(), defineHorizontalRuleMarkerAttr(), defineBlockInputRule(horizontalRuleInputRule.regex, horizontalRuleInputRule.handler));
3171
3143
  }
3172
3144
 
3173
- //#endregion
3174
- //#region src/utils/non-prose-attrs.ts
3145
+ // src/utils/non-prose-attrs.ts
3175
3146
  const NON_PROSE_ATTRS = {
3176
3147
  spellcheck: "false",
3177
3148
  autocorrect: "off",
@@ -3179,8 +3150,7 @@ const NON_PROSE_ATTRS = {
3179
3150
  writingsuggestions: "false"
3180
3151
  };
3181
3152
 
3182
- //#endregion
3183
- //#region src/extensions/html-comment.ts
3153
+ // src/extensions/html-comment.ts
3184
3154
  /**
3185
3155
  * A block-level HTML comment (`<!-- ... -->`) as an invisible, atomic node.
3186
3156
  *
@@ -3219,8 +3189,7 @@ function defineHTMLComment() {
3219
3189
  });
3220
3190
  }
3221
3191
 
3222
- //#endregion
3223
- //#region src/utils/to-positive-number.ts
3192
+ // src/utils/to-positive-number.ts
3224
3193
  /**
3225
3194
  * The value rounded to an integer, or nothing unless it is a finite number
3226
3195
  * above zero.
@@ -3229,8 +3198,7 @@ function toPositiveNumber(value) {
3229
3198
  if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.round(value);
3230
3199
  }
3231
3200
 
3232
- //#endregion
3233
- //#region src/extensions/magic-comment.ts
3201
+ // src/extensions/magic-comment.ts
3234
3202
  const MAGIC_COMMENT_RE = /^<!--\s*(\{[\s\S]*?\})\s*-->/;
3235
3203
  const TRAILING_MAGIC_COMMENT_RE = /(?:<!--\s*\{[\s\S]*?\}\s*-->)+$/;
3236
3204
  /**
@@ -3277,8 +3245,7 @@ function stripMagicComment(source) {
3277
3245
  return source.replace(TRAILING_MAGIC_COMMENT_RE, "");
3278
3246
  }
3279
3247
 
3280
- //#endregion
3281
- //#region src/extensions/post-embed.ts
3248
+ // src/extensions/post-embed.ts
3282
3249
  /**
3283
3250
  * Wrap a loader in a 64-entry LRU keyed by URL. A settled URL answers
3284
3251
  * synchronously, so a revisited document renders its cards in the first
@@ -3339,8 +3306,7 @@ function parsePostEmbedSnapshot(value) {
3339
3306
  return result.success ? result.output : void 0;
3340
3307
  }
3341
3308
 
3342
- //#endregion
3343
- //#region src/extensions/wiki-embed.ts
3309
+ // src/extensions/wiki-embed.ts
3344
3310
  const WIKI_EMBED_SIZE = /^(\d+)(?:x(\d+))?$/i;
3345
3311
  function positiveInteger(value) {
3346
3312
  if (!value) return null;
@@ -3402,8 +3368,7 @@ function wikiEmbedBasename(target) {
3402
3368
  }
3403
3369
  }
3404
3370
 
3405
- //#endregion
3406
- //#region src/extensions/image.ts
3371
+ // src/extensions/image.ts
3407
3372
  /**
3408
3373
  * Show an `src` as-is when it is an http(s) URL, otherwise skip rendering it.
3409
3374
  */
@@ -3766,8 +3731,7 @@ function defineImage(getOptions) {
3766
3731
  });
3767
3732
  }
3768
3733
 
3769
- //#endregion
3770
- //#region src/extensions/mark-chunk.ts
3734
+ // src/extensions/mark-chunk.ts
3771
3735
  function markChunkToJSON(chunk) {
3772
3736
  const [from, to, marks] = chunk;
3773
3737
  return [
@@ -3785,8 +3749,7 @@ function markChunkFromJSON(schema, json) {
3785
3749
  ];
3786
3750
  }
3787
3751
 
3788
- //#endregion
3789
- //#region src/extensions/marks-equal.ts
3752
+ // src/extensions/marks-equal.ts
3790
3753
  /**
3791
3754
  * Position-wise equality on two mark arrays. Returns `true` only when
3792
3755
  * the arrays have the same length and `a[i].eq(b[i])` for every index.
@@ -3798,8 +3761,7 @@ function marksEqual(a, b) {
3798
3761
  return true;
3799
3762
  }
3800
3763
 
3801
- //#endregion
3802
- //#region src/extensions/batch-set-mark-step.ts
3764
+ // src/extensions/batch-set-mark-step.ts
3803
3765
  const SPARSE_CHUNK_LIMIT = 32;
3804
3766
  /**
3805
3767
  * Apply a small batch by visiting each chunk's narrow range independently.
@@ -3968,8 +3930,7 @@ var BatchSetMarkStep = class BatchSetMarkStep extends Step {
3968
3930
  Step.jsonID("batchSetMark", BatchSetMarkStep);
3969
3931
  const emptyBatchSetMarkStep = new BatchSetMarkStep([]);
3970
3932
 
3971
- //#endregion
3972
- //#region src/extensions/reference-links.ts
3933
+ // src/extensions/reference-links.ts
3973
3934
  const MAX_DEFINITION_LENGTH = 1024;
3974
3935
  function normalizeReferenceLabel(label) {
3975
3936
  return normalizeIdentifier(label);
@@ -4076,8 +4037,7 @@ function updateReferenceDefinitions(previous, transaction, doc) {
4076
4037
  return collectReferenceDefinitions(doc);
4077
4038
  }
4078
4039
 
4079
- //#endregion
4080
- //#region src/extensions/inline-text-to-mark-chunks.ts
4040
+ // src/extensions/inline-text-to-mark-chunks.ts
4081
4041
  /**
4082
4042
  * Lookup from Lezer node type id to the ProseMirror mark.
4083
4043
  *
@@ -4650,8 +4610,7 @@ function emit(out, from, to, marks) {
4650
4610
  ]);
4651
4611
  }
4652
4612
 
4653
- //#endregion
4654
- //#region src/extensions/inline-mark-plugin.ts
4613
+ // src/extensions/inline-mark-plugin.ts
4655
4614
  const META_KEY = "inline-marks-applied";
4656
4615
  const TRIGGER_KEY = "inline-marks-trigger";
4657
4616
  const RESTYLE_KEY = "inline-marks-restyle";
@@ -4877,8 +4836,7 @@ function defineInlineMarkPlugin(getOptions) {
4877
4836
  return definePlugin(createInlineMarkPlugin(getOptions));
4878
4837
  }
4879
4838
 
4880
- //#endregion
4881
- //#region src/extensions/inline-marks.ts
4839
+ // src/extensions/inline-marks.ts
4882
4840
  function defineMdImage() {
4883
4841
  return defineMarkSpec({
4884
4842
  name: "mdImage",
@@ -5107,8 +5065,7 @@ function defineInlineMarks() {
5107
5065
  return union(defineMdMark(), defineMdEm(), defineMdStrong(), defineMdCode(), defineMdLinkText(), defineMdLinkUri(), defineMdLinkTitle(), defineMdDel(), defineMdHighlight(), defineMdTag(), defineMdWikilink(), defineMdImage(), defineMdFile(), defineMdMath(), defineMdPack());
5108
5066
  }
5109
5067
 
5110
- //#endregion
5111
- //#region src/utils/backticks.ts
5068
+ // src/utils/backticks.ts
5112
5069
  /**
5113
5070
  * Length of the longest run of `charCode` in `text`, at least `min`.
5114
5071
  */
@@ -5128,8 +5085,7 @@ function longestBacktickRun(text, min = 0) {
5128
5085
  return longestCharRun(text, 96, min);
5129
5086
  }
5130
5087
 
5131
- //#endregion
5132
- //#region src/extensions/inline-toggle.ts
5088
+ // src/extensions/inline-toggle.ts
5133
5089
  const TOGGLE_SPECS = {
5134
5090
  em: {
5135
5091
  node: LEZER_NODE_IDS.Emphasis,
@@ -5383,8 +5339,7 @@ function insideAtom(nodes, pos) {
5383
5339
  return false;
5384
5340
  }
5385
5341
 
5386
- //#endregion
5387
- //#region src/extensions/inline-toggle-commands.ts
5342
+ // src/extensions/inline-toggle-commands.ts
5388
5343
  function toggleInline(spec) {
5389
5344
  return (state, dispatch) => {
5390
5345
  if (state.selection.empty) return caretToggle(spec, state, dispatch);
@@ -5466,8 +5421,7 @@ function defineInlineToggle() {
5466
5421
  return union(defineInlineToggleCommands(), defineInlineToggleKeymap());
5467
5422
  }
5468
5423
 
5469
- //#endregion
5470
- //#region src/extensions/link-click.ts
5424
+ // src/extensions/link-click.ts
5471
5425
  const linkClickKey = new PluginKey("meowdown-link-click");
5472
5426
  /**
5473
5427
  * Call `onClick` when the user clicks a rendered Markdown link
@@ -5492,8 +5446,7 @@ function defineLinkClickHandler(getOnClick) {
5492
5446
  });
5493
5447
  }
5494
5448
 
5495
- //#endregion
5496
- //#region src/extensions/link-commands.ts
5449
+ // src/extensions/link-commands.ts
5497
5450
  /**
5498
5451
  * Normalize a typed URL with the existing autolink logic, else keep it verbatim.
5499
5452
  */
@@ -5661,8 +5614,7 @@ function defineLinkEditKeymap(onLinkEdit) {
5661
5614
  return defineKeymap({ "Mod-k": openLinkEdit(onLinkEdit) });
5662
5615
  }
5663
5616
 
5664
- //#endregion
5665
- //#region src/extensions/link-paste.ts
5617
+ // src/extensions/link-paste.ts
5666
5618
  const linkPasteKey = new PluginKey("meowdown-link-paste");
5667
5619
  /**
5668
5620
  * The pasted text as a link `href` when the clipboard holds exactly one URL:
@@ -5704,8 +5656,7 @@ function defineLinkPaste(enabled) {
5704
5656
  })), Priority$1.high);
5705
5657
  }
5706
5658
 
5707
- //#endregion
5708
- //#region src/extensions/list.ts
5659
+ // src/extensions/list.ts
5709
5660
  function serializeListMarker(value) {
5710
5661
  return value === ")" || value === "*" || value === "+" ? value : void 0;
5711
5662
  }
@@ -6092,8 +6043,7 @@ function defineMeowdownList() {
6092
6043
  return union(defineListSpec(), defineMeowdownListPlugins(), defineListCommands(), defineMeowdownListSerializer(), defineListDropIndicator(), defineMeowdownListInputRules(), defineMeowdownListKeymap(), defineListMarkerAttr(), defineListTaskMarkerAttr(), defineListMarkerGapAttr(), defineMeowdownListCommands());
6093
6044
  }
6094
6045
 
6095
- //#endregion
6096
- //#region src/extensions/mark-mode.ts
6046
+ // src/extensions/mark-mode.ts
6097
6047
  function createMarkModePlugin(getMode) {
6098
6048
  return new Plugin({ props: {
6099
6049
  attributes: (state) => ({ "data-mark-mode": getMode(state) }),
@@ -6150,8 +6100,7 @@ function defineMarkMode(getMode) {
6150
6100
  return definePlugin(createMarkModePlugin(getMode));
6151
6101
  }
6152
6102
 
6153
- //#endregion
6154
- //#region src/utils/katex.ts
6103
+ // src/utils/katex.ts
6155
6104
  let katexRenderPromise;
6156
6105
  /**
6157
6106
  * Load KaTeX's render function on first use and cache it. Most documents
@@ -6179,8 +6128,7 @@ function renderMathInto(katexRender, element, formula, displayMode) {
6179
6128
  }
6180
6129
  }
6181
6130
 
6182
- //#endregion
6183
- //#region src/extensions/math.ts
6131
+ // src/extensions/math.ts
6184
6132
  /**
6185
6133
  * Renders one inline math unit: a KaTeX preview next to the editable
6186
6134
  * `$formula$` source. CSS decides which of the two is visible; in hide and
@@ -6251,8 +6199,7 @@ function defineMath() {
6251
6199
  });
6252
6200
  }
6253
6201
 
6254
- //#endregion
6255
- //#region src/extensions/table-column-align.ts
6202
+ // src/extensions/table-column-align.ts
6256
6203
  function parseTableColumnAlign(value) {
6257
6204
  return value === "left" || value === "center" || value === "right" ? value : null;
6258
6205
  }
@@ -6446,8 +6393,7 @@ function defineTableColumnAlign() {
6446
6393
  return union(defineTableCellAlignAttr(), defineTableHeaderCellAlignAttr(), defineTableAlignSync(), defineTableColumnAlignCommands());
6447
6394
  }
6448
6395
 
6449
- //#endregion
6450
- //#region src/extensions/table.ts
6396
+ // src/extensions/table.ts
6451
6397
  /**
6452
6398
  * Whether the selection sits inside a table cell (data or header). Useful for
6453
6399
  * gating block-creating UI, since cells hold inline content only.
@@ -6486,8 +6432,7 @@ function defineTable() {
6486
6432
  return union(defineTableSpec(), defineTableRowSpec(), defineTableCellSpec(), defineTableHeaderCellSpec(), defineTableCellContent(), defineTableColumnAlign(), defineTableEditingPlugin({ allowTableNodeSelection: true }), defineTableCommands(), defineTableDropIndicator(), defineTableKeymap());
6487
6433
  }
6488
6434
 
6489
- //#endregion
6490
- //#region src/extensions/move-block.ts
6435
+ // src/extensions/move-block.ts
6491
6436
  /**
6492
6437
  * The index of the top-level block holding the whole selection, or undefined
6493
6438
  * when the selection spans several top-level blocks or floats between them (a
@@ -6549,8 +6494,7 @@ function defineMoveBlock() {
6549
6494
  });
6550
6495
  }
6551
6496
 
6552
- //#endregion
6553
- //#region src/extensions/pending-replacement.ts
6497
+ // src/extensions/pending-replacement.ts
6554
6498
  const pendingReplacementKey = new PluginKey("meowdownPendingReplacement");
6555
6499
  /**
6556
6500
  * The active pending replacement, or null when there is none.
@@ -6741,14 +6685,12 @@ function definePendingReplacementHandler(handler) {
6741
6685
  } }) }));
6742
6686
  }
6743
6687
 
6744
- //#endregion
6745
- //#region src/extensions/readonly.ts
6688
+ // src/extensions/readonly.ts
6746
6689
  function defineReadonly(getReadonly = () => true) {
6747
6690
  return definePlugin(new Plugin({ props: { editable: (state) => !getReadonly(state) } }));
6748
6691
  }
6749
6692
 
6750
- //#endregion
6751
- //#region src/utils/caret-coords.ts
6693
+ // src/utils/caret-coords.ts
6752
6694
  /**
6753
6695
  * A dimensionless point: the fallback measurement of a hidden (font-size: 0)
6754
6696
  * syntax run. A real caret rect always has line height, and a block-context
@@ -6776,15 +6718,13 @@ function tryCoordsAtPos(view, pos, side) {
6776
6718
  return isPointRect(coords) ? void 0 : coords;
6777
6719
  }
6778
6720
 
6779
- //#endregion
6780
- //#region src/utils/line-break.ts
6721
+ // src/utils/line-break.ts
6781
6722
  function isAfterLineBreak($pos) {
6782
6723
  const { parentOffset, parent } = $pos;
6783
6724
  return parentOffset > 0 && parent.textBetween(parentOffset - 1, parentOffset) === "\n";
6784
6725
  }
6785
6726
 
6786
- //#endregion
6787
- //#region src/extensions/caret-rect.ts
6727
+ // src/extensions/caret-rect.ts
6788
6728
  function findNativeCaretRect(view) {
6789
6729
  const selection = view.dom.ownerDocument.getSelection();
6790
6730
  if (selection == null || selection.rangeCount === 0) return void 0;
@@ -6890,8 +6830,7 @@ function measureCaretScrollRect(view) {
6890
6830
  return findCoordsCaretRect(view) ?? findAtomCaretRect(view);
6891
6831
  }
6892
6832
 
6893
- //#endregion
6894
- //#region src/extensions/scroll-to-selection.ts
6833
+ // src/extensions/scroll-to-selection.ts
6895
6834
  const key$1 = new PluginKey("meowdown-scroll-to-selection");
6896
6835
  function handleScrollToSelection(view) {
6897
6836
  const selection = view.state.selection;
@@ -6993,8 +6932,7 @@ function defineScrollToSelection() {
6993
6932
  }));
6994
6933
  }
6995
6934
 
6996
- //#endregion
6997
- //#region src/extensions/select-doc-boundary.ts
6935
+ // src/extensions/select-doc-boundary.ts
6998
6936
  function selectDocBoundary(direction, extend) {
6999
6937
  return (state, dispatch) => {
7000
6938
  const boundary = direction < 0 ? Selection.atStart(state.doc) : Selection.atEnd(state.doc);
@@ -7021,8 +6959,7 @@ function defineSelectDocBoundary() {
7021
6959
  });
7022
6960
  }
7023
6961
 
7024
- //#endregion
7025
- //#region src/extensions/soft-break.ts
6962
+ // src/extensions/soft-break.ts
7026
6963
  function canHoldSoftBreak($pos) {
7027
6964
  if (!isNodeOfType($pos.parent, "paragraph")) return false;
7028
6965
  const container = $pos.depth > 0 ? $pos.node($pos.depth - 1) : void 0;
@@ -7070,8 +7007,7 @@ function defineSoftBreak() {
7070
7007
  return union(defineCommands({ insertSoftBreak }), defineKeymap({ "Shift-Enter": chainCommands(exitCodeBlockAtEnd, softBreakCommand) }));
7071
7008
  }
7072
7009
 
7073
- //#endregion
7074
- //#region src/extensions/substitution.ts
7010
+ // src/extensions/substitution.ts
7075
7011
  const SUBSTITUTION_RULES = [
7076
7012
  [/<-/, "←"],
7077
7013
  [new RegExp((canUseRegexLookbehind() ? "(?<!-)" : "") + "->"), "→"],
@@ -7159,8 +7095,7 @@ function defineSubstitution(enabled) {
7159
7095
  return union(defineSubstitutionInputRules(enabled), defineSubstitutionUndo(), defineSubstitutionEnterRules(enabled));
7160
7096
  }
7161
7097
 
7162
- //#endregion
7163
- //#region src/extensions/system-substitution-guard.ts
7098
+ // src/extensions/system-substitution-guard.ts
7164
7099
  const EM_DASH = "—";
7165
7100
  /**
7166
7101
  * Block the macOS "smart dashes" rewrite. With the `spellcheck` attribute on,
@@ -7186,8 +7121,7 @@ function defineSystemSubstitutionGuard() {
7186
7121
  return withPriority$1(definePlugin(plugin), Priority$1.highest);
7187
7122
  }
7188
7123
 
7189
- //#endregion
7190
- //#region src/extensions/view-attributes.ts
7124
+ // src/extensions/view-attributes.ts
7191
7125
  /**
7192
7126
  * Add DOM attributes to the editable root. `class` and `style` values from
7193
7127
  * every such extension are combined, so applying this more than once adds
@@ -7197,8 +7131,7 @@ function defineViewAttributes(attributes) {
7197
7131
  return definePlugin(new Plugin({ props: { attributes } }));
7198
7132
  }
7199
7133
 
7200
- //#endregion
7201
- //#region src/utils/clean-text.ts
7134
+ // src/utils/clean-text.ts
7202
7135
  /**
7203
7136
  * Projects a document slice to syntax-clean text, omitting inline markers and
7204
7137
  * hidden link destinations. Set `preserveMathSource` when the result must keep
@@ -7219,8 +7152,7 @@ function cleanTextFromSlice(slice, options = {}) {
7219
7152
  return blocks.join("\n");
7220
7153
  }
7221
7154
 
7222
- //#endregion
7223
- //#region src/extensions/wikilink-trigger.ts
7155
+ // src/extensions/wikilink-trigger.ts
7224
7156
  const WIKILINK_OPEN = "[[";
7225
7157
  /**
7226
7158
  * Inserts the `[[` wikilink trigger at the cursor and opens the wikilink menu.
@@ -7265,8 +7197,7 @@ function defineWikilinkTrigger(enabled) {
7265
7197
  });
7266
7198
  }
7267
7199
 
7268
- //#endregion
7269
- //#region src/extensions/wikilink.ts
7200
+ // src/extensions/wikilink.ts
7270
7201
  /**
7271
7202
  * Render `mdWikilink` as a non-editable label standing in for the raw source.
7272
7203
  * The source stays in `contentDOM` after the label, hidden by `style.css`
@@ -7311,8 +7242,7 @@ function defineWikilink() {
7311
7242
  });
7312
7243
  }
7313
7244
 
7314
- //#endregion
7315
- //#region src/extensions/x-post-media-click.ts
7245
+ // src/extensions/x-post-media-click.ts
7316
7246
  const xPostMediaClickKey = new PluginKey("meowdown-x-post-media-click");
7317
7247
  /**
7318
7248
  * Call `onClick` when the user activates a photo or video inside an X post
@@ -7330,8 +7260,7 @@ function defineXPostMediaClickHandler(getOnClick) {
7330
7260
  }));
7331
7261
  }
7332
7262
 
7333
- //#endregion
7334
- //#region src/extensions/youtube-video-click.ts
7263
+ // src/extensions/youtube-video-click.ts
7335
7264
  const youTubeVideoClickKey = new PluginKey("meowdown-youtube-video-click");
7336
7265
  /**
7337
7266
  * Call `onClick` when the user activates the poster of a YouTube card.
@@ -7348,8 +7277,7 @@ function defineYouTubeVideoClickHandler(getOnClick) {
7348
7277
  }));
7349
7278
  }
7350
7279
 
7351
- //#endregion
7352
- //#region src/extensions/extension.ts
7280
+ // src/extensions/extension.ts
7353
7281
  function defineEditorExtensionImpl(options) {
7354
7282
  return union(defineMeowdownParagraph(), defineDoc(), defineDocFrontmatterAttr(), defineText(), defineMeowdownBlockquote(), defineMeowdownList(), defineHeading(), defineTable(), defineCodeBlock(), defineMeowdownHorizontalRule(), defineHTMLComment(), defineInlineMarks(), defineEditorConfig(options), defineImage(getEditorConfig), defineFileView(getEditorConfig), defineModClickPrevention(), defineFileClickHandler((state) => getEditorConfig(state).onFileClick), defineImageClickHandler((state) => getEditorConfig(state).onImageClick), defineXPostMediaClickHandler((state) => getEditorConfig(state).onXPostMediaClick), defineYouTubeVideoClickHandler((state) => getEditorConfig(state).onYouTubeVideoClick), defineWikilinkClickHandler((state) => getEditorConfig(state).onWikilinkClick), defineTagClickHandler((state) => getEditorConfig(state).onTagClick), defineLinkClickHandler((state) => getEditorConfig(state).onLinkClick), defineFollowLinkHandler(getEditorConfig), defineExitBoundaryHandler((state) => getEditorConfig(state).onExitBoundary), defineFilePaste(getEditorConfig), defineEmbedPaste((state) => !!getEditorConfig(state).embedPaste), defineLinkPaste((state) => !!getEditorConfig(state).linkPaste), defineBulletAfterHeading((state) => !!getEditorConfig(state).bulletAfterHeading), defineBackspaceEmptyFirstBlock((state) => !!getEditorConfig(state).backspaceDeletesEmptyFirstBlock), defineSubstitution((state) => !!getEditorConfig(state).substitution), defineWikilinkTrigger((state) => !!getEditorConfig(state).wikilinkEnabled), definePlaceholder$1({
7355
7283
  placeholder: (state) => {
@@ -7383,8 +7311,7 @@ function defineEditorExtension(options = {}) {
7383
7311
  return defineEditorExtensionImpl(options);
7384
7312
  }
7385
7313
 
7386
- //#endregion
7387
- //#region src/extensions/schema.ts
7314
+ // src/extensions/schema.ts
7388
7315
  /**
7389
7316
  * The schema shared by every parser and serializer, built once and cached.
7390
7317
  */
@@ -7428,15 +7355,17 @@ function getNodeBuildersForSchema(schema) {
7428
7355
  return builders;
7429
7356
  }
7430
7357
 
7431
- //#endregion
7432
- //#region src/converters/ast-to-pm.ts
7358
+ // src/converters/ast-to-pm.ts
7433
7359
  /**
7434
7360
  * Build nodes with the caller's schema; Markdown inline syntax remains literal text.
7435
7361
  */
7436
7362
  function astToDoc(node, nodes = getNodeBuilders()) {
7437
7363
  const children = node.children?.map((child) => astToDoc(child, nodes)) || [];
7438
7364
  switch (node.type) {
7439
- case "document": return nodes.doc(node.frontmatter == null ? {} : { frontmatter: node.frontmatter }, children);
7365
+ case "document": return nodes.doc({
7366
+ frontmatter: node.frontmatter ?? null,
7367
+ frontmatterTight: !!node.frontmatterTight
7368
+ }, children);
7440
7369
  case "paragraph": return nodes.paragraph(node.value);
7441
7370
  case "heading": return nodes.heading({
7442
7371
  level: node.level,
@@ -7468,8 +7397,7 @@ function astToDoc(node, nodes = getNodeBuilders()) {
7468
7397
  }
7469
7398
  }
7470
7399
 
7471
- //#endregion
7472
- //#region src/converters/md-to-pm.ts
7400
+ // src/converters/md-to-pm.ts
7473
7401
  /**
7474
7402
  * Convert a markdown string into a ProseMirror document node.
7475
7403
  *
@@ -7488,8 +7416,7 @@ function markdownToDoc(markdown, options = {}) {
7488
7416
  return astToDoc(parseMarkdownAst(markdown, options), options.nodes);
7489
7417
  }
7490
7418
 
7491
- //#endregion
7492
- //#region src/extensions/code-block-languages.ts
7419
+ // src/extensions/code-block-languages.ts
7493
7420
  const excludeLanguages = /* @__PURE__ */ new Set([
7494
7421
  "MscGen",
7495
7422
  "Xù",
@@ -7532,8 +7459,7 @@ const codeBlockLanguages = languages.map((language) => ({
7532
7459
  value: language.name.toLowerCase()
7533
7460
  })).filter((language) => !excludeLanguages.has(language.label)).concat(extraLanguages).sort((a, b) => a.label.localeCompare(b.label));
7534
7461
 
7535
- //#endregion
7536
- //#region src/extensions/key-bindings.ts
7462
+ // src/extensions/key-bindings.ts
7537
7463
  /**
7538
7464
  * Human-readable descriptions of the editor's formatting and heading shortcuts.
7539
7465
  */
@@ -7567,8 +7493,7 @@ const EDITOR_KEY_BINDINGS = {
7567
7493
  Escape: "Collapse the selection"
7568
7494
  };
7569
7495
 
7570
- //#endregion
7571
- //#region src/extensions/mark-hover.ts
7496
+ // src/extensions/mark-hover.ts
7572
7497
  const IDLE = { kind: "idle" };
7573
7498
  function getHit(phase) {
7574
7499
  return phase.kind === "active" || phase.kind === "leaving" ? phase.hit : void 0;
@@ -7800,8 +7725,7 @@ function defineMarkHoverHandler(config) {
7800
7725
  }));
7801
7726
  }
7802
7727
 
7803
- //#endregion
7804
- //#region src/extensions/link-hover.ts
7728
+ // src/extensions/link-hover.ts
7805
7729
  const linkHoverKey = new PluginKey("meowdown-link-hover");
7806
7730
  /**
7807
7731
  * Delay before a cold hover enters, in ms.
@@ -7845,14 +7769,12 @@ function dismissLinkHover(state) {
7845
7769
  linkHoverKey.getState(state)?.dismiss();
7846
7770
  }
7847
7771
 
7848
- //#endregion
7849
- //#region src/utils/force-reflow.ts
7772
+ // src/utils/force-reflow.ts
7850
7773
  function forceReflow(element) {
7851
7774
  element.offsetWidth;
7852
7775
  }
7853
7776
 
7854
- //#endregion
7855
- //#region src/extensions/virtual-caret.ts
7777
+ // src/extensions/virtual-caret.ts
7856
7778
  const key = new PluginKey("meowdown-virtual-caret");
7857
7779
  const BLINK_ANIMATIONS = ["md-virtual-caret-blink", "md-virtual-caret-blink2"];
7858
7780
  const DATA_ATTRIBUTE = "data-meowdown-virtual-caret";
@@ -8017,8 +7939,7 @@ function defineVirtualCaret(layer) {
8017
7939
  }));
8018
7940
  }
8019
7941
 
8020
- //#endregion
8021
- //#region src/extensions/wikilink-hover.ts
7942
+ // src/extensions/wikilink-hover.ts
8022
7943
  const wikilinkHoverKey = new PluginKey("meowdown-wikilink-hover");
8023
7944
  /**
8024
7945
  * Delay before a cold hover enters, in ms.
@@ -8058,8 +7979,7 @@ function defineWikilinkHoverHandler(onHoverChange, openDelay = OPEN_DELAY, close
8058
7979
  });
8059
7980
  }
8060
7981
 
8061
- //#endregion
8062
- //#region src/utils/display-text.ts
7982
+ // src/utils/display-text.ts
8063
7983
  function getAtomDisplayText(atom) {
8064
7984
  switch (atom.type.name) {
8065
7985
  case "mdWikilink": {
@@ -8088,8 +8008,7 @@ function getTextblockDisplayText(textblock) {
8088
8008
  return output;
8089
8009
  }
8090
8010
 
8091
- //#endregion
8092
- //#region src/utils/selected-text.ts
8011
+ // src/utils/selected-text.ts
8093
8012
  /**
8094
8013
  * The current selection as Markdown: block structure (list markers, headings,
8095
8014
  * blockquotes) is serialized, and inline Markdown syntax is already literal
@@ -8109,8 +8028,7 @@ function getSelectedText(state) {
8109
8028
  }
8110
8029
  }
8111
8030
 
8112
- //#endregion
8113
- //#region src/utils/virtual-element.ts
8031
+ // src/utils/virtual-element.ts
8114
8032
  function tryHiddenRunCoords(view, pos, side) {
8115
8033
  if (side === 1) {
8116
8034
  const run = getHiddenRunAfter(view.state, pos);
@@ -8149,5 +8067,4 @@ function getVirtualElementFromRange(view, range) {
8149
8067
  };
8150
8068
  }
8151
8069
 
8152
- //#endregion
8153
8070
  export { EDITOR_KEY_BINDINGS, Priority, buildFileMarkdown, codeBlockLanguages, collectReferenceDefinitions, defaultResolveImageUrl, defaultResolveXPost, defaultResolveYouTubeVideo, defineBackspaceEmptyFirstBlock, defineBulletAfterHeading, defineCodeBlockPreviewPlugin, defineCodeBlockSyntaxHighlight, defineEditorExtension, defineEmbedPaste, defineExitBoundaryHandler, defineFileClickHandler, defineFilePaste, defineFileView, defineFollowLinkHandler, defineHTMLComment, defineImage, defineImageClickHandler, defineLinkClickHandler, defineLinkCommands, defineLinkEditKeymap, defineLinkHoverHandler, defineLinkPaste, defineMath, definePendingReplacementHandler, definePlaceholder, defineReadonly, defineSearchStatusHandler, defineSubstitution, defineTagClickHandler, defineViewAttributes, defineVirtualCaret, defineWikilinkClickHandler, defineWikilinkHoverHandler, defineWikilinkTrigger, defineXPostMediaClickHandler, defineYouTubeVideoClickHandler, dismissLinkHover, docToMarkdown, docToParagraphMarkdown, formatFileSize, formatSizedWikiEmbed, getCodeTokens, getEditorConfig, getFileKind, getIsComposing, getLinkText, getLinkUnitAt, getMarkBuilders, getPendingReplacement, getSearchStatus, getSelectedText, getTableColumnAlign, getTextblockDisplayText, getVirtualElementFromRange, inlineTextToMarkChunks, inlineTextToMarkChunksWithContext, insertLink, isCodeBlockPreviewHiddenDecoration, isLinkTextForHref, isMarkOfType, isModEvent, isNodeOfType, isReferenceDefinitionNode, isSelectionInTableCell, loadKaTeX, markdownToDoc, normalizeHref, paragraphMarkdownToDoc, parsePostEmbedSnapshot, parseWikiEmbed, removeLink, renderMathInto, updateEditorConfig, updateLink, wikiEmbedBasename, withPriority };