@meowdown/react 0.11.1 → 0.12.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 +2 -0
- package/dist/index.d.ts +20 -6
- package/dist/index.js +19 -9
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -44,9 +44,11 @@ The Markdown editor component. Renders inside a `div.meowdown` wrapper that fill
|
|
|
44
44
|
- `onTagSearch?: (query: string) => TagItem[] | Promise<TagItem[]>`: enables the tag menu, which opens when typing `#` followed by text in a rich mode. Returns ranked rows `{ tag, label?, detail?, onSelect? }` (the menu does not re-sort). Selecting a row inserts `#tag ` then runs its `onSelect`. Omit to disable.
|
|
45
45
|
- `onWikilinkSearch?: (query: string) => WikilinkItem[] | Promise<WikilinkItem[]>`: enables the wikilink menu, which opens as soon as `[[` is typed in a rich mode. Returns ranked rows `{ target, label?, detail?, onSelect? }` (the menu does not re-sort). Selecting a row inserts `[[target]]` then runs its `onSelect`. Omit to disable.
|
|
46
46
|
- `onWikilinkClick?: (payload: { target: string; event: MouseEvent }) => void`: called when a rendered wiki link is clicked. A plain click inside a link the caret already sits in just places the caret; `Mod`-click always fires. Pass a stable function (e.g. from `useCallback`). Ignored in source mode.
|
|
47
|
+
- `onLinkClick?: (payload: { href: string; event: MouseEvent }) => void`: called with its `href` when a rendered Markdown link (`[text](url)`) is clicked. A plain click inside a link the caret already sits in just places the caret; `Mod`-click always fires. Pass a stable function (e.g. from `useCallback`). Ignored in source mode.
|
|
47
48
|
- `resolveImageUrl?: (src: string) => string | undefined`: maps an image `src` to a displayable URL (or `undefined` to skip). Enables inline image rendering: `` stays literal text and the image renders beneath its line. Pass a stable function. Ignored in source mode.
|
|
48
49
|
- `onImagePaste?: (file: File) => string | undefined | Promise<string | undefined>`: persists a pasted or dropped image file and returns its markdown `src` (or `undefined` to decline), synchronously or as a promise. Pass a stable function. Ignored in source mode.
|
|
49
50
|
- `onImageSaveError?: (error: unknown, file: File) => void`: called when `onImagePaste` throws. Defaults to `console.error`. Ignored in source mode.
|
|
51
|
+
- `onImageClick?: (payload: { src: string; alt: string; event: MouseEvent }) => void`: called when a rendered image is clicked, with its markdown `src`, `alt`, and the originating `MouseEvent`. Pass a stable function (e.g. from `useCallback`). Ignored in source mode.
|
|
50
52
|
- `embedPaste?: boolean`: auto-embeds a pasted tweet or YouTube link as a rich embed; one undo turns the embed back into the raw link. On by default; set `false` to disable. Only takes effect when `resolveImageUrl` is set, since embeds render through the image pipeline. Ignored in source mode.
|
|
51
53
|
- `bulletAfterHeading?: boolean`: pressing Enter at the end of the document's first heading (the title line) starts a fresh empty bullet on the next line instead of a plain paragraph. Off by default. Ignored in source mode.
|
|
52
54
|
- `blockHandle?: boolean`: shows the per-block gutter handle in the rich modes (a drag grip for reordering blocks and a `+` add button, plus the drop indicator). On by default; set `false` to hide the gutter affordance entirely, e.g. when the host does not want block reordering. Ignored in source mode and when `readOnly` is set.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode, Ref } from "react";
|
|
2
|
-
import { ImageOptions, MarkMode, PlaceholderOptions, TypedEditor, WikilinkClickHandler } from "@meowdown/core";
|
|
2
|
+
import { ImageClickHandler, ImageOptions, LinkClickHandler, MarkMode, PlaceholderOptions, TypedEditor, WikilinkClickHandler } from "@meowdown/core";
|
|
3
3
|
import { SelectionJSON, SelectionJSON as SelectionJSON$1 } from "@prosekit/core";
|
|
4
4
|
import { useEditor, useExtension, useKeymap } from "@prosekit/react";
|
|
5
5
|
|
|
@@ -119,8 +119,16 @@ interface EditorProps {
|
|
|
119
119
|
*/
|
|
120
120
|
onWikilinkClick?: WikilinkClickHandler;
|
|
121
121
|
/**
|
|
122
|
-
*
|
|
123
|
-
*
|
|
122
|
+
* Called with the link `href` on click of a rendered Markdown link
|
|
123
|
+
* (`[text](url)`). A plain click inside a link the caret already sits in just
|
|
124
|
+
* places the caret; `Mod`-click always fires. Pass a stable function (e.g.
|
|
125
|
+
* from `useCallback`). Ignored in source mode.
|
|
126
|
+
*/
|
|
127
|
+
onLinkClick?: LinkClickHandler;
|
|
128
|
+
/**
|
|
129
|
+
* Maps an image `src` to a displayable URL, or `undefined` to skip that image.
|
|
130
|
+
* Defaults to showing http(s) URLs as-is. Pass a stable function (e.g. from
|
|
131
|
+
* `useCallback`). Ignored in source mode.
|
|
124
132
|
*/
|
|
125
133
|
resolveImageUrl?: ImageOptions['resolveImageUrl'];
|
|
126
134
|
/**
|
|
@@ -130,11 +138,15 @@ interface EditorProps {
|
|
|
130
138
|
onImagePaste?: ImageOptions['onImagePaste'];
|
|
131
139
|
/** Called when persisting a pasted/dropped image throws. Ignored in source mode. */
|
|
132
140
|
onImageSaveError?: ImageOptions['onImageSaveError'];
|
|
141
|
+
/**
|
|
142
|
+
* Called when the user clicks a rendered image, with its markdown `src`,
|
|
143
|
+
* `alt`, and the originating `MouseEvent`. Pass a stable function (e.g. from
|
|
144
|
+
* `useCallback`). Ignored in source mode.
|
|
145
|
+
*/
|
|
146
|
+
onImageClick?: ImageClickHandler;
|
|
133
147
|
/**
|
|
134
148
|
* Auto-embeds a pasted tweet or YouTube link as a rich embed; one undo turns
|
|
135
|
-
* the embed back into the raw link. On by default. Ignored in source mode
|
|
136
|
-
* only takes effect when `resolveImageUrl` is set, since embeds render through
|
|
137
|
-
* the same image pipeline.
|
|
149
|
+
* the embed back into the raw link. On by default. Ignored in source mode.
|
|
138
150
|
*/
|
|
139
151
|
embedPaste?: boolean;
|
|
140
152
|
/**
|
|
@@ -179,9 +191,11 @@ declare function MeowdownEditor({
|
|
|
179
191
|
onTagSearch,
|
|
180
192
|
onWikilinkSearch,
|
|
181
193
|
onWikilinkClick,
|
|
194
|
+
onLinkClick,
|
|
182
195
|
resolveImageUrl,
|
|
183
196
|
onImagePaste,
|
|
184
197
|
onImageSaveError,
|
|
198
|
+
onImageClick,
|
|
185
199
|
embedPaste,
|
|
186
200
|
bulletAfterHeading,
|
|
187
201
|
blockHandle,
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { Compartment, EditorSelection, EditorState } from "@codemirror/state";
|
|
|
7
7
|
import { EditorView, keymap } from "@codemirror/view";
|
|
8
8
|
import { clamp } from "@ocavue/utils";
|
|
9
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
-
import { codeBlockLanguages, defineBulletAfterHeading, defineEditorExtension, defineEmbedPaste,
|
|
10
|
+
import { codeBlockLanguages, defineBulletAfterHeading, defineEditorExtension, defineEmbedPaste, defineImage, defineImageClickHandler, defineLinkClickHandler, defineMarkMode, definePlaceholder, defineReadonly, defineWikilinkClickHandler, docToMarkdown, markdownToDoc } from "@meowdown/core";
|
|
11
11
|
import { canUseRegexLookbehind, createEditor, defineDocChangeHandler, union } from "@prosekit/core";
|
|
12
12
|
import { Selection, TextSelection } from "@prosekit/pm/state";
|
|
13
13
|
import { ProseKit, defineReactNodeView, useEditor, useEditor as useEditor$1, useEditorDerivedValue, useExtension, useExtension as useExtension$1, useKeymap } from "@prosekit/react";
|
|
@@ -436,7 +436,7 @@ function DropIndicator$1() {
|
|
|
436
436
|
|
|
437
437
|
//#endregion
|
|
438
438
|
//#region src/components/editor-extensions.tsx
|
|
439
|
-
function EditorExtensions({ markMode, onDocChange, onWikilinkClick, resolveImageUrl, onImagePaste, onImageSaveError, embedPaste, bulletAfterHeading, placeholder, readOnly }) {
|
|
439
|
+
function EditorExtensions({ markMode, onDocChange, onWikilinkClick, onLinkClick, resolveImageUrl, onImagePaste, onImageSaveError, onImageClick, embedPaste, bulletAfterHeading, placeholder, readOnly }) {
|
|
440
440
|
useExtension$1(useMemo(() => {
|
|
441
441
|
return defineMarkMode(markMode);
|
|
442
442
|
}, [markMode]));
|
|
@@ -450,19 +450,25 @@ function EditorExtensions({ markMode, onDocChange, onWikilinkClick, resolveImage
|
|
|
450
450
|
return onWikilinkClick ? defineWikilinkClickHandler(onWikilinkClick) : null;
|
|
451
451
|
}, [onWikilinkClick]));
|
|
452
452
|
useExtension$1(useMemo(() => {
|
|
453
|
-
return
|
|
453
|
+
return onLinkClick ? defineLinkClickHandler(onLinkClick) : null;
|
|
454
|
+
}, [onLinkClick]));
|
|
455
|
+
useExtension$1(useMemo(() => {
|
|
456
|
+
return defineImage({
|
|
454
457
|
resolveImageUrl,
|
|
455
458
|
onImagePaste,
|
|
456
459
|
onImageSaveError
|
|
457
|
-
})
|
|
460
|
+
});
|
|
458
461
|
}, [
|
|
459
462
|
resolveImageUrl,
|
|
460
463
|
onImagePaste,
|
|
461
464
|
onImageSaveError
|
|
462
465
|
]));
|
|
463
466
|
useExtension$1(useMemo(() => {
|
|
464
|
-
return
|
|
465
|
-
}, [
|
|
467
|
+
return onImageClick ? defineImageClickHandler(onImageClick) : null;
|
|
468
|
+
}, [onImageClick]));
|
|
469
|
+
useExtension$1(useMemo(() => {
|
|
470
|
+
return embedPaste ? defineEmbedPaste() : null;
|
|
471
|
+
}, [embedPaste]));
|
|
466
472
|
useExtension$1(useMemo(() => {
|
|
467
473
|
return bulletAfterHeading ? defineBulletAfterHeading() : null;
|
|
468
474
|
}, [bulletAfterHeading]));
|
|
@@ -920,7 +926,7 @@ function resolveSelection(doc, selection) {
|
|
|
920
926
|
return TextSelection.between(doc.resolve(anchor), doc.resolve(head));
|
|
921
927
|
}
|
|
922
928
|
}
|
|
923
|
-
function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, resolveImageUrl, onImagePaste, onImageSaveError, embedPaste, bulletAfterHeading, blockHandle = true, placeholder, readOnly, spellCheck, editorClassName, ref, children }) {
|
|
929
|
+
function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, onLinkClick, resolveImageUrl, onImagePaste, onImageSaveError, onImageClick, embedPaste, bulletAfterHeading, blockHandle = true, placeholder, readOnly, spellCheck, editorClassName, ref, children }) {
|
|
924
930
|
const [editor] = useState(() => {
|
|
925
931
|
const editor = createEditor({ extension: union(defineEditorExtension(), defineCodeBlockView()) });
|
|
926
932
|
if (initialMarkdown) editor.setContent(markdownToDoc(initialMarkdown, editor.nodes));
|
|
@@ -977,7 +983,7 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
|
|
|
977
983
|
};
|
|
978
984
|
}, [editor]);
|
|
979
985
|
const handleDocChange = useMemo(() => {
|
|
980
|
-
if (!onDocChange) return
|
|
986
|
+
if (!onDocChange) return;
|
|
981
987
|
return () => {
|
|
982
988
|
if (suppressDocChangeRef.current) return;
|
|
983
989
|
onDocChange();
|
|
@@ -995,9 +1001,11 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
|
|
|
995
1001
|
markMode,
|
|
996
1002
|
onDocChange: handleDocChange,
|
|
997
1003
|
onWikilinkClick,
|
|
1004
|
+
onLinkClick,
|
|
998
1005
|
resolveImageUrl,
|
|
999
1006
|
onImagePaste,
|
|
1000
1007
|
onImageSaveError,
|
|
1008
|
+
onImageClick,
|
|
1001
1009
|
embedPaste,
|
|
1002
1010
|
bulletAfterHeading,
|
|
1003
1011
|
placeholder,
|
|
@@ -1016,7 +1024,7 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
|
|
|
1016
1024
|
|
|
1017
1025
|
//#endregion
|
|
1018
1026
|
//#region src/components/editor.tsx
|
|
1019
|
-
function MeowdownEditor({ mode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, resolveImageUrl, onImagePaste, onImageSaveError, embedPaste = true, bulletAfterHeading = false, blockHandle = true, placeholder, readOnly, spellCheck, editorClassName, wrapperClassName, handleRef, children }) {
|
|
1027
|
+
function MeowdownEditor({ mode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, onLinkClick, resolveImageUrl, onImagePaste, onImageSaveError, onImageClick, embedPaste = true, bulletAfterHeading = false, blockHandle = true, placeholder, readOnly, spellCheck, editorClassName, wrapperClassName, handleRef, children }) {
|
|
1020
1028
|
const childRef = useRef(null);
|
|
1021
1029
|
useImperativeHandle(handleRef, () => {
|
|
1022
1030
|
function getMarkdown() {
|
|
@@ -1081,9 +1089,11 @@ function MeowdownEditor({ mode = "focus", initialMarkdown, onDocChange, onTagSea
|
|
|
1081
1089
|
onTagSearch,
|
|
1082
1090
|
onWikilinkSearch,
|
|
1083
1091
|
onWikilinkClick,
|
|
1092
|
+
onLinkClick,
|
|
1084
1093
|
resolveImageUrl,
|
|
1085
1094
|
onImagePaste,
|
|
1086
1095
|
onImageSaveError,
|
|
1096
|
+
onImageClick,
|
|
1087
1097
|
embedPaste,
|
|
1088
1098
|
bulletAfterHeading,
|
|
1089
1099
|
blockHandle,
|
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.12.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
"@codemirror/state": "^6.6.0",
|
|
25
25
|
"@codemirror/view": "^6.43.1",
|
|
26
26
|
"@ocavue/utils": "^1.7.0",
|
|
27
|
-
"@prosekit/core": "^0.13.0-beta.
|
|
28
|
-
"@prosekit/pm": "^0.1.
|
|
29
|
-
"@prosekit/react": "^0.8.0-beta.
|
|
27
|
+
"@prosekit/core": "^0.13.0-beta.3",
|
|
28
|
+
"@prosekit/pm": "^0.1.19-beta.0",
|
|
29
|
+
"@prosekit/react": "^0.8.0-beta.4",
|
|
30
30
|
"clsx": "^2.1.1",
|
|
31
|
-
"@meowdown/core": "0.
|
|
31
|
+
"@meowdown/core": "0.12.0"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"react": "^19.0.0",
|
|
@@ -45,14 +45,14 @@
|
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@css-modules-kit/codegen": "^1.3.0",
|
|
47
47
|
"@ocavue/tsconfig": "^0.7.1",
|
|
48
|
-
"@tsdown/css": "^0.22.
|
|
48
|
+
"@tsdown/css": "^0.22.3",
|
|
49
49
|
"@types/react": "^19.2.17",
|
|
50
50
|
"@types/react-dom": "^19.2.3",
|
|
51
51
|
"@vitest/browser-playwright": "^4.1.9",
|
|
52
52
|
"dedent": "^1.7.2",
|
|
53
53
|
"react": "^19.2.7",
|
|
54
54
|
"react-dom": "^19.2.7",
|
|
55
|
-
"tsdown": "^0.22.
|
|
55
|
+
"tsdown": "^0.22.3",
|
|
56
56
|
"vitest": "^4.1.9",
|
|
57
57
|
"vitest-browser-commands": "^0.2.1",
|
|
58
58
|
"vitest-browser-react": "^2.2.0"
|