@meowdown/react 0.11.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -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: `![alt](src)` 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
- * Maps an image `src` to a displayable URL (or `undefined` to skip). Enables
123
- * inline image rendering. Pass a stable function. Ignored in source mode.
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, and
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, defineImages, defineMarkMode, definePlaceholder, defineReadonly, defineWikilinkClickHandler, docToMarkdown, markdownToDoc } from "@meowdown/core";
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 resolveImageUrl ? defineImages({
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
- }) : null;
460
+ });
458
461
  }, [
459
462
  resolveImageUrl,
460
463
  onImagePaste,
461
464
  onImageSaveError
462
465
  ]));
463
466
  useExtension$1(useMemo(() => {
464
- return embedPaste && resolveImageUrl ? defineEmbedPaste() : null;
465
- }, [embedPaste, resolveImageUrl]));
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 void 0;
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.11.1",
4
+ "version": "0.13.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.1",
28
- "@prosekit/pm": "^0.1.18",
29
- "@prosekit/react": "^0.8.0-beta.2",
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.11.1"
31
+ "@meowdown/core": "0.13.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.2",
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.2",
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"