@atlaskit/editor-plugin-table 7.18.2 → 7.18.4

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 (75) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/commands/column-resize.js +0 -12
  3. package/dist/cjs/commands/go-to-next-cell.js +8 -11
  4. package/dist/cjs/commands/index.js +6 -0
  5. package/dist/cjs/commands/misc.js +15 -1
  6. package/dist/cjs/commands/selection.js +4 -11
  7. package/dist/cjs/event-handlers.js +7 -11
  8. package/dist/cjs/plugin.js +7 -4
  9. package/dist/cjs/pm-plugins/keymap.js +22 -21
  10. package/dist/cjs/pm-plugins/main.js +26 -30
  11. package/dist/cjs/pm-plugins/table-resizing/event-handlers.js +13 -21
  12. package/dist/cjs/pm-plugins/table-resizing/plugin.js +8 -11
  13. package/dist/cjs/reducer.js +1 -0
  14. package/dist/cjs/ui/FloatingContextualButton/index.js +18 -2
  15. package/dist/cjs/ui/FloatingContextualMenu/ContextualMenu.js +170 -35
  16. package/dist/cjs/ui/FloatingContextualMenu/index.js +4 -2
  17. package/dist/es2019/commands/column-resize.js +0 -12
  18. package/dist/es2019/commands/go-to-next-cell.js +8 -11
  19. package/dist/es2019/commands/index.js +1 -1
  20. package/dist/es2019/commands/misc.js +9 -1
  21. package/dist/es2019/commands/selection.js +4 -11
  22. package/dist/es2019/event-handlers.js +8 -12
  23. package/dist/es2019/plugin.js +7 -4
  24. package/dist/es2019/pm-plugins/keymap.js +24 -23
  25. package/dist/es2019/pm-plugins/main.js +27 -31
  26. package/dist/es2019/pm-plugins/table-resizing/event-handlers.js +13 -21
  27. package/dist/es2019/pm-plugins/table-resizing/plugin.js +9 -12
  28. package/dist/es2019/reducer.js +1 -0
  29. package/dist/es2019/ui/FloatingContextualButton/index.js +17 -2
  30. package/dist/es2019/ui/FloatingContextualMenu/ContextualMenu.js +159 -24
  31. package/dist/es2019/ui/FloatingContextualMenu/index.js +4 -2
  32. package/dist/esm/commands/column-resize.js +0 -12
  33. package/dist/esm/commands/go-to-next-cell.js +8 -11
  34. package/dist/esm/commands/index.js +1 -1
  35. package/dist/esm/commands/misc.js +14 -0
  36. package/dist/esm/commands/selection.js +4 -11
  37. package/dist/esm/event-handlers.js +7 -11
  38. package/dist/esm/plugin.js +7 -4
  39. package/dist/esm/pm-plugins/keymap.js +24 -23
  40. package/dist/esm/pm-plugins/main.js +26 -30
  41. package/dist/esm/pm-plugins/table-resizing/event-handlers.js +13 -21
  42. package/dist/esm/pm-plugins/table-resizing/plugin.js +8 -11
  43. package/dist/esm/reducer.js +1 -0
  44. package/dist/esm/ui/FloatingContextualButton/index.js +15 -2
  45. package/dist/esm/ui/FloatingContextualMenu/ContextualMenu.js +171 -40
  46. package/dist/esm/ui/FloatingContextualMenu/index.js +4 -2
  47. package/dist/types/commands/index.d.ts +1 -1
  48. package/dist/types/commands/misc.d.ts +1 -0
  49. package/dist/types/types.d.ts +6 -0
  50. package/dist/types/ui/FloatingContextualButton/index.d.ts +1 -0
  51. package/dist/types/ui/FloatingContextualMenu/ContextualMenu.d.ts +7 -3
  52. package/dist/types/ui/FloatingContextualMenu/index.d.ts +2 -1
  53. package/dist/types-ts4.5/commands/index.d.ts +1 -1
  54. package/dist/types-ts4.5/commands/misc.d.ts +1 -0
  55. package/dist/types-ts4.5/types.d.ts +6 -0
  56. package/dist/types-ts4.5/ui/FloatingContextualButton/index.d.ts +1 -0
  57. package/dist/types-ts4.5/ui/FloatingContextualMenu/ContextualMenu.d.ts +7 -3
  58. package/dist/types-ts4.5/ui/FloatingContextualMenu/index.d.ts +2 -1
  59. package/package.json +4 -4
  60. package/src/commands/column-resize.ts +0 -14
  61. package/src/commands/go-to-next-cell.ts +7 -10
  62. package/src/commands/index.ts +1 -0
  63. package/src/commands/misc.ts +13 -0
  64. package/src/commands/selection.ts +4 -11
  65. package/src/event-handlers.ts +6 -12
  66. package/src/plugin.tsx +6 -1
  67. package/src/pm-plugins/keymap.ts +65 -62
  68. package/src/pm-plugins/main.ts +27 -31
  69. package/src/pm-plugins/table-resizing/event-handlers.ts +11 -19
  70. package/src/pm-plugins/table-resizing/plugin.ts +7 -10
  71. package/src/reducer.ts +1 -0
  72. package/src/types.ts +8 -1
  73. package/src/ui/FloatingContextualButton/index.tsx +19 -1
  74. package/src/ui/FloatingContextualMenu/ContextualMenu.tsx +207 -30
  75. package/src/ui/FloatingContextualMenu/index.tsx +3 -0
