@flozy/editor 1.4.4 → 1.4.6

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.
@@ -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",