@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vonaffenfels/slate-editor",
3
- "version": "1.0.28",
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": "fe5a1e14e437b67a1aa58fa6781b9ae134914750",
74
+ "gitHead": "007715e3b949cf0368e7b4d70626d2931c7b7829",
75
75
  "publishConfig": {
76
76
  "access": "public"
77
77
  }
@@ -17,7 +17,7 @@
17
17
  }
18
18
 
19
19
  label {
20
- margin: 0 0 6px 0 !important;
20
+ margin: 0 0 2px 0 !important;
21
21
  }
22
22
 
23
23
  input[type="text"],
@@ -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,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
- <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}>
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
- </IconButton>
181
- <IconButton title="Nach unten verschieben" onClick={() => onMove && onMove(storybookElement, "down")} disabled={storybookElement.path[0] === editor.children.length - 1}>
191
+ </IconButton>
192
+ <IconButton title="Nach unten verschieben" onClick={() => onMove && onMove(storybookElement, "down")} disabled={storybookElement.path[0] === editor.children.length - 1}>
182
193
 
183
- </IconButton>
184
- </div>
185
- <IconButton title="Löschen" onClick={() => onDelete && onDelete(storybookElement)}>
194
+ </IconButton>
195
+ </div>
196
+ <IconButton title="Löschen" onClick={() => onDelete && onDelete(storybookElement)}>
186
197
  🗑
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>
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
- {!!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)} />
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
- <hr className="my-4" style={{borderColor: "#cfd9e0"}}/>
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
- {!!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>
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
- if (item.storyContext === "development" || (Array.isArray(item.storyContext) && item.storyContext.includes("development"))) {
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={loadedStorybookStories}
32
+ storybookStories={storybookStories}
42
33
  onChange={setValue}
43
34
  elementPropsMap={{}}
44
35
  value={value}