@manuscripts/body-editor 2.0.6 → 2.0.7-LEAN-3724.0

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.
@@ -15,7 +15,7 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.addColumns = exports.addRows = exports.insertTableFootnote = exports.addInlineComment = exports.addNodeComment = exports.createAndFillTableElement = exports.selectAllIsolating = exports.ignoreAtomBlockNodeForward = exports.isAtEndOfTextBlock = exports.ignoreMetaNodeBackspaceCommand = exports.ignoreAtomBlockNodeBackward = exports.isTextSelection = exports.isAtStartOfTextBlock = exports.insertTOCSection = exports.insertBibliographySection = exports.insertList = exports.insertKeywords = exports.insertContributors = exports.insertAbstract = exports.insertBackMatterSection = exports.insertSection = exports.insertGraphicalAbstract = exports.insertInlineFootnote = exports.insertFootnote = exports.createFootnote = exports.insertInlineEquation = exports.insertCrossReference = exports.insertInlineCitation = exports.insertLink = exports.insertSectionLabel = exports.insertBreak = exports.deleteBlock = exports.insertBlock = exports.insertSupplement = exports.insertFigure = exports.insertGeneralFootnote = exports.createBlock = exports.createSelection = exports.canInsert = exports.blockActive = exports.isNodeSelection = exports.markActive = void 0;
18
+ exports.mergeCellsWithSpace = exports.addColumns = exports.addRows = exports.insertTableFootnote = exports.addInlineComment = exports.addNodeComment = exports.createAndFillTableElement = exports.selectAllIsolating = exports.ignoreAtomBlockNodeForward = exports.isAtEndOfTextBlock = exports.ignoreMetaNodeBackspaceCommand = exports.ignoreAtomBlockNodeBackward = exports.isTextSelection = exports.isAtStartOfTextBlock = exports.insertTOCSection = exports.insertBibliographySection = exports.insertList = exports.insertKeywords = exports.insertContributors = exports.insertAbstract = exports.insertBackMatterSection = exports.insertSection = exports.insertGraphicalAbstract = exports.insertInlineFootnote = exports.insertFootnote = exports.createFootnote = exports.insertInlineEquation = exports.insertCrossReference = exports.insertInlineCitation = exports.insertLink = exports.insertSectionLabel = exports.insertBreak = exports.deleteBlock = exports.insertBlock = exports.insertSupplement = exports.insertFigure = exports.insertGeneralFootnote = exports.createBlock = exports.createSelection = exports.canInsert = exports.blockActive = exports.isNodeSelection = exports.markActive = void 0;
19
19
  const json_schema_1 = require("@manuscripts/json-schema");
20
20
  const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
21
21
  const transform_1 = require("@manuscripts/transform");
