@atlaskit/editor-common 74.29.3 → 74.31.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 (223) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/i18n/cs.js +19 -0
  3. package/dist/cjs/i18n/da.js +19 -0
  4. package/dist/cjs/i18n/de.js +19 -0
  5. package/dist/cjs/i18n/es.js +19 -0
  6. package/dist/cjs/i18n/fi.js +19 -0
  7. package/dist/cjs/i18n/fr.js +19 -0
  8. package/dist/cjs/i18n/hu.js +19 -0
  9. package/dist/cjs/i18n/it.js +19 -0
  10. package/dist/cjs/i18n/ja.js +19 -0
  11. package/dist/cjs/i18n/ko.js +19 -0
  12. package/dist/cjs/i18n/nb.js +19 -0
  13. package/dist/cjs/i18n/nl.js +19 -0
  14. package/dist/cjs/i18n/pl.js +19 -0
  15. package/dist/cjs/i18n/pt_BR.js +19 -0
  16. package/dist/cjs/i18n/ru.js +19 -0
  17. package/dist/cjs/i18n/sv.js +19 -0
  18. package/dist/cjs/i18n/th.js +19 -0
  19. package/dist/cjs/i18n/tr.js +19 -0
  20. package/dist/cjs/i18n/uk.js +19 -0
  21. package/dist/cjs/i18n/vi.js +19 -0
  22. package/dist/cjs/i18n/zh.js +19 -0
  23. package/dist/cjs/i18n/zh_TW.js +19 -0
  24. package/dist/cjs/lists/analytics.js +40 -0
  25. package/dist/cjs/lists/indentation.js +24 -0
  26. package/dist/cjs/lists/index.js +89 -0
  27. package/dist/cjs/lists/node.js +97 -0
  28. package/dist/cjs/lists/replace-content.js +24 -0
  29. package/dist/cjs/lists/selection.js +59 -0
  30. package/dist/cjs/mark/commands.js +201 -0
  31. package/dist/cjs/mark/index.js +30 -0
  32. package/dist/cjs/messages/full-page.js +25 -0
  33. package/dist/cjs/messages/index.js +7 -0
  34. package/dist/cjs/monitoring/error.js +1 -1
  35. package/dist/cjs/node-width/index.js +10 -2
  36. package/dist/cjs/ui/DropList/index.js +1 -1
  37. package/dist/cjs/ui/Toolbar/index.js +8 -0
  38. package/dist/cjs/ui/index.js +7 -0
  39. package/dist/cjs/ui-menu/DropdownMenu/index.js +16 -2
  40. package/dist/cjs/ui-menu/ToolbarArrowKeyNavigationProvider/index.js +219 -0
  41. package/dist/cjs/ui-menu/index.js +23 -4
  42. package/dist/cjs/utils/commands.js +110 -2
  43. package/dist/cjs/utils/document.js +26 -1
  44. package/dist/cjs/utils/index.js +51 -2
  45. package/dist/cjs/utils/prosemirror/autojoin.js +68 -0
  46. package/dist/cjs/version.json +1 -1
  47. package/dist/es2019/i18n/cs.js +19 -0
  48. package/dist/es2019/i18n/da.js +19 -0
  49. package/dist/es2019/i18n/de.js +19 -0
  50. package/dist/es2019/i18n/es.js +19 -0
  51. package/dist/es2019/i18n/fi.js +19 -0
  52. package/dist/es2019/i18n/fr.js +19 -0
  53. package/dist/es2019/i18n/hu.js +19 -0
  54. package/dist/es2019/i18n/it.js +19 -0
  55. package/dist/es2019/i18n/ja.js +19 -0
  56. package/dist/es2019/i18n/ko.js +19 -0
  57. package/dist/es2019/i18n/nb.js +19 -0
  58. package/dist/es2019/i18n/nl.js +19 -0
  59. package/dist/es2019/i18n/pl.js +19 -0
  60. package/dist/es2019/i18n/pt_BR.js +19 -0
  61. package/dist/es2019/i18n/ru.js +19 -0
  62. package/dist/es2019/i18n/sv.js +19 -0
  63. package/dist/es2019/i18n/th.js +19 -0
  64. package/dist/es2019/i18n/tr.js +19 -0
  65. package/dist/es2019/i18n/uk.js +19 -0
  66. package/dist/es2019/i18n/vi.js +19 -0
  67. package/dist/es2019/i18n/zh.js +19 -0
  68. package/dist/es2019/i18n/zh_TW.js +19 -0
  69. package/dist/es2019/lists/analytics.js +36 -0
  70. package/dist/es2019/lists/indentation.js +18 -0
  71. package/dist/es2019/lists/index.js +6 -0
  72. package/dist/es2019/lists/node.js +97 -0
  73. package/dist/es2019/lists/replace-content.js +18 -0
  74. package/dist/es2019/lists/selection.js +53 -0
  75. package/dist/es2019/mark/commands.js +205 -0
  76. package/dist/es2019/mark/index.js +1 -0
  77. package/dist/es2019/messages/full-page.js +18 -0
  78. package/dist/es2019/messages/index.js +1 -0
  79. package/dist/es2019/monitoring/error.js +1 -1
  80. package/dist/es2019/node-width/index.js +7 -0
  81. package/dist/es2019/ui/DropList/index.js +1 -1
  82. package/dist/es2019/ui/Toolbar/index.js +1 -0
  83. package/dist/es2019/ui/index.js +2 -1
  84. package/dist/es2019/ui-menu/DropdownMenu/index.js +16 -2
  85. package/dist/es2019/ui-menu/ToolbarArrowKeyNavigationProvider/index.js +209 -0
  86. package/dist/es2019/ui-menu/index.js +5 -4
  87. package/dist/es2019/utils/commands.js +106 -2
  88. package/dist/es2019/utils/document.js +25 -1
  89. package/dist/es2019/utils/index.js +3 -2
  90. package/dist/es2019/utils/prosemirror/autojoin.js +57 -0
  91. package/dist/es2019/version.json +1 -1
  92. package/dist/esm/i18n/cs.js +19 -0
  93. package/dist/esm/i18n/da.js +19 -0
  94. package/dist/esm/i18n/de.js +19 -0
  95. package/dist/esm/i18n/es.js +19 -0
  96. package/dist/esm/i18n/fi.js +19 -0
  97. package/dist/esm/i18n/fr.js +19 -0
  98. package/dist/esm/i18n/hu.js +19 -0
  99. package/dist/esm/i18n/it.js +19 -0
  100. package/dist/esm/i18n/ja.js +19 -0
  101. package/dist/esm/i18n/ko.js +19 -0
  102. package/dist/esm/i18n/nb.js +19 -0
  103. package/dist/esm/i18n/nl.js +19 -0
  104. package/dist/esm/i18n/pl.js +19 -0
  105. package/dist/esm/i18n/pt_BR.js +19 -0
  106. package/dist/esm/i18n/ru.js +19 -0
  107. package/dist/esm/i18n/sv.js +19 -0
  108. package/dist/esm/i18n/th.js +19 -0
  109. package/dist/esm/i18n/tr.js +19 -0
  110. package/dist/esm/i18n/uk.js +19 -0
  111. package/dist/esm/i18n/vi.js +19 -0
  112. package/dist/esm/i18n/zh.js +19 -0
  113. package/dist/esm/i18n/zh_TW.js +19 -0
  114. package/dist/esm/lists/analytics.js +32 -0
  115. package/dist/esm/lists/indentation.js +17 -0
  116. package/dist/esm/lists/index.js +6 -0
  117. package/dist/esm/lists/node.js +87 -0
  118. package/dist/esm/lists/replace-content.js +17 -0
  119. package/dist/esm/lists/selection.js +50 -0
  120. package/dist/esm/mark/commands.js +190 -0
  121. package/dist/esm/mark/index.js +1 -0
  122. package/dist/esm/messages/full-page.js +18 -0
  123. package/dist/esm/messages/index.js +1 -0
  124. package/dist/esm/monitoring/error.js +1 -1
  125. package/dist/esm/node-width/index.js +7 -0
  126. package/dist/esm/ui/DropList/index.js +1 -1
  127. package/dist/esm/ui/Toolbar/index.js +1 -0
  128. package/dist/esm/ui/index.js +2 -1
  129. package/dist/esm/ui-menu/DropdownMenu/index.js +15 -2
  130. package/dist/esm/ui-menu/ToolbarArrowKeyNavigationProvider/index.js +207 -0
  131. package/dist/esm/ui-menu/index.js +5 -4
  132. package/dist/esm/utils/commands.js +104 -2
  133. package/dist/esm/utils/document.js +25 -1
  134. package/dist/esm/utils/index.js +3 -2
  135. package/dist/esm/utils/prosemirror/autojoin.js +63 -0
  136. package/dist/esm/version.json +1 -1
  137. package/dist/types/i18n/cs.d.ts +19 -0
  138. package/dist/types/i18n/da.d.ts +19 -0
  139. package/dist/types/i18n/de.d.ts +19 -0
  140. package/dist/types/i18n/es.d.ts +19 -0
  141. package/dist/types/i18n/fi.d.ts +19 -0
  142. package/dist/types/i18n/fr.d.ts +19 -0
  143. package/dist/types/i18n/hu.d.ts +19 -0
  144. package/dist/types/i18n/it.d.ts +19 -0
  145. package/dist/types/i18n/ja.d.ts +19 -0
  146. package/dist/types/i18n/ko.d.ts +19 -0
  147. package/dist/types/i18n/nb.d.ts +19 -0
  148. package/dist/types/i18n/nl.d.ts +19 -0
  149. package/dist/types/i18n/pl.d.ts +19 -0
  150. package/dist/types/i18n/pt_BR.d.ts +19 -0
  151. package/dist/types/i18n/ru.d.ts +19 -0
  152. package/dist/types/i18n/sv.d.ts +19 -0
  153. package/dist/types/i18n/th.d.ts +19 -0
  154. package/dist/types/i18n/tr.d.ts +19 -0
  155. package/dist/types/i18n/uk.d.ts +19 -0
  156. package/dist/types/i18n/vi.d.ts +19 -0
  157. package/dist/types/i18n/zh.d.ts +19 -0
  158. package/dist/types/i18n/zh_TW.d.ts +19 -0
  159. package/dist/types/lists/analytics.d.ts +4 -0
  160. package/dist/types/lists/indentation.d.ts +5 -0
  161. package/dist/types/lists/index.d.ts +6 -0
  162. package/dist/types/lists/node.d.ts +18 -0
  163. package/dist/types/lists/replace-content.d.ts +8 -0
  164. package/dist/types/lists/selection.d.ts +13 -0
  165. package/dist/types/mark/commands.d.ts +18 -0
  166. package/dist/types/mark/index.d.ts +1 -0
  167. package/dist/types/messages/full-page.d.ts +17 -0
  168. package/dist/types/messages/index.d.ts +1 -0
  169. package/dist/types/node-width/index.d.ts +1 -0
  170. package/dist/types/ui/Toolbar/index.d.ts +5 -0
  171. package/dist/types/ui/index.d.ts +2 -0
  172. package/dist/types/ui-menu/DropdownMenu/index.d.ts +2 -1
  173. package/dist/types/ui-menu/ToolbarArrowKeyNavigationProvider/index.d.ts +30 -0
  174. package/dist/types/ui-menu/index.d.ts +7 -6
  175. package/dist/types/utils/commands.d.ts +36 -2
  176. package/dist/types/utils/document.d.ts +4 -0
  177. package/dist/types/utils/index.d.ts +4 -2
  178. package/dist/types/utils/prosemirror/autojoin.d.ts +13 -0
  179. package/dist/types-ts4.5/i18n/cs.d.ts +19 -0
  180. package/dist/types-ts4.5/i18n/da.d.ts +19 -0
  181. package/dist/types-ts4.5/i18n/de.d.ts +19 -0
  182. package/dist/types-ts4.5/i18n/es.d.ts +19 -0
  183. package/dist/types-ts4.5/i18n/fi.d.ts +19 -0
  184. package/dist/types-ts4.5/i18n/fr.d.ts +19 -0
  185. package/dist/types-ts4.5/i18n/hu.d.ts +19 -0
  186. package/dist/types-ts4.5/i18n/it.d.ts +19 -0
  187. package/dist/types-ts4.5/i18n/ja.d.ts +19 -0
  188. package/dist/types-ts4.5/i18n/ko.d.ts +19 -0
  189. package/dist/types-ts4.5/i18n/nb.d.ts +19 -0
  190. package/dist/types-ts4.5/i18n/nl.d.ts +19 -0
  191. package/dist/types-ts4.5/i18n/pl.d.ts +19 -0
  192. package/dist/types-ts4.5/i18n/pt_BR.d.ts +19 -0
  193. package/dist/types-ts4.5/i18n/ru.d.ts +19 -0
  194. package/dist/types-ts4.5/i18n/sv.d.ts +19 -0
  195. package/dist/types-ts4.5/i18n/th.d.ts +19 -0
  196. package/dist/types-ts4.5/i18n/tr.d.ts +19 -0
  197. package/dist/types-ts4.5/i18n/uk.d.ts +19 -0
  198. package/dist/types-ts4.5/i18n/vi.d.ts +19 -0
  199. package/dist/types-ts4.5/i18n/zh.d.ts +19 -0
  200. package/dist/types-ts4.5/i18n/zh_TW.d.ts +19 -0
  201. package/dist/types-ts4.5/lists/analytics.d.ts +4 -0
  202. package/dist/types-ts4.5/lists/indentation.d.ts +5 -0
  203. package/dist/types-ts4.5/lists/index.d.ts +6 -0
  204. package/dist/types-ts4.5/lists/node.d.ts +18 -0
  205. package/dist/types-ts4.5/lists/replace-content.d.ts +8 -0
  206. package/dist/types-ts4.5/lists/selection.d.ts +13 -0
  207. package/dist/types-ts4.5/mark/commands.d.ts +18 -0
  208. package/dist/types-ts4.5/mark/index.d.ts +1 -0
  209. package/dist/types-ts4.5/messages/full-page.d.ts +17 -0
  210. package/dist/types-ts4.5/messages/index.d.ts +1 -0
  211. package/dist/types-ts4.5/node-width/index.d.ts +1 -0
  212. package/dist/types-ts4.5/ui/Toolbar/index.d.ts +5 -0
  213. package/dist/types-ts4.5/ui/index.d.ts +2 -0
  214. package/dist/types-ts4.5/ui-menu/DropdownMenu/index.d.ts +2 -1
  215. package/dist/types-ts4.5/ui-menu/ToolbarArrowKeyNavigationProvider/index.d.ts +30 -0
  216. package/dist/types-ts4.5/ui-menu/index.d.ts +7 -6
  217. package/dist/types-ts4.5/utils/commands.d.ts +42 -2
  218. package/dist/types-ts4.5/utils/document.d.ts +4 -0
  219. package/dist/types-ts4.5/utils/index.d.ts +4 -2
  220. package/dist/types-ts4.5/utils/prosemirror/autojoin.d.ts +13 -0
  221. package/lists/package.json +15 -0
  222. package/mark/package.json +15 -0
  223. package/package.json +6 -3
