@manuscripts/body-editor 3.6.9 → 3.6.11

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.
Files changed (36) hide show
  1. package/dist/cjs/commands.js +12 -9
  2. package/dist/cjs/components/outline/DraggableTree.js +1 -0
  3. package/dist/cjs/configs/editor-views.js +4 -1
  4. package/dist/cjs/lib/doc.js +7 -5
  5. package/dist/cjs/lib/utils.js +4 -0
  6. package/dist/cjs/plugins/placeholder.js +3 -0
  7. package/dist/cjs/versions.js +1 -1
  8. package/dist/cjs/views/editable_block.js +1 -0
  9. package/dist/cjs/views/section_title.js +1 -0
  10. package/dist/cjs/views/supplement.js +175 -0
  11. package/dist/cjs/views/supplement_editable.js +20 -0
  12. package/dist/cjs/views/supplements.js +56 -0
  13. package/dist/cjs/views/supplements_editable.js +21 -0
  14. package/dist/es/commands.js +13 -10
  15. package/dist/es/components/outline/DraggableTree.js +1 -0
  16. package/dist/es/configs/editor-views.js +4 -1
  17. package/dist/es/lib/doc.js +5 -3
  18. package/dist/es/lib/utils.js +4 -0
  19. package/dist/es/plugins/placeholder.js +3 -0
  20. package/dist/es/versions.js +1 -1
  21. package/dist/es/views/editable_block.js +1 -0
  22. package/dist/es/views/section_title.js +1 -0
  23. package/dist/es/views/supplement.js +171 -0
  24. package/dist/es/views/supplement_editable.js +18 -0
  25. package/dist/es/views/supplements.js +49 -0
  26. package/dist/es/views/supplements_editable.js +19 -0
  27. package/dist/types/commands.d.ts +1 -1
  28. package/dist/types/lib/doc.d.ts +2 -2
  29. package/dist/types/versions.d.ts +1 -1
  30. package/dist/types/views/supplement.d.ts +37 -0
  31. package/dist/types/views/supplement_editable.d.ts +18 -0
  32. package/dist/types/views/supplements.d.ts +27 -0
  33. package/dist/types/views/supplements_editable.d.ts +44 -0
  34. package/package.json +2 -2
  35. package/styles/AdvancedEditor.css +14 -4
  36. package/styles/Editor.css +159 -0
@@ -297,18 +297,21 @@ const insertTable = (config, state, dispatch) => {
297
297
  return true;
298
298
  };
299
299
  exports.insertTable = insertTable;
300
- const insertSupplement = (file, state, dispatch) => {
300
+ const insertSupplement = (file, view) => {
301
301
  const supplement = transform_1.schema.nodes.supplement.createAndFill({
302
302
  id: (0, transform_1.generateNodeID)(transform_1.schema.nodes.supplement),
303
303
  href: file.id,
304
- });
305
- const tr = state.tr;
306
- const supplements = (0, doc_1.insertSupplementsNode)(tr);
307
- const pos = supplements.pos + supplements.node.nodeSize - 1;
308
- tr.insert(pos, supplement);
309
- if (dispatch) {
310
- dispatch((0, track_changes_plugin_1.skipTracking)(tr));
311
- }
304
+ }, [
305
+ transform_1.schema.nodes.figcaption.create({}, [
306
+ transform_1.schema.nodes.caption_title.create(),
307
+ transform_1.schema.nodes.caption.create(),
308
+ ]),
309
+ ]);
310
+ const tr = view.state.tr;
311
+ const { pos } = (0, doc_1.upsertSupplementsSection)(tr, supplement);
312
+ tr.setSelection(prosemirror_state_1.NodeSelection.create(tr.doc, pos));
313
+ view.focus();
314
+ view.dispatch(tr.scrollIntoView());
312
315
  return true;
313
316
  };
314
317
  exports.insertSupplement = insertSupplement;
@@ -63,6 +63,7 @@ const excludedTypes = [
63
63
  transform_1.schema.nodes.trans_abstract,
64
64
  transform_1.schema.nodes.subtitles,
65
65
  transform_1.schema.nodes.subtitle,
66
+ transform_1.schema.nodes.supplements,
66
67
  ];
