@vonaffenfels/slate-editor 1.0.59 → 1.0.62
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 +1 -1
- package/dist/BlockEditor.js +1 -1
- package/dist/index.css +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/scss/editor.scss +16 -8
- package/src/BlockEditor.js +82 -3
- package/src/ElementAutocomplete.js +84 -0
- package/src/SidebarEditor/Resizable.js +18 -13
- package/src/SidebarEditor/SidebarEditorField.js +1 -1
- package/src/SidebarEditor.js +63 -117
- package/src/Toolbar/Toolbar.js +18 -80
- package/storyLoader.js +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vonaffenfels/slate-editor",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.62",
|
|
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": "
|
|
74
|
+
"gitHead": "6ad3de5f5d37e2ca7447e7591f8f9e4d32089f30",
|
|
75
75
|
"publishConfig": {
|
|
76
76
|
"access": "public"
|
|
77
77
|
}
|
package/scss/editor.scss
CHANGED
|
@@ -259,8 +259,8 @@
|
|
|
259
259
|
|
|
260
260
|
.layout-slot-option-padding {
|
|
261
261
|
position: relative;
|
|
262
|
-
width:
|
|
263
|
-
height:
|
|
262
|
+
width: 26px;
|
|
263
|
+
height: 26px;
|
|
264
264
|
display: inline-block;
|
|
265
265
|
|
|
266
266
|
.layout-slot-option-padding-item {
|
|
@@ -397,15 +397,9 @@
|
|
|
397
397
|
}
|
|
398
398
|
|
|
399
399
|
.button.button--secondary {
|
|
400
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
|
|
401
|
-
width: 100%;
|
|
402
|
-
padding: 8px 0.75rem !important;
|
|
403
400
|
color: #036fe3 !important;
|
|
404
401
|
border: 1px solid #036fe3 !important;
|
|
405
|
-
transition: all 100ms ease-in-out;
|
|
406
402
|
background-color: transparent !important;
|
|
407
|
-
font-size: 0.875rem !important;
|
|
408
|
-
border-radius: 4px !important;
|
|
409
403
|
}
|
|
410
404
|
|
|
411
405
|
.button.button--secondary:hover {
|
|
@@ -418,6 +412,20 @@
|
|
|
418
412
|
color: #FFFFFF !important;
|
|
419
413
|
}
|
|
420
414
|
|
|
415
|
+
.button.button--tertiary {
|
|
416
|
+
color: rgb(90, 101, 124) !important;
|
|
417
|
+
background-color: white !important;
|
|
418
|
+
border: 1px solid #cfd9e0 !important;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.button.button--tertiary:hover {
|
|
422
|
+
background-color: rgb(248, 248, 248) !important;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.button.button--tertiary:active {
|
|
426
|
+
background-color: rgb(237, 237, 237) !important;
|
|
427
|
+
}
|
|
428
|
+
|
|
421
429
|
.resizable {
|
|
422
430
|
.resizable-left {
|
|
423
431
|
position: relative;
|
package/src/BlockEditor.js
CHANGED
|
@@ -77,6 +77,7 @@ export default function BlockEditor({
|
|
|
77
77
|
|
|
78
78
|
const [loadedStorybookStories, setLoadedStorybookStories] = useState([]);
|
|
79
79
|
const [isLoadingStories, setIsLoadingStories] = useState(false);
|
|
80
|
+
const [lastSelection, setLastSelection] = useState(null);
|
|
80
81
|
|
|
81
82
|
const loadStories = async () => {
|
|
82
83
|
setIsLoadingStories(true);
|
|
@@ -92,6 +93,32 @@ export default function BlockEditor({
|
|
|
92
93
|
loadStories();
|
|
93
94
|
}, []);
|
|
94
95
|
|
|
96
|
+
const handleKeyDown = (e) => {
|
|
97
|
+
let keyCode = e.keyCode || e.which;
|
|
98
|
+
|
|
99
|
+
switch (keyCode) {
|
|
100
|
+
case 46: // delete
|
|
101
|
+
case 8: // backspace
|
|
102
|
+
handleSidebarDeleteClick();
|
|
103
|
+
break;
|
|
104
|
+
case 27: // escape
|
|
105
|
+
handleSidebarClose();
|
|
106
|
+
break;
|
|
107
|
+
default:
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (selectedStorybookElement) {
|
|
114
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
115
|
+
} else {
|
|
116
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
120
|
+
}, [selectedStorybookElement]);
|
|
121
|
+
|
|
95
122
|
const resetEditor = () => {
|
|
96
123
|
if (confirm("This action will delete all data in the editor, are you sure?")) {
|
|
97
124
|
onChange(emptyValue);
|
|
@@ -99,6 +126,10 @@ export default function BlockEditor({
|
|
|
99
126
|
};
|
|
100
127
|
|
|
101
128
|
const onSlateChange = (newValue) => {
|
|
129
|
+
if (editor.selection) {
|
|
130
|
+
setLastSelection(editor.selection);
|
|
131
|
+
}
|
|
132
|
+
|
|
102
133
|
if (newValue.length > 0) {
|
|
103
134
|
onChange(newValue);
|
|
104
135
|
} else {
|
|
@@ -199,7 +230,7 @@ export default function BlockEditor({
|
|
|
199
230
|
setSelectedStorybookElement(mergedValue);
|
|
200
231
|
};
|
|
201
232
|
|
|
202
|
-
const handleSidebarDeleteClick = (
|
|
233
|
+
const handleSidebarDeleteClick = () => {
|
|
203
234
|
contentfulSdk.dialogs
|
|
204
235
|
.openConfirm({
|
|
205
236
|
title: 'Element löschen',
|
|
@@ -266,6 +297,50 @@ export default function BlockEditor({
|
|
|
266
297
|
}
|
|
267
298
|
};
|
|
268
299
|
|
|
300
|
+
const handleSidebarDuplicateClick = () => {
|
|
301
|
+
let path = selectedStorybookElement.path;
|
|
302
|
+
|
|
303
|
+
let selectedStorybookElementCopy = JSON.parse(JSON.stringify({
|
|
304
|
+
...selectedStorybookElement,
|
|
305
|
+
editorAttributes: null,
|
|
306
|
+
path: null,
|
|
307
|
+
node: null,
|
|
308
|
+
}));
|
|
309
|
+
|
|
310
|
+
delete selectedStorybookElementCopy.path;
|
|
311
|
+
delete selectedStorybookElementCopy.node;
|
|
312
|
+
delete selectedStorybookElementCopy.editorAttributes;
|
|
313
|
+
|
|
314
|
+
try {
|
|
315
|
+
Transforms.insertNodes(editor, [selectedStorybookElementCopy], {at: path});
|
|
316
|
+
} catch (e) {
|
|
317
|
+
console.error(e);
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const handleSidebarInsertClick = direction => {
|
|
322
|
+
let node = ReactEditor.toSlateNode(editor, selectedStorybookElement.editorAttributes.ref.current);
|
|
323
|
+
let path = ReactEditor.findPath(editor, node);
|
|
324
|
+
|
|
325
|
+
let at;
|
|
326
|
+
|
|
327
|
+
if (direction === "above") {
|
|
328
|
+
at = [path[0]];
|
|
329
|
+
} else {
|
|
330
|
+
at = [path[0] + 1];
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
Transforms.insertNodes(editor, [
|
|
334
|
+
{
|
|
335
|
+
children: [{text: ''}],
|
|
336
|
+
block: "Blocks/Empty",
|
|
337
|
+
attributes: {blockWidth: "site"},
|
|
338
|
+
isEmpty: true,
|
|
339
|
+
type: "storybook",
|
|
340
|
+
},
|
|
341
|
+
], {at});
|
|
342
|
+
};
|
|
343
|
+
|
|
269
344
|
const handleSidebarClose = () => {
|
|
270
345
|
setSelectedStorybookElement(null);
|
|
271
346
|
};
|
|
@@ -286,7 +361,8 @@ export default function BlockEditor({
|
|
|
286
361
|
storybookStories={loadedStorybookStories}
|
|
287
362
|
isLoadingStories={isLoadingStories}
|
|
288
363
|
editor={editor}
|
|
289
|
-
sdk={contentfulSdk}
|
|
364
|
+
sdk={contentfulSdk}
|
|
365
|
+
lastSelection={lastSelection}/>
|
|
290
366
|
</div>
|
|
291
367
|
<div className="relative h-full max-h-full overflow-scroll px-8 py-4" ref={scrollContainer}>
|
|
292
368
|
{isLoading && (
|
|
@@ -331,7 +407,10 @@ export default function BlockEditor({
|
|
|
331
407
|
onClose={handleSidebarClose}
|
|
332
408
|
onDelete={handleSidebarDeleteClick}
|
|
333
409
|
onMove={handleSidebarMoveClick}
|
|
334
|
-
|
|
410
|
+
onDuplicate={handleSidebarDuplicateClick}
|
|
411
|
+
onInsert={handleSidebarInsertClick}
|
|
412
|
+
editor={editor}
|
|
413
|
+
lastSelection={lastSelection} />
|
|
335
414
|
}
|
|
336
415
|
/>
|
|
337
416
|
</div>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {Autocomplete} from "@contentful/forma-36-react-components";
|
|
2
|
+
import {
|
|
3
|
+
useEffect, useState,
|
|
4
|
+
} from "react";
|
|
5
|
+
import {Transforms} from "slate";
|
|
6
|
+
|
|
7
|
+
const devMode = localStorage.getItem("dev-mode") === "true";
|
|
8
|
+
|
|
9
|
+
export const ElementAutocomplete = ({
|
|
10
|
+
storybookStories,
|
|
11
|
+
isLoading,
|
|
12
|
+
editor,
|
|
13
|
+
storyContext = "",
|
|
14
|
+
portal,
|
|
15
|
+
lastSelection,
|
|
16
|
+
onChange,
|
|
17
|
+
...props
|
|
18
|
+
}) => {
|
|
19
|
+
const items = (storybookStories || []).map(story => {
|
|
20
|
+
let storyTitleSplit = String(story.title || "").split("/");
|
|
21
|
+
|
|
22
|
+
if (!story.id) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let splitStoryContext = String(storyContext || "").split(",");
|
|
27
|
+
let isItemInStoryContext = splitStoryContext.find(context => {
|
|
28
|
+
return Array.isArray(story.storyContext) ? story.storyContext.includes(context) : context === story.storyContext;
|
|
29
|
+
});
|
|
30
|
+
let isItemInPortalContext = !story.portalContext || story.portalContext.includes(portal);
|
|
31
|
+
|
|
32
|
+
if (!devMode && (!isItemInStoryContext || !isItemInPortalContext)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
value: story.id.toLowerCase(),
|
|
38
|
+
label: storyTitleSplit[storyTitleSplit.length - 1],
|
|
39
|
+
stories: story.stories,
|
|
40
|
+
};
|
|
41
|
+
}).filter(Boolean);
|
|
42
|
+
|
|
43
|
+
const [filteredItems, setFilteredItems] = useState(items);
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
setFilteredItems(items);
|
|
47
|
+
}, [storybookStories]);
|
|
48
|
+
|
|
49
|
+
const handleQueryChange = (query) => {
|
|
50
|
+
setFilteredItems(query ? items.filter((item) => item.label.toLowerCase().includes(query.toLowerCase())) : items);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const handleOnChange = (item) => {
|
|
54
|
+
onChange(item);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
let autoCompleteElement = document.getElementsByClassName("element-autocomplete")[0];
|
|
59
|
+
|
|
60
|
+
if (autoCompleteElement) {
|
|
61
|
+
autoCompleteElement.value = "";
|
|
62
|
+
}
|
|
63
|
+
}, []);
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<Autocomplete
|
|
67
|
+
items={filteredItems}
|
|
68
|
+
onQueryChange={handleQueryChange}
|
|
69
|
+
isLoading={isLoading}
|
|
70
|
+
placeholder={'Element hinzufügen'}
|
|
71
|
+
emptyListMessage={'Keine Komponenten gefunden'}
|
|
72
|
+
noMatchesMessage={'Keine Ergebnisse gefunden'}
|
|
73
|
+
dropdownProps={{isFullWidth: true}}
|
|
74
|
+
maxHeight={300}
|
|
75
|
+
onChange={handleOnChange}
|
|
76
|
+
width="medium"
|
|
77
|
+
{...props}
|
|
78
|
+
>
|
|
79
|
+
{(options) =>
|
|
80
|
+
options.map((option) => <span key={option.value}>{option.label}</span>)
|
|
81
|
+
}
|
|
82
|
+
</Autocomplete>
|
|
83
|
+
);
|
|
84
|
+
};
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
useEffect, useRef,
|
|
3
|
+
} from "react";
|
|
2
4
|
|
|
3
|
-
export const Resizable = ({
|
|
5
|
+
export const Resizable = ({
|
|
6
|
+
left,
|
|
7
|
+
right,
|
|
8
|
+
}) => {
|
|
4
9
|
const containerRef = useRef();
|
|
5
10
|
const leftRef = useRef();
|
|
6
11
|
const handleRef = useRef();
|
|
@@ -14,11 +19,11 @@ export const Resizable = ({left, right}) => {
|
|
|
14
19
|
if (width < 300) {
|
|
15
20
|
return 300;
|
|
16
21
|
} else if (containerRef.current.getBoundingClientRect().width - width < 300) {
|
|
17
|
-
return containerRef.current.getBoundingClientRect().width - 300
|
|
22
|
+
return containerRef.current.getBoundingClientRect().width - 300;
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
return width;
|
|
21
|
-
}
|
|
26
|
+
};
|
|
22
27
|
|
|
23
28
|
useEffect(() => {
|
|
24
29
|
if (rightRef.current) {
|
|
@@ -41,18 +46,18 @@ export const Resizable = ({left, right}) => {
|
|
|
41
46
|
return;
|
|
42
47
|
}
|
|
43
48
|
|
|
44
|
-
let newWidth = rightRef.current.resizingStartWidth - (e.pageX - rightRef.current.resizingStartMouseX)
|
|
49
|
+
let newWidth = rightRef.current.resizingStartWidth - (e.pageX - rightRef.current.resizingStartMouseX);
|
|
45
50
|
newWidth = checkWidth(newWidth);
|
|
46
51
|
|
|
47
52
|
localStorage.setItem("slate-editor-resizable-width", newWidth);
|
|
48
53
|
|
|
49
54
|
rightRef.current.style.width = newWidth + 'px';
|
|
50
|
-
}
|
|
55
|
+
};
|
|
51
56
|
const onMouseUp = (e) => {
|
|
52
57
|
if (rightRef.current) {
|
|
53
58
|
rightRef.current.resizing = false;
|
|
54
59
|
}
|
|
55
|
-
}
|
|
60
|
+
};
|
|
56
61
|
|
|
57
62
|
rightRef.current.addEventListener("mousedown", onMouseDown);
|
|
58
63
|
document.addEventListener("mousemove", onMouseMove);
|
|
@@ -64,15 +69,15 @@ export const Resizable = ({left, right}) => {
|
|
|
64
69
|
}
|
|
65
70
|
document.removeEventListener("mousemove", onMouseMove);
|
|
66
71
|
document.removeEventListener("mouseup", onMouseUp);
|
|
67
|
-
}
|
|
72
|
+
};
|
|
68
73
|
}
|
|
69
74
|
}, [right, left]);
|
|
70
75
|
|
|
71
|
-
return <div className="w-full
|
|
72
|
-
<div ref={leftRef} className="resizable-left
|
|
73
|
-
{right && <div ref={rightRef} className="resizable-right">
|
|
76
|
+
return <div className="resizable flex w-full" ref={containerRef}>
|
|
77
|
+
<div ref={leftRef} className="resizable-left grow">{left}</div>
|
|
78
|
+
{right && <div ref={rightRef} className="resizable-right shrink-0">
|
|
74
79
|
<div ref={handleRef} className="resizable-x-handle"/>
|
|
75
80
|
{right}
|
|
76
81
|
</div>}
|
|
77
|
-
</div
|
|
78
|
-
}
|
|
82
|
+
</div>;
|
|
83
|
+
};
|
|
@@ -55,7 +55,7 @@ export const SidebarEditorField = ({
|
|
|
55
55
|
));
|
|
56
56
|
} else {
|
|
57
57
|
return Object.keys(field.control.options).map(key => (
|
|
58
|
-
<option key={`select-option-${key}`} value={field.control.options[key]}>{
|
|
58
|
+
<option key={`select-option-${key}`} value={field.control.options[key]}>{key}</option>
|
|
59
59
|
));
|
|
60
60
|
}
|
|
61
61
|
};
|
package/src/SidebarEditor.js
CHANGED
|
@@ -5,6 +5,7 @@ import {SidebarEditorField} from "./SidebarEditor/SidebarEditorField";
|
|
|
5
5
|
import {ToolMargin} from "./Tools/Margin";
|
|
6
6
|
import "../scss/sidebarEditor.scss";
|
|
7
7
|
import {Spinner} from "@contentful/forma-36-react-components";
|
|
8
|
+
import {ElementAutocomplete} from "./ElementAutocomplete";
|
|
8
9
|
|
|
9
10
|
const devMode = localStorage.getItem("dev-mode") === "true";
|
|
10
11
|
|
|
@@ -16,9 +17,14 @@ const SidebarEditor = ({
|
|
|
16
17
|
onChange,
|
|
17
18
|
onDelete,
|
|
18
19
|
onMove,
|
|
20
|
+
onDuplicate,
|
|
21
|
+
onInsert,
|
|
19
22
|
editor,
|
|
20
23
|
isLoading,
|
|
24
|
+
lastSelection,
|
|
21
25
|
}) => {
|
|
26
|
+
const portal = sdk?.entry?.fields?.portal.getValue();
|
|
27
|
+
|
|
22
28
|
const [versions, setVersions] = useState([]);
|
|
23
29
|
const [lastChangedProperty, setLastChangedProperty] = useState(null);
|
|
24
30
|
const [versionCount, setVersionCount] = useState(0);
|
|
@@ -164,8 +170,33 @@ const SidebarEditor = ({
|
|
|
164
170
|
}
|
|
165
171
|
};
|
|
166
172
|
|
|
173
|
+
const handleAutocompleteChange = (item) => {
|
|
174
|
+
if (!item) {
|
|
175
|
+
return onChange({}); // reset to empty
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// reset to the first or second story
|
|
179
|
+
onChange({
|
|
180
|
+
...storybookElement,
|
|
181
|
+
block: item.value,
|
|
182
|
+
attributes: {...(item?.stories?.[0]?.args || item?.stories?.[1]?.args || {})},
|
|
183
|
+
});
|
|
184
|
+
};
|
|
185
|
+
|
|
167
186
|
useEffect(() => resetVersions, [storybookElement?.editorAttributes?.ref]);
|
|
168
187
|
|
|
188
|
+
const renderTitle = () => {
|
|
189
|
+
const story = storybookStories?.find(v => storybookElement.block?.toLowerCase() === v.id?.toLowerCase());
|
|
190
|
+
|
|
191
|
+
if (!story?.title) {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
let storyTitleSplit = String(story.title || "").split("/");
|
|
196
|
+
|
|
197
|
+
return <h2 className="mb-2 text-lg font-bold">{storyTitleSplit[storyTitleSplit.length - 1]}</h2>;
|
|
198
|
+
};
|
|
199
|
+
|
|
169
200
|
return (
|
|
170
201
|
<div id="sidebar-editor-wrapper">
|
|
171
202
|
<div id="sidebar-editor">
|
|
@@ -181,6 +212,11 @@ const SidebarEditor = ({
|
|
|
181
212
|
<div className="grow">
|
|
182
213
|
{storybookElement?.block && (
|
|
183
214
|
<div className="flex items-center">
|
|
215
|
+
<div className="mr-1 flex items-center">
|
|
216
|
+
<ToolMargin
|
|
217
|
+
margin={storybookElement.attributes.margin}
|
|
218
|
+
onChange={value => handleFieldValueChange("margin", value)} />
|
|
219
|
+
</div>
|
|
184
220
|
<div className="icon-button-group mr-1">
|
|
185
221
|
<IconButton title="Rückgängig" onClick={undo} disabled={currentVersion <= 1}>↺</IconButton>
|
|
186
222
|
<IconButton title="Wiederherstellen" onClick={redo} disabled={currentVersion >= versionCount || versionCount === 0}>↻</IconButton>
|
|
@@ -196,25 +232,34 @@ const SidebarEditor = ({
|
|
|
196
232
|
<IconButton title="Löschen" onClick={() => onDelete && onDelete(storybookElement)}>
|
|
197
233
|
🗑
|
|
198
234
|
</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
235
|
</div>
|
|
205
236
|
)}
|
|
206
237
|
</div>
|
|
207
|
-
{!!onClose && <IconButton onClick={onClose} title="Schließen"
|
|
238
|
+
{!!onClose && <IconButton onClick={onClose} title="Schließen">⨉</IconButton>}
|
|
208
239
|
</div>
|
|
209
240
|
<hr className="mt-2" style={{borderColor: "#cfd9e0"}}/>
|
|
210
241
|
</div>
|
|
211
242
|
<div className="grow overflow-y-auto pr-2 pt-2">
|
|
243
|
+
{renderTitle()}
|
|
244
|
+
<div className="mb-2">
|
|
245
|
+
<button className="button button--tertiary" onClick={onDuplicate}>Duplizieren</button>
|
|
246
|
+
</div>
|
|
247
|
+
<div className="mb-2 flex">
|
|
248
|
+
<button className="button button--tertiary mr-1" onClick={() => onInsert("above")}>Davor hinzufügen</button>
|
|
249
|
+
<button className="button button--tertiary ml-1" onClick={() => onInsert("below")}>Danach hinzufügen</button>
|
|
250
|
+
</div>
|
|
212
251
|
<div className="mb-2">
|
|
213
|
-
<
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
storyContext={sdk.parameters.instance.storyContext}
|
|
252
|
+
<ElementAutocomplete
|
|
253
|
+
isLoading={isLoading}
|
|
254
|
+
storybookStories={storybookStories}
|
|
255
|
+
editor={editor}
|
|
256
|
+
storyContext={sdk.parameters.instance.storyContext}
|
|
257
|
+
portal={portal}
|
|
258
|
+
lastSelection={lastSelection}
|
|
259
|
+
onChange={handleAutocompleteChange}
|
|
260
|
+
placeholder="Element wählen"
|
|
261
|
+
width="full"
|
|
262
|
+
/>
|
|
218
263
|
</div>
|
|
219
264
|
{storybookElement?.block && (
|
|
220
265
|
<div>
|
|
@@ -299,11 +344,14 @@ export const IconButton = ({
|
|
|
299
344
|
|
|
300
345
|
switch (size) {
|
|
301
346
|
case "small":
|
|
302
|
-
classNames += " !text-xs min-w-[28px]";
|
|
347
|
+
classNames += " !text-xs min-w-[28px] max-h-[28px]";
|
|
348
|
+
break;
|
|
349
|
+
case "big":
|
|
350
|
+
classNames += " !text-xl min-w-[32px] max-h-[28px] !leading-[18px]";
|
|
303
351
|
break;
|
|
304
352
|
case "medium":
|
|
305
353
|
default:
|
|
306
|
-
classNames += " !text-sm min-w-[32px]";
|
|
354
|
+
classNames += " !text-sm min-w-[32px] max-h-[28px]";
|
|
307
355
|
}
|
|
308
356
|
|
|
309
357
|
return (
|
|
@@ -364,108 +412,6 @@ const VariantSelect = ({
|
|
|
364
412
|
);
|
|
365
413
|
};
|
|
366
414
|
|
|
367
|
-
|
|
368
|
-
stories,
|
|
369
|
-
active,
|
|
370
|
-
onChange,
|
|
371
|
-
className,
|
|
372
|
-
storyContext,
|
|
373
|
-
}) => {
|
|
374
|
-
if (!onChange) {
|
|
375
|
-
return null;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
const onSelectChange = (story) => {
|
|
379
|
-
if (!story) {
|
|
380
|
-
return onChange({}); // reset to empty
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// reset to the first or second story
|
|
384
|
-
onChange({
|
|
385
|
-
...active,
|
|
386
|
-
block: story.id,
|
|
387
|
-
attributes: {...(story?.stories?.[0]?.args || story?.stories?.[1]?.args || {})},
|
|
388
|
-
});
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
function groupArrayToObject(array) {
|
|
392
|
-
const result = {};
|
|
393
|
-
|
|
394
|
-
array.forEach(item => {
|
|
395
|
-
if (!item?.id) {
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
let splitStoryContext = String(storyContext || "").split(",");
|
|
400
|
-
let isItemInContext = splitStoryContext.find(context => {
|
|
401
|
-
return Array.isArray(item.storyContext) ? item.storyContext.includes(context) : context === item.storyContext;
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
if (!devMode && !isItemInContext) {
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
const parts = item.title.split('/');
|
|
409
|
-
let currentLevel = result;
|
|
410
|
-
|
|
411
|
-
parts.forEach((part, index) => {
|
|
412
|
-
if (!currentLevel[part]) {
|
|
413
|
-
currentLevel[part] = {level: index};
|
|
414
|
-
}
|
|
415
|
-
currentLevel = currentLevel[part];
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
currentLevel.title = item.title;
|
|
419
|
-
currentLevel.shortTitle = parts[parts.length - 1];
|
|
420
|
-
currentLevel.id = item.id;
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
return result;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
let storyGroups = groupArrayToObject(stories);
|
|
427
|
-
|
|
428
|
-
const renderOptions = (obj) => Object.keys(obj).map((key, index) => {
|
|
429
|
-
const option = obj[key];
|
|
430
|
-
|
|
431
|
-
if (!option) {
|
|
432
|
-
return null;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
if (option.title && option.id) {
|
|
436
|
-
return (
|
|
437
|
-
<option key={option.id} value={option.id.toLowerCase()}>
|
|
438
|
-
{option.shortTitle}
|
|
439
|
-
</option>
|
|
440
|
-
);
|
|
441
|
-
} else if (typeof option === "object") {
|
|
442
|
-
return (
|
|
443
|
-
<Fragment key={`${key}-${index}`}>
|
|
444
|
-
<option
|
|
445
|
-
disabled
|
|
446
|
-
style={{
|
|
447
|
-
color: "rgba(0, 0, 0, 0.3)",
|
|
448
|
-
fontWeight: option.level === 0 ? "bold" : "normal",
|
|
449
|
-
}}>{key}</option>
|
|
450
|
-
{renderOptions(option)}
|
|
451
|
-
</Fragment>
|
|
452
|
-
);
|
|
453
|
-
}
|
|
454
|
-
});
|
|
455
|
-
|
|
456
|
-
return (
|
|
457
|
-
<div className={className}>
|
|
458
|
-
<label className="block">Element</label>
|
|
459
|
-
<select
|
|
460
|
-
onChange={e => onSelectChange(stories.find(s => s.id?.toLowerCase() === e.target.value))}
|
|
461
|
-
value={active?.block?.toLowerCase()}
|
|
462
|
-
className="font-bold"
|
|
463
|
-
>
|
|
464
|
-
<option>Element wählen</option>
|
|
465
|
-
{renderOptions(storyGroups)}
|
|
466
|
-
</select>
|
|
467
|
-
</div>
|
|
468
|
-
);
|
|
469
|
-
};
|
|
415
|
+
export default SidebarEditor;
|
|
470
416
|
|
|
471
|
-
|
|
417
|
+
// :)
|