@flozy/editor 4.2.2 → 4.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,7 +10,7 @@ import { draftToSlate } from "./utils/draftToSlate";
10
10
  import useMentions from "./hooks/useMentions";
11
11
  import MentionsPopup from "./common/MentionsPopup";
12
12
  import { RemoteCursorOverlay } from "./RemoteCursorOverlay/Overlay";
13
- import { mentionsEvent, commands, indentation, escapeEvent, enterEvent } from "./utils/events";
13
+ import { mentionsEvent, commands, indentation, escapeEvent, enterEvent, upArrowEvent, downArrowEvent } from "./utils/events";
14
14
  import withCommon from "./hooks/withCommon";
15
15
  import DialogWrapper from "./DialogWrapper";
16
16
  import { serializeToText } from "./utils/serializeToText";
@@ -379,6 +379,10 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
379
379
  });
380
380
  }
381
381
  }
382
+ } else if (event.key === "ArrowUp" && otherProps?.tagName !== "Pages") {
383
+ upArrowEvent(event, editor);
384
+ } else if (event.key === "ArrowDown" && otherProps?.tagName !== "Pages") {
385
+ downArrowEvent(event, editor);
382
386
  }
383
387
  }, [chars, editor, target, mentions, setMentions, search, type, mentionsRef]);
384
388
  const Overlay = collaborativeEditor && !isReadOnly ? RemoteCursorOverlay : React.Fragment;
@@ -47,14 +47,7 @@ const ToolBar = ({
47
47
  })]
48
48
  }) : null;
49
49
  };
