@manuscripts/body-editor 3.16.0 → 3.16.1

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 (54) hide show
  1. package/dist/cjs/commands.js +45 -10
  2. package/dist/cjs/components/form/FormFooter.js +2 -2
  3. package/dist/cjs/components/keyboard-shortcuts-modal/KeyboardShortcutsModal.js +4 -2
  4. package/dist/cjs/components/views/CrossReferenceItems.js +139 -52
  5. package/dist/cjs/components/views/DeleteSupplementDialog.js +1 -1
  6. package/dist/cjs/lib/supplements.js +9 -1
  7. package/dist/cjs/menus.js +35 -0
  8. package/dist/cjs/plugins/objects.js +1 -1
  9. package/dist/cjs/toolbar.js +6 -0
  10. package/dist/cjs/versions.js +1 -1
  11. package/dist/cjs/views/cross_reference.js +12 -2
  12. package/dist/cjs/views/cross_reference_editable.js +95 -4
  13. package/dist/cjs/views/figure_editable.js +3 -0
  14. package/dist/es/commands.js +43 -9
  15. package/dist/es/components/form/FormFooter.js +2 -2
  16. package/dist/es/components/keyboard-shortcuts-modal/KeyboardShortcutsModal.js +4 -2
  17. package/dist/es/components/views/CrossReferenceItems.js +141 -54
  18. package/dist/es/components/views/DeleteSupplementDialog.js +2 -2
  19. package/dist/es/lib/supplements.js +8 -1
  20. package/dist/es/menus.js +36 -1
  21. package/dist/es/plugins/objects.js +1 -1
  22. package/dist/es/toolbar.js +8 -2
  23. package/dist/es/versions.js +1 -1
  24. package/dist/es/views/cross_reference.js +12 -2
  25. package/dist/es/views/cross_reference_editable.js +96 -5
  26. package/dist/es/views/figure_editable.js +3 -0
  27. package/dist/types/commands.d.ts +1 -0
  28. package/dist/types/components/form/FormFooter.d.ts +2 -1
  29. package/dist/types/components/views/CrossReferenceItems.d.ts +3 -0
  30. package/dist/types/lib/supplements.d.ts +1 -0
  31. package/dist/types/versions.d.ts +1 -1
  32. package/dist/types/views/cross_reference_editable.d.ts +6 -0
  33. package/package.json +4 -4
  34. package/src/commands.ts +52 -10
  35. package/src/components/ChangeHandlingForm.tsx +4 -2
  36. package/src/components/form/FormFooter.tsx +3 -1
  37. package/src/components/keyboard-shortcuts-modal/KeyboardShortcutsModal.tsx +6 -7
  38. package/src/components/toolbar/InsertEmbedDialog.tsx +6 -2
  39. package/src/components/toolbar/type-selector/styles.ts +2 -1
  40. package/src/components/views/CrossReferenceItems.tsx +227 -100
  41. package/src/components/views/DeleteSupplementDialog.tsx +3 -6
  42. package/src/lib/footnotes.ts +3 -1
  43. package/src/lib/supplements.ts +13 -1
  44. package/src/lib/utils.ts +15 -4
  45. package/src/menus.tsx +39 -0
  46. package/src/plugins/add-subtitle.ts +18 -16
  47. package/src/plugins/objects.ts +2 -6
  48. package/src/toolbar.tsx +9 -0
  49. package/src/versions.ts +1 -1
  50. package/src/views/cross_reference.ts +17 -3
  51. package/src/views/cross_reference_editable.ts +123 -11
  52. package/src/views/figure_editable.ts +4 -0
  53. package/src/views/supplement.ts +0 -1
  54. package/src/views/supplements.ts +2 -2