@@ -1,9 +1,9 @@
1
1
  import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
2
- import { addColumnAfter, addColumnAfterVO, addColumnBefore, addColumnBeforeVO, addRowAfter, addRowAfterVO, addRowBefore, addRowBeforeVO, backspace, bindKeymapWithCommand, decreaseMediaSize, deleteColumn, deleteRow, escape, increaseMediaSize, moveColumnLeft, moveColumnRight, moveLeft, moveRight, moveRowDown, moveRowUp, nextCell, previousCell, startColumnResizing, toggleTable } from '@atlaskit/editor-common/keymaps';
2
+ import { addColumnAfter, addColumnAfterVO, addColumnBefore, addColumnBeforeVO, addRowAfter, addRowAfterVO, addRowBefore, addRowBeforeVO, backspace, bindKeymapWithCommand, decreaseMediaSize, deleteColumn, deleteRow, escape, focusToContextMenuTrigger, increaseMediaSize, moveColumnLeft, moveColumnRight, moveLeft, moveRight, moveRowDown, moveRowUp, nextCell, previousCell, startColumnResizing, toggleTable } from '@atlaskit/editor-common/keymaps';
3
3
  import { chainCommands } from '@atlaskit/editor-prosemirror/commands';
4
4
  import { keymap } from '@atlaskit/editor-prosemirror/keymap';
5
5
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
6
- import { goToNextCell, moveCursorBackward } from '../commands';
6
+ import { goToNextCell, moveCursorBackward, setFocusToCellMenu } from '../commands';
7
7
  import { addRowAroundSelection, changeColumnWidthByStepWithAnalytics, deleteSelectedRowsOrColumnsWithAnalyticsViaShortcut, deleteTableIfSelectedWithAnalytics, emptyMultipleCellsWithAnalytics } from '../commands-with-analytics';
8
8
  import { activateNextResizeArea, initiateKeyboardColumnResizing, stopKeyboardColumnResizing } from '../commands/column-resize';
9
9
  import { addColumnAfter as addColumnAfterCommand, addColumnBefore as addColumnBeforeCommand, createTable } from '../commands/insert';
@@ -47,27 +47,28 @@ export function keymapPlugin(getEditorContainerWidth, editorAnalyticsAPI, dragAn
47
47
  bindKeymapWithCommand(deleteColumn.common, deleteSelectedRowsOrColumnsWithAnalyticsViaShortcut(editorAnalyticsAPI, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent), list);
48
48
  bindKeymapWithCommand(deleteRow.common, deleteSelectedRowsOrColumnsWithAnalyticsViaShortcut(editorAnalyticsAPI, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent), list);
49
49
  }
50
- if (getBooleanFF('platform.editor.a11y-column-resizing_emcvz')) {
51
- bindKeymapWithCommand(startColumnResizing.common, initiateKeyboardColumnResizing({
52
- ariaNotify: ariaNotifyPlugin,
53
- getIntl: getIntl
54
- }), list);
55
- bindKeymapWithCommand(moveRight.common, activateNextResizeArea({
56
- direction: 1,
57
- ariaNotify: ariaNotifyPlugin,
58
- getIntl: getIntl
59
- }), list);
60
- bindKeymapWithCommand(moveLeft.common, activateNextResizeArea({
61
- direction: -1,
62
- ariaNotify: ariaNotifyPlugin,
63
- getIntl: getIntl
64
- }), list);
65
- bindKeymapWithCommand(decreaseMediaSize.common, changeColumnWidthByStepWithAnalytics(editorAnalyticsAPI)(-10, getEditorContainerWidth, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, INPUT_METHOD.SHORTCUT, ariaNotifyPlugin, getIntl), list);
66
- bindKeymapWithCommand(increaseMediaSize.common, changeColumnWidthByStepWithAnalytics(editorAnalyticsAPI)(10, getEditorContainerWidth, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, INPUT_METHOD.SHORTCUT, ariaNotifyPlugin, getIntl), list);
67
- bindKeymapWithCommand(escape.common, stopKeyboardColumnResizing({
68
- ariaNotify: ariaNotifyPlugin,
69
- getIntl: getIntl
70
- }), list);
50
+ bindKeymapWithCommand(startColumnResizing.common, initiateKeyboardColumnResizing({
51
+ ariaNotify: ariaNotifyPlugin,
52
+ getIntl: getIntl
53
+ }), list);
54
+ bindKeymapWithCommand(moveRight.common, activateNextResizeArea({
55
+ direction: 1,
56
+ ariaNotify: ariaNotifyPlugin,
57
+ getIntl: getIntl
58
+ }), list);
59
+ bindKeymapWithCommand(moveLeft.common, activateNextResizeArea({
60
+ direction: -1,
61
+ ariaNotify: ariaNotifyPlugin,
62
+ getIntl: getIntl
63
+ }), list);
64
+ bindKeymapWithCommand(decreaseMediaSize.common, changeColumnWidthByStepWithAnalytics(editorAnalyticsAPI)(-10, getEditorContainerWidth, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, INPUT_METHOD.SHORTCUT, ariaNotifyPlugin, getIntl), list);
65
+ bindKeymapWithCommand(increaseMediaSize.common, changeColumnWidthByStepWithAnalytics(editorAnalyticsAPI)(10, getEditorContainerWidth, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, INPUT_METHOD.SHORTCUT, ariaNotifyPlugin, getIntl), list);
66
+ bindKeymapWithCommand(escape.common, stopKeyboardColumnResizing({
67
+ ariaNotify: ariaNotifyPlugin,
68
+ getIntl: getIntl
69
+ }), list);
70
+ if (getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')) {
71
+ bindKeymapWithCommand(focusToContextMenuTrigger.common, setFocusToCellMenu(), list);
71
72
  }
72
73
  return keymap(list);
73
74
  }
