@manuscripts/body-editor 1.7.19 → 1.7.20

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 (83) hide show
  1. package/dist/cjs/components/authors/AffiliationButton.js +105 -0
  2. package/dist/cjs/components/authors/AffiliationForm.js +50 -0
  3. package/dist/cjs/components/authors/AuthorActions.js +61 -0
  4. package/dist/cjs/components/authors/AuthorAffiliations.js +116 -0
  5. package/dist/cjs/components/authors/AuthorDetailsForm.js +97 -0
  6. package/dist/cjs/components/authors/AuthorFormPlaceholder.js +57 -0
  7. package/dist/cjs/components/authors/AuthorList.js +40 -0
  8. package/dist/cjs/components/authors/AuthorsModal.js +226 -0
  9. package/dist/cjs/components/authors/ChangeHandlingForm.js +37 -0
  10. package/dist/cjs/components/authors/DeleteAuthorConfirmationDialog.js +23 -0
  11. package/dist/cjs/components/authors/DraggableAuthor.js +170 -0
  12. package/dist/cjs/components/authors/SaveAuthorConfirmationDialog.js +21 -0
  13. package/dist/cjs/lib/array-reducer.js +2 -0
  14. package/dist/cjs/lib/authors.js +43 -0
  15. package/dist/cjs/lib/track-changes-utils.js +5 -1
  16. package/dist/cjs/lib/utils.js +1 -5
  17. package/dist/cjs/lib/view.js +97 -0
  18. package/dist/cjs/views/base_node_view.js +0 -19
  19. package/dist/cjs/views/bibliography_element.js +3 -2
  20. package/dist/cjs/views/citation_editable.js +3 -2
  21. package/dist/cjs/views/contributors.js +78 -25
  22. package/dist/es/components/authors/AffiliationButton.js +75 -0
  23. package/dist/es/components/authors/AffiliationForm.js +43 -0
  24. package/dist/es/components/authors/AuthorActions.js +31 -0
  25. package/dist/es/components/authors/AuthorAffiliations.js +85 -0
  26. package/dist/es/components/authors/AuthorDetailsForm.js +67 -0
  27. package/dist/es/components/authors/AuthorFormPlaceholder.js +50 -0
  28. package/dist/es/components/authors/AuthorList.js +33 -0
  29. package/dist/es/components/authors/AuthorsModal.js +196 -0
  30. package/dist/es/components/authors/ChangeHandlingForm.js +10 -0
  31. package/dist/es/components/authors/DeleteAuthorConfirmationDialog.js +16 -0
  32. package/dist/es/components/authors/DraggableAuthor.js +140 -0
  33. package/dist/es/components/authors/SaveAuthorConfirmationDialog.js +14 -0
  34. package/dist/es/configs/editor-views.js +2 -2
  35. package/dist/es/lib/array-reducer.js +2 -0
  36. package/dist/es/lib/authors.js +36 -0
  37. package/dist/es/lib/track-changes-utils.js +3 -0
  38. package/dist/es/lib/utils.js +1 -4
  39. package/dist/es/lib/view.js +64 -0
  40. package/dist/es/views/base_node_view.js +0 -19
  41. package/dist/es/views/bibliography_element.js +3 -2
  42. package/dist/es/views/citation_editable.js +3 -2
  43. package/dist/es/views/contributors.js +79 -26
  44. package/dist/types/components/authors/AffiliationButton.d.ts +8 -0
  45. package/dist/types/components/authors/AffiliationForm.d.ts +7 -0
  46. package/dist/types/components/authors/AuthorActions.d.ts +9 -0
  47. package/dist/types/components/authors/AuthorAffiliations.d.ts +11 -0
  48. package/dist/types/components/authors/AuthorDetailsForm.d.ts +30 -0
  49. package/dist/types/components/authors/AuthorFormPlaceholder.d.ts +2 -0
  50. package/dist/types/components/authors/AuthorList.d.ts +25 -0
  51. package/dist/types/components/authors/AuthorsModal.d.ts +26 -0
  52. package/dist/types/components/authors/ChangeHandlingForm.d.ts +5 -0
  53. package/dist/types/components/authors/DeleteAuthorConfirmationDialog.d.ts +9 -0
  54. package/dist/types/components/authors/DraggableAuthor.d.ts +25 -0
  55. package/dist/types/components/authors/SaveAuthorConfirmationDialog.d.ts +7 -0
  56. package/dist/types/components/outline/DraggableTree.d.ts +1 -1
  57. package/dist/types/configs/ManuscriptsEditor.d.ts +0 -2
  58. package/dist/types/configs/editor-views.d.ts +0 -28
  59. package/dist/types/lib/array-reducer.d.ts +5 -1
  60. package/dist/types/lib/authors.d.ts +23 -0
  61. package/dist/types/lib/track-changes-utils.d.ts +1 -0
  62. package/dist/types/lib/utils.d.ts +0 -1
  63. package/dist/types/lib/view.d.ts +25 -0
  64. package/dist/types/views/base_node_view.d.ts +1 -4
  65. package/dist/types/views/bibliography_element_editable.d.ts +0 -2
  66. package/dist/types/views/blockquote_element_editable.d.ts +0 -2
  67. package/dist/types/views/bullet_list_editable.d.ts +0 -2
  68. package/dist/types/views/contributors.d.ts +25 -8
  69. package/dist/types/views/editable_block.d.ts +0 -2
  70. package/dist/types/views/equation_element_editable.d.ts +0 -2
  71. package/dist/types/views/figure_element_editable.d.ts +0 -2
  72. package/dist/types/views/footnote_editable.d.ts +0 -2
  73. package/dist/types/views/footnotes_element_editable.d.ts +0 -2
  74. package/dist/types/views/listing_element_editable.d.ts +0 -2
  75. package/dist/types/views/ordered_list_editable.d.ts +0 -2
  76. package/dist/types/views/paragraph_editable.d.ts +0 -2
  77. package/dist/types/views/placeholder_element_editable.d.ts +0 -2
  78. package/dist/types/views/pullquote_element_editable.d.ts +0 -2
  79. package/dist/types/views/section_title_editable.d.ts +0 -2
  80. package/dist/types/views/table_element_editable.d.ts +0 -2
  81. package/dist/types/views/toc_element_editable.d.ts +0 -2
  82. package/package.json +4 -3
  83. package/styles/AdvancedEditor.css +3 -3
