@meowdown/core 0.65.6 → 0.66.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/README.md CHANGED
@@ -60,6 +60,7 @@ the current block to that level (or back to a paragraph).
60
60
  | `Mod-5` | Heading 5 | `##### heading` |
61
61
  | `Mod-6` | Heading 6 | `###### heading` |
62
62
  | `Mod-.` | Fold or unfold a bullet | |
63
+ | `Shift-Enter` | Insert a line break | |
63
64
  | `Mod-Enter` | Follow the link under the caret, or cycle a checkbox task | `- [ ]` / `- [x]` |
64
65
  | `Mod-Shift-Enter` | Cycle a circle checkbox task | `+ [ ]` / `+ [x]` |
65
66
  | `Mod-Shift-7` | Ordered list | `1. item` |
package/dist/index.d.ts CHANGED
@@ -793,7 +793,11 @@ declare function defineEditorExtensionImpl(options: EditorExtensionOptions): imp
793
793
  Marks: {
794
794
  mdPack: MdPackAttrs;
795
795
  };
796
- }>]>, import("@prosekit/core").PlainExtension, import("@prosekit/core").Extension<import("@prosekit/core").ExtensionTyping<any, any, any>>, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").Union<readonly [import("@prosekit/core").Extension<{
796
+ }>]>, import("@prosekit/core").PlainExtension, import("@prosekit/core").Extension<import("@prosekit/core").ExtensionTyping<any, any, any>>, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").Union<readonly [import("@prosekit/core").Extension<{
797
+ Commands: {
798
+ insertSoftBreak: [];
799
+ };
800
+ }>, import("@prosekit/core").PlainExtension]>, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").Union<readonly [import("@prosekit/core").Extension<{
797
801
  Commands: {
798
802
  toggleEm: [];
799
803
  toggleStrong: [];
@@ -1337,6 +1341,7 @@ export declare const EDITOR_KEY_BINDINGS: {
1337
1341
  readonly 'Mod-5': "Heading 5";
1338
1342
  readonly 'Mod-6': "Heading 6";
1339
1343
  readonly 'Mod-.': "Fold or unfold a bullet";
1344
+ readonly 'Shift-Enter': "Insert a line break";
1340
1345
  readonly 'Mod-Enter': "Follow the link under the caret, or cycle a checkbox task";
1341
1346
  readonly 'Mod-Shift-Enter': "Cycle a circle checkbox task";
1342
1347
  readonly 'Mod-Shift-7': "Ordered list";
@@ -1396,12 +1401,6 @@ declare const NODE_NAMES: readonly ["doc", "text", "paragraph", "heading", "bloc
1396
1401
  type NodeName = (typeof NODE_NAMES)[number];
1397
1402
  export declare function isNodeOfType(node: ProseMirrorNode, name: NodeName): boolean;
1398
1403
  //#endregion
1399
- //#region src/extensions/spell-check.d.ts
1400
- /**
1401
- * @deprecated This will be removed in future versions.
1402
- */
1403
- export declare function defineSpellCheckPlugin(spellCheck: boolean): PlainExtension;
1404
- //#endregion
1405
1404
  //#region src/extensions/substitution.d.ts
1406
1405
  /**
1407
1406
  * Apply the editor's automatic plain-text substitutions.
package/dist/index.js CHANGED
@@ -32,12 +32,12 @@ import { defineEnterRule, defineTextBlockEnterRule } from "@prosekit/extensions/
32
32
  import { defineInputRule, defineTextBlockInputRule } from "@prosekit/extensions/input-rule";
33
33
  import { triggerAutocomplete } from "@prosekit/extensions/autocomplete";
34
34
  import { defineListCommands, defineListDropIndicator, defineListKeymap, defineListSpec, moveList, toggleList, unwrapList, wrapInList } from "@prosekit/extensions/list";
35
- import { chainCommands, lift } from "@prosekit/pm/commands";
35
+ import { chainCommands, lift, newlineInCode, splitBlock } from "@prosekit/pm/commands";
36
36
  import { defineHorizontalRule } from "@prosekit/extensions/horizontal-rule";
37
- import { AddMarkStep, AddNodeMarkStep, AttrStep, RemoveMarkStep, RemoveNodeMarkStep, ReplaceStep, Step, StepResult, Transform } from "@prosekit/pm/transform";
37
+ import { AttrStep, ReplaceStep, Step, StepResult, Transform } from "@prosekit/pm/transform";
38
38
  import { decodeString } from "micromark-util-decode-string";
39
39
  import { normalizeIdentifier } from "micromark-util-normalize-identifier";
40
- import { createListRenderingPlugin, createSafariInputMethodWorkaroundPlugin, createToggleCollapsedCommand, defaultAttributesGetter, findCheckboxInListItem, handleListMarkerMouseDown, joinListElements, listToDOM, unwrapListSlice, wrappingListInputRule } from "prosemirror-flat-list";
40
+ import { createListRenderingPlugin, createSafariInputMethodWorkaroundPlugin, createToggleCollapsedCommand, defaultAttributesGetter, enterCommand, findCheckboxInListItem, handleListMarkerMouseDown, joinListElements, listToDOM, unwrapListSlice, wrappingListInputRule } from "prosemirror-flat-list";
41
41
  import { defineTableCellSpec, defineTableCommands, defineTableDropIndicator, defineTableEditingPlugin, defineTableHeaderCellSpec, defineTableRowSpec, defineTableSpec, deleteTable, isCellSelection } from "@prosekit/extensions/table";
42
42
  import { closeHistory } from "@prosekit/pm/history";
43
43
  import { registerResizableHandleElement, registerResizableRootElement } from "@prosekit/web/resizable";
@@ -5672,6 +5672,13 @@ function tryCoordsAtPos(view, pos, side) {
5672
5672
  return isPointRect(coords) ? void 0 : coords;
5673
5673
  }
5674
5674
 
5675
+ //#endregion
5676
+ //#region src/utils/line-break.ts
5677
+ function isAfterLineBreak($pos) {
5678
+ const { parentOffset, parent } = $pos;
5679
+ return parentOffset > 0 && parent.textBetween(parentOffset - 1, parentOffset) === "\n";
5680
+ }
5681
+
5675
5682
  //#endregion
5676
5683
  //#region src/extensions/caret-rect.ts
5677
5684
  function findNativeCaretRect(view) {
@@ -5691,11 +5698,10 @@ function findNativeCaretRect(view) {
5691
5698
  }
5692
5699
  function findCoordsCaretRect(view) {
5693
5700
  const state = view.state;
5694
- const head = state.selection.head;
5701
+ const { head, $head } = state.selection;
5695
5702
  const runBefore = getHiddenRunBefore(state, head);
5696
5703
  const runAfter = getHiddenRunAfter(state, head);
5697
- const $head = state.doc.resolve(head);
5698
- const afterLineBreak = $head.parentOffset > 0 && $head.parent.textBetween($head.parentOffset - 1, $head.parentOffset) === "\n";
5704
+ const afterLineBreak = isAfterLineBreak($head);
5699
5705
  const preferredBeforeSide = runBefore == null && !afterLineBreak;
5700
5706
  const probes = [[head, preferredBeforeSide], [head, !preferredBeforeSide]];
5701
5707
  if (runBefore != null) probes.push([runBefore.from, true]);
@@ -5891,6 +5897,55 @@ function defineSelectDocBoundary() {
5891
5897
  });
5892
5898
  }
5893
5899
 
5900
+ //#endregion
5901
+ //#region src/extensions/soft-break.ts
5902
+ function canHoldSoftBreak($pos) {
5903
+ if (!isNodeOfType($pos.parent, "paragraph")) return false;
5904
+ const container = $pos.depth > 0 ? $pos.node($pos.depth - 1) : void 0;
5905
+ if (container == null) return true;
5906
+ return !isNodeOfType(container, "tableCell") && !isNodeOfType(container, "tableHeaderCell");
5907
+ }
5908
+ const splitBlockOnEnter = chainCommands(enterCommand, splitBlock);
5909
+ function isBeforeLineBreak($pos) {
5910
+ const { parentOffset, parent } = $pos;
5911
+ return parentOffset < parent.content.size && parent.textBetween(parentOffset, parentOffset + 1) === "\n";
5912
+ }
5913
+ const splitPendingSoftBreak = (state, dispatch, view) => {
5914
+ const { $from, empty } = state.selection;
5915
+ if (!empty || !canHoldSoftBreak($from)) return false;
5916
+ const inFront = isAfterLineBreak($from);
5917
+ if (!inFront && !isBeforeLineBreak($from)) return false;
5918
+ let split;
5919
+ if (!splitBlockOnEnter(state, (candidate) => {
5920
+ split = candidate;
5921
+ }, view) || split == null) return false;
5922
+ if (dispatch == null) return true;
5923
+ const start = inFront ? $from.pos - 1 : $from.pos;
5924
+ const side = inFront ? -1 : 1;
5925
+ const from = split.mapping.map(start, side);
5926
+ const to = split.mapping.map(start + 1, side);
5927
+ dispatch(split.delete(from, to).scrollIntoView());
5928
+ return true;
5929
+ };
5930
+ const insertSoftBreakText = (state, dispatch) => {
5931
+ if (!canHoldSoftBreak(state.selection.$from)) return false;
5932
+ dispatch?.(state.tr.insertText("\n").scrollIntoView());
5933
+ return true;
5934
+ };
5935
+ const softBreakCommand = chainCommands(newlineInCode, splitPendingSoftBreak, insertSoftBreakText);
5936
+ /**
5937
+ * Insert a markdown soft line break at the caret: a literal `\n` in the
5938
+ * paragraph's text. In a code block it writes the newline plain Enter writes
5939
+ * there. On a caret that already sits beside a soft break it splits the block
5940
+ * instead, because a paragraph cannot hold a blank line.
5941
+ */
5942
+ function insertSoftBreak() {
5943
+ return softBreakCommand;
5944
+ }
5945
+ function defineSoftBreak() {
5946
+ return union(defineCommands({ insertSoftBreak }), defineKeymap({ "Shift-Enter": softBreakCommand }));
5947
+ }
5948
+
5894
5949
  //#endregion
5895
5950
  //#region src/extensions/system-substitution-guard.ts
5896
5951
  const EM_DASH = "—";
@@ -5932,7 +5987,7 @@ function defineViewAttributes(attributes) {
5932
5987
  //#endregion
5933
5988
  //#region src/extensions/extension.ts
5934
5989
  function defineEditorExtensionImpl(options) {
5935
- return union(defineMeowdownParagraph(), defineDoc(), defineDocFrontmatterAttr(), defineText(), defineBlockquote(), defineMeowdownList(), defineHeading(), defineTable(), defineCodeBlock$1(), defineMeowdownHorizontalRule(), defineHTMLComment(), defineInlineMarks(), defineViewAttributes({ class: "meowdown-content" }), defineCodeBlockSyntaxHighlight(), defineCrossEditorDrag(), defineEscapeCollapse(), defineMoveBlock(), defineSelectDocBoundary(), defineInlineMarkPlugin(options), defineInlineToggle(), defineLinkCommands(), defineWikilink(), defineMath(), defineMarkMode(options.markMode ?? "focus"), defineClipboard(), defineScrollToSelection(), defineHiddenRunCaret(), defineSystemSubstitutionGuard(), defineAtomMarkNavigation({ marks: ATOM_SOURCE_MARK_NAMES.map((name) => ({
5990
+ return union(defineMeowdownParagraph(), defineDoc(), defineDocFrontmatterAttr(), defineText(), defineBlockquote(), defineMeowdownList(), defineHeading(), defineTable(), defineCodeBlock$1(), defineMeowdownHorizontalRule(), defineHTMLComment(), defineInlineMarks(), defineViewAttributes({ class: "meowdown-content" }), defineCodeBlockSyntaxHighlight(), defineCrossEditorDrag(), defineEscapeCollapse(), defineSoftBreak(), defineMoveBlock(), defineSelectDocBoundary(), defineInlineMarkPlugin(options), defineInlineToggle(), defineLinkCommands(), defineWikilink(), defineMath(), defineMarkMode(options.markMode ?? "focus"), defineClipboard(), defineScrollToSelection(), defineHiddenRunCaret(), defineSystemSubstitutionGuard(), defineAtomMarkNavigation({ marks: ATOM_SOURCE_MARK_NAMES.map((name) => ({
5936
5991
  name,
5937
5992
  modes: [
5938
5993
  "hide",
@@ -7885,6 +7940,7 @@ const EDITOR_KEY_BINDINGS = {
7885
7940
  "Mod-5": "Heading 5",
7886
7941
  "Mod-6": "Heading 6",
7887
7942
  "Mod-.": "Fold or unfold a bullet",
7943
+ "Shift-Enter": "Insert a line break",
7888
7944
  "Mod-Enter": "Follow the link under the caret, or cycle a checkbox task",
7889
7945
  "Mod-Shift-Enter": "Cycle a circle checkbox task",
7890
7946
  "Mod-Shift-7": "Ordered list",
@@ -8054,98 +8110,6 @@ function defineLinkPaste() {
8054
8110
  })), Priority$1.high);
8055
8111
  }
8056
8112
 
8057
- //#endregion
8058
- //#region src/utils/is-mark-step.ts
8059
- function isMarkStep(step) {
8060
- return step instanceof AddMarkStep || step instanceof AddNodeMarkStep || step instanceof RemoveMarkStep || step instanceof RemoveNodeMarkStep || step instanceof BatchSetMarkStep;
8061
- }
8062
-
8063
- //#endregion
8064
- //#region src/extensions/spell-check.ts
8065
- const SPELL_CHECK_PAUSE_TIMEOUT = 1200;
8066
- function hasContentChanged(transactions) {
8067
- for (const tr of transactions) for (const step of tr.steps) if (!isMarkStep(step)) return true;
8068
- return false;
8069
- }
8070
- /**
8071
- * Stop macOS from rewriting straight punctuation into "smart" punctuation as
8072
- * the user types.
8073
- *
8074
- * On macOS, WebKit applies the system "smart quotes and dashes" substitution
8075
- * inside `contenteditable` when `spellcheck` is true. Typing right after the hidden
8076
- * `<!-- {"width":..,"height":..} -->` sizing comment that backs an image lets
8077
- * it rewrite the `--` in `-->` into an em dash. which invalidates the comment so
8078
- * meowdown can no longer parse it and it leaks into the note as literal text.
8079
- *
8080
- * We disable the `spellcheck` attribute for a few seconds before any doc
8081
- * change transaction. This would prevent the smart punctuation substitution from happening.
8082
- */
8083
- function createSpellCheckPluginState(spellCheck) {
8084
- let view;
8085
- let timeoutId;
8086
- let paused = false;
8087
- let currentValue;
8088
- const update = () => {
8089
- const dom = view && !view.isDestroyed && view.dom;
8090
- if (!dom) return;
8091
- const newValue = spellCheck && !paused;
8092
- if (newValue !== currentValue) {
8093
- currentValue = newValue;
8094
- dom.spellcheck = newValue;
8095
- }
8096
- };
8097
- const pause = () => {
8098
- if (timeoutId) clearTimeout(timeoutId);
8099
- paused = true;
8100
- update();
8101
- timeoutId = setTimeout(() => {
8102
- paused = false;
8103
- update();
8104
- }, SPELL_CHECK_PAUSE_TIMEOUT);
8105
- };
8106
- return {
8107
- pause,
8108
- apply(transactions) {
8109
- if (hasContentChanged(transactions)) pause();
8110
- },
8111
- view(editorView) {
8112
- view = editorView;
8113
- return { destroy() {
8114
- view = void 0;
8115
- } };
8116
- }
8117
- };
8118
- }
8119
- function createSpellCheckPlugin(spellCheck) {
8120
- const spellCheckKey = new PluginKey("spell-check");
8121
- return new Plugin({
8122
- key: spellCheckKey,
8123
- state: {
8124
- init: () => {
8125
- return createSpellCheckPluginState(spellCheck);
8126
- },
8127
- apply: (tr, pluginState) => {
8128
- return pluginState;
8129
- }
8130
- },
8131
- view(view) {
8132
- return spellCheckKey.getState(view.state)?.view(view) || {};
8133
- },
8134
- props: { handleDOMEvents: { beforeinput: (view) => {
8135
- spellCheckKey.getState(view.state)?.pause();
8136
- } } },
8137
- appendTransaction(transactions, state) {
8138
- spellCheckKey.getState(state)?.apply(transactions);
8139
- }
8140
- });
8141
- }
8142
- /**
8143
- * @deprecated This will be removed in future versions.
8144
- */
8145
- function defineSpellCheckPlugin(spellCheck) {
8146
- return definePlugin(createSpellCheckPlugin(spellCheck));
8147
- }
8148
-
8149
8113
  //#endregion
8150
8114
  //#region src/extensions/substitution.ts
8151
8115
  const SUBSTITUTION_RULES = [
@@ -8395,7 +8359,7 @@ var VirtualCaretView = class {
8395
8359
  this.#renderCaret();
8396
8360
  return;
8397
8361
  }
8398
- const nativeRect = findNativeCaretRect(view);
8362
+ const nativeRect = isAfterLineBreak(selection.$head) ? void 0 : findNativeCaretRect(view);
8399
8363
  if (nativeRect && getIsTouchInput()) {
8400
8364
  this.#renderTail();
8401
8365
  this.#renderCaret();
@@ -8647,4 +8611,4 @@ function getVirtualElementFromRange(view, range) {
8647
8611
  }
8648
8612
 
8649
8613
  //#endregion
8650
- export { EDITOR_KEY_BINDINGS, Priority, buildFileMarkdown, checkRoundTrip, codeBlockLanguages, collectReferenceDefinitions, defaultResolveImageUrl, defineBulletAfterHeading, defineCodeBlockPreviewPlugin, defineCodeBlockSyntaxHighlight, defineEditorExtension, defineEmbedPaste, defineExitBoundaryHandler, defineFileClickHandler, defineFilePaste, defineFileView, defineFollowLinkHandler, defineHTMLComment, defineImage, defineImageClickHandler, defineLinkClickHandler, defineLinkCommands, defineLinkEditKeymap, defineLinkHoverHandler, defineLinkPaste, defineMath, definePendingReplacementHandler, definePlaceholder, defineReadonly, defineSearchStatusHandler, defineSpellCheckPlugin, defineSubstitution, defineTagClickHandler, defineViewAttributes, defineVirtualCaret, defineWikilinkClickHandler, defineWikilinkHoverHandler, defineWikilinkTrigger, docToMarkdown, formatFileSize, formatSizedWikiEmbed, getCodeTokens, getFileKind, getIsComposing, getLinkUnitAt, getMarkBuilders, getPendingReplacement, getSearchStatus, getSelectedText, getTableColumnAlign, getTextblockDisplayText, getVirtualElementFromRange, inlineTextToMarkChunks, inlineTextToMarkChunksWithContext, insertLink, isCodeBlockPreviewHiddenDecoration, isMarkOfType, isModEvent, isNodeOfType, isSelectionInTableCell, listenForTweetHeight, loadKaTeX, markdownToDoc, matchEmbed, parseWikiEmbed, removeLink, renderMathInto, updateLink, wikiEmbedBasename, withPriority };
8614
+ export { EDITOR_KEY_BINDINGS, Priority, buildFileMarkdown, checkRoundTrip, codeBlockLanguages, collectReferenceDefinitions, defaultResolveImageUrl, 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, docToMarkdown, formatFileSize, formatSizedWikiEmbed, getCodeTokens, getFileKind, getIsComposing, getLinkUnitAt, getMarkBuilders, getPendingReplacement, getSearchStatus, getSelectedText, getTableColumnAlign, getTextblockDisplayText, getVirtualElementFromRange, inlineTextToMarkChunks, inlineTextToMarkChunksWithContext, insertLink, isCodeBlockPreviewHiddenDecoration, isMarkOfType, isModEvent, isNodeOfType, isSelectionInTableCell, listenForTweetHeight, loadKaTeX, markdownToDoc, matchEmbed, parseWikiEmbed, removeLink, renderMathInto, updateLink, wikiEmbedBasename, withPriority };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meowdown/core",
3
3
  "type": "module",
4
- "version": "0.65.6",
4
+ "version": "0.66.0",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -43,7 +43,7 @@
43
43
  "remark-stringify": "^11.0.0",
44
44
  "unicode-by-name": "^0.2.0",
45
45
  "unified": "^11.0.5",
46
- "@meowdown/markdown": "^0.65.6"
46
+ "@meowdown/markdown": "^0.66.0"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@ocavue/tsconfig": "^0.7.1",