@flozy/editor 4.2.8 → 4.3.0

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.
@@ -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, upArrowEvent, downArrowEvent } from "./utils/events";
13
+ import { mentionsEvent, commands, indentation, escapeEvent, enterEvent } from "./utils/events";
14
14
  import withCommon from "./hooks/withCommon";
15
15
  import DialogWrapper from "./DialogWrapper";
16
16
  import { serializeToText } from "./utils/serializeToText";
@@ -379,10 +379,6 @@ 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);
386
382
  }
387
383
  }, [chars, editor, target, mentions, setMentions, search, type, mentionsRef]);
388
384
  const Overlay = collaborativeEditor && !isReadOnly ? RemoteCursorOverlay : React.Fragment;
@@ -447,10 +443,13 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
447
443
  const selection = window?.getSelection();
448
444
  if (selection && selection.rangeCount > 0) {
449
445
  const cursorPosition = selection.getRangeAt(0)?.getBoundingClientRect();
450
- const containerBottom = container?.getBoundingClientRect()?.bottom;
446
+ const containerRect = container?.getBoundingClientRect();
447
+ const containerBottom = containerRect?.bottom;
451
448
  if (cursorPosition && cursorPosition.bottom > containerBottom - 250) {
449
+ // Calculate dynamic scroll based on remaining space
450
+ const scrollAmount = Math.min(200, cursorPosition.bottom - containerBottom + 250);
452
451
  container?.scrollBy({
453
- top: 200,
452
+ top: scrollAmount,
454
453
  behavior: "smooth"
455
454
  });
456
455
  }
@@ -545,7 +544,8 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
545
544
  customProps: customProps,
546
545
  theme: theme
547
546
  }) : null, /*#__PURE__*/_jsx(PopoverAIInput, {
548
- otherProps: otherProps || {}
547
+ otherProps: otherProps || {},
548
+ editorWrapper: editorWrapper
549
549
  }), footer && (fullScreen || readOnly) && /*#__PURE__*/_jsx(Typography, {
550
550
  sx: {
551
551
  color: "rgb(100, 116, 139)",
@@ -563,7 +563,8 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
563
563
  onDrawerOpen: onDrawerOpen,
564
564
  theme: theme,
565
565
  setIsTextSelected: setIsTextSelected,
566
- customProps: customProps
566
+ customProps: customProps,
567
+ editorWrapper: editorWrapper
567
568
  }) : null, !readOnly && showViewport ? /*#__PURE__*/_jsx(SwitchViewport, {
568
569
  breakpoint: breakpoint,
569
570
  onChange: b => onSwitchBreakpoint(b)
@@ -9,6 +9,7 @@ import { MODES } from "./helper";
9
9
  import { getSelectedText } from "../../utils/helper";
10
10
  import { VoiceToText } from "./VoiceToText";
11
11
  import deserialize from "../../helper/deserialize";
12
+ import useEditorScroll from "../../hooks/useEditorScroll";
12
13
  import { jsx as _jsx } from "react/jsx-runtime";
13
14
  import { jsxs as _jsxs } from "react/jsx-runtime";
14
15
  const getInputWidth = selectedElement => {
@@ -154,7 +155,10 @@ const updateAnchorEl = (setAnchorEl, editor, openAI, selectedElement) => {
154
155
  }
155
156
  };
156
157
  function PopoverAIInput({
157
- otherProps
158
+ otherProps,
159
+ editorWrapper = {
160
+ current: null
161
+ }
158
162
  }) {
159
163
  const {
160
164
  services
@@ -171,6 +175,10 @@ function PopoverAIInput({
171
175
  const [selectedOption, setSelectedOption] = useState();
172
176
  const classes = Styles();
173
177
  const editor = useSlate();
178
+ const updateAnchor = () => {
179
+ updateAnchorEl(setAnchorEl, editor, openAI, selectedElement);
180
+ };
181
+ useEditorScroll(editorWrapper, updateAnchor);
174
182
  const onClickOutside = () => {
175
183
  setAnchorEl(null);
176
184
  setOpenAI("");
@@ -181,9 +189,7 @@ function PopoverAIInput({
181
189
  ReactEditor.focus(editor);
182
190
  Transforms.deselect(editor);
183
191
  };
184
- useEffect(() => {
185
- updateAnchorEl(setAnchorEl, editor, openAI, selectedElement);
186
- }, [openAI, editor.selection]);
192
+ useEffect(updateAnchor, [openAI, editor.selection]);
187
193
  useEffect(() => {
188
194
  if (openAI) {
189
195
  scrollToAIInput(editor);
@@ -1,6 +1,7 @@
1
1
  const Styles = theme => ({
2
2
  aiContainer: {
3
3
  background: "#FCFAFF",
4
+ background: theme?.palette?.editor?.aiInputBackground,
4
5
  border: "1px solid #8360FD",
5
6
  borderRadius: "6px",
6
7
  boxShadow: "0px 4px 10px 0px #00000029"
@@ -12,7 +13,7 @@ const Styles = theme => ({
12
13
  padding: "0px 4px 0px 12px",
13
14
  minHeight: "36px",
14
15
  position: "relative",
15
- background: "#FCFAFF",
16
+ background: theme?.palette?.editor?.aiInputBackground,
16
17
  borderRadius: "5px",
17
18
  "& .icon-container": {
18
19
  display: "flex",
@@ -29,7 +30,7 @@ const Styles = theme => ({
29
30
  background: "transparent",
30
31
  resize: "none",
31
32
  alignSelf: "center",
32
- color: "#000",
33
+ color: theme?.palette?.editor?.textColor,
33
34
  fontSize: "14px !important",
34
35
  fontFamily: '"Inter", sans-serif',
35
36
  "&:focus-visible": {
@@ -81,6 +82,7 @@ const Styles = theme => ({
81
82
  },
82
83
  sendBtnDisabled: {
83
84
  background: "#C0C9D6",
85
+ opacity: "0.5",
84
86
  "&:hover": {
85
87
  background: "#C0C9D6"
86
88
  }
@@ -4,6 +4,7 @@ import STTStyles from "./style";
4
4
  import { Grid, IconButton, Box } from "@mui/material";
5
5
  import { AudioWave } from "./AudioWave";
6
6
  import { CloseGreyCircle, PauseRecordingIcon, TickBlueCircle } from "../../../assets/svg/AIIcons";
7
+ import { useEditorContext } from "../../../hooks/useMouseMove";
7
8
  import { jsx as _jsx } from "react/jsx-runtime";
8
9
  import { jsxs as _jsxs } from "react/jsx-runtime";
9
10
  function STT(props) {
@@ -15,7 +16,10 @@ function STT(props) {
15
16
  const {
16
17
  services
17
18
  } = otherProps;
18
- const classes = STTStyles();
19
+ const {
20
+ theme
21
+ } = useEditorContext();
22
+ const classes = STTStyles(theme);
19
23
  const [mediaRecorder, setMediaRecorder] = useState(null);
20
24
  const [audioChunks, setAudioChunks] = useState([]);
21
25
  const [chunkIndex, setChunkIndex] = useState(0);
@@ -127,6 +131,7 @@ function STT(props) {
127
131
  children: [/*#__PURE__*/_jsx(Box, {
128
132
  children: /*#__PURE__*/_jsx(IconButton, {
129
133
  onClick: closeRecording,
134
+ className: "ai-icon",
130
135
  children: /*#__PURE__*/_jsx(CloseGreyCircle, {})
131
136
  })
132
137
  }), /*#__PURE__*/_jsx(Box, {
@@ -137,6 +142,7 @@ function STT(props) {
137
142
  }), /*#__PURE__*/_jsx(Box, {
138
143
  children: showPause ? /*#__PURE__*/_jsx(IconButton, {
139
144
  onClick: stopRecording,
145
+ className: "ai-icon",
140
146
  children: /*#__PURE__*/_jsx(PauseRecordingIcon, {})
141
147
  }) : /*#__PURE__*/_jsx(IconButton, {
142
148
  onClick: sendToInfiniti,
@@ -1,4 +1,4 @@
1
- const styles = () => ({
1
+ const styles = theme => ({
2
2
  SttContainer: {
3
3
  display: "flex",
4
4
  width: "100%",
@@ -12,17 +12,25 @@ const styles = () => ({
12
12
  borderColor: "#2563EB"
13
13
  },
14
14
  "&& .MuiOutlinedInput-root": {
15
- background: "rgba(252, 250, 255, 1)"
15
+ background: theme?.palette?.editor?.aiInputBackground
16
16
  }
17
17
  },
18
18
  AudioVizualizerContainer: {
19
19
  width: "100%",
20
20
  display: "flex",
21
- background: "rgba(252, 250, 255, 1)",
21
+ background: theme?.palette?.editor?.aiInputBackground,
22
22
  borderRadius: "8px",
23
23
  border: "1px solid #2563EB",
24
24
  alignItems: "center",
25
- flexWrap: "wrap"
25
+ flexWrap: "wrap",
26
+ "& .ai-icon": {
27
+ "& circle": {
28
+ fill: theme?.palette?.editor?.aiInputBackground
29
+ },
30
+ "& rect": {
31
+ fill: theme?.palette?.editor?.aiInputBackground
32
+ }
33
+ }
26
34
  },
27
35
  AudioVizualizerContent: {
28
36
  display: "flex",
@@ -12,7 +12,8 @@ import { jsxs as _jsxs } from "react/jsx-runtime";
12
12
  const EmojiButton = /*#__PURE__*/forwardRef((props, ref) => {
13
13
  const {
14
14
  icoBtnType,
15
- selectionTarget
15
+ selectionTarget,
16
+ theme = 'light'
16
17
  } = props;
17
18
  const editor = useSlateStatic();
18
19
  const [anchorEl, setAnchorEl] = useState(null);
@@ -67,7 +68,8 @@ const EmojiButton = /*#__PURE__*/forwardRef((props, ref) => {
67
68
  children: /*#__PURE__*/_jsx(Paper, {
68
69
  children: /*#__PURE__*/_jsx(EmojiPicker, {
69
70
  data: data,
70
- onEmojiSelect: onEmojiSelect
71
+ onEmojiSelect: onEmojiSelect,
72
+ theme: theme?.palette?.type
71
73
  })
72
74
  })
73
75
  })]
@@ -6,7 +6,7 @@ const EmojiPicker = props => {
6
6
  const {
7
7
  onEmojiSelect,
8
8
  onClose,
9
- theme = 'dark'
9
+ theme = 'light'
10
10
  } = props;
11
11
  return /*#__PURE__*/_jsx(_Fragment, {
12
12
  children: /*#__PURE__*/_jsx(Picker, {
@@ -2,6 +2,7 @@ const commonOptions = ["drag", "edit", "settings", "saveAsTemplate", "close"];
2
2
  const textOptions = ["edit", "settings", "link", "saveAsTemplate", "close"];
3
3
  const buttonOptions = ["settings", "link", "saveAsTemplate", "close"];
4
4
  const imageOptions = ["settings", "link", "imageFrame", "saveAsTemplate", "close"];
5
+ const videoOptions = ["settings", "saveAsTemplate", "close"];
5
6
  const boxOptions = ["settings", "link", "saveAsTemplate", "close"];
6
7
  const appHeaderOptions = ["settings", "saveAsTemplate", "close"];
7
8
  const tableOptions = ["drag", "edit", "settings", "saveAsTemplate", "close"];
@@ -18,6 +19,7 @@ const itemOptions = {
18
19
  form: formOptions,
19
20
  section: sectionOptions,
20
21
  table: tableOptions,
21
- embedScript: embedScriptOptions
22
+ embedScript: embedScriptOptions,
23
+ video: videoOptions
22
24
  };
23
25
  export default itemOptions;
@@ -26,7 +26,13 @@ const VariableButton = props => {
26
26
  onChange: updateVariable,
27
27
  IconComponent: () => /*#__PURE__*/_jsx(KeyboardArrowDownIcon, {}),
28
28
  MenuProps: {
29
- sx: classes.variableMenuItem
29
+ sx: classes.variableMenuItem,
30
+ PaperProps: {
31
+ style: {
32
+ maxHeight: 300,
33
+ overflowY: "auto"
34
+ }
35
+ }
30
36
  },
31
37
  children: [/*#__PURE__*/_jsx(MenuItem, {
32
38
  value: "",
@@ -8,12 +8,14 @@ import useWindowResize from "../../hooks/useWindowResize";
8
8
  import MiniTextFormat from "./MiniTextFormat";
9
9
  import { useEditorContext } from "../../hooks/useMouseMove";
10
10
  import usePopupStyles from "../PopupTool/PopupToolStyle";
11
+ import useEditorScroll from "../../hooks/useEditorScroll";
11
12
  import { jsx as _jsx } from "react/jsx-runtime";
12
13
  const PopupTool = props => {
13
14
  const {
14
15
  theme,
15
16
  setIsTextSelected,
16
- customProps
17
+ customProps,
18
+ editorWrapper
17
19
  } = props;
18
20
  const classes = usePopupStyles(theme);
19
21
  const {
@@ -33,6 +35,27 @@ const PopupTool = props => {
33
35
  const {
34
36
  selectedElement
35
37
  } = useEditorContext();
38
+ const updateAnchorEl = () => {
39
+ try {
40
+ const domSelection = window.getSelection();
41
+ const domRange = domSelection?.getRangeAt(0);
42
+ const {
43
+ startOffset,
44
+ endOffset
45
+ } = domRange || {};
46
+ if (startOffset !== endOffset) {
47
+ const rect = domRange.getBoundingClientRect();
48
+ setAnchorEl({
49
+ clientWidth: rect.width,
50
+ clientHeight: rect.height,
51
+ getBoundingClientRect: () => rect
52
+ });
53
+ }
54
+ } catch (err) {
55
+ console.log(err);
56
+ }
57
+ };
58
+ useEditorScroll(editorWrapper, updateAnchorEl);
36
59
  useEffect(() => {
37
60
  const userStoppedSelection = size?.device === "xs" ? true : event === "end"; // for mobile, when user starts the selection, we are gonna show the popup tool
38
61
 
@@ -57,36 +80,16 @@ const PopupTool = props => {
57
80
  updateAnchorEl();
58
81
  }
59
82
  }, [selection]);
60
- useEffect(() => {
61
- if (selectedElement?.enable === 1) {
62
- setAnchorEl(null);
63
- }
64
- }, [selection, selectedElement?.path, selectedElement?.enable]);
65
- const updateAnchorEl = () => {
66
- try {
67
- const domSelection = window.getSelection();
68
- const domRange = domSelection?.getRangeAt(0);
69
- const {
70
- startOffset,
71
- endOffset
72
- } = domRange || {};
73
- if (startOffset !== endOffset) {
74
- const rect = domRange.getBoundingClientRect();
75
- setAnchorEl({
76
- clientWidth: rect.width,
77
- clientHeight: rect.height,
78
- getBoundingClientRect: () => rect
79
- });
80
- }
81
- } catch (err) {
82
- console.log(err);
83
- }
84
- };
85
83
  const handleClose = () => {
86
84
  setAnchorEl(null);
87
85
  setOpen(false);
88
86
  setPopupType("");
89
87
  };
88
+ useEffect(() => {
89
+ if (selectedElement?.enable === 1) {
90
+ setAnchorEl(null);
91
+ }
92
+ }, [selection, selectedElement?.path, selectedElement?.enable]);
90
93
  return open && !openAI ? /*#__PURE__*/_jsx(ClickAwayListener, {
91
94
  onClickAway: e => {
92
95
  // close the mini toolbar, if user clicks outside the editor (in Flozy app.)
@@ -503,6 +503,10 @@ export const CloseGreyCircle = () => /*#__PURE__*/_jsxs("svg", {
503
503
  viewBox: "0 0 30 30",
504
504
  fill: "none",
505
505
  xmlns: "http://www.w3.org/2000/svg",
506
+ style: {
507
+ border: "1.3px solid #2563EB",
508
+ borderRadius: "50%"
509
+ },
506
510
  children: [/*#__PURE__*/_jsx("rect", {
507
511
  width: "30",
508
512
  height: "30",
@@ -87,7 +87,8 @@ const MentionsPopup = /*#__PURE__*/forwardRef((props, ref) => {
87
87
  ref: i === index ? papperRef : null,
88
88
  children: char.renderComponent ? char.renderComponent({
89
89
  ref: index === i ? buttonRef : null,
90
- selectionTarget: target
90
+ selectionTarget: target,
91
+ theme: theme
91
92
  }) : ListElement ? /*#__PURE__*/_jsx(ListElement, {
92
93
  classes: classes,
93
94
  data: char,
@@ -299,9 +299,12 @@ export const getTextColor = (color = "") => {
299
299
  return color?.indexOf("gradient") >= 0 ? {
300
300
  background: color?.concat("text"),
301
301
  WebkitBackgroundClip: "text",
302
- WebkitTextFillColor: "transparent",
303
- color: "transparent",
304
- caretColor: "black"
302
+ WebkitTextFillColor: "transparent !important",
303
+ color: "transparent !important",
304
+ caretColor: "black",
305
+ '& span': {
306
+ color: "transparent !important"
307
+ }
305
308
  } : {
306
309
  color
307
310
  };
@@ -0,0 +1,24 @@
1
+ import { useEffect } from "react";
2
+ function useEditorScroll(editorWrapper = {
3
+ current: null
4
+ }, callback) {
5
+ useEffect(() => {
6
+ const handleScroll = () => {
7
+ if (editorWrapper.current) {
8
+ callback();
9
+ }
10
+ };
11
+ const currentEditorWrapper = editorWrapper.current;
12
+ if (currentEditorWrapper) {
13
+ currentEditorWrapper.addEventListener("scroll", handleScroll);
14
+ }
15
+
16
+ // Cleanup the event listener on component unmount
17
+ return () => {
18
+ if (currentEditorWrapper) {
19
+ currentEditorWrapper.removeEventListener("scroll", handleScroll);
20
+ }
21
+ };
22
+ }, [editorWrapper.current]);
23
+ }
24
+ export default useEditorScroll;
@@ -285,40 +285,4 @@ export const enterEvent = (e, editor, isMobile) => {
285
285
  } catch (err) {
286
286
  console.log(err);
287
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
- }
324
288
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flozy/editor",
3
- "version": "4.2.8",
3
+ "version": "4.3.0",
4
4
  "description": "An Editor for flozy app brain",
5
5
  "files": [
6
6
  "dist"