@flozy/editor 1.2.7 → 1.2.9
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/Editor/CommonEditor.js +19 -10
- package/dist/Editor/Elements/Button/ButtonPopup.js +3 -1
- package/dist/Editor/Elements/Button/EditorButton.js +34 -5
- package/dist/Editor/Elements/Embed/Embed.js +2 -1
- package/dist/Editor/Elements/ImageText/ImageText.js +29 -2
- package/dist/Editor/Elements/Link/LinkButton.js +2 -3
- package/dist/Editor/Elements/NewLine/NewLineButton.js +8 -6
- package/dist/Editor/common/StyleBuilder/buttonStyle.js +8 -4
- package/dist/Editor/common/StyleBuilder/embedImageStyle.js +0 -8
- package/dist/Editor/common/StyleBuilder/fieldTypes/buttonLink.js +113 -0
- package/dist/Editor/common/StyleBuilder/fieldTypes/index.js +3 -1
- package/dist/Editor/plugins/withEmbeds.js +1 -0
- package/dist/Editor/service/actionTrigger.js +16 -0
- package/dist/Editor/utils/button.js +4 -1
- package/package.json +1 -1
@@ -75,15 +75,23 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
|
|
75
75
|
}));
|
76
76
|
}, [id, content]);
|
77
77
|
useEffect(() => {
|
78
|
-
if (editorWrapper && editorWrapper?.current && loadedValue !== deboundedValue && isInteracted) {
|
79
|
-
const
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
});
|
78
|
+
if (editorWrapper && editorWrapper?.current && loadedValue !== deboundedValue && isInteracted && onSave) {
|
79
|
+
const {
|
80
|
+
value: strVal,
|
81
|
+
...restVal
|
82
|
+
} = getOnSaveData(deboundedValue);
|
83
|
+
onSave(strVal, restVal);
|
85
84
|
}
|
86
85
|
}, [deboundedValue]);
|
86
|
+
const getOnSaveData = val => {
|
87
|
+
const text = serialize(val);
|
88
|
+
const title = val?.find(f => f.type === "title");
|
89
|
+
return {
|
90
|
+
value: JSON.stringify(val),
|
91
|
+
text: text,
|
92
|
+
title: serialize(title?.children) || "Untitled"
|
93
|
+
};
|
94
|
+
};
|
87
95
|
const getPreviewImage = async (needBackground = false, options = {}) => {
|
88
96
|
ReactEditor.blur(editor);
|
89
97
|
const dom = needBackground ? editorWrapper?.current : editorWrapper?.current.getElementsByClassName("innert-editor-textbox")[0];
|
@@ -119,7 +127,7 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
|
|
119
127
|
return editor;
|
120
128
|
},
|
121
129
|
getContent() {
|
122
|
-
return
|
130
|
+
return getOnSaveData(deboundedValue);
|
123
131
|
},
|
124
132
|
insertFragments(fragments) {
|
125
133
|
editor.insertNode(fragments);
|
@@ -150,8 +158,10 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
|
|
150
158
|
setIsInteracted(true);
|
151
159
|
}
|
152
160
|
};
|
161
|
+
const isReadOnly = readOnly === "readonly";
|
153
162
|
const customProps = {
|
154
|
-
...(otherProps || {})
|
163
|
+
...(otherProps || {}),
|
164
|
+
readOnly: isReadOnly
|
155
165
|
};
|
156
166
|
const renderElement = useCallback(props => {
|
157
167
|
return /*#__PURE__*/_jsx(Element, {
|
@@ -190,7 +200,6 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
|
|
190
200
|
});
|
191
201
|
}
|
192
202
|
}, [chars, editor, target, mentions, setMentions]);
|
193
|
-
const isReadOnly = readOnly === "readonly";
|
194
203
|
const Overlay = collaborativeEditor && !isReadOnly ? RemoteCursorOverlay : React.Fragment;
|
195
204
|
return /*#__PURE__*/_jsx(DialogWrapper, {
|
196
205
|
...props,
|
@@ -6,6 +6,7 @@ const ButtonPopup = props => {
|
|
6
6
|
const {
|
7
7
|
element,
|
8
8
|
onSave,
|
9
|
+
customProps,
|
9
10
|
onClose
|
10
11
|
} = props;
|
11
12
|
return /*#__PURE__*/_jsx(StyleBuilder, {
|
@@ -14,7 +15,8 @@ const ButtonPopup = props => {
|
|
14
15
|
element: element,
|
15
16
|
onSave: onSave,
|
16
17
|
onClose: onClose,
|
17
|
-
renderTabs: buttonStyle
|
18
|
+
renderTabs: buttonStyle,
|
19
|
+
customProps: customProps
|
18
20
|
});
|
19
21
|
};
|
20
22
|
export default ButtonPopup;
|
@@ -3,6 +3,7 @@ import { Transforms } from "slate";
|
|
3
3
|
import { ReactEditor, useSlateStatic } from "slate-react";
|
4
4
|
import { Menu, MenuItem } from "@mui/material";
|
5
5
|
import ButtonPopup from "./ButtonPopup";
|
6
|
+
import { actionButtonRedirect } from "../../service/actionTrigger";
|
6
7
|
import { jsx as _jsx } from "react/jsx-runtime";
|
7
8
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
8
9
|
const EditorButton = props => {
|
@@ -12,7 +13,8 @@ const EditorButton = props => {
|
|
12
13
|
customProps
|
13
14
|
} = props;
|
14
15
|
const {
|
15
|
-
readOnly
|
16
|
+
readOnly,
|
17
|
+
metadata
|
16
18
|
} = customProps;
|
17
19
|
const editor = useSlateStatic();
|
18
20
|
const path = ReactEditor.findPath(editor, element);
|
@@ -25,8 +27,13 @@ const EditorButton = props => {
|
|
25
27
|
bannerSpacing,
|
26
28
|
textColor,
|
27
29
|
url,
|
28
|
-
borderColor
|
30
|
+
borderColor,
|
31
|
+
buttonLink
|
29
32
|
} = element;
|
33
|
+
const {
|
34
|
+
linkType,
|
35
|
+
redirectOnURLResult
|
36
|
+
} = buttonLink || {};
|
30
37
|
const {
|
31
38
|
topLeft,
|
32
39
|
topRight,
|
@@ -39,13 +46,34 @@ const EditorButton = props => {
|
|
39
46
|
right,
|
40
47
|
bottom
|
41
48
|
} = bannerSpacing || {};
|
42
|
-
const onClick = e => {
|
43
|
-
|
49
|
+
const onClick = async e => {
|
50
|
+
if (readOnly) {
|
51
|
+
if (metadata?.buttonLink?.handler) {
|
52
|
+
metadata.buttonLink.handler("click");
|
53
|
+
} else if (linkType === "actionTrigger") {
|
54
|
+
if (redirectOnURLResult) {
|
55
|
+
// call api and redirect based on api result
|
56
|
+
const apiResult = await actionButtonRedirect({}, {
|
57
|
+
url: buttonLink?.url
|
58
|
+
});
|
59
|
+
window.open(apiResult, "_blank").focus();
|
60
|
+
} else {
|
61
|
+
const refUrl = buttonLink?.url ? buttonLink?.url.includes("http") ? buttonLink?.url : `//${buttonLink?.url}` : "Link";
|
62
|
+
window.open(refUrl, "_blank").focus();
|
63
|
+
}
|
64
|
+
} else {
|
65
|
+
const refUrl = url ? url.includes("http") ? url : `//${url}` : "Link";
|
66
|
+
window.open(refUrl, "_blank").focus();
|
67
|
+
}
|
68
|
+
} else {
|
69
|
+
setAnchorEl(e.currentTarget);
|
70
|
+
}
|
44
71
|
};
|
45
72
|
const handleClose = () => {
|
46
73
|
setAnchorEl(null);
|
47
74
|
};
|
48
75
|
const onMenuClick = val => () => {
|
76
|
+
console.log(val, url);
|
49
77
|
switch (val) {
|
50
78
|
case "open":
|
51
79
|
const refUrl = url ? url.includes("http") ? url : `//${url}` : "Link";
|
@@ -117,7 +145,8 @@ const EditorButton = props => {
|
|
117
145
|
}), edit && /*#__PURE__*/_jsx(ButtonPopup, {
|
118
146
|
element: element,
|
119
147
|
onSave: onSave,
|
120
|
-
onClose: onClose
|
148
|
+
onClose: onClose,
|
149
|
+
customProps: customProps
|
121
150
|
})]
|
122
151
|
});
|
123
152
|
};
|
@@ -68,6 +68,7 @@ const Embed = ({
|
|
68
68
|
[e.target.name]: e.target.value
|
69
69
|
});
|
70
70
|
};
|
71
|
+
const imageURL = formData?.url === "none" || !formData?.url ? "" : formData?.url;
|
71
72
|
return /*#__PURE__*/_jsxs(_Fragment, {
|
72
73
|
children: [/*#__PURE__*/_jsx(IconButton, {
|
73
74
|
className: isBlockActive(editor, format) ? "active" : "",
|
@@ -127,7 +128,7 @@ const Embed = ({
|
|
127
128
|
size: "small",
|
128
129
|
fullWidth: true,
|
129
130
|
onChange: handleChange,
|
130
|
-
value:
|
131
|
+
value: imageURL || ""
|
131
132
|
})
|
132
133
|
}), /*#__PURE__*/_jsx(Uploader, {
|
133
134
|
value: formData,
|
@@ -1,14 +1,41 @@
|
|
1
1
|
import React from "react";
|
2
|
+
import { IconButton } from "@mui/material";
|
3
|
+
import DeleteIcon from "@mui/icons-material/Delete";
|
4
|
+
import { Transforms } from "slate";
|
5
|
+
import { ReactEditor, useSlateStatic } from "slate-react";
|
2
6
|
import { jsx as _jsx } from "react/jsx-runtime";
|
7
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
3
8
|
const ImageText = props => {
|
4
9
|
const {
|
5
10
|
attributes,
|
11
|
+
element,
|
6
12
|
children
|
7
13
|
} = props;
|
8
|
-
|
14
|
+
const editor = useSlateStatic();
|
15
|
+
const onDelete = () => {
|
16
|
+
const path = ReactEditor.findPath(editor, element);
|
17
|
+
Transforms.removeNodes(editor, {
|
18
|
+
at: [...path]
|
19
|
+
});
|
20
|
+
};
|
21
|
+
return /*#__PURE__*/_jsxs("div", {
|
9
22
|
className: "image-text",
|
10
23
|
...attributes,
|
11
|
-
|
24
|
+
style: {
|
25
|
+
position: "relative"
|
26
|
+
},
|
27
|
+
children: [children, /*#__PURE__*/_jsx("div", {
|
28
|
+
children: /*#__PURE__*/_jsx(IconButton, {
|
29
|
+
onClick: onDelete,
|
30
|
+
style: {
|
31
|
+
background: "#FFF",
|
32
|
+
position: "absolute",
|
33
|
+
right: "0px",
|
34
|
+
top: "0px"
|
35
|
+
},
|
36
|
+
children: /*#__PURE__*/_jsx(DeleteIcon, {})
|
37
|
+
})
|
38
|
+
})]
|
12
39
|
});
|
13
40
|
};
|
14
41
|
export default ImageText;
|
@@ -1,8 +1,7 @@
|
|
1
1
|
import { useRef, useState } from "react";
|
2
2
|
import { Transforms } from "slate";
|
3
|
-
import { Dialog, DialogActions, DialogContent, DialogTitle, FormControl, FormControlLabel, Grid, TextField, Button, IconButton, Typography } from "@mui/material";
|
3
|
+
import { Dialog, DialogActions, DialogContent, DialogTitle, FormControl, FormControlLabel, Grid, TextField, Button, IconButton, Typography, Checkbox } from "@mui/material";
|
4
4
|
import CloseIcon from "@mui/icons-material/Close";
|
5
|
-
import { CheckBox } from "@mui/icons-material";
|
6
5
|
import { insertLink } from "../../utils/link";
|
7
6
|
import Icon from "../../common/Icon";
|
8
7
|
import { isBlockActive } from "../../utils/SlateUtilityFunctions";
|
@@ -112,7 +111,7 @@ const LinkButton = props => {
|
|
112
111
|
},
|
113
112
|
children: /*#__PURE__*/_jsx(FormControl, {
|
114
113
|
children: /*#__PURE__*/_jsx(FormControlLabel, {
|
115
|
-
control: /*#__PURE__*/_jsx(
|
114
|
+
control: /*#__PURE__*/_jsx(Checkbox, {
|
116
115
|
checked: showInNewTab,
|
117
116
|
onChange: handleInputChange
|
118
117
|
}),
|
@@ -2,9 +2,9 @@ import React from "react";
|
|
2
2
|
import { IconButton } from "@mui/material";
|
3
3
|
import KeyboardReturnIcon from "@mui/icons-material/KeyboardReturn";
|
4
4
|
import { Transforms } from "slate";
|
5
|
-
import { useSlateStatic } from "slate-react";
|
5
|
+
import { ReactEditor, useSlateStatic } from "slate-react";
|
6
6
|
import { jsx as _jsx } from "react/jsx-runtime";
|
7
|
-
const NewLineButton =
|
7
|
+
const NewLineButton = () => {
|
8
8
|
const editor = useSlateStatic();
|
9
9
|
const onAddNewLine = () => {
|
10
10
|
Transforms.insertNodes(editor, [{
|
@@ -13,17 +13,19 @@ const NewLineButton = props => {
|
|
13
13
|
text: ""
|
14
14
|
}]
|
15
15
|
}], {
|
16
|
-
at: [editor.children.length]
|
16
|
+
at: [editor.children.length],
|
17
|
+
select: true
|
17
18
|
});
|
19
|
+
ReactEditor.focus(editor);
|
18
20
|
};
|
19
21
|
return /*#__PURE__*/_jsx(IconButton, {
|
20
22
|
title: "New Line",
|
21
23
|
onClick: onAddNewLine,
|
22
24
|
children: /*#__PURE__*/_jsx(KeyboardReturnIcon, {
|
23
25
|
sx: {
|
24
|
-
fill:
|
25
|
-
width:
|
26
|
-
height:
|
26
|
+
fill: "#64748B",
|
27
|
+
width: "18px",
|
28
|
+
height: "18px"
|
27
29
|
}
|
28
30
|
})
|
29
31
|
});
|
@@ -5,10 +5,14 @@ const buttonStyle = [{
|
|
5
5
|
label: "Button Text",
|
6
6
|
key: "label",
|
7
7
|
type: "text"
|
8
|
-
}
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
}]
|
9
|
+
}, {
|
10
|
+
tab: "Link",
|
11
|
+
value: "link",
|
12
|
+
fields: [{
|
13
|
+
label: "Button Link",
|
14
|
+
key: "buttonLink",
|
15
|
+
type: "buttonLink"
|
12
16
|
}]
|
13
17
|
}, {
|
14
18
|
tab: "Banner Spacing",
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import { FormControl, FormLabel, RadioGroup, FormControlLabel, Grid, Radio, TextField, Select, MenuItem } from "@mui/material";
|
3
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
4
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
5
|
+
const ButtonLink = props => {
|
6
|
+
const {
|
7
|
+
value,
|
8
|
+
data,
|
9
|
+
elementProps,
|
10
|
+
customProps,
|
11
|
+
onChange
|
12
|
+
} = props;
|
13
|
+
const {
|
14
|
+
key
|
15
|
+
} = data;
|
16
|
+
const {
|
17
|
+
metadata
|
18
|
+
} = customProps || {
|
19
|
+
metadata: {}
|
20
|
+
};
|
21
|
+
const {
|
22
|
+
buttonLink
|
23
|
+
} = metadata || {
|
24
|
+
actionTrigger: {}
|
25
|
+
};
|
26
|
+
const {
|
27
|
+
actionTrigger
|
28
|
+
} = buttonLink || {};
|
29
|
+
const {
|
30
|
+
options,
|
31
|
+
onClick
|
32
|
+
} = actionTrigger || {
|
33
|
+
options: []
|
34
|
+
};
|
35
|
+
const optSelected = options.filter(f => f.selected) || [];
|
36
|
+
const handleChange = e => {
|
37
|
+
onChange({
|
38
|
+
[key]: {
|
39
|
+
...value,
|
40
|
+
[e.target.name]: e.target.value,
|
41
|
+
onClick: onClick || {}
|
42
|
+
}
|
43
|
+
});
|
44
|
+
};
|
45
|
+
const onURLChange = e => {
|
46
|
+
onChange({
|
47
|
+
url: e.target.value
|
48
|
+
});
|
49
|
+
};
|
50
|
+
const renderLinkTypeFields = () => {
|
51
|
+
if (value?.linkType === "webAddress") {
|
52
|
+
return /*#__PURE__*/_jsx(Grid, {
|
53
|
+
item: true,
|
54
|
+
xs: 12,
|
55
|
+
children: /*#__PURE__*/_jsx(TextField, {
|
56
|
+
fullWidth: true,
|
57
|
+
size: "small",
|
58
|
+
placeholder: "https://",
|
59
|
+
onChange: onURLChange,
|
60
|
+
value: elementProps?.url
|
61
|
+
})
|
62
|
+
});
|
63
|
+
} else if (value?.linkType === "actionTrigger") {
|
64
|
+
return /*#__PURE__*/_jsx(Grid, {
|
65
|
+
item: true,
|
66
|
+
xs: 12,
|
67
|
+
children: /*#__PURE__*/_jsx(Select, {
|
68
|
+
name: "actionStep",
|
69
|
+
size: "small",
|
70
|
+
fullWidth: true,
|
71
|
+
value: optSelected[0]?.value || "",
|
72
|
+
children: optSelected.map(m => {
|
73
|
+
return /*#__PURE__*/_jsx(MenuItem, {
|
74
|
+
value: m.value,
|
75
|
+
children: m.label
|
76
|
+
}, `bl_tr_opt_${m.value}`);
|
77
|
+
})
|
78
|
+
})
|
79
|
+
});
|
80
|
+
}
|
81
|
+
};
|
82
|
+
return /*#__PURE__*/_jsxs(Grid, {
|
83
|
+
container: true,
|
84
|
+
padding: 4,
|
85
|
+
spacing: 1,
|
86
|
+
children: [/*#__PURE__*/_jsx(Grid, {
|
87
|
+
item: true,
|
88
|
+
xs: 12,
|
89
|
+
children: /*#__PURE__*/_jsxs(FormControl, {
|
90
|
+
children: [/*#__PURE__*/_jsx(FormLabel, {
|
91
|
+
id: "demo-radio-buttons-group-label",
|
92
|
+
children: "Where do you want to Link?"
|
93
|
+
}), /*#__PURE__*/_jsxs(RadioGroup, {
|
94
|
+
row: true,
|
95
|
+
"aria-labelledby": "demo-radio-buttons-group-label",
|
96
|
+
value: value?.linkType || "",
|
97
|
+
name: "linkType",
|
98
|
+
onChange: handleChange,
|
99
|
+
children: [/*#__PURE__*/_jsx(FormControlLabel, {
|
100
|
+
value: "actionTrigger",
|
101
|
+
control: /*#__PURE__*/_jsx(Radio, {}),
|
102
|
+
label: "Action Trigger"
|
103
|
+
}), /*#__PURE__*/_jsx(FormControlLabel, {
|
104
|
+
value: "webAddress",
|
105
|
+
control: /*#__PURE__*/_jsx(Radio, {}),
|
106
|
+
label: "Web Address"
|
107
|
+
})]
|
108
|
+
})]
|
109
|
+
})
|
110
|
+
}), renderLinkTypeFields()]
|
111
|
+
});
|
112
|
+
};
|
113
|
+
export default ButtonLink;
|
@@ -8,6 +8,7 @@ import GridSize from "./gridSize";
|
|
8
8
|
import ElementSize from "./elementSize";
|
9
9
|
import ImageTexts from "./imageTexts";
|
10
10
|
import MenusArray from "./menusArray";
|
11
|
+
import ButtonLink from "./buttonLink";
|
11
12
|
const FieldMap = {
|
12
13
|
text: Text,
|
13
14
|
bannerSpacing: BannerSpacing,
|
@@ -18,6 +19,7 @@ const FieldMap = {
|
|
18
19
|
gridSize: GridSize,
|
19
20
|
elementSize: ElementSize,
|
20
21
|
imageTexts: ImageTexts,
|
21
|
-
menusArray: MenusArray
|
22
|
+
menusArray: MenusArray,
|
23
|
+
buttonLink: ButtonLink
|
22
24
|
};
|
23
25
|
export default FieldMap;
|
@@ -16,6 +16,7 @@ const withEmbeds = editor => {
|
|
16
16
|
editor.insertBreak = (...args) => {
|
17
17
|
const parentPath = Path.parent(editor.selection.focus.path);
|
18
18
|
const parentNode = Node.get(editor, parentPath);
|
19
|
+
console.log(parentNode, parentPath, args);
|
19
20
|
if (editor.isVoid(parentNode)) {
|
20
21
|
const nextPath = Path.next(parentPath);
|
21
22
|
Transforms.insertNodes(editor, {
|
@@ -0,0 +1,16 @@
|
|
1
|
+
export const actionButtonRedirect = async (formData, props) => {
|
2
|
+
try {
|
3
|
+
const response = await fetch(`${props.url}`, {
|
4
|
+
method: "POST",
|
5
|
+
headers: {
|
6
|
+
"Content-Type": "application/json"
|
7
|
+
},
|
8
|
+
body: JSON.stringify(formData)
|
9
|
+
});
|
10
|
+
const result = await response.json();
|
11
|
+
return result.data;
|
12
|
+
} catch (err) {
|
13
|
+
console.log(err);
|
14
|
+
return err;
|
15
|
+
}
|
16
|
+
};
|