@vonaffenfels/slate-editor 1.0.26 → 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/dist/BlockEditor.css +1 -1
- package/dist/BlockEditor.js +1 -1
- package/dist/Renderer.js +1 -1
- package/dist/index.css +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -3
- package/src/BlockEditor.js +30 -3
- package/src/Blocks/LayoutBlock.js +55 -0
- package/src/Serializer/Serializer.js +2 -0
- package/src/SidebarEditor/AssetList.js +57 -9
- package/src/SidebarEditor/SidebarEditorField.js +13 -4
- package/src/SidebarEditor.js +101 -90
- package/src/Toolbar/Block.js +16 -1
- package/src/Toolbar/Layout.js +67 -0
- package/src/dev/App.js +1 -10
- package/src/plugins/ListItem.js +3 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vonaffenfels/slate-editor",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.30",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"url-loader": "^4.1.1",
|
|
63
63
|
"util": "^0.12.5",
|
|
64
64
|
"walk-sync": "^3.0.0",
|
|
65
|
-
"webpack": "5.
|
|
65
|
+
"webpack": "5.88.2",
|
|
66
66
|
"webpack-cli": "^4.6.0",
|
|
67
67
|
"webpack-dev-server": "4.7.4"
|
|
68
68
|
},
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"cssnano": "^5.0.1",
|
|
72
72
|
"escape-html": "^1.0.3"
|
|
73
73
|
},
|
|
74
|
-
"gitHead": "
|
|
74
|
+
"gitHead": "fe88a0b3ce82331fa3d7193a4cd62b8e2c8ecfb9",
|
|
75
75
|
"publishConfig": {
|
|
76
76
|
"access": "public"
|
|
77
77
|
}
|
package/src/BlockEditor.js
CHANGED
|
@@ -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,
|
|
@@ -17,6 +17,8 @@ import "../scss/editor.scss";
|
|
|
17
17
|
import {ListItemPlugin} from "./plugins/ListItem";
|
|
18
18
|
import ErrorBoundary from "../src/Blocks/ErrorBoundary";
|
|
19
19
|
import SidebarEditor from './SidebarEditor';
|
|
20
|
+
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
|
21
|
+
import {faSpinner} from '@fortawesome/free-solid-svg-icons';
|
|
20
22
|
|
|
21
23
|
export default function BlockEditor({
|
|
22
24
|
onChange,
|
|
@@ -27,6 +29,7 @@ export default function BlockEditor({
|
|
|
27
29
|
storybookComponentDataLoader,
|
|
28
30
|
storybookStories,
|
|
29
31
|
onSaveClick,
|
|
32
|
+
isLoading,
|
|
30
33
|
}) {
|
|
31
34
|
const scrollContainer = useRef(null);
|
|
32
35
|
const [selectedStorybookElement, setSelectedStorybookElement] = useState(null);
|
|
@@ -61,6 +64,24 @@ export default function BlockEditor({
|
|
|
61
64
|
],
|
|
62
65
|
},
|
|
63
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
|
+
|
|
64
85
|
const resetEditor = () => {
|
|
65
86
|
if (confirm("This action will delete all data in the editor, are you sure?")) {
|
|
66
87
|
onChange(emptyValue);
|
|
@@ -231,7 +252,12 @@ export default function BlockEditor({
|
|
|
231
252
|
<div>
|
|
232
253
|
<Toolbar hover={false} onSaveClick={onSaveClick}/>
|
|
233
254
|
</div>
|
|
234
|
-
<div className="h-full max-h-full overflow-scroll px-8 py-4" ref={scrollContainer}>
|
|
255
|
+
<div className="relative h-full max-h-full overflow-scroll px-8 py-4" ref={scrollContainer}>
|
|
256
|
+
{isLoading && (
|
|
257
|
+
<div className='pointer-events-none fixed left-0 top-0 z-50 text-black dark:text-white' style={{padding: "61px 0 0 16px"}}>
|
|
258
|
+
<FontAwesomeIcon icon={faSpinner} pulse />
|
|
259
|
+
</div>
|
|
260
|
+
)}
|
|
235
261
|
<ErrorBoundary
|
|
236
262
|
name="editor"
|
|
237
263
|
fallback={(
|
|
@@ -261,7 +287,8 @@ export default function BlockEditor({
|
|
|
261
287
|
sdk={contentfulSdk}
|
|
262
288
|
storybookElement={selectedStorybookElement}
|
|
263
289
|
onChange={handleSidebarEditorChange}
|
|
264
|
-
storybookStories={
|
|
290
|
+
storybookStories={loadedStorybookStories}
|
|
291
|
+
isLoading={isSidebarLoading}
|
|
265
292
|
onClose={handleSidebarClose}
|
|
266
293
|
onDelete={handleSidebarDeleteClick}
|
|
267
294
|
onMove={handleSidebarMoveClick}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
|
3
3
|
import {
|
|
4
|
+
faAlignCenter,
|
|
4
5
|
faArrowDown, faArrowUp, faBorderAll, faBorderNone, faCompress, faTimes,
|
|
5
6
|
} from "@fortawesome/free-solid-svg-icons";
|
|
6
7
|
import {Transforms} from "slate";
|
|
@@ -119,6 +120,44 @@ export const LayoutBlock = ({
|
|
|
119
120
|
}, {at: fromPath});
|
|
120
121
|
};
|
|
121
122
|
|
|
123
|
+
const switchCenter = (e) => {
|
|
124
|
+
let node = ReactEditor.toSlateNode(editor, attributes.ref.current);
|
|
125
|
+
let fromPath = ReactEditor.findPath(editor, node);
|
|
126
|
+
|
|
127
|
+
if (!fromPath) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let justifyCenter = !(element?.attributes?.justifyCenter);
|
|
132
|
+
|
|
133
|
+
Transforms.setNodes(editor, {
|
|
134
|
+
type: "layout",
|
|
135
|
+
attributes: {
|
|
136
|
+
...(element.attributes || {}),
|
|
137
|
+
justifyCenter,
|
|
138
|
+
},
|
|
139
|
+
}, {at: fromPath});
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const switchBorder = (e) => {
|
|
143
|
+
let node = ReactEditor.toSlateNode(editor, attributes.ref.current);
|
|
144
|
+
let fromPath = ReactEditor.findPath(editor, node);
|
|
145
|
+
|
|
146
|
+
if (!fromPath) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
let tableBorder = !(element?.attributes?.tableBorder);
|
|
151
|
+
|
|
152
|
+
Transforms.setNodes(editor, {
|
|
153
|
+
type: "layout",
|
|
154
|
+
attributes: {
|
|
155
|
+
...(element.attributes || {}),
|
|
156
|
+
tableBorder,
|
|
157
|
+
},
|
|
158
|
+
}, {at: fromPath});
|
|
159
|
+
};
|
|
160
|
+
|
|
122
161
|
const onMarginChange = (value) => {
|
|
123
162
|
let node = ReactEditor.toSlateNode(editor, attributes.ref.current);
|
|
124
163
|
let path = ReactEditor.findPath(editor, node);
|
|
@@ -159,12 +198,28 @@ export const LayoutBlock = ({
|
|
|
159
198
|
<FontAwesomeIcon icon={faBorderAll} size="lg"/>
|
|
160
199
|
)}
|
|
161
200
|
</span>
|
|
201
|
+
<span className="options-container-option options-container-option-expand" onClick={switchCenter}>
|
|
202
|
+
{!element?.attributes?.justifyCenter ? (
|
|
203
|
+
<FontAwesomeIcon icon={faAlignCenter} size="lg"/>
|
|
204
|
+
) : (
|
|
205
|
+
<FontAwesomeIcon icon={faAlignCenter} color="#3490f3" size="lg"/>
|
|
206
|
+
)}
|
|
207
|
+
</span>
|
|
208
|
+
<span className="options-container-option options-container-option-expand-text mx-2" onClick={switchBorder}>
|
|
209
|
+
{!element?.attributes?.tableBorder ? (
|
|
210
|
+
<span>Kein Rahmen</span>
|
|
211
|
+
) : (
|
|
212
|
+
<span>Rahmen</span>
|
|
213
|
+
)}
|
|
214
|
+
</span>
|
|
162
215
|
<ToolMargin margin={element?.attributes?.margin} onChange={onMarginChange}/>
|
|
163
216
|
</div>
|
|
164
217
|
<div
|
|
165
218
|
className={`layout-block layout-grid layout-grid-cols-${children.length} ` + classNames({
|
|
166
219
|
[classNameArticle + " article-width"]: element?.attributes?.width === "article" || !element?.attributes?.width,
|
|
167
220
|
[classNameSite + " site-width"]: element?.attributes?.width === "full",
|
|
221
|
+
"block-editor-table-border-wrapper": element?.attributes?.tableBorder,
|
|
222
|
+
"justify-center": element?.attributes?.justifyCenter,
|
|
168
223
|
"space-x-4": element?.attributes?.spacing,
|
|
169
224
|
"editor-mt-large": element?.attributes?.margin?.top,
|
|
170
225
|
"editor-mr-large": element?.attributes?.margin?.right,
|
|
@@ -137,6 +137,8 @@ export function Serializer({
|
|
|
137
137
|
"mr-16": props?.attributes?.margin?.right,
|
|
138
138
|
"mb-16": props?.attributes?.margin?.bottom,
|
|
139
139
|
"ml-16": props?.attributes?.margin?.left,
|
|
140
|
+
"block-editor-table-border-wrapper": props?.attributes?.tableBorder,
|
|
141
|
+
"justify-center": props?.attributes?.justifyCenter,
|
|
140
142
|
[typeProps.classNameSite + " site-width"]: !isInSlot && (props.attributes?.width === "site" || props.attributes?.width === "full"),
|
|
141
143
|
[typeProps.classNameArticle + " article-width"]: !isInSlot && (props.attributes?.width === "article" || !props.attributes?.width),
|
|
142
144
|
})}
|
|
@@ -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
|
|
|
@@ -107,6 +132,22 @@ export const Asset = ({
|
|
|
107
132
|
return null;
|
|
108
133
|
}
|
|
109
134
|
|
|
135
|
+
let assetType = "image";
|
|
136
|
+
|
|
137
|
+
if (title?.endsWith(".mp3")) {
|
|
138
|
+
assetType = "audio";
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const renderMedia = () => {
|
|
142
|
+
switch (assetType) {
|
|
143
|
+
case "audio":
|
|
144
|
+
return <audio src={mediaUrl} className="mt-2 w-full" controls />;
|
|
145
|
+
case "image":
|
|
146
|
+
default:
|
|
147
|
+
return <img src={mediaUrl} width="100%" className="mt-2 rounded-md" />;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
110
151
|
return (
|
|
111
152
|
<div className="flex flex-col">
|
|
112
153
|
<div className="flex">
|
|
@@ -120,13 +161,20 @@ export const Asset = ({
|
|
|
120
161
|
<IconButton size="small" onClick={() => onMoveClick("down")} disabled={index === assetsLength - 1}>↓</IconButton>
|
|
121
162
|
</div>
|
|
122
163
|
)}
|
|
123
|
-
<
|
|
124
|
-
|
|
125
|
-
|
|
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>
|
|
126
174
|
<IconButton size="small" onClick={onDeleteClick}>⨯</IconButton>
|
|
127
175
|
</div>
|
|
128
176
|
</div>
|
|
129
|
-
{!!mediaUrl &&
|
|
177
|
+
{!!mediaUrl && renderMedia()}
|
|
130
178
|
</div>
|
|
131
179
|
);
|
|
132
180
|
};
|
|
@@ -122,8 +122,8 @@ export const SidebarEditorField = ({
|
|
|
122
122
|
case "object":
|
|
123
123
|
return (
|
|
124
124
|
<textarea
|
|
125
|
-
value={value || ""}
|
|
126
|
-
onChange={e => onChange(fieldKey, e.target.value)} />
|
|
125
|
+
value={typeof value === "object" ? JSON.stringify(value, null, 2) || "" : value}
|
|
126
|
+
onChange={e => onChange(fieldKey, isJson(e.target.value) ? JSON.parse(e.target.value) : e.target.value)} />
|
|
127
127
|
);
|
|
128
128
|
case "radio":
|
|
129
129
|
return (
|
|
@@ -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 => {
|
|
@@ -379,8 +379,17 @@ export const SidebarEditorField = ({
|
|
|
379
379
|
|
|
380
380
|
return (
|
|
381
381
|
<div key={`${field.name}`} className="mb-2">
|
|
382
|
-
<label className="block">{field.name}</label>
|
|
382
|
+
<label className="block">{field.name || fieldKey}</label>
|
|
383
383
|
{inputField}
|
|
384
384
|
</div>
|
|
385
385
|
);
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
const isJson = (str) => {
|
|
389
|
+
try {
|
|
390
|
+
JSON.parse(str);
|
|
391
|
+
} catch (e) {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
return true;
|
|
386
395
|
};
|
package/src/SidebarEditor.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
169
|
-
<div className="
|
|
170
|
-
<
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
<
|
|
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
|
-
|
|
181
|
-
|
|
189
|
+
</IconButton>
|
|
190
|
+
<IconButton title="Nach unten verschieben" onClick={() => onMove && onMove(storybookElement, "down")} disabled={storybookElement.path[0] === editor.children.length - 1}>
|
|
182
191
|
↓
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
192
|
+
</IconButton>
|
|
193
|
+
</div>
|
|
194
|
+
<IconButton title="Löschen" onClick={() => onDelete && onDelete(storybookElement)}>
|
|
186
195
|
🗑
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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/Toolbar/Block.js
CHANGED
|
@@ -73,8 +73,23 @@ export const toggleBlock = (editor, format, attributes) => {
|
|
|
73
73
|
|
|
74
74
|
export const isBlockActive = (editor, format, attributes) => {
|
|
75
75
|
const {selection} = editor;
|
|
76
|
+
|
|
76
77
|
if (selection) {
|
|
77
|
-
|
|
78
|
+
let selected = editor;
|
|
79
|
+
|
|
80
|
+
let reducedPath = selection.anchor.path.slice(0, -1);
|
|
81
|
+
|
|
82
|
+
for (let i = 0; i < reducedPath.length; i++) {
|
|
83
|
+
let path = reducedPath[i];
|
|
84
|
+
|
|
85
|
+
selected = selected.children[path];
|
|
86
|
+
|
|
87
|
+
if (LIST_TYPES.includes(selected.type)) {
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const selectedNodes = [selected];
|
|
78
93
|
|
|
79
94
|
return !!selectedNodes.find(v => {
|
|
80
95
|
if (Editor.isEditor(v)) {
|