@manuscripts/body-editor 3.17.3 → 3.18.0

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 (63) hide show
  1. package/dist/cjs/commands.js +13 -19
  2. package/dist/cjs/components/references/ReferenceLine.js +14 -1
  3. package/dist/cjs/components/references/ReferencesModal.js +155 -131
  4. package/dist/cjs/configs/editor-views.js +1 -0
  5. package/dist/cjs/icons.js +2 -2
  6. package/dist/cjs/lib/context-menu.js +4 -1
  7. package/dist/cjs/lib/normalize.js +31 -1
  8. package/dist/cjs/lib/paste.js +0 -1
  9. package/dist/cjs/menus.js +1 -1
  10. package/dist/cjs/node-type-icons.js +1 -0
  11. package/dist/cjs/plugins/add-subtitle.js +1 -1
  12. package/dist/cjs/plugins/bibliography.js +7 -1
  13. package/dist/cjs/plugins/section_category.js +5 -2
  14. package/dist/cjs/plugins/translations.js +9 -21
  15. package/dist/cjs/versions.js +1 -1
  16. package/dist/cjs/views/bibliography_element.js +44 -2
  17. package/dist/cjs/views/figure_element.js +1 -1
  18. package/dist/cjs/views/headshot_grid.js +1 -1
  19. package/dist/es/commands.js +13 -19
  20. package/dist/es/components/references/ReferenceLine.js +14 -1
  21. package/dist/es/components/references/ReferencesModal.js +156 -132
  22. package/dist/es/configs/editor-views.js +1 -0
  23. package/dist/es/icons.js +1 -1
  24. package/dist/es/lib/context-menu.js +4 -1
  25. package/dist/es/lib/normalize.js +30 -1
  26. package/dist/es/lib/paste.js +0 -1
  27. package/dist/es/menus.js +1 -1
  28. package/dist/es/node-type-icons.js +1 -0
  29. package/dist/es/plugins/add-subtitle.js +2 -2
  30. package/dist/es/plugins/bibliography.js +7 -1
  31. package/dist/es/plugins/section_category.js +6 -3
  32. package/dist/es/plugins/translations.js +11 -23
  33. package/dist/es/versions.js +1 -1
  34. package/dist/es/views/bibliography_element.js +45 -3
  35. package/dist/es/views/figure_element.js +2 -2
  36. package/dist/es/views/headshot_grid.js +2 -2
  37. package/dist/types/commands.d.ts +2 -2
  38. package/dist/types/components/references/ReferenceLine.d.ts +1 -0
  39. package/dist/types/icons.d.ts +1 -1
  40. package/dist/types/lib/normalize.d.ts +30 -1
  41. package/dist/types/versions.d.ts +1 -1
  42. package/dist/types/views/bibliography_element.d.ts +5 -1
  43. package/package.json +2 -2
  44. package/src/commands.ts +22 -35
  45. package/src/components/references/ReferenceLine.tsx +16 -1
  46. package/src/components/references/ReferencesModal.tsx +178 -140
  47. package/src/configs/editor-views.ts +1 -0
  48. package/src/icons.ts +1 -1
  49. package/src/lib/context-menu.ts +4 -1
  50. package/src/lib/normalize.ts +36 -1
  51. package/src/lib/paste.ts +0 -1
  52. package/src/menus.tsx +1 -1
  53. package/src/node-type-icons.tsx +1 -0
  54. package/src/plugins/add-subtitle.ts +2 -2
  55. package/src/plugins/bibliography.ts +10 -3
  56. package/src/plugins/section_category.ts +7 -2
  57. package/src/plugins/translations.ts +18 -29
  58. package/src/versions.ts +1 -1
  59. package/src/views/bibliography_element.ts +61 -4
  60. package/src/views/figure_element.ts +2 -2
  61. package/src/views/headshot_grid.ts +2 -2
  62. package/styles/AdvancedEditor.css +29 -2
  63. package/styles/Editor.css +7 -0
@@ -21,8 +21,8 @@ const prosemirror_view_1 = require("prosemirror-view");
21
21
  const commands_1 = require("../commands");
22
22
  const icons_1 = require("../icons");
23
23
  const languages_1 = require("../lib/languages");
24
- const template_1 = require("../lib/template");
25
24
  const navigation_utils_1 = require("../lib/navigation-utils");
25
+ const template_1 = require("../lib/template");
26
26
  const createMenuItem = (props, contents, handler, isSelected = false, tabIndex) => {
27
27
  const item = document.createElement('div');
28
28
  item.className = `menu-item ${isSelected ? 'selected' : ''}`;
@@ -60,10 +60,6 @@ const createLanguageMenu = (props, selectedCode, onSelect) => {
60
60
  });
