@meowdown/react 0.63.1 → 0.64.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 +17 -118
- package/dist/index.js +13 -10
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -27,9 +27,6 @@ export function App() {
|
|
|
27
27
|
## Usage
|
|
28
28
|
|
|
29
29
|
```tsx
|
|
30
|
-
import '@meowdown/core/style.css'
|
|
31
|
-
import '@meowdown/react/style.css'
|
|
32
|
-
|
|
33
30
|
import { MeowdownEditor, type EditorHandle } from '@meowdown/react'
|
|
34
31
|
import { useRef, useCallback } from 'react'
|
|
35
32
|
|
|
@@ -50,125 +47,27 @@ export function App() {
|
|
|
50
47
|
}
|
|
51
48
|
```
|
|
52
49
|
|
|
53
|
-
##
|
|
54
|
-
|
|
55
|
-
See the full API reference [here](https://npmx.dev/package-docs/@meowdown%2Freact/).
|
|
56
|
-
|
|
57
|
-
Slash menu host items can include `keywords` to match hidden terms without changing the displayed label.
|
|
58
|
-
|
|
59
|
-
The caret glides between positions by default; pass `caretGlide={false}` to move it instantly (hosts can also tune the duration via the `--meowdown-caret-glide` CSS variable).
|
|
60
|
-
|
|
61
|
-
`MarkdownView` folds collapsed (`+`) bullets like the editor; pass `expandCollapsed` to render them expanded at every depth, for views that show slices of a note (e.g. a backlinks panel) where the source's fold state must not hide the content the view exists to show.
|
|
62
|
-
|
|
63
|
-
Both `MeowdownEditor` and `MarkdownView` resolve CommonMark full, collapsed,
|
|
64
|
-
and shortcut reference links and images. The editor keeps reference definitions
|
|
65
|
-
visible as editable source and preserves them through `getMarkdown()`.
|
|
66
|
-
`MarkdownView` uses the same first-definition-wins resolution but omits
|
|
67
|
-
definition paragraphs from its rendered output. Reference links are read-only
|
|
68
|
-
in the editor's link menu; edit their definition source to change the target.
|
|
69
|
-
|
|
70
|
-
### Wiki embeds
|
|
71
|
-
|
|
72
|
-
Obsidian-style wiki embeds (`![[path]]`, with optional `|width` or
|
|
73
|
-
`|widthxheight`) stay literal and editable unless the host classifies them.
|
|
74
|
-
`resolveWikiEmbed` is a pure, creation-time resolver: return an image, file, or
|
|
75
|
-
note result to reuse the corresponding Meowdown atom and its existing click
|
|
76
|
-
hook; return `undefined` for missing or ambiguous targets.
|
|
77
|
-
|
|
78
|
-
```tsx
|
|
79
|
-
<MeowdownEditor
|
|
80
|
-
initialMarkdown="![[assets/photo.png|320]]"
|
|
81
|
-
resolveWikiEmbed={({ target }) => (target.endsWith('.png') ? { kind: 'image' } : undefined)}
|
|
82
|
-
resolveImageUrl={resolveLocalImageUrl}
|
|
83
|
-
onImageClick={openLightbox}
|
|
84
|
-
/>
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Use `EditorHandle.revealHeading('#Section%20name')` to move the selection to a
|
|
88
|
-
matching heading and scroll it into view after following a heading link.
|
|
50
|
+
## Components
|
|
89
51
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
```tsx
|
|
96
|
-
<MarkdownView
|
|
97
|
-
markdown="[Quarterly report](docs/report.pdf)"
|
|
98
|
-
resolveFileLink={({ href }) => href.startsWith('docs/')}
|
|
99
|
-
resolveFileInfo={resolveLocalFileInfo}
|
|
100
|
-
onFileClick={openLocalFile}
|
|
101
|
-
/>
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
### Find in document
|
|
105
|
-
|
|
106
|
-
`searchQuery` highlights every match and selects the first one at or after the
|
|
107
|
-
caret; changing it re-anchors from wherever the selection is, so refining a
|
|
108
|
-
query keeps the match the user is looking at. A query that matches nothing
|
|
109
|
-
collapses the previous match selection to a caret, and an empty string (the
|
|
110
|
-
default) clears the highlights and leaves the selection alone. `onSearchChange` reports
|
|
111
|
-
`{ total, active }` for a match counter (`active` is one-based; `0` means the
|
|
112
|
-
selection is not on a match), and `EditorHandle.findNext()` /
|
|
113
|
-
`EditorHandle.findPrevious()` walk the matches and wrap at the document edges.
|
|
114
|
-
The query is applied through `useDeferredValue`, so fast typing may skip
|
|
115
|
-
intermediate values on a slow device.
|
|
116
|
-
|
|
117
|
-
```tsx
|
|
118
|
-
const [query, setQuery] = useState('')
|
|
119
|
-
const [status, setStatus] = useState({ total: 0, active: 0 })
|
|
120
|
-
|
|
121
|
-
<input value={query} onChange={(event) => setQuery(event.target.value)} />
|
|
122
|
-
<span>{status.active} / {status.total}</span>
|
|
123
|
-
<MeowdownEditor
|
|
124
|
-
handleRef={editorRef}
|
|
125
|
-
searchQuery={query}
|
|
126
|
-
onSearchChange={setStatus}
|
|
127
|
-
/>
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### Wiki-link hover cards
|
|
131
|
-
|
|
132
|
-
Mount `WikilinkHoverCard` inside `MeowdownEditor` and render host-owned preview
|
|
133
|
-
content from the hovered wiki link's `target`. Returning `null` renders no
|
|
134
|
-
card. The render function may also return a promise: the card stays closed
|
|
135
|
-
until it resolves, resolving to `null` (or rejecting) renders no card, and a
|
|
136
|
-
result that lands after the pointer moved on is discarded, so a host can look
|
|
137
|
-
up local content without ever flashing an empty card.
|
|
138
|
-
|
|
139
|
-
```tsx
|
|
140
|
-
<MeowdownEditor initialMarkdown="See [[Project plan]]">
|
|
141
|
-
<WikilinkHoverCard>
|
|
142
|
-
{async (hit) => {
|
|
143
|
-
const note = await readLocalNote(hit.target)
|
|
144
|
-
return note == null ? null : <LocalNotePreview note={note} />
|
|
145
|
-
}}
|
|
146
|
-
</WikilinkHoverCard>
|
|
147
|
-
</MeowdownEditor>
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
For local-only passive preview content, render Markdown with interaction
|
|
151
|
-
disabled: the tree contains no anchors or focusable controls, and recognized
|
|
152
|
-
tweet and YouTube embeds are omitted before any image resolver runs. Supply a
|
|
153
|
-
resolver that accepts only trusted local image sources.
|
|
154
|
-
|
|
155
|
-
```tsx
|
|
156
|
-
<MarkdownView markdown={markdown} interactive={false} resolveImageUrl={resolveLocalImageUrl} />
|
|
157
|
-
```
|
|
52
|
+
| Component | Description |
|
|
53
|
+
| ------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
54
|
+
| `MeowdownEditor` | The editor. Callbacks and resolvers must be stable; pass them via `useCallback`. |
|
|
55
|
+
| `MarkdownView` | Read-only Markdown renderer. `interactive={false}` renders passive content for previews. |
|
|
56
|
+
| `WikilinkHoverCard` | Mount inside `MeowdownEditor`; renders host content for the hovered wiki link's `target`. Return `null` to render no card. |
|
|
158
57
|
|
|
159
|
-
|
|
58
|
+
Common `MeowdownEditor` props:
|
|
160
59
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
60
|
+
| Prop | What it does |
|
|
61
|
+
| ------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
62
|
+
| `mode` | `'focus'` (default), `'show'`, or `'hide'`: how much Markdown syntax stays in view |
|
|
63
|
+
| `searchQuery` / `onSearchChange` | Find in document, with `EditorHandle.findNext()` / `findPrevious()` |
|
|
64
|
+
| `onWikilinkClick` / `onLinkClick` / `onTagClick` / `onImageClick` / `onFileClick` | Click handling for the rendered atoms |
|
|
65
|
+
| `resolveImageUrl` / `resolveWikiEmbed` / `resolveFileLink` / `resolveFileInfo` | Resolve and classify local content |
|
|
66
|
+
| `onFilePaste` | Persist pasted or dropped files |
|
|
67
|
+
| `onSlashMenuSearch` / `onTagSearch` / `onWikilinkSearch` / `onSelectionMenuSearch` | Search menus for `/`, `#`, `[[`, and selection commands |
|
|
68
|
+
| `readOnly` / `placeholder` / `blockHandle` / `caretGlide` / `embedPaste` / `linkPaste` / `bulletAfterHeading` | Behavior toggles |
|
|
164
69
|
|
|
165
|
-
|
|
166
|
-
Sequence, Class, ER, and XY Chart diagrams. Unsupported syntax renders an error
|
|
167
|
-
instead of an empty preview. Override `--meowdown-mermaid-bg`,
|
|
168
|
-
`--meowdown-mermaid-fg`, `--meowdown-mermaid-line`,
|
|
169
|
-
`--meowdown-mermaid-accent`, `--meowdown-mermaid-muted`,
|
|
170
|
-
`--meowdown-mermaid-surface`, `--meowdown-mermaid-border`, or
|
|
171
|
-
`--meowdown-mermaid-error` to customize the diagram palette.
|
|
70
|
+
Every prop, callback, and `EditorHandle` method is documented in the [API reference](https://npmx.dev/package-docs/@meowdown%2Freact/).
|
|
172
71
|
|
|
173
72
|
## Styling
|
|
174
73
|
|
package/dist/index.js
CHANGED
|
@@ -658,17 +658,19 @@ function LinkMenu({ onLinkClick, onLinkCopy }) {
|
|
|
658
658
|
const [overPopup, setOverPopup] = useState(false);
|
|
659
659
|
const [edit, setEdit] = useState();
|
|
660
660
|
const hoverOpen = useDelayedFlag(onLink || overPopup);
|
|
661
|
-
|
|
661
|
+
const linkHoverExtension = useMemo(() => {
|
|
662
662
|
return defineLinkHoverHandler((hit) => {
|
|
663
663
|
setOnLink(!!hit);
|
|
664
664
|
if (hit) setHover(hit.payload);
|
|
665
665
|
});
|
|
666
|
-
}, [])
|
|
667
|
-
useExtension$1(
|
|
666
|
+
}, []);
|
|
667
|
+
useExtension$1(linkHoverExtension);
|
|
668
|
+
const linkEditExtension = useMemo(() => {
|
|
668
669
|
return defineLinkEditKeymap((options) => {
|
|
669
670
|
setEdit(options);
|
|
670
671
|
});
|
|
671
|
-
}, [])
|
|
672
|
+
}, []);
|
|
673
|
+
useExtension$1(linkEditExtension);
|
|
672
674
|
const closeHover = useCallback(() => {
|
|
673
675
|
setOnLink(false);
|
|
674
676
|
setOverPopup(false);
|
|
@@ -1689,11 +1691,13 @@ function findHeadingPosition(doc, fragment) {
|
|
|
1689
1691
|
}
|
|
1690
1692
|
function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onSlashMenuSearch, onTagSearch, onWikilinkSearch, onSelectionMenuSearch, selectionMenuAffordance = true, pendingReplacementActions, onPendingReplacementResolve, onWikilinkClick, onLinkClick, onLinkCopy, onTagClick, onExitBoundary, resolveImageUrl, resolveFileLink, resolveWikiEmbed, resolveFileInfo, onFileClick, onFilePaste, onFileSaveError, onImageClick, embedPaste, linkPaste, bulletAfterHeading, substitution = true, frontmatter = false, blockHandle = true, placeholder, readOnly, spellCheck, searchQuery = "", onSearchChange, timeFormat, editorClassName, ref, children }) {
|
|
1691
1693
|
const [editor] = useState(() => {
|
|
1692
|
-
const
|
|
1694
|
+
const baseExtension = defineEditorExtension({
|
|
1693
1695
|
resolveFileLink,
|
|
1694
1696
|
resolveWikiEmbed,
|
|
1695
1697
|
markMode
|
|
1696
|
-
})
|
|
1698
|
+
});
|
|
1699
|
+
const extension = union(baseExtension, defineCodeBlockView());
|
|
1700
|
+
const editor = createEditor({ extension });
|
|
1697
1701
|
if (initialMarkdown) editor.setContent(markdownToDoc(initialMarkdown, {
|
|
1698
1702
|
nodes: editor.nodes,
|
|
1699
1703
|
frontmatter
|
|
@@ -2082,9 +2086,7 @@ function attributesToProps(attributes = {}, nodeName) {
|
|
|
2082
2086
|
case BOOLEAN:
|
|
2083
2087
|
props[propName] = true;
|
|
2084
2088
|
break;
|
|
2085
|
-
case OVERLOADED_BOOLEAN:
|
|
2086
|
-
if (attributeValue === "") props[propName] = true;
|
|
2087
|
-
break;
|
|
2089
|
+
case OVERLOADED_BOOLEAN: if (attributeValue === "") props[propName] = true;
|
|
2088
2090
|
}
|
|
2089
2091
|
continue;
|
|
2090
2092
|
}
|
|
@@ -2147,7 +2149,8 @@ function outputSpecToReact(spec, content, context) {
|
|
|
2147
2149
|
reactProps.tabIndex = -1;
|
|
2148
2150
|
}
|
|
2149
2151
|
}
|
|
2150
|
-
|
|
2152
|
+
const reactChildren = rest.map((child) => outputSpecToReact(child, content, context));
|
|
2153
|
+
return createElement(tag, reactProps, ...reactChildren);
|
|
2151
2154
|
}
|
|
2152
2155
|
function WikilinkChip(props) {
|
|
2153
2156
|
const { target, display, onWikilinkClick, children } = props;
|
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.64.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"beautiful-mermaid": "^1.1.3",
|
|
30
30
|
"clsx": "^2.1.1",
|
|
31
31
|
"github-slugger": "^2.0.0",
|
|
32
|
-
"lucide-react": "^1.
|
|
32
|
+
"lucide-react": "^1.28.0",
|
|
33
33
|
"react-property": "^2.0.2",
|
|
34
|
-
"@meowdown/core": "0.
|
|
34
|
+
"@meowdown/core": "0.64.0"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"react": "^19.0.0",
|
|
@@ -48,14 +48,14 @@
|
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@css-modules-kit/codegen": "^1.4.0",
|
|
50
50
|
"@ocavue/tsconfig": "^0.7.1",
|
|
51
|
-
"@tsdown/css": "^0.
|
|
52
|
-
"@types/react": "^19.2.
|
|
53
|
-
"@types/react-dom": "^19.2.
|
|
51
|
+
"@tsdown/css": "^0.23.0-beta.2",
|
|
52
|
+
"@types/react": "^19.2.18",
|
|
53
|
+
"@types/react-dom": "^19.2.4",
|
|
54
54
|
"@vitest/browser-playwright": "^4.1.10",
|
|
55
55
|
"dedent": "^1.7.2",
|
|
56
56
|
"react": "^19.2.8",
|
|
57
57
|
"react-dom": "^19.2.8",
|
|
58
|
-
"tsdown": "^0.
|
|
58
|
+
"tsdown": "^0.23.0-beta.2",
|
|
59
59
|
"vitest": "^4.1.10",
|
|
60
60
|
"vitest-browser-commands": "^0.2.1",
|
|
61
61
|
"vitest-browser-react": "^2.2.0",
|