@manuscripts/body-editor 2.8.84 → 2.8.85

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.
@@ -16,7 +16,7 @@
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.addRows = exports.addInlineComment = exports.addNodeComment = exports.isCommentingAllowed = 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.insertAward = exports.insertAffiliation = exports.insertContributors = exports.insertGraphicalAbstract = exports.insertBackmatterSection = exports.insertAbstractSection = exports.insertSection = exports.insertBoxElement = exports.insertInlineFootnote = exports.insertFootnotesElement = exports.insertTableElementFooter = exports.insertInlineEquation = exports.insertCrossReference = exports.insertInlineCitation = exports.insertLink = exports.insertSectionLabel = exports.findPosBeforeFirstSubsection = exports.insertBreak = exports.deleteBlock = exports.insertBlock = exports.insertAttachment = exports.insertSupplement = exports.insertTable = exports.insertFigure = exports.insertGeneralTableFootnote = exports.insertInlineTableFootnote = exports.insertEmbed = exports.createBlock = exports.createSelection = exports.canInsert = exports.blockActive = exports.isNodeSelection = exports.markActive = exports.addToStart = void 0;
19
- exports.activateSearchReplace = exports.activateSearch = exports.autoComplete = exports.addColumns = exports.addHeaderRow = void 0;
19
+ exports.insertHeroImage = exports.activateSearchReplace = exports.activateSearch = exports.autoComplete = exports.addColumns = exports.addHeaderRow = void 0;
20
20
  const json_schema_1 = require("@manuscripts/json-schema");
21
21
  const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
22
22
  const transform_1 = require("@manuscripts/transform");
