documint 0.0.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 ADDED
@@ -0,0 +1,65 @@
1
+ # 🌿 Documint
2
+
3
+ A canvas-based, batteries-included markdown editor for React.
4
+
5
+ > Try it out: [Documint playground](https://lostintangent.github.io/documint).
6
+
7
+ ## Features
8
+
9
+ - **Markdown in, markdown out** — Documents are parsed from markdown and serialized back to markdown. Full support for CommonMark, GFM tables, task lists, strikethrough, and fenced code blocks with language hints.
10
+
11
+ - **Subtle, delightful animations** — A typing trail highlights newly inserted text. Deleted text fades out before disappearing. List markers pop into place. Punctuation pulses with a soft ring on keystroke. Small details that make editing feel fun.
12
+
13
+ - **Mobile-native editing** — Responsive layout with full support for iOS and Android gestures: auto-capitalization, auto-correct, auto-scroll on keyboard appearance, shake-to-undo, and selection handles all work as expected.
14
+
15
+ - **Rich semantic editing** — Context-sensitive behavior that adapts to what you're editing. Enter splits a paragraph but adds a new row in a table. Backspace at the start of a list item dedents it. Tab indents a list but inserts a column in a table. The editor understands the structure of your document, so every gesture does the right thing.
16
+
17
+ - **Context-aware toolbars ("leaves")** — Floating toolbars that appear based on what you're interacting with: text formatting options on selection, link editing on links, column/row controls on tables, and block insertion (headings, lists, quotes, tables) on empty lines.
18
+
19
+ - **Configurable themes and keybindings** — Ships with built-in light and dark themes, follows the system theme by default, and lets you customize every theme value or start from presets like mint, midnight, and sunrise. Keybindings are configurable too — remap formatting shortcuts, navigation, and list operations to match your users' expectations.
20
+
21
+ - **Comments and presence for review workflows** — Anchor comments to any range of text, with full threading (replies, resolution, deletion) and self-repairing quote-based matching after edits. External user and AI agent presence can be projected into the document as live cursors and viewport indicators without becoming document content.
22
+
23
+ - **Fast and lightweight** — Canvas-based rendering optimized for hot-path performance even on large documents. A custom markdown parser, editor engine, and layout/rendering system all ship in a bundle <70 KB gzipped.
24
+
25
+ ## Getting Started
26
+
27
+ 1. Install the package: `npm install documint` (or `bun add documint`)
28
+ 2. Import the `Documint` component from the package
29
+ 3. Pass your markdown content to it and listen for changes
30
+
31
+ ```tsx
32
+ import { useState } from "react";
33
+ import { Documint } from "documint";
34
+
35
+ const initialMarkdown = `# Hello Documint
36
+
37
+ This editor takes markdown in and gives markdown back out.
38
+ `;
39
+
40
+ export function App() {
41
+ const [content, setContent] = useState(initialMarkdown);
42
+
43
+ return <Documint content={content} onContentChange={setContent} />;
44
+ }
45
+ ```
46
+
47
+ You can also start from one of the built-in themes and tweak just the values you care about.
48
+
49
+ ```tsx
50
+ import { useState } from "react";
51
+ import { Documint, lightTheme } from "documint";
52
+
53
+ const customTheme = {
54
+ ...lightTheme,
55
+ background: "#fff7ed",
56
+ headingText: "#7c2d12",
57
+ linkText: "#c2410c",
58
+ };
59
+
60
+ export function App() {
61
+ const [content, setContent] = useState("# Themed Documint");
62
+
63
+ return <Documint content={content} onContentChange={setContent} theme={customTheme} />;
64
+ }
65
+ ```
@@ -0,0 +1,222 @@
1
+ export type CommentThread = {
2
+ quote: string;
3
+ comments: Comment$1[];
4
+ anchor: Anchor;
5
+ resolvedAt?: string;
6
+ };
7
+ type Comment$1 = {
8
+ body: string;
9
+ updatedAt: string;
10
+ };
11
+ type Document$1 = {
12
+ blocks: Block[];
13
+ comments: CommentThread[];
14
+ };
15
+ export type Block = ParagraphBlock | HeadingBlock | ListBlock | ListItemBlock | BlockquoteBlock | TableBlock | DividerBlock | CodeBlock | DirectiveBlock | RawBlock;
16
+ export type Inline = Text$1 | Link | Image$1 | Code | LineBreak | Raw;
17
+ type DocumentNode<K extends string, P = {}> = {
18
+ id: string;
19
+ type: K;
20
+ } & P;
21
+ type BlockNode<K extends string, P = {}> = DocumentNode<K, {
22
+ plainText: string;
23
+ } & P>;
24
+ type ParagraphBlock = BlockNode<"paragraph", {
25
+ children: Inline[];
26
+ }>;
27
+ type HeadingBlock = BlockNode<"heading", {
28
+ children: Inline[];
29
+ depth: 1 | 2 | 3 | 4 | 5 | 6;
30
+ }>;
31
+ type ListBlock = BlockNode<"list", {
32
+ items: ListItemBlock[];
33
+ ordered: boolean;
34
+ spread: boolean;
35
+ start: number | null;
36
+ }>;
37
+ type ListItemBlock = BlockNode<"listItem", {
38
+ checked: boolean | null;
39
+ children: Block[];
40
+ spread: boolean;
41
+ }>;
42
+ type BlockquoteBlock = BlockNode<"blockquote", {
43
+ children: Block[];
44
+ }>;
45
+ type TableBlock = BlockNode<"table", {
46
+ align: Array<"center" | "left" | "right" | null>;
47
+ rows: TableRow[];
48
+ }>;
49
+ type TableRow = {
50
+ cells: TableCell[];
51
+ id: string;
52
+ };
53
+ type TableCell = {
54
+ children: Inline[];
55
+ id: string;
56
+ plainText: string;
57
+ };
58
+ type DividerBlock = BlockNode<"thematicBreak">;
59
+ type CodeBlock = BlockNode<"code", {
60
+ language: string | null;
61
+ meta: string | null;
62
+ source: string;
63
+ }>;
64
+ export type DirectiveBlock = BlockNode<"directive", {
65
+ attributes: string;
66
+ body: string;
67
+ name: string;
68
+ }>;
69
+ export type RawBlock = BlockNode<"unsupported", {
70
+ originalType: string;
71
+ source: string;
72
+ }>;
73
+ export type Mark = "bold" | "italic" | "strikethrough" | "underline";
74
+ type Text$1 = DocumentNode<"text", {
75
+ marks: Mark[];
76
+ text: string;
77
+ }>;
78
+ export type Link = DocumentNode<"link", {
79
+ children: Inline[];
80
+ title: string | null;
81
+ url: string;
82
+ }>;
83
+ type Image$1 = DocumentNode<"image", {
84
+ alt: string | null;
85
+ title: string | null;
86
+ url: string;
87
+ width: number | null;
88
+ }>;
89
+ type LineBreak = DocumentNode<"break">;
90
+ type Code = DocumentNode<"inlineCode", {
91
+ code: string;
92
+ }>;
93
+ export type Raw = DocumentNode<"unsupported", {
94
+ originalType: string;
95
+ source: string;
96
+ }>;
97
+ declare const ANCHOR_KINDS: readonly [
98
+ "text",
99
+ "code",
100
+ "tableCell"
101
+ ];
102
+ type AnchorKind = (typeof ANCHOR_KINDS)[number];
103
+ export type Anchor = {
104
+ kind?: AnchorKind;
105
+ prefix?: string;
106
+ suffix?: string;
107
+ };
108
+ export type Presence = {
109
+ color?: string;
110
+ cursor?: Anchor;
111
+ imageUrl?: string;
112
+ name: string;
113
+ };
114
+ /**
115
+ * Canvas render themes for the editor surface. These tokens are intentionally
116
+ * semantic so paint code can stay focused on structure rather than color
117
+ * decisions.
118
+ */
119
+ export type EditorTheme = {
120
+ activeBlockBackground: string;
121
+ activeBlockFlash: string;
122
+ background: string;
123
+ blockquoteRule: string;
124
+ blockquoteRuleActive: string;
125
+ blockquoteText: string;
126
+ caret: string;
127
+ checkboxCheckmark: string;
128
+ checkboxCheckedFill: string;
129
+ checkboxCheckedStroke: string;
130
+ checkboxUncheckedFill: string;
131
+ checkboxUncheckedStroke: string;
132
+ codeBackground: string;
133
+ codeText: string;
134
+ commentHighlight: string;
135
+ commentHighlightActive: string;
136
+ commentHighlightResolved: string;
137
+ commentHighlightResolvedActive: string;
138
+ headingRule: string;
139
+ headingText: string;
140
+ imageLoadingOverlay: string;
141
+ imagePlaceholderIcon: string;
142
+ imagePlaceholderText: string;
143
+ imageSurfaceBackground: string;
144
+ imageSurfaceBorder: string;
145
+ inlineCodeBackground: string;
146
+ inlineCodeText: string;
147
+ insertHighlightText: string;
148
+ leafAccent: string;
149
+ leafBackground: string;
150
+ leafBorder: string;
151
+ leafButtonBackground: string;
152
+ leafButtonBorder: string;
153
+ leafButtonText: string;
154
+ leafResolvedBackground: string;
155
+ leafResolvedBorder: string;
156
+ leafSecondaryText: string;
157
+ leafShadow?: string;
158
+ leafText: string;
159
+ linkText: string;
160
+ listMarkerText: string;
161
+ paddingX: number;
162
+ paddingY: number;
163
+ paragraphText: string;
164
+ selectionBackground: string;
165
+ selectionHandleBackground: string;
166
+ selectionHandleBorder: string;
167
+ tableBodyBackground: string;
168
+ tableBorder: string;
169
+ tableHeaderBackground: string;
170
+ };
171
+ type EditorCommand = "dedent" | "deleteBackward" | "indent" | "insertLineBreak" | "moveListItemDown" | "moveListItemUp" | "moveToLineEnd" | "moveToLineStart" | "redo" | "toggleBold" | "toggleInlineCode" | "toggleItalic" | "toggleStrikethrough" | "toggleUnderline" | "undo";
172
+ export type EditorKeybinding = {
173
+ altKey?: boolean;
174
+ command: EditorCommand;
175
+ key: string;
176
+ modKey?: boolean;
177
+ shiftKey?: boolean | "any";
178
+ };
179
+ export declare const defaultKeybindings: EditorKeybinding[];
180
+ export type DocumintState = {
181
+ activeBlockType: string | null;
182
+ activeCommentThreadIndex: number | null;
183
+ activeSpanKind: string | null;
184
+ canonicalContent: string;
185
+ characterCount: number;
186
+ commentThreadCount: number;
187
+ docChangeCount: number;
188
+ lastTransactionMs: number;
189
+ layoutWidth: number;
190
+ lineCount: number;
191
+ resolvedCommentCount: number;
192
+ selectionFrom: number;
193
+ selectionTo: number;
194
+ transactionCount: number;
195
+ };
196
+ export type DocumintTheme = EditorTheme | {
197
+ dark: EditorTheme;
198
+ light: EditorTheme;
199
+ };
200
+ export type DocumintProps = {
201
+ className?: string;
202
+ content: string;
203
+ keybindings?: EditorKeybinding[];
204
+ onContentChange?: (content: string, document: Document$1) => void;
205
+ onStateChange?: (state: DocumintState) => void;
206
+ presence?: Presence[];
207
+ theme?: DocumintTheme;
208
+ };
209
+ export declare function Documint({ className, content, keybindings, onContentChange, onStateChange, presence, theme, }: DocumintProps): import("react/jsx-runtime").JSX.Element;
210
+ export declare const lightTheme: EditorTheme;
211
+ export declare const darkTheme: EditorTheme;
212
+ export declare const mintTheme: EditorTheme;
213
+ export declare const midnightTheme: EditorTheme;
214
+
215
+ export {
216
+ Comment$1 as Comment,
217
+ Document$1 as Document,
218
+ Image$1 as Image,
219
+ Text$1 as Text,
220
+ };
221
+
222
+ export {};