@meowdown/react 0.73.1 → 0.74.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 +1 -1
- package/dist/index.js +102 -61
- package/dist/style.css +3 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -122,7 +122,7 @@ interface EditorHandle {
|
|
|
122
122
|
* Escape hatch: the underlying ProseKit editor, or `undefined` when the
|
|
123
123
|
* handle does not wrap one.
|
|
124
124
|
*/
|
|
125
|
-
|
|
125
|
+
getEditor: () => TypedEditor | undefined;
|
|
126
126
|
}
|
|
127
127
|
/**
|
|
128
128
|
* One row of host items in the slash menu. The host ranks the rows; the menu does not re-sort.
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { clsx } from "clsx/lite";
|
|
2
|
-
import { Fragment, ViewTransition, cloneElement, createElement, memo, startTransition, useCallback, useDeferredValue, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
3
|
-
import { buildFileMarkdown, codeBlockLanguages, collectReferenceDefinitions, defaultResolveImageUrl, defaultResolveXPost, defaultResolveYouTubeVideo, defineCodeBlockPreviewPlugin, defineEditorExtension, defineLinkEditKeymap, defineLinkHoverHandler, definePendingReplacementHandler, defineSearchStatusHandler, defineVirtualCaret, defineWikilinkHoverHandler, docToMarkdown, formatFileSize, getCodeTokens, getFileKind, getLinkText, getMarkBuilders, getPendingReplacement, getSearchStatus, getSelectedText, getTableColumnAlign, getTextblockDisplayText, getVirtualElementFromRange, inlineTextToMarkChunksWithContext, isCodeBlockPreviewHiddenDecoration, isLinkTextForHref, isModEvent, isNodeOfType, isReferenceDefinitionNode, isSelectionInTableCell, loadKaTeX, markdownToDoc, normalizeHref, parsePostEmbedSnapshot, renderMathInto, updateEditorConfig } from "@meowdown/core";
|
|
2
|
+
import { Fragment, ViewTransition, cloneElement, createElement, memo, startTransition, useCallback, useDeferredValue, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState } from "react";
|
|
3
|
+
import { buildFileMarkdown, codeBlockLanguages, collectReferenceDefinitions, defaultResolveImageUrl, defaultResolveXPost, defaultResolveYouTubeVideo, defineCodeBlockPreviewPlugin, defineEditorExtension, defineLinkEditKeymap, defineLinkHoverHandler, definePendingReplacementHandler, defineSearchStatusHandler, defineVirtualCaret, defineWikilinkHoverHandler, dismissLinkHover, docToMarkdown, formatFileSize, getCodeTokens, getFileKind, getLinkText, getMarkBuilders, getPendingReplacement, getSearchStatus, getSelectedText, getTableColumnAlign, getTextblockDisplayText, getVirtualElementFromRange, inlineTextToMarkChunksWithContext, isCodeBlockPreviewHiddenDecoration, isLinkTextForHref, isModEvent, isNodeOfType, isReferenceDefinitionNode, isSelectionInTableCell, loadKaTeX, markdownToDoc, normalizeHref, parsePostEmbedSnapshot, renderMathInto, updateEditorConfig } from "@meowdown/core";
|
|
4
4
|
import { clamp } from "@ocavue/utils";
|
|
5
5
|
import { canUseRegexLookbehind, createEditor, defineDocChangeHandler, defineUpdateHandler, isTextSelection, union } from "@prosekit/core";
|
|
6
6
|
import { Selection, TextSelection } from "@prosekit/pm/state";
|
|
@@ -422,6 +422,44 @@ function EditorExtensions({ config, searchQuery, onDocChange, onSearchChange })
|
|
|
422
422
|
return null;
|
|
423
423
|
}
|
|
424
424
|
|
|
425
|
+
//#endregion
|
|
426
|
+
//#region src/components/link-menu-state.ts
|
|
427
|
+
const LINK_MENU_IDLE = { kind: "idle" };
|
|
428
|
+
/**
|
|
429
|
+
* What the popup renders: the open view, or the closing one during the exit
|
|
430
|
+
* animation.
|
|
431
|
+
*/
|
|
432
|
+
function getLinkMenuView(state) {
|
|
433
|
+
switch (state.kind) {
|
|
434
|
+
case "idle": return;
|
|
435
|
+
case "closing": return state.view;
|
|
436
|
+
default: return state;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
function reduceLinkMenu(state, event) {
|
|
440
|
+
switch (event.type) {
|
|
441
|
+
case "hover":
|
|
442
|
+
if (state.kind === "edit") return state;
|
|
443
|
+
if (event.link) return {
|
|
444
|
+
kind: "preview",
|
|
445
|
+
link: event.link
|
|
446
|
+
};
|
|
447
|
+
return state.kind === "preview" ? {
|
|
448
|
+
kind: "closing",
|
|
449
|
+
view: state
|
|
450
|
+
} : state;
|
|
451
|
+
case "edit": return {
|
|
452
|
+
kind: "edit",
|
|
453
|
+
edit: event.edit
|
|
454
|
+
};
|
|
455
|
+
case "close": return state.kind === "preview" || state.kind === "edit" ? {
|
|
456
|
+
kind: "closing",
|
|
457
|
+
view: state
|
|
458
|
+
} : state;
|
|
459
|
+
case "closed": return state.kind === "closing" ? LINK_MENU_IDLE : state;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
425
463
|
//#endregion
|
|
426
464
|
//#region src/components/link-menu.module.css
|
|
427
465
|
var link_menu_module_default = {
|
|
@@ -735,41 +773,39 @@ function LinkEditContent({ edit, resolveLinkPreview, onSubmit, onRemove }) {
|
|
|
735
773
|
}
|
|
736
774
|
function LinkMenu({ onLinkClick, onLinkCopy, resolveLinkPreview, readOnly = false }) {
|
|
737
775
|
const editor = useEditor$1();
|
|
738
|
-
const [
|
|
739
|
-
const [editOpen, setEditOpen] = useState(false);
|
|
740
|
-
const [link, setLink] = useState();
|
|
741
|
-
const [edit, setEdit] = useState();
|
|
776
|
+
const [state, dispatch] = useReducer(reduceLinkMenu, LINK_MENU_IDLE);
|
|
742
777
|
const isPointerOverPopupRef = useRef(false);
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
778
|
+
useEffect(() => {
|
|
779
|
+
const canLeave = () => !isPointerOverPopupRef.current;
|
|
780
|
+
const linkHoverExtension = defineLinkHoverHandler((hit) => dispatch({
|
|
781
|
+
type: "hover",
|
|
782
|
+
link: hit?.payload
|
|
783
|
+
}), { canLeave });
|
|
784
|
+
return editor.use(linkHoverExtension);
|
|
785
|
+
}, [editor]);
|
|
786
|
+
useEffect(() => {
|
|
787
|
+
if (readOnly) return;
|
|
788
|
+
const linkEditExtension = defineLinkEditKeymap((edit) => dispatch({
|
|
789
|
+
type: "edit",
|
|
790
|
+
edit
|
|
791
|
+
}));
|
|
792
|
+
return editor.use(linkEditExtension);
|
|
793
|
+
}, [editor, readOnly]);
|
|
758
794
|
const handlePointerHover = useCallback((over) => {
|
|
759
795
|
isPointerOverPopupRef.current = over;
|
|
760
796
|
}, []);
|
|
761
|
-
const
|
|
797
|
+
const close = useCallback(() => {
|
|
762
798
|
isPointerOverPopupRef.current = false;
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
799
|
+
dismissLinkHover(editor.state);
|
|
800
|
+
dispatch({ type: "close" });
|
|
801
|
+
}, [editor]);
|
|
802
|
+
const view = getLinkMenuView(state);
|
|
803
|
+
const edit = view?.kind === "edit" ? view.edit : void 0;
|
|
804
|
+
const link = view?.kind === "preview" ? view.link : void 0;
|
|
769
805
|
const handleEditRemove = useCallback(() => {
|
|
770
806
|
editor.commands.removeLink();
|
|
771
|
-
|
|
772
|
-
}, [editor,
|
|
807
|
+
close();
|
|
808
|
+
}, [editor, close]);
|
|
773
809
|
const handleEditSubmit = useCallback((text, href) => {
|
|
774
810
|
if (!edit) return;
|
|
775
811
|
if (edit.link) editor.commands.updateLink({
|
|
@@ -781,52 +817,52 @@ function LinkMenu({ onLinkClick, onLinkCopy, resolveLinkPreview, readOnly = fals
|
|
|
781
817
|
text,
|
|
782
818
|
href
|
|
783
819
|
});
|
|
784
|
-
|
|
820
|
+
close();
|
|
785
821
|
}, [
|
|
786
822
|
edit,
|
|
787
823
|
editor,
|
|
788
|
-
|
|
824
|
+
close
|
|
789
825
|
]);
|
|
790
826
|
const mutable = link != null && !readOnly && link.form !== "reference";
|
|
791
827
|
const linkText = useMemo(() => link ? getLinkText(link) : "", [link]);
|
|
792
828
|
const editLink = useCallback(() => {
|
|
793
829
|
if (!link) return;
|
|
794
830
|
selectLinkUnit(editor, link);
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
831
|
+
dispatch({
|
|
832
|
+
type: "edit",
|
|
833
|
+
edit: {
|
|
834
|
+
from: link.unit.from,
|
|
835
|
+
to: link.unit.to,
|
|
836
|
+
link,
|
|
837
|
+
text: linkText
|
|
838
|
+
}
|
|
800
839
|
});
|
|
801
|
-
setEditOpen(true);
|
|
802
|
-
closeInfo();
|
|
803
840
|
}, [
|
|
804
841
|
link,
|
|
805
842
|
editor,
|
|
806
|
-
linkText
|
|
807
|
-
closeInfo
|
|
843
|
+
linkText
|
|
808
844
|
]);
|
|
809
845
|
const removeLink = useCallback(() => {
|
|
810
846
|
if (!link) return;
|
|
811
847
|
selectLinkUnit(editor, link);
|
|
812
848
|
editor.commands.removeLink();
|
|
813
|
-
|
|
849
|
+
close();
|
|
814
850
|
}, [
|
|
815
851
|
link,
|
|
816
852
|
editor,
|
|
817
|
-
|
|
853
|
+
close
|
|
818
854
|
]);
|
|
819
855
|
const handleUseTitle = useMemo(() => {
|
|
820
856
|
if (!link || !mutable || !isLinkTextForHref(linkText, link.href)) return;
|
|
821
857
|
return (title) => {
|
|
822
858
|
selectLinkUnit(editor, link);
|
|
823
859
|
editor.commands.updateLink({ text: title });
|
|
824
|
-
|
|
860
|
+
close();
|
|
825
861
|
};
|
|
826
862
|
}, [
|
|
827
863
|
link,
|
|
828
864
|
editor,
|
|
829
|
-
|
|
865
|
+
close,
|
|
830
866
|
linkText,
|
|
831
867
|
mutable
|
|
832
868
|
]);
|
|
@@ -836,24 +872,21 @@ function LinkMenu({ onLinkClick, onLinkCopy, resolveLinkPreview, readOnly = fals
|
|
|
836
872
|
if (!range) return;
|
|
837
873
|
return getVirtualElementFromRange(editor.view, range);
|
|
838
874
|
}, [range, editor]);
|
|
839
|
-
const editing = edit != null && !readOnly;
|
|
840
875
|
return /* @__PURE__ */ jsx(LinkPopover, {
|
|
841
876
|
anchor,
|
|
842
|
-
open:
|
|
843
|
-
onClose:
|
|
877
|
+
open: state.kind === "preview" || state.kind === "edit",
|
|
878
|
+
onClose: close,
|
|
844
879
|
onCloseComplete: () => {
|
|
845
|
-
if (
|
|
846
|
-
|
|
847
|
-
editor.focus();
|
|
848
|
-
} else if (!infoOpen) setLink(void 0);
|
|
880
|
+
if (edit) editor.focus();
|
|
881
|
+
dispatch({ type: "closed" });
|
|
849
882
|
},
|
|
850
883
|
onPopupHover: handlePointerHover,
|
|
851
|
-
children:
|
|
884
|
+
children: edit ? /* @__PURE__ */ jsx(LinkEditContent, {
|
|
852
885
|
edit,
|
|
853
886
|
resolveLinkPreview,
|
|
854
887
|
onRemove: edit.link ? handleEditRemove : void 0,
|
|
855
888
|
onSubmit: handleEditSubmit
|
|
856
|
-
}) : link ? /* @__PURE__ */ jsx(LinkInfoContent, {
|
|
889
|
+
}, `${edit.from}:${edit.to}`) : link ? /* @__PURE__ */ jsx(LinkInfoContent, {
|
|
857
890
|
href: link.href,
|
|
858
891
|
previewState,
|
|
859
892
|
onLinkClick,
|
|
@@ -1706,6 +1739,7 @@ function TagMenu({ onTagSearch }) {
|
|
|
1706
1739
|
className: autocomplete_menu_module_default.Popup,
|
|
1707
1740
|
"data-testid": "tag-menu",
|
|
1708
1741
|
children: [items.map((item) => /* @__PURE__ */ jsxs(AutocompleteItem, {
|
|
1742
|
+
value: item.tag,
|
|
1709
1743
|
className: autocomplete_menu_module_default.Item,
|
|
1710
1744
|
onSelect: () => {
|
|
1711
1745
|
editor.commands.insertText({ text: `#${item.tag} ` });
|
|
@@ -1782,6 +1816,7 @@ function WikilinkMenu({ onWikilinkSearch }) {
|
|
|
1782
1816
|
className: autocomplete_menu_module_default.Popup,
|
|
1783
1817
|
"data-testid": "wikilink-menu",
|
|
1784
1818
|
children: [items.map((item) => /* @__PURE__ */ jsxs(AutocompleteItem, {
|
|
1819
|
+
value: item.target,
|
|
1785
1820
|
className: autocomplete_menu_module_default.Item,
|
|
1786
1821
|
onSelect: () => {
|
|
1787
1822
|
editor.commands.insertText({ text: `[[${item.target}]]` });
|
|
@@ -1970,8 +2005,10 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onSl
|
|
|
1970
2005
|
suppressDocChangeRef.current = true;
|
|
1971
2006
|
try {
|
|
1972
2007
|
editor.view.dispatch(transaction);
|
|
1973
|
-
} finally {
|
|
1974
2008
|
suppressDocChangeRef.current = false;
|
|
2009
|
+
} catch (error) {
|
|
2010
|
+
suppressDocChangeRef.current = false;
|
|
2011
|
+
throw error;
|
|
1975
2012
|
}
|
|
1976
2013
|
}
|
|
1977
2014
|
function setState(markdown, selection) {
|
|
@@ -2048,7 +2085,7 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onSl
|
|
|
2048
2085
|
discardPendingReplacement,
|
|
2049
2086
|
findNext,
|
|
2050
2087
|
findPrevious,
|
|
2051
|
-
editor
|
|
2088
|
+
getEditor: () => editor
|
|
2052
2089
|
};
|
|
2053
2090
|
}, [
|
|
2054
2091
|
editor,
|
|
@@ -2056,11 +2093,14 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onSl
|
|
|
2056
2093
|
hasSelectionMenu,
|
|
2057
2094
|
openSelectionMenu
|
|
2058
2095
|
]);
|
|
2096
|
+
const mount = useCallback((element) => {
|
|
2097
|
+
return editor.mount(element);
|
|
2098
|
+
}, [editor]);
|
|
2059
2099
|
return /* @__PURE__ */ jsxs(ProseKit, {
|
|
2060
2100
|
editor,
|
|
2061
2101
|
children: [
|
|
2062
2102
|
/* @__PURE__ */ jsx(VirtualCaret, {}),
|
|
2063
|
-
/* @__PURE__ */ jsx("div", { ref:
|
|
2103
|
+
/* @__PURE__ */ jsx("div", { ref: mount }),
|
|
2064
2104
|
/* @__PURE__ */ jsx(EditorExtensions, {
|
|
2065
2105
|
config,
|
|
2066
2106
|
searchQuery,
|
|
@@ -2081,7 +2121,7 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onSl
|
|
|
2081
2121
|
onLinkCopy,
|
|
2082
2122
|
resolveLinkPreview,
|
|
2083
2123
|
readOnly
|
|
2084
|
-
}),
|
|
2124
|
+
}, String(readOnly)),
|
|
2085
2125
|
onTagSearch && /* @__PURE__ */ jsx(TagMenu, { onTagSearch }),
|
|
2086
2126
|
onWikilinkSearch && /* @__PURE__ */ jsx(WikilinkMenu, { onWikilinkSearch }),
|
|
2087
2127
|
onSelectionMenuSearch && !readOnly && /* @__PURE__ */ jsx(SelectionMenu, {
|
|
@@ -2177,6 +2217,9 @@ function MeowdownEditor({ mode = "focus", initialMarkdown, onDocChange, onSlashM
|
|
|
2177
2217
|
function findPrevious() {
|
|
2178
2218
|
childRef.current?.findPrevious();
|
|
2179
2219
|
}
|
|
2220
|
+
function getEditor() {
|
|
2221
|
+
return childRef.current?.getEditor();
|
|
2222
|
+
}
|
|
2180
2223
|
return {
|
|
2181
2224
|
getMarkdown,
|
|
2182
2225
|
setMarkdown,
|
|
@@ -2197,9 +2240,7 @@ function MeowdownEditor({ mode = "focus", initialMarkdown, onDocChange, onSlashM
|
|
|
2197
2240
|
discardPendingReplacement,
|
|
2198
2241
|
findNext,
|
|
2199
2242
|
findPrevious,
|
|
2200
|
-
|
|
2201
|
-
return childRef.current?.editor;
|
|
2202
|
-
}
|
|
2243
|
+
getEditor
|
|
2203
2244
|
};
|
|
2204
2245
|
}, []);
|
|
2205
2246
|
return /* @__PURE__ */ jsx("div", {
|
package/dist/style.css
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meowdown/react",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.74.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@base-ui/react": "^1.8.0",
|
|
25
|
-
"@meowdown/core": "0.74.
|
|
25
|
+
"@meowdown/core": "0.74.2",
|
|
26
26
|
"@meowdown/embed": "0.2.0",
|
|
27
27
|
"@meowdown/markdown": "0.72.0",
|
|
28
28
|
"@ocavue/utils": "^1.8.0",
|