@flozy/editor 1.1.6 → 1.1.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,7 +16,8 @@ const CollaborativeEditor = props => {
16
16
  onSave,
17
17
  user,
18
18
  socketURL,
19
- apiHOST
19
+ apiHOST,
20
+ ...rest
20
21
  } = props;
21
22
  const convertedContent = draftToSlate({
22
23
  data: content
@@ -105,7 +106,6 @@ const CollaborativeEditor = props => {
105
106
  provider.destroy();
106
107
  setConnected(false);
107
108
  setMessage("Seems your connection is lost... Reload the page to edit the document...");
108
- console.log("closed", provider);
109
109
  });
110
110
  if (authenticated.status === null || !connected === null || !editor) {
111
111
  return /*#__PURE__*/_jsx("h1", {
@@ -122,7 +122,8 @@ const CollaborativeEditor = props => {
122
122
  otherProps: {
123
123
  token: user?.token,
124
124
  API_HOST: apiHOST
125
- }
125
+ },
126
+ ...rest
126
127
  });
127
128
  };
128
129
  export default CollaborativeEditor;
@@ -1,8 +1,8 @@
1
1
  import React, { useCallback, useEffect, useMemo, useState } from "react";
2
+ import { createEditor } from "slate";
2
3
  import { Slate, Editable } from "slate-react";
3
4
  import Toolbar from "./Toolbar/Toolbar";
4
5
  import { getMarked, getBlock } from "./utils/SlateUtilityFunctions";
5
- import "./Editor.css";
6
6
  import CodeToText from "./Elements/CodeToText/CodeToText";
7
7
  import { draftToSlate } from "./utils/draftToSlate";
8
8
  import useMentions from "./hooks/useMentions";
@@ -10,7 +10,10 @@ import MentionsPopup from "./common/MentionsPopup";
10
10
  import { RemoteCursorOverlay } from "./RemoteCursorOverlay/Overlay";
11
11
  import { mentionsEvent, commands } from "./utils/events";
12
12
  import withCommon from "./hooks/withCommon";
13
- import { createEditor } from "slate";
13
+ import DialogWrapper from "./DialogWrapper";
14
+ import useTimeout from "./hooks/useTimeout";
15
+ import "./Editor.css";
16
+ import { serialize } from "./utils/serializer";
14
17
  import { jsx as _jsx } from "react/jsx-runtime";
15
18
  import { jsxs as _jsxs } from "react/jsx-runtime";
16
19
  const Element = props => {
@@ -34,12 +37,17 @@ const CommonEditor = props => {
34
37
  onSave,
35
38
  editor: collaborativeEditor,
36
39
  readOnly,
37
- otherProps
40
+ otherProps,
41
+ timeoutInMS = 1000
38
42
  } = props;
39
43
  const convertedContent = draftToSlate({
40
44
  data: content
41
45
  });
42
46
  const [value, setValue] = useState(convertedContent);
47
+ const [lastUpdated, setLastUpdated] = useState(value);
48
+ const [count] = useTimeout({
49
+ timeoutInMS: timeoutInMS
50
+ });
43
51
  const editor = useMemo(() => {
44
52
  if (collaborativeEditor) return collaborativeEditor;
45
53
  return withCommon(createEditor());
@@ -63,6 +71,11 @@ const CommonEditor = props => {
63
71
  data: content
64
72
  }));
65
73
  }, [id, content]);
