@manuscripts/body-editor 3.12.1 → 3.12.3

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 (67) hide show
  1. package/dist/cjs/components/affiliations/AffiliationItem.js +7 -11
  2. package/dist/cjs/components/affiliations/AffiliationList.js +3 -5
  3. package/dist/cjs/components/affiliations/AffiliationsModal.js +13 -4
  4. package/dist/cjs/components/authors/AuthorDetailsForm.js +44 -34
  5. package/dist/cjs/components/authors/AuthorList.js +4 -2
  6. package/dist/cjs/components/authors/AuthorsModal.js +10 -3
  7. package/dist/cjs/components/authors/DraggableAuthor.js +7 -11
  8. package/dist/cjs/components/awards/AwardForm.js +108 -100
  9. package/dist/cjs/components/hooks/use-debounce.js +15 -0
  10. package/dist/cjs/components/modal-drawer/GenericDrawerGroup.js +1 -0
  11. package/dist/cjs/components/references/CitationEditor.js +6 -7
  12. package/dist/cjs/components/references/ImportBibliographyForm.js +12 -3
  13. package/dist/cjs/components/references/ReferenceForm/PersonDropDown.js +1 -1
  14. package/dist/cjs/components/references/ReferenceForm/styled-components.js +12 -3
  15. package/dist/cjs/components/references/ReferenceSearch.js +2 -2
  16. package/dist/cjs/components/references/ReferenceSearchResults.js +58 -11
  17. package/dist/cjs/components/references/ReferenceSearchSection.js +3 -11
  18. package/dist/cjs/components/references/ReferencesModal.js +5 -4
  19. package/dist/cjs/components/toolbar/InsertTableDialog.js +11 -3
  20. package/dist/cjs/components/views/CrossReferenceItems.js +8 -14
  21. package/dist/cjs/components/views/FootnotesSelector.js +6 -6
  22. package/dist/cjs/components/views/InsertSpecialCharacter.js +24 -10
  23. package/dist/cjs/components/views/LinkForm.js +8 -1
  24. package/dist/cjs/lib/normalize.js +8 -6
  25. package/dist/cjs/lib/popper.js +4 -2
  26. package/dist/cjs/versions.js +1 -1
  27. package/dist/cjs/views/cross_reference_editable.js +1 -0
  28. package/dist/cjs/views/equation_editable.js +6 -0
  29. package/dist/cjs/views/inline_equation_editable.js +6 -0
  30. package/dist/cjs/views/inline_footnote.js +1 -0
  31. package/dist/es/components/affiliations/AffiliationItem.js +8 -12
  32. package/dist/es/components/affiliations/AffiliationList.js +3 -5
  33. package/dist/es/components/affiliations/AffiliationsModal.js +14 -5
  34. package/dist/es/components/authors/AuthorDetailsForm.js +43 -33
  35. package/dist/es/components/authors/AuthorList.js +4 -2
  36. package/dist/es/components/authors/AuthorsModal.js +11 -4
  37. package/dist/es/components/authors/DraggableAuthor.js +8 -12
  38. package/dist/es/components/awards/AwardForm.js +110 -102
  39. package/dist/es/components/hooks/use-debounce.js +15 -1
  40. package/dist/es/components/modal-drawer/GenericDrawerGroup.js +2 -1
  41. package/dist/es/components/references/CitationEditor.js +7 -8
  42. package/dist/es/components/references/ImportBibliographyForm.js +14 -5
  43. package/dist/es/components/references/ReferenceForm/PersonDropDown.js +1 -1
  44. package/dist/es/components/references/ReferenceForm/styled-components.js +13 -4
  45. package/dist/es/components/references/ReferenceSearch.js +3 -3
  46. package/dist/es/components/references/ReferenceSearchResults.js +26 -12
  47. package/dist/es/components/references/ReferenceSearchSection.js +4 -12
  48. package/dist/es/components/references/ReferencesModal.js +6 -5
  49. package/dist/es/components/toolbar/InsertTableDialog.js +11 -3
  50. package/dist/es/components/views/CrossReferenceItems.js +9 -15
  51. package/dist/es/components/views/FootnotesSelector.js +7 -7
  52. package/dist/es/components/views/InsertSpecialCharacter.js +25 -11
  53. package/dist/es/components/views/LinkForm.js +9 -2
  54. package/dist/es/lib/normalize.js +8 -6
  55. package/dist/es/lib/popper.js +4 -2
  56. package/dist/es/versions.js +1 -1
  57. package/dist/es/views/cross_reference_editable.js +1 -0
  58. package/dist/es/views/equation_editable.js +6 -0
  59. package/dist/es/views/inline_equation_editable.js +6 -0
  60. package/dist/es/views/inline_footnote.js +1 -0
  61. package/dist/types/components/authors/AuthorDetailsForm.d.ts +2 -2
  62. package/dist/types/components/hooks/use-debounce.d.ts +1 -0
  63. package/dist/types/components/references/ReferenceForm/styled-components.d.ts +11 -1
  64. package/dist/types/components/references/ReferenceSearchResults.d.ts +20 -2
  65. package/dist/types/versions.d.ts +1 -1
  66. package/package.json +2 -2
  67. package/styles/popper.css +2 -0
