@manuscripts/body-editor 3.9.11 → 3.9.13

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 (105) hide show
  1. package/dist/cjs/commands.js +5 -2
  2. package/dist/cjs/components/keywords/AddKeywordInline.js +12 -1
  3. package/dist/cjs/components/views/FigureDropdown.js +65 -6
  4. package/dist/cjs/configs/ManuscriptsEditor.js +1 -1
  5. package/dist/cjs/index.js +1 -0
  6. package/dist/cjs/keys/misc.js +2 -1
  7. package/dist/cjs/keys/title.js +0 -38
  8. package/dist/cjs/lib/comments.js +1 -0
  9. package/dist/cjs/lib/context-menu.js +74 -8
  10. package/dist/cjs/lib/media.js +27 -3
  11. package/dist/cjs/lib/navigation-utils.js +132 -0
  12. package/dist/cjs/lib/popper.js +25 -1
  13. package/dist/cjs/lib/position-menu.js +3 -0
  14. package/dist/cjs/lib/utils.js +7 -2
  15. package/dist/cjs/plugins/accessibility_element.js +10 -2
  16. package/dist/cjs/plugins/add-subtitle.js +8 -2
  17. package/dist/cjs/plugins/alt-titles.js +6 -1
  18. package/dist/cjs/plugins/comments.js +27 -15
  19. package/dist/cjs/plugins/persistent-cursor.js +4 -6
  20. package/dist/cjs/plugins/section_category.js +42 -9
  21. package/dist/cjs/plugins/translations.js +49 -13
  22. package/dist/cjs/versions.js +1 -1
  23. package/dist/cjs/views/accessibility_element.js +30 -0
  24. package/dist/cjs/views/alt_title.js +29 -0
  25. package/dist/cjs/views/alt_titles_section.js +9 -1
  26. package/dist/cjs/views/attachment.js +1 -1
  27. package/dist/cjs/views/bibliography_element.js +39 -17
  28. package/dist/cjs/views/citation.js +1 -0
  29. package/dist/cjs/views/citation_editable.js +4 -2
  30. package/dist/cjs/views/contributors.js +23 -2
  31. package/dist/cjs/views/cross_reference.js +3 -0
  32. package/dist/cjs/views/editable_block.js +37 -3
  33. package/dist/cjs/views/embed.js +3 -3
  34. package/dist/cjs/views/figure_editable.js +1 -1
  35. package/dist/cjs/views/figure_element.js +3 -0
  36. package/dist/cjs/views/footnote.js +3 -0
  37. package/dist/cjs/views/hero_image.js +4 -1
  38. package/dist/cjs/views/image_element.js +15 -7
  39. package/dist/cjs/views/inline_footnote.js +3 -0
  40. package/dist/cjs/views/keyword.js +15 -0
  41. package/dist/cjs/views/keyword_group.js +38 -0
  42. package/dist/cjs/views/quote_image_editable.js +1 -0
  43. package/dist/cjs/views/supplements.js +4 -1
  44. package/dist/es/commands.js +5 -2
  45. package/dist/es/components/keywords/AddKeywordInline.js +12 -1
  46. package/dist/es/components/views/FigureDropdown.js +66 -7
  47. package/dist/es/configs/ManuscriptsEditor.js +1 -1
  48. package/dist/es/index.js +1 -0
  49. package/dist/es/keys/misc.js +2 -1
  50. package/dist/es/keys/title.js +1 -39
  51. package/dist/es/lib/comments.js +1 -0
  52. package/dist/es/lib/context-menu.js +74 -8
  53. package/dist/es/lib/media.js +27 -3
  54. package/dist/es/lib/navigation-utils.js +122 -0
  55. package/dist/es/lib/popper.js +25 -1
  56. package/dist/es/lib/position-menu.js +3 -0
  57. package/dist/es/lib/utils.js +7 -2
  58. package/dist/es/plugins/accessibility_element.js +10 -2
  59. package/dist/es/plugins/add-subtitle.js +8 -2
  60. package/dist/es/plugins/alt-titles.js +6 -1
  61. package/dist/es/plugins/comments.js +27 -15
  62. package/dist/es/plugins/persistent-cursor.js +4 -6
  63. package/dist/es/plugins/section_category.js +42 -9
  64. package/dist/es/plugins/translations.js +49 -13
  65. package/dist/es/versions.js +1 -1
  66. package/dist/es/views/accessibility_element.js +30 -0
  67. package/dist/es/views/alt_title.js +29 -0
  68. package/dist/es/views/alt_titles_section.js +9 -1
  69. package/dist/es/views/attachment.js +1 -1
  70. package/dist/es/views/bibliography_element.js +39 -17
  71. package/dist/es/views/citation.js +1 -0
  72. package/dist/es/views/citation_editable.js +4 -2
  73. package/dist/es/views/contributors.js +23 -2
  74. package/dist/es/views/cross_reference.js +3 -0
  75. package/dist/es/views/editable_block.js +37 -3
  76. package/dist/es/views/embed.js +3 -3
  77. package/dist/es/views/figure_editable.js +1 -1
  78. package/dist/es/views/figure_element.js +3 -0
  79. package/dist/es/views/footnote.js +3 -0
  80. package/dist/es/views/hero_image.js +4 -1
  81. package/dist/es/views/image_element.js +15 -7
  82. package/dist/es/views/inline_footnote.js +3 -0
  83. package/dist/es/views/keyword.js +15 -0
  84. package/dist/es/views/keyword_group.js +38 -0
  85. package/dist/es/views/quote_image_editable.js +1 -0
  86. package/dist/es/views/supplements.js +4 -1
  87. package/dist/types/configs/ManuscriptsEditor.d.ts +1 -1
  88. package/dist/types/index.d.ts +1 -0
  89. package/dist/types/lib/context-menu.d.ts +1 -0
  90. package/dist/types/lib/media.d.ts +1 -1
  91. package/dist/types/lib/navigation-utils.d.ts +45 -0
  92. package/dist/types/lib/popper.d.ts +3 -0
  93. package/dist/types/lib/utils.d.ts +1 -1
  94. package/dist/types/versions.d.ts +1 -1
  95. package/dist/types/views/accessibility_element.d.ts +2 -0
  96. package/dist/types/views/alt_title.d.ts +2 -0
  97. package/dist/types/views/bibliography_element.d.ts +3 -0
  98. package/dist/types/views/citation_editable.d.ts +1 -1
  99. package/dist/types/views/contributors.d.ts +3 -1
  100. package/dist/types/views/keyword.d.ts +1 -0
  101. package/dist/types/views/keyword_group.d.ts +4 -0
  102. package/package.json +4 -4
  103. package/styles/AdvancedEditor.css +116 -10
  104. package/styles/Editor.css +61 -6
  105. package/styles/popper.css +3 -1
