@mp-lb/mdkit 0.2.2 → 0.2.3-main.21.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 (76) hide show
  1. package/dist/collaboration/useMdKitCollaboration.d.ts +1 -1
  2. package/dist/core/checkpointPolicy.d.ts +25 -0
  3. package/dist/core/checkpointPolicy.js +45 -0
  4. package/dist/core/index.d.ts +2 -0
  5. package/dist/core/index.js +1 -0
  6. package/dist/document/MdKitConflictPanel.d.ts +1 -1
  7. package/dist/document/MdKitConflictPanel.js +1 -1
  8. package/dist/document/MdKitDocumentToolbar.d.ts +3 -3
  9. package/dist/document/MdKitDocumentToolbar.js +1 -1
  10. package/dist/document/useMdKitDocument.d.ts +1 -1
  11. package/dist/fastify.d.ts +3 -3
  12. package/dist/fastify.js +1 -1
  13. package/dist/index.d.ts +29 -25
  14. package/dist/index.js +14 -12
  15. package/dist/markdown/MarkdownBubbleMenu.js +1 -1
  16. package/dist/markdown/MdKitEditor.d.ts +2 -2
  17. package/dist/markdown/MdKitEditor.js +2 -2
  18. package/dist/markdown/MdKitView.js +1 -1
  19. package/dist/markdown/TiptapMarkdownSurface.d.ts +2 -2
  20. package/dist/markdown/TiptapMarkdownSurface.js +33 -25
  21. package/dist/markdown/createMdKitTiptapExtensions.d.ts +8 -0
  22. package/dist/markdown/createMdKitTiptapExtensions.js +27 -0
  23. package/dist/markdown/prepareMarkdownForEditorHydration.js +1 -1
  24. package/dist/markdown/preserveMarkdownWhitespace.js +1 -1
  25. package/dist/server.d.ts +2 -0
  26. package/dist/server.js +1 -0
  27. package/dist/theme/MdKitThemeEditor.d.ts +1 -1
  28. package/dist/transport/backend.d.ts +29 -0
  29. package/dist/transport/backend.js +93 -0
  30. package/dist/transport/fastify.d.ts +1 -1
  31. package/dist/transport/fastify.js +1 -1
  32. package/dist/transport/http.d.ts +1 -1
  33. package/dist/transport/index.d.ts +5 -5
  34. package/dist/transport/index.js +2 -2
  35. package/dist/transport/rest.d.ts +1 -1
  36. package/dist/transport/store.d.ts +1 -1
  37. package/dist/transport/trpcClient.d.ts +29 -8
  38. package/dist/transport/trpcServer.d.ts +1 -1
  39. package/dist/trpc/client.d.ts +3 -3
  40. package/dist/trpc/client.js +1 -1
  41. package/dist/trpc/server.d.ts +5 -3
  42. package/dist/trpc/server.js +2 -1
  43. package/dist/trpc.d.ts +3 -3
  44. package/dist/trpc.js +1 -1
  45. package/dist/versioning/VersionHistoryPanel.d.ts +2 -2
  46. package/dist/versioning/VersionHistoryPanel.js +1 -1
  47. package/dist/versioning/useMdKitDocumentVersions.d.ts +1 -1
  48. package/dist/yjs/MdKitMarkdownYjs.d.ts +12 -0
  49. package/dist/yjs/MdKitMarkdownYjs.js +40 -0
  50. package/dist/yjs/index.d.ts +2 -0
  51. package/dist/yjs/index.js +1 -0
  52. package/docs/.vitepress/cache/deps/@theme_index.js +275 -0
  53. package/docs/.vitepress/cache/deps/@theme_index.js.map +7 -0
  54. package/docs/.vitepress/cache/deps/_metadata.json +40 -0
  55. package/docs/.vitepress/cache/deps/chunk-PM3I3KHC.js +9719 -0
  56. package/docs/.vitepress/cache/deps/chunk-PM3I3KHC.js.map +7 -0
  57. package/docs/.vitepress/cache/deps/chunk-VSHFF4ZG.js +13018 -0
  58. package/docs/.vitepress/cache/deps/chunk-VSHFF4ZG.js.map +7 -0
  59. package/docs/.vitepress/cache/deps/package.json +3 -0
  60. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4505 -0
  61. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  62. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +583 -0
  63. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  64. package/docs/.vitepress/cache/deps/vue.js +347 -0
  65. package/docs/.vitepress/cache/deps/vue.js.map +7 -0
  66. package/docs/.vitepress/config.ts +11 -0
  67. package/docs/api.md +153 -18
  68. package/docs/architecture.md +24 -9
  69. package/docs/collaboration-persistence.md +147 -0
  70. package/docs/index.md +139 -65
  71. package/docs/permissions.md +139 -0
  72. package/docs/rest.md +98 -0
  73. package/docs/shadcn.md +6 -3
  74. package/docs/styling.md +11 -10
  75. package/docs/use-cases.md +148 -0
  76. package/package.json +15 -2
