@mp-lb/mdkit 0.0.1-main.2.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.
Files changed (125) hide show
  1. package/README.md +132 -0
  2. package/dist/collaboration/useMdKitCollaboration.d.ts +10 -0
  3. package/dist/collaboration/useMdKitCollaboration.js +90 -0
  4. package/dist/core/documentEngine.d.ts +38 -0
  5. package/dist/core/documentEngine.js +95 -0
  6. package/dist/core/documentEngine.test.d.ts +1 -0
  7. package/dist/core/documentEngine.test.js +119 -0
  8. package/dist/core/index.d.ts +3 -0
  9. package/dist/core/index.js +1 -0
  10. package/dist/document/MdKitConflictPanel.d.ts +7 -0
  11. package/dist/document/MdKitConflictPanel.js +41 -0
  12. package/dist/document/MdKitDocumentToolbar.d.ts +13 -0
  13. package/dist/document/MdKitDocumentToolbar.js +48 -0
  14. package/dist/document/documentTypes.d.ts +57 -0
  15. package/dist/document/documentTypes.js +1 -0
  16. package/dist/document/useMdKitDocument.d.ts +33 -0
  17. package/dist/document/useMdKitDocument.js +396 -0
  18. package/dist/document/useMdKitDocument.test.d.ts +1 -0
  19. package/dist/document/useMdKitDocument.test.js +151 -0
  20. package/dist/fastify.d.ts +3 -0
  21. package/dist/fastify.js +1 -0
  22. package/dist/index.d.ts +23 -0
  23. package/dist/index.js +11 -0
  24. package/dist/markdown/MarkdownBubbleMenu.d.ts +6 -0
  25. package/dist/markdown/MarkdownBubbleMenu.js +29 -0
  26. package/dist/markdown/MdKitEditor.d.ts +25 -0
  27. package/dist/markdown/MdKitEditor.js +7 -0
  28. package/dist/markdown/MdKitEditor.test.d.ts +1 -0
  29. package/dist/markdown/MdKitEditor.test.js +126 -0
  30. package/dist/markdown/TiptapMarkdownSurface.d.ts +23 -0
  31. package/dist/markdown/TiptapMarkdownSurface.js +430 -0
  32. package/dist/markdown/editorDebug.d.ts +5 -0
  33. package/dist/markdown/editorDebug.js +1 -0
  34. package/dist/markdown/markdownFenceRanges.d.ts +6 -0
  35. package/dist/markdown/markdownFenceRanges.js +41 -0
  36. package/dist/markdown/normalizeMarkdownSerialization.d.ts +1 -0
  37. package/dist/markdown/normalizeMarkdownSerialization.js +34 -0
  38. package/dist/markdown/normalizeMarkdownSerialization.test.d.ts +1 -0
  39. package/dist/markdown/normalizeMarkdownSerialization.test.js +16 -0
  40. package/dist/markdown/prepareMarkdownForEditorHydration.d.ts +1 -0
  41. package/dist/markdown/prepareMarkdownForEditorHydration.js +12 -0
  42. package/dist/markdown/prepareMarkdownForEditorHydration.test.d.ts +1 -0
  43. package/dist/markdown/prepareMarkdownForEditorHydration.test.js +13 -0
  44. package/dist/markdown/preserveMarkdownWhitespace.d.ts +1 -0
  45. package/dist/markdown/preserveMarkdownWhitespace.js +86 -0
  46. package/dist/markdown/preserveMarkdownWhitespace.test.d.ts +1 -0
  47. package/dist/markdown/preserveMarkdownWhitespace.test.js +25 -0
  48. package/dist/test/setup.d.ts +1 -0
  49. package/dist/test/setup.js +13 -0
  50. package/dist/theme/MdKitThemeEditor.d.ts +8 -0
  51. package/dist/theme/MdKitThemeEditor.js +13 -0
  52. package/dist/theme/editorTheme.d.ts +20 -0
  53. package/dist/theme/editorTheme.js +47 -0
  54. package/dist/transport/fastify.d.ts +7 -0
  55. package/dist/transport/fastify.js +19 -0
  56. package/dist/transport/http.d.ts +43 -0
  57. package/dist/transport/http.js +80 -0
  58. package/dist/transport/index.d.ts +5 -0
  59. package/dist/transport/index.js +2 -0
  60. package/dist/transport/rest.d.ts +6 -0
  61. package/dist/transport/rest.js +34 -0
  62. package/dist/transport/store.d.ts +21 -0
  63. package/dist/transport/store.js +1 -0
  64. package/dist/transport/trpcClient.d.ts +81 -0
  65. package/dist/transport/trpcClient.js +21 -0
  66. package/dist/transport/trpcServer.d.ts +72 -0
  67. package/dist/transport/trpcServer.js +45 -0
  68. package/dist/trpc/client.d.ts +3 -0
  69. package/dist/trpc/client.js +1 -0
  70. package/dist/trpc/server.d.ts +3 -0
  71. package/dist/trpc/server.js +1 -0
  72. package/dist/trpc.d.ts +3 -0
  73. package/dist/trpc.js +1 -0
  74. package/dist/ui/joinClassNames.d.ts +1 -0
  75. package/dist/ui/joinClassNames.js +1 -0
  76. package/dist/versioning/VersionHistoryPanel.d.ts +9 -0
  77. package/dist/versioning/VersionHistoryPanel.js +29 -0
  78. package/dist/versioning/useMdKitDocumentVersions.d.ts +16 -0
  79. package/dist/versioning/useMdKitDocumentVersions.js +88 -0
  80. package/dist/versioning/useMdKitDocumentVersions.test.d.ts +1 -0
  81. package/dist/versioning/useMdKitDocumentVersions.test.js +41 -0
  82. package/docs/.vitepress/config.ts +34 -0
  83. package/docs/.vitepress/dist/404.html +22 -0
  84. package/docs/.vitepress/dist/api.html +120 -0
  85. package/docs/.vitepress/dist/architecture.html +25 -0
  86. package/docs/.vitepress/dist/assets/api.md.asncK3PQ.js +96 -0
  87. package/docs/.vitepress/dist/assets/api.md.asncK3PQ.lean.js +1 -0
  88. package/docs/.vitepress/dist/assets/app.BQvrHyG0.js +1 -0
  89. package/docs/.vitepress/dist/assets/architecture.md.BHQLarmZ.js +1 -0
  90. package/docs/.vitepress/dist/assets/architecture.md.BHQLarmZ.lean.js +1 -0
  91. package/docs/.vitepress/dist/assets/chunks/framework.RRduUuAx.js +19 -0
  92. package/docs/.vitepress/dist/assets/chunks/theme.CkCo6Nk1.js +1 -0
  93. package/docs/.vitepress/dist/assets/index.md.CITl-897.js +137 -0
  94. package/docs/.vitepress/dist/assets/index.md.CITl-897.lean.js +1 -0
  95. package/docs/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  96. package/docs/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  97. package/docs/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  98. package/docs/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  99. package/docs/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  100. package/docs/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  101. package/docs/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  102. package/docs/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  103. package/docs/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  104. package/docs/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  105. package/docs/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  106. package/docs/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  107. package/docs/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  108. package/docs/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  109. package/docs/.vitepress/dist/assets/shadcn.md.C3idOo2N.js +57 -0
  110. package/docs/.vitepress/dist/assets/shadcn.md.C3idOo2N.lean.js +1 -0
  111. package/docs/.vitepress/dist/assets/style.BtrGaL3i.css +1 -0
  112. package/docs/.vitepress/dist/assets/styling.md.B2C6kVFa.js +91 -0
  113. package/docs/.vitepress/dist/assets/styling.md.B2C6kVFa.lean.js +1 -0
  114. package/docs/.vitepress/dist/hashmap.json +1 -0
  115. package/docs/.vitepress/dist/index.html +161 -0
  116. package/docs/.vitepress/dist/shadcn.html +81 -0
  117. package/docs/.vitepress/dist/styling.html +115 -0
  118. package/docs/.vitepress/dist/vp-icons.css +1 -0
  119. package/docs/api.md +343 -0
  120. package/docs/architecture.md +67 -0
  121. package/docs/index.md +244 -0
  122. package/docs/shadcn.md +118 -0
  123. package/docs/styling.md +247 -0
  124. package/package.json +105 -0
  125. package/src/styles.css +676 -0
