@crashbytes/contentful-richtext-editor 1.0.11 → 2.0.5

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 (2) hide show
  1. package/README.md +333 -121
  2. package/package.json +4 -1
package/README.md CHANGED
@@ -1,179 +1,391 @@
1
- # Release v2.0.0 - Major Feature Update 🎉
1
+ # Contentful Rich Text Editor
2
2
 
3
- ## 🚀 What's New
3
+ A modern, Tiptap-based rich text editor that's fully compatible with Contentful's rich text format. Provides the same editing experience as Contentful's native editor while maintaining perfect compatibility with Contentful's document structure.
4
4
 
5
- This major release introduces **automatic configuration** from Contentful field settings, significantly enhancing the developer experience and ensuring your editor UI always matches your Contentful configuration.
5
+ ## Features
6
6
 
7
- ### Major New Features
7
+ - **Full Contentful Compatibility** - Seamless conversion between Contentful and Tiptap formats
8
+ - ✅ **Automatic Configuration** - Reads Contentful field settings to auto-configure the editor *(NEW in v2.0)*
9
+ - ✅ **Modern UI** - Clean, intuitive interface matching Contentful's design
10
+ - ✅ **TypeScript Support** - Complete type safety with Contentful's rich text types
11
+ - ✅ **Extensible** - Built on Tiptap v2 for easy customization
12
+ - ✅ **Lightweight** - Tree-shakeable, only import what you need
13
+ - ✅ **Responsive** - Works on desktop and mobile devices
14
+ - ✅ **Keyboard Shortcuts** - Built-in shortcuts for common actions *(NEW in v2.0)*
8
15
 
9
- - **🔄 Automatic Contentful Configuration**: The editor now reads your Contentful field validation settings and automatically enables/disables toolbar features
10
- - **📝 Inline Entry Support**: Added support for inline embedded entries (as configured in Contentful)
11
- - **⌨️ Keyboard Shortcuts**: Built-in shortcuts for common actions (`Cmd/Ctrl + Shift + E` for entries, `Cmd/Ctrl + Shift + A` for assets, etc.)
12
- - **🔍 Enhanced TypeScript Support**: Comprehensive type definitions and better developer experience
13
- - **📊 Content Analysis Utilities**: New utilities for word counting, plain text extraction, and content validation
16
+ ### Supported Features
14
17
 
15
- ### 🔧 Enhanced Features
18
+ - **Text Formatting**: Bold, italic, underline
19
+ - **Headings**: H1 through H6
20
+ - **Lists**: Ordered and unordered lists
21
+ - **Links**: Hyperlinks with URL validation
22
+ - **Tables**: Full table support with headers
23
+ - **Quotes**: Blockquotes
24
+ - **Embedded Content**: Callbacks for Contentful entries and assets
25
+ - **Inline Entries**: Support for inline embedded entries *(NEW in v2.0)*
26
+ - **Undo/Redo**: Full history support
16
27
 
17
- - **Smart Toolbar**: Toolbar buttons now appear/disappear based on your Contentful field configuration
18
- - **Better Error Handling**: Improved error messages and validation
19
- - **Performance Optimizations**: Faster rendering and better memory usage
20
- - **Accessibility Improvements**: Enhanced ARIA support and keyboard navigation
28
+ ## 📦 Installation
21
29
 
22
- ### 🎨 Developer Experience
30
+ ```bash
31
+ npm install @crashbytes/contentful-richtext-editor
32
+ ```
23
33
 
24
- - **Configuration Parser**: New utility to parse Contentful field settings
25
- - **Mock Configuration**: Easy testing with `createMockFieldConfig()`
26
- - **Backward Compatibility**: Existing manual configuration still works
27
- - **Comprehensive Documentation**: Updated with examples and API reference
34
+ ## 🚀 Quick Start
28
35
 
29
- ## 🛠️ Installation
36
+ ### Basic Usage
30
37
 