50
- const ImageContent = ({
51
- readOnly,
52
- setOpenSettings,
53
- element,
54
- handleImageClick,
55
- onTouchEnd,
56
- path
57
- }) => {
50
+ const ImageContent = props => {
58
51
  const {
59
52
  alt,
60
53
  url,
@@ -64,8 +57,13 @@ const ImageContent = ({
64
57
  boxShadow,
65
58
  frame = null,
66
59
  objectFit,
67
- webAddress
68
- } = element;
60
+ webAddress,
61
+ readOnly,
62
+ setOpenSettings,
63
+ handleImageClick,
64
+ onTouchEnd,
65
+ path
66
+ } = props;
69
67
  const theme = useTheme();
70
68
  return !url && !readOnly ? /*#__PURE__*/_jsxs(Box, {
71
69
  component: "button",
@@ -278,9 +276,9 @@ const Image = ({
278
276
  onSettings: onSettings,
279
277
  setOpenNav: setOpenNav
280
278
  }), /*#__PURE__*/_jsx(ImageContent, {
279
+ ...element,
281
280
  readOnly: readOnly,
282
281
  setOpenSettings: setOpenSettings,
283
- element: element,
284
282
  handleImageClick: handleImageClick,
285
283
  onTouchEnd: onTouchEnd,
286
284
  path: path
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect } from "react";
1
+ import React, { useState, useEffect, useCallback } from "react";
2
2
  import { useSlateStatic, ReactEditor } from "slate-react";
3
3
  import { Node, Transforms } from "slate";
4
4
  import { IconButton, Tooltip, Box, useTheme } from "@mui/material";
@@ -13,6 +13,66 @@ import { getEmbedURL } from "../../helper";
13
13
  import { getBreakPointsValue, getTRBLBreakPoints, groupByBreakpoint } from "../../helper/theme";
14
14
  import { jsx as _jsx } from "react/jsx-runtime";
15
15
  import { jsxs as _jsxs } from "react/jsx-runtime";
16
+ const VideoContent = props => {
17
+ const {
18
+ resizing,
19
+ borderColor,
20
+ borderWidth,
21
+ borderStyle,
22
+ bgColor,
23
+ embedURL,
24
+ alt,
25
+ videoSX
26
+ } = props;
27
+ return resizing ? /*#__PURE__*/_jsx("div", {
28
+ style: {
29
+ width: "100%",
30
+ height: "100%",
31
+ border: "2px dashed black",
32
+ display: "flex",
33
+ justifyContent: "center",
34
+ alignItems: "center"
35
+ },
36
+ children: /*#__PURE__*/_jsx(Icon, {
37
+ icon: "videoPlayer"
38
+ })
39
+ }) : /*#__PURE__*/_jsx(Box, {
40
+ component: "iframe",
41
+ className: "embedd-iframe",
42
+ sx: {
43
+ border: "none",
44
+ position: "absolute",
45
+ width: "100%",
46
+ height: "100%",
47
+ maxWidth: "100%",
48
+ left: "0px",
49
+ ...(gradientBorder(borderColor) || {}),
50
+ borderWidth: borderWidth || "1px",
51
+ borderStyle: borderStyle || "solid",
52
+ background: bgColor || "transparent",
53
+ ...videoSX
54
+ },
55
+ src: embedURL,
56
+ title: alt
57
+ });
58
+ };
59
+ const VideoPlaceholder = props => {
60
+ const {
61
+ url,
62
+ readOnly,
63
+ onSettings
64
+ } = props;
65
+ return !url && !readOnly ? /*#__PURE__*/_jsxs(Box, {
66
+ component: "button",
67
+ className: "element-empty-btn",
68
+ onClick: onSettings,
69
+ children: [/*#__PURE__*/_jsx(Icon, {
70
+ icon: "video"
71
+ }), "Embed Video or Other"]
72
+ }) : /*#__PURE__*/_jsx(VideoContent, {
73
+ ...props
74
+ });
75
+ };
16
76
  const Video = ({
17
77
  attributes,
18
78
  element,
@@ -21,17 +81,12 @@ const Video = ({
21
81
  }) => {
22
82
  const theme = useTheme();
23
83
  const {
24
- alt,
25
84
  alignment,
26
85
  borderRadius,
27
- borderWidth,
28
- borderColor,
29
- borderStyle,
30
86
  url,
31
87
  xsHidden,
32
88
  width: oldWidth,
33
- bannerSpacing,
34
- bgColor
89
+ bannerSpacing
35
90
  } = element;
36
91
  const editor = useSlateStatic();
37
92
  const [openSetttings, setOpenSettings] = useState(false);
@@ -124,8 +179,8 @@ const Video = ({
124
179
  const getWidth = () => {
125
180
  if (resizing) {
126
181
  return {
127
- width: `${size.width}px`,
128
- height: url ? `${size.height}px` : "auto"
182
+ width: size.width ? `${size.width}px` : "100%",
183
+ height: url ? `${size.height || 300}px` : "auto"
129
184
  };
130
185
  } else {
131
186
  return {
@@ -149,49 +204,6 @@ const Video = ({
149
204
  ...getTRBLBreakPoints(bannerSpacing)
150
205
  }
151
206
  }, theme);
152
- const VideoContent = () => {
153
- return resizing ? /*#__PURE__*/_jsx("div", {
154
- style: {
155
- width: "100%",
156
- height: "100%",
157
- border: "2px dashed black",
158
- display: "flex",
159
- justifyContent: "center",
160
- alignItems: "center"
161
- },
162
- children: /*#__PURE__*/_jsx(Icon, {
163
- icon: "videoPlayer"
164
- })
165
- }) : /*#__PURE__*/_jsx(Box, {
166
- component: "iframe",
167
- className: "embedd-iframe",
168
- sx: {
169
- border: "none",
170
- position: "absolute",
171
- width: "100%",
172
- height: "100%",
173
- maxWidth: "100%",
174
- left: "0px",
175
- ...(gradientBorder(borderColor) || {}),
176
- borderWidth: borderWidth || "1px",
177
- borderStyle: borderStyle || "solid",
178
- background: bgColor || "transparent",
179
- ...videoSX
180
- },
181
- src: embedURL,
182
- title: alt
183
- });
184
- };
185
- const VideoPlaceholder = () => {
186
- return !url && !readOnly ? /*#__PURE__*/_jsxs(Box, {
187
- component: "button",
188
- className: "element-empty-btn",
189
- onClick: onSettings,
190
- children: [/*#__PURE__*/_jsx(Icon, {
191
- icon: "video"
192
- }), "Embed Video or Other"]
193
- }) : /*#__PURE__*/_jsx(VideoContent, {});
194
- };
195
207
  return /*#__PURE__*/_jsxs(Box, {
196
208
  ...attributes,
197
209
  className: "embed has-hover video dpath",
@@ -224,7 +236,15 @@ const Video = ({
224
236
  ...getWidth(),
225
237
  maxWidth: "100%"
226
238
  },
227
- children: [!readOnly && url && /*#__PURE__*/_jsx(ToolBar, {}), /*#__PURE__*/_jsx(VideoPlaceholder, {}), !readOnly && url ? /*#__PURE__*/_jsx(IconButton, {
239
+ children: [!readOnly && url && /*#__PURE__*/_jsx(ToolBar, {}), /*#__PURE__*/_jsx(VideoPlaceholder, {
240
+ ...element,
241
+ embedURL: embedURL,
242
+ onSettings: onSettings,
243
+ videoSX: videoSX,
244
+ url: url,
245
+ readOnly: readOnly,
246
+ resizing: resizing
247
+ }), !readOnly && url ? /*#__PURE__*/_jsx(IconButton, {
228
248
  onPointerDown: onMouseDown,
229
249
  style: {
230
250
  background: "#FFF"
@@ -401,6 +401,7 @@ const Form = props => {
401
401
  component: "button",
402
402
  onClick: onSubmitClick,
403
403
  disabled: loading,
404
+ contentEditable: false,
404
405
  sx: {
405
406
  background: buttonProps?.bgColor || "rgb(30, 75, 122)",
406
407
  borderWidth: "1px",
@@ -495,6 +496,7 @@ const Form = props => {
495
496
  open: anchorEl !== null,
496
497
  anchorEl: anchorEl,
497
498
  onClose: handleClose,
499
+ contentEditable: false,
498
500
  children: [/*#__PURE__*/_jsx(MenuItem, {
499
501
  onClick: onMenuClick("edit"),
500
502
  children: /*#__PURE__*/_jsx(Tooltip, {
@@ -465,15 +465,15 @@ const FreeGrid = props => {
465
465
  className: "freegrid-container freegrid-container-parent",
466
466
  sx: {
467
467
  ...classes.root,
468
- ...freegridSX
468
+ ...freegridSX,
469
+ background: sectionBgColor,
470
+ backgroundImage: sectionBackgroundImage ? `url('${sectionBackgroundImage}')` : "",
471
+ backgroundSize: "cover"
469
472
  },
470
473
  "data-path": path.join("|"),
471
474
  style: {
472
475
  "--cols": `100%`,
473
- "--rows": `repeat(${repeatTimes}, ${ROW_HEIGHT}px)`,
474
- background: sectionBgColor,
475
- backgroundImage: sectionBackgroundImage ? `url('${sectionBackgroundImage}')` : "",
476
- backgroundSize: "cover"
476
+ "--rows": `repeat(${repeatTimes}, ${ROW_HEIGHT}px)`
477
477
  },
478
478
  children: [children, !readOnly ? /*#__PURE__*/_jsx("span", {
479
479
  placeholder: `Section (${sectionName || "Welcome"})`,
@@ -23,7 +23,7 @@ const TableRow = props => {
23
23
  return /*#__PURE__*/_jsx("tr", {
24
24
  ...attributes,
25
25
  style: {
26
- backgroundColor: bgColor,
26
+ background: bgColor,
27
27
  border: rowBorderColor ? `1px solid ${rowBorderColor}` : ""
28
28
  },
29
29
  children: children
@@ -3,6 +3,6 @@ const mentions = props => {
3
3
  CHARACTERS,
4
4
  search
5
5
  } = props;
6
- return CHARACTERS.filter(c => c.name.toLowerCase().startsWith(search?.toLowerCase())).slice(0, 10);
6
+ return CHARACTERS.filter(c => c?.name?.toLowerCase()?.startsWith(search?.toLowerCase())).slice(0, 10);
7
7
  };
8
8
  export default mentions;
@@ -101,9 +101,6 @@ 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
- }
107
104
  const slateHTML = data?.getData("application/x-slate-fragment");
108
105
  const html = data?.getData("text/html");
109
106
  const currentEl = getCurrentElement(editor);
@@ -117,6 +114,23 @@ const withHtml = editor => {
117
114
  const defaultInsert = loopChildren(decoded, true);
118
115
  if (defaultInsert) {
119
116
  insertData(data);
117
+ // } else if (editor.isChatEditor) {
118
+ // // Only convert table to paragraphs if in chat editor mode
119
+ // const paragraphs = decoded.map(row =>
120
+ // row.children.map(cell =>
121
+ // cell.children.map(paragraph =>
122
+ // paragraph.children.map(textNode => textNode.text).join('')
123
+ // ).join(' ')
124
+ // ).join(' ')
125
+ // ).join('\n'); // Joining with a newline for separate paragraphs
126
+
127
+ // // Insert text as paragraphs
128
+ // const textNodes = paragraphs.split('\n').map(text => ({
129
+ // type: 'paragraph',
130
+ // children: [{ text }]
131
+ // }));
132
+
133
+ // Transforms.insertNodes(editor, textNodes);
120
134
  } else {
121
135
  // do not paste table, grid inside table cell
122
136
  // only plain text for internal paste
@@ -141,6 +155,15 @@ const withHtml = editor => {
141
155
  }
142
156
  const fragment = deserialize(parsed.body);
143
157
  const formattedFragment = formatFragment[eltype] ? formatFragment[eltype](fragment) : fragment;
158
+ let is_img_table = false;
159
+ formattedFragment.map(f => {
160
+ if (f.type === 'image' || f.type === 'table') {
161
+ is_img_table = true;
162
+ }
163
+ });
164
+ if (editor.isChatEditor && is_img_table) {
165
+ return;
166
+ }
144
167
  handleInsert(editor, () => Transforms.insertFragment(editor, formattedFragment), formattedFragment);
145
168
  return;
146
169
  } else {
@@ -1,9 +1,6 @@
1
1
  import { Editor, Transforms, Element as SlateElement } from "slate";
2
2
  import { Box } from "@mui/material";
3
3
  import { fontFamilyMap, sizeMap } from "../font";
4
- import Table from "../../Elements/Table/Table";
5
- import TableRow from "../../Elements/Table/TableRow";
6
- import TableCell from "../../Elements/Table/TableCell";
7
4
  import Mentions from "../../Elements/Mentions/Mentions";
8
5
  import CheckList from "../../Elements/List/CheckList";
9
6
  import { isEmptyTextNode } from "../../helper";
@@ -340,26 +337,6 @@ export const getBlock = props => {
340
337
  ...props,
341
338
  isEmpty: isEmpty
342
339
  });
343
- case "table":
344
- return /*#__PURE__*/_jsx(Table, {
345
- ...props
346
- });
347
- case "table-head":
348
- return /*#__PURE__*/_jsx("thead", {
349
- children: children
350
- });
351
- case "table-body":
352
- return /*#__PURE__*/_jsx("tbody", {
353
- children: children
354
- });
355
- case "table-row":
356
- return /*#__PURE__*/_jsx(TableRow, {
357
- ...props
358
- });
359
- case "table-cell":
360
- return /*#__PURE__*/_jsx(TableCell, {
361
- ...props
362
- });
363
340
  case "mention":
364
341
  return /*#__PURE__*/_jsx(Mentions, {
365
342
  ...props
@@ -5,6 +5,7 @@ import { insertAccordion } from "./accordion";
5
5
  import { isListItem } from "./helper";
6
6
  import RnDCtrlCmds from "./RnD/RnDCtrlCmds";
7
7
  import EDITORCMDS from "../common/EditorCmds";
8
+ import { ReactEditor } from "slate-react";
8
9
  const HOTKEYS = {
9
10
  b: "bold",
10
11
  i: "italic",
@@ -284,4 +285,40 @@ export const enterEvent = (e, editor, isMobile) => {
284
285
  } catch (err) {
285
286
  console.log(err);
286
287
  }
288
+ };
289
+ export const upArrowEvent = (e, editor) => {
290
+ try {
291
+ const {
292
+ selection
293
+ } = editor;
294
+ if (!selection) return;
295
+ const prevNodePath = Editor.before(editor, selection, {
296
+ unit: "line"
297
+ });
298
+ if (prevNodePath) {
299
+ e.preventDefault();
300
+ Transforms.select(editor, prevNodePath);
301
+ ReactEditor.focus(editor);
302
+ }
303
+ } catch (err) {
304
+ console.log(err);
305
+ }
306
+ };
307
+ export const downArrowEvent = (e, editor) => {
308
+ try {
309
+ const {
310
+ selection
311
+ } = editor;
312
+ if (!selection) return;
313
+ const nextNodePath = Editor.after(editor, selection, {
314
+ unit: "line"
315
+ });
316
+ if (nextNodePath) {
317
+ e.preventDefault();
318
+ Transforms.select(editor, nextNodePath);
319
+ ReactEditor.focus(editor);
320
+ }
321
+ } catch (err) {
322
+ console.log(err);
323
+ }
287
324
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flozy/editor",
3
- "version": "4.2.2",
3
+ "version": "4.2.4",
4
4
  "description": "An Editor for flozy app brain",
5
5
  "files": [
6
6
  "dist"