74
+ useEffect(() => {
75
+ if (count > 0) {
76
+ updateChanges(value);
77
+ }
78
+ }, [count]);
66
79
  const [htmlAction, setHtmlAction] = useState({
67
80
  showInput: false,
68
81
  html: "",
@@ -82,9 +95,18 @@ const CommonEditor = props => {
82
95
  const handleEditorChange = newValue => {
83
96
  setValue(newValue);
84
97
  const isAstChange = editor.operations.some(op => "set_selection" !== op.type);
85
- if (isAstChange && onSave) {
98
+ if (isAstChange && onSave && timeoutInMS === 0) {
86
99
  // send the value to onSave api
87
- onSave(JSON.stringify(value));
100
+ updateChanges(newValue);
101
+ }
102
+ };
103
+ const updateChanges = newValue => {
104
+ const stringify = JSON.stringify(newValue);
105
+ if (stringify !== lastUpdated) {
106
+ onSave(stringify, {
107
+ text: serialize(newValue)
108
+ });
109
+ setLastUpdated(stringify);
88
110
  }
89
111
  };
90
112
  const customProps = {
@@ -129,52 +151,55 @@ const CommonEditor = props => {
129
151
  }, [chars, editor, target, mentions, setMentions]);
130
152
  const isReadOnly = readOnly === "readonly";
131
153
  const Overlay = collaborativeEditor && !isReadOnly ? RemoteCursorOverlay : React.Fragment;
132
- return /*#__PURE__*/_jsx("div", {
133
- style: {
134
- display: "flex",
135
- flexDirection: "column",
136
- padding: "0 8px"
137
- },
138
- children: /*#__PURE__*/_jsxs(Slate, {
139
- editor: editor,
140
- initialValue: value,
141
- onChange: handleEditorChange,
142
- children: [/*#__PURE__*/_jsxs(Overlay, {
143
- children: [!isReadOnly ? /*#__PURE__*/_jsx(Toolbar, {
144
- handleCodeToText: handleCodeToText,
145
- customProps: customProps
146
- }) : null, /*#__PURE__*/_jsxs("div", {
147
- className: "editor-wrapper",
148
- style: {
149
- border: "1px solid #f3f3f3",
150
- background: pageProps?.pageColor || "#FFF",
151
- color: pageProps?.color || "#000",
152
- paddingLeft: `${bannerSpacing?.left}px`,
153
- paddingRight: `${bannerSpacing?.right}px`,
154
- paddingTop: `${bannerSpacing?.top}px`,
155
- paddingBottom: `${bannerSpacing?.bottom}px`
156
- },
157
- children: [/*#__PURE__*/_jsx(Editable, {
158
- readOnly: isReadOnly,
159
- placeholder: "Write something",
160
- renderElement: renderElement,
161
- renderLeaf: renderLeaf,
162
- onKeyDown: onKeyDown
163
- }), /*#__PURE__*/_jsx(MentionsPopup, {
164
- mentions: mentions,
165
- setMentions: setMentions,
166
- editor: editor,
167
- target: target,
168
- index: index,
169
- chars: chars
154
+ return /*#__PURE__*/_jsx(DialogWrapper, {
155
+ ...props,
156
+ children: /*#__PURE__*/_jsx("div", {
157
+ style: {
158
+ display: "flex",
159
+ flexDirection: "column",
160
+ padding: "0 8px"
161
+ },
162
+ children: /*#__PURE__*/_jsxs(Slate, {
163
+ editor: editor,
164
+ initialValue: value,
165
+ onChange: handleEditorChange,
166
+ children: [/*#__PURE__*/_jsxs(Overlay, {
167
+ children: [!isReadOnly ? /*#__PURE__*/_jsx(Toolbar, {
168
+ handleCodeToText: handleCodeToText,
169
+ customProps: customProps
170
+ }) : null, /*#__PURE__*/_jsxs("div", {
171
+ className: "editor-wrapper",
172
+ style: {
173
+ border: "1px solid #f3f3f3",
174
+ background: pageProps?.pageColor || "#FFF",
175
+ color: pageProps?.color || "#000",
176
+ paddingLeft: `${bannerSpacing?.left}px`,
177
+ paddingRight: `${bannerSpacing?.right}px`,
178
+ paddingTop: `${bannerSpacing?.top}px`,
179
+ paddingBottom: `${bannerSpacing?.bottom}px`
180
+ },
181
+ children: [/*#__PURE__*/_jsx(Editable, {
182
+ readOnly: isReadOnly,
183
+ placeholder: "Write something",
184
+ renderElement: renderElement,
185
+ renderLeaf: renderLeaf,
186
+ onKeyDown: onKeyDown
187
+ }), /*#__PURE__*/_jsx(MentionsPopup, {
188
+ mentions: mentions,
189
+ setMentions: setMentions,
190
+ editor: editor,
191
+ target: target,
192
+ index: index,
193
+ chars: chars
194
+ })]
170
195
  })]
196
+ }), htmlAction.showInput && /*#__PURE__*/_jsx(CodeToText, {
197
+ ...htmlAction,
198
+ handleCodeToText: handleCodeToText
171
199
  })]
172
- }), htmlAction.showInput && /*#__PURE__*/_jsx(CodeToText, {
173
- ...htmlAction,
174
- handleCodeToText: handleCodeToText
175
- })]
176
- }, id)
200
+ }, id)
201
+ })
177
202
  });
178
203
  };
179
- const CHARACTERS = ["Aayla Secura", "Adi Gallia", "Admiral Dodd Rancit", "Admiral Firmus Piett", "Admiral Gial Ackbar", "Admiral Ozzel", "Admiral Raddus", "Admiral Terrinald Screed", "Admiral Trench", "Admiral U.O. Statura", "Agen Kolar", "Agent Kallus", "Aiolin and Morit Astarte", "Aks Moe", "Almec", "Alton Kastle", "Amee", "AP-5", "Armitage Hux", "Artoo", "Arvel Crynyd", "Asajj Ventress", "Aurra Sing", "AZI-3", "Bala-Tik", "Barada", "Bargwill Tomder", "Baron Papanoida", "Barriss Offee", "Baze Malbus", "Bazine Netal", "BB-8", "BB-9E", "Ben Quadinaros", "Berch Teller", "Beru Lars", "Bib Fortuna", "Biggs Darklighter", "Black Krrsantan", "Bo-Katan Kryze", "Boba Fett", "Bobbajo", "Bodhi Rook", "Borvo the Hutt", "Boss Nass", "Bossk", "Breha Antilles-Organa", "Bren Derlin", "Brendol Hux", "BT-1", "C-3PO", "C1-10P", "Cad Bane", "Caluan Ematt", "Captain Gregor", "Captain Phasma", "Captain Quarsh Panaka", "Captain Rex", "Carlist Rieekan", "Casca Panzoro", "Cassian Andor", "Cassio Tagge", "Cham Syndulla", "Che Amanwe Papanoida", "Chewbacca", "Chi Eekway Papanoida", "Chief Chirpa", "Chirrut Îmwe", "Ciena Ree", "Cin Drallig", "Clegg Holdfast", "Cliegg Lars", "Coleman Kcaj", "Coleman Trebor", "Colonel Kaplan", "Commander Bly", "Commander Cody (CC-2224)", "Commander Fil (CC-3714)", "Commander Fox", "Commander Gree", "Commander Jet", "Commander Wolffe", "Conan Antonio Motti", "Conder Kyl", "Constable Zuvio", "Cordé", "Cpatain Typho", "Crix Madine", "Cut Lawquane", "Dak Ralter", "Dapp", "Darth Bane", "Darth Maul", "Darth Tyranus", "Daultay Dofine", "Del Meeko", "Delian Mors", "Dengar", "Depa Billaba", "Derek Klivian", "Dexter Jettster", "Dineé Ellberger", "DJ", "Doctor Aphra", "Doctor Evazan", "Dogma", "Dormé", "Dr. Cylo", "Droidbait", "Droopy McCool", "Dryden Vos", "Dud Bolt", "Ebe E. Endocott", "Echuu Shen-Jon", "Eeth Koth", "Eighth Brother", "Eirtaé", "Eli Vanto", "Ellé", "Ello Asty", "Embo", "Eneb Ray", "Enfys Nest", "EV-9D9", "Evaan Verlaine", "Even Piell", "Ezra Bridger", "Faro Argyus", "Feral", "Fifth Brother", "Finis Valorum", "Finn", "Fives", "FN-1824", "FN-2003", "Fodesinbeed Annodue", "Fulcrum", "FX-7", "GA-97", "Galen Erso", "Gallius Rax", 'Garazeb "Zeb" Orrelios', "Gardulla the Hutt", "Garrick Versio", "Garven Dreis", "Gavyn Sykes", "Gideon Hask", "Gizor Dellso", "Gonk droid", "Grand Inquisitor", "Greeata Jendowanian", "Greedo", "Greer Sonnel", "Grievous", "Grummgar", "Gungi", "Hammerhead", "Han Solo", "Harter Kalonia", "Has Obbit", "Hera Syndulla", "Hevy", "Hondo Ohnaka", "Huyang", "Iden Versio", "IG-88", "Ima-Gun Di", "Inquisitors", "Inspector Thanoth", "Jabba", "Jacen Syndulla", "Jan Dodonna", "Jango Fett", "Janus Greejatus", "Jar Jar Binks", "Jas Emari", "Jaxxon", "Jek Tono Porkins", "Jeremoch Colton", "Jira", "Jobal Naberrie", "Jocasta Nu", "Joclad Danva", "Joh Yowza", "Jom Barell", "Joph Seastriker", "Jova Tarkin", "Jubnuk", "Jyn Erso", "K-2SO", "Kanan Jarrus", "Karbin", "Karina the Great", "Kes Dameron", "Ketsu Onyo", "Ki-Adi-Mundi", "King Katuunko", "Kit Fisto", "Kitster Banai", "Klaatu", "Klik-Klak", "Korr Sella", "Kylo Ren", "L3-37", "Lama Su", "Lando Calrissian", "Lanever Villecham", "Leia Organa", "Letta Turmond", "Lieutenant Kaydel Ko Connix", "Lieutenant Thire", "Lobot", "Logray", "Lok Durd", "Longo Two-Guns", "Lor San Tekka", "Lorth Needa", "Lott Dod", "Luke Skywalker", "Lumat", "Luminara Unduli", "Lux Bonteri", "Lyn Me", "Lyra Erso", "Mace Windu", "Malakili", "Mama the Hutt", "Mars Guo", "Mas Amedda", "Mawhonic", "Max Rebo", "Maximilian Veers", "Maz Kanata", "ME-8D9", "Meena Tills", "Mercurial Swift", "Mina Bonteri", "Miraj Scintel", "Mister Bones", "Mod Terrik", "Moden Canady", "Mon Mothma", "Moradmin Bast", "Moralo Eval", "Morley", "Mother Talzin", "Nahdar Vebb", "Nahdonnis Praji", "Nien Nunb", "Niima the Hutt", "Nines", "Norra Wexley", "Nute Gunray", "Nuvo Vindi", "Obi-Wan Kenobi", "Odd Ball", "Ody Mandrell", "Omi", "Onaconda Farr", "Oola", "OOM-9", "Oppo Rancisis", "Orn Free Taa", "Oro Dassyne", "Orrimarko", "Osi Sobeck", "Owen Lars", "Pablo-Jill", "Padmé Amidala", "Pagetti Rook", "Paige Tico", "Paploo", "Petty Officer Thanisson", "Pharl McQuarrie", "Plo Koon", "Po Nudo", "Poe Dameron", "Poggle the Lesser", "Pong Krell", "Pooja Naberrie", "PZ-4CO", "Quarrie", "Quay Tolsite", "Queen Apailana", "Queen Jamillia", "Queen Neeyutnee", "Qui-Gon Jinn", "Quiggold", "Quinlan Vos", "R2-D2", "R2-KT", "R3-S6", "R4-P17", "R5-D4", "RA-7", "Rabé", "Rako Hardeen", "Ransolm Casterfo", "Rappertunie", "Ratts Tyerell", "Raymus Antilles", "Ree-Yees", "Reeve Panzoro", "Rey", "Ric Olié", "Riff Tamson", "Riley", "Rinnriyin Di", "Rio Durant", "Rogue Squadron", "Romba", "Roos Tarpals", "Rose Tico", "Rotta the Hutt", "Rukh", "Rune Haako", "Rush Clovis", "Ruwee Naberrie", "Ryoo Naberrie", "Sabé", "Sabine Wren", "Saché", "Saelt-Marae", "Saesee Tiin", "Salacious B. Crumb", "San Hill", "Sana Starros", "Sarco Plank", "Sarkli", "Satine Kryze", "Savage Opress", "Sebulba", "Senator Organa", "Sergeant Kreel", "Seventh Sister", "Shaak Ti", "Shara Bey", "Shmi Skywalker", "Shu Mai", "Sidon Ithano", "Sifo-Dyas", "Sim Aloo", "Siniir Rath Velus", "Sio Bibble", "Sixth Brother", "Slowen Lo", "Sly Moore", "Snaggletooth", "Snap Wexley", "Snoke", "Sola Naberrie", "Sora Bulq", "Strono Tuggs", "Sy Snootles", "Tallissan Lintra", "Tarfful", "Tasu Leech", "Taun We", "TC-14", "Tee Watt Kaa", "Teebo", "Teedo", "Teemto Pagalies", "Temiri Blagg", "Tessek", "Tey How", "Thane Kyrell", "The Bendu", "The Smuggler", "Thrawn", "Tiaan Jerjerrod", "Tion Medon", "Tobias Beckett", "Tulon Voidgazer", "Tup", "U9-C4", "Unkar Plutt", "Val Beckett", "Vanden Willard", "Vice Admiral Amilyn Holdo", "Vober Dand", "WAC-47", "Wag Too", "Wald", "Walrus Man", "Warok", "Wat Tambor", "Watto", "Wedge Antilles", "Wes Janson", "Wicket W. Warrick", "Wilhuff Tarkin", "Wollivan", "Wuher", "Wullf Yularen", "Xamuel Lennox", "Yaddle", "Yarael Poof", "Yoda", "Zam Wesell", "Zev Senesca", "Ziro the Hutt", "Zuckuss"];
204
+ const CHARACTERS = ["Aayla Secura", "Adi Gallia"];
180
205
  export default CommonEditor;
@@ -0,0 +1,43 @@
1
+ import React from "react";
2
+ import { Dialog, DialogTitle, DialogContent, DialogActions, IconButton, Grid } from "@mui/material";
3
+ import CloseIcon from "@mui/icons-material/Close";
4
+ import { jsx as _jsx } from "react/jsx-runtime";
5
+ import { jsxs as _jsxs } from "react/jsx-runtime";
6
+ const DialogWrapper = props => {
7
+ const {
8
+ fullScreen,
9
+ onClose,
10
+ children,
11
+ footer
12
+ } = props;
13
+ return fullScreen ? /*#__PURE__*/_jsxs(Dialog, {
14
+ open: fullScreen,
15
+ fullScreen: fullScreen,
16
+ onClose: onClose,
17
+ children: [/*#__PURE__*/_jsx(DialogTitle, {
18
+ children: /*#__PURE__*/_jsx(Grid, {
19
+ children: /*#__PURE__*/_jsx(Grid, {
20
+ style: {
21
+ display: 'flex',
22
+ justifyContent: 'end'
23
+ },
24
+ children: /*#__PURE__*/_jsx(IconButton, {
25
+ onClick: onClose,
26
+ children: /*#__PURE__*/_jsx(CloseIcon, {})
27
+ })
28
+ })
29
+ })
30
+ }), /*#__PURE__*/_jsx(DialogContent, {
31
+ children: children
32
+ }), /*#__PURE__*/_jsx(DialogActions, {
33
+ children: footer
34
+ })]
35
+ }) : children;
36
+ };
37
+ DialogWrapper.defaultProps = {
38
+ fullScreen: false,
39
+ onClose: () => {},
40
+ children: '',
41
+ footer: ''
42
+ };
43
+ export default DialogWrapper;
@@ -0,0 +1,221 @@
1
+ import React, { useState } from "react";
2
+ import { useSlateStatic, ReactEditor } from "slate-react";
3
+ import { Transforms } from "slate";
4
+ import AppBar from "@mui/material/AppBar";
5
+ import Box from "@mui/material/Box";
6
+ import CssBaseline from "@mui/material/CssBaseline";
7
+ import Divider from "@mui/material/Divider";
8
+ import Drawer from "@mui/material/Drawer";
9
+ import IconButton from "@mui/material/IconButton";
10
+ import List from "@mui/material/List";
11
+ import ListItem from "@mui/material/ListItem";
12
+ import ListItemButton from "@mui/material/ListItemButton";
13
+ import ListItemText from "@mui/material/ListItemText";
14
+ import MenuIcon from "@mui/icons-material/Menu";
15
+ import Toolbar from "@mui/material/Toolbar";
16
+ import Typography from "@mui/material/Typography";
17
+ import Button from "@mui/material/Button";
18
+ import SettingsIcon from "@mui/icons-material/Settings";
19
+ import DeleteIcon from "@mui/icons-material/Delete";
20
+ import AppHeaderPopup from "./AppHeaderPopup";
21
+ import { jsx as _jsx } from "react/jsx-runtime";
22
+ import { jsxs as _jsxs } from "react/jsx-runtime";
23
+ const drawerWidth = 240;
24
+ function AppHeader(props) {
25
+ const [openSetttings, setOpenSettings] = useState(false);
26
+ const {
27
+ attributes,
28
+ element,
29
+ customProps
30
+ } = props;
31
+ const {
32
+ appTitle,
33
+ appLogo,
34
+ menus,
35
+ bgColor,
36
+ menuStyle
37
+ } = element;
38
+ const {
39
+ window
40
+ } = props;
41
+ const [mobileOpen, setMobileOpen] = React.useState(false);
42
+ const editor = useSlateStatic();
43
+ const path = ReactEditor.findPath(editor, element);
44
+ const isDrawer = menuStyle === "drawer";
45
+ const handleDrawerToggle = () => {
46
+ setMobileOpen(prevState => !prevState);
47
+ };
48
+ const onSettings = () => {
49
+ setOpenSettings(true);
50
+ };
51
+ const ToolBar = () => {
52
+ return customProps?.readOnly !== true ? /*#__PURE__*/_jsxs("div", {
53
+ className: "element-toolbar",
54
+ contentEditable: false,
55
+ style: {
56
+ top: "-38px"
57
+ },
58
+ children: [/*#__PURE__*/_jsx(IconButton, {
59
+ size: "small",
60
+ onClick: onSettings,
61
+ children: /*#__PURE__*/_jsx(SettingsIcon, {})
62
+ }), /*#__PURE__*/_jsx(IconButton, {
63
+ size: "small",
64
+ onClick: onDelete,
65
+ children: /*#__PURE__*/_jsx(DeleteIcon, {})
66
+ })]
67
+ }) : null;
68
+ };
69
+ const onSave = data => {
70
+ const updateData = {
71
+ ...data
72
+ };
73
+ delete updateData.children;
74
+ Transforms.setNodes(editor, updateData, {
75
+ at: path
76
+ });
77
+ onClose();
78
+ };
79
+ const onDelete = () => {
80
+ Transforms.removeNodes(editor, {
81
+ at: path
82
+ });
83
+ };
84
+ const onClose = () => {
85
+ setOpenSettings(false);
86
+ };
87
+ const drawer = /*#__PURE__*/_jsxs(Box, {
88
+ onClick: handleDrawerToggle,
89
+ sx: {
90
+ textAlign: "center"
91
+ },
92
+ children: [/*#__PURE__*/_jsx(Typography, {
93
+ variant: "h6",
94
+ sx: {
95
+ my: 2
96
+ },
97
+ children: appLogo && appLogo !== "none" ? /*#__PURE__*/_jsx("img", {
98
+ alt: `${appTitle} Logo`,
99
+ style: {
100
+ height: "40px",
101
+ width: "auto"
102
+ },
103
+ src: appLogo
104
+ }) : appTitle
105
+ }), /*#__PURE__*/_jsx(Divider, {}), /*#__PURE__*/_jsx(List, {
106
+ children: menus.map(item => /*#__PURE__*/_jsx(ListItem, {
107
+ disablePadding: true,
108
+ children: /*#__PURE__*/_jsx(ListItemButton, {
109
+ sx: {
110
+ textAlign: "center"
111
+ },
112
+ children: /*#__PURE__*/_jsx(ListItemText, {
113
+ primary: item.text
114
+ })
115
+ })
116
+ }, item.text))
117
+ })]
118
+ });
119
+ const container = window !== undefined ? () => window().document.body : undefined;
120
+ return /*#__PURE__*/_jsxs(Box, {
121
+ sx: {
122
+ display: "flex",
123
+ position: "relative"
124
+ },
125
+ ...attributes,
126
+ contentEditable: false,
127
+ children: [/*#__PURE__*/_jsx(CssBaseline, {}), /*#__PURE__*/_jsx(AppBar, {
128
+ component: "nav",
129
+ style: {
130
+ position: "relative",
131
+ background: bgColor
132
+ },
133
+ children: /*#__PURE__*/_jsxs(Toolbar, {
134
+ children: [/*#__PURE__*/_jsx(IconButton, {
135
+ color: "inherit",
136
+ "aria-label": "open drawer",
137
+ edge: "start",
138
+ onClick: handleDrawerToggle,
139
+ sx: {
140
+ mr: 2,
141
+ display: {
142
+ sm: "none"
143
+ }
144
+ },
145
+ children: /*#__PURE__*/_jsx(MenuIcon, {})
146
+ }), /*#__PURE__*/_jsxs(Typography, {
147
+ variant: "h6",
148
+ component: "div",
149
+ style: {
150
+ display: "inline-flex",
151
+ alignItems: "center"
152
+ },
153
+ sx: {
154
+ flexGrow: 1,
155
+ display: {
156
+ xs: "none",
157
+ sm: "block"
158
+ }
159
+ },
160
+ children: [appLogo && appLogo !== "none" ? /*#__PURE__*/_jsx("img", {
161
+ alt: `${appTitle} Logo`,
162
+ style: {
163
+ height: "40px",
164
+ width: "auto"
165
+ },
166
+ src: appLogo
167
+ }) : null, "\xA0", appTitle]
168
+ }), /*#__PURE__*/_jsxs(Box, {
169
+ sx: {
170
+ display: {
171
+ xs: "none",
172
+ sm: "block"
173
+ }
174
+ },
175
+ children: [isDrawer ? /*#__PURE__*/_jsx(IconButton, {
176
+ color: "inherit",
177
+ "aria-label": "open drawer",
178
+ edge: "start",
179
+ onClick: handleDrawerToggle,
180
+ children: /*#__PURE__*/_jsx(MenuIcon, {})
181
+ }) : null, !isDrawer ? menus.map(item => /*#__PURE__*/_jsx(Button, {
182
+ component: "a",
183
+ href: item.href,
184
+ sx: {
185
+ color: "#fff"
186
+ },
187
+ children: item.text
188
+ }, item)) : null]
189
+ })]
190
+ })
191
+ }), /*#__PURE__*/_jsx("nav", {
192
+ children: /*#__PURE__*/_jsx(Drawer, {
193
+ container: container,
194
+ variant: "temporary",
195
+ open: mobileOpen,
196
+ onClose: handleDrawerToggle,
197
+ ModalProps: {
198
+ keepMounted: true // Better open performance on mobile.
199
+ },
200
+
201
+ sx: {
202
+ display: {
203
+ xs: "block",
204
+ sm: isDrawer ? "block" : "none"
205
+ },
206
+ "& .MuiDrawer-paper": {
207
+ boxSizing: "border-box",
208
+ width: drawerWidth
209
+ }
210
+ },
211
+ children: drawer
212
+ })
213
+ }), /*#__PURE__*/_jsx(ToolBar, {}), openSetttings ? /*#__PURE__*/_jsx(AppHeaderPopup, {
214
+ element: element,
215
+ onSave: onSave,
216
+ onClose: onClose,
217
+ customProps: customProps
218
+ }) : null]
219
+ });
220
+ }
221
+ export default AppHeader;
@@ -0,0 +1,19 @@
1
+ import React from "react";
2
+ import { IconButton } from "@mui/material";
3
+ import ViewDayIcon from "@mui/icons-material/ViewDay";
4
+ import { insertAppHeader } from "../../utils/insertAppHeader";
5
+ import { jsx as _jsx } from "react/jsx-runtime";
6
+ const AppHeaderButton = props => {
7
+ const {
8
+ editor
9
+ } = props;
10
+ const handleClick = () => {
11
+ insertAppHeader(editor, {});
12
+ };
13
+ return /*#__PURE__*/_jsx(IconButton, {
14
+ title: "App Header",
15
+ onClick: handleClick,
16
+ children: /*#__PURE__*/_jsx(ViewDayIcon, {})
17
+ });
18
+ };
19
+ export default AppHeaderButton;
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ import StyleBuilder from "../../common/StyleBuilder";
3
+ import appHeaderStyle from "../../common/StyleBuilder/appHeaderStyle";
4
+ import { jsx as _jsx } from "react/jsx-runtime";
5
+ const AppHeaderPopup = props => {
6
+ const {
7
+ element,
8
+ onSave,
9
+ onClose
10
+ } = props;
11
+ return /*#__PURE__*/_jsx(StyleBuilder, {
12
+ title: "App Header",
13
+ type: "gridItemStyle",
14
+ element: element,
15
+ onSave: onSave,
16
+ onClose: onClose,
17
+ renderTabs: appHeaderStyle
18
+ });
19
+ };
20
+ export default AppHeaderPopup;
@@ -26,7 +26,6 @@ const Carousel = props => {
26
26
  const selected = useSelected();
27
27
  const [edit, setEdit] = useState(false);
28
28
  const [reload, setReload] = useState(new Date().getTime());
29
- const path = ReactEditor.findPath(editor, element);
30
29
  const settings = {
31
30
  dots: true,
32
31
  infinite: true,
@@ -58,6 +57,7 @@ const Carousel = props => {
58
57
  }
59
58
  };
60
59
  const onDelete = () => {
60
+ const path = ReactEditor.findPath(editor, element);
61
61
  Transforms.removeNodes(editor, {
62
62
  at: [...path]
63
63
  });
@@ -32,9 +32,7 @@ const HtmlCode = props => {
32
32
  } else if (e.keyCode === 8) {
33
33
  Transforms.removeNodes(editor);
34
34
  }
35
- // console.log(e);
36
35
  };
37
-
38
36
  useEffect(() => {
39
37
  document.addEventListener("keyup", handleKeyUp);
40
38
  return () => {
@@ -32,7 +32,6 @@ const EquationButton = ({
32
32
  if (!math) return;
33
33
  selection && Transforms.select(editor, selection);
34
34
  insertEquation(editor, math, displayInline);
35
- console.log("btn click");
36
35
  setShowInput(false);
37
36
  };
38
37
  return /*#__PURE__*/_jsxs("div", {
@@ -5,22 +5,23 @@ import ArticleIcon from "@mui/icons-material/Article";
5
5
  import { useSlateStatic, ReactEditor } from "slate-react";
6
6
  import PageSettingsPopup from "./PageSettingsPopup";
7
7
  import { jsx as _jsx } from "react/jsx-runtime";
8
+ import { Fragment as _Fragment } from "react/jsx-runtime";
8
9
  import { jsxs as _jsxs } from "react/jsx-runtime";
9
10
  const PageSettingsButton = props => {
10
11
  const {
11
12
  customProps
12
13
  } = props;
13
14
  const [openSetttings, setOpenSettings] = useState(false);
14
- const [pageProps, setPageProps] = useState({});
15
15
  const editor = useSlateStatic();
16
16
  const onSettings = () => {
17
17
  const {
18
- element
18
+ element,
19
+ path
19
20
  } = getPageSettingsPath();
20
- if (element) {
21
- setPageProps(element?.pageProps || {});
22
- setOpenSettings(true);
23
- }
21
+ setOpenSettings({
22
+ element: element?.pageProps || {},
23
+ path
24
+ });
24
25
  };
25
26
  const getPageSettingsPath = () => {
26
27
  try {
@@ -30,11 +31,17 @@ const PageSettingsButton = props => {
30
31
  return !Editor.isEditor(n) && Element.isElement(n) && n.type === "page-settings";
31
32
  }
32
33
  });
33
- const path = ReactEditor.findPath(editor, pageSettingsNode[0]);
34
- return {
35
- path,
36
- element: pageSettingsNode[0]
37
- };
34
+ if (pageSettingsNode && pageSettingsNode[0]) {
35
+ const path = ReactEditor.findPath(editor, pageSettingsNode[0]);
36
+ return {
37
+ path,
38
+ element: pageSettingsNode[0]
39
+ };
40
+ } else {
41
+ return {
42
+ path: null
43
+ };
44
+ }
38
45
  } catch (err) {
39
46
  console.log(err);
40
47
  return {
@@ -43,20 +50,17 @@ const PageSettingsButton = props => {
43
50
  }
44
51
  };
45
52
  const onSave = data => {
46
- const {
47
- path
48
- } = getPageSettingsPath();
49
53
  const updateData = {
50
54
  ...data
51
55
  };
52
56
  delete updateData.children;
53
- if (path) {
57
+ if (openSetttings?.path) {
54
58
  Transforms.setNodes(editor, {
55
59
  pageProps: {
56
60
  ...updateData
57
61
  }
58
62
  }, {
59
- at: path
63
+ at: openSetttings?.path
60
64
  });
61
65
  } else {
62
66
  Transforms.insertNodes(editor, [{
@@ -74,11 +78,13 @@ const PageSettingsButton = props => {
74
78
  const onClose = () => {
75
79
  setOpenSettings(false);
76
80
  };
77
- return /*#__PURE__*/_jsxs(IconButton, {
78
- title: "Page Settings",
79
- onClick: onSettings,
80
- children: [/*#__PURE__*/_jsx(ArticleIcon, {}), openSetttings ? /*#__PURE__*/_jsx(PageSettingsPopup, {
81
- element: pageProps,
81
+ return /*#__PURE__*/_jsxs(_Fragment, {
82
+ children: [/*#__PURE__*/_jsx(IconButton, {
83
+ title: "Page Settings",
84
+ onClick: onSettings,
85
+ children: /*#__PURE__*/_jsx(ArticleIcon, {})
86
+ }), openSetttings !== false ? /*#__PURE__*/_jsx(PageSettingsPopup, {
87
+ element: openSetttings?.element || {},
82
88
  onSave: onSave,
83
89
  onClose: onClose,
84
90
  customProps: customProps
@@ -10,7 +10,6 @@ const UploadSignature = props => {
10
10
  } = props;
11
11
  const [base64, setBase64] = useState(null);
12
12
  const [uploading, setUploading] = useState(false);
13
- console.log(customProps);
14
13
  const onChange = async e => {
15
14
  const file = e.target.files[0];
16
15
  const strImage = await convertBase64(file);
@@ -25,6 +25,7 @@ import PageSettingsButton from "../Elements/PageSettings/PageSettingsButton";
25
25
  import CarouselButton from "../Elements/Carousel/CarouselButton";
26
26
  import ChipTextButton from "../Elements/ChipText/ChipTextButton";
27
27
  import DrawerMenuButton from "../Elements/DrawerMenu/DrawerMenuButton";
28
+ import AppHeaderButton from "../Elements/AppHeader/AppHeaderButton";
28
29
  import { jsx as _jsx } from "react/jsx-runtime";
29
30
  import { jsxs as _jsxs } from "react/jsx-runtime";
30
31
  const Toolbar = props => {
@@ -198,6 +199,11 @@ const Toolbar = props => {
198
199
  editor: editor,
199
200
  customProps: customProps
200
201
  }, element.id);
202
+ case "app-header":
203
+ return /*#__PURE__*/_jsx(AppHeaderButton, {
204
+ editor: editor,
205
+ customProps: customProps
206
+ }, element.id);
201
207
  default:
202
208
  return null;
203
209
  }
@@ -131,5 +131,8 @@ const toolbarGroups = [[{
131
131
  }, {
132
132
  id: 36,
133
133
  type: "drawer"
134
+ }, {
135
+ id: 37,
136
+ type: "app-header"
134
137
  }]];
135
138
  export default toolbarGroups;
@@ -0,0 +1,63 @@
1
+ const appHeaderStyle = [{
2
+ tab: "Logo",
3
+ value: "appLogo",
4
+ fields: [{
5
+ label: "App Logo URL",
6
+ key: "appLogo",
7
+ type: "text"
8
+ }, {
9
+ label: "App Logo",
10
+ key: "appLogo",
11
+ type: "backgroundImage"
12
+ }]
13
+ }, {
14
+ tab: "Title",
15
+ value: "appTitle",
16
+ fields: [{
17
+ label: "App Title",
18
+ key: "appTitle",
19
+ type: "text"
20
+ }]
21
+ }, {
22
+ tab: "Menus",
23
+ value: "menus",
24
+ fields: [{
25
+ label: "Menus",
26
+ key: "menus",
27
+ type: "menusArray"
28
+ }]
29
+ }, {
30
+ tab: "Banner Spacing",
31
+ value: "bannerSpacing",
32
+ fields: [{
33
+ label: "Banner Spacing",
34
+ key: "bannerSpacing",
35
+ type: "bannerSpacing"
36
+ }]
37
+ }, {
38
+ tab: "Border Radius",
39
+ value: "borderRadius",
40
+ fields: [{
41
+ label: "Border Radius",
42
+ key: "borderRadius",
43
+ type: "borderRadius"
44
+ }]
45
+ }, {
46
+ tab: "Colors",
47
+ value: "colors",
48
+ fields: [{
49
+ label: "Text",
50
+ key: "textColor",
51
+ type: "color",
52
+ needPreview: true
53
+ }, {
54
+ label: "Background",
55
+ key: "bgColor",
56
+ type: "color"
57
+ }, {
58
+ label: "Border",
59
+ key: "borderColor",
60
+ type: "color"
61
+ }]
62
+ }];
63
+ export default appHeaderStyle;
@@ -7,6 +7,7 @@ import BackgroundImage from "./backgroundImage";
7
7
  import GridSize from "./gridSize";
8
8
  import ElementSize from "./elementSize";
9
9
  import ImageTexts from "./imageTexts";
10
+ import MenusArray from "./menusArray";
10
11
  const FieldMap = {
11
12
  text: Text,
12
13
  bannerSpacing: BannerSpacing,
@@ -16,6 +17,7 @@ const FieldMap = {
16
17
  backgroundImage: BackgroundImage,
17
18
  gridSize: GridSize,
18
19
  elementSize: ElementSize,
19
- imageTexts: ImageTexts
20
+ imageTexts: ImageTexts,
21
+ menusArray: MenusArray
20
22
  };
21
23
  export default FieldMap;
@@ -0,0 +1,114 @@
1
+ import React from "react";
2
+ import { Button, Grid, Radio, RadioGroup, TextField, FormControl, FormLabel, FormControlLabel } from "@mui/material";
3
+ import { jsx as _jsx } from "react/jsx-runtime";
4
+ import { jsxs as _jsxs } from "react/jsx-runtime";
5
+ const MenusArray = props => {
6
+ const {
7
+ value,
8
+ data,
9
+ elementProps,
10
+ onChange
11
+ } = props;
12
+ const {
13
+ key
14
+ } = data;
15
+ const {
16
+ menuStyle
17
+ } = elementProps || {
18
+ menuStyle: "stacked"
19
+ };
20
+ const handleChange = index => e => {
21
+ const upValue = [...(value || [])];
22
+ upValue[index] = {
23
+ ...(upValue[index] || {}),
24
+ [e.target.name]: e.target.value
25
+ };
26
+ onChange({
27
+ [key]: upValue
28
+ });
29
+ };
30
+ const onAddMenu = () => {
31
+ onChange({
32
+ [key]: [...value, {
33
+ ...value[0]
34
+ }]
35
+ });
36
+ };
37
+ const onDelete = index => () => {
38
+ const upValue = [...(value || [])];
39
+ upValue.splice(index, 1);
40
+ onChange({
41
+ [key]: upValue
42
+ });
43
+ };
44
+ const handleVariant = e => {
45
+ onChange({
46
+ [e.target.name]: e.target.value
47
+ });
48
+ };
49
+ return /*#__PURE__*/_jsxs(Grid, {
50
+ container: true,
51
+ padding: 1,
52
+ spacing: 2,
53
+ children: [/*#__PURE__*/_jsx(Grid, {
54
+ item: true,
55
+ xs: 12,
56
+ children: /*#__PURE__*/_jsxs(FormControl, {
57
+ children: [/*#__PURE__*/_jsx(FormLabel, {
58
+ id: "demo-radio-buttons-group-label",
59
+ children: "Menu Variant"
60
+ }), /*#__PURE__*/_jsxs(RadioGroup, {
61
+ row: true,
62
+ "aria-labelledby": "demo-radio-buttons-group-label",
63
+ defaultValue: menuStyle,
64
+ value: menuStyle,
65
+ name: "menuStyle",
66
+ onChange: handleVariant,
67
+ children: [/*#__PURE__*/_jsx(FormControlLabel, {
68
+ value: "stacked",
69
+ checked: menuStyle === "stacked",
70
+ control: /*#__PURE__*/_jsx(Radio, {}),
71
+ label: "Stacked"
72
+ }), /*#__PURE__*/_jsx(FormControlLabel, {
73
+ value: "drawer",
74
+ checked: menuStyle === "drawer",
75
+ control: /*#__PURE__*/_jsx(Radio, {}),
76
+ label: "Drawer"
77
+ })]
78
+ })]
79
+ })
80
+ }), (value || []).map((m, i) => {
81
+ return /*#__PURE__*/_jsxs(Grid, {
82
+ item: true,
83
+ xs: 12,
84
+ children: [/*#__PURE__*/_jsx(TextField, {
85
+ name: "text",
86
+ type: "text",
87
+ value: m.text,
88
+ onChange: handleChange(i),
89
+ size: "small",
90
+ fullWidth: true
91
+ }), /*#__PURE__*/_jsx(TextField, {
92
+ name: "url",
93
+ type: "text",
94
+ value: m.url,
95
+ onChange: handleChange(i),
96
+ size: "small",
97
+ fullWidth: true
98
+ }), /*#__PURE__*/_jsx(Button, {
99
+ onClick: onDelete(i),
100
+ color: "error",
101
+ children: "Delete"
102
+ })]
103
+ }, `add-m-${i}`);
104
+ }), /*#__PURE__*/_jsx(Grid, {
105
+ item: true,
106
+ xs: 12,
107
+ children: /*#__PURE__*/_jsx(Button, {
108
+ onClick: onAddMenu,
109
+ children: "+ Add"
110
+ })
111
+ })]
112
+ });
113
+ };
114
+ export default MenusArray;
@@ -75,7 +75,6 @@ const StyleBuilder = props => {
75
75
  setTab(newValue);
76
76
  };
77
77
  const onElementPropsChange = data => {
78
- console.log(data);
79
78
  setElementProps({
80
79
  ...elementProps,
81
80
  ...data
@@ -5,6 +5,14 @@ const pageSettingsStyle = [{
5
5
  label: "Text",
6
6
  key: "color",
7
7
  type: "color"
8
+ }, {
9
+ label: "Background URL",
10
+ key: "pageColor",
11
+ type: "text"
12
+ }, {
13
+ label: "Background Image",
14
+ key: "pageColor",
15
+ type: "backgroundImage"
8
16
  }, {
9
17
  label: "Background",
10
18
  key: "pageColor",
@@ -0,0 +1,21 @@
1
+ import { useEffect, useState } from "react";
2
+ let t = null;
3
+ const useTimeout = props => {
4
+ const {
5
+ timeoutInMS
6
+ } = props;
7
+ const [count, setCount] = useState(0);
8
+ const onReset = () => {
9
+ clearTimeout(t);
10
+ t = setTimeout(() => {
11
+ setCount(count + 1);
12
+ }, timeoutInMS);
13
+ };
14
+ useEffect(() => {
15
+ if (timeoutInMS) {
16
+ onReset();
17
+ }
18
+ }, [timeoutInMS, count]);
19
+ return [count];
20
+ };
21
+ export default useTimeout;
@@ -23,6 +23,7 @@ import ImageTextWrapper from "../Elements/ImageText/ImageTextWrapper";
23
23
  import ImageText from "../Elements/ImageText/ImageText";
24
24
  import ChipText from "../Elements/ChipText/ChipText";
25
25
  import DrawerMenu from "../Elements/DrawerMenu/DrawerMenu";
26
+ import AppHeader from "../Elements/AppHeader/AppHeader";
26
27
  import { jsx as _jsx } from "react/jsx-runtime";
27
28
  const alignment = ["alignLeft", "alignRight", "alignCenter"];
28
29
  const list_types = ["orderedList", "unorderedList"];
@@ -353,6 +354,10 @@ export const getBlock = props => {
353
354
  return /*#__PURE__*/_jsx(DrawerMenu, {
354
355
  ...props
355
356
  });
357
+ case "app-header":
358
+ return /*#__PURE__*/_jsx(AppHeader, {
359
+ ...props
360
+ });
356
361
  default:
357
362
  return /*#__PURE__*/_jsx("div", {
358
363
  ...element.attr,
@@ -0,0 +1,55 @@
1
+ import { Editor, Transforms, Path, Range, Element } from "slate";
2
+ export const createAppHeaderNode = ({
3
+ menus
4
+ }) => ({
5
+ type: "app-header",
6
+ appTitle: "Title",
7
+ appLogo: "https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Netflix_2015_logo.svg/1200px-Netflix_2015_logo.svg.png",
8
+ menus: !menus ? [{
9
+ type: "menu",
10
+ url: "https://www.google.com",
11
+ target: "_blank",
12
+ text: "Google"
13
+ }] : menus,
14
+ menuStyle: "drawer",
15
+ children: [{
16
+ text: ""
17
+ }]
18
+ });
19
+ export const insertAppHeader = (editor, props) => {
20
+ const {
21
+ selection
22
+ } = editor;
23
+ const appHeader = createAppHeaderNode(props || {});
24
+ if (!!selection) {
25
+ const [parent, parentPath] = Editor.parent(editor, selection.focus.path);
26
+ if (editor.isVoid(parent)) {
27
+ Transforms.insertNodes(editor, {
28
+ type: "paragraph",
29
+ children: [appHeader]
30
+ }, {
31
+ at: Path.next(parentPath),
32
+ select: true
33
+ });
34
+ } else if (Range.isCollapsed(selection)) {
35
+ Transforms.insertNodes(editor, appHeader, {
36
+ select: true
37
+ });
38
+ } else {
39
+ Transforms.wrapNodes(editor, appHeader, {
40
+ split: true
41
+ });
42
+ }
43
+ } else {
44
+ Transforms.insertNodes(editor, {
45
+ type: "paragraph",
46
+ children: [appHeader]
47
+ });
48
+ }
49
+ };
50
+ export const removeAppHeader = (editor, path) => {
51
+ Transforms.unwrapNodes(editor, {
52
+ at: path,
53
+ match: n => !Editor.isEditor(n) && Element.isElement(n) && n.type === "app-header"
54
+ });
55
+ };
@@ -1,28 +1,16 @@
1
- import { Text } from 'slate';
2
- import { getBlock, getMarked } from './SlateUtilityFunctions.js';
3
- import ReactDOMServer from 'react-dom/server';
4
- const {
5
- renderToStaticMarkup
6
- } = ReactDOMServer;
7
1
  export const serialize = node => {
8
- if (Text.isText(node)) {
9
- let string = getMarked(node, node.text);
10
- string = renderToStaticMarkup(string);
11
- return string;
2
+ try {
3
+ if (!node?.type && node?.text) {
4
+ return node?.text;
5
+ }
6
+ let n = Array.isArray(node) ? node : node?.children;
7
+ n = n && Array.isArray(n) ? n : n ? [n] : [];
8
+ let block = n.map(m => {
9
+ return serialize(m);
10
+ }).join(' ');
11
+ return block;
12
+ } catch (err) {
13
+ console.log(err);
14
+ return null;
12
15
  }
13
- const children = node.children.map(n => serialize(n)).join('');
14
- let block = getBlock({
15
- children,
16
- element: node
17
- });
18
- block = renderToStaticMarkup(block);
19
- return block;
20
- };
21
- export const serializer = editorValue => {
22
- if (editorValue.length > 0) {
23
- return editorValue.map(n => serialize(n)).join('');
24
- }
25
- };
26
- export const deserializer = body => {
27
- console.log(body);
28
16
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flozy/editor",
3
- "version": "1.1.6",
3
+ "version": "1.1.8",
4
4
  "description": "An Editor for flozy app brain",
5
5
  "files": [
6
6
  "dist"