@vonaffenfels/slate-editor 1.1.28 → 1.1.31
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/dist/BlockEditor.js +4 -4
- package/dist/Renderer.js +1 -1
- package/dist/index.js +4 -4
- package/package.json +2 -2
- package/src/SidebarEditor/Fields/CloudinaryContentSelect.js +90 -0
- package/src/SidebarEditor/Fields/ColorPicker.js +90 -0
- package/src/SidebarEditor/Fields/ContentfulContentSelect.js +62 -0
- package/src/SidebarEditor/Fields/MVP.js +68 -0
- package/src/SidebarEditor/Fields/StreamSelect.js +16 -0
- package/src/SidebarEditor/Fields/Textarea.js +22 -0
- package/src/SidebarEditor/SidebarEditorField.js +29 -234
- package/src/SidebarEditor.js +1 -17
- package/src/Toolbar/Toolbar.js +2 -0
- package/src/Translation/TranslationToolbarButton.js +1 -9
- /package/src/SidebarEditor/{Switch.js → Fields/Switch.js} +0 -0
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {IconButton} from "../SidebarEditor";
|
|
2
1
|
import {swapArrayElements} from "../helper/array";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
Asset, AssetList,
|
|
6
|
-
} from "./AssetList";
|
|
7
|
-
import {Switch} from "./Switch";
|
|
2
|
+
import {Switch} from "./Fields/Switch";
|
|
8
3
|
import {Select} from "./Fields/Select";
|
|
9
4
|
import {RemoteSelect} from "./Fields/RemoteSelect";
|
|
10
5
|
import {MultiSelect} from "./Fields/MultiSelect";
|
|
6
|
+
import {StreamSelect} from "./Fields/StreamSelect";
|
|
7
|
+
import {Textarea} from "./Fields/Textarea";
|
|
8
|
+
import {ContentfulContentSelect} from "./Fields/ContentfulContentSelect";
|
|
9
|
+
import {CloudinaryContentSelect} from "./Fields/CloudinaryContentSelect";
|
|
10
|
+
import {MVP} from "./Fields/MVP";
|
|
11
|
+
import {ColorPicker} from "./Fields/ColorPicker";
|
|
11
12
|
|
|
12
13
|
export const SidebarEditorField = ({
|
|
13
14
|
field,
|
|
@@ -60,21 +61,7 @@ export const SidebarEditorField = ({
|
|
|
60
61
|
|
|
61
62
|
switch (field?.control?.type) {
|
|
62
63
|
case "text":
|
|
63
|
-
return <
|
|
64
|
-
type="text"
|
|
65
|
-
value={value || ""}
|
|
66
|
-
onChange={e => {
|
|
67
|
-
onChange(fieldKey, e.target.value);
|
|
68
|
-
e.target.style.height = "5px";
|
|
69
|
-
e.target.style.height = e.target.scrollHeight + 2 + "px";
|
|
70
|
-
}}
|
|
71
|
-
onBlur={(e) => {
|
|
72
|
-
e.target.style.height = "42px";
|
|
73
|
-
}}
|
|
74
|
-
onFocus={e => {
|
|
75
|
-
e.target.style.height = "5px";
|
|
76
|
-
e.target.style.height = e.target.scrollHeight + 2 + "px";
|
|
77
|
-
}}/>;
|
|
64
|
+
return <Textarea onChange={e => onChange(fieldKey, e.target.value)} value={value} />;
|
|
78
65
|
case "boolean":
|
|
79
66
|
return (
|
|
80
67
|
<div className="flex items-center">
|
|
@@ -90,16 +77,7 @@ export const SidebarEditorField = ({
|
|
|
90
77
|
case "remote-select":
|
|
91
78
|
return <RemoteSelect onChange={e => onChange(fieldKey, e.target.value)} field={field} value={value} />;
|
|
92
79
|
case "data-stream":
|
|
93
|
-
return (
|
|
94
|
-
<select
|
|
95
|
-
value={value || ""}
|
|
96
|
-
onChange={e => onChange(fieldKey, e.target.value)}>
|
|
97
|
-
<option value="">Auswählen</option>
|
|
98
|
-
{(field?.control?.streams || []).map(stream => (
|
|
99
|
-
<option key={`select-option-${stream.value}`} value={`$$_STREAM__${stream.value}__`}>{stream.label}</option>
|
|
100
|
-
))}
|
|
101
|
-
</select>
|
|
102
|
-
);
|
|
80
|
+
return <StreamSelect onChange={e => onChange(fieldKey, e.target.value)} field={field} value={value} />;
|
|
103
81
|
case "number":
|
|
104
82
|
return (
|
|
105
83
|
<input
|
|
@@ -118,22 +96,7 @@ export const SidebarEditorField = ({
|
|
|
118
96
|
onChange={e => onChange(fieldKey, Number(e.target.value))}/>
|
|
119
97
|
);
|
|
120
98
|
case "object":
|
|
121
|
-
return (
|
|
122
|
-
<textarea
|
|
123
|
-
value={typeof value === "object" ? JSON.stringify(value, null, 2) || "" : value}
|
|
124
|
-
onChange={e => {
|
|
125
|
-
onChange(fieldKey, isJson(e.target.value) ? JSON.parse(e.target.value) : e.target.value);
|
|
126
|
-
e.target.style.height = "5px";
|
|
127
|
-
e.target.style.height = e.target.scrollHeight + 2 + "px";
|
|
128
|
-
}}
|
|
129
|
-
onBlur={(e) => {
|
|
130
|
-
e.target.style.height = "42px";
|
|
131
|
-
}}
|
|
132
|
-
onFocus={e => {
|
|
133
|
-
e.target.style.height = "5px";
|
|
134
|
-
e.target.style.height = e.target.scrollHeight + 2 + "px";
|
|
135
|
-
}}/>
|
|
136
|
-
);
|
|
99
|
+
return <Textarea onChange={e => onChange(fieldKey, isJson(e.target.value) ? JSON.parse(e.target.value) : e.target.value)} />;
|
|
137
100
|
case "radio":
|
|
138
101
|
return (
|
|
139
102
|
<div>
|
|
@@ -210,15 +173,7 @@ export const SidebarEditorField = ({
|
|
|
210
173
|
);
|
|
211
174
|
case "color":
|
|
212
175
|
return (
|
|
213
|
-
<
|
|
214
|
-
<input
|
|
215
|
-
type="color"
|
|
216
|
-
value={value || ""}
|
|
217
|
-
onChange={e => onChange(fieldKey, e.target.value)}/>
|
|
218
|
-
{!!value && (
|
|
219
|
-
<button className="button button--tertiary mt-1" onClick={() => onChange(fieldKey, undefined)}>Zurücksetzen</button>
|
|
220
|
-
)}
|
|
221
|
-
</div>
|
|
176
|
+
<ColorPicker value={value} onChange={c => onChange(fieldKey, c)} />
|
|
222
177
|
);
|
|
223
178
|
case "date":
|
|
224
179
|
return (
|
|
@@ -244,188 +199,28 @@ export const SidebarEditorField = ({
|
|
|
244
199
|
onChange(fieldKey, v);
|
|
245
200
|
}} />;
|
|
246
201
|
case "contentful-content":
|
|
247
|
-
return (
|
|
248
|
-
<>
|
|
249
|
-
{!!value && <div className="mb-2"><Asset
|
|
250
|
-
sdk={sdk}
|
|
251
|
-
asset={value}
|
|
252
|
-
onDeleteClick={() => onChange(fieldKey, null)}
|
|
253
|
-
onChange={v => onChange(fieldKey, v)}/></div>}
|
|
254
|
-
<button
|
|
255
|
-
className="button"
|
|
256
|
-
onClick={() => {
|
|
257
|
-
sdk.dialogs.selectSingleEntry({contentTypes: field.control.contentTypes}).then(content => {
|
|
258
|
-
onChange(fieldKey, reduceContentfulResponse(content, field.control.paths));
|
|
259
|
-
});
|
|
260
|
-
}}
|
|
261
|
-
>Auswählen
|
|
262
|
-
</button>
|
|
263
|
-
</>
|
|
264
|
-
);
|
|
202
|
+
return <ContentfulContentSelect value={value} onChange={v => onChange(fieldKey, v)} field={field} sdk={sdk} />;
|
|
265
203
|
case "contentful-contents":
|
|
266
|
-
return (
|
|
267
|
-
<>
|
|
268
|
-
{value && value.length > 0 && (
|
|
269
|
-
<details className="mb-2">
|
|
270
|
-
<summary>{value.length || 0} {value.length === 1 ? "Element" : "Elemente"}</summary>
|
|
271
|
-
<div className="mt-4">
|
|
272
|
-
<AssetList
|
|
273
|
-
assets={value}
|
|
274
|
-
sdk={sdk}
|
|
275
|
-
onChange={v => onChange(fieldKey, v)}
|
|
276
|
-
onAddClick={() => {
|
|
277
|
-
sdk.dialogs.selectMultipleEntries({contentTypes: field.control.contentTypes}).then(contents => {
|
|
278
|
-
onChange(fieldKey, reduceContentfulResponse([...value, ...contents], field.control.paths));
|
|
279
|
-
});
|
|
280
|
-
}}/>
|
|
281
|
-
</div>
|
|
282
|
-
</details>
|
|
283
|
-
)}
|
|
284
|
-
<button
|
|
285
|
-
className="button"
|
|
286
|
-
onClick={() => {
|
|
287
|
-
sdk.dialogs.selectMultipleEntries({contentTypes: field.control.contentTypes}).then(contents => {
|
|
288
|
-
onChange(fieldKey, reduceContentfulResponse(contents, field.control.paths));
|
|
289
|
-
});
|
|
290
|
-
}}
|
|
291
|
-
>Auswählen
|
|
292
|
-
</button>
|
|
293
|
-
</>
|
|
294
|
-
);
|
|
204
|
+
return <ContentfulContentSelect value={value} onChange={v => onChange(fieldKey, v)} field={field} sdk={sdk} multiple />;
|
|
295
205
|
case "cloudinary-image":
|
|
296
|
-
return (
|
|
297
|
-
<>
|
|
298
|
-
{!!value && <div className="mb-2"><Asset
|
|
299
|
-
cloudinary
|
|
300
|
-
sdk={sdk}
|
|
301
|
-
asset={value}
|
|
302
|
-
onDeleteClick={() => onChange(fieldKey, null)}/></div>}
|
|
303
|
-
<button
|
|
304
|
-
className="button"
|
|
305
|
-
onClick={() => {
|
|
306
|
-
sdk.dialogs.openCurrentApp({
|
|
307
|
-
width: "fullWidth",
|
|
308
|
-
title: "Select Image",
|
|
309
|
-
shouldCloseOnOverlayClick: true,
|
|
310
|
-
shouldCloseOnEscapePress: true,
|
|
311
|
-
parameters: {
|
|
312
|
-
type: "cloudinary",
|
|
313
|
-
portal: sdk?.entry?.fields?.portal?.getValue(),
|
|
314
|
-
},
|
|
315
|
-
}).then((data) => {
|
|
316
|
-
onChange(fieldKey, data?.assets?.[0]);
|
|
317
|
-
});
|
|
318
|
-
}}
|
|
319
|
-
>Auswählen
|
|
320
|
-
</button>
|
|
321
|
-
</>
|
|
322
|
-
);
|
|
206
|
+
return <CloudinaryContentSelect value={value} onChange={v => onChange(fieldKey, v)} field={field} sdk={sdk} />;
|
|
323
207
|
case "cloudinary-images":
|
|
324
|
-
return (
|
|
325
|
-
<>
|
|
326
|
-
{value && value.length > 0 && (
|
|
327
|
-
<details className="mb-2">
|
|
328
|
-
<summary>{value.length || 0} {value.length === 1 ? "Element" : "Elemente"}</summary>
|
|
329
|
-
<div className="mt-4">
|
|
330
|
-
<AssetList
|
|
331
|
-
cloudinary
|
|
332
|
-
assets={value}
|
|
333
|
-
sdk={sdk}
|
|
334
|
-
onChange={v => onChange(fieldKey, v)}
|
|
335
|
-
onAddClick={() => {
|
|
336
|
-
sdk.dialogs.openCurrentApp({
|
|
337
|
-
width: "fullWidth",
|
|
338
|
-
title: "Select Images",
|
|
339
|
-
shouldCloseOnOverlayClick: true,
|
|
340
|
-
shouldCloseOnEscapePress: true,
|
|
341
|
-
parameters: {
|
|
342
|
-
type: "cloudinary",
|
|
343
|
-
multiple: true,
|
|
344
|
-
portal: sdk?.entry?.fields?.portal?.getValue(),
|
|
345
|
-
},
|
|
346
|
-
}).then((data) => {
|
|
347
|
-
onChange(fieldKey, [...value, ...(data?.assets || [])]);
|
|
348
|
-
});
|
|
349
|
-
}}/>
|
|
350
|
-
</div>
|
|
351
|
-
</details>
|
|
352
|
-
)}
|
|
353
|
-
<button
|
|
354
|
-
className="button"
|
|
355
|
-
onClick={() => {
|
|
356
|
-
sdk.dialogs.openCurrentApp({
|
|
357
|
-
width: "fullWidth",
|
|
358
|
-
title: "Select Images",
|
|
359
|
-
shouldCloseOnOverlayClick: true,
|
|
360
|
-
shouldCloseOnEscapePress: true,
|
|
361
|
-
parameters: {
|
|
362
|
-
type: "cloudinary",
|
|
363
|
-
multiple: true,
|
|
364
|
-
portal: sdk?.entry?.fields?.portal?.getValue(),
|
|
365
|
-
},
|
|
366
|
-
}).then((data) => {
|
|
367
|
-
onChange(fieldKey, data?.assets);
|
|
368
|
-
});
|
|
369
|
-
}}
|
|
370
|
-
>Auswählen
|
|
371
|
-
</button>
|
|
372
|
-
</>
|
|
373
|
-
);
|
|
208
|
+
return <CloudinaryContentSelect value={value} onChange={v => onChange(fieldKey, v)} field={field} sdk={sdk} multiple />;
|
|
374
209
|
case "mvp":
|
|
375
|
-
return
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
<IconButton
|
|
390
|
-
size="small"
|
|
391
|
-
onClick={() => handleMVPMoveClick(fieldKey, "down", index)}
|
|
392
|
-
disabled={index === storybookElement.attributes?.[fieldKey]?.length - 1}>↓</IconButton>
|
|
393
|
-
</div>
|
|
394
|
-
<IconButton
|
|
395
|
-
size="small"
|
|
396
|
-
onClick={() => deleteMVPEntry(fieldKey, index)}>🗑</IconButton>
|
|
397
|
-
</div>
|
|
398
|
-
{Object.keys(field.control.fields).map((key, mvpIndex) => {
|
|
399
|
-
let mvpField = field.control.fields[key];
|
|
400
|
-
|
|
401
|
-
value = storybookElement.attributes?.[fieldKey]?.[index]?.[key];
|
|
402
|
-
|
|
403
|
-
return (
|
|
404
|
-
<div key={`mvp-field-${key}`}>
|
|
405
|
-
<SidebarEditorField
|
|
406
|
-
field={mvpField}
|
|
407
|
-
fieldKey={fieldKey}
|
|
408
|
-
value={value}
|
|
409
|
-
storybookElement={storybookElement}
|
|
410
|
-
sdk={sdk}
|
|
411
|
-
onChange={(fK, value) => onChange(
|
|
412
|
-
fK, value, key, index,
|
|
413
|
-
)}/>
|
|
414
|
-
</div>
|
|
415
|
-
);
|
|
416
|
-
})}
|
|
417
|
-
<hr className="my-4" style={{borderColor: "rgb(174, 193, 204)"}}/>
|
|
418
|
-
</div>
|
|
419
|
-
);
|
|
420
|
-
})}
|
|
421
|
-
<button
|
|
422
|
-
className="button button--secondary"
|
|
423
|
-
onClick={() => onChange(fieldKey, [...(storybookElement.attributes[fieldKey] || []), {}])}>Neue
|
|
424
|
-
Zeile
|
|
425
|
-
</button>
|
|
426
|
-
</div>
|
|
427
|
-
</details>
|
|
428
|
-
);
|
|
210
|
+
return <MVP
|
|
211
|
+
value={value}
|
|
212
|
+
onMove={(direction, index) => handleMVPMoveClick(fieldKey, direction, index)}
|
|
213
|
+
onDelete={(index) => deleteMVPEntry(fieldKey, index)}
|
|
214
|
+
field={field}
|
|
215
|
+
onChange={(
|
|
216
|
+
fK, value, key, index,
|
|
217
|
+
) => onChange(
|
|
218
|
+
fK, value, key, index,
|
|
219
|
+
)}
|
|
220
|
+
fieldKey={fieldKey}
|
|
221
|
+
sdk={sdk}
|
|
222
|
+
storybookElement={storybookElement}
|
|
223
|
+
/>;
|
|
429
224
|
default:
|
|
430
225
|
return <div className="message message--negative">Keine Konfiguration zu Feldtyp "{field?.control?.type}"
|
|
431
226
|
gefunden</div>;
|
package/src/SidebarEditor.js
CHANGED
|
@@ -8,7 +8,7 @@ import {Spinner} from "@contentful/forma-36-react-components";
|
|
|
8
8
|
import {
|
|
9
9
|
CollapsableMenu, CollapsableMenuItem,
|
|
10
10
|
} from "./CollapsableMenu/CollapsableMenu";
|
|
11
|
-
import {Switch} from "./SidebarEditor/Switch";
|
|
11
|
+
import {Switch} from "./SidebarEditor/Fields/Switch";
|
|
12
12
|
|
|
13
13
|
const SidebarEditor = ({
|
|
14
14
|
sdk,
|
|
@@ -24,8 +24,6 @@ const SidebarEditor = ({
|
|
|
24
24
|
isLoading,
|
|
25
25
|
lastSelection,
|
|
26
26
|
}) => {
|
|
27
|
-
const portal = sdk?.entry?.fields?.portal.getValue();
|
|
28
|
-
|
|
29
27
|
const [versions, setVersions] = useState([]);
|
|
30
28
|
const [lastChangedProperty, setLastChangedProperty] = useState(null);
|
|
31
29
|
const [versionCount, setVersionCount] = useState(0);
|
|
@@ -172,20 +170,6 @@ const SidebarEditor = ({
|
|
|
172
170
|
}
|
|
173
171
|
};
|
|
174
172
|
|
|
175
|
-
const handleAutocompleteChange = (item) => {
|
|
176
|
-
if (!item) {
|
|
177
|
-
return onChange({}); // reset to empty
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// reset to the first or second story
|
|
181
|
-
onChange({
|
|
182
|
-
...storybookElement,
|
|
183
|
-
block: item.value,
|
|
184
|
-
attributes: item.attributes,
|
|
185
|
-
type: item.type,
|
|
186
|
-
});
|
|
187
|
-
};
|
|
188
|
-
|
|
189
173
|
useEffect(() => resetVersions, [storybookElement?.editorAttributes?.ref]);
|
|
190
174
|
|
|
191
175
|
const renderTitle = () => {
|
package/src/Toolbar/Toolbar.js
CHANGED
|
@@ -13,17 +13,9 @@ export const TranslationToolbarButton = ({
|
|
|
13
13
|
setLocale,
|
|
14
14
|
translateFromLocale = "de",
|
|
15
15
|
}) => {
|
|
16
|
-
const [enabled, setEnabled] = useState(false);
|
|
17
16
|
const [loading, setLoading] = useState(false);
|
|
18
17
|
const [error, setError] = useState(null);
|
|
19
|
-
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
if (sdk) {
|
|
22
|
-
if (sdk?.parameters?.installation?.usersWithTranslation?.includes(sdk?.user?.email) && sdk?.parameters?.installation?.translationService) {
|
|
23
|
-
setEnabled(true);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}, [sdk]);
|
|
18
|
+
const enabled = sdk?.parameters?.installation?.usersWithTranslation?.includes(sdk?.user?.email) && sdk?.parameters?.installation?.translationService;
|
|
27
19
|
|
|
28
20
|
if (sdk.locales.available.length < 2 || !enabled) {
|
|
29
21
|
return null;
|
|
File without changes
|