@flozy/editor 5.2.5 → 5.2.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -72,6 +72,12 @@ const Leaf = ({
72
72
  children: children
73
73
  });
74
74
  };
75
+ const updateTopBanner = (content, setTopBanner) => {
76
+ setTopBanner(() => {
77
+ const firstNode = content[0];
78
+ return firstNode?.type === "topbanner" ? firstNode : null;
79
+ });
80
+ };
75
81
  const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
76
82
  const {
77
83
  id,
@@ -151,6 +157,7 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
151
157
  setValue(draftToSlate({
152
158
  data: content
153
159
  }));
160
+ updateTopBanner(content, setTopBanner);
154
161
  if (!isMobile && !ReactEditor.isFocused(editor)) {
155
162
  ReactEditor.focus(editor);
156
163
  }
@@ -301,10 +308,7 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
301
308
  const handleEditorChange = newValue => {
302
309
  if (!readOnly) {
303
310
  if (JSON.stringify(newValue) !== JSON.stringify(debouncedValue?.current)) {
304
- setTopBanner(() => {
305
- const firstNode = newValue[0];
306
- return firstNode?.type === "topbanner" ? firstNode : null;
307
- });
311
+ updateTopBanner(newValue, setTopBanner);
308
312
  debounced(newValue);
309
313
  if (!isInteracted) {
310
314
  setIsInteracted(true);
@@ -20,8 +20,7 @@ const DataView = props => {
20
20
  attributes,
21
21
  children,
22
22
  element,
23
- customProps,
24
- title
23
+ customProps
25
24
  } = props;
26
25
  const {
27
26
  CHARACTERS,
@@ -30,7 +29,8 @@ const DataView = props => {
30
29
  const {
31
30
  properties,
32
31
  layouts,
33
- rows
32
+ rows,
33
+ title
34
34
  } = element;
35
35
  const classes = useDataViewStyles(theme, appTheme);
36
36
  const path = ReactEditor.findPath(editor, element);
@@ -79,27 +79,41 @@ const DataView = props => {
79
79
  console.log(err);
80
80
  }
81
81
  };
82
+ const onTitleChange = value => {
83
+ try {
84
+ Transforms.setNodes(editor, {
85
+ title: value
86
+ }, {
87
+ at: path
88
+ });
89
+ } catch (err) {
90
+ console.log(err);
91
+ }
92
+ };
82
93
  return /*#__PURE__*/_jsx(Box, {
83
94
  ...attributes,
84
95
  className: "fe-dataview",
85
96
  sx: classes.root,
86
97
  contentEditable: false,
98
+ "data-title": title,
87
99
  children: /*#__PURE__*/_jsxs(DataViewProvider, {
88
100
  initialData: {
89
101
  properties,
90
102
  layouts,
91
103
  rows,
92
- users: users,
93
- tableTitle: title
104
+ users: users
94
105
  },
95
106
  path: path,
96
107
  editor: editor,
108
+ title: title,
97
109
  children: [/*#__PURE__*/_jsx(FilterView, {
98
110
  classes: classes,
99
111
  onEnter: onEnter,
100
112
  onDelete: onDelete,
101
113
  onDuplicate: onDuplicate,
102
- readOnly: readOnly
114
+ readOnly: readOnly,
115
+ title: title,
116
+ onTitleChange: onTitleChange
103
117
  }), /*#__PURE__*/_jsx(LayoutView, {
104
118
  readOnly: readOnly,
105
119
  children: children
@@ -19,7 +19,7 @@ const CheckType = props => {
19
19
  });
20
20
  };
21
21
  return /*#__PURE__*/_jsx(Checkbox, {
22
- checked: value,
22
+ checked: value || false,
23
23
  icon: /*#__PURE__*/_jsx(Icon, {
24
24
  icon: "checkListButton"
25
25
  }),
@@ -11,7 +11,7 @@ const AvatarIcon = props => {
11
11
  avatar
12
12
  } = props;
13
13
  const nameIndex = option.label || option.value;
14
- return avatar ? /*#__PURE__*/_jsx(Avatar, {
14
+ return avatar && nameIndex ? /*#__PURE__*/_jsx(Avatar, {
15
15
  alt: option.label || option.value,
16
16
  src: option.avatar || null,
17
17
  children: nameIndex[0] || ""
@@ -21,7 +21,7 @@ const filter = (opt, params, selectedOpt) => {
21
21
  const selectedVals = selectedOpt?.map(m => m?.value);
22
22
  const fv = opt?.filter(f => !selectedVals.includes(f.value));
23
23
  if (params?.inputValue) {
24
- fv.filter(f => f?.value?.toLowerCase().indexOf(params?.inputValue?.toLowerCase()) >= 0);
24
+ return fv.filter(f => f?.value?.toLowerCase().indexOf(params?.inputValue?.toLowerCase()) >= 0);
25
25
  }
26
26
  return fv;
27
27
  };
@@ -134,7 +134,7 @@ export default function Select(props) {
134
134
  children: /*#__PURE__*/_jsx(Chip, {
135
135
  label: option.label || option.value || "",
136
136
  sx: {
137
- backgroundColor: option.color || "#CCC"
137
+ background: option.color || "#CCC"
138
138
  },
139
139
  avatar: /*#__PURE__*/_jsx(AvatarIcon, {
140
140
  option: option,
@@ -24,7 +24,12 @@ const DateType = props => {
24
24
  return /*#__PURE__*/_jsx(DatePicker, {
25
25
  disabled: readOnly,
26
26
  selected: isValidDate(value) ? new Date(value) : "",
27
- onChange: handleChange
27
+ onChange: handleChange,
28
+ onKeyDown: e => {
29
+ e.preventDefault();
30
+ console.log(e?.target.value);
31
+ },
32
+ placeholderText: "MM/DD/YYYY"
28
33
  });
29
34
  };
30
35
  export default DateType;
@@ -15,16 +15,16 @@ const FilterView = props => {
15
15
  onDelete,
16
16
  onDuplicate,
17
17
  onEnter,
18
- readOnly
18
+ readOnly,
19
+ title,
20
+ onTitleChange
19
21
  } = props;
20
22
  const {
21
23
  sort,
22
24
  selectedRows,
23
25
  onDeleteRows,
24
26
  search,
25
- onSearch,
26
- title,
27
- setTitle
27
+ onSearch
28
28
  } = useDataView();
29
29
  const [anchorEl, setAnchorEl] = useState(null);
30
30
  const [anchorMoreEl, setAnchorMoreEl] = useState(null);
@@ -68,7 +68,7 @@ const FilterView = props => {
68
68
  setAnchorMoreEl(null);
69
69
  };
70
70
  const handleTitleChange = e => {
71
- setTitle(e?.target?.value);
71
+ onTitleChange(e?.target?.value);
72
72
  };
73
73
  const handleEnter = e => {
74
74
  if (e?.key === "Enter") {
@@ -93,7 +93,7 @@ const AddOptions = props => {
93
93
  primary: /*#__PURE__*/_jsx(Chip, {
94
94
  label: m.value,
95
95
  sx: {
96
- backgroundColor: m.color
96
+ background: m.color
97
97
  }
98
98
  })
99
99
  }), /*#__PURE__*/_jsx(ListItemIcon, {
@@ -1,10 +1,10 @@
1
1
  import React from "react";
2
- import { Box, Button } from "@mui/material";
3
- import AddCircleOutlineIcon from "@mui/icons-material/AddCircleOutline";
2
+ import { Box } from "@mui/material";
4
3
  import { useDataView } from "../Providers/DataViewProvider";
5
4
  import ColumnView from "./ColumnView";
6
5
  // import Formula from "./Formula";
7
6
  import { jsx as _jsx } from "react/jsx-runtime";
7
+ import { jsxs as _jsxs } from "react/jsx-runtime";
8
8
  const RenderRow = props => {
9
9
  const {
10
10
  rowIndex,
@@ -30,6 +30,7 @@ const RenderRow = props => {
30
30
  const ViewData = props => {
31
31
  const {
32
32
  attributes,
33
+ children,
33
34
  customProps
34
35
  } = props;
35
36
  const {
@@ -48,10 +49,11 @@ const ViewData = props => {
48
49
  setSelectedRows([...selectedRows?.filter(f => f !== id)]);
49
50
  }
50
51
  };
51
- return /*#__PURE__*/_jsx(Box, {
52
+ return /*#__PURE__*/_jsxs(Box, {
52
53
  component: "tbody",
53
54
  ...attributes,
54
- children: rows?.map((row, i) => {
55
+ contentEditable: false,
56
+ children: [rows?.map((row, i) => {
55
57
  return /*#__PURE__*/_jsx(Box, {
56
58
  component: "tr",
57
59
  className: "tv-act-row",
@@ -64,7 +66,16 @@ const ViewData = props => {
64
66
  readOnly: readOnly
65
67
  })
66
68
  }, i);
67
- })
69
+ }), /*#__PURE__*/_jsx("tr", {
70
+ style: {
71
+ visibility: "hidden",
72
+ display: "none"
73
+ },
74
+ "aria-hidden": "true",
75
+ children: /*#__PURE__*/_jsx("td", {
76
+ children: children
77
+ })
78
+ })]
68
79
  });
69
80
  };
70
81
  export default ViewData;
@@ -44,7 +44,6 @@ export const DataViewProvider = ({
44
44
  const [rows, setRows] = useState(initialData?.rows || []);
45
45
  const [selectedRows, setSelectedRows] = useState([]);
46
46
  const [search, setSearch] = useState("");
47
- const [title, setTitle] = useState(initialData?.tableTitle || "");
48
47
  let {
49
48
  users
50
49
  } = initialData || {};
@@ -57,7 +56,7 @@ export const DataViewProvider = ({
57
56
  // re-order when sort val changes
58
57
  useEffect(() => {
59
58
  if ((sort?.length > 0 || search) && rows?.length > 0) {
60
- const reOrderRows = sort?.length > 0 ? multiSortRows(rows, sort, properties) : [...rows];
59
+ const reOrderRows = sort?.length > 0 ? multiSortRows(initialData?.rows, sort, properties) : [...initialData?.rows];
61
60
  setRows(globalSearch(reOrderRows, search));
62
61
  } else {
63
62
  // reset to default order
@@ -242,18 +241,6 @@ export const DataViewProvider = ({
242
241
  const onSearch = e => {
243
242
  setSearch(e?.target?.value);
244
243
  };
245
- const onTitleChange = value => {
246
- try {
247
- Transforms.setNodes(editor, {
248
- title: value
249
- }, {
250
- at: path
251
- });
252
- setTitle(value);
253
- } catch (err) {
254
- console.log(err);
255
- }
256
- };
257
244
  const value = {
258
245
  layoutType,
259
246
  setLayoutType,
@@ -277,9 +264,7 @@ export const DataViewProvider = ({
277
264
  setSelectedRows,
278
265
  onDeleteRows,
279
266
  search,
280
- onSearch,
281
- title,
282
- setTitle: onTitleChange
267
+ onSearch
283
268
  };
284
269
  return /*#__PURE__*/_jsx(DataViewContext.Provider, {
285
270
  value: value,
@@ -107,6 +107,11 @@ const useDataViewStyles = (theme, appTheme) => ({
107
107
  "& .MuiInputBase-root": {
108
108
  width: "100%"
109
109
  },
110
+ "& .MuiInputBase-input": {
111
+ paddingBottom: "0px",
112
+ fontWeight: "bold",
113
+ fontSize: "16px"
114
+ },
110
115
  [theme?.breakpoints?.between("xs", "md")]: {
111
116
  width: "100%",
112
117
  marginRight: "0px"
@@ -7,6 +7,11 @@ const SimpleTextStyle = ({
7
7
  position: "relative",
8
8
  padding: "0px",
9
9
  lineHeight: lineHeight,
10
+ "&.dataView": {
11
+ "& .placeholder-simple-text": {
12
+ opacity: 0
13
+ }
14
+ },
10
15
  "&.signature": {
11
16
  "& .placeholder-simple-text": {
12
17
  opacity: 0
@@ -30,8 +35,8 @@ const SimpleTextStyle = ({
30
35
  height: "24px",
31
36
  overflow: "hidden",
32
37
  fontSize: "14px",
33
- display: 'inline-flex',
34
- alignItems: 'center',
38
+ display: "inline-flex",
39
+ alignItems: "center",
35
40
  "& .bg-pad-sl": {
36
41
  padding: "2px 4px 2px 4px",
37
42
  background: "transparent",
@@ -1,7 +1,7 @@
1
1
  import React, { useEffect, useRef, useState } from "react";
2
2
  import { Editor, Transforms } from "slate";
3
3
  import { ReactEditor, useSelected, useSlateStatic } from "slate-react";
4
- import { Box, IconButton, Tooltip, Table as TableComp, TableBody, useTheme, Popper, Fade, ClickAwayListener } from "@mui/material";
4
+ import { Box, IconButton, Tooltip, Table as TableComp, TableBody, useTheme, Popper, ClickAwayListener } from "@mui/material";
5
5
  import { TableUtil } from "../../utils/table";
6
6
  import TablePopup from "./TablePopup";
7
7
  import { useEditorContext, useEditorSelection } from "../../hooks/useMouseMove";
@@ -22,6 +22,26 @@ const hideRowDragBtns = (hide, dragRowBtnCls) => {
22
22
  rowDragBtns?.forEach(btn => btn.style.display = hide);
23
23
  }
24
24
  };
25
+ const ToolTableComponent = props => {
26
+ const {
27
+ handleAction,
28
+ editorTheme
29
+ } = props;
30
+ const {
31
+ updateTableSelection
32
+ } = useTable();
33
+ return /*#__PURE__*/_jsx("div", {
34
+ children: /*#__PURE__*/_jsx(TableTool, {
35
+ theme: editorTheme,
36
+ handleToolAction: (type, option) => {
37
+ handleAction(type, option);
38
+ if (type === "duplicate") {
39
+ updateTableSelection(getDefaultTableSelection());
40
+ }
41
+ }
42
+ })
43
+ });
44
+ };
25
45
  const MoreTableSettings = props => {
26
46
  const {
27
47
  exandTools,
@@ -29,9 +49,6 @@ const MoreTableSettings = props => {
29
49
  editorTheme,
30
50
  setExpandTools
31
51
  } = props;
32
- const {
33
- updateTableSelection
34
- } = useTable();
35
52
  const isMobile = window.matchMedia("(max-width: 899px)")?.matches || false;
36
53
  return isMobile ? /*#__PURE__*/_jsx(SwipeableDrawerComponent, {
37
54
  open: Boolean(exandTools),
@@ -39,16 +56,9 @@ const MoreTableSettings = props => {
39
56
  setExpandTools(false);
40
57
  },
41
58
  swipeableDrawer: false,
42
- children: /*#__PURE__*/_jsx("div", {
43
- children: /*#__PURE__*/_jsx(TableTool, {
44
- theme: editorTheme,
45
- handleToolAction: (type, option) => {
46
- handleAction(type, option);
47
- if (type === "duplicate") {
48
- updateTableSelection(getDefaultTableSelection());
49
- }
50
- }
51
- })
59
+ children: /*#__PURE__*/_jsx(ToolTableComponent, {
60
+ handleAction: handleAction,
61
+ editorTheme: editorTheme
52
62
  })
53
63
  }) : /*#__PURE__*/_jsx(Popper, {
54
64
  open: Boolean(exandTools),
@@ -60,16 +70,9 @@ const MoreTableSettings = props => {
60
70
  placement: "bottom-start",
61
71
  children: /*#__PURE__*/_jsx(ClickAwayListener, {
62
72
  onClickAway: () => setExpandTools(false),
63
- children: /*#__PURE__*/_jsx("div", {
64
- children: /*#__PURE__*/_jsx(TableTool, {
65
- theme: editorTheme,
66
- handleToolAction: (type, option) => {
67
- handleAction(type, option);
68
- if (type === "duplicate") {
69
- updateTableSelection(getDefaultTableSelection());
70
- }
71
- }
72
- })
73
+ children: /*#__PURE__*/_jsx(ToolTableComponent, {
74
+ handleAction: handleAction,
75
+ editorTheme: editorTheme
73
76
  })
74
77
  })
75
78
  });
@@ -0,0 +1,41 @@
1
+ function enforceDateFormat(inputElement) {
2
+ inputElement.addEventListener("input", event => {
3
+ const input = event.target;
4
+ let value = input.value;
5
+
6
+ // Allow only numbers and forward slashes
7
+ value = value.replace(/[^\d/]/g, "");
8
+
9
+ // Enforce MM/DD/YYYY structure
10
+ if (value.length > 10) {
11
+ value = value.slice(0, 10);
12
+ }
13
+ const parts = value.split("/");
14
+ if (parts.length > 1) {
15
+ parts[0] = parts[0].slice(0, 2); // Limit MM to 2 digits
16
+ if (parts[0] > 12) parts[0] = "12"; // Max month value
17
+ }
18
+
19
+ if (parts.length > 2) {
20
+ parts[1] = parts[1].slice(0, 2); // Limit DD to 2 digits
21
+ if (parts[1] > 31) parts[1] = "31"; // Max day value
22
+ }
23
+
24
+ if (parts.length > 3) {
25
+ parts[2] = parts[2].slice(0, 4); // Limit YYYY to 4 digits
26
+ }
27
+
28
+ input.value = parts.join("/");
29
+
30
+ // Optionally, validate the full date
31
+ if (input.value.length === 10) {
32
+ const [month, day, year] = input.value.split("/").map(Number);
33
+ const isValidDate = !isNaN(Date.parse(`${year}-${month}-${day}`));
34
+ if (!isValidDate) {
35
+ input.value = ""; // Clear input if invalid
36
+ alert("Invalid date format. Please enter a valid MM/DD/YYYY date.");
37
+ }
38
+ }
39
+ });
40
+ }
41
+ export default enforceDateFormat;
@@ -40,32 +40,36 @@ const withEmbeds = editor => {
40
40
  }
41
41
  };
42
42
  editor.insertBreak = (...args) => {
43
- const parentPath = Path.parent(editor.selection.focus.path);
44
- const parentNode = Node.get(editor, parentPath);
45
- if (editor.isVoid(parentNode)) {
46
- const nextPath = Path.next(parentPath);
47
- Transforms.insertNodes(editor, {
48
- type: "paragraph",
49
- children: [{
50
- text: ""
51
- }]
52
- }, {
53
- at: nextPath,
54
- select: true // Focus on this node once inserted
55
- });
56
- } else if (AvoidCopying.indexOf(parentNode?.type) >= 0) {
57
- const nextPath = Path.next(parentPath);
58
- Transforms.insertNodes(editor, {
59
- type: "paragraph",
60
- children: [{
61
- text: ""
62
- }]
63
- }, {
64
- at: nextPath,
65
- select: true // Focus on this node once inserted
66
- });
67
- } else {
68
- insertBreak(...args);
43
+ try {
44
+ const parentPath = Path.parent(editor.selection.focus.path);
45
+ const parentNode = Node.get(editor, parentPath);
46
+ if (editor.isVoid(parentNode)) {
47
+ const nextPath = Path.next(parentPath);
48
+ Transforms.insertNodes(editor, {
49
+ type: "paragraph",
50
+ children: [{
51
+ text: ""
52
+ }]
53
+ }, {
54
+ at: nextPath,
55
+ select: true // Focus on this node once inserted
56
+ });
57
+ } else if (AvoidCopying.indexOf(parentNode?.type) >= 0) {
58
+ const nextPath = Path.next(parentPath);
59
+ Transforms.insertNodes(editor, {
60
+ type: "paragraph",
61
+ children: [{
62
+ text: ""
63
+ }]
64
+ }, {
65
+ at: nextPath,
66
+ select: true // Focus on this node once inserted
67
+ });
68
+ } else {
69
+ insertBreak(...args);
70
+ }
71
+ } catch (err) {
72
+ console.log(err);
69
73
  }
70
74
  };
71
75
  return editor;
@@ -190,8 +190,8 @@ const withHtml = editor => {
190
190
  }], {
191
191
  at: [0]
192
192
  });
193
- insertData(data);
194
193
  }
194
+ insertData(data);
195
195
  }, decoded);
196
196
  }
197
197
  } else if (html) {
@@ -1,33 +1,31 @@
1
1
  import { Transforms } from "slate";
2
+ import insertNewLine from "./insertNewLine";
2
3
  const getDefaultDatView = () => ({
3
- type: "paragraph",
4
+ type: "dataView",
5
+ title: "",
6
+ layouts: [{
7
+ key: "view1",
8
+ type: "table",
9
+ label: "Table 1 View",
10
+ value: "table1",
11
+ filter: [],
12
+ sort: []
13
+ }],
14
+ properties: [{
15
+ key: "column1",
16
+ label: "Task",
17
+ type: "text",
18
+ visible: true,
19
+ default: true
20
+ }],
21
+ rows: [{
22
+ id: new Date().getTime(),
23
+ column1: ""
24
+ }],
4
25
  children: [{
5
- type: "dataView",
6
- title: "",
7
- layouts: [{
8
- key: "view1",
9
- type: "table",
10
- label: "Table 1 View",
11
- value: "table1",
12
- filter: [],
13
- sort: []
14
- }],
15
- properties: [{
16
- key: "column1",
17
- label: "Task",
18
- type: "text",
19
- visible: true,
20
- default: true
21
- }],
22
- rows: [{
23
- id: new Date().getTime(),
24
- column1: ""
25
- }],
26
+ type: "viewData",
26
27
  children: [{
27
- type: "viewData",
28
- children: [{
29
- text: ""
30
- }]
28
+ text: ""
31
29
  }]
32
30
  }]
33
31
  });
@@ -35,8 +33,10 @@ export const insertDataView = editor => {
35
33
  try {
36
34
  Transforms.insertNodes(editor, {
37
35
  ...getDefaultDatView()
36
+ }, {
37
+ at: editor?.selection.focus.path
38
38
  });
39
- Transforms.move(editor);
39
+ insertNewLine(editor);
40
40
  } catch (err) {
41
41
  console.log(err);
42
42
  }
@@ -4,6 +4,7 @@ import insertNewLine from "./insertNewLine";
4
4
  import { getDevice } from "../helper/theme";
5
5
  export const windowVar = {};
6
6
  let ST_TIMEOUT = null;
7
+ const BLOCKS = ["grid", "dataView"];
7
8
  export const formatDate = (date, format = "MM/DD/YYYY") => {
8
9
  if (!date) return "";
9
10
  var d = new Date(date),
@@ -163,7 +164,7 @@ export const handleInsertLastElement = (event, editor) => {
163
164
  if (isFreeGrid) {
164
165
  return;
165
166
  }
166
- const isLastElementEmpty = lastElement.type === "paragraph" && !lastElement.children[0]?.text && !lastElement.children?.some(c => c.type === "grid");
167
+ const isLastElementEmpty = lastElement.type === "paragraph" && !lastElement.children[0]?.text && !lastElement.children?.some(c => BLOCKS.includes(c.type));
167
168
  if (!ReactEditor.isFocused(editor)) {
168
169
  if (isLastElementEmpty) {
169
170
  if (hasPath) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flozy/editor",
3
- "version": "5.2.5",
3
+ "version": "5.2.7",
4
4
  "description": "An Editor for flozy app brain",
5
5
  "files": [
6
6
  "dist"