@manuscripts/body-editor 3.13.10 → 3.13.12

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 (69) hide show
  1. package/dist/cjs/commands.js +21 -2
  2. package/dist/cjs/components/views/FigureDropdown.js +8 -0
  3. package/dist/cjs/configs/editor-views.js +6 -0
  4. package/dist/cjs/icons.js +2 -1
  5. package/dist/cjs/lib/files.js +6 -1
  6. package/dist/cjs/menus.js +8 -0
  7. package/dist/cjs/node-type-icons.js +4 -0
  8. package/dist/cjs/plugins/accessibility_element.js +2 -1
  9. package/dist/cjs/versions.js +1 -1
  10. package/dist/cjs/views/accessibility_element.js +7 -1
  11. package/dist/cjs/views/affiliations.js +5 -1
  12. package/dist/cjs/views/caption.js +0 -1
  13. package/dist/cjs/views/caption_title.js +0 -1
  14. package/dist/cjs/views/headshot_element.js +74 -0
  15. package/dist/cjs/views/headshot_element_editable.js +20 -0
  16. package/dist/cjs/views/headshot_grid.js +82 -0
  17. package/dist/cjs/views/headshot_grid_editable.js +21 -0
  18. package/dist/cjs/views/headshot_image_editable.js +79 -0
  19. package/dist/cjs/views/supplement.js +16 -1
  20. package/dist/es/commands.js +18 -0
  21. package/dist/es/components/views/FigureDropdown.js +8 -0
  22. package/dist/es/configs/editor-views.js +6 -0
  23. package/dist/es/icons.js +2 -1
  24. package/dist/es/lib/files.js +6 -1
  25. package/dist/es/menus.js +9 -1
  26. package/dist/es/node-type-icons.js +5 -1
  27. package/dist/es/plugins/accessibility_element.js +2 -1
  28. package/dist/es/versions.js +1 -1
  29. package/dist/es/views/accessibility_element.js +7 -1
  30. package/dist/es/views/affiliations.js +5 -1
  31. package/dist/es/views/caption.js +0 -1
  32. package/dist/es/views/caption_title.js +0 -1
  33. package/dist/es/views/headshot_element.js +70 -0
  34. package/dist/es/views/headshot_element_editable.js +18 -0
  35. package/dist/es/views/headshot_grid.js +75 -0
  36. package/dist/es/views/headshot_grid_editable.js +19 -0
  37. package/dist/es/views/headshot_image_editable.js +75 -0
  38. package/dist/es/views/supplement.js +16 -1
  39. package/dist/types/commands.d.ts +1 -0
  40. package/dist/types/icons.d.ts +1 -0
  41. package/dist/types/versions.d.ts +1 -1
  42. package/dist/types/views/headshot_element.d.ts +29 -0
  43. package/dist/types/views/headshot_element_editable.d.ts +18 -0
  44. package/dist/types/views/headshot_grid.d.ts +28 -0
  45. package/dist/types/views/headshot_grid_editable.d.ts +44 -0
  46. package/dist/types/views/headshot_image_editable.d.ts +28 -0
  47. package/dist/types/views/supplement.d.ts +1 -0
  48. package/package.json +2 -2
  49. package/src/commands.ts +27 -0
  50. package/src/components/views/FigureDropdown.tsx +11 -0
  51. package/src/configs/editor-views.ts +6 -0
  52. package/src/icons.ts +2 -0
  53. package/src/lib/files.ts +7 -1
  54. package/src/menus.tsx +10 -0
  55. package/src/node-type-icons.tsx +12 -0
  56. package/src/plugins/accessibility_element.ts +4 -1
  57. package/src/versions.ts +1 -1
  58. package/src/views/accessibility_element.ts +7 -1
  59. package/src/views/affiliations.ts +6 -1
  60. package/src/views/caption.ts +0 -1
  61. package/src/views/caption_title.ts +0 -1
  62. package/src/views/headshot_element.ts +98 -0
  63. package/src/views/headshot_element_editable.ts +20 -0
  64. package/src/views/headshot_grid.ts +98 -0
  65. package/src/views/headshot_grid_editable.ts +21 -0
  66. package/src/views/headshot_image_editable.ts +93 -0
  67. package/src/views/supplement.ts +15 -2
  68. package/styles/AdvancedEditor.css +169 -1
  69. package/styles/Editor.css +1 -1
