@flozy/editor 5.2.5 → 5.2.7

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.
@@ -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"