@@ -15,8 +15,8 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- 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.updateSupplementWeblink = exports.insertSupplementWeblink = 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 = exports.addNodeComment = exports.createAndFillTableElement = void 0;
18
+ 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.canInsertCrossReference = exports.insertInlineCitation = exports.insertLink = exports.insertSectionLabel = exports.findPosBeforeFirstSubsection = exports.insertBreak = exports.deleteBlock = exports.insertBlock = exports.insertAttachment = exports.updateSupplementWeblink = exports.insertSupplementWeblink = 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 = exports.addNodeComment = exports.createAndFillTableElement = exports.selectAllIsolating = 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");
@@ -315,7 +315,7 @@ exports.insertSupplement = insertSupplement;
315
315
  const insertSupplementWeblink = (url, title, view) => {
316
316
  const supplement = transform_1.schema.nodes.supplement.createAndFill({
317
317
  id: (0, transform_1.generateNodeID)(transform_1.schema.nodes.supplement),
318
- href: url
318
+ href: url,
319
319
  }, createAndFillCaption());
320
320
  const tr = view.state.tr;
321
321
  const { pos } = (0, doc_1.upsertSupplementsSection)(tr, supplement);
@@ -493,15 +493,53 @@ const insertInlineCitation = (state, dispatch) => {
493
493
  return true;
494
494
  };
495
495
  exports.insertInlineCitation = insertInlineCitation;
496
+ const canInsertCrossReference = (state) => {
497
+ if (!(0, exports.canInsert)(transform_1.schema.nodes.cross_reference)(state)) {
498
+ return false;
499
+ }
500
+ const { from, to, empty, $from, $to } = state.selection;
501
+ if (empty) {
502
+ return true;
503
+ }
504
+ if (!$from.sameParent($to)) {
505
+ return false;
506
+ }
507
+ let overlaps = false;
508
+ state.doc.nodesBetween(from, to, (node) => {
509
+ if (node.isAtom && !node.isText) {
510
+ overlaps = true;
511
+ return false;
512
+ }
513
+ return !overlaps;
514
+ });
515
+ return !overlaps;
516
+ };
517
+ exports.canInsertCrossReference = canInsertCrossReference;
496
518
  const insertCrossReference = (state, dispatch) => {
519
+ if (!(0, exports.canInsertCrossReference)(state)) {
520
+ return false;
521
+ }
522
+ const text = selectedText();
497
523
  const node = state.schema.nodes.cross_reference.create({
524
+ id: (0, transform_1.generateNodeID)(transform_1.schema.nodes.cross_reference),
498
525
  rids: [],
526
+ label: text,
499
527
  });
500
- const pos = state.selection.to;
501
- const tr = state.tr.insert(pos, node);
528
+ const { tr } = state;
529
+ let pos;
530
+ const isWrap = !state.selection.empty;
531
+ if (isWrap) {
532
+ pos = state.selection.from;
533
+ tr.replaceSelectionWith(node);
534
+ }
535
+ else {
536
+ pos = state.selection.to;
537
+ tr.insert(pos, node);
538
+ }
502
539
  if (dispatch) {
503
540
  const selection = prosemirror_state_1.NodeSelection.create(tr.doc, pos);
504
- dispatch(tr.setSelection(selection).scrollIntoView());
541
+ tr.setSelection(selection).scrollIntoView();
542
+ dispatch(isWrap ? (0, track_changes_plugin_1.skipTracking)(tr) : tr);
505
543
  }
506
544
  return true;
507
545
  };
@@ -1009,10 +1047,7 @@ const insertTransGraphicalAbstract = (category, insertAfterPos) => (state, dispa
1009
1047
  const node = transform_1.schema.nodes.trans_graphical_abstract.createAndFill({
1010
1048
  lang,
1011
1049
  category: category.id,
1012
- }, [
1013
- transform_1.schema.nodes.section_title.create(),
1014
- createAndFillFigureElement(state),
1015
- ]);
1050
+ }, [transform_1.schema.nodes.section_title.create(), createAndFillFigureElement(state)]);
1016
1051
  const tr = state.tr.insert(pos, node);
