@meowdown/core 0.74.1 → 0.75.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.d.ts +18 -3
- package/dist/index.js +345 -210
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -808,14 +808,23 @@ type PostEmbedSnapshot = {
|
|
|
808
808
|
export declare function parsePostEmbedSnapshot(value: unknown): PostEmbedSnapshot | undefined;
|
|
809
809
|
//#endregion
|
|
810
810
|
//#region src/extensions/image.d.ts
|
|
811
|
-
|
|
811
|
+
/**
|
|
812
|
+
* Maps a markdown `src` to a displayable URL, or `undefined` to skip rendering
|
|
813
|
+
* that image. May return a `Promise` when the answer needs data that is not
|
|
814
|
+
* loaded yet: the image appears once it resolves, and a rejection or an
|
|
815
|
+
* `undefined` result leaves the source without a preview.
|
|
816
|
+
*/
|
|
817
|
+
type ImageUrlResolver = (src: string) => string | undefined | Promise<string | undefined>;
|
|
812
818
|
/**
|
|
813
819
|
* Options for {@link defineImage}.
|
|
814
820
|
*/
|
|
815
821
|
interface ImageOptions {
|
|
816
822
|
/**
|
|
817
823
|
* Map a markdown `src` to a displayable URL, or `undefined` to skip rendering
|
|
818
|
-
* that image.
|
|
824
|
+
* that image. May return a `Promise`; while it is pending, an image whose
|
|
825
|
+
* `width` and `height` are both persisted shows a sized placeholder so the
|
|
826
|
+
* resolved image does not shift the layout. Defaults to
|
|
827
|
+
* `defaultResolveImageUrl`.
|
|
819
828
|
*/
|
|
820
829
|
resolveImageUrl?: ImageUrlResolver;
|
|
821
830
|
/**
|
|
@@ -1482,6 +1491,12 @@ interface LinkHoverOptions {
|
|
|
1482
1491
|
* software keyboard.
|
|
1483
1492
|
*/
|
|
1484
1493
|
export declare function defineLinkHoverHandler(onHoverChange: LinkHoverHandler, { canLeave }?: LinkHoverOptions): PlainExtension;
|
|
1494
|
+
/**
|
|
1495
|
+
* Tell the link hover handler that the user dismissed the UI it opened. The
|
|
1496
|
+
* link under the pointer stays silent until the pointer leaves it, so a
|
|
1497
|
+
* pending hover cannot reopen the UI.
|
|
1498
|
+
*/
|
|
1499
|
+
export declare function dismissLinkHover(state: EditorState): void;
|
|
1485
1500
|
//#endregion
|
|
1486
1501
|
//#region src/extensions/link-paste.d.ts
|
|
1487
1502
|
/**
|
|
@@ -1674,4 +1689,4 @@ export declare function getSelectedText(state: EditorState): string;
|
|
|
1674
1689
|
*/
|
|
1675
1690
|
export declare function getVirtualElementFromRange(view: EditorView, range: PositionRange): VirtualElement;
|
|
1676
1691
|
//#endregion
|
|
1677
|
-
export { type AcceptPendingReplacementOptions, type CheckRoundTripOptions, type CodeBlockAttrs, type CodeBlockFenceStyle, type CodeToken, type DocToMarkdownOptions, type EditorConfig, type EditorExtension, type EditorExtensionOptions, 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, type PostEmbedSnapshot, 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, type WikilinkOptions, type WikilinkPayload, type WikilinkResolution, type WikilinkResolver, type XPostMediaClickHandler, type XPostResolver, type YouTubeVideoClickHandler, type YouTubeVideoResolver, defineCodeBlockPreviewPlugin, definePlaceholder, defineSearchStatusHandler, getSearchStatus, isCodeBlockPreviewHiddenDecoration, withPriority };
|
|
1692
|
+
export { type AcceptPendingReplacementOptions, type CheckRoundTripOptions, type CodeBlockAttrs, type CodeBlockFenceStyle, type CodeToken, type DocToMarkdownOptions, type EditorConfig, type EditorExtension, type EditorExtensionOptions, 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 ImageUrlResolver, 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, type PostEmbedSnapshot, 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, type WikilinkOptions, type WikilinkPayload, type WikilinkResolution, type WikilinkResolver, type XPostMediaClickHandler, type XPostResolver, type YouTubeVideoClickHandler, type YouTubeVideoResolver, defineCodeBlockPreviewPlugin, definePlaceholder, defineSearchStatusHandler, getSearchStatus, isCodeBlockPreviewHiddenDecoration, withPriority };
|
package/dist/index.js
CHANGED
|
@@ -84,20 +84,86 @@ function getIsComposing() {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
//#endregion
|
|
87
|
-
//#region src/utils/
|
|
87
|
+
//#region src/utils/input-modality.ts
|
|
88
|
+
const KEYBOARD_MODALITY_KEYS = /* @__PURE__ */ new Set([
|
|
89
|
+
"ArrowLeft",
|
|
90
|
+
"ArrowRight",
|
|
91
|
+
"ArrowUp",
|
|
92
|
+
"ArrowDown",
|
|
93
|
+
"Home",
|
|
94
|
+
"End",
|
|
95
|
+
"PageUp",
|
|
96
|
+
"PageDown"
|
|
97
|
+
]);
|
|
98
|
+
let lastIsTouchInput = false;
|
|
99
|
+
let lastIsPointerSelection = false;
|
|
100
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
101
|
+
function setIsTouchInput(isTouchInput) {
|
|
102
|
+
if (isTouchInput === lastIsTouchInput) return;
|
|
103
|
+
lastIsTouchInput = isTouchInput;
|
|
104
|
+
for (const listener of listeners) listener();
|
|
105
|
+
}
|
|
106
|
+
function handlePointerDown(event) {
|
|
107
|
+
const target = event.target;
|
|
108
|
+
lastIsPointerSelection = target instanceof Element && !!target.closest(".ProseMirror");
|
|
109
|
+
const pointerType = event.pointerType;
|
|
110
|
+
if (pointerType === "mouse") setIsTouchInput(false);
|
|
111
|
+
else if (pointerType === "touch" || pointerType === "pen") setIsTouchInput(true);
|
|
112
|
+
}
|
|
113
|
+
function handleKeyDown(event) {
|
|
114
|
+
if (getIsComposing() || event.isComposing) return;
|
|
115
|
+
lastIsPointerSelection = false;
|
|
116
|
+
if (KEYBOARD_MODALITY_KEYS.has(event.key) || event.metaKey || event.ctrlKey) setIsTouchInput(false);
|
|
117
|
+
}
|
|
118
|
+
if (typeof window !== "undefined") {
|
|
119
|
+
window.addEventListener("pointerdown", handlePointerDown, {
|
|
120
|
+
capture: true,
|
|
121
|
+
passive: true
|
|
122
|
+
});
|
|
123
|
+
window.addEventListener("keydown", handleKeyDown, {
|
|
124
|
+
capture: true,
|
|
125
|
+
passive: true
|
|
126
|
+
});
|
|
127
|
+
}
|
|
88
128
|
/**
|
|
89
|
-
* Whether the
|
|
129
|
+
* Whether the user last drove the selection with a finger (or pen) on the
|
|
130
|
+
* screen, as opposed to precise input (hardware keyboard navigation).
|
|
90
131
|
*
|
|
91
|
-
*
|
|
132
|
+
* Starts as `false` and follows the events; a touch device flips it on the
|
|
133
|
+
* first tap, which necessarily precedes any caret. Only navigation keys and
|
|
134
|
+
* modifier combos flip it back: letter keys are ignored because a software
|
|
135
|
+
* keyboard sends them too, and the software keyboard's own caret gestures (a
|
|
136
|
+
* spacebar long-press drag) reach the page as bare `selectionchange` events
|
|
137
|
+
* with no key or touch events at all, so staying on the previous value is the
|
|
138
|
+
* correct reading for them.
|
|
139
|
+
*/
|
|
140
|
+
function getIsTouchInput() {
|
|
141
|
+
return lastIsTouchInput;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Whether the next selection change in an editor comes from a pointer: the
|
|
145
|
+
* last `pointerdown` landed inside an editor and no key was pressed since.
|
|
146
|
+
*/
|
|
147
|
+
function getIsPointerSelection() {
|
|
148
|
+
return lastIsPointerSelection;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Calls `listener` whenever {@link getIsTouchInput} may report a new value.
|
|
92
152
|
*/
|
|
93
|
-
function
|
|
94
|
-
|
|
153
|
+
function onIsTouchInputChange(listener) {
|
|
154
|
+
listeners.add(listener);
|
|
155
|
+
return () => {
|
|
156
|
+
listeners.delete(listener);
|
|
157
|
+
};
|
|
95
158
|
}
|
|
159
|
+
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region src/utils/transaction.ts
|
|
96
162
|
/**
|
|
97
163
|
* Whether any of the given transactions are selection transactions directly caused by mouse or touch input.
|
|
98
164
|
*/
|
|
99
165
|
function hasPointerSelectionTransaction(transactions) {
|
|
100
|
-
return transactions.some(
|
|
166
|
+
return getIsPointerSelection() && transactions.some((tr) => tr.selectionSet && !tr.docChanged);
|
|
101
167
|
}
|
|
102
168
|
|
|
103
169
|
//#endregion
|
|
@@ -512,9 +578,8 @@ function createCaretSnapPlugin(marks) {
|
|
|
512
578
|
if (markNames.length === 0) return null;
|
|
513
579
|
const selection = newState.selection;
|
|
514
580
|
if (!isTextSelection(selection)) return null;
|
|
515
|
-
const isPointer = hasPointerSelectionTransaction(transactions);
|
|
516
581
|
if (!selection.empty) {
|
|
517
|
-
if (!
|
|
582
|
+
if (!hasPointerSelectionTransaction(transactions)) return null;
|
|
518
583
|
const from = getMarkRangeStrictlyAround(newState, selection.from, markNames)?.from ?? selection.from;
|
|
519
584
|
const to = getMarkRangeStrictlyAround(newState, selection.to, markNames)?.to ?? selection.to;
|
|
520
585
|
if (from === selection.from && to === selection.to) return null;
|
|
@@ -524,6 +589,7 @@ function createCaretSnapPlugin(marks) {
|
|
|
524
589
|
}
|
|
525
590
|
const range = getMarkRangeStrictlyAround(newState, selection.head, markNames);
|
|
526
591
|
if (!range) return null;
|
|
592
|
+
const isPointer = hasPointerSelectionTransaction(transactions);
|
|
527
593
|
const head = getUnitEdge(range, oldState.selection.head, selection.head, isPointer);
|
|
528
594
|
return newState.tr.setSelection(TextSelection.create(newState.doc, head));
|
|
529
595
|
}
|
|
@@ -614,6 +680,9 @@ function handleMouseDown(view, event) {
|
|
|
614
680
|
const { doc } = view.state;
|
|
615
681
|
const lastBlock = doc.lastChild;
|
|
616
682
|
if (!lastBlock || acceptsCaretAtEnd(lastBlock)) return false;
|
|
683
|
+
let bottom = lastBlock;
|
|
684
|
+
while (bottom && !bottom.isTextblock && !isNodeOfType(bottom, "table")) bottom = bottom.lastChild;
|
|
685
|
+
if (bottom && bottom.content.size === 0 && acceptsCaretAtEnd(bottom)) return false;
|
|
617
686
|
const lastBlockDOM = view.nodeDOM(doc.content.size - lastBlock.nodeSize);
|
|
618
687
|
if (!(lastBlockDOM instanceof HTMLElement)) return false;
|
|
619
688
|
if (event.clientY <= lastBlockDOM.getBoundingClientRect().bottom) return false;
|
|
@@ -628,7 +697,8 @@ function handleMouseDown(view, event) {
|
|
|
628
697
|
}
|
|
629
698
|
/**
|
|
630
699
|
* A press below the last block appends an empty paragraph and puts the caret
|
|
631
|
-
* in it, when that block would otherwise keep the caret inside itself
|
|
700
|
+
* in it, when that block would otherwise keep the caret inside itself and
|
|
701
|
+
* does not end in an empty line.
|
|
632
702
|
*/
|
|
633
703
|
function defineClickBelow() {
|
|
634
704
|
return definePlugin(new Plugin({
|
|
@@ -3469,8 +3539,8 @@ function createSnapPlugin() {
|
|
|
3469
3539
|
if (getMarkMode(newState) !== "hide") return null;
|
|
3470
3540
|
const selection = newState.selection;
|
|
3471
3541
|
if (!isTextSelection(selection)) return null;
|
|
3472
|
-
const isPointer = hasPointerSelectionTransaction(transactions);
|
|
3473
3542
|
if (selection.empty) {
|
|
3543
|
+
const isPointer = hasPointerSelectionTransaction(transactions);
|
|
3474
3544
|
const next = getRestPosition(newState, oldState.selection.head, selection.head, isPointer);
|
|
3475
3545
|
if (next === selection.head) return null;
|
|
3476
3546
|
return newState.tr.setSelection(TextSelection.create(newState.doc, next));
|
|
@@ -3922,12 +3992,8 @@ var ImageMarkView = class {
|
|
|
3922
3992
|
this.#contentDOM.className = "md-image-view-content md-atom-view-content";
|
|
3923
3993
|
this.#contentDOM.dataset.testid = "image-source";
|
|
3924
3994
|
for (const [name, value] of Object.entries(NON_PROSE_ATTRS)) this.#contentDOM.setAttribute(name, value);
|
|
3925
|
-
const preview = this.#renderPreview();
|
|
3926
|
-
if (preview) {
|
|
3927
|
-
preview.contentEditable = "false";
|
|
3928
|
-
this.#dom.appendChild(preview);
|
|
3929
|
-
}
|
|
3930
3995
|
this.#dom.appendChild(this.#contentDOM);
|
|
3996
|
+
this.#mountPreview();
|
|
3931
3997
|
}
|
|
3932
3998
|
get dom() {
|
|
3933
3999
|
return this.#dom;
|
|
@@ -3954,22 +4020,67 @@ var ImageMarkView = class {
|
|
|
3954
4020
|
this.#destroyed = true;
|
|
3955
4021
|
}
|
|
3956
4022
|
/**
|
|
3957
|
-
*
|
|
3958
|
-
* resizable `<img
|
|
4023
|
+
* Mount the inline preview for the image `src`, if any: a post-embed card, a
|
|
4024
|
+
* resizable `<img>`, or, while an asynchronous resolver is pending and the
|
|
4025
|
+
* size is persisted, an empty box of that size that the image later fills.
|
|
3959
4026
|
*/
|
|
3960
|
-
#
|
|
4027
|
+
#mountPreview() {
|
|
3961
4028
|
const { src } = this.#attrs;
|
|
3962
|
-
const wrapper = document.createElement("span");
|
|
3963
|
-
wrapper.className = "md-image-view-preview md-atom-view-preview";
|
|
3964
4029
|
const kind = matchEmbed(src);
|
|
3965
4030
|
if (kind) {
|
|
4031
|
+
const wrapper = this.#createWrapper();
|
|
3966
4032
|
wrapper.dataset.testid = `${kind}-embed`;
|
|
3967
4033
|
wrapper.dataset.postEmbed = kind;
|
|
3968
4034
|
wrapper.appendChild(this.#buildPostEmbed(kind, src));
|
|
3969
|
-
|
|
4035
|
+
this.#insertPreview(wrapper);
|
|
4036
|
+
return;
|
|
3970
4037
|
}
|
|
3971
|
-
const
|
|
3972
|
-
if (
|
|
4038
|
+
const resolved = (this.#resolveImageUrl ?? defaultResolveImageUrl)(src);
|
|
4039
|
+
if (resolved instanceof Promise) {
|
|
4040
|
+
const placeholder = this.#hasPersistedSize() ? this.#renderImage(null) : void 0;
|
|
4041
|
+
if (placeholder) this.#insertPreview(placeholder);
|
|
4042
|
+
resolved.then((url) => this.#settle(placeholder, url), () => this.#settle(placeholder, void 0));
|
|
4043
|
+
return;
|
|
4044
|
+
}
|
|
4045
|
+
if (resolved) this.#insertPreview(this.#renderImage(resolved));
|
|
4046
|
+
}
|
|
4047
|
+
#hasPersistedSize() {
|
|
4048
|
+
return this.#attrs.width != null && this.#attrs.height != null;
|
|
4049
|
+
}
|
|
4050
|
+
/**
|
|
4051
|
+
* Apply a resolver's asynchronous answer: fill the placeholder with the
|
|
4052
|
+
* image, mount the image from scratch, or drop the placeholder when there is
|
|
4053
|
+
* nothing to show. A view destroyed in the meantime (its `src` changed, or it
|
|
4054
|
+
* left the document) ignores the answer.
|
|
4055
|
+
*/
|
|
4056
|
+
#settle(placeholder, url) {
|
|
4057
|
+
if (this.#destroyed) return;
|
|
4058
|
+
if (!url) {
|
|
4059
|
+
placeholder?.remove();
|
|
4060
|
+
this.#resizableRoot = void 0;
|
|
4061
|
+
return;
|
|
4062
|
+
}
|
|
4063
|
+
if (placeholder && this.#resizableRoot) this.#attachImage(this.#resizableRoot, url);
|
|
4064
|
+
else this.#insertPreview(this.#renderImage(url));
|
|
4065
|
+
}
|
|
4066
|
+
#createWrapper() {
|
|
4067
|
+
const wrapper = document.createElement("span");
|
|
4068
|
+
wrapper.className = "md-image-view-preview md-atom-view-preview";
|
|
4069
|
+
return wrapper;
|
|
4070
|
+
}
|
|
4071
|
+
/**
|
|
4072
|
+
* Insert a preview in front of the source text.
|
|
4073
|
+
*/
|
|
4074
|
+
#insertPreview(preview) {
|
|
4075
|
+
preview.contentEditable = "false";
|
|
4076
|
+
this.#dom.insertBefore(preview, this.#contentDOM);
|
|
4077
|
+
}
|
|
4078
|
+
/**
|
|
4079
|
+
* The resizable image preview. `null` builds the sized box without its
|
|
4080
|
+
* `<img>`, for an asynchronous resolver to fill through `#attachImage`.
|
|
4081
|
+
*/
|
|
4082
|
+
#renderImage(url) {
|
|
4083
|
+
const wrapper = this.#createWrapper();
|
|
3973
4084
|
wrapper.dataset.testid = "image-preview";
|
|
3974
4085
|
wrapper.appendChild(this.#buildResizableImage(url));
|
|
3975
4086
|
return wrapper;
|
|
@@ -4052,6 +4163,25 @@ var ImageMarkView = class {
|
|
|
4052
4163
|
root.className = "md-image-resizable";
|
|
4053
4164
|
root.dataset.testid = "image-resizable";
|
|
4054
4165
|
root.setAttribute("data-loading", "");
|
|
4166
|
+
applySize(root, this.#attrs.width, this.#attrs.height);
|
|
4167
|
+
const handle = document.createElement("prosekit-resizable-handle");
|
|
4168
|
+
handle.className = "md-image-resize-handle";
|
|
4169
|
+
handle.setAttribute("position", "bottom-right");
|
|
4170
|
+
handle.addEventListener("click", (event) => event.stopPropagation());
|
|
4171
|
+
root.appendChild(handle);
|
|
4172
|
+
root.addEventListener("resizeEnd", (event) => {
|
|
4173
|
+
const { width: nextWidth, height: nextHeight } = event.detail;
|
|
4174
|
+
commitImageSize(this.#view, this.#contentDOM, nextWidth, nextHeight);
|
|
4175
|
+
});
|
|
4176
|
+
this.#resizableRoot = root;
|
|
4177
|
+
if (url != null) this.#attachImage(root, url);
|
|
4178
|
+
return root;
|
|
4179
|
+
}
|
|
4180
|
+
/**
|
|
4181
|
+
* Put the `<img>` for `url` into a resizable root built by
|
|
4182
|
+
* `#buildResizableImage`, in front of its handle.
|
|
4183
|
+
*/
|
|
4184
|
+
#attachImage(root, url) {
|
|
4055
4185
|
const image = document.createElement("img");
|
|
4056
4186
|
image.src = url;
|
|
4057
4187
|
image.alt = this.#attrs.alt;
|
|
@@ -4067,19 +4197,8 @@ var ImageMarkView = class {
|
|
|
4067
4197
|
image.addEventListener("error", () => {
|
|
4068
4198
|
root.removeAttribute("data-loading");
|
|
4069
4199
|
});
|
|
4070
|
-
root.
|
|
4071
|
-
const handle = document.createElement("prosekit-resizable-handle");
|
|
4072
|
-
handle.className = "md-image-resize-handle";
|
|
4073
|
-
handle.setAttribute("position", "bottom-right");
|
|
4074
|
-
handle.addEventListener("click", (event) => event.stopPropagation());
|
|
4075
|
-
root.appendChild(handle);
|
|
4076
|
-
root.addEventListener("resizeEnd", (event) => {
|
|
4077
|
-
const { width: nextWidth, height: nextHeight } = event.detail;
|
|
4078
|
-
commitImageSize(this.#view, this.#contentDOM, nextWidth, nextHeight);
|
|
4079
|
-
});
|
|
4080
|
-
this.#resizableRoot = root;
|
|
4200
|
+
root.prepend(image);
|
|
4081
4201
|
this.#image = image;
|
|
4082
|
-
return root;
|
|
4083
4202
|
}
|
|
4084
4203
|
};
|
|
4085
4204
|
/**
|
|
@@ -8478,32 +8597,29 @@ const EDITOR_KEY_BINDINGS = {
|
|
|
8478
8597
|
|
|
8479
8598
|
//#endregion
|
|
8480
8599
|
//#region src/extensions/mark-hover.ts
|
|
8600
|
+
const IDLE = { kind: "idle" };
|
|
8601
|
+
function getHit(phase) {
|
|
8602
|
+
return phase.kind === "active" || phase.kind === "leaving" ? phase.hit : void 0;
|
|
8603
|
+
}
|
|
8481
8604
|
/**
|
|
8482
|
-
*
|
|
8483
|
-
*
|
|
8484
|
-
* Movement within a mark is de-duplicated. The active hit is also revalidated
|
|
8485
|
-
* after every editor update, so deleting, replacing, or rewriting a hovered
|
|
8486
|
-
* mark emits leave even when the pointer itself never moves. Destroying the
|
|
8487
|
-
* editor or removing the extension emits leave as well.
|
|
8488
|
-
*
|
|
8489
|
-
* With `tap`, a touch tap enters too. The browser is the tap recognizer:
|
|
8490
|
-
* only a recognized stationary single-finger tap synthesizes the
|
|
8491
|
-
* compatibility mouse events and the trailing `click`; scrolls, drags,
|
|
8492
|
-
* long-presses, and multi-finger gestures never produce them.
|
|
8605
|
+
* The tracked element the pointer is on, if any.
|
|
8493
8606
|
*/
|
|
8494
|
-
function
|
|
8495
|
-
|
|
8607
|
+
function getPointerElement(phase) {
|
|
8608
|
+
switch (phase.kind) {
|
|
8609
|
+
case "pending":
|
|
8610
|
+
case "dismissed": return phase.element;
|
|
8611
|
+
case "active": return phase.hit.element;
|
|
8612
|
+
default: return;
|
|
8613
|
+
}
|
|
8614
|
+
}
|
|
8615
|
+
function createHoverTracker(config) {
|
|
8616
|
+
const { openDelay, closeDelay } = config;
|
|
8617
|
+
let phase = IDLE;
|
|
8496
8618
|
/**
|
|
8497
|
-
*
|
|
8619
|
+
* Runs exactly while the phase is `pending` or `leaving`.
|
|
8498
8620
|
*/
|
|
8499
|
-
let emitted;
|
|
8500
8621
|
let timer;
|
|
8501
8622
|
/**
|
|
8502
|
-
* The element of a scheduled enter, `null` for a scheduled leave,
|
|
8503
|
-
* `undefined` when nothing is scheduled.
|
|
8504
|
-
*/
|
|
8505
|
-
let scheduledElement;
|
|
8506
|
-
/**
|
|
8507
8623
|
* The type of the pointer that spawned the current event sequence:
|
|
8508
8624
|
* compatibility mouse events carry no pointer type of their own.
|
|
8509
8625
|
*/
|
|
@@ -8514,127 +8630,201 @@ function defineMarkHoverHandler(config) {
|
|
|
8514
8630
|
const findPayloadForElement = (view, element) => {
|
|
8515
8631
|
return config.findPayloadForElement ? config.findPayloadForElement(view, element) : config.findPayloadAt(view.state, view.posAtDOM(element, 0));
|
|
8516
8632
|
};
|
|
8517
|
-
|
|
8633
|
+
/**
|
|
8634
|
+
* The only transition. It restarts the timer the next phase needs and
|
|
8635
|
+
* reports a change of the hit element.
|
|
8636
|
+
*/
|
|
8637
|
+
const go = (next) => {
|
|
8518
8638
|
clearTimeout(timer);
|
|
8519
|
-
|
|
8639
|
+
const previousHit = getHit(phase);
|
|
8640
|
+
phase = next;
|
|
8641
|
+
if (next.kind === "pending") timer = setTimeout(finishOpen, openDelay);
|
|
8642
|
+
if (next.kind === "leaving") timer = setTimeout(finishLeave, closeDelay);
|
|
8643
|
+
const hit = getHit(next);
|
|
8644
|
+
if (hit?.element !== previousHit?.element) config.onHoverChange(hit);
|
|
8520
8645
|
};
|
|
8521
|
-
const
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8646
|
+
const finishOpen = () => {
|
|
8647
|
+
if (phase.kind !== "pending") return;
|
|
8648
|
+
const { element, view } = phase;
|
|
8649
|
+
const payload = element.isConnected ? findPayloadForElement(view, element) : void 0;
|
|
8650
|
+
go(payload == null ? IDLE : {
|
|
8651
|
+
kind: "active",
|
|
8652
|
+
hit: {
|
|
8653
|
+
payload,
|
|
8654
|
+
element
|
|
8655
|
+
}
|
|
8656
|
+
});
|
|
8526
8657
|
};
|
|
8527
|
-
const
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8658
|
+
const finishLeave = () => {
|
|
8659
|
+
if (phase.kind !== "leaving") return;
|
|
8660
|
+
go(config.canLeave?.() === false ? phase : IDLE);
|
|
8661
|
+
};
|
|
8662
|
+
const startPending = (view, element) => {
|
|
8663
|
+
if (findPayloadForElement(view, element) == null) return;
|
|
8664
|
+
go({
|
|
8665
|
+
kind: "pending",
|
|
8666
|
+
element,
|
|
8667
|
+
view
|
|
8668
|
+
});
|
|
8669
|
+
};
|
|
8670
|
+
const handleOver = (view, event) => {
|
|
8671
|
+
const element = findClosestMark(event.target);
|
|
8672
|
+
if (!element || !view.dom.contains(element)) return;
|
|
8673
|
+
switch (phase.kind) {
|
|
8674
|
+
case "idle": return startPending(view, element);
|
|
8675
|
+
case "pending":
|
|
8676
|
+
case "dismissed":
|
|
8677
|
+
if (element !== phase.element) startPending(view, element);
|
|
8678
|
+
return;
|
|
8679
|
+
case "active":
|
|
8680
|
+
case "leaving": {
|
|
8681
|
+
if (element === phase.hit.element) return go({
|
|
8682
|
+
kind: "active",
|
|
8683
|
+
hit: phase.hit
|
|
8684
|
+
});
|
|
8685
|
+
const payload = findPayloadForElement(view, element);
|
|
8686
|
+
if (payload != null) go({
|
|
8687
|
+
kind: "active",
|
|
8688
|
+
hit: {
|
|
8689
|
+
payload,
|
|
8690
|
+
element
|
|
8691
|
+
}
|
|
8692
|
+
});
|
|
8533
8693
|
return;
|
|
8534
8694
|
}
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8695
|
+
}
|
|
8696
|
+
};
|
|
8697
|
+
const handleOut = (event) => {
|
|
8698
|
+
const element = getPointerElement(phase);
|
|
8699
|
+
if (!element) return;
|
|
8700
|
+
const related = event.relatedTarget;
|
|
8701
|
+
if (related instanceof Node && element.contains(related)) return;
|
|
8702
|
+
go(phase.kind === "active" ? {
|
|
8703
|
+
kind: "leaving",
|
|
8704
|
+
hit: phase.hit
|
|
8705
|
+
} : IDLE);
|
|
8706
|
+
};
|
|
8707
|
+
const handlePointerDown = (event) => {
|
|
8708
|
+
lastPointerType = event.pointerType;
|
|
8538
8709
|
};
|
|
8539
|
-
const
|
|
8710
|
+
const handleMouseDown = (event) => {
|
|
8711
|
+
if (lastPointerType !== "touch" || !findClosestMark(event.target)) return false;
|
|
8712
|
+
event.preventDefault();
|
|
8713
|
+
return true;
|
|
8714
|
+
};
|
|
8715
|
+
const handleClick = (view, event) => {
|
|
8716
|
+
if (lastPointerType !== "touch") return false;
|
|
8717
|
+
const element = findClosestMark(event.target);
|
|
8718
|
+
if (!element || !view.dom.contains(element)) {
|
|
8719
|
+
go(IDLE);
|
|
8720
|
+
return false;
|
|
8721
|
+
}
|
|
8722
|
+
event.preventDefault();
|
|
8540
8723
|
const payload = findPayloadForElement(view, element);
|
|
8541
|
-
if (payload
|
|
8542
|
-
|
|
8543
|
-
|
|
8724
|
+
if (payload != null) go({
|
|
8725
|
+
kind: "active",
|
|
8726
|
+
hit: {
|
|
8544
8727
|
payload,
|
|
8545
8728
|
element
|
|
8546
|
-
}
|
|
8729
|
+
}
|
|
8730
|
+
});
|
|
8731
|
+
return true;
|
|
8732
|
+
};
|
|
8733
|
+
const update = (view) => {
|
|
8734
|
+
if (phase.kind === "dismissed") {
|
|
8735
|
+
if (!view.dom.contains(phase.element)) go(IDLE);
|
|
8547
8736
|
return;
|
|
8548
8737
|
}
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
payload: fresh,
|
|
8738
|
+
if (phase.kind !== "active" && phase.kind !== "leaving") return;
|
|
8739
|
+
const { element } = phase.hit;
|
|
8740
|
+
if (!element.isConnected || !view.dom.contains(element)) return go(IDLE);
|
|
8741
|
+
const payload = findPayloadForElement(view, element);
|
|
8742
|
+
if (payload == null || !config.isSamePayload(phase.hit.payload, payload)) return go(IDLE);
|
|
8743
|
+
phase = {
|
|
8744
|
+
kind: phase.kind,
|
|
8745
|
+
hit: {
|
|
8746
|
+
payload,
|
|
8559
8747
|
element
|
|
8560
|
-
}
|
|
8561
|
-
}
|
|
8748
|
+
}
|
|
8749
|
+
};
|
|
8562
8750
|
};
|
|
8563
|
-
const
|
|
8564
|
-
|
|
8565
|
-
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
|
|
8751
|
+
const dismiss = () => {
|
|
8752
|
+
switch (phase.kind) {
|
|
8753
|
+
case "pending": return go({
|
|
8754
|
+
kind: "dismissed",
|
|
8755
|
+
element: phase.element
|
|
8756
|
+
});
|
|
8757
|
+
case "active": return go({
|
|
8758
|
+
kind: "dismissed",
|
|
8759
|
+
element: phase.hit.element
|
|
8760
|
+
});
|
|
8761
|
+
case "leaving": return go(IDLE);
|
|
8569
8762
|
}
|
|
8570
|
-
if (element === scheduledElement) return;
|
|
8571
|
-
enter(view, element);
|
|
8572
8763
|
};
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
|
|
8764
|
+
return {
|
|
8765
|
+
handleOver,
|
|
8766
|
+
handleOut,
|
|
8767
|
+
handlePointerDown,
|
|
8768
|
+
handleMouseDown,
|
|
8769
|
+
handleClick,
|
|
8770
|
+
update,
|
|
8771
|
+
dismiss,
|
|
8772
|
+
destroy: () => go(IDLE)
|
|
8580
8773
|
};
|
|
8774
|
+
}
|
|
8775
|
+
/**
|
|
8776
|
+
* Delegate hover tracking for a rendered mark to the editor root.
|
|
8777
|
+
*
|
|
8778
|
+
* Movement within a mark is de-duplicated. The active hit is also revalidated
|
|
8779
|
+
* after every editor update, so deleting, replacing, or rewriting a hovered
|
|
8780
|
+
* mark emits leave even when the pointer itself never moves. Destroying the
|
|
8781
|
+
* editor or removing the extension emits leave as well.
|
|
8782
|
+
*
|
|
8783
|
+
* With `tap`, a touch tap enters too. The browser is the tap recognizer:
|
|
8784
|
+
* only a recognized stationary single-finger tap synthesizes the
|
|
8785
|
+
* compatibility mouse events and the trailing `click`; scrolls, drags,
|
|
8786
|
+
* long-presses, and multi-finger gestures never produce them.
|
|
8787
|
+
*
|
|
8788
|
+
* The tracker lives in the plugin state, so `key.getState(state)?.dismiss()`
|
|
8789
|
+
* reaches the one tracking that editor.
|
|
8790
|
+
*/
|
|
8791
|
+
function defineMarkHoverHandler(config) {
|
|
8792
|
+
const { key } = config;
|
|
8581
8793
|
return definePlugin(new Plugin({
|
|
8582
|
-
key
|
|
8794
|
+
key,
|
|
8795
|
+
state: {
|
|
8796
|
+
init: () => createHoverTracker(config),
|
|
8797
|
+
apply: (_tr, tracker) => tracker
|
|
8798
|
+
},
|
|
8583
8799
|
props: { handleDOMEvents: {
|
|
8584
8800
|
mouseover: (view, event) => {
|
|
8585
|
-
handleOver(view, event);
|
|
8801
|
+
key.getState(view.state)?.handleOver(view, event);
|
|
8586
8802
|
return false;
|
|
8587
8803
|
},
|
|
8588
|
-
mouseout: (
|
|
8589
|
-
handleOut(event);
|
|
8804
|
+
mouseout: (view, event) => {
|
|
8805
|
+
key.getState(view.state)?.handleOut(event);
|
|
8590
8806
|
return false;
|
|
8591
8807
|
},
|
|
8592
|
-
...tap && {
|
|
8593
|
-
pointerdown: (
|
|
8594
|
-
|
|
8808
|
+
...config.tap && {
|
|
8809
|
+
pointerdown: (view, event) => {
|
|
8810
|
+
key.getState(view.state)?.handlePointerDown(event);
|
|
8595
8811
|
return false;
|
|
8596
8812
|
},
|
|
8597
|
-
mousedown: (
|
|
8598
|
-
|
|
8599
|
-
event.preventDefault();
|
|
8600
|
-
return true;
|
|
8813
|
+
mousedown: (view, event) => {
|
|
8814
|
+
return key.getState(view.state)?.handleMouseDown(event) ?? false;
|
|
8601
8815
|
},
|
|
8602
8816
|
click: (view, event) => {
|
|
8603
|
-
|
|
8604
|
-
const element = findClosestMark(event.target);
|
|
8605
|
-
if (!element || !view.dom.contains(element)) {
|
|
8606
|
-
emit(void 0);
|
|
8607
|
-
return false;
|
|
8608
|
-
}
|
|
8609
|
-
event.preventDefault();
|
|
8610
|
-
const payload = findPayloadForElement(view, element);
|
|
8611
|
-
if (payload != null) emit({
|
|
8612
|
-
payload,
|
|
8613
|
-
element
|
|
8614
|
-
});
|
|
8615
|
-
return true;
|
|
8817
|
+
return key.getState(view.state)?.handleClick(view, event) ?? false;
|
|
8616
8818
|
}
|
|
8617
8819
|
}
|
|
8618
8820
|
} },
|
|
8619
|
-
view: () =>
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
|
|
8624
|
-
|
|
8625
|
-
|
|
8626
|
-
const payload = findPayloadForElement(view, emitted.element);
|
|
8627
|
-
if (payload == null || !config.isSamePayload(emitted.payload, payload)) {
|
|
8628
|
-
emit(void 0);
|
|
8629
|
-
return;
|
|
8630
|
-
}
|
|
8631
|
-
emitted = {
|
|
8632
|
-
...emitted,
|
|
8633
|
-
payload
|
|
8634
|
-
};
|
|
8635
|
-
},
|
|
8636
|
-
destroy: () => emit(void 0)
|
|
8637
|
-
})
|
|
8821
|
+
view: (view) => {
|
|
8822
|
+
const tracker = key.getState(view.state);
|
|
8823
|
+
return {
|
|
8824
|
+
update: (view) => tracker?.update(view),
|
|
8825
|
+
destroy: () => tracker?.destroy()
|
|
8826
|
+
};
|
|
8827
|
+
}
|
|
8638
8828
|
}));
|
|
8639
8829
|
}
|
|
8640
8830
|
|
|
@@ -8674,6 +8864,14 @@ function defineLinkHoverHandler(onHoverChange, { canLeave } = {}) {
|
|
|
8674
8864
|
onHoverChange
|
|
8675
8865
|
});
|
|
8676
8866
|
}
|
|
8867
|
+
/**
|
|
8868
|
+
* Tell the link hover handler that the user dismissed the UI it opened. The
|
|
8869
|
+
* link under the pointer stays silent until the pointer leaves it, so a
|
|
8870
|
+
* pending hover cannot reopen the UI.
|
|
8871
|
+
*/
|
|
8872
|
+
function dismissLinkHover(state) {
|
|
8873
|
+
linkHoverKey.getState(state)?.dismiss();
|
|
8874
|
+
}
|
|
8677
8875
|
|
|
8678
8876
|
//#endregion
|
|
8679
8877
|
//#region src/utils/force-reflow.ts
|
|
@@ -8681,69 +8879,6 @@ function forceReflow(element) {
|
|
|
8681
8879
|
element.offsetWidth;
|
|
8682
8880
|
}
|
|
8683
8881
|
|
|
8684
|
-
//#endregion
|
|
8685
|
-
//#region src/utils/input-modality.ts
|
|
8686
|
-
const KEYBOARD_MODALITY_KEYS = /* @__PURE__ */ new Set([
|
|
8687
|
-
"ArrowLeft",
|
|
8688
|
-
"ArrowRight",
|
|
8689
|
-
"ArrowUp",
|
|
8690
|
-
"ArrowDown",
|
|
8691
|
-
"Home",
|
|
8692
|
-
"End",
|
|
8693
|
-
"PageUp",
|
|
8694
|
-
"PageDown"
|
|
8695
|
-
]);
|
|
8696
|
-
let lastIsTouchInput = false;
|
|
8697
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
8698
|
-
function setIsTouchInput(isTouchInput) {
|
|
8699
|
-
if (isTouchInput === lastIsTouchInput) return;
|
|
8700
|
-
lastIsTouchInput = isTouchInput;
|
|
8701
|
-
for (const listener of listeners) listener();
|
|
8702
|
-
}
|
|
8703
|
-
function handlePointerDown(event) {
|
|
8704
|
-
const pointerType = event.pointerType;
|
|
8705
|
-
if (pointerType === "mouse") setIsTouchInput(false);
|
|
8706
|
-
else if (pointerType === "touch" || pointerType === "pen") setIsTouchInput(true);
|
|
8707
|
-
}
|
|
8708
|
-
function handleKeyDown(event) {
|
|
8709
|
-
if (getIsComposing() || event.isComposing) return;
|
|
8710
|
-
if (KEYBOARD_MODALITY_KEYS.has(event.key) || event.metaKey || event.ctrlKey) setIsTouchInput(false);
|
|
8711
|
-
}
|
|
8712
|
-
if (typeof window !== "undefined") {
|
|
8713
|
-
window.addEventListener("pointerdown", handlePointerDown, {
|
|
8714
|
-
capture: true,
|
|
8715
|
-
passive: true
|
|
8716
|
-
});
|
|
8717
|
-
window.addEventListener("keydown", handleKeyDown, {
|
|
8718
|
-
capture: true,
|
|
8719
|
-
passive: true
|
|
8720
|
-
});
|
|
8721
|
-
}
|
|
8722
|
-
/**
|
|
8723
|
-
* Whether the user last drove the selection with a finger (or pen) on the
|
|
8724
|
-
* screen, as opposed to precise input (hardware keyboard navigation).
|
|
8725
|
-
*
|
|
8726
|
-
* Starts as `false` and follows the events; a touch device flips it on the
|
|
8727
|
-
* first tap, which necessarily precedes any caret. Only navigation keys and
|
|
8728
|
-
* modifier combos flip it back: letter keys are ignored because a software
|
|
8729
|
-
* keyboard sends them too, and the software keyboard's own caret gestures (a
|
|
8730
|
-
* spacebar long-press drag) reach the page as bare `selectionchange` events
|
|
8731
|
-
* with no key or touch events at all, so staying on the previous value is the
|
|
8732
|
-
* correct reading for them.
|
|
8733
|
-
*/
|
|
8734
|
-
function getIsTouchInput() {
|
|
8735
|
-
return lastIsTouchInput;
|
|
8736
|
-
}
|
|
8737
|
-
/**
|
|
8738
|
-
* Calls `listener` whenever {@link getIsTouchInput} may report a new value.
|
|
8739
|
-
*/
|
|
8740
|
-
function onIsTouchInputChange(listener) {
|
|
8741
|
-
listeners.add(listener);
|
|
8742
|
-
return () => {
|
|
8743
|
-
listeners.delete(listener);
|
|
8744
|
-
};
|
|
8745
|
-
}
|
|
8746
|
-
|
|
8747
8882
|
//#endregion
|
|
8748
8883
|
//#region src/extensions/virtual-caret.ts
|
|
8749
8884
|
const key = new PluginKey("meowdown-virtual-caret");
|
|
@@ -9041,4 +9176,4 @@ function getVirtualElementFromRange(view, range) {
|
|
|
9041
9176
|
}
|
|
9042
9177
|
|
|
9043
9178
|
//#endregion
|
|
9044
|
-
export { EDITOR_KEY_BINDINGS, Priority, buildFileMarkdown, checkRoundTrip, codeBlockLanguages, collectReferenceDefinitions, defaultResolveImageUrl, defaultResolveXPost, defaultResolveYouTubeVideo, 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, docToMarkdown, 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, parsePostEmbedSnapshot, parseWikiEmbed, removeLink, renderMathInto, updateEditorConfig, updateLink, wikiEmbedBasename, withPriority };
|
|
9179
|
+
export { EDITOR_KEY_BINDINGS, Priority, buildFileMarkdown, checkRoundTrip, codeBlockLanguages, collectReferenceDefinitions, defaultResolveImageUrl, defaultResolveXPost, defaultResolveYouTubeVideo, 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, 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, parsePostEmbedSnapshot, parseWikiEmbed, removeLink, renderMathInto, updateEditorConfig, updateLink, wikiEmbedBasename, withPriority };
|