package/docs/index.md ADDED
@@ -0,0 +1,244 @@
1
+ # Quick Start
2
+
3
+ Markdown Editor Kit is a React package for teams that need more than a bare
4
+ markdown editor widget. It starts with a controlled markdown editor that behaves
5
+ like a textarea, then adds autosave, version history, conflict handling, and
6
+ collaboration through adapters.
7
+
8
+ ```bash
9
+ pnpm add @mp-lb/mdkit
10
+ ```
11
+
12
+ Import the stylesheet once if you want reset-resistant markdown defaults and
13
+ generic fallback styling for the base panels:
14
+
15
+ ```ts
16
+ import "@mp-lb/mdkit/styles.css";
17
+ ```
18
+
19
+ See [Styling](./styling.md) for reset handling, dark mode, fonts, sizing, and
20
+ custom panel styles.
21
+
22
+ ## Basic Editor
23
+
24
+ `MdKitEditor` is the textarea-like entry point. It has no persistence, no
25
+ version history, and no collaboration. You own the `value` and `onChange` state.
26
+
27
+ ```tsx
28
+ import { useState } from "react";
29
+ import { MdKitEditor } from "@mp-lb/mdkit";
30
+ import "@mp-lb/mdkit/styles.css";
31
+
32
+ export function MarkdownEditorExample() {
33
+ const [markdown, setMarkdown] = useState("# Hello markdown");
34
+
35
+ return <MdKitEditor value={markdown} onChange={setMarkdown} />;
36
+ }
37
+ ```
38
+
39
+ Use this when you want a local editor, a form field, or a debug surface.
40
+
41
+ ## Connected Editor
42
+
43
+ The connected workflow combines:
44
+
45
+ - `useMdKitDocument` for loading, autosave, dirty state, and conflict detection
46
+ - `useMdKitDocumentVersions` for version browsing and restore
47
+ - `useMdKitCollaboration` for Hocuspocus/Yjs collaboration
48
+ - `MdKitDocumentToolbar`, `VersionHistoryPanel`, and `MdKitConflictPanel` for
49
+ a complete base-panel UI
50
+
51
+ The TypeScript-first path is tRPC. REST is also supported for high-compatibility
52
+ backends and non-TypeScript stacks.
53
+
54
+ ### Frontend With tRPC
55
+
56
+ ```tsx
57
+ import { useMemo, useState } from "react";
58
+ import {
59
+ MdKitConflictPanel,
60
+ MdKitDocumentToolbar,
61
+ MdKitEditor,
62
+ VersionHistoryPanel,
63
+ useMdKitCollaboration,
64
+ useMdKitDocument,
65
+ useMdKitDocumentVersions,
66
+ type MdKitDocumentVersionDetail,
67
+ } from "@mp-lb/mdkit";
68
+ import {
69
+ createMdKitTrpcAdapter,
70
+ createMdKitTrpcClient,
71
+ } from "@mp-lb/mdkit/trpc/client";
72
+
73
+ const documentId = "docs/example.md";
74
+
75
+ export function ConnectedMarkdownEditor({
76
+ apiUrl,
77
+ }: {
78
+ apiUrl: string;
79
+ }) {
80
+ const [versionHistoryOpen, setVersionHistoryOpen] = useState(false);
81
+ const [conflictOpen, setConflictOpen] = useState(false);
82
+
83
+ const trpc = useMemo(
84
+ () => createMdKitTrpcClient({ url: `${apiUrl}/trpc` }),
85
+ [apiUrl],
86
+ );
87
+ const adapter = useMemo(() => createMdKitTrpcAdapter({ client: trpc }), [trpc]);
88
+
89
+ const document = useMdKitDocument({ adapter, documentId });
90
+ const versions = useMdKitDocumentVersions({ adapter, documentId });
91
+ const collaboration = useMdKitCollaboration({
92
+ collaborator: { id: "user-1", name: "Ada" },
93
+ documentId,
94
+ endpoint: `${apiUrl.replace(/^http/, "ws")}/collaboration`,
95
+ });
96
+
97
+ const restoreVersion = async (version: MdKitDocumentVersionDetail) => {
98
+ await trpc.restoreDocumentVersion.mutate({
99
+ documentId,
100
+ versionId: version.id,
101
+ });
102
+ await document.resync();
103
+ await versions.refresh();
104
+ };
105
+
106
+ return (
107
+ <>
108
+ <MdKitDocumentToolbar
109
+ collaboration={collaboration}
110
+ document={document}
111
+ versions={versions}
112
+ onOpenConflict={() => setConflictOpen(true)}
113
+ onOpenVersionHistory={() => setVersionHistoryOpen(true)}
114
+ />
115
+
116
+ <MdKitEditor
117
+ collaboration={collaboration}
118
+ fillHeight
119
+ readOnly={document.conflict}
120
+ value={document.value}
121
+ onChange={document.setContent}
122
+ onFocusChange={document.setFocused}
123
+ />
124
+
125
+ {versionHistoryOpen ? (
126
+ <div role="dialog" aria-label="Version history">
127
+ <VersionHistoryPanel
128
+ controller={versions}
129
+ onRestoreVersion={restoreVersion}
130
+ />
131
+ </div>
132
+ ) : null}
133
+
134
+ {document.conflict && conflictOpen ? (
135
+ <div role="dialog" aria-label="Resolve conflict">
136
+ <MdKitConflictPanel document={document} />
137
+ </div>
138
+ ) : null}
139
+ </>
140
+ );
141
+ }
142
+ ```
143
+
144
+ The modal shells above are intentionally plain. Put `VersionHistoryPanel` and
145
+ `MdKitConflictPanel` inside your own dialog, drawer, side panel, or editor
146
+ replacement view. If your app uses shadcn/ui, see [Shadcn Plugin](./shadcn.md)
147
+ for the source-installed workflow component.
148
+
149
+ ### Backend With Fastify And tRPC
150
+
151
+ The backend only needs a store object. Replace `createYourDocumentStore()` with
152
+ Postgres, MongoDB, Redis, files, or any other durable storage.
153
+
154
+ ```ts
155
+ import cors from "@fastify/cors";
156
+ import websocket from "@fastify/websocket";
157
+ import { Database } from "@hocuspocus/extension-database";
158
+ import { Server } from "@hocuspocus/server";
159
+ import { fastifyTRPCPlugin } from "@trpc/server/adapters/fastify";
160
+ import Fastify from "fastify";
161
+ import { createMdKitTrpcRouter } from "@mp-lb/mdkit/trpc/server";
162
+
163
+ const app = Fastify();
164
+ const store = createYourDocumentStore();
165
+
166
+ const collaboration = Server.configure({
167
+ extensions: [
168
+ new Database({
169
+ fetch: ({ documentName }) => store.readCollaborationState(documentName),
170
+ store: ({ documentName, state }) =>
171
+ store.writeCollaborationState(documentName, state),
172
+ }),
173
+ ],
174
+ });
175
+
176
+ await app.register(cors, { origin: true });
177
+ await app.register(websocket);
178
+
179
+ await app.register(fastifyTRPCPlugin, {
180
+ prefix: "/trpc",
181
+ trpcOptions: {
182
+ router: createMdKitTrpcRouter(store),
183
+ },
184
+ });
185
+
186
+ app.get("/collaboration", { websocket: true }, (socket, request) => {
187
+ collaboration.handleConnection(socket, request.raw, {});
188
+ });
189
+
190
+ await app.listen({ port: Number(process.env.PORT ?? 4312) });
191
+ ```
192
+
193
+ The store object implements `MdKitTransportStore`: current document reads and
194
+ writes, version list/read/restore, and optional collaboration state storage. See
195
+ [API Reference](./api.md#transport-helpers).
196
+
197
+ ### REST Compatibility
198
+
199
+ If you want REST instead of tRPC, use the REST frontend adapter:
200
+
201
+ ```tsx
202
+ import { createMdKitRestAdapter } from "@mp-lb/mdkit";
203
+
204
+ const adapter = createMdKitRestAdapter({
205
+ baseUrl: "https://api.example.com/mdkit",
206
+ });
207
+ ```
208
+
209
+ On Fastify, register the matching REST endpoints:
210
+
211
+ ```ts
212
+ import { registerMdKitFastify } from "@mp-lb/mdkit/fastify";
213
+
214
+ await registerMdKitFastify(app, {
215
+ prefix: "/mdkit",
216
+ store,
217
+ });
218
+ ```
219
+
220
+ The mdkit testbench uses this split deliberately: `Connected (panels)` uses the
221
+ REST adapter, while `Connected (shadcn)` uses the tRPC adapter.
222
+
223
+ ## Questions
224
+
225
+ ### Do the backends need to know about each other?
226
+
227
+ Storage, version history, and collaboration can stay separate. Storage stores
228
+ the current markdown snapshot. Version history stores markdown snapshots.
229
+ Hocuspocus stores live Yjs collaboration state. They only need glue if your
230
+ product wants collaborative edits to automatically become saved markdown
231
+ versions.
232
+
233
+ ### Does mdkit require tRPC or these exact REST endpoints?
234
+
235
+ No. The frontend hooks only need an `MdKitDocumentAdapter`. You can use REST,
236
+ tRPC, GraphQL, server actions, IndexedDB, Rails, Go, or anything else as long as
237
+ your adapter returns the documented shapes.
238
+
239
+ ### Do I have to use the base panels?
240
+
241
+ No. The base panels are the fastest way to get a complete workflow working in
242
+ any React app. If you want a fully custom UI, use `useMdKitDocument`,
243
+ `useMdKitDocumentVersions`, and `useMdKitCollaboration` directly and render your
244
+ own controls.
package/docs/shadcn.md ADDED
@@ -0,0 +1,118 @@
1
+ # Shadcn Plugin
2
+
3
+ The core npm package is design-system agnostic. It exports the editor, hooks,
4
+ base panels, types, and generic CSS. It does not export shadcn components at
5
+ runtime.
6
+
7
+ The shadcn path should be a registry/plugin item. Installing it copies editable
8
+ source into your app, and that source imports your app's own shadcn primitives:
9
+
10
+ ```tsx
11
+ import { Button } from "@/components/ui/button";
12
+ import { Badge } from "@/components/ui/badge";
13
+ import {
14
+ Dialog,
15
+ DialogContent,
16
+ DialogHeader,
17
+ DialogTitle,
18
+ } from "@/components/ui/dialog";
19
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
20
+ import { Textarea } from "@/components/ui/textarea";
21
+ ```
22
+
23
+ That means the workflow component can own polished app UI: toolbar, version
24
+ history dialog, conflict dialog, tabs, buttons, and layout. The underlying state
25
+ still comes from the mdkit hooks. The recommended transport for this path is the
26
+ tRPC adapter from `@mp-lb/mdkit/trpc/client`.
27
+
28
+ ## Intended Shape
29
+
30
+ The installed component should be one app-local workflow component that you
31
+ render next to `MdKitEditor`.
32
+
33
+ ```tsx
34
+ import {
35
+ MdKitEditor,
36
+ useMdKitCollaboration,
37
+ useMdKitDocument,
38
+ useMdKitDocumentVersions,
39
+ } from "@mp-lb/mdkit";
40
+ import {
41
+ createMdKitTrpcAdapter,
42
+ createMdKitTrpcClient,
43
+ } from "@mp-lb/mdkit/trpc/client";
44
+ import { MdKitConnectedWorkflow } from "@/components/mdkit/mdkit-connected-workflow";
45
+
46
+ export function EditorScreen() {
47
+ const client = createMdKitTrpcClient({ url: "/trpc" });
48
+ const adapter = createMdKitTrpcAdapter({ client });
49
+ const document = useMdKitDocument({ adapter, documentId });
50
+ const versions = useMdKitDocumentVersions({ adapter, documentId });
51
+ const collaboration = useMdKitCollaboration({
52
+ collaborator,
53
+ documentId,
54
+ endpoint: hocuspocusEndpoint,
55
+ });
56
+ const restoreVersion = async (version) => {
57
+ await client.restoreDocumentVersion.mutate({
58
+ documentId,
59
+ versionId: version.id,
60
+ });
61
+ await document.resync();
62
+ await versions.refresh();
63
+ };
64
+
65
+ return (
66
+ <MdKitConnectedWorkflow
67
+ collaboration={collaboration}
68
+ document={document}
69
+ versions={versions}
70
+ onRestoreVersion={restoreVersion}
71
+ >
72
+ <MdKitEditor
73
+ collaboration={collaboration}
74
+ readOnly={document.conflict}
75
+ value={document.value}
76
+ onChange={document.setContent}
77
+ onFocusChange={document.setFocused}
78
+ />
79
+ </MdKitConnectedWorkflow>
80
+ );
81
+ }
82
+ ```
83
+
84
+ The shadcn component is deliberately source-installed instead of imported from
85
+ the npm package. That is how shadcn is designed to work: the code lives in your
86
+ app, uses your aliases, and can be edited like any other local component.
87
+
88
+ ## Why Not A Runtime Export?
89
+
90
+ mdkit should not:
91
+
92
+ - bundle copies of shadcn primitives
93
+ - depend on shadcn as a package
94
+ - ask you to pass a map of local `Button`, `Dialog`, or `Tabs` components into
95
+ mdkit
96
+ - ship Tailwind-only wrappers from the npm package and hope your build scans
97
+ external package source
98
+
99
+ The npm package stays focused on the durable logic. The registry item owns the
100
+ app-local shadcn composition.
101
+
102
+ ## Fallback Path
103
+
104
+ If you do not use shadcn, use the base panels from the npm package:
105
+
106
+ - `MdKitDocumentToolbar`
107
+ - `VersionHistoryPanel`
108
+ - `MdKitConflictPanel`
109
+
110
+ They render plain semantic HTML with stable `mdkit-*` classes. Import
111
+ `@mp-lb/mdkit/styles.css` for generic fallback styling, or
112
+ replace the CSS entirely. See [Styling](./styling.md#component-styling).
113
+
114
+ ## Status
115
+
116
+ The mdkit testbench currently contains the reference shadcn workflow component.
117
+ It is the target shape for the future registry/plugin item. Until that registry
118
+ item exists, treat the base panels as the supported published path.
@@ -0,0 +1,247 @@
1
+ # Styling
2
+
3
+ `MdKitEditor` can render without package CSS, but most applications should
4
+ import the stylesheet once. It gives the editor a reset-resistant markdown
5
+ baseline and exposes CSS variables for theme changes.
6
+
7
+ ```ts
8
+ import "@mp-lb/mdkit/styles.css";
9
+ ```
10
+
11
+ Without this stylesheet, the editor still works, but headings, lists,
12
+ blockquotes, code blocks, spacing, and focus areas are left to your app's CSS.
13
+
14
+ ## CSS Resets
15
+
16
+ Many app frameworks include CSS resets. Tailwind Preflight, for example, removes
17
+ default margins and list styling. The package stylesheet restores markdown
18
+ editor defaults under `.mdkit-markdown-editor`, including:
19
+
20
+ - heading sizes and spacing
21
+ - paragraph spacing
22
+ - unordered and ordered list markers
23
+ - compact list item spacing
24
+ - inline code and code block styling
25
+ - blockquote styling
26
+ - link color
27
+ - full-width editor layout
28
+
29
+ Import the stylesheet after global reset styles when possible:
30
+
31
+ ```ts
32
+ import "./app.css";
33
+ import "@mp-lb/mdkit/styles.css";
34
+ ```
35
+
36
+ If your bundler or framework controls CSS order differently, make sure the
37
+ mdkit stylesheet is not overridden by a later broad reset such as
38
+ `ul { list-style: none; }`.
39
+
40
+ ## Default Styling
41
+
42
+ The simplest setup is:
43
+
44
+ ```tsx
45
+ import { MdKitEditor } from "@mp-lb/mdkit";
46
+ import "@mp-lb/mdkit/styles.css";
47
+
48
+ export function Editor({ markdown, setMarkdown }) {
49
+ return <MdKitEditor value={markdown} onChange={setMarkdown} />;
50
+ }
51
+ ```
52
+
53
+ The editor fills the available width by default. Use `fillHeight` only when you
54
+ want the editor to fill its parent's height, own its scroll area, and make the
55
+ empty area below the last line clickable.
56
+
57
+ ```tsx
58
+ <MdKitEditor fillHeight value={markdown} onChange={setMarkdown} />
59
+ ```
60
+
61
+ ## Custom Styling
62
+
63
+ The package stylesheet is intentionally controlled through CSS variables. You
64
+ can override them with a class:
65
+
66
+ ```css
67
+ .my-markdown-editor {
68
+ --hsk-background: #ffffff;
69
+ --hsk-foreground: #172033;
70
+ --hsk-muted: #eef1f4;
71
+ --hsk-muted-foreground: #5b6472;
72
+ --hsk-border: #d8dee8;
73
+ --hsk-link: #4f46e5;
74
+ --hsk-font-family: Inter, system-ui, sans-serif;
75
+ --hsk-font-size: 16px;
76
+ --hsk-line-height: 1.7;
77
+ --hsk-surface-padding: 1rem;
78
+ --hsk-block-gap: 0.75rem;
79
+ --hsk-list-item-gap: 0.125rem;
80
+ --hsk-code-background: #eef1f4;
81
+ --hsk-code-radius: 0.35rem;
82
+ --hsk-code-block-radius: 0.75rem;
83
+ }
84
+ ```
85
+
86
+ ```tsx
87
+ <MdKitEditor
88
+ className="my-markdown-editor"
89
+ value={markdown}
90
+ onChange={setMarkdown}
91
+ />
92
+ ```
93
+
94
+ You can also pass variables through `style` when the values are generated at
95
+ runtime:
96
+
97
+ ```tsx
98
+ <MdKitEditor
99
+ style={{
100
+ "--hsk-font-family": "ui-serif, Georgia, serif",
101
+ "--hsk-font-size": "18px",
102
+ "--hsk-line-height": "1.8",
103
+ }}
104
+ value={markdown}
105
+ onChange={setMarkdown}
106
+ />
107
+ ```
108
+
109
+ See [`MdKitEditorProps`](./api.md#mdkiteditorprops) for the full component
110
+ props.
111
+
112
+ ## Component Styling
113
+
114
+ Editor styling and workflow component styling are separate.
115
+
116
+ `MdKitEditor` is styled through CSS variables on `.mdkit-markdown-editor`.
117
+ Workflow panels such as `MdKitDocumentToolbar`, `MdKitConflictPanel`, and
118
+ `VersionHistoryPanel` are intentionally design-system agnostic. They render raw
119
+ semantic markup with stable `mdkit-*` class names. Without this stylesheet they
120
+ are plain HTML; with this stylesheet they get generic fallback styling: square
121
+ corners, one-pixel borders, clear spacing, and basic buttons.
122
+
123
+ Style them in your app when you want them to match your product:
124
+
125
+ ```css
126
+ .mdkit-document-toolbar {
127
+ display: flex;
128
+ align-items: center;
129
+ gap: 0.5rem;
130
+ border-bottom: 1px solid var(--border);
131
+ padding: 0.5rem 0;
132
+ }
133
+
134
+ .mdkit-document-toolbar-status,
135
+ .mdkit-document-toolbar-actions,
136
+ .mdkit-document-toolbar-conflict {
137
+ display: flex;
138
+ align-items: center;
139
+ gap: 0.5rem;
140
+ }
141
+
142
+ .mdkit-document-toolbar[data-conflict="true"] {
143
+ color: #991b1b;
144
+ }
145
+ ```
146
+
147
+ The toolbar class hooks are:
148
+
149
+ - `.mdkit-document-toolbar`
150
+ - `.mdkit-document-toolbar-status`
151
+ - `.mdkit-document-toolbar-actions`
152
+ - `.mdkit-document-toolbar-error`
153
+ - `.mdkit-document-toolbar-conflict`
154
+
155
+ It also exposes `data-conflict`, `data-dirty`, and `data-save-status`
156
+ attributes for state-based styling.
157
+
158
+ Version history and conflict panels use the same fallback panel CSS and expose:
159
+
160
+ - `.mdkit-version-history-panel`
161
+ - `.mdkit-version-history-header`
162
+ - `.mdkit-version-history-list`
163
+ - `.mdkit-version-history-item`
164
+ - `.mdkit-version-history-preview`
165
+ - `.mdkit-conflict-panel`
166
+ - `.mdkit-conflict-panel-content`
167
+ - `.mdkit-conflict-panel-action-row`
168
+ - `.mdkit-panel-primary-action`
169
+ - `.mdkit-panel-secondary-action`
170
+
171
+ ## Theme Helpers
172
+
173
+ For app code, CSS variables are usually the simplest integration. The package
174
+ also exports theme helpers when you want to store or generate a theme object:
175
+
176
+ ```tsx
177
+ import {
178
+ MdKitEditor,
179
+ createMdKitEditorThemeStyle,
180
+ darkMdKitEditorTheme,
181
+ } from "@mp-lb/mdkit";
182
+
183
+ const style = createMdKitEditorThemeStyle({
184
+ ...darkMdKitEditorTheme,
185
+ fontFamily: "Inter, system-ui, sans-serif",
186
+ lineHeight: "1.75",
187
+ });
188
+
189
+ <MdKitEditor style={style} value={markdown} onChange={setMarkdown} />;
190
+ ```
191
+
192
+ Related exports are listed in the [API reference](./api.md#styling).
193
+
194
+ ## Dark Mode
195
+
196
+ For class-based dark mode, scope variable overrides to your dark selector:
197
+
198
+ ```css
199
+ .my-markdown-editor {
200
+ --hsk-background: #ffffff;
201
+ --hsk-foreground: #172033;
202
+ --hsk-muted: #eef1f4;
203
+ --hsk-muted-foreground: #5b6472;
204
+ --hsk-border: #d8dee8;
205
+ --hsk-link: #4f46e5;
206
+ --hsk-code-background: #eef1f4;
207
+ }
208
+
209
+ .dark .my-markdown-editor {
210
+ --hsk-background: #0b1220;
211
+ --hsk-foreground: #e5edf7;
212
+ --hsk-muted: #172033;
213
+ --hsk-muted-foreground: #94a3b8;
214
+ --hsk-border: #314158;
215
+ --hsk-link: #38bdf8;
216
+ --hsk-code-background: #111827;
217
+ }
218
+ ```
219
+
220
+ Then apply the class normally:
221
+
222
+ ```tsx
223
+ <MdKitEditor
224
+ className="my-markdown-editor"
225
+ value={markdown}
226
+ onChange={setMarkdown}
227
+ />
228
+ ```
229
+
230
+ You can also switch theme objects in React:
231
+
232
+ ```tsx
233
+ const style = createMdKitEditorThemeStyle(
234
+ isDark ? darkMdKitEditorTheme : defaultMdKitEditorTheme,
235
+ );
236
+
237
+ <MdKitEditor style={style} value={markdown} onChange={setMarkdown} />;
238
+ ```
239
+
240
+ ## What Not To Customize First
241
+
242
+ Prefer changing CSS variables before overriding internal selectors like
243
+ `.hsk-tiptap p` or `.hsk-editor-surface`. Direct selector overrides are still an
244
+ escape hatch, but they couple your app to mdkit's internal DOM.
245
+
246
+ Use `MdKitThemeEditor` for theme builders, documentation, and debug tooling. It
247
+ is not required for normal editor integration.
package/package.json ADDED
@@ -0,0 +1,105 @@
1
+ {
2
+ "name": "@mp-lb/mdkit",
3
+ "version": "0.0.1-main.2.1",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "docs",
10
+ "src/styles.css"
11
+ ],
12
+ "exports": {
13
+ ".": {
14
+ "source": "./src/index.ts",
15
+ "import": "./dist/index.js",
16
+ "types": "./dist/index.d.ts"
17
+ },
18
+ "./core": {
19
+ "source": "./src/core/index.ts",
20
+ "import": "./dist/core/index.js",
21
+ "types": "./dist/core/index.d.ts"
22
+ },
23
+ "./fastify": {
24
+ "source": "./src/fastify.ts",
25
+ "import": "./dist/fastify.js",
26
+ "types": "./dist/fastify.d.ts"
27
+ },
28
+ "./trpc": {
29
+ "source": "./src/trpc.ts",
30
+ "import": "./dist/trpc.js",
31
+ "types": "./dist/trpc.d.ts"
32
+ },
33
+ "./styles.css": "./src/styles.css",
34
+ "./trpc/client": {
35
+ "source": "./src/trpc/client.ts",
36
+ "import": "./dist/trpc/client.js",
37
+ "types": "./dist/trpc/client.d.ts"
38
+ },
39
+ "./trpc/server": {
40
+ "source": "./src/trpc/server.ts",
41
+ "import": "./dist/trpc/server.js",
42
+ "types": "./dist/trpc/server.d.ts"
43
+ }
44
+ },
45
+ "publishConfig": {
46
+ "access": "public",
47
+ "registry": "https://registry.npmjs.org/"
48
+ },
49
+ "peerDependencies": {
50
+ "@trpc/client": "^11.7.1",
51
+ "@trpc/server": "^11.7.1",
52
+ "fastify": "^5.1.0",
53
+ "react": "^19.2.0",
54
+ "react-dom": "^19.2.0"
55
+ },
56
+ "peerDependenciesMeta": {
57
+ "@trpc/client": {
58
+ "optional": true
59
+ },
60
+ "@trpc/server": {
61
+ "optional": true
62
+ },
63
+ "fastify": {
64
+ "optional": true
65
+ }
66
+ },
67
+ "dependencies": {
68
+ "@hocuspocus/provider": "^2.15.0",
69
+ "@tiptap/extension-collaboration": "^3.14.0",
70
+ "@tiptap/extension-collaboration-caret": "^3.14.0",
71
+ "@tiptap/extension-link": "^3.14.0",
72
+ "@tiptap/extension-placeholder": "^3.14.0",
73
+ "@tiptap/markdown": "^3.20.1",
74
+ "@tiptap/react": "^3.14.0",
75
+ "@tiptap/starter-kit": "^3.14.0",
76
+ "lucide-react": "^0.554.0",
77
+ "yjs": "^13.6.24",
78
+ "zod": "^4.1.12"
79
+ },
80
+ "devDependencies": {
81
+ "@testing-library/jest-dom": "6.9.1",
82
+ "@testing-library/react": "16.3.2",
83
+ "@trpc/client": "^11.7.1",
84
+ "@trpc/server": "^11.7.1",
85
+ "@types/react": "^19.2.5",
86
+ "@types/react-dom": "^19.2.3",
87
+ "dotenv": "^17.4.2",
88
+ "dotenv-expand": "^13.0.0",
89
+ "fastify": "^5.1.0",
90
+ "jsdom": "29.1.1",
91
+ "vite": "7.2.4",
92
+ "vitepress": "^1.6.4",
93
+ "vitest": "4.1.5"
94
+ },
95
+ "scripts": {
96
+ "dev": "tsc --watch --project tsconfig.json",
97
+ "build": "tsc --project tsconfig.json",
98
+ "docs:build": "vitepress build docs",
99
+ "docs:dev": "node scripts/load-docs-env.mjs dev",
100
+ "docs:preview": "node scripts/load-docs-env.mjs preview",
101
+ "release:check": "pnpm typecheck && pnpm test && pnpm build && pnpm docs:build",
102
+ "test": "vitest run",
103
+ "typecheck": "tsc --noEmit --project tsconfig.json"
104
+ }
105
+ }