@manuscripts/body-editor 3.12.67 → 3.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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,338 @@
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
+ MultiValueInput,
19
+ PrimaryButton,
20
+ SearchIcon,
21
+ SecondaryButton,
22
+ TextField,
23
+ FormRow,
24
+ Label,
25
+ Theme,
26
+ ButtonGroup,
27
+ } from '@manuscripts/style-guide'
28
+ import { Field, FieldProps, Formik, FormikProps } from 'formik'
29
+ import React, { useMemo, useRef } from 'react'
30
+ import styled, { useTheme } from 'styled-components'
31
+
32
+ import { AwardAttrs } from '../../views/award'
33
+ import { ChangeHandlingForm } from '../ChangeHandlingForm'
34
+ import {
35
+ ControlProps,
36
+ OptionProps,
37
+ components,
38
+ StylesConfig,
39
+ InputActionMeta,
40
+ InputProps,
41
+ SingleValue,
42
+ } from 'react-select'
43
+ import AsyncCreatableSelect from 'react-select/async-creatable'
44
+ import useDebounced from '../hooks/use-debounce'
45
+
46
+ export interface AwardFormProps {
47
+ values: AwardAttrs
48
+ onSave: (values: AwardAttrs) => void
49
+ onCancel: () => void
50
+ onChange: (values: AwardAttrs) => void
51
+ }
52
+
53
+ interface Funder {
54
+ id: string
55
+ location: string
56
+ name: string
57
+ 'alt-names': string[]
58
+ uri: string
59
+ replaces: string[]
60
+ 'replaced-by': string[]
61
+ tokens: string[]
62
+ }
63
+
64
+ interface FunderOption {
65
+ value: string
66
+ label: string
67
+ }
68
+
69
+ const loadOptions = async (inputValue: string): Promise<FunderOption[]> => {
70
+ try {
71
+ const formattedQuery = inputValue.replace(/\s+/g, '+')
72
+ const response = await fetch(
73
+ `https://api.crossref.org/funders?query=${encodeURIComponent(formattedQuery)}`
74
+ )
75
+ if (!response.ok) {
76
+ console.log(`HTTP error! status: ${response.status}`)
77
+ return []
78
+ }
79
+ const data = await response.json()
80
+ const funderOptions: FunderOption[] = data.message.items.map(
81
+ (funder: Funder) => ({
82
+ value: funder.name,
83
+ label: funder.name,
84
+ })
85
+ )
86
+ return funderOptions.sort((a, b) => a.label.localeCompare(b.label))
87
+ } catch (e) {
88
+ console.error('Error fetching funders:', e)
89
+ return []
90
+ }
91
+ }
92
+
93
+ export const AwardForm = ({
94
+ values,
95
+ onSave,
96
+ onCancel,
97
+ onChange,
98
+ }: AwardFormProps) => {
99
+ const formRef = useRef<FormikProps<AwardAttrs>>(null)
100
+ const primaryButtonText = values.source ? 'Update funder' : 'Add funder'
101
+
102
+ const themes = useTheme() as Theme
103
+ const customStyles = useMemo(() => getCustomStyles(themes), [themes])
104
+
105
+ const handleOnLoadFunders = useDebounced(
106
+ async (inputValue: string) => loadOptions(inputValue),
107
+ 300
108
+ )
109
+
110
+ const handleCancel = () => {
111
+ formRef.current?.resetForm()
112
+ onCancel()
113
+ }
114
+
115
+ const handleInputChange = (value: string, action: InputActionMeta) => {
116
+ if (action.action === 'input-change') {
117
+ formRef.current?.setFieldValue('source', value)
118
+ }
119
+ }
120
+
121
+ const validate = (values: AwardAttrs) => {
122
+ const errors: Partial<AwardAttrs> = {} // Object to hold validation errors
123
+ if (!values.source) {
124
+ errors.source = 'Funder name is required'
125
+ }
126
+ return errors // Return errors object to Formik
127
+ }
128
+
129
+ return (
130
+ <Formik<AwardAttrs>
131
+ initialValues={values}
132
+ onSubmit={(values, { setSubmitting }) => {
133
+ onSave(values)
134
+ setSubmitting(false)
135
+ }}
136
+ enableReinitialize={true}
137
+ validate={validate}
138
+ validateOnChange={false}
139
+ innerRef={formRef}
140
+ >
141
+ {(formik) => {
142
+ return (
143
+ <ChangeHandlingForm onChange={onChange}>
144
+ <Field type="hidden" name="id" />
145
+
146
+ <FormRow>
147
+ <Label htmlFor={'source'}>Funder name</Label>
148
+ <Field name="source">
149
+ {(props: FieldProps) => (
150
+ <AsyncCreatableSelect<FunderOption>
151
+ inputId={'source'}
152
+ loadOptions={handleOnLoadFunders}
153
+ onInputChange={handleInputChange}
154
+ autoFocus={true}
155
+ onChange={(option: SingleValue<FunderOption>) =>
156
+ option &&
157
+ formRef.current?.setFieldValue('source', option.value)
158
+ }
159
+ inputValue={props.field.value}
160
+ value={null}
161
+ isValidNewOption={() => false}
162
+ components={{
163
+ Input,
164
+ Control,
165
+ Option,
166
+ DropdownIndicator: null,
167
+ IndicatorSeparator: null,
168
+ }}
169
+ styles={customStyles}
170
+ placeholder="Search for funder..."
171
+ />
172
+ )}
173
+ </Field>
174
+ {formik.errors.source && formik.touched.source && (
175
+ <ErrorText>{formik.errors.source}</ErrorText>
176
+ )}
177
+ </FormRow>
178
+
179
+ <FormRow>
180
+ <Label htmlFor={'code'}>Grant number</Label>
181
+ <MultiValueInput
182
+ id="code"
183
+ inputType="text"
184
+ placeholder="Enter grant number and press enter"
185
+ initialValues={values.code ? values.code.split(';') : []}
186
+ onChange={(newValues) => {
187
+ formik.setFieldValue('code', newValues.join(';'))
188
+ }}
189
+ />
190
+ </FormRow>
191
+
192
+ <FormRow>
193
+ <Label htmlFor={'recipient'}>Recipient name</Label>
194
+ <Field name="recipient">
195
+ {(props: FieldProps) => (
196
+ <TextField
197
+ id="recipient"
198
+ placeholder="Enter full name"
199
+ {...props.field}
200
+ />
201
+ )}
202
+ </Field>
203
+ </FormRow>
204
+
205
+ <FormRow>
206
+ <FormActions>
207
+ <SecondaryButton onClick={handleCancel}>Cancel</SecondaryButton>
208
+ <PrimaryButton
209
+ type="submit"
210
+ disabled={!formik.dirty || formik.isSubmitting}
211
+ >
212
+ {primaryButtonText}
213
+ </PrimaryButton>
214
+ </FormActions>
215
+ </FormRow>
216
+ </ChangeHandlingForm>
217
+ )
218
+ }}
219
+ </Formik>
220
+ )
221
+ }
222
+ // TODO:: All that react-select component and styles should be in style-guide with a standard select component
223
+
224
+ const SearchIconContainer = styled.span<{ isFocused: boolean }>`
225
+ display: flex;
226
+ align-items: center;
227
+ padding-left: ${(props) => props.theme.grid.unit * 4}px;
228
+ padding-right: ${(props) => props.theme.grid.unit * 2}px;
229
+
230
+ path {
231
+ stroke: ${(props) =>
232
+ props.isFocused
233
+ ? props.theme.colors.brand.medium
234
+ : props.theme.colors.text.primary};
235
+ }
236
+ `
237
+
238
+ const OptionWrapper = styled.div<{ focused?: boolean; selected?: boolean }>`
239
+ padding-left: ${(props) => props.theme.grid.unit * 4}px;
240
+ padding-top: ${(props) => props.theme.grid.unit * 2}px;
241
+ padding-bottom: ${(props) => props.theme.grid.unit * 2}px;
242
+
243
+ background-color: ${(props) => {
244
+ if (props.selected) {
245
+ return props.theme.colors.background.selected
246
+ }
247
+ if (props.focused) {
248
+ return props.theme.colors.background.fifth
249
+ }
250
+ return 'transparent'
251
+ }};
252
+
253
+ &:hover {
254
+ background-color: ${(props) => props.theme.colors.background.fifth};
255
+ }
256
+ `
257
+
258
+ const Option: React.FC<OptionProps<FunderOption, false>> = ({
259
+ innerProps,
260
+ innerRef,
261
+ data,
262
+ isFocused,
263
+ isSelected,
264
+ }) => {
265
+ return (
266
+ <OptionWrapper
267
+ {...innerProps}
268
+ ref={innerRef}
269
+ focused={isFocused}
270
+ selected={isSelected}
271
+ >
272
+ {data.label}
273
+ </OptionWrapper>
274
+ )
275
+ }
276
+
277
+ const Control = ({ children, ...props }: ControlProps<FunderOption, false>) => {
278
+ return (
279
+ <components.Control {...props}>
280
+ <SearchIconContainer isFocused={props.isFocused}>
281
+ <SearchIcon />
282
+ </SearchIconContainer>
283
+ {children}
284
+ </components.Control>
285
+ )
286
+ }
287
+ // this to prevent clearing text input from selected option ISSUE:
288
+ // https://github.com/JedWatson/react-select/issues/2296
289
+ const Input = (props: InputProps<FunderOption, false>) => (
290
+ <components.Input {...props} isHidden={false} />
291
+ )
292
+
293
+ const getCustomStyles = (theme: Theme): StylesConfig<FunderOption, false> => ({
294
+ control: (provided, state) => ({
295
+ ...provided,
296
+ minHeight: '40px',
297
+ borderRadius: '4px',
298
+ border: `${state.isFocused ? '2px' : '1px'} solid ${state.isFocused ? theme.colors.brand.default : theme.colors.border.secondary}`,
299
+ backgroundColor:
300
+ state.isFocused || state.menuIsOpen
301
+ ? theme.colors.background.fifth
302
+ : theme.colors.background.primary,
303
+ boxShadow: 'none',
304
+ cursor: 'text',
305
+ transition: 'background-color 0.2s',
306
+ '&:hover': {
307
+ backgroundColor: theme.colors.background.fifth,
308
+ },
309
+ }),
310
+ input: (provided) => ({
311
+ ...provided,
312
+ margin: 0,
313
+ padding: 0,
314
+ color: theme.colors.text.primary,
315
+ fontSize: theme.font.size.normal,
316
+ fontFamily: theme.font.family.sans,
317
+ }),
318
+ placeholder: (provided, state) => ({
319
+ ...provided,
320
+ margin: 0,
321
+ fontStyle: 'italic',
322
+ color: state.isFocused ? '#c9c9c9' : theme.colors.text.secondary,
323
+ fontSize: theme.font.size.medium,
324
+ fontFamily: theme.font.family.sans,
325
+ fontWeight: theme.font.weight.normal,
326
+ lineHeight: theme.font.lineHeight.large,
327
+ }),
328
+ })
329
+
330
+ const FormActions = styled(ButtonGroup)`
331
+ margin: ${(props) => props.theme.grid.unit * 2}px;
332
+ `
333
+
334
+ const ErrorText = styled.div`
335
+ color: ${(props) => props.theme.colors.text.error};
336
+ font-size: ${(props) => props.theme.font.size.small};
337
+ margin-top: 4px;
338
+ `
@@ -0,0 +1,120 @@
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
+ ModalCardBody,
19
+ ModalContainer,
20
+ ModalHeader,
21
+ ModalTitle,
22
+ StyledModal,
23
+ } from '@manuscripts/style-guide'
24
+ import React, { useRef, useState } from 'react'
25
+ import { schema } from '@manuscripts/transform'
26
+ import { EditorView } from 'prosemirror-view'
27
+
28
+ import ReactSubView from '../../views/ReactSubView'
29
+ import { AwardAttrs } from '../../views/award'
30
+ import { getEditorProps } from '../../plugins/editor-props'
31
+ import { AwardForm } from './AwardForm'
32
+ import { insertAward } from '../../commands'
33
+
34
+ const normalizeData = (award: AwardAttrs) => ({
35
+ id: award.id || '',
36
+ source: award.source || '',
37
+ code: award.code || '',
38
+ recipient: award.recipient || '',
39
+ })
40
+
41
+ export interface AwardFormData {
42
+ id: string
43
+ recipient: string
44
+ code: string
45
+ source: string
46
+ }
47
+
48
+ export interface AwardModalProps {
49
+ initialData: AwardAttrs
50
+ onSaveAward: (data: AwardFormData) => void
51
+ }
52
+
53
+ export const AwardModal: React.FC<AwardModalProps> = ({
54
+ initialData,
55
+ onSaveAward,
56
+ }) => {
57
+ const [isOpen, setOpen] = useState(true)
58
+ const valuesRef = useRef<AwardAttrs>(undefined)
59
+
60
+ const handleSave = () => {
61
+ const updatedValues = valuesRef.current
62
+ if (updatedValues) {
63
+ onSaveAward(updatedValues)
64
+ handleClose()
65
+ }
66
+ }
67
+ const handleClose = () => setOpen(false)
68
+ const handleChange = (values: AwardAttrs) => (valuesRef.current = values)
69
+
70
+ const normalizedValues = React.useMemo(
71
+ () => normalizeData(initialData),
72
+ [initialData]
73
+ )
74
+
75
+ return (
76
+ <StyledModal
77
+ isOpen={isOpen}
78
+ onRequestClose={handleClose}
79
+ shouldCloseOnOverlayClick={true}
80
+ >
81
+ <ModalContainer data-cy="award-modal">
82
+ <ModalHeader>
83
+ <CloseButton onClick={handleClose} data-cy="modal-close-button" />
84
+ </ModalHeader>
85
+ <ModalCardBody width={480}>
86
+ <ModalTitle>Add Funder information</ModalTitle>
87
+ <AwardForm
88
+ values={normalizedValues}
89
+ onSave={handleSave}
90
+ onCancel={handleClose}
91
+ onChange={handleChange}
92
+ />
93
+ </ModalCardBody>
94
+ </ModalContainer>
95
+ </StyledModal>
96
+ )
97
+ }
98
+
99
+ export const openInsertAwardModal = (view?: EditorView) => {
100
+ if (!view) {
101
+ return
102
+ }
103
+
104
+ const { state, dispatch } = view
105
+ const props = getEditorProps(state)
106
+ const onSaveAward = (attrs: AwardAttrs) => {
107
+ insertAward(attrs)(state, dispatch, view)
108
+ }
109
+ const initialData = schema.nodes.award.create().attrs
110
+ const dialog = ReactSubView(
111
+ props,
112
+ AwardModal,
113
+ { initialData, onSaveAward },
114
+ state.doc,
115
+ () => 0,
116
+ view
117
+ )
118
+
119
+ document.body.appendChild(dialog)
120
+ }
@@ -0,0 +1,52 @@
1
+ /*!
2
+ * © 2023 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 { Category, Dialog } from '@manuscripts/style-guide'
17
+ import React, { useState } from 'react'
18
+
19
+ export interface DeleteAwardDialogProps {
20
+ handleDelete: () => void
21
+ }
22
+
23
+ export const DeleteAwardDialog: React.FC<DeleteAwardDialogProps> = ({
24
+ handleDelete,
25
+ }) => {
26
+ const [isOpen, setOpen] = useState(true)
27
+
28
+ return (
29
+ <Dialog
30
+ isOpen={isOpen}
31
+ actions={{
32
+ primary: {
33
+ action: () => {
34
+ setOpen(false)
35
+ handleDelete()
36
+ },
37
+ title: 'Delete',
38
+ },
39
+ secondary: {
40
+ action: () => setOpen(false),
41
+ title: 'Cancel',
42
+ },
43
+ }}
44
+ category={Category.warning}
45
+ header={'Delete Funder Info'}
46
+ message={''}
47
+ >
48
+ <p>This action will delete the funder information.</p>
49
+ <p>Do you want to continue?</p>
50
+ </Dialog>
51
+ )
52
+ }
@@ -0,0 +1,131 @@
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 { AttentionOrangeIcon, Category, Dialog } from '@manuscripts/style-guide'
17
+ import React from 'react'
18
+ import styled from 'styled-components'
19
+
20
+ const StyledIcon = styled(AttentionOrangeIcon)`
21
+ margin-right: 8px;
22
+ `
23
+
24
+ const MessageBox = styled.div`
25
+ display: flex;
26
+ flex-direction: column;
27
+ justify-content: space-between;
28
+ min-height: 90px;
29
+ `
30
+
31
+ export enum DialogType {
32
+ SAVE = 'save',
33
+ DELETE = 'delete',
34
+ REQUIRED = 'required',
35
+ }
36
+
37
+ const getDialogConfig = (dialogType: DialogType, entityType: string) => {
38
+ const configs = {
39
+ [DialogType.SAVE]: {
40
+ title: 'Unsaved changes',
41
+ message: {
42
+ primary: "You've made changes but not saved them!",
43
+ secondary: 'Would you like to save or discard your changes?',
44
+ },
45
+ buttons: {
46
+ primary: 'Continue editing',
47
+ secondary: 'Discard changes',
48
+ },
49
+ },
50
+ [DialogType.DELETE]: {
51
+ title: `Delete ${entityType}`,
52
+ message: {
53
+ primary:
54
+ entityType === 'affiliation'
55
+ ? 'This action will delete the institution and any links to authors affiliated to it.'
56
+ : `Are you sure you want to remove this ${entityType} from the list?`,
57
+ secondary: 'Do you want to continue?',
58
+ },
59
+ buttons: {
60
+ primary: 'Delete',
61
+ secondary: 'Cancel',
62
+ },
63
+ },
64
+ [DialogType.REQUIRED]: {
65
+ title: 'Empty required field',
66
+ message: {
67
+ primary:
68
+ 'A required field has been left empty. If you discard, any updates will not be saved!',
69
+ secondary: 'Would you like to discard or continue editing?',
70
+ },
71
+ buttons: {
72
+ primary: 'Continue editing',
73
+ secondary: 'Discard',
74
+ },
75
+ minHeight: '90px',
76
+ },
77
+ }
78
+
79
+ return configs[dialogType]
80
+ }
81
+
82
+ interface ConfirmationDialogProps {
83
+ isOpen: boolean
84
+ type: DialogType
85
+ entityType: string
86
+ onPrimary: () => void
87
+ onSecondary: () => void
88
+ }
89
+
90
+ export const ConfirmationDialog: React.FC<ConfirmationDialogProps> = ({
91
+ isOpen,
92
+ type,
93
+ entityType,
94
+ onPrimary,
95
+ onSecondary,
96
+ }) => {
97
+ const config = getDialogConfig(type, entityType)
98
+
99
+ const Header = () => (
100
+ <>
101
+ <StyledIcon /> {config.title}
102
+ </>
103
+ )
104
+
105
+ const Message = () => (
106
+ <MessageBox>
107
+ <div>{config.message.primary}</div>
108
+ {config.message.secondary && <div>{config.message.secondary}</div>}
109
+ </MessageBox>
110
+ )
111
+
112
+ return (
113
+ <Dialog
114
+ isOpen={isOpen}
115
+ category={Category.confirmation}
116
+ header={<Header />}
117
+ message={<Message />}
118
+ actions={{
119
+ primary: {
120
+ action: onPrimary,
121
+ title: config.buttons.primary,
122
+ },
123
+ secondary: {
124
+ action: onSecondary,
125
+ title: config.buttons.secondary,
126
+ variant: type === DialogType.DELETE ? 'default' : 'textDanger',
127
+ },
128
+ }}
129
+ />
130
+ )
131
+ }
@@ -0,0 +1,37 @@
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 { ModalBody, ScrollableModalContent } from '@manuscripts/style-guide'
17
+ import styled from 'styled-components'
18
+
19
+ export const MODAL_ON_CLOSE_NOTIFY_DELAY_MS = 220
20
+
21
+ export const StyledModalBody = styled(ModalBody)`
22
+ position: relative;
23
+ height: calc(90vh - 250px);
24
+ `
25
+
26
+ export const FormTitle = styled.h2`
27
+ margin: 0 0 ${(props) => props.theme.grid.unit * 3}px;
28
+ font-family: ${(props) => props.theme.font.family.sans};
29
+ font-size: ${(props) => props.theme.font.size.large};
30
+ font-weight: ${(props) => props.theme.font.weight.semibold};
31
+ line-height: ${(props) => props.theme.font.lineHeight.large};
32
+ color: ${(props) => props.theme.colors.text.primary};
33
+ `
34
+
35
+ export const StyledScrollableModalContent = styled(ScrollableModalContent)`
36
+ padding: 45px 16px 16px;
37
+ `