@vonaffenfels/slate-editor 1.0.28 → 1.0.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.css +1 -1
- package/dist/BlockEditor.js +1 -1
- package/dist/Renderer.js +1 -1
- package/dist/index.css +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/scss/sidebarEditor.scss +1 -1
- package/src/BlockEditor.js +21 -2
- package/src/SidebarEditor/AssetList.js +40 -8
- package/src/SidebarEditor/SidebarEditorField.js +1 -1
- package/src/SidebarEditor.js +114 -91
- package/src/dev/App.js +1 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vonaffenfels/slate-editor",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.31",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"cssnano": "^5.0.1",
|
|
72
72
|
"escape-html": "^1.0.3"
|
|
73
73
|
},
|
|
74
|
-
"gitHead": "
|
|
74
|
+
"gitHead": "007715e3b949cf0368e7b4d70626d2931c7b7829",
|
|
75
75
|
"publishConfig": {
|
|
76
76
|
"access": "public"
|
|
77
77
|
}
|
package/scss/sidebarEditor.scss
CHANGED
package/src/BlockEditor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, {
|
|
2
|
-
useCallback, useMemo, useState, useRef,
|
|
2
|
+
useCallback, useMemo, useState, useRef, useEffect,
|
|
3
3
|
} from 'react';
|
|
4
4
|
import {
|
|
5
5
|
Slate, Editable, withReact, ReactEditor,
|
|
@@ -64,6 +64,24 @@ export default function BlockEditor({
|
|
|
64
64
|
],
|
|
65
65
|
},
|
|
66
66
|
];
|
|
67
|
+
|
|
68
|
+
const [loadedStorybookStories, setLoadedStorybookStories] = useState([]);
|
|
69
|
+
const [isSidebarLoading, setIsSidebarLoading] = useState(false);
|
|
70
|
+
|
|
71
|
+
const loadStories = async () => {
|
|
72
|
+
setIsSidebarLoading(true);
|
|
73
|
+
|
|
74
|
+
let loadedStories = await storybookStories();
|
|
75
|
+
|
|
76
|
+
setIsSidebarLoading(false);
|
|
77
|
+
|
|
78
|
+
setLoadedStorybookStories(loadedStories);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
loadStories();
|
|
83
|
+
}, []);
|
|
84
|
+
|
|
67
85
|
const resetEditor = () => {
|
|
68
86
|
if (confirm("This action will delete all data in the editor, are you sure?")) {
|
|
69
87
|
onChange(emptyValue);
|
|
@@ -269,7 +287,8 @@ export default function BlockEditor({
|
|
|
269
287
|
sdk={contentfulSdk}
|
|
270
288
|
storybookElement={selectedStorybookElement}
|
|
271
289
|
onChange={handleSidebarEditorChange}
|
|
272
|
-
storybookStories={
|
|
290
|
+
storybookStories={loadedStorybookStories}
|
|
291
|
+
isLoading={isSidebarLoading}
|
|
273
292
|
onClose={handleSidebarClose}
|
|
274
293
|
onDelete={handleSidebarDeleteClick}
|
|
275
294
|
onMove={handleSidebarMoveClick}
|
|
@@ -23,6 +23,7 @@ export const AssetList = ({
|
|
|
23
23
|
assetsLength={assets.length}
|
|
24
24
|
onMoveClick={(direction) => handleMoveClick(direction, index)}
|
|
25
25
|
onDeleteClick={() => handleDeleteClick(index)}
|
|
26
|
+
onChange={handleChange}
|
|
26
27
|
/>
|
|
27
28
|
<hr className="my-2" style={{borderColor: "#cfd9e0"}}/>
|
|
28
29
|
{onAddClick && index === assets.length - 1 && <button onClick={onAddClick} className="button--secondary">Hinzufügen</button>}
|
|
@@ -49,6 +50,24 @@ export const AssetList = ({
|
|
|
49
50
|
onChange(newAssets);
|
|
50
51
|
};
|
|
51
52
|
|
|
53
|
+
const handleChange = (newAsset) => {
|
|
54
|
+
let newAssets = assets.map(asset => {
|
|
55
|
+
if (asset?.sys?.id === newAsset?.sys?.id) {
|
|
56
|
+
return newAsset;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return asset;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
console.log({
|
|
63
|
+
newAssets,
|
|
64
|
+
newAsset,
|
|
65
|
+
assets,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
onChange(newAssets);
|
|
69
|
+
};
|
|
70
|
+
|
|
52
71
|
return (
|
|
53
72
|
<div>{renderAssets}</div>
|
|
54
73
|
);
|
|
@@ -60,21 +79,18 @@ export const Asset = ({
|
|
|
60
79
|
assetsLength,
|
|
61
80
|
onDeleteClick,
|
|
62
81
|
onMoveClick,
|
|
82
|
+
onChange,
|
|
63
83
|
sdk,
|
|
64
84
|
cloudinary = false,
|
|
65
85
|
}) => {
|
|
66
86
|
const [mediaUrl, setMediaUrl] = useState(null);
|
|
67
87
|
|
|
68
88
|
let id = asset?.sys?.id;
|
|
69
|
-
let title = asset?.fields?.title?.["en-US"] || asset?.fields?.title?.["de"] || asset?.fields?.title?.toString();
|
|
70
|
-
let space = asset?.sys?.space?.sys?.id;
|
|
71
|
-
let environment = asset?.sys?.environment?.sys?.id;
|
|
89
|
+
let title = asset?.fields?.title?.["en-US"] || asset?.fields?.title?.["de"] || asset?.fields?.title?.toString() || asset?.title?.toString();
|
|
72
90
|
let mediaAssetId = asset?.fields?.media?.["en-US"]?.sys?.id || asset?.fields?.media?.["de"]?.sys?.id || asset?.fields?.media?.sys?.id;
|
|
73
|
-
let href = `https://app.contentful.com/spaces/${space}/environments/${environment}/entries/${id}`;
|
|
74
91
|
|
|
75
92
|
if (cloudinary) {
|
|
76
93
|
title = asset.public_id;
|
|
77
|
-
href = asset.url;
|
|
78
94
|
}
|
|
79
95
|
|
|
80
96
|
useEffect(() => {
|
|
@@ -85,6 +101,15 @@ export const Asset = ({
|
|
|
85
101
|
}
|
|
86
102
|
|
|
87
103
|
if (!mediaAssetId) {
|
|
104
|
+
if (asset?.media?.url) {
|
|
105
|
+
let params = new URLSearchParams({
|
|
106
|
+
w: "512",
|
|
107
|
+
q: "80",
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
setMediaUrl(`${asset?.media?.url}?${params}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
88
113
|
return;
|
|
89
114
|
}
|
|
90
115
|
|
|
@@ -136,9 +161,16 @@ export const Asset = ({
|
|
|
136
161
|
<IconButton size="small" onClick={() => onMoveClick("down")} disabled={index === assetsLength - 1}>↓</IconButton>
|
|
137
162
|
</div>
|
|
138
163
|
)}
|
|
139
|
-
<
|
|
140
|
-
|
|
141
|
-
|
|
164
|
+
<IconButton
|
|
165
|
+
size="small"
|
|
166
|
+
className="mr-1"
|
|
167
|
+
onClick={() => {
|
|
168
|
+
sdk.navigator.openEntry(id, {slideIn: {waitForClose: true}}).then(({entity}) => {
|
|
169
|
+
if (onChange) {
|
|
170
|
+
onChange(entity);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}}>✎</IconButton>
|
|
142
174
|
<IconButton size="small" onClick={onDeleteClick}>⨯</IconButton>
|
|
143
175
|
</div>
|
|
144
176
|
</div>
|
|
@@ -219,7 +219,7 @@ export const SidebarEditorField = ({
|
|
|
219
219
|
case "contentful-content":
|
|
220
220
|
return (
|
|
221
221
|
<>
|
|
222
|
-
{!!value && <div className="mb-2"><Asset sdk={sdk} asset={value} onDeleteClick={() => onChange(fieldKey, null)} /></div>}
|
|
222
|
+
{!!value && <div className="mb-2"><Asset sdk={sdk} asset={value} onDeleteClick={() => onChange(fieldKey, null)} onChange={v => onChange(fieldKey, v)} /></div>}
|
|
223
223
|
<button
|
|
224
224
|
onClick={() => {
|
|
225
225
|
sdk.dialogs.selectSingleEntry({contentTypes: field.control.contentTypes}).then(content => {
|
package/src/SidebarEditor.js
CHANGED
|
@@ -5,6 +5,10 @@ import {SidebarEditorField} from "./SidebarEditor/SidebarEditorField";
|
|
|
5
5
|
import {ToolMargin} from "./Tools/Margin";
|
|
6
6
|
|
|
7
7
|
import "../scss/sidebarEditor.scss";
|
|
8
|
+
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
|
9
|
+
import {faSpinner} from "@fortawesome/free-solid-svg-icons";
|
|
10
|
+
|
|
11
|
+
const devMode = localStorage.getItem("dev-mode") === "true";
|
|
8
12
|
|
|
9
13
|
const SidebarEditor = ({
|
|
10
14
|
sdk,
|
|
@@ -15,6 +19,7 @@ const SidebarEditor = ({
|
|
|
15
19
|
onDelete,
|
|
16
20
|
onMove,
|
|
17
21
|
editor,
|
|
22
|
+
isLoading,
|
|
18
23
|
}) => {
|
|
19
24
|
const [versions, setVersions] = useState([]);
|
|
20
25
|
const [lastChangedProperty, setLastChangedProperty] = useState(null);
|
|
@@ -26,7 +31,7 @@ const SidebarEditor = ({
|
|
|
26
31
|
tables: {},
|
|
27
32
|
};
|
|
28
33
|
|
|
29
|
-
const story = storybookStories?.find(v => storybookElement.block === v.id);
|
|
34
|
+
const story = storybookStories?.find(v => storybookElement.block?.toLowerCase() === v.id?.toLowerCase());
|
|
30
35
|
|
|
31
36
|
if (story) {
|
|
32
37
|
Object.keys(story.argTypes).forEach(key => {
|
|
@@ -165,99 +170,111 @@ const SidebarEditor = ({
|
|
|
165
170
|
|
|
166
171
|
return (
|
|
167
172
|
<div id="sidebar-editor">
|
|
168
|
-
|
|
169
|
-
<div className="flex items-center justify-
|
|
170
|
-
<
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
<
|
|
173
|
+
{isLoading ? (
|
|
174
|
+
<div className="flex h-full items-center justify-center">
|
|
175
|
+
<FontAwesomeIcon icon={faSpinner} pulse />
|
|
176
|
+
</div>
|
|
177
|
+
) : (
|
|
178
|
+
<>
|
|
179
|
+
<div>
|
|
180
|
+
<div className="flex items-center justify-end">
|
|
181
|
+
<div className="grow">
|
|
182
|
+
{storybookElement?.block && (
|
|
183
|
+
<div className="flex items-center">
|
|
184
|
+
<div className="icon-button-group mr-1">
|
|
185
|
+
<IconButton title="Rückgängig" onClick={undo} disabled={currentVersion <= 1}>↺</IconButton>
|
|
186
|
+
<IconButton title="Wiederherstellen" onClick={redo} disabled={currentVersion >= versionCount || versionCount === 0}>↻</IconButton>
|
|
187
|
+
</div>
|
|
188
|
+
<div className="icon-button-group mr-1">
|
|
189
|
+
<IconButton title="Nach oben verschieben" onClick={() => onMove && onMove(storybookElement, "up")} disabled={storybookElement.path[0] === 0}>
|
|
179
190
|
↑
|
|
180
|
-
|
|
181
|
-
|
|
191
|
+
</IconButton>
|
|
192
|
+
<IconButton title="Nach unten verschieben" onClick={() => onMove && onMove(storybookElement, "down")} disabled={storybookElement.path[0] === editor.children.length - 1}>
|
|
182
193
|
↓
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
194
|
+
</IconButton>
|
|
195
|
+
</div>
|
|
196
|
+
<IconButton title="Löschen" onClick={() => onDelete && onDelete(storybookElement)}>
|
|
186
197
|
🗑
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
198
|
+
</IconButton>
|
|
199
|
+
<div className="ml-1 flex items-center">
|
|
200
|
+
<ToolMargin
|
|
201
|
+
margin={storybookElement.attributes.margin}
|
|
202
|
+
onChange={value => handleFieldValueChange("margin", value)} />
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
)}
|
|
193
206
|
</div>
|
|
194
|
-
|
|
207
|
+
{!!onClose && <IconButton onClick={onClose} title="Schließen">⨯</IconButton>}
|
|
208
|
+
</div>
|
|
209
|
+
<hr className="mt-2" style={{borderColor: "#cfd9e0"}}/>
|
|
195
210
|
</div>
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
</div>
|
|
204
|
-
{storybookElement?.block && (
|
|
205
|
-
<div>
|
|
206
|
-
<div className="mb-2 grid grid-flow-col grid-cols-2 gap-2">
|
|
207
|
-
<VariantSelect className="w-full" story={story} onChange={handleVariantSelectChange} />
|
|
208
|
-
<BlockWidthSelect className="w-full" value={storybookElement.attributes.blockWidth} onChange={e => handleFieldValueChange("blockWidth", e.target.value)} />
|
|
211
|
+
<div className="grow overflow-y-auto pr-2 pt-2">
|
|
212
|
+
<div className="mb-2">
|
|
213
|
+
<BlockSelect
|
|
214
|
+
stories={storybookStories}
|
|
215
|
+
active={storybookElement}
|
|
216
|
+
onChange={handleBlockSelectChange}
|
|
217
|
+
storyContext={sdk.parameters.instance.storyContext} />
|
|
209
218
|
</div>
|
|
210
|
-
|
|
219
|
+
{storybookElement?.block && (
|
|
220
|
+
<div>
|
|
221
|
+
<div className="mb-2 grid grid-flow-col grid-cols-2 gap-2">
|
|
222
|
+
<VariantSelect className="w-full" story={story} onChange={handleVariantSelectChange} />
|
|
223
|
+
<BlockWidthSelect className="w-full" value={storybookElement.attributes.blockWidth} onChange={e => handleFieldValueChange("blockWidth", e.target.value)} />
|
|
224
|
+
</div>
|
|
225
|
+
<hr className="my-4" style={{borderColor: "#cfd9e0"}}/>
|
|
226
|
+
</div>
|
|
227
|
+
)}
|
|
228
|
+
{!!story && (
|
|
229
|
+
<>
|
|
230
|
+
{Object.keys(fields.fields).map(key => {
|
|
231
|
+
const field = fields.fields[key];
|
|
232
|
+
|
|
233
|
+
return <SidebarEditorField
|
|
234
|
+
sdk={sdk}
|
|
235
|
+
value={storybookElement?.attributes?.[key]}
|
|
236
|
+
key={key}
|
|
237
|
+
storybookElement={storybookElement}
|
|
238
|
+
fieldKey={key}
|
|
239
|
+
field={field}
|
|
240
|
+
onChange={(
|
|
241
|
+
key, value, mvpField, mvpIndex,
|
|
242
|
+
) => handleFieldValueChange(
|
|
243
|
+
key, value, mvpField, mvpIndex,
|
|
244
|
+
)}
|
|
245
|
+
/>;
|
|
246
|
+
})}
|
|
247
|
+
{Object.keys(fields.tables).map(tableKey => {
|
|
248
|
+
return (
|
|
249
|
+
<details key={`accordion-item-${tableKey}`} className="mb-2">
|
|
250
|
+
<summary>{tableKey}</summary>
|
|
251
|
+
<div className="mt-4">
|
|
252
|
+
{Object.keys(fields.tables[tableKey]).map(key => {
|
|
253
|
+
const field = fields.tables[tableKey][key];
|
|
254
|
+
|
|
255
|
+
return <SidebarEditorField
|
|
256
|
+
sdk={sdk}
|
|
257
|
+
value={storybookElement?.attributes?.[key]}
|
|
258
|
+
key={key}
|
|
259
|
+
fieldKey={key}
|
|
260
|
+
story={storybookElement}
|
|
261
|
+
field={field}
|
|
262
|
+
onChange={(
|
|
263
|
+
key, value, mvpField, mvpIndex,
|
|
264
|
+
) => handleFieldValueChange(
|
|
265
|
+
key, value, mvpField, mvpIndex,
|
|
266
|
+
)}
|
|
267
|
+
/>;
|
|
268
|
+
})}
|
|
269
|
+
</div>
|
|
270
|
+
</details>
|
|
271
|
+
);
|
|
272
|
+
})}
|
|
273
|
+
</>
|
|
274
|
+
)}
|
|
211
275
|
</div>
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
<>
|
|
215
|
-
{Object.keys(fields.fields).map(key => {
|
|
216
|
-
const field = fields.fields[key];
|
|
217
|
-
|
|
218
|
-
return <SidebarEditorField
|
|
219
|
-
sdk={sdk}
|
|
220
|
-
value={storybookElement?.attributes?.[key]}
|
|
221
|
-
key={key}
|
|
222
|
-
storybookElement={storybookElement}
|
|
223
|
-
fieldKey={key}
|
|
224
|
-
field={field}
|
|
225
|
-
onChange={(
|
|
226
|
-
key, value, mvpField, mvpIndex,
|
|
227
|
-
) => handleFieldValueChange(
|
|
228
|
-
key, value, mvpField, mvpIndex,
|
|
229
|
-
)}
|
|
230
|
-
/>;
|
|
231
|
-
})}
|
|
232
|
-
{Object.keys(fields.tables).map(tableKey => {
|
|
233
|
-
return (
|
|
234
|
-
<details key={`accordion-item-${tableKey}`} className="mb-2">
|
|
235
|
-
<summary>{tableKey}</summary>
|
|
236
|
-
<div className="mt-4">
|
|
237
|
-
{Object.keys(fields.tables[tableKey]).map(key => {
|
|
238
|
-
const field = fields.tables[tableKey][key];
|
|
239
|
-
|
|
240
|
-
return <SidebarEditorField
|
|
241
|
-
sdk={sdk}
|
|
242
|
-
value={storybookElement?.attributes?.[key]}
|
|
243
|
-
key={key}
|
|
244
|
-
fieldKey={key}
|
|
245
|
-
story={storybookElement}
|
|
246
|
-
field={field}
|
|
247
|
-
onChange={(
|
|
248
|
-
key, value, mvpField, mvpIndex,
|
|
249
|
-
) => handleFieldValueChange(
|
|
250
|
-
key, value, mvpField, mvpIndex,
|
|
251
|
-
)}
|
|
252
|
-
/>;
|
|
253
|
-
})}
|
|
254
|
-
</div>
|
|
255
|
-
</details>
|
|
256
|
-
);
|
|
257
|
-
})}
|
|
258
|
-
</>
|
|
259
|
-
)}
|
|
260
|
-
</div>
|
|
276
|
+
</>
|
|
277
|
+
)}
|
|
261
278
|
</div>
|
|
262
279
|
);
|
|
263
280
|
};
|
|
@@ -351,6 +368,7 @@ const BlockSelect = ({
|
|
|
351
368
|
active,
|
|
352
369
|
onChange,
|
|
353
370
|
className,
|
|
371
|
+
storyContext,
|
|
354
372
|
}) => {
|
|
355
373
|
if (!onChange) {
|
|
356
374
|
return null;
|
|
@@ -377,7 +395,12 @@ const BlockSelect = ({
|
|
|
377
395
|
return;
|
|
378
396
|
}
|
|
379
397
|
|
|
380
|
-
|
|
398
|
+
let splitStoryContext = storyContext.split(",");
|
|
399
|
+
let isItemInContext = splitStoryContext.find(context => {
|
|
400
|
+
return Array.isArray(item.storyContext) ? item.storyContext.includes(context) : context === item.storyContext;
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
if (!devMode && !isItemInContext) {
|
|
381
404
|
return;
|
|
382
405
|
}
|
|
383
406
|
|
|
@@ -410,7 +433,7 @@ const BlockSelect = ({
|
|
|
410
433
|
|
|
411
434
|
if (option.title && option.id) {
|
|
412
435
|
return (
|
|
413
|
-
<option key={option.id} value={option.id}>
|
|
436
|
+
<option key={option.id} value={option.id.toLowerCase()}>
|
|
414
437
|
{option.shortTitle}
|
|
415
438
|
</option>
|
|
416
439
|
);
|
|
@@ -433,8 +456,8 @@ const BlockSelect = ({
|
|
|
433
456
|
<div className={className}>
|
|
434
457
|
<label className="block">Element</label>
|
|
435
458
|
<select
|
|
436
|
-
onChange={e => onSelectChange(stories.find(s => s.id === e.target.value))}
|
|
437
|
-
value={active?.block}
|
|
459
|
+
onChange={e => onSelectChange(stories.find(s => s.id?.toLowerCase() === e.target.value))}
|
|
460
|
+
value={active?.block?.toLowerCase()}
|
|
438
461
|
className="font-bold"
|
|
439
462
|
>
|
|
440
463
|
<option>Element wählen</option>
|
package/src/dev/App.js
CHANGED
|
@@ -23,22 +23,13 @@ function App() {
|
|
|
23
23
|
},
|
|
24
24
|
];
|
|
25
25
|
const [value, setValue] = useState(SampleValue);
|
|
26
|
-
const [loadedStorybookStories, setLoadedStorybookStories] = useState([]);
|
|
27
|
-
|
|
28
|
-
const loadStories = async () => {
|
|
29
|
-
setLoadedStorybookStories(await storybookStories());
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
loadStories();
|
|
34
|
-
}, []);
|
|
35
26
|
|
|
36
27
|
return (
|
|
37
28
|
<div className="editor-demo-wrapper">
|
|
38
29
|
<div className="editor-demo block-editor-content">
|
|
39
30
|
<div className="editor-demo-editor container">
|
|
40
31
|
<BlockEditor
|
|
41
|
-
storybookStories={
|
|
32
|
+
storybookStories={storybookStories}
|
|
42
33
|
onChange={setValue}
|
|
43
34
|
elementPropsMap={{}}
|
|
44
35
|
value={value}
|