@meowdown/react 0.5.0 → 0.7.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 +19 -25
- package/dist/index.d.ts +13 -10
- package/dist/index.js +58 -27
- package/dist/style.css +0 -418
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -5,8 +5,10 @@ React components for Meowdown, a hybrid (live-preview) Markdown editor.
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
7
7
|
```tsx
|
|
8
|
-
import
|
|
8
|
+
import '@meowdown/core/style.css'
|
|
9
9
|
import '@meowdown/react/style.css'
|
|
10
|
+
|
|
11
|
+
import { MeowdownEditor, type EditorHandle } from '@meowdown/react'
|
|
10
12
|
import { useRef, useCallback } from 'react'
|
|
11
13
|
|
|
12
14
|
export function App() {
|
|
@@ -15,13 +17,20 @@ export function App() {
|
|
|
15
17
|
console.log(ref.current?.getMarkdown())
|
|
16
18
|
}, [])
|
|
17
19
|
|
|
18
|
-
return
|
|
20
|
+
return (
|
|
21
|
+
<MeowdownEditor
|
|
22
|
+
handleRef={ref}
|
|
23
|
+
mode="focus"
|
|
24
|
+
initialMarkdown="# Hello"
|
|
25
|
+
onDocChange={handleDocChange}
|
|
26
|
+
/>
|
|
27
|
+
)
|
|
19
28
|
}
|
|
20
29
|
```
|
|
21
30
|
|
|
22
31
|
## API
|
|
23
32
|
|
|
24
|
-
### `<
|
|
33
|
+
### `<MeowdownEditor>`
|
|
25
34
|
|
|
26
35
|
The Markdown editor component. Renders inside a `div.meowdown` wrapper that fills a flex parent. In rich modes, typing `/` opens a slash menu for inserting blocks (headings, blockquote, lists, code block, table). Hovering a block shows a handle to its left: the plus button inserts an empty paragraph below the block, and the grip selects the block and can be dragged to move it, with a drop indicator line marking the target.
|
|
27
36
|
|
|
@@ -31,35 +40,31 @@ The Markdown editor component. Renders inside a `div.meowdown` wrapper that fill
|
|
|
31
40
|
- `'hide'`: Markdown syntax is always hidden.
|
|
32
41
|
- `'source'`: raw Markdown source with syntax highlighting.
|
|
33
42
|
- `initialMarkdown?: string`: first render only.
|
|
34
|
-
- `onDocChange?: VoidFunction`: called on every document change.
|
|
43
|
+
- `onDocChange?: VoidFunction`: called on every user-driven document change. Programmatic `setMarkdown` / `setState` on the handle do not fire it.
|
|
35
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.
|
|
36
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.
|
|
37
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.
|
|
38
47
|
- `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.
|
|
39
48
|
- `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:
|
|
41
|
-
- `placeholder?: string | ((state) => string)`: placeholder text shown
|
|
49
|
+
- `onImageSaveError?: (error: unknown, file: File) => void`: called when `onImagePaste` throws. Defaults to `console.error`. Ignored in source mode.
|
|
50
|
+
- `placeholder?: string | ((state) => string)`: placeholder text shown when the whole document is empty. Pass a stable function. Ignored in source mode.
|
|
42
51
|
- `readOnly?: boolean`: makes the editor read-only, in both the rich and source modes.
|
|
43
52
|
- `spellCheck?: boolean`: toggles the browser's native spell checking in the rich modes. Defaults to the browser's behavior. Ignored in source mode.
|
|
44
53
|
- `editorClassName?: string`: class on the editable root (the contenteditable). Rich modes only.
|
|
45
54
|
- `wrapperClassName?: string`: class on the outer `div.meowdown` wrapper.
|
|
46
|
-
- `
|
|
55
|
+
- `handleRef?: Ref<EditorHandle>`
|
|
47
56
|
- `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
57
|
|
|
49
58
|
### `useEditor`
|
|
50
59
|
|
|
51
60
|
Re-exported from `@prosekit/react`. Call it from a component passed as `children` to read the live editor instance.
|
|
52
61
|
|
|
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.
|
|
56
|
-
|
|
57
62
|
### `EditorHandle`
|
|
58
63
|
|
|
59
|
-
Imperative handle for the editor, attached via `
|
|
64
|
+
Imperative handle for the editor, attached via `handleRef`.
|
|
60
65
|
|
|
61
66
|
- `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.
|
|
67
|
+
- `setMarkdown(markdown: string): void`: replaces the whole document as a single undoable edit. Does not fire `onDocChange`.
|
|
63
68
|
- `getState(): EditorStateSnapshot`: returns `[markdown, selection]`, where `selection` is a `SelectionJSON` (`{ anchor: number, head: number, type: string }`).
|
|
64
69
|
- `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
70
|
- `getSelection(): SelectionJSON`: returns the current selection.
|
|
@@ -70,20 +75,9 @@ Imperative handle for the editor, attached via `ref`.
|
|
|
70
75
|
|
|
71
76
|
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.
|
|
72
77
|
|
|
73
|
-
## Keyboard shortcuts
|
|
74
|
-
|
|
75
|
-
In the rich modes (`focus` / `show` / `hide`), these toggle inline formatting on the selection (`Mod` = Cmd on macOS, Ctrl elsewhere):
|
|
76
|
-
|
|
77
|
-
| Key | Action |
|
|
78
|
-
| ------------- | -------------------- |
|
|
79
|
-
| `Mod-B` | toggle bold |
|
|
80
|
-
| `Mod-I` | toggle italic |
|
|
81
|
-
| `Mod-E` | toggle inline code |
|
|
82
|
-
| `Mod-Shift-X` | toggle strikethrough |
|
|
83
|
-
|
|
84
78
|
## Styling
|
|
85
79
|
|
|
86
|
-
`@meowdown/react/style.css`
|
|
80
|
+
Import both stylesheets: `@meowdown/core/style.css` (the editor theme and variables) and `@meowdown/react/style.css` (the component layout). The core theme is documented in [`@meowdown/core`](https://www.npmjs.com/package/@meowdown/core).
|
|
87
81
|
|
|
88
82
|
## License
|
|
89
83
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode, Ref } from "react";
|
|
2
|
-
import { ImageOptions, MarkMode,
|
|
2
|
+
import { ImageOptions, MarkMode, PlaceholderOptions, TypedEditor, WikilinkClickHandler } from "@meowdown/core";
|
|
3
3
|
import { SelectionJSON, SelectionJSON as SelectionJSON$1 } from "@prosekit/core";
|
|
4
4
|
import { useEditor } from "@prosekit/react";
|
|
5
5
|
|
|
@@ -38,7 +38,7 @@ interface EditorHandle {
|
|
|
38
38
|
/** Scrolls the selection into view. */
|
|
39
39
|
scrollIntoView: () => void;
|
|
40
40
|
/** Escape hatch: the underlying ProseKit editor, or `undefined` in source mode. */
|
|
41
|
-
readonly editor: TypedEditor
|
|
41
|
+
readonly editor: TypedEditor | undefined;
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
44
|
/** One row in the tag menu. The host ranks the rows; the menu does not re-sort. */
|
|
@@ -77,7 +77,7 @@ interface WikilinkItem {
|
|
|
77
77
|
type WikilinkSearchHandler = (query: string) => WikilinkItem[] | Promise<WikilinkItem[]>;
|
|
78
78
|
//#endregion
|
|
79
79
|
//#region src/components/editor.d.ts
|
|
80
|
-
type EditorMode = MarkMode
|
|
80
|
+
type EditorMode = MarkMode | 'source';
|
|
81
81
|
interface EditorProps {
|
|
82
82
|
/**
|
|
83
83
|
* The editor mode. The three rich modes ('focus', 'show', 'hide') render a ProseKit
|
|
@@ -91,7 +91,10 @@ interface EditorProps {
|
|
|
91
91
|
* first render is used; later changes are ignored.
|
|
92
92
|
*/
|
|
93
93
|
initialMarkdown?: string;
|
|
94
|
-
/**
|
|
94
|
+
/**
|
|
95
|
+
* Called on every user-driven document change. Programmatic `setMarkdown` and
|
|
96
|
+
* `setState` on the handle do not fire it.
|
|
97
|
+
*/
|
|
95
98
|
onDocChange?: VoidFunction;
|
|
96
99
|
/**
|
|
97
100
|
* Searches tags for the tag menu, which opens when typing `#` followed by
|
|
@@ -128,8 +131,8 @@ interface EditorProps {
|
|
|
128
131
|
/** Called when persisting a pasted/dropped image throws. Ignored in source mode. */
|
|
129
132
|
onImageSaveError?: ImageOptions['onImageSaveError'];
|
|
130
133
|
/**
|
|
131
|
-
* Placeholder text shown
|
|
132
|
-
* state. Pass a stable function. Ignored in source mode.
|
|
134
|
+
* Placeholder text shown when the whole document is empty. A function
|
|
135
|
+
* receives the editor state. Pass a stable function. Ignored in source mode.
|
|
133
136
|
*/
|
|
134
137
|
placeholder?: PlaceholderOptions['placeholder'];
|
|
135
138
|
/** Makes the editor read-only, in both the rich and source modes. */
|
|
@@ -144,11 +147,11 @@ interface EditorProps {
|
|
|
144
147
|
/** Class on the outer `.meowdown` wrapper div. */
|
|
145
148
|
wrapperClassName?: string;
|
|
146
149
|
/** Imperative handle for the editor. */
|
|
147
|
-
|
|
150
|
+
handleRef?: Ref<EditorHandle>;
|
|
148
151
|
/** Nodes rendered inside the editor's ProseKit context (rich modes only). */
|
|
149
152
|
children?: ReactNode;
|
|
150
153
|
}
|
|
151
|
-
declare function
|
|
154
|
+
declare function MeowdownEditor({
|
|
152
155
|
mode,
|
|
153
156
|
initialMarkdown,
|
|
154
157
|
onDocChange,
|
|
@@ -163,8 +166,8 @@ declare function Editor({
|
|
|
163
166
|
spellCheck,
|
|
164
167
|
editorClassName,
|
|
165
168
|
wrapperClassName,
|
|
166
|
-
|
|
169
|
+
handleRef,
|
|
167
170
|
children
|
|
168
171
|
}: EditorProps): import("react").JSX.Element;
|
|
169
172
|
//#endregion
|
|
170
|
-
export {
|
|
173
|
+
export { type EditorHandle, type EditorMode, type EditorProps, type EditorStateSnapshot, MeowdownEditor, type SelectionHint, type SelectionJSON, type TagItem, type TagSearchHandler, type WikilinkItem, type WikilinkSearchHandler, useEditor };
|
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 {
|
|
10
|
+
import { codeBlockLanguages, defineEditorExtension, defineImages, 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, useExtension } from "@prosekit/react";
|
|
@@ -26,6 +26,7 @@ function CodeMirrorEditor({ initialMarkdown, onDocChange, readOnly, ref }) {
|
|
|
26
26
|
const containerRef = useRef(null);
|
|
27
27
|
const viewRef = useRef(null);
|
|
28
28
|
const readOnlyCompartmentRef = useRef(new Compartment());
|
|
29
|
+
const suppressDocChangeRef = useRef(false);
|
|
29
30
|
const onDocChangeRef = useRef(onDocChange);
|
|
30
31
|
useLayoutEffect(() => {
|
|
31
32
|
onDocChangeRef.current = onDocChange;
|
|
@@ -55,15 +56,20 @@ function CodeMirrorEditor({ initialMarkdown, onDocChange, readOnly, ref }) {
|
|
|
55
56
|
}
|
|
56
57
|
if (markdown == null && !selection) return;
|
|
57
58
|
const docLength = markdown == null ? view.state.doc.length : markdown.length;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
suppressDocChangeRef.current = true;
|
|
60
|
+
try {
|
|
61
|
+
view.dispatch({
|
|
62
|
+
changes: markdown == null ? void 0 : {
|
|
63
|
+
from: 0,
|
|
64
|
+
to: view.state.doc.length,
|
|
65
|
+
insert: markdown
|
|
66
|
+
},
|
|
67
|
+
selection: selection ? resolveSelection$1(selection, docLength) : void 0,
|
|
68
|
+
scrollIntoView: true
|
|
69
|
+
});
|
|
70
|
+
} finally {
|
|
71
|
+
suppressDocChangeRef.current = false;
|
|
72
|
+
}
|
|
67
73
|
}
|
|
68
74
|
function setMarkdown(markdown) {
|
|
69
75
|
setState(markdown);
|
|
@@ -104,7 +110,7 @@ function CodeMirrorEditor({ initialMarkdown, onDocChange, readOnly, ref }) {
|
|
|
104
110
|
EditorView.lineWrapping,
|
|
105
111
|
readOnlyCompartmentRef.current.of(EditorState.readOnly.of(initialReadOnlyRef.current)),
|
|
106
112
|
EditorView.updateListener.of((update) => {
|
|
107
|
-
if (!update.docChanged) return;
|
|
113
|
+
if (!update.docChanged || suppressDocChangeRef.current) return;
|
|
108
114
|
onDocChangeRef.current?.();
|
|
109
115
|
})
|
|
110
116
|
]
|
|
@@ -429,22 +435,34 @@ function DropIndicator$1() {
|
|
|
429
435
|
//#endregion
|
|
430
436
|
//#region src/components/editor-extensions.tsx
|
|
431
437
|
function EditorExtensions({ markMode, onDocChange, onWikilinkClick, resolveImageUrl, onImagePaste, onImageSaveError, placeholder, readOnly }) {
|
|
432
|
-
useExtension(useMemo(() =>
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
useExtension(useMemo(() =>
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
}
|
|
438
|
+
useExtension(useMemo(() => {
|
|
439
|
+
return defineMarkMode(markMode);
|
|
440
|
+
}, [markMode]));
|
|
441
|
+
useExtension(useMemo(() => {
|
|
442
|
+
return readOnly ? defineReadonly() : null;
|
|
443
|
+
}, [readOnly]));
|
|
444
|
+
useExtension(useMemo(() => {
|
|
445
|
+
return onDocChange ? defineDocChangeHandler(onDocChange) : null;
|
|
446
|
+
}, [onDocChange]));
|
|
447
|
+
useExtension(useMemo(() => {
|
|
448
|
+
return onWikilinkClick ? defineWikilinkClickHandler(onWikilinkClick) : null;
|
|
449
|
+
}, [onWikilinkClick]));
|
|
450
|
+
useExtension(useMemo(() => {
|
|
451
|
+
return resolveImageUrl ? defineImages({
|
|
452
|
+
resolveImageUrl,
|
|
453
|
+
onImagePaste,
|
|
454
|
+
onImageSaveError
|
|
455
|
+
}) : null;
|
|
456
|
+
}, [
|
|
441
457
|
resolveImageUrl,
|
|
442
458
|
onImagePaste,
|
|
443
459
|
onImageSaveError
|
|
444
460
|
]));
|
|
445
461
|
useExtension(useMemo(() => {
|
|
446
|
-
|
|
447
|
-
|
|
462
|
+
return placeholder ? definePlaceholder({
|
|
463
|
+
placeholder,
|
|
464
|
+
strategy: "doc"
|
|
465
|
+
}) : null;
|
|
448
466
|
}, [placeholder]));
|
|
449
467
|
return null;
|
|
450
468
|
}
|
|
@@ -686,6 +704,7 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
|
|
|
686
704
|
if (initialMarkdown) editor.setContent(markdownToDoc(editor, initialMarkdown));
|
|
687
705
|
return editor;
|
|
688
706
|
});
|
|
707
|
+
const suppressDocChangeRef = useRef(false);
|
|
689
708
|
useImperativeHandle(ref, () => {
|
|
690
709
|
function getMarkdown() {
|
|
691
710
|
return docToMarkdown(editor.state.doc);
|
|
@@ -704,7 +723,12 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
|
|
|
704
723
|
transaction.replaceWith(0, transaction.doc.content.size, doc.content);
|
|
705
724
|
}
|
|
706
725
|
if (selection) transaction.setSelection(resolveSelection(transaction.doc, selection)).scrollIntoView();
|
|
707
|
-
|
|
726
|
+
suppressDocChangeRef.current = true;
|
|
727
|
+
try {
|
|
728
|
+
editor.view.dispatch(transaction);
|
|
729
|
+
} finally {
|
|
730
|
+
suppressDocChangeRef.current = false;
|
|
731
|
+
}
|
|
708
732
|
}
|
|
709
733
|
function setMarkdown(markdown) {
|
|
710
734
|
setState(markdown);
|
|
@@ -730,6 +754,13 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
|
|
|
730
754
|
editor
|
|
731
755
|
};
|
|
732
756
|
}, [editor]);
|
|
757
|
+
const handleDocChange = useMemo(() => {
|
|
758
|
+
if (!onDocChange) return void 0;
|
|
759
|
+
return () => {
|
|
760
|
+
if (suppressDocChangeRef.current) return;
|
|
761
|
+
onDocChange();
|
|
762
|
+
};
|
|
763
|
+
}, [onDocChange]);
|
|
733
764
|
return /* @__PURE__ */ jsxs(ProseKit, {
|
|
734
765
|
editor,
|
|
735
766
|
children: [
|
|
@@ -740,7 +771,7 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
|
|
|
740
771
|
}),
|
|
741
772
|
/* @__PURE__ */ jsx(EditorExtensions, {
|
|
742
773
|
markMode,
|
|
743
|
-
onDocChange,
|
|
774
|
+
onDocChange: handleDocChange,
|
|
744
775
|
onWikilinkClick,
|
|
745
776
|
resolveImageUrl,
|
|
746
777
|
onImagePaste,
|
|
@@ -760,9 +791,9 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
|
|
|
760
791
|
|
|
761
792
|
//#endregion
|
|
762
793
|
//#region src/components/editor.tsx
|
|
763
|
-
function
|
|
794
|
+
function MeowdownEditor({ mode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, resolveImageUrl, onImagePaste, onImageSaveError, placeholder, readOnly, spellCheck, editorClassName, wrapperClassName, handleRef, children }) {
|
|
764
795
|
const childRef = useRef(null);
|
|
765
|
-
useImperativeHandle(
|
|
796
|
+
useImperativeHandle(handleRef, () => {
|
|
766
797
|
function getMarkdown() {
|
|
767
798
|
return childRef.current?.getMarkdown() ?? "";
|
|
768
799
|
}
|
|
@@ -838,4 +869,4 @@ function Editor({ mode = "focus", initialMarkdown, onDocChange, onTagSearch, onW
|
|
|
838
869
|
}
|
|
839
870
|
|
|
840
871
|
//#endregion
|
|
841
|
-
export {
|
|
872
|
+
export { MeowdownEditor, useEditor };
|
package/dist/style.css
CHANGED
|
@@ -323,424 +323,6 @@
|
|
|
323
323
|
flex-shrink: 0;
|
|
324
324
|
font-size: .8125rem;
|
|
325
325
|
}
|
|
326
|
-
.ProseMirror {
|
|
327
|
-
word-wrap: break-word;
|
|
328
|
-
white-space: pre-wrap;
|
|
329
|
-
white-space: break-spaces;
|
|
330
|
-
-webkit-font-variant-ligatures: none;
|
|
331
|
-
font-variant-ligatures: none;
|
|
332
|
-
font-feature-settings: "liga" 0;
|
|
333
|
-
position: relative;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
.ProseMirror pre {
|
|
337
|
-
white-space: pre-wrap;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
.ProseMirror li {
|
|
341
|
-
position: relative;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
.ProseMirror-hideselection ::selection {
|
|
345
|
-
background: none;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
.ProseMirror-hideselection {
|
|
349
|
-
caret-color: #0000;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
.ProseMirror [draggable][contenteditable="false"] {
|
|
353
|
-
user-select: text;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
.ProseMirror-selectednode {
|
|
357
|
-
outline: 2px solid #8cf;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
li.ProseMirror-selectednode {
|
|
361
|
-
outline: none;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
li.ProseMirror-selectednode:after {
|
|
365
|
-
content: "";
|
|
366
|
-
pointer-events: none;
|
|
367
|
-
border: 2px solid #8cf;
|
|
368
|
-
position: absolute;
|
|
369
|
-
inset: -2px -2px -2px -32px;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
img.ProseMirror-separator {
|
|
373
|
-
border: none !important;
|
|
374
|
-
margin: 0 !important;
|
|
375
|
-
display: inline !important;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
:root {
|
|
379
|
-
--prosekit-list-bullet-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='2.5' fill='currentColor'/%3E%3C/svg%3E");
|
|
380
|
-
--prosekit-list-toggle-open-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpolygon points='8,10 12,14 16,10' fill='currentColor'/%3E%3C/svg%3E");
|
|
381
|
-
--prosekit-list-toggle-closed-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpolygon points='10,8 14,12 10,16' fill='currentColor'/%3E%3C/svg%3E");
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
.prosemirror-flat-list {
|
|
385
|
-
margin: 0;
|
|
386
|
-
padding: 0;
|
|
387
|
-
list-style: none;
|
|
388
|
-
position: relative;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
.prosemirror-flat-list > .list-marker {
|
|
392
|
-
text-align: center;
|
|
393
|
-
width: 1lh;
|
|
394
|
-
height: 1lh;
|
|
395
|
-
position: absolute;
|
|
396
|
-
inset-inline-start: 0;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
.prosemirror-flat-list > .list-content {
|
|
400
|
-
margin-inline-start: 1lh;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
.prosemirror-flat-list[data-list-kind="bullet"] > .list-marker, .prosemirror-flat-list[data-list-kind="toggle"] > .list-marker {
|
|
404
|
-
background-color: currentColor;
|
|
405
|
-
mask-position: center;
|
|
406
|
-
mask-size: contain;
|
|
407
|
-
mask-repeat: no-repeat;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
.prosemirror-flat-list[data-list-kind="bullet"] > .list-marker {
|
|
411
|
-
mask-image: var(--prosekit-list-bullet-icon);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
.prosemirror-flat-list[data-list-kind="toggle"] > .list-marker {
|
|
415
|
-
mask-image: var(--prosekit-list-toggle-open-icon);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
.prosemirror-flat-list[data-list-kind="toggle"][data-list-collapsable][data-list-collapsed] > .list-marker {
|
|
419
|
-
mask-image: var(--prosekit-list-toggle-closed-icon);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
.prosemirror-flat-list[data-list-kind="ordered"] > * {
|
|
423
|
-
contain: style;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
.prosemirror-flat-list[data-list-kind="ordered"]:before {
|
|
427
|
-
content: counter(prosemirror-flat-list-counter, decimal) ". ";
|
|
428
|
-
font-variant-numeric: tabular-nums;
|
|
429
|
-
position: absolute;
|
|
430
|
-
inset-inline-end: calc(100% - 1lh);
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
.prosemirror-flat-list[data-list-kind="ordered"] {
|
|
434
|
-
counter-increment: prosemirror-flat-list-counter;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
.prosemirror-flat-list[data-list-kind="ordered"]:first-child, :not(.prosemirror-flat-list[data-list-kind="ordered"]) + .prosemirror-flat-list[data-list-kind="ordered"] {
|
|
438
|
-
counter-reset: prosemirror-flat-list-counter;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
@supports (counter-set: prosemirror-flat-list-counter 1) {
|
|
442
|
-
:is(.prosemirror-flat-list[data-list-kind="ordered"]:first-child, :not(.prosemirror-flat-list[data-list-kind="ordered"]) + .prosemirror-flat-list[data-list-kind="ordered"])[data-list-order] {
|
|
443
|
-
counter-set: prosemirror-flat-list-counter var(--prosemirror-flat-list-order);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
@supports not (counter-set: prosemirror-flat-list-counter 1) {
|
|
448
|
-
:is(.prosemirror-flat-list[data-list-kind="ordered"]:first-child, :not(.prosemirror-flat-list[data-list-kind="ordered"]) + .prosemirror-flat-list[data-list-kind="ordered"])[data-list-order] {
|
|
449
|
-
counter-increment: prosemirror-flat-list-counter var(--prosemirror-flat-list-order);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
.prosemirror-flat-list[data-list-kind="task"] > .list-marker, .prosemirror-flat-list[data-list-kind="task"] > .list-marker * {
|
|
454
|
-
cursor: pointer;
|
|
455
|
-
justify-content: center;
|
|
456
|
-
align-items: center;
|
|
457
|
-
margin: 0;
|
|
458
|
-
padding: 0;
|
|
459
|
-
display: flex;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
.prosemirror-flat-list[data-list-kind="toggle"][data-list-collapsable] > .list-marker {
|
|
463
|
-
cursor: pointer;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
.prosemirror-flat-list[data-list-kind="toggle"]:not([data-list-collapsable]) > .list-marker {
|
|
467
|
-
opacity: .4;
|
|
468
|
-
pointer-events: none;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
.prosemirror-flat-list[data-list-kind="toggle"][data-list-collapsable][data-list-collapsed] > .list-content > :nth-child(n+2) {
|
|
472
|
-
display: none;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
:root {
|
|
476
|
-
--meowdown-text: light-dark(#3f3f46, #d4d4d8);
|
|
477
|
-
--meowdown-heading: light-dark(#18181b, #fafafa);
|
|
478
|
-
--meowdown-muted: light-dark(#52525b, #a1a1aa);
|
|
479
|
-
--meowdown-accent: light-dark(#7c3aed, #c084fc);
|
|
480
|
-
--meowdown-mark: light-dark(#a78bfa, #8b5cf6);
|
|
481
|
-
--meowdown-border: light-dark(#e4e4e7, #3f3f46);
|
|
482
|
-
--meowdown-code-bg: light-dark(#f4f4f5, #18181b);
|
|
483
|
-
--meowdown-table-header-bg: light-dark(#fafafa, #27272a);
|
|
484
|
-
--meowdown-font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
485
|
-
--meowdown-node-outline: light-dark(#53f, #8870ff);
|
|
486
|
-
--meowdown-node-selection: light-dark(#5533ff1a, #8870ff1f);
|
|
487
|
-
--meowdown-selection: light-dark(#5533ff38, #8870ff4d);
|
|
488
|
-
--meowdown-gutter: 3.5rem;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
.ProseMirror {
|
|
492
|
-
box-sizing: border-box;
|
|
493
|
-
padding: 1.25rem var(--meowdown-gutter) 1.75rem;
|
|
494
|
-
color: var(--meowdown-text);
|
|
495
|
-
caret-color: var(--meowdown-accent);
|
|
496
|
-
-webkit-font-smoothing: antialiased;
|
|
497
|
-
outline: none;
|
|
498
|
-
font-size: 1.0625rem;
|
|
499
|
-
line-height: 1.7;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
.ProseMirror > * + * {
|
|
503
|
-
margin-top: .85em;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
.ProseMirror h1, .ProseMirror h2, .ProseMirror h3, .ProseMirror h4, .ProseMirror h5, .ProseMirror h6 {
|
|
507
|
-
letter-spacing: -.01em;
|
|
508
|
-
color: var(--meowdown-heading);
|
|
509
|
-
font-weight: 600;
|
|
510
|
-
line-height: 1.25;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
.ProseMirror h1 {
|
|
514
|
-
font-size: 1.75rem;
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
.ProseMirror h2 {
|
|
518
|
-
font-size: 1.4rem;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
.ProseMirror h3 {
|
|
522
|
-
font-size: 1.2rem;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
.ProseMirror h4 {
|
|
526
|
-
font-size: 1.1rem;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
.ProseMirror h5 {
|
|
530
|
-
font-size: 1rem;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
.ProseMirror h6 {
|
|
534
|
-
font-size: .95rem;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
.ProseMirror a {
|
|
538
|
-
color: var(--meowdown-accent);
|
|
539
|
-
text-underline-offset: 2px;
|
|
540
|
-
text-decoration: underline 1px;
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
.ProseMirror code {
|
|
544
|
-
font-family: var(--meowdown-font-mono);
|
|
545
|
-
background: color-mix(in oklab, var(--meowdown-accent) 10%, transparent);
|
|
546
|
-
color: color-mix(in oklab, var(--meowdown-accent) 80%, var(--meowdown-heading));
|
|
547
|
-
border-radius: .35rem;
|
|
548
|
-
padding: .1em .35em;
|
|
549
|
-
font-size: .9em;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
.ProseMirror blockquote {
|
|
553
|
-
border-left: 3px solid color-mix(in oklab, var(--meowdown-accent) 35%, transparent);
|
|
554
|
-
color: var(--meowdown-muted);
|
|
555
|
-
margin-left: 0;
|
|
556
|
-
padding-left: 1rem;
|
|
557
|
-
font-style: italic;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
.ProseMirror ul, .ProseMirror ol {
|
|
561
|
-
padding-left: 1.5rem;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
.ProseMirror ul {
|
|
565
|
-
list-style: outside;
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
.ProseMirror ol {
|
|
569
|
-
list-style: decimal;
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
.ProseMirror li {
|
|
573
|
-
margin-top: .25em;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
.ProseMirror pre {
|
|
577
|
-
background: var(--meowdown-code-bg);
|
|
578
|
-
font-family: var(--meowdown-font-mono);
|
|
579
|
-
border-radius: .6rem;
|
|
580
|
-
padding: .9rem 1rem;
|
|
581
|
-
font-size: .9em;
|
|
582
|
-
line-height: 1.5;
|
|
583
|
-
overflow-x: auto;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
.ProseMirror pre code {
|
|
587
|
-
color: inherit;
|
|
588
|
-
background: none;
|
|
589
|
-
padding: 0;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
.ProseMirror pre code .tok-keyword {
|
|
593
|
-
color: light-dark(#cf222e, #ff7b72);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
.ProseMirror pre code .tok-comment {
|
|
597
|
-
color: light-dark(#6e7781, #8b949e);
|
|
598
|
-
font-style: italic;
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
.ProseMirror pre code .tok-string, .ProseMirror pre code .tok-url {
|
|
602
|
-
color: light-dark(#0a3069, #a5d6ff);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
.ProseMirror pre code .tok-number, .ProseMirror pre code .tok-bool, .ProseMirror pre code .tok-atom, .ProseMirror pre code .tok-literal {
|
|
606
|
-
color: light-dark(#0550ae, #79c0ff);
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
.ProseMirror pre code .tok-className, .ProseMirror pre code .tok-typeName, .ProseMirror pre code .tok-namespace {
|
|
610
|
-
color: light-dark(#953800, #ffa657);
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
.ProseMirror pre code .tok-definition {
|
|
614
|
-
color: light-dark(#8250df, #d2a8ff);
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
.ProseMirror pre code .tok-macroName, .ProseMirror pre code .tok-meta, .ProseMirror pre code .tok-inserted {
|
|
618
|
-
color: light-dark(#116329, #7ee787);
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
.ProseMirror pre code .tok-invalid, .ProseMirror pre code .tok-deleted {
|
|
622
|
-
color: light-dark(#82071e, #ffa198);
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
.ProseMirror pre code .tok-heading {
|
|
626
|
-
color: light-dark(#0550ae, #79c0ff);
|
|
627
|
-
font-weight: 600;
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
.ProseMirror pre code .tok-strong {
|
|
631
|
-
font-weight: 600;
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
.ProseMirror pre code .tok-emphasis {
|
|
635
|
-
font-style: italic;
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
.ProseMirror pre code .tok-link {
|
|
639
|
-
text-decoration: underline;
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
.ProseMirror hr {
|
|
643
|
-
border: none;
|
|
644
|
-
border-top: 1px solid var(--meowdown-border);
|
|
645
|
-
margin: 1.5em 0;
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
.ProseMirror table {
|
|
649
|
-
border-collapse: collapse;
|
|
650
|
-
table-layout: fixed;
|
|
651
|
-
width: 100%;
|
|
652
|
-
overflow: hidden;
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
.ProseMirror td, .ProseMirror th {
|
|
656
|
-
box-sizing: border-box;
|
|
657
|
-
border: 1px solid var(--meowdown-border);
|
|
658
|
-
vertical-align: top;
|
|
659
|
-
text-align: left;
|
|
660
|
-
padding: .4rem .75rem;
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
.ProseMirror th {
|
|
664
|
-
color: var(--meowdown-heading);
|
|
665
|
-
background: var(--meowdown-table-header-bg);
|
|
666
|
-
font-weight: 600;
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
.ProseMirror table.ProseMirror-selectednode td, .ProseMirror table.ProseMirror-selectednode th {
|
|
670
|
-
border-color: var(--meowdown-node-outline);
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
.ProseMirror .selectedCell {
|
|
674
|
-
border: 1px double var(--meowdown-node-outline);
|
|
675
|
-
background: var(--meowdown-node-selection);
|
|
676
|
-
--meowdown-selection: transparent;
|
|
677
|
-
caret-color: #0000;
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
.ProseMirror ::selection {
|
|
681
|
-
background: var(--meowdown-selection);
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
.ProseMirror .ProseMirror-selectednode {
|
|
685
|
-
--meowdown-selection: transparent;
|
|
686
|
-
outline: 1px solid var(--meowdown-node-outline);
|
|
687
|
-
background: var(--meowdown-node-selection);
|
|
688
|
-
border-radius: 2px;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
.ProseMirror pre.ProseMirror-selectednode {
|
|
692
|
-
border-radius: .6rem;
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
.ProseMirror.prosekit-dragging {
|
|
696
|
-
--meowdown-node-selection: transparent;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
.ProseMirror .md-tag {
|
|
700
|
-
background: color-mix(in oklab, var(--meowdown-accent) 10%, transparent);
|
|
701
|
-
color: color-mix(in oklab, var(--meowdown-accent) 80%, var(--meowdown-heading));
|
|
702
|
-
border-radius: .35rem;
|
|
703
|
-
padding: .1em .35em;
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
.ProseMirror .md-wikilink {
|
|
707
|
-
color: var(--meowdown-accent);
|
|
708
|
-
text-underline-offset: 2px;
|
|
709
|
-
cursor: pointer;
|
|
710
|
-
text-decoration: underline 1px dashed;
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
.ProseMirror .md-image {
|
|
714
|
-
display: block;
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
.ProseMirror .md-image img {
|
|
718
|
-
max-height: var(--meowdown-image-max-height, 24rem);
|
|
719
|
-
border-radius: var(--meowdown-image-radius, .5rem);
|
|
720
|
-
max-width: 100%;
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
.ProseMirror .prosekit-placeholder:before {
|
|
724
|
-
content: attr(data-placeholder);
|
|
725
|
-
float: left;
|
|
726
|
-
pointer-events: none;
|
|
727
|
-
height: 0;
|
|
728
|
-
color: var(--meowdown-placeholder, var(--meowdown-muted));
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
.ProseMirror .md-mark, .ProseMirror .md-link-uri {
|
|
732
|
-
color: var(--meowdown-mark);
|
|
733
|
-
opacity: .7;
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
.ProseMirror[data-mark-mode="hide"] .md-mark, .ProseMirror[data-mark-mode="hide"] .md-link-uri, .ProseMirror[data-mark-mode="focus"] .md-mark, .ProseMirror[data-mark-mode="focus"] .md-link-uri {
|
|
737
|
-
display: none;
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
.ProseMirror[data-mark-mode="focus"] .md-mark:has(.show), .ProseMirror[data-mark-mode="focus"] .md-link-uri:has(.show) {
|
|
741
|
-
display: inline;
|
|
742
|
-
}
|
|
743
|
-
|
|
744
326
|
.meowdown {
|
|
745
327
|
flex-direction: column;
|
|
746
328
|
flex: 1 0 auto;
|
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.7.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@prosekit/pm": "^0.1.18",
|
|
29
29
|
"@prosekit/react": "^0.8.0-beta.0",
|
|
30
30
|
"clsx": "^2.1.1",
|
|
31
|
-
"@meowdown/core": "0.
|
|
31
|
+
"@meowdown/core": "0.7.0"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"react": "^19.0.0",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@css-modules-kit/codegen": "^1.
|
|
46
|
+
"@css-modules-kit/codegen": "^1.3.0",
|
|
47
47
|
"@ocavue/tsconfig": "^0.7.1",
|
|
48
48
|
"@tsdown/css": "^0.22.2",
|
|
49
49
|
"@types/react": "^19.2.17",
|