@meowdown/react 0.3.0 → 0.5.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
@@ -32,15 +32,43 @@ The Markdown editor component. Renders inside a `div.meowdown` wrapper that fill
32
32
  - `'source'`: raw Markdown source with syntax highlighting.
33
33
  - `initialMarkdown?: string`: first render only.
34
34
  - `onDocChange?: VoidFunction`: called on every document change.
35
- - `onTagSearch?: (query: string) => string[] | Promise<string[]>`: enables the tag menu, which opens when typing `#` followed by text in a rich mode; returns the tags to show for a query (lowercased, punctuation stripped). Omit to disable.
36
- - `onWikilinkSearch?: (query: string) => string[] | Promise<string[]>`: enables the wikilink menu, which opens as soon as `[[` is typed in a rich mode; returns the note names to show for a query (lowercased, punctuation stripped, may be empty). Selecting a note inserts `[[Note Name]]`. Omit to disable.
35
+ - `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.
36
+ - `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.
37
+ - `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.
38
+ - `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.
39
+ - `onImagePaste?: (file: File) => Promise<string | undefined>`: persists a pasted or dropped image file and returns its markdown `src` (or `undefined` to decline). Pass a stable function. Ignored in source mode.
40
+ - `onImageSaveError?: (error: Error, file: File) => void`: called when `onImagePaste` throws. Defaults to `console.error`. Ignored in source mode.
41
+ - `placeholder?: string | ((state) => string)`: placeholder text shown in an empty block. Pass a stable function. Ignored in source mode.
42
+ - `readOnly?: boolean`: makes the editor read-only, in both the rich and source modes.
43
+ - `spellCheck?: boolean`: toggles the browser's native spell checking in the rich modes. Defaults to the browser's behavior. Ignored in source mode.
44
+ - `editorClassName?: string`: class on the editable root (the contenteditable). Rich modes only.
45
+ - `wrapperClassName?: string`: class on the outer `div.meowdown` wrapper.
37
46
  - `ref?: Ref<EditorHandle>`
47
+ - `children?: ReactNode`: rendered inside the editor's ProseKit context, so children can call `useEditor()`. Only rendered in the rich modes; source mode ignores them.
48
+
49
+ ### `useEditor`
50
+
51
+ Re-exported from `@prosekit/react`. Call it from a component passed as `children` to read the live editor instance.
52
+
53
+ ### `checkRoundTrip`
54
+
55
+ Re-exported from `@meowdown/core`. `checkRoundTrip(markdown)` returns `'exact' | 'normalizing' | 'lossy'`, for hosts that gate saving markdown files on whether the editor reproduces them faithfully.
38
56
 
39
57
  ### `EditorHandle`
40
58
 
41
59
  Imperative handle for the editor, attached via `ref`.
42
60
 
43
61
  - `getMarkdown(): string`: serializes the current document to Markdown. Can be expensive on large documents; call it on demand (e.g. throttled) instead of on every change.
62
+ - `setMarkdown(markdown: string): void`: replaces the whole document as a single undoable edit.
63
+ - `getState(): EditorStateSnapshot`: returns `[markdown, selection]`, where `selection` is a `SelectionJSON` (`{ anchor: number, head: number, type: string }`).
64
+ - `setState(markdown?: string, selection?: SelectionJSON | 'start' | 'end'): void`: replaces the document (if `markdown` is given) and restores `selection`: exactly when valid, otherwise clamped to the nearest text selection; out-of-range positions never throw. `'start'` and `'end'` jump to the document edges. Without a selection, the current one is mapped through the change. Restore a snapshot with `handle.setState(...handle.getState())`.
65
+ - `getSelection(): SelectionJSON`: returns the current selection.
66
+ - `setSelection(selection: SelectionJSON | 'start' | 'end'): void`: restores a selection with the same hint semantics as `setState`.
67
+ - `focus(): void`: focuses the editor.
68
+ - `scrollIntoView(): void`: scrolls the selection into view.
69
+ - `editor: TypedEditor | undefined`: escape hatch for the underlying ProseKit editor, `undefined` in source mode. No stability guarantees beyond what `@meowdown/core` exports.
70
+
71
+ Selection positions are in the mounted editor's coordinate space: ProseMirror document positions in the rich modes, character offsets in source mode. They round-trip within one mode but are not portable across a mode switch.
44
72
 
45
73
  ## Keyboard shortcuts
46
74
 
@@ -55,13 +83,7 @@ In the rich modes (`focus` / `show` / `hide`), these toggle inline formatting on
55
83
 
