@flozy/editor 4.1.9 → 4.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -46,7 +46,8 @@ const ChatEditor = /*#__PURE__*/forwardRef((props, ref) => {
46
46
  const [deboundedValue] = useDebounce(value, 500);
47
47
  const editor = useMemo(() => {
48
48
  return withCommon(createEditor(), {
49
- needLayout
49
+ needLayout,
50
+ isChatEditor: true
50
51
  });
51
52
  }, []);
52
53
  const isReadOnly = readOnly === "readonly";
@@ -449,7 +449,8 @@ const FreeGrid = props => {
449
449
  props: {
450
450
  editor,
451
451
  path,
452
- classes
452
+ classes,
453
+ customProps
453
454
  }
454
455
  }
455
456
  },
@@ -471,7 +472,7 @@ const FreeGrid = props => {
471
472
  "--cols": `100%`,
472
473
  "--rows": `repeat(${repeatTimes}, ${ROW_HEIGHT}px)`,
473
474
  background: sectionBgColor,
474
- backgroundImage: `url('${sectionBackgroundImage}')`,
475
+ backgroundImage: sectionBackgroundImage ? `url('${sectionBackgroundImage}')` : "",
475
476
  backgroundSize: "cover"
476
477
  },
477
478
  children: [children, !readOnly ? /*#__PURE__*/_jsx("span", {
@@ -200,10 +200,11 @@ const FreeGridBox = props => {
200
200
  ...getBreakPointsValue(sectionBorderRadius || {}, null, "overrideBorderRadius", true)
201
201
  },
202
202
  background: sectionBgColor,
203
- backgroundImage: `url(${sectionBackgroundImage})`,
203
+ backgroundImage: sectionBackgroundImage ? `url('${sectionBackgroundImage}')` : "",
204
204
  borderColor: borderColor || "transparent",
205
205
  borderWidth: borderWidth || "1px",
206
- borderStyle: borderStyle || "solid"
206
+ borderStyle: borderStyle || "solid",
207
+ backgroundSize: "cover"
207
208
  },
208
209
  children: children
209
210
  })
@@ -1,51 +1,65 @@
1
1
  import React from "react";
2
- import { Box, List, ListItemButton } from "@mui/material";
2
+ import { Box, List, ListItemButton, ListItemIcon, ListItemText } from "@mui/material";
3
+ import Icon from "../../../common/Icon";
3
4
  import { jsx as _jsx } from "react/jsx-runtime";
4
5
  import { jsxs as _jsxs } from "react/jsx-runtime";
6
+ const FREE_GRID_ELEMENTS = [{
7
+ actionType: "addText",
8
+ label: "Text",
9
+ icon: "text"
10
+ }, {
11
+ actionType: "addButton",
12
+ label: "Button",
13
+ icon: "button"
14
+ }, {
15
+ actionType: "addImage",
16
+ label: "Image",
17
+ icon: "image"
18
+ }, {
19
+ actionType: "addVideo",
20
+ label: "Embed or Video",
21
+ icon: "embed"
22
+ }, {
23
+ actionType: "addBox",
24
+ label: "Box",
25
+ icon: "colorbox"
26
+ }, {
27
+ actionType: "addTable",
28
+ label: "Table",
29
+ icon: "table"
30
+ }, {
31
+ actionType: "addCode",
32
+ label: "Code",
33
+ icon: "embedScript"
34
+ }, {
35
+ actionType: "addForm",
36
+ label: "Form",
37
+ icon: "form"
38
+ }, {
39
+ actionType: "addAppHeader",
40
+ label: "App Header",
41
+ icon: "appHeader"
42
+ }];
5
43
  const AddElement = props => {
6
44
  const {
7
45
  handleClick
8
46
  } = props;
9
47
  return /*#__PURE__*/_jsx(Box, {
10
- children: /*#__PURE__*/_jsxs(List, {
48
+ children: /*#__PURE__*/_jsx(List, {
11
49
  className: "item-list-wrpr",
12
- children: [/*#__PURE__*/_jsx(ListItemButton, {
13
- className: "item-wrapper",
14
- onClick: handleClick("addText"),
15
- children: "Text"
16
- }), /*#__PURE__*/_jsx(ListItemButton, {
17
- className: "item-wrapper",
18
- onClick: handleClick("addButton"),
19
- children: "Button"
20
- }), /*#__PURE__*/_jsx(ListItemButton, {
21
- className: "item-wrapper",
22
- onClick: handleClick("addImage"),
23
- children: "Image"
24
- }), /*#__PURE__*/_jsx(ListItemButton, {
25
- className: "item-wrapper",
26
- onClick: handleClick("addVideo"),
27
- children: "Embed or Video"
28
- }), /*#__PURE__*/_jsx(ListItemButton, {
29
- className: "item-wrapper",
30
- onClick: handleClick("addTable"),
31
- children: "Table"
32
- }), /*#__PURE__*/_jsx(ListItemButton, {
33
- className: "item-wrapper",
34
- onClick: handleClick("addCode"),
35
- children: "Code"
36
- }), /*#__PURE__*/_jsx(ListItemButton, {
37
- className: "item-wrapper",
38
- onClick: handleClick("addBox"),
39
- children: "Box"
40
- }), /*#__PURE__*/_jsx(ListItemButton, {
41
- className: "item-wrapper",
42
- onClick: handleClick("addForm"),
43
- children: "Form"
44
- }), /*#__PURE__*/_jsx(ListItemButton, {
45
- className: "item-wrapper",
46
- onClick: handleClick("addAppHeader"),
47
- children: "App Header"
48
- })]
50
+ children: FREE_GRID_ELEMENTS.map(m => {
51
+ return /*#__PURE__*/_jsxs(ListItemButton, {
52
+ className: "item-wrapper",
53
+ onClick: handleClick(m.actionType),
54
+ children: [/*#__PURE__*/_jsx(ListItemIcon, {
55
+ children: /*#__PURE__*/_jsx(Icon, {
56
+ icon: m.icon
57
+ })
58
+ }), /*#__PURE__*/_jsx(ListItemText, {
59
+ children: m.label
60
+ })]
61
+ }, m.actionType);
62
+ })
49
63
  })
50
64
  });
51
65
  };
@@ -8,7 +8,8 @@ const SectionSettings = props => {
8
8
  const {
9
9
  editor,
10
10
  path,
11
- classes
11
+ classes,
12
+ customProps
12
13
  } = props;
13
14
  const element = Node.get(editor, path);
14
15
  const styleMaps = sectionStyle?.filter(f => !f?.hideOnFGS);
@@ -38,7 +39,7 @@ const SectionSettings = props => {
38
39
  value: m.value,
39
40
  element: element,
40
41
  onChange: onChange,
41
- customProps: {},
42
+ customProps: customProps,
42
43
  handleClose: handleClose
43
44
  }, `tab_${m.value}_$${i}`);
44
45
  })
@@ -289,6 +289,7 @@ const editorStyles = ({
289
289
  fullScreenWrapper: {
290
290
  "& .MuiPaper-root": {
291
291
  borderRadius: "0px !important",
292
+ paddingTop: '20px',
292
293
  "& .MuiDialogTitle-root": {
293
294
  position: "absolute",
294
295
  top: 0,
@@ -25,8 +25,11 @@ const useOptionsPopupStyle = () => ({
25
25
  }
26
26
  },
27
27
  "& .item-wrapper": {
28
- padding: "12px",
28
+ padding: "8px",
29
29
  fontFamily: "sans-serif",
30
+ "& .MuiListItemIcon-root": {
31
+ minWidth: "30px"
32
+ },
30
33
  "&.title": {
31
34
  display: "flex",
32
35
  fontWeight: "bold",
@@ -5,6 +5,64 @@ import updateAutoProps from "./updateAutoProps";
5
5
  import { calculateGridArea } from "../Utils/gridDropItem";
6
6
  import { jsx as _jsx } from "react/jsx-runtime";
7
7
  const ROOT_ITEM_CLASS = ".freegrid-item.path-3";
8
+
9
+ // Function to group items by path and calculate heights
10
+ function groupByPathAndCalculateHeight(data) {
11
+ const root = {};
12
+ const heightData = {};
13
+
14
+ // Step 1: Group items based on their path
15
+ data.forEach(item => {
16
+ const segments = item.path.split("|");
17
+ let current = root;
18
+ segments.forEach((segment, index) => {
19
+ if (!current[segment]) {
20
+ current[segment] = {
21
+ children: {},
22
+ props: {
23
+ height: 0
24
+ }
25
+ };
26
+ }
27
+ if (index === segments.length - 1) {
28
+ // Assign the properties of the item including height
29
+ current[segment] = {
30
+ ...item,
31
+ children: current[segment].children
32
+ };
33
+ }
34
+ current = current[segment].children;
35
+ });
36
+ });
37
+
38
+ // Step 2: Recursively calculate the height of each parent based on children
39
+ const calculateHeight = node => {
40
+ if (!node.children || Object.keys(node.children).length === 0) {
41
+ // Base case: If there are no children, return the node's height
42
+ return node.props.height;
43
+ }
44
+
45
+ // Calculate the height by summing the heights of all children
46
+ let totalHeight = 0;
47
+ Object.values(node.children).forEach(child => {
48
+ totalHeight += calculateHeight(child);
49
+ });
50
+
51
+ // Update the parent's height to be the total height of its children
52
+ node.props.height = totalHeight;
53
+ if (node?.path) {
54
+ heightData[node.path] = totalHeight;
55
+ }
56
+ return totalHeight;
57
+ };
58
+
59
+ // Start calculation from the root
60
+ Object.values(root).forEach(node => calculateHeight(node));
61
+ return {
62
+ root,
63
+ heightData
64
+ };
65
+ }
8
66
  const VirtualElement = props => {
9
67
  const classes = useVirtualElementStyles();
10
68
  const {
@@ -19,9 +77,10 @@ const VirtualElement = props => {
19
77
  if (virtualRef?.current) {
20
78
  setTimeout(() => {
21
79
  const allData = calculateProps(path, virtualRef?.current, ROOT_ITEM_CLASS, []);
80
+ const groupData = groupByPathAndCalculateHeight(allData);
22
81
  // it should trigger by auto alignment or on clicking mobile view change
23
- updateAutoProps(editor, allData, "xs");
24
- }, 0);
82
+ updateAutoProps(editor, allData, "xs", groupData);
83
+ }, 100);
25
84
  }
26
85
  }, [updated_at, virtualRef?.current]);
27
86
  const calculateProps = (curPath, dom, domClass, allData) => {
@@ -35,11 +94,12 @@ const VirtualElement = props => {
35
94
  };
36
95
  const itemsData = [];
37
96
  const items = dom.querySelectorAll(domClass);
38
- let sectionHeight = 0;
97
+ const nextItemPathLength = curPath?.split("|").length + 2;
98
+ let sectionHeight = 12;
39
99
  for (let i = 0; i < items.length; i++) {
40
100
  const itemRect = items[i]?.getBoundingClientRect();
41
101
  if (items[i]?.classList.contains("type_box")) {
42
- allData = calculateProps(items[i]?.dataset.path, items[i], ".freegrid-item", allData);
102
+ allData = calculateProps(items[i]?.dataset.path, items[i], `.freegrid-item.path-${nextItemPathLength}`, allData);
43
103
  } else {
44
104
  const y = Math.abs(rect.top - itemRect?.top);
45
105
  itemsData.push({
@@ -10,6 +10,7 @@ const useVirtualElementStyles = () => ({
10
10
  right: 0,
11
11
  top: 0,
12
12
  "& .freegrid-item": {
13
+ position: "relative !important",
13
14
  gridArea: "none !important",
14
15
  width: "calc(100% - 48px) !important",
15
16
  height: "auto !important",
@@ -1,6 +1,7 @@
1
1
  import { Node, Transforms } from "slate";
2
- const updateAutoProps = (editor, datas = [], breakpoint = "") => {
2
+ const updateAutoProps = (editor, datas = [], breakpoint = "", groupData) => {
3
3
  try {
4
+ // const { heightData } = groupData;
4
5
  for (let i = 0; i < datas.length; i++) {
5
6
  const {
6
7
  path,
@@ -13,7 +13,7 @@ const getStartEnd = ({
13
13
  // Get start and end, modify it as we move along.
14
14
  let [start, end] = Range.edges(selection);
15
15
 
16
- // Move backwards
16
+ // Move backwards to find the start of the word
17
17
  while (true) {
18
18
  const before = Editor.before(editor, start, {
19
19
  unit: "character"
@@ -22,16 +22,15 @@ const getStartEnd = ({
22
22
  anchor: before,
23
23
  focus: start
24
24
  });
25
- if (before && wordBefore && SHORTHAND_CMDS.indexOf(wordBefore) < 0) {
26
- start = before;
27
- if (start.offset === 0) {
28
- // Means we've wrapped to beginning of another block
25
+ if (before) {
26
+ if (wordBefore.trim() === "") {
27
+ break;
28
+ } else if (SHORTHAND_CMDS.indexOf(wordBefore) < 0) {
29
+ start = before;
30
+ } else {
31
+ start = before;
29
32
  break;
30
33
  }
31
- } else if (SHORTHAND_CMDS.indexOf(wordBefore) >= 0) {
32
- // reached the character end
33
- start = before;
34
- break;
35
34
  } else {
36
35
  break;
37
36
  }
@@ -41,11 +40,38 @@ const getStartEnd = ({
41
40
  focus: end
42
41
  };
43
42
  const word = Editor.string(editor, wordRange);
43
+ const firstChar = word[0];
44
+
45
+ // Handle the commands
46
+ if (firstChar === '@') {
47
+ // Only trigger @ if preceded by a space
48
+ const isPrecededBySpace = Editor.string(editor, {
49
+ anchor: {
50
+ path: start.path,
51
+ offset: start.offset - 1
52
+ },
53
+ focus: start
54
+ }).trim() === "";
55
+ if (isPrecededBySpace) {
56
+ return {
57
+ word,
58
+ search: word.substring(1),
59
+ target: wordRange,
60
+ type: TYPES[firstChar]
61
+ };
62
+ }
63
+ } else if (firstChar === '/') {
64
+ return {
65
+ word,
66
+ search: word.substring(1),
67
+ target: wordRange,
68
+ type: TYPES[firstChar]
69
+ };
70
+ }
44
71
  return {
45
- word,
46
- search: word?.substring(1, word.length),
47
- target: wordRange,
48
- type: TYPES[word[0]]
72
+ word: "",
73
+ wordRange: null,
74
+ type: null
49
75
  };
50
76
  } catch (err) {
51
77
  return {
@@ -9,7 +9,12 @@ import withLayout from "../plugins/withLayout";
9
9
  import withHtml from "../plugins/withHTML";
10
10
  import withErrorHandling from "./withErrorHandling";
11
11
  import withCustomDeleteBackward from "../plugins/withCustomDeleteBackward";
12
- const withCommon = (props, rest = {}) => {
13
- return rest.needLayout ? withErrorHandling(withHtml(withEquation(withLayout(withHistory(withEmbeds(withTables(withLinks(withMentions(withCustomDeleteBackward(withReact(props))))))))))) : withErrorHandling(withHtml(withEquation(withHistory(withEmbeds(withTables(withLinks(withMentions(withCustomDeleteBackward(withReact(props))))))))));
12
+ const withCommon = (props, {
13
+ needLayout = false,
14
+ isChatEditor = false
15
+ }) => {
16
+ const editor = needLayout ? withErrorHandling(withHtml(withEquation(withLayout(withHistory(withEmbeds(withTables(withLinks(withMentions(withCustomDeleteBackward(withReact(props))))))))))) : withErrorHandling(withHtml(withEquation(withHistory(withEmbeds(withTables(withLinks(withMentions(withCustomDeleteBackward(withReact(props))))))))));
17
+ editor.isChatEditor = isChatEditor;
18
+ return editor;
14
19
  };
15
20
  export default withCommon;
@@ -101,6 +101,9 @@ const withHtml = editor => {
101
101
  return element.type === "image" ? true : isVoid(element);
102
102
  };
103
103
  editor.insertData = data => {
104
+ if (editor.isChatEditor) {
105
+ return;
106
+ }
104
107
  const slateHTML = data?.getData("application/x-slate-fragment");
105
108
  const html = data?.getData("text/html");
106
109
  const currentEl = getCurrentElement(editor);
@@ -365,6 +365,6 @@ export const getBlock = props => {
365
365
  ...props
366
366
  });
367
367
  default:
368
- return;
368
+ return null;
369
369
  }
370
370
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flozy/editor",
3
- "version": "4.1.9",
3
+ "version": "4.2.1",
4
4
  "description": "An Editor for flozy app brain",
5
5
  "files": [
6
6
  "dist"