@flozy/editor 3.7.0 → 3.7.2

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.
@@ -0,0 +1,361 @@
1
+ import { Editor, Transforms, Element as SlateElement } from "slate";
2
+ import { Box } from "@mui/material";
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
+ import Mentions from "../../Elements/Mentions/Mentions";
8
+ import CheckList from "../../Elements/List/CheckList";
9
+ import { isEmptyTextNode } from "../../helper";
10
+ import { getBreakPointsValue } from "../../helper/theme";
11
+ import insertNewLine from "../insertNewLine";
12
+ import { getBorderColor } from "../helper";
13
+ import { jsx as _jsx } from "react/jsx-runtime";
14
+ const alignment = ["alignLeft", "alignRight", "alignCenter"];
15
+ const list_types = ["orderedList", "unorderedList"];
16
+ const LIST_FORMAT_TYPE = {
17
+ orderedList: "list-item",
18
+ unorderedList: "list-item"
19
+ };
20
+ const NEWLINESAFTER = ["headingOne", "headingTwo", "headingThree"];
21
+ export const toggleBlock = (editor, format, selection = true, attr = {}) => {
22
+ const isActive = isBlockActive(editor, format);
23
+ const isList = list_types.includes(format);
24
+ const isIndent = alignment.includes(format);
25
+ const isAligned = alignment.some(alignmentType => isBlockActive(editor, alignmentType));
26
+
27
+ /*If the node is already aligned and change in indent is called we should unwrap it first and split the node to prevent
28
+ messy, nested DOM structure and bugs due to that.*/
29
+ if (isAligned && isIndent) {
30
+ Transforms.unwrapNodes(editor, {
31
+ match: n => alignment.includes(!Editor.isEditor(n) && SlateElement.isElement(n) && n.type),
32
+ split: true
33
+ });
34
+ }
35
+
36
+ /* Wraping the nodes for alignment, to allow it to co-exist with other block level operations*/
37
+ if (isIndent) {
38
+ Transforms.wrapNodes(editor, {
39
+ type: format,
40
+ children: []
41
+ });
42
+ return;
43
+ }
44
+ Transforms.unwrapNodes(editor, {
45
+ match: n => list_types.includes(!Editor.isEditor(n) && SlateElement.isElement(n) && n.type),
46
+ split: true
47
+ });
48
+
49
+ // inserting blocks from "/"" commands remove searched word
50
+ if (!selection) {
51
+ Transforms.insertText(editor, "");
52
+ }
53
+ Transforms.setNodes(editor, {
54
+ type: isActive ? "paragraph" : isList ? LIST_FORMAT_TYPE[format] : format,
55
+ ...attr
56
+ });
57
+ if (isList && !isActive) {
58
+ Transforms.wrapNodes(editor, {
59
+ type: format,
60
+ children: []
61
+ });
62
+ }
63
+ if (NEWLINESAFTER.indexOf(format) > -1) {
64
+ insertNewLine(editor);
65
+ }
66
+ };
67
+ export const addMarkData = (editor, data) => {
68
+ try {
69
+ Editor.addMark(editor, data.format, data.value);
70
+ } catch (err) {
71
+ console.log(err);
72
+ }
73
+ };
74
+ export const toggleMark = (editor, format) => {
75
+ const isActive = isMarkActive(editor, format);
76
+ if (isActive) {
77
+ Editor.removeMark(editor, format);
78
+ } else {
79
+ Editor.addMark(editor, format, true);
80
+ }
81
+ };
82
+ export const isMarkActive = (editor, format) => {
83
+ try {
84
+ const marks = Editor.marks(editor);
85
+ return marks ? marks[format] === true : false;
86
+ } catch (err) {
87
+ console.log(err);
88
+ return null;
89
+ }
90
+ };
91
+ export const isBlockActive = (editor, format) => {
92
+ const [match] = Editor.nodes(editor, {
93
+ match: n => !Editor.isEditor(n) && SlateElement.isElement(n) && n.type === format
94
+ });
95
+ return !!match;
96
+ };
97
+ export const getBlockActive = (editor, format) => {
98
+ const [match] = Editor.nodes(editor, {
99
+ match: n => !Editor.isEditor(n) && SlateElement.isElement(n) && n.type === format
100
+ });
101
+ return {
102
+ isActive: !!match,
103
+ props: match && match[0]
104
+ };
105
+ };
106
+ export const upateBlockActive = (editor, format, attr = {}) => {
107
+ const [match] = Editor.nodes(editor, {
108
+ match: n => !Editor.isEditor(n) && SlateElement.isElement(n) && n.type === format
109
+ });
110
+ if (match && match[1] !== undefined) {
111
+ Transforms.setNodes(editor, attr, {
112
+ at: match[1]
113
+ });
114
+ }
115
+ };
116
+ export const activeMark = (editor, format) => {
117
+ const defaultMarkData = {
118
+ color: "#000000",
119
+ bgColor: "#FFFFFF",
120
+ fontSize: "normal",
121
+ fontFamily: "PoppinsRegular",
122
+ fontWeight: "normal"
123
+ };
124
+ try {
125
+ const marks = Editor.marks(editor);
126
+ const defaultValue = defaultMarkData[format];
127
+ return marks?.[format] ?? defaultValue;
128
+ } catch (err) {
129
+ console.log(err);
130
+ return null;
131
+ }
132
+ };
133
+ export const getMarked = (leaf, children) => {
134
+ const className = leaf?.doublequote ? "doublequote" : "";
135
+ if (leaf.bold) {
136
+ children = /*#__PURE__*/_jsx("strong", {
137
+ children: children
138
+ });
139
+ }
140
+ if (leaf.code) {
141
+ children = /*#__PURE__*/_jsx("code", {
142
+ children: children
143
+ });
144
+ }
145
+ if (leaf.italic) {
146
+ children = /*#__PURE__*/_jsx("em", {
147
+ children: children
148
+ });
149
+ }
150
+ if (leaf.strikethrough) {
151
+ children = /*#__PURE__*/_jsx("span", {
152
+ style: {
153
+ textDecoration: "line-through"
154
+ },
155
+ children: children
156
+ });
157
+ }
158
+ if (leaf.underline) {
159
+ children = /*#__PURE__*/_jsx("u", {
160
+ children: children
161
+ });
162
+ }
163
+ if (leaf.superscript) {
164
+ children = /*#__PURE__*/_jsx("sup", {
165
+ children: children
166
+ });
167
+ }
168
+ if (leaf.subscript) {
169
+ children = /*#__PURE__*/_jsx("sub", {
170
+ children: children
171
+ });
172
+ }
173
+ // cover under single span
174
+ if (leaf.color || leaf.bgColor || leaf.fontSize || leaf.fontFamily || leaf.fontWeight || className) {
175
+ const family = fontFamilyMap[leaf?.fontFamily];
176
+ const textStyles = leaf?.color?.indexOf("gradient") >= 0 ? {
177
+ background: leaf?.color?.concat("text"),
178
+ WebkitBackgroundClip: "text",
179
+ WebkitTextFillColor: "transparent"
180
+ } : {
181
+ color: leaf.color
182
+ };
183
+ children = /*#__PURE__*/_jsx("span", {
184
+ style: {
185
+ background: leaf.bgColor
186
+ },
187
+ children: /*#__PURE__*/_jsx(Box, {
188
+ className: className,
189
+ component: "span",
190
+ sx: {
191
+ fontSize: {
192
+ lg: sizeMap[leaf.fontSize] || leaf.fontSize,
193
+ ...getBreakPointsValue(leaf.fontSize, null, "overrideText")
194
+ },
195
+ ...textStyles,
196
+ fontFamily: family,
197
+ fontWeight: leaf.fontWeight
198
+ },
199
+ children: children
200
+ })
201
+ });
202
+ }
203
+ if (leaf.decoration === "link") {
204
+ children = /*#__PURE__*/_jsx("a", {
205
+ style: {
206
+ cursor: "pointer"
207
+ },
208
+ rel: "noreferrer",
209
+ target: "_blank",
210
+ href: leaf.text,
211
+ children: children
212
+ });
213
+ }
214
+ return children;
215
+ };
216
+ export const getBlock = props => {
217
+ const {
218
+ element,
219
+ children
220
+ } = props;
221
+ const attributes = props.attributes ?? {};
222
+ const isEmpty = isEmptyTextNode(element);
223
+ switch (element.type) {
224
+ case "paragraph":
225
+ return /*#__PURE__*/_jsx("p", {
226
+ ...attributes,
227
+ ...element.attr,
228
+ className: `content-editable ${isEmpty ? "empty" : ""}`
229
+ // placeholder="paragraph"
230
+ ,
231
+ children: children
232
+ });
233
+ case "headingOne":
234
+ return /*#__PURE__*/_jsx("h1", {
235
+ ...attributes,
236
+ ...element.attr,
237
+ className: `content-editable ${isEmpty ? "empty" : ""}`
238
+ // placeholder="Heading 1"
239
+ ,
240
+ children: children
241
+ });
242
+ case "headingTwo":
243
+ return /*#__PURE__*/_jsx("h2", {
244
+ ...attributes,
245
+ ...element.attr,
246
+ className: `content-editable ${isEmpty ? "empty" : ""}`
247
+ // placeholder="Heading 2"
248
+ ,
249
+ children: children
250
+ });
251
+ case "headingThree":
252
+ return /*#__PURE__*/_jsx("h3", {
253
+ ...attributes,
254
+ ...element.attr,
255
+ className: `content-editable ${isEmpty ? "empty" : ""}`
256
+ // placeholder="Heading 3"
257
+ ,
258
+ children: children
259
+ });
260
+ case "blockquote":
261
+ return /*#__PURE__*/_jsx("blockquote", {
262
+ ...attributes,
263
+ ...element.attr,
264
+ style: {
265
+ // borderColor: element?.color || "transparent",
266
+ ...getBorderColor(element?.color || "transparent", 3),
267
+ background: element?.bgColor || "none",
268
+ padding: `${element?.bgColor ? "16px" : "0px"} 8px`,
269
+ borderRadius: `${element?.color ? "0px" : "12px"} 12px 12px ${element?.color ? "0px" : "12px"}`,
270
+ margin: `${element?.bgColor ? "16px" : "0px"} 0px`,
271
+ width: element?.bgColor ? "calc(100% - 16px)" : "100%",
272
+ borderWidth: element?.color ? "0px 0px 0px 3px" : "0px"
273
+ },
274
+ children: children
275
+ });
276
+ case "alignLeft":
277
+ return /*#__PURE__*/_jsx("div", {
278
+ ...attributes,
279
+ ...element.attr,
280
+ children: children
281
+ });
282
+ case "alignCenter":
283
+ return /*#__PURE__*/_jsx("div", {
284
+ style: {
285
+ display: "flex",
286
+ alignItems: "center",
287
+ flexDirection: "column",
288
+ textAlign: "center"
289
+ },
290
+ ...attributes,
291
+ ...element.attr,
292
+ children: children
293
+ });
294
+ case "alignRight":
295
+ return /*#__PURE__*/_jsx("div", {
296
+ style: {
297
+ display: "flex",
298
+ alignItems: "flex-end",
299
+ flexDirection: "column",
300
+ textAlign: "right"
301
+ },
302
+ ...attributes,
303
+ ...element.attr,
304
+ children: children
305
+ });
306
+ case "list-item":
307
+ const firstChildren = element.children[0] || {};
308
+ return /*#__PURE__*/_jsx("li", {
309
+ ...attributes,
310
+ ...element.attr,
311
+ className: `content-editable ${isEmpty ? "empty" : ""}`,
312
+ placeholder: "List",
313
+ style: {
314
+ color: firstChildren?.color
315
+ },
316
+ children: children
317
+ });
318
+ case "orderedList":
319
+ return /*#__PURE__*/_jsx("ol", {
320
+ type: "1",
321
+ ...attributes,
322
+ children: children
323
+ });
324
+ case "unorderedList":
325
+ return /*#__PURE__*/_jsx("ul", {
326
+ ...attributes,
327
+ children: children
328
+ });
329
+ case "check-list-item":
330
+ return /*#__PURE__*/_jsx(CheckList, {
331
+ ...props,
332
+ isEmpty: isEmpty
333
+ });
334
+ case "table":
335
+ return /*#__PURE__*/_jsx(Table, {
336
+ ...props
337
+ });
338
+ case "table-head":
339
+ return /*#__PURE__*/_jsx("thead", {
340
+ children: children
341
+ });
342
+ case "table-body":
343
+ return /*#__PURE__*/_jsx("tbody", {
344
+ children: children
345
+ });
346
+ case "table-row":
347
+ return /*#__PURE__*/_jsx(TableRow, {
348
+ ...props
349
+ });
350
+ case "table-cell":
351
+ return /*#__PURE__*/_jsx(TableCell, {
352
+ ...props
353
+ });
354
+ case "mention":
355
+ return /*#__PURE__*/_jsx(Mentions, {
356
+ ...props
357
+ });
358
+ default:
359
+ return;
360
+ }
361
+ };
@@ -208,7 +208,13 @@ export const hasVerticalScrollbar = (element = {}) => {
208
208
  return element.scrollHeight > element.clientHeight;
209
209
  };