@@ -24,6 +24,7 @@ const transform_1 = require("@manuscripts/transform");
24
24
  const prosemirror_state_1 = require("prosemirror-state");
25
25
  const ReferencesEditor_1 = require("../components/references/ReferencesEditor");
26
26
  const comments_1 = require("../lib/comments");
27
+ const navigation_utils_1 = require("../lib/navigation-utils");
27
28
  const doc_1 = require("../lib/doc");
28
29
  const dompurify_1 = require("../lib/dompurify");
29
30
  const track_changes_utils_1 = require("../lib/track-changes-utils");
@@ -39,31 +40,50 @@ class BibliographyElementBlockView extends block_view_1.default {
39
40
  super(...arguments);
40
41
  this.stopEvent = () => true;
41
42
  this.ignoreMutation = () => true;
43
+ this.handleCommentMarkerInteraction = (marker) => {
44
+ const key = marker.dataset.key;
45
+ const tr = this.view.state.tr;
46
+ (0, comments_2.setCommentSelection)(tr, key, undefined, false);
47
+ this.view.dispatch(tr);
48
+ };
49
+ this.handleBibItemInteraction = (item) => {
50
+ if (!this.props.getCapabilities().seeReferencesButtons) {
51
+ return;
52
+ }
53
+ this.showContextMenu(item);
54
+ const node = (0, view_1.findChildByID)(this.view, item.id);
55
+ if (node) {
56
+ const tr = this.view.state.tr;
57
+ tr.setSelection(prosemirror_state_1.NodeSelection.create(this.view.state.doc, node.pos));
58
+ this.view.dispatch(tr);
59
+ }
60
+ };
42
61
  this.handleClick = (event) => {
43
62
  const element = event.target;
44
63
  const marker = element.closest('.comment-marker');
45
64
  if (marker) {
46
- const key = marker.dataset.key;
47
- const tr = this.view.state.tr;
48
- (0, comments_2.setCommentSelection)(tr, key, undefined, false);
49
- this.view.dispatch(tr);
65
+ this.handleCommentMarkerInteraction(marker);
50
66
  return;
51
67
  }
52
- if (this.props.getCapabilities().seeReferencesButtons) {
53
- const item = element.closest('.bib-item');
54
- if (item) {
55
- this.showContextMenu(item);
56
- const node = (0, view_1.findChildByID)(this.view, item.id);
57
- if (!node) {
58
- return;
59
- }
60
- const view = this.view;
61
- const tr = view.state.tr;
62
- tr.setSelection(prosemirror_state_1.NodeSelection.create(view.state.doc, node.pos));
63
- view.dispatch(tr);
64
- }
68
+ const item = element.closest('.bib-item');
69
+ if (item) {
70
+ this.handleBibItemInteraction(item);
65
71
  }
66
72
  };
73
+ this.handleKeyDown = (event) => {
74
+ (0, navigation_utils_1.handleEnterKey)(() => {
75
+ const target = document.activeElement;
76
+ const marker = target?.closest('.comment-marker');
77
+ if (marker) {
78
+ this.handleCommentMarkerInteraction(marker);
79
+ return;
80
+ }
81
+ const bibItem = target?.closest('.bib-item');
82
+ if (bibItem) {
83
+ this.handleBibItemInteraction(bibItem);
84
+ }
85
+ })(event);
86
+ };
67
87
  this.createElement = () => {
68
88
  this.container = document.createElement('div');
69
89
  this.container.classList.add('block');
@@ -170,6 +190,7 @@ class BibliographyElementBlockView extends block_view_1.default {
170
190
  const wrapper = document.createElement('div');
171
191
  wrapper.classList.add('contents');
172
192
  wrapper.addEventListener('click', this.handleClick);
193
+ wrapper.addEventListener('keydown', this.handleKeyDown);
173
194
  const [meta, bibliography] = bib.engine.makeBibliography();
174
195
  for (let i = 0; i < bibliography.length; i++) {
175
196
  const id = meta.entry_ids[i][0];
@@ -196,6 +217,7 @@ class BibliographyElementBlockView extends block_view_1.default {
196
217
  }
197
218
  }
198
219
  const element = (0, dompurify_1.sanitize)(`<div id="${id}" class="bib-item"><div class="csl-bib-body">${tempDiv.innerHTML}</div></div>`).firstElementChild;
220
+ element.tabIndex = 0;
199
221
  const comment = (0, comments_1.createCommentMarker)('div', id);
200
222
  element.prepend(comment);
201
223
  (0, track_changes_utils_1.addTrackChangesAttributes)(node.attrs, element);
@@ -32,6 +32,7 @@ class CitationView extends base_node_view_1.BaseNodeView {
32
32
  createDOM() {
33
33
  this.dom = document.createElement('span');
34
34
  this.dom.classList.add('citation');
35
+ this.dom.tabIndex = 0;
35
36
  }
36
37
  updateContents() {
37
38
  super.updateContents();
@@ -27,6 +27,7 @@ const CitationEditor_1 = require("../components/references/CitationEditor");
27
27
  const CitationViewer_1 = require("../components/references/CitationViewer");
28
28
  const comments_1 = require("../lib/comments");
29
29
  const crossref_1 = require("../lib/crossref");
30
+ const navigation_utils_1 = require("../lib/navigation-utils");
30
31
  const track_changes_utils_1 = require("../lib/track-changes-utils");
31
32
  const view_1 = require("../lib/view");
32
33
  const bibliography_1 = require("../plugins/bibliography");
@@ -47,12 +48,12 @@ class CitationEditableView extends citation_1.CitationView {
47
48
  element.classList.contains('comment-icon') ||
48
49
  element.parentElement?.classList.contains('comment-icon'));
49
50
  };
50
- this.handleClick = (event) => {
51
+ this.handleClick = () => {
51
52
  if (!this.can.seeReferencesButtons ||
52
53
  this.dom.classList.contains('inconsistency-highlight')) {
53
54
  this.showPopper();
54
55
  }
55
- else if (!(0, track_changes_utils_1.isDeleted)(this.node) && event.button === 0) {
56
+ else if (!(0, track_changes_utils_1.isDeleted)(this.node)) {
56
57
  const attrs = this.node.attrs;
57
58
  if (attrs.rids.length) {
58
59
  this.showContextMenu();
@@ -197,6 +198,7 @@ class CitationEditableView extends citation_1.CitationView {
197
198
  createDOM() {
198
199
  super.createDOM();
199
200
  this.dom.addEventListener('mouseup', this.handleClick);
201
+ this.dom.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(() => this.handleClick()));
200
202
  }
201
203
  insertBibliographyNode(attrs) {
202
204
  const { doc, tr } = this.view.state;
@@ -25,6 +25,7 @@ const prosemirror_state_1 = require("prosemirror-state");
25
25
  const AuthorsModal_1 = require("../components/authors/AuthorsModal");
26
26
  const authors_1 = require("../lib/authors");
27
27
  const comments_1 = require("../lib/comments");
28
+ const navigation_utils_1 = require("../lib/navigation-utils");
28
29
  const track_changes_utils_1 = require("../lib/track-changes-utils");
29
30
  const utils_1 = require("../lib/utils");
30
31
  const view_1 = require("../lib/view");
@@ -51,11 +52,26 @@ class ContributorsView extends block_view_1.default {
51
52
  const can = this.props.getCapabilities();
52
53
  if (can.editMetadata) {
53
54
  wrapper.addEventListener('click', this.handleClick);
55
+ this.removeKeydownListener = (0, navigation_utils_1.createKeyboardInteraction)({
56
+ container: wrapper,
57
+ navigation: {
58
+ getItems: () => {
59
+ return Array.from(wrapper.querySelectorAll('.contributor'));
60
+ },
61
+ arrowKeys: { forward: 'ArrowRight', backward: 'ArrowLeft' },
62
+ },
63
+ additionalKeys: {
64
+ Enter: (e) => {
65
+ e.preventDefault();
66
+ this.handleClick(e);
67
+ },
68
+ },
69
+ });
54
70
  }
55
71
  const authors = affs.contributors;
56
72
  authors.sort(authors_1.authorComparator).forEach((author, i) => {
57
73
  const jointAuthors = this.isJointFirstAuthor(authors, i);
58
- wrapper.appendChild(this.buildAuthor(author, jointAuthors));
74
+ wrapper.appendChild(this.buildAuthor(author, jointAuthors, i));
59
75
  if (i !== authors.length - 1) {
60
76
  const separator = document.createElement('span');
61
77
  separator.classList.add('separator');
@@ -65,13 +81,14 @@ class ContributorsView extends block_view_1.default {
65
81
  });
66
82
  this.container.appendChild(wrapper);
67
83
  };
68
- this.buildAuthor = (attrs, isJointFirstAuthor) => {
84
+ this.buildAuthor = (attrs, isJointFirstAuthor, index) => {
69
85
  const state = this.view.state;
70
86
  const affs = affiliations_1.affiliationsKey.getState(state)?.indexedAffiliationIds;
71
87
  const container = document.createElement('span');
72
88
  container.classList.add('contributor');
73
89
  container.setAttribute('id', attrs.id);
74
90
  container.setAttribute('contenteditable', 'false');
91
+ container.tabIndex = index === 0 ? 0 : -1;
75
92
  (0, track_changes_utils_1.addTrackChangesAttributes)(attrs, container);
76
93
  const name = (0, authors_1.authorLabel)(attrs);
77
94
  container.innerHTML =
@@ -275,6 +292,10 @@ class ContributorsView extends block_view_1.default {
275
292
  note.classList.add('contributor-note');
276
293
  return note;
277
294
  }
295
+ destroy() {
296
+ this.removeKeydownListener?.();
297
+ super.destroy();
298
+ }
278
299
  }
279
300
  exports.ContributorsView = ContributorsView;
280
301
  exports.default = (0, creators_1.createNodeView)(ContributorsView);
@@ -16,6 +16,7 @@
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.CrossReferenceView = void 0;
19
+ const navigation_utils_1 = require("../lib/navigation-utils");
19
20
  const objects_1 = require("../plugins/objects");
20
21
  const base_node_view_1 = require("./base_node_view");
21
22
  const creators_1 = require("./creators");
@@ -40,6 +41,8 @@ class CrossReferenceView extends base_node_view_1.BaseNodeView {
40
41
  this.createDOM = () => {
41
42
  this.dom = document.createElement('span');
42
43
  this.dom.className = 'cross-reference';
44
+ this.dom.tabIndex = 0;
45
+ this.dom.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(() => this.handleClick()));
43
46
  };
44
47
  }
45
48
  updateContents() {
@@ -19,6 +19,7 @@ exports.EditableBlock = void 0;
19
19
  const transform_1 = require("@manuscripts/transform");
20
20
  const context_menu_1 = require("../lib/context-menu");
21
21
  const utils_1 = require("../lib/utils");
22
+ const navigation_utils_1 = require("../lib/navigation-utils");
22
23
  const EditableBlock = (Base) => {
23
24
  return class extends Base {
24
25
  constructor() {
@@ -28,7 +29,12 @@ const EditableBlock = (Base) => {
28
29
  };
29
30
  }
30
31
  gutterButtons() {
31
- return [this.createAddButton(), this.createEditButton()].filter(utils_1.isNotNull);
32
+ const buttons = [this.createAddButton(), this.createEditButton()].filter(utils_1.isNotNull);
33
+ buttons.forEach((btn) => (btn.tabIndex = -1));
34
+ if (buttons.length > 0) {
35
+ buttons[0].tabIndex = 0;
36
+ }
37
+ return buttons;
32
38
  }
33
39
  actionGutterButtons() {
34
40
  return [];
@@ -56,10 +62,24 @@ const EditableBlock = (Base) => {
56
62
  button.setAttribute('role', 'button');
57
63
  button.setAttribute('aria-label', `Add an element below`);
58
64
  button.setAttribute('data-balloon-pos', 'down-left');
59
- button.addEventListener('mousedown', (event) => {
65
+ const handleClick = (event) => {
60
66
  event.preventDefault();
61
67
  const menu = this.createMenu();
62
68
  menu.showAddMenu(event.currentTarget);
69
+ };
70
+ button.addEventListener('mousedown', handleClick);
71
+ (0, navigation_utils_1.createKeyboardInteraction)({
72
+ container: button,
73
+ additionalKeys: {
74
+ Enter: handleClick,
75
+ ArrowRight: () => {
76
+ const parent = button.parentElement;
77
+ const editButton = parent?.querySelector('.edit-block');
78
+ if (editButton) {
79
+ editButton.focus();
80
+ }
81
+ },
82
+ },
63
83
  });
64
84
  return button;
65
85
  }
@@ -72,10 +92,24 @@ const EditableBlock = (Base) => {
72
92
  button.setAttribute('role', 'button');
73
93
  button.setAttribute('aria-label', 'Open menu');
74
94
  button.setAttribute('data-balloon-pos', 'down-left');
75
- button.addEventListener('mousedown', (event) => {
95
+ const handleClick = (event) => {
76
96
  event.preventDefault();
77
97
  const menu = this.createMenu();
78
98
  menu.showEditMenu(event.currentTarget);
99
+ };
100
+ button.addEventListener('mousedown', handleClick);
101
+ (0, navigation_utils_1.createKeyboardInteraction)({
102
+ container: button,
103
+ additionalKeys: {
104
+ Enter: handleClick,
105
+ ArrowLeft: () => {
106
+ const parent = button.parentElement;
107
+ const addButton = parent?.querySelector('.add-block');
108
+ if (addButton) {
109
+ addButton.focus();
110
+ }
111
+ },
112
+ },
79
113
  });
80
114
  return button;
81
115
  }
@@ -164,7 +164,7 @@ class EmbedView extends block_view_1.default {
164
164
  const href = this.node.attrs.href;
165
165
  let object;
166
166
  if (!href) {
167
- object = (0, media_1.createMediaPlaceholder)(media_1.MediaType.Media, this.view, this.getPos);
167
+ object = (0, media_1.createMediaPlaceholder)(media_1.MediaType.Media, this.view, this.getPos, this.props);
168
168
  }
169
169
  else if (this.isUploadedFile()) {
170
170
  const files = this.props.getFiles();
@@ -178,14 +178,14 @@ class EmbedView extends block_view_1.default {
178
178
  : (0, media_1.createUnsupportedFormat)(file.name, this.props.getCapabilities().editArticle);
179
179
  }
180
180
  else {
181
- object = (0, media_1.createMediaPlaceholder)(media_1.MediaType.Media, this.view, this.getPos);
181
+ object = (0, media_1.createMediaPlaceholder)(media_1.MediaType.Media, this.view, this.getPos, this.props);
182
182
  }
183
183
  }
184
184
  else if (this.isEmbedLink()) {
185
185
  object = await this.createEmbedPreview();
186
186
  }
187
187
  else {
188
- object = (0, media_1.createMediaPlaceholder)(media_1.MediaType.Media, this.view, this.getPos);
188
+ object = (0, media_1.createMediaPlaceholder)(media_1.MediaType.Media, this.view, this.getPos, this.props);
189
189
  }
190
190
  const can = this.props.getCapabilities();
191
191
  if (can.uploadFile && object.classList.contains('placeholder')) {
@@ -52,7 +52,7 @@ class FigureEditableView extends figure_1.FigureView {
52
52
  return img;
53
53
  };
54
54
  this.createPlaceholder = () => {
55
- return (0, media_1.createMediaPlaceholder)(media_1.MediaType.Figure);
55
+ return (0, media_1.createMediaPlaceholder)(media_1.MediaType.Figure, this.view, this.getPos, this.props);
56
56
  };
57
57
  }
58
58
  initialise() {
@@ -19,6 +19,7 @@ exports.FigureElementView = void 0;
19
19
  const transform_1 = require("@manuscripts/transform");
20
20
  const prosemirror_state_1 = require("prosemirror-state");
21
21
  const icons_1 = require("../icons");
22
+ const navigation_utils_1 = require("../lib/navigation-utils");
22
23
  const creators_1 = require("./creators");
23
24
  const image_element_1 = require("./image_element");
24
25
  class FigureElementView extends image_element_1.ImageElementView {
@@ -74,6 +75,8 @@ class FigureElementView extends image_element_1.ImageElementView {
74
75
  title: 'Add figure',
75
76
  });
76
77
  this.addFigureBtn.addEventListener('click', () => this.addFigure());
78
+ this.addFigureBtn.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(() => this.addFigure()));
79
+ this.addFigureBtn.tabIndex = 0;
77
80
  this.container.prepend(this.addFigureBtn);
78
81
  }
79
82
  }
@@ -31,15 +31,18 @@ const track_changes_utils_1 = require("../lib/track-changes-utils");
31
31
  const base_node_view_1 = require("./base_node_view");
32
32
  const creators_1 = require("./creators");
33
33
  const ReactSubView_1 = __importDefault(require("./ReactSubView"));
34
+ const navigation_utils_1 = require("../lib/navigation-utils");
34
35
  class FootnoteView extends base_node_view_1.BaseNodeView {
35
36
  constructor() {
36
37
  super(...arguments);
37
38
  this.initialise = () => {
38
39
  this.dom = document.createElement('div');
39
40
  this.dom.classList.add('footnote');
41
+ this.dom.tabIndex = 0;
40
42
  this.contentDOM = document.createElement('div');
41
43
  this.contentDOM.classList.add('footnote-text');
42
44
  this.dom.addEventListener('mousedown', this.handleClick);
45
+ this.dom.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(this.handleClick));
43
46
  this.updateContents();
44
47
  };
45
48
  this.handleClick = (event) => {
@@ -20,6 +20,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
21
  exports.HeroImageView = void 0;
22
22
  const icons_1 = require("../icons");
23
+ const navigation_utils_1 = require("../lib/navigation-utils");
23
24
  const block_view_1 = __importDefault(require("./block_view"));
24
25
  const creators_1 = require("./creators");
25
26
  class HeroImageView extends block_view_1.default {
@@ -48,13 +49,15 @@ class HeroImageView extends block_view_1.default {
48
49
  heroImageToggleBtn.classList.add('toggle-btn', 'button-reset');
49
50
  heroImageToggleBtn.innerHTML = icons_1.arrowUp;
50
51
  heroImageToggleBtn.classList.toggle('collapsed', this.collapsed);
51
- heroImageToggleBtn.onclick = () => {
52
+ const handleToggle = () => {
52
53
  this.collapsed = !this.collapsed;
53
54
  if (this.contentDOM) {
54
55
  this.contentDOM.style.display = this.collapsed ? 'none' : '';
55
56
  }
56
57
  heroImageToggleBtn.classList.toggle('collapsed', this.collapsed);
57
58
  };
59
+ heroImageToggleBtn.onclick = handleToggle;
60
+ heroImageToggleBtn.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(handleToggle));
58
61
  panel.appendChild(label);
59
62
  panel.appendChild(heroImageToggleBtn);
60
63
  return panel;
@@ -23,6 +23,7 @@ const style_guide_1 = require("@manuscripts/style-guide");
23
23
  const transform_1 = require("@manuscripts/transform");
24
24
  const icons_1 = require("../icons");
25
25
  const media_1 = require("../lib/media");
26
+ const navigation_utils_1 = require("../lib/navigation-utils");
26
27
  const position_menu_1 = require("../lib/position-menu");
27
28
  const block_view_1 = __importDefault(require("./block_view"));
28
29
  const creators_1 = require("./creators");
@@ -200,14 +201,16 @@ class ImageElementView extends block_view_1.default {
200
201
  label.innerText = 'Link';
201
202
  const container = document.createElement('div');
202
203
  container.classList.add('ext-link-editor-placeholder-container');
203
- const placeholder = (0, media_1.createMediaPlaceholder)(media_1.MediaType.ExternalLink);
204
+ const placeholder = (0, media_1.createMediaPlaceholder)(media_1.MediaType.ExternalLink, this.view, this.getPos, this.props);
204
205
  const closeButton = document.createElement('button');
205
206
  closeButton.classList.add('close-button');
206
207
  closeButton.setAttribute('aria-label', 'Close');
207
- closeButton.addEventListener('click', () => {
208
+ const handleClose = () => {
208
209
  this.setIsEditingExtLink(false);
209
210
  this.updateContents();
210
- });
211
+ };
212
+ closeButton.addEventListener('click', handleClose);
213
+ closeButton.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(handleClose));
211
214
  container.append(placeholder, closeButton);
212
215
  this.extLinkEditorContainer.append(label, container);
213
216
  if (can.uploadFile) {
@@ -222,10 +225,13 @@ class ImageElementView extends block_view_1.default {
222
225
  button.appendChild(buttonText);
223
226
  button.setAttribute('aria-label', 'Add linked file');
224
227
  button.classList.add('icon-button');
225
- button.addEventListener('click', () => {
228
+ button.tabIndex = 0;
229
+ const handleAdd = () => {
226
230
  this.setIsEditingExtLink(true);
227
231
  this.updateContents();
228
- });
232
+ };
233
+ button.addEventListener('click', handleAdd);
234
+ button.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(handleAdd));
229
235
  this.extLinkEditorContainer.appendChild(button);
230
236
  }
231
237
  createLinkedFile() {
@@ -240,10 +246,12 @@ class ImageElementView extends block_view_1.default {
240
246
  removeButton.classList.add('icon-button', 'remove-button');
241
247
  removeButton.setAttribute('aria-label', 'Remove link');
242
248
  removeButton.innerHTML = icons_1.deleteIcon;
243
- removeButton.addEventListener('click', () => {
249
+ const handleRemove = () => {
244
250
  this.isEditingExtLink = false;
245
251
  this.removeExtLink();
246
- });
252
+ };
253
+ removeButton.addEventListener('click', handleRemove);
254
+ removeButton.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(handleRemove));
247
255
  div.appendChild(removeButton);
248
256
  this.extLinkEditorContainer.appendChild(div);
249
257
  }
@@ -23,6 +23,7 @@ const style_guide_1 = require("@manuscripts/style-guide");
23
23
  const prosemirror_state_1 = require("prosemirror-state");
24
24
  const commands_1 = require("../commands");
25
25
  const FootnotesSelector_1 = require("../components/views/FootnotesSelector");
26
+ const navigation_utils_1 = require("../lib/navigation-utils");
26
27
  const footnotes_1 = require("../lib/footnotes");
27
28
  const track_changes_utils_1 = require("../lib/track-changes-utils");
28
29
  const base_node_view_1 = require("./base_node_view");
@@ -108,7 +109,9 @@ class InlineFootnoteView extends base_node_view_1.BaseNodeView {
108
109
  this.initialise = () => {
109
110
  this.dom = this.createDOM();
110
111
  this.dom.classList.add('footnote-marker');
112
+ this.dom.tabIndex = 0;
111
113
  this.dom.addEventListener('click', this.handleClick);
114
+ this.dom.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(() => this.handleClick()));
112
115
  this.updateContents();
113
116
  };
114
117
  this.selectNode = () => {
@@ -21,9 +21,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
21
21
  exports.KeywordView = void 0;
22
22
  const prosemirror_state_1 = require("prosemirror-state");
23
23
  const DeleteKeywordDialog_1 = require("../components/keywords/DeleteKeywordDialog");
24
+ const navigation_utils_1 = require("../lib/navigation-utils");
24
25
  const base_node_view_1 = require("./base_node_view");
25
26
  const creators_1 = require("./creators");
26
27
  const ReactSubView_1 = __importDefault(require("./ReactSubView"));
28
+ const track_changes_utils_1 = require("../lib/track-changes-utils");
27
29
  const deleteIcon = '<svg width="8px" height="8px" viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg">\n' +
28
30
  ' <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">\n' +
29
31
  ' <g fill="#6E6E6E">\n' +
@@ -42,6 +44,8 @@ class KeywordView extends base_node_view_1.BaseNodeView {
42
44
  this.createDOM = () => {
43
45
  this.dom = document.createElement('span');
44
46
  this.dom.classList.add('keyword');
47
+ this.dom.tabIndex = this.isFirstKeyword() ? 0 : -1;
48
+ this.dom.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(() => this.showConfirmationDialog()));
45
49
  this.contentDOM = document.createElement('span');
46
50
  };
47
51
  this.showConfirmationDialog = () => {
@@ -63,6 +67,17 @@ class KeywordView extends base_node_view_1.BaseNodeView {
63
67
  }
64
68
  };
65
69
  }
70
+ isFirstKeyword() {
71
+ const pos = this.getPos();
72
+ const parent = this.view.state.doc.resolve(pos).parent;
73
+ for (let i = 0; i < parent.childCount; i++) {
74
+ const child = parent.child(i);
75
+ if (!(0, track_changes_utils_1.isDeleted)(child)) {
76
+ return child === this.node;
77
+ }
78
+ }
79
+ return false;
80
+ }
66
81
  updateContents() {
67
82
  super.updateContents();
68
83
  this.dom.innerHTML = '';
@@ -20,6 +20,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
21
  exports.KeywordGroupView = void 0;
22
22
  const AddKeywordInline_1 = require("../components/keywords/AddKeywordInline");
23
+ const navigation_utils_1 = require("../lib/navigation-utils");
24
+ const track_changes_utils_1 = require("../lib/track-changes-utils");
23
25
  const block_view_1 = __importDefault(require("./block_view"));
24
26
  const creators_1 = require("./creators");
25
27
  const ReactSubView_1 = __importDefault(require("./ReactSubView"));
@@ -36,6 +38,13 @@ class KeywordGroupView extends block_view_1.default {
36
38
  this.contentDOM.setAttribute('id', this.node.attrs.id);
37
39
  this.contentDOM.setAttribute('contenteditable', 'false');
38
40
  this.element.appendChild(this.contentDOM);
41
+ this.removeKeydownListener = (0, navigation_utils_1.createKeyboardInteraction)({
42
+ container: this.element,
43
+ navigation: {
44
+ getItems: () => Array.from(this.element.querySelectorAll('.keyword:not(.deleted), .keyword-add')),
45
+ arrowKeys: { forward: 'ArrowRight', backward: 'ArrowLeft' },
46
+ },
47
+ });
39
48
  if (this.props.getCapabilities().editArticle) {
40
49
  this.addingTools = (0, ReactSubView_1.default)(this.props, AddKeywordInline_1.AddKeywordInline, { getUpdatedNode: () => this.node }, this.node, this.getPos, this.view, ['keywords-editor']);
41
50
  }
@@ -44,6 +53,35 @@ class KeywordGroupView extends block_view_1.default {
44
53
  }
45
54
  };
46
55
  }
56
+ updateContents() {
57
+ super.updateContents();
58
+ this.setKeywordsTabIndices();
59
+ }
60
+ setKeywordsTabIndices() {
61
+ const container = this.contentDOM;
62
+ if (!container) {
63
+ return;
64
+ }
65
+ let firstFocusableFound = false;
66
+ for (let i = 0; i < this.node.childCount; i++) {
67
+ const child = this.node.child(i);
68
+ const keyword = container.querySelector(`.keyword[id="${child.attrs.id}"]`);
69
+ if (!keyword) {
70
+ continue;
71
+ }
72
+ if (!(0, track_changes_utils_1.isDeleted)(child) && !firstFocusableFound) {
73
+ keyword.tabIndex = 0;
74
+ firstFocusableFound = true;
75
+ }
76
+ else {
77
+ keyword.tabIndex = -1;
78
+ }
79
+ }
80
+ }
81
+ destroy() {
82
+ this.removeKeydownListener?.();
83
+ super.destroy();
84
+ }
47
85
  }
48
86
  exports.KeywordGroupView = KeywordGroupView;
49
87
  exports.default = (0, creators_1.createNodeView)(KeywordGroupView);
@@ -26,6 +26,7 @@ class QuoteImageEditableView extends figure_editable_1.FigureEditableView {
26
26
  this.createPlaceholder = () => {
27
27
  const element = document.createElement('div');
28
28
  element.classList.add('figure', 'placeholder');
29
+ element.tabIndex = 0;
29
30
  const instructions = document.createElement('div');
30
31
  instructions.classList.add('instructions');
31
32
  instructions.innerHTML = `${icons_1.plusIcon}<div>Drag or click here to upload image</div>`;
@@ -20,6 +20,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
21
  exports.SupplementsView = void 0;
22
22
  const icons_1 = require("../icons");
23
+ const navigation_utils_1 = require("../lib/navigation-utils");
23
24
  const block_view_1 = __importDefault(require("./block_view"));
24
25
  const creators_1 = require("./creators");
25
26
  class SupplementsView extends block_view_1.default {
@@ -31,11 +32,13 @@ class SupplementsView extends block_view_1.default {
31
32
  this.toggleButton = document.createElement('button');
32
33
  this.toggleButton.classList.add('supplements-toggle-btn', 'button-reset');
33
34
  this.toggleButton.innerHTML = icons_1.arrowUp;
34
- this.toggleButton.onclick = () => {
35
+ const handleToggle = () => {
35
36
  this.collapsed = !this.collapsed;
36
37
  this.toggleContent();
37
38
  this.toggleButton?.classList.toggle('collapsed', this.collapsed);
38
39
  };
40
+ this.toggleButton.onclick = handleToggle;
41
+ this.toggleButton.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(handleToggle));
39
42
  this.contentDOM = document.createElement('div');
40
43
  this.contentDOM.classList.add('supplements-content');
41
44
  this.contentDOM.classList.add('block');
@@ -34,6 +34,7 @@ import { setCommentSelection } from './plugins/comments';
34
34
  import { getEditorProps } from './plugins/editor-props';
35
35
  import { searchReplaceKey } from './plugins/search-replace';
36
36
  import { checkForCompletion } from './plugins/section_title/autocompletion';
37
+ import { persistentCursor } from './plugins/persistent-cursor';
37
38
  export const addToStart = (state, dispatch) => {
38
39
  const { selection } = state;
39
40
  const props = getEditorProps(state);
@@ -1296,10 +1297,12 @@ export const ignoreEnterInSubtitles = (state) => {
1296
1297
  }
1297
1298
  return false;
1298
1299
  };
1299
- export const exitEditorToContainer = () => {
1300
+ export const exitEditorToContainer = (state, dispatch, view) => {
1300
1301
  const editorContainer = document.getElementById('editor');
1301
- if (editorContainer) {
1302
+ if (editorContainer && dispatch && view) {
1302
1303
  editorContainer.focus();
1304
+ const tr = view.state.tr.setMeta(persistentCursor, { on: true });
1305
+ view.dispatch(tr);
1303
1306
  return true;
1304
1307
  }
1305
1308
  return false;
@@ -28,6 +28,12 @@ const NewKeywordButton = styled.button `
28
28
  margin: 0;
29
29
  padding: 0;
30
30
  cursor: pointer;
31
+
32
+ &:focus-visible {
33
+ outline: 4px solid ${(props) => props.theme.colors.outline.focus};
34
+ outline-offset: 2px;
35
+ border-radius: 3px;
36
+ }
31
37
  `;
32
38
  const CreateKeywordButtonWrapper = styled.div `
33
39
  position: absolute;
@@ -157,8 +163,13 @@ export const AddKeywordInline = ({ viewProps, getUpdatedNode }) => {
157
163
  },
158
164
  };
159
165
  return (React.createElement(AddNewKeyword, { ref: nodeRef },
160
- !isAddingNewKeyword && (React.createElement(NewKeywordButton, { onClick: () => {
166
+ !isAddingNewKeyword && (React.createElement(NewKeywordButton, { tabIndex: -1, className: "keyword-add", onClick: () => {
161
167
  setIsAddingNewKeyword(true);
168
+ }, onKeyDown: (e) => {
169
+ if (e.key === 'Enter') {
170
+ e.preventDefault();
171
+ setIsAddingNewKeyword(true);
172
+ }
162
173
  } }, "New keyword...")),
163
174
  isAddingNewKeyword && React.createElement(KeywordInput, null),
164
175
  isAddingNewKeyword && isValidNewKeyword() && (React.createElement(CreateKeywordButtonElement, null)),