@@ -15,8 +15,8 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.addInlineComment = exports.addNodeComment = exports.createAndFillTableElement = exports.selectAllIsolating = exports.ignoreAtomBlockNodeForward = exports.isAtEndOfTextBlock = exports.ignoreMetaNodeBackspaceCommand = exports.ignoreAtomBlockNodeBackward = exports.isTextSelection = exports.isAtStartOfTextBlock = exports.insertTransGraphicalAbstract = exports.insertTransAbstract = 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.insertEmbed = exports.insertFigure = exports.insertGeneralTableFootnote = exports.insertInlineTableFootnote = exports.createBlock = exports.createSelection = exports.canInsert = exports.blockActive = exports.isNodeSelection = exports.markActive = exports.addToStart = void 0;
19
- exports.paste = exports.copySelection = exports.exitEditorToContainer = exports.ignoreEnterInSubtitles = exports.insertHeroImage = exports.activateSearchReplace = exports.activateSearch = exports.autoComplete = exports.addColumns = exports.addHeaderRow = exports.addRows = void 0;
18
+ exports.addNodeComment = exports.createAndFillTableElement = exports.selectAllIsolating = exports.ignoreAtomBlockNodeForward = exports.isAtEndOfTextBlock = exports.ignoreMetaNodeBackspaceCommand = exports.ignoreAtomBlockNodeBackward = exports.isTextSelection = exports.isAtStartOfTextBlock = exports.insertTransGraphicalAbstract = exports.insertTransAbstract = exports.insertTOCSection = exports.insertBibliographySection = exports.insertList = exports.insertKeywords = exports.insertAward = exports.insertAffiliation = exports.insertContributors = exports.insertGraphicalAbstract = exports.insertBackmatterSection = exports.insertAbstractSection = exports.insertSection = exports.insertHeadshotGrid = 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.insertEmbed = exports.insertFigure = exports.insertGeneralTableFootnote = exports.insertInlineTableFootnote = exports.createBlock = exports.createSelection = exports.canInsert = exports.blockActive = exports.isNodeSelection = exports.markActive = exports.addToStart = void 0;
19
+ exports.paste = exports.copySelection = exports.exitEditorToContainer = exports.ignoreEnterInSubtitles = exports.insertHeroImage = exports.activateSearchReplace = exports.activateSearch = exports.autoComplete = exports.addColumns = exports.addHeaderRow = exports.addRows = exports.addInlineComment = void 0;
20
20
  const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
21
21
  const transform_1 = require("@manuscripts/transform");
22
22
  const prosemirror_model_1 = require("prosemirror-model");
@@ -598,6 +598,25 @@ const insertBoxElement = (state, dispatch) => {
598
598
  return true;
599
599
  };
600
600
  exports.insertBoxElement = insertBoxElement;
601
+ const insertHeadshotGrid = (state, dispatch) => {
602
+ const selection = state.selection;
603
+ const { nodes } = transform_1.schema;
604
+ const isBody = (0, prosemirror_utils_1.hasParentNodeOfType)(nodes.body)(selection);
605
+ if (!isBody) {
606
+ return false;
607
+ }
608
+ const position = findBlockInsertPosition(state);
609
+ if (position && dispatch) {
610
+ const headshotElement = transform_1.schema.nodes.headshot_element.createAndFill();
611
+ const node = nodes.headshot_grid.create({}, headshotElement);
612
+ const tr = state.tr.insert(position, node);
613
+ const headshotNamePosition = position + 2;
614
+ tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, headshotNamePosition));
615
+ dispatch(tr.scrollIntoView());
616
+ }
617
+ return true;
618
+ };
619
+ exports.insertHeadshotGrid = insertHeadshotGrid;
601
620
  const insertSection = (subsection = false) => (state, dispatch, view) => {
602
621
  const { nodes } = transform_1.schema;
603
622
  const $pos = state.selection.$from;
@@ -119,6 +119,14 @@ const FigureOptions = ({ can, getDoc, getFiles, onDownload, onUpload, onDetach,
119
119
  }
120
120
  }, [isOpen, container.classList]);
121
121
  useDropdownKeyboardNav(isOpen, dropdownRef, toggleOpen);
122
+ const hasAnyActions = !!showDownload ||
123
+ !!showUpload ||
124
+ !!showDetach ||
125
+ !!showReplace ||
126
+ showDelete();
127
+ if (!hasAnyActions) {
128
+ return null;
129
+ }
122
130
  const isEmbedMode = !!onReplaceEmbed;
123
131
  const groupFiles = (0, files_1.memoGroupFiles)();
