@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,222 @@
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
+ import {
18
+ ButtonGroup,
19
+ DialogModalBody,
20
+ MessageContainer,
21
+ PrimaryBoldHeading,
22
+ PrimaryButton,
23
+ PrimarySmallText,
24
+ SecondaryButton,
25
+ StyledModal,
26
+ TextArea,
27
+ Label,
28
+ FormRow,
29
+ } from '@manuscripts/style-guide'
30
+ import { ManuscriptEditorState } from '@manuscripts/transform'
31
+ import { EditorView } from 'prosemirror-view'
32
+ import React, { useEffect, useState } from 'react'
33
+ import styled from 'styled-components'
34
+
35
+ import { Dispatch, insertEmbed } from '../../commands'
36
+ import { allowedHref } from '../../lib/url'
37
+ import { useDoWithDebounce } from '../../lib/use-do-with-debounce'
38
+ import { getEditorProps } from '../../plugins/editor-props'
39
+ import ReactSubView from '../../views/ReactSubView'
40
+ import { Open } from '../views/LinkForm'
41
+
42
+ const HeaderContainer = styled(PrimaryBoldHeading)`
43
+ font-size: ${(props) => props.theme.font.size.large};
44
+ `
45
+
46
+ const Container = styled.div`
47
+ display: flex;
48
+ flex-direction: column;
49
+ padding-bottom: 16px;
50
+ `
51
+
52
+ const DialogContainer = styled(DialogModalBody)`
53
+ min-width: 750px;
54
+ `
55
+
56
+ const PreviewContainer = styled.div`
57
+ display: flex;
58
+ justify-content: center;
59
+ border: 1px solid ${(props) => props.theme.colors.border.field.default};
60
+ border-radius: ${(props) => props.theme.grid.radius.small};
61
+ padding: 6px ${(props) => props.theme.grid.unit * 4}px;
62
+ `
63
+
64
+ export type InsertEmbedDialogProps = {
65
+ state: ManuscriptEditorState
66
+ dispatch: Dispatch
67
+ pos?: number
68
+ }
69
+
70
+ export const InsertEmbedDialog: React.FC<InsertEmbedDialogProps> = ({
71
+ state,
72
+ dispatch,
73
+ pos,
74
+ }) => {
75
+ const attrs = pos ? state.doc.nodeAt(pos)?.attrs : undefined
76
+ const [isOpen, setOpen] = useState(true)
77
+ const [url, setUrl] = useState<string>(attrs?.href)
78
+ const [oembedHTML, setOEmbedHTML] = useState<string>()
79
+
80
+ const debounce = useDoWithDebounce()
81
+
82
+ const handleSave = () => {
83
+ if (!pos) {
84
+ insertEmbed(state, dispatch, { href: url })
85
+ } else {
86
+ const tr = state.tr.setNodeAttribute(pos, 'href', url)
87
+ dispatch(tr)
88
+ }
89
+ setOpen(false)
90
+ }
91
+
92
+ useEffect(
93
+ () => {
94
+ debounce(async () => {
95
+ if (url && allowedHref(url)) {
96
+ const html = await getEditorProps(state).fetchOEmbedHtml(url, 368, 217)
97
+ setOEmbedHTML(html)
98
+ }
99
+ })
100
+ },
101
+ [url] // eslint-disable-line react-hooks/exhaustive-deps
102
+ )
103
+
104
+ const operation = pos !== undefined && attrs?.href ? 'Update' : 'Insert'
105
+
106
+ return (
107
+ <StyledModal isOpen={isOpen} onRequestClose={() => setOpen(false)}>
108
+ <DialogContainer data-cy="media-editor">
109
+ <HeaderContainer>{operation} external media</HeaderContainer>
110
+
111
+ <MessageContainer>
112
+ <Container>
113
+ <FormRow direction={'row'}>
114
+ <Label htmlFor={'embed-link'}>Media link</Label>
115
+ {url && allowedHref(url) && (
116
+ <Open
117
+ id={'media-link'}
118
+ href={url}
119
+ target={'_blank'}
120
+ rel={'noopener'}
121
+ />
122
+ )}
123
+
124
+ <TextArea
125
+ id={'embed-link'}
126
+ rows={2}
127
+ cols={2}
128
+ defaultValue={url}
129
+ autoFocus={true}
130
+ required={true}
131
+ placeholder={'https://youtube.com/...'}
132
+ onChange={(e) => setUrl(e.target.value.trim())}
133
+ />
134
+ </FormRow>
135
+ </Container>
136
+ {url && allowedHref(url) && (
137
+ <Container>
138
+ <FormRow>
139
+ <Label>Preview</Label>
140
+ </FormRow>
141
+ {(oembedHTML && (
142
+ <PreviewContainer
143
+ dangerouslySetInnerHTML={{ __html: oembedHTML }}
144
+ />
145
+ )) || <NoPreviewMessage />}
146
+ </Container>
147
+ )}
148
+ </MessageContainer>
149
+
150
+ <ButtonGroup>
151
+ <SecondaryButton onClick={() => setOpen(false)}>
152
+ Cancel
153
+ </SecondaryButton>
154
+ <PrimaryButton
155
+ onClick={handleSave}
156
+ disabled={!(url && allowedHref(url))}
157
+ >
158
+ {operation}
159
+ </PrimaryButton>
160
+ </ButtonGroup>
161
+ </DialogContainer>
162
+ </StyledModal>
163
+ )
164
+ }
165
+
166
+ const Wrapper = styled.div`
167
+ display: flex;
168
+ justify-content: center;
169
+ padding: 50px 0;
170
+ `
171
+
172
+ const NoPreviewMessage: React.FC = () => (
173
+ <PreviewContainer>
174
+ <Wrapper>Preview not available</Wrapper>
175
+ </PreviewContainer>
176
+ )
177
+
178
+ const NoPreviewContainer = styled(PreviewContainer)`
179
+ flex-direction: column;
180
+ background: #fafafa;
181
+ padding: 16px 56px 16px 48px;
182
+ `
183
+
184
+ const Heading = styled(PrimaryBoldHeading)`
185
+ font-size: ${(props) => props.theme.font.size.medium};
186
+ `
187
+
188
+ export const NoPreviewMessageWithLink: React.FC<{ href: string }> = ({
189
+ href,
190
+ }) => (
191
+ <NoPreviewContainer>
192
+ <Heading>Preview currently not available</Heading>
193
+ <PrimarySmallText>
194
+ <a href={href} target={'_blank'} rel="noreferrer">
195
+ Click here
196
+ </a>{' '}
197
+ to see the source media
198
+ </PrimarySmallText>
199
+ </NoPreviewContainer>
200
+ )
201
+
202
+ export const openEmbedDialog = (view?: EditorView, pos?: number) => {
203
+ if (!view) {
204
+ return
205
+ }
206
+ const { state, dispatch } = view
207
+
208
+ const dialog = ReactSubView(
209
+ getEditorProps(state),
210
+ InsertEmbedDialog,
211
+ {
212
+ state,
213
+ dispatch,
214
+ pos,
215
+ },
216
+ state.doc,
217
+ () => 0,
218
+ view
219
+ )
220
+
221
+ document.body.appendChild(dialog)
222
+ }
@@ -0,0 +1,208 @@
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
+ import {
18
+ Category,
19
+ CheckboxField,
20
+ CheckboxLabel,
21
+ Dialog,
22
+ } from '@manuscripts/style-guide'
23
+ import { ManuscriptEditorState } from '@manuscripts/transform'
24
+ import React, { useState } from 'react'
25
+ import Select, { OptionProps } from 'react-select'
26
+ import styled from 'styled-components'
27
+
28
+ import { Dispatch, insertTable } from '../../commands'
29
+ import { getEditorProps } from '../../plugins/editor-props'
30
+ import ReactSubView from '../../views/ReactSubView'
31
+
32
+ const Label = styled.div`
33
+ padding-right: 16px;
34
+ width: 150px;
35
+ `
36
+ const SelectContainer = styled.div`
37
+ width: 182px;
38
+ height: 30px;
39
+ `
40
+
41
+ const Container = styled.div`
42
+ display: flex;
43
+ align-items: center;
44
+ padding-bottom: 16px;
45
+ `
46
+ const OptionWrapper = styled.div<{ focused?: boolean; selected?: boolean }>`
47
+ padding-left: ${(props) => props.theme.grid.unit * 4}px;
48
+ padding-top: ${(props) => props.theme.grid.unit * 2}px;
49
+ padding-bottom: ${(props) => props.theme.grid.unit * 2}px;
50
+
51
+ background-color: ${(props) => {
52
+ if (props.selected) {
53
+ return props.theme.colors.background.selected
54
+ }
55
+ if (props.focused) {
56
+ return props.theme.colors.background.fifth
57
+ }
58
+ return 'transparent'
59
+ }};
60
+
61
+ &:hover {
62
+ background-color: ${(props) => props.theme.colors.background.fifth};
63
+ }
64
+ `
65
+
66
+ export type InsertTableDialogProps = {
67
+ state: ManuscriptEditorState
68
+ dispatch?: Dispatch
69
+ }
70
+
71
+ export const InsertTableDialog: React.FC<InsertTableDialogProps> = ({
72
+ state,
73
+ dispatch,
74
+ }) => {
75
+ const [isOpen, setOpen] = useState(true)
76
+ const [numberOfColumns, setNumColumns] = useState({ value: 4, label: `4` })
77
+ const [numberOfRows, setNumRows] = useState({ value: 4, label: `4` })
78
+ const [includeHeader, setIncludeHeader] = useState(true)
79
+
80
+ type OptionType = { value: number; label: string }
81
+
82
+ const handleColumnChange = (newValue: OptionType) => {
83
+ setNumColumns(newValue)
84
+ }
85
+
86
+ const handleRowChange = (newValue: OptionType) => {
87
+ setNumRows(newValue)
88
+ }
89
+
90
+ const options: OptionType[] = Array.from({ length: 20 }, (_, index) => ({
91
+ value: index + 1,
92
+ label: `${index + 1}`,
93
+ }))
94
+
95
+ const OptionComponent: React.FC<OptionProps<OptionType, false>> = ({
96
+ innerProps,
97
+ data,
98
+ innerRef,
99
+ isFocused,
100
+ isSelected,
101
+ }) => {
102
+ return (
103
+ <OptionWrapper
104
+ {...innerProps}
105
+ ref={innerRef}
106
+ focused={isFocused}
107
+ selected={isSelected}
108
+ >
109
+ {data.label}
110
+ </OptionWrapper>
111
+ )
112
+ }
113
+
114
+ const actions = {
115
+ primary: {
116
+ action: () => {
117
+ const config = {
118
+ numberOfColumns: numberOfColumns.value,
119
+ numberOfRows: numberOfRows.value,
120
+ includeHeader,
121
+ }
122
+ insertTable(config, state, dispatch)
123
+ setOpen(false)
124
+ },
125
+ title: 'Create table',
126
+ },
127
+ secondary: {
128
+ action: () => setOpen(false),
129
+ title: 'Cancel',
130
+ },
131
+ }
132
+
133
+ return (
134
+ <Dialog
135
+ isOpen={isOpen}
136
+ actions={actions}
137
+ category={Category.confirmation}
138
+ header={'Insert table'}
139
+ message={''}
140
+ >
141
+ <Container>
142
+ <Label>Number of columns:</Label>
143
+ <SelectContainer>
144
+ <Select<OptionType>
145
+ onChange={(v) => handleColumnChange(v as OptionType)}
146
+ value={numberOfColumns}
147
+ options={options}
148
+ components={{
149
+ Option: OptionComponent,
150
+ }}
151
+ menuPosition="fixed"
152
+ maxMenuHeight={150}
153
+ />
154
+ </SelectContainer>
155
+ </Container>
156
+ <Container>
157
+ <Label>Number of rows:</Label>
158
+ <SelectContainer>
159
+ <Select<OptionType>
160
+ onChange={(v) => handleRowChange(v as OptionType)}
161
+ value={numberOfRows}
162
+ options={options}
163
+ components={{
164
+ Option: OptionComponent,
165
+ }}
166
+ menuPosition="fixed"
167
+ maxMenuHeight={150}
168
+ />
169
+ </SelectContainer>
170
+ </Container>
171
+ <CheckboxLabel>
172
+ <CheckboxField
173
+ name={'include-header'}
174
+ checked={includeHeader}
175
+ onChange={(e) => {
176
+ setIncludeHeader(e.target.checked)
177
+ }}
178
+ />
179
+ <div>Include header row</div>
180
+ </CheckboxLabel>
181
+ </Dialog>
182
+ )
183
+ }
184
+
185
+ export const openInsertTableDialog = (
186
+ state: ManuscriptEditorState,
187
+ dispatch?: Dispatch
188
+ ) => {
189
+ const props = getEditorProps(state)
190
+
191
+ const componentProps: InsertTableDialogProps = {
192
+ state,
193
+ dispatch,
194
+ }
195
+
196
+ const dialog = ReactSubView(
197
+ props,
198
+ InsertTableDialog,
199
+ componentProps,
200
+ state.doc,
201
+ //@ts-ignore
202
+ null,
203
+ //@ts-ignore
204
+ null
205
+ )
206
+
207
+ document.body.appendChild(dialog)
208
+ }
@@ -0,0 +1,203 @@
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
+ import {
17
+ Menu,
18
+ MenuComponentProps,
19
+ NestedSubmenusContainer,
20
+ SubmenuContainer,
21
+ SubmenuLabel,
22
+ } from '@manuscripts/style-guide'
23
+ import React, { useEffect, useRef } from 'react'
24
+ import styled from 'styled-components'
25
+
26
+ export const ListMenuItem: React.FC<MenuComponentProps> = ({
27
+ menu,
28
+ handleClick,
29
+ close,
30
+ }) => {
31
+ const styleRefs = useRef<(HTMLDivElement | null)[]>([])
32
+
33
+ useEffect(() => {
34
+ if (menu.isOpen && styleRefs.current.length > 0) {
35
+ // Auto-focus first style when menu opens
36
+ styleRefs.current[0]?.focus()
37
+ }
38
+ }, [menu.isOpen])
39
+
40
+ if (!menu.submenu) {
41
+ return null
42
+ }
43
+ const styles = menu.submenu.map((m) => (m as Menu).id)
44
+
45
+ const handleStyleClick = (s: string, i: number) => {
46
+ handleClick([i])
47
+ close()
48
+ }
49
+
50
+ const handleKeyDown = (e: React.KeyboardEvent) => {
51
+ const items = styleRefs.current.filter(Boolean) as HTMLDivElement[]
52
+ if (items.length === 0) {
53
+ return
54
+ }
55
+
56
+ const currentIndex = items.indexOf(document.activeElement as HTMLDivElement)
57
+ if (currentIndex === -1) {
58
+ return
59
+ }
60
+
61
+ e.preventDefault()
62
+ e.stopPropagation()
63
+
64
+ switch (e.key) {
65
+ case 'ArrowDown':
66
+ case 'ArrowRight':
67
+ items[(currentIndex + 1) % items.length]?.focus()
68
+ break
69
+ case 'ArrowUp':
70
+ case 'ArrowLeft':
71
+ items[(currentIndex - 1 + items.length) % items.length]?.focus()
72
+ break
73
+ case 'Escape':
74
+ close()
75
+ break
76
+ case 'Enter': {
77
+ const el = document.activeElement as HTMLElement
78
+ el?.click()
79
+ break
80
+ }
81
+ }
82
+ }
83
+
84
+ return (
85
+ <SubmenuContainer>
86
+ <SubmenuLabel menu={menu} handleClick={handleClick} close={close} />
87
+ {menu.isOpen && (
88
+ <NestedSubmenusContainer onKeyDown={handleKeyDown}>
89
+ <ListStyles
90
+ styles={styles}
91
+ onClick={handleStyleClick}
92
+ styleRefs={styleRefs}
93
+ />
94
+ </NestedSubmenusContainer>
95
+ )}
96
+ </SubmenuContainer>
97
+ )
98
+ }
99
+
100
+ export interface ListSubmenuItemsProps {
101
+ styles: string[]
102
+ onClick: (style: string, index: number) => void
103
+ styleRefs?: React.MutableRefObject<(HTMLDivElement | null)[]>
104
+ }
105
+
106
+ export const ListStyles: React.FC<ListSubmenuItemsProps> = ({
107
+ styles,
108
+ onClick,
109
+ styleRefs,
110
+ }) => {
111
+ return (
112
+ <ListContainer>
113
+ {styles.map((style, index) => (
114
+ <StyleBlock
115
+ data-cy="submenu"
116
+ key={index}
117
+ ref={(el) => {
118
+ if (styleRefs) {
119
+ styleRefs.current[index] = el
120
+ }
121
+ }}
122
+ onClick={() => onClick(style, index)}
123
+ onKeyDown={(e) => {
124
+ if (e.key === 'Enter') {
125
+ e.preventDefault()
126
+ onClick(style, index)
127
+ }
128
+ }}
129
+ tabIndex={0}
130
+ >
131
+ {styleItems[style].map((item, index) => (
132
+ <BlockItem key={index}>
133
+ <Label hide={item === '-'}>{item}</Label>
134
+ <Block />
135
+ </BlockItem>
136
+ ))}
137
+ </StyleBlock>
138
+ ))}
139
+ </ListContainer>
140
+ )
141
+ }
142
+
143
+ const styleItems: { [key: string]: string[] } = {
144
+ order: ['1.', '2.', '3.'],
145
+ 'alpha-upper': ['A.', 'B.', 'C.'],
146
+ 'alpha-lower': ['a.', 'b.', 'c.'],
147
+ 'roman-upper': ['I.', 'II.', 'III.'],
148
+ 'roman-lower': ['i.', 'ii.', 'iii.'],
149
+ bullet: ['•', '•', '•'],
150
+ simple: ['-', '-', '-'],
151
+ }
152
+
153
+ export const ListContainer = styled.div`
154
+ padding: ${(props) => props.theme.grid.unit * 4}px;
155
+ display: grid;
156
+ grid-template-columns:
157
+ ${(props) => props.theme.grid.unit * 21}px
158
+ ${(props) => props.theme.grid.unit * 21}px;
159
+ gap: 6px;
160
+ `
161
+
162
+ export const StyleBlock = styled.div`
163
+ border: 1px solid ${(props) => props.theme.colors.border.tertiary};
164
+ padding: ${(props) => props.theme.grid.unit * 2}px;
165
+ cursor: pointer;
166
+ display: flex;
167
+ flex-direction: column;
168
+ row-gap: ${(props) => props.theme.grid.unit * 2}px;
169
+
170
+ &:hover {
171
+ background: ${(props) => props.theme.colors.button.default.border.hover};
172
+ }
173
+
174
+ &:active {
175
+ border-color: ${(props) => props.theme.colors.border.primary};
176
+ }
177
+
178
+ &:focus-visible {
179
+ outline: 2px solid ${(props) => props.theme.colors.outline.focus};
180
+ outline-offset: -2px;
181
+ }
182
+ `
183
+
184
+ export const BlockItem = styled.div`
185
+ display: flex;
186
+ align-items: center;
187
+ gap: 6px;
188
+ `
189
+
190
+ export const Block = styled.div`
191
+ height: 3px;
192
+ width: ${(props) => props.theme.grid.unit * 14}px;
193
+ background: ${(props) => props.theme.colors.border.tertiary};
194
+ `
195
+
196
+ export const Label = styled.div<{ hide?: boolean }>`
197
+ font-family: Lato, serif;
198
+ font-size: ${(props) => props.theme.font.size.small};
199
+ font-weight: ${(props) => props.theme.font.weight.normal};
200
+ line-height: ${(props) => props.theme.font.lineHeight.small};
201
+ font-style: normal;
202
+ color: ${(props) => (props.hide && 'white') || 'initial'};
203
+ `