@@ -1,4 +1,4 @@
1
- import { ButtonGroup, Category, DeleteSolidIcon, Dialog, EditIcon, IconButton, IconTextButton, PrimaryButton, SecondaryButton, } from '@manuscripts/style-guide';
1
+ import { ButtonGroup, Category, DeleteSolidIcon, Dialog, EditIcon, IconButton, PrimaryButton, SecondaryButton, withFocusTrap, } from '@manuscripts/style-guide';
2
2
  import { generateNodeID, schema, } from '@manuscripts/transform';
3
3
  import React, { useMemo, useReducer, useState } from 'react';
4
4
  import styled from 'styled-components';
@@ -9,6 +9,7 @@ import { ImportBibliographyModal } from './ImportBibliographyModal';
9
9
  import { ReferenceLine } from './ReferenceLine';
10
10
  import { ReferenceSearch } from './ReferenceSearch';
11
11
  import { ReferencesModal } from './ReferencesModal';
12
+ const Container = withFocusTrap(styled.div ``);
12
13
  const CitedItemActions = styled.div `
13
14
  display: flex;
14
15
  align-items: center;
@@ -41,10 +42,10 @@ const ActionButton = styled(IconButton).attrs({
41
42
  const EditReferenceButton = styled(ActionButton) `
42
43
  margin-right: ${(props) => props.theme.grid.unit * 3}px;
43
44
  `;
44
- const Actions = styled.div `
45
+ const Actions = styled(ButtonGroup) `
45
46
  margin: ${(props) => props.theme.grid.unit * 4}px;
46
47
  display: flex;
47
- justify-content: space-between;
48
+ justify-content: flex-end;
48
49
  align-items: center;
49
50
  `;
50
51
  const itemsReducer = attrsReducer();