124
132
  return (react_1.default.createElement(DropdownWrapper, { ref: wrapperRef },
@@ -31,6 +31,9 @@ const footnote_1 = __importDefault(require("../views/footnote"));
31
31
  const footnotes_element_1 = __importDefault(require("../views/footnotes_element"));
32
32
  const general_table_footnote_1 = __importDefault(require("../views/general_table_footnote"));
33
33
  const hero_image_editable_1 = __importDefault(require("../views/hero_image_editable"));
34
+ const headshot_grid_editable_1 = __importDefault(require("../views/headshot_grid_editable"));
35
+ const headshot_element_1 = __importDefault(require("../views/headshot_element"));
36
+ const headshot_image_editable_1 = __importDefault(require("../views/headshot_image_editable"));
34
37
  const image_element_editable_1 = __importDefault(require("../views/image_element_editable"));
35
38
  const inline_equation_editable_1 = __importDefault(require("../views/inline_equation_editable"));
36
39
  const inline_footnote_editable_1 = __importDefault(require("../views/inline_footnote_editable"));
@@ -111,6 +114,9 @@ exports.default = (props, dispatch) => {
111
114
  long_desc: (0, accessibility_element_1.default)(props, dispatch),
112
115
  alt_text: (0, accessibility_element_1.default)(props, dispatch),
113
116
  hero_image: (0, hero_image_editable_1.default)(props, dispatch),
117
+ headshot_grid: (0, headshot_grid_editable_1.default)(props, dispatch),
118
+ headshot_element: (0, headshot_element_1.default)(props, dispatch),
119
+ headshot_image: (0, headshot_image_editable_1.default)(props, dispatch),
114
120
  abstracts: (0, abstracts_1.default)(props),
115
121
  trans_abstract: (0, translated_abstract_editable_1.default)(props),
116
122
  trans_graphical_abstract: (0, trans_graphical_abstract_editable_1.default)(props),
package/dist/cjs/icons.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ORCIDIcon = exports.tickIcon = exports.fileMainDocumentIcon = exports.linkIcon = exports.translateIcon = exports.draggableIcon = exports.fileCorruptedIcon = exports.imageDefaultIcon = exports.imageLeftIcon = exports.imageRightIcon = exports.plusIcon = exports.lockIcon = exports.scrollIcon = exports.sectionCategoryIcon = exports.editIcon = exports.deleteIcon = exports.alertIcon = exports.arrowUp = exports.arrowDown = exports.addAuthorIcon = void 0;
3
+ exports.ORCIDIcon = exports.tickIcon = exports.fileMainDocumentIcon = exports.linkIcon = exports.translateIcon = exports.draggableIcon = exports.fileCorruptedIcon = exports.imageDefaultIcon = exports.imageLeftIcon = exports.imageRightIcon = exports.plusIcon = exports.lockIcon = exports.scrollIcon = exports.sectionCategoryIcon = exports.editIcon = exports.deleteIcon = exports.cameraIcon = exports.alertIcon = exports.arrowUp = exports.arrowDown = exports.addAuthorIcon = 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");
@@ -9,6 +9,7 @@ exports.addAuthorIcon = renderIcon(style_guide_1.AddAuthorIcon);
9
9
  exports.arrowDown = renderIcon(style_guide_1.ArrowDownCircleIcon);
10
10
  exports.arrowUp = renderIcon(style_guide_1.ArrowUpIcon);
11
11
  exports.alertIcon = renderIcon(style_guide_1.AlertIcon);
12
+ exports.cameraIcon = renderIcon(style_guide_1.CameraIcon);
12
13
  exports.deleteIcon = renderIcon(style_guide_1.DeleteIcon);
13
14
  exports.editIcon = renderIcon(style_guide_1.EditIcon);
14
15
  exports.sectionCategoryIcon = renderIcon(style_guide_1.SectionCategoryIcon);
@@ -13,6 +13,7 @@ const figureTypes = [
13
13
  transform_1.schema.nodes.figure_element,
14
14
  transform_1.schema.nodes.image_element,
15
15
  transform_1.schema.nodes.hero_image,
16
+ transform_1.schema.nodes.headshot_grid,
16
17
  transform_1.schema.nodes.embed,
17
18
  ];
18
19
  function memoGroupFiles() {
@@ -56,7 +57,11 @@ const groupFiles = (doc, files) => {
56
57
  }
57
58
  }
58
59
  else {
59
- for (const figure of (0, prosemirror_utils_1.findChildrenByType)(node, transform_1.schema.nodes.figure)) {
60
+ const descend = node.type === transform_1.schema.nodes.headshot_grid;
61
+ const figureNodeType = node.type === transform_1.schema.nodes.headshot_grid
62
+ ? transform_1.schema.nodes.headshot_image
63
+ : transform_1.schema.nodes.figure;
64
+ for (const figure of (0, prosemirror_utils_1.findChildrenByType)(node, figureNodeType, descend)) {
60
65
  if ((0, track_changes_utils_1.isHidden)(figure.node)) {
61
66
  continue;
62
67
  }
package/dist/cjs/menus.js CHANGED
@@ -272,6 +272,14 @@ const getEditorMenus = (editor) => {
272
272
  run: doCommand(commands_1.insertBoxElement),
273
273
  isHidden: !(0, template_1.templateAllows)(state, transform_1.schema.nodes.box_element),
274
274
  },
275
+ {
276
+ id: 'insert-headshot-grid',
277
+ label: 'Headshot Panel',
278
+ isEnabled: (0, utils_1.isEditAllowed)(state) &&
279
+ isCommandValid((0, commands_1.canInsert)(transform_1.schema.nodes.headshot_grid)),
280
+ run: doCommand(commands_1.insertHeadshotGrid),
281
+ isHidden: !(0, template_1.templateAllows)(state, transform_1.schema.nodes.headshot_grid),
282
+ },
275
283
  {
276
284
  role: 'separator',
277
285
  },
@@ -23,6 +23,8 @@ const style_guide_1 = require("@manuscripts/style-guide");
23
23
  const transform_1 = require("@manuscripts/transform");
24
24
  const react_1 = __importDefault(require("react"));
25
25
  const { nodes } = transform_1.schema;
26
+ const OutlineHeadshotGridIcon = () => (react_1.default.createElement(style_guide_1.FileHeadshotGridIcon, { width: "12", height: "12" }));
27
+ const OutlineHeadshotElementIcon = () => (react_1.default.createElement(style_guide_1.AvatarIcon, { width: "16", height: "16" }));
26
28
  const OutlineImageIcon = () => (react_1.default.createElement(style_guide_1.FileImageIcon, { width: "11", height: "14" }));
27
29
  const OutlineSupplementsIcon = () => (react_1.default.createElement(style_guide_1.SupplementsIcon, { width: "11", height: "14" }));
28
30
  const OutlineMainDocumentIcon = () => (react_1.default.createElement(style_guide_1.FileDocumentIcon, { width: "11", height: "14" }));
@@ -44,6 +46,8 @@ const icons = new Map([
44
46
  [nodes.hero_image, OutlineImageIcon],
45
47
  [nodes.supplements, OutlineSupplementsIcon],
46
48
  [nodes.attachments, OutlineMainDocumentIcon],
49
+ [nodes.headshot_grid, OutlineHeadshotGridIcon],
50
+ [nodes.headshot_element, OutlineHeadshotElementIcon],
47
51
  ]);
48
52
  const nodeTypeIcon = (nodeType, listType) => {
49
53
  if (nodeType === transform_1.schema.nodes.list) {
@@ -30,7 +30,8 @@ const isSelectionWithin = (node, pos, selection) => {
30
30
  const buildExpandButtonDecorations = (doc) => {
31
31
  const decorations = [];
32
32
  doc.descendants((node, pos) => {
33
- if (node.type.spec.content?.includes('alt_text')) {
33
+ if (node.type !== transform_1.schema.nodes.headshot_element &&
34
+ node.type.spec.content?.includes('alt_text')) {
34
35
  decorations.push(prosemirror_view_1.Decoration.widget(pos + node.nodeSize - 1, (view) => {
35
36
  const container = document.createElement('div');
36
37
  container.className =
@@ -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.13.10';
4
+ exports.VERSION = '3.13.12';
5
5
  exports.MATHJAX_VERSION = '3.2.2';
@@ -9,8 +9,15 @@ const prosemirror_state_1 = require("prosemirror-state");
9
9
  const navigation_utils_1 = require("../lib/navigation-utils");
10
10
  const block_view_1 = __importDefault(require("./block_view"));
11
11
  const creators_1 = require("./creators");
12
+ const empty_1 = __importDefault(require("./empty"));
12
13
  class AccessibilityElementView extends block_view_1.default {
13
14
  initialise() {
15
+ const $pos = this.view.state.doc.resolve(this.getPos());
16
+ if ($pos.parent.type === transform_1.schema.nodes.headshot_element) {
17
+ const { dom } = (0, empty_1.default)('accessibility_element')();
18
+ this.dom = dom;
19
+ return;
20
+ }
14
21
  this.createDOM();
15
22
  this.createElement();
16
23
  this.updateContents();
@@ -30,7 +37,6 @@ class AccessibilityElementView extends block_view_1.default {
30
37
  createElement() {
31
38
  super.createElement();
32
39
  this.contentDOM.className = 'accessibility_element_input';
33
- this.contentDOM.setAttribute('contenteditable', 'true');
34
40
  this.contentDOM.tabIndex = this.node.type === transform_1.schema.nodes.alt_text ? 0 : -1;
35
41
  this.removeKeydownListener = (0, navigation_utils_1.createKeyboardInteraction)({
36
42
  container: this.contentDOM,
@@ -120,7 +120,6 @@ class AffiliationsView extends block_view_1.default {
120
120
  this.container = document.createElement('div');
121
121
  this.container.classList.add('affiliations', 'block');
122
122
  this.container.contentEditable = 'false';
123
- this.container.addEventListener('click', this.handleClick);
124
123
  this.dom.setAttribute('contenteditable', 'false');
125
124
  this.dom.appendChild(this.container);
126
125
  }
@@ -140,6 +139,11 @@ class AffiliationsView extends block_view_1.default {
140
139
  this.updateSelection();
141
140
  }
142
141
  buildAffiliations(affs) {
142
+ const can = this.props.getCapabilities();
143
+ this.container.removeEventListener('click', this.handleClick);
144
+ if (can.editMetadata) {
145
+ this.container.addEventListener('click', this.handleClick);
146
+ }
143
147
  const elements = [];
144
148
  for (const affiliation of affs.affiliations) {
145
149
  const index = affs.indexedAffiliationIds.get(affiliation.id);
@@ -28,7 +28,6 @@ class CaptionView extends base_node_view_1.BaseNodeView {
28
28
  createDOM() {
29
29
  this.dom = document.createElement('caption');
30
30
  this.dom.className = 'caption-description placeholder';
31
- this.dom.contentEditable = 'true';
32
31
  this.contentDOM = this.dom;
33
32
  }
34
33
  }
@@ -28,7 +28,6 @@ class CaptionTitleView extends base_node_view_1.BaseNodeView {
28
28
  createDOM() {
29
29
  this.dom = document.createElement('label');
30
30
  this.dom.className = 'caption-title placeholder';
31
- this.dom.contentEditable = 'true';
32
31
  this.contentDOM = this.dom;
33
32
  }
34
33
  }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ /*!
3
+ * © 2026 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.HeadshotElement = void 0;
19
+ const prosemirror_state_1 = require("prosemirror-state");
20
+ const icons_1 = require("../icons");
21
+ const navigation_utils_1 = require("../lib/navigation-utils");
22
+ const base_node_view_1 = require("./base_node_view");
23
+ const creators_1 = require("./creators");
24
+ class HeadshotElement extends base_node_view_1.BaseNodeView {
25
+ constructor() {
26
+ super(...arguments);
27
+ this.elementType = 'div';
28
+ this.createElement = () => {
29
+ this.dom = document.createElement('div');
30
+ this.dom.classList.add('headshot-element');
31
+ this.dom.tabIndex = 0;
32
+ this.dom.setAttribute('id', this.node.attrs.id);
33
+ this.container = document.createElement('div');
34
+ this.container.classList.add('block');
35
+ this.dom.appendChild(this.container);
36
+ this.contentDOM = document.createElement('div');
37
+ this.contentDOM.classList.add('block-container', 'headshot-element-block');
38
+ this.container.appendChild(this.contentDOM);
39
+ const can = this.props.getCapabilities();
40
+ if (can.editArticle) {
41
+ this.deleteHeadshotButton = document.createElement('button');
42
+ this.deleteHeadshotButton.innerHTML = icons_1.plusIcon;
43
+ this.deleteHeadshotButton.classList.add('headshot-remove-button');
44
+ this.deleteHeadshotButton.setAttribute('data-cy', 'headshot-delete');
45
+ this.deleteHeadshotButton.contentEditable = 'false';
46
+ this.deleteHeadshotButton.addEventListener('click', this.handleDeleteHeadshot);
47
+ this.deleteHeadshotButton.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(this.handleDeleteHeadshot));
48
+ this.container.appendChild(this.deleteHeadshotButton);
49
+ }
50
+ };
51
+ this.handleDeleteHeadshot = () => {
52
+ const { state, dispatch } = this.view;
53
+ const { tr } = state;
54
+ const pos = this.getPos();
55
+ tr.delete(pos, pos + this.node.nodeSize);
56
+ this.view.focus();
57
+ const $pos = tr.doc.resolve(pos);
58
+ if ($pos.node().nodeSize > 2) {
59
+ tr.setSelection(prosemirror_state_1.TextSelection.near(tr.doc.resolve($pos.start()))).scrollIntoView();
60
+ }
61
+ dispatch(tr);
62
+ };
63
+ }
64
+ initialise() {
65
+ this.createElement();
66
+ this.updateContents();
67
+ }
68
+ destroy() {
69
+ this.deleteHeadshotButton?.removeEventListener('click', this.handleDeleteHeadshot);
70
+ super.destroy();
71
+ }
72
+ }
73
+ exports.HeadshotElement = HeadshotElement;
74
+ exports.default = (0, creators_1.createNodeView)(HeadshotElement);
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /*!
3
+ * © 2026 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 headshot_element_1 = require("./headshot_element");
20
+ exports.default = (0, creators_1.createEditableNodeView)(headshot_element_1.HeadshotElement);
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ /*!
3
+ * © 2026 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.HeadshotGridView = void 0;
22
+ const transform_1 = require("@manuscripts/transform");
23
+ const prosemirror_state_1 = require("prosemirror-state");
24
+ const icons_1 = require("../icons");
25
+ const navigation_utils_1 = require("../lib/navigation-utils");
26
+ const block_view_1 = __importDefault(require("./block_view"));
27
+ const creators_1 = require("./creators");
28
+ class HeadshotGridView extends block_view_1.default {
29
+ constructor() {
30
+ super(...arguments);
31
+ this.elementType = 'div';
32
+ this.createElement = () => {
33
+ this.container = document.createElement('div');
34
+ this.container.classList.add('block', 'headshot-grid-container');
35
+ this.dom.appendChild(this.container);
36
+ this.contentDOM = document.createElement('div');
37
+ this.contentDOM.classList.add('headshot-grid-block');
38
+ this.contentDOM.setAttribute('id', this.node.attrs.id);
39
+ this.removeKeydownListener = (0, navigation_utils_1.createKeyboardInteraction)({
40
+ container: this.contentDOM,
41
+ navigation: {
42
+ arrowKeys: { forward: 'ArrowDown', backward: 'ArrowUp' },
43
+ getItems: () => [...(this.contentDOM?.children || [])],
44
+ },
45
+ });
46
+ this.container.appendChild(this.contentDOM);
47
+ const can = this.props.getCapabilities();
48
+ if (can.editArticle) {
49
+ this.addHeadshotButton = document.createElement('button');
50
+ this.addHeadshotButton.classList.add('add-headshot-element-button');
51
+ this.addHeadshotButton.setAttribute('data-cy', 'headshot-add');
52
+ this.addHeadshotButton.contentEditable = 'false';
53
+ this.addHeadshotButton.innerHTML = icons_1.addAuthorIcon;
54
+ const buttonText = document.createElement('span');
55
+ buttonText.classList.add('add-headshot-element-text');
56
+ buttonText.innerText = 'Add Headshot';
57
+ this.addHeadshotButton.appendChild(buttonText);
58
+ this.addHeadshotButton.addEventListener('click', this.handleAddHeadshot);
59
+ this.addHeadshotButton.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(this.handleAddHeadshot));
60
+ this.container.appendChild(this.addHeadshotButton);
61
+ }
62
+ this.dom.appendChild(this.container);
63
+ };
64
+ this.handleAddHeadshot = () => {
65
+ const { state, dispatch } = this.view;
66
+ const { tr } = state;
67
+ const headshotElementNode = transform_1.schema.nodes.headshot_element.createAndFill();
68
+ const insertPos = this.getPos() + 1;
69
+ tr.insert(insertPos, headshotElementNode);
70
+ this.view.focus();
71
+ tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, insertPos));
72
+ dispatch(tr.scrollIntoView());
73
+ };
74
+ }
75
+ destroy() {
76
+ this.addHeadshotButton?.removeEventListener('click', this.handleAddHeadshot);
77
+ this.removeKeydownListener?.();
78
+ super.destroy();
79
+ }
80
+ }
81
+ exports.HeadshotGridView = HeadshotGridView;
82
+ exports.default = (0, creators_1.createNodeView)(HeadshotGridView);
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /*!
3
+ * © 2026 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 headshot_grid_1 = require("./headshot_grid");
21
+ exports.default = (0, creators_1.createEditableNodeView)((0, editable_block_1.EditableBlock)(headshot_grid_1.HeadshotGridView));
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ /*!
3
+ * © 2026 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.HeadshotImageEditableView = void 0;
19
+ const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
20
+ const icons_1 = require("../icons");
21
+ const navigation_utils_1 = require("../lib/navigation-utils");
22
+ const creators_1 = require("./creators");
23
+ const figure_editable_1 = require("./figure_editable");
24
+ class HeadshotImageEditableView extends figure_editable_1.FigureEditableView {
25
+ constructor() {
26
+ super(...arguments);
27
+ this.ignoreMutation = () => true;
28
+ this.createPlaceholder = () => {
29
+ const element = document.createElement('div');
30
+ element.classList.add('figure', 'placeholder');
31
+ element.tabIndex = 0;
32
+ const instructions = document.createElement('div');
33
+ instructions.classList.add('instructions');
34
+ instructions.innerHTML = `${icons_1.cameraIcon}<div>Upload<br>photo</div>`;
35
+ element.appendChild(instructions);
36
+ return element;
37
+ };
38
+ this.handleDetachImage = () => {
39
+ const { state, dispatch } = this.view;
40
+ const pos = this.getPos();
41
+ dispatch(state.tr.delete(pos, pos + this.node.nodeSize));
42
+ };
43
+ }
44
+ createDOM() {
45
+ this.dom = document.createElement('figure');
46
+ this.container = document.createElement('div');
47
+ this.container.className = 'headshot-figure';
48
+ this.container.contentEditable = 'false';
49
+ this.dom.appendChild(this.container);
50
+ }
51
+ addTools() {
52
+ const src = this.node.attrs.src;
53
+ const files = this.props.getFiles();
54
+ const file = src && files.filter((f) => f.id === src)[0];
55
+ const link = file && this.props.fileManagement.previewLink(file);
56
+ const can = this.props.getCapabilities();
57
+ if (can.detachFile && link) {
58
+ this.detachImageButton = document.createElement('button');
59
+ this.detachImageButton.innerHTML = icons_1.plusIcon;
60
+ this.detachImageButton.classList.add('headshot-remove-button');
61
+ this.detachImageButton.setAttribute('data-cy', 'headshot-image-detach');
62
+ this.detachImageButton.contentEditable = 'false';
63
+ this.detachImageButton.addEventListener('click', this.handleDetachImage);
64
+ this.detachImageButton.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(this.handleDetachImage));
65
+ this.container.appendChild(this.detachImageButton);
66
+ }
67
+ }
68
+ updateContents() {
69
+ super.updateContents();
70
+ (0, track_changes_plugin_1.addTrackChangesAttributes)(this.node.attrs, this.dom);
71
+ (0, track_changes_plugin_1.addTrackChangesClassNames)(this.node.attrs, this.dom);
72
+ }
73
+ destroy() {
74
+ this.detachImageButton?.removeEventListener('click', this.handleDetachImage);
75
+ super.destroy();
76
+ }
77
+ }
78
+ exports.HeadshotImageEditableView = HeadshotImageEditableView;
79
+ exports.default = (0, creators_1.createEditableNodeView)(HeadshotImageEditableView);
@@ -25,6 +25,7 @@ const creators_1 = require("./creators");
25
25
  class SupplementView extends base_node_view_1.BaseNodeView {
26
26
  constructor() {
27
27
  super(...arguments);
28
+ this.dragAndDropInitialized = false;
28
29
  this.ignoreMutation = () => true;
29
30
  this.createElement = () => {
30
31
  this.dom = document.createElement('div');
@@ -43,11 +44,25 @@ class SupplementView extends base_node_view_1.BaseNodeView {
43
44
  initialise() {
44
45
  this.createElement();
45
46
  this.updateContents();
46
- this.setupDragAndDrop();
47
47
  }
48
48
  updateContents() {
49
49
  super.updateContents();
50
50
  this.refreshFileInfo();
51
+ const can = this.props.getCapabilities();
52
+ this.dom.draggable = can.editArticle;
53
+ if (can.editArticle) {
54
+ if (!this.dragAndDropInitialized) {
55
+ this.setupDragAndDrop();
56
+ this.dragAndDropInitialized = true;
57
+ }
58
+ if (!this.dragIcon) {
59
+ this.addDragIcon();
60
+ }
61
+ }
62
+ else {
63
+ this.dragIcon?.remove();
64
+ this.dragIcon = undefined;
65
+ }
51
66
  }
52
67
  getDropSide(element, clientY) {
53
68
  const { top, bottom } = element.getBoundingClientRect();
@@ -567,6 +567,24 @@ export const insertBoxElement = (state, dispatch) => {
567
567
  }
568
568
  return true;
569
569
  };
570
+ export const insertHeadshotGrid = (state, dispatch) => {
571
+ const selection = state.selection;
572
+ const { nodes } = schema;
573
+ const isBody = hasParentNodeOfType(nodes.body)(selection);
574
+ if (!isBody) {
575
+ return false;
576
+ }
577
+ const position = findBlockInsertPosition(state);
578
+ if (position && dispatch) {
579
+ const headshotElement = schema.nodes.headshot_element.createAndFill();
580
+ const node = nodes.headshot_grid.create({}, headshotElement);
581
+ const tr = state.tr.insert(position, node);
582
+ const headshotNamePosition = position + 2;
583
+ tr.setSelection(TextSelection.create(tr.doc, headshotNamePosition));
584
+ dispatch(tr.scrollIntoView());
585
+ }
586
+ return true;
587
+ };
570
588
  export const insertSection = (subsection = false) => (state, dispatch, view) => {
571
589
  const { nodes } = schema;
572
590
  const $pos = state.selection.$from;
@@ -80,6 +80,14 @@ export const FigureOptions = ({ can, getDoc, getFiles, onDownload, onUpload, onD
80
80
  }
81
81
  }, [isOpen, container.classList]);
82
82
  useDropdownKeyboardNav(isOpen, dropdownRef, toggleOpen);
83
+ const hasAnyActions = !!showDownload ||
84
+ !!showUpload ||
85
+ !!showDetach ||
86
+ !!showReplace ||
87
+ showDelete();
88
+ if (!hasAnyActions) {
89
+ return null;
90
+ }
83
91
  const isEmbedMode = !!onReplaceEmbed;
84
92
  const groupFiles = memoGroupFiles();
85
93
  return (React.createElement(DropdownWrapper, { ref: wrapperRef },
@@ -26,6 +26,9 @@ import footnote from '../views/footnote';
26
26
  import footnotesElement from '../views/footnotes_element';
27
27
  import generalTableFootnote from '../views/general_table_footnote';
28
28
  import heroImage from '../views/hero_image_editable';
29
+ import headshotGrid from '../views/headshot_grid_editable';
30
+ import headshotElement from '../views/headshot_element';
31
+ import headshotImage from '../views/headshot_image_editable';
29
32
  import imageElement from '../views/image_element_editable';
30
33
  import inlineEquation from '../views/inline_equation_editable';
31
34
  import inlineFootnote from '../views/inline_footnote_editable';
@@ -106,6 +109,9 @@ export default (props, dispatch) => {
106
109
  long_desc: accessibilityElement(props, dispatch),
107
110
  alt_text: accessibilityElement(props, dispatch),
108
111
  hero_image: heroImage(props, dispatch),
112
+ headshot_grid: headshotGrid(props, dispatch),
113
+ headshot_element: headshotElement(props, dispatch),
114
+ headshot_image: headshotImage(props, dispatch),
109
115
  abstracts: abstracts(props),
110
116
  trans_abstract: transAbstract(props),
111
117
  trans_graphical_abstract: transGraphicalAbstract(props),
package/dist/es/icons.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AddAuthorIcon, AlertIcon, ArrowDownCircleIcon, ArrowUpIcon, DeleteIcon, DraggableIcon, EditIcon, FileCorruptedIcon, FileMainDocumentIcon, ImageDefaultIcon, ImageLeftIcon, ImageRightIcon, LinkIcon, LockIcon, ORCIDIcon as ORCID, PlusIcon, ScrollIcon, SectionCategoryIcon, TickIcon, TranslateIcon, } from '@manuscripts/style-guide';
1
+ import { AddAuthorIcon, AlertIcon, ArrowDownCircleIcon, ArrowUpIcon, CameraIcon, DeleteIcon, DraggableIcon, EditIcon, FileCorruptedIcon, FileMainDocumentIcon, ImageDefaultIcon, ImageLeftIcon, ImageRightIcon, LinkIcon, LockIcon, ORCIDIcon as ORCID, PlusIcon, ScrollIcon, SectionCategoryIcon, TickIcon, TranslateIcon, } 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));
@@ -6,6 +6,7 @@ export const addAuthorIcon = renderIcon(AddAuthorIcon);
6
6
  export const arrowDown = renderIcon(ArrowDownCircleIcon);
7
7
  export const arrowUp = renderIcon(ArrowUpIcon);
8
8
  export const alertIcon = renderIcon(AlertIcon);
9
+ export const cameraIcon = renderIcon(CameraIcon);
9
10
  export const deleteIcon = renderIcon(DeleteIcon);
10
11
  export const editIcon = renderIcon(EditIcon);
11
12
  export const sectionCategoryIcon = renderIcon(SectionCategoryIcon);