@crashbytes/contentful-richtext-editor 1.0.9 → 2.0.4
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 +227 -428
- 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 +35 -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,332 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @crashbytes/contentful-richtext-editor
|
|
2
2
|
|
|
3
|
-
A
|
|
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
|
-
## Features
|
|
5
|
+
## ✨ Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
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
|
+
- ✅ **Full Contentful Compatibility** - Seamless conversion between Contentful and Tiptap formats
|
|
8
|
+
- ✅ **Modern UI** - Clean, intuitive interface matching Contentful's design
|
|
9
|
+
- ✅ **TypeScript Support** - Complete type safety with Contentful's rich text types
|
|
10
|
+
- ✅ **Extensible** - Built on Tiptap v2 for easy customization
|
|
11
|
+
- ✅ **Lightweight** - Tree-shakeable, only import what you need
|
|
12
|
+
- ✅ **Responsive** - Works on desktop and mobile devices
|
|
13
|
+
- ✅ **Customizable Borders** - Control editor appearance with `showBorder` prop
|
|
17
14
|
|
|
18
|
-
## Installation
|
|
15
|
+
## 🚀 Installation
|
|
19
16
|
|
|
20
17
|
```bash
|
|
21
|
-
npm install @
|
|
22
|
-
# or
|
|
23
|
-
yarn add @your-org/contentful-rich-text-editor
|
|
18
|
+
npm install @crashbytes/contentful-richtext-editor
|
|
24
19
|
```
|
|
25
20
|
|
|
26
|
-
##
|
|
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
|
|
21
|
+
## 📖 Quick Start
|
|
37
22
|
|
|
38
23
|
```tsx
|
|
39
24
|
import React, { useState } from 'react';
|
|
40
|
-
import { ContentfulRichTextEditor } from '@
|
|
25
|
+
import { ContentfulRichTextEditor } from '@crashbytes/contentful-richtext-editor';
|
|
26
|
+
import '@crashbytes/contentful-richtext-editor/dist/index.css';
|
|
41
27
|
import { Document } from '@contentful/rich-text-types';
|
|
42
28
|
|
|
43
|
-
function
|
|
29
|
+
function App() {
|
|
44
30
|
const [content, setContent] = useState<Document>();
|
|
45
31
|
|
|
32
|
+
const handleChange = (document: Document) => {
|
|
33
|
+
setContent(document);
|
|
34
|
+
console.log('Contentful document:', document);
|
|
35
|
+
};
|
|
36
|
+
|
|
46
37
|
return (
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
38
|
+
<div>
|
|
39
|
+
<h1>My Rich Text Editor</h1>
|
|
40
|
+
<ContentfulRichTextEditor
|
|
41
|
+
placeholder="Start writing your content..."
|
|
42
|
+
onChange={handleChange}
|
|
43
|
+
initialValue={content}
|
|
44
|
+
showBorder={true} // Control border visibility
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
52
47
|
);
|
|
53
48
|
}
|
|
49
|
+
|
|
50
|
+
export default App;
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 🎨 Border Control
|
|
54
|
+
|
|
55
|
+
Control the editor's border appearance with the `showBorder` prop:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
// Default - with border (backward compatible)
|
|
59
|
+
<ContentfulRichTextEditor />
|
|
60
|
+
|
|
61
|
+
// Borderless editor for custom layouts
|
|
62
|
+
<ContentfulRichTextEditor
|
|
63
|
+
showBorder={false}
|
|
64
|
+
className="my-custom-editor"
|
|
65
|
+
/>
|
|
66
|
+
|
|
67
|
+
// Themed borderless editor
|
|
68
|
+
<ContentfulRichTextEditor
|
|
69
|
+
showBorder={false}
|
|
70
|
+
theme="minimal"
|
|
71
|
+
/>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Custom Styling with Borderless Mode
|
|
75
|
+
|
|
76
|
+
```css
|
|
77
|
+
/* Custom styling for borderless editor */
|
|
78
|
+
.my-custom-editor {
|
|
79
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
80
|
+
border-radius: 8px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.my-custom-editor .contentful-toolbar {
|
|
84
|
+
background: linear-gradient(45deg, #667eea, #764ba2);
|
|
85
|
+
}
|
|
54
86
|
```
|
|
55
87
|
|
|
56
|
-
|
|
88
|
+
## 🎯 Supported Features
|
|
89
|
+
|
|
90
|
+
- **Text Formatting**: Bold, italic, underline
|
|
91
|
+
- **Headings**: H1 through H6
|
|
92
|
+
- **Lists**: Ordered and unordered lists
|
|
93
|
+
- **Links**: Hyperlinks with URL validation
|
|
94
|
+
- **Tables**: Full table support with headers
|
|
95
|
+
- **Quotes**: Blockquotes
|
|
96
|
+
- **Embedded Content**: Callbacks for Contentful entries and assets
|
|
97
|
+
- **Undo/Redo**: Full history support
|
|
98
|
+
|
|
99
|
+
## 🔧 Advanced Usage
|
|
100
|
+
|
|
101
|
+
### With Contentful Integration
|
|
57
102
|
|
|
58
103
|
```tsx
|
|
59
|
-
import
|
|
60
|
-
import
|
|
61
|
-
ContentfulRichTextEditor,
|
|
62
|
-
fetchContentfulFieldConfig,
|
|
63
|
-
ContentfulFieldConfiguration
|
|
64
|
-
} from '@your-org/contentful-rich-text-editor';
|
|
104
|
+
import { ContentfulRichTextEditor } from '@crashbytes/contentful-richtext-editor';
|
|
105
|
+
import '@crashbytes/contentful-richtext-editor/dist/index.css';
|
|
65
106
|
|
|
66
107
|
function ContentfulEditor() {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
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
|
+
};
|
|
78
119
|
|
|
79
120
|
return (
|
|
80
121
|
<ContentfulRichTextEditor
|
|
81
|
-
|
|
82
|
-
onChange={(doc) =>
|
|
122
|
+
placeholder="Write your travel tip..."
|
|
123
|
+
onChange={(doc) => saveToContentful(doc)}
|
|
83
124
|
onEmbedEntry={handleEmbedEntry}
|
|
84
125
|
onEmbedAsset={handleEmbedAsset}
|
|
85
|
-
|
|
126
|
+
theme="contentful"
|
|
127
|
+
showBorder={true}
|
|
86
128
|
/>
|
|
87
129
|
);
|
|
88
130
|
}
|
|
89
131
|
```
|
|
90
132
|
|
|
91
|
-
|
|
133
|
+
### Customized Editor
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
<ContentfulRichTextEditor
|
|
137
|
+
placeholder="Simple editor..."
|
|
138
|
+
disabledFeatures={['table', 'embed', 'quote']}
|
|
139
|
+
theme="minimal"
|
|
140
|
+
readonly={false}
|
|
141
|
+
showBorder={false}
|
|
142
|
+
onChange={handleChange}
|
|
143
|
+
/>
|
|
144
|
+
```
|
|
92
145
|
|
|
93
|
-
|
|
146
|
+
## 📋 Props Reference
|
|
94
147
|
|
|
95
148
|
| Prop | Type | Default | Description |
|
|
96
149
|
|------|------|---------|-------------|
|
|
150
|
+
| `showBorder` | `boolean` | `true` | Control editor border visibility |
|
|
97
151
|
| `initialValue` | `Document` | `undefined` | Initial Contentful rich text document |
|
|
98
152
|
| `onChange` | `(document: Document) => void` | `undefined` | Callback when content changes |
|
|
99
|
-
| `onEmbedEntry` | `() => Promise<any
|
|
100
|
-
| `onEmbedAsset` | `() => Promise<any
|
|
101
|
-
| `onEmbedInlineEntry` | `() => Promise<any
|
|
102
|
-
| `fieldConfiguration` | `ContentfulFieldConfiguration` | `undefined` | Contentful field validation config |
|
|
103
|
-
| `readonly` | `boolean` | `false` | Whether editor is read-only |
|
|
153
|
+
| `onEmbedEntry` | `() => Promise<any> \| void` | `undefined` | Callback for embedding Contentful entries |
|
|
154
|
+
| `onEmbedAsset` | `() => Promise<any> \| void` | `undefined` | Callback for embedding Contentful assets |
|
|
155
|
+
| `onEmbedInlineEntry` | `() => Promise<any> \| void` | `undefined` | Callback for embedding inline entries |
|
|
104
156
|
| `placeholder` | `string` | `'Start writing...'` | Placeholder text |
|
|
105
|
-
| `
|
|
157
|
+
| `readonly` | `boolean` | `false` | Whether editor is read-only |
|
|
106
158
|
| `className` | `string` | `''` | Additional CSS classes |
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
|
|
111
|
-
### Configuration Types
|
|
112
|
-
|
|
113
|
-
```tsx
|
|
114
|
-
interface ContentfulFieldConfiguration {
|
|
115
|
-
validations?: Array<{
|
|
116
|
-
enabledMarks?: string[];
|
|
117
|
-
enabledNodeTypes?: string[];
|
|
118
|
-
}>;
|
|
119
|
-
settings?: {
|
|
120
|
-
helpText?: string;
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
```
|
|
159
|
+
| `theme` | `'default' \| 'minimal' \| 'contentful'` | `'contentful'` | Visual theme |
|
|
160
|
+
| `disabledFeatures` | `Array<string>` | `[]` | Features to disable |
|
|
161
|
+
| `availableHeadings` | `Array<1 \| 2 \| 3 \| 4 \| 5 \| 6>` | `[1,2,3,4,5,6]` | Available heading levels |
|
|
162
|
+
| `availableMarks` | `Array<'bold' \| 'italic' \| 'underline'>` | `['bold','italic','underline']` | Available text formatting |
|
|
124
163
|
|
|
125
|
-
|
|
164
|
+
## 🚫 Disabling Features
|
|
126
165
|
|
|
127
|
-
|
|
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
|
|
166
|
+
You can disable specific features by passing them in the `disabledFeatures` array:
|
|
137
167
|
|
|
138
|
-
|
|
168
|
+
- `'bold'` - Bold text formatting
|
|
169
|
+
- `'italic'` - Italic text formatting
|
|
170
|
+
- `'underline'` - Underline text formatting
|
|
171
|
+
- `'link'` - Hyperlinks
|
|
172
|
+
- `'lists'` - Ordered and unordered lists
|
|
173
|
+
- `'headings'` - All heading levels
|
|
174
|
+
- `'quote'` - Blockquotes
|
|
175
|
+
- `'table'` - Tables
|
|
176
|
+
- `'embed'` - Embedded content
|
|
139
177
|
|
|
140
|
-
|
|
141
|
-
- `italic` - Italic text
|
|
142
|
-
- `underline` - Underlined text
|
|
143
|
-
- `code` - Inline code
|
|
144
|
-
|
|
145
|
-
## Configuration Examples
|
|
146
|
-
|
|
147
|
-
### Mock Configuration for Testing
|
|
178
|
+
## 🛠️ Utility Functions
|
|
148
179
|
|
|
149
180
|
```tsx
|
|
150
|
-
import {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
181
|
+
import {
|
|
182
|
+
contentfulToTiptap,
|
|
183
|
+
tiptapToContentful,
|
|
184
|
+
validateContentfulDocument,
|
|
185
|
+
createEmptyDocument,
|
|
186
|
+
extractPlainText,
|
|
187
|
+
countWords,
|
|
188
|
+
findEmbeddedContent
|
|
189
|
+
} from '@crashbytes/contentful-richtext-editor';
|
|
190
|
+
|
|
191
|
+
// Convert between formats
|
|
192
|
+
const tiptapJson = contentfulToTiptap(contentfulDocument);
|
|
193
|
+
const contentfulDoc = tiptapToContentful(tiptapJson);
|
|
194
|
+
|
|
195
|
+
// Validation and utilities
|
|
196
|
+
const isValid = validateContentfulDocument(someDocument);
|
|
197
|
+
const emptyDoc = createEmptyDocument();
|
|
198
|
+
const plainText = extractPlainText(document);
|
|
199
|
+
const wordCount = countWords(document);
|
|
200
|
+
const embedded = findEmbeddedContent(document);
|
|
165
201
|
```
|
|
166
202
|
|
|
167
|
-
|
|
203
|
+
## 🎨 Styling
|
|
204
|
+
|
|
205
|
+
The editor comes with default styles that match Contentful's design. Import the CSS:
|
|
168
206
|
|
|
169
207
|
```tsx
|
|
170
|
-
|
|
171
|
-
availableHeadings={[1, 2, 3]}
|
|
172
|
-
availableMarks={['bold', 'italic']}
|
|
173
|
-
disabledFeatures={['table', 'embed']}
|
|
174
|
-
/>
|
|
208
|
+
import '@crashbytes/contentful-richtext-editor/dist/index.css';
|
|
175
209
|
```
|
|
176
210
|
|
|
177
|
-
|
|
211
|
+
### Custom Styling
|
|
178
212
|
|
|
179
|
-
|
|
213
|
+
You can override the default styles by targeting the CSS classes:
|
|
180
214
|
|
|
181
215
|
```css
|
|
182
|
-
/* Main editor container */
|
|
183
216
|
.contentful-editor {
|
|
184
|
-
border:
|
|
185
|
-
border-radius: 6px;
|
|
217
|
+
border: 2px solid #your-color;
|
|
186
218
|
}
|
|
187
219
|
|
|
188
|
-
/* Toolbar */
|
|
189
220
|
.contentful-toolbar {
|
|
190
|
-
background: #
|
|
191
|
-
border-bottom: 1px solid #d3dce6;
|
|
221
|
+
background: #your-background;
|
|
192
222
|
}
|
|
193
223
|
|
|
194
|
-
/* Content area */
|
|
195
224
|
.contentful-editor-content {
|
|
196
|
-
|
|
197
|
-
min-height: 200px;
|
|
225
|
+
font-family: 'Your Font', sans-serif;
|
|
198
226
|
}
|
|
199
227
|
|
|
200
|
-
/*
|
|
201
|
-
.contentful-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
padding: 8px;
|
|
205
|
-
border-radius: 4px;
|
|
228
|
+
/* Borderless editor styling */
|
|
229
|
+
.contentful-editor--borderless {
|
|
230
|
+
border: none;
|
|
231
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
206
232
|
}
|
|
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
|
-
};
|
|
276
233
|
```
|
|
277
234
|
|
|
278
|
-
###
|
|
235
|
+
### Themes
|
|
279
236
|
|
|
280
|
-
|
|
281
|
-
|
|
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
|
|
237
|
+
**Contentful** (default)
|
|
238
|
+
Matches Contentful's native editor appearance.
|
|
289
239
|
|
|
290
|
-
|
|
240
|
+
**Minimal**
|
|
241
|
+
Clean, minimal design with reduced visual elements.
|
|
291
242
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
validateContentfulDocument,
|
|
295
|
-
extractPlainText,
|
|
296
|
-
countWords,
|
|
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);
|
|
313
|
-
|
|
314
|
-
// Find embedded content
|
|
315
|
-
const embedded = findEmbeddedContent(document);
|
|
316
|
-
console.log('Embedded content:', embedded);
|
|
317
|
-
|
|
318
|
-
saveDocument(document);
|
|
319
|
-
};
|
|
320
|
-
```
|
|
243
|
+
**Default**
|
|
244
|
+
Standard rich text editor appearance with serif fonts.
|
|
321
245
|
|
|
322
|
-
|
|
246
|
+
## 🌐 Next.js Usage
|
|
323
247
|
|
|
324
248
|
```tsx
|
|
325
|
-
|
|
249
|
+
// pages/editor.tsx or app/editor/page.tsx
|
|
250
|
+
import dynamic from 'next/dynamic';
|
|
326
251
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
['paragraph', 'heading-1', 'heading-2', 'unordered-list'], // allowed nodes
|
|
331
|
-
['bold', 'italic'] // allowed marks
|
|
252
|
+
const ContentfulEditor = dynamic(
|
|
253
|
+
() => import('@crashbytes/contentful-richtext-editor').then(mod => mod.ContentfulRichTextEditor),
|
|
254
|
+
{ ssr: false }
|
|
332
255
|
);
|
|
333
|
-
```
|
|
334
256
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
## Utilities
|
|
347
|
-
|
|
348
|
-
### Configuration Parser
|
|
349
|
-
|
|
350
|
-
```tsx
|
|
351
|
-
import { parseContentfulFieldConfig } from '@your-org/contentful-rich-text-editor';
|
|
352
|
-
|
|
353
|
-
const config = parseContentfulFieldConfig(fieldConfiguration);
|
|
354
|
-
// Returns parsed configuration with boolean flags for each feature
|
|
355
|
-
console.log(config.allowHyperlinks); // true/false
|
|
356
|
-
console.log(config.availableHeadings); // [1, 2, 3]
|
|
357
|
-
console.log(config.disabledFeatures); // ['table', 'embed']
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
### Content Transformation
|
|
361
|
-
|
|
362
|
-
```tsx
|
|
363
|
-
import {
|
|
364
|
-
contentfulToTiptap,
|
|
365
|
-
tiptapToContentful
|
|
366
|
-
} from '@your-org/contentful-rich-text-editor';
|
|
367
|
-
|
|
368
|
-
// Convert between formats
|
|
369
|
-
const tiptapContent = contentfulToTiptap(contentfulDocument);
|
|
370
|
-
const contentfulContent = tiptapToContentful(tiptapDocument);
|
|
257
|
+
export default function EditorPage() {
|
|
258
|
+
return (
|
|
259
|
+
<div>
|
|
260
|
+
<ContentfulEditor
|
|
261
|
+
placeholder="Write something amazing..."
|
|
262
|
+
onChange={(doc) => console.log(doc)}
|
|
263
|
+
showBorder={false}
|
|
264
|
+
/>
|
|
265
|
+
</div>
|
|
266
|
+
);
|
|
267
|
+
}
|
|
371
268
|
```
|
|
372
269
|
|
|
373
|
-
## TypeScript Support
|
|
270
|
+
## 📝 TypeScript Support
|
|
374
271
|
|
|
375
|
-
This package is written in TypeScript and includes full type definitions. All
|
|
272
|
+
This package is written in TypeScript and includes full type definitions. All Contentful rich text types are re-exported for convenience:
|
|
376
273
|
|
|
377
274
|
```tsx
|
|
378
275
|
import type {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
TiptapDocument
|
|
386
|
-
} from '@your-org/contentful-rich-text-editor';
|
|
276
|
+
Document,
|
|
277
|
+
Block,
|
|
278
|
+
Inline,
|
|
279
|
+
Text,
|
|
280
|
+
ContentfulRichTextEditorProps
|
|
281
|
+
} from '@crashbytes/contentful-richtext-editor';
|
|
387
282
|
```
|
|
388
283
|
|
|
389
|
-
## Browser Support
|
|
284
|
+
## 🌐 Browser Support
|
|
390
285
|
|
|
391
|
-
- Chrome
|
|
392
|
-
- Firefox
|
|
393
|
-
- Safari
|
|
394
|
-
- Edge
|
|
286
|
+
- Chrome 80+
|
|
287
|
+
- Firefox 78+
|
|
288
|
+
- Safari 13+
|
|
289
|
+
- Edge 80+
|
|
395
290
|
|
|
396
|
-
##
|
|
291
|
+
## 🔄 Migration
|
|
397
292
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
- Consider implementing virtualization for very large content
|
|
401
|
-
- Use the `readonly` prop when displaying content to improve performance
|
|
402
|
-
|
|
403
|
-
## Accessibility
|
|
404
|
-
|
|
405
|
-
The editor is built with accessibility in mind:
|
|
406
|
-
|
|
407
|
-
- Full keyboard navigation support
|
|
408
|
-
- Screen reader compatible
|
|
409
|
-
- ARIA labels and descriptions
|
|
410
|
-
- High contrast mode support
|
|
411
|
-
- Focus management
|
|
412
|
-
|
|
413
|
-
## Troubleshooting
|
|
414
|
-
|
|
415
|
-
### Common Issues
|
|
416
|
-
|
|
417
|
-
1. **Editor not loading**: Check that all peer dependencies are installed
|
|
418
|
-
2. **Configuration not applying**: Ensure `fieldConfiguration` prop is properly set
|
|
419
|
-
3. **Embed callbacks not working**: Verify that embed handlers return proper Contentful objects
|
|
420
|
-
4. **Styling issues**: Check that CSS is properly imported and not conflicting
|
|
421
|
-
|
|
422
|
-
### Debug Mode
|
|
423
|
-
|
|
424
|
-
Enable debug logging:
|
|
293
|
+
### From v2.0.3 to v2.0.4
|
|
294
|
+
No breaking changes! Simply update and optionally use the new `showBorder` prop:
|
|
425
295
|
|
|
426
296
|
```tsx
|
|
427
|
-
//
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
}, []);
|
|
297
|
+
// Before
|
|
298
|
+
<ContentfulRichTextEditor />
|
|
299
|
+
|
|
300
|
+
// After (optional)
|
|
301
|
+
<ContentfulRichTextEditor showBorder={false} />
|
|
433
302
|
```
|
|
434
303
|
|
|
435
|
-
## Contributing
|
|
304
|
+
## 🤝 Contributing
|
|
305
|
+
|
|
306
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
436
307
|
|
|
437
308
|
1. Fork the repository
|
|
438
309
|
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
439
|
-
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
310
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
440
311
|
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
441
312
|
5. Open a Pull Request
|
|
442
313
|
|
|
443
|
-
|
|
314
|
+
## 📄 License
|
|
444
315
|
|
|
445
|
-
|
|
446
|
-
# Clone the repo
|
|
447
|
-
git clone https://github.com/your-org/contentful-rich-text-editor.git
|
|
316
|
+
MIT © [CrashBytes](https://github.com/CrashBytes)
|
|
448
317
|
|
|
449
|
-
|
|
450
|
-
npm install
|
|
318
|
+
## 🔗 Related Packages
|
|
451
319
|
|
|
452
|
-
|
|
453
|
-
|
|
320
|
+
- [@contentful/rich-text-react-renderer](https://www.npmjs.com/package/@contentful/rich-text-react-renderer) - For rendering Contentful rich text
|
|
321
|
+
- [@contentful/rich-text-types](https://www.npmjs.com/package/@contentful/rich-text-types) - Contentful rich text type definitions
|
|
322
|
+
- [@tiptap/react](https://www.npmjs.com/package/@tiptap/react) - The underlying editor framework
|
|
454
323
|
|
|
455
|
-
|
|
456
|
-
npm test
|
|
324
|
+
## 📈 Version History
|
|
457
325
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
326
|
+
- **v2.0.4** - Added `showBorder` prop for flexible styling, resolved publishing issues
|
|
327
|
+
- **v2.0.0** - Major release with full Contentful compatibility and modern architecture
|
|
328
|
+
- **v1.x** - Initial releases with basic functionality
|
|
329
|
+
|
|
330
|
+
---
|
|
461
331
|
|
|
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
|
|
332
|
+
Made with ❤️ for the Contentful community
|