31
- ```bash
32
- npm install @crashbytes/contentful-richtext-editor@2.0.0
38
+ ```tsx
39
+ import React, { useState } from 'react';
40
+ import { ContentfulRichTextEditor } from '@crashbytes/contentful-richtext-editor';
41
+ import '@crashbytes/contentful-richtext-editor/dist/index.css';
42
+ import { Document } from '@contentful/rich-text-types';
43
+
44
+ function App() {
45
+ const [content, setContent] = useState<Document>();
46
+
47
+ const handleChange = (document: Document) => {
48
+ setContent(document);
49
+ console.log('Contentful document:', document);
50
+ };
51
+
52
+ return (
53
+ <div>
54
+ <h1>My Rich Text Editor</h1>
55
+ <ContentfulRichTextEditor
56
+ placeholder="Start writing your content..."
57
+ onChange={handleChange}
58
+ initialValue={content}
59
+ />
60
+ </div>
61
+ );
62
+ }
63
+
64
+ export default App;
65
+ ```
66
+
67
+ ### Automatic Configuration (NEW in v2.0)
68
+
69
+ The editor can automatically configure itself based on your Contentful field settings:
70
+
71
+ ```tsx
72
+ import {
73
+ ContentfulRichTextEditor,
74
+ fetchContentfulFieldConfig
75
+ } from '@crashbytes/contentful-richtext-editor';
76
+ import '@crashbytes/contentful-richtext-editor/dist/index.css';
77
+
78
+ function AutoConfiguredEditor() {
79
+ const [fieldConfig, setFieldConfig] = useState();
80
+
81
+ useEffect(() => {
82
+ // Fetch configuration from Contentful Management API
83
+ fetchContentfulFieldConfig(
84
+ 'your-space-id',
85
+ 'your-content-type-id',
86
+ 'your-field-id',
87
+ 'your-management-token'
88
+ ).then(setFieldConfig);
89
+ }, []);
90
+
91
+ return (
92
+ <ContentfulRichTextEditor
93
+ fieldConfiguration={fieldConfig}
94
+ placeholder="Auto-configured based on Contentful settings!"
95
+ onChange={handleChange}
96
+ />
97
+ );
98
+ }
99
+ ```
100
+
101
+ ### Advanced Usage with Embeds
102
+
103
+ ```tsx
104
+ import { ContentfulRichTextEditor } from '@crashbytes/contentful-richtext-editor';
105
+ import '@crashbytes/contentful-richtext-editor/dist/index.css';
106
+
107
+ function ContentfulEditor() {
108
+ const handleEmbedEntry = async () => {
109
+ // Your logic to select a Contentful entry
110
+ const entry = await openEntrySelector();
111
+ return entry;
112
+ };
113
+
114
+ const handleEmbedAsset = async () => {
115
+ // Your logic to select a Contentful asset
116
+ const asset = await openAssetSelector();
117
+ return asset;
118
+ };
119
+
120
+ const handleEmbedInlineEntry = async () => {
121
+ // NEW v2.0 - Your logic to select an inline entry
122
+ const entry = await openInlineEntrySelector();
123
+ return entry;
124
+ };
125
+
126
+ return (
127
+ <ContentfulRichTextEditor
128
+ placeholder="Write your travel tip..."
129
+ onChange={(doc) => saveToContentful(doc)}
130
+ onEmbedEntry={handleEmbedEntry}
131
+ onEmbedAsset={handleEmbedAsset}
132
+ onEmbedInlineEntry={handleEmbedInlineEntry}
133
+ theme="contentful"
134
+ />
135
+ );
136
+ }
33
137
  ```
34
138
 
35
- ## 🔄 Migration from v1.x
139
+ ### Minimal Configuration
36
140
 
37
- ### Automatic Configuration (Recommended)
38
141
  ```tsx
39
- // Before (v1.x)
40
142
  <ContentfulRichTextEditor
41
- availableHeadings={[1, 2, 3]}
42
- availableMarks={['bold', 'italic']}
43
- disabledFeatures={['table']}
143
+ placeholder="Simple editor..."
144
+ disabledFeatures={['table', 'embed', 'quote']}
145
+ theme="minimal"
146
+ readonly={false}
147
+ showBorder={false}
148
+ onChange={handleChange}
44
149
  />
150
+ ```
151
+
152
+ ### With Initial Content
153
+
154
+ ```tsx
155
+ import { createEmptyDocument } from '@crashbytes/contentful-richtext-editor';
156
+
157
+ const initialContent = {
158
+ nodeType: 'document',
159
+ data: {},
160
+ content: [
161
+ {
162
+ nodeType: 'paragraph',
163
+ data: {},
164
+ content: [
165
+ {
166
+ nodeType: 'text',
167
+ value: 'Hello world!',
168
+ marks: [{ type: 'bold' }],
169
+ data: {}
170
+ }
171
+ ]
172
+ }
173
+ ]
174
+ };
45
175
 
46
- // After (v2.x) - Automatically configured!
47
176
  <ContentfulRichTextEditor
48
- fieldConfiguration={contentfulFieldConfig}
49
- onEmbedInlineEntry={handleInlineEntry} // New!
177
+ initialValue={initialContent}
178
+ onChange={handleChange}
50
179
  />
