@flozy/editor 2.0.6 → 2.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable no-unused-vars */
2
2
  import React, { useRef, useCallback, useEffect, useMemo, useState, forwardRef, useImperativeHandle } from "react";
3
- import { createEditor, Editor, Transforms } from "slate";
3
+ import { createEditor, Transforms } from "slate";
4
4
  import { Slate, Editable, ReactEditor } from "slate-react";
5
5
  import { useDebounce } from "use-debounce";
6
6
  import { getMarked, getBlock } from "./utils/SlateUtilityFunctions";
@@ -1102,3 +1102,10 @@ blockquote {
1102
1102
  0 0 #e3aad6;
1103
1103
  }
1104
1104
  }
1105
+
1106
+ .doublequote::before {
1107
+ content: '\201C';
1108
+ }
1109
+ .doublequote::after {
1110
+ content: '\201D';
1111
+ }
@@ -323,7 +323,7 @@ const Grid = props => {
323
323
  flexWrap: {
324
324
  ...getBreakPointsValue(flexWrap || "wrap")
325
325
  },
326
- height: "fit-content"
326
+ height: "auto"
327
327
  },
328
328
  "data-path": path.join(","),
329
329
  children: children
@@ -51,7 +51,6 @@ const GridItem = props => {
51
51
  const selected = hoverPath === path.join(",");
52
52
  const [showTool] = useEditorSelection(editor);
53
53
  const isEmpty = !readOnly && isEmptyNode(editor, element?.children, path) ? "empty" : "";
54
- console.log(cellGHeight);
55
54
  const GridItemToolbar = () => {
56
55
  return selected && !showTool ? /*#__PURE__*/_jsx("div", {
57
56
  contentEditable: false,
@@ -1,19 +1,27 @@
1
1
  import React from "react";
2
2
  import Icon from "../../common/Icon";
3
3
  import Button from "../../common/Button";
4
- import { toggleBlock, isBlockActive } from "../../utils/SlateUtilityFunctions.js";
4
+ import { toggleBlock, isBlockActive, isMarkActive, toggleMark } from "../../utils/SlateUtilityFunctions.js";
5
5
  import { jsx as _jsx } from "react/jsx-runtime";
6
- const BlockButton = ({
7
- editor,
8
- format,
9
- title
10
- }) => {
6
+ const MARK_TYPES = ["doublequote"];
7
+ const BlockButton = props => {
8
+ const {
9
+ editor,
10
+ format,
11
+ title
12
+ } = props;
13
+ const isMark = MARK_TYPES?.indexOf(format) >= 0;
14
+ const isActive = isMark ? isMarkActive(editor, format) : isBlockActive(editor, format);
11
15
  return /*#__PURE__*/_jsx(Button, {
12
- active: isBlockActive(editor, format),
16
+ active: isActive,
13
17
  format: format,
14
18
  onMouseDown: e => {
15
19
  e.preventDefault();
16
- toggleBlock(editor, format);
20
+ if (isMark) {
21
+ toggleMark(editor, format);
22
+ } else {
23
+ toggleBlock(editor, format);
24
+ }
17
25
  },
18
26
  title: title,
19
27
  children: /*#__PURE__*/_jsx(Icon, {
@@ -8,6 +8,7 @@ import useDrag from "../../hooks/useDrag";
8
8
  import PopperHeader from "./PopperHeader";
9
9
  import { TableUtil } from "../../utils/table";
10
10
  import useWindowResize from "../../hooks/useWindowResize";
11
+ import useEvent from "../../hooks/useKeys";
11
12
  import { jsx as _jsx } from "react/jsx-runtime";
12
13
  import { jsxs as _jsxs } from "react/jsx-runtime";
13
14
  const PopupTool = props => {
@@ -26,6 +27,7 @@ const PopupTool = props => {
26
27
  const id = open ? "popup-edit-tool" : "";
27
28
  const table = new TableUtil(editor);
28
29
  const [size] = useWindowResize();
30
+ const [eventKey] = useEvent();
29
31
  useEffect(() => {
30
32
  if (event === "end" && anchorEl && !open) {
31
33
  // for table cell selection
@@ -37,6 +39,11 @@ const PopupTool = props => {
37
39
  setOpen(false);
38
40
  }
39
41
  }, [event, anchorEl]);
42
+ useEffect(() => {
43
+ if (eventKey) {
44
+ setOpen(false);
45
+ }
46
+ }, [eventKey]);
40
47
  useEffect(() => {
41
48
  if (!selection || !inFocus || Range.isCollapsed(selection) || Editor.string(editor, selection) === "") {
42
49
  setAnchorEl(null);
@@ -103,9 +103,9 @@ export const toolbarGroups = [[{
103
103
  group: "typography"
104
104
  }, {
105
105
  id: 14,
106
- format: "blockquote",
106
+ format: "doublequote",
107
107
  type: "block",
108
- title: "Block Quote",
108
+ title: "Double Quote",
109
109
  group: "typography"
110
110
  }], [{
111
111
  id: 15,
@@ -8,8 +8,8 @@ import { SiLatex } from "react-icons/si";
8
8
  import { RiDeleteColumn, RiDeleteRow } from "react-icons/ri";
9
9
  import { IoIosImage } from "react-icons/io";
10
10
  import { GridIcon, AccordionIcon, SignatureIcon, ButtonIcon, Carousal, FormIcon, BoldIcon, FontFamilyIcon, FontSizeIcon, ImageIcon, ItalicIcon, LinkIcon, StrikethroughIcon, TableIcon, UnderLineIcon, VideoIcon, CheckboxIcon, AppHeader, MoreHorizontal, UploadImage, DocsUpload, LeftArrow, RightArrow, CheckListButton, CheckListButtonActive, ExcelIcon, CsvIcon, DividerIcon } from "./iconslist";
11
- import ArrowRightIcon from '@mui/icons-material/ArrowRight';
12
- import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
11
+ import ArrowRightIcon from "@mui/icons-material/ArrowRight";
12
+ import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
13
13
  import { jsx as _jsx } from "react/jsx-runtime";
14
14
  import { jsxs as _jsxs } from "react/jsx-runtime";
15
15
  const iconList = {
@@ -51,6 +51,10 @@ const iconList = {
51
51
  size: 20,
52
52
  fill: "#64748B"
53
53
  }),
54
+ doublequote: /*#__PURE__*/_jsx(MdFormatQuote, {
55
+ size: 20,
56
+ fill: "#64748B"
57
+ }),
54
58
  superscript: /*#__PURE__*/_jsx(FaSuperscript, {
55
59
  size: 15,
56
60
  fill: "#64748B"
@@ -69,8 +69,9 @@ const ImageSelector = props => {
69
69
  children: /*#__PURE__*/_jsxs(Tabs, {
70
70
  sx: classes.tabs,
71
71
  onChange: handleTabChange,
72
- orientation: "horizontal",
73
72
  value: tabValue,
73
+ variant: "scrollable",
74
+ scrollButtons: "auto",
74
75
  children: [/*#__PURE__*/_jsx(Tab, {
75
76
  className: `${isActive("upload")} ${TAB_SHOW[title].indexOf("upload") === -1 ? "hidden" : ""}`,
76
77
  sx: classes.tab,
@@ -0,0 +1,107 @@
1
+ import { jsx } from "slate-hyperscript";
2
+ const ELEMENT_TAGS = {
3
+ A: el => ({
4
+ type: "link",
5
+ url: el.getAttribute("href")
6
+ }),
7
+ BLOCKQUOTE: () => ({
8
+ type: "quote"
9
+ }),
10
+ H1: () => ({
11
+ type: "headingOne"
12
+ }),
13
+ H2: () => ({
14
+ type: "headingTwo"
15
+ }),
16
+ H3: () => ({
17
+ type: "headingThree"
18
+ }),
19
+ H4: () => ({
20
+ type: "headingFour"
21
+ }),
22
+ H5: () => ({
23
+ type: "headingFive"
24
+ }),
25
+ H6: () => ({
26
+ type: "headingSix"
27
+ }),
28
+ IMG: el => ({
29
+ type: "image",
30
+ url: el.getAttribute("src")
31
+ }),
32
+ LI: () => ({
33
+ type: "list-item"
34
+ }),
35
+ UL: () => ({
36
+ type: "unorderedList"
37
+ }),
38
+ OL: () => ({
39
+ type: "orderedList"
40
+ }),
41
+ P: () => ({
42
+ type: "paragraph"
43
+ }),
44
+ PRE: () => ({
45
+ type: "code"
46
+ })
47
+ };
48
+
49
+ // COMPAT: `B` is omitted here because Google Docs uses `<b>` in weird ways.
50
+ const TEXT_TAGS = {
51
+ CODE: () => ({
52
+ code: true
53
+ }),
54
+ DEL: () => ({
55
+ strikethrough: true
56
+ }),
57
+ EM: () => ({
58
+ italic: true
59
+ }),
60
+ I: () => ({
61
+ italic: true
62
+ }),
63
+ S: () => ({
64
+ strikethrough: true
65
+ }),
66
+ STRONG: () => ({
67
+ bold: true
68
+ }),
69
+ U: () => ({
70
+ underline: true
71
+ })
72
+ };
73
+ const deserialize = el => {
74
+ if (el.nodeType === 3) {
75
+ return el.textContent;
76
+ } else if (el.nodeType !== 1) {
77
+ return null;
78
+ } else if (el.nodeName === "BR") {
79
+ return "\n";
80
+ }
81
+ const {
82
+ nodeName
83
+ } = el;
84
+ let parent = el;
85
+ if (nodeName === "PRE" && el.childNodes[0] && el.childNodes[0].nodeName === "CODE") {
86
+ parent = el.childNodes[0];
87
+ }
88
+ let children = Array.from(parent.childNodes).map(deserialize).flat();
89
+ if (children.length === 0) {
90
+ children = [{
91
+ text: ""
92
+ }];
93
+ }
94
+ if (el.nodeName === "BODY") {
95
+ return jsx("fragment", {}, children);
96
+ }
97
+ if (ELEMENT_TAGS[nodeName]) {
98
+ const attrs = ELEMENT_TAGS[nodeName](el);
99
+ return jsx("element", attrs, children);
100
+ }
101
+ if (TEXT_TAGS[nodeName]) {
102
+ const attrs = TEXT_TAGS[nodeName](el);
103
+ return children.map(child => jsx("text", attrs, child));
104
+ }
105
+ return children;
106
+ };
107
+ export default deserialize;
@@ -0,0 +1,21 @@
1
+ import { useEffect, useState } from "react";
2
+ const useEvent = () => {
3
+ const [event, setEvent] = useState("");
4
+ useEffect(() => {
5
+ addListener();
6
+ return () => {
7
+ removeListener();
8
+ };
9
+ }, []);
10
+ const onKeyUp = e => {
11
+ setEvent(e.keyCode);
12
+ };
13
+ const addListener = () => {
14
+ document.addEventListener("keyup", onKeyUp);
15
+ };
16
+ const removeListener = () => {
17
+ document.removeEventListener("keyup", onKeyUp);
18
+ };
19
+ return [event];
20
+ };
21
+ export default useEvent;
@@ -6,9 +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
+ import withHtml from "../plugins/withHTML";
11
10
  const withCommon = (props, rest = {}) => {
12
- return rest.needLayout ? withEquation(withLayout(withHistory(withEmbeds(withTables(withLinks(withMentions(withReact(props)))))))) : withEquation(withHistory(withEmbeds(withTables(withLinks(withMentions(withReact(props)))))));
11
+ return rest.needLayout ? withHtml(withEquation(withLayout(withHistory(withEmbeds(withTables(withLinks(withMentions(withReact(props))))))))) : withHtml(withEquation(withHistory(withEmbeds(withTables(withLinks(withMentions(withReact(props))))))));
13
12
  };
14
13
  export default withCommon;
@@ -0,0 +1,41 @@
1
+ import { Transforms, Editor, Element } from "slate";
2
+ import deserialize from "../helper/deserialize";
3
+ const withHtml = editor => {
4
+ const {
5
+ insertData,
6
+ isInline,
7
+ isVoid
8
+ } = editor;
9
+ editor.isInline = element => {
10
+ return element.type === "link" ? true : isInline(element);
11
+ };
12
+ editor.isVoid = element => {
13
+ return element.type === "image" ? true : isVoid(element);
14
+ };
15
+ editor.insertData = data => {
16
+ const slateHTML = data?.getData("application/x-slate-fragment");
17
+ const html = data?.getData("text/html");
18
+ if (slateHTML) {
19
+ const [tableNode] = Editor.nodes(editor, {
20
+ match: n => !Editor.isEditor(n) && Element.isElement(n) && n.type === "table"
21
+ });
22
+ // do not paste table cell inside table cell
23
+ // only plain text for internal paste
24
+ if (tableNode && tableNode[0]) {
25
+ const text = data?.getData("text/plain");
26
+ Transforms.insertText(editor, text);
27
+ } else {
28
+ insertData(data);
29
+ }
30
+ } else if (html) {
31
+ const parsed = new DOMParser().parseFromString(html, "text/html");
32
+ const fragment = deserialize(parsed.body);
33
+ Transforms.insertFragment(editor, fragment);
34
+ return;
35
+ } else {
36
+ insertData(data);
37
+ }
38
+ };
39
+ return editor;
40
+ };
41
+ export default withHtml;
@@ -5,15 +5,17 @@ const withTable = editor => {
5
5
  deleteBackward,
6
6
  deleteForward
7
7
  } = editor;
8
- editor.insertData = data => {
9
- try {
10
- const text = data.getData("text/plain");
11
- Transforms.insertText(editor, text);
12
- return;
13
- } catch (err) {
14
- console.log(err);
15
- }
16
- };
8
+
9
+ // editor.insertData = (data) => {
10
+ // try {
11
+ // // const text = data.getData("text/plain");
12
+ // Transforms.insertFragment(editor, data);
13
+ // return;
14
+ // } catch (err) {
15
+ // console.log(err);
16
+ // }
17
+ // };
18
+
17
19
  editor.deleteBackward = unit => {
18
20
  const {
19
21
  selection
@@ -39,6 +39,7 @@ import { getBreakPointsValue } from "../helper/theme";
39
39
  import Variables from "../Elements/Variables/Variable";
40
40
  import insertNewLine from "./insertNewLine";
41
41
  import Divider from "../Elements/Divider/Divider";
42
+ import { getBorderColor } from "./helper";
42
43
  import { jsx as _jsx } from "react/jsx-runtime";
43
44
  const alignment = ["alignLeft", "alignRight", "alignCenter"];
44
45
  const list_types = ["orderedList", "unorderedList"];
@@ -160,6 +161,7 @@ export const activeMark = (editor, format) => {
160
161
  }
161
162
  };
162
163
  export const getMarked = (leaf, children) => {
164
+ const className = leaf?.doublequote ? "doublequote" : "";
163
165
  if (leaf.bold) {
164
166
  children = /*#__PURE__*/_jsx("strong", {
165
167
  children: children
@@ -198,7 +200,9 @@ export const getMarked = (leaf, children) => {
198
200
  children: children
199
201
  });
200
202
  }
201
- if (leaf.color) {
203
+ // cover under single span
204
+ if (leaf.color || leaf.bgColor || leaf.fontSize || leaf.fontFamily || leaf.fontWeight) {
205
+ const family = fontFamilyMap[leaf?.fontFamily];
202
206
  const textStyles = leaf?.color?.indexOf("gradient") >= 0 ? {
203
207
  background: leaf?.color?.concat("text"),
204
208
  WebkitBackgroundClip: "text",
@@ -206,45 +210,17 @@ export const getMarked = (leaf, children) => {
206
210
  } : {
207
211
  color: leaf.color
208
212
  };
209
- children = /*#__PURE__*/_jsx("span", {
210
- style: {
211
- ...textStyles
212
- },
213
- children: children
214
- });
215
- }
216
- if (leaf.bgColor) {
217
- children = /*#__PURE__*/_jsx("span", {
218
- style: {
219
- background: leaf.bgColor
220
- },
221
- children: children
222
- });
223
- }
224
- if (leaf.fontSize) {
225
213
  children = /*#__PURE__*/_jsx(Box, {
214
+ className: className,
226
215
  component: "span",
227
216
  sx: {
228
217
  fontSize: {
229
218
  lg: sizeMap[leaf.fontSize] || leaf.fontSize,
230
219
  ...getBreakPointsValue(leaf.fontSize, null, "overrideText")
231
- }
232
- },
233
- children: children
234
- });
235
- }
236
- if (leaf.fontFamily) {
237
- const family = fontFamilyMap[leaf.fontFamily];
238
- children = /*#__PURE__*/_jsx("span", {
239
- style: {
240
- fontFamily: family
241
- },
242
- children: children
243
- });
244
- }
245
- if (leaf.fontWeight) {
246
- children = /*#__PURE__*/_jsx("span", {
247
- style: {
220
+ },
221
+ background: leaf.bgColor,
222
+ ...textStyles,
223
+ fontFamily: family,
248
224
  fontWeight: leaf.fontWeight
249
225
  },
250
226
  children: children
@@ -300,7 +276,8 @@ export const getBlock = props => {
300
276
  ...attributes,
301
277
  ...element.attr,
302
278
  style: {
303
- borderColor: element?.color || "transparent",
279
+ // borderColor: element?.color || "transparent",
280
+ ...getBorderColor(element?.color || "transparent", 3),
304
281
  background: element?.bgColor || "none",
305
282
  padding: `${element?.bgColor ? "16px" : "0px"} 8px`,
306
283
  borderRadius: `${element?.color ? "0px" : "12px"} 12px 12px ${element?.color ? "0px" : "12px"}`,
@@ -1,7 +1,9 @@
1
1
  import { Transforms } from "slate";
2
2
  import insertNewLine from "./insertNewLine";
3
+ import { getSelectedText } from "./helper";
3
4
  export const insertAccordion = (editor, path) => {
4
5
  try {
6
+ const selectedText = getSelectedText(editor);
5
7
  const accordion = {
6
8
  type: "accordion",
7
9
  children: [{
@@ -9,7 +11,7 @@ export const insertAccordion = (editor, path) => {
9
11
  children: [{
10
12
  type: "paragraph",
11
13
  children: [{
12
- text: ""
14
+ text: selectedText || ""
13
15
  }]
14
16
  }]
15
17
  }, {
@@ -43,6 +43,19 @@ export const gradientBorder = color => {
43
43
  };
44
44
  }
45
45
  };
46
+ export const getBorderColor = (color, borderWidth = 3) => {
47
+ if (color?.indexOf("linear") > -1) {
48
+ return {
49
+ borderImage: `${color} ${borderWidth}`,
50
+ borderWidth: `0px 0px 0px ${borderWidth}px`,
51
+ borderStyle: "solid"
52
+ };
53
+ } else {
54
+ return {
55
+ borderColor: color || "transparent"
56
+ };
57
+ }
58
+ };
46
59
  export const absoluteLink = url => {
47
60
  try {
48
61
  if (url?.indexOf("://") === -1) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flozy/editor",
3
- "version": "2.0.6",
3
+ "version": "2.0.8",
4
4
  "description": "An Editor for flozy app brain",
5
5
  "files": [
6
6
  "dist"
@@ -41,6 +41,7 @@
41
41
  "react-slick": "^0.29.0",
42
42
  "slate": "^0.94.1",
43
43
  "slate-history": "^0.93.0",
44
+ "slate-hyperscript": "^0.100.0",
44
45
  "slate-react": "^0.98.3",
45
46
  "styled-components": "^5.3.11",
46
47
  "use-debounce": "^10.0.0",