@mp-lb/mdkit 0.2.5 → 0.3.1
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 +1 -0
- package/dist/document/useMdKitDocument.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/markdown/MarkdownBubbleMenu.js +4 -2
- package/dist/markdown/MarkdownPasteExtension.d.ts +3 -0
- package/dist/markdown/MarkdownPasteExtension.js +62 -0
- package/dist/markdown/MarkdownSearchExtension.d.ts +9 -0
- package/dist/markdown/MarkdownSearchExtension.js +42 -0
- package/dist/markdown/MarkdownSearchPanel.d.ts +13 -0
- package/dist/markdown/MarkdownSearchPanel.js +25 -0
- package/dist/markdown/MdKitEditor.d.ts +2 -0
- package/dist/markdown/MdKitView.d.ts +2 -1
- package/dist/markdown/MdKitView.js +6 -2
- package/dist/markdown/TiptapMarkdownSurface.d.ts +4 -0
- package/dist/markdown/TiptapMarkdownSurface.js +168 -7
- package/dist/markdown/createMdKitTiptapExtensions.js +5 -1
- package/dist/markdown/yamlFrontMatter.d.ts +16 -0
- package/dist/markdown/yamlFrontMatter.js +88 -0
- package/dist/theme/editorTheme.js +4 -4
- package/dist/yjs/MdKitMarkdownYjs.d.ts +1 -0
- package/dist/yjs/MdKitMarkdownYjs.js +23 -4
- package/docs/.vitepress/config.ts +2 -0
- package/docs/api.md +6 -0
- package/docs/index.md +5 -1
- package/docs/plain-text.md +131 -0
- package/docs/shadcn.md +5 -1
- package/docs/styling.md +6 -1
- package/package.json +2 -1
- package/src/styles.css +230 -13
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { parseDocument } from "yaml";
|
|
2
|
+
const delimiter = "---";
|
|
3
|
+
const getLineEnd = (markdown, lineStart) => {
|
|
4
|
+
const newlineIndex = markdown.indexOf("\n", lineStart);
|
|
5
|
+
if (newlineIndex === -1) {
|
|
6
|
+
return {
|
|
7
|
+
contentEnd: markdown.length,
|
|
8
|
+
lineEnd: markdown.length,
|
|
9
|
+
newline: "",
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
const contentEnd = newlineIndex > lineStart && markdown[newlineIndex - 1] === "\r"
|
|
13
|
+
? newlineIndex - 1
|
|
14
|
+
: newlineIndex;
|
|
15
|
+
return {
|
|
16
|
+
contentEnd,
|
|
17
|
+
lineEnd: newlineIndex + 1,
|
|
18
|
+
newline: markdown.slice(contentEnd, newlineIndex + 1),
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
const getNextBodyStart = (markdown, lineStart) => {
|
|
22
|
+
let bodyStart = lineStart;
|
|
23
|
+
while (bodyStart < markdown.length) {
|
|
24
|
+
const lineEnd = getLineEnd(markdown, bodyStart);
|
|
25
|
+
const line = markdown.slice(bodyStart, lineEnd.contentEnd);
|
|
26
|
+
if (!/^[ \t]*$/.test(line)) {
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
bodyStart = lineEnd.lineEnd;
|
|
30
|
+
}
|
|
31
|
+
return bodyStart;
|
|
32
|
+
};
|
|
33
|
+
export const parseYamlFrontMatter = (yaml) => {
|
|
34
|
+
const document = parseDocument(yaml, { prettyErrors: false });
|
|
35
|
+
if (document.errors.length > 0) {
|
|
36
|
+
throw new Error(document.errors.map((error) => error.message).join("\n"));
|
|
37
|
+
}
|
|
38
|
+
return document.toJSON();
|
|
39
|
+
};
|
|
40
|
+
export const extractYamlFrontMatter = (markdown) => {
|
|
41
|
+
const openingLine = getLineEnd(markdown, 0);
|
|
42
|
+
if (markdown.slice(0, openingLine.contentEnd) !== delimiter) {
|
|
43
|
+
return { body: markdown, errors: [], frontMatter: null };
|
|
44
|
+
}
|
|
45
|
+
let lineStart = openingLine.lineEnd;
|
|
46
|
+
while (lineStart < markdown.length) {
|
|
47
|
+
const lineEnd = getLineEnd(markdown, lineStart);
|
|
48
|
+
const line = markdown.slice(lineStart, lineEnd.contentEnd);
|
|
49
|
+
if (line !== delimiter) {
|
|
50
|
+
lineStart = lineEnd.lineEnd;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const bodyStart = getNextBodyStart(markdown, lineEnd.lineEnd);
|
|
54
|
+
const raw = markdown.slice(0, bodyStart);
|
|
55
|
+
const yaml = markdown.slice(openingLine.lineEnd, lineStart);
|
|
56
|
+
const trailingWhitespace = markdown.slice(lineEnd.lineEnd, bodyStart);
|
|
57
|
+
try {
|
|
58
|
+
const data = parseYamlFrontMatter(yaml);
|
|
59
|
+
return {
|
|
60
|
+
body: markdown.slice(bodyStart),
|
|
61
|
+
errors: [],
|
|
62
|
+
frontMatter: {
|
|
63
|
+
data,
|
|
64
|
+
raw,
|
|
65
|
+
trailingWhitespace,
|
|
66
|
+
yaml,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
return {
|
|
72
|
+
body: markdown,
|
|
73
|
+
errors: [error instanceof Error ? error.message : String(error)],
|
|
74
|
+
frontMatter: null,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { body: markdown, errors: [], frontMatter: null };
|
|
79
|
+
};
|
|
80
|
+
export const hasYamlFrontMatter = (markdown) => extractYamlFrontMatter(markdown).frontMatter !== null;
|
|
81
|
+
export const removeYamlFrontMatter = (markdown) => extractYamlFrontMatter(markdown).body;
|
|
82
|
+
export const prependYamlFrontMatter = (frontMatter, body) => {
|
|
83
|
+
if (!frontMatter) {
|
|
84
|
+
return body;
|
|
85
|
+
}
|
|
86
|
+
const raw = typeof frontMatter === "string" ? frontMatter : frontMatter.raw;
|
|
87
|
+
return `${raw}${body}`;
|
|
88
|
+
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export const defaultMdKitEditorTheme = {
|
|
2
2
|
background: "#ffffff",
|
|
3
|
-
blockGap: "0.
|
|
3
|
+
blockGap: "0.72em",
|
|
4
4
|
border: "#d8dee8",
|
|
5
5
|
codeBackground: "#eef1f4",
|
|
6
6
|
codeRadius: "0.35rem",
|
|
7
7
|
fontFamily: "inherit",
|
|
8
8
|
fontSize: "16px",
|
|
9
9
|
foreground: "#18212f",
|
|
10
|
-
lineHeight: "1.
|
|
10
|
+
lineHeight: "1.55",
|
|
11
11
|
link: "#4f46e5",
|
|
12
12
|
muted: "#eef1f4",
|
|
13
13
|
mutedForeground: "#5b6472",
|
|
@@ -15,14 +15,14 @@ export const defaultMdKitEditorTheme = {
|
|
|
15
15
|
};
|
|
16
16
|
export const darkMdKitEditorTheme = {
|
|
17
17
|
background: "#0b1220",
|
|
18
|
-
blockGap: "0.
|
|
18
|
+
blockGap: "0.72em",
|
|
19
19
|
border: "#314158",
|
|
20
20
|
codeBackground: "#111827",
|
|
21
21
|
codeRadius: "0.35rem",
|
|
22
22
|
fontFamily: "inherit",
|
|
23
23
|
fontSize: "16px",
|
|
24
24
|
foreground: "#e5edf7",
|
|
25
|
-
lineHeight: "1.
|
|
25
|
+
lineHeight: "1.55",
|
|
26
26
|
link: "#38bdf8",
|
|
27
27
|
muted: "#172033",
|
|
28
28
|
mutedForeground: "#94a3b8",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as Y from "yjs";
|
|
2
2
|
export type MdKitMarkdownYjsOptions = {
|
|
3
3
|
fragmentName?: string;
|
|
4
|
+
ignoreYamlFrontMatter?: boolean;
|
|
4
5
|
};
|
|
5
6
|
export declare const replaceMdKitYjsMarkdown: (ydoc: Y.Doc, markdown: string, options?: MdKitMarkdownYjsOptions) => Uint8Array;
|
|
6
7
|
export declare const markdownToMdKitYjs: (markdown: string, options?: MdKitMarkdownYjsOptions) => Uint8Array;
|
|
@@ -3,10 +3,14 @@ import { MarkdownManager } from "@tiptap/markdown";
|
|
|
3
3
|
import { prosemirrorJSONToYXmlFragment, yXmlFragmentToProsemirrorJSON, } from "@tiptap/y-tiptap";
|
|
4
4
|
import * as Y from "yjs";
|
|
5
5
|
import { createMdKitTiptapExtensions } from "../markdown/createMdKitTiptapExtensions.js";
|
|
6
|
+
import { extractYamlFrontMatter, prependYamlFrontMatter, } from "../markdown/yamlFrontMatter.js";
|
|
6
7
|
import { normalizeMarkdownSerialization } from "../markdown/normalizeMarkdownSerialization.js";
|
|
7
8
|
import { prepareMarkdownForEditorHydration } from "../markdown/prepareMarkdownForEditorHydration.js";
|
|
8
9
|
const defaultMdKitYjsFragmentName = "default";
|
|
10
|
+
const mdKitYjsMetadataMapName = "__mdkit";
|
|
11
|
+
const frontMatterPrefixMetadataKey = "frontMatterPrefix";
|
|
9
12
|
const getMdKitYjsFragmentName = (options) => options?.fragmentName ?? defaultMdKitYjsFragmentName;
|
|
13
|
+
const getFrontMatterPrefixMetadataKey = (fragmentName) => `${fragmentName}:${frontMatterPrefixMetadataKey}`;
|
|
10
14
|
const createMdKitMarkdownManager = () => new MarkdownManager({
|
|
11
15
|
extensions: createMdKitTiptapExtensions(),
|
|
12
16
|
markedOptions: {
|
|
@@ -17,10 +21,22 @@ const createMdKitProseMirrorSchema = () => getSchema(createMdKitTiptapExtensions
|
|
|
17
21
|
const markdownToProseMirrorJson = (markdown) => createMdKitMarkdownManager().parse(prepareMarkdownForEditorHydration(markdown));
|
|
18
22
|
const proseMirrorJsonToMarkdown = (json) => normalizeMarkdownSerialization(createMdKitMarkdownManager().serialize(json));
|
|
19
23
|
export const replaceMdKitYjsMarkdown = (ydoc, markdown, options) => {
|
|
20
|
-
const
|
|
24
|
+
const fragmentName = getMdKitYjsFragmentName(options);
|
|
25
|
+
const fragment = ydoc.getXmlFragment(fragmentName);
|
|
26
|
+
const metadata = ydoc.getMap(mdKitYjsMetadataMapName);
|
|
21
27
|
const schema = createMdKitProseMirrorSchema();
|
|
22
|
-
const
|
|
28
|
+
const frontMatter = options?.ignoreYamlFrontMatter
|
|
29
|
+
? extractYamlFrontMatter(markdown)
|
|
30
|
+
: null;
|
|
31
|
+
const json = markdownToProseMirrorJson(frontMatter?.body ?? markdown);
|
|
32
|
+
const metadataKey = getFrontMatterPrefixMetadataKey(fragmentName);
|
|
23
33
|
prosemirrorJSONToYXmlFragment(schema, json, fragment);
|
|
34
|
+
if (frontMatter?.frontMatter) {
|
|
35
|
+
metadata.set(metadataKey, frontMatter.frontMatter.raw);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
metadata.delete(metadataKey);
|
|
39
|
+
}
|
|
24
40
|
return Y.encodeStateAsUpdate(ydoc);
|
|
25
41
|
};
|
|
26
42
|
export const markdownToMdKitYjs = (markdown, options) => {
|
|
@@ -30,8 +46,11 @@ export const markdownToMdKitYjs = (markdown, options) => {
|
|
|
30
46
|
export const mdKitYjsToMarkdown = (yjsState, options) => {
|
|
31
47
|
const ydoc = new Y.Doc();
|
|
32
48
|
Y.applyUpdate(ydoc, yjsState);
|
|
33
|
-
const
|
|
34
|
-
|
|
49
|
+
const fragmentName = getMdKitYjsFragmentName(options);
|
|
50
|
+
const json = yXmlFragmentToProsemirrorJSON(ydoc.getXmlFragment(fragmentName));
|
|
51
|
+
const metadata = ydoc.getMap(mdKitYjsMetadataMapName);
|
|
52
|
+
const frontMatterRaw = metadata.get(getFrontMatterPrefixMetadataKey(fragmentName)) ?? "";
|
|
53
|
+
return prependYamlFrontMatter(frontMatterRaw, proseMirrorJsonToMarkdown(json));
|
|
35
54
|
};
|
|
36
55
|
export const yjs = {
|
|
37
56
|
markdownToMdKitYjs,
|
|
@@ -7,6 +7,7 @@ export default defineConfig({
|
|
|
7
7
|
themeConfig: {
|
|
8
8
|
nav: [
|
|
9
9
|
{ text: "Quick Start", link: "/" },
|
|
10
|
+
{ text: "Plain Text", link: "/plain-text" },
|
|
10
11
|
{ text: "Styling", link: "/styling" },
|
|
11
12
|
{ text: "Shadcn", link: "/shadcn" },
|
|
12
13
|
{ text: "REST", link: "/rest" },
|
|
@@ -21,6 +22,7 @@ export default defineConfig({
|
|
|
21
22
|
text: "Guide",
|
|
22
23
|
items: [
|
|
23
24
|
{ text: "Quick Start", link: "/" },
|
|
25
|
+
{ text: "Plain Text Editors", link: "/plain-text" },
|
|
24
26
|
{ text: "Styling", link: "/styling" },
|
|
25
27
|
{ text: "Shadcn Plugin", link: "/shadcn" },
|
|
26
28
|
{ text: "REST Backend", link: "/rest" },
|
package/docs/api.md
CHANGED
|
@@ -39,6 +39,7 @@ Local editing props:
|
|
|
39
39
|
- `onChange?: (markdown: string) => void`
|
|
40
40
|
- `onFocusChange?: (focused: boolean) => void`
|
|
41
41
|
- `fillHeight?: boolean`
|
|
42
|
+
- `search?: boolean`
|
|
42
43
|
- `instanceKey?: string | number`
|
|
43
44
|
- `className?: string`
|
|
44
45
|
- `style?: CSSProperties`
|
|
@@ -50,6 +51,7 @@ Collaborative editing props:
|
|
|
50
51
|
- `onChange?: (markdown: string) => void`
|
|
51
52
|
- `onFocusChange?: (focused: boolean) => void`
|
|
52
53
|
- `fillHeight?: boolean`
|
|
54
|
+
- `search?: boolean`
|
|
53
55
|
- `className?: string`
|
|
54
56
|
- `style?: CSSProperties`
|
|
55
57
|
|
|
@@ -57,6 +59,10 @@ Collaborative editing props:
|
|
|
57
59
|
keep blank space below the last line clickable so it focuses the cursor at the
|
|
58
60
|
end. Leave it off when the host application owns sizing and scrolling.
|
|
59
61
|
|
|
62
|
+
`search` opts the editor into the built-in document search panel. The panel is
|
|
63
|
+
not rendered by default; when enabled, users open it with `Cmd+F` on macOS or
|
|
64
|
+
`Ctrl+F` on Windows/Linux.
|
|
65
|
+
|
|
60
66
|
The package stylesheet includes reset-resistant markdown rules for headings,
|
|
61
67
|
lists, code blocks, blockquotes, and links. Styling is controlled with CSS
|
|
62
68
|
variables on `.mp-lb-mdkit-markdown-editor`. See [Styling](./styling.md) for setup,
|
package/docs/index.md
CHANGED
|
@@ -113,7 +113,11 @@ export function ConnectedMarkdownEditor({
|
|
|
113
113
|
() => createMdKitTrpcAdapter({ client: trpc.mdkit }),
|
|
114
114
|
[trpc],
|
|
115
115
|
);
|
|
116
|
-
const document = useMdKitDocument({
|
|
116
|
+
const document = useMdKitDocument({
|
|
117
|
+
adapter,
|
|
118
|
+
debounceMs: 1000,
|
|
119
|
+
documentId,
|
|
120
|
+
});
|
|
117
121
|
const versions = useMdKitDocumentVersions({ adapter, documentId });
|
|
118
122
|
|
|
119
123
|
const collaboration = useMdKitCollaboration({
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Plain Text Editors
|
|
2
|
+
|
|
3
|
+
MDKit's connected workflow is not limited to `MdKitEditor`. The document hooks
|
|
4
|
+
and backend adapters work with serialized text, so you can bring a plain text,
|
|
5
|
+
code, JSON, or custom text editor and still use the same storage, autosave,
|
|
6
|
+
checkpoint history, restore, and conflict handling.
|
|
7
|
+
|
|
8
|
+
The one major exception is collaboration. Collaboration is currently a
|
|
9
|
+
markdown/Tiptap capability because it depends on Yjs, ProseMirror, and the
|
|
10
|
+
Tiptap collaboration extensions.
|
|
11
|
+
|
|
12
|
+
## What Works
|
|
13
|
+
|
|
14
|
+
Any editor can plug into the connected workflow if it behaves like a controlled
|
|
15
|
+
text input:
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
type TextEditorProps = {
|
|
19
|
+
value: string;
|
|
20
|
+
onChange(value: string): void;
|
|
21
|
+
onFocusChange?(focused: boolean): void;
|
|
22
|
+
readOnly?: boolean;
|
|
23
|
+
};
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
That is enough for:
|
|
27
|
+
|
|
28
|
+
- loading the current document
|
|
29
|
+
- autosave
|
|
30
|
+
- dirty state
|
|
31
|
+
- conflict detection
|
|
32
|
+
- force save
|
|
33
|
+
- remote resync
|
|
34
|
+
- checkpoint history
|
|
35
|
+
- checkpoint restore
|
|
36
|
+
|
|
37
|
+
The editor does not need to know about MDKit internals. It only needs to receive
|
|
38
|
+
`document.value` and call `document.setContent`.
|
|
39
|
+
|
|
40
|
+
## Example
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import {
|
|
44
|
+
MdKitConflictPanel,
|
|
45
|
+
MdKitDocumentToolbar,
|
|
46
|
+
VersionHistoryPanel,
|
|
47
|
+
useMdKitDocument,
|
|
48
|
+
useMdKitDocumentVersions,
|
|
49
|
+
type MdKitDocumentAdapter,
|
|
50
|
+
} from "@mp-lb/mdkit";
|
|
51
|
+
|
|
52
|
+
function PlainTextDocument({
|
|
53
|
+
adapter,
|
|
54
|
+
documentId,
|
|
55
|
+
}: {
|
|
56
|
+
adapter: MdKitDocumentAdapter;
|
|
57
|
+
documentId: string;
|
|
58
|
+
}) {
|
|
59
|
+
const document = useMdKitDocument({
|
|
60
|
+
adapter,
|
|
61
|
+
debounceMs: 1000,
|
|
62
|
+
documentId,
|
|
63
|
+
});
|
|
64
|
+
const versions = useMdKitDocumentVersions({ adapter, documentId });
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<>
|
|
68
|
+
<MdKitDocumentToolbar document={document} versions={versions} />
|
|
69
|
+
|
|
70
|
+
<textarea
|
|
71
|
+
readOnly={document.conflict}
|
|
72
|
+
value={document.value}
|
|
73
|
+
onBlur={() => document.setFocused(false)}
|
|
74
|
+
onChange={(event) => document.setContent(event.currentTarget.value)}
|
|
75
|
+
onFocus={() => document.setFocused(true)}
|
|
76
|
+
/>
|
|
77
|
+
|
|
78
|
+
<MdKitConflictPanel document={document} />
|
|
79
|
+
<VersionHistoryPanel controller={versions} />
|
|
80
|
+
</>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Use the same backend adapter you would use for markdown. The document content is
|
|
86
|
+
still just `content: string`.
|
|
87
|
+
|
|
88
|
+
## Backend Shape
|
|
89
|
+
|
|
90
|
+
You do not need a separate backend for plain text documents. A single MDKit
|
|
91
|
+
backend can expose:
|
|
92
|
+
|
|
93
|
+
- document read/write
|
|
94
|
+
- checkpoint list/read/restore
|
|
95
|
+
- optional collaboration websocket routes
|
|
96
|
+
- optional collaboration state persistence
|
|
97
|
+
|
|
98
|
+
Plain text editors use the document and checkpoint APIs. Markdown collaborative
|
|
99
|
+
editors additionally use the collaboration websocket and Yjs persistence.
|
|
100
|
+
|
|
101
|
+
The underlying database layout is application-owned. It is reasonable to store
|
|
102
|
+
markdown and plain text documents in the same documents table, or in separate
|
|
103
|
+
tables if your product needs that. MDKit only requires a stable `documentId`,
|
|
104
|
+
`content`, and an opaque revision token.
|
|
105
|
+
|
|
106
|
+
## Collaboration Boundary
|
|
107
|
+
|
|
108
|
+
Do not pass `useMdKitCollaboration` to a plain text editor. The current
|
|
109
|
+
collaboration adapter is for `MdKitEditor` because that editor knows how to bind
|
|
110
|
+
Tiptap to a Yjs document and render remote cursors.
|
|
111
|
+
|
|
112
|
+
For plain text documents:
|
|
113
|
+
|
|
114
|
+
- keep using `useMdKitDocument`
|
|
115
|
+
- omit `useMdKitCollaboration`
|
|
116
|
+
- omit collaboration UI
|
|
117
|
+
- rely on optimistic conflicts and resync for multi-client safety
|
|
118
|
+
|
|
119
|
+
If MDKit later adds a collaboration-capable CodeMirror, Monaco, or textarea
|
|
120
|
+
adapter, that should be a new editor-specific capability. The generic text
|
|
121
|
+
workflow does not need to change.
|
|
122
|
+
|
|
123
|
+
## Testbench
|
|
124
|
+
|
|
125
|
+
The testbench includes a connected stack named
|
|
126
|
+
`Storage + checkpoints (plain text)`. It reuses the same checkpoints backend as
|
|
127
|
+
the markdown stack, stores content under `docs/plain-text.txt`, and renders a
|
|
128
|
+
controlled textarea instead of `MdKitEditor`.
|
|
129
|
+
|
|
130
|
+
Use it to verify that plain text can autosave, create checkpoints, restore
|
|
131
|
+
history, and avoid collaboration UI.
|
package/docs/shadcn.md
CHANGED
|
@@ -46,7 +46,11 @@ import { MdKitConnectedWorkflow } from "@/components/mdkit/mdkit-connected-workf
|
|
|
46
46
|
export function EditorScreen() {
|
|
47
47
|
const client = createMdKitTrpcClient({ url: "/trpc" });
|
|
48
48
|
const adapter = createMdKitTrpcAdapter({ client });
|
|
49
|
-
const document = useMdKitDocument({
|
|
49
|
+
const document = useMdKitDocument({
|
|
50
|
+
adapter,
|
|
51
|
+
debounceMs: 1000,
|
|
52
|
+
documentId,
|
|
53
|
+
});
|
|
50
54
|
const versions = useMdKitDocumentVersions({ adapter, documentId });
|
|
51
55
|
|
|
52
56
|
const collaboration = useMdKitCollaboration({
|
package/docs/styling.md
CHANGED
|
@@ -120,7 +120,8 @@ you need structural changes, component-specific spacing, or state styling.
|
|
|
120
120
|
|
|
121
121
|
`MdKitEditor` renders the markdown editing surface and the selection bubble
|
|
122
122
|
toolbar. The toolbar appears for non-empty text selections while the editor or
|
|
123
|
-
toolbar has focus.
|
|
123
|
+
toolbar has focus. The search panel appears only when `search` is enabled and
|
|
124
|
+
the user opens it with the find keyboard shortcut.
|
|
124
125
|
|
|
125
126
|
- `.mp-lb-mdkit-markdown-editor`: root element rendered by `MdKitEditor`
|
|
126
127
|
- `.mp-lb-mdkit-markdown-editor-fill-height`: added to the root when
|
|
@@ -129,6 +130,10 @@ toolbar has focus.
|
|
|
129
130
|
- `.mp-lb-mdkit-editor-surface`: scroll and background surface around the
|
|
130
131
|
ProseMirror editor
|
|
131
132
|
- `.mp-lb-mdkit-editor-empty`: loading or connecting placeholder
|
|
133
|
+
- `.mp-lb-mdkit-search-panel`: optional document search panel
|
|
134
|
+
- `.mp-lb-mdkit-search-input`: search text input
|
|
135
|
+
- `.mp-lb-mdkit-search-status`: search result count
|
|
136
|
+
- `.mp-lb-mdkit-search-button`: search navigation or close button
|
|
132
137
|
- `.mp-lb-mdkit-tiptap`: ProseMirror editable element
|
|
133
138
|
- `.mp-lb-mdkit-toolbar`: selection bubble toolbar
|
|
134
139
|
- `.mp-lb-mdkit-toolbar-button`: toolbar button
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mp-lb/mdkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -94,6 +94,7 @@
|
|
|
94
94
|
"lucide-react": "^0.554.0",
|
|
95
95
|
"react-markdown": "10.1.0",
|
|
96
96
|
"remark-gfm": "4.0.1",
|
|
97
|
+
"yaml": "2.9.0",
|
|
97
98
|
"yjs": "^13.6.24",
|
|
98
99
|
"zod": "^4.1.12"
|
|
99
100
|
},
|