1017
1052
  if (node.lastChild) {
1018
1053
  (0, accessibility_element_1.expandAccessibilitySection)(tr, node.lastChild);
@@ -21,9 +21,9 @@ const Footer = styled_components_1.default.div `
21
21
  const StyledIconTextButton = (0, styled_components_1.default)(style_guide_1.IconTextButton) `
22
22
  color: ${(props) => props.theme.colors.brand.default};
23
23
  `;
24
- const FormFooter = ({ onCancel, primaryAction, }) => {
24
+ const FormFooter = ({ onCancel, primaryAction, cancelLabel = 'Close', }) => {
25
25
  return (react_1.default.createElement(Footer, null,
26
- react_1.default.createElement(StyledIconTextButton, { color: "secondary", onClick: onCancel }, "Close"),
26
+ react_1.default.createElement(StyledIconTextButton, { color: "secondary", onClick: onCancel }, cancelLabel),
27
27
  primaryAction));
28
28
  };
29
29
  exports.default = FormFooter;
@@ -79,7 +79,8 @@ const ShortcutTabs = (0, styled_components_1.default)(style_guide_1.InspectorTab
79
79
  min-height: 0;
80
80
  `;
81
81
  const ModalTabsWrapper = (0, styled_components_1.default)('div') `
82
- margin: 0 ${(props) => props.theme.grid.unit * 8}px ${(props) => props.theme.grid.unit * 3}px;
82
+ margin: 0 ${(props) => props.theme.grid.unit * 8}px
83
+ ${(props) => props.theme.grid.unit * 3}px;
83
84
  `;
84
85
  const ShortcutTabPanel = (0, styled_components_1.default)(style_guide_1.InspectorTabPanel).attrs({
85
86
  tabIndex: -1,
@@ -130,7 +131,8 @@ const Section = styled_components_1.default.section `
130
131
  }
131
132
  `;
132
133
  const SectionTitle = styled_components_1.default.h3 `
133
- margin: 0 ${(props) => props.theme.grid.unit * 8}px ${(props) => props.theme.grid.unit * 2}px;
134
+ margin: 0 ${(props) => props.theme.grid.unit * 8}px
135
+ ${(props) => props.theme.grid.unit * 2}px;
134
136
  font-size: ${(props) => props.theme.font.size.large};
135
137
  font-weight: ${(props) => props.theme.font.weight.normal};
136
138
  line-height: ${(props) => props.theme.font.lineHeight.large};
@@ -53,73 +53,121 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
53
53
  Object.defineProperty(exports, "__esModule", { value: true });
54
54
  exports.CrossReferenceItems = void 0;
55
55
  const style_guide_1 = require("@manuscripts/style-guide");
56
+ const transform_1 = require("@manuscripts/transform");
56
57
  const react_1 = __importStar(require("react"));
57
58
  const styled_components_1 = __importDefault(require("styled-components"));
58
- const Container = (0, style_guide_1.withFocusTrap)(styled_components_1.default.div `
59
- padding: ${(props) => props.theme.grid.unit * 3}px
60
- ${(props) => props.theme.grid.unit * 4}px;
61
- display: flex;
62
- flex-direction: column;
63
- max-height: 60vh;
64
- overflow: hidden;
65
- `);
66
- const Actions = styled_components_1.default.div `
67
- display: flex;
68
- align-items: center;
69
- justify-content: flex-end;
70
- flex-shrink: 0;
71
- `;
59
+ const url_1 = require("../../lib/url");
60
+ const node_type_icons_1 = require("../../node-type-icons");
61
+ const FormFooter_1 = __importDefault(require("../form/FormFooter"));
72
62
  const Items = (0, style_guide_1.withListNavigation)(styled_components_1.default.div `
73
63
  flex: 1;
74
64
  overflow-y: auto;
75
- padding: ${(props) => props.theme.grid.unit * 3}px;
76
65
  `);
77
66
  const CrossReferenceItem = (0, style_guide_1.withNavigableListItem)(styled_components_1.default.div `
78
67
  cursor: pointer;
79
- padding: ${(props) => props.theme.grid.unit * 4}px;
80
- background-color: ${(props) => props.$isSelected
81
- ? props.theme.colors.background.selected
82
- : props.theme.colors.background.primary};
68
+ padding: ${(props) => props.theme.grid.unit * 2}px;
69
+ background-color: ${(props) => props.theme.colors.background.primary};
83
70
  transition: background-color 0.1s;
84
- border: solid
85
- ${(props) => props.$isSelected
86
- ? props.theme.colors.brand.medium
87
- : props.theme.colors.border.secondary};
88
- border-width: 1px 0;
89
- z-index: ${(props) => (props.$isSelected ? '1' : '0')};
71
+ border: 1px solid ${(props) => props.theme.colors.border.secondary};
72
+ overflow: hidden;
73
+ max-width: 100%;
74
+ box-sizing: border-box;
75
+ margin-bottom: ${(props) => props.theme.grid.unit * 2}px;
90
76
 
91
77
  &:hover {
92
- background-color: ${(props) => props.theme.colors.background.selected};
78
+ background-color: #f2f2f2;
79
+ }
80
+
81
+ &.active {
82
+ background-color: #f2f2f2;
83
+ z-index: 1;
93
84
  }
94
85
  `);
95
86
  const Label = styled_components_1.default.span `
96
87
  color: ${(props) => props.theme.colors.text.primary};
88
+ -webkit-line-clamp: 2;
89
+ -webkit-box-orient: vertical;
90
+ overflow: hidden;
91
+ word-break: break-all;
92
+ overflow-wrap: break-word;
93
+ min-width: fit-content;
97
94
  `;
98
95
  const Caption = styled_components_1.default.span `
99
96
  color: ${(props) => props.theme.colors.text.secondary};
97
+ display: -webkit-box;
98
+ -webkit-line-clamp: 2;
99
+ -webkit-box-orient: vertical;
100
+ overflow: hidden;
101
+ word-break: break-all;
102
+ overflow-wrap: break-word;
103
+ margin-left: 3.2px;
100
104
  `;
101
105
  const Heading = styled_components_1.default.div `
102
- display: flex;
103
- align-items: center;
104
- justify-content: space-between;
105
- flex-shrink: 0;
106
+ font-size: ${(props) => props.theme.font.size.medium};
106
107
  font-weight: ${(props) => props.theme.font.weight.bold};
108
+ color: ${(props) => props.theme.colors.text.primary};
109
+ margin-bottom: ${(props) => props.theme.grid.unit * 3}px;
107
110
  `;
108
111
  const Empty = styled_components_1.default.div `
109
112
  margin-bottom: ${(props) => props.theme.grid.unit * 4}px;
110
113
  color: ${(props) => props.theme.colors.text.tertiary};
111
114
  `;
115
+ const GroupExpandableSection = (0, styled_components_1.default)(style_guide_1.ExpandableSection) `
116
+ & > div:first-child {
117
+ flex-direction: row-reverse;
118
+ justify-content: flex-end;
119
+ padding-left: 0;
120
+ gap: 10px;
121
+ font-weight: ${(props) => props.theme.font.weight.normal};
122
+ svg {
123
+ width: 20px;
124
+ height: 20px;
125
+ }
126
+ }
127
+ `;
112
128
  const DefaultLabelWrapper = styled_components_1.default.div `
113
- margin-bottom: ${(props) => props.theme.grid.unit * 2}px;
129
+ display: flex;
130
+ align-items: center;
131
+ min-width: 0;
114
132
  `;
115
- const CustomTextArea = (0, styled_components_1.default)(style_guide_1.TextArea) `
116
- width: 100%;
117
- height: 75px;
133
+ const ItemIcon = styled_components_1.default.span `
134
+ flex-shrink: 0;
135
+ display: flex;
136
+ align-items: center;
118
137
  color: ${(props) => props.theme.colors.text.secondary};
119
- background-color: ${(props) => props.theme.colors.background.primary} !important;
138
+ margin-right: ${(props) => props.theme.grid.unit * 2}px;
139
+ svg {
140
+ width: 20px;
141
+ height: 20px;
142
+ }
143
+ `;
144
+ const FieldLabel = styled_components_1.default.label `
145
+ font-size: ${(props) => props.theme.font.size.normal};
146
+ color: ${(props) => props.theme.colors.text.secondary};
147
+ margin-top: ${(props) => props.theme.grid.unit * 4}px;
148
+ margin-bottom: ${(props) => props.theme.grid.unit}px;
149
+ `;
150
+ const CustomTextInput = styled_components_1.default.input `
151
+ color: ${(props) => props.theme.colors.text.secondary};
152
+ background-color: ${(props) => props.theme.colors.background.primary};
120
153
  border: 1px solid ${(props) => props.theme.colors.border.secondary};
121
154
  border-radius: ${(props) => props.theme.grid.radius.small};
122
155
  padding: ${(props) => props.theme.grid.unit * 2}px;
156
+ &:disabled {
157
+ cursor: not-allowed;
158
+ background-color: ${(props) => props.theme.colors.background.disabled};
159
+ color: ${(props) => props.theme.colors.text.muted};
160
+ }
161
+ `;
162
+ const StyledModalBody = (0, styled_components_1.default)(style_guide_1.ModalBody) `
163
+ display: flex;
164
+ flex-direction: column;
165
+ padding: ${(props) => props.theme.grid.unit * 5}px
166
+ ${(props) => props.theme.grid.unit * 6}px;
167
+ max-height: 580px;
168
+ min-width: 600px;
169
+ max-width: 600px;
170
+ overflow: hidden;
123
171
  `;
124
172
  const trimmedCaption = (caption, limit) => {
125
173
  if (caption.length <= limit) {
@@ -128,7 +176,27 @@ const trimmedCaption = (caption, limit) => {
128
176
  const captionSearch = new RegExp(`^(.{${limit}}[^\\s]*).*`);
129
177
  return caption.replace(captionSearch, '$1…');
130
178
  };
131
- const CrossReferenceItems = ({ targets, handleSelect, handleCancel, currentTargetId, currentCustomLabel, }) => {
179
+ const getTargetIcon = (target, files) => {
180
+ if (target.type === transform_1.schema.nodes.supplement.name) {
181
+ if (target.href && (0, url_1.allowedHref)(target.href)) {
182
+ return react_1.default.createElement(style_guide_1.WebLinkIcon, { className: "file-icon" });
183
+ }
184
+ const fileName = files.find((f) => f.id === target.href)?.name ?? target.label ?? '';
185
+ return (0, style_guide_1.getFileIcon)(fileName) ?? react_1.default.createElement(style_guide_1.FileUnknownIcon, null);
186
+ }
187
+ return (0, node_type_icons_1.nodeTypeIcon)(transform_1.schema.nodes[target.type]);
188
+ };
189
+ const GROUP_LABELS = {
190
+ figure_element: 'Figures',
191
+ table_element: 'Tables',
192
+ equation_element: 'Equations',
193
+ listing_element: 'Listings',
194
+ box_element: 'Boxes',
195
+ embed: 'Media',
196
+ supplement: 'Supplementary files',
197
+ };
198
+ const CrossReferenceItems = ({ targets, files, handleSelect, handleCancel, currentTargetId, currentCustomLabel, isEdit = false, }) => {
199
+ const [isOpen, setIsOpen] = (0, react_1.useState)(true);
132
200
  const [selectedItem, setSelectedItem] = (0, react_1.useState)('');
133
201
  const customTextRef = (0, react_1.useRef)(null);
134
202
  (0, react_1.useEffect)(() => {
@@ -136,21 +204,40 @@ const CrossReferenceItems = ({ targets, handleSelect, handleCancel, currentTarge
136
204
  setSelectedItem(currentTargetId);
137
205
  }
138
206
  }, [currentTargetId]);
139
- return (react_1.default.createElement(Container, null,
140
- react_1.default.createElement(Heading, null, "Insert Cross-reference"),
141
- react_1.default.createElement(Items, null, targets.length ? (targets.map((target) => (react_1.default.createElement(CrossReferenceItem, { key: target.id, "$isSelected": selectedItem === target.id, onClick: () => setSelectedItem(target.id) },
142
- react_1.default.createElement(DefaultLabelWrapper, null,
143
- react_1.default.createElement(Label, null, target.label),
144
- react_1.default.createElement(Caption, null, target.caption && ': ' + trimmedCaption(target.caption, 200))),
145
- selectedItem === target.id && (react_1.default.createElement(CustomTextArea, { ref: customTextRef, placeholder: 'Or type custom text', defaultValue: currentTargetId &&
146
- currentTargetId === selectedItem &&
147
- currentCustomLabel
148
- ? currentCustomLabel
149
- : '' })))))) : (react_1.default.createElement(Empty, null, "No cross-reference targets available."))),
150
- react_1.default.createElement(Actions, null,
151
- react_1.default.createElement(style_guide_1.ButtonGroup, null,
152
- react_1.default.createElement(style_guide_1.SecondaryButton, { onClick: handleCancel }, "Cancel"),
153
- react_1.default.createElement(style_guide_1.PrimaryButton, { onClick: () => selectedItem &&
154
- handleSelect(selectedItem, customTextRef.current?.value || ''), disabled: !selectedItem }, "Insert")))));
207
+ const close = (0, react_1.useCallback)(() => {
208
+ setIsOpen(false);
209
+ handleCancel();
210
+ }, [handleCancel]);
211
+ const grouped = targets.reduce((acc, t) => {
212
+ var _a;
213
+ ;
214
+ (acc[_a = t.type] ?? (acc[_a] = [])).push(t);
215
+ return acc;
216
+ }, {});
217
+ return (react_1.default.createElement(style_guide_1.StyledModal, { isOpen: isOpen, onRequestClose: close, shouldCloseOnOverlayClick: true },
218
+ react_1.default.createElement(style_guide_1.ModalContainer, { "data-cy": "cross-reference-editor" },
219
+ react_1.default.createElement(style_guide_1.ModalHeader, null,
220
+ react_1.default.createElement(style_guide_1.CloseButton, { onClick: close })),
221
+ react_1.default.createElement(StyledModalBody, null,
222
+ react_1.default.createElement(Heading, null, isEdit ? 'Edit Cross-reference' : 'Insert Cross-reference'),
223
+ react_1.default.createElement(FieldLabel, { htmlFor: "cross-reference-custom-text" }, "Custom display text"),
224
+ react_1.default.createElement(CustomTextInput, { ref: customTextRef, id: "cross-reference-custom-text", "data-cy": "cross-reference-custom-text", type: "text", placeholder: 'Custom display text...', disabled: !selectedItem, defaultValue: currentCustomLabel ?? '' }),
225
+ react_1.default.createElement(Items, null, Object.keys(grouped).length ? (Object.entries(grouped).map(([type, group]) => (react_1.default.createElement(GroupExpandableSection, { key: type, title: GROUP_LABELS[type], icon: style_guide_1.ArrowDownIcon }, group.map((target) => {
226
+ const icon = getTargetIcon(target, files);
227
+ return (react_1.default.createElement(CrossReferenceItem, { key: target.id, "data-cy": "cross-reference-item", className: selectedItem === target.id ? 'active' : undefined, onClick: () => setSelectedItem(target.id) },
228
+ react_1.default.createElement(DefaultLabelWrapper, null,
229
+ icon ? react_1.default.createElement(ItemIcon, null, icon) : null,
230
+ react_1.default.createElement(Label, null,
231
+ target.label,
232
+ target.caption && `:`),
233
+ react_1.default.createElement(Caption, null, trimmedCaption(target.caption, 200)))));
234
+ }))))) : (react_1.default.createElement(Empty, null, "No cross-reference targets available.")))),
235
+ react_1.default.createElement(FormFooter_1.default, { onCancel: close, cancelLabel: "Cancel", primaryAction: react_1.default.createElement(style_guide_1.PrimaryButton, { onClick: () => {
236
+ if (selectedItem) {
237
+ setIsOpen(false);
238
+ const customLabel = customTextRef.current?.value;
239
+ handleSelect(selectedItem, customLabel || '');
240
+ }
241
+ }, disabled: !selectedItem }, isEdit ? 'Update' : 'Insert') }))));
155
242
  };
156
243
  exports.CrossReferenceItems = CrossReferenceItems;
@@ -44,7 +44,7 @@ const editor_props_1 = require("../../plugins/editor-props");
44
44
  const ReactSubView_1 = __importDefault(require("../../views/ReactSubView"));
45
45
  const DeleteSupplementDialog = ({ label, onDelete }) => {
46
46
  const [isOpen, setOpen] = (0, react_1.useState)(true);
47
- return (react_1.default.createElement(style_guide_1.Dialog, { isOpen: isOpen, category: style_guide_1.Category.confirmation, header: 'Delete supplement', message: 'Are you sure you want to delete \u201C{label}\u201D?', actions: {
47
+ return (react_1.default.createElement(style_guide_1.Dialog, { isOpen: isOpen, category: style_guide_1.Category.confirmation, header: "Delete supplement", message: "Are you sure you want to delete \u201C{label}\u201D?", actions: {
48
48
  primary: {
49
49
  action: () => {
50
50
  onDelete();
@@ -15,11 +15,19 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.deleteSupplementAtPos = exports.performDeleteSupplement = exports.getSupplementDisplayLabel = void 0;
18
+ exports.deleteSupplementAtPos = exports.performDeleteSupplement = exports.getSupplementDisplayLabel = exports.getSupplementCaptionTitle = void 0;
19
19
  const transform_1 = require("@manuscripts/transform");
20
20
  const prosemirror_utils_1 = require("prosemirror-utils");
21
21
  const url_1 = require("./url");
22
+ const getSupplementCaptionTitle = (node) => {
23
+ return node.firstChild?.textContent.trim() ?? '';
24
+ };
25
+ exports.getSupplementCaptionTitle = getSupplementCaptionTitle;
22
26
  const getSupplementDisplayLabel = (node, files) => {
27
+ const captionTitle = (0, exports.getSupplementCaptionTitle)(node);
28
+ if (captionTitle) {
29
+ return captionTitle;
30
+ }
23
31
  const href = node.attrs.href;
24
32
  if ((0, url_1.allowedHref)(href)) {
25
33
  return href;
package/dist/cjs/menus.js CHANGED
@@ -333,6 +333,41 @@ const getEditorMenus = (editor) => {
333
333
  {
334
334
  role: 'separator',
335
335
  },
336
+ {
337
+ id: 'insert-citation',
338
+ label: 'Citation',
339
+ shortcut: {
340
+ mac: 'Option+CommandOrControl+C',
341
+ pc: 'CommandOrControl+Option+C',
342
+ },
343
+ isEnabled: (0, utils_1.isEditAllowed)(state) &&
344
+ isCommandValid((0, commands_1.canInsert)(transform_1.schema.nodes.citation)),
345
+ run: doCommand(commands_1.insertInlineCitation),
346
+ isHidden: !(0, template_1.templateAllows)(state, transform_1.schema.nodes.citation),
347
+ },
348
+ {
349
+ id: 'insert-cross-reference',
350
+ label: 'Cross-reference',
351
+ shortcut: {
352
+ mac: 'Option+CommandOrControl+R',
353
+ pc: 'CommandOrControl+Option+R',
354
+ },
355
+ isEnabled: (0, utils_1.isEditAllowed)(state) && isCommandValid(commands_1.canInsertCrossReference),
356
+ run: doCommand(commands_1.insertCrossReference),
357
+ isHidden: !(0, template_1.templateAllows)(state, transform_1.schema.nodes.cross_reference),
358
+ },
359
+ {
360
+ id: 'insert-footnote',
361
+ label: 'Footnote',
362
+ shortcut: {
363
+ mac: 'Option+CommandOrControl+F',
364
+ pc: 'CommandOrControl+Option+F',
365
+ },
366
+ isEnabled: (0, utils_1.isEditAllowed)(state) &&
367
+ isCommandValid((0, commands_1.canInsert)(transform_1.schema.nodes.inline_footnote)),
368
+ run: doCommand(commands_1.insertInlineFootnote),
369
+ isHidden: !(0, template_1.templateAllows)(state, transform_1.schema.nodes.inline_footnote),
370
+ },
336
371
  {
337
372
  id: 'insert-special-character',
338
373
  label: 'Special Characters',
@@ -42,7 +42,7 @@ exports.default = () => {
42
42
  const { id } = node.attrs;
43
43
  if (id) {
44
44
  const target = targets.get(id);
45
- if (target) {
45
+ if (target && target.label) {
46
46
  const caption = (0, prosemirror_utils_1.findChildren)(node, (node) => node.type === transform_1.schema.nodes.caption ||
47
47
  node.type === transform_1.schema.nodes.caption_title, false)[0];
48
48
  if (caption) {
@@ -119,6 +119,12 @@ exports.toolbar = {
119
119
  isEnabled: isEnabled((0, commands_1.canInsert)(transform_1.schema.nodes.highlight_marker)),
120
120
  run: commands_1.addInlineComment,
121
121
  },
122
+ cross_reference: {
123
+ title: 'Insert cross-reference',
124
+ content: react_1.default.createElement(style_guide_1.ToolbarCrossReferenceIcon, null),
125
+ isEnabled: isEnabled(commands_1.canInsertCrossReference),
126
+ run: commands_1.insertCrossReference,
127
+ },
122
128
  citation: {
123
129
  title: 'Insert citation',
124
130
  content: react_1.default.createElement(style_guide_1.ToolbarCitationIcon, null),
@@ -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.16.0';
4
+ exports.VERSION = '3.16.1';
5
5
  exports.MATHJAX_VERSION = '3.2.2';
@@ -16,7 +16,10 @@
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.CrossReferenceView = void 0;
19
+ const transform_1 = require("@manuscripts/transform");
20
+ const doc_1 = require("../lib/doc");
19
21
  const navigation_utils_1 = require("../lib/navigation-utils");
22
+ const supplements_1 = require("../lib/supplements");
20
23
  const objects_1 = require("../plugins/objects");
21
24
  const base_node_view_1 = require("./base_node_view");
22
25
  const creators_1 = require("./creators");
@@ -49,8 +52,15 @@ class CrossReferenceView extends base_node_view_1.BaseNodeView {
49
52
  super.updateContents();
50
53
  const targets = objects_1.objectsKey.getState(this.view.state);
51
54
  const attrs = this.node.attrs;
52
- const label = attrs.rids.length && targets.get(attrs.rids[0])?.label;
53
- this.dom.textContent = attrs.label || label || '';
55
+ const target = attrs.rids.length ? targets.get(attrs.rids[0]) : undefined;
56
+ let derivedLabel = target?.label || '';
57
+ if (target?.type === transform_1.schema.nodes.supplement.name && target.href) {
58
+ const found = (0, doc_1.findNodeByID)(this.view.state.doc, target.id);
59
+ if (found) {
60
+ derivedLabel = (0, supplements_1.getSupplementDisplayLabel)(found.node, this.props.getFiles());
61
+ }
62
+ }
63
+ this.dom.textContent = attrs.label || derivedLabel;
54
64
  this.dom.addEventListener('click', this.handleClick);
55
65
  }
56
66
  }
@@ -19,10 +19,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
21
  exports.CrossReferenceEditableView = void 0;
22
+ const style_guide_1 = require("@manuscripts/style-guide");
22
23
  const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
23
24
  const transform_1 = require("@manuscripts/transform");
24
25
  const prosemirror_state_1 = require("prosemirror-state");
25
26
  const CrossReferenceItems_1 = require("../components/views/CrossReferenceItems");
27
+ const comments_1 = require("../lib/comments");
28
+ const doc_1 = require("../lib/doc");
29
+ const supplements_1 = require("../lib/supplements");
26
30
  const objects_1 = require("../plugins/objects");
27
31
  const creators_1 = require("./creators");
28
32
  const cross_reference_1 = require("./cross_reference");
@@ -37,14 +41,20 @@ class CrossReferenceEditableView extends cross_reference_1.CrossReferenceView {
37
41
  if (!can?.editArticle || rids.length) {
38
42
  return;
39
43
  }
44
+ this.showPicker();
45
+ };
46
+ this.showPicker = () => {
47
+ const rids = this.node.attrs.rids;
40
48
  const componentProps = {
41
49
  handleSelect: this.handleSelect,
42
50
  targets: this.getTargets(),
51
+ files: this.props.getFiles(),
43
52
  handleCancel: this.handleCancel,
44
53
  currentTargetId: rids[0],
45
54
  currentCustomLabel: this.node.attrs.label,
55
+ isEdit: rids.length > 0,
46
56
  };
47
- this.popperContainer = (0, ReactSubView_1.default)(this.props, CrossReferenceItems_1.CrossReferenceItems, componentProps, this.node, this.getPos, this.view, ['cross-reference-editor']);
57
+ this.popperContainer = (0, ReactSubView_1.default)(this.props, CrossReferenceItems_1.CrossReferenceItems, componentProps, this.node, this.getPos, this.view);
48
58
  this.popperContainer.setAttribute('tabindex', '0');
49
59
  this.props.popper.show(this.dom, this.popperContainer, 'auto');
50
60
  };
@@ -56,15 +66,39 @@ class CrossReferenceEditableView extends cross_reference_1.CrossReferenceView {
56
66
  this.handleCancel();
57
67
  };
58
68
  this.getTargets = () => {
59
- const excludedTypes = [transform_1.schema.nodes.image_element.name];
60
69
  const targets = objects_1.objectsKey.getState(this.view.state);
61
- return Array.from(targets.values()).filter((t) => !excludedTypes.includes(t.type));
70
+ const files = this.props.getFiles();
71
+ const fileMap = new Map(files.map((f) => [f.id, f.name]));
72
+ const excludedTypes = [transform_1.schema.nodes.image_element.name];
73
+ const supplement = transform_1.schema.nodes.supplement.name;
74
+ return Array.from(targets.values()).reduce((acc, t) => {
75
+ if (excludedTypes.includes(t.type)) {
76
+ return acc;
77
+ }
78
+ if (t.type === supplement && t.href) {
79
+ const found = (0, doc_1.findNodeByID)(this.view.state.doc, t.id);
80
+ const label = found
81
+ ? (0, supplements_1.getSupplementDisplayLabel)(found.node, files)
82
+ : (fileMap.get(t.href) ?? t.href);
83
+ acc.push({ ...t, label, caption: '' });
84
+ }
85
+ else {
86
+ acc.push(t);
87
+ }
88
+ return acc;
89
+ }, []);
62
90
  };
63
91
  this.handleCancel = () => {
64
92
  if (!this.node.attrs.rids.length) {
65
93
  const { state } = this.view;
66
94
  const pos = this.getPos();
67
- const tr = state.tr.delete(pos, pos + this.node.nodeSize);
95
+ if (pos === undefined) {
96
+ return;
97
+ }
98
+ const label = this.node.attrs.label;
99
+ const tr = label
100
+ ? state.tr.replaceWith(pos, pos + this.node.nodeSize, state.schema.text(label))
101
+ : state.tr.delete(pos, pos + this.node.nodeSize);
68
102
  tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, pos));
69
103
  (0, track_changes_plugin_1.skipTracking)(tr);
70
104
  this.view.dispatch(tr);
@@ -85,6 +119,63 @@ class CrossReferenceEditableView extends cross_reference_1.CrossReferenceView {
85
119
  this.view.dispatch(tr.setSelection(selection));
86
120
  this.destroy();
87
121
  };
122
+ this.handleClick = () => {
123
+ if ((0, track_changes_plugin_1.isDeleted)(this.node)) {
124
+ return;
125
+ }
126
+ if (!this.node.attrs.rids.length) {
127
+ return;
128
+ }
129
+ this.showContextMenu();
130
+ };
131
+ this.showContextMenu = () => {
132
+ this.props.popper.destroy();
133
+ const can = this.props.getCapabilities();
134
+ const targets = objects_1.objectsKey.getState(this.view.state);
135
+ const rid = this.node.attrs.rids[0];
136
+ const isOrphaned = !targets?.get(rid);
137
+ const actions = [
138
+ {
139
+ label: 'Comment',
140
+ icon: 'AddComment',
141
+ action: () => {
142
+ this.props.popper.destroy();
143
+ (0, comments_1.handleComment)(this.node, this.view);
144
+ },
145
+ },
146
+ {
147
+ label: 'Go to content',
148
+ icon: 'Scroll',
149
+ action: () => this.navigateToTarget(),
150
+ disabled: isOrphaned,
151
+ },
152
+ ];
153
+ if (can?.editArticle) {
154
+ actions.unshift({
155
+ label: 'Edit',
156
+ icon: 'Edit',
157
+ action: () => this.handleEdit(),
158
+ disabled: isOrphaned,
159
+ });
160
+ }
161
+ this.contextMenu = (0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, { actions }, this.node, this.getPos, this.view, ['context-menu']);
162
+ this.props.popper.show(this.dom, this.contextMenu, 'right-start', false);
163
+ };
164
+ this.navigateToTarget = () => {
165
+ this.props.popper.destroy();
166
+ const rids = this.node.attrs.rids;
167
+ if (!rids.length) {
168
+ return;
169
+ }
170
+ this.props.navigate({
171
+ pathname: this.props.location.pathname,
172
+ hash: '#' + rids[0],
173
+ });
174
+ };
175
+ this.handleEdit = () => {
176
+ this.props.popper.destroy();
177
+ this.showPicker();
178
+ };
88
179
  }
89
180
  }
90
181
  exports.CrossReferenceEditableView = CrossReferenceEditableView;