@manuscripts/body-editor 3.16.0 → 3.16.2

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 (99) 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/references/CitationEditor.js +13 -19
  5. package/dist/cjs/components/references/ImportBibliography.js +77 -0
  6. package/dist/cjs/components/references/ImportBibliographyForm.js +1 -1
  7. package/dist/cjs/components/references/ImportBibliographyModal.js +12 -81
  8. package/dist/cjs/components/references/ImportReferencesConfirmation.js +113 -0
  9. package/dist/cjs/components/references/ImportSuccessPlaceholder.js +56 -0
  10. package/dist/cjs/components/references/ReferenceSearch.js +2 -5
  11. package/dist/cjs/components/references/ReferencesEditor.js +18 -2
  12. package/dist/cjs/components/references/ReferencesModal.js +86 -33
  13. package/dist/cjs/components/views/CrossReferenceItems.js +139 -52
  14. package/dist/cjs/components/views/DeleteSupplementDialog.js +1 -1
  15. package/dist/cjs/lib/supplements.js +9 -1
  16. package/dist/cjs/lib/view.js +39 -1
  17. package/dist/cjs/menus.js +35 -0
  18. package/dist/cjs/plugins/objects.js +1 -1
  19. package/dist/cjs/toolbar.js +6 -0
  20. package/dist/cjs/versions.js +1 -1
  21. package/dist/cjs/views/bibliography_element.js +1 -2
  22. package/dist/cjs/views/citation_editable.js +2 -29
  23. package/dist/cjs/views/cross_reference.js +12 -2
  24. package/dist/cjs/views/cross_reference_editable.js +95 -4
  25. package/dist/cjs/views/figure_editable.js +3 -0
  26. package/dist/es/commands.js +43 -9
  27. package/dist/es/components/form/FormFooter.js +2 -2
  28. package/dist/es/components/keyboard-shortcuts-modal/KeyboardShortcutsModal.js +4 -2
  29. package/dist/es/components/references/CitationEditor.js +13 -19
  30. package/dist/es/components/references/ImportBibliography.js +70 -0
  31. package/dist/es/components/references/ImportBibliographyForm.js +1 -1
  32. package/dist/es/components/references/ImportBibliographyModal.js +13 -79
  33. package/dist/es/components/references/ImportReferencesConfirmation.js +73 -0
  34. package/dist/es/components/references/ImportSuccessPlaceholder.js +49 -0
  35. package/dist/es/components/references/ReferenceSearch.js +3 -6
  36. package/dist/es/components/references/ReferencesEditor.js +19 -3
  37. package/dist/es/components/references/ReferencesModal.js +88 -35
  38. package/dist/es/components/views/CrossReferenceItems.js +141 -54
  39. package/dist/es/components/views/DeleteSupplementDialog.js +2 -2
  40. package/dist/es/lib/supplements.js +8 -1
  41. package/dist/es/lib/view.js +36 -0
  42. package/dist/es/menus.js +36 -1
  43. package/dist/es/plugins/objects.js +1 -1
  44. package/dist/es/toolbar.js +8 -2
  45. package/dist/es/versions.js +1 -1
  46. package/dist/es/views/bibliography_element.js +2 -3
  47. package/dist/es/views/citation_editable.js +3 -30
  48. package/dist/es/views/cross_reference.js +12 -2
  49. package/dist/es/views/cross_reference_editable.js +96 -5
  50. package/dist/es/views/figure_editable.js +3 -0
  51. package/dist/types/commands.d.ts +1 -0
  52. package/dist/types/components/form/FormFooter.d.ts +2 -1
  53. package/dist/types/components/references/CitationEditor.d.ts +1 -1
  54. package/dist/types/components/references/ImportBibliography.d.ts +7 -0
  55. package/dist/types/components/references/ImportReferencesConfirmation.d.ts +8 -0
  56. package/dist/types/components/references/ImportSuccessPlaceholder.d.ts +5 -0
  57. package/dist/types/components/references/ReferenceSearch.d.ts +0 -1
  58. package/dist/types/components/references/ReferencesEditor.d.ts +4 -1
  59. package/dist/types/components/references/ReferencesModal.d.ts +1 -0
  60. package/dist/types/components/views/CrossReferenceItems.d.ts +3 -0
  61. package/dist/types/lib/supplements.d.ts +1 -0
  62. package/dist/types/lib/view.d.ts +3 -1
  63. package/dist/types/versions.d.ts +1 -1
  64. package/dist/types/views/citation_editable.d.ts +0 -1
  65. package/dist/types/views/cross_reference_editable.d.ts +6 -0
  66. package/package.json +4 -4
  67. package/src/commands.ts +52 -10
  68. package/src/components/ChangeHandlingForm.tsx +4 -2
  69. package/src/components/form/FormFooter.tsx +3 -1
  70. package/src/components/keyboard-shortcuts-modal/KeyboardShortcutsModal.tsx +6 -7
  71. package/src/components/references/CitationEditor.tsx +16 -25
  72. package/src/components/references/ImportBibliography.tsx +119 -0
  73. package/src/components/references/ImportBibliographyForm.tsx +1 -1
  74. package/src/components/references/ImportBibliographyModal.tsx +34 -110
  75. package/src/components/references/ImportReferencesConfirmation.tsx +133 -0
  76. package/src/components/references/ImportSuccessPlaceholder.tsx +93 -0
  77. package/src/components/references/ReferenceSearch.tsx +0 -7
  78. package/src/components/references/ReferencesEditor.tsx +35 -6
  79. package/src/components/references/ReferencesModal.tsx +164 -78
  80. package/src/components/toolbar/InsertEmbedDialog.tsx +6 -2
  81. package/src/components/toolbar/type-selector/styles.ts +2 -1
  82. package/src/components/views/CrossReferenceItems.tsx +227 -100
  83. package/src/components/views/DeleteSupplementDialog.tsx +3 -6
  84. package/src/lib/footnotes.ts +3 -1
  85. package/src/lib/supplements.ts +13 -1
  86. package/src/lib/utils.ts +15 -4
  87. package/src/lib/view.ts +65 -0
  88. package/src/menus.tsx +39 -0
  89. package/src/plugins/add-subtitle.ts +18 -16
  90. package/src/plugins/objects.ts +2 -6
  91. package/src/toolbar.tsx +9 -0
  92. package/src/versions.ts +1 -1
  93. package/src/views/bibliography_element.ts +3 -4
  94. package/src/views/citation_editable.ts +5 -50
  95. package/src/views/cross_reference.ts +17 -3
  96. package/src/views/cross_reference_editable.ts +123 -11
  97. package/src/views/figure_editable.ts +4 -0
  98. package/src/views/supplement.ts +0 -1
  99. package/src/views/supplements.ts +2 -2