@@ -0,0 +1,205 @@
1
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
2
+ // eslint-disable-next-line no-duplicate-imports
3
+
4
+ import { CellSelection } from '@atlaskit/editor-tables/cell-selection';
5
+ const SMART_TO_ASCII = {
6
+ '…': '...',
7
+ '→': '->',
8
+ '←': '<-',
9
+ '–': '--',
10
+ '“': '"',
11
+ '”': '"',
12
+ '‘': "'",
13
+ '’': "'"
14
+ };
15
+ const FIND_SMART_CHAR = new RegExp(`[${Object.keys(SMART_TO_ASCII).join('')}]`, 'g');
16
+ const isNodeTextBlock = schema => {
17
+ const {
18
+ mention,
19
+ text,
20
+ emoji
21
+ } = schema.nodes;
22
+ return (node, _, parent) => {
23
+ if (node.type === mention || node.type === emoji || node.type === text) {
24
+ return parent === null || parent === void 0 ? void 0 : parent.isTextblock;
25
+ }
26
+ return;
27
+ };
28
+ };
29
+ const replaceSmartCharsToAscii = (position, textContent, tr) => {
30
+ const {
31
+ schema
32
+ } = tr.doc.type;
33
+ let match;
34
+ while (match = FIND_SMART_CHAR.exec(textContent)) {
35
+ const {
36
+ 0: smartChar,
37
+ index: offset
38
+ } = match;
39
+ const replacePos = tr.mapping.map(position + offset);
40
+ const replacementText = schema.text(SMART_TO_ASCII[smartChar]);
41
+ tr.replaceWith(replacePos, replacePos + smartChar.length, replacementText);
42
+ }
43
+ };
44
+ const replaceMentionOrEmojiForTextContent = (position, nodeSize, textContent, tr) => {
45
+ const currentPos = tr.mapping.map(position);
46
+ const {
47
+ schema
48
+ } = tr.doc.type;
49
+ tr.replaceWith(currentPos, currentPos + nodeSize, schema.text(textContent));
50
+ };
51
+ export function filterChildrenBetween(doc, from, to, predicate) {
52
+ const results = [];
53
+ doc.nodesBetween(from, to, (node, pos, parent) => {
54
+ if (predicate(node, pos, parent)) {
55
+ results.push({
56
+ node,
57
+ pos
58
+ });
59
+ }
60
+ });
61
+ return results;
62
+ }
63
+ export const transformSmartCharsMentionsAndEmojis = (from, to, tr) => {
64
+ const {
65
+ schema
66
+ } = tr.doc.type;
67
+ const {
68
+ mention,
69
+ text,
70
+ emoji
71
+ } = schema.nodes;
72
+ // Traverse through all the nodes within the range and replace them with their plaintext counterpart
73
+ const children = filterChildrenBetween(tr.doc, from, to, isNodeTextBlock(schema));
74
+ children.forEach(({
75
+ node,
76
+ pos
77
+ }) => {
78
+ if (node.type === mention || node.type === emoji) {
79
+ // Convert gracefully when no text found, ProseMirror will blow up if you try to create a node with an empty string or undefined
80
+ let replacementText = node.attrs.text;
81
+ if (typeof replacementText === 'undefined' || replacementText === '') {
82
+ replacementText = `${node.type.name} text missing`;
83
+ }
84
+ replaceMentionOrEmojiForTextContent(pos, node.nodeSize, replacementText, tr);
85
+ } else if (node.type === text && node.text) {
86
+ const replacePosition = pos > from ? pos : from;
87
+ const textToReplace = pos > from ? node.text : node.text.substr(from - pos);
88
+ replaceSmartCharsToAscii(replacePosition, textToReplace, tr);
89
+ }
90
+ });
91
+ };
92
+ export const applyMarkOnRange = (from, to, removeMark, mark, tr) => {
93
+ const {
94
+ schema
95
+ } = tr.doc.type;
96
+ const {
97
+ code
98
+ } = schema.marks;
99
+ if (mark.type === code) {
100
+ transformSmartCharsMentionsAndEmojis(from, to, tr);
101
+ }
102
+ tr.doc.nodesBetween(tr.mapping.map(from), tr.mapping.map(to), (node, pos) => {
103
+ if (!node.isText) {
104
+ return true;
105
+ }
106
+
107
+ // This is an issue when the user selects some text.
108
+ // We need to check if the current node position is less than the range selection from.
109
+ // If it’s true, that means we should apply the mark using the range selection,
110
+ // not the current node position.
111
+ const nodeBetweenFrom = Math.max(pos, tr.mapping.map(from));
112
+ const nodeBetweenTo = Math.min(pos + node.nodeSize, tr.mapping.map(to));
113
+ if (removeMark) {
114
+ tr.removeMark(nodeBetweenFrom, nodeBetweenTo, mark);
115
+ } else {
116
+ tr.addMark(nodeBetweenFrom, nodeBetweenTo, mark);
117
+ }
118
+ return true;
119
+ });
120
+ return tr;
121
+ };
122
+ const entireSelectionContainsMark = (mark, doc, fromPos, toPos) => {
123
+ let onlyContainsMark = true;
124
+ doc.nodesBetween(fromPos, toPos, node => {
125
+ // Skip recursion once we've found text which doesn't include the mark
126
+ if (!onlyContainsMark) {
127
+ return false;
128
+ }
129
+ if (node.isText) {
130
+ onlyContainsMark && (onlyContainsMark = mark.isInSet(node.marks));
131
+ }
132
+ });
133
+ return onlyContainsMark;
134
+ };
135
+ const toggleMarkInRange = mark => (state, dispatch) => {
136
+ const {
137
+ tr
138
+ } = state;
139
+ if (state.selection instanceof CellSelection) {
140
+ let removeMark = true;
141
+ const cells = [];
142
+ state.selection.forEachCell((cell, cellPos) => {
143
+ cells.push({
144
+ node: cell,
145
+ pos: cellPos
146
+ });
147
+ const from = cellPos;
148
+ const to = cellPos + cell.nodeSize;
149
+ removeMark && (removeMark = entireSelectionContainsMark(mark, state.doc, from, to));
150
+ });
151
+ for (let i = cells.length - 1; i >= 0; i--) {
152
+ const cell = cells[i];
153
+ const from = cell.pos;
154
+ const to = from + cell.node.nodeSize;
155
+ applyMarkOnRange(from, to, removeMark, mark, tr);
156
+ }
157
+ } else {
158
+ const {
159
+ $from,
160
+ $to
161
+ } = state.selection;
162
+ // We decide to remove the mark only if the entire selection contains the mark
163
+ // Examples with *bold* text
164
+ // Scenario 1: Selection contains both bold and non-bold text -> bold entire selection
165
+ // Scenario 2: Selection contains only bold text -> un-bold entire selection
166
+ // Scenario 3: Selection contains no bold text -> bold entire selection
167
+ const removeMark = entireSelectionContainsMark(mark, state.doc, $from.pos, $to.pos);
168
+ applyMarkOnRange($from.pos, $to.pos, removeMark, mark, tr);
169
+ }
170
+ if (tr.docChanged) {
171
+ if (dispatch) {
172
+ dispatch(tr);
173
+ }
174
+ return true;
175
+ }
176
+ return false;
177
+ };
178
+
179
+ /**
180
+ * A wrapper over the default toggleMark, except when we have a selection
181
+ * we only toggle marks on text nodes rather than inline nodes.
182
+ * @param markType
183
+ * @param attrs
184
+ */
185
+ export const toggleMark = (markType, attrs) => (state, dispatch) => {
186
+ const mark = markType.create(attrs);
187
+
188
+ // For cursor selections we can use the default behaviour.
189
+ if (state.selection instanceof TextSelection && state.selection.$cursor) {
190
+ const {
191
+ tr
192
+ } = state;
193
+ if (mark.isInSet(state.storedMarks || state.selection.$cursor.marks())) {
194
+ tr.removeStoredMark(mark);
195
+ } else {
196
+ tr.addStoredMark(mark);
197
+ }
198
+ if (dispatch) {
199
+ dispatch(tr);
200
+ return true;
201
+ }
202
+ return false;
203
+ }
204
+ return toggleMarkInRange(mark)(state, dispatch);
205
+ };
@@ -0,0 +1 @@
1
+ export { transformSmartCharsMentionsAndEmojis, applyMarkOnRange, toggleMark, filterChildrenBetween } from './commands';
@@ -0,0 +1,18 @@
1
+ import { defineMessages } from 'react-intl-next';
2
+ export const messages = defineMessages({
3
+ toolbarLabel: {
4
+ id: 'fabric.editor.toolbarLabel',
5
+ defaultMessage: 'Editor toolbar',
6
+ description: 'Label for the ARIA region landmark'
7
+ },
8
+ pageActionsLabel: {
9
+ id: 'fabric.editor.pageActionsLabel',
10
+ defaultMessage: 'Page actions',
11
+ description: 'Label for the ARIA region landmark'
12
+ },
13
+ editableContentLabel: {
14
+ id: 'fabric.editor.editableContentLabel',
15
+ defaultMessage: 'Editable content',
16
+ description: 'Label for the ARIA region landmark'
17
+ }
18
+ });
@@ -7,6 +7,7 @@ export { codeBlockButtonMessages } from './codeBlockButton';
7
7
  export { toolbarInsertBlockMessages } from './insert-block';