@@ -1,4 +1,4 @@
1
- import type { MdKitCollaborationParticipant, MdKitCollaborationSession } from "../document/documentTypes";
1
+ import type { MdKitCollaborationParticipant, MdKitCollaborationSession } from "../document/documentTypes.js";
2
2
  export type UseMdKitCollaborationOptions = {
3
3
  collaborator: MdKitCollaborationParticipant;
4
4
  documentId: string | null;
@@ -0,0 +1,25 @@
1
+ import type { MdKitDocumentVersionDetail, MdKitDocumentWriteInput, MdKitDocumentWriteResult } from "../document/documentTypes.js";
2
+ export type MdKitCheckpointPolicyInput = {
3
+ currentContent: string;
4
+ documentId: string;
5
+ editDistance: number;
6
+ previousCheckpoint: MdKitDocumentVersionDetail | null;
7
+ previousCheckpointContent: string | null;
8
+ timeSinceLastCheckpointMs: number | null;
9
+ writeInput: MdKitDocumentWriteInput;
10
+ writeResult: MdKitDocumentWriteResult;
11
+ };
12
+ export type MdKitCheckpointPolicy = {
13
+ shouldCheckpoint(input: MdKitCheckpointPolicyInput): boolean | Promise<boolean>;
14
+ };
15
+ export type MdKitSmartCheckpointPolicyOptions = {
16
+ minEditDistance?: number;
17
+ minIntervalMs?: number;
18
+ };
19
+ export declare const measureMdKitEditDistance: (left: string, right: string) => number;
20
+ export declare const CheckpointPolicy: {
21
+ readonly always: () => MdKitCheckpointPolicy;
22
+ readonly function: (shouldCheckpoint: MdKitCheckpointPolicy["shouldCheckpoint"]) => MdKitCheckpointPolicy;
23
+ readonly never: () => MdKitCheckpointPolicy;
24
+ readonly smart: (options?: MdKitSmartCheckpointPolicyOptions) => MdKitCheckpointPolicy;
25
+ };
@@ -0,0 +1,45 @@
1
+ const defaultMinEditDistance = 250;
2
+ const defaultMinIntervalMs = 5 * 60_000;
3
+ export const measureMdKitEditDistance = (left, right) => {
4
+ if (left === right) {
5
+ return 0;
6
+ }
7
+ if (left.length === 0) {
8
+ return right.length;
9
+ }
10
+ if (right.length === 0) {
11
+ return left.length;
12
+ }
13
+ let previous = Array.from({ length: right.length + 1 }, (_, index) => index);
14
+ let current = new Array(right.length + 1);
15
+ for (let leftIndex = 1; leftIndex <= left.length; leftIndex += 1) {
16
+ current[0] = leftIndex;
17
+ for (let rightIndex = 1; rightIndex <= right.length; rightIndex += 1) {
18
+ const cost = left[leftIndex - 1] === right[rightIndex - 1] ? 0 : 1;
19
+ current[rightIndex] = Math.min(current[rightIndex - 1] + 1, previous[rightIndex] + 1, previous[rightIndex - 1] + cost);
20
+ }
21
+ [previous, current] = [current, previous];
22
+ }
23
+ return previous[right.length] ?? 0;
24
+ };
25
+ export const CheckpointPolicy = {
26
+ always: () => ({
27
+ shouldCheckpoint: () => true,
28
+ }),
29
+ function: (shouldCheckpoint) => ({
30
+ shouldCheckpoint,
31
+ }),
32
+ never: () => ({
33
+ shouldCheckpoint: () => false,
34
+ }),
35
+ smart: (options = {}) => {
36
+ const minEditDistance = options.minEditDistance ?? defaultMinEditDistance;
37
+ const minIntervalMs = options.minIntervalMs ?? defaultMinIntervalMs;
38
+ return {
39
+ shouldCheckpoint: ({ editDistance, previousCheckpoint, timeSinceLastCheckpointMs, }) => !previousCheckpoint ||
40
+ editDistance >= minEditDistance ||
41
+ (timeSinceLastCheckpointMs !== null &&
42
+ timeSinceLastCheckpointMs >= minIntervalMs),
43
+ };
44
+ },
45
+ };
@@ -1,3 +1,5 @@
1
1
  export { createMdKitDocumentRecord, detectMdKitDocumentConflict, normalizeMdKitVersionToken, restoreMdKitDocumentVersion, writeMdKitDocumentRecord, } from "./documentEngine.js";
2
+ export { CheckpointPolicy, measureMdKitEditDistance, } from "./checkpointPolicy.js";
2
3
  export type { CreateMdKitDocumentRecordInput, MdKitDocumentRecord, RestoreMdKitDocumentVersionInput, RestoreMdKitDocumentVersionResult, WriteMdKitDocumentRecordInput, WriteMdKitDocumentRecordResult, } from "./documentEngine.js";
4
+ export type { MdKitCheckpointPolicy, MdKitCheckpointPolicyInput, MdKitSmartCheckpointPolicyOptions, } from "./checkpointPolicy.js";
3
5
  export type { MdKitDocumentSnapshot, MdKitDocumentVersionDetail, MdKitDocumentVersionSummary, MdKitDocumentVersionToken, MdKitDocumentWriteInput, MdKitDocumentWriteResult, } from "../document/documentTypes.js";
@@ -1 +1,2 @@
1
1
  export { createMdKitDocumentRecord, detectMdKitDocumentConflict, normalizeMdKitVersionToken, restoreMdKitDocumentVersion, writeMdKitDocumentRecord, } from "./documentEngine.js";
2
+ export { CheckpointPolicy, measureMdKitEditDistance, } from "./checkpointPolicy.js";
@@ -1,4 +1,4 @@
1
- import type { MdKitDocumentController } from "./useMdKitDocument";
1
+ import type { MdKitDocumentController } from "./useMdKitDocument.js";
2
2
  export type MdKitConflictPanelProps = {
3
3
  className?: string;
4
4
  document: MdKitDocumentController;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from "react";
3
- import { joinClassNames } from "../ui/joinClassNames";
3
+ import { joinClassNames } from "../ui/joinClassNames.js";
4
4
  export const MdKitConflictPanel = ({ className, document, title = "Document conflict", }) => {
5
5
  const [pendingAction, setPendingAction] = useState(null);
6
6
  const [activePreview, setActivePreview] = useState("remote");
@@ -1,6 +1,6 @@
1
- import type { MdKitCollaborationSession } from "./documentTypes";
2
- import type { MdKitDocumentController } from "./useMdKitDocument";
3
- import type { MdKitDocumentVersionsController } from "../versioning/useMdKitDocumentVersions";
1
+ import type { MdKitCollaborationSession } from "./documentTypes.js";
2
+ import type { MdKitDocumentController } from "./useMdKitDocument.js";
3
+ import type { MdKitDocumentVersionsController } from "../versioning/useMdKitDocumentVersions.js";
4
4
  export type MdKitDocumentToolbarProps = {
5
5
  className?: string;
6
6
  collaboration?: MdKitCollaborationSession | null;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from "react";
3
- import { joinClassNames } from "../ui/joinClassNames";
3
+ import { joinClassNames } from "../ui/joinClassNames.js";
4
4
  const formatUpdatedAt = (updatedAt) => {
5
5
  if (!updatedAt) {
6
6
  return "Never saved";
@@ -1,4 +1,4 @@
1
- import type { MdKitDocumentAdapter, MdKitDocumentVersionToken } from "./documentTypes";
1
+ import type { MdKitDocumentAdapter, MdKitDocumentVersionToken } from "./documentTypes.js";
2
2
  export type UseMdKitDocumentOptions = {
3
3
  adapter: Pick<MdKitDocumentAdapter, "readDocument" | "writeDocument" | "resyncDocument">;
4
4
  debounceMs?: number;
package/dist/fastify.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { registerMdKitFastify } from "./transport/fastify";
2
- export type { RegisterMdKitFastifyOptions } from "./transport/fastify";
3
- export type { MdKitRestoreDocumentVersionInput, MdKitTransportStore, } from "./transport/store";
1
+ export { registerMdKitFastify } from "./transport/fastify.js";
2
+ export type { RegisterMdKitFastifyOptions } from "./transport/fastify.js";
3
+ export type { MdKitRestoreDocumentVersionInput, MdKitTransportStore, } from "./transport/store.js";
package/dist/fastify.js CHANGED
@@ -1 +1 @@
1
- export { registerMdKitFastify } from "./transport/fastify";
1
+ export { registerMdKitFastify } from "./transport/fastify.js";
package/dist/index.d.ts CHANGED
@@ -1,25 +1,29 @@
1
- export { useMdKitCollaboration } from "./collaboration/useMdKitCollaboration";
2
- export { createMdKitDocumentRecord, detectMdKitDocumentConflict, normalizeMdKitVersionToken, restoreMdKitDocumentVersion, writeMdKitDocumentRecord, } from "./core/documentEngine";
3
- export { useMdKitDocument } from "./document/useMdKitDocument";
4
- export { MdKitConflictPanel } from "./document/MdKitConflictPanel";
5
- export { MdKitDocumentToolbar } from "./document/MdKitDocumentToolbar";
6
- export { MdKitEditor } from "./markdown/MdKitEditor";
7
- export { MdKitView } from "./markdown/MdKitView";
8
- export { MdKitThemeEditor } from "./theme/MdKitThemeEditor";
9
- export { createMdKitRestAdapter } from "./transport/rest";
10
- export { createMdKitEditorThemeStyle, darkMdKitEditorTheme, defaultMdKitEditorTheme, } from "./theme/editorTheme";
11
- export { VersionHistoryPanel } from "./versioning/VersionHistoryPanel";
12
- export { useMdKitDocumentVersions } from "./versioning/useMdKitDocumentVersions";
13
- export type { CreateMdKitDocumentRecordInput, MdKitDocumentRecord, RestoreMdKitDocumentVersionInput, RestoreMdKitDocumentVersionResult, WriteMdKitDocumentRecordInput, WriteMdKitDocumentRecordResult, } from "./core/documentEngine";
14
- export type { MdKitCollaborationParticipant, MdKitCollaborationSession, MdKitCollaborationStatus, MdKitDocumentAdapter, MdKitDocumentSnapshot, MdKitDocumentVersionDetail, MdKitDocumentVersionSummary, MdKitDocumentVersionToken, MdKitDocumentWriteInput, MdKitDocumentWriteResult, } from "./document/documentTypes";
15
- export type { MdKitDocumentConflictDetails, MdKitDocumentController, } from "./document/useMdKitDocument";
16
- export type { MdKitConflictPanelProps } from "./document/MdKitConflictPanel";
17
- export type { MdKitDocumentToolbarProps } from "./document/MdKitDocumentToolbar";
18
- export type { MdKitEditorProps } from "./markdown/MdKitEditor";
19
- export type { MdKitEditorDebugEvent } from "./markdown/editorDebug";
20
- export type { MdKitViewProps } from "./markdown/MdKitView";
21
- export type { MdKitThemeEditorProps } from "./theme/MdKitThemeEditor";
22
- export type { CreateMdKitRestAdapterOptions } from "./transport/rest";
23
- export type { MdKitEditorTheme, MdKitEditorThemeStyle, } from "./theme/editorTheme";
24
- export type { MdKitDocumentVersionsController, UseMdKitDocumentVersionsOptions, } from "./versioning/useMdKitDocumentVersions";
25
- export type { VersionHistoryPanelProps } from "./versioning/VersionHistoryPanel";
1
+ export { useMdKitCollaboration } from "./collaboration/useMdKitCollaboration.js";
2
+ export { CheckpointPolicy, measureMdKitEditDistance, } from "./core/checkpointPolicy.js";
3
+ export { createMdKitDocumentRecord, detectMdKitDocumentConflict, normalizeMdKitVersionToken, restoreMdKitDocumentVersion, writeMdKitDocumentRecord, } from "./core/documentEngine.js";
4
+ export { useMdKitDocument } from "./document/useMdKitDocument.js";
5
+ export { MdKitConflictPanel } from "./document/MdKitConflictPanel.js";
6
+ export { MdKitDocumentToolbar } from "./document/MdKitDocumentToolbar.js";
7
+ export { MdKitEditor } from "./markdown/MdKitEditor.js";
8
+ export { MdKitView } from "./markdown/MdKitView.js";
9
+ export { MdKitThemeEditor } from "./theme/MdKitThemeEditor.js";
10
+ export { createMdKitRestAdapter } from "./transport/rest.js";
11
+ export { createMdKitEditorThemeStyle, darkMdKitEditorTheme, defaultMdKitEditorTheme, } from "./theme/editorTheme.js";
12
+ export { VersionHistoryPanel } from "./versioning/VersionHistoryPanel.js";
13
+ export { useMdKitDocumentVersions } from "./versioning/useMdKitDocumentVersions.js";
14
+ export { yjs } from "./yjs/index.js";
15
+ export type { MdKitCheckpointPolicy, MdKitCheckpointPolicyInput, MdKitSmartCheckpointPolicyOptions, } from "./core/checkpointPolicy.js";
16
+ export type { CreateMdKitDocumentRecordInput, MdKitDocumentRecord, RestoreMdKitDocumentVersionInput, RestoreMdKitDocumentVersionResult, WriteMdKitDocumentRecordInput, WriteMdKitDocumentRecordResult, } from "./core/documentEngine.js";
17
+ export type { MdKitCollaborationParticipant, MdKitCollaborationSession, MdKitCollaborationStatus, MdKitDocumentAdapter, MdKitDocumentSnapshot, MdKitDocumentVersionDetail, MdKitDocumentVersionSummary, MdKitDocumentVersionToken, MdKitDocumentWriteInput, MdKitDocumentWriteResult, } from "./document/documentTypes.js";
18
+ export type { MdKitDocumentConflictDetails, MdKitDocumentController, } from "./document/useMdKitDocument.js";
19
+ export type { MdKitConflictPanelProps } from "./document/MdKitConflictPanel.js";
20
+ export type { MdKitDocumentToolbarProps } from "./document/MdKitDocumentToolbar.js";
21
+ export type { MdKitEditorProps } from "./markdown/MdKitEditor.js";
22
+ export type { MdKitEditorDebugEvent } from "./markdown/editorDebug.js";
23
+ export type { MdKitViewProps } from "./markdown/MdKitView.js";
24
+ export type { MdKitThemeEditorProps } from "./theme/MdKitThemeEditor.js";
25
+ export type { CreateMdKitRestAdapterOptions } from "./transport/rest.js";
26
+ export type { MdKitEditorTheme, MdKitEditorThemeStyle, } from "./theme/editorTheme.js";
27
+ export type { MdKitDocumentVersionsController, UseMdKitDocumentVersionsOptions, } from "./versioning/useMdKitDocumentVersions.js";
28
+ export type { VersionHistoryPanelProps } from "./versioning/VersionHistoryPanel.js";
29
+ export type { MdKitMarkdownYjsOptions } from "./yjs/index.js";
package/dist/index.js CHANGED
@@ -1,12 +1,14 @@
1
- export { useMdKitCollaboration } from "./collaboration/useMdKitCollaboration";
2
- export { createMdKitDocumentRecord, detectMdKitDocumentConflict, normalizeMdKitVersionToken, restoreMdKitDocumentVersion, writeMdKitDocumentRecord, } from "./core/documentEngine";
3
- export { useMdKitDocument } from "./document/useMdKitDocument";
4
- export { MdKitConflictPanel } from "./document/MdKitConflictPanel";
5
- export { MdKitDocumentToolbar } from "./document/MdKitDocumentToolbar";
6
- export { MdKitEditor } from "./markdown/MdKitEditor";
7
- export { MdKitView } from "./markdown/MdKitView";
8
- export { MdKitThemeEditor } from "./theme/MdKitThemeEditor";
9
- export { createMdKitRestAdapter } from "./transport/rest";
10
- export { createMdKitEditorThemeStyle, darkMdKitEditorTheme, defaultMdKitEditorTheme, } from "./theme/editorTheme";
11
- export { VersionHistoryPanel } from "./versioning/VersionHistoryPanel";
12
- export { useMdKitDocumentVersions } from "./versioning/useMdKitDocumentVersions";
1
+ export { useMdKitCollaboration } from "./collaboration/useMdKitCollaboration.js";
2
+ export { CheckpointPolicy, measureMdKitEditDistance, } from "./core/checkpointPolicy.js";
3
+ export { createMdKitDocumentRecord, detectMdKitDocumentConflict, normalizeMdKitVersionToken, restoreMdKitDocumentVersion, writeMdKitDocumentRecord, } from "./core/documentEngine.js";
4
+ export { useMdKitDocument } from "./document/useMdKitDocument.js";
5
+ export { MdKitConflictPanel } from "./document/MdKitConflictPanel.js";
6
+ export { MdKitDocumentToolbar } from "./document/MdKitDocumentToolbar.js";
7
+ export { MdKitEditor } from "./markdown/MdKitEditor.js";
8
+ export { MdKitView } from "./markdown/MdKitView.js";
9
+ export { MdKitThemeEditor } from "./theme/MdKitThemeEditor.js";
10
+ export { createMdKitRestAdapter } from "./transport/rest.js";
11
+ export { createMdKitEditorThemeStyle, darkMdKitEditorTheme, defaultMdKitEditorTheme, } from "./theme/editorTheme.js";
12
+ export { VersionHistoryPanel } from "./versioning/VersionHistoryPanel.js";
13
+ export { useMdKitDocumentVersions } from "./versioning/useMdKitDocumentVersions.js";
14
+ export { yjs } from "./yjs/index.js";
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEditorState } from "@tiptap/react";
3
3
  import { BubbleMenu } from "@tiptap/react/menus";
4
4
  import { Bold, Code2, Heading1, Heading2, Italic, Link2, List, ListOrdered, Quote, Strikethrough, } from "lucide-react";
5
- import { joinClassNames } from "../ui/joinClassNames";
5
+ import { joinClassNames } from "../ui/joinClassNames.js";
6
6
  const toolbarActiveStateIsEqual = (left, right) => {
7
7
  if (!right) {
8
8
  return false;
@@ -1,6 +1,6 @@
1
1
  import type { CSSProperties } from "react";
2
- import type { MdKitCollaborationSession } from "../document/documentTypes";
3
- import type { MdKitEditorDebugEvent } from "./editorDebug";
2
+ import type { MdKitCollaborationSession } from "../document/documentTypes.js";
3
+ import type { MdKitEditorDebugEvent } from "./editorDebug.js";
4
4
  type MdKitEditorBaseProps = {
5
5
  className?: string;
6
6
  fillHeight?: boolean;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { joinClassNames } from "../ui/joinClassNames";
3
- import { TiptapMarkdownSurface } from "./TiptapMarkdownSurface";
2
+ import { joinClassNames } from "../ui/joinClassNames.js";
3
+ import { TiptapMarkdownSurface } from "./TiptapMarkdownSurface.js";
4
4
  export const MdKitEditor = (props) => {
5
5
  const { className, fillHeight = false, readOnly = false, style, ...surfaceProps } = props;
6
6
  return (_jsx("div", { className: joinClassNames("mp-lb-mdkit-markdown-editor", fillHeight && "mp-lb-mdkit-markdown-editor-fill-height", className), "data-read-only": readOnly ? "true" : undefined, style: style, children: _jsx(TiptapMarkdownSurface, { readOnly: readOnly, ...surfaceProps }, props.instanceKey) }));
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import ReactMarkdown from "react-markdown";
3
3
  import remarkGfm from "remark-gfm";
4
- import { joinClassNames } from "../ui/joinClassNames";
4
+ import { joinClassNames } from "../ui/joinClassNames.js";
5
5
  export const MdKitView = ({ className, fillHeight = false, placeholder, style, value, }) => {
6
6
  const renderedValue = value.trim().length > 0 ? value : (placeholder ?? "");
7
7
  return (_jsx("div", { className: joinClassNames("mp-lb-mdkit-markdown-editor", "mp-lb-mdkit-markdown-view", fillHeight && "mp-lb-mdkit-markdown-editor-fill-height", className), "data-read-only": "true", style: style, children: _jsx("div", { className: "mp-lb-mdkit-editor-shell", children: _jsx("div", { className: "mp-lb-mdkit-editor-surface", children: renderedValue.length > 0 ? (_jsx("div", { className: "mp-lb-mdkit-tiptap mp-lb-mdkit-view-content", children: _jsx(ReactMarkdown, { components: {
@@ -1,5 +1,5 @@
1
- import type { MdKitCollaborationSession } from "../document/documentTypes";
2
- import type { MdKitEditorDebugEvent } from "./editorDebug";
1
+ import type { MdKitCollaborationSession } from "../document/documentTypes.js";
2
+ import type { MdKitEditorDebugEvent } from "./editorDebug.js";
3
3
  type LocalTiptapMarkdownSurfaceProps = {
4
4
  collaboration?: null;
5
5
  onChange?: (markdown: string) => void;
@@ -2,13 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useRef } from "react";
3
3
  import Collaboration from "@tiptap/extension-collaboration";
4
4
  import CollaborationCaret from "@tiptap/extension-collaboration-caret";
5
- import { Markdown } from "@tiptap/markdown";
6
- import Placeholder from "@tiptap/extension-placeholder";
7
5
  import { EditorContent, useEditor } from "@tiptap/react";
8
- import StarterKit from "@tiptap/starter-kit";
9
- import { MarkdownBubbleMenu } from "./MarkdownBubbleMenu";
10
- import { normalizeMarkdownSerialization } from "./normalizeMarkdownSerialization";
11
- import { prepareMarkdownForEditorHydration } from "./prepareMarkdownForEditorHydration";
6
+ import { createMdKitTiptapExtensions } from "./createMdKitTiptapExtensions.js";
7
+ import { MarkdownBubbleMenu } from "./MarkdownBubbleMenu.js";
8
+ import { normalizeMarkdownSerialization } from "./normalizeMarkdownSerialization.js";
9
+ import { prepareMarkdownForEditorHydration } from "./prepareMarkdownForEditorHydration.js";
12
10
  const describeElement = (element) => {
13
11
  const classes = element instanceof HTMLElement && element.className
14
12
  ? `.${String(element.className).trim().replace(/\s+/g, ".")}`
@@ -123,26 +121,9 @@ export const TiptapMarkdownSurface = (props) => {
123
121
  },
124
122
  },
125
123
  extensions: [
126
- StarterKit.configure({
127
- heading: { levels: [1, 2] },
128
- link: {
129
- HTMLAttributes: {
130
- rel: "noopener noreferrer",
131
- target: "_blank",
132
- },
133
- autolink: true,
134
- linkOnPaste: true,
135
- openOnClick: true,
136
- },
137
- undoRedo: hasCollaboration ? false : undefined,
138
- }),
139
- Placeholder.configure({
124
+ ...createMdKitTiptapExtensions({
140
125
  placeholder,
141
- }),
142
- Markdown.configure({
143
- markedOptions: {
144
- gfm: true,
145
- },
126
+ undoRedo: !hasCollaboration,
146
127
  }),
147
128
  ...(collaborationDocument
148
129
  ? [
@@ -191,6 +172,33 @@ export const TiptapMarkdownSurface = (props) => {
191
172
  useEffect(() => {
192
173
  editor?.setEditable(!readOnly);
193
174
  }, [editor, readOnly]);
175
+ useEffect(() => {
176
+ if (!editor) {
177
+ return;
178
+ }
179
+ const blurEditorOnExternalPointerDown = (event) => {
180
+ if (editor.isDestroyed) {
181
+ return;
182
+ }
183
+ const target = event.target;
184
+ if (!(target instanceof Element)) {
185
+ return;
186
+ }
187
+ if (editorSurfaceRef.current?.contains(target) ||
188
+ target.closest(".mp-lb-mdkit-toolbar")) {
189
+ return;
190
+ }
191
+ editor.commands.blur();
192
+ };
193
+ document.addEventListener("pointerdown", blurEditorOnExternalPointerDown, {
194
+ capture: true,
195
+ });
196
+ return () => {
197
+ document.removeEventListener("pointerdown", blurEditorOnExternalPointerDown, {
198
+ capture: true,
199
+ });
200
+ };
201
+ }, [editor]);
194
202
  useEffect(() => {
195
203
  if (!editor) {
196
204
  return;
@@ -0,0 +1,8 @@
1
+ import type { Extensions } from "@tiptap/core";
2
+ type CreateMdKitTiptapExtensionsOptions = {
3
+ placeholder?: string;
4
+ undoRedo?: boolean;
5
+ };
6
+ export declare const defaultMdKitMarkdownPlaceholder = "Start writing...";
7
+ export declare const createMdKitTiptapExtensions: ({ placeholder, undoRedo, }?: CreateMdKitTiptapExtensionsOptions) => Extensions;
8
+ export {};
@@ -0,0 +1,27 @@
1
+ import { Markdown } from "@tiptap/markdown";
2
+ import Placeholder from "@tiptap/extension-placeholder";
3
+ import StarterKit from "@tiptap/starter-kit";
4
+ export const defaultMdKitMarkdownPlaceholder = "Start writing...";
5
+ export const createMdKitTiptapExtensions = ({ placeholder = defaultMdKitMarkdownPlaceholder, undoRedo = true, } = {}) => [
6
+ StarterKit.configure({
7
+ heading: { levels: [1, 2] },
8
+ link: {
9
+ HTMLAttributes: {
10
+ rel: "noopener noreferrer",
11
+ target: "_blank",
12
+ },
13
+ autolink: true,
14
+ linkOnPaste: true,
15
+ openOnClick: true,
16
+ },
17
+ undoRedo: undoRedo ? undefined : false,
18
+ }),
19
+ Placeholder.configure({
20
+ placeholder,
21
+ }),
22
+ Markdown.configure({
23
+ markedOptions: {
24
+ gfm: true,
25
+ },
26
+ }),
27
+ ];
@@ -1,4 +1,4 @@
1
- import { getMarkdownFenceRanges, isInsideMarkdownFence, } from "./markdownFenceRanges";
1
+ import { getMarkdownFenceRanges, isInsideMarkdownFence, } from "./markdownFenceRanges.js";
2
2
  const expandedBlankLineRunPattern = /\n{3,}/g;
3
3
  export const prepareMarkdownForEditorHydration = (markdown) => {
4
4
  const fenceRanges = getMarkdownFenceRanges(markdown);
@@ -1,4 +1,4 @@
1
- import { getMarkdownFenceRanges, isInsideMarkdownFence, } from "./markdownFenceRanges";
1
+ import { getMarkdownFenceRanges, isInsideMarkdownFence, } from "./markdownFenceRanges.js";
2
2
  const tokenizeMarkdownBlocks = (markdown) => {
3
3
  const ranges = getMarkdownFenceRanges(markdown);
4
4
  const tokens = [];
@@ -0,0 +1,2 @@
1
+ export { createMdKitBackend } from "./transport/backend.js";
2
+ export type { CreateMdKitBackendOptions, MdKitBackendStore, MdKitCreateCheckpointInput, } from "./transport/backend.js";
package/dist/server.js ADDED
@@ -0,0 +1 @@
1
+ export { createMdKitBackend } from "./transport/backend.js";
@@ -1,4 +1,4 @@
1
- import type { MdKitEditorTheme } from "./editorTheme";
1
+ import type { MdKitEditorTheme } from "./editorTheme.js";
2
2
  export type MdKitThemeEditorProps = {
3
3
  className?: string;
4
4
  onChange: (theme: MdKitEditorTheme) => void;
@@ -0,0 +1,29 @@
1
+ import type { MdKitDocumentSnapshot, MdKitDocumentVersionDetail, MdKitDocumentVersionSummary, MdKitDocumentVersionToken, MdKitDocumentWriteInput, MdKitDocumentWriteResult } from "../document/documentTypes.js";
2
+ import { type MdKitCheckpointPolicy } from "../core/checkpointPolicy.js";
3
+ import type { MdKitRestoreDocumentVersionInput, MdKitTransportStore } from "./store.js";
4
+ export type MdKitCreateCheckpointInput = {
5
+ content: string;
6
+ documentId: string;
7
+ metadata?: unknown;
8
+ sourceRevision: MdKitDocumentVersionToken;
9
+ };
10
+ export type MdKitBackendStore = {
11
+ createCheckpoint?(input: MdKitCreateCheckpointInput): Promise<MdKitDocumentVersionSummary> | MdKitDocumentVersionSummary;
12
+ getLatestCheckpoint?(documentId: string): Promise<MdKitDocumentVersionDetail | null> | MdKitDocumentVersionDetail | null;
13
+ listDocumentVersions?(documentId: string): Promise<MdKitDocumentVersionSummary[]> | MdKitDocumentVersionSummary[];
14
+ readCollaborationState?(documentName: string): Promise<Uint8Array | null> | Uint8Array | null;
15
+ readDocument(documentId: string): Promise<MdKitDocumentSnapshot> | MdKitDocumentSnapshot;
16
+ readDocumentVersion?(input: {
17
+ documentId: string;
18
+ versionId: string;
19
+ }): Promise<MdKitDocumentVersionDetail | null> | MdKitDocumentVersionDetail | null;
20
+ resyncDocument?(documentId: string): Promise<MdKitDocumentSnapshot> | MdKitDocumentSnapshot;
21
+ restoreDocumentVersion?(input: MdKitRestoreDocumentVersionInput): Promise<MdKitDocumentWriteResult> | MdKitDocumentWriteResult;
22
+ writeCollaborationState?(documentName: string, state: Uint8Array): Promise<void> | void;
23
+ writeDocument(input: MdKitDocumentWriteInput): Promise<MdKitDocumentWriteResult> | MdKitDocumentWriteResult;
24
+ };
25
+ export type CreateMdKitBackendOptions = {
26
+ checkpointPolicy?: MdKitCheckpointPolicy;
27
+ store: MdKitBackendStore;
28
+ };
29
+ export declare const createMdKitBackend: ({ checkpointPolicy, store, }: CreateMdKitBackendOptions) => MdKitTransportStore;
@@ -0,0 +1,93 @@
1
+ import { CheckpointPolicy, measureMdKitEditDistance, } from "../core/checkpointPolicy.js";
2
+ const timestampMs = (value) => {
3
+ if (!value) {
4
+ return null;
5
+ }
6
+ const timestamp = Date.parse(value);
7
+ return Number.isFinite(timestamp) ? timestamp : null;
8
+ };
9
+ const successfulWriteRevision = (result) => "conflict" in result ? null : result.version;
10
+ const latestCheckpointFromList = async (store, documentId) => {
11
+ const versions = await store.listDocumentVersions?.(documentId);
12
+ const latestSummary = versions?.at(-1);
13
+ if (!latestSummary || !store.readDocumentVersion) {
14
+ return null;
15
+ }
16
+ return store.readDocumentVersion({
17
+ documentId,
18
+ versionId: latestSummary.id,
19
+ });
20
+ };
21
+ const readLatestCheckpoint = async (store, documentId) => (await store.getLatestCheckpoint?.(documentId)) ??
22
+ (await latestCheckpointFromList(store, documentId));
23
+ const maybeCreateCheckpoint = async (store, policy, input, result) => {
24
+ const sourceRevision = successfulWriteRevision(result);
25
+ if (!store.createCheckpoint || sourceRevision === null) {
26
+ return;
27
+ }
28
+ const previousCheckpoint = await readLatestCheckpoint(store, input.documentId);
29
+ const previousCheckpointContent = previousCheckpoint?.content ?? null;
30
+ const editDistance = measureMdKitEditDistance(previousCheckpointContent ?? "", input.content);
31
+ const checkpointTimestamp = timestampMs(previousCheckpoint?.createdAt);
32
+ const timeSinceLastCheckpointMs = checkpointTimestamp === null ? null : Date.now() - checkpointTimestamp;
33
+ const shouldCheckpoint = await policy.shouldCheckpoint({
34
+ currentContent: input.content,
35
+ documentId: input.documentId,
36
+ editDistance,
37
+ previousCheckpoint,
38
+ previousCheckpointContent,
39
+ timeSinceLastCheckpointMs,
40
+ writeInput: input,
41
+ writeResult: result,
42
+ });
43
+ if (!shouldCheckpoint) {
44
+ return;
45
+ }
46
+ await store.createCheckpoint({
47
+ content: input.content,
48
+ documentId: input.documentId,
49
+ sourceRevision,
50
+ });
51
+ };
52
+ const restoreWithStorePrimitives = async (store, input) => {
53
+ if (!store.readDocumentVersion) {
54
+ if (!store.restoreDocumentVersion) {
55
+ throw new Error("Version restore is not supported");
56
+ }
57
+ return store.restoreDocumentVersion(input);
58
+ }
59
+ const restoredVersion = await store.readDocumentVersion(input);
60
+ if (!restoredVersion) {
61
+ throw new Error(`Version not found: ${input.versionId}`);
62
+ }
63
+ const current = await store.readDocument(input.documentId);
64
+ const latestCheckpoint = await readLatestCheckpoint(store, input.documentId);
65
+ if (store.createCheckpoint &&
66
+ latestCheckpoint?.content !== current.content) {
67
+ await store.createCheckpoint({
68
+ content: current.content,
69
+ documentId: input.documentId,
70
+ sourceRevision: current.version,
71
+ });
72
+ }
73
+ return store.writeDocument({
74
+ baseVersion: current.version,
75
+ content: restoredVersion.content,
76
+ documentId: input.documentId,
77
+ force: true,
78
+ });
79
+ };
80
+ export const createMdKitBackend = ({ checkpointPolicy = CheckpointPolicy.never(), store, }) => ({
81
+ listDocumentVersions: (documentId) => store.listDocumentVersions?.(documentId) ?? [],
82
+ readCollaborationState: (documentName) => store.readCollaborationState?.(documentName) ?? null,
83
+ readDocument: (documentId) => store.readDocument(documentId),
84
+ readDocumentVersion: (input) => store.readDocumentVersion?.(input) ?? null,
85
+ resyncDocument: (documentId) => (store.resyncDocument ?? store.readDocument)(documentId),
86
+ restoreDocumentVersion: (input) => restoreWithStorePrimitives(store, input),
87
+ writeCollaborationState: (documentName, state) => store.writeCollaborationState?.(documentName, state),
88
+ writeDocument: async (input) => {
89
+ const result = await store.writeDocument(input);
90
+ await maybeCreateCheckpoint(store, checkpointPolicy, input, result);
91
+ return result;
92
+ },
93
+ });
@@ -1,5 +1,5 @@
1
1
  import type { FastifyInstance } from "fastify";
2
- import type { MdKitTransportStore } from "./store";
2
+ import type { MdKitTransportStore } from "./store.js";
3
3
  export type RegisterMdKitFastifyOptions = {
4
4
  prefix?: string;
5
5
  store: MdKitTransportStore;
@@ -1,4 +1,4 @@
1
- import { createMdKitHttpHandlers } from "./http";
1
+ import { createMdKitHttpHandlers } from "./http.js";
2
2
  const send = async (reply, response) => {
3
3
  const { body, status } = await response;
4
4
  return reply.status(status).send(body);
@@ -1,4 +1,4 @@
1
- import type { MdKitTransportStore } from "./store";
1
+ import type { MdKitTransportStore } from "./store.js";
2
2
  export type MdKitHttpRequest = {
3
3
  body?: unknown;
4
4
  params?: Record<string, unknown>;
@@ -1,5 +1,5 @@
1
- export { createMdKitHttpHandlers } from "./http";
2
- export { createMdKitRestAdapter } from "./rest";
3
- export type { MdKitHttpHandlers, MdKitHttpRequest, MdKitHttpResponse, } from "./http";
4
- export type { CreateMdKitRestAdapterOptions } from "./rest";
5
- export type { MdKitRestoreDocumentVersionInput, MdKitTransportStore, } from "./store";
1
+ export { createMdKitHttpHandlers } from "./http.js";
2
+ export { createMdKitRestAdapter } from "./rest.js";
3
+ export type { MdKitHttpHandlers, MdKitHttpRequest, MdKitHttpResponse, } from "./http.js";
4
+ export type { CreateMdKitRestAdapterOptions } from "./rest.js";
5
+ export type { MdKitRestoreDocumentVersionInput, MdKitTransportStore, } from "./store.js";
@@ -1,2 +1,2 @@
1
- export { createMdKitHttpHandlers } from "./http";
2
- export { createMdKitRestAdapter } from "./rest";
1
+ export { createMdKitHttpHandlers } from "./http.js";
2
+ export { createMdKitRestAdapter } from "./rest.js";
@@ -1,4 +1,4 @@
1
- import type { MdKitDocumentAdapter } from "../document/documentTypes";
1
+ import type { MdKitDocumentAdapter } from "../document/documentTypes.js";
2
2
  export type CreateMdKitRestAdapterOptions = {
3
3
  baseUrl: string;
4
4
  fetch?: typeof fetch;
@@ -1,4 +1,4 @@
1
- import type { MdKitDocumentSnapshot, MdKitDocumentVersionDetail, MdKitDocumentVersionSummary, MdKitDocumentWriteInput, MdKitDocumentWriteResult } from "../document/documentTypes";
1
+ import type { MdKitDocumentSnapshot, MdKitDocumentVersionDetail, MdKitDocumentVersionSummary, MdKitDocumentWriteInput, MdKitDocumentWriteResult } from "../document/documentTypes.js";
2
2
  export type MdKitTransportStore = {
3
3
  readDocument(documentId: string): Promise<MdKitDocumentSnapshot> | MdKitDocumentSnapshot;
4
4
  writeDocument(input: MdKitDocumentWriteInput): Promise<MdKitDocumentWriteResult> | MdKitDocumentWriteResult;