@flozy/editor 4.4.9 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -27,7 +27,7 @@ import DragAndDrop from "./common/DnD";
27
27
  import Section from "./common/Section";
28
28
  import decorators from "./utils/Decorators";
29
29
  import { getTRBLBreakPoints } from "./helper/theme";
30
- import { handleInsertLastElement, isFreeGridFragment, outsideEditorClickLabel } from "./utils/helper";
30
+ import { handleInsertLastElement, isFreeGrid, isFreeGridFragment, outsideEditorClickLabel } from "./utils/helper";
31
31
  import useWindowResize from "./hooks/useWindowResize";
32
32
  import PopoverAIInput from "./Elements/AI/PopoverAIInput";
33
33
  import RnDCopy from "./common/RnD/RnDCopy";
@@ -82,7 +82,6 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
82
82
  onSave,
83
83
  editor: collaborativeEditor,
84
84
  readOnly,
85
- toolbarOptions,
86
85
  otherProps,
87
86
  isIframe,
88
87
  theme,
@@ -288,10 +287,11 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
288
287
  index,
289
288
  type
290
289
  } = mentions;
291
- const chars = type ? Shorthands[type]({
290
+ const updatedHideTools = !isFreeGrid(content) ? [...hideTools, "freegrid"] : hideTools;
291
+ const chars = type && !isFreeGrid(content) ? Shorthands[type]({
292
292
  ...mentions,
293
293
  CHARACTERS,
294
- hideTools: hideTools || []
294
+ hideTools: updatedHideTools || []
295
295
  }) : [];
296
296
  const handleEditorChange = newValue => {
297
297
  setValue(newValue);
@@ -370,7 +370,7 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
370
370
  } else if (event.key === "ArrowDown" && otherProps?.tagName !== 'Pages') {
371
371
  upDownArrowKeyEvents(event, editor);
372
372
  }
373
- }, [chars, editor, target, mentions, setMentions, search, type, mentionsRef]);
373
+ }, [chars, target, mentions, setMentions, search, type, mentionsRef]);
374
374
  const Overlay = collaborativeEditor && !isReadOnly ? RemoteCursorOverlay : React.Fragment;
