@manuscripts/body-editor 3.12.66 → 3.13.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 (289) hide show
  1. package/dist/cjs/components/toolbar/type-selector/styles.js +2 -1
  2. package/dist/cjs/versions.js +1 -1
  3. package/dist/es/components/toolbar/type-selector/styles.js +2 -1
  4. package/dist/es/versions.js +1 -1
  5. package/dist/types/components/toolbar/type-selector/styles.d.ts +2 -2
  6. package/dist/types/lib/footnotes.d.ts +4 -2
  7. package/dist/types/lib/utils.d.ts +5 -4
  8. package/dist/types/versions.d.ts +1 -1
  9. package/package.json +37 -36
  10. package/{dist/es/lib/statistics.js → src/__mocks__/styleMock.ts} +2 -14
  11. package/src/assets.ts +20 -0
  12. package/src/classes/collabProvider.ts +38 -0
  13. package/src/clipboard.ts +54 -0
  14. package/src/commands.ts +2109 -0
  15. package/src/components/ChangeHandlingForm.tsx +54 -0
  16. package/src/components/LanguageDropdown/index.tsx +343 -0
  17. package/src/components/affiliations/AffiliationForm.tsx +238 -0
  18. package/src/components/affiliations/AffiliationItem.tsx +151 -0
  19. package/src/components/affiliations/AffiliationList.tsx +71 -0
  20. package/src/components/affiliations/AffiliationsModal.tsx +676 -0
  21. package/src/components/affiliations/AffiliationsPanel.tsx +76 -0
  22. package/src/components/affiliations/CreateAffiliationModal.tsx +135 -0
  23. package/src/components/authors/AuthorDetailsForm.tsx +438 -0
  24. package/src/components/authors/AuthorList.tsx +81 -0
  25. package/src/components/authors/AuthorsModal.tsx +642 -0
  26. package/src/components/authors/AuthorsPanel.tsx +69 -0
  27. package/src/components/authors/CreateAuthorModal.tsx +172 -0
  28. package/src/components/authors/CreditDrawer.tsx +71 -0
  29. package/src/components/authors/DraggableAuthor.tsx +228 -0
  30. package/src/components/authors/useManageAffiliations.tsx +77 -0
  31. package/src/components/authors/useManageCredit.tsx +63 -0
  32. package/src/components/authors-affiliations/AuthorsAndAffiliationsModals.tsx +170 -0
  33. package/src/components/authors-affiliations/GenericPanel.tsx +164 -0
  34. package/src/components/authors-affiliations/ModalTabs.tsx +100 -0
  35. package/src/components/awards/AwardForm.tsx +338 -0
  36. package/src/components/awards/AwardModal.tsx +120 -0
  37. package/src/components/awards/DeleteAwardDiaolog.tsx +52 -0
  38. package/src/components/dialog/ConfirmationDialog.tsx +131 -0
  39. package/src/components/form/CreateModalStyles.tsx +37 -0
  40. package/src/components/form/FormFooter.tsx +54 -0
  41. package/src/components/form/FormPlaceholder.tsx +71 -0
  42. package/src/components/form/ModalFormActions.tsx +88 -0
  43. package/src/components/form/UnsavedLabel.tsx +49 -0
  44. package/src/components/hooks/use-debounce.ts +56 -0
  45. package/src/components/hooks/useAffiliationShowsErrorIndicator.ts +51 -0
  46. package/src/components/hooks/useAuthorShowsErrorIndicator.ts +73 -0
  47. package/src/components/keyboard-shortcuts-modal/FormattedShortcut.tsx +56 -0
  48. package/src/components/keyboard-shortcuts-modal/KeyboardShortcutsModal.tsx +283 -0
  49. package/src/components/keyboard-shortcuts-modal/keyboard-shortcuts.ts +304 -0
  50. package/src/components/keywords/AddKeywordInline.tsx +284 -0
  51. package/src/components/keywords/DeleteKeywordDialog.tsx +52 -0
  52. package/src/components/modal-drawer/GenericDrawer.tsx +65 -0
  53. package/src/components/modal-drawer/GenericDrawerGroup.tsx +125 -0
  54. package/src/components/outline/DraggableTree.tsx +438 -0
  55. package/src/components/outline/ManuscriptOutline.tsx +127 -0
  56. package/src/components/outline/Outline.tsx +141 -0
  57. package/src/components/references/BibliographyItemSource.ts +80 -0
  58. package/src/components/references/CitationEditor.tsx +301 -0
  59. package/src/components/references/CitationViewer.tsx +62 -0
  60. package/src/components/references/ImportBibliographyForm.tsx +232 -0
  61. package/src/components/references/ImportBibliographyModal.tsx +159 -0
  62. package/src/components/references/ReferenceForm/PersonDropDown.tsx +93 -0
  63. package/src/components/references/ReferenceForm/ReferenceForm.tsx +701 -0
  64. package/src/components/references/ReferenceForm/config.ts +133 -0
  65. package/src/components/references/ReferenceForm/styled-components.ts +156 -0
  66. package/src/components/references/ReferenceLine.tsx +43 -0
  67. package/src/components/references/ReferenceSearch.tsx +163 -0
  68. package/src/components/references/ReferenceSearchResults.tsx +113 -0
  69. package/src/components/references/ReferenceSearchResultsPlaceholder.tsx +71 -0
  70. package/src/components/references/ReferenceSearchSection.tsx +124 -0
  71. package/src/components/references/ReferencesEditor.tsx +61 -0
  72. package/src/components/references/ReferencesModal.tsx +352 -0
  73. package/src/components/references/SearchInput.tsx +98 -0
  74. package/src/components/toolbar/InsertEmbedDialog.tsx +222 -0
  75. package/src/components/toolbar/InsertTableDialog.tsx +208 -0
  76. package/src/components/toolbar/ListMenuItem.tsx +203 -0
  77. package/src/components/toolbar/helpers.ts +547 -0
  78. package/src/components/toolbar/type-selector/OptionComponent.tsx +89 -0
  79. package/src/components/toolbar/type-selector/TypeSelector.tsx +157 -0
  80. package/src/components/toolbar/type-selector/styles.ts +79 -0
  81. package/src/components/views/CrossReferenceItems.tsx +199 -0
  82. package/src/components/views/DeleteEmbedDialog.tsx +83 -0
  83. package/src/components/views/DeleteFootnoteDialog.tsx +54 -0
  84. package/src/components/views/FigureDropdown.tsx +423 -0
  85. package/src/components/views/FootnotesSelector.tsx +255 -0
  86. package/src/components/views/InsertSpecialCharacter.tsx +245 -0
  87. package/src/components/views/LinkForm.tsx +220 -0
  88. package/src/components/views/TableCellContextMenu.tsx +241 -0
  89. package/src/configs/ManuscriptsEditor.ts +140 -0
  90. package/src/configs/editor-plugins.ts +119 -0
  91. package/src/configs/editor-views.ts +139 -0
  92. package/src/icons.ts +62 -0
  93. package/src/index.ts +65 -0
  94. package/src/keys/highlight.ts +65 -0
  95. package/src/keys/index.ts +33 -0
  96. package/src/keys/keyword.ts +69 -0
  97. package/src/keys/list.ts +156 -0
  98. package/src/keys/misc.ts +112 -0
  99. package/src/keys/title.ts +221 -0
  100. package/src/lib/__tests__/__fixtures__/doc.json +388 -0
  101. package/src/lib/__tests__/__snapshots__/paste.test.ts.snap +24 -0
  102. package/src/lib/__tests__/authors.test.ts +202 -0
  103. package/src/lib/__tests__/helpers.test.ts +46 -0
  104. package/src/lib/__tests__/paste.test.ts +57 -0
  105. package/src/lib/__tests__/plugins.test.ts +176 -0
  106. package/src/lib/__tests__/url.test.ts +31 -0
  107. package/src/lib/array-reducer.ts +68 -0
  108. package/src/lib/authors-and-affiliations.ts +81 -0
  109. package/src/lib/authors.ts +67 -0
  110. package/src/lib/capabilities.ts +55 -0
  111. package/src/lib/codemirror.ts +37 -0
  112. package/src/lib/comments.ts +123 -0
  113. package/src/lib/context-menu.ts +745 -0
  114. package/src/lib/copy.ts +30 -0
  115. package/src/lib/crossref.ts +90 -0
  116. package/src/lib/dnd.ts +29 -0
  117. package/src/lib/doc.ts +167 -0
  118. package/src/lib/dompurify.ts +28 -0
  119. package/src/lib/files.ts +180 -0
  120. package/src/lib/footnotes.ts +83 -0
  121. package/src/lib/get-media-type.ts +105 -0
  122. package/src/lib/helpers.ts +199 -0
  123. package/src/lib/hierarchy.ts +117 -0
  124. package/src/lib/languages.ts +37 -0
  125. package/src/lib/lists.ts +56 -0
  126. package/src/lib/math.ts +111 -0
  127. package/src/lib/media.ts +334 -0
  128. package/src/lib/navigation-utils.ts +235 -0
  129. package/src/lib/normalize.ts +70 -0
  130. package/src/lib/paste.ts +304 -0
  131. package/src/lib/placeholder.ts +32 -0
  132. package/src/lib/platform.ts +18 -0
  133. package/src/lib/plugins.ts +22 -0
  134. package/src/lib/popper.ts +180 -0
  135. package/src/lib/position-menu.ts +184 -0
  136. package/src/lib/references.ts +94 -0
  137. package/src/lib/template.ts +29 -0
  138. package/src/lib/track-changes-utils.ts +34 -0
  139. package/{dist/types/lib/statistics.d.ts → src/lib/url.ts} +11 -8
  140. package/src/lib/use-do-with-debounce.ts +39 -0
  141. package/src/lib/utils.ts +323 -0
  142. package/src/lib/view.ts +100 -0
  143. package/src/menus.tsx +684 -0
  144. package/src/node-type-icons.tsx +83 -0
  145. package/src/plugins/__tests__/__fixtures__/deleted-footnote.json +140 -0
  146. package/src/plugins/__tests__/__fixtures__/inserted-footnote.json +153 -0
  147. package/src/plugins/__tests__/footnotes.test.ts +67 -0
  148. package/src/plugins/accessibility_element.ts +219 -0
  149. package/src/plugins/add-subtitle.ts +102 -0
  150. package/src/plugins/affiliations.ts +136 -0
  151. package/src/plugins/alt-titles.ts +219 -0
  152. package/src/plugins/bibliography.ts +235 -0
  153. package/src/plugins/comments.ts +328 -0
  154. package/src/plugins/cross-references.ts +70 -0
  155. package/src/plugins/detect-inconsistency/detect-inconsistency-utils.ts +102 -0
  156. package/src/plugins/detect-inconsistency/index.ts +55 -0
  157. package/src/plugins/detect-inconsistency/validators.ts +283 -0
  158. package/src/plugins/doi.ts +66 -0
  159. package/src/plugins/editor-props.ts +39 -0
  160. package/src/plugins/elements.ts +60 -0
  161. package/src/plugins/footnotes.ts +298 -0
  162. package/src/plugins/link.ts +53 -0
  163. package/src/plugins/lock-body.ts +136 -0
  164. package/src/plugins/move-node.ts +55 -0
  165. package/src/plugins/objects.ts +125 -0
  166. package/src/plugins/paragraphs.ts +90 -0
  167. package/src/plugins/persist.ts +64 -0
  168. package/src/plugins/persistent-cursor.ts +66 -0
  169. package/src/plugins/placeholder.ts +219 -0
  170. package/src/plugins/prevent-empty.ts +50 -0
  171. package/src/plugins/search-replace/index.ts +157 -0
  172. package/src/plugins/search-replace/lib.ts +95 -0
  173. package/src/plugins/section_category.ts +212 -0
  174. package/src/plugins/section_title/autocompletion.ts +87 -0
  175. package/src/plugins/section_title/index.ts +105 -0
  176. package/src/plugins/selected-suggestion.ts +243 -0
  177. package/src/plugins/tables-cursor-fix.ts +143 -0
  178. package/src/plugins/translations.ts +263 -0
  179. package/src/rules.ts +60 -0
  180. package/src/selection.ts +112 -0
  181. package/src/testing/default-capabilities.ts +48 -0
  182. package/src/testing/default-editor-data.ts +73 -0
  183. package/src/testing/empty-editor-doc.json +62 -0
  184. package/src/testing/polyfill-dom.ts +43 -0
  185. package/src/testing/section-categories.json +161 -0
  186. package/src/testing/setup-editor.ts +55 -0
  187. package/src/tests.ts +42 -0
  188. package/src/toolbar.tsx +259 -0
  189. package/src/types/@citation-js/core.d.ts +16 -0
  190. package/src/types/@citation-js/index.d.ts +16 -0
  191. package/src/types/@citation-js/plugin-bibtex.d.ts +16 -0
  192. package/src/types/@citation-js/plugin-csl.d.ts +16 -0
  193. package/src/types/@citation-js/plugin-doi.d.ts +16 -0
  194. package/src/types/@citation-js/plugin-enw.d.ts +16 -0
  195. package/src/types/@citation-js/plugin-pubmed.d.ts +16 -0
  196. package/src/types/@citation-js/plugin-ris.d.ts +16 -0
  197. package/src/types/citeproc.d.ts +124 -0
  198. package/src/types/css.d.ts +16 -0
  199. package/src/types/json.d.ts +17 -0
  200. package/src/types/prosemirror-dev-tools.d.ts +16 -0
  201. package/src/types/prosemirror-dropcursor.d.ts +16 -0
  202. package/src/types/styled-components.d.ts +23 -0
  203. package/src/types.ts +49 -0
  204. package/src/useEditor.ts +244 -0
  205. package/src/versions.ts +3 -0
  206. package/src/views/ReactSubView.tsx +145 -0
  207. package/src/views/abstracts.ts +46 -0
  208. package/src/views/accessibility_element.ts +86 -0
  209. package/src/views/affiliations.ts +254 -0
  210. package/src/views/alt_title.ts +85 -0
  211. package/src/views/alt_titles_section.ts +97 -0
  212. package/src/views/attachment.ts +160 -0
  213. package/src/views/attachments.ts +72 -0
  214. package/src/views/author_notes.ts +96 -0
  215. package/src/views/award.ts +194 -0
  216. package/src/views/awards.ts +59 -0
  217. package/src/views/base_node_view.ts +85 -0
  218. package/src/views/bibliography_element.ts +313 -0
  219. package/src/views/block_view.ts +100 -0
  220. package/src/views/blockquote_element.ts +26 -0
  221. package/src/views/blockquote_element_editable.ts +24 -0
  222. package/src/views/box_element.ts +33 -0
  223. package/src/views/caption.ts +37 -0
  224. package/src/views/caption_title.ts +33 -0
  225. package/src/views/citation.ts +67 -0
  226. package/src/views/citation_editable.ts +312 -0
  227. package/src/views/contributors.ts +341 -0
  228. package/src/views/creators.ts +82 -0
  229. package/src/views/cross_reference.ts +74 -0
  230. package/src/views/cross_reference_editable.ts +113 -0
  231. package/src/views/editable_block.ts +141 -0
  232. package/src/views/embed.ts +345 -0
  233. package/src/views/empty.ts +26 -0
  234. package/src/views/equation.ts +47 -0
  235. package/src/views/equation_editable.ts +84 -0
  236. package/src/views/equation_element.ts +29 -0
  237. package/src/views/equation_element_editable.ts +21 -0
  238. package/src/views/figure.ts +84 -0
  239. package/src/views/figure_editable.ts +361 -0
  240. package/src/views/figure_element.ts +197 -0
  241. package/src/views/figure_element_editable.ts +21 -0
  242. package/src/views/footnote.ts +236 -0
  243. package/src/views/footnotes_element.ts +54 -0
  244. package/src/views/general_table_footnote.ts +140 -0
  245. package/src/views/hero_image.ts +76 -0
  246. package/src/views/hero_image_editable.ts +21 -0
  247. package/src/views/image_element.ts +373 -0
  248. package/src/views/image_element_editable.ts +21 -0
  249. package/src/views/inline_equation.ts +47 -0
  250. package/src/views/inline_equation_editable.ts +70 -0
  251. package/src/views/inline_footnote.ts +264 -0
  252. package/src/views/inline_footnote_editable.ts +20 -0
  253. package/src/views/keyword.ts +127 -0
  254. package/src/views/keyword_group.ts +109 -0
  255. package/src/views/link.ts +27 -0
  256. package/src/views/link_editable.ts +169 -0
  257. package/src/views/list.ts +46 -0
  258. package/src/views/list_item.ts +26 -0
  259. package/src/views/paragraph.ts +26 -0
  260. package/src/views/paragraph_editable.ts +21 -0
  261. package/src/views/placeholder.ts +35 -0
  262. package/src/views/placeholder_element.ts +38 -0
  263. package/src/views/placeholder_element_editable.ts +21 -0
  264. package/src/views/pullquote_element.ts +106 -0
  265. package/src/views/pullquote_element_editable.ts +24 -0
  266. package/src/views/quote_image_editable.ts +84 -0
  267. package/src/views/section.ts +64 -0
  268. package/src/views/section_label.ts +20 -0
  269. package/src/views/section_title.ts +87 -0
  270. package/src/views/section_title_editable.ts +21 -0
  271. package/src/views/subtitle.ts +42 -0
  272. package/src/views/subtitle_editable.ts +20 -0
  273. package/src/views/subtitles.ts +34 -0
  274. package/src/views/subtitles_editable.ts +21 -0
  275. package/src/views/supplement.ts +236 -0
  276. package/src/views/supplement_editable.ts +20 -0
  277. package/src/views/supplements.ts +65 -0
  278. package/src/views/supplements_editable.ts +21 -0
  279. package/src/views/table_cell.ts +150 -0
  280. package/src/views/table_element.ts +33 -0
  281. package/src/views/table_element_editable.ts +21 -0
  282. package/src/views/table_element_footer.ts +41 -0
  283. package/src/views/title.ts +46 -0
  284. package/src/views/title_editable.ts +20 -0
  285. package/src/views/trans_graphical_abstract.ts +55 -0
  286. package/src/views/trans_graphical_abstract_editable.ts +21 -0
  287. package/src/views/translated_abstract.ts +53 -0
  288. package/src/views/translated_abstract_editable.ts +21 -0
  289. package/dist/cjs/lib/statistics.js +0 -38
