@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,83 @@
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
+ FileDocumentIcon,
19
+ SupplementsIcon,
20
+ FileImageIcon,
21
+ OutlineBlockQuoteIcon,
22
+ OutlineEmbedIcon,
23
+ OutlineEquationIcon,
24
+ OutlineFigureIcon,
25
+ OutlineManuscriptIcon,
26
+ OutlineOrderedListIcon,
27
+ OutlineParagraphIcon,
28
+ OutlinePullQuoteIcon,
29
+ OutlineSectionIcon,
30
+ OutlineTableIcon,
31
+ OutlineUnorderedListIcon,
32
+ } from '@manuscripts/style-guide'
33
+ import { ManuscriptNodeType, schema } from '@manuscripts/transform'
34
+ import { NodeType } from 'prosemirror-model'
35
+ import React from 'react'
36
+
37
+ const { nodes } = schema
38
+
39
+ const OutlineImageIcon: React.FC = () => (
40
+ <FileImageIcon width="11" height="14" />
41
+ )
42
+ const OutlineSupplementsIcon: React.FC = () => (
43
+ <SupplementsIcon width="11" height="14" />
44
+ )
45
+
46
+ const OutlineMainDocumentIcon: React.FC = () => (
47
+ <FileDocumentIcon width="11" height="14" />
48
+ )
49
+ const icons: Map<
50
+ ManuscriptNodeType,
51
+ React.FunctionComponent<React.SVGAttributes<SVGElement>>
52
+ > = new Map([
53
+ [nodes.manuscript, OutlineManuscriptIcon],
54
+ [nodes.bibliography_section, OutlineSectionIcon],
55
+ [nodes.blockquote_element, OutlineBlockQuoteIcon],
56
+ [nodes.equation_element, OutlineEquationIcon],
57
+ [nodes.embed, OutlineEmbedIcon],
58
+ [nodes.figure_element, OutlineFigureIcon],
59
+ [nodes.paragraph, OutlineParagraphIcon],
60
+ [nodes.pullquote_element, OutlinePullQuoteIcon],
61
+ [nodes.section, OutlineSectionIcon],
62
+ [nodes.table_element, OutlineTableIcon],
63
+ [nodes.graphical_abstract_section, OutlineSectionIcon],
64
+ [nodes.trans_graphical_abstract, OutlineSectionIcon],
65
+ [nodes.footnotes_section, OutlineSectionIcon],
66
+ [nodes.image_element, OutlineImageIcon],
67
+ [nodes.hero_image, OutlineImageIcon],
68
+ [nodes.supplements, OutlineSupplementsIcon],
69
+ [nodes.attachments, OutlineMainDocumentIcon],
70
+ ])
71
+
72
+ export const nodeTypeIcon = (nodeType: NodeType, listType?: string) => {
73
+ if (nodeType === schema.nodes.list) {
74
+ if (listType === 'bullet') {
75
+ return <OutlineUnorderedListIcon />
76
+ } else {
77
+ return <OutlineOrderedListIcon />
78
+ }
79
+ }
80
+ const Icon = icons.get(nodeType as ManuscriptNodeType)
81
+
82
+ return Icon ? <Icon /> : null
83
+ }
@@ -0,0 +1,140 @@
1
+ {
2
+ "doc": {
3
+ "type": "manuscript",
4
+ "attrs": {
5
+ "id": "MPManuscript:D1797375-EF63-49AF-B140-04B2FA6B8365"
6
+ },
7
+ "content": [
8
+ {
9
+ "type": "abstracts",
10
+ "attrs": {
11
+ "id": ""
12
+ },
13
+ "content": []
14
+ },
15
+ {
16
+ "type": "body",
17
+ "attrs": {
18
+ "id": "MPSection:5346C94F-8C83-4585-811E-2209C269ED71"
19
+ },
20
+ "content": [
21
+ {
22
+ "type": "section",
23
+ "attrs": {
24
+ "id": "MPSection:5346C94F-8C83-4585-811E-2209C269ED71",
25
+ "category": "",
26
+ "titleSuppressed": false,
27
+ "dataTracked": null,
28
+ "comments": null
29
+ },
30
+ "content": [
31
+ {
32
+ "type": "section_title",
33
+ "attrs": {
34
+ "dataTracked": null
35
+ }
36
+ },
37
+ {
38
+ "type": "paragraph",
39
+ "attrs": {
40
+ "id": "MPParagraphElement:08E4B001-BB01-4666-9E33-9355AEC3CFC3",
41
+ "paragraphStyle": "MPParagraphStyle:51671E8C-C9EE-461D-B6FF-756817829B3F",
42
+ "placeholder": "",
43
+ "dataTracked": null,
44
+ "comments": null
45
+ },
46
+ "content": [
47
+ {
48
+ "type": "text",
49
+ "text": "test"
50
+ }
51
+ ]
52
+ }
53
+ ]
54
+ }
55
+ ]
56
+ },
57
+ {
58
+ "type": "backmatter",
59
+ "attrs": {
60
+ "id": "MPSection:05EA736A-BBE3-4904-B2F5-59E861208BA9"
61
+ },
62
+ "content": [
63
+ {
64
+ "type": "footnotes_section",
65
+ "attrs": {
66
+ "id": "footnotes_section_id",
67
+ "dataTracked": null
68
+ },
69
+ "content": [
70
+ {
71
+ "type": "section_title",
72
+ "attrs": {
73
+ "dataTracked": null
74
+ },
75
+ "content": [
76
+ {
77
+ "type": "text",
78
+ "text": "Footnotes"
79
+ }
80
+ ]
81
+ },
82
+ {
83
+ "type": "footnotes_element",
84
+ "attrs": {
85
+ "id": "footnotes_element_id",
86
+ "kind": "footnote",
87
+ "paragraphStyle": "",
88
+ "dataTracked": null
89
+ },
90
+ "content": [
91
+ {
92
+ "type": "footnote",
93
+ "attrs": {
94
+ "id": "footnote_id",
95
+ "kind": "footnote",
96
+ "paragraphStyle": "",
97
+ "placeholder": "",
98
+ "dataTracked": null,
99
+ "comments": null
100
+ },
101
+ "content": [
102
+ {
103
+ "type": "paragraph",
104
+ "attrs": {
105
+ "id": "paragraph_id",
106
+ "paragraphStyle": "",
107
+ "placeholder": "",
108
+ "dataTracked": null,
109
+ "comments": null
110
+ },
111
+ "content": [
112
+ {
113
+ "type": "text",
114
+ "text": "a footnote"
115
+ }
116
+ ]
117
+ }
118
+ ]
119
+ }
120
+ ]
121
+ }
122
+ ]
123
+ }
124
+ ]
125
+ },
126
+ {
127
+ "type": "comments",
128
+ "attrs": {
129
+ "id": ""
130
+ },
131
+ "content": []
132
+ }
133
+ ]
134
+ },
135
+ "selection": {
136
+ "type": "text",
137
+ "anchor": 10,
138
+ "head": 10
139
+ }
140
+ }
@@ -0,0 +1,153 @@
1
+ {
2
+ "doc": {
3
+ "type": "manuscript",
4
+ "attrs": {
5
+ "id": "MPManuscript:D1797375-EF63-49AF-B140-04B2FA6B8365"
6
+ },
7
+ "content": [
8
+ {
9
+ "type": "abstracts",
10
+ "attrs": {
11
+ "id": ""
12
+ },
13
+ "content": []
14
+ },
15
+ {
16
+ "type": "body",
17
+ "attrs": {
18
+ "id": "MPSection:5346C94F-8C83-4585-811E-2209C269ED71"
19
+ },
20
+ "content": [
21
+ {
22
+ "type": "section",
23
+ "attrs": {
24
+ "id": "MPSection:5346C94F-8C83-4585-811E-2209C269ED71",
25
+ "category": "",
26
+ "titleSuppressed": false,
27
+ "dataTracked": null,
28
+ "comments": null
29
+ },
30
+ "content": [
31
+ {
32
+ "type": "section_title",
33
+ "attrs": {
34
+ "dataTracked": null
35
+ }
36
+ },
37
+ {
38
+ "type": "paragraph",
39
+ "attrs": {
40
+ "id": "MPParagraphElement:08E4B001-BB01-4666-9E33-9355AEC3CFC3",
41
+ "paragraphStyle": "MPParagraphStyle:51671E8C-C9EE-461D-B6FF-756817829B3F",
42
+ "placeholder": "",
43
+ "dataTracked": null,
44
+ "comments": null
45
+ },
46
+ "content": [
47
+ {
48
+ "type": "text",
49
+ "text": "tes"
50
+ },
51
+ {
52
+ "type": "inline_footnote",
53
+ "attrs": {
54
+ "id": "inline_footnote_id",
55
+ "rids": ["footnote_id"],
56
+ "contents": "a",
57
+ "dataTracked": null
58
+ }
59
+ },
60
+ {
61
+ "type": "text",
62
+ "text": "t"
63
+ }
64
+ ]
65
+ }
66
+ ]
67
+ }
68
+ ]
69
+ },
70
+ {
71
+ "type": "backmatter",
72
+ "attrs": {
73
+ "id": "MPSection:05EA736A-BBE3-4904-B2F5-59E861208BA9"
74
+ },
75
+ "content": [
76
+ {
77
+ "type": "footnotes_section",
78
+ "attrs": {
79
+ "id": "footnotes_section_id",
80
+ "dataTracked": null
81
+ },
82
+ "content": [
83
+ {
84
+ "type": "section_title",
85
+ "attrs": {
86
+ "dataTracked": null
87
+ },
88
+ "content": [
89
+ {
90
+ "type": "text",
91
+ "text": "Footnotes"
92
+ }
93
+ ]
94
+ },
95
+ {
96
+ "type": "footnotes_element",
97
+ "attrs": {
98
+ "id": "footnotes_element_id",
99
+ "kind": "footnote",
100
+ "paragraphStyle": "",
101
+ "dataTracked": null
102
+ },
103
+ "content": [
104
+ {
105
+ "type": "footnote",
106
+ "attrs": {
107
+ "id": "footnote_id",
108
+ "kind": "footnote",
109
+ "paragraphStyle": "",
110
+ "placeholder": "",
111
+ "dataTracked": null,
112
+ "comments": null
113
+ },
114
+ "content": [
115
+ {
116
+ "type": "paragraph",
117
+ "attrs": {
118
+ "id": "paragraph_id",
119
+ "paragraphStyle": "",
120
+ "placeholder": "",
121
+ "dataTracked": null,
122
+ "comments": null
123
+ },
124
+ "content": [
125
+ {
126
+ "type": "text",
127
+ "text": "a footnote"
128
+ }
129
+ ]
130
+ }
131
+ ]
132
+ }
133
+ ]
134
+ }
135
+ ]
136
+ }
137
+ ]
138
+ },
139
+ {
140
+ "type": "comments",
141
+ "attrs": {
142
+ "id": ""
143
+ },
144
+ "content": []
145
+ }
146
+ ]
147
+ },
148
+ "selection": {
149
+ "type": "text",
150
+ "anchor": 41,
151
+ "head": 41
152
+ }
153
+ }
@@ -0,0 +1,67 @@
1
+ /*!
2
+ * © 2019 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { ManuscriptNodeType } from '@manuscripts/transform'
18
+ import { vi } from 'vitest'
19
+
20
+ import { insertInlineFootnote } from '../../commands'
21
+ import { parseDoc, setupEditor } from '../../testing/setup-editor'
22
+ import deletedFootnoteJson from './__fixtures__/deleted-footnote.json'
23
+ import insertedFootnoteJson from './__fixtures__/inserted-footnote.json'
24
+
25
+ vi.mock('@manuscripts/transform', async (importOriginal) => {
26
+ const mockTransformOriginal =
27
+ await importOriginal<typeof import('@manuscripts/transform')>()
28
+ return {
29
+ ...mockTransformOriginal,
30
+ // Ids are generated by the persist plugin in an appendTransaction
31
+ generateNodeID: (type: ManuscriptNodeType) => `${type.name}_id`,
32
+ }
33
+ })
34
+
35
+ describe('footnotes plugin', () => {
36
+ test("should create an inline node and footnotes section if it doesn't exist", () => {
37
+ const expectedDoc = parseDoc(insertedFootnoteJson.doc)
38
+
39
+ const { view } = setupEditor()
40
+ .selectText(10)
41
+ .command(insertInlineFootnote)
42
+ .insertText('a footnote')
43
+ .callback((content) => {
44
+ expect(content.state.tr.doc.toJSON()).toEqual(expectedDoc.toJSON())
45
+ expect(content.state.tr.selection.toJSON()).toEqual(
46
+ insertedFootnoteJson.selection
47
+ )
48
+ })
49
+ view.destroy()
50
+ })
51
+ test('should remove the inline node as well as the footnote on deletion', () => {
52
+ const expectedDoc = parseDoc(deletedFootnoteJson.doc)
53
+ const { view } = setupEditor()
54
+ .selectText(10)
55
+ .command(insertInlineFootnote)
56
+ .insertText('a footnote')
57
+ .selectText(11)
58
+ .backspace()
59
+ .callback((content) => {
60
+ expect(content.state.tr.doc.toJSON()).toEqual(expectedDoc.toJSON())
61
+ expect(content.state.tr.selection.toJSON()).toEqual(
62
+ deletedFootnoteJson.selection
63
+ )
64
+ })
65
+ view.destroy()
66
+ })
67
+ })
@@ -0,0 +1,219 @@
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
+ ManuscriptNode,
18
+ ManuscriptTransaction,
19
+ schema,
20
+ } from '@manuscripts/transform'
21
+ import { Plugin, PluginKey, Selection } from 'prosemirror-state'
22
+ import { Decoration, DecorationSet, EditorView } from 'prosemirror-view'
23
+
24
+ import { createToggleButton } from '../lib/utils'
25
+
26
+ export interface PluginState {
27
+ expandButtonDecorations: Decoration[]
28
+ expandedElementDecorations: Decoration[]
29
+ expandedElementIDs: Set<string>
30
+ }
31
+
32
+ export const accessibilityElementKey = new PluginKey<PluginState>(
33
+ 'accessibility-element'
34
+ )
35
+
36
+ const nodeTypes = [schema.nodes.alt_text, schema.nodes.long_desc]
37
+
38
+ const handleExpandButtonClick = (
39
+ view: EditorView,
40
+ node: ManuscriptNode,
41
+ event: MouseEvent | KeyboardEvent
42
+ ) => {
43
+ const tr = view.state.tr
44
+ toggleAccessibilitySection(tr, node)
45
+ view.dispatch(tr)
46
+
47
+ // Only auto-focus first accessibility element on keyboard interaction, not mouse clicks
48
+ const isKeyboardEvent = event.type === 'keydown'
49
+ if (isKeyboardEvent) {
50
+ const parentElement = view.dom.querySelector(`[id="${node.attrs.id}"]`)
51
+ if (parentElement) {
52
+ const firstInput = parentElement.querySelector(
53
+ '.accessibility_element_input'
54
+ ) as HTMLElement
55
+ firstInput?.focus()
56
+ }
57
+ }
58
+ }
59
+ const isSelectionWithin = (
60
+ node: ManuscriptNode,
61
+ pos: number,
62
+ selection?: Selection
63
+ ) => {
64
+ if (!selection || !nodeTypes.includes(node.type)) {
65
+ return false
66
+ }
67
+ const to = pos + node.nodeSize
68
+ return selection.from >= pos && selection.to <= to
69
+ }
70
+
71
+ const buildExpandButtonDecorations = (doc: ManuscriptNode) => {
72
+ const decorations: Decoration[] = []
73
+ doc.descendants((node, pos) => {
74
+ if (node.type.spec.content?.includes('alt_text')) {
75
+ decorations.push(
76
+ Decoration.widget(
77
+ pos + node.nodeSize - 1,
78
+ (view) => {
79
+ const container = document.createElement('div')
80
+ container.className =
81
+ 'accessibility_element_expander_button_container'
82
+ container.appendChild(
83
+ createToggleButton(
84
+ (e) => handleExpandButtonClick(view, node, e),
85
+ 'additional info'
86
+ )
87
+ )
88
+ return container
89
+ },
90
+ {
91
+ key: node.attrs.id,
92
+ }
93
+ )
94
+ )
95
+ }
96
+ })
97
+
98
+ return decorations
99
+ }
100
+
101
+ const buildExpandedElementsDecorations = (
102
+ doc: ManuscriptNode,
103
+ expandedElementIDs: Set<string>,
104
+ selection?: Selection
105
+ ) => {
106
+ const decorations: Decoration[] = []
107
+ doc.descendants((node, pos) => {
108
+ if (
109
+ expandedElementIDs.has(node.attrs.id) ||
110
+ isSelectionWithin(node, pos, selection)
111
+ ) {
112
+ decorations.push(
113
+ Decoration.node(pos, pos + node.nodeSize, {
114
+ class: 'show_accessibility_element',
115
+ })
116
+ )
117
+ }
118
+ })
119
+
120
+ return decorations
121
+ }
122
+
123
+ export default () => {
124
+ return new Plugin<PluginState>({
125
+ key: accessibilityElementKey,
126
+ state: {
127
+ init(config, instance) {
128
+ return {
129
+ expandButtonDecorations: buildExpandButtonDecorations(instance.doc),
130
+ expandedElementDecorations: [],
131
+ expandedElementIDs: new Set(),
132
+ }
133
+ },
134
+ apply(tr, value, oldState, newState) {
135
+ const s = {
136
+ expandButtonDecorations: value.expandButtonDecorations,
137
+ expandedElementDecorations: value.expandedElementDecorations,
138
+ expandedElementIDs: new Set(value.expandedElementIDs),
139
+ }
140
+
141
+ if (tr.docChanged) {
142
+ s.expandButtonDecorations = buildExpandButtonDecorations(newState.doc)
143
+ }
144
+
145
+ let expandedElementIDsChanged = false
146
+ const meta = tr.getMeta(accessibilityElementKey)
147
+ if (meta) {
148
+ expandedElementIDsChanged = true
149
+ const isExpanded = s.expandedElementIDs.has(meta.id)
150
+ if (
151
+ meta.action === 'add' ||
152
+ (meta.action === 'toggle' && !isExpanded)
153
+ ) {
154
+ s.expandedElementIDs.add(meta.id)
155
+ } else if (
156
+ meta.action === 'remove' ||
157
+ (meta.action === 'toggle' && isExpanded)
158
+ ) {
159
+ s.expandedElementIDs.delete(meta.id)
160
+ }
161
+ }
162
+
163
+ if (tr.selectionSet) {
164
+ const $pos = tr.selection.$from
165
+ for (let i = $pos.depth; i >= 0; i--) {
166
+ const node = $pos.node(i)
167
+ if (nodeTypes.includes(node.type)) {
168
+ const parent = $pos.node(i - 1)
169
+ s.expandedElementIDs.add(parent.attrs.id)
170
+ expandedElementIDsChanged = true
171
+ break
172
+ }
173
+ }
174
+ }
175
+
176
+ if (expandedElementIDsChanged || tr.docChanged) {
177
+ s.expandedElementDecorations = buildExpandedElementsDecorations(
178
+ newState.doc,
179
+ s.expandedElementIDs
180
+ )
181
+ }
182
+ return s
183
+ },
184
+ },
185
+ props: {
186
+ decorations: (state) => {
187
+ const pluginState = accessibilityElementKey.getState(state)
188
+ if (pluginState) {
189
+ return DecorationSet.create(state.doc, [
190
+ ...pluginState.expandButtonDecorations,
191
+ ...pluginState.expandedElementDecorations,
192
+ ])
193
+ }
194
+ },
195
+ },
196
+ })
197
+ }
198
+
199
+ export const expandAccessibilitySection = (
200
+ tr: ManuscriptTransaction,
201
+ node: ManuscriptNode
202
+ ) => {
203
+ if (node.attrs.id && node.type.spec.content?.includes('alt_text')) {
204
+ tr.setMeta(accessibilityElementKey, {
205
+ action: 'add',
206
+ id: node.attrs.id,
207
+ })
208
+ }
209
+ }
210
+
211
+ export const toggleAccessibilitySection = (
212
+ tr: ManuscriptTransaction,
213
+ node: ManuscriptNode
214
+ ) => {
215
+ tr.setMeta(accessibilityElementKey, {
216
+ action: 'toggle',
217
+ id: node.attrs.id,
218
+ })
219
+ }