56
84
  ## Styling
57
85
 
58
- `@meowdown/react/style.css` includes the default theme from [`@meowdown/core`](https://www.npmjs.com/package/@meowdown/core). Colors follow the page's `color-scheme`; customize via the `--meowdown-*` CSS variables documented there. The editor reserves a horizontal gutter (`--meowdown-gutter`) so the block handle has room to the left of the hovered block.
59
-
60
- Selection colors are standalone variables (independent from `--meowdown-accent`):
61
-
62
- - `--meowdown-node-outline`: outline of a selected node (e.g. a block grabbed by its handle).
63
- - `--meowdown-node-selection`: background wash of a selected node.
64
- - `--meowdown-selection`: text `::selection` background.
86
+ `@meowdown/react/style.css` includes the default theme from [`@meowdown/core`](https://www.npmjs.com/package/@meowdown/core).
65
87
 
66
88
  ## License
67
89
 
package/dist/index.d.ts CHANGED
@@ -1,26 +1,80 @@
1
- import { Ref } from "react";
2
- import { MarkMode, MarkMode as MarkMode$1, TypedEditor } from "@meowdown/core";
1
+ import { ReactNode, Ref } from "react";
2
+ import { ImageOptions, MarkMode, MarkMode as MarkMode$1, PlaceholderOptions, RoundTripFidelity, TypedEditor, TypedEditor as TypedEditor$1, WikilinkClickHandler, checkRoundTrip } from "@meowdown/core";
3
+ import { SelectionJSON, SelectionJSON as SelectionJSON$1 } from "@prosekit/core";
4
+ import { useEditor } from "@prosekit/react";
3
5
 
4
6
  //#region src/components/types.d.ts
7
+ /** A selection to restore: an exact JSON selection, or a document edge. */
8
+ type SelectionHint = SelectionJSON$1 | 'start' | 'end';
9
+ /**
10
+ * The current Markdown and selection. Selection positions are in the mounted
11
+ * editor's coordinate space: ProseMirror positions in the rich modes,
12
+ * character offsets in source mode. Not portable across a mode switch.
13
+ */
14
+ type EditorStateSnapshot = [markdown: string, selection: SelectionJSON$1];
5
15
  interface EditorHandle {
6
16
  /**
7
17
  * Serializes the current document to Markdown. Can be expensive on large
8
18
  * documents; call it on demand (e.g. throttled) instead of on every change.
9
19
  */
10
20
  getMarkdown: () => string;
21
+ /** Replaces the whole document as a single undoable edit. */
22
+ setMarkdown: (markdown: string) => void;
23
+ /** Returns the current Markdown and selection. */
24
+ getState: () => EditorStateSnapshot;
25
+ /**
26
+ * Replaces the document (if `markdown` is given) and restores `selection`:
27
+ * exactly when valid, otherwise clamped to the nearest text selection;
28
+ * out-of-range positions never throw. Without a selection, the current one
29
+ * is mapped through the change.
30
+ */
31
+ setState: (markdown?: string, selection?: SelectionHint) => void;
32
+ /** Returns the current selection. */
33
+ getSelection: () => SelectionJSON$1;
34
+ /** Restores a selection with the same hint semantics as `setState`. */
35
+ setSelection: (selection: SelectionHint) => void;
36
+ /** Focuses the editor. */
37
+ focus: () => void;
38
+ /** Scrolls the selection into view. */
39
+ scrollIntoView: () => void;
40
+ /** Escape hatch: the underlying ProseKit editor, or `undefined` in source mode. */
41
+ readonly editor: TypedEditor$1 | undefined;
42
+ }
43
+ /**
44
+ /** One row in the tag menu. The host ranks the rows; the menu does not re-sort. */
45
+ interface TagItem {
46
+ /** Inserted as `#tag `. */
47
+ tag: string;
48
+ /** Display text; defaults to `#tag`. */
49
+ label?: string;
50
+ /** Secondary text shown beside the label. */
51
+ detail?: string;
52
+ /** Side effect run after the tag is inserted (e.g. create the tag). */
53
+ onSelect?: () => void;
11
54
  }
12
55
  /**
13
56
  * Searches tags for the tag menu. Receives the query typed after `#`
14
- * (lowercased, punctuation stripped) and returns the tags to show, either
57
+ * (lowercased, punctuation stripped) and returns the rows to show, either
15
58
  * synchronously or as a promise.
16
59
  */
17
- type TagSearchHandler = (query: string) => string[] | Promise<string[]>;
60
+ type TagSearchHandler = (query: string) => TagItem[] | Promise<TagItem[]>;
61
+ /** One row in the wikilink menu. The host ranks the rows; the menu does not re-sort. */
62
+ interface WikilinkItem {
63
+ /** Inserted as `[[target]]`. */
64
+ target: string;
65
+ /** Display text; defaults to `target`. */
66
+ label?: string;
67
+ /** Secondary text shown beside the label. */
68
+ detail?: string;
69
+ /** Side effect run after the link is inserted (e.g. create the note). */
70
+ onSelect?: () => void;
71
+ }
18
72
  /**
19
73
  * Searches notes for the wikilink menu. Receives the query typed after
20
74
  * `[[` (lowercased, punctuation stripped, may be empty or contain spaces)
21
- * and returns the note names to show, either synchronously or as a promise.
75
+ * and returns the rows to show, either synchronously or as a promise.
22
76
  */
23
- type WikilinkSearchHandler = (query: string) => string[] | Promise<string[]>;
77
+ type WikilinkSearchHandler = (query: string) => WikilinkItem[] | Promise<WikilinkItem[]>;
24
78
  //#endregion
25
79
  //#region src/components/editor.d.ts
26
80
  type EditorMode = MarkMode$1 | 'source';
@@ -56,8 +110,43 @@ interface EditorProps {
56
110
  * mode.
57
111
  */
58
112
  onWikilinkSearch?: WikilinkSearchHandler;
113
+ /**
114
+ * Called with the link target on click of a rendered wiki link. Pass a stable
115
+ * function (e.g. from `useCallback`). Ignored in source mode.
116
+ */
117
+ onWikilinkClick?: WikilinkClickHandler;
118
+ /**
119
+ * Maps an image `src` to a displayable URL (or `undefined` to skip). Enables
120
+ * inline image rendering. Pass a stable function. Ignored in source mode.
121
+ */
122
+ resolveImageUrl?: ImageOptions['resolveImageUrl'];
123
+ /**
124
+ * Persists a pasted/dropped image file and returns its markdown `src`. Pass a
125
+ * stable function. Ignored in source mode.
126
+ */
127
+ onImagePaste?: ImageOptions['onImagePaste'];
128
+ /** Called when persisting a pasted/dropped image throws. Ignored in source mode. */
129
+ onImageSaveError?: ImageOptions['onImageSaveError'];
130
+ /**
131
+ * Placeholder text shown in an empty block. A function receives the editor
132
+ * state. Pass a stable function. Ignored in source mode.
133
+ */
134
+ placeholder?: PlaceholderOptions['placeholder'];
135
+ /** Makes the editor read-only, in both the rich and source modes. */
136
+ readOnly?: boolean;
137
+ /**
138
+ * Enables the browser's native spell checking in the rich modes. Defaults
139
+ * to the browser's behavior. Ignored in source mode.
140
+ */
141
+ spellCheck?: boolean;
142
+ /** Class on the editable root (the contenteditable). Rich modes only. */
143
+ editorClassName?: string;
144
+ /** Class on the outer `.meowdown` wrapper div. */
145
+ wrapperClassName?: string;
59
146
  /** Imperative handle for the editor. */
60
147
  ref?: Ref<EditorHandle>;
148
+ /** Nodes rendered inside the editor's ProseKit context (rich modes only). */
149
+ children?: ReactNode;
61
150
  }
62
151
  declare function Editor({
63
152
  mode,
@@ -65,7 +154,17 @@ declare function Editor({
65
154
  onDocChange,
66
155
  onTagSearch,
67
156
  onWikilinkSearch,
68
- ref
157
+ onWikilinkClick,
158
+ resolveImageUrl,
159
+ onImagePaste,
160
+ onImageSaveError,
161
+ placeholder,
162
+ readOnly,
163
+ spellCheck,
164
+ editorClassName,
165
+ wrapperClassName,
166
+ ref,
167
+ children
69
168
  }: EditorProps): import("react").JSX.Element;
70
169
  //#endregion
71
- export { Editor, type EditorHandle, type EditorMode, type EditorProps, type MarkMode, type TagSearchHandler, type TypedEditor, type WikilinkSearchHandler };
170
+ export { Editor, type EditorHandle, type EditorMode, type EditorProps, type EditorStateSnapshot, type MarkMode, type RoundTripFidelity, type SelectionHint, type SelectionJSON, type TagItem, type TagSearchHandler, type TypedEditor, type WikilinkItem, type WikilinkSearchHandler, checkRoundTrip, useEditor };