@vonaffenfels/slate-editor 1.2.30 → 1.2.41
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/.babelrc +43 -43
- package/README.md +5 -5
- package/componentLoader.js +93 -93
- package/dist/BlockEditor.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/postcss.config.js +6 -6
- package/scss/demo.scss +148 -148
- package/scss/sidebarEditor.scss +185 -185
- package/scss/toolbar.scss +162 -162
- package/src/Blocks/EmptyBlock.js +11 -11
- package/src/Blocks/EmptyWrapper.js +4 -4
- package/src/Blocks/ErrorBoundary.js +40 -40
- package/src/Blocks/LayoutBlock.js +274 -274
- package/src/Blocks/LayoutSlot.js +90 -90
- package/src/CollapsableMenu/CollapsableMenu.js +48 -48
- package/src/Context/StorybookContext.js +6 -6
- package/src/ElementAutocomplete.js +134 -134
- package/src/Loader.js +137 -137
- package/src/Nodes/Default.js +162 -162
- package/src/Nodes/Leaf.js +54 -54
- package/src/Nodes/Text.js +97 -97
- package/src/ObjectId.js +3 -3
- package/src/Renderer.js +73 -73
- package/src/Serializer/Html.js +42 -42
- package/src/Serializer/Serializer.js +374 -374
- package/src/Serializer/Text.js +17 -17
- package/src/Serializer/ads.js +187 -187
- package/src/Serializer/index.js +3 -3
- package/src/SidebarEditor/AssetList.js +185 -181
- package/src/SidebarEditor/Fields/CloudinaryContentSelect.js +89 -89
- package/src/SidebarEditor/Fields/ColorPicker.js +89 -89
- package/src/SidebarEditor/Fields/ContentfulContentSelect.js +63 -62
- package/src/SidebarEditor/Fields/DateTime.js +55 -55
- package/src/SidebarEditor/Fields/MVP.js +66 -66
- package/src/SidebarEditor/Fields/MultiSelect.js +13 -13
- package/src/SidebarEditor/Fields/RemoteMultiSelect.js +40 -40
- package/src/SidebarEditor/Fields/RemoteSelect.js +39 -39
- package/src/SidebarEditor/Fields/Select.js +47 -47
- package/src/SidebarEditor/Fields/StreamSelect.js +15 -15
- package/src/SidebarEditor/Fields/Switch.js +34 -34
- package/src/SidebarEditor/Fields/Textarea.js +21 -21
- package/src/SidebarEditor/Resizable.js +85 -85
- package/src/Storybook.js +151 -151
- package/src/Toolbar/Align.js +64 -64
- package/src/Toolbar/Anchor.js +94 -94
- package/src/Toolbar/Block.js +135 -135
- package/src/Toolbar/Element.js +44 -44
- package/src/Toolbar/Formats.js +71 -71
- package/src/Toolbar/Insert.js +28 -28
- package/src/Toolbar/Layout.js +399 -399
- package/src/Toolbar/Link.js +164 -164
- package/src/Toolbar/Toolbar.js +235 -235
- package/src/Tools/Margin.js +51 -51
- package/src/Translation/TranslationToolbarButton.js +119 -119
- package/src/dev/draftToSlate.json +3147 -3147
- package/src/dev/index.css +2 -2
- package/src/dev/index.html +10 -10
- package/src/dev/index.js +4 -4
- package/src/dev/sampleValue1.json +4294 -4294
- package/src/dev/sampleValueValid.json +410 -410
- package/src/dev/testComponents/TestStory.js +74 -74
- package/src/dev/testComponents/TestStory.stories.js +216 -216
- package/src/dev/testComponents/TestStory2.js +74 -74
- package/src/dev/testComponents/TestStory2.stories.js +197 -197
- package/src/dev/testComponents/TestStory3.js +74 -74
- package/src/dev/testComponents/TestStory3.stories.js +197 -197
- package/src/dev/testSampleValue.json +746 -746
- package/src/fromHTML.js +4 -4
- package/src/helper/array.js +8 -8
- package/src/index.js +10 -10
- package/src/plugins/ListItem.js +48 -48
- package/src/plugins/SoftBreak.js +23 -23
- package/src/toHTML.js +6 -6
- package/src/toText.js +6 -6
- package/src/util/reduceContentfulResponse.js +64 -64
- package/src/util.js +19 -19
- package/storyLoader.js +47 -47
- package/tailwind.config.js +4 -4
- package/webpack.config.build.js +55 -55
- package/webpack.config.dev.js +60 -60
- package/webpack.config.js +130 -130
- package/webpack.config.watch.js +4 -4
|
@@ -1,90 +1,90 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useEffect, useState,
|
|
3
|
-
} from "react";
|
|
4
|
-
|
|
5
|
-
export const ColorPicker = ({
|
|
6
|
-
value,
|
|
7
|
-
onChange,
|
|
8
|
-
}) => {
|
|
9
|
-
const [opacity, setOpacity] = useState(1);
|
|
10
|
-
const [color, setColor] = useState(null);
|
|
11
|
-
|
|
12
|
-
const handleChange = (e) => {
|
|
13
|
-
setColor(e.target.value);
|
|
14
|
-
|
|
15
|
-
let c = e.target.value;
|
|
16
|
-
|
|
17
|
-
var rgbaCol = 'rgba(' + parseInt(c.slice(-6, -4), 16) + ',' + parseInt(c.slice(-4, -2), 16) + ',' + parseInt(c.slice(-2), 16) + ',' + opacity + ')';
|
|
18
|
-
|
|
19
|
-
onChange(rgbaCol);
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
if (!color) {
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
var rgbaCol = 'rgba(' + parseInt(color.slice(-6, -4), 16) + ',' + parseInt(color.slice(-4, -2), 16) + ',' + parseInt(color.slice(-2), 16) + ',' + opacity + ')';
|
|
28
|
-
|
|
29
|
-
onChange(rgbaCol);
|
|
30
|
-
}, [opacity]);
|
|
31
|
-
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
if (!value) {
|
|
34
|
-
setColor("#000000");
|
|
35
|
-
setOpacity(1);
|
|
36
|
-
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (value?.startsWith("rgba")) {
|
|
41
|
-
const color = parseColor(value);
|
|
42
|
-
|
|
43
|
-
setColor(convertColorToHex(value));
|
|
44
|
-
setOpacity(color.a);
|
|
45
|
-
} else {
|
|
46
|
-
setColor(value);
|
|
47
|
-
}
|
|
48
|
-
}, [value]);
|
|
49
|
-
|
|
50
|
-
return (
|
|
51
|
-
<div className="flex flex-col">
|
|
52
|
-
<input
|
|
53
|
-
type="color"
|
|
54
|
-
value={color || ""}
|
|
55
|
-
className="mb-1"
|
|
56
|
-
onChange={handleChange}/>
|
|
57
|
-
<input type="range" min="0" max="1" step="0.1" value={opacity} onChange={e => setOpacity(e.target.value)} />
|
|
58
|
-
{!!value && (
|
|
59
|
-
<button className="button button--tertiary mt-1" onClick={() => onChange(undefined)}>Zurücksetzen</button>
|
|
60
|
-
)}
|
|
61
|
-
</div>
|
|
62
|
-
);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
function convertColorToHex(inputColor) {
|
|
66
|
-
function rgbToHex(r, g, b) {
|
|
67
|
-
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Parse the input color value
|
|
71
|
-
let color;
|
|
72
|
-
if (inputColor.startsWith("#")) {
|
|
73
|
-
color = inputColor; // Already in HEX format
|
|
74
|
-
} else if (inputColor.startsWith("rgb")) {
|
|
75
|
-
color = parseColor(inputColor); // Convert to HEX format
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return rgbToHex(color.r, color.g, color.b);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const parseColor = (inputColor) => {
|
|
82
|
-
let values = inputColor.match(/[\d.]+/g);
|
|
83
|
-
|
|
84
|
-
return {
|
|
85
|
-
r: parseInt(values[0]),
|
|
86
|
-
g: parseInt(values[1]),
|
|
87
|
-
b: parseInt(values[2]),
|
|
88
|
-
a: values[3] ? parseFloat(values[3]) : undefined,
|
|
89
|
-
};
|
|
1
|
+
import {
|
|
2
|
+
useEffect, useState,
|
|
3
|
+
} from "react";
|
|
4
|
+
|
|
5
|
+
export const ColorPicker = ({
|
|
6
|
+
value,
|
|
7
|
+
onChange,
|
|
8
|
+
}) => {
|
|
9
|
+
const [opacity, setOpacity] = useState(1);
|
|
10
|
+
const [color, setColor] = useState(null);
|
|
11
|
+
|
|
12
|
+
const handleChange = (e) => {
|
|
13
|
+
setColor(e.target.value);
|
|
14
|
+
|
|
15
|
+
let c = e.target.value;
|
|
16
|
+
|
|
17
|
+
var rgbaCol = 'rgba(' + parseInt(c.slice(-6, -4), 16) + ',' + parseInt(c.slice(-4, -2), 16) + ',' + parseInt(c.slice(-2), 16) + ',' + opacity + ')';
|
|
18
|
+
|
|
19
|
+
onChange(rgbaCol);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (!color) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var rgbaCol = 'rgba(' + parseInt(color.slice(-6, -4), 16) + ',' + parseInt(color.slice(-4, -2), 16) + ',' + parseInt(color.slice(-2), 16) + ',' + opacity + ')';
|
|
28
|
+
|
|
29
|
+
onChange(rgbaCol);
|
|
30
|
+
}, [opacity]);
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (!value) {
|
|
34
|
+
setColor("#000000");
|
|
35
|
+
setOpacity(1);
|
|
36
|
+
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (value?.startsWith("rgba")) {
|
|
41
|
+
const color = parseColor(value);
|
|
42
|
+
|
|
43
|
+
setColor(convertColorToHex(value));
|
|
44
|
+
setOpacity(color.a);
|
|
45
|
+
} else {
|
|
46
|
+
setColor(value);
|
|
47
|
+
}
|
|
48
|
+
}, [value]);
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div className="flex flex-col">
|
|
52
|
+
<input
|
|
53
|
+
type="color"
|
|
54
|
+
value={color || ""}
|
|
55
|
+
className="mb-1"
|
|
56
|
+
onChange={handleChange}/>
|
|
57
|
+
<input type="range" min="0" max="1" step="0.1" value={opacity} onChange={e => setOpacity(e.target.value)} />
|
|
58
|
+
{!!value && (
|
|
59
|
+
<button className="button button--tertiary mt-1" onClick={() => onChange(undefined)}>Zurücksetzen</button>
|
|
60
|
+
)}
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function convertColorToHex(inputColor) {
|
|
66
|
+
function rgbToHex(r, g, b) {
|
|
67
|
+
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Parse the input color value
|
|
71
|
+
let color;
|
|
72
|
+
if (inputColor.startsWith("#")) {
|
|
73
|
+
color = inputColor; // Already in HEX format
|
|
74
|
+
} else if (inputColor.startsWith("rgb")) {
|
|
75
|
+
color = parseColor(inputColor); // Convert to HEX format
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return rgbToHex(color.r, color.g, color.b);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const parseColor = (inputColor) => {
|
|
82
|
+
let values = inputColor.match(/[\d.]+/g);
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
r: parseInt(values[0]),
|
|
86
|
+
g: parseInt(values[1]),
|
|
87
|
+
b: parseInt(values[2]),
|
|
88
|
+
a: values[3] ? parseFloat(values[3]) : undefined,
|
|
89
|
+
};
|
|
90
90
|
};
|
|
@@ -1,63 +1,64 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Asset, AssetList,
|
|
3
|
-
} from "../AssetList";
|
|
4
|
-
import {reduceContentfulResponse} from "../../util/reduceContentfulResponse";
|
|
5
|
-
|
|
6
|
-
export const ContentfulContentSelect = ({
|
|
7
|
-
value,
|
|
8
|
-
onChange,
|
|
9
|
-
sdk,
|
|
10
|
-
multiple,
|
|
11
|
-
field,
|
|
12
|
-
}) => {
|
|
13
|
-
if (multiple) {
|
|
14
|
-
return (
|
|
15
|
-
<>
|
|
16
|
-
{value && value.length > 0 && (
|
|
17
|
-
<details className="mb-2">
|
|
18
|
-
<summary>{value.length || 0} {value.length === 1 ? "Element" : "Elemente"}</summary>
|
|
19
|
-
<div className="mt-4">
|
|
20
|
-
<AssetList
|
|
21
|
-
assets={value}
|
|
22
|
-
sdk={sdk}
|
|
23
|
-
onChange={onChange}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
1
|
+
import {
|
|
2
|
+
Asset, AssetList,
|
|
3
|
+
} from "../AssetList";
|
|
4
|
+
import {reduceContentfulResponse} from "../../util/reduceContentfulResponse";
|
|
5
|
+
|
|
6
|
+
export const ContentfulContentSelect = ({
|
|
7
|
+
value,
|
|
8
|
+
onChange,
|
|
9
|
+
sdk,
|
|
10
|
+
multiple,
|
|
11
|
+
field,
|
|
12
|
+
}) => {
|
|
13
|
+
if (multiple) {
|
|
14
|
+
return (
|
|
15
|
+
<>
|
|
16
|
+
{value && value.length > 0 && (
|
|
17
|
+
<details className="mb-2">
|
|
18
|
+
<summary>{value.length || 0} {value.length === 1 ? "Element" : "Elemente"}</summary>
|
|
19
|
+
<div className="mt-4">
|
|
20
|
+
<AssetList
|
|
21
|
+
assets={value}
|
|
22
|
+
sdk={sdk}
|
|
23
|
+
onChange={onChange}
|
|
24
|
+
displayField={field.control.displayField}
|
|
25
|
+
onAddClick={() => {
|
|
26
|
+
sdk.dialogs.selectMultipleEntries({contentTypes: field.control.contentTypes}).then(contents => {
|
|
27
|
+
onChange(reduceContentfulResponse([...value, ...contents], field.control.paths));
|
|
28
|
+
});
|
|
29
|
+
}}/>
|
|
30
|
+
</div>
|
|
31
|
+
</details>
|
|
32
|
+
)}
|
|
33
|
+
<button
|
|
34
|
+
className="button"
|
|
35
|
+
onClick={() => {
|
|
36
|
+
sdk.dialogs.selectMultipleEntries({contentTypes: field.control.contentTypes}).then(contents => {
|
|
37
|
+
onChange(reduceContentfulResponse(contents, field.control.paths));
|
|
38
|
+
});
|
|
39
|
+
}}
|
|
40
|
+
>Auswählen
|
|
41
|
+
</button>
|
|
42
|
+
</>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<>
|
|
48
|
+
{!!value && <div className="mb-2"><Asset
|
|
49
|
+
sdk={sdk}
|
|
50
|
+
asset={value}
|
|
51
|
+
onDeleteClick={() => onChange(null)}
|
|
52
|
+
onChange={onChange}/></div>}
|
|
53
|
+
<button
|
|
54
|
+
className="button"
|
|
55
|
+
onClick={() => {
|
|
56
|
+
sdk.dialogs.selectSingleEntry({contentTypes: field.control.contentTypes}).then(content => {
|
|
57
|
+
onChange(reduceContentfulResponse(content, field.control.paths));
|
|
58
|
+
});
|
|
59
|
+
}}
|
|
60
|
+
>Auswählen
|
|
61
|
+
</button>
|
|
62
|
+
</>
|
|
63
|
+
);
|
|
63
64
|
};
|
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
import classNames from "classnames";
|
|
2
|
-
|
|
3
|
-
export const DateTime = ({
|
|
4
|
-
value,
|
|
5
|
-
onChange,
|
|
6
|
-
className,
|
|
7
|
-
inline,
|
|
8
|
-
...props
|
|
9
|
-
}) => {
|
|
10
|
-
// Separate date and time values
|
|
11
|
-
const dateValue = value ? value.split("T")[0] : "";
|
|
12
|
-
const timeValue = value ? value.split("T")[1] : "";
|
|
13
|
-
|
|
14
|
-
// Handle changes for date and time inputs
|
|
15
|
-
const handleDateChange = (e) => {
|
|
16
|
-
const newDate = e.target.value;
|
|
17
|
-
const newDateTime = `${newDate}T${timeValue || "00:00"}`;
|
|
18
|
-
onChange(newDateTime);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const handleTimeChange = (e) => {
|
|
22
|
-
const newTime = e.target.value;
|
|
23
|
-
const newDateTime = `${dateValue || "1970-01-01"}T${newTime}`;
|
|
24
|
-
onChange(newDateTime);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
return (
|
|
28
|
-
<div className={classNames(className, "grid gap-2", {
|
|
29
|
-
"grid-cols-2": inline,
|
|
30
|
-
"grid-cols-1": !inline,
|
|
31
|
-
})}>
|
|
32
|
-
{/* Date input */}
|
|
33
|
-
<input
|
|
34
|
-
type="date"
|
|
35
|
-
className="w-full"
|
|
36
|
-
value={dateValue}
|
|
37
|
-
onChange={handleDateChange}
|
|
38
|
-
{...props}
|
|
39
|
-
/>
|
|
40
|
-
|
|
41
|
-
{/* Time input */}
|
|
42
|
-
<input
|
|
43
|
-
type="time"
|
|
44
|
-
className="w-full"
|
|
45
|
-
value={timeValue}
|
|
46
|
-
onChange={handleTimeChange}
|
|
47
|
-
{...props}
|
|
48
|
-
/>
|
|
49
|
-
|
|
50
|
-
{!!value && (
|
|
51
|
-
<button className="button button--tertiary" onClick={() => onChange(undefined)}>Zurücksetzen</button>
|
|
52
|
-
)}
|
|
53
|
-
</div>
|
|
54
|
-
);
|
|
55
|
-
};
|
|
1
|
+
import classNames from "classnames";
|
|
2
|
+
|
|
3
|
+
export const DateTime = ({
|
|
4
|
+
value,
|
|
5
|
+
onChange,
|
|
6
|
+
className,
|
|
7
|
+
inline,
|
|
8
|
+
...props
|
|
9
|
+
}) => {
|
|
10
|
+
// Separate date and time values
|
|
11
|
+
const dateValue = value ? value.split("T")[0] : "";
|
|
12
|
+
const timeValue = value ? value.split("T")[1] : "";
|
|
13
|
+
|
|
14
|
+
// Handle changes for date and time inputs
|
|
15
|
+
const handleDateChange = (e) => {
|
|
16
|
+
const newDate = e.target.value;
|
|
17
|
+
const newDateTime = `${newDate}T${timeValue || "00:00"}`;
|
|
18
|
+
onChange(newDateTime);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const handleTimeChange = (e) => {
|
|
22
|
+
const newTime = e.target.value;
|
|
23
|
+
const newDateTime = `${dateValue || "1970-01-01"}T${newTime}`;
|
|
24
|
+
onChange(newDateTime);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div className={classNames(className, "grid gap-2", {
|
|
29
|
+
"grid-cols-2": inline,
|
|
30
|
+
"grid-cols-1": !inline,
|
|
31
|
+
})}>
|
|
32
|
+
{/* Date input */}
|
|
33
|
+
<input
|
|
34
|
+
type="date"
|
|
35
|
+
className="w-full"
|
|
36
|
+
value={dateValue}
|
|
37
|
+
onChange={handleDateChange}
|
|
38
|
+
{...props}
|
|
39
|
+
/>
|
|
40
|
+
|
|
41
|
+
{/* Time input */}
|
|
42
|
+
<input
|
|
43
|
+
type="time"
|
|
44
|
+
className="w-full"
|
|
45
|
+
value={timeValue}
|
|
46
|
+
onChange={handleTimeChange}
|
|
47
|
+
{...props}
|
|
48
|
+
/>
|
|
49
|
+
|
|
50
|
+
{!!value && (
|
|
51
|
+
<button className="button button--tertiary" onClick={() => onChange(undefined)}>Zurücksetzen</button>
|
|
52
|
+
)}
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
import {IconButton} from "../../SidebarEditor";
|
|
2
|
-
import {SidebarEditorField} from "../SidebarEditorField";
|
|
3
|
-
|
|
4
|
-
export const MVP = ({
|
|
5
|
-
value,
|
|
6
|
-
onChange,
|
|
7
|
-
onMove,
|
|
8
|
-
onDelete,
|
|
9
|
-
field,
|
|
10
|
-
fieldKey,
|
|
11
|
-
storybookElement,
|
|
12
|
-
sdk,
|
|
13
|
-
}) => {
|
|
14
|
-
return (
|
|
15
|
-
<details>
|
|
16
|
-
<summary>{value?.length || 0} {value?.length === 1 ? "Element" : "Elemente"}</summary>
|
|
17
|
-
<div className="mt-4">
|
|
18
|
-
{value?.map((f, index) => {
|
|
19
|
-
return (
|
|
20
|
-
<div className="mb-4" key={`mvp-${index}`}>
|
|
21
|
-
<div className="mb-2 flex items-center">
|
|
22
|
-
<b className="grow">{field.name} [{index.toString()}]</b>
|
|
23
|
-
<div className="icon-button-group mr-1">
|
|
24
|
-
<IconButton
|
|
25
|
-
size="small"
|
|
26
|
-
onClick={() => onMove("up", index)}
|
|
27
|
-
disabled={index === 0}>↑</IconButton>
|
|
28
|
-
<IconButton
|
|
29
|
-
size="small"
|
|
30
|
-
onClick={() => onMove("down", index)}
|
|
31
|
-
disabled={index === value?.length - 1}>↓</IconButton>
|
|
32
|
-
</div>
|
|
33
|
-
<IconButton
|
|
34
|
-
size="small"
|
|
35
|
-
onClick={() => onDelete(index)}>🗑</IconButton>
|
|
36
|
-
</div>
|
|
37
|
-
{Object.keys(field.control.fields).map((key) => {
|
|
38
|
-
let mvpField = field.control.fields[key];
|
|
39
|
-
let mvpValue = value?.[index]?.[key];
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<div key={`mvp-field-${key}`}>
|
|
43
|
-
<SidebarEditorField
|
|
44
|
-
field={mvpField}
|
|
45
|
-
fieldKey={fieldKey}
|
|
46
|
-
value={mvpValue}
|
|
47
|
-
storybookElement={storybookElement}
|
|
48
|
-
sdk={sdk}
|
|
49
|
-
onChange={(fK, value) => onChange(
|
|
50
|
-
fK, value, key, index,
|
|
51
|
-
)}/>
|
|
52
|
-
</div>
|
|
53
|
-
);
|
|
54
|
-
})}
|
|
55
|
-
<hr className="my-4" style={{borderColor: "rgb(174, 193, 204)"}}/>
|
|
56
|
-
</div>
|
|
57
|
-
);
|
|
58
|
-
})}
|
|
59
|
-
<button
|
|
60
|
-
className="button button--secondary"
|
|
61
|
-
onClick={() => onChange(fieldKey, [...(value || []), {}])}>Neue
|
|
62
|
-
Zeile
|
|
63
|
-
</button>
|
|
64
|
-
</div>
|
|
65
|
-
</details>
|
|
66
|
-
);
|
|
1
|
+
import {IconButton} from "../../SidebarEditor";
|
|
2
|
+
import {SidebarEditorField} from "../SidebarEditorField";
|
|
3
|
+
|
|
4
|
+
export const MVP = ({
|
|
5
|
+
value,
|
|
6
|
+
onChange,
|
|
7
|
+
onMove,
|
|
8
|
+
onDelete,
|
|
9
|
+
field,
|
|
10
|
+
fieldKey,
|
|
11
|
+
storybookElement,
|
|
12
|
+
sdk,
|
|
13
|
+
}) => {
|
|
14
|
+
return (
|
|
15
|
+
<details>
|
|
16
|
+
<summary>{value?.length || 0} {value?.length === 1 ? "Element" : "Elemente"}</summary>
|
|
17
|
+
<div className="mt-4">
|
|
18
|
+
{value?.map((f, index) => {
|
|
19
|
+
return (
|
|
20
|
+
<div className="mb-4" key={`mvp-${index}`}>
|
|
21
|
+
<div className="mb-2 flex items-center">
|
|
22
|
+
<b className="grow">{field.name} [{index.toString()}]</b>
|
|
23
|
+
<div className="icon-button-group mr-1">
|
|
24
|
+
<IconButton
|
|
25
|
+
size="small"
|
|
26
|
+
onClick={() => onMove("up", index)}
|
|
27
|
+
disabled={index === 0}>↑</IconButton>
|
|
28
|
+
<IconButton
|
|
29
|
+
size="small"
|
|
30
|
+
onClick={() => onMove("down", index)}
|
|
31
|
+
disabled={index === value?.length - 1}>↓</IconButton>
|
|
32
|
+
</div>
|
|
33
|
+
<IconButton
|
|
34
|
+
size="small"
|
|
35
|
+
onClick={() => onDelete(index)}>🗑</IconButton>
|
|
36
|
+
</div>
|
|
37
|
+
{Object.keys(field.control.fields).map((key) => {
|
|
38
|
+
let mvpField = field.control.fields[key];
|
|
39
|
+
let mvpValue = value?.[index]?.[key];
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<div key={`mvp-field-${key}`}>
|
|
43
|
+
<SidebarEditorField
|
|
44
|
+
field={mvpField}
|
|
45
|
+
fieldKey={fieldKey}
|
|
46
|
+
value={mvpValue}
|
|
47
|
+
storybookElement={storybookElement}
|
|
48
|
+
sdk={sdk}
|
|
49
|
+
onChange={(fK, value) => onChange(
|
|
50
|
+
fK, value, key, index,
|
|
51
|
+
)}/>
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
})}
|
|
55
|
+
<hr className="my-4" style={{borderColor: "rgb(174, 193, 204)"}}/>
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
})}
|
|
59
|
+
<button
|
|
60
|
+
className="button button--secondary"
|
|
61
|
+
onClick={() => onChange(fieldKey, [...(value || []), {}])}>Neue
|
|
62
|
+
Zeile
|
|
63
|
+
</button>
|
|
64
|
+
</div>
|
|
65
|
+
</details>
|
|
66
|
+
);
|
|
67
67
|
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {renderFieldSelectOptions} from "./Select";
|
|
2
|
-
|
|
3
|
-
export const MultiSelect = ({
|
|
4
|
-
value,
|
|
5
|
-
field,
|
|
6
|
-
onChange,
|
|
7
|
-
}) => {
|
|
8
|
-
return <select
|
|
9
|
-
multiple
|
|
10
|
-
value={value}
|
|
11
|
-
onChange={onChange}>
|
|
12
|
-
{renderFieldSelectOptions(field)}
|
|
13
|
-
</select>;
|
|
1
|
+
import {renderFieldSelectOptions} from "./Select";
|
|
2
|
+
|
|
3
|
+
export const MultiSelect = ({
|
|
4
|
+
value,
|
|
5
|
+
field,
|
|
6
|
+
onChange,
|
|
7
|
+
}) => {
|
|
8
|
+
return <select
|
|
9
|
+
multiple
|
|
10
|
+
value={value}
|
|
11
|
+
onChange={onChange}>
|
|
12
|
+
{renderFieldSelectOptions(field)}
|
|
13
|
+
</select>;
|
|
14
14
|
};
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import {RemoteSelect} from "./RemoteSelect";
|
|
2
|
-
import {renderFieldSelectOptions} from "./Select";
|
|
3
|
-
import {
|
|
4
|
-
useEffect, useState,
|
|
5
|
-
} from "react";
|
|
6
|
-
|
|
7
|
-
export const RemoteMultiSelect = ({
|
|
8
|
-
value = [],
|
|
9
|
-
field,
|
|
10
|
-
onChange,
|
|
11
|
-
}) => {
|
|
12
|
-
const [options, setOptions] = useState([]);
|
|
13
|
-
|
|
14
|
-
const renderSelected = (value || []).map((v, index) => {
|
|
15
|
-
let label = (options || []).find(o => o.value === v)?.label || v;
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<div key={`remote-multi-select-selected-${index}`} title={label} className="mb-1 mr-1 inline-flex overflow-hidden rounded-md bg-[#036fe3] p-2">
|
|
19
|
-
<p className="mr-2 max-w-[150px] truncate !text-white">
|
|
20
|
-
{label}
|
|
21
|
-
</p>
|
|
22
|
-
<button onClick={() => onChange(value.filter((_, i) => i !== index))} className="!text-white">⨯</button>
|
|
23
|
-
</div>
|
|
24
|
-
);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const handleChange = e => {
|
|
28
|
-
if (!e?.target?.value) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
onChange([...value, e.target.value]);
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<div>
|
|
37
|
-
{renderSelected}
|
|
38
|
-
<RemoteSelect onChange={handleChange} field={field} onOptionsChange={opts => setOptions(opts)} />
|
|
39
|
-
</div>
|
|
40
|
-
);
|
|
1
|
+
import {RemoteSelect} from "./RemoteSelect";
|
|
2
|
+
import {renderFieldSelectOptions} from "./Select";
|
|
3
|
+
import {
|
|
4
|
+
useEffect, useState,
|
|
5
|
+
} from "react";
|
|
6
|
+
|
|
7
|
+
export const RemoteMultiSelect = ({
|
|
8
|
+
value = [],
|
|
9
|
+
field,
|
|
10
|
+
onChange,
|
|
11
|
+
}) => {
|
|
12
|
+
const [options, setOptions] = useState([]);
|
|
13
|
+
|
|
14
|
+
const renderSelected = (value || []).map((v, index) => {
|
|
15
|
+
let label = (options || []).find(o => o.value === v)?.label || v;
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div key={`remote-multi-select-selected-${index}`} title={label} className="mb-1 mr-1 inline-flex overflow-hidden rounded-md bg-[#036fe3] p-2">
|
|
19
|
+
<p className="mr-2 max-w-[150px] truncate !text-white">
|
|
20
|
+
{label}
|
|
21
|
+
</p>
|
|
22
|
+
<button onClick={() => onChange(value.filter((_, i) => i !== index))} className="!text-white">⨯</button>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const handleChange = e => {
|
|
28
|
+
if (!e?.target?.value) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
onChange([...value, e.target.value]);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div>
|
|
37
|
+
{renderSelected}
|
|
38
|
+
<RemoteSelect onChange={handleChange} field={field} onOptionsChange={opts => setOptions(opts)} />
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
41
|
};
|