@@ -132,7 +133,7 @@ export const CitationEditor = ({ query, rids: $rids, items: $items, citationCoun
132
133
  if (!rids.length) {
133
134
  return (React.createElement(ReferenceSearch, { query: query, sources: sources, items: items, onAdd: handleAdd, onImport: handleImport, onCite: handleCite, onCancel: onCancel }));
134
135
  }
135
- return (React.createElement(React.Fragment, null,
136
+ return (React.createElement(Container, null,
136
137
  React.createElement(Dialog, { isOpen: deleteDialog.show, category: Category.confirmation, header: "Remove cited item", message: "Are you sure you want to remove this cited item? It will still exist in the reference list.", actions: {
137
138
  secondary: {
138
139
  action: () => {
@@ -156,8 +157,6 @@ export const CitationEditor = ({ query, rids: $rids, items: $items, citationCoun
156
157
  React.createElement(ActionButton, { disabled: !canEdit, onClick: () => setDeleteDialog({ show: true, id: item.id }) },
157
158
  React.createElement(DeleteSolidIcon, { className: 'remove-icon' }))))))),
158
159
  React.createElement(Actions, null,
159
- React.createElement(IconTextButton, null),
160
- React.createElement(ButtonGroup, null,
161
- React.createElement(SecondaryButton, { onClick: onCancel }, "Done"),
162
- React.createElement(PrimaryButton, { disabled: !canEdit, onClick: () => setSearching(true) }, "Add Citation")))));
160
+ React.createElement(SecondaryButton, { onClick: onCancel }, "Done"),
161
+ React.createElement(PrimaryButton, { disabled: !canEdit, onClick: () => setSearching(true) }, "Add Citation"))));
163
162
  };
@@ -13,15 +13,16 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { FormActionsBar, FormRow, Label, PrimaryButton, SecondaryButton, TextArea, } from '@manuscripts/style-guide';
16
+ import { FormActionsBar, FormRow, Label, outlineStyle, PrimaryButton, SecondaryButton, TextArea, } from '@manuscripts/style-guide';
17
17
  import { useFormik } from 'formik';
18
18
  import { debounce } from 'lodash';
19
- import React, { useCallback, useEffect, useMemo, useState } from 'react';
19
+ import React, { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
20
20
  import styled, { css } from 'styled-components';
21
21
  import { importBibliographyItems } from '../../lib/references';
22
22
  import { ReferenceLine } from './ReferenceLine';
23
23
  export const ImportBibliographyForm = ({ onCancel, onSave, }) => {
24
24
  const [dragging, setDragging] = useState(false);
25
+ const fileInputRef = useRef(null);
25
26
  const formik = useFormik({
26
27
  initialValues: {
27
28
  content: '',
@@ -80,13 +81,19 @@ export const ImportBibliographyForm = ({ onCancel, onSave, }) => {
80
81
  };
81
82
  reader.readAsText(file);
82
83
  };
84
+ const handleOnKeyDown = (e) => {
85
+ if (e.key === 'Enter' || e.key === ' ') {
86
+ e.preventDefault();
87
+ fileInputRef?.current?.click();
88
+ }
89
+ };
83
90
  return (React.createElement("form", { onSubmit: formik.handleSubmit, onReset: formik.handleReset },
84
91
  React.createElement(FormRow, null,
85
- React.createElement(DropContainer, { onDrop: handleDrop, onDragOver: (e) => {
92
+ React.createElement(DropContainer, { tabIndex: 0, role: "button", onDrop: handleDrop, onDragOver: (e) => {
86
93
  e.preventDefault();
87
94
  setDragging(true);
88
- }, onDragLeave: () => setDragging(false), active: dragging },
89
- React.createElement("input", { id: "file", name: "file", type: "file", onChange: handleFileChange, style: { display: 'none' } }),
95
+ }, onDragLeave: () => setDragging(false), onKeyDown: handleOnKeyDown, active: dragging },
96
+ React.createElement("input", { id: "file", name: "file", type: "file", ref: fileInputRef, onChange: handleFileChange, style: { display: 'none' } }),
90
97
  React.createElement(Label, { htmlFor: "file" }, "Drag & Drop or Click here to upload a file."))),
91
98
  React.createElement(FormRow, null,
92
99
  React.createElement(Label, { htmlFor: "content" }, "Alternatively, you can directly Copy&Paste below, the text of the bibliography items."),
@@ -134,4 +141,6 @@ const DropContainer = styled.div `
134
141
  font-family: ${(props) => props.theme.font.family.Lato};
135
142
  color: ${(props) => props.theme.colors.text.onLight};
136
143
  }
144
+
145
+ ${outlineStyle}
137
146
  `;
@@ -13,7 +13,7 @@ export const PersonDropDown = (props) => {
13
13
  React.createElement(ToggleButton, { type: "button", onClick: () => setIsOpen(!isOpen), isOpen: isOpen },
14
14
  React.createElement(DropdownIndicator, null),
15
15
  title),
16
- React.createElement(RemoveButton, { type: "button", "aria-label": "Delete this editor", onClick: () => remove(index) },
16
+ React.createElement(RemoveButton, { size: 13, type: "button", "aria-label": "Delete this editor", onClick: () => remove(index) },
17
17
  React.createElement(DeleteIcon, null))),
18
18
  isOpen && (React.createElement(PersonForm, null,
19
19
  React.createElement(FormRow, null,
@@ -1,4 +1,4 @@
1
- import { ArrowDownIcon, IconButton, TextArea, TextField, } from '@manuscripts/style-guide';
1
+ import { ArrowDownIcon, IconButton, outlineStyle, SecondaryIconButton, TextArea, TextField, } from '@manuscripts/style-guide';
2
2
  import styled from 'styled-components';
3
3
  export const Button = styled(IconButton).attrs({
4
4
  defaultColor: true,
@@ -86,7 +86,7 @@ export const ToggleButton = styled.button `
86
86
  text-align: left;
87
87
  font-family: ${(props) => props.theme.font.family.sans};
88
88
  font-size: 1rem;
89
- padding: 0.6em 0.5em;
89
+ margin: 0.6em;
90
90
 
91
91
  outline: none;
92
92
 
@@ -97,11 +97,20 @@ export const ToggleButton = styled.button `
97
97
  svg {
98
98
  transform: ${(props) => (props.isOpen ? 'rotateX(180deg)' : 'initial')};
99
99
  }
100
+ ${outlineStyle}
100
101
  `;
101
- export const RemoveButton = styled.button `
102
+ export const RemoveButton = styled(SecondaryIconButton) `
102
103
  border: none;
103
104
  background: transparent;
104
105
  padding: 0;
105
-
106
106
  outline: none;
107
+ svg {
108
+ path[fill='white'] {
109
+ fill: white;
110
+ }
111
+ rect[fill],
112
+ path:not([fill='white']) {
113
+ fill: #f35143;
114
+ }
115
+ }
107
116
  `;
@@ -13,7 +13,7 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { AddNewIcon, ButtonGroup, IconTextButton, PrimaryButton, SecondaryButton, UploadIcon, } from '@manuscripts/style-guide';
16
+ import { AddNewIcon, ButtonGroup, IconTextButton, PrimaryButton, SecondaryButton, UploadIcon, withFocusTrap, } from '@manuscripts/style-guide';
17
17
  import { debounce } from 'lodash';
18
18
  import React, { useState } from 'react';
19
19
  import styled from 'styled-components';
@@ -31,10 +31,10 @@ const Actions = styled(ButtonGroup) `
31
31
  justify-content: space-between;
32
32
  padding: ${(props) => props.theme.grid.unit * 4}px;
33
33
  `;
34
- const Container = styled.div `
34
+ const Container = withFocusTrap(styled.div `
35
35
  flex: 1;
36
36
  font-family: ${(props) => props.theme.font.family.sans};
37
- `;
37
+ `);
38
38
  const AddReferenceActions = styled(ButtonGroup) `
39
39
  button {
40
40
  margin-right: ${(props) => props.theme.grid.unit * 8}px;
@@ -13,8 +13,8 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { AddedIcon, AddIcon, SecondaryButton } from '@manuscripts/style-guide';
17
- import React from 'react';
16
+ import { AddedIcon, AddIcon, SecondaryButton, withListNavigation, withNavigableListItem, } from '@manuscripts/style-guide';
17
+ import React, { useRef } from 'react';
18
18
  import styled from 'styled-components';
19
19
  import { ReferenceLine } from './ReferenceLine';
20
20
  const StatusIcon = styled.div `
@@ -36,12 +36,14 @@ const MoreButton = styled(SecondaryButton) `
36
36
  margin-left: ${(props) => props.theme.grid.unit * 4}px;
37
37
  color: ${(props) => props.theme.colors.button.default.color.default};
38
38
  `;
39
- export const ReferenceSearchResultsContainer = styled.div `
40
- padding: 0 ${(props) => props.theme.grid.unit * 4}px;
39
+ export const ReferenceSearchResultsContainer = withListNavigation(styled.div `
40
+ padding: ${(props) => props.theme.grid.unit * 2}px
41
+ ${(props) => props.theme.grid.unit * 4}px;
41
42
  flex: 1;
42
43
  overflow-y: auto;
43
- `;
44
- export const ReferenceSearchResult = styled.div `
44
+ outline: none;
45
+ `);
46
+ export const ReferenceSearchResult = withNavigableListItem(styled.div `
45
47
  cursor: pointer;
46
48
  padding: ${(props) => props.theme.grid.unit * 2}px 0;
47
49
  display: flex;
@@ -49,9 +51,21 @@ export const ReferenceSearchResult = styled.div `
49
51
  &:not(:last-of-type) {
50
52
  border-bottom: 1px solid #f6f6f6;
51
53
  }
52
- `;
53
- export const ReferenceSearchResults = ({ items, total, isSelected, onSelect, onShowMore }) => (React.createElement(ReferenceSearchResultsContainer, null,
54
- items.map((item) => (React.createElement(ReferenceSearchResult, { onClick: () => onSelect(item), key: item.id, "data-cy": `${isSelected(item) ? 'selected-reference' : 'reference'}` },
55
- React.createElement(StatusIcon, null, isSelected(item) ? (React.createElement(AddedIcon, { width: 24, height: 24 })) : (React.createElement(AddIcon, { width: 24, height: 24 }))),
56
- React.createElement(ReferenceLine, { item: item })))),
57
- items.length < 25 && total > items.length ? (React.createElement(MoreButton, { onClick: onShowMore, "data-cy": 'more-button' }, "Show more")) : undefined));
54
+ `);
55
+ export const ReferenceSearchResults = ({ items, total, isSelected, onSelect, onShowMore }) => {
56
+ const list = useRef(null);
57
+ const onExpandReferenceList = () => {
58
+ const element = list.current;
59
+ if (element) {
60
+ element.setAttribute('tabindex', '0');
61
+ element.focus();
62
+ element.setAttribute('tabindex', '-1');
63
+ }
64
+ onShowMore();
65
+ };
66
+ return (React.createElement(ReferenceSearchResultsContainer, { ref: list },
67
+ items.map((item) => (React.createElement(ReferenceSearchResult, { onClick: () => onSelect(item), key: item.id, "data-cy": `${isSelected(item) ? 'selected-reference' : 'reference'}` },
68
+ React.createElement(StatusIcon, null, isSelected(item) ? (React.createElement(AddedIcon, { width: 24, height: 24 })) : (React.createElement(AddIcon, { width: 24, height: 24 }))),
69
+ React.createElement(ReferenceLine, { item: item })))),
70
+ items.length < 25 && total > items.length ? (React.createElement(MoreButton, { onClick: onExpandReferenceList, "data-cy": 'more-button' }, "Show more")) : undefined));
71
+ };
@@ -13,24 +13,16 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { TriangleCollapsedIcon, TriangleExpandedIcon, } from '@manuscripts/style-guide';
16
+ import { IconTextButton, TriangleCollapsedIcon, TriangleExpandedIcon, } from '@manuscripts/style-guide';
17
17
  import React, { useEffect, useState } from 'react';
18
18
  import styled from 'styled-components';
19
19
  import { ReferenceSearchResults } from './ReferenceSearchResults';
20
20
  import { ReferenceSearchResultsPlaceholder } from './ReferenceSearchResultsPlaceholder';
21
- const SearchSourceLabel = styled.div `
22
- margin: 0 ${(props) => props.theme.grid.unit * 4}px
21
+ const SearchSourceLabel = styled(IconTextButton) `
22
+ margin: ${(props) => props.theme.grid.unit * 2}px
23
+ ${(props) => props.theme.grid.unit * 4}px
23
24
  ${(props) => props.theme.grid.unit * 2}px;
24
25
  color: ${(props) => props.theme.colors.text.secondary};
25
- cursor: pointer;
26
-
27
- display: flex;
28
- align-items: center;
29
-
30
- .icon {
31
- margin-left: 8px;
32
- margin-right: 13px;
33
- }
34
26
 
35
27
  &:hover {
36
28
  color: ${(props) => props.theme.colors.text.muted};
@@ -1,4 +1,4 @@
1
- import { Category, CitationCountIcon, CloseButton, Dialog, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, ScrollableModalContent, SidebarContent, StyledModal, useScrollDetection, } from '@manuscripts/style-guide';
1
+ import { Category, CitationCountIcon, CloseButton, Dialog, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, ScrollableModalContent, SidebarContent, StyledModal, useScrollDetection, withListNavigation, withNavigableListItem, } from '@manuscripts/style-guide';
2
2
  import { isEqual } from 'lodash';
3
3
  import React, { useEffect, useRef, useState } from 'react';
4
4
  import styled from 'styled-components';
@@ -13,10 +13,11 @@ const ReferencesSidebar = styled(ModalSidebar) `
13
13
  const ReferencesSidebarContent = styled(SidebarContent) `
14
14
  overflow-y: auto;
15
15
  `;
16
- const ReferencesInnerWrapper = styled.div `
16
+ const ReferencesInnerWrapper = withListNavigation(styled.div `
17
17
  width: 100%;
18
- `;
19
- const ReferenceButton = styled.div `
18
+ padding: 12px 0;
19
+ `);
20
+ const ReferenceButton = withNavigableListItem(styled.div `
20
21
  cursor: pointer;
21
22
  display: flex;
22
23
  justify-content: flex-start;
@@ -43,7 +44,7 @@ const ReferenceButton = styled.div `
43
44
  padding: ${(props) => props.theme.grid.unit * 2}px;
44
45
  border-radius: 6px;
45
46
  }
46
- `;
47
+ `);
47
48
  const IconContainer = styled.div `
48
49
  padding-right: ${(props) => props.theme.grid.unit * 5}px;
49
50
  position: relative;
@@ -38,7 +38,15 @@ const OptionWrapper = styled.div `
38
38
  padding-top: ${(props) => props.theme.grid.unit * 2}px;
39
39
  padding-bottom: ${(props) => props.theme.grid.unit * 2}px;
40
40
 
41
- background-color: ${(props) => props.focused ? props.theme.colors.background.fifth : 'transparent'};
41
+ background-color: ${(props) => {
42
+ if (props.selected) {
43
+ return props.theme.colors.background.selected;
44
+ }
45
+ if (props.focused) {
46
+ return props.theme.colors.background.fifth;
47
+ }
48
+ return 'transparent';
49
+ }};
42
50
 
43
51
  &:hover {
44
52
  background-color: ${(props) => props.theme.colors.background.fifth};
@@ -59,8 +67,8 @@ export const InsertTableDialog = ({ state, dispatch, }) => {
59
67
  value: index + 1,
60
68
  label: `${index + 1}`,
61
69
  }));
62
- const OptionComponent = ({ innerProps, data, }) => {
63
- return (React.createElement(OptionWrapper, { ...innerProps, ref: null }, data.label));
70
+ const OptionComponent = ({ innerProps, data, innerRef, isFocused, isSelected, }) => {
71
+ return (React.createElement(OptionWrapper, { ...innerProps, ref: innerRef, focused: isFocused, selected: isSelected }, data.label));
64
72
  };
65
73
  const actions = {
66
74
  primary: {
@@ -13,30 +13,29 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { ButtonGroup, PrimaryButton, SecondaryButton, TextArea, } from '@manuscripts/style-guide';
16
+ import { ButtonGroup, PrimaryButton, SecondaryButton, TextArea, withFocusTrap, withListNavigation, withNavigableListItem, } from '@manuscripts/style-guide';
17
17
  import React, { useEffect, useRef, useState } from 'react';
18
18
  import styled from 'styled-components';
19
- const Container = styled.div `
19
+ const Container = withFocusTrap(styled.div `
20
20
  padding: ${(props) => props.theme.grid.unit * 3}px
21
21
  ${(props) => props.theme.grid.unit * 4}px;
22
22
  display: flex;
23
23
  flex-direction: column;
24
24
  max-height: 60vh;
25
25
  overflow: hidden;
26
- `;
26
+ `);
27
27
  const Actions = styled.div `
28
28
  display: flex;
29
29
  align-items: center;
30
30
  justify-content: flex-end;
31
31
  flex-shrink: 0;
32
32
  `;
33
- const Items = styled.div `
33
+ const Items = withListNavigation(styled.div `
34
34
  flex: 1;
35
35
  overflow-y: auto;
36
- margin: ${(props) => props.theme.grid.unit * 4}px 0;
37
- `;
38
- const CrossReferenceItem = styled.div `
39
- position: relative;
36
+ padding: ${(props) => props.theme.grid.unit * 3}px;
37
+ `);
38
+ const CrossReferenceItem = withNavigableListItem(styled.div `
40
39
  cursor: pointer;
41
40
  padding: ${(props) => props.theme.grid.unit * 4}px;
42
41
  background-color: ${(props) => props.isSelected
@@ -48,17 +47,12 @@ const CrossReferenceItem = styled.div `
48
47
  ? props.theme.colors.brand.medium
49
48
  : props.theme.colors.border.secondary};
50
49
  border-width: 1px 0;
51
- margin-top: -1px;
52
50
  z-index: ${(props) => (props.isSelected ? '1' : '0')};
53
51
 
54
- &:first-child {
55
- margin-top: 0;
56
- }
57
-
58
52
  &:hover {
59
53
  background-color: ${(props) => props.theme.colors.background.selected};
60
54
  }
61
- `;
55
+ `);
62
56
  const Label = styled.span `
63
57
  color: ${(props) => props.theme.colors.text.primary};
64
58
  `;
@@ -105,7 +99,7 @@ export const CrossReferenceItems = ({ targets, handleSelect, handleCancel, curre
105
99
  }, [currentTargetId]);
106
100
  return (React.createElement(Container, null,
107
101
  React.createElement(Heading, null, "Insert Cross-reference"),
108
- React.createElement(Items, null, targets.length ? (targets.map((target) => (React.createElement(CrossReferenceItem, { key: target.id, isSelected: selectedItem === target.id, onMouseDown: () => setSelectedItem(target.id) },
102
+ React.createElement(Items, null, targets.length ? (targets.map((target) => (React.createElement(CrossReferenceItem, { key: target.id, isSelected: selectedItem === target.id, onClick: () => setSelectedItem(target.id) },
109
103
  React.createElement(DefaultLabelWrapper, null,
110
104
  React.createElement(Label, null, target.label),
111
105
  React.createElement(Caption, null, target.caption && ': ' + trimmedCaption(target.caption, 200))),
@@ -13,7 +13,7 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { AddedIcon, AddIcon, AddNewIcon, ButtonGroup, IconTextButton, PrimaryButton, SecondaryButton, } from '@manuscripts/style-guide';
16
+ import { AddedIcon, AddIcon, AddNewIcon, ButtonGroup, IconTextButton, PrimaryButton, SecondaryButton, withFocusTrap, withListNavigation, withNavigableListItem, } from '@manuscripts/style-guide';
17
17
  import React, { useState } from 'react';
18
18
  import styled from 'styled-components';
19
19
  import { isDeleted } from '../../lib/track-changes-utils';
@@ -29,10 +29,10 @@ const Actions = styled(ButtonGroup) `
29
29
  justify-content: space-between;
30
30
  padding: ${(props) => props.theme.grid.unit * 4}px;
31
31
  `;
32
- const Container = styled.div `
32
+ const Container = withFocusTrap(styled.div `
33
33
  flex: 1;
34
34
  font-family: ${(props) => props.theme.font.family.sans};
35
- `;
35
+ `);
36
36
  const AddNewFootnote = styled(ButtonGroup) `
37
37
  button {
38
38
  margin-right: ${(props) => props.theme.grid.unit * 8}px;
@@ -113,17 +113,17 @@ const Separator = styled.div `
113
113
  border-bottom: 1px solid #e2e2e2;
114
114
  margin: 4px 0;
115
115
  `;
116
- const NotesListContainer = styled.div `
116
+ const NotesListContainer = withListNavigation(styled.div `
117
117
  padding: ${(props) => props.theme.grid.unit * 6}px
118
118
  ${(props) => props.theme.grid.unit * 5}px;
119
119
  flex: 1;
120
120
  overflow-y: auto;
121
- `;
122
- const FootnoteItemContainer = styled.div `
121
+ `);
122
+ const FootnoteItemContainer = withNavigableListItem(styled.div `
123
123
  cursor: pointer;
124
124
  padding: ${(props) => props.theme.grid.unit * 2}px 0;
125
125
  display: flex;
126
- `;
126
+ `);
127
127
  const StatusIcon = styled.div `
128
128
  flex-shrink: 1;
129
129
  margin-right: ${(props) => props.theme.grid.unit * 3}px;
@@ -1,4 +1,4 @@
1
- import { ButtonGroup, CloseButton, IconButton, IconButtonGroup, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, PrimaryButton, SidebarContent, StyledModal, } from '@manuscripts/style-guide';
1
+ import { ButtonGroup, CloseButton, IconButton, IconButtonGroup, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, PrimaryButton, SidebarContent, StyledModal, withNavigableListItem, withListNavigation, } from '@manuscripts/style-guide';
2
2
  import React, { useState } from 'react';
3
3
  import Select from 'react-select';
4
4
  import styled from 'styled-components';
@@ -39,8 +39,8 @@ const InsertSpecialCharacterDialog = ({ view }) => {
39
39
  React.createElement(ButtonsContainer, null,
40
40
  React.createElement(PrimaryButton, { onClick: handleClose }, "Close")))))));
41
41
  };
42
- const OptionComponent = ({ innerProps, data, }) => {
43
- return (React.createElement(OptionWrapper, { ...innerProps, ref: null }, data.label));
42
+ const OptionComponent = ({ innerProps, innerRef, data, isFocused, isSelected, }) => {
43
+ return (React.createElement(OptionWrapper, { ...innerProps, ref: innerRef, focused: isFocused, selected: isSelected }, data.label));
44
44
  };
45
45
  const Container = styled(ModalContainer) `
46
46
  padding: 8px;
@@ -64,7 +64,15 @@ const OptionWrapper = styled.div `
64
64
  padding-top: ${(props) => props.theme.grid.unit * 2}px;
65
65
  padding-bottom: ${(props) => props.theme.grid.unit * 2}px;
66
66
 
67
- background-color: ${(props) => props.focused ? props.theme.colors.background.fifth : 'transparent'};
67
+ background-color: ${(props) => {
68
+ if (props.selected) {
69
+ return props.theme.colors.background.selected;
70
+ }
71
+ if (props.focused) {
72
+ return props.theme.colors.background.fifth;
73
+ }
74
+ return 'transparent';
75
+ }};
68
76
 
69
77
  &:hover {
70
78
  background-color: ${(props) => props.theme.colors.background.fifth};
@@ -74,19 +82,20 @@ const CharactersSetContainer = styled.div `
74
82
  flex: 1;
75
83
  overflow-y: scroll;
76
84
  margin: 18px 0;
77
- border: 1px solid #ddd;
85
+ padding: 8px;
78
86
  `;
79
- const CharactersSet = styled(IconButtonGroup) `
87
+ const CharactersSet = withListNavigation(styled(IconButtonGroup) `
80
88
  display: grid;
81
89
  grid-template-columns: repeat(auto-fit, minmax(28px, max-content));
82
- height: ${(props) => props.theme.grid.unit * 8}px;
83
- `;
84
- const Character = styled(IconButton) `
90
+ border: 1px solid #ddd;
91
+ `);
92
+ const Character = withNavigableListItem(styled(IconButton) `
85
93
  border-bottom: 1px solid #ddd;
86
94
  border-right: 1px solid #ddd;
87
95
  border-radius: unset;
88
96
 
89
- :hover {
97
+ :hover,
98
+ :focus {
90
99
  background-color: #f0f0f0 !important;
91
100
  }
92
101
 
@@ -96,7 +105,12 @@ const Character = styled(IconButton) `
96
105
  border-bottom: 1px solid #ddd !important;
97
106
  border-right: 1px solid #ddd !important;
98
107
  }
99
- `;
108
+
109
+ &&:not([disabled]):focus-visible {
110
+ outline: 1px solid ${(props) => props.theme.colors.outline.focus};
111
+ outline-offset: 2px;
112
+ }
113
+ `);
100
114
  export const openInsertSpecialCharacterDialog = (view) => {
101
115
  if (!view) {
102
116
  return;
@@ -13,7 +13,7 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { DeleteIcon, FormContainer, FormRow, Label, PrimaryButton, SecondaryButton, TextField, InputErrorText, } from '@manuscripts/style-guide';
16
+ import { DeleteIcon, FormContainer, FormRow, Label, PrimaryButton, SecondaryButton, TextField, InputErrorText, withFocusTrap, } from '@manuscripts/style-guide';
17
17
  import React, { useCallback, useState } from 'react';
18
18
  import styled from 'styled-components';
19
19
  import { allowedHref } from '../../lib/url';
@@ -44,6 +44,7 @@ const RemoveButton = styled(SecondaryButton) `
44
44
  export const Open = styled.a `
45
45
  display: inline-block;
46
46
  margin-left: ${(props) => props.theme.grid.unit * 2}px;
47
+ margin-top: 4px;
47
48
  text-transform: uppercase;
48
49
  color: inherit;
49
50
  font-size: ${(props) => props.theme.font.size.small};
@@ -53,7 +54,13 @@ export const Open = styled.a `
53
54
  content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAQElEQVR42qXKwQkAIAxDUUdxtO6/RBQkQZvSi8I/pL4BoGw/XPkh4XigPmsUgh0626AjRsgxHTkUThsG2T/sIlzdTsp52kSS1wAAAABJRU5ErkJggg==);
54
55
  margin-left: 4px;
55
56
  }
57
+
58
+ &&:not([disabled]):focus-visible {
59
+ outline: 2px solid ${(props) => props.theme.colors.outline.focus};
60
+ outline-offset: 3px;
61
+ }
56
62
  `;
63
+ const Form = withFocusTrap(styled.form ``);
57
64
  export const LinkForm = ({ onCancel, onRemove, onSave, value, }) => {
58
65
  const [href, setHref] = useState(value.href);
59
66
  const [text, setText] = useState(value.text);
@@ -93,7 +100,7 @@ export const LinkForm = ({ onCancel, onRemove, onSave, value, }) => {
93
100
  onSave({ href, text, title });
94
101
  }
95
102
  }, [href, text, title, onSave, validate]);
96
- return (React.createElement("form", { onSubmit: handleSubmit, noValidate: true },
103
+ return (React.createElement(Form, { onSubmit: handleSubmit, noValidate: true },
97
104
  React.createElement(FormContainer, null,
98
105
  React.createElement(FormRow, null,
99
106
  React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' } },
@@ -14,21 +14,23 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { generateNodeID, schema } from '@manuscripts/transform';
17
+ const trim = (value) => (value ?? '').trim();
17
18
  export const normalizeAuthor = (author) => {
18
19
  const basic = {
19
20
  id: author.id,
20
- role: author.role || '',
21
+ role: trim(author.role),
21
22
  affiliationIDs: (author.affiliationIDs || []).sort(),
22
- given: author.given || '',
23
- family: author.family || '',
24
- email: author.email || '',
23
+ given: trim(author.given),
24
+ family: trim(author.family),
25
+ email: trim(author.email),
25
26
  isCorresponding: author.isCorresponding || false,
26
- ORCID: author.ORCID || '',
27
+ ORCID: trim(author.ORCID),
27
28
  priority: author.priority,
28
29
  isJointContributor: author.isJointContributor || false,
29
30
  footnoteIDs: author.footnoteIDs || [],
30
31
  correspIDs: author.correspIDs || [],
31
- prefix: author.prefix || '',
32
+ prefix: trim(author.prefix),
33
+ suffix: trim(author.suffix),
32
34
  };
33
35
  if (author.creditRoles && Array.isArray(author.creditRoles)) {
34
36
  basic.creditRoles = author.creditRoles;
@@ -37,11 +37,13 @@ export class PopperManager {
37
37
  this.triggerElement.focus();
38
38
  }
39
39
  };
40
+ const isMenu = contents.classList.contains('context-menu') ||
41
+ contents.classList.contains('menu');
40
42
  createKeyboardInteraction({
41
43
  container,
42
44
  additionalKeys: {
43
45
  Escape: closeAndRestoreFocus,
44
- Tab: closeAndRestoreFocus,
46
+ Tab: isMenu ? closeAndRestoreFocus : undefined,
45
47
  },
46
48
  });
47
49
  if (showArrow) {
@@ -113,7 +115,7 @@ export class PopperManager {
113
115
  return;
114
116
  }
115
117
  if (autoFocus) {
116
- const button = container.querySelector('button:not([disabled])');
118
+ const button = container.querySelector('button:not([disabled]), [tabindex]:not([tabindex="-1"])');
117
119
  button?.focus();
118
120
  }
119
121
  }
@@ -1,2 +1,2 @@
1
- export const VERSION = '3.12.1';
1
+ export const VERSION = '3.12.3';
2
2
  export const MATHJAX_VERSION = '3.2.2';
@@ -39,6 +39,7 @@ export class CrossReferenceEditableView extends CrossReferenceView {
39
39
  currentCustomLabel: this.node.attrs.label,
40
40
  };
41
41
  this.popperContainer = ReactSubView(this.props, CrossReferenceItems, componentProps, this.node, this.getPos, this.view, ['cross-reference-editor']);
42
+ this.popperContainer.setAttribute('tabindex', '0');
42
43
  this.props.popper.show(this.dom, this.popperContainer, 'auto');
43
44
  };
44
45
  this.destroy = () => {
@@ -30,6 +30,12 @@ export class EquationEditableView extends EquationView {
30
30
  mode: 'stex',
31
31
  placeholder,
32
32
  autofocus: true,
33
+ extraKeys: {
34
+ Esc: () => {
35
+ this.props.popper.destroy();
36
+ this.view.focus();
37
+ },
38
+ },
33
39
  });
34
40
  input.on('changes', async () => {
35
41
  const contents = input.getValue();
@@ -30,6 +30,12 @@ export class InlineEquationEditableView extends InlineEquationView {
30
30
  mode: 'stex',
31
31
  placeholder,
32
32
  autofocus: true,
33
+ extraKeys: {
34
+ Esc: () => {
35
+ this.props.popper.destroy();
36
+ this.view.focus();
37
+ },
38
+ },
33
39
  });
34
40
  input.on('changes', async () => {
35
41
  const contents = input.getValue();
@@ -98,6 +98,7 @@ export class InlineFootnoteView extends BaseNodeView {
98
98
  onInsert: this.handleInsert,
99
99
  };
100
100
  this.popperContainer = ReactSubView(this.props, FootnotesSelector, props, this.node, this.getPos, this.view, ['footnote-editor']);
101
+ this.popperContainer.setAttribute('tabindex', '0');
101
102
  this.props.popper.show(this.dom, this.popperContainer, 'auto', false);
102
103
  };
103
104
  this.initialise = () => {