51
180
  ```
52
181
 
53
- ### New Props Available
182
+ ## 📋 API Reference
183
+
184
+ ### ContentfulRichTextEditor Props
185
+
186
+ | Prop | Type | Default | Description |
187
+ |------|------|---------|-------------|
188
+ | `availableHeadings` | `Array<1\|2\|3\|4\|5\|6>` | `[1,2,3,4,5,6]` | Available heading levels (fallback when no fieldConfiguration) |
189
+ | `availableMarks` | `Array<'bold'\|'italic'\|'underline'>` | `['bold','italic','underline']` | Available text formatting marks (fallback when no fieldConfiguration) |
190
+ | `className` | `string` | `''` | Additional CSS classes |
191
+ | `disabledFeatures` | `Array<string>` | `[]` | Features to disable |
192
+ | `fieldConfiguration` | `ContentfulFieldConfiguration` | `undefined` | **NEW v2.0** - Contentful field validation config (takes precedence over manual settings) |
193
+ | `initialValue` | `Document` | `undefined` | Initial Contentful rich text document |
194
+ | `onChange` | `(document: Document) => void` | `undefined` | Callback when content changes |
195
+ | `onEmbedAsset` | `() => Promise<any> \| void` | `undefined` | Callback for embedding Contentful assets |
196
+ | `onEmbedEntry` | `() => Promise<any> \| void` | `undefined` | Callback for embedding Contentful entries |
197
+ | `onEmbedInlineEntry` | `() => Promise<any> \| void` | `undefined` | **NEW v2.0** - Callback for embedding inline entries |
198
+ | `placeholder` | `string` | `'Start writing...'` | Placeholder text |
199
+ | `readonly` | `boolean` | `false` | Whether editor is read-only |
200
+ | `showBorder` | `boolean` | `true` | Whether to show border around the editor |
201
+ | `theme` | `'default' \| 'minimal' \| 'contentful'` | `'contentful'` | Visual theme |
202
+
203
+ ### Disabled Features
204
+
205
+ You can disable specific features by passing them in the `disabledFeatures` array:
206
+
207
+ - `'bold'` - Bold text formatting
208
+ - `'italic'` - Italic text formatting
209
+ - `'underline'` - Underline text formatting
210
+ - `'link'` - Hyperlinks
211
+ - `'lists'` - Ordered and unordered lists
212
+ - `'headings'` - All heading levels
213
+ - `'quote'` - Blockquotes
214
+ - `'table'` - Tables
215
+ - `'embed'` - Embedded content
216
+
217
+ ### Configuration Types (NEW v2.0)
218
+
54
219
  ```tsx