61
61
  return { menu, destroy };
62
62
  };
63
- const getInsertionPos = (doc, nodePos) => {
64
- const node = doc.nodeAt(nodePos);
65
- return node ? nodePos + node.nodeSize : null;
66
- };
67
63
  exports.default = (props) => new prosemirror_state_1.Plugin({
68
64
  props: {
69
65
  decorations: (state) => {
@@ -74,14 +70,11 @@ exports.default = (props) => new prosemirror_state_1.Plugin({
74
70
  const canEditTransGraphicalAbstract = can.editArticle &&
75
71
  (0, template_1.templateAllows)(state, transform_1.schema.nodes.trans_graphical_abstract);
76
72
  const widgets = [];
77
- state.doc.descendants((node, pos, parent) => {
78
- const isAbstractSection = (node.type === transform_1.schema.nodes.section ||
79
- node.type === transform_1.schema.nodes.graphical_abstract_section) &&
80
- parent?.type === transform_1.schema.nodes.abstracts;
73
+ state.doc.descendants((node, pos) => {
74
+ const isAbstractSection = (0, transform_1.isAbstractNode)(node) || (0, transform_1.isGraphicalAbstractSectionNode)(node);
81
75
  if (isAbstractSection) {
82
- const isGraphical = node.type === transform_1.schema.nodes.graphical_abstract_section;
83
76
  const category = props.sectionCategories.get(node.attrs.category);
84
- const canEdit = isGraphical
77
+ const canEdit = (0, transform_1.isGraphicalAbstractSectionNode)(node)
85
78
  ? canEditTransGraphicalAbstract &&
86
79
  category &&
87
80
  (0, commands_1.insertTransGraphicalAbstract)(category)(state)
@@ -92,19 +85,15 @@ exports.default = (props) => new prosemirror_state_1.Plugin({
92
85
  $span.tabIndex = 0;
93
86
  $span.className = 'add-trans-abstract';
94
87
  $span.title = 'Add translation';
95
- $span.innerHTML = `${icons_1.addAuthorIcon} <span class="add-trans-abstract-text">Add translation</span>`;
88
+ $span.innerHTML = `${icons_1.addIcon} <span class="add-trans-abstract-text">Add translation</span>`;
96
89
  const handleActivate = (event) => {
97
90
  event.preventDefault();
98
91
  event.stopPropagation();
99
- const insertPos = getInsertionPos(view.state.doc, pos);
100
- if (insertPos == null) {
101
- return;
102
- }
103
- if (isGraphical && category) {
104
- (0, commands_1.insertTransGraphicalAbstract)(category, insertPos)(view.state, view.dispatch, view);
92
+ if ((0, transform_1.isGraphicalAbstractSectionNode)(node) && category) {
93
+ (0, commands_1.insertTransGraphicalAbstract)(category)(view.state, view.dispatch, view);
105
94
  }
106
95
  else {
107
- (0, commands_1.insertTransAbstract)(view.state, view.dispatch, node.attrs.category, insertPos);
96
+ (0, commands_1.insertTransAbstract)(view.state, view.dispatch, node.attrs.category);
108
97
  }
109
98
  };
110
99
  $span.addEventListener('mousedown', handleActivate);
@@ -113,8 +102,7 @@ exports.default = (props) => new prosemirror_state_1.Plugin({
113
102
  }, { key: `add-trans-${node.attrs.id}-${pos}` }));
114
103
  }
115
104
  }
116
- const isTransNode = node.type === transform_1.schema.nodes.trans_abstract ||
117
- node.type === transform_1.schema.nodes.trans_graphical_abstract;
105
+ const isTransNode = (0, transform_1.isTransAbstractNode)(node) || (0, transform_1.isTransGraphicalAbstractNode)(node);
118
106
  if (isTransNode) {
119
107
  const canEdit = node.type === transform_1.schema.nodes.trans_abstract
120
108
  ? canEditTransAbstract
@@ -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.17.3';
4
+ exports.VERSION = '3.18.0';
5
5
  exports.MATHJAX_VERSION = '3.2.2';
@@ -20,6 +20,7 @@ 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");
23
24
  const prosemirror_state_1 = require("prosemirror-state");
24
25
  const ReferencesEditor_1 = require("../components/references/ReferencesEditor");
25
26
  const comments_1 = require("../lib/comments");
@@ -34,6 +35,7 @@ const block_view_1 = __importDefault(require("./block_view"));
34
35
  const creators_1 = require("./creators");
35
36
  const ReactSubView_1 = __importDefault(require("./ReactSubView"));
36
37
  const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
38
+ const icons_1 = require("../icons");
37
39
  class BibliographyElementBlockView extends block_view_1.default {
38
40
  constructor() {
39
41
  super(...arguments);
@@ -138,7 +140,7 @@ class BibliographyElementBlockView extends block_view_1.default {
138
140
  const componentProps = {
139
141
  items: Array.from(bib.bibliographyItems.values()),
140
142
  citationCounts: bib.citationCounts,
141
- item: bib.bibliographyItems.get(id),
143
+ item: id ? bib.bibliographyItems.get(id) : undefined,
142
144
  onSave: this.handleSave,
143
145
  onDelete: this.handleDelete,
144
146
  };
@@ -181,7 +183,18 @@ class BibliographyElementBlockView extends block_view_1.default {
181
183
  return;
182
184
  }
183
185
  this.version = bib.version;
186
+ this.renderBibs(bib);
187
+ this.createInlineModalButton();
188
+ this.updateSelections();
189
+ }
190
+ renderBibs(bib) {
184
191
  const nodes = new Map();
192
+ const rids = [];
193
+ this.view.state.doc.descendants((node) => {
194
+ if ((0, transform_1.isCitationNode)(node)) {
195
+ rids.push(...node.attrs.rids);
196
+ }
197
+ });
185
198
  this.node.descendants((node) => {
186
199
  const id = node.attrs.id;
187
200
  nodes.set(id, node);
@@ -219,6 +232,12 @@ class BibliographyElementBlockView extends block_view_1.default {
219
232
  element.tabIndex = 0;
220
233
  const comment = (0, comments_1.createCommentMarker)('div', id);
221
234
  element.prepend(comment);
235
+ if (!rids.includes(id)) {
236
+ const uncitedMarker = document.createElement('span');
237
+ uncitedMarker.innerHTML = 'UNCITED';
238
+ uncitedMarker.classList.add('uncited-reference-marker');
239
+ element.prepend(uncitedMarker);
240
+ }
222
241
  (0, track_changes_plugin_1.addTrackChangesAttributes)(node.attrs, element);
223
242
  (0, track_changes_plugin_1.addTrackChangesClassNames)(node.attrs, element);
224
243
  wrapper.append(element);
@@ -236,7 +255,30 @@ class BibliographyElementBlockView extends block_view_1.default {
236
255
  else {
237
256
  this.container.appendChild(wrapper);
238
257
  }
239
- this.updateSelections();
258
+ }
259
+ createInlineModalButton() {
260
+ const can = this.props.getCapabilities();
261
+ if (!can.editCitationsAndRefs) {
262
+ if (this.inlineModalButton) {
263
+ this.inlineModalButton.remove();
264
+ this.inlineModalButton = null;
265
+ }
266
+ return;
267
+ }
268
+ if (this.inlineModalButton) {
269
+ return;
270
+ }
271
+ const $span = document.createElement('span');
272
+ $span.tabIndex = 0;
273
+ $span.className = 'add-new-reference add-trans-abstract';
274
+ $span.title = 'Add New Reference';
275
+ $span.innerHTML = `${icons_1.addIcon} <span type="button" tabindex="0" class="add-new-reference-text">Add new reference</span>`;
276
+ $span.addEventListener('click', (e) => {
277
+ this.showPopper();
278
+ });
279
+ $span.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(() => this.showPopper()));
280
+ this.inlineModalButton = $span;
281
+ this.dom.appendChild($span);
240
282
  }
241
283
  }
242
284
  exports.BibliographyElementBlockView = BibliographyElementBlockView;
@@ -71,7 +71,7 @@ class FigureElementView extends image_element_1.ImageElementView {
71
71
  if (this.props.getCapabilities()?.editArticle) {
72
72
  this.addFigureBtn = Object.assign(document.createElement('button'), {
73
73
  className: 'add-button',
74
- innerHTML: icons_1.addAuthorIcon,
74
+ innerHTML: icons_1.addIcon,
75
75
  title: 'Add figure',
76
76
  });
77
77
  this.addFigureBtn.addEventListener('click', () => this.addFigure());
@@ -51,7 +51,7 @@ class HeadshotGridView extends block_view_1.default {
51
51
  this.addHeadshotButton.classList.add('add-headshot-element-button');
52
52
  this.addHeadshotButton.setAttribute('data-cy', 'headshot-add');
53
53
  this.addHeadshotButton.contentEditable = 'false';
54
- this.addHeadshotButton.innerHTML = icons_1.addAuthorIcon;
54
+ this.addHeadshotButton.innerHTML = icons_1.addIcon;
55
55
  const buttonText = document.createElement('span');
56
56
  buttonText.classList.add('add-headshot-element-text');
57
57
  buttonText.innerText = 'Add Headshot';
@@ -717,16 +717,14 @@ export const insertAbstractSection = (category) => (state, dispatch, view) => {
717
717
  return false;
718
718
  }
719
719
  const abstracts = findAbstractsNode(state.doc);
720
- const sections = findChildrenByType(abstracts.node, schema.nodes.section);
721
- if (sections.some((s) => s.node.attrs.category === category.id)) {
720
+ const abstractNodes = findChildrenByType(abstracts.node, schema.nodes.abstract);
721
+ if (abstractNodes.some((s) => s.node.attrs.category === category.id)) {
722
722
  return false;
723
723
  }
724
- const ga = findChildrenByType(state.doc, schema.nodes.graphical_abstract_section)[0];
725
- let pos = ga ? ga.pos : abstracts.pos + abstracts.node.content.size + 1;
726
- if (category.id === 'abstract') {
727
- pos = abstracts.pos + 1;
728
- }
729
- const node = schema.nodes.section.create({ category: category.id }, [
724
+ const pos = findInsertionPosition(schema.nodes.abstract, abstracts.node) +
725
+ abstracts.pos +
726
+ 1;
727
+ const node = schema.nodes.abstract.create({ category: category.id }, [
730
728
  schema.nodes.section_title.create({}, schema.text(category.titles[0])),
731
729
  schema.nodes.paragraph.create({ placeholder: 'Type abstract here...' }),
732
730
  ]);
@@ -776,9 +774,9 @@ export const insertGraphicalAbstract = (category) => (state, dispatch, view) =>
776
774
  if (sections.some((s) => s.node.attrs.category === category.id)) {
777
775
  return false;
778
776
  }
779
- const ga = findChildrenByType(state.doc, schema.nodes.graphical_abstract_section)[0];
780
- let pos = abstracts.pos + abstracts.node.content.size + 1;
781
- pos = ga && category.id === 'abstract-key-image' ? ga.pos : pos;
777
+ const pos = findInsertionPosition(schema.nodes.graphical_abstract_section, abstracts.node) +
778
+ abstracts.pos +
779
+ 1;
782
780
  const node = schema.nodes.graphical_abstract_section.createAndFill({ category: category.id }, [
783
781
  schema.nodes.section_title.create({}, schema.text(category.titles[0])),
784
782
  createAndFillFigureElement(state),
@@ -982,7 +980,7 @@ export const insertBibliographySection = () => {
982
980
  export const insertTOCSection = () => {
983
981
  return false;
984
982
  };
985
- export const insertTransAbstract = (state, dispatch, category, insertAfterPos) => {
983
+ export const insertTransAbstract = (state, dispatch, category) => {
986
984
  if (!templateAllows(state, schema.nodes.trans_abstract)) {
987
985
  return false;
988
986
  }
@@ -997,16 +995,14 @@ export const insertTransAbstract = (state, dispatch, category, insertAfterPos) =
997
995
  category,
998
996
  }, [title, paragraph]);
999
997
  const abstracts = findAbstractsNode(state.doc);
1000
- const pos = insertAfterPos != null
1001
- ? insertAfterPos
1002
- : abstracts.pos + abstracts.node.nodeSize - 1;
998
+ const pos = abstracts.node.content.size + abstracts.pos + 1;
1003
999
  const tr = state.tr.insert(pos, node);
1004
1000
  const selection = TextSelection.create(tr.doc, pos + 1);
1005
1001
  tr.setSelection(selection).scrollIntoView();
1006
1002
  dispatch(tr);
1007
1003
  return true;
1008
1004
  };
1009
- export const insertTransGraphicalAbstract = (category, insertAfterPos) => (state, dispatch, view) => {
1005
+ export const insertTransGraphicalAbstract = (category) => (state, dispatch, view) => {
1010
1006
  if (!templateAllows(state, schema.nodes.trans_graphical_abstract)) {
1011
1007
  return false;
1012
1008
  }
@@ -1015,9 +1011,7 @@ export const insertTransGraphicalAbstract = (category, insertAfterPos) => (state
1015
1011
  }
1016
1012
  const lang = state.doc.attrs.primaryLanguageCode || 'en';
1017
1013
  const abstracts = findAbstractsNode(state.doc);
1018
- const pos = insertAfterPos != null
1019
- ? insertAfterPos
1020
- : abstracts.pos + abstracts.node.content.size + 1;
1014
+ const pos = abstracts.node.content.size + abstracts.pos + 1;
1021
1015
  const node = schema.nodes.trans_graphical_abstract.createAndFill({
1022
1016
  lang,
1023
1017
  category: category.id,
@@ -23,8 +23,21 @@ export const Metadata = styled.div `
23
23
  margin-top: ${(props) => props.theme.grid.unit}px;
24
24
  `;
25
25
  export const MetadataContainer = styled.div `
26
+ position: relative;
26
27
  flex: 1;
27
28
  `;
28
- export const ReferenceLine = ({ item }) => (React.createElement(MetadataContainer, null,
29
+ export const ReferenceLine = ({ item, showUncited }) => (React.createElement(MetadataContainer, null,
30
+ showUncited && React.createElement(UncitedBadge, null, "UNCITED"),
29
31
  React.createElement("div", { "data-cy": 'reference-title' }, item.title || item.literal || 'Untitled'),
30
32
  React.createElement(Metadata, null, metadata(item))));
33
+ const UncitedBadge = styled.span `
34
+ padding: 1px 6px;
35
+ display: flex;
36
+ margin-bottom: 2px;
37
+ max-width: max-content;
38
+ border-radius: 4px;
39
+ color: #353535;
40
+ background-color: #f7b314;
41
+ font-size: 10px;
42
+ font-weight: 500;
43
+ `;
@@ -1,4 +1,5 @@
1
- import { AddAuthorIcon, Category, CitationCountIcon, CloseButton, Dialog, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, ScrollableModalContent, SidebarContent, StyledModal, useScrollDetection, withListNavigation, withNavigableListItem, } from '@manuscripts/style-guide';
1
+ import { AddIcon, AddAuthorIcon, Category, CitationCountIcon, CloseButton, Dialog, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, ScrollableModalContent, SidebarContent, StyledModal, useScrollDetection, withListNavigation, withNavigableListItem, } from '@manuscripts/style-guide';
2
+ import { generateNodeID, schema, } from '@manuscripts/transform';
2
3
  import isEqual from 'lodash/isEqual';
3
4
  import React, { useEffect, useMemo, useRef, useState } from 'react';
4
5
  import styled from 'styled-components';
@@ -6,135 +7,19 @@ import { ReferenceForm, } from './ReferenceForm/ReferenceForm';
6
7
  import { ReferenceLine } from './ReferenceLine';
7
8
  import { ImportBibliographyModal } from './ImportBibliographyModal';
8
9
  import { ImportSuccessPlaceholder } from './ImportSuccessPlaceholder';
9
- const ReferencesModalContainer = styled(ModalContainer) `
10
- min-width: 960px;
11
- `;
12
- const ReferencesSidebar = styled(ModalSidebar) `
13
- width: 70%;
14
- `;
15
- const ReferencesSidebarContent = styled(SidebarContent) `
16
- overflow-y: auto;
17
- `;
18
- const ImportFromFileFooter = styled.div `
19
- padding: 16px;
20
- `;
21
- const ImportFromFileButton = styled.button `
22
- display: flex;
23
- width: 100%;
24
- padding: 8px 24px;
25
- justify-content: center;
26
- align-items: center;
27
- gap: 8px;
28
- border-radius: 4px;
29
- border: 1px dashed #c9c9c9;
30
- background: #fafafa;
31
- cursor: pointer;
32
- font-family: ${(props) => props.theme.font.family.sans};
33
- font-size: 14px;
34
- color: #353535;
35
-
36
- svg {
37
- width: 20px;
38
- height: 20px;
39
- }
40
-
41
- svg rect {
42
- fill: #6e6e6e;
43
- }
44
- `;
45
- const ReferencesInnerWrapper = withListNavigation(styled.div `
46
- width: 100%;
47
- padding: 12px 0;
48
- `);
49
- const ReferenceButton = withNavigableListItem(styled.div `
50
- cursor: pointer;
51
- display: flex;
52
- justify-content: flex-start;
53
- padding: ${(props) => props.theme.grid.unit * 4}px 0;
54
- border-top: 1px solid transparent;
55
- border-bottom: 1px solid transparent;
56
-
57
- path {
58
- fill: #c9c9c9;
59
- }
60
-
61
- &:hover {
62
- background: ${(props) => props.theme.colors.background.info};
63
- }
64
-
65
- &.selected {
66
- background: ${(props) => props.theme.colors.background.info};
67
- border-top-color: #bce7f6;
68
- border-bottom-color: #bce7f6;
69
- }
70
-
71
- .tooltip {
72
- max-width: ${(props) => props.theme.grid.unit * 25}px;
73
- padding: ${(props) => props.theme.grid.unit * 2}px;
74
- border-radius: 6px;
75
- }
76
- `);
77
- const IconContainer = styled.div `
78
- padding-right: ${(props) => props.theme.grid.unit * 5}px;
79
- position: relative;
80
- `;
81
- const CitationCount = styled.div `
82
- border-radius: 50%;
83
- width: 12px;
84
- height: 12px;
85
- position: absolute;
86
- color: #ffffff;
87
- background-color: #bce7f6;
88
- text-align: center;
89
- vertical-align: top;
90
- top: 0;
91
- left: 16px;
92
- font-size: 9px;
93
-
94
- &.unused {
95
- background-color: #fe8f1f;
96
- }
97
- `;
10
+ import { normalizeBlblioItem } from '../../lib/normalize';
98
11
  const selectionTopOffset = 10;
99
12
  const pageSize = 12;
100
13
  const topTrigger = 0.2;
101
14
  const bottomTrigger = 0.8;
102
15
  const dropLimit = 36;
103
- const normalize = (item) => ({
104
- id: item.id,
105
- type: item.type,
106
- author: item.author || [],
107
- editor: item.editor || [],
108
- issued: item.issued,
109
- ['container-title']: item['container-title'] || '',
110
- ['collection-title']: item['collection-title'] || '',
111
- DOI: item.DOI || '',
112
- URL: item.URL || '',
113
- volume: item.volume || '',
114
- issue: item.issue || '',
115
- supplement: item.supplement || '',
116
- edition: item.edition || '',
117
- page: item.page || '',
118
- ['number-of-pages']: item['number-of-pages'] || '',
119
- title: item.title || '',
120
- literal: item.literal || '',
121
- std: item.std || '',
122
- publisher: item.publisher || '',
123
- ['publisher-place']: item['publisher-place'] || '',
124
- event: item.event || '',
125
- ['event-place']: item['event-place'] || '',
126
- ['event-date']: item['event-date'],
127
- institution: item.institution || '',
128
- locator: item.locator || '',
129
- accessed: item.accessed,
130
- comment: item.comment || '',
131
- });
132
16
  export const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts, onSave, onDelete, handleImport, }) => {
133
17
  const [importing, setImporting] = useState(false);
134
18
  const [importSuccessCount, setImportSuccessCount] = useState(null);
135
19
  const [confirm, setConfirm] = useState(false);
136
20
  const valuesRef = useRef(undefined);
137
21
  const [selection, setSelection] = useState();
22
+ const [isNew, setIsNew] = useState(false);
138
23
  const selectionRef = useRef(null);
139
24
  const sortedItems = useMemo(() => [...items].sort((a, b) => {
140
25
  const aUncited = (citationCounts.get(a.id) ?? 0) === 0;
@@ -149,7 +34,17 @@ export const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts,
149
34
  };
150
35
  const selectionIndex = sortedItems.findIndex(isSelected);
151
36
  useEffect(() => {
152
- setSelection(item);
37
+ if (item) {
38
+ setSelection(item);
39
+ setIsNew(false);
40
+ }
41
+ else {
42
+ setIsNew(true);
43
+ setSelection({
44
+ id: generateNodeID(schema.nodes.bibliography_item),
45
+ type: 'article-journal',
46
+ });
47
+ }
153
48
  }, [item]);
154
49
  useEffect(() => {
155
50
  setTimeout(() => {
@@ -199,10 +94,11 @@ export const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts,
199
94
  };
200
95
  const currentCitationCount = citationCounts.get(item.id);
201
96
  if (currentCitationCount === undefined) {
202
- citationCounts.set(item.id, 1);
97
+ citationCounts.set(item.id, 0);
203
98
  }
204
99
  onSave(item);
205
100
  setSelection(item);
101
+ setIsNew(false);
206
102
  setConfirm(false);
207
103
  };
208
104
  const handleDelete = () => {
@@ -212,14 +108,18 @@ export const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts,
212
108
  onDelete(selection);
213
109
  setSelection(undefined);
214
110
  };
111
+ const hasChanged = () => {
112
+ const values = valuesRef.current;
113
+ return (values && selection && !isEqual(values, normalizeBlblioItem(selection)));
114
+ };
215
115
  const clearImportSuccess = () => setImportSuccessCount(null);
216
116
  const handleItemClick = (item) => {
217
117
  clearImportSuccess();
218
- const values = valuesRef.current;
219
- if (values && selection && !isEqual(values, normalize(selection))) {
118
+ if (hasChanged()) {
220
119
  setConfirm(true);
221
120
  return;
222
121
  }
122
+ setIsNew(false);
223
123
  setSelection(item);
224
124
  };
225
125
  const handleChange = (values) => {
@@ -231,9 +131,6 @@ export const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts,
231
131
  setSelection(undefined);
232
132
  setImportSuccessCount(data.length);
233
133
  };
234
- if (sortedItems.length <= 0) {
235
- return React.createElement(React.Fragment, null);
236
- }
237
134
  return (React.createElement(React.Fragment, null,
238
135
  importing && (React.createElement(ImportBibliographyModal, { onCancel: () => setImporting(false), onSave: handleImportSave })),
239
136
  React.createElement(StyledModal, { isOpen: isOpen, onRequestClose: onCancel },
@@ -255,15 +152,142 @@ export const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts,
255
152
  React.createElement(ModalSidebarHeader, null,
256
153
  React.createElement(ModalSidebarTitle, null, "References")),
257
154
  React.createElement(ReferencesSidebarContent, { ref: ref },
258
- React.createElement(ReferencesInnerWrapper, null, sortedItems.slice(startIndex, endIndex + 1).map((item) => (React.createElement(ReferenceButton, { key: item.id, id: item.id, className: isSelected(item) ? 'selected' : '', onClick: () => handleItemClick(item), ref: isSelected(item) ? selectionRef : null },
259
- React.createElement(IconContainer, null,
260
- React.createElement(CitationCountIcon, null),
261
- (citationCounts.get(item.id) || 0) > 0 ? (React.createElement(CitationCount, { "data-tooltip-content": "Number of times used in the document" }, citationCounts.get(item.id))) : (React.createElement(CitationCount, { className: "unused" }, "0"))),
262
- React.createElement(ReferenceLine, { item: item })))))),
155
+ React.createElement(NewReferenceButton, { onClick: () => {
156
+ if (hasChanged()) {
157
+ setConfirm(true);
158
+ return;
159
+ }
160
+ setIsNew(true);
161
+ setSelection({
162
+ id: generateNodeID(schema.nodes.bibliography_item),
163
+ type: 'article-journal',
164
+ });
165
+ }, className: isNew ? 'selected' : '', disabled: isNew },
166
+ React.createElement(AddIcon, null),
167
+ React.createElement("span", null, "New Reference")),
168
+ React.createElement(ReferencesInnerWrapper, null,
169
+ React.createElement(ExistingReferencesHeading, null, "Existing References"),
170
+ sortedItems.slice(startIndex, endIndex + 1).map((item) => (React.createElement(ReferenceButton, { key: item.id, id: item.id, className: isSelected(item) ? 'selected' : '', onClick: () => handleItemClick(item), ref: isSelected(item) ? selectionRef : null },
171
+ React.createElement(IconContainer, null,
172
+ React.createElement(CitationCountIconStyled, null),
173
+ (citationCounts.get(item.id) || 0) > 0 ? (React.createElement(CitationCount, { "data-tooltip-content": "Number of times used in the document" }, citationCounts.get(item.id))) : (React.createElement(CitationCount, { className: "unused" }, "0"))),
174
+ React.createElement(ReferenceLine, { showUncited: !citationCounts.get(item.id), item: item })))))),
263
175
  React.createElement(ImportFromFileFooter, null,
264
176
  React.createElement(ImportFromFileButton, { type: "button", "data-cy": "import-from-file-button", onClick: () => setImporting(true) },
265
177
  React.createElement(AddAuthorIcon, null),
266
178
  "Import from file"))),
267
- React.createElement(ScrollableModalContent, null, importSuccessCount !== null ? (React.createElement(ImportSuccessPlaceholder, { count: importSuccessCount })) : (selection && (React.createElement(ReferenceForm, { values: normalize(selection), showDelete: !citationCounts.get(selection.id) &&
179
+ React.createElement(ScrollableModalContent, null, importSuccessCount !== null ? (React.createElement(ImportSuccessPlaceholder, { count: importSuccessCount })) : (selection && (React.createElement(ReferenceForm, { values: normalizeBlblioItem(selection), showDelete: !citationCounts.get(selection.id) &&
268
180
  isNewItem(selection, ['id', 'type']), onChange: handleChange, onCancel: onCancel, onDelete: handleDelete, onSave: handleSave, actionsRef: actionsRef })))))))));
269
181
  };
182
+ const ReferencesModalContainer = styled(ModalContainer) `
183
+ min-width: 960px;
184
+ `;
185
+ const ReferencesSidebar = styled(ModalSidebar) `
186
+ width: 70%;
187
+ `;
188
+ const ReferencesSidebarContent = styled(SidebarContent) `
189
+ overflow-y: auto;
190
+ `;
191
+ const ReferencesInnerWrapper = withListNavigation(styled.div `
192
+ width: 100%;
193
+ padding: 12px 0;
194
+ `);
195
+ const CitationCountIconStyled = styled(CitationCountIcon) ``;
196
+ const ReferenceButton = withNavigableListItem(styled.button `
197
+ cursor: pointer;
198
+ display: flex;
199
+ width: 100%;
200
+ justify-content: flex-start;
201
+ font: inherit;
202
+ appearance: none;
203
+ -webkit-appearance: none;
204
+ background: none;
205
+ border: none;
206
+ border-radius: 0;
207
+ text-align: inherit;
208
+
209
+ padding: ${(props) => props.theme.grid.unit * 4}px 0;
210
+ border-top: 1px solid transparent;
211
+ border-bottom: 1px solid transparent;
212
+
213
+ ${CitationCountIconStyled} path {
214
+ fill: #c9c9c9;
215
+ }
216
+
217
+ &:hover {
218
+ background: ${(props) => props.theme.colors.background.info};
219
+ }
220
+
221
+ &.selected {
222
+ background: ${(props) => props.theme.colors.background.info};
223
+ border-top-color: #bce7f6;
224
+ border-bottom-color: #bce7f6;
225
+ }
226
+
227
+ .tooltip {
228
+ max-width: ${(props) => props.theme.grid.unit * 25}px;
229
+ padding: ${(props) => props.theme.grid.unit * 2}px;
230
+ border-radius: 6px;
231
+ }
232
+ `);
233
+ const IconContainer = styled.div `
234
+ padding-right: ${(props) => props.theme.grid.unit * 5}px;
235
+ position: relative;
236
+ `;
237
+ const CitationCount = styled.div `
238
+ border-radius: 50%;
239
+ width: 12px;
240
+ height: 12px;
241
+ position: absolute;
242
+ color: #ffffff;
243
+ background-color: #bce7f6;
244
+ text-align: center;
245
+ vertical-align: top;
246
+ top: 0;
247
+ left: 16px;
248
+ font-size: 9px;
249
+
250
+ &.unused {
251
+ background-color: #fe8f1f;
252
+ }
253
+ `;
254
+ const NewReferenceButton = styled(ReferenceButton) `
255
+ svg {
256
+ margin-right: 8px;
257
+ }
258
+ `;
259
+ const ExistingReferencesHeading = styled.h3 `
260
+ font-size: 18px;
261
+ font-style: normal;
262
+ font-weight: 400;
263
+ padding: 8px 0 20px;
264
+ margin: 0;
265
+ color: #6e6e6e;
266
+ `;
267
+ const ImportFromFileFooter = styled.div `
268
+ padding: 16px;
269
+ `;
270
+ const ImportFromFileButton = styled.button `
271
+ display: flex;
272
+ width: 100%;
273
+ padding: 8px 24px;
274
+ justify-content: center;
275
+ align-items: center;
276
+ gap: 8px;
277
+ border-radius: 4px;
278
+ border: 1px dashed #c9c9c9;
279
+ background: #fafafa;
280
+ cursor: pointer;
281
+ font-family: ${(props) => props.theme.font.family.sans};
282
+ font-size: 14px;
283
+ color: #353535;
284
+
285
+ svg {
286
+ width: 20px;
287
+ height: 20px;
288
+ }
289
+
290
+ svg rect {
291
+ fill: #6e6e6e;
292
+ }
293
+ `;
@@ -113,6 +113,7 @@ export default (props, dispatch) => {
113
113
  headshot_element: headshotElement(props, dispatch),
114
114
  headshot_image: headshotImage(props, dispatch),
115
115
  abstracts: abstracts(props),
116
+ abstract: section(props),
116
117
  trans_abstract: transAbstract(props),
117
118
  trans_graphical_abstract: transGraphicalAbstract(props),
118
119
  attachment: attachment(props, dispatch),
package/dist/es/icons.js CHANGED
@@ -2,7 +2,7 @@ import { AddAuthorIcon, AlertIcon, ArrowDownCircleIcon, ArrowUpIcon, CameraIcon,
2
2
  import { createElement } from 'react';
3
3
  import { renderToStaticMarkup } from 'react-dom/server';
4
4
  const renderIcon = (c) => renderToStaticMarkup(createElement(c));
5
- export const addAuthorIcon = renderIcon(AddAuthorIcon);
5
+ export const addIcon = renderIcon(AddAuthorIcon);
6
6
  export const arrowDown = renderIcon(ArrowDownCircleIcon);
7
7
  export const arrowUp = renderIcon(ArrowUpIcon);
8
8
  export const alertIcon = renderIcon(AlertIcon);