@@ -160,6 +160,9 @@ const createBlock = (nodeType, position, state, dispatch, attrs) => {
160
160
  case transform_1.schema.nodes.image_element:
161
161
  node = createImageElement(attrs);
162
162
  break;
163
+ case transform_1.schema.nodes.hero_image:
164
+ node = createHeroImage(attrs);
165
+ break;
163
166
  case transform_1.schema.nodes.listing_element:
164
167
  node = transform_1.schema.nodes.listing_element.create({}, [
165
168
  transform_1.schema.nodes.listing.create(),
@@ -1077,7 +1080,8 @@ const isCommentingAllowed = (type) => type === transform_1.schema.nodes.title ||
1077
1080
  type === transform_1.schema.nodes.embed ||
1078
1081
  type === transform_1.schema.nodes.affiliations ||
1079
1082
  type === transform_1.schema.nodes.contributors ||
1080
- type === transform_1.schema.nodes.image_element;
1083
+ type === transform_1.schema.nodes.image_element ||
1084
+ type === transform_1.schema.nodes.hero_image;
1081
1085
  exports.isCommentingAllowed = isCommentingAllowed;
1082
1086
  const addNodeComment = (node, state, dispatch) => {
1083
1087
  if (!(0, exports.isCommentingAllowed)(node.type)) {
@@ -1235,3 +1239,19 @@ const activateSearchReplace = (state, dispatch) => {
1235
1239
  return true;
1236
1240
  };
1237
1241
  exports.activateSearchReplace = activateSearchReplace;
1242
+ const createHeroImage = (attrs) => transform_1.schema.nodes.hero_image.create(Object.assign(Object.assign({}, attrs), { id: (0, transform_1.generateNodeID)(transform_1.schema.nodes.hero_image) }), [
1243
+ transform_1.schema.nodes.figure.create(),
1244
+ transform_1.schema.nodes.alt_text.create(),
1245
+ transform_1.schema.nodes.long_desc.create(),
1246
+ ]);
1247
+ const insertHeroImage = () => (state, dispatch, view) => {
1248
+ if ((0, utils_1.getChildOfType)(state.doc, transform_1.schema.nodes.hero_image, true)) {
1249
+ return false;
1250
+ }
1251
+ const backmatter = (0, doc_1.findBackmatter)(state.doc);
1252
+ const position = backmatter.pos + backmatter.node.content.size + 1;
1253
+ view === null || view === void 0 ? void 0 : view.focus();
1254
+ (0, exports.createBlock)(transform_1.schema.nodes.hero_image, position, state, dispatch);
1255
+ return true;
1256
+ };
1257
+ exports.insertHeroImage = insertHeroImage;
@@ -47,7 +47,8 @@ const excludedTypes = [
47
47
  transform_1.schema.nodes.title,
48
48
  transform_1.schema.nodes.alt_titles,
49
49
  transform_1.schema.nodes.alt_title,
50
- transform_1.schema.nodes.hero_image,
50
+ transform_1.schema.nodes.alt_text,
51
+ transform_1.schema.nodes.long_desc,
51
52
  ];
52
53
  const childrenExcludedTypes = [
53
54
  transform_1.schema.nodes.pullquote_element,
@@ -174,7 +175,8 @@ const DraggableTree = ({ tree, view, depth, can, }) => {
174
175
  }),
175
176
  });
176
177
  const isDeletedItem = (0, track_changes_utils_1.isDeleted)(node);
177
- const isTop = isManuscriptNode(parent);
178
+ const isHeroImage = (0, transform_1.isHeroImageNode)(node);
179
+ const isTop = isManuscriptNode(parent) && !isHeroImage;
178
180
  const handleContextMenu = (e) => {
179
181
  e.preventDefault();
180
182
  e.stopPropagation();
@@ -191,8 +193,9 @@ const DraggableTree = ({ tree, view, depth, can, }) => {
191
193
  const dragClass = isDragging ? 'dragging' : '';
192
194
  const dropClass = isOver && dropSide ? `drop-${dropSide}` : '';
193
195
  const deletedClass = isDeletedItem ? 'deleted' : '';
194
- return (react_1.default.createElement(Outline_1.Outline, { ref: ref, className: `${dragClass} ${dropClass} ${deletedClass}` },
195
- !isTop && node.type.name != 'manuscript' && (react_1.default.createElement(Outline_1.OutlineItem, { depth: depth, onContextMenu: handleContextMenu },
196
+ const heroImageClass = isHeroImage ? 'hero-image' : '';
197
+ return (react_1.default.createElement(Outline_1.Outline, { ref: ref, className: `${dragClass} ${dropClass} ${deletedClass} ${heroImageClass}` },
198
+ !isTop && node.type.name != 'manuscript' && (react_1.default.createElement(Outline_1.OutlineItem, { depth: isHeroImage ? 1 : depth, onContextMenu: handleContextMenu },
196
199
  items.length ? (react_1.default.createElement(Outline_1.OutlineItemArrow, { onClick: toggleOpen }, isOpen ? react_1.default.createElement(style_guide_1.TriangleExpandedIcon, null) : react_1.default.createElement(style_guide_1.TriangleCollapsedIcon, null))) : (react_1.default.createElement(Outline_1.OutlineItemNoArrow, null)),
197
200
  react_1.default.createElement(Outline_1.OutlineItemLink, { to: `#${node.attrs.id}` },
198
201
  react_1.default.createElement(Outline_1.OutlineItemIcon, null, (0, node_type_icons_1.nodeTypeIcon)(node.type)),
@@ -119,5 +119,11 @@ exports.Outline = styled_components_1.default.div `
119
119
  & .subtree.collapsed {
120
120
  display: none;
121
121
  }
122
+
123
+ & .hero-image {
124
+ margin-top: 1rem;
125
+ padding-top: 0.5rem;
126
+ border-top: 1px dashed #ddd;
127
+ }
122
128
  `;
123
129
  exports.OutlineItemPlaceholder = styled_components_1.default.span ``;
@@ -25,6 +25,7 @@ const figure_element_editable_1 = __importDefault(require("../views/figure_eleme
25
25
  const footnote_1 = __importDefault(require("../views/footnote"));
26
26
  const footnotes_element_1 = __importDefault(require("../views/footnotes_element"));
27
27
  const general_table_footnote_1 = __importDefault(require("../views/general_table_footnote"));
28
+ const hero_image_editable_1 = __importDefault(require("../views/hero_image_editable"));
28
29
  const inline_equation_editable_1 = __importDefault(require("../views/inline_equation_editable"));
29
30
  const inline_footnote_editable_1 = __importDefault(require("../views/inline_footnote_editable"));
30
31
  const keyword_1 = __importDefault(require("../views/keyword"));
@@ -92,6 +93,6 @@ exports.default = (props, dispatch) => {
92
93
  award: (0, award_1.default)(props, dispatch),
93
94
  long_desc: (0, accessibility_element_1.default)(props, dispatch),
94
95
  alt_text: (0, accessibility_element_1.default)(props, dispatch),
95
- hero_image: (0, empty_1.default)('hero_image'),
96
+ hero_image: (0, hero_image_editable_1.default)(props, dispatch),
96
97
  };
97
98
  };
package/dist/cjs/icons.js CHANGED
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.plusIcon = exports.lockIcon = exports.scrollIcon = exports.sectionCategoryIcon = exports.editIcon = exports.deleteIcon = exports.alertIcon = exports.arrowDown = void 0;
3
+ exports.plusIcon = exports.lockIcon = exports.scrollIcon = exports.sectionCategoryIcon = exports.editIcon = exports.deleteIcon = exports.alertIcon = exports.arrowUp = exports.arrowDown = void 0;
4
4
  const style_guide_1 = require("@manuscripts/style-guide");
5
5
  const react_1 = require("react");
6
6
  const server_1 = require("react-dom/server");
7
7
  const renderIcon = (c) => (0, server_1.renderToStaticMarkup)((0, react_1.createElement)(c));
8
8
  exports.arrowDown = renderIcon(style_guide_1.ArrowDownCircleIcon);
9
+ exports.arrowUp = renderIcon(style_guide_1.ArrowUpIcon);
9
10
  exports.alertIcon = renderIcon(style_guide_1.AlertIcon);
10
11
  exports.deleteIcon = renderIcon(style_guide_1.DeleteIcon);
11
12
  exports.editIcon = (0, server_1.renderToStaticMarkup)((0, react_1.createElement)(style_guide_1.EditIcon));
@@ -8,7 +8,11 @@ const MISSING_FILE = {
8
8
  id: '',
9
9
  name: '',
10
10
  };
11
- const figureTypes = [transform_1.schema.nodes.figure_element, transform_1.schema.nodes.image_element];
11
+ const figureTypes = [
12
+ transform_1.schema.nodes.figure_element,
13
+ transform_1.schema.nodes.image_element,
14
+ transform_1.schema.nodes.hero_image,
15
+ ];
12
16
  const groupFiles = (doc, files) => {
13
17
  const fileMap = new Map(files.map((f) => [f.id, f]));
14
18
  const figures = [];
package/dist/cjs/menus.js CHANGED
@@ -237,6 +237,12 @@ const getEditorMenus = (editor) => {
237
237
  isCommandValid((0, commands_1.canInsert)(transform_1.schema.nodes.image_element)),
238
238
  run: doCommand((0, commands_1.insertBlock)(transform_1.schema.nodes.image_element)),
239
239
  },
240
+ {
241
+ id: 'insert-hero-image',
242
+ label: 'Hero Image',
243
+ isEnabled: (0, utils_1.isEditAllowed)(state) && isCommandValid((0, commands_1.insertHeroImage)()),
244
+ run: doCommand((0, commands_1.insertHeroImage)()),
245
+ },
240
246
  {
241
247
  id: 'insert-table-element',
242
248
  label: 'Table',
@@ -38,6 +38,7 @@ const icons = new Map([
38
38
  [nodes.graphical_abstract_section, style_guide_1.OutlineSectionIcon],
39
39
  [nodes.footnotes_section, style_guide_1.OutlineSectionIcon],
40
40
  [nodes.image_element, OutlineImageIcon],
41
+ [nodes.hero_image, OutlineImageIcon],
41
42
  ]);
42
43
  const nodeTypeIcon = (nodeType, listType) => {
43
44
  if (nodeType === transform_1.schema.nodes.list) {
@@ -187,6 +187,7 @@ const getDecorationPos = (node, pos) => {
187
187
  case transform_1.schema.nodes.paragraph:
188
188
  case transform_1.schema.nodes.embed:
189
189
  case transform_1.schema.nodes.contributors:
190
+ case transform_1.schema.nodes.hero_image:
190
191
  return pos;
191
192
  case transform_1.schema.nodes.keywords:
192
193
  return pos + 2;
@@ -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.8.84';
4
+ exports.VERSION = '2.8.85';
5
5
  exports.MATHJAX_VERSION = '3.2.2';
@@ -0,0 +1,64 @@
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.HeroImageView = 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 HeroImageView extends block_view_1.default {
26
+ constructor() {
27
+ super(...arguments);
28
+ this.collapsed = false;
29
+ this.ignoreMutation = () => true;
30
+ this.createElement = () => {
31
+ this.container = document.createElement('div');
32
+ this.container.classList.add('block', 'hero-image-container');
33
+ this.dom.appendChild(this.container);
34
+ this.container.appendChild(this.createPanel());
35
+ this.contentDOM = document.createElement('figure');
36
+ this.contentDOM.classList.add('figure-block', 'hero-image-figure');
37
+ this.contentDOM.setAttribute('id', this.node.attrs.id);
38
+ this.container.appendChild(this.contentDOM);
39
+ };
40
+ }
41
+ createPanel() {
42
+ const panel = document.createElement('div');
43
+ panel.classList.add('hero-image-panel');
44
+ const label = document.createElement('span');
45
+ label.textContent = 'Hero image';
46
+ label.contentEditable = 'false';
47
+ const heroImageToggleBtn = document.createElement('button');
48
+ heroImageToggleBtn.classList.add('hero-image-toggle-btn', 'button-reset');
49
+ heroImageToggleBtn.innerHTML = icons_1.arrowUp;
50
+ heroImageToggleBtn.classList.toggle('collapsed', this.collapsed);
51
+ heroImageToggleBtn.onclick = () => {
52
+ this.collapsed = !this.collapsed;
53
+ if (this.contentDOM) {
54
+ this.contentDOM.style.display = this.collapsed ? 'none' : '';
55
+ }
56
+ heroImageToggleBtn.classList.toggle('collapsed', this.collapsed);
57
+ };
58
+ panel.appendChild(label);
59
+ panel.appendChild(heroImageToggleBtn);
60
+ return panel;
61
+ }
62
+ }
63
+ exports.HeroImageView = HeroImageView;
64
+ exports.default = (0, creators_1.createNodeView)(HeroImageView);
@@ -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 hero_image_1 = require("./hero_image");
21
+ exports.default = (0, creators_1.createEditableNodeView)((0, editable_block_1.EditableBlock)(hero_image_1.HeroImageView));
@@ -150,6 +150,9 @@ export const createBlock = (nodeType, position, state, dispatch, attrs) => {
150
150
  case schema.nodes.image_element:
151
151
  node = createImageElement(attrs);
152
152
  break;
153
+ case schema.nodes.hero_image:
154
+ node = createHeroImage(attrs);
155
+ break;
153
156
  case schema.nodes.listing_element:
154
157
  node = schema.nodes.listing_element.create({}, [
155
158
  schema.nodes.listing.create(),
@@ -1027,7 +1030,8 @@ export const isCommentingAllowed = (type) => type === schema.nodes.title ||
1027
1030
  type === schema.nodes.embed ||
1028
1031
  type === schema.nodes.affiliations ||
1029
1032
  type === schema.nodes.contributors ||
1030
- type === schema.nodes.image_element;
1033
+ type === schema.nodes.image_element ||
1034
+ type === schema.nodes.hero_image;
1031
1035
  export const addNodeComment = (node, state, dispatch) => {
1032
1036
  if (!isCommentingAllowed(node.type)) {
1033
1037
  return false;
@@ -1176,3 +1180,18 @@ export const activateSearchReplace = (state, dispatch) => {
1176
1180
  dispatch && dispatch(tr);
1177
1181
  return true;
1178
1182
  };
1183
+ const createHeroImage = (attrs) => schema.nodes.hero_image.create(Object.assign(Object.assign({}, attrs), { id: generateNodeID(schema.nodes.hero_image) }), [
1184
+ schema.nodes.figure.create(),
1185
+ schema.nodes.alt_text.create(),
1186
+ schema.nodes.long_desc.create(),
1187
+ ]);
1188
+ export const insertHeroImage = () => (state, dispatch, view) => {
1189
+ if (getChildOfType(state.doc, schema.nodes.hero_image, true)) {
1190
+ return false;
1191
+ }
1192
+ const backmatter = findBackmatter(state.doc);
1193
+ const position = backmatter.pos + backmatter.node.content.size + 1;
1194
+ view === null || view === void 0 ? void 0 : view.focus();
1195
+ createBlock(schema.nodes.hero_image, position, state, dispatch);
1196
+ return true;
1197
+ };
@@ -1,5 +1,5 @@
1
1
  import { TriangleCollapsedIcon, TriangleExpandedIcon, } from '@manuscripts/style-guide';
2
- import { isElementNodeType, nodeTitle, nodeTitlePlaceholder, schema, } from '@manuscripts/transform';
2
+ import { isElementNodeType, isHeroImageNode, nodeTitle, nodeTitlePlaceholder, schema, } from '@manuscripts/transform';
3
3
  import { Fragment } from 'prosemirror-model';
4
4
  import React, { useRef, useState } from 'react';
5
5
  import { useDrag, useDrop } from 'react-dnd';
@@ -21,7 +21,8 @@ const excludedTypes = [
21
21
  schema.nodes.title,
22
22
  schema.nodes.alt_titles,
23
23
  schema.nodes.alt_title,
24
- schema.nodes.hero_image,
24
+ schema.nodes.alt_text,
25
+ schema.nodes.long_desc,
25
26
  ];
26
27
  const childrenExcludedTypes = [
27
28
  schema.nodes.pullquote_element,
@@ -147,7 +148,8 @@ export const DraggableTree = ({ tree, view, depth, can, }) => {
147
148
  }),
148
149
  });
149
150
  const isDeletedItem = isDeleted(node);
150
- const isTop = isManuscriptNode(parent);
151
+ const isHeroImage = isHeroImageNode(node);
152
+ const isTop = isManuscriptNode(parent) && !isHeroImage;
151
153
  const handleContextMenu = (e) => {
152
154
  e.preventDefault();
153
155
  e.stopPropagation();
@@ -164,8 +166,9 @@ export const DraggableTree = ({ tree, view, depth, can, }) => {
164
166
  const dragClass = isDragging ? 'dragging' : '';
165
167
  const dropClass = isOver && dropSide ? `drop-${dropSide}` : '';
166
168
  const deletedClass = isDeletedItem ? 'deleted' : '';
167
- return (React.createElement(Outline, { ref: ref, className: `${dragClass} ${dropClass} ${deletedClass}` },
168
- !isTop && node.type.name != 'manuscript' && (React.createElement(OutlineItem, { depth: depth, onContextMenu: handleContextMenu },
169
+ const heroImageClass = isHeroImage ? 'hero-image' : '';
170
+ return (React.createElement(Outline, { ref: ref, className: `${dragClass} ${dropClass} ${deletedClass} ${heroImageClass}` },
171
+ !isTop && node.type.name != 'manuscript' && (React.createElement(OutlineItem, { depth: isHeroImage ? 1 : depth, onContextMenu: handleContextMenu },
169
172
  items.length ? (React.createElement(OutlineItemArrow, { onClick: toggleOpen }, isOpen ? React.createElement(TriangleExpandedIcon, null) : React.createElement(TriangleCollapsedIcon, null))) : (React.createElement(OutlineItemNoArrow, null)),
170
173
  React.createElement(OutlineItemLink, { to: `#${node.attrs.id}` },
171
174
  React.createElement(OutlineItemIcon, null, nodeTypeIcon(node.type)),
@@ -113,5 +113,11 @@ export const Outline = styled.div `
113
113
  & .subtree.collapsed {
114
114
  display: none;
115
115
  }
116
+
117
+ & .hero-image {
118
+ margin-top: 1rem;
119
+ padding-top: 0.5rem;
120
+ border-top: 1px dashed #ddd;
121
+ }
116
122
  `;
117
123
  export const OutlineItemPlaceholder = styled.span ``;
@@ -20,6 +20,7 @@ import figureElement from '../views/figure_element_editable';
20
20
  import footnote from '../views/footnote';
21
21
  import footnotesElement from '../views/footnotes_element';
22
22
  import generalTableFootnote from '../views/general_table_footnote';
23
+ import heroImage from '../views/hero_image_editable';
23
24
  import inlineEquation from '../views/inline_equation_editable';
24
25
  import inlineFootnote from '../views/inline_footnote_editable';
25
26
  import keyword from '../views/keyword';
@@ -87,6 +88,6 @@ export default (props, dispatch) => {
87
88
  award: award(props, dispatch),
88
89
  long_desc: accessibilityElement(props, dispatch),
89
90
  alt_text: accessibilityElement(props, dispatch),
90
- hero_image: empty('hero_image'),
91
+ hero_image: heroImage(props, dispatch),
91
92
  };
92
93
  };
package/dist/es/icons.js CHANGED
@@ -1,8 +1,9 @@
1
- import { AlertIcon, ArrowDownCircleIcon, DeleteIcon, EditIcon, LockIcon, PlusIcon, ScrollIcon, SectionCategoryIcon, } from '@manuscripts/style-guide';
1
+ import { AlertIcon, ArrowDownCircleIcon, ArrowUpIcon, DeleteIcon, EditIcon, LockIcon, PlusIcon, ScrollIcon, SectionCategoryIcon, } from '@manuscripts/style-guide';
2
2
  import { createElement } from 'react';
3
3
  import { renderToStaticMarkup } from 'react-dom/server';
4
4
  const renderIcon = (c) => renderToStaticMarkup(createElement(c));
5
5
  export const arrowDown = renderIcon(ArrowDownCircleIcon);
6
+ export const arrowUp = renderIcon(ArrowUpIcon);
6
7
  export const alertIcon = renderIcon(AlertIcon);
7
8
  export const deleteIcon = renderIcon(DeleteIcon);
8
9
  export const editIcon = renderToStaticMarkup(createElement(EditIcon));
@@ -5,7 +5,11 @@ const MISSING_FILE = {
5
5
  id: '',
6
6
  name: '',
7
7
  };
8
- const figureTypes = [schema.nodes.figure_element, schema.nodes.image_element];
8
+ const figureTypes = [
9
+ schema.nodes.figure_element,
10
+ schema.nodes.image_element,
11
+ schema.nodes.hero_image,
12
+ ];
9
13
  export const groupFiles = (doc, files) => {
10
14
  const fileMap = new Map(files.map((f) => [f.id, f]));
11
15
  const figures = [];
package/dist/es/menus.js CHANGED
@@ -16,7 +16,7 @@
16
16
  import { getGroupCategories, schema, } from '@manuscripts/transform';
17
17
  import { toggleMark } from 'prosemirror-commands';
18
18
  import { redo, undo } from 'prosemirror-history';
19
- import { activateSearchReplace, addInlineComment, blockActive, canInsert, insertAbstractSection, insertAffiliation, insertAward, insertBackmatterSection, insertBlock, insertBoxElement, insertContributors, insertCrossReference, insertGraphicalAbstract, insertInlineCitation, insertInlineEquation, insertInlineFootnote, insertKeywords, insertLink, insertList, insertSection, markActive, } from './commands';
19
+ import { activateSearchReplace, addInlineComment, blockActive, canInsert, insertAbstractSection, insertAffiliation, insertAward, insertBackmatterSection, insertBlock, insertBoxElement, insertContributors, insertCrossReference, insertGraphicalAbstract, insertHeroImage, insertInlineCitation, insertInlineEquation, insertInlineFootnote, insertKeywords, insertLink, insertList, insertSection, markActive, } from './commands';
20
20
  import { openEmbedDialog } from './components/toolbar/InsertEmbedDialog';
21
21
  import { openInsertTableDialog } from './components/toolbar/InsertTableDialog';
22
22
  import { ListMenuItem } from './components/toolbar/ListMenuItem';
@@ -234,6 +234,12 @@ export const getEditorMenus = (editor) => {
234
234
  isCommandValid(canInsert(schema.nodes.image_element)),
235
235
  run: doCommand(insertBlock(schema.nodes.image_element)),
236
236
  },
237
+ {
238
+ id: 'insert-hero-image',
239
+ label: 'Hero Image',
240
+ isEnabled: isEditAllowed(state) && isCommandValid(insertHeroImage()),
241
+ run: doCommand(insertHeroImage()),
242
+ },
237
243
  {
238
244
  id: 'insert-table-element',
239
245
  label: 'Table',
@@ -32,6 +32,7 @@ const icons = new Map([
32
32
  [nodes.graphical_abstract_section, OutlineSectionIcon],
33
33
  [nodes.footnotes_section, OutlineSectionIcon],
34
34
  [nodes.image_element, OutlineImageIcon],
35
+ [nodes.hero_image, OutlineImageIcon],
35
36
  ]);
36
37
  export const nodeTypeIcon = (nodeType, listType) => {
37
38
  if (nodeType === schema.nodes.list) {
@@ -182,6 +182,7 @@ const getDecorationPos = (node, pos) => {
182
182
  case schema.nodes.paragraph:
183
183
  case schema.nodes.embed:
184
184
  case schema.nodes.contributors:
185
+ case schema.nodes.hero_image:
185
186
  return pos;
186
187
  case schema.nodes.keywords:
187
188
  return pos + 2;
@@ -1,2 +1,2 @@
1
- export const VERSION = '2.8.84';
1
+ export const VERSION = '2.8.85';
2
2
  export const MATHJAX_VERSION = '3.2.2';
@@ -0,0 +1,57 @@
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 HeroImageView extends BlockView {
20
+ constructor() {
21
+ super(...arguments);
22
+ this.collapsed = false;
23
+ this.ignoreMutation = () => true;
24
+ this.createElement = () => {
25
+ this.container = document.createElement('div');
26
+ this.container.classList.add('block', 'hero-image-container');
27
+ this.dom.appendChild(this.container);
28
+ this.container.appendChild(this.createPanel());
29
+ this.contentDOM = document.createElement('figure');
30
+ this.contentDOM.classList.add('figure-block', 'hero-image-figure');
31
+ this.contentDOM.setAttribute('id', this.node.attrs.id);
32
+ this.container.appendChild(this.contentDOM);
33
+ };
34
+ }
35
+ createPanel() {
36
+ const panel = document.createElement('div');
37
+ panel.classList.add('hero-image-panel');
38
+ const label = document.createElement('span');
39
+ label.textContent = 'Hero image';
40
+ label.contentEditable = 'false';
41
+ const heroImageToggleBtn = document.createElement('button');
42
+ heroImageToggleBtn.classList.add('hero-image-toggle-btn', 'button-reset');
43
+ heroImageToggleBtn.innerHTML = arrowUp;
44
+ heroImageToggleBtn.classList.toggle('collapsed', this.collapsed);
45
+ heroImageToggleBtn.onclick = () => {
46
+ this.collapsed = !this.collapsed;
47
+ if (this.contentDOM) {
48
+ this.contentDOM.style.display = this.collapsed ? 'none' : '';
49
+ }
50
+ heroImageToggleBtn.classList.toggle('collapsed', this.collapsed);
51
+ };
52
+ panel.appendChild(label);
53
+ panel.appendChild(heroImageToggleBtn);
54
+ return panel;
55
+ }
56
+ }
57
+ export default createNodeView(HeroImageView);
@@ -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 { HeroImageView } from './hero_image';
19
+ export default createEditableNodeView(EditableBlock(HeroImageView));
@@ -83,3 +83,4 @@ export declare const addColumns: (direction: 'right' | 'left') => (state: Editor
83
83
  export declare const autoComplete: (state: ManuscriptEditorState, dispatch?: Dispatch) => boolean;
84
84
  export declare const activateSearch: (state: ManuscriptEditorState, dispatch?: Dispatch) => boolean;
85
85
  export declare const activateSearchReplace: (state: ManuscriptEditorState, dispatch?: Dispatch) => boolean;
86
+ export declare const insertHeroImage: () => (state: ManuscriptEditorState, dispatch?: Dispatch, view?: EditorView) => boolean;
@@ -1,4 +1,5 @@
1
1
  export declare const arrowDown: string;
2
+ export declare const arrowUp: string;
2
3
  export declare const alertIcon: string;
3
4
  export declare const deleteIcon: string;
4
5
  export declare const editIcon: string;
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "2.8.84";
1
+ export declare const VERSION = "2.8.85";
2
2
  export declare const MATHJAX_VERSION = "3.2.2";
@@ -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 { FigureElementNode } from '@manuscripts/transform';
17
+ import { Trackable } from '../types';
18
+ import BlockView from './block_view';
19
+ export declare class HeroImageView extends BlockView<Trackable<FigureElementNode>> {
20
+ private container;
21
+ private collapsed;
22
+ ignoreMutation: () => boolean;
23
+ createElement: () => void;
24
+ createPanel(): HTMLDivElement;
25
+ }
26
+ declare const _default: (props: import("../configs/ManuscriptsEditor").EditorProps, dispatch?: import("..").Dispatch | undefined) => import("../types").NodeViewCreator<HeroImageView>;
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 { HeroImageView } from './hero_image';
17
+ declare const _default: (props: import("../configs/ManuscriptsEditor").EditorProps, dispatch?: import("..").Dispatch | undefined) => 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 | undefined;
34
+ elementType: string;
35
+ readonly props: import("../configs/ManuscriptsEditor").EditorProps;
36
+ node: import("prosemirror-model").Node;
37
+ readonly view: import("prosemirror-view").EditorView;
38
+ readonly getPos: () => number;
39
+ update(newNode: import("prosemirror-model").Node): boolean;
40
+ selectNode(): void;
41
+ deselectNode(): void;
42
+ destroy(): void;
43
+ } & HeroImageView>;
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": "2.8.84",
4
+ "version": "2.8.85",
5
5
  "repository": "github:Atypon-OpenSource/manuscripts-body-editor",
6
6
  "license": "Apache-2.0",
7
7
  "main": "dist/cjs",
@@ -33,7 +33,7 @@
33
33
  "@manuscripts/library": "1.3.14",
34
34
  "@manuscripts/style-guide": "2.1.13",
35
35
  "@manuscripts/track-changes-plugin": "1.10.8",
36
- "@manuscripts/transform": "3.0.67",
36
+ "@manuscripts/transform": "3.0.68",
37
37
  "@popperjs/core": "^2.11.8",
38
38
  "astrocite-eutils": "^0.16.4",
39
39
  "codemirror": "^5.58.1",
@@ -307,7 +307,8 @@
307
307
  }
308
308
 
309
309
  .comment-marker:has(+ .block-contributors),
310
- .comment-marker:has(+ .block-affiliations) {
310
+ .comment-marker:has(+ .block-affiliations),
311
+ .comment-marker:has(+ .block-hero_image) {
311
312
  height: 0;
312
313
  top: 0;
313
314
  right: 60px;
@@ -434,7 +435,8 @@ span.comment-marker {
434
435
  display: none;
435
436
  }
436
437
 
437
- .ProseMirror div.backmatter:has(:only-child.bibliography > .empty-node)::before {
438
+ .ProseMirror
439
+ div.backmatter:has(:only-child.bibliography > .empty-node)::before {
438
440
  border-bottom: none;
439
441
  }
440
442
 
@@ -1261,7 +1263,7 @@ th:hover > .table-context-menu-button,
1261
1263
  position: relative;
1262
1264
  pointer-events: none;
1263
1265
  user-select: none;
1264
- box-shadow: inset 49px 0 0 white, inset 53px 0 0 #6E6E6E;
1266
+ box-shadow: inset 49px 0 0 white, inset 53px 0 0 #6e6e6e;
1265
1267
  }
1266
1268
  .ProseMirror .non-editable .body-overlay,
1267
1269
  .ProseMirror .non-editable .figure-overlay {
@@ -1275,7 +1277,7 @@ th:hover > .table-context-menu-button,
1275
1277
  z-index: 10;
1276
1278
  }
1277
1279
  .ProseMirror .non-editable .body-overlay {
1278
- width: 52px
1280
+ width: 52px;
1279
1281
  }
1280
1282
  .ProseMirror .non-editable .block {
1281
1283
  opacity: 50%;
@@ -1335,7 +1337,9 @@ th:hover > .table-context-menu-button,
1335
1337
  transform: rotate(180deg);
1336
1338
  }
1337
1339
 
1338
- .ProseMirror .accessibility_element_expander_button_container .toggle-button-open {
1340
+ .ProseMirror
1341
+ .accessibility_element_expander_button_container
1342
+ .toggle-button-open {
1339
1343
  right: calc(100% - 6px);
1340
1344
  }
1341
1345
 
@@ -1344,6 +1348,49 @@ th:hover > .table-context-menu-button,
1344
1348
  bottom: 36px;
1345
1349
  }
1346
1350
 
1347
- .ProseMirror .block-table_element .accessibility_element_expander_button_container {
1351
+ .ProseMirror
1352
+ .block-table_element
1353
+ .accessibility_element_expander_button_container {
1348
1354
  left: 93%;
1349
1355
  }
1356
+
1357
+ .hero-image-container {
1358
+ border: 1px solid #c9c9c9;
1359
+ border-radius: 4px;
1360
+ background: white;
1361
+ padding: 0 !important;
1362
+ }
1363
+
1364
+ .ProseMirror div.backmatter:has(+ .block-container.block-hero_image)::after {
1365
+ content: '';
1366
+ display: block;
1367
+ border-bottom: 1px solid #e2e2e2;
1368
+ margin: 0 35pt 32px 35pt;
1369
+ }
1370
+
1371
+ .hero-image-panel {
1372
+ display: flex;
1373
+ justify-content: space-between;
1374
+ align-items: center;
1375
+ background-color: #f2f2f2;
1376
+ padding: 8px 12px;
1377
+ font-weight: bold;
1378
+ font-size: 14px;
1379
+ color: #6e6e6e;
1380
+ border-bottom: 1px solid #c9c9c9;
1381
+ }
1382
+
1383
+ .hero-image-container .figure-block {
1384
+ border: none !important;
1385
+ }
1386
+
1387
+ .hero-image-container .position-menu {
1388
+ display: none !important;
1389
+ }
1390
+ .hero-image-toggle-btn svg {
1391
+ width: 16px;
1392
+ height: 9px;
1393
+ }
1394
+ .hero-image-toggle-btn.collapsed svg {
1395
+ transform: rotate(180deg);
1396
+ }