@vonaffenfels/slate-editor 1.0.3 → 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/dist/BlockEditor.css +4 -4
- package/dist/BlockEditor.js +1 -1
- package/dist/BlockEditor.js.LICENSE.txt +0 -33
- package/dist/Renderer.js +1 -1
- package/dist/index.css +4 -4
- package/dist/index.js +1 -1
- package/dist/index.js.LICENSE.txt +0 -33
- package/package.json +2 -2
- package/scss/demo.scss +7 -0
- package/scss/editor.scss +70 -38
- package/scss/sidebarEditor.scss +60 -21
- 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 +132 -64
- package/src/SidebarEditor.js +270 -121
- 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
|
@@ -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,70 +178,100 @@ 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
262
|
<details>
|
|
199
|
-
<summary>{storybookElement?.attributes?.[fieldKey]?.length || 0} Elemente</summary>
|
|
263
|
+
<summary>{storybookElement?.attributes?.[fieldKey]?.length || 0} {storybookElement?.attributes?.[fieldKey]?.length === 1 ? "Element" : "Elemente"}</summary>
|
|
200
264
|
<div className="mt-4">
|
|
201
265
|
{storybookElement?.attributes?.[fieldKey]?.map((f, index) => {
|
|
202
266
|
return (
|
|
203
267
|
<div className="mb-4" key={`mvp-${index}`}>
|
|
204
268
|
<div className="mb-2 flex items-center">
|
|
205
269
|
<b className="grow">{field.name} [{index.toString()}]</b>
|
|
206
|
-
<div className="
|
|
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>
|
|
207
275
|
</div>
|
|
208
276
|
{Object.keys(field.control.fields).map((key, mvpIndex) => {
|
|
209
277
|
let mvpField = field.control.fields[key];
|
|
@@ -228,12 +296,12 @@ export const SidebarEditorField = ({
|
|
|
228
296
|
</div>
|
|
229
297
|
);
|
|
230
298
|
})}
|
|
231
|
-
<
|
|
299
|
+
<button onClick={() => onChange(fieldKey, [...(storybookElement.attributes[fieldKey] || []), {}])}>Neue Zeile</button>
|
|
232
300
|
</div>
|
|
233
301
|
</details>
|
|
234
302
|
);
|
|
235
303
|
default:
|
|
236
|
-
return <
|
|
304
|
+
return <div className="message message--negative">Keine Konfiguration zu Feldtyp "{field?.control?.type}" gefunden</div>;
|
|
237
305
|
}
|
|
238
306
|
};
|
|
239
307
|
|