@@ -43,6 +43,8 @@ const react_1 = __importStar(require("react"));
43
43
  const styled_components_1 = __importDefault(require("styled-components"));
44
44
  const ReferenceForm_1 = require("./ReferenceForm/ReferenceForm");
45
45
  const ReferenceLine_1 = require("./ReferenceLine");
46
+ const ImportBibliographyModal_1 = require("./ImportBibliographyModal");
47
+ const ImportSuccessPlaceholder_1 = require("./ImportSuccessPlaceholder");
46
48
  const ReferencesModalContainer = (0, styled_components_1.default)(style_guide_1.ModalContainer) `
47
49
  min-width: 960px;
48
50
  `;
@@ -52,6 +54,33 @@ const ReferencesSidebar = (0, styled_components_1.default)(style_guide_1.ModalSi
52
54
  const ReferencesSidebarContent = (0, styled_components_1.default)(style_guide_1.SidebarContent) `
53
55
  overflow-y: auto;
54
56
  `;
57
+ const ImportFromFileFooter = styled_components_1.default.div `
58
+ padding: 16px;
59
+ `;
60
+ const ImportFromFileButton = styled_components_1.default.button `
61
+ display: flex;
62
+ width: 100%;
63
+ padding: 8px 24px;
64
+ justify-content: center;
65
+ align-items: center;
66
+ gap: 8px;
67
+ border-radius: 4px;
68
+ border: 1px dashed #c9c9c9;
69
+ background: #fafafa;
70
+ cursor: pointer;
71
+ font-family: ${(props) => props.theme.font.family.sans};
72
+ font-size: 14px;
73
+ color: #353535;
74
+
75
+ svg {
76
+ width: 20px;
77
+ height: 20px;
78
+ }
79
+
80
+ svg rect {
81
+ fill: #6e6e6e;
82
+ }
83
+ `;
55
84
  const ReferencesInnerWrapper = (0, style_guide_1.withListNavigation)(styled_components_1.default.div `
56
85
  width: 100%;
57
86
  padding: 12px 0;
@@ -139,15 +168,25 @@ const normalize = (item) => ({
139
168
  accessed: item.accessed,
140
169
  comment: item.comment || '',
141
170
  });
142
- const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts, onSave, onDelete, }) => {
171
+ const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts, onSave, onDelete, handleImport, }) => {
172
+ const [importing, setImporting] = (0, react_1.useState)(false);
173
+ const [importSuccessCount, setImportSuccessCount] = (0, react_1.useState)(null);
143
174
  const [confirm, setConfirm] = (0, react_1.useState)(false);
144
175
  const valuesRef = (0, react_1.useRef)(undefined);
145
176
  const [selection, setSelection] = (0, react_1.useState)();
146
177
  const selectionRef = (0, react_1.useRef)(null);
178
+ const sortedItems = (0, react_1.useMemo)(() => [...items].sort((a, b) => {
179
+ const aUncited = (citationCounts.get(a.id) ?? 0) === 0;
180
+ const bUncited = (citationCounts.get(b.id) ?? 0) === 0;
181
+ if (aUncited === bUncited) {
182
+ return 0;
183
+ }
184
+ return aUncited ? 1 : -1;
185
+ }), [items, citationCounts]);
147
186
  const isSelected = (item) => {
148
187
  return item.id === selection?.id;
149
188
  };
150
- const selectionIndex = items.findIndex(isSelected);
189
+ const selectionIndex = sortedItems.findIndex(isSelected);
151
190
  (0, react_1.useEffect)(() => {
152
191
  setSelection(item);
153
192
  }, [item]);
@@ -165,8 +204,8 @@ const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts, onSave
165
204
  (0, react_1.useEffect)(() => {
166
205
  const base = Math.max(0, selectionIndex - selectionTopOffset);
167
206
  setStartIndex(base);
168
- setEndIndex(Math.min(items.length - 1, base + pageSize));
169
- }, [selectionIndex, items]);
207
+ setEndIndex(Math.min(sortedItems.length - 1, base + pageSize));
208
+ }, [selectionIndex, sortedItems]);
170
209
  (0, react_1.useEffect)(() => {
171
210
  if (triggers.top) {
172
211
  const newFirst = Math.max(0, startIndex - pageSize);
@@ -174,11 +213,11 @@ const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts, onSave
174
213
  setEndIndex(Math.min(newFirst + dropLimit, endIndex));
175
214
  }
176
215
  if (triggers.bottom) {
177
- const newLast = Math.min(items.length - 1, endIndex + pageSize);
216
+ const newLast = Math.min(sortedItems.length - 1, endIndex + pageSize);
178
217
  setEndIndex(newLast);
179
218
  setStartIndex(Math.max(newLast - dropLimit, startIndex));
180
219
  }
181
- }, [triggers, items]);
220
+ }, [triggers, sortedItems]);
182
221
  const actionsRef = (0, react_1.useRef)(undefined);
183
222
  const reset = () => {
184
223
  actionsRef.current?.reset();
@@ -212,7 +251,9 @@ const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts, onSave
212
251
  onDelete(selection);
213
252
  setSelection(undefined);
214
253
  };
254
+ const clearImportSuccess = () => setImportSuccessCount(null);
215
255
  const handleItemClick = (item) => {
256
+ clearImportSuccess();
216
257
  const values = valuesRef.current;
217
258
  if (values && selection && !(0, isEqual_1.default)(values, normalize(selection))) {
218
259
  setConfirm(true);
@@ -223,34 +264,46 @@ const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts, onSave
223
264
  const handleChange = (values) => {
224
265
  valuesRef.current = values;
225
266
  };
226
- if (items.length <= 0) {
267
+ const handleImportSave = (data) => {
268
+ handleImport(data);
269
+ setImporting(false);
270
+ setSelection(undefined);
271
+ setImportSuccessCount(data.length);
272
+ };
273
+ if (sortedItems.length <= 0) {
227
274
  return react_1.default.createElement(react_1.default.Fragment, null);
228
275
  }
229
- return (react_1.default.createElement(style_guide_1.StyledModal, { isOpen: isOpen, onRequestClose: onCancel },
230
- react_1.default.createElement(style_guide_1.Dialog, { isOpen: confirm, category: style_guide_1.Category.confirmation, header: "You've made changes to this option", message: "Would you like to save or discard your changes?", actions: {
231
- secondary: {
232
- action: () => reset(),
233
- title: 'Discard',
234
- },
235
- primary: {
236
- action: () => handleSave(valuesRef.current),
237
- title: 'Save',
238
- },
239
- } }),
240
- react_1.default.createElement(ReferencesModalContainer, { "data-cy": 'references-editor' },
241
- react_1.default.createElement(style_guide_1.ModalHeader, null,
242
- react_1.default.createElement(style_guide_1.CloseButton, { onClick: onCancel })),
243
- react_1.default.createElement(style_guide_1.ModalBody, null,
244
- react_1.default.createElement(ReferencesSidebar, null,
245
- react_1.default.createElement(style_guide_1.ModalSidebarHeader, null,
246
- react_1.default.createElement(style_guide_1.ModalSidebarTitle, null, "References")),
247
- react_1.default.createElement(ReferencesSidebarContent, { ref: ref },
248
- react_1.default.createElement(ReferencesInnerWrapper, null, items.slice(startIndex, endIndex + 1).map((item) => (react_1.default.createElement(ReferenceButton, { key: item.id, id: item.id, className: isSelected(item) ? 'selected' : '', onClick: () => handleItemClick(item), ref: isSelected(item) ? selectionRef : null },
249
- react_1.default.createElement(IconContainer, null,
250
- react_1.default.createElement(style_guide_1.CitationCountIcon, null),
251
- (citationCounts.get(item.id) || 0) > 0 ? (react_1.default.createElement(CitationCount, { "data-tooltip-content": "Number of times used in the document" }, citationCounts.get(item.id))) : (react_1.default.createElement(CitationCount, { className: "unused" }, "0"))),
252
- react_1.default.createElement(ReferenceLine_1.ReferenceLine, { item: item }))))))),
253
- react_1.default.createElement(style_guide_1.ScrollableModalContent, null, selection && (react_1.default.createElement(ReferenceForm_1.ReferenceForm, { values: normalize(selection), showDelete: !citationCounts.get(selection.id) &&
254
- isNewItem(selection, ['id', 'type']), onChange: handleChange, onCancel: onCancel, onDelete: handleDelete, onSave: handleSave, actionsRef: actionsRef })))))));
276
+ return (react_1.default.createElement(react_1.default.Fragment, null,
277
+ importing && (react_1.default.createElement(ImportBibliographyModal_1.ImportBibliographyModal, { onCancel: () => setImporting(false), onSave: handleImportSave })),
278
+ react_1.default.createElement(style_guide_1.StyledModal, { isOpen: isOpen, onRequestClose: onCancel },
279
+ react_1.default.createElement(style_guide_1.Dialog, { isOpen: confirm, category: style_guide_1.Category.confirmation, header: "You've made changes to this option", message: "Would you like to save or discard your changes?", actions: {
280
+ secondary: {
281
+ action: () => reset(),
282
+ title: 'Discard',
283
+ },
284
+ primary: {
285
+ action: () => handleSave(valuesRef.current),
286
+ title: 'Save',
287
+ },
288
+ } }),
289
+ react_1.default.createElement(ReferencesModalContainer, { "data-cy": 'references-editor' },
290
+ react_1.default.createElement(style_guide_1.ModalHeader, null,
291
+ react_1.default.createElement(style_guide_1.CloseButton, { "data-cy": "modal-close-button", onClick: onCancel })),
292
+ react_1.default.createElement(style_guide_1.ModalBody, null,
293
+ react_1.default.createElement(ReferencesSidebar, null,
294
+ react_1.default.createElement(style_guide_1.ModalSidebarHeader, null,
295
+ react_1.default.createElement(style_guide_1.ModalSidebarTitle, null, "References")),
296
+ react_1.default.createElement(ReferencesSidebarContent, { ref: ref },
297
+ react_1.default.createElement(ReferencesInnerWrapper, null, sortedItems.slice(startIndex, endIndex + 1).map((item) => (react_1.default.createElement(ReferenceButton, { key: item.id, id: item.id, className: isSelected(item) ? 'selected' : '', onClick: () => handleItemClick(item), ref: isSelected(item) ? selectionRef : null },
298
+ react_1.default.createElement(IconContainer, null,
299
+ react_1.default.createElement(style_guide_1.CitationCountIcon, null),
300
+ (citationCounts.get(item.id) || 0) > 0 ? (react_1.default.createElement(CitationCount, { "data-tooltip-content": "Number of times used in the document" }, citationCounts.get(item.id))) : (react_1.default.createElement(CitationCount, { className: "unused" }, "0"))),
301
+ react_1.default.createElement(ReferenceLine_1.ReferenceLine, { item: item })))))),
302
+ react_1.default.createElement(ImportFromFileFooter, null,
303
+ react_1.default.createElement(ImportFromFileButton, { type: "button", "data-cy": "import-from-file-button", onClick: () => setImporting(true) },
304
+ react_1.default.createElement(style_guide_1.AddAuthorIcon, null),
305
+ "Import from file"))),
306
+ react_1.default.createElement(style_guide_1.ScrollableModalContent, null, importSuccessCount !== null ? (react_1.default.createElement(ImportSuccessPlaceholder_1.ImportSuccessPlaceholder, { count: importSuccessCount })) : (selection && (react_1.default.createElement(ReferenceForm_1.ReferenceForm, { values: normalize(selection), showDelete: !citationCounts.get(selection.id) &&
307
+ isNewItem(selection, ['id', 'type']), onChange: handleChange, onCancel: onCancel, onDelete: handleDelete, onSave: handleSave, actionsRef: actionsRef })))))))));
255
308
  };
256
309
  exports.ReferencesModal = ReferencesModal;
@@ -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;
@@ -48,7 +48,7 @@ var __importStar = (this && this.__importStar) || (function () {
48
48
  };
49
49
  })();
50
50
  Object.defineProperty(exports, "__esModule", { value: true });
51
- exports.deleteNode = exports.updateNodeAttrs = exports.findChildrenAttrsByType = exports.findChildrenByType = exports.findChildByType = exports.findChildByID = void 0;
51
+ exports.saveBibliographyItem = exports.insertBibliographyItems = exports.deleteNode = exports.updateNodeAttrs = exports.findChildrenAttrsByType = exports.findChildrenByType = exports.findChildByType = exports.findChildByID = void 0;
52
52
  const transform_1 = require("@manuscripts/transform");
53
53
  const prosemirror_state_1 = require("prosemirror-state");
54
54
  const utils = __importStar(require("prosemirror-utils"));
@@ -106,3 +106,41 @@ const deleteNode = (view, id) => {
106
106
  }
107
107
  };
108
108
  exports.deleteNode = deleteNode;
109
+ const createBibliographySection = (nodes) => transform_1.schema.nodes.bibliography_section.createAndFill({}, [
110
+ transform_1.schema.nodes.section_title.create({}, transform_1.schema.text('References')),
111
+ transform_1.schema.nodes.bibliography_element.create({}, nodes),
112
+ ]);
113
+ const insertBibliographyItems = (view, items) => {
114
+ const { doc } = view.state;
115
+ let tr = view.state.tr;
116
+ const biblioSection = utils.findChildrenByType(doc, transform_1.schema.nodes.bibliography_element, true);
117
+ if (biblioSection.length) {
118
+ let insertPos = biblioSection[0].pos + 1;
119
+ for (const attrs of items) {
120
+ const node = transform_1.schema.nodes.bibliography_item.create(attrs);
121
+ tr = tr.insert(insertPos, node);
122
+ insertPos += node.nodeSize;
123
+ }
124
+ }
125
+ else {
126
+ const backmatter = utils.findChildrenByType(doc, transform_1.schema.nodes.backmatter, true);
127
+ const backmatterEnd = backmatter[0]
128
+ ? backmatter[0].node.nodeSize + backmatter[0].pos
129
+ : 0;
130
+ const nodes = items.map((attrs) => transform_1.schema.nodes.bibliography_item.create(attrs));
131
+ tr = tr.insert(backmatterEnd ? backmatterEnd - 1 : tr.doc.content.size, createBibliographySection(nodes));
132
+ }
133
+ view.dispatch(tr);
134
+ };
135
+ exports.insertBibliographyItems = insertBibliographyItems;
136
+ const saveBibliographyItem = (view, attrs) => {
137
+ if (attrs.length === 1) {
138
+ const item = attrs[0];
139
+ if ((0, exports.findChildByID)(view, item.id)) {
140
+ (0, exports.updateNodeAttrs)(view, transform_1.schema.nodes.bibliography_item, item);
141
+ return;
142
+ }
143
+ }
144
+ (0, exports.insertBibliographyItems)(view, attrs);
145
+ };
146
+ exports.saveBibliographyItem = saveBibliographyItem;
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.2';
5
5
  exports.MATHJAX_VERSION = '3.2.2';
@@ -20,7 +20,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
21
  exports.BibliographyElementBlockView = void 0;
22
22
  const style_guide_1 = require("@manuscripts/style-guide");
23
- const transform_1 = require("@manuscripts/transform");
24
23
  const prosemirror_state_1 = require("prosemirror-state");
25
24
  const ReferencesEditor_1 = require("../components/references/ReferencesEditor");
26
25
  const comments_1 = require("../lib/comments");
@@ -92,7 +91,7 @@ class BibliographyElementBlockView extends block_view_1.default {
92
91
  this.dom.appendChild(this.container);
93
92
  };
94
93
  this.handleSave = (attrs) => {
95
- (0, view_1.updateNodeAttrs)(this.view, transform_1.schema.nodes.bibliography_item, attrs);
94
+ (0, view_1.saveBibliographyItem)(this.view, attrs);
96
95
  };
97
96
  this.handleDelete = (item) => {
98
97
  (0, view_1.deleteNode)(this.view, item.id);