nextext-editor 0.1.0 → 0.1.2

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,329 @@
1
+ # NextText Editor
2
+
3
+ > A modern, customizable rich text editor for React with shadcn/ui patterns, Tailwind CSS styling, and collaborative editing powered by Loro CRDT.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/nextext-editor)](https://www.npmjs.com/package/nextext-editor)
6
+
7
+ ## Preview
8
+
9
+ ![NextText Editor Screenshot](./assets/editor-screenshot.png)
10
+
11
+ ## Features
12
+
13
+ - 🎨 **Rich Formatting** - Bold, italic, underline, strikethrough, inline code, text color, and highlighting
14
+ - 📝 **Block Types** - Headings (H1-H6), paragraphs, bullet lists, numbered lists, blockquotes, code blocks, horizontal rules
15
+ - 🖼️ **Media Support** - Image upload with drag-and-drop (max 5MB, auto-styled)
16
+ - 📊 **Tables** - Insert and edit tables with styled cells
17
+ - 🔄 **Built-in Collaboration** - Loro CRDT for conflict-free real-time editing
18
+ - 🎨 **Customizable Design** - shadcn/ui-inspired design tokens for easy theming
19
+ - 📱 **Responsive** - Works seamlessly on desktop and mobile
20
+ - ⌨️ **Keyboard Shortcuts** - Familiar shortcuts (Ctrl/Cmd+B, I, U, Z, Y)
21
+ - 🔍 **Live Preview** - View your content in HTML, Text, or JSON format
22
+ - 📊 **Word & Character Count** - Real-time statistics display
23
+ - 🎯 **TypeScript** - Fully typed for better DX
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ npm install nextext-editor
29
+ # or
30
+ yarn add nextext-editor
31
+ # or
32
+ pnpm add nextext-editor
33
+ ```
34
+
35
+ ## Quick Start
36
+
37
+ ### Basic Usage
38
+
39
+ ```tsx
40
+ import { EditorBlock } from 'nextext-editor';
41
+ import 'nextext-editor/styles.css';
42
+
43
+ function App() {
44
+ return <EditorBlock placeholder="Start writing..." />;
45
+ }
46
+ ```
47
+
48
+ ### With Preview Panel
49
+
50
+ ```tsx
51
+ import { EditorBlock } from 'nextext-editor';
52
+ import 'nextext-editor/styles.css';
53
+
54
+ function App() {
55
+ return (
56
+ <EditorBlock
57
+ showPreview
58
+ placeholder="Start writing..."
59
+ />
60
+ );
61
+ }
62
+ ```
63
+
64
+ ### Controlled Mode with External State
65
+
66
+ ```tsx
67
+ import { useState } from 'react';
68
+ import { EditorBlock } from 'nextext-editor';
69
+ import 'nextext-editor/styles.css';
70
+
71
+ function App() {
72
+ const [content, setContent] = useState('<p>Initial content</p>');
73
+
74
+ return (
75
+ <EditorBlock
76
+ externalContent={content}
77
+ onContentChange={setContent}
78
+ showPreview
79
+ />
80
+ );
81
+ }
82
+ ```
83
+
84
+ ### Using Loro CRDT for Collaboration
85
+
86
+ ```tsx
87
+ import { useLoroEditor, EditorBlock } from 'nextext-editor';
88
+ import 'nextext-editor/styles.css';
89
+
90
+ function CollaborativeEditor() {
91
+ const { content, updateContent, loroDoc } = useLoroEditor();
92
+
93
+ // Share loroDoc with other clients for real-time sync
94
+
95
+ return (
96
+ <EditorBlock
97
+ externalContent={content}
98
+ onContentChange={updateContent}
99
+ />
100
+ );
101
+ }
102
+ ```
103
+
104
+ ### Using Editor Directly (Headless)
105
+
106
+ If you want to build your own toolbar and UI, use the low-level `Editor` component:
107
+
108
+ ```tsx
109
+ import { useState } from 'react';
110
+ import { Editor } from 'nextext-editor';
111
+ import 'nextext-editor/styles.css';
112
+
113
+ function CustomEditor() {
114
+ const [content, setContent] = useState('<p>Start typing...</p>');
115
+
116
+ return (
117
+ <div>
118
+ <div className="my-custom-toolbar">
119
+ <button onClick={() => document.execCommand('bold')}>Bold</button>
120
+ <button onClick={() => document.execCommand('italic')}>Italic</button>
121
+ </div>
122
+ <Editor
123
+ content={content}
124
+ onContentChange={setContent}
125
+ placeholder="Write something..."
126
+ />
127
+ </div>
128
+ );
129
+ }
130
+ ```
131
+
132
+ ## Tech Stack
133
+
134
+ - **React 18** - UI framework
135
+ - **TypeScript** - Type safety
136
+ - **Loro CRDT** - Conflict-free collaboration
137
+ - **Tailwind CSS v4** - Styling
138
+ - **Lucide React** - Icons
139
+ - **Vite** - Build tool
140
+
141
+ ## API Reference
142
+
143
+ ### Editor Props (Core ContentEditable Component)
144
+
145
+ | Prop | Type | Default | Description |
146
+ |------|------|---------|-------------|
147
+ | `content` | `string` | **required** | HTML content to display |
148
+ | `onContentChange` | `(html: string) => void` | **required** | Called when content changes |
149
+ | `placeholder` | `string` | `"Start typing..."` | Placeholder text when empty |
150
+ | `className` | `string` | - | Custom class for the editable area |
151
+ | `tokens` | `EditorTokens` | `editorTokens` | Custom design tokens |
152
+
153
+ ### EditorBlock Props (Complete Editor with Toolbar & Preview)
154
+
155
+ | Prop | Type | Default | Description |
156
+ |------|------|---------|-------------|
157
+ | `initialContent` | `string` | - | Initial HTML content |
158
+ | `showPreview` | `boolean` | `false` | Show live preview panel |
159
+ | `showToolbar` | `boolean` | `true` | Show formatting toolbar |
160
+ | `externalContent` | `string` | - | Controlled content (for controlled mode) |
161
+ | `onContentChange` | `(html: string) => void` | - | Content change callback |
162
+ | `className` | `string` | - | Custom container class |
163
+ | `placeholder` | `string` | `"Start typing..."` | Placeholder text |
164
+ | `tokens` | `EditorTokens` | `editorTokens` | Custom design tokens |
165
+
166
+ ### useLoroEditor Hook
167
+
168
+ Returns an object with:
169
+
170
+ ```tsx
171
+ {
172
+ content: string; // Current HTML content
173
+ format: TextFormat; // Current text format state
174
+ updateContent: (html: string) => void; // Update content
175
+ insertText: (text: string, position?: number) => void; // Insert text
176
+ deleteText: (start: number, length: number) => void; // Delete text
177
+ applyFormat: (start: number, end: number, format: TextFormat) => void; // Apply formatting
178
+ getSnapshot: () => Uint8Array; // Export Loro snapshot
179
+ loadSnapshot: (snapshot: Uint8Array) => void; // Import Loro snapshot
180
+ loroDoc: Loro | null; // Raw Loro document instance
181
+ }
182
+ ```
183
+
184
+ ### Design Tokens
185
+
186
+ Customize the editor's appearance by passing custom tokens:
187
+
188
+ ```tsx
189
+ import { EditorBlock, editorTokens } from 'nextext-editor';
190
+
191
+ const customTokens = {
192
+ ...editorTokens,
193
+ container: {
194
+ ...editorTokens.container,
195
+ base: 'w-full bg-slate-900 rounded-xl border border-slate-700',
196
+ },
197
+ editor: {
198
+ ...editorTokens.editor,
199
+ base: 'min-h-[500px] p-8 text-slate-100',
200
+ },
201
+ };
202
+
203
+ function App() {
204
+ return <EditorBlock tokens={customTokens} />;
205
+ }
206
+ ```
207
+
208
+ ## Toolbar Actions
209
+
210
+ The editor supports these formatting actions:
211
+
212
+ ### Text Formatting
213
+ - `bold` - Toggle bold text
214
+ - `italic` - Toggle italic text
215
+ - `underline` - Toggle underline
216
+ - `strikethrough` - Toggle strikethrough
217
+ - `code` - Toggle inline code
218
+ - `textColor` - Change text color
219
+ - `highlight` - Change background color
220
+ - `clearMarks` - Remove all formatting
221
+
222
+ ### Block Types
223
+ - `paragraph` - Normal paragraph
224
+ - `h1`, `h2`, `h3`, `h4`, `h5`, `h6` - Headings
225
+ - `bulletList` - Unordered list
226
+ - `numberedList` - Ordered list
227
+ - `codeBlock` - Code block
228
+ - `blockquote` - Blockquote
229
+ - `clearNodes` - Reset to paragraph
230
+
231
+ ### Content
232
+ - `image` - Upload image (max 5MB)
233
+ - `table` - Insert 3x3 table
234
+ - `horizontalRule` - Insert horizontal line
235
+ - `hardBreak` - Insert line break
236
+
237
+ ### History
238
+ - `undo` - Undo last change
239
+ - `redo` - Redo last change
240
+
241
+ ## Keyboard Shortcuts
242
+
243
+ - **Ctrl/Cmd + B** - Bold
244
+ - **Ctrl/Cmd + I** - Italic
245
+ - **Ctrl/Cmd + U** - Underline
246
+ - **Ctrl/Cmd + Z** - Undo
247
+ - **Ctrl/Cmd + Y** - Redo
248
+
249
+ ## Architecture
250
+
251
+ The editor follows a clean component hierarchy:
252
+
253
+ ```
254
+ Editor (Core - in components/)
255
+ └── Low-level contentEditable component
256
+ └── Handles HTML editing, cursor management, keyboard events
257
+
258
+ EditorBlock (Complete Editor - in block/)
259
+ ├── Uses Editor component
260
+ ├── Adds Toolbar
261
+ ├── Adds Preview panel
262
+ ├── Adds word/character count
263
+ └── Integrates with Loro CRDT via useLoroEditor hook
264
+ ```
265
+
266
+ **File Structure:**
267
+ ```
268
+ src/
269
+ ├── components/
270
+ │ ├── Editor.tsx ← Core contentEditable (low-level)
271
+ │ ├── Toolbar.tsx
272
+ │ ├── Preview.tsx
273
+ │ └── ...
274
+ ├── block/
275
+ │ └── EditorBlock.tsx ← Complete editor (high-level)
276
+ ├── hooks/
277
+ │ └── useLoroEditor.ts
278
+ └── index.ts
279
+ ```
280
+
281
+ ## Exported Components
282
+
283
+ ```tsx
284
+ import {
285
+ Editor, // Core contentEditable component (low-level)
286
+ EditorBlock, // Complete editor with toolbar & preview (high-level)
287
+ Toolbar, // Formatting toolbar component
288
+ Preview, // Preview panel component
289
+ ColorPicker, // Color picker dropdown
290
+ HeadingSelector, // Heading selector dropdown
291
+ } from 'nextext-editor';
292
+ ```
293
+
294
+ ## Exported Utilities
295
+
296
+ ```tsx
297
+ import {
298
+ useLoroEditor, // Loro CRDT hook
299
+ editorTokens, // Default design tokens
300
+ cn, // className utility (clsx + tailwind-merge)
301
+ } from 'nextext-editor';
302
+ ```
303
+
304
+ ## TypeScript Types
305
+
306
+ ```tsx
307
+ import type {
308
+ TextFormat, // Text formatting state
309
+ EditorState, // Editor state
310
+ ToolbarAction, // Toolbar action types
311
+ PreviewMode, // Preview mode ('html' | 'text' | 'json')
312
+ EditorTokens, // Design tokens type
313
+ EditorBlockProps, // EditorBlock props
314
+ } from 'nextext-editor';
315
+ ```
316
+
317
+ ## License
318
+
319
+ MIT © [NaveenChand](https://github.com/NaveenChand755)
320
+
321
+ ## Contributing
322
+
323
+ Contributions are welcome! Please check out the [GitHub repository](https://github.com/NaveenChand755/hyper-text).
324
+
325
+ ## Support
326
+
327
+ - 🐛 [Report Issues](https://github.com/NaveenChand755/hyper-text/issues)
328
+ - 💬 [Discussions](https://github.com/NaveenChand755/hyper-text/discussions)
329
+ - 📖 [Documentation](https://github.com/NaveenChand755/hyper-text#readme)
@@ -0,0 +1,38 @@
1
+ import { default as React } from 'react';
2
+ import { editorTokens } from '../lib/tokens';
3
+ export interface EditorBlockProps {
4
+ /**
5
+ * Initial content (HTML string)
6
+ */
7
+ initialContent?: string;
8
+ /**
9
+ * Show preview panel
10
+ */
11
+ showPreview?: boolean;
12
+ /**
13
+ * Show toolbar
14
+ */
15
+ showToolbar?: boolean;
16
+ /**
17
+ * External content control (for controlled component)
18
+ */
19
+ externalContent?: string;
20
+ /**
21
+ * Content change handler (for controlled component)
22
+ */
23
+ onContentChange?: (content: string) => void;
24
+ /**
25
+ * Custom class name for container
26
+ */
27
+ className?: string;
28
+ /**
29
+ * Placeholder text
30
+ */
31
+ placeholder?: string;
32
+ /**
33
+ * Custom design tokens
34
+ */
35
+ tokens?: typeof editorTokens;
36
+ }
37
+ export declare const EditorBlock: React.NamedExoticComponent<EditorBlockProps>;
38
+ export default EditorBlock;
@@ -1,38 +1,11 @@
1
1
  import { default as React } from 'react';
2
2
  import { editorTokens } from '../lib/tokens';
3
3
  export interface EditorProps {
4
- /**
5
- * Initial content (HTML string)
6
- */
7
- initialContent?: string;
8
- /**
9
- * Show preview panel
10
- */
11
- showPreview?: boolean;
12
- /**
13
- * Show toolbar
14
- */
15
- showToolbar?: boolean;
16
- /**
17
- * External content control (for controlled component)
18
- */
19
- externalContent?: string;
20
- /**
21
- * Content change handler (for controlled component)
22
- */
23
- onContentChange?: (content: string) => void;
24
- /**
25
- * Custom class name for container
26
- */
27
- className?: string;
28
- /**
29
- * Placeholder text
30
- */
4
+ content: string;
5
+ onContentChange: (content: string) => void;
31
6
  placeholder?: string;
32
- /**
33
- * Custom design tokens
34
- */
7
+ className?: string;
35
8
  tokens?: typeof editorTokens;
36
9
  }
37
- export declare const Editor: React.NamedExoticComponent<EditorProps>;
10
+ export declare const Editor: React.FC<EditorProps>;
38
11
  export default Editor;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { Editor } from './components/Editor';
2
- export { EditorBlock } from './components/block';
3
- export type { EditorBlockProps } from './components/block';
2
+ export type { EditorProps } from './components/Editor';
3
+ export { EditorBlock } from './block';
4
+ export type { EditorBlockProps } from './block';
4
5
  export { Toolbar } from './components/Toolbar';
5
6
  export { Preview } from './components/Preview';
6
7
  export { ColorPicker } from './components/ColorPicker';