8
8
  export { toolbarMessages as mediaAndEmbedToolbarMessages } from './media-and-embed-toolbar';
9
9
  export { messages as cardMessages } from './card';
10
+ export { messages as fullPageMessages } from './full-page';
10
11
  export default defineMessages({
11
12
  layoutFixedWidth: {
12
13
  id: 'fabric.editor.layoutFixedWidth',
@@ -1,6 +1,6 @@
1
1
  const SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
2
2
  const packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
3
- const packageVersion = "74.29.3";
3
+ const packageVersion = "74.31.0";
4
4
  const sanitiseSentryEvents = (data, _hint) => {
5
5
  // Remove URL as it has UGC
6
6
  // TODO: Sanitise the URL instead of just removing it
@@ -102,4 +102,11 @@ export const getTableContainerWidth = node => {
102
102
  return node.attrs.width;
103
103
  }
104
104
  return layoutToWidth[node.attrs.layout];
105
+ };
106
+ export const getTableWidthWithNumberColumn = (node, offset) => {
107
+ const isNumberColumnEnabled = node.attrs.isNumberColumnEnabled;
108
+ if (isNumberColumnEnabled && offset > 0) {
109
+ return getTableContainerWidth(node) - offset;
110
+ }
111
+ return getTableContainerWidth(node);
105
112
  };
@@ -8,7 +8,7 @@ import { themed } from '@atlaskit/theme/components';
8
8
  import { borderRadius } from '@atlaskit/theme/constants';
9
9
  import Layer from '../Layer';
10
10
  const packageName = "@atlaskit/editor-common";
11
- const packageVersion = "74.29.3";
11
+ const packageVersion = "74.31.0";
12
12
  const halfFocusRing = 1;
13
13
  const dropOffset = '0, 8';
14
14
  class DropList extends Component {
@@ -0,0 +1 @@
1
+ export const EDIT_AREA_ID = 'ak-editor-textarea';
@@ -25,4 +25,5 @@ export { snapTo, handleSides, imageAlignmentMap } from './ResizerLegacy/utils';
25
25
  export { wrapperStyle } from './ResizerLegacy/styled';
26
26
  export { panelTextInput } from './PanelTextInput/styles';
27
27
  export { default as PanelTextInput } from './PanelTextInput';
28
- export { default as Announcer } from './Announcer/announcer';
28
+ export { default as Announcer } from './Announcer/announcer';
29
+ export { EDIT_AREA_ID } from './Toolbar';
@@ -1,7 +1,7 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
3
  /** @jsx jsx */
4
- import React, { PureComponent } from 'react';
4
+ import React, { PureComponent, useContext } from 'react';
5
5
  import { css, jsx } from '@emotion/react';
6
6
  import { akEditorFloatingPanelZIndex } from '@atlaskit/editor-shared-styles';
7
7
  import { CustomItem, MenuGroup } from '@atlaskit/menu';
@@ -10,6 +10,7 @@ import { B100, DN600, DN80, N70, N900 } from '@atlaskit/theme/colors';
10
10
  import { themed } from '@atlaskit/theme/components';
11
11
  import Tooltip from '@atlaskit/tooltip';
12
12
  import { DropdownMenuSharedCssClassName } from '../../styles';
13
+ import { KeyDownHandlerContext } from '../../ui-menu/ToolbarArrowKeyNavigationProvider';
13
14
  import { withReactEditorViewOuterListeners } from '../../ui-react';
14
15
  import DropList from '../../ui/DropList';
15
16
  import Popup from '../../ui/Popup';
@@ -319,4 +320,17 @@ function DropdownMenuItem({
319
320
  }, dropListItem);
320
321
  }
321
322
  return dropListItem;
322
- }
323
+ }
324
+ export const DropdownMenuWithKeyboardNavigation = /*#__PURE__*/React.memo(({
325
+ ...props
326
+ }) => {
327
+ const keyDownHandlerContext = useContext(KeyDownHandlerContext);
328
+ //This context is to handle the tab, Arrow Right/Left key events for dropdown.
329
+ //Default context has the void callbacks for above key events
330
+ return jsx(DropdownMenuWrapper, _extends({
331
+ arrowKeyNavigationProviderOptions: {
332
+ ...props.arrowKeyNavigationProviderOptions,
333
+ keyDownHandlerContext
334
+ }
335
+ }, props));
336
+ });
@@ -0,0 +1,209 @@
1
+ /** @jsx jsx */
2
+ /* eslint-disable no-console */
3
+ import React, { useCallback, useLayoutEffect, useRef } from 'react';
4
+ import { css, jsx } from '@emotion/react';
5
+ import { fullPageMessages as messages } from '../../messages';
6
+ import { EDIT_AREA_ID } from '../../ui';
7
+ /*
8
+ ** The context is used to handle the keydown events of submenus.
9
+ ** Because the keyboard navigation is explicitly managed for main toolbar items
10
+ ** Few key presses such as Tab,Arrow Right/Left need ot be handled here via context
11
+ */
12
+ export const KeyDownHandlerContext = /*#__PURE__*/React.createContext({
13
+ handleArrowLeft: () => {},
14
+ handleArrowRight: () => {},
15
+ handleTab: () => {}
16
+ });
17
+ const centeredToolbarContainer = css`
18
+ display: flex;
19
+ width: 100%;
20
+ align-items: center;
21
+ `;
22
+
23
+ /**
24
+ * This component is a wrapper of main toolbar which listens to keydown events of children
25
+ * and handles left/right arrow key navigation for all focusable elements
26
+ * @param
27
+ * @returns
28
+ */
29
+ export const ToolbarArrowKeyNavigationProvider = ({
30
+ children,
31
+ editorView,
32
+ childComponentSelector,
33
+ handleEscape,
34
+ disableArrowKeyNavigation,
35
+ isShortcutToFocusToolbar,
36
+ editorAppearance,
37
+ useStickyToolbar,
38
+ intl
39
+ }) => {
40
+ const wrapperRef = useRef(null);
41
+ const selectedItemIndex = useRef(0);
42
+ const incrementIndex = useCallback(list => {
43
+ let index = 0;
44
+ if (document.activeElement) {
45
+ index = list.indexOf(document.activeElement);
46
+ index = (index + 1) % list.length;
47
+ }
48
+ selectedItemIndex.current = index;
49
+ }, []);
50
+ const decrementIndex = useCallback(list => {
51
+ let index = 0;
52
+ if (document.activeElement) {
53
+ index = list.indexOf(document.activeElement);
54
+ index = (list.length + index - 1) % list.length;
55
+ }
56
+ selectedItemIndex.current = index;
57
+ }, []);
58
+ const handleArrowRight = () => {
59
+ var _filteredFocusableEle;
60
+ const filteredFocusableElements = getFilteredFocusableElements(wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current);
61
+ incrementIndex(filteredFocusableElements);
62
+ (_filteredFocusableEle = filteredFocusableElements[selectedItemIndex.current]) === null || _filteredFocusableEle === void 0 ? void 0 : _filteredFocusableEle.focus();
63
+ };
64
+ const handleArrowLeft = () => {
65
+ var _filteredFocusableEle2;
66
+ const filteredFocusableElements = getFilteredFocusableElements(wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current);
67
+ decrementIndex(filteredFocusableElements);
68
+ (_filteredFocusableEle2 = filteredFocusableElements[selectedItemIndex.current]) === null || _filteredFocusableEle2 === void 0 ? void 0 : _filteredFocusableEle2.focus();
69
+ };
70
+ const handleTab = () => {
71
+ var _filteredFocusableEle3;
72
+ const filteredFocusableElements = getFilteredFocusableElements(wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current);
73
+ (_filteredFocusableEle3 = filteredFocusableElements[selectedItemIndex.current]) === null || _filteredFocusableEle3 === void 0 ? void 0 : _filteredFocusableEle3.focus();
74
+ };
75
+ const handleTabLocal = () => {
76
+ const filteredFocusableElements = getFilteredFocusableElements(wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current);
77
+ filteredFocusableElements.forEach(element => {
78
+ element.setAttribute('tabindex', '-1');
79
+ });
80
+ filteredFocusableElements[selectedItemIndex.current].setAttribute('tabindex', '0');
81
+ };
82
+ const focusAndScrollToElement = (element, scrollToElement = true) => {
83
+ if (scrollToElement) {
84
+ element === null || element === void 0 ? void 0 : element.scrollIntoView({
85
+ behavior: 'smooth',
86
+ block: 'center',
87
+ inline: 'nearest'
88
+ });
89
+ }
90
+ element.focus();
91
+ };
92
+ const submenuKeydownHandleContext = {
93
+ handleArrowLeft,
94
+ handleArrowRight,
95
+ handleTab
96
+ };
97
+ useLayoutEffect(() => {
98
+ if (!wrapperRef.current || disableArrowKeyNavigation) {
99
+ return;
100
+ }
101
+ const {
102
+ current: element
103
+ } = wrapperRef;
104
+
105
+ /**
106
+ * To handle the key events on the list
107
+ * @param event
108
+ */
109
+ const handleKeyDown = event => {
110
+ var _document$querySelect, _document$querySelect2, _wrapperRef$current;
111
+ //To trap the focus inside the horizontal toolbar for left and right arrow keys
112
+ const targetElement = event.target;
113
+
114
+ //To filter out the events outside the child component
115
+ if (!targetElement.closest(`${childComponentSelector}`)) {
116
+ return;
117
+ }
118
+
119
+ //The key events are from child components such as dropdown menus / popups are ignored
120
+ if ((_document$querySelect = document.querySelector('[data-role="droplistContent"], [data-test-id="color-picker-menu"], [data-emoji-picker-container="true"]')) !== null && _document$querySelect !== void 0 && _document$querySelect.contains(targetElement) || (_document$querySelect2 = document.querySelector('[data-test-id="color-picker-menu"]')) !== null && _document$querySelect2 !== void 0 && _document$querySelect2.contains(targetElement) || event.key === 'ArrowUp' || event.key === 'ArrowDown' || disableArrowKeyNavigation) {
121
+ return;
122
+ }
123
+ const menuWrapper = document.querySelector('.menu-key-handler-wrapper');
124
+ if (menuWrapper) {
125
+ // if menu wrapper exists, then a menu is open and arrow keys will be handled by MenuArrowKeyNavigationProvider
126
+ return;
127
+ }
128
+ const filteredFocusableElements = getFilteredFocusableElements(wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current);
129
+ if (!filteredFocusableElements || (filteredFocusableElements === null || filteredFocusableElements === void 0 ? void 0 : filteredFocusableElements.length) === 0) {
130
+ return;
131
+ }
132
+
133
+ //This is kind of hack to reset the current focused toolbar item
134
+ //to handle some use cases such as Tab in/out of main toolbar
135
+ if (!((_wrapperRef$current = wrapperRef.current) !== null && _wrapperRef$current !== void 0 && _wrapperRef$current.contains(targetElement))) {
136
+ selectedItemIndex.current = -1;
137
+ } else {
138
+ selectedItemIndex.current = filteredFocusableElements.indexOf(targetElement) > -1 ? filteredFocusableElements.indexOf(targetElement) : selectedItemIndex.current;
139
+ }
140
+
141
+ //do not scroll to focused element for sticky toolbar when navigating with arrows to avoid unnesessary scroll jump
142
+ const allowScrollToElement = !(editorAppearance === 'comment' && !!useStickyToolbar);
143
+ switch (event.key) {
144
+ case 'ArrowRight':
145
+ incrementIndex(filteredFocusableElements);
146
+ focusAndScrollToElement(filteredFocusableElements[selectedItemIndex.current], allowScrollToElement);
147
+ event.preventDefault();
148
+ break;
149
+ case 'ArrowLeft':
150
+ decrementIndex(filteredFocusableElements);
151
+ focusAndScrollToElement(filteredFocusableElements[selectedItemIndex.current], allowScrollToElement);
152
+ event.preventDefault();
153
+ break;
154
+ case 'Tab':
155
+ handleTabLocal();
156
+ break;
157
+ case 'Escape':
158
+ handleEscape(event);
159
+ break;
160
+ default:
161
+ }
162
+ };
163
+ const globalKeyDownHandler = event => {
164
+ //To focus the first element in the toolbar
165
+ if (isShortcutToFocusToolbar(event)) {
166
+ var _filteredFocusableEle4, _filteredFocusableEle5;
167
+ const filteredFocusableElements = getFilteredFocusableElements(wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current);
168
+ (_filteredFocusableEle4 = filteredFocusableElements[0]) === null || _filteredFocusableEle4 === void 0 ? void 0 : _filteredFocusableEle4.focus();
169
+ (_filteredFocusableEle5 = filteredFocusableElements[0]) === null || _filteredFocusableEle5 === void 0 ? void 0 : _filteredFocusableEle5.scrollIntoView({
170
+ behavior: 'smooth',
171
+ block: 'center',
172
+ inline: 'nearest'
173
+ });
174
+ }
175
+ };
176
+ element === null || element === void 0 ? void 0 : element.addEventListener('keydown', handleKeyDown);
177
+ const editorViewDom = editorView === null || editorView === void 0 ? void 0 : editorView.dom;
178
+ if (isShortcutToFocusToolbar) {
179
+ editorViewDom === null || editorViewDom === void 0 ? void 0 : editorViewDom.addEventListener('keydown', globalKeyDownHandler);
180
+ }
181
+ return () => {
182
+ element === null || element === void 0 ? void 0 : element.removeEventListener('keydown', handleKeyDown);
183
+ if (isShortcutToFocusToolbar) {
184
+ editorViewDom === null || editorViewDom === void 0 ? void 0 : editorViewDom.removeEventListener('keydown', globalKeyDownHandler);
185
+ }
186
+ };
187
+ }, [selectedItemIndex, wrapperRef, editorView, disableArrowKeyNavigation, handleEscape, childComponentSelector, incrementIndex, decrementIndex, isShortcutToFocusToolbar, editorAppearance, useStickyToolbar]);
188
+ return jsx("div", {
189
+ css: editorAppearance === 'comment' && centeredToolbarContainer,
190
+ className: "custom-key-handler-wrapper",
191
+ ref: wrapperRef,
192
+ role: "toolbar",
193
+ "aria-label": intl.formatMessage(messages.toolbarLabel),
194
+ "aria-controls": EDIT_AREA_ID
195
+ }, jsx(KeyDownHandlerContext.Provider, {
196
+ value: submenuKeydownHandleContext
197
+ }, children));
198
+ };
199
+ function getFocusableElements(rootNode) {
200
+ if (!rootNode) {
201
+ return [];
202
+ }
203
+ const focusableModalElements = rootNode.querySelectorAll('a[href], button:not([disabled]), textarea, input, select, div[tabindex="-1"], div[tabindex="0"]') || [];
204
+ return Array.from(focusableModalElements);
205
+ }
206
+ function getFilteredFocusableElements(rootNode) {
207
+ //The focusable elements from child components such as dropdown menus / popups are ignored
208
+ return getFocusableElements(rootNode).filter(elm => !elm.closest('[data-role="droplistContent"]') && !elm.closest('[data-emoji-picker-container="true"]') && !elm.closest('[data-test-id="color-picker-menu"]') && !elm.closest('.scroll-buttons'));
209
+ }
@@ -1,6 +1,7 @@
1
- export { default as DropdownMenu } from '../ui-menu/DropdownMenu';
2
- export { default as ToolbarButton, TOOLBAR_BUTTON } from '../ui-menu/ToolbarButton';
3
- export { ArrowKeyNavigationProvider } from '../ui-menu/ArrowKeyNavigationProvider';
4
- export { ArrowKeyNavigationType } from '../ui-menu/ArrowKeyNavigationProvider/types';
1
+ export { default as DropdownMenu, DropdownMenuWithKeyboardNavigation } from './DropdownMenu';
2
+ export { default as ToolbarButton, TOOLBAR_BUTTON } from './ToolbarButton';
3
+ export { ArrowKeyNavigationProvider } from './ArrowKeyNavigationProvider';
4
+ export { ToolbarArrowKeyNavigationProvider, KeyDownHandlerContext } from './ToolbarArrowKeyNavigationProvider';
5
+ export { ArrowKeyNavigationType } from './ArrowKeyNavigationProvider/types';
5
6
  export { ColorPaletteArrowKeyNavigationProvider } from './ArrowKeyNavigationProvider/ColorPaletteArrowKeyNavigationProvider';
6
7
  export { default as Dropdown } from './Dropdown';
@@ -1,4 +1,7 @@
1
- export const filter = (predicates, cmd) => {
1
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
2
+ import { GapCursorSelection } from '../selection';
3
+ import { isEmptyParagraph } from './editor-core-utils';
4
+ const filter = (predicates, cmd) => {
2
5
  return function (state, dispatch, view) {
3
6
  if (!Array.isArray(predicates)) {
4
7
  predicates = [predicates];
@@ -8,4 +11,105 @@ export const filter = (predicates, cmd) => {
8
11
  }
9
12
  return cmd(state, dispatch, view) || false;
10
13
  };
11
- };
14
+ };
15
+
16
+ /**
17
+ * Walk forwards from a position until we encounter the (inside) start of
18
+ * the next node, or reach the end of the document.
19
+ *
20
+ * @param $startPos Position to start walking from.
21
+ */
22
+ export const walkNextNode = $startPos => {
23
+ let $pos = $startPos;
24
+
25
+ // invariant 1: don't walk past the end of the document
26
+ // invariant 2: we are at the beginning or
27
+ // we haven't walked to the start of *any* node
28
+ // parentOffset includes textOffset.
29
+ while ($pos.pos < $pos.doc.nodeSize - 2 && ($pos.pos === $startPos.pos || $pos.parentOffset > 0)) {
30
+ $pos = $pos.doc.resolve($pos.pos + 1);
31
+ }
32
+ return {
33
+ $pos: $pos,
34
+ foundNode: $pos.pos < $pos.doc.nodeSize - 2
35
+ };
36
+ };
37
+
38
+ /**
39
+ * Walk backwards from a position until we encounter the (inside) end of
40
+ * the previous node, or reach the start of the document.
41
+ *
42
+ * @param $startPos Position to start walking from.
43
+ */
44
+ export const walkPrevNode = $startPos => {
45
+ let $pos = $startPos;
46
+ while ($pos.pos > 0 && ($pos.pos === $startPos.pos || $pos.parentOffset < $pos.parent.nodeSize - 2)) {
47
+ $pos = $pos.doc.resolve($pos.pos - 1);
48
+ }
49
+ return {
50
+ $pos: $pos,
51
+ foundNode: $pos.pos > 0
52
+ };
53
+ };
54
+
55
+ /**
56
+ * If the selection is empty, is inside a paragraph node and `canNextNodeMoveUp` is true then delete current paragraph
57
+ * and move the node below it up. The selection will be retained, to be placed in the moved node.
58
+ *
59
+ * @param canNextNodeMoveUp check if node directly after the selection is able to be brought up to selection
60
+ * @returns PM Command
61
+ */
62
+ export const deleteEmptyParagraphAndMoveBlockUp = canNextNodeMoveUp => {
63
+ return (state, dispatch, view) => {
64
+ const {
65
+ selection: {
66
+ $from: {
67
+ pos,
68
+ parent
69
+ },
70
+ $head,
71
+ empty
72
+ },
73
+ tr,
74
+ doc
75
+ } = state;
76
+ const {
77
+ $pos
78
+ } = walkNextNode($head);
79
+ const nextPMNode = doc.nodeAt($pos.pos - 1);
80
+ if (empty && nextPMNode && canNextNodeMoveUp(nextPMNode) && isEmptyParagraph(parent) && view !== null && view !== void 0 && view.endOfTextblock('right')) {
81
+ tr.deleteRange(pos - 1, pos + 1);
82
+ if (dispatch) {
83
+ dispatch(tr);
84
+ }
85
+ return true;
86
+ }
87
+ return false;
88
+ };
89
+ };
90
+ export const insertContentDeleteRange = (tr, getSelectionResolvedPos, insertions, deletions) => {
91
+ insertions.forEach(contentInsert => {
92
+ let [content, pos] = contentInsert;
93
+ tr.insert(tr.mapping.map(pos), content);
94
+ });
95
+ deletions.forEach(deleteRange => {
96
+ let [firstPos, lastPos] = deleteRange;
97
+ tr.delete(tr.mapping.map(firstPos), tr.mapping.map(lastPos));
98
+ });
99
+ tr.setSelection(new TextSelection(getSelectionResolvedPos(tr)));
100
+ };
101
+ export const isEmptySelectionAtStart = state => {
102
+ const {
103
+ empty,
104
+ $from
105
+ } = state.selection;
106
+ return empty && ($from.parentOffset === 0 || state.selection instanceof GapCursorSelection);
107
+ };
108
+ export const isEmptySelectionAtEnd = state => {
109
+ const {
110
+ empty,
111
+ $from
112
+ } = state.selection;
113
+ return empty && ($from.end() === $from.pos || state.selection instanceof GapCursorSelection);
114
+ };
115
+ export { filter as filterCommand };