55
- interface ContentfulRichTextEditorProps {
56
- // New in v2.0
57
- fieldConfiguration?: ContentfulFieldConfiguration;
58
- onEmbedInlineEntry?: () => Promise<any> | void;
59
-
60
- // Existing props still work (backward compatible)
61
- availableHeadings?: Array<1 | 2 | 3 | 4 | 5 | 6>;
62
- availableMarks?: Array<'bold' | 'italic' | 'underline'>;
63
- disabledFeatures?: Array<string>;
220
+ interface ContentfulFieldConfiguration {
221
+ validations?: Array<{
222
+ enabledMarks?: string[]; // ['bold', 'italic', 'underline', 'code']
223
+ enabledNodeTypes?: string[]; // ['paragraph', 'heading-1', 'unordered-list', ...]
224
+ }>;
225
+ settings?: {
226
+ helpText?: string;
227
+ };
64
228
  }
65
229
  ```
66
230
 
67
- ### Fetching Configuration from Contentful
231
+ ## 🛠️ Utility Functions
232
+
68
233
  ```tsx
69
- import { fetchContentfulFieldConfig } from '@crashbytes/contentful-richtext-editor';
234
+ import {
235
+ contentfulToTiptap,
236
+ tiptapToContentful,
237
+ validateContentfulDocument,
238
+ createEmptyDocument,
239
+ extractPlainText, // NEW v2.0
240
+ countWords, // NEW v2.0
241
+ findEmbeddedContent, // NEW v2.0
242
+ sanitizeContentfulDocument // NEW v2.0
243
+ } from '@crashbytes/contentful-richtext-editor';
244
+
245
+ // Convert between formats
246
+ const tiptapJson = contentfulToTiptap(contentfulDocument);
247
+ const contentfulDoc = tiptapToContentful(tiptapJson);
248
+
249
+ // Validation
250
+ const isValid = validateContentfulDocument(someDocument);
70
251
 
71
- const fieldConfig = await fetchContentfulFieldConfig(
72
- 'space-id',
73
- 'content-type-id',
74
- 'field-id',
75
- 'management-token'
252
+ // Create empty document
253
+ const emptyDoc = createEmptyDocument();
254
+
255
+ // NEW v2.0 - Content analysis
256
+ const plainText = extractPlainText(contentfulDocument);
257
+ const wordCount = countWords(contentfulDocument);
258
+ const embedded = findEmbeddedContent(contentfulDocument);
259
+
260
+ // NEW v2.0 - Sanitize content
261
+ const sanitized = sanitizeContentfulDocument(
262
+ document,
263
+ ['paragraph', 'heading-1', 'unordered-list'], // allowed nodes
264
+ ['bold', 'italic'] // allowed marks
76
265
  );
77
266
  ```
78
267
 
79
- ## 📋 New Utilities
268
+ ## ⌨️ Keyboard Shortcuts (NEW v2.0)
80
269
 
81
- ### Content Analysis
82
- ```tsx
83
- import {
84
- extractPlainText,
85
- countWords,
86
- findEmbeddedContent,
87
- sanitizeContentfulDocument
88
- } from '@crashbytes/contentful-richtext-editor';
270
+ - `Cmd/Ctrl + B` - Bold
271
+ - `Cmd/Ctrl + I` - Italic
272
+ - `Cmd/Ctrl + U` - Underline
273
+ - `Cmd/Ctrl + K` - Add/edit link
274
+ - `Cmd/Ctrl + Shift + E` - Embed entry
275
+ - `Cmd/Ctrl + Shift + A` - Embed asset
276
+ - `Cmd/Ctrl + Shift + I` - Embed inline entry
277
+ - `Cmd/Ctrl + Z` - Undo
278
+ - `Cmd/Ctrl + Y` / `Cmd/Ctrl + Shift + Z` - Redo
89
279
 
90
- const plainText = extractPlainText(document);
91
- const wordCount = countWords(document);
92
- const embedded = findEmbeddedContent(document);
93
- ```
280
+ ## 🎨 Styling
281
+
282
+ The editor comes with default styles that match Contentful's design. Import the CSS:
94
283
 
95
- ### Configuration Management
96
284
  ```tsx
97
- import {
98
- parseContentfulFieldConfig,
99
- createMockFieldConfig
100
- } from '@crashbytes/contentful-richtext-editor';
285
+ import '@crashbytes/contentful-richtext-editor/dist/index.css';
286
+ ```
287
+
288
+ You can override the default styles by targeting the CSS classes:
289
+
290
+ ```css
291
+ .contentful-editor {
292
+ border: 2px solid #your-color;
293
+ }
101
294
 
102
- // Parse Contentful config
103
- const parsed = parseContentfulFieldConfig(fieldConfig);
295
+ .contentful-toolbar {
296
+ background: #your-background;
297
+ }
298
+
299
+ .contentful-editor-content {
300
+ font-family: 'Your Font', sans-serif;
301
+ }
104
302
 
105
- // Create mock for testing
106
- const mockConfig = createMockFieldConfig({
107
- enabledMarks: ['bold', 'italic'],
108
- enabledNodeTypes: ['paragraph', 'heading-1', 'unordered-list']
109
- });
303
+ /* NEW v2.0 - Inline entries */
304
+ .contentful-inline-embedded-entry {
305
+ background: #e8f4fd;
306
+ padding: 2px 4px;
307
+ border-radius: 3px;
308
+ font-weight: 600;
309
+ }
110
310
  ```
111
311
 
112
- ## ⌨️ New Keyboard Shortcuts
312
+ ### Themes
113
313
 
114
- - `Cmd/Ctrl + Shift + E` - Embed entry
115
- - `Cmd/Ctrl + Shift + A` - Embed asset
116
- - `Cmd/Ctrl + Shift + I` - Embed inline entry
117
- - `Cmd/Ctrl + K` - Add/edit link
118
- - Standard formatting shortcuts (Bold, Italic, Underline)
314
+ **`contentful`** (default)
315
+ Matches Contentful's native editor appearance.
119
316
 
120
- ## 🐛 Bug Fixes
317
+ **`minimal`**
318
+ Clean, minimal design with reduced visual elements.
121
319
 
122
- - Fixed TypeScript compilation warnings
123
- - Improved link handling in complex nested structures
124
- - Fixed table rendering issues
125
- - Better handling of embedded content transformation
126
- - Resolved build process issues
320
+ **`default`**
321
+ Standard rich text editor appearance with serif fonts.
127
322
 
128
- ## 🔧 Technical Improvements
323
+ ## ⚛️ Next.js Integration
129
324
 
130
- - **Build System**: Improved Rollup configuration
131
- - **Type Safety**: Better TypeScript definitions throughout
132
- - **Performance**: Optimized re-renders and memory usage
133
- - **Code Quality**: Enhanced error boundaries and validation
325
+ ```tsx
326
+ // pages/editor.tsx or app/editor/page.tsx
327
+ import dynamic from 'next/dynamic';
134
328
 
135
- ## 📚 Documentation
329
+ const ContentfulEditor = dynamic(
330
+ () => import('@crashbytes/contentful-richtext-editor').then(mod => mod.ContentfulRichTextEditor),
331
+ { ssr: false }
332
+ );
136
333
 
137
- - **Complete API Reference**: Full documentation of all props and methods
138
- - **Usage Examples**: 5 different implementation examples
139
- - **Migration Guide**: Step-by-step upgrade instructions
140
- - **TypeScript Support**: Full type definitions and examples
334
+ export default function EditorPage() {
335
+ return (
336
+ <div>
337
+ <ContentfulEditor
338
+ placeholder="Write something amazing..."
339
+ onChange={(doc) => console.log(doc)}
340
+ />
341
+ </div>
342
+ );
343
+ }
344
+ ```
141
345
 
142
- ## 🎯 What's Next
346
+ ## 🔷 TypeScript Support
143
347
 
144
- We're already working on v2.1 with:
145
- - Real-time collaboration support
146
- - Advanced table editing features
147
- - Plugin system for custom extensions
148
- - More keyboard shortcuts and accessibility improvements
348
+ This package is written in TypeScript and includes full type definitions. All Contentful rich text types are re-exported for convenience:
149
349
 
150
- ## 🤝 Contributing
350
+ ```tsx
351
+ import type {
352
+ Document,
353
+ Block,
354
+ Inline,
355
+ Text,
356
+ ContentfulRichTextEditorProps,
357
+ ContentfulFieldConfiguration, // NEW v2.0
358
+ ParsedEditorConfig // NEW v2.0
359
+ } from '@crashbytes/contentful-richtext-editor';
360
+ ```
151
361
 
152
- We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
362
+ ## 🌐 Browser Support
153
363
 
154
- ## 📖 Full Documentation
364
+ - Chrome 80+
365
+ - Firefox 78+
366
+ - Safari 13+
367
+ - Edge 80+
155
368
 
156
- - [README](README.md) - Complete setup and usage guide
157
- - [API Reference](docs/API.md) - Detailed prop and method documentation
158
- - [Examples](examples/) - Implementation examples
159
- - [Changelog](CHANGELOG.md) - Complete version history
369
+ ## 🤝 Contributing
160
370
 
161
- ## 🔗 Links
371
+ Contributions are welcome! Please feel free to submit a Pull Request.
162
372
 
163
- - **GitHub**: https://github.com/your-org/contentful-richtext-editor
164
- - **npm**: https://www.npmjs.com/package/@crashbytes/contentful-richtext-editor
165
- - **Issues**: https://github.com/your-org/contentful-richtext-editor/issues
166
- - **Discussions**: https://github.com/your-org/contentful-richtext-editor/discussions
373
+ 1. Fork the repository
374
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
375
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
376
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
377
+ 5. Open a Pull Request
167
378
 
168
- ## 💝 Acknowledgments
379
+ ## 📄 License
169
380
 
170
- Special thanks to:
171
- - The Contentful team for their excellent Rich Text API
172
- - The TipTap team for the amazing editor framework
173
- - All early adopters and contributors who provided feedback
381
+ MIT © [CrashBytes](https://github.com/CrashBytes)
174
382
 
175
- ---
383
+ ## 🔗 Related Packages
384
+
385
+ - [@contentful/rich-text-react-renderer](https://www.npmjs.com/package/@contentful/rich-text-react-renderer) - For rendering Contentful rich text
386
+ - [@contentful/rich-text-types](https://www.npmjs.com/package/@contentful/rich-text-types) - Contentful rich text type definitions
387
+ - [@tiptap/react](https://www.npmjs.com/package/@tiptap/react) - The underlying editor framework
176
388
 
177
- **Full Changelog**: https://github.com/your-org/contentful-richtext-editor/compare/v1.0.10...v2.0.0
389
+ ---
178
390
 
179
- **Happy editing! 🎉**
391
+ Made with ❤️ for the Contentful community
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crashbytes/contentful-richtext-editor",
3
- "version": "1.0.11",
3
+ "version": "2.0.5",
4
4
  "description": "A Tiptap-based rich text editor compatible with Contentful's rich text format",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -9,6 +9,9 @@
9
9
  "files": [
10
10
  "dist"
11
11
  ],
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
12
15
  "keywords": [
13
16
  "contentful",
14
17
  "tiptap",