@flozy/editor 1.4.4 → 1.4.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,6 +3,8 @@ import { createEditor } from "slate";
3
3
  import { Slate, Editable, ReactEditor } from "slate-react";
4
4
  import { DndContext, DragOverlay } from "@dnd-kit/core";
5
5
  import { useDebounce } from "use-debounce";
6
+ // import { onKeyDown as linkifyOnKeyDown } from '@mercuriya/slate-linkify';
7
+
6
8
  import Toolbar from "./Toolbar/Toolbar";
7
9
  import { getMarked, getBlock } from "./utils/SlateUtilityFunctions";
8
10
  import CodeToText from "./Elements/CodeToText/CodeToText";
@@ -242,6 +244,8 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
242
244
  event,
243
245
  editor
244
246
  });
247
+ } else {
248
+ // linkifyOnKeyDown(event, editor);
245
249
  }
246
250
  }, [chars, editor, target, mentions, setMentions]);
247
251
  const handleDragStart = e => {
@@ -97,6 +97,8 @@ blockquote {
97
97
  padding: 0px;
98
98
  position: relative;
99
99
  flex-wrap: wrap;
100
+ background-repeat: no-repeat;
101
+ background-size: cover;
100
102
  }
101
103
 
102
104
  .grid-container-toolbar,
@@ -1,6 +1,6 @@
1
1
  import React, { useRef, useState } from "react";
2
2
  import { useSlateStatic, ReactEditor } from "slate-react";
3
- import { Transforms } from "slate";
3
+ import { Transforms, Editor, Element } from "slate";
4
4
  import AppBar from "@mui/material/AppBar";
5
5
  import Box from "@mui/material/Box";
6
6
  import CssBaseline from "@mui/material/CssBaseline";
@@ -63,7 +63,8 @@ function AppHeader(props) {
63
63
  const handleDrawerToggle = () => {
64
64
  setMobileOpen(prevState => !prevState);
65
65
  };
66
- const onSettings = () => {
66
+ const onSettings = e => {
67
+ e.stopPropagation();
67
68
  setOpenSettings(true);
68
69
  };
69
70
  const ToolBar = () => {
@@ -103,7 +104,8 @@ function AppHeader(props) {
103
104
  });
104
105
  onClose();
105
106
  };
106
- const onDelete = () => {
107
+ const onDelete = e => {
108
+ e.stopPropagation();
107
109
  Transforms.removeNodes(editor, {
108
110
  at: path
109
111
  });
@@ -111,6 +113,20 @@ function AppHeader(props) {
111
113
  const onClose = () => {
112
114
  setOpenSettings(false);
113
115
  };
116
+ const handleFocus = e => {
117
+ e.preventDefault();
118
+ try {
119
+ const [[, gridItemPath]] = Editor.nodes(editor, {
120
+ at: path,
121
+ match: n => !Editor.isEditor(n) && Element.isElement(n) && n.type === "grid-item"
122
+ });
123
+ if (gridItemPath) {
124
+ Transforms.select(editor, gridItemPath);
125
+ }
126
+ } catch (err) {
127
+ console.log(err);
128
+ }
129
+ };
114
130
 
115
131
  // const onMenuSettings = (menuItem, i) => (event) => {
116
132
  // event.preventDefault();
@@ -168,6 +184,7 @@ function AppHeader(props) {
168
184
  },
169
185
  ...attributes,
170
186
  contentEditable: false,
187
+ onClick: handleFocus,
171
188
  children: [/*#__PURE__*/_jsxs("div", {
172
189
  ref: navWrprRef,
173
190
  style: {
@@ -1,17 +1,28 @@
1
- import React from "react";
1
+ import React, { useState } from "react";
2
+ import { Transforms } from "slate";
3
+ import { useSlateStatic, ReactEditor } from "slate-react";
4
+ import * as fIcons from "@mui/icons-material";
5
+ import ChipTextPopup from "./ChipTextPopup";
2
6
  import { jsx as _jsx } from "react/jsx-runtime";
7
+ import { jsxs as _jsxs } from "react/jsx-runtime";
3
8
  const ChipText = props => {
4
9
  const {
5
10
  attributes,
6
- children,
7
- element
11
+ element,
12
+ customProps,
13
+ children
8
14
  } = props;
15
+ const {
16
+ readOnly
17
+ } = customProps;
9
18
  const {
10
19
  bgColor,
11
20
  textColor,
12
21
  bannerSpacing,
13
22
  borderRadius,
14
- borderColor
23
+ borderColor,
24
+ buttonIcon,
25
+ textSize
15
26
  } = element;
16
27
  const {
17
28
  left,
@@ -25,12 +36,51 @@ const ChipText = props => {
25
36
  bottomLeft,
26
37
  bottomRight
27
38
  } = borderRadius || {};
28
- return /*#__PURE__*/_jsx("button", {
39
+ const BtnIcon = buttonIcon ? fIcons[buttonIcon] : fIcons["Check"];
40
+ const [openSetttings, setOpenSettings] = useState(false);
41
+ const editor = useSlateStatic();
42
+ const path = ReactEditor.findPath(editor, element);
43
+ const handleStyle = () => {
44
+ if (!readOnly) {
45
+ setOpenSettings(true);
46
+ }
47
+ };
48
+ const onClose = () => {
49
+ setOpenSettings(false);
50
+ };
51
+ const onSave = data => {
52
+ try {
53
+ const updateData = {
54
+ ...data
55
+ };
56
+ delete updateData.children;
57
+ Transforms.setNodes(editor, {
58
+ ...updateData
59
+ }, {
60
+ at: path
61
+ });
62
+ onClose();
63
+ } catch (err) {
64
+ console.log(err);
65
+ }
66
+ };
67
+ const onDelete = () => {
68
+ try {
69
+ Transforms.removeNodes(editor, {
70
+ at: path
71
+ });
72
+ onClose();
73
+ } catch (err) {
74
+ console.log(err);
75
+ }
76
+ };
77
+ return /*#__PURE__*/_jsxs("button", {
29
78
  ...attributes,
30
79
  className: "editor-chip-text",
31
80
  contentEditable: false,
32
81
  style: {
33
- display: "inline",
82
+ display: "inline-block",
83
+ verticalAlign: "middle",
34
84
  paddingLeft: `${left}px`,
35
85
  paddingRight: `${right}px`,
36
86
  paddingTop: `${top}px`,
@@ -40,10 +90,30 @@ const ChipText = props => {
40
90
  background: bgColor || "#CCC",
41
91
  color: textColor
42
92
  },
43
- children: /*#__PURE__*/_jsx("div", {
44
- contentEditable: true,
93
+ children: [/*#__PURE__*/_jsx(BtnIcon, {
94
+ style: {
95
+ fontSize: textSize || "16px",
96
+ lineHeight: textSize || "16px",
97
+ display: "inline-block",
98
+ verticalAlign: "middle"
99
+ },
100
+ onClick: handleStyle
101
+ }), /*#__PURE__*/_jsx("div", {
102
+ contentEditable: false,
103
+ style: {
104
+ display: "inline-block",
105
+ verticalAlign: "middle",
106
+ fontSize: textSize || "16px",
107
+ width: "0px"
108
+ },
45
109
  children: children
46
- })
110
+ }), openSetttings !== false ? /*#__PURE__*/_jsx(ChipTextPopup, {
111
+ element: element || {},
112
+ onSave: onSave,
113
+ onClose: onClose,
114
+ onDelete: onDelete,
115
+ customProps: customProps
116
+ }) : null]
47
117
  });
48
118
  };
49
119
  export default ChipText;
@@ -1,68 +1,29 @@
1
- import React, { useState } from "react";
2
- import { Editor, Transforms } from "slate";
1
+ import React from "react";
3
2
  import { IconButton } from "@mui/material";
4
3
  import SmartButtonIcon from "@mui/icons-material/SmartButton";
5
- import { insertChipText, removeChipText } from "../../utils/insertChipText";
6
- import ChipTextPopup from "./ChipTextPopup";
4
+ import { insertChipText } from "../../utils/insertChipText";
7
5
  import { jsx as _jsx } from "react/jsx-runtime";
8
6
  import { Fragment as _Fragment } from "react/jsx-runtime";
9
- import { jsxs as _jsxs } from "react/jsx-runtime";
10
7
  const ChipTextButton = props => {
11
8
  const {
12
- editor,
13
- customProps
9
+ editor
14
10
  } = props;
15
- const [openSetttings, setOpenSettings] = useState(false);
16
11
  const handleClick = () => {
17
- const [parent, parentPath] = Editor.parent(editor, editor.selection.focus.path);
18
- if (parent && parent?.type === "chip-text") {
19
- setOpenSettings({
20
- element: parent,
21
- path: parentPath
22
- });
23
- // removeChipText(editor, parentPath);
24
- } else {
25
- insertChipText(editor, {
26
- url: "",
27
- showInNewTab: false
28
- });
29
- }
30
- };
31
- const onSave = data => {
32
- const updateData = {
33
- ...data
34
- };
35
- delete updateData.children;
36
- Transforms.setNodes(editor, {
37
- ...updateData
38
- }, {
39
- at: openSetttings?.path
12
+ insertChipText(editor, {
13
+ url: "",
14
+ showInNewTab: false
40
15
  });
41
- onClose();
42
- };
43
- const onClose = () => {
44
- setOpenSettings(false);
45
- };
46
- const onDelete = () => {
47
- removeChipText(editor, openSetttings?.path);
48
- onClose();
49
16
  };
50
- return /*#__PURE__*/_jsxs(_Fragment, {
51
- children: [/*#__PURE__*/_jsx(IconButton, {
52
- title: "Chip Text",
17
+ return /*#__PURE__*/_jsx(_Fragment, {
18
+ children: /*#__PURE__*/_jsx(IconButton, {
19
+ title: "Icon",
53
20
  onClick: handleClick,
54
21
  children: /*#__PURE__*/_jsx(SmartButtonIcon, {
55
22
  sx: {
56
- fill: '#64748B'
23
+ fill: "#64748B"
57
24
  }
58
25
  })
59
- }), openSetttings !== false ? /*#__PURE__*/_jsx(ChipTextPopup, {
60
- element: openSetttings?.element || {},
61
- onSave: onSave,
62
- onClose: onClose,
63
- onDelete: onDelete,
64
- customProps: customProps
65
- }) : null]
26
+ })
66
27
  });
67
28
  };
68
29
  export default ChipTextButton;
@@ -1,16 +1,14 @@
1
1
  import React, { useRef, useState } from "react";
2
2
  import { ReactEditor } from "slate-react";
3
3
  import Button from "../../common/Button";
4
- import { colors } from "./defaultColors";
5
4
  import { addMarkData, activeMark } from "../../utils/SlateUtilityFunctions";
6
5
  import { Transforms } from "slate";
7
6
  import usePopup from "../../utils/customHooks/usePopup";
8
7
  import { logo } from "./LogoIcon";
9
8
  import "./ColorPicker.css";
10
- import { ButtonBase } from "@mui/material";
9
+ import ColorPickerTool from "react-gcolor-picker";
11
10
  import { jsx as _jsx } from "react/jsx-runtime";
12
11
  import { jsxs as _jsxs } from "react/jsx-runtime";
13
- import { Fragment as _Fragment } from "react/jsx-runtime";
14
12
  const DEFAULT_COLOR = {
15
13
  color: "#000000",
16
14
  bgcolor: "#FFFFFF"
@@ -22,53 +20,31 @@ const ColorPicker = ({
22
20
  title
23
21
  }) => {
24
22
  const [selection, setSelection] = useState();
25
- const [hexValue, setHexValue] = useState("");
26
- const [validHex, setValidHex] = useState();
27
23
  const colorPickerRef = useRef(null);
28
24
  const [showOptions, setShowOptions] = usePopup(colorPickerRef);
29
- const isValideHexSix = new RegExp("^#[0-9A-Za-z]{6}");
30
- const isValideHexThree = new RegExp("^#[0-9A-Za-z]{3}");
31
- const changeColor = e => {
32
- const clickedColor = e.target.getAttribute("data-value");
33
- selection && Transforms.select(editor, selection);
34
- selection && ReactEditor.focus(editor);
35
- addMarkData(editor, {
36
- format,
37
- value: clickedColor
38
- });
39
- setShowOptions(false);
40
- };
41
- const toggleOption = () => {
25
+ const toggleOption = e => {
42
26
  setSelection(editor.selection);
43
27
  selection && ReactEditor.focus(editor);
44
28
  setShowOptions(prev => !prev);
45
29
  };
46
- const handleFormSubmit = e => {
47
- e.preventDefault();
48
- if (!validHex) return;
30
+ const handleFormSubmit = color => {
31
+ if (!color) return;
49
32
  selection && Transforms.select(editor, selection);
50
33
  addMarkData(editor, {
51
34
  format,
52
- value: hexValue
35
+ value: color
53
36
  });
54
37
  setShowOptions(false);
55
- setValidHex("");
56
- setHexValue("");
57
38
  selection && ReactEditor.focus(editor);
58
39
  };
59
- const handleHexChange = e => {
60
- e.preventDefault();
61
- const newHex = e.target.value;
62
- setValidHex(isValideHexSix.test(newHex) || isValideHexThree.test(newHex));
63
- setHexValue(newHex);
64
- };
65
40
  const activeColor = showOptions ? DEFAULT_COLOR[format] : activeMark(editor, format);
66
41
  return /*#__PURE__*/_jsxs("div", {
67
- className: "color-picker popup-wrapper1 color-picker-dialog",
42
+ className: "",
68
43
  ref: colorPickerRef,
69
44
  style: {
70
45
  display: "flex",
71
- alignItems: "center"
46
+ alignItems: "center",
47
+ position: "relative"
72
48
  },
73
49
  children: [showHex ? /*#__PURE__*/_jsx("div", {
74
50
  style: {
@@ -84,59 +60,23 @@ const ColorPicker = ({
84
60
  onClick: toggleOption,
85
61
  title: title,
86
62
  children: logo[format](activeColor)
87
- }), showOptions && /*#__PURE__*/_jsxs(_Fragment, {
88
- children: [/*#__PURE__*/_jsx("div", {
89
- className: "backdrop",
90
- onClick: () => {
91
- setShowOptions(false);
92
- }
93
- }), /*#__PURE__*/_jsxs("div", {
94
- className: "af-popup",
95
- children: [/*#__PURE__*/_jsx("div", {
96
- className: "color-options",
97
- children: colors.map((color, index) => {
98
- return /*#__PURE__*/_jsx("div", {
99
- "data-value": color,
100
- onClick: changeColor,
101
- className: "option",
102
- style: {
103
- background: color
104
- }
105
- }, index);
106
- })
107
- }), /*#__PURE__*/_jsx("p", {
108
- style: {
109
- textAlign: "center",
110
- opacity: "0.7",
111
- width: "100%"
112
- },
113
- children: "or"
114
- }), /*#__PURE__*/_jsxs("form", {
115
- onSubmit: handleFormSubmit,
116
- children: [/*#__PURE__*/_jsx("div", {
117
- className: "hexPreview",
118
- style: {
119
- background: validHex ? hexValue : "#000000"
120
- }
121
- }), /*#__PURE__*/_jsx("input", {
122
- type: "text",
123
- placeholder: "#000000",
124
- value: hexValue,
125
- onChange: handleHexChange,
126
- style: {
127
- border: validHex === false ? "1px solid red" : "1px solid lightgray"
128
- }
129
- }), /*#__PURE__*/_jsx(ButtonBase, {
130
- className: "colorSaveBtn",
131
- style: {
132
- background: validHex ? "#2563EB" : "#64748B",
133
- color: "#fff"
134
- },
135
- type: "submit",
136
- children: "Save"
137
- })]
138
- })]
139
- })]
63
+ }), showOptions && /*#__PURE__*/_jsx("div", {
64
+ style: {
65
+ position: "fixed",
66
+ top: 0,
67
+ left: 0,
68
+ right: 0,
69
+ bottom: 0,
70
+ margin: "auto",
71
+ zIndex: 100,
72
+ width: "300px",
73
+ height: "300px"
74
+ },
75
+ children: /*#__PURE__*/_jsx(ColorPickerTool, {
76
+ gradient: true,
77
+ value: activeColor,
78
+ onChange: handleFormSubmit
79
+ })
140
80
  })]
141
81
  });
142
82
  };
@@ -1,13 +1,16 @@
1
- .embed{
1
+ .embed {
2
2
  width: fit-content;
3
3
  position: relative;
4
4
  margin: 0px;
5
5
  }
6
- .embed img,.embed iframe{
6
+
7
+ .embed img,
8
+ .embed iframe {
7
9
  width: 100%;
8
- height:100%;
10
+ height: 100%;
9
11
  }
10
- .embed button.resize{
12
+
13
+ .embed button.resize {
11
14
  position: absolute;
12
15
  bottom: 2px;
13
16
  right: 2px;
@@ -27,8 +30,53 @@
27
30
 
28
31
  .image-text {
29
32
  padding: 12px;
30
- background-color: rgba(0,0,0,0.5);
33
+ background-color: rgba(0, 0, 0, 0.5);
31
34
  margin: 0px;
32
35
  color: #FFF;
33
36
  font-weight: bold;
37
+ }
38
+
39
+ .link-embed-wrapper iframe {
40
+ width: 100%;
41
+ height: 100%;
42
+ }
43
+
44
+ .link-embed-wrapper {
45
+ width: 100%;
46
+ height: 100%;
47
+ }
48
+
49
+ .link-embed-wrapper iframe {
50
+ aspect-ratio: 16/9;
51
+ }
52
+
53
+ .link-embed-wrapper .deleteButton {
54
+ background-color: white;
55
+ /* box-shadow: 0px 0px 8px #ccc; */
56
+ padding: 5px;
57
+ width: 26px;
58
+ height: 26px;
59
+ }
60
+
61
+ .link-embed-wrapper-container {
62
+ position: relative;
63
+ display: flex;
64
+ width: 100%;
65
+ height: 100%;
66
+ }
67
+
68
+ .link-embed-wrapper-container .docDeleteContainer {
69
+ display: none;
70
+ }
71
+
72
+ .link-embed-wrapper-hover-container:hover .docDeleteContainer {
73
+ display: block;
74
+ position: absolute;
75
+ top: -16px;
76
+ right: 0;
77
+ background-color: white;
78
+ }
79
+
80
+ .link-embed-wrapper-hover-container:hover .link-embed-wrapper {
81
+ padding-top: 24px;
34
82
  }
@@ -0,0 +1,58 @@
1
+ import { Grid, IconButton, Tooltip } from '@mui/material';
2
+ import React from 'react';
3
+ import { Transforms } from 'slate';
4
+ import { ReactEditor, useSlateStatic } from 'slate-react';
5
+ import DeleteIcon from "@mui/icons-material/Delete";
6
+ import "./Embed.css";
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ import { jsxs as _jsxs } from "react/jsx-runtime";
9
+ const EmbedLink = ({
10
+ attributes,
11
+ element,
12
+ children,
13
+ customProps: {
14
+ readOnly
15
+ }
16
+ }) => {
17
+ const {
18
+ url,
19
+ width,
20
+ height
21
+ } = element;
22
+ const editor = useSlateStatic();
23
+ const path = ReactEditor.findPath(editor, element);
24
+ return /*#__PURE__*/_jsxs("div", {
25
+ ...attributes,
26
+ className: `link-embed-wrapper-container ${!readOnly ? 'link-embed-wrapper-hover-container' : ''}`,
27
+ style: {
28
+ height: height,
29
+ width: width
30
+ },
31
+ children: [/*#__PURE__*/_jsxs("div", {
32
+ className: "link-embed-wrapper",
33
+ children: [/*#__PURE__*/_jsx("iframe", {
34
+ src: url.includes('http') ? url : `//${url}`,
35
+ frameBorder: "0",
36
+ title: url
37
+ }), /*#__PURE__*/_jsx(Grid, {
38
+ className: "docDeleteContainer",
39
+ children: /*#__PURE__*/_jsx(Tooltip, {
40
+ title: "Delete",
41
+ arrow: true,
42
+ children: /*#__PURE__*/_jsx(IconButton
43
+ // className='deleteButton'
44
+ , {
45
+ onClick: () => {
46
+ Transforms.removeNodes(editor, {
47
+ at: path
48
+ });
49
+ ReactEditor.focus(editor);
50
+ },
51
+ children: /*#__PURE__*/_jsx(DeleteIcon, {})
52
+ })
53
+ })
54
+ })]
55
+ }), children]
56
+ });
57
+ };
58
+ export default EmbedLink;
@@ -43,6 +43,12 @@ const GridItem = props => {
43
43
  horizantal,
44
44
  flexDirection
45
45
  } = alignment || {};
46
+ const {
47
+ topLeft,
48
+ topRight,
49
+ bottomLeft,
50
+ bottomRight
51
+ } = borderRadius || {};
46
52
  const editor = useSlateStatic();
47
53
  const selected = useSelected();
48
54
  const itemWidth = (grid || 6) / 12 * 100;
@@ -98,7 +104,7 @@ const GridItem = props => {
98
104
  sx: {
99
105
  display: "flex",
100
106
  flexDirection: flexDirection || "column",
101
- backgroundColor: bgColor || "transparent",
107
+ background: bgColor || "transparent",
102
108
  alignItems: horizantal,
103
109
  justifyContent: vertical,
104
110
  width: `${itemWidth}%`,
@@ -129,7 +135,7 @@ const GridItem = props => {
129
135
  height: gridHeight || "auto",
130
136
  borderColor: borderColor || "transparent",
131
137
  borderWidth: borderWidth || "1px",
132
- borderRadius: borderRadius || "0px",
138
+ borderRadius: `${topLeft}px ${topRight}px ${bottomLeft}px ${bottomRight}px`,
133
139
  borderStyle: borderStyle || "solid",
134
140
  color: textColor || "#000",
135
141
  "&:hover": {
@@ -0,0 +1,54 @@
1
+ import React from "react";
2
+ import * as fIcons from "@mui/icons-material";
3
+ import { jsx as _jsx } from "react/jsx-runtime";
4
+ import { jsxs as _jsxs } from "react/jsx-runtime";
5
+ const InlineIcon = props => {
6
+ const {
7
+ attributes,
8
+ children,
9
+ element
10
+ } = props;
11
+ const {
12
+ bgColor,
13
+ textColor,
14
+ bannerSpacing,
15
+ borderRadius,
16
+ borderColor,
17
+ icon
18
+ } = element;
19
+ const {
20
+ left,
21
+ top,
22
+ right,
23
+ bottom
24
+ } = bannerSpacing || {};
25
+ const {
26
+ topLeft,
27
+ topRight,
28
+ bottomLeft,
29
+ bottomRight
30
+ } = borderRadius || {};
31
+ const BtnIcon = fIcons["Check"];
32
+ console.log(icon);
33
+ return /*#__PURE__*/_jsxs("button", {
34
+ ...attributes,
35
+ className: "editor-icon-text",
36
+ contentEditable: false,
37
+ style: {
38
+ display: "inline",
39
+ paddingLeft: `${left}px`,
40
+ paddingRight: `${right}px`,
41
+ paddingTop: `${top}px`,
42
+ paddingBottom: `${bottom}px`,
43
+ border: borderColor ? `1px solid ${borderColor}` : "none",
44
+ borderRadius: `${topLeft}px ${topRight}px ${bottomLeft}px ${bottomRight}px`,
45
+ background: bgColor || "#CCC",
46
+ color: textColor
47
+ },
48
+ children: [/*#__PURE__*/_jsx(BtnIcon, {}), /*#__PURE__*/_jsx("div", {
49
+ contentEditable: true,
50
+ children: children
51
+ })]
52
+ });
53
+ };
54
+ export default InlineIcon;
@@ -0,0 +1,69 @@
1
+ import React, { useState } from "react";
2
+ import { Editor, Transforms } from "slate";
3
+ import { IconButton } from "@mui/material";
4
+ import SmartButtonIcon from "@mui/icons-material/SmartButton";
5
+ import { removeChipText } from "../../utils/insertChipText";
6
+ import { insertIconText } from "../../utils/insertIconText";
7
+ import ChipTextPopup from "./InlineIconPopup";
8
+ import { jsx as _jsx } from "react/jsx-runtime";
9
+ import { Fragment as _Fragment } from "react/jsx-runtime";
10
+ import { jsxs as _jsxs } from "react/jsx-runtime";
11
+ const InlineIconButton = props => {
12
+ const {
13
+ editor,
14
+ customProps
15
+ } = props;
16
+ const [openSetttings, setOpenSettings] = useState(false);
17
+ const handleClick = () => {
18
+ const [parent, parentPath] = Editor.parent(editor, editor.selection.focus.path);
19
+ if (parent && parent?.type === "chip-text") {
20
+ setOpenSettings({
21
+ element: parent,
22
+ path: parentPath
23
+ });
24
+ // removeChipText(editor, parentPath);
25
+ } else {
26
+ insertIconText(editor, {
27
+ url: "",
28
+ showInNewTab: false
29
+ });
30
+ }
31
+ };
32
+ const onSave = data => {
33
+ const updateData = {
34
+ ...data
35
+ };
36
+ delete updateData.children;
37
+ Transforms.setNodes(editor, {
38
+ ...updateData
39
+ }, {
40
+ at: openSetttings?.path
41
+ });
42
+ onClose();
43
+ };
44
+ const onClose = () => {
45
+ setOpenSettings(false);
46
+ };
47
+ const onDelete = () => {
48
+ removeChipText(editor, openSetttings?.path);
49
+ onClose();
50
+ };
51
+ return /*#__PURE__*/_jsxs(_Fragment, {
52
+ children: [/*#__PURE__*/_jsx(IconButton, {
53
+ title: "Icon",
54
+ onClick: handleClick,
55
+ children: /*#__PURE__*/_jsx(SmartButtonIcon, {
56
+ sx: {
57
+ fill: "#64748B"
58
+ }
59
+ })
60
+ }), openSetttings !== false ? /*#__PURE__*/_jsx(ChipTextPopup, {
61
+ element: openSetttings?.element || {},
62
+ onSave: onSave,
63
+ onClose: onClose,
64
+ onDelete: onDelete,
65
+ customProps: customProps
66
+ }) : null]
67
+ });
68
+ };
69
+ export default InlineIconButton;
@@ -0,0 +1,24 @@
1
+ import React from "react";
2
+ import StyleBuilder from "../../common/StyleBuilder";
3
+ import chipTextStyle from "../../common/StyleBuilder/chipTextStyle";
4
+ import { jsx as _jsx } from "react/jsx-runtime";
5
+ const InlineIconPopup = props => {
6
+ const {
7
+ element,
8
+ onSave,
9
+ onClose,
10
+ onDelete,
11
+ customProps
12
+ } = props;
13
+ return /*#__PURE__*/_jsx(StyleBuilder, {
14
+ title: "Chip Text",
15
+ type: "ChipTextPopup",
16
+ element: element,
17
+ onSave: onSave,
18
+ onClose: onClose,
19
+ onDelete: onDelete,
20
+ renderTabs: chipTextStyle,
21
+ customProps: customProps
22
+ });
23
+ };
24
+ export default InlineIconPopup;
@@ -3,6 +3,9 @@ import { useFocused, useSelected, useSlateStatic } from "slate-react";
3
3
  import { removeLink } from "../../utils/link";
4
4
  import unlink from "../../Toolbar/toolbarIcons/unlink.svg";
5
5
  import "./styles.css";
6
+ import { GrDocumentUpload } from 'react-icons/gr';
7
+ import { insertEmbed } from "../../utils/embed";
8
+ import { getQueryStrings } from "../../utils/SlateUtilityFunctions";
6
9
  import { jsx as _jsx } from "react/jsx-runtime";
7
10
  import { jsxs as _jsxs } from "react/jsx-runtime";
8
11
  const Link = ({
@@ -13,6 +16,24 @@ const Link = ({
13
16
  const editor = useSlateStatic();
14
17
  const selected = useSelected();
15
18
  const focused = useFocused();
19
+ let refUrl = element.href ? element.href : element.url;
20
+ refUrl = refUrl ? refUrl.includes('http') ? refUrl : `//${refUrl}` : 'Link';
21
+ let embedUrl = refUrl;
22
+
23
+ // const urlMatch = embedUrl.match(regex);
24
+ // embedUrl = urlMatch && urlMatch.length > 0 ? urlMatch[0] : '';
25
+ if (embedUrl.includes('youtube')) embedUrl = getQueryStrings(embedUrl); //embedUrl.replace(/\/watch\?v=/g, '/embed/')
26
+ if (embedUrl.includes('youtu.be')) embedUrl = getQueryStrings(embedUrl); //embedUrl.replace(/youtu.be\//, 'youtube.com/embed/')
27
+ // Others
28
+ if (embedUrl.includes('loom')) embedUrl = embedUrl.replace(/\/share\//, '/embed/');
29
+ if (embedUrl.includes('vimeo')) embedUrl = embedUrl.replace(/\/vimeo.com\//, '/player.vimeo.com/video/');
30
+ if (embedUrl.includes('dailymotion') && embedUrl.includes('video')) embedUrl = embedUrl.replace(/www.dailymotion.com\//, 'www.dailymotion.com/embed/');
31
+ if (embedUrl.includes('dai.ly')) embedUrl = embedUrl.replace(/dai.ly\//, 'www.dailymotion.com/embed/video/');
32
+ const embedDoc = () => {
33
+ insertEmbed(editor, {
34
+ url: embedUrl
35
+ }, 'embed');
36
+ };
16
37
  return /*#__PURE__*/_jsxs("div", {
17
38
  className: "link",
18
39
  children: [/*#__PURE__*/_jsx("a", {
@@ -28,6 +49,9 @@ const Link = ({
28
49
  href: element.href,
29
50
  target: element.target,
30
51
  children: element.href
52
+ }), /*#__PURE__*/_jsx("button", {
53
+ onClick: () => embedDoc(editor),
54
+ children: /*#__PURE__*/_jsx(GrDocumentUpload, {})
31
55
  }), /*#__PURE__*/_jsx("button", {
32
56
  onClick: () => removeLink(editor),
33
57
  children: /*#__PURE__*/_jsx("img", {
@@ -14,8 +14,8 @@ const DrawSignature = props => {
14
14
  } = props;
15
15
  const [uploading, setUploading] = useState(false);
16
16
  const onSigned = async () => {
17
- setUploading(true);
18
17
  const strImage = canvasRef.toDataURL();
18
+ setUploading(true);
19
19
  const result = await services("uploadFile", {
20
20
  image: strImage
21
21
  });
@@ -33,7 +33,10 @@ const SignaturePopup = props => {
33
33
  const handleClose = () => {
34
34
  setOpen(false);
35
35
  };
36
- const handleSave = () => {
36
+ const handleSave = async () => {
37
+ await customProps?.services("workFlowAction", {
38
+ resource_id: customProps?.page_id
39
+ });
37
40
  onSave(signedData);
38
41
  handleClose();
39
42
  };
@@ -23,6 +23,7 @@ import AppHeaderButton from "../Elements/AppHeader/AppHeaderButton";
23
23
  import FormButton from "../Elements/Form/FormButton.js";
24
24
  import Text from "./FormatTools/Text";
25
25
  import ChipTextButton from "../Elements/ChipText/ChipTextButton";
26
+ import InlineIconButton from "../Elements/InlineIcon/InlineIconButton";
26
27
  import "./styles.css";
27
28
  import { jsx as _jsx } from "react/jsx-runtime";
28
29
  import { jsxs as _jsxs } from "react/jsx-runtime";
@@ -162,6 +163,11 @@ const Toolbar = props => {
162
163
  editor: editor,
163
164
  customProps: customProps
164
165
  }, element.id);
166
+ case "icon-text":
167
+ return /*#__PURE__*/_jsx(InlineIconButton, {
168
+ editor: editor,
169
+ customProps: customProps
170
+ }, element.id);
165
171
  default:
166
172
  return null;
167
173
  }
@@ -154,5 +154,11 @@ const toolbarGroups = [[{
154
154
  }, {
155
155
  id: 38,
156
156
  type: "form"
157
- }]];
157
+ }
158
+ // {
159
+ // id: 39,
160
+ // type: "icon-text",
161
+ // },
162
+ ]];
163
+
158
164
  export default toolbarGroups;
@@ -1,6 +1,7 @@
1
1
  import React, { useState } from "react";
2
2
  import { Grid, Button, Popover } from "@mui/material";
3
- import ColorPicker from "react-best-gradient-color-picker";
3
+ // import ColorPicker from "react-best-gradient-color-picker";
4
+ import ColorPickerTool from "react-gcolor-picker";
4
5
  import { jsx as _jsx } from "react/jsx-runtime";
5
6
  import { jsxs as _jsxs } from "react/jsx-runtime";
6
7
  import { Fragment as _Fragment } from "react/jsx-runtime";
@@ -35,6 +36,14 @@ const ColorPickerButton = props => {
35
36
  }), /*#__PURE__*/_jsx(Popover, {
36
37
  open: open,
37
38
  anchorEl: anchorEl,
39
+ anchorOrigin: {
40
+ vertical: "center",
41
+ horizontal: "center"
42
+ },
43
+ transformOrigin: {
44
+ vertical: "center",
45
+ horizontal: "center"
46
+ },
38
47
  onClose: handleClose,
39
48
  sx: {
40
49
  "& .MuiPaper-root": {
@@ -47,7 +56,8 @@ const ColorPickerButton = props => {
47
56
  children: /*#__PURE__*/_jsxs(Grid, {
48
57
  item: true,
49
58
  xs: 12,
50
- children: [/*#__PURE__*/_jsx(ColorPicker, {
59
+ children: [/*#__PURE__*/_jsx(ColorPickerTool, {
60
+ gradient: true,
51
61
  value: color,
52
62
  onChange: setColor
53
63
  }), /*#__PURE__*/_jsxs("div", {
@@ -1,4 +1,28 @@
1
1
  const chipTextStyle = [{
2
+ tab: "Icon",
3
+ value: "icon",
4
+ fields: [{
5
+ label: "Font Size",
6
+ key: "textSize",
7
+ type: "text",
8
+ placeholder: "16px or 1em"
9
+ }, {
10
+ label: "Icon Position",
11
+ key: "iconPosition",
12
+ type: "textOptions",
13
+ options: [{
14
+ value: "start",
15
+ label: "Start"
16
+ }, {
17
+ value: "end",
18
+ label: "End"
19
+ }]
20
+ }, {
21
+ label: "Button Icons",
22
+ key: "buttonIcon",
23
+ type: "icons"
24
+ }]
25
+ }, {
2
26
  tab: "Banner Spacing",
3
27
  value: "bannerSpacing",
4
28
  fields: [{
@@ -6,6 +6,8 @@ import withEmbeds from "../plugins/withEmbeds";
6
6
  import withEquation from "../plugins/withEquation";
7
7
  import withMentions from "../plugins/withMentions";
8
8
  import withLayout from "../plugins/withLayout";
9
+ // import { withLinkify } from '@mercuriya/slate-linkify';
10
+
9
11
  const withCommon = (props, rest = {}) => {
10
12
  return rest.needLayout ? withEquation(withLayout(withHistory(withEmbeds(withTables(withLinks(withMentions(withReact(props)))))))) : withEquation(withHistory(withEmbeds(withTables(withLinks(withMentions(withReact(props)))))));
11
13
  };
@@ -1,5 +1,5 @@
1
1
  import { Transforms, Element, Node } from "slate";
2
- const INLINE_ELLEMENTS = ["link", "chip-text", "drawer"];
2
+ const INLINE_ELLEMENTS = ["link", "chip-text", "drawer", "icon-text"];
3
3
  const withLinks = editor => {
4
4
  const {
5
5
  isInline,
@@ -28,6 +28,8 @@ import PageSettings from "../Elements/PageSettings/PageSettings";
28
28
  import Title from "../Elements/Title/title";
29
29
  import Form from "../Elements/Form/Form";
30
30
  import FormField from "../Elements/Form/FormField";
31
+ import InlineIcon from "../Elements/InlineIcon/InlineIcon";
32
+ import EmbedLink from "../Elements/Embed/link";
31
33
  import { jsx as _jsx } from "react/jsx-runtime";
32
34
  const alignment = ["alignLeft", "alignRight", "alignCenter"];
33
35
  const list_types = ["orderedList", "unorderedList"];
@@ -379,6 +381,14 @@ export const getBlock = props => {
379
381
  return /*#__PURE__*/_jsx(FormField, {
380
382
  ...props
381
383
  });
384
+ case "icon-text":
385
+ return /*#__PURE__*/_jsx(InlineIcon, {
386
+ ...props
387
+ });
388
+ case "embed":
389
+ return /*#__PURE__*/_jsx(EmbedLink, {
390
+ ...props
391
+ });
382
392
  default:
383
393
  return /*#__PURE__*/_jsx("div", {
384
394
  ...element.attr,
@@ -386,4 +396,12 @@ export const getBlock = props => {
386
396
  children: children
387
397
  });
388
398
  }
399
+ };
400
+ export const getQueryStrings = urlString => {
401
+ const newUrl = new URL(urlString);
402
+ var youCode = newUrl.searchParams.get("v");
403
+ if (!youCode) {
404
+ youCode = newUrl.pathname.replace("/", "");
405
+ }
406
+ return `https://www.youtube.com/embed/${youCode}`;
389
407
  };
@@ -1,4 +1,4 @@
1
- import { Transforms } from "slate";
1
+ import { Editor, Transforms } from "slate";
2
2
  import { createParagraph } from "./paragraph";
3
3
  export const createEmbedNode = (type, {
4
4
  url,
@@ -16,9 +16,29 @@ export const insertEmbed = (editor, embedData, format) => {
16
16
  url
17
17
  } = embedData;
18
18
  if (!url) return;
19
+ const {
20
+ selection
21
+ } = editor;
22
+ if (!selection?.focus?.path) return;
23
+ const [parent, parentPath] = Editor.parent(editor, selection?.focus?.path);
19
24
  const embed = createEmbedNode(format, embedData);
25
+ let removePath = parentPath;
26
+ let parentPosition = parentPath;
27
+ if (parentPath?.length - 1 > 0) {
28
+ removePath = parentPath.slice(0, parentPath?.length - 1);
29
+ parentPosition = parentPath.slice(0, parentPath?.length - 1);
30
+ }
31
+ removePath = removePath.map((elem, i) => {
32
+ if (i === removePath.length - 1) {
33
+ return elem + 1;
34
+ }
35
+ return elem;
36
+ });
20
37
  Transforms.insertNodes(editor, embed, {
21
- select: true
38
+ at: parentPosition
39
+ });
40
+ Transforms.unwrapNodes(editor, {
41
+ at: [...removePath]
22
42
  });
23
43
  Transforms.insertNodes(editor, createParagraph(""));
24
44
  };
@@ -14,7 +14,7 @@ export const insertChipText = (editor, {
14
14
  const {
15
15
  selection
16
16
  } = editor;
17
- const chipText = createChipTextNode(url, showInNewTab, "Chip Text");
17
+ const chipText = createChipTextNode(url, showInNewTab, " ");
18
18
  if (!!selection) {
19
19
  const [parent, parentPath] = Editor.parent(editor, selection.focus.path);
20
20
  if (editor.isVoid(parent)) {
@@ -0,0 +1,50 @@
1
+ import { Editor, Transforms, Path, Range, Element } from "slate";
2
+ export const createIconTextNode = (href, showInNewTab, text) => ({
3
+ type: "icon-text",
4
+ href,
5
+ icon: "Check",
6
+ target: showInNewTab ? "_blank" : "_self",
7
+ children: [{
8
+ text
9
+ }]
10
+ });
11
+ export const insertIconText = (editor, {
12
+ url,
13
+ showInNewTab
14
+ }) => {
15
+ const {
16
+ selection
17
+ } = editor;
18
+ const chipText = createIconTextNode(url, showInNewTab, "");
19
+ if (!!selection) {
20
+ const [parent, parentPath] = Editor.parent(editor, selection.focus.path);
21
+ if (editor.isVoid(parent)) {
22
+ Transforms.insertNodes(editor, {
23
+ type: "paragraph",
24
+ children: [chipText]
25
+ }, {
26
+ at: Path.next(parentPath),
27
+ select: true
28
+ });
29
+ } else if (Range.isCollapsed(selection)) {
30
+ Transforms.insertNodes(editor, chipText, {
31
+ select: true
32
+ });
33
+ } else {
34
+ Transforms.wrapNodes(editor, chipText, {
35
+ split: true
36
+ });
37
+ }
38
+ } else {
39
+ Transforms.insertNodes(editor, {
40
+ type: "paragraph",
41
+ children: [chipText]
42
+ });
43
+ }
44
+ };
45
+ export const removeIconText = (editor, path) => {
46
+ Transforms.unwrapNodes(editor, {
47
+ at: path,
48
+ match: n => !Editor.isEditor(n) && Element.isElement(n) && n.type === "icon-text"
49
+ });
50
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flozy/editor",
3
- "version": "1.4.4",
3
+ "version": "1.4.6",
4
4
  "description": "An Editor for flozy app brain",
5
5
  "files": [
6
6
  "dist"
@@ -27,6 +27,7 @@
27
27
  "prettier": "^3.0.1",
28
28
  "react-best-gradient-color-picker": "^2.2.23",
29
29
  "react-datepicker": "^4.18.0",
30
+ "react-gcolor-picker": "^1.3.1",
30
31
  "react-icons": "^4.10.1",
31
32
  "react-katex": "^3.0.1",
32
33
  "react-scripts": "5.0.1",