@meowdown/core 0.65.6 → 0.67.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 +1 -0
- package/dist/index.d.ts +71 -17
- package/dist/index.js +321 -179
- package/dist/style.css +4 -0
- package/package.json +7 -7
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
|
@@ -267,27 +267,36 @@ type MdPackAttrs = {
|
|
|
267
267
|
revealInFocus: true;
|
|
268
268
|
revealInHide?: null;
|
|
269
269
|
} | {
|
|
270
|
-
key: 'link';
|
|
270
|
+
key: 'link-inline' | 'link-reference';
|
|
271
271
|
data: {
|
|
272
|
-
form: 'inline' | 'reference';
|
|
273
272
|
href: string;
|
|
274
273
|
title: string;
|
|
275
|
-
}
|
|
276
|
-
|
|
274
|
+
};
|
|
275
|
+
slot?: 1 | null;
|
|
276
|
+
revealInFocus: true;
|
|
277
|
+
revealInHide?: null;
|
|
278
|
+
} | {
|
|
279
|
+
key: 'link-angle';
|
|
280
|
+
data: {
|
|
277
281
|
href: string;
|
|
278
282
|
};
|
|
279
283
|
slot?: 1 | null;
|
|
280
284
|
revealInFocus: true;
|
|
281
285
|
revealInHide?: null;
|
|
282
286
|
} | {
|
|
283
|
-
key: 'link';
|
|
287
|
+
key: 'link-bare';
|
|
284
288
|
data: {
|
|
285
|
-
form: 'bare';
|
|
286
289
|
href: string;
|
|
287
290
|
};
|
|
288
291
|
slot?: 1 | null;
|
|
289
292
|
revealInFocus?: null;
|
|
290
293
|
revealInHide?: null;
|
|
294
|
+
} | {
|
|
295
|
+
key: 'noLink';
|
|
296
|
+
data?: null;
|
|
297
|
+
slot?: 1 | null;
|
|
298
|
+
revealInFocus: true;
|
|
299
|
+
revealInHide?: null;
|
|
291
300
|
} | {
|
|
292
301
|
key: 'math';
|
|
293
302
|
data?: null;
|
|
@@ -364,15 +373,30 @@ export declare function getLinkUnitAt(state: EditorState, pos: number): LinkUnit
|
|
|
364
373
|
interface LinkAttrs {
|
|
365
374
|
href?: string;
|
|
366
375
|
title?: string;
|
|
376
|
+
text?: string;
|
|
367
377
|
}
|
|
378
|
+
/**
|
|
379
|
+
* Normalize a typed URL with the existing autolink logic, else keep it verbatim.
|
|
380
|
+
*/
|
|
381
|
+
export declare function normalizeHref(raw: string): string;
|
|
382
|
+
/**
|
|
383
|
+
* Get a link's plain visible text.
|
|
384
|
+
*/
|
|
385
|
+
export declare function getLinkText(state: EditorState, link: LinkUnit): string;
|
|
386
|
+
/**
|
|
387
|
+
* Whether plain visible link text names the same destination as the link.
|
|
388
|
+
*/
|
|
389
|
+
export declare function isLinkTextForHref(text: string, href: string): boolean;
|
|
368
390
|
interface InsertLinkOptions {
|
|
369
391
|
href?: string;
|
|
370
392
|
title?: string;
|
|
393
|
+
text?: string;
|
|
371
394
|
wrapText?: boolean;
|
|
372
395
|
}
|
|
373
|
-
export declare function insertLink({ href, title, wrapText }?: InsertLinkOptions): Command;
|
|
396
|
+
export declare function insertLink({ href, title, text, wrapText }?: InsertLinkOptions): Command;
|
|
374
397
|
/**
|
|
375
|
-
* Rewrite
|
|
398
|
+
* Rewrite a mutable link. Autolinks are promoted to inline Markdown when
|
|
399
|
+
* their visible text or destination changes.
|
|
376
400
|
*/
|
|
377
401
|
export declare function updateLink(attrs: LinkAttrs): Command;
|
|
378
402
|
/**
|
|
@@ -390,6 +414,7 @@ interface LinkEditOptions {
|
|
|
390
414
|
from: number;
|
|
391
415
|
to: number;
|
|
392
416
|
link: LinkUnit | undefined;
|
|
417
|
+
text: string;
|
|
393
418
|
}
|
|
394
419
|
type LinkEditHandler = (options: LinkEditOptions) => void;
|
|
395
420
|
export declare function defineLinkEditKeymap(onLinkEdit: LinkEditHandler): PlainExtension;
|
|
@@ -793,7 +818,11 @@ declare function defineEditorExtensionImpl(options: EditorExtensionOptions): imp
|
|
|
793
818
|
Marks: {
|
|
794
819
|
mdPack: MdPackAttrs;
|
|
795
820
|
};
|
|
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").
|
|
821
|
+
}>]>, 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<{
|
|
822
|
+
Commands: {
|
|
823
|
+
insertSoftBreak: [];
|
|
824
|
+
};
|
|
825
|
+
}>, 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
826
|
Commands: {
|
|
798
827
|
toggleEm: [];
|
|
799
828
|
toggleStrong: [];
|
|
@@ -1337,6 +1366,7 @@ export declare const EDITOR_KEY_BINDINGS: {
|
|
|
1337
1366
|
readonly 'Mod-5': "Heading 5";
|
|
1338
1367
|
readonly 'Mod-6': "Heading 6";
|
|
1339
1368
|
readonly 'Mod-.': "Fold or unfold a bullet";
|
|
1369
|
+
readonly 'Shift-Enter': "Insert a line break";
|
|
1340
1370
|
readonly 'Mod-Enter': "Follow the link under the caret, or cycle a checkbox task";
|
|
1341
1371
|
readonly 'Mod-Shift-Enter': "Cycle a circle checkbox task";
|
|
1342
1372
|
readonly 'Mod-Shift-7': "Ordered list";
|
|
@@ -1359,7 +1389,21 @@ interface MarkHoverHit<Payload> {
|
|
|
1359
1389
|
//#endregion
|
|
1360
1390
|
//#region src/extensions/link-hover.d.ts
|
|
1361
1391
|
type LinkHoverHandler = (hit: MarkHoverHit<LinkUnit> | undefined) => void;
|
|
1362
|
-
|
|
1392
|
+
interface LinkHoverOptions {
|
|
1393
|
+
/**
|
|
1394
|
+
* Return `false` while the pointer is on the popup the link opened: a
|
|
1395
|
+
* pending leave then re-checks later instead of firing.
|
|
1396
|
+
*/
|
|
1397
|
+
canLeave?: () => boolean;
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* Track the link under the user's attention: a mouse hover after a short
|
|
1401
|
+
* dwell, or a touch tap immediately, since touch has no hover. Without the
|
|
1402
|
+
* tap entry, the popup's preview and actions would stay unreachable on
|
|
1403
|
+
* phones, where a tap on a link only places the caret and raises the
|
|
1404
|
+
* software keyboard.
|
|
1405
|
+
*/
|
|
1406
|
+
export declare function defineLinkHoverHandler(onHoverChange: LinkHoverHandler, { canLeave }?: LinkHoverOptions): PlainExtension;
|
|
1363
1407
|
//#endregion
|
|
1364
1408
|
//#region src/extensions/link-paste.d.ts
|
|
1365
1409
|
/**
|
|
@@ -1377,6 +1421,22 @@ export declare function defineLinkHoverHandler(onHoverChange: LinkHoverHandler):
|
|
|
1377
1421
|
*/
|
|
1378
1422
|
export declare function defineLinkPaste(): PlainExtension;
|
|
1379
1423
|
//#endregion
|
|
1424
|
+
//#region src/extensions/link-preview.d.ts
|
|
1425
|
+
/**
|
|
1426
|
+
* Metadata a host application can supply for a web link.
|
|
1427
|
+
*/
|
|
1428
|
+
interface LinkPreview {
|
|
1429
|
+
readonly title: string;
|
|
1430
|
+
readonly description?: string;
|
|
1431
|
+
readonly iconSrc?: string;
|
|
1432
|
+
}
|
|
1433
|
+
/**
|
|
1434
|
+
* Resolve display metadata for a link, or return `undefined` when unavailable.
|
|
1435
|
+
* Deliberately signal-free to keep the API simple: callers drop stale results
|
|
1436
|
+
* instead of cancelling in-flight work.
|
|
1437
|
+
*/
|
|
1438
|
+
type LinkPreviewResolver = (href: string) => LinkPreview | undefined | Promise<LinkPreview | undefined>;
|
|
1439
|
+
//#endregion
|
|
1380
1440
|
//#region src/extensions/mark-names.d.ts
|
|
1381
1441
|
declare const MARK_NAMES: readonly ["mdWikilink", "mdImage", "mdFile", "mdMath", "mdMark", "mdEm", "mdStrong", "mdCode", "mdLinkText", "mdLinkUri", "mdLinkTitle", "mdDel", "mdHighlight", "mdTag", "mdPack"];
|
|
1382
1442
|
type MarkName = (typeof MARK_NAMES)[number];
|
|
@@ -1396,12 +1456,6 @@ declare const NODE_NAMES: readonly ["doc", "text", "paragraph", "heading", "bloc
|
|
|
1396
1456
|
type NodeName = (typeof NODE_NAMES)[number];
|
|
1397
1457
|
export declare function isNodeOfType(node: ProseMirrorNode, name: NodeName): boolean;
|
|
1398
1458
|
//#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
1459
|
//#region src/extensions/substitution.d.ts
|
|
1406
1460
|
/**
|
|
1407
1461
|
* Apply the editor's automatic plain-text substitutions.
|
|
@@ -1539,4 +1593,4 @@ export declare function getSelectedText(state: EditorState): string;
|
|
|
1539
1593
|
*/
|
|
1540
1594
|
export declare function getVirtualElementFromRange(view: EditorView, range: PositionRange): VirtualElement;
|
|
1541
1595
|
//#endregion
|
|
1542
|
-
export { type AcceptPendingReplacementOptions, type CheckRoundTripOptions, type CodeBlockAttrs, type CodeBlockFenceStyle, type CodeToken, type DocToMarkdownOptions, type EditorExtension, type EditorExtensionOptions, type EmbedDescriptor, type ExitBoundaryHandler, type ExitBoundaryOptions, type FileClickHandler, type FileClickPayload, type FileInfo, type FileInfoResolver, type FileLinkOptions, type FileLinkPayload, type FileLinkResolver, type FilePasteHandler, type FilePasteOptions, type FileSaveErrorHandler, type FileViewOptions, type FollowLinkHandlers, type ImageClickHandler, type ImageClickPayload, type ImageOptions, type InlineMarkContext, type InlineMarkOptions, type KaTeXRender, type LanguageItem, type LinkAttrs, type LinkClickHandler, type LinkClickPayload, type LinkCopyHandler, type LinkCopyPayload, type LinkEditHandler, type LinkEditOptions, type LinkHoverHandler, type LinkUnit, type ListMarker, type MarkChunk, type MarkMode, type MarkName, type MarkdownToDocOptions, type MdFileAttrs, type MdImageAttrs, type MdLinkTextAttrs, type MdMathAttrs, type MdWikilinkAttrs, type MeowdownCodeBlockAttrs, type MeowdownHTMLCommentAttrs, type MeowdownListAttrs, type MeowdownTableCellAttrs, type NodeName, type ParsedWikiEmbed, type PendingReplacement, type PendingReplacementEvent, type PendingReplacementHandler, type PendingReplacementMode, type PendingReplacementOutcome, type PlaceholderOptions, type PositionRange, Priority, type ReferenceDefinition, type ReferenceDefinitionIndex, type ReferenceDefinitions, type RoundTripFidelity, type SearchStatus, type SearchStatusHandler, type StartPendingReplacementOptions, type TableColumnAlign, type TagClickHandler, type TagClickPayload, type TypedEditor, type TypedMarkBuilders, type VirtualElement, type WikiEmbedOptions, type WikiEmbedResolution, type WikiEmbedResolver, type WikilinkClickHandler, type WikilinkClickPayload, type WikilinkHoverHandler, type WikilinkHoverHit, defineCodeBlockPreviewPlugin, definePlaceholder, defineReadonly, defineSearchStatusHandler, getSearchStatus, isCodeBlockPreviewHiddenDecoration, withPriority };
|
|
1596
|
+
export { type AcceptPendingReplacementOptions, type CheckRoundTripOptions, type CodeBlockAttrs, type CodeBlockFenceStyle, type CodeToken, type DocToMarkdownOptions, type EditorExtension, type EditorExtensionOptions, type EmbedDescriptor, type ExitBoundaryHandler, type ExitBoundaryOptions, type FileClickHandler, type FileClickPayload, type FileInfo, type FileInfoResolver, type FileLinkOptions, type FileLinkPayload, type FileLinkResolver, type FilePasteHandler, type FilePasteOptions, type FileSaveErrorHandler, type FileViewOptions, type FollowLinkHandlers, type ImageClickHandler, type ImageClickPayload, type ImageOptions, type InlineMarkContext, type InlineMarkOptions, type KaTeXRender, type LanguageItem, type LinkAttrs, type LinkClickHandler, type LinkClickPayload, type LinkCopyHandler, type LinkCopyPayload, type LinkEditHandler, type LinkEditOptions, type LinkHoverHandler, type LinkHoverOptions, type LinkPreview, type LinkPreviewResolver, type LinkUnit, type ListMarker, type MarkChunk, type MarkMode, type MarkName, type MarkdownToDocOptions, type MdFileAttrs, type MdImageAttrs, type MdLinkTextAttrs, type MdMathAttrs, type MdWikilinkAttrs, type MeowdownCodeBlockAttrs, type MeowdownHTMLCommentAttrs, type MeowdownListAttrs, type MeowdownTableCellAttrs, type NodeName, type ParsedWikiEmbed, type PendingReplacement, type PendingReplacementEvent, type PendingReplacementHandler, type PendingReplacementMode, type PendingReplacementOutcome, type PlaceholderOptions, type PositionRange, Priority, type ReferenceDefinition, type ReferenceDefinitionIndex, type ReferenceDefinitions, type RoundTripFidelity, type SearchStatus, type SearchStatusHandler, type StartPendingReplacementOptions, type TableColumnAlign, type TagClickHandler, type TagClickPayload, type TypedEditor, type TypedMarkBuilders, type VirtualElement, type WikiEmbedOptions, type WikiEmbedResolution, type WikiEmbedResolver, type WikilinkClickHandler, type WikilinkClickPayload, type WikilinkHoverHandler, type WikilinkHoverHit, defineCodeBlockPreviewPlugin, definePlaceholder, defineReadonly, defineSearchStatusHandler, getSearchStatus, isCodeBlockPreviewHiddenDecoration, withPriority };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Priority, Priority as Priority$1, createMarkBuilders, createNodeBuilders, defineBaseCommands, defineBaseKeymap, defineClipboardSerializer, defineCommands, defineHistory, defineKeymap, defineMarkSpec, defineMarkView, defineNodeAttr, defineNodeSpec, definePlugin, getMarkRange, getMarkType, getNodeType, isAllSelection, isApple, isAtBlockStart, isNodeSelection, isTextSelection, setBlockType, toggleNode, union, unsetBlockType, withPriority, withPriority as withPriority$1, withSkipCodeBlock } from "@prosekit/core";
|
|
1
|
+
import { Priority, Priority as Priority$1, createMarkBuilders, createNodeBuilders, defineBaseCommands, defineBaseKeymap, defineClipboardSerializer, defineCommands, defineHistory, defineKeymap, defineMarkSpec, defineMarkView, defineNodeAttr, defineNodeSpec, definePlugin, findMarkRange, getMarkRange, getMarkType, getNodeType, isAllSelection, isApple, isAtBlockStart, isNodeSelection, isTextSelection, setBlockType, toggleNode, union, unsetBlockType, withPriority, withPriority as withPriority$1, withSkipCodeBlock } from "@prosekit/core";
|
|
2
2
|
import { defineCodeBlock, defineCodeBlockHighlight, defineCodeBlockPreviewPlugin, isCodeBlockPreviewHiddenDecoration } from "@prosekit/extensions/code-block";
|
|
3
3
|
import { definePlaceholder } from "@prosekit/extensions/placeholder";
|
|
4
4
|
import { defineReadonly } from "@prosekit/extensions/readonly";
|
|
@@ -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 {
|
|
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";
|
|
@@ -354,13 +354,13 @@ function resolvePosition(state, pos) {
|
|
|
354
354
|
}
|
|
355
355
|
/**
|
|
356
356
|
* Returns the run of the mark covering `pos`, or `undefined` when none covers
|
|
357
|
-
* it. `
|
|
358
|
-
*
|
|
357
|
+
* it. `predicate` narrows the match to marks it accepts, which is how a
|
|
358
|
+
* caller picks one level out of a nested stack of the same mark.
|
|
359
359
|
*/
|
|
360
|
-
function getMarkRangeAt(state, pos, markName,
|
|
360
|
+
function getMarkRangeAt(state, pos, markName, predicate) {
|
|
361
361
|
const $pos = resolvePosition(state, pos);
|
|
362
362
|
if (!$pos) return;
|
|
363
|
-
return ATOM_MARK_NAMES.includes(markName) ? getAtomUnitRange(state, $pos, markName) :
|
|
363
|
+
return ATOM_MARK_NAMES.includes(markName) ? getAtomUnitRange(state, $pos, markName) : findMarkRange($pos, (mark) => isMarkOfType(mark, markName) && (!predicate || predicate(mark)));
|
|
364
364
|
}
|
|
365
365
|
/**
|
|
366
366
|
* The range of the atom unit touching `$pos`, preferring the child to the
|
|
@@ -368,7 +368,7 @@ function getMarkRangeAt(state, pos, markName, attrs) {
|
|
|
368
368
|
* marks, so eq-based expansion would run across both; the unit boundary comes
|
|
369
369
|
* from the innermost pack instead, which `slot` keeps distinct. A text node
|
|
370
370
|
* without a pack (a document not produced by the inline parser) falls back to
|
|
371
|
-
* the eq-based range. Does not support `
|
|
371
|
+
* the eq-based range. Does not support `predicate` filtering.
|
|
372
372
|
*/
|
|
373
373
|
function getAtomUnitRange(state, $pos, name) {
|
|
374
374
|
const parent = $pos.parent;
|
|
@@ -2843,10 +2843,12 @@ function parseMagicComment(comment) {
|
|
|
2843
2843
|
if (!isObject(data)) return;
|
|
2844
2844
|
const width = toPositiveNumber(data.width);
|
|
2845
2845
|
const height = toPositiveNumber(data.height);
|
|
2846
|
-
|
|
2846
|
+
const noLink = data.noLink === true ? true : void 0;
|
|
2847
|
+
if (!width && !height && !noLink) return;
|
|
2847
2848
|
return {
|
|
2848
2849
|
width,
|
|
2849
|
-
height
|
|
2850
|
+
height,
|
|
2851
|
+
noLink
|
|
2850
2852
|
};
|
|
2851
2853
|
}
|
|
2852
2854
|
function toPositiveNumber(value) {
|
|
@@ -3185,6 +3187,14 @@ function walk(nodes, parentMarks, rangeStart, rangeEnd, text, marks, out, option
|
|
|
3185
3187
|
pos = atomEnd;
|
|
3186
3188
|
continue;
|
|
3187
3189
|
}
|
|
3190
|
+
if (node.type === LEZER_NODE_IDS.URL) {
|
|
3191
|
+
const trailing = takeMagicComments(nodes, index, text);
|
|
3192
|
+
if (trailing?.magic.noLink) {
|
|
3193
|
+
walkUnlinkedURL(node, trailing, parentMarks, marks, out);
|
|
3194
|
+
pos = trailing.to;
|
|
3195
|
+
continue;
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3188
3198
|
walkNode(node, parentMarks, text, marks, out, options, context);
|
|
3189
3199
|
pos = node.to;
|
|
3190
3200
|
}
|
|
@@ -3251,11 +3261,8 @@ function walkAutolink(node, parentMarks, text, marks, out) {
|
|
|
3251
3261
|
const urlNode = node.children.find((child) => child.type === LEZER_NODE_IDS.URL);
|
|
3252
3262
|
const href = urlNode ? getAutolinkHref(text.slice(urlNode.from, urlNode.to)) ?? "" : "";
|
|
3253
3263
|
const base = [...parentMarks, createUnitPack(marks, out, parentMarks, node.from, {
|
|
3254
|
-
key: "link",
|
|
3255
|
-
data: {
|
|
3256
|
-
form: "angle",
|
|
3257
|
-
href
|
|
3258
|
-
},
|
|
3264
|
+
key: "link-angle",
|
|
3265
|
+
data: { href },
|
|
3259
3266
|
revealInFocus: true
|
|
3260
3267
|
})];
|
|
3261
3268
|
let pos = node.from;
|
|
@@ -3282,15 +3289,26 @@ function walkURL(node, parentMarks, text, marks, out) {
|
|
|
3282
3289
|
emit(out, node.from, node.to, [
|
|
3283
3290
|
...parentMarks,
|
|
3284
3291
|
createUnitPack(marks, out, parentMarks, node.from, {
|
|
3285
|
-
key: "link",
|
|
3286
|
-
data: {
|
|
3287
|
-
form: "bare",
|
|
3288
|
-
href
|
|
3289
|
-
}
|
|
3292
|
+
key: "link-bare",
|
|
3293
|
+
data: { href }
|
|
3290
3294
|
}),
|
|
3291
3295
|
marks.mdLinkText.create({ href })
|
|
3292
3296
|
]);
|
|
3293
3297
|
}
|
|
3298
|
+
/**
|
|
3299
|
+
* A URL followed directly by a `<!-- {"noLink":true} -->` magic comment
|
|
3300
|
+
* stays plain text instead of autolinking. The comment rides behind the
|
|
3301
|
+
* address as hidden syntax that reveals in focus, so it can be edited or
|
|
3302
|
+
* deleted in place.
|
|
3303
|
+
*/
|
|
3304
|
+
function walkUnlinkedURL(node, trailing, parentMarks, marks, out) {
|
|
3305
|
+
const base = [...parentMarks, createUnitPack(marks, out, parentMarks, node.from, {
|
|
3306
|
+
key: "noLink",
|
|
3307
|
+
revealInFocus: true
|
|
3308
|
+
})];
|
|
3309
|
+
emit(out, node.from, node.to, base);
|
|
3310
|
+
emit(out, node.to, trailing.to, [...base, marks.mdMark.create()]);
|
|
3311
|
+
}
|
|
3294
3312
|
function walkLink(node, parentMarks, text, marks, out, options, context) {
|
|
3295
3313
|
const parts = scanLinkParts(node);
|
|
3296
3314
|
const resolution = resolveLink(parts, text, context);
|
|
@@ -3432,9 +3450,8 @@ function walkResolvedLink(node, parts, resolution, parentMarks, text, marks, out
|
|
|
3432
3450
|
const linkTextMark = marks.mdLinkText.create({ href });
|
|
3433
3451
|
const inLabel = (pos) => labelEnd >= 0 && pos < labelEnd;
|
|
3434
3452
|
const pack = createUnitPack(marks, out, parentMarks, node.from, {
|
|
3435
|
-
key: "link",
|
|
3453
|
+
key: isReference ? "link-reference" : "link-inline",
|
|
3436
3454
|
data: {
|
|
3437
|
-
form: isReference ? "reference" : "inline",
|
|
3438
3455
|
href,
|
|
3439
3456
|
title
|
|
3440
3457
|
},
|
|
@@ -3475,9 +3492,9 @@ function walkResolvedLink(node, parts, resolution, parentMarks, text, marks, out
|
|
|
3475
3492
|
}
|
|
3476
3493
|
/**
|
|
3477
3494
|
* The run of magic comments chained immediately behind `nodes[index]` (an
|
|
3478
|
-
* image), or undefined when no magic comment directly abuts it. The
|
|
3479
|
-
* comment's data wins: a rewrite of an unfolded image inserted the
|
|
3480
|
-
* comment right at the image's end, so in a stacked run left is newest.
|
|
3495
|
+
* image or a URL), or undefined when no magic comment directly abuts it. The
|
|
3496
|
+
* first comment's data wins: a rewrite of an unfolded image inserted the
|
|
3497
|
+
* fresh comment right at the image's end, so in a stacked run left is newest.
|
|
3481
3498
|
*/
|
|
3482
3499
|
function takeMagicComments(nodes, index, text) {
|
|
3483
3500
|
let magic;
|
|
@@ -4496,32 +4513,32 @@ function lastMarkRunIn(state, range, markName) {
|
|
|
4496
4513
|
* the `mdLinkUri` run locates the `( )` body.
|
|
4497
4514
|
*/
|
|
4498
4515
|
function getLinkUnitAt(state, pos) {
|
|
4499
|
-
const unit = getMarkRangeAt(state, pos, "mdPack",
|
|
4516
|
+
const unit = getMarkRangeAt(state, pos, "mdPack", (mark) => mark.attrs.key.startsWith("link-"));
|
|
4500
4517
|
if (!unit) return;
|
|
4501
|
-
const
|
|
4518
|
+
const attrs = unit.mark.attrs;
|
|
4502
4519
|
const unitRange = {
|
|
4503
4520
|
from: unit.from,
|
|
4504
4521
|
to: unit.to
|
|
4505
4522
|
};
|
|
4506
|
-
switch (
|
|
4507
|
-
case "bare": return {
|
|
4523
|
+
switch (attrs.key) {
|
|
4524
|
+
case "link-bare": return {
|
|
4508
4525
|
form: "bare",
|
|
4509
4526
|
unit: unitRange,
|
|
4510
4527
|
text: unitRange,
|
|
4511
|
-
href: data.href,
|
|
4528
|
+
href: attrs.data.href,
|
|
4512
4529
|
title: ""
|
|
4513
4530
|
};
|
|
4514
|
-
case "angle": return {
|
|
4531
|
+
case "link-angle": return {
|
|
4515
4532
|
form: "angle",
|
|
4516
4533
|
unit: unitRange,
|
|
4517
4534
|
text: {
|
|
4518
4535
|
from: unit.from + 1,
|
|
4519
4536
|
to: unit.to - 1
|
|
4520
4537
|
},
|
|
4521
|
-
href: data.href,
|
|
4538
|
+
href: attrs.data.href,
|
|
4522
4539
|
title: ""
|
|
4523
4540
|
};
|
|
4524
|
-
case "reference": {
|
|
4541
|
+
case "link-reference": {
|
|
4525
4542
|
const linkText = getMarkRangeAt(state, pos, "mdLinkText");
|
|
4526
4543
|
return {
|
|
4527
4544
|
form: "reference",
|
|
@@ -4530,11 +4547,11 @@ function getLinkUnitAt(state, pos) {
|
|
|
4530
4547
|
from: linkText.from + 1,
|
|
4531
4548
|
to: linkText.to
|
|
4532
4549
|
},
|
|
4533
|
-
href: data.href,
|
|
4534
|
-
title: data.title
|
|
4550
|
+
href: attrs.data.href,
|
|
4551
|
+
title: attrs.data.title
|
|
4535
4552
|
};
|
|
4536
4553
|
}
|
|
4537
|
-
case "inline": {
|
|
4554
|
+
case "link-inline": {
|
|
4538
4555
|
const uri = lastMarkRunIn(state, unitRange, "mdLinkUri");
|
|
4539
4556
|
const closeBracket = uri ? uri.from - 2 : unit.to - 3;
|
|
4540
4557
|
const destFrom = uri ? uri.from : unit.to - 1;
|
|
@@ -4551,8 +4568,8 @@ function getLinkUnitAt(state, pos) {
|
|
|
4551
4568
|
from: destFrom,
|
|
4552
4569
|
to: unit.to - 1
|
|
4553
4570
|
},
|
|
4554
|
-
href: data.href,
|
|
4555
|
-
title: data.title
|
|
4571
|
+
href: attrs.data.href,
|
|
4572
|
+
title: attrs.data.title
|
|
4556
4573
|
};
|
|
4557
4574
|
}
|
|
4558
4575
|
}
|
|
@@ -4574,6 +4591,39 @@ function destText(href, title) {
|
|
|
4574
4591
|
return href + (title ? ` "${title.replaceAll(/(["\\])/g, String.raw`\$1`)}"` : "");
|
|
4575
4592
|
}
|
|
4576
4593
|
/**
|
|
4594
|
+
* Escape a plain-text label so it cannot pick up inline semantics: the
|
|
4595
|
+
* CommonMark delimiters plus meowdown's `==highlight==`, `$math$`, and `#tag`.
|
|
4596
|
+
*/
|
|
4597
|
+
function linkLabelText(text) {
|
|
4598
|
+
return text.replaceAll(/([&<\\[\]_*`~=$#])/g, String.raw`\$1`);
|
|
4599
|
+
}
|
|
4600
|
+
/**
|
|
4601
|
+
* Get a range's plain visible text, skipping hidden syntax runs.
|
|
4602
|
+
*/
|
|
4603
|
+
function getVisibleText(state, range) {
|
|
4604
|
+
let text = "";
|
|
4605
|
+
state.doc.nodesBetween(range.from, range.to, (node, pos) => {
|
|
4606
|
+
if (!node.isText || !node.text || hasSyntaxMark(node.marks)) return;
|
|
4607
|
+
const from = Math.max(range.from, pos) - pos;
|
|
4608
|
+
const to = Math.min(range.to, pos + node.nodeSize) - pos;
|
|
4609
|
+
text += node.text.slice(from, to);
|
|
4610
|
+
});
|
|
4611
|
+
return text;
|
|
4612
|
+
}
|
|
4613
|
+
/**
|
|
4614
|
+
* Get a link's plain visible text.
|
|
4615
|
+
*/
|
|
4616
|
+
function getLinkText(state, link) {
|
|
4617
|
+
return getVisibleText(state, link.text);
|
|
4618
|
+
}
|
|
4619
|
+
/**
|
|
4620
|
+
* Whether plain visible link text names the same destination as the link.
|
|
4621
|
+
*/
|
|
4622
|
+
function isLinkTextForHref(text, href) {
|
|
4623
|
+
const value = text.trim();
|
|
4624
|
+
return value === href || getAutolinkHref(value) === href;
|
|
4625
|
+
}
|
|
4626
|
+
/**
|
|
4577
4627
|
* The range a new link would wrap: the current selection when it is a
|
|
4578
4628
|
* non-empty text selection inside a single non-code textblock, trimmed of
|
|
4579
4629
|
* surrounding whitespace. `undefined` when there is nothing to wrap.
|
|
@@ -4592,16 +4642,24 @@ function getWrapRange(state) {
|
|
|
4592
4642
|
to: base + to
|
|
4593
4643
|
};
|
|
4594
4644
|
}
|
|
4595
|
-
function insertLink({ href, title, wrapText = true } = {}) {
|
|
4645
|
+
function insertLink({ href, title, text, wrapText = true } = {}) {
|
|
4596
4646
|
return (state, dispatch) => {
|
|
4597
4647
|
const range = getWrapRange(state);
|
|
4598
4648
|
if (!range) return false;
|
|
4599
4649
|
if (dispatch) {
|
|
4600
4650
|
const { from, to } = range;
|
|
4601
4651
|
const tr = state.tr;
|
|
4602
|
-
const
|
|
4603
|
-
|
|
4604
|
-
|
|
4652
|
+
const dest = destText(normalizeHref(href ?? ""), title ?? "");
|
|
4653
|
+
let linkTo;
|
|
4654
|
+
if (text !== void 0 && text !== getVisibleText(state, range)) {
|
|
4655
|
+
const markdown = `[${linkLabelText(text)}](${dest})`;
|
|
4656
|
+
tr.insertText(markdown, from, to);
|
|
4657
|
+
linkTo = from + markdown.length;
|
|
4658
|
+
} else {
|
|
4659
|
+
const close = `](${dest})`;
|
|
4660
|
+
tr.insertText(close, to).insertText("[", from);
|
|
4661
|
+
linkTo = to + 1 + close.length;
|
|
4662
|
+
}
|
|
4605
4663
|
tr.setSelection(wrapText ? TextSelection.create(tr.doc, from, linkTo) : TextSelection.create(tr.doc, linkTo));
|
|
4606
4664
|
tr.scrollIntoView();
|
|
4607
4665
|
dispatch(tr);
|
|
@@ -4610,14 +4668,18 @@ function insertLink({ href, title, wrapText = true } = {}) {
|
|
|
4610
4668
|
};
|
|
4611
4669
|
}
|
|
4612
4670
|
/**
|
|
4613
|
-
* Rewrite
|
|
4671
|
+
* Rewrite a mutable link. Autolinks are promoted to inline Markdown when
|
|
4672
|
+
* their visible text or destination changes.
|
|
4614
4673
|
*/
|
|
4615
4674
|
function updateLink(attrs) {
|
|
4616
4675
|
return (state, dispatch) => {
|
|
4617
4676
|
const link = getLinkUnitAt(state, state.selection.from);
|
|
4618
|
-
if (link
|
|
4619
|
-
const
|
|
4620
|
-
|
|
4677
|
+
if (!link || link.form === "reference") return false;
|
|
4678
|
+
const href = normalizeHref(attrs.href ?? link.href);
|
|
4679
|
+
const title = attrs.title ?? link.title;
|
|
4680
|
+
const text = attrs.text ?? getLinkText(state, link);
|
|
4681
|
+
const replacingUnit = attrs.text !== void 0 || link.form !== "inline";
|
|
4682
|
+
if (dispatch) dispatch((replacingUnit ? state.tr.insertText(`[${linkLabelText(text)}](${destText(href, title)})`, link.unit.from, link.unit.to) : state.tr.insertText(destText(href, title), link.dest.from, link.dest.to)).scrollIntoView());
|
|
4621
4683
|
return true;
|
|
4622
4684
|
};
|
|
4623
4685
|
}
|
|
@@ -4627,8 +4689,11 @@ function updateLink(attrs) {
|
|
|
4627
4689
|
function removeLink() {
|
|
4628
4690
|
return (state, dispatch) => {
|
|
4629
4691
|
const link = getLinkUnitAt(state, state.selection.from);
|
|
4630
|
-
if (link
|
|
4631
|
-
if (dispatch)
|
|
4692
|
+
if (!link || link.form === "reference") return false;
|
|
4693
|
+
if (dispatch) {
|
|
4694
|
+
const text = getLinkText(state, link);
|
|
4695
|
+
dispatch((link.form === "inline" && !getAutolinkHref(text) ? state.tr.delete(link.label.to, link.unit.to).delete(link.unit.from, link.label.from) : state.tr.insertText(text + formatMagicComment({ noLink: true }), link.unit.from, link.unit.to)).scrollIntoView());
|
|
4696
|
+
}
|
|
4632
4697
|
return true;
|
|
4633
4698
|
};
|
|
4634
4699
|
}
|
|
@@ -4643,7 +4708,7 @@ function openLinkEdit(onLinkEdit) {
|
|
|
4643
4708
|
return (state, dispatch, view) => {
|
|
4644
4709
|
const link = getLinkUnitAt(state, state.selection.from);
|
|
4645
4710
|
if (link) {
|
|
4646
|
-
if (link.form
|
|
4711
|
+
if (link.form === "reference") return false;
|
|
4647
4712
|
if (dispatch && view) {
|
|
4648
4713
|
const { unit: { from, to } } = link;
|
|
4649
4714
|
dispatch(state.tr.setSelection(TextSelection.create(state.doc, from, to)).scrollIntoView());
|
|
@@ -4651,7 +4716,8 @@ function openLinkEdit(onLinkEdit) {
|
|
|
4651
4716
|
onLinkEdit({
|
|
4652
4717
|
from,
|
|
4653
4718
|
to,
|
|
4654
|
-
link
|
|
4719
|
+
link,
|
|
4720
|
+
text: getLinkText(state, link)
|
|
4655
4721
|
});
|
|
4656
4722
|
}
|
|
4657
4723
|
return true;
|
|
@@ -4665,7 +4731,8 @@ function openLinkEdit(onLinkEdit) {
|
|
|
4665
4731
|
onLinkEdit({
|
|
4666
4732
|
from,
|
|
4667
4733
|
to,
|
|
4668
|
-
link: void 0
|
|
4734
|
+
link: void 0,
|
|
4735
|
+
text: getVisibleText(state, wrapRange)
|
|
4669
4736
|
});
|
|
4670
4737
|
}
|
|
4671
4738
|
return true;
|
|
@@ -5672,6 +5739,13 @@ function tryCoordsAtPos(view, pos, side) {
|
|
|
5672
5739
|
return isPointRect(coords) ? void 0 : coords;
|
|
5673
5740
|
}
|
|
5674
5741
|
|
|
5742
|
+
//#endregion
|
|
5743
|
+
//#region src/utils/line-break.ts
|
|
5744
|
+
function isAfterLineBreak($pos) {
|
|
5745
|
+
const { parentOffset, parent } = $pos;
|
|
5746
|
+
return parentOffset > 0 && parent.textBetween(parentOffset - 1, parentOffset) === "\n";
|
|
5747
|
+
}
|
|
5748
|
+
|
|
5675
5749
|
//#endregion
|
|
5676
5750
|
//#region src/extensions/caret-rect.ts
|
|
5677
5751
|
function findNativeCaretRect(view) {
|
|
@@ -5691,11 +5765,10 @@ function findNativeCaretRect(view) {
|
|
|
5691
5765
|
}
|
|
5692
5766
|
function findCoordsCaretRect(view) {
|
|
5693
5767
|
const state = view.state;
|
|
5694
|
-
const head = state.selection
|
|
5768
|
+
const { head, $head } = state.selection;
|
|
5695
5769
|
const runBefore = getHiddenRunBefore(state, head);
|
|
5696
5770
|
const runAfter = getHiddenRunAfter(state, head);
|
|
5697
|
-
const
|
|
5698
|
-
const afterLineBreak = $head.parentOffset > 0 && $head.parent.textBetween($head.parentOffset - 1, $head.parentOffset) === "\n";
|
|
5771
|
+
const afterLineBreak = isAfterLineBreak($head);
|
|
5699
5772
|
const preferredBeforeSide = runBefore == null && !afterLineBreak;
|
|
5700
5773
|
const probes = [[head, preferredBeforeSide], [head, !preferredBeforeSide]];
|
|
5701
5774
|
if (runBefore != null) probes.push([runBefore.from, true]);
|
|
@@ -5891,6 +5964,55 @@ function defineSelectDocBoundary() {
|
|
|
5891
5964
|
});
|
|
5892
5965
|
}
|
|
5893
5966
|
|
|
5967
|
+
//#endregion
|
|
5968
|
+
//#region src/extensions/soft-break.ts
|
|
5969
|
+
function canHoldSoftBreak($pos) {
|
|
5970
|
+
if (!isNodeOfType($pos.parent, "paragraph")) return false;
|
|
5971
|
+
const container = $pos.depth > 0 ? $pos.node($pos.depth - 1) : void 0;
|
|
5972
|
+
if (container == null) return true;
|
|
5973
|
+
return !isNodeOfType(container, "tableCell") && !isNodeOfType(container, "tableHeaderCell");
|
|
5974
|
+
}
|
|
5975
|
+
const splitBlockOnEnter = chainCommands(enterCommand, splitBlock);
|
|
5976
|
+
function isBeforeLineBreak($pos) {
|
|
5977
|
+
const { parentOffset, parent } = $pos;
|
|
5978
|
+
return parentOffset < parent.content.size && parent.textBetween(parentOffset, parentOffset + 1) === "\n";
|
|
5979
|
+
}
|
|
5980
|
+
const splitPendingSoftBreak = (state, dispatch, view) => {
|
|
5981
|
+
const { $from, empty } = state.selection;
|
|
5982
|
+
if (!empty || !canHoldSoftBreak($from)) return false;
|
|
5983
|
+
const inFront = isAfterLineBreak($from);
|
|
5984
|
+
if (!inFront && !isBeforeLineBreak($from)) return false;
|
|
5985
|
+
let split;
|
|
5986
|
+
if (!splitBlockOnEnter(state, (candidate) => {
|
|
5987
|
+
split = candidate;
|
|
5988
|
+
}, view) || split == null) return false;
|
|
5989
|
+
if (dispatch == null) return true;
|
|
5990
|
+
const start = inFront ? $from.pos - 1 : $from.pos;
|
|
5991
|
+
const side = inFront ? -1 : 1;
|
|
5992
|
+
const from = split.mapping.map(start, side);
|
|
5993
|
+
const to = split.mapping.map(start + 1, side);
|
|
5994
|
+
dispatch(split.delete(from, to).scrollIntoView());
|
|
5995
|
+
return true;
|
|
5996
|
+
};
|
|
5997
|
+
const insertSoftBreakText = (state, dispatch) => {
|
|
5998
|
+
if (!canHoldSoftBreak(state.selection.$from)) return false;
|
|
5999
|
+
dispatch?.(state.tr.insertText("\n").scrollIntoView());
|
|
6000
|
+
return true;
|
|
6001
|
+
};
|
|
6002
|
+
const softBreakCommand = chainCommands(newlineInCode, splitPendingSoftBreak, insertSoftBreakText);
|
|
6003
|
+
/**
|
|
6004
|
+
* Insert a markdown soft line break at the caret: a literal `\n` in the
|
|
6005
|
+
* paragraph's text. In a code block it writes the newline plain Enter writes
|
|
6006
|
+
* there. On a caret that already sits beside a soft break it splits the block
|
|
6007
|
+
* instead, because a paragraph cannot hold a blank line.
|
|
6008
|
+
*/
|
|
6009
|
+
function insertSoftBreak() {
|
|
6010
|
+
return softBreakCommand;
|
|
6011
|
+
}
|
|
6012
|
+
function defineSoftBreak() {
|
|
6013
|
+
return union(defineCommands({ insertSoftBreak }), defineKeymap({ "Shift-Enter": softBreakCommand }));
|
|
6014
|
+
}
|
|
6015
|
+
|
|
5894
6016
|
//#endregion
|
|
5895
6017
|
//#region src/extensions/system-substitution-guard.ts
|
|
5896
6018
|
const EM_DASH = "—";
|
|
@@ -5932,7 +6054,7 @@ function defineViewAttributes(attributes) {
|
|
|
5932
6054
|
//#endregion
|
|
5933
6055
|
//#region src/extensions/extension.ts
|
|
5934
6056
|
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) => ({
|
|
6057
|
+
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
6058
|
name,
|
|
5937
6059
|
modes: [
|
|
5938
6060
|
"hide",
|
|
@@ -7885,6 +8007,7 @@ const EDITOR_KEY_BINDINGS = {
|
|
|
7885
8007
|
"Mod-5": "Heading 5",
|
|
7886
8008
|
"Mod-6": "Heading 6",
|
|
7887
8009
|
"Mod-.": "Fold or unfold a bullet",
|
|
8010
|
+
"Shift-Enter": "Insert a line break",
|
|
7888
8011
|
"Mod-Enter": "Follow the link under the caret, or cycle a checkbox task",
|
|
7889
8012
|
"Mod-Shift-Enter": "Cycle a circle checkbox task",
|
|
7890
8013
|
"Mod-Shift-7": "Ordered list",
|
|
@@ -7930,36 +8053,98 @@ function defineLinkClickHandler(onClick) {
|
|
|
7930
8053
|
* after every editor update, so deleting, replacing, or rewriting a hovered
|
|
7931
8054
|
* mark emits leave even when the pointer itself never moves. Destroying the
|
|
7932
8055
|
* editor or removing the extension emits leave as well.
|
|
8056
|
+
*
|
|
8057
|
+
* With `tap`, a touch tap enters too. The browser is the tap recognizer:
|
|
8058
|
+
* only a recognized stationary single-finger tap synthesizes the
|
|
8059
|
+
* compatibility mouse events and the trailing `click`; scrolls, drags,
|
|
8060
|
+
* long-presses, and multi-finger gestures never produce them.
|
|
7933
8061
|
*/
|
|
7934
8062
|
function defineMarkHoverHandler(config) {
|
|
7935
|
-
|
|
8063
|
+
const { openDelay, closeDelay, tap } = config;
|
|
8064
|
+
/**
|
|
8065
|
+
* What `onHoverChange` last received, while that is a hit.
|
|
8066
|
+
*/
|
|
8067
|
+
let emitted;
|
|
8068
|
+
let timer;
|
|
8069
|
+
/**
|
|
8070
|
+
* The element of a scheduled enter, `null` for a scheduled leave,
|
|
8071
|
+
* `undefined` when nothing is scheduled.
|
|
8072
|
+
*/
|
|
8073
|
+
let scheduledElement;
|
|
8074
|
+
/**
|
|
8075
|
+
* The type of the pointer that spawned the current event sequence:
|
|
8076
|
+
* compatibility mouse events carry no pointer type of their own.
|
|
8077
|
+
*/
|
|
8078
|
+
let lastPointerType = "";
|
|
8079
|
+
const findClosestMark = (target) => {
|
|
8080
|
+
return isElementLike(target) ? target.closest(config.selector) : null;
|
|
8081
|
+
};
|
|
7936
8082
|
const findPayloadForElement = (view, element) => {
|
|
7937
8083
|
return config.findPayloadForElement ? config.findPayloadForElement(view, element) : config.findPayloadAt(view.state, view.posAtDOM(element, 0));
|
|
7938
8084
|
};
|
|
7939
|
-
const
|
|
7940
|
-
|
|
7941
|
-
|
|
7942
|
-
config.onHoverChange(void 0);
|
|
8085
|
+
const cancel = () => {
|
|
8086
|
+
clearTimeout(timer);
|
|
8087
|
+
scheduledElement = void 0;
|
|
7943
8088
|
};
|
|
7944
|
-
const
|
|
7945
|
-
|
|
7946
|
-
if (!
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
|
|
8089
|
+
const emit = (hit) => {
|
|
8090
|
+
cancel();
|
|
8091
|
+
if (!hit && !emitted) return;
|
|
8092
|
+
emitted = hit;
|
|
8093
|
+
config.onHoverChange(hit);
|
|
8094
|
+
};
|
|
8095
|
+
const scheduleLeave = () => {
|
|
8096
|
+
cancel();
|
|
8097
|
+
scheduledElement = null;
|
|
8098
|
+
const fire = () => {
|
|
8099
|
+
if (config.canLeave?.() === false) {
|
|
8100
|
+
timer = setTimeout(fire, closeDelay);
|
|
8101
|
+
return;
|
|
8102
|
+
}
|
|
8103
|
+
emit(void 0);
|
|
8104
|
+
};
|
|
8105
|
+
timer = setTimeout(fire, closeDelay);
|
|
8106
|
+
};
|
|
8107
|
+
const enter = (view, element) => {
|
|
7950
8108
|
const payload = findPayloadForElement(view, element);
|
|
7951
8109
|
if (payload == null) return;
|
|
7952
|
-
|
|
7953
|
-
|
|
7954
|
-
|
|
7955
|
-
|
|
7956
|
-
|
|
8110
|
+
if (emitted) {
|
|
8111
|
+
emit({
|
|
8112
|
+
payload,
|
|
8113
|
+
element
|
|
8114
|
+
});
|
|
8115
|
+
return;
|
|
8116
|
+
}
|
|
8117
|
+
cancel();
|
|
8118
|
+
scheduledElement = element;
|
|
8119
|
+
timer = setTimeout(() => {
|
|
8120
|
+
const fresh = element.isConnected ? findPayloadForElement(view, element) : void 0;
|
|
8121
|
+
if (fresh == null) {
|
|
8122
|
+
cancel();
|
|
8123
|
+
return;
|
|
8124
|
+
}
|
|
8125
|
+
emit({
|
|
8126
|
+
payload: fresh,
|
|
8127
|
+
element
|
|
8128
|
+
});
|
|
8129
|
+
}, openDelay);
|
|
8130
|
+
};
|
|
8131
|
+
const handleOver = (view, event) => {
|
|
8132
|
+
const element = findClosestMark(event.target);
|
|
8133
|
+
if (!element || !view.dom.contains(element)) return;
|
|
8134
|
+
if (element === emitted?.element) {
|
|
8135
|
+
if (scheduledElement === null) cancel();
|
|
8136
|
+
return;
|
|
8137
|
+
}
|
|
8138
|
+
if (element === scheduledElement) return;
|
|
8139
|
+
enter(view, element);
|
|
7957
8140
|
};
|
|
7958
8141
|
const handleOut = (event) => {
|
|
7959
|
-
|
|
8142
|
+
const active = emitted?.element ?? scheduledElement;
|
|
8143
|
+
if (!active) return;
|
|
7960
8144
|
const related = event.relatedTarget;
|
|
7961
|
-
if (related instanceof Node &&
|
|
7962
|
-
|
|
8145
|
+
if (related instanceof Node && active.contains(related)) return;
|
|
8146
|
+
if (emitted) scheduleLeave();
|
|
8147
|
+
else cancel();
|
|
7963
8148
|
};
|
|
7964
8149
|
return definePlugin(new Plugin({
|
|
7965
8150
|
key: config.key,
|
|
@@ -7971,26 +8156,52 @@ function defineMarkHoverHandler(config) {
|
|
|
7971
8156
|
mouseout: (_view, event) => {
|
|
7972
8157
|
handleOut(event);
|
|
7973
8158
|
return false;
|
|
8159
|
+
},
|
|
8160
|
+
...tap && {
|
|
8161
|
+
pointerdown: (_view, event) => {
|
|
8162
|
+
lastPointerType = event.pointerType;
|
|
8163
|
+
return false;
|
|
8164
|
+
},
|
|
8165
|
+
mousedown: (_view, event) => {
|
|
8166
|
+
if (lastPointerType !== "touch" || !findClosestMark(event.target)) return false;
|
|
8167
|
+
event.preventDefault();
|
|
8168
|
+
return true;
|
|
8169
|
+
},
|
|
8170
|
+
click: (view, event) => {
|
|
8171
|
+
if (lastPointerType !== "touch") return false;
|
|
8172
|
+
const element = findClosestMark(event.target);
|
|
8173
|
+
if (!element || !view.dom.contains(element)) {
|
|
8174
|
+
emit(void 0);
|
|
8175
|
+
return false;
|
|
8176
|
+
}
|
|
8177
|
+
event.preventDefault();
|
|
8178
|
+
const payload = findPayloadForElement(view, element);
|
|
8179
|
+
if (payload != null) emit({
|
|
8180
|
+
payload,
|
|
8181
|
+
element
|
|
8182
|
+
});
|
|
8183
|
+
return true;
|
|
8184
|
+
}
|
|
7974
8185
|
}
|
|
7975
8186
|
} },
|
|
7976
8187
|
view: () => ({
|
|
7977
8188
|
update: (view) => {
|
|
7978
|
-
if (!
|
|
7979
|
-
if (!
|
|
7980
|
-
|
|
8189
|
+
if (!emitted) return;
|
|
8190
|
+
if (!emitted.element.isConnected || !view.dom.contains(emitted.element)) {
|
|
8191
|
+
emit(void 0);
|
|
7981
8192
|
return;
|
|
7982
8193
|
}
|
|
7983
|
-
const payload = findPayloadForElement(view,
|
|
7984
|
-
if (payload == null || !config.isSamePayload(
|
|
7985
|
-
|
|
8194
|
+
const payload = findPayloadForElement(view, emitted.element);
|
|
8195
|
+
if (payload == null || !config.isSamePayload(emitted.payload, payload)) {
|
|
8196
|
+
emit(void 0);
|
|
7986
8197
|
return;
|
|
7987
8198
|
}
|
|
7988
|
-
|
|
7989
|
-
...
|
|
8199
|
+
emitted = {
|
|
8200
|
+
...emitted,
|
|
7990
8201
|
payload
|
|
7991
8202
|
};
|
|
7992
8203
|
},
|
|
7993
|
-
destroy:
|
|
8204
|
+
destroy: () => emit(void 0)
|
|
7994
8205
|
})
|
|
7995
8206
|
}));
|
|
7996
8207
|
}
|
|
@@ -7998,10 +8209,30 @@ function defineMarkHoverHandler(config) {
|
|
|
7998
8209
|
//#endregion
|
|
7999
8210
|
//#region src/extensions/link-hover.ts
|
|
8000
8211
|
const linkHoverKey = new PluginKey("meowdown-link-hover");
|
|
8001
|
-
|
|
8212
|
+
/**
|
|
8213
|
+
* Dwell before a cold hover enters, in ms.
|
|
8214
|
+
*/
|
|
8215
|
+
const OPEN_DELAY = 300;
|
|
8216
|
+
/**
|
|
8217
|
+
* Grace before a leave fires, in ms. The window lets a pointer travel from
|
|
8218
|
+
* the hovered link onto the popup it anchors.
|
|
8219
|
+
*/
|
|
8220
|
+
const CLOSE_DELAY = 100;
|
|
8221
|
+
/**
|
|
8222
|
+
* Track the link under the user's attention: a mouse hover after a short
|
|
8223
|
+
* dwell, or a touch tap immediately, since touch has no hover. Without the
|
|
8224
|
+
* tap entry, the popup's preview and actions would stay unreachable on
|
|
8225
|
+
* phones, where a tap on a link only places the caret and raises the
|
|
8226
|
+
* software keyboard.
|
|
8227
|
+
*/
|
|
8228
|
+
function defineLinkHoverHandler(onHoverChange, { canLeave } = {}) {
|
|
8002
8229
|
return defineMarkHoverHandler({
|
|
8003
8230
|
key: linkHoverKey,
|
|
8004
8231
|
selector: ".md-link",
|
|
8232
|
+
openDelay: OPEN_DELAY,
|
|
8233
|
+
closeDelay: CLOSE_DELAY,
|
|
8234
|
+
tap: true,
|
|
8235
|
+
canLeave,
|
|
8005
8236
|
findPayloadAt: (state, pos) => {
|
|
8006
8237
|
return getLinkUnitAt(state, pos);
|
|
8007
8238
|
},
|
|
@@ -8054,98 +8285,6 @@ function defineLinkPaste() {
|
|
|
8054
8285
|
})), Priority$1.high);
|
|
8055
8286
|
}
|
|
8056
8287
|
|
|
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
8288
|
//#endregion
|
|
8150
8289
|
//#region src/extensions/substitution.ts
|
|
8151
8290
|
const SUBSTITUTION_RULES = [
|
|
@@ -8395,7 +8534,7 @@ var VirtualCaretView = class {
|
|
|
8395
8534
|
this.#renderCaret();
|
|
8396
8535
|
return;
|
|
8397
8536
|
}
|
|
8398
|
-
const nativeRect = findNativeCaretRect(view);
|
|
8537
|
+
const nativeRect = isAfterLineBreak(selection.$head) ? void 0 : findNativeCaretRect(view);
|
|
8399
8538
|
if (nativeRect && getIsTouchInput()) {
|
|
8400
8539
|
this.#renderTail();
|
|
8401
8540
|
this.#renderCaret();
|
|
@@ -8480,6 +8619,9 @@ function defineWikilinkHoverHandler(onHoverChange) {
|
|
|
8480
8619
|
return defineMarkHoverHandler({
|
|
8481
8620
|
key: wikilinkHoverKey,
|
|
8482
8621
|
selector: ".md-wikilink-view-preview",
|
|
8622
|
+
openDelay: 0,
|
|
8623
|
+
closeDelay: 0,
|
|
8624
|
+
tap: false,
|
|
8483
8625
|
findPayloadAt: findWikilinkAt,
|
|
8484
8626
|
findPayloadForElement: findWikilinkForElement,
|
|
8485
8627
|
isSamePayload: (previous, next) => previous.target === next.target,
|
|
@@ -8647,4 +8789,4 @@ function getVirtualElementFromRange(view, range) {
|
|
|
8647
8789
|
}
|
|
8648
8790
|
|
|
8649
8791
|
//#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,
|
|
8792
|
+
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, getLinkText, getLinkUnitAt, getMarkBuilders, getPendingReplacement, getSearchStatus, getSelectedText, getTableColumnAlign, getTextblockDisplayText, getVirtualElementFromRange, inlineTextToMarkChunks, inlineTextToMarkChunksWithContext, insertLink, isCodeBlockPreviewHiddenDecoration, isLinkTextForHref, isMarkOfType, isModEvent, isNodeOfType, isSelectionInTableCell, listenForTweetHeight, loadKaTeX, markdownToDoc, matchEmbed, normalizeHref, parseWikiEmbed, removeLink, renderMathInto, updateLink, wikiEmbedBasename, withPriority };
|
package/dist/style.css
CHANGED
|
@@ -155,6 +155,7 @@
|
|
|
155
155
|
--meowdown-heading: light-dark(oklch(21% .006 286), oklch(98.5% 0 0));
|
|
156
156
|
--meowdown-muted: light-dark(oklch(44.2% .015 286), oklch(71.2% .013 286));
|
|
157
157
|
--meowdown-accent: light-dark(oklch(64.6% .194 41), oklch(75.8% .159 56));
|
|
158
|
+
--meowdown-accent-contrast: light-dark(oklch(100% 0 0), oklch(21% .006 286));
|
|
158
159
|
--meowdown-caret: var(--meowdown-accent);
|
|
159
160
|
--meowdown-caret-glide: 80ms;
|
|
160
161
|
--meowdown-mark: var(--meowdown-muted);
|
|
@@ -189,6 +190,9 @@
|
|
|
189
190
|
--meowdown-table-header-bg: light-dark(oklch(98.5% 0 0), oklch(27.4% .005 286));
|
|
190
191
|
--meowdown-popover-bg: light-dark(oklch(100% 0 0), oklch(21% .006 286));
|
|
191
192
|
--meowdown-popover-hover-bg: light-dark(oklch(96.7% 0 0), oklch(27.4% .005 286));
|
|
193
|
+
--meowdown-hover-card-border: var(--meowdown-border);
|
|
194
|
+
--meowdown-hover-card-radius: .75rem;
|
|
195
|
+
--meowdown-hover-card-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;
|
|
192
196
|
--meowdown-danger: light-dark(oklch(63.7% .208 25), oklch(71.1% .166 22));
|
|
193
197
|
--meowdown-placeholder: var(--meowdown-muted);
|
|
194
198
|
--meowdown-font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meowdown/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.67.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"@floating-ui/dom": "^1.8.0",
|
|
27
27
|
"@lezer/highlight": "^1.2.3",
|
|
28
28
|
"@ocavue/utils": "^1.7.0",
|
|
29
|
-
"@prosekit/core": "^0.13.
|
|
30
|
-
"@prosekit/extensions": "^0.18.
|
|
29
|
+
"@prosekit/core": "^0.13.1",
|
|
30
|
+
"@prosekit/extensions": "^0.18.1",
|
|
31
31
|
"@prosekit/pm": "^0.1.19",
|
|
32
|
-
"@prosekit/web": "^0.9.
|
|
32
|
+
"@prosekit/web": "^0.9.1",
|
|
33
33
|
"hast-util-to-mdast": "^10.1.2",
|
|
34
34
|
"katex": "^0.18.1",
|
|
35
35
|
"mdast-util-to-markdown": "^2.1.2",
|
|
@@ -43,20 +43,20 @@
|
|
|
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.
|
|
46
|
+
"@meowdown/markdown": "^0.67.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@ocavue/tsconfig": "^0.7.1",
|
|
50
50
|
"@tsdown/css": "^0.23.0-beta.2",
|
|
51
51
|
"@types/hast": "^3.0.5",
|
|
52
52
|
"@types/mdast": "^4.0.4",
|
|
53
|
-
"@vitest/browser-playwright": "^4.1.
|
|
53
|
+
"@vitest/browser-playwright": "^4.1.11",
|
|
54
54
|
"commonmark.json": "^0.31.0",
|
|
55
55
|
"dedent": "^1.7.2",
|
|
56
56
|
"diffable-html-snapshot": "^0.3.0",
|
|
57
57
|
"fast-check": "^4.9.0",
|
|
58
58
|
"tsdown": "^0.23.0-beta.2",
|
|
59
|
-
"vitest": "^4.1.
|
|
59
|
+
"vitest": "^4.1.11",
|
|
60
60
|
"@meowdown/vitest": "0.0.0"
|
|
61
61
|
},
|
|
62
62
|
"publishConfig": {
|