@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.
@@ -1,6 +1,8 @@
1
+ import {IconButton} from "../SidebarEditor";
2
+ import {swapArrayElements} from "../helper/array";
1
3
  import {
2
- Button, Icon, Note,
3
- } from "@contentful/forma-36-react-components";
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}`}>{field.control.options[key]}</label>
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}`}>{field.control.options[key]}</label>
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 id={`${fieldKey}-${index}`} type="checkbox" value={key} name={fieldKey} />
100
- <label htmlFor={`${fieldKey}-${index}`}>{field.control.options[key]}</label>
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 id={`${fieldKey}-${index}`} type="checkbox" value={key} name={fieldKey} />
111
- <label htmlFor={`${fieldKey}-${index}`}>{field.control.options[key]}</label>
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 => onChange(fieldKey, e.target.value)}>
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
- <Button
144
- onClick={() => {
145
- sdk.dialogs.selectSingleEntry({contentTypes: field.control.contentTypes}).then(content => {
146
- onChange(fieldKey, content);
147
- });
148
- }}
149
- isFullWidth>Auswählen</Button>
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
- <Button
154
- onClick={() => {
155
- sdk.dialogs.selectMultipleEntries({contentTypes: field.control.contentTypes}).then(contents => {
156
- onChange(fieldKey, contents);
157
- });
158
- }}
159
- isFullWidth>Auswählen</Button>
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
- <Button
164
- onClick={() => {
165
- sdk.dialogs.openCurrentApp({
166
- width: "fullWidth",
167
- title: "Select Image",
168
- shouldCloseOnOverlayClick: true,
169
- shouldCloseOnEscapePress: true,
170
- parameters: {type: "cloudinary"},
171
- }).then((image) => {
172
- onChange(fieldKey, image);
173
- });
174
- }}
175
- isFullWidth>Auswählen</Button>
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
- <Button
180
- onClick={() => {
181
- sdk.dialogs.openCurrentApp({
182
- width: "fullWidth",
183
- title: "Select Images",
184
- shouldCloseOnOverlayClick: true,
185
- shouldCloseOnEscapePress: true,
186
- parameters: {
187
- type: "cloudinary",
188
- multiple: true,
189
- },
190
- }).then((images) => {
191
- onChange(fieldKey, images);
192
- });
193
- }}
194
- isFullWidth>Auswählen</Button>
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]?.map((f, index) => {
200
- return (
201
- <div className="mb-4" key={`mvp-${index}`}>
202
- <div className="mb-2 flex items-center">
203
- <b className="grow">{field.name} [{index.toString()}]</b>
204
- <div className="cursor-pointer p-1" onClick={() => deleteMVPEntry(fieldKey, index)}><Icon icon="Delete" /></div>
205
- </div>
206
- {Object.keys(field.control.fields).map((key, mvpIndex) => {
207
- let mvpField = field.control.fields[key];
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
- value = storybookElement.attributes?.[fieldKey]?.[index]?.[key];
279
+ value = storybookElement.attributes?.[fieldKey]?.[index]?.[key];
210
280
 
211
- return (
212
- <div key={`mvp-field-${key}`}>
213
- <SidebarEditorField
214
- field={mvpField}
215
- fieldKey={fieldKey}
216
- value={value}
217
- storybookElement={storybookElement}
218
- sdk={sdk}
219
- onChange={(fK, value) => onChange(
220
- fK, value, key, index,
221
- )} />
222
- </div>
223
- );
224
- })}
225
- <hr className="my-4" style={{borderColor: "rgb(174, 193, 204)"}} />
226
- </div>
227
- );
228
- })}
229
- <Button onClick={() => onChange(fieldKey, [...storybookElement.attributes[fieldKey], {}])}>Neue Zeile</Button>
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 <Note noteType="negative">Keine Konfiguration zu Feldtyp "{field?.control?.type}" gefunden</Note>;
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
  );