@vonaffenfels/slate-editor 1.0.28 → 1.0.30

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vonaffenfels/slate-editor",
3
- "version": "1.0.28",
3
+ "version": "1.0.30",
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": "fe5a1e14e437b67a1aa58fa6781b9ae134914750",
74
+ "gitHead": "fe88a0b3ce82331fa3d7193a4cd62b8e2c8ecfb9",
75
75
  "publishConfig": {
76
76
  "access": "public"
77
77
  }
@@ -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={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
- <a className="mr-1" target="_blank" href={href} rel="noreferrer">
140
- <IconButton size="small">Asset</IconButton>
141
- </a>
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 => {
@@ -5,6 +5,8 @@ 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";
8
10
 
9
11
  const SidebarEditor = ({
10
12
  sdk,
@@ -15,6 +17,7 @@ const SidebarEditor = ({
15
17
  onDelete,
16
18
  onMove,
17
19
  editor,
20
+ isLoading,
18
21
  }) => {
19
22
  const [versions, setVersions] = useState([]);
20
23
  const [lastChangedProperty, setLastChangedProperty] = useState(null);
@@ -26,7 +29,7 @@ const SidebarEditor = ({
26
29
  tables: {},
27
30
  };
28
31
 
29
- const story = storybookStories?.find(v => storybookElement.block === v.id);
32
+ const story = storybookStories?.find(v => storybookElement.block?.toLowerCase() === v.id?.toLowerCase());
30
33
 
31
34
  if (story) {
32
35
  Object.keys(story.argTypes).forEach(key => {
@@ -165,99 +168,107 @@ const SidebarEditor = ({
165
168
 
166
169
  return (
167
170
  <div id="sidebar-editor">
168
- <div>
169
- <div className="flex items-center justify-end">
170
- <div className="grow">
171
- {storybookElement?.block && (
172
- <div className="flex items-center">
173
- <div className="icon-button-group mr-1">
174
- <IconButton title="Rückgängig" onClick={undo} disabled={currentVersion <= 1}>↺</IconButton>
175
- <IconButton title="Wiederherstellen" onClick={redo} disabled={currentVersion >= versionCount || versionCount === 0}>↻</IconButton>
176
- </div>
177
- <div className="icon-button-group mr-1">
178
- <IconButton title="Nach oben verschieben" onClick={() => onMove && onMove(storybookElement, "up")} disabled={storybookElement.path[0] === 0}>
171
+ {isLoading ? (
172
+ <div className="text-center">
173
+ <FontAwesomeIcon icon={faSpinner} pulse />
174
+ </div>
175
+ ) : (
176
+ <>
177
+ <div>
178
+ <div className="flex items-center justify-end">
179
+ <div className="grow">
180
+ {storybookElement?.block && (
181
+ <div className="flex items-center">
182
+ <div className="icon-button-group mr-1">
183
+ <IconButton title="Rückgängig" onClick={undo} disabled={currentVersion <= 1}>↺</IconButton>
184
+ <IconButton title="Wiederherstellen" onClick={redo} disabled={currentVersion >= versionCount || versionCount === 0}>↻</IconButton>
185
+ </div>
186
+ <div className="icon-button-group mr-1">
187
+ <IconButton title="Nach oben verschieben" onClick={() => onMove && onMove(storybookElement, "up")} disabled={storybookElement.path[0] === 0}>
179
188
 
180
- </IconButton>
181
- <IconButton title="Nach unten verschieben" onClick={() => onMove && onMove(storybookElement, "down")} disabled={storybookElement.path[0] === editor.children.length - 1}>
189
+ </IconButton>
190
+ <IconButton title="Nach unten verschieben" onClick={() => onMove && onMove(storybookElement, "down")} disabled={storybookElement.path[0] === editor.children.length - 1}>
182
191
 
183
- </IconButton>
184
- </div>
185
- <IconButton title="Löschen" onClick={() => onDelete && onDelete(storybookElement)}>
192
+ </IconButton>
193
+ </div>
194
+ <IconButton title="Löschen" onClick={() => onDelete && onDelete(storybookElement)}>
186
195
  🗑
187
- </IconButton>
188
- <div className="ml-1 flex items-center">
189
- <ToolMargin
190
- margin={storybookElement.attributes.margin}
191
- onChange={value => handleFieldValueChange("margin", value)} />
192
- </div>
196
+ </IconButton>
197
+ <div className="ml-1 flex items-center">
198
+ <ToolMargin
199
+ margin={storybookElement.attributes.margin}
200
+ onChange={value => handleFieldValueChange("margin", value)} />
201
+ </div>
202
+ </div>
203
+ )}
193
204
  </div>
194
- )}
205
+ {!!onClose && <IconButton onClick={onClose} title="Schließen">⨯</IconButton>}
206
+ </div>
207
+ <hr className="mt-2" style={{borderColor: "#cfd9e0"}}/>
195
208
  </div>
196
- {!!onClose && <IconButton onClick={onClose} title="Schließen">⨯</IconButton>}
197
- </div>
198
- <hr className="mt-2" style={{borderColor: "#cfd9e0"}}/>
199
- </div>
200
- <div className="grow overflow-y-auto pr-2 pt-2">
201
- <div className="mb-2">
202
- <BlockSelect stories={storybookStories} active={storybookElement} onChange={handleBlockSelectChange} />
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)} />
209
+ <div className="grow overflow-y-auto pr-2 pt-2">
210
+ <div className="mb-2">
211
+ <BlockSelect stories={storybookStories} active={storybookElement} onChange={handleBlockSelectChange} />
209
212
  </div>
210
- <hr className="my-4" style={{borderColor: "#cfd9e0"}}/>
213
+ {storybookElement?.block && (
214
+ <div>
215
+ <div className="mb-2 grid grid-flow-col grid-cols-2 gap-2">
216
+ <VariantSelect className="w-full" story={story} onChange={handleVariantSelectChange} />
217
+ <BlockWidthSelect className="w-full" value={storybookElement.attributes.blockWidth} onChange={e => handleFieldValueChange("blockWidth", e.target.value)} />
218
+ </div>
219
+ <hr className="my-4" style={{borderColor: "#cfd9e0"}}/>
220
+ </div>
221
+ )}
222
+ {!!story && (
223
+ <>
224
+ {Object.keys(fields.fields).map(key => {
225
+ const field = fields.fields[key];
226
+
227
+ return <SidebarEditorField
228
+ sdk={sdk}
229
+ value={storybookElement?.attributes?.[key]}
230
+ key={key}
231
+ storybookElement={storybookElement}
232
+ fieldKey={key}
233
+ field={field}
234
+ onChange={(
235
+ key, value, mvpField, mvpIndex,
236
+ ) => handleFieldValueChange(
237
+ key, value, mvpField, mvpIndex,
238
+ )}
239
+ />;
240
+ })}
241
+ {Object.keys(fields.tables).map(tableKey => {
242
+ return (
243
+ <details key={`accordion-item-${tableKey}`} className="mb-2">
244
+ <summary>{tableKey}</summary>
245
+ <div className="mt-4">
246
+ {Object.keys(fields.tables[tableKey]).map(key => {
247
+ const field = fields.tables[tableKey][key];
248
+
249
+ return <SidebarEditorField
250
+ sdk={sdk}
251
+ value={storybookElement?.attributes?.[key]}
252
+ key={key}
253
+ fieldKey={key}
254
+ story={storybookElement}
255
+ field={field}
256
+ onChange={(
257
+ key, value, mvpField, mvpIndex,
258
+ ) => handleFieldValueChange(
259
+ key, value, mvpField, mvpIndex,
260
+ )}
261
+ />;
262
+ })}
263
+ </div>
264
+ </details>
265
+ );
266
+ })}
267
+ </>
268
+ )}
211
269
  </div>
212
- )}
213
- {!!story && (
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>
270
+ </>
271
+ )}
261
272
  </div>
262
273
  );
263
274
  };
@@ -410,7 +421,7 @@ const BlockSelect = ({
410
421
 
411
422
  if (option.title && option.id) {
412
423
  return (
413
- <option key={option.id} value={option.id}>
424
+ <option key={option.id} value={option.id.toLowerCase()}>
414
425
  {option.shortTitle}
415
426
  </option>
416
427
  );
@@ -433,8 +444,8 @@ const BlockSelect = ({
433
444
  <div className={className}>
434
445
  <label className="block">Element</label>
435
446
  <select
436
- onChange={e => onSelectChange(stories.find(s => s.id === e.target.value))}
437
- value={active?.block}
447
+ onChange={e => onSelectChange(stories.find(s => s.id?.toLowerCase() === e.target.value))}
448
+ value={active?.block?.toLowerCase()}
438
449
  className="font-bold"
439
450
  >
440
451
  <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={loadedStorybookStories}
32
+ storybookStories={storybookStories}
42
33
  onChange={setValue}
43
34
  elementPropsMap={{}}
44
35
  value={value}