@vonaffenfels/slate-editor 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/componentLoader.js +10 -8
- package/dist/BlockEditor.css +4 -95
- package/dist/BlockEditor.js +1 -1
- package/dist/BlockEditor.js.LICENSE.txt +0 -33
- package/dist/index.css +4 -95
- package/dist/index.js +1 -1
- package/dist/index.js.LICENSE.txt +0 -33
- package/package.json +2 -3
- package/scss/demo.scss +7 -0
- package/scss/editor.scss +70 -38
- package/scss/sidebarEditor.scss +143 -0
- package/scss/storybook.scss +73 -5
- package/scss/toolbar.scss +2 -0
- package/src/BlockEditor.js +85 -45
- package/src/Nodes/Element.js +11 -9
- package/src/Nodes/Storybook.js +13 -32
- package/src/SidebarEditor/AssetList.js +129 -0
- package/src/SidebarEditor/SidebarEditorField.js +164 -93
- package/src/SidebarEditor.js +266 -116
- package/src/Toolbar/Toolbar.js +39 -34
- package/src/dev/App.js +6 -0
- package/src/dev/testComponents/TestStory.js +68 -2
- package/src/dev/testComponents/TestStory.stories.js +13 -3
- package/src/helper/array.js +9 -0
- package/webpack.config.build.js +2 -0
- package/src/SidebarEditor.css +0 -92
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import {IconButton} from "../SidebarEditor";
|
|
2
|
+
import {swapArrayElements} from "../helper/array";
|
|
1
3
|
import {
|
|
2
|
-
|
|
3
|
-
} from "
|
|
4
|
+
Asset, AssetList,
|
|
5
|
+
} from "./AssetList";
|
|
4
6
|
|
|
5
7
|
export const SidebarEditorField = ({
|
|
6
8
|
field,
|
|
@@ -20,12 +22,25 @@ export const SidebarEditorField = ({
|
|
|
20
22
|
}
|
|
21
23
|
};
|
|
22
24
|
|
|
25
|
+
const handleMVPMoveClick = (fieldKey, direction, index) => {
|
|
26
|
+
let value = storybookElement.attributes[fieldKey];
|
|
27
|
+
let newIndex = direction === "up" ? index - 1 : index + 1;
|
|
28
|
+
|
|
29
|
+
if (direction === "up" && index === 0) {
|
|
30
|
+
return;
|
|
31
|
+
} else if (direction === "down" && index === value.length - 1) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
onChange(fieldKey, swapArrayElements(value, index, newIndex));
|
|
36
|
+
};
|
|
37
|
+
|
|
23
38
|
const getInputByField = (field, fieldKey) => {
|
|
24
39
|
switch (field?.control?.type) {
|
|
25
40
|
case "text":
|
|
26
41
|
return <input
|
|
27
42
|
type="text"
|
|
28
|
-
value={value}
|
|
43
|
+
value={value || ""}
|
|
29
44
|
onChange={e => onChange(fieldKey, e.target.value)} />;
|
|
30
45
|
case "boolean":
|
|
31
46
|
return (
|
|
@@ -39,8 +54,9 @@ export const SidebarEditorField = ({
|
|
|
39
54
|
case "select":
|
|
40
55
|
return (
|
|
41
56
|
<select
|
|
42
|
-
value={value}
|
|
57
|
+
value={value || ""}
|
|
43
58
|
onChange={e => onChange(fieldKey, e.target.value)}>
|
|
59
|
+
<option value="">Auswählen</option>
|
|
44
60
|
{Object.keys(field.control.options).map(key => (
|
|
45
61
|
<option key={`select-option-${key}`} value={field.control.options[key]}>{key}</option>
|
|
46
62
|
))}
|
|
@@ -50,7 +66,7 @@ export const SidebarEditorField = ({
|
|
|
50
66
|
return (
|
|
51
67
|
<input
|
|
52
68
|
type="number"
|
|
53
|
-
value={value}
|
|
69
|
+
value={value || ""}
|
|
54
70
|
onChange={e => onChange(fieldKey, e.target.value)} />
|
|
55
71
|
);
|
|
56
72
|
case "range":
|
|
@@ -66,7 +82,7 @@ export const SidebarEditorField = ({
|
|
|
66
82
|
case "object":
|
|
67
83
|
return (
|
|
68
84
|
<textarea
|
|
69
|
-
value={value}
|
|
85
|
+
value={value || ""}
|
|
70
86
|
onChange={e => onChange(fieldKey, e.target.value)} />
|
|
71
87
|
);
|
|
72
88
|
case "radio":
|
|
@@ -74,8 +90,8 @@ export const SidebarEditorField = ({
|
|
|
74
90
|
<div>
|
|
75
91
|
{Object.keys(field.control.options).map((key, index) => (
|
|
76
92
|
<div key={`radio-option-${key}`}>
|
|
77
|
-
<input id={`${fieldKey}-${index}`} type="radio" value={key} name={fieldKey} />
|
|
78
|
-
<label htmlFor={`${fieldKey}-${index}`}>{
|
|
93
|
+
<input id={`${fieldKey}-${index}`} checked={value === field.control.options[key]} type="radio" value={field.control.options[key]} name={fieldKey} onChange={e => onChange(fieldKey, e.target.value)} />
|
|
94
|
+
<label htmlFor={`${fieldKey}-${index}`}>{key}</label>
|
|
79
95
|
</div>
|
|
80
96
|
))}
|
|
81
97
|
</div>
|
|
@@ -85,8 +101,8 @@ export const SidebarEditorField = ({
|
|
|
85
101
|
<div>
|
|
86
102
|
{Object.keys(field.control.options).map((key, index) => (
|
|
87
103
|
<div key={`inline-radio-option-${key}`} className="inline-check-wrapper">
|
|
88
|
-
<input id={`${fieldKey}-${index}`} type="radio" value={key} name={fieldKey} />
|
|
89
|
-
<label htmlFor={`${fieldKey}-${index}`}>{
|
|
104
|
+
<input id={`${fieldKey}-${index}`} checked={value === field.control.options[key]} type="radio" value={field.control.options[key]} name={fieldKey} onChange={e => onChange(fieldKey, e.target.value)} />
|
|
105
|
+
<label htmlFor={`${fieldKey}-${index}`}>{key}</label>
|
|
90
106
|
</div>
|
|
91
107
|
))}
|
|
92
108
|
</div>
|
|
@@ -96,8 +112,17 @@ export const SidebarEditorField = ({
|
|
|
96
112
|
<div>
|
|
97
113
|
{Object.keys(field.control.options).map((key, index) => (
|
|
98
114
|
<div key={`check-option-${key}`}>
|
|
99
|
-
<input
|
|
100
|
-
|
|
115
|
+
<input
|
|
116
|
+
id={`${fieldKey}-${index}`}
|
|
117
|
+
type="checkbox"
|
|
118
|
+
value={field.control.options[key]}
|
|
119
|
+
name={fieldKey}
|
|
120
|
+
checked={value?.[field.control.options[key]]}
|
|
121
|
+
onChange={e => onChange(fieldKey, {
|
|
122
|
+
...value,
|
|
123
|
+
[field.control.options[key]]: e.target.checked,
|
|
124
|
+
})} />
|
|
125
|
+
<label htmlFor={`${fieldKey}-${index}`}>{key}</label>
|
|
101
126
|
</div>
|
|
102
127
|
))}
|
|
103
128
|
</div>
|
|
@@ -107,8 +132,17 @@ export const SidebarEditorField = ({
|
|
|
107
132
|
<div>
|
|
108
133
|
{Object.keys(field.control.options).map((key, index) => (
|
|
109
134
|
<div key={`inline-check-option-${key}`} className="inline-check-wrapper">
|
|
110
|
-
<input
|
|
111
|
-
|
|
135
|
+
<input
|
|
136
|
+
id={`${fieldKey}-${index}`}
|
|
137
|
+
type="checkbox"
|
|
138
|
+
value={field.control.options[key]}
|
|
139
|
+
name={fieldKey}
|
|
140
|
+
checked={value?.[field.control.options[key]]}
|
|
141
|
+
onChange={e => onChange(fieldKey, {
|
|
142
|
+
...value,
|
|
143
|
+
[field.control.options[key]]: e.target.checked,
|
|
144
|
+
})} />
|
|
145
|
+
<label htmlFor={`${fieldKey}-${index}`}>{key}</label>
|
|
112
146
|
</div>
|
|
113
147
|
))}
|
|
114
148
|
</div>
|
|
@@ -117,14 +151,14 @@ export const SidebarEditorField = ({
|
|
|
117
151
|
return (
|
|
118
152
|
<input
|
|
119
153
|
type="color"
|
|
120
|
-
value={value}
|
|
154
|
+
value={value || ""}
|
|
121
155
|
onChange={e => onChange(fieldKey, e.target.value)} />
|
|
122
156
|
);
|
|
123
157
|
case "date":
|
|
124
158
|
return (
|
|
125
159
|
<input
|
|
126
160
|
type="date"
|
|
127
|
-
value={value}
|
|
161
|
+
value={value || ""}
|
|
128
162
|
onChange={e => onChange(fieldKey, e.target.value)} />
|
|
129
163
|
);
|
|
130
164
|
case "multi-select":
|
|
@@ -132,7 +166,11 @@ export const SidebarEditorField = ({
|
|
|
132
166
|
<select
|
|
133
167
|
multiple
|
|
134
168
|
value={value}
|
|
135
|
-
onChange={e =>
|
|
169
|
+
onChange={e => {
|
|
170
|
+
let v = Array.from(e.target.selectedOptions, option => option.value);
|
|
171
|
+
|
|
172
|
+
onChange(fieldKey, v);
|
|
173
|
+
}}>
|
|
136
174
|
{Object.keys(field.control.options).map(key => (
|
|
137
175
|
<option key={`select-option-${key}`} value={field.control.options[key]}>{key}</option>
|
|
138
176
|
))}
|
|
@@ -140,97 +178,130 @@ export const SidebarEditorField = ({
|
|
|
140
178
|
);
|
|
141
179
|
case "contentful-content":
|
|
142
180
|
return (
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
181
|
+
<>
|
|
182
|
+
{!!value && <div className="mb-2"><Asset sdk={sdk} asset={value} onDeleteClick={() => onChange(fieldKey, null)} /></div>}
|
|
183
|
+
<button
|
|
184
|
+
onClick={() => {
|
|
185
|
+
sdk.dialogs.selectSingleEntry({contentTypes: field.control.contentTypes}).then(content => {
|
|
186
|
+
onChange(fieldKey, content);
|
|
187
|
+
});
|
|
188
|
+
}}
|
|
189
|
+
>Auswählen</button>
|
|
190
|
+
</>
|
|
150
191
|
);
|
|
151
192
|
case "contentful-contents":
|
|
152
193
|
return (
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
194
|
+
<>
|
|
195
|
+
{value && value.length > 0 && (
|
|
196
|
+
<details className="mb-2">
|
|
197
|
+
<summary>{value.length || 0} {value.length === 1 ? "Element" : "Elemente"}</summary>
|
|
198
|
+
<div className="mt-4">
|
|
199
|
+
<AssetList assets={value} sdk={sdk} onChange={v => onChange(fieldKey, v)} />
|
|
200
|
+
</div>
|
|
201
|
+
</details>
|
|
202
|
+
)}
|
|
203
|
+
<button
|
|
204
|
+
onClick={() => {
|
|
205
|
+
sdk.dialogs.selectMultipleEntries({contentTypes: field.control.contentTypes}).then(contents => {
|
|
206
|
+
onChange(fieldKey, contents);
|
|
207
|
+
});
|
|
208
|
+
}}
|
|
209
|
+
>Auswählen</button>
|
|
210
|
+
</>
|
|
160
211
|
);
|
|
161
212
|
case "cloudinary-image":
|
|
162
213
|
return (
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
214
|
+
<>
|
|
215
|
+
{!!value && <div className="mb-2"><Asset cloudinary sdk={sdk} asset={value} onDeleteClick={() => onChange(fieldKey, null)} /></div>}
|
|
216
|
+
<button
|
|
217
|
+
onClick={() => {
|
|
218
|
+
sdk.dialogs.openCurrentApp({
|
|
219
|
+
width: "fullWidth",
|
|
220
|
+
title: "Select Image",
|
|
221
|
+
shouldCloseOnOverlayClick: true,
|
|
222
|
+
shouldCloseOnEscapePress: true,
|
|
223
|
+
parameters: {type: "cloudinary"},
|
|
224
|
+
}).then((data) => {
|
|
225
|
+
onChange(fieldKey, data?.assets?.[0]);
|
|
226
|
+
});
|
|
227
|
+
}}
|
|
228
|
+
>Auswählen</button>
|
|
229
|
+
</>
|
|
176
230
|
);
|
|
177
231
|
case "cloudinary-images":
|
|
178
232
|
return (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
233
|
+
<>
|
|
234
|
+
{value && value.length > 0 && (
|
|
235
|
+
<details className="mb-2">
|
|
236
|
+
<summary>{value.length || 0} {value.length === 1 ? "Element" : "Elemente"}</summary>
|
|
237
|
+
<div className="mt-4">
|
|
238
|
+
<AssetList cloudinary assets={value} sdk={sdk} onChange={v => onChange(fieldKey, v)} />
|
|
239
|
+
</div>
|
|
240
|
+
</details>
|
|
241
|
+
)}
|
|
242
|
+
<button
|
|
243
|
+
onClick={() => {
|
|
244
|
+
sdk.dialogs.openCurrentApp({
|
|
245
|
+
width: "fullWidth",
|
|
246
|
+
title: "Select Images",
|
|
247
|
+
shouldCloseOnOverlayClick: true,
|
|
248
|
+
shouldCloseOnEscapePress: true,
|
|
249
|
+
parameters: {
|
|
250
|
+
type: "cloudinary",
|
|
251
|
+
multiple: true,
|
|
252
|
+
},
|
|
253
|
+
}).then((data) => {
|
|
254
|
+
onChange(fieldKey, data?.assets);
|
|
255
|
+
});
|
|
256
|
+
}}
|
|
257
|
+
>Auswählen</button>
|
|
258
|
+
</>
|
|
195
259
|
);
|
|
196
260
|
case "mvp":
|
|
197
261
|
return (
|
|
198
|
-
|
|
199
|
-
{storybookElement?.attributes[fieldKey]?.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
<div className="
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
262
|
+
<details>
|
|
263
|
+
<summary>{storybookElement?.attributes?.[fieldKey]?.length || 0} {storybookElement?.attributes?.[fieldKey]?.length === 1 ? "Element" : "Elemente"}</summary>
|
|
264
|
+
<div className="mt-4">
|
|
265
|
+
{storybookElement?.attributes?.[fieldKey]?.map((f, index) => {
|
|
266
|
+
return (
|
|
267
|
+
<div className="mb-4" key={`mvp-${index}`}>
|
|
268
|
+
<div className="mb-2 flex items-center">
|
|
269
|
+
<b className="grow">{field.name} [{index.toString()}]</b>
|
|
270
|
+
<div className="icon-button-group mr-1">
|
|
271
|
+
<IconButton size="small" onClick={() => handleMVPMoveClick(fieldKey, "up", index)} disabled={index === 0}>↑</IconButton>
|
|
272
|
+
<IconButton size="small" onClick={() => handleMVPMoveClick(fieldKey, "down", index)} disabled={index === storybookElement.attributes?.[fieldKey]?.length - 1}>↓</IconButton>
|
|
273
|
+
</div>
|
|
274
|
+
<IconButton size="small" onClick={() => deleteMVPEntry(fieldKey, index)}>🗑</IconButton>
|
|
275
|
+
</div>
|
|
276
|
+
{Object.keys(field.control.fields).map((key, mvpIndex) => {
|
|
277
|
+
let mvpField = field.control.fields[key];
|
|
208
278
|
|
|
209
|
-
|
|
279
|
+
value = storybookElement.attributes?.[fieldKey]?.[index]?.[key];
|
|
210
280
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
281
|
+
return (
|
|
282
|
+
<div key={`mvp-field-${key}`}>
|
|
283
|
+
<SidebarEditorField
|
|
284
|
+
field={mvpField}
|
|
285
|
+
fieldKey={fieldKey}
|
|
286
|
+
value={value}
|
|
287
|
+
storybookElement={storybookElement}
|
|
288
|
+
sdk={sdk}
|
|
289
|
+
onChange={(fK, value) => onChange(
|
|
290
|
+
fK, value, key, index,
|
|
291
|
+
)} />
|
|
292
|
+
</div>
|
|
293
|
+
);
|
|
294
|
+
})}
|
|
295
|
+
<hr className="my-4" style={{borderColor: "rgb(174, 193, 204)"}} />
|
|
296
|
+
</div>
|
|
297
|
+
);
|
|
298
|
+
})}
|
|
299
|
+
<button onClick={() => onChange(fieldKey, [...(storybookElement.attributes[fieldKey] || []), {}])}>Neue Zeile</button>
|
|
300
|
+
</div>
|
|
301
|
+
</details>
|
|
231
302
|
);
|
|
232
303
|
default:
|
|
233
|
-
return <
|
|
304
|
+
return <div className="message message--negative">Keine Konfiguration zu Feldtyp "{field?.control?.type}" gefunden</div>;
|
|
234
305
|
}
|
|
235
306
|
};
|
|
236
307
|
|
|
@@ -242,7 +313,7 @@ export const SidebarEditorField = ({
|
|
|
242
313
|
|
|
243
314
|
return (
|
|
244
315
|
<div key={`${field.name}`} className="mb-2">
|
|
245
|
-
<label>{field.name}</label>
|
|
316
|
+
<label className="block">{field.name}</label>
|
|
246
317
|
{inputField}
|
|
247
318
|
</div>
|
|
248
319
|
);
|