67
68
  const childrenExcludedTypes = [
68
69
  transform_1.schema.nodes.pullquote_element,
@@ -47,6 +47,8 @@ const section_label_1 = __importDefault(require("../views/section_label"));
47
47
  const section_title_editable_1 = __importDefault(require("../views/section_title_editable"));
48
48
  const subtitle_editable_1 = __importDefault(require("../views/subtitle_editable"));
49
49
  const subtitles_editable_1 = __importDefault(require("../views/subtitles_editable"));
50
+ const supplement_editable_1 = __importDefault(require("../views/supplement_editable"));
51
+ const supplements_editable_1 = __importDefault(require("../views/supplements_editable"));
50
52
  const table_cell_1 = __importDefault(require("../views/table_cell"));
51
53
  const table_element_editable_1 = __importDefault(require("../views/table_element_editable"));
52
54
  const table_element_footer_1 = __importDefault(require("../views/table_element_footer"));
@@ -96,7 +98,8 @@ exports.default = (props, dispatch) => {
96
98
  table_header: (0, table_cell_1.default)(props),
97
99
  table_element_footer: (0, table_element_footer_1.default)(props),
98
100
  comments: (0, empty_1.default)('comments'),
99
- supplements: (0, empty_1.default)('supplements'),
101
+ supplements: (0, supplements_editable_1.default)(props, dispatch),
102
+ supplement: (0, supplement_editable_1.default)(props, dispatch),
100
103
  author_notes: (0, author_notes_1.default)(props, dispatch),
101
104
  awards: (0, awards_1.default)(props, dispatch),
102
105
  award: (0, award_1.default)(props, dispatch),
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.findNodeByID = exports.findGraphicalAbstractFigureElement = exports.findFootnotesSection = exports.findBibliographySection = exports.findBackmatter = exports.findBody = exports.findAbstractsNode = exports.insertFootnotesSection = exports.insertAttachmentsNode = exports.insertSupplementsNode = exports.insertAwardsNode = void 0;
3
+ exports.findNodeByID = exports.findGraphicalAbstractFigureElement = exports.findFootnotesSection = exports.findBibliographySection = exports.findBackmatter = exports.findBody = exports.findAbstractsNode = exports.insertFootnotesSection = exports.insertAttachmentsNode = exports.upsertSupplementsSection = exports.insertAwardsNode = void 0;
4
4
  const transform_1 = require("@manuscripts/transform");
5
5
  const prosemirror_utils_1 = require("prosemirror-utils");
6
6
  const utils_1 = require("./utils");
@@ -19,21 +19,23 @@ const insertAwardsNode = (tr) => {
19
19
  };
20
20
  };
21
21
  exports.insertAwardsNode = insertAwardsNode;
22
- const insertSupplementsNode = (tr) => {
22
+ const upsertSupplementsSection = (tr, supplement) => {
23
23
  const doc = tr.doc;
24
24
  const supplements = (0, prosemirror_utils_1.findChildrenByType)(doc, transform_1.schema.nodes.supplements)[0];
25
25
  if (supplements) {
26
- return supplements;
26
+ const pos = supplements.pos + supplements.node.nodeSize - 1;
27
+ tr.insert(pos, supplement);
28
+ return { node: supplements.node, pos };
27
29
  }
28
30
  const pos = (0, utils_1.findInsertionPosition)(transform_1.schema.nodes.supplements, doc);
29
- const node = transform_1.schema.nodes.supplements.createAndFill();
31
+ const node = transform_1.schema.nodes.supplements.createAndFill({ id: (0, transform_1.generateNodeID)(transform_1.schema.nodes.supplements) }, [supplement]);
30
32
  tr.insert(pos, node);
31
33
  return {
32
34
  node,
33
35
  pos,
34
36
  };
35
37
  };
36
- exports.insertSupplementsNode = insertSupplementsNode;
38
+ exports.upsertSupplementsSection = upsertSupplementsSection;
37
39
  const insertAttachmentsNode = (tr) => {
38
40
  const attachmentsNodes = (0, prosemirror_utils_1.findChildrenByType)(tr.doc, transform_1.schema.nodes.attachments);
39
41
  if (attachmentsNodes.length) {
@@ -181,6 +181,10 @@ const findInsertionPosition = (type, doc) => {
181
181
  insertPos = offset;
182
182
  }
183
183
  });
184
+ if (insertPos === 0 &&
185
+ doc.canReplaceWith(doc.childCount, doc.childCount, type)) {
186
+ insertPos = doc.content.size;
187
+ }
184
188
  return insertPos;
185
189
  };
186
190
  exports.findInsertionPosition = findInsertionPosition;
@@ -84,6 +84,9 @@ exports.default = () => new prosemirror_state_1.Plugin({
84
84
  if ((0, prosemirror_utils_1.findParentNodeOfTypeClosestToPos)($pos, transform_1.schema.nodes.box_element)) {
85
85
  placeholderText = 'Optional box title...';
86
86
  }
87
+ if ((0, prosemirror_utils_1.findParentNodeOfTypeClosestToPos)($pos, transform_1.schema.nodes.supplements)) {
88
+ placeholderText = 'Supplements';
89
+ }
87
90
  decorations.push(prosemirror_view_1.Decoration.widget(pos + 1, placeholderWidget(placeholderText)));
88
91
  }
89
92
  else if (node.type === node.type.schema.nodes.trans_abstract) {
@@ -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 = '3.6.9';
4
+ exports.VERSION = '3.6.11';
5
5
  exports.MATHJAX_VERSION = '3.2.2';
@@ -42,6 +42,7 @@ const EditableBlock = (Base) => {
42
42
  const nodeType = this.node.type;
43
43
  if (nodeType === transform_1.schema.nodes.hero_image ||
44
44
  nodeType === transform_1.schema.nodes.subtitles ||
45
+ nodeType === transform_1.schema.nodes.supplements ||
45
46
  (0, utils_1.hasParent)($pos, [
46
47
  transform_1.schema.nodes.keywords,
47
48
  transform_1.schema.nodes.bibliography_section,
@@ -32,6 +32,7 @@ class SectionTitleView extends block_view_1.default {
32
32
  transform_1.schema.nodes.bibliography_section,
33
33
  transform_1.schema.nodes.footnotes_section,
34
34
  transform_1.schema.nodes.graphical_abstract_section,
35
+ transform_1.schema.nodes.supplements,
35
36
  ];
36
37
  this.createElement = () => {
37
38
  this.contentDOM = document.createElement(this.elementType);
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ /*!
3
+ * © 2025 Atypon Systems LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.SupplementView = void 0;
19
+ const style_guide_1 = require("@manuscripts/style-guide");
20
+ const server_1 = require("react-dom/server");
21
+ const icons_1 = require("../icons");
22
+ const doc_1 = require("../lib/doc");
23
+ const base_node_view_1 = require("./base_node_view");
24
+ const creators_1 = require("./creators");
25
+ class SupplementView extends base_node_view_1.BaseNodeView {
26
+ constructor() {
27
+ super(...arguments);
28
+ this.ignoreMutation = () => true;
29
+ this.createElement = () => {
30
+ this.dom = document.createElement('div');
31
+ this.dom.classList.add('supplement-item');
32
+ this.dom.classList.add('block');
33
+ this.dom.setAttribute('id', this.node.attrs.id);
34
+ this.dom.setAttribute('href', this.node.attrs.href);
35
+ this.dom.draggable = true;
36
+ this.contentDOM = document.createElement('div');
37
+ this.contentDOM.classList.add('supplement-caption');
38
+ this.dom.appendChild(this.contentDOM);
39
+ this.addFileInfo();
40
+ this.addDragIcon();
41
+ };
42
+ }
43
+ initialise() {
44
+ this.createElement();
45
+ this.updateContents();
46
+ this.setupDragAndDrop();
47
+ }
48
+ updateContents() {
49
+ super.updateContents();
50
+ this.refreshFileInfo();
51
+ }
52
+ getDropSide(element, clientY) {
53
+ const { top, bottom } = element.getBoundingClientRect();
54
+ const middleY = (top + bottom) / 2;
55
+ return clientY > middleY ? 'after' : 'before';
56
+ }
57
+ noActualMove(currentPos, nodeSize, targetPos) {
58
+ return targetPos === currentPos || targetPos === currentPos + nodeSize;
59
+ }
60
+ handleDragStart() {
61
+ const supplementId = this.node.attrs.id;
62
+ SupplementView.currentDragSupplementId = supplementId;
63
+ this.dom.classList.add('dragging');
64
+ }
65
+ setupDragAndDrop() {
66
+ const clearDropClasses = () => {
67
+ this.dom.classList.remove('drop-target-above', 'drop-target-below');
68
+ };
69
+ this.dom.addEventListener('dragstart', () => {
70
+ if (this.node.attrs.id) {
71
+ this.handleDragStart();
72
+ }
73
+ });
74
+ this.dom.addEventListener('dragend', () => {
75
+ SupplementView.currentDragSupplementId = null;
76
+ this.dom.classList.remove('dragging');
77
+ clearDropClasses();
78
+ });
79
+ this.dom.addEventListener('dragover', (e) => {
80
+ if (SupplementView.currentDragSupplementId) {
81
+ e.preventDefault();
82
+ e.stopPropagation();
83
+ const side = this.getDropSide(this.dom, e.clientY);
84
+ clearDropClasses();
85
+ this.dom.classList.add(side === 'before' ? 'drop-target-above' : 'drop-target-below');
86
+ }
87
+ });
88
+ this.dom.addEventListener('dragleave', (e) => {
89
+ if (!this.dom.contains(e.relatedTarget)) {
90
+ clearDropClasses();
91
+ }
92
+ });
93
+ this.dom.addEventListener('drop', (e) => {
94
+ if (!SupplementView.currentDragSupplementId) {
95
+ return;
96
+ }
97
+ e.preventDefault();
98
+ e.stopPropagation();
99
+ const supplementId = SupplementView.currentDragSupplementId;
100
+ if (!supplementId) {
101
+ return;
102
+ }
103
+ const { state } = this.view;
104
+ const supplement = (0, doc_1.findNodeByID)(state.doc, supplementId);
105
+ if (!supplement) {
106
+ return;
107
+ }
108
+ const toPos = this.getPos();
109
+ const side = this.getDropSide(this.dom, e.clientY);
110
+ const targetPos = side === 'before' ? toPos : toPos + this.node.nodeSize;
111
+ if (this.noActualMove(supplement.pos, supplement.node.nodeSize, targetPos)) {
112
+ clearDropClasses();
113
+ return;
114
+ }
115
+ this.moveSupplement(supplement.pos, supplement.node, targetPos);
116
+ clearDropClasses();
117
+ });
118
+ }
119
+ moveSupplement(fromPos, fromNode, targetPos) {
120
+ const { state } = this.view;
121
+ const { tr } = state;
122
+ tr.insert(targetPos, fromNode);
123
+ const mappedFrom = tr.mapping.map(fromPos, -1);
124
+ tr.delete(mappedFrom, mappedFrom + fromNode.nodeSize);
125
+ this.view.dispatch(tr);
126
+ }
127
+ addFileInfo() {
128
+ this.supplementInfoEl = document.createElement('div');
129
+ this.supplementInfoEl.classList.add('supplement-file-info');
130
+ this.supplementInfoEl.contentEditable = 'false';
131
+ const files = this.props.getFiles();
132
+ const file = files.find((f) => f.id === this.node.attrs.href);
133
+ if (file) {
134
+ const iconElement = document.createElement('span');
135
+ iconElement.classList.add('supplement-file-icon');
136
+ const icon = (0, style_guide_1.getFileIcon)(file.name);
137
+ if (icon) {
138
+ iconElement.innerHTML = (0, server_1.renderToStaticMarkup)(icon);
139
+ }
140
+ this.supplementInfoEl.appendChild(iconElement);
141
+ const fileName = document.createElement('span');
142
+ fileName.classList.add('supplement-file-name');
143
+ fileName.textContent = file.name;
144
+ this.supplementInfoEl.appendChild(fileName);
145
+ }
146
+ else {
147
+ const placeholder = document.createElement('span');
148
+ placeholder.textContent = 'File not found';
149
+ this.supplementInfoEl.appendChild(placeholder);
150
+ }
151
+ this.dom.appendChild(this.supplementInfoEl);
152
+ }
153
+ refreshFileInfo() {
154
+ this.supplementInfoEl.remove();
155
+ this.addFileInfo();
156
+ }
157
+ addDragIcon() {
158
+ if (this.dragIcon) {
159
+ this.dragIcon.remove();
160
+ this.dragIcon = undefined;
161
+ }
162
+ const dragIcon = document.createElement('div');
163
+ dragIcon.className = 'drag-icon';
164
+ dragIcon.innerHTML = icons_1.draggableIcon;
165
+ dragIcon.draggable = false;
166
+ dragIcon.addEventListener('mousedown', (e) => {
167
+ e.stopPropagation();
168
+ });
169
+ this.dragIcon = dragIcon;
170
+ this.dom.appendChild(dragIcon);
171
+ }
172
+ }
173
+ exports.SupplementView = SupplementView;
174
+ SupplementView.currentDragSupplementId = null;
175
+ exports.default = (0, creators_1.createNodeView)(SupplementView);
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /*!
3
+ * © 2025 Atypon Systems LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ const creators_1 = require("./creators");
19
+ const supplement_1 = require("./supplement");
20
+ exports.default = (0, creators_1.createEditableNodeView)(supplement_1.SupplementView);
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ /*!
3
+ * © 2025 Atypon Systems LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.SupplementsView = void 0;
22
+ const icons_1 = require("../icons");
23
+ const block_view_1 = __importDefault(require("./block_view"));
24
+ const creators_1 = require("./creators");
25
+ class SupplementsView extends block_view_1.default {
26
+ constructor() {
27
+ super(...arguments);
28
+ this.collapsed = false;
29
+ this.ignoreMutation = () => true;
30
+ this.createElement = () => {
31
+ this.toggleButton = document.createElement('button');
32
+ this.toggleButton.classList.add('supplements-toggle-btn', 'button-reset');
33
+ this.toggleButton.innerHTML = icons_1.arrowUp;
34
+ this.toggleButton.onclick = () => {
35
+ this.collapsed = !this.collapsed;
36
+ this.toggleContent();
37
+ this.toggleButton?.classList.toggle('collapsed', this.collapsed);
38
+ };
39
+ this.contentDOM = document.createElement('div');
40
+ this.contentDOM.classList.add('supplements-content');
41
+ this.contentDOM.classList.add('block');
42
+ this.dom.appendChild(this.toggleButton);
43
+ this.dom.setAttribute('id', this.node.attrs.id);
44
+ this.dom.appendChild(this.contentDOM);
45
+ };
46
+ }
47
+ toggleContent() {
48
+ const supplementItems = this.contentDOM?.querySelectorAll('.supplement-item');
49
+ supplementItems?.forEach((item) => {
50
+ const element = item;
51
+ element.style.display = this.collapsed ? 'none' : '';
52
+ });
53
+ }
54
+ }
55
+ exports.SupplementsView = SupplementsView;
56
+ exports.default = (0, creators_1.createNodeView)(SupplementsView);
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /*!
3
+ * © 2025 Atypon Systems LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ const creators_1 = require("./creators");
19
+ const editable_block_1 = require("./editable_block");
20
+ const supplements_1 = require("./supplements");
21
+ exports.default = (0, creators_1.createEditableNodeView)((0, editable_block_1.EditableBlock)(supplements_1.SupplementsView));
@@ -23,7 +23,7 @@ import { addColumnAfter, addColumnBefore, addRow, selectedRect, } from 'prosemir
23
23
  import { findWrapping, liftTarget, ReplaceAroundStep, ReplaceStep, } from 'prosemirror-transform';
24
24
  import { findChildrenByType, findParentNodeOfType, findParentNodeOfTypeClosestToPos, flatten, hasParentNodeOfType, } from 'prosemirror-utils';
25
25
  import { getCommentKey, getCommentRange } from './lib/comments';
26
- import { findAbstractsNode, findBackmatter, findBibliographySection, findBody, findFootnotesSection, insertAttachmentsNode, insertAwardsNode, insertFootnotesSection, insertSupplementsNode, } from './lib/doc';
26
+ import { findAbstractsNode, findBackmatter, findBibliographySection, findBody, findFootnotesSection, insertAttachmentsNode, insertAwardsNode, insertFootnotesSection, upsertSupplementsSection, } from './lib/doc';
27
27
  import { createFootnote, findFootnotesContainerNode, getFootnotesElementState, } from './lib/footnotes';
28
28
  import { findWordBoundaries, isNodeOfType, nearestAncestor, } from './lib/helpers';
29
29
  import { templateAllows } from './lib/template';
@@ -281,18 +281,21 @@ export const insertTable = (config, state, dispatch) => {
281
281
  dispatch && dispatch(tr);
282
282
  return true;
283
283
  };
284
- export const insertSupplement = (file, state, dispatch) => {
284
+ export const insertSupplement = (file, view) => {
285
285
  const supplement = schema.nodes.supplement.createAndFill({
286
286
  id: generateNodeID(schema.nodes.supplement),
287
287
  href: file.id,
288
- });
289
- const tr = state.tr;
290
- const supplements = insertSupplementsNode(tr);
291
- const pos = supplements.pos + supplements.node.nodeSize - 1;
292
- tr.insert(pos, supplement);
293
- if (dispatch) {
294
- dispatch(skipTracking(tr));
295
- }
288
+ }, [
289
+ schema.nodes.figcaption.create({}, [
290
+ schema.nodes.caption_title.create(),
291
+ schema.nodes.caption.create(),
292
+ ]),
293
+ ]);
294
+ const tr = view.state.tr;
295
+ const { pos } = upsertSupplementsSection(tr, supplement);
296
+ tr.setSelection(NodeSelection.create(tr.doc, pos));
297
+ view.focus();
298
+ view.dispatch(tr.scrollIntoView());
296
299
  return true;
297
300
  };
298
301
  export const insertAttachment = (file, state, type, dispatch) => {
@@ -27,6 +27,7 @@ const excludedTypes = [
27
27
  schema.nodes.trans_abstract,
28
28
  schema.nodes.subtitles,
29
29
  schema.nodes.subtitle,
30
+ schema.nodes.supplements,
30
31
  ];
31
32
  const childrenExcludedTypes = [
32
33
  schema.nodes.pullquote_element,
@@ -42,6 +42,8 @@ import sectionLabel from '../views/section_label';
42
42
  import sectionTitle from '../views/section_title_editable';
43
43
  import subtitle from '../views/subtitle_editable';
44
44
  import subtitles from '../views/subtitles_editable';
45
+ import supplement from '../views/supplement_editable';
46
+ import supplements from '../views/supplements_editable';
45
47
  import tableCell from '../views/table_cell';
46
48
  import tableElement from '../views/table_element_editable';
47
49
  import tableElementFooter from '../views/table_element_footer';
@@ -91,7 +93,8 @@ export default (props, dispatch) => {
91
93
  table_header: tableCell(props),
92
94
  table_element_footer: tableElementFooter(props),
93
95
  comments: empty('comments'),
94
- supplements: empty('supplements'),
96
+ supplements: supplements(props, dispatch),
97
+ supplement: supplement(props, dispatch),
95
98
  author_notes: authorNotes(props, dispatch),
96
99
  awards: awards(props, dispatch),
97
100
  award: award(props, dispatch),
@@ -15,14 +15,16 @@ export const insertAwardsNode = (tr) => {
15
15
  pos,
16
16
  };
17
17
  };
18
- export const insertSupplementsNode = (tr) => {
18
+ export const upsertSupplementsSection = (tr, supplement) => {
19
19
  const doc = tr.doc;
20
20
  const supplements = findChildrenByType(doc, schema.nodes.supplements)[0];
21
21
  if (supplements) {
22
- return supplements;
22
+ const pos = supplements.pos + supplements.node.nodeSize - 1;
23
+ tr.insert(pos, supplement);
24
+ return { node: supplements.node, pos };
23
25
  }
24
26
  const pos = findInsertionPosition(schema.nodes.supplements, doc);
25
- const node = schema.nodes.supplements.createAndFill();
27
+ const node = schema.nodes.supplements.createAndFill({ id: generateNodeID(schema.nodes.supplements) }, [supplement]);
26
28
  tr.insert(pos, node);
27
29
  return {
28
30
  node,
@@ -161,6 +161,10 @@ export const findInsertionPosition = (type, doc) => {
161
161
  insertPos = offset;
162
162
  }
163
163
  });
164
+ if (insertPos === 0 &&
165
+ doc.canReplaceWith(doc.childCount, doc.childCount, type)) {
166
+ insertPos = doc.content.size;
167
+ }
164
168
  return insertPos;
165
169
  };
166
170
  export const filterBlockNodes = (fragment, predicate) => {
@@ -82,6 +82,9 @@ export default () => new Plugin({
82
82
  if (findParentNodeOfTypeClosestToPos($pos, schema.nodes.box_element)) {
83
83
  placeholderText = 'Optional box title...';
84
84
  }
85
+ if (findParentNodeOfTypeClosestToPos($pos, schema.nodes.supplements)) {
86
+ placeholderText = 'Supplements';
87
+ }
85
88
  decorations.push(Decoration.widget(pos + 1, placeholderWidget(placeholderText)));
86
89
  }
87
90
  else if (node.type === node.type.schema.nodes.trans_abstract) {
@@ -1,2 +1,2 @@
1
- export const VERSION = '3.6.9';
1
+ export const VERSION = '3.6.11';
2
2
  export const MATHJAX_VERSION = '3.2.2';
@@ -39,6 +39,7 @@ export const EditableBlock = (Base) => {
39
39
  const nodeType = this.node.type;
40
40
  if (nodeType === schema.nodes.hero_image ||
41
41
  nodeType === schema.nodes.subtitles ||
42
+ nodeType === schema.nodes.supplements ||
42
43
  hasParent($pos, [
43
44
  schema.nodes.keywords,
44
45
  schema.nodes.bibliography_section,
@@ -26,6 +26,7 @@ export class SectionTitleView extends BlockView {
26
26
  schema.nodes.bibliography_section,
27
27
  schema.nodes.footnotes_section,
28
28
  schema.nodes.graphical_abstract_section,
29
+ schema.nodes.supplements,
29
30
  ];
30
31
  this.createElement = () => {
31
32
  this.contentDOM = document.createElement(this.elementType);
@@ -0,0 +1,171 @@
1
+ /*!
2
+ * © 2025 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { getFileIcon } from '@manuscripts/style-guide';
17
+ import { renderToStaticMarkup } from 'react-dom/server';
18
+ import { draggableIcon } from '../icons';
19
+ import { findNodeByID } from '../lib/doc';
20
+ import { BaseNodeView } from './base_node_view';
21
+ import { createNodeView } from './creators';
22
+ export class SupplementView extends BaseNodeView {
23
+ constructor() {
24
+ super(...arguments);
25
+ this.ignoreMutation = () => true;
26
+ this.createElement = () => {
27
+ this.dom = document.createElement('div');
28
+ this.dom.classList.add('supplement-item');
29
+ this.dom.classList.add('block');
30
+ this.dom.setAttribute('id', this.node.attrs.id);
31
+ this.dom.setAttribute('href', this.node.attrs.href);
32
+ this.dom.draggable = true;
33
+ this.contentDOM = document.createElement('div');
34
+ this.contentDOM.classList.add('supplement-caption');
35
+ this.dom.appendChild(this.contentDOM);
36
+ this.addFileInfo();
37
+ this.addDragIcon();
38
+ };
39
+ }
40
+ initialise() {
41
+ this.createElement();
42
+ this.updateContents();
43
+ this.setupDragAndDrop();
44
+ }
45
+ updateContents() {
46
+ super.updateContents();
47
+ this.refreshFileInfo();
48
+ }
49
+ getDropSide(element, clientY) {
50
+ const { top, bottom } = element.getBoundingClientRect();
51
+ const middleY = (top + bottom) / 2;
52
+ return clientY > middleY ? 'after' : 'before';
53
+ }
54
+ noActualMove(currentPos, nodeSize, targetPos) {
55
+ return targetPos === currentPos || targetPos === currentPos + nodeSize;
56
+ }
57
+ handleDragStart() {
58
+ const supplementId = this.node.attrs.id;
59
+ SupplementView.currentDragSupplementId = supplementId;
60
+ this.dom.classList.add('dragging');
61
+ }
62
+ setupDragAndDrop() {
63
+ const clearDropClasses = () => {
64
+ this.dom.classList.remove('drop-target-above', 'drop-target-below');
65
+ };
66
+ this.dom.addEventListener('dragstart', () => {
67
+ if (this.node.attrs.id) {
68
+ this.handleDragStart();
69
+ }
70
+ });
71
+ this.dom.addEventListener('dragend', () => {
72
+ SupplementView.currentDragSupplementId = null;
73
+ this.dom.classList.remove('dragging');
74
+ clearDropClasses();
75
+ });
76
+ this.dom.addEventListener('dragover', (e) => {
77
+ if (SupplementView.currentDragSupplementId) {
78
+ e.preventDefault();
79
+ e.stopPropagation();
80
+ const side = this.getDropSide(this.dom, e.clientY);
81
+ clearDropClasses();
82
+ this.dom.classList.add(side === 'before' ? 'drop-target-above' : 'drop-target-below');
83
+ }
84
+ });
85
+ this.dom.addEventListener('dragleave', (e) => {
86
+ if (!this.dom.contains(e.relatedTarget)) {
87
+ clearDropClasses();
88
+ }
89
+ });
90
+ this.dom.addEventListener('drop', (e) => {
91
+ if (!SupplementView.currentDragSupplementId) {
92
+ return;
93
+ }
94
+ e.preventDefault();
95
+ e.stopPropagation();
96
+ const supplementId = SupplementView.currentDragSupplementId;
97
+ if (!supplementId) {
98
+ return;
99
+ }
100
+ const { state } = this.view;
101
+ const supplement = findNodeByID(state.doc, supplementId);
102
+ if (!supplement) {
103
+ return;
104
+ }
105
+ const toPos = this.getPos();
106
+ const side = this.getDropSide(this.dom, e.clientY);
107
+ const targetPos = side === 'before' ? toPos : toPos + this.node.nodeSize;
108
+ if (this.noActualMove(supplement.pos, supplement.node.nodeSize, targetPos)) {
109
+ clearDropClasses();
110
+ return;
111
+ }
112
+ this.moveSupplement(supplement.pos, supplement.node, targetPos);
113
+ clearDropClasses();
114
+ });
115
+ }
116
+ moveSupplement(fromPos, fromNode, targetPos) {
117
+ const { state } = this.view;
118
+ const { tr } = state;
119
+ tr.insert(targetPos, fromNode);
120
+ const mappedFrom = tr.mapping.map(fromPos, -1);
121
+ tr.delete(mappedFrom, mappedFrom + fromNode.nodeSize);
122
+ this.view.dispatch(tr);
123
+ }
124
+ addFileInfo() {
125
+ this.supplementInfoEl = document.createElement('div');
126
+ this.supplementInfoEl.classList.add('supplement-file-info');
127
+ this.supplementInfoEl.contentEditable = 'false';
128
+ const files = this.props.getFiles();
129
+ const file = files.find((f) => f.id === this.node.attrs.href);
130
+ if (file) {
131
+ const iconElement = document.createElement('span');
132
+ iconElement.classList.add('supplement-file-icon');
133
+ const icon = getFileIcon(file.name);
134
+ if (icon) {
135
+ iconElement.innerHTML = renderToStaticMarkup(icon);
136
+ }
137
+ this.supplementInfoEl.appendChild(iconElement);
138
+ const fileName = document.createElement('span');
139
+ fileName.classList.add('supplement-file-name');
140
+ fileName.textContent = file.name;
141
+ this.supplementInfoEl.appendChild(fileName);
142
+ }
143
+ else {
144
+ const placeholder = document.createElement('span');
145
+ placeholder.textContent = 'File not found';
146
+ this.supplementInfoEl.appendChild(placeholder);
147
+ }
148
+ this.dom.appendChild(this.supplementInfoEl);
149
+ }
150
+ refreshFileInfo() {
151
+ this.supplementInfoEl.remove();
152
+ this.addFileInfo();
153
+ }
154
+ addDragIcon() {
155
+ if (this.dragIcon) {
156
+ this.dragIcon.remove();
157
+ this.dragIcon = undefined;
158
+ }
159
+ const dragIcon = document.createElement('div');
160
+ dragIcon.className = 'drag-icon';
161
+ dragIcon.innerHTML = draggableIcon;
162
+ dragIcon.draggable = false;
163
+ dragIcon.addEventListener('mousedown', (e) => {
164
+ e.stopPropagation();
165
+ });
166
+ this.dragIcon = dragIcon;
167
+ this.dom.appendChild(dragIcon);
168
+ }
169
+ }
170
+ SupplementView.currentDragSupplementId = null;
171
+ export default createNodeView(SupplementView);
@@ -0,0 +1,18 @@
1
+ /*!
2
+ * © 2025 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { createEditableNodeView } from './creators';
17
+ import { SupplementView } from './supplement';
18
+ export default createEditableNodeView(SupplementView);
@@ -0,0 +1,49 @@
1
+ /*!
2
+ * © 2025 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { arrowUp } from '../icons';
17
+ import BlockView from './block_view';
18
+ import { createNodeView } from './creators';
19
+ export class SupplementsView extends BlockView {
20
+ constructor() {
21
+ super(...arguments);
22
+ this.collapsed = false;
23
+ this.ignoreMutation = () => true;
24
+ this.createElement = () => {
25
+ this.toggleButton = document.createElement('button');
26
+ this.toggleButton.classList.add('supplements-toggle-btn', 'button-reset');
27
+ this.toggleButton.innerHTML = arrowUp;
28
+ this.toggleButton.onclick = () => {
29
+ this.collapsed = !this.collapsed;
30
+ this.toggleContent();
31
+ this.toggleButton?.classList.toggle('collapsed', this.collapsed);
32
+ };
33
+ this.contentDOM = document.createElement('div');
34
+ this.contentDOM.classList.add('supplements-content');
35
+ this.contentDOM.classList.add('block');
36
+ this.dom.appendChild(this.toggleButton);
37
+ this.dom.setAttribute('id', this.node.attrs.id);
38
+ this.dom.appendChild(this.contentDOM);
39
+ };
40
+ }
41
+ toggleContent() {
42
+ const supplementItems = this.contentDOM?.querySelectorAll('.supplement-item');
43
+ supplementItems?.forEach((item) => {
44
+ const element = item;
45
+ element.style.display = this.collapsed ? 'none' : '';
46
+ });
47
+ }
48
+ }
49
+ export default createNodeView(SupplementsView);
@@ -0,0 +1,19 @@
1
+ /*!
2
+ * © 2025 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { createEditableNodeView } from './creators';
17
+ import { EditableBlock } from './editable_block';
18
+ import { SupplementsView } from './supplements';
19
+ export default createEditableNodeView(EditableBlock(SupplementsView));
@@ -32,7 +32,7 @@ export declare const insertGeneralTableFootnote: (element: [ManuscriptNode, numb
32
32
  export declare const insertFigure: (file: FileAttachment, state: ManuscriptEditorState, dispatch?: Dispatch) => boolean;
33
33
  export declare const insertEmbed: (state: ManuscriptEditorState, dispatch?: Dispatch, attrs?: Attrs) => boolean;
34
34
  export declare const insertTable: (config: TableConfig, state: ManuscriptEditorState, dispatch?: Dispatch) => boolean;
35
- export declare const insertSupplement: (file: FileAttachment, state: ManuscriptEditorState, dispatch?: Dispatch) => boolean;
35
+ export declare const insertSupplement: (file: FileAttachment, view: ManuscriptEditorView) => boolean;
36
36
  export declare const insertAttachment: (file: FileAttachment, state: ManuscriptEditorState, type: string, dispatch?: Dispatch) => boolean;
37
37
  export declare const insertBlock: (nodeType: ManuscriptNodeType) => (state: ManuscriptEditorState, dispatch?: Dispatch) => boolean;
38
38
  export declare const deleteBlock: (typeToDelete: string) => (state: ManuscriptEditorState, dispatch?: Dispatch) => boolean;
@@ -1,4 +1,4 @@
1
- import { AwardsNode, ManuscriptNode, ManuscriptTransaction, SupplementsNode } from '@manuscripts/transform';
1
+ import { AwardsNode, ManuscriptNode, ManuscriptTransaction, SupplementNode, SupplementsNode } from '@manuscripts/transform';
2
2
  export declare const insertAwardsNode: (tr: ManuscriptTransaction) => {
3
3
  node: import("prosemirror-model").Node;
4
4
  pos: number;
@@ -6,7 +6,7 @@ export declare const insertAwardsNode: (tr: ManuscriptTransaction) => {
6
6
  node: AwardsNode;
7
7
  pos: number;
8
8
  };
9
- export declare const insertSupplementsNode: (tr: ManuscriptTransaction) => {
9
+ export declare const upsertSupplementsSection: (tr: ManuscriptTransaction, supplement: SupplementNode) => {
10
10
  node: import("prosemirror-model").Node;
11
11
  pos: number;
12
12
  } | {
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "3.6.9";
1
+ export declare const VERSION = "3.6.11";
2
2
  export declare const MATHJAX_VERSION = "3.2.2";
@@ -0,0 +1,37 @@
1
+ /*!
2
+ * © 2025 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { SupplementNode } from '@manuscripts/transform';
17
+ import { Trackable } from '../types';
18
+ import { BaseNodeView } from './base_node_view';
19
+ export declare class SupplementView extends BaseNodeView<Trackable<SupplementNode>> {
20
+ private supplementInfoEl;
21
+ private static currentDragSupplementId;
22
+ private dragIcon;
23
+ ignoreMutation: () => boolean;
24
+ initialise(): void;
25
+ createElement: () => void;
26
+ updateContents(): void;
27
+ private getDropSide;
28
+ private noActualMove;
29
+ private handleDragStart;
30
+ private setupDragAndDrop;
31
+ private moveSupplement;
32
+ private addFileInfo;
33
+ private refreshFileInfo;
34
+ private addDragIcon;
35
+ }
36
+ declare const _default: (props: import("../configs/ManuscriptsEditor").EditorProps, dispatch?: import("..").Dispatch) => import("../types").NodeViewCreator<SupplementView>;
37
+ export default _default;
@@ -0,0 +1,18 @@
1
+ /*!
2
+ * © 2025 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { SupplementView } from './supplement';
17
+ declare const _default: (props: import("../configs/ManuscriptsEditor").EditorProps, dispatch?: import("..").Dispatch) => import("../types").NodeViewCreator<SupplementView>;
18
+ export default _default;
@@ -0,0 +1,27 @@
1
+ /*!
2
+ * © 2025 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { SupplementsNode } from '@manuscripts/transform';
17
+ import { Trackable } from '../types';
18
+ import BlockView from './block_view';
19
+ export declare class SupplementsView extends BlockView<Trackable<SupplementsNode>> {
20
+ private collapsed;
21
+ private toggleButton;
22
+ ignoreMutation: () => boolean;
23
+ createElement: () => void;
24
+ private toggleContent;
25
+ }
26
+ declare const _default: (props: import("../configs/ManuscriptsEditor").EditorProps, dispatch?: import("..").Dispatch) => import("../types").NodeViewCreator<SupplementsView>;
27
+ export default _default;
@@ -0,0 +1,44 @@
1
+ /*!
2
+ * © 2025 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { SupplementsView } from './supplements';
17
+ declare const _default: (props: import("../configs/ManuscriptsEditor").EditorProps, dispatch?: import("..").Dispatch) => import("../types").NodeViewCreator<{
18
+ gutterButtons(): HTMLElement[];
19
+ actionGutterButtons(): never[];
20
+ createAddButton(): HTMLAnchorElement | null;
21
+ createEditButton(): HTMLElement | null;
22
+ createMenu: () => import("../lib/context-menu").ContextMenu;
23
+ initialise(): void;
24
+ updateContents(): void;
25
+ handleTrackChanges(): void;
26
+ updateClasses(): void;
27
+ updatePlaceholder(): void;
28
+ createElement(): void;
29
+ createDOM(): void;
30
+ gutter: Record<string, HTMLElement>;
31
+ createGutter(className: string, buttons: HTMLElement[]): void;
32
+ dom: HTMLElement;
33
+ contentDOM?: HTMLElement;
34
+ elementType: string;
35
+ readonly props: import("../configs/ManuscriptsEditor").EditorProps;
36
+ node: import("prosemirror-model").Node;
37
+ readonly view: import("@manuscripts/transform").ManuscriptEditorView;
38
+ readonly getPos: () => number;
39
+ update(newNode: import("@manuscripts/transform").ManuscriptNode): boolean;
40
+ selectNode(): void;
41
+ deselectNode(): void;
42
+ destroy(): void;
43
+ } & SupplementsView>;
44
+ export default _default;
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": "3.6.9",
4
+ "version": "3.6.11",
5
5
  "repository": "github:Atypon-OpenSource/manuscripts-body-editor",
6
6
  "license": "Apache-2.0",
7
7
  "main": "dist/cjs",
@@ -41,7 +41,7 @@
41
41
  "@manuscripts/json-schema": "2.2.12",
42
42
  "@manuscripts/style-guide": "3.3.4",
43
43
  "@manuscripts/track-changes-plugin": "2.1.0",
44
- "@manuscripts/transform": "4.3.5",
44
+ "@manuscripts/transform": "4.3.6",
45
45
  "@popperjs/core": "2.11.8",
46
46
  "citeproc": "2.4.63",
47
47
  "codemirror": "5.65.19",
@@ -840,7 +840,9 @@ span.comment-marker {
840
840
 
841
841
  .selected-suggestion:not(.block-container):not(.graphical-abstract):not(
842
842
  .keywords
843
- ):not(figure):not(figure .equation):not(.inconsistency-highlight),
843
+ ):not(figure):not(figure .equation):not(.inconsistency-highlight):not(
844
+ .supplement-item:is([data-track-op='move'])
845
+ ),
844
846
  .footnote-marker-selected {
845
847
  border-width: 2px 0 2px 0 !important;
846
848
  border-style: solid !important;
@@ -1067,13 +1069,19 @@ figure.block:has(.equation.selected-suggestion) {
1067
1069
  .tracking-visible
1068
1070
  .selected-suggestion:is([data-track-op='move'], [data-track-op='structure'])
1069
1071
  .block,
1070
- .block:has(
1072
+ .block:not(.supplements-content):has(
1071
1073
  figure.selected-suggestion,
1072
1074
  [data-track-op='move'][data-track-status='pending']
1073
1075
  ) {
1074
1076
  box-shadow: inset 3px 0 0 var(--updated-border-color);
1075
1077
  }
1076
1078
 
1079
+ .supplements-content.block:has(
1080
+ [data-track-op='move'][data-track-status='pending']
1081
+ ) {
1082
+ border-left: 3px solid var(--updated-border-color) !important;
1083
+ }
1084
+
1077
1085
  .tracking-visible
1078
1086
  .selected-suggestion[data-track-op='set_attrs']
1079
1087
  .block:not(.trans-abstract),
@@ -1693,7 +1701,7 @@ th:hover > .table-context-menu-button,
1693
1701
  left: 93%;
1694
1702
  }
1695
1703
 
1696
- .block-hero_image {
1704
+ .block-hero_image, .block-supplements {
1697
1705
  margin-bottom: 30px;
1698
1706
  }
1699
1707
 
@@ -1703,6 +1711,7 @@ th:hover > .table-context-menu-button,
1703
1711
  border-radius: 4px;
1704
1712
  background: #ffffff;
1705
1713
  padding: 0 !important;
1714
+ width: 100%;
1706
1715
  }
1707
1716
 
1708
1717
  .ProseMirror div.backmatter:has(+ .block-container.block-hero_image)::after {
@@ -1744,7 +1753,8 @@ th:hover > .table-context-menu-button,
1744
1753
 
1745
1754
  .ProseMirror .block-image_element .block:focus-visible,
1746
1755
  .ProseMirror .block-figure_element .block:focus-visible,
1747
- .ProseMirror .block-embed .block:focus-visible {
1756
+ .ProseMirror .block-embed .block:focus-visible,
1757
+ .ProseMirror .supplement-caption:focus-visible {
1748
1758
  outline: none;
1749
1759
  }
1750
1760
 
package/styles/Editor.css CHANGED
@@ -1134,3 +1134,162 @@
1134
1134
  .highlight {
1135
1135
  background-color: #ffeebf !important;
1136
1136
  }
1137
+
1138
+ .ProseMirror .supplement-item {
1139
+ position: relative;
1140
+ padding: 12px 24px;
1141
+ border-bottom: 1px solid #e2e2e2;
1142
+ }
1143
+
1144
+ .ProseMirror .supplement-item:last-child {
1145
+ border-bottom: none;
1146
+ }
1147
+
1148
+ .ProseMirror .supplement-item figcaption {
1149
+ text-align: left;
1150
+ margin-top: 0;
1151
+ }
1152
+
1153
+ .ProseMirror .supplement-item .caption-title.empty-node::before {
1154
+ content: 'Insert caption title...';
1155
+ color: #c9c9c9;
1156
+ font-style: italic;
1157
+ }
1158
+
1159
+ .ProseMirror .supplement-item .caption-description.empty-node::before {
1160
+ content: 'Insert caption...';
1161
+ color: #c9c9c9;
1162
+ font-style: italic;
1163
+ }
1164
+
1165
+ .ProseMirror .supplement-file-info {
1166
+ display: flex;
1167
+ align-items: center;
1168
+ margin-top: 8px;
1169
+ gap: 4px;
1170
+ }
1171
+
1172
+ .ProseMirror .supplement-file-icon {
1173
+ display: flex;
1174
+ align-items: center;
1175
+ width: 14px;
1176
+ height: 16px;
1177
+ }
1178
+
1179
+ .ProseMirror .supplement-file-name {
1180
+ font-size: 14px;
1181
+ }
1182
+
1183
+
1184
+ .ProseMirror .supplements-toggle-btn {
1185
+ background: none;
1186
+ border: none;
1187
+ cursor: pointer;
1188
+ padding: 0;
1189
+ display: flex;
1190
+ align-items: center;
1191
+ justify-content: center;
1192
+ transition: opacity 0.2s ease;
1193
+ position: absolute;
1194
+ top: 16px;
1195
+ right: 65px;
1196
+ z-index: 10;
1197
+ }
1198
+
1199
+
1200
+ .ProseMirror .supplements-toggle-btn svg {
1201
+ width: 16px;
1202
+ height: 9px;
1203
+ }
1204
+
1205
+ .ProseMirror .supplements-toggle-btn.collapsed svg {
1206
+ transform: rotate(180deg);
1207
+ }
1208
+
1209
+
1210
+ .ProseMirror .supplements-content {
1211
+ border: 1px solid #c9c9c9;
1212
+ border-radius: 4px;
1213
+ background: white;
1214
+ padding: 0 !important;
1215
+ width: 100%;
1216
+ }
1217
+
1218
+ /* Make section title look like a horizontal panel header */
1219
+ .ProseMirror .supplements-content .block-section_title {
1220
+ border-top: 1px solid #c9c9c9;
1221
+ border-bottom: 1px solid #c9c9c9;
1222
+ display: block !important;
1223
+ }
1224
+
1225
+ .ProseMirror .supplements-content .block-section_title .block-gutter {
1226
+ display: none;
1227
+ }
1228
+
1229
+ .ProseMirror .supplements-content .block-section_title .action-gutter {
1230
+ display: none;
1231
+ }
1232
+
1233
+ .ProseMirror .supplements-content .block-section_title h1 {
1234
+ background-color: #f2f2f2;
1235
+ padding: 8px 12px !important;
1236
+ font-size: 14px;
1237
+ display: flex;
1238
+ margin-top: -1px;
1239
+ color: #6e6e6e !important;
1240
+ }
1241
+
1242
+ .ProseMirror .supplements-content .block-section_title h1.empty-node span {
1243
+ color: #6e6e6e !important;
1244
+ font-style: normal;
1245
+ }
1246
+
1247
+ /* Horizontal line before supplements block */
1248
+ .ProseMirror div.backmatter:has(+ .block-container.block-supplements)::after {
1249
+ content: '';
1250
+ display: block;
1251
+ border-bottom: 1px solid #e2e2e2;
1252
+ margin: 0 35pt 32px 35pt;
1253
+ }
1254
+
1255
+ .ProseMirror .supplement-item.drop-target-above,
1256
+ .ProseMirror .supplement-item.drop-target-below {
1257
+ border: 2px dotted #20aedf !important;
1258
+ }
1259
+
1260
+ .ProseMirror .supplement-item.dragging {
1261
+ background-color: #F2F2F2 !important;
1262
+ opacity: 0.3;
1263
+ z-index: 1000;
1264
+ }
1265
+
1266
+ .ProseMirror .supplement-item:hover {
1267
+ background-color: #F2F2F2 !important;
1268
+ cursor: move;
1269
+ }
1270
+
1271
+ .ProseMirror .supplement-item:hover figcaption {
1272
+ background-color: #F2F2F2 !important;
1273
+ }
1274
+
1275
+ .ProseMirror .supplement-item .drag-icon {
1276
+ position: absolute;
1277
+ top: 50%;
1278
+ left: 0;
1279
+ transform: translateY(-50%);
1280
+ width: 16px;
1281
+ height: 16px;
1282
+ cursor: grab;
1283
+ opacity: 0;
1284
+ transition: opacity 0.2s;
1285
+ z-index: 5;
1286
+ pointer-events: auto;
1287
+ }
1288
+
1289
+ .ProseMirror .supplement-item:hover .drag-icon {
1290
+ opacity: 1;
1291
+ }
1292
+
1293
+ .ProseMirror .supplement-item .drag-icon:active {
1294
+ cursor: grabbing;
1295
+ }