@crashbytes/react-version-compare 1.0.1 → 1.0.3
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 +43 -3
- package/dist/cjs/index.js +313 -88
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +294 -88
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/styles.css +42 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@ The Storybook provides interactive examples for all comparison scenarios. You ca
|
|
|
18
18
|
- 🎯 **Precise Highlighting**: Only highlights the actual differences, not entire lines
|
|
19
19
|
- 📝 **String Comparison**: Word-level diff for text content
|
|
20
20
|
- 📋 **Array Comparison**: Item-level diff for arrays of strings
|
|
21
|
+
- 📄 **Contentful Rich Text**: Compare Contentful documents with text or structure modes
|
|
21
22
|
- 🎨 **Clean Visual Design**: Clear red/green highlighting for changes
|
|
22
23
|
- 📱 **Responsive**: Works on desktop and mobile devices
|
|
23
24
|
- ⚡ **TypeScript Support**: Full TypeScript definitions included
|
|
@@ -78,16 +79,52 @@ const modifiedArray = [
|
|
|
78
79
|
/>
|
|
79
80
|
```
|
|
80
81
|
|
|
82
|
+
### Contentful Rich Text Comparison
|
|
83
|
+
|
|
84
|
+
The component now supports comparing Contentful Rich Text documents with two different modes:
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
import { Compare } from '@crashbytes/react-version-compare';
|
|
88
|
+
import { Document } from '@contentful/rich-text-types';
|
|
89
|
+
|
|
90
|
+
// Text mode - extracts plain text for comparison
|
|
91
|
+
<Compare
|
|
92
|
+
original={contentfulDoc1}
|
|
93
|
+
modified={contentfulDoc2}
|
|
94
|
+
compareMode="text"
|
|
95
|
+
viewMode="side-by-side"
|
|
96
|
+
/>
|
|
97
|
+
|
|
98
|
+
// Structure mode - compares document structure
|
|
99
|
+
<Compare
|
|
100
|
+
original={contentfulDoc1}
|
|
101
|
+
modified={contentfulDoc2}
|
|
102
|
+
compareMode="structure"
|
|
103
|
+
viewMode="side-by-side"
|
|
104
|
+
/>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Structure Mode** preserves the semantic meaning of the document by comparing:
|
|
108
|
+
- Headings (with levels)
|
|
109
|
+
- Paragraphs
|
|
110
|
+
- Lists and list items
|
|
111
|
+
- Block quotes
|
|
112
|
+
- And other rich text elements
|
|
113
|
+
|
|
114
|
+
**Text Mode** extracts plain text content and performs word-level comparison, similar to string comparison.
|
|
115
|
+
|
|
81
116
|
## API Reference
|
|
82
117
|
|
|
83
118
|
### Props
|
|
84
119
|
|
|
85
120
|
| Prop | Type | Default | Description |
|
|
86
121
|
|------|------|---------|-------------|
|
|
87
|
-
| `original` | `string \| string[]` | **required** | The original content |
|
|
88
|
-
| `modified` | `string \| string[]` | **required** | The modified content |
|
|
122
|
+
| `original` | `string \| string[] \| Document` | **required** | The original content |
|
|
123
|
+
| `modified` | `string \| string[] \| Document` | **required** | The modified content |
|
|
89
124
|
| `viewMode` | `'side-by-side' \| 'inline'` | `'side-by-side'` | How to display the comparison |
|
|
90
125
|
| `className` | `string` | `''` | Custom CSS class name |
|
|
126
|
+
| `caseSensitive` | `boolean` | `true` | Whether comparison is case sensitive |
|
|
127
|
+
| `compareMode` | `'text' \| 'structure'` | `'text'` | Comparison mode for Contentful documents |
|
|
91
128
|
|
|
92
129
|
## Examples
|
|
93
130
|
|
|
@@ -149,13 +186,16 @@ The component uses CSS classes that you can customize:
|
|
|
149
186
|
- **Content management**: Show edits in articles or posts
|
|
150
187
|
- **Data comparison**: Compare lists or arrays of items
|
|
151
188
|
- **Translation work**: Compare original and translated text
|
|
189
|
+
- **Contentful CMS**: Compare rich text content versions and track editorial changes
|
|
190
|
+
- **Documentation**: Track changes in structured content with semantic meaning
|
|
152
191
|
|
|
153
192
|
## How It Works
|
|
154
193
|
|
|
155
194
|
- **String comparison**: Uses word-level diffing to identify precise changes
|
|
156
195
|
- **Array comparison**: Compares items by position and content
|
|
196
|
+
- **Contentful comparison**: Extracts plain text or compares structural elements
|
|
157
197
|
- **Smart highlighting**: Only highlights actual differences, not entire lines
|
|
158
|
-
- **Type safety**: Ensures both inputs are the same type (
|
|
198
|
+
- **Type safety**: Ensures both inputs are the same type (strings, arrays, or Contentful documents)
|
|
159
199
|
|
|
160
200
|
## License
|
|
161
201
|
|
package/dist/cjs/index.js
CHANGED
|
@@ -2,142 +2,367 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var diff = require('diff');
|
|
6
|
-
require('react');
|
|
7
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var react = require('react');
|
|
7
|
+
var richTextTypes = require('@contentful/rich-text-types');
|
|
8
|
+
var Diff = require('diff');
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const originalParts = [];
|
|
22
|
-
const modifiedParts = [];
|
|
23
|
-
for (const part of diff$1) {
|
|
24
|
-
if (part.removed) {
|
|
25
|
-
originalParts.push(/*#__PURE__*/jsxRuntime.jsx("span", {
|
|
26
|
-
className: "diff-removed",
|
|
27
|
-
children: part.value
|
|
28
|
-
}, originalParts.length));
|
|
29
|
-
} else if (part.added) {
|
|
30
|
-
modifiedParts.push(/*#__PURE__*/jsxRuntime.jsx("span", {
|
|
31
|
-
className: "diff-added",
|
|
32
|
-
children: part.value
|
|
33
|
-
}, modifiedParts.length));
|
|
34
|
-
} else {
|
|
35
|
-
originalParts.push(/*#__PURE__*/jsxRuntime.jsx("span", {
|
|
36
|
-
className: "diff-unchanged",
|
|
37
|
-
children: part.value
|
|
38
|
-
}, originalParts.length));
|
|
39
|
-
modifiedParts.push(/*#__PURE__*/jsxRuntime.jsx("span", {
|
|
40
|
-
className: "diff-unchanged",
|
|
41
|
-
children: part.value
|
|
42
|
-
}, modifiedParts.length));
|
|
43
|
-
}
|
|
10
|
+
function _interopNamespaceDefault(e) {
|
|
11
|
+
var n = Object.create(null);
|
|
12
|
+
if (e) {
|
|
13
|
+
Object.keys(e).forEach(function (k) {
|
|
14
|
+
if (k !== 'default') {
|
|
15
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return e[k]; }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
44
22
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
23
|
+
n.default = e;
|
|
24
|
+
return Object.freeze(n);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var Diff__namespace = /*#__PURE__*/_interopNamespaceDefault(Diff);
|
|
50
28
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
29
|
+
// Exported type guard for Contentful documents
|
|
30
|
+
function isContentfulDocument(value) {
|
|
31
|
+
return value && typeof value === 'object' && value.nodeType === richTextTypes.BLOCKS.DOCUMENT && Array.isArray(value.content);
|
|
32
|
+
}
|
|
33
|
+
// Extract plain text from Contentful document
|
|
34
|
+
function extractPlainText(document) {
|
|
35
|
+
const extractFromNode = node => {
|
|
36
|
+
if (node.nodeType === 'text') {
|
|
37
|
+
return node.value;
|
|
38
|
+
}
|
|
39
|
+
if ('content' in node && node.content) {
|
|
40
|
+
return node.content.map(child => extractFromNode(child)).join('');
|
|
41
|
+
}
|
|
42
|
+
return '';
|
|
43
|
+
};
|
|
44
|
+
return extractFromNode(document);
|
|
45
|
+
}
|
|
46
|
+
// Extract structured content for structure diff
|
|
47
|
+
function extractStructuredContent(document) {
|
|
48
|
+
const result = [];
|
|
49
|
+
const extractFromNode = node => {
|
|
50
|
+
if (node.nodeType === 'text') return;
|
|
51
|
+
if ('content' in node && node.content) {
|
|
52
|
+
const textContent = node.content.map(child => child.nodeType === 'text' ? child.value : '').join('');
|
|
53
|
+
let displayType = node.nodeType;
|
|
54
|
+
let headingLevel;
|
|
55
|
+
switch (node.nodeType) {
|
|
56
|
+
case richTextTypes.BLOCKS.HEADING_1:
|
|
57
|
+
displayType = 'Heading';
|
|
58
|
+
headingLevel = 1;
|
|
59
|
+
break;
|
|
60
|
+
case richTextTypes.BLOCKS.HEADING_2:
|
|
61
|
+
displayType = 'Heading';
|
|
62
|
+
headingLevel = 2;
|
|
63
|
+
break;
|
|
64
|
+
case richTextTypes.BLOCKS.HEADING_3:
|
|
65
|
+
displayType = 'Heading';
|
|
66
|
+
headingLevel = 3;
|
|
67
|
+
break;
|
|
68
|
+
case richTextTypes.BLOCKS.HEADING_4:
|
|
69
|
+
displayType = 'Heading';
|
|
70
|
+
headingLevel = 4;
|
|
71
|
+
break;
|
|
72
|
+
case richTextTypes.BLOCKS.HEADING_5:
|
|
73
|
+
displayType = 'Heading';
|
|
74
|
+
headingLevel = 5;
|
|
75
|
+
break;
|
|
76
|
+
case richTextTypes.BLOCKS.HEADING_6:
|
|
77
|
+
displayType = 'Heading';
|
|
78
|
+
headingLevel = 6;
|
|
79
|
+
break;
|
|
80
|
+
case richTextTypes.BLOCKS.PARAGRAPH:
|
|
81
|
+
displayType = 'Text';
|
|
82
|
+
break;
|
|
83
|
+
case richTextTypes.BLOCKS.UL_LIST:
|
|
84
|
+
displayType = 'List';
|
|
85
|
+
break;
|
|
86
|
+
case richTextTypes.BLOCKS.OL_LIST:
|
|
87
|
+
displayType = 'Numbered List';
|
|
88
|
+
break;
|
|
89
|
+
case richTextTypes.BLOCKS.LIST_ITEM:
|
|
90
|
+
displayType = 'List Item';
|
|
91
|
+
break;
|
|
92
|
+
case richTextTypes.BLOCKS.QUOTE:
|
|
93
|
+
displayType = 'Quote';
|
|
94
|
+
break;
|
|
95
|
+
case richTextTypes.BLOCKS.TABLE:
|
|
96
|
+
displayType = 'Table';
|
|
97
|
+
break;
|
|
98
|
+
default:
|
|
99
|
+
displayType = node.nodeType.charAt(0).toUpperCase() + node.nodeType.slice(1);
|
|
100
|
+
}
|
|
101
|
+
if (textContent.trim()) {
|
|
102
|
+
result.push({
|
|
103
|
+
type: displayType,
|
|
104
|
+
content: textContent.trim(),
|
|
105
|
+
level: headingLevel
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
node.content.forEach(child => {
|
|
109
|
+
if (child.nodeType !== 'text') extractFromNode(child);
|
|
110
|
+
});
|
|
58
111
|
}
|
|
59
|
-
|
|
112
|
+
};
|
|
113
|
+
if (document.content) document.content.forEach(node => extractFromNode(node));
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
// Main Contentful diff renderer
|
|
117
|
+
async function renderContentfulDiff(origDoc, modDoc, compareMode, caseSensitive, renderStringDiff) {
|
|
118
|
+
// Dynamically import diff for Vite/ESM compatibility
|
|
119
|
+
const DiffModule = await import('diff');
|
|
120
|
+
const Diff = DiffModule.default ?? DiffModule;
|
|
121
|
+
const {
|
|
122
|
+
diffWords,
|
|
123
|
+
diffArrays
|
|
124
|
+
} = Diff;
|
|
125
|
+
if (compareMode === 'structure') {
|
|
126
|
+
const origStructure = extractStructuredContent(origDoc);
|
|
127
|
+
const modStructure = extractStructuredContent(modDoc);
|
|
128
|
+
const diff = diffArrays(origStructure, modStructure, {
|
|
129
|
+
comparator: (a, b) => a.type === b.type && a.content === b.content && a.level === b.level
|
|
130
|
+
});
|
|
60
131
|
const originalParts = [];
|
|
61
132
|
const modifiedParts = [];
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
part.value.forEach((item, index) => {
|
|
72
|
-
modifiedParts.push(/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
133
|
+
let origIdx = 0;
|
|
134
|
+
let modIdx = 0;
|
|
135
|
+
diff.forEach(part => {
|
|
136
|
+
if (part.added) {
|
|
137
|
+
part.value.forEach((modItem, i) => {
|
|
138
|
+
originalParts.push(jsxRuntime.jsx("div", {
|
|
139
|
+
className: "diff-blank-line"
|
|
140
|
+
}, `blank-orig-${modIdx + i}`));
|
|
141
|
+
modifiedParts.push(jsxRuntime.jsxs("div", {
|
|
73
142
|
className: "diff-added-line",
|
|
74
|
-
children:
|
|
75
|
-
|
|
143
|
+
children: [jsxRuntime.jsx("span", {
|
|
144
|
+
className: "diff-structure-type",
|
|
145
|
+
children: modItem.type
|
|
146
|
+
}), modItem.level && jsxRuntime.jsxs("span", {
|
|
147
|
+
className: "diff-structure-level",
|
|
148
|
+
children: [" H", modItem.level]
|
|
149
|
+
}), jsxRuntime.jsxs("span", {
|
|
150
|
+
className: "diff-structure-content",
|
|
151
|
+
children: [": ", modItem.content]
|
|
152
|
+
})]
|
|
153
|
+
}, `added-mod-${modIdx + i}`));
|
|
76
154
|
});
|
|
155
|
+
modIdx += part.count || 0;
|
|
156
|
+
} else if (part.removed) {
|
|
157
|
+
part.value.forEach((origItem, i) => {
|
|
158
|
+
originalParts.push(jsxRuntime.jsxs("div", {
|
|
159
|
+
className: "diff-removed-line",
|
|
160
|
+
children: [jsxRuntime.jsx("span", {
|
|
161
|
+
className: "diff-structure-type",
|
|
162
|
+
children: origItem.type
|
|
163
|
+
}), origItem.level && jsxRuntime.jsxs("span", {
|
|
164
|
+
className: "diff-structure-level",
|
|
165
|
+
children: [" H", origItem.level]
|
|
166
|
+
}), jsxRuntime.jsxs("span", {
|
|
167
|
+
className: "diff-structure-content",
|
|
168
|
+
children: [": ", origItem.content]
|
|
169
|
+
})]
|
|
170
|
+
}, `removed-orig-${origIdx + i}`));
|
|
171
|
+
modifiedParts.push(jsxRuntime.jsx("div", {
|
|
172
|
+
className: "diff-blank-line"
|
|
173
|
+
}, `blank-mod-${origIdx + i}`));
|
|
174
|
+
});
|
|
175
|
+
origIdx += part.count || 0;
|
|
77
176
|
} else {
|
|
78
|
-
part.value.forEach((item,
|
|
79
|
-
originalParts.push(
|
|
177
|
+
part.value.forEach((item, i) => {
|
|
178
|
+
originalParts.push(jsxRuntime.jsxs("div", {
|
|
80
179
|
className: "diff-unchanged-line",
|
|
81
|
-
children:
|
|
82
|
-
|
|
83
|
-
|
|
180
|
+
children: [jsxRuntime.jsx("span", {
|
|
181
|
+
className: "diff-structure-type",
|
|
182
|
+
children: item.type
|
|
183
|
+
}), item.level && jsxRuntime.jsxs("span", {
|
|
184
|
+
className: "diff-structure-level",
|
|
185
|
+
children: [" H", item.level]
|
|
186
|
+
}), jsxRuntime.jsxs("span", {
|
|
187
|
+
className: "diff-structure-content",
|
|
188
|
+
children: [": ", item.content]
|
|
189
|
+
})]
|
|
190
|
+
}, `unchanged-orig-${origIdx + i}`));
|
|
191
|
+
modifiedParts.push(jsxRuntime.jsxs("div", {
|
|
84
192
|
className: "diff-unchanged-line",
|
|
85
|
-
children:
|
|
86
|
-
|
|
193
|
+
children: [jsxRuntime.jsx("span", {
|
|
194
|
+
className: "diff-structure-type",
|
|
195
|
+
children: item.type
|
|
196
|
+
}), item.level && jsxRuntime.jsxs("span", {
|
|
197
|
+
className: "diff-structure-level",
|
|
198
|
+
children: [" H", item.level]
|
|
199
|
+
}), jsxRuntime.jsxs("span", {
|
|
200
|
+
className: "diff-structure-content",
|
|
201
|
+
children: [": ", item.content]
|
|
202
|
+
})]
|
|
203
|
+
}, `unchanged-mod-${modIdx + i}`));
|
|
87
204
|
});
|
|
205
|
+
origIdx += part.count || 0;
|
|
206
|
+
modIdx += part.count || 0;
|
|
88
207
|
}
|
|
89
|
-
}
|
|
208
|
+
});
|
|
90
209
|
return {
|
|
91
210
|
originalParts,
|
|
92
211
|
modifiedParts
|
|
93
212
|
};
|
|
213
|
+
} else {
|
|
214
|
+
// Text-based comparison of Contentful documents
|
|
215
|
+
const origText = extractPlainText(origDoc);
|
|
216
|
+
const modText = extractPlainText(modDoc);
|
|
217
|
+
return renderStringDiff(origText, modText);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function renderStringDiff(orig, mod) {
|
|
222
|
+
const difference = Diff__namespace.diffWords(orig, mod);
|
|
223
|
+
const originalParts = [];
|
|
224
|
+
const modifiedParts = [];
|
|
225
|
+
for (const part of difference) {
|
|
226
|
+
if (part.removed) {
|
|
227
|
+
originalParts.push(jsxRuntime.jsx("span", {
|
|
228
|
+
className: "diff-removed",
|
|
229
|
+
children: part.value
|
|
230
|
+
}, originalParts.length));
|
|
231
|
+
} else if (part.added) {
|
|
232
|
+
modifiedParts.push(jsxRuntime.jsx("span", {
|
|
233
|
+
className: "diff-added",
|
|
234
|
+
children: part.value
|
|
235
|
+
}, modifiedParts.length));
|
|
236
|
+
} else {
|
|
237
|
+
originalParts.push(jsxRuntime.jsx("span", {
|
|
238
|
+
className: "diff-unchanged",
|
|
239
|
+
children: part.value
|
|
240
|
+
}, originalParts.length));
|
|
241
|
+
modifiedParts.push(jsxRuntime.jsx("span", {
|
|
242
|
+
className: "diff-unchanged",
|
|
243
|
+
children: part.value
|
|
244
|
+
}, modifiedParts.length));
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
originalParts,
|
|
249
|
+
modifiedParts
|
|
94
250
|
};
|
|
251
|
+
}
|
|
252
|
+
function renderArrayDiff(original, modified) {
|
|
253
|
+
const maxLength = Math.max(original.length, modified.length);
|
|
254
|
+
const originalParts = [];
|
|
255
|
+
const modifiedParts = [];
|
|
256
|
+
for (let i = 0; i < maxLength; i++) {
|
|
257
|
+
const orig = original[i] ?? '';
|
|
258
|
+
const mod = modified[i] ?? '';
|
|
259
|
+
if (orig === mod) {
|
|
260
|
+
originalParts.push(jsxRuntime.jsx("div", {
|
|
261
|
+
className: "diff-unchanged-line",
|
|
262
|
+
children: orig
|
|
263
|
+
}, `orig-${i}`));
|
|
264
|
+
modifiedParts.push(jsxRuntime.jsx("div", {
|
|
265
|
+
className: "diff-unchanged-line",
|
|
266
|
+
children: mod
|
|
267
|
+
}, `mod-${i}`));
|
|
268
|
+
} else {
|
|
269
|
+
originalParts.push(jsxRuntime.jsx("div", {
|
|
270
|
+
className: orig ? "diff-removed-line" : "diff-blank-line",
|
|
271
|
+
children: orig
|
|
272
|
+
}, `orig-${i}`));
|
|
273
|
+
modifiedParts.push(jsxRuntime.jsx("div", {
|
|
274
|
+
className: mod ? "diff-added-line" : "diff-blank-line",
|
|
275
|
+
children: mod
|
|
276
|
+
}, `mod-${i}`));
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return {
|
|
280
|
+
originalParts,
|
|
281
|
+
modifiedParts
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
const Compare = ({
|
|
285
|
+
original,
|
|
286
|
+
modified,
|
|
287
|
+
className = '',
|
|
288
|
+
viewMode = 'side-by-side',
|
|
289
|
+
caseSensitive = true,
|
|
290
|
+
compareMode = 'text'
|
|
291
|
+
}) => {
|
|
95
292
|
const isStringComparison = typeof original === 'string' && typeof modified === 'string';
|
|
96
293
|
const isArrayComparison = Array.isArray(original) && Array.isArray(modified);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
294
|
+
const isContentfulComparison = isContentfulDocument(original) && isContentfulDocument(modified);
|
|
295
|
+
const [contentfulParts, setContentfulParts] = react.useState(null);
|
|
296
|
+
react.useEffect(() => {
|
|
297
|
+
let cancelled = false;
|
|
298
|
+
if (isContentfulComparison) {
|
|
299
|
+
setContentfulParts(null); // reset while loading
|
|
300
|
+
renderContentfulDiff(original, modified, compareMode, caseSensitive, renderStringDiff).then(result => {
|
|
301
|
+
if (!cancelled) setContentfulParts(result);
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
return () => {
|
|
305
|
+
cancelled = true;
|
|
306
|
+
};
|
|
307
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
308
|
+
}, [original, modified, compareMode, caseSensitive, isContentfulComparison]);
|
|
309
|
+
let originalParts = [],
|
|
310
|
+
modifiedParts = [];
|
|
104
311
|
if (isStringComparison) {
|
|
105
312
|
({
|
|
106
313
|
originalParts,
|
|
107
314
|
modifiedParts
|
|
108
315
|
} = renderStringDiff(original, modified));
|
|
109
|
-
} else {
|
|
316
|
+
} else if (isArrayComparison) {
|
|
110
317
|
({
|
|
111
318
|
originalParts,
|
|
112
319
|
modifiedParts
|
|
113
320
|
} = renderArrayDiff(original, modified));
|
|
321
|
+
} else if (isContentfulComparison) {
|
|
322
|
+
if (contentfulParts) {
|
|
323
|
+
originalParts = contentfulParts.originalParts;
|
|
324
|
+
modifiedParts = contentfulParts.modifiedParts;
|
|
325
|
+
} else {
|
|
326
|
+
originalParts = [jsxRuntime.jsx("div", {
|
|
327
|
+
children: "Loading..."
|
|
328
|
+
}, "loading")];
|
|
329
|
+
modifiedParts = [jsxRuntime.jsx("div", {
|
|
330
|
+
children: "Loading..."
|
|
331
|
+
}, "loading")];
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (!isStringComparison && !isArrayComparison && !isContentfulComparison) {
|
|
335
|
+
return jsxRuntime.jsx("div", {
|
|
336
|
+
className: `compare-error ${className}`,
|
|
337
|
+
children: "Error: Invalid input for comparison."
|
|
338
|
+
});
|
|
114
339
|
}
|
|
115
340
|
if (viewMode === 'inline') {
|
|
116
|
-
return
|
|
341
|
+
return jsxRuntime.jsx("div", {
|
|
117
342
|
className: `compare-inline ${className}`,
|
|
118
|
-
children:
|
|
343
|
+
children: jsxRuntime.jsxs("div", {
|
|
119
344
|
className: "compare-content",
|
|
120
345
|
children: [originalParts, modifiedParts]
|
|
121
346
|
})
|
|
122
347
|
});
|
|
123
348
|
}
|
|
124
|
-
return
|
|
349
|
+
return jsxRuntime.jsxs("div", {
|
|
125
350
|
className: `compare-side-by-side ${className}`,
|
|
126
|
-
children: [
|
|
351
|
+
children: [jsxRuntime.jsxs("div", {
|
|
127
352
|
className: "compare-panel",
|
|
128
|
-
children: [
|
|
353
|
+
children: [jsxRuntime.jsx("div", {
|
|
129
354
|
className: "compare-header original-header",
|
|
130
355
|
children: "Original"
|
|
131
|
-
}),
|
|
356
|
+
}), jsxRuntime.jsx("div", {
|
|
132
357
|
className: "compare-content original-content",
|
|
133
358
|
children: originalParts
|
|
134
359
|
})]
|
|
135
|
-
}),
|
|
360
|
+
}), jsxRuntime.jsxs("div", {
|
|
136
361
|
className: "compare-panel",
|
|
137
|
-
children: [
|
|
362
|
+
children: [jsxRuntime.jsx("div", {
|
|
138
363
|
className: "compare-header modified-header",
|
|
139
364
|
children: "Modified"
|
|
140
|
-
}),
|
|
365
|
+
}), jsxRuntime.jsx("div", {
|
|
141
366
|
className: "compare-content modified-content",
|
|
142
367
|
children: modifiedParts
|
|
143
368
|
})]
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/components/Compare.tsx"],"sourcesContent":["import { diffWords, diffArrays } from 'diff';\nimport React from 'react';\n\n// Types\nexport interface CompareProps {\n original: string | string[];\n modified: string | string[];\n className?: string;\n viewMode?: 'side-by-side' | 'inline';\n caseSensitive?: boolean; // <-- Added\n}\n\nexport const Compare: React.FC<CompareProps> = ({\n original,\n modified,\n className = '',\n viewMode = 'side-by-side',\n caseSensitive = true, // <-- Default true\n}) => {\n // Handle string comparison\n const renderStringDiff = (orig: string, mod: string) => {\n const diff = diffWords(orig, mod, { ignoreCase: !caseSensitive });\n const originalParts: any[] = [];\n const modifiedParts: any[] = [];\n for (const part of diff) {\n if (part.removed) {\n originalParts.push(\n <span key={originalParts.length} className=\"diff-removed\">\n {part.value}\n </span>\n );\n } else if (part.added) {\n modifiedParts.push(\n <span key={modifiedParts.length} className=\"diff-added\">\n {part.value}\n </span>\n );\n } else {\n originalParts.push(\n <span key={originalParts.length} className=\"diff-unchanged\">\n {part.value}\n </span>\n );\n modifiedParts.push(\n <span key={modifiedParts.length} className=\"diff-unchanged\">\n {part.value}\n </span>\n );\n }\n }\n return { originalParts, modifiedParts };\n };\n\n // Handle array comparison\n const renderArrayDiff = (orig: string[], mod: string[]) => {\n let origArr = orig;\n let modArr = mod;\n if (!caseSensitive) {\n origArr = orig.map((s) => (typeof s === 'string' ? s.toLowerCase() : s));\n modArr = mod.map((s) => (typeof s === 'string' ? s.toLowerCase() : s));\n }\n const diff = diffArrays(origArr, modArr);\n const originalParts: any[] = [];\n const modifiedParts: any[] = [];\n for (const part of diff) {\n if (part.removed) {\n part.value.forEach((item: string, index: number) => {\n originalParts.push(\n <div key={`${originalParts.length}-${index}`} className=\"diff-removed-line\">\n {orig[origArr.indexOf(item, originalParts.length)] ?? item}\n </div>\n );\n });\n } else if (part.added) {\n part.value.forEach((item: string, index: number) => {\n modifiedParts.push(\n <div key={`${modifiedParts.length}-${index}`} className=\"diff-added-line\">\n {mod[modArr.indexOf(item, modifiedParts.length)] ?? item}\n </div>\n );\n });\n } else {\n part.value.forEach((item: string, index: number) => {\n originalParts.push(\n <div key={`${originalParts.length}-${index}`} className=\"diff-unchanged-line\">\n {orig[origArr.indexOf(item, originalParts.length)] ?? item}\n </div>\n );\n modifiedParts.push(\n <div key={`${modifiedParts.length}-${index}`} className=\"diff-unchanged-line\">\n {mod[modArr.indexOf(item, modifiedParts.length)] ?? item}\n </div>\n );\n });\n }\n }\n return { originalParts, modifiedParts };\n };\n\n const isStringComparison = typeof original === 'string' && typeof modified === 'string';\n const isArrayComparison = Array.isArray(original) && Array.isArray(modified);\n\n if (!isStringComparison && !isArrayComparison) {\n return (\n <div className={`compare-error ${className}`}>\n Error: Both inputs must be either strings or arrays of strings\n </div>\n );\n }\n\n let originalParts: any[], modifiedParts: any[];\n if (isStringComparison) {\n ({ originalParts, modifiedParts } = renderStringDiff(original as string, modified as string));\n } else {\n ({ originalParts, modifiedParts } = renderArrayDiff(original as string[], modified as string[]));\n }\n\n if (viewMode === 'inline') {\n return (\n <div className={`compare-inline ${className}`}>\n <div className=\"compare-content\">\n {originalParts}\n {modifiedParts}\n </div>\n </div>\n );\n }\n\n return (\n <div className={`compare-side-by-side ${className}`}>\n <div className=\"compare-panel\">\n <div className=\"compare-header original-header\">Original</div>\n <div className=\"compare-content original-content\">\n {originalParts}\n </div>\n </div>\n <div className=\"compare-panel\">\n <div className=\"compare-header modified-header\">Modified</div>\n <div className=\"compare-content modified-content\">\n {modifiedParts}\n </div>\n </div>\n </div>\n );\n};\n\nexport default Compare;"],"names":["Compare","original","modified","className","viewMode","caseSensitive","renderStringDiff","orig","mod","diff","diffWords","ignoreCase","originalParts","modifiedParts","part","removed","push","_jsx","children","value","length","added","renderArrayDiff","origArr","modArr","map","s","toLowerCase","diffArrays","forEach","item","index","indexOf","isStringComparison","isArrayComparison","Array","isArray","_jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/components/contentfulDiff.tsx","../../src/components/Compare.tsx"],"sourcesContent":["import React from 'react';\nimport { BLOCKS, Document, Block, Inline, Text } from '@contentful/rich-text-types';\n\n// Exported type guard for Contentful documents\nexport function isContentfulDocument(value: any): value is Document {\n return (\n value &&\n typeof value === 'object' &&\n value.nodeType === BLOCKS.DOCUMENT &&\n Array.isArray(value.content)\n );\n}\n\n// Extract plain text from Contentful document\nexport function extractPlainText(document: Document): string {\n const extractFromNode = (node: Block | Inline | Text): string => {\n if (node.nodeType === 'text') {\n return (node as Text).value;\n }\n if ('content' in node && node.content) {\n return node.content.map(child => extractFromNode(child)).join('');\n }\n return '';\n };\n return extractFromNode(document);\n}\n\n// Extract structured content for structure diff\nexport function extractStructuredContent(document: Document): Array<{ type: string; content: string; level?: number }> {\n const result: Array<{ type: string; content: string; level?: number }> = [];\n const extractFromNode = (node: Block | Inline | Text): void => {\n if (node.nodeType === 'text') return;\n if ('content' in node && node.content) {\n const textContent = node.content.map(child =>\n child.nodeType === 'text' ? (child as Text).value : ''\n ).join('');\n let displayType: string = node.nodeType;\n let headingLevel: number | undefined;\n switch (node.nodeType) {\n case BLOCKS.HEADING_1: displayType = 'Heading'; headingLevel = 1; break;\n case BLOCKS.HEADING_2: displayType = 'Heading'; headingLevel = 2; break;\n case BLOCKS.HEADING_3: displayType = 'Heading'; headingLevel = 3; break;\n case BLOCKS.HEADING_4: displayType = 'Heading'; headingLevel = 4; break;\n case BLOCKS.HEADING_5: displayType = 'Heading'; headingLevel = 5; break;\n case BLOCKS.HEADING_6: displayType = 'Heading'; headingLevel = 6; break;\n case BLOCKS.PARAGRAPH: displayType = 'Text'; break;\n case BLOCKS.UL_LIST: displayType = 'List'; break;\n case BLOCKS.OL_LIST: displayType = 'Numbered List'; break;\n case BLOCKS.LIST_ITEM: displayType = 'List Item'; break;\n case BLOCKS.QUOTE: displayType = 'Quote'; break;\n case BLOCKS.TABLE: displayType = 'Table'; break;\n default: displayType = node.nodeType.charAt(0).toUpperCase() + node.nodeType.slice(1);\n }\n if (textContent.trim()) {\n result.push({ type: displayType, content: textContent.trim(), level: headingLevel });\n }\n node.content.forEach(child => {\n if (child.nodeType !== 'text') extractFromNode(child);\n });\n }\n };\n if (document.content) document.content.forEach(node => extractFromNode(node));\n return result;\n}\n\n// Main Contentful diff renderer\nexport async function renderContentfulDiff(\n origDoc: Document,\n modDoc: Document,\n compareMode: 'text' | 'structure',\n caseSensitive: boolean,\n renderStringDiff: (a: string, b: string) => { originalParts: any[]; modifiedParts: any[] }\n) {\n // Dynamically import diff for Vite/ESM compatibility\n const DiffModule = await import('diff');\n const Diff = DiffModule.default ?? DiffModule;\n const { diffWords, diffArrays } = Diff;\n\n if (compareMode === 'structure') {\n const origStructure = extractStructuredContent(origDoc);\n const modStructure = extractStructuredContent(modDoc);\n\n const diff = diffArrays(\n origStructure,\n modStructure,\n {\n comparator: (a: any, b: any) =>\n a.type === b.type &&\n a.content === b.content &&\n a.level === b.level\n }\n );\n\n const originalParts: any[] = [];\n const modifiedParts: any[] = [];\n\n let origIdx = 0;\n let modIdx = 0;\n\n diff.forEach((part: any) => {\n if (part.added) {\n part.value.forEach((modItem: any, i: number) => {\n originalParts.push(\n <div key={`blank-orig-${modIdx + i}`} className=\"diff-blank-line\" />\n );\n modifiedParts.push(\n <div key={`added-mod-${modIdx + i}`} className=\"diff-added-line\">\n <span className=\"diff-structure-type\">{modItem.type}</span>\n {modItem.level && <span className=\"diff-structure-level\"> H{modItem.level}</span>}\n <span className=\"diff-structure-content\">: {modItem.content}</span>\n </div>\n );\n });\n modIdx += part.count || 0;\n } else if (part.removed) {\n part.value.forEach((origItem: any, i: number) => {\n originalParts.push(\n <div key={`removed-orig-${origIdx + i}`} className=\"diff-removed-line\">\n <span className=\"diff-structure-type\">{origItem.type}</span>\n {origItem.level && <span className=\"diff-structure-level\"> H{origItem.level}</span>}\n <span className=\"diff-structure-content\">: {origItem.content}</span>\n </div>\n );\n modifiedParts.push(\n <div key={`blank-mod-${origIdx + i}`} className=\"diff-blank-line\" />\n );\n });\n origIdx += part.count || 0;\n } else {\n part.value.forEach((item: any, i: number) => {\n originalParts.push(\n <div key={`unchanged-orig-${origIdx + i}`} className=\"diff-unchanged-line\">\n <span className=\"diff-structure-type\">{item.type}</span>\n {item.level && <span className=\"diff-structure-level\"> H{item.level}</span>}\n <span className=\"diff-structure-content\">: {item.content}</span>\n </div>\n );\n modifiedParts.push(\n <div key={`unchanged-mod-${modIdx + i}`} className=\"diff-unchanged-line\">\n <span className=\"diff-structure-type\">{item.type}</span>\n {item.level && <span className=\"diff-structure-level\"> H{item.level}</span>}\n <span className=\"diff-structure-content\">: {item.content}</span>\n </div>\n );\n });\n origIdx += part.count || 0;\n modIdx += part.count || 0;\n }\n });\n\n return { originalParts, modifiedParts };\n } else {\n // Text-based comparison of Contentful documents\n const origText = extractPlainText(origDoc);\n const modText = extractPlainText(modDoc);\n return renderStringDiff(origText, modText);\n }\n}","import React, { useEffect, useState } from 'react';\nimport { Document } from '@contentful/rich-text-types';\nimport {\n isContentfulDocument,\n renderContentfulDiff\n} from './contentfulDiff';\nimport * as Diff from 'diff';\n\nfunction renderStringDiff(orig: string, mod: string) {\n const difference = Diff.diffWords(orig, mod);\n const originalParts: any[] = [];\n const modifiedParts: any[] = [];\n for (const part of difference) {\n if (part.removed) {\n originalParts.push(\n <span key={originalParts.length} className=\"diff-removed\">\n {part.value}\n </span>\n );\n } else if (part.added) {\n modifiedParts.push(\n <span key={modifiedParts.length} className=\"diff-added\">\n {part.value}\n </span>\n );\n } else {\n originalParts.push(\n <span key={originalParts.length} className=\"diff-unchanged\">\n {part.value}\n </span>\n );\n modifiedParts.push(\n <span key={modifiedParts.length} className=\"diff-unchanged\">\n {part.value}\n </span>\n );\n }\n }\n return { originalParts, modifiedParts };\n}\n\nfunction renderArrayDiff(original: string[], modified: string[]) {\n const maxLength = Math.max(original.length, modified.length);\n const originalParts: any[] = [];\n const modifiedParts: any[] = [];\n for (let i = 0; i < maxLength; i++) {\n const orig = original[i] ?? '';\n const mod = modified[i] ?? '';\n if (orig === mod) {\n originalParts.push(\n <div key={`orig-${i}`} className=\"diff-unchanged-line\">{orig}</div>\n );\n modifiedParts.push(\n <div key={`mod-${i}`} className=\"diff-unchanged-line\">{mod}</div>\n );\n } else {\n originalParts.push(\n <div key={`orig-${i}`} className={orig ? \"diff-removed-line\" : \"diff-blank-line\"}>{orig}</div>\n );\n modifiedParts.push(\n <div key={`mod-${i}`} className={mod ? \"diff-added-line\" : \"diff-blank-line\"}>{mod}</div>\n );\n }\n }\n return { originalParts, modifiedParts };\n}\n\nexport interface CompareProps {\n original: string | string[] | Document;\n modified: string | string[] | Document;\n className?: string;\n viewMode?: 'side-by-side' | 'inline';\n caseSensitive?: boolean;\n compareMode?: 'text' | 'structure';\n}\n\nexport const Compare: React.FC<CompareProps> = ({\n original,\n modified,\n className = '',\n viewMode = 'side-by-side',\n caseSensitive = true,\n compareMode = 'text',\n}) => {\n const isStringComparison = typeof original === 'string' && typeof modified === 'string';\n const isArrayComparison = Array.isArray(original) && Array.isArray(modified);\n const isContentfulComparison = isContentfulDocument(original) && isContentfulDocument(modified);\n\n const [contentfulParts, setContentfulParts] = useState<{ originalParts: any[]; modifiedParts: any[] } | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n if (isContentfulComparison) {\n setContentfulParts(null); // reset while loading\n renderContentfulDiff(\n original as Document,\n modified as Document,\n compareMode,\n caseSensitive,\n renderStringDiff\n ).then(result => {\n if (!cancelled) setContentfulParts(result);\n });\n }\n return () => { cancelled = true; };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [original, modified, compareMode, caseSensitive, isContentfulComparison]);\n\n let originalParts: any[] = [], modifiedParts: any[] = [];\n if (isStringComparison) {\n ({ originalParts, modifiedParts } = renderStringDiff(original as string, modified as string));\n } else if (isArrayComparison) {\n ({ originalParts, modifiedParts } = renderArrayDiff(original as string[], modified as string[]));\n } else if (isContentfulComparison) {\n if (contentfulParts) {\n originalParts = contentfulParts.originalParts;\n modifiedParts = contentfulParts.modifiedParts;\n } else {\n originalParts = [<div key=\"loading\">Loading...</div>];\n modifiedParts = [<div key=\"loading\">Loading...</div>];\n }\n }\n\n if (\n !isStringComparison &&\n !isArrayComparison &&\n !isContentfulComparison\n ) {\n return (\n <div className={`compare-error ${className}`}>\n Error: Invalid input for comparison.\n </div>\n );\n }\n\n if (viewMode === 'inline') {\n return (\n <div className={`compare-inline ${className}`}>\n <div className=\"compare-content\">\n {originalParts}\n {modifiedParts}\n </div>\n </div>\n );\n }\n \n\n return (\n <div className={`compare-side-by-side ${className}`}>\n <div className=\"compare-panel\">\n <div className=\"compare-header original-header\">Original</div>\n <div className=\"compare-content original-content\">\n {originalParts}\n </div>\n </div>\n <div className=\"compare-panel\">\n <div className=\"compare-header modified-header\">Modified</div>\n <div className=\"compare-content modified-content\">\n {modifiedParts}\n </div>\n </div>\n </div>\n );\n};\n\nexport default Compare;"],"names":["isContentfulDocument","value","nodeType","BLOCKS","DOCUMENT","Array","isArray","content","extractPlainText","document","extractFromNode","node","map","child","join","extractStructuredContent","result","textContent","displayType","headingLevel","HEADING_1","HEADING_2","HEADING_3","HEADING_4","HEADING_5","HEADING_6","PARAGRAPH","UL_LIST","OL_LIST","LIST_ITEM","QUOTE","TABLE","charAt","toUpperCase","slice","trim","push","type","level","forEach","renderContentfulDiff","origDoc","modDoc","compareMode","caseSensitive","renderStringDiff","DiffModule","Diff","default","diffWords","diffArrays","origStructure","modStructure","diff","comparator","a","b","originalParts","modifiedParts","origIdx","modIdx","part","added","modItem","i","_jsx","className","_jsxs","children","count","removed","origItem","item","origText","modText","orig","mod","difference","length","renderArrayDiff","original","modified","maxLength","Math","max","Compare","viewMode","isStringComparison","isArrayComparison","isContentfulComparison","contentfulParts","setContentfulParts","useState","useEffect","cancelled","then"],"mappings":"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"}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,139 +1,345 @@
|
|
|
1
|
-
import { diffWords, diffArrays } from 'diff';
|
|
2
|
-
import 'react';
|
|
3
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { BLOCKS } from '@contentful/rich-text-types';
|
|
4
|
+
import * as Diff from 'diff';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const diff = diffWords(orig, mod, {
|
|
15
|
-
ignoreCase: !caseSensitive
|
|
16
|
-
});
|
|
17
|
-
const originalParts = [];
|
|
18
|
-
const modifiedParts = [];
|
|
19
|
-
for (const part of diff) {
|
|
20
|
-
if (part.removed) {
|
|
21
|
-
originalParts.push(/*#__PURE__*/jsx("span", {
|
|
22
|
-
className: "diff-removed",
|
|
23
|
-
children: part.value
|
|
24
|
-
}, originalParts.length));
|
|
25
|
-
} else if (part.added) {
|
|
26
|
-
modifiedParts.push(/*#__PURE__*/jsx("span", {
|
|
27
|
-
className: "diff-added",
|
|
28
|
-
children: part.value
|
|
29
|
-
}, modifiedParts.length));
|
|
30
|
-
} else {
|
|
31
|
-
originalParts.push(/*#__PURE__*/jsx("span", {
|
|
32
|
-
className: "diff-unchanged",
|
|
33
|
-
children: part.value
|
|
34
|
-
}, originalParts.length));
|
|
35
|
-
modifiedParts.push(/*#__PURE__*/jsx("span", {
|
|
36
|
-
className: "diff-unchanged",
|
|
37
|
-
children: part.value
|
|
38
|
-
}, modifiedParts.length));
|
|
39
|
-
}
|
|
6
|
+
// Exported type guard for Contentful documents
|
|
7
|
+
function isContentfulDocument(value) {
|
|
8
|
+
return value && typeof value === 'object' && value.nodeType === BLOCKS.DOCUMENT && Array.isArray(value.content);
|
|
9
|
+
}
|
|
10
|
+
// Extract plain text from Contentful document
|
|
11
|
+
function extractPlainText(document) {
|
|
12
|
+
const extractFromNode = node => {
|
|
13
|
+
if (node.nodeType === 'text') {
|
|
14
|
+
return node.value;
|
|
40
15
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
16
|
+
if ('content' in node && node.content) {
|
|
17
|
+
return node.content.map(child => extractFromNode(child)).join('');
|
|
18
|
+
}
|
|
19
|
+
return '';
|
|
45
20
|
};
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
21
|
+
return extractFromNode(document);
|
|
22
|
+
}
|
|
23
|
+
// Extract structured content for structure diff
|
|
24
|
+
function extractStructuredContent(document) {
|
|
25
|
+
const result = [];
|
|
26
|
+
const extractFromNode = node => {
|
|
27
|
+
if (node.nodeType === 'text') return;
|
|
28
|
+
if ('content' in node && node.content) {
|
|
29
|
+
const textContent = node.content.map(child => child.nodeType === 'text' ? child.value : '').join('');
|
|
30
|
+
let displayType = node.nodeType;
|
|
31
|
+
let headingLevel;
|
|
32
|
+
switch (node.nodeType) {
|
|
33
|
+
case BLOCKS.HEADING_1:
|
|
34
|
+
displayType = 'Heading';
|
|
35
|
+
headingLevel = 1;
|
|
36
|
+
break;
|
|
37
|
+
case BLOCKS.HEADING_2:
|
|
38
|
+
displayType = 'Heading';
|
|
39
|
+
headingLevel = 2;
|
|
40
|
+
break;
|
|
41
|
+
case BLOCKS.HEADING_3:
|
|
42
|
+
displayType = 'Heading';
|
|
43
|
+
headingLevel = 3;
|
|
44
|
+
break;
|
|
45
|
+
case BLOCKS.HEADING_4:
|
|
46
|
+
displayType = 'Heading';
|
|
47
|
+
headingLevel = 4;
|
|
48
|
+
break;
|
|
49
|
+
case BLOCKS.HEADING_5:
|
|
50
|
+
displayType = 'Heading';
|
|
51
|
+
headingLevel = 5;
|
|
52
|
+
break;
|
|
53
|
+
case BLOCKS.HEADING_6:
|
|
54
|
+
displayType = 'Heading';
|
|
55
|
+
headingLevel = 6;
|
|
56
|
+
break;
|
|
57
|
+
case BLOCKS.PARAGRAPH:
|
|
58
|
+
displayType = 'Text';
|
|
59
|
+
break;
|
|
60
|
+
case BLOCKS.UL_LIST:
|
|
61
|
+
displayType = 'List';
|
|
62
|
+
break;
|
|
63
|
+
case BLOCKS.OL_LIST:
|
|
64
|
+
displayType = 'Numbered List';
|
|
65
|
+
break;
|
|
66
|
+
case BLOCKS.LIST_ITEM:
|
|
67
|
+
displayType = 'List Item';
|
|
68
|
+
break;
|
|
69
|
+
case BLOCKS.QUOTE:
|
|
70
|
+
displayType = 'Quote';
|
|
71
|
+
break;
|
|
72
|
+
case BLOCKS.TABLE:
|
|
73
|
+
displayType = 'Table';
|
|
74
|
+
break;
|
|
75
|
+
default:
|
|
76
|
+
displayType = node.nodeType.charAt(0).toUpperCase() + node.nodeType.slice(1);
|
|
77
|
+
}
|
|
78
|
+
if (textContent.trim()) {
|
|
79
|
+
result.push({
|
|
80
|
+
type: displayType,
|
|
81
|
+
content: textContent.trim(),
|
|
82
|
+
level: headingLevel
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
node.content.forEach(child => {
|
|
86
|
+
if (child.nodeType !== 'text') extractFromNode(child);
|
|
87
|
+
});
|
|
54
88
|
}
|
|
55
|
-
|
|
89
|
+
};
|
|
90
|
+
if (document.content) document.content.forEach(node => extractFromNode(node));
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
// Main Contentful diff renderer
|
|
94
|
+
async function renderContentfulDiff(origDoc, modDoc, compareMode, caseSensitive, renderStringDiff) {
|
|
95
|
+
// Dynamically import diff for Vite/ESM compatibility
|
|
96
|
+
const DiffModule = await import('diff');
|
|
97
|
+
const Diff = DiffModule.default ?? DiffModule;
|
|
98
|
+
const {
|
|
99
|
+
diffWords,
|
|
100
|
+
diffArrays
|
|
101
|
+
} = Diff;
|
|
102
|
+
if (compareMode === 'structure') {
|
|
103
|
+
const origStructure = extractStructuredContent(origDoc);
|
|
104
|
+
const modStructure = extractStructuredContent(modDoc);
|
|
105
|
+
const diff = diffArrays(origStructure, modStructure, {
|
|
106
|
+
comparator: (a, b) => a.type === b.type && a.content === b.content && a.level === b.level
|
|
107
|
+
});
|
|
56
108
|
const originalParts = [];
|
|
57
109
|
const modifiedParts = [];
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
part.value.forEach((item, index) => {
|
|
68
|
-
modifiedParts.push(/*#__PURE__*/jsx("div", {
|
|
110
|
+
let origIdx = 0;
|
|
111
|
+
let modIdx = 0;
|
|
112
|
+
diff.forEach(part => {
|
|
113
|
+
if (part.added) {
|
|
114
|
+
part.value.forEach((modItem, i) => {
|
|
115
|
+
originalParts.push(jsx("div", {
|
|
116
|
+
className: "diff-blank-line"
|
|
117
|
+
}, `blank-orig-${modIdx + i}`));
|
|
118
|
+
modifiedParts.push(jsxs("div", {
|
|
69
119
|
className: "diff-added-line",
|
|
70
|
-
children:
|
|
71
|
-
|
|
120
|
+
children: [jsx("span", {
|
|
121
|
+
className: "diff-structure-type",
|
|
122
|
+
children: modItem.type
|
|
123
|
+
}), modItem.level && jsxs("span", {
|
|
124
|
+
className: "diff-structure-level",
|
|
125
|
+
children: [" H", modItem.level]
|
|
126
|
+
}), jsxs("span", {
|
|
127
|
+
className: "diff-structure-content",
|
|
128
|
+
children: [": ", modItem.content]
|
|
129
|
+
})]
|
|
130
|
+
}, `added-mod-${modIdx + i}`));
|
|
131
|
+
});
|
|
132
|
+
modIdx += part.count || 0;
|
|
133
|
+
} else if (part.removed) {
|
|
134
|
+
part.value.forEach((origItem, i) => {
|
|
135
|
+
originalParts.push(jsxs("div", {
|
|
136
|
+
className: "diff-removed-line",
|
|
137
|
+
children: [jsx("span", {
|
|
138
|
+
className: "diff-structure-type",
|
|
139
|
+
children: origItem.type
|
|
140
|
+
}), origItem.level && jsxs("span", {
|
|
141
|
+
className: "diff-structure-level",
|
|
142
|
+
children: [" H", origItem.level]
|
|
143
|
+
}), jsxs("span", {
|
|
144
|
+
className: "diff-structure-content",
|
|
145
|
+
children: [": ", origItem.content]
|
|
146
|
+
})]
|
|
147
|
+
}, `removed-orig-${origIdx + i}`));
|
|
148
|
+
modifiedParts.push(jsx("div", {
|
|
149
|
+
className: "diff-blank-line"
|
|
150
|
+
}, `blank-mod-${origIdx + i}`));
|
|
72
151
|
});
|
|
152
|
+
origIdx += part.count || 0;
|
|
73
153
|
} else {
|
|
74
|
-
part.value.forEach((item,
|
|
75
|
-
originalParts.push(
|
|
154
|
+
part.value.forEach((item, i) => {
|
|
155
|
+
originalParts.push(jsxs("div", {
|
|
76
156
|
className: "diff-unchanged-line",
|
|
77
|
-
children:
|
|
78
|
-
|
|
79
|
-
|
|
157
|
+
children: [jsx("span", {
|
|
158
|
+
className: "diff-structure-type",
|
|
159
|
+
children: item.type
|
|
160
|
+
}), item.level && jsxs("span", {
|
|
161
|
+
className: "diff-structure-level",
|
|
162
|
+
children: [" H", item.level]
|
|
163
|
+
}), jsxs("span", {
|
|
164
|
+
className: "diff-structure-content",
|
|
165
|
+
children: [": ", item.content]
|
|
166
|
+
})]
|
|
167
|
+
}, `unchanged-orig-${origIdx + i}`));
|
|
168
|
+
modifiedParts.push(jsxs("div", {
|
|
80
169
|
className: "diff-unchanged-line",
|
|
81
|
-
children:
|
|
82
|
-
|
|
170
|
+
children: [jsx("span", {
|
|
171
|
+
className: "diff-structure-type",
|
|
172
|
+
children: item.type
|
|
173
|
+
}), item.level && jsxs("span", {
|
|
174
|
+
className: "diff-structure-level",
|
|
175
|
+
children: [" H", item.level]
|
|
176
|
+
}), jsxs("span", {
|
|
177
|
+
className: "diff-structure-content",
|
|
178
|
+
children: [": ", item.content]
|
|
179
|
+
})]
|
|
180
|
+
}, `unchanged-mod-${modIdx + i}`));
|
|
83
181
|
});
|
|
182
|
+
origIdx += part.count || 0;
|
|
183
|
+
modIdx += part.count || 0;
|
|
84
184
|
}
|
|
85
|
-
}
|
|
185
|
+
});
|
|
86
186
|
return {
|
|
87
187
|
originalParts,
|
|
88
188
|
modifiedParts
|
|
89
189
|
};
|
|
190
|
+
} else {
|
|
191
|
+
// Text-based comparison of Contentful documents
|
|
192
|
+
const origText = extractPlainText(origDoc);
|
|
193
|
+
const modText = extractPlainText(modDoc);
|
|
194
|
+
return renderStringDiff(origText, modText);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function renderStringDiff(orig, mod) {
|
|
199
|
+
const difference = Diff.diffWords(orig, mod);
|
|
200
|
+
const originalParts = [];
|
|
201
|
+
const modifiedParts = [];
|
|
202
|
+
for (const part of difference) {
|
|
203
|
+
if (part.removed) {
|
|
204
|
+
originalParts.push(jsx("span", {
|
|
205
|
+
className: "diff-removed",
|
|
206
|
+
children: part.value
|
|
207
|
+
}, originalParts.length));
|
|
208
|
+
} else if (part.added) {
|
|
209
|
+
modifiedParts.push(jsx("span", {
|
|
210
|
+
className: "diff-added",
|
|
211
|
+
children: part.value
|
|
212
|
+
}, modifiedParts.length));
|
|
213
|
+
} else {
|
|
214
|
+
originalParts.push(jsx("span", {
|
|
215
|
+
className: "diff-unchanged",
|
|
216
|
+
children: part.value
|
|
217
|
+
}, originalParts.length));
|
|
218
|
+
modifiedParts.push(jsx("span", {
|
|
219
|
+
className: "diff-unchanged",
|
|
220
|
+
children: part.value
|
|
221
|
+
}, modifiedParts.length));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
originalParts,
|
|
226
|
+
modifiedParts
|
|
90
227
|
};
|
|
228
|
+
}
|
|
229
|
+
function renderArrayDiff(original, modified) {
|
|
230
|
+
const maxLength = Math.max(original.length, modified.length);
|
|
231
|
+
const originalParts = [];
|
|
232
|
+
const modifiedParts = [];
|
|
233
|
+
for (let i = 0; i < maxLength; i++) {
|
|
234
|
+
const orig = original[i] ?? '';
|
|
235
|
+
const mod = modified[i] ?? '';
|
|
236
|
+
if (orig === mod) {
|
|
237
|
+
originalParts.push(jsx("div", {
|
|
238
|
+
className: "diff-unchanged-line",
|
|
239
|
+
children: orig
|
|
240
|
+
}, `orig-${i}`));
|
|
241
|
+
modifiedParts.push(jsx("div", {
|
|
242
|
+
className: "diff-unchanged-line",
|
|
243
|
+
children: mod
|
|
244
|
+
}, `mod-${i}`));
|
|
245
|
+
} else {
|
|
246
|
+
originalParts.push(jsx("div", {
|
|
247
|
+
className: orig ? "diff-removed-line" : "diff-blank-line",
|
|
248
|
+
children: orig
|
|
249
|
+
}, `orig-${i}`));
|
|
250
|
+
modifiedParts.push(jsx("div", {
|
|
251
|
+
className: mod ? "diff-added-line" : "diff-blank-line",
|
|
252
|
+
children: mod
|
|
253
|
+
}, `mod-${i}`));
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
originalParts,
|
|
258
|
+
modifiedParts
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
const Compare = ({
|
|
262
|
+
original,
|
|
263
|
+
modified,
|
|
264
|
+
className = '',
|
|
265
|
+
viewMode = 'side-by-side',
|
|
266
|
+
caseSensitive = true,
|
|
267
|
+
compareMode = 'text'
|
|
268
|
+
}) => {
|
|
91
269
|
const isStringComparison = typeof original === 'string' && typeof modified === 'string';
|
|
92
270
|
const isArrayComparison = Array.isArray(original) && Array.isArray(modified);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
271
|
+
const isContentfulComparison = isContentfulDocument(original) && isContentfulDocument(modified);
|
|
272
|
+
const [contentfulParts, setContentfulParts] = useState(null);
|
|
273
|
+
useEffect(() => {
|
|
274
|
+
let cancelled = false;
|
|
275
|
+
if (isContentfulComparison) {
|
|
276
|
+
setContentfulParts(null); // reset while loading
|
|
277
|
+
renderContentfulDiff(original, modified, compareMode, caseSensitive, renderStringDiff).then(result => {
|
|
278
|
+
if (!cancelled) setContentfulParts(result);
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
return () => {
|
|
282
|
+
cancelled = true;
|
|
283
|
+
};
|
|
284
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
285
|
+
}, [original, modified, compareMode, caseSensitive, isContentfulComparison]);
|
|
286
|
+
let originalParts = [],
|
|
287
|
+
modifiedParts = [];
|
|
100
288
|
if (isStringComparison) {
|
|
101
289
|
({
|
|
102
290
|
originalParts,
|
|
103
291
|
modifiedParts
|
|
104
292
|
} = renderStringDiff(original, modified));
|
|
105
|
-
} else {
|
|
293
|
+
} else if (isArrayComparison) {
|
|
106
294
|
({
|
|
107
295
|
originalParts,
|
|
108
296
|
modifiedParts
|
|
109
297
|
} = renderArrayDiff(original, modified));
|
|
298
|
+
} else if (isContentfulComparison) {
|
|
299
|
+
if (contentfulParts) {
|
|
300
|
+
originalParts = contentfulParts.originalParts;
|
|
301
|
+
modifiedParts = contentfulParts.modifiedParts;
|
|
302
|
+
} else {
|
|
303
|
+
originalParts = [jsx("div", {
|
|
304
|
+
children: "Loading..."
|
|
305
|
+
}, "loading")];
|
|
306
|
+
modifiedParts = [jsx("div", {
|
|
307
|
+
children: "Loading..."
|
|
308
|
+
}, "loading")];
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (!isStringComparison && !isArrayComparison && !isContentfulComparison) {
|
|
312
|
+
return jsx("div", {
|
|
313
|
+
className: `compare-error ${className}`,
|
|
314
|
+
children: "Error: Invalid input for comparison."
|
|
315
|
+
});
|
|
110
316
|
}
|
|
111
317
|
if (viewMode === 'inline') {
|
|
112
|
-
return
|
|
318
|
+
return jsx("div", {
|
|
113
319
|
className: `compare-inline ${className}`,
|
|
114
|
-
children:
|
|
320
|
+
children: jsxs("div", {
|
|
115
321
|
className: "compare-content",
|
|
116
322
|
children: [originalParts, modifiedParts]
|
|
117
323
|
})
|
|
118
324
|
});
|
|
119
325
|
}
|
|
120
|
-
return
|
|
326
|
+
return jsxs("div", {
|
|
121
327
|
className: `compare-side-by-side ${className}`,
|
|
122
|
-
children: [
|
|
328
|
+
children: [jsxs("div", {
|
|
123
329
|
className: "compare-panel",
|
|
124
|
-
children: [
|
|
330
|
+
children: [jsx("div", {
|
|
125
331
|
className: "compare-header original-header",
|
|
126
332
|
children: "Original"
|
|
127
|
-
}),
|
|
333
|
+
}), jsx("div", {
|
|
128
334
|
className: "compare-content original-content",
|
|
129
335
|
children: originalParts
|
|
130
336
|
})]
|
|
131
|
-
}),
|
|
337
|
+
}), jsxs("div", {
|
|
132
338
|
className: "compare-panel",
|
|
133
|
-
children: [
|
|
339
|
+
children: [jsx("div", {
|
|
134
340
|
className: "compare-header modified-header",
|
|
135
341
|
children: "Modified"
|
|
136
|
-
}),
|
|
342
|
+
}), jsx("div", {
|
|
137
343
|
className: "compare-content modified-content",
|
|
138
344
|
children: modifiedParts
|
|
139
345
|
})]
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/components/Compare.tsx"],"sourcesContent":["import { diffWords, diffArrays } from 'diff';\nimport React from 'react';\n\n// Types\nexport interface CompareProps {\n original: string | string[];\n modified: string | string[];\n className?: string;\n viewMode?: 'side-by-side' | 'inline';\n caseSensitive?: boolean; // <-- Added\n}\n\nexport const Compare: React.FC<CompareProps> = ({\n original,\n modified,\n className = '',\n viewMode = 'side-by-side',\n caseSensitive = true, // <-- Default true\n}) => {\n // Handle string comparison\n const renderStringDiff = (orig: string, mod: string) => {\n const diff = diffWords(orig, mod, { ignoreCase: !caseSensitive });\n const originalParts: any[] = [];\n const modifiedParts: any[] = [];\n for (const part of diff) {\n if (part.removed) {\n originalParts.push(\n <span key={originalParts.length} className=\"diff-removed\">\n {part.value}\n </span>\n );\n } else if (part.added) {\n modifiedParts.push(\n <span key={modifiedParts.length} className=\"diff-added\">\n {part.value}\n </span>\n );\n } else {\n originalParts.push(\n <span key={originalParts.length} className=\"diff-unchanged\">\n {part.value}\n </span>\n );\n modifiedParts.push(\n <span key={modifiedParts.length} className=\"diff-unchanged\">\n {part.value}\n </span>\n );\n }\n }\n return { originalParts, modifiedParts };\n };\n\n // Handle array comparison\n const renderArrayDiff = (orig: string[], mod: string[]) => {\n let origArr = orig;\n let modArr = mod;\n if (!caseSensitive) {\n origArr = orig.map((s) => (typeof s === 'string' ? s.toLowerCase() : s));\n modArr = mod.map((s) => (typeof s === 'string' ? s.toLowerCase() : s));\n }\n const diff = diffArrays(origArr, modArr);\n const originalParts: any[] = [];\n const modifiedParts: any[] = [];\n for (const part of diff) {\n if (part.removed) {\n part.value.forEach((item: string, index: number) => {\n originalParts.push(\n <div key={`${originalParts.length}-${index}`} className=\"diff-removed-line\">\n {orig[origArr.indexOf(item, originalParts.length)] ?? item}\n </div>\n );\n });\n } else if (part.added) {\n part.value.forEach((item: string, index: number) => {\n modifiedParts.push(\n <div key={`${modifiedParts.length}-${index}`} className=\"diff-added-line\">\n {mod[modArr.indexOf(item, modifiedParts.length)] ?? item}\n </div>\n );\n });\n } else {\n part.value.forEach((item: string, index: number) => {\n originalParts.push(\n <div key={`${originalParts.length}-${index}`} className=\"diff-unchanged-line\">\n {orig[origArr.indexOf(item, originalParts.length)] ?? item}\n </div>\n );\n modifiedParts.push(\n <div key={`${modifiedParts.length}-${index}`} className=\"diff-unchanged-line\">\n {mod[modArr.indexOf(item, modifiedParts.length)] ?? item}\n </div>\n );\n });\n }\n }\n return { originalParts, modifiedParts };\n };\n\n const isStringComparison = typeof original === 'string' && typeof modified === 'string';\n const isArrayComparison = Array.isArray(original) && Array.isArray(modified);\n\n if (!isStringComparison && !isArrayComparison) {\n return (\n <div className={`compare-error ${className}`}>\n Error: Both inputs must be either strings or arrays of strings\n </div>\n );\n }\n\n let originalParts: any[], modifiedParts: any[];\n if (isStringComparison) {\n ({ originalParts, modifiedParts } = renderStringDiff(original as string, modified as string));\n } else {\n ({ originalParts, modifiedParts } = renderArrayDiff(original as string[], modified as string[]));\n }\n\n if (viewMode === 'inline') {\n return (\n <div className={`compare-inline ${className}`}>\n <div className=\"compare-content\">\n {originalParts}\n {modifiedParts}\n </div>\n </div>\n );\n }\n\n return (\n <div className={`compare-side-by-side ${className}`}>\n <div className=\"compare-panel\">\n <div className=\"compare-header original-header\">Original</div>\n <div className=\"compare-content original-content\">\n {originalParts}\n </div>\n </div>\n <div className=\"compare-panel\">\n <div className=\"compare-header modified-header\">Modified</div>\n <div className=\"compare-content modified-content\">\n {modifiedParts}\n </div>\n </div>\n </div>\n );\n};\n\nexport default Compare;"],"names":["Compare","original","modified","className","viewMode","caseSensitive","renderStringDiff","orig","mod","diff","diffWords","ignoreCase","originalParts","modifiedParts","part","removed","push","_jsx","children","value","length","added","renderArrayDiff","origArr","modArr","map","s","toLowerCase","diffArrays","forEach","item","index","indexOf","isStringComparison","isArrayComparison","Array","isArray","_jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/components/contentfulDiff.tsx","../../src/components/Compare.tsx"],"sourcesContent":["import React from 'react';\nimport { BLOCKS, Document, Block, Inline, Text } from '@contentful/rich-text-types';\n\n// Exported type guard for Contentful documents\nexport function isContentfulDocument(value: any): value is Document {\n return (\n value &&\n typeof value === 'object' &&\n value.nodeType === BLOCKS.DOCUMENT &&\n Array.isArray(value.content)\n );\n}\n\n// Extract plain text from Contentful document\nexport function extractPlainText(document: Document): string {\n const extractFromNode = (node: Block | Inline | Text): string => {\n if (node.nodeType === 'text') {\n return (node as Text).value;\n }\n if ('content' in node && node.content) {\n return node.content.map(child => extractFromNode(child)).join('');\n }\n return '';\n };\n return extractFromNode(document);\n}\n\n// Extract structured content for structure diff\nexport function extractStructuredContent(document: Document): Array<{ type: string; content: string; level?: number }> {\n const result: Array<{ type: string; content: string; level?: number }> = [];\n const extractFromNode = (node: Block | Inline | Text): void => {\n if (node.nodeType === 'text') return;\n if ('content' in node && node.content) {\n const textContent = node.content.map(child =>\n child.nodeType === 'text' ? (child as Text).value : ''\n ).join('');\n let displayType: string = node.nodeType;\n let headingLevel: number | undefined;\n switch (node.nodeType) {\n case BLOCKS.HEADING_1: displayType = 'Heading'; headingLevel = 1; break;\n case BLOCKS.HEADING_2: displayType = 'Heading'; headingLevel = 2; break;\n case BLOCKS.HEADING_3: displayType = 'Heading'; headingLevel = 3; break;\n case BLOCKS.HEADING_4: displayType = 'Heading'; headingLevel = 4; break;\n case BLOCKS.HEADING_5: displayType = 'Heading'; headingLevel = 5; break;\n case BLOCKS.HEADING_6: displayType = 'Heading'; headingLevel = 6; break;\n case BLOCKS.PARAGRAPH: displayType = 'Text'; break;\n case BLOCKS.UL_LIST: displayType = 'List'; break;\n case BLOCKS.OL_LIST: displayType = 'Numbered List'; break;\n case BLOCKS.LIST_ITEM: displayType = 'List Item'; break;\n case BLOCKS.QUOTE: displayType = 'Quote'; break;\n case BLOCKS.TABLE: displayType = 'Table'; break;\n default: displayType = node.nodeType.charAt(0).toUpperCase() + node.nodeType.slice(1);\n }\n if (textContent.trim()) {\n result.push({ type: displayType, content: textContent.trim(), level: headingLevel });\n }\n node.content.forEach(child => {\n if (child.nodeType !== 'text') extractFromNode(child);\n });\n }\n };\n if (document.content) document.content.forEach(node => extractFromNode(node));\n return result;\n}\n\n// Main Contentful diff renderer\nexport async function renderContentfulDiff(\n origDoc: Document,\n modDoc: Document,\n compareMode: 'text' | 'structure',\n caseSensitive: boolean,\n renderStringDiff: (a: string, b: string) => { originalParts: any[]; modifiedParts: any[] }\n) {\n // Dynamically import diff for Vite/ESM compatibility\n const DiffModule = await import('diff');\n const Diff = DiffModule.default ?? DiffModule;\n const { diffWords, diffArrays } = Diff;\n\n if (compareMode === 'structure') {\n const origStructure = extractStructuredContent(origDoc);\n const modStructure = extractStructuredContent(modDoc);\n\n const diff = diffArrays(\n origStructure,\n modStructure,\n {\n comparator: (a: any, b: any) =>\n a.type === b.type &&\n a.content === b.content &&\n a.level === b.level\n }\n );\n\n const originalParts: any[] = [];\n const modifiedParts: any[] = [];\n\n let origIdx = 0;\n let modIdx = 0;\n\n diff.forEach((part: any) => {\n if (part.added) {\n part.value.forEach((modItem: any, i: number) => {\n originalParts.push(\n <div key={`blank-orig-${modIdx + i}`} className=\"diff-blank-line\" />\n );\n modifiedParts.push(\n <div key={`added-mod-${modIdx + i}`} className=\"diff-added-line\">\n <span className=\"diff-structure-type\">{modItem.type}</span>\n {modItem.level && <span className=\"diff-structure-level\"> H{modItem.level}</span>}\n <span className=\"diff-structure-content\">: {modItem.content}</span>\n </div>\n );\n });\n modIdx += part.count || 0;\n } else if (part.removed) {\n part.value.forEach((origItem: any, i: number) => {\n originalParts.push(\n <div key={`removed-orig-${origIdx + i}`} className=\"diff-removed-line\">\n <span className=\"diff-structure-type\">{origItem.type}</span>\n {origItem.level && <span className=\"diff-structure-level\"> H{origItem.level}</span>}\n <span className=\"diff-structure-content\">: {origItem.content}</span>\n </div>\n );\n modifiedParts.push(\n <div key={`blank-mod-${origIdx + i}`} className=\"diff-blank-line\" />\n );\n });\n origIdx += part.count || 0;\n } else {\n part.value.forEach((item: any, i: number) => {\n originalParts.push(\n <div key={`unchanged-orig-${origIdx + i}`} className=\"diff-unchanged-line\">\n <span className=\"diff-structure-type\">{item.type}</span>\n {item.level && <span className=\"diff-structure-level\"> H{item.level}</span>}\n <span className=\"diff-structure-content\">: {item.content}</span>\n </div>\n );\n modifiedParts.push(\n <div key={`unchanged-mod-${modIdx + i}`} className=\"diff-unchanged-line\">\n <span className=\"diff-structure-type\">{item.type}</span>\n {item.level && <span className=\"diff-structure-level\"> H{item.level}</span>}\n <span className=\"diff-structure-content\">: {item.content}</span>\n </div>\n );\n });\n origIdx += part.count || 0;\n modIdx += part.count || 0;\n }\n });\n\n return { originalParts, modifiedParts };\n } else {\n // Text-based comparison of Contentful documents\n const origText = extractPlainText(origDoc);\n const modText = extractPlainText(modDoc);\n return renderStringDiff(origText, modText);\n }\n}","import React, { useEffect, useState } from 'react';\nimport { Document } from '@contentful/rich-text-types';\nimport {\n isContentfulDocument,\n renderContentfulDiff\n} from './contentfulDiff';\nimport * as Diff from 'diff';\n\nfunction renderStringDiff(orig: string, mod: string) {\n const difference = Diff.diffWords(orig, mod);\n const originalParts: any[] = [];\n const modifiedParts: any[] = [];\n for (const part of difference) {\n if (part.removed) {\n originalParts.push(\n <span key={originalParts.length} className=\"diff-removed\">\n {part.value}\n </span>\n );\n } else if (part.added) {\n modifiedParts.push(\n <span key={modifiedParts.length} className=\"diff-added\">\n {part.value}\n </span>\n );\n } else {\n originalParts.push(\n <span key={originalParts.length} className=\"diff-unchanged\">\n {part.value}\n </span>\n );\n modifiedParts.push(\n <span key={modifiedParts.length} className=\"diff-unchanged\">\n {part.value}\n </span>\n );\n }\n }\n return { originalParts, modifiedParts };\n}\n\nfunction renderArrayDiff(original: string[], modified: string[]) {\n const maxLength = Math.max(original.length, modified.length);\n const originalParts: any[] = [];\n const modifiedParts: any[] = [];\n for (let i = 0; i < maxLength; i++) {\n const orig = original[i] ?? '';\n const mod = modified[i] ?? '';\n if (orig === mod) {\n originalParts.push(\n <div key={`orig-${i}`} className=\"diff-unchanged-line\">{orig}</div>\n );\n modifiedParts.push(\n <div key={`mod-${i}`} className=\"diff-unchanged-line\">{mod}</div>\n );\n } else {\n originalParts.push(\n <div key={`orig-${i}`} className={orig ? \"diff-removed-line\" : \"diff-blank-line\"}>{orig}</div>\n );\n modifiedParts.push(\n <div key={`mod-${i}`} className={mod ? \"diff-added-line\" : \"diff-blank-line\"}>{mod}</div>\n );\n }\n }\n return { originalParts, modifiedParts };\n}\n\nexport interface CompareProps {\n original: string | string[] | Document;\n modified: string | string[] | Document;\n className?: string;\n viewMode?: 'side-by-side' | 'inline';\n caseSensitive?: boolean;\n compareMode?: 'text' | 'structure';\n}\n\nexport const Compare: React.FC<CompareProps> = ({\n original,\n modified,\n className = '',\n viewMode = 'side-by-side',\n caseSensitive = true,\n compareMode = 'text',\n}) => {\n const isStringComparison = typeof original === 'string' && typeof modified === 'string';\n const isArrayComparison = Array.isArray(original) && Array.isArray(modified);\n const isContentfulComparison = isContentfulDocument(original) && isContentfulDocument(modified);\n\n const [contentfulParts, setContentfulParts] = useState<{ originalParts: any[]; modifiedParts: any[] } | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n if (isContentfulComparison) {\n setContentfulParts(null); // reset while loading\n renderContentfulDiff(\n original as Document,\n modified as Document,\n compareMode,\n caseSensitive,\n renderStringDiff\n ).then(result => {\n if (!cancelled) setContentfulParts(result);\n });\n }\n return () => { cancelled = true; };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [original, modified, compareMode, caseSensitive, isContentfulComparison]);\n\n let originalParts: any[] = [], modifiedParts: any[] = [];\n if (isStringComparison) {\n ({ originalParts, modifiedParts } = renderStringDiff(original as string, modified as string));\n } else if (isArrayComparison) {\n ({ originalParts, modifiedParts } = renderArrayDiff(original as string[], modified as string[]));\n } else if (isContentfulComparison) {\n if (contentfulParts) {\n originalParts = contentfulParts.originalParts;\n modifiedParts = contentfulParts.modifiedParts;\n } else {\n originalParts = [<div key=\"loading\">Loading...</div>];\n modifiedParts = [<div key=\"loading\">Loading...</div>];\n }\n }\n\n if (\n !isStringComparison &&\n !isArrayComparison &&\n !isContentfulComparison\n ) {\n return (\n <div className={`compare-error ${className}`}>\n Error: Invalid input for comparison.\n </div>\n );\n }\n\n if (viewMode === 'inline') {\n return (\n <div className={`compare-inline ${className}`}>\n <div className=\"compare-content\">\n {originalParts}\n {modifiedParts}\n </div>\n </div>\n );\n }\n \n\n return (\n <div className={`compare-side-by-side ${className}`}>\n <div className=\"compare-panel\">\n <div className=\"compare-header original-header\">Original</div>\n <div className=\"compare-content original-content\">\n {originalParts}\n </div>\n </div>\n <div className=\"compare-panel\">\n <div className=\"compare-header modified-header\">Modified</div>\n <div className=\"compare-content modified-content\">\n {modifiedParts}\n </div>\n </div>\n </div>\n );\n};\n\nexport default Compare;"],"names":["isContentfulDocument","value","nodeType","BLOCKS","DOCUMENT","Array","isArray","content","extractPlainText","document","extractFromNode","node","map","child","join","extractStructuredContent","result","textContent","displayType","headingLevel","HEADING_1","HEADING_2","HEADING_3","HEADING_4","HEADING_5","HEADING_6","PARAGRAPH","UL_LIST","OL_LIST","LIST_ITEM","QUOTE","TABLE","charAt","toUpperCase","slice","trim","push","type","level","forEach","renderContentfulDiff","origDoc","modDoc","compareMode","caseSensitive","renderStringDiff","DiffModule","Diff","default","diffWords","diffArrays","origStructure","modStructure","diff","comparator","a","b","originalParts","modifiedParts","origIdx","modIdx","part","added","modItem","i","_jsx","className","_jsxs","children","count","removed","origItem","item","origText","modText","orig","mod","difference","length","renderArrayDiff","original","modified","maxLength","Math","max","Compare","viewMode","isStringComparison","isArrayComparison","isContentfulComparison","contentfulParts","setContentfulParts","useState","useEffect","cancelled","then"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { Document } from '@contentful/rich-text-types';
|
|
2
3
|
|
|
3
4
|
interface CompareProps {
|
|
4
|
-
original: string | string[];
|
|
5
|
-
modified: string | string[];
|
|
5
|
+
original: string | string[] | Document;
|
|
6
|
+
modified: string | string[] | Document;
|
|
6
7
|
className?: string;
|
|
7
8
|
viewMode?: 'side-by-side' | 'inline';
|
|
8
9
|
caseSensitive?: boolean;
|
|
10
|
+
compareMode?: 'text' | 'structure';
|
|
9
11
|
}
|
|
10
12
|
declare const Compare: React.FC<CompareProps>;
|
|
11
13
|
|
package/dist/styles.css
CHANGED
|
@@ -119,6 +119,48 @@
|
|
|
119
119
|
font-weight: 500;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
/* Contentful document comparison styles */
|
|
123
|
+
.diff-structure-type {
|
|
124
|
+
font-weight: bold;
|
|
125
|
+
color: #4a5568;
|
|
126
|
+
font-size: 0.875rem;
|
|
127
|
+
text-transform: uppercase;
|
|
128
|
+
letter-spacing: 0.05em;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.diff-structure-level {
|
|
132
|
+
color: #718096;
|
|
133
|
+
font-size: 0.75rem;
|
|
134
|
+
margin-left: 0.25rem;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.diff-structure-content {
|
|
138
|
+
margin-left: 0.5rem;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.diff-removed-line .diff-structure-type {
|
|
142
|
+
color: #c53030;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.diff-added-line .diff-structure-type {
|
|
146
|
+
color: #38a169;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.diff-unchanged-line .diff-structure-type {
|
|
150
|
+
color: #4a5568;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* Enhanced styles for Contentful content */
|
|
154
|
+
.compare-content .diff-structure-type {
|
|
155
|
+
display: inline-block;
|
|
156
|
+
min-width: 80px;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.compare-content .diff-structure-level {
|
|
160
|
+
display: inline-block;
|
|
161
|
+
min-width: 20px;
|
|
162
|
+
}
|
|
163
|
+
|
|
122
164
|
/* Responsive design */
|
|
123
165
|
@media (max-width: 768px) {
|
|
124
166
|
.compare-side-by-side {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crashbytes/react-version-compare",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "A React component for comparing strings and arrays with precise word-level and item-level highlighting of differences.",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"scripts": {
|
|
16
16
|
"build": "rollup -c && cp src/styles/Compare.css dist/styles.css",
|
|
17
17
|
"dev": "rollup -c -w",
|
|
18
|
-
"test": "jest",
|
|
18
|
+
"test": "jest --no-coverage",
|
|
19
|
+
"test:coverage": "jest --coverage",
|
|
19
20
|
"test:watch": "jest --watch",
|
|
20
21
|
"clean": "rm -rf dist",
|
|
21
22
|
"prepublishOnly": "npm run clean && npm run build",
|
|
@@ -55,6 +56,7 @@
|
|
|
55
56
|
"react-dom": ">=16.8.0"
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
59
|
+
"@contentful/rich-text-types": "^17.0.1",
|
|
58
60
|
"diff": "^8.0.1",
|
|
59
61
|
"tslib": "^2.8.1"
|
|
60
62
|
},
|