@@ -16,7 +16,6 @@
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.BaseNodeView = void 0;
19
- const utils_1 = require("../lib/utils");
20
19
  class BaseNodeView {
21
20
  constructor(props, node, view, getPos, decorations) {
22
21
  this.props = props;
@@ -62,24 +61,6 @@ class BaseNodeView {
62
61
  this.dom.classList.toggle('has-sync-error', this.syncErrors.length > 0);
63
62
  }
64
63
  };
65
- this.updateNodeAttrs = (attrs) => {
66
- this.view.state.doc.descendants((node, pos) => {
67
- if (node.attrs.id === attrs.id) {
68
- const tr = this.view.state.tr.setNodeMarkup(pos, undefined, attrs);
69
- if ((0, utils_1.isMetaNode)(node.type.name)) {
70
- tr.setMeta('track-changes-update-meta-node', true);
71
- }
72
- this.view.dispatch(tr);
73
- }
74
- });
75
- };
76
- this.deleteNode = (id) => {
77
- this.view.state.doc.descendants((node, pos) => {
78
- if (node.attrs.id === id) {
79
- this.view.dispatch(this.view.state.tr.delete(pos, pos + node.nodeSize));
80
- }
81
- });
82
- };
83
64
  }
84
65
  setDomAttrs(node, element, omit = []) {
85
66
  Object.keys(node.attrs || {}).forEach((attr) => {
@@ -33,6 +33,7 @@ const transform_1 = require("@manuscripts/transform");
33
33
  const assets_1 = require("../assets");
34
34
  const dompurify_1 = require("../lib/dompurify");
35
35
  const track_changes_utils_1 = require("../lib/track-changes-utils");
36
+ const view_1 = require("../lib/view");
36
37
  const bibliography_1 = require("../plugins/bibliography");
37
38
  const comment_annotation_1 = require("../plugins/comment_annotation");
38
39
  const selected_suggestion_ui_1 = require("../plugins/selected-suggestion-ui");
@@ -151,10 +152,10 @@ class BibliographyElementBlockView extends block_view_1.default {
151
152
  };
152
153
  this.handleSave = (item) => {
153
154
  const node = this.decoder.decode(item);
154
- this.updateNodeAttrs(node.attrs);
155
+ (0, view_1.updateNode)(this.view, node);
155
156
  };
156
157
  this.handleDelete = (item) => {
157
- return this.deleteNode(item._id);
158
+ (0, view_1.deleteNode)(this.view, item._id);
158
159
  };
159
160
  this.addClickListenerToBibItem = (element, dataTracked) => {
160
161
  if (dataTracked.status !== track_changes_plugin_1.CHANGE_STATUS.rejected) {
@@ -27,6 +27,7 @@ const prosemirror_state_1 = require("prosemirror-state");
27
27
  const prosemirror_utils_1 = require("prosemirror-utils");
28
28
  const citation_sources_1 = require("../citation-sources");
29
29
  const track_changes_utils_1 = require("../lib/track-changes-utils");
30
+ const view_1 = require("../lib/view");
30
31
  const bibliography_1 = require("../plugins/bibliography");
31
32
  const citation_1 = require("./citation");
32
33
  const CitationEditorWrapper_1 = require("./CitationEditorWrapper");
@@ -101,7 +102,7 @@ class CitationEditableView extends citation_1.CitationView {
101
102
  }
102
103
  else {
103
104
  const node = this.decoder.decode(item);
104
- this.updateNodeAttrs(node.attrs);
105
+ (0, view_1.updateNodeAttrs)(this.view, node.type, node.attrs);
105
106
  }
106
107
  };
107
108
  this.handleUncite = (id) => {
@@ -145,7 +146,7 @@ class CitationEditableView extends citation_1.CitationView {
145
146
  this.handleCancel();
146
147
  };
147
148
  this.handleDelete = (item) => {
148
- return this.deleteNode(item._id);
149
+ return (0, view_1.deleteNode)(this.view, item._id);
149
150
  };
150
151
  this.handleComment = () => {
151
152
  const comment = (0, transform_1.buildComment)(this.node.attrs.id);
@@ -1,4 +1,19 @@
1
1
  "use strict";
2
+ /*!
3
+ * © 2023 Atypon Systems LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
2
17
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
18
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
19
  };
@@ -6,7 +21,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
21
  exports.ContributorsView = void 0;
7
22
  const style_guide_1 = require("@manuscripts/style-guide");
8
23
  const transform_1 = require("@manuscripts/transform");
24
+ const AuthorsModal_1 = require("../components/authors/AuthorsModal");
25
+ const authors_1 = require("../lib/authors");
9
26
  const track_changes_utils_1 = require("../lib/track-changes-utils");
27
+ const view_1 = require("../lib/view");
10
28
  const affiliations_1 = require("../plugins/affiliations");
11
29
  const selected_suggestion_ui_1 = require("../plugins/selected-suggestion-ui");
12
30
  const block_view_1 = __importDefault(require("./block_view"));
@@ -77,15 +95,11 @@ class ContributorsView extends block_view_1.default {
77
95
  }
78
96
  const can = this.props.getCapabilities();
79
97
  const disableEditButton = !can.editMetadata;
80
- const { bibliographicName, isCorresponding, email, id } = displayAttr;
81
- container.addEventListener('click', (e) => {
82
- e.preventDefault();
83
- if (!disableEditButton) {
84
- this.props.openAuthorEditing();
85
- this.props.selectAuthorForEditing(id);
86
- }
87
- });
88
- const name = this.buildNameLiteral(bibliographicName);
98
+ const { isCorresponding, email } = displayAttr;
99
+ if (!disableEditButton) {
100
+ container.addEventListener('click', this.handleClick);
101
+ }
102
+ const name = (0, authors_1.authorLabel)(displayAttr);
89
103
  container.innerHTML =
90
104
  isCorresponding && email
91
105
  ? `<span class="name">${name} (${email})</span>`
@@ -113,21 +127,6 @@ class ContributorsView extends block_view_1.default {
113
127
  }
114
128
  return container;
115
129
  };
116
- this.initials = (given) => given
117
- ? given
118
- .trim()
119
- .split(' ')
120
- .map((part) => part.substr(0, 1).toUpperCase() + '.')
121
- .join('')
122
- : '';
123
- this.buildNameLiteral = ({ given = '', family = '', suffix = '' }) => {
124
- if (!given && !family) {
125
- return 'Unknown Author';
126
- }
127
- return [this.initials(given), family, suffix]
128
- .filter((part) => part)
129
- .join(' ');
130
- };
131
130
  this.isJointFirstAuthor = (authors, index) => {
132
131
  const author = index === 0 ? authors[index] : authors[index - 1];
133
132
  return Boolean(author.attrs.isJointContributor);
@@ -148,7 +147,7 @@ class ContributorsView extends block_view_1.default {
148
147
  const can = this.props.getCapabilities();
149
148
  const button = (0, ReactSubView_1.default)(this.props, style_guide_1.SecondaryButton, {
150
149
  mini: true,
151
- onClick: this.props.openAuthorEditing,
150
+ onClick: this.handleClick,
152
151
  className: 'edit-authors-button',
153
152
  disabled: !can.editMetadata,
154
153
  children: 'Edit Authors',
@@ -168,6 +167,60 @@ class ContributorsView extends block_view_1.default {
168
167
  }
169
168
  }
170
169
  };
170
+ this.handleClick = (e) => {
171
+ var _a, _b;
172
+ e.stopPropagation();
173
+ const contributors = (0, view_1.findChildrenAttrsByType)(this.view, transform_1.schema.nodes.contributor);
174
+ const affiliations = (0, view_1.findChildrenAttrsByType)(this.view, transform_1.schema.nodes.affiliation);
175
+ let author = undefined;
176
+ const target = e.target;
177
+ if (target) {
178
+ const id = (_a = target.closest('.contributor')) === null || _a === void 0 ? void 0 : _a.getAttribute('id');
179
+ author = contributors.filter((a) => a.id === id)[0];
180
+ }
181
+ const componentProps = {
182
+ author,
183
+ authors: contributors,
184
+ affiliations,
185
+ onSaveAuthor: this.handleSaveAuthor,
186
+ onDeleteAuthor: this.handleDeleteAuthor,
187
+ onSaveAffiliation: this.handleSaveAffiliation,
188
+ };
189
+ (_b = this.popper) === null || _b === void 0 ? void 0 : _b.remove();
190
+ this.popper = (0, ReactSubView_1.default)(this.props, AuthorsModal_1.AuthorsModal, componentProps, this.node, this.getPos, this.view);
191
+ this.container.appendChild(this.popper);
192
+ };
193
+ this.handleSaveAuthor = (author) => {
194
+ if (!(0, view_1.findChildByID)(this.view, author.id)) {
195
+ this.insertAuthorNode(author);
196
+ }
197
+ else {
198
+ (0, view_1.updateNodeAttrs)(this.view, transform_1.schema.nodes.contributor, author);
199
+ }
200
+ };
201
+ this.handleDeleteAuthor = (author) => {
202
+ (0, view_1.deleteNode)(this.view, author.id);
203
+ };
204
+ this.handleSaveAffiliation = (affiliation) => {
205
+ if (!(0, view_1.findChildByID)(this.view, affiliation.id)) {
206
+ this.insertAffiliationNode(affiliation);
207
+ }
208
+ else {
209
+ (0, view_1.updateNodeAttrs)(this.view, transform_1.schema.nodes.affiliation, affiliation);
210
+ }
211
+ };
212
+ this.insertAuthorNode = (attrs) => {
213
+ const parent = (0, view_1.findChildByType)(this.view, transform_1.schema.nodes.contributors);
214
+ const tr = this.view.state.tr;
215
+ const node = transform_1.schema.nodes.contributor.create(attrs);
216
+ this.view.dispatch(tr.insert(parent.pos + 1, node));
217
+ };
218
+ this.insertAffiliationNode = (attrs) => {
219
+ const parent = (0, view_1.findChildByType)(this.view, transform_1.schema.nodes.affiliations);
220
+ const tr = this.view.state.tr;
221
+ const node = transform_1.schema.nodes.affiliation.create(attrs);
222
+ this.view.dispatch(tr.insert(parent.pos + 1, node));
223
+ };
171
224
  this.ignoreMutation = () => true;
172
225
  this.stopEvent = () => true;
173
226
  }
@@ -0,0 +1,75 @@
1
+ import ArrowDownBlue from '@manuscripts/assets/react/ArrowDownBlue';
2
+ import { DeleteIcon } from '@manuscripts/style-guide';
3
+ import { isEqual } from 'lodash';
4
+ import React, { useState } from 'react';
5
+ import styled from 'styled-components';
6
+ import { affiliationLabel } from '../../lib/authors';
7
+ import { AffiliationForm } from './AffiliationForm';
8
+ const Container = styled.div `
9
+ border: 1px solid ${(props) => props.theme.colors.border.field.default};
10
+ border-radius: ${(props) => props.theme.grid.radius.default};
11
+ background: ${(props) => props.theme.colors.background.primary};
12
+ margin-bottom: 2px;
13
+ overflow: hidden;
14
+ `;
15
+ const AffiliationFormContainer = styled.div `
16
+ border: 1px solid ${(props) => props.theme.colors.border.field.default};
17
+ border-radius: ${(props) => props.theme.grid.radius.default};
18
+ margin: 6px 12px 12px;
19
+ overflow: hidden;
20
+ `;
21
+ const AffiliationLabel = styled.div `
22
+ margin: 0;
23
+ display: flex;
24
+ align-items: center;
25
+ font-size: 0.875rem;
26
+ padding-right: 0.5rem;
27
+ `;
28
+ const DropdownIndicator = styled(ArrowDownBlue) `
29
+ border: 0;
30
+ border-radius: 50%;
31
+ margin-right: 0.6em;
32
+ min-width: 20px;
33
+ `;
34
+ const ToggleButton = styled.button `
35
+ flex-grow: 1;
36
+ display: flex;
37
+ align-items: center;
38
+ width: 100%;
39
+ background: transparent;
40
+ border: none;
41
+ text-align: left;
42
+ font-family: ${(props) => props.theme.font.family.sans};
43
+ font-size: 1rem;
44
+ padding: 0.6em 0.5em;
45
+ outline: none;
46
+
47
+ &.open svg {
48
+ transform: rotateX(180deg);
49
+ }
50
+ `;
51
+ const RemoveButton = styled.div `
52
+ cursor: pointer;
53
+ `;
54
+ export const AffiliationButton = ({ affiliation, onSave, onRemove, }) => {
55
+ const [isOpen, setOpen] = useState(false);
56
+ const toggleOpen = () => {
57
+ setOpen((o) => !o);
58
+ };
59
+ const handleSave = (values) => {
60
+ if (isEqual(values, affiliation)) {
61
+ return;
62
+ }
63
+ const copy = Object.assign(Object.assign({}, affiliation), values);
64
+ onSave(copy);
65
+ };
66
+ return (React.createElement(Container, null,
67
+ React.createElement(AffiliationLabel, null,
68
+ React.createElement(ToggleButton, { type: "button", className: isOpen ? 'open' : '', onClick: toggleOpen },
69
+ React.createElement(DropdownIndicator, null),
70
+ affiliationLabel(affiliation)),
71
+ React.createElement(RemoveButton, { onClick: onRemove },
72
+ React.createElement(DeleteIcon, null))),
73
+ isOpen && (React.createElement(AffiliationFormContainer, null,
74
+ React.createElement(AffiliationForm, { values: affiliation, onSave: handleSave })))));
75
+ };
@@ -0,0 +1,43 @@
1
+ import { TextField } from '@manuscripts/style-guide';
2
+ import { Field, Formik } from 'formik';
3
+ import React from 'react';
4
+ import styled from 'styled-components';
5
+ import { ChangeHandlingForm } from './ChangeHandlingForm';
6
+ const Row = styled.div `
7
+ display: flex;
8
+ border-top: 1px solid ${(props) => props.theme.colors.border.field.default};
9
+ &:first-child {
10
+ border-top: none;
11
+ }
12
+ `;
13
+ const AffiliationsTextField = styled(TextField) `
14
+ border: none;
15
+ border-radius: 0;
16
+ background: transparent;
17
+ &:not(:first-child) {
18
+ border-left: 1px solid ${(props) => props.theme.colors.border.field.default};
19
+ }
20
+
21
+ &[aria-invalid] {
22
+ background: ${(props) => props.theme.colors.background.warning};
23
+ }
24
+
25
+ &[aria-invalid]:focus {
26
+ background: transparent;
27
+ }
28
+ `;
29
+ export const AffiliationForm = ({ values, onSave, }) => {
30
+ return (React.createElement(Formik, { initialValues: values, onSubmit: onSave }, () => (React.createElement(ChangeHandlingForm, { onChange: onSave },
31
+ React.createElement(Row, null,
32
+ React.createElement(Field, { name: "institution" }, (props) => (React.createElement(AffiliationsTextField, Object.assign({ id: "institution", placeholder: "Institution Name" }, props.field))))),
33
+ React.createElement(Row, null,
34
+ React.createElement(Field, { name: "department" }, (props) => (React.createElement(AffiliationsTextField, Object.assign({ id: "department", placeholder: "Department" }, props.field))))),
35
+ React.createElement(Row, null,
36
+ React.createElement(Field, { name: "addressLine1" }, (props) => (React.createElement(AffiliationsTextField, Object.assign({ id: "addressLine1", placeholder: "Street Address" }, props.field))))),
37
+ React.createElement(Row, null,
38
+ React.createElement(Field, { name: "city" }, (props) => (React.createElement(AffiliationsTextField, Object.assign({ id: "city", placeholder: "City" }, props.field)))),
39
+ React.createElement(Field, { name: "county" }, (props) => (React.createElement(AffiliationsTextField, Object.assign({ id: "county", placeholder: "State / Province" }, props.field))))),
40
+ React.createElement(Row, null,
41
+ React.createElement(Field, { name: "postCode" }, (props) => (React.createElement(AffiliationsTextField, Object.assign({ id: "postCode", placeholder: "Postal Code" }, props.field)))),
42
+ React.createElement(Field, { name: "country" }, (props) => (React.createElement(AffiliationsTextField, Object.assign({ id: "country", placeholder: "Country" }, props.field)))))))));
43
+ };
@@ -0,0 +1,31 @@
1
+ import { ButtonGroup, DeleteIcon, PrimaryButton, SecondaryButton, } from '@manuscripts/style-guide';
2
+ import React, { useState } from 'react';
3
+ import styled from 'styled-components';
4
+ import { DeleteAuthorConfirmationDialog } from './DeleteAuthorConfirmationDialog';
5
+ const AuthorActionsContainer = styled.div `
6
+ display: flex;
7
+ `;
8
+ const RemoveButton = styled.div `
9
+ display: flex;
10
+ align-items: center;
11
+
12
+ svg {
13
+ cursor: pointer;
14
+ }
15
+ `;
16
+ const StyledButtonGroup = styled(ButtonGroup) `
17
+ flex: 1;
18
+ `;
19
+ export const AuthorActions = ({ author, onSave, onDelete, onCancel, }) => {
20
+ const [showDeleteDialog, setShowDeleteDialog] = useState(false);
21
+ return (React.createElement(AuthorActionsContainer, null,
22
+ React.createElement(DeleteAuthorConfirmationDialog, { author: author, isOpen: showDeleteDialog, onDelete: () => {
23
+ setShowDeleteDialog(true);
24
+ onDelete();
25
+ }, onCancel: () => setShowDeleteDialog(false) }),
26
+ React.createElement(RemoveButton, { onClick: () => setShowDeleteDialog(true) },
27
+ React.createElement(DeleteIcon, null)),
28
+ React.createElement(StyledButtonGroup, null,
29
+ React.createElement(SecondaryButton, { onClick: onCancel }, "Cancel"),
30
+ React.createElement(PrimaryButton, { onClick: onSave }, "Save"))));
31
+ };
@@ -0,0 +1,85 @@
1
+ import AddAuthor from '@manuscripts/assets/react/AddAuthor';
2
+ import { generateID, ObjectTypes } from '@manuscripts/json-schema';
3
+ import React, { useContext, useMemo, useState } from 'react';
4
+ import CreatableSelect from 'react-select/creatable';
5
+ import styled, { ThemeContext } from 'styled-components';
6
+ import { affiliationLabel, } from '../../lib/authors';
7
+ import { AffiliationButton } from './AffiliationButton';
8
+ const AddAffiliation = styled(AddAuthor) `
9
+ width: 24px;
10
+ height: 24px;
11
+ margin-right: 4px;
12
+
13
+ circle,
14
+ use {
15
+ fill: ${(props) => props.theme.colors.brand.default};
16
+ }
17
+
18
+ path {
19
+ mask: none;
20
+ }
21
+ `;
22
+ export const AddAffiliationIndicator = () => React.createElement(AddAffiliation, null);
23
+ const getSelectStyles = (focus, theme) => ({
24
+ backgroundColor: focus
25
+ ? theme.colors.background.fifth
26
+ : theme.colors.background.primary,
27
+ borderColor: focus
28
+ ? theme.colors.border.field.active
29
+ : theme.colors.border.field.default,
30
+ '&:hover': {
31
+ backgroundColor: theme.colors.background.fifth,
32
+ },
33
+ borderRadius: theme.grid.radius.default,
34
+ boxShadow: 'none',
35
+ fontFamily: theme.font.family.sans,
36
+ });
37
+ export const AuthorAffiliations = ({ author, affiliations, onSave, onAdd, onRemove, }) => {
38
+ const theme = useContext(ThemeContext);
39
+ const [searchText, setSearchText] = useState('');
40
+ const affiliationMap = useMemo(() => new Map(affiliations.map((a) => [a.id, a])), [affiliations]);
41
+ const authorAffiliations = useMemo(() => {
42
+ var _a;
43
+ return (_a = author.affiliations) === null || _a === void 0 ? void 0 : _a.map((i) => affiliationMap.get(i));
44
+ }, [affiliationMap, author]);
45
+ const otherAffiliations = useMemo(() => {
46
+ var _a;
47
+ const copy = new Map(affiliationMap);
48
+ (_a = author.affiliations) === null || _a === void 0 ? void 0 : _a.forEach((i) => copy.delete(i));
49
+ return Array.from(copy.values());
50
+ }, [affiliationMap, author]);
51
+ const options = otherAffiliations.map((a) => ({
52
+ value: a.id,
53
+ label: affiliationLabel(a),
54
+ }));
55
+ const handleChange = (id) => {
56
+ const affiliation = affiliationMap.get(id);
57
+ if (!affiliation) {
58
+ return;
59
+ }
60
+ onAdd(affiliation);
61
+ setSearchText('');
62
+ };
63
+ const handleCreate = (institution) => {
64
+ const affiliation = {
65
+ id: generateID(ObjectTypes.Affiliation),
66
+ addressLine1: '',
67
+ city: '',
68
+ country: '',
69
+ county: '',
70
+ department: '',
71
+ institution: institution,
72
+ postCode: '',
73
+ priority: 0,
74
+ };
75
+ onSave(affiliation);
76
+ onAdd(affiliation);
77
+ };
78
+ return (React.createElement(React.Fragment, null,
79
+ authorAffiliations.map((a) => (React.createElement(AffiliationButton, { key: `${author.id}-${a.id}`, affiliation: a, onSave: onSave, onRemove: () => onRemove(a) }))),
80
+ React.createElement(CreatableSelect, { options: options, isMulti: false, isClearable: true, value: null, inputValue: searchText, components: {
81
+ IndicatorsContainer: AddAffiliationIndicator,
82
+ }, placeholder: "Begin typing to add affiliation", noOptionsMessage: () => 'Type the name of an institution', onChange: (i) => i && handleChange(i.value), onInputChange: setSearchText, onCreateOption: (v) => v && handleCreate(v), isValidNewOption: (t) => !!t, styles: {
83
+ control: (provided, state) => (Object.assign(Object.assign({}, provided), getSelectStyles(state.isFocused, theme))),
84
+ } })));
85
+ };
@@ -0,0 +1,67 @@
1
+ /*!
2
+ * © 2019 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { CheckboxField, CheckboxLabel, TextField, TextFieldGroupContainer, TextFieldLabel, } from '@manuscripts/style-guide';
17
+ import { Field, Formik } from 'formik';
18
+ import React, { useRef } from 'react';
19
+ import styled from 'styled-components';
20
+ import { ChangeHandlingForm } from './ChangeHandlingForm';
21
+ export const LabelText = styled.div `
22
+ font: ${(props) => props.theme.font.weight.normal}
23
+ ${(props) => props.theme.font.size.normal} / 1
24
+ ${(props) => props.theme.font.family.sans};
25
+ letter-spacing: -0.2px;
26
+ color: ${(props) => props.theme.colors.text.primary};
27
+ `;
28
+ export const Fieldset = styled.fieldset `
29
+ padding: 0;
30
+ margin: 0;
31
+ border: none;
32
+ `;
33
+ const OrcidContainer = styled.div `
34
+ margin: 16px 0 0;
35
+ `;
36
+ export const AuthorDetailsForm = ({ values, onChange, onSave, actionsRef, }) => {
37
+ const formRef = useRef(null);
38
+ if (actionsRef && !actionsRef.current) {
39
+ actionsRef.current = {
40
+ reset: () => {
41
+ var _a;
42
+ (_a = formRef.current) === null || _a === void 0 ? void 0 : _a.resetForm();
43
+ },
44
+ };
45
+ }
46
+ return (React.createElement(Formik, { initialValues: values, onSubmit: onSave, enableReinitialize: true, validateOnChange: false, innerRef: formRef }, (formik) => {
47
+ const isAuthor = formik.values.role === 'author';
48
+ return (React.createElement(ChangeHandlingForm, { onChange: onChange },
49
+ React.createElement(Fieldset, null,
50
+ React.createElement(TextFieldGroupContainer, null,
51
+ React.createElement(Field, { name: 'bibliographicName.given' }, (props) => (React.createElement(TextField, Object.assign({ id: 'given-name', placeholder: 'Given name' }, props.field)))),
52
+ React.createElement(Field, { name: 'bibliographicName.family' }, (props) => (React.createElement(TextField, Object.assign({ id: 'family-name', placeholder: 'Family name' }, props.field))))),
53
+ React.createElement(Field, { name: 'email', type: 'email' }, (props) => (React.createElement(TextField, Object.assign({ id: 'email', placeholder: 'Email address' }, props.field)))),
54
+ React.createElement(CheckboxLabel, { disabled: !isAuthor },
55
+ React.createElement(Field, { name: 'isCorresponding' }, (props) => (React.createElement(CheckboxField, Object.assign({ id: 'isCorresponding', checked: props.field.value, disabled: !isAuthor }, props.field)))),
56
+ React.createElement(LabelText, null, "Corresponding Author")),
57
+ React.createElement(CheckboxLabel, null,
58
+ React.createElement(Field, { name: 'role', type: 'checkbox' }, (props) => (React.createElement(CheckboxField, { name: 'role', checked: isAuthor, onChange: (e) => {
59
+ formik.setFieldValue(props.field.name, e.target.checked ? 'author' : 'other', false);
60
+ } }))),
61
+ React.createElement(LabelText, null, "Include in Authors List")),
62
+ React.createElement(OrcidContainer, null,
63
+ React.createElement(TextFieldLabel, null,
64
+ React.createElement(LabelText, null, "ORCID"),
65
+ React.createElement(Field, { name: 'ORCIDIdentifier', type: 'text' }, (props) => (React.createElement(TextField, Object.assign({ id: 'orcid', placeholder: 'https://orcid.org/...' }, props.field)))))))));
66
+ }));
67
+ };
@@ -0,0 +1,50 @@
1
+ import ContributorDetails from '@manuscripts/assets/react/ContributorDetailsPlaceholder';
2
+ import React from 'react';
3
+ import styled from 'styled-components';
4
+ const OuterContainer = styled.div `
5
+ display: flex;
6
+ flex-direction: column;
7
+ align-items: center;
8
+ justify-content: center;
9
+ height: 100%;
10
+ overflow-y: auto;
11
+ `;
12
+ const InnerContainer = styled.div `
13
+ text-align: center;
14
+ max-width: 480px;
15
+ font-size: ${(props) => props.theme.font.size.xlarge};
16
+ line-height: ${(props) => props.theme.font.lineHeight.large};
17
+ `;
18
+ const Placeholder = styled.div `
19
+ display: flex;
20
+ justify-content: center;
21
+ margin-bottom: ${(props) => props.theme.grid.unit * 5}px;
22
+ `;
23
+ const Action = styled.div `
24
+ display: flex;
25
+ align-items: center;
26
+ justify-content: center;
27
+ font-size: ${(props) => props.theme.font.size.xlarge};
28
+ font-weight: ${(props) => props.theme.font.weight.medium};
29
+ letter-spacing: -0.5px;
30
+ `;
31
+ const Message = styled.div `
32
+ max-width: 400px;
33
+ font-size: ${(props) => props.theme.font.size.xlarge};
34
+ margin-top: ${(props) => props.theme.grid.unit * 6}px;
35
+ font-weight: ${(props) => props.theme.font.weight.light};
36
+ color: ${(props) => props.theme.colors.text.secondary};
37
+
38
+ @media (max-width: 850px) {
39
+ margin-right: ${(props) => props.theme.grid.unit * 5}px;
40
+ margin-left: ${(props) => props.theme.grid.unit * 5}px;
41
+ max-width: 350px;
42
+ }
43
+ `;
44
+ export const AuthorFormPlaceholder = () => (React.createElement(OuterContainer, { "data-cy": 'author-details' },
45
+ React.createElement(InnerContainer, null,
46
+ React.createElement(Placeholder, null,
47
+ React.createElement(ContributorDetails, null)),
48
+ React.createElement(React.Fragment, null,
49
+ React.createElement(Action, null, "Author Details"),
50
+ React.createElement(Message, null, "Select an author from the list to display their details here.")))));
@@ -0,0 +1,33 @@
1
+ /*!
2
+ * © 2019 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { DragLayer } from '@manuscripts/style-guide';
17
+ import React from 'react';
18
+ import { DndProvider } from 'react-dnd';
19
+ import { HTML5Backend } from 'react-dnd-html5-backend';
20
+ import styled from 'styled-components';
21
+ import { DraggableAuthor } from './DraggableAuthor';
22
+ const AuthorListContainer = styled.div `
23
+ flex: 1;
24
+ overflow-y: visible;
25
+ `;
26
+ export const AuthorList = ({ author, authors, onSelect, moveAuthor, }) => {
27
+ return (React.createElement(DndProvider, { backend: HTML5Backend },
28
+ React.createElement(AuthorListContainer, null,
29
+ React.createElement(DragLayer, null),
30
+ authors.map((a) => {
31
+ return (React.createElement(DraggableAuthor, { key: a.id, author: a, isSelected: a.id === (author === null || author === void 0 ? void 0 : author.id), onClick: () => onSelect(a), moveAuthor: moveAuthor }));
32
+ }))));
33
+ };