@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,105 @@
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
+ interface MediaTypeInfo {
17
+ extension: string
18
+ isVideo: boolean
19
+ isAudio: boolean
20
+ isImage: boolean
21
+ isSupported: boolean
22
+ mimetype?: string
23
+ mimeSubtype?: string
24
+ }
25
+
26
+ export const getMediaTypeInfo = (
27
+ filenameOrFile: string | File
28
+ ): MediaTypeInfo => {
29
+ const filename =
30
+ typeof filenameOrFile === 'string'
31
+ ? filenameOrFile
32
+ : filenameOrFile?.name || ''
33
+ const extension = filename.toLowerCase().split('.').pop()?.trim() || ''
34
+
35
+ const videoExtensions = new Set([
36
+ 'mp4',
37
+ 'webm',
38
+ 'avi',
39
+ 'mov',
40
+ 'mkv',
41
+ 'flv',
42
+ 'wmv',
43
+ 'mpg',
44
+ 'mpeg',
45
+ ])
46
+ const audioExtensions = new Set([
47
+ 'mp3',
48
+ 'wav',
49
+ 'aac',
50
+ 'ogg',
51
+ 'flac',
52
+ 'm4a',
53
+ 'wma',
54
+ ])
55
+ const imageExtensions = new Set([
56
+ 'jpg',
57
+ 'jpeg',
58
+ 'png',
59
+ 'gif',
60
+ 'bmp',
61
+ 'svg',
62
+ 'webp',
63
+ 'tiff',
64
+ 'tif',
65
+ ])
66
+
67
+ let mimetype: string | undefined
68
+ let mimeSubtype: string | undefined
69
+
70
+ if (typeof filenameOrFile !== 'string' && filenameOrFile?.type) {
71
+ const [type, subtype] = filenameOrFile.type.split('/')
72
+ if (type && subtype && ['video', 'audio', 'image'].includes(type)) {
73
+ mimetype = type
74
+ mimeSubtype = subtype
75
+ }
76
+ }
77
+
78
+ if (!mimetype || !mimeSubtype) {
79
+ if (videoExtensions.has(extension)) {
80
+ mimetype = 'video'
81
+ mimeSubtype = extension === 'mov' ? 'quicktime' : extension
82
+ } else if (audioExtensions.has(extension)) {
83
+ mimetype = 'audio'
84
+ mimeSubtype = extension === 'm4a' ? 'mp4' : extension
85
+ } else if (imageExtensions.has(extension)) {
86
+ mimetype = 'image'
87
+ mimeSubtype = extension === 'jpg' ? 'jpeg' : extension
88
+ }
89
+ }
90
+
91
+ const isVideo = mimetype === 'video' || videoExtensions.has(extension)
92
+ const isAudio = mimetype === 'audio' || audioExtensions.has(extension)
93
+ const isImage = mimetype === 'image' || imageExtensions.has(extension)
94
+ const isSupported = isVideo || isAudio || isImage
95
+
96
+ return {
97
+ extension,
98
+ isVideo,
99
+ isAudio,
100
+ isImage,
101
+ isSupported,
102
+ mimetype,
103
+ mimeSubtype,
104
+ }
105
+ }
@@ -0,0 +1,199 @@
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
+ isExecutableNodeType,
19
+ ManuscriptEditorState,
20
+ ManuscriptNode,
21
+ schema,
22
+ } from '@manuscripts/transform'
23
+ import { Node, ResolvedPos } from 'prosemirror-model'
24
+ import { NodeSelection, TextSelection } from 'prosemirror-state'
25
+ import { EditorView } from 'prosemirror-view'
26
+
27
+ export const isNodeOfType =
28
+ (...type: string[]) =>
29
+ (node: Node): boolean => {
30
+ const [head, ...tail] = type
31
+ if (node.type === node.type.schema.nodes[head]) {
32
+ return true
33
+ }
34
+ if (tail && tail.length) {
35
+ return isNodeOfType(...tail)(node)
36
+ }
37
+ return false
38
+ }
39
+
40
+ export const nearestAncestor =
41
+ (func: (node: ManuscriptNode) => boolean) =>
42
+ ($pos: ResolvedPos): number | null => {
43
+ for (let d = $pos.depth; d >= 0; d--) {
44
+ if (func($pos.node(d))) {
45
+ return d
46
+ }
47
+ }
48
+ return null
49
+ }
50
+
51
+ // This function finds and merges similar items in an array.
52
+ // It uses a compare function to determine which items in the array
53
+ // are similar (or identical), and if a match is found, uses the mergeFunc
54
+ // to merge it with the match.
55
+ export const mergeSimilarItems =
56
+ <T>(compareFunc: (a: T, b: T) => boolean, mergeFunc: (a: T, b: T) => T) =>
57
+ (items: T[]): T[] => {
58
+ return items.reduce((acc: T[], item: T) => {
59
+ const existingIndex = acc.findIndex((existing) =>
60
+ compareFunc(existing, item)
61
+ )
62
+ if (existingIndex === -1) {
63
+ return [...acc, item]
64
+ }
65
+ return [
66
+ ...acc.slice(0, existingIndex),
67
+ mergeFunc(acc[existingIndex], item),
68
+ ...acc.slice(existingIndex + 1),
69
+ ]
70
+ }, [])
71
+ }
72
+
73
+ export const selectionForOutlineNavigation = (
74
+ doc: Node,
75
+ pos: number
76
+ ): NodeSelection | TextSelection => {
77
+ const node = doc.nodeAt(pos)
78
+ if (!node || isExecutableNodeType(node.type)) {
79
+ return NodeSelection.create(doc, pos)
80
+ }
81
+
82
+ if (node.isTextblock) {
83
+ return TextSelection.create(doc, pos + 1)
84
+ }
85
+
86
+ if (node.type === schema.nodes.section) {
87
+ let textPos: number | null = null
88
+ node.forEach((child, offset) => {
89
+ if (textPos !== null) {
90
+ return
91
+ }
92
+ if (
93
+ child.type === schema.nodes.section_title ||
94
+ child.type === schema.nodes.section_title_plain
95
+ ) {
96
+ textPos = pos + 1 + offset + 1
97
+ }
98
+ })
99
+ if (textPos !== null) {
100
+ return TextSelection.create(doc, textPos)
101
+ }
102
+ }
103
+
104
+ return NodeSelection.create(doc, pos)
105
+ }
106
+
107
+ export const handleScrollToSelectedTarget = (view: EditorView): boolean => {
108
+ const selection = view.state.selection
109
+ if (selection.empty) {
110
+ return false
111
+ }
112
+
113
+ const node = view.state.doc.nodeAt(selection.from)
114
+ if (!node) {
115
+ return false
116
+ }
117
+
118
+ let target: Element | null
119
+
120
+ //this is to support scrolling to nodes whose views are not managed by PM
121
+ if (node.attrs.id) {
122
+ target = view.dom.querySelector(`[id="${node.attrs.id}"]`)
123
+ } else {
124
+ let node = view.domAtPos(selection.from).node
125
+
126
+ const ELEMENT_NODE = 1
127
+ while (node.nodeType !== ELEMENT_NODE && node.parentElement) {
128
+ node = node.parentElement
129
+ }
130
+ target = node as Element
131
+ }
132
+
133
+ if (!target || !(target instanceof HTMLElement)) {
134
+ return false
135
+ }
136
+
137
+ // Set block alignment based on the node type
138
+ const blockAlignment =
139
+ node.type === schema.nodes.bibliography_item ? 'center' : 'start'
140
+
141
+ // Scroll the target element into view
142
+ target.scrollIntoView({
143
+ behavior: 'smooth',
144
+ block: blockAlignment,
145
+ })
146
+
147
+ return true
148
+ }
149
+
150
+ // Find the boundaries of the intended word based on the current cursor position
151
+ export const findWordBoundaries = (
152
+ state: ManuscriptEditorState,
153
+ position: number
154
+ ) => {
155
+ let start = position
156
+ let end = position
157
+ const resolvedPos = state.doc.resolve(position)
158
+ const blockStart = resolvedPos.start()
159
+ const blockEnd = resolvedPos.end()
160
+
161
+ // Move backward to find the start of the word
162
+ while (
163
+ start > blockStart &&
164
+ !/\s/.test(state.doc.textBetween(start - 1, start))
165
+ ) {
166
+ start--
167
+ }
168
+ // Move forward to find the end of the word
169
+ while (end < blockEnd && !/\s/.test(state.doc.textBetween(end, end + 1))) {
170
+ end++
171
+ }
172
+
173
+ let from = start
174
+ let to = end
175
+
176
+ // If no word is found (cursor between spaces), search for the previous word
177
+ if (from === to) {
178
+ // Move backward through spaces
179
+ while (
180
+ start > blockStart &&
181
+ /\s/.test(state.doc.textBetween(start - 1, start))
182
+ ) {
183
+ start--
184
+ }
185
+ to = start
186
+
187
+ // Move backward to find the start of the previous word
188
+ while (
189
+ start > blockStart &&
190
+ !/\s/.test(state.doc.textBetween(start - 1, start))
191
+ ) {
192
+ start--
193
+ }
194
+
195
+ from = start
196
+ }
197
+
198
+ return { from, to }
199
+ }
@@ -0,0 +1,117 @@
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
+ GROUP_LIST,
19
+ hasGroup,
20
+ isElementNodeType,
21
+ isSectionNodeType,
22
+ ManuscriptEditorState,
23
+ ManuscriptNode,
24
+ ManuscriptNodeType,
25
+ nodeNames,
26
+ } from '@manuscripts/transform'
27
+ import { ResolvedPos } from 'prosemirror-model'
28
+
29
+ import { Dispatch } from '../commands'
30
+
31
+ interface NodeWithPosition {
32
+ node: ManuscriptNode
33
+ before: number
34
+ after: number
35
+ }
36
+
37
+ const isListNodeType = (nodeType: ManuscriptNodeType) =>
38
+ hasGroup(nodeType, GROUP_LIST)
39
+
40
+ export const findListParent = (
41
+ $pos: ResolvedPos
42
+ ): NodeWithPosition | undefined => {
43
+ for (let depth = $pos.depth; depth > 0; depth--) {
44
+ const node = $pos.node(depth)
45
+
46
+ if (isListNodeType(node.type)) {
47
+ return {
48
+ node,
49
+ before: $pos.before(depth),
50
+ after: $pos.after(depth),
51
+ }
52
+ }
53
+ }
54
+ }
55
+
56
+ export const findClosestParentElement = (
57
+ $pos: ResolvedPos
58
+ ): NodeWithPosition | undefined => {
59
+ const listParent = findListParent($pos)
60
+
61
+ if (listParent) {
62
+ return listParent
63
+ }
64
+
65
+ for (let depth = $pos.depth; depth > 0; depth--) {
66
+ const node = $pos.node(depth)
67
+
68
+ if (isSectionNodeType(node.type) || isElementNodeType(node.type)) {
69
+ return {
70
+ node,
71
+ before: $pos.before(depth),
72
+ after: $pos.after(depth),
73
+ }
74
+ }
75
+ }
76
+ }
77
+
78
+ export const findClosestParentElementNodeName = (
79
+ state: ManuscriptEditorState
80
+ ): string => {
81
+ if (state.selection) {
82
+ const fromParentElement = findClosestParentElement(state.selection.$from)
83
+ const toParentElement = findClosestParentElement(state.selection.$to)
84
+
85
+ if (fromParentElement && toParentElement) {
86
+ if (fromParentElement.node === toParentElement.node) {
87
+ const nodeName = nodeNames.get(fromParentElement.node.type)
88
+
89
+ if (nodeName) {
90
+ return nodeName
91
+ }
92
+ }
93
+ }
94
+ }
95
+
96
+ return ''
97
+ }
98
+
99
+ export const deleteClosestParentElement = (
100
+ state: ManuscriptEditorState,
101
+ dispatch?: Dispatch
102
+ ) => {
103
+ if (state.selection) {
104
+ const fromParentElement = findClosestParentElement(state.selection.$from)
105
+ const toParentElement = findClosestParentElement(state.selection.$to)
106
+
107
+ if (dispatch) {
108
+ if (fromParentElement && toParentElement) {
109
+ dispatch(
110
+ state.tr.delete(fromParentElement.before, toParentElement.after)
111
+ )
112
+ }
113
+ }
114
+ return true
115
+ }
116
+ return false
117
+ }
@@ -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
+
17
+ export interface Language {
18
+ code: string
19
+ name: string
20
+ nativeName: string
21
+ }
22
+
23
+ const ENGLISH = {
24
+ code: 'en',
25
+ name: 'English',
26
+ nativeName: 'English',
27
+ }
28
+
29
+ export const getLanguage = (code: string, languages: Language[]) => {
30
+ return languages.find((l) => l.code === code) || ENGLISH
31
+ }
32
+
33
+ export const getLanguageLabel = (language: Language) => {
34
+ return language.nativeName && language.nativeName !== language.name
35
+ ? `${language.name} (${language.nativeName})`
36
+ : language.name
37
+ }
@@ -0,0 +1,56 @@
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 { ListStyleType } from '@manuscripts/transform'
17
+
18
+ export const parseCssListStyleType = (style: string): ListStyleType => {
19
+ switch (style) {
20
+ case 'disc':
21
+ return 'bullet'
22
+ case 'decimal':
23
+ return 'order'
24
+ case 'lower-alpha':
25
+ return 'alpha-lower'
26
+ case 'upper-alpha':
27
+ return 'alpha-upper'
28
+ case 'lower-roman':
29
+ return 'roman-lower'
30
+ case 'upper-roman':
31
+ return 'roman-upper'
32
+ case 'none':
33
+ return 'simple'
34
+ default:
35
+ return 'simple'
36
+ }
37
+ }
38
+
39
+ export const writeCssListStyleType = (type: ListStyleType) => {
40
+ switch (type) {
41
+ case 'bullet':
42
+ return 'disc'
43
+ case 'order':
44
+ return 'decimal'
45
+ case 'alpha-lower':
46
+ return 'lower-alpha'
47
+ case 'alpha-upper':
48
+ return 'upper-alpha'
49
+ case 'roman-lower':
50
+ return 'lower-roman'
51
+ case 'roman-upper':
52
+ return 'upper-roman'
53
+ case 'simple':
54
+ return 'none'
55
+ }
56
+ }
@@ -0,0 +1,111 @@
1
+ /*!
2
+ * © 2024 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
+ /**
18
+ * The versions file is generated at build time using
19
+ * the `versions.mjs` script.
20
+ */
21
+ //@ts-ignore
22
+ //eslint-disable-next-line import/no-unresolved
23
+ import { MATHJAX_VERSION } from '../versions'
24
+
25
+ const src = `https://cdn.jsdelivr.net/npm/mathjax@${MATHJAX_VERSION}/es5/tex-svg.js`
26
+
27
+ /**
28
+ * MathJax uses delimiters to find math in the doc by default, which is
29
+ * not what we want. This will override that behavior and will instead
30
+ * look for equation nodes, and is based on the
31
+ * [MathJax upgrade guide](https://docs.mathjax.org/en/v3.2-latest/upgrading/v2.html).
32
+ */
33
+ //@ts-ignore
34
+ const findMath = (doc) => {
35
+ let nodes = doc.options.elements
36
+ if (!nodes) {
37
+ nodes = doc.document.querySelectorAll('.equation')
38
+ }
39
+ for (const node of nodes) {
40
+ const math = new doc.options.MathItem(
41
+ node.textContent,
42
+ doc.inputJax[0],
43
+ node.tagName !== 'SPAN'
44
+ )
45
+ const text = document.createTextNode('')
46
+ node.innerHTML = ''
47
+ node.appendChild(text)
48
+ math.start = { node: text, delim: '', n: 0 }
49
+ math.end = { node: text, delim: '', n: 0 }
50
+ doc.math.push(math)
51
+ }
52
+ }
53
+
54
+ const config = {
55
+ options: {
56
+ renderActions: {
57
+ find: [10, findMath, ''],
58
+ },
59
+ },
60
+ }
61
+
62
+ export const initMathJax = () => {
63
+ // @ts-ignore
64
+ window.MathJax = config
65
+ const script = document.createElement('script')
66
+ script.src = src
67
+ script.async = true
68
+ document.head.appendChild(script)
69
+ }
70
+
71
+ export const renderMath = (node: HTMLElement) => {
72
+ /* eslint-disable */
73
+ //@ts-ignore
74
+ if (!window.MathJax) {
75
+ initMathJax()
76
+ }
77
+ //@ts-ignore
78
+ if (window.MathJax.typeset) {
79
+ //@ts-ignore
80
+ if (!node.parentNode) {
81
+ awaitMounting(node).then(() => {
82
+ //@ts-ignore
83
+ window.MathJax.typeset([node])
84
+ })
85
+ } else {
86
+ //@ts-ignore
87
+ window.MathJax.typeset([node])
88
+ }
89
+ }
90
+ /* eslint-enable */
91
+ }
92
+
93
+ function awaitMounting(node: HTMLElement) {
94
+ return new Promise<void>(function (resolve, reject) {
95
+ let max = 10
96
+ function wait() {
97
+ max--
98
+ if (!node.parentNode) {
99
+ setTimeout(() => {
100
+ wait()
101
+ }, 0)
102
+ } else {
103
+ resolve()
104
+ }
105
+ if (max <= 0) {
106
+ reject()
107
+ }
108
+ }
109
+ wait()
110
+ })
111
+ }