210
210
  const isHomePage = page => {
211
- return page === "home" || page === "iframe.html" || !page;
211
+ return page === "home" || page === "iframe.html" || page === "_currentPage" || !page;
212
+ };
213
+ const getScrollElement = () => {
214
+ const slateWrapper = document.getElementById("slate-wrapper-scroll-container");
215
+ const isSlateWrapperScroll = hasVerticalScrollbar(slateWrapper);
216
+ const scrollFrom = isSlateWrapperScroll ? slateWrapper : window;
217
+ return scrollFrom;
212
218
  };
213
219
  export const handleLinkType = (url, linkType, readOnly, openInNewTab, onClick = () => {}) => {
214
220
  const props = {};
@@ -239,16 +245,33 @@ export const handleLinkType = (url, linkType, readOnly, openInNewTab, onClick =
239
245
  }
240
246
  break;
241
247
  case "page":
242
- props.component = "a";
243
- const [page, section] = url?.split("#") || [];
248
+ const [page = "", section] = url?.split("#") || [];
244
249
  const sec = section ? `#${section}` : "";
245
- const currentUserPage = getCurrentUserPage();
246
- props.href = isHomePage(page) ? `./${currentUserPage}${sec}` : `./${url}`;
247
- if (openInNewTab) {
248
- if (isCurrentPage(page)) {
249
- // temp fix, if user is presented in current page, open in new tab option is restricted, we will scroll to the element in current page
250
- } else {
251
- props.target = "_blank";
250
+ if (page === "_currentPage") {
251
+ props.component = "button";
252
+ props.onClick = () => {
253
+ const scrollFrom = getScrollElement();
254
+ if (sec) {
255
+ const element = document.getElementById(section);
256
+ if (element) {
257
+ const topPosition = element.getBoundingClientRect().top + scrollFrom.scrollTop;
258
+ scrollFrom.scrollTo({
259
+ top: topPosition,
260
+ behavior: "smooth"
261
+ });
262
+ }
263
+ }
264
+ };
265
+ } else {
266
+ props.component = "a";
267
+ const currentUserPage = getCurrentUserPage();
268
+ props.href = isCurrentPage(page) ? `./${currentUserPage}${sec}` : `./${url}`;
269
+ if (openInNewTab) {
270
+ if (isCurrentPage(page)) {
271
+ // temp fix, if user is presented in current page, open in new tab option is restricted, we will scroll to the element in current page
272
+ } else {
273
+ props.target = "_blank";
274
+ }
252
275
  }
253
276
  }
254
277
  break;
@@ -1,22 +1,34 @@
1
1
  import { renderToString } from "react-dom/server";
2
- import { getBlock } from "./SlateUtilityFunctions";
2
+ import { getBlock } from "./chatEditor/SlateUtilityFunctions";
3
3
  const serializeToHTML = nodes => {
4
4
  try {
5
- const htmlString = nodes.map(n => {
6
- if (n) {
5
+ const htmlString = nodes.map(node => {
6
+ // Render function for each node
7
+ const renderNode = node => {
7
8
  const props = {
8
- element: n,
9
- children: n?.children
9
+ element: node,
10
+ children: node.children?.map(child => {
11
+ // Render each child node
12
+ if (child.text !== undefined) {
13
+ // For text nodes, return the text
14
+ return child.text;
15
+ }
16
+ // For other nodes, render them recursively
17
+ return renderNode(child);
18
+ }) || []
10
19
  };
11
- const reactString = renderToString(getBlock(props));
12
- return reactString;
13
- } else {
14
- return "";
15
- }
16
- });
17
- console.log(htmlString);
20
+ return getBlock(props);
21
+ };
22
+
23
+ // Render root node to HTML string
24
+ const reactElement = renderNode(node);
25
+ return renderToString(reactElement);
26
+ }).join(''); // Combine all HTML strings
27
+
28
+ return htmlString;
18
29
  } catch (err) {
19
- console.log(err);
30
+ console.error('Error serializing to HTML:', err);
31
+ return '';
20
32
  }
21
33
  };
22
34
  export default serializeToHTML;
package/dist/index.js CHANGED
@@ -2,7 +2,11 @@ import Collaborative from "./Editor/CollaborativeEditor";
2
2
  import CommonEditor from "./Editor/CommonEditor";
3
3
  import Mini from "./Editor/MiniEditor";
4
4
  import EditorInFrame from "./Editor/IframeEditor";
5
+ import Chat from "./Editor/ChatEditor";
6
+ import Emoji from "./Editor/Elements/Emoji/EmojiPicker";
5
7
  export const Editor = CommonEditor;
6
8
  export const MiniEditor = Mini;
7
9
  export const CollaborativeEditor = Collaborative;
8
- export const IframeEditor = EditorInFrame;
10
+ export const IframeEditor = EditorInFrame;
11
+ export const ChatEditor = Chat;
12
+ export const EmojiPicker = Emoji;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flozy/editor",
3
- "version": "3.7.0",
3
+ "version": "3.7.2",
4
4
  "description": "An Editor for flozy app brain",
5
5
  "files": [
6
6
  "dist"
@@ -58,11 +58,11 @@
58
58
  "prepare": "husky install .husky",
59
59
  "lint": "./node_modules/.bin/eslint --ignore-path .gitignore .",
60
60
  "start": "craco start",
61
- "build": "craco build",
61
+ "build": "NODE_OPTIONS='--max_old_space_size=4096' craco build",
62
62
  "test": "craco test --passWithNoTests",
63
63
  "eject": "react-scripts eject",
64
- "storybook": "storybook dev -p 6006",
65
- "build-storybook": "storybook build",
64
+ "storybook": "NODE_OPTIONS='--max_old_space_size=4096' storybook dev -p 6006",
65
+ "build-storybook": "NODE_OPTIONS='--max_old_space_size=4096' storybook build",
66
66
  "publish:npm": "rm -rf dist && mkdir dist && babel src/components -d dist --copy-files",
67
67
  "publish:local": "rm -rf /Users/agenciflow08/Documents/flozy/client/node_modules/@flozy/editor/dist && babel src/components -d /Users/agenciflow08/Documents/flozy/client/node_modules/@flozy/editor/dist --copy-files"
68
68
  },