@crashbytes/contentful-richtext-editor 1.0.9 → 1.0.11
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 +118 -472
- package/dist/index.css +1 -1
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +353 -241
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +353 -241
- package/dist/index.js.map +1 -1
- package/package.json +32 -9
- package/dist/components/ContentfulDocument.d.ts +0 -2
- package/dist/components/ContentfulEditor.d.ts +0 -34
- package/dist/components/ContentfulEditor.stories.d.ts +0 -18
- package/dist/components/ContentfulEmbedded.d.ts +0 -15
- package/dist/components/Toolbar.d.ts +0 -14
- package/dist/components/Toolbar.stories.d.ts +0 -10
- package/dist/index.d.ts +0 -8
- package/dist/testData/samples.d.ts +0 -11
- package/dist/utils/configParser.d.ts +0 -37
- package/dist/utils/contentfulTransform.d.ts +0 -48
- package/dist/utils/contentfulTransform.stories.d.ts +0 -6
- package/dist/utils/types.d.ts +0 -141
package/README.md
CHANGED
|
@@ -1,533 +1,179 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Release v2.0.0 - Major Feature Update 🎉
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 🚀 What's New
|
|
4
4
|
|
|
5
|
-
|
|
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.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- 📝 **Rich Text Support**: Full support for headings, lists, tables, quotes, and text formatting
|
|
9
|
-
- 🔗 **Hyperlinks**: Configurable link support with URL validation
|
|
10
|
-
- 📎 **Embeds**: Support for embedded entries, assets, and inline entries
|
|
11
|
-
- 🎨 **Themes**: Multiple built-in themes (contentful, minimal, default)
|
|
12
|
-
- ♿ **Accessibility**: Built with accessibility in mind
|
|
13
|
-
- 🔧 **Customizable**: Extensive configuration options and styling hooks
|
|
14
|
-
- 📱 **Responsive**: Works well on mobile and desktop
|
|
15
|
-
- ⌨️ **Keyboard Shortcuts**: Built-in shortcuts for common actions
|
|
16
|
-
- 🔍 **TypeScript**: Full TypeScript support with comprehensive type definitions
|
|
7
|
+
### ✨ Major New Features
|
|
17
8
|
|
|
18
|
-
|
|
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
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
npm install @your-org/contentful-rich-text-editor
|
|
22
|
-
# or
|
|
23
|
-
yarn add @your-org/contentful-rich-text-editor
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Dependencies
|
|
27
|
-
|
|
28
|
-
This component requires the following peer dependencies:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npm install react @tiptap/react @tiptap/starter-kit @contentful/rich-text-types
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Quick Start
|
|
35
|
-
|
|
36
|
-
### Basic Usage
|
|
37
|
-
|
|
38
|
-
```tsx
|
|
39
|
-
import React, { useState } from 'react';
|
|
40
|
-
import { ContentfulRichTextEditor } from '@your-org/contentful-rich-text-editor';
|
|
41
|
-
import { Document } from '@contentful/rich-text-types';
|
|
42
|
-
|
|
43
|
-
function MyEditor() {
|
|
44
|
-
const [content, setContent] = useState<Document>();
|
|
45
|
-
|
|
46
|
-
return (
|
|
47
|
-
<ContentfulRichTextEditor
|
|
48
|
-
initialValue={content}
|
|
49
|
-
onChange={setContent}
|
|
50
|
-
placeholder="Start writing..."
|
|
51
|
-
/>
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### With Contentful Configuration
|
|
57
|
-
|
|
58
|
-
```tsx
|
|
59
|
-
import React, { useEffect, useState } from 'react';
|
|
60
|
-
import {
|
|
61
|
-
ContentfulRichTextEditor,
|
|
62
|
-
fetchContentfulFieldConfig,
|
|
63
|
-
ContentfulFieldConfiguration
|
|
64
|
-
} from '@your-org/contentful-rich-text-editor';
|
|
65
|
-
|
|
66
|
-
function ContentfulEditor() {
|
|
67
|
-
const [fieldConfig, setFieldConfig] = useState<ContentfulFieldConfiguration>();
|
|
68
|
-
|
|
69
|
-
useEffect(() => {
|
|
70
|
-
// Fetch configuration from Contentful Management API
|
|
71
|
-
fetchContentfulFieldConfig(
|
|
72
|
-
'your-space-id',
|
|
73
|
-
'your-content-type-id',
|
|
74
|
-
'your-field-id',
|
|
75
|
-
'your-management-token'
|
|
76
|
-
).then(setFieldConfig);
|
|
77
|
-
}, []);
|
|
78
|
-
|
|
79
|
-
return (
|
|
80
|
-
<ContentfulRichTextEditor
|
|
81
|
-
fieldConfiguration={fieldConfig}
|
|
82
|
-
onChange={(doc) => console.log('Content changed:', doc)}
|
|
83
|
-
onEmbedEntry={handleEmbedEntry}
|
|
84
|
-
onEmbedAsset={handleEmbedAsset}
|
|
85
|
-
placeholder="Start writing..."
|
|
86
|
-
/>
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## API Reference
|
|
92
|
-
|
|
93
|
-
### ContentfulRichTextEditor Props
|
|
94
|
-
|
|
95
|
-
| Prop | Type | Default | Description |
|
|
96
|
-
|------|------|---------|-------------|
|
|
97
|
-
| `initialValue` | `Document` | `undefined` | Initial Contentful rich text document |
|
|
98
|
-
| `onChange` | `(document: Document) => void` | `undefined` | Callback when content changes |
|
|
99
|
-
| `onEmbedEntry` | `() => Promise<any>` | `undefined` | Callback for embedding entries |
|
|
100
|
-
| `onEmbedAsset` | `() => Promise<any>` | `undefined` | Callback for embedding assets |
|
|
101
|
-
| `onEmbedInlineEntry` | `() => Promise<any>` | `undefined` | Callback for embedding inline entries |
|
|
102
|
-
| `fieldConfiguration` | `ContentfulFieldConfiguration` | `undefined` | Contentful field validation config |
|
|
103
|
-
| `readonly` | `boolean` | `false` | Whether editor is read-only |
|
|
104
|
-
| `placeholder` | `string` | `'Start writing...'` | Placeholder text |
|
|
105
|
-
| `theme` | `'contentful' \| 'minimal' \| 'default'` | `'contentful'` | Editor theme |
|
|
106
|
-
| `className` | `string` | `''` | Additional CSS classes |
|
|
107
|
-
| `availableHeadings` | `Array<1\|2\|3\|4\|5\|6>` | `[1,2,3,4,5,6]` | Available heading levels (fallback) |
|
|
108
|
-
| `availableMarks` | `Array<'bold'\|'italic'\|'underline'>` | `['bold','italic','underline']` | Available text marks (fallback) |
|
|
109
|
-
| `disabledFeatures` | `Array<string>` | `[]` | Manually disabled features (fallback) |
|
|
110
|
-
|
|
111
|
-
### Configuration Types
|
|
15
|
+
### 🔧 Enhanced Features
|
|
112
16
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
enabledNodeTypes?: string[];
|
|
118
|
-
}>;
|
|
119
|
-
settings?: {
|
|
120
|
-
helpText?: string;
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### Supported Node Types
|
|
126
|
-
|
|
127
|
-
- `paragraph` - Regular paragraphs
|
|
128
|
-
- `heading-1` through `heading-6` - Headings
|
|
129
|
-
- `unordered-list`, `ordered-list` - Lists
|
|
130
|
-
- `blockquote` - Quotes
|
|
131
|
-
- `table` - Tables
|
|
132
|
-
- `hyperlink` - Links
|
|
133
|
-
- `embedded-entry-block` - Block-level entry embeds
|
|
134
|
-
- `embedded-asset-block` - Block-level asset embeds
|
|
135
|
-
- `embedded-entry-inline` - Inline entry embeds
|
|
136
|
-
- `hr` - Horizontal rules
|
|
137
|
-
|
|
138
|
-
### Supported Marks
|
|
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
|
|
139
21
|
|
|
140
|
-
|
|
141
|
-
- `italic` - Italic text
|
|
142
|
-
- `underline` - Underlined text
|
|
143
|
-
- `code` - Inline code
|
|
22
|
+
### 🎨 Developer Experience
|
|
144
23
|
|
|
145
|
-
|
|
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
|
|
146
28
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
```tsx
|
|
150
|
-
import { createMockFieldConfig } from '@your-org/contentful-rich-text-editor';
|
|
151
|
-
|
|
152
|
-
const mockConfig = createMockFieldConfig({
|
|
153
|
-
enabledMarks: ['bold', 'italic'],
|
|
154
|
-
enabledNodeTypes: [
|
|
155
|
-
'paragraph',
|
|
156
|
-
'heading-1',
|
|
157
|
-
'heading-2',
|
|
158
|
-
'unordered-list',
|
|
159
|
-
'hyperlink',
|
|
160
|
-
'embedded-entry-block'
|
|
161
|
-
]
|
|
162
|
-
});
|
|
29
|
+
## 🛠️ Installation
|
|
163
30
|
|
|
164
|
-
|
|
31
|
+
```bash
|
|
32
|
+
npm install @crashbytes/contentful-richtext-editor@2.0.0
|
|
165
33
|
```
|
|
166
34
|
|
|
167
|
-
|
|
35
|
+
## 🔄 Migration from v1.x
|
|
168
36
|
|
|
37
|
+
### Automatic Configuration (Recommended)
|
|
169
38
|
```tsx
|
|
39
|
+
// Before (v1.x)
|
|
170
40
|
<ContentfulRichTextEditor
|
|
171
41
|
availableHeadings={[1, 2, 3]}
|
|
172
42
|
availableMarks={['bold', 'italic']}
|
|
173
|
-
disabledFeatures={['table'
|
|
43
|
+
disabledFeatures={['table']}
|
|
174
44
|
/>
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
## Styling
|
|
178
|
-
|
|
179
|
-
The editor comes with built-in CSS classes that you can override:
|
|
180
|
-
|
|
181
|
-
```css
|
|
182
|
-
/* Main editor container */
|
|
183
|
-
.contentful-editor {
|
|
184
|
-
border: 1px solid #d3dce6;
|
|
185
|
-
border-radius: 6px;
|
|
186
|
-
}
|
|
187
45
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
/* Content area */
|
|
195
|
-
.contentful-editor-content {
|
|
196
|
-
padding: 16px;
|
|
197
|
-
min-height: 200px;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/* Embedded content */
|
|
201
|
-
.contentful-embedded-entry {
|
|
202
|
-
background: #f0f8ff;
|
|
203
|
-
border: 1px dashed #2e75d4;
|
|
204
|
-
padding: 8px;
|
|
205
|
-
border-radius: 4px;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/* Inline embedded content */
|
|
209
|
-
.contentful-inline-embedded-entry {
|
|
210
|
-
background: #e8f4fd;
|
|
211
|
-
padding: 2px 4px;
|
|
212
|
-
border-radius: 3px;
|
|
213
|
-
font-weight: 600;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/* Tables */
|
|
217
|
-
.contentful-table {
|
|
218
|
-
border-collapse: collapse;
|
|
219
|
-
width: 100%;
|
|
220
|
-
margin: 1em 0;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
.contentful-table-header {
|
|
224
|
-
background: #f7f9fa;
|
|
225
|
-
font-weight: 600;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/* Lists */
|
|
229
|
-
.contentful-bullet-list,
|
|
230
|
-
.contentful-ordered-list {
|
|
231
|
-
margin: 1em 0;
|
|
232
|
-
padding-left: 1.5em;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/* Quotes */
|
|
236
|
-
.contentful-blockquote {
|
|
237
|
-
border-left: 4px solid #2e75d4;
|
|
238
|
-
margin: 1em 0;
|
|
239
|
-
padding-left: 1em;
|
|
240
|
-
font-style: italic;
|
|
241
|
-
}
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
## Advanced Usage
|
|
245
|
-
|
|
246
|
-
### Custom Embed Handlers
|
|
247
|
-
|
|
248
|
-
```tsx
|
|
249
|
-
const handleEmbedEntry = async () => {
|
|
250
|
-
// Open your entry selector modal/component
|
|
251
|
-
const selectedEntry = await openEntrySelector();
|
|
252
|
-
return {
|
|
253
|
-
sys: { id: selectedEntry.id, type: 'Entry' },
|
|
254
|
-
fields: { title: selectedEntry.title }
|
|
255
|
-
};
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
const handleEmbedAsset = async () => {
|
|
259
|
-
const selectedAsset = await openAssetSelector();
|
|
260
|
-
return {
|
|
261
|
-
sys: { id: selectedAsset.id, type: 'Asset' },
|
|
262
|
-
fields: {
|
|
263
|
-
title: selectedAsset.title,
|
|
264
|
-
file: { url: selectedAsset.url }
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
const handleEmbedInlineEntry = async () => {
|
|
270
|
-
const selectedEntry = await openInlineEntrySelector();
|
|
271
|
-
return {
|
|
272
|
-
sys: { id: selectedEntry.id, type: 'Entry' },
|
|
273
|
-
fields: { name: selectedEntry.name }
|
|
274
|
-
};
|
|
275
|
-
};
|
|
46
|
+
// After (v2.x) - Automatically configured!
|
|
47
|
+
<ContentfulRichTextEditor
|
|
48
|
+
fieldConfiguration={contentfulFieldConfig}
|
|
49
|
+
onEmbedInlineEntry={handleInlineEntry} // New!
|
|
50
|
+
/>
|
|
276
51
|
```
|
|
277
52
|
|
|
278
|
-
###
|
|
279
|
-
|
|
280
|
-
- `Ctrl/Cmd + B` - Bold
|
|
281
|
-
- `Ctrl/Cmd + I` - Italic
|
|
282
|
-
- `Ctrl/Cmd + U` - Underline
|
|
283
|
-
- `Ctrl/Cmd + K` - Add link
|
|
284
|
-
- `Ctrl/Cmd + Shift + E` - Embed entry
|
|
285
|
-
- `Ctrl/Cmd + Shift + A` - Embed asset
|
|
286
|
-
- `Ctrl/Cmd + Shift + I` - Embed inline entry
|
|
287
|
-
- `Ctrl/Cmd + Z` - Undo
|
|
288
|
-
- `Ctrl/Cmd + Y` / `Ctrl/Cmd + Shift + Z` - Redo
|
|
289
|
-
|
|
290
|
-
### Content Validation and Analysis
|
|
291
|
-
|
|
53
|
+
### New Props Available
|
|
292
54
|
```tsx
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
findEmbeddedContent
|
|
298
|
-
} from '@your-org/contentful-rich-text-editor';
|
|
299
|
-
|
|
300
|
-
const handleChange = (document: Document) => {
|
|
301
|
-
// Validate document structure
|
|
302
|
-
if (validateContentfulDocument(document)) {
|
|
303
|
-
console.log('Document is valid');
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Extract plain text
|
|
307
|
-
const plainText = extractPlainText(document);
|
|
308
|
-
console.log('Plain text:', plainText);
|
|
309
|
-
|
|
310
|
-
// Count words
|
|
311
|
-
const wordCount = countWords(document);
|
|
312
|
-
console.log('Word count:', wordCount);
|
|
55
|
+
interface ContentfulRichTextEditorProps {
|
|
56
|
+
// New in v2.0
|
|
57
|
+
fieldConfiguration?: ContentfulFieldConfiguration;
|
|
58
|
+
onEmbedInlineEntry?: () => Promise<any> | void;
|
|
313
59
|
|
|
314
|
-
//
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
};
|
|
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>;
|
|
64
|
+
}
|
|
320
65
|
```
|
|
321
66
|
|
|
322
|
-
###
|
|
323
|
-
|
|
67
|
+
### Fetching Configuration from Contentful
|
|
324
68
|
```tsx
|
|
325
|
-
import {
|
|
69
|
+
import { fetchContentfulFieldConfig } from '@crashbytes/contentful-richtext-editor';
|
|
326
70
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
71
|
+
const fieldConfig = await fetchContentfulFieldConfig(
|
|
72
|
+
'space-id',
|
|
73
|
+
'content-type-id',
|
|
74
|
+
'field-id',
|
|
75
|
+
'management-token'
|
|
332
76
|
);
|
|
333
77
|
```
|
|
334
78
|
|
|
335
|
-
##
|
|
336
|
-
|
|
337
|
-
For API integration, set these environment variables:
|
|
338
|
-
|
|
339
|
-
```env
|
|
340
|
-
REACT_APP_CONTENTFUL_SPACE_ID=your_space_id
|
|
341
|
-
REACT_APP_CONTENTFUL_CONTENT_TYPE_ID=your_content_type_id
|
|
342
|
-
REACT_APP_CONTENTFUL_FIELD_ID=your_rich_text_field_id
|
|
343
|
-
REACT_APP_CONTENTFUL_MANAGEMENT_TOKEN=your_management_token
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
## Utilities
|
|
347
|
-
|
|
348
|
-
### Configuration Parser
|
|
79
|
+
## 📋 New Utilities
|
|
349
80
|
|
|
81
|
+
### Content Analysis
|
|
350
82
|
```tsx
|
|
351
|
-
import {
|
|
83
|
+
import {
|
|
84
|
+
extractPlainText,
|
|
85
|
+
countWords,
|
|
86
|
+
findEmbeddedContent,
|
|
87
|
+
sanitizeContentfulDocument
|
|
88
|
+
} from '@crashbytes/contentful-richtext-editor';
|
|
352
89
|
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
console.log(config.availableHeadings); // [1, 2, 3]
|
|
357
|
-
console.log(config.disabledFeatures); // ['table', 'embed']
|
|
90
|
+
const plainText = extractPlainText(document);
|
|
91
|
+
const wordCount = countWords(document);
|
|
92
|
+
const embedded = findEmbeddedContent(document);
|
|
358
93
|
```
|
|
359
94
|
|
|
360
|
-
###
|
|
361
|
-
|
|
95
|
+
### Configuration Management
|
|
362
96
|
```tsx
|
|
363
97
|
import {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
} from '@
|
|
367
|
-
|
|
368
|
-
// Convert between formats
|
|
369
|
-
const tiptapContent = contentfulToTiptap(contentfulDocument);
|
|
370
|
-
const contentfulContent = tiptapToContentful(tiptapDocument);
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
## TypeScript Support
|
|
98
|
+
parseContentfulFieldConfig,
|
|
99
|
+
createMockFieldConfig
|
|
100
|
+
} from '@crashbytes/contentful-richtext-editor';
|
|
374
101
|
|
|
375
|
-
|
|
102
|
+
// Parse Contentful config
|
|
103
|
+
const parsed = parseContentfulFieldConfig(fieldConfig);
|
|
376
104
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
EmbeddedEntry,
|
|
383
|
-
EmbeddedAsset,
|
|
384
|
-
ContentfulDocument,
|
|
385
|
-
TiptapDocument
|
|
386
|
-
} from '@your-org/contentful-rich-text-editor';
|
|
105
|
+
// Create mock for testing
|
|
106
|
+
const mockConfig = createMockFieldConfig({
|
|
107
|
+
enabledMarks: ['bold', 'italic'],
|
|
108
|
+
enabledNodeTypes: ['paragraph', 'heading-1', 'unordered-list']
|
|
109
|
+
});
|
|
387
110
|
```
|
|
388
111
|
|
|
389
|
-
##
|
|
112
|
+
## ⌨️ New Keyboard Shortcuts
|
|
390
113
|
|
|
391
|
-
-
|
|
392
|
-
-
|
|
393
|
-
-
|
|
394
|
-
-
|
|
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)
|
|
395
119
|
|
|
396
|
-
##
|
|
120
|
+
## 🐛 Bug Fixes
|
|
397
121
|
|
|
398
|
-
-
|
|
399
|
-
-
|
|
400
|
-
-
|
|
401
|
-
-
|
|
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
|
|
402
127
|
|
|
403
|
-
##
|
|
128
|
+
## 🔧 Technical Improvements
|
|
404
129
|
|
|
405
|
-
|
|
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
|
|
406
134
|
|
|
407
|
-
|
|
408
|
-
- Screen reader compatible
|
|
409
|
-
- ARIA labels and descriptions
|
|
410
|
-
- High contrast mode support
|
|
411
|
-
- Focus management
|
|
135
|
+
## 📚 Documentation
|
|
412
136
|
|
|
413
|
-
|
|
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
|
|
414
141
|
|
|
415
|
-
|
|
142
|
+
## 🎯 What's Next
|
|
416
143
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
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
|
|
421
149
|
|
|
422
|
-
|
|
150
|
+
## 🤝 Contributing
|
|
423
151
|
|
|
424
|
-
|
|
152
|
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
425
153
|
|
|
426
|
-
|
|
427
|
-
// Add to your component
|
|
428
|
-
useEffect(() => {
|
|
429
|
-
if (process.env.NODE_ENV === 'development') {
|
|
430
|
-
window.contentfulEditorDebug = true;
|
|
431
|
-
}
|
|
432
|
-
}, []);
|
|
433
|
-
```
|
|
154
|
+
## 📖 Full Documentation
|
|
434
155
|
|
|
435
|
-
|
|
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
|
|
436
160
|
|
|
437
|
-
|
|
438
|
-
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
439
|
-
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
440
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
441
|
-
5. Open a Pull Request
|
|
161
|
+
## 🔗 Links
|
|
442
162
|
|
|
443
|
-
|
|
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
|
|
444
167
|
|
|
445
|
-
|
|
446
|
-
# Clone the repo
|
|
447
|
-
git clone https://github.com/your-org/contentful-rich-text-editor.git
|
|
168
|
+
## 💝 Acknowledgments
|
|
448
169
|
|
|
449
|
-
|
|
450
|
-
|
|
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
|
|
451
174
|
|
|
452
|
-
|
|
453
|
-
npm run dev
|
|
175
|
+
---
|
|
454
176
|
|
|
455
|
-
|
|
456
|
-
npm test
|
|
457
|
-
|
|
458
|
-
# Build for production
|
|
459
|
-
npm run build
|
|
460
|
-
```
|
|
177
|
+
**Full Changelog**: https://github.com/your-org/contentful-richtext-editor/compare/v1.0.10...v2.0.0
|
|
461
178
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
MIT License
|
|
465
|
-
|
|
466
|
-
Copyright (c) 2024 [Your Name]
|
|
467
|
-
|
|
468
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
469
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
470
|
-
in the Software without restriction, including without limitation the rights
|
|
471
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
472
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
473
|
-
furnished to do so, subject to the following conditions:
|
|
474
|
-
|
|
475
|
-
The above copyright notice and this permission notice shall be included in all
|
|
476
|
-
copies or substantial portions of the Software.
|
|
477
|
-
|
|
478
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
479
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
480
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
481
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
482
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
483
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
484
|
-
SOFTWARE.
|
|
485
|
-
|
|
486
|
-
## Changelog
|
|
487
|
-
|
|
488
|
-
### v2.0.0 - 2024-01-XX
|
|
489
|
-
- ✨ **BREAKING**: Added automatic configuration from Contentful field settings
|
|
490
|
-
- ✨ Added support for inline embedded entries
|
|
491
|
-
- ✨ Added comprehensive utility functions (sanitization, analysis, validation)
|
|
492
|
-
- ✨ Added keyboard shortcuts for embed actions
|
|
493
|
-
- ✨ Enhanced TypeScript support with better type definitions
|
|
494
|
-
- ✨ Added content analysis utilities (word count, plain text extraction)
|
|
495
|
-
- 🔧 Improved accessibility with better ARIA support
|
|
496
|
-
- 🔧 Better error handling and validation
|
|
497
|
-
- 🔧 Performance optimizations
|
|
498
|
-
- 🐛 Fixed link handling in complex nested structures
|
|
499
|
-
- 🐛 Fixed table rendering issues
|
|
500
|
-
- 🐛 Various bug fixes and improvements
|
|
501
|
-
|
|
502
|
-
### v1.2.0 - 2023-12-XX
|
|
503
|
-
- ✨ Added table support
|
|
504
|
-
- ✨ Added themes (minimal, default, contentful)
|
|
505
|
-
- 🔧 Improved toolbar layout and responsiveness
|
|
506
|
-
- 🐛 Fixed undo/redo functionality
|
|
507
|
-
|
|
508
|
-
### v1.1.0 - 2023-11-XX
|
|
509
|
-
- ✨ Added embedded assets support
|
|
510
|
-
- ✨ Added link functionality
|
|
511
|
-
- 🔧 Improved content transformation
|
|
512
|
-
- 🐛 Fixed list nesting issues
|
|
513
|
-
|
|
514
|
-
### v1.0.0 - 2023-10-XX
|
|
515
|
-
- 🎉 Initial release
|
|
516
|
-
- ✨ Basic rich text editing
|
|
517
|
-
- ✨ Contentful document format support
|
|
518
|
-
- ✨ Embedded entries support
|
|
519
|
-
- ✨ Manual configuration options
|
|
520
|
-
|
|
521
|
-
## Support
|
|
522
|
-
|
|
523
|
-
For support, please:
|
|
524
|
-
|
|
525
|
-
1. Check the [documentation](https://github.com/your-org/contentful-rich-text-editor/docs)
|
|
526
|
-
2. Search [existing issues](https://github.com/your-org/contentful-rich-text-editor/issues)
|
|
527
|
-
3. Create a [new issue](https://github.com/your-org/contentful-rich-text-editor/issues/new) with detailed information
|
|
528
|
-
|
|
529
|
-
## Related Projects
|
|
530
|
-
|
|
531
|
-
- [@contentful/rich-text-renderer](https://github.com/contentful/rich-text) - Official Contentful rich text renderer
|
|
532
|
-
- [@tiptap/react](https://tiptap.dev/) - The underlying editor framework
|
|
533
|
-
- [Contentful Management API](https://www.contentful.com/developers/docs/references/content-management-api/) - For fetching field configurations
|
|
179
|
+
**Happy editing! 🎉**
|
package/dist/index.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.contentful-editor{background:#fff;border:1px solid #d3dce6;border-radius:6px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif}.contentful-editor--loading{align-items:center;color:#68737d;display:flex;justify-content:center;min-height:200px}.contentful-toolbar{background:#f7f9fa;border-bottom:1px solid #d3dce6;border-radius:6px 6px 0 0;padding:8px 12px}.contentful-toolbar,.contentful-toolbar__group{align-items:center;display:flex;gap:4px}.contentful-toolbar__group--right{margin-left:auto}.contentful-toolbar__separator{background:#d3dce6;height:24px;margin:0 8px;width:1px}.contentful-toolbar__select{background:#fff;border:1px solid #d3dce6;border-radius:4px;font-size:14px;min-width:120px;padding:4px 8px}.contentful-toolbar__select:focus{border-color:#2e75d4;box-shadow:0 0 0 2px rgba(46,117,212,.2);outline:none}.contentful-toolbar__button{align-items:center;background:transparent;border:1px solid transparent;border-radius:4px;cursor:pointer;display:flex;font-size:14px;height:32px;justify-content:center;line-height:1;min-width:32px;padding:6px 8px}.contentful-toolbar__button:hover{background:#e5ebed;border-color:#d3dce6}.contentful-toolbar__button:disabled{cursor:not-allowed;opacity:.5}.contentful-toolbar__button--active{background:#2e75d4;border-color:#2e75d4;color:#fff}.contentful-toolbar__button--active:hover{background:#1e5aa8;border-color:#1e5aa8}.contentful-toolbar__link-input{align-items:center;display:flex;gap:4px;margin-left:8px}.contentful-toolbar__link-input input{border:1px solid #d3dce6;border-radius:4px;font-size:14px;padding:4px 8px;width:200px}.contentful-toolbar__link-input input:focus{border-color:#2e75d4;box-shadow:0 0 0 2px rgba(46,117,212,.2);outline:none}.contentful-toolbar__link-input button{background:#fff;border:1px solid #d3dce6;border-radius:4px;cursor:pointer;font-size:12px;padding:4px 8px}.contentful-toolbar__embed-dropdown{position:relative}.contentful-toolbar__embed-button{background:#2e75d4;border:1px solid #2e75d4;border-radius:4px;color:#fff;cursor:pointer;font-size:14px;font-weight:500;padding:6px 12px}.contentful-toolbar__embed-button:hover{background:#1e5aa8;border-color:#1e5aa8}.contentful-toolbar__embed-dropdown:hover .contentful-toolbar__embed-menu{display:block}.contentful-toolbar__embed-menu{background:#fff;border:1px solid #d3dce6;border-radius:4px;box-shadow:0 2px 8px rgba(0,0,0,.15);display:none;min-width:120px;position:absolute;right:0;top:100%;z-index:100}.contentful-toolbar__embed-option{background:none;border:none;cursor:pointer;display:block;font-size:14px;padding:8px 12px;text-align:left;width:100%}.contentful-toolbar__embed-option:hover{background:#f7f9fa}.contentful-editor__content-wrapper{position:relative}.contentful-editor__content{min-height:200px}.contentful-editor-content{color:#2c3e50;font-size:16px;line-height:1.6;outline:none;padding:16px}.contentful-editor-content:empty:before{color:#68737d;content:attr(data-placeholder);pointer-events:none}.contentful-editor-content h1{font-size:2em;font-weight:600;line-height:1.2;margin:1em 0 .5em}.contentful-editor-content h2{font-size:1.5em;font-weight:600;line-height:1.3;margin:1em 0 .5em}.contentful-editor-content h3{font-size:1.25em;font-weight:600;line-height:1.4;margin:1em 0 .5em}.contentful-editor-content h4,.contentful-editor-content h5,.contentful-editor-content h6{font-size:1em;font-weight:600;line-height:1.5;margin:1em 0 .5em}.contentful-editor-content p{margin:0 0 1em}.contentful-editor-content p:last-child{margin-bottom:0}.contentful-bullet-list,.contentful-ordered-list{margin:1em 0;padding-left:1.5em}.contentful-bullet-list li,.contentful-ordered-list li{margin:.25em 0}.contentful-blockquote{border-left:4px solid #2e75d4;color:#68737d;font-style:italic;margin:1em 0;padding-left:1em}.contentful-link{color:#2e75d4;text-decoration:underline}.contentful-link:hover{color:#1e5aa8}.contentful-table{border:1px solid #d3dce6;border-collapse:collapse;margin:1em 0;width:100%}.contentful-table-cell,.contentful-table-header{border:1px solid #d3dce6;padding:8px 12px;text-align:left}.contentful-table-header{background:#f7f9fa;font-weight:600}.contentful-editor--minimal{border:none;border-radius:0}.contentful-editor--minimal .contentful-toolbar{background:#fff;border-bottom:1px solid #e1e8ed;border-radius:0}.contentful-editor--default .contentful-editor-content{font-family:Georgia,serif}.contentful-editor:focus-within{border-color:#2e75d4;box-shadow:0 0 0 2px rgba(46,117,212,.2)}@media (max-width:768px){.contentful-toolbar{flex-wrap:wrap}.contentful-toolbar__select{min-width:100px}.contentful-editor-content{font-size:14px;padding:12px}}
|
|
1
|
+
.contentful-editor{background:#fff;border:1px solid #d3dce6;border-radius:6px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif}.contentful-editor--borderless{border:none!important}.contentful-editor--loading{align-items:center;color:#68737d;display:flex;justify-content:center;min-height:200px}.contentful-toolbar{background:#f7f9fa;border-bottom:1px solid #d3dce6;border-radius:6px 6px 0 0;padding:8px 12px}.contentful-toolbar,.contentful-toolbar__group{align-items:center;display:flex;gap:4px}.contentful-toolbar__group--right{margin-left:auto}.contentful-toolbar__separator{background:#d3dce6;height:24px;margin:0 8px;width:1px}.contentful-toolbar__select{background:#fff;border:1px solid #d3dce6;border-radius:4px;font-size:14px;min-width:120px;padding:4px 8px}.contentful-toolbar__select:focus{border-color:#2e75d4;box-shadow:0 0 0 2px rgba(46,117,212,.2);outline:none}.contentful-toolbar__button{align-items:center;background:transparent;border:1px solid transparent;border-radius:4px;cursor:pointer;display:flex;font-size:14px;height:32px;justify-content:center;line-height:1;min-width:32px;padding:6px 8px}.contentful-toolbar__button:hover{background:#e5ebed;border-color:#d3dce6}.contentful-toolbar__button:disabled{cursor:not-allowed;opacity:.5}.contentful-toolbar__button--active{background:#2e75d4;border-color:#2e75d4;color:#fff}.contentful-toolbar__button--active:hover{background:#1e5aa8;border-color:#1e5aa8}.contentful-toolbar__link-input{align-items:center;display:flex;gap:4px;margin-left:8px}.contentful-toolbar__link-input input{border:1px solid #d3dce6;border-radius:4px;font-size:14px;padding:4px 8px;width:200px}.contentful-toolbar__link-input input:focus{border-color:#2e75d4;box-shadow:0 0 0 2px rgba(46,117,212,.2);outline:none}.contentful-toolbar__link-input button{background:#fff;border:1px solid #d3dce6;border-radius:4px;cursor:pointer;font-size:12px;padding:4px 8px}.contentful-toolbar__embed-dropdown{position:relative}.contentful-toolbar__embed-button{background:#2e75d4;border:1px solid #2e75d4;border-radius:4px;color:#fff;cursor:pointer;font-size:14px;font-weight:500;padding:6px 12px}.contentful-toolbar__embed-button:hover{background:#1e5aa8;border-color:#1e5aa8}.contentful-toolbar__embed-dropdown:hover .contentful-toolbar__embed-menu{display:block}.contentful-toolbar__embed-menu{background:#fff;border:1px solid #d3dce6;border-radius:4px;box-shadow:0 2px 8px rgba(0,0,0,.15);display:none;min-width:120px;position:absolute;right:0;top:100%;z-index:100}.contentful-toolbar__embed-option{background:none;border:none;cursor:pointer;display:block;font-size:14px;padding:8px 12px;text-align:left;width:100%}.contentful-toolbar__embed-option:hover{background:#f7f9fa}.contentful-editor__content-wrapper{position:relative}.contentful-editor__content{min-height:200px}.contentful-editor-content{color:#2c3e50;font-size:16px;line-height:1.6;outline:none;padding:16px}.contentful-editor-content:empty:before{color:#68737d;content:attr(data-placeholder);pointer-events:none}.contentful-editor-content h1{font-size:2em;font-weight:600;line-height:1.2;margin:1em 0 .5em}.contentful-editor-content h2{font-size:1.5em;font-weight:600;line-height:1.3;margin:1em 0 .5em}.contentful-editor-content h3{font-size:1.25em;font-weight:600;line-height:1.4;margin:1em 0 .5em}.contentful-editor-content h4,.contentful-editor-content h5,.contentful-editor-content h6{font-size:1em;font-weight:600;line-height:1.5;margin:1em 0 .5em}.contentful-editor-content p{margin:0 0 1em}.contentful-editor-content p:last-child{margin-bottom:0}.contentful-bullet-list,.contentful-ordered-list{margin:1em 0;padding-left:1.5em}.contentful-bullet-list li,.contentful-ordered-list li{margin:.25em 0}.contentful-blockquote{border-left:4px solid #2e75d4;color:#68737d;font-style:italic;margin:1em 0;padding-left:1em}.contentful-link{color:#2e75d4;text-decoration:underline}.contentful-link:hover{color:#1e5aa8}.contentful-table{border:1px solid #d3dce6;border-collapse:collapse;margin:1em 0;width:100%}.contentful-table-cell,.contentful-table-header{border:1px solid #d3dce6;padding:8px 12px;text-align:left}.contentful-table-header{background:#f7f9fa;font-weight:600}.contentful-editor--minimal{border:none;border-radius:0}.contentful-editor--minimal .contentful-toolbar{background:#fff;border-bottom:1px solid #e1e8ed;border-radius:0}.contentful-editor--default .contentful-editor-content{font-family:Georgia,serif}.contentful-editor:focus-within{border-color:#2e75d4;box-shadow:0 0 0 2px rgba(46,117,212,.2)}@media (max-width:768px){.contentful-toolbar{flex-wrap:wrap}.contentful-toolbar__select{min-width:100px}.contentful-editor-content{font-size:14px;padding:12px}}
|