@@ -0,0 +1,172 @@
1
+ /*!
2
+ * © 2025 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 {
17
+ CloseButton,
18
+ ModalContainer,
19
+ ModalHeader,
20
+ StyledModal,
21
+ } from '@manuscripts/style-guide'
22
+ import { generateNodeID, schema } from '@manuscripts/transform'
23
+ import React, { useEffect, useMemo, useRef, useState } from 'react'
24
+
25
+ import { AffiliationAttrs, ContributorAttrs } from '../../lib/authors'
26
+ import { normalizeAuthor } from '../../lib/normalize'
27
+ import {
28
+ MODAL_ON_CLOSE_NOTIFY_DELAY_MS,
29
+ FormTitle,
30
+ StyledModalBody,
31
+ StyledScrollableModalContent,
32
+ } from '../form/CreateModalStyles'
33
+ import FormFooter from '../form/FormFooter'
34
+ import { ModalFormSaveButton } from '../form/ModalFormActions'
35
+ import { AuthorDetailsForm, FormActions } from './AuthorDetailsForm'
36
+ import { useManageAffiliations } from './useManageAffiliations'
37
+ import { useManageCredit } from './useManageCredit'
38
+
39
+ export interface CreateAuthorModalProps {
40
+ authorsCount: number
41
+ affiliations: AffiliationAttrs[]
42
+ onSave: (author: ContributorAttrs) => void
43
+ onClose: () => void
44
+ }
45
+
46
+ export const CreateAuthorModal: React.FC<CreateAuthorModalProps> = ({
47
+ authorsCount,
48
+ affiliations: $affiliations,
49
+ onSave,
50
+ onClose,
51
+ }) => {
52
+ const [isOpen, setIsOpen] = useState(true)
53
+ const [isDisableSave, setDisableSave] = useState(true)
54
+ const [isEmailRequired, setEmailRequired] = useState(false)
55
+ const [hasError, setHasError] = useState(false)
56
+ const actionsRef = useRef<FormActions>(undefined)
57
+ const authorFormRef = useRef<HTMLFormElement>(null)
58
+
59
+ const selection = useMemo(
60
+ () => createEmptyAuthor(authorsCount),
61
+ // eslint-disable-next-line react-hooks/exhaustive-deps
62
+ []
63
+ )
64
+
65
+ // Wait for the close animation to finish before calling onClose.
66
+ const prevIsOpenRef = useRef(true)
67
+ useEffect(() => {
68
+ if (prevIsOpenRef.current && !isOpen) {
69
+ prevIsOpenRef.current = isOpen
70
+ const id = window.setTimeout(() => {
71
+ onClose()
72
+ }, MODAL_ON_CLOSE_NOTIFY_DELAY_MS)
73
+ return () => window.clearTimeout(id)
74
+ }
75
+ prevIsOpenRef.current = isOpen
76
+ }, [isOpen, onClose])
77
+
78
+ const { selectedAffiliations } = useManageAffiliations(
79
+ selection,
80
+ $affiliations
81
+ )
82
+
83
+ const { selectedCreditRoles } = useManageCredit(selection)
84
+
85
+ const handleSave = (values: ContributorAttrs) => {
86
+ onSave({ ...selection, ...values })
87
+ setIsOpen(false)
88
+ }
89
+
90
+ const handleChange = (values: ContributorAttrs) => {
91
+ const { given, family, email, isCorresponding } = values
92
+ const isNameFilled = given?.length || family?.length
93
+
94
+ if (isNameFilled) {
95
+ if (isCorresponding) {
96
+ setDisableSave(!email?.length)
97
+ } else {
98
+ setDisableSave(false)
99
+ }
100
+ } else {
101
+ setDisableSave(true)
102
+ }
103
+
104
+ setEmailRequired(!!isCorresponding)
105
+ }
106
+
107
+ return (
108
+ <StyledModal
109
+ isOpen={isOpen}
110
+ onRequestClose={() => setIsOpen(false)}
111
+ shouldCloseOnOverlayClick={true}
112
+ >
113
+ <ModalContainer data-cy="create-author-modal">
114
+ <ModalHeader>
115
+ <CloseButton
116
+ onClick={() => setIsOpen(false)}
117
+ data-cy="modal-close-button"
118
+ />
119
+ </ModalHeader>
120
+ <StyledModalBody>
121
+ <StyledScrollableModalContent>
122
+ <FormTitle>Create Author</FormTitle>
123
+ <AuthorDetailsForm
124
+ values={normalizeAuthor(selection)}
125
+ onChange={handleChange}
126
+ onSave={handleSave}
127
+ actionsRef={actionsRef}
128
+ isEmailRequired={isEmailRequired}
129
+ selectedAffiliations={selectedAffiliations.map((a) => a.id)}
130
+ authorFormRef={authorFormRef}
131
+ selectedCreditRoles={selectedCreditRoles}
132
+ newEntity={true}
133
+ onAuthorDetailsTabErrorChange={setHasError}
134
+ />
135
+ </StyledScrollableModalContent>
136
+ </StyledModalBody>
137
+ <FormFooter
138
+ onCancel={() => setIsOpen(false)}
139
+ primaryAction={
140
+ <ModalFormSaveButton
141
+ form="author-details-form"
142
+ isDisableSave={isDisableSave || hasError}
143
+ label="New Author"
144
+ onSubmitForm={() => actionsRef.current?.submitForm?.()}
145
+ />
146
+ }
147
+ />
148
+ </ModalContainer>
149
+ </StyledModal>
150
+ )
151
+ }
152
+
153
+ function createEmptyAuthor(priority: number): ContributorAttrs {
154
+ return {
155
+ id: generateNodeID(schema.nodes.contributor),
156
+ role: '',
157
+ affiliationIDs: [],
158
+ degrees: [],
159
+ given: '',
160
+ family: '',
161
+ email: '',
162
+ suffix: '',
163
+ isCorresponding: false,
164
+ ORCID: '',
165
+ priority,
166
+ isJointContributor: false,
167
+ correspIDs: [],
168
+ footnoteIDs: [],
169
+ prefix: '',
170
+ creditRoles: [],
171
+ }
172
+ }
@@ -0,0 +1,71 @@
1
+ /*!
2
+ * © 2025 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 {
17
+ CheckboxField,
18
+ CheckboxLabel,
19
+ LabelText,
20
+ } from '@manuscripts/style-guide'
21
+ import React from 'react'
22
+ import styled from 'styled-components'
23
+
24
+ import { CheckboxContainer } from './AuthorDetailsForm'
25
+
26
+ export interface CreditContributionsCheckboxesProps {
27
+ items: { id: string; vocabTerm: string }[]
28
+ selectedItems: { id: string }[]
29
+ onSelect: (id: string) => void
30
+ }
31
+
32
+ export const CreditContributionsCheckboxes: React.FC<
33
+ CreditContributionsCheckboxesProps
34
+ > = ({ items, selectedItems = [], onSelect }) => {
35
+ const selectedIds = selectedItems.map((a) => a.id)
36
+ return (
37
+ <TwoColumnContainer
38
+ data-cy="credit-taxnonomy"
39
+ role="group"
40
+ aria-label="Contributions (CRediT)"
41
+ >
42
+ {items.map((item) => (
43
+ <TwoColumnCheckbox key={item.id}>
44
+ <CheckboxLabel>
45
+ <CheckboxField
46
+ name={item.id}
47
+ checked={selectedIds.includes(item.id)}
48
+ onChange={() => {
49
+ onSelect(item.id)
50
+ }}
51
+ />
52
+ <LabelText>{item.vocabTerm}</LabelText>
53
+ </CheckboxLabel>
54
+ </TwoColumnCheckbox>
55
+ ))}
56
+ </TwoColumnContainer>
57
+ )
58
+ }
59
+
60
+ const TwoColumnContainer = styled.ul`
61
+ list-style: none;
62
+ padding: 0 ${(props) => props.theme.grid.unit * 4}px;
63
+ margin: 0;
64
+ display: flex;
65
+ flex-flow: row wrap;
66
+ position: relative;
67
+ `
68
+
69
+ const TwoColumnCheckbox = styled(CheckboxContainer)`
70
+ flex: 1 0 50%;
71
+ `
@@ -0,0 +1,228 @@
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
+
17
+ import {
18
+ Avatar,
19
+ CorrespondingAuthorIcon,
20
+ CrclTickAnimation,
21
+ DeleteIcon,
22
+ DraggableIcon,
23
+ withNavigableListItem,
24
+ } from '@manuscripts/style-guide'
25
+ import React, { useRef, useState } from 'react'
26
+ import { useDrag, useDrop } from 'react-dnd'
27
+ import styled from 'styled-components'
28
+
29
+ import { authorLabel, ContributorAttrs } from '../../lib/authors'
30
+ import { DropSide, getDropSide } from '../../lib/dnd'
31
+ import { DeleteButton } from '../references/ReferenceForm/styled-components'
32
+
33
+ const AuthorContainer = withNavigableListItem(styled.div`
34
+ padding: ${(props) => props.theme.grid.unit * 2}px 0
35
+ ${(props) => props.theme.grid.unit * 2}px;
36
+ display: flex;
37
+ justify-content: space-between;
38
+ align-items: center;
39
+ transition: background-color 0.25s;
40
+ border: 1px solid transparent;
41
+ border-left: 0;
42
+ border-right: 0;
43
+ cursor: pointer;
44
+ &:hover,
45
+ &.active {
46
+ background: ${(props) => props.theme.colors.background.fifth};
47
+ border-color: ${(props) => props.theme.colors.border.primary};
48
+ }
49
+ &.dragging {
50
+ opacity: 1;
51
+ cursor: grabbing;
52
+ }
53
+
54
+ &.dragging * {
55
+ opacity: 0;
56
+ }
57
+
58
+ &.drop-before {
59
+ cursor: grabbing;
60
+ border-top-color: ${(props) => props.theme.colors.brand.dark};
61
+ }
62
+
63
+ &.drop-after {
64
+ cursor: grabbing;
65
+ border-bottom-color: ${(props) => props.theme.colors.brand.dark};
66
+ }
67
+ `)
68
+
69
+ const AvatarContainer = styled.div`
70
+ display: inline-flex;
71
+ position: relative;
72
+ align-items: center;
73
+ `
74
+
75
+ const Box = styled.div`
76
+ margin-left: 14px;
77
+ `
78
+
79
+ const AuthorBadge = styled.div`
80
+ display: inline-flex;
81
+ align-items: center;
82
+ justify-content: center;
83
+ position: relative;
84
+ `
85
+
86
+ const AuthorNotes = styled.div`
87
+ position: absolute;
88
+ top: 0;
89
+ right: 0;
90
+
91
+ & ${AuthorBadge}:not(:last-child) {
92
+ right: -20%;
93
+ }
94
+ `
95
+
96
+ const AuthorName = styled.div`
97
+ margin-left: 12px;
98
+ flex: 1;
99
+ `
100
+
101
+ const DragHandle = styled(DraggableIcon)`
102
+ cursor: move;
103
+ margin-left: -4px;
104
+ margin-right: -12px;
105
+ `
106
+ const RemoveButton = styled(DeleteButton)`
107
+ .icon_element {
108
+ fill: ${(props) => (props.disabled && '#c9c9c9') || '#6E6E6E'} !important;
109
+ }
110
+ `
111
+ const StyledCrclTickAnimation = styled(CrclTickAnimation)`
112
+ margin-left: 12px;
113
+ `
114
+ interface DragItem {
115
+ author: ContributorAttrs
116
+ }
117
+
118
+ interface DraggableAuthorProps {
119
+ author: ContributorAttrs
120
+ isSelected: boolean
121
+ onClick: () => void
122
+ onDelete: () => void
123
+ moveAuthor: (
124
+ from: ContributorAttrs,
125
+ to: ContributorAttrs,
126
+ shift: number
127
+ ) => void
128
+ showSuccessIcon?: boolean
129
+ }
130
+
131
+ export const DraggableAuthor: React.FC<DraggableAuthorProps> = React.memo(
132
+ ({ author, isSelected, onClick, onDelete, moveAuthor, showSuccessIcon }) => {
133
+ const [dropSide, setDropSide] = useState<DropSide>()
134
+ const ref = useRef<HTMLDivElement>(null)
135
+ const [{ isDragging }, dragRef, preview] = useDrag({
136
+ type: 'author',
137
+ item: {
138
+ author,
139
+ },
140
+ collect: (monitor) => {
141
+ return {
142
+ isDragging: monitor.isDragging(),
143
+ }
144
+ },
145
+ })
146
+ preview(ref)
147
+ const [{ isOver }, dropRef] = useDrop({
148
+ accept: 'author',
149
+ hover: (item: DragItem, monitor) => {
150
+ if (!ref.current) {
151
+ return
152
+ }
153
+ const side = getDropSide(ref.current, monitor)
154
+ setDropSide(side)
155
+ },
156
+ drop: (item: DragItem, monitor) => {
157
+ if (!ref.current) {
158
+ return
159
+ }
160
+ const side = getDropSide(ref.current, monitor)
161
+ const diff = side === 'before' ? -0.5 : 0.5
162
+ moveAuthor(item.author, author, diff)
163
+ },
164
+ collect: (monitor) => ({
165
+ isOver: monitor.isOver(),
166
+ }),
167
+ })
168
+
169
+ dragRef(dropRef(ref))
170
+
171
+ const classes: string[] = []
172
+ if (isDragging) {
173
+ classes.push('dragging')
174
+ }
175
+
176
+ if (isOver && dropSide) {
177
+ classes.push(`drop-${dropSide}`)
178
+ }
179
+
180
+ if (isSelected) {
181
+ classes.push('active')
182
+ if (ref.current) {
183
+ ref.current.scrollIntoView({
184
+ behavior: 'smooth',
185
+ block: 'center',
186
+ })
187
+ }
188
+ }
189
+
190
+ return (
191
+ <AuthorContainer
192
+ ref={ref}
193
+ className={classes.join(' ')}
194
+ onClick={onClick}
195
+ data-cy="author-item"
196
+ >
197
+ <AvatarContainer data-cy="author-avatar">
198
+ {isSelected && <DragHandle />}
199
+ <Box>
200
+ {showSuccessIcon && <StyledCrclTickAnimation size={36} />}
201
+ <Avatar
202
+ size={36}
203
+ color={'#6e6e6e'}
204
+ opacity={showSuccessIcon ? 0.05 : 1}
205
+ />
206
+ </Box>
207
+ <AuthorNotes data-cy="author-notes">
208
+ {author.isCorresponding && (
209
+ <AuthorBadge>
210
+ <CorrespondingAuthorIcon />
211
+ </AuthorBadge>
212
+ )}
213
+ </AuthorNotes>
214
+ </AvatarContainer>
215
+ <AuthorName data-cy="author-name">{authorLabel(author)}</AuthorName>
216
+ {isSelected && (
217
+ <RemoveButton
218
+ size={13}
219
+ onClick={() => onDelete()}
220
+ data-tooltip-content="Delete"
221
+ >
222
+ <DeleteIcon fill={'#6E6E6E'} />
223
+ </RemoveButton>
224
+ )}
225
+ </AuthorContainer>
226
+ )
227
+ }
228
+ )
@@ -0,0 +1,77 @@
1
+ /*!
2
+ * © 2025 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 { useEffect, useReducer, useState } from 'react'
17
+
18
+ import { arrayReducer } from '../../lib/array-reducer'
19
+ import { AffiliationAttrs, ContributorAttrs } from '../../lib/authors'
20
+
21
+ export const affiliationsReducer = arrayReducer<AffiliationAttrs>(
22
+ (a, b) => a.id === b.id
23
+ )
24
+
25
+ export const useManageAffiliations = (
26
+ selection: ContributorAttrs | undefined,
27
+ $affiliations: AffiliationAttrs[]
28
+ ) => {
29
+ const [affiliations, dispatchAffiliations] = useReducer(affiliationsReducer, [
30
+ ...$affiliations,
31
+ ])
32
+
33
+ useEffect(() => {
34
+ dispatchAffiliations({ type: 'set', state: [...$affiliations] })
35
+ }, [$affiliations])
36
+ const [selectedAffiliations, setSelectedAffiliations] = useState<
37
+ {
38
+ id: string
39
+ institution: string
40
+ }[]
41
+ >([])
42
+
43
+ const removeAffiliation = (affId: string) => {
44
+ if (!selection) {
45
+ return
46
+ }
47
+ const newAffiliations = selectedAffiliations
48
+ .map((a) => a.id)
49
+ .filter((id) => id !== affId)
50
+ setSelectedAffiliations(
51
+ affiliations.filter((item) => newAffiliations.includes(item.id))
52
+ )
53
+ }
54
+ const selectAffiliation = (affiliationId: string) => {
55
+ if (!selection) {
56
+ return
57
+ }
58
+
59
+ const currentAffiliations = selectedAffiliations.map((a) => a.id)
60
+ const isAlreadySelected = currentAffiliations.includes(affiliationId)
61
+
62
+ const newAffiliations = isAlreadySelected
63
+ ? currentAffiliations.filter((id) => id !== affiliationId)
64
+ : [...currentAffiliations, affiliationId]
65
+
66
+ setSelectedAffiliations(
67
+ affiliations.filter((item) => newAffiliations.includes(item.id))
68
+ )
69
+ }
70
+ return {
71
+ selectedAffiliations,
72
+ setSelectedAffiliations,
73
+ removeAffiliation,
74
+ selectAffiliation,
75
+ affiliations,
76
+ }
77
+ }
@@ -0,0 +1,63 @@
1
+ /*!
2
+ * © 2025 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 { CreditRole, CreditVocabTerm } from '@manuscripts/transform'
17
+ import { useEffect, useMemo, useState } from 'react'
18
+
19
+ import { ContributorAttrs } from '../../lib/authors'
20
+
21
+ export const useManageCredit = (selection: ContributorAttrs | undefined) => {
22
+ const vocabTermItems = useMemo(() => {
23
+ return Object.values(CreditVocabTerm).map((c) => ({
24
+ vocabTerm: c,
25
+ id: c,
26
+ }))
27
+ }, [])
28
+
29
+ useEffect(() => {
30
+ setSelectedCreditRoles(selection?.creditRoles ? selection?.creditRoles : [])
31
+ }, [selection])
32
+
33
+ const [selectedCreditRoles, setSelectedCreditRoles] = useState<CreditRole[]>(
34
+ []
35
+ )
36
+
37
+ const selectCreditRole = (role: string) => {
38
+ setSelectedCreditRoles((prev) => {
39
+ const clear = prev.filter((t) => t.vocabTerm !== role)
40
+ if (clear.length !== prev.length) {
41
+ return clear
42
+ }
43
+ const newTerm = vocabTermItems.find((t) => t.vocabTerm === role)
44
+ if (newTerm) {
45
+ return [...prev, { vocabTerm: newTerm.vocabTerm }]
46
+ }
47
+ return prev
48
+ })
49
+ }
50
+
51
+ const removeCreditRole = (role: string) => {
52
+ setSelectedCreditRoles((prev) => {
53
+ return prev.filter((r) => r.vocabTerm !== role)
54
+ })
55
+ }
56
+ return {
57
+ removeCreditRole,
58
+ selectCreditRole,
59
+ selectedCreditRoles,
60
+ setSelectedCreditRoles,
61
+ vocabTermItems,
62
+ }
63
+ }