375
375
  const dotBg = needDotsBG ? {
376
376
  background: "white",
@@ -499,6 +499,8 @@ const FreeGrid = props => {
499
499
  backgroundSize: "cover"
500
500
  },
501
501
  "data-path": path.join("|"),
502
+ "data-dragOverId": path.join("|"),
503
+ "data-dragOverType": "parent",
502
504
  style: {
503
505
  "--cols": `100%`,
504
506
  "--rows": `repeat(${repeatTimes}, ${ROW_HEIGHT}px)`
@@ -190,6 +190,8 @@ const FreeGridBox = props => {
190
190
  ...attributes,
191
191
  className: "fgi_type_box freegrid-container-parent",
192
192
  "data-path": path.join("|"),
193
+ "data-dragOverId": path.join("|"),
194
+ "data-dragOverType": "parent",
193
195
  style: {
194
196
  "--height": `${height}px`,
195
197
  "--cols": `100%`,
@@ -20,6 +20,9 @@ const useFreeGridStyles = ({
20
20
  marginLeft: `calc((100% - ${MAX_DEVICE_WIDTH}px) * 0.5)`,
21
21
  "&.active-drag": {
22
22
  pointerEvents: "none",
23
+ "& *": {
24
+ pointerEvents: "none"
25
+ },
23
26
  zIndex: "9999 !important"
24
27
  },
25
28
  "&.inactive-drag": {
@@ -206,9 +209,26 @@ const useFreeGridStyles = ({
206
209
  "& .freegrid-item": {
207
210
  marginLeft: "0px"
208
211
  // pointerEvents: "none",
212
+ },
213
+
214
+ "&.rnd-dragOver": {
215
+ outline: "2px solid #116dff",
216
+ "&:before": {
217
+ content: '"Attach to Box"',
218
+ position: "absolute",
219
+ top: "-36px",
220
+ left: 0,
221
+ right: 0,
222
+ margin: "0px auto",
223
+ width: "fit-content",
224
+ background: "#116dff",
225
+ padding: "8px 12px",
226
+ color: "#FFF",
227
+ fontSize: "14px",
228
+ borderRadius: "7px"
229
+ }
209
230
  }
210
231
  },
211
-
212
232
  "& .fgi_type_form": {
213
233
  "& .form-field": {
214
234
  "& input": {
@@ -289,6 +309,22 @@ const useFreeGridStyles = ({
289
309
  [theme.breakpoints.between("xs", "md")]: {
290
310
  marginLeft: `calc((100% - 320px) * 0.5)`
291
311
  }
312
+ },
313
+ "&.rnd-dragOver": {
314
+ "&:before": {
315
+ content: '"Attact to this Section"',
316
+ position: "absolute",
317
+ top: 0,
318
+ left: 0,
319
+ right: 0,
320
+ margin: "0px auto",
321
+ width: "fit-content",
322
+ background: "#116dff",
323
+ padding: "8px 12px",
324
+ color: "#FFF",
325
+ fontSize: "14px",
326
+ borderRadius: "7px"
327
+ }
292
328
  }
293
329
  }
294
330
  },
@@ -17,7 +17,6 @@ const DragOver = props => {
17
17
  const open = Boolean(anchorEl);
18
18
  const isSectionHover = status && type === "parent";
19
19
  const isContainerHover = hover_on === path && type === "parent-container";
20
- console.log(isSectionHover, isContainerHover);
21
20
  useEffect(() => {
22
21
  if (ref?.current) {
23
22
  const getBoundingClientRect = () => ref?.current?.getBoundingClientRect();
@@ -11,13 +11,14 @@ import DragInfo from "./DragInfo";
11
11
  import GuideLines from "./GuideLines";
12
12
  import ShadowElement from "./ShadowElement";
13
13
  import BoundaryLine from "./GuideLines/BoundaryLine";
14
- import DragOver from "./DragOver";
15
14
  import ContextMenu from "./ContextMenu";
16
15
  import VirtualElement from "./VirtualElement";
17
16
  import { ItemTypes } from "./ElementSettings/settingsConstants";
18
17
  import { focusSelection, clearSelection } from "../../helper";
19
18
  import { selectText } from "../../utils/helper";
20
19
  import { removeSign } from "./ElementSettings/OtherSettings";
20
+ import useDragging from "../../hooks/useDragging";
21
+ import { dragOverOn } from "../../helper/RnD/focusNode";
21
22
  import { jsx as _jsx } from "react/jsx-runtime";
22
23
  import { jsxs as _jsxs } from "react/jsx-runtime";
23
24
  import { Fragment as _Fragment } from "react/jsx-runtime";
@@ -58,7 +59,6 @@ const RnD = props => {
58
59
  const {
59
60
  isSelectedElement,
60
61
  setSelectedElement,
61
- dragging,
62
62
  updateDragging,
63
63
  contextMenu,
64
64
  setContextMenu,
@@ -76,21 +76,25 @@ const RnD = props => {
76
76
  const open = Boolean(enable);
77
77
  const currentAction = str_path === sp ? selectedAction : null;
78
78
  const positionRef = useRef();
79
+ const {
80
+ draggingRef,
81
+ startDragging,
82
+ stopDragging,
83
+ setDragOver
84
+ } = useDragging();
85
+ const dragging = draggingRef?.current;
79
86
  const {
80
87
  active,
81
88
  id,
82
- parentPath,
83
- dragOver
89
+ parentPath
84
90
  } = dragging;
85
91
  const dragInfoOpen = id === str_path;
86
- const dragOverStatus = dragOver === str_path && parentPath !== str_path;
87
92
  const [absPosition, setAbsPosition] = useState({});
88
93
  const openContextMenu = contextMenu?.path === str_path;
89
94
  const [position, setPosition] = useState({
90
95
  x: 0,
91
96
  y: 0
92
97
  });
93
- const pathIsDragging = dragOver === str_path && dragging?.isDragging;
94
98
  const parentSectionPath = str_path?.split("|").slice(0, 2).join("_");
95
99
  useEffect(() => {
96
100
  if (ITEM_TYPES.includes(type)) {
@@ -156,7 +160,6 @@ const RnD = props => {
156
160
  switch (e.detail) {
157
161
  case 1:
158
162
  if (!enable) {
159
- // focusSelection(editor, { path });
160
163
  setSelectedElement({
161
164
  path: str_path,
162
165
  enable: 1,
@@ -164,6 +167,7 @@ const RnD = props => {
164
167
  anchorEl: rndRef?.current
165
168
  });
166
169
  }
170
+ // ReactEditor.focus(editor);
167
171
  break;
168
172
  case 2:
169
173
  focusSelection(editor, {
@@ -281,9 +285,8 @@ const RnD = props => {
281
285
  dragOver: null
282
286
  }, null);
283
287
  }
284
- // focusSelection(editor, { path: updated_at });
288
+ stopDragging();
285
289
  };
286
-
287
290
  const onDragStart = e => {
288
291
  e.preventDefault();
289
292
  if (e?.target?.dataset?.path?.split(",").join("|") === sp) {
@@ -301,6 +304,9 @@ const RnD = props => {
301
304
  diffX: parseInt(Math.abs(Math.floor(left - e.clientX))),
302
305
  diffY: parseInt(Math.abs(Math.floor(top - e.clientY)))
303
306
  };
307
+ const parentPath = getParentSectionPath({
308
+ ref
309
+ }, ".freegrid-container-parent");
304
310
  updateDragging({
305
311
  ...dragging,
306
312
  active: true,
@@ -312,17 +318,24 @@ const RnD = props => {
312
318
  width,
313
319
  height
314
320
  },
315
- isDragging: true,
316
- parentPath: getParentSectionPath({
317
- ref
318
- }, ".freegrid-container-parent")
321
+ isDragging: 1,
322
+ parentPath
319
323
  });
320
324
  setPosition({
321
325
  ...updatedPosition
322
326
  });
327
+ startDragging({
328
+ active: true,
329
+ id: str_path,
330
+ position: {
331
+ ...updatedPosition
332
+ },
333
+ isDragging: 1,
334
+ parentPath
335
+ });
323
336
  }
324
337
  };
325
- const onDrag = (e, d) => {
338
+ const onDrag = e => {
326
339
  e.preventDefault();
327
340
  const lines = getClosestDraggable(e.clientX, e.clientY, `.freegrid-section_${parentSectionPath} .freegrid-container .freegrid-item.inactive-drag`.replace(/\|/g, "\\|"), ".freegrid-item.active-drag:not(.exclude-virtual)");
328
341
  setAbsPosition({
@@ -330,7 +343,7 @@ const RnD = props => {
330
343
  "--zIndex": 2000
331
344
  });
332
345
  updateDragging({
333
- isDragging: true,
346
+ isDragging: 2,
334
347
  position: {
335
348
  ...dragging.position,
336
349
  x: e.clientX,
@@ -344,16 +357,34 @@ const RnD = props => {
344
357
  y: e.clientY,
345
358
  lines: lines
346
359
  });
360
+ const isDragOverOnParent = {};
361
+ let dragOverEle = e?.toElement?.dataset?.dragovertype !== "child" ? e?.toElement : e?.toElement?.closest(".freegrid-container-parent");
362
+
363
+ // some cases
364
+ if (dragOverEle?.dataset?.dragovertype === undefined) {
365
+ // means check for parent element
366
+ dragOverEle = e?.toElement?.parentElement;
367
+ }
368
+ if (dragOverEle?.dataset?.dragovertype !== "child") {
369
+ const oldPath = dragging.dragOver;
370
+ isDragOverOnParent.dragOver = dragOverEle?.dataset?.dragoverid;
371
+ isDragOverOnParent.dragOverType = dragOverEle?.dataset?.dragovertype;
372
+ dragOverOn(oldPath, dragOverEle?.dataset?.dragoverid);
373
+ }
374
+ startDragging({
375
+ isDragging: 2,
376
+ ...isDragOverOnParent
377
+ });
347
378
  };
348
379
  const onDragStop = (e, d) => {
349
380
  e.preventDefault();
350
381
  e.stopPropagation();
351
- if (dragging?.isDragging && dragging?.position?.strXY) {
382
+ if (dragging?.isDragging === 2 && dragging?.position?.strXY && dragging?.dragOver) {
352
383
  d.x = e.x;
353
384
  d.y = e.y;
354
385
  d.offsetX = e.offsetX;
355
386
  d.offsetY = e.offsetY;
356
- d.dragOver = dragOver;
387
+ d.dragOver = dragging?.dragOver;
357
388
  d.parentPath = parentPath;
358
389
  d.diffX = position?.diffX;
359
390
  d.diffY = position?.diffY;
@@ -381,6 +412,11 @@ const RnD = props => {
381
412
  setAbsPosition({
382
413
  ...ud
383
414
  });
415
+ stopDragging();
416
+ } else {
417
+ // invalid drags
418
+ // found in dev mode and in safari browser
419
+ onAfterDrop(path);
384
420
  }
385
421
  };
386
422
  const onResizeStop = (e, direction, ref, d, position) => {
@@ -431,6 +467,9 @@ const RnD = props => {
431
467
  e.stopPropagation();
432
468
  }
433
469
  if (type !== "child") {
470
+ setDragOver({
471
+ dragOver: str_path
472
+ });
434
473
  updateDragging({
435
474
  dragOver: str_path
436
475
  }, str_path);
@@ -504,14 +543,9 @@ const RnD = props => {
504
543
  "data-event": "rnd-click",
505
544
  className: "editor-blocker",
506
545
  "data-path": path,
507
- contentEditable: false
508
- }) : null, pathIsDragging ? /*#__PURE__*/_jsx(DragOver, {
509
- status: dragOverStatus,
510
- hover_on: dragOver,
511
- path: str_path,
512
- parentPath: parentPath,
513
- type: type,
514
- childType: childType
546
+ contentEditable: false,
547
+ "data-dragOverId": str_path,
548
+ "data-dragOverType": type
515
549
  }) : null]
516
550
  }, eId), !active && rndRef?.current && open ? /*#__PURE__*/_jsx(ElementOptions, {
517
551
  id: `opt_ref_${str_path}`,
@@ -55,15 +55,17 @@ const SectionStyle = theme => ({
55
55
  },
56
56
  "&.is-temp": {
57
57
  position: "fixed",
58
- background: "red",
58
+ background: "transparent",
59
59
  padding: "12px",
60
60
  width: "10px",
61
61
  height: "10px",
62
- // left: 0,
63
- // top: 0,
62
+ left: 0,
63
+ top: 0,
64
+ bottom: 0,
65
+ right: 0,
64
66
  margin: "auto",
65
- left: "var(--left)",
66
- top: "var(--top)",
67
+ // left: "var(--left)",
68
+ // top: "var(--top)",
67
69
  zIndex: 1000,
68
70
  pointerEvents: "none"
69
71
  }
@@ -17,6 +17,7 @@ const ensureTemporaryFocusNode = (editor, selectedDOM) => {
17
17
  type: "temp",
18
18
  temp: TEMP_NODE_ID,
19
19
  children: [{
20
+ type: "restrictedType",
20
21
  text: ""
21
22
  }],
22
23
  left,
@@ -24,22 +25,9 @@ const ensureTemporaryFocusNode = (editor, selectedDOM) => {
24
25
  }, {
25
26
  at: [editor.children.length]
26
27
  });
27
- } else {
28
- Transforms.setNodes(editor, {
29
- type: "temp",
30
- temp: TEMP_NODE_ID,
31
- children: [{
32
- text: ""
33
- }],
34
- left,
35
- top
36
- }, {
37
- at: tempNodeEntry[1]
38
- });
39
28
  }
40
29
  };
41
30
  export const focusUsingTemporaryNode = (editor, selectedDOM) => {
42
- // de-select and select
43
31
  Transforms.deselect(editor);
44
32
 
45
33
  // Ensure the temporary node exists
@@ -52,9 +40,8 @@ export const focusUsingTemporaryNode = (editor, selectedDOM) => {
52
40
  });
53
41
  if (tempNodeEntry) {
54
42
  const [, path] = tempNodeEntry;
55
- Transforms.select(editor, path); // Move selection to the temp node
43
+ Transforms.select(editor, path);
56
44
  }
57
-
58
45
  ReactEditor.focus(editor);
59
46
  };
60
47
  export const cleanupTemporaryFocusNode = editor => {
@@ -67,4 +54,21 @@ export const cleanupTemporaryFocusNode = editor => {
67
54
  at: path
68
55
  });
69
56
  }
57
+ };
58
+ export const dragOverOn = (previousPath, currentPath) => {
59
+ try {
60
+ const previousElement = document.querySelector(`[data-dragoverid="${previousPath}"]`);
61
+ const currentElement = document.querySelector(`[data-dragoverid="${currentPath}"]`);
62
+ // Remove 'dragOver' class from the current element, if it exists
63
+ if (previousElement && previousElement.classList.contains("rnd-dragOver")) {
64
+ previousElement.classList.remove("rnd-dragOver");
65
+ }
66
+
67
+ // Add 'dragOver' class to the new element
68
+ if (currentElement) {
69
+ currentElement.classList.add("rnd-dragOver");
70
+ }
71
+ } catch (err) {
72
+ console.log(err);
73
+ }
70
74
  };
@@ -0,0 +1,51 @@
1
+ import { useState, useCallback, useRef } from "react";
2
+ const initialState = {
3
+ id: null,
4
+ active: false,
5
+ isDragging: 0,
6
+ dragOver: false,
7
+ dragOverType: null
8
+ };
9
+ const useDragging = () => {
10
+ const [dragging, setDragging] = useState({
11
+ ...initialState
12
+ });
13
+
14
+ // Ref to keep the latest draggingStatus
15
+ const draggingRef = useRef(dragging);
16
+ const updateDragging = newStatus => {
17
+ setDragging(prevStatus => {
18
+ const updatedStatus = {
19
+ ...prevStatus,
20
+ ...newStatus
21
+ };
22
+ draggingRef.current = updatedStatus; // Update the ref to hold latest status
23
+ return updatedStatus;
24
+ });
25
+ };
26
+ const startDragging = useCallback(data => {
27
+ // console.log("dragissue", "startDragging");
28
+ updateDragging({
29
+ ...data
30
+ });
31
+ }, []);
32
+ const stopDragging = useCallback(() => {
33
+ // console.log("dragissue", "stopDragging");
34
+ updateDragging({
35
+ ...initialState
36
+ });
37
+ }, []);
38
+ const setDragOver = useCallback(isOver => {
39
+ updateDragging({
40
+ dragOver: isOver
41
+ });
42
+ }, []);
43
+ return {
44
+ dragging,
45
+ draggingRef,
46
+ startDragging,
47
+ stopDragging,
48
+ setDragOver
49
+ };
50
+ };
51
+ export default useDragging;
@@ -98,7 +98,11 @@ export const EditorProvider = ({
98
98
  updateDragging,
99
99
  fontFamilies,
100
100
  setFontFamilies
101
- }), [path, editor?.selection, selectedPath, selectedElement, dragging.active, dragging.isDragging, dragging.dragOver, contextMenu, openAI, popupType, drop, fontFamilies]);
101
+ }), [path, editor?.selection, selectedPath, selectedElement,
102
+ // dragging.active,
103
+ // dragging.isDragging,
104
+ // dragging.dragOver,
105
+ contextMenu, openAI, popupType, drop]);
102
106
  return /*#__PURE__*/_jsx(EditorContext.Provider, {
103
107
  value: otherValues,
104
108
  children: children
@@ -9,6 +9,7 @@ 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
+ import withRestrictedNodes from "./withRestrictedNodes";
12
13
  const withCommon = (props, rest = {}) => {
13
14
  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))))))))));
14
15
  };
@@ -0,0 +1,48 @@
1
+ import { Editor } from "slate";
2
+
3
+ // Custom insertText that prevents updates in specific node types
4
+ const withRestrictedNodes = editor => {
5
+ const {
6
+ insertText,
7
+ deleteBackward
8
+ } = editor;
9
+
10
+ // Override insertText
11
+ editor.insertText = text => {
12
+ const {
13
+ selection
14
+ } = editor;
15
+ if (selection) {
16
+ const [node] = Editor.node(editor, selection);
17
+ console.log(node);
18
+
19
+ // Prevent insertText if node type matches
20
+ if (node && node.type === "restrictedType") {
21
+ return; // Skip inserting text
22
+ }
23
+ }
24
+
25
+ // Call the original insertText if node type does not match
26
+ insertText(text);
27
+ };
28
+
29
+ // Similarly override deleteBackward if needed
30
+ editor.deleteBackward = (...args) => {
31
+ const {
32
+ selection
33
+ } = editor;
34
+ if (selection) {
35
+ const [node] = Editor.node(editor, selection);
36
+
37
+ // Prevent deletion if node type matches
38
+ if (node && node.type === "restrictedType") {
39
+ return; // Skip deleting text
40
+ }
41
+ }
42
+
43
+ // Call the original deleteBackward if node type does not match
44
+ deleteBackward(...args);
45
+ };
46
+ return editor;
47
+ };
48
+ export default withRestrictedNodes;
@@ -157,7 +157,7 @@ const onBringBack = (event, {
157
157
  console.log(err);
158
158
  }
159
159
  };
160
- export const onInsertFragment = async ({
160
+ export const onInsertFragment = ({
161
161
  editor,
162
162
  slateNodes
163
163
  }) => {
@@ -181,6 +181,18 @@ export const onInsertFragment = async ({
181
181
  setSelectedElement: window.updateSelectedItem
182
182
  });
183
183
  }
184
+ } else {
185
+ // if no selection place items at last
186
+ const np = onPasteRnDNode(editor, {
187
+ path: [editor.children.length - 1, 0],
188
+ children: [],
189
+ slateNodes: slateNodes
190
+ });
191
+ if (np && window.updateSelectedItem) {
192
+ focusOnNewItem(editor, np, {
193
+ setSelectedElement: window.updateSelectedItem
194
+ });
195
+ }
184
196
  }
185
197
  } catch (err) {
186
198
  console.log(err);
@@ -543,8 +543,8 @@ export const getBlock = props => {
543
543
  return /*#__PURE__*/_jsx("span", {
544
544
  ...attributes,
545
545
  ...element.attr,
546
- contentEditable: false,
547
546
  className: "temp-focus-node",
547
+ contentEditable: false,
548
548
  children: children
549
549
  });
550
550
  default:
@@ -1,4 +1,4 @@
1
- import { Editor, Node, Transforms, Element } from "slate";
1
+ import { Editor, Node, Transforms, Element, Path } from "slate";
2
2
  import { ReactEditor } from "slate-react";
3
3
  import insertNewLine from "./insertNewLine";
4
4
  import { getDevice } from "../helper/theme";
@@ -470,4 +470,20 @@ export const editorThemeStyle = {
470
470
  };
471
471
  export const getEditorTheme = (themeType = "light") => {
472
472
  return editorThemeStyle[themeType] || {};
473
+ };
474
+ export const isFreeGrid = (nodes, types = ["freegrid", "freegridItem", "freegridBox"]) => {
475
+ try {
476
+ for (const node of nodes) {
477
+ if (types.includes(node.type)) {
478
+ return true;
479
+ }
480
+ if (node.children && isFreeGrid(node.children, types)) {
481
+ return true;
482
+ }
483
+ }
484
+ return false;
485
+ } catch (err) {
486
+ console.log('isFreeGrid error:', err);
487
+ return false;
488
+ }
473
489
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flozy/editor",
3
- "version": "4.4.9",
3
+ "version": "4.5.0",
4
4
  "description": "An Editor for flozy app brain",
5
5
  "files": [
6
6
  "dist"