@@ -106,31 +106,29 @@ export const createPlugin = (dispatchAnalyticsEvent, dispatch, portalProviderAPI
106
106
  tableRef = parent.querySelector('table') || undefined;
107
107
  }
108
108
  const tableNode = findTable(state.selection);
109
- if (getBooleanFF('platform.editor.a11y-column-resizing_emcvz')) {
110
- // when keyboard cursor leaves the table we need to stop column resizing
111
- const pluginPrevState = getPluginState(prevState);
112
- const isStopKeyboardColumResizing = pluginPrevState.isResizeHandleWidgetAdded && pluginPrevState.isKeyboardResize;
113
- if (isStopKeyboardColumResizing) {
114
- const isTableNodesDifferent = (pluginPrevState === null || pluginPrevState === void 0 ? void 0 : pluginPrevState.tableNode) !== (tableNode === null || tableNode === void 0 ? void 0 : tableNode.node);
115
- if (pluginPrevState !== null && pluginPrevState !== void 0 && pluginPrevState.tableNode && tableNode && isTableNodesDifferent) {
116
- const oldRowsNumber = TableMap.get(pluginPrevState.tableNode).height;
117
- const newRowsNumber = TableMap.get(tableNode.node).height;
118
- if (oldRowsNumber !== newRowsNumber ||
119
- // Add/delete row
120
- tableNode.node.attrs.localId !== pluginPrevState.tableNode.attrs.localId) {
121
- // Jump to another table
122
- stopKeyboardColumnResizing({
123
- ariaNotify: ariaNotifyPlugin,
124
- getIntl: getIntl
125
- })(state, dispatch);
126
- }
127
- } else if (!tableNode) {
128
- // selection outside of table
109
+ // when keyboard cursor leaves the table we need to stop column resizing
110
+ const pluginPrevState = getPluginState(prevState);
111
+ const isStopKeyboardColumResizing = pluginPrevState.isResizeHandleWidgetAdded && pluginPrevState.isKeyboardResize;
112
+ if (isStopKeyboardColumResizing) {
113
+ const isTableNodesDifferent = (pluginPrevState === null || pluginPrevState === void 0 ? void 0 : pluginPrevState.tableNode) !== (tableNode === null || tableNode === void 0 ? void 0 : tableNode.node);
114
+ if (pluginPrevState !== null && pluginPrevState !== void 0 && pluginPrevState.tableNode && tableNode && isTableNodesDifferent) {
115
+ const oldRowsNumber = TableMap.get(pluginPrevState.tableNode).height;
116
+ const newRowsNumber = TableMap.get(tableNode.node).height;
117
+ if (oldRowsNumber !== newRowsNumber ||
118
+ // Add/delete row
119
+ tableNode.node.attrs.localId !== pluginPrevState.tableNode.attrs.localId) {
120
+ // Jump to another table
129
121
  stopKeyboardColumnResizing({
130
122
  ariaNotify: ariaNotifyPlugin,
131
123
  getIntl: getIntl
132
124
  })(state, dispatch);
133
125
  }
126
+ } else if (!tableNode) {
127
+ // selection outside of table
128
+ stopKeyboardColumnResizing({
129
+ ariaNotify: ariaNotifyPlugin,
130
+ getIntl: getIntl
131
+ })(state, dispatch);
134
132
  }
135
133
  }
136
134
  }
@@ -240,17 +238,15 @@ export const createPlugin = (dispatchAnalyticsEvent, dispatch, portalProviderAPI
240
238
  state,
241
239
  dispatch
242
240
  } = view;
243
- if (getBooleanFF('platform.editor.a11y-column-resizing_emcvz')) {
244
- const {
245
- isKeyboardResize
246
- } = getPluginState(state);
247
- if (isKeyboardResize) {
248
- stopKeyboardColumnResizing({
249
- ariaNotify: ariaNotifyPlugin,
250
- getIntl: getIntl
251
- })(state, dispatch);
252
- return false;
253
- }
241
+ const {
242
+ isKeyboardResize
243
+ } = getPluginState(state);
244
+ if (isKeyboardResize) {
245
+ stopKeyboardColumnResizing({
246
+ ariaNotify: ariaNotifyPlugin,
247
+ getIntl: getIntl
248
+ })(state, dispatch);
249
+ return false;
254
250
  }
255
251
  const tr = replaceSelectedTable(state, text, INPUT_METHOD.KEYBOARD, editorAnalyticsAPI);
256
252
  if (tr.selectionSet) {
@@ -118,15 +118,11 @@ export const handleMouseDown = (view, event, localResizeHandlePos, getEditorCont
118
118
 
119
119
  // If we let go in the same place we started, don't need to do anything.
120
120
  if (dragging && clientX === dragging.startX) {
121
- if (getBooleanFF('platform.editor.a11y-column-resizing_emcvz')) {
122
- if (isKeyboardResize || !isTableHovered) {
123
- /** if column resize had started via keyboard but continued by mouse
124
- * or mouse pointer leaves the table but mouse button still pressed
125
- */
126
- return stopKeyboardColumnResizing({})(state, dispatch, view);
127
- } else {
128
- return stopResizing()(state, dispatch);
129
- }
121
+ if (isKeyboardResize || !isTableHovered) {
122
+ /** if column resize had started via keyboard but continued by mouse
123
+ * or mouse pointer leaves the table but mouse button still pressed
124
+ */
125
+ return stopKeyboardColumnResizing({})(state, dispatch, view);
130
126
  } else {
131
127
  return stopResizing()(state, dispatch);
132
128
  }
@@ -197,17 +193,13 @@ export const handleMouseDown = (view, event, localResizeHandlePos, getEditorCont
197
193
  }
198
194
  })(tr);
199
195
  }
200
- if (getBooleanFF('platform.editor.a11y-column-resizing_emcvz')) {
201
- if (isKeyboardResize || !isTableHovered) {
202
- /** if column resize had started via keyboard but continued by mouse
203
- * or mouse pointer leaves the table but mouse button still pressed
204
- */
205
- return stopKeyboardColumnResizing({
206
- originalTr: tr
207
- })(state, dispatch, view);
208
- } else {
209
- return stopResizing(tr)(state, dispatch);
210
- }
196
+ if (isKeyboardResize || !isTableHovered) {
197
+ /** if column resize had started via keyboard but continued by mouse
198
+ * or mouse pointer leaves the table but mouse button still pressed
199
+ */
200
+ return stopKeyboardColumnResizing({
201
+ originalTr: tr
202
+ })(state, dispatch, view);
211
203
  } else {
212
204
  return stopResizing(tr)(state, dispatch);
213
205
  }
@@ -228,7 +220,7 @@ export const handleMouseDown = (view, event, localResizeHandlePos, getEditorCont
228
220
  const {
229
221
  isTableHovered
230
222
  } = getTablePluginState(state);
231
- if (!which || !dragging || resizeHandlePos === null || !pointsAtCell(state.doc.resolve(resizeHandlePos)) || !isTableHovered && getBooleanFF('platform.editor.a11y-column-resizing_emcvz')) {
223
+ if (!which || !dragging || resizeHandlePos === null || !pointsAtCell(state.doc.resolve(resizeHandlePos)) || !isTableHovered) {
232
224
  return finish(event);
233
225
  }
234
226
  const $cell = state.doc.resolve(resizeHandlePos);
@@ -1,6 +1,5 @@
1
1
  import classnames from 'classnames';
2
2
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
3
- import { getBooleanFF } from '@atlaskit/platform-feature-flags';
4
3
  import { TableCssClassName as ClassName } from '../../types';
5
4
  import { getPluginState as getTablePluginState } from '../plugin-factory';
6
5
  import { setResizeHandlePos } from './commands';
@@ -41,17 +40,15 @@ export function createPlugin(dispatch, {
41
40
  dragging
42
41
  } = getPluginState(state);
43
42
  let isColumnKeyboardResizeStarted = false;
44
- if (getBooleanFF('platform.editor.a11y-column-resizing_emcvz')) {
45
- /*
46
- We need to start listening mouse events if column resize started from keyboard.
47
- This will allow continue resizing via mouse
48
- */
49
- const {
50
- isKeyboardResize
51
- } = getTablePluginState(state);
52
- if (isKeyboardResize) {
53
- isColumnKeyboardResizeStarted = isKeyboardResize;
54
- }
43
+ /*
44
+ We need to start listening mouse events if column resize started from keyboard.
45
+ This will allow continue resizing via mouse
46
+ */
47
+ const {
48
+ isKeyboardResize
49
+ } = getTablePluginState(state);
50
+ if (isKeyboardResize) {
51
+ isColumnKeyboardResizeStarted = isKeyboardResize;
55
52
  }
56
53
  if (resizeHandlePos !== null && (!dragging || isColumnKeyboardResizeStarted)) {
57
54
  if (handleMouseDown(view, event, resizeHandlePos, getEditorContainerWidth, getEditorFeatureFlags, isTableScalingEnabled || false, editorAnalyticsAPI, isNewColumnResizingEnabled)) {
@@ -116,6 +116,7 @@ export default ((pluginState, action) => {
116
116
  case 'HOVER_CELL':
117
117
  case 'SHOW_RESIZE_HANDLE_LINE':
118
118
  case 'SET_EDITOR_FOCUS':
119
+ case 'SET_CELL_MENU_OPEN':
119
120
  return {
120
121
  ...pluginState,
121
122
  ...action.data
@@ -1,5 +1,5 @@
1
1
  /** @jsx jsx */
2
- import React from 'react';
2
+ import React, { useEffect } from 'react';
3
3
 
4
4
  // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
5
5
  import { jsx } from '@emotion/react';
@@ -12,6 +12,7 @@ import { ToolbarButton } from '@atlaskit/editor-common/ui-menu';
12
12
  import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
13
13
  import { akEditorSmallZIndex } from '@atlaskit/editor-shared-styles';
14
14
  import ExpandIcon from '@atlaskit/icon/glyph/chevron-down';
15
+ import { getBooleanFF } from '@atlaskit/platform-feature-flags';
15
16
  import { toggleContextualMenu } from '../../commands';
16
17
  import { TableCssClassName as ClassName } from '../../types';
17
18
  import FixedButton from './FixedButton';
@@ -26,6 +27,7 @@ const FloatingContextualButtonInner = /*#__PURE__*/React.memo(props => {
26
27
  stickyHeader,
27
28
  tableWrapper,
28
29
  targetCellPosition,
30
+ isCellMenuOpenByKeyboard,
29
31
  intl: {
30
32
  formatMessage
31
33
  }
@@ -48,6 +50,18 @@ const FloatingContextualButtonInner = /*#__PURE__*/React.memo(props => {
48
50
  const domAtPos = editorView.domAtPos.bind(editorView);
49
51
  let targetCellRef;
50
52
  targetCellRef = findDomRefAtPos(targetCellPosition, domAtPos);
53
+ useEffect(() => {
54
+ if (getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')) {
55
+ if (isCellMenuOpenByKeyboard && !isContextualMenuOpen) {
56
+ const {
57
+ state,
58
+ dispatch
59
+ } = editorView;
60
+ // open the menu when the keyboard shortcut is pressed
61
+ toggleContextualMenu()(state, dispatch);
62
+ }
63
+ }
64
+ }, [isCellMenuOpenByKeyboard, isContextualMenuOpen, editorView]);
51
65
  if (!targetCellRef || !(targetCellRef instanceof HTMLElement)) {
52
66
  return null;
53
67
  }
@@ -68,7 +82,8 @@ const FloatingContextualButtonInner = /*#__PURE__*/React.memo(props => {
68
82
  iconBefore: jsx(ExpandIcon, {
69
83
  label: ""
70
84
  }),
71
- "aria-label": labelCellOptions
85
+ "aria-label": labelCellOptions,
86
+ "aria-expanded": getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c') ? isContextualMenuOpen : undefined
72
87
  }));
73
88
  const parentSticky = targetCellRef.parentElement && targetCellRef.parentElement.className.indexOf('sticky') > -1;
74
89
  if (stickyHeader && parentSticky && tableWrapper) {
@@ -1,8 +1,7 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  /* eslint-disable @atlaskit/design-system/prefer-primitives */
3
3
  /** @jsx jsx */
4
- import { Component } from 'react';
5
-
4
+ import React, { Component } from 'react';
6
5
  // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
7
6
  import { jsx } from '@emotion/react';
8
7
  import { injectIntl } from 'react-intl-next';
@@ -11,8 +10,8 @@ import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
11
10
  import { addColumnAfter, addRowAfter, backspace, tooltip } from '@atlaskit/editor-common/keymaps';
12
11
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
13
12
  import { DropdownMenuSharedCssClassName } from '@atlaskit/editor-common/styles';
14
- import { backgroundPaletteTooltipMessages, cellBackgroundColorPalette, ColorPalette } from '@atlaskit/editor-common/ui-color';
15
- import { ArrowKeyNavigationType, DropdownMenu } from '@atlaskit/editor-common/ui-menu';
13
+ import { backgroundPaletteTooltipMessages, cellBackgroundColorPalette, ColorPalette, getSelectedRowAndColumnFromPalette } from '@atlaskit/editor-common/ui-color';
14
+ import { ArrowKeyNavigationProvider, ArrowKeyNavigationType, DropdownMenu } from '@atlaskit/editor-common/ui-menu';
16
15
  import { closestElement } from '@atlaskit/editor-common/utils';
17
16
  import { hexToEditorBackgroundPaletteColor } from '@atlaskit/editor-palette';
18
17
  import { shortcutStyle } from '@atlaskit/editor-shared-styles/shortcut';
@@ -21,22 +20,26 @@ import CrossCircleIcon from '@atlaskit/icon/glyph/cross-circle';
21
20
  import EditorBackgroundColorIcon from '@atlaskit/icon/glyph/editor/background-color';
22
21
  import RemoveIcon from '@atlaskit/icon/glyph/editor/remove';
23
22
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
24
- import { clearHoverSelection, hoverColumns, hoverMergedCells, hoverRows, toggleContextualMenu } from '../../commands';
23
+ import { clearHoverSelection, hoverColumns, hoverMergedCells, hoverRows, setFocusToCellMenu, toggleContextualMenu } from '../../commands';
25
24
  import { deleteColumnsWithAnalytics, deleteRowsWithAnalytics, distributeColumnsWidthsWithAnalytics, emptyMultipleCellsWithAnalytics, insertColumnWithAnalytics, insertRowWithAnalytics, mergeCellsWithAnalytics, setColorWithAnalytics, sortColumnWithAnalytics, splitCellWithAnalytics } from '../../commands-with-analytics';
26
25
  import { getPluginState } from '../../pm-plugins/plugin-factory';
26
+ import { pluginKey as tablePluginKey } from '../../pm-plugins/plugin-key';
27
27
  import { getNewResizeStateFromSelectedColumns } from '../../pm-plugins/table-resizing/utils/resize-state';
28
28
  import { canMergeCells } from '../../transforms';
29
29
  import { TableCssClassName as ClassName } from '../../types';
30
30
  import { getMergedCellsPositions, getSelectedColumnIndexes, getSelectedRowIndexes } from '../../utils';
31
- import { contextualMenuDropdownWidth, contextualMenuDropdownWidthDnD } from '../consts';
31
+ import { colorPalletteColumns, contextualMenuDropdownWidth, contextualMenuDropdownWidthDnD } from '../consts';
32
32
  import { AddColRightIcon, AddRowBelowIcon, MergeCellsIcon, SplitCellIcon } from '../icons';
33
33
  import { cellColourPreviewStyles, elementBeforeIconStyles } from './styles';
34
+ const arrowsList = new Set(['ArrowRight', 'ArrowLeft']);
34
35
  export class ContextualMenu extends Component {
35
36
  constructor(...args) {
36
37
  super(...args);
37
38
  _defineProperty(this, "state", {
38
- isSubmenuOpen: false
39
+ isSubmenuOpen: false,
40
+ isOpenAllowed: false
39
41
  });
42
+ _defineProperty(this, "dropdownMenuRef", /*#__PURE__*/React.createRef());
40
43
  _defineProperty(this, "handleSubMenuRef", ref => {
41
44
  const parent = closestElement(this.props.editorView.dom, '.fabric-editor-popup-scroll-parent');
42
45
  if (!(parent && ref)) {
@@ -58,7 +61,8 @@ export class ContextualMenu extends Component {
58
61
  intl: {
59
62
  formatMessage
60
63
  },
61
- editorView
64
+ editorView,
65
+ isCellMenuOpenByKeyboard
62
66
  } = this.props;
63
67
  const {
64
68
  isSubmenuOpen
@@ -68,9 +72,16 @@ export class ContextualMenu extends Component {
68
72
  isDragAndDropEnabled
69
73
  } = getPluginState(editorView.state);
70
74
  if (allowBackgroundColor) {
71
- var _node$attrs, _node$attrs2;
75
+ var _node$attrs, _node$attrs2, _node$attrs3;
72
76
  const node = isOpen && targetCellPosition ? state.doc.nodeAt(targetCellPosition) : null;
73
77
  const background = hexToEditorBackgroundPaletteColor((node === null || node === void 0 ? void 0 : (_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.background) || '#ffffff');
78
+ let selectedRowIndex;
79
+ let selectedColumnIndex;
80
+ if (getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')) {
81
+ const selectedRowAndColumnFromPalette = getSelectedRowAndColumnFromPalette(cellBackgroundColorPalette, background, colorPalletteColumns);
82
+ selectedRowIndex = selectedRowAndColumnFromPalette.selectedRowIndex;
83
+ selectedColumnIndex = selectedRowAndColumnFromPalette.selectedColumnIndex;
84
+ }
74
85
  return {
75
86
  content: isDragAndDropEnabled ? formatMessage(messages.backgroundColor) : formatMessage(messages.cellBackground),
76
87
  value: {
@@ -94,10 +105,27 @@ export class ContextualMenu extends Component {
94
105
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
95
106
  ,
96
107
  className: isDragAndDropEnabled ? ClassName.CONTEXTUAL_MENU_ICON_SMALL : ClassName.CONTEXTUAL_MENU_ICON
97
- }), isSubmenuOpen && jsx("div", {
108
+ }), getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c') ? isSubmenuOpen && jsx("div", {
98
109
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
99
110
  className: ClassName.CONTEXTUAL_SUBMENU,
100
111
  ref: this.handleSubMenuRef
112
+ }, jsx(ArrowKeyNavigationProvider, {
113
+ type: ArrowKeyNavigationType.COLOR,
114
+ selectedRowIndex: selectedRowIndex || 0,
115
+ selectedColumnIndex: selectedColumnIndex || 0,
116
+ handleClose: () => {
117
+ this.setState({
118
+ isSubmenuOpen: false
119
+ });
120
+ if (this.dropdownMenuRef && this.dropdownMenuRef.current) {
121
+ const focusableItems = this.dropdownMenuRef.current.querySelectorAll('div[tabindex="-1"]:not([disabled])');
122
+ if (focusableItems && focusableItems.length) {
123
+ focusableItems[0].focus();
124
+ }
125
+ }
126
+ },
127
+ isPopupPositioned: true,
128
+ isOpenedByKeyboard: isCellMenuOpenByKeyboard
101
129
  }, jsx(ColorPalette, {
102
130
  cols: 7,
103
131
  onClick: this.setColor,
@@ -107,7 +135,22 @@ export class ContextualMenu extends Component {
107
135
  paletteColorTooltipMessages: backgroundPaletteTooltipMessages,
108
136
  hexToPaletteColor: hexToEditorBackgroundPaletteColor
109
137
  }
110
- })))
138
+ }))) : isSubmenuOpen &&
139
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
140
+ jsx("div", {
141
+ className: ClassName.CONTEXTUAL_SUBMENU,
142
+ ref: this.handleSubMenuRef
143
+ }, jsx(ColorPalette, {
144
+ cols: 7,
145
+ onClick: this.setColor,
146
+ selectedColor: (node === null || node === void 0 ? void 0 : (_node$attrs3 = node.attrs) === null || _node$attrs3 === void 0 ? void 0 : _node$attrs3.background) || '#ffffff',
147
+ paletteOptions: {
148
+ palette: cellBackgroundColorPalette,
149
+ paletteColorTooltipMessages: backgroundPaletteTooltipMessages,
150
+ hexToPaletteColor: hexToEditorBackgroundPaletteColor
151
+ }
152
+ }))),
153
+ 'aria-expanded': getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c') ? isSubmenuOpen : undefined
111
154
  };
112
155
  }
113
156
  });
@@ -439,7 +482,8 @@ export class ContextualMenu extends Component {
439
482
  selectionRect,
440
483
  editorAnalyticsAPI,
441
484
  getEditorContainerWidth,
442
- getEditorFeatureFlags
485
+ getEditorFeatureFlags,
486
+ isCellMenuOpenByKeyboard
443
487
  } = this.props;
444
488
  // TargetCellPosition could be outdated: https://product-fabric.atlassian.net/browse/ED-8129
445
489
  const {
@@ -454,6 +498,21 @@ export class ContextualMenu extends Component {
454
498
  tableDuplicateCellColouring = false,
455
499
  tableWithFixedColumnWidthsOption = false
456
500
  } = getEditorFeatureFlags ? getEditorFeatureFlags() : {};
501
+ // context menu opened by keyboard and any item except 'background' activated
502
+ // or color has been chosen from color palette
503
+ if (getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c') && isCellMenuOpenByKeyboard && (item.value.name !== 'background' || item.value.name === 'background' && this.state.isSubmenuOpen)) {
504
+ const {
505
+ tr
506
+ } = state;
507
+ tr.setMeta(tablePluginKey, {
508
+ type: 'SET_CELL_MENU_OPEN',
509
+ data: {
510
+ isCellMenuOpenByKeyboard: false
511
+ }
512
+ });
513
+ dispatch(tr);
514
+ editorView.dom.focus(); // otherwise cursor disappears from cell
515
+ }
457
516
  const shouldUseIncreasedScalingPercent = isTableScalingEnabled && tableWithFixedColumnWidthsOption && getBooleanFF('platform.editor.table.use-increased-scaling-percent');
458
517
  switch (item.value.name) {
459
518
  case 'sort_column_desc':
@@ -507,6 +566,19 @@ export class ContextualMenu extends Component {
507
566
  deleteRowsWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.CONTEXT_MENU, selectionRect, !!isHeaderRowRequired)(state, dispatch);
508
567
  this.toggleOpen();
509
568
  break;
569
+ case 'background':
570
+ {
571
+ // This is called twice.
572
+ // 1st time when user chooses the background color item.
573
+ // 2nd when color has been chosen from color palette.
574
+ // here we are handling the 1st call relying on the isSubmenuOpen state value
575
+ if (getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c') && isCellMenuOpenByKeyboard && !this.state.isSubmenuOpen) {
576
+ this.setState({
577
+ isSubmenuOpen: true
578
+ });
579
+ }
580
+ break;
581
+ }
510
582
  }
511
583
  });
512
584
  _defineProperty(this, "toggleOpen", () => {
@@ -524,17 +596,51 @@ export class ContextualMenu extends Component {
524
596
  });
525
597
  }
526
598
  });
527
- _defineProperty(this, "handleOpenChange", () => {
599
+ _defineProperty(this, "handleOpenChange", payload => {
528
600
  const {
529
601
  editorView: {
530
602
  state,
531
- dispatch
532
- }
603
+ dispatch,
604
+ dom
605
+ },
606
+ isCellMenuOpenByKeyboard
533
607
  } = this.props;
534
- toggleContextualMenu()(state, dispatch);
535
- this.setState({
536
- isSubmenuOpen: false
537
- });
608
+ if (getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')) {
609
+ if (payload) {
610
+ const {
611
+ event
612
+ } = payload;
613
+ if (event && event instanceof KeyboardEvent) {
614
+ if (!this.state.isSubmenuOpen) {
615
+ if (arrowsList.has(event.key)) {
616
+ // preventing default behavior for avoiding cursor jump to next/previous table column
617
+ // when left/right arrow pressed.
618
+ event.preventDefault();
619
+ }
620
+ toggleContextualMenu()(state, dispatch);
621
+ this.setState({
622
+ isSubmenuOpen: false
623
+ });
624
+ setFocusToCellMenu(false)(state, dispatch);
625
+ dom.focus();
626
+ }
627
+ } else {
628
+ // mouse click outside
629
+ toggleContextualMenu()(state, dispatch);
630
+ this.setState({
631
+ isSubmenuOpen: false
632
+ });
633
+ if (isCellMenuOpenByKeyboard) {
634
+ setFocusToCellMenu(false)(state, dispatch);
635
+ }
636
+ }
637
+ }
638
+ } else {
639
+ toggleContextualMenu()(state, dispatch);
640
+ this.setState({
641
+ isSubmenuOpen: false
642
+ });
643
+ }
538
644
  });
539
645
  _defineProperty(this, "handleItemMouseEnter", ({
540
646
  item
@@ -601,21 +707,46 @@ export class ContextualMenu extends Component {
601
707
  this.toggleOpen();
602
708
  });
603
709
  }
710
+ componentDidMount() {
711
+ if (getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')) {
712
+ // ArrowKeyNavigationProvider in DropdownMenu expects that menu handle will stay focused
713
+ // until user pressed ArrowDown.
714
+ // Behavior above fails the A11Y requirement about first item in menu should be focused immediately.
715
+ // so here is triggering componentDidUpdate inside dropdown to set focus on first element
716
+ const {
717
+ isCellMenuOpenByKeyboard
718
+ } = this.props;
719
+ if (isCellMenuOpenByKeyboard) {
720
+ this.setState({
721
+ ...this.state,
722
+ isOpenAllowed: isCellMenuOpenByKeyboard
723
+ });
724
+ }
725
+ }
726
+ }
604
727
  render() {
605
728
  const {
606
729
  isOpen,
607
730
  mountPoint,
608
731
  offset,
609
732
  boundariesElement,
610
- editorView
733
+ editorView,
734
+ isCellMenuOpenByKeyboard
611
735
  } = this.props;
612
736
  const {
613
737
  isDragAndDropEnabled
614
738
  } = getPluginState(editorView.state);
615
739
  const items = isDragAndDropEnabled ? this.createNewContextMenuItems() : this.createOriginalContextMenuItems();
740
+ let isOpenAllowed = false;
741
+ if (getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')) {
742
+ isOpenAllowed = isCellMenuOpenByKeyboard ? this.state.isOpenAllowed : isOpen;
743
+ } else {
744
+ isOpenAllowed = isOpen;
745
+ }
616
746
  return jsx("div", {
617
747
  "data-testid": "table-cell-contextual-menu",
618
- onMouseLeave: this.closeSubmenu
748
+ onMouseLeave: this.closeSubmenu,
749
+ ref: this.dropdownMenuRef
619
750
  }, jsx(DropdownMenu, {
620
751
  mountTo: mountPoint
621
752
  //This needs be removed when the a11y is completely handled
@@ -623,21 +754,25 @@ export class ContextualMenu extends Component {
623
754
  ,
624
755
  arrowKeyNavigationProviderOptions: {
625
756
  type: ArrowKeyNavigationType.MENU,
626
- disableArrowKeyNavigation: true
757
+ disableArrowKeyNavigation: getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c') && isCellMenuOpenByKeyboard && !this.state.isSubmenuOpen ? false : true
627
758
  },
628
759
  items: items,
629
- isOpen: isOpen,
760
+ isOpen: isOpenAllowed,
630
761
  onOpenChange: this.handleOpenChange,
631
762
  onItemActivated: this.onMenuItemActivated,
632
763
  onMouseEnter: this.handleItemMouseEnter,
633
764
  onMouseLeave: this.handleItemMouseLeave,
634
765
  fitHeight: 188,
635
766
  fitWidth: isDragAndDropEnabled ? contextualMenuDropdownWidthDnD : contextualMenuDropdownWidth,
767
+ shouldFocusFirstItem: getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c') ? () => {
768
+ return Boolean(isCellMenuOpenByKeyboard);
769
+ } : undefined,
636
770
  boundariesElement: boundariesElement,
637
771
  offset: offset,
638
772
  section: isDragAndDropEnabled ? {
639
773
  hasSeparator: true
640
- } : undefined
774
+ } : undefined,
775
+ isAllowEnterDefaultBehavior: getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c') ? this.state.isSubmenuOpen : false
641
776
  }));
642
777
  }
643
778
  }
@@ -18,7 +18,8 @@ const FloatingContextualMenu = ({
18
18
  pluginConfig,
19
19
  editorAnalyticsAPI,
20
20
  getEditorContainerWidth,
21
- getEditorFeatureFlags
21
+ getEditorFeatureFlags,
22
+ isCellMenuOpenByKeyboard
22
23
  }) => {
23
24
  // TargetCellPosition could be outdated: https://product-fabric.atlassian.net/browse/ED-8129
24
25
  const {
@@ -71,7 +72,8 @@ const FloatingContextualMenu = ({
71
72
  boundariesElement: boundariesElement,
72
73
  editorAnalyticsAPI: editorAnalyticsAPI,
73
74
  getEditorContainerWidth: getEditorContainerWidth,
74
- getEditorFeatureFlags: getEditorFeatureFlags
75
+ getEditorFeatureFlags: getEditorFeatureFlags,
76
+ isCellMenuOpenByKeyboard: isCellMenuOpenByKeyboard
75
77
  })));
76
78
  };
77
79
  FloatingContextualMenu.displayName = 'FloatingContextualMenu';