@@ -787,7 +787,7 @@ const createAndFillTableElement = (state, tableConfig) => {
787
787
  const { nodes } = state.schema;
788
788
  const { numberOfColumns, numberOfRows, includeHeader } = tableConfig;
789
789
  const createRow = (cellType) => {
790
- const cells = Array.from({ length: numberOfColumns }, () => nodes[cellType].create());
790
+ const cells = Array.from({ length: numberOfColumns }, () => nodes[cellType].create({}, state.schema.nodes.paragraph.create()));
791
791
  return nodes.table_row.create({}, cells);
792
792
  };
793
793
  const tableRows = includeHeader ? [createRow('table_header')] : [];
@@ -1012,3 +1012,80 @@ const addColumns = (direction) => (state, dispatch) => {
1012
1012
  return true;
1013
1013
  };
1014
1014
  exports.addColumns = addColumns;
1015
+ function isEmpty(cell) {
1016
+ const c = cell.content;
1017
+ return (c.childCount == 1 && c.child(0).isTextblock && c.child(0).childCount == 0);
1018
+ }
1019
+ function cellsOverlapRectangle({ width, height, map }, rect) {
1020
+ let indexTop = rect.top * width + rect.left, indexLeft = indexTop;
1021
+ let indexBottom = (rect.bottom - 1) * width + rect.left, indexRight = indexTop + (rect.right - rect.left - 1);
1022
+ for (let i = rect.top; i < rect.bottom; i++) {
1023
+ if ((rect.left > 0 && map[indexLeft] == map[indexLeft - 1]) ||
1024
+ (rect.right < width && map[indexRight] == map[indexRight + 1])) {
1025
+ return true;
1026
+ }
1027
+ indexLeft += width;
1028
+ indexRight += width;
1029
+ }
1030
+ for (let i = rect.left; i < rect.right; i++) {
1031
+ if ((rect.top > 0 && map[indexTop] == map[indexTop - width]) ||
1032
+ (rect.bottom < height && map[indexBottom] == map[indexBottom + width])) {
1033
+ return true;
1034
+ }
1035
+ indexTop++;
1036
+ indexBottom++;
1037
+ }
1038
+ return false;
1039
+ }
1040
+ function mergeCellsWithSpace(state, dispatch) {
1041
+ const sel = state.selection;
1042
+ if (!(sel instanceof prosemirror_tables_1.CellSelection) ||
1043
+ sel.$anchorCell.pos == sel.$headCell.pos) {
1044
+ return false;
1045
+ }
1046
+ const rect = (0, prosemirror_tables_1.selectedRect)(state), { map } = rect;
1047
+ if (cellsOverlapRectangle(map, rect)) {
1048
+ return false;
1049
+ }
1050
+ if (dispatch) {
1051
+ const tr = state.tr;
1052
+ const seen = {};
1053
+ let content = prosemirror_model_1.Fragment.empty;
1054
+ let mergedPos;
1055
+ let mergedCell;
1056
+ for (let row = rect.top; row < rect.bottom; row++) {
1057
+ for (let col = rect.left; col < rect.right; col++) {
1058
+ const cellPos = map.map[row * map.width + col];
1059
+ const cell = rect.table.nodeAt(cellPos);
1060
+ if (seen[cellPos] || !cell) {
1061
+ continue;
1062
+ }
1063
+ seen[cellPos] = true;
1064
+ if (mergedPos == null) {
1065
+ mergedPos = cellPos;
1066
+ mergedCell = cell;
1067
+ }
1068
+ else {
1069
+ if (!isEmpty(cell)) {
1070
+ content = content.append(cell.content.addToStart(cell.type.schema.text(' ')));
1071
+ }
1072
+ const mapped = tr.mapping.map(cellPos + rect.tableStart);
1073
+ tr.delete(mapped, mapped + cell.nodeSize);
1074
+ }
1075
+ }
1076
+ }
1077
+ if (mergedPos == null || mergedCell == null) {
1078
+ return true;
1079
+ }
1080
+ tr.setNodeMarkup(mergedPos + rect.tableStart, null, Object.assign(Object.assign({}, (0, prosemirror_tables_1.addColSpan)(mergedCell.attrs, mergedCell.attrs.colspan, rect.right - rect.left - mergedCell.attrs.colspan)), { rowspan: rect.bottom - rect.top }));
1081
+ if (content.size) {
1082
+ const end = mergedPos + 1 + mergedCell.content.size;
1083
+ const start = isEmpty(mergedCell) ? mergedPos + 1 : end;
1084
+ tr.replaceWith(start + rect.tableStart, end + rect.tableStart, content);
1085
+ }
1086
+ tr.setSelection(new prosemirror_tables_1.CellSelection(tr.doc.resolve(mergedPos + rect.tableStart)));
1087
+ dispatch(tr);
1088
+ }
1089
+ return true;
1090
+ }
1091
+ exports.mergeCellsWithSpace = mergeCellsWithSpace;
@@ -53,16 +53,20 @@ const ContextMenu = ({ view, close, }) => {
53
53
  close();
54
54
  };
55
55
  const [columnAction, setColumnAction] = (0, react_1.useState)(undefined);
56
+ const isCellSelectionMerged = (0, prosemirror_tables_1.mergeCells)(view.state);
57
+ const isCellSelectionSplittable = (0, prosemirror_tables_1.splitCell)(view.state);
56
58
  const { rows, columns } = getSelectedCellsCount(view.state);
57
59
  return (react_1.default.createElement(MenuDropdownList, null,
58
60
  react_1.default.createElement(ActionButton, { onClick: () => runCommand((0, commands_1.addRows)('top')) },
59
61
  react_1.default.createElement(style_guide_1.PlusIcon, null),
60
- " Insert row above ",
61
- rows),
62
+ " Insert ",
63
+ rows,
64
+ " above"),
62
65
  react_1.default.createElement(ActionButton, { onClick: () => runCommand((0, commands_1.addRows)('bottom')) },
63
66
  react_1.default.createElement(style_guide_1.PlusIcon, null),
64
- " Insert row below ",
65
- rows),
67
+ " Insert ",
68
+ rows,
69
+ " below"),
66
70
  react_1.default.createElement(ActionButton, { onClick: () => setColumnAction(() => (0, commands_1.addColumns)('left')) },
67
71
  react_1.default.createElement(style_guide_1.PlusIcon, null),
68
72
  " Insert ",
@@ -82,6 +86,9 @@ const ContextMenu = ({ view, close, }) => {
82
86
  react_1.default.createElement(GrayDeleteIcon, null),
83
87
  " Delete ",
84
88
  columns),
89
+ (isCellSelectionMerged || isCellSelectionSplittable) && react_1.default.createElement(Separator, null),
90
+ isCellSelectionMerged && (react_1.default.createElement(ActionButton, { onClick: () => runCommand(commands_1.mergeCellsWithSpace, true) }, "Merge cells")),
91
+ isCellSelectionSplittable && (react_1.default.createElement(ActionButton, { onClick: () => runCommand(prosemirror_tables_1.splitCell, true) }, "Split cells")),
85
92
  react_1.default.createElement(style_guide_1.ColumnChangeWarningDialog, { isOpen: !!columnAction, primaryAction: () => {
86
93
  if (columnAction) {
87
94
  runCommand(columnAction, true);
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MATHJAX_VERSION = exports.VERSION = void 0;
4
- exports.VERSION = '2.0.6';
4
+ exports.VERSION = '2.0.7-LEAN-3724.0';
5
5
  exports.MATHJAX_VERSION = '3.2.2';
@@ -19,7 +19,7 @@ import { generateID, generateNodeID, isElementNodeType, isFootnoteNode, isInBibl
19
19
  import { Fragment, NodeRange, } from 'prosemirror-model';
20
20
  import { wrapInList } from 'prosemirror-schema-list';
21
21
  import { NodeSelection, TextSelection, } from 'prosemirror-state';
22
- import { addColumnAfter, addColumnBefore, addRow, selectedRect, } from 'prosemirror-tables';
22
+ import { addColSpan, addColumnAfter, addColumnBefore, addRow, CellSelection, selectedRect, } from 'prosemirror-tables';
23
23
  import { findWrapping, liftTarget, ReplaceAroundStep, } from 'prosemirror-transform';
24
24
  import { findChildrenByType, findParentNodeOfType, findParentNodeOfTypeClosestToPos, } from 'prosemirror-utils';
25
25
  import { getCommentKey, getCommentRange } from './lib/comments';
@@ -748,7 +748,7 @@ export const createAndFillTableElement = (state, tableConfig) => {
748
748
  const { nodes } = state.schema;
749
749
  const { numberOfColumns, numberOfRows, includeHeader } = tableConfig;
750
750
  const createRow = (cellType) => {
751
- const cells = Array.from({ length: numberOfColumns }, () => nodes[cellType].create());
751
+ const cells = Array.from({ length: numberOfColumns }, () => nodes[cellType].create({}, state.schema.nodes.paragraph.create()));
752
752
  return nodes.table_row.create({}, cells);
753
753
  };
754
754
  const tableRows = includeHeader ? [createRow('table_header')] : [];
@@ -967,3 +967,79 @@ export const addColumns = (direction) => (state, dispatch) => {
967
967
  }
968
968
  return true;
969
969
  };
970
+ function isEmpty(cell) {
971
+ const c = cell.content;
972
+ return (c.childCount == 1 && c.child(0).isTextblock && c.child(0).childCount == 0);
973
+ }
974
+ function cellsOverlapRectangle({ width, height, map }, rect) {
975
+ let indexTop = rect.top * width + rect.left, indexLeft = indexTop;
976
+ let indexBottom = (rect.bottom - 1) * width + rect.left, indexRight = indexTop + (rect.right - rect.left - 1);
977
+ for (let i = rect.top; i < rect.bottom; i++) {
978
+ if ((rect.left > 0 && map[indexLeft] == map[indexLeft - 1]) ||
979
+ (rect.right < width && map[indexRight] == map[indexRight + 1])) {
980
+ return true;
981
+ }
982
+ indexLeft += width;
983
+ indexRight += width;
984
+ }
985
+ for (let i = rect.left; i < rect.right; i++) {
986
+ if ((rect.top > 0 && map[indexTop] == map[indexTop - width]) ||
987
+ (rect.bottom < height && map[indexBottom] == map[indexBottom + width])) {
988
+ return true;
989
+ }
990
+ indexTop++;
991
+ indexBottom++;
992
+ }
993
+ return false;
994
+ }
995
+ export function mergeCellsWithSpace(state, dispatch) {
996
+ const sel = state.selection;
997
+ if (!(sel instanceof CellSelection) ||
998
+ sel.$anchorCell.pos == sel.$headCell.pos) {
999
+ return false;
1000
+ }
1001
+ const rect = selectedRect(state), { map } = rect;
1002
+ if (cellsOverlapRectangle(map, rect)) {
1003
+ return false;
1004
+ }
1005
+ if (dispatch) {
1006
+ const tr = state.tr;
1007
+ const seen = {};
1008
+ let content = Fragment.empty;
1009
+ let mergedPos;
1010
+ let mergedCell;
1011
+ for (let row = rect.top; row < rect.bottom; row++) {
1012
+ for (let col = rect.left; col < rect.right; col++) {
1013
+ const cellPos = map.map[row * map.width + col];
1014
+ const cell = rect.table.nodeAt(cellPos);
1015
+ if (seen[cellPos] || !cell) {
1016
+ continue;
1017
+ }
1018
+ seen[cellPos] = true;
1019
+ if (mergedPos == null) {
1020
+ mergedPos = cellPos;
1021
+ mergedCell = cell;
1022
+ }
1023
+ else {
1024
+ if (!isEmpty(cell)) {
1025
+ content = content.append(cell.content.addToStart(cell.type.schema.text(' ')));
1026
+ }
1027
+ const mapped = tr.mapping.map(cellPos + rect.tableStart);
1028
+ tr.delete(mapped, mapped + cell.nodeSize);
1029
+ }
1030
+ }
1031
+ }
1032
+ if (mergedPos == null || mergedCell == null) {
1033
+ return true;
1034
+ }
1035
+ tr.setNodeMarkup(mergedPos + rect.tableStart, null, Object.assign(Object.assign({}, addColSpan(mergedCell.attrs, mergedCell.attrs.colspan, rect.right - rect.left - mergedCell.attrs.colspan)), { rowspan: rect.bottom - rect.top }));
1036
+ if (content.size) {
1037
+ const end = mergedPos + 1 + mergedCell.content.size;
1038
+ const start = isEmpty(mergedCell) ? mergedPos + 1 : end;
1039
+ tr.replaceWith(start + rect.tableStart, end + rect.tableStart, content);
1040
+ }
1041
+ tr.setSelection(new CellSelection(tr.doc.resolve(mergedPos + rect.tableStart)));
1042
+ dispatch(tr);
1043
+ }
1044
+ return true;
1045
+ }
@@ -1,9 +1,9 @@
1
1
  import { ColumnChangeWarningDialog, DeleteIcon, IconTextButton, PlusIcon, } from '@manuscripts/style-guide';
2
2
  import { skipTracking } from '@manuscripts/track-changes-plugin';
3
- import { CellSelection, deleteColumn, deleteRow, selectedRect, } from 'prosemirror-tables';
3
+ import { CellSelection, deleteColumn, deleteRow, mergeCells, selectedRect, splitCell, } from 'prosemirror-tables';
4
4
  import React, { useState } from 'react';
5
5
  import styled from 'styled-components';
6
- import { addColumns, addRows } from '../../commands';
6
+ import { addColumns, addRows, mergeCellsWithSpace } from '../../commands';
7
7
  const getSelectedCellsCount = (state) => {
8
8
  const { selection } = state;
9
9
  const selectedCells = { rows: 1, columns: 1 };
@@ -24,16 +24,20 @@ export const ContextMenu = ({ view, close, }) => {
24
24
  close();
25
25
  };
26
26
  const [columnAction, setColumnAction] = useState(undefined);
27
+ const isCellSelectionMerged = mergeCells(view.state);
28
+ const isCellSelectionSplittable = splitCell(view.state);
27
29
  const { rows, columns } = getSelectedCellsCount(view.state);
28
30
  return (React.createElement(MenuDropdownList, null,
29
31
  React.createElement(ActionButton, { onClick: () => runCommand(addRows('top')) },
30
32
  React.createElement(PlusIcon, null),
31
- " Insert row above ",
32
- rows),
33
+ " Insert ",
34
+ rows,
35
+ " above"),
33
36
  React.createElement(ActionButton, { onClick: () => runCommand(addRows('bottom')) },
34
37
  React.createElement(PlusIcon, null),
35
- " Insert row below ",
36
- rows),
38
+ " Insert ",
39
+ rows,
40
+ " below"),
37
41
  React.createElement(ActionButton, { onClick: () => setColumnAction(() => addColumns('left')) },
38
42
  React.createElement(PlusIcon, null),
39
43
  " Insert ",
@@ -53,6 +57,9 @@ export const ContextMenu = ({ view, close, }) => {
53
57
  React.createElement(GrayDeleteIcon, null),
54
58
  " Delete ",
55
59
  columns),
60
+ (isCellSelectionMerged || isCellSelectionSplittable) && React.createElement(Separator, null),
61
+ isCellSelectionMerged && (React.createElement(ActionButton, { onClick: () => runCommand(mergeCellsWithSpace, true) }, "Merge cells")),
62
+ isCellSelectionSplittable && (React.createElement(ActionButton, { onClick: () => runCommand(splitCell, true) }, "Split cells")),
56
63
  React.createElement(ColumnChangeWarningDialog, { isOpen: !!columnAction, primaryAction: () => {
57
64
  if (columnAction) {
58
65
  runCommand(columnAction, true);
@@ -1,2 +1,2 @@
1
- export const VERSION = '2.0.6';
1
+ export const VERSION = '2.0.7-LEAN-3724.0';
2
2
  export const MATHJAX_VERSION = '3.2.2';
@@ -68,4 +68,5 @@ interface NodeWithPosition {
68
68
  export declare const insertTableFootnote: (node: ManuscriptNode, position: number, view: EditorView, inlineFootnote?: NodeWithPosition) => void;
69
69
  export declare const addRows: (direction: 'top' | 'bottom') => (state: EditorState, dispatch?: ((tr: Transaction) => void) | undefined) => boolean;
70
70
  export declare const addColumns: (direction: 'right' | 'left') => (state: EditorState, dispatch?: ((tr: Transaction) => void) | undefined) => boolean;
71
+ export declare function mergeCellsWithSpace(state: EditorState, dispatch?: (tr: Transaction) => void): boolean;
71
72
  export {};
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "2.0.6";
1
+ export declare const VERSION = "2.0.7-LEAN-3724.0";
2
2
  export declare const MATHJAX_VERSION = "3.2.2";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@manuscripts/body-editor",
3
3
  "description": "Prosemirror components for editing and viewing manuscripts",
4
- "version": "2.0.6",
4
+ "version": "2.0.7-LEAN-3724.0",
5
5
  "repository": "github:Atypon-OpenSource/manuscripts-body-editor",
6
6
  "license": "Apache-2.0",
7
7
  "main": "dist/cjs",